-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEvaluation.c
719 lines (654 loc) · 21.2 KB
/
Evaluation.c
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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
#include "Evaluation.h"
#include "Shell.h"
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define ECHO "echo"
#define CD "cd"
#define SOURCE "source"
#define EXIT "exit"
#define TRUE "true"
#define FALSE "false"
sigset_t allsig; // Value sigset that represent all signals
/**
* @brief Sig Handler to install
*
* @param signum the signal to treat
*/
void sig_handler_zombies(int signum) {
int status = 0;
int w = 0;
switch(signum){
case (SIGCHLD):
do{
w = waitpid(0, &status, WNOHANG);
if(w > 0)
fprintf(stderr, "%d done\n", w);
}while(w > 0);
break;
case(SIGTTIN):
fprintf(stderr, "SIGTTIN was catched \n");
default:
break;
}
}
/**
* @brief enum to know which type of internal command to execute
*
*/
typedef enum INTERN_CMD {NO_INTERN, _ECHO, _CD, _SOURCE, _EXIT, _TRUE, _FALSE } intern_cmd;
/**
* @brief Return 1 with a message that the functionality is not implemented
*
* @return int
*/
int not_implemented_yet(void) {
fprintf(stderr, "Not implemented yet !\n");
return 1;
}
/**
* @brief check that the condition is true if not
* return 1 and show the last error with perror
*
* @param cond condition to check
* @param msg message to display
* @return int
*/
int check(int cond, char *msg) {
if (!cond) {
perror(msg);
return 1;
}
return 0;
}
/**
* @brief Return an internal_cmd,
* basically check if a command is an internal command
* or not if the command is not internal NO_INTERN is returned else see the enum
* intern_cmd
*
* @param cmd command to execute (string of character)
* @return intern_cmd
*/
intern_cmd is_internal_cmd(char *cmd) {
if (cmd == NULL) {
fprintf(stderr, "Wrong paramter passed to is_internal_cmd; cmd == NULL\n");
return -1;
}
else if (!strcmp(ECHO, cmd)) {
return _ECHO;
} else if (!strcmp(CD, cmd)) {
return _CD;
} else if (!strcmp(SOURCE, cmd)) {
return _SOURCE;
}else if(!strcmp(EXIT, cmd)){
return _EXIT;
}else if(!strcmp(TRUE, cmd)){
return _TRUE;
}
else if(!strcmp(FALSE, cmd)){
return _FALSE;
}
return NO_INTERN;
}
int _true(){
return 0;
}
int _false(){
return 1;
}
/**
* @brief Copy of the function echo in bash =>
* function repeat the input given,
* if NULL is given just do an empty line
*
* @param arguments Strings to repeat
* @return int
*/
int echo(char **arguments) {
int i = 1;
int w;
while (arguments[i]) {
if(i > 1){
w = write(1, " ", sizeof(char));
check(w > 0, "write ");
}
w = write(1, arguments[i], strlen(arguments[i]));
check(w > 0, "write ");
i++;
}
w = write(1, "\n", sizeof(char));
check(w > 0, "write");
return 0;
}
/**
* @brief Reproduce the cd command call function chdir to change directory
*
* @param path path where you want to go
* @return int return 0 on success else the return value of chdir
*/
int cd(char *path){
int ch = chdir(path);
check(ch == 0, "change directory");
return ch;
}
/**
* @brief Copy of the source command, execute the command given through a file
* Basically a shell is executed in a child and read from
* a file instead of the normal tty, so it's reading the command from the file
* and execute them one by one.
*
* @param arguments name of the file to read from (no options implemented)
* @return int return
*/
int source(char **arguments) {
int fd = open(arguments[1], O_RDONLY); // open the file
check(fd >= 0, "open"); // check opening
int pid = fork(); // create a child
if (pid == 0) { // child
dup2(fd, 0); // redirect input as the file
return 0;
// int status = execl("./Shell", "Shell", NULL); // execute a shell which
// has as input the file exit(status);
}
waitpid(pid, &status, 0); // wait for the child to finish
return status;
}
/**
* @brief Execute an internal command (only internal)
* Look at the typeof_cmd and execute the command
* that correspond to it Of not implemented error message will be displayed
*
* @param typeof_cmd enum inter_cmd to know which command to execute 0 is always
* no command
* @param arguments the arguments is the command itself with its arguments
* @param background boolean set to true if the command should be executed in
* the background
* @return int return 1 if error else 0
*/
int exec_internal_cmd(intern_cmd typeof_cmd, char **arguments,
bool background) {
if (arguments == NULL || typeof_cmd == NO_INTERN) {
fprintf(stderr, "Wrong parameter passed to exec_internal_cmd, arguments == "
"NULL or type_cmd == NULL\n");
return -1;
} else if (typeof_cmd == _ECHO) {
if (background) {
int pid = fork();
if (!pid) {
//fprintf(stderr, "echo => %d", getpid());
exit(echo(arguments)); // exit the program as a child because return is
// link to an adress
}
return 0;
}
return echo(arguments);
// return not_implemented_yet();
} else if (typeof_cmd == _CD) {
return cd(arguments[1]);
} else if (typeof_cmd == _SOURCE) {
return source(arguments);
} else if (typeof_cmd == _EXIT){
exit(0);
}else if( typeof_cmd == _TRUE){
return _true();
}else if(typeof_cmd == _FALSE){
return _false();
}
return 1;
}
/**
* @brief Given the type of redirection through option and a pipe will redirect
* STDOUT_FILENO and STDIN_FILENO to the right end of the pipe.
*
* @param option option that correspond to the type of redirection wanted
* REDIRECTION_I => redirect the
* standard input to pipe[0] (and close pipe[1]) REDIRECTION_O => redirect the
* standard output to pipe[1] (and close pipe[0]) PIPE => redirect both standard
* output and input
*
* @param pipe_fd pipe to redirect to
*/
void manage_pipe_redirection(expr_t option, int *pipe_fd) {
if ((option == REDIRECTION_I || option == REDIRECTION_O || option == PIPE) &&
pipe_fd == NULL) {
fprintf(stderr, "Pipe passed in parameter with a valid option was NULL\n");
}
if (option == REDIRECTION_I && pipe_fd != NULL) {
dup2(pipe_fd[0], 0);
close(pipe_fd[1]);
} else if (option == REDIRECTION_O && pipe_fd != NULL) {
dup2(pipe_fd[1], 1);
close(pipe_fd[0]);
} else if (option == PIPE && pipe_fd != NULL) {
dup2(pipe_fd[0], 0);
dup2(pipe_fd[1], 1);
}
}
/**
* @brief Execute a command using execvp (Cannot execute internal command)
*
* Create a child process to execute a command given
* through
* **args if option set to 0 and pipe to NULL the return value is the pid of the
* child process Meaning the caller of this function is responsible to wait or
* not for this child.$ If option and pipe set to correct values, the function
* will return 0 command will be executed in background and the child will
* become a zombie if the child process finish its job
*
* @param args Command and its arguments to execute
* @param option option for the redirection of the pipe
* REDIRECTION_I => redirect STDIN_FILENO
* to pipe[0] (close pipe[1]) REDIRECTION_O => redirect STDOUT_FILENO to pipe[1]
* (close pipe[0]) PIPE => redirect both STDOUT_FILENO and STDIN_FILENO
* @param pipe Pipe (must be initialized before the call of this function)
* @return int pid of child if option = 0 and pipe = NULL else 0
*/
int exec_command(char **args, expr_t option, int *pipe) {
int child = fork(); // create a child process
if (!child) { // code to execute for the child process
//fprintf(stderr, "%s, => %d\n", args[0], getpid());
/*int i = setpgid(getpid(), getppid());
check(i == 0, "setpgid");*/
manage_pipe_redirection(option, pipe);
execvp(args[0], args);
fprintf(stderr, "%s : command not found\n", args[0]);
exit(EXIT_FAILURE); // if execvp fails exit failure
}
return child; // return the pid of the child
}
/**
* @brief Execute a command (Can execute internal commands)
* Use exec_command and exec_internal_cmd to execute
* the given command Can execute the given command in background if background
* is set to true (meaning it's to the caller to manage the child zombies etc..)
*
* Can also execute the command with redirection of to
* a pipe with the option given The redirection is done in the child process
* meaning that the redirection of the current process is not modified.
*
* REDIRECTION_I => redirect STDIN_FILENO to pipe[0]
* (close pipe[1]) REDIRECTION_O => redirect STDOUT_FILENO to pipe[1] (close
* pipe[0]) PIPE => redirect STDOUT_FILENO and STDIN_FILENO
*
* @param args Command and its arguments to execute
* @param background boolean: true will execute the command in background, false
* in the current process
* @param option To use only with pipe to redirect the the output or input to a
* pipe
* @param pipe Pipe to redirect to
* @return int return 0 if the command didn't failed or executed in background,
* else return the status error of the command
*/
int execute_command(char **args, bool background, expr_t option, int *pipe) {
intern_cmd typeof_cmd = is_internal_cmd(args[0]);
if (typeof_cmd != NO_INTERN) { // if the command is an internal command
return exec_internal_cmd(typeof_cmd, args, background);
}
pid_t pid = exec_command(args, option, pipe); // execute the command
if (background) { // if background == true we don't wait for children
if(!pipe)
fprintf(stderr, "\n%d\n", getpid());
return 0;
}
int status; // status exit of the child
int w = waitpid(pid, &status, 0); // wait for the child
check(w > 0, "waitpid");
return status; // return status of executing the command
}
/**
* @brief Kill zombies that have been created when call it will wait for only
* child that terminated
*
*/
void zombies_collector() {
int wstatus = 0;
int w = waitpid(-1, &wstatus, WNOHANG);
// check(w < 0, "waitpid");
if (w > 0 && WIFSIGNALED(wstatus)) {
fprintf(stderr, "process %d was signaled\n", w);
fprintf(stderr, "%s\n", strsignal(WTERMSIG(wstatus)));
}
if (w > 0 && WIFSTOPPED(wstatus)) {
fprintf(stderr, "process %d was stopped\n", w);
}
if (w > 0 && WIFEXITED(wstatus)) {
fprintf(stderr, "%d, Fini\n", w);
}
if (w > 0 && WIFCONTINUED(status)) {
fprintf(stderr, "%d, Continued\n", w);
}
}
/**
* @brief Install a handler to catch SIGCHLD and get rid of zombies
*
* @param sa struct sigaction
* @param old save of the old table of the signal behavior
* @param f function handler for catching signal
*/
void zombies_collector_sig(struct sigaction sa, struct sigaction old, void (*f)(int)){
//Setting up signal handler
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
sa.sa_handler = f;
sigaction(SIGCHLD, &sa, &old);
sigset_t allsig;
sigemptyset(&allsig);
sigprocmask(SIG_BLOCK, &allsig, NULL); // block all signals
}
/**
* @brief Will set back the behavior of SIGCHLD
*
* @param old Struct sigaction of the saved signal structure
*/
void reset_handler(struct sigaction old){
sigaction(SIGCHLD, &old, NULL);
}
/**
* @brief Close both ends of a pipe passed in parameters
*
* @param pipefile
*/
void close_pipe(int *fd_p) {
if (fd_p) {
close(fd_p[0]);
close(fd_p[1]);
}
}
/**
* @brief Evaluate an expression that has a type REDIRECTION_X
* Will create the file needed and temporary
* redirect STDOUT_FILENO or STDERR_FILENO or STDIN_FILENO and execute the
* corresponding command
*
* @param e Expression to evaluate
* @param background boolean set to true if the expression should be executed in
* a background
* @param option option to know which redirection to do on the fd
* voir enum expr_t
* (REDIRECTION_I, REDIRECTION_O, REDIRECTION_EO, REDIRECTION_A ...)
* @param fd file descriptor to redirect to
* @param option_pipe when pipe is needed you can add option with a valid pipe
* (initialized before) REDIRECTION_I => redirect STDIN_FILENO to pipe[0] (close
* pipe[1]) REDIRECTION_O => redirect STDOUT_FILENO to pipe[1] (close pipe[0])
* PIPE => redirect
* both STDOUT_FILENO and STDIN_FILENO
* @param fd_p NULL if you don't want to redirect to a pipe else a valid pipe
* already initialized with function pipe()
* @return int return 0 if success else error code
*/
int evaluer_redirection(Expression *e, bool background, expr_t option, int fd,
expr_t option_pipe, int *fd_p) {
if (e == NULL) {
fprintf(stderr, "Expression passed in parameter is NULL\n");
return 1;
}
if (e->type == SIMPLE) {
return execute_command(e->arguments, background, option_pipe, fd_p);
} else if (e->type == REDIRECTION_I) {
int file = open(e->arguments[0], O_RDONLY);
check(file >= 0, "open");
int save_i = dup(0);
dup2(file, 0);
int status = evaluer_redirection(e->gauche, background, e->type, file,
option_pipe, fd_p);
dup2(save_i, 0);
close(save_i);
return status;
} else if (e->type == REDIRECTION_O) {
int file = open(e->arguments[0], O_WRONLY + O_TRUNC + O_CREAT, 0666);
check(file >= 0, "open:");
int save_o = dup(1);
dup2(file, 1);
int status = evaluer_redirection(e->gauche, background, e->type, file,
option_pipe, fd_p);
dup2(save_o, 1);
close(save_o);
close(file);
return status;
} else if (e->type == REDIRECTION_A) {
int file = open(e->arguments[0], O_WRONLY + O_APPEND + O_CREAT, 0666);
check(file >= 0, "open");
int save_o = dup(1);
dup2(file, 1);
int status = evaluer_redirection(e->gauche, background, e->type, file,
option_pipe, fd_p);
dup2(save_o, 1);
close(save_o);
return status;
} else if (e->type == REDIRECTION_E) {
int file = open(e->arguments[0], O_WRONLY + O_CREAT, 0666);
check(file >= 0, "open");
int save_e = dup(2);
dup2(file, 2);
int status = evaluer_redirection(e->gauche, background, e->type, file,
option_pipe, fd_p);
dup2(save_e, 2);
close(save_e);
return status;
} else if (e->type == REDIRECTION_EO) {
int file = open(e->arguments[0], O_WRONLY + O_CREAT, 0666);
check(file >= 0, "open");
int save_e = dup(2);
int save_o = dup(1);
dup2(file, 1);
dup2(file, 2);
int status = evaluer_redirection(e->gauche, background, e->type, file,
option_pipe, fd_p);
dup2(save_e, 2);
dup2(save_o, 1);
close(save_e);
close(save_o);
return status;
}
}
/**
* @brief Evaluate an expresion that should be executed in the background
* When called with true whenever it will call
* execute_command with background set to true
*
* If the expression is not command to execute we
* evaluate the left part normally and the right part in background until
* finding the command to execute
*
*
* @param e Expression to evaluate in the background
* @param background boolean to carry out the execution in background
* @return int return 1 in case of error because of expression, else the status
*/
int evaluer_expr_bg(Expression *e, bool background){
if (e == NULL) {
fprintf(stderr, "Expression passed in parameter is NULL\n");
return 1;
} else if (e->type == SIMPLE) {
return execute_command(e->arguments, background, 0, NULL);
}
else if(e->type >= REDIRECTION_I){
int status = evaluer_redirection(e, background, e->type, 0, 0, NULL);
return status;
}
else if(e->type == BG){
int status = evaluer_expr_bg(e->gauche, true);
return status;
}else if(e->type == PIPE){
return evaluer_expr(e);
}else if(e->type == SEQUENCE){
evaluer_expr_bg(e->gauche, false);
int status = evaluer_expr_bg(e->droite, true);
return status;
}
return not_implemented_yet();
/*int status = evaluer_expr_bg(e->gauche, true);
return evaluer_expr_bg(e->droite, true);*/
}
/**
* @brief Function to evaluate an expression of type PIPE
* Will redirect the standard output or input to
* the pipe given with the option paramater
*
* @param e Expression pipe to evaluate
* @param option option for pipe redirection
* REDIRECTION_I => redirect STDIN_FILENO
* to pipe[0] (close pipe[1]) REDIRECTION_O => redirect STDOUT_FILENO to pipe[1]
* (close pipe[0]) PIPE => redirect both STDOUT_FILENO and STDIN_FILENO
*
* @param fd_p Pipe to redirect to
* @return int return 0 if success
*/
int evaluer_pipe(Expression *e, expr_t option, int *fd_p) {
if (e == NULL) {
// to do
}
if (e->type == VIDE) {
fprintf(stderr, "Expression passed in parameter is NULL\n");
return 1;
}
if (e->type == SIMPLE) {
// return exec_command(e->arguments, option, fd_p); // doesn't handle
// internal commands
int status = execute_command(e->arguments, true, option,
fd_p); // now can execute internal command with pipes
}
if (e->type == PIPE) {
int pipe_fd[2];
pipe(pipe_fd);
int nb_children = 1 + evaluer_pipe(e->gauche, REDIRECTION_O, pipe_fd);
pipe(fd_p);
close(pipe_fd[1]);
pipe_fd[1] = fd_p[1];
nb_children += evaluer_pipe(e->droite, PIPE, pipe_fd);
return nb_children;
}
else if(e->type == BG){
return evaluer_pipe(e->gauche, option, fd_p);
}
else if (e->type >= REDIRECTION_I) {
if (option == REDIRECTION_O) {
int status;
int save_o = dup(1);
dup2(fd_p[1], 1);
status = evaluer_redirection(e, true, e->type, 0, option, fd_p);
dup2(save_o, 1);
close(save_o);
return 0;
} else if (option == REDIRECTION_I) {
int save_i = dup(0);
dup2(fd_p[0], 0);
evaluer_redirection(e, true, e->type, 0, option, fd_p);
dup2(save_i, 0);
close(save_i);
return 0;
} else if (option == PIPE) {
int save_o = dup(1);
int save_i = dup(0);
dup2(fd_p[1], 1);
dup2(fd_p[0], 0);
evaluer_redirection(e, true, e->type, 0, option, fd_p);
dup2(save_i, 0);
dup2(save_o, 1);
return 0;
}
}
}
/**
* @brief Check if you have multiple pipe for a current context in a tree
*
* @param e Expression to look
* @return int return 1 if another pipe is find else 0
*/
int multiple_pipe(Expression *e) {
if (e->gauche->type == PIPE) {
return 1;
}
return 0;
}
/**
* @brief Wait for a given number of children,
* For exemple if you created 3 zombies on purpose (with
* 2 pipes) At the end of the execution calling this function will kill the
* zombies
*
* @param nb_children number of children to wait for
* @return int return the last status return of the last children
*/
int wait_children_pipe(int nb_children) {
int status;
for (int i = 0; i < nb_children; i++) {
int w = waitpid(0, &status, 0);
// fprintf(stderr, "status %d, retrun wait = %d \n", status, w);
}
return status;
}
/**
* @brief Evaluate an expression of the tree, will look at the given type of the
* expression and execute the different functions or commands.
*
* @param e Expression to evaluate
* @return int return 0 on success else error code
*/
int evaluer_expr(Expression *e) {
struct sigaction sa, old;
zombies_collector_sig(sa, old, sig_handler_zombies); // install handler and also block all signals
//zombies_collector();
//zombies_collector_sig();
if (e == NULL) {
fprintf(stderr, "Expression passed in parameter is NULL\n");
return 1;
}
if (e->type == VIDE) {
sigprocmask(SIG_UNBLOCK, &allsig, NULL); // unblock all signals after finishing execution
return 0;
}
if (e->type == SIMPLE){
int status = execute_command(e->arguments, false, 0, NULL);
sigprocmask(SIG_UNBLOCK, &allsig, NULL); // unblock all signals after finishing execution
return status;
}
else if (e->type == SEQUENCE) {
evaluer_expr(e->gauche); // first evaluating left but
return evaluer_expr(e->droite); // then evaluate right
// we only return the value of the last cmd of the sequence ;
}
else if (e->type == SEQUENCE_ET) {
int status = evaluer_expr(e->gauche);
if (!status) { // if the evaluation of left has no error (means returned 0)
return evaluer_expr(e->droite); // evaluate the right member
}
return status; // else return error of left memeber
}
else if (e->type == SEQUENCE_OU) {
int status = evaluer_expr(e->gauche);
if (status) { // if left member fails
return evaluer_expr(e->droite);
}
return status;
}
else if (e->type == BG){
int status = evaluer_expr_bg(e->gauche, true);
sigprocmask(SIG_UNBLOCK, &allsig, NULL); // unblock all signals after finishing execution
return status;
} else if (e->type >= REDIRECTION_I){
return evaluer_redirection(e, false, 0, 0, 0, NULL);
} else if (e->type == PIPE) {
int status = 0;
int fd_p[2];
int nb_children;
if (!multiple_pipe(e)) { // if you have only one pipe
int p = pipe(fd_p);
check(p >= 0, "pipe");
}
nb_children = 1+evaluer_pipe(e->gauche, REDIRECTION_O, fd_p);
nb_children = 1+evaluer_pipe(e->droite, REDIRECTION_I, fd_p);
close_pipe(fd_p);
status = wait_children_pipe(nb_children);
sigprocmask(SIG_UNBLOCK, &allsig, NULL); // unblock all signals after finishing execution
return status;
}
return not_implemented_yet();
}