virlog.c 38.8 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 30 31
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
32
#include <unistd.h>
33
#include <execinfo.h>
34
#include <regex.h>
D
Daniel Veillard 已提交
35
#if HAVE_SYSLOG_H
36
# include <syslog.h>
D
Daniel Veillard 已提交
37
#endif
D
Daniel P. Berrange 已提交
38 39 40 41
#include <sys/socket.h>
#if HAVE_SYS_UN_H
# include <sys/un.h>
#endif
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

E
Eric Blake 已提交
54 55 56 57 58 59
/* 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

60 61
#define VIR_FROM_THIS VIR_FROM_NONE

62 63
VIR_LOG_INIT("util.log");

64
static regex_t *virLogRegex;
65 66


67 68
#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}"
69
#define VIR_LOG_PID_REGEX "[0-9]+"
70
#define VIR_LOG_LEVEL_REGEX "(debug|info|warning|error)"
71 72 73 74

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

76 77 78 79
VIR_ENUM_DECL(virLogDestination);
VIR_ENUM_IMPL(virLogDestination, VIR_LOG_TO_OUTPUT_LAST,
              "stderr", "syslog", "file", "journald");

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

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 111
static virLogOutputPtr *virLogOutputs;
static size_t virLogNbOutputs;
D
Daniel Veillard 已提交
112 113 114 115

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

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

132

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

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


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

151 152 153 154

static const char *
virLogPriorityString(virLogPriority lvl)
{
D
Daniel Veillard 已提交
155
    switch (lvl) {
156 157 158 159 160 161 162 163
    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 已提交
164
    }
165
    return "unknown";
D
Daniel Veillard 已提交
166 167 168
}


169 170
static int
virLogOnceInit(void)
171
{
172 173 174
    if (virMutexInit(&virLogMutex) < 0)
        return -1;

D
Daniel Veillard 已提交
175
    virLogLock();
176
    virLogDefaultPriority = VIR_LOG_DEFAULT;
177

178
    if (VIR_ALLOC_QUIET(virLogRegex) >= 0) {
179 180 181 182
        if (regcomp(virLogRegex, VIR_LOG_REGEX, REG_EXTENDED) != 0)
            VIR_FREE(virLogRegex);
    }

D
Daniel Veillard 已提交
183
    virLogUnlock();
184
    return 0;
D
Daniel Veillard 已提交
185 186
}

187 188
VIR_ONCE_GLOBAL_INIT(virLog)

189

D
Daniel Veillard 已提交
190 191 192 193 194 195 196
/**
 * virLogReset:
 *
 * Reset the logging module to its default initial state
 *
 * Returns 0 if successful, and -1 in case or error
 */
197 198 199
int
virLogReset(void)
{
200 201
    if (virLogInitialize() < 0)
        return -1;
D
Daniel Veillard 已提交
202 203 204 205

    virLogLock();
    virLogResetFilters();
    virLogResetOutputs();
206
    virLogDefaultPriority = VIR_LOG_DEFAULT;
D
Daniel Veillard 已提交
207
    virLogUnlock();
208
    return 0;
D
Daniel Veillard 已提交
209 210 211 212 213 214 215 216 217 218 219 220
}

/**
 * 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.
 */
221 222 223
int
virLogSetDefaultPriority(virLogPriority priority)
{
224
    if ((priority < VIR_LOG_DEBUG) || (priority > VIR_LOG_ERROR)) {
225
        VIR_WARN("Ignoring invalid log level setting.");
226
        return -1;
227
    }
228 229 230
    if (virLogInitialize() < 0)
        return -1;

D
Daniel Veillard 已提交
231
    virLogDefaultPriority = priority;
232
    return 0;
D
Daniel Veillard 已提交
233 234
}

235

D
Daniel Veillard 已提交
236 237 238 239 240
/**
 * virLogResetFilters:
 *
 * Removes the set of logging filters defined.
 */
241
static void
242 243
virLogResetFilters(void)
{
244
    size_t i;
D
Daniel Veillard 已提交
245

246 247 248 249
    for (i = 0; i < virLogNbFilters; i++) {
        VIR_FREE(virLogFilters[i]->match);
        VIR_FREE(virLogFilters[i]);
    }
D
Daniel Veillard 已提交
250 251
    VIR_FREE(virLogFilters);
    virLogNbFilters = 0;
252
    virLogFiltersSerial++;
D
Daniel Veillard 已提交
253 254
}

