1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <sys/types.h> 31 #include <poll.h> 32 #include <sys/wait.h> 33 #include <errno.h> 34 #include <strings.h> 35 #include <sys/stropts.h> 36 #include "libfsmgt.h" 37 38 #define MASKVAL (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND) 39 #define STDOUT 1 40 #define STDERR 2 41 42 /* 43 * Public methods 44 */ 45 46 /* 47 * Method: cmd_execute_command 48 * 49 * Description: Executes the given command and returns the output written to 50 * stdout and stderr in two separate file descriptors to be read by the caller. 51 * It is recommended that the caller use the cmd_retrieve_string method or 52 * another polling method to read from the file descriptors especially in the 53 * case that the command output is expected to be lengthy. 54 * 55 * Parameters: 56 * - char *cmd - The command to execute. 57 * - int *output_filedes - The file descriptor to which the stdout output 58 * is written. 59 * - int *err_filedes - The file descriptor to which the stderr output 60 * is written. 61 * 62 * Returns: 63 * - int - This value will always be zero. This was intended to be the 64 * the exit status of the executed command, but in the case of the 65 * execution of a command with a large amount of output (ex: ls of a large 66 * directory) we can't wait for the exec'd command to exit. This is 67 * because of the way that file descriptors work. When the child process, 68 * or the process executing the command, writes of 'x' amount of data to 69 * a file desciptor (fd), the fd reaches a threshold and will lock and wait 70 * for a reader to read before writing anymore data. In this case, we 71 * don't have a reader since the caller reads from the file descriptors, 72 * not the parent process. 73 * The result is that the parent process cannot be allowed to wait for the 74 * child process to exit. Hence, cannot get the exit status of the 75 * executed command. 76 */ 77 int 78 cmd_execute_command(char *cmd, int *output_filedes, int *err_filedes) { 79 pid_t child_pid; 80 int output[2]; 81 int error[2]; 82 int ret_val; 83 84 if (pipe(output) == -1) { 85 return (errno); 86 } 87 88 if (pipe(error) == -1) { 89 return (errno); 90 } 91 92 if ((child_pid = fork()) == -1) { 93 return (errno); 94 } 95 96 if (child_pid == 0) { 97 /* 98 * We are in the child. 99 */ 100 101 /* 102 * Close the file descriptors we aren't using. 103 */ 104 close(output[0]); 105 close(error[0]); 106 107 /* 108 * Close stdout and dup to output[1] 109 */ 110 if (close(STDOUT) == -1) { 111 exit(errno); 112 } 113 114 if (dup(output[1]) == -1) { 115 exit(errno); 116 } 117 118 close(output[1]); 119 120 /* 121 * Close stderr and dup to error[1] 122 */ 123 if (close(STDERR) == -1) { 124 exit(errno); 125 } 126 127 if (dup(error[1]) == -1) { 128 exit(errno); 129 } 130 131 close(error[1]); 132 133 if (execl("/usr/bin/sh", "sh", "-c", cmd, (char *)0) == -1) { 134 135 exit(errno); 136 } else { 137 exit(0); 138 } 139 } 140 141 /* 142 * We are in the parent 143 */ 144 145 /* 146 * Close the file descriptors we aren't using. 147 */ 148 close(output[1]); 149 close(error[1]); 150 151 *output_filedes = output[0]; 152 *err_filedes = error[0]; 153 154 /* 155 * Do not wait for the child process to exit. Just return. 156 */ 157 ret_val = 0; 158 return (ret_val); 159 160 } /* cmd_execute_command */ 161 162 /* 163 * Method: cmd_execute_command_and_retrieve_string 164 * 165 * Description: Executes the given string and returns the output as it is 166 * output as it is written to stdout and stderr in the return string. 167 * 168 * Parameters: 169 * - char *cmd - the command to execute. 170 * - int *errp - the error indicator. This will be set to a non-zero 171 * upon error. 172 * 173 * Returns: 174 * char * - The output of the command to stderr and stdout. 175 */ 176 char * 177 cmd_execute_command_and_retrieve_string(char *cmd, int *errp) { 178 pid_t child_pid; 179 int output[2]; 180 int err; 181 int status; 182 char *ret_val; 183 184 *errp = 0; 185 if (pipe(output) == -1) { 186 *errp = errno; 187 return (NULL); 188 } 189 190 if ((child_pid = fork()) == -1) { 191 *errp = errno; 192 return (NULL); 193 } 194 195 if (child_pid == 0) { 196 /* 197 * We are in the child. 198 */ 199 200 /* 201 * Close the unused file descriptor. 202 */ 203 close(output[0]); 204 205 /* 206 * Close stdout and dup to output[1] 207 */ 208 if (close(STDOUT) == -1) { 209 *errp = errno; 210 exit(*errp); 211 } 212 213 if (dup(output[1]) == -1) { 214 *errp = errno; 215 exit(*errp); 216 } 217 218 /* 219 * Close stderr and dup to output[1] 220 */ 221 if (close(STDERR) == -1) { 222 *errp = errno; 223 exit(*errp); 224 } 225 226 if (dup(output[1]) == -1) { 227 *errp = errno; 228 exit(*errp); 229 } 230 231 close(output[1]); 232 233 if (execl("/usr/bin/sh", "sh", "-c", cmd, (char *)0) == -1) { 234 235 *errp = errno; 236 exit(*errp); 237 } else { 238 exit(0); 239 } 240 } 241 242 /* 243 * We are in the parent 244 */ 245 246 /* 247 * Close the file descriptors we are not using. 248 */ 249 close(output[1]); 250 251 /* 252 * Wait for the child process to exit. 253 */ 254 while ((wait(&status) != child_pid)) { 255 ret_val = cmd_retrieve_string(output[0], &err); 256 } 257 258 /* 259 * Evaluate the wait status and set the evaluated value to 260 * the value of errp. 261 */ 262 *errp = WEXITSTATUS(status); 263 264 ret_val = cmd_retrieve_string(output[0], &err); 265 266 /* 267 * Caller must free space allocated for ret_val with free() 268 */ 269 return (ret_val); 270 } /* cmd_execute_command_and_retrieve_string */ 271 272 /* 273 * Method: cmd_retrieve_string 274 * 275 * Description: Returns the data written to the file descriptor passed in. 276 * 277 * Parameters: 278 * - int filedes - The file descriptor to be read. 279 * - int *errp - The error indicator. This will be set to a non-zero 280 * value upon error. 281 * 282 * Returns: 283 * - char * - The data read from the file descriptor. 284 */ 285 char * 286 cmd_retrieve_string(int filedes, int *errp) { 287 int returned_value = 0; 288 int buffer_size = 1024; 289 int len; 290 char *ret_val; 291 char *buffer; 292 boolean_t stop_loop = B_FALSE; 293 struct pollfd pollfds[1]; 294 295 *errp = 0; 296 /* 297 * Read from the file descriptor passed into the function. This 298 * will read data written to the file descriptor on a FIFO basis. 299 * Care must be taken to make sure to get all data from the file 300 * descriptor. 301 */ 302 303 ret_val = (char *)calloc((size_t)1, (size_t)sizeof (char)); 304 ret_val[0] = '\0'; 305 306 307 /* 308 * Set up the pollfd structure with appropriate information. 309 */ 310 pollfds[0].fd = filedes; 311 pollfds[0].events = MASKVAL; 312 pollfds[0].revents = 0; 313 314 while (stop_loop == B_FALSE) { 315 char *tmp_string; 316 317 switch (poll(pollfds, 1, INFTIM)) { 318 case -1: 319 320 case 0: 321 /* 322 * Nothing to read yet so continue. 323 */ 324 continue; 325 default: 326 buffer = (char *)calloc( 327 (size_t)(buffer_size + 1), 328 (size_t)sizeof (char)); 329 330 if (buffer == NULL) { 331 /* 332 * Out of memory 333 */ 334 *errp = errno; 335 return (NULL); 336 } 337 338 /* 339 * Call read to read from the filedesc. 340 */ 341 returned_value = read(filedes, buffer, 342 buffer_size); 343 if (returned_value <= 0) { 344 /* 345 * Either we errored or didn't read any 346 * bytes of data. 347 * returned_value == -1 represents an 348 * error. 349 * returned value == 0 represents 0 350 * bytes read. 351 */ 352 stop_loop = B_TRUE; 353 continue; 354 } 355 356 len = strlen(buffer); 357 358 /* 359 * Allocate space for the new string. 360 */ 361 tmp_string = 362 (char *)calloc((size_t)(len+strlen(ret_val)+1), 363 (size_t)sizeof (char)); 364 365 if (tmp_string == NULL) { 366 /* 367 * Out of memory 368 */ 369 370 *errp = errno; 371 return (NULL); 372 } 373 374 /* 375 * Concatenate the the new string in 'buffer' 376 * with whatever is in the 'ret_val' buffer. 377 */ 378 snprintf(tmp_string, (size_t)(len + 379 strlen(ret_val) + 1), "%s%s", 380 ret_val, buffer); 381 382 (void) free(ret_val); 383 ret_val = strdup(tmp_string); 384 385 if (ret_val == NULL) { 386 /* 387 * Out of memory 388 */ 389 *errp = errno; 390 return (NULL); 391 } 392 (void) free(tmp_string); 393 (void) free(buffer); 394 395 } /* switch (poll(pollfds, 1, INFTIM)) */ 396 397 } /* while (stop_loop == B_FALSE) */ 398 399 return (ret_val); 400 } /* cmd_retrieve_string */ 401