Installing Debian on a small USB flash drive What I wanted: - plain Debian - upgradable directly via apt-get - on my 128MB USB flash drive - mostly for rescue style operation Choices: - boot with grub, because it's a nice boot loader. - use jffs2. This choice is not necessarily the best: + compressed (it's the only compressed writable fs in the stock kernel) + supports all users/accessrights/devfiles/... + wear-levelling (not necessarily important, since your USB flash drive probably does it for you anyway) - grub can't read it - inefficient: jffs2 is designed to work directly on flash chips, but USB drives don't give direct access to the chips, so we go through flash -> "mtd2block" -> USB -> block2mtd -> jffs2. - slow to mount - slightly incompatible with APT (see below) If you don't need the compression, you're probably better off using ext2/ext3. But I wanted to use a 128MB flash drive, which couldn't hold the base system without compression. Another option might be to use e2compr, although I don't know anythin about its current status. Finally, you could trim down the system such that it fits in 128MB. I didn't want to spend time on this, and I wanted to keep manpages and things like that, which always come in handy. So, here is how I did it (9 Mar 2007) - partition the drive into 2: a 10MB partition (for /boot) and the rest for the jffs2 root partition. I used ext2 for /boot, but any other choice would work as well, e.g. vfat. - clear the jffs2 partition. I used while true; do printf "\xff\xff\xff\xff\xff\xff"; done >/dev/ A cleared partition is accepted by jffs2 as an empty file system, so you don't need to mkfs. There is an mkfs.jffs2 in mtd-tools, but when I tried to use it the resulting partiton was received by jffs2 with lots of complaints. The above while loop is ugly, takes ages and won't stop at the end of the device, so it's clearly not the best choice, but it did the job. I ust looked at the LED on my flash key and when it stopped blinking I figured that I had reached the end. - create the mtd device out of the block device: modprobe block2mtd block2mtd=/dev/ - mount the file system: mount -t jffs2 mtd0 /mnt if you want to use an actual devfile, you need /dev/mtdblock0. Oddly, /dev/MAKEDEV knows how to make /dev/mtd0, but not /dev/mtdblock0. So you'll have to do it by hand: mknod /dev/mtdblock0 b 31 0 (and mknod /dev/mtdblock1 b 31 1, ...). The mount will probably take a little while: it's normal. - mkfs -t ext2 /dev/ - mkdir /mnt/boot - mount -j /dev/ /mnt/boot - deboostrap etch /tmp/root http://your.local.debian.mirror/debian I wanted `testing', but there's no deboostrap script for it, so I used `etch'. I did not deboostrap directly into /mnt because I wanted to see the resulting size before, and be able to trim things rather than get a failure in the middle of deboostrap. After deboostrapping, I removed a few files. Most importantly: rm /tmp/root/var/cache/apt/archives/* And then cp -a /tmp/root/* /mnt/ - never quite sure about what grub-install does, I installed grub by hand: cp -a /boot/grub /mnt/boot/ grub root (hdN,M) setup (hdN) To find the N and M values, use TAB as in: root(hd1,1)/[TAB] which will show you the content of the drive, so you'll know which is which. - edit /mnt/boot/grub/menu.list the `groot' should be (hd0,M) where M is the partition. Note that it really will be `hd0' even if you had to use `hd1' or `hd2' above. the command line for the kernels will contain root=/dev/mtdblock0 rootfstype=jffs2 because Linux does not automatically try jffs2. - chroot /mnt - configure the system the way I like it. apt-get install linux-image-2.6.18-4-686 grub ... - you need to figure out which of the disk devices is your USB key (could be /dev/sda or /dev/sdb or ...) So I just told udev to give it a special name: create a file /etc/udev/rules.d/z20_shorthand.rules which contains: BUS=="usb", KERNEL=="sd*", SYMLINK+="usbdisk%n" if you have other disks connected via USB this won't help. In that case you could add a contraint like ATTRS{size}=="251904" (use udevinfo -a -p /dev/ to figure out the size of your disk). - I need to create the mtd device before mounting the real root. If you don't use jffs2 you don't need that. I first added jffs2 block2mtd in /etc/initramfs-tools/modules to make sure they're included in the initramfs. I originally added a "block2mtd=/dev/" argument there, but the problem is that the jffs2part device is created (by udev) after the `modules' file is processed. So instead I created a file /etc/initramfs-tools/scripts/local-top/block2mtd that says: #!/bin/sh -x PREREQ="" prereqs() { echo "$PREREQ"; } case $1 in prereqs) prereqs; exit 0 ;; esac dev=/dev/usbdisk2 while test ! -b "$dev"; do sleep 1; done echo "$dev" >/sys/module/block2mtd/parameters/block2mtd mknod /dev/mtdblock0 b 31 0 log_success_msg "Done creating the MTD device" Note that the `log_success_msg' command doesn't actually work. I guess I misread the initramfs-tools manpage or something. The sleeps are there to wait for udev to discover the USB drive and to create the relevant devices. - you still need to create the /etc/fstab. Mine looks like: proc /proc proc defaults /dev/mtdblock0 / jffs2 defaults 0 1 /dev/usbdisk4 /boot ext2 defaults 0 2 tmpfs /tmp tmpfs defaults # This saves us from storing large debian packages # but most importantly, this works around an incompatibility between jffs2 # and APT where apt-get uses an mmap call which jffs2 does not implement. tmpfs /var/cache/apt tmpfs defaults note that my /boot partition is partition 4 rather than partition 1 (left over from attempts to boot using the USB-ZIP protocol), but this is not important. - rm /boot/initrd* - update-initramfs -c -k all - grub-update - this is it, you should be able to boot off of your USB flash drive now with a base Debian system which you can then tweak to your liking and keep upgrading at will. - because /var/cache/apt is emptied at each boot, you'll sometimes have to mkdir -p /var/cache/apt/archives/partial before running apt-get. You may want to add something your boot scripts to do that automatically. Or you may prefer to report it as a bug in apt-get.