2 * Unix SMB/CIFS implementation.
3 * Samba system utilities
4 * Copyright (C) Jeremy Allison 2000
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "system/wait.h"
22 #include "system/filesys.h"
24 #include "lib/sys_popen.h"
25 #include "lib/util/debug.h"
27 /**************************************************************************
28 Extract a command into an arg list.
29 ****************************************************************************/
31 static char **extract_args(TALLOC_CTX *mem_ctx, const char *command)
40 if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
41 DEBUG(0, ("talloc failed\n"));
45 if(!(ptr = strtok_r(trunc_cmd, " \t", &saveptr))) {
46 TALLOC_FREE(trunc_cmd);
55 for( argcl = 1; ptr; ptr = strtok_r(NULL, " \t", &saveptr))
58 TALLOC_FREE(trunc_cmd);
60 if (!(argl = talloc_array(mem_ctx, char *, argcl + 1))) {
65 * Now do the extraction.
68 if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
72 ptr = strtok_r(trunc_cmd, " \t", &saveptr);
75 if (!(argl[i++] = talloc_strdup(argl, ptr))) {
79 while((ptr = strtok_r(NULL, " \t", &saveptr)) != NULL) {
81 if (!(argl[i++] = talloc_strdup(argl, ptr))) {
87 TALLOC_FREE(trunc_cmd);
91 DEBUG(0, ("talloc failed\n"));
92 TALLOC_FREE(trunc_cmd);
98 /**************************************************************************
99 Wrapper for popen. Safer as it doesn't search a path.
100 Modified from the glibc sources.
101 modified by tridge to return a file descriptor. We must kick our FILE* habit
102 ****************************************************************************/
104 typedef struct _popen_list
108 struct _popen_list *next;
111 static popen_list *popen_chain;
113 int sys_popen(const char *command)
115 int parent_end, child_end;
117 popen_list *entry = NULL;
126 ret = pipe(pipe_fds);
128 DEBUG(0, ("sys_popen: error opening pipe: %s\n",
133 parent_end = pipe_fds[0];
134 child_end = pipe_fds[1];
136 entry = talloc_zero(NULL, popen_list);
138 DEBUG(0, ("sys_popen: malloc failed\n"));
143 * Extract the command and args into a NULL terminated array.
146 argl = extract_args(NULL, command);
148 DEBUG(0, ("sys_popen: extract_args() failed: %s\n", strerror(errno)));
152 entry->child_pid = fork();
154 if (entry->child_pid == -1) {
155 DEBUG(0, ("sys_popen: fork failed: %s\n", strerror(errno)));
159 if (entry->child_pid == 0) {
165 int child_std_end = STDOUT_FILENO;
169 if (child_end != child_std_end) {
170 dup2 (child_end, child_std_end);
175 * POSIX.2: "popen() shall ensure that any streams from previous
176 * popen() calls that remain open in the parent process are closed
177 * in the new child process."
180 for (p = popen_chain; p; p = p->next)
183 ret = execv(argl[0], argl);
185 DEBUG(0, ("sys_popen: ERROR executing command "
186 "'%s': %s\n", command, strerror(errno)));
198 /* Link into popen_chain. */
199 entry->next = popen_chain;
201 entry->fd = parent_end;
214 /**************************************************************************
215 Wrapper for pclose. Modified from the glibc sources.
216 ****************************************************************************/
218 int sys_pclose(int fd)
221 popen_list **ptr = &popen_chain;
222 popen_list *entry = NULL;
226 /* Unlink from popen_chain. */
227 for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
228 if ((*ptr)->fd == fd) {
236 if (status < 0 || close(entry->fd) < 0)
240 * As Samba is catching and eating child process
241 * exits we don't really care about the child exit
242 * code, a -1 with errno = ECHILD will do fine for us.
246 wait_pid = waitpid (entry->child_pid, &wstatus, 0);
247 } while (wait_pid == -1 && errno == EINTR);