/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to plugin-runner.c

  • Committer: Teddy Hogeborn
  • Date: 2024-11-17 18:43:11 UTC
  • Revision ID: teddy@recompile.se-20241117184311-ox25kvngy62h209g
Debian package: Avoid suggesting a C compiler unnecessarily

The list of suggested packages, meant to enable the "mandos" program
to find the correct value of SO_BINDTODEVICE by using a C compiler,
are not necessary when Python 3.3 or later is used, since it has the
SO_BINDTODEVICE constant defined in the "socket" module.  Also, Python
2.6 or older has the same constant in the old "IN" module.  Therefore,
we should suggest these Python versions as alternatives to a C
compiler, so that a C compiler is not installed unnecessarily.

debian/control (Package: mandos/Suggests): Add "python3 (>= 3.3)" and
"python (<= 2.6)" as alternatives to "libc6-dev | libc-dev" and
"c-compiler".

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
/*
3
3
 * Mandos plugin runner - Run Mandos plugins
4
4
 *
5
 
 * Copyright © 2008-2014 Teddy Hogeborn
6
 
 * Copyright © 2008-2014 Björn Påhlsson
7
 
 * 
8
 
 * This program is free software: you can redistribute it and/or
9
 
 * modify it under the terms of the GNU General Public License as
10
 
 * published by the Free Software Foundation, either version 3 of the
11
 
 * License, or (at your option) any later version.
12
 
 * 
13
 
 * This program is distributed in the hope that it will be useful, but
 
5
 * Copyright © 2008-2022 Teddy Hogeborn
 
6
 * Copyright © 2008-2022 Björn Påhlsson
 
7
 * 
 
8
 * This file is part of Mandos.
 
9
 * 
 
10
 * Mandos is free software: you can redistribute it and/or modify it
 
11
 * under the terms of the GNU General Public License as published by
 
12
 * the Free Software Foundation, either version 3 of the License, or
 
13
 * (at your option) any later version.
 
14
 * 
 
15
 * Mandos is distributed in the hope that it will be useful, but
14
16
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
18
 * General Public License for more details.
17
19
 * 
18
20
 * You should have received a copy of the GNU General Public License
19
 
 * along with this program.  If not, see
20
 
 * <http://www.gnu.org/licenses/>.
 
21
 * along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
21
22
 * 
22
23
 * Contact the authors at <mandos@recompile.se>.
23
24
 */
24
25
 
25
 
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), getline(),
26
 
                                   O_CLOEXEC, pipe2() */
 
26
#define _GNU_SOURCE             /* strchrnul(), TEMP_FAILURE_RETRY(),
 
27
                                   getline(), asprintf(), O_CLOEXEC,
 
28
                                   scandirat(), pipe2() */
 
29
#include <argp.h>               /* argp_program_version,
 
30
                                   argp_program_bug_address,
 
31
                                   struct argp_option,
 
32
                                   struct argp_state, argp_error(),
 
33
                                   ARGP_NO_EXIT, argp_state_help,
 
34
                                   ARGP_HELP_STD_HELP,
 
35
                                   ARGP_HELP_USAGE, ARGP_HELP_EXIT_OK,
 
36
                                   ARGP_KEY_ARG, ARGP_ERR_UNKNOWN,
 
37
                                   struct argp, argp_parse(),
 
38
                                   ARGP_IN_ORDER, ARGP_NO_HELP */
 
39
#include <stdbool.h>            /* bool, false, true */
 
40
#include <sys/types.h>          /* pid_t, sig_atomic_t, uid_t, gid_t,
 
41
                                   getuid(), setgid(), setuid() */
27
42
#include <stddef.h>             /* size_t, NULL */
28
 
#include <stdlib.h>             /* malloc(), exit(), EXIT_SUCCESS,
29
 
                                   realloc() */
30
 
#include <stdbool.h>            /* bool, true, false */
31
 
#include <stdio.h>              /* fileno(), fprintf(),
32
 
                                   stderr, STDOUT_FILENO, fclose() */
