[Toybox] "bad xform" not very helpful

David Seikel onefang_toybox at dave.isageek.net
Thu Sep 1 02:50:46 PDT 2022


On 2022-09-01 04:35:24, Rob Landley wrote:
> On 8/30/22 03:59, David Seikel wrote:
> > I'm good at reading code, but I know you are not.
> 
> As demonstrated below.

Well I had already cobbled together something that works for me, copying
stuff from other parts of toybox, that largely did what you describe
below.  I was mostly wondering if there was some easy calltoy() type
function I had missed.

My cobbled together one still has a TODO to return the output.

> On 8/31/22 20:33, David Seikel wrote:
> > On 2022-08-31 18:18:15, enh via Toybox wrote:
> >>    it does by default. that's what i turned off as a workaround for this bug.
> > 
> > Um how does one using toybox as the foundation for something else
> > actually call any random toy directly?  Is there a vararg calltoy()
> > function I missed?
> 
> You know how we're calling xexec() everywhere?
> 
>   $ grep -l xexec main.c lib/*.c toys/*/*.c | wc -l
>   30
> 
> That does:
> 
>   // Only recurse to builtin when we have multiplexer and !vfork context.
>   if (CFG_TOYBOX && !CFG_TOYBOX_NORECURSE)
>     if (toys.stacktop && !strchr(*argv, '/')) toy_exec(argv);
>   execvp(argv[0], argv);
> 
> That first part is calling toy_exec() out of main.c, and falling back to
> execvp() if it can't (or when it fails).
> 
> There's a lot of sanity checks in toy_exec() and the things it calls, checking
> if we need to re-exec to acquire SUID privileges, and measuring stack depth and
> refusing to recurse if it's gone too deep. But that's not actually required, the
> actual the actual CALL to the other command is just this bit at the end, lightly
> cleaned up to be usable out of context:
> 
>   // Run command
>   toy_init(toy_find(*argv), argv);
>   if (toys.which) {
>     toys.which->toy_main();
>     xexit();
>   }
> 
> You could also look at main() at the end of main.c to find the standalone init:
> 
>     // single command built standalone with no multiplexer is first list entry
>     toy_singleinit(toy_list, argv);
>     toy_list->toy_main();
> 
> (Using the first entry in toy_list instead of having toy_find() binary search
> for a neame...)
> 
> Or in toybox_main() there's this bit:
> 
>     char *ss = basename(s);
>     struct toy_list *tl = toy_find(ss);
> 
>     if (tl==toy_list && s!=toys.argv[1]) unknown(ss);
>     toy_exec_which(tl, toys.argv+1);
> 
> All toy_exec() does is call toy_find() and then call toy_exec_which() with the
> toy_list pointer instead of the name, but that splits them so it can add a
> special error check in between to prevent "toybox toybox toybox toybox toybox
> ls" from being recognized.
> 
> I didn't think starting at "main()" or reading the xexec() implementation in
> lib/ was an unreasonably high bar? There are other less obvious places you could
> have found it.
> 
> This "which = toy_find(); toy_singleinit(which, argv); which->toy_main();" trio
> is also done manually in sh.c to implement shell builtins, but I wouldn't expect
> you to find that on a casual browse without knowing what you're looking for.
> 
> The xpopen()/xrun() family of functions funnel into xpopen_both(), which is also
> a bit much to read (all that juggling pipes and nommu support), but it both
> calls xexec() and does:
> 
>       toy_init(toys.which, toys.argv);
>       toys.stacktop = 0;
>       toys.which->toy_main();
>       xexit();
> 
> to implement the "call ourselves again" case where argv is NULL when fork() is
> available. (No toy_find() there, it re-uses the existing toys.which to just
> recursively call the same command. The toys.stacktop is both to disable further
> recursion and to signal to the re-entered command that this is not the first
> time it's been called, but that has to do with command reentry, ala this bit of
> cpio.c:
> 
>     if (toys.stacktop) {
>       // xpopen() doesn't return from child due to vfork(), instead restarts
>       // with !toys.stacktop
>       pid = xpopen(0, &pipe, 0);
>       afd = pipe;
>     } else {
>       // child
>       toys.optflags |= FLAG_i;
>       xchdir(*toys.optargs);
>     }
> 
> Or this bit of tar.c:
> 
>         // Fork a copy of ourselves to handle extraction (reads from zip output
>         // pipe, writes to stdout).
>         pipefd[0] = pipefd[1];
>         pipefd[1] = 1;
>         pid = xpopen_both(0, pipefd);
>         close(pipefd[1]);
> 
> (This is because nommu systems can't do fork(), and vfork() requires calling
> exec() to unblock the parent, so xopen() can take a NULL argv to re-exec
> ourselves, in which case the parent will have a non-null toys.stacktop when it
> enters command_main() and the child will have a null one. The xpopen pipe(s) let
> the parent feed the child whatever info it needs; you can also do it through
> inherited environment variables.)
> 
> See also:
> https://landley.net/toybox/code.html#running
> 
> And:
> https://landley.net/toybox/code.html#:~:text=The%20following%20functions
> 
> Sorry I haven't done a video walkthrough of this part yet. Every time I look at
> prudetube it hits me with a fresh round of:

I hate prudetube as well, and avoid it.  Especially for things about
coding, coz you can't copy paste text from a video.

> https://youtu.be/IPXukSZhTuI
> https://youtu.be/punLD6zM2bI
> https://youtu.be/IdE_ADys95c
> https://youtu.be/zOV1DDMenrU

So I'm not clicking on whatever those are.

> And I go "maybe I should find another video hosting solution"...

-- 
A big old stinking pile of genius that no one wants
coz there are too many silver coated monkeys in the world.


More information about the Toybox mailing list