diff options
Diffstat (limited to 'crash-worker/util.c')
-rw-r--r-- | crash-worker/util.c | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/crash-worker/util.c b/crash-worker/util.c new file mode 100644 index 0000000..2b00a99 --- /dev/null +++ b/crash-worker/util.c @@ -0,0 +1,299 @@ +/* + * CRASH-WORKER + * Copyright (c) 2012-2013 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. + */ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <fcntl.h> +#include <stdarg.h> +#include <unistd.h> +#include <limits.h> +#include <string.h> +#include <signal.h> +#include <time.h> +#include <errno.h> +#include <wait.h> +#include "util.h" + +int system_command(char *command) +{ + int pid = 0, + status = 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); + } + do { + if (waitpid(pid, &status, 0) == -1) { + if (errno != EINTR) + return -1; + } else { + return status; + } + } while (1); + + return status; +} +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) { + LOGERR("fork: %s\n", strerror(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); + LOGINFO("exec(%s): %s\n", command, strerror(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)) + LOGINFO("%s: Killed by signal %d\n", command, WTERMSIG(status)); + else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) + LOGINFO("%s: Exit code %d\n", command, WEXITSTATUS(status)); + return status; + } + if (timeout_seconds && elapsed > timeout_seconds) { + LOGINFO("%s: Timed out after %.1fs (killing pid %d)\n", + command, elapsed, pid); + kill(pid, SIGTERM); + return -1; + } + /* poll every 0.1 sec */ + usleep(100000); + } +} + +/* WARNING : formatted string buffer is limited to 1024 byte */ +int fprintf_fd(int fd, const char *fmt, ...) +{ + int n; + int ret; + char buff[1024]; + va_list args; + + va_start(args, fmt); + n = vsnprintf(buff, 1024 - 1, fmt, args); + ret = write(fd, buff, n); + va_end(args); + return ret; +} + +int file_exist(const char *file) +{ + FILE *fp; + + fp = fopen(file, "r"); + if (fp == NULL) + return -1; + fclose(fp); + return 1; +} + +int write_fd(int fd, const void *buf, int len) +{ + int count; + int total; + total = 0; + while (len) { + count = write(fd, buf, len); + if (count < 0) { + if (total) + return total; + return count; + } + total += count; + buf = ((const char *)buf) + count; + len -= count; + } + return total; +} + +int copy_file(char *src, char *dst) +{ + int sfd; + int dfd; + char buf[PIPE_BUF]; + + retvm_if(src == NULL, -1, "Invalid argument: source is NULL\n"); + retvm_if(dst == NULL, -1, "Invalid argument: destination is NULL\n"); + sfd = open(src, O_RDONLY); + if (sfd < 0) { + LOGERR("Failed to open (%s)\n", src); + return -1; + } + dfd = open(dst, O_WRONLY|O_CREAT|O_EXCL, 0644); + if (dfd < 0) { + close(sfd); + LOGERR("Failed to open (%s)\n", dst); + return -1; + } + for (;;) { + int ret = read(sfd, buf, sizeof(buf)); + if (ret > 0) + ret = write_fd(dfd, buf, ret); + if (ret <= 0) + break; + } + close(sfd); + close(dfd); + LOGINFO("copy (%s) to (%s)\n", src, dst); + return 1; +} + +int cat_file(char *src, char *dst) +{ + int sfd; + int dfd; + char buf[PIPE_BUF]; + + retvm_if(src == NULL, -1, "Invalid argument: source is NULL\n"); + retvm_if(dst == NULL, -1, "Invalid argument: destination is NULL\n"); + sfd = open(src, O_RDONLY); + if (sfd < 0) { + LOGERR("Failed to open (%s)\n", src); + return -1; + } + dfd = open(dst, O_WRONLY|O_APPEND); + if (dfd < 0) { + close(sfd); + LOGERR("Failed to open (%s)\n", dst); + return -1; + } + for (;;) { + int ret = read(sfd, buf, sizeof(buf)); + if (ret > 0) + ret = write_fd(dfd, buf, ret); + if (ret <= 0) + break; + } + close(sfd); + close(dfd); + LOGINFO("copy (%s) to (%s)\n", src, dst); + return 1; +} + +static int _delete_dir_contents(DIR *d, const char *ignore) +{ + int result = 0; + struct dirent *de; + int dfd; + + dfd = dirfd(d); + if (dfd < 0) + return -1; + while ((de = readdir(d))) { + const char *name = de->d_name; + /* skip the ignore name if provided */ + if (ignore && !strcmp(name, ignore)) + continue; + if (de->d_type == DT_DIR) { + int subfd; + DIR *subdir; + /* always skip "." and ".." */ + if (name[0] == '.') { + if (name[1] == 0) + continue; + if ((name[1] == '.') && (name[2] == 0)) + continue; + } + subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); + if (subfd < 0) { + LOGERR("Couldn't openat %s: %s\n", name, strerror(errno)); + result = -1; + continue; + } + subdir = fdopendir(subfd); + if (subdir == NULL) { + LOGERR("Couldn't fdopendir %s: %s\n", name, strerror(errno)); + close(subfd); + result = -1; + continue; + } + if (_delete_dir_contents(subdir, 0)) + result = -1; + closedir(subdir); + if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) { + LOGERR("Couldn't unlinkat %s: %s\n", name, strerror(errno)); + result = -1; + } + } else { + if (unlinkat(dfd, name, 0) < 0) { + LOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno)); + result = -1; + } + } + } + return result; +} + +int delete_dir_contents(const char *pathname, + int also_delete_dir, + const char *ignore) +{ + int res = 0; + DIR *d; + + d = opendir(pathname); + if (d == NULL) { + LOGERR("Couldn't opendir %s: %s\n", pathname, strerror(errno)); + return -errno; + } + res = _delete_dir_contents(d, ignore); + closedir(d); + if (also_delete_dir) { + if (rmdir(pathname)) { + LOGERR("Couldn't rmdir %s: %s\n", pathname, strerror(errno)); + res = -1; + } + } + return res; +} +/** + * @} + */ |