]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/log.c
tree-wide: priority -> level
[mirror_lxc.git] / src / lxc / log.c
CommitLineData
e0b4037d
DL
1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Cedric Le Goater <legoater@free.fr>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
250b1eec 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
e0b4037d 22 */
b4c42474
CB
23
24#define _GNU_SOURCE
65a9df89 25#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
65a9df89 26#include <stdint.h>
0ad19a3f 27#include <stdio.h>
28#include <errno.h>
65a9df89 29#include <inttypes.h>
cb8c5720
CLG
30#include <limits.h>
31#include <unistd.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <string.h>
858377e4 35#include <pthread.h>
02d25a9e 36#include <time.h>
cb8c5720 37
64c57ea1
BD
38#include <syslog.h>
39#include <stdio.h>
40
cb8c5720
CLG
41#include <fcntl.h>
42#include <stdlib.h>
43
28f602ff
DL
44#include "log.h"
45#include "caps.h"
ab1bf971 46#include "utils.h"
73b910a3 47#include "lxccontainer.h"
cb8c5720 48
c57dbb96
CB
49/* We're logging in seconds and nanoseconds. Assuming that the underlying
50 * datatype is currently at maximum a 64bit integer, we have a date string that
51 * is of maximum length (2^64 - 1) * 2 = (21 + 21) = 42.
52 */
eab15c1e 53#define LXC_LOG_TIME_SIZE ((LXC_NUMSTRLEN64)*2)
6a22e862 54
9f4f402a 55int lxc_log_fd = -1;
64c57ea1 56static int syslog_enable = 0;
858377e4
SH
57int lxc_quiet_specified;
58int lxc_log_use_global_fd;
59static int lxc_loglevel_specified;
60
6b9f3917 61static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
ab1bf971 62static char *log_fname = NULL;
64c57ea1 63static char *log_vmname = NULL;
cb8c5720
CLG
64
65lxc_log_define(lxc_log, lxc);
66
64c57ea1
BD
67static int lxc_log_priority_to_syslog(int priority)
68{
69 switch (priority) {
4b73005c 70 case LXC_LOG_LEVEL_FATAL:
64c57ea1 71 return LOG_EMERG;
4b73005c 72 case LXC_LOG_LEVEL_ALERT:
64c57ea1 73 return LOG_ALERT;
4b73005c 74 case LXC_LOG_LEVEL_CRIT:
64c57ea1 75 return LOG_CRIT;
4b73005c 76 case LXC_LOG_LEVEL_ERROR:
64c57ea1 77 return LOG_ERR;
4b73005c 78 case LXC_LOG_LEVEL_WARN:
64c57ea1 79 return LOG_WARNING;
4b73005c
CB
80 case LXC_LOG_LEVEL_NOTICE:
81 case LXC_LOG_LEVEL_NOTSET:
64c57ea1 82 return LOG_NOTICE;
4b73005c 83 case LXC_LOG_LEVEL_INFO:
64c57ea1 84 return LOG_INFO;
4b73005c
CB
85 case LXC_LOG_LEVEL_TRACE:
86 case LXC_LOG_LEVEL_DEBUG:
64c57ea1
BD
87 return LOG_DEBUG;
88 }
89
90 /* Not reached */
91 return LOG_NOTICE;
92}
93
94/*---------------------------------------------------------------------------*/
95static int log_append_syslog(const struct lxc_log_appender *appender,
96 struct lxc_log_event *event)
97{
98 char *msg;
99 int rc, len;
100 va_list args;
101
102 if (!syslog_enable)
103 return 0;
104
105 va_copy(args, *event->vap);
106 len = vsnprintf(NULL, 0, event->fmt, args) + 1;
107 va_end(args);
108 msg = malloc(len * sizeof(char));
109 if (msg == NULL)
110 return 0;
111 rc = vsnprintf(msg, len, event->fmt, *event->vap);
112 if (rc == -1 || rc >= len) {
113 free(msg);
114 return 0;
115 }
116
117 syslog(lxc_log_priority_to_syslog(event->priority),
76d0127f 118 "%s%s %s - %s:%s:%d - %s" ,
64c57ea1 119 log_vmname ? log_vmname : "",
76d0127f 120 log_vmname ? ":" : "",
64c57ea1
BD
121 event->category,
122 event->locinfo->file, event->locinfo->func,
123 event->locinfo->line,
124 msg);
125 free(msg);
126 return 0;
127}
128
d737c074
MN
129/*---------------------------------------------------------------------------*/
130static int log_append_stderr(const struct lxc_log_appender *appender,
131 struct lxc_log_event *event)
132{
4b73005c 133 if (event->priority < LXC_LOG_LEVEL_ERROR)
d737c074
MN
134 return 0;
135
c3ff6e24 136 fprintf(stderr, "%s: %s%s", log_prefix, log_vmname ? log_vmname : "", log_vmname ? ": " : "");
15bc516e 137 fprintf(stderr, "%s: %s: %d ", event->locinfo->file, event->locinfo->func, event->locinfo->line);
d737c074
MN
138 vfprintf(stderr, event->fmt, *event->vap);
139 fprintf(stderr, "\n");
140 return 0;
141}
142
cb8c5720 143/*---------------------------------------------------------------------------*/
65a9df89
CB
144int lxc_unix_epoch_to_utc(char *buf, size_t bufsize, const struct timespec *time)
145{
d86c0d08
CB
146 int64_t epoch_to_days, z, era, doe, yoe, year, doy, mp, day, month,
147 d_in_s, hours, h_in_s, minutes, seconds;
eab15c1e 148 char nanosec[LXC_NUMSTRLEN64];
65a9df89
CB
149 int ret;
150
151 /* See https://howardhinnant.github.io/date_algorithms.html for an
152 * explanation of the algorithm used here.
153 */
d86c0d08
CB
154
155 /* Convert Epoch in seconds to number of days. */
156 epoch_to_days = time->tv_sec / 86400;
157
158 /* Shift the Epoch from 1970-01-01 to 0000-03-01. */
159 z = epoch_to_days + 719468;
160
161 /* compute the era from the serial date by simply dividing by the number
162 * of days in an era (146097).
163 */
65a9df89 164 era = (z >= 0 ? z : z - 146096) / 146097;
d86c0d08
CB
165
166 /* The day-of-era (doe) can then be found by subtracting the era number
167 * times the number of days per era, from the serial date.
168 */
65a9df89 169 doe = (z - era * 146097);
d86c0d08
CB
170
171 /* From the day-of-era (doe), the year-of-era (yoe, range [0, 399]) can
172 * be computed.
173 */
65a9df89 174 yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
d86c0d08
CB
175
176 /* Given year-of-era, and era, one can now compute the year. */
86698d38 177 year = yoe + era * 400;
d86c0d08
CB
178
179 /* Also the day-of-year, again with the year beginning on Mar. 1, can be
180 * computed from the day-of-era and year-of-era.
181 */
65a9df89 182 doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
d86c0d08
CB
183
184 /* Given day-of-year, find the month number. */
65a9df89 185 mp = (5 * doy + 2) / 153;
d86c0d08
CB
186
187 /* From day-of-year and month-of-year we can now easily compute
188 * day-of-month.
189 */
65a9df89 190 day = doy - (153 * mp + 2) / 5 + 1;
d86c0d08
CB
191
192 /* Transform the month number from the [0, 11] / [Mar, Feb] system to
193 * the civil system: [1, 12] to find the correct month.
194 */
65a9df89 195 month = mp + (mp < 10 ? 3 : -9);
d86c0d08 196
86698d38
CB
197 /* The algorithm assumes that a year begins on 1 March, so add 1 before
198 * that. */
199 if (month < 3)
200 year++;
201
d86c0d08
CB
202 /* Transform days in the epoch to seconds. */
203 d_in_s = epoch_to_days * 86400;
204
205 /* To find the current hour simply substract the Epoch_to_days from the
206 * total Epoch and divide by the number of seconds in an hour.
207 */
65a9df89 208 hours = (time->tv_sec - d_in_s) / 3600;
d86c0d08
CB
209
210 /* Transform hours to seconds. */
65a9df89 211 h_in_s = hours * 3600;
d86c0d08
CB
212
213 /* Calculate minutes by substracting the seconds for all days in the
214 * epoch and for all hours in the epoch and divide by the number of
215 * minutes in an hour.
216 */
65a9df89 217 minutes = (time->tv_sec - d_in_s - h_in_s) / 60;
d86c0d08
CB
218
219 /* Calculate the seconds by substracting the seconds for all days in the
220 * epoch, hours in the epoch and minutes in the epoch.
221 */
65a9df89
CB
222 seconds = (time->tv_sec - d_in_s - h_in_s - (minutes * 60));
223
d86c0d08 224 /* Make string from nanoseconds. */
eab15c1e
CB
225 ret = snprintf(nanosec, LXC_NUMSTRLEN64, "%ld", time->tv_nsec);
226 if (ret < 0 || ret >= LXC_NUMSTRLEN64)
65a9df89 227 return -1;
d86c0d08
CB
228
229 /* Create final timestamp for the log and shorten nanoseconds to 3
230 * digit precision.
231 */
9d7468fd
CB
232 ret = snprintf(buf, bufsize,
233 "%" PRId64 "%02" PRId64 "%02" PRId64 "%02" PRId64
234 "%02" PRId64 "%02" PRId64 ".%.3s",
65a9df89
CB
235 year, month, day, hours, minutes, seconds, nanosec);
236 if (ret < 0 || (size_t)ret >= bufsize)
237 return -1;
238
239 return 0;
240}
241
c57dbb96
CB
242/* This function needs to make extra sure that it is thread-safe. We had some
243 * problems with that before. This especially involves time-conversion
244 * functions. I don't want to find any localtime() or gmtime() functions or
245 * relatives in here. Not even localtime_r() or gmtime_r() or relatives. They
246 * all fiddle with global variables and locking in various libcs. They cause
247 * deadlocks when liblxc is used multi-threaded and no matter how smart you
248 * think you are, you __will__ cause trouble using them.
249 * (As a short example how this can cause trouble: LXD uses forkstart to fork
250 * off a new process that runs the container. At the same time the go runtime
251 * LXD relies on does its own multi-threading thing which we can't controll. The
252 * fork()ing + threading then seems to mess with the locking states in these
253 * time functions causing deadlocks.)
254 * The current solution is to be good old unix people and use the Epoch as our
255 * reference point and simply use the seconds and nanoseconds that have past
256 * since then. This relies on clock_gettime() which is explicitly marked MT-Safe
257 * with no restrictions! This way, anyone who is really strongly invested in
258 * getting the actual time the log entry was created, can just convert it for
259 * themselves. Our logging is mostly done for debugging purposes so don't try
260 * to make it pretty. Pretty might cost you thread-safety.
261 */
cb8c5720 262static int log_append_logfile(const struct lxc_log_appender *appender,
5fd8380b 263 struct lxc_log_event *event)
cb8c5720
CLG
264{
265 char buffer[LXC_LOG_BUFFER_SIZE];
e1378d35
CB
266 char date_time[LXC_LOG_TIME_SIZE];
267 int n;
858377e4 268 int fd_to_use = -1;
42e56013 269
858377e4
SH
270#ifndef NO_LXC_CONF
271 if (!lxc_log_use_global_fd && current_config)
272 fd_to_use = current_config->logfd;
273#endif
274
275 if (fd_to_use == -1)
276 fd_to_use = lxc_log_fd;
277
278 if (fd_to_use == -1)
cb8c5720
CLG
279 return 0;
280
e1378d35 281 if (lxc_unix_epoch_to_utc(date_time, LXC_LOG_TIME_SIZE, &event->timestamp) < 0)
c57dbb96
CB
282 return 0;
283
284 n = snprintf(buffer, sizeof(buffer),
e1378d35 285 "%15s%s%s %s %-8s %s - %s:%s:%d - ",
c57dbb96
CB
286 log_prefix,
287 log_vmname ? " " : "",
288 log_vmname ? log_vmname : "",
e1378d35 289 date_time,
c57dbb96
CB
290 lxc_log_priority_to_string(event->priority),
291 event->category,
292 event->locinfo->file, event->locinfo->func,
293 event->locinfo->line);
cb8c5720 294
f6c79610
LZ
295 if (n < 0)
296 return n;
cb8c5720 297
450b6d3d 298 if ((size_t)n < (sizeof(buffer) - 1))
0dcdbf8a
CB
299 n += vsnprintf(buffer + n, sizeof(buffer) - n, event->fmt, *event->vap);
300 else
cb8c5720 301 n = sizeof(buffer) - 1;
cb8c5720
CLG
302
303 buffer[n] = '\n';
304
858377e4 305 return write(fd_to_use, buffer, n + 1);
cb8c5720
CLG
306}
307
64c57ea1
BD
308static struct lxc_log_appender log_appender_syslog = {
309 .name = "syslog",
310 .append = log_append_syslog,
311 .next = NULL,
312};
313
d737c074
MN
314static struct lxc_log_appender log_appender_stderr = {
315 .name = "stderr",
316 .append = log_append_stderr,
317 .next = NULL,
318};
319
cb8c5720
CLG
320static struct lxc_log_appender log_appender_logfile = {
321 .name = "logfile",
322 .append = log_append_logfile,
441e4963 323 .next = NULL,
cb8c5720
CLG
324};
325
326static struct lxc_log_category log_root = {
327 .name = "root",
4b73005c 328 .priority = LXC_LOG_LEVEL_ERROR,
cb8c5720
CLG
329 .appender = NULL,
330 .parent = NULL,
331};
332
333struct lxc_log_category lxc_log_category_lxc = {
334 .name = "lxc",
4b73005c 335 .priority = LXC_LOG_LEVEL_ERROR,
858377e4 336 .appender = &log_appender_logfile,
cb8c5720
CLG
337 .parent = &log_root
338};
339
340/*---------------------------------------------------------------------------*/
5e1e7aaf
SH
341static int build_dir(const char *name)
342{
343 char *n = strdup(name); // because we'll be modifying it
344 char *p, *e;
345 int ret;
346
347 if (!n) {
348 ERROR("Out of memory while creating directory '%s'.", name);
349 return -1;
350 }
351
352 e = &n[strlen(n)];
353 for (p = n+1; p < e; p++) {
354 if (*p != '/')
355 continue;
356 *p = '\0';
357 if (access(n, F_OK)) {
358 ret = lxc_unpriv(mkdir(n, 0755));
8479c136 359 if (ret && errno != EEXIST) {
5e1e7aaf
SH
360 SYSERROR("failed to create directory '%s'.", n);
361 free(n);
362 return -1;
363 }
364 }
365 *p = '/';
366 }
367 free(n);
368 return 0;
369}
370
cb8c5720
CLG
371/*---------------------------------------------------------------------------*/
372static int log_open(const char *name)
373{
374 int fd;
375 int newfd;
376
28f602ff
DL
377 fd = lxc_unpriv(open(name, O_CREAT | O_WRONLY |
378 O_APPEND | O_CLOEXEC, 0666));
cb8c5720
CLG
379 if (fd == -1) {
380 ERROR("failed to open log file \"%s\" : %s", name,
381 strerror(errno));
382 return -1;
383 }
384
385 if (fd > 2)
386 return fd;
387
388 newfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
389 if (newfd == -1)
390 ERROR("failed to dup log fd %d : %s", fd, strerror(errno));
391
392 close(fd);
393 return newfd;
394}
395
ab1bf971
DE
396/*
397 * Build the path to the log file
398 * @name : the name of the container
399 * @lxcpath : the lxcpath to use as a basename or NULL to use LOGPATH
ec64264d 400 * Returns malloced path on success, or NULL on failure
ab1bf971
DE
401 */
402static char *build_log_path(const char *name, const char *lxcpath)
5e1e7aaf
SH
403{
404 char *p;
ee25a44f
DE
405 int len, ret, use_dir;
406
74f052dd
SG
407 if (!name)
408 return NULL;
409
ee25a44f
DE
410#if USE_CONFIGPATH_LOGS
411 use_dir = 1;
412#else
413 use_dir = 0;
414#endif
5e1e7aaf
SH
415
416 /*
ee25a44f
DE
417 * If USE_CONFIGPATH_LOGS is true or lxcpath is given, the resulting
418 * path will be:
5e1e7aaf 419 * '$logpath' + '/' + '$name' + '/' + '$name' + '.log' + '\0'
ab1bf971
DE
420 *
421 * If USE_CONFIGPATH_LOGS is false the resulting path will be:
422 * '$logpath' + '/' + '$name' + '.log' + '\0'
5e1e7aaf 423 */
ab1bf971 424 len = strlen(name) + 6; /* 6 == '/' + '.log' + '\0' */
ee25a44f
DE
425 if (lxcpath)
426 use_dir = 1;
427 else
ab1bf971 428 lxcpath = LOGPATH;
ee25a44f
DE
429
430 if (use_dir)
431 len += strlen(lxcpath) + 1 + strlen(name) + 1; /* add "/$container_name/" */
432 else
433 len += strlen(lxcpath) + 1;
5e1e7aaf
SH
434 p = malloc(len);
435 if (!p)
436 return p;
ee25a44f
DE
437
438 if (use_dir)
439 ret = snprintf(p, len, "%s/%s/%s.log", lxcpath, name, name);
440 else
441 ret = snprintf(p, len, "%s/%s.log", lxcpath, name);
442
5e1e7aaf
SH
443 if (ret < 0 || ret >= len) {
444 free(p);
445 return NULL;
446 }
447 return p;
448}
449
d9c9b180
SH
450extern void lxc_log_close(void)
451{
64c57ea1
BD
452 closelog();
453 free(log_vmname);
454 log_vmname = NULL;
d9c9b180
SH
455 if (lxc_log_fd == -1)
456 return;
457 close(lxc_log_fd);
458 lxc_log_fd = -1;
459 free(log_fname);
460 log_fname = NULL;
461}
462
ab1bf971
DE
463/*
464 * This can be called:
465 * 1. when a program calls lxc_log_init with no logfile parameter (in which
466 * case the default is used). In this case lxc.logfile can override this.
467 * 2. when a program calls lxc_log_init with a logfile parameter. In this
468 * case we don't want lxc.logfile to override this.
469 * 3. When a lxc.logfile entry is found in config file.
470 */
471static int __lxc_log_set_file(const char *fname, int create_dirs)
472{
473 if (lxc_log_fd != -1) {
474 // we are overriding the default.
d9c9b180 475 lxc_log_close();
ab1bf971
DE
476 }
477
97bc2422
CB
478 if (!fname)
479 return -1;
3f53c691
SH
480
481 if (strlen(fname) == 0) {
6edbfc86
SG
482 log_fname = NULL;
483 return 0;
484 }
485
ab1bf971
DE
486#if USE_CONFIGPATH_LOGS
487 // we don't build_dir for the default if the default is
488 // i.e. /var/lib/lxc/$container/$container.log
489 if (create_dirs)
490#endif
491 if (build_dir(fname)) {
492 ERROR("failed to create dir for log file \"%s\" : %s", fname,
493 strerror(errno));
494 return -1;
495 }
496
497 lxc_log_fd = log_open(fname);
498 if (lxc_log_fd == -1)
499 return -1;
500
501 log_fname = strdup(fname);
502 return 0;
503}
504
505static int _lxc_log_set_file(const char *name, const char *lxcpath, int create_dirs)
506{
507 char *logfile;
508 int ret;
509
510 logfile = build_log_path(name, lxcpath);
511 if (!logfile) {
512 ERROR("could not build log path");
513 return -1;
514 }
515 ret = __lxc_log_set_file(logfile, create_dirs);
516 free(logfile);
517 return ret;
518}
5e1e7aaf 519
64c57ea1
BD
520extern int lxc_log_syslog(int facility)
521{
522 struct lxc_log_appender *appender;
523
524 openlog(log_prefix, LOG_PID, facility);
525 if (!lxc_log_category_lxc.appender) {
526 lxc_log_category_lxc.appender = &log_appender_syslog;
527 return 0;
528 }
529 appender = lxc_log_category_lxc.appender;
530 while (appender->next != NULL)
531 appender = appender->next;
532 appender->next = &log_appender_syslog;
533
534 return 0;
535}
536
537extern void lxc_log_enable_syslog(void)
538{
539 syslog_enable = 1;
540}
541
858377e4
SH
542/*
543 * lxc_log_init:
544 * Called from lxc front-end programs (like lxc-create, lxc-start) to
545 * initalize the log defaults.
546 */
73b910a3 547extern int lxc_log_init(struct lxc_log *log)
cb8c5720 548{
4b73005c 549 int lxc_priority = LXC_LOG_LEVEL_ERROR;
5e1e7aaf 550 int ret;
51cab631 551
ab1bf971
DE
552 if (lxc_log_fd != -1) {
553 WARN("lxc_log_init called with log already initialized");
2312f31b 554 return 0;
ab1bf971 555 }
2312f31b 556
4b73005c
CB
557 if (log->level)
558 lxc_priority = lxc_log_priority_to_int(log->level);
51cab631 559
858377e4
SH
560 if (!lxc_loglevel_specified) {
561 lxc_log_category_lxc.priority = lxc_priority;
562 lxc_loglevel_specified = 1;
563 }
cb8c5720 564
01db0197 565 if (!lxc_quiet_specified) {
73b910a3 566 if (!log->quiet)
01db0197
WD
567 lxc_log_category_lxc.appender->next = &log_appender_stderr;
568 }
441e4963 569
73b910a3 570 if (log->prefix)
571 lxc_log_set_prefix(log->prefix);
74476cf1 572
73b910a3 573 if (log->name)
574 log_vmname = strdup(log->name);
64c57ea1 575
73b910a3 576 if (log->file) {
577 if (strcmp(log->file, "none") == 0)
ab1bf971 578 return 0;
73b910a3 579 ret = __lxc_log_set_file(log->file, 1);
858377e4 580 lxc_log_use_global_fd = 1;
5e1e7aaf 581 } else {
74f052dd 582 /* if no name was specified, there nothing to do */
73b910a3 583 if (!log->name)
74f052dd
SG
584 return 0;
585
ab1bf971
DE
586 ret = -1;
587
73b910a3 588 if (!log->lxcpath)
589 log->lxcpath = LOGPATH;
e0b0b533 590
361e0e3c 591 /* try LOGPATH if lxcpath is the default for the privileged containers */
73b910a3 592 if (!geteuid() && strcmp(LXCPATH, log->lxcpath) == 0)
593 ret = _lxc_log_set_file(log->name, NULL, 0);
5e1e7aaf 594
ab1bf971
DE
595 /* try in lxcpath */
596 if (ret < 0)
73b910a3 597 ret = _lxc_log_set_file(log->name, log->lxcpath, 1);
ab1bf971
DE
598
599 /* try LOGPATH in case its writable by the caller */
600 if (ret < 0)
73b910a3 601 ret = _lxc_log_set_file(log->name, NULL, 0);
ab1bf971 602 }
5e1e7aaf 603
5e1e7aaf 604 /*
ab1bf971
DE
605 * If !file, that is, if the user did not request this logpath, then
606 * ignore failures and continue logging to console
5e1e7aaf 607 */
73b910a3 608 if (!log->file && ret != 0) {
5e1e7aaf
SH
609 INFO("Ignoring failure to open default logfile.");
610 ret = 0;
611 }
612
5e1e7aaf 613 return ret;
cb8c5720 614}
4a85ce2a
SH
615
616/*
617 * This is called when we read a lxc.loglevel entry in a lxc.conf file. This
618 * happens after processing command line arguments, which override the .conf
619 * settings. So only set the level if previously unset.
620 */
858377e4 621extern int lxc_log_set_level(int *dest, int level)
4a85ce2a 622{
4b73005c 623 if (level < 0 || level >= LXC_LOG_LEVEL_NOTSET) {
4a85ce2a
SH
624 ERROR("invalid log priority %d", level);
625 return -1;
626 }
858377e4 627 *dest = level;
4a85ce2a
SH
628 return 0;
629}
630
ab1bf971
DE
631extern int lxc_log_get_level(void)
632{
ab1bf971
DE
633 return lxc_log_category_lxc.priority;
634}
635
fabf7361
QH
636extern bool lxc_log_has_valid_level(void)
637{
638 int log_level = lxc_log_get_level();
4b73005c 639 if (log_level < 0 || log_level >= LXC_LOG_LEVEL_NOTSET)
fabf7361
QH
640 return false;
641 return true;
642}
643
4a85ce2a 644/*
ab1bf971
DE
645 * This is called when we read a lxc.logfile entry in a lxc.conf file. This
646 * happens after processing command line arguments, which override the .conf
647 * settings. So only set the file if previously unset.
4a85ce2a 648 */
858377e4 649extern int lxc_log_set_file(int *fd, const char *fname)
4a85ce2a 650{
858377e4
SH
651 if (*fd != -1) {
652 close(*fd);
653 *fd = -1;
654 }
655
656 if (build_dir(fname)) {
657 ERROR("failed to create dir for log file \"%s\" : %s", fname,
658 strerror(errno));
659 return -1;
660 }
661
662 *fd = log_open(fname);
663 if (*fd == -1)
664 return -errno;
665 return 0;
4a85ce2a 666}
9ea87d5d 667
ab1bf971 668extern const char *lxc_log_get_file(void)
5e1e7aaf 669{
ab1bf971 670 return log_fname;
5e1e7aaf
SH
671}
672
ab1bf971 673extern void lxc_log_set_prefix(const char *prefix)
9ea87d5d 674{
ab1bf971
DE
675 strncpy(log_prefix, prefix, sizeof(log_prefix));
676 log_prefix[sizeof(log_prefix) - 1] = 0;
9ea87d5d
SH
677}
678
ab1bf971 679extern const char *lxc_log_get_prefix(void)
9ea87d5d 680{
ab1bf971 681 return log_prefix;
9ea87d5d 682}
6edbfc86
SG
683
684extern void lxc_log_options_no_override()
685{
01db0197 686 lxc_quiet_specified = 1;
858377e4 687 lxc_loglevel_specified = 1;
6edbfc86 688}