-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdevShell.cpp
232 lines (186 loc) · 4.46 KB
/
devShell.cpp
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#include <fcntl.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include <string>
using namespace std;
#define NC "\e[0m"
#define RED "\e[0;31m"
#define GRN "\e[0;32m"
#define YEL "\033[33m"
#define MAXSIZE 50
#define READ 0
#define WRITE 1
char* args[MAXSIZE + 1];
// function to get input from console
void takeInput(string& input) {
cout << YEL << endl;
if (fork() == 0) {
execlp("pwd", "pwd", NULL);
} else {
wait(NULL);
}
cout << GRN << "> " << NC;
getline(cin, input);
}
// simple tokenizer
void tokenize(string input) {
char* token = strtok((char*)(input.c_str()), " ");
int i = 0;
while (token != NULL) {
args[i++] = token;
token = strtok(NULL, " ");
}
args[i] = NULL;
}
// function to check for type of redirection and get file name
string getRedirectFile(string& input, int& type) {
int fd;
string fileName;
int read = input.find("<");
int write = input.find(">");
if (read != -1) {
fileName = input.substr(read + 1);
input = input.substr(0, read);
} else if (write != -1) {
fileName = input.substr(write + 1);
input = input.substr(0, write);
}
if (read != -1)
type = READ;
else if (write != -1)
type = WRITE;
return fileName;
}
// get 1 token (left side of pipe if it exists)
string getToken(string& input, string& token, int& type) {
int isPipe = input.find("|");
// if pipe exists then give me the left side and truncate the input
if (isPipe != -1) {
token = input.substr(0, isPipe);
input = input.substr(isPipe + 1);
}
// else there is no pipe (there's only one command) so give me the whole input
else {
token = input;
input = "";
}
string _file;
// check for any redirection, get redirect file
if (token.find(">") || token.find("<")) {
_file = getRedirectFile(token, type);
}
return _file;
}
void executeCommand(string input) {
string token;
int file, type;
char* filename;
string _filename;
int readBackup = 0;
int fd[2];
while (true) {
type = -1;
// pipe
if (pipe(fd) == -1) {
cout << "Pipe failed" << endl;
};
// get 1 token (while check if there is redirection)
_filename = getToken(input, token, type);
filename = (char*)_filename.c_str();
// if token is empty (no command to execute) break
if (!token.length()) {
break;
}
int pid = fork();
if (pid == 0) {
// tokenize the command to execute
tokenize(token);
// there is some redirection
// write
if (type == WRITE) {
file = open(filename, O_WRONLY | O_CREAT, 0777);
dup2(readBackup, READ);
dup2(file, WRITE);
close(file);
}
// read
else if (type == READ) {
file = open(filename, O_RDONLY, 0777);
dup2(file, READ);
close(file);
if (input.length()) {
dup2(fd[WRITE], WRITE);
}
}
// if no redirection
else {
// read 1st time from stdin then read from backup (read end of pipe)
dup2(readBackup, READ);
// if there are commands left to execute, keep writing to pipe
if (input.length()) {
dup2(fd[WRITE], WRITE);
}
}
close(fd[READ]);
close(fd[WRITE]);
// execute
if (execvp(args[0], args) == -1) {
cout << RED "Command not found!" << NC << endl;
}
}
// parent
else if (pid > 0) {
wait(NULL);
close(fd[WRITE]);
// assign backup for next read
readBackup = fd[READ];
} else {
// fork failed
cout << RED "Fork failed" << NC << endl;
}
}
// close pipes if left
close(fd[WRITE]);
close(fd[READ]);
}
// function to execute cd command
bool checkForCD(string input) {
int isCD = input.find("cd");
if (isCD != -1) {
tokenize(input);
// cd case
if (args[1] == NULL) {
chdir("/");
}
// ~ case
else if (strcmp(args[1], "~") == 0) {
chdir(getenv("HOME"));
}
// else
else if (chdir(args[1]) == -1) {
cout << RED "Invalid Directory!" << NC << endl;
}
return true;
}
return false;
}
int main() {
string input;
cout << "\nWelcome to " << GRN << "devShell!\n" << NC;
cout << " Enter your command or enter exit to "
"exit.\n"
<< endl;
while (true) {
takeInput(input);
if (input == "exit") {
break;
} else if (checkForCD(input)) {
continue;
}
executeCommand(input);
}
return 0;
}