]>
Commit | Line | Data |
---|---|---|
7f3e6257 LP |
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 General Public License as published by | |
10 | the Free Software Foundation; either version 2 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 | General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU 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 | ||
27 | #include "sd-journal.h" | |
28 | #include "util.h" | |
fe652127 | 29 | #include "socket-util.h" |
7f3e6257 LP |
30 | |
31 | /* We open a single fd, and we'll share it with the current process, | |
32 | * all its threads, and all its subprocesses. This means we need to | |
33 | * initialize it atomically, and need to operate on it atomically | |
34 | * never assuming we are the only user */ | |
35 | ||
36 | static int journal_fd(void) { | |
37 | int fd; | |
38 | static int fd_plus_one = 0; | |
39 | ||
40 | retry: | |
41 | if (fd_plus_one > 0) | |
42 | return fd_plus_one - 1; | |
43 | ||
44 | fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); | |
45 | if (fd < 0) | |
46 | return -errno; | |
47 | ||
48 | if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) { | |
49 | close_nointr_nofail(fd); | |
50 | goto retry; | |
51 | } | |
52 | ||
53 | return fd; | |
54 | } | |
55 | ||
a5344d2c | 56 | _public_ int sd_journal_print(int priority, const char *format, ...) { |
7f3e6257 LP |
57 | int r; |
58 | va_list ap; | |
59 | ||
60 | va_start(ap, format); | |
d0bbc21c | 61 | r = sd_journal_printv(priority, format, ap); |
7f3e6257 LP |
62 | va_end(ap); |
63 | ||
64 | return r; | |
65 | } | |
66 | ||
a5344d2c | 67 | _public_ int sd_journal_printv(int priority, const char *format, va_list ap) { |
d0bbc21c LP |
68 | char buffer[8 + LINE_MAX], p[11]; |
69 | struct iovec iov[2]; | |
70 | ||
fe652127 LP |
71 | if (priority < 0 || priority > 7) |
72 | return -EINVAL; | |
73 | ||
74 | if (!format) | |
75 | return -EINVAL; | |
76 | ||
d0bbc21c LP |
77 | snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK); |
78 | char_array_0(p); | |
7f3e6257 LP |
79 | |
80 | memcpy(buffer, "MESSAGE=", 8); | |
81 | vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap); | |
7f3e6257 LP |
82 | char_array_0(buffer); |
83 | ||
84 | zero(iov); | |
d0bbc21c LP |
85 | IOVEC_SET_STRING(iov[0], buffer); |
86 | IOVEC_SET_STRING(iov[1], p); | |
7f3e6257 | 87 | |
d0bbc21c | 88 | return sd_journal_sendv(iov, 2); |
7f3e6257 LP |
89 | } |
90 | ||
a5344d2c | 91 | _public_ int sd_journal_send(const char *format, ...) { |
7f3e6257 LP |
92 | int r, n = 0, i = 0, j; |
93 | va_list ap; | |
94 | struct iovec *iov = NULL; | |
95 | ||
96 | va_start(ap, format); | |
97 | while (format) { | |
98 | struct iovec *c; | |
99 | char *buffer; | |
100 | ||
101 | if (i >= n) { | |
102 | n = MAX(i*2, 4); | |
103 | c = realloc(iov, n * sizeof(struct iovec)); | |
104 | if (!c) { | |
105 | r = -ENOMEM; | |
106 | goto fail; | |
107 | } | |
108 | ||
109 | iov = c; | |
110 | } | |
111 | ||
112 | if (vasprintf(&buffer, format, ap) < 0) { | |
113 | r = -ENOMEM; | |
114 | goto fail; | |
115 | } | |
116 | ||
117 | IOVEC_SET_STRING(iov[i++], buffer); | |
118 | ||
119 | format = va_arg(ap, char *); | |
120 | } | |
121 | va_end(ap); | |
122 | ||
123 | r = sd_journal_sendv(iov, i); | |
124 | ||
125 | fail: | |
126 | for (j = 0; j < i; j++) | |
127 | free(iov[j].iov_base); | |
128 | ||
129 | free(iov); | |
130 | ||
131 | return r; | |
132 | } | |
133 | ||
a5344d2c | 134 | _public_ int sd_journal_sendv(const struct iovec *iov, int n) { |
7f3e6257 LP |
135 | int fd; |
136 | struct iovec *w; | |
137 | uint64_t *l; | |
138 | int i, j = 0; | |
139 | struct msghdr mh; | |
140 | struct sockaddr_un sa; | |
141 | ||
142 | if (!iov || n <= 0) | |
143 | return -EINVAL; | |
144 | ||
145 | w = alloca(sizeof(struct iovec) * n * 5); | |
146 | l = alloca(sizeof(uint64_t) * n); | |
147 | ||
148 | for (i = 0; i < n; i++) { | |
149 | char *c, *nl; | |
150 | ||
a5344d2c LP |
151 | if (!iov[i].iov_base || |
152 | iov[i].iov_len <= 1) | |
153 | return -EINVAL; | |
154 | ||
7f3e6257 | 155 | c = memchr(iov[i].iov_base, '=', iov[i].iov_len); |
a5344d2c | 156 | if (!c || c == iov[i].iov_base) |
7f3e6257 LP |
157 | return -EINVAL; |
158 | ||
159 | nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len); | |
160 | if (nl) { | |
161 | if (nl < c) | |
162 | return -EINVAL; | |
163 | ||
164 | /* Already includes a newline? Bummer, then | |
165 | * let's write the variable name, then a | |
166 | * newline, then the size (64bit LE), followed | |
167 | * by the data and a final newline */ | |
168 | ||
169 | w[j].iov_base = iov[i].iov_base; | |
170 | w[j].iov_len = c - (char*) iov[i].iov_base; | |
171 | j++; | |
172 | ||
173 | IOVEC_SET_STRING(w[j++], "\n"); | |
174 | ||
175 | l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1); | |
176 | w[j].iov_base = &l[i]; | |
177 | w[j].iov_len = sizeof(uint64_t); | |
178 | j++; | |
179 | ||
180 | w[j].iov_base = c + 1; | |
181 | w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1; | |
182 | j++; | |
183 | ||
184 | } else | |
185 | /* Nothing special? Then just add the line and | |
186 | * append a newline */ | |
187 | w[j++] = iov[i]; | |
188 | ||
189 | IOVEC_SET_STRING(w[j++], "\n"); | |
190 | } | |
191 | ||
192 | fd = journal_fd(); | |
193 | if (fd < 0) | |
194 | return fd; | |
195 | ||
196 | zero(sa); | |
197 | sa.sun_family = AF_UNIX; | |
259d2e76 | 198 | strncpy(sa.sun_path,"/run/systemd/journal/socket", sizeof(sa.sun_path)); |
7f3e6257 LP |
199 | |
200 | zero(mh); | |
201 | mh.msg_name = &sa; | |
202 | mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path); | |
203 | mh.msg_iov = w; | |
204 | mh.msg_iovlen = j; | |
205 | ||
206 | if (sendmsg(fd, &mh, MSG_NOSIGNAL) < 0) | |
207 | return -errno; | |
208 | ||
209 | return 0; | |
210 | } | |
fe652127 | 211 | |
a5344d2c | 212 | _public_ int sd_journal_stream_fd(const char *tag, int priority, int priority_prefix) { |
fe652127 LP |
213 | union sockaddr_union sa; |
214 | int fd; | |
215 | char *header; | |
216 | size_t l; | |
217 | ssize_t r; | |
218 | ||
219 | if (priority < 0 || priority > 7) | |
220 | return -EINVAL; | |
221 | ||
222 | fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); | |
223 | if (fd < 0) | |
224 | return -errno; | |
225 | ||
226 | zero(sa); | |
227 | sa.un.sun_family = AF_UNIX; | |
259d2e76 | 228 | strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path)); |
fe652127 LP |
229 | |
230 | r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)); | |
231 | if (r < 0) { | |
232 | close_nointr_nofail(fd); | |
233 | return -errno; | |
234 | } | |
235 | ||
236 | if (!tag) | |
237 | tag = ""; | |
238 | ||
239 | l = strlen(tag); | |
224f2ee2 | 240 | header = alloca(l + 1 + 2 + 2 + 2 + 2 + 2); |
fe652127 LP |
241 | |
242 | memcpy(header, tag, l); | |
243 | header[l++] = '\n'; | |
244 | header[l++] = '0' + priority; | |
245 | header[l++] = '\n'; | |
246 | header[l++] = '0' + !!priority_prefix; | |
247 | header[l++] = '\n'; | |
248 | header[l++] = '0'; | |
249 | header[l++] = '\n'; | |
224f2ee2 LP |
250 | header[l++] = '0'; |
251 | header[l++] = '\n'; | |
252 | header[l++] = '0'; | |
253 | header[l++] = '\n'; | |
fe652127 LP |
254 | |
255 | r = loop_write(fd, header, l, false); | |
256 | if (r < 0) { | |
257 | close_nointr_nofail(fd); | |
258 | return (int) r; | |
259 | } | |
260 | ||
261 | if ((size_t) r != l) { | |
262 | close_nointr_nofail(fd); | |
263 | return -errno; | |
264 | } | |
265 | ||
266 | return fd; | |
267 | } |