Merge pull request #189 from hallyn/2019-11-11/vpiw
Fix vipw not resuming correctly when suspended
This commit is contained in:
		
							
								
								
									
										47
									
								
								src/vipw.c
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								src/vipw.c
									
									
									
									
									
								
							@@ -207,6 +207,8 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void))
 | 
			
		||||
	struct stat st1, st2;
 | 
			
		||||
	int status;
 | 
			
		||||
	FILE *f;
 | 
			
		||||
	pid_t orig_pgrp, editor_pgrp = -1;
 | 
			
		||||
	sigset_t mask, omask;
 | 
			
		||||
	/* FIXME: the following should have variable sizes */
 | 
			
		||||
	char filebackup[1024], fileedit[1024];
 | 
			
		||||
	char *to_rename;
 | 
			
		||||
@@ -294,6 +296,8 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void))
 | 
			
		||||
		editor = DEFAULT_EDITOR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	orig_pgrp = tcgetpgrp(STDIN_FILENO);
 | 
			
		||||
 | 
			
		||||
	pid = fork ();
 | 
			
		||||
	if (-1 == pid) {
 | 
			
		||||
		vipwexit ("fork", 1, 1);
 | 
			
		||||
@@ -303,6 +307,14 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void))
 | 
			
		||||
		char *buf;
 | 
			
		||||
		int status;
 | 
			
		||||
 | 
			
		||||
		/* Wait for parent to make us the foreground pgrp. */
 | 
			
		||||
		if (orig_pgrp != -1) {
 | 
			
		||||
			pid = getpid();
 | 
			
		||||
			setpgid(0, 0);
 | 
			
		||||
			while (tcgetpgrp(STDIN_FILENO) != pid)
 | 
			
		||||
				continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		buf = (char *) malloc (strlen (editor) + strlen (fileedit) + 2);
 | 
			
		||||
		snprintf (buf, strlen (editor) + strlen (fileedit) + 2,
 | 
			
		||||
		          "%s %s", editor, fileedit);
 | 
			
		||||
@@ -325,19 +337,50 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Run child in a new pgrp and make it the foreground pgrp. */
 | 
			
		||||
	if (orig_pgrp != -1) {
 | 
			
		||||
		setpgid(pid, pid);
 | 
			
		||||
		tcsetpgrp(STDIN_FILENO, pid);
 | 
			
		||||
 | 
			
		||||
		/* Avoid SIGTTOU when changing foreground pgrp below. */
 | 
			
		||||
		sigemptyset(&mask);
 | 
			
		||||
		sigaddset(&mask, SIGTTOU);
 | 
			
		||||
		sigprocmask(SIG_BLOCK, &mask, &omask);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		pid = waitpid (pid, &status, WUNTRACED);
 | 
			
		||||
		if ((pid != -1) && (WIFSTOPPED (status) != 0)) {
 | 
			
		||||
			/* The child (editor) was suspended.
 | 
			
		||||
			 * Suspend vipw. */
 | 
			
		||||
			 * Restore terminal pgrp and suspend vipw. */
 | 
			
		||||
			if (orig_pgrp != -1) {
 | 
			
		||||
				editor_pgrp = tcgetpgrp(STDIN_FILENO);
 | 
			
		||||
				if (editor_pgrp == -1) {
 | 
			
		||||
					fprintf (stderr, "%s: %s: %s", Prog,
 | 
			
		||||
						 "tcgetpgrp", strerror (errno));
 | 
			
		||||
				}
 | 
			
		||||
				if (tcsetpgrp(STDIN_FILENO, orig_pgrp) == -1) {
 | 
			
		||||
					fprintf (stderr, "%s: %s: %s", Prog,
 | 
			
		||||
						 "tcsetpgrp", strerror (errno));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			kill (getpid (), SIGSTOP);
 | 
			
		||||
			/* wake child when resumed */
 | 
			
		||||
			kill (pid, SIGCONT);
 | 
			
		||||
			if (editor_pgrp != -1) {
 | 
			
		||||
				if (tcsetpgrp(STDIN_FILENO, editor_pgrp) == -1) {
 | 
			
		||||
					fprintf (stderr, "%s: %s: %s", Prog,
 | 
			
		||||
						 "tcsetpgrp", strerror (errno));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			killpg (pid, SIGCONT);
 | 
			
		||||
		} else {
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (orig_pgrp != -1)
 | 
			
		||||
		sigprocmask(SIG_SETMASK, &omask, NULL);
 | 
			
		||||
 | 
			
		||||
	if (-1 == pid) {
 | 
			
		||||
		vipwexit (editor, 1, 1);
 | 
			
		||||
	} else if (   WIFEXITED (status)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user