Hi,
I have this stuff to do for university that's basically a simple custom shell and I'm currently having some difficulties.
The basic functionality is already done, I read a command from the stdin and execute it with execvp(). After that, with wait(NULL), I wait for that process to finish before returning to the shell. I now can properly run processes in the foreground one at a time. Time to implement background processes...
The first step is to check if the "&" is the last argument, if it is, run the process in the background. To do that I simply check for the "&" and set a background variable to true or false accordingly. Then, if background == false do not wait for the process to finish and return to the shell.
So far so good... Now my problem...
When running processes in the background like this, it's likely they end up "zombies" right? I need to take care of them and for that, I believe I need to handle the SIGCHLD signal... At least I need to use the signal() function to handle something because that's part of the exercise. And that's what I did as you'll see in the code below...
Now my questions:
1) Is this code ok or should I do it differently? I ask this because if I run a process in the foreground, there will be two waits, the first one (wait(NULL)) right after executing the command and a second one (waitpid(-1, &status, WNOHANG)) right after the process terminates or is killed/stopped/whatever.
I don't think that this should happen. First because it doesn't make sense to call wait two times for a foreground process, the first wait will turn the second one redundant. Second because part of my exercise is that I need to print the status changes of the processes but there's no reason to do this for foreground processes. So basically, I need to call the waitpid() in childSignalHandler() only for background processes.
How should I solve this then?
2) As I said in my first question, I need to print the status changes of the processes running in the background. Any changes how to handle this? My first guess is that I simply need to print the value of status after waitpid() in childSignalHandler(). Is that it?
That's almost all I want to know, I still have a couple of more things that I want to accomplish but they are not part of the exercise for university, they are just some things I want to do to improve my custom shell a little bit, I'll talk about them later...
I was just going to forget about the code lol, here it is:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>
#include <sys/types.h>
#include "data.h"
void childSignalHandler(int signum) {
int status;
pid_t pid;
pid = waitpid(-1, &status, WNOHANG);
}
int main(int argc, char **argv) {
char bBuffer[BUFSIZ], *pArgs[10], *aPtr = NULL, *sPtr;
bool background;
ssize_t rBytes;
int aCount;
pid_t pid;
signal(SIGCHLD, childSignalHandler);
while(1) {
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 = FALSE;
if(!strcmp(pArgs[aCount-2], "&")) {
pArgs[aCount-2] = NULL;
background = TRUE;
}
if(strlen(pArgs[0]) > 1) {
pid = fork();
if(pid == -1) {
perror("fork");
exit(1);
}
if(pid == 0) {
execvp(pArgs[0], pArgs);
exit(0);
}
if(!background) {
wait(NULL);
}
}
}
return 0;
}