bigbro 0.3.11

Library for tracking file accesses of processes
Documentation
#include "realpath.h"
#include "fcntl.h" // for AT_FDCWD

static inline char *flexible_realpath_at(pid_t pid, int dirfd, const char *path,
                                         rw_status *h,
                                         enum last_symlink_handling lasth) {
  if (!path) return NULL;
  char *rawpath = NULL;
  do {
    /* printf("path: %s\n", path); */
    const char *procself = "/proc/self/";
    const int procselflen = strlen(procself);
    if (strlen(path) > procselflen &&
        !memcmp(path, procself, procselflen)) {
      char *out = malloc(PATH_MAX);
      snprintf(out, PATH_MAX, "/proc/%d/%s", pid, path + procselflen);
      /* printf("rawpath: %s\n", out); */
      rawpath = out;
      break;
    }
    /* printf("path '%s' does not match '%s'\n", path, procself); */
    if (path[0] == '/') {
      /* printf("rawpath: %s\n", path); */
      rawpath = strdup(path);
      break;
    }

    char *proc_fd = malloc(PATH_MAX);
    if (dirfd >= 0 && dirfd != AT_FDCWD) snprintf(proc_fd, PATH_MAX, "/proc/%d/fd/%d", pid, dirfd);
    else snprintf(proc_fd, PATH_MAX, "/proc/%d/cwd", pid);
    char *cwd = malloc(PATH_MAX);
    int linklen = readlink(proc_fd, cwd, PATH_MAX);
    if (linklen < 0) {
      fprintf(stderr, "unable to determine cwd from %s i.e. fd %d!!! (%s)\n",
              proc_fd, dirfd, strerror(errno));
      return NULL;
    }
    cwd[linklen] = 0;
    /* printf("cwd(%d): %s (from %s)\n", dirfd, cwd, proc_fd); */
    int total_len = strlen(cwd) + strlen(path) + 4;
    if (total_len > PATH_MAX) cwd = realloc(cwd, total_len);
    strcat(cwd, "/");
    strcat(cwd, path);
    free(proc_fd);
    /* printf("rawpath: (%d) %s\n", dirfd, cwd); */
    rawpath = cwd;
    break;
  } while (0); // this loop is just to easily allow early jumping with break (hokey)

  // at this stage, rawpath holds `pwd`/path, but we have not yet
  // interpreted for symlinks, which is our next job:
  char *rp = flexible_realpath(rawpath, h, lasth);
  free(rawpath);
  return rp;
}

static inline void read_dir_fd(pid_t pid, int dirfd, rw_status *h) {
  char *abspath = flexible_realpath_at(pid, dirfd, ".", h, look_for_file_or_directory);
  if (!lookup_in_hash(&h->mkdir, abspath)) {
    insert_hashset(&h->readdir, abspath);
  }
  free(abspath);
}

static inline void read_something_at(pid_t pid, int dirfd, const char *path,
                                     rw_status *h, enum last_symlink_handling lh) {
  char *abspath = flexible_realpath_at(pid, dirfd, path, h, lh);
  if (!abspath) return;
  struct stat st;
  if (!lookup_in_hash(&h->written, abspath) && !stat(abspath, &st) && S_ISREG(st.st_mode)) {
    insert_hashset(&h->read, abspath);
  }
  free(abspath);
}

static inline void write_something_at(pid_t pid, int dirfd, const char *path,
                                      rw_status *h, enum last_symlink_handling lh) {
  char *abspath = flexible_realpath_at(pid, dirfd, path, h, lh);
  insert_hashset(&h->written, abspath);
  delete_from_hashset(&h->read, abspath);
  free(abspath);
}

static inline void read_file_at(pid_t pid, int dirfd, const char *path,
                                rw_status *h) {
  read_something_at(pid, dirfd, path, h, look_for_file_or_directory);
}

static inline void maybe_read_file_at(pid_t pid, int dirfd, const char *path,
                                rw_status *h) {
  read_something_at(pid, dirfd, path, h, look_for_file_or_directory);
}

static inline void write_file_at(pid_t pid, int dirfd, const char *path,
                                 rw_status *h) {
  write_something_at(pid, dirfd, path, h, look_for_file_or_directory);
}

static inline void read_link_at(pid_t pid, int dirfd, const char *path,
                                rw_status *h) {
  read_something_at(pid, dirfd, path, h, look_for_symlink);
}

static inline void write_link_at(pid_t pid, int dirfd, const char *path,
                                 rw_status *h) {
  write_something_at(pid, dirfd, path, h, look_for_symlink);
}