#!/bin/sh -e # Copyright 2008 Tobias Tacke, all rights reserved. # This program is free software; you can redistribute it and/or modify it under the GPL-terms (http://dev.perl.org/licenses/gpl1.html) _assert_not_run() { if _is_mount_remain ; then echo "Error: some mounts still exists" exit 1 fi if _is_skelett_remain ; then echo "Error: some parts of /.disk2ram - skelett still exists" exit 1 fi return 0 } _assert_run_complete() { if ! _is_skelett_complete ; then echo "Error: /.disk2ram - skelett is'n complete" exit 1 fi if ! _is_mount_complete ; then echo "Error: mounts are incomplete" exit 1 fi return 0 } _sync_to_state() { rsync -cav --delete --exclude=/lib/dpkg --exclude=/lib/apt --exclude=/cache --exclude=/run --exclude=/lock /.disk2ram/var.volatile/ /.disk2ram/var.state/ || return 1 rsync -cav --delete /.disk2ram/tmp.volatile/ /.disk2ram/tmp.state/ || return 1 return 0 } _sync_to_volatile() { rsync -a --exclude=/lib/dpkg --exclude=/lib/apt --exclude=/cache --exclude=/run --exclude=/lock /.disk2ram/var.state/ /.disk2ram/var.volatile/ || return 1 mkdir /.disk2ram/var.volatile/run || return 1 mkdir /.disk2ram/var.volatile/lock || return 1 rsync -a /.disk2ram/tmp.state/ /.disk2ram/tmp.volatile/ || return 1 return 0 } _mount() { mount -t tmpfs -o size=1024M -o sync -o dirsync -o mode=0755 -o rw -o nosuid -o nodev -o noauto disk2ram.var /.disk2ram/var.volatile || return 1 mount -t tmpfs -o size=256M -o sync -o dirsync -o mode=1777 -o rw -o nosuid -o nodev -o noauto disk2ram.tmp /.disk2ram/tmp.volatile || return 1 mount -o bind /var /.disk2ram/var.state || return 1 # external binds mount -o bind /media/sicher/www /.disk2ram/var.state/www || return 1 mount -o bind /media/sicher/mysql /.disk2ram/var.state/lib/mysql || return 1 mount -o bind /media/sicher/log /.disk2ram/var.state/log || return 1 # Disabled! Not very clever to have multiple tmps # mount -o bind /media/sicher/vartmp /.disk2ram/var.state/tmp || return 1 # mount -o bind /media/sicher/tmp /tmp || return 1 mount -o bind /tmp /.disk2ram/tmp.state || return 1 _sync_to_volatile || return 1 mount -o bind /var/run /.disk2ram/var.state/run || return 1 mount -o bind /var/lock /.disk2ram/var.state/lock || return 1 umount -l /var/lock || return 1 umount -l /var/run || return 1 ln -s /.disk2ram/var.state/cache/ /.disk2ram/var.volatile/cache || return 1 ln -s /.disk2ram/var.state/lib/apt/ /.disk2ram/var.volatile/lib/apt || return 1 ln -s /.disk2ram/var.state/lib/dpkg/ /.disk2ram/var.volatile/lib/dpkg || return 1 mount -o bind /.disk2ram/var.volatile /var || return 1 mount -o bind /.disk2ram/var.state/run /var/run || return 1 mount -o bind /.disk2ram/var.state/lock /var/lock || return 1 mount -o bind /.disk2ram/tmp.volatile /tmp || return 1 return 0 } _force_unmount() { # external binds umount -l /.disk2ram/var.state/www umount -l /.disk2ram/var.state/lib/mysql umount -l /.disk2ram/var.state/log umount -l /tmp umount -l /.disk2ram/tmp.state umount -l /.disk2ram/tmp.volatile umount -l /var umount -l /.disk2ram/var.state umount -l /.disk2ram/var.volatile } _unmount() { _sync_to_state || return 1 umount -l /var/lock || return 1 umount -l /var/run || return 1 umount -l /var || return 1 mount -o bind /.disk2ram/var.state/run /var/run || return 1 mount -o bind /.disk2ram/var.state/lock /var/lock || return 1 umount -l /.disk2ram/var.state/lock || return 1 umount -l /.disk2ram/var.state/run || return 1 # external binds umount -l /.disk2ram/var.state/www || return 1 umount -l /.disk2ram/var.state/lib/mysql || return 1 umount -l /.disk2ram/var.state/log || return 1 umount -l /.disk2ram/var.state || return 1 umount -l /.disk2ram/var.volatile || return 1 umount -l /tmp || return 1 umount -l /.disk2ram/tmp.state || return 1 umount -l /.disk2ram/tmp.volatile || return 1 return 0 } _create_skelett() { mkdir /.disk2ram || return mkdir /.disk2ram/var.state || return 1 mkdir /.disk2ram/var.volatile || return 1 mkdir /.disk2ram/tmp.state || return 1 mkdir /.disk2ram/tmp.volatile || return 1 return 0 } _remove_skelett() { rmdir /.disk2ram/var.state/ || return 1 rmdir /.disk2ram/var.volatile/ || return 1 rmdir /.disk2ram/tmp.state/ || return 1 rmdir /.disk2ram/tmp.volatile/ || return 1 rmdir /.disk2ram/ || return 1 return 0 } _force_remove_skelett() { rmdir /.disk2ram/var.state/ rmdir /.disk2ram/var.volatile/ rmdir /.disk2ram/tmp.state/ rmdir /.disk2ram/tmp.volatile/ rmdir /.disk2ram/ return 0 } _is_mount_complete() { # external binds grep '/media/sicher/www /.disk2ram/var.state/www' /etc/mtab 1> /dev/null || return 1 grep '/media/sicher/mysql /.disk2ram/var.state/lib/mysql' /etc/mtab 1> /dev/null || return 1 grep '/media/sicher/log /.disk2ram/var.state/log' /etc/mtab 1> /dev/null || return 1 grep 'disk2ram.var /.disk2ram/var.volatile tmpfs ' /etc/mtab 1> /dev/null || return 1 grep '/var /.disk2ram/var.state none ' /etc/mtab 1> /dev/null || return 1 grep '/.disk2ram/var.volatile /var none ' /etc/mtab 1> /dev/null || return 1 grep 'disk2ram.tmp /.disk2ram/tmp.volatile tmpfs ' /etc/mtab 1> /dev/null || return 1 grep '/tmp /.disk2ram/tmp.state none ' /etc/mtab 1> /dev/null || return 1 grep '/.disk2ram/tmp.volatile /tmp none ' /etc/mtab 1> /dev/null || return 1 return 0 } _is_mount_remain() { # external binds grep '/media/sicher/www /.disk2ram/var.state/www' /etc/mtab 1> /dev/null && return 0 grep '/media/sicher/mysql /.disk2ram/var.state/lib/mysql' /etc/mtab 1> /dev/null && return 0 grep '/media/sicher/log /.disk2ram/var.state/log' /etc/mtab 1> /dev/null && return 0 grep 'disk2ram.var /.disk2ram/var.volatile tmpfs ' /etc/mtab 1> /dev/null && return 0 grep '/var /.disk2ram/var.state none ' /etc/mtab 1> /dev/null && return 0 grep '/.disk2ram/var.volatile /var none ' /etc/mtab 1> /dev/null && return 0 grep 'disk2ram.tmp /.disk2ram/tmp.volatile tmpfs ' /etc/mtab 1> /dev/null && return 0 grep '/tmp /.disk2ram/tmp.state none ' /etc/mtab 1> /dev/null && return 0 grep '/.disk2ram/tmp.volatile /tmp none ' /etc/mtab 1> /dev/null && return 0 return 1 } _is_skelett_complete() { [ -d /.disk2ram ] || return 1 [ -d /.disk2ram/var.state ] || return 1 [ -d /.disk2ram/var.volatile ] || return 1 [ -d /.disk2ram/tmp.state ] || return 1 [ -d /.disk2ram/tmp.volatile ] || return 1 return 0 } _is_skelett_remain() { [ -d /.disk2ram ] && return 0 [ -d /.disk2ram/var.state ] && return 0 [ -d /.disk2ram/var.volatile ] && return 0 [ -d /.disk2ram/tmp.state ] && return 0 [ -d /.disk2ram/tmp.volatile ] && return 0 return 1 } _stop_all_jobs() { service apparmor stop echo "Stop all jobs..." perl -e " use strict; use warnings; my \$USED_JOBS = { apache2 => 'apache2', openvpn => 'openvpn', cron => 'cron', atd => 'atd', rsyslogd => 'rsyslog', mysqld => 'mysql', dbus => 'dbus', ddclient => 'KILL', acpid => 'acpid', dhclient3 => 'KILL', php5 => 'SLEEP', }; if(!_stop_all()) { print \"failed\"; exit(1); } sub _get_running_jobs { \$| = 1; open(FH, '-|', 'lsof|grep \' /var\''); my \$jobs = {}; while(my \$line = ) { my @line = split(/\W/, \$line); next if(\$line[0] eq \"init\" && \$line =~ m/\/var\/log\/upstart\//); \$jobs->{\$line[0]} = 1; } close(FH); return keys(%\$jobs); } sub _exec { my (\$job, \$cmd) = @_; my \$job_name = \$USED_JOBS->{\$job}; my \$command = \"service \$job_name \$cmd\"; if(\$job_name eq 'KILL') { \$command = \"killall -r \$job\"; } elsif(\$job_name eq 'SLEEP') { \$command = \"sleep 10\"; } elsif(\$job eq 'dhclient3') { \$command = \"dhclient3 -e IF_METRIC=100 -pf /var/run/dhclient.eth0.pid -lf /var/lib/dhcp/dhclient.eth0.leases -1 eth0 -r -x\"; } print \"\n\$cmd \$job: \$command ... \"; my \$result = system(\$command) ? 0 : 1; print ' ... ' . (\$result ? 'done' : 'FAILED!') . \"\n\"; return \$result; } sub _stop_all { my \$failed = 0; foreach my \$name (_get_running_jobs()) { if(!_exec(\$name, 'stop')) { \$failed = 1; } } foreach my \$name (_get_running_jobs()) { print \"process \$name is still running! Please stop it!!!\n\"; \$failed = 1; } return 0 if(\$failed); return 1; } " || exit 1 echo "...done" return 0 } _start_all_jobs() { echo "Start all jobs..." perl -e " use strict; use warnings; my \$USED_JOBS = { apache2 => 'apache2', openvpn => 'openvpn', cron => 'cron', atd => 'atd', rsyslogd => 'rsyslog', mysqld => 'mysql', dbus => 'dbus', ddclient => 'ddclient', acpid => 'acpid', dhclient3 => 1, }; if(!_start_all()) { print \"failed\"; exit(1); } sub _exec { my (\$job, \$cmd) = @_; my \$job_name = \$USED_JOBS->{\$job}; my \$command = \"service \$job_name \$cmd\"; print \"\n\$cmd \$job: \$command ... \"; # START if(\$job eq \"dhclient3\") { \$command = \"dhclient3 -e IF_METRIC=100 -pf /var/run/dhclient.eth0.pid -lf /var/lib/dhcp/dhclient.eth0.leases -1 eth0\"; } my \$result = system(\$command) ? 0 : 1; print ' ... ' . (\$result ? 'done' : 'FAILED!') . \"\n\"; return \$result; } sub _start_all { my \$failed = 0; my %all_jobs = %\$USED_JOBS; foreach my \$name (keys(%all_jobs)) { if(!_exec(\$name, 'start')) { if(!_exec(\$name, 'restart')) { \$failed = 1; } } } return 0 if(\$failed); return 1; } " || exit 1 echo "...done" return 0 service apparmor start } _is_external_cryptdisk_mounted() { grep '/dev/mapper/sdb1_crypt /media/sicher' /etc/mtab 1> /dev/null && return 0 return 1 } _mount_external_cryptdisk() { cryptdisks_start sdb1_crypt || return 1 mount /media/sicher || return 1 return 0 } _handle_external_cryptdisk() { if _is_external_cryptdisk_mounted ; then echo "cryptdisk is already mounted" return 0 fi echo "mounting cryptdisk..." if _mount_external_cryptdisk ; then echo "...done" return 0; fi echo "failed" exit 1 } echo "disk2ram $1 ..." case $1 in status) if _is_mount_complete && _is_skelett_complete ; then echo "started" exit 0 fi if ! _is_skelett_remain && ! _is_mount_remain ; then echo "stopped" exit 0 fi echo "corrupt" exit 1 ;; start) if _is_mount_complete && _is_skelett_complete ; then echo "Nothing to do. Still started" exit 0 fi _assert_not_run _handle_external_cryptdisk if ! _create_skelett ; then echo "Error: can't create skelett" exit 1 fi _stop_all_jobs if ! _mount ; then echo "Error: can't mount" exit 1 fi _assert_run_complete _start_all_jobs echo "started" ;; sync) if ! _is_mount_complete || ! _is_skelett_complete ; then echo "Error: disk2ram is not correct running. Sync without correct state is dangerous! Perform manual sync if you like (remove option '-n' to execute)" echo " rsync -xcav -n --delete --exclude=/lib/dpkg --exclude=/lib/apt --exclude=/cache --exclude=/run --exclude=/lock /.disk2ram/var.volatile/ /.disk2ram/var.state/" echo " rsync -xcav -n --delete /.disk2ram/tmp.volatile/ /.disk2ram/tmp.state/" exit 1 fi _stop_all_jobs _sync_to_state _start_all_jobs ;; stop) if ! _is_skelett_remain && ! _is_mount_remain ; then echo "Nothing to do. Still stopped" exit 0 fi _assert_run_complete _stop_all_jobs _sync_to_state if ! _unmount ; then echo "Error: can't unmount" exit 1 fi if ! _remove_skelett ; then echo "Error: can't remove skelett" exit 1 fi _assert_not_run _start_all_jobs echo "stopped" ;; restart|reload|force-reload) echo "Error: argument '$1' not supported" exit 3 ;; force-umount) if [ "$2" != 'do-it' ] ; then echo "Warning: that will result in loss of data! Say: '/etc/init.d/disk2ram force-umount do-it' to execute this" exit 3 fi _force_unmount ;; force-remove_skelett) if [ "$2" != 'do-it' ] ; then echo "Warning: that will result in loss of data! Say: '/etc/init.d/disk2ram force-remove_skelett do-it' to execute this" exit 3 fi _force_remove_skelett ;; *) echo "Usage: /etc/init.d/disk2ram {start|stop|status|sync|force-remove_skelett|force-umount}" exit 3 ;; esac exit 0