Lambdaカクテル

京都在住Webエンジニアの日記です

Invite link for Scalaわいわいランド

LinuxディストリビューションごとのTARがデフォルトで吐くフォーマットを調べた

先日、TARにはpaxフォーマットがあるからこれを使おうという記事を書いた:

blog.3qe.us

ところで、自分のマシンではGNU TARが入っていて、デフォルトでpaxを使う設定になっていた(これはコンパイルタイミングで設定される)。自分はopenSuSE Tumbleweedを利用しているが、他のディストリビューションではどうなっているのだろう?そもそも、GNU TARがどのフォーマットをデフォルトで吐くかは決まってないってみんな知ってた?

The default format for GNU tar is defined at compilation time.

GNU tar 1.35: 8 Controlling the Archive Format

わざわざディストリビューションをインストールしなくても、実際に欲しいのは各ディストリビューションにおける(GNU) TARの実行結果である。そしてこれはdockerを実行すれば簡単に得られることに気付いた。

そこで、以下のよく使われるディストリビューションについて、tar --helpを実行して得られたデフォルトフォーマットを抽出してみることにした:

ubuntu
debian
alpine
fedora
rockylinux
almalinux
oraclelinux
archlinux
opensuse/leap
amazonlinux

手法

以下のスクリプトを実行する。rockylinuxoraclelinuxにはlatestが存在しなかったため執筆タイミングで最新のイメージを指定した。またデフォルトでtarが含まれないディストリビューションがあるため、この場合はインストールコマンドを実行させた:

check-all.sh

#!/bin/sh

set -eux
set -o pipefail

LISTFILE=./images.txt
VERIFIER=./check-tar-default-format.sh

while read LINE; do
    IMAGE=$(echo "${LINE}" | awk -F ':' '{print $1}')
    TAG=$(echo "${LINE}" | awk -F ':' '{print $2}')
    PRERUN=$(echo "${LINE}" | awk -F ':' '{print $3}')
    $VERIFIER "${IMAGE}" "${TAG}" "${PRERUN}"
done < $LISTFILE

check-tar-default-format.sh

#!/bin/sh

set -ux
set -o pipefail

IMAGE=$1
TAG=${2:-latest}
PRERUN=${3:-}

echo "## $IMAGE"
if [ ! -z "$PRERUN" ]; then
    docker run --rm ${IMAGE}:${TAG} sh -c "$PRERUN && tar --help" | grep -F -e '*This* tar defaults to:' -A 1 | sed -ne '1d;s/\s.*$//;p';
else
    docker run --rm ${IMAGE}:${TAG} sh -c "tar --help" | grep  -F -e '*This* tar defaults to:' -A 1 | sed -ne '1d;s/\s.*$//;p'
fi

if [ $? -ne 0 ]; then
    echo 'N/A'
fi

images.txt

ubuntu
debian
alpine
fedora
rockylinux:9.3
almalinux
oraclelinux:10
archlinux
opensuse/leap:latest:zypper install -y tar
amazonlinux:latest:yum install -y tar

結果(2025-09-17時点)

## ubuntu
--format=gnu
## debian
--format=gnu
## alpine
N/A
## fedora
--format=gnu
## rockylinux
--format=gnu
## almalinux
--format=gnu
## oraclelinux
--format=gnu
## archlinux
--format=gnu
## opensuse/leap
--format=posix
## amazonlinux
--format=gnu

ほとんどのディストリビューションはGNU拡張形式を利用していることがわかった。冒頭で紹介した記事にも書いたが、GNU拡張形式はGNU TARにしか実装されていない独自の拡張形式であり、使うべきではない。paxを使うべきである。

また、opensuseはposix(これはpaxのシノニム)を利用していることがわかった。自分のマシンのtarがpaxを利用していたのも、opensuseを利用していたからだった。

alpineのtarはどのtarか

最後にalpineは検出に失敗している。これは、alpineに入っているtarはbusybox由来のものであるためだ。そこでtar.cを読みに行く。

coral.googlesource.com

するとマジックナンバーとしてGNU拡張のものを書いているっぽい。しかしGNU特有のヘッダは使わず、内容はustarに寄せている感じの素朴な実装になっている。

以下の記事によれば、LまたはKファイルタイプが出現すればGNU拡張だといえるし、xまたはgファイルタイプが出現すればpaxである。

mort.coffee

しかしながらこのいずれもソースコードには登場しないため、互換性のためにGNU拡張のようなヘッダを利用しつつ、実質的にはustarを読み書きしているものと思われる。

また、ソースコードには以下のような記述がある:

/* POSIX tar Header Block, from POSIX 1003.1-1990  */
struct TarHeader
{
                                /* byte offset */
    char name[100];               /*   0-99 */
    char mode[8];                 /* 100-107 */
    char uid[8];                  /* 108-115 */
    char gid[8];                  /* 116-123 */
    char size[12];                /* 124-135 */
    char mtime[12];               /* 136-147 */
    char chksum[8];               /* 148-155 */
    char typeflag;                /* 156-156 */
    char linkname[100];           /* 157-256 */
    char magic[6];                /* 257-262 */
    char version[2];              /* 263-264 */
    char uname[32];               /* 265-296 */
    char gname[32];               /* 297-328 */
    char devmajor[8];             /* 329-336 */
    char devminor[8];             /* 337-344 */
    char prefix[155];             /* 345-499 */
    char padding[12];             /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */
};

POSIX 1003.1-1990はPOSIX 1003.1-1988の後継であるため、ustarを使っているとみて間違いない。

www.gnu.org

★記事をRTしてもらえると喜びます
Webアプリケーション開発関連の記事を投稿しています.読者になってみませんか?