/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: 2008-12-10 01:26:02 UTC
  • mfrom: (237.1.2 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20081210012602-vhz3h75xkj24t340
First version of a somewhat complete D-Bus server interface.  Also
change user/group name to "_mandos".

* debian/mandos.postinst: Rename old "mandos" user and group to
                          "_mandos"; create "_mandos" user and group
                          if none exist.
* debian/mandos-client.postinst: - '' -

* initramfs-tools-hook: Try "_mandos" before "mandos" as user and
                        group name.

* mandos (_datetime_to_dbus_struct): New; was previously local.
  (Client.started): Renamed to "last_started".  All users changed.
  (Client.started): New; boolean.
  (Client.dbus_object_path): New.
  (Client.check_command): Renamed to "checker_command".  All users
                          changed.
  (Client.__init__): Set and use "self.dbus_object_path".  Set
                     "self.started".
  (Client.start): Update "self.started".  Emit "self.PropertyChanged"
                  signals for both "started" and "last_started".
  (Client.stop): Update "self.started".  Emit "self.PropertyChanged"
                 signal for "started".
  (Client.checker_callback): Take additional "command" argument.  All
                             callers changed. Emit
                             "self.PropertyChanged" signal.
  (Client.bump_timeout): Emit "self.PropertyChanged" signal for
                         "last_checked_ok".
  (Client.start_checker): Emit "self.PropertyChanged" signal for
                          "checker_running".
  (Client.stop_checker): Emit "self.PropertyChanged" signal for
                         "checker_running".
  (Client.still_valid): Bug fix: use "getattr(self, started, False)"
                        instead of "self.started" in case this client
                        object is so new that the "started" attribute
                        has not been created yet.
  (Client.IntervalChanged, Client.CheckerIsRunning, Client.GetChecker,
  Client.GetCreated, Client.GetFingerprint, Client.GetHost,
  Client.GetInterval, Client.GetName, Client.GetStarted,
  Client.GetTimeout, Client.StateChanged, Client.TimeoutChanged):
  Removed; all callers changed.
  (Client.CheckerCompleted): Add "condition" and "command" arguments.
                             All callers changed.
  (Client.GetAllProperties, Client.PropertyChanged): New.
  (Client.StillValid): Renamed to "IsStillValid".
  (Client.StartChecker): Changed to its own function to avoid the
                         return value from "Client.start_checker()".
  (Client.Stop): Changed to its own function to avoid the return value
                 from "Client.stop()".
  (main): Try "_mandos" before "mandos" as user and group name.
          Removed inner function "remove_from_clients".  New inner
          class "MandosServer".

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,2009 Teddy Hogeborn
6
 
 * Copyright © 2008,2009 Björn Påhlsson
 
5
 * Copyright © 2008 Teddy Hogeborn
 
6
 * Copyright © 2008 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
38
38
#include <sys/select.h>         /* fd_set, select(), FD_ZERO(),
39
39
                                   FD_SET(), FD_ISSET(), FD_CLR */
40
40
#include <sys/wait.h>           /* wait(), waitpid(), WIFEXITED(),
41
 
                                   WEXITSTATUS(), WTERMSIG(),
42
 
                                   WCOREDUMP() */
 
41
                                   WEXITSTATUS() */
43
42
#include <sys/stat.h>           /* struct stat, stat(), S_ISREG() */
44
43
#include <iso646.h>             /* and, or, not */
45
44
#include <dirent.h>             /* DIR, struct dirent, opendir(),
53
52
                                   close() */
54
53
#include <fcntl.h>              /* fcntl(), F_GETFD, F_SETFD,
55
54
                                   FD_CLOEXEC */
56
 
#include <string.h>             /* strsep, strlen(), asprintf(),
57
 
                                   strsignal() */
 
55
#include <string.h>             /* strsep, strlen(), asprintf() */
58
56
#include <errno.h>              /* errno */
59
57
#include <argp.h>               /* struct argp_option, struct
60
58
                                   argp_state, struct argp,
64
62
#include <signal.h>             /* struct sigaction, sigemptyset(),
65
63
                                   sigaddset(), sigaction(),
66
64
                                   sigprocmask(), SIG_BLOCK, SIGCHLD,
67
 
                                   SIG_UNBLOCK, kill(), sig_atomic_t
68
 
                                */
 
65
                                   SIG_UNBLOCK, kill() */
69
66
#include <errno.h>              /* errno, EBADF */
70
 
#include <inttypes.h>           /* intmax_t, PRIdMAX, strtoimax() */
71
67
 
72
68
#define BUFFER_SIZE 256
73
69
 
84
80
  char **environ;
85
81
  int envc;
86
82
  bool disabled;
87
 
  
 
83
 
88
84
  /* Variables used for running processes*/
89
85
  pid_t pid;
90
86
  int fd;
92
88
  size_t buffer_size;
93
89
  size_t buffer_length;
94
90
  bool eof;
95
 
  volatile sig_atomic_t completed;
96
 
  int status;
 
91
  volatile bool completed;
 
92
  volatile int status;
97
93
  struct plugin *next;
98
94
} plugin;
99
95
 
