/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: 2016-06-03 17:27:03 UTC
  • Revision ID: teddy@recompile.se-20160603172703-mc6tjor6rhq4xy74
mandos: Bug fix: Do multiprocessing cleanup correctly on exit

* mandos (main): Save module "multiprocessing" and open file "wnull"
                 as scope variables accessible by function cleanup(),
                 since the module and global variable may not be
                 accessible when the cleanup() function is run as
                 scheduled by atexit().

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-2013 Teddy Hogeborn
6
 
 * Copyright © 2008-2013 Björn Påhlsson
 
5
 * Copyright © 2008-2016 Teddy Hogeborn
 
6
 * Copyright © 2008-2016 Björn Påhlsson
7
7
 * 
8
8
 * This program is free software: you can redistribute it and/or
9
9
 * modify it under the terms of the GNU General Public License as
23
23
 */
24
24
 
25
25
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), getline(),
26
 
                                   asprintf(), O_CLOEXEC */
 
26
                                   O_CLOEXEC, pipe2() */
27
27
#include <stddef.h>             /* size_t, NULL */
28
28
#include <stdlib.h>             /* malloc(), exit(), EXIT_SUCCESS,
29
29
                                   realloc() */
30
30
#include <stdbool.h>            /* bool, true, false */
31
31
#include <stdio.h>              /* fileno(), fprintf(),
32
 
                                   stderr, STDOUT_FILENO */
33
 
#include <sys/types.h>          /* DIR, fdopendir(), stat(), struct
34
 
                                   stat, waitpid(), WIFEXITED(),
35
 
                                   WEXITSTATUS(), wait(), pid_t,
36
 
                                   uid_t, gid_t, getuid(), getgid(),
37
 
                                   dirfd() */
 
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() */
38
37
#include <sys/select.h>         /* fd_set, select(), FD_ZERO(),
39
38
                                   FD_SET(), FD_ISSET(), FD_CLR */
40
39
#include <sys/wait.h>           /* wait(), waitpid(), WIFEXITED(),
41
 
                                   WEXITSTATUS(), WTERMSIG(),
42
 
                                   WCOREDUMP() */
43
 
#include <sys/stat.h>           /* struct stat, stat(), S_ISREG() */
 
40
                                   WEXITSTATUS(), WTERMSIG() */
 
41
#include <sys/stat.h>           /* struct stat, fstat(), S_ISREG() */
44
42
#include <iso646.h>             /* and, or, not */
45
 
#include <dirent.h>             /* DIR, struct dirent, fdopendir(),
46
 
                                   readdir(), closedir(), dirfd() */
47
 
#include <unistd.h>             /* struct stat, stat(), S_ISREG(),
48
 
                                   fcntl(), setuid(), setgid(),
49
 
                                   F_GETFD, F_SETFD, FD_CLOEXEC,
50
 
                                   access(), pipe(), fork(), close()
51
 
                                   dup2(), STDOUT_FILENO, _exit(),
52
 
                                   execv(), write(), read(),
53
 
                                   close() */
 
43
#include <dirent.h>             /* struct dirent, scandirat() */
 
44
#include <unistd.h>             /* fcntl(), F_GETFD, F_SETFD,
 
45
                                   FD_CLOEXEC, write(), STDOUT_FILENO,
 
46
                                   struct stat, fstat(), close(),
 
47
                                   setgid(), setuid(), S_ISREG(),
 
48
                                   faccessat() pipe2(), fork(),
 
49
                                   _exit(), dup2(), fexecve(), read()
 
50
                                */
54
51
#include <fcntl.h>              /* fcntl(), F_GETFD, F_SETFD,
55
 
                                   FD_CLOEXEC */
56
 
#include <string.h>             /* strsep, strlen(), asprintf(),
57
 
                                   strsignal(), strcmp(), strncmp() */
 
52
                                   FD_CLOEXEC, openat(), scandirat(),
 
53
                                   pipe2() */
 
54
#include <string.h>             /* strsep, strlen(), strsignal(),
 
55
                                   strcmp(), strncmp() */
58
56
#include <errno.h>              /* errno */
59
57
#include <argp.h>               /* struct argp_option, struct
60
58
                                   argp_state, struct argp,
72
70
                                   EX_CONFIG, EX_UNAVAILABLE, EX_OK */
