[libvirt] [PATCH v2 02/13] Import stripped down virtlockd code as basis of virtlogd

John Ferlan jferlan at redhat.com
Wed Nov 18 16:11:44 UTC 2015



On 11/12/2015 12:18 PM, Daniel P. Berrange wrote:
> Copy the virtlockd codebase across to form the initial virlogd
> code. Simple search & replace of s/lock/log/ and gut the remote
> protocol & dispatcher. This gives us a daemon that starts up
> and listens for connections, but does nothing with them.
> 
> Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
> ---
>  .gitignore                        |    7 +
>  cfg.mk                            |    4 +-
>  include/libvirt/virterror.h       |    1 +
>  libvirt.spec.in                   |   24 +-
>  po/POTFILES.in                    |    2 +
>  src/Makefile.am                   |  169 +++++-
>  src/logging/log_daemon.c          | 1177 +++++++++++++++++++++++++++++++++++++
>  src/logging/log_daemon.h          |   42 ++
>  src/logging/log_daemon_config.c   |  203 +++++++
>  src/logging/log_daemon_config.h   |   50 ++
>  src/logging/log_daemon_dispatch.c |   37 ++
>  src/logging/log_daemon_dispatch.h |   31 +
>  src/logging/log_protocol.x        |   22 +
>  src/logging/test_virtlogd.aug.in  |   12 +
>  src/logging/virtlogd.aug          |   45 ++
>  src/logging/virtlogd.conf         |   67 +++
>  src/logging/virtlogd.init.in      |   94 +++
>  src/logging/virtlogd.pod.in       |  162 +++++
>  src/logging/virtlogd.service.in   |   17 +
>  src/logging/virtlogd.socket.in    |    8 +
>  src/logging/virtlogd.sysconf      |    3 +
>  src/util/virerror.c               |    1 +
>  22 files changed, 2156 insertions(+), 22 deletions(-)
>  create mode 100644 src/logging/log_daemon.c
>  create mode 100644 src/logging/log_daemon.h
>  create mode 100644 src/logging/log_daemon_config.c
>  create mode 100644 src/logging/log_daemon_config.h
>  create mode 100644 src/logging/log_daemon_dispatch.c
>  create mode 100644 src/logging/log_daemon_dispatch.h
>  create mode 100644 src/logging/log_protocol.x
>  create mode 100644 src/logging/test_virtlogd.aug.in
>  create mode 100644 src/logging/virtlogd.aug
>  create mode 100644 src/logging/virtlogd.conf
>  create mode 100644 src/logging/virtlogd.init.in
>  create mode 100644 src/logging/virtlogd.pod.in
>  create mode 100644 src/logging/virtlogd.service.in
>  create mode 100644 src/logging/virtlogd.socket.in
>  create mode 100644 src/logging/virtlogd.sysconf
> 

Full disclosure - the aspects of Makefiles, cfg files, spec files, etc.
- not my area of expertise... Looks like things were copied correctly
though and it does build... Whether it builds on all platforms for all
strange variants of make - I'll leave to existing build processes...

[...]

Hopefully some assumptions can be made regarding how much of this is
copied from lockd ;-)

> diff --git a/src/logging/log_daemon.c b/src/logging/log_daemon.c
> new file mode 100644
> index 0000000..184076c
> --- /dev/null
> +++ b/src/logging/log_daemon.c
> @@ -0,0 +1,1177 @@
> +/*
> + * log_daemon.c: log management daemon
> + *
> + * Copyright (C) 2006-2015 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/>.
> + *
> + * Author: Daniel P. Berrange <berrange at redhat.com>
> + */

[...]

> +static void
> +virLogDaemonFree(virLogDaemonPtr logd)
> +{
> +    if (!logd)
> +        return;

Should there be a virMutexDestroy(logd->lock); ?  If so, it's also
missing from lockd

> +
> +    virObjectUnref(logd->srv);
> +    virObjectUnref(logd->dmn);
> +
> +    VIR_FREE(logd);
> +}
> +
> +

[...]

> +
> +static int
> +virLogDaemonUnixSocketPaths(bool privileged,
> +                            char **sockfile)
> +{
> +    if (privileged) {
> +        if (VIR_STRDUP(*sockfile, LOCALSTATEDIR "/run/libvirt/virtlogd-sock") < 0)
> +            goto error;
> +    } else {
> +        char *rundir = NULL;
> +        mode_t old_umask;
> +
> +        if (!(rundir = virGetUserRuntimeDirectory()))
> +            goto error;
> +
> +        old_umask = umask(077);
> +        if (virFileMakePath(rundir) < 0) {
> +            umask(old_umask);

VIR_FREE(rundir);  - I see this is true in lockd too...

> +            goto error;
> +        }
> +        umask(old_umask);
> +
> +        if (virAsprintf(sockfile, "%s/virtlogd-sock", rundir) < 0) {
> +            VIR_FREE(rundir);
> +            goto error;
> +        }
> +
> +        VIR_FREE(rundir);
> +    }
> +    return 0;
> +
> + error:
> +    return -1;
> +}
> +
> +
> +static void
> +virLogDaemonErrorHandler(void *opaque ATTRIBUTE_UNUSED,
> +                         virErrorPtr err ATTRIBUTE_UNUSED)
> +{
> +    /* Don't do anything, since logging infrastructure already
> +     * took care of reporting the error */
> +}
> +
> +
> +/*
> + * 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.
> + */
> +static int
> +virLogDaemonSetupLogging(virLogDaemonConfigPtr config,
> +                         bool privileged,
> +                         bool verbose,
> +                         bool godaemon)
> +{
> +    virLogReset();
> +
> +    /*
> +     * Libvirtd's order of precedence is:
> +     * cmdline > environment > config
> +     *
> +     * In order to achieve this, we must process configuration in
> +     * different order for the log level versus the filters and
> +     * outputs. Because filters and outputs append, we have to look at
> +     * the environment first and then only check the config file if
> +     * there was no result from the environment. The default output is
> +     * then applied only if there was no setting from either of the
> +     * first two. Because we don't have a way to determine if the log
> +     * level has been set, we must process variables in the opposite
> +     * order, each one overriding the previous.
> +     */
> +    if (config->log_level != 0)
> +        virLogSetDefaultPriority(config->log_level);
> +
> +    virLogSetFromEnv();
> +
> +    if (virLogGetNbFilters() == 0)
> +        virLogParseFilters(config->log_filters);
> +
> +    if (virLogGetNbOutputs() == 0)
> +        virLogParseOutputs(config->log_outputs);
> +
> +    /*
> +     * If no defined outputs, and either running
> +     * as daemon or not on a tty, then first try
> +     * to direct it to the systemd journal
> +     * (if it exists)....
> +     */
> +    if (virLogGetNbOutputs() == 0 &&
> +        (godaemon || !isatty(STDIN_FILENO))) {
> +        char *tmp;
> +        if (access("/run/systemd/journal/socket", W_OK) >= 0) {
> +            if (virAsprintf(&tmp, "%d:journald", virLogGetDefaultPriority()) < 0)
> +                goto error;
> +            virLogParseOutputs(tmp);
> +            VIR_FREE(tmp);
> +        }
> +    }
> +
> +    /*
> +     * otherwise direct to libvirtd.log when running
> +     * as daemon. Otherwise the default output is stderr.
> +     */
> +    if (virLogGetNbOutputs() == 0) {
> +        char *tmp = NULL;
> +
> +        if (godaemon) {
> +            if (privileged) {
> +                if (virAsprintf(&tmp, "%d:file:%s/log/libvirt/virtlogd.log",
> +                                virLogGetDefaultPriority(),
> +                                LOCALSTATEDIR) == -1)
> +                    goto error;
> +            } else {
> +                char *logdir = virGetUserCacheDirectory();
> +                mode_t old_umask;
> +
> +                if (!logdir)
> +                    goto error;
> +
> +                old_umask = umask(077);
> +                if (virFileMakePath(logdir) < 0) {
> +                    umask(old_umask);

VIR_FREE(logdir);   - same in lockd

> +                    goto error;
> +                }
> +                umask(old_umask);
> +
> +                if (virAsprintf(&tmp, "%d:file:%s/virtlogd.log",
> +                                virLogGetDefaultPriority(), logdir) == -1) {
> +                    VIR_FREE(logdir);
> +                    goto error;
> +                }
> +                VIR_FREE(logdir);
> +            }
> +        } else {
> +            if (virAsprintf(&tmp, "%d:stderr", virLogGetDefaultPriority()) < 0)
> +                goto error;
> +        }
> +        virLogParseOutputs(tmp);
> +        VIR_FREE(tmp);
> +    }
> +
> +    /*
> +     * Command line override for --verbose
> +     */
> +    if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
> +        virLogSetDefaultPriority(VIR_LOG_INFO);
> +
> +    return 0;
> +
> + error:
> +    return -1;
> +}
> +
> +
> +

[...]


> +static void *
> +virLogDaemonClientNew(virNetServerClientPtr client,
> +                      void *opaque)
> +{
> +    virLogDaemonClientPtr priv;
> +    uid_t clientuid;
> +    gid_t clientgid;
> +    unsigned long long timestamp;
> +    bool privileged = opaque != NULL;
> +
> +    if (VIR_ALLOC(priv) < 0)
> +        return NULL;
> +
> +    if (virMutexInit(&priv->lock) < 0) {
> +        VIR_FREE(priv);
> +        virReportSystemError(errno, "%s", _("unable to init mutex"));
> +        return NULL;
> +    }
> +
> +    if (virNetServerClientGetUNIXIdentity(client,
> +                                          &clientuid,
> +                                          &clientgid,
> +                                          &priv->clientPid,
> +                                          &timestamp) < 0)
> +        goto error;
> +
> +    VIR_DEBUG("New client pid %llu uid %llu",
> +              (unsigned long long)priv->clientPid,
> +              (unsigned long long)clientuid);
> +
> +    if (!privileged) {
> +        if (geteuid() != clientuid) {
> +            virReportRestrictedError(_("Disallowing client %llu with uid %llu"),
> +                                     (unsigned long long)priv->clientPid,
> +                                     (unsigned long long)clientuid);
> +            goto error;
> +        }
> +    } else {
> +        if (clientuid != 0) {
> +            virReportRestrictedError(_("Disallowing client %llu with uid %llu"),
> +                                     (unsigned long long)priv->clientPid,
> +                                     (unsigned long long)clientuid);
> +            goto error;
> +        }
> +    }
> +
> +    return priv;
> +
> + error:

Could use virLogDaemonClientFree()

> +    virMutexDestroy(&priv->lock);
> +    VIR_FREE(priv);
> +    return NULL;
> +}
> +
> +

[...]

> +
> +static void
> +virLogDaemonUsage(const char *argv0, bool privileged)
> +{
> +    fprintf(stderr,
> +            _("\n"
> +              "Usage:\n"
> +              "  %s [options]\n"
> +              "\n"
> +              "Options:\n"
> +              "  -h | --help            Display program help:\n"
> +              "  -v | --verbose         Verbose messages.\n"
> +              "  -d | --daemon          Run as a daemon & write PID file.\n"
> +              "  -t | --timeout <secs>  Exit after timeout period.\n"
> +              "  -f | --config <file>   Configuration file.\n"
> +              "  -V | --version         Display version information.\n"
> +              "  -p | --pid-file <file> Change name of PID file.\n"
> +              "\n"
> +              "libvirt lock management daemon:\n"), argv0);

s/lock/log/

> +
> +    if (privileged) {
> +        fprintf(stderr,
> +                _("\n"
> +                  "  Default paths:\n"
> +                  "\n"
> +                  "    Configuration file (unless overridden by -f):\n"
> +                  "      %s/libvirt/virtlogd.conf\n"
> +                  "\n"
> +                  "    Sockets:\n"
> +                  "      %s/run/libvirt/virtlogd-sock\n"
> +                  "\n"
> +                  "    PID file (unless overridden by -p):\n"
> +                  "      %s/run/virtlogd.pid\n"
> +                  "\n"),
> +                SYSCONFDIR,
> +                LOCALSTATEDIR,
> +                LOCALSTATEDIR);
> +    } else {
> +        fprintf(stderr, "%s",
> +                _("\n"
> +                  "  Default paths:\n"
> +                  "\n"
> +                  "    Configuration file (unless overridden by -f):\n"
> +                  "      $XDG_CONFIG_HOME/libvirt/virtlogd.conf\n"
> +                  "\n"
> +                  "    Sockets:\n"
> +                  "      $XDG_RUNTIME_DIR/libvirt/virtlogd-sock\n"
> +                  "\n"
> +                  "    PID file:\n"
> +                  "      $XDG_RUNTIME_DIR/libvirt/virtlogd.pid\n"
> +                  "\n"));
> +    }
> +}
> +
> +#define MAX_LISTEN 5
> +int main(int argc, char **argv) {
> +    virNetServerProgramPtr logProgram = NULL;
> +    char *remote_config_file = NULL;
> +    int statuswrite = -1;
> +    int ret = 1;
> +    int verbose = 0;
> +    int godaemon = 0;
> +    char *run_dir = NULL;
> +    char *pid_file = NULL;
> +    int pid_file_fd = -1;
> +    char *sock_file = NULL;
> +    int timeout = -1;        /* -t: Shutdown timeout */
> +    char *state_file = NULL;
> +    bool implicit_conf = false;
> +    mode_t old_umask;
> +    bool privileged = false;
> +    virLogDaemonConfigPtr config = NULL;
> +    int rv;
> +
> +    struct option opts[] = {
> +        { "verbose", no_argument, &verbose, 'v'},
> +        { "daemon", no_argument, &godaemon, 'd'},
> +        { "config", required_argument, NULL, 'f'},
> +        { "timeout", required_argument, NULL, 't'},
> +        { "pid-file", required_argument, NULL, 'p'},
> +        { "version", no_argument, NULL, 'V' },
> +        { "help", no_argument, NULL, 'h' },
> +        {0, 0, 0, 0}
> +    };
> +
> +    privileged = geteuid() == 0;
> +
> +    if (setlocale(LC_ALL, "") == NULL ||
> +        bindtextdomain(PACKAGE, LOCALEDIR) == NULL ||
> +        textdomain(PACKAGE) == NULL ||
> +        virThreadInitialize() < 0 ||
> +        virErrorInitialize() < 0) {
> +        fprintf(stderr, _("%s: initialization failed\n"), argv[0]);
> +        exit(EXIT_FAILURE);
> +    }
> +
> +    while (1) {
> +        int optidx = 0;
> +        int c;
> +        char *tmp;
> +
> +        c = getopt_long(argc, argv, "ldf:p:t:vVh", opts, &optidx);
                                        ^
Is 'l' valid?  Same for lockd BTW

> +
> +        if (c == -1)
> +            break;
> +
> +        switch (c) {
> +        case 0:
> +            /* Got one of the flags */
> +            break;
> +        case 'v':
> +            verbose = 1;
> +            break;
> +        case 'd':
> +            godaemon = 1;
> +            break;
> +
> +        case 't':
> +            if (virStrToLong_i(optarg, &tmp, 10, &timeout) != 0
> +                || timeout <= 0
> +                /* Ensure that we can multiply by 1000 without overflowing.  */
> +                || timeout > INT_MAX / 1000) {
> +                VIR_ERROR(_("Invalid value for timeout"));
> +                exit(EXIT_FAILURE);
> +            }
> +            break;
> +
> +        case 'p':
> +            VIR_FREE(pid_file);
> +            if (VIR_STRDUP_QUIET(pid_file, optarg) < 0)
> +                goto no_memory;
> +            break;
> +
> +        case 'f':
> +            VIR_FREE(remote_config_file);
> +            if (VIR_STRDUP_QUIET(remote_config_file, optarg) < 0)
> +                goto no_memory;
> +            break;
> +
> +        case 'V':
> +            virLogDaemonVersion(argv[0]);
> +            exit(EXIT_SUCCESS);
> +
> +        case 'h':
> +            virLogDaemonUsage(argv[0], privileged);
> +            exit(EXIT_SUCCESS);
> +
> +        case '?':
> +        default:
> +            virLogDaemonUsage(argv[0], privileged);
> +            exit(EXIT_FAILURE);
> +        }
> +    }
> +
> +    virFileActivateDirOverride(argv[0]);
> +
> +    if (!(config = virLogDaemonConfigNew(privileged))) {
> +        VIR_ERROR(_("Can't create initial configuration"));
> +        exit(EXIT_FAILURE);
> +    }
> +
> +    /* No explicit config, so try and find a default one */
> +    if (remote_config_file == NULL) {
> +        implicit_conf = true;
> +        if (virLogDaemonConfigFilePath(privileged,
> +                                        &remote_config_file) < 0) {
                                          ^
Extra space

> +            VIR_ERROR(_("Can't determine config path"));
> +            exit(EXIT_FAILURE);
> +        }
> +    }
> +
> +    /* Read the config file if it exists*/
> +    if (remote_config_file &&
> +        virLogDaemonConfigLoadFile(config, remote_config_file, implicit_conf) < 0) {
> +        virErrorPtr err = virGetLastError();
> +        if (err && err->message)
> +            VIR_ERROR(_("Can't load config file: %s: %s"),
> +                      err->message, remote_config_file);
> +        else
> +            VIR_ERROR(_("Can't load config file: %s"), remote_config_file);
> +        exit(EXIT_FAILURE);
> +    }
> +
> +    if (virLogDaemonSetupLogging(config, privileged, verbose, godaemon) < 0) {
> +        VIR_ERROR(_("Can't initialize logging"));
> +        exit(EXIT_FAILURE);
> +    }
> +
> +    if (!pid_file &&
> +        virPidFileConstructPath(privileged,
> +                                LOCALSTATEDIR,
> +                                "virtlogd",
> +                                &pid_file) < 0) {
> +        VIR_ERROR(_("Can't determine pid file path."));
> +        exit(EXIT_FAILURE);
> +    }
> +    VIR_DEBUG("Decided on pid file path '%s'", NULLSTR(pid_file));
> +
> +    if (virLogDaemonUnixSocketPaths(privileged,
> +                                     &sock_file) < 0) {
                                       ^
Extra space (repeats a couple times...))

> +        VIR_ERROR(_("Can't determine socket paths"));
> +        exit(EXIT_FAILURE);
> +    }
> +    VIR_DEBUG("Decided on socket paths '%s'",
> +              sock_file);
> +
> +    if (virLogDaemonExecRestartStatePath(privileged,
> +                                          &state_file) < 0) {

extra space

> +        VIR_ERROR(_("Can't determine restart state file path"));
> +        exit(EXIT_FAILURE);
> +    }
> +    VIR_DEBUG("Decided on restart state file path '%s'",
> +              state_file);
> +
> +    /* Ensure the rundir exists (on tmpfs on some systems) */
> +    if (privileged) {
> +        if (VIR_STRDUP_QUIET(run_dir, LOCALSTATEDIR "/run/libvirt") < 0)
> +            goto no_memory;
> +    } else {
> +        if (!(run_dir = virGetUserRuntimeDirectory())) {
> +            VIR_ERROR(_("Can't determine user directory"));
> +            goto cleanup;
> +        }
> +    }
> +
> +    if (privileged)
> +        old_umask = umask(022);
> +    else
> +        old_umask = umask(077);
> +    VIR_DEBUG("Ensuring run dir '%s' exists", run_dir);
> +    if (virFileMakePath(run_dir) < 0) {
> +        char ebuf[1024];
> +        VIR_ERROR(_("unable to create rundir %s: %s"), run_dir,
> +                  virStrerror(errno, ebuf, sizeof(ebuf)));
> +        ret = VIR_LOG_DAEMON_ERR_RUNDIR;

should we umask(old_umask) here?

> +        goto cleanup;
> +    }
> +    umask(old_umask);
> +
> +    if ((rv = virLogDaemonPostExecRestart(state_file,
> +                                          pid_file,
> +                                          &pid_file_fd,
> +                                          privileged)) < 0) {
> +        ret = VIR_LOG_DAEMON_ERR_INIT;
> +        goto cleanup;
> +    }
> +
> +    /* rv == 1, means we setup everything from saved state,
> +     * so only (possibly) daemonize and setup stuff from
> +     * scratch if rv == 0
> +     */
> +    if (rv == 0) {
> +        if (godaemon) {
> +            char ebuf[1024];
> +
> +            if (chdir("/") < 0) {
> +                VIR_ERROR(_("cannot change to root directory: %s"),
> +                          virStrerror(errno, ebuf, sizeof(ebuf)));
> +                goto cleanup;
> +            }
> +
> +            if ((statuswrite = virLogDaemonForkIntoBackground(argv[0])) < 0) {
> +                VIR_ERROR(_("Failed to fork as daemon: %s"),
> +                          virStrerror(errno, ebuf, sizeof(ebuf)));
> +                goto cleanup;
> +            }
> +        }
> +
> +        /* If we have a pidfile set, claim it now, exiting if already taken */
> +        if ((pid_file_fd = virPidFileAcquirePath(pid_file, false, getpid())) < 0) {
> +            ret = VIR_LOG_DAEMON_ERR_PIDFILE;
> +            goto cleanup;
> +        }
> +
> +        if (!(logDaemon = virLogDaemonNew(config, privileged))) {
> +            ret = VIR_LOG_DAEMON_ERR_INIT;
> +            goto cleanup;
> +        }
> +
> +        if ((rv = virLogDaemonSetupNetworkingSystemD(logDaemon->srv)) < 0) {
> +            ret = VIR_LOG_DAEMON_ERR_NETWORK;
> +            goto cleanup;
> +        }
> +
> +        /* Only do this, if systemd did not pass a FD */
> +        if (rv == 0 &&
> +            virLogDaemonSetupNetworkingNative(logDaemon->srv, sock_file) < 0) {
> +            ret = VIR_LOG_DAEMON_ERR_NETWORK;
> +            goto cleanup;
> +        }
> +    }
> +
> +    if (timeout != -1) {
> +        VIR_DEBUG("Registering shutdown timeout %d", timeout);
> +        virNetDaemonAutoShutdown(logDaemon->dmn,
> +                                 timeout);
> +    }
> +
> +    if ((virLogDaemonSetupSignals(logDaemon->dmn)) < 0) {
> +        ret = VIR_LOG_DAEMON_ERR_SIGNAL;
> +        goto cleanup;
> +    }
> +
> +    if (!(logProgram = virNetServerProgramNew(VIR_LOG_MANAGER_PROTOCOL_PROGRAM,
> +                                              VIR_LOG_MANAGER_PROTOCOL_PROGRAM_VERSION,
> +                                              virLogManagerProtocolProcs,
> +                                              virLogManagerProtocolNProcs))) {
> +        ret = VIR_LOG_DAEMON_ERR_INIT;
> +        goto cleanup;
> +    }
> +    if (virNetServerAddProgram(logDaemon->srv, logProgram) < 0) {
> +        ret = VIR_LOG_DAEMON_ERR_INIT;
> +        goto cleanup;
> +    }
> +
> +    /* Disable error func, now logging is setup */
> +    virSetErrorFunc(NULL, virLogDaemonErrorHandler);
> +
> +
> +