33
 
#include <sys/types.h>          /* fstat(), struct stat, waitpid(),
34
 
                                   WIFEXITED(), WEXITSTATUS(), wait(),
35
 
                                   pid_t, uid_t, gid_t, getuid(),
36
 
                                   getgid() */
37
 
#include <sys/select.h>         /* fd_set, select(), FD_ZERO(),
38
 
                                   FD_SET(), FD_ISSET(), FD_CLR */
39
 
#include <sys/wait.h>           /* wait(), waitpid(), WIFEXITED(),
40
 
                                   WEXITSTATUS(), WTERMSIG(),
41
 
                                   WCOREDUMP() */
42
 
#include <sys/stat.h>           /* struct stat, fstat(), S_ISREG() */
43
 
#include <iso646.h>             /* and, or, not */
44
 
#include <dirent.h>             /* struct dirent, scandirat() */
45
 
#include <unistd.h>             /* fcntl(), F_GETFD, F_SETFD,
46
 
                                   FD_CLOEXEC, write(), STDOUT_FILENO,
47
 
                                   struct stat, fstat(), close(),
48
 
                                   setgid(), setuid(), S_ISREG(),
49
 
                                   faccessat() pipe2(), fork(),
50
 
                                   _exit(), dup2(), fexecve(), read()
51
 
                                */
 
43
#include <iso646.h>             /* or, and, not */
 
44
#include <string.h>             /* strcmp(), strdup(), strchrnul(),
 
45
                                   strncmp(), strlen(), strcpy(),
 
46
                                   strsep(), strchr(), strsignal() */
 
47
#include <stdlib.h>             /* malloc(), free(), reallocarray(),
 
48
                                   realloc(), EXIT_SUCCESS */
 
49
#include <errno.h>              /* errno, EINTR, ENOMEM, ECHILD,
 
50
                                   error_t, EINVAL, EMFILE, ENFILE,
 
51
                                   ENOENT, ESRCH */
 
52
#include <stdint.h>             /* SIZE_MAX */
 
53
#define _GNU_SOURCE             /* strchrnul(), TEMP_FAILURE_RETRY(),
 
54
                                   getline(), asprintf(), O_CLOEXEC,
 
55
                                   scandirat(), pipe2() */
 
56
#include <unistd.h>             /* TEMP_FAILURE_RETRY(), ssize_t,
 
57
                                   write(), STDOUT_FILENO, uid_t,
 
58
                                   gid_t, getuid(), fchown(), close(),
 
59
                                   symlink(), setgid(), setuid(),
 
60
                                   faccessat(), X_OK, pipe(), pipe2(),
 
61
                                   fork(), _exit(), dup2(), fexecve(),
 
62
                                   read(), getpass() */
52
63
#include <fcntl.h>              /* fcntl(), F_GETFD, F_SETFD,
53
 
                                   FD_CLOEXEC, openat(), scandirat(),
54
 
                                   pipe2() */
55
 
#include <string.h>             /* strsep, strlen(), strsignal(),
56
 
                                   strcmp(), strncmp() */
57
 
#include <errno.h>              /* errno */
58
 
#include <argp.h>               /* struct argp_option, struct
59
 
                                   argp_state, struct argp,
60
 
                                   argp_parse(), ARGP_ERR_UNKNOWN,
61
 
                                   ARGP_KEY_END, ARGP_KEY_ARG,
62
 
                                   error_t */
63
 
#include <signal.h>             /* struct sigaction, sigemptyset(),
64
 
                                   sigaddset(), sigaction(),
65
 
                                   sigprocmask(), SIG_BLOCK, SIGCHLD,
66
 
                                   SIG_UNBLOCK, kill(), sig_atomic_t
67
 
                                */
68
 
#include <errno.h>              /* errno, EBADF */
69
 
#include <inttypes.h>           /* intmax_t, PRIdMAX, strtoimax() */
 
64
                                   FD_CLOEXEC, open(), O_RDONLY,
 
65
                                   O_CLOEXEC, openat() */
 
