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
					
				
			
			
				
	
			
			
			
						parent
						
							0b9c3c0803
						
					
				
				
					commit
					863e1a5c87
				
			@@ -107,7 +107,8 @@ static RC_STRINGLIST *deptypes_mwua;	/* need+want+use+after deps for stopping */
 | 
				
			|||||||
static void
 | 
					static void
 | 
				
			||||||
handle_signal(int sig)
 | 
					handle_signal(int sig)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int serrno = errno;
 | 
						int serrno = errno, status;
 | 
				
			||||||
 | 
						pid_t pid;
 | 
				
			||||||
	const char *signame = NULL;
 | 
						const char *signame = NULL;
 | 
				
			||||||
	struct winsize ws;
 | 
						struct winsize ws;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -117,12 +118,13 @@ handle_signal(int sig)
 | 
				
			|||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SIGCHLD:
 | 
						case SIGCHLD:
 | 
				
			||||||
		if (signal_pipe[1] > -1) {
 | 
							while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
 | 
				
			||||||
			if (write(signal_pipe[1], &sig, sizeof(sig)) == -1)
 | 
								if (signal_pipe[1] > -1 && pid == service_pid) {
 | 
				
			||||||
 | 
									if (write(signal_pipe[1], &status, sizeof(status)) == -1)
 | 
				
			||||||
					eerror("%s: send: %s",
 | 
										eerror("%s: send: %s",
 | 
				
			||||||
					    service, strerror(errno));
 | 
										    service, strerror(errno));
 | 
				
			||||||
		} else
 | 
								}
 | 
				
			||||||
			rc_waitpid(-1);
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SIGWINCH:
 | 
						case SIGWINCH:
 | 
				
			||||||
@@ -438,6 +440,7 @@ svc_exec(const char *arg1, const char *arg2)
 | 
				
			|||||||
			if (errno != EINTR) {
 | 
								if (errno != EINTR) {
 | 
				
			||||||
				eerror("%s: poll: %s",
 | 
									eerror("%s: poll: %s",
 | 
				
			||||||
				    service, strerror(errno));
 | 
									    service, strerror(errno));
 | 
				
			||||||
 | 
									ret = -1;
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -448,10 +451,21 @@ svc_exec(const char *arg1, const char *arg2)
 | 
				
			|||||||
				write_prefix(buffer, bytes, &prefixed);
 | 
									write_prefix(buffer, bytes, &prefixed);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Only SIGCHLD signals come down this pipe */
 | 
								/* signal_pipe receives service_pid's exit status */
 | 
				
			||||||
			if (fd[0].revents & (POLLIN | POLLHUP))
 | 
								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;
 | 
										break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
									ret = WEXITSTATUS(ret);
 | 
				
			||||||
 | 
									if (ret != 0 && errno == ECHILD)
 | 
				
			||||||
 | 
										/* killall5 -9 could cause this */
 | 
				
			||||||
 | 
										ret = 0;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(buffer);
 | 
						free(buffer);
 | 
				
			||||||
@@ -473,11 +487,6 @@ svc_exec(const char *arg1, const char *arg2)
 | 
				
			|||||||
		master_tty = -1;
 | 
							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;
 | 
						service_pid = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user