basE91で少し効率よくバイナリをテキストに変換

バイナリを利用できない環境でのデータ転送時にUNIX環境では古くは uudecode, uuencode が,日本のパソコン通信では ish などが使われていました.近頃は base64 がよく使われているように感じます.

これらのツールではバイナリをASCIIで表現するためサイズが大きくなってしまいます.でも全てのASCIIを使っていません.

今回見つけたbasE91はASCIIの0x21-0x7Eのうち -, \, ' を除いた91文字を使ってデコードすることで効率よくするもののようです.

早速試してみます.Debianパッケージがないかなと探しましたがありませんでした.

sourceを貰ってきてmakeします.
※hashは「 basE91 – Browse /basE91/0.6.0 at SourceForge.net 」で確認できる.

$ wget http://downloads.sourceforge.net/base91/base91-0.6.0.tar.gz
$ md5sum base91-0.6.0.tar.gz
e227841d900cc463a162bd79775aeb54  base91-0.6.0.tar.gz
$ sha1sum base91-0.6.0.tar.gz
00cfd573ec8b3d0160dbf53e2c7a49b99a1aa720  base91-0.6.0.tar.gz
$ tar tvf base91-0.6.0.tar.gz
-rw-r--r-- 0/0             575 2005-06-25 00:00 base91-0.6.0/AWK/README
-rwxr-xr-x 0/0             727 2006-11-02 05:13 base91-0.6.0/AWK/b91dec.awk
-rw-r--r-- 0/0             932 2006-09-04 03:00 base91-0.6.0/PHP4/README
-rw-r--r-- 0/0            1513 2006-11-02 05:13 base91-0.6.0/PHP4/base91.php
-rw-r--r-- 0/0             149 2006-09-04 03:00 base91-0.6.0/test/Makefile
-rw-r--r-- 0/0            4265 2006-11-02 05:13 base91-0.6.0/test/test.sh
-rw-r--r-- 0/0             332 2006-08-25 17:00 base91-0.6.0/DOS-asm/readme.txt
-rw-r--r-- 0/0            3487 2006-11-02 05:13 base91-0.6.0/DOS-asm/b91enc.asm
-rw-r--r-- 0/0            5034 2006-11-02 05:13 base91-0.6.0/Java/b91cli.java
-rw-r--r-- 0/0            3297 2006-11-02 05:13 base91-0.6.0/Java/basE91.java
-rw-r--r-- 0/0            1526 2006-11-02 05:13 base91-0.6.0/Java/license.txt
-rw-r--r-- 0/0             793 2006-11-02 05:13 base91-0.6.0/Java/readme.txt
-rw-r--r-- 0/0             112 2006-09-04 03:00 base91-0.6.0/Java/manifest.mf
-rwxr-xr-x 0/0             178 2006-11-02 05:13 base91-0.6.0/Java/build_jar.sh
-rw-r--r-- 0/0            7502 2006-11-02 05:13 base91-0.6.0/cli.c
-rw-r--r-- 0/0            5066 2006-11-02 05:13 base91-0.6.0/base91.c
-rw-r--r-- 0/0            1501 2006-11-02 05:13 base91-0.6.0/LICENSE
-rw-r--r-- 0/0             561 2006-11-02 05:13 base91-0.6.0/base91.h
-rw-r--r-- 0/0            2360 2006-11-02 05:13 base91-0.6.0/README
-rw-r--r-- 0/0            1762 2006-11-02 05:13 base91-0.6.0/base91.1
-rw-r--r-- 0/0             903 2006-09-04 03:00 base91-0.6.0/Makefile
-rw-r--r-- 0/0            2330 2006-11-02 05:13 base91-0.6.0/NEWS
$ tar xf base91-0.6.0.tar.gz
$ cd base91-0.6.0
$ make
$ ./base91 -h
Usage: base91 [OPTION]... [FILE]
basE91 encode or decode FILE, or standard input, to standard output.

  -d, --decode          decode data
  -m SIZE               use SIZE bytes of memory for buffers (suffixes b, K, M)
  -o, --output=FILE     write to FILE instead of standard output
  -v, --verbose         verbose mode
  -w, --wrap=COLS       wrap encoded lines after COLS characters (default 76)
  --help                display this help and exit
  --version             output version information and exit

With no FILE, or when FILE is -, read standard input.

encodeしてdecodeしてみます.
当たり前ですが,encode, decodeしてもdiffもhashも同じです.

$ ./base91 ./base91 -o ./base91.base91
$ ./base91 -d ./base91.base91 -o ./base91.tmp
$ diff ./base91 ./base91.tmp
$ sha512sum ./base91
bc903be7c5b694841a9d0303351846f80f4798ad8848e8f298cf2c4818c68a2270b065db495b969503b25cdf672632e1cced18094f935fed47b75718c3c3e976  ./base91
$ ./base91 ./base91 | ./base91 -d | sha512sum
bc903be7c5b694841a9d0303351846f80f4798ad8848e8f298cf2c4818c68a2270b065db495b969503b25cdf672632e1cced18094f935fed47b75718c3c3e976  -

basE91, base64, base32, uudecode で変換してみます.
basE91 が一番小さいですね

$ ls --block-size=1 -s ./base91
16384 ./base91
$ ./base91 ./base91 | wc -c
17340
$ base64 ./base91 | wc -c
19615
$ uuencode ./base91 - | wc -c
20024
$ base32 ./base91 | wc -c
23538

