/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: 2021-02-03 23:10:42 UTC
  • Revision ID: teddy@recompile.se-20210203231042-2z3egrvpo1zt7nej
mandos-ctl: Fix bad test for command.Remove and related minor issues

The test for command.Remove removes all clients from the spy server,
and then loops over all clients, looking for the corresponding Remove
command as recorded by the spy server.  But since since there aren't
any clients left after they were removed, no assertions are made, and
the test therefore does nothing.  Fix this.

In tests for command.Approve and command.Deny, add checks that clients
were not somehow removed by the command (in which case, likewise, no
assertions are made).

Add related checks to TestPropertySetterCmd.runTest; i.e. test that a
sequence is not empty before looping over it and making assertions.

* mandos-ctl (TestBaseCommands.test_Remove): Save a copy of the
  original "clients" dict, and loop over those instead.  Add assertion
  that all clients were indeed removed.  Also fix the code which looks
  for the Remove command, which now needs to actually work.
  (TestBaseCommands.test_Approve, TestBaseCommands.test_Deny): Add
  assertion that there are still clients before looping over them.
  (TestPropertySetterCmd.runTest): Add assertion that the list of
  values to get is not empty before looping over them.  Also add check
  that there are still clients before looping over clients.

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-2021 Teddy Hogeborn
 
6
 * Copyright © 2008-2021 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
 
78
92
#define PDIR "/lib/mandos/plugins.d"
 
93
#define PHDIR "/lib/mandos/plugin-helpers"
79
94
#define AFILE "/conf/conf.d/mandos/plugin-runner.conf"
80
95
 
81
96
const char *argp_program_version = "plugin-runner " VERSION;
178
193
  /* Resize the pointed-to array to hold one more pointer */
179
194
  char **new_array = NULL;
