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