d8280c2a613a80f2c898cba442c994450dddf5ca
[platform/core/system/dlog.git] / src / logger / dlogutil_line.c
1 #include "dlogutil_line.h"
2 #include "logger_internal.h"
3 #include <getopt.h>
4
5 void reset_getopt_internals(void *fake)
6 {
7         optarg = NULL;
8         optind = 0;
9         optopt = 0;
10 }
11
12 bool initialize_dlogutil_line_params(struct dlogutil_line_params *params)
13 {
14         assert(params);
15
16         logfile_init(&params->file);
17         params->monitor = false;
18         params->is_dumping = false;
19         params->buf_id = LOG_ID_INVALID;
20         params->file_path = NULL;
21
22         params->filter = log_filter_new();
23         if (!params->filter)
24                 return false;
25
26         return true;
27 }
28
29 void free_dlogutil_line_params(struct dlogutil_line_params *params)
30 {
31         logfile_free(&params->file);
32         log_filter_free(params->filter);
33         free(params->file_path);
34 }
35
36 static int make_argc_argv_from_dlogutil_line(const char *cmdl, size_t buf_size, char buffer[buf_size], int *argc, char **argv)
37 {
38         assert(cmdl);
39         assert(argc);
40         assert(argv);
41
42         snprintf(buffer, buf_size, "%s", cmdl); // strtok is destructive
43
44         char *tok_sv;
45         char *tok = strtok_r(buffer, DELIMITER, &tok_sv);
46
47         /* Legacy requirement: emulate `dlogutil`
48          * invocations right up to the binary name */
49         if (!tok || strcmp(tok, "dlogutil"))
50                 return -EINVAL;
51
52         int curr_argc = 0;
53         const int argv_size = *argc - 1; // for NULL at the end
54         while (tok && (curr_argc < argv_size)) {
55                 argv[curr_argc++] = tok;
56                 tok = strtok_r(NULL, DELIMITER, &tok_sv);
57         }
58
59         argv[curr_argc] = NULL;
60         *argc = curr_argc;
61
62         return 0;
63 }
64
65 static int get_dlogutil_params_from_argc_argv(int argc, char **argv, struct dlogutil_line_params *params)
66 {
67         assert(argc >= 0);
68         assert(argv);
69         assert(params);
70
71         bool silence = false;
72
73         static const struct option long_options[] = {
74                 {"tid", required_argument, NULL, 0},
75                 {"pid", required_argument, NULL, 1},
76                 {0}
77         };
78
79         __attribute__((cleanup(reset_getopt_internals))) int option;
80         while ((option = getopt_long(argc, argv, "cdt:gsf:r:n:v:b:mu:", long_options, NULL)) != -1) {
81                 switch (option) {
82                         break;
83                 case 'd':
84                 case 't':
85                         params->is_dumping = true;
86                         break;
87                 case 'm':
88                         params->monitor = true;
89                         break;
90                 case 'f':
91                         free(params->file_path);
92                         params->file_path = strdup(optarg);
93                         if (!params->file_path)
94                                 return -ENOMEM;
95                         break;
96                 case 'b':
97                         params->buf_id = log_id_by_name(optarg);
98                         if (params->buf_id == LOG_ID_INVALID)
99                                 return -EINVAL;
100                         break;
101                 case 'r':
102                         if (sscanf(optarg, "%zu", &params->file.rotate_size_kbytes) != 1)
103                                 return -EINVAL;
104                         break;
105                 case 'n':
106                         if (sscanf(optarg, "%zu", &params->file.max_rotated) != 1)
107                                 return -EINVAL;
108                         break;
109                 case 'v':
110                         params->file.format.format = log_format_from_string(optarg);
111                         break;
112                 case 's':
113                         silence = true;
114                         dlogutil_filter_options_set_filterspec(params->filter, "*:s");
115                         break;
116                 case 0: {
117                         pid_t tid;
118                         if (sscanf(optarg, "%d", &tid) != 1 || dlogutil_filter_options_set_tid(params->filter, tid))
119                                 return -EINVAL;
120                         break;
121                 }
122                 case 1: {
123                         pid_t pid;
124                         if (sscanf(optarg, "%d", &pid) != 1 || dlogutil_filter_options_set_pid(params->filter, pid))
125                                 return -EINVAL;
126                         break;
127                 }
128                 case '?': // invalid option or missing argument
129                         return -EINVAL;
130                 default:
131                         // everything else gets handled in util directly
132                         break;
133                 }
134         }
135
136         // dump + monitor = continuous
137         if (params->monitor && params->is_dumping) {
138                 params->is_dumping = false;
139                 params->monitor = false;
140         }
141
142         if (optind < argc)
143                 while (optind < argc)
144                         dlogutil_filter_options_set_filterspec(params->filter, argv[optind++]);
145         else if (!silence)
146                 dlogutil_filter_options_set_filterspec(params->filter, "*:D");
147
148         return 0;
149 }
150
151 int get_dlogutil_line_params(const char *cmdl, struct dlogutil_line_params *params)
152 {
153         assert(params);
154         assert(cmdl);
155         char buffer[1024];
156         char *argv[64]; // size arbitrary, should reasonably fit all args
157         int argc = NELEMS(argv);
158         int ret = make_argc_argv_from_dlogutil_line(cmdl, sizeof buffer, buffer, &argc, argv);
159         if (ret < 0)
160                 return ret;
161
162         return get_dlogutil_params_from_argc_argv(argc, argv, params);
163 }
164