4 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 #include <dumpsys-system.h>
25 #include "dump_systemstate/dump_systemstate.h"
26 #include "dump_systemstate/extras.h"
27 #include "shared/log.h"
28 #include "shared/spawn.h"
29 #include "shared/util.h"
31 #define DUMP_SYSTEMSTATE_BUS_NAME "org.tizen.systemstate"
32 #define DUMP_SYSTEMSTATE_OBJECT_PATH "/Org/Tizen/Systemstate"
33 #define DUMP_SYSTEMSTATE_INTERFACE_NAME DUMP_SYSTEMSTATE_BUS_NAME
34 #define TIMEOUT_INTERVAL_SEC 30
36 static GMainLoop *loop = NULL;
37 static GMutex timeout_mutex;
38 static guint timeout_id;
39 static GHashTable *commands = NULL;
40 struct extra_items_vector commands_list = { .size = 0, .data = NULL };
42 static int timeout_cb(gpointer data)
46 g_main_loop_quit((GMainLoop *)data);
51 static void add_timeout(void)
53 g_mutex_lock(&timeout_mutex);
56 g_source_remove(timeout_id);
57 timeout_id = g_timeout_add_seconds(TIMEOUT_INTERVAL_SEC, timeout_cb, loop);
59 g_mutex_unlock(&timeout_mutex);
60 _D("Add loop timeout (%d)", TIMEOUT_INTERVAL_SEC);
63 static void remove_timeout(void)
65 g_mutex_lock(&timeout_mutex);
68 g_source_remove(timeout_id);
72 g_mutex_unlock(&timeout_mutex);
73 _D("Remove loop timeout");
76 char** split(const char *str, size_t *size)
81 char *str_tmp = strdup(str);
82 if (str_tmp == NULL) {
88 char *chunk = strtok_r(str_tmp, " ", &tmpptr);
91 while (chunk != NULL) {
92 char **result_tmp = realloc(result, (*size + 1) * sizeof(char *));
93 char *chunk_copy = strdup(chunk);
95 if (result_tmp == NULL) {
101 if (chunk_copy != NULL)
106 if (chunk_copy == NULL) {
114 result[(*size)++] = chunk_copy;
115 chunk = strtok_r(NULL, " ", &tmpptr);
118 char **result_tmp = realloc(result, (*size + 1) * sizeof(char *));
119 if (result_tmp == NULL) {
127 result[*size] = NULL;
134 static void free_array(char **array)
137 for (size_t i = 0; array[i] != NULL; i++)
143 static char** build_argv_array(const char *path, int argc, char **argv)
145 char **av = malloc((argc + 2) * sizeof(char *));
151 av[0] = strdup(path);
158 for (int i = 0; i < argc; i++) {
159 av[i + 1] = strdup(argv[i]);
160 if (av[i + 1] == NULL) {
172 static char** prepare_dumpsys_args(const char *path, int dumpsys_argc, char **dumpsys_argv)
174 return build_argv_array(path, dumpsys_argc - 1, dumpsys_argv+1);
177 static char** prepare_config_args(const char *path, char *args)
180 char **argv = split(args, &argc);
184 char **result = build_argv_array(path, argc, argv);
189 static char** prepare_args(struct extra_dump_item *item, const int dumpsys_argc, char **dumpsys_argv)
191 bool allow_dumpsys_args = false;
192 if (item->fields[INI_FIELD_ALLOWDUMPSYSARGS] != NULL)
193 allow_dumpsys_args = strncasecmp(item->fields[INI_FIELD_ALLOWDUMPSYSARGS], "yes", 4) == 0;
195 if (allow_dumpsys_args && dumpsys_argc > 1)
196 return prepare_dumpsys_args(item->fields[INI_FIELD_PATH], dumpsys_argc, dumpsys_argv);
198 return prepare_config_args(item->fields[INI_FIELD_PATH], item->fields[INI_FIELD_ARGS]);
201 static char** prepare_env(const char *config_env)
205 if (config_env != NULL) {
207 ev = split(config_env, &size);
213 static int dump_item(int fd, struct extra_dump_item *item, const int dumpsys_argc, char **dumpsys_argv)
217 int result = TIZEN_ERROR_NONE;
219 char **av = prepare_args(item, dumpsys_argc, dumpsys_argv);
224 char **ev = prepare_env(item->fields[INI_FIELD_ENV]);
226 spawn_param_s param_stdout = { .fn = spawn_setstdout, .u.int_val = fd };
227 spawn_param_s param_stderr = { .fn = spawn_setstderr, .u.int_val = fd, .next = ¶m_stdout };
229 if (!spawn_wait(av, ev, ¶m_stderr, DEFAULT_COMMAND_TIMEOUT_MS, &err))
230 result = TIZEN_ERROR_INVALID_OPERATION;
239 static bool dumpsys_enabled(struct extra_dump_item *item)
243 return item->fields[INI_FIELD_DUMPSYSCMD] != NULL && *(item->fields[INI_FIELD_DUMPSYSCMD]) != '\0';
246 static void print_header(int fd, struct extra_dump_item *item)
250 "\n==== %s (%s %s)\n",
251 item->fields[INI_FIELD_TITLE] ?: "",
252 item->fields[INI_FIELD_PATH] ?: "",
253 item->fields[INI_FIELD_ARGS] ?: "");
256 static int dump_all_items(int fd)
258 int result = TIZEN_ERROR_NONE;
260 for (size_t i = 0; i < commands_list.size; i++) {
261 if (dumpsys_enabled(&commands_list.data[i])) {
262 print_header(fd, &commands_list.data[i]);
263 result |= dump_item(fd, &commands_list.data[i], 0, NULL);
270 static int dumpsys_cb(const int fd, const int argc, char **argv)
275 if (commands == NULL) {
276 _E("Commands not initialized");
277 return TIZEN_ERROR_INVALID_OPERATION;
280 int result = TIZEN_ERROR_NONE;
282 result = dump_all_items(fd);
284 struct extra_dump_item *item = g_hash_table_lookup(commands, argv[0]);
286 _E("Command not found: %s", argv[0]);
287 return TIZEN_ERROR_INVALID_PARAMETER;
289 result = dump_item(fd, item, argc, argv);
295 static void free_item(struct extra_dump_item *item)
299 for (size_t i = 0; i < ARRAY_SIZE(item->fields); i++)
300 free(item->fields[i]);
303 static int fill_commands()
305 int result = read_ini_files(STDOUT_FILENO, DUMP_SYSTEMSTATE_CONFIG_DIR_PROGRAMS_PATH, &commands_list);
307 if (result != EXIT_OK)
310 commands = g_hash_table_new(g_str_hash, g_str_equal);
311 if (commands == NULL) {
316 struct extra_dump_item *item = commands_list.data;
318 for (size_t i = 0; i < commands_list.size; i++, item++) {
319 char *dumpcmd = item->fields[INI_FIELD_DUMPSYSCMD];
321 if (dumpcmd != NULL && strlen(dumpcmd) > 0) {
322 if (g_hash_table_lookup(commands, dumpcmd) != NULL) {
323 _I("Duplicated command: %s", dumpcmd);
326 _D("New dumpsys command: %s", dumpcmd);
327 g_hash_table_insert(commands, dumpcmd, item);
337 void *handler = NULL;
338 int exit_code = EXIT_SUCCESS;
340 if (fill_commands() != EXIT_OK) {
341 exit_code = EXIT_FAILURE;
345 loop = g_main_loop_new(NULL, false);
347 if (dumpsys_system_register_dump_cb(dumpsys_cb, DUMP_SYSTEMSTATE_BUS_NAME, &handler) != TIZEN_ERROR_NONE) {
348 _E("Callback registration error");
349 exit_code = EXIT_FAILURE;
353 g_mutex_init(&timeout_mutex);
355 g_main_loop_run(loop);
357 g_mutex_clear(&timeout_mutex);
361 g_main_loop_unref(loop);
364 dumpsys_system_unregister_dump_cb(handler);
366 if (commands != NULL)
367 g_hash_table_destroy(commands);
369 for (size_t i = 0; i < commands_list.size; i++)
370 free_item(&commands_list.data[i]);