xref: /freebsd/usr.sbin/autofs/popen.c (revision 4d65a7c6951cea0333f1a0c1b32c38489cdfa6c5)
13914ddf8SEdward Tomasz Napierala /*
2*abdd3945SEdward Tomasz Napierala  * SPDX-License-Identifier: BSD-3-Clause
3*abdd3945SEdward Tomasz Napierala  *
43914ddf8SEdward Tomasz Napierala  * Copyright (c) 1988, 1993
53914ddf8SEdward Tomasz Napierala  *	The Regents of the University of California.  All rights reserved.
63914ddf8SEdward Tomasz Napierala  * Copyright (c) 2014 The FreeBSD Foundation
73914ddf8SEdward Tomasz Napierala  * All rights reserved.
83914ddf8SEdward Tomasz Napierala  *
93914ddf8SEdward Tomasz Napierala  * This code is derived from software written by Ken Arnold and
103914ddf8SEdward Tomasz Napierala  * published in UNIX Review, Vol. 6, No. 8.
113914ddf8SEdward Tomasz Napierala  *
123914ddf8SEdward Tomasz Napierala  * Portions of this software were developed by Edward Tomasz Napierala
133914ddf8SEdward Tomasz Napierala  * under sponsorship from the FreeBSD Foundation.
143914ddf8SEdward Tomasz Napierala  *
153914ddf8SEdward Tomasz Napierala  * Redistribution and use in source and binary forms, with or without
163914ddf8SEdward Tomasz Napierala  * modification, are permitted provided that the following conditions
173914ddf8SEdward Tomasz Napierala  * are met:
183914ddf8SEdward Tomasz Napierala  * 1. Redistributions of source code must retain the above copyright
193914ddf8SEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer.
203914ddf8SEdward Tomasz Napierala  * 2. Redistributions in binary form must reproduce the above copyright
213914ddf8SEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer in the
223914ddf8SEdward Tomasz Napierala  *    documentation and/or other materials provided with the distribution.
23fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
243914ddf8SEdward Tomasz Napierala  *    may be used to endorse or promote products derived from this software
253914ddf8SEdward Tomasz Napierala  *    without specific prior written permission.
263914ddf8SEdward Tomasz Napierala  *
273914ddf8SEdward Tomasz Napierala  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
283914ddf8SEdward Tomasz Napierala  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
293914ddf8SEdward Tomasz Napierala  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
303914ddf8SEdward Tomasz Napierala  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
313914ddf8SEdward Tomasz Napierala  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
323914ddf8SEdward Tomasz Napierala  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
333914ddf8SEdward Tomasz Napierala  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
343914ddf8SEdward Tomasz Napierala  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
353914ddf8SEdward Tomasz Napierala  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
363914ddf8SEdward Tomasz Napierala  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
373914ddf8SEdward Tomasz Napierala  * SUCH DAMAGE.
383914ddf8SEdward Tomasz Napierala  *
393914ddf8SEdward Tomasz Napierala  */
403914ddf8SEdward Tomasz Napierala 
413914ddf8SEdward Tomasz Napierala #include <sys/param.h>
423914ddf8SEdward Tomasz Napierala #include <sys/queue.h>
433914ddf8SEdward Tomasz Napierala #include <sys/wait.h>
443914ddf8SEdward Tomasz Napierala 
453914ddf8SEdward Tomasz Napierala #include <errno.h>
463914ddf8SEdward Tomasz Napierala #include <fcntl.h>
473914ddf8SEdward Tomasz Napierala #include <unistd.h>
483914ddf8SEdward Tomasz Napierala #include <stdarg.h>
493914ddf8SEdward Tomasz Napierala #include <stdio.h>
503914ddf8SEdward Tomasz Napierala #include <stdlib.h>
513914ddf8SEdward Tomasz Napierala #include <string.h>
523914ddf8SEdward Tomasz Napierala #include <paths.h>
533914ddf8SEdward Tomasz Napierala 
543914ddf8SEdward Tomasz Napierala #include "common.h"
553914ddf8SEdward Tomasz Napierala 
563914ddf8SEdward Tomasz Napierala extern char **environ;
573914ddf8SEdward Tomasz Napierala 
583914ddf8SEdward Tomasz Napierala struct pid {
593914ddf8SEdward Tomasz Napierala 	SLIST_ENTRY(pid) next;
603914ddf8SEdward Tomasz Napierala 	FILE *outfp;
613914ddf8SEdward Tomasz Napierala 	pid_t pid;
623914ddf8SEdward Tomasz Napierala 	char *command;
633914ddf8SEdward Tomasz Napierala };
643914ddf8SEdward Tomasz Napierala static SLIST_HEAD(, pid) pidlist = SLIST_HEAD_INITIALIZER(pidlist);
653914ddf8SEdward Tomasz Napierala 
663914ddf8SEdward Tomasz Napierala #define	ARGV_LEN	42
673914ddf8SEdward Tomasz Napierala 
683914ddf8SEdward Tomasz Napierala /*
693914ddf8SEdward Tomasz Napierala  * Replacement for popen(3), without stdin (which we do not use), but with
703914ddf8SEdward Tomasz Napierala  * stderr, proper logging, and improved command line arguments passing.
713914ddf8SEdward Tomasz Napierala  * Error handling is built in - if it returns, then it succeeded.
723914ddf8SEdward Tomasz Napierala  */
733914ddf8SEdward Tomasz Napierala FILE *
auto_popen(const char * argv0,...)743914ddf8SEdward Tomasz Napierala auto_popen(const char *argv0, ...)
753914ddf8SEdward Tomasz Napierala {
763914ddf8SEdward Tomasz Napierala 	va_list ap;
773914ddf8SEdward Tomasz Napierala 	struct pid *cur, *p;
783914ddf8SEdward Tomasz Napierala 	pid_t pid;
793914ddf8SEdward Tomasz Napierala 	int error, i, nullfd, outfds[2];
803914ddf8SEdward Tomasz Napierala 	char *arg, *argv[ARGV_LEN], *command;
813914ddf8SEdward Tomasz Napierala 
823914ddf8SEdward Tomasz Napierala 	nullfd = open(_PATH_DEVNULL, O_RDWR, 0);
833914ddf8SEdward Tomasz Napierala 	if (nullfd < 0)
843914ddf8SEdward Tomasz Napierala 		log_err(1, "cannot open %s", _PATH_DEVNULL);
853914ddf8SEdward Tomasz Napierala 
863914ddf8SEdward Tomasz Napierala 	error = pipe(outfds);
873914ddf8SEdward Tomasz Napierala 	if (error != 0)
883914ddf8SEdward Tomasz Napierala 		log_err(1, "pipe");
893914ddf8SEdward Tomasz Napierala 
903914ddf8SEdward Tomasz Napierala 	cur = malloc(sizeof(struct pid));
913914ddf8SEdward Tomasz Napierala 	if (cur == NULL)
923914ddf8SEdward Tomasz Napierala 		log_err(1, "malloc");
933914ddf8SEdward Tomasz Napierala 
943914ddf8SEdward Tomasz Napierala 	argv[0] = checked_strdup(argv0);
953914ddf8SEdward Tomasz Napierala 	command = argv[0];
963914ddf8SEdward Tomasz Napierala 
973914ddf8SEdward Tomasz Napierala 	va_start(ap, argv0);
983914ddf8SEdward Tomasz Napierala 	for (i = 1;; i++) {
993914ddf8SEdward Tomasz Napierala 		if (i >= ARGV_LEN)
1003914ddf8SEdward Tomasz Napierala 			log_errx(1, "too many arguments to auto_popen");
1013914ddf8SEdward Tomasz Napierala 		arg = va_arg(ap, char *);
1023914ddf8SEdward Tomasz Napierala 		argv[i] = arg;
1033914ddf8SEdward Tomasz Napierala 		if (arg == NULL)
1043914ddf8SEdward Tomasz Napierala 			break;
1053914ddf8SEdward Tomasz Napierala 
1066d8e60c3SEdward Tomasz Napierala 		command = concat(command, ' ', arg);
1073914ddf8SEdward Tomasz Napierala 	}
1083914ddf8SEdward Tomasz Napierala 	va_end(ap);
1093914ddf8SEdward Tomasz Napierala 
1103914ddf8SEdward Tomasz Napierala 	cur->command = checked_strdup(command);
1113914ddf8SEdward Tomasz Napierala 
1123914ddf8SEdward Tomasz Napierala 	switch (pid = fork()) {
1133914ddf8SEdward Tomasz Napierala 	case -1:			/* Error. */
1143914ddf8SEdward Tomasz Napierala 		log_err(1, "fork");
1153914ddf8SEdward Tomasz Napierala 		/* NOTREACHED */
1163914ddf8SEdward Tomasz Napierala 	case 0:				/* Child. */
1173914ddf8SEdward Tomasz Napierala 		dup2(nullfd, STDIN_FILENO);
1183914ddf8SEdward Tomasz Napierala 		dup2(outfds[1], STDOUT_FILENO);
1193914ddf8SEdward Tomasz Napierala 
1203914ddf8SEdward Tomasz Napierala 		close(nullfd);
1213914ddf8SEdward Tomasz Napierala 		close(outfds[0]);
1223914ddf8SEdward Tomasz Napierala 		close(outfds[1]);
1233914ddf8SEdward Tomasz Napierala 
1243914ddf8SEdward Tomasz Napierala 		SLIST_FOREACH(p, &pidlist, next)
1253914ddf8SEdward Tomasz Napierala 			close(fileno(p->outfp));
1263914ddf8SEdward Tomasz Napierala 		execvp(argv[0], argv);
1273914ddf8SEdward Tomasz Napierala 		log_err(1, "failed to execute %s", argv[0]);
1283914ddf8SEdward Tomasz Napierala 		/* NOTREACHED */
1293914ddf8SEdward Tomasz Napierala 	}
1303914ddf8SEdward Tomasz Napierala 
1313914ddf8SEdward Tomasz Napierala 	log_debugx("executing \"%s\" as pid %d", command, pid);
1323914ddf8SEdward Tomasz Napierala 
1333914ddf8SEdward Tomasz Napierala 	/* Parent; assume fdopen cannot fail. */
1343914ddf8SEdward Tomasz Napierala 	cur->outfp = fdopen(outfds[0], "r");
1353914ddf8SEdward Tomasz Napierala 	close(nullfd);
1363914ddf8SEdward Tomasz Napierala 	close(outfds[1]);
1373914ddf8SEdward Tomasz Napierala 
1383914ddf8SEdward Tomasz Napierala 	/* Link into list of file descriptors. */
1393914ddf8SEdward Tomasz Napierala 	cur->pid = pid;
1403914ddf8SEdward Tomasz Napierala 	SLIST_INSERT_HEAD(&pidlist, cur, next);
1413914ddf8SEdward Tomasz Napierala 
1423914ddf8SEdward Tomasz Napierala 	return (cur->outfp);
1433914ddf8SEdward Tomasz Napierala }
1443914ddf8SEdward Tomasz Napierala 
1453914ddf8SEdward Tomasz Napierala int
auto_pclose(FILE * iop)1463914ddf8SEdward Tomasz Napierala auto_pclose(FILE *iop)
1473914ddf8SEdward Tomasz Napierala {
1483914ddf8SEdward Tomasz Napierala 	struct pid *cur, *last = NULL;
1493914ddf8SEdward Tomasz Napierala 	int status;
1503914ddf8SEdward Tomasz Napierala 	pid_t pid;
1513914ddf8SEdward Tomasz Napierala 
1523914ddf8SEdward Tomasz Napierala 	/*
1533914ddf8SEdward Tomasz Napierala 	 * Find the appropriate file pointer and remove it from the list.
1543914ddf8SEdward Tomasz Napierala 	 */
1553914ddf8SEdward Tomasz Napierala 	SLIST_FOREACH(cur, &pidlist, next) {
1563914ddf8SEdward Tomasz Napierala 		if (cur->outfp == iop)
1573914ddf8SEdward Tomasz Napierala 			break;
1583914ddf8SEdward Tomasz Napierala 		last = cur;
1593914ddf8SEdward Tomasz Napierala 	}
1603914ddf8SEdward Tomasz Napierala 	if (cur == NULL) {
1613914ddf8SEdward Tomasz Napierala 		return (-1);
1623914ddf8SEdward Tomasz Napierala 	}
1633914ddf8SEdward Tomasz Napierala 	if (last == NULL)
1643914ddf8SEdward Tomasz Napierala 		SLIST_REMOVE_HEAD(&pidlist, next);
1653914ddf8SEdward Tomasz Napierala 	else
1663914ddf8SEdward Tomasz Napierala 		SLIST_REMOVE_AFTER(last, next);
1673914ddf8SEdward Tomasz Napierala 
1683914ddf8SEdward Tomasz Napierala 	fclose(cur->outfp);
1693914ddf8SEdward Tomasz Napierala 
1703914ddf8SEdward Tomasz Napierala 	do {
1713914ddf8SEdward Tomasz Napierala 		pid = wait4(cur->pid, &status, 0, NULL);
1723914ddf8SEdward Tomasz Napierala 	} while (pid == -1 && errno == EINTR);
1733914ddf8SEdward Tomasz Napierala 
1743914ddf8SEdward Tomasz Napierala 	if (WIFSIGNALED(status)) {
1753914ddf8SEdward Tomasz Napierala 		log_warnx("\"%s\", pid %d, terminated with signal %d",
1763914ddf8SEdward Tomasz Napierala 		    cur->command, pid, WTERMSIG(status));
1773914ddf8SEdward Tomasz Napierala 		return (status);
1783914ddf8SEdward Tomasz Napierala 	}
1793914ddf8SEdward Tomasz Napierala 
1803914ddf8SEdward Tomasz Napierala 	if (WEXITSTATUS(status) != 0) {
1813914ddf8SEdward Tomasz Napierala 		log_warnx("\"%s\", pid %d, terminated with exit status %d",
1823914ddf8SEdward Tomasz Napierala 		    cur->command, pid, WEXITSTATUS(status));
1833914ddf8SEdward Tomasz Napierala 		return (status);
1843914ddf8SEdward Tomasz Napierala 	}
1853914ddf8SEdward Tomasz Napierala 
1863914ddf8SEdward Tomasz Napierala 	log_debugx("\"%s\", pid %d, terminated gracefully", cur->command, pid);
1873914ddf8SEdward Tomasz Napierala 
1883914ddf8SEdward Tomasz Napierala 	free(cur->command);
1893914ddf8SEdward Tomasz Napierala 	free(cur);
1903914ddf8SEdward Tomasz Napierala 
1913914ddf8SEdward Tomasz Napierala 	return (pid == -1 ? -1 : status);
1923914ddf8SEdward Tomasz Napierala }
193