add smack rule
[framework/system/dlog.git] / logutil.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
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 <fcntl.h>
26 #include <time.h>
27 #include <sys/time.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <assert.h>
31 #include <sys/stat.h>
32 #include <arpa/inet.h>
33
34
35 #include <logger.h>
36 #include <logprint.h>
37
38 #define DEFAULT_LOG_ROTATE_SIZE_KBYTES 16
39 #define DEFAULT_MAX_ROTATED_LOGS 4
40
41 #define LOG_FILE_DIR    "/dev/log_"
42
43 static log_format* g_logformat;
44 static bool g_nonblock = false;
45 static int g_tail_lines = 0;
46
47 static const char * g_output_filename = NULL;
48 static int g_log_rotate_size_kbytes = 0;                   // 0 means "no log rotation"
49 static int g_max_rotated_logs = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
50 static int g_outfd = -1;
51 static off_t g_out_byte_count = 0;
52 static int g_dev_count = 0;
53
54 struct queued_entry_t {
55         union {
56                 unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
57                 struct logger_entry entry __attribute__((aligned(4)));
58         };
59         struct queued_entry_t* next;
60 };
61
62 static int cmp(struct queued_entry_t* a, struct queued_entry_t* b)
63 {
64         int n = a->entry.sec - b->entry.sec;
65         if (n != 0)
66         {
67                 return n;
68         }
69         return a->entry.nsec - b->entry.nsec;
70 }
71
72
73 struct log_device_t {
74         char* device;
75         int fd;
76         bool printed;
77         struct queued_entry_t* queue;
78         struct log_device_t* next;
79 };
80
81 static void enqueue(struct log_device_t* device, struct queued_entry_t* entry)
82 {
83         if( device->queue == NULL)
84         {
85                 device->queue = entry;
86         }
87         else
88         {
89                 struct queued_entry_t** e = &device->queue;
90                 while(*e && cmp(entry, *e) >= 0 )
91                 {
92                         e = &((*e)->next);
93                 }
94                 entry->next = *e;
95                 *e = entry;
96     }
97 }
98
99 static int open_logfile (const char *pathname)
100 {
101     return open(pathname, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
102 }
103
104 static void rotate_logs()
105 {
106     int err;
107         int i;
108         char file0[256]={0};
109         char file1[256]={0};
110
111     // Can't rotate logs if we're not outputting to a file
112     if (g_output_filename == NULL) {
113         return;
114     }
115
116     close(g_outfd);
117
118     for (i = g_max_rotated_logs ; i > 0 ; i--)
119         {
120                 snprintf(file1, 255, "%s.%d", g_output_filename, i);
121
122                 if (i - 1 == 0) {
123                         snprintf(file0, 255, "%s", g_output_filename);
124                 } else {
125                         snprintf(file0, 255, "%s.%d", g_output_filename, i - 1);
126                 }
127
128                 err = rename (file0, file1);
129
130                 if (err < 0 && errno != ENOENT) {
131                         perror("while rotating log files");
132                 }
133     }
134
135     g_outfd = open_logfile (g_output_filename);
136
137     if (g_outfd < 0) {
138         perror ("couldn't open output file");
139         exit(-1);
140     }
141
142     g_out_byte_count = 0;
143
144 }
145
146
147 static void processBuffer(struct log_device_t* dev, struct logger_entry *buf)
148 {
149         int bytes_written = 0;
150         int err;
151         log_entry entry;
152         char mgs_buf[1024];
153
154         err = log_process_log_buffer(buf, &entry);
155
156         if (err < 0) {
157                 goto error;
158         }
159
160         if (log_should_print_line(g_logformat, entry.tag, entry.priority)) {
161                 if (false && g_dev_count > 1) {
162                         // FIXME
163                         mgs_buf[0] = dev->device[0];
164                         mgs_buf[1] = ' ';
165                         bytes_written = write(g_outfd, mgs_buf, 2);
166                         if (bytes_written < 0)
167                         {
168                                 perror("output error");
169                                 exit(-1);
170                         }
171                 }
172
173                 bytes_written = log_print_log_line(g_logformat, g_outfd, &entry);
174
175                 if (bytes_written < 0)
176                 {
177                         perror("output error");
178                         exit(-1);
179                 }
180         }
181
182         g_out_byte_count += bytes_written;
183
184         if (g_log_rotate_size_kbytes > 0 && (g_out_byte_count / 1024) >= g_log_rotate_size_kbytes) {
185                 if (g_nonblock) {
186                         exit(0);
187                 } else {
188                         rotate_logs();
189                 }
190         }
191
192 error:
193         //fprintf (stderr, "Error processing record\n");
194         return;
195 }
196
197 static void chooseFirst(struct log_device_t* dev, struct log_device_t** firstdev)
198 {
199         for (*firstdev = NULL; dev != NULL; dev = dev->next) {
200                 if (dev->queue != NULL && (*firstdev == NULL || cmp(dev->queue, (*firstdev)->queue) < 0))
201                 {
202                         *firstdev = dev;
203                 }
204         }
205 }
206
207 static void maybePrintStart(struct log_device_t* dev) {
208         if (!dev->printed) {
209                 dev->printed = true;
210                 if (g_dev_count > 1 ) {
211                         char buf[1024];
212                         snprintf(buf, sizeof(buf), "--------- beginning of %s\n", dev->device);
213                         if (write(g_outfd, buf, strlen(buf)) < 0) {
214                                 perror("output error");
215                                 exit(-1);
216                         }
217                 }
218         }
219 }
220
221 static void skipNextEntry(struct log_device_t* dev) {
222         maybePrintStart(dev);
223         struct queued_entry_t* entry = dev->queue;
224         dev->queue = entry->next;
225         free(entry);
226 }
227
228 static void printNextEntry(struct log_device_t* dev)
229 {
230         maybePrintStart(dev);
231         processBuffer(dev, &dev->queue->entry);
232         skipNextEntry(dev);
233 }
234
235
236 static void read_log_lines(struct log_device_t* devices)
237 {
238         struct log_device_t* dev;
239         int max = 0;
240         int ret;
241         int queued_lines = 0;
242         bool sleep = false; // for exit immediately when log buffer is empty and g_nonblock value is true.
243
244         int result;
245         fd_set readset;
246
247         for (dev=devices; dev; dev = dev->next) {
248                 if (dev->fd > max) {
249                         max = dev->fd;
250                 }
251         }
252
253         while (1) {
254                 do {
255                         struct timeval timeout = { 0, 5000 /* 5ms */ }; // If we oversleep it's ok, i.e. ignore EINTR.
256                         FD_ZERO(&readset);
257                         for (dev=devices; dev; dev = dev->next) {
258                                 FD_SET(dev->fd, &readset);
259                         }
260                         result = select(max + 1, &readset, NULL, NULL, sleep ? NULL : &timeout);
261                 } while (result == -1 && errno == EINTR);
262
263         if (result >= 0) {
264             for (dev=devices; dev; dev = dev->next) {
265                 if (FD_ISSET(dev->fd, &readset)) {
266                     struct queued_entry_t* entry = (struct queued_entry_t *)malloc(sizeof( struct queued_entry_t));
267                                         if (entry == NULL) {
268                                                 fprintf(stderr,"Can't malloc queued_entry\n");
269                                                 exit(-1);
270                                         }
271                                         entry->next = NULL;
272
273                     /* NOTE: driver guarantees we read exactly one full entry */
274                     ret = read(dev->fd, entry->buf, LOGGER_ENTRY_MAX_LEN);
275                     if (ret < 0) {
276                         if (errno == EINTR) {
277                             free(entry);
278                             goto next;
279                         }
280                         if (errno == EAGAIN) {
281                             free(entry);
282                             break;
283                         }
284                         perror("dlogutil read");
285                         exit(EXIT_FAILURE);
286                     }
287                     else if (!ret) {
288                         free(entry);
289                         fprintf(stderr, "read: Unexpected EOF!\n");
290                         exit(EXIT_FAILURE);
291                     }
292                     else if (entry->entry.len != ret - sizeof(struct logger_entry)) {
293                         free(entry);
294                         fprintf(stderr, "read: unexpected length. Expected %d, got %d\n",
295                                 entry->entry.len, ret - sizeof(struct logger_entry));
296                         exit(EXIT_FAILURE);
297                     }
298                     entry->entry.msg[entry->entry.len] = '\0';
299
300                     enqueue(dev, entry);
301                     ++queued_lines;
302                 }
303             }
304
305             if (result == 0) {
306                 // we did our short timeout trick and there's nothing new
307                 // print everything we have and wait for more data
308                 sleep = true;
309                 while (true) {
310                     chooseFirst(devices, &dev);
311                     if (dev == NULL) {
312                         break;
313                     }
314                     if (g_tail_lines == 0 || queued_lines <= g_tail_lines) {
315                         printNextEntry(dev);
316                     } else {
317                         skipNextEntry(dev);
318                     }
319                     --queued_lines;
320                 }
321
322                 // the caller requested to just dump the log and exit
323                 if (g_nonblock) {
324                     exit(0);
325                 }
326             } else {
327                 // print all that aren't the last in their list
328                 sleep = false;
329                 while (g_tail_lines == 0 || queued_lines > g_tail_lines) {
330                     chooseFirst(devices, &dev);
331                     if (dev == NULL || dev->queue->next == NULL) {
332                         break;
333                     }
334                     if (g_tail_lines == 0) {
335                         printNextEntry(dev);
336                     } else {
337                         skipNextEntry(dev);
338                     }
339                     --queued_lines;
340                 }
341             }
342         }
343 next:
344         ;
345     }
346 }
347
348
349 static int clear_log(int logfd)
350 {
351     return ioctl(logfd, LOGGER_FLUSH_LOG);
352 }
353
354 /* returns the total size of the log's ring buffer */
355 static int get_log_size(int logfd)
356 {
357     return ioctl(logfd, LOGGER_GET_LOG_BUF_SIZE);
358 }
359
360 /* returns the readable size of the log's ring buffer (that is, amount of the log consumed) */
361 static int get_log_readable_size(int logfd)
362 {
363     return ioctl(logfd, LOGGER_GET_LOG_LEN);
364 }
365
366 static void setup_output()
367 {
368
369         if (g_output_filename == NULL) {
370                 g_outfd = STDOUT_FILENO;
371
372         } else {
373                 struct stat statbuf;
374
375                 g_outfd = open_logfile (g_output_filename);
376
377                 if (g_outfd < 0) {
378                         perror ("couldn't open output file");
379                         exit(-1);
380                 }
381                 if (fstat(g_outfd, &statbuf) == -1)
382                         g_out_byte_count = 0;
383                 else
384                         g_out_byte_count = statbuf.st_size;
385         }
386 }
387
388 static int set_log_format(const char * formatString)
389 {
390         static log_print_format format;
391
392         format = log_format_from_string(formatString);
393
394         if (format == FORMAT_OFF) {
395                 // FORMAT_OFF means invalid string
396                 return -1;
397         }
398
399         log_set_print_format(g_logformat, format);
400
401         return 0;
402 }
403
404 static void show_help(const char *cmd)
405 {
406     fprintf(stderr,"Usage: %s [options] [filterspecs]\n", cmd);
407
408     fprintf(stderr, "options include:\n"
409                     "  -s              Set default filter to silent.\n"
410                     "                  Like specifying filterspec '*:s'\n"
411                     "  -f <filename>   Log to file. Default to stdout\n"
412                     "  -r [<kbytes>]   Rotate log every kbytes. (16 if unspecified). Requires -f\n"
413                     "  -n <count>      Sets max number of rotated logs to <count>, default 4\n"
414                     "  -v <format>     Sets the log print format, where <format> is one of:\n\n"
415                     "                  brief(by default) process tag thread raw time threadtime long\n\n"
416                     "  -c              clear (flush) the entire log and exit, conflicts with '-g'\n"
417                     "  -d              dump the log and then exit (don't block)\n"
418                     "  -t <count>      print only the most recent <count> lines (implies -d)\n"
419                     "  -g              get the size of the log's ring buffer and exit, conflicts with '-c'\n"
420                     "  -b <buffer>     request alternate ring buffer\n"
421                     "                  ('main' (default), 'radio', 'system')");
422
423
424     fprintf(stderr,"\nfilterspecs are a series of \n"
425                    "  <tag>[:priority]\n\n"
426                    "where <tag> is a log component tag (or * for all) and priority is:\n"
427                    "  V    Verbose\n"
428                    "  D    Debug\n"
429                    "  I    Info\n"
430                    "  W    Warn\n"
431                    "  E    Error\n"
432                    "  F    Fatal\n"
433                    "  S    Silent (supress all output)\n"
434                    "\n'*' means '*:D' and <tag> by itself means <tag>:V\n"
435                    "If no filterspec is found, filter defaults to '*:I'\n\n");
436 }
437
438
439 /*
440  * free one log_device_t and it doesn't take care of chain so it
441  * may break the chain list
442  */
443 static void log_devices_free(struct log_device_t *dev)
444 {
445         if (!dev)
446                 return;
447
448         if (dev->device)
449                 free(dev->device);
450
451         if (dev->queue) {
452                 while (dev->queue->next) {
453                         struct queued_entry_t *tmp = dev->queue->next;
454                         dev->queue->next = tmp->next;
455                         free(tmp);
456                 }
457                 free(dev->queue);
458         }
459
460         free(dev);
461         dev = NULL;
462 }
463
464
465 /*
466  * free all the nodes after the "dev" and includes itself
467  */
468 static void log_devices_chain_free(struct log_device_t *dev)
469 {
470         if (!dev)
471                 return;
472
473         while (dev->next) {
474                 struct log_device_t *tmp = dev->next;
475                 dev->next = tmp->next;
476                 log_devices_free(tmp);
477         }
478
479         log_devices_free(dev);
480         dev = NULL;
481 }
482
483
484 /*
485  * create a new log_device_t instance but don't care about
486  * the device node accessable or not
487  */
488 static struct log_device_t *log_devices_new(const char *path)
489 {
490         struct log_device_t *new;
491
492         if (!path || strlen(path) <= 0)
493                 return NULL;
494
495         new = malloc(sizeof(*new));
496         if (!new) {
497                 fprintf(stderr, "out of memory\n");
498                 return NULL;
499         }
500
501         new->device = strdup(path);
502         new->fd = -1;
503         new->printed = false;
504         new->queue = NULL;
505         new->next = NULL;
506
507         return new;
508 }
509
510
511 /*
512  * add a new device to the tail of chain
513  */
514 static int log_devices_add_to_tail(struct log_device_t *devices, struct log_device_t *new)
515 {
516         struct log_device_t *tail = devices;
517
518         if (!devices || !new)
519                 return -1;
520
521         while (tail->next)
522                 tail = tail->next;
523
524         tail->next = new;
525         g_dev_count++;
526
527         return 0;
528 }
529
530 int main(int argc, char **argv)
531 {
532     int err;
533     int has_set_log_format = 0;
534     int is_clear_log = 0;
535     int getLogSize = 0;
536     int mode = O_RDONLY;
537         int i;
538 //    const char *forceFilters = NULL;
539         struct log_device_t* devices = NULL;
540         struct log_device_t* dev;
541
542     g_logformat = (log_format *)log_format_new();
543
544     if (argc == 2 && 0 == strcmp(argv[1], "--test")) {
545         logprint_run_tests();
546         exit(0);
547     }
548
549     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
550         show_help(argv[0]);
551         exit(0);
552     }
553
554     for (;;) {
555         int ret;
556
557         ret = getopt(argc, argv, "cdt:gsf:r:n:v:b:D");
558
559         if (ret < 0) {
560             break;
561         }
562
563         switch(ret) {
564             case 's':
565                 // default to all silent
566                 log_add_filter_rule(g_logformat, "*:s");
567             break;
568
569             case 'c':
570                 is_clear_log = 1;
571                 mode = O_WRONLY;
572             break;
573
574             case 'd':
575                 g_nonblock = true;
576             break;
577
578             case 't':
579                 g_nonblock = true;
580                 g_tail_lines = atoi(optarg);
581             break;
582
583
584             case 'g':
585                 getLogSize = 1;
586             break;
587
588                         case 'b': {
589                                                   char *buf;
590                                                   if (asprintf(&buf, LOG_FILE_DIR "%s", optarg) == -1) {
591                                                           asprintf(stderr,"Can't malloc LOG_FILE_DIR\n");
592                                                           exit(-1);
593                                                   }
594
595                                                   dev = log_devices_new(buf);
596                                                   if (dev == NULL) {
597                                                           fprintf(stderr,"Can't add log device: %s\n", buf);
598                                                           exit(-1);
599                                                   }
600                                                   if (devices) {
601                                                           if (log_devices_add_to_tail(devices, dev)) {
602                                                                   fprintf(stderr, "Open log device %s failed\n", buf);
603                                                                   exit(-1);
604                                                           }
605                                                   } else {
606                                                           devices = dev;
607                                                           g_dev_count = 1;
608                                                   }
609                                           }
610             break;
611
612             case 'f':
613                 // redirect output to a file
614
615                 g_output_filename = optarg;
616
617             break;
618
619             case 'r':
620 //                if (optarg == NULL) {
621 //                                      fprintf(stderr,"optarg == null\n");
622  //                  g_log_rotate_size_kbytes = DEFAULT_LOG_ROTATE_SIZE_KBYTES;
623  //              } else {
624                     //long logRotateSize;
625                     //char *lastDigit;
626
627                     if (!isdigit(optarg[0])) {
628                         fprintf(stderr,"Invalid parameter to -r\n");
629                         show_help(argv[0]);
630                         exit(-1);
631                     }
632                     g_log_rotate_size_kbytes = atoi(optarg);
633    //             }
634             break;
635
636             case 'n':
637                 if (!isdigit(optarg[0])) {
638                     fprintf(stderr,"Invalid parameter to -r\n");
639                     show_help(argv[0]);
640                     exit(-1);
641                 }
642
643                 g_max_rotated_logs = atoi(optarg);
644             break;
645
646             case 'v':
647                 err = set_log_format (optarg);
648                 if (err < 0) {
649                     fprintf(stderr,"Invalid parameter to -v\n");
650                     show_help(argv[0]);
651                     exit(-1);
652                 }
653
654                 has_set_log_format = 1;
655             break;
656
657                         default:
658                                 fprintf(stderr,"Unrecognized Option\n");
659                                 show_help(argv[0]);
660                                 exit(-1);
661                         break;
662                 }
663         }
664
665         /* get log size conflicts with write mode */
666         if (getLogSize && mode != O_RDONLY) {
667                 show_help(argv[0]);
668                 exit(-1);
669         }
670
671         if (!devices) {
672                 devices = log_devices_new("/dev/"LOGGER_LOG_MAIN);
673                 if (devices == NULL) {
674                         fprintf(stderr,"Can't add log device: %s\n", LOGGER_LOG_MAIN);
675                         exit(-1);
676                 }
677         g_dev_count = 1;
678
679         int accessmode =
680                   (mode == O_RDONLY) ? R_OK : 0
681                 | (mode == O_WRONLY) ? W_OK : 0;
682
683         // only add this if it's available
684         if (0 == access("/dev/"LOGGER_LOG_SYSTEM, accessmode)) {
685                 if (log_devices_add_to_tail(devices, log_devices_new("/dev/"LOGGER_LOG_SYSTEM))) {
686                         fprintf(stderr,"Can't add log device: %s\n", LOGGER_LOG_SYSTEM);
687                         exit(-1);
688                 }
689         }
690         if (0 == access("/dev/"LOGGER_LOG_APPS, accessmode)) {
691                 if (log_devices_add_to_tail(devices, log_devices_new("/dev/"LOGGER_LOG_APPS))) {
692                         fprintf(stderr,"Can't add log device: %s\n", LOGGER_LOG_APPS);
693                         exit(-1);
694                 }
695         }
696
697 /*
698         // only add this if it's available
699         int fd;
700         if ((fd = open("/dev/"LOGGER_LOG_SYSTEM, mode)) != -1) {
701                 devices->next = (struct log_device_t *)malloc( sizeof(struct log_device_t));
702                 devices->next->device = strdup("/dev/"LOGGER_LOG_SYSTEM);
703                 devices->next->fd = -1;
704                 devices->next->printed = false;
705                 devices->next->queue = NULL;
706                 devices->next->next = NULL;
707                 g_dev_count ++;
708
709                 close(fd);
710         }
711 */
712     }
713
714     if (g_log_rotate_size_kbytes != 0 && g_output_filename == NULL)
715         {
716                 fprintf(stderr,"-r requires -f as well\n");
717                 show_help(argv[0]);
718                 exit(-1);
719         }
720
721     setup_output();
722
723
724         if (has_set_log_format == 0) {
725                 err = set_log_format("brief");
726         }
727 /*
728                 const char* logFormat = getenv("DLOG_PRINTF_LOG");
729
730                 if (logFormat != NULL) {
731                         err = set_log_format("brief");
732
733                         if (err < 0) {
734                                 fprintf(stderr, "invalid format in DLOG_PRINTF_LOG '%s'\n", logFormat);
735                         }
736                 }
737         }
738         if (forceFilters) {
739                 err = log_add_filter_string(g_logformat, forceFilters);
740                 if (err < 0) {
741                         fprintf (stderr, "Invalid filter expression in -logcat option\n");
742                         exit(0);
743                 }
744         } else if (argc == optind) {
745         // Add from environment variable
746                 char *env_tags_orig = getenv("DLOG_LOG_TAGS");
747
748                 if (env_tags_orig != NULL) {
749                         err = log_add_filter_string(g_logformat, env_tags_orig);
750
751                         if (err < 0) {
752                                 fprintf(stderr, "Invalid filter expression in DLOG_LOG_TAGS\n");
753                                 show_help(argv[0]);
754                                 exit(-1);
755                         }
756                 }
757         } else {
758         // Add from commandline
759 */
760         fprintf(stderr,"arc = %d, optind = %d ,Kb %d, rotate %d\n", argc, optind,g_log_rotate_size_kbytes,g_max_rotated_logs);
761
762         if(argc == optind )
763         {
764                 // Add from environment variable
765         //char *env_tags_orig = getenv("DLOG_TAGS");
766                 log_add_filter_string(g_logformat, "*:d");
767         }
768         else
769         {
770
771                 for (i = optind ; i < argc ; i++) {
772                         err = log_add_filter_string(g_logformat, argv[i]);
773
774                         if (err < 0) {
775                                 fprintf (stderr, "Invalid filter expression '%s'\n", argv[i]);
776                                 show_help(argv[0]);
777                                 exit(-1);
778                         }
779                 }
780         }
781 /*
782     }
783 */
784     dev = devices;
785     while (dev) {
786         dev->fd = open(dev->device, mode);
787         if (dev->fd < 0) {
788             fprintf(stderr, "Unable to open log device '%s': %s\n",
789                 dev->device, strerror(errno));
790             exit(EXIT_FAILURE);
791         }
792
793         if (is_clear_log) {
794             int ret;
795             ret = clear_log(dev->fd);
796             if (ret) {
797                 perror("ioctl");
798                 exit(EXIT_FAILURE);
799             }
800         }
801
802         if (getLogSize) {
803             int size, readable;
804
805             size = get_log_size(dev->fd);
806             if (size < 0) {
807                 perror("ioctl");
808                 exit(EXIT_FAILURE);
809             }
810
811             readable = get_log_readable_size(dev->fd);
812             if (readable < 0) {
813                 perror("ioctl");
814                 exit(EXIT_FAILURE);
815             }
816
817             printf("%s: ring buffer is %dKb (%dKb consumed), "
818                    "max entry is %db, max payload is %db\n", dev->device,
819                    size / 1024, readable / 1024,
820                    (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
821         }
822
823         dev = dev->next;
824     }
825
826     if (getLogSize) {
827         return 0;
828     }
829
830     if (is_clear_log) {
831         return 0;
832     }
833
834     read_log_lines(devices);
835
836         log_devices_chain_free(devices);
837
838     return 0;
839 }