Raspberry PiでUSBメモリ内のファイルを実行可能にする方法

# 追記

-- 2022年3月28日追記 --

udisks2.9.0で設定ファイルを読み込む機能が追加されました。
設定ファイルは /etc/udisk2/mount_options.conf で
mount_options.conf.example が提供されていますので、
コピーして編集すれば、USBメモリ内のファイルを実行可能にできます。

 ```
$ sudo cp /etc/udisks2/mount_options.conf{.example,} 
$ sudo nano /etc/udisk2/mount_options.conf
```

編集内容は
* [defaults] の行のコメントを外す
* vfat_defaults の行のコメントとshowexecを外す

です。

編集後、rebootすると mountのshowexecオプションが外れます。


参考: [Configurable mount options: UDisks Reference Manual](http://storaged.org/doc/udisks2-api/latest/mount_options.html)

-- 2022年3月28日追記 おわり--


# 背景

時々、Raspberry Piを業務で使用する。その場合、fsprotectとaufsでROM化し、いつでも電源切断可能状態にしている。これだとsdカードの寿命も気にする必要が無い。設定やデータの保存を行いたい場合には、USBメモリを刺し、保存している。

今回、顧客からプログラムのバージョンアップ機能もつけて欲しいという要望があり、プログラムをUSBメモリ側に置いて走らせれば良いかと考えていたが、試してみるとUSBメモリー上のファイルに実行可能パーミッションがつかない。 chmod +x してもつかない。実行できない。

# 現状の調査/ showexecオプション

raspberry piは Rasbianで動作している。 GUI (X-window)を動かしているので、ファイル・マネージャ (pcmanfm)が udisks2 を使用し USBの抜き差しを監視し、mountしているらしい。

USBメモリは /media以下にマウントされる。mountの状態を見てみる。vfatファイルシステムでマウントされている。

![sc200213a.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144308/db6c7256-1450-d6c5-dc1a-5b5b881f1730.png)

同じく vfatの /bootのマウントの状態を見る。

![sc200213b.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144308/c7b8a2f8-1a11-8583-d6b6-f9cea52fa2f0.png)

/boot以下のファイルには、全て 実行可能フラグがついている。mountオプションの違いを調べると showexecが怪しい。man で調べると

```
      sys_immutable, showexec, dots, nodots, dotsOK=[yes|no]
              FAT ファイルシステムに Unix または DOS のしきたりを 強制しようと
              するさまざまな試み。 おそらくは用いるべきでない。
```

とか

```
showexec
    If set, the execute permission bits of the file will be allowed only if the
    extension part of the name is .EXE, .COM, or .BAT. Not set by default. 
```

などとあるが、拡張子 .EXEのファイルで試しても 実行可能パーミッションはつかない。vfatファイルシステムの通常ファイルの実行可能フラグが、デフォルトでは全部ついて、このオプションがある時は、全部吐かないという動作になるのではないかと思われる。

# 対策の検討

mount時にshowexecオプションがつかないように設定できれば解決しそうなのだが、いくら調べても指定の方法がわからない。 showexecという文字列が使用されている場所を探したところ、udisks2のソースファイル中に発見。　vfatファイルシステムのデフォルトのマウントオプションらしい。　ソースを書き換え udisks2を置き換えてやれば解決できそうだ。

# udisks2の改造

下記ページを参考に、raspberrry pi上で改造を行った。
[Raspberry piにてapt-srcでパッケージをビルドするには](https://denor.jp/raspberry-pi%E3%81%AB%E3%81%A6apt-src%E3%81%A7%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%82%92%E3%83%93%E3%83%AB%E3%83%89%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF)

## ツールの取得

ソースの取得とコンパイルに必要なツール apt-srcとbuild-essentialをインストールする。

```
$ sudo apt-get install apt-src build-essential
```

## ソースの取得

/etc/apt/sources.listを編集し、deb-srcの行のコメントを外す。

```
$ sudo apt-get update
$ sudo apt-src update
$ cd 適当な作業ディレクトリ
$ apt-src install udisks2
```

## プログラムの書き換え

./udisks2-2.18/src/udiskslinuxfilesystem.c を編集。
"showexec"という文字列を検索し、showexecの部分をコメントアウトする。

287行あたり、修正後の状態。

```
static const gchar *vfat_defaults[] = { "uid=", "gid=", "shortname=mixed", "utf8=1", /* "showexec", */ "flush", NULL };
```

## コンパイル

以下のコマンドを実行する。
結構時間がかかる。

```
$ apt-src build udisks2
```

完了すると、拡張子 .debのファイルが、いくつか出来ている。

## インストール

dpkgコマンドで .debファイルをインストールするが、インストールされたかどうか
わかりにくいので、元のファイルをコピーしておく。

```
$ sudo cp /usr/bin/udisksctl{,.orig}
$ sudo cp /usr/lib/udisk2/udisksd{,.orig}
$ sudo dpkg --install *.deb
```

## 確認

書き換わったことを確認します。

```
$ ls -l /usr/bin/udisksctl*
-rwxr-xr-x 1 root root 43100 11月 25  2016 /usr/bin/udisksctl
-rwxr-xr-x 1 root root 43048  2月 12 19:07 /usr/bin/udisksctl.orig
$ ls -l /usr/lib/udisks2/udisksd*
-rwxr-xr-x 1 root root 307948 11月 25  2016 /usr/lib/udisks2/udisksd
-rwxr-xr-x 1 root root 307952  2月 12 19:08 /usr/lib/udisks2/udisksd.orig
$
```

rebootし、mountオプションを確認する。

![sc200213c.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144308/36c68628-9de4-0976-c670-5f632c078a7f.png)

USBメモリ内のファイルを見ると、ファイルに
実行パーミッションが付いた。

![sc200213d.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144308/21295461-1799-6ea1-e3d7-8942847326d9.png)

# 最後に

システムの設定の変更をするのに、ソースを変更するのは違う気がするが、設定ファイルで変更する方法がわからなかったので仕方がない。設定ファイルで行う方法をご存じの方は、教えて頂ければ有り難い。