disklabel

install in GPT

OpenBSD6.5をuEFI対応PCにインストールする方法

OpenBSD のインストール (7.0 ARM64 on rpi 版)

切り口を変えて検索すると、色々な方の例が出て来るなあ。世の中リナだけで回っていない事がよく分る。

endian

ふと、 エンディアン について調べてみた。

日本はビッグエンディアンが普通だ。年月日って表す。ヨーロッパは、日月年って具合。 日付の国際規格では、2022-11-15 のように表す。この日は、神社、写真館、レンタルな衣装屋が儲かる日だな。

糞石の世界は、ひねくれていて、リトルエンディアンだ。どう格納されるか、小さいコードで確認してみる。 @ FreeBSD(32Bit version)

int lo = 0x12345678;
int hi = 0xfedcba98;
int main() {}

gdbでmainで止める。

(gdb) p/x lo
$2 = 0x12345678
(gdb) p/x hi
$3 = 0xfedcba98
(gdb) x/8b &lo
0x40393c <lo>:  0x78    0x56    0x34    0x12    0x98    0xba    0xdc    0xfe

long longな場合はどうか?

(gdb) p/x abc
$1 = 0x123456789abcdef
(gdb) x/8b &abc
0x403830 <abc>: 0xef    0xcd    0xab    0x89    0x67    0x45    0x23    0x01

hexeditを使って、バイナリーデータを検索する時は、要注意だな。ってか、脳内変換なんて、到底無理と思うので、変換スクリプトを考えてみる。rubyでやるなら、取り敢えず2文字づつの分解が山だな。

