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