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