From: Mateusz Majewski Date: Fri, 25 Sep 2020 11:03:31 +0000 (+0200) Subject: Move the util parser outside of util so we can reuse it X-Git-Tag: accepted/tizen/6.0/unified/20201030.115440~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=078ea7ca07476939a3027e84fdafcf1051789a68;p=platform%2Fcore%2Fsystem%2Fdlog.git Move the util parser outside of util so we can reuse it Change-Id: Icec52e46925923e549850ad9f10f221f7e363dfc --- diff --git a/Makefile.am b/Makefile.am index d0c3c4e..f38f03f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -93,7 +93,8 @@ dlogutil_SOURCES = \ src/shared/logcommon.c \ src/shared/logprint.c \ src/shared/log_file.c \ - src/shared/ptrs_list.c + src/shared/ptrs_list.c \ + src/shared/util_parser.c libexec_PROGRAMS = dlog-log-critical diff --git a/include/util_parser.h b/include/util_parser.h new file mode 100644 index 0000000..d595ee3 --- /dev/null +++ b/include/util_parser.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include + +typedef enum action_e { + ACTION_PRINT = 0, + ACTION_GET_CAPACITY, + ACTION_CLEAR, +} action_e; + +struct parse_result { + enum { + PARSE_OK, + PARSE_OOM, + PARSE_BAD_COLOR, + PARSE_BAD_SORT_BY, + PARSE_BAD_BUFFER, + PARSE_BAD_FORMAT, + PARSE_OPTION_REPEATED, + PARSE_OPTION_NUMERICAL_ARGUMENT, + PARSE_VERSION_REQUESTED, + PARSE_HELP_REQUESTED, + PARSE_NO_PARSE, + } status; + union { + struct { + bool colors_auto; + bool colors_force; + log_print_format format; + size_t rotate_size_kbytes; + size_t max_rotated; + const char *file_path; + size_t write_buffer_size; + int enabled_buffers; + action_e action; + list_head filterspecs; + list_head pid_filters; + list_head tid_filters; + int sorting_settings; + dlogutil_mode_e mode; + unsigned dump_size; + dlogutil_sorting_order_e sort_by; + }; + const char *which_option; + const char *bad_contents; + }; +}; + +struct parse_result parse_options(int argc, char **argv); +void parse_result_cleanup(struct parse_result *pr); diff --git a/src/logutil/logutil.c b/src/logutil/logutil.c index 079642e..a3862c7 100644 --- a/src/logutil/logutil.c +++ b/src/logutil/logutil.c @@ -19,12 +19,10 @@ #include #include -#include #include #include -#include -#include +#include #include "logutil_doc.h" @@ -40,265 +38,11 @@ // buffers to use by default, when nothing specified static const int default_buffers = (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_APPS); -typedef enum action_e { - ACTION_PRINT = 0, - ACTION_GET_CAPACITY, - ACTION_CLEAR, -} action_e; - static void show_version(const char *name) { printf("%s version: %s-%s\n", name, __DLOG_VERSION, __DLOG_RELEASE); } -struct parse_result { - enum { - PARSE_OK, - PARSE_OOM, - PARSE_BAD_COLOR, - PARSE_BAD_SORT_BY, - PARSE_BAD_BUFFER, - PARSE_BAD_FORMAT, - PARSE_OPTION_REPEATED, - PARSE_OPTION_NUMERICAL_ARGUMENT, - PARSE_VERSION_REQUESTED, - PARSE_HELP_REQUESTED, - PARSE_NO_PARSE, - } status; - union { - struct { - bool colors_auto; - bool colors_force; - log_print_format format; - size_t rotate_size_kbytes; - size_t max_rotated; - const char *file_path; - size_t write_buffer_size; - int enabled_buffers; - action_e action; - list_head filterspecs; - list_head pid_filters; - list_head tid_filters; - int sorting_settings; - dlogutil_mode_e mode; - unsigned dump_size; - dlogutil_sorting_order_e sort_by; - }; - const char *which_option; - const char *bad_contents; - }; -}; - -void parse_result_cleanup(struct parse_result *pr) -{ - if (pr && pr->status == PARSE_OK) { - list_clear(&pr->filterspecs); - list_clear_free_contents(&pr->pid_filters); - list_clear_free_contents(&pr->tid_filters); - } -} - -static struct parse_result parse_options(int argc, char **argv) -{ - bool colors_auto = true; - bool colors_force = false; - log_print_format format = FORMAT_BRIEF; - size_t rotate_size_kbytes = DEFAULT_ROTATE_SIZE_KB; - size_t max_rotated = DEFAULT_ROTATE_NUM_FILES; - const char *file_path = NULL; - size_t write_buffer_size = 0; - int enabled_buffers = 0; - action_e action = ACTION_PRINT; - __attribute__((cleanup(list_clear))) list_head filterspecs = NULL; - __attribute__((cleanup(list_clear_free_contents))) list_head pid_filters = NULL; - __attribute__((cleanup(list_clear_free_contents))) list_head tid_filters = NULL; - int sorting_settings = DEFAULT_SORT_BUFFER_SIZE; - dlogutil_mode_e mode = DLOGUTIL_MODE_CONTINUOUS; - unsigned dump_size = DLOGUTIL_MAX_DUMP_SIZE; - dlogutil_sorting_order_e sort_by = DLOGUTIL_SORT_DEFAULT; - - bool buffer_made = false; - - while (1) { - static const struct option long_options[] = { - {"tid" , required_argument, NULL, 0}, - {"pid" , required_argument, NULL, 1}, - {"version", no_argument, NULL, 2}, - {"color" , required_argument, NULL, 3}, - {"sort-by", required_argument, NULL, 4}, - {"help" , no_argument, NULL, 'h'}, - {0} - }; - int option = getopt_long(argc, argv, "cdmt:gsf:r:n:v:b:u:e:h", long_options, NULL); - - if (option < 0) - break; - - switch (option) { - case 0: { /* tid filter */ - int tid; - if (sscanf(optarg, "%d", &tid) != 1) - return (struct parse_result) { .status = PARSE_OPTION_NUMERICAL_ARGUMENT, .which_option = "--tid", }; - else { - pid_t *insert = calloc(1, sizeof(pid_t)); - if (insert == NULL) - return (struct parse_result) { .status = PARSE_OOM, }; - *insert = tid; - if (!list_add(&tid_filters, insert)) { - free(insert); - return (struct parse_result) { .status = PARSE_OOM, }; - } - } - break; - } - case 1: { /* pid filter */ - int pid; - if (sscanf(optarg, "%d", &pid) != 1) - return (struct parse_result) { .status = PARSE_OPTION_NUMERICAL_ARGUMENT, .which_option = "--pid", }; - else { - pid_t *insert = calloc(1, sizeof(pid_t)); - if (insert == NULL) - return (struct parse_result) { .status = PARSE_OOM, }; - *insert = pid; - if (!list_add(&tid_filters, insert)) { - free(insert); - return (struct parse_result) { .status = PARSE_OOM, }; - } - } - break; - } - case 2: { /* version */ - return (struct parse_result) { .status = PARSE_VERSION_REQUESTED, }; - } - case 3: /* colored headers */ - colors_auto = false; - if (!strcmp(optarg, "always")) - colors_force = true; - else if (!strcmp(optarg, "auto")) - colors_auto = true; - else if (!strcmp(optarg, "never")) - colors_force = false; - else - return (struct parse_result) { .status = PARSE_BAD_COLOR, .bad_contents = optarg, }; - break; - case 4: /* timestamp */ - if (!strcmp(optarg, "default")) - sort_by = DLOGUTIL_SORT_DEFAULT; - else { - sort_by = get_order_from_string(optarg); - if (sort_by == DLOGUTIL_SORT_DEFAULT) - return (struct parse_result) { .status = PARSE_BAD_SORT_BY, .bad_contents = optarg, }; - } - break; - case 'd': - mode = DLOGUTIL_MODE_DUMP; - break; - case 'm': - mode = DLOGUTIL_MODE_MONITOR; - break; - case 't': - mode = DLOGUTIL_MODE_DUMP; - if (sscanf(optarg, "%u", &dump_size) != 1) - return (struct parse_result) { .status = PARSE_OPTION_NUMERICAL_ARGUMENT, .which_option = "-t", }; - break; - case 'c': - action = ACTION_CLEAR; - break; - case 'g': - action = ACTION_GET_CAPACITY; - break; - case 'b': { - log_id_t id = log_id_by_name(optarg); - if (id == LOG_ID_INVALID) - return (struct parse_result) { .status = PARSE_BAD_BUFFER, .bad_contents = optarg, }; - bit_set(&enabled_buffers, id); - break; - } - case 'u': { - unsigned size; - if (sscanf(optarg, "%u", &size) != 1) - return (struct parse_result) { .status = PARSE_OPTION_NUMERICAL_ARGUMENT, .which_option = "-u", }; - if (size == 0) - sorting_settings = 0; - else - sorting_settings = size; - break; - } - case 'f': - file_path = optarg; - break; - case 'v': { - format = log_format_from_string(optarg); - if (format == FORMAT_OFF) - return (struct parse_result) { .status = PARSE_BAD_FORMAT, .bad_contents = optarg, }; - break; - } - case 's': - if (!list_add(&filterspecs, "*:S")) - return (struct parse_result) { .status = PARSE_OOM, }; - break; - case 'r': - if (sscanf(optarg, "%zu", &rotate_size_kbytes) != 1) - return (struct parse_result) { .status = PARSE_OPTION_NUMERICAL_ARGUMENT, .which_option = "-r", }; - break; - case 'n': - if (sscanf(optarg, "%zu", &max_rotated) != 1) - return (struct parse_result) { .status = PARSE_OPTION_NUMERICAL_ARGUMENT, .which_option = "-n", }; - break; - case 'e': { - if (buffer_made) - return (struct parse_result) { .status = PARSE_OPTION_REPEATED, .which_option = "-e", }; - if (sscanf(optarg, "%zu", &write_buffer_size) != 1) - return (struct parse_result) { .status = PARSE_OPTION_NUMERICAL_ARGUMENT, .which_option = "-e", }; - buffer_made = true; - break; - } - case 'h': - return (struct parse_result) { .status = PARSE_HELP_REQUESTED, }; - default: // invalid option or missing mandatory parameter - return (struct parse_result) { .status = PARSE_NO_PARSE, }; - } - } - - while (optind < argc) { - /* TODO: We don't want to call log_filter_set_filterspec/dlogutil_config_filter_filterspec here, - * as we want the option parser to be general. Unfortunately, this means that the user has to parse - * the filterspecs and not us. Any idea on how to make this nicer? */ - if (!list_add(&filterspecs, argv[optind++])) - return (struct parse_result) { .status = PARSE_OOM, }; - } - - if (enabled_buffers == 0) - enabled_buffers = default_buffers; - - if (!buffer_made && mode == DLOGUTIL_MODE_DUMP) - write_buffer_size = DEFAULT_WRITE_BUFFER_SIZE; - - struct parse_result ret = (struct parse_result) { - .status = PARSE_OK, - .colors_auto = colors_auto, - .colors_force = colors_force, - .format = format, - .rotate_size_kbytes = rotate_size_kbytes, - .max_rotated = max_rotated, - .file_path = file_path, - .write_buffer_size = write_buffer_size, - .enabled_buffers = enabled_buffers, - .action = action, - .filterspecs = filterspecs, - .pid_filters = pid_filters, - .tid_filters = tid_filters, - .sorting_settings = sorting_settings, - .mode = mode, - .dump_size = dump_size, - .sort_by = sort_by, - }; - filterspecs = NULL; - pid_filters = NULL; - tid_filters = NULL; - return ret; -} - static void config_cleanup(dlogutil_config_s *const *config) { assert(config); dlogutil_config_destroy(*config); @@ -608,18 +352,20 @@ int main(int argc, char **argv) ERR("Error: out of memory while applying TID filter\n"); } + int enabled_buffers = pr.enabled_buffers != 0 ? pr.enabled_buffers : default_buffers; + int r; switch (pr.action) { case ACTION_PRINT: { - r = do_print(pr.mode, pr.dump_size, pr.enabled_buffers, pr.sort_by, config, &l_file); + r = do_print(pr.mode, pr.dump_size, enabled_buffers, pr.sort_by, config, &l_file); break; } case ACTION_GET_CAPACITY: { - r = for_each_buffer(pr.enabled_buffers, print_buffer_capacity); + r = for_each_buffer(enabled_buffers, print_buffer_capacity); break; } case ACTION_CLEAR: - r = for_each_buffer(pr.enabled_buffers, clear_buffer); + r = for_each_buffer(enabled_buffers, clear_buffer); break; } diff --git a/src/logutil/logutil_doc.h b/src/logutil/logutil_doc.h index 94921d0..b3d4d5d 100644 --- a/src/logutil/logutil_doc.h +++ b/src/logutil/logutil_doc.h @@ -36,8 +36,6 @@ If you specify any other tag without priority, the priority defaults to V #include -#define DEFAULT_WRITE_BUFFER_SIZE 1048576 - static void show_help(const char *cmd, bool requested_by_user) { static const char *format_str = "Usage: %s [options] [filterspecs]" diff --git a/src/shared/util_parser.c b/src/shared/util_parser.c new file mode 100644 index 0000000..a72dd54 --- /dev/null +++ b/src/shared/util_parser.c @@ -0,0 +1,212 @@ +#include +#include +#include + +#define DEFAULT_WRITE_BUFFER_SIZE 1048576 + +void parse_result_cleanup(struct parse_result *pr) +{ + if (pr && pr->status == PARSE_OK) { + list_clear(&pr->filterspecs); + list_clear_free_contents(&pr->pid_filters); + list_clear_free_contents(&pr->tid_filters); + } +} + +struct parse_result parse_options(int argc, char **argv) +{ + bool colors_auto = true; + bool colors_force = false; + log_print_format format = FORMAT_BRIEF; + size_t rotate_size_kbytes = DEFAULT_ROTATE_SIZE_KB; + size_t max_rotated = DEFAULT_ROTATE_NUM_FILES; + const char *file_path = NULL; + size_t write_buffer_size = 0; + int enabled_buffers = 0; + action_e action = ACTION_PRINT; + __attribute__((cleanup(list_clear))) list_head filterspecs = NULL; + __attribute__((cleanup(list_clear_free_contents))) list_head pid_filters = NULL; + __attribute__((cleanup(list_clear_free_contents))) list_head tid_filters = NULL; + int sorting_settings = DEFAULT_SORT_BUFFER_SIZE; + dlogutil_mode_e mode = DLOGUTIL_MODE_CONTINUOUS; + unsigned dump_size = DLOGUTIL_MAX_DUMP_SIZE; + dlogutil_sorting_order_e sort_by = DLOGUTIL_SORT_DEFAULT; + + bool buffer_made = false; + + while (1) { + static const struct option long_options[] = { + {"tid" , required_argument, NULL, 0}, + {"pid" , required_argument, NULL, 1}, + {"version", no_argument, NULL, 2}, + {"color" , required_argument, NULL, 3}, + {"sort-by", required_argument, NULL, 4}, + {"help" , no_argument, NULL, 'h'}, + {0} + }; + int option = getopt_long(argc, argv, "cdmt:gsf:r:n:v:b:u:e:h", long_options, NULL); + + if (option < 0) + break; + + switch (option) { + case 0: { /* tid filter */ + int tid; + if (sscanf(optarg, "%d", &tid) != 1) + return (struct parse_result) { .status = PARSE_OPTION_NUMERICAL_ARGUMENT, .which_option = "--tid", }; + else { + pid_t *insert = calloc(1, sizeof(pid_t)); + if (insert == NULL) + return (struct parse_result) { .status = PARSE_OOM, }; + *insert = tid; + if (!list_add(&tid_filters, insert)) { + free(insert); + return (struct parse_result) { .status = PARSE_OOM, }; + } + } + break; + } + case 1: { /* pid filter */ + int pid; + if (sscanf(optarg, "%d", &pid) != 1) + return (struct parse_result) { .status = PARSE_OPTION_NUMERICAL_ARGUMENT, .which_option = "--pid", }; + else { + pid_t *insert = calloc(1, sizeof(pid_t)); + if (insert == NULL) + return (struct parse_result) { .status = PARSE_OOM, }; + *insert = pid; + if (!list_add(&tid_filters, insert)) { + free(insert); + return (struct parse_result) { .status = PARSE_OOM, }; + } + } + break; + } + case 2: { /* version */ + return (struct parse_result) { .status = PARSE_VERSION_REQUESTED, }; + } + case 3: /* colored headers */ + colors_auto = false; + if (!strcmp(optarg, "always")) + colors_force = true; + else if (!strcmp(optarg, "auto")) + colors_auto = true; + else if (!strcmp(optarg, "never")) + colors_force = false; + else + return (struct parse_result) { .status = PARSE_BAD_COLOR, .bad_contents = optarg, }; + break; + case 4: /* timestamp */ + if (!strcmp(optarg, "default")) + sort_by = DLOGUTIL_SORT_DEFAULT; + else { + sort_by = get_order_from_string(optarg); + if (sort_by == DLOGUTIL_SORT_DEFAULT) + return (struct parse_result) { .status = PARSE_BAD_SORT_BY, .bad_contents = optarg, }; + } + break; + case 'd': + mode = DLOGUTIL_MODE_DUMP; + break; + case 'm': + mode = DLOGUTIL_MODE_MONITOR; + break; + case 't': + mode = DLOGUTIL_MODE_DUMP; + if (sscanf(optarg, "%u", &dump_size) != 1) + return (struct parse_result) { .status = PARSE_OPTION_NUMERICAL_ARGUMENT, .which_option = "-t", }; + break; + case 'c': + action = ACTION_CLEAR; + break; + case 'g': + action = ACTION_GET_CAPACITY; + break; + case 'b': { + log_id_t id = log_id_by_name(optarg); + if (id == LOG_ID_INVALID) + return (struct parse_result) { .status = PARSE_BAD_BUFFER, .bad_contents = optarg, }; + bit_set(&enabled_buffers, id); + break; + } + case 'u': { + unsigned size; + if (sscanf(optarg, "%u", &size) != 1) + return (struct parse_result) { .status = PARSE_OPTION_NUMERICAL_ARGUMENT, .which_option = "-u", }; + if (size == 0) + sorting_settings = 0; + else + sorting_settings = size; + break; + } + case 'f': + file_path = optarg; + break; + case 'v': { + format = log_format_from_string(optarg); + if (format == FORMAT_OFF) + return (struct parse_result) { .status = PARSE_BAD_FORMAT, .bad_contents = optarg, }; + break; + } + case 's': + if (!list_add(&filterspecs, "*:S")) + return (struct parse_result) { .status = PARSE_OOM, }; + break; + case 'r': + if (sscanf(optarg, "%zu", &rotate_size_kbytes) != 1) + return (struct parse_result) { .status = PARSE_OPTION_NUMERICAL_ARGUMENT, .which_option = "-r", }; + break; + case 'n': + if (sscanf(optarg, "%zu", &max_rotated) != 1) + return (struct parse_result) { .status = PARSE_OPTION_NUMERICAL_ARGUMENT, .which_option = "-n", }; + break; + case 'e': { + if (buffer_made) + return (struct parse_result) { .status = PARSE_OPTION_REPEATED, .which_option = "-e", }; + if (sscanf(optarg, "%zu", &write_buffer_size) != 1) + return (struct parse_result) { .status = PARSE_OPTION_NUMERICAL_ARGUMENT, .which_option = "-e", }; + buffer_made = true; + break; + } + case 'h': + return (struct parse_result) { .status = PARSE_HELP_REQUESTED, }; + default: // invalid option or missing mandatory parameter + return (struct parse_result) { .status = PARSE_NO_PARSE, }; + } + } + + while (optind < argc) { + /* TODO: We don't want to call log_filter_set_filterspec/dlogutil_config_filter_filterspec here, + * as we want the option parser to be general. Unfortunately, this means that the user has to parse + * the filterspecs and not us. Any idea on how to make this nicer? */ + if (!list_add(&filterspecs, argv[optind++])) + return (struct parse_result) { .status = PARSE_OOM, }; + } + + if (!buffer_made && mode == DLOGUTIL_MODE_DUMP) + write_buffer_size = DEFAULT_WRITE_BUFFER_SIZE; + + struct parse_result ret = (struct parse_result) { + .status = PARSE_OK, + .colors_auto = colors_auto, + .colors_force = colors_force, + .format = format, + .rotate_size_kbytes = rotate_size_kbytes, + .max_rotated = max_rotated, + .file_path = file_path, + .write_buffer_size = write_buffer_size, + .enabled_buffers = enabled_buffers, + .action = action, + .filterspecs = filterspecs, + .pid_filters = pid_filters, + .tid_filters = tid_filters, + .sorting_settings = sorting_settings, + .mode = mode, + .dump_size = dump_size, + .sort_by = sort_by, + }; + filterspecs = NULL; + pid_filters = NULL; + tid_filters = NULL; + return ret; +}