Tiny Core Linux 9の起動用USBメモリを作る

Tiny Core Linuxの起動用USBメモリを作りたい時は`sudo dd if=Core-current.iso of=/dev/sdb`で書き込めばそれでOK!なーんて記憶していたんですが、最近、同じ事をやってみたら起動できないという場面に遭遇しました。

でもどうしてもあのテキストで書かれたTCペンギンに逢いたいっという思いが捨てきれず、パーティション作ってブートローダーを登録してコピーしてって追いかけてみたら思ったよりも簡単に出会えた（起動できた）のでその時のメモです。Coreだから？だとしたらCoreって素敵ですね。※後で少しの変更でTinyCoreでも起動できることが分かったので後述の「おまけ」で書いています。

今回は手元にあったLubuntu16を使用して起動用USBメモリを作成しています。ブートローダーにはsyslinuxを使用しています。syslinuxを選択した理由はLubuntu16なら標準でインストールされているため新たにインストールする必要がないからです。それだけと言われればそれだけで深い理由はないです。

またパーティション操作に`fdisk`を使用し`echo`でパーティション操作コマンドを流すようにしています。この方法だと何をやっているのか分かりにくいですし`fdisk`の挙動が変わると動きがおかしくなるという問題もあるのですが、そのおかげでパーティション操作からファイルのコピー、ブートローダーの登録までをコマンドのコピー＆ペーストで行えるようになりました。シェルを書いて一気に作成ということもできるかもしれない、そんな期待を込めてそうしてみました。

## 注意
今回の作業はパーティション操作をしたりフォーマットしたりしますので、とっても危険です。そうゆう事をしてもへっちゃらなUSBメモリを使用し、誤って書き込んでしまわないように使用するUSBメモリ以外のデバイスは取り外した状態で作業してください。また内蔵HDDのデータも壊れても良いようにバックアップをとった上で行うようにしてください。

私は途中で別のHDDをマウントしたことを忘れて作業を進めた結果、1Tの外付けHDDがTiny Core Linuxになってしまいました。同じことにならないよう細心の注意を払って作業してください。

## 最初の準備
最初に起動用USBメモリのデバイス名を変数に入れておきます。以前は`TARGET=sdb`とシンプルに設定していたのですが誤って外付けのHDDをTiny Core Linuxにしてしまったという教訓からデバイス名を`lsblk`コマンドの実行結果から取得するようにします。

まずは`lsblk`コマンドで接続されているデバイスの情報を取得します。その中から起動用USBメモリの情報を覚えておきます。厳密に行いたければシリアルですが、私の場合1.9GでBUFFALOというだけでUSBメモリということが分かって、USBメモリは起動用や一時使用しか使わないことが分かっているので「1.9G BUFFALO」といったキーワードでも十分となります。そのあたりの調整は環境に合わせて行う必要があります。

```bash:デバイスの情報を取得
lsblk -o KNAME,SIZE,VENDOR,MODEL,SERIAL
KNAME   SIZE VENDOR   MODEL            SERIAL
sda   232.9G ATA      WDC WD2500BEVT-7 WD-WXJ0A69W8486
sda1    229G                           
sda2      1K                           
sda5      4G                           
sdb     1.9G BUFFALO  USB Flash Disk   07CC1008C44F0726
sr0    1024M TSSTcorp DVD+-RW TS-L633C R4956GHS907860
loop0     5G                           
dm-0      5G                           
```

条件にマッチするデバイス名を取得し変数に格納します。もしデバイスを発見できなかった場合や複数見つかった場合はこの先の処理がエラーになるように`null`を指定しています。目で確認することは絶対に必要ですが、うっかりそれを忘れていた場合でも「データの入っているHDDがTiny Core Linuxに！」なんていう事態は防げるかもしれない。そんな思いを込めています。

```bash:ターゲットデバイスを設定する（1.9GのBUFFALOを検索）
#ターゲットデバイスを設定する（1.9GのBUFFALOを検索）
TARGET=$(lsblk -o KNAME,SIZE,VENDOR,MODEL,SERIAL | grep " 1.9G BUFFALO" | awk '{print $1}')
[ -z "$TARGET" ] && TARGET=null
[ -n "$(echo $TARGET | grep ' ')" ] && TARGET=null
##以下のコマンド結果から$TARGETが正しいUSBメモリなのかを必ず確認する
echo /dev/$TARGET
lsblk -o KNAME,SIZE,VENDOR,MODEL,SERIAL /dev/$TARGET
```

実行結果は以下のようになります。`$TARGET`が起動用USBメモリであることを確認します。

