libbb: introduce and use BB_EXECVP_or_die()

function                                             old     new   delta
BB_EXECVP_or_die                                       -      47     +47
time_main                                           1042    1043      +1
chrt_main                                            371     364      -7
ionice_main                                          292     282     -10
setsid_main                                           69      56     -13
nohup_main                                           236     223     -13
cttyhack_main                                        266     253     -13
chroot_main                                           94      81     -13
chpst_main                                           746     733     -13
timeout_main                                         297     279     -18
taskset_main                                         541     522     -19
vfork_child                                           67      45     -22
parse                                                975     953     -22
lpd_main                                             770     748     -22
launch_helper                                        192     170     -22
tcpudpsvd_main                                      1810    1782     -28
nice_main                                            190     156     -34
env_main                                             242     206     -36
run_command                                          221     174     -47
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/17 up/down: 48/-352)         Total: -304 bytes

Signed-off-by: Pascal Bellard <pascal.bellard@ads-lu.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/console-tools/openvt.c b/console-tools/openvt.c
index 6f58916..e3ea71b 100644
--- a/console-tools/openvt.c
+++ b/console-tools/openvt.c
@@ -97,8 +97,7 @@
 		//bb_error_msg("our pgrp %d", getpgrp());
 		//bb_error_msg("VT's sid %d", tcgetsid(0));
 		//bb_error_msg("VT's pgrp %d", tcgetpgrp(0));
-		BB_EXECVP(argv[0], argv);
-		bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+		BB_EXECVP_or_die(argv);
 	}
 }
 
diff --git a/coreutils/chroot.c b/coreutils/chroot.c
index bc0b1f8..046c2fa 100644
--- a/coreutils/chroot.c
+++ b/coreutils/chroot.c
@@ -30,6 +30,5 @@
 		argv[1] = (char *) "-i";
 	}
 
-	BB_EXECVP(argv[0], argv);
-	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+	BB_EXECVP_or_die(argv);
 }
diff --git a/coreutils/env.c b/coreutils/env.c
index c6ba04d..d4eab19 100644
--- a/coreutils/env.c
+++ b/coreutils/env.c
@@ -77,10 +77,7 @@
 	}
 
 	if (argv[0]) {
-		BB_EXECVP(argv[0], argv);
-		/* SUSv3-mandated exit codes. */
-		xfunc_error_retval = (errno == ENOENT) ? 127 : 126;
-		bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+		BB_EXECVP_or_die(argv);
 	}
 
 	if (environ) { /* clearenv() may set environ == NULL! */
diff --git a/coreutils/nice.c b/coreutils/nice.c
index 0f70f10..ff3eb11 100644
--- a/coreutils/nice.c
+++ b/coreutils/nice.c
@@ -47,8 +47,5 @@
 		}
 	}
 
-	BB_EXECVP(argv[0], argv);
-	/* The exec failed... */
-	xfunc_error_retval = (errno == ENOENT) ? 127 : 126; /* SUSv3 */
-	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+	BB_EXECVP_or_die(argv);
 }
diff --git a/coreutils/nohup.c b/coreutils/nohup.c
index 1027ada..3dc5314 100644
--- a/coreutils/nohup.c
+++ b/coreutils/nohup.c
@@ -76,6 +76,5 @@
 	signal(SIGHUP, SIG_IGN);
 
 	argv++;
-	BB_EXECVP(argv[0], argv);
-	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+	BB_EXECVP_or_die(argv);
 }
diff --git a/include/libbb.h b/include/libbb.h
index e260017..4b6699f 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -839,6 +839,7 @@
 #define BB_EXECVP(prog,cmd)     execvp(prog,cmd)
 #define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__)
 #endif
+int BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC;
 
 /* NOMMU friendy fork+exec: */
 pid_t spawn(char **argv) FAST_FUNC;
diff --git a/libbb/execable.c b/libbb/execable.c
index 5c7ac16..82241cd 100644
--- a/libbb/execable.c
+++ b/libbb/execable.c
@@ -76,3 +76,11 @@
 					argv);
 }
 #endif
+
+int FAST_FUNC BB_EXECVP_or_die(char **argv)
+{
+	BB_EXECVP(argv[0], argv);
+	/* SUSv3-mandated exit codes */
+	xfunc_error_retval = (errno == ENOENT) ? 127 : 126;
+	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+}
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 082f0f6..8102ea2 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -67,40 +67,6 @@
 	return pid;
 }
 
