aboutsummaryrefslogtreecommitdiffstats
path: root/cmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmd.c')
-rw-r--r--cmd.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/cmd.c b/cmd.c
new file mode 100644
index 0000000..e38da41
--- /dev/null
+++ b/cmd.c
@@ -0,0 +1,195 @@
1#include "cmd.h"
2
3Command *newCmd() {
4 Command *cmd = (Command *)malloc(sizeof(Command));
5 cmd->argc = 0;
6 cmd->args = NULL;
7 cmd->type = CMD_NORMAL;
8 cmd->left = NULL;
9 cmd->right = NULL;
10 for (int i = 0; i < 3; i++) {
11 cmd->redirectFile[i] = NULL;
12 cmd->redirectFD[i] = i;
13 }
14 cmd->background = false;
15 return cmd;
16}
17
18void freeCmd(Command *cmd) {
19 if (cmd == NULL) {
20 return;
21 }
22 if (cmd->left != NULL) {
23 freeCmd(cmd->left);
24 }
25 if (cmd->right != NULL) {
26 freeCmd(cmd->right);
27 }
28 int i;
29 for (i = 0; i < cmd->argc; i++) {
30 free(cmd->args[i]);
31 }
32 free(cmd->args);
33 for (i = 0; i < 3; i++) {
34 if (cmd->redirectFile[i] != NULL) {
35 free(cmd->redirectFile[i]);
36 }
37 }
38 free(cmd);
39}
40
41int runCmd(Command *cmd) {
42 int status;
43 if (cmd == NULL) {
44 fprintf(stderr, "cmd is NULL\n");
45 return -1;
46 }
47 switch (cmd->type) {
48 case CMD_NORMAL:
49 status = runNormalCmd(cmd);
50 break;
51 case CMD_PIPE:
52 status = runPipeCmd(cmd);
53 break;
54 case CMD_AND:
55 case CMD_OR:
56 status = runAndOrCmd(cmd);
57 break;
58 }
59
60 freeCmd(cmd);
61 return status;
62}
63
64int runNormalCmd(Command *cmd) {
65 pid_t pid;
66 int status;
67 if (!strcmp(cmd->args[0], "exit")) {
68 printf("Good Bye, %s!\n", username);
69 exit(0);
70 } else if (!strcmp(cmd->args[0], "cd")) {
71 if (cmd->argc == 1) {
72 chdir(getenv("HOME"));
73 } else {
74 chdir(cmd->args[1]);
75 }
76 printf("\r");
77 getcwd(pwd, sizeof(pwd));
78 } else {
79 if ((pid = fork()) == 0) {
80 // consider the redirection now
81 // it's just a part of normal command
82 // but not in other commands
83 redirect(cmd);
84 exit(execvp(cmd->args[0], cmd->args));
85 } else {
86 if (!cmd->background) {
87 waitpid(pid, &status, 0);
88 if (!WIFEXITED(status)) {
89 if (WIFSIGNALED(status)) {
90 fprintf(stderr, "Process %d was killed by signal %d\n",
91 pid, WTERMSIG(status));
92 } else {
93 fprintf(stderr, "Process %d exited with status %d\n",
94 pid, WEXITSTATUS(status));
95 }
96 }
97 }
98 }
99 // return the exit status of the child process
100 return WEXITSTATUS(status);
101 }
102}
103
104int runPipeCmd(Command *cmd) {
105 int status;
106 // create a pipe file and gets two file descriptors
107 // fd[0] is the read end, while fd[1] the write end
108 int fd[2];
109 pid_t left, right;
110 pipe(fd);
111 if ((left = fork()) == 0) {
112 /*
113 * close the read end of the pipe, so that the child process
114 * can only write to it; then redirect the standard output
115 * to the write end of the pipe, and close the write end
116 * itself as a file descriptor.
117 */
118 close(fd[0]);
119 dup2(fd[1], 1);
120 close(fd[1]);
121 exit(runCmd(cmd->left));
122 }
123 if ((right = fork()) == 0) {
124 close(fd[1]);
125 dup2(fd[0], 0);
126 close(fd[0]);
127 exit(runCmd(cmd->right));
128 }
129 // close the pipe, because the parent process doesn't need it
130 // and wait for the two child processes to exit
131 close(fd[0]);
132 close(fd[1]);
133 waitpid(left, NULL, 0);
134 waitpid(right, NULL, 0);
135}
136
137int runAndOrCmd(Command *cmd) {
138 int status;
139 if (cmd->type == CMD_AND) {
140 if (fork() == 0) {
141 exit(runCmd(cmd->left));
142 } else {
143 waitpid(-1, &status, 0);
144 if (WIFEXITED(status) && WEXITSTATUS(status) == 0 && fork() == 0) {
145 status = runCmd(cmd->right);
146 }
147 wait(NULL);
148 }
149 } else if (cmd->type == CMD_OR) {
150 if (fork() == 0) {
151 exit(runCmd(cmd->left));
152 } else {
153 waitpid(-1, &status, 0);
154 if (WIFEXITED(status) && WEXITSTATUS(status) != 0 && fork() == 0) {
155 status = runCmd(cmd->right);
156 }
157 wait(NULL);
158 }
159 }
160}
161
162void redirect(Command *cur) {
163 int fd;
164 char *rfile;
165 for (int i = 0; i < 3; i++) {
166 fd = cur->redirectFD[i];
167 rfile = cur->redirectFile[i];
168 if (fd < -1 || fd > 2) {
169 fprintf(stderr, "file descriptor %d is invalid\n", fd);
170 exit(1);
171 }
172 if (fd == i && rfile == NULL) {
173 continue;
174 }
175 if (fd == -1) {
176 // append
177 fd = open(rfile, O_WRONLY | O_CREAT | O_APPEND, 0666);
178 } else if (rfile != NULL) {
179 // normal redirection
180 fd = open(rfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
181 } else {
182 // file descriptor redirection
183 // when here, fd is surely in 0, 1, 2
184 ;
185 }
186
187 if (fd < 0) {
188 fprintf(stderr, "open file %s failed\n", rfile);
189 exit(1);
190 }
191 close(i);
192 dup2(fd, i);
193 close(fd);
194 }
195} \ No newline at end of file