Hello, I'm experimenting with testing coreutils on Alpine Linux ( https://alpinelinux.org/ ). Alpine is a lightweight Linux-based system, with musl libc and busybox utilities - so not very GNU-like, and possibly not POSIX compliant. These minor failures are obviously not a priority, but I suspect such systems will become more common in the future (due to usage in small VMs / containers). Most of them are problems with the tests, not with the programs.
I'll provide brief notes here, with more details in the attachments. The failures are: FAIL: tests/ln/sf-1.sh FAIL: tests/misc/help-version.sh FAIL: tests/misc/sort-debug-warn.sh FAIL: tests/misc/wc-files0.sh === tests/misc/help-version.sh === This fails because musk-libc disables the UTMP mechanism on purpose: http://wiki.musl-libc.org/wiki/FAQ#Q:_why_is_the_utmp.2Fwtmp_functionality_only_implemented_as_stubs_.3F The file 'utmp.h' contains: $ cat /usr/include/utmp.h [...] #define _PATH_UTMP "/dev/null/utmp" #define _PATH_WTMP "/dev/null/wtmp" #define UTMP_FILE _PATH_UTMP #define WTMP_FILE _PATH_WTMP #define UTMP_FILENAME _PATH_UTMP #define WTMP_FILENAME _PATH_WTMP which means that 'readutmp.m4' passes all the normal detection checks, but the compiled 'pinky' and 'who' use the hard-coded (and non-existing) file: $ ./src/pinky ./src/pinky: /dev/null/utmp: Not a directory $ ./src/who ./src/who: /dev/null/utmp: Not a directory Perhaps additional checks be made in 'readutmp.m4', or alternatively skip 'pinky' tests if the file is invalid? === tests/ln/sf-1.sh === fails because of (non-portable?) printf usage: + printf %0*d 256 0 ash: %0*d: invalid format The attached patch replaces the printf usage into a more portable one. (an alternative would be to use 'env printf' invoking coreutils' printf, but other tests use the built-in printf with embedded "%${size}d" syntax). regarding the portability of "*" in printf, the POSIX page says: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html APPLICATION USAGE [..] No provision is made in this volume of POSIX.1-2008 which allows field widths and precisions to be specified as '*' since the '*' can be replaced directly in the format operand using shell variable substitution. Implementations can also provide this feature as an extension if they so choose. === tests/misc/wc-files0.sh === This fails because the "expected" output file is generated using the $'\t' syntax, and it seems BusyBox ash does not support it (if I read the log correctly): The test script has: printf '%s\n' "0 0 0 '1'$'\\n''2'" > exp || framework_failure_ And the failure log has: + diff -u exp out --- exp +++ out @@ -1 +1 @@ -0 0 0 '1''\n''2' +0 0 0 '1'$'\n''2' + fail=1 The attached 'alp-bug-shell-dollar-sign.txt' gives example of the syntax on few shells, it seems ASH is the exception. === tests/misc/sort-debug-warn.sh === The failure is in the last debug message. The expected message is for an invalid forced locale, but musl-libc seems to accept the invalid locale: + diff -u exp out --- exp +++ out @@ -29,4 +29,4 @@ sort: using simple byte comparison sort: using simple byte comparison sort: using simple byte comparison -sort: failed to set locale; using simple byte comparison +sort: using ‘missing’ sorting rules + fail=1 The flow is: 1. 'LC_ALL=missing sort --debug ...' calls 'hard_locale()' 2. most libc implementations return 'C' for invalid locales, thus 'hard_locale' returns false. 3. musl-libc implementation return 'missing' and 'hard_locale' returns true. 4. the incorrect debug message is printed. The attached 'alp-bug-LC-ALL-missing.txt' contains a tiny C program to demonstrate this, with results from several libc implementations. Comments welcomed. I'm happy to test things further if needed. regards, - assaf
0001-tests-avoid-non-portable-printf.patch
Description: Binary data
/*
Test 'setlocale()' behaviour.
Copyright (C) 2016 Assaf Gordon
license: GNU All permissive license.
compile:
cc -o print-locale print-locale.c
test:
./print-locale
LC_ALL=C ./print-locale
LC_ALL=missing ./print-locale
*/
#include <locale.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char* p = getenv("LC_ALL");
printf("LC_ALL env var = '%s'\n", p?p:"(NULL)");
p = setlocale(LC_ALL,"");
printf("setlocale(LC_ALL,\"\") = '%s'\n", p?p:"(NULL)");
p = setlocale(LC_ALL,NULL);
printf("LC_ALL from setlocale = '%s'\n", p?p:"(NULL)");
p = setlocale(LC_COLLATE,NULL);
printf("LC_COLLATE from setlocale = '%s'\n", p?p:"(NULL)");
return 0;
}
==== glibc (Ubuntu) ====
$ ./print-locale
LC_ALL env var = '(NULL)'
setlocale(LC_ALL,"") = 'en_US.UTF-8'
LC_ALL from setlocale = 'en_US.UTF-8'
LC_COLLATE from setlocale = 'en_US.UTF-8'
$ LC_ALL=C ./print-locale
LC_ALL env var = 'C'
setlocale(LC_ALL,"") = 'C'
LC_ALL from setlocale = 'C'
LC_COLLATE from setlocale = 'C'
$ LC_ALL=missing ./print-locale
LC_ALL env var = 'missing'
setlocale(LC_ALL,"") = '(NULL)'
LC_ALL from setlocale = 'C'
LC_COLLATE from setlocale = 'C'
==== musl libc =======
$ ./print-locale
LC_ALL env var = '(NULL)'
setlocale(LC_ALL,"") = 'C.UTF-8;C;C;C;C;C'
LC_ALL from setlocale = 'C.UTF-8;C;C;C;C;C'
LC_COLLATE from setlocale = 'C'
$ LC_ALL=c ./print-locale
LC_ALL env var = 'C'
setlocale(LC_ALL,"") = 'C;C;C;C;C;C'
LC_ALL from setlocale = 'C;C;C;C;C;C'
LC_COLLATE from setlocale = 'C'
$ LC_ALL=missing ./print-locale
LC_ALL env var = 'missing'
setlocale(LC_ALL,"") = 'missing;missing;missing;missing;missing;missing'
LC_ALL from setlocale = 'missing;missing;missing;missing;missing;missing'
LC_COLLATE from setlocale = 'missing'
==== FreeBSD ====
$ ./print-locale
LC_ALL env var = '(NULL)'
setlocale(LC_ALL,"") = 'C'
LC_ALL from setlocale = 'C'
LC_COLLATE from setlocale = 'C'
$ LC_ALL=C ./print-locale
LC_ALL env var = 'C'
setlocale(LC_ALL,"") = 'C'
LC_ALL from setlocale = 'C'
LC_COLLATE from setlocale = 'C'
$ LC_ALL=missing ./print-locale
LC_ALL env var = 'missing'
setlocale(LC_ALL,"") = '(NULL)'
LC_ALL from setlocale = 'C'
LC_COLLATE from setlocale = 'C'
==== OpenBSD ====
$ ./print-locale
LC_ALL env var = '(NULL)'
setlocale(LC_ALL,"") = 'C'
LC_ALL from setlocale = 'C'
LC_COLLATE from setlocale = 'C'
$ LC_ALL=C ./print-locale
LC_ALL env var = 'C'
setlocale(LC_ALL,"") = 'C'
LC_ALL from setlocale = 'C'
LC_COLLATE from setlocale = 'C'
$ LC_ALL=missing ./print-locale
LC_ALL env var = 'missing'
setlocale(LC_ALL,"") = 'C/missing/C/C/C/C'
LC_ALL from setlocale = 'C/missing/C/C/C/C'
LC_COLLATE from setlocale = 'C'
BusyBox's ash:
$ echo a$'\t'b
a b
$ echo "a$'\t'b"
a'\t'b
Bash:
$ echo a$'\t'b
a b
$ echo "a$'\t'b"
a$'\t'b
zsh:
% echo a$'\t'b
a b
% echo "a$'\t'b"
a$' 'b
ksh on Ubuntu (mksh: MirBSD Korn Shell v46):
$ echo a$'\t'b
a b
$ echo "a$'\t'b"
a$' 'b
FreeBSD 10.1 default bourne sh
$ echo a$'\t'b
a b
$ echo "a$'\t'b"
a$'\t'b
ksh on OpenBSD 5.8 (KSH v5.2.14 99/07/13.2)
$ echo a$'\t'b
a$ b
$ echo "a$'\t'b"
a$' 'b
alpine-test-suite.log.xz
Description: Binary data
