diff options
author | netblue30 <netblue30@yahoo.com> | 2016-09-03 09:48:45 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-09-03 09:48:45 -0400 |
commit | 28699cc5f4bfa8b47697a06ead764e6a54c0e12b (patch) | |
tree | 1b1513853294d49a168c1a824838e3eb6c29e91d | |
parent | Merge pull request #763 from manevich/join (diff) | |
parent | firecfg: small fixes (diff) | |
download | firejail-28699cc5f4bfa8b47697a06ead764e6a54c0e12b.tar.gz firejail-28699cc5f4bfa8b47697a06ead764e6a54c0e12b.tar.zst firejail-28699cc5f4bfa8b47697a06ead764e6a54c0e12b.zip |
Merge pull request #758 from manevich/firecfg
Option to fix .desktop files for firecfg
-rw-r--r-- | src/firecfg/main.c | 171 | ||||
-rw-r--r-- | src/man/firecfg.txt | 12 |
2 files changed, 183 insertions, 0 deletions
diff --git a/src/firecfg/main.c b/src/firecfg/main.c index 9c7c49e1d..3f9285776 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 - skipped, %s not in PATH\n", filename, bname); | ||
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(); |
diff --git a/src/man/firecfg.txt b/src/man/firecfg.txt index 9458c4b67..4acacb071 100644 --- a/src/man/firecfg.txt +++ b/src/man/firecfg.txt | |||
@@ -26,6 +26,9 @@ Print options end exit. | |||
26 | \fB\-\-list | 26 | \fB\-\-list |
27 | List all firejail symbolic links | 27 | List all firejail symbolic links |
28 | .TP | 28 | .TP |
29 | \fB\-\-fix | ||
30 | Fix .desktop files. Some .desktop files use full path to executable. Firecfg will check .desktop files in /usr/share/applications/, replace full path by name if it is in PATH, and write result to $HOME/.local/share/applications/. | ||
31 | .TP | ||
29 | \fB\-\-version | 32 | \fB\-\-version |
30 | Print program version and exit. | 33 | Print program version and exit. |
31 | 34 | ||
@@ -58,6 +61,15 @@ $ sudo firecfg --clean | |||
58 | /usr/local/bin/vlc removed | 61 | /usr/local/bin/vlc removed |
59 | .br | 62 | .br |
60 | [...] | 63 | [...] |
64 | .br | ||
65 | $ firecfg --fix | ||
66 | .br | ||
67 | /home/user/.local/share/applications/chromium.desktop created | ||
68 | .br | ||
69 | /home/user/.local/share/applications/vlc.desktop created | ||
70 | .br | ||
71 | [...] | ||
72 | |||
61 | 73 | ||
62 | .SH LICENSE | 74 | .SH LICENSE |
63 | This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. | 75 | This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. |