corrections for echoing the last command when "!!" is given,
[unix-history] / usr / src / libexec / ftpd / popen.c
CommitLineData
96c0abd0
KB
1/*
2 * Copyright (c) 1988 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software written by Ken Arnold and
6 * published in UNIX Review, Vol. 6, No. 8.
7 *
1343342a 8 * %sccs.include.redist.c%
96c0abd0 9 *
96c0abd0
KB
10 */
11
12#ifndef lint
60de319b 13static char sccsid[] = "@(#)popen.c 5.10 (Berkeley) %G%";
96c0abd0
KB
14#endif /* not lint */
15
5f3a5fe7 16#include <sys/types.h>
882508af 17#include <sys/wait.h>
60de319b 18
5bb0ca89
KB
19#include <signal.h>
20#include <unistd.h>
96c0abd0 21#include <stdio.h>
5bb0ca89
KB
22#include <stdlib.h>
23#include <string.h>
60de319b 24#include "extern.h"
96c0abd0 25
5f3a5fe7
KB
26/*
27 * Special version of popen which avoids call to shell. This insures noone
28 * may create a pipe to a hidden program as a side effect of a list or dir
29 * command.
30 */
882508af 31static int *pids;
96c0abd0
KB
32static int fds;
33
34FILE *
5256bbac 35ftpd_popen(program, type)
96c0abd0
KB
36 char *program, *type;
37{
5f3a5fe7 38 register char *cp;
96c0abd0 39 FILE *iop;
5f3a5fe7
KB
40 int argc, gargc, pdes[2], pid;
41 char **pop, *argv[100], *gargv[1000], *vv[2];
96c0abd0
KB
42
43 if (*type != 'r' && *type != 'w' || type[1])
44 return(NULL);
45
46 if (!pids) {
47 if ((fds = getdtablesize()) <= 0)
48 return(NULL);
882508af 49 if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
96c0abd0 50 return(NULL);
882508af 51 bzero((char *)pids, fds * sizeof(int));
96c0abd0
KB
52 }
53 if (pipe(pdes) < 0)
54 return(NULL);
5f3a5fe7
KB
55
56 /* break up string into pieces */
57 for (argc = 0, cp = program;; cp = NULL)
58 if (!(argv[argc++] = strtok(cp, " \t\n")))
59 break;
60
61 /* glob each piece */
62 gargv[0] = argv[0];
63 for (gargc = argc = 1; argv[argc]; argc++) {
5bb0ca89 64 if (!(pop = ftpglob(argv[argc]))) { /* globbing failed */
5f3a5fe7
KB
65 vv[0] = argv[argc];
66 vv[1] = NULL;
67 pop = copyblk(vv);
68 }
69 argv[argc] = (char *)pop; /* save to free later */
70 while (*pop && gargc < 1000)
71 gargv[gargc++] = *pop++;
72 }
73 gargv[gargc] = NULL;
74
75 iop = NULL;
96c0abd0
KB
76 switch(pid = vfork()) {
77 case -1: /* error */
78 (void)close(pdes[0]);
79 (void)close(pdes[1]);
97f47643 80 goto pfree;
96c0abd0
KB
81 /* NOTREACHED */
82 case 0: /* child */
83 if (*type == 'r') {
84 if (pdes[1] != 1) {
85 dup2(pdes[1], 1);
f8086b89 86 dup2(pdes[1], 2); /* stderr, too! */
96c0abd0
KB
87 (void)close(pdes[1]);
88 }
89 (void)close(pdes[0]);
90 } else {
91 if (pdes[0] != 0) {
92 dup2(pdes[0], 0);
93 (void)close(pdes[0]);
94 }
95 (void)close(pdes[1]);
96 }
5f3a5fe7
KB
97 execv(gargv[0], gargv);
98 _exit(1);
96c0abd0
KB
99 }
100 /* parent; assume fdopen can't fail... */
101 if (*type == 'r') {
102 iop = fdopen(pdes[0], type);
103 (void)close(pdes[1]);
104 } else {
105 iop = fdopen(pdes[1], type);
106 (void)close(pdes[0]);
107 }
108 pids[fileno(iop)] = pid;
5f3a5fe7 109
97f47643 110pfree: for (argc = 1; argv[argc] != NULL; argc++) {
5f3a5fe7 111 blkfree((char **)argv[argc]);
97f47643
KB
112 free((char *)argv[argc]);
113 }
96c0abd0
KB
114 return(iop);
115}
116
60de319b 117int
882508af 118ftpd_pclose(iop)
96c0abd0
KB
119 FILE *iop;
120{
121 register int fdes;
882508af
MK
122 int omask;
123 union wait stat_loc;
124 int pid;
96c0abd0
KB
125
126 /*
127 * pclose returns -1 if stream is not associated with a
128 * `popened' command, or, if already `pclosed'.
129 */
882508af 130 if (pids == 0 || pids[fdes = fileno(iop)] == 0)
96c0abd0
KB
131 return(-1);
132 (void)fclose(iop);
133 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
5bb0ca89 134 while ((pid = wait((int *)&stat_loc)) != pids[fdes] && pid != -1);
96c0abd0
KB
135 (void)sigsetmask(omask);
136 pids[fdes] = 0;
882508af 137 return(pid == -1 ? -1 : stat_loc.w_status);
96c0abd0 138}