]>
glassweightruler.freedombox.rocks Git - Ventoy.git/blob - LinuxGUI/Ventoy2Disk/ventoy_gui.c
10 #include <sys/utsname.h>
11 #include <sys/types.h>
13 #include <sys/fcntl.h>
16 #define LIB_FLAG_GTK2 (1 << 0)
17 #define LIB_FLAG_GTK3 (1 << 1)
18 #define LIB_FLAG_GTK4 (1 << 2)
19 #define LIB_FLAG_QT4 (1 << 3)
20 #define LIB_FLAG_QT5 (1 << 4)
21 #define LIB_FLAG_QT6 (1 << 5)
22 #define LIB_FLAG_GLADE2 (1 << 30)
24 #define LIB_FLAG_GTK (LIB_FLAG_GTK2 | LIB_FLAG_GTK3 | LIB_FLAG_GTK4)
25 #define LIB_FLAG_QT (LIB_FLAG_QT4 | LIB_FLAG_QT5 | LIB_FLAG_QT6)
28 #define MAX_LOG_BUF (1024 * 1024)
29 #define VTOY_GUI_PATH "_vtoy_gui_path_="
30 #define VTOY_ENV_STR "_vtoy_env_str_="
31 #define LD_CACHE_FILE "/etc/ld.so.cache"
32 #define INT2STR_YN(a) ((a) == 0 ? "NO" : "YES")
34 static char *g_log_buf
= NULL
;
35 extern char ** environ
;
37 #define CACHEMAGIC "ld.so-1.7.0"
41 int flags
; /* This is 1 for an ELF library. */
42 unsigned int key
, value
; /* String table indices. */
47 char magic
[sizeof CACHEMAGIC
- 1];
49 struct file_entry libs
[0];
52 #define CACHEMAGIC_NEW "glibc-ld.so.cache"
53 #define CACHE_VERSION "1.1"
54 #define CACHEMAGIC_VERSION_NEW CACHEMAGIC_NEW CACHE_VERSION
58 int32_t flags
; /* This is 1 for an ELF library. */
59 uint32_t key
, value
; /* String table indices. */
60 uint32_t osversion
; /* Required OS version. */
61 uint64_t hwcap
; /* Hwcap entry. */
66 char magic
[sizeof CACHEMAGIC_NEW
- 1];
67 char version
[sizeof CACHE_VERSION
- 1];
68 uint32_t nlibs
; /* Number of entries. */
69 uint32_t len_strings
; /* Size of string table. */
70 uint32_t unused
[5]; /* Leave space for future extensions
71 and align to 8 byte boundary. */
72 struct file_entry_new libs
[0]; /* Entries describing libraries. */
73 /* After this the string table of size len_strings is found. */
76 /* Used to align cache_file_new. */
77 #define ALIGN_CACHE(addr) \
78 (((addr) + __alignof__ (struct cache_file_new) -1) \
79 & (~(__alignof__ (struct cache_file_new) - 1)))
81 static void vlog(const char *Fmt
, ...)
92 localtime_r(&stamp
, &ttm
);
102 buflen
= sizeof(log
);
106 vsnprintf(buf
, buflen
, Fmt
, arg
);
109 fp
= fopen("log.txt", "a+");
112 fprintf(fp
, "[%04u/%02u/%02u %02u:%02u:%02u] %s",
113 ttm
.tm_year
+ 1900, ttm
.tm_mon
, ttm
.tm_mday
,
114 ttm
.tm_hour
, ttm
.tm_min
, ttm
.tm_sec
,
119 printf("[%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
,
125 static int is_gtk_env(void)
127 const char *env
= NULL
;
129 env
= getenv("GNOME_SETUP_DISPLAY");
130 if (env
&& env
[0] == ':')
132 vlog("GNOME_SETUP_DISPLAY=%s\n", env
);
136 env
= getenv("DESKTOP_SESSION");
137 if (env
&& strcasecmp(env
, "xfce") == 0)
139 vlog("DESKTOP_SESSION=%s\n", env
);
146 static int is_qt_env(void)
151 static int detect_gtk_version(int libflag
)
158 gtk2
= libflag
& LIB_FLAG_GTK2
;
159 gtk3
= libflag
& LIB_FLAG_GTK3
;
160 gtk4
= libflag
& LIB_FLAG_GTK4
;
161 glade2
= libflag
& LIB_FLAG_GLADE2
;
163 if (gtk2
> 0 && glade2
> 0 && (gtk3
== 0 && gtk4
== 0))
168 if (gtk3
> 0 && (gtk2
== 0 && gtk4
== 0))
173 if (gtk4
> 0 && (gtk2
== 0 && gtk3
== 0))
188 if (gtk2
> 0 && glade2
> 0)
196 static int detect_qt_version(int libflag
)
202 qt4
= libflag
& LIB_FLAG_QT4
;
203 qt5
= libflag
& LIB_FLAG_QT5
;
204 qt6
= libflag
& LIB_FLAG_QT6
;
206 if (qt4
> 0 && (qt5
== 0 && qt6
== 0))
211 if (qt5
> 0 && (qt4
== 0 && qt6
== 0))
216 if (qt6
> 0 && (qt4
== 0 && qt5
== 0))
239 int bit_from_machine(const char *machine
)
241 if (strstr(machine
, "64"))
251 int get_os_bit(int *bit
)
254 struct utsname unameData
;
256 memset(&unameData
, 0, sizeof(unameData
));
257 ret
= uname(&unameData
);
260 vlog("uname error, code: %d\n", errno
);
264 *bit
= strstr(unameData
.machine
, "64") ? 64 : 32;
265 vlog("uname -m <%s> %dbit\n", unameData
.machine
, *bit
);
270 int read_file_1st_line(const char *file
, char *buffer
, int buflen
)
274 fp
= fopen(file
, "r");
277 vlog("Failed to open file %s code:%d", file
, errno
);
281 fgets(buffer
, buflen
, fp
);
286 static int read_pid_cmdline(long pid
, char *Buffer
, int BufLen
)
290 snprintf(path
, sizeof(path
), "/proc/%ld/cmdline", pid
);
291 return read_file_1st_line(path
, Buffer
, BufLen
);
294 static int find_exe_path(const char *exe
, char *pathbuf
, int buflen
)
299 char *saveptr
= NULL
;
301 const char *env
= getenv("PATH");
308 newenv
= strdup(env
);
315 while (NULL
!= (tmpptr
= strtok_r(tmpptr
, ":", &saveptr
)))
317 snprintf(path
, sizeof(path
), "%s/%s", tmpptr
, exe
);
318 if (access(path
, F_OK
) != -1)
320 snprintf(pathbuf
, buflen
, "%s", path
);
331 void dump_args(const char *prefix
, char **argv
)
335 vlog("=========%s ARGS BEGIN===========\n", prefix
);
338 vlog("argv[%d]=<%s>\n", i
, argv
[i
]);
341 vlog("=========%s ARGS END===========\n", prefix
);
349 const char *env
= NULL
;
351 env
= getenv("DISPLAY");
352 if (NULL
== env
|| env
[0] != ':')
354 vlog("DISPLAY not exist(%p). Not in X environment.\n", env
);
358 ret
= get_os_bit(&bit
);
361 vlog("Failed to get os bit.\n");
365 buildbit
= strstr(VTOY_GUI_ARCH
, "64") ? 64 : 32;
366 vlog("Build bit is %d (%s)\n", buildbit
, VTOY_GUI_ARCH
);
370 vlog("Current system is %d bit (%s). Please run the correct VentoyGUI.\n", bit
, VTOY_GUI_ARCH
);
377 static char * find_argv(int argc
, char **argv
, char *key
)
382 len
= (int)strlen(key
);
383 for (i
= 0; i
< argc
; i
++)
385 if (strncmp(argv
[i
], key
, len
) == 0)
394 static int adjust_cur_dir(char *argv0
)
406 for (pos
= argv0
; pos
&& *pos
; pos
++)
427 static char **recover_environ_param(char *env
)
433 char **newenvs
= NULL
;
435 for (i
= 0; env
[i
]; i
++)
443 newenvs
= malloc(sizeof(char *) * (cnt
+ 1));
446 vlog("malloc new envs fail %d\n", cnt
+ 1);
449 memset(newenvs
, 0, sizeof(char *) * (cnt
+ 1));
451 for (j
= i
= 0; env
[i
]; i
++)
456 newenvs
[k
++] = env
+ j
;
461 vlog("recover environ %d %d\n", cnt
, k
);
465 static int restart_main(int argc
, char **argv
, char *guiexe
)
471 char *newargv
[MAX_PARAS
+ 1] = { NULL
};
473 para
= find_argv(argc
, argv
, VTOY_ENV_STR
);
476 vlog("failed to find %s\n", VTOY_ENV_STR
);
480 newargv
[j
++] = guiexe
;
481 for (i
= 1; i
< argc
&& j
< MAX_PARAS
; i
++)
483 if (strncmp(argv
[i
], "_vtoy_", 6) != 0)
485 newargv
[j
++] = argv
[i
];
489 envs
= recover_environ_param(para
+ strlen(VTOY_ENV_STR
));
492 vlog("recover success, argc=%d evecve <%s>\n", j
, guiexe
);
493 execve(guiexe
, newargv
, envs
);
497 vlog("recover failed, argc=%d evecv <%s>\n", j
, guiexe
);
498 execv(guiexe
, newargv
);
504 static char *create_environ_param(const char *prefix
, char **envs
)
513 prelen
= strlen(prefix
);
514 for (i
= 0; envs
[i
]; i
++)
517 envlen
+= strlen(envs
[i
]) + 1;
520 para
= malloc(prelen
+ envlen
);
523 vlog("failed to malloc env str %d\n", prelen
+ envlen
);
528 memcpy(cur
, prefix
, prelen
);
531 for (i
= 0; envs
[i
]; i
++)
533 envlen
= strlen(envs
[i
]);
534 memcpy(cur
, envs
[i
], envlen
);
540 vlog("create environment param %d\n", cnt
);
544 static int restart_by_pkexec(int argc
, char **argv
, const char *curpath
, const char *exe
)
550 char pkexec
[PATH_MAX
];
551 char exepara
[PATH_MAX
];
552 char *newargv
[MAX_PARAS
+ 1] = { NULL
};
554 vlog("try restart self by pkexec ...\n");
556 if (find_exe_path("pkexec", pkexec
, sizeof(pkexec
)))
558 vlog("Find pkexec at <%s>\n", pkexec
);
562 vlog("pkexec not found\n");
566 if (argv
[0][0] != '/')
568 snprintf(path
, sizeof(path
), "%s/%s", curpath
, argv
[0]);
572 snprintf(path
, sizeof(path
), "%s", argv
[0]);
574 snprintf(exepara
, sizeof(exepara
), "%s%s", VTOY_GUI_PATH
, exe
);
576 newargv
[j
++] = pkexec
;
578 for (i
= 1; i
< argc
&& j
< MAX_PARAS
- 2; i
++)
580 newargv
[j
++] = argv
[i
];
582 newargv
[j
++] = create_environ_param(VTOY_ENV_STR
, environ
);
583 newargv
[j
++] = exepara
;
585 dump_args("PKEXEC", newargv
);
586 execv(pkexec
, newargv
);
591 static int ld_cache_lib_check(const char *lib
, int *flag
)
593 if (((*flag
) & LIB_FLAG_GTK3
) == 0)
595 if (strncmp(lib
, "libgtk-3.so", 11) == 0)
597 vlog("LIB:<%s>\n", lib
);
598 *flag
|= LIB_FLAG_GTK3
;
603 if (((*flag
) & LIB_FLAG_GTK2
) == 0)
605 if (strncmp(lib
, "libgtk-x11-2.0.so", 17) == 0)
607 vlog("LIB:<%s>\n", lib
);
608 *flag
|= LIB_FLAG_GTK2
;
613 if (((*flag
) & LIB_FLAG_GTK4
) == 0)
615 if (strncmp(lib
, "libgtk-4.so", 11) == 0)
617 vlog("LIB:<%s>\n", lib
);
618 *flag
|= LIB_FLAG_GTK4
;
623 if (((*flag
) & LIB_FLAG_QT4
) == 0)
625 if (strncmp(lib
, "libqt4", 6) == 0)
627 vlog("LIB:<%s>\n", lib
);
628 *flag
|= LIB_FLAG_QT4
;
633 if (((*flag
) & LIB_FLAG_QT5
) == 0)
635 if (strncmp(lib
, "libqt5", 6) == 0)
637 vlog("LIB:<%s>\n", lib
);
638 *flag
|= LIB_FLAG_QT5
;
643 if (((*flag
) & LIB_FLAG_QT6
) == 0)
645 if (strncmp(lib
, "libqt6", 6) == 0)
647 vlog("LIB:<%s>\n", lib
);
648 *flag
|= LIB_FLAG_QT6
;
653 if (((*flag
) & LIB_FLAG_GLADE2
) == 0)
655 if (strncmp(lib
, "libglade-2", 10) == 0)
657 vlog("LIB:<%s>\n", lib
);
658 *flag
|= LIB_FLAG_GLADE2
;
666 static int parse_ld_cache(int *flag
)
673 size_t cache_size
= 0;
674 const char *cache_data
= NULL
;
675 struct cache_file
*cache
= NULL
;
676 struct cache_file_new
*cache_new
= NULL
;
680 fd
= open(LD_CACHE_FILE
, O_RDONLY
);
683 vlog("failed to open %s err:%d\n", LD_CACHE_FILE
, errno
);
687 if (fstat(fd
, &st
) < 0 || st
.st_size
== 0)
693 cache
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
694 if (cache
== MAP_FAILED
)
700 cache_size
= st
.st_size
;
701 if (cache_size
< sizeof (struct cache_file
))
703 vlog("File is not a cache file.\n");
704 munmap (cache
, cache_size
);
709 if (memcmp(cache
->magic
, CACHEMAGIC
, sizeof CACHEMAGIC
- 1))
711 /* This can only be the new format without the old one. */
712 cache_new
= (struct cache_file_new
*) cache
;
714 if (memcmp(cache_new
->magic
, CACHEMAGIC_NEW
, sizeof CACHEMAGIC_NEW
- 1) ||
715 memcmp (cache_new
->version
, CACHE_VERSION
, sizeof CACHE_VERSION
- 1))
717 munmap (cache
, cache_size
);
723 /* This is where the strings start. */
724 cache_data
= (const char *) cache_new
;
728 /* Check for corruption, avoiding overflow. */
729 if ((cache_size
- sizeof (struct cache_file
)) / sizeof (struct file_entry
) < cache
->nlibs
)
731 vlog("File is not a cache file.\n");
732 munmap (cache
, cache_size
);
737 offset
= ALIGN_CACHE(sizeof (struct cache_file
) + (cache
->nlibs
* sizeof (struct file_entry
)));
739 /* This is where the strings start. */
740 cache_data
= (const char *) &cache
->libs
[cache
->nlibs
];
742 /* Check for a new cache embedded in the old format. */
743 if (cache_size
> (offset
+ sizeof (struct cache_file_new
)))
745 cache_new
= (struct cache_file_new
*) ((void *)cache
+ offset
);
747 if (memcmp(cache_new
->magic
, CACHEMAGIC_NEW
, sizeof CACHEMAGIC_NEW
- 1) == 0 &&
748 memcmp(cache_new
->version
, CACHE_VERSION
, sizeof CACHE_VERSION
- 1) == 0)
750 cache_data
= (const char *) cache_new
;
758 vlog("%d libs found in cache format 0\n", cache
->nlibs
);
759 for (i
= 0; i
< cache
->nlibs
; i
++)
761 ld_cache_lib_check(cache_data
+ cache
->libs
[i
].key
, flag
);
764 else if (format
== 1)
766 vlog("%d libs found in cache format 1\n", cache_new
->nlibs
);
768 for (i
= 0; i
< cache_new
->nlibs
; i
++)
770 ld_cache_lib_check(cache_data
+ cache_new
->libs
[i
].key
, flag
);
774 vlog("ldconfig lib flags 0x%x\n", *flag
);
775 vlog("lib flags GLADE2:[%s] GTK2:[%s] GTK3:[%s] GTK4:[%s] QT4:[%s] QT5:[%s] QT6:[%s]\n",
776 INT2STR_YN((*flag
) & LIB_FLAG_GLADE2
), INT2STR_YN((*flag
) & LIB_FLAG_GTK2
),
777 INT2STR_YN((*flag
) & LIB_FLAG_GTK3
), INT2STR_YN((*flag
) & LIB_FLAG_GTK4
),
778 INT2STR_YN((*flag
) & LIB_FLAG_QT4
), INT2STR_YN((*flag
) & LIB_FLAG_QT5
),
779 INT2STR_YN((*flag
) & LIB_FLAG_QT6
));
781 munmap (cache
, cache_size
);
786 static int detect_gui_exe_path(const char *curpath
, char *pathbuf
, int buflen
)
791 const char *guitype
= NULL
;
794 struct stat filestat
;
796 if (access("./ventoy_gui_type", F_OK
) != -1)
798 vlog("Get GUI type from ventoy_gui_type file.\n");
801 read_file_1st_line("./ventoy_gui_type", line
, sizeof(line
));
802 if (strncmp(line
, "gtk2", 4) == 0)
807 parse_ld_cache(&libflag
);
808 if ((libflag
& LIB_FLAG_GLADE2
) == 0)
810 vlog("libglade2 is necessary for GTK2, but not found.\n");
814 else if (strncmp(line
, "gtk3", 4) == 0)
819 else if (strncmp(line
, "gtk4", 4) == 0)
824 else if (strncmp(line
, "qt4", 3) == 0)
829 else if (strncmp(line
, "qt5", 3) == 0)
834 else if (strncmp(line
, "qt6", 3) == 0)
841 vlog("Current X environment is NOT supported.\n");
847 vlog("Now detect the GUI type ...\n");
849 parse_ld_cache(&libflag
);
851 if ((LIB_FLAG_GTK
& libflag
) > 0 && (LIB_FLAG_QT
& libflag
) == 0)
854 ver
= detect_gtk_version(libflag
);
856 else if ((LIB_FLAG_GTK
& libflag
) == 0 && (LIB_FLAG_QT
& libflag
) > 0)
859 ver
= detect_qt_version(libflag
);
861 else if ((LIB_FLAG_GTK
& libflag
) > 0 && (LIB_FLAG_QT
& libflag
) > 0)
866 ver
= detect_gtk_version(libflag
);
868 else if (is_qt_env())
871 ver
= detect_qt_version(libflag
);
875 vlog("Current X environment is NOT supported.\n");
881 vlog("Current X environment is NOT supported.\n");
886 snprintf(pathbuf
, buflen
, "%s/tool/%s/Ventoy2Disk.%s%d", curpath
, VTOY_GUI_ARCH
, guitype
, ver
);
888 vlog("This is %s%d X environment.\n", guitype
, ver
);
889 vlog("exe = %s\n", pathbuf
);
891 if (access(pathbuf
, F_OK
) == -1)
893 vlog("%s is not exist.\n", pathbuf
);
897 if (access(pathbuf
, X_OK
) == -1)
899 vlog("execute permission check fail, try chmod.\n", pathbuf
);
900 if (stat(pathbuf
, &filestat
) == 0)
902 mode
= filestat
.st_mode
| S_IXUSR
| S_IXGRP
| S_IXOTH
;
903 ret
= chmod(pathbuf
, mode
);
904 vlog("old mode=%o new mode=%o ret=%d\n", filestat
.st_mode
, mode
, ret
);
909 vlog("execute permission check success.\n");
915 int real_main(int argc
, char **argv
)
921 char curpath
[PATH_MAX
];
923 ret
= adjust_cur_dir(argv
[0]);
926 vlog("=========================================================\n");
927 vlog("=========================================================\n");
928 vlog("=============== VentoyGui %s ===============\n", VTOY_GUI_ARCH
);
929 vlog("=========================================================\n");
930 vlog("=========================================================\n");
933 getcwd(curpath
, sizeof(curpath
));
935 vlog("pid:%ld ppid:%ld uid:%d euid:%d\n", (long)getpid(), (long)getppid(), getuid(), euid
);
936 vlog("adjust dir:%d current path:%s\n", ret
, curpath
);
937 dump_args("RAW", argv
);
939 if (access("./boot/boot.img", F_OK
) == -1)
941 vlog("Please run under the correct directory!\n");
945 exe
= find_argv(argc
, argv
, VTOY_GUI_PATH
);
950 vlog("Invalid euid %d when restart.\n", euid
);
954 return restart_main(argc
, argv
, exe
+ strlen(VTOY_GUI_PATH
));
963 if (detect_gui_exe_path(curpath
, path
, sizeof(path
)))
970 vlog("We have root privileges, just exec %s\n", path
);
973 execv(argv
[0], argv
);
977 vlog("EUID check failed.\n");
980 restart_by_pkexec(argc
, argv
, curpath
, path
);
982 vlog("### Please run with root privileges. ###\n");
990 int main(int argc
, char **argv
)
994 g_log_buf
= malloc(MAX_LOG_BUF
);
997 vlog("Failed to malloc log buffer %d\n", MAX_LOG_BUF
);
1001 ret
= real_main(argc
, argv
);