root/usr/src/cmd/cmd-inet/usr.bin/ftp/pclose.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 *      Copyright 1996 Sun Microsystems, Inc.  All rights reserved.
 *      Use is subject to license terms.
 */

/*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
/*      All Rights Reserved     */

/*
 *      University Copyright- Copyright (c) 1982, 1986, 1988
 *      The Regents of the University of California
 *      All Rights Reserved
 *
 *      University Acknowledgment- Portions of this document are derived from
 *      software developed by the University of California, Berkeley, and its
 *      contributors.
 */

#include "ftp_var.h"

#ifndef sigmask
#define sigmask(m)      (1 << ((m)-1))
#endif

#define set2mask(setp) ((setp)->__sigbits[0])
#define mask2set(mask, setp) \
        ((mask) == -1 ? sigfillset(setp) : (((setp)->__sigbits[0]) = (mask)))


static int
sigsetmask(int mask)
{
        sigset_t oset;
        sigset_t nset;

        (void) sigprocmask(0, (sigset_t *)0, &nset);
        mask2set(mask, &nset);
        (void) sigprocmask(SIG_SETMASK, &nset, &oset);
        return (set2mask(&oset));
}

static int
sigblock(int mask)
{
        sigset_t oset;
        sigset_t nset;

        (void) sigprocmask(0, (sigset_t *)0, &nset);
        mask2set(mask, &nset);
        (void) sigprocmask(SIG_BLOCK, &nset, &oset);
        return (set2mask(&oset));
}

#define signal(s, f)    sigset(s, f)

#define tst(a, b)       (*mode == 'r'? (b) : (a))
#define RDR             0
#define WTR             1
#define NOFILES         20      /* just in case */

static  pid_t *popen_pid;
static  rlim_t nfiles = 0;

FILE *
mypopen(char *cmd, char *mode)
{
        int p[2];
        pid_t pid;
        int myside, remside, i;
        struct rlimit rl;

        if (nfiles <= 0) {
                if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
                        nfiles = rl.rlim_max;
                else
                        nfiles = NOFILES;
        }
        if (popen_pid == NULL) {
                popen_pid = (pid_t *)malloc((unsigned)nfiles *
                    sizeof (*popen_pid));
                if (popen_pid == NULL)
                        return (NULL);
                for (i = 0; i < nfiles; i++)
                        popen_pid[i] = (pid_t)-1;
        }
        if (pipe(p) < 0)
                return (NULL);
        myside = tst(p[WTR], p[RDR]);
        remside = tst(p[RDR], p[WTR]);
        if ((pid = vfork()) == 0) {
                /* myside and remside reverse roles in child */
                (void) close(myside);
                if (remside != tst(0, 1)) {
                        (void) dup2(remside, tst(0, 1));
                        (void) close(remside);
                }
                execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
                _exit(127);
        }
        if (pid == (pid_t)-1) {
                (void) close(myside);
                (void) close(remside);
                return (NULL);
        }
        popen_pid[myside] = pid;
        (void) close(remside);
        return (fdopen(myside, mode));
}

/*ARGSUSED*/
static void
pabort(int sig)
{
        extern int mflag;

        mflag = 0;
}

int
mypclose(FILE *ptr)
{
        pid_t child, pid;
        int omask;
        void (*istat)();
        int status;

        child = popen_pid[fileno(ptr)];
        popen_pid[fileno(ptr)] = (pid_t)-1;
        (void) fclose(ptr);
        if (child == (pid_t)-1)
                return (-1);
        istat = signal(SIGINT, pabort);
        omask = sigblock(sigmask(SIGQUIT)|sigmask(SIGHUP));
        while ((pid = wait(&status)) != child && pid != (pid_t)-1)
                ;
        (void) sigsetmask(omask);
        (void) signal(SIGINT, istat);
        return (pid == (pid_t)-1 ? -1 : 0);
}