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