]> git.saurik.com Git - apple/syslog.git/blob - syslogd.tproj/asl_in.c
syslog-13.1.tar.gz
[apple/syslog.git] / syslogd.tproj / asl_in.c
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/fcntl.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29 #include <sys/uio.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include "daemon.h"
36
37 #define forever for(;;)
38
39 #define MY_ID "asl"
40
41 static int sock = -1;
42 static FILE *aslfile = NULL;
43 static asl_msg_t *query = NULL;
44
45 extern int asl_log_filter;
46
47 #define MATCH_EOF -1
48 #define MATCH_NULL 0
49 #define MATCH_TRUE 1
50 #define MATCH_FALSE 2
51
52 extern int prune;
53
54 static int filter_token = -1;
55
56 struct prune_query_entry
57 {
58 asl_msg_t *query;
59 TAILQ_ENTRY(prune_query_entry) entries;
60 };
61
62 static TAILQ_HEAD(pql, prune_query_entry) pquery;
63
64 static int
65 _search_next(FILE *log, char **outstr)
66 {
67 char *str;
68 aslmsg m;
69 int match, i;
70 struct prune_query_entry *p;
71
72 *outstr = NULL;
73
74 if (log == NULL) return MATCH_EOF;
75
76 str = get_line_from_file(log);
77 if (str == NULL) return MATCH_EOF;
78
79 m = asl_msg_from_string(str);
80 if (m == NULL)
81 {
82 free(str);
83 return MATCH_NULL;
84 }
85
86 *outstr = str;
87
88 for (i = 0, p = pquery.tqh_first; p != NULL; p = p->entries.tqe_next, i++)
89 {
90 match = asl_msg_cmp(p->query, m);
91 if (match == 1)
92 {
93 asl_free(m);
94 return MATCH_TRUE;
95 }
96 }
97
98 asl_free(m);
99 return MATCH_FALSE;
100 }
101
102 /*
103 * Pruning the main output file (asl.log)
104 *
105 * The prune file (_PATH_ASL_PRUNE) is set up by the syslog command-line utiliy.
106 * It contains a set of queries. The main output file is read, and each
107 * message is matched against these queries. If any query matches, we save
108 * that message. Anything that doesn't match is discarded.
109 *
110 */
111 int
112 asl_prune(asl_msg_t *inq)
113 {
114 char *pname, *str;
115 FILE *pfile, *qfile;
116 struct prune_query_entry *p, *n;
117 asl_msg_t *q;
118 int status, incount, outcount;
119
120 asldebug("syslogd: pruning %s\n", _PATH_ASL_OUT);
121
122 if (inq != NULL)
123 {
124 TAILQ_INIT(&pquery);
125 p = (struct prune_query_entry *)calloc(1, sizeof(struct prune_query_entry));
126 if (p == NULL) return -1;
127
128 p->query = inq;
129 TAILQ_INSERT_TAIL(&pquery, p, entries);
130 }
131 else
132 {
133 qfile = fopen(_PATH_ASL_PRUNE, "r");
134 if (qfile == NULL)
135 {
136 asldebug("syslogd: can't read %s: %s\n", _PATH_ASL_PRUNE, strerror(errno));
137 return 0;
138 }
139
140 TAILQ_INIT(&pquery);
141
142 forever
143 {
144 str = get_line_from_file(qfile);
145 if (str == NULL) break;
146
147 q = asl_msg_from_string(str);
148 asldebug("syslogd: prune line %s\n", str);
149
150 free(str);
151 if (q == NULL) continue;
152
153 if (q->type != ASL_TYPE_QUERY)
154 {
155 asl_free(q);
156 continue;
157 }
158
159 p = (struct prune_query_entry *)calloc(1, sizeof(struct prune_query_entry));
160 if (p == NULL) return -1;
161
162 p->query = q;
163 TAILQ_INSERT_TAIL(&pquery, p, entries);
164 }
165 }
166
167 pname = NULL;
168 asprintf(&pname, "%s.%d", _PATH_ASL_OUT, getpid());
169 if (pname == NULL) return -1;
170
171 pfile = fopen(pname, "w");
172 if (pfile == NULL)
173 {
174 asldebug("syslogd: can't write %s: %s\n", pname, strerror(errno));
175 free(pname);
176 return -1;
177 }
178
179 fclose(aslfile);
180 aslfile = fopen(_PATH_ASL_OUT, "r");
181 if (aslfile == NULL)
182 {
183 asldebug("syslogd: can't read %s: %s\n", _PATH_ASL_OUT, strerror(errno));
184 free(pname);
185 aslfile = fopen(_PATH_ASL_OUT, "a");
186 return -1;
187 }
188
189 incount = 0;
190 outcount = 0;
191
192 do
193 {
194 str = NULL;
195 incount++;
196 status = _search_next(aslfile, &str);
197
198 /*
199 * Pruning deletes records that match the search.
200 * If the match fails, we keep the record.
201 */
202 if (status == MATCH_FALSE)
203 {
204 outcount++;
205 fprintf(pfile, "%s\n", str);
206 }
207
208 if (str != NULL) free(str);
209 }
210 while (status != MATCH_EOF);
211
212 fclose(pfile);
213 fclose(aslfile);
214
215 unlink(_PATH_ASL_OUT);
216 rename(pname, _PATH_ASL_OUT);
217 free(pname);
218 unlink(_PATH_ASL_PRUNE);
219 aslfile = fopen(_PATH_ASL_OUT, "a");
220
221 n = NULL;
222 for (p = pquery.tqh_first; p != NULL; p = n)
223 {
224 n = p->entries.tqe_next;
225
226 if (p->query != NULL) asl_free(p->query);
227
228 TAILQ_REMOVE(&pquery, p, entries);
229 free(p);
230 }
231
232 asldebug("syslogd: prune %d records in, %d records out\n", incount, outcount);
233
234 return 0;
235 }
236
237 asl_msg_t *
238 asl_in_getmsg(int fd)
239 {
240 char *out;
241 asl_msg_t *m;
242 uint32_t len, n;
243 char ls[16];
244
245 n = read(fd, ls, 11);
246 if (n < 11)
247 {
248 if (n <= 0)
249 {
250 asldebug("%s: read error (len): %s\n", MY_ID, strerror(errno));
251 if (errno != EINTR)
252 {
253 close(fd);
254 aslevent_removefd(fd);
255 return NULL;
256 }
257 }
258
259 return NULL;
260 }
261
262 len = atoi(ls);
263 asldebug("%s: expecting message length %d bytes\n", MY_ID, len);
264 out = malloc(len);
265 if (out == NULL) return NULL;
266
267 n = read(fd, out, len);
268 if (n < len)
269 {
270 if (n <= 0)
271 {
272 asldebug("%s: read error (body): %s\n", MY_ID, strerror(errno));
273 if (errno != EINTR)
274 {
275 close(fd);
276 aslevent_removefd(fd);
277 free(out);
278 return NULL;
279 }
280 }
281 }
282
283 m = asl_msg_from_string(out);
284 free(out);
285 return m;
286 }
287
288 asl_msg_t *
289 asl_in_acceptmsg(int fd)
290 {
291 int clientfd;
292
293 asldebug("%s: accepting message\n", MY_ID);
294 clientfd = accept(fd, NULL, 0);
295 if (clientfd < 0)
296 {
297 asldebug("%s: error accepting socket fd %d: %s\n", MY_ID, fd, strerror(errno));
298 return NULL;
299 }
300
301 if (fcntl(clientfd, F_SETFL, O_NONBLOCK) < 0)
302 {
303 close(clientfd);
304 clientfd = -1;
305 asldebug("%s: couldn't set O_NONBLOCK for fd %d: %s\n", MY_ID, clientfd, strerror(errno));
306 return NULL;
307 }
308
309 aslevent_addfd(clientfd, asl_in_getmsg, NULL, NULL);
310 return NULL;
311 }
312
313 int
314 aslmod_sendmsg(asl_msg_t *msg, const char *outid)
315 {
316 const char *vlevel;
317 char *mstr;
318 uint32_t n, lmask;
319 int status, x, level;
320
321 if (aslfile == NULL) return -1;
322
323 /* set up com.apple.syslog.asl_filter */
324 if (filter_token == -1)
325 {
326 status = notify_register_check(NOTIFY_SYSTEM_ASL_FILTER, &filter_token);
327 if (status != NOTIFY_STATUS_OK)
328 {
329 filter_token = -1;
330 }
331 else
332 {
333 status = notify_check(filter_token, &x);
334 if (status == NOTIFY_STATUS_OK) status = notify_set_state(filter_token, asl_log_filter);
335 if (status != NOTIFY_STATUS_OK)
336 {
337 notify_cancel(filter_token);
338 filter_token = -1;
339 }
340 }
341 }
342
343 if (filter_token >= 0)
344 {
345 x = 1;
346 status = notify_check(filter_token, &x);
347 if ((status == NOTIFY_STATUS_OK) && (x == 1))
348 {
349 x = asl_log_filter;
350 status = notify_get_state(filter_token, &x);
351 if ((status == NOTIFY_STATUS_OK) && (x != 0)) asl_log_filter = x;
352 }
353 }
354
355 vlevel = asl_get(msg, ASL_KEY_LEVEL);
356 level = 7;
357 if (vlevel != NULL) level = atoi(vlevel);
358 lmask = ASL_FILTER_MASK(level);
359 if ((lmask & asl_log_filter) == 0) return 0;
360
361 mstr = asl_msg_to_string(msg, &n);
362 if (mstr != NULL)
363 {
364 fprintf(aslfile, "%s\n", mstr);
365 fflush(aslfile);
366 free(mstr);
367 }
368
369 return 0;
370 }
371
372 int
373 asl_in_init(void)
374 {
375 struct sockaddr_un sun;
376 int rbufsize;
377 int len;
378
379 asldebug("%s: init\n", MY_ID);
380 if (sock >= 0) return sock;
381
382 unlink(_PATH_ASL_IN);
383 sock = socket(AF_UNIX, SOCK_STREAM, 0);
384 if (sock < 0)
385 {
386 asldebug("%s: couldn't create socket for %s: %s\n", MY_ID, _PATH_ASL_IN, strerror(errno));
387 return -1;
388 }
389
390 asldebug("%s: creating %s for fd %d\n", MY_ID, _PATH_ASL_IN, sock);
391
392 memset(&sun, 0, sizeof(sun));
393 sun.sun_family = AF_UNIX;
394 strcpy(sun.sun_path, _PATH_ASL_IN);
395
396 len = sizeof(struct sockaddr_un);
397 if (bind(sock, (struct sockaddr *)&sun, len) < 0)
398 {
399 asldebug("%s: couldn't bind socket %d for %s: %s\n", MY_ID, sock, _PATH_ASL_IN, strerror(errno));
400 close(sock);
401 sock = -1;
402 return -1;
403 }
404
405 rbufsize = 128 * 1024;
406 len = sizeof(rbufsize);
407
408 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rbufsize, len) < 0)
409 {
410 asldebug("%s: couldn't set receive buffer size for %s: %s\n", MY_ID, sock, _PATH_ASL_IN, strerror(errno));
411 close(sock);
412 sock = -1;
413 return -1;
414 }
415
416 if (listen(sock, SOMAXCONN) < 0)
417 {
418 asldebug("%s: couldn't listen on socket %d for %s: %s\n", MY_ID, sock, _PATH_ASL_IN, strerror(errno));
419 close(sock);
420 sock = -1;
421 unlink(_PATH_ASL_IN);
422 return -1;
423 }
424
425 if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0)
426 {
427 asldebug("%s: couldn't set O_NONBLOCK for socket %d (%s): %s\n", MY_ID, sock, _PATH_ASL_IN, strerror(errno));
428 close(sock);
429 sock = -1;
430 return -1;
431 }
432
433 chmod(_PATH_ASL_IN, 0666);
434
435 /* Add logger routine for main output file */
436 aslfile = fopen(_PATH_ASL_OUT, "a");
437 if (aslfile != NULL)
438 {
439 query = asl_new(ASL_TYPE_QUERY);
440 aslevent_addmatch(query, MY_ID);
441 aslevent_addoutput(aslmod_sendmsg, MY_ID);
442 }
443
444 return aslevent_addfd(sock, asl_in_acceptmsg, NULL, NULL);
445 }
446
447 int
448 asl_in_reset(void)
449 {
450 return 0;
451 }
452
453 int
454 asl_in_close(void)
455 {
456 if (sock < 0) return 1;
457
458 if (filter_token >= 0) notify_cancel(filter_token);
459 filter_token = -1;
460 asl_log_filter = 0;
461
462 asl_free(query);
463 close(sock);
464 if (aslfile != NULL) fclose(aslfile);
465 unlink(_PATH_ASL_IN);
466
467 return 0;
468 }