[Aboriginal] simple-root-filesystem now lives in initramfs (which is actually initmpfs).

James McMechan james_mcmechan at hotmail.com
Sat Mar 14 20:28:18 PDT 2015


________________________________
> Date: Fri, 13 Mar 2015 20:13:30 +0000
> From: dahalls at gmail.com
> To: rob at landley.net
> CC: aboriginal at lists.landley.net
> Subject: Re: [Aboriginal] simple-root-filesystem now lives in initramfs
> (which is actually initmpfs).
>
> Btw, these are the Toybox patches I'm running with:
>
> diff -ru toybox-0.5.2.orig/lib/portability.c toybox-0.5.2/lib/portability.c
> --- toybox-0.5.2.orig/lib/portability.c 2015-02-26 02:42:24.000000000 +0000
> +++ toybox-0.5.2/lib/portability.c 2015-03-13 20:07:48.017855796 +0000
> @@ -45,7 +45,7 @@
>         new_line = realloc(*linep, new_len);
>         if (!new_line) return -1;
>         *np = new_len;
> -      *linep = new_line;
> +      line = *linep = new_line;
>       }
>
>       line[i] = ch;
> @@ -59,7 +59,7 @@
>       new_line = realloc(*linep, new_len);
>       if (!new_line) return -1;
>       *np = new_len;
> -    *linep = new_line;
> +    line = *linep = new_line;
>     }
>     line[i + 1] = '\0';
>

portability.c/getdelim under _APPLE_ & __ANDROID__ looks like it has
several glitches I find it simpler if only one alloc block can be used, instead
of three also realloc does not clear the expanded buffer so if you have
realloced and hit EOF you will end up with uninitialized data in the last byte
since it puts the \0 after where it thinks the delim is, also the 3rd realloc could
allow the \0 to write after the end of the buffer if *np == i
I can also descope two vars and eliminate one local which is nice.
For testing I ran it with the ifdef __APPLE__/__ANDROID__ commented
out.
Do you have better test cases?

The manual pages all specified that when both *linep and *np are 0 allocate
but don't mention what happens if *linep is 0 and *np is a number.
I this case I made it use *np for the first allocation.
the toybox grep does call getdelim with a var called unused
that does not get cleared between calls, would that be a bug or a feature?
My logic was that if you are calling with a number use it, the caller may
have a better guess how big it should be, and reallocating the same size
as just freed is likely best.