```console:実行結果
$ TARGET=$(lsblk -o KNAME,SIZE,VENDOR,MODEL,SERIAL | grep " 1.9G BUFFALO" | awk '{print $1}')
$ [ -z "$TARGET" ] && TARGET=null
$ [ -n "$(echo $TARGET | grep ' ')" ] && TARGET=null
$ echo /dev/$TARGET
sdb
$ lsblk -o KNAME,SIZE,VENDOR,MODEL,SERIAL /dev/$TARGET
KNAME  SIZE VENDOR   MODEL            SERIAL
sdb    1.9G BUFFALO  USB Flash Disk   07CC1008C44F0726
sdb1   1.9G                           
```

既にUSBメモリがフォーマットされていると自動でマウントされている可能性があるためアンマウントします。

```bash:アンマウント
ls /dev/${TARGET}? | sudo xargs -n1 umount -f
```

## パーティションの作成とフォーマット
`wipefs`でUSBメモリ上のパーティションテーブルを破壊した後で、`fdisk`でパーティションを作成し起動フラグを付け、パーティションタイプをW95 FAT32 (LBA)に変更し`mkfs.vfat`でフォーマットしています。ext3やext4じゃなくてFATでフォーマットするのはsyslinuxがFATにしか対応しないためです。フォーマットやマウントがうまくできない場合は`fdisk`使用後`sudo partprobe`を実行するか再起動してみてください。

```bash:パーティションの作成
#パーティションの作成
sudo wipefs -a /dev/$TARGET
echo -e "n\np\n1\n\n\na\nt\nc\nw" | sudo fdisk /dev/$TARGET
##パーティションが作成されているかの確認
sudo fdisk -l /dev/$TARGET
```

```bash:フォーマット
#フォーマット
sudo mkfs.vfat -v /dev/${TARGET}1
```

実行結果は以下のようになります。全てのコマンドが正常終了していることを確認します。

```console:実行結果
$ #パーティションの作成
$ sudo wipefs -a /dev/$TARGET
/dev/sdb: 2 bytes were erased at offset 0x000001fe (dos): 55 aa
/dev/sdb: calling ioctl to re-read partition table: Success

$ echo -e "n\np\n1\n\n\na\nt\nc\nw" | sudo fdisk /dev/$TARGET
Welcome to fdisk (util-linux 2.27.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0x6ead914f.

Command (m for help): Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): Partition number (1-4, default 1): First sector (2048-3915775, default 2048): Last sector, +sectors or +size{K,M,G,T,P} (2048-3915775, default 3915775): 
Created a new partition 1 of type 'Linux' and of size 1.9 GiB.

Command (m for help): Selected partition 1
The bootable flag on partition 1 is enabled now.

Command (m for help): Selected partition 1
Partition type (type L to list all types): Changed type of partition 'Linux' to 'W95 FAT32 (LBA)'.

Command (m for help): The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

$ ##パーティションが作成されているかの確認
$ sudo fdisk -l /dev/$TARGET
Disk /dev/sdb: 1.9 GiB, 2004877312 bytes, 3915776 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x6ead914f

Device     Boot Start     End Sectors  Size Id Type
/dev/sdb1  *     2048 3915775 3913728  1.9G  c W95 FAT32 (LBA)

$ #フォーマット
$ sudo mkfs.vfat -v /dev/${TARGET}1
mkfs.fat 3.0.28 (2015-05-16)
Auto-selecting FAT32 for large filesystem
/dev/sdb1 has 62 heads and 62 sectors per track,
hidden sectors 0x0800;
logical sector size is 512,
using 0xf8 media descriptor, with 3913728 sectors;
drive number 0x80;
filesystem has 2 32-bit FATs and 8 sectors per cluster.
FAT size is 3815 sectors, and provides 488258 clusters.
There are 32 reserved sectors.
Volume ID is 6adc77a0, no volume label.
```

