Ubuntu Installation to a USB Stick

version 1.1
author K. Shaffer

It's wonderful to have a portable Linux environment on a USB stick -- I use one for doing my everyday tasks, and for demonstrating Linux on friends' computers. You can set up a bootable USB stick as either a "live" media on a stick as small as 1G (2G recommended) or as a standard installation on a stick 4G or larger. Setting up a live USB install media with some persistent storage is easy since creation of such a stick has been a menu item since Ubuntu distribution 9.04 (Jaunty). For instructions for stick creation on a Windows host see: https://wiki.ubuntu.com/LiveUSBPendrivePersistent and on a Mac see: http://www.makeuseof.com/tag/how-to-create-an-ubuntu-installation-USB-on-the-mac/

The big benefit of a live media of course is the ability to install Ubuntu to friends' hard disks. Easy as these live media installations are, they will still benefit from the erase-block modifications to the USB stick described below in the partitioning section if an ext2 filesystem is also included on the stick for persistent storage. Boot times on live media sticks may be reduced to less than 45 seconds by typing three quick returns at the purple screen with the little keyboard and man. ( first for manual selection, second for language selection, third to select "Try Ubuntu" ). Since the live-media installations are pretty well covered elsewhere, This article concentrated on doing a standard installation to a 4G or 8G stick, with the modifications done to improve speed and longevity.

The Ubuntu "System/Administration/USB Startup Disk Creator" menu item creates a "Live USB" on a 2G stick which may be used for installing Linux as well as giving you up to 1G of writable space. This sort of installation has a compressed, read-only filesystem, and runs quite acceptably. The trick of manually forcing the text menu at bootup instead of allowing the graphics menu to appear will half the boot time. For systems with a writable partition, first redo the partitioning and set the head/sectors-track geometry to 4/16, as described below. One caution, if you make a second partition labeled casper-rw, ensure it starts on a cylinder boundary and a 4M boundary. When making the first partition with a size (e.g. +910M), you may end the first partition in the middle of a cylinder. Also, lately, I have been having permission problems running the startup disk creator, so I drop back to a terminal and run sudo usb-creator-gtk. I have had good success splitting a 2G stick into two 1G partitions, the first a vfat (either type 6 (FAT16) or type c (FAT32), and the second a linux partition on which I put an ext2 filesystem with mkfs -text2 /dev/sdcx . Start the partitions on 4M boundaries. Run mkdosfs to put a FAT filesystem for the first partition, and you may then run the "create startup disk" menu item. If you experience any permission problems, run sudo usb-creator-gtk.

A standard desktop direct install to a 4G USB stick will use about 60%, leaving the rest for you. A little initial preparation of the stick is necessary to allow for increased life and snappier performance: http://wiki.laptop.org/go/How_to_Damage_a_FLASH_Storage_Device

When installing a standard filesystem on flash memory, you need to be aware of buildup of unwanted files, and of frequency of writes to certain locations. After every update, all the package files are left in /var/cache/apt/archives. Putting this directory into ram will automatically "clean up" these package files at reboot. Lots of old copies of system log files are also kept. There are options to limit the number of old copies of log files, but writing the log files to a ramdisk means they do not cause any flash memory wear. If there be problems however, you should remember to make a permanent copy of appropriate log files.

Assumptions

1) The USB stick will be set up from a running Linux system, and standard Linux/Hurd tools are available (fdisk, cfdisk, mke2fs, cp, df, dmesg, free, mount, tail, vi, ... ). A directory has been set up with all the scripts in the appendices, and after installation, the scripts will be run from this directory.
2) The USB stick will be the installation target of a live media (CD-ROM or usb).
3) The install system can access a USB drive, but does not have to be able to boot from one.
4) Explicit instructions below assume a Gnome desktop -- use the equivalent actions for your system.
5) Not all USB sticks/cards have equal performance. I have used Pqi and Kingston SD4 cards, Kingston Datatraveler, HP, Pqi, and Patriot 4G sticks with good success, but of this group, the HP sticks had the best performance. Check the packaging or vendor web site for any indication of the media speed. The cards usually indicate class 4 (4MB/sec) or class 6 (6MB/sec). Sometimes the ambiguous "x" nomenclature is used. x could mean either 1.2M or 150k. 6x is probably 7.2MB/Sec, 10x is probably 12MB/sec, but 150x is only 24M/sec read and 19.5M/sec write for Pqi 16G cards. I am starting to see more speed indications on the USB sticks for sale, both read and write speeds. http://en.wikipedia.org/wiki/Secure_Digital#Speeds has the table mapping the speed to class. Notice that read speeds are faster than write speeds, and ideally, the vendor will report both.
6) The flash memory erase block size is assumed to be 128k. This perhaps should actually be 256k for sticks larger than 4G, but I don't know how to tell for USB sticks. Actual cards, mounted at mmcblk0p1 for instance, will have erase block information in a card specific data (csd) file. This csd file is located at /sys/class/block/mmcblk0/device/csd. One 2G SD card had a 32k erase block size, another had a 64k size. Google ProdManualSDCardv1.9.pdf for the bit definitions (right to left) in the csd file, or use the script in Appendix I to output the erase-block size for an SD card with a csd file.
7) The USB stick will be rebooted regularly, so buildup of temporary files in the ramdisks will not be a problem.