255

D
Daniel Veillard 已提交
256 257 258 259
/**
 * virLogDefineFilter:
 * @match: the pattern to match
 * @priority: the priority to give to messages matching the pattern
260
 * @flags: extra flags, see virLogFilterFlags enum
D
Daniel Veillard 已提交
261 262 263 264 265 266 267 268
 *
 * Defines a pattern used for log filtering, it allow to select or
 * reject messages independently of the default priority.
 * 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 -1 in case of failure or the filter number if successful
 */
269 270 271 272
int
virLogDefineFilter(const char *match,
                   virLogPriority priority,
                   unsigned int flags)
273
{
274 275
    size_t i;
    int ret = -1;
D
Daniel Veillard 已提交
276
    char *mdup = NULL;
277
    virLogFilterPtr filter = NULL;
D
Daniel Veillard 已提交
278

279
    virCheckFlags(VIR_LOG_STACK_TRACE, -1);
280

281 282 283
    if (virLogInitialize() < 0)
        return -1;

D
Daniel Veillard 已提交
284 285
    if ((match == NULL) || (priority < VIR_LOG_DEBUG) ||
        (priority > VIR_LOG_ERROR))
286
        return -1;
D
Daniel Veillard 已提交
287 288

    virLogLock();
289
    for (i = 0; i < virLogNbFilters; i++) {
290 291
        if (STREQ(virLogFilters[i]->match, match)) {
            virLogFilters[i]->priority = priority;
292
            ret = i;
D
Daniel Veillard 已提交
293 294 295 296
            goto cleanup;
        }
    }

297
    if (VIR_STRDUP_QUIET(mdup, match) < 0)
D
Daniel Veillard 已提交
298
        goto cleanup;
299 300

    if (VIR_ALLOC_QUIET(filter) < 0) {
D
Daniel Veillard 已提交
301 302 303
        VIR_FREE(mdup);
        goto cleanup;
    }
304 305 306 307 308 309 310 311

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

    if (VIR_APPEND_ELEMENT_QUIET(virLogFilters, virLogNbFilters, filter) < 0)
        goto cleanup;

312
    virLogFiltersSerial++;
313
 cleanup:
D
Daniel Veillard 已提交
314
    virLogUnlock();
315
    if (ret < 0)
316
        virReportOOMError();
317
    return virLogNbFilters;
D
Daniel Veillard 已提交
318 319 320 321 322 323 324
}

/**
 * virLogResetOutputs:
 *
 * Removes the set of logging output defined.
 */
325
static void
326 327
virLogResetOutputs(void)
{
328 329
    virLogOutputListFree(virLogOutputs, virLogNbOutputs);
    virLogOutputs = NULL;
D
Daniel Veillard 已提交
330 331 332
    virLogNbOutputs = 0;
}

333

334 335 336 337 338 339 340 341 342 343 344 345 346
void
virLogOutputFree(virLogOutputPtr output)
{
    if (!output)
        return;

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

}

347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368

/**
 * 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);
}


D
Daniel Veillard 已提交
369 370 371
/**
 * virLogDefineOutput:
 * @f: the function to call to output a message
372
 * @c: the function to call to close the output (or NULL)
D
Daniel Veillard 已提交
373 374
 * @data: extra data passed as first arg to the function
 * @priority: minimal priority for this filter, use 0 for none
375 376
 * @dest: where to send output of this priority
 * @name: optional name data associated with an output
D
Daniel Veillard 已提交
377 378 379 380 381 382 383
 * @flags: extra flag, currently unused
 *
 * Defines an output function for log messages. Each message once
 * gone though filtering is emitted through each registered output.
 *
 * Returns -1 in case of failure or the output number if successful
 */
384 385 386 387 388 389 390 391
int
virLogDefineOutput(virLogOutputFunc f,
                   virLogCloseFunc c,
                   void *data,
                   virLogPriority priority,
                   virLogDestination dest,
                   const char *name,
                   unsigned int flags)
