[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