-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.c
More file actions
176 lines (163 loc) · 4.87 KB
/
main.c
File metadata and controls
176 lines (163 loc) · 4.87 KB
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
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
#define MAX_JOBS_SIZE 128
#define MAX_INPUT_LENGTH 1024
#define MAX_ARGS_LENGTH 512
// info about a running command
typedef struct Command {
char name[MAX_INPUT_LENGTH];
pid_t pid;
} Command;
/**
* Array of all running commands info, and a index for its
* current size(number of running commands)
*/
static Command Jobs[MAX_JOBS_SIZE];
unsigned int NumOfJobs = 0;
/**
* Add the command info to the jobs array
* @param argsSize size of args
* @param args arguments array
* @param pid pid of the process that runs the command
*/
void add_command(unsigned argsSize, char **args, pid_t pid) {
Command c;
c.pid = pid;
// build the command name with its arguments:
for (unsigned int j = 0; j < argsSize; ++j) {
strcat(c.name, args[j]);
if (j != argsSize - 1) strcat(c.name, " ");
}
// add command info to array of Jobs
Jobs[NumOfJobs] = c;
++NumOfJobs;
}
/**
* Remove command with the given pid from jobs array
* @param pid running process pid
*/
void remove_command(pid_t pid) {
unsigned int location = 0;
for (unsigned int i = 0; i < NumOfJobs; ++i) {
if (pid == Jobs[i].pid) break;
++location;
}
for (; location < NumOfJobs; ++location)
Jobs[location] = Jobs[location + 1];
if (NumOfJobs)--NumOfJobs;
}
/**
* Print all running commands info
* @return 1, in order to tell the program to keep running
*/
int print_running_commands() {
for (unsigned int i = 0; i < NumOfJobs; ++i) {
printf("%d %s\n", Jobs[i].pid, Jobs[i].name);
}
return 1;
}
/**
* check if the command is special(either cd, exit, or jobs)
* @param args arguments
* @return 2 if no command requires special treatment, else returns command required finish status
*/
int special_commands(char **args) {
if (!strcmp(args[0], "jobs")) return print_running_commands();
else if (!strcmp(args[0], "cd")) {
if (chdir(args[1]) == -1)fprintf(stderr, "Error in system call\n");
return 1;
} else if (!strcmp(args[0], "exit")) {
_exit(0);
}
return 2;
}
/**
* execute the user's request
* @param argsSize number of arguments
* @param args arguments
* @param shouldWait 1 if father needs to wait for forked child, else 0
* @return > 0 if shell should continue running, else 0
*/
int execute(unsigned int argsSize, char **args, int shouldWait) {
int returnVal;
pid_t pid;
// collect all PID's of dead childes and remove theme from Jobs array:
while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) remove_command(pid);
if ((returnVal = special_commands(args)) == 2) {
if (!strcmp(args[0], "man")) shouldWait = 1;
if ((pid = fork()) == -1) {
fprintf(stderr, "Error in system call\n");
return 1;
}
if (!pid) { // child will execute the command
execvp(args[0], args);
fprintf(stderr, "Error in system call\n");// gets here if error occured on execute
return 1;
}
if (shouldWait) waitpid(pid,NULL, WCONTINUED); // parent will wait
else add_command(argsSize, args, pid); // parent will add the given command to Jobs and continue
}
return returnVal;
}
/**
* Read user input
* @return user input
*/
char *read_input() {
printf(">");
char input[MAX_INPUT_LENGTH] = {0};
fgets(input, MAX_INPUT_LENGTH, stdin); // input
char *line = input;
return line;
}
/**
* Split user input by spaces and create arguments array
* @param input user input
* @return array of arguments
*/
char **create_args(char *input) {
char *args[MAX_ARGS_LENGTH]; // args array
strtok(input, "\n"); // trim \n from input
char *token = strtok(input, " ");
unsigned int argsSize = 0; // number of arguments
while (token && argsSize < MAX_ARGS_LENGTH) {
args[argsSize] = token;
token = strtok(NULL, " ");
++argsSize;
} // ^ inside loop : continue splitting by space, and add arguments to args array
args[argsSize] = NULL;
char **arr = args;
return arr;
}
/**
* @param args arguments array
* @return number of arguments
*/
unsigned int number_of_args(char **args) {
unsigned int i = 0;
while (args[i]) ++i;
return i;
}
int run_shell() {
int status = 1;
while (status) {
char *input = read_input();
char **args = create_args(input);
if (**args == '\n') continue; // empty input
unsigned int argsSize = number_of_args(args);
// father will have to wait if there is no & in end of args
int shouldWait = (*args[argsSize - 1] != '&');
if (!shouldWait) { // to remove the last arg, which is &
args[argsSize - 1] = NULL;
--argsSize;
}
status = execute(argsSize, args, shouldWait);
}
return 0;
}
int main() {
return run_shell();
}