73
71
#include <errno.h>              /* errno */
74
72
#include <error.h>              /* error() */
 
73
#include <fnmatch.h>            /* fnmatch() */
75
74
 
76
75
#define BUFFER_SIZE 256
77
76
 
78
77
#define PDIR "/lib/mandos/plugins.d"
 
78
#define PHDIR "/lib/mandos/plugin-helpers"
79
79
#define AFILE "/conf/conf.d/mandos/plugin-runner.conf"
80
80
 
81
81
const char *argp_program_version = "plugin-runner " VERSION;
240
240
  return add_to_char_array(def, &(p->environ), &(p->envc));
241
241
}
242
242
 
 
243
#ifndef O_CLOEXEC
243
244
/*
244
245
 * Based on the example in the GNU LibC manual chapter 13.13 "File
245
246
 * Descriptor Flags".
256
257
  return (int)TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD,
257
258
                                       ret | FD_CLOEXEC));
258
259
}
 
260
#endif  /* not O_CLOEXEC */
259
261
 
260
262
 
261
263
/* Mark processes as completed when they exit, and save their exit
345
347
 
346
348
int main(int argc, char *argv[]){
347
349
  char *plugindir = NULL;
 
350
  char *pluginhelperdir = NULL;
348
351
  char *argfile = NULL;
349
352
  FILE *conffp;
350
 
  size_t d_name_len;
351
 
  DIR *dir = NULL;
352
 
  struct dirent *dirst;
 
353
  struct dirent **direntries = NULL;
353
354
  struct stat st;
354
355
  fd_set rfds_all;
355
356
  int ret, maxfd = 0;
363
364
                                      .sa_flags = SA_NOCLDSTOP };
364
365
  char **custom_argv = NULL;
365
366
  int custom_argc = 0;
 
367
  int dir_fd = -1;
366
368
  
367
369
  /* Establish a signal handler */
368
370
  sigemptyset(&sigchld_action.sa_mask);
413
415
      .doc = "Group ID the plugins will run as", .group = 3 },
414
416
    { .name = "debug", .key = 132,
415
417
      .doc = "Debug mode", .group = 4 },
 
418
    { .name = "plugin-helper-dir", .key = 133,
 
419
      .arg = "DIRECTORY",
 
420
      .doc = "Specify a different plugin helper directory",
 
421
      .group = 2 },
416
422
    /*
417
423
     * These reproduce what we would get without ARGP_NO_HELP
418
424
     */
544
550
    case 132:                   /* --debug */
545
551
      debug = true;
546
552
      break;
 
553
    case 133:                   /* --plugin-helper-dir */
 
554
      free(pluginhelperdir);
 
555
      pluginhelperdir = strdup(arg);
 
556
      if(pluginhelperdir != NULL){
 
557
        errno = 0;
 
558
      }
 
559
      break;
547
560
      /*
548
561
       * These reproduce what we would get without ARGP_NO_HELP
549
562
       */
600
613
    case 130:                   /* --userid */
601
614
    case 131:                   /* --groupid */
602
615
    case 132:                   /* --debug */
 
616
    case 133:                   /* --plugin-helper-dir */
603
617
    case '?':                   /* --help */
604
618
    case -3:                    /* --usage */
605
619
    case 'V':                   /* --version */
686
700
        custom_argc += 1;
687
701
        {
688
702
          char **new_argv = realloc(custom_argv, sizeof(char *)
689
 
                                    * ((unsigned int)
690
 
                                       custom_argc + 1));
 
703
                                    * ((size_t)custom_argc + 1));
691
704
          if(new_argv == NULL){
692
705
            error(0, errno, "realloc");
693
706
            exitstatus = EX_OSERR;
760
773
    goto fallback;
761
774
  }
762
775
  
 
776
  {
 
777
    char *pluginhelperenv;
 
778
    bool bret = true;
 
779
    ret = asprintf(&pluginhelperenv, "MANDOSPLUGINHELPERDIR=%s",
 
780
                   pluginhelperdir != NULL ? pluginhelperdir : PHDIR);
 
781
    if(ret != -1){
 
782
      bret = add_environment(getplugin(NULL), pluginhelperenv, true);
 
783
    }
 
784
    if(ret == -1 or not bret){
 
785
      error(0, errno, "Failed to set MANDOSPLUGINHELPERDIR"
 
786
            " environment variable to \"%s\" for all plugins\n",
 
787
            pluginhelperdir != NULL ? pluginhelperdir : PHDIR);
 
788
    }
 
789
    if(ret != -1){
 
790
      free(pluginhelperenv);
 
791
    }
 
792
  }
 
