root で chown -R や rm -r を実行する時には -x オプションを追加しろ

新年早々 samba がこけまして、 samba に認証情報をあずけてあるユーザーが認証できなくなっって大弱りでした。 原因は fdescfs をマウントしてあるところに chown -R を実行してしまったことです。 最近のソフトウェアは、自分の領域の下の方の path に fdescfs をマウントしていることが多いので (samba とか)、うっかり root で chown や rm を実行してそいつを踏んでしまうと、 おもいもかけぬファイルの所有者を変更したり消してしまったりします。 それで samba が読み書きできなくなったディレクトリやファイルがあってこけてしまったのでした。

そういう事故を防ぐために、root で chown や rm を再帰的に実行する場合は、 mount 境界をまたがないようにすることが重要です。 それが -x オプションです。

というわけで、root で chown や rm を再帰的に実行する際には、

# chown -Rx ...

とか

# rm -rfx ...

とか

# rm -rdx ...

とか、忘れずに -x をつけましょう。今年の抱負です。

従来の方法で更新してきた FreeBSD システムを PKGBASE 方式に変換する

pkgbasify

実のところ、 必要な手順を lua script にしたものFreeBSD Foundation が公開しているので、 これを持ってきて動かせば済む話だったりします。

というわけで、

freebsd-update で更新してきた場合

こちらは公式にずっと従っているわけですから特別なことはなくて、pkgbasify の説明に書いてあるとおりにやればよいです。

makeworld で更新してきた場合

こちらも pkgbasify スクリプトは使えるのですが、ちょっとした準備がいります。

まず、make buildworld buildkernel してから installkernel installworld でシステムを更新します。 make delete-old delete-old-libs も実行しておいて、余計なファイルを消しておくべきでしょう。

make packages も行って pkgbase リポジトリを構築します。 これについては先日ざっと書いたので、 それを参考にしてください。httpd で取れるようにするところは書いていませんが、 まあ分かりますよね。

そうしたら、その pkgbase リポジトリを記述した pkg コマンドの設定ファイルを /etc/pkg に置きます。 これは、pkgbasify がパッケージリポジトリごとに pkg update を実行して、 リポジトリの情報を読み取る手順があるのですが、この時 pkg update が実行されるのが /etc/pkg 以下の *.conf ファイルに設定が書かれているリポジトリに対してだけだからです。 一般的に自分で記述したパッケージリポジトリの設定は /usr/local/etc/pkg/repos/ 以下に置くと思いますが、後で消してよいのでそれを /etc/pkg 下にコピーしてください。

以上を行ってから pkgbasify を実行します。 その時にいくつか引数を指定します。

# ./pkgbasify.lua --no-create-repo-conf --repo-name myrepo-base

--no-create-repo-confFreeBSD 公式のパッケージリポジトリの設定を書き出さないオプションです。 base、ports 含めていらないという場合に指定してください。 公式から入れることもあるんだよなあという場合は外してください。

--repo-name は公式のパッケージリポジトリの代わりに base のパッケージを取ってくるリポジトリ名を指定します。 ここでは myrepo-base としていますが、ご自分で設定した名称を指定してください。

実行中に何か問題があって --force オプションをつけてやり直す場合も、 上記オプションの指定を忘れないようにしてください。

pkgbasify の実行後に何を確認するか

pkgbasify の README にかかれているとおり、/etc/master.passwd と /etc/group が大切なのはそうなんですが、 *.pkgsave ファイルがあったら確認して不要になったら消すとか、 pkg which してどのパッケージにも所属していないファイルがないか探すとかいろいろある気はします。 正直よくわかりません。

FreeBSD で音楽再生中の音飛びをなくす

小ネタ。

FreeBSD で音楽を聞いていると、通常のプロセスの優先度だと音飛びが発生することがある。 root で renice して nice 値を下げてスケジューリングの優先度を上げてもあまり効果がなかったりすることが多い。

そこで優先度を上げるとよいのが realtime priority である。最大値(優先度最低)が 31 なので、

# rtprio 30 -$(pgrep progname)

みたいに実行する。こちらも数値が小さい方が優先度が高い。 基本は root のみが実行できるが、MAC で一般ユーザーも使えるように設定できて、/boot/loader.conf に

mac_priority_load="YES"

を追加して、realtime グループ (47) にユーザーを追加すると、そのユーザーも rtprio コマンドが使える。

