#include <sys/types.h> /* include this before any other sys headers */
#include <sys/wait.h> /* header for waitpid() and various macros */
#include <signal.h> /* header for signal functions */
#include <stdio.h> /* header for fprintf() */
#include <unistd.h> /* header for fork() */
void sig_chld(int); /* prototype for our SIGCHLD handler */
int main()
{
struct sigaction act;
pid_t pid;
/* Assign sig_chld as our SIGCHLD handler */
act.sa_handler = sig_chld;
/* We don't want to block any other signals in this example */
sigemptyset(&act.sa_mask);
/*
* We're only interested in children that have terminated, not ones
* which have been stopped (eg user pressing control-Z at terminal)
*/
act.sa_flags = SA_NOCLDSTOP;
/*
* Make these values effective. If we were writing a real
* application, we would probably save the old value instead of
* passing NULL.
*/
if (sigaction(SIGCHLD, &act, NULL) < 0)
{
fprintf(stderr, "sigaction failed\n");
return 1;
}
/* Fork */
switch (pid = fork())
{
case -1:
fprintf(stderr, "fork failed\n");
return 1;
case 0: /* child -- finish straight away */
_exit(7); /* exit status = 7 */
default: /* parent */
sleep(10); /* give child time to finish */
}
return 0;
}
/*
* The signal handler function -- only gets called when a SIGCHLD
* is received, ie when a child terminates
*/
void sig_chld(int signo)
{
int status, child_val;
/* Wait for any child without blocking */
if (waitpid(-1, &status, WNOHANG) < 0)
{
/*
* calling standard I/O functions like fprintf() in a
* signal handler is not recommended, but probably OK
* in toy programs like this one.
*/
fprintf(stderr, "waitpid failed\n");
return;
}
/*
* We now have the info in 'status' and can manipulate it using
* the macros in wait.h.
*/
if (WIFEXITED(status)) /* did child exit normally? */
{
child_val = WEXITSTATUS(status); /* get child's exit status */
printf("child's exited normally with status %d\n", child_val);
}
}
#define _KMEMUSER
#include <sys/proc.h>
#include <kvm.h>
#include <fcntl.h>
char regexpstr[256];
#define INIT register char *sp=regexpstr;
#define GETC() (*sp++)
#define PEEKC() (*sp)
#define UNGETC(c) (--sp)
#define RETURN(pointer) return(pointer);
#define ERROR(val)
#include <regexp.h>
pid_t
getpidbyname(char *name,pid_t skipit)
{
kvm_t *kd;
char **arg;
int error;
char *p_name=NULL;
char expbuf[256];
char **freeme;
int curpid;
struct user * cur_user;
struct user myuser;
struct proc * cur_proc;
if((kd=kvm_open(NULL,NULL,NULL,O_RDONLY,NULL))==NULL){
return(-1);
}
sprintf(regexpstr,"^.*/%s$",name);
compile(NULL,expbuf,expbuf+256,'\0');
while(cur_proc=kvm_nextproc(kd)){
curpid = cur_proc->p_pid;
if((cur_user=kvm_getu(kd,cur_proc))!=NULL){
error=kvm_getcmd(kd,cur_proc,cur_user,&arg,NULL);
if(error==-1){
if(cur_user->u_comm[0]!='\0'){
p_name=cur_user->u_comm;
}
}
else{
p_name=arg[0];
}
}
if(p_name){
if(!strcmp(p_name,name)){
if(error!=-1){
free(arg);
}
if(skipit!=-1 && ourretval==skipit){
ourretval=-1;
}
else{
close(fd);
break;
}
break;
}
else{
if(step(p_name,expbuf)){
if(error!=-1){
free(arg);
}
break;
}
}
}
if(error!=-1){
free(arg);
}
p_name=NULL;
}
kvm_close(kd);
if(p_name!=NULL){
return(curpid);
}
return (-1);
}
pid_t
getpidbyname(char *name,pid_t skipit)
{
DIR *dp;
struct dirent *dirp;
prpsinfo_t retval;
int fd;
pid_t ourretval=-1;
if((dp=opendir("/proc"))==NULL){
return -1;
}
chdir("/proc");
while((dirp=readdir(dp))!=NULL){
if(dirp->d_name[0]!='.'){
if((fd=open(dirp->d_name,O_RDONLY))!=-1){
if(ioctl(fd,PIOCPSINFO,&retval)!=-1){
if(!strcmp(retval.pr_fname,name)){
ourretval=(pid_t)atoi(dirp->d_name);
if(skipit!=-1 && ourretval==skipit){
ourretval=-1;
}
else{
close(fd);
break;
}
}
}
close(fd);
}
}
}
closedir(dp);
return ourretval;
}
#include <stdio.h>
#include <procinfo.h>
int getprocs(struct procsinfo *, int, struct fdsinfo *,
int, pid_t *, int);
pid_t getpidbyname(char *name, pid_t *nextPid)
{
struct procsinfo pi;
pid_t retval = (pid_t) -1;
pid_t pid;
pid = *nextPid;
while(1)
{
if(getprocs(&pi, sizeof pi, 0, 0, &pid, 1) != 1)
break;
if(!strcmp(name, pi.pi_comm))
{
retval = pi.pi_pid;
*nextPid = pid;
break;
}
}
return retval;
}
int main(int argc, char *argv[])
{
int curArg;
pid_t pid;
pid_t nextPid;
if(argc == 1)
{
printf("syntax: %s <program> [program ...]\n",argv[0]);
exit(1);
}
for(curArg = 1; curArg < argc; curArg++)
{
printf("Process IDs for %s\n", argv[curArg]);
for(nextPid = 0, pid = 0; pid != -1; )
if((pid = getpidbyname(argv[curArg], &nextPid)) != -1)
printf("\t%d\n", pid);
}
}
#include <stdio.h> /* FILE, sprintf, fgets, puts */
#include <stdlib.h> /* atoi, exit, EXIT_SUCCESS */
#include <string.h> /* strtok, strcmp */
#include <sys/types.h> /* pid_t */
#include <sys/wait.h> /* WIFEXITED, WEXITSTATUS */
char *procname(pid_t pid)
{
static char line[133], command[80], *linep, *token, *cmd;
FILE *fp;
int status;
if (0 == pid) return (char *)0;
sprintf(command, "ps -p %d 2>/dev/null", pid);
fp = popen(command, "r");
if ((FILE *)0 == fp) return (char *)0;
/* read the header line */
if ((char *)0 == fgets(line, sizeof line, fp))
{
pclose(fp);
return (char *)0;
}
/* figure out where the command name is from the column headings.
* (BSD-ish machines put the COMMAND in the 5th column, while SysV
* seems to put CMD or COMMAND in the 4th column.)
*/
for (linep = line; ; linep = (char *)0)
{
if ((char *)0 == (token = strtok(linep, " \t\n")))
{
pclose(fp);
return (char *)0;
}
if (0 == strcmp("COMMAND", token) || 0 == strcmp("CMD", token))
{ /* we found the COMMAND column */
cmd = token;
break;
}
}
/* read the ps(1) output line */
if ((char *)0 == fgets(line, sizeof line, fp))
{
pclose(fp);
return (char *)0;
}
/* grab the "word" underneath the command heading... */
if ((char *)0 == (token = strtok(cmd, " \t\n")))
{
pclose(fp);
return (char *)0;
}
status = pclose(fp);
if (!WIFEXITED(status) || 0 != WEXITSTATUS(status))
return (char *)0;
return token;
}
int main(int argc, char *argv[])
{
puts(procname(atoi(argv[1])));
exit(EXIT_SUCCESS);
}
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
/* closeall() -- close all FDs >= a specified value */
void closeall(int fd)
{
int fdlimit = sysconf(_SC_OPEN_MAX);
while (fd < fdlimit)
close(fd++);
}
/* daemon() -- detach process from user and disappear into the background
* returns -1 on failure, but you can't do much except exit in that case
* since we may already have forked. This is based on the BSD version,
* so the caller is responsible for things like the umask, etc.
*/
/* believed to work on all Posix systems */
int daemon(int nochdir, int noclose)
{
switch (fork())
{
case 0: break;
case -1: return -1;
default: _exit(0); /* exit the original process */
}
if (setsid() < 0) /* shoudn't fail */
return -1;
/* dyke out this switch if you want to acquire a control tty in */
/* the future -- not normally advisable for daemons */
switch (fork())
{
case 0: break;
case -1: return -1;
default: _exit(0);
}
if (!nochdir)
chdir("/");
if (!noclose)
{
closeall(0);
open("/dev/null",O_RDWR);
dup(0); dup(0);
}
return 0;
}
/* fork2() -- like fork, but the new process is immediately orphaned
* (won't leave a zombie when it exits)
* Returns 1 to the parent, not any meaningful pid.
* The parent cannot wait() for the new process (it's unrelated).
*/
/* This version assumes that you *haven't* caught or ignored SIGCHLD. */
/* If you have, then you should just be using fork() instead anyway. */
int fork2()
{
pid_t pid;
int rc;
int status;
if (!(pid = fork()))
{
switch (fork())
{
case 0: return 0;
case -1: _exit(errno); /* assumes all errnos are <256 */
default: _exit(0);
}
}
if (pid < 0 || waitpid(pid,&status,0) < 0)
return -1;
if (WIFEXITED(status))
if (WEXITSTATUS(status) == 0)
return 1;
else
errno = WEXITSTATUS(status);
else
errno = EINTR; /* well, sort of :-) */
return -1;
}
An example of using the above functions:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <errno.h>
int daemon(int,int);
int fork2(void);
void closeall(int);
#define TCP_PORT 8888
void errexit(const char *str)
{
syslog(LOG_INFO, "%s failed: %d (%m)", str, errno);
exit(1);
}
void errreport(const char *str)
{
syslog(LOG_INFO, "%s failed: %d (%m)", str, errno);
}
/* the actual child process is here. */
void run_child(int sock)
{
FILE *in = fdopen(sock,"r");
FILE *out = fdopen(sock,"w");
int ch;
setvbuf(in, NULL, _IOFBF, 1024);
setvbuf(out, NULL, _IOLBF, 1024);
while ((ch = fgetc(in)) != EOF)
fputc(toupper(ch), out);
fclose(out);
}
/* This is the daemon's main work -- listen for connections and spawn */
void process()
{
struct sockaddr_in addr;
int addrlen = sizeof(addr);
int sock = socket(AF_INET, SOCK_STREAM, 0);
int flag = 1;
int rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
&flag, sizeof(flag));
if (rc < 0)
errexit("setsockopt");
addr.sin_family = AF_INET;
addr.sin_port = htons(TCP_PORT);
addr.sin_addr.s_addr = INADDR_ANY;
rc = bind(sock, (struct sockaddr *) &addr, addrlen);
if (rc < 0)
errexit("bind");
rc = listen(sock, 5);
if (rc < 0)
errexit("listen");
for (;;)
{
rc = accept(sock, (struct sockaddr *) &addr, &addrlen);
if (rc >= 0)
switch (fork2())
{
case 0: close(sock); run_child(rc); _exit(0);
case -1: errreport("fork2"); close(rc); break;
default: close(rc);
}
}
}
int main()
{
if (daemon(0,0) < 0)
{
perror("daemon");
exit(2);
}
openlog("test", LOG_PID, LOG_DAEMON);
process();
return 0;
}
/* issue some simple modem commands
* requires the name of a serial device (preferably a dial-out device,
* or a non-modem-control device) as its only parameter.
* If you don't have functional dial-out devices, then move CLOCAL
* to CFLAGS_TO_SET instead.
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h> /* maybe; system-dependent */
#include <termios.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#define CFLAGS_TO_SET (CREAD | HUPCL)
#define CFLAGS_TO_CLEAR (CSTOPB | PARENB | CLOCAL)
enum flowmode { NoFlow, HardFlow, SoftFlow };
/* system-dependent */
#define CFLAGS_HARDFLOW (CRTSCTS)
#define EXAMPLE_BAUD B19200
#define EXAMPLE_FLOW HardFlow
static void die(const char *msg)
{
fprintf(stderr, "%s\n", msg);
exit(1);
}
static int close_and_complain(int fd, const char *msg, int err)
{
fprintf(stderr, "%s: %s\n", msg, strerror(err));
if (fd >= 0)
close(fd);
errno = err;
return -1;
}
int open_port(const char *name, speed_t baud, enum flowmode flow)
{
int flags;
struct termios attr;
int fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY);
if (fd < 0)
return close_and_complain(-1, "open", errno);
/* set vaguely sensibe settings */
if (tcgetattr(fd, &attr) < 0)
return close_and_complain(fd, "tcgetattr", errno);
/* no special input or output processing */
attr.c_iflag = (flow == SoftFlow) ? (IXON | IXOFF) : 0;
attr.c_oflag = 0;
/* set 8-bit character size and miscellanous control modes */
attr.c_cflag &= ~(CSIZE | CFLAGS_TO_CLEAR | CFLAGS_HARDFLOW);
attr.c_cflag |= (CS8 | CFLAGS_TO_SET);
if (flow == HardFlow)
attr.c_cflag |= CFLAGS_HARDFLOW;
/* local modes */
attr.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ISIG);
/* special characters -- most are disabled by prior settings anyway */
{
int i;
#ifdef _POSIX_VDISABLE
attr.c_cc[0] = _POSIX_VDISABLE;
#else
attr.c_cc[0] = fpathconf(fd, _PC_VDISABLE);
#endif
for (i = 1; i < NCCS; i++)
attr.c_cc[i] = attr.c_cc[0];
}
attr.c_cc[VSTART] = 0x11;
attr.c_cc[VSTOP] = 0x13;
/* timing controls for read() */
attr.c_cc[VMIN] = 1;
attr.c_cc[VTIME] = 0;
/* baud rate */
cfsetispeed(&attr, baud);
cfsetospeed(&attr, baud);
/* write settings */
if (tcsetattr(fd, TCSANOW, &attr) < 0)
return close_and_complain(fd, "tcsetattr", errno);
/* turn off O_NONBLOCK if the device remembered it */
flags = fcntl(fd, F_GETFL, 0);
if (flags < 0)
return close_and_complain(fd, "fcntl(GETFL)", errno);
if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) < 0)
return close_and_complain(fd, "fcntl(SETFL)", errno);
return fd;
}
/* some simple timing utilities */
/* add SECS and USECS to *TV */
static void timeradd(struct timeval *tv, long secs, long usecs)
{
tv->tv_sec += secs;
if ((tv->tv_usec += usecs) >= 1000000)
{
tv->tv_sec += tv->tv_usec / 1000000;
tv->tv_usec %= 1000000;
}
}
/* Set *RES = *A - *B, returning the sign of the result */
static int timersub(struct timeval *res,
const struct timeval *a, const struct timeval *b)
{
long sec = a->tv_sec - b->tv_sec;
long usec = a->tv_usec - b->tv_usec;
if (usec < 0)
usec += 1000000, --sec;
res->tv_sec = sec;
res->tv_usec = usec;
return (sec < 0) ? (-1) : ((sec == 0 && usec == 0) ? 0 : 1);
}
/* this doesn't try and cope with pathological strings (e.g. ababc)
* timeout is in millisecs
* A more usual approach to this is to use alarm() for the timeout.
* This example avoids signal handling for simplicity and to illustrate
* an alternative approach
*/
int expect(int fd, const char *str, int timeo)
{
int matchlen = 0;
int len = strlen(str);
struct timeval now,end,left;
fd_set fds;
char c;
gettimeofday(&end, NULL);
timeradd(&end, timeo/1000, timeo%1000);
while (matchlen < len)
{
gettimeofday(&now, NULL);
if (timersub(&left, &end, &now) <= 0)
return -1;
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (select(fd+1, &fds, NULL, NULL, &left) <= 0)
return -1;
if (read(fd, &c, 1) != 1)
return -1;
if (isprint((unsigned char)c) || c == '\n' || c == '\r')
putchar(c);
else
printf("\\x%02x", c);
if (c == str[matchlen])
++matchlen;
else
matchlen = 0;
}
return 0;
}
int main(int argc, char **argv)
{
int fd;
unsigned char c;
if (argc < 2)
die("no port specified");
setvbuf(stdout, NULL, _IONBF, 0);
fd = open_port(argv[1], EXAMPLE_BAUD, EXAMPLE_FLOW);
if (fd < 0)
die("cannot open port");
write(fd, "AT\r", 3);
if (expect(fd, "OK", 5000) < 0)
{
write(fd, "AT\r", 3);
if (expect(fd, "OK", 5000) < 0)
{
tcflush(fd, TCIOFLUSH);
close(fd);
die("no response to AT");
}
}
write(fd, "ATI4\r", 5);
expect(fd, "OK", 10000);
putchar('\n');
tcflush(fd, TCIOFLUSH);
close(fd);
return 0;
}
/* functions to spawn foreground/background jobs */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
/* Some of the functions below fail if the control tty can't be
* located, or if the calling process isn't in the foreground. In the
* first case, we are assuming that a foreground process will have the
* ctty open on either stdin, stdout or stderr, and we return ENOTTY
* if it isn't. In the second case, we return EPERM if a
* non-foreground process attempts to put something into the
* foreground (probably overly paranoid) except for the special case
* of foreground_self().
*/
/* Like fork(), but does job control. FG is true if the newly-created
* process is to be placed in the foreground. (This implicitly puts
* the calling process in the background, so watch out for tty I/O
* after doing this.) PGRP is -1 to create a new job, in which case
* the returned pid is also the pgrp of the new job, or specifies an
* existing job in the same session (normally used only for starting
* second or subsequent process in a pipeline). */
pid_t spawn_job(int fg, pid_t pgrp)
{
int ctty = -1;
pid_t pid;
/* If spawning a *new* foreground job, require that at least one
* of stdin, stdout or stderr refer to the control tty, and that
* the current process is in the foreground.
* Only check for controlling tty if starting a new foreground
* process in an existing job.
* A session without a control tty can only have background jobs
*/
if (fg)
{
pid_t curpgrp;
if ((curpgrp = tcgetpgrp(ctty = 2)) < 0
&& (curpgrp = tcgetpgrp(ctty = 0)) < 0
&& (curpgrp = tcgetpgrp(ctty = 1)) < 0)
return errno = ENOTTY, (pid_t)-1;
if (pgrp < 0 && curpgrp != getpgrp())
return errno = EPERM, (pid_t)-1;
}
switch (pid = fork())
{
case -1: /* fork failure */
return pid;
case 0: /* child */
/* establish new process group, and put ourselves in
* foreground if necessary
* unclear what to do if setpgid fails (it's a "can't happen")
*/
if (pgrp < 0)
pgrp = getpid();
if (setpgid(0,pgrp) == 0 && fg)
tcsetpgrp(ctty, pgrp);
return 0;
default: /* parent */
/* establish child process group here too. */
if (pgrp < 0)
pgrp = pid;
setpgid(pid, pgrp);
return pid;
}
/*NOTREACHED*/
}
/* Kill job PGRP with signal SIGNO */
int kill_job(pid_t pgrp, int signo)
{
return kill(-pgrp, signo);
}
/* Suspend job PGRP */
int suspend_job(pid_t pgrp)
{
return kill_job(pgrp, SIGSTOP);
}
/* Resume job PGRP in background */
int resume_job_bg(pid_t pgrp)
{
return kill_job(pgrp, SIGCONT);
}
/* resume job PGRP in foreground */
int resume_job_fg(pid_t pgrp)
{
pid_t curpgrp;
int ctty;
if ((curpgrp = tcgetpgrp(ctty = 2)) < 0
&& (curpgrp = tcgetpgrp(ctty = 0)) < 0
&& (curpgrp = tcgetpgrp(ctty = 1)) < 0)
return errno = ENOTTY, (pid_t)-1;
if (curpgrp != getpgrp())
return errno = EPERM, (pid_t)-1;
if (tcsetpgrp(ctty, pgrp) < 0)
return -1;
return kill_job(pgrp, SIGCONT);
}
/* put ourselves in the foreground, e.g. after suspending a foreground
* job
*/
int foreground_self()
{
pid_t curpgrp;
int ctty;
if ((curpgrp = tcgetpgrp(ctty = 2)) < 0
&& (curpgrp = tcgetpgrp(ctty = 0)) < 0
&& (curpgrp = tcgetpgrp(ctty = 1)) < 0)
return errno = ENOTTY, (pid_t)-1;
return tcsetpgrp(ctty, getpgrp());
}
/* closeall() - close all FDs >= a specified value */
void closeall(int fd)
{
int fdlimit = sysconf(_SC_OPEN_MAX);
while (fd < fdlimit)
close(fd++);
}
/* like system(), but executes the specified command as a background
* job, returning the pid of the shell process (which is also the pgrp
* of the job, suitable for kill_job etc.)
* If INFD, OUTFD or ERRFD are non-NULL, then a pipe will be opened and
* a descriptor for the parent end of the relevent pipe stored there.
* If any of these are NULL, they will be redirected to /dev/null in the
* child.
* Also closes all FDs > 2 in the child process (an oft-overlooked task)
*/
pid_t spawn_background_command(const char *cmd,
int *infd, int *outfd, int *errfd)
{
int nullfd = -1;
int pipefds[3][2];
int error = 0;
if (!cmd)
return errno = EINVAL, -1;
pipefds[0][0] = pipefds[0][1] = -1;
pipefds[1][0] = pipefds[1][1] = -1;
pipefds[2][0] = pipefds[2][1] = -1;
if (infd && pipe(pipefds[0]) < 0)
error = errno;
else if (outfd && pipe(pipefds[1]) < 0)
error = errno;
else if (errfd && pipe(pipefds[2]) < 0)
error = errno;
if (!error && !(infd && outfd && errfd))
{
nullfd = open("/dev/null",O_RDWR);
if (nullfd < 0)
error = errno;
}
if (!error)
{
pid_t pid = spawn_job(0, -1);
switch (pid)
{
case -1: /* fork failure */
error = errno;
break;
case 0: /* child proc */
dup2(infd ? pipefds[0][0] : nullfd, 0);
dup2(outfd ? pipefds[1][1] : nullfd, 1);
dup2(errfd ? pipefds[2][1] : nullfd, 2);
closeall(3);
execl("/bin/sh","sh","-c",cmd,(char*)NULL);
_exit(127);
default: /* parent proc */
close(nullfd);
if (infd)
close(pipefds[0][0]), *infd = pipefds[0][1];
if (outfd)
close(pipefds[1][1]), *outfd = pipefds[1][0];
if (errfd)
close(pipefds[2][1]), *errfd = pipefds[2][0];
return pid;
}
}
/* only reached if error */
{
int i,j;
for (i = 0; i < 3; ++i)
for (j = 0; j < 2; ++j)
if (pipefds[i][j] >= 0)
close(pipefds[i][j]);
}
if (nullfd >= 0)
close(nullfd);
return errno = error, (pid_t) -1;
}
/*----------------------------------------------------------------------*/
/* This bit is a somewhat trivial example of using the above. */
pid_t bgjob = -1;
volatile int signo = 0;
#ifndef WCOREDUMP
/* If WCOREDUMP is missing, you might want to supply a correct
* definition for your platform (usually (status & 0x80) but not always)
* or punt (as in this example) by assuming no core dumps.
*/
# define WCOREDUMP(status) (0)
#endif
int check_children()
{
pid_t pid;
int status;
int count = 0;
while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0)
{
if (pid == bgjob && !WIFSTOPPED(status))
bgjob = -1;
++count;
if (WIFEXITED(status))
fprintf(stderr,"Process %ld exited with return code %d\n",
(long)pid, WEXITSTATUS(status));
else if (WIFSIGNALED(status))
fprintf(stderr,"Process %ld killed by signal %d%s\n",
(long)pid, WTERMSIG(status),
WCOREDUMP(status) ? " (core dumped)" : "");
else if (WIFSTOPPED(status))
fprintf(stderr,"Process %ld stopped by signal %d\n",
(long)pid, WSTOPSIG(status));
else
fprintf(stderr,"Unexpected status - pid=%ld, status=0x%x\n",
(long)pid, status);
}
return count;
}
void sighandler(int sig)
{
if (sig != SIGCHLD)
signo = sig;
}
int main()
{
struct sigaction act;
int sigcount = 0;
act.sa_handler = sighandler;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGINT,&act,NULL);
sigaction(SIGQUIT,&act,NULL);
sigaction(SIGTERM,&act,NULL);
sigaction(SIGTSTP,&act,NULL);
sigaction(SIGCHLD,&act,NULL);
fprintf(stderr,"Starting background job 'sleep 60'\n");
bgjob = spawn_background_command("sleep 60", NULL, NULL, NULL);
if (bgjob < 0)
{
perror("spawn_background_command");
exit(1);
}
fprintf(stderr,"Background job started with id %ld\n", (long)bgjob);
while (bgjob >= 0)
{
if (signo)
{
fprintf(stderr,"Signal %d caught\n", signo);
if (sigcount++)
kill_job(bgjob, SIGKILL);
else
{
kill_job(bgjob, SIGTERM);
kill_job(bgjob, SIGCONT);
}
}
if (!check_children())
pause();
}
fprintf(stderr,"Done - exiting\n");
return 0;
}
Go to the first, previous, next, last section, table of contents.