[BusyBox] vfork_daemon_rexec

Russ Dill Russ.Dill at asu.edu
Tue Nov 25 22:19:45 UTC 2003


On Tue, 2003-11-25 at 05:47, Vladimir N. Oleynik wrote:
> Russ,
> 
> >>>(btw, vfork_daemon_rexec doesn't work for me, it just says
> >>>f: applet not found)
> >>
> >>Have your argv[0] valid name?
> > 
> > 
> > char **vfork_args;
> > int a = 0;
> > 
> > vfork_args = xcalloc(sizeof(char *), argc + 3);
> > while(*argv) {
> >     vfork_args[a++] = *argv;
> >     argv++;
> > }
> > vfork_args[a] = foreground_opt;
> > execvp("/proc/self/exe", vfork_args);
> 
> > vfork_args[0] = "/bin/busybox";
> > execv(vfork_args[0], vfork_args);
> 
> Ok. This two line must change to one line (not tested, only idea):
> execv("bin/busybox", vfork_args);
> 
> > bb_perror_msg_and_die("execv %s", vfork_args[0]);
> > 
> > argv[0] will always be /bin/busybox. argv[1] will probably be foreground
> > op. (execvp falls through since /proc/self/exe isn't implemented)
> > 
> > thus the command would be:
> > 
> > /bin/busybox -f
> 
> busybox applet is not daemon and don`t call vfork_rexec().
> Your argv[0] must have daemon name always or this strange problem.

This is the behavior with inetd. Thats what the code does. It fails the
execvp, then proceeds to set argv[0] to /bin/busybox (overwriting the
string inetd), and sets argv[1] to -f. busybox then sees argv[0] as
busybox, so it looks to agrv[1] to find the applet name. It finds -f.

There are a lot of other problems as well. All the applets using
vfork_daemon_rexec also call daemon, which returns after a failed fork
on uclinux (does nothing). A working vfork_daemon_rexec might look like
this:

void vfork_daemon_rexec(int nochdir, int noclose,
                int argc, char **argv, char *foreground_opt)
{
        int fd;
        char **vfork_args;
        int a = 0;
                                                                                                         
        if (setsid() == -1)
                return(-1);
                                                                                                         
        if (!nochdir)
                chdir("/");
                                                                                                         
        if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
                dup2(fd, STDIN_FILENO);
                dup2(fd, STDOUT_FILENO);
                dup2(fd, STDERR_FILENO);
                if (fd > 2)
                        close(fd);
        }
                                                                                                         
        vfork_args = xcalloc(sizeof(char *), argc + 3);
        vfork_args[a++] = "/bin/busybox";
        while(*argv) {
            vfork_args[a++] = *argv;
            argv++;
        }
        vfork_args[a++] = foreground_opt;
        vfork_args[a] = NULL;
        switch (vfork()) {
        case 0: /* child */
                /* Make certain we are not a session leader, or else we
                 * might reacquire a controlling terminal */
                if (vfork())
                        _exit(0);
                execv(vfork_args[0], vfork_args);
                bb_perror_msg_and_die("execv %s", vfork_args[0]);
        case -1: /* error */
                bb_perror_msg_and_die("vfork");
        default: /* parent */
                exit(0);
        }
}

-- 
Russ Dill <Russ.Dill at asu.edu>




More information about the busybox mailing list