diff -ur toybox.old/lib/portability.c toybox/lib/portability.c
--- toybox.old/lib/portability.c        2015-03-14 13:03:46.090840772 -0700
+++ toybox/lib/portability.c    2015-03-14 14:48:17.595678713 -0700
@@ -13,9 +13,7 @@
 ssize_t getdelim(char **linep, size_t *np, int delim, FILE *stream)
 {
   int ch;
-  size_t new_len;
   ssize_t i = 0;
-  char *line, *new_line;

   // Invalid input
   if (!linep || !np) {
@@ -23,37 +21,30 @@
     return -1;
   }

-  if (*linep == NULL || *np == 0) {
-    *np = 1024;
-    *linep = calloc(1, *np);
-    if (*linep == NULL) return -1;
-  }
-  line = *linep;
-
-  while ((ch = getc(stream)) != EOF) {
-    if (i> *np) {
+  while (1) {
+    if ( *np - i < 2 || *linep == NULL) {
       // Need more space
-      new_len = *np + 1024;
-      new_line = realloc(*linep, new_len);
+      size_t new_len = *np;
+
+      // if we have previously allocated or new_len is too small 
+      if (*linep || new_len < 2) new_len += 1024;
+
+      char *new_line = realloc(*linep, new_len);
+
       if (!new_line) return -1;
+
       *np = new_len;
       *linep = new_line;
     }

-    line[i] = ch;
+    if ((ch = getc(stream)) == EOF) break;
+
+    (*linep)[i++] = ch;
+
     if (ch == delim) break;
-    i += 1;
   }
 
-  if (i> *np) {
-    // Need more space
-    new_len  = i + 2;
-    new_line = realloc(*linep, new_len);
-    if (!new_line) return -1;
-    *np = new_len;
-    *linep = new_line;
-  }
-  line[i + 1] = '\0';
+  (*linep)[i] = '\0';
 
   return i> 0 ? i : -1;
 }

> diff -ru toybox-0.5.2.orig/toys/posix/cp.c toybox-0.5.2/toys/posix/cp.c
> --- toybox-0.5.2.orig/toys/posix/cp.c 2015-02-26 02:42:24.000000000 +0000
> +++ toybox-0.5.2/toys/posix/cp.c 2015-03-13 20:08:18.990360352 +0000
> @@ -391,6 +391,7 @@
>     }
>
>     if (toys.optflags & FLAG_D) {
> +    TT.destname = toys.optargs[toys.optc-1];
>       if (mkpathat(AT_FDCWD, TT.destname, 0, 2))
>         perror_exit("-D '%s'", TT.destname);
>       if (toys.optc == 1) return;


For cp.c/do_install It is not working like the coreutils version of install
O joy, install does not respect umask in coreutils and always creates 755
toybox does respect umask, but on failure may leave the freshly
created directory behind. and while your version does not segfault it will 
not produce the target file if that optc 1: return is still present.
and even this version does not set the mode if it conflicts with the umask.
Should it just set the mode anyway or should it honor the umask?
no clue on the man install page what umask does but it does mention
the default mode of 755

diff -ur toybox.old/toys/posix/cp.c toybox/toys/posix/cp.c
--- toybox.old/toys/posix/cp.c  2015-03-14 13:03:45.454256768 -0700
+++ toybox/toys/posix/cp.c      2015-03-14 16:38:07.480061072 -0700
@@ -378,9 +378,9 @@
   }
 
   if (toys.optflags & FLAG_D) {
+    TT.destname = toys.optargs[toys.optc - 1];
     if (mkpathat(AT_FDCWD, TT.destname, 0, 2))
       perror_exit("-D '%s'", TT.destname);
-    if (toys.optc == 1) return;
   }
   if (toys.optc < 2) error_exit("needs 2 args");

$ touch from
$ chmod 777 from
$ umask 12
$ rm -rf /tmp/jim;./toybox
 install -D -m577 from /tmp/jim/mcmechan/test;ls -ld from /tmp/jim 
/tmp/jim/mcmechan /tmp/jim/mcmechan/test  
-rwxrwxrwx 1 mcmechan mcmechan    0 Mar 14 16:30 from
drwxrw-r-x 3 mcmechan mcmechan 4096 Mar 14 16:30 /tmp/jim
drwxrw-r-x 2 mcmechan mcmechan 4096 Mar 14 16:30 /tmp/jim/mcmechan
-r-xrw-r-x 1 mcmechan mcmechan    0 Mar 14 16:30 /tmp/jim/mcmechan/test
$ rm -rf /tmp/jim;install -D -m577 from 
/tmp/jim/mcmechan/test;ls -ld from /tmp/jim /tmp/jim/mcmechan 
/tmp/jim/mcmechan/test 
-rwxrwxrwx 1 mcmechan mcmechan    0 Mar 14 16:30 from
drwxr-xr-x 3 mcmechan mcmechan 4096 Mar 14 16:31 /tmp/jim
drwxr-xr-x 2 mcmechan mcmechan 4096 Mar 14 16:31 /tmp/jim/mcmechan
-r-xrwxrwx 1 mcmechan mcmechan    0 Mar 14 16:31 /tmp/jim/mcmechan/test

$ rm -rf /tmp/jim;./toybox install -D from /tmp/jim/mcmechan/test;ls -ld from /tmp/jim /tmp/jim/mcmechan /tmp/jim/mcmechan/test 
-rwxrwxrwx 1 mcmechan mcmechan    0 Mar 14 16:30 from
drwxrw-r-x 3 mcmechan mcmechan 4096 Mar 14 16:33 /tmp/jim
drwxrw-r-x 2 mcmechan mcmechan 4096 Mar 14 16:33 /tmp/jim/mcmechan
-rwxrw-r-x 1 mcmechan mcmechan    0 Mar 14 16:33 /tmp/jim/mcmechan/test
$ rm -rf /tmp/jim;install -D from /tmp/jim/mcmechan/test;ls -ld from /tmp/jim /tmp/jim/mcmechan /tmp/jim/mcmechan/test 
-rwxrwxrwx 1 mcmechan mcmechan    0 Mar 14 16:30 from
drwxr-xr-x 3 mcmechan mcmechan 4096 Mar 14 16:33 /tmp/jim
drwxr-xr-x 2 mcmechan mcmechan 4096 Mar 14 16:33 /tmp/jim/mcmechan
-rwxr-xr-x 1 mcmechan mcmechan    0 Mar 14 16:33 /tmp/jim/mcmechan/test

$ rm -rf /tmp/jim;./toybox install -D /tmp/jim/mcmechan/test;ls -ld from /tmp/jim /tmp/jim/mcmechan /tmp/jim/mcmechan/test 
install: needs 2 args
ls: cannot access /tmp/jim/mcmechan/test: No such file or directory
-rwxrwxrwx 1 mcmechan mcmechan    0 Mar 14 16:30 from
drwxrw-r-x 3 mcmechan mcmechan 4096 Mar 14 16:35 /tmp/jim
drwxrw-r-x 2 mcmechan mcmechan 4096 Mar 14 16:35 /tmp/jim/mcmechan
$ rm -rf /tmp/jim;install -D /tmp/jim/mcmechan/test;ls -ld from /tmp/jim /tmp/jim/mcmechan /tmp/jim/mcmechan/test 
install: missing destination file operand after ‘/tmp/jim/mcmechan/test’
Try 'install --help' for more information.
ls: cannot access /tmp/jim: No such file or directory
ls: cannot access /tmp/jim/mcmechan: No such file or directory
ls: cannot access /tmp/jim/mcmechan/test: No such file or directory
-rwxrwxrwx 1 mcmechan mcmechan 0 Mar 14 16:30 from

> diff -ru toybox-0.5.2.orig/toys/posix/find.c toybox-0.5.2/toys/posix/find.c
> --- toybox-0.5.2.orig/toys/posix/find.c 2015-02-26 02:42:24.000000000 +0000
> +++ toybox-0.5.2/toys/posix/find.c 2015-03-13 20:07:20.927409060 +0000
> @@ -435,7 +435,7 @@
>             if (aa->dir && TT.topdir == -1) TT.topdir = xopen(".", 0);
>
>           // collect names and execute commands
> -        } else if (check) {
> +        } else {
>             char *name, *ss1 = ss[1];
>             struct double_list **ddl;
>
> @@ -443,6 +443,7 @@
>             aa = (void *)llist_pop(&argdata);
>             ss += aa->arglen + 1;
>
> +          if (check) {
>             // name is always a new malloc, so we can always free it.
>             name = aa->dir ? xstrdup(new->name) : dirtree_path(new, 0);
>
> @@ -479,6 +480,7 @@
>             dlist_add(ddl, name);
>             aa->namecount++;
>             if (!aa->plus) test = flush_exec(new, aa);
> +          }
>           }
>
>           // Argument consumed, skip the check.

