diff options
author | 2016-09-02 14:22:01 +0300 | |
---|---|---|
committer | 2016-09-02 14:22:01 +0300 | |
commit | c08a57c8811cbb2868ab448de5b7e7a68e6b0bb4 (patch) | |
tree | 78e25c0855eb0ac9289c141168bc62af7b4cf541 | |
parent | Merge pull request #752 from reinerh/master (diff) | |
download | firejail-c08a57c8811cbb2868ab448de5b7e7a68e6b0bb4.tar.gz firejail-c08a57c8811cbb2868ab448de5b7e7a68e6b0bb4.tar.zst firejail-c08a57c8811cbb2868ab448de5b7e7a68e6b0bb4.zip |
firecfg: option to fix .desktop files
-rw-r--r-- | src/firecfg/main.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/src/firecfg/main.c b/src/firecfg/main.c index 9c7c49e1d..8ca56a2ff 100644 --- a/src/firecfg/main.c +++ b/src/firecfg/main.c | |||
@@ -24,7 +24,11 @@ | |||
24 | #include <dirent.h> | 24 | #include <dirent.h> |
25 | #include <sys/types.h> | 25 | #include <sys/types.h> |
26 | #include <sys/stat.h> | 26 | #include <sys/stat.h> |
27 | #include <fcntl.h> | ||
27 | #include <unistd.h> | 28 | #include <unistd.h> |
29 | #include <string.h> | ||
30 | #include <errno.h> | ||
31 | #include <sys/mman.h> | ||
28 | #include "../include/common.h" | 32 | #include "../include/common.h" |
29 | static int arg_debug = 0; | 33 | static int arg_debug = 0; |
30 | 34 | ||
@@ -41,6 +45,7 @@ static void usage(void) { | |||
41 | printf(" --debug - print debug messages.\n\n"); | 45 | printf(" --debug - print debug messages.\n\n"); |
42 | printf(" --help, -? - this help screen.\n\n"); | 46 | printf(" --help, -? - this help screen.\n\n"); |
43 | printf(" --list - list all firejail symbolic links.\n\n"); | 47 | printf(" --list - list all firejail symbolic links.\n\n"); |
48 | printf(" --fix - fix .desktop files.\n\n"); | ||
44 | printf(" --version - print program version and exit.\n\n"); | 49 | printf(" --version - print program version and exit.\n\n"); |
45 | printf("Example:\n\n"); | 50 | printf("Example:\n\n"); |
46 | printf(" $ sudo firecfg\n"); | 51 | printf(" $ sudo firecfg\n"); |
@@ -55,6 +60,10 @@ static void usage(void) { | |||
55 | printf(" /usr/local/bin/firefox removed\n"); | 60 | printf(" /usr/local/bin/firefox removed\n"); |
56 | printf(" /usr/local/bin/vlc removed\n"); | 61 | printf(" /usr/local/bin/vlc removed\n"); |
57 | printf(" [...]\n"); | 62 | printf(" [...]\n"); |
63 | printf(" $ firecfg --fix\n"); | ||
64 | printf(" /home/user/.local/share/applications/chromium.desktop created\n"); | ||
65 | printf(" /home/user/.local/share/applications/vlc.desktop created\n"); | ||
66 | printf(" [...]\n"); | ||
58 | printf("\n"); | 67 | printf("\n"); |
59 | printf("License GPL version 2 or later\n"); | 68 | printf("License GPL version 2 or later\n"); |
60 | printf("Homepage: http://firejail.wordpress.com\n\n"); | 69 | printf("Homepage: http://firejail.wordpress.com\n\n"); |
@@ -285,6 +294,164 @@ static void set(void) { | |||
285 | free(firejail_exec); | 294 | free(firejail_exec); |
286 | } | 295 | } |
287 | 296 | ||
297 | static void fix_desktop_files(void) { | ||
298 | if (getuid() == 0) { | ||
299 | fprintf(stderr, "Error: you should run --fix as user\n"); | ||
300 | exit(1); | ||
301 | } | ||
302 | |||
303 | char *homedir = getenv("HOME"); | ||
304 | if (!homedir) | ||
305 | errExit("getenv"); | ||
306 | |||
307 | char *user_apps_dir; | ||
308 | if (asprintf(&user_apps_dir, "%s/.local/share/applications", homedir) == -1) | ||
309 | errExit("asprintf"); | ||
310 | |||
311 | DIR *dir = opendir("/usr/share/applications"); | ||
312 | if (!dir) { | ||
313 | perror("Error: cannot open /usr/share/applications directory"); | ||
314 | exit(1); | ||
315 | } | ||
316 | |||
317 | if (chdir("/usr/share/applications")) { | ||
318 | perror("Error: cannot chdir to /usr/share/applications"); | ||
319 | exit(1); | ||
320 | } | ||
321 | |||
322 | struct dirent *entry; | ||
323 | while ((entry = readdir(dir)) != NULL) { | ||
324 | if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) | ||
325 | continue; | ||
326 | |||
327 | // skip if not regular file or link | ||
328 | if (entry->d_type != DT_REG && entry->d_type != DT_LNK) | ||
329 | continue; | ||
330 | |||
331 | // skip if not .desktop file | ||
332 | if (strstr(entry->d_name,".desktop") != (entry->d_name+strlen(entry->d_name)-8)) | ||
333 | continue; | ||
334 | |||
335 | char *filename = entry->d_name; | ||
336 | |||
337 | // skip links | ||
338 | if (is_link(filename)) | ||
339 | continue; | ||
340 | |||
341 | struct stat sb; | ||
342 | if (stat(filename, &sb) == -1) | ||
343 | errExit("stat"); | ||
344 | |||
345 | int fd = open(filename, O_RDONLY); | ||
346 | if (fd == -1) | ||
347 | errExit("open"); | ||
348 | |||
349 | char *buf = mmap(NULL, sb.st_size + 1, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); | ||
350 | if (buf == MAP_FAILED) | ||
351 | errExit("mmap"); | ||
352 | |||
353 | close(fd); | ||
354 | |||
355 | // check format | ||
356 | if (strstr(buf, "[Desktop Entry]\n") == NULL) { | ||
357 | if (arg_debug) | ||
358 | fprintf(stderr, "/usr/share/applications/%s - SKIPPED: wrong format?\n", filename); | ||
359 | munmap(buf, sb.st_size + 1); | ||
360 | continue; | ||
361 | } | ||
362 | |||
363 | // get executable name | ||
364 | char *ptr1 = strstr(buf,"\nExec="); | ||
365 | if (!ptr1 || strlen(ptr1) < 7) { | ||
366 | if (arg_debug) | ||
367 | fprintf(stderr, "/usr/share/applications/%s - SKIPPED: wrong format?\n", filename); | ||
368 | munmap(buf, sb.st_size + 1); | ||
369 | continue; | ||
370 | } | ||
371 | |||
372 | char *execname = ptr1 + 6; | ||
373 | // https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html | ||
374 | // The executable program can either be specified with its full path | ||
375 | // or with the name of the executable only | ||
376 | if (execname[0] != '/') { | ||
377 | if (arg_debug) | ||
378 | fprintf(stderr, "/usr/share/applications/%s - already OK\n", filename); | ||
379 | continue; | ||
380 | } | ||
381 | // executable name can be quoted, this is rare and currently unsupported, TODO | ||
382 | if (execname[0] == '"') { | ||
383 | if (arg_debug) | ||
384 | fprintf(stderr, "/usr/share/applications/%s - skipped: path quoting unsupported\n", filename); | ||
385 | continue; | ||
386 | } | ||
387 | |||
388 | // put '\0' at end of filename | ||
389 | char *tail = NULL; | ||
390 | char endchar; | ||
391 | if (execname[0] == '/') { | ||
392 | char *ptr2 = index(execname, ' '); | ||
393 | char *ptr3 = index(execname, '\n'); | ||
394 | if (ptr2 && (!ptr3 || (ptr2 < ptr3))) { | ||
395 | endchar = ptr2[0]; | ||
396 | ptr2[0] = '\0'; | ||
397 | tail = ptr2 + 1; | ||
398 | } else if (ptr3 && (!ptr2 || (ptr3 < ptr2))) { | ||
399 | endchar = ptr3[0]; | ||
400 | ptr3[0] = '\0'; | ||
401 | tail = ptr3 + 1; | ||
402 | } | ||
403 | ptr1[5] = '\0'; | ||
404 | } | ||
405 | |||
406 | char *bname = basename(execname); | ||
407 | assert(bname); | ||
408 | |||
409 | // check if basename in PATH | ||
410 | if (!which(bname)) { | ||
411 | fprintf(stderr, "/usr/share/applications/%s - unable to fix: executable not in PATH\n", filename); | ||
412 | continue; | ||
413 | } | ||
414 | |||
415 | char *outname; | ||
416 | if (asprintf(&outname ,"%s/%s", user_apps_dir, filename) == -1) | ||
417 | errExit("asprintf"); | ||
418 | |||
419 | int fd1 = open(outname, O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR); | ||
420 | free(outname); | ||
421 | |||
422 | if (fd1 == -1) { | ||
423 | fprintf(stderr, "%s/%s skipped: %s\n", user_apps_dir, filename, strerror(errno)); | ||
424 | munmap(buf, sb.st_size + 1); | ||
425 | continue; | ||
426 | } | ||
427 | |||
428 | FILE *outfile = fdopen(fd1, "w"); | ||
429 | if (!outfile) { | ||
430 | fprintf(stderr, "%s/%s skipped: %s\n", user_apps_dir, filename, strerror(errno)); | ||
431 | munmap(buf, sb.st_size + 1); | ||
432 | close(fd1); | ||
433 | continue; | ||
434 | } | ||
435 | |||
436 | if (fprintf(outfile,\ | ||
437 | "# Converted by firecfg --fix from /usr/share/applications/%s\n\n%s=%s%c%s",\ | ||
438 | filename, buf, bname, endchar, tail) < 0) { | ||
439 | fprintf(stderr, "Unable to write %s/%s: %s\n", user_apps_dir, filename, strerror(errno)); | ||
440 | munmap(buf, sb.st_size + 1); | ||
441 | fclose(outfile); | ||
442 | continue; | ||
443 | } | ||
444 | |||
445 | fclose(outfile); | ||
446 | munmap(buf, sb.st_size + 1); | ||
447 | |||
448 | printf("%s/%s created\n", user_apps_dir, filename); | ||
449 | } | ||
450 | |||
451 | closedir(dir); | ||
452 | free(user_apps_dir); | ||
453 | } | ||
454 | |||
288 | int main(int argc, char **argv) { | 455 | int main(int argc, char **argv) { |
289 | int i; | 456 | int i; |
290 | 457 | ||
@@ -309,6 +476,10 @@ int main(int argc, char **argv) { | |||
309 | list(); | 476 | list(); |
310 | return 0; | 477 | return 0; |
311 | } | 478 | } |
479 | else if (strcmp(argv[i], "--fix") == 0) { | ||
480 | fix_desktop_files(); | ||
481 | return 0; | ||
482 | } | ||
312 | else { | 483 | else { |
313 | fprintf(stderr, "Error: invalid command line option\n"); | 484 | fprintf(stderr, "Error: invalid command line option\n"); |
314 | usage(); | 485 | usage(); |