1 /* run.c --- routines for executing subprocesses under OS/2. 2 3 This file is part of GNU CVS. 4 5 GNU CVS is free software; you can redistribute it and/or modify it 6 under the terms of the GNU General Public License as published by the 7 Free Software Foundation; either version 2, or (at your option) any 8 later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. */ 14 15 #include "cvs.h" 16 17 #include "os2inc.h" 18 19 #include <process.h> 20 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <sys/types.h> 24 #include <sys/stat.h> 25 #include <string.h> 26 #include <fcntl.h> 27 #include <errno.h> 28 #include <io.h> 29 30 #define STDIN 0 31 #define STDOUT 1 32 #define STDERR 2 33 34 static void run_add_arg PROTO((const char *s)); 35 static void run_init_prog PROTO((void)); 36 37 extern char *strtok (); 38 39 /* 40 * To exec a program under CVS, first call run_setup() to setup any initial 41 * arguments. The options to run_setup are essentially like printf(). The 42 * arguments will be parsed into whitespace separated words and added to the 43 * global run_argv list. 44 * 45 * Then, optionally call run_arg() for each additional argument that you'd like 46 * to pass to the executed program. 47 * 48 * Finally, call run_exec() to execute the program with the specified 49 * arguments. 50 * The execvp() syscall will be used, so that the PATH is searched correctly. 51 * File redirections can be performed in the call to run_exec(). 52 */ 53 static char **run_argv; 54 static int run_argc; 55 static int run_argc_allocated; 56 57 void 58 run_setup (const char *prog) 59 { 60 char *cp; 61 int i; 62 63 char *run_prog; 64 65 /* clean out any malloc'ed values from run_argv */ 66 for (i = 0; i < run_argc; i++) 67 { 68 if (run_argv[i]) 69 { 70 free (run_argv[i]); 71 run_argv[i] = (char *) 0; 72 } 73 } 74 run_argc = 0; 75 76 run_prog = xstrdup (prog); 77 78 /* put each word into run_argv, allocating it as we go */ 79 for (cp = strtok (run_prog, " \t"); cp; cp = strtok ((char *) NULL, " \t")) 80 run_add_arg (cp); 81 82 free (run_prog) 83 } 84 85 void 86 run_arg (s) 87 const char *s; 88 { 89 run_add_arg (s); 90 } 91 92 /* Return a malloc'd copy of s, with double quotes around it. */ 93 static char * 94 quote (const char *s) 95 { 96 size_t s_len = strlen (s); 97 char *copy = xmalloc (s_len + 3); 98 char *scan = copy; 99 100 *scan++ = '"'; 101 strcpy (scan, s); 102 scan += s_len; 103 *scan++ = '"'; 104 *scan++ = '\0'; 105 106 return copy; 107 } 108 109 static void 110 run_add_arg (s) 111 const char *s; 112 { 113 /* allocate more argv entries if we've run out */ 114 if (run_argc >= run_argc_allocated) 115 { 116 run_argc_allocated += 50; 117 run_argv = (char **) xrealloc ((char *) run_argv, 118 run_argc_allocated * sizeof (char **)); 119 } 120 121 if (s) 122 { 123 run_argv[run_argc] = (run_argc ? quote (s) : xstrdup (s)); 124 run_argc++; 125 } 126 else 127 /* not post-incremented on purpose! */ 128 run_argv[run_argc] = (char *) 0; 129 } 130 131 int 132 run_exec (stin, stout, sterr, flags) 133 char *stin; 134 char *stout; 135 char *sterr; 136 int flags; 137 { 138 int shin, shout, sherr; 139 int sain, saout, saerr; /* saved handles */ 140 int mode_out, mode_err; 141 int status = -1; 142 int rerrno = 0; 143 int rval = -1; 144 void (*old_sigint) (int); 145 146 if (trace) /* if in trace mode */ 147 { 148 (void) fprintf (stderr, "-> system("); 149 run_print (stderr); 150 (void) fprintf (stderr, ")\n"); 151 } 152 if (noexec && (flags & RUN_REALLY) == 0) /* if in noexec mode */ 153 return (0); 154 155 /* 156 * start the engine and take off 157 */ 158 159 /* make sure that we are null terminated, since we didn't calloc */ 160 run_add_arg ((char *) 0); 161 162 /* setup default file descriptor numbers */ 163 shin = 0; 164 shout = 1; 165 sherr = 2; 166 167 /* set the file modes for stdout and stderr */ 168 mode_out = mode_err = O_WRONLY | O_CREAT; 169 mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC); 170 mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC); 171 172 /* open the files as required, shXX are shadows of stdin... */ 173 if (stin && (shin = open (stin, O_RDONLY)) == -1) 174 { 175 rerrno = errno; 176 error (0, errno, "cannot open %s for reading (prog %s)", 177 stin, run_argv[0]); 178 goto out0; 179 } 180 if (stout && (shout = open (stout, mode_out, 0666)) == -1) 181 { 182 rerrno = errno; 183 error (0, errno, "cannot open %s for writing (prog %s)", 184 stout, run_argv[0]); 185 goto out1; 186 } 187 if (sterr && (flags & RUN_COMBINED) == 0) 188 { 189 if ((sherr = open (sterr, mode_err, 0666)) == -1) 190 { 191 rerrno = errno; 192 error (0, errno, "cannot open %s for writing (prog %s)", 193 sterr, run_argv[0]); 194 goto out2; 195 } 196 } 197 /* now save the standard handles */ 198 sain = saout = saerr = -1; 199 sain = dup( 0); /* dup stdin */ 200 saout = dup( 1); /* dup stdout */ 201 saerr = dup( 2); /* dup stderr */ 202 203 /* the new handles will be dup'd to the standard handles 204 * for the spawn. 205 */ 206 207 if (shin != 0) 208 { 209 (void) dup2 (shin, 0); 210 (void) close (shin); 211 } 212 if (shout != 1) 213 { 214 (void) dup2 (shout, 1); 215 (void) close (shout); 216 } 217 if (flags & RUN_COMBINED) 218 (void) dup2 (1, 2); 219 else if (sherr != 2) 220 { 221 (void) dup2 (sherr, 2); 222 (void) close (sherr); 223 } 224 225 /* Ignore signals while we're running this. */ 226 old_sigint = signal (SIGINT, SIG_IGN); 227 228 /* dup'ing is done. try to run it now */ 229 rval = spawnvp ( P_WAIT, run_argv[0], run_argv); 230 231 /* Restore signal handling. */ 232 signal (SIGINT, old_sigint); 233 234 /* restore the original file handles */ 235 if (sain != -1) { 236 (void) dup2( sain, 0); /* re-connect stdin */ 237 (void) close( sain); 238 } 239 if (saout != -1) { 240 (void) dup2( saout, 1); /* re-connect stdout */ 241 (void) close( saout); 242 } 243 if (saerr != -1) { 244 (void) dup2( saerr, 2); /* re-connect stderr */ 245 (void) close( saerr); 246 } 247 248 /* Recognize the return code for a failed subprocess. */ 249 if (rval == -1) 250 return 2; 251 else 252 return rval; /* return child's exit status */ 253 254 /* error cases */ 255 /* cleanup the open file descriptors */ 256 out2: 257 if (stout) 258 (void) close (shout); 259 out1: 260 if (stin) 261 (void) close (shin); 262 263 out0: 264 if (rerrno) 265 errno = rerrno; 266 return (status); 267 } 268 269 270 void 271 run_print (fp) 272 FILE *fp; 273 { 274 int i; 275 276 for (i = 0; i < run_argc; i++) 277 { 278 (void) fprintf (fp, "'%s'", run_argv[i]); 279 if (i != run_argc - 1) 280 (void) fprintf (fp, " "); 281 } 282 } 283 284 static char * 285 requote (const char *cmd) 286 { 287 char *requoted = xmalloc (strlen (cmd) + 1); 288 char *p = requoted; 289 290 strcpy (requoted, cmd); 291 while ((p = strchr (p, '\'')) != NULL) 292 { 293 *p++ = '"'; 294 } 295 296 return requoted; 297 } 298 299 FILE * 300 run_popen (cmd, mode) 301 const char *cmd; 302 const char *mode; 303 { 304 if (trace) 305 #ifdef SERVER_SUPPORT 306 (void) fprintf (stderr, "%c-> run_popen(%s,%s)\n", 307 (server_active) ? 'S' : ' ', cmd, mode); 308 #else 309 (void) fprintf (stderr, "-> run_popen(%s,%s)\n", cmd, mode); 310 #endif 311 312 if (noexec) 313 return (NULL); 314 315 /* If the command string uses single quotes, turn them into 316 double quotes. */ 317 { 318 char *requoted = requote (cmd); 319 FILE *result = popen (requoted, mode); 320 free (requoted); 321 return result; 322 } 323 } 324 325 326 /* Running children with pipes connected to them. */ 327 328 /* Create a pipe. Set READWRITE[0] to its reading end, and 329 READWRITE[1] to its writing end. */ 330 331 static int 332 my_pipe (int *readwrite) 333 { 334 fprintf (stderr, 335 "Error: my_pipe() is unimplemented.\n"); 336 exit (1); 337 } 338 339 340 /* Create a child process running COMMAND with IN as its standard input, 341 and OUT as its standard output. Return a handle to the child, or 342 INVALID_HANDLE_VALUE. */ 343 static int 344 start_child (char *command, int in, int out) 345 { 346 fprintf (stderr, 347 "Error: start_child() is unimplemented.\n"); 348 exit (1); 349 } 350 351 352 /* Given an array of arguments that one might pass to spawnv, 353 construct a command line that one might pass to CreateProcess. 354 Try to quote things appropriately. */ 355 static char * 356 build_command (char **argv) 357 { 358 int len; 359 360 /* Compute the total length the command will have. */ 361 { 362 int i; 363 364 len = 0; 365 for (i = 0; argv[i]; i++) 366 { 367 char *p; 368 369 len += 2; /* for the double quotes */ 370 371 for (p = argv[i]; *p; p++) 372 { 373 if (*p == '"') 374 len += 2; 375 else 376 len++; 377 } 378 } 379 len++; /* for the space or the '\0' */ 380 } 381 382 { 383 char *command = (char *) malloc (len); 384 int i; 385 char *p; 386 387 if (! command) 388 { 389 errno = ENOMEM; 390 return command; 391 } 392 393 p = command; 394 /* copy each element of argv to command, putting each command 395 in double quotes, and backslashing any quotes that appear 396 within an argument. */ 397 for (i = 0; argv[i]; i++) 398 { 399 char *a; 400 *p++ = '"'; 401 for (a = argv[i]; *a; a++) 402 { 403 if (*a == '"') 404 *p++ = '\\', *p++ = '"'; 405 else 406 *p++ = *a; 407 } 408 *p++ = '"'; 409 *p++ = ' '; 410 } 411 p[-1] = '\0'; 412 413 return command; 414 } 415 } 416 417 418 /* Create an asynchronous child process executing ARGV, 419 with its standard input and output connected to the 420 parent with pipes. Set *TO to the file descriptor on 421 which one writes data for the child; set *FROM to 422 the file descriptor from which one reads data from the child. 423 Return the handle of the child process (this is what 424 _cwait and waitpid expect). */ 425 int 426 piped_child (char **argv, int *to, int *from) 427 { 428 fprintf (stderr, 429 "Error: piped_child() is unimplemented.\n"); 430 exit (1); 431 } 432 433 /* 434 * dir = 0 : main proc writes to new proc, which writes to oldfd 435 * dir = 1 : main proc reads from new proc, which reads from oldfd 436 * 437 * If this returns at all, then it was successful and the return value 438 * is a file descriptor; else it errors and exits. 439 */ 440 int 441 filter_stream_through_program (int oldfd, int dir, 442 char **prog, int *pidp) 443 { 444 int newfd; /* Gets set to one end of the pipe and returned. */ 445 HFILE from, to; 446 HFILE Old0 = -1, Old1 = -1, Old2 = -1, Tmp; 447 448 if (DosCreatePipe (&from, &to, 4096)) 449 return FALSE; 450 451 /* Save std{in,out,err} */ 452 DosDupHandle (STDIN, &Old0); 453 DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT); 454 DosDupHandle (STDOUT, &Old1); 455 DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT); 456 DosDupHandle (STDERR, &Old2); 457 DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT); 458 459 /* Redirect std{in,out,err} */ 460 if (dir) /* Who goes where? */ 461 { 462 Tmp = STDIN; 463 DosDupHandle (oldfd, &Tmp); 464 Tmp = STDOUT; 465 DosDupHandle (to, &Tmp); 466 Tmp = STDERR; 467 DosDupHandle (to, &Tmp); 468 469 newfd = from; 470 _setmode (newfd, O_BINARY); 471 472 DosClose (oldfd); 473 DosClose (to); 474 DosSetFHState (from, OPEN_FLAGS_NOINHERIT); 475 } 476 else 477 { 478 Tmp = STDIN; 479 DosDupHandle (from, &Tmp); 480 Tmp = STDOUT; 481 DosDupHandle (oldfd, &Tmp); 482 Tmp = STDERR; 483 DosDupHandle (oldfd, &Tmp); 484 485 newfd = to; 486 _setmode (newfd, O_BINARY); 487 488 DosClose (oldfd); 489 DosClose (from); 490 DosSetFHState (to, OPEN_FLAGS_NOINHERIT); 491 } 492 493 /* Spawn we now our hoary brood. */ 494 *pidp = spawnvp (P_NOWAIT, prog[0], prog); 495 496 /* Restore std{in,out,err} */ 497 Tmp = STDIN; 498 DosDupHandle (Old0, &Tmp); 499 DosClose (Old0); 500 Tmp = STDOUT; 501 DosDupHandle (Old1, &Tmp); 502 DosClose (Old1); 503 Tmp = STDERR; 504 DosDupHandle (Old2, &Tmp); 505 DosClose (Old2); 506 507 if(*pidp < 0) 508 { 509 DosClose (from); 510 DosClose (to); 511 error (1, 0, "error spawning %s", prog[0]); 512 } 513 514 return newfd; 515 } 516 517 518 int 519 pipe (int *filedesc) 520 { 521 /* todo: actually, we can use DosCreatePipe(). Fix this. */ 522 fprintf (stderr, 523 "Error: pipe() should not have been called in client.\n"); 524 exit (1); 525 } 526 527 528 void 529 close_on_exec (int fd) 530 { 531 /* Just does nothing for now... */ 532 533 /* Actually, we probably *can* implement this one. Let's see... */ 534 /* Nope. OS/2 has <fcntl.h>, but no fcntl() ! Wow. */ 535 /* Well, I'll leave this stuff in for future reference. */ 536 } 537 538 539 /* Actually, we #define sleep() in config.h now. */ 540 #ifndef sleep 541 unsigned int 542 sleep (unsigned int seconds) 543 { 544 /* I don't want to interfere with alarm signals, so I'm going to do 545 this the nasty way. */ 546 547 time_t base; 548 time_t tick; 549 int i; 550 551 /* Init. */ 552 time (&base); 553 time (&tick); 554 555 /* Loop until time has passed. */ 556 while (difftime (tick, base) < seconds) 557 { 558 /* This might be more civilized than calling time over and over 559 again. */ 560 for (i = 0; i < 10000; i++) 561 ; 562 time (&tick); 563 } 564 565 return 0; 566 } 567 #endif /* sleep */ 568