aboutsummaryrefslogtreecommitdiffstats
path: root/src/firecfg/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firecfg/main.c')
-rw-r--r--src/firecfg/main.c194
1 files changed, 187 insertions, 7 deletions
diff --git a/src/firecfg/main.c b/src/firecfg/main.c
index 70d29a3ed..d2566ce22 100644
--- a/src/firecfg/main.c
+++ b/src/firecfg/main.c
@@ -24,8 +24,13 @@
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"
33static int arg_debug = 0;
29 34
30static void usage(void) { 35static void usage(void) {
31 printf("firecfg - version %s\n\n", VERSION); 36 printf("firecfg - version %s\n\n", VERSION);
@@ -37,8 +42,10 @@ static void usage(void) {
37 printf("DESKTOP INTEGRATION section in man 1 firejail.\n\n"); 42 printf("DESKTOP INTEGRATION section in man 1 firejail.\n\n");
38 printf("Usage: firecfg [OPTIONS]\n\n"); 43 printf("Usage: firecfg [OPTIONS]\n\n");
39 printf(" --clean - remove all firejail symbolic links.\n\n"); 44 printf(" --clean - remove all firejail symbolic links.\n\n");
45 printf(" --debug - print debug messages.\n\n");
40 printf(" --help, -? - this help screen.\n\n"); 46 printf(" --help, -? - this help screen.\n\n");
41 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");
42 printf(" --version - print program version and exit.\n\n"); 49 printf(" --version - print program version and exit.\n\n");
43 printf("Example:\n\n"); 50 printf("Example:\n\n");
44 printf(" $ sudo firecfg\n"); 51 printf(" $ sudo firecfg\n");
@@ -49,10 +56,14 @@ static void usage(void) {
49 printf(" /usr/local/bin/firefox\n"); 56 printf(" /usr/local/bin/firefox\n");
50 printf(" /usr/local/bin/vlc\n"); 57 printf(" /usr/local/bin/vlc\n");
51 printf(" [...]\n"); 58 printf(" [...]\n");
52 printf(" $ sudo firecfg --clear\n"); 59 printf(" $ sudo firecfg --clean\n");
53 printf(" /usr/local/bin/firefox removed\n"); 60 printf(" /usr/local/bin/firefox removed\n");
54 printf(" /usr/local/bin/vlc removed\n"); 61 printf(" /usr/local/bin/vlc removed\n");
55 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");
56 printf("\n"); 67 printf("\n");
57 printf("License GPL version 2 or later\n"); 68 printf("License GPL version 2 or later\n");
58 printf("Homepage: http://firejail.wordpress.com\n\n"); 69 printf("Homepage: http://firejail.wordpress.com\n\n");
@@ -67,9 +78,12 @@ static int find(const char *program, const char *directory) {
67 errExit("asprintf"); 78 errExit("asprintf");
68 79
69 struct stat s; 80 struct stat s;
70 if (stat(fname, &s) == 0) 81 if (stat(fname, &s) == 0) {
82 if (arg_debug)
83 printf("found %s in directory %s\n", program, directory);
71 retval = 1; 84 retval = 1;
72 85 }
86
73 free(fname); 87 free(fname);
74 return retval; 88 return retval;
75} 89}
@@ -79,7 +93,8 @@ static int find(const char *program, const char *directory) {
79static int which(const char *program) { 93static int which(const char *program) {
80 // check some well-known paths 94 // check some well-known paths
81 if (find(program, "/bin") || find(program, "/usr/bin") || 95 if (find(program, "/bin") || find(program, "/usr/bin") ||
82 find(program, "/sbin") || find(program, "/usr/sbin")) 96 find(program, "/sbin") || find(program, "/usr/sbin") ||
97 find(program, "/usr/games"))
83 return 1; 98 return 1;
84 99
85 // check environment 100 // check environment
@@ -205,8 +220,9 @@ static void set_file(const char *name, const char *firejail_exec) {
205 errExit("asprintf"); 220 errExit("asprintf");
206 221
207 struct stat s; 222 struct stat s;
208 if (stat(fname, &s) == 0) 223 if (stat(fname, &s) == 0) {
209 ; //printf("%s already present\n", fname); 224 printf("%s is already present, skipping...\n", fname);
225 }
210 else { 226 else {
211 int rv = symlink(firejail_exec, fname); 227 int rv = symlink(firejail_exec, fname);
212 if (rv) { 228 if (rv) {
@@ -268,7 +284,7 @@ static void set(void) {
268 // empty line 284 // empty line
269 if (*start == '\0') 285 if (*start == '\0')
270 continue; 286 continue;
271 287
272 // set link 288 // set link
273 set_file(start, firejail_exec); 289 set_file(start, firejail_exec);
274 } 290 }
@@ -278,6 +294,164 @@ static void set(void) {
278 free(firejail_exec); 294 free(firejail_exec);
279} 295}
280 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 - 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
281int main(int argc, char **argv) { 455int main(int argc, char **argv) {
282 int i; 456 int i;
283 457
@@ -288,6 +462,8 @@ int main(int argc, char **argv) {
288 usage(); 462 usage();
289 return 0; 463 return 0;
290 } 464 }
465 else if (strcmp(argv[i], "--debug") == 0)
466 arg_debug = 1;
291 else if (strcmp(argv[i], "--version") == 0) { 467 else if (strcmp(argv[i], "--version") == 0) {
292 printf("firecfg version %s\n\n", VERSION); 468 printf("firecfg version %s\n\n", VERSION);
293 return 0; 469 return 0;
@@ -300,6 +476,10 @@ int main(int argc, char **argv) {
300 list(); 476 list();
301 return 0; 477 return 0;
302 } 478 }
479 else if (strcmp(argv[i], "--fix") == 0) {
480 fix_desktop_files();
481 return 0;
482 }
303 else { 483 else {
304 fprintf(stderr, "Error: invalid command line option\n"); 484 fprintf(stderr, "Error: invalid command line option\n");
305 usage(); 485 usage();