Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * Samba system utilities
4 : * Copyright (C) Jeremy Allison 2000
5 : *
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.
10 : *
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.
15 : *
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/>.
18 : */
19 :
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"
26 :
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 : ****************************************************************************/
32 :
33 : typedef struct _popen_list
34 : {
35 : int fd;
36 : pid_t child_pid;
37 : struct _popen_list *next;
38 : } popen_list;
39 :
40 : static popen_list *popen_chain;
41 :
42 274 : int sys_popenv(char * const argl[])
43 : {
44 : int parent_end, child_end;
45 : int pipe_fds[2];
46 274 : popen_list *entry = NULL;
47 274 : const char *command = NULL;
48 : int ret;
49 :
50 274 : if (argl == NULL) {
51 0 : errno = EINVAL;
52 0 : return -1;
53 : }
54 274 : command = argl[0];
55 :
56 274 : if (!*command) {
57 0 : errno = EINVAL;
58 0 : return -1;
59 : }
60 :
61 274 : ret = pipe(pipe_fds);
62 274 : if (ret < 0) {
63 0 : DBG_ERR("error opening pipe: %s\n",
64 : strerror(errno));
65 0 : return -1;
66 : }
67 :
68 274 : parent_end = pipe_fds[0];
69 274 : child_end = pipe_fds[1];
70 :
71 274 : entry = talloc_zero(NULL, popen_list);
72 274 : if (entry == NULL) {
73 0 : DBG_ERR("talloc failed\n");
74 0 : goto err_exit;
75 : }
76 :
77 274 : entry->child_pid = fork();
78 :
79 556 : if (entry->child_pid == -1) {
80 0 : DBG_ERR("fork failed: %s\n", strerror(errno));
81 0 : goto err_exit;
82 : }
83 :
84 556 : if (entry->child_pid == 0) {
85 :
86 : /*
87 : * Child !
88 : */
89 :
90 282 : int child_std_end = STDOUT_FILENO;
91 : popen_list *p;
92 :
93 282 : close(parent_end);
94 282 : if (child_end != child_std_end) {
95 282 : dup2 (child_end, child_std_end);
96 282 : close (child_end);
97 : }
98 :
99 : /*
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."
103 : */
104 :
105 1262 : for (p = popen_chain; p; p = p->next)
106 980 : close(p->fd);
107 :
108 282 : ret = execv(argl[0], argl);
109 282 : if (ret == -1) {
110 0 : DBG_ERR("ERROR executing command "
111 : "'%s': %s\n", command, strerror(errno));
112 : }
113 282 : _exit (127);
114 : }
115 :
116 : /*
117 : * Parent.
118 : */
119 :
120 274 : close (child_end);
121 :
122 : /* Link into popen_chain. */
123 274 : entry->next = popen_chain;
124 274 : popen_chain = entry;
125 274 : entry->fd = parent_end;
126 :
127 274 : return entry->fd;
128 :
129 0 : err_exit:
130 :
131 0 : TALLOC_FREE(entry);
132 0 : close(pipe_fds[0]);
133 0 : close(pipe_fds[1]);
134 0 : return -1;
135 : }
136 :
137 : /**************************************************************************
138 : Wrapper for pclose. Modified from the glibc sources.
139 : ****************************************************************************/
140 :
141 274 : int sys_pclose(int fd)
142 : {
143 : int wstatus;
144 274 : popen_list **ptr = &popen_chain;
145 274 : popen_list *entry = NULL;
146 : pid_t wait_pid;
147 274 : int status = -1;
148 :
149 : /* Unlink from popen_chain. */
150 1040 : for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
151 1040 : if ((*ptr)->fd == fd) {
152 274 : entry = *ptr;
153 274 : *ptr = (*ptr)->next;
154 274 : status = 0;
155 274 : break;
156 : }
157 : }
158 :
159 274 : if (status < 0 || close(entry->fd) < 0)
160 0 : return -1;
161 :
162 : /*
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.
166 : */
167 :
168 : do {
169 291 : wait_pid = waitpid (entry->child_pid, &wstatus, 0);
170 291 : } while (wait_pid == -1 && errno == EINTR);
171 :
172 274 : TALLOC_FREE(entry);
173 :
174 274 : if (wait_pid == -1)
175 61 : return -1;
176 213 : return wstatus;
177 : }
|