392
{
393
    char *ndup = NULL;
394
    virLogOutputPtr output = NULL;
D
Daniel Veillard 已提交
395

396 397
    virCheckFlags(0, -1);

398 399 400
    if (virLogInitialize() < 0)
        return -1;

D
Daniel Veillard 已提交
401
    if (f == NULL)
402
        return -1;
D
Daniel Veillard 已提交
403

404
    if (dest == VIR_LOG_TO_SYSLOG || dest == VIR_LOG_TO_FILE) {
405 406
        if (!name) {
            virReportOOMError();
407
            return -1;
408 409
        }
        if (VIR_STRDUP(ndup, name) < 0)
410
            return -1;
411 412
    }

413
    if (VIR_ALLOC_QUIET(output) < 0) {
414
        VIR_FREE(ndup);
415
        return -1;
D
Daniel Veillard 已提交
416
    }
417 418 419 420 421 422 423 424 425 426 427 428 429

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

    virLogLock();
    if (VIR_APPEND_ELEMENT_QUIET(virLogOutputs, virLogNbOutputs, output))
        goto cleanup;

430
 cleanup:
D
Daniel Veillard 已提交
431
    virLogUnlock();
432
    return virLogNbOutputs;
D
Daniel Veillard 已提交
433 434
}

435

436 437
static int
virLogFormatString(char **msg,
438
                   int linenr,
439
                   const char *funcname,
440
                   virLogPriority priority,
441 442 443
                   const char *str)
{
    int ret;
444 445 446 447 448 449 450 451

    /*
     * 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.
     */
452
    if ((funcname != NULL)) {
453 454 455
        ret = virAsprintfQuiet(msg, "%llu: %s : %s:%d : %s\n",
                               virThreadSelfID(), virLogPriorityString(priority),
                               funcname, linenr, str);
456
    } else {
457 458 459
        ret = virAsprintfQuiet(msg, "%llu: %s : %s\n",
                               virThreadSelfID(), virLogPriorityString(priority),
                               str);
460 461 462 463
    }
    return ret;
}

464

465
static int
466 467
virLogVersionString(const char **rawmsg,
                    char **msg)
468
{
469 470
    *rawmsg = VIR_LOG_VERSION_STRING;
    return virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, VIR_LOG_VERSION_STRING);
471 472
}

473 474 475 476
/* Similar to virGetHostname() but avoids use of error
 * reporting APIs or logging APIs, to prevent recursion
 */
static int
477
virLogHostnameString(char **rawmsg,
478 479 480 481 482 483 484 485 486 487 488 489
                     char **msg)
{
    char *hostname = virGetHostnameQuiet();
    char *hoststr;

    if (!hostname)
        return -1;

    if (virAsprintfQuiet(&hoststr, "hostname: %s", hostname) < 0) {
        VIR_FREE(hostname);
        return -1;
    }
490
    VIR_FREE(hostname);
491 492 493 494 495 496 497 498 499

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

500

501 502 503 504 505 506 507 508 509 510
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++) {
511 512 513
            if (strstr(source->name, virLogFilters[i]->match)) {
                priority = virLogFilters[i]->priority;
                flags = virLogFilters[i]->flags;
514 515 516 517 518 519 520 521 522 523 524
                break;
            }
        }

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

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

556

557 558
/**
 * virLogVMessage:
559
 * @source: where is that message coming from
560
 * @priority: the priority level
561
 * @filename: file where the message was emitted
562
 * @linenr: line where the message was emitted
563
 * @funcname: the function emitting the (debug) message
564
 * @metadata: NULL or metadata array, terminated by an item with NULL key
565 566 567 568 569 570
 * @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
 */
571
void
572
virLogVMessage(virLogSourcePtr source,
573
               virLogPriority priority,
574
               const char *filename,
575
               int linenr,
576
               const char *funcname,
M
Miloslav Trmač 已提交
577
               virLogMetadataPtr metadata,
578 579
               const char *fmt,
               va_list vargs)
580
{
581
    static bool logInitMessageStderr = true;
D
Daniel Veillard 已提交
582
    char *str = NULL;
583
    char *msg = NULL;
584
    char timestamp[VIR_TIME_STRING_BUFLEN];
585
    int ret;
586
    size_t i;
587
    int saved_errno = errno;
588
    unsigned int filterflags = 0;
D
Daniel Veillard 已提交
589

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

    if (fmt == NULL)
594
        return;
D
Daniel Veillard 已提交
595 596

    /*
597 598 599 600 601 602
     * 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 已提交
603
     */
604 605 606
    if (source->serial < virLogFiltersSerial)
        virLogSourceUpdate(source);
    if (priority < source->priority)
607
        goto cleanup;
608
    filterflags = source->flags;
609

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

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

620 621
    if (virTimeStringNowRaw(timestamp) < 0)
        timestamp[0] = '\0';
622

623 624
    virLogLock();

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

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

689

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

#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) {
704 705 706
        ignore_value(safewrite(fd, msg, strlen(msg)));
        doneWarning = true;
    }