793
  
763
794
  if(debug){
764
795
    for(plugin *p = plugin_list; p != NULL; p=p->next){
765
796
      fprintf(stderr, "Plugin: %s has %d arguments\n",
779
810
       <http://bugs.debian.org/633582> */
780
811
    int plugindir_fd = open(/* plugindir or */ PDIR, O_RDONLY);
781
812
    if(plugindir_fd == -1){
782
 
      error(0, errno, "open");
 
813
      if(errno != ENOENT){
 
814
        error(0, errno, "open(\"" PDIR "\")");
 
815
      }
783
816
    } else {
784
817
      ret = (int)TEMP_FAILURE_RETRY(fstat(plugindir_fd, &st));
785
818
      if(ret == -1){
792
825
          }
793
826
        }
794
827
      }
795
 
      TEMP_FAILURE_RETRY(close(plugindir_fd));
 
828
      close(plugindir_fd);
796
829
    }
797
830
  }
798
831
  
808
841
  
809
842
  /* Open plugin directory with close_on_exec flag */
810
843
  {
811
 
    int dir_fd = -1;
812
 
    if(plugindir == NULL){
813
 
      dir_fd = open(PDIR, O_RDONLY |
814
 
#ifdef O_CLOEXEC
815
 
                    O_CLOEXEC
816
 
#else  /* not O_CLOEXEC */
817
 
                    0
818
 
#endif  /* not O_CLOEXEC */
819
 
                    );
820
 
    } else {
821
 
      dir_fd = open(plugindir, O_RDONLY |
822
 
#ifdef O_CLOEXEC
823
 
                    O_CLOEXEC
824
 
#else  /* not O_CLOEXEC */
825
 
                    0
826
 
#endif  /* not O_CLOEXEC */
827
 
                    );
828
 
    }
 
844
    dir_fd = open(plugindir != NULL ? plugindir : PDIR, O_RDONLY |
 
845
#ifdef O_CLOEXEC
 
846
                  O_CLOEXEC
 
847
#else  /* not O_CLOEXEC */
 
848
                  0
 
849
#endif  /* not O_CLOEXEC */
 
850
                  );
829
851
    if(dir_fd == -1){
830
852
      error(0, errno, "Could not open plugin dir");
831
853
      exitstatus = EX_UNAVAILABLE;
837
859
    ret = set_cloexec_flag(dir_fd);
838
860
    if(ret < 0){
839
861
      error(0, errno, "set_cloexec_flag");
840
 
      TEMP_FAILURE_RETRY(close(dir_fd));
841
862
      exitstatus = EX_OSERR;
842
863
      goto fallback;
843
864
    }
844
865
#endif  /* O_CLOEXEC */
845
 
    
846
 
    dir = fdopendir(dir_fd);
847
 
    if(dir == NULL){
848
 
      error(0, errno, "Could not open plugin dir");
849
 
      TEMP_FAILURE_RETRY(close(dir_fd));
850
 
      exitstatus = EX_OSERR;
851
 
      goto fallback;
 
866
  }
 
867
  
 
868
  int good_name(const struct dirent * const dirent){
 
869
    const char * const patterns[] = { ".*", "#*#", "*~", "*.dpkg-new",
 
870
                                      "*.dpkg-old", "*.dpkg-bak",
 
871
                                      "*.dpkg-divert", NULL };
 
872
#ifdef __GNUC__
 
873
#pragma GCC diagnostic push
 
874
#pragma GCC diagnostic ignored "-Wcast-qual"
 
875
#endif
 
876
    for(const char **pat = (const char **)patterns;
 
877
        *pat != NULL; pat++){
 
878
#ifdef __GNUC__
 
879
#pragma GCC diagnostic pop
 
880
#endif
 
881
      if(fnmatch(*pat, dirent->d_name, FNM_FILE_NAME | FNM_PERIOD)
 
882
         != FNM_NOMATCH){
 
883
        if(debug){
 
884
            fprintf(stderr, "Ignoring plugin dir entry \"%s\""
 
885
                    " matching pattern %s\n", dirent->d_name, *pat);
 
886
        }
 
887
        return 0;
 
888
      }
852
889
    }
 
890
    return 1;
 
891
  }
 
892
  
 
893
  int numplugins = scandirat(dir_fd, ".", &direntries, good_name,
 
894
                             alphasort);
 
895
  if(numplugins == -1){
 
896
    error(0, errno, "Could not scan plugin dir");
 
897
    direntries = NULL;
 
898
    exitstatus = EX_OSERR;
 
899
    goto fallback;
853
900
  }
854
901
  
855
902
  FD_ZERO(&rfds_all);
856
903
  
857
904
  /* Read and execute any executable in the plugin directory*/
858
 
  while(true){
859
 
    do {
860
 
      dirst = readdir(dir);
861
 
    } while(dirst == NULL and errno == EINTR);
862
 
    
863
 
    /* All directory entries have been processed */
864
 
    if(dirst == NULL){
865
 
      if(errno == EBADF){
866
 
        error(0, errno, "readdir");
867
 
        exitstatus = EX_IOERR;
868
 
        goto fallback;
869
 
      }
870
 
      break;
871
 
    }
872
 
    
873
 
    d_name_len = strlen(dirst->d_name);
874
 
    
875
 
    /* Ignore dotfiles, backup files and other junk */
876
 
    {
877
 
      bool bad_name = false;
878
 
      
879
 
      const char * const bad_prefixes[] = { ".", "#", NULL };
880
 
      
881
 
      const char * const bad_suffixes[] = { "~", "#", ".dpkg-new",
882
 
                                           ".dpkg-old",
883
 
                                           ".dpkg-bak",
884
 
                                           ".dpkg-divert", NULL };
885
 
#ifdef __GNUC__
886
 
#pragma GCC diagnostic push
887
 
#pragma GCC diagnostic ignored "-Wcast-qual"
888
 
#endif
889
 
      for(const char **pre = (const char **)bad_prefixes;
890
 
          *pre != NULL; pre++){
891
 
#ifdef __GNUC__
892
 
#pragma GCC diagnostic pop
893
 
#endif
894
 
        size_t pre_len = strlen(*pre);
895
 
        if((d_name_len >= pre_len)
896
 
           and strncmp((dirst->d_name), *pre, pre_len) == 0){
897
 
          if(debug){
898
 
            fprintf(stderr, "Ignoring plugin dir entry \"%s\""
899
 
                    " with bad prefix %s\n", dirst->d_name, *pre);
900
 
          }
901
 
          bad_name = true;
902
 
          break;
903
 
        }
904
 
      }
905
 
      if(bad_name){
906
 
        continue;
907
 
      }
908
 
#ifdef __GNUC__
909
 
#pragma GCC diagnostic push
910
 
#pragma GCC diagnostic ignored "-Wcast-qual"
911
 
#endif
912
 
      for(const char **suf = (const char **)bad_suffixes;
913
 
          *suf != NULL; suf++){
914
 
#ifdef __GNUC__
915
 
#pragma GCC diagnostic pop
916
 
#endif
917
 
        size_t suf_len = strlen(*suf);
918
 
        if((d_name_len >= suf_len)
919
 
           and (strcmp((dirst->d_name) + d_name_len-suf_len, *suf)
920
 
                == 0)){
921
 
          if(debug){
922
 
            fprintf(stderr, "Ignoring plugin dir entry \"%s\""
923
 
                    " with bad suffix %s\n", dirst->d_name, *suf);
924
 
          }
925
 
          bad_name = true;
926
 
          break;
927
 
        }
928
 
      }
929
 
      
930
 
      if(bad_name){
931
 
        continue;
932
 
      }
933
 
    }
934
 
    
935
 
    char *filename;
936
 
    if(plugindir == NULL){
937
 
      ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, PDIR "/%s",
938
 
                                             dirst->d_name));
939
 
    } else {
940
 
      ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, "%s/%s",
941
 
                                             plugindir,
942
 
                                             dirst->d_name));
943
 
    }
944
 
    if(ret < 0){
945
 
      error(0, errno, "asprintf");
 
905
  for(int i = 0; i < numplugins; i++){
 
906
    
 
907
    int plugin_fd = openat(dir_fd, direntries[i]->d_name, O_RDONLY);
 
908
    if(plugin_fd == -1){
 
909
      error(0, errno, "Could not open plugin");
 
910
      free(direntries[i]);
946
911
      continue;
947
912
    }
948
 
    
949
 
    ret = (int)TEMP_FAILURE_RETRY(stat(filename, &st));
 
913
    ret = (int)TEMP_FAILURE_RETRY(fstat(plugin_fd, &st));
950
914
    if(ret == -1){
951
915
      error(0, errno, "stat");
952
 
      free(filename);
 
916
      close(plugin_fd);
 
917
      free(direntries[i]);
953
918
      continue;
954
919
    }
955
920
    
956
921
    /* Ignore non-executable files */
957
922
    if(not S_ISREG(st.st_mode)
958
 
       or (TEMP_FAILURE_RETRY(access(filename, X_OK)) != 0)){
 
923
       or (TEMP_FAILURE_RETRY(faccessat(dir_fd, direntries[i]->d_name,
 
924
                                        X_OK, 0)) != 0)){
959
925
      if(debug){
960
 
        fprintf(stderr, "Ignoring plugin dir entry \"%s\""
961
 
                " with bad type or mode\n", filename);
 
926
        fprintf(stderr, "Ignoring plugin dir entry \"%s/%s\""
 
927
                " with bad type or mode\n",
 
928
                plugindir != NULL ? plugindir : PDIR,
 
929
                direntries[i]->d_name);
962
930
      }
963
 
      free(filename);
 
931
      close(plugin_fd);
 
932
      free(direntries[i]);
964
933
      continue;
965
934
    }
966
935
    
967
 
    plugin *p = getplugin(dirst->d_name);
 
936
    plugin *p = getplugin(direntries[i]->d_name);
968
937
    if(p == NULL){
969
938
      error(0, errno, "getplugin");
970
 
      free(filename);
 
939
      close(plugin_fd);
 
940
      free(direntries[i]);
971
941
      continue;
972
942
    }
973
943
    if(p->disabled){
974
944
      if(debug){
975
945
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
976
 
                dirst->d_name);
 
946
                direntries[i]->d_name);
977
947
      }
978
 
      free(filename);
 
948
      close(plugin_fd);
 
949
      free(direntries[i]);
979
950
      continue;
980
951
    }
981
952
    {
995
966
        }
996
967
      }
997
968
    }
998
 
    /* If this plugin has any environment variables, we will call
999
 
       using execve and need to duplicate the environment from this
1000
 
       process, too. */
 
969
    /* If this plugin has any environment variables, we need to
 
970
       duplicate the environment from this process, too. */
1001
971
    if(p->environ[0] != NULL){
1002
972
      for(char **e = environ; *e != NULL; e++){
1003
973
        if(not add_environment(p, *e, false)){
1007
977
    }
1008
978
    
1009
979
    int pipefd[2];
 
980
#ifndef O_CLOEXEC
1010
981
    ret = (int)TEMP_FAILURE_RETRY(pipe(pipefd));
 
982
#else  /* O_CLOEXEC */
 
983
    ret = (int)TEMP_FAILURE_RETRY(pipe2(pipefd, O_CLOEXEC));
 
984
#endif  /* O_CLOEXEC */
1011
985
    if(ret == -1){
1012
986
      error(0, errno, "pipe");
1013
987
      exitstatus = EX_OSERR;
1014
 
      goto fallback;
1015
 
    }
 
988
      free(direntries[i]);
 
989
      goto fallback;
 
990
    }
 
991
    if(pipefd[0] >= FD_SETSIZE){
 
992
      fprintf(stderr, "pipe()[0] (%d) >= FD_SETSIZE (%d)", pipefd[0],
 
993
              FD_SETSIZE);
 
994
      close(pipefd[0]);
 
995
      close(pipefd[1]);
 
996
      exitstatus = EX_OSERR;
 
997
      free(direntries[i]);
 
998
      goto fallback;
 
999
    }
 
1000
#ifndef O_CLOEXEC
1016
1001
    /* Ask OS to automatic close the pipe on exec */
1017
1002
    ret = set_cloexec_flag(pipefd[0]);
1018
1003
    if(ret < 0){
1019
1004
      error(0, errno, "set_cloexec_flag");
 
1005
      close(pipefd[0]);
 
1006
      close(pipefd[1]);
1020
1007
      exitstatus = EX_OSERR;
 
1008
      free(direntries[i]);
1021
1009
      goto fallback;
1022
1010
    }
1023
1011
    ret = set_cloexec_flag(pipefd[1]);
1024
1012
    if(ret < 0){
1025
1013
      error(0, errno, "set_cloexec_flag");
 
1014
      close(pipefd[0]);
 
1015
      close(pipefd[1]);
1026
1016
      exitstatus = EX_OSERR;
 
1017
      free(direntries[i]);
1027
1018
      goto fallback;
1028
1019
    }
 
1020
#endif  /* not O_CLOEXEC */
1029
1021
    /* Block SIGCHLD until process is safely in process list */
1030
1022
    ret = (int)TEMP_FAILURE_RETRY(sigprocmask(SIG_BLOCK,
1031
1023
                                              &sigchld_action.sa_mask,
1033
1025
    if(ret < 0){
1034
1026
      error(0, errno, "sigprocmask");
1035
1027
      exitstatus = EX_OSERR;
 
1028
      free(direntries[i]);
1036
1029
      goto fallback;
1037
1030
    }
1038
1031
    /* Starting a new process to be watched */
1042
1035
    } while(pid == -1 and errno == EINTR);
1043
1036
    if(pid == -1){
1044
1037
      error(0, errno, "fork");
 
1038
      TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
 
1039
                                     &sigchld_action.sa_mask, NULL));
 
1040
      close(pipefd[0]);
 
1041
      close(pipefd[1]);
1045
1042
      exitstatus = EX_OSERR;
 
1043
      free(direntries[i]);
1046
1044
      goto fallback;
1047
1045
    }
