我が家の(と言うより、僕の)コンピュータ環境に発生している、ある特殊な問題(あとで紹介する)の解決のために、Mac に関する問題をいろいろ調べることになった。長い間、Mac でシステムプログラミングをしていなかったので、OS 周りのことはすっかり忘れてしまっている。以下では僕の知識を整理し、また新たに得た知識を補いながら、 MacOS について今回いろいろ気がついたことを書いている。また僕の立場からの不満を述べているが、それらは、現在では解決されているかも知れない。(何しろ僕の環境は古い!)
unix のコマンドについての十分な知識を持っている読者を想定している。
最初に、この話の中で登場するコンピューターを紹介しておく。主役は mbook である。コマンドのプロンプトにはホスト名が使われているので、どこで実行されたか判るであろう。
mbook
MacBook Pro 10.2 with Sierra (= ver.10.12.6)
2012 Model, 500GB SSD, 8GB memory
購入から 10 年近く経っているが、まだバリバリに使える。
OS のアップグレードはもはやできない。
MacBook を買い換える気はない。最後まで使い切るのが僕の主義である。
Apple は Mac を現代の文具として位置付けていると思う。しかも誰でも使える文具を目指している。
コンピューターとしての使いやすさを求める僕のような人間を、Apple はユーザーとしては想定していないと思える。
hebe
Plan9/9front の下で動いているサーバーである。この Web のページも hebe でサービスしている。
maia
Linux/Ubuntu の下で動いているサーバーである。外部にはサービスしていない。単に Linux ではどうなっているかを調べるために存在する。
普通の Mac のユーザー(コマンドを使わないユーザー)は ".DS_Store
" の名のファイルの存在に気付かないと思う。ほぼ完全に隠されているからである。他方、ネットで ".DS_Store
" を検索すると不満タラタラである。このファイルは Mac のユーザーには隠れて見え難いのであるが、他の OS のファイルシステムの中に作られると、露わに見える。多くのユーザは SD カードや USB メモリーなども使い、そこに Mac で作られたファイルをコピーしたりする。それを Windows など、Mac 以外の OS でみると ".DS_Store
" を露わに見ることになり、これは何だ、気持ち悪い! と言うことになる。
僕の観察では、".DS_Store
" は
.DS_Store
" を表示しない
".DS_Store
" は Finder からは見えないが、コマンド環境では存在が確認できる。
mbook$ ls -al -rw------- 1 arisawa staff 8196 7 12 06:41 .DS_Store
勝手に ".DS_Store
" が作られるのは鬱陶しい。しかし、標準設定では、消しても消しても作られる。
このファイルは Finder のアイコン表示で使われているようだ。実際、表示されているアイコンをマウスで移動すると ".DS_Store
" は更新される。 Finder をアイコン表示にし、アイコンをマウスで移動させることを許した場合、 移動後の位置情報の記憶が必要になる。そのアイコンの位置情報が ".DS_Store
" に含まれているとか。僕はアイコン表示にしないので、このような機能は僕にとっては必要ない。
以前は Finder の環境設定で unix の隠しファイル(ピリオド '.
' で始まるファイル)を見せるか否かの選択ができたのだが、現在はそのメニューは無くなっている。その代わりに
command + shift .
.DS_Store
は隠されている。
実は Finder が隠しているのは '.
' で始まるファイルだけではない。全ての開発環境が隠されていると言ってもよい1。
そのことは Finder に表示される root ディレクトリと、ls
コマンドで見える root ディレクトリを比較してみれば解る。
Finder はユーザー arisawa のエージェントとして動いている。このことは
mbook$ ps axl|grep 'Finder$' 501 351 1 0 4 0 5757832 370408 - S ?? 50:21.85 /System/Library/CoreServices/Finder.app/Contents/MacOS/Finder mbook$ ps axl|head -1 UID PID PPID CPU PRI NI VSZ RSS WCHAN STAT TT TIME COMMAND mbook$ id uid=501(arisawa) gid=20(staff) ... mbook$で確認できる。
501
は arisawa の UID である。従って arisawa では書き込み権限のないフォルダー(例えば システムフォルダー)には ".DS_Store
" は作られない。
".DS_Store
" は Mac にとって本当に必要なファイルなのであろうか? 代替え案を考えてみよう。
(a) Finder をアイコン表示にしたとしても、アイコンを移動した時にのみ ".DS_Store
" を作れば良いではないか?
(b) アイコンを移動するニーズは極めて稀であって、情報をメモリー上に持てば良いではないか? Finder がリスタートすれば記憶が消えるが、気にするような話でもなかろう。単に元の位置に並べ替えられるだけである。
このうち (a) は実現されている:
mbook$ defaults write com.apple.desktopservices DSDontWriteNetworkStores True mbook$ killall Finder(b) を採用しなかったのは Apple の完璧主義によるものか?
ファイルやフォルダーのアイコンを Finder の中に表示するために、Finder は各ファイルのアイコンにアクセスしに行く。この問題は Finder のリスト表示でもカラム表示でも発生しブラウジングの速度を落とす。Finder がローカルなファイルシステムを表示している限り、問題にならないのであるが、ネット上にあるファイルをマウントして Finder に表示している場合には、ブラウジングの遅さが気になって来る。そのために、Apple は macOS 10.13 以降、やり方を少し変えたとか[2]... Finder の中にファイルやフォルダーのアイコンが見えるのは、クールで見栄えが良い。しかしそれはブラウジングの速度を著しく落とす代償の上に成立していることを忘れてはならない。
文献[1]に DS_STORE
に関する丁寧な解説がある。
ファイル ".DS_Store
" の先頭部分は、例えば次のようになっている1:
mbook$ xd -c .DS_Store |p 0000000 00 00 00 01 B u d 1 00 00 18 00 00 00 \b 00 0000010 00 00 18 00 00 00 10 0b 00 00 00 00 00 00 00 00 0000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \b 00 0000030 00 00 \b 00 00 00 00 00 00 00 00 00 00 00 00 00 0000040 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 \n ...
いくつかの DS_Store
について試したが、先頭8Bは共通ではないかと思える。
DS_Store
についての書式は非公開らしい。推測するしかない。
先頭8Bに含まれる文字列 "Bud1
" は DS_Store
のマジックワードらしい。書式の推定については文献[4] と[5]が詳しい。また、たまたま見つけた[6]も面白い。
xd
(hexa dump) は unix の od
(octal dump) の 16進数版であり、plan9port に含まれている。xd
に頼らなくても hexdump
が Mac に備わっている。
[1] DS_STOREファイルとは何ですか?
https://www.file-extension.info/ja/format/ds_store
[2] macOS で SMB ブラウジングの動作を調整する (2021)
https://support.apple.com/ja-jp/HT208209
[3] DS Store File Format
https://wiki.mozilla.org/DS_Store_File_Format
[4] DS_Store Format
https://metacpan.org/dist/Mac-Finder-DSStore/view/DSStoreFormat.pod
[5] Parsing the .DS_Store file format
https://0day.work/parsing-the-ds_store-file-format/
[6] 50年前に作られたメモリ管理アルゴリズム「Buddy memory allocation」(2016)
https://codezine.jp/article/detail/9325
リソースフォークに関しては、(僕には)解らないことが多すぎる。同様なことは文献[6]の著者も述べている。整理する必要があるが、まだできていない。特に HFS Plus が解らない。Apple の公式な文献が[5]にある。しかし名前付きフォークがよく解らない。
file = "data fork" + "resource fork"
unix のファイルシステムでは初めからマルチユーザ環境が想定されていた。つまりサーバーとして設計されていた。マルチユーザ環境に必要なファイルに関する属性は整理され、それらはコマンド "ls -al
" で見ることができる。また現在では(習慣的に)ファイル拡張子に意味を持たせ、そのファイルの内容の基本的な特徴を表すようになっていて、Macintosh のリソースフォークの機能の一部を担っている。
Apple を追い出された Jobs が立ち上げた NeXTSTEP は、BSD 系の unix の OS の下で構築された。Apple に復帰した Jobs は、NeXTSTEP をベースにした OS を新しい Macintosh として売り出し、現在に至っている。"OS X" つまり "OS 10" の名称は NeXTSTEP が Macintosh の "OS 9" の後継であることをアピールしている。なお現在では "OS X" よりも "MacOS" と表現される。
Jobs は OS X のファイルシステムとして、NeXTSTEP のファイルシステム UFS (unix file system) を採用せず、Macintosh OS 9 のファイルシステム HFS Plus を採用した。その理由は多分次のようなものだろう。
https://ja.wikipedia.org/wiki/リソースフォーク
[2] Unix File System
https://ja.wikipedia.org/wiki/Unix_File_System
[3] NEXTSTEP
https://www.operating-system.org/betriebssystem/_english/bs-nextstep.htm
[4] 第7回 HFS、HFS Plusの基本的概念【前編】
https://www.itmedia.co.jp/enterprise/articles/0707/24/news009.html
白山さん良い記事を書きますね---。
[5] HFS Plus Volume Format
https://developer.apple.com/library/archive/technotes/tn/tn1150.html
[6] Mac OS X Resource Forks
https://jonsview.com/mac-os-x-resource-forks
「拡張属性」の対立概念として「基本属性」があるべきだが、市民権を得ていない1。もともと単なる「属性」があり、それを拡張したので「拡張属性」と言われている。
unix 系の OS の場合、ファイル属性とは "ls -l
" コマンドで見える情報である。例えば我が Mac では、ファイル foo.txt
の属性は
-rw-r--r-- 1 arisawa staff 1572 8 23 12:19 foo.txt
OS によっては、ここに含まれないファイル属性を持っている。それらは xattr
コマンドでみることができる。
MacOS のマニュアルには
XATTR(1) BSD General Commands Manual XATTR(1)とある。
The xattr command can be used to display, modify or remove the extended attributes of one or more files, including directories and symbolic links. Extended attributes are arbitrary metadata stored with a file, but separate from the filesystem attributes (such as modification time or file size). The metadata is often a null-terminated UTF-8 string, but can also be arbitrary binary data.
Mac の拡張属性には
mbook$ pwd /Users/arisawa/Downloads mbook$ ls -l rfc2555.txt -rw-r--r--@ 1 arisawa staff 42902 5 10 2020 rfc2555.txt mbook$ xattr -l rfc2555.txt com.apple.metadata:kMDItemWhereFroms: 00000000 62 70 6C 69 73 74 30 30 A1 01 5F 10 26 66 74 70 |bplist00.._.&ftp| 00000010 3A 2F 2F 66 74 70 2E 69 73 69 2E 65 64 75 2F 69 |://ftp.isi.edu/i| 00000020 6E 2D 6E 6F 74 65 73 2F 72 66 63 32 35 35 35 2E |n-notes/rfc2555.| 00000030 74 78 74 08 0A 00 00 00 00 00 00 01 01 00 00 00 |txt.............| 00000040 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 |................| 00000050 00 00 00 00 33 |....3| 00000055 com.apple.quarantine: 0081;5eb72ffd;Google Chrome.app;22CCDB41-A3E7-431C-B0CB-6B8E4E12389F mbook$ ls -l@ rfc2555.txt -rw-r--r--@ 1 arisawa staff 42902 5 10 2020 rfc2555.txt com.apple.metadata:kMDItemWhereFroms 85 com.apple.quarantine 68 mbook$この例では
rfc2555.txt
が Google Chrome を使って ftp://ftp.isi.edu/
からダウンロードされたことが読み取られるであろう。TextEdit.app
がファイルを読み取って、何か良からぬことをやらかせば、TextEdit.app
のバグではないか! バグであれば Apple の責任で修正するのが筋であろうに... Apple は何を心配しているのか全く理解できない。
他のアプリではどうか? iText Express、TeXShop.app、Xcode.app などでは
“main.txt” の開発元は未確認です。開いてもよろしいですか?と一応開かせて貰える。
MacOS にマウントされている他のフォーマットのファイルシステムでは、ファイル foo
の拡張属性は /._foo
のように、ファイル本体と別のファイルに作られる。MacOS のユーザは、あたかも foo が拡張属性を持っているかのように見える。
拡張属性は僕にとっては邪魔以外の何物でもない。
拡張属性は xattr
コマンドで除去できる:
xattr -c path xattr -cr path # act recursively
xattr
に関するプログラミングマニュアルには "basic attribute" がある。
mbook には SD カードのスロットが付いている。ここに SD カードを差し込むと SD カードの内容が(僕の場合には) /Volumes/MSD
に見える。ここに MSD
は僕が勝手に付けた名前である。
mbook$ ls -l foo.txt -rw-r--r--@ 1 arisawa staff 46 8 1 21:10 foo.txt mbook$ cp foo.txt /Volumes/MSD/tmp mbook$ ls -l /Volumes/MSD/tmp -rwxrwxrwx@ 1 arisawa staff 46 8 2 08:13 foo.txt mbook$
この SD カードは diskutil
コマンドでは "DOS_FAT_32
" と表示されている。
Windows 系のファイルシステムには、個々のファイルに対するアクセス管理の情報がない。
unix で言えばファイルの owner や group の概念が存在しない。もちろんリソースフォークの属性も存在しない。
それにも関わらず、あたかも Mac のファイルのように見せかけているのは MacOS の仕事である。これを他の OS で見るとどうなるか?
Linux/Ubuntu の下で動くシステム maia
で見ると
maia$ ls -al /media/arisawa/3237-6332/tmp total 71232 drwxr-xr-x 2 arisawa arisawa 32768 7月 9 00:32 . drwxr-xr-x 14 arisawa arisawa 32768 1月 1 1970 .. -rw-r--r-- 1 arisawa arisawa 4096 8月 2 2021 ._foo.txt -rw-r--r-- 1 arisawa arisawa 46 8月 2 2021 foo.txt maia$となる。
MacOS の cp コマンドは、コピー先(SD カード)に Mac の本来のファイルを作れないことを理解しているのだ。
Linux は unix 系で "." で始まる名前は隠されるので、目立たない。
ところが Windows 系では露わに見えるはずである。
SD カードでなくとも、mbook にマウントされた maia のファイルシステムについても同様である。
mbook$ ls -l foo.txt -rw-r--r--@ 1 arisawa staff 46 8 1 21:10 foo.txt mbook$ cp foo.txt /n/maia/home/arisawa/tmp mbook$ ls -al /n/maia/home/arisawa/tmp total 6656 -rw-r--r-- 1 arisawa staff 4096 8 2 11:31 ._foo.txt -rw-r--r--@ 1 arisawa staff 46 8 2 11:31 foo.txt mbook$
拡張属性を作らないシステムの設定が可能なら、僕はもっと幸せになるのだが...
Mac の
/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources
BookmarkIcon.icns
.icns
を持っている。.icon
ではなく、複数形になっているのは、様々なサイズのアイコンの集合だからである。.icns
を他の形式、例えば .png
に変換したくば、Preview.app
で可能である。Preview.app
で可能である。「書き出す」のときに option キーを組み合わせれば画像形式のメニューが増え、その増えたメニューの中に .icns
が含まれている。ls
コマンドで見た BookmarkIcon.icns
のサイズ 1497744-rw-r--r-- 1 arisawa staff 1497744 4 21 2017 BookmarkIcon.icnsは後の議論で使われる。
ファイルやフォルダーのアイコンを自分の好みのものしたければ、「情報を見る」を開いて、現在のアイコンの上に、好みのアイコンを重ねればよい:
フォルダー bar
のアイコンを好みのものに変更したとせよ。ls
コマンドで bar
を見ると:
mbook$ ls -l@ bar total 2928 -rw-r--r--@ 1 arisawa staff 0 8 24 16:09 Icon? com.apple.FinderInfo 32 com.apple.ResourceFork 1498054 mbook$ファイル "
Icon?
" が新たに作られ、そのファイルは、2つの属性 com.apple.FinderInfo
と com.apple.ResourceFork
を持っている。以下で話題にするのは com.apple.ResourceFork
の方である。その前に "Icon?
" の「?
」を片付けておく。
ls
コマンドによって "Icon?
" と表示されているこのファイルの名称は、実は "Icon?
" ではない。そのことは
mbook$ cd bar mbook$ echo -n Icon? |hexdump 0000000 49 63 6f 6e 0d 0000005 mbook$ echo -n 'Icon?' |hexdump 0000000 49 63 6f 6e 3f 0000005 mbook$で判る1。つまり "
Icon
" の末尾に、Macintosh 時代の改行コードであった "0d
" が添えられて、それが ls
コマンドでは 「?
」として見えているのだ。そしてls Icon?
?
」はシェルのワイルドカードであり、任意の1文字にマッチする。従ってこのケースでは 0d
コードにマッチする。何のために Apple はこんなつまらないトリックを?
BookmarkIcon.icns
のサイズは 1497744
であったが、このアイコンを表示する "Icon?
" の ResourceFork
のサイズは、これより少し大きい 1498054
である。少し膨らませて Apple は何をしたのだろう? いくつか実験をしてみた:
(1) フォルダー baz
を作り、そこに bar
の "Icon?
" をコピーしたら baz
のアイコンになるか? ⇒ ならない
(2) bar
を qux
と名称変更したら "Icon?
" は qux
のアイコンになっているか? ⇒ なっている
(3) bar
から bar.tar
を作り、どこかにコピーして展開して bar
を作ると、この bar
のアイコンは "Icon?
" になっているか? ⇒ なっている
以上の3つを満たす方法を考えてみたが、簡単な方法は思いつかない...
Mac のファイルやフォルダーは拡張属性を抱えているために、プログラム作りは unix に比べて一段と面倒になる。単なるコピーだけでも...
コマンド環境でも拡張属性を(ある程度)扱える。"Icon?" を例にとる。
mbook$ xattr -px com.apple.ResourceFork Icon? > res mbook$ ls -l total 11712 -rw-r--r--@ 1 arisawa staff 0 8 24 16:09 Icon? -rw-r--r-- 1 arisawa staff 4494162 8 25 12:58 res mbook$
res
のサイズが com.apple.ResourceFork
の3倍になったのは res
は 16進数で表現されmbook$ head res 00 00 01 00 00 16 DB 94 00 16 DA 94 00 00 00 32 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...のようになっているからだ。
そこでこの res
を他のファイルのアイコンに使ってみよう。
mbook$ touch baz.txt mbook$ xattr -wx com.apple.ResourceFork "`cat res`" baz.txt -bash: /usr/bin/xattr: Argument list too long mbook$うーむ... これは
xattr
コマンドのバグでしょう...
ls
コマンドは -b
や -B
のフラグを持っており、ファイル名に含まれる制御文字を表示してくれる。
文献[2] はあまり役に立たない。microsoft の説明である点で載せた。解説は文献[3]が良く纏まっている。
[1] 拡張ファイル属性
https://ja.wikipedia.org/wiki/拡張ファイル属性
[2] FAT、HPFS、NTFS ファイル システムの概要
https://docs.microsoft.com/ja-jp/troubleshoot/windows-client/backup-and-storage/fat-hpfs-and-ntfs-file-systems
[3] 第9回 Windowsのファイルシステムの概要とFATファイルシステム
https://www.atmarkit.co.jp/ait/articles/1507/16/news034.html
MacOS には chflags
と言うコマンドがある。
使い方は次のようなものである:
mbook$ pwd /Users/arisawa mbook$ ls -lO total 184 drwxr-xr-x 9 arisawa staff - 306 11 7 2019 Applications ... drwx------@ 8 arisawa staff - 272 4 16 2017 GoogleDrive drwx------@ 101 arisawa staff hidden 3434 7 17 2019 Library drwx------ 6 arisawa staff - 204 1 13 2017 Movies ... mbook$"
ls
" のオプション "-lO
" の "O" は大文字の "O" (オー) である。Options の意味であろう。単なる "ls -l
" と異なりオプションを表示する欄が現れる。Library
" に対して "hidden
" のオプションが指定されている。マニュアル1によると GUI から隠されるのだとか... 実際 Finder からは ホームディレクトリに存在するはずの「ライブラリ」が見えない。見えるようにするにはmbook$ chflags nohidden Library
mbook$ chflags hidden Library
マニュアルによると、chflags
の変更対象となるフラグには管理者特権を要するもがある。これらの情報は、一種の拡張属性ではあるが、コマンド xattr
で変更できる fork とは別の fork に含まれていると推測する。
root ディレクトには Finder では表示されない多数の名前があった。そこではどうなっているか?
mbook$ cd / mbook$ ls -lO total 69 drwxrwxr-x+ 187 root admin sunlnk 6358 8 8 15:08 Applications drwxrwxr-x@ 16 root admin - 544 9 2 2013 Developer ... mbook$実際、ここには
hidden
や restricted
など、多数のフラグ付きファイルの存在が確認できる。
2つの意味がある。
(a) 終了する時に「保存」を選択しなくても自動的に変更内容がファイルに反映されるようにする。
iPhone や iPad ではこの機能は便利なのであるが、自動保存に頼っていると、プログラムの開発時に頭を傾げることになる。自動保存されたと思ってコンパイラを走らせても、まだ自動保存が完了していないことがあるのだ。手動で保存する方が確実で早い。
この意味での auto save は
システム環境設定 > 一般 > 書類を閉じるときに変更内容を保持するかどうかを確認
(b) 編集中の途中の状態を自動的にファイルに保存する。
この機能はクラッシュやフリーズした時に威力を発揮する。しかし保存のタイミングを自分で決められないのは辛い。特に、サーバのファイルをマウントして Mac から編集する時に困る。
この自動保存は止められない(多分)。この問題は後に議論する。
auto save はどうやら全てのアプリケーションに均一に作用している1。
(a) のチェックマークは「バージョンを戻す」と関係している。
「バージョン」の意味が、チェックマークを入れている場合と、外している場合で異なる。
実験によると、チェックマークを外していると改行のタイミングでひとつのバージョンができる2。
チェックマークが入っていると、保存のタイミングでひとつのバージョンができる。
https://atom.io
) は自動保存はしていない。Apple が提供するライブラリに依存していると自動保存になるのではないかと思える。atom にもう少し僕の好みが入れば、僕が好きなテキストエディタになるのではないかと思えるのだが... あともう少し、頑張れ atom.
どこかに foo.txt を作り、テキストエディタで開き、foo.txt への書き込みと
ls -l foo.txt
文献[2] によると
defaults write com.apple.TextEdit ApplePersistence -bool no
文献[3] によると
defaults write -g ApplePersistence -bool no
https://eshop.macsales.com/blog/47415-auto-save-and-versions-an-often-overlooked-mac-feature/
[2] Disable Autosave and Enable "Save As..."
http://hints.macworld.com/article.php?story=20120604101520950
[3] How to completely disable auto-save and versions in Mac OS X Lion?
https://apple.stackexchange.com/questions/27544/how-to-completely-disable-auto-save-and-versions-in-mac-os-x-lion
"別名で保存 (save as)" が見えない。MacOS が Lion になってかららしい。
現在の標準設定では「別名で保存」のメニューは隠されている。
これは非常に不便。特に書き込み禁止領域のファイルをどこかに保存したい時。
キー操作
command+shift S
[1] [Mac]「別名で保存…」を復活させる方法。
http://appdrill.net/62277/re-save.html
TextEdit.app
はしばしば「アクセス権がありません。情報を見てください」と読み取りも書き込みも拒否することがある。ファインダーの情報やコマンドからの情報を見る限りアクセス権はあるはずである。しかも、システム領域や、他システムのファイルに対してではない。mbook の何の変哲も無い僕のファイルに対してである。今のところ、他のエディタではこの現象には出会っていない1。
これはバグらしい。TextEdit.app
の再起動で解決する。
TextEdit.app
が好きでよく使い、走りっぱなしになっている。そのためにバグが現れやすいと考えられる。ときどきリスタートさせればこんなことにはならないのではないか?
僕は Linux のシステムを /n/maia/
に、Plan9 のシステムを /n/hebe/
にマウントしている。ところが /n/hebe/
の僕の領域 /usr/arisawa/doc/
に TextEdit.app のファイルを保存しようとすると「アクセス権がありません」と拒否される。
情報を見ろと言われるので、見ると
「カスタムアクセス権が割り当てています」
「読み出し/書き込みができます」
他のアプリ、例えば mi.app の場合には保存させて貰えるので、TextEdit.app の個性であろう。コマンドによる hebe へのコピーは可能である。
この違いはどこから来ているのか? また「カスタムアクセス権」の内容は何か? どこで設定されているのか?
hebe の場合 /n/hebe の「情報」は
容量: 0 バイト 空き領域: 0 バイト 使用領域: 0 バイト
maia は正しく表示されている。
容量: 240.84 GB 空き領域: 206.97 GB 使用領域: 33,866,063,872 バイト(ディスク上の33.87 GB)
df の出力が参考になる。
mbook$ df Filesystem 512-blocks Used Available Capacity iused ifree %iused Mounted on arisawa@maia:/ 470392688 42110616 404247976 10% 344687 14663057 2% /n/maia mount_macfus@macfuse9 0 0 0 100% 0 0 100% /n/hebe mbook$他にも情報は表示されているが、今の話に関係のない部分は捨てた。
Used
とは使用されたブロック数、Available
は(一般ユーザーにとって)利用可能なブロック数である*。多分 TextEdit.app
は丁寧に作られていて、/n/hebe
には利用可能な容量はないと判断している可能性がある。実際には膨大な利用可能な記憶域が存在するのだが TextEdit.app
の知るところではない ...
sys/mount.h
に含まれる struct statfs
の中のコメントを見よ。
df
の情報はどのようにして得られたか? 幸い df
のソースコードが存在する:
https://opensource.apple.com/source/file_cmds/file_cmds-45/df/df.c.auto.html
df.c
を読むに、関数 getmntinfo()
を通じて Used
、Available
の情報を得ている。
getmntinfo()
の情報はカーネルから来る。カーネルは Plan9 サーバー hebe に問い合わせるのであるが、その仲介は plan9port (p9p) の配布ファイルに含まれる 9pfuse
が行なっているはずである。
/dev
を見ればデバイスファイル
macfuse0, macfuse1, ..., macfuse63
9pfuse
と macFUSE
のコミュニケーションに使われている。 9pfuse
は、この窓口を通じて macFUSE
の要請を受け、hebe に利用可能な容量を問い合わせたはずである。
p9p の 9pfuse では、それをどのように処理したか?
plan9port の配布ファイルの /src/cmd/9pfuse/main.c
の中に著者の Russ のコメントがある。
/* * Statfs. Send back information about file system. * Not really worth implementing, except that if we * reply with ENOSYS, programs like df print messages like * df: `/tmp/z': Function not implemented * and that gets annoying. Returning all zeros excludes * us from df without appearing to cause any problems. */ void fusestatfs(FuseMsg *m) { struct fuse_statfs_out out; memset(&out, 0, sizeof out); replyfuse(m, &out, sizeof out); }つまり macFUSE が要求する空き領域などの情報に対して全て 0 として返事することにしたのである。
Plan9 には df
コマンドは存在しない。なぜか? この理由は Plan9 のリリースにあたって開発者が説明している:
記憶メディアは安く大容量になり、サーバーは使い切れないほどの容量を備えるようになった。ユーザーが df
コマンドで容量を気にする時代は去ったのだ[1]。とか...
我が家の Plan9 サーバーも確かにそうである。僕が残りの人生の間に満杯になることはないであろう。
なお、誤解がないよう... Plan9 ではファイルシステムの残りの容量を見れないと言っているのではない。これはファイルシステムを提供するシステム管理者の仕事であって、ユーザーが気にする話ではないと言っている。
Russ のやり方で、MacOS が現実に問題を引き起こしている。そこでこの問題をどのように解決したら良いかを考えて見る。3つの方向が考えられる。
(a) fusestatfs()
を改造してサーバーの正しい情報を教えてやる。しかし、これは Plan9 サーバー側にも手入れが要求される。何しろ Plan9 のファイルシステムは OS に固定されていなくて、ユーザーの作成を許すのである。その結果、現実に多様なファイルシステムが存在する。fusestatfs()
の要求を受け止めるプロトコルが存在しない。
(b) fusestatfs()
を少し改造して、MacOS を騙す。残り容量を適当に返すのである。これで MacOS 側は完全に騙せて、残り容量があるものとして、ファイルを作らせてくれるかも知れない1。
(c) 第三の方法は既存のソフトウェアをそのままに使って、リモートシステムの編集方法を変える。つまり直接編集しないで、僕の mbook に一旦コピーして、そこで編集し、終わったらリモートシステムにコピーバックする。さすがにコピーコマンドはテキストエディタのように馬鹿丁寧にリモートシステムの残り容量を吟味しない。
僕は現在、第三の方法を採用している。コピーとコピーバックの2つが発生するので、やり難そうに思えるかも知れないが、簡単なシェルスクリプトで実現できる。この方法は大きなメリットを持っている。MacOS はさすがにローカルなファイルシステムを使っている限り、良くできている。不満はない。特に作成中のデータを失わないように細心の注意と努力が払われている。なにしろ Mac は現代の文具である。そのために必要な要件を Apple はよく考えていると思う。作品を作るのに没頭し、保存し忘れ、システムクラッシュやフリーズによる作品が喪失することを Apple は恐れたのであろう。従ってリモートのファイルをローカルにコピーし、そこで編集することは Mac のこの特性を享受することになり、大きなメリットを持っている。
このシェルスクリプトの名は edit
である。特殊な使い方は
mbook$ man xxx | edit
xxx
のマニュアルが(edit
で指定された)テキストエディタでみることができる。これは非常に良い。man コマンドの output を Terminal で見るなどというのは歴史の遺物であって、バカバカしくてやっておれない。
[1] Plan 9 from Bell Labs
https://9p.io/sys/doc/9.html
僕の MacBook Pro は古いので バージョンは 10.12.6 (Sierra) である。もうバージョンアップはさせてくれない。しかしバージョンアップをしなくてもよいなら、それが一番幸せである。なにしろ、Mac はバージョンアップを重ねるたびに使い難くなる。僕は Mac の過剰と思える保護機能にうんざりしている。Sierra においてすらそうだ。
僕はこれまで
(a) Apple が責任を持って管理する領域
(b) サードパーティのアプリケーションが使ってよい領域
(c) 個人ユーザーが自由に使える領域
の区分を Apple がどのように考えているのかはっきりしていなかった。
最近(2019)になって、Apple の見解が正式に示されたようだ[6]。
それによると
/System
/usr
/bin
/sbin
/var
/Applications
/Applications
は Apple 以外との共存を許す。
サードパーティのアプリが使える領域は
/Applications
/Library
/usr/local
残りはユーザーが自由に使えると解釈したいが... 僕は /home
を作って /Users
にリンクを貼っていたが、いつのまにか消されていた。どうやら /home
は Apple が何かに使う予定らしい1。
領域区分をはっきりさせておくことは良いことだ。僕は管理者権限でソフトをインストールしたくはない。面倒だからと言うのではなく、危険だからである。Mac はサーバーとしては設計されていない。サーバーとしてなら、別の選択肢を考えるべきである。Mac の設計コンセプトは現代の文具であって、サーバー管理の作法を Mac に持ち込むことは間違っている。
文具
df
コマンドの出力を見よ。
文献[5]によると
OS X Yosemite以降、ドライバなどのカーネル機能拡張には、特定のアップルが承認したコード署名をする必要がある。 その為、開発者は、アップルへ開発者IDを要求する必要がある[11] 。コード署名されていない機能拡張が存在する場合、カーネルはシステムの起動を拒否し、代わりに禁止記号を表示する。このメカニズムは、 "kext署名"と呼ばれ、システム整合性保護に統合された[12]。macOS High Sierraからは、カーネル機能拡張に署名がある場合でも、初回起動時にユーザによる許可を必要とするSecure Kernel Extension Loading(SKEL)が導入された[13]。とある。文献[5]の根拠となっているのは文献[6]だとおもう。ここには
Kernel Extensions Must Be Signedとある。確かに、いい加減なドライバーは大問題である。(Mac に限らず) OS はドライバーをカーネル空間に持っている。その場合バグの破壊力が大きすぎる。さらにネットでダウンロードしたドライバには、どのような罠が仕掛けられているか判らない。Apple が厳格な統制をしたがるのは理解できる。
Kernel extensions must be signed with a Developer ID for Signing Kexts certificate.
カーネル機能拡張の問題点は、銀行などの窓口業務に例えて見ればよく理解できるだろう。なぜ銀行などがカウンターを備えてそこに窓口を設けているのか? 部外者を事務空間からシャットアウトするためである。カーネル拡張とは、利用者が窓口を通さずにセルフサービスで銀行の資源を操作するに等しい。このようなやり方は昔からパーソナルコンピュータ界で平気で行われていた。そして今も行われている。もっとも致し方ない面もあった。新しい種類のハードウェアが次々と誕生し、OS の提供側がそれに追いつかず、ハードウェアメーカーがドライバを作るスタイルが定着して行ったのである。Microsoft はそれにすっかり安住している。Apple はこのスタイルと決裂すると宣言したのである(と思いたい)。
次は文献[8]からの引用である:
重要: macOSではkextは推奨されなくなりました。kextはオペレーティングシステムの整合性と信頼性を危険にさらすため、ユーザはむしろカーネルの拡張を必要としないソリューションを好むでしょう。
macOS Mojave からは、 Apple の署名のない kext は特殊な方法を使わないと使用できなくなっているらしい[7]。
僕の mbook にも気づかないうちに kext がインストールされている。
mbook$ cd /Library/Extensions mbook$ ls -l total 0 drwxr-xr-x 3 root wheel 102 6 13 2014 ACS6x.kext drwxr-xr-x 3 root wheel 102 6 28 2016 ATTOCelerityFC8.kext drwxr-xr-x 3 root wheel 102 6 28 2016 ATTOExpressSASHBA2.kext drwxr-xr-x 3 root wheel 102 6 28 2016 ATTOExpressSASRAID2.kext drwxr-xr-x 3 root wheel 102 8 21 2013 ArcMSR.kext drwxr-xr-x 3 root wheel 102 9 12 2014 BJUSBLoad.kext drwxr-xr-x 3 root wheel 102 2 16 2016 CIJUSBLoad.kext drwxr-xr-x 3 root wheel 102 9 1 2013 CalDigitHDProDrv.kext drwxr-xr-x 3 root wheel 102 8 15 2014 HighPointIOP.kext drwxr-xr-x 3 root wheel 102 8 15 2014 HighPointRR.kext drwxr-xr-x 3 root wheel 102 2 2 2021 Plser.kext drwxr-xr-x 3 root wheel 102 9 10 2020 ProlificUsbSerial.kext drwxr-xr-x 3 root wheel 102 4 28 2014 PromiseSTEX.kext drwxr-xr-x 3 root wheel 102 8 4 2016 SoftRAID.kext mbook$ ls -lO
他に kext
を組み込んだアプリケーションがある。Apple 以外のアプリで kext
を使用しているものは次のようにして見ることができる:
mbook$ kextstat|grep -v com.apple Index Refs Address Size Wired Name (Version) UUID <Linked Against> 144 3 0xffffff7f833da000 0xf0000 0xf0000 org.virtualbox.kext.VBoxDrv (6.0.18) 96270992-93C7-3FCE-9AA2-37A8A7DCC926 <7 5 4 3 1> 146 0 0xffffff7f834ca000 0x8000 0x8000 org.virtualbox.kext.VBoxUSB (6.0.18) B9318296-40DB-31E6-AD39-0806529AA3F2 <145 144 43 7 5 4 3 1> 147 0 0xffffff7f834d2000 0x5000 0x5000 org.virtualbox.kext.VBoxNetFlt (6.0.18) 336536F2-3A17-3603-9F72-77A72B523230 <144 7 5 4 3 1> 148 0 0xffffff7f834d7000 0x6000 0x6000 org.virtualbox.kext.VBoxNetAdp (6.0.18) D7DDC615-34B1-3AFF-BD69-D60CF308B972 <144 5 4 1> 150 0 0xffffff7f834ec000 0x17000 0x17000 io.macfuse.filesystems.macfuse (2066.16) DB178900-CE62-3448-ACCA-B1798E2D045C <7 5 4 3 1> mbook$
このリストの最後にある mscfuse
は後で説明する。
ドライバーのバグ(あるいは悪意のドライバー)の影響範囲が限定されれば問題は解決するのだが、現在の技術ではそこまでやれていないだろう。
[1] Mac OSX 10のカスタムアクセス権を簡単に解除する方法
https://anicame.com/post-2121/
[2] Macでファイル、フォルダ、またはディスクに対するアクセス権を変更する
https://support.apple.com/ja-jp/guide/mac-help/mchlp1203/mac
[3] Mac のシステム整合性保護について
https://support.apple.com/ja-jp/HT204899
[4] Catalinaでファイルシステムがこう変わる
https://news.mynavi.jp/article/osxhack-242/
[5] システム整合性保護
https://ja.wikipedia.org/wiki/システム整合性保護
[6] System Integrity Protection Guide
https://developer.apple.com/library/archive/documentation/Security/Conceptual/System_Integrity_Protection_Guide/Introduction/Introduction.html
[7] FUSE for macOS will not load with SIP enabled
https://discussions.apple.com/thread/251861999
[8] macOSのカーネル機能拡張
https://support.apple.com/ja-jp/guide/deployment-reference-macos/apd37565d329/web
[9] Mac で App を安全に開く
https://support.apple.com/ja-jp/HT202491
可能性のあるカーネル拡張技術の方向は fuse である。fuse はユーザープログラムによってカーネルに組み込まれていないファイルシステムを実現する技術である。もちろん fuse 自体はカーネルを拡張している。 fuse はカーネルにユーザープログラムとの交渉窓口を開く。現在の MacOS の場合には、その窓口は
/dev/macfuse0, /dev/macfuse1, ..., /dev/macfuse63
僕の環境では fuse は我が家のサーバーのファイルシステムを mbook にマウントするのに使われている。サーバーは Plan9 の下に動いているものと、Linux や FreeBSD で動いているものがある。後者は sshfs
でマウントされるので、サーバーを持っている人は使ったことがあるだろう。
ネットの記事を見ていると fuse について Linux 由来であるとの解説が支配的である。「由来」をどのような意味に取るかが問題である。カーネルに組み込まれていないファイルシステム(これをユーザーランドのファイルシステムと言う)を使い出したのは Plan9 である。発祥の地は Bell 研究所である。このアイデアを Linux で実現したいとする人たちが現れ、Linux のカーネルの中に必要なインターフェースが組み込まれた。Mac へも fuse の技術が Google によって MacFUSE として持ち込まれた2。
つまりアイデアは Plan9 由来である。さらにコードを眺めていると、コードの骨格も Plan9 のものと同じである。まあ、同じアイデアに立てば、誰が書いても同じようなコードになるのだろう。コードのコピペで「由来」を判断すれば、Linux の fuse は独自のものだったかもしれない。
/dev/fuse
だけが見える。Mac のは沢山あるのでサービスが良いのかと言えば違う。Linux のはお客さんが窓口に見えれば、直ちに新しい窓口を作ってくれる魔法の窓口なのである。エレガントだね。
Apple の iCloud が WebDav の技術に基づいているのか否かは定かではない。iCloud が行われる前のサービス(iDisk)が WebDav に基づいていたと WikiPedia に解説されている[1]。この解説は信じてもよいのではと思う。
iCloud のファイルを Finder から見えるようにするには
Finder > 環境設定 > サイドバー
Finder を通じて Mac を WebDav クライアントにするには
Finder > 移動 > サーバーへ接続 > サーバーアドレス
Pegasus 下の WebDav サーバに来る Mac の Finder からのリクエストには
User-Agent: WebDAVFS/3.0.0
WebDAVFS
が Apple による正式名称である。
URL http://ar:8080/dav/
で指定される WebDav サーバーに接続したままで ps
を実行すると
mbook$ ps ax | grep webdav 1438 ?? Ss 0:00.58 webdavfs_agent -o noautomounted -o browse -o nordonly -a4 -vdav http://ar:8080/dav/ /Volumes/dav 1466 s001 R+ 0:00.00 grep webdav mbook$つまり
WebDAVFS
の接続先が見える。iCloud は動いているので、もしも WebDAVFS
が iCloud と接続していれば、ps
で見えたはずである。従って、 WebDAVFS
は iCloud には接続していないと断言してよい。
iCloud に関係のあるプロセスは(全部ではないかもしれないが)次のようにして見える:
mbook$ ps axl | grep -i icloud 501 472 1 0 20 0 2869052 18316 - S ?? 0:07.94 /usr/libexec/SafariCloudHistoryPushAgent 501 1561 1 0 4 0 2724284 42060 - S ?? 0:00.21 /System/Library/PrivateFrameworks/AOSKit.framework/Versions/A/XPCServices/com.apple.iCloudHelper.xpc/Contents/MacOS/com.apple.iCloudHelper 501 1570 1530 0 31 0 2453252 2124 - S+ s002 0:00.02 grep -i icloud mbook$他方
netstat
の情報も参考になる:mbook$ netstat -n|grep tcp tcp4 0 0 192.168.0.249.51852 162.125.36.2.443 ESTABLISHED tcp4 0 0 192.168.0.249.51843 17.57.145.54.5223 ESTABLISHED tcp4 0 0 192.168.0.249.51841 17.57.152.23.993 ESTABLISHED tcp4 0 0 192.168.0.249.51838 17.188.166.20.5223 ESTABLISHED tcp4 0 0 192.168.0.249.51835 162.125.35.134.443 ESTABLISHED tcp4 0 0 192.168.0.249.51834 108.177.97.108.993 ESTABLISHED tcp4 0 0 192.168.0.249.51829 17.57.152.23.993 ESTABLISHED ... mbook$これと
whois
データベースを付き合わせると162.125.0.0 - 162.125.255.255
は DropBox17.0.0.0 - 17.255.255.255
は Apple108.177.0.0 - 108.177.127.255
は Google
文献[3]によるとポート 5223 について
iCloud DAV サービス (連絡先、カレンダー、ブックマーク)、プッシュ通知、FaceTime、iMessage、Game Center、フォトストリームとある。つまり(説明によると) iCloud でも WebDav が使われている。それにも関わらず
WebDAVFS
がそのために使われていない。どう解釈したらよいのだろう?
Apple にとって、ポート 5223 のサービスはトップクラスの重要性を持っていると考えてよい。従って十分な信頼性が要求される。ところが WebDav の標準的なプロトコルは貧弱である。セキュリティ的にも問題で、効率も悪く、Apple の現実的なニーズに応えられそうもない(と僕は感じる)。Apple は WebDav のプロトコルを独自に拡張して iCloud に適用しているのだろうと推測する。
rfc4331 には、クライアントからサーバーへの要求「空き容量を知らせてほしい」
<D:propfind xmlns:D="DAV:"> <D:prop> <D:quota-available-bytes/> <D:quota-used-bytes/> </D:prop> </D:propfind>が例示されている。
しかし、 WebDAVFS
からは、次のような要求が来る。
<?xml version="1.0" encoding="utf-8"?> <D:propfind xmlns:D="DAV:"> <D:prop> <D:quota-available-bytes/> <D:quota-used-bytes/> <D:quota/> <D:quotaused/> </D:prop> </D:propfind>ここに現れる
quota
とか quotaused
とかは、古い WebDav クライアントとの互換性を保つために入っているらしい2。
mtpt=.... # your favorite mount point mount_webdav -si http://ar:8080/dav $mtpt
注 2: Apple が公開している webdavfs ソースコードの中のコメントから判る。
[1] iDisk
https://ja.wikipedia.org/wiki/IDisk
[2] How to Stop Finder WEBDAVFS from requesting .hidden, ._Directory , ._FileName files after Remotes File System Mount has happened?
https://discussions.apple.com/thread/3786731
[3] Apple ソフトウェア製品で使われている TCP および UDP ポート
https://support.apple.com/ja-jp/HT202944
普通の unix 系のシステム(例えば Linux)では C のインクルードファイルは /usr/include
に置かれる。ところが我が環境では
mbook$ ls /usr/include ls: /usr/include: No such file or directory mbook$となっていた。
インクルードファイルを探すことにした。例えば最も初等的な stdio.h はどこにあるか?
/usr/local/include
なぜか Plan9 関係のもここにある。しかも新しい。
u.h
が 2017 年。いつここにコピーされたか?
/opt/local/include
ここには何も無い
/Developer/Headers
ここは Apple 関係限定
/Developer/usr/include
ここは gcc、しかも殆ど何もない
/Developer/usr/llvm-gcc-4.2/include
殆ど何もない
/sw/include
ここが一番近い。しかも apt-pkg
の include
がある。
しかし stdio.h
が無い
/Developer/SDKs/MacOSX10.6.sdk/usr/include
ここに stdio.h
がある。
他にも SDK
のバージョンごとに存在する:
mbook$ ls -l /Developer/SDKs/ total 14728 -rw-r--r--@ 1 root wheel 483 2 20 2013 MEMO.txt drwxr-xr-x 7 arisawa staff 238 12 2 2011 MacOSX10.4u.sdk drwxr-xr-x 7 root wheel 238 6 30 2009 MacOSX10.5.sdk drwxr-xr-x 7 root wheel 238 8 3 2009 MacOSX10.6.sdk -rwxr-xr-x@ 1 arisawa wheel 1941316 2 20 2013 MacOSX10.7.sdk -rwxr-xr-x@ 1 arisawa wheel 1825968 12 17 2013 MacOSX10.8.sdk mbook$一番新しいバージョンのはどこにあるのか?
mbook$ ls -l /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs total 8 drwxr-xr-x 5 root wheel 170 1 1 1970 MacOSX.sdk lrwxr-xr-x 1 root wheel 10 1 19 2018 MacOSX10.13.sdk -> MacOSX.sdk mbook$ここに含まれている!
補注: 実は locate
コマンドを使えば、もっと簡単に見つかったはずである。単に
locate include|grep '/stdio.h$'
locate
データベースのデフォルトは off である。容易に on にできる。locate
コマンドを実行すれば、on にする方法が表示される。Mac には Spotlight があるではないか? mdfind があるではないか? しかし output が多すぎて役に立ったことが無い。
ところで今頃こんな話をしているのは、C のコンパイラを使っていて、インクルードファイルが見つからないとは言われたことがなかったからである。Mac におけるインクルードファイルの配置は特殊である。それなのにどのようにして C のコンパイラはその位置を知ったのか。尤も、インクルードファイルの問題は C のプリプロセッサ cpp
の問題である。従って僕の疑問は「cpp
はどのようにしてインクルードファイルの位置を知ったのか?」にある。
この疑問の答えは次の URL に存在する:
https://gcc.gnu.org/onlinedocs/cpp/Search-Path.html
これによると cpp
のコンパイル時に指定できるらしい。その内容は
cpp -v /dev/null -o /dev/null
mbook$ cpp -v /dev/null -o /dev/null Apple LLVM version 9.0.0 (clang-900.0.39.2) Target: x86_64-apple-darwin16.7.0 Thread model: posix InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.12.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -E -disable-free -disable-llvm-verifier -discard-value-names -main-file-name null -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -fno-strict-return -masm-verbose -munwind-tables -target-cpu penryn -target-linker-version 305 -v -dwarf-column-info -debugger-tuning=lldb -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/9.0.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk -I/usr/local/include -fdebug-compilation-dir /Users/arisawa/dist/p9git-2021 -ferror-limit 19 -fmessage-length 145 -stack-protector 1 -fblocks -fobjc-runtime=macosx-10.12.0 -fencode-extended-block-signature -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -traditional-cpp -o - -x c /dev/null clang -cc1 version 9.0.0 (clang-900.0.39.2) default target x86_64-apple-darwin16.7.0 ignoring nonexistent directory "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/local/include" ignoring nonexistent directory "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/Library/Frameworks" #include "..." search starts here: #include <...> search starts here: /usr/local/include /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/9.0.0/include /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/System/Library/Frameworks (framework directory) End of search list. # 1 "/dev/null" # 1 "<built-in>" 1 # 1 "<built-in>" 3 # 330 "<built-in>" 3 # 1 "<command line>" 1 # 1 "<built-in>" 2 # 1 "/dev/null" 2 Apple LLVM version 9.0.0 (clang-900.0.39.2) Target: x86_64-apple-darwin16.7.0 Thread model: posix InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin clang: warning: argument unused during compilation: '-traditional' [-Wunused-command-line-argument] mbook$この出力には、実際に C コンパイラで使われているインクルードファイルだけが表示されているはずで、この方法を知っていれば苦労はしなかったはずである。
ところでプログラムの開発においてインクルードファイルの参照は不可欠である。unix や Linux であれば、いくつかの固定した場所(例えば /usr/include
や /usr/local/include
) に置かれているので探すのに苦労は要らない。
僕がよく使う、Plan9 のシステムでも、もちろん置き場所のルールがある。さらにテキストエディタの中で簡単に探せる:
#include <xxx.h>
xxx.h
" をマウスでクリックすると、直ちに xxx.h
を参照できる。Mac では、類似の機能は Xcode.app
にすらない。
Mac は複雑である。cpp -v
の output を見る限り、インクルードファイルの置き場所として、少なくとも次の4つは含まれている。
/usr/local/include /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/9.0.0/include /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include他にも何箇所かあるが、規則がはっきりせず、その全てを列挙する元気がない。
#!/usr/local/plan9/bin/rc # you need plan9port and also lr and 9xa # look http://p9.nyx.link/netlib for lr and 9xa # rfork e usage='usage: hgrep [-v] pattern' vflag=0 while(~ $1 -*){ switch($1){ case -v vflag=1 shift case -* echo $usage exit }} a=`{cpp -v /dev/null -o /dev/null > /dev/null |[2] grep '/include$'} if(~ $vflag 1){ for(b in $a) echo $b } if(! ~ $#1 1) exit t=$1 lr -f $a | 9xa grep -n $tこのシェルスクリプトは、与えられた文字列パターンが含まれているヘッダファイルを探し出す。強力な武器になるはずである。
なお、シェルスクリプトは Plan9 の rc
である。可読性に富み、シンプルかつ強力で、僕は bash
を使う元気がない。
また lr
と 9xa
については
開発に必要なマニュアルがイントールされていないことに気づいた:
mbook$ man listxattr No manual entry for listxattr mbook$しかし存在するのだ:
mbook$ lr /Applications/Xcode.app/Contents | grep listxattr /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/share/man/man2/flistxattr.2 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/share/man/man2/listxattr.2 mbook$
ここに lr
は僕が Plan9 用に作ったプログラムである。lr
とは ls recursively の意味で、ファイルを探す時に威力を発揮する。lr
は (Plan9port の下で) Mac や Linux などへも移植できる。次の URL で手に入る:
http://p9.nyx.link/netlib/cmd/lr/
lr
は unix の ls -1R
と違って、1つの行に1つのパスの考えに徹している。その方が出力を再利用しやすい。出力を grep
に渡せるのは、そのように設計されているからだ1。
マニュアルへのリンクを作ることにした:
mbook$ ls -l /usr/local/xcode total 8 lrwxr-xr-x 1 arisawa wheel 108 8 3 07:25 man -> /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/share/man mbook$それで
mbook$ lr -L /usr/local/xcode | grep listxattr /usr/local/xcode/man/man2/flistxattr.2 /usr/local/xcode/man/man2/listxattr.2 mbook$そして環境変数
MANPATH
を修正してmbook$ man listxattr ... mbook$OK
ところで
mbook$ manpath /usr/local/xcode/man:/usr/share/man:/usr/local/man:/usr/local/texlive/2017/texmf-dist/doc/man mbook$は
mbook$ echo $MANPATH /usr/local/xcode/man:/usr/man:/usr/share/man:/usr/local/man:/usr/X11R6/man:/usr/local/texlive/2017/texmf-dist/doc/man mbook$と必ず同じ内容を表示するわけではない。
manpath
が表示するのは man
が実際に読み取って利用しているマニュアルのパスである。そこにマニュアルが存在しなければ表示しない。mbook$ ls -l /usr/bin/man* -r-xr-xr-x 1 root wheel 70128 7 15 2017 /usr/bin/man lrwxr-xr-x 1 root wheel 3 8 20 2017 /usr/bin/manpath -> man mbook$リンクが上手く使われている。
manpath
が man
とは別プログラムになっていないことが、manpath
が man
の実際に迫れる秘訣である。
ところでマニュアルは、今やローカルに持たなくても、ネットで見れるのだね。
例えば http://www.manpagez.com/
がある。この中の rename
を眺めていると、次の説明が気になった:
The rename() system call guarantees that an instance of new will always exist, even if the system should crash in the middle of the operation.うーむ、首を傾げてしまう。一般に、ファイル操作中のシステムクラッシュは、操作対象のファイルだけではなく、最悪の場合にはシステムの全てのファイルを消失させる2。システムを二重化せずに、どのような仕組みになって入れば、このようなことが可能なのか? 知りたいものだ。
locate listxattr|grep man
locate
コマンドは、標準では off になっている)
今回、macFUSE
の動作を知りたくて、いろいろ調べることになった。理由は Apple がカーネル拡張を廃止するとアナウンスしているからである。ならば具体的にどうするつもりであるか? カーネル拡張に依存していた企業は、この間、Apple の新しい方針に沿ったドライバを作ってきたはずである。その際、Apple からの指導や、情報が企業のエンジニアに与えられたはずである。ところが僕はそのような情報を持っていない。どこから手に入れたら良いのか?
僕は macFUSE
を調べることにした。macFUSE
もカーネル拡張を使っていた。macFUSE
のソースコードの変化を調べれば答えが得られるだろうと期待したのである。僕が持っている関連するソースコードは macFUSE
の前に使われていた osxFUSE
までである。このソースコードは 2017 年に入手している。
ところがどれだけ調べても macFUSE
のソースコードが見つからないのである。そうこうしている間に次の2つの記事[1,2]を見つけた。
文献[1]にによると 2019年以降 macFUSE
はオープンソースではない:
Since 2019 (version 3.9) some components of the macFUSE software are no longer open source, e.g. the kernel extension. The source code of all open source components can be found in the release branch of the macfuse repository.
文献[2]は、この問題に対する macFUSE
のメンテナンスを行っている Benjamin Fleischer のインタービュー記事である。企業の方はオープンソースの著者たちから大きな恩恵を受けながら、オープンソースを支えようとはしない。理由は単純で、無料だからであると...
Apple はオープンソースから多大の恩恵を受けている企業の一つである。Mac のコマンドの殆どは BSD 由来である。また開発で使われているコンパイラやツール類もまたオープンソースのコミュニティに由来している。現代社会は、オープンソースのコミュニティに属する人々の善意の無償のソフトウェアの上に成立しているのである。彼らに大学の教員などの生活基盤があれば問題は少ないが、しかしそのような生活基盤がない場合、誰がどのように彼らの生活を支えるのか?
ここで言う企業は、(多分) Apple を指していないだろう。文献[3]に Open Source に対する Apple の見解がある。Apple は Open Source にタダ乗りはしない。Apple も Open Source の発展に努力しているのだと。Google も Open Source を支えている[4]。そもそも macFUSE
は Google の MacFUSE
のコードを受け継いでいる。であるから macFUSE
は誰が開発したのかを定めるのは実際には難しい問題である。他人の善意に甘え、ソースコードの出典すら隠す企業が多数存在するのだろう。
今回の問題は、企業と Open Source との関わりに一石を投じた。注意深く見守りたい。健全な姿は macFUSE
がオープンソースであり続け、企業はオープンソースを支援する適切な関係を構築することである。しかしそれに必要な仕組みははっきりしない1。
[1] Open Source Status
https://github-wiki-see.page/m/macfuse/macfuse/wiki/Open-Source-Status
[2] FUSE for macOS: Why a popular open source library became closed source and commercially licensed
https://www.theregister.com/2019/12/16/fuse_macos_closed_source/
Mon 16 Dec 2019
[3] Open Source
https://developer.apple.com/opensource/
[4] Google Open Source
https://opensource.google
今日のパーソナルコンピュータには、スーパーコンピュータに使われていた技術が使われている。その代表的な例はパイプライン処理であろう。パイプライン処理は工場の生産ラインの流れ作業に例えることができる。ベルトコンベアに多数の作業員を並べ、製品を流していく。この方法は大量生産に向いているのだが、うまくいくためには一人ひとりの作業量が均一になるように調整されていなくてはならない1。
ところが現在のパーソナルコンピュータの主流アーキテクチャであるインテル系の x86 の命令セットは複雑で、パイプライン処理に向いていない。そこで最近の x86 系の CPU では、命令をパイプライン処理に適した RISC 系の命令に変換してパイプラインに流しているらしい[1]。それなら率直に RISC 系の CPU を使った方が良いではないか?
最近(2020)、Apple は x86 に別れを告げ、自社設計した RISC 系の ARM/M1 を載せたパーソナルコンピュータを販売し出して好評を得ているらしい。Apple の M1 が成功すれば x86 に未来はないことになる。
他方では危惧していることもある。x86 の技術情報がオープンであり得たのは、Intel が第3者に彼らの CPU を使ってもらう必要があったからである。Apple の M1 はどうか? Mac だけでも M1 への投資を回収できるだけの需要があるだろう。その場合 Apple は技術情報の開示には消極的になるのではないだろうか? 現在だって macOS には隠された部分が多い。
記事[2]および同サイトに載っている関連した記事が面白い。
[1] パターソン & ヘネシー:「コンピュータの構成と設計 —— ハードウェアとソフトウェアのインターフェース (第4版)」
(日経BP社,2011)
[2] RISCの実用性を証明した「MIPSアーキテクチャ」の誕生
https://www.itmedia.co.jp/news/articles/2004/23/news099.html
噂によると mac のファイルシステムに ZFS が利用できるようになるそうである。ZFS は既存の unix のファイルシステムに比べて優秀らしくて注目されている。snapshot を採る機能もある。Mac の Time Machin はファイルシステムの外にあったために、バックアップのときには外付けの HD と接続する必要があった。そのために僕のように面倒くさがり屋はついついバックアップをサボるのであった。ZFS の場合にはファイルシステムの仕組みとしてバックアップ機能を持っている。なかなか良いのではないだろうか? unix の世界も少しづつ Plan9 的な要素が取り入れられているんだね。残念ながら僕の MacBook は古くて、ZFS が載りそうにはない。
ZFS は現在の FreeBSD の標準ファイルシステムである。従って ZFS に関しては FreeBSD を調べれば解る。FreeBSD での知識は macOS においても活きるはずである。そこで以下では FreeBSD の ZFS の使い方を紹介する。
ここで取り上げる FreeBSD のバージョンは
bsd$ uname -a FreeBSD bsd 13.0-RELEASE FreeBSD 13.0-RELEASE #0 releng/13.0-n244733-ea31abc261f: Fri Apr 9 04:24:09 UTC 2021 root@releng1.nyi.freebsd.org:/usr/obj/usr/src/amd64.amd64/sys/GENERIC amd64 bsd$また ZFS のバージョンは
bsd$ zfs version zfs-2.0.0-FreeBSD_gf11b09dec zfs-kmod-2.0.0-FreeBSD_gf11b09dec bsd$である。
FreeBSD が全面的に ZFS の下で動いていることは
bsd$ gpart show => 40 625140256 ada0 GPT (298G) 40 1024 1 freebsd-boot (512K) 1064 984 - free - (492K) 2048 4194304 2 freebsd-swap (2.0G) 4196352 620943360 3 freebsd-zfs (296G) 625139712 584 - free - (292K) bsd$で確認できる。
ZFS ではデータの置き場を pool と言っている。pool の状態は
bsd$ zpool list NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT zroot 296G 9.09G 287G - - 0% 3% 1.00x ONLINE - bsd$で判る。
list
によると pool は1つだけで、名前は zroot
となっている。これは defualt の名前である。
さて df
コマンドで mount の状態を調べると
bsd$ df Filesystem 1K-blocks Used Avail Capacity Mounted on zroot/ROOT/default 298963956 2817280 296146676 1% / devfs 1 1 0 100% /dev zroot/var/mail 296146856 180 296146676 0% /var/mail zroot/usr/src 296865524 718848 296146676 0% /usr/src zroot/var/tmp 296146772 96 296146676 0% /var/tmp zroot/var/audit 296146772 96 296146676 0% /var/audit zroot/var/crash 296146772 96 296146676 0% /var/crash zroot/usr/ports 296883972 737296 296146676 0% /usr/ports zroot/usr/home 296399220 252544 296146676 0% /usr/home zroot 296146772 96 296146676 0% /zroot zroot/tmp 296146840 164 296146676 0% /tmp zroot/var/log 296147252 576 296146676 0% /var/log bsd$となっていた。ここに表示されたのは ZFS によって発生している mount である。
mount
コマンドも同じマウント関係を示す。なお "filesystem
" とは、ZFS の内部。"mounted on
" が我々に見える部分。
第1フィールドが解りにくい。何故こんなにたくさん表示されるのだろう? 3つ
zroot /zroot zroot/ROOT/default / devfs /dev
類似の結果は次でも得られる
bsd$ zfs list NAME USED AVAIL REFER MOUNTPOINT zroot 5.13G 282G 96K /zroot zroot/ROOT 3.04G 282G 96K none zroot/ROOT/default 3.04G 282G 3.04G / zroot/tmp 172K 282G 172K /tmp zroot/usr 2.09G 282G 96K /usr zroot/usr/home 576M 282G 576M /usr/home zroot/usr/ports 857M 282G 857M /usr/ports zroot/usr/src 702M 282G 702M /usr/src zroot/var 1.18M 282G 96K /var zroot/var/audit 96K 282G 96K /var/audit zroot/var/crash 96K 282G 96K /var/crash zroot/var/log 640K 282G 640K /var/log zroot/var/mail 188K 282G 188K /var/mail zroot/var/tmp 96K 282G 96K /var/tmp bsd$
この "NAME
" 欄は、どのように機能しているのか?
ZFS の snapshot のマニュアル[1]を読むに、"NAME
" 欄は snapshot と密接に関係している。例えば次のようにやる:
sudo zfs snapshot -r zroot/usr/home@2021-11-21
@
" の左は "NAME
" 欄に存在しなくてはならない。"@
" の右は snapshot を識別するための ID である。従って何でもよいが、重複は許されない。(撮影日にするのが良いだろう)-r
" は再帰フラグで、これによって下位のディレクトリを含めた snapshot を採る。
snapshot のリストは
zfs list -t snapshot
bsd$ ls -l /home/.zfs/snapshot total 1 drwxr-xr-x 4 root wheel 4 Nov 20 11:46 2021-11-21 bsd$ ls -l /home/.zfs/snapshot/2021-11-21 ... bsd$のように辿っていける。
従って、この "NAME
" 欄は ZFS ご推奨の撮影スポットと考えられる。
"NAME
" 欄は自由に再編できるが、下手すると後悔することになる。いろいろ弄って楽しみたいなら、潰してもよいように、VM 上の FreeBSD でやった方が無難である。
"rollback" とかがあるが、僕は副作用が怖くて運用中のシステムに試す気にはならない。
[1] zfs-snapshot(8)
#include <stdio.h> int a; void f(void); int main(int argc,char *argv[]) { f(); printf("%d\n",a); return 0; }
譜1: a.c
int a; void f(void) { a += 1; }
譜2: b.c
compile
cc -o a a.c b.c
cc
and Mac cc
However on FreeBSD cc
bsd$ cc -o a a.c b.c ld: error: duplicate symbol: a >>> defined at a.c >>> /tmp/a-4e27ce.o:(a) >>> defined at b.c >>> /tmp/b-d70c4f.o:(.bss+0x0) cc: error: linker command failed with exit code 1 (use -v to see invocation) bsd$つまり名前
a
の定義が2ヶ所にあると言って跳ねられる。
"cc -v
" が表示する cc
のバージョンは
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
Apple LLVM version 9.0.0 (clang-900.0.39.2)
FreeBSD clang version 11.0.1
問題は
int a;
僕のように古い人間は文献[1]で C を学んでいる。この本は(たぶん今でも) C プログラマにとってのバイブルである。以下これを C89 と言うことにする。実際には最初の版で C を学んだのであるが、ここでは言わないことにしよう。
文献[1]によると
int a;
int a=0;
Plan9 のコンパイラ(正しくはリンカ)はどうなっているか? やってみると gcc のように振る舞う。Plan9 プロジェクトにリッチーが関与しているにも関わらずである!
この問題についてネットで調べていると文献[2]に出会った。C99 では
int a;
extern int a;
a
に明示的に値を与えなくてはならない。そこでextern int a = 0;
こんな旗色のはっきりしない仕様が C99 で「標準」になっているとは... 制定者たちの論理的センスを疑わざるを得ない。
なお C99 の正式な仕様書は有料でしか手に入らないらしい。文献[3]は draft であるが参考にはなるだろう。僕は規格書は無料にして欲しいと思う。ISO も日本規格協会も、規格書ビジネスは止めてほしい。オープンになっていない規格を強いる資格はだれにも無いはずである。我々はそのような「規格」に従う必要は無い。
[1] B.W.カーニハン/D.M.リッチー,石田晴久訳『プログラミング言語 C』
共立出版株式会社 (2006)
[2] C のグローバル変数の仮定義とは
https://gist.github.com/tenpoku1000/4900093cf2f87247cb523a3a7b808c82
[3] Committee Draft — Septermber 7, 2007 ISO/IEC 9899:TC3
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
カーニハン・リッチーは今でも C プログラマにとってのバイブルである。従ってこれを超えるのは慎重であるべきだ。いくら新しい「標準」があっても。
次のように書けばプログラマの意図が明瞭にコンパイラに伝わる。これは C89 のレベルである。もちろん gcc でも clang も正しくコンパイルされる。これを通さないコンパイラはバグっていると断じてよい。
a1.c
#include <stdio.h> extern int a; int a = 0; void f(void); int main(int argc,char *argv[]) { f(); printf("%d\n",a); return 0; }
b1.c
extern int a; void f(void) { a += 1; }
なお a1.c
の
extern int a;
a1.c
の
int a = 0;
int a;
Brian W. Kernighan, Rob Pike
僕の観測によると、Mac の C コンパイラも gcc も甘い。作成した C のプログラムコードを FreeBSD の clang でも試してみると問題点が良く判る。