1*517295ddSchristos /* $NetBSD: mime_child.c,v 1.10 2019/12/14 20:21:43 christos Exp $ */
28207b28aSchristos
38207b28aSchristos /*-
48207b28aSchristos * Copyright (c) 2006 The NetBSD Foundation, Inc.
58207b28aSchristos * All rights reserved.
68207b28aSchristos *
78207b28aSchristos * This code is derived from software contributed to The NetBSD Foundation
88207b28aSchristos * by Anon Ymous.
98207b28aSchristos *
108207b28aSchristos * Redistribution and use in source and binary forms, with or without
118207b28aSchristos * modification, are permitted provided that the following conditions
128207b28aSchristos * are met:
138207b28aSchristos * 1. Redistributions of source code must retain the above copyright
148207b28aSchristos * notice, this list of conditions and the following disclaimer.
158207b28aSchristos * 2. Redistributions in binary form must reproduce the above copyright
168207b28aSchristos * notice, this list of conditions and the following disclaimer in the
178207b28aSchristos * documentation and/or other materials provided with the distribution.
188207b28aSchristos *
198207b28aSchristos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
208207b28aSchristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
218207b28aSchristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
228207b28aSchristos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
238207b28aSchristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
248207b28aSchristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
258207b28aSchristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
268207b28aSchristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
278207b28aSchristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
288207b28aSchristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
298207b28aSchristos * POSSIBILITY OF SUCH DAMAGE.
308207b28aSchristos */
318207b28aSchristos
328207b28aSchristos
338207b28aSchristos #ifdef MIME_SUPPORT
348207b28aSchristos
358207b28aSchristos #include <sys/cdefs.h>
368207b28aSchristos #ifndef __lint__
37*517295ddSchristos __RCSID("$NetBSD: mime_child.c,v 1.10 2019/12/14 20:21:43 christos Exp $");
388207b28aSchristos #endif /* not __lint__ */
398207b28aSchristos
408207b28aSchristos #include <assert.h>
418207b28aSchristos #include <fcntl.h>
428207b28aSchristos #include <signal.h>
438207b28aSchristos #include <stdio.h>
448207b28aSchristos #include <stdlib.h>
458207b28aSchristos #include <unistd.h>
468207b28aSchristos
478207b28aSchristos #include "def.h"
488207b28aSchristos #include "extern.h"
498207b28aSchristos
508207b28aSchristos #ifdef MIME_SUPPORT
518207b28aSchristos #include "mime.h"
528207b28aSchristos #include "mime_child.h"
538207b28aSchristos #endif
548207b28aSchristos
558207b28aSchristos /*
568207b28aSchristos * This module contains the core routines used by mime modules that
578207b28aSchristos * need to fork children. Nothing else in the mime modules should be
588207b28aSchristos * doing a pipe(), fork(), or a call to any popen functions that do.
598207b28aSchristos * These routines are tied to the file registry in popen.c and hence
608207b28aSchristos * share much of popen code.
618207b28aSchristos */
628207b28aSchristos
638207b28aSchristos #define READ 0
648207b28aSchristos #define WRITE 1
658207b28aSchristos
668207b28aSchristos static int
get_cmd_flags(const char * cmd,const char ** cmd_start)678207b28aSchristos get_cmd_flags(const char *cmd, const char **cmd_start)
688207b28aSchristos {
698207b28aSchristos const char *cp;
708207b28aSchristos int flags;
718207b28aSchristos
728207b28aSchristos flags = 0;
738207b28aSchristos for (cp = cmd; cp && *cp; cp++)
748207b28aSchristos switch (*cp) {
758207b28aSchristos case '+':
768207b28aSchristos flags |= CMD_FLAG_ALTERNATIVE;
778207b28aSchristos break;
788207b28aSchristos case '-':
798207b28aSchristos flags |= CMD_FLAG_NO_DECODE;
808207b28aSchristos break;
818207b28aSchristos case '!':
828207b28aSchristos flags |= CMD_FLAG_SHELLCMD;
838207b28aSchristos break;
848207b28aSchristos default:
858207b28aSchristos goto done;
868207b28aSchristos }
878207b28aSchristos done:
888207b28aSchristos if (cmd_start)
898207b28aSchristos *cmd_start = cp;
908207b28aSchristos
918207b28aSchristos return flags;
928207b28aSchristos }
938207b28aSchristos
948207b28aSchristos
958207b28aSchristos static int
prepare_pipe(sigset_t * nset,int p[2])968207b28aSchristos prepare_pipe(sigset_t *nset, int p[2])
978207b28aSchristos {
98674e12d2Schristos if (pipe2(p, O_CLOEXEC) == -1)
998207b28aSchristos return -1;
1008207b28aSchristos
1018207b28aSchristos /*
1028207b28aSchristos * We _must_ ignore SIGINT and SIGPIPE or the child
1038207b28aSchristos * will end up in our earlier handlers.
1048207b28aSchristos */
105c77cd738Schristos (void)sigemptyset(nset);
106c77cd738Schristos (void)sigaddset(nset, SIGINT);
107c77cd738Schristos (void)sigaddset(nset, SIGPIPE);
10875df0a78Schristos (void)sigaddset(nset, SIGHUP);
10975df0a78Schristos (void)sigaddset(nset, SIGTSTP);
11075df0a78Schristos (void)sigaddset(nset, SIGTTOU);
11175df0a78Schristos (void)sigaddset(nset, SIGTTIN);
11275df0a78Schristos
1138207b28aSchristos return 0;
1148207b28aSchristos }
1158207b28aSchristos
1168207b28aSchristos
1178207b28aSchristos PUBLIC int
mime_run_command(const char * cmd,FILE * fo)1188207b28aSchristos mime_run_command(const char *cmd, FILE *fo)
1198207b28aSchristos {
1208207b28aSchristos sigset_t nset;
1218207b28aSchristos FILE *nfo;
1228207b28aSchristos pid_t pid;
1238207b28aSchristos int p[2];
1248207b28aSchristos int flags;
1258207b28aSchristos
1268207b28aSchristos if (cmd == NULL)
1278207b28aSchristos return 0;
1288207b28aSchristos
1298207b28aSchristos flags = get_cmd_flags(cmd, &cmd);
1308207b28aSchristos if (fo == NULL) /* no output file, just return the flags! */
1318207b28aSchristos return flags;
1328207b28aSchristos
1338207b28aSchristos if ((flags & CMD_FLAG_SHELLCMD) != 0) { /* run command under the shell */
1348207b28aSchristos char *cp;
1358207b28aSchristos char *shellcmd;
136f3098750Schristos if ((shellcmd = value(ENAME_SHELL)) == NULL)
1378207b28aSchristos shellcmd = __UNCONST(_PATH_CSHELL);
138f3098750Schristos (void)sasprintf(&cp, "%s -c '%s'", shellcmd, cmd);
139f3098750Schristos cmd = cp;
1408207b28aSchristos }
1418207b28aSchristos if (prepare_pipe(&nset, p) != 0) {
1428207b28aSchristos warn("mime_run_command: prepare_pipe");
1438207b28aSchristos return flags; /* XXX - this or -1? */
1448207b28aSchristos }
1458207b28aSchristos flush_files(fo, 0); /* flush fo, all registered files, and stdout */
1468207b28aSchristos
1478207b28aSchristos switch (pid = start_command(cmd, &nset, p[READ], fileno(fo), NULL)) {
1488207b28aSchristos case -1: /* error */
1498207b28aSchristos /* start_command already did a warn(). */
1508207b28aSchristos warnx("mime_run_command: %s", cmd); /* tell a bit more */
1518207b28aSchristos (void)close(p[READ]);
1528207b28aSchristos (void)close(p[WRITE]);
1538207b28aSchristos return flags; /* XXX - this or -1? */
1548207b28aSchristos
1558207b28aSchristos case 0: /* child */
1568207b28aSchristos assert(/*CONSTCOND*/ 0); /* a real coding error! */
1578207b28aSchristos /* NOTREACHED */
1588207b28aSchristos
1598207b28aSchristos default: /* parent */
1608207b28aSchristos (void)close(p[READ]);
1618207b28aSchristos
162*517295ddSchristos nfo = fdopen(p[WRITE], "we");
1638207b28aSchristos if (nfo == NULL) {
1648207b28aSchristos warn("mime_run_command: fdopen");
1658207b28aSchristos (void)close(p[WRITE]);
1668207b28aSchristos warn("fdopen");
1678207b28aSchristos return flags;
1688207b28aSchristos }
1698207b28aSchristos register_file(nfo, 1, pid);
1708207b28aSchristos return flags;
1718207b28aSchristos }
1728207b28aSchristos }
1738207b28aSchristos
1748207b28aSchristos
1758207b28aSchristos PUBLIC void
mime_run_function(void (* fn)(FILE *,FILE *,void *),FILE * fo,void * cookie)1768207b28aSchristos mime_run_function(void (*fn)(FILE *, FILE *, void *), FILE *fo, void *cookie)
1778207b28aSchristos {
1788207b28aSchristos sigset_t nset;
1798207b28aSchristos FILE *nfo;
1808207b28aSchristos pid_t pid;
1818207b28aSchristos int p[2];
1828207b28aSchristos
1838207b28aSchristos if (prepare_pipe(&nset, p) != 0) {
1848207b28aSchristos warn("mime_run_function: pipe");
1858207b28aSchristos return;
1868207b28aSchristos }
1878207b28aSchristos flush_files(fo, 0); /* flush fo, all registered files, and stdout */
1888207b28aSchristos
1898207b28aSchristos switch (pid = fork()) {
1908207b28aSchristos case -1: /* error */
1918207b28aSchristos warn("mime_run_function: fork");
1928207b28aSchristos (void)close(p[READ]);
1938207b28aSchristos (void)close(p[WRITE]);
1948207b28aSchristos return;
1958207b28aSchristos
1968207b28aSchristos case 0: /* child */
1978207b28aSchristos (void)close(p[WRITE]);
1988207b28aSchristos prepare_child(&nset, p[READ], fileno(fo));
1998207b28aSchristos fn(stdin, stdout, cookie);
2008207b28aSchristos (void)fflush(stdout);
2018207b28aSchristos _exit(0);
2028207b28aSchristos /* NOTREACHED */
2038207b28aSchristos
2048207b28aSchristos default: /* parent */
2058207b28aSchristos (void)close(p[READ]);
206*517295ddSchristos nfo = fdopen(p[WRITE], "we");
2078207b28aSchristos if (nfo == NULL) {
2088207b28aSchristos warn("run_function: fdopen");
2098207b28aSchristos (void)close(p[WRITE]);
2108207b28aSchristos return;
2118207b28aSchristos }
2128207b28aSchristos register_file(nfo, 1, pid);
2138207b28aSchristos return;
2148207b28aSchristos }
2158207b28aSchristos }
2168207b28aSchristos
2178207b28aSchristos #endif /* MIME_SUPPORT */
218