#NAME ": " FMT, __VA_ARGS__);
# endif
+/* Specific error values for use in forwarding programs such as
+ * virt-login-shell; these values match what GNU env does. */
+enum {
+ EXIT_CANCELED = 125, /* Failed before attempting exec */
+ EXIT_CANNOT_INVOKE = 126, /* Exists but couldn't exec */
+ EXIT_ENOENT = 127, /* Could not find program to exec */
+};
#endif /* __VIR_INTERNAL_H__ */
/*
* vircommand.c: Child command execution
*
- * Copyright (C) 2010-2013 Red Hat, Inc.
+ * Copyright (C) 2010-2014 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* @pid - a pointer to a pid_t that will receive the return value from
* fork()
*
- * fork a new process while avoiding various race/deadlock conditions
+ * Wrapper around fork() that avoids various race/deadlock conditions.
*
* on return from virFork(), if *pid < 0, the fork failed and there is
* no new process. Otherwise, just like fork(), if *pid == 0, it is the
* Even if *pid >= 0, if the return value from virFork() is < 0, it
* indicates a failure that occurred in the parent or child process
* after the fork. In this case, the child process should call
- * _exit(EXIT_FAILURE) after doing any additional error reporting.
+ * _exit(EXIT_CANCELED) after doing any additional error reporting.
*/
int
virFork(pid_t *pid)
if (pthread_sigmask(SIG_SETMASK, &newmask, NULL) != 0) {
saved_errno = errno; /* save for caller */
virReportSystemError(errno, "%s", _("cannot unblock signals"));
- goto cleanup;
+ virDispatchError(NULL);
+ _exit(EXIT_CANCELED);
}
ret = 0;
}
/* child */
+ ret = EXIT_CANCELED;
if (forkRet < 0) {
/* The fork was successful, but after that there was an error
* in the child (which was already logged).
cmd->pidfile, pid);
goto fork_error;
}
- _exit(0);
+ _exit(EXIT_SUCCESS);
}
}
else
execv(binary, cmd->args);
+ ret = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
virReportSystemError(errno,
_("cannot execute binary %s"),
cmd->args[0]);
fork_error:
virDispatchError(NULL);
- _exit(EXIT_FAILURE);
+ _exit(ret);
cleanup:
/* This is cleanup of parent process only - child
/*
* commandtest.c: Test the libCommand API
*
- * Copyright (C) 2010-2013 Red Hat, Inc.
+ * Copyright (C) 2010-2014 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
cmd = virCommandNew(abs_builddir "/commandhelper-doesnotexist");
if (virCommandRun(cmd, &status) < 0)
goto cleanup;
- if (status == 0)
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_ENOENT)
goto cleanup;
ret = 0;
return ret;
}
+static int
+test22(const void *unused ATTRIBUTE_UNUSED)
+{
+ int ret = -1;
+ virCommandPtr cmd;
+ int status = -1;
+
+ cmd = virCommandNewArgList("/bin/sh", "-c", "exit 3", NULL);
+
+ if (virCommandRun(cmd, &status) < 0) {
+ virErrorPtr err = virGetLastError();
+ printf("Cannot run child %s\n", err->message);
+ goto cleanup;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 3) {
+ printf("Unexpected status %d\n", status);
+ goto cleanup;
+ }
+
+ virCommandFree(cmd);
+ cmd = virCommandNewArgList("/bin/sh", "-c", "kill -9 $$", NULL);
+
+ if (virCommandRun(cmd, &status) < 0) {
+ virErrorPtr err = virGetLastError();
+ printf("Cannot run child %s\n", err->message);
+ goto cleanup;
+ }
+ if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL) {
+ printf("Unexpected status %d\n", status);
+ goto cleanup;
+ }
+
+ ret = 0;
+cleanup:
+ virCommandFree(cmd);
+ return ret;
+}
+
static void virCommandThreadWorker(void *opaque)
{
virCommandTestDataPtr test = opaque;
DO_TEST(test19);
DO_TEST(test20);
DO_TEST(test21);
+ DO_TEST(test22);
virMutexLock(&test->lock);
if (test->running) {