Top/EBUG勉強会/20250531_usbfadm

usbfadm

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

usbfadm (USB Flashdrive ADMinistration tool)

usbfadmは、河豚板でUSBメモリを管理するためのユティリティツールであり、河豚板の機能の中核を担っている。

これは、USBメモリを扱うためのツールであるが、河豚板LiveUSBの登場以前から存在しており、当初は河豚板LiveCDで、mfsの内容をUSBメモリに保存し次回の起動で読み込む、河豚板LiveCDの補助ツールだった。

機能

sync
メモリ上のファイルシステムの内容をUSBメモリへ保存(同期)
newdrive
USBメモリに河豚板のシステムを作成
expand
LiveUSBのデータ領域を拡張
archive
saveasで指定した保存データをアーカイブ化
target
sync,archive,expandするデバイスを指定
saveas
USBメモリへの保存データ名を設定
info
targetで指定した保存用パーティションの状況を表示

利用は、以下のように対話形式で行うのが基本。

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 ->

各機能の説明

sync

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

usbfadm_sync.png

newdrive

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

usbfadm_newdrive.png

※) 河豚板LiveDVDのISOイメージファイルを生成する場合は、remaster_dvdコマンドを使用する。

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スクリプトで、概ね以下のような構成になっている。

#ユティリティ関数群の定義
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

readline機能の付加

コマンドの読込には、rlwrapコマンドを利用して、rl_wread関数を定義。コマンド/デバイス/ファイルなどの補完が可能になっている。

始めにrlwrapコマンドをダミーで起動し、rlwrapコマンドが正常に使えるか判定。NGな場合は、単純な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
}

使用法

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.$(ARCH)を読み込むことで対応している。

例: (ビルドシステム)/lib/usbfadm_postproc.sh.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
    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だが、新たに以下の問題が発生する。


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