Skip to content
Advertisement

setpgid for Child Zombie Process Gives ESRCH instead of EACCES?

According to the man setpgid(2) page,

EACCES An attempt was made to change the process group ID of one of the children of the calling process and the child had already performed an execve(2) (setpgid(), setpgrp()).

ESRCH For getpgid(): pid does not match any process. For setpgid(): pid is not the calling process and not a child of the calling process.

The errno should be EACCES according to the description. But why do I get ESRCH instead?

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

void print_errno() {
  if (errno == EACCES) printf("errno: EACCESn");
  else if (errno == EPERM) printf("errno: EPERMn");
  else if (errno == ESRCH) printf("errno: ESRCHn");
}

#define CHECK(syscall, msg) do {                    
    if ((syscall) == -1) {                          
      print_errno();                                
      perror(msg);                                  
      _exit(1);                                     
    }                                               
  } while(0)

int main () {
  int ls_pid;
  char *ls_argv[] = { "ls", NULL };

  CHECK(ls_pid = fork(), "fork error");
  if (!ls_pid) {
    CHECK(execvp(ls_argv[0], ls_argv), "execvp error");
  } else {
    sleep(2);
    CHECK(setpgid(ls_pid, ls_pid), "setpgid error");
    CHECK(wait(NULL), "wait error");

    printf("Finishn");
  }
}

Advertisement

Answer

The specification of setpgid does not say what error is to be returned by setpgid when the pid argument refers to a zombie child of the calling process, whether or not it called execve. Thus, this is not technically a bug.

ESRCH makes sense if you consider that zombies aren’t really processes anymore; they’re just the data that needs to stick around until someone gets around to calling wait. For instance, it would make a lot of sense for kill to fail with ESRCH when applied to a zombie.

I’d like to close with some observations on how this is actually implemented, but, alas, I looked at the source code for setpgid in Linux and could not figure out what it would return for this case, because Linux’s namespace support has turned many process-related syscalls into horrible mazes of spaghetti. So then I tried to look at FreeBSD instead and I couldn’t even find the relevant part of the source code, because the file-level organization of the FreeBSD kernel is incomprehensible. So you’re going to have to do without, sorry.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement