Index: process.c
===================================================================
--- process.c (nonexistent)
+++ process.c (revision 5)
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 1999-2003 Red Hat, Inc. All rights reserved.
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/signal.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <popt.h>
+
+#include <regex.h>
+
+#include "initlog.h"
+#include "process.h"
+
+extern regex_t **regList;
+
+int forkCommand(char **args, int *outfd, int *errfd, int *cmdfd, int quiet) {
+ /* Fork command 'cmd', returning pid, and optionally pointer
+ * to open file descriptor fd */
+ int fdout=-1, fderr=-1, fdcmd=-1, pid;
+ int outpipe[2], errpipe[2], fdpipe[2];
+ int ourpid;
+
+ if ( (pipe(outpipe)==-1) || (pipe(errpipe)==-1) || (pipe(fdpipe)==-1) ) {
+ perror("pipe");
+ return -1;
+ }
+
+ if (outfd) {
+ fdout = outpipe[1];
+ *outfd = outpipe[0];
+ } else {
+ if (!quiet)
+ fdout=dup(1);
+ }
+ if (errfd) {
+ fderr = errpipe[1];
+ *errfd = errpipe[0];
+ } else {
+ if (!quiet)
+ fderr=dup(2);
+ }
+
+ if (cmdfd) {
+ *cmdfd = fdpipe[0];
+ fdcmd = fdpipe[1];
+ } else {
+ fdcmd = open("/dev/null",O_WRONLY);
+ }
+ if (fdout==-1 || fderr==-1 || fdcmd==-1)
+ return -1;
+ ourpid = getpid();
+ if ((pid = fork())==-1) {
+ perror("fork");
+ return -1;
+ }
+ /* We exec the command normally as the child. However, if we're getting passed
+ * back arguments via an fd, we'll exec it as the parent. Therefore, if Bill
+ * fucks up and we segfault or something, we don't kill rc.sysinit. */
+ if ( (cmdfd&&!pid) || (pid &&!cmdfd)) {
+ /* parent */
+ close(fdout);
+ close(fderr);
+ close(fdcmd);
+ if (!pid)
+ return ourpid;
+ else
+ return pid;
+ } else {
+ /* kid */
+ int sc_open_max;
+
+ if (outfd) {
+ if ( (dup2(fdout,1)==-1) ) {
+ perror("dup2");
+ exit(-1);
+ }
+ } else if (quiet)
+ if ((dup2(open("/dev/null",O_WRONLY),1))==-1) {
+ perror("dup2");
+ exit(-1);
+ }
+
+ if (errfd) {
+ if ((dup2(fderr,2)==-1)) {
+ perror("dup2");
+ exit(-1);
+ }
+ } else if (quiet)
+ if ((dup2(open("/dev/null",O_WRONLY),2))==-1) {
+ perror("dup2");
+ exit(-1);
+ }
+
+
+ if ((dup2(fdcmd,CMD_FD)==-1)) {
+ perror("dup2");
+ exit(-1);
+ }
+ close(fdout);
+ close(fderr);
+ close(fdcmd);
+ if (outfd)
+ close(*outfd);
+ if (errfd)
+ close(*errfd);
+ if (cmdfd)
+ close(*cmdfd);
+
+ /* close up extra fds, and hope this doesn't break anything */
+ sc_open_max = sysconf(_SC_OPEN_MAX);
+ if(sc_open_max > 1) {
+ int fd;
+ for(fd = 3; fd < sc_open_max; fd++) {
+ if (!(cmdfd && fd == CMD_FD))
+ close(fd);
+ }
+ }
+
+ execvp(args[0],args);
+ perror("execvp");
+ exit(-1);
+ }
+}
+
+int monitor(char *cmdname, int pid, int numfds, int *fds, int reexec, int quiet, int debug) {
+ struct pollfd *pfds;
+ char *outbuf=NULL;
+ char *tmpstr=NULL;
+ int x,y,rc=-1;
+ int done=0;
+ int output=0;
+ char **cmdargs=NULL;
+ char **tmpargs=NULL;
+ int cmdargc;
+ char *procpath = NULL;
+
+ if (reexec) {
+ procpath=malloc(20*sizeof(char));
+ snprintf(procpath,20,"/proc/%d",pid);
+ }
+
+ pfds = malloc(numfds*sizeof(struct pollfd));
+ for (x=0;x<numfds;x++) {
+ pfds[x].fd = fds[x];
+ pfds[x].events = POLLIN | POLLPRI;
+ }
+
+ while (!done) {
+ usleep(500);
+ if (((x=poll(pfds,numfds,500))==-1)&&errno!=EINTR) {
+ perror("poll");
+ free(pfds);
+ if (procpath)
+ free(procpath);
+ return -1;
+ }
+ if (!reexec) {
+ if (waitpid(pid,&rc,WNOHANG))
+ done=1;
+ } else {
+ struct stat sbuf;
+ /* if /proc/pid ain't there and /proc is, it's dead... */
+ if (stat(procpath,&sbuf)&&!stat("/proc/cpuinfo",&sbuf))
+ done=1;
+ }
+ if (x<0)
+ continue;
+ y=0;
+ while (y<numfds) {
+ if ( x && ((pfds[y].revents & (POLLIN | POLLPRI)) )) {
+ int bytesread = 0;
+
+ do {
+ char *b, *buf=calloc(8193,sizeof(char));
+ b = buf;
+ bytesread = read(pfds[y].fd,buf,8192);
+ if (bytesread==-1) {
+ perror("read");
+ free(pfds);
+ if (procpath)
+ free(procpath);
+ free(buf);
+ return -1;
+ }
+ if (bytesread) {
+ if (!quiet && !reexec)
+ write(1,buf,bytesread);
+ if (quiet) {
+ outbuf=realloc(outbuf,(outbuf ? strlen(outbuf)+bytesread+1 : bytesread+1));
+ if (!output) outbuf[0]='\0';
+ strcat(outbuf,buf);
+ output = 1;
+ }
+ while ((tmpstr=getLine(&buf))) {
+ int ignore=0;
+
+ if (regList) {
+ int count=0;
+
+ while (regList[count]) {
+ if (!regexec(regList[count],tmpstr,0,NULL,0)) {
+ ignore=1;
+ break;
+ }
+ count++;
+ }
+ }
+ if (!ignore) {
+ if (!reexec) {
+ if (getenv("IN_INITLOG")) {
+ char *buffer=calloc(8192,sizeof(char));
+ DDEBUG("sending =%s= to initlog parent\n",tmpstr);
+ snprintf(buffer,8192,"-n %s -s \"%s\"\n",
+ cmdname,tmpstr);
+ /* don't blow up if parent isn't there */
+ signal(SIGPIPE,SIG_IGN);
+ write(CMD_FD,buffer,strlen(buffer));
+ signal(SIGPIPE,SIG_DFL);
+ free(buffer);
+ } else {
+ logString(cmdname,tmpstr);
+ }
+ } else {
+ int z;
+
+ cmdargs=NULL;
+ tmpargs=NULL;
+ cmdargc=0;
+
+ poptParseArgvString(tmpstr,&cmdargc,(const char ***)&tmpargs);
+ cmdargs=malloc( (cmdargc+2) * sizeof(char *) );
+ cmdargs[0]=strdup("initlog");
+ for (z=0;z<(cmdargc);z++) {
+ cmdargs[z+1]=tmpargs[z];
+ }
+ cmdargs[cmdargc+1]=NULL;
+ processArgs(cmdargc+1,cmdargs,1);
+ free(cmdargs[0]);
+ free(tmpargs);
+ free(cmdargs);
+ }
+ }
+ if (tmpstr) free(tmpstr);
+ }
+ }
+ free(b);
+ } while ( bytesread==8192 );
+ }
+ y++;
+ }
+ }
+ if ((!WIFEXITED(rc)) || (rc=WEXITSTATUS(rc))) {
+ /* If there was an error and we're quiet, be loud */
+
+ if (quiet && output) {
+ write(1,outbuf,strlen(outbuf));
+ }
+ free(pfds);
+ if (procpath)
+ free(procpath);
+ if(outbuf)
+ free(outbuf);
+ return (rc);
+ }
+ free(pfds);
+ if (procpath)
+ free(procpath);
+ if(outbuf)
+ free(outbuf);
+ return 0;
+}
+
+int runCommand(char *cmd, int reexec, int quiet, int debug) {
+ int fds[2];
+ int pid,x;
+ char **args, **tmpargs;
+ char *cmdname;
+
+ poptParseArgvString(cmd,&x,(const char ***)&tmpargs);
+ args = malloc((x+1)*sizeof(char *));
+ for ( pid = 0; pid < x ; pid++) {
+ args[pid] = strdup(tmpargs[pid]);
+ }
+ args[pid] = NULL;
+ if (strcmp(args[0],"sh") && strcmp(args[0],"/bin/sh"))
+ cmdname = basename(args[0]);
+ else
+ cmdname = basename(args[1]);
+ if ((cmdname[0] =='K' || cmdname[0] == 'S') &&
+ ( cmdname[1] >= '0' && cmdname[1] <= '9' ) &&
+ ( cmdname[2] >= '0' && cmdname[2] <= '9' ) )
+ cmdname+=3;
+ if (!reexec) {
+ pid=forkCommand(args,&fds[0],&fds[1],NULL,quiet);
+ if (pid == -1)
+ return -1;
+ x=monitor(cmdname,pid,2,fds,reexec,quiet,debug);
+ } else {
+ setenv("IN_INITLOG","yes",1);
+ pid=forkCommand(args,NULL,NULL,&fds[0],quiet);
+ if (pid == -1)
+ return -1;
+ unsetenv("IN_INITLOG");
+ x=monitor(cmdname,pid,1,&fds[0],reexec,quiet,debug);
+ }
+ return x;
+}