vserver.functions (43278B)
1 # $Id$ --*- sh -*-- 2 3 # Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de> 4 # 5 # This program is free software; you can redistribute it and/or modify 6 # it under the terms of the GNU General Public License as published by 7 # the Free Software Foundation; version 2 of the License. 8 # 9 # This program is distributed in the hope that it will be useful, 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 # GNU General Public License for more details. 13 # 14 # You should have received a copy of the GNU General Public License 15 # along with this program; if not, write to the Free Software 16 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 ## Expected env: 19 # $VSERVER_DIR ... path to vserver-cfg dir 20 # $VSERVER_NAME ... name of vserver 21 22 declare -a NICE_CMD=() 23 declare -a IONICE_CMD=() 24 declare -a NETNS_CMD=() 25 declare -a CHBIND_CMD=() 26 declare -a CAP_OPTS=() 27 declare -a CHCONTEXT_INIT_OPTS=() 28 declare -a CHCONTEXT_FLAG_OPTS=() 29 declare -a CHCONTEXT_OPTS=() 30 declare -a CAPCHROOT_OPTS=() 31 declare -a INTERFACES=() 32 33 declare -a INITCMD_RESCUE=( /bin/sleep 900 ) 34 declare -a INITCMD_START=() 35 declare -a INITCMD_START_SYNC=() 36 declare -a INITCMD_STOP=() 37 declare -a INITCMD_STOP_SYNC=() 38 declare -a INITCMD_PREPARE=() 39 declare -a INITKILL_SEQ=() 40 declare -a ENTER_SHELL=() 41 42 declare -a OPTS_VCONTEXT_CREATE=() 43 declare -a OPTS_VCONTEXT_MIGRATE=() 44 declare -a OPTS_VCONTEXT_ENTER=() 45 OPT_VCONTEXT_CHROOT=--chroot 46 OPT_VCONTEXT_CLOSE_FD="" 47 declare -a OPTS_VATTRIBUTE=( --flag fakeinit ) 48 declare -a OPTS_VSCHED=() 49 declare -a OPTS_ENV=() 50 declare -a OPTS_VTAG_CREATE=() 51 declare -a OPTS_VTAG_ENTER=() 52 declare -a OPTS_VMEMCTRL=() 53 declare -a OPTS_VSPACE=( --default ) 54 declare -a OPTS_VSPACE_SHARED=() 55 declare -a VSPACE_SHARED_CMD=() 56 57 declare -a STOPCMD_PREPARE=() 58 59 declare -a VSERVER_EXTRA_CMDS=() 60 61 INIT_RESCUE= 62 VSHELPER_SYNC_TIMEOUT=30 63 USE_VNAMESPACE= 64 INTERFACE_CMDS_IDX=0 65 RUNLEVEL_START= 66 RUNLEVEL_STOP= 67 _HAVE_INTERFACE_OPTIONS= 68 _HAVE_CHBIND_OPTIONS= 69 _NEED_VSHELPER_SYNC= 70 _IS_FAKEINIT= 71 72 INITSTYLE=sysv 73 74 S_CONTEXT= 75 N_CONTEXT= 76 77 SILENT_OPT= 78 79 CGROUP_MNT=/dev/cgroup 80 declare -a CGROUP_SUBSYS=() 81 declare -a CGROUP_INHERIT=( cpuset.cpus cpuset.mems ) 82 CGROUP_BASE="" 83 CGROUP_MNT_PER_SS="" 84 85 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")} 86 87 if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then 88 SILENT_OPT= 89 else 90 SILENT_OPT='--silent' 91 fi 92 93 function _readFileToArray 94 { 95 local _rfta_f="$1" 96 local _rfta_a="$2" 97 local _rfta_p="$3" 98 local _rfta_v 99 100 test -e "$_rfta_f" || return 0 101 while read _rfta_v; do 102 case x"$_rfta_v" in 103 (x|x\#*) ;; 104 (*) eval "$_rfta_a=( \"\${$_rfta_a[@]}\" $_rfta_p \"$_rfta_v\" )";; 105 esac 106 done <"$_rfta_f" 107 } 108 109 function _generateChbindOptions 110 { 111 local vdir="$1" 112 local i 113 local bcast= 114 local lback= 115 local nid= 116 117 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir" 118 119 if test -e "$vdir"/noncontext -o \ 120 \( -e "$vdir"/spaces/net -a ! -e "$vdir"/ncontext \); then 121 _HAVE_CHBIND_OPTIONS=1 122 return 0 123 fi 124 125 local f="$vdir"/interfaces/bcast 126 getFileValue bcast "$f" 127 f="$vdir"/interfaces/lback 128 getFileValue lback "$f" 129 130 CHBIND_CMD=( $_CHBIND $SILENT_OPT --secure ${N_CONTEXT:+--nid "$N_CONTEXT"} 131 ${bcast:+--bcast "$bcast"} ${lback:+--lback "$lback"} 132 ) 133 134 for i in "${INTERFACES[@]}"; do 135 CHBIND_CMD=( "${CHBIND_CMD[@]}" --ip "$i" ) 136 done 137 138 _readFileToArray "$vdir"/nflags CHBIND_CMD --flag 139 _readFileToArray "$vdir"/ncapabilities CHBIND_CMD --ncap 140 141 _HAVE_CHBIND_OPTIONS=1 142 } 143 144 function _generateNiceCommand 145 { 146 local vdir=$1 147 local nice=0 148 local current_nice=`$_NICE` 149 150 test -r "$vdir/nice" && read nice <"$vdir"/nice 151 152 let nice=$nice-$current_nice || : 153 NICE_CMD=( $_NICE -n $nice ) 154 } 155 156 function _generateIONiceCommand 157 { 158 local vdir=$1 159 local ionice_class= 160 local ionice_priority= 161 162 test -n "$_IONICE" || return 0 163 164 test -r "$vdir/ionice/class" && read ionice_class <"$vdir"/ionice/class 165 test -r "$vdir/ionice/priority" && read ionice_priority <"$vdir"/ionice/priority 166 167 test -n "$ionice_class$ionice_priority" || return 0 168 169 if test -z "$ionice_class" -a -n "$ionice_priority"; then 170 IONICE_CMD=( $_IONICE -c2 -n"$ionice_priority" ) 171 else 172 IONICE_CMD=( $_IONICE ${ionice_class:+-c$ionice_class} ${ionice_priority:+-n$ionice_priority} ) 173 fi 174 } 175 176 function _generatePersonalityOptions 177 { 178 local vdir="$1" 179 local f="$vdir"/personality 180 local type flags 181 182 test -s "$f" || return 0 183 184 { 185 local delim tmp 186 187 read type 188 while read tmp; do 189 case x$tmp in 190 (x\#*|x) ;; 191 (*) flags=$flags$delim$tmp 192 delim=, 193 ;; 194 esac 195 done 196 } <"$f" 197 198 OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}" 199 --personality-type "$type" 200 ${flags:+--personality-flags "$flags"} ) 201 } 202 203 function _generateCCapabilityOptions 204 { 205 local vdir=$1 206 207 _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap 208 } 209 210 function _generateBCapabilityOptions 211 { 212 local vdir=$1 213 214 _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap 215 } 216 217 function _generateUMaskOptions 218 { 219 local vdir=$1 220 221 _readFileToArray "$vdir"/umask OPTS_VATTRIBUTE --umask 222 } 223 224 function _generateCapabilityOptions 225 { 226 local vdir=$1 227 local cap 228 229 _generateBCapabilityOptions "$vdir" 230 _generateCCapabilityOptions "$vdir" 231 232 test -e "$vdir"/capabilities || return 0 233 234 CAP_OPTS=() 235 CAPCHROOT_OPTS=() 236 237 while read cap; do 238 case x"$cap" in 239 (x|x\#*) ;; 240 (!CAP_SYSCHROOT) 241 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" ) 242 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot ) 243 ;; 244 (*) 245 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" ) 246 ;; 247 esac 248 done <"$vdir"/capabilities 249 } 250 251 function getEnterShell 252 { 253 local vdir=$1 254 local shell_file 255 256 ENTER_SHELL=() 257 258 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell 259 260 test -n "$ENTER_SHELL" || { 261 local i 262 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do 263 set -- $i 264 test -x "$vdir/vdir/$1" || continue 265 ENTER_SHELL=( "$@" ) 266 break 267 done 268 } 269 } 270 271 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]* 272 function sendKillSequence 273 { 274 local ctx=$1 275 local wait= 276 shift 277 278 while isCtxRunning "$ctx"; do 279 test -z "$wait" || sleep "$wait" 280 281 killContext "$ctx" "$1" 282 test -n "$2" || break 283 wait="$2" 284 shift 2 285 done 286 } 287 288 function _generateInitOptions 289 { 290 local vdir=$1 291 local cfgdir=$vdir/apps/init 292 local i f 293 294 INITCMD_START=() 295 INITCMD_STOP=() 296 INITCMD_START_SYNC=() 297 INITCMD_STOP_SYNC=() 298 INITCMD_PREPARE=() 299 STOPCMD_PREPARE=() 300 301 INITKILL_SEQ=( 15 5 9 ) 302 CHCONTEXT_INIT_OPTS=() 303 304 305 test x"$INITSTYLE" = xrescue || \ 306 getFileValue INITSTYLE "$cfgdir"/style 307 getFileValue RUNLEVEL_START "$cfgdir"/runlevel 308 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start 309 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop 310 getFileArray INITKILL_SEQ "$cfgdir"/killseq || : 311 312 findFile _gio_env "$cfgdir"/environment \ 313 "$__CONFDIR"/.defaults/apps/init/environment \ 314 "$__PKGLIBDEFAULTDIR"/environment 315 getFileArray OPTS_ENV "$_gio_env" || : 316 317 case x"$INITSTYLE" in 318 (xrescue) 319 INITCMD_START=( "${INITCMD_RESCUE[@]}" ) 320 INITCMD_STOP=( /sbin/killall5 ) 321 ;; 322 323 (xsysv) 324 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3 325 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6 326 327 for i in /etc/init.d/rc /etc/rc.d/rc; do 328 test -x "$vdir/vdir/$i" || continue 329 INITCMD_START=( "$i" "$RUNLEVEL_START" ) 330 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" ) 331 done 332 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp ) 333 OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" ) 334 if test -n "$OPTION_DEBUG_SYSV"; then 335 INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" ) 336 INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" ) 337 fi 338 ;; 339 340 (xplain) 341 INITCMD_START=( /sbin/init ) 342 INITCMD_STOP=( /sbin/init ) 343 _IS_FAKEINIT=1 344 _NEED_VSHELPER_SYNC=1 345 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" ) 346 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" ) 347 ;; 348 349 (xminit) 350 INITCMD_START=( /sbin/minit-start ) 351 INITCMD_STOP=( /sbin/minit-stop ) 352 _IS_FAKEINIT=1 353 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" ) 354 _NEED_VSHELPER_SYNC=1 355 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" ) 356 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" ) 357 ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp ) 358 ;; 359 360 (xgentoo|xopenrc) 361 test -n "$RUNLEVEL_START" || RUNLEVEL_START="default" 362 RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin 363 364 if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then 365 RC_WRAP=/lib/rcscripts/sh/init-vserver.sh 366 elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then 367 RC_WRAP=/lib/rc/sh/init-vserver.sh 368 else 369 panic "init-vserver.sh not found; aborting" 370 fi 371 372 OPTS_ENV=( "${OPTS_ENV[@]}" TERM=$TERM ) 373 INITCMD_START=( $RC_WRAP "$RUNLEVEL_START" ) 374 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown ) 375 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp ) 376 ;; 377 378 (xarch) 379 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3 380 INITCMD_START=( /etc/rc.multi ) 381 INITCMD_STOP=( /etc/rc.shutdown ) 382 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp ) 383 ;; 384 385 (x) ;; 386 (*) panic "Unknown init-style '$INITSTYLE'; aborting";; 387 esac 388 389 if test x"$INITSTYLE" != xrescue; then 390 getFileArray INITCMD_START "$cfgdir"/cmd.start || : 391 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || : 392 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || : 393 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || : 394 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || : 395 fi 396 397 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || { 398 INITCMD_START_SYNC=() 399 INITCMD_STOP_SYNC=() 400 _NEED_VSHELPER_SYNC= 401 } 402 403 if vshelper.isEnabled; then 404 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || : 405 else 406 _NEED_VSHELPER_SYNC= 407 fi 408 } 409 410 function _generateFlagOptions 411 { 412 local vdir=$1 413 local file 414 415 CHCONTEXT_FLAG_OPTS=() 416 417 findFile file "$vdir"/cflags "$vdir"/flags "" 418 test -z "$file" || \ 419 while read flag; do 420 case x"$flag" in 421 (x|x\#*) ;; 422 (xnamespace) ;; 423 (xfakeinit) 424 _IS_FAKEINIT=1 425 ;; 426 (*) 427 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" ) 428 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" 429 --flag "$flag" ) 430 ;; 431 esac 432 done <"$file" 433 434 isAvoidNamespace "$vdir" || { 435 USE_VNAMESPACE=1 436 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace ) 437 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \ 438 OPT_VCONTEXT_CHROOT=--pivot-root 439 } 440 } 441 442 function _generateChcontextOptions 443 { 444 local vdir=$1 445 local ctx hostname domainname 446 local cap_opts 447 local flag 448 449 { 450 read ctx <"$vdir"/context || : 451 ## LEGACY ALERT 452 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || : 453 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || : 454 } 2>/dev/null 455 456 test -z "$S_CONTEXT" || ctx=$S_CONTEXT 457 458 _generateCapabilityOptions "$vdir" 459 _generateFlagOptions "$vdir" 460 _generateUMaskOptions "$vdir" 461 462 CHCONTEXT_OPTS=( $SILENT_OPT \ 463 "${CHCONTEXT_FLAG_OPTS[@]}" \ 464 "${CAP_OPTS[@]}" \ 465 --secure 466 ${ctx:+--ctx "$ctx"} \ 467 ${hostname:+--hostname "$hostname"} \ 468 ${domainname:+--domainname "$domainname"} ) 469 470 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \ 471 ${ctx:+--xid "$ctx"} ) 472 findFile file "$vdir"/keepfds "$__CONFDIR/.defaults/keepfds" "" 473 test -n "$file" || OPT_VCONTEXT_CLOSE_FD="--closefd" 474 ## put '--secure' at front so that it can be overridden 475 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" ) 476 } 477 478 function _generateScheduleOptions 479 { 480 local vdir=$1 481 if test -d "$vdir"/sched; then 482 OPTS_VSCHED=( --dir "$vdir"/sched --missingok ) 483 return 0 484 fi 485 486 local f="$vdir"/schedule 487 test -e "$f" || return 0 488 489 local fill_rate interval tokens tokens_min tokens_max prio_bias 490 { 491 { 492 read fill_rate && \ 493 read interval && \ 494 read tokens && \ 495 read tokens_min && \ 496 read tokens_max && \ 497 read prio_bias || prio_bias= 498 } <"$f" 499 } 2>/dev/null 500 501 test -n "$prio_bias" || { 502 echo $"Bad content in '$f'; aborting..." >&2 503 false 504 } 505 506 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \ 507 --tokens "$tokens" --tokens_min "$tokens_min" \ 508 --tokens_max "$tokens_max" --priority-bias "$prio_bias" ) 509 } 510 511 function _getInterfaceValue 512 { 513 local _giv_val=$1 514 local _giv_dflt=$2 515 shift 2 516 517 local _giv_i 518 local _giv_tmp 519 520 for _giv_i; do 521 read _giv_tmp <"$_giv_i/$_giv_val" && break || : 522 done 2>/dev/null 523 524 : ${_giv_tmp:=$_giv_dflt} 525 eval $_giv_val=\$_giv_tmp 526 } 527 528 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask> 529 function _transformMask2Prefix 530 { 531 local _tm2p_tmp=$2 532 533 test -n "$_tm2p_tmp" || { 534 $_MASK2PREFIX "$3" || _tm2p_tmp=$? 535 } 536 537 eval $1=\$_tm2p_tmp 538 return 0 539 } 540 541 function _addInterfaceCmd 542 { 543 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )' 544 let ++INTERFACE_CMDS_IDX 545 } 546 547 ## Usage: _generateMac <var> <iface> <ctx> 548 function _generateMac 549 { 550 isNumber "$2" || { 551 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2 552 return 1 553 } 554 555 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ]) 556 } 557 558 function _getVLANInfo 559 { 560 case "$1" in 561 (vlan????) 562 panic "\ 563 creation of VLAN_PLUS_VID devices is not supported; please create them 564 before starting the vserver and use the 'nodev' flag then" 565 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID" 566 ;; 567 (vlan*) 568 panic "\ 569 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please 570 create them before starting the vserver and use the 'nodev' flag then" 571 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD" 572 ;; 573 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";; 574 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";; 575 (*) return 1 576 esac 577 578 return 0 579 } 580 581 function _getTunInfo 582 { 583 local iface="$1" 584 585 test -e "$iface/tun" -o -e "$iface/tap" || return 1 586 test ! -e "$iface/tun" || echo --tun 587 test ! -e "$iface/tap" || echo --tap 588 test ! -e "$iface/nocsum" || echo --~checksum 589 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT" 590 if test -e "$iface/uid"; then 591 local uid 592 getFileValue uid "$iface/uid" 593 echo --uid "$uid" 594 fi 595 if test -e "$iface/gid"; then 596 local gid 597 getFileValue gid "$iface/gid" 598 echo --gid "$gid" 599 fi 600 if test -e "$iface/linktype"; then 601 local linktype 602 getFileValue linktype "$iface/linktype" 603 echo --linktype "$linktype" 604 fi 605 return 0 606 } 607 608 ## Usage: _processSingleInterface <interface-directory> 609 function _processSingleInterface 610 { 611 local iface=$1 612 613 local ip 614 local dev 615 local prefix 616 local mask 617 local bcast 618 local name 619 local scope 620 local mac 621 local extip 622 local up="up" 623 local peer 624 625 _getInterfaceValue ip '' "$iface" 626 _getInterfaceValue extip '' "$iface" "$iface/.." 627 _getInterfaceValue dev '' "$iface" "$iface/.." 628 _getInterfaceValue prefix '' "$iface" "$iface/.." 629 _getInterfaceValue mask '' "$iface" "$iface/.." 630 _getInterfaceValue bcast '' "$iface" "$iface/.." 631 _getInterfaceValue name '' "$iface" 632 _getInterfaceValue scope '' "$iface" "$iface/.." 633 _getInterfaceValue mac '' "$iface" 634 _getInterfaceValue peer '' "$iface" 635 636 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; } 637 test -n "$dev" -o -e "$iface"/nodev || { 638 echo $"No device specified for '$iface'" >&2 639 return 1; 640 } 641 642 test ! -e "$iface"/down || up= 643 644 while true; do 645 _transformMask2Prefix prefix "$prefix" "$mask" 646 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" ) 647 648 test ! -e "$iface"/nodev || break 649 ## LEGACY ALERT 650 test ! -e "$iface"/only_ip || break 651 652 test -e "$iface/vlandev" \ 653 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \ 654 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \ 655 -a ! -e "$iface/novlandev" \ 656 -a ! -e "$iface/../novlandev" \) && { 657 local vlan_info 658 if vlan_info=$(_getVLANInfo "$dev"); then 659 test -d /proc/net/vlan || { 660 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2 661 return 1 662 } 663 _addInterfaceCmd $VCONFIGOP $vlan_info 664 fi 665 } 666 667 if ! test -e "$iface"/indirect; then 668 # XXX: IPv6 hack 669 local use_bcast="broadcast ${bcast:-+}" 670 echo "$ip" | $_GREP -q : && use_bcast= 671 672 local tun_info 673 if tun_info=$(_getTunInfo "$iface"); then 674 _addInterfaceCmd TUNCTL "$dev" $tun_info 675 fi 676 677 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"} 678 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev" 679 _addInterfaceCmd IP_LINK "$dev" $up 680 elif ! test -n "$N_CONTEXT"; then 681 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2 682 return 1 683 else 684 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1 685 _addInterfaceCmd MODPROBE dummy "$dev" 686 _addInterfaceCmd IP_LINK dev dummy0 address "$mac" 687 _addInterfaceCmd NAMEIF "$dev" "$mac" 688 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev" 689 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip" 690 fi 691 692 break 693 done 694 } 695 696 ## Usage: _generateInterfaceOptions <vserver-directory> 697 function _generateInterfaceOptions 698 { 699 local iface 700 701 # XXX: This is here instead of in _generateChbindOptions 702 # to avoid a circular dependency 703 getFileValue N_CONTEXT "$1/ncontext" "$1/context" 704 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT" 705 706 for iface in "$1/interfaces/"*; do 707 test -d "$iface" || continue 708 test ! -e "$iface"/disabled || continue 709 710 _processSingleInterface "$iface" 711 done 712 _HAVE_INTERFACE_OPTIONS=1 713 } 714 715 function enableInterfaces 716 { 717 local i=0 718 declare -a var 719 720 lock "$__LOCKDIR"/vserver.interfaces 721 722 while test $i -lt $INTERFACE_CMDS_IDX; do 723 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )' 724 local type=${var[0]} 725 unset var[0] 726 727 set -- "${var[@]}" 728 case "$type" in 729 IPTABLES) ;; ## TODO 730 MODPROBE) 731 local mod=$1 732 local name=$2 733 shift 2 734 $_MODPROBE ${name:+-o "$name"} "$mod" "$@" 735 ;; 736 NAMEIF) $_NAMEIF "$@";; 737 VCONFIG) $_IP link add link "$2" name "$1" type vlan id "$3";; 738 VCONFIG_LEGACY) $_VCONFIG set_name_type "$4" >/dev/null 739 $_VCONFIG add "$2" "$3" >/dev/null;; 740 IP_ADDR) $_IP addr add "$@";; 741 IP_ADDR_FLUSH) $_IP addr flush "$@";; 742 IP_LINK) $_IP link set "$@";; 743 IP_ROUTE) $_IP route add "$@";; 744 TUNCTL) 745 local dev="$1" 746 shift 747 $_TUNCTL --persist "$@" "$dev" 748 ;; 749 *) echo "Unknown interface-command type '$type'" >&2; false;; 750 esac 751 752 let ++i 753 done 754 755 unlock 1 756 } 757 758 function disableInterfaces 759 { 760 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1" 761 762 local i=$INTERFACE_CMDS_IDX 763 declare -a var 764 765 lock "$__LOCKDIR"/vserver.interfaces 766 767 while test $i -gt 0; do 768 let --i || : 769 770 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )' 771 local type=${var[0]} 772 unset var[0] 773 774 set -- "${var[@]}" 775 case "$type" in 776 IPTABLES) ;; ## TODO 777 MODPROBE) $_RMMOD "${2:-$1}";; 778 NAMEIF) ;; 779 VCONFIG) $_IP link delete "$1" type vlan;; 780 VCONFIG_LEGACY) $_VCONFIG rem "$2.$3" >/dev/null;; 781 IP_ADDR) $_IP addr del "$@";; 782 IP_ADDR_FLUSH) ;; 783 IP_LINK) ;; ## Ignore the link-down command for now 784 IP_ROUTE) $_IP route del "$@";; 785 TUNCTL) 786 local dev="$1" 787 shift 788 $_TUNCTL --~persist "$@" "$dev" 789 ;; 790 *) echo "Unknown interface-command type '$type'" >&2; false;; 791 esac 792 done 793 794 unlock 1 795 } 796 797 function _generateTagOptions 798 { 799 local vdir="$1" 800 local tag 801 802 getFileValue tag "$vdir/tag" "$vdir/context" 803 test -n "$tag" || return 0 804 805 OPTS_VTAG_CREATE=( --tag "$tag" ) 806 OPTS_VTAG_ENTER=( --tag "$tag" ) 807 } 808 809 function _generateMemctrlOptions 810 { 811 local vdir="$1" 812 local badness 813 814 getFileValue badness "$vdir/badness" 815 test -n "$badness" || return 0 816 817 OPTS_VMEMCTRL=( --badness "$badness" ) 818 } 819 820 function _generateSpaceOptions 821 { 822 local vdir="$1" 823 local d="$vdir"/spaces 824 local shared 825 local space 826 827 for space in pid net; do 828 if test -e "$d"/$space; then 829 getFileValue shared "$d"/$space || shared="" 830 if test -z "$shared"; then 831 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --$space ) 832 elif test "$shared" = "0"; then 833 : # Do nothing 834 else 835 OPTS_VSPACE_SHARED=( "${OPTS_VSPACE_SHARED[@]}" --$space ) 836 VSPACE_SHARED_CMD=( "${VSPACE_SHARED_CMD[@]}" $_VSPACE --enter "$shared" --$space -- ) 837 fi 838 fi 839 done 840 841 local mask 842 getFileValue mask "$d"/mask || \ 843 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" ) 844 } 845 846 ## Usage: prepareInit <vserver-directory> 847 function prepareInit 848 { 849 pushd "$1/vdir" >/dev/null 850 case "$INITSTYLE" in 851 sysv) 852 local -a dirs=( $($_CHROOT_SH realpath /var/run /var/lock | $_SED 's!^/*!!' || :) ) 853 local dir 854 for dir in "${dirs[@]}"; do 855 test ! -L "$dir" || continue 856 $_FIND "$dir/." ! -type d -print0 2>/dev/null | xargs -0r $_CHROOT_SH rm 857 done 858 ;; 859 plain) 860 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || : 861 : | $_CHROOT_SH truncate fastboot 2>/dev/null || : 862 ;; 863 minit) 864 ;; 865 esac 866 "${INITCMD_PREPARE[@]}" 867 popd >/dev/null 868 } 869 870 ## Usage: prepareInit <vserver-directory> 871 function prepareStop 872 { 873 pushd "$1/vdir" >/dev/null 874 case "$INITSTYLE" in 875 (sysv) 876 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts 877 ;; 878 esac 879 "${STOPCMD_PREPARE[@]}" 880 popd >/dev/null 881 } 882 883 884 function generateOptions 885 { 886 _generateInterfaceOptions "$1" 887 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1" 888 _generateNiceCommand "$1" 889 _generateIONiceCommand "$1" 890 _generateInitOptions "$1" 891 _generateChcontextOptions "$1" 892 _generateScheduleOptions "$1" 893 _generatePersonalityOptions "$1" 894 _generateTagOptions "$1" 895 _generateMemctrlOptions "$1" 896 _generateSpaceOptions "$1" 897 _generateCgroupOptions 898 899 if test -n "$_IS_FAKEINIT"; then 900 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit ) 901 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect ) 902 fi 903 } 904 905 function addtoCPUSET 906 { 907 local vdir=$1 908 local cpuset 909 local f="$vdir"/cpuset 910 local i 911 local configured=0 912 913 test -d "$f" || return 0 914 test -e "$f"/name || return 0 915 916 read cpuset < "$f"/name 917 test -e "$f"/nocreate || { 918 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1 919 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do 920 if test -e "$f"/"$i"; then 921 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || { 922 configured=1 923 break 924 } 925 fi 926 done 927 } 928 929 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1 930 if [ "$configured" -ne 0 ]; then 931 warning $"\ 932 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2 933 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || : 934 return 0 935 fi 936 } 937 938 function removeCPUSET 939 { 940 local vdir=$1 941 local cpuset 942 local f="$vdir"/cpuset 943 944 test -d "$f" || return 0 945 test -e "$f"/name || return 0 946 947 read cpuset < "$f"/name 948 test -e "$f"/nocreate || { 949 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || : 950 } 951 } 952 953 function _mountVserverInternal 954 { 955 local fstab="$1" 956 local xflag= 957 958 test -e "$fstab" || return 0 959 shift 960 961 pushd "$vdir" >/dev/null 962 # check whether / is mounted readonly or whether there is special 963 # magic regarding the mtab file; when etc/mtab can not be touched, 964 # add the '-n' flag to mount 965 test -w etc -o -w etc/mtab || xflag=-n 966 if test -h etc/mtab; then 967 local l=$($_READLINK etc/mtab) 968 test "${l##/proc/}" = "$l" || xflag=-n 969 fi 970 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no 971 popd >/dev/null 972 } 973 974 function mountRootFS 975 { 976 local cfgdir=$1 977 local vdir=$1/vdir 978 local fstab="$cfgdir"/fstab 979 local xflag= 980 981 test -e "$fstab" || return 0 982 pushd "$vdir" >/dev/null 983 # check whether / is mounted readonly or whether there is special 984 # magic regarding the mtab file; when etc/mtab can not be touched, 985 # add the '-n' flag to mount 986 test -w etc -o -w etc/mtab || xflag=-n 987 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n 988 popd >/dev/null 989 } 990 991 function mountVserver 992 { 993 local cfgdir=$1 994 local vdir=$1/vdir 995 local mtab_src 996 local extra_opt= 997 local real_vdir 998 999 test -e "$cfgdir"/fstab -o \ 1000 -e "$cfgdir"/fstab.local -o \ 1001 -e "$cfgdir"/fstab.remote || return 0 1002 1003 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null 1004 1005 pushd "$vdir" >/dev/null 1006 $_CHROOT_SH truncate /etc/mtab <"$mtab_src" 1007 popd >/dev/null 1008 1009 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir" 1010 1011 _mountVserverInternal "$cfgdir"/fstab 1012 _mountVserverInternal "$cfgdir"/fstab.local 1013 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" 1014 1015 isNamespaceCleanup "$cfgdir" && \ 1016 _namespaceCleanup "$cfgdir" 1017 1018 real_vdir=$(getPhysicalDir "$vdir") 1019 isAvoidNamespace "$cfgdir" || \ 1020 $_SECURE_MOUNT --rbind -n -o dev "$vdir" "$real_vdir" 1021 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \ 1022 $_SECURE_MOUNT -n -o shared,rec "$real_vdir" "$real_vdir" 1023 } 1024 1025 function _umountVserverInternal 1026 { 1027 local fstab="$1" 1028 test -e "$fstab" || return 0 1029 shift 1030 1031 $_TAC "$fstab" | { 1032 is_ok=1 1033 while read src dst tmp; do 1034 test -n "$tmp" || continue 1035 case x"$src" in 1036 (x\#*) continue;; 1037 esac 1038 1039 1040 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok= 1041 done 1042 test -n "$is_ok" 1043 } 1044 } 1045 1046 function umountVserver 1047 { 1048 local cfgdir=$1 1049 local vdir=$1/vdir 1050 local is_ok=1 1051 1052 isAvoidNamespace "$cfgdir" || return 0 1053 test -e "$cfgdir"/fstab -o \ 1054 -e "$cfgdir"/fstab.local -o \ 1055 -e "$cfgdir"/fstab.remote || return 0 1056 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir" 1057 1058 pushd "$vdir/" >/dev/null || return 1 1059 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok= 1060 _umountVserverInternal "$cfgdir"/fstab.local || is_ok= 1061 _umountVserverInternal "$cfgdir"/fstab || is_ok= 1062 popd >/dev/null || return 1 1063 1064 test -n "$is_ok" 1065 } 1066 1067 function fsckAllFS 1068 { 1069 local cfgdir=$1 1070 local fstab="$cfgdir"/fstab 1071 local FSTAB_FILE 1072 local fsck_exitcode 1073 1074 test -e "$fstab" || return 0 1075 1076 export FSTAB_FILE="$fstab" 1077 $_FSCK -s -n -A -T 1078 fsck_exitcode=$? 1079 test "$fsck_exitcode" -eq 0 -o \ 1080 "$fsck_exitcode" -eq 1 || return $fsck_exitcode 1081 } 1082 1083 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname> 1084 function initSync 1085 { 1086 local _is_meth=sync 1087 test -n "$_NEED_VSHELPER_SYNC" && \ 1088 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async 1089 1090 vshelper.initSync "$1" "$3" "$_is_meth" 1091 } 1092 1093 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname> 1094 function initWait 1095 { 1096 if $_VSERVER_INFO - FEATURE vwait; then 1097 local _is_tmpdir 1098 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX) 1099 1100 ( 1101 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \ 1102 --status-fd 3 "$2" \ 1103 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo 1104 rc=$? 1105 1106 if test "$rc" -ne 0 -a "$rc" -ne 1; then 1107 $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4 1108 killContext "$S_CONTEXT" 9 1109 fi 1110 1111 exit $rc 1112 ) 4>$_is_tmpdir/procs & 1113 1114 echo "$!" >$_is_tmpdir/pid 1115 eval "$3"=$_is_tmpdir 1116 fi </dev/null 1117 } 1118 1119 1120 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs> 1121 function _waitForVWait 1122 { 1123 wait "$3" || : 1124 1125 declare -a status 1126 declare -r procs=$(cat $4) 1127 1128 getFileArray status "$2" 1129 set -- ${status[0]} 1130 1131 case "$1" in 1132 (ERROR) warning $"\ 1133 'vwait' exited with error '$2' which indicates that vserver could not 1134 be stopped properly" 1135 ;; 1136 (FINISHED) ;; 1137 (KILLED) warning $"\ 1138 A timeout occured while waiting for the vserver to finish and it was 1139 killed by sending a SIGKILL signal. Please investigate the reasons 1140 and/or increase the timeout in apps/vshelper/sync-timeout." 1141 ;; 1142 1143 (TIMEOUT) warning $"\ 1144 A timeout occured while waiting for the vserver to finish and it will 1145 be killed by sending a SIGKILL signal. The following process list 1146 might be useful for finding out the reason of this behavior: 1147 1148 ---------------------------------------------------------------------- 1149 ${procs:+$procs 1150 }----------------------------------------------------------------------" 1151 ;; 1152 1153 (\?\?\?|*) warning $"\ 1154 internal error: 'vwait' exited with an unexpected status '$1'; I will 1155 try to continue but be prepared for unexpected events." 1156 ;; 1157 esac 1158 1159 return 0 1160 } 1161 1162 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>] 1163 function waitForSync 1164 { 1165 local cfgdir=$1 1166 local fifo=$2 1167 local vwait_statdir=$3 1168 local vwait_pid=$4 1169 1170 if test -d "$vwait_statdir"; then 1171 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs" 1172 elif test -n "$_NEED_VSHELPER_SYNC"; then 1173 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \ 1174 warning $"\ 1175 A timeout or other error occured while waiting for the synchronization 1176 signal from vserver '$VSERVER_NAME'. 1177 The vserver will be killed nevertheless..." 1178 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then 1179 "${INITCMD_STOP_SYNC[@]}" || \ 1180 warning $"\ 1181 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver 1182 will be killed nevertheless..." 1183 fi 1184 1185 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync || 1186 sleep 1 1187 } 1188 1189 function _sourceWrap 1190 { 1191 local vdir name flavor start i already_handled base 1192 . "$@" 1193 } 1194 1195 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor> 1196 function execScriptlets 1197 { 1198 declare -r vdir=$1 1199 declare -r name=$2 1200 declare -r flavor=$3 1201 local base i 1202 1203 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do 1204 local DONT_SKIP_DEFAULTS= 1205 local already_handled= 1206 1207 for i in "$base/$flavor" "$base/$flavor.d"/*; do 1208 isRegularFile "$i" || continue 1209 test -r "$i" || continue 1210 1211 already_handled=1 1212 local start= 1213 test -x "$i" || start=_sourceWrap 1214 $start "$i" "$flavor" "$name" 1215 done 1216 1217 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break 1218 done 1219 } 1220 1221 1222 function sanityCheck 1223 { 1224 declare -r cfgdir=$1 1225 1226 ! test -e "$cfgdir"/fstab.local || 1227 warning $"\ 1228 WARNING: 'fstab' will *not* be executed in the network context of the 1229 vserver anymore. Therefore, 'fstab.local' has the same functionality 1230 and is obsoleted. When you need the old behaviour, put the mounts 1231 into 'fstab.remote'" 1232 1233 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname || 1234 warning $"\ 1235 WARNING: The hostname is now configured in 'uts/nodename' but not in 1236 'hostname'." 1237 1238 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname || 1239 warning $"\ 1240 WARNING: The domainname is now configured in 'uts/domainname' but not 1241 in 'domainname'." >&2 1242 1243 1244 local i 1245 for i in "$cfgdir"/interfaces/*/only_ip; do 1246 if test -e "$i"; then 1247 local iface 1248 iface=${i##$cfgdir/interfaces/} 1249 iface=${iface%%/only_ip} 1250 warning $"\ 1251 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use 1252 'nodev' instead of" 1253 fi 1254 done 1255 1256 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \ 1257 warning $"\ 1258 WARNING: There is no cachedirectory configured for this vserver; 1259 please create '$cfgdir/cache' e.g. by executing 1260 1261 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache 1262 " 1263 1264 $_FIND "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';' 1265 1266 vshelper.doSanityCheck 1267 1268 $_VSERVER_INFO - VERIFYCAP || 1269 panic $"capabilities are not enabled in kernel-setup" 1270 1271 $_VSERVER_INFO - VERIFYPROC || 1272 panic $"\ 1273 /proc/uptime can not be accessed. Usually, this is caused by 1274 procfs-security. Please read the FAQ for more details 1275 http://linux-vserver.org/Proc-Security" 1276 1277 test -e "$cfgdir"/context || { 1278 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE ) 1279 test "$TYPE" != "static" || panic $"\ 1280 The kernel does not have dynamic contexts enabled. Please configure 1281 a static one by executing 1282 1283 echo [number between 2 and 49151] > $cfgdir/context" 1284 } 1285 } 1286 1287 1288 function _setSingleDiskLimit 1289 { 1290 local vdir=$1 1291 local dlimit=$2 1292 local space_used= 1293 local space_total= 1294 local inodes_used= 1295 local inodes_total= 1296 local reserved= 1297 local directory= 1298 local ctx= 1299 1300 getFileValue ctx "$vdir/context" 1301 getFileValue directory "$dlimit/directory" || return 0 1302 getFileValue space_total "$dlimit/space_total" || return 0 1303 getFileValue inodes_total "$dlimit/inodes_total" || return 0 1304 getFileValue reserved "$dlimit/reserved" || return 0 1305 1306 local cachename=$ctx$directory 1307 cachename=dlimits/${cachename//\//_} 1308 1309 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename" 1310 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache 1311 $_RM -f "$vdir/cache/$cachename" 1312 1313 if test -z "$inodes_used" -o -z "$space_used"; then 1314 local tmpvdu 1315 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"` 1316 inodes_used=${tmpvdu##* } 1317 space_used=${tmpvdu%% *} 1318 fi 1319 1320 $_VDLIMIT --xid $ctx \ 1321 --set space_used=$space_used \ 1322 --set space_total=$space_total \ 1323 --set inodes_used=$inodes_used \ 1324 --set inodes_total=$inodes_total \ 1325 --set reserved=$reserved \ 1326 "$directory" 1327 } 1328 1329 1330 function setDiskLimits 1331 { 1332 local vdir=$1 1333 local dlimit 1334 1335 # Disk Limits without a static context are useless 1336 test -e "$vdir"/context || return 0 1337 1338 for dlimit in "$vdir/dlimits/"*; do 1339 test -d "$dlimit" || continue 1340 test ! -e "$dlimit/disabled" || continue 1341 1342 _setSingleDiskLimit "$vdir" "$dlimit" 1343 done 1344 } 1345 1346 1347 function _saveSingleDiskLimit 1348 { 1349 local vdir=$1 1350 local dlimit=$2 1351 local ctx= 1352 local directory= 1353 1354 getFileValue ctx "$vdir/context" 1355 getFileValue directory "$dlimit/directory" || return 0 1356 1357 local cachename=$ctx$directory 1358 cachename=${cachename//\//_} 1359 1360 # Things are getting ugly here... LFS says that /var/cache (where 1361 # cachename is usually pointing to) can vanish and applications 1362 # have to deal with it. So, we have to interprete the $vdir/cache 1363 # symlink and have to create the needed directories manually. 1364 if test -d "$vdir/cache"; then 1365 : # ok, exists already 1366 elif test -L "$vdir/cache"; then 1367 # it's a dangling symlink 1368 local link 1369 link=$($_READLINK "$vdir/cache") 1370 ( cd $vdir && $_MKDIR -p "$link" ) 1371 else 1372 return 0 1373 fi 1374 1375 test -d "$vdir/cache" 1376 $_MKDIR -p "$vdir"/cache/dlimits 1377 1378 $_VDLIMIT --xid $ctx "$directory" | \ 1379 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename" 1380 1381 $_VDLIMIT --xid $ctx --remove "$directory" 1382 } 1383 1384 1385 function saveDiskLimits 1386 { 1387 local vdir=$1 1388 local dlimit 1389 1390 test -e "$vdir"/context || return 0 1391 1392 for dlimit in "$vdir/dlimits/"*; do 1393 test -d "$dlimit" || continue 1394 test ! -e "$dlimit/disabled" || continue 1395 1396 _saveSingleDiskLimit "$vdir" "$dlimit" 1397 done 1398 } 1399 1400 function _namespaceCleanup 1401 { 1402 local vdir="$1" 1403 local root=$($_VSERVER_INFO "$1" VDIR 1) 1404 local -a list 1405 local -a skip 1406 local i 1407 local j 1408 1409 getFileArray skip "$vdir"/namespace-cleanup-skip \ 1410 "$__CONFDIR"/.defaults/namespace-cleanup-skip || : 1411 1412 # these are things that have to be accessible post-cleanup 1413 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \ 1414 "$__PKGSTATEDIR" "$__LOCKDIR" "$__PKGDATADIR" "$__PKGLIBEXECDIR" \ 1415 /usr/local /tmp "${skip[@]}"; do 1416 local real=`getPhysicalDir "$i"` 1417 test "$i" != "$real" || real= 1418 for j in "$i" "$real"; do 1419 while test -n "$j"; do 1420 list=( "${list[@]}" "$j" ) 1421 j="${j%/*}" 1422 done 1423 done 1424 done 1425 1426 # keep cgroup mount points 1427 list=( "${list[@]}" "${CGROUP_MNT}" ) 1428 if test -n "$CGROUP_MNT_PER_SS"; then 1429 for ss in "${CGROUP_SUBSYS[@]}"; do 1430 list=( "${list[@]}" "${CGROUP_MNT}/${ss}" ) 1431 done 1432 fi 1433 1434 local -a list_umount 1435 while read -r dev path opts; do 1436 test -n "$path" || continue 1437 path_dir="${path}/" 1438 for i in "$root" /dev /proc /sys; do 1439 test "${path_dir#${i}/}" != "${path_dir}" && continue 2 1440 done 1441 for i in "${list[@]}" /; do 1442 test "$path" = "$i" && continue 2 1443 done 1444 # unmount them in reverse order so mounts further down the tree get unmounted first 1445 list_umount=( "$path" "${list_umount[@]}" ) 1446 done < /proc/mounts 1447 # separate loop to avoid races while reading /proc/mounts 1448 for i in "${list_umount[@]}"; do 1449 $_UMOUNT -l -n -i "$i" 1450 done 1451 } 1452 1453 function handleDeviceMap 1454 { 1455 local op="$1" 1456 local xid="$2" 1457 local dir="$3" 1458 local flags device target 1459 1460 test -d "$dir" || return 0 1461 test -n "$xid" || return 0 1462 1463 for i in "$dir"/*; do 1464 test -d "$i" || continue 1465 1466 local -a vdevmap_opts=() 1467 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create ) 1468 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open ) 1469 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap ) 1470 1471 getFileValue flags "$i/flags" || : 1472 getFileValue device "$i/device" || : 1473 getFileValue target "$i/target" || : 1474 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \ 1475 ${device:+--device "$device"} ${target:+--target "$target"} ) 1476 1477 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $? 1478 done 1479 } 1480 1481 function hasCgroup 1482 { 1483 $_GREP -q "cgroup" /proc/filesystems 1484 } 1485 1486 function _generateCgroupOptions 1487 { 1488 local file 1489 1490 hasCgroup || return 0 1491 1492 findFile file "$__CONFDIR/.defaults/cgroup/subsys" "" 1493 if test -n "$file"; then 1494 _readFileToArray "$file" CGROUP_SUBSYS "" 1495 else 1496 CGROUP_SUBSYS=( $($_AWK '/^#/ { next; } $1 == "ns" { next; } $4 != "0" { print $1; }' /proc/cgroups) ) 1497 fi 1498 findFile file "$__CONFDIR/.defaults/cgroup/mnt" "" 1499 if test -n "$file"; then 1500 read CGROUP_MNT < "$file" 1501 elif test -d /sys/fs/cgroup -a -d /sys/fs/cgroup/"${CGROUP_SUBSYS[0]}"; then 1502 CGROUP_MNT=/sys/fs/cgroup 1503 CGROUP_MNT_PER_SS=1 1504 fi 1505 findFile file "$__CONFDIR/.defaults/cgroup/inherit" "" 1506 if test -n "$file"; then 1507 _readFileToArray "$file" CGROUP_INHERIT "" 1508 fi 1509 findFile file "$__CONFDIR/.defaults/cgroup/base" "" 1510 if test -n "$file"; then 1511 read CGROUP_BASE < "$file" 1512 test "$CGROUP_BASE" != "${CGROUP_BASE%/}" || \ 1513 CGROUP_BASE="${CGROUP_BASE}/" 1514 fi 1515 findFile file "$__CONFDIR/.defaults/cgroup/per-ss" "" 1516 if test -n "$file"; then 1517 CGROUP_MNT_PER_SS=1 1518 fi 1519 1520 return 0 1521 } 1522 1523 function useCgroup 1524 { 1525 hasCgroup || return 1 1526 if test -n "$CGROUP_MNT_PER_SS"; then 1527 local existing=0 1528 local ss 1529 for ss in "${CGROUP_SUBSYS[@]}"; do 1530 if test -e "$CGROUP_MNT/$ss/tasks"; then 1531 let existing=${existing}+1 1532 fi 1533 done 1534 test "$existing" -gt 0 || return 1 1535 else 1536 test -e "$CGROUP_MNT/tasks" || return 1 1537 fi 1538 local memcg="" 1539 if $_VSERVER_INFO - FEATURE memcg; then 1540 memcg=1 1541 fi 1542 test -d "$1/cgroup" -o \ 1543 \( \( -d "$__CONFDIR/.defaults/cgroup" -o -n "$memcg" \) -a \ 1544 ! -e "$1/nocgroup" \) 1545 } 1546 1547 function _handleCgroup 1548 { 1549 local action="$1" 1550 local vdir="$2" 1551 local dir 1552 local name 1553 local i 1554 local j 1555 local parent 1556 local -a mnts 1557 local ss 1558 1559 useCgroup "$vdir" || return 0 1560 1561 findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" "" 1562 1563 if test -n "$dir" -a -r "$dir"/name; then 1564 read name < "$dir"/name 1565 else 1566 name="$VSERVER_NAME" 1567 fi 1568 1569 if test -n "$CGROUP_MNT_PER_SS"; then 1570 mnts=() 1571 for ss in "${CGROUP_SUBSYS[@]}"; do 1572 mnts=( "${mnts[@]}" "$CGROUP_MNT/$ss" ) 1573 done 1574 else 1575 mnts=( "$CGROUP_MNT" ) 1576 fi 1577 for mnt in "${mnts[@]}"; do 1578 test -d "$mnt" || continue 1579 if test "$action" = "attach"; then 1580 if test -n "$CGROUP_BASE"; then 1581 local -a dirs=() 1582 i="$mnt/$CGROUP_BASE" 1583 while test "$mnt" != "$i"; do 1584 dirs=( "$i" "${dirs[@]}" ) 1585 i="${i%/*}" 1586 done 1587 for i in "${dirs[@]}"; do 1588 if mkdir "$i" 2>/dev/null; then 1589 parent="${i%/*}" 1590 for j in "${CGROUP_INHERIT[@]}"; do 1591 test -f "$parent/$j" || continue 1592 cat "$parent/$j" > "$i/$j" 1593 done 1594 fi 1595 done 1596 fi 1597 if mkdir "$mnt/$CGROUP_BASE$name" 2>/dev/null; then 1598 parent="$mnt/$CGROUP_BASE$name" 1599 parent="${parent%/*}" 1600 for i in "${CGROUP_INHERIT[@]}"; do 1601 test -f "$parent/$i" || continue 1602 cat "$parent/$i" > "$mnt/$CGROUP_BASE$name/$i" 1603 done 1604 1605 if test -n "$dir"; then 1606 shopt -s nullglob 1607 for i in "$dir"/*; do 1608 f="${i##*/}" 1609 test "$f" != mnt -a "$f" != subsys -a \ 1610 "$f" != inherit -a "$f" != name -a "$f" != base -a \ 1611 "$f" != per-ss \ 1612 || continue 1613 if test -n "$CGROUP_MNT_PER_SS"; then 1614 ss="${f%%.*}" 1615 test "$ss" = "${mnt##*/}" || continue 1616 fi 1617 cat "$i" > "$mnt/$CGROUP_BASE$name/$f" 1618 done 1619 fi 1620 fi 1621 echo "$$" > "$mnt/$CGROUP_BASE$name/tasks" 1622 elif test "$action" = "destroy"; then 1623 rmdir "$mnt/$CGROUP_BASE$name" 2>/dev/null || : 1624 fi 1625 done 1626 1627 return 0 1628 } 1629 1630 function attachToCgroup 1631 { 1632 _handleCgroup attach "$@" 1633 } 1634 1635 function destroyCgroup 1636 { 1637 _handleCgroup destroy "$@" 1638 } 1639 1640 function _handleNetNS 1641 { 1642 local action="$1" 1643 local vdir="$2" 1644 local dir 1645 local name 1646 1647 findDir dir "$vdir/netns" "$__CONFDIR/.defaults/netns" "" 1648 test -n "$dir" -a ! -e "$vdir"/nonetns || return 0 1649 1650 if test -r "$dir"/name; then 1651 read name < "$dir"/name 1652 else 1653 name="$VSERVER_NAME" 1654 fi 1655 1656 NETNS_CMD=( "$_IP" netns exec "$name" ) 1657 if test ! -e "$dir"/shared; then 1658 if test "$action" = "add"; then 1659 "$_IP" netns add "$name" 1660 shopt -s nullglob 1661 counter=0 1662 for i in "$dir"/interfaces/*; do 1663 local host 1664 local guest 1665 local type 1666 read host < "$i"/host 1667 if test -r "$i"/guest; then 1668 read guest < "$i"/guest 1669 else 1670 guest="geth$counter" 1671 counter=$(( $counter + 1 )) 1672 fi 1673 if test -r "$i"/type; then 1674 read type < "$i"/type 1675 else 1676 type="veth" 1677 fi 1678 "$_IP" link add name "$host" type "$type" peer name "$guest" 1679 "$_IP" link set "$guest" netns "$name" 1680 done 1681 elif test "$action" = "del"; then 1682 shopt -s nullglob 1683 for i in "$dir"/interfaces/*; do 1684 local host 1685 read host < "$i"/host 1686 "$_IP" link del "$host" 1687 done 1688 "$_IP" netns del "$name" 1689 fi 1690 fi 1691 } 1692 1693 function setupNetNS 1694 { 1695 _handleNetNS add "$1" 1696 } 1697 1698 function enterNetNS 1699 { 1700 _handleNetNS exec "$1" 1701 } 1702 1703 function destroyNetNS 1704 { 1705 _handleNetNS del "$1" 1706 }