1048
1046
    if(pid == 0){
1064
1062
        _exit(EX_OSERR);
1065
1063
      }
1066
1064
      
1067
 
      if(dirfd(dir) < 0){
1068
 
        /* If dir has no file descriptor, we could not set FD_CLOEXEC
1069
 
           above and must now close it manually here. */
1070
 
        closedir(dir);
1071
 
      }
1072
 
      if(p->environ[0] == NULL){
1073
 
        if(execv(filename, p->argv) < 0){
1074
 
          error(0, errno, "execv for %s", filename);
1075
 
          _exit(EX_OSERR);
1076
 
        }
1077
 
      } else {
1078
 
        if(execve(filename, p->argv, p->environ) < 0){
1079
 
          error(0, errno, "execve for %s", filename);
1080
 
          _exit(EX_OSERR);
1081
 
        }
 
1065
      if(fexecve(plugin_fd, p->argv,
 
1066
                (p->environ[0] != NULL) ? p->environ : environ) < 0){
 
1067
        error(0, errno, "fexecve for %s/%s",
 
1068
              plugindir != NULL ? plugindir : PDIR,
 
1069
              direntries[i]->d_name);
 
1070
        _exit(EX_OSERR);
1082
1071
      }
1083
1072
      /* no return */
1084
1073
    }
1085
1074
    /* Parent process */
1086
 
    TEMP_FAILURE_RETRY(close(pipefd[1])); /* Close unused write end of
1087
 
                                             pipe */
1088
 
    free(filename);
1089
 
    plugin *new_plugin = getplugin(dirst->d_name);
 
1075
    close(pipefd[1]);           /* Close unused write end of pipe */
 
1076
    close(plugin_fd);
 
1077
    plugin *new_plugin = getplugin(direntries[i]->d_name);
1090
1078
    if(new_plugin == NULL){
1091
1079
      error(0, errno, "getplugin");
1092
1080
      ret = (int)(TEMP_FAILURE_RETRY
1096
1084
        error(0, errno, "sigprocmask");
1097
1085
      }
1098
1086
      exitstatus = EX_OSERR;
 
1087
      free(direntries[i]);
1099
1088
      goto fallback;
1100
1089
    }
 
1090
    free(direntries[i]);
1101
1091
    
1102
1092
    new_plugin->pid = pid;
1103
1093
    new_plugin->fd = pipefd[0];
1113
1103
      goto fallback;
1114
1104
    }
1115
1105
    
1116
 
#if defined (__GNUC__) and defined (__GLIBC__)
1117
 
