-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCS575_myz540_p1.cc
218 lines (188 loc) · 5.22 KB
/
CS575_myz540_p1.cc
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
/*
CS575 Operating Systems
Mike Zhong
10/2/16
Program 1
*/
// Header files needed
#include <stdio.h>
#include <iostream>
#include <vector>
#include <cstring>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <errno.h>
#include <list>
#include <fcntl.h>
// Define constants
#define MAXLINE 1024
#define MAXARGS 20
#define PROMPT "MZshell> "
#define HISTSIZE 10 // history size
using namespace std;
int parseCmd(const char *cmdline, char** arglist, int* flags);
int main(int argc, char *argv[])
{
list<string> cmd_history;
while(1){
// declare local variables
pid_t pid;
char cmd_buffer[MAXLINE];
char* arglist[MAXARGS];
char* args_passed[MAXARGS];
int argcount = 0;
int end_of_args = 0;
int last_arg = 0;
string temp_string;
int flags[4] = {0,0,0,0}; // flags array for signalling &, <, >, |
char* input = NULL; // input redirection
char* output = NULL; // output redirection
int pipefd[2];
// prompt and attemp to read in command
cout << "\n" << PROMPT << flush;
cin.getline(cmd_buffer, MAXLINE);
// if user enters nothing, keep prompting
while(cmd_buffer[0] == '\0'){
cout << "\n" << PROMPT << flush;
cin.getline(cmd_buffer, MAXLINE);
}
temp_string = cmd_buffer; // convert to string object for history
// cout << cmd_buffer << endl;
// add command to history, limit to 10 items
if(cmd_history.size() < HISTSIZE){
cmd_history.push_front(temp_string);
}
else{
cmd_history.pop_back();
cmd_history.push_front(temp_string);
}
// parse command
argcount = parseCmd(cmd_buffer, arglist, flags);
last_arg = argcount - 1;
for(int i = 0; i < argcount; ++i){
// printf("arglist[%d]: %s ", i, arglist[i]);
// check input and output redirection
// case of main < input.txt > output.txt
if(!strcmp(arglist[i], "<")){
if(!end_of_args){
end_of_args = 1;
last_arg = i - 1;
}
input = arglist[i + 1];
// cout << "input redirect detected, setting flag\n";
flags[1] = 1;
}
else if(!strcmp(arglist[i], ">")){
if(!end_of_args){
end_of_args = 1;
last_arg = i - 1;
}
// cout << "output redirect detected, setting flag\n";
output = arglist[i + 1];
flags[2] = 1;
}
}
// what to do now... set all arguments beyond the redirection operators to null
for(int i = last_arg + 1; i < argcount; ++i){
arglist[i] = NULL;
}
// not handling weird cases yet
// input = strstr(arglist[0], '<');
// check exit command
if(!strcmp(arglist[0], "exit")){
exit(1);
}
// check cd command
else if(!strcmp(arglist[0], "cd")){
if(chdir(arglist[1]) < 0){
cout << "Directory change failed\n";
}
}// check history command
else if(!strcmp(arglist[0], "history")){
cout << "displaying history\n";
for(auto iter : cmd_history){
cout << "command: " << iter << endl;
}
}
else{ // no other known commands, time to execute
// cout << "forking now\n";
pid = fork();
if(pid < 0){ // failed
cout << "Fork failed\n";
}
else if(pid == 0){ // child process
// cout << "hello from child process\n";
if(flags[1]){ // input redirection
// printf("About to redirect input to: %s\n", input);
int fd0 = open(input, O_RDONLY);
if(fd0 < 0){
cout << "open() failed\n";
}
if(dup2(fd0, STDIN_FILENO) < 0){
cout << "dup2() failed\n";
}
close(fd0);
}
if(flags[2]){ // output redirection
// printf("About to redirect output to: %s\n", output);
int fd1 = creat(output, 0644);
if(fd1 < 0){
cout << "creat() failed\n";
}
int chk1 = dup2(fd1, STDOUT_FILENO);
if(dup2(fd1, STDOUT_FILENO) < 0){
cout << "dup2() failed\n";
}
close(fd1);
}
// cout << "bout ta execute!!!\n";
execvp(arglist[0], arglist);
cout << "Unrecognized command, execvp not successful\n";
exit(0);
}
else{ // parent process
// cout << "hello from parent process\n";
if(!flags[0]){ // if it's not a background process, wait
// cout << "parent gonna wait\n";
waitpid(-1, NULL, 0);
}
}
}
}
return 0;
}
/*
* parsecmd - Parse the command line and build the argv array.
* Return the number of arguments.
*/
int parseCmd(const char *cmdline, char** arglist, int* flags)
{
static char array[MAXLINE]; /* holds local copy of command line */
char *buf = array; /* ptr that traverses command line */
char *delim; /* points to first space delimiter */
int argc; /* number of args */
strncpy(buf, cmdline, strlen(cmdline)+1);
buf[strlen(buf)] = ' '; /* replace trailing '\n' with space */
while (*buf && (*buf == ' ')) /* ignore leading spaces */
buf++;
/* Build the arglist list */
argc = 0;
// based on delimiter " "(space), separate the commandline into arglist
while ((delim = strchr(buf, ' ')) && (argc < MAXARGS - 1)) {
arglist[argc++] = buf;
*delim = '\0';
buf = delim + 1;
// check last char of arglist[0] and entirety of arglist[1] for &
if(*(delim - 1) == '&'){
flags[0] = 1;
*(delim - 1) = '\0';
}
while (*buf && (*buf == ' ')) /* ignore spaces */
buf++;
}
arglist[argc] = NULL;
return argc;
}