]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journal-send.c
Add hasprefix macro to check prefixes of fixed length
[thirdparty/systemd.git] / src / journal / journal-send.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <errno.h>
25 #include <stddef.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <printf.h>
29
30 #define SD_JOURNAL_SUPPRESS_LOCATION
31
32 #include "sd-journal.h"
33 #include "util.h"
34 #include "socket-util.h"
35
36 #define SNDBUF_SIZE (8*1024*1024)
37
38 #define ALLOCA_CODE_FUNC(f, func) \
39 do { \
40 size_t _fl; \
41 const char *_func = (func); \
42 char **_f = &(f); \
43 _fl = strlen(_func) + 1; \
44 *_f = alloca(_fl + 10); \
45 memcpy(*_f, "CODE_FUNC=", 10); \
46 memcpy(*_f + 10, _func, _fl); \
47 } while(false)
48
49 /* We open a single fd, and we'll share it with the current process,
50 * all its threads, and all its subprocesses. This means we need to
51 * initialize it atomically, and need to operate on it atomically
52 * never assuming we are the only user */
53
54 static int journal_fd(void) {
55 int fd;
56 static int fd_plus_one = 0;
57
58 retry:
59 if (fd_plus_one > 0)
60 return fd_plus_one - 1;
61
62 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
63 if (fd < 0)
64 return -errno;
65
66 fd_inc_sndbuf(fd, SNDBUF_SIZE);
67
68 if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) {
69 close_nointr_nofail(fd);
70 goto retry;
71 }
72
73 return fd;
74 }
75
76 _public_ int sd_journal_print(int priority, const char *format, ...) {
77 int r;
78 va_list ap;
79
80 va_start(ap, format);
81 r = sd_journal_printv(priority, format, ap);
82 va_end(ap);
83
84 return r;
85 }
86
87 _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
88
89 /* FIXME: Instead of limiting things to LINE_MAX we could do a
90 C99 variable-length array on the stack here in a loop. */
91
92 char buffer[8 + LINE_MAX], p[11]; struct iovec iov[2];
93
94 if (priority < 0 || priority > 7)
95 return -EINVAL;
96
97 if (!format)
98 return -EINVAL;
99
100 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
101 char_array_0(p);
102
103 memcpy(buffer, "MESSAGE=", 8);
104 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
105 char_array_0(buffer);
106
107 zero(iov);
108 IOVEC_SET_STRING(iov[0], buffer);
109 IOVEC_SET_STRING(iov[1], p);
110
111 return sd_journal_sendv(iov, 2);
112 }
113
114 _printf_attr_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
115 PROTECT_ERRNO;
116 int r, n = 0, i = 0, j;
117 struct iovec *iov = NULL;
118
119 assert(_iov);
120
121 if (extra > 0) {
122 n = MAX(extra * 2, extra + 4);
123 iov = malloc0(n * sizeof(struct iovec));
124 if (!iov) {
125 r = -ENOMEM;
126 goto fail;
127 }
128
129 i = extra;
130 }
131
132 while (format) {
133 struct iovec *c;
134 char *buffer;
135 va_list aq;
136
137 if (i >= n) {
138 n = MAX(i*2, 4);
139 c = realloc(iov, n * sizeof(struct iovec));
140 if (!c) {
141 r = -ENOMEM;
142 goto fail;
143 }
144
145 iov = c;
146 }
147
148 va_copy(aq, ap);
149 if (vasprintf(&buffer, format, aq) < 0) {
150 va_end(aq);
151 r = -ENOMEM;
152 goto fail;
153 }
154 va_end(aq);
155
156 VA_FORMAT_ADVANCE(format, ap);
157
158 IOVEC_SET_STRING(iov[i++], buffer);
159
160 format = va_arg(ap, char *);
161 }
162
163 *_iov = iov;
164
165 return i;
166
167 fail:
168 for (j = 0; j < i; j++)
169 free(iov[j].iov_base);
170
171 free(iov);
172
173 return r;
174 }
175
176 _public_ int sd_journal_send(const char *format, ...) {
177 int r, i, j;
178 va_list ap;
179 struct iovec *iov = NULL;
180
181 va_start(ap, format);
182 i = fill_iovec_sprintf(format, ap, 0, &iov);
183 va_end(ap);
184
185 if (_unlikely_(i < 0)) {
186 r = i;
187 goto finish;
188 }
189
190 r = sd_journal_sendv(iov, i);
191
192 finish:
193 for (j = 0; j < i; j++)
194 free(iov[j].iov_base);
195
196 free(iov);
197
198 return r;
199 }
200
201 _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
202 PROTECT_ERRNO;
203 int fd, buffer_fd;
204 struct iovec *w;
205 uint64_t *l;
206 int i, j = 0;
207 struct sockaddr_un sa = {
208 .sun_family = AF_UNIX,
209 .sun_path = "/run/systemd/journal/socket",
210 };
211 struct msghdr mh = {
212 .msg_name = &sa,
213 .msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path),
214 };
215 ssize_t k;
216 union {
217 struct cmsghdr cmsghdr;
218 uint8_t buf[CMSG_SPACE(sizeof(int))];
219 } control;
220 struct cmsghdr *cmsg;
221 /* We use /dev/shm instead of /tmp here, since we want this to
222 * be a tmpfs, and one that is available from early boot on
223 * and where unprivileged users can create files. */
224 char path[] = "/dev/shm/journal.XXXXXX";
225 bool have_syslog_identifier = false;
226
227 if (_unlikely_(!iov))
228 return -EINVAL;
229
230 if (_unlikely_(n <= 0))
231 return -EINVAL;
232
233 w = alloca(sizeof(struct iovec) * n * 5 + 3);
234 l = alloca(sizeof(uint64_t) * n);
235
236 for (i = 0; i < n; i++) {
237 char *c, *nl;
238
239 if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1))
240 return -EINVAL;
241
242 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
243 if (_unlikely_(!c || c == iov[i].iov_base))
244 return -EINVAL;
245
246 have_syslog_identifier = have_syslog_identifier ||
247 (c == (char *) iov[i].iov_base + 17 &&
248 hasprefix(iov[i].iov_base, "SYSLOG_IDENTIFIER"));
249
250 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
251 if (nl) {
252 if (_unlikely_(nl < c))
253 return -EINVAL;
254
255 /* Already includes a newline? Bummer, then
256 * let's write the variable name, then a
257 * newline, then the size (64bit LE), followed
258 * by the data and a final newline */
259
260 w[j].iov_base = iov[i].iov_base;
261 w[j].iov_len = c - (char*) iov[i].iov_base;
262 j++;
263
264 IOVEC_SET_STRING(w[j++], "\n");
265
266 l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
267 w[j].iov_base = &l[i];
268 w[j].iov_len = sizeof(uint64_t);
269 j++;
270
271 w[j].iov_base = c + 1;
272 w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
273 j++;
274
275 } else
276 /* Nothing special? Then just add the line and
277 * append a newline */
278 w[j++] = iov[i];
279
280 IOVEC_SET_STRING(w[j++], "\n");
281 }
282
283 if (!have_syslog_identifier &&
284 string_is_safe(program_invocation_short_name)) {
285
286 /* Implicitly add program_invocation_short_name, if it
287 * is not set explicitly. We only do this for
288 * program_invocation_short_name, and nothing else
289 * since everything else is much nicer to retrieve
290 * from the outside. */
291
292 IOVEC_SET_STRING(w[j++], "SYSLOG_IDENTIFIER=");
293 IOVEC_SET_STRING(w[j++], program_invocation_short_name);
294 IOVEC_SET_STRING(w[j++], "\n");
295 }
296
297 fd = journal_fd();
298 if (_unlikely_(fd < 0))
299 return fd;
300
301 mh.msg_iov = w;
302 mh.msg_iovlen = j;
303
304 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
305 if (k >= 0)
306 return 0;
307
308 if (errno != EMSGSIZE && errno != ENOBUFS)
309 return -errno;
310
311 /* Message doesn't fit... Let's dump the data in a temporary
312 * file and just pass a file descriptor of it to the other
313 * side */
314
315 buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR);
316 if (buffer_fd < 0)
317 return -errno;
318
319 if (unlink(path) < 0) {
320 close_nointr_nofail(buffer_fd);
321 return -errno;
322 }
323
324 n = writev(buffer_fd, w, j);
325 if (n < 0) {
326 close_nointr_nofail(buffer_fd);
327 return -errno;
328 }
329
330 mh.msg_iov = NULL;
331 mh.msg_iovlen = 0;
332
333 zero(control);
334 mh.msg_control = &control;
335 mh.msg_controllen = sizeof(control);
336
337 cmsg = CMSG_FIRSTHDR(&mh);
338 cmsg->cmsg_level = SOL_SOCKET;
339 cmsg->cmsg_type = SCM_RIGHTS;
340 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
341 memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
342
343 mh.msg_controllen = cmsg->cmsg_len;
344
345 k = sendmsg(fd, &mh, MSG_NOSIGNAL);
346 close_nointr_nofail(buffer_fd);
347
348 if (k < 0)
349 return -errno;
350
351 return 0;
352 }
353
354 static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
355 PROTECT_ERRNO;
356 size_t n, k;
357
358 k = isempty(message) ? 0 : strlen(message) + 2;
359 n = 8 + k + 256 + 1;
360
361 for (;;) {
362 char buffer[n];
363 char* j;
364
365 errno = 0;
366 j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k);
367 if (errno == 0) {
368 char error[6 + 10 + 1]; /* for a 32bit value */
369
370 if (j != buffer + 8 + k)
371 memmove(buffer + 8 + k, j, strlen(j)+1);
372
373 memcpy(buffer, "MESSAGE=", 8);
374
375 if (k > 0) {
376 memcpy(buffer + 8, message, k - 2);
377 memcpy(buffer + 8 + k - 2, ": ", 2);
378 }
379
380 snprintf(error, sizeof(error), "ERRNO=%u", _saved_errno_);
381 char_array_0(error);
382
383 IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
384 IOVEC_SET_STRING(iov[skip+1], buffer);
385 IOVEC_SET_STRING(iov[skip+2], error);
386
387 return sd_journal_sendv(iov, skip + 3);
388 }
389
390 if (errno != ERANGE)
391 return -errno;
392
393 n *= 2;
394 }
395 }
396
397 _public_ int sd_journal_perror(const char *message) {
398 struct iovec iovec[3];
399
400 return fill_iovec_perror_and_send(message, 0, iovec);
401 }
402
403 _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
404 union sockaddr_union sa = {
405 .un.sun_family = AF_UNIX,
406 .un.sun_path = "/run/systemd/journal/stdout",
407 };
408 int fd;
409 char *header;
410 size_t l;
411 ssize_t r;
412
413 if (priority < 0 || priority > 7)
414 return -EINVAL;
415
416 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
417 if (fd < 0)
418 return -errno;
419
420 r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
421 if (r < 0) {
422 close_nointr_nofail(fd);
423 return -errno;
424 }
425
426 if (shutdown(fd, SHUT_RD) < 0) {
427 close_nointr_nofail(fd);
428 return -errno;
429 }
430
431 fd_inc_sndbuf(fd, SNDBUF_SIZE);
432
433 if (!identifier)
434 identifier = "";
435
436 l = strlen(identifier);
437 header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
438
439 memcpy(header, identifier, l);
440 header[l++] = '\n';
441 header[l++] = '\n'; /* unit id */
442 header[l++] = '0' + priority;
443 header[l++] = '\n';
444 header[l++] = '0' + !!level_prefix;
445 header[l++] = '\n';
446 header[l++] = '0';
447 header[l++] = '\n';
448 header[l++] = '0';
449 header[l++] = '\n';
450 header[l++] = '0';
451 header[l++] = '\n';
452
453 r = loop_write(fd, header, l, false);
454 if (r < 0) {
455 close_nointr_nofail(fd);
456 return (int) r;
457 }
458
459 if ((size_t) r != l) {
460 close_nointr_nofail(fd);
461 return -errno;
462 }
463
464 return fd;
465 }
466
467 _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
468 int r;
469 va_list ap;
470
471 va_start(ap, format);
472 r = sd_journal_printv_with_location(priority, file, line, func, format, ap);
473 va_end(ap);
474
475 return r;
476 }
477
478 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
479 char buffer[8 + LINE_MAX], p[11];
480 struct iovec iov[5];
481 char *f;
482
483 if (priority < 0 || priority > 7)
484 return -EINVAL;
485
486 if (_unlikely_(!format))
487 return -EINVAL;
488
489 snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK);
490 char_array_0(p);
491
492 memcpy(buffer, "MESSAGE=", 8);
493 vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
494 char_array_0(buffer);
495
496 /* func is initialized from __func__ which is not a macro, but
497 * a static const char[], hence cannot easily be prefixed with
498 * CODE_FUNC=, hence let's do it manually here. */
499 ALLOCA_CODE_FUNC(f, func);
500
501 zero(iov);
502 IOVEC_SET_STRING(iov[0], buffer);
503 IOVEC_SET_STRING(iov[1], p);
504 IOVEC_SET_STRING(iov[2], file);
505 IOVEC_SET_STRING(iov[3], line);
506 IOVEC_SET_STRING(iov[4], f);
507
508 return sd_journal_sendv(iov, ELEMENTSOF(iov));
509 }
510
511 _public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
512 int r, i, j;
513 va_list ap;
514 struct iovec *iov = NULL;
515 char *f;
516
517 va_start(ap, format);
518 i = fill_iovec_sprintf(format, ap, 3, &iov);
519 va_end(ap);
520
521 if (_unlikely_(i < 0)) {
522 r = i;
523 goto finish;
524 }
525
526 ALLOCA_CODE_FUNC(f, func);
527
528 IOVEC_SET_STRING(iov[0], file);
529 IOVEC_SET_STRING(iov[1], line);
530 IOVEC_SET_STRING(iov[2], f);
531
532 r = sd_journal_sendv(iov, i);
533
534 finish:
535 for (j = 3; j < i; j++)
536 free(iov[j].iov_base);
537
538 free(iov);
539
540 return r;
541 }
542
543 _public_ int sd_journal_sendv_with_location(
544 const char *file, const char *line,
545 const char *func,
546 const struct iovec *iov, int n) {
547
548 struct iovec *niov;
549 char *f;
550
551 if (_unlikely_(!iov))
552 return -EINVAL;
553
554 if (_unlikely_(n <= 0))
555 return -EINVAL;
556
557 niov = alloca(sizeof(struct iovec) * (n + 3));
558 memcpy(niov, iov, sizeof(struct iovec) * n);
559
560 ALLOCA_CODE_FUNC(f, func);
561
562 IOVEC_SET_STRING(niov[n++], file);
563 IOVEC_SET_STRING(niov[n++], line);
564 IOVEC_SET_STRING(niov[n++], f);
565
566 return sd_journal_sendv(niov, n);
567 }
568
569 _public_ int sd_journal_perror_with_location(
570 const char *file, const char *line,
571 const char *func,
572 const char *message) {
573
574 struct iovec iov[6];
575 char *f;
576
577 ALLOCA_CODE_FUNC(f, func);
578
579 IOVEC_SET_STRING(iov[0], file);
580 IOVEC_SET_STRING(iov[1], line);
581 IOVEC_SET_STRING(iov[2], f);
582
583 return fill_iovec_perror_and_send(message, 3, iov);
584 }