180
195
  do {
181
 
    new_array = realloc(*array, sizeof(char *)
182
 
                        * (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
183
209
  } while(new_array == NULL and errno == EINTR);
184
210
  /* Malloc check */
185
211
  if(new_array == NULL){
312
338
__attribute__((nonnull))
313
339
static void free_plugin(plugin *plugin_node){
314
340
  
315
 
  for(char **arg = plugin_node->argv; *arg != NULL; arg++){
 
341
  for(char **arg = (plugin_node->argv)+1; *arg != NULL; arg++){
316
342
    free(*arg);
317
343
  }
 
344
  free(plugin_node->name);
318
345
  free(plugin_node->argv);
319
346
  for(char **env = plugin_node->environ; *env != NULL; env++){
320
347
    free(*env);
347
374
 
348
375
int main(int argc, char *argv[]){
349
376
  char *plugindir = NULL;
 
377
  char *pluginhelperdir = NULL;
350
378
  char *argfile = NULL;
351
379
  FILE *conffp;
352
380
  struct dirent **direntries = NULL;
414
442
      .doc = "Group ID the plugins will run as", .group = 3 },
415
443
    { .name = "debug", .key = 132,
416
444
      .doc = "Debug mode", .group = 4 },
 
445
    { .name = "plugin-helper-dir", .key = 133,
 
446
      .arg = "DIRECTORY",
 
447
      .doc = "Specify a different plugin helper directory",
 
448
      .group = 2 },
417
449
    /*
418
450
     * These reproduce what we would get without ARGP_NO_HELP
419
451
     */
545
577
    case 132:                   /* --debug */
546
578
      debug = true;
547
579
      break;
 
580
    case 133:                   /* --plugin-helper-dir */
 
581
      free(pluginhelperdir);
 
582
      pluginhelperdir = strdup(arg);
 
583
      if(pluginhelperdir != NULL){
 
584
        errno = 0;
 
585
      }
 
586
      break;
548
587
      /*
549
588
       * These reproduce what we would get without ARGP_NO_HELP
550
589
       */
551
590
    case '?':                   /* --help */
552
591
      state->flags &= ~(unsigned int)ARGP_NO_EXIT; /* force exit */
553
592
      argp_state_help(state, state->out_stream, ARGP_HELP_STD_HELP);
 
593
      __builtin_unreachable();
554
594
    case -3:                    /* --usage */
555
595
      state->flags &= ~(unsigned int)ARGP_NO_EXIT; /* force exit */
556
596
      argp_state_help(state, state->out_stream,
557
597
                      ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK);
 
598
      __builtin_unreachable();
558
599
    case 'V':                   /* --version */
559
600
      fprintf(state->out_stream, "%s\n", argp_program_version);
560
601
      exit(EXIT_SUCCESS);
570
611
      if(arg[0] == '\0'){
571
612
        break;
572
613
      }
 
614
#if __GNUC__ >= 7
 
615
      __attribute__((fallthrough));
 
616
#else
 
617
          /* FALLTHROUGH */
 
618
#endif
573
619
    default:
574
620
      return ARGP_ERR_UNKNOWN;
575
621
    }
601
647
    case 130:                   /* --userid */
602
648
    case 131:                   /* --groupid */
603
649
    case 132:                   /* --debug */
 
650
    case 133:                   /* --plugin-helper-dir */
604
651
    case '?':                   /* --help */
605
652
    case -3:                    /* --usage */
606
653
    case 'V':                   /* --version */
686
733
        
687
734
        custom_argc += 1;
688
735
        {
689
 
          char **new_argv = realloc(custom_argv, sizeof(char *)
690
 
                                    * ((unsigned int)
691
 
                                       custom_argc + 1));
 
736
#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 26)
 
737
          char **new_argv = reallocarray(custom_argv, (size_t)custom_argc + 1,
 
738
                                         sizeof(char *));
 
739
#else
 
740
          char **new_argv = NULL;
 
741
          if(((size_t)custom_argc + 1) > (SIZE_MAX / sizeof(char *))){
 
742
            /* overflow */
 
743
            errno = ENOMEM;
 
744
          } else {
 
745
            new_argv = realloc(custom_argv, ((size_t)custom_argc + 1)
 
746
                               * sizeof(char *));
 
747
          }
 
748
#endif
692
749
          if(new_argv == NULL){
693
 
            error(0, errno, "realloc");
 
750
            error(0, errno, "reallocarray");
694
751
            exitstatus = EX_OSERR;
695
752
            free(new_arg);
696
753
            free(org_line);
761
818
    goto fallback;
762
819
  }
763
820
  
 
821
  {
 
822
    char *pluginhelperenv;
 
823
    bool bret = true;
 
824
    ret = asprintf(&pluginhelperenv, "MANDOSPLUGINHELPERDIR=%s",
 
825
                   pluginhelperdir != NULL ? pluginhelperdir : PHDIR);
 
826
    if(ret != -1){
 
827
      bret = add_environment(getplugin(NULL), pluginhelperenv, true);
 
828
    }
 
829
    if(ret == -1 or not bret){
 
830
      error(0, errno, "Failed to set MANDOSPLUGINHELPERDIR"
 
831
            " environment variable to \"%s\" for all plugins\n",
 
832
            pluginhelperdir != NULL ? pluginhelperdir : PHDIR);
 
833
    }
 
834
    if(ret != -1){
 
835
      free(pluginhelperenv);
 
836
    }
 
837
  }
 
838
  
764
839
  if(debug){
765
 
    for(plugin *p = plugin_list; p != NULL; p=p->next){
 
840
    for(plugin *p = plugin_list; p != NULL; p = p->next){
766
841
      fprintf(stderr, "Plugin: %s has %d arguments\n",
767
842
              p->name ? p->name : "Global", p->argc - 1);
768
843
      for(char **a = p->argv; *a != NULL; a++){
777
852
  
778
853
  if(getuid() == 0){
779
854
    /* Work around Debian bug #633582:
780
 
       <http://bugs.debian.org/633582> */
 
855
       <https://bugs.debian.org/633582> */
781
856
    int plugindir_fd = open(/* plugindir or */ PDIR, O_RDONLY);
782
857
    if(plugindir_fd == -1){
783
858
      if(errno != ENOENT){
795
870
          }
796
871
        }
797
872
      }
798
 
      TEMP_FAILURE_RETRY(close(plugindir_fd));
 
873
      close(plugindir_fd);
 
874
    }
 
875
 
 
876
    /* Work around Debian bug #981302
 
877
       <https://bugs.debian.org/981302> */
 
878
    if(lstat("/dev/fd", &st) != 0 and errno == ENOENT){
 
879
      ret = symlink("/proc/self/fd", "/dev/fd");
 
880
      if(ret == -1){
 
881
        error(0, errno, "Failed to create /dev/fd symlink");
 
882
      }
799
883
    }
800
884
  }
801
885
  
860
944
    return 1;
861
945
  }
862
946
  
863
 
#ifdef __GLIBC__
864
 
#if __GLIBC_PREREQ(2, 15)
865
947
  int numplugins = scandirat(dir_fd, ".", &direntries, good_name,
866
948
                             alphasort);
867
 
#else  /* not __GLIBC_PREREQ(2, 15) */
868
 
  int numplugins = scandir(plugindir != NULL ? plugindir : PDIR,
869
 
                           &direntries, good_name, alphasort);
870
 
#endif  /* not __GLIBC_PREREQ(2, 15) */
871
 
#else   /* not __GLIBC__ */
872
 
  int numplugins = scandir(plugindir != NULL ? plugindir : PDIR,
873
 
                           &direntries, good_name, alphasort);
874
 
#endif  /* not __GLIBC__ */
875
949
  if(numplugins == -1){
876
950
    error(0, errno, "Could not scan plugin dir");
877
951
    direntries = NULL;
893
967
    ret = (int)TEMP_FAILURE_RETRY(fstat(plugin_fd, &st));
894
968
    if(ret == -1){
895
969
      error(0, errno, "stat");
896
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
970
      close(plugin_fd);
897
971
      free(direntries[i]);
898
972
      continue;
899
973
    }
908
982
                plugindir != NULL ? plugindir : PDIR,
909
983
                direntries[i]->d_name);
910
984
      }
911
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
985
      close(plugin_fd);
912
986
      free(direntries[i]);
913
987
      continue;
914
988
    }
916
990
    plugin *p = getplugin(direntries[i]->d_name);
917
991
    if(p == NULL){
918
992
      error(0, errno, "getplugin");
919
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
993
      close(plugin_fd);
920
994
      free(direntries[i]);
921
995
      continue;
922
996
    }
925
999
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
926
1000
                direntries[i]->d_name);
927
1001
      }
928
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
1002
      close(plugin_fd);
929
1003
      free(direntries[i]);
930
1004
      continue;
931
1005
    }
971
1045
    if(pipefd[0] >= FD_SETSIZE){
972
1046
      fprintf(stderr, "pipe()[0] (%d) >= FD_SETSIZE (%d)", pipefd[0],
973
1047
              FD_SETSIZE);
974
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
975
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1048
      close(pipefd[0]);
 
1049
      close(pipefd[1]);
976
1050
      exitstatus = EX_OSERR;
977
1051
      free(direntries[i]);
978
1052
      goto fallback;
982
1056
    ret = set_cloexec_flag(pipefd[0]);
983
1057
    if(ret < 0){
984
1058
      error(0, errno, "set_cloexec_flag");
985
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
986
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1059
      close(pipefd[0]);
 
1060
      close(pipefd[1]);
987
1061
      exitstatus = EX_OSERR;
988
1062
      free(direntries[i]);
989
1063
      goto fallback;
991
1065
    ret = set_cloexec_flag(pipefd[1]);
992
1066
    if(ret < 0){
993
1067
      error(0, errno, "set_cloexec_flag");
994
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
995
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1068
      close(pipefd[0]);
 
1069
      close(pipefd[1]);
996
1070
      exitstatus = EX_OSERR;
997
1071
      free(direntries[i]);
998
1072
      goto fallback;
1017
1091
      error(0, errno, "fork");
1018
1092
      TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
1019
1093
                                     &sigchld_action.sa_mask, NULL));
1020
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
1021
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1094
      close(pipefd[0]);
 
1095
      close(pipefd[1]);
1022
1096
      exitstatus = EX_OSERR;
1023
1097
      free(direntries[i]);
1024
1098
      goto fallback;
1052
1126
      /* no return */
1053
1127
    }
1054
1128
    /* Parent process */
1055
 
    TEMP_FAILURE_RETRY(close(pipefd[1])); /* Close unused write end of
1056
 
                                             pipe */
1057
 
    TEMP_FAILURE_RETRY(close(plugin_fd));
 
1129
    close(pipefd[1]);           /* Close unused write end of pipe */
 
1130
    close(plugin_fd);
1058
1131
    plugin *new_plugin = getplugin(direntries[i]->d_name);
1059
1132
    if(new_plugin == NULL){
1060
1133
      error(0, errno, "getplugin");
1072
1145
    
1073
1146
    new_plugin->pid = pid;
1074
1147
    new_plugin->fd = pipefd[0];
1075
 
    
 
1148
 
 
1149
    if(debug){
 
1150
      fprintf(stderr, "Plugin %s started (PID %" PRIdMAX ")\n",
 
1151
              new_plugin->name, (intmax_t) (new_plugin->pid));
 
1152
    }
 
1153
 
1076
1154
    /* Unblock SIGCHLD so signal handler can be run if this process
1077
1155
       has already completed */
1078
1156
    ret = (int)TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
1084
1162
      goto fallback;
1085
1163
    }
1086
1164
    
1087
 
#if defined (__GNUC__) and defined (__GLIBC__)
1088
 
#if not __GLIBC_PREREQ(2, 16)
1089
 
#pragma GCC diagnostic push
1090
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1091
 
#endif
1092
 
#endif
1093
 
    FD_SET(new_plugin->fd, &rfds_all); /* Spurious warning from
1094
 
                                          -Wconversion in GNU libc
1095
 
                                          before 2.16 */
1096
 
#if defined (__GNUC__) and defined (__GLIBC__)
1097
 
#if not __GLIBC_PREREQ(2, 16)
1098
 
#pragma GCC diagnostic pop
1099
 
#endif
1100
 
#endif
 
1165
    FD_SET(new_plugin->fd, &rfds_all);
1101
1166
    
1102
1167
    if(maxfd < new_plugin->fd){
1103
1168
      maxfd = new_plugin->fd;
1106
1171
  
1107
1172
  free(direntries);
1108
1173
  direntries = NULL;
1109
 
  TEMP_FAILURE_RETRY(close(dir_fd));
 
1174
  close(dir_fd);
1110
1175
  dir_fd = -1;
1111
1176
  free_plugin(getplugin(NULL));
1112
1177
  
1152
1217
                      (intmax_t) (proc->pid),
1153
1218
                      WTERMSIG(proc->status),
1154
1219
                      strsignal(WTERMSIG(proc->status)));
1155
 
            } else if(WCOREDUMP(proc->status)){
1156
 
              fprintf(stderr, "Plugin %s [%" PRIdMAX "] dumped"
1157
 
                      " core\n", proc->name, (intmax_t) (proc->pid));
1158
1220
            }
1159
1221
          }
