[BACK]Return to popen.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mail

Annotation of src/usr.bin/mail/popen.c, Revision 1.33

1.33    ! millert     1: /*     $OpenBSD: popen.c,v 1.32 2002/06/12 06:07:15 mpech Exp $        */
1.6       millert     2: /*     $NetBSD: popen.c,v 1.6 1997/05/13 06:48:42 mikel Exp $  */
1.2       deraadt     3:
1.1       deraadt     4: /*
                      5:  * Copyright (c) 1980, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
1.33    ! millert    16:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
                     33: #ifndef lint
1.2       deraadt    34: #if 0
1.29      millert    35: static const char sccsid[] = "@(#)popen.c      8.1 (Berkeley) 6/6/93";
1.2       deraadt    36: #else
1.33    ! millert    37: static const char rcsid[] = "$OpenBSD: popen.c,v 1.32 2002/06/12 06:07:15 mpech Exp $";
1.2       deraadt    38: #endif
1.1       deraadt    39: #endif /* not lint */
                     40:
                     41: #include "rcv.h"
                     42: #include <sys/wait.h>
                     43: #include <fcntl.h>
1.12      deraadt    44: #include <errno.h>
1.25      millert    45: #include <stdarg.h>
1.1       deraadt    46: #include "extern.h"
                     47:
                     48: #define READ 0
                     49: #define WRITE 1
                     50:
                     51: struct fp {
                     52:        FILE *fp;
                     53:        int pipe;
1.29      millert    54:        pid_t pid;
1.1       deraadt    55:        struct fp *link;
                     56: };
                     57: static struct fp *fp_head;
                     58:
                     59: struct child {
1.29      millert    60:        pid_t pid;
1.1       deraadt    61:        char done;
                     62:        char free;
1.13      millert    63:        int status;
1.1       deraadt    64:        struct child *link;
                     65: };
1.15      niklas     66: static struct child *child, *child_freelist = NULL;
1.29      millert    67:
                     68: static struct child *findchild(pid_t, int);
                     69: static void delchild(struct child *);
                     70: static pid_t file_pid(FILE *);
                     71: static int handle_spool_locks(int);
1.1       deraadt    72:
                     73: FILE *
1.29      millert    74: Fopen(char *file, char *mode)
1.1       deraadt    75: {
                     76:        FILE *fp;
                     77:
                     78:        if ((fp = fopen(file, mode)) != NULL) {
                     79:                register_file(fp, 0, 0);
1.7       millert    80:                (void)fcntl(fileno(fp), F_SETFD, 1);
1.1       deraadt    81:        }
1.6       millert    82:        return(fp);
1.1       deraadt    83: }
                     84:
                     85: FILE *
1.29      millert    86: Fdopen(int fd, char *mode)
1.1       deraadt    87: {
                     88:        FILE *fp;
                     89:
                     90:        if ((fp = fdopen(fd, mode)) != NULL) {
                     91:                register_file(fp, 0, 0);
1.7       millert    92:                (void)fcntl(fileno(fp), F_SETFD, 1);
1.1       deraadt    93:        }
1.6       millert    94:        return(fp);
1.1       deraadt    95: }
                     96:
                     97: int
1.29      millert    98: Fclose(FILE *fp)
1.1       deraadt    99: {
1.29      millert   100:
1.1       deraadt   101:        unregister_file(fp);
1.6       millert   102:        return(fclose(fp));
1.1       deraadt   103: }
                    104:
                    105: FILE *
