/* $NetBSD: mime_child.c,v 1.2 2006/10/31 20:07:32 christos Exp $ */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Anon Ymous. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifdef MIME_SUPPORT #include #ifndef __lint__ __RCSID("$NetBSD: mime_child.c,v 1.2 2006/10/31 20:07:32 christos Exp $"); #endif /* not __lint__ */ #include #include #include #include #include #include #include "def.h" #include "extern.h" #ifdef MIME_SUPPORT #include "mime.h" #include "mime_child.h" #endif /* * This module contains the core routines used by mime modules that * need to fork children. Nothing else in the mime modules should be * doing a pipe(), fork(), or a call to any popen functions that do. * These routines are tied to the file registry in popen.c and hence * share much of popen code. */ #define READ 0 #define WRITE 1 static int get_cmd_flags(const char *cmd, const char **cmd_start) { const char *cp; int flags; flags = 0; for (cp = cmd; cp && *cp; cp++) switch (*cp) { case '+': flags |= CMD_FLAG_ALTERNATIVE; break; case '-': flags |= CMD_FLAG_NO_DECODE; break; case '!': flags |= CMD_FLAG_SHELLCMD; break; default: goto done; } done: if (cmd_start) *cmd_start = cp; return flags; } static int prepare_pipe(sigset_t *nset, int p[2]) { if (pipe(p) == -1) return -1; (void)fcntl(p[READ], F_SETFD, FD_CLOEXEC); (void)fcntl(p[WRITE], F_SETFD, FD_CLOEXEC); /* * We _must_ ignore SIGINT and SIGPIPE or the child * will end up in our earlier handlers. */ (void)sigfillset(nset); /* XXX - ignore all of em? */ return 0; } PUBLIC int mime_run_command(const char *cmd, FILE *fo) { sigset_t nset; FILE *nfo; pid_t pid; int p[2]; int flags; if (cmd == NULL) return 0; flags = get_cmd_flags(cmd, &cmd); if (fo == NULL) /* no output file, just return the flags! */ return flags; if ((flags & CMD_FLAG_SHELLCMD) != 0) { /* run command under the shell */ char *cp; char *shellcmd; if ((shellcmd = value("SHELL")) == NULL) shellcmd = __UNCONST(_PATH_CSHELL); if (asprintf(&cp, "%s -c '%s'", shellcmd, cmd) == -1) warn("mime_run_command: asprintf"); else { cmd = savestr(cp); free(cp); } } if (prepare_pipe(&nset, p) != 0) { warn("mime_run_command: prepare_pipe"); return flags; /* XXX - this or -1? */ } flush_files(fo, 0); /* flush fo, all registered files, and stdout */ switch (pid = start_command(cmd, &nset, p[READ], fileno(fo), NULL)) { case -1: /* error */ /* start_command already did a warn(). */ warnx("mime_run_command: %s", cmd); /* tell a bit more */ (void)close(p[READ]); (void)close(p[WRITE]); return flags; /* XXX - this or -1? */ case 0: /* child */ assert(/*CONSTCOND*/ 0); /* a real coding error! */ /* NOTREACHED */ default: /* parent */ (void)close(p[READ]); nfo = fdopen(p[WRITE], "w"); if (nfo == NULL) { warn("mime_run_command: fdopen"); (void)close(p[WRITE]); warn("fdopen"); return flags; } register_file(nfo, 1, pid); return flags; } } PUBLIC void mime_run_function(void (*fn)(FILE *, FILE *, void *), FILE *fo, void *cookie) { sigset_t nset; FILE *nfo; pid_t pid; int p[2]; if (prepare_pipe(&nset, p) != 0) { warn("mime_run_function: pipe"); return; } flush_files(fo, 0); /* flush fo, all registered files, and stdout */ switch (pid = fork()) { case -1: /* error */ warn("mime_run_function: fork"); (void)close(p[READ]); (void)close(p[WRITE]); return; case 0: /* child */ (void)close(p[WRITE]); prepare_child(&nset, p[READ], fileno(fo)); fn(stdin, stdout, cookie); (void)fflush(stdout); _exit(0); /* NOTREACHED */ default: /* parent */ (void)close(p[READ]); nfo = fdopen(p[WRITE], "w"); if (nfo == NULL) { warn("run_function: fdopen"); (void)close(p[WRITE]); return; } register_file(nfo, 1, pid); return; } } #endif /* MIME_SUPPORT */