707
#undef STRIP_DEPTH
708 709
}

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

    if (fd < 0)
727
        return;
728

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

732
    ignore_value(safewrite(fd, msg, strlen(msg)));
733 734
    VIR_FREE(msg);

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

739 740 741

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

745
    VIR_LOG_CLOSE(fd);
D
Daniel Veillard 已提交
746 747
}

748 749 750 751

static int
virLogAddOutputToStderr(virLogPriority priority)
{
752 753
    if (virLogDefineOutput(virLogOutputToFd, NULL, (void *)2L, priority,
                           VIR_LOG_TO_STDERR, NULL, 0) < 0)
754 755
        return -1;
    return 0;
D
Daniel Veillard 已提交
756 757
}

758 759 760 761 762

static int
virLogAddOutputToFile(virLogPriority priority,
                      const char *file)
{
D
Daniel Veillard 已提交
763 764
    int fd;

765
    fd = open(file, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR);
D
Daniel Veillard 已提交
766
    if (fd < 0)
767
        return -1;
768 769
    if (virLogDefineOutput(virLogOutputToFd, virLogCloseFd,
                           (void *)(intptr_t)fd,
770
                           priority, VIR_LOG_TO_FILE, file, 0) < 0) {
771
        VIR_FORCE_CLOSE(fd);
772
        return -1;
D
Daniel Veillard 已提交
773
    }
774
    return 0;
D
Daniel Veillard 已提交
775 776
}

777

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 844 845 846

static int
virLogAddOutputToSyslog(virLogPriority priority,
                        const char *ident)
{
847 848 849 850
    /*
     * ident needs to be kept around on Solaris
     */
    VIR_FREE(current_ident);
851
    if (VIR_STRDUP(current_ident, ident) < 0)
852
        return -1;
853 854

    openlog(current_ident, 0, 0);
D
Daniel Veillard 已提交
855
    if (virLogDefineOutput(virLogOutputToSyslog, virLogCloseSyslog, NULL,
856
                           priority, VIR_LOG_TO_SYSLOG, ident, 0) < 0) {
D
Daniel Veillard 已提交
857
        closelog();
858
        VIR_FREE(current_ident);
859
        return -1;
D
Daniel Veillard 已提交
860
    }
861
    return 0;
D
Daniel Veillard 已提交
862
}
D
Daniel P. Berrange 已提交
863 864


E
Eric Blake 已提交
865
# if USE_JOURNALD
866 867 868 869 870
#  define IOVEC_SET(iov, data, size)            \
    do {                                        \
        struct iovec *_i = &(iov);              \
        _i->iov_base = (void*)(data);           \
        _i->iov_len = (size);                   \
D
Daniel P. Berrange 已提交
871 872
    } while (0)

873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 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
#  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 已提交
938 939 940 941

static int journalfd = -1;

static void
942
virLogOutputToJournald(virLogSourcePtr source,
D
Daniel P. Berrange 已提交
943 944 945 946 947
                       virLogPriority priority,
                       const char *filename,
                       int linenr,
                       const char *funcname,
                       const char *timestamp ATTRIBUTE_UNUSED,
948
                       virLogMetadataPtr metadata,
D
Daniel P. Berrange 已提交
949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966
                       unsigned int flags,
                       const char *rawstr,
                       const char *str ATTRIBUTE_UNUSED,
                       void *data ATTRIBUTE_UNUSED)
{
    virCheckFlags(VIR_LOG_STACK_TRACE,);
    int buffd = -1;
    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";
967
    size_t nmetadata = 0;
D
Daniel P. Berrange 已提交
968

969 970 971
#  define NUM_FIELDS_CORE 6
#  define NUM_FIELDS_META 5
#  define NUM_FIELDS (NUM_FIELDS_CORE + NUM_FIELDS_META)
972 973 974
    struct iovec iov[NUM_FIELDS * 5];
    char iov_bufs[NUM_FIELDS][JOURNAL_BUF_SIZE];
    struct journalState state;
D
Daniel P. Berrange 已提交
975

976 977 978 979
    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 已提交
980

E
Eric Blake 已提交
981
    journalAddString(&state, "MESSAGE", rawstr);
982 983
    journalAddInt(&state, "PRIORITY",
                  virLogPrioritySyslog(priority));
984
    journalAddInt(&state, "SYSLOG_FACILITY", LOG_DAEMON);
985
    journalAddString(&state, "LIBVIRT_SOURCE", source->name);
986 987
    if (filename)
        journalAddString(&state, "CODE_FILE", filename);
988
    journalAddInt(&state, "CODE_LINE", linenr);
989 990
    if (funcname)
        journalAddString(&state, "CODE_FUNC", funcname);
991 992 993 994 995 996 997 998 999 1000 1001
    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 已提交
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011

    memset(&sa, 0, sizeof(sa));
    sa.sun_family = AF_UNIX;
    if (!virStrcpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path)))
        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;
