Home | History | Annotate | Line # | Download | only in mail
      1  1.10  christos /*	$NetBSD: mime_child.c,v 1.10 2019/12/14 20:21:43 christos Exp $	*/
      2   1.1  christos 
      3   1.1  christos /*-
      4   1.1  christos  * Copyright (c) 2006 The NetBSD Foundation, Inc.
      5   1.1  christos  * All rights reserved.
      6   1.1  christos  *
      7   1.1  christos  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1  christos  * by Anon Ymous.
      9   1.1  christos  *
     10   1.1  christos  * Redistribution and use in source and binary forms, with or without
     11   1.1  christos  * modification, are permitted provided that the following conditions
     12   1.1  christos  * are met:
     13   1.1  christos  * 1. Redistributions of source code must retain the above copyright
     14   1.1  christos  *    notice, this list of conditions and the following disclaimer.
     15   1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     17   1.1  christos  *    documentation and/or other materials provided with the distribution.
     18   1.1  christos  *
     19   1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1  christos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1  christos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1  christos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1  christos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1  christos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1  christos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1  christos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1  christos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1  christos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1  christos  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1  christos  */
     31   1.1  christos 
     32   1.1  christos 
     33   1.1  christos #ifdef MIME_SUPPORT
     34   1.1  christos 
     35   1.1  christos #include <sys/cdefs.h>
     36   1.1  christos #ifndef __lint__
     37  1.10  christos __RCSID("$NetBSD: mime_child.c,v 1.10 2019/12/14 20:21:43 christos Exp $");
     38   1.1  christos #endif /* not __lint__ */
     39   1.1  christos 
     40   1.1  christos #include <assert.h>
     41   1.1  christos #include <fcntl.h>
     42   1.1  christos #include <signal.h>
     43   1.1  christos #include <stdio.h>
     44   1.1  christos #include <stdlib.h>
     45   1.1  christos #include <unistd.h>
     46   1.1  christos 
     47   1.1  christos #include "def.h"
     48   1.1  christos #include "extern.h"
     49   1.1  christos 
     50   1.1  christos #ifdef MIME_SUPPORT
     51   1.1  christos #include "mime.h"
     52   1.1  christos #include "mime_child.h"
     53   1.1  christos #endif
     54   1.1  christos 
     55   1.1  christos /*
     56   1.1  christos  * This module contains the core routines used by mime modules that
     57   1.1  christos  * need to fork children.  Nothing else in the mime modules should be
     58   1.1  christos  * doing a pipe(), fork(), or a call to any popen functions that do.
     59   1.1  christos  * These routines are tied to the file registry in popen.c and hence
     60   1.1  christos  * share much of popen code.
     61   1.1  christos  */
     62   1.1  christos 
     63   1.1  christos #define READ 0
     64   1.1  christos #define WRITE 1
     65   1.1  christos 
     66   1.1  christos static int
     67   1.1  christos get_cmd_flags(const char *cmd, const char **cmd_start)
     68   1.1  christos {
     69   1.1  christos 	const char *cp;
     70   1.1  christos 	int flags;
     71   1.1  christos 
     72   1.1  christos 	flags = 0;
     73   1.1  christos 	for (cp = cmd; cp && *cp; cp++)
     74   1.1  christos 		switch (*cp) {
     75   1.1  christos 		case '+':
     76   1.1  christos 			flags |= CMD_FLAG_ALTERNATIVE;
     77   1.1  christos 			break;
     78   1.1  christos 		case '-':
     79   1.1  christos 			flags |= CMD_FLAG_NO_DECODE;
     80   1.1  christos 			break;
     81   1.1  christos 		case '!':
     82   1.1  christos 			flags |= CMD_FLAG_SHELLCMD;
     83   1.1  christos 			break;
     84   1.1  christos 		default:
     85   1.1  christos 			goto done;
     86   1.1  christos 		}
     87   1.1  christos  done:
     88   1.1  christos 	if (cmd_start)
     89   1.1  christos 		*cmd_start = cp;
     90   1.1  christos 
     91   1.1  christos 	return flags;
     92   1.1  christos }
     93   1.1  christos 
     94   1.1  christos 
     95   1.1  christos static int
     96   1.1  christos prepare_pipe(sigset_t *nset, int p[2])
     97   1.1  christos {
     98   1.8  christos 	if (pipe2(p, O_CLOEXEC) == -1)
     99   1.1  christos 		return -1;
    100   1.1  christos 
    101   1.1  christos 	/*
    102   1.1  christos 	 * We _must_ ignore SIGINT and SIGPIPE or the child
    103   1.1  christos 	 * will end up in our earlier handlers.
    104   1.1  christos 	 */
    105   1.4  christos 	(void)sigemptyset(nset);
    106   1.4  christos 	(void)sigaddset(nset, SIGINT);
    107   1.4  christos 	(void)sigaddset(nset, SIGPIPE);
    108   1.5  christos 	(void)sigaddset(nset, SIGHUP);
    109   1.5  christos 	(void)sigaddset(nset, SIGTSTP);
    110   1.5  christos 	(void)sigaddset(nset, SIGTTOU);
    111   1.5  christos 	(void)sigaddset(nset, SIGTTIN);
    112   1.5  christos 
    113   1.1  christos 	return 0;
    114   1.1  christos }
    115   1.1  christos 
    116   1.1  christos 
    117   1.1  christos PUBLIC int
    118   1.1  christos mime_run_command(const char *cmd, FILE *fo)
    119   1.1  christos {
    120   1.1  christos 	sigset_t nset;
    121   1.1  christos 	FILE *nfo;
    122   1.1  christos 	pid_t pid;
    123   1.1  christos 	int p[2];
    124   1.1  christos 	int flags;
    125   1.1  christos 
    126   1.1  christos 	if (cmd == NULL)
    127   1.1  christos 		return 0;
    128   1.1  christos 
    129   1.1  christos 	flags = get_cmd_flags(cmd, &cmd);
    130   1.1  christos 	if (fo == NULL)		/* no output file, just return the flags! */
    131   1.1  christos 		return flags;
    132   1.1  christos 
    133   1.1  christos 	if ((flags & CMD_FLAG_SHELLCMD) != 0) {	/* run command under the shell */
    134   1.1  christos 		char *cp;
    135   1.1  christos 		char *shellcmd;
    136   1.3  christos 		if ((shellcmd = value(ENAME_SHELL)) == NULL)
    137   1.1  christos 			shellcmd = __UNCONST(_PATH_CSHELL);
    138   1.3  christos 		(void)sasprintf(&cp, "%s -c '%s'", shellcmd, cmd);
    139   1.3  christos 		cmd = cp;
    140   1.1  christos 	}
    141   1.1  christos 	if (prepare_pipe(&nset, p) != 0) {
    142   1.1  christos 		warn("mime_run_command: prepare_pipe");
    143   1.1  christos 		return flags;	/* XXX - this or -1? */
    144   1.1  christos 	}
    145   1.1  christos 	flush_files(fo, 0); /* flush fo, all registered files, and stdout */
    146   1.1  christos 
    147   1.1  christos 	switch (pid = start_command(cmd, &nset, p[READ], fileno(fo), NULL)) {
    148   1.1  christos 	case -1:	/* error */
    149   1.1  christos 		/* start_command already did a warn(). */
    150   1.1  christos 		warnx("mime_run_command: %s", cmd); /* tell a bit more */
    151   1.1  christos 		(void)close(p[READ]);
    152   1.1  christos 		(void)close(p[WRITE]);
    153   1.1  christos 		return flags;			/* XXX - this or -1? */
    154   1.1  christos 
    155   1.1  christos 	case 0:		/* child */
    156   1.1  christos 		assert(/*CONSTCOND*/ 0);	/* a real coding error! */
    157   1.1  christos 		/* NOTREACHED */
    158   1.1  christos 
    159   1.1  christos 	default:	/* parent */
    160   1.1  christos 		(void)close(p[READ]);
    161   1.6  christos 
    162  1.10  christos 		nfo = fdopen(p[WRITE], "we");
    163   1.1  christos 		if (nfo == NULL) {
    164   1.1  christos 			warn("mime_run_command: fdopen");
    165   1.1  christos 			(void)close(p[WRITE]);
    166   1.1  christos 			warn("fdopen");
    167   1.1  christos 			return flags;
    168   1.1  christos 		}
    169   1.1  christos 		register_file(nfo, 1, pid);
    170   1.1  christos 		return flags;
    171   1.1  christos 	}
    172   1.1  christos }
    173   1.1  christos 
    174   1.1  christos 
    175   1.1  christos PUBLIC void
    176   1.1  christos mime_run_function(void (*fn)(FILE *, FILE *, void *), FILE *fo, void *cookie)
    177   1.1  christos {
    178   1.1  christos 	sigset_t nset;
    179   1.1  christos 	FILE *nfo;
    180   1.1  christos 	pid_t pid;
    181   1.1  christos 	int p[2];
    182   1.6  christos 
    183   1.1  christos 	if (prepare_pipe(&nset, p) != 0) {
    184   1.1  christos 		warn("mime_run_function: pipe");
    185   1.1  christos 		return;
    186   1.1  christos 	}
    187   1.1  christos 	flush_files(fo, 0); /* flush fo, all registered files, and stdout */
    188   1.1  christos 
    189   1.1  christos 	switch (pid = fork()) {
    190   1.1  christos 	case -1:	/* error */
    191   1.1  christos 		warn("mime_run_function: fork");
    192   1.1  christos 		(void)close(p[READ]);
    193   1.1  christos 		(void)close(p[WRITE]);
    194   1.1  christos 		return;
    195   1.1  christos 
    196   1.1  christos 	case 0:		/* child */
    197   1.1  christos 		(void)close(p[WRITE]);
    198   1.1  christos 		prepare_child(&nset, p[READ], fileno(fo));
    199   1.1  christos 		fn(stdin, stdout, cookie);
    200   1.1  christos 		(void)fflush(stdout);
    201   1.1  christos 		_exit(0);
    202   1.1  christos 		/* NOTREACHED */
    203   1.1  christos 
    204   1.1  christos 	default:	/* parent */
    205   1.1  christos 		(void)close(p[READ]);
    206  1.10  christos 		nfo = fdopen(p[WRITE], "we");
    207   1.1  christos 		if (nfo == NULL) {
    208   1.1  christos 			warn("run_function: fdopen");
    209   1.1  christos 			(void)close(p[WRITE]);
    210   1.1  christos 			return;
    211   1.1  christos 		}
    212   1.1  christos 		register_file(nfo, 1, pid);
    213   1.1  christos 		return;
    214   1.1  christos 	}
    215   1.1  christos }
    216   1.1  christos 
    217   1.1  christos #endif /* MIME_SUPPORT */
    218