-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathshell.c
More file actions
303 lines (291 loc) · 9.22 KB
/
Copy pathshell.c
File metadata and controls
303 lines (291 loc) · 9.22 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
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
#include "shell.h"
#include "builtin.h"
#include <asm-generic/errno-base.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
void execute(char line[], struct cmdInfo *cmd_info) {
/*
Declaración de variables y reserva de memoria
*/
char *cmd = line;
struct args *cmd_args = (struct args *)malloc(sizeof(struct args));
struct execDetails *exec_details =
(struct execDetails *)malloc(sizeof(struct execDetails));
int syntax_error = 0;
int is_cmd_args_cleaned = 0;
/*
Recolectar argumentos del comando
*/
int argc = getArgs(cmd_args, cmd);
char *first_arg[argc + 1];
cmd = getArgsList(cmd_args, first_arg, argc);
cleanExec(exec_details);
// Si no hay argumentos ejecutar comando simple
if (cmd == NULL) {
execSimple(first_arg, argc, exec_details);
} else if (findRedirections(cmd, exec_details) < 0) {
syntax_error = 1; // si se encuentran errores en los argumentos se informa
// el error de sintaxis
} else {
// se toman todas las palabras del comando
cmd = exec_details->command;
if (cmd != NULL) {
if (cmd[0] == '|') { // si comienza la línea con un operador de pipe
cleanArgs(cmd_args);
is_cmd_args_cleaned = 1;
if (cmd[1] != '\0') // si no hay más nada en el comando se informa error
// de sintaxis
syntax_error = 1;
else {
// si hay más argumentos se recolectan y se repite el proceso de
// ideintificación de errores
int argc = getArgs(cmd_args, cmd + 2);
char *second_argument[argc + 1];
cmd = getArgsList(cmd_args, second_argument, argc);
if (findRedirections(cmd, exec_details) < 0)
syntax_error = 1;
else {
// si todo ocurre de manera correcta se manda a ejecutar el pipe (el
// par de comandos conectados)
execPipe(first_arg, second_argument, exec_details);
}
}
}
} else {
// si hay redirecciónes de entrada o salida se abren los ficheros y se
// ejecuta el comando simple
redirect(exec_details);
execSimple(first_arg, argc, exec_details);
}
}
// una vez ejectado todo se libera la memoria ocupada por los argumentos
if(!is_cmd_args_cleaned){
cleanArgs(cmd_args);
}
free(cmd_args);
// Se informa de errores de ejecución o se actualiza el estado
if (syntax_error) {
printf("Error: Syntax Error\n");
} else {
cmd_info->runtime_error = exec_details->runtime_error;
}
}
void execSimple(char *line[], int argc, struct execDetails *exec_details) {
// estado de la subtarea
int status = 0;
pid_t son_id; // id del hijo
son_id = fork();
int wait_signal = 0;
// Si el comando tiene el operador & al final se correrá en segundo plano
if (strcmp(line[argc - 1], "&") == 0) {
// printf("0\n");
line[argc - 1] = NULL;
wait_signal = 1;
}
// SI hubo errores a la hora de crear el proceso hijo, informar al usuario
if (son_id == -1) {
printf("Error creando el proceso");
} else if (son_id == 0 && line != NULL) {
// Si todo ocurrió correctamente, ejecutar el comando e informar de posibles
// errores en la ejecución del comando
execvp(line[0], line);
perror(line[0]);
exit(2);
} else {
// Si el comando no debía ejecutarse en segundo plano, esperar a q termine y
// guardar los detalles de la ejecución
if (wait_signal != 1) {
waitpid(son_id, &status, 0);
exec_details->runtime_error = status;
} else {
// añadir el id a la lista de procesos en segundo plano
printf("%d\n", son_id);
add_job(son_id);
// si debía ejecutarse en segundo plano, solo guardar los detalles
exec_details->runtime_error = status;
}
}
}
void execPipe(char *args1[], char *args2[], struct execDetails *exec_details) {
int fd[2]; // fd para el pipe
int pid, status = 0;
pipe(fd);
pid = fork();
if (pid == 0) {
// cerrar el fd q no se va a utilizar
close(fd[0]);
// verificar que no haya redireccióne de entrada para este comando
if (exec_details->in_file != NULL)
redirect_input(exec_details->in_file);
close(
1); // retornar a la entrada estándar (en caso de q se hubiera abierto)
// abrir el fd de escritura
dup(fd[1]);
close(fd[1]);
// ejecutar el comando
execvp(args1[0], args1);
perror(args1[0]);
exit(2);
} else {
close(fd[1]); // cerrar el fd q no se va a utilizar
pid = fork(); // crear un nuevo subproceso para el segundo comando
if (pid == 0) {
close(fd[1]);
// buscar redirecciones de salida
if (exec_details->out_file != NULL) {
if (exec_details->add == 1)
redirect_output(exec_details->out_file, 1);
else
redirect_output(exec_details->out_file, 0);
}
// leer los datos de entrada envviados por el comando anterior
close(0);
dup(fd[0]);
close(fd[0]);
// ejecutar el comando
execvp(args2[0], args2);
perror(args2[0]);
exit(2);
} else
close(fd[0]);
}
// esperar que termine la ejecución y guardar los detalles de esta
waitpid(pid, &status, 0);
exec_details->runtime_error = status;
waitpid(pid, &status, 0);
exec_details->runtime_error += status;
}
int getArgs(struct args *args, char *cmd) {
int i = 0;
struct args *cmd_args = args;
cmd = strtok(cmd, " ");
// procesar la cadena recibida y dividirla en tokens separados por espacio
while (cmd != NULL) {
// Si hay operadores de pipe o redirección de entrada o salida terminar el
// procesamiento pues ya no hay más argumentos del comando
if (cmd[0] == '>' || cmd[0] == '<' || cmd[0] == '|') {
break;
}
// añadir los comandos a cmd_args y crear un nuevo elemento para guardar el
// próximo argumento
cmd_args->arg = cmd;
cmd_args->next = (struct args *)malloc(sizeof(struct args));
cmd_args = cmd_args->next;
cmd = strtok(NULL, " ");
i++;
}
// añadir un último argumento null
cmd_args->arg = cmd;
cmd_args->next = NULL;
// modificar el argumento help para ejecutar el binario de help.c
if (strncmp(args->arg, "help", 4) == 0)
args->arg = (char *)"./help";
cleanArgs(cmd_args);
// retornar la cantidad de argumentos del comando
return i;
}
char *getArgsList(struct args *args, char **first_arg, int argc) {
// procesar todos los argumentos obtenidos en getArgs y añadirlos
// a una lista de strings
int i = 0;
while (i < argc) {
first_arg[i] = args->arg;
args = args->next;
i++;
}
first_arg[i] = NULL;
insertNULL(first_arg[i - 1]);
return args->arg;
}
void cleanExec(struct execDetails *exec_details) {
// limpiar los detalles de la ejecución
exec_details->add = 0;
exec_details->command = NULL;
exec_details->runtime_error = 0;
exec_details->in_file = NULL;
exec_details->out_file = NULL;
}
int findRedirections(char *cmd, struct execDetails *exec_details) {
if (cmd != NULL) {
// si hay redirección de entrada (<)
if (cmd[0] == '<') {
if (strlen(cmd) > 1) {
return -1;
}
// procesar la cadena para obtener el archivo q se debe abrir
cmd = strchr(cmd, ' ');
cmd = strtok(NULL, " ");
if (cmd == NULL)
return -1;
// añadir el fichero a exec details para cuando se vaya a ejecutar el
// comando
exec_details->in_file = cmd;
insertNULL(cmd);
cmd = strtok(NULL, " ");
}
// de igual manera se hace con los ficheros de salida
else if (cmd[0] == '>') {
if (cmd[1] == '>') {
if (strlen(cmd) > 2) {
return -1;
}
exec_details->add =
1; // si se debe abrir el fichero para añadir datos y no
// sobreescribir también se informa en el exec_details
} else if (strlen(cmd) > 1) {
return -1;
}
cmd = strchr(cmd, ' ');
cmd = strtok(NULL, " ");
if (cmd == NULL)
return -1;
exec_details->out_file = cmd;
insertNULL(cmd);
cmd = strtok(NULL, " ");
}
}
exec_details->command = cmd;
return 0;
}
void cleanArgs(struct args *args) {
// liberar memoria ocupada por los argumentos
struct args *arguments = args->next;
while (arguments != NULL) {
struct args *current_arg = arguments;
arguments = arguments->next;
free(current_arg);
}
}
void redirect(struct execDetails *exec_details) {
// abrir los respectivos ficheros de entrada y/o salida
if (exec_details->in_file != NULL)
redirect_input(exec_details->in_file);
else if (exec_details->out_file != NULL) {
redirect_output(exec_details->out_file, 1);
} else
redirect_output(exec_details->out_file, 0);
}
void redirect_input(char *file) {
int fd = open(file, O_RDONLY);
dup2(fd, 0);
close(fd);
}
void redirect_output(char *file, int append) {
if (!append) {
int fd;
fd = creat(file, 0777); // crea y abre el fichero con todos los permisos
close(1); // cierro la entrada estandar
dup(fd);
} else {
int fd;
fd = open(file, O_CREAT | O_WRONLY | O_APPEND,
0777); // creo el fichero o se abre si ya existe
close(1); // cierro la salida estandar
dup(fd);
}
}