1c72fcc34Sopenharmony_ci/* 2c72fcc34Sopenharmony_ci * Copyright (C) 2004-2005 Kay Sievers <kay.sievers@vrfy.org> 3c72fcc34Sopenharmony_ci * 4c72fcc34Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it 5c72fcc34Sopenharmony_ci * under the terms of the GNU General Public License as published by the 6c72fcc34Sopenharmony_ci * Free Software Foundation version 2 of the License. 7c72fcc34Sopenharmony_ci * 8c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 9c72fcc34Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 10c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11c72fcc34Sopenharmony_ci * General Public License for more details. 12c72fcc34Sopenharmony_ci * 13c72fcc34Sopenharmony_ci * You should have received a copy of the GNU General Public License along 14c72fcc34Sopenharmony_ci * with this program; if not, write to the Free Software Foundation, Inc., 15c72fcc34Sopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16c72fcc34Sopenharmony_ci * 17c72fcc34Sopenharmony_ci */ 18c72fcc34Sopenharmony_ci 19c72fcc34Sopenharmony_ci#define MY_MAX(a,b) ((a) > (b) ? (a) : (b)) 20c72fcc34Sopenharmony_ci 21c72fcc34Sopenharmony_ci#define READ_END 0 22c72fcc34Sopenharmony_ci#define WRITE_END 1 23c72fcc34Sopenharmony_ci 24c72fcc34Sopenharmony_cistatic 25c72fcc34Sopenharmony_ciint run_program1(struct space *space, 26c72fcc34Sopenharmony_ci const char *command0, char *result, 27c72fcc34Sopenharmony_ci size_t ressize, size_t *reslen, int log); 28c72fcc34Sopenharmony_ci 29c72fcc34Sopenharmony_cistatic 30c72fcc34Sopenharmony_ciint run_program0(struct space *space, 31c72fcc34Sopenharmony_ci const char *command0, char *result, 32c72fcc34Sopenharmony_ci size_t ressize, size_t *reslen, int log) 33c72fcc34Sopenharmony_ci{ 34c72fcc34Sopenharmony_ci int retval = 0; 35c72fcc34Sopenharmony_ci int status; 36c72fcc34Sopenharmony_ci int outpipe[2] = {-1, -1}; 37c72fcc34Sopenharmony_ci int errpipe[2] = {-1, -1}; 38c72fcc34Sopenharmony_ci pid_t pid; 39c72fcc34Sopenharmony_ci char arg[PATH_SIZE]; 40c72fcc34Sopenharmony_ci char program[PATH_SIZE]; 41c72fcc34Sopenharmony_ci char *argv[(sizeof(arg) / 2) + 1]; 42c72fcc34Sopenharmony_ci int devnull; 43c72fcc34Sopenharmony_ci int i; 44c72fcc34Sopenharmony_ci 45c72fcc34Sopenharmony_ci /* build argv from comand */ 46c72fcc34Sopenharmony_ci strlcpy(arg, command0, sizeof(arg)); 47c72fcc34Sopenharmony_ci i = 0; 48c72fcc34Sopenharmony_ci if (strchr(arg, ' ') != NULL) { 49c72fcc34Sopenharmony_ci char *pos = arg; 50c72fcc34Sopenharmony_ci 51c72fcc34Sopenharmony_ci while (pos != NULL) { 52c72fcc34Sopenharmony_ci if (pos[0] == '\'') { 53c72fcc34Sopenharmony_ci /* don't separate if in apostrophes */ 54c72fcc34Sopenharmony_ci pos++; 55c72fcc34Sopenharmony_ci argv[i] = strsep(&pos, "\'"); 56c72fcc34Sopenharmony_ci while (pos != NULL && pos[0] == ' ') 57c72fcc34Sopenharmony_ci pos++; 58c72fcc34Sopenharmony_ci } else { 59c72fcc34Sopenharmony_ci argv[i] = strsep(&pos, " "); 60c72fcc34Sopenharmony_ci } 61c72fcc34Sopenharmony_ci dbg("arg[%i] '%s'", i, argv[i]); 62c72fcc34Sopenharmony_ci i++; 63c72fcc34Sopenharmony_ci } 64c72fcc34Sopenharmony_ci argv[i] = NULL; 65c72fcc34Sopenharmony_ci } else { 66c72fcc34Sopenharmony_ci argv[0] = arg; 67c72fcc34Sopenharmony_ci argv[1] = NULL; 68c72fcc34Sopenharmony_ci } 69c72fcc34Sopenharmony_ci info("'%s'", command0); 70c72fcc34Sopenharmony_ci 71c72fcc34Sopenharmony_ci /* prepare pipes from child to parent */ 72c72fcc34Sopenharmony_ci if (result || log) { 73c72fcc34Sopenharmony_ci if (pipe(outpipe) != 0) { 74c72fcc34Sopenharmony_ci Perror(space, "pipe failed: %s", strerror(errno)); 75c72fcc34Sopenharmony_ci return -1; 76c72fcc34Sopenharmony_ci } 77c72fcc34Sopenharmony_ci } 78c72fcc34Sopenharmony_ci if (log) { 79c72fcc34Sopenharmony_ci if (pipe(errpipe) != 0) { 80c72fcc34Sopenharmony_ci Perror(space, "pipe failed: %s", strerror(errno)); 81c72fcc34Sopenharmony_ci return -1; 82c72fcc34Sopenharmony_ci } 83c72fcc34Sopenharmony_ci } 84c72fcc34Sopenharmony_ci 85c72fcc34Sopenharmony_ci /* allow programs in /lib/alsa called without the path */ 86c72fcc34Sopenharmony_ci if (strchr(argv[0], '/') == NULL) { 87c72fcc34Sopenharmony_ci strlcpy(program, "/lib/alsa/", sizeof(program)); 88c72fcc34Sopenharmony_ci strlcat(program, argv[0], sizeof(program)); 89c72fcc34Sopenharmony_ci argv[0] = program; 90c72fcc34Sopenharmony_ci } 91c72fcc34Sopenharmony_ci 92c72fcc34Sopenharmony_ci pid = fork(); 93c72fcc34Sopenharmony_ci switch(pid) { 94c72fcc34Sopenharmony_ci case 0: 95c72fcc34Sopenharmony_ci /* child closes parent ends of pipes */ 96c72fcc34Sopenharmony_ci if (outpipe[READ_END] > 0) 97c72fcc34Sopenharmony_ci close(outpipe[READ_END]); 98c72fcc34Sopenharmony_ci if (errpipe[READ_END] > 0) 99c72fcc34Sopenharmony_ci close(errpipe[READ_END]); 100c72fcc34Sopenharmony_ci 101c72fcc34Sopenharmony_ci /* discard child output or connect to pipe */ 102c72fcc34Sopenharmony_ci devnull = open("/dev/null", O_RDWR); 103c72fcc34Sopenharmony_ci if (devnull > 0) { 104c72fcc34Sopenharmony_ci dup2(devnull, STDIN_FILENO); 105c72fcc34Sopenharmony_ci if (outpipe[WRITE_END] < 0) 106c72fcc34Sopenharmony_ci dup2(devnull, STDOUT_FILENO); 107c72fcc34Sopenharmony_ci if (errpipe[WRITE_END] < 0) 108c72fcc34Sopenharmony_ci dup2(devnull, STDERR_FILENO); 109c72fcc34Sopenharmony_ci close(devnull); 110c72fcc34Sopenharmony_ci } else 111c72fcc34Sopenharmony_ci Perror(space, "open /dev/null failed: %s", strerror(errno)); 112c72fcc34Sopenharmony_ci if (outpipe[WRITE_END] > 0) { 113c72fcc34Sopenharmony_ci dup2(outpipe[WRITE_END], STDOUT_FILENO); 114c72fcc34Sopenharmony_ci close(outpipe[WRITE_END]); 115c72fcc34Sopenharmony_ci } 116c72fcc34Sopenharmony_ci if (errpipe[WRITE_END] > 0) { 117c72fcc34Sopenharmony_ci dup2(errpipe[WRITE_END], STDERR_FILENO); 118c72fcc34Sopenharmony_ci close(errpipe[WRITE_END]); 119c72fcc34Sopenharmony_ci } 120c72fcc34Sopenharmony_ci execv(argv[0], argv); 121c72fcc34Sopenharmony_ci 122c72fcc34Sopenharmony_ci /* we should never reach this */ 123c72fcc34Sopenharmony_ci Perror(space, "exec of program '%s' failed", argv[0]); 124c72fcc34Sopenharmony_ci _exit(1); 125c72fcc34Sopenharmony_ci case -1: 126c72fcc34Sopenharmony_ci Perror(space, "fork of '%s' failed: %s", argv[0], strerror(errno)); 127c72fcc34Sopenharmony_ci return -1; 128c72fcc34Sopenharmony_ci default: 129c72fcc34Sopenharmony_ci /* read from child if requested */ 130c72fcc34Sopenharmony_ci if (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) { 131c72fcc34Sopenharmony_ci ssize_t count; 132c72fcc34Sopenharmony_ci size_t respos = 0; 133c72fcc34Sopenharmony_ci 134c72fcc34Sopenharmony_ci /* parent closes child ends of pipes */ 135c72fcc34Sopenharmony_ci if (outpipe[WRITE_END] > 0) 136c72fcc34Sopenharmony_ci close(outpipe[WRITE_END]); 137c72fcc34Sopenharmony_ci if (errpipe[WRITE_END] > 0) 138c72fcc34Sopenharmony_ci close(errpipe[WRITE_END]); 139c72fcc34Sopenharmony_ci 140c72fcc34Sopenharmony_ci /* read child output */ 141c72fcc34Sopenharmony_ci while (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) { 142c72fcc34Sopenharmony_ci int fdcount; 143c72fcc34Sopenharmony_ci fd_set readfds; 144c72fcc34Sopenharmony_ci 145c72fcc34Sopenharmony_ci FD_ZERO(&readfds); 146c72fcc34Sopenharmony_ci if (outpipe[READ_END] > 0) 147c72fcc34Sopenharmony_ci FD_SET(outpipe[READ_END], &readfds); 148c72fcc34Sopenharmony_ci if (errpipe[READ_END] > 0) 149c72fcc34Sopenharmony_ci FD_SET(errpipe[READ_END], &readfds); 150c72fcc34Sopenharmony_ci fdcount = select(MY_MAX(outpipe[READ_END], errpipe[READ_END])+1, &readfds, NULL, NULL, NULL); 151c72fcc34Sopenharmony_ci if (fdcount < 0) { 152c72fcc34Sopenharmony_ci if (errno == EINTR) 153c72fcc34Sopenharmony_ci continue; 154c72fcc34Sopenharmony_ci retval = -1; 155c72fcc34Sopenharmony_ci break; 156c72fcc34Sopenharmony_ci } 157c72fcc34Sopenharmony_ci 158c72fcc34Sopenharmony_ci /* get stdout */ 159c72fcc34Sopenharmony_ci if (outpipe[READ_END] > 0 && FD_ISSET(outpipe[READ_END], &readfds)) { 160c72fcc34Sopenharmony_ci char inbuf[1024]; 161c72fcc34Sopenharmony_ci char *pos; 162c72fcc34Sopenharmony_ci char *line; 163c72fcc34Sopenharmony_ci 164c72fcc34Sopenharmony_ci count = read(outpipe[READ_END], inbuf, sizeof(inbuf)-1); 165c72fcc34Sopenharmony_ci if (count <= 0) { 166c72fcc34Sopenharmony_ci close(outpipe[READ_END]); 167c72fcc34Sopenharmony_ci outpipe[READ_END] = -1; 168c72fcc34Sopenharmony_ci if (count < 0) { 169c72fcc34Sopenharmony_ci Perror(space, "stdin read failed: %s", strerror(errno)); 170c72fcc34Sopenharmony_ci retval = -1; 171c72fcc34Sopenharmony_ci } 172c72fcc34Sopenharmony_ci continue; 173c72fcc34Sopenharmony_ci } 174c72fcc34Sopenharmony_ci inbuf[count] = '\0'; 175c72fcc34Sopenharmony_ci 176c72fcc34Sopenharmony_ci /* store result for rule processing */ 177c72fcc34Sopenharmony_ci if (result) { 178c72fcc34Sopenharmony_ci if (respos + count < ressize) { 179c72fcc34Sopenharmony_ci memcpy(&result[respos], inbuf, count); 180c72fcc34Sopenharmony_ci respos += count; 181c72fcc34Sopenharmony_ci } else { 182c72fcc34Sopenharmony_ci Perror(space, "ressize %ld too short", (long)ressize); 183c72fcc34Sopenharmony_ci retval = -1; 184c72fcc34Sopenharmony_ci } 185c72fcc34Sopenharmony_ci } 186c72fcc34Sopenharmony_ci pos = inbuf; 187c72fcc34Sopenharmony_ci while ((line = strsep(&pos, "\n"))) 188c72fcc34Sopenharmony_ci if (pos || line[0] != '\0') 189c72fcc34Sopenharmony_ci info("'%s' (stdout) '%s'", argv[0], line); 190c72fcc34Sopenharmony_ci } 191c72fcc34Sopenharmony_ci 192c72fcc34Sopenharmony_ci /* get stderr */ 193c72fcc34Sopenharmony_ci if (errpipe[READ_END] > 0 && FD_ISSET(errpipe[READ_END], &readfds)) { 194c72fcc34Sopenharmony_ci char errbuf[1024]; 195c72fcc34Sopenharmony_ci char *pos; 196c72fcc34Sopenharmony_ci char *line; 197c72fcc34Sopenharmony_ci 198c72fcc34Sopenharmony_ci count = read(errpipe[READ_END], errbuf, sizeof(errbuf)-1); 199c72fcc34Sopenharmony_ci if (count <= 0) { 200c72fcc34Sopenharmony_ci close(errpipe[READ_END]); 201c72fcc34Sopenharmony_ci errpipe[READ_END] = -1; 202c72fcc34Sopenharmony_ci if (count < 0) 203c72fcc34Sopenharmony_ci Perror(space, "stderr read failed: %s", strerror(errno)); 204c72fcc34Sopenharmony_ci continue; 205c72fcc34Sopenharmony_ci } 206c72fcc34Sopenharmony_ci errbuf[count] = '\0'; 207c72fcc34Sopenharmony_ci pos = errbuf; 208c72fcc34Sopenharmony_ci while ((line = strsep(&pos, "\n"))) 209c72fcc34Sopenharmony_ci if (pos || line[0] != '\0') 210c72fcc34Sopenharmony_ci info("'%s' (stderr) '%s'", argv[0], line); 211c72fcc34Sopenharmony_ci } 212c72fcc34Sopenharmony_ci } 213c72fcc34Sopenharmony_ci if (outpipe[READ_END] > 0) 214c72fcc34Sopenharmony_ci close(outpipe[READ_END]); 215c72fcc34Sopenharmony_ci if (errpipe[READ_END] > 0) 216c72fcc34Sopenharmony_ci close(errpipe[READ_END]); 217c72fcc34Sopenharmony_ci 218c72fcc34Sopenharmony_ci /* return the childs stdout string */ 219c72fcc34Sopenharmony_ci if (result) { 220c72fcc34Sopenharmony_ci result[respos] = '\0'; 221c72fcc34Sopenharmony_ci dbg("result='%s'", result); 222c72fcc34Sopenharmony_ci if (reslen) 223c72fcc34Sopenharmony_ci *reslen = respos; 224c72fcc34Sopenharmony_ci } 225c72fcc34Sopenharmony_ci } 226c72fcc34Sopenharmony_ci waitpid(pid, &status, 0); 227c72fcc34Sopenharmony_ci if (WIFEXITED(status)) { 228c72fcc34Sopenharmony_ci info("'%s' returned with status %i", argv[0], WEXITSTATUS(status)); 229c72fcc34Sopenharmony_ci if (WEXITSTATUS(status) != 0) 230c72fcc34Sopenharmony_ci retval = -1; 231c72fcc34Sopenharmony_ci } else { 232c72fcc34Sopenharmony_ci Perror(space, "'%s' abnormal exit", argv[0]); 233c72fcc34Sopenharmony_ci retval = -1; 234c72fcc34Sopenharmony_ci } 235c72fcc34Sopenharmony_ci } 236c72fcc34Sopenharmony_ci 237c72fcc34Sopenharmony_ci return retval; 238c72fcc34Sopenharmony_ci} 239c72fcc34Sopenharmony_ci 240c72fcc34Sopenharmony_cistatic 241c72fcc34Sopenharmony_ciint run_program(struct space *space, const char *command0, char *result, 242c72fcc34Sopenharmony_ci size_t ressize, size_t *reslen, int log) 243c72fcc34Sopenharmony_ci{ 244c72fcc34Sopenharmony_ci if (command0[0] == '_' && command0[1] == '_') 245c72fcc34Sopenharmony_ci return run_program1(space, command0, result, ressize, reslen, log); 246c72fcc34Sopenharmony_ci return run_program0(space, command0, result, ressize, reslen, log); 247c72fcc34Sopenharmony_ci} 248