s3: tests: Add new test_stream_dir_rename.sh test.
[Samba.git] / lib / util / sys_popen.c
blobf62199b42ffe0cdbdd0da1521e960432257044ae
1 /*
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/>.
20 #include "replace.h"
21 #include "system/wait.h"
22 #include "system/filesys.h"
23 #include <talloc.h>
24 #include "lib/util/sys_popen.h"
25 #include "lib/util/debug.h"
27 /**************************************************************************
28 Wrapper for popen. Safer as it doesn't search a path.
29 Modified from the glibc sources.
30 modified by tridge to return a file descriptor. We must kick our FILE* habit
31 ****************************************************************************/
33 typedef struct _popen_list
35 int fd;
36 pid_t child_pid;
37 struct _popen_list *next;
38 } popen_list;
40 static popen_list *popen_chain;
42 int sys_popenv(char * const argl[])
44 int parent_end, child_end;
45 int pipe_fds[2];
46 popen_list *entry = NULL;
47 const char *command = NULL;
48 int ret;
50 if (argl == NULL) {
51 errno = EINVAL;
52 return -1;
54 command = argl[0];
56 if (!*command) {
57 errno = EINVAL;
58 return -1;
61 ret = pipe(pipe_fds);
62 if (ret < 0) {
63 DBG_ERR("error opening pipe: %s\n",
64 strerror(errno));
65 return -1;
68 parent_end = pipe_fds[0];
69 child_end = pipe_fds[1];
71 entry = talloc_zero(NULL, popen_list);
72 if (entry == NULL) {
73 DBG_ERR("talloc failed\n");
74 goto err_exit;
77 entry->child_pid = fork();
79 if (entry->child_pid == -1) {
80 DBG_ERR("fork failed: %s\n", strerror(errno));
81 goto err_exit;
84 if (entry->child_pid == 0) {
87 * Child !
90 int child_std_end = STDOUT_FILENO;
91 popen_list *p;
93 close(parent_end);
94 if (child_end != child_std_end) {
95 dup2 (child_end, child_std_end);
96 close (child_end);
100 * POSIX.2: "popen() shall ensure that any streams from previous
101 * popen() calls that remain open in the parent process are closed
102 * in the new child process."
105 for (p = popen_chain; p; p = p->next)
106 close(p->fd);
108 ret = execv(argl[0], argl);
109 if (ret == -1) {
110 DBG_ERR("ERROR executing command "
111 "'%s': %s\n", command, strerror(errno));
113 _exit (127);
117 * Parent.
120 close (child_end);
122 /* Link into popen_chain. */
123 entry->next = popen_chain;
124 popen_chain = entry;
125 entry->fd = parent_end;
127 return entry->fd;
129 err_exit:
131 TALLOC_FREE(entry);
132 close(pipe_fds[0]);
133 close(pipe_fds[1]);
134 return -1;
137 /**************************************************************************
138 Wrapper for pclose. Modified from the glibc sources.
139 ****************************************************************************/
141 int sys_pclose(int fd)
143 int wstatus;
144 popen_list **ptr = &popen_chain;
145 popen_list *entry = NULL;
146 pid_t wait_pid;
147 int status = -1;
149 /* Unlink from popen_chain. */
150 for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
151 if ((*ptr)->fd == fd) {
152 entry = *ptr;
153 *ptr = (*ptr)->next;
154 status = 0;
155 break;
159 if (status < 0 || close(entry->fd) < 0)
160 return -1;
163 * As Samba is catching and eating child process
164 * exits we don't really care about the child exit
165 * code, a -1 with errno = ECHILD will do fine for us.
168 do {
169 wait_pid = waitpid (entry->child_pid, &wstatus, 0);
170 } while (wait_pid == -1 && errno == EINTR);
172 TALLOC_FREE(entry);
174 if (wait_pid == -1)
175 return -1;
176 return wstatus;