圧縮すると大分小さくなります.圧縮のほうがずっと効きますね.

$ xz -c ./base91 | wc -c
4528
$ xz -c ./base91 | ./base91 | wc -c
5640
$ xz -c ./base91 | base64 | wc -c
6120
$ xz -c ./base91 | uuencode - | wc -c
6260
$ xz -c ./base91 | base32 | wc -c
7344

他のファイルも試してみます./usr/bin 以下のファイルを適当に見繕って比較x5です.

#!/bin/bash

XZ=`mktemp`
for i in `seq 1 5`
do
  CMD=`find /usr/bin -type f | shuf -n 1`
  echo $CMD
  echo -n "raw  "
  stat -c %s $CMD
  xz -9 -c $CMD > $XZ
  echo -n "xz "
  stat -c %s $XZ
  echo -n "xz.uu  "
  uuencode $XZ - | wc -c
  echo -n "xz.base64  "
  base64 $XZ | wc -c
  echo -n "xz.base91  "
  base91 $XZ | wc -c
done
rm $XZ
$ bash ./bin2ascii.bash | column -t
/usr/bin/lxc-snapshot
raw                          27632
xz                           6756
xz.uu                        9328
xz.base64                    9127
xz.base91                    8418
/usr/bin/dh_installtmpfiles
raw                          3263
xz                           1540
xz.uu                        2144
xz.base64                    2084
xz.base91                    1917
/usr/bin/pbmtogo
raw                          10384
xz                           3164
xz.uu                        4380
xz.base64                    4276
xz.base91                    3942
/usr/bin/chartread
raw                          3966528
xz                           772956
xz.uu                        1064980
xz.base64                    1044169
xz.base91                    963047
/usr/bin/spamassassin
raw                          29898
xz                           9608
xz.uu                        13258
xz.base64                    12981
xz.base91                    11971

おまけ?armelでstatic linkなバイナリを作ってみました.Sipeed Lichee Nano で動かないかな?と.

$ git diff HEAD~~ Makefile
diff --git a/Makefile b/Makefile
index 246aede..129acff 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
-CFLAGS = -Wall -W -O2
-LDFLAGS = -s
+CFLAGS = -static -Wall -W -O2
+LDFLAGS = -static -s

-CC = gcc
+CC = arm-linux-gnueabi-gcc
 INSTALL = install
 INSTALL_DATA = $(INSTALL) -m 444
 INSTALL_PROGRAM = $(INSTALL) -m 555

qemu-arm-static では動くのを確認したけど実機では未確認です.

$ file ./base91
./base91: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, BuildID[sha1]=88ec4ccbf69c4bb41640b5de63b6b5373b7e5365, for GNU/Linux 3.2.0, stripped
$ ldd ./base91
        not a dynamic executable
$ echo 😺 | qemu-arm-static ./base91 | pee cat "qemu-arm-static ./base91 -d"
=~m6xHA
😺

以下にバイナリとuuencodeしたものが置いてあります.

blog元のmemo

環境
$ dpkg-query -W gcc-10-arm-linux-gnueabi qemu-user-static gcc coreutils sharutils
coreutils       8.32-3
gcc     4:10.1.0-1
gcc-10-arm-linux-gnueabi        10.2.0-3cross2
qemu-user-static        1:5.0-13
sharutils       1:4.15.2-5
$ lsb_release -dr
Description:    Debian GNU/Linux bullseye/sid
Release:        unstable
$ uname -m
x86_64

鹿児島Linux User Groupの鹿児島Linux勉強会 2020.07(オンライン)に参加

  • 「鹿児島Linux勉強会 2020.07」
    日時
    2020-07-26(sun) 14:00〜17:00
    会場
    Discord
    テキストチャンネル「meetup-202007」,ボイスチャンネル「General」.
    前回まではボイスチャンネルを分けていたけど今の所勉強会のとき以外はボイスチャンネルが使われていない&間違える人が居たのでGeneralのみに.テキストチャンネルは毎回分けて終了後しばらくしたらアーカイブする感じにしています.

参加人数は申込者9人で実際の参加者は7人でした.地域は鹿児島県が3人,その他4人(東京都,静岡県,岐阜県,愛知県x2)オンラインになってからの鹿児島の参加人数が一番多かった気がします.

以下のような話題で盛り上がりました.

  • 「Photon OSを使ってみた話」
  • 「ssh login時の通知を簡単に設定できないか?の相談」
  • 「ArchiveBoxで自分用WebArchive(django版)」
  • 「5月のYoctoLTSの続報」
  • 「ArchLinuxのインストールがうまく行かない相談」
  • 「m3u8のプレイリストからダウンロード」
  • 「Free RADIUSサーバーの構築についての相談」

この中で私の発表は,「ArchiveBoxで自分用WebArchive(django版)」でした.鹿児島Linux勉強会2019.08(オンライン)での発表の続報でした.不具合が減っていろいろと機能も増えていい感じです.リモートで試せるようデモサーバをRaspberry Piで起動して触って貰ったりしました.

次回は08/23(日)の開催予定です.

Raspberry Pi OS/Debian/Ubuntuでの既定のPython切り替え

最近使うPythonアプリはPython3が多くなっています.Python2のEoLが迫っているので正しいのですが,手元の環境では python コマンドは python2 に向いています.python3 コマンドを叩けばいいのですが,これを python3 に向けられないかなと試してみました.

Raspberry Pi OS arm64(busterベース)でのPython確認してみます.python コマンドは python2.7 を呼ぶようになっています.