-pid_t FAST_FUNC safe_waitpid(pid_t pid, int *wstat, int options)
-{
-	pid_t r;
-
-	do
-		r = waitpid(pid, wstat, options);
-	while ((r == -1) && (errno == EINTR));
-	return r;
-}
-
-pid_t FAST_FUNC wait_any_nohang(int *wstat)
-{
-	return safe_waitpid(-1, wstat, WNOHANG);
-}
-
-// Wait for the specified child PID to exit, returning child's error return.
-int FAST_FUNC wait4pid(pid_t pid)
-{
-	int status;
-
-	if (pid <= 0) {
-		/*errno = ECHILD; -- wrong. */
-		/* we expect errno to be already set from failed [v]fork/exec */
-		return -1;
-	}
-	if (safe_waitpid(pid, &status, 0) == -1)
-		return -1;
-	if (WIFEXITED(status))
-		return WEXITSTATUS(status);
-	if (WIFSIGNALED(status))
-		return WTERMSIG(status) + 0x180;
-	return 0;
-}
-
 #if ENABLE_FEATURE_PREFER_APPLETS
 void FAST_FUNC save_nofork_data(struct nofork_save_area *save)
 {
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index 6543721..275dd4b 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -268,3 +268,37 @@
 {
 	return tcsetattr(STDIN_FILENO, TCSANOW, tp);
 }
+
+pid_t FAST_FUNC safe_waitpid(pid_t pid, int *wstat, int options)
+{
+	pid_t r;
+
+	do
+		r = waitpid(pid, wstat, options);
+	while ((r == -1) && (errno == EINTR));
+	return r;
+}
+
+pid_t FAST_FUNC wait_any_nohang(int *wstat)
+{
+	return safe_waitpid(-1, wstat, WNOHANG);
+}
+
+// Wait for the specified child PID to exit, returning child's error return.
+int FAST_FUNC wait4pid(pid_t pid)
+{
+	int status;
+
+	if (pid <= 0) {
+		/*errno = ECHILD; -- wrong. */
+		/* we expect errno to be already set from failed [v]fork/exec */
+		return -1;
+	}
+	if (safe_waitpid(pid, &status, 0) == -1)
+		return -1;
+	if (WIFEXITED(status))
+		return WEXITSTATUS(status);
+	if (WIFSIGNALED(status))
+		return WTERMSIG(status) + 0x180;
+	return 0;
+}
diff --git a/mailutils/mail.c b/mailutils/mail.c
index 49e72c3..5eb99e1 100644
--- a/mailutils/mail.c
+++ b/mailutils/mail.c
@@ -67,8 +67,7 @@
 	if (!G.helper_pid) {
 		// child: try to execute connection helper
 		// NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec
-		BB_EXECVP(argv[0], (char **)argv);
-		bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+		BB_EXECVP_or_die((char**)argv);
 	}
 
 	// parent
diff --git a/mailutils/mime.c b/mailutils/mime.c
index 654b873..5eb8ef6 100644
--- a/mailutils/mime.c
+++ b/mailutils/mime.c
@@ -288,8 +288,7 @@
 					xsetenv("CHARSET", charset);
 					xsetenv("ENCODING", encoding);
 					xsetenv("FILENAME", filename);
-					BB_EXECVP(argv[0], argv);
-					bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+					BB_EXECVP_or_die(argv);
 				}
 				// parent dumps to fd[1]
 				close(fd[0]);
diff --git a/miscutils/chrt.c b/miscutils/chrt.c
index 3d0da58..d5f87c4 100644
--- a/miscutils/chrt.c
+++ b/miscutils/chrt.c
@@ -120,6 +120,5 @@
 	if (!argv[0]) /* "-p <priority> <pid> [...]" */
 		goto print_rt_info;
 
-	BB_EXECVP(argv[0], argv);
-	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+	BB_EXECVP_or_die(argv);
 }
diff --git a/miscutils/ionice.c b/miscutils/ionice.c
index 8393cd8..52e51b9 100644
--- a/miscutils/ionice.c
+++ b/miscutils/ionice.c
@@ -90,8 +90,7 @@
 		if (ioprio_set(IOPRIO_WHO_PROCESS, pid, pri) == -1)
 			bb_perror_msg_and_die("ioprio_%cet", 's');
 		if (argv[0]) {
-			BB_EXECVP(argv[0], argv);
-			bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+			BB_EXECVP_or_die(argv);
 		}
 	}
 
diff --git a/miscutils/setsid.c b/miscutils/setsid.c
index 60ee062..c573fae 100644
--- a/miscutils/setsid.c
+++ b/miscutils/setsid.c
@@ -45,6 +45,5 @@
 	}
 
 	argv++;
