Mercurial > hg
comparison contrib/chg/chg.c @ 29344:bb3d5c20eaf6
chg: exec pager in child process
Before this patch, chg uses the old pager behavior (pre 369741ef7253), which
executes pager in the main process. The user will see the exit code of the
pager, instead of the hg command.
Like 369741ef7253, this patch fixes the behavior by executing the pager in
the child process, and wait for it at the end of the main process.
author | Jun Wu <quark@fb.com> |
---|---|
date | Sat, 11 Jun 2016 20:25:49 +0100 |
parents | 94451300f3ec |
children | 62b890496de5 |
comparison
equal
deleted
inserted
replaced
29343:e095b9e753f7 | 29344:bb3d5c20eaf6 |
---|---|
415 | 415 |
416 error: | 416 error: |
417 abortmsgerrno("failed to set up signal handlers"); | 417 abortmsgerrno("failed to set up signal handlers"); |
418 } | 418 } |
419 | 419 |
420 /* This implementation is based on hgext/pager.py (pre 369741ef7253) */ | 420 /* This implementation is based on hgext/pager.py (post 369741ef7253) |
421 static void setuppager(hgclient_t *hgc, const char *const args[], | 421 * Return 0 if pager is not started, or pid of the pager */ |
422 static pid_t setuppager(hgclient_t *hgc, const char *const args[], | |
422 size_t argsize) | 423 size_t argsize) |
423 { | 424 { |
424 const char *pagercmd = hgc_getpager(hgc, args, argsize); | 425 const char *pagercmd = hgc_getpager(hgc, args, argsize); |
425 if (!pagercmd) | 426 if (!pagercmd) |
426 return; | 427 return 0; |
427 | 428 |
428 int pipefds[2]; | 429 int pipefds[2]; |
429 if (pipe(pipefds) < 0) | 430 if (pipe(pipefds) < 0) |
430 return; | 431 return 0; |
431 pid_t pid = fork(); | 432 pid_t pid = fork(); |
432 if (pid < 0) | 433 if (pid < 0) |
433 goto error; | 434 goto error; |
434 if (pid == 0) { | 435 if (pid > 0) { |
435 close(pipefds[0]); | 436 close(pipefds[0]); |
436 if (dup2(pipefds[1], fileno(stdout)) < 0) | 437 if (dup2(pipefds[1], fileno(stdout)) < 0) |
437 goto error; | 438 goto error; |
438 if (isatty(fileno(stderr))) { | 439 if (isatty(fileno(stderr))) { |
439 if (dup2(pipefds[1], fileno(stderr)) < 0) | 440 if (dup2(pipefds[1], fileno(stderr)) < 0) |
440 goto error; | 441 goto error; |
441 } | 442 } |
442 close(pipefds[1]); | 443 close(pipefds[1]); |
443 hgc_attachio(hgc); /* reattach to pager */ | 444 hgc_attachio(hgc); /* reattach to pager */ |
444 return; | 445 return pid; |
445 } else { | 446 } else { |
446 dup2(pipefds[0], fileno(stdin)); | 447 dup2(pipefds[0], fileno(stdin)); |
447 close(pipefds[0]); | 448 close(pipefds[0]); |
448 close(pipefds[1]); | 449 close(pipefds[1]); |
449 | 450 |
450 int r = execlp("/bin/sh", "/bin/sh", "-c", pagercmd, NULL); | 451 int r = execlp("/bin/sh", "/bin/sh", "-c", pagercmd, NULL); |
451 if (r < 0) { | 452 if (r < 0) { |
452 abortmsgerrno("cannot start pager '%s'", pagercmd); | 453 abortmsgerrno("cannot start pager '%s'", pagercmd); |
453 } | 454 } |
454 return; | 455 return 0; |
455 } | 456 } |
456 | 457 |
457 error: | 458 error: |
458 close(pipefds[0]); | 459 close(pipefds[0]); |
459 close(pipefds[1]); | 460 close(pipefds[1]); |
460 abortmsgerrno("failed to prepare pager"); | 461 abortmsgerrno("failed to prepare pager"); |
462 return 0; | |
463 } | |
464 | |
465 static void waitpager(pid_t pid) | |
466 { | |
467 /* close output streams to notify the pager its input ends */ | |
468 fclose(stdout); | |
469 fclose(stderr); | |
470 while (1) { | |
471 pid_t ret = waitpid(pid, NULL, 0); | |
472 if (ret == -1 && errno == EINTR) | |
473 continue; | |
474 break; | |
475 } | |
461 } | 476 } |
462 | 477 |
463 /* Run instructions sent from the server like unlink and set redirect path | 478 /* Run instructions sent from the server like unlink and set redirect path |
464 * Return 1 if reconnect is needed, otherwise 0 */ | 479 * Return 1 if reconnect is needed, otherwise 0 */ |
465 static int runinstructions(struct cmdserveropts *opts, const char **insts) | 480 static int runinstructions(struct cmdserveropts *opts, const char **insts) |
583 "wrapper, wrap chg instead of hg.", | 598 "wrapper, wrap chg instead of hg.", |
584 gethgcmd()); | 599 gethgcmd()); |
585 } | 600 } |
586 | 601 |
587 setupsignalhandler(hgc_peerpid(hgc)); | 602 setupsignalhandler(hgc_peerpid(hgc)); |
588 setuppager(hgc, argv + 1, argc - 1); | 603 pid_t pagerpid = setuppager(hgc, argv + 1, argc - 1); |
589 int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1); | 604 int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1); |
590 hgc_close(hgc); | 605 hgc_close(hgc); |
591 freecmdserveropts(&opts); | 606 freecmdserveropts(&opts); |
607 if (pagerpid) | |
608 waitpager(pagerpid); | |
609 | |
592 return exitcode; | 610 return exitcode; |
593 } | 611 } |