逆に、あるプロセスに CPU が本当に idle 状態でないと動かないようにして、 ほかのプログラムの邪魔をさせたくない場合、idprio コマンドで idle priority を設定するとよい。 こちらの場合は idletime グループ (48) にユーザーを追加する。

2026-01-07 追記

idprio を poudriere bulk のような全体ではかなり CPU や I/O を食うジョブに設定すると、 むしろ GUI がまともに動かなくなって困ることがあった。 idprio の manpage に、idprio を使うとデッドロックが起きる可能性が高いと書いてあって、 どうやらそれみたい。 idprio を使う場合は、その配下のプロセスを含めても CPU やら メモリやら I/O やらのリソースをあまり食わない範囲で使うべきなようで、 poudriere bulk なんかは nice で通常のスケジューリング優先度を下げるべきなようである。

FreeBSD の PKGBASE サーバーを自分で用意する

はじめに

RELEASE インストールして、公式が提供してくれるのを、 freebsd-update と pkg で入れていればいいじゃんと煽られても頑なに stable を(最近は current も) 追いかけているし、poudriere で自分用の package repository をビルドしています。 こんにちは。

今回は、そんな私のような人向けに、FreeBSD 15.0-RELEASE からは PKGBASE という、 base のいろいろも pkg コマンドで扱う仕組みが入ったんですけれども、 それでも自分用の pkgbase repository をビルドして stable (とか current) 追っかけが続けられるんだろうか、もちろんできますよという話です。

今回の前提

これまで注ぎ足し注ぎ足しで面倒を見てきた stable の入った PC を前提にした話をすると長くなるので、 今回は FreeBSD 15.0-RELEASE とか stable/15 のスナップショットを pkgbase 方式でインストールしたシステムを前提とします。 buildworld 方式でやってきたシステムからの移行の話はちょっと待っていてください。

host と poudriere jail のソースを合わせる

poudriere jail は一番近い RELEASE を freebsd-update で入れているんだという場合は、 どこかに base のソースコードを置いて、それに対する操作に読み替えてください。

というわけで、poudriere jail のソースコードからビルドしたものを host にもインストールして、 両者のリビジョンを合わせます。あんまり意味はないけどそうしています。 ケチだから make buildworld の回数を減らしたいんですよ。

poudriere jail の作成

# poudriere jail -c -j s15amd64 -v stable/15 -m git+https

という感じで stable のソースコードを取ってきて poudriere jail をビルドします。 最初に必要な poudriere とか git はどうしましょう問題はありますが、 そこは仕方がないので FreeBSD 公式のパッケージをインストールして使います。

せっかくだから poudriere jail も pkgbase 方式で用意したら? と思うかもしれませんが、 そうするとソースコードが無くて kernel module が作れません。やめた方がよいです。 そもそも pkgbase のリポジトリも作れません。

kernel のビルド

poudriere jail -c で buildworld が実行されますので、終わったら /usr/local/poudriere/jails/s15amd64/usr/src に移動します。 generic kernel ではなく、自分用の設定でビルドした kernel を使いたい場合は、 sys/amd64/conf/MYKERNCONF とか、なんか kernel configuration file を作成します。 Aarch64 とか他のアーキテクチャについては適宜読み替えてください。

で、

# make KERNCONF=MYKERNCONF buildkernel

とやって kernel をビルドします。generic kernel で良い場合は KERNCONF の指定は不要です。

注意ですが、このあと installkernel、installworld はしないように気をつけてください。

pkgbase の作成

pkgbase のリポジトリを置くディレクトリを作成します。 私は /usr/local/poudriere/data/pkgbase としましたが、この辺はお好きなように。

次にいよいよ base パッケージを作成します。/usr/local/poudriere/jails/s15amd64/usr/src で

# make REPODIR=/usr/local/poudriere/data/pkgbase KERNCONF=MYKERNCONF packages

とやって、終わるまでしばらく待ちます。

リポジトリに署名しておきたい場合は、タイプ ecdsa の秘密鍵が /usr/local/etc/pkg/keys/myrepo.key にあるとして、

# make REPODIR=/usr/local/poudriere/data/pkgbase KERNCONF=MYKERNCONF PKG_REPO_SIGNING_KEY=ecdsa:/usr/local/etc/pkg/keys/myrepo.key packages

とします。

どうやって myrepo.key (と myrepo.pub)を作ればいいのと半べそをかいている人に教えてあげますが、 pkg-key(8) に書いてあって、次のようにすればよいです。

# pkg key --create -t ecdsa /usr/local/etc/pkg/keys/myrepo.key > /usr/local/etc/pkg/keys/myrepo.pub