## 必要なファイルのコピー
「[Tiny Core Linuxのダウンロードページ](http://tinycorelinux.net/downloads.html)」からダウンロードします。パスが分かっていれば`wget -N http://tinycorelinux.net/9.x/x86/release/Core-current.iso`のような感じでダウンロードすることもできます。

ダウンロードができたら展開するための作業用ディレクトリを作成しUSBメモリとダウンロードしたISOファイルをマウントします。

```bash:作業用ディレクトリの作成とマウント
#作業用ディレクトリの作成とマウント
mkdir iso drive
sudo mount /dev/${TARGET}1 drive
sudo mount -o loop Core-current.iso iso
```

```bash:ファイルのコピー
#ファイルのコピー
sudo cp -r iso/boot drive
sudo mv drive/boot/isolinux drive/boot/syslinux
sudo mv drive/boot/syslinux/isolinux.cfg drive/boot/syslinux/syslinux.cfg
sudo rm drive/boot/syslinux/isolinux.bin drive/boot/syslinux/boot.cat
```

## ブートローダーの登録
ブートローダーを登録します。

```bash:ブートローダーの登録
#ブートローダーの登録
sudo dd if=/usr/lib/syslinux/mbr/mbr.bin of=/dev/$TARGET bs=440 count=1 conv=notrunc
sudo syslinux --install /dev/${TARGET}1
```

私の環境ではこの状態のUSBメモリから起動すると内蔵HDDにもUSBメモリにも作業状態を保存できない状態となってしまいました。isoファイルからコピーしたsyslinux.cfgは以下のような感じです。

```text:syslinux.cfgの中身
display boot.msg
default microcore
label microcore
        kernel /boot/vmlinuz
        initrd /boot/core.gz
        append loglevel=3

label mc
        kernel /boot/vmlinuz
        append initrd=/boot/core.gz loglevel=3
implicit 0
prompt 1
timeout 300
F1 boot.msg
F2 f2
F3 f3
F4 f4
```

色々と試行錯誤した結果`waitusb`を追加すれば保存できるようになることが分かりました。さらに保存先をUSBメモリに固定したい場合は`tce=UUID="xxx"`とすればよさそうです。

```bash:USBメモリに保存したい場合
#USBメモリに保存したい場合
UUID=$(lsblk -o KNAME,UUID | grep "^${TARGET}1" | awk '{print $2}')
sudo sed -i "/append/ s/$/ waitusb=5 tce=UUID=\"$UUID\"/" drive/boot/syslinux/syslinux.cfg
```

作業で使用したisoファイルとUSBメモリをアンマウントします。

```bash:アンマウント
#アンマウント
sudo umount /dev/${TARGET}1
sudo umount iso
```

## 起動！
作成した起動用USBメモリから起動できるかを確認します。UBSメモリに保存する設定をしている場合は`ls -Al /etc/sysconfig/`を実行して`tcedir`のリンク先がUSBメモリになっていることを確認します。可能なら`filetool.sh -b`で保存がうまくできるかとか`tce-load`で読み込んだパッケージが再起動しても残っているかを確認できれば良いかなと思います。

```console:tcedirが正しく設定されているか？
$ ls -Al /etc/sysconfig/
total 32
-rw-r--r--    1 root     root             2 Apr 10 23:34 backup
-rw-rw-r--    1 root     staff            9 Apr 10 23:34 backup_device
-rw-r--r--    1 root     root             9 Apr 10 23:34 cdroms
-rw-r--r--    1 root     root            10 Apr 10 23:34 keymap
-rw-r--r--    1 root     root             7 Apr 10 23:34 language
-rw-r--r--    1 root     root             7 Apr 10 23:34 mydata
-rw-r--r--    1 root     root            13 Mar 19 11:06 ntpserver
lrwxrwxrwx    1 root     root            13 Apr 10 23:34 tcedir -> /mnt/sdb1/tce/
-rw-r--r--    1 root     root             3 Apr 10 23:34 tcuser
```

## まとめてみた
これまでのをまとめてみました。1行めのUSBメモリの条件は各自の環境にあわせて変更してください。一気に実行できるかもしれませんが、少しずつ実行し結果を確認しながら進めることを想定しています。

```bash:まとめてみた
#ターゲットデバイスを設定する（1.9GのBUFFALOを検索）
TARGET=$(lsblk -o KNAME,SIZE,VENDOR,MODEL,SERIAL | grep " 1.9G BUFFALO" | awk '{print $1}')
[ -z "$TARGET" ] && TARGET=null
[ -n "$(echo $TARGET | grep ' ')" ] && TARGET=null
##以下のコマンド結果から$TARGETが正しいUSBメモリなのかを必ず確認する
echo /dev/$TARGET
lsblk -o KNAME,SIZE,VENDOR,MODEL,SERIAL /dev/$TARGET

#アンマウント
ls /dev/${TARGET}? | sudo xargs -n1 umount -f

#パーティションの作成
sudo wipefs -f -a /dev/$TARGET
echo -e "n\np\n1\n\n\na\nt\nc\nw" | sudo fdisk /dev/$TARGET
##パーティションが作成されているかの確認
sudo fdisk -l /dev/$TARGET

#フォーマット
sudo mkfs.vfat -v /dev/${TARGET}1

#ファイルのゲット（必要なら）
#wget -N http://tinycorelinux.net/9.x/x86/release/Core-current.iso

#作業用ディレクトリの作成とマウント
mkdir iso drive
sudo mount /dev/${TARGET}1 drive
sudo mount -o loop Core-current.iso iso

#ファイルのコピー
sudo cp -r iso/boot drive
sudo mv drive/boot/isolinux drive/boot/syslinux
sudo mv drive/boot/syslinux/isolinux.cfg drive/boot/syslinux/syslinux.cfg
sudo rm drive/boot/syslinux/isolinux.bin drive/boot/syslinux/boot.cat

#ブートローダーの登録
sudo dd if=/usr/lib/syslinux/mbr/mbr.bin of=/dev/$TARGET bs=440 count=1 conv=notrunc
sudo syslinux --install /dev/${TARGET}1

#USBメモリに保存したい場合
UUID=$(lsblk -o KNAME,UUID | grep ${TARGET}1 | awk '{print $2}')
sudo sed -i "/append/ s/$/ waitusb=5 tce=UUID=\"$UUID\"/" drive/boot/syslinux/syslinux.cfg

#アンマウント
sudo umount /dev/${TARGET}1
sudo umount iso
```

## おまけ（TinyCoreの場合）
TinyCoreの場合は`cde`フォルダのコピーと`menu.c32`とそれに関係するファイルをコピーする必要があります。USBメモリに保存したい場合はブートオプションから`cde`を`tce=xxx`に変更してデフォルトのラベルを`waitusb`の指定してあるラベル（tcw）に変更します。

```bash:TinyCoreの場合に追加するもの
sudo cp -r iso/cde drive/tce
sudo cp /usr/lib/syslinux/modules/bios/libutil.c32 drive
sudo cp /usr/lib/syslinux/modules/bios/menu.c32 drive

sudo sed -i "/APPEND/ s/cde/tce=UUID=\"$UUID\"/" drive/boot/syslinux/syslinux.cfg
sudo sed -i '/DEFAULT/ s/ tc$/ tcw/' drive/boot/syslinux/syslinux.cfg
sudo sed -i '/ONTIMEOUT/ s/ tc$/ tcw/' drive/boot/syslinux/syslinux.cfg
```

まとめて実行する場合は以下のようになります。

```bash:TinyCoreの起動用USBメモリ作成をまとめて実行
#ターゲットデバイスを設定する（1.9GのBUFFALOを検索）
TARGET=$(lsblk -o KNAME,SIZE,VENDOR,MODEL,SERIAL | grep " 1.9G BUFFALO" | awk '{print $1}')
[ -z "$TARGET" ] && TARGET=null
[ -n "$(echo $TARGET | grep ' ')" ] && TARGET=null
##以下のコマンド結果から$TARGETが正しいUSBメモリなのかを必ず確認する
echo /dev/$TARGET
lsblk -o KNAME,SIZE,VENDOR,MODEL,SERIAL /dev/$TARGET

#アンマウント
ls /dev/${TARGET}? | sudo xargs -n1 umount -f

#パーティションの作成
sudo wipefs -a /dev/$TARGET
echo -e "n\np\n1\n\n\na\nt\nc\nw" | sudo fdisk /dev/$TARGET
##パーティションが作成されているかの確認
sudo fdisk -l /dev/$TARGET

#フォーマット
sudo mkfs.vfat -v /dev/${TARGET}1

#作業用ディレクトリの作成
mkdir iso drive

#ファイルのゲット（必要なら）
#wget -N http://tinycorelinux.net/9.x/x86/release/TinyCore-current.iso

#マウント
sudo mount /dev/${TARGET}1 drive
sudo mount -o loop TinyCore-current.iso iso

#ファイルのコピー
sudo cp -r iso/boot drive
sudo mv drive/boot/isolinux drive/boot/syslinux
sudo mv drive/boot/syslinux/isolinux.cfg drive/boot/syslinux/syslinux.cfg
sudo rm drive/boot/syslinux/isolinux.bin drive/boot/syslinux/boot.cat
sudo cp -r iso/cde drive/tce
sudo cp /usr/lib/syslinux/modules/bios/libutil.c32 drive/boot/syslinux
sudo cp /usr/lib/syslinux/modules/bios/menu.c32 drive/boot/syslinux

#ブートローダーの登録
sudo dd if=/usr/lib/syslinux/mbr/mbr.bin of=/dev/$TARGET bs=440 count=1 conv=notrunc
sudo syslinux --install /dev/${TARGET}1

#USBメモリに保存したい場合
UUID=$(lsblk -o KNAME,UUID | grep ${TARGET}1 | awk '{print $2}')
sudo sed -i "/APPEND/ s/cde/tce=UUID=\"$UUID\"/" drive/boot/syslinux/syslinux.cfg
sudo sed -i '/DEFAULT/ s/ tc$/ tcw/' drive/boot/syslinux/syslinux.cfg
sudo sed -i '/ONTIMEOUT/ s/ tc$/ tcw/' drive/boot/syslinux/syslinux.cfg

#アンマウント
sudo umount /dev/${TARGET}1
sudo umount iso
```