66
#include <sys/wait.h>           /* waitpid(), WNOHANG, WIFEXITED(),
 
67
                                   WEXITSTATUS(), WIFSIGNALED(),
 
68
                                   WTERMSIG(), wait() */
 
69
#include <error.h>              /* error() */
 
70
#include <stdio.h>              /* FILE, fprintf(), fopen(),
 
71
                                   getline(), fclose(), EOF,
 
72
                                   asprintf(), stderr */
 
73
#include <dirent.h>             /* struct dirent, scandirat(),
 
74
                                   alphasort() */
 
75
#include <sys/stat.h>           /* struct stat, fstat(), S_ISDIR(),
 
76
                                   lstat(), S_ISREG() */
 
77
#include <sys/select.h>         /* fd_set, FD_ZERO(), FD_SETSIZE,
 
78
                                   FD_SET(), select(), FD_CLR(),
 
79
                                   FD_ISSET() */
 
80
#include <signal.h>             /* struct sigaction, SA_NOCLDSTOP,
 
81
                                   sigemptyset(), sigaddset(),
 
82
                                   SIGCHLD, sigprocmask(), SIG_BLOCK,
 
83
                                   SIG_UNBLOCK, kill(), SIGTERM */
70
84
#include <sysexits.h>           /* EX_OSERR, EX_USAGE, EX_IOERR,
71
85
                                   EX_CONFIG, EX_UNAVAILABLE, EX_OK */
72
 
#include <errno.h>              /* errno */
73
 
#include <error.h>              /* error() */
74
 
#include <fnmatch.h>            /* fnmatch() */
 
86
#include <inttypes.h>           /* intmax_t, strtoimax(), PRIdMAX */
 
87
#include <fnmatch.h>            /* fnmatch(), FNM_FILE_NAME,
 
88
                                   FNM_PERIOD, FNM_NOMATCH */
75
89
 
76
90
#define BUFFER_SIZE 256
77
91
 
179
193
  /* Resize the pointed-to array to hold one more pointer */
180
194
  char **new_array = NULL;
181
195
  do {
182
 
    new_array = realloc(*array, sizeof(char *)
183
 
                        * (size_t) ((*len) + 2));
 
196
#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 26)
 
197
    new_array = reallocarray(*array, (size_t)((*len) + 2),
 
198
                             sizeof(char *));
 
199
#else
 
200
    if(((size_t)((*len) + 2)) > (SIZE_MAX / sizeof(char *))){
 
201
      /* overflow */
 
202
      new_array = NULL;
 
203
      errno = ENOMEM;
 
204
    } else {
 
205
      new_array = realloc(*array, (size_t)((*len) + 2)
 
206
                          * sizeof(char *));
 
207
    }
 
208
#endif
184
209
  } while(new_array == NULL and errno == EINTR);
185
210
  /* Malloc check */
