libvirt/src/util/virdaemon.c
Rafael Fonseca c360ea28dc util: virdaemon: fix compilation on mingw
The daemons are not supported on Win32 and therefore were not compiled
in that platform. However, with the daemon code sharing, all the code in
utils *is* compiled and it failed because `waitpid`, `fork`, and
`setsid` are not available. So, as before, let's not build them on
Win32 and make the code more portable by using existing vir* wrappers.

Signed-off-by: Rafael Fonseca <r4f4rfs@gmail.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2020-03-30 09:48:22 +02:00

289 lines
8.6 KiB
C

/*
* virdaemon.c: shared daemon setup code
*
* Copyright (C) 2020 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
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdbool.h>
#include "virdaemon.h"
#include "virutil.h"
#include "virfile.h"
#include "virlog.h"
#include "viralloc.h"
#include "virprocess.h"
#include "vircommand.h"
#include "configmake.h"
#ifndef WIN32
int
virDaemonForkIntoBackground(const char *argv0)
{
int statuspipe[2];
if (virPipeQuiet(statuspipe) < 0)
return -1;
pid_t pid = virFork();
switch (pid) {
case 0:
{
/* intermediate child */
int stdinfd = -1;
int stdoutfd = -1;
int nextpid;
VIR_FORCE_CLOSE(statuspipe[0]);
if ((stdinfd = open("/dev/null", O_RDONLY)) < 0)
goto cleanup;
if ((stdoutfd = open("/dev/null", O_WRONLY)) < 0)
goto cleanup;
if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
goto cleanup;
if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
goto cleanup;
if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
goto cleanup;
if (VIR_CLOSE(stdinfd) < 0)
goto cleanup;
if (VIR_CLOSE(stdoutfd) < 0)
goto cleanup;
if (setsid() < 0)
goto cleanup;
nextpid = virFork();
switch (nextpid) {
case 0: /* grandchild */
return statuspipe[1];
case -1: /* error */
goto cleanup;
default: /* intermediate child succeeded */
_exit(EXIT_SUCCESS);
}
cleanup:
VIR_FORCE_CLOSE(stdoutfd);
VIR_FORCE_CLOSE(stdinfd);
VIR_FORCE_CLOSE(statuspipe[1]);
_exit(EXIT_FAILURE);
}
case -1: /* error in parent */
goto error;
default:
{
/* parent */
int got, exitstatus = 0;
int ret;
char status;
VIR_FORCE_CLOSE(statuspipe[1]);
/* We wait to make sure the first child forked successfully */
if ((got = virProcessWait(pid, &exitstatus, 0)) < 0 ||
got != pid ||
exitstatus != 0) {
goto error;
}
/* If we got here, then the grandchild was spawned, so we
* must exit. Block until the second child initializes
* successfully */
ret = saferead(statuspipe[0], &status, 1);
VIR_FORCE_CLOSE(statuspipe[0]);
if (ret != 1) {
fprintf(stderr,
_("%s: error: unable to determine if daemon is "
"running: %s\n"), argv0,
g_strerror(errno));
exit(EXIT_FAILURE);
} else if (status != 0) {
fprintf(stderr,
_("%s: error: %s. Check /var/log/messages or run without "
"--daemon for more info.\n"), argv0,
virDaemonErrTypeToString(status));
exit(EXIT_FAILURE);
}
_exit(EXIT_SUCCESS);
}
}
error:
VIR_FORCE_CLOSE(statuspipe[0]);
VIR_FORCE_CLOSE(statuspipe[1]);
return -1;
}
/*
* Set up the logging environment
* By default if daemonized all errors go to the logfile libvirtd.log,
* but if verbose or error debugging is asked for then also output
* informational and debug messages. Default size if 64 kB.
*/
void
virDaemonSetupLogging(const char *daemon_name,
unsigned int log_level,
char *log_filters,
char *log_outputs,
bool privileged,
bool verbose,
bool godaemon)
{
virLogReset();
/*
* Libvirtd's order of precedence is:
* cmdline > environment > config
*
* Given the precedence, we must process the variables in the opposite
* order, each one overriding the previous.
*/
if (log_level != 0)
virLogSetDefaultPriority(log_level);
/* In case the config is empty, both filters and outputs will become empty,
* however we can't start with empty outputs, thus we'll need to define and
* setup a default one.
*/
ignore_value(virLogSetFilters(log_filters));
ignore_value(virLogSetOutputs(log_outputs));
/* If there are some environment variables defined, use those instead */
virLogSetFromEnv();
/*
* Command line override for --verbose
*/
if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
virLogSetDefaultPriority(VIR_LOG_INFO);
/* Define the default output. This is only applied if there was no setting
* from either the config or the environment.
*/
virLogSetDefaultOutput(daemon_name, godaemon, privileged);
if (virLogGetNbOutputs() == 0)
virLogSetOutputs(virLogGetDefaultOutput());
}
int
virDaemonUnixSocketPaths(const char *sock_prefix,
bool privileged,
char *unix_sock_dir,
char **sockfile,
char **rosockfile,
char **admsockfile)
{
int ret = -1;
char *rundir = NULL;
if (unix_sock_dir) {
if (sockfile)
*sockfile = g_strdup_printf("%s/%s-sock", unix_sock_dir, sock_prefix);
if (privileged) {
if (rosockfile)
*rosockfile = g_strdup_printf("%s/%s-sock-ro",
unix_sock_dir, sock_prefix);
if (admsockfile)
*admsockfile = g_strdup_printf("%s/%s-admin-sock",
unix_sock_dir, sock_prefix);
}
} else {
if (privileged) {
if (sockfile)
*sockfile = g_strdup_printf("%s/libvirt/%s-sock",
RUNSTATEDIR, sock_prefix);
if (rosockfile)
*rosockfile = g_strdup_printf("%s/libvirt/%s-sock-ro",
RUNSTATEDIR, sock_prefix);
if (admsockfile)
*admsockfile = g_strdup_printf("%s/libvirt/%s-admin-sock",
RUNSTATEDIR, sock_prefix);
} else {
mode_t old_umask;
rundir = virGetUserRuntimeDirectory();
old_umask = umask(077);
if (virFileMakePath(rundir) < 0) {
umask(old_umask);
goto cleanup;
}
umask(old_umask);
if (sockfile)
*sockfile = g_strdup_printf("%s/%s-sock", rundir, sock_prefix);
if (admsockfile)
*admsockfile = g_strdup_printf("%s/%s-admin-sock", rundir, sock_prefix);
}
}
ret = 0;
cleanup:
VIR_FREE(rundir);
return ret;
}
#else /* WIN32 */
int virDaemonForkIntoBackground(const char *argv0 G_GNUC_UNUSED)
{
errno = ENOTSUP;
return -1;
}
void virDaemonSetupLogging(const char *daemon_name G_GNUC_UNUSED,
unsigned int log_level G_GNUC_UNUSED,
char *log_filters G_GNUC_UNUSED,
char *log_outputs G_GNUC_UNUSED,
bool privileged G_GNUC_UNUSED,
bool verbose G_GNUC_UNUSED,
bool godaemon G_GNUC_UNUSED)
{
/* NOOP */
errno = ENOTSUP;
return;
}
int virDaemonUnixSocketPaths(const char *sock_prefix G_GNUC_UNUSED,
bool privileged G_GNUC_UNUSED,
char *unix_sock_dir G_GNUC_UNUSED,
char **sockfile G_GNUC_UNUSED,
char **rosockfile G_GNUC_UNUSED,
char **adminSockfile G_GNUC_UNUSED)
{
errno = ENOTSUP;
return -1;
}
#endif /* WIN32 */