aboutsummaryrefslogtreecommitdiffstats
path: root/src/firecfg/main.c
diff options
context:
space:
mode:
authorLibravatar Aleksey Manevich <manevich.aleksey@gmail.com>2016-09-02 14:22:01 +0300
committerLibravatar Aleksey Manevich <manevich.aleksey@gmail.com>2016-09-02 14:22:01 +0300
commitc08a57c8811cbb2868ab448de5b7e7a68e6b0bb4 (patch)
tree78e25c0855eb0ac9289c141168bc62af7b4cf541 /src/firecfg/main.c
parentMerge pull request #752 from reinerh/master (diff)
downloadfirejail-c08a57c8811cbb2868ab448de5b7e7a68e6b0bb4.tar.gz
firejail-c08a57c8811cbb2868ab448de5b7e7a68e6b0bb4.tar.zst
firejail-c08a57c8811cbb2868ab448de5b7e7a68e6b0bb4.zip
firecfg: option to fix .desktop files
Diffstat (limited to 'src/firecfg/main.c')
-rw-r--r--src/firecfg/main.c171
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"
29static int arg_debug = 0; 33static 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
297static 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
288int main(int argc, char **argv) { 455int 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();