qfile-agent.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #define _GNU_SOURCE
  2. #include <dirent.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <sys/stat.h>
  6. #include <signal.h>
  7. #include <fcntl.h>
  8. #include <malloc.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. #include <errno.h>
  12. #include <gui-fatal.h>
  13. #include <libqubes-rpc-filecopy.h>
  14. enum {
  15. PROGRESS_FLAG_NORMAL,
  16. PROGRESS_FLAG_INIT,
  17. PROGRESS_FLAG_DONE
  18. };
  19. void do_notify_progress(long long total, int flag)
  20. {
  21. const char *du_size_env = getenv("FILECOPY_TOTAL_SIZE");
  22. const char *progress_type_env = getenv("PROGRESS_TYPE");
  23. const char *saved_stdout_env = getenv("SAVED_FD_1");
  24. int ignore;
  25. if (!progress_type_env)
  26. return;
  27. if (!strcmp(progress_type_env, "console") && du_size_env) {
  28. char msg[256];
  29. snprintf(msg, sizeof(msg), "sent %lld/%lld KB\r",
  30. total / 1024, strtoull(du_size_env, NULL, 0));
  31. ignore = write(2, msg, strlen(msg));
  32. if (flag == PROGRESS_FLAG_DONE)
  33. ignore = write(2, "\n", 1);
  34. if (ignore < 0) {
  35. /* silence gcc warning */
  36. }
  37. }
  38. if (!strcmp(progress_type_env, "gui") && saved_stdout_env) {
  39. char msg[256];
  40. snprintf(msg, sizeof(msg), "%lld\n", total);
  41. if (write(strtoul(saved_stdout_env, NULL, 0), msg, strlen(msg)) == -1
  42. && errno == EPIPE)
  43. exit(32);
  44. }
  45. }
  46. void notify_progress(int size, int flag)
  47. {
  48. static long long total = 0;
  49. static long long prev_total = 0;
  50. total += size;
  51. if (total > prev_total + PROGRESS_NOTIFY_DELTA
  52. || (flag != PROGRESS_FLAG_NORMAL)) {
  53. // check for possible error from qfile-unpacker; if error occured,
  54. // exit() will be called, so don't bother with current state
  55. // (notify_progress can be called as callback from copy_file())
  56. if (flag == PROGRESS_FLAG_NORMAL)
  57. wait_for_result();
  58. do_notify_progress(total, flag);
  59. prev_total = total;
  60. }
  61. }
  62. char *get_abs_path(const char *cwd, const char *pathname)
  63. {
  64. char *ret;
  65. if (pathname[0] == '/')
  66. return strdup(pathname);
  67. if (asprintf(&ret, "%s/%s", cwd, pathname) < 0)
  68. return NULL;
  69. else
  70. return ret;
  71. }
  72. int main(int argc, char **argv)
  73. {
  74. int i;
  75. char *entry;
  76. char *cwd;
  77. char *sep;
  78. int ignore_symlinks = 0;
  79. qfile_pack_init();
  80. register_error_handler(qfile_gui_fatal);
  81. register_notify_progress(&notify_progress);
  82. notify_progress(0, PROGRESS_FLAG_INIT);
  83. cwd = getcwd(NULL, 0);
  84. for (i = 1; i < argc; i++) {
  85. if (strcmp(argv[i], "--ignore-symlinks")==0) {
  86. ignore_symlinks = 1;
  87. continue;
  88. }
  89. entry = get_abs_path(cwd, argv[i]);
  90. do {
  91. sep = rindex(entry, '/');
  92. if (!sep)
  93. gui_fatal
  94. ("Internal error: nonabsolute filenames not allowed");
  95. *sep = 0;
  96. } while (sep[1] == 0);
  97. if (entry[0] == 0) {
  98. if (chdir("/") < 0) {
  99. gui_fatal("Internal error: chdir(\"/\") failed?!");
  100. }
  101. } else if (chdir(entry))
  102. gui_fatal("chdir to %s", entry);
  103. do_fs_walk(sep + 1, ignore_symlinks);
  104. free(entry);
  105. }
  106. notify_end_and_wait_for_result();
  107. notify_progress(0, PROGRESS_FLAG_DONE);
  108. return 0;
  109. }