-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprog_execution.c
More file actions
239 lines (204 loc) · 6.43 KB
/
prog_execution.c
File metadata and controls
239 lines (204 loc) · 6.43 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
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
233
234
235
236
237
238
//Darshil Patel
//3-22-23
//CIS 3207: Systems Programming and Operating System
//Project 2 : SHELL similar to tsch
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdbool.h>
#include <errno.h>
#include <sys/types.h>
#include "tools.h"
//Count number of pipes in command-line
int count_pipes(char **args) {
int num_pipes = 0;
for (int i = 0; args[i] != NULL; i++) {
if (strcmp(args[i], "|") == 0) {
num_pipes++;
}
}
return num_pipes;
}
//Prepare command to parse
//Code was provided
void prep_to_parse(char *get_line) {
char _line[1000];
strncpy(_line, get_line, sizeof(_line) - 1);
_line[sizeof(_line) - 1] = '\0';
char *line = strdup(_line);
char **array = parse(line, " ");
int num_pipes = count_pipes(array);
if (num_pipes > 0) {
execute_pipes(array, num_pipes);
}
else {
program_execution(array);
}
//program_execution(array);
/*
if (array == NULL)
{
exit(1);
}*/
/*
int i = 0;
while (array[i] != NULL)
{
printf("%s", array[i++]);
}*/
free(array);
free(line);
}
//Code was provided
char **parse(char *line, char *delim) {
char **array = malloc(sizeof(char *));
*array = NULL;
int n = 0;
char *buf = strtok(line, delim);
if (buf == NULL) {
free(array);
array = NULL;
return array;
}
while (buf != NULL) {
char **temp = realloc(array, (n + 2) * sizeof(char *));
if (temp == NULL) {
free(array);
array = NULL;
return array;
}
array = temp;
temp[n++] = buf;
temp[n] = NULL;
buf = strtok(NULL, delim);
}
return array;
}
//Search for an executable file with the given command name in the directories
//listed in the PATH Environment Variable
char *search_executable(const char *command) {
char *path = getenv("PATH"); //get value of the PATH environment variable using the getenv
if (path == NULL) { //check if PATH is not NULL
return NULL;
}
//Create copy of path string for later use needed for parsing the directories.
char *path_copy = strdup(path);
char *saveptr;
char *dir = strtok_r(path_copy, ":", &saveptr);
//Loop keeps calling strtok_r to tokenize the path_copy string, and it looks
//for an executable file with the given command name
while (dir)
{
char *full_path = malloc(strlen(dir) + strlen(command) + 2);
strcpy(full_path, dir); //copy to full_path
strcat(full_path, "/");
strcat(full_path, command);
//Checks if resulting full_path corresponds to existing executable file for execution
//Access function is used to do this, and the X_OK argument specifies that the file must be executable.
//If an executable file is found, the function returns the full_path string.
if (access(full_path, X_OK) == 0) {
free(path_copy);
return full_path;
}
free(full_path);
dir = strtok_r(NULL, ":", &saveptr); //Restart while loop by calling strtok_r again
}
free(path_copy);
return NULL;
}
//Executes external commands by taking in list of args
void program_execution(char **args) {
//for echo
if (strcmp(args[0], "echo") == 0) {
for (int i = 1; args[i] != NULL; i++) { //checks if its echo command
if (args[i][0] == '$') { //If so, it handles it separately by printing the arguments to the console.
char *environment_var = getenv(args[i] + 1); //If an argument starts with $, it checks for an environment variable
if (environment_var) { //with the corresponding name and prints its value.
printf("%s ", environment_var);
}
}
else {
printf("%s ", args[i]);
}
}
printf("\n");
return;
}
pid_t pid = fork();
int status;
//block of code runs in the child process. It handles input/output redirection by calling
//process_redirection function, which sets up file descriptors for input and output based
//on any < or > characters found in the argument list.
//If an executable path is found by calling search_executable function, it is executed using execv function.
//execv replaces the current process with a new process image, and if it succeeds, it never returns.
//If execv fails, an error message is printed to stderr, and the child process exits with failure status.
if (pid == 0) {
// Child process
// Handle input/output redirection
int input_fd = -1;
int output_fd = -1;
if (process_redirection(args, &input_fd, &output_fd) == -1)
{
exit(EXIT_FAILURE);
}
if (input_fd != -1)
{
dup2(input_fd, STDIN_FILENO);
close(input_fd);
}
if (output_fd != -1)
{
dup2(output_fd, STDOUT_FILENO);
close(output_fd);
}
char *executable_path = NULL;
// If the command starts with '/', use the provided full path
if (args[0][0] == '/')
{
executable_path = args[0];
}
else
{
executable_path = search_executable(args[0]);
}
if (executable_path)
{
if (execv(executable_path, args) == -1)
{
fprintf(stderr, "Error 404 in executing '%s': %s\n", args[0], strerror(errno));
exit(EXIT_FAILURE);
}
if (args[0][0] != '/')
{
free(executable_path);
}
}
else
{
fprintf(stderr, "Error 404 '%s' cannot be found\n", args[0]);
exit(EXIT_FAILURE);
}
}
else if (pid < 0)
{
perror("Error 404");
exit(EXIT_FAILURE);
}
//Runs in the parent process.
//It waits for the child process to terminate using waitpid function.
{
// Parent process
do
{
pid_t w = waitpid(pid, &status, WUNTRACED);
if (w == -1)
{
perror("Error to get waid PID");
exit(EXIT_FAILURE);
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
}