それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

暗号化ディスクを新しいSSDに移動させてサイズを増大させる enlarge lvm on Luks

ssd を移動させたい。しかし暗号化ディスクだ

HDD/ssd はデータ式年遷宮をするのだけど、今回は、暗号化ディスクだった。

手順

手順は次の通り

  • とりあえず、dd
  • ubuntu など live disk で起動させる
  • gdisk などでパーティションを拡大
  • crypt領域を拡大
  • lvm pv を拡大
  • lvm vg lv を拡大
  • ext4 を拡大

lvm の拡大とext4 の拡大は、よくあるので大丈夫でしょう。

問題は、 cryptdisk の拡大ですね。

他にも dump restore でまるっと新しいものにすることもできるけど、dump 結果の保存場所を考えるとやっぱり ddかなと

SSDの移動

ssd 間で データをコピーする

ubuntu の live usb で起動して

dd status=progress if=/dev/sda of=/dev/sdb bs=1M

gdisk でパーティションを最大にする

今回は、EFI パーティションを含むディスクなので、パーティションは3つ。 1 はEFI互換性システム、2がEFI。3がルートファイルシステムになる。

パーティションを最大にする

takuya@:~$ sudo gdisk /dev/sdb
GPT fdisk (gdisk) version 1.0.4

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048         1050623   512.0 MiB   EF00  EFI System Partition
   2         1050624         2549759   732.0 MiB   8300
   3         2549760        69658623   32.0 GiB    8300  Linux filesystem

Command (? for help): d
Partition number (1-3): 3
Command (? for help): n
Partition number (3-128, default 3):
First sector (34-234441614, default = 2549760) or {+-}size{KMGTP}:
Last sector (2549760-234441614, default = 234441614) or {+-}size{KMGTP}: 
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300):
Changed type of partition to 'Linux filesystem'

Command (? for help): p

