Top/EBUG勉強会/20250531_usbfadm

usbfadm

EBUG 第93回会合 2025年5月31日
川俣吉広、kaw@on.rim.or.jp

usbfadmについて

usbfadm (USB Flashdrive ADMinistration tool) は、河豚板LiveUSBでUSBメモリを管理するためのユティリティツールです。

このツールは当初、河豚板LiveUSBもまだなかったころ、河豚板LiveCDでmfsの内容をUSBメモリに保存し次回の起動で読み込むための補助的な存在でした。

現在ではUSBメモリへのデータ保存以外にも、LiveUSBメディアのカスタマイズ・再構築やディスクデバイスの構成変更などを行える、河豚板LiveUSBの総合管理ツールとなっており、日本語デスクトップ環境構築対話的ネットワーク設定ライブアップデートなどを行うツールとならび、河豚板独自の機能を提供しています。
(なお、このツールには"USB Flashdrive"という名称が使われていますが、実際にはOpenBSDがマウントして読み書きできる全てのストレージデバイスに対して利用可能です)

今回は、このusbfadmについて見ていきます。


目次

usbfadmの機能

機能一覧

コマンド名機能
syncメモリ上のファイルシステムの内容をUSBメモリへ保存(同期)
newdriveUSBメモリに河豚板のシステムを作成(リマスタリング)
expandLiveUSBのデータ保存領域を拡張
archivesyncで保存したデータをアーカイブ化
targetsync,archive,expandするデバイス・パーティションを設定
saveasUSBメモリへの保存データ名を設定
infotargetで指定したパーティションの状況を表示
コマンド名クリックで「河豚板ガイド」の説明箇所へ

実行例

以下のように、対話形式での利用が基本となっている。実行にはroot権限が必要。

nimbus33$ doas usbfadm
doas (kaw@nimbus33.honjoji.local) password: 

Welcome to usbfadm.
USB flash drive administration tool for FuguIta

Version/Arch: 7.6/amd64  (FuguIta-7.6-amd64-202504091)
    Boot mode: usbflash
Target device: /dev/sd2d
Data saved as: nimbus33

readline capability available
TAB to complete the reserved words

Type ? for help.

sd2d : nimbus33 ->?

Interactive commands are;
    target    -  set the partition for sync, info and expand
    saveas    -  set the name of the data to be saved
    sync      -  sync the target with the current mfs
    archive   -  archive saved directory to *.cpio.gz
    info      -  show info about the target partition
    newdrive  -  make a new FuguIta LiveUSB
    expand    -  expand the target partition as large as possible
    bye, exit, quit
              - end of this utility

Command line options are;
    -r : redo sync non-interactively
        (must run 'sync' at interactive mode before doing this)
    -i : show info about the persistent storage
    -q : quiet mode when redo sync
    -t : trace output (pass -x to shell)
    -d : debug output for newdrive to file 'usbf.debugout'
    -h : print this help

sd2d : nimbus33 ->

上の「sd2d : nimbus33 ->」がコマンドプロンプト。この例では「sd2d」が操作対象のパーティション、「nimbus33」がsync, archiveを行う際の名称を表している。

各機能の説明

sync

メモリ上のファイルシステムの内容をUSBメモリへ保存(同期)する。

usbfadm_sync.png
メモリからストレージへの同期

newdrive

河豚板LiveUSBを新規作成(リマスタリング)する。

usbfadm_newdrive.png

なお、上の図からわかるように、newdriveでは保存データのコピーは行わないため、元のシステムと同じ環境が必要な場合は、別途、targetを新デバイスに変更した上でsyncを実行する必要がある。

expand

デバイスに未使用領域がある場合、データ保存用パーティションをデバイスのサイズ一杯まで拡張する。

河豚板LiveUSBのイメージファイルは、現在、2GBのサイズで作成され、配布されている。
よって、それ以上のサイズのUSBメモリにイメージを書き込んで使用することになるが、書き込んだだけでは使用するUSBメモリのサイズに関係なく2GBしか領域を使用できない。そして、河豚板のシステムが約1GBを占有しているので、usbfadmでデータを保存できるのは1ギガバイト程度となる。

expandコマンドは、データ保存用パーティションをデバイスのサイズ一杯まで拡張し、デバイスを有効に使用できるようにする。

usbfadm_expand.png

archive

saveasで指定した保存データをアーカイブ化する。

saveasコマンドで指定し、syncコマンドで保存したファイルツリーから*.cpio.gz形式のアーカイブを作成する (パス名の最大長は、tarよりもcpioが長いため、cpioを採用した)。

usbfadm_archive.png

このアーカイブファイルは、syncで保存したデータと同様、河豚板の起動モード3で指定して読み込むことができる。

実装上のTopics色々

スクリプトの概要

usbfadmは、ディスクデバイスを管理するコマンドに対するwrapper scriptという見方もできる。

usbfadmが提供する機能は、fdisk, disklabel, newfs, bioctlなど、ディスクデバイスを扱うコマンドを直接使用することで実行できるが、usbfadmはそれらコマンドの詳細を知ることなく、河豚板LiveUSBの管理を安全かつ容易に実行可能。

usbfadmは、単一のkshスクリプトで、概ね以下のような構成になっている。
参考: usbfadmのソースコード (GitHub)

#ユティリティ関数群の定義
echoerr() { ... }
clear_exit() { ...}
 ...

