stop services in reverse order
[rrq/overlay-boot.git] / functions
1 # This file implements common functions for all boot methods
2
3 die() {
4     echo "$*" >&2
5     exit 1
6 }
7
8 # grab and set a configuration variable
9 # $1 = variable, [ $2 = default .. error otherwise ]
10 config() {
11     eval $1="'$(sed "/^$1=.*/{s|^$1=||;b};d" $CONFIG)'"
12     [ -z "$(eval echo "\$$1")" ] || return 0
13     [ $# -lt 2 ] && die "Missing $1=... in $CONFIG"
14     eval $1="'$2'"
15     eval echo "$1=\$$1"
16 }
17
18 # Install a default $1/etc/network/interfaces on the subhost root $1
19 setup_networking() {
20     [ -r $1/etc/network/interfaces ] && return 0
21     mkdir -p $1/etc/network
22     cat <<EOF >> $1/etc/network/interfaces
23 # Generated for $NAME subhost
24 auto lo
25 iface lo inet loopback
26 EOF
27     for IF in $(ip netns exec $NAME ip link show | grep "^eth") ; do
28         cat <<EOF >> $1/etc/network/interfaces
29
30 auto eth$i
31 iface eth$i inet manual
32 EOF
33     done
34 }
35
36 # Setup the network namespace for the given $CABLES
37 # $1=netns ( $2="br=mac" .. )
38 setup_veth_cables() {
39     local NETNS BR IF MAC C i ADD
40     NETNS="$1"
41     shift 1
42     i=0
43     for C in "$@" ; do
44         IF=$NETNS$i
45         MAC="${C#*=}"
46         [ -z "$MAC" ] || MAC="address $MAC"
47         ip link add $IF type veth peer name eth$i $MAC netns $NETNS
48         ip link set $IF up
49         BR="${C%=*}"
50         if [ -z "$BR" ] ; then
51             ip link set $IF
52             ifup $IF
53         else
54             brctl addif $BR $IF
55         fi
56         i=$((i+1))
57     done
58 }
59
60 # (name live system root work)
61 # Set up an overlay fmr $name on $live, with a new tmpfs on its /run,
62 # and "install" a "reaper" as the upcoming pid 1
63 setup_overlay() {
64     local LIVE="$2" LOWER="$3" UPPER="$4" ROOT
65
66     if grep -q "$1 $2" /proc/mounts ; then
67         die "$1 is already mounted"
68     fi
69
70     if [ -f "${UPPER%% *}" ] ; then
71         if [ -x "${UPPER%% *}" ] ; then
72             echo "${UPPER%% *} appears to be executable" >&2
73             # Giving a program/script as UPPER= asks for running this
74             # first, to make a root filesystem available. The script takes
75             # ACTION "setup" and "teardown", and on "setup" it must tell
76             # where the ROOT is set up.
77             ROOT="$(env ACTION=setup $UPPER)"
78             if [ ! -d "$ROOT" ] ; then
79                 # setup failed
80                 die "root setup failed: $UPPER"
81             fi
82             UPPER="$ROOT"
83             ## Now falling down to "normal overlay" setup
84         else
85             die "${UPPER%% *} (root setup program/script) is not executable"
86         fi
87     fi
88
89     # LIVE is the same as LOWER then skip the overlay; just assume
90     # a proper chroot system exists at LIVE.
91     if [ "$LIVE" != "$LOWER" ] ; then
92         # sanity check
93         [ -d "$WORK" ] || die "WORK=$WORK is not a directory"
94         [ -d "$UPPER" ] || die "UPPER=$UPPER is not a directory"
95         [ -d "$LOWER" ] || die "LOWER=LOWPER is not a directory"
96         [ -d "$LIVE" ] || die "LOWER=LOWPER is not a directory"
97         # setup $UPPER/dev
98         mkdir -p "$UPPER/dev"
99         mount -t tmpfs -osize=50M tmpfs "$UPPER/dev"
100         mknod -m 622 "$UPPER/dev/console" c 5 1
101         mknod -m 666 "$UPPER/dev/null" c 1 3
102         mknod -m 666 "$UPPER/dev/zero" c 1 5
103         mknod -m 666 "$UPPER/dev/ptmx" c 5 2
104         mknod -m 666 "$UPPER/dev/tty" c 5 0
105         mknod -m 444 "$UPPER/dev/random" c 1 8
106         mknod -m 444 "$UPPER/dev/urandom" c 1 9
107         chown root:tty "$UPPER/dev/console"
108         chown root:tty "$UPPER/dev/ptmx"
109         chown root:tty "$UPPER/dev/tty"
110         ln -sTf /proc/self/fd "$UPPER/dev/fd"
111         ln -sTf /proc/self/fd/0 "$UPPER/dev/stdin"
112         ln -sTf /proc/self/fd/1 "$UPPER/dev/stdout"
113         ln -sTf /proc/self/fd/2 "$UPPER/dev/stderr"
114         ln -sTf /proc/kcore "$UPPER/dev/core"
115         mkdir "$UPPER/dev/shm"
116         mkdir "$UPPER/dev/pts"
117         chmod 1777 "$UPPER/dev/shm"
118
119         # all good so far ; now avoid using the host's networking setup
120         setup_networking "$UPPER"
121
122         OLY="-olowerdir=$3,upperdir=$UPPER,workdir=$5"
123         if ! mount -t overlay "$OLY" $1 $2 ; then
124             umount -R "$UPPER/dev"
125             umount "$UPPER/run"
126             die "Cannot set up the overlay mount $2"
127         fi
128     fi
129
130     echo "Installing $OVERLAYDIR/reaper to $LIVE/.reaper"
131     cp -p $OVERLAYDIR/reaper $LIVE/.reaper
132 }
133
134 start_services() {
135     for S in "$@" ; do
136         service $S start
137     done
138 }
139
140 # find the upperdir option for an overlay mount line
141 getupper() {
142     sed 's/.*upperdir=\([^,]*\).*/\1/'
143 }
144
145 # Check if $1 is "live" and echo the
146 # unshare and reaper process pids
147 is_live() {
148     local NAME=$1
149     local USPID="$(pgrep -f "unshare.* $NAME ")"
150     [ -z "$USPID" ] && return 1
151     echo $USPID $(pgrep -f ".reaper $NAME")
152 }
153
154 list_running() {
155     for C in $(pgrep -a overlay-boot | awk '{print $4}') ; do
156         eval NAME="$(sed "/^NAME=.*/{s|^NAME=||;b};d" $C)"
157         [ -z "$NAME" ] && NAME=$(basename $C .conf)
158         echo $NAME
159     done
160 }