source: projects/initscripts/tags/initscripts-8.91.3/src/process.c @ 1108

Revision 1108, 7.8 KB checked in by daisuke, 14 years ago (diff)

import initscripts-8.90.6 from internal cvs repository

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