openrc-run: fix rc_parallel race in svc_exec
svc_exec waits until SIGCHLD comes in to close its input, but in rc_parallel case the SIGCHLD might be unrelated. Checking the proper pid is found in signal handler and only signaling signal_pipe the status code directly avoids this problem.
This commit is contained in:
		
				
					committed by
					
						 William Hubbs
						William Hubbs
					
				
			
			
				
	
			
			
			
						parent
						
							0b9c3c0803
						
					
				
				
					commit
					863e1a5c87
				
			| @@ -107,7 +107,8 @@ static RC_STRINGLIST *deptypes_mwua;	/* need+want+use+after deps for stopping */ | ||||
| static void | ||||
| handle_signal(int sig) | ||||
| { | ||||
| 	int serrno = errno; | ||||
| 	int serrno = errno, status; | ||||
| 	pid_t pid; | ||||
| 	const char *signame = NULL; | ||||
| 	struct winsize ws; | ||||
|  | ||||
| @@ -117,12 +118,13 @@ handle_signal(int sig) | ||||
| 		break; | ||||
|  | ||||
| 	case SIGCHLD: | ||||
| 		if (signal_pipe[1] > -1) { | ||||
| 			if (write(signal_pipe[1], &sig, sizeof(sig)) == -1) | ||||
| 				eerror("%s: send: %s", | ||||
| 				    service, strerror(errno)); | ||||
| 		} else | ||||
| 			rc_waitpid(-1); | ||||
| 		while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { | ||||
| 			if (signal_pipe[1] > -1 && pid == service_pid) { | ||||
| 				if (write(signal_pipe[1], &status, sizeof(status)) == -1) | ||||
| 					eerror("%s: send: %s", | ||||
| 					    service, strerror(errno)); | ||||
| 			} | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case SIGWINCH: | ||||
| @@ -438,6 +440,7 @@ svc_exec(const char *arg1, const char *arg2) | ||||
| 			if (errno != EINTR) { | ||||
| 				eerror("%s: poll: %s", | ||||
| 				    service, strerror(errno)); | ||||
| 				ret = -1; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| @@ -448,9 +451,20 @@ svc_exec(const char *arg1, const char *arg2) | ||||
| 				write_prefix(buffer, bytes, &prefixed); | ||||
| 			} | ||||
|  | ||||
| 			/* Only SIGCHLD signals come down this pipe */ | ||||
| 			if (fd[0].revents & (POLLIN | POLLHUP)) | ||||
| 			/* signal_pipe receives service_pid's exit status */ | ||||
| 			if (fd[0].revents & (POLLIN | POLLHUP)) { | ||||
| 				if ((s = read(signal_pipe[0], &ret, sizeof(ret))) != sizeof(ret)) { | ||||
| 					eerror("%s: receive failed: %s", service, | ||||
| 						s < 0 ? strerror(errno) : "short read"); | ||||
| 					ret = -1; | ||||
| 					break; | ||||
| 				} | ||||
| 				ret = WEXITSTATUS(ret); | ||||
| 				if (ret != 0 && errno == ECHILD) | ||||
| 					/* killall5 -9 could cause this */ | ||||
| 					ret = 0; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -473,11 +487,6 @@ svc_exec(const char *arg1, const char *arg2) | ||||
| 		master_tty = -1; | ||||
| 	} | ||||
|  | ||||
| 	ret = rc_waitpid(service_pid); | ||||
| 	ret = WEXITSTATUS(ret); | ||||
| 	if (ret != 0 && errno == ECHILD) | ||||
| 		/* killall5 -9 could cause this */ | ||||
| 		ret = 0; | ||||
| 	service_pid = 0; | ||||
|  | ||||
| 	return ret; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user