#各コマンド関数群の定義
cmd_sync() { ... }
cmd_archive() { ... }
 ...

#ここからメイン処理

#初期化
大域変数の定義
実行環境のチェック
デフォルト値の設定
設定ファイルの読込
コマンドラインオプションの解析

if コマンドラインオプションあり; then
  非対話的処理
  (usbfadm -rなど)
  clear_exit
fi

#対話的処理
while :; do
  プロンプトの表示
  コマンドの読込
  case コマンド in
    sync)    cmd_sync;;
    archive) cmd_archive;;
    ...
  esac
done
clear_exit

ユーザがCtrl-Cなどでusbfadmを強制終了させた場合、安全に終了できること。副作用なくクリーンに終了すること。

readline機能の付加

コマンドの読込には、rlwrapコマンドを利用したrl_wread関数を定義。この関数により、以下の機能が実装されている。

rl_wread関数は、始めにrlwrapコマンドをダミーで起動し、rlwrapコマンドが正常に使えるか判定する。rlwrapが正常に使用できない場合は、単純なread文にフォールバックする。

#-------------------
# read user's input with readline functionality
# outputs echoed to stdout
#
#     usage: rl_wread prompt-str default-str [completion words ....]
#
rl_wread () {
    local prompt="$1";  shift
    local default="$1"; shift
    local retval

    # check if rlwrap is available
    #   When control tty is missing (in /etc/rc.shutdown for example),
    #   rlwrap in command substitution "$(rlwrap ...) " fails.
    if retval=$(rlwrap true) 2>/dev/null 2>&1 ; then
        echo "$@" > $lockdir/rl_words
        rlwrap -b '' \
               -f $lockdir/rl_words \
               -P "$default" \
               sh -f -c 'echo -n "'"$prompt"'->" >&2 ; read w || echo EOF; echo $w' || echo RL_ERR
    else
        #-------------------
        # fallback to dumb input
        #
        if [[ -z "$default" ]]; then
            echo -n "${prompt}->" >&2
            read w
        else
            echo -n "$prompt [$default] -> " >&2
            read w
            if [[ -z "$w" ]]; then
              w="$default"
            fi
        fi
        echo $w
    fi
}

使用法: ユーザの入力値は標準出力に返されるので、シェルのコマンド置換でキャプチャする。
end of fileの場合は文字列「EOF」が、エラーが発生した場合は「RL_ERR」が返される。

cmd=$(rl_wread "$d : $u " '' quit bye exit sync archive info saveas target newdrive expand help ?)
                   ↑     ↑  ↑
               プロンプト ↑  TABで補完する単語群
                     デフォルト値

プラットフォーム依存の処理

usbfadmは、OSによって抽象化されたデバイスやファイルを扱うので、処理の大部分はプラットフォーム非依存だが、newdrive機能では、起動廻りの処理を扱うのでプラットフォームに依存する部分が存在する。
この処理は、newdrive()関数内で/etc/fuguita/usbfadm_postproc.shを読み込む(sourceする)ことで対応している。

arm64アーキテクチャの例:
河豚板/arm64では、newdrive時にラズパイ3/4用にEFI/U-boot関連の設定が必要なので、その処理をusbfadm_postproc.sh.arm64で行っている。

#
# post processing for Raspberry Pi 3/4
# This file is included in usbfadm
#

notice "Change partition ID and Boot flag for Raspberry Pi..."

if [ "$instsys" = UEFI ]; then
    echo "e 0\n0C\n\n\n\nf 0\nq" | fdisk -e "$scandev"  ← パーティションタイプの変更
fi


# install Raspberry Pi Firmwares and U-Boot binaries
#
notice "Copying U-BOOT stuffs..."

if mount -t msdos -o-l /dev/${scandev}i /mnt; then
    tar -xvz -C /mnt -f /usr/fuguita/mdec/bootstuff.$(uname -m).tar.gz  ← ESPにブート関連の
    umount /mnt                                                            ファイルを配置
fi

expand機能の改良: GPTの拡張

expand機能は、従来、MBRパーティションにのみ対応していた。河豚板LiveUSBの配布イメージはMBR+UEFIで行っており、これで必要十分であったが、GPTの場合にもデータ保存領域の拡張が行えるようexpand機能の改良を行った。

usbfadmではパーティションの操作を行う際は、行いたい操作に操作するfdiskやdisklabelのコマンド文字列を生成し、これをパイプライン経由でそれらのコマンドに入力することで実現している。

コーディング例

fdisk_input="e ${partid_obsd}\nA6\nn\n\n*\nw\nq\n"
  ...
echo -n "$fdisk_input" | fdisk -e "$scandev" >/dev/null

GPTのパーティション拡張の場合も、概ねこの方針でOKだが、新たに以下の問題が発生する。

usbfadm_gptexpand.png

GPTの再構成方法の概要は以下のとおり

なお、この処理はGPTを全面的に書き換えるクリティカルな処理のため、以下のようなエラー対策を実施している。

GPT拡張後、disklabelコマンドを呼び出してデータ保存用パーティションの拡張を行う。この部分は従来のMBRパーティションの場合と同じ。

今後の開発予定

おまけ

河豚板 7.7の「日本語デスクトップ環境デモ版」を作ってみたので、使ってみてください。


Front page   New Page list Search Recent changes   Help   RSS of recent changes