/first-draft/cde.c

https://github.com/rortian/CDE · C · 145 lines · 88 code · 25 blank · 32 comment · 28 complexity · 17da0798fd88a5b19d7ae0c5ed19f3ae MD5 · raw file

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