Repository navigation
Expand file tree
/
Copy pathexecute_command.c
More file actions
124 lines (115 loc) · 4 KB
/
Copy pathexecute_command.c
File metadata and controls
124 lines (115 loc) · 4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
//
// Created by Ysw on 2021/10/3.
//
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include<sys/wait.h>
#include "process_manager.h"
#include "nyush.h"
extern struct SuspendedJobs *suspended_jobs_list_tail;
/** To execute the job command, no matter it is piped or not
*
* @param jobs:: the head node of a double linked list storing the whole command,
* in which a node is a subcommand except the head
* @param isPipe:: the flag representing if the current job command is a piped command, if 0 then not,
* otherwise the number of the pipe
*/
void execute_command(struct Jobs *jobs, int isPipe){
int pipe_fd[isPipe * 2];
for (int i = 0; i < isPipe * 2; i = i + 2){
pipe(pipe_fd+i);
}
siginfo_t infop;
pid_t pgid = -1; // process group ID, initialized as -1
int idx = 0;
struct Jobs *job = jobs;
while(job){
int input_fd;
int output_fd;
if (!isPipe){ // if not piped
input_fd = job->input_fd;
output_fd = job->output_fd;
}
else{ // if piped
if (idx == 0){
input_fd = job->input_fd;
output_fd = pipe_fd[idx*2 + 1];
}
else if (!job->next){
input_fd = pipe_fd[idx * 2 - 2];
output_fd = job->output_fd;
}
else{
input_fd = pipe_fd[idx * 2 - 2];
output_fd = pipe_fd[idx * 2 + 1];
}
}
idx++;
pid_t child = fork();
if (child == -1){
fprintf(stderr, "Error: fork failed\n");
return;
}
if (child == 0){
if (pgid == -1){ // especially used for the piped command to store the process group ID
pgid = getpid();
}
setpgid(getpid(), pgid); // set all child processes to the same process group
signal(SIGTSTP, SIG_DFL); // restore the signal
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
signal(SIGSTOP, SIG_DFL);
signal(SIGTERM, SIG_DFL);
signal(SIGTTOU, SIG_DFL);
signal(SIGTTIN, SIG_DFL);
if (input_fd != STDIN_FILENO) { // input redirection
dup2(input_fd, STDIN_FILENO);
close(input_fd);
}
if (output_fd != STDOUT_FILENO) { // output redirection
dup2(output_fd, STDOUT_FILENO);
close(output_fd);
}
for (int i = 0; i < isPipe * 2; i++){ // close pipe
close(pipe_fd[i]);
}
execv(job->cmdname, job->args);
exit(-1);
}
else{
if (pgid == -1){ // especially used for the piped command to store the process group ID
pgid = child;
setpgid(child, pgid);
tcsetpgrp(STDOUT_FILENO, pgid); // switch foreground
tcsetpgrp(STDIN_FILENO, pgid);
}
setpgid(child, pgid); // set all child processes to the same process group
}
job = job->next;
}
for (int i = 0; i < isPipe * 2; i++){
close(pipe_fd[i]);
}
while (waitid(P_PGID, pgid, &infop, WEXITED | WSTOPPED) != -1){
if (infop.si_code == CLD_EXITED){
if (infop.si_status != 0){ // if exited abnormally, send SIGKILL to the group
kill(pgid, SIGKILL);
break;
}
}
else if (infop.si_code == CLD_STOPPED){ // if stopped, send SIGTSTP to the group and handle suspended job
kill(pgid, SIGTSTP);
child_process_signal_handler(pgid);
break;
}
else if (infop.si_code == CLD_DUMPED){
kill(pgid, SIGKILL);
break;
}
}
// if exited normally, do nothing, just switch the foreground
tcsetpgrp(STDIN_FILENO, getpgid(getpid()));
tcsetpgrp(STDOUT_FILENO, getpgid(getpid()));
}