$ python --version
Python 2.7.16
$ ls -l `which python`
lrwxrwxrwx 1 root root 7  3月  5  2019 /usr/bin/python -> python2
$ ls -l `which python2`
lrwxrwxrwx 1 root root 9  3月  5  2019 /usr/bin/python2 -> python2.7
$ ls -l `which python3`
lrwxrwxrwx 1 root root 9  3月 26  2019 /usr/bin/python3 -> python3.7

update-alternatives で管理されてるのかな?と思いましたが設定がなさそうです.

$ update-alternatives --get-selections|grep -i ^python

update-alternatives を手動で設定してみます.
これで python コマンドが python3.7 を呼ぶようになりました.

$ sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
update-alternatives: /usr/bin/python (python) を提供するために自動モードで /usr/bin/python2.7 を使います
$ sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.7 2
update-alternatives: /usr/bin/python (python) を提供するために自動モードで /usr/bin/python3.7 を使います
$ ls -l `which python`
lrwxrwxrwx 1 root root 24  7月 28 08:47 /usr/bin/python -> /etc/alternatives/python
$ python --version
Python 3.7.3
$ update-alternatives --query python
Name: python
Link: /usr/bin/python
Status: auto
Best: /usr/bin/python3.7
Value: /usr/bin/python3.7

Alternative: /usr/bin/python2.7
Priority: 1

Alternative: /usr/bin/python3.7
Priority: 2

切り替えたいときはこんな感じで選択肢なおせばok.

$ sudo update-alternatives --config python
alternative python (/usr/bin/python を提供) には 2 個の選択肢があります。

  選択肢    パス              優先度  状態
------------------------------------------------------------
* 0            /usr/bin/python3.7   2         自動モード
  1            /usr/bin/python2.7   1         手動モード
  2            /usr/bin/python3.7   2         手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください:

Debian asid amd64, Ubuntu 20.04 LTS amd64 でも設定してみました.

Debian sid amd64
$ update-alternatives --query python
Name: python
Link: /usr/bin/python
Status: auto
Best: /usr/bin/python3.8
Value: /usr/bin/python3.8

Alternative: /usr/bin/python2.7
Priority: 1

Alternative: /usr/bin/python3.7
Priority: 2

Alternative: /usr/bin/python3.8
Priority: 3
Ubuntu 20,04 LTS amd64
$ update-alternatives --query python
Name: python
Link: /usr/bin/python
Status: auto
Best: /usr/bin/python3.8
Value: /usr/bin/python3.8

Alternative: /usr/bin/python2.7
Priority: 1

Alternative: /usr/bin/python3.5
Priority: 2

Alternative: /usr/bin/python3.8
Priority: 3

てことで python コマンドが python3 になりました.しかしシステムワイドな設定なのでシステムのプログラムなどで問題が出るかもしれないですね.
問題が起こったらpython2に戻しましょう.

Rasoberry Pi OS amd64
$ dpkg-query -W python python3
python  2.7.16-1
python3 3.7.3-1
$ lsb_release -dr
Description:    Debian GNU/Linux 10 (buster)
Release:        10
$ uname -m
aarch64
$ cat /proc/device-tree/model&&echo
Raspberry Pi 3 Model B Rev 1.2
Debian sid amd64
$ dpkg-query -W python python3 python3.7
python  2.7.17-2
python3 3.8.2-3
python3.7       3.7.7-1+b1
$ lsb_release -dr
Description:    Debian GNU/Linux bullseye/sid
Release:        unstable
$ uname -m
x86_64
Ubuntu 20.04 LTS amd64
$ dpkg-query -W python python3 python3.7
python  2.7.17-1
python3 3.8.2-0ubuntu2
python3.7
$ lsb_release -dr
Description:    Ubuntu 20.04.1 LTS
Release:        20.04
$ uname -m
x86_64

Sipeed Lichee Nanoでhello world

2020-07-23低レベル勉強会に参加しました.Zoom.usでの開催でした.

内容はLinux名刺的なものを開発しようという内容で,リファレンスとしてSDカードサイズの小さなLinuxの動作するarmコンピュータのSipeed Lichee Nanoを使いました.

欲しい場合は1000円ちょいくらいからで入手できそうです.

Lichee Nanoを持っていない人はリモートで触れるようにしてあったので持っていない私も楽しめました.

このリモート開発の仕組みはLichee NanoとRaspberry PiをUSB経由のUARTで接続し,Raspberry PiでGNU screenを起動,ssh経由でGNU screenに繋いで操作という感じです.
GNU screenをGotty等にするとウェブブラウザで参加できてちょっと便利かもと思ったりも.(GoTTYは開発止まってるように見えるから別のもののほうがいいかもしれない)

Lichee Nanoで何かを動かしたい.armだけどarmhf動くのかな?とりあえずなにか転送して動かしてみようと.

とりあえずDebianのarmhfバイナリをuuencodeしてコピペで転送してみます.これが動けばDebianのパッケージ群が利用できるかもだけど…….

まずは簡単そうなfortuneを試します.

Debian sidでfortune-modパッケージのarmhfバイナリパッケージをダウンロードして展開(add archtecture armhfしてある環境)
$ apt download -t armhf fortune-mod
$ unar fortune-mod_1.99.1-7+b1_armhf.deb
$ cd fortune-mod_1.99.1-7+b1_armhf
$ tar xf data.tar.xz
$ cd usr/games

