/* * $Id: proc.c,v 1.6 2002/08/23 13:41:37 howardjp Exp $ * * Copyright (c) 1990 * Jan Wolter. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Jan Wolter * and his contributors. * 4. Neither the name of Jan Wolter nor the names of his contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JAN WOLTER AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JAN WOLTER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* PARTY PROGRAM -- FILTER MANAGEMENT AND SIMILAR TRICKY STUFF -- Jan Wolter */ #include "party.h" #include "opt.h" int out_fd = 1; /* File descriptor of terminal or external filter */ char ofilter[BFSZ]; /* Command line of current filter */ /* START_FILTER: Start up the external filter named by the filter option. * If some different filter is already running, we kill it first. */ start_filter() { FILE *out_fp; /* If a filter is running, and it is different, kill it */ if (out_fd != 1) { if (!strncmp(ofilter,opt[OPT_FILTER].str, BFSZ)) return(0); else stop_filter(); } if ((out_fp = upopen(opt[OPT_FILTER].str,"w")) == NULL) { err("cannot execute filter: %s\n",ofilter); opt[OPT_FILTER].yes = 0; return; } out_fd = fileno(out_fp); strcpy(ofilter,opt[OPT_FILTER].str); } /* STOP_FILTER: This shuts down any output filter currently running in * a nice manner (by closing it's input stream), and resets output direct * to the terminal. This is the normal method of shutting down a filter. */ stop_filter() { if (out_fd == 1) return; upclose(); out_fd= 1; } /* KILL_FILTER: This shuts down any output filter currently running in * a nasty manner (by killing the process), and resets output direct * to the terminal. This is done when party was terminated by an interrupt * or a hangup. */ kill_filter() { if (out_fd == 1) return; upkill(); out_fd= 1; } /* UPOPEN/UPCLOSE/UPKILL - Run command on a pipe * * This is similar to the Unix popen() and pclose() calls, except * (1) upopen() runs the command with the original user id. * (2) upopen() shuts off interrupts in the child process. * (2) upopen() closes the last upopen() whenever it is called. * (3) upclose() closes the last upopen(), and takes no args. * upkill() just murders the child process and returns. */ FILE *f_lastpop = NULL; /* current upopened stream (NULL means none) */ int p_lastpop; /* process id of last upopened command */ FILE *upopen(cmd,mode) char *cmd; char *mode; { int pip[2]; register int chd_pipe,par_pipe; FILE *fdopen(); #ifdef NODUP2 int t; #endif /*NODUP2*/ if (f_lastpop) upclose(); /* Make a pipe */ if (pipe(pip)) return((FILE *)0); /* Choose ends */ par_pipe= (*mode == 'r') ? pip[0] : pip[1]; chd_pipe= (*mode == 'r') ? pip[1] : pip[0]; switch (p_lastpop= fork()) { case 0: /* Child - run command */ signal(SIGINT,SIG_IGN); signal(SIGQUIT,SIG_IGN); close(par_pipe); if (chd_pipe != (*mode == 'r'?1:0)) { #ifdef NODUP2 close(t = (*mode == 'r'?1:0)); if (fcntl(chd_pipe,F_DUPFD,t) != t) { printf("Panic: can dup pipe\n"); exit(1); } #else dup2(chd_pipe,(*mode == 'r'?1:0)); #endif /*NODUP2*/ close(chd_pipe); } setuid(getuid()); setgid(getgid()); execcmd(cmd); exit(-1); case -1: close(chd_pipe); close(par_pipe); return((FILE *)0); default: close(chd_pipe); return(f_lastpop=fdopen(par_pipe,mode)); } } upclose() { int pid; if (f_lastpop == NULL || fclose(f_lastpop)) return; f_lastpop=NULL; while ((pid=wait((int *)0)) != -1 && pid != p_lastpop ) ; } upkill() { if (f_lastpop != NULL) kill(p_lastpop,SIGTERM); } /* PRINTEXEC: Print the given string, unless the first characters is a ! * in which case we exec it. */ printexec(fp,str) FILE *fp; char *str; { if (*str == '!') usystem(str+1); else if (*str == '/') help(str,1); else fprintf(fp,"%s\n",str); } /* USYSTEM: A modified version of the system() command that resets the uid * and the gid to the user before executing the subcommand. If the command * doesn't appear to include any special characters, it will exec the * command directly instead of starting a shell to parse it. */ usystem(cmd) char *cmd; { register int cpid,wpid; vint (*old_intr)(), (*old_quit)(); if (debug) db("usystem: %s\n",cmd); if ((cpid = fork()) == 0) { dup2(2,1); setuid(getuid()); setgid(getgid()); signal(SIGPIPE,oldsigpipe); execcmd(cmd); exit(-1); } old_intr = signal(SIGINT,SIG_IGN); old_quit = signal(SIGQUIT,SIG_IGN); while ((wpid = wait((int *)0)) != cpid && wpid != -1) ; signal(SIGINT,old_intr); signal(SIGQUIT,old_quit); if (debug) db("usystem done\n"); } execcmd(cmd) char *cmd; { char *cmdv[200]; char *cp; int i,j; /* If there are no fancy characters in it, parse it ourselves */ if (opt[OPT_FASTSHELL].yes && strpbrk(cmd,"<>*?|![]{}~`$&';\\\"") == NULL) { /* Skip leading spaces */ cp= firstout(cmd," \t"); cmdv[i=0] = cp; /* Break up args at the spaces */ while (*(cp= firstin(cp," \t")) != '\0') { *(cp++) = '\0'; cp= firstout(cp," \t"); if (*cp != '\0') cmdv[++i] = cp; } /* Ignore Null command */ if (cmdv[0] == cp) return; cmdv[i+1] = NULL; execvp(cmdv[0],cmdv); fprintf(stderr,"%s: cannot execute %s\n",progname,cmdv[0]); } else { execl(opt[OPT_SHELL].str,leafname(opt[OPT_SHELL].str),"-c", cmd,(char *)NULL); fprintf(stderr,"%s: cannot execute shell %s\n", progname,opt[OPT_SHELL].str); } }