so-info.c
dbus_notify.c
${CMAKE_SOURCE_DIR}/src/shared/util.c
+ ${CMAKE_SOURCE_DIR}/src/shared/spawn.c
)
INCLUDE(FindPkgConfig)
#include "so-info.h"
#include "shared/log.h"
#include "shared/util.h"
+#include "shared/spawn.h"
#include "dbus_notify.h"
#undef LOG_TAG
g_object_unref(conn);
}
-static int dump_system_state(const struct crash_info *cinfo)
+static pid_t dump_system_state(const struct crash_info *cinfo)
{
- int ret;
- char command[PATH_MAX];
-
- ret = snprintf(command, sizeof(command),
- "/usr/bin/dump_systemstate -d -k -j -f %s",
- cinfo->log_path);
- if (ret < 0) {
- _E("Failed to snprintf for dump_systemstate command");
- return -1;
- }
+ char *av[] = {"/usr/bin/dump_systemstate", "-d", "-k", "-j", cinfo->log_path, NULL};
- return system_command_parallel(command);
+ pid_t pid;
+ int r = spawn(av, NULL, NULL, NULL, 0, &pid);
+ return r == 0 ? pid : r;
}
static void copy_maps(const struct crash_info *cinfo)
NULL
};
- _D(" %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
- args[0], args[1], args[2], args[3],
- args[4], args[5], args[6], args[7],
- args[8], args[9], args[10], args[11],
- args[12], args[13], args[14]);
-
- run_command_timeout(args[0], args, NULL, MINICOREDUMPER_TIMEOUT);
+ spawn_wait(args, NULL, NULL, NULL, MINICOREDUMPER_TIMEOUT);
ret = 0;
/* Minicoredumper must be executed to dump at least PRSTATUS for
NULL
};
- _D(" %s %s %s %s %s %s %s %s %s",
- args[0], args[1], args[2], args[3],
- args[4], args[5], args[6], args[7], args[8]);
-
fd = open(cinfo->info_path, O_WRONLY | O_CREAT, 0600);
if (fd < 0) {
_E("open %s error: %m", cinfo->info_path);
goto out;
}
- ret = run_command_write_fd_timeout(CRASH_STACK_PATH, args, NULL, fd, NULL, 0, CRASH_STACK_TIMEOUT);
-
+ ret = spawn_wait(args, NULL, spawn_setstdout, (void *)fd, CRASH_STACK_TIMEOUT);
out:
if (fd >= 0)
close(fd);
{
int ret, lock_fd;
char zip_path[PATH_MAX];
- char cwd[PATH_MAX];
ret = snprintf(zip_path, sizeof(zip_path), "%s/report.zip",
cinfo->temp_dir);
return;
}
- if (getcwd(cwd, sizeof(cwd)) == NULL) {
- _E("getcwd() error: %m\n");
- return;
- }
-
- if (chdir(cinfo->temp_dir) == -1) {
- _E("chdir() to %s error: %m\n", cinfo->temp_dir);
- return;
- }
-
char *args[] = {
"/bin/zip",
"-y",
NULL
};
- run_command_timeout(args[0], args, NULL, ZIP_TIMEOUT);
-
- if (chdir(cwd) == -1) {
- _E("chdir() to %s error: %m\n", cwd);
- return;
- }
+ (void)spawn_wait(args, NULL, spawn_chdir, (void *)cinfo->temp_dir, 0);
if ((lock_fd = lock_dumpdir()) < 0)
return;
struct crash_info cinfo = {0};
/* Execute dump_systemstate in parallel */
- static int dump_state_pid;
+ static pid_t dump_state_pid;
int debug_mode = access(DEBUGMODE_PATH, F_OK) == 0;
int res = 0;
remove_maps(&cinfo);
/* Wait dump_system_state */
- wait_system_command(dump_state_pid);
+ wait_for_pid(dump_state_pid);
/* Tar compression */
if (allow_zip)
SET(SRCS
dump_systemstate.c
${CMAKE_SOURCE_DIR}/src/shared/util.c
+ ${CMAKE_SOURCE_DIR}/src/shared/spawn.c
)
INCLUDE(FindPkgConfig)
#include "shared/util.h"
#include "shared/log.h"
+#include "shared/spawn.h"
#define FILE_PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
-#define TIMEOUT_DEFAULT 60
+#define TIMEOUT_DEFAULT_MS 60*1000 /* 60sec */
static struct dump_path {
const char *title;
dprintf(out_fd, " %s", commands[i].av[j]);
dprintf(out_fd, ")\n");
}
- int ret = run_command_write_fd_timeout(commands[i].av[0], commands[i].av, ev, out_fd, NULL, 0, TIMEOUT_DEFAULT);
- if (ret < 0)
+ int ret = spawn_wait(commands[i].av, ev, spawn_setstdout, (void *)out_fd, TIMEOUT_DEFAULT_MS);
+ if (ret != 0)
break;
}
log_dump.c
dbus-handler.c
${CMAKE_SOURCE_DIR}/src/shared/util.c
+ ${CMAKE_SOURCE_DIR}/src/shared/spawn.c
)
INCLUDE(FindPkgConfig)
SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
ENDFOREACH(flag)
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE -D_GNU_SOURCE=1")
CONFIGURE_FILE(log_dump.h.in log_dump.h @ONLY)
ADD_EXECUTABLE(${PROJECT_NAME} ${LOG_DUMP_SRCS})
#include <libgen.h>
#include <system_info.h>
#include "shared/util.h"
-#include "log_dump.h"
+#include "shared/spawn.h"
#include "dbus-handler.h"
+#include <tzplatform_config.h>
+#include "log_dump.h"
-#undef LOG_TAG
-#define LOG_TAG "LOG_DUMP"
#define SYSTEM_INFO_KEY_BUILD_STRING "http://tizen.org/system/build.string"
static const struct option opts[] = {
{ 0, 0, 0, 0 }
};
+/* tzplaform vars */
+char *log_dump_dir;
+char *log_dump_result;
+char *log_dump_root;
+char *dump_scripts_dir;
+/* compile time vars */
+char *crash_dump_dir = CRASH_DUMP_DIR;
+char *crash_temp_dir = CRASH_TEMP_DIR;
+
+static int init_vars(void)
+{
+ log_dump_dir = strdup(tzplatform_getenv(TZ_SYS_ALLLOGS));
+ log_dump_result = strdup(tzplatform_mkpath(TZ_SYS_CRASH_ROOT, "debug"));
+ log_dump_root = strdup(tzplatform_getenv(TZ_SYS_CRASH_ROOT));
+ dump_scripts_dir = strdup(tzplatform_getenv(TZ_SYS_DUMPGEN));
+
+ crash_dump_dir = strdup(CRASH_DUMP_DIR);
+ crash_temp_dir = strdup(CRASH_TEMP_DIR);
+
+ return log_dump_dir && log_dump_result && log_dump_root && dump_scripts_dir
+ && crash_dump_dir && crash_temp_dir;
+}
+
static inline void usage(void)
{
printf("Usage: log_dump [OPTION]\n");
printf("Dump options:\n");
printf(" %-10s %s (%s)\n", "--normal",
- "dump all logs", DUMP_SCRIPTS_DIR);
+ "dump all logs", dump_scripts_dir);
printf(" %-10s %s\n", "--short",
"dump systemstate only");
printf(" %-10s %s\n", "--dbus",
char command[PATH_MAX];
int script_num, i;
- script_num = scandir(DUMP_SCRIPTS_DIR, &dir_list, NULL, NULL);
+ script_num = scandir(dump_scripts_dir, &dir_list, NULL, NULL);
if (script_num < 0) {
- _E("Failed to scandir %s", DUMP_SCRIPTS_DIR);
+ _E("Failed to scandir %s", dump_scripts_dir);
return -1;
}
if (dir_list[i]->d_type != DT_REG)
continue;
- snprintf(command, sizeof(command), "%s/%s %s",
- DUMP_SCRIPTS_DIR, dir_list[i]->d_name,
- LOG_DUMP_DIR);
- _D("%s", command);
- system_command(command);
+ snprintf(command, sizeof(command), "%s/%s",
+ dump_scripts_dir, dir_list[i]->d_name);
+
+ char *av[] = {command, log_dump_dir, NULL};
+ (void)spawn_wait(av, NULL, NULL, NULL, 0);
}
for (i = 0; i < script_num; i++)
return 0;
}
+static int compress_prep(void *userdata)
+{
+ return spawn_nullifyfds(0) && spawn_chdir(userdata);
+}
+
+static int dump_systemstate(const char *timestr)
+{
+ char *dump_path = NULL;
+
+ if (asprintf(&dump_path, "%s/dump_systemstate_%s.log", log_dump_dir, timestr) < 0)
+ return -1;
+
+ char *av[] = {"/usr/bin/dump_systemstate", "-k", "-d", "-j", "-f", dump_path};
+ (void)spawn_wait(av, NULL, NULL, NULL, 0);
+
+ free(dump_path);
+
+ return 0;
+}
+
+static int mkdir_p(char *const path)
+{
+ if (access(path, F_OK) != 0) {
+ char *av[] = {"/bin/mkdir", "-p", path};
+ if (spawn_wait(av, NULL, NULL, NULL, 0) != 0) {
+ _E("Failed to mkdir -p %s", path);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int compress(const char *timestr, int option)
+{
+ char *dump_path = NULL;
+ char *version_str = NULL;
+
+ int r = system_info_get_platform_string(SYSTEM_INFO_KEY_BUILD_STRING, &version_str);
+ if (r != SYSTEM_INFO_ERROR_NONE) {
+ _E("Failed to system_info_get_platform_string");
+ version_str = NULL;
+ r = asprintf(&dump_path, "%s/log_dump_%s%s.zip", log_dump_result, version_str, timestr);
+ } else
+ r = asprintf(&dump_path, "%s/log_dump%s.zip", log_dump_result, timestr);
+ if (r < 0)
+ goto out;
+
+
+ if (option == OPT_NORMAL) {
+ char *av[] = {"/bin/zip", "-r", dump_path, basename(log_dump_dir), NULL};
+ r = spawn_wait(av, NULL, compress_prep, (void*)log_dump_root, 0);
+ } else {
+ char *av[] = {"/bin/zip", "-r", dump_path, basename(log_dump_dir), basename(crash_dump_dir), NULL};
+ r = spawn_wait(av, NULL, compress_prep, (void*)log_dump_root, 0);
+ }
+ r = 0;
+out:
+ return r;
+}
+
int log_dump(int option)
{
int ret;
- char *version_str = NULL;
- char *dump_dirname = NULL;
- char *crash_dirname = NULL;
char timestr[80];
- char command[PATH_MAX];
- char dump_filename[NAME_MAX];
time_t cur_time;
struct tm loc_tm;
broadcast_logdump_start();
- /* Make debug directory */
- if (access(LOG_DUMP_DIR, F_OK) != 0) {
- ret = snprintf(command, sizeof(command),
- "/usr/bin/mkdir -p %s", LOG_DUMP_DIR);
- if (ret < 0) {
- _E("Failed to mkdir");
- return -1;
- }
- system_command(command);
- }
+ char *dirs[] = {log_dump_dir, log_dump_result};
- /* Make result directory */
- if (access(LOG_DUMP_RESULT, F_OK) != 0) {
- ret = snprintf(command, sizeof(command),
- "/usr/bin/mkdir -p %s", LOG_DUMP_RESULT);
- if (ret < 0) {
- _E("Failed to mkdir");
- return -1;
- }
- system_command(command);
+ for (int i = 0; i < ARRAY_SIZE(dirs); i++) {
+ int ret = mkdir_p(dirs[i]) < 0;
+ if (ret < 0)
+ return ret;
}
/* Get timestamp */
localtime_r(&cur_time, &loc_tm);
strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S", &loc_tm);
- /* Get version */
- ret = system_info_get_platform_string(SYSTEM_INFO_KEY_BUILD_STRING,
- &version_str);
- if (ret != SYSTEM_INFO_ERROR_NONE) {
- _E("Failed to system_info_get_platform_string");
- version_str = NULL;
- }
-
- /* Dump system states */
- ret = snprintf(command, sizeof(command),
- "/usr/bin/dump_systemstate -k -d -j -f "
- "%s/dump_systemstate_%s.log", LOG_DUMP_DIR, timestr);
- if (ret < 0) {
- _E("Failed to snprintf for command");
- goto exit;
- }
- system_command(command);
+ ret = dump_systemstate(timestr);
+ if (ret < 0)
+ return ret;
/* Dump all logs */
if (option == OPT_NORMAL)
dump_scripts();
- if (version_str) {
- ret = snprintf(dump_filename, sizeof(dump_filename), "%s_%s",
- "log_dump", version_str);
- if (ret < 0) {
- _E("Failed to snprintf for dump path");
- goto exit;
- }
- } else {
- ret = snprintf(dump_filename, sizeof(dump_filename), "%s",
- "log_dump");
- if (ret < 0) {
- _E("Failed to snprintf for dump path");
- return -1;
- }
- }
-
- /* Compression */
- dump_dirname = strdup(LOG_DUMP_DIR);
- if (!dump_dirname) {
- _E("Failed to strdup for dump_dirname");
- goto exit;
- }
-
- if (option == OPT_NORMAL) {
- crash_dirname = strdup(CRASH_DUMP_DIR);
- if (!crash_dirname) {
- _E("Failed to strdup for dump_dirname");
- goto exit;
- }
-
- ret = snprintf(command, sizeof(command),
- "cd %s && /bin/zip -r %s/%s%s.zip %s %s > /dev/null 2>&1",
- LOG_DUMP_ROOT,
- LOG_DUMP_RESULT, dump_filename, timestr,
- basename(dump_dirname), basename(crash_dirname));
- if (ret < 0) {
- _E("Failed to snprintf for command");
- goto exit;
- }
- } else {
- ret = snprintf(command, sizeof(command),
- "cd %s && /bin/zip -r %s/%s%s.zip %s > /dev/null 2>&1",
- LOG_DUMP_ROOT,
- LOG_DUMP_RESULT, dump_filename, timestr,
- basename(dump_dirname));
- if (ret < 0) {
- _E("Failed to snprintf for command");
- goto exit;
- }
- }
- system_command(command);
+ compress(timestr, option);
sync();
/* Remove gatherd dump */
- ret = remove_dir(LOG_DUMP_DIR, 0);
+ ret = remove_dir(log_dump_dir, 0);
if (ret < 0) {
_E("Failed to delete dump directory");
- goto exit;
+ return ret;
}
if (option == OPT_NORMAL) {
- ret = remove_dir(CRASH_DUMP_DIR, 0);
+ ret = remove_dir(crash_dump_dir, 0);
if (ret < 0) {
_E("Failed to delete crash dump directory");
- goto exit;
+ return ret;
}
}
broadcast_logdump_finish();
- /* Further operations for log_dump here */
-
-exit:
- if (version_str)
- free(version_str);
- if (dump_dirname)
- free(dump_dirname);
- if (crash_dirname)
- free(crash_dirname);
-
return ret;
}
{
_I("delete_dump!");
- remove_dir(LOG_DUMP_DIR, 0);
- remove_dir(LOG_DUMP_RESULT, 1);
- remove_dir(CRASH_DUMP_DIR, 0);
- remove_dir(CRASH_TEMP_DIR, 0);
+ remove_dir(log_dump_dir, 0);
+ remove_dir(log_dump_result, 1);
+ remove_dir(crash_dump_dir, 0);
+ remove_dir(crash_temp_dir, 0);
return 0;
}
}
}
+ if (!init_vars())
+ exit(EXIT_FAILURE);
+
if (option == OPT_DBUS)
ret = log_dump_dbus();
else
/*
* log_dump
*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016, 2018 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
#ifndef __LOGDUMP_H__
#define __LOGDUMP_H__
-#include <tzplatform_config.h>
-#include "shared/log.h"
-#undef LOG_TAG
#define LOG_TAG "LOG_DUMP"
-
-#define LOG_DUMP_ROOT tzplatform_getenv(TZ_SYS_CRASH_ROOT)
-#define LOG_DUMP_DIR tzplatform_getenv(TZ_SYS_ALLLOGS)
-#define LOG_DUMP_RESULT tzplatform_mkpath(TZ_SYS_CRASH_ROOT, "debug")
-#define CRASH_DUMP_DIR "@CRASH_PATH@"
-#define CRASH_TEMP_DIR "@CRASH_TEMP@"
-#define DUMP_SCRIPTS_DIR tzplatform_getenv(TZ_SYS_DUMPGEN)
+#include "shared/log.h"
enum {
OPT_NORMAL,
OPT_DBUS,
};
+#define CRASH_DUMP_DIR "@CRASH_PATH@"
+#define CRASH_TEMP_DIR "@CRASH_TEMP@"
+
int log_dump(int option);
int delete_dump(void);
--- /dev/null
+/*
+ * crash-manager
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <wait.h>
+#include <poll.h>
+
+#include "shared/log.h"
+
+typedef int (*spawn_prepare_fn)(void *);
+
+/* spawn prepare function(s) */
+int spawn_nullifyfds(void *const userdata) {
+ int fd = open("/dev/null", O_RDWR);
+ return (fd < 0 || dup2(fd, STDIN_FILENO) < 0 || dup2(fd, STDOUT_FILENO) < 0 || dup2(fd, STDERR_FILENO) < 0) ? -1 : 0;
+}
+
+int spawn_setstdout(void *const userdata) {
+ int fd = (int)userdata;
+ return dup2(fd, STDOUT_FILENO) < 0 ? -1 : 0;
+}
+
+int spawn_chdir(void *const userdata) {
+ return chdir((char *const)userdata) < 0 ? -1 : 0;
+}
+
+int wait_for_pid(pid_t pid)
+{
+ int status = 0;
+ int r = 0;
+
+ if (pid < 0)
+ return -1;
+
+ do {
+ if (waitpid(pid, &status, 0) == -1) {
+ if (errno != EINTR)
+ return -1;
+ } else {
+ if (WIFEXITED(status))
+ r = WEXITSTATUS(status);
+ else if (WIFSIGNALED(status))
+ r = WTERMSIG(status);
+ else if (WIFSTOPPED(status))
+ r = WSTOPSIG(status);
+ goto out;
+ }
+ } while (!WIFEXITED(status) && !WIFSIGNALED(status));
+
+out:
+ _I("Child with pid %d termitated with exit code %d", pid, r);
+ return r;
+}
+
+static int __spawn_child(char *const av[], char *const ev[], spawn_prepare_fn prep, void *prepdata)
+{
+ static const int spawn_error = 127;
+
+
+ int r = prep ? prep(prepdata) : 0;
+
+ if (r < 0)
+ return spawn_error;
+
+ execve(av[0], av, ev);
+ return spawn_error;
+}
+
+static char *nullvec2ptr(char *const vec[])
+{
+ char command[PATH_MAX] = {0, };
+
+ for (char *const *p = vec; *p; ++p) {
+ strncat(command, *p, sizeof(command)-1);
+ strncat(command, " ", sizeof(command)-1);
+ }
+ command[PATH_MAX-1] = 0;
+ return strdup(command);
+}
+
+int spawn(char *const av[], char *const ev[], spawn_prepare_fn prep, void *prepdata, int timeout_ms, pid_t *childpid)
+{
+ int pipefd[2];
+ if (pipe(pipefd) < 0)
+ return -1;
+
+ pid_t pid = fork();
+ if (pid < 0) {
+ return -1;
+ } else if (pid == 0) {
+ close(pipefd[0]);
+ _exit(__spawn_child(av, ev, prep, prepdata));
+ }
+ close(pipefd[1]);
+
+ char *cmd = nullvec2ptr(av);
+ _I("Spawned child with pid %d to execute command: %s", pid, cmd);
+ free(cmd);
+
+ /* parent */
+ if (childpid)
+ *childpid = pid;
+
+ if (timeout_ms) {
+ struct pollfd pfd[1] = {
+ { .fd = pipefd[0], .events = POLLIN | POLLERR | POLLHUP },
+ };
+ int r = poll(pfd, 1, timeout_ms);
+ if (r == 0) {
+ _E("Timeout %dms for child pid %d expired. Killing.", timeout_ms, pid);
+ kill(pid, SIGKILL);
+ }
+ }
+
+ close(pipefd[0]);
+
+ return 0;
+}
+
+int spawn_wait(char *const av[], char *const ev[], spawn_prepare_fn prep, void *prepdata, int timeout_ms)
+{
+ pid_t child;
+
+ return spawn(av, ev, prep, prepdata, timeout_ms, &child) == 0 ? wait_for_pid(child) : -1;
+}
--- /dev/null
+/*
+ * crash-manager
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __SPAWN_H__
+#define __SPAWN_H__
+
+typedef int (*spawn_prepare_fn)(void *);
+
+int spawn_nullifyfds(void *const userdata);
+int spawn_setstdout(void *const userdata);
+int spawn_chdir(void *const userdata);
+
+int wait_for_pid(int pid);
+int spawn(char *const av[], char *const ev[], spawn_prepare_fn prep, void *prepdata, int timeout_ms, pid_t *childpid);
+int spawn_wait(char *const av[], char *const ev[], spawn_prepare_fn prep, void *prepdata, int timeout_ms);
+
+#endif
#include "util.h"
#include "log.h"
-#define READ_BUFF_SIZE 4096
-#define SELECT_TIMEOUT_US 100000
-
-int system_command_parallel(char *command)
-{
- int pid = 0;
- const char *environ[] = { NULL };
-
- if (command == NULL)
- return -1;
- pid = fork();
- if (pid == -1)
- return -1;
- if (pid == 0) {
- char *argv[4];
- argv[0] = "sh";
- argv[1] = "-c";
- argv[2] = (char *)command;
- argv[3] = 0;
- execve("/bin/sh", argv, (char **)environ);
- exit(127);
- }
-
- return pid;
-}
-
-int wait_system_command(int pid)
-{
- int status = 0;
-
- if (pid < 0)
- return -1;
-
- do {
- if (waitpid(pid, &status, 0) == -1) {
- if (errno != EINTR)
- return -1;
- } else {
- if (WIFEXITED(status))
- return WEXITSTATUS(status);
- else if (WIFSIGNALED(status))
- return WTERMSIG(status);
- else if (WIFSTOPPED(status))
- return WSTOPSIG(status);
- }
- } while (!WIFEXITED(status) && !WIFSIGNALED(status));
-
- return 0;
-}
-
-int system_command(char *command)
-{
- int pid = 0;
-
- pid = system_command_parallel(command);
-
- return wait_system_command(pid);
-}
-
-int system_command_with_timeout(int timeout_seconds, char *command)
-{
- const char *environ[] = { NULL };
-
- if (command == NULL)
- return -1;
- clock_t start = clock();
- pid_t pid = fork();
- /* handle error case */
- if (pid < 0) {
- _E("fork: %d\n", errno);
- return pid;
- }
- /* handle child case */
- if (pid == 0) {
- char *argv[4];
- argv[0] = "sh";
- argv[1] = "-c";
- argv[2] = (char *)command;
- argv[3] = 0;
-
- execve("/bin/sh", argv, (char **)environ);
- _SI("exec(%s): %d\n", command, errno);
- _exit(-1);
- }
- /* handle parent case */
- for (;;) {
- int status;
- pid_t p = waitpid(pid, &status, WNOHANG);
- float elapsed = (float) (clock() - start) / CLOCKS_PER_SEC;
- if (p == pid) {
- if (WIFSIGNALED(status))
- _SI("%s: Killed by signal %d\n", command, WTERMSIG(status));
- else if (WIFEXITED(status) && WEXITSTATUS(status) > 0)
- _SI("%s: Exit code %d\n", command, WEXITSTATUS(status));
- return WEXITSTATUS(status);
- }
- if (timeout_seconds && elapsed > timeout_seconds) {
- _SI("%s: Timed out after %.1fs (killing pid %d)\n",
- command, elapsed, pid);
- kill(pid, SIGTERM);
- return -1;
- }
- /* poll every 0.1 sec */
- usleep(100000);
- }
-}
-
int file_exist(const char *file)
{
FILE *fp;
return res;
}
-static int run_command(char *path, char *args[], char *env[], int fd[])
-{
- if (dup2(fd[1], STDOUT_FILENO) == -1) {
- _E("dup2 error: %m");
- return -1;
- }
-
- if (close(fd[1]) == -1) {
- _E("close fd error: %m");
- return -1;
- }
-
- if (close(fd[0]) == -1) {
- _E("close fd error: %m");
- return -1;
- }
-
- if (execvpe(path, args, env) == -1) {
- _E("run command %s error: %m", path);
- return -1;
- }
- return -1;
-}
-
-static int wait_for_child(pid_t pid, int *exit_code, int timeout)
-{
- for (int i = 0; i < 10*timeout; i++) {
- int status;
- pid_t p = waitpid(pid, &status, WNOHANG);
- if (p == pid) {
- if (WIFSIGNALED(status)) {
- _I("Killed by signal %d\n", WTERMSIG(status));
- return -1;
- } else if (WIFEXITED(status)) {
- *exit_code = WEXITSTATUS(status);
- return 0;
- }
- } else if (p == -1) {
- _E("waitpid error: %m");
- return -1;
- }
- usleep(100000);
- }
- return -1;
-}
-
-static int read_into_buff(int fd, char *buff, int size, int timeout_us, int *eof)
-{
- struct timeval tout;
- int sel_ret;
- fd_set set;
-
- FD_ZERO(&set);
- FD_SET(fd, &set);
-
- tout.tv_sec = timeout_us / 1000000;
- tout.tv_usec = timeout_us % 1000000;
- *eof = 0;
-
- int buff_pos = 0;
- if ((sel_ret = select(fd+1, &set, NULL, NULL, &tout)) >= 0) {
- if (sel_ret > 0) {
- // we can do nonblocking read
- int readed = read(fd, &buff[buff_pos], size);
-
- if (readed > 0) {
- buff_pos += readed;
- size -= readed;
- } else if (readed == 0) {
- // no more data to read
- *eof = 1;
- } else {
- // error
- _E("read data from the pipe error: %m");
- return -1;
- }
- }
- } else
- _E("select() error: %m");
- return buff_pos;
-}
-
-// Usage:
-// if buff is not NULL then 'size' bytes of the result is written the buffer,
-// otherwise result is written to the dfd descriptor
-int run_command_write_fd_timeout(char *path, char *args[], char *env[], int dfd, char *buff, int size, int timeout)
-{
- char BUFF[READ_BUFF_SIZE];
- int fd[2];
- struct timeval start, end;
- int write_to_fd = buff == NULL ? 1 : 0;
-
- if (!write_to_fd && size <= 0) {
- _E("buffer size must be greather than zero");
- return -1;
- }
-
- if (pipe(fd)) {
- _E("pipe create error: %m");
- return -1;
- }
-
- pid_t pid = fork();
-
- if (pid == 0) {
- return run_command(path, args, env, fd);
- } else if (pid > 0) {
- if (close(fd[1]) == -1) {
- _E("close fd error: %m");
- return -1;
- }
-
- if (gettimeofday(&start, NULL) == -1) {
- _E("gettimeofday error: %m");
- return -1;
- }
-
- int readed;
- int eof = 0;
- int outdated = 0;
- int count = 0;
-
- int act_size;
- char *act_buff;
-
- if (write_to_fd) {
- act_size = READ_BUFF_SIZE;
- act_buff = BUFF;
- } else {
- act_size = size;
- act_buff = buff;
- }
-
- while ((readed = read_into_buff(fd[0], act_buff, act_size, 1000000, &eof)) >= 0) {
- if (readed > 0) {
- // we have some data
- if (count < (INT_MAX - readed))
- count += readed;
- else
- count = INT_MAX;
-
- if (write_to_fd) {
- if (write_fd(dfd, act_buff, readed) == -1) {
- _E("write data to pipe error: %m");
- break;
- }
- } else {
- act_buff += readed;
- act_size -= readed;
-
- if (act_size == 0) {
- // buff is full, we can return
- eof = 1;
- }
- }
- }
-
- if (eof)
- break;
-
- if (gettimeofday(&end, NULL) == -1) {
- _E("gettimeofday error: %m");
- break;
- }
-
- if ((end.tv_sec - start.tv_sec) > timeout) {
- outdated = 1;
- break;
- }
-
- if (readed == 0)
- usleep(100000);
- }
-
- if (outdated) {
- _E("command timeout: %s", path);
- if (kill(pid, 0) == 0) {
- // we can kill a child because we don't
- // need it anymore
- if (kill(pid, SIGTERM) == -1)
- _E("kill child %d error: %m", pid);
- }
- }
-
- if (close(fd[0]) == -1) {
- _E("close fd error: %m");
- return -1;
- }
-
- // let's wait a second for a child
- int exit_code = -1;
- int wait_res = wait_for_child(pid, &exit_code, 1);
-
- if (wait_res != 0)
- _I("wait_for_child for \%s\" returns non-zero value\n", path);
- else if (exit_code != 0)
- _I("\"%s\" exit code: %d\n", path, exit_code);
-
- return (eof == 1 && exit_code == 0) ? count : -abs(exit_code);
- } else {
- _E("fork() error: %m");
- return -1;
- }
-
- return -1;
-}
-
-int run_command_timeout(char *path, char *args[], char *env[], int timeout)
-{
- int fd = open("/dev/null", O_WRONLY);
- if (fd < 0) {
- _E("open /dev/null error: %m");
- return -1;
- }
-
- int res = run_command_write_fd_timeout(path, args, env, fd, NULL, 0, timeout);
-
- close(fd);
-
- return res;
-}
-
static int remove_dir_internal(int fd)
{
DIR *dir;
#define __CONSTRUCTOR__ __attribute__ ((constructor))
#endif
-int system_command(char *command);
-
-int system_command_with_timeout(int timeout_seconds, char *command);
-
-int system_command_parallel(char *command);
-
-int wait_system_command(int pid);
-
#define fprintf_fd(fd, fmt, ...) dprintf(fd, fmt, ##__VA_ARGS__)
int write_fd(int fd, const void *buf, int len);
int dump_file_write_fd(char *src, int dfd);
-int run_command_write_fd_timeout(char *path, char *args[], char *env[], int dfd, char *buff, int size, int timeout);
-
-int run_command_timeout(char *path, char *args[], char *env[], int timeout);
-
int remove_dir(const char *path, int del_dir);
int get_exec_pid(const char *execpath);