aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2016-04-14 20:55:48 +0000
committerIngo Schwarze <schwarze@openbsd.org>2016-04-14 20:55:48 +0000
commitb5bf8afcdb00cf4d6cc3b38b0ec2f6c184ebc2c3 (patch)
treedef6f1d48dd0f186225ad53e57e0af1093fe24eb
parent60f3c419013efd374b4edb4e0accd134de5cd50e (diff)
downloadmandoc-b5bf8afcdb00cf4d6cc3b38b0ec2f6c184ebc2c3.tar.gz
mandoc-b5bf8afcdb00cf4d6cc3b38b0ec2f6c184ebc2c3.tar.zst
mandoc-b5bf8afcdb00cf4d6cc3b38b0ec2f6c184ebc2c3.zip
Fix a process group race.
It could occasionally happen that the child process spawned less(1) before the parent process passed the control of the terminal to the child, and in that case, less(1) sometimes complained "Stopped (tty output)". Issue reported by naddy@.
-rw-r--r--main.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/main.c b/main.c
index 94b591ff..eb056230 100644
--- a/main.c
+++ b/main.c
@@ -1,4 +1,4 @@
-/* $Id: main.c,v 1.264 2016/04/13 12:26:25 schwarze Exp $ */
+/* $Id: main.c,v 1.265 2016/04/14 20:55:48 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2012, 2014-2016 Ingo Schwarze <schwarze@openbsd.org>
@@ -35,6 +35,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
#include "mandoc_aux.h"
@@ -1020,6 +1021,7 @@ mmsg(enum mandocerr t, enum mandoclevel lvl,
static pid_t
spawn_pager(struct tag_files *tag_files)
{
+ const struct timespec timeout = { 0, 100000000 }; /* 0.1s */
#define MAX_PAGER_ARGS 16
char *argv[MAX_PAGER_ARGS];
const char *pager;
@@ -1069,8 +1071,6 @@ spawn_pager(struct tag_files *tag_files)
case -1:
err((int)MANDOCLEVEL_SYSERR, "fork");
case 0:
- /* Set pgrp in both parent and child to avoid racing exec. */
- (void)setpgid(0, 0);
break;
default:
(void)setpgid(pager_pid, 0);
@@ -1089,6 +1089,12 @@ spawn_pager(struct tag_files *tag_files)
err((int)MANDOCLEVEL_SYSERR, "pager stdout");
close(tag_files->ofd);
close(tag_files->tfd);
+
+ /* Do not start the pager before controlling the terminal. */
+
+ while (tcgetpgrp(STDIN_FILENO) != getpid())
+ nanosleep(&timeout, NULL);
+
execvp(argv[0], argv);
err((int)MANDOCLEVEL_SYSERR, "exec %s", argv[0]);
}