Skip to content

Instantly share code, notes, and snippets.

@saltlakeryan
Last active December 28, 2020 10:28
Show Gist options
  • Save saltlakeryan/53b52ef8128865781b95 to your computer and use it in GitHub Desktop.
Save saltlakeryan/53b52ef8128865781b95 to your computer and use it in GitHub Desktop.
Family PC Windows / Linux Dual Boot Setup

Poor Man's SteadyState (or DeepFreeze or ReturnNil or ...)

This is the configuration I have used to set up home PCs to be resistant to the kinds of bugs and malware and spyware that seem to get installed over time on a windows PC. This is in combination with using limited accounts for everyone who uses the PC.

The quick overview is:

  • Partition hard disk into 3 partitions:
    • 1st: Windows C: drive (this is the smallest and is the partition to be "frozen")
    • 2nd: Windows D: drive (an NTFS partition that can be used to store persistent data and shared with Linux)
    • 3rd (and maybe 4th and 5th): Ubuntu installation that may include multiple partitions for linux swap, etc. This is where snapshots of C: drive are stored (though the 2nd partition could be used as well)
  • Install Operating Systems: First windows (setting up C: and D: partitions), then ubuntu, choosing the "install alongside windows" option.
  • Create the first snapshot of C: drive
  • Create scripts and grub configuration so that windows is the default operating system and each reboot uses an imaging tool to restore the snapshot of the C: drive.

Install Windows

I used rufus for creating a windows installer usb from a CD for computer with no CD drive.

  • Delete all partitions
  • Create c: NTFS partition with 30G
  • Create d: NTFS partition with 50G
  • Leave the rest alone for ubuntu
  • Install windows on C:

Install ubuntu

  • Use ubuntu usb or cd to install to remaining partition. Choose to install alongside windows. Accept all the defaults

Set up tools to take snapshots of windows C: partition

Here is a step by step guide to setting up snapshots. It makes some assumptions about which partition windows is on and which version of ubuntu is used. Everything here should work if windows C: drive corresponds to /dev/sda1 in linux and if ubuntu is version 14.04. If that is the case, you can avoid all the following steps by just downloading and running the following script in ubuntu: https://gist.githubusercontent.com/saltlakeryan/ecd4cea06573681044d5/raw/setup-snapstates.sh

  • Customize grub boot options:
    • set windows as default boot option
    • create new menu option called "Restore Windows"
    • edit kernel flags to end with "xcmd=restore 1" (the xcmd=restore is arbitrary flag to use in restore script later, the "1" is single user mode)
  • Accomplish the above by editing /etc/grub.d/40_custom as follows. The assumptions made are that the windows menu entry that was created during ubuntu install is called "Microsoft Windows XP Professional (on /dev/sda1)" and that linux was installed on /dev/sda5. Also, vmlinuz-3.13.0-32-generic and initrd.img-3.13.0-32 are OS specific. If using a different version of ubuntu, those file names may need to be updated :
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.

menuentry 'Restore Windows' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'win-restore' {
	load_video
	gfxmode $linux_gfx_mode
	insmod gzio
	insmod part_msdos
	insmod ext2
	set root='hd0,msdos5'
	linux	/boot/vmlinuz-3.13.0-32-generic root=/dev/sda5 ro xcmd=restore 1
	initrd	/boot/initrd.img-3.13.0-32-generic
}

if [ -z "${need_restore}" ]; then
     set need_restore="yes"
     save_env need_restore
     set default="Microsoft Windows XP Professional (on /dev/sda1)"
  else
     set need_restore=
     save_env need_restore
     set default="Restore Windows"
fi
  • run: sudo update-grub

  • Install partclone to create initial backup

    sudo su
    apt-get install partclone
  • Use backup script to create initial backup. Replace /root/backup-windows.sh with the following:
#!/bin/bash

set -e

mkdir -p /var/backups
BACKUPDATE=`date +%Y-%m-%d_%H_%M_%S`
BACKUPNAME="sda1_$BACKUPDATE.partclone.img.gz"
partclone.ntfs -c -d -F -L /var/log/partclone.log -s /dev/sda1 | gzip -c --fast > /var/backups/$BACKUPNAME
rm -f /var/backups/windows-pristine.img.gz
ln -s /var/backups/$BACKUPNAME /var/backups/windows-pristine.img.gz
  • Run the backup script
sudo /root/backup-windows.sh

Fix grub.cfg to retain default boot item

I found that occassionally the "recordfail" grub environment would cause the default boot menu item to change. If this happens, you can fix it with the following:

Change /etc/grub.d/00_header: from 'if [ "${recordfail}" = 1 ] ; then' to 'if [ 0 -eq 1 ] ; then'

then run 'sudo update-grub' in order to keep that if clause from ever executing.

Root Bashrc Snippet

Append to /root/.bashrc the following:

cat /proc/cmdline | grep 'xcmd=restore'
if [ $? -eq 0 ]
then
	echo "restore mode"
	~/restore-windows.sh
fi

Restore Windows Script

Replace /root/restore-windows.sh with the following (make sure file is executable by root afterwards -- eg. sudo chmod 755 /root/restore-windows.sh):

#!/bin/bash

main() {
	display_warning
	read -p "Do you want to restore windows to original backup? Type 'yes' if so. " yesno
	case $yesno in
		yes ) restore;;
		* ) echo "Not restoring";; 
	esac
}

restore() {
	echo "Restoring with command (in 5 seconds):"
	echo "cat /var/backups/windows-pristine.img.gz | gzip -d -c | partclone.restore -F -L /var/log/partclone-restore.log -O /dev/sda1"
	sleep 5
	cat /var/backups/windows-pristine.img.gz | gzip -d -c | partclone.restore -F -L /var/log/partclone-restore.log -O /dev/sda1
}

display_warning() {
	clear
	cat <<EOF
***************************************
*              WARNING:               *
* About to restore windows to backed  *
* image.  You may lose data.          *
*                                     *
* Press CTRL + C to stop              *
***************************************
EOF
}

main
reboot

RESTORE ON EVERY REBOOT!

If you want to go crazy and restore on every reboot, you can modify the grub config so that the grub environment contains a variable that toggles between true and false every boot. Then you use that variable to decide to either boot into windows or boot into the "Restore Windows" boot option we created. Here are the steps you would take to create this setup:

Edit /boot/grub/grub.cfg

  1. before load_env is called, set the toggling parameter to a default value. Example:
...
set need_restore="yes"
if [ -s $prefix/grubenv ]; then
  set have_grubenv=true
  load_env
fi
...
  1. after all other logic for setting the default menu item (look for "set default=..."), add if statement to use the toggling parameter to boot into the restore mode every other boot. Example:
...
if [ -z "${need_restore}" ]; then
     set need_restore="yes"
     save_env need_restore
  else
     set need_restore=
     save_env need_restore
     set default="Restore Windows"
fi
...

Creating New Snapshots of Windows Drive

Inevitably, you'll want to update the windows image. In that case, just make your updates, reboot into plain ubuntu and run the backup script again (/root/backup-windows.sh). Of course, you could make another boot menu item that does this for you.