how to recreate the current process? - Unix

This is a discussion on how to recreate the current process? - Unix ; Hi group, I'm trying to allow a process to recreate itself by forking and execve'ing itself (argv[0]) in the child. The parent should exit ignoring SIGCHLD. The code below works only the first time. It seems that the child isn't ...

+ Reply to Thread
Results 1 to 10 of 10

Thread: how to recreate the current process?

  1. how to recreate the current process?

    Hi group,

    I'm trying to allow a process to recreate itself by forking and
    execve'ing itself (argv[0]) in the child. The parent should exit
    ignoring SIGCHLD.
    The code below works only the first time. It seems that the child isn't
    able to mask its own signals... any idea?

    Thanks in advance!

    ---------8-->---------8-->---------8-->---------8-->---------8-->
    #include
    #include
    #include
    #include
    #include
    #include

    #include /* printf */
    #include /* exit */

    static char **args;
    void sig_handler(int);

    void
    sig_handler(int sig)
    {
    pid_t pid;

    pid = fork();

    if(pid < 0) {
    exit(EXIT_FAILURE);
    }

    if(pid > 0)
    {
    printf("parent exiting after fork");
    exit(EXIT_SUCCESS);
    }

    printf("i'm the child\n");
    if(execve(args[0], &args[0], NULL) == -1)
    printf("%s\n", strerror(errno));
    }

    int
    main(int argc, char **argv)
    {
    signal( SIGUSR1, sig_handler );
    signal( SIGCHLD, SIG_IGN );

    args = argv;
    printf("start\n");

    sleep(1);

    printf("sending signal to myself (%u)\n", getpid());
    kill(getpid(), SIGUSR1);

    return (0);
    }
    ---------8-->---------8-->---------8-->---------8-->---------8-->

    --
    Pietro Cerutti

    PGP Public Key:
    http://gahr.ch/pgp

  2. Re: how to recreate the current process?

    On Nov 7, 9:01 am, Pietro Cerutti
    wrote:
    > Hi group,
    >
    > I'm trying to allow a process to recreate itself by forking and
    > execve'ing itself (argv[0]) in the child. The parent should exit
    > ignoring SIGCHLD.
    > The code below works only the first time. It seems that the child isn't
    > able to mask its own signals... any idea?


    Several things:

    1. On some systems, a handler installed by signal() is only called the
    first time the signal arrives; the signal disposition is set back to
    SIG_DFL afterwards. So when you try to do this a second time, the
    handler is no longer active. It's nothing to do with it being the
    parent or child. Either call signal() again or else use sigaction()
    and clear the SA_RESETHAND flag. Also, a terminology issue, you don't
    mean "mask" but "handle". Masking signals is a way to temporarily
    prevent them from being seen.

    2. According to POSIX you aren't allowed to call fork() and exec() in
    a signal handler. The only things you are allowed to do are (a) set a
    flag of type `volatile sig_atomic_t` or (b) call longjmp(). So for
    portability you should use one of these methods to have the signal
    handler tell the main program to do whatever is required.

    3. What's the point of all this messing around with fork() and signal
    handlers? If you want to start your program from the beginning just
    call execve() by itself. That's what it does.

    4. argv[0] doesn't necessarily contain the path to your program's
    binary.


  3. Re: how to recreate the current process?

    fjblurt@yahoo.com wrote:
    > On Nov 7, 9:01 am, Pietro Cerutti
    > wrote:
    >> Hi group,
    >>
    >> I'm trying to allow a process to recreate itself by forking and
    >> execve'ing itself (argv[0]) in the child. The parent should exit
    >> ignoring SIGCHLD.
    >> The code below works only the first time. It seems that the child isn't
    >> able to mask its own signals... any idea?

    >
    > Several things:


    First off, thank you very much for your analysis and complete answer!

    >
    > 1. On some systems, a handler installed by signal() is only called the
    > first time the signal arrives; the signal disposition is set back to
    > SIG_DFL afterwards. So when you try to do this a second time, the
    > handler is no longer active. It's nothing to do with it being the
    > parent or child. Either call signal() again or else use sigaction()
    > and clear the SA_RESETHAND flag. Also, a terminology issue, you don't
    > mean "mask" but "handle". Masking signals is a way to temporarily
    > prevent them from being seen.


    I know. But calling signal() on main should solve this problem,
    shouldn't it?

    >
    > 2. According to POSIX you aren't allowed to call fork() and exec() in
    > a signal handler. The only things you are allowed to do are (a) set a
    > flag of type `volatile sig_atomic_t` or (b) call longjmp(). So for
    > portability you should use one of these methods to have the signal
    > handler tell the main program to do whatever is required.


    Is it also valid for signal handler which are only called from within
    the application? I mean, nobody's going to delivery a SIGUSR1 to my
    application. Since it's not threaded, it should be safe to do whatever I
    want inside the handler.

    >
    > 3. What's the point of all this messing around with fork() and signal
    > handlers? If you want to start your program from the beginning just
    > call execve() by itself. That's what it does.


    hem.. right o_O....

    >
    > 4. argv[0] doesn't necessarily contain the path to your program's
    > binary.
    >


    How not?


    --
    Pietro Cerutti

    PGP Public Key:
    http://gahr.ch/pgp

  4. Re: how to recreate the current process?

    On Nov 8, 8:23 am, Pietro Cerutti
    wrote:
    > fjbl...@yahoo.com wrote:

    [snip]
    > > 4. argv[0] doesn't necessarily contain the path to your program's
    > > binary.

    >
    > How not?


    In the target program, argv[0] is a value that is explicitly set by
    the program that exec()s the target. By convention, argv[0] contains
    the path (as expressed to the exec()ing program) of the binary, but
    this is not guaranteed by the system. Indeed, some applications are
    explicitly started with values other than a path in argv[0], in order
    to invoke special or unusual behaviour.

    To show you what I mean, consider the following example:

    lpitcher@merlin:~/code/argv0$ # nothing up my sleeve
    lpitcher@merlin:~/code/argv0$ ls
    argv0.c argv0launch.c

    lpitcher@merlin:~/code/argv0$ # first, a program that prints it's
    argv[0]
    lpitcher@merlin:~/code/argv0$ cat argv0.c
    #include
    #include

    int main (int argc, char *argv[])
    {
    if (argc > 0) printf("argv[0] is \"%s\"\n",argv[0]);
    return EXIT_SUCCESS;
    }

    lpitcher@merlin:~/code/argv0$ # which we compile
    lpitcher@merlin:~/code/argv0$ cc -o argv0 argv0.c

    lpitcher@merlin:~/code/argv0$ # and run (notice the value it prints)
    lpitcher@merlin:~/code/argv0$ ./argv0
    argv[0] is "./argv0"

    lpitcher@merlin:~/code/argv0$ # now, a program that exec()s the
    first pgm
    lpitcher@merlin:~/code/argv0$ cat argv0launch.c
    #include
    #include
    #include

    int main(void)
    {
    printf("Next messages from argv0 program\n");
    execl("argv0","nasty nasty nasty",NULL);
    return EXIT_FAILURE;
    }

    lpitcher@merlin:~/code/argv0$ cc -o argv0launch argv0launch.c

    lpitcher@merlin:~/code/argv0$ # now we use this program to launch
    the other
    lpitcher@merlin:~/code/argv0$ # Watch the message that comes from
    the argv0.c pgm
    lpitcher@merlin:~/code/argv0$ ./argv0launch
    Next messages from argv0 program
    argv[0] is "nasty nasty nasty"

    lpitcher@merlin:~/code/argv0$ # See, in this case, argv[0] is *not*
    the path
    lpitcher@merlin:~/code/argv0$

    HTH
    --
    Lew




  5. Re: how to recreate the current process?

    fjblurt@yahoo.com writes:

    [...]

    > 2. According to POSIX you aren't allowed to call fork() and exec() in
    > a signal handler. The only things you are allowed to do are (a) set a
    > flag of type `volatile sig_atomic_t` or (b) call longjmp().


    According to UNIX(*) (IEEE Std 1003.1), both fork and exec are
    async-signal-safe and can be called from signal handlers. The actual
    requirement is only:

    In the presence of signals, all functions defined by this
    volume of IEEE Std 1003.1-2001 shall behave as defined when
    called from or interrupted by a signal-catching function, with
    a single exception: when a signal interrupts an unsafe
    function and the signal-catching function calls an unsafe
    function, the behavior is undefined.
    (SUS, 'Signal Concepts')

  6. Re: how to recreate the current process?

    On Wed, 07 Nov 2007 10:47:17 -0800, fjblurt@yahoo.com wrote:

    >2. According to POSIX you aren't allowed to call fork() and exec() in
    >a signal handler. The only things you are allowed to do are (a) set a
    >flag of type `volatile sig_atomic_t` or (b) call longjmp(). So for
    >portability you should use one of these methods to have the signal
    >handler tell the main program to do whatever is required.


    Is that true? I don't have a copy of the standard to hand, but
    according to:
    https://www.securecoding.cert.org/co...Comments=false
    (or http://tinyurl.com/yovd6e)

    any of the following are supposed to be async-signal-safe and
    therefore callable from a signal handler:

    _Exit()
    _exit()
    abort()
    accept()
    access()
    aio_error()
    aio_return()
    aio_suspend()
    alarm()
    bind()
    cfgetispeed()
    cfgetospeed()
    cfsetispeed()
    cfsetospeed()
    chdir()
    chmod()
    chown()
    clock_gettime()
    close()
    connect()
    creat()
    dup()
    dup2()
    execle()
    execve()
    fchmod()
    fchown()
    fcntl()
    fdatasync()
    fork() <<<<<<<<<<<<<<<< !!!
    fpathconf()
    fstat()
    fsync()
    ftruncate()
    getegid()
    geteuid()
    getgid()
    getgroups()
    getpeername()
    getpgrp()
    getpid()
    getppid()
    getsockname()
    getsockopt()
    getuid()
    kill()
    link()
    listen()
    lseek()
    lstat()
    mkdir()
    mkfifo()
    open()
    pathconf()
    pause()
    pipe()
    poll()
    posix_trace_event()
    pselect()
    raise()
    read()
    readlink()
    recv()
    recvfrom()
    recvmsg()
    rename()
    rmdir()
    select()
    sem_post()
    send()
    sendmsg()
    sendto()
    setgid()
    setpgid()
    setsid()
    setsockopt()
    setuid()
    shutdown()
    sigaction()
    sigaddset()
    sigdelset()
    sigemptyset()
    sigfillset()
    sigismember()
    sleep()
    signal()
    sigpause()
    sigpending()
    sigprocmask()
    sigqueue()
    sigset()
    sigsuspend()
    sockatmark()
    socket()
    socketpair()
    stat()
    symlink()
    sysconf()
    tcdrain()
    tcflow()
    tcflush()
    tcgetattr()
    tcgetpgrp()
    tcsendbreak()
    tcsetattr()
    tcsetpgrp()
    time()
    timer_getoverrun()
    timer_gettime()
    timer_settime()
    times()
    umask()
    uname()
    unlink()
    utime()
    wait()
    waitpid()
    write()
    --
    PGP key ID 0xEB7180EC

  7. Re: how to recreate the current process?

    fjblurt wrote:

    > According to POSIX you aren't allowed to call fork() and exec() in
    > a signal handler.


    You are allowed to call fork(), execle() and execve(). They are in
    the list of async-signal-safe functions in XSH section 2.4.3.

    > The only things you are allowed to do are (a) set a
    > flag of type `volatile sig_atomic_t` or (b) call longjmp().


    Actually, longjmp() and siglongjmp() are _not_ in the list of
    async-signal-safe functions. That's because for functions in that
    list "applications may invoke them, without restriction, from
    signal-catching functions", but for [sig]longjmp() there are
    restrictions:

    "longjmp() shall execute correctly in contexts of interrupts,
    signals, and any of their associated functions. However, if
    longjmp() is invoked from a nested signal handler (that is, from
    a function invoked as a result of a signal raised during the
    handling of another signal), the behavior is undefined."

    --
    Geoff Clare

  8. Re: how to recreate the current process?

    Pietro Cerutti wrote:
    >> 4. argv[0] doesn't necessarily contain the path to your program's
    >> binary.
    >>

    >
    > How not?


    Explained elsewhere, but note that many systems provide a way to get a
    best-guess answer. For instance, Solaris has getexecname(). It comes
    with a few caveats but is generally correct.

    HT

  9. Re: how to recreate the current process?

    On Nov 8, 5:23 am, Pietro Cerutti
    wrote:
    > fjbl...@yahoo.com wrote:
    > > On Nov 7, 9:01 am, Pietro Cerutti
    > > wrote:
    > >> Hi group,

    >
    > >> I'm trying to allow a process to recreate itself by forking and
    > >> execve'ing itself (argv[0]) in the child. The parent should exit
    > >> ignoring SIGCHLD.
    > >> The code below works only the first time. It seems that the child isn't
    > >> able to mask its own signals... any idea?

    >
    > > Several things:

    >
    > First off, thank you very much for your analysis and complete answer!


    You're welcome. Sorry it was mostly wrong

    > > 1. On some systems, a handler installed by signal() is only called the
    > > first time the signal arrives; the signal disposition is set back to
    > > SIG_DFL afterwards. So when you try to do this a second time, the
    > > handler is no longer active. It's nothing to do with it being the
    > > parent or child. Either call signal() again or else use sigaction()
    > > and clear the SA_RESETHAND flag. Also, a terminology issue, you don't
    > > mean "mask" but "handle". Masking signals is a way to temporarily
    > > prevent them from being seen.

    >
    > I know. But calling signal() on main should solve this problem,
    > shouldn't it?


    Indeed it should, and does. Looking at it again, I see what's wrong
    -- it is an issue with signal masking after all. SIGUSR1 is
    automatically masked on entry to the signal handler, and possibly
    unmasked when it exits (depending on the current signal mask as set by
    sigprocmask()). But in this case, the signal handler never exits, and
    the signal mask is preserved across exec(). You can't avoid having
    SIGUSR1 masked when the signal handler is called, but you could unmask
    it manually: for instance, by calling sigprocmask() at the top of
    main(). After making that change it works as expected.

    > > 2. According to POSIX you aren't allowed to call fork() and exec() in
    > > a signal handler. The only things you are allowed to do are (a) set a
    > > flag of type `volatile sig_atomic_t` or (b) call longjmp(). So for
    > > portability you should use one of these methods to have the signal
    > > handler tell the main program to do whatever is required.

    >
    > Is it also valid for signal handler which are only called from within
    > the application? I mean, nobody's going to delivery a SIGUSR1 to my
    > application. Since it's not threaded, it should be safe to do whatever I
    > want inside the handler.


    As several people pointed out, my advice is wrong. fork() and exec()
    are legal under various Unix standards. I was thinking of ANSI C
    whose requirements are much more stringent, but even then I'm not sure
    I described it correctly. Sorry for the confusion.

    Hope this helps!


  10. Re: how to recreate the current process?

    fjblurt@yahoo.com wrote:
    > On Nov 8, 5:23 am, Pietro Cerutti
    > wrote:
    >> fjbl...@yahoo.com wrote:
    >>> On Nov 7, 9:01 am, Pietro Cerutti
    >>> wrote:
    >>>> Hi group,
    >>>> I'm trying to allow a process to recreate itself by forking and
    >>>> execve'ing itself (argv[0]) in the child. The parent should exit
    >>>> ignoring SIGCHLD.
    >>>> The code below works only the first time. It seems that the child isn't
    >>>> able to mask its own signals... any idea?
    >>> Several things:

    >> First off, thank you very much for your analysis and complete answer!

    >
    > You're welcome. Sorry it was mostly wrong
    >
    >>> 1. On some systems, a handler installed by signal() is only called the
    >>> first time the signal arrives; the signal disposition is set back to
    >>> SIG_DFL afterwards. So when you try to do this a second time, the
    >>> handler is no longer active. It's nothing to do with it being the
    >>> parent or child. Either call signal() again or else use sigaction()
    >>> and clear the SA_RESETHAND flag. Also, a terminology issue, you don't
    >>> mean "mask" but "handle". Masking signals is a way to temporarily
    >>> prevent them from being seen.

    >> I know. But calling signal() on main should solve this problem,
    >> shouldn't it?

    >
    > Indeed it should, and does. Looking at it again, I see what's wrong
    > -- it is an issue with signal masking after all. SIGUSR1 is
    > automatically masked on entry to the signal handler, and possibly
    > unmasked when it exits (depending on the current signal mask as set by
    > sigprocmask()). But in this case, the signal handler never exits, and
    > the signal mask is preserved across exec(). You can't avoid having
    > SIGUSR1 masked when the signal handler is called, but you could unmask
    > it manually: for instance, by calling sigprocmask() at the top of
    > main(). After making that change it works as expected.


    Yep, good shot!

    >
    >>> 2. According to POSIX you aren't allowed to call fork() and exec() in
    >>> a signal handler. The only things you are allowed to do are (a) set a
    >>> flag of type `volatile sig_atomic_t` or (b) call longjmp(). So for
    >>> portability you should use one of these methods to have the signal
    >>> handler tell the main program to do whatever is required.

    >> Is it also valid for signal handler which are only called from within
    >> the application? I mean, nobody's going to delivery a SIGUSR1 to my
    >> application. Since it's not threaded, it should be safe to do whatever I
    >> want inside the handler.

    >
    > As several people pointed out, my advice is wrong. fork() and exec()
    > are legal under various Unix standards. I was thinking of ANSI C
    > whose requirements are much more stringent, but even then I'm not sure
    > I described it correctly. Sorry for the confusion.


    Nope, thanks for all!

    >
    > Hope this helps!
    >



    --
    Pietro Cerutti

    PGP Public Key:
    http://gahr.ch/pgp

+ Reply to Thread