summaryrefslogtreecommitdiffstats
path: root/sys-utils/nsenter.c
diff options
context:
space:
mode:
authorEric W. Biederman2013-01-17 01:34:17 +0100
committerKarel Zak2013-01-17 13:17:35 +0100
commitc9515f86d461e8d341b9c222ffba7f4cf5e65a51 (patch)
treec886e1e4ebe814bb8e35fef19e00be6f2bb4c329 /sys-utils/nsenter.c
parentunshare: Add support for the pid and user namespaces (diff)
downloadkernel-qcow2-util-linux-c9515f86d461e8d341b9c222ffba7f4cf5e65a51.tar.gz
kernel-qcow2-util-linux-c9515f86d461e8d341b9c222ffba7f4cf5e65a51.tar.xz
kernel-qcow2-util-linux-c9515f86d461e8d341b9c222ffba7f4cf5e65a51.zip
nsenter: Enhance waiting for a child process
In the case of a pid namespace we need to fork a child process instead of calling exec. Move all of that logic out of line into a function continue_as_child, making the logic of the primary case easier to understand. Update the logic for waiting for a child process to suspend ourselves when the child processes suspends and to continue the child process when we are unsuspsended. This supports the bash suspend command and various editors that suspend themselves. If the child process exits with a signal update the logic to run kill(getpid(), WTERMSIG(status)) so the caller sees the same exit code that nsenter observed. There will always be permission to send signals to our children and the tty is not changing so there is no need for the intermediate process to forward signals to it's child. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'sys-utils/nsenter.c')
-rw-r--r--sys-utils/nsenter.c48
1 files changed, 35 insertions, 13 deletions
diff --git a/sys-utils/nsenter.c b/sys-utils/nsenter.c
index f9c663648..a264515eb 100644
--- a/sys-utils/nsenter.c
+++ b/sys-utils/nsenter.c
@@ -145,6 +145,39 @@ static void open_namespace_fd(int nstype, char *path)
err(EXIT_FAILURE, "Unrecognized namespace type");
}
+static void continue_as_child(void)
+{
+ pid_t child = fork();
+ int status;
+ pid_t ret;
+
+ if (child < 0)
+ err(EXIT_FAILURE, _("fork failed"));
+
+ /* Only the child returns */
+ if (child == 0)
+ return;
+
+ for (;;) {
+ ret = waitpid(child, &status, WUNTRACED);
+ if ((ret == child) && (WIFSTOPPED(status))) {
+ /* The child suspended so suspend us as well */
+ kill(getpid(), SIGSTOP);
+ kill(child, SIGCONT);
+ } else {
+ break;
+ }
+ }
+ /* Return the child's exit code if possible */
+ if (WIFEXITED(status)) {
+ exit(WEXITSTATUS(status));
+ }
+ else if (WIFSIGNALED(status)) {
+ kill(getpid(), WTERMSIG(status));
+ }
+ exit(EXIT_FAILURE);
+}
+
int main(int argc, char *argv[])
{
static const struct option longopts[] = {
@@ -266,19 +299,8 @@ int main(int argc, char *argv[])
wd_fd = -1;
}
- if (do_fork) {
- pid_t child = fork();
- if (child < 0)
- err(EXIT_FAILURE, _("fork failed"));
- if (child != 0) {
- int status;
- if ((waitpid(child, &status, 0) == child) &&
- WIFEXITED(status)) {
- exit(WEXITSTATUS(status));
- }
- exit(EXIT_FAILURE);
- }
- }
+ if (do_fork)
+ continue_as_child();
execvp(argv[optind], argv + optind);