LCOV - code coverage report
Current view: top level - src - executor.c (source / functions) Coverage Total Hit
Test: report.info Lines: 78.9 % 209 165
Test Date: 2025-02-11 09:58:02 Functions: 100.0 % 8 8

            Line data    Source code
       1              : #include "executor.h"
       2              : 
       3            2 : void sigchld_handler(int signo)
       4              : {
       5              :     int status;
       6              :     pid_t pid;
       7              : 
       8            4 :     while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
       9              :     {
      10            2 :         if (WIFEXITED(status))
      11            1 :             print_generic(STDOUT_FILENO, "[%d] Process exited with status %d.\n", pid, WEXITSTATUS(status));
      12            1 :         else if (WIFSIGNALED(status))
      13            1 :             print_generic(STDOUT_FILENO, "[%d] Process killed by signal %d.\n", pid, WTERMSIG(status));
      14              :     }
      15            2 : }
      16              : 
      17           70 : int execute_single_command(char **args)
      18              : {
      19           70 :     if (args == NULL || args[0] == NULL)
      20            8 :         return EXIT_FAILURE;
      21              : 
      22           62 :     pid_t pid = fork();
      23          124 :     if (pid < 0)
      24              :     {
      25            0 :         print_error("[ERROR] fork() failed");
      26            0 :         return EXIT_FAILURE;
      27              :     }
      28              : 
      29          124 :     if (pid == 0)
      30              :     {
      31           62 :         int child_status = custom_exec(args[0], args);
      32            3 :         if (child_status == -1)
      33              :         {
      34            3 :             print_error("[ERROR] %s", args[0]);
      35            3 :             exit(EXIT_FAILURE);
      36              :         }
      37              :     }
      38              :     else
      39              :     {
      40           62 :         if (!is_custom_command_main_process(args[0]))
      41              :         {
      42              :             int status;
      43           38 :             waitpid(pid, &status, 0);
      44           38 :             return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
      45              :         }
      46              :         else
      47              :         {
      48              :             // Wait for fork to close; ignoring result
      49              :             int status;
      50           24 :             waitpid(pid, &status, 0);
      51              : 
      52           24 :             return execute_custom_command_main_process(args[0], args) ? EXIT_SUCCESS : EXIT_FAILURE;
      53              :         }
      54              :     }
      55            0 :     return EXIT_SUCCESS;
      56              : }
      57              : 
      58            7 : int execute_pipe_command(command_node_t *node)
      59              : {
      60            7 :     if (!node || node->op_type != OP_PIPE)
      61            0 :         return EXIT_FAILURE;
      62              : 
      63              :     // Count commands
      64            7 :     int cmd_count = 1;
      65            7 :     command_node_t *current = node;
      66           11 :     while (current->left && current->left->op_type == OP_PIPE)
      67              :     {
      68            4 :         cmd_count++;
      69            4 :         current = current->left;
      70              :     }
      71            7 :     cmd_count++; // Add the last command
      72              : 
      73              :     // Collect all commands in order
      74            7 :     command_node_t **commands = malloc(cmd_count * sizeof(command_node_t *));
      75            7 :     if (!commands)
      76              :     {
      77            0 :         errno = ENOMEM;
      78            0 :         print_error("[ERROR] Failed to allocate memory for commands array");
      79            0 :         return EXIT_FAILURE;
      80              :     }
      81              : 
      82              :     // Fetch commands FROM RIGHT TO LEFT
      83            7 :     int index = cmd_count - 1;
      84            7 :     current = node;
      85            7 :     commands[index--] = current->right; // Rightmost command
      86           11 :     while (current->left && current->left->op_type == OP_PIPE)
      87              :     {
      88            4 :         commands[index--] = current->left->right;
      89            4 :         current = current->left;
      90              :     }
      91            7 :     commands[0] = current->left; // Leftmost command
      92              : 
      93              :     int pipefd[2];
      94            7 :     int prev_pipe_read = STDIN_FILENO;
      95            7 :     pid_t *pids = malloc(cmd_count * sizeof(pid_t));
      96              : 
      97            7 :     if (!pids)
      98              :     {
      99            0 :         free_if_needed(commands);
     100            0 :         errno = ENOMEM;
     101            0 :         print_error("[ERROR] Failed to allocate memory for PIDs array");
     102            0 :         return EXIT_FAILURE;
     103              :     }
     104              : 
     105           25 :     for (int i = 0; i < cmd_count; i++)
     106              :     {
     107           18 :         if (i < cmd_count - 1)
     108              :         {
     109           11 :             if (pipe(pipefd) == -1)
     110              :             {
     111            0 :                 print_error("[ERROR] Failed to create pipe");
     112            0 :                 free_if_needed(commands);
     113            0 :                 free_if_needed(pids);
     114            0 :                 return EXIT_FAILURE;
     115              :             }
     116              :         }
     117              : 
     118           18 :         pids[i] = fork();
     119           36 :         if (pids[i] < 0)
     120              :         {
     121            0 :             print_error("[ERROR] Fork failed");
     122            0 :             free_if_needed(commands);
     123            0 :             free_if_needed(pids);
     124            0 :             return EXIT_FAILURE;
     125              :         }
     126              : 
     127           36 :         if (pids[i] == 0)
     128              :         {
     129           18 :             if (i > 0)
     130              :             {
     131           11 :                 if (dup2(prev_pipe_read, STDIN_FILENO) == -1)
     132              :                 {
     133            0 :                     print_error("[ERROR] Failed to duplicate input fd");
     134            0 :                     exit(EXIT_FAILURE);
     135              :                 }
     136              :             }
     137              : 
     138           18 :             if (i < cmd_count - 1)
     139              :             {
     140           11 :                 if (dup2(pipefd[1], STDOUT_FILENO) == -1)
     141              :                 {
     142            0 :                     print_error("[ERROR] Failed to duplicate output fd");
     143            0 :                     exit(EXIT_FAILURE);
     144              :                 }
     145           11 :                 safe_close(pipefd[0]);
     146           11 :                 safe_close(pipefd[1]);
     147              :             }
     148              : 
     149           18 :             if (custom_exec(commands[i]->args[0], commands[i]->args) == -1)
     150              :             {
     151            0 :                 errno = ENOENT;
     152            0 :                 print_error("[ERROR] %s", commands[i]->args[0]);
     153            0 :                 exit(EXIT_FAILURE);
     154              :             }
     155            0 :             exit(EXIT_SUCCESS);
     156              :         }
     157              : 
     158           18 :         if (i > 0)
     159           11 :             safe_close(prev_pipe_read);
     160              : 
     161           18 :         if (i < cmd_count - 1)
     162              :         {
     163           11 :             safe_close(pipefd[1]);
     164           11 :             prev_pipe_read = pipefd[0];
     165              :         }
     166              :     }
     167              : 
     168              :     int status;
     169            7 :     int last_status = EXIT_SUCCESS;
     170           25 :     for (int i = 0; i < cmd_count; i++)
     171              :     {
     172           18 :         waitpid(pids[i], &status, 0);
     173           18 :         if (i == cmd_count - 1)
     174            7 :             last_status = WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
     175              :     }
     176              : 
     177            7 :     free_if_needed(commands);
     178            7 :     free_if_needed(pids);
     179              : 
     180            7 :     return last_status;
     181              : }
     182              : 
     183            2 : int execute_background_command(command_node_t *node)
     184              : {
     185            2 :     pid_t pid = fork();
     186            3 :     if (pid < 0)
     187              :     {
     188            0 :         print_error("[ERROR] fork() failed");
     189            0 :         return EXIT_FAILURE;
     190              :     }
     191              : 
     192            3 :     if (pid == 0)
     193              :     {
     194            1 :         int child_status = custom_exec(node->args[0], node->args);
     195            0 :         if (child_status == -1)
     196              :         {
     197            0 :             print_error("[ERROR] %s", node->args[0]);
     198            0 :             exit(EXIT_FAILURE);
     199              :         }
     200              :     }
     201              : 
     202            2 :     print_generic(STDOUT_FILENO, "[%d] %s running in background.\n", pid, node->args[0]);
     203            2 :     signal(SIGCHLD, sigchld_handler);
     204            2 :     return EXIT_SUCCESS;
     205              : }
     206              : 
     207            8 : int execute_redirection_command(command_node_t *left, command_node_t *right, operator_t redirect_type)
     208              : {
     209            8 :     if (left == NULL || right == NULL)
     210            1 :         return EXIT_FAILURE;
     211              : 
     212            7 :     int input_fd = -1;
     213            7 :     int output_fd = -1;
     214              : 
     215            7 :     switch (redirect_type)
     216              :     {
     217            2 :     case OP_REDIR_OUT:
     218            2 :         output_fd = safe_open(right->args[0], O_WRONLY | O_CREAT | O_TRUNC, 0644);
     219            2 :         break;
     220            1 :     case OP_APPEND:
     221            1 :         output_fd = safe_open(right->args[0], O_WRONLY | O_CREAT | O_APPEND, 0644);
     222            1 :         break;
     223            3 :     case OP_REDIR_IN:
     224              :     case OP_HEREDOC:
     225            3 :         input_fd = safe_open(right->args[0], O_RDONLY, 0);
     226            3 :         break;
     227            1 :     default:
     228            1 :         return EXIT_FAILURE;
     229              :     }
     230              : 
     231            6 :     if ((input_fd < 0 && (redirect_type == OP_REDIR_IN || redirect_type == OP_HEREDOC)) ||
     232            3 :         (output_fd < 0 && (redirect_type == OP_REDIR_OUT || redirect_type == OP_APPEND)))
     233              :     {
     234            0 :         print_error("[ERROR] Failed to open redirection file");
     235            0 :         return EXIT_FAILURE;
     236              :     }
     237              : 
     238            6 :     pid_t pid = fork();
     239           12 :     if (pid < 0)
     240              :     {
     241            0 :         print_error("[ERROR] fork() failed");
     242            0 :         if (input_fd >= 0)
     243            0 :             safe_close(input_fd);
     244            0 :         if (output_fd >= 0)
     245            0 :             safe_close(output_fd);
     246            0 :         return EXIT_FAILURE;
     247              :     }
     248              : 
     249           12 :     if (pid == 0)
     250              :     {
     251            6 :         if (input_fd >= 0)
     252              :         {
     253            3 :             if (dup2(input_fd, STDIN_FILENO) < 0)
     254              :             {
     255            0 :                 print_error("[ERROR] Input redirection failed");
     256            0 :                 exit(EXIT_FAILURE);
     257              :             }
     258            3 :             safe_close(input_fd);
     259              :         }
     260              : 
     261            6 :         if (output_fd >= 0)
     262              :         {
     263            3 :             if (dup2(output_fd, STDOUT_FILENO) < 0)
     264              :             {
     265            0 :                 print_error("[ERROR] Output redirection failed");
     266            0 :                 exit(EXIT_FAILURE);
     267              :             }
     268            3 :             safe_close(output_fd);
     269              :         }
     270              : 
     271            6 :         exit(execute_command_tree(left));
     272              :     }
     273              : 
     274            6 :     if (input_fd >= 0)
     275            3 :         safe_close(input_fd);
     276            6 :     if (output_fd >= 0)
     277            3 :         safe_close(output_fd);
     278              : 
     279              :     int status;
     280            6 :     waitpid(pid, &status, 0);
     281              : 
     282            6 :     return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
     283              : }
     284              : 
     285           83 : int custom_exec(char *command, char **args)
     286              : {
     287           83 :     if (command == NULL)
     288            1 :         return -1;
     289              : 
     290              :     // Custom commands
     291           82 :     if (is_custom_command(command))
     292              :     {
     293           47 :         execute_custom_command(command, args);
     294              :     }
     295              : 
     296              :     // Only reach here for non-custom commands
     297            3 :     return execvp(command, args);
     298              : }
     299              : 
     300          121 : int execute_command_tree(command_node_t *node)
     301              : {
     302          121 :     if (node == NULL)
     303            1 :         return EXIT_SUCCESS;
     304              : 
     305              :     int status;
     306              : 
     307          120 :     switch (node->op_type)
     308              :     {
     309            7 :     case OP_PIPE:
     310            7 :         status = execute_pipe_command(node);
     311            7 :         break;
     312           23 :     case OP_SEQ:
     313           23 :         if (node->left != NULL)
     314           23 :             status = execute_command_tree(node->left);
     315           23 :         if (node->right != NULL)
     316           23 :             status = execute_command_tree(node->right);
     317           23 :         break;
     318            7 :     case OP_AND:
     319            7 :         status = execute_command_tree(node->left);
     320            7 :         if (status == EXIT_SUCCESS)
     321            7 :             status = execute_command_tree(node->right);
     322            7 :         break;
     323            4 :     case OP_OR:
     324            4 :         status = execute_command_tree(node->left);
     325            4 :         if (status != EXIT_SUCCESS)
     326            1 :             status = execute_command_tree(node->right);
     327            4 :         break;
     328            2 :     case OP_BG:
     329            2 :         status = execute_background_command(node->left);
     330            2 :         break;
     331            6 :     case OP_REDIR_OUT:
     332              :     case OP_REDIR_IN:
     333              :     case OP_APPEND:
     334              :     case OP_HEREDOC:
     335            6 :         status = execute_redirection_command(node->left, node->right, node->op_type);
     336            6 :         break;
     337           70 :     case OP_NONE:
     338           70 :         status = execute_single_command(node->args);
     339           70 :         break;
     340            1 :     default:
     341            1 :         status = EXIT_FAILURE;
     342            1 :         break;
     343              :     }
     344              : 
     345          120 :     return status;
     346              : }
     347              : 
     348            4 : int execute_command(char *input, command_tree_t *command_tree)
     349              : {
     350            4 :     add_history_entry(input);
     351            4 :     command_tree = parse_command(input);
     352            4 :     if (command_tree == NULL)
     353              :     {
     354            1 :         print_error("[ERROR] Failed to parse command");
     355            1 :         return EXIT_FAILURE;
     356              :     }
     357              :     // TODO: add the command tree to the history
     358              :     // Check if command_tree is a built-in command
     359            3 :     print_command_tree(command_tree->root, 0);
     360            3 :     int status = execute_command_tree(command_tree->root);
     361            3 :     free_command_node(command_tree->root);
     362            3 :     free_if_needed(command_tree);
     363            3 :     command_tree = NULL;
     364            3 :     return status;
     365              : }
        

Generated by: LCOV version 2.0-1