1160
1222
          
1161
1223
          /* Remove the plugin */
1162
 
#if defined (__GNUC__) and defined (__GLIBC__)
1163
 
#if not __GLIBC_PREREQ(2, 16)
1164
 
#pragma GCC diagnostic push
1165
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1166
 
#endif
1167
 
#endif
1168
 
          FD_CLR(proc->fd, &rfds_all); /* Spurious warning from
1169
 
                                          -Wconversion in GNU libc
1170
 
                                          before 2.16 */
1171
 
#if defined (__GNUC__) and defined (__GLIBC__)
1172
 
#if not __GLIBC_PREREQ(2, 16)
1173
 
#pragma GCC diagnostic pop
1174
 
#endif
1175
 
#endif
 
1224
          FD_CLR(proc->fd, &rfds_all);
1176
1225
          
1177
1226
          /* Block signal while modifying process_list */
1178
1227
          ret = (int)TEMP_FAILURE_RETRY(sigprocmask
1218
1267
      }
1219
1268
      
1220
1269
      /* This process has not completed.  Does it have any output? */
1221
 
#if defined (__GNUC__) and defined (__GLIBC__)
1222
 
#if not __GLIBC_PREREQ(2, 16)
1223
 
#pragma GCC diagnostic push
1224
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1225
 
#endif
1226
 
#endif
1227
 
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){ /* Spurious
1228
 
                                                         warning from
1229
 
                                                         -Wconversion
1230
 
                                                         in GNU libc
1231
 
                                                         before
1232
 
                                                         2.16 */
1233
 
#if defined (__GNUC__) and defined (__GLIBC__)
1234
 
#if not __GLIBC_PREREQ(2, 16)
1235
 
#pragma GCC diagnostic pop
1236
 
#endif
1237
 
#endif
 
1270
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
1238
1271
        /* This process had nothing to say at this time */
1239
1272
        proc = proc->next;
1240
1273
        continue;
1310
1343
  free(direntries);
1311
1344
  
1312
1345
  if(dir_fd != -1){
1313
 
    TEMP_FAILURE_RETRY(close(dir_fd));
 
1346
    close(dir_fd);
1314
1347
  }
1315
1348
  
1316
1349
  /* Kill the processes */
1336
1369
  free_plugin_list();
1337
1370
  
1338
1371
  free(plugindir);
 
1372
  free(pluginhelperdir);
1339
1373
  free(argfile);
1340
1374
  
1341
1375
  return exitstatus;