1012
    mh.msg_iovlen = state.iov - iov;
D
Daniel P. Berrange 已提交
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035

    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;

1036
    if (writev(buffd, iov, state.iov - iov) < 0)
D
Daniel P. Berrange 已提交
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
        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;

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

1056
 cleanup:
D
Daniel P. Berrange 已提交
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
    VIR_LOG_CLOSE(buffd);
}


static void virLogCloseJournald(void *data ATTRIBUTE_UNUSED)
{
    VIR_LOG_CLOSE(journalfd);
}


static int virLogAddOutputToJournald(int priority)
{
    if ((journalfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
        return -1;
    if (virSetInherit(journalfd, false) < 0) {
        VIR_LOG_CLOSE(journalfd);
        return -1;
    }
    if (virLogDefineOutput(virLogOutputToJournald, virLogCloseJournald, NULL,
                           priority, VIR_LOG_TO_JOURNALD, NULL, 0) < 0) {
        return -1;
    }
    return 0;
}
E
Eric Blake 已提交
1081
# endif /* USE_JOURNALD */
J
Ján Tomko 已提交
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106

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 已提交
1107 1108 1109 1110 1111 1112
#endif /* HAVE_SYSLOG_H */

#define IS_SPACE(cur)                                                   \
    ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') ||               \
     (*cur == '\r') || (*cur == '\\'))

1113

1114 1115 1116 1117 1118 1119 1120 1121
static int
virLogParseOutput(const char *src)
{
    int ret = -1;
    char **tokens = NULL;
    char *abspath = NULL;
    size_t count = 0;
    virLogPriority prio;
1122
    int dest;
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185
    bool isSUID = virIsSUID();

    if (!src)
        return -1;

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

    /* split our format prio:destination:additional_data to tokens and parse
     * them individually
     */
    if (!(tokens = virStringSplitCount(src, ":", 0, &count)))
        return -1;

    if (virStrToLong_uip(tokens[0], NULL, 10, &prio) < 0 ||
        (prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
        goto cleanup;

    if ((dest = virLogDestinationTypeFromString(tokens[1])) < 0)
        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))
        goto cleanup;

    /* if running with setuid, only 'stderr' is allowed */
    if (isSUID && dest != VIR_LOG_TO_STDERR)
        goto cleanup;

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

 cleanup:
    if (ret < 0)
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to parse and define log output %s"), src);
    virStringFreeList(tokens);
    return ret;
}


D
Daniel Veillard 已提交
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
/**
 * virLogParseOutputs:
 * @outputs: string defining a (set of) output(s)
 *
 * The format for an output can be:
 *    x:stderr
 *       output goes to stderr
 *    x:syslog:name
 *       use syslog for the output and use the given name as the ident
 *    x:file:file_path
 *       output to a file, with the given filepath
 * In all case the x prefix is the minimal level, acting as a filter
 *    1: DEBUG
 *    2: INFO
 *    3: WARNING
 *    4: ERROR
 *
 * Multiple output can be defined in a single @output, they just need to be
 * separated by spaces.
 *
1206 1207 1208
 * If running in setuid mode, then only the 'stderr' output will
 * be allowed
 *
1209
 * Returns the number of output parsed or -1 in case of error.
D
Daniel Veillard 已提交
1210
 */
1211
int
1212
virLogParseOutputs(const char *src)
1213
{
1214 1215
    int ret = -1;
    int count = 0;
1216 1217
    size_t i;
    char **strings = NULL;
D
Daniel Veillard 已提交
1218

1219
    if (!src)
1220
        return -1;
D
Daniel Veillard 已提交
1221

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

1224 1225 1226 1227 1228 1229 1230 1231 1232
    if (!(strings = virStringSplit(src, " ", 0)))
        goto cleanup;

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

        if (virLogParseOutput(strings[i]) < 0)
1233
            goto cleanup;
1234 1235

        count++;
D
Daniel Veillard 已提交
1236
    }
1237

1238
    ret = count;
1239
 cleanup:
1240
    virStringFreeList(strings);
1241
    return ret;
D
Daniel Veillard 已提交
1242 1243
}

1244

1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290
static int
virLogParseFilter(const char *filter)
{
    int ret = -1;
    size_t count = 0;
    virLogPriority prio;
    char **tokens = NULL;
    unsigned int flags = 0;
    char *ref = NULL;

    if (!filter)
        return -1;

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

    if (!(tokens = virStringSplitCount(filter, ":", 0, &count)))
        return -1;

    if (count != 2)
        goto cleanup;

    if (virStrToLong_uip(tokens[0], NULL, 10, &prio) < 0 ||
        (prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
        goto cleanup;

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

    if (!*ref)
        goto cleanup;

    if (virLogDefineFilter(ref, prio, flags) < 0)
        goto cleanup;

    ret = 0;
 cleanup:
    if (ret < 0)
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to parse and define log filter %s"), filter);
    virStringFreeList(tokens);
    return ret;
}

D
Daniel Veillard 已提交
1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306
/**
 * virLogParseFilters:
 * @filters: string defining a (set of) filter(s)
 *
 * The format for a filter is:
 *    x:name
 *       where name is a match string
 * the x prefix is the minimal level where the messages should be logged
 *    1: DEBUG
 *    2: INFO
 *    3: WARNING
 *    4: ERROR
 *
 * Multiple filter can be defined in a single @filters, they just need to be
 * separated by spaces.
 *
1307
 * Returns the number of filter parsed or -1 in case of error.
D
Daniel Veillard 已提交
1308
 */
1309 1310 1311
int
virLogParseFilters(const char *filters)
{
1312 1313
    int ret = -1;
    int count = 0;
1314 1315
    size_t i;
    char **strings = NULL;
D
Daniel Veillard 已提交
1316

1317
    if (!filters)
1318
        return -1;
D
Daniel Veillard 已提交
1319

1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330
    VIR_DEBUG("filters=%s", filters);

    if (!(strings = virStringSplit(filters, " ", 0)))
        goto cleanup;

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

        if (virLogParseFilter(strings[i]) < 0)
1331
            goto cleanup;
1332 1333

        count++;
D
Daniel Veillard 已提交
1334
    }
1335

1336
    ret = count;
1337
 cleanup:
1338
    virStringFreeList(strings);
1339
    return ret;
D
Daniel Veillard 已提交
1340
}
1341

1342

1343 1344 1345 1346 1347
/**
 * virLogGetDefaultPriority:
 *
 * Returns the current logging priority level.
 */
1348 1349 1350
virLogPriority
virLogGetDefaultPriority(void)
{
1351
    return virLogDefaultPriority;
1352 1353
}

1354

1355 1356 1357 1358 1359 1360 1361
/**
 * virLogGetFilters:
 *
 * Returns a string listing the current filters, in the format originally
 * specified in the config file or environment. Caller must free the
 * result.
 */
1362 1363 1364
char *
virLogGetFilters(void)
{
1365
    size_t i;
1366 1367 1368 1369
    virBuffer filterbuf = VIR_BUFFER_INITIALIZER;

    virLogLock();
    for (i = 0; i < virLogNbFilters; i++) {
1370
        const char *sep = ":";
1371
        if (virLogFilters[i]->flags & VIR_LOG_STACK_TRACE)
1372 1373
            sep = ":+";
        virBufferAsprintf(&filterbuf, "%d%s%s ",
1374
                          virLogFilters[i]->priority,
1375
                          sep,
1376
                          virLogFilters[i]->match);
1377 1378 1379
    }
    virLogUnlock();

1380 1381
    if (virBufferError(&filterbuf)) {
        virBufferFreeAndReset(&filterbuf);
1382
        return NULL;
1383
    }
1384 1385 1386 1387

    return virBufferContentAndReset(&filterbuf);
}

1388

1389 1390 1391 1392 1393 1394 1395
/**
 * virLogGetOutputs:
 *
 * Returns a string listing the current outputs, in the format originally
 * specified in the config file or environment. Caller must free the
 * result.
 */
1396 1397 1398
char *
virLogGetOutputs(void)
{
1399
    size_t i;
1400 1401 1402 1403
    virBuffer outputbuf = VIR_BUFFER_INITIALIZER;

    virLogLock();
    for (i = 0; i < virLogNbOutputs; i++) {
1404
        virLogDestination dest = virLogOutputs[i]->dest;
1405
        if (i)
1406
            virBufferAddChar(&outputbuf, ' ');
1407 1408 1409
        switch (dest) {
            case VIR_LOG_TO_SYSLOG:
            case VIR_LOG_TO_FILE:
1410
                virBufferAsprintf(&outputbuf, "%d:%s:%s",
1411
                                  virLogOutputs[i]->priority,
1412
                                  virLogDestinationTypeToString(dest),
1413
                                  virLogOutputs[i]->name);
1414 1415
                break;
            default:
1416
                virBufferAsprintf(&outputbuf, "%d:%s",
1417
                                  virLogOutputs[i]->priority,
1418
                                  virLogDestinationTypeToString(dest));
1419 1420 1421 1422
        }
    }
    virLogUnlock();

1423 1424
    if (virBufferError(&outputbuf)) {
        virBufferFreeAndReset(&outputbuf);
1425
        return NULL;
1426
    }
1427 1428 1429 1430

    return virBufferContentAndReset(&outputbuf);
}

1431

1432 1433 1434 1435 1436
/**
 * virLogGetNbFilters:
 *
 * Returns the current number of defined log filters.
 */
1437 1438 1439
int
virLogGetNbFilters(void)
{
1440
    return virLogNbFilters;
1441 1442
}

1443

1444 1445 1446 1447 1448
/**
 * virLogGetNbOutputs:
 *
 * Returns the current number of defined log outputs.
 */
1449 1450 1451
int
virLogGetNbOutputs(void)
{
1452
    return virLogNbOutputs;
1453
}
1454

1455

1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466
/**
 * virLogParseDefaultPriority:
 * @priority: string defining the desired logging level
 *
 * Parses and sets the default log priority level. It can take a string or
 * number corresponding to the following levels:
 *    1: DEBUG
 *    2: INFO
 *    3: WARNING
 *    4: ERROR
 *
1467
 * Returns 0 if successful, -1 in case of error.
1468
 */
1469 1470 1471
int
virLogParseDefaultPriority(const char *priority)
{
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
    int ret = -1;

    if (STREQ(priority, "1") || STREQ(priority, "debug"))
        ret = virLogSetDefaultPriority(VIR_LOG_DEBUG);
    else if (STREQ(priority, "2") || STREQ(priority, "info"))
        ret = virLogSetDefaultPriority(VIR_LOG_INFO);
    else if (STREQ(priority, "3") || STREQ(priority, "warning"))
        ret = virLogSetDefaultPriority(VIR_LOG_WARN);
    else if (STREQ(priority, "4") || STREQ(priority, "error"))
        ret = virLogSetDefaultPriority(VIR_LOG_ERROR);
    else
1483
        VIR_WARN("Ignoring invalid log level setting");
1484 1485 1486 1487

    return ret;
}

1488

1489 1490 1491 1492 1493 1494
/**
 * virLogSetFromEnv:
 *
 * Sets virLogDefaultPriority, virLogFilters and virLogOutputs based on
 * environment variables.
 */
1495 1496 1497
void
virLogSetFromEnv(void)
{
1498
    const char *debugEnv;
1499

1500 1501 1502
    if (virLogInitialize() < 0)
        return;

1503
    debugEnv = virGetEnvAllowSUID("LIBVIRT_DEBUG");
1504 1505
    if (debugEnv && *debugEnv)
        virLogParseDefaultPriority(debugEnv);
1506
    debugEnv = virGetEnvAllowSUID("LIBVIRT_LOG_FILTERS");
1507
    if (debugEnv && *debugEnv)
1508
        virLogParseFilters(debugEnv);
1509
    debugEnv = virGetEnvAllowSUID("LIBVIRT_LOG_OUTPUTS");
1510
    if (debugEnv && *debugEnv)
1511
        virLogParseOutputs(debugEnv);
1512
}
1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528


/*
 * 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;
}