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

Revision 24083, 7.8 KB checked in by broder, 12 years ago (diff)
In reactivate: * geofft's transformation of /etc/pam.d/su was running outside the chroot, and editing the file in place, thus clobbering the symlink. We need to fix all of this in the postinst.
  • Property svn:executable set to *
Line 
1#!/bin/bash
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
24exec >>/var/log/athena-reactivate 2>&1
25
26updflag=/var/run/athena-update-in-progress
27bootflag=/var/run/athena-reboot-after-update
28lockfile=/var/run/athena-snapshot.lock
29snapshotsize=10G
30event=$1
31binddirs="/proc /sys /dev /dev/shm /dev/pts /var/run /var/lock /var/tmp /afs /mit /tmp /media /home"
32addgroups="admin lpadmin adm fuse cdrom floppy audio video plugdev scanner dialout"
33daemons="$(/usr/sbin/policy-rc.d --daemons)"
34
35rootdev=$(awk '$2 == "/" { dev=$1 } END { print dev }' /proc/mounts)
36vgname=$(lvs --noheadings -o vg_name "$rootdev" | awk '{print $1}')
37rootlvname=$(lvs --noheadings -o lv_name "$rootdev" | awk '{print $1}')
38rootlvpath=/dev/$vgname/$rootlvname
39loginlvname=login
40loginlvpath=/dev/$vgname/login
41uloginlvname=login-update
42uloginlvpath=/dev/$vgname/login-update
43
44echo "-----"
45echo "** Beginning Athena reactivation ($event) session at $(date)"
46
47finish() {
48    echo "** Finishing Athena reactivation ($event) at $(date)"
49    echo "-----"
50    echo
51    exit
52}
53trap finish EXIT
54
55v() {
56    echo "** Running:" "$@"
57    echo "** $(date)"
58    "$@"
59}
60
61(
62  flock -x 9
63  case $event in
64  login-start)
65    # Procure a login snapshot and mount it.
66
67    if [ -e "$loginlvpath" ]; then
68      # A login snapshot already exists; perhaps the machine rebooted
69      # during a login.  Clean it up.
70      v lvremove -f "$loginlvpath"
71    fi
72
73    if [ -e "$updflag" ]; then
74      # An update is in progress.  If we get here, we expect there to
75      # be a login-update snapshot created before the update started.
76      # (If we already used it up, /etc/nologin should prevent us from
77      # getting here until the update ends.)  Rename it to login.
78      [ -e "$uloginlvpath" ]
79      v lvrename "$vgname" "$uloginlvname" "$loginlvname"
80    else
81      # No update is in progress.  Create our own snapshot of the root.
82      sync
83      v lvcreate --snapshot --size "$snapshotsize" --name "$loginlvname" \
84        "$rootlvpath"
85    fi
86
87    # Mount the login snapshot.
88    mkdir -p /login
89    v mount -o noatime "$loginlvpath" /login
90
91    # Enable subtree operations on /media by making it a mount point,
92    # then share it.
93    v mount --bind /media /media
94    v mount --make-shared /media
95
96    # Bind-mount a bunch of stuff from the real root into the chroot.
97    for dir in $binddirs; do
98      v mount --bind "$dir" "/login$dir"
99    done
100
101    # Add the user to a bunch of groups in the chroot.
102    for group in $addgroups; do
103      v chroot /login gpasswd -a "$USER" "$group"
104    done
105
106    # Remove the su message intended for quickstations and unlock the
107    # command.
108    sed -i "/su-error/d" "/login/etc/pam.d/su.debathena"
109
110    # There are some daemons that should be running inside the
111    # chroot. For example, changes to CUPS config shouldn't persist
112    # between sessions.
113    #
114    # Start those daemons inside the chroot
115    #
116    # For extra special bonus points, cupsys was renamed to cups at
117    # some point, so we have to try both names and catch the error for
118    # the one that doesn't exist
119    for daemon in $daemons; do
120      v invoke-rc.d $daemon stop || [ $? = 100 ]
121      v chroot /login invoke-rc.d $daemon start || [ $? = 100 ]
122    done
123
124    v touch /login/ClusterLogin
125    v touch /var/run/athena-login
126
127    # Add an schroot.conf entry for the chroot.
128    conf=/etc/schroot/schroot.conf
129    sed -e '/###ATHENA-BEGIN###/,/###ATHENA-END###/d' $conf > $conf.new
130    cat >> $conf.new <<EOF
131###ATHENA-BEGIN###
132[login]
133description=Login root snapshot
134location=/login
135users=$USER
136environment-filter=""
137###ATHENA-END###
138EOF
139    mv $conf.new $conf
140    ;;
141
142  login-end)
143    # Clean-up the temporary file to indicate the logged in state
144    v rm /var/run/athena-login
145
146    # Stop any daemons that were specifically started inside the
147    # chroot
148    for daemon in $daemons; do
149      v chroot /login invoke-rc.d $daemon stop || [ $? = 100 ]
150      v invoke-rc.d $daemon start || [ $? = 100 ]
151    done
152
153    # Clean up any remaining user processes using the bind mounts.
154    # Try sending SIGTERM first to give processes a chance to exit
155    # cleanly.
156    if [ -n "$USER" -a "$USER" != root ]; then
157      for dir in $binddirs; do
158        v su -s /bin/sh "$USER" -c "fuser -kmv -TERM /login$dir" || true
159      done
160      sleep 3
161      for dir in $binddirs; do
162        v su -s /bin/sh "$USER" -c "fuser -kmv /login$dir" || true
163      done
164    fi
165
166    # Clean up any processes using the chroot mountpoint.
167    v fuser -kvm /login || true
168    sleep 2
169
170    # Clean up the bind mounts we made earlier.
171    # If any of these fail, the umount of /login will fail below,
172    # and we will reboot.
173    for dir in $(echo $binddirs|tac -s\ ); do
174      v umount "/login$dir" || true
175    done
176
177    # Unmount /media, which we bind-mounted to itself earlier so it
178    # could be shared and then bind-mounted.
179    v umount /media || true
180
181    # Attempt to unmount /login.
182    if ! v umount /login; then
183      # There may be an unkillable process in I/O wait keeping the
184      # mountpoint busy.  We need to reboot the machine.
185      if [ -e "$updflag" ]; then
186        # ... but we don't want to reboot during an update.  Schedule it
187        # for the end of the update.
188        if [ ! -e /etc/nologin ]; then
189          echo "An update and reboot is in progress, please try again later." \
190            > /etc/nologin.update
191          v ln /etc/nologin.update /etc/nologin
192        fi
193        v touch "$bootflag"
194      else
195        # We can just reboot now.
196        echo "** Rebooting because of umount /login failure"
197        v reboot
198      fi
199    fi
200    v lvremove -f "$loginlvpath"
201
202    if [ -e "$updflag" -a ! -e "$uloginlvpath" ]; then
203      # An update is in progress and we just used up its snapshot.  We
204      # must block further logins until the update completes.
205      if [ ! -e /etc/nologin ]; then
206        echo "An update is in progress, please try again later." \
207          > /etc/nologin.update
208        ln /etc/nologin.update /etc/nologin
209      fi
210    fi
211    ;;
212
213  update-start)
214    # Before starting the update, create a root snapshot for use by
215    # the next login.  We give this snapshot a different name in case
216    # there is already a login in process.
217    if [ -e "$uloginlvpath" ]; then
218      # It already exists; perhaps the machine rebooted during an
219      # update.  Clean it up.
220      v lvremove -f "$uloginlvpath"
221    fi
222    sync
223    v lvcreate --snapshot --size "$snapshotsize" --name "$uloginlvname" \
224      "$rootlvpath"
225
226    # Touch the flag file signifying an update in progress.
227    v touch "$updflag"
228    ;;
229
230  update-end)
231    if [ -e "$uloginlvpath" ]; then
232      # It appears our login snapshot was never used.  Clean it up.
233      v lvremove -f "$uloginlvpath"
234    fi
235
236    if [ -e /etc/nologin.update ]; then
237      # Our login snapshot was used and that login ended before we
238      # did, causing further logins to block.  Now that the update has
239      # ended, we can unblock logins.
240      v rm -f /etc/nologin.update /etc/nologin
241    fi
242
243    if [ -e "$bootflag" ]; then
244      # We need to reboot in order to unmount /login.
245      echo "Rebooting in order to unmount /login."
246      v reboot
247    fi
248
249    # Remove the flag file signifying an update in progress.
250    v rm -f "$updflag"
251    ;;
252  esac
253) 9> $lockfile
Note: See TracBrowser for help on using the repository browser.