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