Planning

First check for any known USB problems on the machine used to create the USB stick and the eventual target machine: http://www.USBman.com/Guides/Computers%20with%20Known%20USB%20Problems.htm No sense wasting time on a machines with USB problems trying to create a USB stick.

Flash media has a limited number of writes, and blocks are grouped -- a write of one block forces all the blocks in the group to be rewritten. The size of this group of blocks is known as the "erase block size". Some thought is needed to position partitions and filesystem parts to minimize unnecessary group rewrites. Space is a critical resource on these USB sticks, so consider forgoing boot and swap partitions. A standard Ubuntu desktop installation will fit nicely on a 4G card or stick, leaving about 1G free.

Historically, a boot partition allowed positioning the kernel within the first 1024 cylinders of a disk for BIOSes whose address space was limited. Some older machines may still need this. If the 1024 limit is not a factor on your machine, then doing away with a boot partition will not waste the unused space in such a partition. If you are setting up a generic stick which will boot in the maximum number of (older) machines, maybe you do want a boot partition for the first partition. I have not had any problems with the 1024 cylinder limit myself, but I have heard of problems booting a 16G stick on an old laptop which boots 4G sticks without problems, and the 16G stick boots on other machines. This is the sort of problem which may be caused by this 1024 cylinder limitation. The rest of this article assumes no separate boot partition is needed.

Swap space simulates having more, slow, memory on your computer. It may not even be needed, but if it is, may be added later as a file or as a separate USB stick. If you are on a GNU/Linux machine with similar memory to the one on which you will be running the USB stick, check swap usage with "free", "swapon -s", or "cat /proc/swap". Newer machines probably have memory to spare, so seeing no swap activity is typical. Hibernation capability may be lost without swap. If swap activity is seen or hibernation is needed, then decide if the convenience of having swap on the USB boot stick is worth the space and possibly shortened lifespan of the stick (assuming the writes to the swap device wear the stick out before anything else). The alternative solution is to use a second small (cheap) 0.5-2G stick for swap. This may extend the life of the larger (more expensive) boot stick.

The stick partition start (and end) will be selected to be aligned with the presumed size of 128k for erase block groups, and moved a bit from the start of the disk. I use a non-journaling filesystem, ext2, the with block size set to 4096 (default) and the groupsize set to 32768 (also the default). The standard installer format should be just fine for your ext2 filesystem. However, my biggest problem installing to these sticks is after completion, finding something has reset my partition geometry, and booting takes two minutes instead of one minute. The problem is not consistent, and I'm almost at the point of just saying, after partitioning, put the fileystem on, and reboot! Then check the stick again for the proper head-sectors/track geometry before starting to install.

Partitioning the USB stick

You will lose any data on the disk when you re-partition it, so save what you want from it first. Insert the USB stick drive (or memory card). If the media is automounted, an icon will appear on the desktop, and a window may open. Use df, mount, dmesg, or sudo fdisk -l to determine the device -- see Appendix II for details.

The below assumes sdc for the device -- make sure you use the appropriate device for your system.

The information from the below link: http://wiki.laptop.org/go/How_to_Damage_a_FLASH_Storage_Device resulted in the selection of the partition parameters. I guessed my 4G USB devices were of the 128k write block instead of the 256k block variety, but I haven't figured out how to tell. I can find nothing which corresponds to the SD card's "csd" file, which has all this important information.

Examine the device to determine the default parameters and partitioning. a 4G Kingston stick had h=5 s=32 and the partition start at 81920 sectors of 512 bytes -- about a 40 meg offset, and not even a power of 2. If there is any way to use this initial information to determine erase block size, I do not know it. Choose heads=4, sectors/track=16 and partition start at 8192. Zero the existing partition table and reset the heads and sectors/track. This may be done within fdisk when the partition is made, or on the command line (writing out the changes, then quiting):
cfdisk -z -h 4 -s 16 /dev/sdc

Note, the above command performed as I expected on a 4G sd card inserted in mmcblk0, but several 4G USB sticks failed to get the expected h and s. This unexpected resetting of h and s has also occurred when using fdisk. Reset them in fdisk when setting up the partition if necessary. See the below output. There appears to be some buffering which does not get flushed as expected, as I have seen this sort of problem frequently. Try removing the media right after exiting fdisk, and reinserting. Check with fdisk to ensure the proper number of heads and sectors/track is present. Resolve this before making the filesystem.

If you decide to make a swap area on the USB stick, figure out its size in cylinders so you can make the root (first partition) smaller by that amount. With fdisk, the m command is for help, which lists all the commands. Ensure that the heads and sectors are still set, or set them now, in the x=advanced section of commands (h for heads, s for sectors, r to return to main menu). See Appendix III for the explicit commands used for partitioning, and for some potential problems.

