1 /*
2 * Copyright (C) 2018-2022 Intel Corporation.
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <pthread.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <malloc.h>
13 #include <errno.h>
14 #include <sys/inotify.h>
15 #include <sys/epoll.h>
16 #include <time.h>
17 #include <signal.h>
18 #include "load_conf.h"
19 #include "event_queue.h"
20 #include "fsutils.h"
21 #include "strutils.h"
22 #include "channels.h"
23 #include "startupreason.h"
24 #include "probeutils.h"
25 #include "log_sys.h"
26 #include "android_events.h"
27 #include "crash_reclassify.h"
28
29 #define POLLING_TIMER_SIG 0xCEAC
30
31 static void channel_oneshot(struct channel_t *cnl);
32 static void channel_polling(struct channel_t *cnl);
33 static void channel_inotify(struct channel_t *cnl);
34
35 /**
36 * @brief structure containing implementation of each channel.
37 *
38 * This structure describes all channels, all channel_* functions would
39 * called by main thread in order.
40 */
41 static struct channel_t channels[] = {
42 {"oneshot", -1, channel_oneshot},
43 {"polling", -1, channel_polling},
44 {"inotify", -1, channel_inotify},
45 };
46
47 #define for_each_channel(i, channel) \
48 for (i = 0; \
49 (i < (int)ARRAY_SIZE(channels)) && (channel = &channels[i]); \
50 i++)
51
52 /**
53 * Helper function to create a event and fill event_t structure.
54 *
55 * @param event_type Type of this event.
56 * @param channel Channel where the event comes from.
57 * @param private The corresponding configuration info to the event.
58 * @param watchfd For watch channel, so far, only used by inotify.
59 * @param path File which trigger this event.
60 * @param plen The length of path.
61 *
62 * @return a pointer to the filled event if successful,
63 * or NULL on error.
64 */
create_event(enum event_type_t event_type,const char * channel,void * private,int watchfd,const char * path,size_t plen)65 static struct event_t *create_event(enum event_type_t event_type,
66 const char *channel, void *private,
67 int watchfd, const char *path, size_t plen)
68 {
69 struct event_t *e;
70 size_t path_len = 0;
71
72 if (path) {
73 path_len = plen;
74 if (path_len > PATH_MAX) {
75 LOGE("invalid path, drop event.\n");
76 return NULL;
77 }
78 }
79
80 e = malloc(sizeof(*e) + path_len + 1);
81 if (e) {
82 memset(e, 0, sizeof(*e) + path_len + 1);
83 e->watchfd = watchfd;
84 e->channel = channel;
85 e->private = private;
86 e->event_type = event_type;
87 if (path_len > 0) {
88 e->len = path_len;
89 *(char *)(mempcpy(e->path, path, path_len)) = '\0';
90 }
91 } else {
92 LOGE("malloc failed, error (%s)\n", strerror(errno));
93 }
94
95 return e;
96 }
97
98 /**
99 * Only check once when process startup
100 *
101 * @param cnl Structure of channel.
102 */
channel_oneshot(struct channel_t * cnl)103 static void channel_oneshot(struct channel_t *cnl)
104 {
105 int id;
106 struct crash_t *crash;
107 struct info_t *info;
108 struct event_t *e;
109 char *cname = cnl->name;
110
111 LOGD("initializing channel %s ...\n", cname);
112
113 if (!is_boot_id_changed())
114 return;
115
116 for_each_crash(id, crash, conf) {
117 if (!crash || !is_root_crash(crash))
118 continue;
119
120 if (strcmp(crash->channel, cname))
121 continue;
122
123 if (!crash->trigger)
124 continue;
125
126 if (!strcmp("file", crash->trigger->type) ||
127 !strcmp("node", crash->trigger->type)) {
128 if (!crash_match_filefmt(crash, crash->trigger->path))
129 continue;
130
131 e = create_event(CRASH, cname, (void *)crash,
132 0, crash->trigger->path,
133 crash->trigger->path_len);
134 if (e)
135 event_enqueue(e);
136 } else if (!strcmp("rebootreason", crash->trigger->type)) {
137 char rreason[REBOOT_REASON_SIZE];
138
139 read_startupreason(rreason, sizeof(rreason));
140 if (!strcmp(rreason, crash->content[0])) {
141 e = create_event(CRASH, cname, (void *)crash,
142 0, crash->trigger->path,
143 crash->trigger->path_len);
144 if (e)
145 event_enqueue(e);
146 }
147 }
148 }
149
150 e = create_event(REBOOT, cname, NULL, 0, NULL, 0);
151 if (e)
152 event_enqueue(e);
153
154 for_each_info(id, info, conf) {
155 if (!info)
156 continue;
157
158 if (strcmp(info->channel, cname))
159 continue;
160
161 if (info->trigger &&
162 !strcmp("file", info->trigger->type) &&
163 file_exists(info->trigger->path)) {
164 e = create_event(INFO, cname, (void *)info,
165 0, NULL, 0);
166 if (e)
167 event_enqueue(e);
168 }
169 }
170 }
171
172 /* TODO: implement multiple polling jobs */
173 static struct polling_job_t {
174 timer_t timerid;
175 uint32_t timer_val;
176
177 enum event_type_t type;
178 void (*fn)(union sigval v);
179 } vm_job;
180
create_vm_event(const char * msg,size_t len,const struct vm_t * vm)181 static int create_vm_event(const char *msg, size_t len, const struct vm_t *vm)
182 {
183 struct vm_event_t *vme = malloc(sizeof(*vme));
184 struct event_t *e;
185
186 if (!vme)
187 return VMEVT_DEFER;
188
189 vme->vm_msg = strndup(msg, len);
190 if (!vme->vm_msg) {
191 free(vme);
192 return VMEVT_DEFER;
193 }
194
195 vme->vm_msg_len = len;
196 vme->vm = vm;
197
198 e = create_event(VM, "polling", (void *)vme, 0, NULL, 0);
199 if (e) {
200 event_enqueue(e);
201 return VMEVT_HANDLED;
202 }
203
204 free(vme->vm_msg);
205 free(vme);
206 return VMEVT_DEFER;
207 }
208
209 /**
210 * Callback thread of a polling job.
211 */
polling_vm(union sigval v)212 static void polling_vm(union sigval v __attribute__((unused)))
213 {
214 refresh_vm_history(get_sender_by_name("crashlog"), create_vm_event);
215 }
216
217 /**
218 * Setup a timer with specific loop time. The callback fn will be performed
219 * after timer expire.
220 *
221 * @param pjob Polling_job filled by caller.
222 *
223 * @return 0 if successful, or -1 if not.
224 */
create_polling_job(struct polling_job_t * pjob)225 static int create_polling_job(struct polling_job_t *pjob)
226 {
227 struct sigevent sig_evt;
228 struct itimerspec timer_val;
229
230 memset(&sig_evt, 0, sizeof(struct sigevent));
231 sig_evt.sigev_value.sival_int = POLLING_TIMER_SIG;
232 sig_evt.sigev_notify = SIGEV_THREAD;
233 sig_evt.sigev_notify_function = pjob->fn;
234
235 if (timer_create(CLOCK_REALTIME, &sig_evt, &pjob->timerid) == -1) {
236 LOGE("timer_create failed.\n");
237 return -1;
238 }
239
240 memset(&timer_val, 0, sizeof(struct itimerspec));
241 timer_val.it_value.tv_sec = pjob->timer_val;
242 timer_val.it_interval.tv_sec = pjob->timer_val;
243
244 if (timer_settime(pjob->timerid, 0, &timer_val, NULL) == -1) {
245 LOGE("timer_settime failed.\n");
246 timer_delete(pjob->timerid);
247 return -1;
248 }
249
250 return 0;
251 }
252
253 /**
254 * Setup polling jobs. These jobs running with fixed time interval.
255 *
256 * @param cnl Structure of channel.
257 */
channel_polling(struct channel_t * cnl)258 static void channel_polling(struct channel_t *cnl)
259 {
260 int id;
261 int jt;
262 struct vm_t *vm;
263 char *cname = cnl->name;
264
265 LOGD("initializing channel %s ...\n", cname);
266
267 /* one job for all vm polling*/
268 for_each_vm(id, vm, conf) {
269 if (!vm)
270 continue;
271
272 if (strcmp(vm->channel, "polling"))
273 continue;
274
275 if (cfg_atoi(vm->interval, vm->interval_len,
276 &jt) == -1) {
277 LOGE("invalid interval (%s) in config file, exiting\n",
278 vm->interval);
279 exit(EXIT_FAILURE);
280 }
281
282 if (jt <= 0) {
283 LOGE("interval (%s) must be greater than 0, exiting\n",
284 vm->interval);
285 exit(EXIT_FAILURE);
286 } else
287 vm_job.timer_val = (uint32_t)jt;
288
289 }
290
291 LOGD("start polling job with %ds\n", vm_job.timer_val);
292 vm_job.fn = polling_vm;
293 vm_job.type = VM;
294 if (create_polling_job(&vm_job) == -1) {
295 LOGE("failed to create polling job\n, error (%s)\n",
296 strerror(errno));
297 exit(EXIT_FAILURE);
298 }
299 }
300
301 /**
302 * Setup inotify, watch the changes of dir/file.
303 *
304 * @param cnl Structure of channel.
305 */
channel_inotify(struct channel_t * cnl)306 static void channel_inotify(struct channel_t *cnl)
307 {
308 int inotify_fd;
309 int id;
310 struct crash_t *crash;
311 struct sender_t *sender;
312 struct uptime_t *uptime;
313 struct trigger_t *trigger;
314 char *cname = cnl->name;
315
316 LOGD("initializing channel %s ...\n", cname);
317
318 /* use this func to get "return 0" from read */
319 inotify_fd = inotify_init1(IN_NONBLOCK);
320 if (inotify_fd < 0) {
321 LOGE("inotify init fail, %s\n", strerror(errno));
322 return;
323 }
324
325 for_each_crash(id, crash, conf) {
326 if (!crash || !is_root_crash(crash))
327 continue;
328
329 if (strcmp(crash->channel, cname))
330 continue;
331
332 if (!crash->trigger)
333 continue;
334
335 trigger = crash->trigger;
336 if (!strcmp("dir", trigger->type)) {
337 if (directory_exists(trigger->path)) {
338 crash->wd = inotify_add_watch(inotify_fd,
339 trigger->path,
340 BASE_DIR_MASK);
341 if (crash->wd < 0) {
342 LOGE("add %s failed, error (%s)\n",
343 trigger->path, strerror(errno));
344 exit(EXIT_FAILURE);
345 }
346 LOGI("add %s succuessed\n", trigger->path);
347 } else {
348 LOGW("path to watch (%s) isn't exsits\n",
349 trigger->path);
350 }
351 }
352 /* TODO: else for other types to use channel inotify */
353 }
354 /* add uptime path for each sender */
355 for_each_sender(id, sender, conf) {
356 if (!sender)
357 continue;
358
359 uptime = sender->uptime;
360 uptime->wd = inotify_add_watch(inotify_fd, uptime->path,
361 UPTIME_MASK);
362 if (uptime->wd < 0) {
363 LOGE("add %s failed, error (%s)\n",
364 uptime->path, strerror(errno));
365 exit(EXIT_FAILURE);
366 }
367 LOGI("add %s succuessed\n", uptime->path);
368 }
369
370 cnl->fd = inotify_fd;
371 }
372
373 /**
374 * Handle inotify events, read out all events and enqueue.
375 *
376 * @param channel Channel structure of inotify.
377 *
378 * @return 0 if successful, or -1 if not.
379 */
receive_inotify_events(struct channel_t * channel)380 static int receive_inotify_events(struct channel_t *channel)
381 {
382 int len;
383 int read_left;
384 char buf[256];
385 char *p;
386 struct event_t *e;
387 struct inotify_event *ievent;
388 enum event_type_t event_type;
389 void *private;
390
391 read_left = 0;
392 while (1) {
393 len = read(channel->fd, (char *)&buf[read_left],
394 (int)sizeof(buf) - read_left);
395 if (len < 0) {
396 if (errno == EAGAIN)
397 break;
398 LOGE("read fail with (%d, %p, %d), error: %s\n",
399 channel->fd, (char *)&buf[read_left],
400 (int)sizeof(buf) - read_left, strerror(errno));
401 return -1;
402 }
403 if (len == 0)
404 break;
405
406 for (p = buf; p < buf + read_left + len;) {
407 if (p + sizeof(struct inotify_event) >
408 &buf[0] + len + read_left) {
409 /* we dont recv the entire inotify_event yet */
410 break;
411 }
412
413 /* then we can get len */
414 ievent = (struct inotify_event *)p;
415 if (p + sizeof(struct inotify_event) + ievent->len >
416 &buf[0] + len + read_left) {
417 /* we dont recv the entire
418 * inotify_event + name
419 */
420 break;
421 }
422 /* we have a entire event, send it... */
423 event_type = get_conf_by_wd(ievent->wd, &private);
424 if (event_type == UNKNOWN) {
425 LOGE("get a unknown event\n");
426 } else {
427 e = create_event(event_type, channel->name,
428 private, channel->fd,
429 ievent->name, ievent->len);
430 if (e)
431 event_enqueue(e);
432 }
433 /* next event start */
434 p += sizeof(struct inotify_event) + ievent->len;
435 }
436 /* move the bytes that have been read out to the head of buf,
437 * and let the rest of the buf do recv continually
438 */
439 read_left = &buf[0] + len + read_left - p;
440 memmove(buf, p, read_left);
441 }
442
443 return 0;
444 }
445
446 /**
447 * Enqueue a HEART_BEAT event to event_queue.
448 */
heart_beat(void)449 static void heart_beat(void)
450 {
451 struct event_t *e = create_event(HEART_BEAT, NULL, NULL, 0, NULL, 0);
452
453 if (e)
454 event_enqueue(e);
455 }
456
457 /**
458 * Wait events asynchronously for all watch needed channels.
459 */
wait_events(void * unused)460 static void *wait_events(void *unused __attribute__((unused)))
461 {
462 int epfd;
463 int id;
464 int ret;
465 struct channel_t *channel;
466 struct epoll_event ev, *events;
467
468 epfd = epoll_create(MAXEVENTS + 1);
469 if (epfd < 0) {
470 LOGE("epoll_create failed, exiting\n");
471 exit(EXIT_FAILURE);
472 }
473
474 ev.events = EPOLLIN | EPOLLET;
475 for_each_channel(id, channel) {
476 if (channel->fd <= 0)
477 continue;
478
479 ev.data.fd = channel->fd;
480 ret = epoll_ctl(epfd, EPOLL_CTL_ADD, channel->fd, &ev);
481 if (ret < 0) {
482 LOGE("epoll_ctl failed, exiting\n");
483 exit(EXIT_FAILURE);
484 } else
485 LOGD("add (%d) to epoll for (%s)\n", channel->fd,
486 channel->name);
487 }
488
489 events = calloc(MAXEVENTS, sizeof(ev));
490 if (events == NULL) {
491 LOGE("calloc failed, error (%s)\n", strerror(errno));
492 exit(EXIT_FAILURE);
493 }
494
495 while (1) {
496 int i;
497 int n;
498
499 n = epoll_wait(epfd, events, MAXEVENTS, HEART_RATE);
500 heart_beat();
501 for (i = 0; i < n; i++) {
502 for_each_channel(id, channel)
503 if (channel->fd == events[i].data.fd) {
504 if (events[i].events & EPOLLERR ||
505 !(events[i].events & EPOLLIN)) {
506 LOGE("error ev, channel:%s\n",
507 channel->name);
508 continue;
509 }
510 /* Until now, we only have
511 * inotify channel to wait
512 */
513 receive_inotify_events(channel);
514 }
515 }
516 }
517 }
518
519 /**
520 * Create a detached thread.
521 * Once these thread exit, their resources would be released immediately.
522 *
523 * @param[out] pid Pid of new thread.
524 * @param fn The entry of new thread.
525 * @param arg The arg of fn.
526 *
527 * @return 0 if successful, or errno if not.
528 */
create_detached_thread(pthread_t * pid,void * (* fn)(void *),void * arg)529 int create_detached_thread(pthread_t *pid, void *(*fn)(void *), void *arg)
530 {
531 int ret;
532 pthread_attr_t attr;
533
534 ret = pthread_attr_init(&attr);
535 if (ret) {
536 LOGE("pthread attr init failed\n, error (%s)\n",
537 strerror(ret));
538 return ret;
539 }
540
541 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
542 if (ret) {
543 LOGE("pthread attr setdetachstate failed\n, error (%s)\n",
544 strerror(ret));
545 goto fail;
546 }
547
548 ret = pthread_create(pid, &attr, fn, arg);
549 if (ret) {
550 LOGE("pthread create failed\n, error (%s)\n",
551 strerror(ret));
552 }
553 fail:
554 pthread_attr_destroy(&attr);
555
556 return ret;
557 }
558
559 /**
560 * Initailize all channels, performing channel_* in channels one by one.
561 *
562 * @return 0 if successful, or errno if not.
563 */
init_channels(void)564 int init_channels(void)
565 {
566 pthread_t pid;
567 int id;
568 int ret;
569 struct channel_t *channel;
570
571 for_each_channel(id, channel) {
572 channel->channel_fn(channel);
573 }
574
575 ret = create_detached_thread(&pid, &wait_events, NULL);
576 if (ret) {
577 LOGE("create wait_events fail, ret (%s)\n", strerror(ret));
578 return ret;
579 }
580
581 return 0;
582 }
583