core-agent-linux/qubes-rpc/vm-file-editor.c
Marek Marczykowski-Górecki 8f840e10dc vm-file-editor: add override for mimeinfo *.png entry (#753)
MIME-info database contains multiple entries for *.png, namely image/png
and image/x-apple-ios-png. The later one doesn't have associated handler
program, but this one is selected by mimeopen tool.

Not sure how this tool should behave in case of multiple matches (IOW is
it a bug in File::MimeInfo perl module used by mimeopen).  Instead of
switching to different tool, which probably will break other files
(check #423), add override for this particular file type.
2013-11-14 21:38:27 +01:00

166 lines
4.1 KiB
C

#include <sys/stat.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <ioall.h>
#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.%lld",
(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 </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
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);
return 0;
}