You may manually make the filesystem now, or do this at install time, since the defaults are 4096 blocksize and 32768 blocks/group. Doing the filesystem manually allows you to copy the superblock backups to aid in any future recovery efforts.


sudo mkfs.ext2 -b 4096 -g 32768 /dev/sdc1
...
  Superblock backups stored on blocks: 
    32768, 98304, 163840, 229376, 294912, 819200, 884736

Installation

The USB stick or card is now ready for a standard installation from a live media.

Boot your install media -- if your install media is also a USB stick, and you have problems booting with two USB sticks present, you might need to insert the target stick after the boot starts. Select the manual partitioning option, ("Something Else" in the 11.04 installation) and select sdc1 which should be the first partition on the target USB (sda is the Windows internal disk, sdb the USB installer, so sdc should be the target USB). Check the sizes, to confirm the disk lettering, because sometimes the sdb and sdc are reversed. Reject all offers to repartition the card, so what was set up above will be used. Formatting the ext2 filesystem at install is OK since the defaults are what we want. Continue through all warnings about missing swap, or illegal attributes on the filesystem (not seen on 11.04 installation).

Edit the sdc1 partition info, select ext2, / (root), and format if not done earlier.

ALWAYS check the location grub will put its boot block. After setting up the sdc1, the boot block should automatically change from the sda default to sdc (well, it did in the 10.10 installation, but not in the 11.04). Change it if it did not automatically get set to sdc device (Note, not the partition sdc1). It needs to be the target stick, and it better be a real device, /dev/sdx, not a grub device like hd0 (9.10 bug). Regardless of your install media, hd0 is most likely the Windows hard disk, and that is not a place most people want to rewrite when setting up a bootable USB.

There will be several warnings of problems -- no swap space (assuming you have no swap partition), and possibly invalid file attributes if you did a manual format, all of which may be ignored.

Installation should take about an hour on a USB 2.0 system. A 2-3 hour install probably indicates a problem with the disk geometry or filesystem type. After installation completes, remove the install media, and Check that the BIOS boot order has the USB stick before the hard disk (in case your live media was a CD-ROM).

Next, tailor the new USB stick before booting it the first time. In fstab, put /tmp and /var/log into ram, and put some links into ram from places like 1) /var/cache/apt/archives (where new package files are downloaded for updates) and 2) the first user's firefox cache. See Appendix V for the modifications collected into the script preboot_filemods. Other modifications this script performs are: using noatime and nodiratime on /, making storage locations for the ram based users' homes, modifying rc.local to set up the ram disk, put in a splash screen for grub and modify some boot text colors, and copy the boot modifications scripts to the new stick's first user's home. Get the script onto a running Linux system, mount the new USB stick and run the script. You may try booting from the stick now if the install media was a CD-ROM. If your install media was another USB, decide if you want to edit the grub.cfg file as described in the next paragraph. If you choose to edit grub.cfg, manually add write permission to the grub.cfg file first (and remove it afterwards).

