#include #include #include #include #include #include #include #include #include "dvm2.h" #define USER_HOME "/home/user" #define MIMEINFO_DATABASES "/usr/share/mime:/usr/local/share:" USER_HOME "/.local/share:/usr/share/qubes/mime-override" char *gettime() { 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; } char *get_filename() { char buf[DVM_FILENAME_SIZE]; static char retname[sizeof(buf) + sizeof("/tmp/")]; int i; if (!read_all(0, buf, sizeof(buf))) exit(1); if (index(buf, '/')) { fprintf(stderr, "filename contains /"); exit(1); } for (i=0; i < DVM_FILENAME_SIZE && buf[i]!=0; i++) { // replace some characters with _ (eg mimeopen have problems with some of them) if (index(" !?\"#$%^&*()[]<>;`~", buf[i])) buf[i]='_'; } snprintf(retname, sizeof(retname), "/tmp/%s", buf); return retname; } void copy_file(char *filename) { int fd = open(filename, O_WRONLY | O_CREAT, 0600); if (fd < 0) { perror("open file"); exit(1); } if (!copy_fd_all(fd, 0)) exit(1); close(fd); } void send_file_back(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); } int main() { struct stat stat_pre, stat_post, session_stat; char *filename = get_filename(); int child, status, log_fd, null_fd; char var[1024], val[4096]; FILE *env_file; FILE *waiter_pidfile; copy_file(filename); if (stat(filename, &stat_pre)) { perror("stat pre"); exit(1); } fprintf(stderr, "time=%s, waiting for qubes-session\n", gettime()); // 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)); } } } fprintf(stderr, "time=%s, starting editor\n", gettime()); 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); env_file = fopen("/tmp/qubes-session-env", "r"); while(fscanf(env_file, "%1024[^=]=%4096[^\n]\n", var, val) == 2) { setenv(var, val, 1); } fclose(env_file); 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/mimeopen", "mimeopen", "-n", "--database", MIMEINFO_DATABASES, 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 /tmp/kdialog.log 2>&1 /tmp/kdialog.log 2>&1