On Wed, 13 Sep 2017, Martijn van Duren wrote:
> When reading up on setsid I found ERRORS section confusing. It indicates 
> that EPERM may occur if the process group ID of a process other than the 
> calling process matches the process ID of the calling process.
> 
> To me this appears to be in contradiction with the fork manpage, which 
> states: The child process has a unique process ID, which also does not 
> match any existing process group ID.
> 
> So how can the former occur if the latter states that it's unique?

It may start unique, but PGIDs are shared among processes and a process 
change move among process groups.  Put those together and you get a 
program such as the following, which demonstrates a setsid() call failing 
because the process group with the same ID as the target process already 
exists.

So nope, the manpage is correct as is.


Philip Guenther

--------
#include <sys/wait.h>
#include <err.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

int
main(void)
{
        pid_t c1, c2, g;
        ssize_t len;
        int fds[2];
        int ch, status;

        printf("p:\t%d\t%d\n", getpid(), getpgrp());
        if (pipe(fds))
                err(1, "pipe");
        if ((c1 = fork()) == -1)
                err(1, "fork %d", 1);
        if (c1 == 0) {
                close(fds[0]);
                printf("c1:\t%d\t%d\n", getpid(), getpgrp());
                if (setpgrp(0, 0))
                        err(1, "setpgrp");
                printf("c1:\t%d\t%d\n", getpid(), getpgrp());
                if (write(fds[1], "", 1) != 1)
                        err(1, "write");
                close(fds[1]);
                sleep(60);
                _exit(0);
        }
        close(fds[1]);
        if ((len = read(fds[0], &ch, 1)) == -1)
                err(1, "read");
        if (len != 1) {
                waitpid(c1, &status, 0);
                errx(1, "c1: %#x", status);
        }
        close(fds[0]);

        if (pipe(fds))
                err(1, "pipe");
        if ((c2 = fork()) == -1)
                err(1, "fork %d", 2);
        if (c2 == 0) {
                close(fds[0]);
                printf("c2:\t%d\t%d\n", getpid(), getpgrp());
                if (setpgrp(0, 0))
                        err(1, "setpgrp");
                printf("c2:\t%d\t%d\n", getpid(), getpgrp());
                if ((g = fork()) == -1)
                        err(1, "fork %d", 3);
                if (g == 0) {
                        printf("g:\t%d\t%d\n", getpid(), getpgrp());
                        close(fds[0]);
                        close(fds[1]);
                        sleep(60);
                        _exit(0);
                }
                if ((len = write(fds[1], &g, sizeof g)) == -1)
                        err(1, "write pid");
                if (len != (int)sizeof g)
                        errx(1, "write %zd != %zu", len, sizeof g);
                close(fds[1]);
                if (setpgid(0, c1))
                        err(1, "setpgrp");
                printf("c2:\t%d\t%d\n", getpid(), getpgrp());
                if (setsid())
                        err(1, "setsid");
                _exit(0);
        }

        waitpid(c2, &status, 0);
        if (kill(c1, SIGINT))
                err(1, "kill");

        return 0;
}

Reply via email to