pkg 向けに repository を定義する

/etc/pkg/FreeBSD.conf を参考にします。

ローカルの場合は httpd が何かのトラブルで動かない場合もインストールできるように file: で指定します。 リモートの場合は http:https: ですね。そう、http サーバーを設定すれば、他の PC にも同じものがインストールできるのです。

ローカルはこんな感じ:

myrepo-base: {
  url: "file:///usr/local/poudriere/data/pkgbase/FreeBSD:15:amd64/latest",
  mirror_type: "none",
  signature_type: "none",
  enabled: yes,
  priority: 10
}

リモートで署名してある場合はこんな感じ:

myrepo-base: {
  url: "https://pkg.example.jp/base/FreeBSD:15:amd64/latest",
  mirror_type: "none",
  signature_type: "pubkey",
  pubkey: "/usr/local/etc/pkg/keys/myrepo.pub",
  enabled: yes,
  priority: 10
}

さあアップデートしてみよう

# pkg upgrade -r myrepo-base 

で新しい base のパッケージがインストールされるはずです。 kernel が新しくなっているか、再起動する前に

# pkg info -a | grep kernel

とかやって確認しておきましょう。

もうひとつ

これまで make buildworld buildkernel; make installkernel installworld でやってきたのを、 PKGBASE 方式に移行できないのかと思うのはもっともなことですが、実はそれもできます。 それについてはまた後日。

FreeBSD でも GPU に計算させて遊ぶ(FFTライブラリ篇)

CUDA ではありません

FreeBSD でも Linux エミュレーションで頑張ったら CUDA を使えるよという話は FreeBSD forum になんか記事があったのでそっちを見てください。

FreeBSD でも GPU で計算

世の中、GPU(というよりは CUDA)で計算をいろいろやらせてとかうるせえなあ、しょせん私が使っているのは FreeBSD でと言いたいところだけど、 FreeBSD でも GPU が使える以上は GPU に計算してもらうことだってできるはず。

というわけで、AMD GPU なら FreeBSD でも cloverOpenCL 遊びができますよという話。 NVidiaGPU については知らないけど、そっちをサポートしている OpenCL の実装がなかったっけ?

いきなり OpenCL をがりがりと書くのもなんなので、まずは既存のライブラリを使って FFT 計算をやってもらおう。 Ports/packages には clFFT が入っているからそれを使えばいいよね。 比較のために、CPU で計算する FFTW も使ってみよう。

ソースコード

というわけで、サンプルコードをここ https://github.com/oikumene/fft_example においた。 bench-* というプログラムに指定した画像ファイルをグレースケールに変換して FFT をかけるだけ。 一般的には GPU での計算は float でやるみたいだけど、なんかの科学技術計算ができたらいいなと思っているので double でやってみた。 FFTW 版は、1スレッドと6スレッドの2回計算している。 preparation がそれぞれのライブラリ用のデータ構造に画像のデータをコピーする処理にかかっている時間で、 execution が FFT の実行時間。clFFT 版はGPUからデータを取ってくるところも execution に入れている。 FFT の結果としてどういう情報を保存すればよいのか分からないので実部だけを保存するようにしてみたが、なんかおかしい。 逆フーリエ変換はうまくいくので、画像を保存する時のデータの取り出し方がたぶんなんかまずいんだけど。

実行結果

FFTW版。Motorola g13 のカメラで撮影した画像を処理したもの。 6スレッドあると計算時間が 1/3 くらいになるみたい。

% ./bin/bench-fftw img/IMG_20250227_200104.jpg 
FFTW(double) image (nthread = 1): img/IMG_20250227_200104.jpg
preparation: 0.00387s; execution: 0.19646s; total: 0.20033s
FFTW(double) image (nthread = 6): img/IMG_20250227_200104.jpg
preparation: 0.01027s; execution: 0.06586s; total: 0.07613s

なんだけど、clFFT 版はエラーになる。どうやら画像が大きすぎるよう。

% ./bin/bench-clfft img/IMG_20250227_200104.jpg
clFFT image: img/IMG_20250227_200104.jpg
Platform: Clover
Device: AMD Radeon RX 580 Series (radeonsi, polaris10, LLVM 19.1.7, DRM 3.49, 14.3-STABLE)
preparation: 0.19309s; execution: 0.00000s; total: 0.19309s
Executing clFFT on img/IMG_20250227_200104.jpg failed.

