]> arthur.barton.de Git - netdata.git/blob - src/popen.c
splitted netdata to multiple source files
[netdata.git] / src / popen.c
1 #include <signal.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <sys/wait.h>
6
7 #include "log.h"
8 #include "popen.h"
9
10 #define PIPE_READ 0
11 #define PIPE_WRITE 1
12
13 FILE *mypopen(const char *command, pid_t *pidptr)
14 {
15         int pipefd[2];
16
17         if(pipe(pipefd) == -1) return NULL;
18
19         int pid = fork();
20         if(pid == -1) {
21                 close(pipefd[PIPE_READ]);
22                 close(pipefd[PIPE_WRITE]);
23                 return NULL;
24         }
25         if(pid != 0) {
26                 // the parent
27                 *pidptr = pid;
28                 close(pipefd[PIPE_WRITE]);
29                 FILE *fp = fdopen(pipefd[PIPE_READ], "r");
30                 return(fp);
31         }
32         // the child
33
34         // close all files
35         int i;
36         for(i = sysconf(_SC_OPEN_MAX); i > 0; i--)
37                 if(i != STDIN_FILENO && i != STDERR_FILENO && i != pipefd[PIPE_WRITE]) close(i);
38
39         // move the pipe to stdout
40         if(pipefd[PIPE_WRITE] != STDOUT_FILENO) {
41                 dup2(pipefd[PIPE_WRITE], STDOUT_FILENO);
42                 close(pipefd[PIPE_WRITE]);
43         }
44
45 #ifdef DETACH_PLUGINS_FROM_NETDATA
46         // this was an attempt to detach the child and use the suspend mode charts.d
47         // unfortunatelly it does not work as expected.
48
49         // fork again to become session leader
50         pid = fork();
51         if(pid == -1) fprintf(stderr, "Cannot fork again on pid %d\n", getpid());
52         if(pid != 0) {
53                 // the parent
54                 exit(0);
55         }
56
57         // set a new process group id for just this child
58         if( setpgid(0, 0) != 0 )
59                 fprintf(stderr, "Cannot set a new process group for pid %d (%s)\n", getpid(), strerror(errno));
60
61         if( getpgid(0) != getpid() )
62                 fprintf(stderr, "Process group set is incorrect. Expected %d, found %d\n", getpid(), getpgid(0));
63
64         if( setsid() != 0 )
65                 fprintf(stderr, "Cannot set session id for pid %d (%s)\n", getpid(), strerror(errno));
66
67         fprintf(stdout, "MYPID %d\n", getpid());
68         fflush(NULL);
69 #endif
70         
71         // ignore all signals
72         for (i = 1 ; i < 65 ;i++) if(i != SIGSEGV) signal(i, SIG_DFL);
73
74         fprintf(stderr, "executing command: '%s' on pid %d.\n", command, getpid());
75         execl("/bin/sh", "sh", "-c", command, NULL);
76         exit(1);
77 }
78
79 void mypclose(FILE *fp)
80 {
81         // this is a very poor implementation of pclose()
82         // the caller should catch SIGCHLD and waitpid() on the exited child
83         // otherwise the child will be a zombie forever
84
85         fclose(fp);
86 }
87
88 void process_childs(int wait)
89 {
90         siginfo_t info;
91         int options = WEXITED;
92         if(!wait) options |= WNOHANG;
93
94         info.si_pid = 0;
95         while(waitid(P_ALL, 0, &info, options) == 0) {
96                 if(!info.si_pid) break;
97                 switch(info.si_code) {
98                         case CLD_EXITED:
99                                 error("pid %d exited with code %d.", info.si_pid, info.si_status);
100                                 break;
101
102                         case CLD_KILLED:
103                                 error("pid %d killed by signal %d.", info.si_pid, info.si_status);
104                                 break;
105
106                         case CLD_DUMPED: 
107                                 error("pid %d core dumped by signal %d.", info.si_pid, info.si_status);
108                                 break;
109
110                         case CLD_STOPPED:
111                                 error("pid %d stopped by signal %d.", info.si_pid, info.si_status);
112                                 break;
113
114                         case CLD_TRAPPED:
115                                 error("pid %d trapped by signal %d.", info.si_pid, info.si_status);
116                                 break;
117
118                         case CLD_CONTINUED:
119                                 error("pid %d continued by signal %d.", info.si_pid, info.si_status);
120                                 break;
121
122                         default:
123                                 error("pid %d gave us a SIGCHLD with code %d and status %d.", info.si_pid, info.si_code, info.si_status);
124                                 break;
125                 }
126
127                 // prevent an infinite loop
128                 info.si_pid = 0;
129         }
130 }