]>
Commit | Line | Data |
---|---|---|
cee18a41 AM |
1 | |
2 | #include <errno.h> | |
3 | #include <fcntl.h> | |
4 | #include <stdlib.h> | |
5 | #include <string.h> | |
6 | #include <unistd.h> | |
7 | ||
458f14b7 | 8 | #include <sys/signal.h> |
cee18a41 | 9 | #include <sys/poll.h> |
458f14b7 | 10 | #include <sys/stat.h> |
cee18a41 AM |
11 | #include <sys/wait.h> |
12 | ||
13 | #include <popt.h> | |
14 | ||
458f14b7 AM |
15 | #include <regex.h> |
16 | ||
cee18a41 AM |
17 | #include "initlog.h" |
18 | #include "process.h" | |
19 | ||
458f14b7 AM |
20 | extern regex_t **regList; |
21 | ||
cee18a41 AM |
22 | int forkCommand(char **args, int *outfd, int *errfd, int *cmdfd, int quiet) { |
23 | /* Fork command 'cmd', returning pid, and optionally pointer | |
24 | * to open file descriptor fd */ | |
de1fc6ce | 25 | int fdout, fderr, fdcmd, pid; |
cee18a41 | 26 | int outpipe[2], errpipe[2], fdpipe[2]; |
458f14b7 | 27 | int ourpid; |
cee18a41 AM |
28 | |
29 | if ( (pipe(outpipe)==-1) || (pipe(errpipe)==-1) || (pipe(fdpipe)==-1) ) { | |
30 | perror("pipe"); | |
31 | return -1; | |
32 | } | |
33 | ||
cee18a41 AM |
34 | if (outfd) { |
35 | fdout = outpipe[1]; | |
36 | *outfd = outpipe[0]; | |
37 | } else { | |
38 | if (!quiet) | |
39 | fdout=dup(1); | |
40 | } | |
41 | if (errfd) { | |
42 | fderr = errpipe[1]; | |
43 | *errfd = errpipe[0]; | |
44 | } else { | |
45 | if (!quiet) | |
46 | fderr=dup(2); | |
47 | } | |
de1fc6ce JR |
48 | |
49 | if (cmdfd) { | |
50 | *cmdfd = fdpipe[0]; | |
51 | fdcmd = fdpipe[1]; | |
52 | } else { | |
53 | fdcmd = open("/dev/null",O_WRONLY); | |
54 | } | |
458f14b7 | 55 | ourpid = getpid(); |
cee18a41 AM |
56 | if ((pid = fork())==-1) { |
57 | perror("fork"); | |
58 | return -1; | |
59 | } | |
458f14b7 AM |
60 | /* We exec the command normally as the child. However, if we're getting passed |
61 | * back arguments via an fd, we'll exec it as the parent. Therefore, if Bill | |
62 | * fucks up and we segfault or something, we don't kill rc.sysinit. */ | |
63 | if ( (cmdfd&&!pid) || (pid &&!cmdfd)) { | |
cee18a41 | 64 | /* parent */ |
cee18a41 AM |
65 | close(fdout); |
66 | close(fderr); | |
67 | close(fdcmd); | |
458f14b7 AM |
68 | if (!pid) |
69 | return ourpid; | |
70 | else | |
71 | return pid; | |
cee18a41 AM |
72 | } else { |
73 | /* kid */ | |
de1fc6ce JR |
74 | int sc_open_max; |
75 | ||
cee18a41 AM |
76 | if (outfd) { |
77 | if ( (dup2(fdout,1)==-1) ) { | |
78 | perror("dup2"); | |
79 | exit(-1); | |
80 | } | |
81 | } else if (quiet) | |
82 | if ((dup2(open("/dev/null",O_WRONLY),1))==-1) { | |
83 | perror("dup2"); | |
84 | exit(-1); | |
85 | } | |
86 | ||
87 | if (errfd) { | |
88 | if ((dup2(fderr,2)==-1)) { | |
89 | perror("dup2"); | |
90 | exit(-1); | |
91 | } | |
92 | } else if (quiet) | |
93 | if ((dup2(open("/dev/null",O_WRONLY),2))==-1) { | |
94 | perror("dup2"); | |
95 | exit(-1); | |
96 | } | |
97 | ||
98 | ||
99 | if ((dup2(fdcmd,CMD_FD)==-1)) { | |
100 | perror("dup2"); | |
101 | exit(-1); | |
102 | } | |
103 | close(fdout); | |
104 | close(fderr); | |
105 | close(fdcmd); | |
106 | if (outfd) | |
107 | close(*outfd); | |
108 | if (errfd) | |
109 | close(*errfd); | |
110 | if (cmdfd) | |
111 | close(*cmdfd); | |
de1fc6ce JR |
112 | |
113 | /* close up extra fds, and hope this doesn't break anything */ | |
114 | sc_open_max = sysconf(_SC_OPEN_MAX); | |
115 | if(sc_open_max > 1) { | |
116 | int fd; | |
117 | for(fd = 3; fd < sc_open_max; fd++) { | |
118 | if (!(cmdfd && fd == CMD_FD)) | |
119 | close(fd); | |
120 | } | |
121 | } | |
122 | ||
cee18a41 AM |
123 | execvp(args[0],args); |
124 | perror("execvp"); | |
125 | exit(-1); | |
126 | } | |
127 | } | |
128 | ||
129 | int monitor(char *cmdname, int pid, int numfds, int *fds, int reexec, int quiet, int debug) { | |
130 | struct pollfd *pfds; | |
458f14b7 AM |
131 | char *buf=malloc(8192*sizeof(char)); |
132 | char *outbuf=NULL; | |
cee18a41 AM |
133 | char *tmpstr=NULL; |
134 | int x,y,rc=-1; | |
135 | int done=0; | |
136 | int output=0; | |
458f14b7 AM |
137 | char **cmdargs=NULL; |
138 | char **tmpargs=NULL; | |
139 | int cmdargc; | |
140 | char *procpath; | |
141 | ||
142 | if (reexec) { | |
143 | procpath=malloc(20*sizeof(char)); | |
144 | snprintf(procpath,20,"/proc/%d",pid); | |
145 | } | |
cee18a41 | 146 | |
cee18a41 AM |
147 | pfds = malloc(numfds*sizeof(struct pollfd)); |
148 | for (x=0;x<numfds;x++) { | |
149 | pfds[x].fd = fds[x]; | |
150 | pfds[x].events = POLLIN | POLLPRI; | |
151 | } | |
152 | ||
153 | while (!done) { | |
458f14b7 | 154 | usleep(500); |
cee18a41 AM |
155 | if (((x=poll(pfds,numfds,500))==-1)&&errno!=EINTR) { |
156 | perror("poll"); | |
157 | return -1; | |
158 | } | |
458f14b7 AM |
159 | if (!reexec) { |
160 | if (waitpid(pid,&rc,WNOHANG)) | |
161 | done=1; | |
162 | } else { | |
163 | struct stat sbuf; | |
164 | /* if /proc/pid ain't there and /proc is, it's dead... */ | |
165 | if (stat(procpath,&sbuf)&&!stat("/proc/cpuinfo",&sbuf)) | |
166 | done=1; | |
167 | } | |
cee18a41 AM |
168 | y=0; |
169 | while (y<numfds) { | |
170 | if ( x && ((pfds[y].revents & (POLLIN | POLLPRI)) )) { | |
171 | int bytesread = 0; | |
172 | ||
173 | do { | |
458f14b7 AM |
174 | buf=calloc(8192,sizeof(char)); |
175 | bytesread = read(pfds[y].fd,buf,8192); | |
cee18a41 AM |
176 | if (bytesread==-1) { |
177 | perror("read"); | |
178 | return -1; | |
179 | } | |
180 | if (bytesread) { | |
181 | if (!quiet && !reexec) | |
182 | write(1,buf,bytesread); | |
183 | if (quiet) { | |
458f14b7 AM |
184 | outbuf=realloc(outbuf,(outbuf ? strlen(outbuf)+bytesread+1 : bytesread+1)); |
185 | if (!output) outbuf[0]='\0'; | |
186 | strcat(outbuf,buf); | |
187 | output = 1; | |
cee18a41 AM |
188 | } |
189 | while ((tmpstr=getLine(&buf))) { | |
458f14b7 AM |
190 | int ignore=0; |
191 | ||
192 | if (regList) { | |
193 | int count=0; | |
194 | ||
195 | while (regList[count]) { | |
196 | if (!regexec(regList[count],tmpstr,0,NULL,0)) { | |
197 | ignore=1; | |
198 | break; | |
199 | } | |
200 | count++; | |
201 | } | |
202 | } | |
203 | if (!ignore) { | |
204 | if (!reexec) { | |
205 | if (getenv("IN_INITLOG")) { | |
206 | char *buffer=calloc(8192,sizeof(char)); | |
207 | DDEBUG("sending =%s= to initlog parent\n",tmpstr); | |
208 | snprintf(buffer,8192,"-n %s -s \"%s\"\n", | |
209 | cmdname,tmpstr); | |
210 | /* don't blow up if parent isn't there */ | |
211 | signal(SIGPIPE,SIG_IGN); | |
212 | write(CMD_FD,buffer,strlen(buffer)); | |
213 | signal(SIGPIPE,SIG_DFL); | |
214 | free(buffer); | |
215 | } else { | |
216 | logString(cmdname,tmpstr); | |
217 | } | |
218 | } else { | |
219 | int z; | |
cee18a41 | 220 | |
458f14b7 AM |
221 | cmdargs=NULL; |
222 | tmpargs=NULL; | |
223 | cmdargc=0; | |
224 | ||
225 | poptParseArgvString(tmpstr,&cmdargc,&tmpargs); | |
226 | cmdargs=malloc( (cmdargc+2) * sizeof(char *) ); | |
227 | cmdargs[0]=strdup("initlog"); | |
228 | for (z=0;z<(cmdargc);z++) { | |
229 | cmdargs[z+1]=tmpargs[z]; | |
230 | } | |
231 | cmdargs[cmdargc+1]=NULL; | |
232 | processArgs(cmdargc+1,cmdargs,1); | |
233 | } | |
234 | } | |
cee18a41 AM |
235 | } |
236 | } | |
458f14b7 | 237 | } while ( bytesread==8192 ); |
cee18a41 AM |
238 | } |
239 | y++; | |
240 | } | |
241 | } | |
242 | if ((!WIFEXITED(rc)) || (rc=WEXITSTATUS(rc))) { | |
243 | /* If there was an error and we're quiet, be loud */ | |
cee18a41 AM |
244 | |
245 | if (quiet && output) { | |
458f14b7 | 246 | write(1,outbuf,strlen(outbuf)); |
cee18a41 AM |
247 | } |
248 | return (rc); | |
249 | } | |
250 | return 0; | |
251 | } | |
252 | ||
253 | int runCommand(char *cmd, int reexec, int quiet, int debug) { | |
254 | int fds[2]; | |
255 | int pid,x; | |
256 | char **args, **tmpargs; | |
257 | char *cmdname; | |
258 | ||
259 | poptParseArgvString(cmd,&x,&tmpargs); | |
260 | args = malloc((x+1)*sizeof(char *)); | |
261 | for ( pid = 0; pid < x ; pid++) { | |
262 | args[pid] = strdup(tmpargs[pid]); | |
263 | } | |
264 | args[pid] = NULL; | |
265 | if (strcmp(args[0],"sh") && strcmp(args[0],"/bin/sh")) | |
de1fc6ce | 266 | cmdname = basename(args[0]); |
cee18a41 | 267 | else |
de1fc6ce | 268 | cmdname = basename(args[1]); |
458f14b7 AM |
269 | if ((cmdname[0] =='K' || cmdname[0] == 'S') && ( '0' <= cmdname[1] <= '9' ) |
270 | && ( '0' <= cmdname[2] <= '9' ) ) | |
cee18a41 AM |
271 | cmdname+=3; |
272 | if (!reexec) { | |
273 | pid=forkCommand(args,&fds[0],&fds[1],NULL,quiet); | |
274 | x=monitor(cmdname,pid,2,fds,reexec,quiet,debug); | |
275 | } else { | |
276 | setenv("IN_INITLOG","yes",1); | |
277 | pid=forkCommand(args,NULL,NULL,&fds[0],quiet); | |
278 | unsetenv("IN_INITLOG"); | |
279 | x=monitor(cmdname,pid,1,&fds[0],reexec,quiet,debug); | |
280 | } | |
281 | return x; | |
282 | } |