/* * Copyright (c) 1999-2003 Red Hat, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * */ #include #include #include #include #include #include #include #include #include #include #include #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= '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; }