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