]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/log.c
licensing: Add missing headers and FSF address
[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 */
0ad19a3f 23#include <stdio.h>
24#include <errno.h>
cb8c5720
CLG
25#include <limits.h>
26#include <unistd.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <string.h>
30
31#define __USE_GNU /* for *_CLOEXEC */
32
33#include <fcntl.h>
34#include <stdlib.h>
35
28f602ff
DL
36#include "log.h"
37#include "caps.h"
ab1bf971 38#include "utils.h"
cb8c5720 39
6b9f3917
DL
40#define LXC_LOG_PREFIX_SIZE 32
41#define LXC_LOG_BUFFER_SIZE 512
42
d737c074 43int lxc_log_fd = -1;
6b9f3917 44static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
ab1bf971
DE
45static char *log_fname = NULL;
46/* command line values for logfile or logpriority should always override
47 * values from the configuration file or defaults
48 */
49static int lxc_logfile_specified = 0;
9ea87d5d 50static int lxc_loglevel_specified = 0;
cb8c5720
CLG
51
52lxc_log_define(lxc_log, lxc);
53
d737c074
MN
54/*---------------------------------------------------------------------------*/
55static int log_append_stderr(const struct lxc_log_appender *appender,
56 struct lxc_log_event *event)
57{
58 if (event->priority < LXC_LOG_PRIORITY_ERROR)
59 return 0;
60
61 fprintf(stderr, "%s: ", log_prefix);
62 vfprintf(stderr, event->fmt, *event->vap);
63 fprintf(stderr, "\n");
64 return 0;
65}
66
cb8c5720
CLG
67/*---------------------------------------------------------------------------*/
68static int log_append_logfile(const struct lxc_log_appender *appender,
5fd8380b 69 struct lxc_log_event *event)
cb8c5720
CLG
70{
71 char buffer[LXC_LOG_BUFFER_SIZE];
72 int n;
73
74 if (lxc_log_fd == -1)
75 return 0;
76
77 n = snprintf(buffer, sizeof(buffer),
78 "%15s %10ld.%03ld %-8s %s - ",
79 log_prefix,
80 event->timestamp.tv_sec,
81 event->timestamp.tv_usec / 1000,
82 lxc_log_priority_to_string(event->priority),
83 event->category);
84
85 n += vsnprintf(buffer + n, sizeof(buffer) - n, event->fmt,
5fd8380b 86 *event->vap);
cb8c5720
CLG
87
88 if (n >= sizeof(buffer) - 1) {
5fd8380b 89 WARN("truncated next event from %d to %zd bytes", n,
cb8c5720
CLG
90 sizeof(buffer));
91 n = sizeof(buffer) - 1;
92 }
93
94 buffer[n] = '\n';
95
96 return write(lxc_log_fd, buffer, n + 1);
97}
98
d737c074
MN
99static struct lxc_log_appender log_appender_stderr = {
100 .name = "stderr",
101 .append = log_append_stderr,
102 .next = NULL,
103};
104
cb8c5720
CLG
105static struct lxc_log_appender log_appender_logfile = {
106 .name = "logfile",
107 .append = log_append_logfile,
441e4963 108 .next = NULL,
cb8c5720
CLG
109};
110
111static struct lxc_log_category log_root = {
112 .name = "root",
113 .priority = LXC_LOG_PRIORITY_ERROR,
114 .appender = NULL,
115 .parent = NULL,
116};
117
118struct lxc_log_category lxc_log_category_lxc = {
119 .name = "lxc",
120 .priority = LXC_LOG_PRIORITY_ERROR,
25df6b78 121 .appender = &log_appender_stderr,
cb8c5720
CLG
122 .parent = &log_root
123};
124
125/*---------------------------------------------------------------------------*/
5e1e7aaf
SH
126static int build_dir(const char *name)
127{
128 char *n = strdup(name); // because we'll be modifying it
129 char *p, *e;
130 int ret;
131
132 if (!n) {
133 ERROR("Out of memory while creating directory '%s'.", name);
134 return -1;
135 }
136
137 e = &n[strlen(n)];
138 for (p = n+1; p < e; p++) {
139 if (*p != '/')
140 continue;
141 *p = '\0';
142 if (access(n, F_OK)) {
143 ret = lxc_unpriv(mkdir(n, 0755));
144 if (ret && errno != -EEXIST) {
145 SYSERROR("failed to create directory '%s'.", n);
146 free(n);
147 return -1;
148 }
149 }
150 *p = '/';
151 }
152 free(n);
153 return 0;
154}
155
cb8c5720
CLG
156/*---------------------------------------------------------------------------*/
157static int log_open(const char *name)
158{
159 int fd;
160 int newfd;
161
28f602ff
DL
162 fd = lxc_unpriv(open(name, O_CREAT | O_WRONLY |
163 O_APPEND | O_CLOEXEC, 0666));
cb8c5720
CLG
164 if (fd == -1) {
165 ERROR("failed to open log file \"%s\" : %s", name,
166 strerror(errno));
167 return -1;
168 }
169
170 if (fd > 2)
171 return fd;
172
173 newfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
174 if (newfd == -1)
175 ERROR("failed to dup log fd %d : %s", fd, strerror(errno));
176
177 close(fd);
178 return newfd;
179}
180
ab1bf971
DE
181/*
182 * Build the path to the log file
183 * @name : the name of the container
184 * @lxcpath : the lxcpath to use as a basename or NULL to use LOGPATH
185 * Returns malloced path on sucess, or NULL on failure
186 */
187static char *build_log_path(const char *name, const char *lxcpath)
5e1e7aaf
SH
188{
189 char *p;
ee25a44f
DE
190 int len, ret, use_dir;
191
192#if USE_CONFIGPATH_LOGS
193 use_dir = 1;
194#else
195 use_dir = 0;
196#endif
5e1e7aaf
SH
197
198 /*
ee25a44f
DE
199 * If USE_CONFIGPATH_LOGS is true or lxcpath is given, the resulting
200 * path will be:
5e1e7aaf 201 * '$logpath' + '/' + '$name' + '/' + '$name' + '.log' + '\0'
ab1bf971
DE
202 *
203 * If USE_CONFIGPATH_LOGS is false the resulting path will be:
204 * '$logpath' + '/' + '$name' + '.log' + '\0'
5e1e7aaf 205 */
ab1bf971 206 len = strlen(name) + 6; /* 6 == '/' + '.log' + '\0' */
ee25a44f
DE
207 if (lxcpath)
208 use_dir = 1;
209 else
ab1bf971 210 lxcpath = LOGPATH;
ee25a44f
DE
211
212 if (use_dir)
213 len += strlen(lxcpath) + 1 + strlen(name) + 1; /* add "/$container_name/" */
214 else
215 len += strlen(lxcpath) + 1;
5e1e7aaf
SH
216 p = malloc(len);
217 if (!p)
218 return p;
ee25a44f
DE
219
220 if (use_dir)
221 ret = snprintf(p, len, "%s/%s/%s.log", lxcpath, name, name);
222 else
223 ret = snprintf(p, len, "%s/%s.log", lxcpath, name);
224
5e1e7aaf
SH
225 if (ret < 0 || ret >= len) {
226 free(p);
227 return NULL;
228 }
229 return p;
230}
231
ab1bf971
DE
232/*
233 * This can be called:
234 * 1. when a program calls lxc_log_init with no logfile parameter (in which
235 * case the default is used). In this case lxc.logfile can override this.
236 * 2. when a program calls lxc_log_init with a logfile parameter. In this
237 * case we don't want lxc.logfile to override this.
238 * 3. When a lxc.logfile entry is found in config file.
239 */
240static int __lxc_log_set_file(const char *fname, int create_dirs)
241{
242 if (lxc_log_fd != -1) {
243 // we are overriding the default.
244 close(lxc_log_fd);
245 free(log_fname);
246 }
247
248#if USE_CONFIGPATH_LOGS
249 // we don't build_dir for the default if the default is
250 // i.e. /var/lib/lxc/$container/$container.log
251 if (create_dirs)
252#endif
253 if (build_dir(fname)) {
254 ERROR("failed to create dir for log file \"%s\" : %s", fname,
255 strerror(errno));
256 return -1;
257 }
258
259 lxc_log_fd = log_open(fname);
260 if (lxc_log_fd == -1)
261 return -1;
262
263 log_fname = strdup(fname);
264 return 0;
265}
266
267static int _lxc_log_set_file(const char *name, const char *lxcpath, int create_dirs)
268{
269 char *logfile;
270 int ret;
271
272 logfile = build_log_path(name, lxcpath);
273 if (!logfile) {
274 ERROR("could not build log path");
275 return -1;
276 }
277 ret = __lxc_log_set_file(logfile, create_dirs);
278 free(logfile);
279 return ret;
280}
5e1e7aaf 281
5e1e7aaf 282extern int lxc_log_init(const char *name, const char *file,
ab1bf971
DE
283 const char *priority, const char *prefix, int quiet,
284 const char *lxcpath)
cb8c5720 285{
51cab631 286 int lxc_priority = LXC_LOG_PRIORITY_ERROR;
5e1e7aaf 287 int ret;
51cab631 288
ab1bf971
DE
289 if (lxc_log_fd != -1) {
290 WARN("lxc_log_init called with log already initialized");
2312f31b 291 return 0;
ab1bf971 292 }
2312f31b 293
51cab631 294 if (priority) {
4a85ce2a 295 lxc_loglevel_specified = 1;
51cab631
MN
296 lxc_priority = lxc_log_priority_to_int(priority);
297
298 if (lxc_priority == LXC_LOG_PRIORITY_NOTSET) {
299 ERROR("invalid log priority %s", priority);
300 return -1;
301 }
302 }
303
304 lxc_log_category_lxc.priority = lxc_priority;
25df6b78 305 lxc_log_category_lxc.appender = &log_appender_logfile;
cb8c5720 306
441e4963
MN
307 if (!quiet)
308 lxc_log_category_lxc.appender->next = &log_appender_stderr;
309
cb8c5720 310 if (prefix)
ab1bf971 311 lxc_log_set_prefix(prefix);
74476cf1 312
ab1bf971
DE
313 if (file) {
314 lxc_logfile_specified = 1;
315 if (strcmp(file, "none") == 0)
316 return 0;
317 ret = __lxc_log_set_file(file, 1);
5e1e7aaf 318 } else {
ab1bf971
DE
319 ret = -1;
320
e0b0b533
DE
321 if (!lxcpath)
322 lxcpath = LOGPATH;
323
ab1bf971
DE
324 /* try LOGPATH if lxcpath is the default */
325 if (strcmp(lxcpath, default_lxc_path()) == 0)
326 ret = _lxc_log_set_file(name, NULL, 0);
5e1e7aaf 327
ab1bf971
DE
328 /* try in lxcpath */
329 if (ret < 0)
330 ret = _lxc_log_set_file(name, lxcpath, 1);
331
332 /* try LOGPATH in case its writable by the caller */
333 if (ret < 0)
334 ret = _lxc_log_set_file(name, NULL, 0);
335 }
5e1e7aaf 336
5e1e7aaf 337 /*
ab1bf971
DE
338 * If !file, that is, if the user did not request this logpath, then
339 * ignore failures and continue logging to console
5e1e7aaf 340 */
ab1bf971 341 if (!file && ret != 0) {
5e1e7aaf
SH
342 INFO("Ignoring failure to open default logfile.");
343 ret = 0;
344 }
345
5e1e7aaf 346 return ret;
cb8c5720 347}
4a85ce2a
SH
348
349/*
350 * This is called when we read a lxc.loglevel entry in a lxc.conf file. This
351 * happens after processing command line arguments, which override the .conf
352 * settings. So only set the level if previously unset.
353 */
354extern int lxc_log_set_level(int level)
355{
356 if (lxc_loglevel_specified)
357 return 0;
358 if (level < 0 || level >= LXC_LOG_PRIORITY_NOTSET) {
359 ERROR("invalid log priority %d", level);
360 return -1;
361 }
362 lxc_log_category_lxc.priority = level;
363 return 0;
364}
365
ab1bf971
DE
366extern int lxc_log_get_level(void)
367{
368 if (!lxc_loglevel_specified)
369 return LXC_LOG_PRIORITY_NOTSET;
370 return lxc_log_category_lxc.priority;
371}
372
fabf7361
QH
373extern bool lxc_log_has_valid_level(void)
374{
375 int log_level = lxc_log_get_level();
376 if (log_level < 0 || log_level >= LXC_LOG_PRIORITY_NOTSET)
377 return false;
378 return true;
379}
380
4a85ce2a 381/*
ab1bf971
DE
382 * This is called when we read a lxc.logfile entry in a lxc.conf file. This
383 * happens after processing command line arguments, which override the .conf
384 * settings. So only set the file if previously unset.
4a85ce2a 385 */
ab1bf971 386extern int lxc_log_set_file(const char *fname)
4a85ce2a 387{
ab1bf971 388 if (lxc_logfile_specified)
5e1e7aaf 389 return 0;
ab1bf971 390 return __lxc_log_set_file(fname, 0);
4a85ce2a 391}
9ea87d5d 392
ab1bf971 393extern const char *lxc_log_get_file(void)
5e1e7aaf 394{
ab1bf971 395 return log_fname;
5e1e7aaf
SH
396}
397
ab1bf971 398extern void lxc_log_set_prefix(const char *prefix)
9ea87d5d 399{
ab1bf971
DE
400 strncpy(log_prefix, prefix, sizeof(log_prefix));
401 log_prefix[sizeof(log_prefix) - 1] = 0;
9ea87d5d
SH
402}
403
ab1bf971 404extern const char *lxc_log_get_prefix(void)
9ea87d5d 405{
ab1bf971 406 return log_prefix;
9ea87d5d 407}