Lichee Nanoはserialで接続されていて,Internetには繋がっていないのでバイナリファイルの転送にはuudecode/uuencodeを使いました.久々です.
手元のGNU sharutils 4.15.2のuudecodeにはbase64を使う -m, --base64 があるので良さそう.と思ったけどLichee Nanoの方はbusyboxのもので非対応でした.

ローカル端末で圧縮してuuencodeしてクリップボードへ
$ gzip -c fortune | uuencode fortune.gz > fortune.gz.uu
$ cat fortune.gz.uu | xclip
リモートで伸張して解凍
# cat | uudecode    #ここでクリップボードから貼り付け
# zcat fortune.gz > fortune
# rm fortune.gz

そして…​…​

# ./fortune
-sh: ./fortune: not found
# ldd ./fortune
checking sub-depends for 'not found'
checking sub-depends for '/lib/libc.so.6'
/lib/ld-linux.so.3 (0xb6fa0000)
librecode.so.0 => not found (0x00000000)
libc.so.6 => /lib/libc.so.6 (0x00000000)
/lib/ld-linux.so.3 => /lib/ld-linux.so.3 (0x00000000)

これを動かすのはダイナミックリンクされているものを用意してあげないといけないのでストレージの容量的に難しいですね.

ここではgzipで圧縮しましたが,Lichee Nanoのbusyboxにxzがありました.gzipよりxzにしたほうが小さくなりますね.試してみるとこんな感じでした.$ xz -c fortune | uuencode fortune.xz > fortune.xz.uu

サイズ比較
-rw-r--r-- 1 matoken matoken 22368 Jul 23 15:11 fortune #元ファイル
-rw-r--r-- 1 matoken matoken 30844 Jul 23 14:58 fortune.uu #uudecode
-rw-r--r-- 1 matoken matoken 14975 Jul 23 15:08 fortune.gz.uu #zip + uudecode
-rw-r--r-- 1 matoken matoken 13047 Jul 23 15:47 fortune.xz.uu #xz + uudecode

そういえばあまり有名ではないですがbasE91なんてものもあります.base64よりサイズが小さくなりますが導入からやらないといけないのでちょっと面倒.

Hello worldを試してみます.適当にプログラムを用意してスタティックリンクでコンパイルしてみます.

$ cat hello.c
#include <stdio.h>
int
main(void)
{
    printf("Hello, world!\n");
    return 0;
}
$ gcc -static ./hello.c
$ ./a.out
Hello, world!
$ ls -l a.out
-rwxr-xr-x 1 pi pi 571120 7月 23 16:18 a.out

でかい…​…​

とりあえずでかいのはおいといてこれだとarm64なので動くはずがない.ということでクロスコンパイル環境を用意します.

今回試したホストはDebian sid amd64/Ubuntu 20.04 LTS arm64/Raspberry Pi OS arm64です.いずれも同じ手順でOKでした.

crossbuild-essential-<arch> パッケージで各種アーキテクチャの環境が導入できるようです.

$ apt-cache search crossbuild-essential-
crossbuild-essential-amd64 - Informational list of cross-build-essential packages
crossbuild-essential-arm64 - Informational list of cross-build-essential packages
crossbuild-essential-armel - Informational list of cross-build-essential packages
crossbuild-essential-armhf - Informational list of cross-build-essential packages
crossbuild-essential-i386 - Informational list of cross-build-essential packages
crossbuild-essential-powerpc - Informational list of cross-build-essential packages
crossbuild-essential-ppc64el - Informational list of cross-build-essential packages
crossbuild-essential-s390x - Informational list of cross-build-essential packages
crossbuild-essential-mips - Informational list of cross-build-essential packages
crossbuild-essential-mips64 - Informational list of cross-build-essential packages
crossbuild-essential-mips64el - Informational list of cross-build-essential packages
crossbuild-essential-mips64r6 - Informational list of cross-build-essential packages
crossbuild-essential-mips64r6el - Informational list of cross-build-essential packages
crossbuild-essential-mipsel - Informational list of cross-build-essential packages
crossbuild-essential-mipsr6 - Informational list of cross-build-essential packages
crossbuild-essential-mipsr6el - Informational list of cross-build-essential packages

沢山あります.今回はarmlf/armhfの crossbuild-essential-armel, crossbuild-essential-armhf を導入しました.

$ sudo apt install crossbuild-essential-armel crossbuild-essential-armhf

gccだけでいい場合はarmlfは gcc-arm-linux-gnueabi,armhfは gcc-arm-linux-gnueabihf だけでOKです.

まずは arm-linux-gnueabihf-gcc を使ってarmhfのバイナリを作ります.

$ /usr/bin/arm-linux-gnueabihf-gcc -static ./hello.c
$ strip a.out
$ xz -c a.out | uuencode a.out.xz > a.out.xz.uu

armhfは駄目そうです.

# cat | uudecode
^d
# xzcat ./a.out.xz > ./a.out
# chmod +x ./a.out
# ./a.out
Segmentation fault

次は gcc-arm-linux-gnueabi でarmlfのバイナリを作って試すと動きました.

$ /usr/bin/arm-linux-gnueabi-gcc -static ./hello.c
$ strip a.out
$ xz -c a.out | uuencode a.out.xz > a.out.xz.uu
# cat | uudecode
^d
# xzcat ./a.out.xz > ./a.out
# chmod +x ./a.out
# ./a.out
Hello, world!
# /usr/bin/time -f "%M KB" ./a.out
Hello, world!
2144 KB

