/*-1* Copyright (c) 2013-2018 Devin Teske <[email protected]>2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#include <sys/cdefs.h>27#include <err.h>28#include <limits.h>29#include <spawn.h>30#include <stdio.h>31#include <stdlib.h>32#include <unistd.h>3334#include "util.h"3536extern char **environ;37static char cmdbuf[CMDBUFMAX] = "";38static char shellcmd[PATH_MAX] = PATH_SHELL;39static char *shellcmd_argv[6] = {40shellcmd,41__DECONST(char *, "-c"),42cmdbuf,43__DECONST(char *, "--"),44shellcmd,45NULL,46};4748/*49* Spawn a sh(1) command. Writes the resulting process ID to the pid_t pointed50* at by `pid'. Returns a file descriptor (int) suitable for writing data to51* the spawned command (data written to file descriptor is seen as standard-in52* by the spawned sh(1) command). Returns `-1' if unable to spawn command.53*54* If cmd contains a single "%s" sequence, replace it with label if non-NULL.55*/56int57shell_spawn_pipecmd(const char *cmd, const char *label, pid_t *pid)58{59int error;60int len;61posix_spawn_file_actions_t action;62#if SHELL_SPAWN_DEBUG63unsigned int i;64#endif65int stdin_pipe[2] = { -1, -1 };6667/* Populate argument array */68if (label != NULL && fmtcheck(cmd, "%s") == cmd)69len = snprintf(cmdbuf, CMDBUFMAX, cmd, label);70else71len = snprintf(cmdbuf, CMDBUFMAX, "%s", cmd);72if (len >= CMDBUFMAX) {73warnx("%s:%d:%s: cmdbuf[%u] too small to hold cmd argument",74__FILE__, __LINE__, __func__, CMDBUFMAX);75return (-1);76}7778/* Open a pipe to communicate with [X]dialog(1) */79if (pipe(stdin_pipe) < 0)80err(EXIT_FAILURE, "%s: pipe(2)", __func__);8182/* Fork sh(1) process */83#if SHELL_SPAWN_DEBUG84fprintf(stderr, "%s: spawning `", __func__);85for (i = 0; shellcmd_argv[i] != NULL; i++) {86if (i == 0)87fprintf(stderr, "%s", shellcmd_argv[i]);88else if (i == 2)89fprintf(stderr, " '%s'", shellcmd_argv[i]);90else91fprintf(stderr, " %s", shellcmd_argv[i]);92}93fprintf(stderr, "'\n");94#endif95posix_spawn_file_actions_init(&action);96posix_spawn_file_actions_adddup2(&action, stdin_pipe[0], STDIN_FILENO);97posix_spawn_file_actions_addclose(&action, stdin_pipe[1]);98error = posix_spawnp(pid, shellcmd, &action,99(const posix_spawnattr_t *)NULL, shellcmd_argv, environ);100if (error != 0) err(EXIT_FAILURE, "%s", shellcmd);101102return stdin_pipe[1];103}104105106