fexec.c revision 1.1
1/*-
2 * Copyright (c) 2003 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Matthias Scheler.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30
31#if HAVE_CONFIG_H
32#include "config.h"
33#endif
34#include <nbcompat.h>
35#if HAVE_SYS_CDEFS_H
36#include <sys/cdefs.h>
37#endif
38#if HAVE_SYS_WAIT_H
39#include <sys/wait.h>
40#endif
41
42#if HAVE_ERR_H
43#include <err.h>
44#endif
45#if HAVE_ERRNO_H
46#include <errno.h>
47#endif
48#if HAVE_STDARG_H
49#include <stdarg.h>
50#endif
51#if HAVE_STDLIB_H
52#include <stdlib.h>
53#endif
54#if HAVE_UNISTD_H
55#include <unistd.h>
56#endif
57
58#include "lib.h"
59
60#ifndef lint
61__RCSID("$NetBSD: fexec.c,v 1.1 2008/09/30 19:00:27 joerg Exp $");
62#endif
63
64static int	vfcexec(const char *, int, const char *, va_list);
65
66/*
67 * fork, then change current working directory to path and
68 * execute the command and arguments in the argv array.
69 * wait for the command to finish, then return the exit status.
70 */
71int
72pfcexec(const char *path, const char *file, const char **argv)
73{
74	pid_t			child;
75	int			status;
76
77	child = vfork();
78	switch (child) {
79	case 0:
80		if ((path != NULL) && (chdir(path) < 0))
81			_exit(127);
82
83		(void)execvp(file, (char ** const)argv);
84		_exit(127);
85		/* NOTREACHED */
86	case -1:
87		return -1;
88	}
89
90	while (waitpid(child, &status, 0) < 0) {
91		if (errno != EINTR)
92			return -1;
93	}
94
95	if (!WIFEXITED(status))
96		return -1;
97
98	return WEXITSTATUS(status);
99}
100
101static int
102vfcexec(const char *path, int skipempty, const char *arg, va_list ap)
103{
104	const char **argv;
105	size_t argv_size, argc;
106	int retval;
107
108	argv_size = 16;
109	if ((argv = malloc(argv_size * sizeof(*argv))) == NULL)
110		err(EXIT_FAILURE, "vfcexec: malloc failed");
111
112	argv[0] = arg;
113	argc = 1;
114
115	do {
116		if (argc == argv_size) {
117			argv_size *= 2;
118			argv = realloc(argv, argv_size * sizeof(*argv));
119			if (argv == NULL)
120				err(EXIT_FAILURE, "vfcexec: realloc failed");
121		}
122		arg = va_arg(ap, const char *);
123		if (skipempty && arg && strlen(arg) == 0)
124		    continue;
125		argv[argc++] = arg;
126	} while (arg != NULL);
127
128	retval = pfcexec(path, argv[0], argv);
129	free(argv);
130	return retval;
131}
132
133int
134fexec(const char *arg, ...)
135{
136	va_list	ap;
137	int	result;
138
139	va_start(ap, arg);
140	result = vfcexec(NULL, 0, arg, ap);
141	va_end(ap);
142
143	return result;
144}
145
146int
147fexec_skipempty(const char *arg, ...)
148{
149	va_list	ap;
150	int	result;
151
152	va_start(ap, arg);
153	result = vfcexec(NULL, 1, arg, ap);
154	va_end(ap);
155
156	return result;
157}
158
159int
160fcexec(const char *path, const char *arg, ...)
161{
162	va_list	ap;
163	int	result;
164
165	va_start(ap, arg);
166	result = vfcexec(path, 0, arg, ap);
167	va_end(ap);
168
169	return result;
170}
171