I know I believe in nothing but it is my sweet nothing.:2021年08月15日分

2021/08/15(Sun)

[タッパーウェア] xargs(1)実装における非互換性

xargs(1)の-Iオプション、これって Issue6以前は255byte制限だったのですわ、以下引用。

Constructed arguments cannot grow larger than 255 bytes.

そんで 最近(Issue7)になってGNU findutils実装の挙動を正当化すべく

constructed arguments cannot grow larger than an implementation-defined limit greater than or equal to 255 bytes.

と書き換えられたばかり(2018年なんてつい一昨日だろ)なのよね、まぁいまやOpenGroup/Austin Groupという場所はSingle UNIX(TM) SpecどころかOnly GNU/Linux Specだからな。 もうベンダはどこもUNIX(TM)などというコンコルドやスペースシャトルのような埋没費用に関わりたくもないだろうしな。

まぁ結論としてはリンク先の記事の最後の通りGNU findutilsのxargsを使えということ、なぜならPOSIX縛りなら255以上は実装依存で移植性を考えたら使うべきでないから。

ちなみに歴史を紐解くとxargs(1)は PWB UNIX 1.0で導入された、困ったことにUnix Archiveにはソースが見当たらないので マニュアルを読んでみよう。

Constructed args may not grow larger than 255 characters,

ちゅーことで上で引用したIssue6の文章とほぼ一緒ですやね。

うーんソースも読みてえなということで、多分同じものだと思われる V10 UNIXのやつから該当部分を抜粋してみよう。

#define MAXSBUF 255
...
char *
insert(pattern, subst)
char *pattern, *subst;
{
static char buffer[MAXSBUF+1];
int len, ipatlen;
register char *pat;
register char *bufend;
register char *pbuf;

len = strlen(subst);
ipatlen = strlen(INSPAT)-1;
pat = pattern-1;
pbuf = buffer;
bufend = &buffer[MAXSBUF];

while ( *++pat ) {
	if( xindex(pat,INSPAT) == 0 ) {
		if ( pbuf+len >= bufend ) break;
		else {
			strcpy(pbuf, subst);
			pat += ipatlen;
			pbuf += len;
			}
		}
	else {
		*pbuf++ = *pat;
		if (pbuf >= bufend ) break;
		}
	}

if ( ! *pat ) {
	*pbuf = '\0';
	return (buffer);
	}
else {
	sprintf(Errstr, "max arg size with insertion via %s's exceeded\n", INSPAT);
	ermsg(Errstr);
	ERR = TRUE;
	return 0;
	}
}
...

そんんでxargs(1)が*BSDに導入されたのは 4.3BSD-Renoからなんだけど、そもそも当時は-i/-Iオプション無かったのですわ、ということで*BSD(Mac) vs GNUというわけではなく、あくまでPOSIX vs GNUの齟齬だったということですな。

つーか*BSDで最初に実装したのは FreeBSDで、これは2002年とUNIXおじいちゃん的にはつい最近の出来事なんだよね。

ひとつだけ残った疑問なのだが、Issue6からIssue7の間に「larger than」が「greater than or equal」に改められてるので、どっかに

buf[255+1]

でなく

buf[255]

な実装が存在する可能性なんだよな、前述の通り*BSDではないので謎なのである。