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