1.29      millert   106: Popen(char *cmd, char *mode)
1.1       deraadt   107: {
                    108:        int p[2];
                    109:        int myside, hisside, fd0, fd1;
1.29      millert   110:        pid_t pid;
1.2       deraadt   111:        sigset_t nset;
1.1       deraadt   112:        FILE *fp;
                    113:
                    114:        if (pipe(p) < 0)
1.6       millert   115:                return(NULL);
1.7       millert   116:        (void)fcntl(p[READ], F_SETFD, 1);
                    117:        (void)fcntl(p[WRITE], F_SETFD, 1);
1.1       deraadt   118:        if (*mode == 'r') {
                    119:                myside = p[READ];
1.25      millert   120:                hisside = fd0 = fd1 = p[WRITE];
1.1       deraadt   121:        } else {
                    122:                myside = p[WRITE];
                    123:                hisside = fd0 = p[READ];
                    124:                fd1 = -1;
                    125:        }
1.2       deraadt   126:        sigemptyset(&nset);
1.31      millert   127:        pid = start_command(value("SHELL"), &nset, fd0, fd1, "-c", cmd, NULL);
1.28      millert   128:        if (pid < 0) {
1.6       millert   129:                (void)close(p[READ]);
                    130:                (void)close(p[WRITE]);
                    131:                return(NULL);
1.1       deraadt   132:        }
1.6       millert   133:        (void)close(hisside);
1.1       deraadt   134:        if ((fp = fdopen(myside, mode)) != NULL)
                    135:                register_file(fp, 1, pid);
1.6       millert   136:        return(fp);
1.1       deraadt   137: }
                    138:
                    139: int
1.29      millert   140: Pclose(FILE *ptr)
1.1       deraadt   141: {
                    142:        int i;
1.2       deraadt   143:        sigset_t nset, oset;
1.1       deraadt   144:
                    145:        i = file_pid(ptr);
                    146:        unregister_file(ptr);
1.6       millert   147:        (void)fclose(ptr);
1.2       deraadt   148:        sigemptyset(&nset);
                    149:        sigaddset(&nset, SIGINT);
                    150:        sigaddset(&nset, SIGHUP);
                    151:        sigprocmask(SIG_BLOCK, &nset, &oset);
1.1       deraadt   152:        i = wait_child(i);
1.2       deraadt   153:        sigprocmask(SIG_SETMASK, &oset, NULL);
1.6       millert   154:        return(i);
1.1       deraadt   155: }
                    156:
                    157: void
1.29      millert   158: close_all_files(void)
1.1       deraadt   159: {
                    160:
                    161:        while (fp_head)
                    162:                if (fp_head->pipe)
1.6       millert   163:                        (void)Pclose(fp_head->fp);
1.1       deraadt   164:                else
1.6       millert   165:                        (void)Fclose(fp_head->fp);
1.1       deraadt   166: }
                    167:
                    168: void
1.29      millert   169: register_file(FILE *fp, int pipe, pid_t pid)
1.1       deraadt   170: {
                    171:        struct fp *fpp;
                    172:
1.7       millert   173:        if ((fpp = (struct fp *)malloc(sizeof(*fpp))) == NULL)
1.14      millert   174:                errx(1, "Out of memory");
1.1       deraadt   175:        fpp->fp = fp;
                    176:        fpp->pipe = pipe;
                    177:        fpp->pid = pid;
                    178:        fpp->link = fp_head;
                    179:        fp_head = fpp;
                    180: }
                    181:
                    182: void
1.29      millert   183: unregister_file(FILE *fp)
1.1       deraadt   184: {
                    185:        struct fp **pp, *p;
                    186:
1.2       deraadt   187:        for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link)
1.1       deraadt   188:                if (p->fp == fp) {
                    189:                        *pp = p->link;
1.7       millert   190:                        (void)free(p);
1.1       deraadt   191:                        return;
                    192:                }
1.14      millert   193:        errx(1, "Invalid file pointer");
1.1       deraadt   194: }
                    195:
1.29      millert   196: static pid_t
                    197: file_pid(FILE *fp)