Force the grub screen to appear if there is no other operating system on the system by holding down the shift key. If your install media was a USB stick, then you need to edit the grub boot commands. At the grub menu screen, enter "e" to edit the grub commands. Bug 384633 causes an attempt to boot linux off root=/dev/sdc1, which should not exist after the USB install media has been removed (the rebooting target will typically be sdb). Other things will be wrong in the grub.cfg file, but that sdc1 is the killer for the 10.10 release. For a 10.x installation, change the sdc1 to sdb1 and then boot with control X. For an 11.04 system, change every sdc to sdb in the boot paragraph for an 11.04 system (There is a set root= line which needs to be changed for the boot to work, in addition to the linux... line. Notice the (hdx,msdosy) items -- I recommend changing these to be hd0 for the Windows paragraphs, and hd1 for the Linux USB paragraphs. I am uncomfortable seeing Windows on sdbx since I have seen it on sda for years. Also, the disks may switch with any run of update-grub, and I prefer my devices to be consistent.

After the first boot, login and immediately start a terminal and run:
sudo update-grub
This should fix all the grub.cfg problems, and normal booting should work. The expected outcome is root on sdb1, and Windows on sdax.

The modification scripts in the appendices have been copied into the first user's "mods" directory by the preboot_filemods script. Create the .mozilla directory by running firefox or copying from an existing .mozilla on another system. This will allow the Cache link to be set up. The next script to run is the firstlogin_usermods with two names for the two ram homed users. The first name will be put into the group of the first user on the system, the second name will be just for guest use.

Reboot the system so the ram-based HOMEs for the new users are present. Log in as the ram-based users and tailor their desktops. Then login as the first user and run the ramtailoring_usermods. The changes to the /tmp/HOMEs will be saved and be present at the next reboot. The only release specific (11.04) edits performed were for the grub splash screen. If you set up an earlier release, you might want to fix the 05_debian_theme to use the file "splash.png". I find these USB sticks highly usable, and they are my primary login environment. Of course, backup regularly, but I have to admit, I have not lost a stick due to errors even after several year's use.

Appendix I -- Card Specific Data Interpretation

Erase block sizes are easy to determine for SD cards. The information is present in a file, which may be interpreted by the below script.

A Kingston 4G SD card has the following /sys/class/block/mmcblk0/device/csd:
400e00325b5900001d877f800a400000

./csd.py kingston.csd Erase block size is 65536 bytes.

The csd.py script follows.

#!/usr/bin/env python
# Read SD card Card Specific Data register bits for the erase block size
# NOT valid for Multi Media Cards!

# Debian GNU/Linux
# Copyright (C) 2011 Free Software Foundation, Inc.
# This is free software;  for copying, see the GNU General Public
# License version 2, or (at your option) any later version.
# There is NO warranty.

import sys

def unstuff(x, start, size):
    return (x >> start) & (2**size - 1)

def main(name, args):
    if len(args) != 1:
        print "Syntax: %s <>" % (name, )
        print "Example: %s /sys/class/block/mmcblk0/device/csd" % (name, )
        return 100

    # read in 128 bits of csd register
    csd = int(file(args[0]).read(), 16)

    write_block_size = 2**unstuff(csd,22,4)
    erase_sector_size = unstuff(csd,39,7)+1
    erase_block_size = write_block_size*(erase_sector_size)
    print "Erase block size is %d bytes." % (erase_block_size)

sys.exit(main(sys.argv[0], sys.argv[1:]))

Appendix II -- Determining the Target Device

df
  Filesystem           1K-blocks      Used Available Use% Mounted on
  /dev/sdb7             14112620   6632504   6763220  50% /
  ...
  /dev/sdc1              3969024        32   3968992   1% /media/disk

or

mount
  ...
  /dev/sdc1 on /media/disk type vfat (rw,nosuid,nodev,uhelper=hal,shortname=mixed,uid=1000,utf8,umask=077,flush)

close the filesystem window if one opened at the automount, and unmount the media (the icon should disappear). -- right click on the drive desktop icon, then select "safely remove" if present, or "Unmount volume" if not. Wait few seconds to see if the automount occurs again (problem since 10.10), and repeat the "safely remove" if it does.

If the automount does not run (it is a configuration item), get the device from the system messages, which the dmesg command outputs. tail will just get lines from the end of the output.

dmesg | tail -23

[ 5524.328108] USB 1-3: new high speed USB device using ehci_hcd and address 5
[ 5524.463443] USB 1-3: configuration #1 chosen from 1 choice
[ 5524.464185] scsi6 : SCSI emulation for USB Mass Storage devices
[ 5524.464674] USB-storage: device found at 5
[ 5524.464679] USB-storage: waiting for device to settle before scanning
[ 5529.464419] USB-storage: device scan complete
[ 5529.466864] scsi 6:0:0:0: Direct-Access     Multi    Flash Reader     1.00 PQ: 0 ANSI: 0
[ 5529.797821] sd 6:0:0:0: [sdc] 7954432 512-byte hardware sectors: (4.07 GB/3.79 GiB)
[ 5529.799666] sd 6:0:0:0: [sdc] Write Protect is off
[ 5529.799672] sd 6:0:0:0: [sdc] Mode Sense: 03 00 00 00
[ 5529.799678] sd 6:0:0:0: [sdc] Assuming drive cache: write through
[ 5529.804687] sd 6:0:0:0: [sdc] 7954432 512-byte hardware sectors: (4.07 GB/3.79 GiB)
[ 5529.808673] sd 6:0:0:0: [sdc] Write Protect is off
[ 5529.808679] sd 6:0:0:0: [sdc] Mode Sense: 03 00 00 00
[ 5529.808685] sd 6:0:0:0: [sdc] Assuming drive cache: write through
[ 5529.808698]  sdc: sdc1
[ 5529.810505] sd 6:0:0:0: [sdc] Attached SCSI removable disk
[ 5529.810662] sd 6:0:0:0: Attached scsi generic sg3 type 0

The device is sdc above, and mmcblk0 for the card below.

...dmesg output for a directly inserted memory card (automounts :
[ 4833.619838] mmc0: new SD card at address e624
[ 4833.646052] mmcblk0: mmc0:e624 SD02G 1.89 GiB 
[ 4833.646179]  mmcblk0: p1

sudo fdisk -l  

All disk details will be shown, pick out the target by size and position (last) in the list.

Appendix III -- Partitioning

   $ sudo fdisk /dev/sdc
   [sudo] password for user: 

If not done with cfdsk, set the heads and sectors/track

   x (advanced commands)
   h (set the heads to 4)
   s (set the sectors/track to 16)
   r (return to main menu)

Set the units to sectors (which start at 0) with the u command, then make a root partition:


   u (toggle units to sectors from cylinders)

Delete the old partition if not already done with cfdisk

   d (delete the existing partition)

Create a new partition

   n ( new partition),
   p (primary partition),
   1 (first primary),
    8192 (start sector, 4M and a power of 2),
    XXXX (end sector at end of the available sectors or back by the swap
          size in sectors)  Technically, this should be one less than a
          multiple of 8192, but I no longer bother.

The type of the partition should default to linux type -- check with p to print out the partition information. Set it explicitly with the t command with type = 83. Make it bootable:


   a (select first partition)

If you want a swap partition, make it now as the next primary.

   n (new partition)
   p (primary)
   2 (number 2)
   XXXX+1 (starting on the next free sector beyond the end of the first, which
           should be a multiple of 8192.
   YYYY (end of the swap partition, (as one less than a multiple of 8192),

Set its type to 82, with the t command.

   t (Set the type)
   2 (partition 2)
   82 (swap type)

Exit fdisk saving the new configuration:

   w (write out the new info, and exit)

Example, checking with fdisk after setting everything:

$ sudo fdisk /dev/sdc
[sudo] password for user: 

The number of cylinders for this disk is set to 122496.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
   (e.g., DOS FDISK, OS/2 FDISK)

Command (m for help): p

Disk /dev/sdc: 4013 MB, 4013948928 bytes
4 heads, 16 sectors/track, 122496 cylinders
Units = cylinders of 64 * 512 = 32768 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sdc1             129      122496     3915776   83  Linux

Command (m for help): u
Changing display/entry units to sectors

Command (m for help): p

Disk /dev/sdc: 4013 MB, 4013948928 bytes
4 heads, 16 sectors/track, 122496 cylinders, total 7839744 sectors
Units = sectors of 1 * 512 = 512 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sdc1            8192     7839743     3915776   83  Linux

Command (m for help): q

Partitioning Problems

1) Sticks that appear identical may not be identical internally. Makes little difference, unless you are trying to copy a stick with dd, and the target is smaller than the source.

The first Kingston 4G stick's initial information:

Disk /dev/sdc: 4013 MB, 4013948928 bytes
5 heads, 32 sectors/track, 48998 cylinders
Units = cylinders of 160 * 512 = 81920 bytes
Disk identifier: 0x00000000
   Device Boot      Start         End      Blocks   Id  System
/dev/sdc1   *          51       48999     3915840    c  W95 FAT32 (LBA)

An "identical" Kingston 4G stick purchased 6 months later:

Disk /dev/sdb: 4009 MB, 4009754624 bytes
51 heads, 51 sectors/track, 3010 cylinders
Units = cylinders of 2601 * 512 = 1331712 bytes
Disk identifier: 0x04030201

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1               1        3011     3915204    c  W95 FAT32 (LBA)

2) The cfdisk and/or fdisk setups may not be completely correct. Look at the cylinders below after doing the fdisk setup for heads and sectors/track -- they are the same as above, and did not get reset properly.

Disk /dev/sdb: 4009 MB, 4009754624 bytes
4 heads, 16 sectors/track, 3010 cylinders, total 7831552 sectors
Units = sectors of 1 * 512 = 512 bytes
Disk identifier: 0x04030201

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1            8192     7831551     3911680   83  Linux

Same problem when using cylinder units:


Disk /dev/sdb: 4009 MB, 4009754624 bytes
4 heads, 16 sectors/track, 3010 cylinders
Units = cylinders of 64 * 512 = 32768 bytes
Disk identifier: 0x04030201

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1             129      122368     3911680   83  Linux

Command (m for help): q

Recheck your target USB just before installation, and again just afterwards for the correct geometry of heads and sectors/track.

Appendix IV -- Make a Filesystem

The ext2 filesystem menu choice at installation is fine, but creating a filesystem manually lets you ensure it is the correct size and lets you grab a copy of the superblocks for later use.

sudo mkfs.ext2 -b 4096 -g 32768 /dev/sdc1
  mke2fs 1.41.4 (27-Jan-2009)
  Filesystem label=
  OS type: Linux
  Block size=4096 (log=2)
  Fragment size=4096 (log=2)
  244800 inodes, 978944 blocks
  48947 blocks (5.00%) reserved for the super user
  First data block=0
  Maximum filesystem blocks=1002438656
  30 block groups
  32768 blocks per group, 32768 fragments per group
  8160 inodes per group
  Superblock backups stored on blocks: 
    32768, 98304, 163840, 229376, 294912, 819200, 884736

  Writing inode tables: done                            
  Writing superblocks and filesystem accounting information: done

  This filesystem will be automatically checked every 25 mounts or
  180 days, whichever comes first.  Use tune2fs -c or -i to override.

Appendix V -- Preboot File Modifications Script

After successfully installing to a usb stick, I usually perform the modifications in the preboot_filemods script before booting the stick for the first time. Of course, this requires a running system, but even the live media will be sufficient to run the script. The modifications are designed to put into ram some parts of the filesystem which will be written to. Mount the new USB stick, and run the below script with an argument specifying the device or its mount point: e.g.

./preboot_filemods sdc
#=====START preboot_filemods =====
#!/bin/sh
#-t- preboot_filemods - filesystem mods for the usb stick setup
# The install has been done to the stick, these mods are then done
# before the stick is booted.
# Arg 1:  The target usb device to be modified or its mount point.

# Debian GNU/Linux
# Copyright (C) 2011 Free Software Foundation, Inc.
# This is free software;  for copying, see the GNU General Public
# License version 2, or (at your option) any later version.
# There is NO warranty.

USAGE="$0 \n   e.g. $0 sdc"

# Check that the arg has been given
if [ $# -lt 1 ] ; then
  echo $USAGE
  exit 1
fi
TARGET="$1"

# Check that the arg is a block device
if [ -b /dev/"$TARGET" ] ; then
  DEVTARGET="/dev/$TARGET"
  # Find its mount point
  BMNTTARGET=`df |fgrep "$DEVTARGET" |cut -f2 -d%`
  # Remove the leading space
  MNTTARGET=${BMNTTARGET# }
elif [ -d "$TARGET" ] ; then
  MNTTARGET="$TARGET"
else
  echo "$0 : You must give a device or directory which is present"
  echo "$USAGE"
  exit 1
fi

echo "Confirm that the device to edit is $TARGET mounted at $MNTTARGET : [yN]"

read line
ANS=`echo $line |tr "Y" "y"`
if [ "$ANS" != "y" ] ; then
  echo "$0 exiting on response $line"
  exit 1
fi


# ===== Link the package download directory into a /tmp/debs (on a ramdisk)
sudo rm -rf ${MNTTARGET}/var/cache/apt/archives
sudo ln -s /tmp/debs ${MNTTARGET}/var/cache/apt/archives

# ===== Make the storage location for the tailored ram users tarball HOMEs
sudo mkdir ${MNTTARGET}/usr/local/tmpusers

# ===== Add the ramdisks for /var/log and /tmp
# Update manager needs tmpfs to get a real size
PART1=`fgrep -n /proc ${MNTTARGET}/etc/fstab | cut -f1 -d:`
PART2=`expr 1 + $PART1`

head ${MNTTARGET}/etc/fstab -n $PART1 >/tmp/f1
cat >> /tmp/f1 <>/tmp/f1 

# ===== Add noatime to / and the ramdisks in fstab =====
# Add in the noatime for flash write minimization and move back to /etc
sed -e "s/t-ro/t-ro,noatime,nodiratime/" /tmp/f1 > /tmp/f2
sudo mv /tmp/f2 ${MNTTARGET}/etc/fstab
rm /tmp/f1

# ==== Modify rc.local which sets up the /tmp ramdisk =====
NUM=`grep -n "^exit 0" ${MNTTARGET}/etc/rc.local |cut -f1 -d:`
INSLOC=`expr $NUM - 1`
sudo ./insert_file ${MNTTARGET}/etc/rc.local $INSLOC p_rclocalinsert

# ===== Add a splash screen for grub (image picked up automatically in 11.04)
sudo cp splash.png ${MNTTARGET}/boot/grub

# ===== Edit the grub.cfg creation files to use better menu colors on splash
# The 11.04 code picks up image with no modifications, but menu wrong color
sed -i -e 's%image "${background}"%image "${background}" "black/black" "magenta/black"%' \
    ${MNTTARGET}/etc/grub.d/05_debian_theme
# Confirm the edit?
# Replace the splash generation file
#sudo cp /tmp/05.tmp ${MNTTARGET}/etc/grub.d/05_debian_theme
#rm /tmp/05.tmp

# copy the post boot scripts to a the existing user home dir
FIRSTUSR=`fgrep 1000 ${MNTTARGET}/etc/passwd | cut -f1 -d":"`
mkdir ${MNTTARGET}/home/$FIRSTUSR/mods
cp addu chuser insert_file notes preboot_filemods p_rclocalinsert prelogin_usermods ramtailoring_usermods splash.png update_ramuser ${MNTTARGET}/home/$FIRSTUSR/mods
#=====END preboot_filemods =====
#=====START insert_file =====
#! /bin/bash
#-t- insf - Insert a file into another after line n
# Arg1 - File to edit (inserting another file into it)
# Arg2 - Line number or pattern after which to insert file
# Arg3 - File to insert

# Debian GNU/Linux
# Copyright (C) 2011 Free Software Foundation, Inc.
# This is free software;  for copying, see the GNU General Public
# License version 2, or (at your option) any later version.
# There is NO warranty.

USAGE="$0 file afterLineN fileadditions
$0 file pattern fileadditions"
if [ $# -lt 3 ] ; then
  echo "$USAGE"
  exit 1
fi
EFILE="$1"
P1LINES="$2"
IFILE="$3"


P2LINES=`expr 1 + $P1LINES`
echo "Args are $EFILE , $P1LINES , $P2LINES , $IFILE "

# Insert IFILE into EFILE
TMPF=`mktemp`
head $EFILE -n $P1LINES >$TMPF
cat $IFILE >>$TMPF
tail $EFILE -n +$P2LINES >>$TMPF

#Confirm edits
echo "Comparing file $EFILE and file $TMPF"
diff $EFILE $TMPF

echo "Replace file $EFILE with $TMPF ?"
read line
if [ "$line" = "y" ]; then
  sudo cp "$TMPF" "$EFILE"
  rm "$TMPF"
fi

#=====END insert_file =====
#=====START p_rclocalinsert =====
# Debian GNU/Linux
# Copyright (C) 2011 Free Software Foundation, Inc.
# This is free software;  for copying, see the GNU General Public
# License version 2, or (at your option) any later version.
# There is NO warranty.


# Set up the ram based directories and links for use with flash installations
cd /tmp
#
# if /var/cache/apt/archives is a link for package downloads, create target
if [ -h /var/cache/apt/archives ]; then
  if [ "/tmp/debs" = `XX=$(ls -l /var/cache/apt/archives); echo ${XX##*->}` ]; then
    mkdir -p /tmp/debs/partial
  fi
fi

# postgresql needs this to work
if [ -n "`fgrep postgres /etc/passwd`" ]
then
  mkdir -m777 /var/log/apt
  mkdir -m775 /var/log/postgresql
  chgrp postgres /var/log/postgresql 
fi

# create the temp users home dirs in /tmp
find /usr/local/tmpusers -name "*.tgz" -exec tar -xpzf \{\} \;

# set up the flash home user firefox cache in ram
FUPASSWDLN=`fgrep x:1000: /etc/passwd`
FIRSTUSER=`echo ${FUPASSWDLN%%:*}`
mkdir -m775 /tmp/Cache-${FIRSTUSER}
chown ${FIRSTUSER}:${FIRSTUSER} /tmp/Cache-${FIRSTUSER}

#=====END p_rclocalinsert =====

Appendix VI -- First Login User Modifications

#=====START firstlogin_usermods =====
#! /bin/bash
#-t- firstlogin_usermods, Run at first login to create the ram HOMEd users,
# and some perform some initial user environment edits.
# Optional arg 1 and 2 are usernames, defaulting to quick and guest
# Assume the preboot_filemods have been done.
# Assume user 1001 is related to user 1000, used for quick access
# without making many modifications to flash, like Gnome will do.
# The 1002 user will be for guest, left pretty much uninitialized.
# Even these users will have permanent storage available in /home/$USER

# Debian GNU/Linux
# Copyright (C) 2011 Free Software Foundation, Inc.
# This is free software;  for copying, see the GNU General Public
# License version 2, or (at your option) any later version.
# There is NO warranty.

# Add the two ram based users interactively
U1=${1-quick}
U2=${2-guest}
sudo ./addu "$U1" "$U2"

for RAMUSER in 1000 1001 1002
do
  NEWUSER=`fgrep $RAMUSER /etc/passwd |cut -f1 -d:`
  export NEWUSER
  # Create bin directories for ram based users
  sudo mkdir -p                    /home/${NEWUSER}/bin
  # first ram user 1001 is related to user 1000
  if [ $RAMUSER -eq 1001 ]; then
    sudo cp chuser /home/${NEWUSER}/bin
  fi
  sudo chown -R ${NEWUSER}:${NEWUSER} /home/${NEWUSER}/bin

  # Make a color prompt for the terminal
  sudo sed -i -e "s/32m/35m/" \
              -e "s/#force_color_prompt=yes/force_color_prompt=yes/" \
              /home/${NEWUSER}/.bashrc

  # Alter the PATH to include the permanent storage bin
  NUM=`fgrep -n "set PATH so it includes" /home/${NEWUSER}/.profile |cut -f1 -d:`
  PART1=`expr $NUM - 1 `
  head /home/${NEWUSER}/.profile -n $PART1 >/tmp/profile
  cat >>/tmp/profile <

#=====START addu =====
#!/bin/bash
# addu - add ram home bases users
# arg1 - first user to add, with group access to usdr 1000
# arg2 - second user, no special group access, for guests
# Create users 1001 (also in group 1000) and user 1002

# Debian GNU/Linux
# Copyright (C) 2011 Free Software Foundation, Inc.
# This is free software;  for copying, see the GNU General Public
# License version 2, or (at your option) any later version.
# There is NO warranty.

# Initial checking
if [ $# -lt 2 ]; then
  echo " usage: $0 newuser1 newuser2"
  echo " newuser1 will be added to the 1000 group also"
  exit 1
fi
grep "100[12]" /etc/passwd
if [ $? -eq 0 ]; then
  echo "users 1001 and 1002 already exist, exiting"
  exit 1
fi

# Add the users (interactively)
ui=1
for u in 1001 1002
do
  eval echo "adding user name \$$ui with uid $u"
  eval sudo adduser "\$$ui"
  ui=`expr $ui + 1`
done

# set up the first user's group
FUSRGRPLN=`fgrep x:1000: /etc/group`
FIRSTUSRGRP=`echo ${FUSRGRPLN%%:*}`

# Add user 1001 to this first user's group
sudo adduser $1 $FIRSTUSRGRP

#=====END addu =====
#=====START chuser =====
#! /bin/sh
# -t- chuser, Changes user (partially) so the new user can run
#     x, but not have the Gnome record keeping written into the
#     home directory. 
#     Used to switch a /tmp homed user to one with permanent storage.
# arg 1 -- the other user to become

# Debian GNU/Linux
# Copyright (C) 2011 Free Software Foundation, Inc.
# This is free software;  for copying, see the GNU General Public
# License version 2, or (at your option) any later version.
# There is NO warranty.
#
# Default to the first user
FUPASSWDLN=`fgrep x:1000: /etc/passwd`
FIRSTUSER=`echo ${FUPASSWDLN%%:*}`
OTHERUSER=${1-`echo $FIRSTUSER`}
#
# Open up X to everyone, or just one other user
if [ -n "$1" ]
then
  xhost +SI:localuser:$OTHERUSER
else
  xhost +
fi

#
# Go to the home of the otheruser
cd /home/$OTHERUSER
#
# Become the otheruser. the - misses DISPLAY, and puts in many
# Gnome variables probably better left unset to keep the
# Gnome desktop logging in /tmp
echo "Becoming $OTHERUSER"
su $OTHERUSER
#
#---- to be done, not visible after su
# Fix missing critical items (when - used)
#export DISPLAY=":0.0"
# 
# Change to new home directory
#cd

#=====END chuser =====
#=====START ramtailoring_usermods =====
#! /bin/bash
#-t- b_user2 - Run after ram HOME users have been added, and
# their /home files modified, and tared to tmpusers.
# Tailor the users in ram, and re-tar.
# changes to their ram HOMES which will be saved

# Debian GNU/Linux
# Copyright (C) 2011 Free Software Foundation, Inc.
# This is free software;  for copying, see the GNU General Public
# License version 2, or (at your option) any later version.
# There is NO warranty.

for RAMUSER in 1001 1002
do
  NEWUSERH=`fgrep $RAMUSER /etc/passwd |cut -f6 -d:`
  NEWUSER=`fgrep $RAMUSER /etc/passwd |cut -f1 -d:`

  cd ${NEWUSERH}

  # Add a link to permanent storage
  sudo ln -s /home/${NEWUSER} flashhome
  sudo chown ${NEWUSER}:${NEWUSER} flashhome

  echo "Now Tailor the user $USER, and retar the /tmp/${NEWUSER} to /usr/local/tmpusers"

done

echo "Suggestions, put terminal on toolbar, size, scroll, color, login"
echo "Try linking .mozilla in user 1001 to the 1000 user's .mozilla, but "
echo "group access still needs to be set recursively to work."
echo "Put the user 1000 .mozilla cache into ram"
echo "etc..."

#=====END ramtailoring_usermods =====
#=====START update_ramuser =====
#!/bin/bash
# update_ramuser - Retar the login directory of a ram user to preserve the setup
# arg1 is the name of the user, which should be the same as the home directory
# This script must be run by a user able to run sudo

# Debian GNU/Linux
# Copyright (C) 2011 Free Software Foundation, Inc.
# This is free software;  for copying, see the GNU General Public
# License version 2, or (at your option) any later version.
# There is NO warranty.

if [ $# -lt 1 ]; then
  echo "usage: $0 user"
  exit 1
fi
USR=$1
cd /tmp

# Check that the user's home directory exists
if [ ! -d $USR ]; then
  echo "/tmp/$USR does not exist"
  exit 1
fi

# Create the compressed tar of the user whose home is in /tmp
sudo tar -czf /usr/local/tmpusers/${USR}_new.tgz $USR
sudo chown $USR:$USR /usr/local/tmpusers/${USR}_new.tgz

# Save any existing tared login, removing the previous one.
if [ -f /usr/local/tmpusers/${USR}.tgz ]; then
  sudo rm /usr/local/tmpusers/${USR}_back.tgz 2>/dev/null
  sudo mv /usr/local/tmpusers/${USR}.tgz /usr/local/tmpusers/${USR}_back.tgz
fi

sudo mv /usr/local/tmpusers/${USR}_new.tgz /usr/local/tmpusers/${USR}.tgz
ls -l /usr/local/tmpusers/${USR}*

#=====END update_ramuser =====

Appendix VII -- Notes

After creating an installed usb stick, before attempting to boot it, insert it and run the preboot_filemods.

Manually edit the grub.cfg file to fix wrong devices for first boot.

After booting the new stick, login as the first user and run: sudo update-grub cd mods ./firstlogin_usermods.

Log in as the ram based users, tailor their desktops, mail etc., and then as the first user, run ramtailoring_usermods.