Total free space is 2014 sectors (1007.0 KiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048         1050623   512.0 MiB   EF00  EFI System Partition
   2         1050624         2549759   732.0 MiB   8300
   3         2549760       234441614   110.6 GiB   8300  Linux filesystem

暗号化ディスクを最大にする

最初に 暗号化ディスクを解錠して読み込み可能にする。

cryptsetup luksOpen /dev/sdb my_crypt

つぎにリサイズをかける

cryptsetup resize /dev/mapper/my_crypt
Enter passphrase for /dev/sda3:

ここまでで、ほぼ完了に近い。

LVM PVでリサイズする

つぎに、lvm で pv を最大にする

pvresize /dev/mapper/my_crypt

確認する。

Before

takuya@:~$ sudo pvs
  PV                     VG Fmt  Attr PSize  PFree
  /dev/mapper/dm_crypt-0 vg lvm2 a--  27.92g    0

After

takuya@livaz:~$ sudo pvs
  PV                     VG Fmt  Attr PSize   PFree
  /dev/mapper/dm_crypt-0 vg lvm2 a--  110.55g 82.63g

LVM vg/lv を最大にする

このへんはいつもの

takuya@livaz:~$ sudo lvresize -l100%FREE /dev/mapper/vg-lv
  Size of logical volume vg/lv changed from 27.92 GiB (7148 extents) to 82.63 GiB (21154 extents).
  Logical volume vg/lv successfully resized.
takuya@livaz:~$

ext4 を最大にする

このへんも、いつものオンラインリサイズ

sudo resize2fs /dev/mapper/vg-lv

まとめ

cryptsetup resize

これを覚える

暗号化ディスクをddしてコピーしても大丈夫。 blkid などをちゃんと設定しておくと、ddしたそのままで動く。

参考資料

https://wiki.archlinux.org/index.php/Resizing_LVM-on-LUKS

php のコマンド実行のproc_open でexitcode を取得する

proc_open でexitcode を取得すると -1 になる

proc_open の関数で、exitcode を参照すると、常に -1 が固定で返ってくる件

proc_get_status($process)['exitcode']; // -1
proc_get_status($process)['exitcode']; // -1
array:8 [
  "command" => "ssh"
  "pid" => 6694
  "running" => false
  "signaled" => false
  "stopped" => false
  "exitcode" => -1
  "termsig" => 0
  "stopsig" => 0
]

原因

プロセス終了後に status 取得すると、常に -1 しか返ってこない。そういうものである

対策。

proc_get_status($process)['running']false になった瞬間の status を保存しておくと exitcode が正しく取れる。

終了後に初めて呼び出したときに、正しいexitcode が取れる。それ以降は「終了済み」を示す -1 が常に返ってくる。

<?php 
$cmd = ['ssh','localhost', '/bin/noexists_command'];
$process = proc_open($cmd, [2=>$fd_ferr=fopen('php://temp','w')] , $pipes);
if( ! is_resource($process) ) { throw new \Exception("実行エラー");}

do {
        $stat = proc_get_status($process);
        // waiting
        usleep(1000*1);
} while($stat['running']);

if ($stat['exitcode'] > 0 ){
        fseek($fd_ferr,0);
        $err = stream_get_contents($fd_ferr);
        throw new \Exception($err);
}

これは、気づかんわ。

参考資料

https://stackoverflow.com/questions/7645499/getting-the-real-exit-code-after-proc-open

phpのproc_open関数でコマンドのstdin/stdout/パイプを使う例を確認しました。

php でプロセス(プログラム実行)

phpでプログラム実行をするなんて邪悪なことを誰がやるんだろうかと。

symfony process でいいじゃないかと思うんですが、駄目なんですね。synfony processだと巨大なSTDIN/STDOUTを扱えないんですね。たとえば、ffmpegにパイプで渡すとか、ssh経由でデータを受け渡すとか出来ないんですね。

既存の解決策が行き詰まるとき、最後の砦になるのが、proc_openでのコマンドの実行です。

proc_openでプログラム実行 exec同等

単純に `command`exec('command') shell_exec と同じことを proc_openでやる。

echo exec('dd if=/dev/urandom bs=1M count=2')

これは、次のソースコードと同等になる。

<?php 
//
$cmd = preg_split('/\s+/','dd if=/dev/urandom bs=1M count=2');
//
$descriptor = [
    0 => STDIN,
    1 => STDOUT,
    2 => STDERR
  ];
//
$process = proc_open($cmd,$descriptor, $pipes);
if( ! is_resource($process) ) {throw new \Exception("実行エラー");}
while(proc_get_status($process)['running']){
  usleep(1000);
}
proc_close($process);

proc_open で開いたプロセスは、何らかの形でwait して待ってあげます。

上記の例では、proc_get_status() の結果が false になるまで wait しています。

wait するのはいくつが方法が考えられます。 たとえば、 proc_get_status($process); で開いた子プロセスの情報が取れるので、exitcodeを見ることも可能です。

wait を工夫すれば、一定時間経過したら強制終了も可能です。

もしやるなら、posix 関数posix_kill で一定時間経過したら KILLするなども出来ます。

proc_open は実質的には fork / exec ( php 関数では pcntl_fork/ pcntl_exec ) ですね。

コマンドからの出力

コマンドを実行して、起動したプロセスからの出力を操作する方法を見ていきます。

標準出力・エラーを捨てる

標準出力とエラーを捨てるときのコードは、こんな感じものがよく書かれますが

<?php 
passthru('ls -l > /dev/null 2> /dev/null');
echo exec('ls -l > /dev/null 2> /dev/null');

これは、proc_openでは次のようにする。

<?php 
$cmd = preg_split('/\s+/','dd if=/dev/urandom bs=1M count=2');
//
$descriptor = [
    0 => STDIN,
    1 => ['file', '/dev/null', 'w'],
    2 => ['file', '/dev/null', 'w']
  ];
//
$process = proc_open($cmd, $descriptor );
if( ! is_resource($process) ) {throw new \Exception("実行エラー");}
while(proc_get_status($process)['running']){
  usleep(1000);
}
proc_close($process);

省略可能

また、$descriptor は指定しないもの以外を省略できる。

使わないディスクリプタは、省略して構わない。

省略するとデフォルト [ STDIN , STDOUT, STDERR ] が適用される。

<?php 
$descriptor = [
    // 0 => STDIN,
    1 => ['file', '/dev/null', 'w'],
    2 => ['file', '/dev/null', 'w']
  ];
//
$process = proc_open($cmd, $descriptor );

標準出力を指定のファイルに

コマンドの出力を別のファイルに接続する。シェルからのコマンド実行だと次のようになる。

<?php
exec(' ls -l > /tmp/out');

これをproc_open 場合は、次のように書くと同様になる。

<?php
//
$cmd = preg_split('/\s+/','ls -alt /tmp/');
//
$fout = fopen('/tmp/out', 'w+');
$descriptor = [
    1 => $fout,
  ];
//
$process = proc_open($cmd, $descriptor );
if( ! is_resource($process) ) {throw new \Exception("実行エラー");}
while(proc_get_status($process)['running']){
  usleep(1000);
}

fseek($fout,0);
$stdout = stream_get_contents($fout);
var_dump($stdout);
//
proc_close($process);

fopen() で開いたファイルに、proc_openしたコマンドのプロセスの標準出力が次々とfwrite されます。

プロセス終了後にファイルのシークは末尾に来ている。

なので、読み出すならfseek($fout,0);をして先頭に持ってくる。

先頭に持ってくるとその場で読み込める。

出力結果を一時ファイルに出す。

出力先を、 php://temp に変更すると、一時ファイルを作成削除を考えずに済むので助かる。

<?php
$fout = fopen('php://temp', 'w+');
$descriptor = [
    1 => $fout,
  ];

php のコードを見ていると、一時ファイルを作成して削除するパターンを非常によく見かけるのだけれど、fopenでfd を持ち回したほうが管理が圧倒的に楽だと思うんです。

php://temp を使う場合の注意点

php://temp には少し癖があり、open するたびに、別のファイルとして扱われる。 必ず、fseek で動かすこと。

## 間違い
$fout = fopen('php://temp', 'w+');
fwrite($fout, 'aaaaaaa');
$out = file_get_contents('php://temp', 'r');
## 正しい
$fout = fopen('php://temp', 'w+');
fwrite($fout, 'aaaaaaa');
fseek($fout, 0);
$out = stream_get_contents($fd);

php://memory and php://temp are not reusable, i.e. after the streams have been closed there is no way to refer to them again.

詳しくは本家のマニュアルを読むこと https://www.php.net/manual/en/wrappers.php.php

標準エラー出力を別のファイルに

エラー出力を、指定したファイルに出す。

ls -alt 2> /tmp/error-log.txt

これと同等のことを proc_open でやると次のようになる。

<?php
//
$cmd = preg_split('/\s+/','ls -alt /tmp/');
//
$ferr = fopen('/tmp/error-log.txt', 'w+');
$descriptor = [
    2 => $ferr,
  ];
//
$process = proc_open($cmd, $descriptor );
if( ! is_resource($process) ) {throw new \Exception("実行エラー");}
while(proc_get_status($process)['running']){
  usleep(1000);
}

//
proc_close($process);

エラー出力と標準出力をそれぞれ別のファイルに出す。

$descriptorをアレコレすると直接ファイルに書き出せる。

<?php
$descriptor = [
    1 => fopen('/tmp/log.txt', 'w+'),
    2 => fopen('/tmp/error-log.txt', 'w+'),
  ];

出力にパイプを使う。

パイプを使う場合は、次のようにしてパイプを指定する。

<?php
$descriptor = [
    1 => ['pipe','w'],
    2 => ['pipe','w'],
  ];
$process = proc_open($cmd, $descriptor, $pipes , '/tmp', []  );

パイプはファイルディスクリプタでプロセス起動後にアクセスができるようになる。

パイプを使う例

pipeを使うと、パイプされているfd から読み込まれる。proc_open() の3th 引数で取得できる。

<?php
//
$cmd = preg_split('/\s+/','ls -alt /tmp/');
//
$descriptor = [
    1 => ['pipe','w'],
  ];
//
$process = proc_open($cmd, $descriptor, $pipes , '/tmp', []  );
if( ! is_resource($process) ) {throw new \Exception("実行エラー");}
while(proc_get_status($process)['running']){
  usleep(1000);
}

$out = stream_get_contents($pipes[1]);
var_dump($out);
//
proc_close($process);

パイプは内部で読み込みと書き込みにfd2つ開けて接続する。

out書き込み用は内部的に使われていて、関数の戻り値にもらえるのは読み込み用 open 後に読み込み用のfd (ファイルディスクリプタ)が返される

パイプ close タイミング

出力用 pipe は、fcloseを明示的に呼ばなくても良い、proc_close() したタイミングで、開いているファイルは close される。

<?php
//fclose( $pipes[1]); //←不要
//fclose( $pipes[2]); //←不要
proc_close($process);

コマンドへの入力

ここまでは、コマンドからの出力を読み込み用に貰ってくる話でした。

ここからは、コマンドへ入力する話です。

標準入力をプロセスにわたす。

実行プログラムの標準入力にファイルを渡すなら、シェルならリダイレクトで書きます。

cat < /tmp/out.txt

入力のリダイレクト、これを proc_open で書くと次のようになる。

<?php
//
$cmd = preg_split('/\s+/','cat');
//
//
$descriptor = [
  0 => fopen('/tmp/out.txt', 'r'),
  ];
//
$process = proc_open($cmd, $descriptor, $pipes , '/tmp', []  );
if( ! is_resource($process) ) {throw new \Exception("実行エラー");}
while(proc_get_status($process)['running']){
  usleep(1000);
}
//
proc_close($process);

cat を起動して、stdin にfopen の結果をリダイレクトでつなぐ。

パイプでコマンドに入力を渡す。

入力を渡すのであれば、パイプを経由するのが一般的だと思います。

cat  /tmp/out.txt | cat 

これを proc_openで書くとしたら、pipe を 指定して、そこに書き込んで、fclose する。

<?php
//
$cmd = preg_split('/\s+/','cat');
//
//
$descriptor = [
  0 => ['pipe','r'],
  ];
//
$process = proc_open($cmd, $descriptor, $pipes , '/tmp', []  );
if( ! is_resource($process) ) {throw new \Exception("実行エラー");}

// write to pipe
$f_in = fopen('/tmp/out.txt', 'r');
while(!feof($f_in)){
  fwrite( $pipes[0], fread($f_in, 1024));
}
fclose($pipes[0]);
// waiting
while(proc_get_status($process)['running']){
  usleep(1000);
}
//
proc_close($process);

fclose($pipes[0]); で開けている パイプをcloseしないとプロセスはEOFが来ないので、読み込み待ちでずっとWaitingになるんで注意 0 => ['pipe','r'] で read を指定しているのは、プロセスからみて read ですね。返ってくる $pipeには プロセスへのwrite が戻されるね。

proc_close($process); するとパイプは自動で閉じられる。

一時ファイル作らずにパイプと標準入出力を使う。

php のコードを見ていると、よく見かけるのだけれど tempファイルをバンバン使うんですね。 でも、それってゴミファイルが残ったり管理がめんどくさいんですね。

<?php

$temp1 = tempnam(  sys_get_temp_dir() );
$temp2 = tempnam(  sys_get_temp_dir() );
$str = exec( 'cat '. $temp1 );
file_put_contents($temp2,$str);
pcntl_signal(SIGINT,  "sig_handler");
@unlink($temp1);
@unlink($temp2);

function sig_handler(){
@unlink($temp1);
@unlink($temp2);
}

削除処理が必要になる理由

一時ファイルを使うの用途にはメモリ上限になっちゃう巨大サイズのコマンド実行を扱うとき。

サイズが大きいデータをクラス間で受け渡すときによく使うんですね。だから一時ファイルを適切に削除しないと面倒が増える。

また、巨大なファイルを変数に読み込んでいると、php のメモリ上限などで困るんですよね。

プロセスを開いて流し込んでパイプでつなぎ、プロセス出力をファイルディスクリプタで受け取ればメモリを浪費せずに済む。

これで一時ファイルの管理の地獄にならないで助かる。

プロセスと一時ファイルを使う。

サイズの大きなファイルを扱うときに、変数に取り出したり、一時ファイルを作成して管理せずに直接にファイルディスクリプタを扱えば、管理から開放される。

<?php
function my_command(){
  $descriptor = [
    1 => $fd = fopen('php://temp','w'),
  ];
  
  
  $process = proc_open("cat", $descriptor, $pipes , '/tmp', []  );
  if( ! is_resource($process) ) {throw new \Exception("実行エラー");}
  
  while(proc_get_status($process)['running']) {
    usleep(1000);
  }
  fseek($fd);
  proc_close($process);
  
  return $fd;
  
}

php://temp をつかっておけば、SIG INIT や HUP時に残る一時ファイルはphpがうまいことやってくれる(はず)

proc_open で標準出力・入力を使ってコマンドを起動する

たとえば、ffmpeg を使って ssh 経由で 変換するとか

cat bigfile.ts | ssh ffmpeg -i   pipe:0   ...  pipe:1  | cat -> out.mp4
<?php
//
$cmd = preg_split('/\s+/','ssh server ffmpeg -i pipe:0  -f h265 pipe:1 ');
//
$f_in = fopen('/tmp/out.ts','r');
$f_out = fopen('/tmp/out.mp4','r');
$descriptor = [
  0 => ['pipe','r'],
  1 => ['pipe','w'],
  2 => STDERR,
  ];
//
$process = proc_open($cmd, $descriptor, $pipes , '/tmp', []  );
if( ! is_resource($process) ) {throw new \Exception("実行エラー");}

// write to pipe
while(!feof($f_in)){
  fwrite( $pipes[0], fread($f_in, 1024));
}
// fclose($pipes[0]);
// waiting
while(proc_get_status($process)['running']){
  usleep(1000);
}

while(!feof($pipes[1])){
  fwrite( $f_out, fread( $pipes[1], 1024));
}

//
proc_close($process);
//
fseek($f_out,0);
var_dump(fstat($f_out));

proc_close($process); するとパイプは自動で閉じられるので、パイプに残った内容を別のファイルに取り出す必要がありますね。

パイプでプロセスをつなぐ。

ここまで、わかれば、proc_open でプロセスをつないで、パイプパイプでプログラムを複数つなぐことができる。

<?php

/// プロセスA
$descriptor_a = [
  0 => $fin = fopen('/tmp/out.txt','r'),
  1 => ['pipe','w'],
  2 => STDERR,
];


$process_a = proc_open("cat", $descriptor_a, $pipes_a , '/tmp', []  );
if( ! is_resource($process_a) ) {throw new \Exception("実行エラー");}

/// プロセスB
$descriptor_b = [
  0 => $pipes_a[1],
  1 => ['pipe','w'],
  2 => STDERR,
];

$process_b = proc_open("cat", $descriptor_b, $pipes_b , '/tmp', []  );
if( ! is_resource($process_a) ) {throw new \Exception("実行エラー");}

// プロセス待ち
while(proc_get_status($process_a)['running']){
  usleep(1000);
}
while(proc_get_status($process_b)['running']){
  usleep(1000);
}
// 結果を取得
while(!feof($pipes_b[1])){
  fwrite( STDOUT, fread( $pipes_b[1], 1024));
}


//close
proc_close($process_a);
proc_close($process_b);

このようにすれば、シェル経由をせずともプロセスを複数つないで実行することができる。

注意点 : 2020-03-10 追加

proc_open を使っていてわかったのですが 、php の['pipe'] は、すぐに詰まります。 phpが proc_open のpipe を内部的にどうしてるのかわからないのですが。

pipe 経由で 数MBの出力をバッファリングすると、すぐにエラーになって固まります。ほんとうにこれphpのバグだと思う。

まとめ

proc_open は 標準出力・入力を指定して扱える。

デフォルト指定

$descriptor = [
  STDIN
  STDOUT,
  STDERR,
  ];

リダイレクト

入力をリダイレクト

$descriptor = [
  0 => fopen("/path/to", 'r')
  ];

出力をリダイレクト

$descriptor = [
  1 => fopen("/path/to", 'w')
  ];

エラーをリダイレクト

$descriptor = [
  2 => fopen("/path/to", 'w')
  ];

パイプ

出力をパイプする

$descriptor = [
  1 => ['pipe','w']
  ];
proc_open( $cmd, $descriptor, $pipes);
stream_get_content($pipes[1]);

入力をパイプする。

$descriptor = [
  0 => ['pipe','r']
  ];
proc_open( $cmd, $descriptor, $pipes);
fwrite($pipes[0], "aaaaaa");
fclose($pipes[0]);

一時ファイル php:/temp を使う

一時ファイルをコマンドの入力に渡す。

$fd_in = fopen('php://temp', 'w+');
fwrite($fd_in, "aaaaaa");
fseek($fd, 0);
$descriptor = [
  0 => $fd
  ];
proc_open( $cmd, $descriptor);

出力を一時ファイルに取り出す

$fd_in = fopen('php://temp', 'w+');
$descriptor = [
  1 => $fd
  ];
proc_open( $cmd, $descriptor);
fseek($fd, 0);

プロセスA→ プロセスB

プロセスをパイプでつなぐ

/// プロセスA
$descriptor_a = [
  0 => $fin = fopen('/tmp/out.txt','r'),
  1 => ['pipe','w'],
  2 => STDERR,
];
$process_a = proc_open("cat", $descriptor_a, $pipes_a , '/tmp', []  );

/// プロセスB
$descriptor_b = [
  0 => $pipes_a[1], // Aの結果をBへ
  1 => ['pipe','w'],
  2 => STDERR,
];
$process_b = proc_open("cat", $descriptor_b, $pipes_b , '/tmp', []  );

参考資料

おすすめ Linux(UNIX)のコマンドの実行とパイプの考え方が一番良くわかった本。

自動入力は悪と決めつけて邪悪な対応をするイオンカード。フィッシング・サイト対策にはむしろ自動入力を使いましょう。

イオンカードがまたやばい。

見に行ってみた。

うわああ邪悪すぎる。 input[type=url] にして自動入力をオフにしている。

f:id:takuya_1st:20200303152533p:plain

自動入力は「信用できる」

自動入力のほうがずっと信用できる。イオンカードのためにIDを覚えておくほうが不可能に近い。

IDも使いまわしてはいけない。

「パスワードの使いまわし、ダメ絶対」と一人歩きしているが、正しくは「ID/パスワードのペアの使いまわしは駄目」なんですよね。

ID自動入力を認めないと結局はIDも使いまわしされてしまう。

自動入力するひとはそもそも、自動生成もしてる可能性が高いし。ほんとうに何から何を守ってるんでしょうか。

ブラウザの入力履歴が悪とする、邪悪対応

ブラウザには入力履歴があり、入力履歴から自動入力が生成されるわけですが、履歴の自動保存をすると、間違った入力履歴も覚えてしまうのでトラブルのもとであるということでしょうか。

しかし、ここはインターネットです。インターネットではインターネットの流儀に従ってほしい。

謎リスクベース認証イオンカード

IPとCookieでリスクベース認証と謎なことを称するのであれば、ログイン後に閲覧時に追加パスワードを求めたらいい話である。

ログイン時にパスワードを排してメールアドレスだけで認証すればいい話である。

本当に何にコストを掛けているのやら。

そもそもID/PWを抜かれていたら、リスクベース認証もクソもないんですよ。

自動入力は「フィッシング詐欺」に対してとても有効

自動入力を使うと「ドメイン」が一致しないと、パスワードを入力できない。初心者にドメインを覚えろは不可能に近いので、自動入力を覚えろだと、とても有効である。なので、自動入力を封鎖するサイトは滅びていい

フィッシング対策としてとても有効なのです。初心者に「ドメイン覚えろ」なんて口が裂けても言えない。その代わり、「自動入力を使おう、もしパスワードが自動入力できないならそれは詐欺サイト」と呼びかけられる。

フィッシング詐欺サイトで自動入力が効かない例

これは昨日送られてきたAmazonフィッシング詐欺サイトだけど、ほら自動入力が効かないので、詐欺サイトと気づけるよね?

https://cdn-ak.f.st-hatena.com/images/fotolife/t/takuya_1st/20200307/20200307181306.gif

面倒はモノは使われない。

明細を確認するだけのために、「ワンタイムパスワード」「リスクベース認証」「自動保存入力不可」、どれだけ時間を掛けさせるんですか。無駄である。

しかも自動入力を使わせないのはフィッシング詐欺全盛期のいまは、安全策として最低である。

広告まみれのWEB明細

ログインしても広告まみれのWEB明細確認は、存在する目的を自問してほしいです。

メールアドレスで「認証」をでき、メールアドレスを信用するのであれば、そこあてに明細.pdf を送ってくればいいじゃないか。 PDF閲覧に必要なパスワードをWEBサイトで入手・登録すればいいわけですよ。

OPNSense に ports を入れて htopを入れてみた。

OPNSense に ports を導入

portsを使ってOPNSenseにパッケージを導入してみる

ports をダウンロード

opnsense-code ports tools

ビルド用ツールを用意

pkg install autoconf automake libtool

念の為にソースコードも用意

opnsense-code tools ports src

カレントのバージョンのソースコードをチェックアウトする。

cd /usr/src
git checkout tags/20.1 -f 

バージョンの確認は次のように。

takuya@OPNsense:~ % freebsd-version
11.2--HBSD
takuya@OPNsense:~ % opnsense-version
OPNsense 20.1.1 (amd64/OpenSSL)

試しに htop をインストール

htop のソースコードがあるports ディレクトリに移動して  make install

cd /usr/ports/sysutils/htop
sudo make install 

htop を実行

ビルドが終わったら実行する。

f:id:takuya_1st:20200303000247p:plain
がある

ports 経由のインストール。

これで ports 経由のインストールができた。

容量に注意

ports と ビルド用のツールと、ソースコードをすべてダウンロードしてくるので、ディスク容量を使います。私は何も考えずにlibvirt仮想マシン起動中に、これらをダウンロードして容量足りずにシステムやsshdが機能しなくなり爆死しました。ports関連に5Gくらいは必須でした。

ports といえば

bsd といえば ports ですよね。macos も今でこそ hombrew だけど、昔は macports のほうがよく使われてたと思う。私がmacを使い始めた頃がちょうど brew 誕生だったので乗り換えてしまってたなぁ。

参考資料

OPNSenseゲストのdisk容量をリサイズした

OPNSense めっちゃディスク食う

OpenWRTなら、3GBもあれば十分だったけど。OPNSenseはメモリもディスクも大食らいでした。

こんなことなら libvirt じゃなくて vbox 使えばよかった。後悔はするけど、勇気を持って前に進む。

BSDのコマンドでディスク容量を「オンライン・リサイズ」していきます。

KVM(libvirt)側のゲストのディスク容量を拡大する

libvirtqemu イメージを指定サイズ拡張する。

sudo qemu-img resize /var/lib/libvirt/images/generic.qcow2  +5G

結果がこれになります。10GBに増えています。サイズ5GB で使い切ってて5GB足したので10GBになっています。

takuya@:~$ sudo qemu-img info /var/lib/libvirt/images/generic.qcow2
image: /var/lib/libvirt/images/generic.qcow2
file format: qcow2
virtual size: 10G (10737418240 bytes)
disk size: 5.0G
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: true
    refcount bits: 16
    corrupt: false

OPNSense(FreeBSD) 側でディスク拡張

ディスク拡張は Linux と違うのでちょっと慣れが必要

通常通りログインします。

通常通りログイン

root@OPNsense:~ # 

gpart でディスクを確認します。

root@OPNsense:~ #  gpart list
Geom name: vtbd0
modified: false
state: OK
fwheads: 16
fwsectors: 63
last: 20971479
first: 40
entries: 152
scheme: GPT
Providers:
1. Name: vtbd0p1
   Mediasize: 209715200 (200M)
  (略
2. Name: vtbd0p2
   Mediasize: 524288 (512K)
  (略
3. Name: vtbd0p3
   Mediasize: 8589934592 (8.0G)
  (略
Consumers:
1. Name: vtbd0
   Mediasize: 10737418240 (10G)
   Sectorsize: 512
   Mode: r1w1e3

ここから、virtio のディスクは vtbd0 という名前であるとわかる。 パーティション名は vtbd0p1 / vtbd0p2 / vtbd0p3 であるとわかる。

バイス名からパーミッションを一覧します。

root@OPNsense:~ # gpart show vtbd0
=>      40  10485680  vtbd0  GPT  (10G) [CORRUPT]
        40    409600      1  efi  (200M)
    409640      1024      2  freebsd-boot  (512K)
    410664   8388600      3  freebsd-ufs  (4.0G)
   8799264   1686456         - free -  (823M)

今回は、EFI起動ディスクを採用しているためefi / boot / root と3つのパーティションがあります。

残容量を最新に反映

パーティションを確認しました。しかし、残容量が反映されていません。

パーティションを反映させる。

root@OPNsense:~ # gpart recover vtbd0
vtbd0 recovered

残容量が更新された

更新されて、残量のfree が変化したことを確認した。

root@OPNsense:~ # gpart show vtbd0
=>      40  20971440  vtbd0  GPT  (10G)
        40    409600      1  efi  (200M)
    409640      1024      2  freebsd-boot  (512K)
    410664   8388600      3  freebsd-ufs  (4.0G)
   8799264  12172216         - free -  (5.8G)

パーティション3に容量を割り当て

パーティション3の直後がフリーな空きエリアなので、単純に容量を拡大できる。

root@OPNsense:~ # gpart resize -i 3  -s 8G vtbd0
vtbd0p3 resized

パーティション3なので インデックス -i3 を指定、変更後の容量を -s 8G で指定、対象は virtio vtbd0 を指定した。

もし ufs の後ろにSwapなどがあれば一旦削除する必要がある。LVMみたいに容量割り当てるというより、ディスク容量のパーティションを拡大する感じ。

容量の割当の結果を表示

容量が移動したことを確認。

root@OPNsense:~ # gpart show vtbd0
=>      40  20971440  vtbd0  GPT  (10G)
        40    409600      1  efi  (200M)
    409640      1024      2  freebsd-boot  (512K)
    410664  16777216      3  freebsd-ufs  (8.0G)
  17187880   3783600         - free -  (1.8G)

空き容量が減って、ufs が増えたことがわかる。

パーティションをリサイズ

root@OPNsense:~ # growfs /
Device is mounted read-write; resizing will result in temporary write suspension for /.
It's strongly recommended to make a backup before growing the file system.
OK to grow filesystem on /dev/gpt/rootfs, mounted on /, from 6.0GB to 8.0GB? [yes/no] yes
super-block backups (for fsck_ffs -b #) at:
 12822592, 14104832, 15387072, 16669312

マウント中の / (root) ファイルシステムの拡張をするので / を指定してる

ちなみに、マウント中のルート・パーティションの場合直接デバイス・ファイルを指定することは出来ない。 マウント中のroot ファイルシステムにgrowfs をかけるとパーミッション denied になった。

root@OPNsense:~ # growfs /dev/vtbd0p3
It's strongly recommended to make a backup before growing the file system.
OK to grow filesystem on /dev/vtbd0p3 from 6.0GB to 8.0GB? [yes/no] yes
growfs: /dev/vtbd0p3: Operation not permitted

最大まで拡張するなら

サイズ指定が不要なのでもっと楽。

root@OPNsense:~ # gpart resize -i 3  vtbd0
vtbd0p3 resized
root@OPNsense:~ # growfs /
Device is mounted read-write; resizing will result in temporary write suspension for /.
It's strongly recommended to make a backup before growing the file system.
OK to grow filesystem on /dev/gpt/rootfs, mounted on /, from 8.0GB to 9.8GB? [yes/no] yes
super-block backups (for fsck_ffs -b #) at:
 17951552, 19233792, 20516032

まとめ

gpart で確認して、 growfs で拡張、growfs / でマウント中のrootパーティションを拡張。

vtbd0 は 、vt がvirtio のvt で、bd が block device の略称と思われる。

bsd はやっぱり linux とはだいぶコマンド体系が異なるので、ちょっと面食らうよね。

gnu 系のコマンド入れちゃってもいいんだけどそれだとなんか違う気もするし

参考資料

GLOBIGNORE で一時的に*(ワイルドカード)のglob 展開を止める。

bash / sh を使ってると glob が邪魔な時がある。

シェルスクリプトを書いていると、 * ワイルドカードの展開がじゃまになるときが多々あります。

その都度エスケープ刷ることが多いと思います。

たとえばワイルドカードを受け取ってあとで展開するようなコマンドを作るとき

mkdir sample
touch a.txt
function commandA (){
  GLOBIGNORE=*
   commandB $@
  GLOBIGNORE=''
}
function commandB(){
   echo $@
}


commandA \*.txt

これを実行すると。。。

a.txt

"*.txt" を出力したいが、 途中で echo *.txt になるので展開されてしまう。

このようにコマンドやfunctionで引数を曳き回すときにワイルドカード *\* で展開させたくない。

またワイルドカードエスケープしているときにミスってワイルドカードのファイルを作っちゃったとか

ls -l 
*.*  *aaa*  ## あああ辛い

こうやってゴミファイルを大量に作っちゃうことを防ぎたい。

GLOBIGNORE 変数をいれる。

GLOBIGNORE という変数があり、これを使うと一時的に、 ワイルドカードの展開を止めることができる。

GLOBIGNORE=*

GLOBIGNORE に書いたファイルは マッチしたものから、指定したものを除外します。

これを使うと、* を * のままエスケープなしで渡すことが出来ます。

先程の例を

GLOBIGNOREを使って無視すると・・・

function commandA (){
  GLOBIGNORE=*
   commandB $@
  GLOBIGNORE=''
}
function commandB(){
   echo $@
}

実行すると

commandA \*.txt
*.txt

このように、途中でエスケープしたり、クォートしたりしなくてもワイルドカードを渡せる。楽ができた。便利かもしれない。

関数内で使うと便利

引数を処理してべつの関数に渡すような function を書くときにワイルドカードをそのまま渡したいとき、ワイルドカードをクォートしたりクォートのクォートのクォートとか、エスケープのエスケープとか考えることが減るので楽。

もとに戻すときは

  GLOBIGNORE=''

変数の内容を空にしてあげる。こ後処理を忘れると面倒になる。ワイルドカードが反応しない。glob 展開されないと焦る羽目になる。

bash のマニュアルよると

GLOBIGNORE
A colon-separated list of patterns defining the set of filenames to be ignored 
by pathname expansion. If a filename matched by a pathname expansion pattern 
also matches one of the patterns in GLOBIGNORE, it is removed from the list of matches.

参考資料

間違って /tmp を消してしまったので対処。

/tmp にクソでかいキャッシュを作ってしまった

間違って /tmp に大量のファイルと巨大なファイルを作ってしまったので、消そうとして -mindepth つけ忘れた。

find /tmp -exec rm {} ;

悲劇。 /tmp が消えました。あああ・・・ mindepth は alias でつけたほうがいいですね・・・

手作業で再度作る

sudo mkdir /tmp 
sudo chown root:root /tmp
sudo chmod 1777

/tmp が正常なときのパーミッション

stat で詳細な情報を確認してみた。

takuya@host:~$ sudo stat /tmp
[sudo] password for takuya:
  File: /tmp
  Size: 24576       Blocks: 48         IO Block: 4096   directory
Device: fd01h/64769d    Inode: 915714      Links: 11
Access: (1777/drwxrwxrwt)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2020-02-26 12:34:28.058064062 +0900
Modify: 2020-02-26 12:34:24.034106334 +0900
Change: 2020-02-26 12:34:24.034106334 +0900
 Birth: -

うん。1777 ですね。

関連資料

https://takuya-1st.hatenablog.jp/entry/2016/03/14/180620

OPNSenseをKVMのvirtio で動かしたほうが速かった

OPNSenseをKVM+qemu 上に作成した。

構成としては、OpenWRTを載せた同じマシンに載せた。

virtio

参考資料として、さくらインターネットの記事を見ていたら、virtio について次のような記述があった。

たとえばKVMではストレージドライバとしてvirtioを利用するとトラブルが出るケースがあるようだ。こうした仮想環境上へのインストールについては公式Wikiドキュメントが公開されているので、こちらを事前に参照しておくと良いだろう。

FreeBSDベースのファイアウォールOS「OPNsense」(インストール編) | さくらのナレッジ

ネットワークをvirtio にするのは 19.07 あたりでサポートされていて、今日現在(2020-02-25)の最新バージョンであれば、特に何もせずに認識されました。

ただ、一点注意があるとすれば。nic の名前が通常と異なる。

通常であれば em0 / em1 / em2 となるところが、vtnet0 / vtnet1 / vtnet2 のように、ネットワークの名前が変わりました。

そのためにLAN/WANなどの割当てがすべて設定し直しになる。インストール後に設定変更する際には、名前に注意が必要

f:id:takuya_1st:20200225142702p:plain

速度測定

LAN内部で速度測定をしてみました。 em1 の場合は、〜300Mbps だったが、vtnet1 の場合は 〜700Mbpsくらい出ていた。キャッシュやメモリの設定が影響するとはいえ、ドライバ変更で、速度に大幅に変化があるので、virtio のほうが速いといって差し支えないと思う。

f:id:takuya_1st:20200225142328p:plain

rcloneのバックアップがシンボリックリンクのリンク取得していないことが判明

rclone でgsuite / google drive にバックアップに注意が必要

google ドライブなどいくつかのストレージは、シンボリックリンクをサポートしていないので、シンボリックリンクは取得されない。リンクされたファイルが無視される。

取得されない例

rclone sync /etc/ my-google-drive:/my-etc

シンボリックリンクを辿って取得する

シンボリックリンクそのものが取得できないなら、ファイルを「辿って」取得してしまえばいいのではないかという乱暴な解決策がある。

link をコピーするフラグ

takuya@:~$ rclone help flags | grep links
150:  -L, --copy-links                                 Follow symlinks and copy the pointed to item.
249:      --skip-links                                 Don't warn about skipped symlinks.

ファイルを実体としてコピーする

rclone  --copy-links sync /etc/ my-google-drive:/my-etc

これで、ファイルはシンボリックリンクとしてはコピーされないが、中身はコピーされる。

その他の解決策

そもそも sync / copy を使わない。ちゃんと tar.gz は dump ファイルを取得してバックアップとして転送するなどの解決策が考えられる。

ただし、1つの巨大なファイルを送信するとストレージ・サービス側で拒否される可能性が大きい。

symlink をいれるときの注意

symlink を使うと再帰的なフォルダ構成になる可能性があるので、永遠にsyncが終わらないという事件も起きそう。

少し落ち着いて考える必要がありますね。

シンボリック・リンクのファイルを多く入れているフォルダをrclone したときにはバックアップがないので、なにか手をうつ必要があるのは間違いがない。

2021-11-03

 -l, --links                                        Translate symlinks to/from regular files with a '.rclonelink' extension

link ファイルをリンクファイルとして扱うフラグが追加されているのを発見した。

参考資料

  • rclone help flags

netatalk をアップデートしてmacのタイムマシンを作る

netatalk を更新した

mac のタイムマシンに samba が使えるのは知ってるんだけど、ずっとnetatalk なので引き続き使ってます。いまのところ特に問題ないし、現代のsambaは設定が煩雑すぎて目的を見失って沼に嵌りそうですし。

過去記事

netatalkでLinuxサーバーをNAS TimeCapusleサーバーにする。 - それマグで!

インストール

cd /usr/local/src
curl -LJO 'http://prdownloads.sourceforge.net/netatalk/netatalk-3.1.12.tar.bz2?download'
tar jxvf netatalk-3.1.12.tar.bz2
cd netatalk-3.1.12


sudo apt -y install \
build-essential \
libssl-dev \
libgcrypt*-dev \
libkrb5-dev \
libpam0g-dev \
libwrap0-dev \
libdb-dev \
libtdb-dev \
default-libmysqlclient-dev \
libavahi-client-dev \
libacl1-dev \
libldap2-dev \
libcrack2-dev \
systemtap-sdt-dev \
libdbus-1-dev \
libdbus-glib-1-dev \
libglib2.0-dev \
tracker \
libtracker-sparql*-dev \
libtracker-miner-*-dev 


./configure \
   --with-init-style=debian-systemd \
   --with-libevent=no \
   --with-cnid-tdb-backend=no \
   --with-tdb=no \
   --with-cracklib \
   --enable-krbV-uam \
   --with-pam-confdir=/etc/pam.d \
   --with-dbus-daemon=/usr/bin/dbus-daemon \
   --with-dbus-sysconf-dir=/etc/dbus-1/system.d \
   --with-tracker-pkgconfig-version=2.0


sudo dpkg -r netatalk3.1.11

sudo checkinstall \
   --pkgname=netatalk3.1.12 \
   --pkgversion="1:$(date +%Y%m%d%H%M)" \
   --backup=no \
   --deldoc=yes --fstrans=no --default


sudo systemctl daemon-reload
sudo systemctl status netatalk
sudo systemctl start netatalk
sudo systemctl status netatalk

設定ファイルをリンク作成

etc に持ってきておく

sudo ln -s /usr/local/etc/afp.conf /etc/afp.conf
sudo ln -s /etc/afp.conf /etc/netatlk.conf

afp.conf で有ることを忘れるので netatalk.conf にしておく

afp.conf

[Global]
    uam list = uams_dhx.so uams_dhx2_passwd.so
    mac charset = MAC_JAPANESE
    hostname = acid-afp
    vol preset = default_for_all_volumes
    log file = /var/log/netatalk.log
    #log level = default:maxdebug
    log level = default
    cnid scheme = cdb

    dbus daemon = /usr/bin/dbus-daemon

    mimic model = MacPro
    ;mimic model = RackMac

    dsireadbuf = 120 ; default 12
    dircachesize = 16384

[default_for_all_volumes]
    file perm = 0600
    directory perm = 0700

[Homes]
    basedir regex = /home
    follow symlinks = true
    time machine = no
    spotlight = true
    home name = $u's home(afp)
[My Time Machine Volume]
    path = /home/takuya/.backups/time_capsule/
    time machine = yes
    vol size limit = 450000

systemd のaccounts-daemon がCPU使用率を100%で上がってくるので止めた

ubuntu server の cpu 使用率

ubuntu server を入れてしばらくしていたときに、cpu 使用率をモニタリングしていたら、使用率が定期的にSPIKE してることに気づいた。

cpu 使用率が定期的に上がる

f:id:takuya_1st:20200221090747p:plain
cpu 使用率

4コアのうち1コアを完全に使い切る

一時的であるが accounts-daemonが cpu にピークを作っていることがわかった。

f:id:takuya_1st:20200221091918p:plain

消しちゃえ

accounts-service は、主に GNOMEデスクトップで使うものであるし、パーソナルユースのマシンではあまり役に立たないし.

しかも、Ubuntu CoreのServer版である。 要らない。と判断した

sudo systemctl stop   accounts-daemon
sudo systemctl disable   accounts-daemon
sudo systemctl mask  accounts-daemon

何に使うかは未だによくわからない。

ストップしてから1週間ほどですが、全く影響がない。ホントなんだったんだろう

参考資料

https://unix.stackexchange.com/questions/383138/should-i-disable-accounts-daemon

macOSからlinuxのvirt-managerのkvm+qemu の仮想マシンを管理する

macOSから 仮想マシンを管理したい。

macから仮想マシンを管理したいと思っても、フロントのアプリケーションがこれというものがありません。

virt-managerを 無理やり起動する brew もあるのですがイマイチです。

git にある tap を読み込んだ場合

brew tap jeffreywildman/homebrew-virt-manager
brew install  virt-manager virt-viewer
virt-manager -c 'qemu+ssh://takuya@192.168.1.144/system?socket=/var/run/libvirt/libvirt-sock'

ステータスを見るくらいしか出来ない。

起動はするが、詳細を設定できない。 f:id:takuya_1st:20200220105617p:plain

X11 に頼る。

古代魔術となってしまったOSXX11 を動かすやつを macOSになった今再度動かすことにする。

brew  cask install  xquartz 

再起動してライブラリを反映

reboot 

ssh 経由でXServerを使う。

どこか適当な踏み台となる、Ubuntu Desktop で Xを実行してそこから virt-managerを開ける。

ssh -X 192.168.1.111

リモートセッションのX11virt-manager

リモートワークしましょう。

f:id:takuya_1st:20200220105317p:plain

linux仮想マシンのフロント

詳細設定をGUIで設定することを考えると、ESXi や vCenter が良いのかもしれない。

普段だと ubuntu desktop を用意していてそこに XRDPするのですが、 今回は、dist-upgrade 中に gnome がエラー吐きまくってubuntu Desktopが一切使えなくなったので苦肉の策。

apt searchは正規表現で絞り込む

apt search で grep すると警告が出るんですね。

takuya@:~$ apt search docker | grep cockpit

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

9:cockpit-docker/stable,now 188-1 all [インストール済み]
10:  Cockpit user interface for Docker containers

apt の結果を grep しちゃうと駄目なんですね。昔にaptitude を使ってた癖でgrep しちゃうんですが。grep じゃ駄目なんですね

apt search の引数は正規表現

apt search の引数って apt-cache と同じで「正規表現」がそのまま使えるんですね。

 apt search 'cockpit|docker$'

ということはで、正規表現をsearchに使うと便利です。

パッケージ名に対して正規表現が出来ます。

takuya@:~$ apt search '^cockpit.*docker$'
ソート中... 完了
全文検索... 完了
cockpit-docker/stable,now 188-1 all [インストール済み]
  Cockpit user interface for Docker containers

takuya@:~$

個人的には、正規表現よりワイルドカードのほうが便利なんですが、grep するより簡単ですね。

aptコマンドでインストール済みを検索する

apt の結果をgrep するといつも警告が出る。

takuya@:~$ apt list --installed | grep docker

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

いつもこれどうしたものかとかと悩んでたんですが。ある日偶然タイプミスして解決方法に気づいたのでメモ

apt の引数にワイルドカードがつけられる。

docker のapt を消して snapd に変更しようとしてて、ワイルドカードを使ってる。

apt purge docker*
apt install docker*
apt list docker*

ワイルドカードが使えるんですね。apt の引数には

apt list の引数は ワイルドカードが取れる

ということは、ワイルドカードで検索ができる。

takuya@:~$ apt list --installed *docker*
一覧表示... 完了
cockpit-docker/stable,now 188-1 all [インストール済み]
docker-ce-cli/now 5:19.03.6~3-0~debian-stretch amd64 [インストール済み、ローカル]
docker-ce/now 5:19.03.6~3-0~debian-stretch amd64 [インストール済み、ローカル]
docker-compose/stable,now 1.21.0-3 all [インストール済み]
golang-docker-credential-helpers/stable,now 0.6.1-2 amd64 [インストール済み、自動]
python3-docker/stable,now 3.4.1-4 all [インストール済み、自動]
python3-dockerpty/stable,now 0.4.1-1 all [インストール済み、自動]
python3-dockerpycreds/stable,now 0.3.0-1 all [インストール済み、自動]

シェルの引数展開ではなくapt

シェルのワイルドカード展開かなともおもってエスケープしたり引数をクォートした。ちゃんとワイルドカードで取ってくれるのがわかる

takuya@:~$ apt list --installed \*docker*
takuya@:~$ apt list --installed \*docker\*
takuya@:~$ apt list --installed '*docker*'
一覧表示... 完了
cockpit-docker/stable,now 188-1 all [インストール済み]
docker-ce-cli/now 5:19.03.6~3-0~debian-stretch amd64 [インストール済み、ローカル]
docker-ce/now 5:19.03.6~3-0~debian-stretch amd64 [インストール済み、ローカル]
docker-compose/stable,now 1.21.0-3 all [インストール済み]
golang-docker-credential-helpers/stable,now 0.6.1-2 amd64 [インストール済み、自動]
python3-docker/stable,now 3.4.1-4 all [インストール済み、自動]
python3-dockerpty/stable,now 0.4.1-1 all [インストール済み、自動]
python3-dockerpycreds/stable,now 0.3.0-1 all [インストール済み、自動]

便利です。

インストール済みのパッケージを探したり、まとめて消すときや、関連するパッケージをまとめて探すのがとても便利になった。