186
211
  if(new_array == NULL){
313
338
__attribute__((nonnull))
314
339
static void free_plugin(plugin *plugin_node){
315
340
  
316
 
  for(char **arg = plugin_node->argv; *arg != NULL; arg++){
 
341
  for(char **arg = (plugin_node->argv)+1; *arg != NULL; arg++){
317
342
    free(*arg);
318
343
  }
 
344
  free(plugin_node->name);
319
345
  free(plugin_node->argv);
320
346
  for(char **env = plugin_node->environ; *env != NULL; env++){
321
347
    free(*env);
564
590
    case '?':                   /* --help */
565
591
      state->flags &= ~(unsigned int)ARGP_NO_EXIT; /* force exit */
566
592
      argp_state_help(state, state->out_stream, ARGP_HELP_STD_HELP);
 
593
      __builtin_unreachable();
567
594
    case -3:                    /* --usage */
568
595
      state->flags &= ~(unsigned int)ARGP_NO_EXIT; /* force exit */
569
596
      argp_state_help(state, state->out_stream,
570
597
                      ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK);
 
598
      __builtin_unreachable();
571
599
    case 'V':                   /* --version */
572
600
      fprintf(state->out_stream, "%s\n", argp_program_version);
573
601
      exit(EXIT_SUCCESS);
583
611
      if(arg[0] == '\0'){
584
612
        break;
585
613
      }
 
614
#if __GNUC__ >= 7
 
615
      __attribute__((fallthrough));
 
616
#else
 
617
          /* FALLTHROUGH */
 
618
#endif
586
619
    default:
587
620
      return ARGP_ERR_UNKNOWN;
588
621
    }
700
733
        
701
734
        custom_argc += 1;
702
735
        {
703
 
          char **new_argv = realloc(custom_argv, sizeof(char *)
704
 
                                    * ((unsigned int)
705
 
                                       custom_argc + 1));
 
736
#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 26)
 
737
          char **new_argv = reallocarray(custom_argv,
 
738
                                         (size_t)custom_argc + 1,
 
739
                                         sizeof(char *));
 
740
#else
 
741
          char **new_argv = NULL;
 
742
          if(((size_t)custom_argc + 1) > (SIZE_MAX / sizeof(char *))){
 
743
            /* overflow */
 
744
            errno = ENOMEM;
 
745
          } else {
 
746
            new_argv = realloc(custom_argv, ((size_t)custom_argc + 1)
 
747
                               * sizeof(char *));
 
748
          }
 
749
#endif
706
750
          if(new_argv == NULL){
707
 
            error(0, errno, "realloc");
 
751
            error(0, errno, "reallocarray");
708
752
            exitstatus = EX_OSERR;
709
753
            free(new_arg);
710
754
            free(org_line);
794
838
  }
795
839
  
796
840
  if(debug){
797
 
    for(plugin *p = plugin_list; p != NULL; p=p->next){
 
841
    for(plugin *p = plugin_list; p != NULL; p = p->next){
798
842
      fprintf(stderr, "Plugin: %s has %d arguments\n",
799
843
              p->name ? p->name : "Global", p->argc - 1);
800
844
      for(char **a = p->argv; *a != NULL; a++){
809
853
  
810
854
  if(getuid() == 0){
811
855
    /* Work around Debian bug #633582:
812
 
       <http://bugs.debian.org/633582> */
 
856
       <https://bugs.debian.org/633582> */
813
857
    int plugindir_fd = open(/* plugindir or */ PDIR, O_RDONLY);
814
858
    if(plugindir_fd == -1){
815
859
      if(errno != ENOENT){
827
871
          }
828
872
        }
829
873
      }
830
 
      TEMP_FAILURE_RETRY(close(plugindir_fd));
 
874
      close(plugindir_fd);
 
875
    }
 
876
 
 
877
    /* Work around Debian bug #981302
 
878
       <https://bugs.debian.org/981302> */
 
879
    if(lstat("/dev/fd", &st) != 0 and errno == ENOENT){
 
880
      ret = symlink("/proc/self/fd", "/dev/fd");
 
881
      if(ret == -1){
 
882
        error(0, errno, "Failed to create /dev/fd symlink");
 
883
      }
831
884
    }
832
885
  }
833
886
  
892
945
    return 1;
893
946
  }
894
947
  
895
 
#ifdef __GLIBC__
896
 
#if __GLIBC_PREREQ(2, 15)
897
948
  int numplugins = scandirat(dir_fd, ".", &direntries, good_name,
898
949
                             alphasort);
899
 
#else  /* not __GLIBC_PREREQ(2, 15) */
900
 
  int numplugins = scandir(plugindir != NULL ? plugindir : PDIR,
901
 
                           &direntries, good_name, alphasort);
902
 
#endif  /* not __GLIBC_PREREQ(2, 15) */
903
 
#else   /* not __GLIBC__ */
904
 
  int numplugins = scandir(plugindir != NULL ? plugindir : PDIR,
905
 
                           &direntries, good_name, alphasort);
906
 
#endif  /* not __GLIBC__ */
907
950
  if(numplugins == -1){
908
951
    error(0, errno, "Could not scan plugin dir");
909
952
    direntries = NULL;
925
968
    ret = (int)TEMP_FAILURE_RETRY(fstat(plugin_fd, &st));
926
969
    if(ret == -1){
927
970
      error(0, errno, "stat");
928
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
971
      close(plugin_fd);
929
972
      free(direntries[i]);
930
973
      continue;
931
974
    }
940
983
                plugindir != NULL ? plugindir : PDIR,
941
984
                direntries[i]->d_name);
942
985
      }
943
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
986
      close(plugin_fd);
944
987
      free(direntries[i]);
945
988
      continue;
946
989
    }
948
991
    plugin *p = getplugin(direntries[i]->d_name);
949
992
    if(p == NULL){
950
993
      error(0, errno, "getplugin");
951
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
994
      close(plugin_fd);
952
995
      free(direntries[i]);
953
996
      continue;
954
997
    }
957
1000
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
958
1001
                direntries[i]->d_name);
959
1002
      }
960
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
1003
      close(plugin_fd);
961
1004
      free(direntries[i]);
962
1005
      continue;
963
1006
    }
