揮発性のメモ2

知識をメモ書きしておく

feofでループするとバグる

feof() は終端まで到達していたらEOFを返すけど、終端かどうかは最後の文字の次の文字を読むまでわからない。
よって、while(!feof() みたいにループで1文字ずつ読むと、必ず最後にゴミがでる。

今までファイルを1文字ずつ読んだことなんかなかったので、初めて気づいた

<?php
$fp=fopen($argv[1],"r") or die("fopen");
while(!feof($fp)){
    $c = fgetc($fp);
    if($c===false){
        echo "ナンデ?\n";
    }else{
        echo ord($c).",";
    }
}
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    int c;

    fp = fopen(argv[1],"r");
    if(fp==NULL){
        perror("fopen");
        return 1;
    }
    while(!feof(fp)){
        c = fgetc(fp);
        if(c==EOF){
            printf("ナンデ?\n");
        }else{
            printf("%d,",c);
        }
    }

    return 0;
}


ググったら文句を言っている人はいっぱいいた。 PHPに至ってはマニュアルで愚痴ってる
stackoverflow.com
hnw.hatenablog.com
https://www.php.net/manual/ja/function.feof.php

udevでバックグラウンドで動くプログラムを起動する 3

USB機器を挿した契機で、ちょっと時間のかかるプログラムをバックグラウンドで起動したい。
また、抜けたら抜けたで何か起動したい。

/etc/udev/rules.d/99-local-usb.rules

# USB機器が刺さったらなんかする
ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", TAG+="systemd", ENV{SYSTEMD_WANTS}+="hoge@%E{DEVPATH}.service"

/etc/systemd/system/hoge@.service

[Unit]
Description=HOGEHOGE service %I
#After=network.target
StopWhenUnneeded=true

[Service]
Type=oneshot
ExecStart=/usr/local/bin/hoge.sh add %I
ExecStop=/usr/local/bin/hoge.sh remove %I
RemainAfterExit=true

[Install]
WantedBy=multi-user.target

systemd.unit
bugzilla.redhat.com
まず、TAG+="systemd" とした時点で ACTION=="remove"はなんやかんやで利かなくなる。
よって、addのときはsystemd経由でremoveのときは自分でRUN、などはできない。

StopWhenUnneeded

不要になったとき(addに対するremoveのとき)に自動でStopを呼ぶかどうかの設定。
これだけを有効にすると、oneshotのときは 呼び出したプログラムが正常終了した契機でも 不要扱いとなり、Stopが実行されてしまうのでもう一つ設定する。

RemainAfterExit

oneshotのとき、プログラムが正常終了しても ステータスを維持する。
これだけを有効にしても、removeに対する行動はとくに起きない。


この2つの設定をすることで刺さったときも抜けたときも別のプログラムを背後で起動できる

udevでバックグラウンドで動くプログラムを起動する 2

USB機器を挿した契機で、ちょっと時間のかかるプログラムをバックグラウンドで起動したい。
そのまま呼ぶと一瞬で殺されるので、systemdを使って起動する

/etc/udev/rules.d/99-local-usb.rules
# USB機器が刺さったらなんかする
#ACTION=="add"  , SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", RUN+="/usr/local/bin/hoge.sh"
ACTION=="add"   , SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", TAG+="systemd", ENV{SYSTEMD_WANTS}+="hoge.service"
/etc/systemd/system/hoge.service
[Unit]
Description=HOGEHOGE service
#After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/hoge.sh

[Install]
WantedBy=multi-user.target


Linux でデバイスを接続している時だけ動くサービスを作る - Qiita
access.redhat.com

      •  
続きを読む

udevでバックグラウンドで動くプログラムを起動する

USB機器を挿した契機で、ちょっと時間のかかるプログラムをバックグラウンドで起動したい。
ちょっと前までは nohup とか付けたプログラムを2段ロケットで呼べば動いていたけど、最近(Debianならstretchから?)ではdisownだろうがnohupだろうが 1秒も経たずに普通に殺してくるようになった。
以下、殺される方法

99-hogehoge-usb.rules

# USB機器が刺さったらなんかする
ACTION=="add"   , SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", RUN+="/usr/local/bin/hoge.sh"

hoge.sh

#!/bin/bash

# バックグラウンドで動かしたいプログラムの本体を呼ぶ
nohup /usr/local/bin/piyo.sh &>/dev/null </dev/null &

piyo.sh

#!/bin/bash

# バックグラウンドで動かしたいプログラムの本体
while :; do
  date +"%H:%M:%S.%N" >> /tmp/piyo.log
  sleep 0.01
done

nohupさえつけておけば死ぬことはないだろうと油断していたので、古いのから移植するときに
まずそもそも何が起きているのか把握するまでが大変だった。


askubuntu.com
unix.stackexchange.com

[: missing ]

/usr/local/bin/hoge: 8: [: missing ]

というエラーが出て、その8行目は

[ -z "$ADDR"] || ADDR="HOGEHOGE"

という塩梅だった。


"[" が文法じゃなくて内部コマンドだということを失念していたため、[ ] を単なる飾りとして見ていて、: missing ってなんだろうとずっと思っていた。
/usr/local/bin/hoge の 8行目の "[" コマンドで、 ] が見つからないというエラーだった。
("$ADDR" と ] の間にスペースがないので1文字列として認識されて ] を見失ってた)
思い込みって怖い

grepでファイルシステムをまたがずに検索する

普通に / からgrepで全ファイル検索しようとすると、/sysや/procまでたどるので困る。
なので、同一ファイルシステム内だけで検索したい
(findなら -xdevが、cpなら -x がある)


unix.stackexchange.com

find / -xdev -type f -print0 | xargs -0 grep -I -H "hogehoge"
find オプション
-xdev ファイルシステムを跨がない
-print0 空白区切りでなく \0 区切りで出力する*1
xargs オプション
-0 空白区切りでなく \0 区切りで入力する
grep オプション
-I バイナリファイルは無視
-H 出力結果にファイル名を常に出す

何十年もみんな求めてる機能だし そろそろ実装されてもいい頃合いなんだけど、なかなか実装されないな

*1:ファイル名にスペースを使うアホが居ても困らないように

tmpfsでオーナーを指定する

wiki.archlinux.org

# ls -ld /hoge
drwxrwxrwx 2 root root 4096 May 22  2018 /hoge

# mount -o uid=www-data,mode=700 -t tmpfs tmpfs /hoge

# ls -ld /hoge
drwx------ 2 www-data root 40 Jun 29 10:00 /hoge

tmpfsは、オプションでパーミッションや所有者をちゃんと指定できる。
ext4みたいな適当なやつとはわけが違う