In this previous question I posted most of my own shell code. My next step is to implement foreground and background process execution and properly wait for them to terminate so
This should get you started. The major difference is that I got rid of the child handler and added waitpid
in the main loop with some feedback. Tested and working, but obviously needs more TLC.
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char **argv) {
char bBuffer[BUFSIZ], *pArgs[10], *aPtr = NULL, *sPtr;
int background;
ssize_t rBytes;
int aCount;
pid_t pid;
int status;
while(1) {
pid = waitpid(-1, &status, WNOHANG);
if (pid > 0)
printf("waitpid reaped child pid %d\n", pid);
write(1, "\e[1;31mmyBash \e[1;32m# \e[0m", 27);
rBytes = read(0, bBuffer, BUFSIZ-1);
if(rBytes == -1) {
perror("read");
exit(1);
}
bBuffer[rBytes-1] = '\0';
if(!strcasecmp(bBuffer, "exit"))
exit(0);
sPtr = bBuffer;
aCount = 0;
do {
aPtr = strsep(&sPtr, " ");
pArgs[aCount++] = aPtr;
} while(aPtr);
background = (strcmp(pArgs[aCount-2], "&") == 0);
if (background)
pArgs[aCount-2] = NULL;
if (strlen(pArgs[0]) > 1) {
pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
} else if (pid == 0) {
execvp(pArgs[0], pArgs);
exit(1);
} else if (!background) {
pid = waitpid(pid, &status, 0);
if (pid > 0)
printf("waitpid reaped child pid %d\n", pid);
}
}
}
return 0;
}
EDIT: Adding back in signal handling isn't difficult with waitpid()
using WNOHANG. It's as simple as moving the waitpid()
stuff from the top of the loop into the signal handler. You should be aware of two things, though:
First, even "foreground" processes will send SIGCHLD. Since there can be only one foreground process you can simply store the foreground pid (parent's return value from fork()
) in a variable visible to the signal handler if you want to do special handling of foreground vs. background.
Second, you're currently doing blocking I/O on standard input (the read()
at main loop top). You are extremely likely to be blocked on read()
when SIGCHLD occurs, resulting in an interrupted system call. Depending on OS it may restart the system call automatically, or it may send a signal that you must handle.