1.1       deraadt   198: {
                    199:        struct fp *p;
                    200:
                    201:        for (p = fp_head; p; p = p->link)
                    202:                if (p->fp == fp)
1.6       millert   203:                        return(p->pid);
1.14      millert   204:        errx(1, "Invalid file pointer");
1.1       deraadt   205:        /*NOTREACHED*/
                    206: }
                    207:
                    208: /*
                    209:  * Run a command without a shell, with optional arguments and splicing
1.26      millert   210:  * of stdin (-1 means none) and stdout.  The command name can be a sequence
                    211:  * of words.
1.1       deraadt   212:  * Signals must be handled by the caller.
1.20      millert   213:  * "nset" contains the signals to ignore in the new process.
                    214:  * SIGINT is enabled unless it's in "nset".
1.1       deraadt   215:  */
1.29      millert   216: pid_t
                    217: start_commandv(char *cmd, sigset_t *nset, int infd, int outfd, va_list args)
1.1       deraadt   218: {
1.29      millert   219:        pid_t pid;
1.1       deraadt   220:
1.25      millert   221:        if ((pid = fork()) < 0) {
1.6       millert   222:                warn("fork");
                    223:                return(-1);
1.1       deraadt   224:        }
                    225:        if (pid == 0) {
                    226:                char *argv[100];
1.6       millert   227:                int i = getrawlist(cmd, argv, sizeof(argv)/ sizeof(*argv));
1.1       deraadt   228:
1.25      millert   229:                while ((argv[i++] = va_arg(args, char *)))
                    230:                        ;
                    231:                argv[i] = NULL;
1.10      millert   232:                prepare_child(nset, infd, outfd);
1.1       deraadt   233:                execvp(argv[0], argv);
1.24      millert   234:                warn("%s", argv[0]);
1.1       deraadt   235:                _exit(1);
                    236:        }
1.6       millert   237:        return(pid);
1.1       deraadt   238: }
                    239:
1.25      millert   240: int
                    241: run_command(char *cmd, sigset_t *nset, int infd, int outfd, ...)
                    242: {
1.29      millert   243:        pid_t pid;
1.25      millert   244:        va_list args;
                    245:
                    246:        va_start(args, outfd);
                    247:        pid = start_commandv(cmd, nset, infd, outfd, args);
                    248:        va_end(args);
                    249:        if (pid < 0)
                    250:                return(-1);
                    251:        return(wait_command(pid));
                    252: }
                    253:
                    254: int
                    255: start_command(char *cmd, sigset_t *nset, int infd, int outfd, ...)
                    256: {
                    257:        va_list args;
                    258:        int r;
                    259:
                    260:        va_start(args, outfd);
                    261:        r = start_commandv(cmd, nset, infd, outfd, args);
                    262:        va_end(args);
                    263:        return(r);
                    264: }
                    265:
1.1       deraadt   266: void
1.29      millert   267: prepare_child(sigset_t *nset, int infd, int outfd)
1.1       deraadt   268: {
                    269:        int i;
1.9       millert   270:        sigset_t eset;
1.1       deraadt   271:
                    272:        /*
                    273:         * All file descriptors other than 0, 1, and 2 are supposed to be
                    274:         * close-on-exec.
                    275:         */
1.26      millert   276:        if (infd > 0) {
1.1       deraadt   277:                dup2(infd, 0);
1.26      millert   278:        } else if (infd != 0) {
1.25      millert   279:                /* we don't want the child stealing my stdin input */
                    280:                close(0);
                    281:                open(_PATH_DEVNULL, O_RDONLY, 0);
                    282:        }
1.26      millert   283:        if (outfd >= 0 && outfd != 1)
1.1       deraadt   284:                dup2(outfd, 1);
1.6       millert   285:        if (nset == NULL)
                    286:                return;
                    287:        if (nset != NULL) {
1.5       deraadt   288:                for (i = 1; i < NSIG; i++)
1.3       dm        289:                        if (sigismember(nset, i))
1.7       millert   290:                                (void)signal(i, SIG_IGN);
1.3       dm        291:        }
1.6       millert   292:        if (nset == NULL || !sigismember(nset, SIGINT))
1.7       millert   293:                (void)signal(SIGINT, SIG_DFL);
1.9       millert   294:        sigemptyset(&eset);
                    295:        (void)sigprocmask(SIG_SETMASK, &eset, NULL);
1.1       deraadt   296: }
                    297:
                    298: int
