Fix svace issues
[platform/core/system/crash-worker.git] / src / shared / util.c
index f3685d4..0606045 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <sys/file.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <ctype.h>
 #include <grp.h>
 
+#include "defs.h"
 #include "util.h"
 #include "log.h"
 
+bool have_livecoredumper(void)
+{
+       return access(LIVEDUMPER_BIN_PATH, X_OK) == 0;
+}
+
 int write_fd(int fd, const void *buf, int len)
 {
        int count;
@@ -114,7 +123,7 @@ int copy_bytes(int destfd, int srcfd, off_t *ncopied)
        return r == 0 ? r : copy_bytes_rw(destfd, srcfd, ncopied);
 }
 
-int copy_file(char *dst, char *src)
+int copy_file(const char *dst, const char *src)
 {
        int res;
        int sfd;
@@ -132,7 +141,7 @@ int copy_file(char *dst, char *src)
        dfd = open(dst, O_WRONLY|O_CREAT|O_EXCL, 0644);
        if (dfd < 0) {
                close(sfd);
-               _SE("Failed to open (%s)\n", dst);
+               _E("Failed to open (%s)\n", dst);
                return -1;
        }
 
@@ -143,7 +152,7 @@ int copy_file(char *dst, char *src)
        return res;
 }
 
-int move_file(char *dst, char *src)
+int move_file(const char *dst, const char *src)
 {
        if (copy_file(dst, src) < 0)
                return -1;
@@ -163,7 +172,7 @@ int dump_file_write_fd(int dfd, char *src)
        }
        sfd = open(src, O_RDONLY);
        if (sfd < 0) {
-               _SE("Failed to open (%s)\n", src);
+               _E("Failed to open (%s)\n", src);
                return -1;
        }
 
@@ -189,29 +198,44 @@ int fsync_path(char *const path)
        return ret;
 }
 
-int make_dir(const char *path, const char *name, int mode)
+bool make_dir(const char *path, int mode)
 {
-       int r = -1;
+       int r = mkdir(path, mode);
 
-       DIR *dir = opendir(path);
-       if (dir) {
-               int dfd = dirfd(dir);
-               r = mkdirat(dfd, name, mode);
-               closedir(dir);
+       if (r < 0 && errno != EEXIST) {
+               _E("Unable to create directory %s: %m", path);
+               return false;
        }
 
-       return r == 0 || (r == -1 && errno == EEXIST) ? 0 : -1;
+       if (chmod(path, mode) != 0) // Fixup permissions for directories created with bad umask
+               _E("Error changing permission for %s to %d: %m", path, mode);
+
+       if (r >= 0)
+               return true;
+
+       struct stat st = {0};
+       r = stat(path, &st);
+       bool isdir = !!(st.st_mode & S_IFDIR);
+
+       if (!r && isdir)
+               return true;
+       else if (!r && !isdir)
+               errno = ENOTDIR;
+
+       _E("Failure while trying to ensure %s exists and it is directory: %m", path);
+       return false;
 }
 
-static int remove_dir_internal(int fd)
+static bool remove_dir_internal(int fd)
 {
        DIR *dir;
        struct dirent *de;
-       int subfd, ret = 0;
+       bool ret = true;
+       int subfd = 0;
 
        dir = fdopendir(fd);
        if (!dir)
-               return -1;
+               return false;
 
        while ((de = readdir(dir))) {
                if (de->d_type == DT_DIR) {
@@ -219,21 +243,21 @@ static int remove_dir_internal(int fd)
                                continue;
                        subfd = openat(fd, de->d_name, O_RDONLY | O_DIRECTORY);
                        if (subfd < 0) {
-                               _SE("Couldn't openat %s: %d\n", de->d_name, errno);
-                               ret = -1;
+                               _E("Couldn't openat %s: %d\n", de->d_name, errno);
+                               ret = false;
                                continue;
                        }
-                       if (remove_dir_internal(subfd))
-                               ret = -1;
+                       if (!remove_dir_internal(subfd))
+                               ret = false;
                        close(subfd);
                        if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
-                               _SE("Couldn't unlinkat %s: %d\n", de->d_name, errno);
-                               ret = -1;
+                               _E("Couldn't unlinkat %s: %d\n", de->d_name, errno);
+                               ret = false;
                        }
                } else {
                        if (unlinkat(fd, de->d_name, 0) < 0) {
-                               _SE("Couldn't unlinkat %s: %d\n", de->d_name, errno);
-                               ret = -1;
+                               _E("Couldn't unlinkat %s: %d\n", de->d_name, errno);
+                               ret = false;
                        }
                }
        }
@@ -241,29 +265,62 @@ static int remove_dir_internal(int fd)
        return ret;
 }
 
