/* Demonstrate job control. WH 1994 DEC/1996 NOV Stopping and restarting a child process group. Giving terminal to child and getting it back. */ #define SRCDIR "/home/??????" /* ## CHANGE ## to directory containing job.c */ #define TRACEFILE "/dev/console" /* trace output file */ #include #include #include #include #include #include #include #include void prompt(void); void change_tty_pg(pid_t pid, int ttyd); pid_t wait_onchild(pid_t pid); static FILE *ftrace; int main() { pid_t child_pgid,main_pgid; int ttyd,pgrp; int c; fprintf(stderr,"Trace messages will go to " TRACEFILE "\n"); if ((ftrace = fopen(TRACEFILE,"w")) == NULL) {fprintf(stderr,"Can not open " TRACEFILE "\n"); exit(1); } fprintf(ftrace,"\nNew run of jobcntl.\n"); ttyd = open(ctermid(NULL) /* = "/dev/tty" */ ,O_RDWR,0700); main_pgid = getpid(); pgrp = tcgetpgrp(ttyd); fprintf(ftrace,"Process group of terminal is %d.\n",pgrp); fflush(ftrace); if ((child_pgid = fork()) == -1) {perror("jobcntl"); exit(1); } else if (child_pgid == 0) /* child */ {close(ttyd); fclose(ftrace); setpgid(0,0); /* Make child a process group leader */ execlp(SRCDIR "job","job",NULL); perror("child of jobcntl"); _exit(1); } else /* parent */ {fprintf(ftrace,"Child PGID is %d.\n",child_pgid); setpgid(child_pgid,0); /* Make child a process group leader */ /* Done in parent to defeat race */ prompt(); for (;;) switch (c = getchar()) {case 'z': /* suspend process group */ fprintf(ftrace,"SIGTSTP sent to %d\n",-child_pgid); kill(-child_pgid,SIGTSTP); /* killpg(child_pgid,SIGTSTP); */ break; case 'c': /* restart process group */ fprintf(ftrace,"SIGCONT sent to %d\n",-child_pgid); kill(-child_pgid,SIGCONT); break; case 'f': /* bring child pg to foreground */ change_tty_pg(child_pgid,ttyd); /* give tty to child pg */ kill(-child_pgid,SIGCONT); /* restart child pg */ /* wait till child changes status */ while (0 == wait_onchild(-child_pgid)) sleep(1); change_tty_pg(main_pgid,ttyd); /* reclaim terminal */ break; case EOF: case 'q': return 0; case '\n': prompt(); break; } } } void prompt(void) { printf("\nState: T=sTopped, S=Sleeping, R=Runable, O=running, Z=Zombie\n"); system("ps -o pid,ppid,pgid,tty,s,comm"); printf("jobcntl:\n" " z to suspend child pg\n" " c to continue/restart child pg\n" " f to foreground and restart child" " (Once in child, background child with ^Z)\n" " p to get ps listing and prompt\n" " q to quit\n Enter choice: "); fflush(stdout); } void change_tty_pg(pid_t pid,int ttyd) { fprintf(ftrace,"tty PG was %d and ",tcgetpgrp(ttyd)); signal(SIGTTOU,SIG_IGN); if (-1 == tcsetpgrp(ttyd,pid)) perror("tcsetpgrp (child no longer exists?)"); /* should reset SIGTTOU to previous disposition */ fprintf(ftrace,"is now %d\n",tcgetpgrp(ttyd)); } pid_t wait_onchild(pid_t pid) { int status; pid_t retpid; retpid = waitpid(pid,&status, WNOHANG | WUNTRACED ); fprintf(ftrace,"wait on %d returned with pid %d ",pid, retpid); if (retpid == 0) fprintf(ftrace,"- No child wishes to report.\n"); else {fprintf(ftrace,"raw status: %04x (in hex)\n",status); if (WIFEXITED(status)) fprintf(ftrace,"exit status: %02x\n",WEXITSTATUS(status)); if (WIFSIGNALED(status)) fprintf(ftrace,"signal status: %02x\n",WTERMSIG(status)); if (WIFSTOPPED(status)) fprintf(ftrace,"stopped status: %02x\n",WSTOPSIG(status)); } return(retpid); }