* 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;
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;
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;
}
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;
}
sfd = open(src, O_RDONLY);
if (sfd < 0) {
- _SE("Failed to open (%s)\n", src);
+ _E("Failed to open (%s)\n", src);
return -1;
}
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) {
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;
}
}
}
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;
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;
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.
*/
-char* concatenate(char *const vec[])
+char *concatenate(char *const vec[])
{
size_t length = 0;
for (char *const *p = vec; p && *p; p++)
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;
+}
+
/**
* @}
*/