123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- #include <sys/stat.h>
- #include <sys/wait.h>
- #include <sys/time.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <errno.h>
- #include <libqubes-rpc-filecopy.h>
- #include "dvm2.h"
- #define USER_HOME "/home/user"
- #define TMP_LOC "/tmp/qopen/"
- // #define DEBUG
- static const char *cleanup_filename = NULL;
- static const char *cleanup_dirname = NULL;
- static void cleanup_file(void)
- {
- if (cleanup_filename) {
- if (unlink(cleanup_filename) < 0)
- fprintf(stderr, "Failed to remove file at exit\n");
- cleanup_filename = NULL;
- }
- if (cleanup_dirname) {
- if (rmdir(cleanup_dirname) < 0)
- fprintf(stderr, "Failed to remove directory at exit\n");
- cleanup_dirname = NULL;
- }
- }
- const char *gettime(void)
- {
- static char retbuf[60];
- struct timeval tv;
- gettimeofday(&tv, NULL);
- snprintf(retbuf, sizeof(retbuf), "%lld.%06lld",
- (long long) tv.tv_sec, (long long) tv.tv_usec);
- return retbuf;
- }
- static char *get_directory(void)
- {
- const char *remote_domain;
- char *dir;
- size_t len;
- char *ret;
- remote_domain = getenv("QREXEC_REMOTE_DOMAIN");
- if (!remote_domain) {
- fprintf(stderr, "Cannot get remote domain name\n");
- exit(1);
- }
- if (!*remote_domain || index(remote_domain, '/'))
- goto fail;
- if (!strcmp(remote_domain, ".") || !strcmp(remote_domain, ".."))
- goto fail;
- len = strlen("/tmp/-XXXXXX")+strlen(remote_domain)+1;
- dir = malloc(len);
- if (!dir) {
- fprintf(stderr, "Cannot allocate memory\n");
- exit(1);
- }
- snprintf(dir, len, "/tmp/%s-XXXXXX", remote_domain);
- ret = mkdtemp(dir);
- if (ret == NULL) {
- perror("mkdtemp");
- exit(1);
- }
- cleanup_dirname = strdup(ret);
- return ret;
- fail:
- fprintf(stderr, "Invalid remote domain name: %s\n", remote_domain);
- exit(1);
- }
- char *get_filename(void)
- {
- char buf[DVM_FILENAME_SIZE];
- static char *retname;
- int i;
- char *directory;
- size_t len;
- directory = get_directory();
- if (!read_all(0, buf, sizeof(buf)))
- exit(1);
- buf[DVM_FILENAME_SIZE-1] = 0;
- if (index(buf, '/')) {
- fprintf(stderr, "filename contains /");
- exit(1);
- }
- for (i=0; buf[i]!=0; i++) {
- // replace some characters with _ (eg mimeopen have problems with some of them)
- if (index(" !?\"#$%^&*()[]<>;`~|", buf[i]))
- buf[i]='_';
- }
- len = strlen(directory)+1+strlen(buf)+1;
- retname = malloc(len);
- if (!retname) {
- fprintf(stderr, "Cannot allocate memory\n");
- exit(1);
- }
- snprintf(retname, len, "%s/%s", directory, buf);
- free(directory);
- return retname;
- }
- void copy_file_by_name(const char *filename)
- {
- int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0600);
- if (fd < 0) {
- perror("open file");
- exit(1);
- }
- /* we now have created a new file, ensure we delete it at the end */
- cleanup_filename = strdup(filename);
- atexit(cleanup_file);
- if (!copy_fd_all(fd, 0))
- exit(1);
- close(fd);
- }
- void send_file_back(const char * filename)
- {
- int fd = open(filename, O_RDONLY);
- if (fd < 0) {
- perror("open file");
- exit(1);
- }
- if (!copy_fd_all(1, fd))
- exit(1);
- close(fd);
- close(1);
- }
- int
- main()
- {
- struct stat stat_pre, stat_post, session_stat;
- char *filename = get_filename();
- int child, status, log_fd, null_fd;
- FILE *waiter_pidfile;
- copy_file_by_name(filename);
- if (stat(filename, &stat_pre)) {
- perror("stat pre");
- exit(1);
- }
- #ifdef DEBUG
- fprintf(stderr, "time=%s, waiting for qubes-session\n", gettime());
- #endif
- // wait for X server to starts (especially in DispVM)
- if (stat("/tmp/qubes-session-env", &session_stat)) {
- switch (child = fork()) {
- case -1:
- perror("fork");
- exit(1);
- case 0:
- waiter_pidfile = fopen("/tmp/qubes-session-waiter", "a");
- if (waiter_pidfile == NULL) {
- perror("fopen waiter_pidfile");
- exit(1);
- }
- fprintf(waiter_pidfile, "%d\n", getpid());
- fclose(waiter_pidfile);
- // check the second time, to prevent race
- if (stat("/tmp/qubes-session-env", &session_stat)) {
- // wait for qubes-session notify
- pause();
- }
- exit(0);
- default:
- waitpid(child, &status, 0);
- if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
- //propagate exit code from child
- exit(WEXITSTATUS(status));
- }
- }
- }
- #ifdef DEBUG
- fprintf(stderr, "time=%s, starting editor\n", gettime());
- #endif
- switch (child = fork()) {
- case -1:
- perror("fork");
- exit(1);
- case 0:
- null_fd = open("/dev/null", O_RDONLY);
- dup2(null_fd, 0);
- close(null_fd);
- log_fd = open("/tmp/mimeopen.log", O_CREAT | O_APPEND, 0666);
- if (log_fd == -1) {
- perror("open /tmp/mimeopen.log");
- exit(1);
- }
- dup2(log_fd, 1);
- close(log_fd);
- setenv("HOME", USER_HOME, 1);
- setenv("DISPLAY", ":0", 1);
- execl("/usr/bin/qubes-open", "qubes-open", filename, (char*)NULL);
- perror("execl");
- exit(1);
- default:
- waitpid(child, &status, 0);
- if (status != 0) {
- char cmd[512];
- #ifdef USE_KDIALOG
- snprintf(cmd, sizeof(cmd),
- "HOME=/home/user DISPLAY=:0 /usr/bin/kdialog --sorry 'Unable to handle mimetype of the requested file (exit status: %d)!' > /tmp/kdialog.log 2>&1 </dev/null", status);
- ("HOME=/home/user DISPLAY=:0 /usr/bin/kdialog --sorry 'Unable to handle mimetype of the requested file (exit status: %d)!' > /tmp/kdialog.log 2>&1 </dev/null", status);
- #else
- snprintf(cmd, sizeof(cmd),
- "HOME=/home/user DISPLAY=:0 /usr/bin/zenity --error --text 'Unable to handle mimetype of the requested file (exit status: %d)!' > /tmp/kdialog.log 2>&1 </dev/null", status);
- #endif
- status = system(cmd);
- }
- }
- if (stat(filename, &stat_post)) {
- perror("stat post");
- exit(1);
- }
- if (stat_pre.st_mtime != stat_post.st_mtime)
- send_file_back(filename);
- free(filename);
- return 0;
- }
|