0361555045451dd93b7f040cc984881cfc8a087d
[util-vserver.git] / util-vserver / scripts / vserver.start
1 #! /bin/bash
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 CHBIND_OPTS=()
24 declare -a CAP_OPTS=()
25 declare -a CHCONTEXT_FLAG_OPTS=()
26 declare -a CHCONTEXT_OPTS=()
27 declare -a CAPCHROOT_OPTS=()
28 declare -a INTERFACES=()
29 declare -a START_CMD=()
30
31 SILENT_OPT=
32 INITSTYLE=sysv
33 RUNLEVEL=3
34
35 function _generateInterfaceList
36 {
37     local vdir="$1"
38     local iface
39     local ip mask prefix
40
41     for iface in "$VSERVER_DIR/interfaces/"*; do
42         test   -d "$iface"          || continue
43         test ! -e "$iface"/disabled || continue
44
45         _getInterfaceValue ip     '' "$iface"
46         _getInterfaceValue mask   '' "$iface" "$iface/.."
47         _getInterfaceValue prefix '' "$iface" "$iface/.."
48         
49         _transformMask2Prefix prefix "$prefix" "$mask"
50         
51         INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
52     done 2>/dev/null
53 }
54
55 function _generateChbindOptions
56 {
57     local vdir="$1"
58     local i
59     local bcast=
60
61     local f=$vdir/interfaces/bcast
62     test ! -e "$f" || read bcast <"$f"
63     
64     CHBIND_OPTS=( $SILENT_OPT ${bcast:+--bcast "$bcast"} )
65
66     for i in "${INTERFACES[@]}"; do
67         CHBIND_OPTS=( "${CHBIND_OPTS[@]}" --ip "$i" )
68     done
69 }
70
71 function _generateNiceCommand
72 {
73     local vdir=$1
74     local nice
75
76     test -e "$vdir/nice" || return 0;
77     read nice <"$vdir"/nice
78
79     NICE_CMD=( $_NICE -$nice )
80 }
81
82 function _generateCapabilityOptions
83 {
84     local vdir=$1
85     local cap
86
87     test -e "$vdir"/capabilities || return 0
88
89     CAP_OPTS=()
90     CAPCHROOT_OPTS=()
91
92     while read cap; do
93         case x"$cap" in
94             x|x#)       ;;
95             !CAP_SYSCHROOT)
96                 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
97                 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
98                 ;;
99             *)
100                 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" );;
101         esac
102     done <"$vdir"/capabilities
103 }
104
105 function _generateFlagOptions
106 {
107     local vdir=$1
108
109     CHCONTEXT_FLAG_OPTS=()
110
111     ## TODO: get_initdefault
112     START_CMD=( /etc/rc.d/rc "$RUNLEVEL" )
113     test ! -x "$vdir/etc/init.d/rc" || {
114         START_CMD=( /etc/init.d/rc "$RUNLEVEL" )
115     }
116     
117     test -e "$vdir"/flags || return 0
118
119     while read flag; do
120         case x"$flag" in
121             x|x#)               ;;
122             dummy)              ;;
123             minit|fakeinit)
124                 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" \
125                                       --disconnect --flag --fakeinit )
126                 case "$flag" in
127                     minit)
128                         START_CMD=( /sbin/minit-start )
129                         INITSTYLE=minit
130                         ;;
131                     *)          START_CMD=( /sbin/init );;
132                 esac
133                 ;;
134             *)
135                 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
136                                       --flag "$flag" )
137                 ;;
138         esac
139     done <"$vdir"/flags
140 }
141
142 function _generateChcontextOptions
143 {
144     local vdir=$1
145     local ctx hostname domainname
146     local cap_opts
147     local flag
148
149     {
150         read ctx        <"$vdir"/context
151         read hostname   <"$vdir"/hostname
152         read domainname <"$vdir"/domainname
153     } 2>/dev/null
154
155     _generateCapabilityOptions "$vdir"
156     _generateFlagOptions       "$vdir"
157
158     CHCONTEXT_OPTS=( $SILENT_OPT \
159                      "${CHCONTEXT_FLAG_OPTS[@]}" \
160                      "${CAP_OPTS[@]}" \
161                      --secure
162                      ${ctx:+--ctx "$ctx"} \
163                      ${hostname:+--hostname "$hostname"} \
164                      ${domainname:+--domainname "$domainname"} )
165 }
166
167 function _getInterfaceValue
168 {
169     local val=$1
170     local dflt=$2
171     shift 2
172     
173     local i
174     local tmp
175
176     for i; do
177         read tmp  <"$i/$val" && break || :
178     done 2>/dev/null
179
180     eval $val=${tmp:-$dflt}
181 }
182
183 function _transformMask2Prefix
184 {
185     local tmp=$2
186     
187     test "$tmp" || {
188         $_MASK2PREFIX "$3" || tmp=$?
189     }
190
191     eval $1=$tmp
192     return 0
193 }
194
195 function enableSingleInterface
196 {
197     local iface=$1
198
199     local ip
200     local dev
201     local prefix
202     local mask
203     local bcast
204     local name
205     local scope
206
207     _getInterfaceValue ip     '' "$iface"
208     _getInterfaceValue dev    '' "$iface" "$iface/.."
209     _getInterfaceValue prefix '' "$iface" "$iface/.."
210     _getInterfaceValue mask   '' "$iface" "$iface/.."
211     _getInterfaceValue bcast  '' "$iface" "$iface/.."
212     _getInterfaceValue name   '' "$iface"
213     _getInterfaceValue scope  '' "$iface" "$iface/.."
214
215     test "$ip" || { echo $"Can not read ip for '$iface'"; return 1; }
216     
217     test ! -e "$iface"/only_ip   || unset dev
218     
219     if test "$dev"; then
220         _transformMask2Prefix prefix "$prefix" "$mask"
221
222         case "$dev" in
223             *.*)
224                 test -d /proc/net/vlan || {
225                     echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers"
226                     return 1
227                 }
228                 test -f /proc/net/vlan || {
229                     $_VCONFIG add  ${dev/./ }
230                     $_IP      addr add 127.0.0.1/8 broadcast 127.255.255.255 dev "$dev"
231                     $_IP      link set "$dev" up
232                 }
233                 ;;
234         esac
235
236         $_IP addr  add "$ip${prefix:+/$prefix}" broadcast ${bcast:-+} \
237                    ${name:+label "$dev:$name"} dev "$dev"
238         $_IP route add "$ip""${prefix:+/$prefix}" dev "$dev"
239         $_IP link  set "$dev" up
240     fi
241 }
242
243 function enableInterfaces
244 {
245     local VSERVER_DIR=$1
246     local VSERVER_NAME=$2
247     
248     local iface
249     declare -a all_ips
250
251     for iface in "$VSERVER_DIR/interfaces/"*; do
252         test   -d "$iface"          || continue
253         test ! -e "$iface"/disabled || continue
254     
255         enableSingleInterface "$iface"
256     done
257 }
258
259 function prepareInit
260 {
261     local vdir=$1
262     local style=$2
263
264     pushd "$vdir/vdir" >/dev/null
265     case "$style" in
266         sysv)
267             { find var/run  ! -type d -print0; \
268               find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_RM
269             $_FAKE_RUNLEVEL "$RUNLEVEL" /var/run/utmp
270             ;;
271         minit)
272             ;;
273     esac
274     popd >/dev/null
275 }
276
277 function generateOptions
278 {
279     _generateInterfaceList "$1"
280     _generateChbindOptions "$1"
281     _generateNiceCommand   "$1"
282     _generateChcontextOptions  "$1"
283 }
284
285 function mountVserver
286 {
287     local cfgdir=$1
288     local vdir=$1/vdir
289     local src dst type opts aux
290     local mountopts
291
292     declare -a mountopts
293
294     test -e "$cfgdir"/fstab || return 0
295     $_CHBIND "${CHBIND_OPTS[@]}" \
296         $_SECURE_MOUNT -a --chroot "$vdir" --fstab "$cfgdir"/fstab
297 }
298
299 function execScriptlets
300 {
301     local vdir=$1
302     local name=$2
303     local flavor=$3
304     local i
305
306     for i in "$vdir/scripts/$flavor" "$vdir/scripts/$flavor.d"/*; do
307         test -f "$i" -a -x "$i" || continue
308         "$i" "$flavor" "$name"
309     done
310 }
311
312 ############################################
313
314 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
315
316 if test -e "$VSERVER_DIR"/noisy; then
317     SILENT_OPT=
318 else
319     SILENT_OPT='--silent'
320 fi
321
322 if isVserverRunning "$VSERVER_DIR"; then
323     echo $"vserver '$VSERVER_NAME' already running; aborting..."
324     exit 1
325 fi
326
327 execScriptlets   "$VSERVER_DIR" "$VSERVER_NAME" prepre-start
328 generateOptions  "$VSERVER_DIR"
329 enableInterfaces "$VSERVER_DIR" "$VSERVER_NAME"
330
331 mountVserver "$VSERVER_DIR"
332 prepareInit  "$VSERVER_DIR" "$INITSTYLE"
333
334 cd "$VSERVER_DIR"/vdir/
335
336 execScriptlets   "$VSERVER_DIR" "$VSERVER_NAME" pre-start
337
338 "${NICE_CMD[@]}" \
339     "$_CHBIND" "${CHBIND_OPTS[@]}" \
340     "$_CHCONTEXT" "${CHCONTEXT_OPTS[@]}" \
341     "$_SAVE_CTXINFO" "$VSERVER_DIR" \
342     "$_CAPCHROOT" "${CAPCHROOT_OPTS[@]}" . "${START_CMD[@]}"
343
344 execScriptlets   "$VSERVER_DIR" "$VSERVER_NAME" post-start