| #include <sys/types.h> |
| #include <inttypes.h> |
| #include <assert.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <fcntl.h> |
| #include <limits.h> |
| #ifdef _MSC_VER |
| #include <io.h> |
| #define ssize_t size_t |
| #define basename(x) strrchr(x, '\\') + 1 |
| #else |
| #include <unistd.h> |
| #include <libgen.h> |
| #endif |
| |
| #include "fsatrace.h" |
| #include "proc.h" |
| |
| int |
| main(int argc, char *const argv[]) |
| { |
| int rc = EXIT_FAILURE; |
| const char *out; |
| const char *opts; |
| char bopts[256]; |
| int verr; |
| char *const *args = argv + 4; |
| unsigned nargs = argc - 4; |
| |
| if (argc < 5 || (strcmp(argv[3], "--") && strcmp(argv[3], "---"))) |
| fatal( |
| " usage: %s <options> <output> -- <cmdline>\n" |
| " where <options> is a combination of the following characters:\n" |
| " v: print args vector\n" |
| " e: print verbose errors\n" |
| " r: dump read operations\n" |
| " w: dump write operations\n" |
| " m: dump file move operations\n" |
| " d: dump file delete operations\n" |
| " q: dump file stat operations\n", |
| argv[0]); |
| out = argv[2]; |
| fflush(stdout); |
| opts = (const char *)argv[1]; |
| setenv(ENV_OPTS, opts, 1); |
| memset(bopts, 0, sizeof(bopts)); |
| while (*opts) |
| bopts[(unsigned char)*opts++] = 1; |
| if (bopts['v']) |
| procDumpArgs(nargs, args); |
| verr = bopts['e']; |
| enum procerr ret = procRun(nargs, args, &rc, out); |
| switch (ret) { |
| case ERR_PROC_FORK: |
| if (verr) |
| aerror(nargs, args, "forking process"); |
| break; |
| case ERR_PROC_EXEC: |
| if (verr) |
| aerror(nargs, args, "executing command: %d", rc); |
| break; |
| case ERR_PROC_SIGNALED: |
| if (verr) |
| aerror(nargs, args, "process signaled: %d", rc); |
| break; |
| case ERR_PROC_STOPPED: |
| if (verr) |
| aerror(nargs, args, "process stopped: %d", rc); |
| break; |
| case ERR_PROC_UNKNOWN: |
| if (verr) |
| aerror(nargs, args, "unknown process error"); |
| break; |
| case ERR_PROC_WAIT: |
| if (verr) |
| aerror(nargs, args, "waiting for command completion"); |
| break; |
| case ERR_FIFO_TIMEOUT: |
| aerror(nargs, args, |
| "Timeout opening the FIFO for writing the traced operations.\n" |
| "\n" |
| "This is more than likely because the process being traced does\n" |
| "not dynamically link libc. The fsatrace program uses LD_PRELOAD\n" |
| "to inject hooks around libc calls, and this error should only\n" |
| "occur when those hooks are not injected into the process being\n" |
| "traced.\n" |
| "\n" |
| "A simple \"fix\" is to wrap the program being launched inside\n" |
| "another program that dynmically links libc, but that approach\n" |
| "is invalid because the process not dynamically linking libc\n" |
| "indicates the process will not run the hooks installed by\n" |
| "fsatrace to trace filesystem accesses. Thus, doing something\n" |
| "like `bash -c \"exec my_program\"` is unlikely to achieve your\n" |
| "reason for using fsatrace in the first place.\n" |
| "\n" |
| ); |
| break; |
| case ERR_FIFO_UNKNOWN: |
| aerror(nargs, args, "Error opening FIFO for writing the traced operations."); |
| break; |
| case OK: |
| if (rc) { |
| if (verr) |
| aerror(nargs, args, |
| "command failed with code %d", rc); |
| } |
| break; |
| default: |
| aerror(nargs, args, "Uncaught procerr %d", ret); |
| } |
| return rc; |
| } |