I run Gentoo Linux on a variety of laptops, and while I'm generally happy with it, there are some places where the default system just doesn't fit my needs. Sometimes you can just feel how parts of the software were designed for 24/7 servers and not for mobile devices. For example, there are some processes that need to be run frequently, but that you really don't want to kick in when you're out in the field and running on battery power - updatedb, makewhatis or Leafnode's texpire for example. And there are some other maintenance actions that should be performed on a regular basis, too - emerge --sync and backup for example. And most of the time, I just don't feel inclined to manually perform all these tasks when retuning home after a working day. This is why I added a "maintenance mode" to my laptop installations. Usage of this maintenance mode is very straight forward - plug the laptop into the local network, power it on, select "maintenance mode" in the boot loader menu and go away. The system will automatically perform all actions and then power down.
Building this maintenance mode is rather easy, as you'll shortly see. I'll assume you're working with Gentoo - this will most probably work for other distros, but you'll have to adapt paths and other details.
First, we need another runlevel - let's call it "maintenance" for obvious reasons. If you've only got the default runlevel, you can copy and adapt it:
# cp -r /etc/runlevels/default /etc/runlevels/maintenance
I tend to have several different runlevels on my laptops - one for the "home" configuration, another one for the "roadwarrior" setup. Doesn't really matter, you can use any existing runlevel as a template or create a new one from scratch with
# mkdir /etc/runlevels/maintenance
Now we need to select the services we want to run in maintenance mode. As a rule of thumb, try to start as few services as possible. Do not start any *cron* services (anacron, vixie-cron, ...). This is how one of my laptops is configured:
# update-rc show alsasound | boot anacron | away home bbackupd | maintenance bootmisc | boot checkfs | boot checkroot | boot clock | boot consolefont | boot cpufrequtils | away home maintenance cyrus | away home dbus | boot exim | away home hald | away home maintenance hostname | boot keymaps | boot local | away home maintenance localmount | boot modules | boot net.eth0 | home net.eth1 | home net.lo | boot netmount | away home nscd | boot ntp-client | maintenance rmnologin | boot saslauthd | away home maintenance syslog-ng | away home maintenance urandom | boot vixie-cron | away home xdm | away home xinetd | away home
Next, we need to adapt the configuration of the boot loader - in my case, /boot/grub/menu.lst - and add a new menu entry with a softlevel option. The result might look like this:
default 0 timeout 3 splashimage=(hd0,0)/boot/grub/splash.xpm.gz title home root (hd0,0) kernel /boot/kernel root=/dev/ram0 init=/linuxrc ramdisk=8192 real_root=/dev/sda2 softlevel=home initrd /boot/initramfs title on the road root (hd0,0) kernel /boot/kernel root=/dev/ram0 init=/linuxrc ramdisk=8192 real_root=/dev/sda2 softlevel=away initrd /boot/initramfs title maintenance root (hd0,0) kernel /boot/kernel root=/dev/ram0 init=/linuxrc ramdisk=8192 real_root=/dev/sda2 softlevel=maintenance initrd /boot/initramfs
Now we add a new init script to the maintenance runlevel. A nice goodie: vi /etc/init.d/sysmaint already provides you with a nice template - just add some code. This is what my script looks like:
depend() { after * } start() { for script in `ls /etc/sysmaint/scripts/* | sort` do source ${script} done }
As you can see, it simply executes all scripts placed in /etc/sysmaint/scripts in order. Caution: The script file names may not containe spaces because this breaks the iteration. The after * is perhaps not the cleanest way to ensure that this is the last init script run, but it works for me.
Now we need to create and populate the directory /etc/sysmaint/scripts. Here are some of my scripts.
# file 01_logrotate ebegin "Rotating log files" /usr/sbin/logrotate /etc/logrotate.conf eend $?
Pretty straightforward. Don't forget to comment out the corresponding line in /etc/cron.daily/logrotate.cron.
# file 03_news_daily ebegin "Expiring news articles" /usr/sbin/texpire eend $?
Obviously only of interest if you're using Leafnode. Again, don't forget to disable the corresponding cron job if you've enabled it (it's disabled by default).
# file 12_backup_cyrus_mailboxlist # # dumps the Cyrus IMAPD mailbox configuration to /var/backup/cyrus # # remove old backup files ebegin "Cleaning up old Cyrus backup files" mkdir -p /var/backup/cyrus find /var/backup/cyrus -type f -ctime 14 -exec rm \{\} \; eend $? # create new backup ebegin "Backing up Cyrus mailbox list" su - cyrus -c "/usr/lib/cyrus/ctl_mboxlist -d" | bzip2 > /var/backup/cyrus/mboxlist-`date +%Y-%m-%d-%H-%M` eend $?
For Cyrus users only - you get the idea.
# file 20_backup ebegin "Backing up files" /usr/sbin/bbackupctl -q sync # wait until the backup is finished /usr/sbin/bbackupctl -q wait-for-sync 2>&1 | grep -v "not in automatic mode" eend 0
I use BoxBackup in snapshot mode. That's admittedly a crazy way to wait for a backup to finish, but it works quite well.
# file 30_portage_rsync ebegin "Updating the Gentoo Portage repository" /usr/bin/emerge --sync --quiet eend $?
Note that this is only advisable if you've got a local rsync mirror.
# file 40_slocate_updatedb ebegin "Updating the slocate file database" /usr/bin/updatedb eend $?
Again, don't forget to disable the cron job /etc/cron.daily/slocate.
# file 50_makewhatis ebegin "Updating the 'whatis' index" /usr/sbin/makewhatis eend $?
And once again, disable /etc/cron.daily/makewhatis.
And finally...
# file 99_halt /sbin/shutdown -h now
Now there's only one thing left to do - hook up the new init script in the new runlevel:
# chmod 0755 /etc/init.d/sysmaint # update-rc add sysmaint maintenance
As you can see, there is very little magic to it. Adapt it to your needs and have fun.
Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer