virlog.c 51.5 KB
Newer Older
1
/*
2
 * virlog.c: internal logging and debugging
3
 *
4
 * Copyright (C) 2008, 2010-2014 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16
 *
 * 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
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
19 20 21 22 23
 *
 */

#include <config.h>

D
Daniel Veillard 已提交
24 25 26 27 28 29
#include <stdarg.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
30
#include <unistd.h>
31
#include <execinfo.h>
32
#include <regex.h>
D
Daniel P. Berrange 已提交
33
#include <sys/uio.h>
D
Daniel Veillard 已提交
34
#if HAVE_SYSLOG_H
35
# include <syslog.h>
D
Daniel Veillard 已提交
36
#endif
D
Daniel P. Berrange 已提交
37 38 39 40
#include <sys/socket.h>
#if HAVE_SYS_UN_H
# include <sys/un.h>
#endif
41
#include <fnmatch.h>
D
Daniel Veillard 已提交
42

43
#include "virerror.h"
44
#include "virlog.h"
45
#include "viralloc.h"
46
#include "virutil.h"
47
#include "virbuffer.h"
48
#include "virthread.h"
E
Eric Blake 已提交
49
#include "virfile.h"
50
#include "virtime.h"
D
Daniel P. Berrange 已提交
51
#include "intprops.h"
52
#include "virstring.h"
53
#include "configmake.h"
54

E
Eric Blake 已提交
55 56 57 58 59 60
/* Journald output is only supported on Linux new enough to expose
 * htole64.  */
#if HAVE_SYSLOG_H && defined(__linux__) && HAVE_DECL_HTOLE64
# define USE_JOURNALD 1
#endif

61 62
#define VIR_FROM_THIS VIR_FROM_NONE

63 64
VIR_LOG_INIT("util.log");

65
static regex_t *virLogRegex;
66
static char virLogHostname[HOST_NAME_MAX+1];
67 68


69 70
#define VIR_LOG_DATE_REGEX "[0-9]{4}-[0-9]{2}-[0-9]{2}"
#define VIR_LOG_TIME_REGEX "[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}\\+[0-9]{4}"
71
#define VIR_LOG_PID_REGEX "[0-9]+"
72
#define VIR_LOG_LEVEL_REGEX "(debug|info|warning|error)"
73 74 75 76

#define VIR_LOG_REGEX \
    VIR_LOG_DATE_REGEX " " VIR_LOG_TIME_REGEX ": " \
    VIR_LOG_PID_REGEX ": " VIR_LOG_LEVEL_REGEX " : "
D
Daniel Veillard 已提交
77

78 79 80 81
VIR_ENUM_DECL(virLogDestination);
VIR_ENUM_IMPL(virLogDestination, VIR_LOG_TO_OUTPUT_LAST,
              "stderr", "syslog", "file", "journald");

D
Daniel Veillard 已提交
82 83 84 85 86
/*
 * Filters are used to refine the rules on what to keep or drop
 * based on a matching pattern (currently a substring)
 */
struct _virLogFilter {
87
    char *match;
88
    virLogPriority priority;
89
    unsigned int flags; /* bitwise OR of virLogFilterFlags */
D
Daniel Veillard 已提交
90 91
};

92
static int virLogFiltersSerial = 1;
93 94
static virLogFilterPtr *virLogFilters;
static size_t virLogNbFilters;
D
Daniel Veillard 已提交
95 96 97 98 99 100

/*
 * Outputs are used to emit the messages retained
 * after filtering, multiple output can be used simultaneously
 */
struct _virLogOutput {
101
    bool logInitMessage;
D
Daniel Veillard 已提交
102 103 104
    void *data;
    virLogOutputFunc f;
    virLogCloseFunc c;
105
    virLogPriority priority;
106
    virLogDestination dest;
107
    char *name;
D
Daniel Veillard 已提交
108 109
};

110
static char *virLogDefaultOutput;
111 112
static virLogOutputPtr *virLogOutputs;
static size_t virLogNbOutputs;
D
Daniel Veillard 已提交
113 114 115 116

/*
 * Default priorities
 */
117
static virLogPriority virLogDefaultPriority = VIR_LOG_DEFAULT;
D
Daniel Veillard 已提交
118

119 120
static void virLogResetFilters(void);
static void virLogResetOutputs(void);
121
static void virLogOutputToFd(virLogSourcePtr src,
122
                             virLogPriority priority,
123
                             const char *filename,
124
                             int linenr,
125
                             const char *funcname,
126
                             const char *timestamp,
M
Miloslav Trmač 已提交
127
                             virLogMetadataPtr metadata,
128
                             unsigned int flags,
129 130
                             const char *rawstr,
                             const char *str,
131
                             void *data);
D
Daniel Veillard 已提交
132

133

D
Daniel Veillard 已提交
134 135 136
/*
 * Logs accesses must be serialized though a mutex
 */
137
virMutex virLogMutex;
D
Daniel Veillard 已提交
138

139 140
void
virLogLock(void)
D
Daniel Veillard 已提交
141
{
142
    virMutexLock(&virLogMutex);
D
Daniel Veillard 已提交
143
}
144 145 146 147


void
virLogUnlock(void)
D
Daniel Veillard 已提交
148
{
149
    virMutexUnlock(&virLogMutex);
D
Daniel Veillard 已提交
150 151
}

152

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
static int
virLogSetDefaultOutputToStderr(void)
{
    return virAsprintf(&virLogDefaultOutput, "%d:stderr",
                       virLogDefaultPriority);
}


static int
virLogSetDefaultOutputToJournald(void)
{
    virLogPriority priority = virLogDefaultPriority;

    /* By default we don't want to log too much stuff into journald as
     * it may employ rate limiting and thus block libvirt execution. */
    if (priority == VIR_LOG_DEBUG)
        priority = VIR_LOG_INFO;

    return virAsprintf(&virLogDefaultOutput, "%d:journald", priority);
}


static int
virLogSetDefaultOutputToFile(const char *filename, bool privileged)
{
    int ret = -1;
    char *logdir = NULL;
    mode_t old_umask;

    if (privileged) {
        if (virAsprintf(&virLogDefaultOutput,
                        "%d:file:%s/log/libvirt/%s", virLogDefaultPriority,
                        LOCALSTATEDIR, filename) < 0)
            goto cleanup;
    } else {
        if (!(logdir = virGetUserCacheDirectory()))
            goto cleanup;

        old_umask = umask(077);
        if (virFileMakePath(logdir) < 0) {
            umask(old_umask);
            goto cleanup;
        }
        umask(old_umask);

        if (virAsprintf(&virLogDefaultOutput, "%d:file:%s/%s",
                        virLogDefaultPriority, logdir, filename) < 0)
            goto cleanup;
    }

    ret = 0;
 cleanup:
    VIR_FREE(logdir);
    return ret;
}


/*
 * virLogSetDefaultOutput:
 * @filename: the file that the output should be redirected to (only needed
 *            when @godaemon equals true
 * @godaemon: whether we're running daemonized
 * @privileged: whether we're running with root privileges or not (session)
 *
 * Decides on what the default output (journald, file, stderr) should be
 * according to @filename, @godaemon, @privileged. This function should be run
 * exactly once at daemon startup, so no locks are used.
 *
 * Returns 0 on success, -1 in case of a failure.
 */
int
virLogSetDefaultOutput(const char *filename, bool godaemon, bool privileged)
{
    if (!godaemon)
        return virLogSetDefaultOutputToStderr();

    if (access("/run/systemd/journal/socket", W_OK) >= 0)
        return virLogSetDefaultOutputToJournald();

    return virLogSetDefaultOutputToFile(filename, privileged);
}


char *
virLogGetDefaultOutput(void)
{
    return virLogDefaultOutput;
}


243 244 245
static const char *
virLogPriorityString(virLogPriority lvl)
{
D
Daniel Veillard 已提交
246
    switch (lvl) {
247 248 249 250 251 252 253 254
    case VIR_LOG_DEBUG:
        return "debug";
    case VIR_LOG_INFO:
        return "info";
    case VIR_LOG_WARN:
        return "warning";
    case VIR_LOG_ERROR:
        return "error";
D
Daniel Veillard 已提交
255
    }
256
    return "unknown";
D
Daniel Veillard 已提交
257 258 259
}


260 261
static int
virLogOnceInit(void)
262
{
263 264
    int r;

265 266 267
    if (virMutexInit(&virLogMutex) < 0)
        return -1;

D
Daniel Veillard 已提交
268
    virLogLock();
269
    virLogDefaultPriority = VIR_LOG_DEFAULT;
270

271
    if (VIR_ALLOC_QUIET(virLogRegex) >= 0) {
272 273 274 275
        if (regcomp(virLogRegex, VIR_LOG_REGEX, REG_EXTENDED) != 0)
            VIR_FREE(virLogRegex);
    }

276 277 278
    /* We get and remember the hostname early, because at later time
     * it might not be possible to load NSS modules via getaddrinfo()
     * (e.g. at container startup the host filesystem will not be
279 280 281 282 283 284
     * accessible anymore.
     * Must not use virGetHostname though as that causes re-entrancy
     * problems if it triggers logging codepaths
     */
    r = gethostname(virLogHostname, sizeof(virLogHostname));
    if (r == -1) {
285
        ignore_value(virStrcpyStatic(virLogHostname, "(unknown)"));
286 287 288
    } else {
        NUL_TERMINATE(virLogHostname);
    }
289

D
Daniel Veillard 已提交
290
    virLogUnlock();
291
    return 0;
D
Daniel Veillard 已提交
292 293
}

294 295
VIR_ONCE_GLOBAL_INIT(virLog)

296

D
Daniel Veillard 已提交
297 298 299 300 301 302 303
/**
 * virLogReset:
 *
 * Reset the logging module to its default initial state
 *
 * Returns 0 if successful, and -1 in case or error
 */
304 305 306
int
virLogReset(void)
{
307 308
    if (virLogInitialize() < 0)
        return -1;
D
Daniel Veillard 已提交
309 310 311 312

    virLogLock();
    virLogResetFilters();
    virLogResetOutputs();
313
    virLogDefaultPriority = VIR_LOG_DEFAULT;
D
Daniel Veillard 已提交
314
    virLogUnlock();
315
    return 0;
D
Daniel Veillard 已提交
316 317 318 319 320 321 322 323 324 325 326 327
}

/**
 * virLogSetDefaultPriority:
 * @priority: the default priority level
 *
 * Set the default priority level, i.e. any logged data of a priority
 * equal or superior to this level will be logged, unless a specific rule
 * was defined for the log category of the message.
 *
 * Returns 0 if successful, -1 in case of error.
 */
328 329 330
int
virLogSetDefaultPriority(virLogPriority priority)
{
331
    if ((priority < VIR_LOG_DEBUG) || (priority > VIR_LOG_ERROR)) {
332 333 334
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Failed to set logging priority, argument '%u' is "
                         "invalid"), priority);
335
        return -1;
336
    }
337 338 339
    if (virLogInitialize() < 0)
        return -1;

D
Daniel Veillard 已提交
340
    virLogDefaultPriority = priority;
341
    return 0;
D
Daniel Veillard 已提交
342 343
}

344

D
Daniel Veillard 已提交
345 346 347 348 349
/**
 * virLogResetFilters:
 *
 * Removes the set of logging filters defined.
 */
350
static void
351 352
virLogResetFilters(void)
{
353 354
    virLogFilterListFree(virLogFilters, virLogNbFilters);
    virLogFilters = NULL;
D
Daniel Veillard 已提交
355
    virLogNbFilters = 0;
356
    virLogFiltersSerial++;
D
Daniel Veillard 已提交
357 358
}

359

360 361 362 363 364 365 366 367 368 369
void
virLogFilterFree(virLogFilterPtr filter)
{
    if (!filter)
        return;

    VIR_FREE(filter->match);
    VIR_FREE(filter);
}

370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391

/**
 * virLogFilterFreeList:
 * @list: list of filters to be freed
 * @count: number of elements in the list
 *
 * Frees a list of filters.
 */
void
virLogFilterListFree(virLogFilterPtr *list, int count)
{
    size_t i;

    if (!list || count < 0)
        return;

    for (i = 0; i < count; i++)
        virLogFilterFree(list[i]);
    VIR_FREE(list);
}


D
Daniel Veillard 已提交
392 393 394 395 396
/**
 * virLogResetOutputs:
 *
 * Removes the set of logging output defined.
 */
397
static void
398 399
virLogResetOutputs(void)
{
400 401
    virLogOutputListFree(virLogOutputs, virLogNbOutputs);
    virLogOutputs = NULL;
D
Daniel Veillard 已提交
402 403 404
    virLogNbOutputs = 0;
}

405

406 407 408 409 410 411 412 413 414 415 416 417 418
void
virLogOutputFree(virLogOutputPtr output)
{
    if (!output)
        return;

    if (output->c)
        output->c(output->data);
    VIR_FREE(output->name);
    VIR_FREE(output);

}

419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440

/**
 * virLogOutputsFreeList:
 * @list: list of outputs to be freed
 * @count: number of elements in the list
 *
 * Frees a list of outputs.
 */
void
virLogOutputListFree(virLogOutputPtr *list, int count)
{
    size_t i;

    if (!list || count < 0)
        return;

    for (i = 0; i < count; i++)
        virLogOutputFree(list[i]);
    VIR_FREE(list);
}


441 442
static int
virLogFormatString(char **msg,
443
                   int linenr,
444
                   const char *funcname,
445
                   virLogPriority priority,
446 447 448
                   const char *str)
{
    int ret;
449 450 451 452 453 454 455 456

    /*
     * Be careful when changing the following log message formatting, we rely
     * on it when stripping libvirt debug messages from qemu log files. So when
     * changing this, you might also need to change the code there.
     * virLogFormatString() function name is mentioned there so it's sufficient
     * to just grep for it to find the right place.
     */
457
    if ((funcname != NULL)) {
458 459 460
        ret = virAsprintfQuiet(msg, "%llu: %s : %s:%d : %s\n",
                               virThreadSelfID(), virLogPriorityString(priority),
                               funcname, linenr, str);
461
    } else {
462 463 464
        ret = virAsprintfQuiet(msg, "%llu: %s : %s\n",
                               virThreadSelfID(), virLogPriorityString(priority),
                               str);
465 466 467 468
    }
    return ret;
}

469

470
static int
471 472
virLogVersionString(const char **rawmsg,
                    char **msg)
473
{
474 475
    *rawmsg = VIR_LOG_VERSION_STRING;
    return virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, VIR_LOG_VERSION_STRING);
476 477
}

478 479 480 481
/* Similar to virGetHostname() but avoids use of error
 * reporting APIs or logging APIs, to prevent recursion
 */
static int
482
virLogHostnameString(char **rawmsg,
483 484 485 486
                     char **msg)
{
    char *hoststr;

A
Andrea Bolognani 已提交
487
    if (virAsprintfQuiet(&hoststr, "hostname: %s", virLogHostname) < 0)
488 489 490 491 492 493 494 495 496 497
        return -1;

    if (virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, hoststr) < 0) {
        VIR_FREE(hoststr);
        return -1;
    }
    *rawmsg = hoststr;
    return 0;
}

498

499 500 501 502 503 504 505 506 507 508
static void
virLogSourceUpdate(virLogSourcePtr source)
{
    virLogLock();
    if (source->serial < virLogFiltersSerial) {
        unsigned int priority = virLogDefaultPriority;
        unsigned int flags = 0;
        size_t i;

        for (i = 0; i < virLogNbFilters; i++) {
509
            if (fnmatch(virLogFilters[i]->match, source->name, 0) == 0) {
510 511
                priority = virLogFilters[i]->priority;
                flags = virLogFilters[i]->flags;
512 513 514 515 516 517 518 519 520 521 522
                break;
            }
        }

        source->priority = priority;
        source->flags = flags;
        source->serial = virLogFiltersSerial;
    }
    virLogUnlock();
}

D
Daniel Veillard 已提交
523 524
/**
 * virLogMessage:
525
 * @source: where is that message coming from
D
Daniel Veillard 已提交
526
 * @priority: the priority level
527
 * @filename: file where the message was emitted
528
 * @linenr: line where the message was emitted
529
 * @funcname: the function emitting the (debug) message
530
 * @metadata: NULL or metadata array, terminated by an item with NULL key
D
Daniel Veillard 已提交
531 532 533
 * @fmt: the string format
 * @...: the arguments
 *
E
Eric Blake 已提交
534
 * Call the libvirt logger with some information. Based on the configuration
D
Daniel Veillard 已提交
535 536
 * the message may be stored, sent to output or just discarded
 */
537
void
538
virLogMessage(virLogSourcePtr source,
539
              virLogPriority priority,
540
              const char *filename,
541
              int linenr,
542
              const char *funcname,
543
              virLogMetadataPtr metadata,
544
              const char *fmt, ...)
545 546 547
{
    va_list ap;
    va_start(ap, fmt);
548
    virLogVMessage(source, priority,
549
                   filename, linenr, funcname,
550
                   metadata, fmt, ap);
551 552 553
    va_end(ap);
}

554

555 556
/**
 * virLogVMessage:
557
 * @source: where is that message coming from
558
 * @priority: the priority level
559
 * @filename: file where the message was emitted
560
 * @linenr: line where the message was emitted
561
 * @funcname: the function emitting the (debug) message
562
 * @metadata: NULL or metadata array, terminated by an item with NULL key
563 564 565 566 567 568
 * @fmt: the string format
 * @vargs: format args
 *
 * Call the libvirt logger with some information. Based on the configuration
 * the message may be stored, sent to output or just discarded
 */
569
void
570
virLogVMessage(virLogSourcePtr source,
571
               virLogPriority priority,
572
               const char *filename,
573
               int linenr,
574
               const char *funcname,
M
Miloslav Trmač 已提交
575
               virLogMetadataPtr metadata,
576 577
               const char *fmt,
               va_list vargs)
578
{
579
    static bool logInitMessageStderr = true;
D
Daniel Veillard 已提交
580
    char *str = NULL;
581
    char *msg = NULL;
582
    char timestamp[VIR_TIME_STRING_BUFLEN];
583
    int ret;
584
    size_t i;
585
    int saved_errno = errno;
586
    unsigned int filterflags = 0;
D
Daniel Veillard 已提交
587

588 589
    if (virLogInitialize() < 0)
        return;
D
Daniel Veillard 已提交
590 591

    if (fmt == NULL)
592
        return;
D
Daniel Veillard 已提交
593 594

    /*
595 596 597 598 599 600
     * 3 intentionally non-thread safe variable reads.
     * Since writes to the variable are serialized on
     * virLogLock, worst case result is a log message
     * is accidentally dropped or emitted, if another
     * thread is updating log filter list concurrently
     * with a log message emission.
D
Daniel Veillard 已提交
601
     */
602 603 604
    if (source->serial < virLogFiltersSerial)
        virLogSourceUpdate(source);
    if (priority < source->priority)
605
        goto cleanup;
606
    filterflags = source->flags;
607

D
Daniel Veillard 已提交
608 609 610
    /*
     * serialize the error message, add level and timestamp
     */
611
    if (virVasprintfQuiet(&str, fmt, vargs) < 0)
612
        goto cleanup;
D
Daniel Veillard 已提交
613

614
    ret = virLogFormatString(&msg, linenr, funcname, priority, str);
615 616
    if (ret < 0)
        goto cleanup;
D
Daniel Veillard 已提交
617

618 619
    if (virTimeStringNowRaw(timestamp) < 0)
        timestamp[0] = '\0';
620

621 622
    virLogLock();

D
Daniel Veillard 已提交
623
    /*
624
     * Push the message to the outputs defined, if none exist then
D
Daniel Veillard 已提交
625 626
     * use stderr.
     */
627
    for (i = 0; i < virLogNbOutputs; i++) {
628 629
        if (priority >= virLogOutputs[i]->priority) {
            if (virLogOutputs[i]->logInitMessage) {
630
                const char *rawinitmsg;
631
                char *hoststr = NULL;
632 633
                char *initmsg = NULL;
                if (virLogVersionString(&rawinitmsg, &initmsg) >= 0)
634
                    virLogOutputs[i]->f(&virLogSelf, VIR_LOG_INFO,
635 636 637
                                        __FILE__, __LINE__, __func__,
                                        timestamp, NULL, 0, rawinitmsg, initmsg,
                                        virLogOutputs[i]->data);
638
                VIR_FREE(initmsg);
639
                if (virLogHostnameString(&hoststr, &initmsg) >= 0)
640
                    virLogOutputs[i]->f(&virLogSelf, VIR_LOG_INFO,
641 642 643
                                        __FILE__, __LINE__, __func__,
                                        timestamp, NULL, 0, hoststr, initmsg,
                                        virLogOutputs[i]->data);
644
                VIR_FREE(hoststr);
645
                VIR_FREE(initmsg);
646
                virLogOutputs[i]->logInitMessage = false;
647
            }
648
            virLogOutputs[i]->f(source, priority,
649 650 651
                                filename, linenr, funcname,
                                timestamp, metadata, filterflags,
                                str, msg, virLogOutputs[i]->data);
652
        }
D
Daniel Veillard 已提交
653
    }
654
    if (virLogNbOutputs == 0) {
655 656
        if (logInitMessageStderr) {
            const char *rawinitmsg;
657
            char *hoststr = NULL;
658 659 660 661 662 663 664
            char *initmsg = NULL;
            if (virLogVersionString(&rawinitmsg, &initmsg) >= 0)
                virLogOutputToFd(&virLogSelf, VIR_LOG_INFO,
                                 __FILE__, __LINE__, __func__,
                                 timestamp, NULL, 0, rawinitmsg, initmsg,
                                 (void *) STDERR_FILENO);
            VIR_FREE(initmsg);
665
            if (virLogHostnameString(&hoststr, &initmsg) >= 0)
666
                virLogOutputToFd(&virLogSelf, VIR_LOG_INFO,
667
                                 __FILE__, __LINE__, __func__,
668
                                 timestamp, NULL, 0, hoststr, initmsg,
669
                                 (void *) STDERR_FILENO);
670
            VIR_FREE(hoststr);
671 672
            VIR_FREE(initmsg);
            logInitMessageStderr = false;
673
        }
674
        virLogOutputToFd(source, priority,
675
                         filename, linenr, funcname,
M
Miloslav Trmač 已提交
676
                         timestamp, metadata, filterflags,
677
                         str, msg, (void *) STDERR_FILENO);
678
    }
D
Daniel Veillard 已提交
679 680
    virLogUnlock();

681
 cleanup:
682
    VIR_FREE(str);
683
    VIR_FREE(msg);
684
    errno = saved_errno;
D
Daniel Veillard 已提交
685 686
}

687

688 689
static void
virLogStackTraceToFd(int fd)
690 691 692
{
    void *array[100];
    int size;
693
    static bool doneWarning;
694
    const char *msg = "Stack trace not available on this platform\n";
695 696 697 698 699 700 701

#define STRIP_DEPTH 3
    size = backtrace(array, ARRAY_CARDINALITY(array));
    if (size) {
        backtrace_symbols_fd(array +  STRIP_DEPTH, size - STRIP_DEPTH, fd);
        ignore_value(safewrite(fd, "\n", 1));
    } else if (!doneWarning) {
702 703 704
        ignore_value(safewrite(fd, msg, strlen(msg)));
        doneWarning = true;
    }
705
#undef STRIP_DEPTH
706 707
}

708
static void
709
virLogOutputToFd(virLogSourcePtr source ATTRIBUTE_UNUSED,
710
                 virLogPriority priority ATTRIBUTE_UNUSED,
711
                 const char *filename ATTRIBUTE_UNUSED,
712
                 int linenr ATTRIBUTE_UNUSED,
713
                 const char *funcname ATTRIBUTE_UNUSED,
714
                 const char *timestamp,
M
Miloslav Trmač 已提交
715
                 virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
716 717 718 719
                 unsigned int flags,
                 const char *rawstr ATTRIBUTE_UNUSED,
                 const char *str,
                 void *data)
720
{
721
    int fd = (intptr_t) data;
722
    char *msg;
D
Daniel Veillard 已提交
723 724

    if (fd < 0)
725
        return;
726

727
    if (virAsprintfQuiet(&msg, "%s: %s", timestamp, str) < 0)
728
        return;
729

730
    ignore_value(safewrite(fd, msg, strlen(msg)));
731 732
    VIR_FREE(msg);

733 734
    if (flags & VIR_LOG_STACK_TRACE)
        virLogStackTraceToFd(fd);
D
Daniel Veillard 已提交
735 736
}

737 738 739

static void
virLogCloseFd(void *data)
740
{
741
    int fd = (intptr_t) data;
D
Daniel Veillard 已提交
742

743
    VIR_LOG_CLOSE(fd);
D
Daniel Veillard 已提交
744 745
}

746

747
static virLogOutputPtr
748 749 750 751 752 753 754
virLogNewOutputToStderr(virLogPriority priority)
{
    return virLogOutputNew(virLogOutputToFd, NULL, (void *)STDERR_FILENO,
                           priority, VIR_LOG_TO_STDERR, NULL);
}


755
static virLogOutputPtr
756 757 758 759 760 761 762
virLogNewOutputToFile(virLogPriority priority,
                      const char *file)
{
    int fd;
    virLogOutputPtr ret = NULL;

    fd = open(file, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR);
763 764
    if (fd < 0) {
        virReportSystemError(errno, _("failed to open %s"), file);
765
        return NULL;
766
    }
767 768 769 770 771 772 773 774 775 776 777

    if (!(ret = virLogOutputNew(virLogOutputToFd, virLogCloseFd,
                                (void *)(intptr_t)fd,
                                priority, VIR_LOG_TO_FILE, file))) {
        VIR_LOG_CLOSE(fd);
        return NULL;
    }
    return ret;
}


778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
#if HAVE_SYSLOG_H || USE_JOURNALD

/* Compat in case we build with journald, but no syslog */
# ifndef LOG_DEBUG
#  define LOG_DEBUG 7
# endif
# ifndef LOG_INFO
#  define LOG_INFO 6
# endif
# ifndef LOG_WARNING
#  define LOG_WARNING 4
# endif
# ifndef LOG_ERR
#  define LOG_ERR 3
# endif

794 795
static int
virLogPrioritySyslog(virLogPriority priority)
796 797 798 799 800 801 802 803 804 805 806 807 808 809
{
    switch (priority) {
    case VIR_LOG_DEBUG:
        return LOG_DEBUG;
    case VIR_LOG_INFO:
        return LOG_INFO;
    case VIR_LOG_WARN:
        return LOG_WARNING;
    case VIR_LOG_ERROR:
        return LOG_ERR;
    default:
        return LOG_ERR;
    }
}
810
#endif /* HAVE_SYSLOG_H || USE_JOURNALD */
811

812

813
#if HAVE_SYSLOG_H
814
static void
815
virLogOutputToSyslog(virLogSourcePtr source ATTRIBUTE_UNUSED,
816
                     virLogPriority priority,
817
                     const char *filename ATTRIBUTE_UNUSED,
818
                     int linenr ATTRIBUTE_UNUSED,
819
                     const char *funcname ATTRIBUTE_UNUSED,
820
                     const char *timestamp ATTRIBUTE_UNUSED,
M
Miloslav Trmač 已提交
821
                     virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
822 823 824 825
                     unsigned int flags,
                     const char *rawstr ATTRIBUTE_UNUSED,
                     const char *str,
                     void *data ATTRIBUTE_UNUSED)
826
{
827
    virCheckFlags(VIR_LOG_STACK_TRACE,);
828

829
    syslog(virLogPrioritySyslog(priority), "%s", str);
D
Daniel Veillard 已提交
830 831
}

832
static char *current_ident;
833

834 835 836 837

static void
virLogCloseSyslog(void *data ATTRIBUTE_UNUSED)
{
D
Daniel Veillard 已提交
838
    closelog();
839
    VIR_FREE(current_ident);
D
Daniel Veillard 已提交
840 841
}

842

843
static virLogOutputPtr
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
virLogNewOutputToSyslog(virLogPriority priority,
                        const char *ident)
{
    virLogOutputPtr ret = NULL;
    int at = -1;

    /* There are a couple of issues with syslog:
     * 1) If we re-opened the connection by calling openlog now, it would change
     * the message tag immediately which is not what we want, since we might be
     * in the middle of parsing of a new set of outputs where anything still can
     * go wrong and we would introduce an inconsistent state to the log. We're
     * also not holding a lock on the logger if we tried to change the tag
     * while other workers are actively logging.
     *
     * 2) Syslog keeps the open file descriptor private, so we can't just dup()
     * it like we would do with files if an output already existed.
     *
     * If a syslog connection already exists changing the message tag has to be
     * therefore special-cased and postponed until the very last moment.
     */
    if ((at = virLogFindOutput(virLogOutputs, virLogNbOutputs,
                               VIR_LOG_TO_SYSLOG, NULL)) < 0) {
        /*
         * rather than copying @ident, syslog uses caller's reference instead
         */
        VIR_FREE(current_ident);
        if (VIR_STRDUP(current_ident, ident) < 0)
            return NULL;

        openlog(current_ident, 0, 0);
    }

    if (!(ret = virLogOutputNew(virLogOutputToSyslog, virLogCloseSyslog,
                                NULL, priority, VIR_LOG_TO_SYSLOG, ident))) {
        if (at < 0) {
            closelog();
            VIR_FREE(current_ident);
        }
        return NULL;
    }
    return ret;
}


E
Eric Blake 已提交
888
# if USE_JOURNALD
889 890 891 892 893
#  define IOVEC_SET(iov, data, size) \
    do { \
        struct iovec *_i = &(iov); \
        _i->iov_base = (void*)(data); \
        _i->iov_len = (size); \
D
Daniel P. Berrange 已提交
894 895
    } while (0)

896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960
#  define IOVEC_SET_STRING(iov, str) IOVEC_SET(iov, str, strlen(str))

/* Used for conversion of numbers to strings, and for length of binary data */
#  define JOURNAL_BUF_SIZE (MAX(INT_BUFSIZE_BOUND(int), sizeof(uint64_t)))

struct journalState
{
    struct iovec *iov, *iov_end;
    char (*bufs)[JOURNAL_BUF_SIZE], (*bufs_end)[JOURNAL_BUF_SIZE];
};

static void
journalAddString(struct journalState *state, const char *field,
                 const char *value)
{
    static const char newline = '\n', equals = '=';

    if (strchr(value, '\n') != NULL) {
        uint64_t nstr;

        /* If 'str' contains a newline, then we must
         * encode the string length, since we can't
         * rely on the newline for the field separator
         */
        if (state->iov_end - state->iov < 5 || state->bufs == state->bufs_end)
            return; /* Silently drop */
        nstr = htole64(strlen(value));
        memcpy(state->bufs[0], &nstr, sizeof(nstr));

        IOVEC_SET_STRING(state->iov[0], field);
        IOVEC_SET(state->iov[1], &newline, sizeof(newline));
        IOVEC_SET(state->iov[2], state->bufs[0], sizeof(nstr));
        state->bufs++;
        state->iov += 3;
    } else {
        if (state->iov_end - state->iov < 4)
            return; /* Silently drop */
        IOVEC_SET_STRING(state->iov[0], field);
        IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals));
        state->iov += 2;
    }
    IOVEC_SET_STRING(state->iov[0], value);
    IOVEC_SET(state->iov[1], (void *)&newline, sizeof(newline));
    state->iov += 2;
}

static void
journalAddInt(struct journalState *state, const char *field, int value)
{
    static const char newline = '\n', equals = '=';

    char *num;

    if (state->iov_end - state->iov < 4 || state->bufs == state->bufs_end)
        return; /* Silently drop */

    num = virFormatIntDecimal(state->bufs[0], sizeof(state->bufs[0]), value);

    IOVEC_SET_STRING(state->iov[0], field);
    IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals));
    IOVEC_SET_STRING(state->iov[2], num);
    IOVEC_SET(state->iov[3], (void *)&newline, sizeof(newline));
    state->bufs++;
    state->iov += 4;
}
D
Daniel P. Berrange 已提交
961 962

static void
963
virLogOutputToJournald(virLogSourcePtr source,
D
Daniel P. Berrange 已提交
964 965 966 967 968
                       virLogPriority priority,
                       const char *filename,
                       int linenr,
                       const char *funcname,
                       const char *timestamp ATTRIBUTE_UNUSED,
969
                       virLogMetadataPtr metadata,
D
Daniel P. Berrange 已提交
970 971 972
                       unsigned int flags,
                       const char *rawstr,
                       const char *str ATTRIBUTE_UNUSED,
973
                       void *data)
D
Daniel P. Berrange 已提交
974 975 976
{
    virCheckFlags(VIR_LOG_STACK_TRACE,);
    int buffd = -1;
977
    int journalfd = (intptr_t) data;
D
Daniel P. Berrange 已提交
978 979 980 981 982 983 984 985 986 987 988
    struct msghdr mh;
    struct sockaddr_un sa;
    union {
        struct cmsghdr cmsghdr;
        uint8_t buf[CMSG_SPACE(sizeof(int))];
    } control;
    struct cmsghdr *cmsg;
    /* We use /dev/shm instead of /tmp here, since we want this to
     * be a tmpfs, and one that is available from early boot on
     * and where unprivileged users can create files. */
    char path[] = "/dev/shm/journal.XXXXXX";
989
    size_t nmetadata = 0;
D
Daniel P. Berrange 已提交
990

991 992 993
#  define NUM_FIELDS_CORE 6
#  define NUM_FIELDS_META 5
#  define NUM_FIELDS (NUM_FIELDS_CORE + NUM_FIELDS_META)
994 995 996
    struct iovec iov[NUM_FIELDS * 5];
    char iov_bufs[NUM_FIELDS][JOURNAL_BUF_SIZE];
    struct journalState state;
D
Daniel P. Berrange 已提交
997

998 999 1000 1001
    state.iov = iov;
    state.iov_end = iov + ARRAY_CARDINALITY(iov);
    state.bufs = iov_bufs;
    state.bufs_end = iov_bufs + ARRAY_CARDINALITY(iov_bufs);
D
Daniel P. Berrange 已提交
1002

E
Eric Blake 已提交
1003
    journalAddString(&state, "MESSAGE", rawstr);
1004 1005
    journalAddInt(&state, "PRIORITY",
                  virLogPrioritySyslog(priority));
1006
    journalAddInt(&state, "SYSLOG_FACILITY", LOG_DAEMON);
1007
    journalAddString(&state, "LIBVIRT_SOURCE", source->name);
1008 1009
    if (filename)
        journalAddString(&state, "CODE_FILE", filename);
1010
    journalAddInt(&state, "CODE_LINE", linenr);
1011 1012
    if (funcname)
        journalAddString(&state, "CODE_FUNC", funcname);
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
    if (metadata != NULL) {
        while (metadata->key != NULL &&
               nmetadata < NUM_FIELDS_META) {
            if (metadata->s != NULL)
                journalAddString(&state, metadata->key, metadata->s);
            else
                journalAddInt(&state, metadata->key, metadata->iv);
            metadata++;
            nmetadata++;
        }
    }
D
Daniel P. Berrange 已提交
1024 1025 1026

    memset(&sa, 0, sizeof(sa));
    sa.sun_family = AF_UNIX;
1027
    if (virStrcpyStatic(sa.sun_path, "/run/systemd/journal/socket") < 0)
D
Daniel P. Berrange 已提交
1028 1029 1030 1031 1032 1033
        return;

    memset(&mh, 0, sizeof(mh));
    mh.msg_name = &sa;
    mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
    mh.msg_iov = iov;
1034
    mh.msg_iovlen = state.iov - iov;
D
Daniel P. Berrange 已提交
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057

    if (sendmsg(journalfd, &mh, MSG_NOSIGNAL) >= 0)
        return;

    if (errno != EMSGSIZE && errno != ENOBUFS)
        return;

    /* Message was too large, so dump to temporary file
     * and pass an FD to the journal
     */

    /* NB: mkostemp is not declared async signal safe by
     * POSIX, but this is Linux only code and the GLibc
     * impl is safe enough, only using open() and inline
     * asm to read a timestamp (falling back to gettimeofday
     * on some arches
     */
    if ((buffd = mkostemp(path, O_CLOEXEC|O_RDWR)) < 0)
        return;

    if (unlink(path) < 0)
        goto cleanup;

1058
    if (writev(buffd, iov, state.iov - iov) < 0)
D
Daniel P. Berrange 已提交
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
        goto cleanup;

    mh.msg_iov = NULL;
    mh.msg_iovlen = 0;

    memset(&control, 0, sizeof(control));
    mh.msg_control = &control;
    mh.msg_controllen = sizeof(control);

    cmsg = CMSG_FIRSTHDR(&mh);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    memcpy(CMSG_DATA(cmsg), &buffd, sizeof(int));

    mh.msg_controllen = cmsg->cmsg_len;

1076
    ignore_value(sendmsg(journalfd, &mh, MSG_NOSIGNAL));
D
Daniel P. Berrange 已提交
1077

1078
 cleanup:
D
Daniel P. Berrange 已提交
1079 1080 1081 1082
    VIR_LOG_CLOSE(buffd);
}


1083
static virLogOutputPtr
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
virLogNewOutputToJournald(int priority)
{
    int journalfd;
    virLogOutputPtr ret = NULL;

    if ((journalfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
        return NULL;

    if (virSetInherit(journalfd, false) < 0) {
        VIR_LOG_CLOSE(journalfd);
        return NULL;
    }

    if (!(ret = virLogOutputNew(virLogOutputToJournald, virLogCloseFd,
                                (void *)(intptr_t) journalfd, priority,
                                VIR_LOG_TO_JOURNALD, NULL))) {
        VIR_LOG_CLOSE(journalfd);
        return NULL;
    }

    return ret;
}
E
Eric Blake 已提交
1106
# endif /* USE_JOURNALD */
J
Ján Tomko 已提交
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131

int virLogPriorityFromSyslog(int priority)
{
    switch (priority) {
    case LOG_EMERG:
    case LOG_ALERT:
    case LOG_CRIT:
    case LOG_ERR:
        return VIR_LOG_ERROR;
    case LOG_WARNING:
    case LOG_NOTICE:
        return VIR_LOG_WARN;
    case LOG_INFO:
        return VIR_LOG_INFO;
    case LOG_DEBUG:
        return VIR_LOG_DEBUG;
    }
    return VIR_LOG_ERROR;
}

#else /* HAVE_SYSLOG_H */
int virLogPriorityFromSyslog(int priority ATTRIBUTE_UNUSED)
{
    return VIR_LOG_ERROR;
}
D
Daniel Veillard 已提交
1132 1133
#endif /* HAVE_SYSLOG_H */

1134

1135 1136 1137 1138 1139
/**
 * virLogGetDefaultPriority:
 *
 * Returns the current logging priority level.
 */
1140 1141 1142
virLogPriority
virLogGetDefaultPriority(void)
{
1143
    return virLogDefaultPriority;
1144 1145
}

1146

1147 1148 1149 1150 1151 1152 1153
/**
 * virLogGetFilters:
 *
 * Returns a string listing the current filters, in the format originally
 * specified in the config file or environment. Caller must free the
 * result.
 */
1154 1155 1156
char *
virLogGetFilters(void)
{
1157
    size_t i;
1158 1159 1160 1161
    virBuffer filterbuf = VIR_BUFFER_INITIALIZER;

    virLogLock();
    for (i = 0; i < virLogNbFilters; i++) {
1162
        const char *sep = ":";
1163
        if (virLogFilters[i]->flags & VIR_LOG_STACK_TRACE)
1164 1165
            sep = ":+";
        virBufferAsprintf(&filterbuf, "%d%s%s ",
1166
                          virLogFilters[i]->priority,
1167
                          sep,
1168
                          virLogFilters[i]->match);
1169 1170 1171
    }
    virLogUnlock();

1172 1173
    if (virBufferError(&filterbuf)) {
        virBufferFreeAndReset(&filterbuf);
1174
        return NULL;
1175
    }
1176 1177 1178 1179

    return virBufferContentAndReset(&filterbuf);
}

1180

1181 1182 1183 1184 1185 1186 1187
/**
 * virLogGetOutputs:
 *
 * Returns a string listing the current outputs, in the format originally
 * specified in the config file or environment. Caller must free the
 * result.
 */
1188 1189 1190
char *
virLogGetOutputs(void)
{
1191
    size_t i;
1192 1193 1194 1195
    virBuffer outputbuf = VIR_BUFFER_INITIALIZER;

    virLogLock();
    for (i = 0; i < virLogNbOutputs; i++) {
1196
        virLogDestination dest = virLogOutputs[i]->dest;
1197
        if (i)
1198
            virBufferAddChar(&outputbuf, ' ');
1199 1200 1201
        switch (dest) {
            case VIR_LOG_TO_SYSLOG:
            case VIR_LOG_TO_FILE:
1202
                virBufferAsprintf(&outputbuf, "%d:%s:%s",
1203
                                  virLogOutputs[i]->priority,
1204
                                  virLogDestinationTypeToString(dest),
1205
                                  virLogOutputs[i]->name);
1206
                break;
1207 1208
            case VIR_LOG_TO_STDERR:
            case VIR_LOG_TO_JOURNALD:
1209
                virBufferAsprintf(&outputbuf, "%d:%s",
1210
                                  virLogOutputs[i]->priority,
1211
                                  virLogDestinationTypeToString(dest));
1212 1213 1214 1215 1216
                break;
            case VIR_LOG_TO_OUTPUT_LAST:
            default:
                virReportEnumRangeError(virLogDestination, dest);
                goto error;
1217 1218 1219
        }
    }

1220
    if (virBufferError(&outputbuf))
1221
        goto error;
1222

1223
    virLogUnlock();
1224
    return virBufferContentAndReset(&outputbuf);
1225 1226 1227 1228 1229

 error:
    virLogUnlock();
    virBufferFreeAndReset(&outputbuf);
    return NULL;
1230 1231
}

1232

1233 1234 1235 1236 1237
/**
 * virLogGetNbFilters:
 *
 * Returns the current number of defined log filters.
 */
1238 1239 1240
int
virLogGetNbFilters(void)
{
1241
    return virLogNbFilters;
1242 1243
}

1244

1245 1246 1247 1248 1249
/**
 * virLogGetNbOutputs:
 *
 * Returns the current number of defined log outputs.
 */
1250 1251 1252
int
virLogGetNbOutputs(void)
{
1253
    return virLogNbOutputs;
1254
}
1255

1256

1257 1258
/**
 * virLogParseDefaultPriority:
1259 1260
 * @priority: string defining the desired logging level (either a numeric or a
 *            word form, see below)
1261
 *
1262 1263 1264 1265 1266 1267
 * Parses the desired log priority level. The input @priority shall conform to
 * one of the following levels:
 *    1 = DEBUG
 *    2 = INFO
 *    3 = WARNING
 *    4 = ERROR
1268
 *
1269 1270 1271 1272
 *
 * Returns the corresponding priority enum on success, -1 in case of error. A
 * call to virLogSetDefaultPriority should be issued upon returning from this
 * function.
1273
 */
1274 1275 1276
int
virLogParseDefaultPriority(const char *priority)
{
1277
    if (STREQ(priority, "1") || STREQ(priority, "debug"))
1278
        return VIR_LOG_DEBUG;
1279
    else if (STREQ(priority, "2") || STREQ(priority, "info"))
1280
        return VIR_LOG_INFO;
1281
    else if (STREQ(priority, "3") || STREQ(priority, "warning"))
1282
        return VIR_LOG_WARN;
1283
    else if (STREQ(priority, "4") || STREQ(priority, "error"))
1284 1285
        return VIR_LOG_ERROR;
    return -1;
1286 1287
}

1288

1289 1290 1291 1292 1293 1294
/**
 * virLogSetFromEnv:
 *
 * Sets virLogDefaultPriority, virLogFilters and virLogOutputs based on
 * environment variables.
 */
1295 1296 1297
void
virLogSetFromEnv(void)
{
1298
    const char *debugEnv;
1299

1300 1301 1302
    if (virLogInitialize() < 0)
        return;

1303
    debugEnv = virGetEnvAllowSUID("LIBVIRT_DEBUG");
1304
    if (debugEnv && *debugEnv)
1305
        virLogSetDefaultPriority(virLogParseDefaultPriority(debugEnv));
1306
    debugEnv = virGetEnvAllowSUID("LIBVIRT_LOG_FILTERS");
1307
    if (debugEnv && *debugEnv)
1308
        virLogSetFilters(debugEnv);
1309
    debugEnv = virGetEnvAllowSUID("LIBVIRT_LOG_OUTPUTS");
1310
    if (debugEnv && *debugEnv)
1311
        virLogSetOutputs(debugEnv);
1312
}
1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328


/*
 * Returns a true value if the first line in @str is
 * probably a log message generated by the libvirt
 * logging layer
 */
bool virLogProbablyLogMessage(const char *str)
{
    bool ret = false;
    if (!virLogRegex)
        return false;
    if (regexec(virLogRegex, str, 0, NULL, 0) == 0)
        ret = true;
    return ret;
}
E
Erik Skultety 已提交
1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383


/**
 * virLogOutputNew:
 * @f: the function to call to output a message
 * @c: the function to call to close the output (or NULL)
 * @data: extra data passed as first arg to functions @f and @c
 * @priority: minimal priority for this filter, use 0 for none
 * @dest: where to send output of this priority (see virLogDestination)
 * @name: additional data associated with syslog and file-based outputs (ident
 *        and filename respectively)
 *
 * Allocates and returns a new log output object. The object has to be later
 * defined, so that the output will be taken into account when emitting a
 * message.
 *
 * Returns reference to a newly created object or NULL in case of failure.
 */
virLogOutputPtr
virLogOutputNew(virLogOutputFunc f,
                virLogCloseFunc c,
                void *data,
                virLogPriority priority,
                virLogDestination dest,
                const char *name)
{
    virLogOutputPtr ret = NULL;
    char *ndup = NULL;

    if (dest == VIR_LOG_TO_SYSLOG || dest == VIR_LOG_TO_FILE) {
        if (!name) {
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("Missing auxiliary data in output definition"));
            return NULL;
        }

        if (VIR_STRDUP(ndup, name) < 0)
            return NULL;
    }

    if (VIR_ALLOC(ret) < 0) {
        VIR_FREE(ndup);
        return NULL;
    }

    ret->logInitMessage = true;
    ret->f = f;
    ret->c = c;
    ret->data = data;
    ret->priority = priority;
    ret->dest = dest;
    ret->name = ndup;

    return ret;
}
E
Erik Skultety 已提交
1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408


/**
 * virLogFilterNew:
 * @match: the pattern to match
 * @priority: the priority to give to messages matching the pattern
 * @flags: extra flags, see virLogFilterFlags enum
 *
 * Allocates and returns a new log filter object. The object has to be later
 * defined, so that the pattern will be taken into account when executing the
 * log filters (to select or reject a particular message) on messages.
 *
 * The filter defines a rules that will apply only to messages matching
 * the pattern (currently if @match is a substring of the message category)
 *
 * Returns a reference to a newly created filter that needs to be defined using
 * virLogDefineFilters, or NULL in case of an error.
 */
virLogFilterPtr
virLogFilterNew(const char *match,
                virLogPriority priority,
                unsigned int flags)
{
    virLogFilterPtr ret = NULL;
    char *mdup = NULL;
1409
    size_t mlen = strlen(match);
E
Erik Skultety 已提交
1410

1411
    virCheckFlags(VIR_LOG_STACK_TRACE, NULL);
E
Erik Skultety 已提交
1412 1413 1414 1415 1416 1417 1418

    if (priority < VIR_LOG_DEBUG || priority > VIR_LOG_ERROR) {
        virReportError(VIR_ERR_INVALID_ARG, _("Invalid log priority %d"),
                       priority);
        return NULL;
    }

1419 1420 1421 1422
    /* We must treat 'foo' as equiv to '*foo*' for fnmatch
     * todo substring matches, so add 2 extra bytes
     */
    if (VIR_ALLOC_N_QUIET(mdup, mlen + 3) < 0)
E
Erik Skultety 已提交
1423 1424
        return NULL;

1425 1426 1427 1428
    mdup[0] = '*';
    memcpy(mdup + 1, match, mlen);
    mdup[mlen + 1] = '*';

E
Erik Skultety 已提交
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
    if (VIR_ALLOC_QUIET(ret) < 0) {
        VIR_FREE(mdup);
        return NULL;
    }

    ret->match = mdup;
    ret->priority = priority;
    ret->flags = flags;

    return ret;
}
E
Erik Skultety 已提交
1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471


/**
 * virLogFindOutput:
 * @outputs: a list of outputs where to look for the output of type @dest
 * @noutputs: number of elements in @outputs
 * @dest: destination type of an output
 * @opaque: opaque data to the method (only filename at the moment)
 *
 * Looks for an output of destination type @dest in the source list @outputs.
 * If such an output exists, index of the object in the list is returned.
 * In case of the destination being of type FILE also a comparison of the
 * output's filename with @opaque is performed first.
 *
 * Returns the index of the object in the list or -1 if no object matching the
 * specified @dest type and/or @opaque data one was found.
 */
int
virLogFindOutput(virLogOutputPtr *outputs, size_t noutputs,
                 virLogDestination dest, const void *opaque)
{
    size_t i;
    const char *name = opaque;

    for (i = 0; i < noutputs; i++) {
        if (dest == outputs[i]->dest &&
            (STREQ_NULLABLE(outputs[i]->name, name)))
                return i;
    }

    return -1;
}
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485


/**
 * virLogDefineOutputs:
 * @outputs: new set of outputs to be defined
 * @noutputs: number of outputs in @outputs
 *
 * Resets any existing set of outputs and defines a completely new one.
 *
 * Returns number of outputs successfully defined or -1 in case of error;
 */
int
virLogDefineOutputs(virLogOutputPtr *outputs, size_t noutputs)
{
1486
#if HAVE_SYSLOG_H
1487 1488
    int id;
    char *tmp = NULL;
1489
#endif /* HAVE_SYSLOG_H */
1490

1491 1492 1493 1494 1495
    if (virLogInitialize() < 0)
        return -1;

    virLogLock();
    virLogResetOutputs();
1496

1497
#if HAVE_SYSLOG_H
1498 1499 1500 1501 1502 1503 1504
    /* syslog needs to be special-cased, since it keeps the fd in private */
    if ((id = virLogFindOutput(outputs, noutputs, VIR_LOG_TO_SYSLOG,
                               current_ident)) != -1) {
        /* nothing can go wrong now (except for malloc) and since we're also
         * holding the lock so it's safe to call openlog and change the message
         * tag
         */
1505 1506 1507 1508
        if (VIR_STRDUP_QUIET(tmp, outputs[id]->name) < 0) {
            virLogUnlock();
            return -1;
        }
1509 1510 1511 1512
        VIR_FREE(current_ident);
        current_ident = tmp;
        openlog(current_ident, 0, 0);
    }
1513
#endif /* HAVE_SYSLOG_H */
1514

1515 1516 1517
    virLogOutputs = outputs;
    virLogNbOutputs = noutputs;

1518
    virLogUnlock();
1519
    return 0;
1520
}
1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547


/**
 * virLogDefineFilters:
 * @filters: new set of filters to be defined
 * @nfilters: number of filters in @filters
 *
 * Resets any existing set of filters and defines a completely new one. The
 * resulting set can also be empty in which case NULL should be passed to
 * @filters.
 *
 * Returns 0 on success or -1 in case of error.
 */
int
virLogDefineFilters(virLogFilterPtr *filters, size_t nfilters)
{
    if (virLogInitialize() < 0)
        return -1;

    virLogLock();
    virLogResetFilters();
    virLogFilters = filters;
    virLogNbFilters = nfilters;
    virLogUnlock();

    return 0;
}
1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592


/**
 * virLogParseOutput:
 * @src: string defining a single output
 *
 * The format of @src should be one of the following:
 *    x:stderr - output is sent to stderr
 *    x:journald - output is sent to journald
 *    x:syslog:name - output is sent to syslog using 'name' as the message tag
 *    x:file:abs_file_path - output is sent to file specified by 'abs_file_path'
 *
 *      'x' - minimal priority level which acts as a filter meaning that only
 *            messages with priority level greater than or equal to 'x' will be
 *            sent to output @src; supported values for 'x' are as follows:
 *              1: DEBUG
 *              2: INFO
 *              3: WARNING
 *              4: ERROR
 *
 * Parses @src string into a logging object type. If running in setuid mode,
 * then only destination of type 'stderr' is permitted.
 *
 * Returns a newly created logging object from @src on success or NULL in case
 * of an error.
 */
virLogOutputPtr
virLogParseOutput(const char *src)
{
    virLogOutputPtr ret = NULL;
    char **tokens = NULL;
    char *abspath = NULL;
    size_t count = 0;
    virLogPriority prio;
    int dest;
    bool isSUID = virIsSUID();

    VIR_DEBUG("output=%s", src);

    /* split our format prio:destination:additional_data to tokens and parse
     * them individually
     */
    if (!(tokens = virStringSplitCount(src, ":", 0, &count)) || count < 2) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Malformed format for output '%s'"), src);
1593
        goto cleanup;
1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653
    }

    if (virStrToLong_uip(tokens[0], NULL, 10, &prio) < 0 ||
        (prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR)) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Invalid priority '%s' for output '%s'"),
                       tokens[0], src);
        goto cleanup;
    }

    if ((dest = virLogDestinationTypeFromString(tokens[1])) < 0) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Invalid destination '%s' for output '%s'"),
                       tokens[1], src);
        goto cleanup;
    }

    if (((dest == VIR_LOG_TO_STDERR ||
          dest == VIR_LOG_TO_JOURNALD) && count != 2) ||
        ((dest == VIR_LOG_TO_FILE ||
          dest == VIR_LOG_TO_SYSLOG) && count != 3)) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Output '%s' does not meet the format requirements "
                         "for destination type '%s'"), src, tokens[1]);
        goto cleanup;
    }

    /* if running with setuid, only 'stderr' is allowed */
    if (isSUID && dest != VIR_LOG_TO_STDERR) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Running with SUID permits only destination of type "
                         "'stderr'"));
        goto cleanup;
    }

    switch ((virLogDestination) dest) {
    case VIR_LOG_TO_STDERR:
        ret = virLogNewOutputToStderr(prio);
        break;
    case VIR_LOG_TO_SYSLOG:
#if HAVE_SYSLOG_H
        ret = virLogNewOutputToSyslog(prio, tokens[2]);
#endif
        break;
    case VIR_LOG_TO_FILE:
        if (virFileAbsPath(tokens[2], &abspath) < 0)
            goto cleanup;
        ret = virLogNewOutputToFile(prio, abspath);
        VIR_FREE(abspath);
        break;
    case VIR_LOG_TO_JOURNALD:
#if USE_JOURNALD
        ret = virLogNewOutputToJournald(prio);
#endif
        break;
    case VIR_LOG_TO_OUTPUT_LAST:
        break;
    }

 cleanup:
1654
    virStringListFree(tokens);
1655 1656
    return ret;
}
1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701


/**
 * virLogParseFilter:
 * @src: string defining a single filter
 *
 * The format of @src should be one of the following:
 *    x:name - filter affecting all modules which match 'name'
 *    x:+name
 *
 *      '+' - hints the logger to also include a stack trace for every message
 *      'name' - match string which either matches a name of a directory in
 *               libvirt's source tree which in turn affects all modules in
 *               that directory or it can matches a specific module within a
 *               directory, e.g. 'util.file' will only affect messages from
 *               module virfile.c inside src/util/ directory
 *      'x' - minimal priority level which acts as a filter meaning that only
 *            messages with priority level greater than or equal to 'x' will be
 *            sent to output; supported values for 'x' are as follows:
 *              1: DEBUG
 *              2: INFO
 *              3: WARNING
 *              4: ERROR
 *
 * Parses @src string into a logging object type.
 *
 * Returns a newly created logging object from @src on success or NULL in case
 * of an error.
 */
virLogFilterPtr
virLogParseFilter(const char *src)
{
    virLogFilterPtr ret = NULL;
    size_t count = 0;
    virLogPriority prio;
    char **tokens = NULL;
    unsigned int flags = 0;
    char *match = NULL;

    VIR_DEBUG("filter=%s", src);

    /* split our format prio:match_str to tokens and parse them individually */
    if (!(tokens = virStringSplitCount(src, ":", 0, &count)) || count != 2) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Malformed format for filter '%s'"), src);
1702
        goto cleanup;
1703 1704 1705 1706 1707
    }

    if (virStrToLong_uip(tokens[0], NULL, 10, &prio) < 0 ||
        (prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR)) {
        virReportError(VIR_ERR_INVALID_ARG,
1708
                       _("Invalid priority '%s' for filter '%s'"),
1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730
                       tokens[0], src);
        goto cleanup;
    }

    match = tokens[1];
    if (match[0] == '+') {
        flags |= VIR_LOG_STACK_TRACE;
        match++;
    }

    /* match string cannot comprise just from a single '+' */
    if (!*match) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Invalid match string '%s'"), tokens[1]);

        goto cleanup;
    }

    if (!(ret = virLogFilterNew(match, prio, flags)))
        goto cleanup;

 cleanup:
1731
    virStringListFree(tokens);
1732 1733
    return ret;
}
1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790

/**
 * virLogParseOutputs:
 * @src: string defining a (set of) output(s)
 * @outputs: user-supplied list where parsed outputs from @src shall be stored
 *
 * Parses a (set of) output(s) into a list of logging objects. Multiple outputs
 * can be defined within @src string, they just need to be separated by spaces.
 * If running in setuid mode, then only the 'stderr' output will be allowed.
 *
 * Returns the number of outputs parsed or -1 in case of error.
 */
int
virLogParseOutputs(const char *src, virLogOutputPtr **outputs)
{
    int ret = -1;
    int at = -1;
    size_t noutputs = 0;
    size_t i, count;
    char **strings = NULL;
    virLogOutputPtr output = NULL;
    virLogOutputPtr *list = NULL;

    VIR_DEBUG("outputs=%s", src);

    if (!(strings = virStringSplitCount(src, " ", 0, &count)))
        goto cleanup;

    for (i = 0; i < count; i++) {
        /* virStringSplit may return empty strings */
        if (STREQ(strings[i], ""))
            continue;

        if (!(output = virLogParseOutput(strings[i])))
            goto cleanup;

        /* let's check if a duplicate output does not already exist in which
         * case we need to replace it with its last occurrence, however, rather
         * than first deleting the duplicate and then adding the new one, the
         * new output object is added first so in case of an error we don't
         * lose the old entry
         */
        at = virLogFindOutput(list, noutputs, output->dest, output->name);
        if (VIR_APPEND_ELEMENT(list, noutputs, output) < 0) {
            virLogOutputFree(output);
            goto cleanup;
        }
        if (at >= 0) {
            virLogOutputFree(list[at]);
            VIR_DELETE_ELEMENT(list, at, noutputs);
        }
    }

    ret = noutputs;
    *outputs = list;
    list = NULL;
 cleanup:
1791
    virStringListFree(strings);
1792 1793
    return ret;
}
1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840

/**
 * virLogParseFilters:
 * @src: string defining a (set of) filter(s)
 * @filters: pointer to a list where the individual filters shall be parsed
 *
 * This method parses @src and produces a list of individual filters which then
 * needs to be passed to virLogDefineFilters in order to be set and taken into
 * effect.
 * Multiple filters can be defined in a single @src, they just need to be
 * separated by spaces.
 *
 * Returns the number of filter parsed or -1 in case of error.
 */
int
virLogParseFilters(const char *src, virLogFilterPtr **filters)
{
    int ret = -1;
    size_t nfilters = 0;
    size_t i, count;
    char **strings = NULL;
    virLogFilterPtr filter = NULL;
    virLogFilterPtr *list = NULL;

    VIR_DEBUG("filters=%s", src);

    if (!(strings = virStringSplitCount(src, " ", 0, &count)))
        goto cleanup;

    for (i = 0; i < count; i++) {
        /* virStringSplit may return empty strings */
        if (STREQ(strings[i], ""))
            continue;

        if (!(filter = virLogParseFilter(strings[i])))
            goto cleanup;

        if (VIR_APPEND_ELEMENT(list, nfilters, filter)) {
            virLogFilterFree(filter);
            goto cleanup;
        }
    }

    ret = nfilters;
    *filters = list;
    list = NULL;
 cleanup:
1841
    virStringListFree(strings);
1842 1843
    return ret;
}
E
Erik Skultety 已提交
1844 1845 1846 1847 1848 1849

/**
 * virLogSetOutputs:
 * @outputs: string defining a (set of) output(s)
 *
 * Replaces the current set of defined outputs with a new set of outputs.
1850 1851
 * Should the set be empty or NULL, a default output is used according to the
 * daemon's runtime attributes.
E
Erik Skultety 已提交
1852 1853 1854 1855 1856 1857 1858 1859
 *
 * Returns 0 on success or -1 in case of an error.
 */
int
virLogSetOutputs(const char *src)
{
    int ret = -1;
    int noutputs = 0;
1860
    const char *outputstr = virLogDefaultOutput;
E
Erik Skultety 已提交
1861 1862 1863 1864 1865
    virLogOutputPtr *outputs = NULL;

    if (virLogInitialize() < 0)
        return -1;

1866 1867 1868
    if (src && *src)
        outputstr = src;

1869 1870 1871 1872 1873 1874 1875
    /* This can only happen during daemon init when the default output is not
     * determined yet. It's safe to do, since it's the only place setting the
     * default output.
     */
    if (!outputstr)
        return 0;

1876
    if ((noutputs = virLogParseOutputs(outputstr, &outputs)) < 0)
E
Erik Skultety 已提交
1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887
        goto cleanup;

    if (virLogDefineOutputs(outputs, noutputs) < 0)
        goto cleanup;

    outputs = NULL;
    ret = 0;
 cleanup:
    virLogOutputListFree(outputs, noutputs);
    return ret;
}
E
Erik Skultety 已提交
1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919


/**
 * virLogSetFilters:
 * @src: string defining a (set of) filter(s)
 *
 * Replaces the current set of defined filters with a new set of filters.
 *
 * Returns 0 on success or -1 in case of an error.
 */
int
virLogSetFilters(const char *src)
{
    int ret = -1;
    int nfilters = 0;
    virLogFilterPtr *filters = NULL;

    if (virLogInitialize() < 0)
        return -1;

    if (src && (nfilters = virLogParseFilters(src, &filters)) < 0)
        goto cleanup;

    if (virLogDefineFilters(filters, nfilters) < 0)
        goto cleanup;

    filters = NULL;
    ret = 0;
 cleanup:
    virLogFilterListFree(filters, nfilters);
    return ret;
}