1003
1046
    if(pipefd[0] >= FD_SETSIZE){
1004
1047
      fprintf(stderr, "pipe()[0] (%d) >= FD_SETSIZE (%d)", pipefd[0],
1005
1048
              FD_SETSIZE);
1006
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
1007
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1049
      close(pipefd[0]);
 
1050
      close(pipefd[1]);
1008
1051
      exitstatus = EX_OSERR;
1009
1052
      free(direntries[i]);
1010
1053
      goto fallback;
1014
1057
    ret = set_cloexec_flag(pipefd[0]);
1015
1058
    if(ret < 0){
1016
1059
      error(0, errno, "set_cloexec_flag");
1017
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
1018
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1060
      close(pipefd[0]);
 
1061
      close(pipefd[1]);
1019
1062
      exitstatus = EX_OSERR;
1020
1063
      free(direntries[i]);
1021
1064
      goto fallback;
1023
1066
    ret = set_cloexec_flag(pipefd[1]);
1024
1067
    if(ret < 0){
1025
1068
      error(0, errno, "set_cloexec_flag");
1026
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
1027
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1069
      close(pipefd[0]);
 
1070
      close(pipefd[1]);
1028
1071
      exitstatus = EX_OSERR;
1029
1072
      free(direntries[i]);
1030
1073
      goto fallback;
1049
1092
      error(0, errno, "fork");
1050
1093
      TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
1051
1094
                                     &sigchld_action.sa_mask, NULL));
1052
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
1053
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1095
      close(pipefd[0]);
 
1096
      close(pipefd[1]);
1054
1097
      exitstatus = EX_OSERR;
1055
1098
      free(direntries[i]);
1056
1099
      goto fallback;
1084
1127
      /* no return */
1085
1128
    }
1086
1129
    /* Parent process */
1087
 
    TEMP_FAILURE_RETRY(close(pipefd[1])); /* Close unused write end of
1088
 
                                             pipe */
1089
 
    TEMP_FAILURE_RETRY(close(plugin_fd));
 
1130
    close(pipefd[1]);           /* Close unused write end of pipe */
 
1131
    close(plugin_fd);
1090
1132
    plugin *new_plugin = getplugin(direntries[i]->d_name);
1091
1133
    if(new_plugin == NULL){
1092
1134
      error(0, errno, "getplugin");
1104
1146
    
1105
1147
    new_plugin->pid = pid;
1106
1148
    new_plugin->fd = pipefd[0];
1107
 
    
 
1149
 
 
1150
    if(debug){
 
1151
      fprintf(stderr, "Plugin %s started (PID %" PRIdMAX ")\n",
 
1152
              new_plugin->name, (intmax_t) (new_plugin->pid));
 
1153
    }
 
1154
 
1108
1155
    /* Unblock SIGCHLD so signal handler can be run if this process
1109
1156
       has already completed */
1110
1157
    ret = (int)TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
1116
1163
      goto fallback;
1117
1164
    }