この辺りで今回は時間切れ.次回の同じような感じになりそうです.興味のある方は以下のページから.

とりあえずarmelのバイナリが動くようなのがわかったので面白そうな小さなプログラムを試そうかなと思っています.cowsayとか好きなんだけどこれはPerlなので容量的に難しそう.とりあえずfortuneあたりかな?

以前PQI Air PenでやったようにSD cardを用意してそこにDebian armlf環境を展開してchrootとかもできそうです.

rsync 3.2.0の新機能を少し試す

ファイル同期にとても便利なrsyncの3.2.0がリリースされました.

バグフィクスや,いくつかの新機能が入ったようなので少し試してみました.

※1. この記事投稿時には 3.2.2 が出ています.
※2. 鹿児島Linux勉強会 2020.06で発表したものと同じ内容です.

導入例

Debian sid amd64 & Ubuntu 20.04 LTS amd64

$ sudo apt build-dep rsync
$ sudo apt install libxxhash-dev libzstd-dev liblz4-dev
$ wget -c \
https://download.samba.org/pub/rsync/rsync-3.2.0.tar.gz \
https://download.samba.org/pub/rsync/rsync-3.2.0.tar.gz.asc \
https://opencoder.net/WayneDavison.key
$ gpg2 --import ./WayneDavison.key
$ gpg2 --verify ./rsync-3.2.0.tar.gz.asc
$ tar tvzf ./rsync-3.2.0.tar.gz
$ tar xzf ./rsync-3.2.0.tar.gz
$ cd rsync-3.2.0
$ ./configure --help
$ ./configure
$ make
$ ./rsync --version
rsync  version 3.2.0  protocol version 31
Copyright (C) 1996-2020 by Andrew Tridgell, Wayne Davison, and others.
Web site: http://rsync.samba.org/
Capabilities:
    64-bit files, 64-bit inums, 64-bit timestamps, 64-bit long ints,
    socketpairs, hardlinks, symlinks, IPv6, batchfiles, inplace, append,
    ACLs, xattrs, iconv, symtimes, prealloc, SIMD
Checksum list:
    xxh64 (xxhash) md5 md4 none
Compress list:
    zstd lz4 zlibx zlib none

rsync comes with ABSOLUTELY NO WARRANTY.  This is free software, and you
are welcome to redistribute it under certain conditions.  See the GNU
General Public Licence for details.
Note
gpg鍵は次から入手できます.rsync download

Raspberri Pi OS amd64

Raspberry Pi OS arm64の場合 libzstd-dev のバージョンが 1.3.8+dfsg-3 と少し古くbuildに失敗します. ./configure --disable-zstd としてzstdを無効にするか,sourceから zstd 1.4.5 を導入することでbuild出来ました.

$ make
  :
token.c: In function ‘init_compression_level’:
token.c:73:40: warning: implicit declaration of function ‘ZSTD_minCLevel’; did you mean ‘ZSTD_maxCLevel’? [-Wimplicit-function-declaration]
   min_level = skip_compression_level = ZSTD_minCLevel();
                                        ^~~~~~~~~~~~~~
                                        ZSTD_maxCLevel
token.c: In function ‘send_zstd_token’:
token.c:685:2: error: unknown type name ‘ZSTD_EndDirective’; did you mean ‘ZSTD_DDict’?
  ZSTD_EndDirective flush = ZSTD_e_continue;
  ^~~~~~~~~~~~~~~~~
  ZSTD_DDict
token.c:685:28: error: ‘ZSTD_e_continue’ undeclared (first use in this function)
  ZSTD_EndDirective flush = ZSTD_e_continue;
                            ^~~~~~~~~~~~~~~
token.c:685:28: note: each undeclared identifier is reported only once for each function it appears in
token.c:701:3: warning: implicit declaration of function ‘ZSTD_CCtx_setParameter’ [-Wimplicit-function-declaration]
   ZSTD_CCtx_setParameter(zstd_cctx, ZSTD_c_compressionLevel, do_compression_level);
   ^~~~~~~~~~~~~~~~~~~~~~
token.c:701:37: error: ‘ZSTD_c_compressionLevel’ undeclared (first use in this function); did you mean ‘skip_compression_level’?
   ZSTD_CCtx_setParameter(zstd_cctx, ZSTD_c_compressionLevel, do_compression_level);
                                     ^~~~~~~~~~~~~~~~~~~~~~~
                                     skip_compression_level
token.c:751:13: error: ‘ZSTD_e_flush’ undeclared (first use in this function); did you mean ‘ZSTD_DCtx_s’?
     flush = ZSTD_e_flush;
             ^~~~~~~~~~~~
             ZSTD_DCtx_s
token.c:753:8: warning: implicit declaration of function ‘ZSTD_compressStream2’; did you mean ‘ZSTD_compressStream’? [-Wimplicit-function-declaration]
    r = ZSTD_compressStream2(zstd_cctx, &zstd_out_buff, &zstd_in_buff, flush);
        ^~~~~~~~~~~~~~~~~~~~
        ZSTD_compressStream
$ cd ..
$ sudo apt remove libzstd-dev
$ wget https://github.com/facebook/zstd/releases/download/v1.4.5/zstd-1.4.5.tar.gz \
https://github.com/facebook/zstd/releases/download/v1.4.5/zstd-1.4.5.tar.gz.sha256
$ sha256sum -c ./zstd-1.4.5.tar.gz.sha256
$ tar tvf ./zstd-1.4.5.tar.gz | lv
$ tar xf ./zstd-1.4.5.tar.gz
$ cd zstd-1.4.5
$ make
$ sudo make install
$ cd ../rsync-3.2.0
$ ./configure && make

