]> TLD Linux GIT Repositories - rc-scripts.git/blob - src/process.c
- disable lock checks (happens on LUKS2 and fails during system boot)
[rc-scripts.git] / src / process.c
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  */
12
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18
19 #include <sys/signal.h>
20 #include <sys/poll.h>
21 #include <sys/stat.h>
22 #include <sys/wait.h>
23
24 #include <popt.h>
25
26 #include <regex.h>
27
28 #include "initlog.h"
29 #include "process.h"
30
31 extern regex_t **regList;
32
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 */
36     int fdout=-1, fderr=-1, fdcmd=-1, pid;
37     int outpipe[2], errpipe[2], fdpipe[2];
38     int ourpid;
39     
40     if ( (pipe(outpipe)==-1) || (pipe(errpipe)==-1) || (pipe(fdpipe)==-1) ) {
41         perror("pipe");
42         return -1;
43     }
44     
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     }
59     
60     if (cmdfd) {
61         *cmdfd = fdpipe[0];
62         fdcmd = fdpipe[1];
63     } else {
64         fdcmd = open("/dev/null",O_WRONLY);
65     }
66     if (fdout==-1 || fderr==-1 || fdcmd==-1)
67         return -1;
68     ourpid = getpid();
69     if ((pid = fork())==-1) {
70         perror("fork");
71         return -1;
72     }
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)) {
77         /* parent */
78         close(fdout);
79         close(fderr);
80         close(fdcmd);
81         if (!pid)
82           return ourpid;
83         else
84           return pid;
85     } else {
86         /* kid */
87        int sc_open_max;
88
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);
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
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;
144     char *outbuf=NULL;
145     char *tmpstr=NULL;
146     int x,y,rc=-1;
147     int done=0;
148     int output=0;
149     char **cmdargs=NULL;
150     char **tmpargs=NULL;
151     int cmdargc;
152     char *procpath = NULL;
153     
154     if (reexec) {
155         procpath=malloc(20*sizeof(char));
156         snprintf(procpath,20,"/proc/%d",pid);
157     }
158     
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) {
166        usleep(500);
167        if (((x=poll(pfds,numfds,500))==-1)&&errno!=EINTR) {
168           perror("poll");
169           free(pfds);
170           if (procpath)
171              free(procpath);
172           return -1;
173        }
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        }
183        if (x<0)
184           continue;
185        y=0;
186        while (y<numfds) {
187           if ( x && ((pfds[y].revents & (POLLIN | POLLPRI)) )) {
188              int bytesread = 0;
189              
190              do {
191                 char *b, *buf=calloc(8193,sizeof(char));
192                 b = buf;
193                 bytesread = read(pfds[y].fd,buf,8192);
194                 if (bytesread==-1) {
195                    perror("read");
196                    free(pfds);
197                    if (procpath)
198                       free(procpath);
199                    free(buf);
200                    return -1;
201                 }
202                 if (bytesread) {
203                   if (!quiet && !reexec)
204                     write(1,buf,bytesread);
205                   if (quiet) {
206                           outbuf=realloc(outbuf,(outbuf ? strlen(outbuf)+bytesread+1 : bytesread+1));
207                           if (!output) outbuf[0]='\0';
208                           strcat(outbuf,buf);
209                           output = 1;
210                   }
211                   while ((tmpstr=getLine(&buf))) {
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; 
242                         
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);
255                               free(cmdargs[0]);
256                               free(tmpargs);
257                               free(cmdargs);
258                           }
259                       }
260                       if (tmpstr) free(tmpstr);
261                   }
262                 }
263                 free(b);
264              } while ( bytesread==8192 );
265           }
266           y++;
267        }
268     }
269     if ((!WIFEXITED(rc)) || (rc=WEXITSTATUS(rc))) {
270       /* If there was an error and we're quiet, be loud */
271       
272       if (quiet && output) {
273             write(1,outbuf,strlen(outbuf));
274       }
275       free(pfds);
276       if (procpath)
277          free(procpath);
278       if(outbuf)
279          free(outbuf);
280       return (rc);
281    }
282    free(pfds);
283    if (procpath)
284       free(procpath);
285    if(outbuf)
286       free(outbuf);
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")) 
303       cmdname = basename(args[0]);
304     else
305       cmdname = basename(args[1]);
306     if ((cmdname[0] =='K' || cmdname[0] == 'S') && 
307         ( cmdname[1] >= '0' && cmdname[1] <= '9' ) &&
308         ( cmdname[2] >= '0' && cmdname[2] <= '9' ) )
309       cmdname+=3;
310     if (!reexec) {
311        pid=forkCommand(args,&fds[0],&fds[1],NULL,quiet);
312        if (pid == -1)
313           return -1;
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);
318        if (pid == -1)
319           return -1;
320        unsetenv("IN_INITLOG");
321        x=monitor(cmdname,pid,1,&fds[0],reexec,quiet,debug);
322     }
323     return x;
324 }