325 lines
7.5 KiB
C
325 lines
7.5 KiB
C
|
/*
|
||
|
* 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,&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,&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;
|
||
|
}
|