I wrote a shell program for linux, and created the following code for pipe command:
void PipeCommand::execute() {
jobs_list->removeFinishedJobs();
if(signal(SIGTSTP , ctrlZHandlerPipe)==SIG_ERR) {
perror("smash error: failed to set ctrl-Z handler");
return;
}
if(signal(SIGINT , ctrlCHandlerPipe)==SIG_ERR) {
perror("smash error: failed to set ctrl-C handler");
return;
}
bool is_bg = false;
string new_command = command;
if (_isBackgroundComamnd(command.c_str())) {
//Ends with &
is_bg = true;
char temp[COMMAND_ARGS_MAX_LENGTH];
strcpy(temp, command.c_str());
_removeBackgroundSign(temp);
new_command = string(temp);
}
//Produce first and second command
int pipeIndex = new_command.find('|');
bool isStderrPipe = new_command[pipeIndex + 1] == '&';
string cmd1 = new_command.substr(0, pipeIndex);
string cmd2 = new_command.substr(pipeIndex + 1 + (int) isStderrPipe);
SmallShell &temp_smash = SmallShell::getInstance();
auto command1 = temp_smash.CreateCommand(cmd1.c_str());
auto command2 = temp_smash.CreateCommand(cmd2.c_str());
pid_t pid = fork();
if (pid < 0) {
perror("smash error: fork failed");
return;
} else if (pid == 0) {
//Child
setpgid(0,0);
//pid_t gid = getpgid(0);
//Create pipe
int fd[2];
if (pipe(fd) == -1) {
perror("smash error: pipe failed");
return;
}
pid_t pid_cmd1 = fork();
if (pid_cmd1 < 0) {
perror("smash error: fork failed");
return;
} else if (pid_cmd1 == 0) {
//Child command 1
if (isStderrPipe) {
if (dup2(fd[1], STDERR_FILENO) == -1) {
perror("smash error: dup2 failed");
return;
}
} else {
if (dup2(fd[1], STDOUT_FILENO) == -1) {
perror("smash error: dup2 failed");
return;
}
}
close(fd[0]);
close(fd[1]);
command1->execute();
exit(0);
} else {
//Parent command 1
pid_t pid_cmd2 = fork();
if (pid_cmd2 < 0) {
perror("smash error: fork failed");
return;
} else if (pid_cmd2 == 0) {
if (dup2(fd[0], STDIN_FILENO) == -1) {
perror("smash error: dup2 failed");
return;
}
close(fd[1]);
close(fd[0]);
command2->execute();
exit(0);
}
else{
close(fd[0]);
close(fd[1]);
int res1 = waitpid(pid_cmd1, nullptr, WUNTRACED);
int res2= waitpid(pid_cmd2, nullptr, WUNTRACED);
if (res1 == -1 || res2 == -1) {
perror("smash error: waitpid failed");
return;
}
exit(0);
}
}
} else {
//Parent
if (is_bg) {
jobs_list->addJob(command, pid, false);
return; //No need to wait...
} else {
jobs_list->setFg(command, pid, -1);
int res = waitpid(pid, nullptr, WUNTRACED);
if (res == -1) {
perror("smash error: waitpid failed");
return;
}
jobs_list->setFg("", -1, -1);
}
if(signal(SIGTSTP , ctrlZHandler)==SIG_ERR) {
perror("smash error: failed to set ctrl-Z handler");
}
if(signal(SIGINT , ctrlCHandler)==SIG_ERR) {
perror("smash error: failed to set ctrl-C handler");
}
}
}
And the following handler for ctrZ which send SIGSTOP to the pipe and its inner commands:
void ctrlZHandlerPipe(int sig_num){
cout << "smash: got ctrl-Z" << endl;
SmallShell& smash = SmallShell::getInstance();
pid_t fg_pid = smash.getJobsList()->getFgPid();
if(fg_pid == smash.getSmashPid()){
return;
}
if(fg_pid != -1){
if(killpg(fg_pid, SIGSTOP) == -1){
perror("smash error: kill failed");
}
else{
if(!smash.getJobsList()->getBgToFg()){
smash.getJobsList()->addJob(smash.getJobsList()->getFgCmd(),fg_pid, true);
}
else{
smash.getJobsList()->getJobById(smash.getJobsList()->getFgId())->setJobStatus(false);
}
smash.getJobsList()->setFg("", -1, -1);
smash.getJobsList()->setBgToFg(false);
cout << "smash: process " << fg_pid << " was stopped" << endl;
}
}
if(signal(SIGTSTP , ctrlZHandler)==SIG_ERR) {
perror("smash error: failed to set ctrl-Z handler");
}
}
Now the problem is that while I run a pipe command, for example sleep 100|sleep 100, then pressing ctrlZ and then sending SIGCONT to the pipe again, it immediately continues and not waiting for its inner commands in the following lines:
int res1 = waitpid(pid_cmd1, nullptr, WUNTRACED);
int res2= waitpid(pid_cmd2, nullptr, WUNTRACED);
I cant figure out the problem might be..
Thank you
Aucun commentaire:
Enregistrer un commentaire