Debian sid amd64

Debian sid amd64 環境にはすでに降ってきているのでパッケージから導入するだけでOKです.

$ sudo apt install rsync
$ rsync --version
rsync  version 3.2.0  protocol version 31
Copyright (C) 1996-2020 by Andrew Tridgell, Wayne Davison, and others.
Web site: http://rsync.samba.org/
Capabilities:
    64-bit files, 64-bit inums, 64-bit timestamps, 64-bit long ints,
    socketpairs, hardlinks, symlinks, IPv6, batchfiles, inplace, append,
    ACLs, xattrs, iconv, symtimes, prealloc, SIMD
Checksum list:
    xxh64 (xxhash) md5 md4 none
Compress list:
    zstd lz4 zlibx zlib none

rsync comes with ABSOLUTELY NO WARRANTY.  This is free software, and you
are welcome to redistribute it under certain conditions.  See the GNU
General Public Licence for details.
$ dpkg-query -W rsync
rsync   3.2.0-1

ってことで試せるようになりました.NEWSを見てみます.

BUG FIX

Avoid a hang when an overabundance of messages clogs up all the I/O buffers.

このバグ修正がちょっと気になります.fat32の制限に引っかかったときに帰ってこない問題もこれで解決してるかも?未確認.

ENHANCEMENTS

–checksum-choice=STR, –cc=STR

チェックサム形式を選べるようになったようです.現在選択できるのは xxh64/md5/md4 の3種類 or none or auto(既定値)

man(1)より
              o      auto (the default)
              o      xxh64 (aka xxhash)
              o      md5
              o      md4
              o      none

--version にも出力されます.

$ rsync --version | grep Checksum -A1
Checksum list:
    xxh64 (xxhash) md5 md4 none

configure option に --disable-xxhash がありました.

  --disable-xxhash        disable xxhash checksums

環境変数 RSYNC_CHECKSUM_LIST でも指定できます.オプション --checksum-choice がある場合はオプションのほうが優先なようです.

ちなみに --checksum-choice オプションに対応していない 3.1.3 に対して xxh64 を向けて叩いてみると以下のようなエラーになりました.(md4, md5 はok)