-int remove_dir(const char *path, int del_dir)
+bool remove_dir(const char *path, bool del_dir)
 {
-       int fd, ret = 0;
+       bool ret = true;
+       int fd = 0;
 
        if (!path)
-               return -1;
+               return false;
        fd = open(path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
        if (fd < 0) {
-               _SE("Couldn't opendir %s: %d\n", path, errno);
-               return -errno;
+               _E("Couldn't opendir %s: %d\n", path, errno);
+               return false;
        }
        ret = remove_dir_internal(fd);
        close(fd);
 
        if (del_dir) {
                if (rmdir(path)) {
-                       _SE("Couldn't rmdir %s: %d\n", path, errno);
-                       ret = -1;
+                       _E("Couldn't rmdir %s: %d\n", path, errno);
+                       ret = false;
                }
        }
        return ret;
 }
 
+int lock_dir(const char *path, bool block)
+{
+       assert(path);
+
+       int fd;
+
+       if ((fd = open(path, O_RDONLY | O_DIRECTORY)) == -1) {
+               _E("Failed to open %s: %m", path);
+               return -1;
+       }
+
+       int flock_flags = LOCK_EX;
+
+       if (!block)
+               flock_flags |= LOCK_NB;
+
+       if (flock(fd, flock_flags) == -1) {
+               _E("Failed to lock %s for exclusive access: %m", path);
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+void unlock_dir(int fd)
+{
+       if (flock(fd, LOCK_UN) < 0)
+               _E("Failed to unlock file descriptor: %m");
+       close(fd);
+}
+
 int get_exec_pid(const char *execpath)
 {
        DIR *dp;
@@ -357,7 +414,7 @@ off_t get_directory_usage(char *path)
                if (!strncmp(de->d_name, ".", 2) || !strncmp(de->d_name, "..", 3))
                        continue;
                if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
-                       _SE("Failed to fstatat  %s: %d\n", de->d_name, errno);
+                       _E("Failed to fstatat  %s: %d\n", de->d_name, errno);
                        continue;
                }
                usage += st.st_size;
@@ -467,73 +524,84 @@ int find_crash_tid(int pid)
        return -1;
 }
 
-char* get_cmd_line(pid_t pid)
+bool filter_drop_trailing_whitespace(char *buf, int size, int datalen)
 {
-       char cmdline_path[PATH_MAX];
+       assert(buf);
+       assert(datalen <= size);
 
-       snprintf(cmdline_path, sizeof(cmdline_path),
-                       "/proc/%d/cmdline", pid);
+       bool filtered = false;
 
-       int fd = open(cmdline_path, O_RDONLY);
-       if (fd < 0) {
-               _E("Failed to open %s: %m\n", cmdline_path);
-               return NULL;
+       for (int i = datalen; i >= 0 && isspace(buf[i]); --i) {
+               buf[i] = '\0';
+               filtered = true;
        }
 
-       char buffer[PATH_MAX];
-       ssize_t ret = read(fd, buffer, sizeof(buffer) - 1);
-       close(fd);
+       return filtered;
+}
 
-       if (ret <= 0) {
-               _E("Failed to read %s: %m\n", cmdline_path);
-               return NULL;
+bool read_proc_file(pid_t pid, const char * const file, char *outbuf, size_t bufsize, charp0filter filter)
+{
+       assert(file);
+       assert(outbuf);
+       assert(bufsize > 0);
+
+       char path[PATH_MAX];
+
+       snprintf(path, sizeof(path), "/proc/%d/%s", pid, file);
+
+       int fd = open(path, O_RDONLY);
+       if (fd < 0) {
+               _E("Failed to open %s: %m\n", path);
+               return false;
        }
-       buffer[ret] = '\0';
 
-       char *result;
-       if (asprintf(&result, "%s", buffer) == -1) {
-               _E("asprintf() error: %m\n");
-               return NULL;
+       ssize_t ret = read(fd, outbuf, bufsize - 1);
+       if (ret < 0) {
+               _E("Failed to read %s: %m\n", path);
+               goto err_close;
        }
+       outbuf[ret] = '\0';
 
-       return result;
+       close(fd);
+
+       if (ret > 0 && filter)
+               (void)filter(outbuf, bufsize, ret - 1);
+
+       return true;
+
+err_close:
+       close(fd);
+       return false;
 }
 
-char* get_exe_path(pid_t pid)
+bool get_exe_path(pid_t pid, char *outbuf, size_t outbuf_len)
 {
-       char exe_link[PATH_MAX];
-       char buffer[PATH_MAX];
+       assert(outbuf);
+       assert(outbuf_len > 0);
 
-       snprintf(exe_link, sizeof(exe_link),
-               "/proc/%d/exe", pid);
+       char exe_link[PATH_MAX];
 
-       ssize_t ret = readlink(exe_link, buffer, sizeof(buffer) - 1);
+       snprintf(exe_link, sizeof(exe_link), "/proc/%d/exe", pid);
 
+       ssize_t ret = readlink(exe_link, outbuf, outbuf_len - 1);
        if (ret <= 0) {
                _E("Failed to read link %s: %m", exe_link);
-               return NULL;
-       }
-       buffer[ret] = '\0';
-
-       if (access(buffer, F_OK) == -1) {
-               _E("Invalid path %s", buffer);
-               return NULL;
+               return false;
        }
+       outbuf[ret] = '\0';
 
-       char *result;
-       if (asprintf(&result, "%s", buffer) == -1) {
-               _E("asprintf() error: %m\n");
-               return NULL;
+       if (access(outbuf, F_OK) == -1) {
+               _E("Unable to access %s: %m", outbuf);
+               return false;
        }
-
-       return result;
+       return true;
 }
 
 /* This function is supposed to accept same data as passed to execve
  * (argv and envp), which can be arrays of strings as well as NULL
  * pointer.
  */
-charconcatenate(char *const vec[])
+char *concatenate(char *const vec[])
 {
        size_t length = 0;
        for (char *const *p = vec; p && *p; p++)
@@ -565,12 +633,86 @@ bool string_ends_with(const char *string, const char *suffix)
        return (string_len >= suffix_len) && !strcmp(string + string_len - suffix_len, suffix);
 }
 
+/* what for: kernel.core_pattern's %E replaces / with !, this function does opposite process */
+void kernel_exe_path_normalize(char *path)
+{
+       assert(path);
+
+       for (size_t i = 0, len = strlen(path); i < len; i++)
+               path[i] = path[i] == '!' ? '/' : path[i];
+}
+
 bool file_exists(const char *path)
 {
        struct stat buf;
        return stat(path, &buf) == 0;
 }
 
+bool file_exists_in_dir(const char *base_dir, const char *file_name)
+{
+       char *path;
+       bool result = false;
+
+       if (asprintf(&path, "%s/%s", base_dir, file_name) == -1) {
+               _E("Failed to asprintf for path: %m");
+       } else {
+               result = file_exists(path);
+               free(path);
+       }
+
+       return result;
+}
+
+bool write_to_file(const char *content, const char *base_dir, const char *file_name)
+{
+       char *path;
+       bool result = false;
+
+       if (asprintf(&path, "%s/%s", base_dir, file_name) == -1) {
+               _E("Failed to asprintf for path: %m");
+               return false;
+       }
+
+       int fd = open(path, O_WRONLY | O_CREAT, 0600);
+
+       if (fd < 0) {
+               _E("Failed to open %s: %m", path);
+               goto exit;
+       }
+
+       if (dprintf(fd, "%s", content) < 0) {
+               _E("Failed to write to file %s: %m", path);
+               close(fd);
+               goto exit;
+       }
+
+       close(fd);
+exit:
+       free(path);
+       return result;
+}
+
+bool is_dotnet_file(const char *path)
+{
+       static const char *DOTNET_EXTS[] = { ".dll", ".exe", NULL };
+
+       bool result = false;
+       size_t p_len = strlen(path);
+       while (p_len > 0 && path[p_len-1] == '\n')
+               p_len--;
+
+       for (const char **ext = DOTNET_EXTS; *ext != NULL; ext++) {
+               size_t d_len = strlen(*ext);
+
+               if ((p_len >= d_len) &&
+                   (strncasecmp(&path[p_len - d_len], *ext, d_len) == 0)) {
+                       result = true;
+                       break;
+               }
+       }
+       return result;
+}
+
 /**
  * @}
  */