-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexec.c
182 lines (137 loc) · 3.35 KB
/
exec.c
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include "exec.h"
// sets the environment variables passed
// in the command line
static void set_environ_vars(char** eargv, int eargc) {
int equalIndex;
char key[50], value[50];
for (int i = 0; i < eargc; i++) {
equalIndex = block_contains(eargv[i], '=');
get_environ_key(eargv[i], key);
get_environ_value(eargv[i], value, equalIndex);
setenv(key, value, 1);
}
}
// opens the file in which the stdin or
// stdout flow will be redirected
static int open_redir_fd(char* file, int flags) {
int fd;
fd = open(file,
flags | O_CLOEXEC,
S_IRUSR | S_IWUSR);
return fd;
}
// opens the file and redirects it
// to the appropiate standar flow
static void redir_std_flow(struct cmd* cmd,
struct file f, int redir_fd) {
int fd;
char buf[BUFLEN];
if (strlen(f.name) > 0) {
if (strcmp(f.name, "&1") == 0)
fd = STDOUT_FILENO;
else if ((fd = open_redir_fd(f.name, f.flags)) < 0) {
memset(buf, 0, BUFLEN);
snprintf(buf, sizeof buf, "cannot open file: %s ", f.name);
perror(buf);
free(ss.ss_sp);
free_command(cmd);
_exit(EXIT_FAILURE);
}
if (dup2(fd, redir_fd) < 0) {
memset(buf, 0, BUFLEN);
snprintf(buf, sizeof buf, "cannot dup file: %s ", f.name);
perror(buf);
free(ss.ss_sp);
free_command(cmd);
_exit(EXIT_FAILURE);
}
}
}
// executes a command - does not return
void exec_cmd(struct cmd* cmd) {
struct redircmd* r;
struct execcmd* e;
struct pipecmd* p;
struct backcmd* b;
char buf[BUFLEN];
int pfd[2];
int exit_code, s;
pid_t auxp, rp;
switch (cmd->type) {
case EXEC:
e = (struct execcmd*)cmd;
set_environ_vars(e->eargv, e->eargc);
execvp(e->argv[0], e->argv);
memset(buf, 0, BUFLEN);
snprintf(buf, sizeof buf, "cannot exec %s ", e->argv[0]);
perror(buf);
break;
case BACK: {
b = (struct backcmd*)cmd;
// sets the current
// process group id
// to the PID of the
// calling process
setpgid(0, 0);
exec_cmd(b->c);
break;
}
case REDIR: {
// changes the input/output flow
r = (struct redircmd*)cmd;
// stdin redirection
redir_std_flow(cmd, r->in, STDIN_FILENO);
// stdout redirection
redir_std_flow(cmd, r->out, STDOUT_FILENO);
// stderr redirection
redir_std_flow(cmd, r->err, STDERR_FILENO);
exec_cmd(r->c);
free(ss.ss_sp);
free_command(cmd);
_exit(EXIT_FAILURE);
break;
}
case PIPE: {
// pipes two commands
p = (struct pipecmd*)cmd;
if (pipe(pfd) < 0) {
memset(buf, 0, sizeof buf);
snprintf(buf, sizeof buf, "pipe creation failed ");
perror(buf);
_exit(EXIT_FAILURE);
}
if (fork() == 0) {
dup2(pfd[WRITE], STDOUT_FILENO);
close(pfd[READ]);
close(pfd[WRITE]);
exec_cmd(p->leftcmd);
}
rp = fork();
if (rp == 0) {
dup2(pfd[READ], STDIN_FILENO);
close(pfd[READ]);
close(pfd[WRITE]);
exec_cmd(p->rightcmd);
}
close(pfd[READ]);
close(pfd[WRITE]);
// free the memory allocated
// for the pipe tree structure
free_command(parsed_pipe);
free(ss.ss_sp);
// waits for both childs
// and watches which one is the
// right command. Checks the status
// code to forward it to the
// main 'shell' process.
auxp = wait(&s);
if (auxp == rp)
exit_code = WEXITSTATUS(s);
auxp = wait(&s);
if (auxp == rp)
exit_code = WEXITSTATUS(s);
_exit(exit_code);
break;
}
}
}