xref: /freebsd/lib/libdpv/util.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
1041394f3SDevin Teske /*-
2*cfeecda0SDevin Teske  * Copyright (c) 2013-2018 Devin Teske <dteske@FreeBSD.org>
3041394f3SDevin Teske  * All rights reserved.
4041394f3SDevin Teske  *
5041394f3SDevin Teske  * Redistribution and use in source and binary forms, with or without
6041394f3SDevin Teske  * modification, are permitted provided that the following conditions
7041394f3SDevin Teske  * are met:
8041394f3SDevin Teske  * 1. Redistributions of source code must retain the above copyright
9041394f3SDevin Teske  *    notice, this list of conditions and the following disclaimer.
10041394f3SDevin Teske  * 2. Redistributions in binary form must reproduce the above copyright
11041394f3SDevin Teske  *    notice, this list of conditions and the following disclaimer in the
12041394f3SDevin Teske  *    documentation and/or other materials provided with the distribution.
13041394f3SDevin Teske  *
14041394f3SDevin Teske  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15041394f3SDevin Teske  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16041394f3SDevin Teske  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17041394f3SDevin Teske  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18041394f3SDevin Teske  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19041394f3SDevin Teske  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20041394f3SDevin Teske  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21041394f3SDevin Teske  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22041394f3SDevin Teske  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23041394f3SDevin Teske  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24041394f3SDevin Teske  * SUCH DAMAGE.
25041394f3SDevin Teske  */
26041394f3SDevin Teske 
27041394f3SDevin Teske #include <sys/cdefs.h>
28041394f3SDevin Teske #include <err.h>
29041394f3SDevin Teske #include <limits.h>
30041394f3SDevin Teske #include <spawn.h>
31041394f3SDevin Teske #include <stdio.h>
32041394f3SDevin Teske #include <stdlib.h>
33041394f3SDevin Teske #include <unistd.h>
34041394f3SDevin Teske 
35041394f3SDevin Teske #include "util.h"
36041394f3SDevin Teske 
37041394f3SDevin Teske extern char **environ;
38041394f3SDevin Teske static char cmdbuf[CMDBUFMAX]	= "";
39041394f3SDevin Teske static char shellcmd[PATH_MAX]	= PATH_SHELL;
40041394f3SDevin Teske static char *shellcmd_argv[6]	= {
41041394f3SDevin Teske 	shellcmd,
42041394f3SDevin Teske 	__DECONST(char *, "-c"),
43041394f3SDevin Teske 	cmdbuf,
44041394f3SDevin Teske 	__DECONST(char *, "--"),
45041394f3SDevin Teske 	shellcmd,
46041394f3SDevin Teske 	NULL,
47041394f3SDevin Teske };
48041394f3SDevin Teske 
49041394f3SDevin Teske /*
50041394f3SDevin Teske  * Spawn a sh(1) command. Writes the resulting process ID to the pid_t pointed
51041394f3SDevin Teske  * at by `pid'. Returns a file descriptor (int) suitable for writing data to
52041394f3SDevin Teske  * the spawned command (data written to file descriptor is seen as standard-in
53041394f3SDevin Teske  * by the spawned sh(1) command). Returns `-1' if unable to spawn command.
54041394f3SDevin Teske  *
55041394f3SDevin Teske  * If cmd contains a single "%s" sequence, replace it with label if non-NULL.
56041394f3SDevin Teske  */
57041394f3SDevin Teske int
shell_spawn_pipecmd(const char * cmd,const char * label,pid_t * pid)58041394f3SDevin Teske shell_spawn_pipecmd(const char *cmd, const char *label, pid_t *pid)
59041394f3SDevin Teske {
60041394f3SDevin Teske 	int error;
61041394f3SDevin Teske 	int len;
62041394f3SDevin Teske 	posix_spawn_file_actions_t action;
63041394f3SDevin Teske #if SHELL_SPAWN_DEBUG
64041394f3SDevin Teske 	unsigned int i;
65041394f3SDevin Teske #endif
66041394f3SDevin Teske 	int stdin_pipe[2] = { -1, -1 };
67041394f3SDevin Teske 
68041394f3SDevin Teske 	/* Populate argument array */
69041394f3SDevin Teske 	if (label != NULL && fmtcheck(cmd, "%s") == cmd)
70041394f3SDevin Teske 		len = snprintf(cmdbuf, CMDBUFMAX, cmd, label);
71041394f3SDevin Teske 	else
72041394f3SDevin Teske 		len = snprintf(cmdbuf, CMDBUFMAX, "%s", cmd);
73041394f3SDevin Teske 	if (len >= CMDBUFMAX) {
74041394f3SDevin Teske 		warnx("%s:%d:%s: cmdbuf[%u] too small to hold cmd argument",
75041394f3SDevin Teske 		    __FILE__, __LINE__, __func__, CMDBUFMAX);
76041394f3SDevin Teske 		return (-1);
77041394f3SDevin Teske 	}
78041394f3SDevin Teske 
79041394f3SDevin Teske 	/* Open a pipe to communicate with [X]dialog(1) */
80041394f3SDevin Teske 	if (pipe(stdin_pipe) < 0)
81041394f3SDevin Teske 		err(EXIT_FAILURE, "%s: pipe(2)", __func__);
82041394f3SDevin Teske 
83041394f3SDevin Teske 	/* Fork sh(1) process */
84041394f3SDevin Teske #if SHELL_SPAWN_DEBUG
85041394f3SDevin Teske 	fprintf(stderr, "%s: spawning `", __func__);
86041394f3SDevin Teske 	for (i = 0; shellcmd_argv[i] != NULL; i++) {
87041394f3SDevin Teske 		if (i == 0)
88041394f3SDevin Teske 			fprintf(stderr, "%s", shellcmd_argv[i]);
89041394f3SDevin Teske 		else if (i == 2)
90041394f3SDevin Teske 			fprintf(stderr, " '%s'", shellcmd_argv[i]);
91041394f3SDevin Teske 		else
92041394f3SDevin Teske 			fprintf(stderr, " %s", shellcmd_argv[i]);
93041394f3SDevin Teske 	}
94041394f3SDevin Teske 	fprintf(stderr, "'\n");
95041394f3SDevin Teske #endif
96041394f3SDevin Teske 	posix_spawn_file_actions_init(&action);
97041394f3SDevin Teske 	posix_spawn_file_actions_adddup2(&action, stdin_pipe[0], STDIN_FILENO);
98041394f3SDevin Teske 	posix_spawn_file_actions_addclose(&action, stdin_pipe[1]);
99041394f3SDevin Teske 	error = posix_spawnp(pid, shellcmd, &action,
100041394f3SDevin Teske 	    (const posix_spawnattr_t *)NULL, shellcmd_argv, environ);
101*cfeecda0SDevin Teske 	if (error != 0) err(EXIT_FAILURE, "%s", shellcmd);
102041394f3SDevin Teske 
103041394f3SDevin Teske 	return stdin_pipe[1];
104041394f3SDevin Teske }
105