popen.c revision 1590
1153151Sjkim/* 2153151Sjkim * Copyright (c) 1980, 1993 3153151Sjkim * The Regents of the University of California. All rights reserved. 4153151Sjkim * 5153151Sjkim * Redistribution and use in source and binary forms, with or without 6153151Sjkim * modification, are permitted provided that the following conditions 7153151Sjkim * are met: 8153151Sjkim * 1. Redistributions of source code must retain the above copyright 9153151Sjkim * notice, this list of conditions and the following disclaimer. 10153151Sjkim * 2. Redistributions in binary form must reproduce the above copyright 11153151Sjkim * notice, this list of conditions and the following disclaimer in the 12153151Sjkim * documentation and/or other materials provided with the distribution. 13153151Sjkim * 3. All advertising materials mentioning features or use of this software 14153151Sjkim * must display the following acknowledgement: 15153151Sjkim * This product includes software developed by the University of 16153151Sjkim * California, Berkeley and its contributors. 17153151Sjkim * 4. Neither the name of the University nor the names of its contributors 18153151Sjkim * may be used to endorse or promote products derived from this software 19153151Sjkim * without specific prior written permission. 20153151Sjkim * 21153151Sjkim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22153151Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23153151Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24153151Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25153151Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26153151Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27153151Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28153151Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29153151Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30153151Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31153151Sjkim * SUCH DAMAGE. 32153151Sjkim */ 33153151Sjkim 34153151Sjkim#ifndef lint 35153151Sjkimstatic char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93"; 36153151Sjkim#endif /* not lint */ 37153151Sjkim 38153151Sjkim#include "rcv.h" 39153151Sjkim#include <sys/wait.h> 40153151Sjkim#include <fcntl.h> 41153151Sjkim#include "extern.h" 42153151Sjkim 43153151Sjkim#define READ 0 44153151Sjkim#define WRITE 1 45153151Sjkim 46153151Sjkimstruct fp { 47153151Sjkim FILE *fp; 48153151Sjkim int pipe; 49153151Sjkim int pid; 50153151Sjkim struct fp *link; 51153151Sjkim}; 52153151Sjkimstatic struct fp *fp_head; 53153151Sjkim 54153151Sjkimstruct child { 55153151Sjkim int pid; 56153151Sjkim char done; 57153151Sjkim char free; 58153151Sjkim union wait status; 59153151Sjkim struct child *link; 60153151Sjkim}; 61153151Sjkimstatic struct child *child; 62153151Sjkimstatic struct child *findchild __P((int)); 63153151Sjkimstatic void delchild __P((struct child *)); 64153151Sjkim 65153151SjkimFILE * 66153151SjkimFopen(file, mode) 67153151Sjkim char *file, *mode; 68153151Sjkim{ 69153151Sjkim FILE *fp; 70153151Sjkim 71153151Sjkim if ((fp = fopen(file, mode)) != NULL) { 72153151Sjkim register_file(fp, 0, 0); 73153151Sjkim (void) fcntl(fileno(fp), F_SETFD, 1); 74153151Sjkim } 75153151Sjkim return fp; 76153151Sjkim} 77153151Sjkim 78153151SjkimFILE * 79153151SjkimFdopen(fd, mode) 80153151Sjkim int fd; 81153151Sjkim char *mode; 82153151Sjkim{ 83153151Sjkim FILE *fp; 84153151Sjkim 85153151Sjkim if ((fp = fdopen(fd, mode)) != NULL) { 86153151Sjkim register_file(fp, 0, 0); 87153151Sjkim (void) fcntl(fileno(fp), F_SETFD, 1); 88153151Sjkim } 89153151Sjkim return fp; 90153151Sjkim} 91153151Sjkim 92153151Sjkimint 93153151SjkimFclose(fp) 94153151Sjkim FILE *fp; 95153151Sjkim{ 96153151Sjkim unregister_file(fp); 97153151Sjkim return fclose(fp); 98153151Sjkim} 99153151Sjkim 100153151SjkimFILE * 101153151SjkimPopen(cmd, mode) 102153151Sjkim char *cmd; 103153151Sjkim char *mode; 104153151Sjkim{ 105153151Sjkim int p[2]; 106153995Sjkim int myside, hisside, fd0, fd1; 107153995Sjkim int pid; 108153995Sjkim FILE *fp; 109153995Sjkim 110153151Sjkim if (pipe(p) < 0) 111153151Sjkim return NULL; 112153157Sjkim (void) fcntl(p[READ], F_SETFD, 1); 113153151Sjkim (void) fcntl(p[WRITE], F_SETFD, 1); 114153151Sjkim if (*mode == 'r') { 115153151Sjkim myside = p[READ]; 116153151Sjkim fd0 = -1; 117153151Sjkim hisside = fd1 = p[WRITE]; 118153151Sjkim } else { 119153151Sjkim myside = p[WRITE]; 120153151Sjkim hisside = fd0 = p[READ]; 121153151Sjkim fd1 = -1; 122153151Sjkim } 123153151Sjkim if ((pid = start_command(cmd, 0, fd0, fd1, NOSTR, NOSTR, NOSTR)) < 0) { 124153151Sjkim close(p[READ]); 125153151Sjkim close(p[WRITE]); 126153151Sjkim return NULL; 127153151Sjkim } 128153151Sjkim (void) close(hisside); 129153151Sjkim if ((fp = fdopen(myside, mode)) != NULL) 130153151Sjkim register_file(fp, 1, pid); 131153151Sjkim return fp; 132153151Sjkim} 133153151Sjkim 134181644Sjkimint 135179967SjkimPclose(ptr) 136181644Sjkim FILE *ptr; 137181644Sjkim{ 138153151Sjkim int i; 139153151Sjkim int omask; 140153151Sjkim 141153151Sjkim i = file_pid(ptr); 142153151Sjkim unregister_file(ptr); 143153151Sjkim (void) fclose(ptr); 144153151Sjkim omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP)); 145153151Sjkim i = wait_child(i); 146153151Sjkim sigsetmask(omask); 147179967Sjkim return i; 148181644Sjkim} 149181644Sjkim 150153151Sjkimvoid 151153151Sjkimclose_all_files() 152153151Sjkim{ 153181644Sjkim 154181644Sjkim while (fp_head) 155153151Sjkim if (fp_head->pipe) 156153151Sjkim (void) Pclose(fp_head->fp); 157153151Sjkim else 158179967Sjkim (void) Fclose(fp_head->fp); 159179967Sjkim} 160179967Sjkim 161181644Sjkimvoid 162181644Sjkimregister_file(fp, pipe, pid) 163179977Sjkim FILE *fp; 164181644Sjkim int pipe, pid; 165181644Sjkim{ 166179967Sjkim struct fp *fpp; 167153151Sjkim 168153151Sjkim if ((fpp = (struct fp *) malloc(sizeof *fpp)) == NULL) 169153151Sjkim panic("Out of memory"); 170153151Sjkim fpp->fp = fp; 171179977Sjkim fpp->pipe = pipe; 172179967Sjkim fpp->pid = pid; 173179967Sjkim fpp->link = fp_head; 174179967Sjkim fp_head = fpp; 175181644Sjkim} 176181644Sjkim 177181644Sjkimvoid 178181644Sjkimunregister_file(fp) 179179967Sjkim FILE *fp; 180153151Sjkim{ 181153151Sjkim struct fp **pp, *p; 182153151Sjkim 183153151Sjkim for (pp = &fp_head; p = *pp; pp = &p->link) 184179977Sjkim if (p->fp == fp) { 185179967Sjkim *pp = p->link; 186181644Sjkim free((char *) p); 187181644Sjkim return; 188181644Sjkim } 189181644Sjkim panic("Invalid file pointer"); 190179967Sjkim} 191153151Sjkim 192153151Sjkimfile_pid(fp) 193153151Sjkim FILE *fp; 194181644Sjkim{ 195153151Sjkim struct fp *p; 196153151Sjkim 197153151Sjkim for (p = fp_head; p; p = p->link) 198181644Sjkim if (p->fp == fp) 199153151Sjkim return (p->pid); 200153151Sjkim panic("Invalid file pointer"); 201153151Sjkim /*NOTREACHED*/ 202179967Sjkim} 203179967Sjkim 204179967Sjkim/* 205179967Sjkim * Run a command without a shell, with optional arguments and splicing 206181644Sjkim * of stdin and stdout. The command name can be a sequence of words. 207181644Sjkim * Signals must be handled by the caller. 208179977Sjkim * "Mask" contains the signals to ignore in the new process. 209181644Sjkim * SIGINT is enabled unless it's in the mask. 210181644Sjkim */ 211179967Sjkim/*VARARGS4*/ 212153151Sjkimint 213153151Sjkimrun_command(cmd, mask, infd, outfd, a0, a1, a2) 214153151Sjkim char *cmd; 215153151Sjkim int mask, infd, outfd; 216179977Sjkim char *a0, *a1, *a2; 217179967Sjkim{ 218179967Sjkim int pid; 219179967Sjkim 220179967Sjkim if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0) 221181644Sjkim return -1; 222181644Sjkim return wait_command(pid); 223181644Sjkim} 224181644Sjkim 225179967Sjkim/*VARARGS4*/ 226153151Sjkimint 227153151Sjkimstart_command(cmd, mask, infd, outfd, a0, a1, a2) 228153151Sjkim char *cmd; 229153151Sjkim int mask, infd, outfd; 230179977Sjkim char *a0, *a1, *a2; 231179967Sjkim{ 232179967Sjkim int pid; 233181644Sjkim 234181644Sjkim if ((pid = vfork()) < 0) { 235181644Sjkim perror("fork"); 236181644Sjkim return -1; 237179967Sjkim } 238153151Sjkim if (pid == 0) { 239153151Sjkim char *argv[100]; 240153151Sjkim int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv); 241179967Sjkim 242181644Sjkim if ((argv[i++] = a0) != NOSTR && 243181644Sjkim (argv[i++] = a1) != NOSTR && 244179977Sjkim (argv[i++] = a2) != NOSTR) 245181644Sjkim argv[i] = NOSTR; 246181644Sjkim prepare_child(mask, infd, outfd); 247179977Sjkim execvp(argv[0], argv); 248179967Sjkim perror(argv[0]); 249179967Sjkim _exit(1); 250179967Sjkim } 251153151Sjkim return pid; 252153151Sjkim} 253153151Sjkim 254179967Sjkimvoid 255153151Sjkimprepare_child(mask, infd, outfd) 256153151Sjkim int mask, infd, outfd; 257153151Sjkim{ 258179967Sjkim int i; 259153151Sjkim 260153151Sjkim /* 261153151Sjkim * All file descriptors other than 0, 1, and 2 are supposed to be 262179967Sjkim * close-on-exec. 263179967Sjkim */ 264179967Sjkim if (infd >= 0) 265153151Sjkim dup2(infd, 0); 266153151Sjkim if (outfd >= 0) 267153151Sjkim dup2(outfd, 1); 268179967Sjkim for (i = 1; i <= NSIG; i++) 269179967Sjkim if (mask & sigmask(i)) 270179967Sjkim (void) signal(i, SIG_IGN); 271153151Sjkim if ((mask & sigmask(SIGINT)) == 0) 272153151Sjkim (void) signal(SIGINT, SIG_DFL); 273153151Sjkim (void) sigsetmask(0); 274153151Sjkim} 275153151Sjkim 276153151Sjkimint 277153151Sjkimwait_command(pid) 278153151Sjkim int pid; 279179967Sjkim{ 280179967Sjkim 281179967Sjkim if (wait_child(pid) < 0) { 282153151Sjkim printf("Fatal error in process.\n"); 283153151Sjkim return -1; 284153151Sjkim } 285179967Sjkim return 0; 286179967Sjkim} 287179967Sjkim 288153151Sjkimstatic struct child * 289153151Sjkimfindchild(pid) 290153151Sjkim int pid; 291153151Sjkim{ 292153151Sjkim register struct child **cpp; 293153151Sjkim 294153151Sjkim for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 295153151Sjkim cpp = &(*cpp)->link) 296179967Sjkim ; 297153151Sjkim if (*cpp == NULL) { 298153151Sjkim *cpp = (struct child *) malloc(sizeof (struct child)); 299153151Sjkim (*cpp)->pid = pid; 300153151Sjkim (*cpp)->done = (*cpp)->free = 0; 301153151Sjkim (*cpp)->link = NULL; 302153151Sjkim } 303153151Sjkim return *cpp; 304153151Sjkim} 305179967Sjkim 306153151Sjkimstatic void 307153151Sjkimdelchild(cp) 308153151Sjkim register struct child *cp; 309153151Sjkim{ 310153151Sjkim register struct child **cpp; 311153151Sjkim 312153151Sjkim for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 313179967Sjkim ; 314153151Sjkim *cpp = cp->link; 315153151Sjkim free((char *) cp); 316153151Sjkim} 317153151Sjkim 318153151Sjkimvoid 319153151Sjkimsigchild(signo) 320153151Sjkim int signo; 321179967Sjkim{ 322179967Sjkim int pid; 323153151Sjkim union wait status; 324153151Sjkim register struct child *cp; 325153151Sjkim 326153151Sjkim while ((pid = 327153151Sjkim wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) { 328153151Sjkim cp = findchild(pid); 329153151Sjkim if (cp->free) 330179967Sjkim delchild(cp); 331153151Sjkim else { 332153151Sjkim cp->done = 1; 333153151Sjkim cp->status = status; 334153151Sjkim } 335153151Sjkim } 336153151Sjkim} 337153151Sjkim 338179967Sjkimunion wait wait_status; 339153151Sjkim 340153151Sjkim/* 341153151Sjkim * Wait for a specific child to die. 342153151Sjkim */ 343153151Sjkimint 344153151Sjkimwait_child(pid) 345153151Sjkim int pid; 346179967Sjkim{ 347153151Sjkim int mask = sigblock(sigmask(SIGCHLD)); 348153151Sjkim register struct child *cp = findchild(pid); 349153151Sjkim 350153151Sjkim while (!cp->done) 351153151Sjkim sigpause(mask); 352153151Sjkim wait_status = cp->status; 353153151Sjkim delchild(cp); 354179967Sjkim sigsetmask(mask); 355179967Sjkim return wait_status.w_status ? -1 : 0; 356153151Sjkim} 357153151Sjkim 358153151Sjkim/* 359153151Sjkim * Mark a child as don't care. 360153151Sjkim */ 361153151Sjkimvoid 362153151Sjkimfree_child(pid) 363179967Sjkim int pid; 364153151Sjkim{ 365153151Sjkim int mask = sigblock(sigmask(SIGCHLD)); 366153151Sjkim register struct child *cp = findchild(pid); 367179967Sjkim 368153151Sjkim if (cp->done) 369153151Sjkim delchild(cp); 370153151Sjkim else 371179967Sjkim cp->free = 1; 372179967Sjkim sigsetmask(mask); 373153151Sjkim} 374153151Sjkim