From 8bcfbe6a15f6195c3501b9bde633081da67179d1 Mon Sep 17 00:00:00 2001
From: scratko <m@scratko.xyz>
Date: Wed, 5 Jun 2024 18:06:48 +0300
Subject: Signal handler

Moving zombie process cleanup to the signal handler.
---
 shell.c | 85 ++++++++++++++++++++++++++++++-----------------------------------
 1 file changed, 39 insertions(+), 46 deletions(-)

diff --git a/shell.c b/shell.c
index 9ce5a32..d3b96b3 100644
--- a/shell.c
+++ b/shell.c
@@ -7,6 +7,8 @@
 #include <string.h>
 #include <sys/wait.h>
 #include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
 
 enum modes { word_separation, whole_word };
 enum {
@@ -53,6 +55,20 @@ static void print_error()
     fprintf(stderr, "Error: unmatched quotes\n");
 }
 
+/* remove background zombie processes */
+static void handler(int signal)
+{
+    int save_errno = errno;
+    int pid;
+
+    if(signal == SIGCHLD) {
+        do {
+            pid = wait4(-1, NULL, WNOHANG, NULL);
+        } while(pid > 0);
+    }
+    errno = save_errno;
+}
+
 static void init_params(struct param_type *params, enum modes *current_mode)
 {
     params->is_word = 0;
@@ -294,16 +310,7 @@ static int start_escape_sequence(int ch, struct param_type params)
 static int excessive_words(int ch, const struct param_type *params)
 {
     int next_ch;
-#if 0
-    if(filename_waiting(params))
-        return
-            (params->tokens == '<' && params->streams.input_stream != NULL) ||
-            (params->tokens == '>' && params->streams.output_stream !=NULL) ||
-            (params->tokens == append &&
-                params->streams.output_stream_to_append != NULL);
-    else
-        return 0;
-#endif
+
     if(filename_waiting(params)) {
         if(ch == new_line)
             return 0;
@@ -320,23 +327,6 @@ static int excessive_words(int ch, const struct param_type *params)
     return 0;
 }
 
-#if 0
-static void print_word(char *word)
-{
-    putchar('[');
-    while(*word) {
-        putchar(*word);
-        ++word;
-    }
-    printf("]\n");
-}
-
-static void print_line(const struct queue *word_chain)
-{
-    queue_processing(word_chain, print_word);
-}
-#endif
-
 static char** create_cmdline(const struct queue *word_chain,
                                    int word_counter)
 {
@@ -382,14 +372,6 @@ static void clean_up_memory(struct queue *word_chain, char **cmdline,
     clear_filename(params);
 }
 
-static void clean_up_zombie_process()
-{
-    int pid;
-    do {
-        pid = wait4(-1, NULL, WNOHANG, NULL);
-    } while(pid > 0);
-}
-
 static void open_files(const struct param_type *params, int *input_fd,
                       int *output_fd)
 {
@@ -427,11 +409,13 @@ static void run_external_program(struct queue *word_chain,
                                  struct param_type *params)
 {
     int pid, wait_pid, result, input_fd, output_fd;
+    input_fd = 0;
+    output_fd = 0;
+
     if(word_chain->first == NULL) {
         fprintf(stderr, "empty command\n");
         return;
     }
-
     if(is_stream_redirection_set(params))
         open_files(params, &input_fd, &output_fd);
 
@@ -451,7 +435,16 @@ static void run_external_program(struct queue *word_chain,
             perror("fork error");
             exit(1);
         }
-        /* child process  */
+        if(params->tokens == '&')
+            /* zombie process termination on signal */
+            signal(SIGCHLD, handler);
+        else
+            /* the parent process will wait for the process to complete;
+               default signal disposition
+             */
+            signal(SIGCHLD, SIG_DFL);
+
+        /* child process */
         if(pid == 0) {
             if(is_stream_redirection_set(params))
                 change_streams(input_fd, output_fd);
@@ -460,18 +453,19 @@ static void run_external_program(struct queue *word_chain,
             perror(cmdline[0]);
             exit(1);
         }
-        /* parent process */
 
+        /* parent process */
         close_files(input_fd, output_fd);
         clean_up_memory(word_chain, cmdline, params);
 
-        /* waiting for forground process */
-        if(params->tokens != '&') {
+        /* waiting for forground process by pid*/
+        if(params->tokens != '&')
             do {
                 wait_pid = wait(&result);
             } while(wait_pid != pid);
-        } else
-            clean_up_zombie_process();
+
+        /* return of background process zombie cleanup */
+        signal(SIGCHLD, handler);
     }
 }
 
@@ -521,9 +515,9 @@ static int is_empty_word(int ch, struct param_type params)
 }
 
 static void word_separation_processing(int ch, struct param_type *params,
-                                  enum modes *current_mode,
-                                  struct queue *word_chain,
-                                  struct dynamic_array *tmp_word)
+                                       enum modes *current_mode,
+                                       struct queue *word_chain,
+                                       struct dynamic_array *tmp_word)
 {
     /* could be a marker for the beginning of a blank word */
     params->stored_symbol = ch;
@@ -636,7 +630,6 @@ int main()
     init_params(&params, &current_mode);
     show_invitation();
     while((ch = getchar()) != EOF) {
-        clean_up_zombie_process();
         if(ch == new_line)
             command_processing(&params, &current_mode, &word_chain,
                                &tmp_word, ch);
-- 
cgit v1.2.3