103
99
   or if none is found, creates a new one */
104
100
static plugin *getplugin(char *name){
105
101
  /* Check for exiting plugin with that name */
106
 
  for(plugin *p = plugin_list; p != NULL; p = p->next){
107
 
    if((p->name == name)
108
 
       or (p->name and name and (strcmp(p->name, name) == 0))){
 
102
  for (plugin *p = plugin_list; p != NULL; p = p->next){
 
103
    if ((p->name == name)
 
104
        or (p->name and name and (strcmp(p->name, name) == 0))){
109
105
      return p;
110
106
    }
111
107
  }
112
108
  /* Create a new plugin */
113
109
  plugin *new_plugin = malloc(sizeof(plugin));
114
 
  if(new_plugin == NULL){
 
110
  if (new_plugin == NULL){
115
111
    return NULL;
116
112
  }
117
113
  char *copy_name = NULL;
118
114
  if(name != NULL){
119
115
    copy_name = strdup(name);
120
116
    if(copy_name == NULL){
121
 
      free(new_plugin);
122
117
      return NULL;
123
118
    }
124
119
  }
125
120
  
126
 
  *new_plugin = (plugin){ .name = copy_name,
127
 
                          .argc = 1,
128
 
                          .disabled = false,
129
 
                          .next = plugin_list };
 
121
  *new_plugin = (plugin) { .name = copy_name,
 
122
                           .argc = 1,
 
123
                           .disabled = false,
 
124
                           .next = plugin_list };
130
125
  
131
126
  new_plugin->argv = malloc(sizeof(char *) * 2);
132
 
  if(new_plugin->argv == NULL){
 
127
  if (new_plugin->argv == NULL){
133
128
    free(copy_name);
134
129
    free(new_plugin);
135
130
    return NULL;
226
221
/* Mark processes as completed when they exit, and save their exit
227
222
   status. */
228
223
static void handle_sigchld(__attribute__((unused)) int sig){
229
 
  int old_errno = errno;
230
224
  while(true){
231
225
    plugin *proc = plugin_list;
232
226
    int status;
236
230
      break;
237
231
    }
238
232
    if(pid == -1){
239
 
      if(errno == ECHILD){
240
 
        /* No child processes */
241
 
        break;
 
233
      if (errno != ECHILD){
 
234
        perror("waitpid");
242
235
      }
243
 
      perror("waitpid");
 
236
      /* No child processes */
 
237
      break;
244
238
    }
245
239
    
246
240
    /* A child exited, find it in process_list */
252
246
      continue;
253
247
    }
254
248
    proc->status = status;
255
 
    proc->completed = 1;
 
249
    proc->completed = true;
256
250
  }
257
 
  errno = old_errno;
258
251
}
259
252
 
260
253
/* Prints out a password to stdout */
282
275
  }
283
276
  free(plugin_node->environ);
284
277
  free(plugin_node->buffer);
285
 
  
 
278
 
286
279
  /* Removes the plugin from the singly-linked list */
287
280
  if(plugin_node == plugin_list){
288
281
    /* First one - simple */
316
309
  struct stat st;
317
310
  fd_set rfds_all;
318
311
  int ret, maxfd = 0;
319
 
  ssize_t sret;
320
 
  intmax_t tmpmax;
321
312
  uid_t uid = 65534;
322
313
  gid_t gid = 65534;
323
314
  bool debug = false;
380
371
    { .name = NULL }
381
372
  };
382
373
  
383
 
  error_t parse_opt(int key, char *arg, __attribute__((unused))
384
 
                    struct argp_state *state){
385
 
    char *tmp;
386
 
    switch(key){
 
374
  error_t parse_opt (int key, char *arg, __attribute__((unused))
 
375
                     struct argp_state *state) {
 
376
    switch (key) {
387
377
    case 'g':                   /* --global-options */
388
 
      if(arg != NULL){
389
 
        char *plugin_option;
390
 
        while((plugin_option = strsep(&arg, ",")) != NULL){
391
 
          if(plugin_option[0] == '\0'){
 
378
      if (arg != NULL){
 
379
        char *p;
 
380
        while((p = strsep(&arg, ",")) != NULL){
 
381
          if(p[0] == '\0'){
392
382
            continue;
393
383
          }
394
 
          if(not add_argument(getplugin(NULL), plugin_option)){
 
384
          if(not add_argument(getplugin(NULL), p)){
395
385
            perror("add_argument");
396
386
            return ARGP_ERR_UNKNOWN;
397
387
          }
407
397
      }
408
398
      break;
409
399
    case 'o':                   /* --options-for */
410
 
      if(arg != NULL){
411
 
        char *plugin_name = strsep(&arg, ":");
412
 
        if(plugin_name[0] == '\0'){
413
 
          break;
414
 
        }
415
 
        char *plugin_option;
416
 
        while((plugin_option = strsep(&arg, ",")) != NULL){
417
 
          if(not add_argument(getplugin(plugin_name), plugin_option)){
 
400
      if (arg != NULL){
 
401
        char *p_name = strsep(&arg, ":");
 
402
        if(p_name[0] == '\0' or arg == NULL){
 
403
          break;
 
404
        }
 
405
        char *opt = strsep(&arg, ":");
 
406
        if(opt[0] == '\0' or opt == NULL){
 
407
          break;
 
408
        }
 
409
        char *p;
 
410
        while((p = strsep(&opt, ",")) != NULL){
 
411
          if(p[0] == '\0'){
 
412
            continue;
 
413
          }
 
414
          if(not add_argument(getplugin(p_name), p)){
418
415
            perror("add_argument");
419
416
            return ARGP_ERR_UNKNOWN;
420
417
          }
437
434
      }
438
435
      break;
439
436
    case 'd':                   /* --disable */
440
 
      if(arg != NULL){
 
437
      if (arg != NULL){
441
438
        plugin *p = getplugin(arg);
442
439
        if(p == NULL){
443
440
          return ARGP_ERR_UNKNOWN;
446
443
      }
447
444
      break;
448
445
    case 'e':                   /* --enable */
449
 
      if(arg != NULL){
 
446
      if (arg != NULL){
450
447
        plugin *p = getplugin(arg);
451
448
        if(p == NULL){
452
449
          return ARGP_ERR_UNKNOWN;
459
456
      plugindir = strdup(arg);
460
457
      if(plugindir == NULL){
461
458
        perror("strdup");
462
 
      }
 
459
      }      
463
460
      break;
464
461
    case 129:                   /* --config-file */
465
462
      /* This is already done by parse_opt_config_file() */
466
463
      break;
467
464
    case 130:                   /* --userid */
468
 
      errno = 0;
469
 
      tmpmax = strtoimax(arg, &tmp, 10);
470
 
      if(errno != 0 or tmp == arg or *tmp != '\0'
471
 
         or tmpmax != (uid_t)tmpmax){
472
 
        fprintf(stderr, "Bad user ID number: \"%s\", using %"
473
 
                PRIdMAX "\n", arg, (intmax_t)uid);
474
 
      } else {
475
 
        uid = (uid_t)tmpmax;
476
 
      }
 
465
      uid = (uid_t)strtol(arg, NULL, 10);
477
466
      break;
478
467
    case 131:                   /* --groupid */
479
 
      errno = 0;
480
 
      tmpmax = strtoimax(arg, &tmp, 10);
481
 
      if(errno != 0 or tmp == arg or *tmp != '\0'
482
 
         or tmpmax != (gid_t)tmpmax){
483
 
        fprintf(stderr, "Bad group ID number: \"%s\", using %"
484
 
                PRIdMAX "\n", arg, (intmax_t)gid);
485
 
      } else {
486
 
        gid = (gid_t)tmpmax;
487
 
      }
 
468
      gid = (gid_t)strtol(arg, NULL, 10);
488
469
      break;
489
470
    case 132:                   /* --debug */
490
471
      debug = true;
491
472
      break;
492
 
/*
493
 
 * When adding more options before this line, remember to also add a
494
 
 * "case" to the "parse_opt_config_file" function below.
495
 
 */
496
473
    case ARGP_KEY_ARG:
497
474
      /* Cryptsetup always passes an argument, which is an empty
498
475
         string if "none" was specified in /etc/crypttab.  So if
511
488
  
512
489
  /* This option parser is the same as parse_opt() above, except it
513
490
     ignores everything but the --config-file option. */
514
 
  error_t parse_opt_config_file(int key, char *arg,
515
 
                                __attribute__((unused))
516
 
                                struct argp_state *state){
517
 
    switch(key){
 
491
  error_t parse_opt_config_file (int key, char *arg,
 
492
                                 __attribute__((unused))
 
493
                                 struct argp_state *state) {
 
494
    switch (key) {
518
495
    case 'g':                   /* --global-options */
519
496
    case 'G':                   /* --global-env */
520
497
    case 'o':                   /* --options-for */
529
506
      if(argfile == NULL){
530
507
        perror("strdup");
531
508
      }
532
 
      break;
 
509
      break;      
533
510
    case 130:                   /* --userid */
534
511
    case 131:                   /* --groupid */
535
512
    case 132:                   /* --debug */
547
524
                       .args_doc = "",
548
525
                       .doc = "Mandos plugin runner -- Run plugins" };
549
526
  
550
 
  /* Parse using parse_opt_config_file() in order to get the custom
 
527
  /* Parse using the parse_opt_config_file in order to get the custom
551
528
     config file location, if any. */
552
 
  ret = argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, NULL);
553
 
  if(ret == ARGP_ERR_UNKNOWN){
 
529
  ret = argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, NULL);
 
530
  if (ret == ARGP_ERR_UNKNOWN){
554
531
    fprintf(stderr, "Unknown error while parsing arguments\n");
555
532
    exitstatus = EXIT_FAILURE;
556
533
    goto fallback;
560
537
  argp.parser = parse_opt;
561
538
  
562
539
  /* Open the configfile if available */
563
 
  if(argfile == NULL){
 
540
  if (argfile == NULL){
564
541
    conffp = fopen(AFILE, "r");
565
542
  } else {
566
543
    conffp = fopen(argfile, "r");
567
 
  }
 
544
  }  
568
545
  if(conffp != NULL){
569
546
    char *org_line = NULL;
570
547
    char *p, *arg, *new_arg, *line;
571
548
    size_t size = 0;
 
549
    ssize_t sret;
572
550
    const char whitespace_delims[] = " \r\t\f\v\n";
573
551
    const char comment_delim[] = "#";
574
 
    
 
552
 
575
553
    custom_argc = 1;
576
554
    custom_argv = malloc(sizeof(char*) * 2);
577
555
    if(custom_argv == NULL){
581
559
    }
582
560
    custom_argv[0] = argv[0];
583
561
    custom_argv[1] = NULL;
584
 
    
 
562
 
585
563
    /* for each line in the config file, strip whitespace and ignore
586
564
       commented text */
587
565
    while(true){
589
567
      if(sret == -1){
590
568
        break;
591
569
      }
592
 
      
 
570
 
593
571
      line = org_line;
594
572
      arg = strsep(&line, comment_delim);
595
573
      while((p = strsep(&arg, whitespace_delims)) != NULL){
614
592
          goto fallback;
615
593
        }
616
594
        custom_argv[custom_argc-1] = new_arg;
617
 
        custom_argv[custom_argc] = NULL;
 
595
        custom_argv[custom_argc] = NULL;        
618
596
      }
619
597
    }
620
598
    free(org_line);
621
599
  } else {
622
600
    /* Check for harmful errors and go to fallback. Other errors might
623
601
       not affect opening plugins */
624
 
    if(errno == EMFILE or errno == ENFILE or errno == ENOMEM){
 
602
    if (errno == EMFILE or errno == ENFILE or errno == ENOMEM){
625
603
      perror("fopen");
626
604
      exitstatus = EXIT_FAILURE;
627
605
      goto fallback;
630
608
  /* If there was any arguments from configuration file,
631
609
     pass them to parser as command arguments */
632
610
  if(custom_argv != NULL){
633
 
    ret = argp_parse(&argp, custom_argc, custom_argv, ARGP_IN_ORDER,
634
 
                     0, NULL);
635
 
    if(ret == ARGP_ERR_UNKNOWN){
 
611
    ret = argp_parse (&argp, custom_argc, custom_argv, ARGP_IN_ORDER,
 
612
                      0, NULL);
 
613
    if (ret == ARGP_ERR_UNKNOWN){
636
614
      fprintf(stderr, "Unknown error while parsing arguments\n");
637
615
      exitstatus = EXIT_FAILURE;
638
616
      goto fallback;
641
619
  
642
620
  /* Parse actual command line arguments, to let them override the
643
621
     config file */
644
 
  ret = argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, NULL);
645
 
  if(ret == ARGP_ERR_UNKNOWN){
 
622
  ret = argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, NULL);
 
623
  if (ret == ARGP_ERR_UNKNOWN){
646
624
    fprintf(stderr, "Unknown error while parsing arguments\n");
647
625
    exitstatus = EXIT_FAILURE;
648
626
    goto fallback;
655
633
      for(char **a = p->argv; *a != NULL; a++){
656
634
        fprintf(stderr, "\tArg: %s\n", *a);
657
635
      }
658
 
      fprintf(stderr, "...and %d environment variables\n", p->envc);
 
636
      fprintf(stderr, "...and %u environment variables\n", p->envc);
659
637
      for(char **a = p->environ; *a != NULL; a++){
660
638
        fprintf(stderr, "\t%s\n", *a);
661
639
      }
663
641
  }
664
642
  
665
643
  /* Strip permissions down to nobody */
 
644
  ret = setuid(uid);
 
645
  if (ret == -1){
 
646
    perror("setuid");
 
647
  }  
666
648
  setgid(gid);
667
 
  if(ret == -1){
 
649
  if (ret == -1){
668
650
    perror("setgid");
669
651
  }
670
 
  ret = setuid(uid);
671
 
  if(ret == -1){
672
 
    perror("setuid");
673
 
  }
674
652
  
675
 
  if(plugindir == NULL){
 
653
  if (plugindir == NULL){
676
654
    dir = opendir(PDIR);
677
655
  } else {
678
656
    dir = opendir(plugindir);
705
683
    
706
684
    /* All directory entries have been processed */
707
685
    if(dirst == NULL){
708
 
      if(errno == EBADF){
 
686
      if (errno == EBADF){
709
687
        perror("readdir");
710
688
        exitstatus = EXIT_FAILURE;
711
689
        goto fallback;
758
736
        continue;
759
737
      }
760
738
    }
761
 
    
 
739
 
762
740
    char *filename;
763
741
    if(plugindir == NULL){
764
742
      ret = asprintf(&filename, PDIR "/%s", dirst->d_name);
771
749
    }
772
750
    
773
751
    ret = stat(filename, &st);
774
 
    if(ret == -1){
 
752
    if (ret == -1){
775
753
      perror("stat");
776
754
      free(filename);
777
755
      continue;
778
756
    }
779
 
    
 
757
 
780
758
    /* Ignore non-executable files */
781
 
    if(not S_ISREG(st.st_mode) or (access(filename, X_OK) != 0)){
 
759
    if (not S_ISREG(st.st_mode) or (access(filename, X_OK) != 0)){
782
760
      if(debug){
783
761
        fprintf(stderr, "Ignoring plugin dir entry \"%s\""
784
762
                " with bad type or mode\n", filename);
831
809
    
832
810
    int pipefd[2];
833
811
    ret = pipe(pipefd);
834
 
    if(ret == -1){
 
812
    if (ret == -1){
835
813
      perror("pipe");
836
814
      exitstatus = EXIT_FAILURE;
837
815
      goto fallback;
850
828
      goto fallback;
851
829
    }
852
830
    /* Block SIGCHLD until process is safely in process list */
853
 
    ret = sigprocmask(SIG_BLOCK, &sigchld_action.sa_mask, NULL);
 
831
    ret = sigprocmask (SIG_BLOCK, &sigchld_action.sa_mask, NULL);
854
832
    if(ret < 0){
855
833
      perror("sigprocmask");
856
834
      exitstatus = EXIT_FAILURE;
904
882
    close(pipefd[1]);           /* Close unused write end of pipe */
905
883
    free(filename);
906
884
    plugin *new_plugin = getplugin(dirst->d_name);
907
 
    if(new_plugin == NULL){
 
885
    if (new_plugin == NULL){
908
886
      perror("getplugin");
909
 
      ret = sigprocmask(SIG_UNBLOCK, &sigchld_action.sa_mask, NULL);
 
887
      ret = sigprocmask (SIG_UNBLOCK, &sigchld_action.sa_mask, NULL);
910
888
      if(ret < 0){
911
889
        perror("sigprocmask");
912
890
      }
919
897
    
920
898
    /* Unblock SIGCHLD so signal handler can be run if this process
921
899
       has already completed */
922
 
    ret = sigprocmask(SIG_UNBLOCK, &sigchld_action.sa_mask, NULL);
 
900
    ret = sigprocmask (SIG_UNBLOCK, &sigchld_action.sa_mask, NULL);
923
901
    if(ret < 0){
924
902
      perror("sigprocmask");
925
903
      exitstatus = EXIT_FAILURE;
928
906
    
929
907
    FD_SET(new_plugin->fd, &rfds_all);
930
908
    
931
 
    if(maxfd < new_plugin->fd){
 
909
    if (maxfd < new_plugin->fd){
932
910
      maxfd = new_plugin->fd;
933
911
    }
934
912
  }
935
913
  
936
914
  closedir(dir);
937
915
  dir = NULL;
938
 
  free_plugin(getplugin(NULL));
939
916
  
940
917
  for(plugin *p = plugin_list; p != NULL; p = p->next){
941
918
    if(p->pid != 0){
952
929
  while(plugin_list){
953
930
    fd_set rfds = rfds_all;
954
931
    int select_ret = select(maxfd+1, &rfds, NULL, NULL, NULL);
955
 
    if(select_ret == -1){
 
932
    if (select_ret == -1){
956
933
      perror("select");
957
934
      exitstatus = EXIT_FAILURE;
958
935
      goto fallback;
961
938
       from one of them */
962
939
    for(plugin *proc = plugin_list; proc != NULL;){
963
940
      /* Is this process completely done? */
964
 
      if(proc->completed and proc->eof){
 
941
      if(proc->eof and proc->completed){
965
942
        /* Only accept the plugin output if it exited cleanly */
966
943
        if(not WIFEXITED(proc->status)
967
944
           or WEXITSTATUS(proc->status) != 0){
968
945
          /* Bad exit by plugin */
969
 
          
 
946
 
970
947
          if(debug){
971
948
            if(WIFEXITED(proc->status)){
972
 
              fprintf(stderr, "Plugin %s [%" PRIdMAX "] exited with"
973
 
                      " status %d\n", proc->name,
974
 
                      (intmax_t) (proc->pid),
 
949
              fprintf(stderr, "Plugin %u exited with status %d\n",
 
950
                      (unsigned int) (proc->pid),
975
951
                      WEXITSTATUS(proc->status));
976
 
            } else if(WIFSIGNALED(proc->status)){
977
 
              fprintf(stderr, "Plugin %s [%" PRIdMAX "] killed by"
978
 
                      " signal %d: %s\n", proc->name,
979
 
                      (intmax_t) (proc->pid),
980
 
                      WTERMSIG(proc->status),
981
 
                      strsignal(WTERMSIG(proc->status)));
 
952
            } else if(WIFSIGNALED(proc->status)) {
 
953
              fprintf(stderr, "Plugin %u killed by signal %d\n",
 
954
                      (unsigned int) (proc->pid),
 
955
                      WTERMSIG(proc->status));
982
956
            } else if(WCOREDUMP(proc->status)){
983
 
              fprintf(stderr, "Plugin %s [%" PRIdMAX "] dumped"
984
 
                      " core\n", proc->name, (intmax_t) (proc->pid));
 
957
              fprintf(stderr, "Plugin %d dumped core\n",
 
958
                      (unsigned int) (proc->pid));
985
959
            }
986
960
          }
987
961
          
988
962
          /* Remove the plugin */
989
963
          FD_CLR(proc->fd, &rfds_all);
990
 
          
 
964
 
991
965
          /* Block signal while modifying process_list */
992
966
          ret = sigprocmask(SIG_BLOCK, &sigchld_action.sa_mask, NULL);
993
967
          if(ret < 0){
1001
975
          proc = next_plugin;
1002
976
          
1003
977
          /* We are done modifying process list, so unblock signal */
1004
 
          ret = sigprocmask(SIG_UNBLOCK, &sigchld_action.sa_mask,
1005
 
                            NULL);
 
978
          ret = sigprocmask (SIG_UNBLOCK, &sigchld_action.sa_mask,
 
979
                             NULL);
1006
980
          if(ret < 0){
1007
981
            perror("sigprocmask");
1008
982
            exitstatus = EXIT_FAILURE;
1037
1011
      if(proc->buffer_length + BUFFER_SIZE > proc->buffer_size){
1038
1012
        proc->buffer = realloc(proc->buffer, proc->buffer_size
1039
1013
                               + (size_t) BUFFER_SIZE);
1040
 
        if(proc->buffer == NULL){
 
1014
        if (proc->buffer == NULL){
1041
1015
          perror("malloc");
1042
1016
          exitstatus = EXIT_FAILURE;
1043
1017
          goto fallback;
1045
1019
        proc->buffer_size += BUFFER_SIZE;
1046
1020
      }
1047
1021
      /* Read from the process */
1048
 
      sret = read(proc->fd, proc->buffer + proc->buffer_length,
1049
 
                  BUFFER_SIZE);
1050
 
      if(sret < 0){
 
1022
      ret = read(proc->fd, proc->buffer + proc->buffer_length,
 
1023
                 BUFFER_SIZE);
 
1024
      if(ret < 0){
1051
1025
        /* Read error from this process; ignore the error */
1052
1026
        proc = proc->next;
1053
1027
        continue;
1054
1028
      }
1055
 
      if(sret == 0){
 
1029
      if(ret == 0){
1056
1030
        /* got EOF */
1057
1031
        proc->eof = true;
1058
1032
      } else {
1059
 
        proc->buffer_length += (size_t) sret;
 
1033
        proc->buffer_length += (size_t) ret;
1060
1034
      }
1061
1035
    }
1062
1036
  }
1063
 
  
1064
 
  
 
1037
 
 
1038
 
1065
1039
 fallback:
1066
1040
  
1067
1041
  if(plugin_list == NULL or exitstatus != EXIT_SUCCESS){