$ rsync --checksum-choice=xxh64 -avc ./* user@remote:/tmp/
unknown checksum name: xxh64
rsync error: requested action not supported (code 4) at checksum.c(73) [server=3.1.3]
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(235) [sender=3.2.0]

時間がどのくらい変わるかちょうど転がっていたkernel source(小さいファイルが沢山)で試してみました.はじめ普通に同期した後,キャッシュクリアして md4, md5, xxh64 で試してみました.思ったより差が出ない感じ?

md4
$ find ./linux-5.6 | wc -l
82114
$ du -ms ./linux-5.6
1310    ./linux-5.6
$ rsync --checksum-choice=auto -ac ./linux-5.6 /tmp/
$ sync ; echo 3 | sudo tee /proc/sys/vm/drop_caches ; time rsync --checksum-choice=md4 -ac ./linux-5.6 /tmp/
3

real    0m52.393s
user    0m5.051s
sys     0m12.246s
md5
$ sync ; echo 3 | sudo tee /proc/sys/vm/drop_caches ; time rsync --checksum-choice=md5 -ac ./linux-5.6 /tmp/
3

real    0m57.716s
user    0m6.976s
sys     0m13.486s
xxh64
$ sync ; echo 3 | sudo tee /proc/sys/vm/drop_caches ; time rsync --checksum-choice=xxh64 -ac ./linux-5.6 /tmp/
3

real    1m5.520s
user    0m2.507s
sys     0m13.625s

大きめのファイルでも試してみました.4GB程のisoファイル1つです.md4, md5 はあまり代わりませんが,xxh64 はかなり高速ですね.

md4
$ ls -s ./Parrot-security-4.9.1_x64.iso*
3909164 ./Parrot-security-4.9.1_x64.iso  3909164 ./Parrot-security-4.9.1_x64.iso2
$ sync ; echo 3 | sudo tee /proc/sys/vm/drop_caches ; time rsync --checksum-choice=md4 -ac ./Parrot-security-4.9.1_x64.iso ./Parrot-security-4.9.1_x
64.iso2
3

real    0m23.276s
user    0m10.601s
sys     0m4.387s
md5
$ sync ; echo 3 | sudo tee /proc/sys/vm/drop_caches ; time rsync --checksum-choice=md5 -ac ./Parrot-security-4.9.1_x64.iso ./Parrot-security-4.9.1_x64.iso2
3

real    0m28.150s
user    0m16.945s
sys     0m4.399s
xxh64
$ sync ; echo 3 | sudo tee /proc/sys/vm/drop_caches ; time rsync --checksum-choice=xxh64 -ac ./Parrot-security-4.9.1_x64.iso ./Parrot-security-4.9.1_x64.iso2
3

real    0m12.767s
user    0m1.375s
sys     0m4.060s

この辺の速度は環境により大分変わると思うので参考程度に.

–compress-choice=STR, –zc=STR

--compress オプション利用時の圧縮形式を指定できるようです.

圧縮形式はrsync 3.2.0 同士では zlibx 形式が zlib 形式よりも優先されるようです.
選択できるオプションは zstd, lz4, zlibx, zlib, none のようです.

man(1)より
              o      zstd
              o      lz4
              o      zlibx
              o      zlib
              o      none

rsync --version でも確認できます.

$ rsync --version | grep Compress -A1
Compress list:
    zstd lz4 zlibx zlib none

configure oprion に --disable-zstd, --disable-lz4 があります.

  --disable-zstd          disable zstd compression
  --disable-lz4           disable LZ4 compression

環境変数 RSYNC_COMPRESS_LIST でも指定できるようです.

未対応の 3.1.3 に対して指定すると unknown option と言われます.

$ time rsync --compress-choice=zstd --compress -a ./hoge mk@x201i.local:/tmp/
rsync: on remote machine: --compress-choice=zstd: unknown option
rsync error: syntax or usage error (code 1) at main.c(1596) [server=3.1.3]
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(235) [sender=3.2.0]

こちらも簡単にベンチを.でもWi-Fi環境だし参考程度に.

zstd
$ ssh user@remote rm -rf ~/tmp/linux-5.6; echo 3 | sudo tee /proc/sys/vm/drop_caches; time rsync --compress-choice=zstd --compress -a --rsync-path=~/src/rsync-3.2.0/rsync ~/src/linux-5.6 user@remote:~/tmp/
3

real    4m38.921s
user    0m24.463s
sys     0m7.182s
lz4
$ ssh user@remote rm -rf ~user/tmp/linux-5.6; echo 3 | sudo tee /proc/sys/vm/drop_caches; time rsync --compress-choice=lz4 --compress -a --rsync-path=~/src/rsync-3.2.0/rsync ~/src/linux-5.6 user@remote:~/tmp/
3

real    9m28.829s
user    0m4.878s
sys     0m6.177s
zlibx
$ ssh user@remote rm -rf ~user/tmp/linux-5.6; echo 3 | sudo tee /proc/sys/vm/drop_caches; time rsync --compress-choice=zlibx --compress -a --rsync-path=~/src/rsync-3.2.0/rsync ~/src/linux-5.6 user@remote:~/tmp/
3

real    5m21.702s
user    0m46.740s
sys     0m6.541s
zlib
$ ssh user@remote rm -rf ~user/tmp/linux-5.6; echo 3 | sudo tee /proc/sys/vm/drop_caches; time rsync --compress-choice=zlib --compress -a --rsync-path=~/src/rsync-3.2.0/rsync ~/src/linux-5.6 user@remote:~/tmp/
3

real    5m28.722s
user    0m45.861s
sys     0m6.381s
none
$ ssh user@remote rm -rf ~user/tmp/linux-5.6; echo 3 | sudo tee /proc/sys/vm/drop_caches; time rsync --compress-choice=none -a --rsync-path=~/src/rsync-3.2.0/rsync ~/src/linux-5.6 user@remote:~/tmp/
3

real    22m56.712s
user    0m1.848s
sys     0m7.323s

–debug=NSTR

チェックサムと圧縮の詳細を表示するオプションのようです.どのアルゴリズムを利用しているのかが確認できます.

–debug=NSTR を付けたときのの実行結果例
Client negotiated checksum: xxh64
Client compress: zstd (level 3)

–debug=OPTS, -M—​debug=OPTS

--debug=OPTS を使うとリモートのrsyncにデバッグオプションを送らなくなるようです.これによりクライアント側とサーバ側で異なるデバッグレベルを指定できるようになったそうです.
リモート側にオプションを送る場合には -M—​debug=OPTS

SIGINFO & SIGVTALRM

rsyncプロセスに SIGINFO & SIGVTALRM シグナルを送信することでステータスを表示できるようになったようです.Linuxは SIGINFO に対応していないので, SIGVTALRM を試しました.

rsyncを実行している状態で SIGVTALRM を送信
$ pkill -SIGVTALRM rsync
rsyncがステータスを表示
linux-5.6/arch/sparc/lib/lshrdi3.S
    114,384,392  81%  931.12kB/s    0:01:59 (xfr#21058, ir-chk=1030/23451)

–copy-as=USER[:GROUP]

指定ユーザ/グループ権限でファイルをコピーするようです.

コピー元に3ユーザのファイル
$ ls -Al /tmp/rsync-test/
total 0
-rw-r--r-- 1 matoken  matoken  0 Jun 25 18:50 matokenfile
-rw-r--r-- 1 root     root     0 Jun 25 18:51 root
-rw-r--r-- 1 www-data www-data 0 Jun 25 18:51 www-data
普通にコピーするとユーザが引き継がれる
$ sudo ./rsync -a /tmp/rsync-test/ /tmp/rsync-test2
$ ls -lA /tmp/rsync-test2
total 0
-rw-r--r-- 1 matoken  matoken  0 Jun 25 18:50 matokenfile
-rw-r--r-- 1 root     root     0 Jun 25 18:51 root
-rw-r--r-- 1 www-data www-data 0 Jun 25 18:51 www-data
--copy-as=matoken を指定するとすべてmatokenになる
$ sudo \rm -rf /tmp/rsync-test2
$ sudo ./rsync --copy-as=matoken -a /tmp/rsync-test/ /tmp/rsync-test2
$ ls -lA /tmp/rsync-test2
total 0
-rw-r--r-- 1 matoken matoken 0 Jun 25 18:50 matokenfile
-rw-r--r-- 1 matoken matoken 0 Jun 25 18:51 root
-rw-r--r-- 1 matoken matoken 0 Jun 25 18:51 www-data

-V

--version の短いオプションとして -V が入りました.

$ ./rsync --help|grep -- -V
--version, -V            print the version + other info and exit
$ ./rsync --help|grep \-V
grep (GNU grep) 3.4
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Mike Haertel and others; see
<https://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>.

–ipv4, -4 / –ipv6, -6

ipv4, ipv6 を指定したいときに rsh='ssh -4' とするより便利な --ipv4, -4, --ipv6, -6 オプションが入りました.

ipv4しかない環境で -6 を指定して失敗する
$ rsync -avc6 ./ user@remote:/tmp/
ssh: Could not resolve hostname remote: Name or service not known
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: unexplained error (code 255) at io.c(235) [sender=3.2.1]

awesome wmでの壁紙変更設定を変更(crontabからDISPLAY番号取得)

awesome wm環境での壁紙自動変更にcrontab経由で feh コマンドを利用しています.

30分ごとに~/Pictures/wp/以下のファイルをダンダムに設定
*/30 * * * *    DISPLAY=:0 feh --bg-scale "$(find ~/Pictures/wp/ -type f | shuf -n 1)"