1.29      millert   299: wait_command(pid_t pid)
1.1       deraadt   300: {
                    301:
                    302:        if (wait_child(pid) < 0) {
1.6       millert   303:                puts("Fatal error in process.");
                    304:                return(-1);
1.1       deraadt   305:        }
1.6       millert   306:        return(0);
1.1       deraadt   307: }
                    308:
                    309: static struct child *
1.29      millert   310: findchild(pid_t pid, int dont_alloc)
1.1       deraadt   311: {
1.14      millert   312:        struct child **cpp;
1.1       deraadt   313:
                    314:        for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
                    315:             cpp = &(*cpp)->link)
                    316:                        ;
                    317:        if (*cpp == NULL) {
1.15      niklas    318:                if (dont_alloc)
                    319:                        return(NULL);
                    320:                if (child_freelist) {
                    321:                        *cpp = child_freelist;
                    322:                        child_freelist = (*cpp)->link;
1.30      millert   323:                } else {
1.15      niklas    324:                        *cpp = (struct child *)malloc(sizeof(struct child));
1.30      millert   325:                        if (*cpp == NULL)
                    326:                                errx(1, "Out of memory");
                    327:                }
1.1       deraadt   328:                (*cpp)->pid = pid;
                    329:                (*cpp)->done = (*cpp)->free = 0;
                    330:                (*cpp)->link = NULL;
                    331:        }
1.6       millert   332:        return(*cpp);
1.1       deraadt   333: }
                    334:
                    335: static void
1.29      millert   336: delchild(struct child *cp)
1.1       deraadt   337: {
1.14      millert   338:        struct child **cpp;
1.1       deraadt   339:
                    340:        for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
                    341:                ;
                    342:        *cpp = cp->link;
1.15      niklas    343:        cp->link = child_freelist;
                    344:        child_freelist = cp;
1.1       deraadt   345: }
                    346:
                    347: void
1.29      millert   348: sigchild(int signo)
1.1       deraadt   349: {
1.29      millert   350:        pid_t pid;
1.13      millert   351:        int status;
1.14      millert   352:        struct child *cp;
1.11      deraadt   353:        int save_errno = errno;
1.1       deraadt   354:
                    355:        while ((pid =
1.13      millert   356:            waitpid((pid_t)-1, &status, WNOHANG)) > 0) {
1.15      niklas    357:                cp = findchild(pid, 1);
                    358:                if (!cp)
                    359:                        continue;
1.1       deraadt   360:                if (cp->free)
                    361:                        delchild(cp);
                    362:                else {
                    363:                        cp->done = 1;
                    364:                        cp->status = status;
                    365:                }
                    366:        }
1.11      deraadt   367:        errno = save_errno;
1.1       deraadt   368: }
                    369:
1.13      millert   370: int wait_status;
1.1       deraadt   371:
                    372: /*
                    373:  * Wait for a specific child to die.
                    374:  */
                    375: int
1.29      millert   376: wait_child(pid_t pid)
1.1       deraadt   377: {
1.20      millert   378:        struct child *cp;
1.2       deraadt   379:        sigset_t nset, oset;
1.32      mpech     380:        pid_t rv = 0;
1.9       millert   381:
1.2       deraadt   382:        sigemptyset(&nset);
                    383:        sigaddset(&nset, SIGCHLD);
                    384:        sigprocmask(SIG_BLOCK, &nset, &oset);
1.21      millert   385:        /*
                    386:         * If we have not already waited on the pid (via sigchild)
                    387:         * wait on it now.  Otherwise, use the wait status stashed
                    388:         * by sigchild.
                    389:         */
                    390:        cp = findchild(pid, 1);
                    391:        if (cp == NULL || !cp->done)
                    392:                rv = waitpid(pid, &wait_status, 0);
                    393:        else
                    394:                wait_status = cp->status;
                    395:        if (cp != NULL)
                    396:                delchild(cp);
                    397:        sigprocmask(SIG_SETMASK, &oset, NULL);
                    398:        if (rv == -1 || (WIFEXITED(wait_status) && WEXITSTATUS(wait_status)))
1.20      millert   399:                return(-1);
1.21      millert   400:        else
                    401:                return(0);
1.1       deraadt   402: }
                    403:
                    404: /*
                    405:  * Mark a child as don't care.
                    406:  */
                    407: void
