-
Notifications
You must be signed in to change notification settings - Fork 0
/
mysh.c
167 lines (144 loc) · 3.85 KB
/
mysh.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
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
//A source: https://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm
// This is the maximum number of arguments your shell should handle for one command
#define MAX_ARGS 128
void parseCommand(char* line, int blocker);
void split_command(char* str)
{
char* current_position = str;
while(true)
{
// Call strpbrk to find the next occurrence of a delimeter
char* delim_position = strpbrk(current_position, "&;");
if(delim_position == NULL)
{
// There were no more delimeters.
parseCommand(str, 1);
return;
}
else
{
int blocker = 1;
// There was a delimeter. First, save it.
if(*delim_position =='&')
{
blocker = 0;
}
// Overwrite the delimeter with a null terminator so we can print just this fragment
*delim_position = '\0';
parseCommand(str, blocker);
str = delim_position+1;
}
// Move our current position in the string to one character past the delimeter
current_position = delim_position + 1;
}
}
void parseCommand(char* line, int blocker)
{
const char s[] = " $\n";
char *token;
char *args [MAX_ARGS+1];
// get the first token
token = strtok(line, s );
char *cd = "cd";
char *exitCommand = "exit";
if(token == NULL) {}
else if(strcmp(token, exitCommand) == 0 ) {}
else if(strcmp(token, cd) == 0 )
{
chdir(strtok(NULL,s));
}
else
{
int argCount = 0;
// walk through other tokens
while( token != NULL && argCount < MAX_ARGS)
{
args[argCount] = token;
token = strtok(NULL, s);
argCount++;
}
args[argCount] = NULL;
//We run execvp
int status = 0;
pid_t waitres = 0;
pid_t i = fork();
if(i == 0)
{
execvp(args[0] ,args);
}
else
{
//The case where we have &
if(blocker == 0) {}
else
{
waitres = wait(&status);
}
}
printf("Child process %d", i);
printf(" exited with status %d\n", WEXITSTATUS(status));
}
}
int main(int argc, char** argv)
{
// If there was a command line option passed in, use that file instead of stdin
if(argc == 2)
{
// Try to open the file
int new_input = open(argv[1], O_RDONLY);
if(new_input == -1)
{
fprintf(stderr, "Failed to open input file %s\n", argv[1]);
exit(1);
}
// Now swap this file in and use it as stdin
if(dup2(new_input, STDIN_FILENO) == -1)
{
fprintf(stderr, "Failed to set new file as input\n");
exit(2);
}
}
int status = 0;
char* line = NULL; // Pointer that will hold the line we read in
size_t line_size = 0; // The number of bytes available in line
// Loop forever
while(true)
{
while(waitpid(-1, &status, WNOHANG) == 0)
{}
// Print the shell prompt
printf("$ ");
// Get a line of stdin, storing the string pointer in line
if(getline(&line, &line_size, stdin) == -1)
{
if(errno == EINVAL)
{
perror("Unable to read command line");
exit(2);
}
else
{
// Must have been end of file (ctrl+D)
printf("\nShutting down...\n");
// Exit the infinite loop
break;
}
}
printf("Received command: %s\n", line);
split_command(line);
}
if(line != NULL)
{
free(line);
}
return 0;
}