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 1690 : int sys_popenv(char * const argl[]) 43 : { 44 0 : int parent_end, child_end; 45 0 : int pipe_fds[2]; 46 1690 : popen_list *entry = NULL; 47 1690 : const char *command = NULL; 48 0 : int ret; 49 : 50 1690 : if (argl == NULL) { 51 0 : errno = EINVAL; 52 0 : return -1; 53 : } 54 1690 : command = argl[0]; 55 : 56 1690 : if (!*command) { 57 0 : errno = EINVAL; 58 0 : return -1; 59 : } 60 : 61 1690 : ret = pipe(pipe_fds); 62 1690 : if (ret < 0) { 63 0 : DBG_ERR("error opening pipe: %s\n", 64 : strerror(errno)); 65 0 : return -1; 66 : } 67 : 68 1690 : parent_end = pipe_fds[0]; 69 1690 : child_end = pipe_fds[1]; 70 : 71 1690 : entry = talloc_zero(NULL, popen_list); 72 1690 : if (entry == NULL) { 73 0 : DBG_ERR("talloc failed\n"); 74 0 : goto err_exit; 75 : } 76 : 77 1690 : entry->child_pid = fork(); 78 : 79 3428 : if (entry->child_pid == -1) { 80 0 : DBG_ERR("fork failed: %s\n", strerror(errno)); 81 0 : goto err_exit; 82 : } 83 : 84 3428 : if (entry->child_pid == 0) { 85 : 86 : /* 87 : * Child ! 88 : */ 89 : 90 1738 : int child_std_end = STDOUT_FILENO; 91 0 : popen_list *p; 92 : 93 1738 : close(parent_end); 94 1738 : if (child_end != child_std_end) { 95 1738 : dup2 (child_end, child_std_end); 96 1738 : 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 4566 : for (p = popen_chain; p; p = p->next) 106 2828 : close(p->fd); 107 : 108 1738 : ret = execv(argl[0], argl); 109 1738 : if (ret == -1) { 110 0 : DBG_ERR("ERROR executing command " 111 : "'%s': %s\n", command, strerror(errno)); 112 : } 113 1738 : _exit (127); 114 : } 115 : 116 : /* 117 : * Parent. 118 : */ 119 : 120 1690 : close (child_end); 121 : 122 : /* Link into popen_chain. */ 123 1690 : entry->next = popen_chain; 124 1690 : popen_chain = entry; 125 1690 : entry->fd = parent_end; 126 : 127 1690 : 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 1690 : int sys_pclose(int fd) 142 : { 143 0 : int wstatus; 144 1690 : popen_list **ptr = &popen_chain; 145 1690 : popen_list *entry = NULL; 146 0 : pid_t wait_pid; 147 1690 : int status = -1; 148 : 149 : /* Unlink from popen_chain. */ 150 3018 : for ( ; *ptr != NULL; ptr = &(*ptr)->next) { 151 3018 : if ((*ptr)->fd == fd) { 152 1690 : entry = *ptr; 153 1690 : *ptr = (*ptr)->next; 154 1690 : status = 0; 155 1690 : break; 156 : } 157 : } 158 : 159 1690 : 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 0 : do { 169 1812 : wait_pid = waitpid (entry->child_pid, &wstatus, 0); 170 1812 : } while (wait_pid == -1 && errno == EINTR); 171 : 172 1690 : TALLOC_FREE(entry); 173 : 174 1690 : if (wait_pid == -1) 175 1079 : return -1; 176 611 : return wstatus; 177 : }