1.29      millert   408: free_child(pid_t pid)
1.1       deraadt   409: {
1.20      millert   410:        struct child *cp;
1.2       deraadt   411:        sigset_t nset, oset;
1.17      millert   412:
1.2       deraadt   413:        sigemptyset(&nset);
                    414:        sigaddset(&nset, SIGCHLD);
                    415:        sigprocmask(SIG_BLOCK, &nset, &oset);
1.21      millert   416:        if ((cp = findchild(pid, 0)) != NULL) {
                    417:                if (cp->done)
                    418:                        delchild(cp);
                    419:                else
                    420:                        cp->free = 1;
                    421:        }
1.2       deraadt   422:        sigprocmask(SIG_SETMASK, &oset, NULL);
1.4       millert   423: }
                    424:
                    425: /*
1.22      millert   426:  * Lock(1)/unlock(0) mail spool using lockspool(1).
1.4       millert   427:  * Returns 1 for success, 0 for failure, -1 for bad usage.
                    428:  */
                    429: static int
1.29      millert   430: handle_spool_locks(int action)
1.4       millert   431: {
                    432:        static FILE *lockfp = NULL;
1.29      millert   433:        static pid_t lock_pid;
1.4       millert   434:
                    435:        if (action == 0) {
                    436:                /* Clear the lock */
                    437:                if (lockfp == NULL) {
1.6       millert   438:                        fputs("handle_spool_locks: no spool lock to remove.\n",
                    439:                            stderr);
                    440:                        return(-1);
1.4       millert   441:                }
1.6       millert   442:                (void)Pclose(lockfp);
1.4       millert   443:                lockfp = NULL;
                    444:        } else if (action == 1) {
1.27      millert   445:                char *cmd;
                    446:                char buf[sizeof(_PATH_LOCKSPOOL) + MAXLOGNAME + 1];
1.23      millert   447:
                    448:                /* XXX - lockspool requires root for user arg, we do not */
1.27      millert   449:                if (uflag) {
                    450:                        snprintf(buf, sizeof(buf), "%s %s", _PATH_LOCKSPOOL,
                    451:                            myname);
                    452:                        cmd = buf;
                    453:                } else
                    454:                        cmd = _PATH_LOCKSPOOL;
1.23      millert   455:
1.4       millert   456:                /* Create the lock */
1.23      millert   457:                lockfp = Popen(cmd, "r");
1.25      millert   458:                if (lockfp == NULL)
                    459:                        return(0);
                    460:                if (getc(lockfp) != '1') {
                    461:                        Pclose(lockfp);
1.4       millert   462:                        lockfp = NULL;
1.6       millert   463:                        return(0);
1.4       millert   464:                }
                    465:                lock_pid = fp_head->pid;        /* new entries added at head */
                    466:        } else {
1.19      millert   467:                (void)fprintf(stderr, "handle_spool_locks: unknown action %d\n",
1.4       millert   468:                    action);
1.6       millert   469:                return(-1);
1.4       millert   470:        }
                    471:
1.6       millert   472:        return(1);
1.4       millert   473: }
                    474:
                    475: int
1.29      millert   476: spool_lock(void)
1.4       millert   477: {
1.29      millert   478:
1.4       millert   479:        return(handle_spool_locks(1));
                    480: }
                    481:
                    482: int
1.29      millert   483: spool_unlock(void)
1.4       millert   484: {
1.29      millert   485:
1.4       millert   486:        return(handle_spool_locks(0));
1.1       deraadt   487: }