Hi, On 07/01/2014 08:01 PM, Rob Landley wrote:
I meant to get out a release...
Well, before you do that, I have some patches and some questions. You suggested a while back that someone should go through POSIX and add tests for conformance (and tests in general), so I decided to do that. I'm going through the spec in alphabetical order, and I haven't gotten very far, but I thought I'd try to get this much sent in before you release. I have attached patches for cleanup and tests of basename, blkid, cat, and cp. cp fails some of its tests that I did not try to fix (-P is broken); some of the code in the for loop is too dense for me to figure out. As always, your thoughts are appreciated, and so is the work you put into toybox.
Rob
Regards, Samuel
>From 80b8b44829e50892f33560d7879e730a2fde8fe6 Mon Sep 17 00:00:00 2001 From: Samuel Holland <[email protected]> Date: Wed, 11 Jun 2014 12:58:33 -0500 Subject: [PATCH 1/5] basename: fix segfault on null input; add tests When passed an empty string, glibc's basename() returns a pointer to the string "." in its private memory. If an empty suffix is given, it fits the condition of being shorter than the path, so we try to overwrite the null byte and crash. We fix this by just ignoring empty suffixes; they don't do anything anyway. Also, updated the help text. --- scripts/test/basename.test | 7 ++++++- toys/posix/basename.c | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/scripts/test/basename.test b/scripts/test/basename.test index 2f7a2ec..2789e29 100755 --- a/scripts/test/basename.test +++ b/scripts/test/basename.test @@ -4,6 +4,11 @@ #testing "name" "command" "result" "infile" "stdin" +# Null Input +testing "basename null path" "basename ''" ".\n" "" "" +testing "basename null path and suffix" "basename '' ''" ".\n" "" "" +testing "basename path with null suffix" "basename a/b/c ''" "c\n" "" "" + # Removal of extra /'s testing "basename /-only" "basename ///////" "/\n" "" "" testing "basename trailing /" "basename a//////" "a\n" "" "" @@ -19,5 +24,5 @@ testing "basename suffix=result" "basename .txt .txt" ".txt\n" "" "" testing "basename reappearing suffix 1" "basename a.txt.txt .txt" "a.txt\n" "" "" testing "basename reappearing suffix 2" "basename a.txt.old .txt" "a.txt.old\n" "" "" -# A suffix should be a real suffix, only a the end. +# A suffix should be a real suffix, only at the end. testing "basename invalid suffix" "basename isthisasuffix? suffix" "isthisasuffix?\n" "" "" diff --git a/toys/posix/basename.c b/toys/posix/basename.c index c49a5f3..917f62f 100644 --- a/toys/posix/basename.c +++ b/toys/posix/basename.c @@ -11,9 +11,9 @@ config BASENAME bool "basename" default y help - usage: basename string [suffix] + usage: basename PATH [SUFFIX] - Return non-directory portion of a pathname removing suffix + Return non-directory portion of PATH, optionally removing SUFFIX. */ #include "toys.h" @@ -23,7 +23,7 @@ void basename_main(void) char *base = basename(*toys.optargs), *suffix = toys.optargs[1]; // chop off the suffix if provided - if (suffix) { + if (suffix && *suffix) { char *s = base + strlen(base) - strlen(suffix); if (s > base && !strcmp(s, suffix)) *s = 0; } -- 2.0.1
>From 3a9f055a18f9098884a614a997b3909ad178569f Mon Sep 17 00:00:00 2001 From: Samuel Holland <[email protected]> Date: Tue, 1 Jul 2014 20:21:46 -0500 Subject: [PATCH 2/5] cat: fix/add tests; minor cleanup /proc/self/exe means two different things to cmp and cat Add test coverage for -u argument Tweak help text to be more in line with others Turning the conditional into a while loop makes more sense to me --- scripts/test/cat.test | 9 +++++++-- toys/posix/cat.c | 12 +++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/scripts/test/cat.test b/scripts/test/cat.test index 3d5842a..ec01595 100755 --- a/scripts/test/cat.test +++ b/scripts/test/cat.test @@ -9,6 +9,7 @@ echo "two" > file2 testing "cat" "cat && echo yes" "oneyes\n" "" "one" testing "cat -" "cat - && echo yes" "oneyes\n" "" "one" testing "cat file1 file2" "cat file1 file2" "one\ntwo\n" "" "" +testing "cat -u file1 file2" "cat -u file1 file2" "one\ntwo\n" "" "" testing "cat - file" "cat - file1" "zero\none\n" "" "zero\n" testing "cat file -" "cat file1 -" "one\nzero\n" "" "zero\n" @@ -16,8 +17,12 @@ testing "cat file1 notfound file2" \ "cat file1 notfound file2 2>stderr && echo ok ; cat stderr; rm stderr" \ "one\ntwo\ncat: notfound: No such file or directory\n" "" "" +testing "cat -u file1 notfound file2" \ + "cat -u file1 notfound file2 2>&1 && echo ok" \ + "one\ncat: notfound: No such file or directory\ntwo\n" "" "" + testing "cat file1" \ - "cat /proc/self/exe > file1 && cmp /proc/self/exe file1 && echo yes" \ + "cat `which cmp` > file1 && cmp /proc/self/exe file1 && echo yes" \ "yes\n" "" "" testing "cat - file1" \ @@ -28,4 +33,4 @@ testing "cat > /dev/full" \ "cat - > /dev/full 2>stderr && echo ok; cat stderr; rm stderr" \ "cat: xwrite: No space left on device\n" "" "zero\n" -rm file1 file2 \ No newline at end of file +rm file1 file2 diff --git a/toys/posix/cat.c b/toys/posix/cat.c index 3644c4f..892cc17 100644 --- a/toys/posix/cat.c +++ b/toys/posix/cat.c @@ -10,10 +10,10 @@ config CAT bool "cat" default y help - usage: cat [-u] [file...] + usage: cat [-u] [FILE...] - Copy (concatenate) files to stdout. If no files listed, copy from stdin. - Filename "-" is a synonym for stdin. + Copy (concatenate) each FILE in order to stdout. If no FILE listed, + copy from stdin. Filename "-" is a synonym for stdin. -u Copy one byte at a time (slow). */ @@ -22,12 +22,10 @@ config CAT static void do_cat(int fd, char *name) { - int len, size=toys.optflags ? 1 : sizeof(toybuf); + int len, size = toys.optflags ? 1 : sizeof(toybuf); - for (;;) { - len = read(fd, toybuf, size); + while ((len = read(fd, toybuf, size))) { if (len<0) perror_msg("%s",name); - if (len<1) break; xwrite(1, toybuf, len); } } -- 2.0.1
>From 57fa276c827b13b43e7b469f4fa6f2c5682222ea Mon Sep 17 00:00:00 2001 From: Samuel Holland <[email protected]> Date: Tue, 1 Jul 2014 20:31:05 -0500 Subject: [PATCH 3/5] blkid.test: Remove trailing whitespace --- scripts/test/blkid.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/test/blkid.test b/scripts/test/blkid.test index 0026aeb..e6d9dba 100755 --- a/scripts/test/blkid.test +++ b/scripts/test/blkid.test @@ -14,10 +14,10 @@ testing "blkid cramfs" 'bzcat "$BDIR"/cramfs.bz2 | blkid -' \ '-: LABEL="mycramfs" TYPE="cramfs"\n' "" "" testing "blkid ext2" 'bzcat "$BDIR"/ext2.bz2 | blkid -' \ '-: LABEL="myext2" UUID="e59093ba-4135-4fdb-bcc4-f20beae4dfaf" TYPE="ext2"\n' \ - "" "" + "" "" testing "blkid ext3" 'bzcat "$BDIR"/ext3.bz2 | blkid -' \ '-: LABEL="myext3" UUID="79d1c877-1a0f-4e7d-b21d-fc32ae3ef101" TYPE="ext2"\n' \ - "" "" + "" "" testing "blkid ext4" 'bzcat "$BDIR"/ext4.bz2 | blkid -' \ '-: LABEL="myext4" UUID="dc4b7c00-c0c0-4600-af7e-0335f09770fa" TYPE="ext2"\n' \ "" "" -- 2.0.1
>From d2a87a712b01dd3f16553c5bf52b7eb4cafbaa36 Mon Sep 17 00:00:00 2001 From: Samuel Holland <[email protected]> Date: Tue, 1 Jul 2014 22:48:53 -0500 Subject: [PATCH 4/5] cp: greatly expand test suite --- scripts/test/cp.test | 177 ++++++++++++++++++++++++++++----------------------- 1 file changed, 98 insertions(+), 79 deletions(-) diff --git a/scripts/test/cp.test b/scripts/test/cp.test index eea0471..4c5f066 100755 --- a/scripts/test/cp.test +++ b/scripts/test/cp.test @@ -3,95 +3,114 @@ [ -f testing.sh ] && . testing.sh # Create test file -dd if=/dev/urandom of=random bs=64 count=1 2> /dev/null +dd if=/dev/urandom of=rand1 bs=1 count=64 2> /dev/null +dd if=/dev/urandom of=rand2 bs=1 count=64 2> /dev/null +dd if=/dev/urandom of=rand3 bs=1 count=64 2> /dev/null +ln -s rand1 symrand + +mkdir four five six eight eleven +mkdir -p nine/two/three/four +touch zero +touch nine/two/three/five +touch nine/{six,seven,eight} + +chmod 000 zero six +chmod 707 rand1 +chmod 646 rand2 +chmod 776 nine/seven #testing "name" "command" "result" "infile" "stdin" +# First synopsis form testing "cp not enough arguments [fail]" "cp one 2>/dev/null || echo yes" \ "yes\n" "" "" -testing "cp -missing source [fail]" "cp missing two 2>/dev/null || echo yes" \ +testing "cp missing source [fail]" "cp missing two 2>/dev/null || echo yes" \ "yes\n" "" "" -testing "cp file->file" "cp random two && cmp random two && echo yes" \ +testing "cp file -> missing" "cp rand1 two && cmp rand1 two && echo yes" \ "yes\n" "" "" -rm two - -mkdir two -testing "cp file->dir" "cp random two && cmp random two/random && echo yes" \ - "yes\n" "" "" -rm two/random -testing "cp file->dir/file" \ - "cp random two/random && cmp random two/random && echo yes" \ - "yes\n" "" "" -testing "cp -r dir->missing" \ - "cp -r two three && cmp random three/random && echo yes" \ - "yes\n" "" "" -touch walrus -testing "cp -r dir->file [fail]" \ - "cp -r two walrus 2>/dev/null || echo yes" "yes\n" "" "" -touch two/three -testing "cp -r dir hits file." \ - "cp -r three two 2>/dev/null || echo yes" "yes\n" "" "" -rm -rf two three walrus - -touch two -chmod 000 two -testing "cp file->inaccessable [fail]" \ - "cp random two 2>/dev/null || echo yes" "yes\n" "" "" -rm -f two - -touch two -chmod 000 two -testing "cp -f file->inaccessable" \ - "cp -f random two && cmp random two && echo yes" "yes\n" "" "" -mkdir sub -chmod 000 sub -testing "cp file->inaccessable_dir [fail]" \ - "cp random sub 2>/dev/null || echo yes" "yes\n" "" "" -rm two -rmdir sub - -mkdir dir -touch file -testing "cp -rf dir file [fail]" "cp -rf dir file 2>/dev/null || echo yes" \ +testing "cp symlink -> missing" "cp symrand three && cmp rand1 three && echo yes" \ "yes\n" "" "" -rm -rf dir file - -touch one two -testing "cp file1 file2 missing [fail]" \ - "cp one two missing 2>/dev/null || echo yes" "yes\n" "" "" -mkdir dir -testing "cp dir file missing [fail]" \ - "cp dir two missing 2>/dev/null || echo yes" "yes\n" "" "" -testing "cp -rf dir file missing [fail]" \ - "cp dir two missing 2>/dev/null || echo yes" "yes\n" "" "" -testing "cp file1 file2 file [fail]" \ - "cp random one two 2>/dev/null || echo yes" "yes\n" "" "" -testing "cp file1 file2 dir" \ - "cp random one dir && cmp random dir/random && cmp one dir/one && echo yes" \ - "yes\n" "" "" -rm one two random -rm -rf dir +testing "cp symlink -> file" "cp symrand three && cmp rand1 three && echo yes" \ + "yes\n" "" "" +testing "cp -P symlink -> missing" "cp -P symrand one && readlink one" \ + "rand1\n" "" "" +testing "cp -P symlink -> symlink" "cp -P symrand one && readlink one" \ + "rand1\n" "" "" +testing "cp file -> file" "cp rand2 three && cmp rand2 three && echo yes" \ + "yes\n" "" "" +testing "cp file -> dir/file" "cp rand1 four/extra && cmp rand1 four/extra && echo yes" \ + "yes\n" "" "" +testing "cp dir/file -> missing" "cp four/extra extra2 && cmp four/extra extra2 && echo yes" \ + "yes\n" "" "" +testing "cp file -> itself [fail]" "cp rand1 rand1 2>/dev/null || echo yes" \ + "yes\n" "" "" +testing "cp file -> symlink to itself [fail]" "cp rand1 symrand 2>/dev/null || echo yes" \ + "yes\n" "" "" +testing "cp file -> inaccessable [fail]" "cp rand1 zero 2>/dev/null || echo yes" \ + "yes\n" "" "" +testing "cp -f file -> inaccessable" "cp -f rand2 zero && cmp rand2 zero && echo yes" \ + "yes\n" "" "" +testing "cp -p file -> missing" "cp -p rand1 twelve && find -path ./twelve -printf '%m' 2>/dev/null " \ + "707" "" "" +testing "cp -p file -> file" "cp -p rand2 twelve && find -path ./twelve -printf '%m' 2>/dev/null " \ + "646" "" "" -mkdir -p one/two/three/four -touch one/two/three/five -touch one/{six,seven,eight} -testing "cp -r /abspath dest" \ - "cp -r \"$(readlink -f one)\" dir && diff -r one dir && echo yes" \ - "yes\n" "" "" -testing "cp -r dir again" "cp -r one/. dir && diff -r one dir && echo yes" \ - "yes\n" "" "" -mkdir dir2 -testing "cp -r dir1/* dir2" \ - "cp -r one/* dir2 && diff -r one dir2 && echo yes" "yes\n" "" "" -rm -rf one dir dir2 +# Second synopsis form +testing "cp file -> dir" "cp rand1 four && cmp rand1 four/rand1 && echo yes" \ + "yes\n" "" "" +testing "cp ../file -> dir" "cd nine/two && cp ../six three && cmp ../six three/six && echo yes" \ + "yes\n" "" "" +testing "cp file1 file2 -> dir" "cp rand2 rand3 four && cmp rand2 four/rand2 && echo yes" \ + "yes\n" "" "" +testing "cp file1 file2 -> file [fail]" "cp rand1 rand2 rand3 2>/dev/null || echo yes" \ + "yes\n" "" "" +testing "cp file1 file2 -> missing [fail]" "cp rand1 rand2 missing 2>/dev/null || echo yes" \ + "yes\n" "" "" +testing "cp dir -> dir [fail]" "cp four five 2>/dev/null || echo yes" \ + "yes\n" "" "" +testing "cp file dir -> dir [fail]" "cp rand2 four five 2>/dev/null || echo yes" \ + "yes\n" "" "" +testing "cp symlink -> dir" "cp symrand five && cmp rand1 five/symrand && echo yes" \ + "yes\n" "" "" +testing "cp file -> inaccessable_dir [fail]" "cp rand3 six 2>/dev/null || echo yes" \ + "yes\n" "" "" +testing "cp dir/file -> dir (itself) [fail]" "cp nine/two/three/five nine/two/three 2>/dev/null || echo yes" \ + "yes\n" "" "" +testing "cp -p file -> dir (overwrite)" "cp -p rand2 four && find -path ./four/rand2 -printf '%m' 2>/dev/null " \ + "646" "" "" -# cp -r ../source destdir -# cp -r one/two/three missing -# cp -r one/two/three two -# mkdir one; touch one/two; ln -s two one/three -# cp file1 file2 dir -# cp file1 missing file2 -> dir +# Third synopsis form +testing "cp -r dir -> missing" "cp -r five seven && cmp five/symrand seven/symrand && echo yes" \ + "yes\n" "" "" +testing "cp -r dir -> dir" "cp -r four seven && cmp four/rand3 seven/four/rand3 && echo yes" \ + "yes\n" "" "" +testing "cp -r dir -> dir/name" "cp -r five seven/extra && cmp five/symrand seven/extra/symrand && echo yes" \ + "yes\n" "" "" +testing "cp -r dir -> itself [fail]" "cp -r five five 2>/dev/null || echo yes" \ + "yes\n" "" "" +testing "cp -r dir -> inaccessible dir [fail]" "cp -r five six 2>/dev/null || echo yes" \ + "yes\n" "" "" +testing "cp -r dir -> file [fail]" "cp -r five rand2 2>/dev/null || echo yes" \ + "yes\n" "" "" +testing "cp -rf dir file [fail]" "cp -rf file rand1 2>/dev/null || echo yes" \ + "yes\n" "" "" +testing "cp -r dir -> dir (file exists) [fail]" "cp -r seven/extra four 2>/dev/null || echo yes" \ + "yes\n" "" "" +testing "cp -r dir1 dir2 -> dir" "cp -r four five eight && cmp eight/four/extra eight/five/symrand && echo yes" \ + "yes\n" "" "" +testing "cp -r dir1 dir2 -> missing [fail]" "cp -r four five missing 2>/dev/null || echo yes" \ + "yes\n" "" "" +testing "cp -r /abspath dir" "cp -r \"$(readlink -f nine)\" ten && diff -r nine ten && echo yes" \ + "yes\n" "" "" +testing "cp -r dir again" "cp -r nine/. ten && diff -r nine ten && echo yes" \ + "yes\n" "" "" +testing "cp -r ten/* eleven" "cp -r ten/* eleven && diff -r nine eleven && echo yes" \ + "yes\n" "" "" +testing "cp -rp dir -> missing" "cp -rp nine thirteen && find -path ./thirteen/seven -printf '%m' 2>/dev/null " \ + "776" "" "" -# Make sure it's truncating existing file # copy with -d at top level, with -d in directory, without -d at top level, # without -d in directory + +rm rand1 rand2 rand3 symrand extra2 +rm -rf zero one two three four five six seven eight nine ten eleven twelve thirteen -- 2.0.1
>From f02092e4a59bf5ce29f50384c90d7d663ac56287 Mon Sep 17 00:00:00 2001 From: Samuel Holland <[email protected]> Date: Tue, 1 Jul 2014 22:50:44 -0500 Subject: [PATCH 5/5] cp: fix 'cp -rf dir -> file' case We want to skip it, not delete it and come back --- toys/posix/cp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/toys/posix/cp.c b/toys/posix/cp.c index a8d3aee..15e344c 100644 --- a/toys/posix/cp.c +++ b/toys/posix/cp.c @@ -155,8 +155,10 @@ int cp_node(struct dirtree *try) if (!mkdirat(cfd, catch, try->st.st_mode | 0200) || errno == EEXIST) if (-1 != (try->extra = openat(cfd, catch, O_NOFOLLOW))) - if (!fstat(try->extra, &st2)) + if (!fstat(try->extra, &st2)) { if (S_ISDIR(st2.st_mode)) return DIRTREE_COMEAGAIN; + else break; + } // Hardlink -- 2.0.1
_______________________________________________ Toybox mailing list [email protected] http://lists.landley.net/listinfo.cgi/toybox-landley.net
