1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
#include "cde.h"
int main(int argc, char* argv[]) {
pid_t child_pid;
int status;
if (argc <= 1) {
fprintf(stderr, "Error: empty command\n");
exit(1);
}
child_pid = fork();
if (child_pid == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
char** target_program_argv = argv + 1;
execvp(target_program_argv[0], target_program_argv);
// If execv returns, it must have failed
fprintf(stderr, "Unknown command %s\n", target_program_argv[0]);
exit(1);
}
else if (child_pid < 0) {
fprintf(stderr, "Error: fork failed\n");
exit(1);
}
else {
// TODO: add as a new field in 'struct pcb'
char filename[255]; // hope this is big enough!
char open_mode;
struct pcb* child_pcb = new_pcb(child_pid, INUSER);
assert(child_pcb);
while (1) {
pid_t pid = waitpid(child_pcb->pid, &status, 0);
//pid_t pid = waitpid(child_pcb->pid, &status, __WALL);
assert(pid == child_pcb->pid);
if (WIFEXITED(status)) {
break;
}
// populates child_pcb->regs
EXITIF(ptrace(PTRACE_GETREGS, child_pcb->pid, NULL, &child_pcb->regs) < 0);
switch (child_pcb->state) {
case INUSER:
if (child_pcb->regs.orig_eax == SYS_open) {
// filename is a pointer in the child process's address space
char* child_filename = (char*)child_pcb->regs.ebx;
long open_flags = child_pcb->regs.ecx;
open_mode = (open_flags & 0x3);
// TODO: could create a strcpy to optimize, since most filenames
// aren't long, so we can bail on the first NULL
memcpy_from_child(child_pcb, filename, child_filename, 255);
}
else if (child_pcb->regs.orig_eax == SYS_execve) {
char* child_filename = (char*)child_pcb->regs.ebx;
printf("execve %p %d\n", child_filename,
ptrace(PTRACE_PEEKUSER, child_pcb->pid, 0, NULL));
//memcpy_from_child(child_pcb, filename, child_filename, 255);
//open_mode = O_RDONLY;
}
child_pcb->state = INCALL;
EXITIF(ptrace(PTRACE_SYSCALL, child_pcb->pid, NULL, NULL) < 0);
break;
case INCALL:
if (child_pcb->regs.orig_eax == SYS_open) {
// a non-negative return value means that a VALID file
// descriptor was returned (i.e., the file actually exists)
// also, only grab info for files opened in read mode
if ((child_pcb->regs.eax >= 0) &&
(open_mode == O_RDONLY || open_mode == O_RDWR)) {
struct stat st;
EXITIF(stat(filename, &st));
// check whether it's a REGULAR-ASS file
if (S_ISREG(st.st_mode)) {
// assume that relative paths are in working directory,
// so no need to grab those files
//
// TODO: this isn't a perfect assumption since a
// relative path could be something like '../data.txt',
// which this won't pick up :)
// WOW, this libc function seems useful for
// canonicalizing filenames:
// char* canonicalize_file_name (const char *name)
if (filename[0] == '/') {
// modify filename so that it appears as a RELATIVE PATH
// within a cde-root/ sub-directory
char* rel_path = malloc(strlen(filename) + strlen("cde-root") + 1);
strcpy(rel_path, "cde-root");
strcat(rel_path, filename);
struct path* p = str2path(rel_path);
path_pop(p); // ignore filename portion to leave just the dirname
// now mkdir all directories specified in rel_path
int i;
for (i = 1; i <= p->depth; i++) {
char* dn = path2str(p, i);
mkdir(dn, 0777);
free(dn);
}
// finally, 'copy' filename over to rel_path
// 1.) try a hard link for efficiency
// 2.) if that fails, then do a straight-up copy
// TODO: can optimize by first checking md5sum or
// something before copying
// EEXIST means the file already exists, which isn't
// really a hard link failure ...
if (link(filename, rel_path) && (errno != EEXIST)) {
copy_file(filename, rel_path);
}
delete_path(p);
free(rel_path);
}
}
}
}
child_pcb->state = INUSER;
EXITIF(ptrace(PTRACE_SYSCALL, child_pcb->pid, NULL, NULL) < 0);
break;
default:
assert(0);
break;
}
}
delete_pcb(child_pcb);
}
return 0;
}
|