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 }