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