このときXのディスプレイ番号を固定で書いているのですがディスプレイ番号が変わることもあってその時エラーになってしまいます.
ウィンドウマネージャを変更したときもよくなさそう.

ということでcronからユーザのawesome wmのディスプレイ番号を探すようにしてみました.

まずは対象ユーザのawesome wmのプロセス番号を調べます.

$ pgrep -u $(id -u) awesome
2932

/proc/$PID/environ からDISPLAYを探します.

$ cat /proc/2932/environ 2> /dev/null | tr '
$ cat /proc/2932/environ 2> /dev/null | tr '\0' '\n' | grep ^DISPLAY=:
DISPLAY=:1
' '\n' | grep ^DISPLAY=: DISPLAY=:1

カレントユーザのawesome wmのディスプレイ番号が :1 なのが解りました :)

これを組み合わせてこのようにしてみました.これでディスプレイ番号が変わっても大丈夫で,awesome以外のウィンドウマネージャを使ったときには何もしないはず( xargs --no-run-if-empty )です.
同じユーザでawesomeを複数起動した場合は先に起動した方しか反映されないはずですが,あまりそういったことはしないと思うので大丈夫かなと.

*/30 * * * *    cat /proc/$(pgrep -u $(id -u) awesome)/environ 2> /dev/null | tr '
*/30 * * * *    cat /proc/$(pgrep -u $(id -u) awesome)/environ 2> /dev/null | tr '\0' '\n' | grep ^DISPLAY=: | xargs --no-run-if-empty -I{} sh -c '{} feh --bg-scale "$(find ~/Pictures/wp/ -type f | shuf -n 1)"'
' '\n' | grep ^DISPLAY=: | xargs --no-run-if-empty -I{} sh -c '{} feh --bg-scale "$(find ~/Pictures/wp/ -type f | shuf -n 1)"'

2020-07-17 ADD
fehに -z, --randomize と言うオプションがありました.これを使うとコマンドが2つ減って少しわかりやすく……あまり変わらないか.

*/30 * * * *    cat /proc/$(pgrep -u $(id -u) awesome)/environ 2> /dev/null | tr '
*/30 * * * *    cat /proc/$(pgrep -u $(id -u) awesome)/environ 2> /dev/null | tr '\0' '\n' | grep ^DISPLAY=: | xargs --no-run-if-empty -I{} {} feh --bg-scale -z ~/Pictures/wp/
' '\n' | grep ^DISPLAY=: | xargs --no-run-if-empty -I{} {} feh --bg-scale -z ~/Pictures/wp/
環境
$ dpkg-query -W awesome feh procps findutils grep
awesome 4.3-4
feh     3.4.1-1
findutils       4.7.0-1
grep    3.4-1
procps  2:3.3.16-5
$ lsb_release -dr
Description:    Debian GNU/Linux bullseye/sid
Release:        unstable
$ uname -m
x86_64

Speaker Deckのスライドが全て非公開になって困る

Speaker Deckというスライド共有サービスがあります.日本ではSlideShareの次くらいによく使われていそうなサービスです.ここでトラブルがあったので健忘録としてメモしておきます.

このサービスにスライドを登録しようとアップロードしたところ変換に失敗してしまいます.スライドのデータが悪いのかな?と他のものも試すとやはり駄目です.
よく見ると5月以降に登録したスライドはアクセスが0です.なにかおかしい.

ログアウトした状態で見るとスライドが1つも見えなくなってしまっています.

speakerdeck 20200625 07:06:04 766282.resized

既存のスライドを公開(publish)し直しても公開されません.

全てのスライドが非公開になっている,ログインしたら見えるけど公開できない,新しいスライドの登録は失敗する……という状態です.

DMCAとか著作権違反とかが報告されてロックされていそうな感じがします(心当たりはないけど他のサービスもそれでBANされた前科あり).メールを探しますが特にそれらしいものは見当たりません.

ちょっと自分ではどうしようもなさそうだとSpeaker Deckの「Feedback」リンクからメールで問い合わせてみました.しかし反応がありません.
ダメ元でTwitterのSpeaker Deckアカウントである@speakerdeckにmentionを投げてみると数時間で復旧していました.

スライドはちゃんと公開され,新しいスライドのアップロードも出来ました.ということでよくわかりませんがシステムの不具合だったのかな?

やっぱり人任せにするのは怖いですね.自分でコントロールできるところでもまとめておこうと思います.