source: trunk/debathena/config/reactivate/debian/athena-login-snapshot @ 23155

Revision 23155, 5.5 KB checked in by ghudson, 13 years ago (diff)
In reactivate: * Rewrite to use login chroots.
  • Property svn:executable set to *
Line 
1#!/bin/sh
2
3# Usage: athena-login-snapshot {login-start|login-end|update-start|update-end}
4
5# This script contains the logic to manage LVM snapshots of the root
6# volume.
7
8# Requirements:
9
10# * The root volume is a logical volume
11# * The volume group of the root volume has 21GB of free space for us
12#   to use.
13
14# Login snapshots will have a 10GB copy-on-write store for
15# modifications to the snapshot.  This backing store will typically
16# only be used if a user installs additional packages in the login
17# root.
18
19# This script may choose to reboot the machine in order to clear
20# I/O-bound process entries blocking the unmount of /login, though
21# that circumstance should be fairly rare.
22
23set -e
24
25updflag=/var/run/athena-update-in-progress
26bootflag=/var/run/athena-reboot-after-update
27lockfile=/var/run/athena-snapshot.lock
28snapshotsize=10G
29event=$1
30binddirs="/proc /sys /dev /var/run /var/lock /afs /mit /tmp /media /home"
31addgroups="cdrom floppy audio video plugdev"
32
33rootdev=$(awk '$2 == "/" { dev=$1 } END { print dev }' /proc/mounts)
34vgname=$(lvs --noheadings -o vg_name "$rootdev" | awk '{print $1}')
35rootlvname=$(lvs --noheadings -o lv_name "$rootdev" | awk '{print $1}')
36rootlvpath=/dev/$vgname/$rootlvname
37loginlvname=login
38loginlvpath=/dev/$vgname/login
39uloginlvname=login-update
40uloginlvpath=/dev/$vgname/login-update
41
42(
43  flock -x 9
44  case $event in
45  login-start)
46    # Procure a login snapshot and mount it.
47
48    if [ -e "$loginlvpath" ]; then
49      # A login snapshot already exists; perhaps the machine rebooted
50      # during a login.  Clean it up.
51      lvremove -f "$loginlvpath"
52    fi
53
54    if [ -e "$updflag" ]; then
55      # An update is in progress.  If we get here, we expect there to
56      # be a login-update snapshot created before the update started.
57      # (If we already used it up, /etc/nologin should prevent us from
58      # getting here until the update ends.)  Rename it to login.
59      [ -e "$uloginlvpath" ]
60      lvrename "$vgname" "$uloginlvname" "$loginlvname"
61    else
62      # No update is in progress.  Create our own snapshot of the root.
63      sync
64      lvcreate --snapshot --size "$snapshotsize" --name "$loginlvname" \
65        "$rootlvpath"
66    fi
67
68    # Mount the login snapshot.
69    mkdir -p /login
70    mount "$loginlvpath" /login
71
72    # Bind-mount a bunch of stuff from the real root into the chroot.
73    for dir in $binddirs; do
74      mount --bind "$dir" "/login$dir"
75    done
76
77    # Add the user to a bunch of groups in the chroot.
78    for group in $addgroups; do
79      chroot /login gpasswd -a "$USER" "$group"
80    done
81
82    # Prevent daemons from starting inside the chroot.
83    (echo "#!/bin/sh"; echo "exit 101") > /login/usr/sbin/policy-rc.d
84    chmod 755 /login/usr/sbin/policy-rc.d
85
86    # Add an schroot.conf entry for the chroot.
87    conf=/etc/schroot/schroot.conf
88    sed -e '/###ATHENA-BEGIN###/,/###ATHENA-END###/d' $conf > $conf.new
89    cat >> $conf.new <<EOF
90###ATHENA-BEGIN###
91[login]
92description=Login root snapshot
93location=/login
94users=$USER
95environment_filter=""
96###ATHENA-END###
97EOF
98    mv $conf.new $conf
99    ;;
100
101  login-end)
102    # Clean up any processes using the mountpoint.
103    fuser -km /login > /dev/null || true
104    sleep 2
105
106    # Clean up the bind mounts we made earlier.
107    for dir in $binddirs; do
108      umount "/login$dir"
109    done
110
111    # Attempt to unmount /login.
112    if ! umount /login; then
113      # There may be an unkillable process in I/O wait keeping the
114      # mountpoint busy.  We need to reboot the machine.
115      if [ -e "$updflag" ]; then
116        # ... but we don't want to reboot during an update.  Schedule it
117        # for the end of the update.
118        if [ ! -e /etc/nologin ]; then
119          echo "An update and reboot is in progress, please try again later." \
120            > /etc/nologin.update
121          ln /etc/nologin.update /etc/nologin
122        fi
123        touch "$bootflag"
124      else
125        # We can just reboot now.
126        reboot
127      fi
128    fi
129    lvremove -f "$loginlvpath"
130
131    if [ -e "$updflag" -a ! -e "$uloginlvpath" ]; then
132      # An update is in progress and we just used up its snapshot.  We
133      # must block further logins until the update completes.
134      if [ ! -e /etc/nologin ]; then
135        echo "An update is in progress, please try again later." \
136          > /etc/nologin.update
137        ln /etc/nologin.update /etc/nologin
138      fi
139    fi
140    ;;
141
142  update-start)
143    # Before starting the update, create a root snapshot for use by
144    # the next login.  We give this snapshot a different name in case
145    # there is already a login in process.
146    if [ -e "$uloginlvpath" ]; then
147      # It already exists; perhaps the machine rebooted during an
148      # update.  Clean it up.
149      lvremove -f "$uloginlvpath"
150    fi
151    sync
152    lvcreate --snapshot --size "$snapshotsize" --name "$uloginlvname" \
153      "$rootlvpath"
154
155    # Touch the flag file signifying an update in progress.
156    touch "$updflag"
157    ;;
158
159  update-end)
160    if [ -e "$uloginlvpath" ]; then
161      # It appears our login snapshot was never used.  Clean it up.
162      lvremove -f "$uloginlvpath"
163    fi
164
165    if [ -e /etc/nologin.update ]; then
166      # Our login snapshot was used and that login ended before we
167      # did, causing further logins to block.  Now that the update has
168      # ended, we can unblock logins.
169      rm -f /etc/nologin.update /etc/nologin
170    fi
171
172    if [ -e "$bootflag" ]; then
173      # We need to reboot in order to unmount /login.
174      echo "Rebooting in order to unmount /login."
175      reboot
176    fi
177
178    # Remove the flag file signifying an update in progress.
179    rm -f "$updflag"
180    ;;
181  esac
182) 9> $lockfile
Note: See TracBrowser for help on using the repository browser.