#if not __GLIBC_PREREQ(2, 16)
1118
 
#pragma GCC diagnostic push
1119
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1120
 
#endif
1121
 
#endif
1122
 
    FD_SET(new_plugin->fd, &rfds_all); /* Spurious warning from
1123
 
                                          -Wconversion in GNU libc
1124
 
                                          before 2.16 */
1125
 
#if defined (__GNUC__) and defined (__GLIBC__)
1126
 
#if not __GLIBC_PREREQ(2, 16)
1127
 
#pragma GCC diagnostic pop
1128
 
#endif
1129
 
#endif
 
1106
    FD_SET(new_plugin->fd, &rfds_all);
1130
1107
    
1131
1108
    if(maxfd < new_plugin->fd){
1132
1109
      maxfd = new_plugin->fd;
1133
1110
    }
1134
1111
  }
1135
1112
  
1136
 
  TEMP_FAILURE_RETRY(closedir(dir));
1137
 
  dir = NULL;
 
1113
  free(direntries);
 
1114
  direntries = NULL;
 
1115
  close(dir_fd);
 
1116
  dir_fd = -1;
1138
1117
  free_plugin(getplugin(NULL));
1139
1118
  
1140
1119
  for(plugin *p = plugin_list; p != NULL; p = p->next){
1179
1158
                      (intmax_t) (proc->pid),
1180
1159
                      WTERMSIG(proc->status),
1181
1160
                      strsignal(WTERMSIG(proc->status)));
1182
 
            } else if(WCOREDUMP(proc->status)){
1183
 
              fprintf(stderr, "Plugin %s [%" PRIdMAX "] dumped"
1184
 
                      " core\n", proc->name, (intmax_t) (proc->pid));
1185
1161
            }
1186
1162
          }
1187
1163
          
1188
1164
          /* Remove the plugin */
1189
 
#if defined (__GNUC__) and defined (__GLIBC__)
1190
 
#if not __GLIBC_PREREQ(2, 16)
1191
 
#pragma GCC diagnostic push
1192
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1193
 
#endif
1194
 
#endif
1195
 
          FD_CLR(proc->fd, &rfds_all); /* Spurious warning from
1196
 
                                          -Wconversion in GNU libc
1197
 
                                          before 2.16 */
1198
 
#if defined (__GNUC__) and defined (__GLIBC__)
1199
 
#if not __GLIBC_PREREQ(2, 16)
1200
 
#pragma GCC diagnostic pop
1201
 
#endif
1202
 
#endif
 
1165
          FD_CLR(proc->fd, &rfds_all);
1203
1166
          
1204
1167
          /* Block signal while modifying process_list */
1205
1168
          ret = (int)TEMP_FAILURE_RETRY(sigprocmask
1245
1208
      }
1246
1209
      
1247
1210
      /* This process has not completed.  Does it have any output? */
1248
 
#if defined (__GNUC__) and defined (__GLIBC__)
1249
 
#if not __GLIBC_PREREQ(2, 16)
1250
 
#pragma GCC diagnostic push
1251
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1252
 
#endif
1253
 
#endif
1254
 
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){ /* Spurious
1255
 
                                                         warning from
1256
 
                                                         -Wconversion
1257
 
                                                         in GNU libc
1258
 
                                                         before
1259
 
                                                         2.16 */
1260
 
#if defined (__GNUC__) and defined (__GLIBC__)
1261
 
#if not __GLIBC_PREREQ(2, 16)
1262
 
#pragma GCC diagnostic pop
1263
 
#endif
1264
 
#endif
 
1211
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
1265
1212
        /* This process had nothing to say at this time */
1266
1213
        proc = proc->next;
1267
1214
        continue;
1334
1281
    free(custom_argv);
1335
1282
  }
1336
1283
  
1337
 
  if(dir != NULL){
1338
 
    closedir(dir);
 
1284
  free(direntries);
 
1285
  
 
1286
  if(dir_fd != -1){
 
1287
    close(dir_fd);
1339
1288
  }
1340
1289
  
1341
1290
  /* Kill the processes */
1361
1310
  free_plugin_list();
1362
1311
  
1363
1312
  free(plugindir);
 
1313
  free(pluginhelperdir);
1364
1314
  free(argfile);
1365
1315
  
1366
1316
  return exitstatus;