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
);