-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathShell.c
146 lines (129 loc) · 3.76 KB
/
Shell.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
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
char *lsh_read_line(void) {
size_t bufsize = 0;
char *line = NULL;
if (getline(&line, &bufsize, stdin) == -1) {
if (feof(stdin)) {
exit(EXIT_SUCCESS);
} else {
perror("readline");
exit(EXIT_FAILURE);
}
}
return line;
}
#define LSH_TOK_BUFSIZE 64
#define LSH_TOK_DELIM " \t\r\n\a"
char **lsh_split_line(char *line) {
int bufsize = LSH_TOK_BUFSIZE, pos = 0;
char **tokens = malloc(sizeof(char *) * bufsize);
char *token;
if (!tokens) {
fprintf(stderr, "lsh: allocation error\n");
exit(EXIT_FAILURE);
}
token = strtok(line, LSH_TOK_DELIM);
while (token != NULL) {
tokens[pos++] = token;
if (pos >= bufsize) {
bufsize += LSH_TOK_BUFSIZE;
tokens = realloc(tokens, bufsize * sizeof(char *));
if (!tokens) {
fprintf(stderr, "lsh: allocation error\n");
exit(EXIT_FAILURE);
}
}
token = strtok(NULL, LSH_TOK_DELIM);
}
tokens[pos] = NULL;
return tokens;
}
int lsh_launch(
char **args) { // first the parent creates a child , they both get their
// "lash_launch" function and they are handled based on the
// return value of fork which is pid. if the pid =0 then
// child , if greater than 0 then we are in parent and it
// executes until the child is finished (execvp continuously
// replaces the child with the next arguement function until
// -1 is returned which is the case of an error)
pid_t pid, wpid;
int status;
pid = fork(); // in parent, this returns the childs pid which is newly created
// and if we are already in the child, fork will return 0
if (pid == 0) {
if (execvp(args[0], args) == -1) {
perror("lsh");
}
exit(EXIT_FAILURE);
} else if (pid < 0) {
perror("lsh");
} else {
do {
wpid = waitpid(pid, &status,
WUNTRACED); // waitpid sets the status of the child of pid
// in the status variable and wuntraced simply
// helps wait for additional scenarious such as
// the child pausing or stopped which typically
// isnt handled by wifexited or wifsignaled
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
return 1;
}
int lsh_cd(char **args);
int lsh_help(char **args);
int lsh_exit(char **args);
char *builtin_str[] = {"cd", "help", "exit"};
int (*builtin_func[])(
char **) = { // quite literally an array of function pointers taking the
// arguements of char ** for each function like lsh_cd(args)
&lsh_cd, &lsh_help, &lsh_exit};
int lsh_num_builtins() { return sizeof(builtin_str) / sizeof(char *); }
int lsh_cd(char **args) {
if (args[1] == NULL) {
fprintf(stderr, "lsh: expected arguement to \"cd\"\n");
} else {
if (chdir(args[1]) != 0) {
perror("lsh");
}
}
return 1;
}
int lsh_help(char **args) {
printf("Use the man command for information on other programs.\n");
return 1;
}
int lsh_exit(char **args) { return 0; }
int lsh_execute(char **args) {
int i;
if (args[0] == NULL) {
return 1;
}
for (i = 0; i < lsh_num_builtins(); i++) {
if (strcmp(args[0], builtin_str[i]) == 0) {
return (*builtin_func[i])(args);
}
}
return lsh_launch(args);
}
void lsh_loop(void) {
char *line;
char **args;
int status;
do {
printf("> ");
line = lsh_read_line();
args = lsh_split_line(line);
status = lsh_execute(args);
free(line);
free(args);
} while (status);
}
int main(int argc, char **argv) {
lsh_loop();
return EXIT_SUCCESS;
}