もう少し小さい画像ということで、WX321J のカメラで撮った画像を処理してみた。 まず FFTW 版。 準備にかかる時間があまり変わらなくて、計算時間が縮まったので6スレッドでもトータルの時間はあまり変わらない。

% ./bin/bench-fftw img/J0010126.jpg 
FFTW(double) image (nthread = 1): img/J0010126.jpg
preparation: 0.00359s; execution: 0.00525s; total: 0.00885s
FFTW(double) image (nthread = 6): img/J0010126.jpg
preparation: 0.00505s; execution: 0.00175s; total: 0.00680s

clFFT 版。今度は計算できた。float にすれば必要なメモリ量が半分になるのでもう少し大きな画像でもいけるはず。 だが、Radeon RX580 くらいだと、CPU (Xeon のなんか) の一スレッドと同じくらいの計算時間で (データ転送の時間があるので、計算時間そのものは短いとは思うが)、 準備の時間がだいぶかかってしまって、あまり GPU で計算するメリットがないかもしれない。

% ./bin/bench-clfft img/J0010126.jpg          
clFFT image: img/J0010126.jpg
Platform: Clover
Device: AMD Radeon RX 580 Series (radeonsi, polaris10, LLVM 19.1.7, DRM 3.49, 14.3-STABLE)
preparation: 4.24376s; execution: 0.00579s; total: 4.24955s

ついった謎辞典

なんか出会ったら追加していく。

sssd を設定して、ノートPC上の FreeBSD でも Active Directory 認証を使う

Active Directory によるユーザー管理

Windowsunix 系OSでユーザー管理を共通化する方法として Active Directory を利用する方法がある。 ドメインコントローラ―には Windows server を使っても良いが、Samba を利用することもできる。

Samba

Active Directory Domain Controller および member サーバー

Samba の設定については、Samba WikiSamba を Active Directory ドメインコントローラーとして設定する記事と、 メンバーサーバーとして設定する記事 でだいたいは足りると思われる。

winbind と pam によるユーザー認証

Samba を用いる場合、Samba についてくる winbindd で認証を行う。そのための pam の設定は FreeBSD では以下のようになる。

/etc/pam.d/system:

auth            sufficient      pam_winbind.so
auth            required        pam_unix.so             no_warn try_first_pass nullok

account         sufficient      pam_winbind.so
account         required        pam_login_access.so
account         required        pam_unix.so

session         required        pam_lastlog.so          no_fail
session         required        pam_xdg.so

password        sufficient      pam_winbind.so
password        required        pam_unix.so             no_warn try_firstpass

Samba による認証の問題点

ここまでの設定だと DC がオンラインでないと認証ができない。

/usr/local/etc/smb4.conf に

winbind offline logon = yes

/etc/security/pam_winbind.conf に

cached_login = yes

を追加することで認証情報をキャッシュしてオフラインでもログオンできるようになるが、 FreeBSD forum の記事 によれば、オンラインだが DC が見つからない場合にログオンできない問題がある。

sssd

この問題に対応できるのが sssd で、現在 FreeBSD ports には security/sssd2 が入っている。 sssd は Kerberos の実装は MIT にしか対応していないため、Heimdal に設定してインストールしている ports があったら MIT でビルドしなおしてインストールする必要がある。

realmd を利用した初期設定

samba を利用して手動で設定することもできるが、 おすすめは net-mgmt/realmd を利用した自動設定である。

必須ではないが、realm discover コマンドでドメインが検出できるか確認する。 なお、realmd は dbus に依存しており、dbus サービスを動かしておく必要がある。

# realm discover EXAMPLE.COM
example.com
  type: kerberos
  realm-name: EXAMPLE.COM
  domain-name: example.com
  configured: no
  server-software: active-directory
  client-software: sssd
  required-package: sssd2
  required-package: adcli
  required-package: samba416

required-package で設定および動作に必要なソフトウェアが示されているが、adcli と samba416 は sssd2 の依存関係でインストールされているはずである。

その後、realm join コマンドでドメインに join するとともに、各種設定を済ませる。

# realm join EXAMPLE.COM

Active Directory の Administrator パスワードの入力が要求されるが、入力すると /etc/krb5.conf、/etc/krb5.keytab、/usr/local/etc/sssd (とその下位ファイル)が生成されているはずである。 必要であれば、/usr/local/etc/sssd/sssd.conf を編集する。

例えば、私の場合は AD ドメインはひとつしか運用していないので、次のように変更を入れている。

generated:

[sssd]
domains = oikumene.ukehi.net
config_file_version = 2
services = nss, pam, ifp

