<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "env.h"
#include "event.h"
#include "net.h"
#include "util.h"
#include <voyeur.h>

// Note that in event handlers, we always have to read the data,
// even if the callback isn't present, so we can move on to the
// next event in the stream. In practice the callback should always be
// present, so it's not worth worrying about.

static void handle_exec(voyeur_context* context, int fd)
{
  // Read the path.
  char* path;
  TRY(voyeur_read_string, fd, &path, 0);

  // Read the arguments.
  int argc;
  TRY(voyeur_read_int, fd, &argc);

  char** argv = malloc(sizeof(char*) * (argc + 1));
  for (int i = 0 ; i < argc ; ++i) {
    char* arg;
    TRY(voyeur_read_string, fd, &arg, 0);
    argv[i] = arg;
  }
  argv[argc] = NULL;

  // Read the environment.
  int envc;
  char** envp = NULL;
  if (context->exec_opts & OBSERVE_EXEC_ENV) {
    TRY(voyeur_read_int, fd, &envc);

    envp = malloc(sizeof(char*) * (envc + 1));
    for (int i = 0 ; i < envc ; ++i) {
      char* envvar;
      TRY(voyeur_read_string, fd, &envvar, 0);
      envp[i] = envvar;
    }
    envp[envc] = NULL;
  }

  // Read the current working directory.
  char* cwd = NULL;
  if (context->exec_opts & OBSERVE_EXEC_CWD) {
    TRY(voyeur_read_string, fd, &cwd, 0);
  }

  if (context->exec_cb) {
    ((voyeur_exec_callback)context->exec_cb)(path, argv, envp, cwd,
                                             context->exec_userdata);
  }

  // Free everything.
  free(path);

  for (int i = 0 ; i < argc ; ++i) {
    free(argv[i]);
  }
  free(argv);

  if (context->exec_opts & OBSERVE_EXEC_ENV) {
    for (int i = 0 ; i < envc ; ++i) {
      free(envp[i]);
    }
    free(envp);
  }

  if (context->exec_opts & OBSERVE_EXEC_CWD) {
    free(cwd);
  }
}

static void handle_open(voyeur_context* context, int fd)
{
  char* path;
  int oflag, mode, retval;

  TRY(voyeur_read_string, fd, &path, 0);
  TRY(voyeur_read_int, fd, &oflag);
  TRY(voyeur_read_int, fd, &mode);
  TRY(voyeur_read_int, fd, &retval);

  // Read the current working directory.
  char* cwd = NULL;
  if (context->open_opts & OBSERVE_OPEN_CWD) {
    TRY(voyeur_read_string, fd, &cwd, 0);
  }

  if (context->open_cb) {
    ((voyeur_open_callback)context->open_cb)(path, oflag, (mode_t) mode, cwd,
                                             retval, context->open_userdata);
  }

  free(path);
}

static void handle_close(voyeur_context* context, int fd)
{
  int fildes, retval;

  TRY(voyeur_read_int, fd, &fildes);
  TRY(voyeur_read_int, fd, &retval);

  if (context->close_cb) {
    ((voyeur_close_callback)context->close_cb)(fildes, retval,
                                               context->close_userdata);
  }
}

#define ON_EVENT(E, e)                          \
  case VOYEUR_EVENT_##E:                        \
    handle_##e(context, fd);                    \
    break;

void voyeur_handle_event(voyeur_context* context, voyeur_event_type type, int fd)
{
  switch (type) {
    MAP_EVENTS
    default:
      fprintf(stderr, "libvoyeur: got unknown event type %u\n",
              (unsigned) type);
      exit(EXIT_FAILURE);
  }
}

#undef ON_EVENT

#define LIBS_SIZE 256

#ifdef __APPLE__
#define LIB_SUFFIX ".dylib"
#else
#define LIB_SUFFIX ".so"
#endif

