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