[domain/oikumene.ukehi.net]
default_shell = /bin/sh
krb5_store_password_if_offline = True
cache_credentials = True
krb5_realm = OIKUMENE.UKEHI.NET
realmd_tags = manages-system joined-with-adcli 
id_provider = ad
fallback_homedir = /home/%u@%d
ad_domain = oikumene.ukehi.net

編集後

[sssd]
domains = oikumene.ukehi.net
config_file_version = 2
services = nss, pam, ifp

[domain/oikumene.ukehi.net]
default_shell = /bin/sh
krb5_store_password_if_offline = True
cache_credentials = True
krb5_realm = OIKUMENE.UKEHI.NET
realmd_tags = manages-system joined-with-adcli 
id_provider = ad
auth_provider = ad
access_provider = ad
chpass_provider = ad
override_homedir = /home/%u
ad_domain = oikumene.ukehi.net
use_fully_qualified_names = False
ad_maximum_account_password_age = 0
ldap_id_mapping = True
ldap_schema = rfc2307
ldap_idmap_range_min = 10000
ldap_idmap_autorid_compat = True

以下、解説を少々。

  • cache_credentials: True にすると認証情報をキャッシュするのでオフライン時も認証が可能である。 sssd を入れるのはこの設定ができるからと言っても過言ではない。

  • auth_provider, access_provider, chpass_provider: よくわかんないけど、とりあえず ad にしておこう。詳しくは sssd-ad(8) を読んでね。

  • override_homedir: これは、私の Active Directory RFC2307 なんちゃらの設定が古いのを残さざるを得なくて、 /usr/home となっているから上書きしている。 また、複数ドメインを運用している場合は @domain をつける必要があるかもしれないが、 私はそんなのはなくて良いので簡単のために単に /home/user にしている。

  • use_fully_qualified_names: False に設定することで、getent などで表示されるユーザー名を user@domain から user と短い形式にして unix ぽくできる。

  • ldap_ip_mapping と関連オプション: Samba の設定の idmap config なんちゃらと同様の設定を行う。 ただし、全く同じにはできないので、マッピングされる uid、gid は winbind によるものとは通常異なる。 ldap_idmap_autorid_compat を True にするとより winbind っぽくなるが、全く同じには以下略。

sssd と pam によるユーザー認証

/etc/nsswitch.conf の以下の行を編集する

group: files sss
netgroup: files sss
passwd: files sss
services: files sss

FreeBSD ではドキュメントと異なり pam の設定は自動では変更されないので、/etc/pam.d/system と /etc/pam.d/sshd を編集する。 pam_unix(8) の no_warn に対応するのが quiet であり、try_first_pass は実装されていないので forward_pass または use_first_pass を使う。 どちらを使うかは単純で、auth 行で pam_sss.so が最初に来ていたら、forward_pass、 2番目以降なら use_first_pass を指定すればよい。

auth    sufficient    pam_sss.so    quiet forward_pass
auth    requied    pam_unix.so    no_warn try_first_pass

account    sufficient    pam_sss.so    ignore_unknown_user
account    required    pam_login_access.so
account    required    pam_unix.so

session    optional    pam_sss.so
session    required    pam_lastlog.so    no_fail
session    required    pam_xdg.so

password    sufficient    pam_sss.so    quiet use_authtok
password    required    pam_unix.so    no_warn try_first_pass

また、/etc/pam.d/login と /etc/pam.d/sshd あと必要なら /etc/pam.d/xdm に次の設定を追加する。 詳しくは [ホームディレクトリを自動で作成したい](https://cugel.hatenablog.com/entry/2020/08/10/232231] 参照のこと。

session    optional    pam_sss.so
session    optional    pam_mkhomedir.so
session    required    pam_lastlog.so    no_fail
session    required    pam_xdg.so

テスト

getent passwd または id コマンドで情報が取れているかを確認後、su コマンドで su できるか確認するとよい。 ただし、root から su するとパスワードの入力がバイパスされるので、 shell が /bin/sh のシステムアカウントのどれかを経由する。

使わなくなった時の後始末

sssd は自分を DC として登録している(いないけど、なんかそんなことをしている)ので、 その PC を使わなくなった時は demote する必要がある。 この時も samba を利用する。

# samba-tool domain demote

しばしばあることではあるが、うっかり demote するのを忘れて PC を初期化するとか捨てるとかしてしまった場合は、他の DC で samba-tool を使って demote できる。

# samba-tool domain demote --remove-other-dead-server=COMPUTERNAME