#define ON_EVENT(_, e) \
  if (context->e##_cb) { \
    if (prev) strlcat(libs, ":", LIBS_SIZE); \
    strlcat(libs, cwd, LIBS_SIZE); \
    strlcat(libs, "/", LIBS_SIZE); \
    strlcat(libs, "libvoyeur-" #e LIB_SUFFIX, LIBS_SIZE); \
    prev = 1; \
  } \

char* voyeur_requested_libs(voyeur_context* context)
{
  char* libs = calloc(1, LIBS_SIZE);
  char prev = 0;
  
  // TODO: This should be relative to the library location, not the current
  // directory. This is just a quick hack.
  char* cwd = getcwd(NULL, 0);

  MAP_EVENTS

  free(cwd);
<commit_msg>Locate helper libraries relative to libvoyeur location<commit_after>#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "env.h"
#include "event.h"
#include "net.h"
#include "util.h"
#include <voyeur.h>

// Note that in event handlers, we always have to read the data,
// even if the callback isn't present, so we can move on to the
// next event in the stream. In practice the callback should always be
// present, so it's not worth worrying about.

static void handle_exec(voyeur_context* context, int fd)
{
  // Read the path.
  char* path;
  TRY(voyeur_read_string, fd, &path, 0);

  // Read the arguments.
  int argc;
  TRY(voyeur_read_int, fd, &argc);

  char** argv = malloc(sizeof(char*) * (argc + 1));
  for (int i = 0 ; i < argc ; ++i) {
    char* arg;
    TRY(voyeur_read_string, fd, &arg, 0);
    argv[i] = arg;
  }
  argv[argc] = NULL;

  // Read the environment.
  int envc;
  char** envp = NULL;
  if (context->exec_opts & OBSERVE_EXEC_ENV) {
    TRY(voyeur_read_int, fd, &envc);

    envp = malloc(sizeof(char*) * (envc + 1));
    for (int i = 0 ; i < envc ; ++i) {
      char* envvar;
      TRY(voyeur_read_string, fd, &envvar, 0);
      envp[i] = envvar;
    }
    envp[envc] = NULL;
  }

  // Read the current working directory.
  char* cwd = NULL;
  if (context->exec_opts & OBSERVE_EXEC_CWD) {
    TRY(voyeur_read_string, fd, &cwd, 0);
  }

  if (context->exec_cb) {
    ((voyeur_exec_callback)context->exec_cb)(path, argv, envp, cwd,
                                             context->exec_userdata);
  }

  // Free everything.
  free(path);

  for (int i = 0 ; i < argc ; ++i) {
    free(argv[i]);
  }
  free(argv);

  if (context->exec_opts & OBSERVE_EXEC_ENV) {
    for (int i = 0 ; i < envc ; ++i) {
      free(envp[i]);
    }
    free(envp);
  }

  if (context->exec_opts & OBSERVE_EXEC_CWD) {
    free(cwd);
  }
}

static void handle_open(voyeur_context* context, int fd)
{
  char* path;
  int oflag, mode, retval;

  TRY(voyeur_read_string, fd, &path, 0);
  TRY(voyeur_read_int, fd, &oflag);
  TRY(voyeur_read_int, fd, &mode);
  TRY(voyeur_read_int, fd, &retval);

  // Read the current working directory.
  char* cwd = NULL;
  if (context->open_opts & OBSERVE_OPEN_CWD) {
    TRY(voyeur_read_string, fd, &cwd, 0);
  }

  if (context->open_cb) {
    ((voyeur_open_callback)context->open_cb)(path, oflag, (mode_t) mode, cwd,
                                             retval, context->open_userdata);
  }

  free(path);
}

static void handle_close(voyeur_context* context, int fd)
{
  int fildes, retval;

  TRY(voyeur_read_int, fd, &fildes);
  TRY(voyeur_read_int, fd, &retval);

  if (context->close_cb) {
    ((voyeur_close_callback)context->close_cb)(fildes, retval,
                                               context->close_userdata);
  }
}

#define ON_EVENT(E, e)                          \
  case VOYEUR_EVENT_##E:                        \
    handle_##e(context, fd);                    \
    break;

void voyeur_handle_event(voyeur_context* context, voyeur_event_type type, int fd)
{
  switch (type) {
    MAP_EVENTS
    default:
      fprintf(stderr, "libvoyeur: got unknown event type %u\n",
              (unsigned) type);
      exit(EXIT_FAILURE);
  }
}

#undef ON_EVENT

#define LIBS_SIZE 256

#ifdef __APPLE__
#define LIB_SUFFIX ".dylib"
#else
#define LIB_SUFFIX ".so"
#endif

#define ON_EVENT(_, e)                                    \
  if (context->e##_cb) {                                  \
    if (prev) strlcat(libs, ":", LIBS_SIZE);              \
    strlcat(libs, libdir, LIBS_SIZE);                     \
    strlcat(libs, "libvoyeur-" #e LIB_SUFFIX, LIBS_SIZE); \
    prev = 1;                                             \
  }                                                       \

char* voyeur_requested_libs(voyeur_context* context)
{
  char* libs = calloc(1, LIBS_SIZE);
  char prev = 0;
  
  bool did_allocate = false;
  char* libdir = "./";
  Dl_info dlinfo;
  if (dladdr(voyeur_requested_libs, &dlinfo) && dlinfo.dli_fname) {
    // Strip the filename. It'd be great if 'dirname' could be used
    // for this, but it's not thread safe. Note that if no slash is
    // found, we just stick with "./".
    char* last_slash = strrchr(dlinfo.dli_fname, '/');
    if (last_slash) {
      did_allocate = true;
      int len_with_slash_and_null = (last_slash - dlinfo.dli_fname) + 2;
      libdir = calloc(1, len_with_slash_and_null);
      strlcpy(libdir, dlinfo.dli_fname, len_with_slash_and_null);
    }
  }

  MAP_EVENTS

  if (did_allocate) {
    free(libdir);
  }

{'fraction_non_alphanumeric': 0.1357674583481035, 'fraction_numerical': 0.004608294930875576, 'mean_word_length': 2.4874330449114135, 'pattern_counts': {'":': 2, '<': 22, '<?xml version=': 0, '>': 44, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2425086', 'n_tokens_mistral': 3308, 'n_tokens_neox': 3164, 'n_words': 767}