NetBSDでUSBメモリをフォーマットしてみる

[NetBSD Advent Calendar 2018](https://qiita.com/advent-calendar/2018/netbsd)、2日目の記事です。
今日はNetBSDを使用した、簡単なTipsを紹介しようと思います。

## 背景

コンビニに置いてあるコピー機はUSBメモリやSDカード内のデータから印刷することも可能なため、ちょっとした印刷に重宝します。

しかしながら、USBメモリを自分のPCとコンビニのコピー機で使いまわすのは、セキュリティ的にちょっと不安な面もあります。
その都度USBメモリをフォーマットすれば良いという話ですが、WindowsやMacではUSBメモリを接続するとautorunが走ったらどうしよう等々、考えだしたらキリがありません。

そこで、明示的にmountしないとUSBメモリの中身が見られないNetBSD(というかUNIX系OS)でフォーマットを楽に行えるようにすれば良いのではなかろうか、というのが今日のお話の背景になります。

## NetBSDでのUSBメモリフォーマット

そもそもNetBSDでUSBメモリのフォーマットはどう行うのか、簡単に手順を解説します。
適当なUSBメモリをNetBSDがインストールされているマシンに接続すると、以下のようなdmesgが確認できます。この例ではUSBメモリが `/dev/sd0` というデバイス名で見えています。

```sh 
$ dmesg
...中略...
sd0 at scsibus0 target 0 lun 0: <JetFlash, Transcend 16GB, 8.07> disk removable
sd0: fabricating a geometry
sd0: 15316 MB, 15316 cyl, 64 head, 32 sec, 512 bytes/sect x 31367168 sectors
sd0: fabricating a geometry
```

あとは `disklabel` コマンドで確認したデバイスに対して `newfs_msdos` を実行します。
`newfs_msdos` はフォーマット対象のデバイスをキャラクタデバイス名で指定する必要があります。先述した `disklabel` コマンドの一行目にキャラクタデバイス名(今回のケースでは `/dev/rsd0d` )が示されているので、それを指定します。

```sh 
$ # sd0aはブロックデバイス
$ file /dev/sd0a
/dev/sd0a: block special (4/0)
$
$ # rsd0aはキャラクタデバイス
$ file /dev/rsd0a
/dev/rsd0a: character special (13/0)
$
$ # キャラクタデバイスを指定してnewfsする
$ sudo newfs_msdos /dev/rsd0d
```

フォーマットしたデバイスをmountできることを確認します。

```
$ sudo mount -t msdos /dev/sd0a /mnt
$ mount | grep \/mnt
/dev/sd0a on /mnt type msdos (local)
```

ちなみに、ブロックデバイスを指定して `newfs_msdos` すると以下のエラーになります。

```
$ # エラーになる例！
$ sudo newfs_msdos /dev/sd0a
newfs_msdos: warning, /dev/sd0a is not a character device
```

## パーティション情報が飛んでしまったUSBメモリをフォーマットする

先述した手順により、USBメモリを使う都度フォーマットすることが可能になります。
しかし、USBメモリにOSのインストールイメージを書き込んでいたものを普通のUSBメモリとしてフォーマットしたいような場合は、パーティション情報が失われているため、 `newfs_msdos` でエラーになってしまいます。

そのような場合には、以下の手順を実行します。

 * fdiskコマンドでMSDOSパーティションを設定する
 * disklabelコマンドでNetBSDディスクラベルを設定する
 * newfsコマンドでフォーマットを実行する

### fdiskコマンドでMSDOSパーティションを設定する

まずはMSDOSパーティションを設定します。今回は以下のようなまっさらなパーティションの状態から手順を実行して行きます。

```sh 
$ sudo fdisk -u /dev/sd0
Disk: /dev/sd0
...中略...
Partition table:
0: <UNUSED>
1: <UNUSED>
2: <UNUSED>
3: <UNUSED>
First active partition: 0
Drive serial number: 86212239 (0x05237e8f)
Which partition do you want to change?: [none]
```

編集したいパーティションの番号を指定します。今回は「1:」のパーティションを編集してみます。 `sysid` は6(=MSDOS)、 `start` と `size` はデフォルトではUSBメモリの全体のサイズが提示されるので、デフォルト値のまま設定します。

```sh 
Which partition do you want to change?: [none] 1
The data for partition 1 is:
<UNUSED>
sysid: [0..255 default: 169] 6  # ←sysid(後述)を指定する
start: [0..115cyl default: 63, 0cyl, 0MB] # ←そのままリターンキーを入力
size: [0..115cyl default: 1855425, 115cyl, 906MB] # ←そのままリターンキーを入力
bootmenu: []
The bootselect code is not installed, do you want to install it now? [n]

Partition table:
0: <UNUSED>
1: Primary 'big' DOS, 16-bit FAT (> 32MB) (sysid 6)
    start 63, size 1855425 (906 MB, Cyls 0-115/127/12)
        PBR is not bootable: All bytes are identical (0x00)
2: <UNUSED>
3: <UNUSED>
First active partition: 0
Drive serial number: 86212239 (0x05237e8f)
Which partition do you want to change?: [none]
```

ちなみに、sysidの一覧は `fdisk -l` で確認できます。今回は `006 Primary 'big' DOS, 16-bit FAT (> 32MB)` を指定したいので、 `sysid` は「6」になります。

```sh 
$ fdisk -l | grep DOS | grep FAT
001 Primary DOS with 12 bit FAT
004 Primary DOS with 16 bit FAT <32M
006 Primary 'big' DOS, 16-bit FAT (> 32MB)
011 Primary DOS with 32 bit FAT
012 Primary DOS with 32 bit FAT - LBA
014 DOS (16-bit FAT) - LBA
```

設定が済んだら"Should we write new partition table?"で「y」を指定してパーティション情報を書き込みます。

```sh 
We haven't written the MBR back to disk yet.  This is your last chance.
Partition table:
0: <UNUSED>
1: Primary 'big' DOS, 16-bit FAT (> 32MB) (sysid 6)
    start 63, size 1855425 (906 MB, Cyls 0-115/127/12)
        PBR is not bootable: All bytes are identical (0x00)
2: <UNUSED>
3: <UNUSED>
First active partition: 0
Drive serial number: 86212239 (0x05237e8f)
Should we write new partition table? [n] y
```

### disklabelを設定する

次はNetBSDディスクラベルの設定です。今回の例では `a:` のNetBSDパーティションを設定します(fdiskのパーティションと紛らわしいので、以降は「NetBSDパーティション」と表記します)。

```sh 
$ sudo disklabel -i sd0
Enter '?' for help
partition>P
4 partitions:
#        size    offset     fstype [fsize bsize cpg/sgs]
 a:  31367168         0     4.2BSD      0     0     0  # (Cyl.      0 -  15315)
 d:  31367168         0     unused      0     0        # (Cyl.      0 -  15315)
```

編集したいNetBSDパーティション名を指定します。 `Filesysytem type` には `MSDOS` を指定します。 `start` と `offset` はデフォルトでディスク全体を指定した状態になっているので、そのままデフォルト値を使用します。

```sh 
$ sudo disklabel -i sd0
...中略...
partition>a
Filesystem type [4.2BSD]: MSDOS # ← ファイルシステムタイプ(後述)を指定する
Start offset ('x' to start after partition 'x') [0c, 0s, 0M]: # ←そのままリターンキーを入力
Partition size ('$' for all remaining) [15316c, 31367168s, 15316M]: # ←そのままリターンキーを入力
 a:  31367168         0      MSDOS                     # (Cyl.      0 -  15315)
```

`P` コマンドでNetBSDパーティションの状態を確認できます。ちゃんと設定が反映されていますね。

```sh 
partition>P
4 partitions:
#        size    offset     fstype [fsize bsize cpg/sgs]
 a:  31367168         0      MSDOS                     # (Cyl.      0 -  15315)
 d:  31367168         0     unused      0     0        # (Cyl.      0 -  15315)
```

あとはNetBSDパーティション情報を `W` コマンドで書き込みます。
`Q` コマンドでdisklabelコマンドを終了させ、準備は完了となります。

```
partition>W
Label disk [n]?y
Label written
partition>Q
```

あとは先ほどの例と同じく、 `newfs_msdos` コマンドでフォーマットします。

```sh 
$ sudo disklabel sd0
# /dev/rsd0d:
...中略...
4 partitions:
#        size    offset     fstype [fsize bsize cpg/sgs]
 a:  31367168         0      MSDOS                     # (Cyl.      0 -  15315)
 d:  31367168         0     unused      0     0        # (Cyl.      0 -  15315)
$
$ sudo newfs_msdos /dev/rsd0d
```

MSDOS領域がマウントできることが確認できました。

```sh 
$ sudo mount /dev/sd0a /mnt
$ mount | grep \/mnt
/dev/sd0a on /mnt type msdos (local)
$ df -h | grep \/mnt
/dev/sd0a           15G        32K        15G   0% /mnt
```

## まとめ

NetBSDでUSBメモリをフォーマットする方法を紹介しました。
通常は `newfs_msdos` でフォーマットするだけで良いのですが、USBメモリにOSイメージ等を書き込んだものを再利用する場合には、 `fdisk` と `disklabel` によるMSDOS/NetBSDパーティションの設定を行う必要があるため、その手順も併せて紹介しました。

明日の記事ではNetBSDのカーネルモジュールについて紹介できればと思います。