-	BB_EXECVP(argv[0], argv);
-	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+	BB_EXECVP_or_die(argv);
 }
diff --git a/miscutils/taskset.c b/miscutils/taskset.c
index 2891003..08198d5 100644
--- a/miscutils/taskset.c
+++ b/miscutils/taskset.c
@@ -132,6 +132,5 @@
 	if (!argv[0]) /* "-p <aff> <pid> [...ignored...]" */
 		goto print_aff; /* print new affinity and exit */
 
-	BB_EXECVP(argv[0], argv);
-	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+	BB_EXECVP_or_die(argv);
 }
diff --git a/miscutils/time.c b/miscutils/time.c
index f5d1e15..5cfbcef 100644
--- a/miscutils/time.c
+++ b/miscutils/time.c
@@ -367,20 +367,17 @@
    Put the statistics in *RESP.  */
 static void run_command(char *const *cmd, resource_t *resp)
 {
-	pid_t pid;			/* Pid of child.  */
+	pid_t pid;
 	void (*interrupt_signal)(int);
 	void (*quit_signal)(int);
 
 	resp->elapsed_ms = monotonic_ms();
-	pid = vfork();		/* Run CMD as child process.  */
+	pid = vfork();
 	if (pid < 0)
-		bb_perror_msg_and_die("fork");
-	if (pid == 0) {	/* If child.  */
-		/* Don't cast execvp arguments; that causes errors on some systems,
-		   versus merely warnings if the cast is left off.  */
-		BB_EXECVP(cmd[0], cmd);
-		xfunc_error_retval = (errno == ENOENT ? 127 : 126);
-		bb_perror_msg_and_die("can't execute '%s'", cmd[0]);
+		bb_perror_msg_and_die("vfork");
+	if (pid == 0) {
+		/* Child */
+		BB_EXECVP_or_die((char**)cmd);
 	}
 
 	/* Have signals kill the child but not self (if possible).  */
diff --git a/miscutils/timeout.c b/miscutils/timeout.c
index 273d269..f6e655a 100644
--- a/miscutils/timeout.c
+++ b/miscutils/timeout.c
@@ -110,6 +110,5 @@
 	argv[0] = sv1;
 	argv[1] = sv2;
 #endif
-	BB_EXECVP(argv[0], argv);
-	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+	BB_EXECVP_or_die(argv);
 }
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index 714d2a1..1bab2c5 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -1052,8 +1052,7 @@
 		close(outfd.rd);
 		xmove_fd(infd.rd, 0);
 		xmove_fd(outfd.wr, 1);
-		BB_EXECVP(command, argv);
-		bb_perror_msg_and_die("can't execute '%s'", command);
+		BB_EXECVP_or_die(argv);
 	}
 	/* parent */
 	close(infd.rd);
diff --git a/networking/tcpudp.c b/networking/tcpudp.c
index 4e47567..53e622b 100644
--- a/networking/tcpudp.c
+++ b/networking/tcpudp.c
@@ -501,10 +501,10 @@
 #ifdef SSLSVD
 	strcpy(id, utoa(pid));
 	ssl_io(0, argv);
-#else
-	BB_EXECVP(argv[0], argv);
-#endif
 	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+#else
+	BB_EXECVP_or_die(argv);
+#endif
 }
 
 /*
diff --git a/printutils/lpd.c b/printutils/lpd.c
index 15f1ba2..d91491f 100644
--- a/printutils/lpd.c
+++ b/printutils/lpd.c
@@ -181,8 +181,7 @@
 			// this call reopens stdio fds to "/dev/null"
 			// (no daemonization is done)
 			bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL);
-			BB_EXECVP(argv[0], argv);
-			bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+			BB_EXECVP_or_die(argv);
 		}
 
 		// validate input.
diff --git a/runit/chpst.c b/runit/chpst.c
index 028a28d..ad08112 100644
--- a/runit/chpst.c
+++ b/runit/chpst.c
@@ -382,6 +382,5 @@
 	if (opt & OPT_2)
 		close(STDERR_FILENO);
 
-	BB_EXECVP(argv[0], argv);
-	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+	BB_EXECVP_or_die(argv);
 }
diff --git a/shell/cttyhack.c b/shell/cttyhack.c
index bde2acd..67736ad 100644
--- a/shell/cttyhack.c
+++ b/shell/cttyhack.c
@@ -81,6 +81,5 @@
 		}
 	}
 
-	BB_EXECVP(argv[0], argv);
-	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+	BB_EXECVP_or_die(argv);
 }