]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/mail/popen.c
Cleanup mail(1)'s varying styles by converting to using style(9).
[FreeBSD/FreeBSD.git] / usr.bin / mail / popen.c
1 /*
2  * Copyright (c) 1980, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 #if 0
36 static char sccsid[] = "@(#)popen.c     8.1 (Berkeley) 6/6/93";
37 #endif
38 static const char rcsid[] =
39   "$FreeBSD$";
40 #endif /* not lint */
41
42 #include "rcv.h"
43 #include <sys/wait.h>
44 #include <fcntl.h>
45 #include "extern.h"
46
47 #define READ 0
48 #define WRITE 1
49
50 struct fp {
51         FILE    *fp;
52         int     pipe;
53         int     pid;
54         struct  fp *link;
55 };
56 static struct fp *fp_head;
57
58 struct child {
59         int     pid;
60         char    done;
61         char    free;
62         int     status;
63         struct  child *link;
64 };
65 static struct child *child;
66 static struct child *findchild __P((int));
67 static void delchild __P((struct child *));
68 static int file_pid __P((FILE *));
69
70 FILE *
71 Fopen(path, mode)
72         const char *path, *mode;
73 {
74         FILE *fp;
75
76         if ((fp = fopen(path, mode)) != NULL) {
77                 register_file(fp, 0, 0);
78                 (void)fcntl(fileno(fp), F_SETFD, 1);
79         }
80         return (fp);
81 }
82
83 FILE *
84 Fdopen(fd, mode)
85         int fd;
86         const char *mode;
87 {
88         FILE *fp;
89
90         if ((fp = fdopen(fd, mode)) != NULL) {
91                 register_file(fp, 0, 0);
92                 (void)fcntl(fileno(fp), F_SETFD, 1);
93         }
94         return (fp);
95 }
96
97 int
98 Fclose(fp)
99         FILE *fp;
100 {
101         unregister_file(fp);
102         return (fclose(fp));
103 }
104
105 FILE *
106 Popen(cmd, mode)
107         char *cmd;
108         const char *mode;
109 {
110         int p[2];
111         int myside, hisside, fd0, fd1;
112         int pid;
113         FILE *fp;
114
115         if (pipe(p) < 0)
116                 return (NULL);
117         (void)fcntl(p[READ], F_SETFD, 1);
118         (void)fcntl(p[WRITE], F_SETFD, 1);
119         if (*mode == 'r') {
120                 myside = p[READ];
121                 fd0 = -1;
122                 hisside = fd1 = p[WRITE];
123         } else {
124                 myside = p[WRITE];
125                 hisside = fd0 = p[READ];
126                 fd1 = -1;
127         }
128         if ((pid = start_command(cmd, 0, fd0, fd1, NULL, NULL, NULL)) < 0) {
129                 (void)close(p[READ]);
130                 (void)close(p[WRITE]);
131                 return (NULL);
132         }
133         (void)close(hisside);
134         if ((fp = fdopen(myside, mode)) != NULL)
135                 register_file(fp, 1, pid);
136         return (fp);
137 }
138
139 int
140 Pclose(ptr)
141         FILE *ptr;
142 {
143         int i;
144         int omask;
145
146         i = file_pid(ptr);
147         unregister_file(ptr);
148         (void)fclose(ptr);
149         omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP));
150         i = wait_child(i);
151         (void)sigsetmask(omask);
152         return (i);
153 }
154
155 void
156 close_all_files()
157 {
158
159         while (fp_head != NULL)
160                 if (fp_head->pipe)
161                         (void)Pclose(fp_head->fp);
162                 else
163                         (void)Fclose(fp_head->fp);
164 }
165
166 void
167 register_file(fp, pipe, pid)
168         FILE *fp;
169         int pipe, pid;
170 {
171         struct fp *fpp;
172
173         if ((fpp = malloc(sizeof(*fpp))) == NULL)
174                 err(1, "Out of memory");
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
183 unregister_file(fp)
184         FILE *fp;
185 {
186         struct fp **pp, *p;
187
188         for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link)
189                 if (p->fp == fp) {
190                         *pp = p->link;
191                         (void)free(p);
192                         return;
193                 }
194         errx(1, "Invalid file pointer");
195         /*NOTREACHED*/
196 }
197
198 int
199 file_pid(fp)
200         FILE *fp;
201 {
202         struct fp *p;
203
204         for (p = fp_head; p != NULL; p = p->link)
205                 if (p->fp == fp)
206                         return (p->pid);
207         errx(1, "Invalid file pointer");
208         /*NOTREACHED*/
209 }
210
211 /*
212  * Run a command without a shell, with optional arguments and splicing
213  * of stdin and stdout.  The command name can be a sequence of words.
214  * Signals must be handled by the caller.
215  * "Mask" contains the signals to ignore in the new process.
216  * SIGINT is enabled unless it's in the mask.
217  */
218 /*VARARGS4*/
219 int
220 run_command(cmd, mask, infd, outfd, a0, a1, a2)
221         char *cmd;
222         int mask, infd, outfd;
223         char *a0, *a1, *a2;
224 {
225         int pid;
226
227         if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0)
228                 return (-1);
229         return (wait_command(pid));
230 }
231
232 /*VARARGS4*/
233 int
234 start_command(cmd, mask, infd, outfd, a0, a1, a2)
235         char *cmd;
236         int mask, infd, outfd;
237         char *a0, *a1, *a2;
238 {
239         int pid;
240
241         if ((pid = fork()) < 0) {
242                 warn("fork");
243                 return (-1);
244         }
245         if (pid == 0) {
246                 char *argv[100];
247                 int i = getrawlist(cmd, argv, sizeof(argv) / sizeof(*argv));
248
249                 if ((argv[i++] = a0) != NULL &&
250                     (argv[i++] = a1) != NULL &&
251                     (argv[i++] = a2) != NULL)
252                         argv[i] = NULL;
253                 prepare_child(mask, infd, outfd);
254                 execvp(argv[0], argv);
255                 warn("%s", argv[0]);
256                 _exit(1);
257         }
258         return (pid);
259 }
260
261 void
262 prepare_child(mask, infd, outfd)
263         int mask, infd, outfd;
264 {
265         int i;
266
267         /*
268          * All file descriptors other than 0, 1, and 2 are supposed to be
269          * close-on-exec.
270          */
271         if (infd >= 0)
272                 dup2(infd, 0);
273         if (outfd >= 0)
274                 dup2(outfd, 1);
275         for (i = 1; i <= NSIG; i++)
276                 if (mask & sigmask(i))
277                         (void)signal(i, SIG_IGN);
278         if ((mask & sigmask(SIGINT)) == 0)
279                 (void)signal(SIGINT, SIG_DFL);
280         (void)sigsetmask(0);
281 }
282
283 int
284 wait_command(pid)
285         int pid;
286 {
287
288         if (wait_child(pid) < 0) {
289                 printf("Fatal error in process.\n");
290                 return (-1);
291         }
292         return (0);
293 }
294
295 static struct child *
296 findchild(pid)
297         int pid;
298 {
299         struct child **cpp;
300
301         for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
302             cpp = &(*cpp)->link)
303                         ;
304         if (*cpp == NULL) {
305                 *cpp = malloc(sizeof(struct child));
306                 if (*cpp == NULL)
307                         err(1, "Out of memory");
308                 (*cpp)->pid = pid;
309                 (*cpp)->done = (*cpp)->free = 0;
310                 (*cpp)->link = NULL;
311         }
312         return (*cpp);
313 }
314
315 static void
316 delchild(cp)
317         struct child *cp;
318 {
319         struct child **cpp;
320
321         for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
322                 ;
323         *cpp = cp->link;
324         (void)free(cp);
325 }
326
327 /*ARGSUSED*/
328 void
329 sigchild(signo)
330         int signo;
331 {
332         int pid;
333         int status;
334         struct child *cp;
335
336         while ((pid = waitpid((pid_t)-1, &status, WNOHANG)) > 0) {
337                 cp = findchild(pid);
338                 if (cp->free)
339                         delchild(cp);
340                 else {
341                         cp->done = 1;
342                         cp->status = status;
343                 }
344         }
345 }
346
347 int wait_status;
348
349 /*
350  * Wait for a specific child to die.
351  */
352 int
353 wait_child(pid)
354         int pid;
355 {
356         int mask = sigblock(sigmask(SIGCHLD));
357         struct child *cp = findchild(pid);
358
359         while (!cp->done)
360                 sigpause(mask);
361         wait_status = cp->status;
362         delchild(cp);
363         (void)sigsetmask(mask);
364         return ((WIFEXITED(wait_status) && WEXITSTATUS(wait_status)) ? -1 : 0);
365 }
366
367 /*
368  * Mark a child as don't care.
369  */
370 void
371 free_child(pid)
372         int pid;
373 {
374         int mask = sigblock(sigmask(SIGCHLD));
375         struct child *cp = findchild(pid);
376
377         if (cp->done)
378                 delchild(cp);
379         else
380                 cp->free = 1;
381         (void)sigsetmask(mask);
382 }