vbox$ irb
irb(main):001:0> s = "1234567890"
=> "1234567890"
irb(main):002:0> n=2
=> 2
irb(main):003:0> s.scan(/.{1,#{n}}/)
=> ["12", "34", "56", "78", "90"]

でも、rubyはデフォでは入っていない。やはり古典的な方法が無難だ。ああ、pythonなんて論外です。頼みもしないけど、いつの間にか鎮座してるけどね。

#!/bin/sh
# big endian to little endian
echo $1 | sed -e 's/0x//' |
awk  '{
     if ( length($0) % 2 == 1 ) { $0 = sprintf("0%s", $0) }
     for (i = length($0) - 1; i > 0; i -= 2) {
         printf substr($0, i, 2) ;
     }
     printf "\n"; } '

使用例。上のC言語のサンプルをコンパイル。そうしておいてバイナリーエディタを起ち上げ。vi宜しく、/ で検索文字を入力。カーソルはvvの所に来た。続く、0xfedcba98も次の位置に見えている。これで、検索が捗るな。

vbox$ b2l 0x12345678
78563412
vbox$ hexedit a.out
                            Hexa string to search: 78563412
                                                  vv
000010C0   61 17 00 00  81 17 00 00  A1 17 00 00  78 56 34 12  a...........xV4.
000010D0   98 BA DC FE  01 11 01 25  0E 13 05 03  0E 10 06 1B  .......%........
---  a.out       --0x10DC/0x1AF0--63%------------------------------------------

こんなに頭を悩ませるのは、そもそも糞石のせい。普通の人はビッグエンディアンなのに、あの石は常軌を逸脱したリトルエンディアンですから。それからラズパイの石ってかOSもリトルエンディアンなんだよな。困ったものだ。

最近、考古学者は名探偵なんて本を読んだんよ。そしたら、本当に糞石ってのが有るそうな。 コプロライトって学術名がついているらしい。ギリシャ語で、コプロってのが糞を意味し、ライトは石の意味だそうだ。

遺跡を発掘すると、昔の人の便所が出てくる事があるとか。条件が良いと糞が石状になってるらしい。これを分析すると、昔の人が何を食べていたか分るとか。寄生虫の卵を分析するとか、人と犬のウンチは似てて区別がつかなかったけど、残留脂肪酸分析で区別がつくようになったとか。

先人の活躍、ウンチに対する知見を広めるため、はじめ – ふんばった時に最初に出てくる先端部分、シボリ – 最後の部分、バナナ – 中間の弧の部分、コロ – 便秘ぎみ。その他、踏まれてひしゃげた物はフミクソ、火にあぶられた跡のある物はヤケクソって言うらしい。落語みたいだな。一度聞いたら忘れられない強烈なネーミングだ。

おさらい

ちょっと32MのDISKを作って、それを8Mと24Mのパーテションに分てみる。

vbox# dd if=/dev/zero of=test.img bs=1M count=32
32+0 records in
32+0 records out
33554432 bytes transferred in 0.335 secs (100110771 bytes/sec)
vbox# vnconfig test.img
vnd0
vbox# disklabel -E vnd0
Label editor (enter '?' for help at any prompt)
vnd0> a d
offset: [0]
size: [65536] 16384
FS type: [4.2BSD]
vnd0*> a e
offset: [16384]
size: [49152]
FS type: [4.2BSD]
vnd0*> w
vnd0> p
OpenBSD area: 0-65536; size: 65536; free: 0
#                size           offset  fstype [fsize bsize   cpg]
  c:            65536                0  unused
  d:            16384                0  4.2BSD   2048 16384     1
  e:            49152            16384  4.2BSD   2048 16384     1

cパーテションはDISK全体を表す決まりになってる。それ以外では、a,bパーテションがデフォの機能を担当する事になってて、後は自由だ。

vbox# newfs vnd0d
/dev/rvnd0d: 8.0MB in 16384 sectors of 512 bytes
4 cylinder groups of 2.00MB, 128 blocks, 256 inodes each
super-block backups (for fsck -b #) at:
 160, 4256, 8352, 12448,
vbox# newfs vnd0e
/dev/rvnd0e: 24.0MB in 49152 sectors of 512 bytes
4 cylinder groups of 6.00MB, 384 blocks, 768 inodes each
super-block backups (for fsck -b #) at:
 160, 12448, 24736, 37024,

それぞれをnewfsしてみた。次は、それをマウントして、DISKの容量とinodeの消費状態を確認。

vbox# mkdir /tst
vbox# mount /dev/vnd0d /mnt
vbox# mount /dev/vnd0e /tst
vbox# df -ki
Filesystem  1K-blocks      Used     Avail Capacity iused   ifree  %iused  Mounted on
  :
/dev/vnd0d       7726         2      7338     0%       1    1021     0%   /mnt
/dev/vnd0e      23598         2     22418     0%       1    3069     0%   /tst

4シリンダー有るので、実際に使える容量とinodeは報告された物の4倍になる。また、1つのファイルの最小容量は2048byteだ。これは、fsize すなわちフラグメントサイズになる。bsizeと言うのはブロックサイズを意味し、DMAでの転送単位になるのかな。

シリンダーってのは、DISKを半径方向に分割し、使用エリアが分散するような管理をしてる。また、大事なスーパーブロックもそれぞれのシリンダーに分散させてバックアップを兼ねさせている。

vbox# disklabel -E vnd0
Label editor (enter '?' for help at any prompt)
vnd0> p
OpenBSD area: 0-65536; size: 65536; free: 0
#                size           offset  fstype [fsize bsize   cpg]
  c:            65536                0  unused
  d:            16384                0  4.2BSD   2048 16384   128
  e:            49152            16384  4.2BSD   2048 16384   384

一度使用すると、cpgが更新されるみたい。これは、個々のシリンダーグループが幾つのシリンダー(トラック)で構成されてるかを表すのかな。

disklabel

DISKの区画を作るのに手動でやった。自動でやる場合は、どんな風に分るか、更にはDISKの諸元が必要だ。それをあらかじめ登録したファイルが有る。OpenBSDではお任せにしちゃう事が多いので、余り登録されていない。下記は、FreeBSDから代表例を引いてきたものだ。

/etc/disktab

# a == root
# b == swap
# c == d == whole disk
# e == /var
# f == scratch
# h == /usr

cp3100new|Connor Peripherals 100MB IDE, with a different configuration:\
        :dt=ST506:ty=winchester:se#512:nt#8:ns#33:nc#766: \
        :pa#15840:oa#0:ta=4.2BSD:ba#4096:fa#512: \
        :pb#24288:ob#15840:tb=swap: \
        :pc#202224:oc#0: \
        :pd#202224:od#0: \
        :pe#15840:oe#40128:te=4.2BSD:be#4096:fe#512: \
        :pg#15840:og#55968:tg=4.2BSD:bg#4096:fg#512: \
        :ph#130416:oh#71808:th=4.2BSD:bh#4096:fh#512:

それはさておき、本物のDISKで試してみる。今迄は、ファイルをデバイスに見立てるって方法だったからね。

qemu disk

qemuにDISKを用意させ、そいつを有効にして起動。次は、disklabelを使って、オートレイアウトで、パーテショニング。出来栄えを確認。

ob$  qemu-img create -f qcow2 ext.img 4G
Formatting 'ext.img', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=4294967296 lazy_refcounts=off refcount_bits=16
ob$ ./boot -E
 :
qm# disklabel -wA wd1
qm# disklabel wd1
# /dev/rwd1c:
type: ESDI
disk: ESDI/IDE disk
label: QEMU HARDDISK
duid: 2fd85dfcaa0d1990
flags:
bytes/sector: 512
sectors/track: 63
tracks/cylinder: 255
sectors/cylinder: 16065
cylinders: 522
total sectors: 8388608
boundstart: 0
boundend: 8388608
drivedata: 0

16 partitions:
#                size           offset  fstype [fsize bsize   cpg]
  a:          1808352                0  4.2BSD   2048 16384     1
  b:           503800          1808352    swap
  c:          8388608                0  unused
  d:          5314080          2312160  4.2BSD   2048 16384     1
  e:           762368          7626240  4.2BSD   2048 16384     1

a,d,eのパーテションは地均しする必要が有る。で、dパーテションだけフォーマット。この時、各パーテション毎に4つのシリンダーグループが作られるんで、12ヶ出来るはずだけど、一つ多い。それって、swap用かな。

qm# newfs wd1d
/dev/rwd1d: 2594.8MB in 5314080 sectors of 512 bytes
13 cylinder groups of 202.50MB, 12960 blocks, 25920 inodes each
super-block backups (for fsck -b #) at:
 160, 414880, 829600, 1244320, 1659040, 2073760, 2488480, 2903200, 3317920,
 3732640, 4147360, 4562080, 4976800,

こうしてdパーテションを作成すると、cpg は、12960 にセットされてたよ。

ラベルブロックがどんな風になってるか、確認したい。が、相手は本物?のHDD、そのままではアクセスが面倒。そんな時の為にDISK全体を表すcパーテションを利用する。

DISKの先頭の1ブロックをスキップしてから1セクター分のデータを取出して確認。

qm# dd if=/dev/wd1c of=sb.txt   skip=1 count=1
1+0 records in
1+0 records out
512 bytes transferred in 0.005 secs (97312 bytes/sec)
qm# hexdump -C sb.txt
00000000  57 45 56 82 05 00 00 00  45 53 44 49 2f 49 44 45  |WEV.....ESDI/IDE|
00000010  20 64 69 73 6b 00 00 00  51 45 4d 55 20 48 41 52  | disk...QEMU HAR|
00000020  44 44 49 53 4b 20 20 20  00 02 00 00 3f 00 00 00  |DDISK   ....?...|
00000030  ff 00 00 00 0a 02 00 00  c1 3e 00 00 00 00 80 00  |.........>......|
00000040  2f d8 5d fc aa 0d 19 90  00 00 00 00 00 00 00 00  |/.].............|
00000050  00 00 00 00 00 00 80 00  00 00 00 00 00 00 00 00  |................|
00000060  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000070  00 00 01 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000080  00 00 00 00 57 45 56 82  98 9f 10 00 00 20 00 00  |....WEV...... ..|
00000090  00 00 01 00 e0 97 1b 00  00 00 00 00 00 00 00 00  |................|
000000a0  07 14 01 00 f8 af 07 00  e0 97 1b 00 00 00 00 00  |................|
000000b0  01 00 00 00 00 00 80 00  00 00 00 00 00 00 00 00  |................|
000000c0  00 00 00 00 20 16 51 00  e0 47 23 00 00 00 00 00  |.... .Q..G#.....|
000000d0  07 14 a0 32 00 a2 0b 00  00 5e 74 00 00 00 00 00  |...2.....^t.....|
000000e0  07 14 01 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200

busy ?

上で出て来た仕様書により区画を作れるか確認。まあ無理筋とは思うけど。

qm# disklabel -w /dev/wd1c cp3100new
disklabel: DIOCWDINFO: Device busy
qm# disklabel -wA /dev/wd1c

やっぱり無理、理由は忙しいとな。そんなのソース嫁。 disklabel.c

writelabel(int f, struct disklabel *lp)
{
                /* Write new label to disk. */
                if (ioctl(f, DIOCWDINFO, lp) == -1) {
                        warn("DIOCWDINFO");
                        return (1);
                }

その先は、 dev/ata/wd.c ここみたいって、大変な場所だな。この先を見る気分じゃないよ。

wdioctl(dev_t dev, u_long xfer, caddr_t addr, int flag, struct proc *p)
{
        case DIOCWDINFO:
        case DIOCSDINFO:
                if ((flag & FWRITE) == 0) {
                        error = EBADF;
                        goto exit;
                }

                if ((error = disk_lock(&wd->sc_dk)) != 0)
                        goto exit;

                error = setdisklabel(wd->sc_dk.dk_label,
                    (struct disklabel *)addr, wd->sc_dk.dk_openmask);

これHDDが持ってる特性エリアを直接読み出したものだろう。それを曲げて違うHDDを名乗るって、詐欺になるぞって事なんだな。

qm# atactl wd1 identify
Model: QEMU HARDDISK, Rev: 2.5+, Serial #: QM00002
Device type: ATA, fixed
Cylinders: 8322, heads: 16, sec/track: 63, total sectors: 8388608
Device capabilities:
        IORDY operation
Device supports the following standards:
ATA-4 ATA-5 ATA-6 ATA-7
Device supports the following command sets:
        NOP command
        Write cache
        SMART feature set
        Flush Cache Ext command
        Flush Cache command
        48bit address feature set
Device has enabled the following command sets/features:
        NOP command
        Write cache
        SMART feature set
        Flush Cache Ext command
        Flush Cache command
        48bit address feature set

smart

本物のDISKだとSMARTが動くらしいので、確認する

qm# atactl /dev/wd1c smartread
Off-line data collection:
    status: completed ok
    activity completion time: 288 seconds
    capabilities:
        execute immediate
        read scanning
        self-test routines
Self-test execution:
    status: completed ok or not started
    recommended polling time:
        short routine: 2 minutes
        extended routine: 54 minutes
SMART capabilities:
    saving SMART data
    enable/disable attribute autosave
Error logging: supported
qm# atactl /dev/wd1c smartreadlog selftest
Test 1
    LBA Low: 0x0
    status: completed ok or not started
    timestamp: 4660
    failure checkpoint byte: 0x0
    failing LBA: 0x0

portsにsmartmontoolsが有ると言うのにデフォで機能を搭載してるって、安全に留意してますって事かな。変な事をされない為ってのが錦の旗です。

seeing by disklabel

vnd0を作って、-wA vnd0 した時の図。

(gdb) bt
#0  writelabel (f=6, lp=0x348b1070) at disklabel.c:311
#1  0x148bdc3b in main (argc=1, argv=0xcf7e198c) at disklabel.c:286
(gdb) p *lp
$3 = {d_magic = 2186691927, d_type = 12, d_subtype = 0,
  d_typename = 0x348b1078 "vnd device", d_packname = 0x348b1088 "fictitious",
  d_secsize = 512, d_nsectors = 100, d_ntracks = 1, d_ncylinders = 655,
  d_secpercyl = 100, d_secperunit = 65536, d_uid = 0x348b10b0 "",
  d_acylinders = 0, d_bstarth = 0, d_bendh = 0, d_bstart = 0, d_bend = 65536,
  d_flags = 0, d_drivedata = 0x348b10cc, d_secperunith = 0, d_version = 1,
  d_spare = 0x348b10e4, d_magic2 = 2186691927, d_checksum = 21137,
  d_npartitions = 16, d_bbsize = 8192, d_sbsize = 65536,
  d_partitions = 0x348b1104}

詐欺を働こうとすると、

318                     if (ioctl(f, DIOCWDINFO, lp) == -1) {
(gdb)
0x18fd1080          #define __sgetc(p) (--(p)->_r < 0 ? __srget(p) : (int)(*(p)->_p++))
(gdb)
319                             warn("DIOCWDINFO");
(gdb)
disklabel: DIOCWDINFO: Device busy
320                             return (1);

こんな風に引掛った。

dd

今迄度々登場してるddコマンド。 A dd utility appeared in Version 5 AT&T UNIX. のように由緒あるやつ。dd - convert and copy a file とあるように、cpのついでにconvertするのが主目的。

大型コンピュータのデータをunixとやり取りするのが主目的。その頃の大型コンピュータと言ったら、IBMさんのやつがデファクトスタンダード。こいつの文字コードがebcdicという独自のもの。unixのASCIIコードとは、相容れないやつだ。

だから、コピーのついでに文字コードも変換出来たら楽だねって事で、unix側がすりよった。 小さな工夫と言ったらなんだけど、512バイトのブロック単位にコピー出来れば更に楽出来る。 という事で、コピーの単位を512バイトをデフォとした。そして、それを何回繰り返すって指定も出来るようにした。ifとかofってのは、入出力のファイル名。

sakae@deb:~$ dd if=/dev/zero of=z count=1000000
1000000+0 records in
1000000+0 records out
512000000 bytes (512 MB, 488 MiB) copied, 7.68823 s, 66.6 MB/s
sakae@deb:~$ dd if=/dev/zero of=z count=1000 bs=512000
1000+0 records in
1000+0 records out
512000000 bytes (512 MB, 488 MiB) copied, 8.23623 s, 62.2 MB/s

で、上のような例になる。bsでブロックサイズを任意に設定出来る。bsを大目にして、繰返し回数を減らせば、スピードアップが図れる。普通はこの使いかたをする。

それから変換の指定は、conv=ibm,lcase と言うように機能をカンマ区切で並べて指定する。今となっては遺物っぽいな。

R + Tcl/Tk