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 || chunk_copy == NULL) {
97 if (result_tmp != NULL)
99 if (chunk_copy != NULL)
107 result[(*size)++] = chunk_copy;
108 chunk = strtok_r(NULL, " ", &tmpptr);
111 char **result_tmp = realloc(result, (*size + 1) * sizeof(char *));
112 if (result_tmp == NULL) {
120 result[*size] = NULL;
127 static void free_array(char **array)
130 for (size_t i = 0; array[i] != NULL; i++)
136 static char** build_argv_array(const char *path, int argc, char **argv)
138 char **av = malloc((argc + 2) * sizeof(char *));
144 av[0] = strdup(path);
151 for (int i = 0; i < argc; i++) {
152 av[i + 1] = strdup(argv[i]);
153 if (av[i + 1] == NULL) {
165 static char** prepare_dumpsys_args(const char *path, int dumpsys_argc, char **dumpsys_argv)
167 return build_argv_array(path, dumpsys_argc - 1, dumpsys_argv+1);
170 static char** prepare_config_args(const char *path, char *args)
173 char **argv = split(args, &argc);
177 char **result = build_argv_array(path, argc, argv);
182 static char** prepare_args(struct extra_dump_item *item, const int dumpsys_argc, char **dumpsys_argv)
184 bool allow_dumpsys_args = false;
185 if (item->fields[INI_FIELD_ALLOWDUMPSYSARGS] != NULL)
186 allow_dumpsys_args = strncasecmp(item->fields[INI_FIELD_ALLOWDUMPSYSARGS], "yes", 4) == 0;
188 if (allow_dumpsys_args && dumpsys_argc > 1)
189 return prepare_dumpsys_args(item->fields[INI_FIELD_PATH], dumpsys_argc, dumpsys_argv);
191 return prepare_config_args(item->fields[INI_FIELD_PATH], item->fields[INI_FIELD_ARGS]);
194 static char** prepare_env(const char *config_env)
198 if (config_env != NULL) {
200 ev = split(config_env, &size);
206 static int dump_item(int fd, struct extra_dump_item *item, const int dumpsys_argc, char **dumpsys_argv)
210 int result = TIZEN_ERROR_NONE;
212 char **av = prepare_args(item, dumpsys_argc, dumpsys_argv);
217 char **ev = prepare_env(item->fields[INI_FIELD_ENV]);
219 spawn_param_s param_stdout = { .fn = spawn_setstdout, .u.int_val = fd };
220 spawn_param_s param_stderr = { .fn = spawn_setstderr, .u.int_val = fd, .next = ¶m_stdout };
222 if (!spawn_wait(av, ev, ¶m_stderr, DEFAULT_COMMAND_TIMEOUT_MS, &err))
223 result = TIZEN_ERROR_INVALID_OPERATION;
232 static bool dumpsys_enabled(struct extra_dump_item *item)
236 return item->fields[INI_FIELD_DUMPSYSCMD] != NULL && *(item->fields[INI_FIELD_DUMPSYSCMD]) != '\0';
239 static void print_header(int fd, struct extra_dump_item *item)
243 "\n==== %s (%s %s)\n",
244 item->fields[INI_FIELD_TITLE] ?: "",
245 item->fields[INI_FIELD_PATH] ?: "",
246 item->fields[INI_FIELD_ARGS] ?: "");
249 static int dump_all_items(int fd)
251 int result = TIZEN_ERROR_NONE;
253 for (size_t i = 0; i < commands_list.size; i++) {
254 if (dumpsys_enabled(&commands_list.data[i])) {
255 print_header(fd, &commands_list.data[i]);
256 result |= dump_item(fd, &commands_list.data[i], 0, NULL);
263 static int dumpsys_cb(const int fd, const int argc, char **argv)
268 if (commands == NULL) {
269 _E("Commands not initialized");
270 return TIZEN_ERROR_INVALID_OPERATION;
273 int result = TIZEN_ERROR_NONE;
275 result = dump_all_items(fd);
277 struct extra_dump_item *item = g_hash_table_lookup(commands, argv[0]);
279 _E("Command not found: %s", argv[0]);
280 return TIZEN_ERROR_INVALID_PARAMETER;
282 result = dump_item(fd, item, argc, argv);
288 static void free_item(struct extra_dump_item *item)
292 for (size_t i = 0; i < ARRAY_SIZE(item->fields); i++)
293 free(item->fields[i]);
296 static int fill_commands()
298 int result = read_ini_files(STDOUT_FILENO, DUMP_SYSTEMSTATE_CONFIG_DIR_PROGRAMS_PATH, &commands_list);
300 if (result != EXIT_OK)
303 commands = g_hash_table_new(g_str_hash, g_str_equal);
304 if (commands == NULL) {
309 struct extra_dump_item *item = commands_list.data;
311 for (size_t i = 0; i < commands_list.size; i++, item++) {
312 char *dumpcmd = item->fields[INI_FIELD_DUMPSYSCMD];
314 if (dumpcmd != NULL && strlen(dumpcmd) > 0) {
315 if (g_hash_table_lookup(commands, dumpcmd) != NULL) {
316 _I("Duplicated command: %s", dumpcmd);
319 _D("New dumpsys command: %s", dumpcmd);
320 g_hash_table_insert(commands, dumpcmd, item);
330 void *handler = NULL;
331 int exit_code = EXIT_SUCCESS;
333 if (fill_commands() != EXIT_OK) {
334 exit_code = EXIT_FAILURE;
338 loop = g_main_loop_new(NULL, false);
340 if (dumpsys_system_register_dump_cb(dumpsys_cb, DUMP_SYSTEMSTATE_BUS_NAME, &handler) != TIZEN_ERROR_NONE) {
341 _E("Callback registration error");
342 exit_code = EXIT_FAILURE;
346 g_mutex_init(&timeout_mutex);
348 g_main_loop_run(loop);
350 g_mutex_clear(&timeout_mutex);
354 g_main_loop_unref(loop);
357 dumpsys_system_unregister_dump_cb(handler);
359 if (commands != NULL)
360 g_hash_table_destroy(commands);
362 for (size_t i = 0; i < commands_list.size; i++)
363 free_item(&commands_list.data[i]);