1118
1165
    
1119
 
#if defined (__GNUC__) and defined (__GLIBC__)
1120
 
#if not __GLIBC_PREREQ(2, 16)
1121
 
#pragma GCC diagnostic push
1122
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1123
 
#endif
1124
 
#endif
1125
 
    FD_SET(new_plugin->fd, &rfds_all); /* Spurious warning from
1126
 
                                          -Wconversion in GNU libc
1127
 
                                          before 2.16 */
1128
 
#if defined (__GNUC__) and defined (__GLIBC__)
1129
 
#if not __GLIBC_PREREQ(2, 16)
1130
 
#pragma GCC diagnostic pop
1131
 
#endif
1132
 
#endif
 
1166
    FD_SET(new_plugin->fd, &rfds_all);
1133
1167
    
1134
1168
    if(maxfd < new_plugin->fd){
1135
1169
      maxfd = new_plugin->fd;
1138
1172
  
1139
1173
  free(direntries);
1140
1174
  direntries = NULL;
1141
 
  TEMP_FAILURE_RETRY(close(dir_fd));
 
1175
  close(dir_fd);
1142
1176
  dir_fd = -1;
1143
1177
  free_plugin(getplugin(NULL));
1144
1178
  
1184
1218
                      (intmax_t) (proc->pid),
1185
1219
                      WTERMSIG(proc->status),
1186
1220
                      strsignal(WTERMSIG(proc->status)));
1187
 
            } else if(WCOREDUMP(proc->status)){
1188
 
              fprintf(stderr, "Plugin %s [%" PRIdMAX "] dumped"
1189
 
                      " core\n", proc->name, (intmax_t) (proc->pid));
1190
1221
            }
1191
1222
          }
1192
1223
          
1193
1224
          /* Remove the plugin */
1194
 
#if defined (__GNUC__) and defined (__GLIBC__)
1195
 
#if not __GLIBC_PREREQ(2, 16)
1196
 
#pragma GCC diagnostic push
1197
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1198
 
#endif
1199
 
#endif
1200
 
          FD_CLR(proc->fd, &rfds_all); /* Spurious warning from
1201
 
                                          -Wconversion in GNU libc
1202
 
                                          before 2.16 */
1203
 
#if defined (__GNUC__) and defined (__GLIBC__)
1204
 
#if not __GLIBC_PREREQ(2, 16)
1205
 
#pragma GCC diagnostic pop
1206
 
#endif
1207
 
#endif
 
1225
          FD_CLR(proc->fd, &rfds_all);
1208
1226
          
1209
1227
          /* Block signal while modifying process_list */
1210
1228
          ret = (int)TEMP_FAILURE_RETRY(sigprocmask
1250
1268
      }
1251
1269
      
1252
1270
      /* This process has not completed.  Does it have any output? */
1253
 
#if defined (__GNUC__) and defined (__GLIBC__)
1254
 
#if not __GLIBC_PREREQ(2, 16)
1255
 
#pragma GCC diagnostic push
1256
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1257
 
#endif
1258
 
#endif
1259
 
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){ /* Spurious
1260
 
                                                         warning from
1261
 
                                                         -Wconversion
1262
 
                                                         in GNU libc
1263
 
                                                         before
1264
 
                                                         2.16 */
1265
 
#if defined (__GNUC__) and defined (__GLIBC__)
1266
 
#if not __GLIBC_PREREQ(2, 16)
1267
 
#pragma GCC diagnostic pop
1268
 
#endif
1269
 
#endif
 
1271
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
1270
1272
        /* This process had nothing to say at this time */
1271
1273
        proc = proc->next;
1272
1274
        continue;
1342
1344
  free(direntries);
1343
1345
  
1344
1346
  if(dir_fd != -1){
1345
 
    TEMP_FAILURE_RETRY(close(dir_fd));
 
1347
    close(dir_fd);
1346
1348
  }
1347
1349
  
1348
1350
  /* Kill the processes */