summaryrefslogtreecommitdiff
path: root/crash-worker/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'crash-worker/util.c')
-rw-r--r--crash-worker/util.c299
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;
+}
+/**
+ * @}
+ */