d3d5fc638e6183cc02d09ce3a0d5d53a02142eff
[framework/system/dlog.git] / src / logger / logger.c
1 /*
2  * Copyright (c) 2005-2008, The Android Open Source Project
3  * Copyright (c) 2009-2013, Samsung Electronics Co., Ltd. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #define _GNU_SOURCE
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdbool.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <limits.h>
26 #include <signal.h>
27 #include <fcntl.h>
28 #include <time.h>
29 #include <sys/time.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <assert.h>
33 #include <sys/stat.h>
34 #include <arpa/inet.h>
35
36 #include <logger.h>
37 #include <logprint.h>
38
39 #ifdef DEBUG_ON
40 #define _D(...) printf(__VA_ARGS__)
41 #else
42 #define _D(...) do { } while (0)
43 #endif
44 #define _E(...) fprintf(stderr, __VA_ARGS__)
45
46 #define COMMAND_MAX 5
47 #define DELIMITER " "
48 #define FILE_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
49 #define MAX_ARGS 16
50 #define MAX_ROTATED 4
51
52 #define CONFIG_FILE "/opt/etc/dlog_logger.conf"
53
54 #define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0]))
55
56 struct queued_entry {
57         union {
58                 unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
59                 struct logger_entry entry __attribute__((aligned(4)));
60         };
61         struct queued_entry *next;
62 };
63
64 struct log_command {
65         char *filename;
66         int option_file;
67         int option_buffer;
68         int rotate_size;
69         int max_rotated;
70         int devices[LOG_ID_MAX];
71         log_format *format;
72 };
73
74 struct log_work {
75         char *filename;
76         bool printed;
77         int fd;
78         int size;
79         int rotate_size;
80         int max_rotated;
81         log_format *format;
82         struct log_work *next;
83 };
84
85 struct log_task_link {
86         struct log_work *work;
87         struct log_task_link *next;
88 };
89
90 struct log_device {
91         int id;
92         int fd;
93         struct queued_entry *queue;
94         struct log_task_link *task;
95         struct log_device *next;
96 };
97
98 static const char *device_path_table[] = {
99         [LOG_ID_MAIN] = "/dev/log_main",
100         [LOG_ID_RADIO] = "/dev/log_radio",
101         [LOG_ID_SYSTEM] = "/dev/log_system",
102         [LOG_ID_APPS] = "/dev/log_apps",
103         [LOG_ID_MAX] = NULL
104 };
105
106 static struct log_work *works;
107 static struct log_device *devices;
108 static int device_list[] = {
109         [LOG_ID_MAIN] = false,
110         [LOG_ID_RADIO] = false,
111         [LOG_ID_SYSTEM] = false,
112         [LOG_ID_APPS] = false,
113         [LOG_ID_MAX] = false,
114 };
115
116 /*
117  * get log device id from device path table by device name
118  */
119 static int get_device_id_by_name(const char *name)
120 {
121         int i;
122
123         if (name == NULL)
124                 return -1;
125         for (i = 0; i < ARRAY_SIZE(device_path_table); i++) {
126                 if (strstr(device_path_table[i], name) != NULL)
127                         return i;
128         }
129
130         return -1;
131 }
132
133 /*
134  * check device registration on watch device list
135  */
136 static int check_device(int id)
137 {
138         if (id < 0 || LOG_ID_MAX < id)
139                 return 0;
140
141         return (device_list[id] == true) ? 0 : -1;
142 }
143
144 /*
145  * register device to watch device list
146  */
147 static int register_device(int id)
148 {
149         if (id < 0 || LOG_ID_MAX < id)
150                 return -1;
151         device_list[id] = true;
152
153         return 0;
154 }
155
156 /*
157  * comparison function to distinct entries by time
158  */
159 static int cmp(struct queued_entry *a, struct queued_entry *b)
160 {
161         int n = a->entry.sec - b->entry.sec;
162         if (n != 0)
163                 return n;
164
165         return a->entry.nsec - b->entry.nsec;
166 }
167
168 /*
169  * enqueueing the log_entry into the log_device
170  */
171 static void enqueue(struct log_device *device, struct queued_entry *entry)
172 {
173         if (device->queue == NULL) {
174                 device->queue = entry;
175         } else {
176                 struct queued_entry **e = &device->queue;
177                 while (*e && cmp(entry, *e) >= 0)
178                         e = &((*e)->next);
179                 entry->next = *e;
180                 *e = entry;
181         }
182 }
183
184 /*
185  * open file
186  */
187 static int open_work(const char *path)
188 {
189         return open(path, O_WRONLY | O_APPEND | O_CREAT, FILE_PERMS);
190 }
191
192 /*
193  * rotate log files
194  */
195 static void rotate_logs(struct log_work *logwork)
196 {
197         int i, ret;
198         char *filename;
199         char file0[NAME_MAX];
200         char file1[NAME_MAX];
201
202         close(logwork->fd);
203         filename = logwork->filename;
204         for (i = logwork->max_rotated ; i > 0 ; i--) {
205                 snprintf(file1, NAME_MAX, "%s.%d", filename, i);
206                 if (i - 1 == 0)
207                         snprintf(file0, NAME_MAX, "%s",  filename);
208                 else
209                         snprintf(file0, NAME_MAX, "%s.%d", filename, i - 1);
210                 ret = rename(file0, file1);
211                 if (ret < 0 && errno != ENOENT)
212                         _E("while rotating log works");
213         }
214         /* open log file again */
215         logwork->fd = open_work(filename);
216         if (logwork->fd < 0) {
217                 _E("couldn't open log file");
218                 exit(EXIT_FAILURE);
219         }
220         logwork->size = 0;
221
222         return;
223 }
224
225 /*
226  * process to print log
227  * and check the log file size to rotate
228  */
229 static void process_buffer(struct log_device *dev, struct logger_entry *buf)
230 {
231         int bytes_written, err;
232         log_entry entry;
233         struct log_work *logwork;
234         struct log_task_link *task;
235
236         err = log_process_log_buffer(buf, &entry);
237
238         if (err < 0)
239                 goto exit;
240
241         for (task = dev->task; task; task = task->next) {
242                 logwork = task->work;
243                 if (log_should_print_line(logwork->format,
244                                         entry.tag, entry.priority)) {
245                         bytes_written =
246                                 log_print_log_line(logwork->format,
247                                                 logwork->fd, &entry);
248                         if (bytes_written < 0) {
249                                 _E("work error");
250                                 exit(EXIT_FAILURE);
251                         }
252                         logwork->size += bytes_written;
253                 }
254                 if (logwork->rotate_size > 0 &&
255                                 (logwork->size / 1024) >= logwork->rotate_size) {
256                         rotate_logs(logwork);
257                 }
258         }
259 exit:
260         return;
261 }
262
263 /*
264  * choose first device by log_entry
265  */
266 static void choose_first(struct log_device *dev, struct log_device **firstdev)
267 {
268         for (*firstdev = NULL; dev != NULL; dev = dev->next) {
269                 if (dev->queue != NULL &&
270                                 (*firstdev == NULL ||
271                                  cmp(dev->queue,
272                                          (*firstdev)->queue) < 0)) {
273                         *firstdev = dev;
274                 }
275         }
276 }
277
278 /*
279  * print beginnig string into the log files
280  */
281 static void maybe_print_start(struct log_device *dev)
282 {
283         struct log_work *logwork;
284         struct log_task_link *task;
285         char buf[1024];
286
287         for (task = dev->task; task; task = task->next) {
288                 logwork = task->work;
289                 if (!logwork->printed) {
290                         logwork->printed = true;
291                         snprintf(buf, sizeof(buf),
292                                         "--------- beginning of %s\n",
293                                         device_path_table[dev->id]);
294                         if (write(logwork->fd, buf, strlen(buf)) < 0) {
295                                 _E("maybe work error");
296                                 exit(EXIT_FAILURE);
297                         }
298                 }
299         }
300 }
301
302 /*
303  * skip log_entry
304  */
305 static void skip_next_entry(struct log_device *dev)
306 {
307         maybe_print_start(dev);
308         struct queued_entry *entry = dev->queue;
309         dev->queue = entry->next;
310         free(entry);
311 }
312
313 /*
314  * print log_entry
315  */
316 static void print_next_entry(struct log_device *dev)
317 {
318         maybe_print_start(dev);
319         process_buffer(dev, &dev->queue->entry);
320         skip_next_entry(dev);
321 }
322
323 /*
324  * do logging
325  */
326 static void do_logger(struct log_device *dev)
327 {
328         struct log_device *pdev;
329         int ret, result;
330         fd_set readset;
331         bool sleep = false;
332         int queued_lines = 0;
333         int max = 0;
334
335         for (pdev = dev; pdev; pdev = pdev->next) {
336                 if (pdev->fd > max)
337                         max = pdev->fd;
338         }
339
340         while (1) {
341                 do {
342                         struct timeval timeout = { 0, 5000 /* 5ms */ };
343                         FD_ZERO(&readset);
344                         for (pdev = dev; pdev; pdev = pdev->next)
345                                 FD_SET(pdev->fd, &readset);
346                         result = select(max + 1, &readset, NULL, NULL,
347                                         sleep ? NULL : &timeout);
348                 } while (result == -1 && errno == EINTR);
349
350                 if (result < 0)
351                         continue;
352
353                 for (pdev = dev; pdev; pdev = pdev->next) {
354                         if (FD_ISSET(pdev->fd, &readset)) {
355                                 struct queued_entry *entry =
356                                         (struct queued_entry *)
357                                         malloc(sizeof(struct queued_entry));
358                                 if (entry == NULL) {
359                                         _E("failed to malloc queued_entry\n");
360                                         goto exit;//exit(EXIT_FAILURE);
361                                 }
362                                 entry->next = NULL;
363                                 ret = read(pdev->fd, entry->buf,
364                                                 LOGGER_ENTRY_MAX_LEN);
365                                 if (ret < 0) {
366                                         if (errno == EINTR) {
367                                                 free(entry);
368                                                 goto next;
369                                         }
370                                         if (errno == EAGAIN) {
371                                                 free(entry);
372                                                 break;
373                                         }
374                                         _E("dlogutil read");
375                                         goto exit;//exit(EXIT_FAILURE);
376                                 } else if (!ret) {
377                                         free(entry);
378                                         _E("read: Unexpected EOF!\n");
379                                         exit(EXIT_FAILURE);
380                                 } else if (entry->entry.len !=
381                                                 ret - sizeof(struct logger_entry)) {
382                                         free(entry);
383                                         _E("unexpected length. Expected %d, got %d\n",
384                                                         entry->entry.len,
385                                                         ret - sizeof(struct logger_entry));
386                                         goto exit;//exit(EXIT_FAILURE);
387                                 }
388
389                                 entry->entry.msg[entry->entry.len] = '\0';
390
391                                 enqueue(pdev, entry);
392                                 ++queued_lines;
393                         }
394                 }
395
396                 if (result == 0) {
397                         sleep = true;
398                         while (true) {
399                                 choose_first(dev, &pdev);
400                                 if (pdev == NULL)
401                                         break;
402                                 print_next_entry(pdev);
403                                 --queued_lines;
404                         }
405                 } else {
406                         /* print all that aren't the last in their list */
407                         sleep = false;
408                         while (true) {
409                                 choose_first(dev, &pdev);
410                                 if (pdev == NULL || pdev->queue->next == NULL)
411                                         break;
412                                 print_next_entry(pdev);
413                                 --queued_lines;
414                         }
415                 }
416 next:
417                 ;
418         }
419 exit:
420         exit(EXIT_FAILURE);
421 }
422
423
424 /*
425  * create a work
426  */
427 static struct log_work *work_new(void)
428 {
429         struct log_work *work;
430
431         work = malloc(sizeof(*work));
432         if (work == NULL) {
433                 _E("failed to malloc log_work\n");
434                 return NULL;
435         }
436         work->filename = NULL;
437         work->fd = -1;
438         work->printed = false;
439         work->size = 0;
440         work->next = NULL;
441         _D("work alloc %p\n", work);
442
443         return work;
444 }
445
446 /*
447  * add a new log_work to the tail of chain
448  */
449 static int work_add_to_tail(struct log_work *work, struct log_work *nwork)
450 {
451         struct log_work *tail = work;
452
453         if (!nwork)
454                 return -1;
455
456         if (work == NULL) {
457                 work = nwork;
458                 return 0;
459         }
460
461         while (tail->next)
462                 tail = tail->next;
463         tail->next = nwork;
464
465         return 0;
466 }
467
468 /*
469  * add a new work task to the tail of chain
470  */
471 static void work_add_to_device(struct log_device *dev, struct log_work *work)
472 {
473         struct log_task_link *tail;
474
475         if (!dev || !work)
476                 return;
477         _D("dev %p work %p\n", dev, work);
478         if (dev->task == NULL) {
479                 dev->task =
480                         (struct log_task_link *)
481                         malloc(sizeof(struct log_task_link));
482                 if (dev->task == NULL) {
483                         _E("failed to malloc log_task_link\n");
484                         return;
485                 }
486                 tail = dev->task;
487         } else {
488                 tail = dev->task;
489                 while (tail->next)
490                         tail = tail->next;
491                 tail->next =
492                         (struct log_task_link *)
493                         malloc(sizeof(struct log_task_link));
494                 if (tail->next == NULL) {
495                         _E("failed to malloc log_task_link\n");
496                         return;
497                 }
498                 tail = tail->next;
499         }
500         tail->work = work;
501         tail->next = NULL;
502 }
503
504 /*
505  * free work file descriptor
506  */
507 static void work_free(struct log_work *work)
508 {
509         if (!work)
510                 return;
511         if (work->filename) {
512                 free(work->filename);
513                 work->filename = NULL;
514                 if (work->fd != -1) {
515                         close(work->fd);
516                         work->fd = -1;
517                 }
518         }
519         log_format_free(work->format);
520         work->format = NULL;
521         free(work);
522         work = NULL;
523 }
524
525 /*
526  * free all the nodes after the "work" and includes itself
527  */
528 static void work_chain_free(struct log_work *work)
529 {
530         if (!work)
531                 return;
532         while (work->next) {
533                 struct log_work *tmp = work->next;
534                 work->next = tmp->next;
535                 work_free(tmp);
536         }
537         work_free(work);
538         work = NULL;
539 }
540
541 /*
542  * create a new log_device instance
543  * and open device
544  */
545 static struct log_device *device_new(int id)
546 {
547         struct log_device *dev;
548
549         if (LOG_ID_MAX < id)
550                 return NULL;
551         dev = malloc(sizeof(*dev));
552         if (dev == NULL) {
553                 _E("failed to malloc log_device\n");
554                 return NULL;
555         }
556         dev->id = id;
557         dev->fd = open(device_path_table[id], O_RDONLY);
558         if (dev->fd < 0) {
559                 _E("Unable to open log device '%s': %s\n",
560                                 device_path_table[id],
561                                 strerror(errno));
562                 return NULL;
563         }
564         _D("device new id %d fd %d\n", dev->id, dev->fd);
565         dev->task = NULL;
566         dev->queue = NULL;
567         dev->next = NULL;
568
569         return dev;
570 }
571
572 /*
573  * add a new log_device to the tail of chain
574  */
575 static int device_add_to_tail(struct log_device *dev, struct log_device *ndev)
576 {
577         struct log_device *tail = dev;
578
579         if (!dev || !ndev)
580                 return -1;
581
582         while (tail->next)
583                 tail = tail->next;
584         tail->next = ndev;
585
586         return 0;
587 }
588
589 /*
590  * add a new log_device or add to the tail of chain
591  */
592 static void device_add(int id)
593 {
594         if (check_device(id) < 0)
595                 return;
596
597         if (!devices) {
598                         devices = device_new(id);
599                         if (devices == NULL) {
600                                 _E("failed to device_new: %s\n",
601                                                 device_path_table[id]);
602                                 exit(EXIT_FAILURE);
603                         }
604         } else {
605                 if (device_add_to_tail(devices, device_new(id)) < 0) {
606                         _E("failed to device_add_to_tail: %s\n",
607                                         device_path_table[id]);
608                         exit(EXIT_FAILURE);
609                 }
610         }
611         return;
612 }
613
614 /*
615  * free one log_device  and it doesn't take care of chain so it
616  * may break the chain list
617  */
618 static void device_free(struct log_device *dev)
619 {
620         if (!dev)
621                 return;
622         if (dev->queue) {
623                 while (dev->queue->next) {
624                         struct queued_entry *tmp =
625                                 dev->queue->next;
626                         dev->queue->next = tmp->next;
627                         free(tmp);
628                 }
629                 free(dev->queue);
630                 dev->queue = NULL;
631         }
632         if (dev->task) {
633                 while (dev->task->next) {
634                         struct log_task_link *tmp =
635                                 dev->task->next;
636                         dev->task->next = tmp->next;
637                         free(tmp);
638                 }
639                 free(dev->task);
640                 dev->task = NULL;
641         }
642         free(dev);
643         dev = NULL;
644 }
645
646 /*
647  * free all the nodes after the "dev" and includes itself
648  */
649 static void device_chain_free(struct log_device *dev)
650 {
651         if (!dev)
652                 return;
653         while (dev->next) {
654                 struct log_device *tmp = dev->next;
655                 dev->next = tmp->next;
656                 device_free(tmp);
657         }
658         device_free(dev);
659         dev = NULL;
660 }
661
662 /*
663  * parse command line
664  * using getopt function
665  */
666 static int parse_command_line(char *linebuffer, struct log_command *cmd)
667 {
668         int i, ret, id, argc;
669         char *argv[MAX_ARGS];
670         char *tok, *cmdline;
671
672         if (linebuffer == NULL || cmd == NULL)
673                 return -1;
674         /* copy command line */
675         cmdline = strdup(linebuffer);
676         tok = strtok(cmdline, DELIMITER);
677         /* check the availability of command line
678            by comparing first word with dlogutil*/
679         if (!tok || strcmp(tok, "dlogutil")) {
680                 _D("Ignore this line (%s)\n", linebuffer);
681                 free(cmdline);
682                 return -1;
683         }
684         _D("Parsing this line (%s)\n", linebuffer);
685         /* fill the argc and argv
686            for extract option from command line */
687         argc = 0;
688         while (tok && (argc < MAX_ARGS)) {
689                 argv[argc] = strdup(tok);
690                 tok = strtok(NULL, DELIMITER);
691                 argc++;
692         }
693         free(cmdline);
694
695         /* initialize the command struct with the default value */
696         memset(cmd->devices, 0, sizeof(cmd->devices));
697         cmd->option_file = false;
698         cmd->option_buffer = false;
699         cmd->filename = NULL;
700         cmd->rotate_size = 0;
701         cmd->max_rotated = MAX_ROTATED;
702         cmd->format = (log_format *)log_format_new();
703
704         /* get option and fill the command struct */
705         while ((ret = getopt(argc, argv, "f:r:n:v:b:")) != -1) {
706                 switch (ret) {
707                 case 'f':
708                         cmd->filename = strdup(optarg);
709                         _D("command filename %s\n", cmd->filename);
710                         cmd->option_file = true;
711                         break;
712                 case 'b':
713                         id = get_device_id_by_name(optarg);
714                         _D("command device name %s id %d\n", optarg, id);
715                         if (id < 0 || LOG_ID_MAX < id)
716                                 break;
717                         cmd->option_buffer = true;
718                         /* enable to log in device on/off struct */
719                         cmd->devices[id] = true;
720                         /* enable to open in global device on/off struct */
721                         register_device(id);
722                         break;
723                 case 'r':
724                         if (!isdigit(optarg[0]))
725                                 goto exit_free;
726                         cmd->rotate_size = atoi(optarg);
727                         _D("command rotate size %d\n", cmd->rotate_size);
728                         break;
729                 case 'n':
730                         if (!isdigit(optarg[0]))
731                                 goto exit_free;
732                         cmd->max_rotated = atoi(optarg);
733                         _D("command max rotated %d\n", cmd->max_rotated);
734                         break;
735                 case 'v':
736                         {
737                                 log_print_format print_format;
738                                 print_format = log_format_from_string(optarg);
739                                 if (print_format == FORMAT_OFF) {
740                                         _E("failed to add format\n");
741                                         goto exit_free;
742                                 }
743                                 _D("command format %s\n", optarg);
744                                 log_set_print_format(cmd->format, print_format);
745                         }
746                         break;
747                 default:
748                         break;
749                 }
750         }
751         /* add filter string, when command line have tags */
752         if (argc != optind) {
753                 for (i = optind ; i < argc ; i++) {
754                         ret = log_add_filter_string(cmd->format, argv[i]);
755                         _D("command add fileter string %s\n", argv[i]);
756                         if (ret < 0) {
757                                 _E("Invalid filter expression '%s'\n", argv[i]);
758                                 goto exit_free;
759                         }
760                 }
761         } else {
762                 ret = log_add_filter_string(cmd->format, "*:d");
763                 if (ret < 0) {
764                         _E("Invalid silent filter expression\n");
765                         goto exit_free;
766                 }
767         }
768         /* free argv */
769         for (i = 0; i < argc; i++)
770                 free(argv[i]);
771
772         if (cmd->option_file == false)
773                 goto exit_free;
774         /* If it have not the -b option,
775            set the default devices to open and log */
776         if (cmd->option_buffer == false) {
777                 _D("set default device\n", cmd->filename);
778                 cmd->devices[LOG_ID_MAIN] = true;
779                 cmd->devices[LOG_ID_SYSTEM] = true;
780                 register_device(LOG_ID_MAIN);
781                 register_device(LOG_ID_SYSTEM);
782         }
783         /* for use getopt again */
784         optarg = NULL;
785         optind = 1;
786         optopt = 0;
787
788         return 0;
789
790 exit_free:
791         if (cmd->filename)
792                 free(cmd->filename);
793         return -1;
794 }
795
796 /*
797  * parse command from configuration file
798  * and return the command list with number of command
799  * if an command was successfully parsed, then it returns number of parsed command.
800  * on error or not founded, 0 is returned
801  */
802 static int parse_command(struct log_command *command_list)
803 {
804         FILE *fp;
805         int ncmd;
806         char *line_p;
807         char linebuffer[1024];
808
809         fp = fopen(CONFIG_FILE, "re");
810         if (!fp) {
811                 _E("no config file\n");
812                 goto exit;
813         }
814         ncmd = 0;
815         while (fgets(linebuffer, sizeof(linebuffer), fp) != NULL) {
816                 line_p = strchr(linebuffer, '\n');
817                 if (line_p != NULL)
818                         *line_p = '\0';
819                 if (parse_command_line(linebuffer, &command_list[ncmd]) == 0)
820                         ncmd++;
821                 if (COMMAND_MAX <= ncmd)
822                         break;
823         }
824         fclose(fp);
825
826         return ncmd;
827
828 exit:
829         return 0;
830 }
831
832 /*
833  * free dynamically allocated memory
834  */
835 static void cleanup(void)
836 {
837         work_chain_free(works);
838         device_chain_free(devices);
839 }
840
841 /*
842  * SIGINT, SIGTERM, SIGQUIT signal handler
843  */
844 static void sig_handler(int signo)
845 {
846         _D("sig_handler\n");
847         cleanup();
848         exit(EXIT_SUCCESS);
849 }
850
851 int main(int argc, char **argv)
852 {
853         int i, ncmd;
854         struct stat statbuf;
855         struct log_device *dev;
856         struct log_work *work;
857         struct log_command command_list[COMMAND_MAX];
858         struct sigaction act;
859
860         /* set the signal handler for free dynamically allocated memory. */
861         memset(&act, 0, sizeof(act));
862         sigemptyset(&act.sa_mask);
863         act.sa_handler = (void *)sig_handler;
864         act.sa_flags = 0;
865
866         if (sigaction(SIGQUIT, &act, NULL) < 0)
867                 _E("failed to sigaction for SIGQUIT");
868         if (sigaction(SIGINT, &act, NULL) < 0)
869                 _E("failed to sigaction for SIGINT");
870         if (sigaction(SIGTERM, &act, NULL) < 0)
871                 _E("failed to sigaction for SIGTERM");
872
873         /* parse command from command configuration file. */
874         ncmd = parse_command(command_list);
875
876         /* If it have nothing command, exit. */
877         if (!ncmd)
878                 goto exit;
879
880         /* create log device */
881         device_add(LOG_ID_MAIN);
882         device_add(LOG_ID_SYSTEM);
883         device_add(LOG_ID_RADIO);
884
885         /* create work from the parsed command */
886         for (i = 0; i < ncmd; i++) {
887                 work = work_new();
888                 _D("work new\n");
889                 if (work == NULL) {
890                         _E("failed to work_new\n");
891                         goto clean_exit;
892                 }
893                 /* attatch the work to global works variable */
894                 if (work_add_to_tail(works, work) < 0) {
895                         _E("failed to work_add_to_tail\n");
896                         goto clean_exit;
897                 }
898                 /* 1. set filename, fd and file current size */
899                 work->filename = command_list[i].filename;
900                 if (work->filename == NULL) {
901                         _E("file name is NULL");
902                         goto clean_exit;
903                 }
904                 work->fd = open_work(work->filename);
905                 if (work->fd < 0) {
906                         _E("failed to open log file");
907                         exit(EXIT_FAILURE);
908                 }
909                 if (fstat(work->fd, &statbuf) == -1)
910                         work->size = 0;
911                 else
912                         work->size = statbuf.st_size;
913
914                 /* 2. set size limits for log files */
915                 work->rotate_size = command_list[i].rotate_size;
916
917                 /* 3. set limit on the number of rotated log files */
918                 work->max_rotated = command_list[i].max_rotated;
919
920                 /* 4. set log_format to filter logs*/
921                 work->format = command_list[i].format;
922
923                 /* 5. attatch the work to device task for logging */
924                 dev = devices;
925                 while (dev) {
926                         if (command_list[i].devices[dev->id] == true) {
927                                 work_add_to_device(dev, work);
928                         }
929                         dev = dev->next;
930                 }
931         }
932
933         /* do log */
934         do_logger(devices);
935
936 clean_exit:
937         work_chain_free(works);
938         device_chain_free(devices);
939 exit:
940         return 0;
941 }