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