]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - LinuxGUI/Ventoy2Disk/ventoy_gui.c
Optimization for Ventoy2Disk.exe
[Ventoy.git] / LinuxGUI / Ventoy2Disk / ventoy_gui.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <string.h>
5 #include <stdarg.h>
6 #include <unistd.h>
7 #include <errno.h>
8 #include <time.h>
9 #include <dirent.h>
10 #include <sys/utsname.h>
11 #include <sys/types.h>
12 #include <linux/limits.h>
13 #include <sys/stat.h>
14 #include <sys/fcntl.h>
15 #include <sys/mman.h>
16 #include "ventoy_json.h"
17
18 #define LIB_FLAG_GTK2 (1 << 0)
19 #define LIB_FLAG_GTK3 (1 << 1)
20 #define LIB_FLAG_GTK4 (1 << 2)
21 #define LIB_FLAG_QT4 (1 << 3)
22 #define LIB_FLAG_QT5 (1 << 4)
23 #define LIB_FLAG_QT6 (1 << 5)
24 #define LIB_FLAG_GLADE2 (1 << 30)
25
26 #define LIB_FLAG_GTK (LIB_FLAG_GTK2 | LIB_FLAG_GTK3 | LIB_FLAG_GTK4)
27 #define LIB_FLAG_QT (LIB_FLAG_QT4 | LIB_FLAG_QT5 | LIB_FLAG_QT6)
28
29 #define MAX_PARAS 64
30 #define MAX_LOG_BUF (1024 * 1024)
31 #define VTOY_GUI_PATH "_vtoy_gui_path_="
32 #define VTOY_ENV_STR "_vtoy_env_str_="
33 #define LD_CACHE_FILE "/etc/ld.so.cache"
34 #define INT2STR_YN(a) ((a) == 0 ? "NO" : "YES")
35
36 static int g_xdg_log = 0;
37 static int g_xdg_ini = 0;
38 static char g_log_file[PATH_MAX];
39 static char g_ini_file[PATH_MAX];
40 static char *g_log_buf = NULL;
41 extern char ** environ;
42
43 #define CACHEMAGIC "ld.so-1.7.0"
44
45 struct file_entry
46 {
47 int flags; /* This is 1 for an ELF library. */
48 unsigned int key, value; /* String table indices. */
49 };
50
51 struct cache_file
52 {
53 char magic[sizeof CACHEMAGIC - 1];
54 unsigned int nlibs;
55 struct file_entry libs[0];
56 };
57
58 #define CACHEMAGIC_NEW "glibc-ld.so.cache"
59 #define CACHE_VERSION "1.1"
60 #define CACHEMAGIC_VERSION_NEW CACHEMAGIC_NEW CACHE_VERSION
61
62 struct file_entry_new
63 {
64 int32_t flags; /* This is 1 for an ELF library. */
65 uint32_t key, value; /* String table indices. */
66 uint32_t osversion; /* Required OS version. */
67 uint64_t hwcap; /* Hwcap entry. */
68 };
69
70 struct cache_file_new
71 {
72 char magic[sizeof CACHEMAGIC_NEW - 1];
73 char version[sizeof CACHE_VERSION - 1];
74 uint32_t nlibs; /* Number of entries. */
75 uint32_t len_strings; /* Size of string table. */
76 uint32_t unused[5]; /* Leave space for future extensions
77 and align to 8 byte boundary. */
78 struct file_entry_new libs[0]; /* Entries describing libraries. */
79 /* After this the string table of size len_strings is found. */
80 };
81
82 /* Used to align cache_file_new. */
83 #define ALIGN_CACHE(addr) \
84 (((addr) + __alignof__ (struct cache_file_new) -1) \
85 & (~(__alignof__ (struct cache_file_new) - 1)))
86
87 #define vlog(fmt, args...) ventoy_syslog(0, fmt, ##args)
88
89 void ventoy_syslog(int level, const char *Fmt, ...)
90 {
91 int buflen;
92 char *buf = NULL;
93 char log[512];
94 va_list arg;
95 time_t stamp;
96 struct tm ttm;
97 FILE *fp;
98
99 (void)level;
100
101 time(&stamp);
102 localtime_r(&stamp, &ttm);
103
104 if (g_log_buf)
105 {
106 buf = g_log_buf;
107 buflen = MAX_LOG_BUF;
108 }
109 else
110 {
111 buf = log;
112 buflen = sizeof(log);
113 }
114
115 va_start(arg, Fmt);
116 vsnprintf(buf, buflen, Fmt, arg);
117 va_end(arg);
118
119 fp = fopen(g_log_file, "a+");
120 if (fp)
121 {
122 fprintf(fp, "[%04u/%02u/%02u %02u:%02u:%02u] %s",
123 ttm.tm_year + 1900, ttm.tm_mon, ttm.tm_mday,
124 ttm.tm_hour, ttm.tm_min, ttm.tm_sec,
125 buf);
126 fclose(fp);
127 }
128
129 #if 0
130 printf("[%04u/%02u/%02u %02u:%02u:%02u] %s",
131 ttm.tm_year + 1900, ttm.tm_mon, ttm.tm_mday,
132 ttm.tm_hour, ttm.tm_min, ttm.tm_sec,
133 buf);
134 #endif
135 }
136
137 static int is_gtk_env(void)
138 {
139 const char *env = NULL;
140
141 env = getenv("GNOME_SETUP_DISPLAY");
142 if (env && env[0] == ':')
143 {
144 vlog("GNOME_SETUP_DISPLAY=%s\n", env);
145 return 1;
146 }
147
148 env = getenv("DESKTOP_SESSION");
149 if (env && strcasecmp(env, "xfce") == 0)
150 {
151 vlog("DESKTOP_SESSION=%s\n", env);
152 return 1;
153 }
154
155 return 0;
156 }
157
158 static int is_qt_env(void)
159 {
160 return 0;
161 }
162
163 static int detect_gtk_version(int libflag)
164 {
165 int gtk2;
166 int gtk3;
167 int gtk4;
168 int glade2;
169
170 gtk2 = libflag & LIB_FLAG_GTK2;
171 gtk3 = libflag & LIB_FLAG_GTK3;
172 gtk4 = libflag & LIB_FLAG_GTK4;
173 glade2 = libflag & LIB_FLAG_GLADE2;
174
175 if (gtk2 > 0 && glade2 > 0 && (gtk3 == 0 && gtk4 == 0))
176 {
177 return 2;
178 }
179
180 if (gtk3 > 0 && (gtk2 == 0 && gtk4 == 0))
181 {
182 return 3;
183 }
184
185 if (gtk4 > 0 && (gtk2 == 0 && gtk3 == 0))
186 {
187 return 4;
188 }
189
190 if (gtk3 > 0)
191 {
192 return 3;
193 }
194
195 if (gtk4 > 0)
196 {
197 return 4;
198 }
199
200 if (gtk2 > 0 && glade2 > 0)
201 {
202 return 2;
203 }
204
205 return 0;
206 }
207
208 static int detect_qt_version(int libflag)
209 {
210 int qt4;
211 int qt5;
212 int qt6;
213
214 qt4 = libflag & LIB_FLAG_QT4;
215 qt5 = libflag & LIB_FLAG_QT5;
216 qt6 = libflag & LIB_FLAG_QT6;
217
218 if (qt4 > 0 && (qt5 == 0 && qt6 == 0))
219 {
220 return 4;
221 }
222
223 if (qt5 > 0 && (qt4 == 0 && qt6 == 0))
224 {
225 return 5;
226 }
227
228 if (qt6 > 0 && (qt4 == 0 && qt5 == 0))
229 {
230 return 6;
231 }
232
233 if (qt5 > 0)
234 {
235 return 5;
236 }
237
238 if (qt6 > 0)
239 {
240 return 6;
241 }
242
243 if (qt4 > 0)
244 {
245 return 4;
246 }
247
248 return 0;
249 }
250
251 int bit_from_machine(const char *machine)
252 {
253 if (strstr(machine, "64"))
254 {
255 return 64;
256 }
257 else
258 {
259 return 32;
260 }
261 }
262
263 int get_os_bit(int *bit)
264 {
265 int ret;
266 struct utsname unameData;
267
268 memset(&unameData, 0, sizeof(unameData));
269 ret = uname(&unameData);
270 if (ret != 0)
271 {
272 vlog("uname error, code: %d\n", errno);
273 return 1;
274 }
275
276 *bit = strstr(unameData.machine, "64") ? 64 : 32;
277 vlog("uname -m <%s> %dbit\n", unameData.machine, *bit);
278
279 return 0;
280 }
281
282 int read_file_1st_line(const char *file, char *buffer, int buflen)
283 {
284 FILE *fp = NULL;
285
286 fp = fopen(file, "r");
287 if (fp == NULL)
288 {
289 vlog("Failed to open file %s code:%d", file, errno);
290 return 1;
291 }
292
293 fgets(buffer, buflen, fp);
294 fclose(fp);
295 return 0;
296 }
297
298 static int read_pid_cmdline(long pid, char *Buffer, int BufLen)
299 {
300 char path[256];
301
302 snprintf(path, sizeof(path), "/proc/%ld/cmdline", pid);
303 return read_file_1st_line(path, Buffer, BufLen);
304 }
305
306 static int find_exe_path(const char *exe, char *pathbuf, int buflen)
307 {
308 int i;
309 char path[PATH_MAX];
310 char *tmpptr = NULL;
311 char *saveptr = NULL;
312 char *newenv = NULL;
313 const char *env = getenv("PATH");
314
315 if (NULL == env)
316 {
317 return 0;
318 }
319
320 newenv = strdup(env);
321 if (!newenv)
322 {
323 return 0;
324 }
325
326 tmpptr = newenv;
327 while (NULL != (tmpptr = strtok_r(tmpptr, ":", &saveptr)))
328 {
329 snprintf(path, sizeof(path), "%s/%s", tmpptr, exe);
330 if (access(path, F_OK) != -1)
331 {
332 snprintf(pathbuf, buflen, "%s", path);
333 free(newenv);
334 return 1;
335 }
336 tmpptr = NULL;
337 }
338
339 free(newenv);
340 return 0;
341 }
342
343 void dump_args(const char *prefix, char **argv)
344 {
345 int i = 0;
346
347 vlog("=========%s ARGS BEGIN===========\n", prefix);
348 while (argv[i])
349 {
350 vlog("argv[%d]=<%s>\n", i, argv[i]);
351 i++;
352 }
353 vlog("=========%s ARGS END===========\n", prefix);
354 }
355
356 int pre_check(void)
357 {
358 int ret;
359 int bit;
360 int buildbit;
361 const char *env = NULL;
362
363 env = getenv("DISPLAY");
364 if (NULL == env || env[0] != ':')
365 {
366 vlog("DISPLAY not exist(%p). Not in X environment.\n", env);
367 return 1;
368 }
369
370 ret = get_os_bit(&bit);
371 if (ret)
372 {
373 vlog("Failed to get os bit.\n");
374 return 1;
375 }
376
377 buildbit = strstr(VTOY_GUI_ARCH, "64") ? 64 : 32;
378 vlog("Build bit is %d (%s)\n", buildbit, VTOY_GUI_ARCH);
379
380 if (bit != buildbit)
381 {
382 vlog("Current system is %d bit (%s). Please run the correct VentoyGUI.\n", bit, VTOY_GUI_ARCH);
383 return 1;
384 }
385
386 return 0;
387 }
388
389 static char * find_argv(int argc, char **argv, char *key)
390 {
391 int i;
392 int len;
393
394 len = (int)strlen(key);
395 for (i = 0; i < argc; i++)
396 {
397 if (strncmp(argv[i], key, len) == 0)
398 {
399 return argv[i];
400 }
401 }
402
403 return NULL;
404 }
405
406 static int adjust_cur_dir(char *argv0)
407 {
408 int ret = 2;
409 char c;
410 char *pos = NULL;
411 char *end = NULL;
412
413 if (argv0[0] == '.')
414 {
415 return 1;
416 }
417
418 for (pos = argv0; pos && *pos; pos++)
419 {
420 if (*pos == '/')
421 {
422 end = pos;
423 }
424 }
425
426 if (end)
427 {
428 c = *end;
429 *end = 0;
430 ret = chdir(argv0);
431 *end = c;
432 }
433
434 return ret;
435 }
436
437
438
439 static char **recover_environ_param(char *env)
440 {
441 int i = 0;
442 int j = 0;
443 int k = 0;
444 int cnt = 0;
445 char **newenvs = NULL;
446
447 for (i = 0; env[i]; i++)
448 {
449 if (env[i] == '\n')
450 {
451 cnt++;
452 }
453 }
454
455 newenvs = malloc(sizeof(char *) * (cnt + 1));
456 if (!newenvs)
457 {
458 vlog("malloc new envs fail %d\n", cnt + 1);
459 return NULL;
460 }
461 memset(newenvs, 0, sizeof(char *) * (cnt + 1));
462
463 for (j = i = 0; env[i]; i++)
464 {
465 if (env[i] == '\n')
466 {
467 env[i] = 0;
468 newenvs[k++] = env + j;
469 j = i + 1;
470 }
471 }
472
473 vlog("recover environ %d %d\n", cnt, k);
474 return newenvs;
475 }
476
477 static int restart_main(int argc, char **argv, char *guiexe)
478 {
479 int i = 0;
480 int j = 0;
481 char *para = NULL;
482 char **envs = NULL;
483 char *newargv[MAX_PARAS + 1] = { NULL };
484
485 para = find_argv(argc, argv, VTOY_ENV_STR);
486 if (!para)
487 {
488 vlog("failed to find %s\n", VTOY_ENV_STR);
489 return 1;
490 }
491
492 newargv[j++] = guiexe;
493 for (i = 1; i < argc && j < MAX_PARAS; i++)
494 {
495 if (strncmp(argv[i], "_vtoy_", 6) != 0)
496 {
497 newargv[j++] = argv[i];
498 }
499 }
500
501 envs = recover_environ_param(para + strlen(VTOY_ENV_STR));
502 if (envs)
503 {
504 vlog("recover success, argc=%d evecve <%s>\n", j, guiexe);
505 dump_args("EXECVE", newargv);
506 execve(guiexe, newargv, envs);
507 }
508 else
509 {
510 vlog("recover failed, argc=%d evecv <%s>\n", j, guiexe);
511 execv(guiexe, newargv);
512 }
513
514 return 1;
515 }
516
517 static char *create_environ_param(const char *prefix, char **envs)
518 {
519 int i = 0;
520 int cnt = 0;
521 int envlen = 0;
522 int prelen = 0;
523 char *cur = NULL;
524 char *para = NULL;
525
526 prelen = strlen(prefix);
527 for (i = 0; envs[i]; i++)
528 {
529 cnt++;
530 envlen += strlen(envs[i]) + 1;
531 }
532
533 para = malloc(prelen + envlen);
534 if (!para)
535 {
536 vlog("failed to malloc env str %d\n", prelen + envlen);
537 return NULL;
538 }
539
540 cur = para;
541 memcpy(cur, prefix, prelen);
542 cur += prelen;
543
544 for (i = 0; envs[i]; i++)
545 {
546 envlen = strlen(envs[i]);
547 memcpy(cur, envs[i], envlen);
548
549 cur[envlen] = '\n';
550 cur += envlen + 1;
551 }
552
553 vlog("create environment param %d\n", cnt);
554 return para;
555 }
556
557 static int restart_by_pkexec(int argc, char **argv, const char *curpath, const char *exe)
558 {
559 int i = 0;
560 int j = 0;
561 char envcount[64];
562 char path[PATH_MAX];
563 char pkexec[PATH_MAX];
564 char exepara[PATH_MAX];
565 char *newargv[MAX_PARAS + 1] = { NULL };
566
567 vlog("try restart self by pkexec ...\n");
568
569 if (find_exe_path("pkexec", pkexec, sizeof(pkexec)))
570 {
571 vlog("Find pkexec at <%s>\n", pkexec);
572 }
573 else
574 {
575 vlog("pkexec not found\n");
576 return 1;
577 }
578
579 if (argv[0][0] != '/')
580 {
581 snprintf(path, sizeof(path), "%s/%s", curpath, argv[0]);
582 }
583 else
584 {
585 snprintf(path, sizeof(path), "%s", argv[0]);
586 }
587 snprintf(exepara, sizeof(exepara), "%s%s", VTOY_GUI_PATH, exe);
588
589 newargv[j++] = pkexec;
590 newargv[j++] = path;
591 for (i = 1; i < argc && j < MAX_PARAS; i++)
592 {
593 if (strcmp(argv[i], "--xdg") == 0)
594 {
595 continue;
596 }
597 newargv[j++] = argv[i];
598 }
599
600 if (j < MAX_PARAS)
601 {
602 newargv[j++] = create_environ_param(VTOY_ENV_STR, environ);
603 }
604
605 if (j < MAX_PARAS)
606 {
607 newargv[j++] = exepara;
608 }
609
610 if (g_xdg_log && j + 1 < MAX_PARAS)
611 {
612 newargv[j++] = "-l";
613 newargv[j++] = g_log_file;
614 }
615
616 if (g_xdg_ini && j + 1 < MAX_PARAS)
617 {
618 newargv[j++] = "-i";
619 newargv[j++] = g_ini_file;
620 }
621
622 dump_args("PKEXEC", newargv);
623 execv(pkexec, newargv);
624
625 return 1;
626 }
627
628 static int ld_cache_lib_check(const char *lib, int *flag)
629 {
630 if (((*flag) & LIB_FLAG_GTK3) == 0)
631 {
632 if (strncmp(lib, "libgtk-3.so", 11) == 0)
633 {
634 vlog("LIB:<%s>\n", lib);
635 *flag |= LIB_FLAG_GTK3;
636 return 0;
637 }
638 }
639
640 if (((*flag) & LIB_FLAG_GTK2) == 0)
641 {
642 if (strncmp(lib, "libgtk-x11-2.0.so", 17) == 0)
643 {
644 vlog("LIB:<%s>\n", lib);
645 *flag |= LIB_FLAG_GTK2;
646 return 0;
647 }
648 }
649
650 if (((*flag) & LIB_FLAG_GTK4) == 0)
651 {
652 if (strncmp(lib, "libgtk-4.so", 11) == 0)
653 {
654 vlog("LIB:<%s>\n", lib);
655 *flag |= LIB_FLAG_GTK4;
656 return 0;
657 }
658 }
659
660 if (((*flag) & LIB_FLAG_QT4) == 0)
661 {
662 if (strncmp(lib, "libQt4", 6) == 0)
663 {
664 vlog("LIB:<%s>\n", lib);
665 *flag |= LIB_FLAG_QT4;
666 return 0;
667 }
668 }
669
670 if (((*flag) & LIB_FLAG_QT5) == 0)
671 {
672 if (strncmp(lib, "libQt5", 6) == 0)
673 {
674 vlog("LIB:<%s>\n", lib);
675 *flag |= LIB_FLAG_QT5;
676 return 0;
677 }
678 }
679
680 if (((*flag) & LIB_FLAG_QT6) == 0)
681 {
682 if (strncmp(lib, "libQt6", 6) == 0)
683 {
684 vlog("LIB:<%s>\n", lib);
685 *flag |= LIB_FLAG_QT6;
686 return 0;
687 }
688 }
689
690 if (((*flag) & LIB_FLAG_GLADE2) == 0)
691 {
692 if (strncmp(lib, "libglade-2", 10) == 0)
693 {
694 vlog("LIB:<%s>\n", lib);
695 *flag |= LIB_FLAG_GLADE2;
696 return 0;
697 }
698 }
699
700 return 0;
701 }
702
703 static int parse_ld_cache(int *flag)
704 {
705 int fd;
706 int format;
707 unsigned int i;
708 struct stat st;
709 size_t offset = 0;
710 size_t cache_size = 0;
711 const char *cache_data = NULL;
712 struct cache_file *cache = NULL;
713 struct cache_file_new *cache_new = NULL;
714
715 *flag = 0;
716
717 fd = open(LD_CACHE_FILE, O_RDONLY);
718 if (fd < 0)
719 {
720 vlog("failed to open %s err:%d\n", LD_CACHE_FILE, errno);
721 return 1;
722 }
723
724 if (fstat(fd, &st) < 0 || st.st_size == 0)
725 {
726 close(fd);
727 return 1;
728 }
729
730 cache = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
731 if (cache == MAP_FAILED)
732 {
733 close(fd);
734 return 1;
735 }
736
737 cache_size = st.st_size;
738 if (cache_size < sizeof (struct cache_file))
739 {
740 vlog("File is not a cache file.\n");
741 munmap (cache, cache_size);
742 close(fd);
743 return 1;
744 }
745
746 if (memcmp(cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
747 {
748 /* This can only be the new format without the old one. */
749 cache_new = (struct cache_file_new *) cache;
750
751 if (memcmp(cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1) ||
752 memcmp (cache_new->version, CACHE_VERSION, sizeof CACHE_VERSION - 1))
753 {
754 munmap (cache, cache_size);
755 close(fd);
756 return 1;
757 }
758
759 format = 1;
760 /* This is where the strings start. */
761 cache_data = (const char *) cache_new;
762 }
763 else
764 {
765 /* Check for corruption, avoiding overflow. */
766 if ((cache_size - sizeof (struct cache_file)) / sizeof (struct file_entry) < cache->nlibs)
767 {
768 vlog("File is not a cache file.\n");
769 munmap (cache, cache_size);
770 close(fd);
771 return 1;
772 }
773
774 offset = ALIGN_CACHE(sizeof (struct cache_file) + (cache->nlibs * sizeof (struct file_entry)));
775
776 /* This is where the strings start. */
777 cache_data = (const char *) &cache->libs[cache->nlibs];
778
779 /* Check for a new cache embedded in the old format. */
780 if (cache_size > (offset + sizeof (struct cache_file_new)))
781 {
782 cache_new = (struct cache_file_new *) ((void *)cache + offset);
783
784 if (memcmp(cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1) == 0 &&
785 memcmp(cache_new->version, CACHE_VERSION, sizeof CACHE_VERSION - 1) == 0)
786 {
787 cache_data = (const char *) cache_new;
788 format = 1;
789 }
790 }
791 }
792
793 if (format == 0)
794 {
795 vlog("%d libs found in cache format 0\n", cache->nlibs);
796 for (i = 0; i < cache->nlibs; i++)
797 {
798 ld_cache_lib_check(cache_data + cache->libs[i].key, flag);
799 }
800 }
801 else if (format == 1)
802 {
803 vlog("%d libs found in cache format 1\n", cache_new->nlibs);
804
805 for (i = 0; i < cache_new->nlibs; i++)
806 {
807 ld_cache_lib_check(cache_data + cache_new->libs[i].key, flag);
808 }
809 }
810
811 vlog("ldconfig lib flags 0x%x\n", *flag);
812 vlog("lib flags GLADE2:[%s] GTK2:[%s] GTK3:[%s] GTK4:[%s] QT4:[%s] QT5:[%s] QT6:[%s]\n",
813 INT2STR_YN((*flag) & LIB_FLAG_GLADE2), INT2STR_YN((*flag) & LIB_FLAG_GTK2),
814 INT2STR_YN((*flag) & LIB_FLAG_GTK3), INT2STR_YN((*flag) & LIB_FLAG_GTK4),
815 INT2STR_YN((*flag) & LIB_FLAG_QT4), INT2STR_YN((*flag) & LIB_FLAG_QT5),
816 INT2STR_YN((*flag) & LIB_FLAG_QT6));
817
818 munmap (cache, cache_size);
819 close (fd);
820 return 0;
821 }
822
823 static int gui_type_check(VTOY_JSON *pstNode)
824 {
825 FILE *fp = NULL;
826 const char *env = NULL;
827 const char *arch = NULL;
828 const char *srctype = NULL;
829 const char *srcname = NULL;
830 const char *condition = NULL;
831 const char *expression = NULL;
832 char line[1024];
833
834 arch = vtoy_json_get_string_ex(pstNode, "arch");
835 srctype = vtoy_json_get_string_ex(pstNode, "type");
836 srcname = vtoy_json_get_string_ex(pstNode, "name");
837 condition = vtoy_json_get_string_ex(pstNode, "condition");
838 expression = vtoy_json_get_string_ex(pstNode, "expression");
839
840 if (srctype == NULL || srcname == NULL || condition == NULL)
841 {
842 return 0;
843 }
844
845 if (arch && NULL == strstr(arch, VTOY_GUI_ARCH))
846 {
847 return 0;
848 }
849
850 vlog("check <%s> <%s> <%s>\n", srctype, srcname, condition);
851
852 if (strcmp(srctype, "file") == 0)
853 {
854 if (access(srcname, F_OK) == -1)
855 {
856 return 0;
857 }
858
859 if (strcmp(condition, "exist") == 0)
860 {
861 vlog("File %s exist\n", srcname);
862 return 1;
863 }
864 else if (strcmp(condition, "contains") == 0)
865 {
866 fp = fopen(srcname, "r");
867 if (fp == NULL)
868 {
869 return 0;
870 }
871
872 while (fgets(line, sizeof(line), fp))
873 {
874 if (strstr(line, expression))
875 {
876 vlog("File %s contains %s\n", srcname, expression);
877 fclose(fp);
878 return 1;
879 }
880 }
881
882 fclose(fp);
883 return 0;
884 }
885 }
886 else if (strcmp(srctype, "env") == 0)
887 {
888 env = getenv(srcname);
889 if (env == NULL)
890 {
891 return 0;
892 }
893
894 if (strcmp(condition, "exist") == 0)
895 {
896 vlog("env %s exist\n", srcname);
897 return 1;
898 }
899 else if (strcmp(condition, "equal") == 0)
900 {
901 if (strcmp(expression, env) == 0)
902 {
903 vlog("env %s is %s\n", srcname, env);
904 return 1;
905 }
906 return 0;
907 }
908 else if (strcmp(condition, "contains") == 0)
909 {
910 if (strstr(env, expression))
911 {
912 vlog("env %s is %s contains %s\n", srcname, env, expression);
913 return 1;
914 }
915 return 0;
916 }
917 }
918
919 return 0;
920 }
921
922 static int read_file_to_buf(const char *FileName, int ExtLen, void **Bufer, int *BufLen)
923 {
924 int FileSize;
925 FILE *fp = NULL;
926 void *Data = NULL;
927
928 fp = fopen(FileName, "rb");
929 if (fp == NULL)
930 {
931 vlog("Failed to open file %s", FileName);
932 return 1;
933 }
934
935 fseek(fp, 0, SEEK_END);
936 FileSize = (int)ftell(fp);
937
938 Data = malloc(FileSize + ExtLen);
939 if (!Data)
940 {
941 fclose(fp);
942 return 1;
943 }
944
945 fseek(fp, 0, SEEK_SET);
946 fread(Data, 1, FileSize, fp);
947
948 fclose(fp);
949
950 *Bufer = Data;
951 *BufLen = FileSize;
952
953 return 0;
954 }
955
956 static int distro_check_gui_env(char *type, int len, int *pver)
957 {
958 int size;
959 int length;
960 char *pBuf = NULL;
961 VTOY_JSON *pstNode = NULL;
962 VTOY_JSON *pstJson = NULL;
963
964 vlog("distro_check_gui_env ...\n");
965
966 if (access("./tool/distro_gui_type.json", F_OK) == -1)
967 {
968 vlog("distro_gui_type.json file not exist\n");
969 return 0;
970 }
971
972 read_file_to_buf("./tool/distro_gui_type.json", 1, (void **)&pBuf, &size);
973 pBuf[size] = 0;
974
975 pstJson = vtoy_json_create();
976 vtoy_json_parse(pstJson, pBuf);
977
978 for (pstNode = pstJson->pstChild; pstNode; pstNode = pstNode->pstNext)
979 {
980 if (gui_type_check(pstNode->pstChild))
981 {
982 length = (int)snprintf(type, len, "%s", vtoy_json_get_string_ex(pstNode->pstChild, "gui"));
983 *pver = type[length - 1] - '0';
984 type[length - 1] = 0;
985 break;
986 }
987 }
988
989 vtoy_json_destroy(pstJson);
990 return pstNode ? 1 : 0;
991 }
992
993 static int detect_gui_exe_path(int argc, char **argv, const char *curpath, char *pathbuf, int buflen)
994 {
995 int i;
996 int ret;
997 int ver;
998 int libflag = 0;
999 const char *guitype = NULL;
1000 char line[256];
1001 mode_t mode;
1002 struct stat filestat;
1003
1004 for (i = 1; i < argc; i++)
1005 {
1006 if (argv[i] && strcmp(argv[i], "--gtk2") == 0)
1007 {
1008 guitype = "gtk";
1009 ver = 2;
1010 }
1011 else if (argv[i] && strcmp(argv[i], "--gtk3") == 0)
1012 {
1013 guitype = "gtk";
1014 ver = 3;
1015 }
1016 else if (argv[i] && strcmp(argv[i], "--gtk4") == 0)
1017 {
1018 guitype = "gtk";
1019 ver = 4;
1020 }
1021 else if (argv[i] && strcmp(argv[i], "--qt4") == 0)
1022 {
1023 guitype = "qt";
1024 ver = 4;
1025 }
1026 else if (argv[i] && strcmp(argv[i], "--qt5") == 0)
1027 {
1028 guitype = "qt";
1029 ver = 5;
1030 }
1031 else if (argv[i] && strcmp(argv[i], "--qt6") == 0)
1032 {
1033 guitype = "qt";
1034 ver = 6;
1035 }
1036 }
1037
1038 if (guitype)
1039 {
1040 vlog("Get GUI type from param <%s%d>.\n", guitype, ver);
1041 }
1042 else if (access("./ventoy_gui_type", F_OK) != -1)
1043 {
1044 vlog("Get GUI type from ventoy_gui_type file.\n");
1045
1046 line[0] = 0;
1047 read_file_1st_line("./ventoy_gui_type", line, sizeof(line));
1048 if (strncmp(line, "gtk2", 4) == 0)
1049 {
1050 guitype = "gtk";
1051 ver = 2;
1052
1053 parse_ld_cache(&libflag);
1054 if ((libflag & LIB_FLAG_GLADE2) == 0)
1055 {
1056 vlog("libglade2 is necessary for GTK2, but not found.\n");
1057 return 1;
1058 }
1059 }
1060 else if (strncmp(line, "gtk3", 4) == 0)
1061 {
1062 guitype = "gtk";
1063 ver = 3;
1064 }
1065 else if (strncmp(line, "gtk4", 4) == 0)
1066 {
1067 guitype = "gtk";
1068 ver = 4;
1069 }
1070 else if (strncmp(line, "qt4", 3) == 0)
1071 {
1072 guitype = "qt";
1073 ver = 4;
1074 }
1075 else if (strncmp(line, "qt5", 3) == 0)
1076 {
1077 guitype = "qt";
1078 ver = 5;
1079 }
1080 else if (strncmp(line, "qt6", 3) == 0)
1081 {
1082 guitype = "qt";
1083 ver = 6;
1084 }
1085 else
1086 {
1087 vlog("Current X environment is NOT supported.\n");
1088 return 1;
1089 }
1090 }
1091 else
1092 {
1093 vlog("Now detect the GUI type ...\n");
1094
1095 parse_ld_cache(&libflag);
1096
1097 if ((LIB_FLAG_GTK & libflag) > 0 && (LIB_FLAG_QT & libflag) == 0)
1098 {
1099 guitype = "gtk";
1100 ver = detect_gtk_version(libflag);
1101 }
1102 else if ((LIB_FLAG_GTK & libflag) == 0 && (LIB_FLAG_QT & libflag) > 0)
1103 {
1104 guitype = "qt";
1105 ver = detect_qt_version(libflag);
1106 }
1107 else if ((LIB_FLAG_GTK & libflag) > 0 && (LIB_FLAG_QT & libflag) > 0)
1108 {
1109 if (distro_check_gui_env(line, sizeof(line), &ver))
1110 {
1111 guitype = line;
1112 vlog("distro_check_gui <%s%d> ...\n", line, ver);
1113 }
1114 else if (is_gtk_env())
1115 {
1116 guitype = "gtk";
1117 ver = detect_gtk_version(libflag);
1118 }
1119 else if (is_qt_env())
1120 {
1121 guitype = "qt";
1122 ver = detect_qt_version(libflag);
1123 }
1124 else
1125 {
1126 vlog("Can not distinguish GTK and QT, default use GTK.\n");
1127 guitype = "gtk";
1128 ver = detect_gtk_version(libflag);
1129 }
1130 }
1131 else
1132 {
1133 vlog("Current X environment is NOT supported.\n");
1134 return 1;
1135 }
1136 }
1137
1138 snprintf(pathbuf, buflen, "%s/tool/%s/Ventoy2Disk.%s%d", curpath, VTOY_GUI_ARCH, guitype, ver);
1139
1140 vlog("This is %s%d X environment.\n", guitype, ver);
1141 vlog("exe = %s\n", pathbuf);
1142
1143 if (access(pathbuf, F_OK) == -1)
1144 {
1145 vlog("%s is not exist.\n", pathbuf);
1146 return 1;
1147 }
1148
1149 if (access(pathbuf, X_OK) == -1)
1150 {
1151 vlog("execute permission check fail, try chmod.\n", pathbuf);
1152 if (stat(pathbuf, &filestat) == 0)
1153 {
1154 mode = filestat.st_mode | S_IXUSR | S_IXGRP | S_IXOTH;
1155 ret = chmod(pathbuf, mode);
1156 vlog("old mode=%o new mode=%o ret=%d\n", filestat.st_mode, mode, ret);
1157 }
1158 }
1159 else
1160 {
1161 vlog("execute permission check success.\n");
1162 }
1163
1164 return 0;
1165 }
1166
1167 int real_main(int argc, char **argv)
1168 {
1169 int ret;
1170 int euid;
1171 char *exe = NULL;
1172 char path[PATH_MAX];
1173 char curpath[PATH_MAX];
1174
1175 ret = adjust_cur_dir(argv[0]);
1176
1177 vlog("\n");
1178 vlog("=========================================================\n");
1179 vlog("=========================================================\n");
1180 vlog("=============== VentoyGui %s ===============\n", VTOY_GUI_ARCH);
1181 vlog("=========================================================\n");
1182 vlog("=========================================================\n");
1183 vlog("log file is <%s>\n", g_log_file);
1184
1185 euid = geteuid();
1186 getcwd(curpath, sizeof(curpath));
1187
1188 vlog("pid:%ld ppid:%ld uid:%d euid:%d\n", (long)getpid(), (long)getppid(), getuid(), euid);
1189 vlog("adjust dir:%d current path:%s\n", ret, curpath);
1190 dump_args("RAW", argv);
1191
1192 if (access("./boot/boot.img", F_OK) == -1)
1193 {
1194 vlog("Please run under the correct directory!\n");
1195 return 1;
1196 }
1197
1198 exe = find_argv(argc, argv, VTOY_GUI_PATH);
1199 if (exe)
1200 {
1201 if (euid != 0)
1202 {
1203 vlog("Invalid euid %d when restart.\n", euid);
1204 return 1;
1205 }
1206
1207 return restart_main(argc, argv, exe + strlen(VTOY_GUI_PATH));
1208 }
1209 else
1210 {
1211 if (pre_check())
1212 {
1213 return 1;
1214 }
1215
1216 if (detect_gui_exe_path(argc, argv, curpath, path, sizeof(path)))
1217 {
1218 return 1;
1219 }
1220
1221 if (euid == 0)
1222 {
1223 vlog("We have root privileges, just exec %s\n", path);
1224 argv[0] = path;
1225 execv(argv[0], argv);
1226 }
1227 else
1228 {
1229 vlog("EUID check failed.\n");
1230
1231 /* try pkexec */
1232 restart_by_pkexec(argc, argv, curpath, path);
1233
1234 vlog("### Please run with root privileges. ###\n");
1235 return 1;
1236 }
1237 }
1238
1239 return 1;
1240 }
1241
1242 int main(int argc, char **argv)
1243 {
1244 int i;
1245 int ret;
1246 const char *env = NULL;
1247
1248 snprintf(g_log_file, sizeof(g_log_file), "log.txt");
1249 for (i = 0; i < argc; i++)
1250 {
1251 if (argv[i] && argv[i + 1] && strcmp(argv[i], "-l") == 0)
1252 {
1253 snprintf(g_log_file, sizeof(g_log_file), "%s", argv[i + 1]);
1254 break;
1255 }
1256 else if (argv[i] && strcmp(argv[i], "--xdg") == 0)
1257 {
1258 env = getenv("XDG_CACHE_HOME");
1259 if (env)
1260 {
1261 g_xdg_log = 1;
1262 snprintf(g_log_file, sizeof(g_log_file), "%s/ventoy.log", env);
1263 }
1264
1265 env = getenv("XDG_CONFIG_HOME");
1266 if (env)
1267 {
1268 g_xdg_ini = 1;
1269 snprintf(g_ini_file, sizeof(g_ini_file), "%s/Ventoy2Disk.ini", env);
1270 }
1271 }
1272 }
1273
1274 g_log_buf = malloc(MAX_LOG_BUF);
1275 if (!g_log_buf)
1276 {
1277 vlog("Failed to malloc log buffer %d\n", MAX_LOG_BUF);
1278 return 1;
1279 }
1280
1281 ret = real_main(argc, argv);
1282 free(g_log_buf);
1283 return ret;
1284 }
1285