at the moment I don't know how you would get so check is not set on a non
first arg processing in exec ok execdir okdir?
it looks sort of like dlist_add*() is paired with llist_pop
so we are advancing the argdata pointer and ss (by the length of argdata)
what is this a fix for?

> diff -ru toybox-0.5.2.orig/toys/posix/grep.c toybox-0.5.2/toys/posix/grep.c
> --- toybox-0.5.2.orig/toys/posix/grep.c 2015-02-26 02:42:24.000000000 +0000
> +++ toybox-0.5.2/toys/posix/grep.c 2015-03-13 20:07:48.017855796 +0000
> @@ -75,6 +75,17 @@
>       return;
>     }
>
> +  struct stat stat;
> +  if (fstat(fd, &stat) != 0) {
> +    perror_msg("%s", name);
> +    fclose(file);
> +    return;
> +  }
> +  if (S_ISDIR(stat.st_mode)) {
> +    fclose(file);
> +    return;
> +  }
> +
>     for (;;) {
>       char *line = 0, *start;
>       regmatch_t matches[3];
>
For grep.c/do_grep if I move the fdopen down both fcloses can be removed
from the ifs and you then don't bother fdopening a directory just to close it.
I added setting the EISDIR and perror_msg for the IS_DIR case too like coreutils.
I am not sure how to do it correctly for socket files toybox grep got EBADFD
when coreutils reported nothing and toybox tries to go through device files when
they are recursed into
$ grep -r fred /dev/block
$ ./toybox grep -r fred /dev/block
grep: /dev/block/8:0: Bad file descriptor
 
$ grep -r fred /dev/block/8:0
grep: /dev/block/8:0: Permission denied
$ ./toybox grep -r fred /dev/block/8:0
grep: /dev/block/8:0: Bad file descriptor

diff -ur toybox.old/toys/posix/grep.c toybox/toys/posix/grep.c
--- toybox.old/toys/posix/grep.c        2015-03-14 13:03:45.474254171 -0700
+++ toybox/toys/posix/grep.c    2015-03-14 13:17:07.270358868 -0700
@@ -52,7 +52,7 @@
 
 static void do_grep(int fd, char *name)
 {
-  FILE *file = fdopen(fd, "r");
+  FILE *file;
   long offset = 0;
   int lcount = 0, mcount = 0, which = toys.optflags & FLAG_w ? 2 : 0;
   char indelim = '\n' * !(toys.optflags&FLAG_z),
@@ -60,6 +60,18 @@
 
   if (!fd) name = "(standard input)";
 
+  struct stat stat;
+  if (fstat(fd, &stat ) != 0) {
+    perror_msg("%s", name);
+    return;
+    }
+  if (S_ISDIR(stat.st_mode)) {
+    errno=EISDIR;
+    perror_msg("%s", name);
+    return;
+    }
+
+  file = fdopen(fd, "r");
   if (!file) {
     perror_msg("%s", name);
     return;

>
> On 13 March 2015 at 06:32, David Halls
> <dahalls at gmail.com<mailto:dahalls at gmail.com>> wrote:
> I note that if you're building a nontrivial amount of stuff,
> chroot-setup is probably your friend. Otherwise you'll install stuff
> into / until you fill it up, it's generally only got 100 megs or so of
> space. (Half of physical memory.)
>
> I'm installing everything I build into /home/install, don't touch the
> rest. Then /home/install itself becomes a sqf so it can't be messed
> with either.
>
>
> I still have a todo item from you (grep segfault with uClibc). I should
> go fix that now. (I had enough work getting the move to initramfs
> working I just shipped it once it built LFS on the targets. I'm still a
> kernel version behind, it's still running uclibc instead of musl...)
>
> No worries, I automate the patching anyway.
> Aboriginal is good enough for me as it is, although uclibc could
> probably to with some love/replacement.
>

while running make test to double check the patches above
I found that the toybox vs coreutils chmod behave  differently
with respect to umask where it appears coreutils does not follow
the man chmod page about umask and clears the bits rather than
leaving them alone. this showed up when I accidentally left the
umask set after testing install patch, note that it says that the
umask is only used if none of [augo] are used to specify which
bits to set.

$ touch file
$ umask 124
$
 k=777;echo file set to $k;for j in "";do for i in $j+r $j-r $j=r $j+w 
$j-w $j=w $j+x $j-x $j=x; do echo;echo "testing $i";chmod $k 
file;./toybox chmod $i file;ls -l file;chmod $k file;echo; chmod $i 
file;ls -l file; done; done
file set to 777

testing +r
-rwxrwxrwx 1 mcmechan mcmechan 0 Mar 14 17:37 file

-rwxrwxrwx 1 mcmechan mcmechan 0 Mar 14 17:37 file

testing -r
--wx-wxrwx 1 mcmechan mcmechan 0 Mar 14 17:37 file

chmod: file: new permissions are -wx-wxrwx, not -wx-wx-wx
--wx-wxrwx 1 mcmechan mcmechan 0 Mar 14 17:37 file

testing =r
-r-xrw-r-- 1 mcmechan mcmechan 0 Mar 14 17:37 file

-r--r----- 1 mcmechan mcmechan 0 Mar 14 17:37 file

testing +w
-rwxrwxrwx 1 mcmechan mcmechan 0 Mar 14 17:37 file

-rwxrwxrwx 1 mcmechan mcmechan 0 Mar 14 17:37 file

testing -w
-r-xrwxr-x 1 mcmechan mcmechan 0 Mar 14 17:37 file

chmod: file: new permissions are r-xrwxr-x, not r-xr-xr-x
-r-xrwxr-x 1 mcmechan mcmechan 0 Mar 14 17:37 file

testing =w
--wx-w-rw- 1 mcmechan mcmechan 0 Mar 14 17:37 file

--w-----w- 1 mcmechan mcmechan 0 Mar 14 17:37 file

testing +x
-rwxrwxrwx 1 mcmechan mcmechan 0 Mar 14 17:37 file

-rwxrwxrwx 1 mcmechan mcmechan 0 Mar 14 17:37 file

testing -x
-rwxrw-rw- 1 mcmechan mcmechan 0 Mar 14 17:37 file

chmod: file: new permissions are rwxrw-rw-, not rw-rw-rw-
-rwxrw-rw- 1 mcmechan mcmechan 0 Mar 14 17:37 file

testing =x
---x-wxr-x 1 mcmechan mcmechan 0 Mar 14 17:37 file

------x--x 1 mcmechan mcmechan 0 Mar 14 17:37 file


by the way be sure to reset the umask before compiling

if you change k above to 000 or
change the umask to 000 they all match
because if the file has perm 000 coreutils honours the umask
for + & - r/w/x but always clears the umask for = r/w/x after
setting the bits so a file at 777 with umask 124 will end up
at 202 after chmod =w despite setting a bit that was already
set to the value in the argument
and yes I do find this somewhat insane on coreutils part
when the manual page says that the bits in umask are not
affected when u/g/o/a are not given.
 		 	   		  


More information about the Aboriginal mailing list