There's an extra line here.

    /* Tell parent of daemon that basic initialization is complete
> +     * In particular we're ready to accept net connections & have
> +     * written the pidfile
> +     */
> +    if (statuswrite != -1) {
> +        char status = 0;
> +        while (write(statuswrite, &status, 1) == -1 &&
> +               errno == EINTR)
> +            ;
> +        VIR_FORCE_CLOSE(statuswrite);
> +    }
> +
> +    /* Start accepting new clients from network */
> +
> +    virNetServerUpdateServices(logDaemon->srv, true);
> +    virNetDaemonRun(logDaemon->dmn);
> +
> +    if (execRestart &&
> +        virLogDaemonPreExecRestart(state_file,
> +                                   logDaemon->dmn,
> +                                   argv) < 0)
> +        ret = VIR_LOG_DAEMON_ERR_REEXEC;
> +    else
> +        ret = 0;
> +
> + cleanup:
> +    virObjectUnref(logProgram);
> +    virLogDaemonFree(logDaemon);
> +    if (statuswrite != -1) {
> +        if (ret != 0) {
> +            /* Tell parent of daemon what failed */
> +            char status = ret;
> +            while (write(statuswrite, &status, 1) == -1 &&
> +                   errno == EINTR)
> +                ;
> +        }
> +        VIR_FORCE_CLOSE(statuswrite);
> +    }
> +    if (pid_file_fd != -1)
> +        virPidFileReleasePath(pid_file, pid_file_fd);
> +    VIR_FREE(pid_file);
> +    VIR_FREE(sock_file);
> +    VIR_FREE(state_file);
> +    VIR_FREE(run_dir);
> +    return ret;
> +
> + no_memory:
> +    VIR_ERROR(_("Can't allocate memory"));
> +    exit(EXIT_FAILURE);
> +}

[...]

Admittedly I know very little about the log_protocol.x and other
src/logging/* files from here...  I do note that test_virtlogd.aug.in
doesn't have 'max_clients', although virtlogd.aug has a reference.  I
also note there's a log_buffer_size listed, but no corresponding element
in the virLogDaemonConfig (or of course read of such element).


> diff --git a/src/logging/virtlogd.pod.in b/src/logging/virtlogd.pod.in
> new file mode 100644
> index 0000000..bba7714
> --- /dev/null
> +++ b/src/logging/virtlogd.pod.in
> @@ -0,0 +1,162 @@
> +=head1 NAME
> +
> +virtlogd - libvirt log management daemon
> +
> +=head1 SYNOPSIS
> +
> +B<virtlogd> [ -dv ] [ -f config_file ] [ -p pid_file ]

't' timeout?
'V' version (yes, I see --version)

> +
> +B<virtlogd> --version
> +
> +=head1 DESCRIPTION
> +
> +The B<virtlogd> program is a server side daemon component of the libvirt
> +virtualization management system that is used to manage logs from virtual
> +machine consoles.
> +
> +This daemon is not used directly by libvirt client applications, rather it
> +is called on their behalf by B<libvirtd>. By maintaining the logs in a
> +standalone daemon, the main libvirtd daemon can be restarted without risk
> +of losing logs. The B<virtlogd> daemon has the ability to re-exec()
> +itself upon receiving SIGUSR1, to allow live upgrades without downtime.
> +
> +The virtlogd daemon listens for requests on a local Unix domain socket.
> +
> +=head1 OPTIONS
> +
> +=over
> +
> +=item B<-h, --help>
> +
> +Display command line help usage then exit.
> +
> +=item B<-d, --daemon>
> +
> +Run as a daemon and write PID file.
> +
> +=item B<-f, --config> I<FILE>
> +
> +Use this configuration file, overriding the default value.
> +
> +=item B<-p, --pid-file> I<FILE>
> +
> +Use this name for the PID file, overriding the default value.
> +
> +=item B<-v, --verbose>
> +
> +Enable output of verbose messages.
> +
> +=item B<-V, --version>
> +

't' 'timeout'...

> +Display version information then exit.
> +
> +=back
> +
> +=head1 SIGNALS
> +
> +On receipt of B<SIGUSR1> virtlogd will re-exec() its binary, while
> +maintaining all current logs and clients. This allows for live
> +upgrades of the virtlogd service.
> +
> +=head1 FILES
> +
> +=head2 When run as B<root>.
> +
> +=over
> +
> +=item F<SYSCONFDIR/virtlogd.conf>
> +
> +The default configuration file used by virtlogd, unless overridden on the
> +command line using the B<-f>|B<--config> option.
> +
> +=item F<LOCALSTATEDIR/run/libvirt/virtlogd-sock>
> +
> +The sockets libvirtd will use.
> +
> +=item F<LOCALSTATEDIR/run/virtlogd.pid>
> +
> +The PID file to use, unless overridden by the B<-p>|B<--pid-file> option.
> +
> +=back
> +
> +=head2 When run as B<non-root>.
> +
> +=over
> +
> +=item F<$XDG_CONFIG_HOME/virtlogd.conf>
> +
> +The default configuration file used by libvirtd, unless overridden on the
> +command line using the B<-f>|B<--config> option.
> +
> +=item F<$XDG_RUNTIME_DIR/libvirt/virtlogd-sock>
> +
> +The socket libvirtd will use.
> +
> +=item F<$XDG_RUNTIME_DIR/libvirt/virtlogd.pid>
> +
> +The PID file to use, unless overridden by the B<-p>|B<--pid-file> option.
> +
> +=item If $XDG_CONFIG_HOME is not set in your environment, libvirtd will use F<$HOME/.config>
> +
> +=item If $XDG_RUNTIME_DIR is not set in your environment, libvirtd will use F<$HOME/.cache>
> +
> +=back
> +
> +=head1 EXAMPLES
> +
> +To retrieve the version of virtlogd:
> +
> + # virtlogd --version
> + virtlogd (libvirt) 1.1.1
> + #
> +
> +To start virtlogd, instructing it to daemonize and create a PID file:
> +
> + # virtlogd -d
> + # ls -la LOCALSTATEDIR/run/virtlogd.pid
> + -rw-r--r-- 1 root root 6 Jul  9 02:40 LOCALSTATEDIR/run/virtlogd.pid
> + #
> +
> +=head1 BUGS
> +
> +Please report all bugs you discover.  This should be done via either:
> +
> +=over
> +
> +=item a) the mailing list
> +
> +L<http://libvirt.org/contact.html>
> +
> +=item or,
> +
> +B<>
> +
> +=item b) the bug tracker
> +
> +L<http://libvirt.org/bugs.html>
> +
> +=item Alternatively, you may report bugs to your software distributor / vendor.
> +
> +=back
> +
> +=head1 AUTHORS
> +
> +Please refer to the AUTHORS file distributed with libvirt.
> +
> +=head1 COPYRIGHT
> +
> +Copyright (C) 2006-2015 Red Hat, Inc., and the authors listed in the
> +libvirt AUTHORS file.
> +
> +=head1 LICENSE
> +
> +virtlogd is distributed under the terms of the GNU LGPL v2.1+.
> +This is free software; see the source for copying conditions. There
> +is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
> +PURPOSE
> +
> +=head1 SEE ALSO
> +
> +L<libvirtd(8)>,  L<http://www.libvirt.org/>
> +
> +=cut


ACK - with a couple of minor adjustments.

John




More information about the libvir-list mailing list