Skip to content

Commit 91a1da2

Browse files
committed
runtime: always use link target for /proc/self/exe
When running an AppImage under [gcompat][0] (e.g. on Alpine Linux), `fopen("/proc/self/exe", "rb")` opens the dynamic linker (e.g. `/lib/ld-musl-x86_64.so.1`) instead of the AppImage itself. However, `readlink("/proc/self/exe", ...)` does give the path to the AppImage as expected, even under gcompat. This commit fixes this problem by always using the link target for `/proc/self/exe` in places that read the AppImage instead of the link itself. Without this commit, running an AppImage under gcompat results in [the error message "This doesn't look like a squashfs image." from squashfuse][1]. With this commit, AppImages run as expected under gcompat. In order to make `--appimage-help` and `--appimage-portable-{home,config}` work under gcompat, I also move the calculation of the `fullpath` variable in `main()` to earlier in the function and change `print_help()` and `portable_option()` to use it instead of calculating the fullpath separately. (When `$TARGET_APPIMAGE` is set, since `realpath()` is (already) used instead of `readlink()` in that case, this change could result in a different path being used in help output and when _creating_ the portable home and config directories with the respective command line options, but `fullpath` is already being used to find existing portable directories when running an AppImage, so this should not affect existing portable installations.) For consistency, I also rename the `fullpath` variable in `main()` and the corresponding arguments in `print_help()` and `portable_option()` to `appimage_fullpath`. Fixes AppImage#1015 on Alpine Linux systems with gcompat installed, for AppImages made with this changeset applied. Tested on Alpine Linux edge x86_64 and postmarketOS (based on Alpine) edge aarch64. [0]: https://git.adelielinux.org/adelie/gcompat/ [1]: https://github.com/vasi/squashfuse/blob/e51978cd6bb5c4d16fae9eee43d0b258f570bb0f/util.c#L81-L82
1 parent a2d9cfc commit 91a1da2

File tree

1 file changed

+38
-51
lines changed

1 file changed

+38
-51
lines changed

src/runtime.c

+38-51
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ mkdir_p(const char* const path)
212212
}
213213

214214
void
215-
print_help(const char *appimage_path)
215+
print_help(const char *appimage_fullpath)
216216
{
217217
// TODO: "--appimage-list List content from embedded filesystem image\n"
218218
fprintf(stderr,
@@ -244,27 +244,19 @@ print_help(const char *appimage_path)
244244
" and is neither moved nor renamed, the application contained inside this\n"
245245
" AppImage to store its data in this directory rather than in your home\n"
246246
" directory\n"
247-
, appimage_path);
247+
, appimage_fullpath);
248248
}
249249

250250
void
251-
portable_option(const char *arg, const char *appimage_path, const char *name)
251+
portable_option(const char *arg, const char *appimage_fullpath, const char *name)
252252
{
253253
char option[32];
254254
sprintf(option, "appimage-portable-%s", name);
255255

256256
if (arg && strcmp(arg, option)==0) {
257257
char portable_dir[PATH_MAX];
258-
char fullpath[PATH_MAX];
259258

260-
ssize_t length = readlink(appimage_path, fullpath, sizeof(fullpath));
261-
if (length < 0) {
262-
fprintf(stderr, "Error getting realpath for %s\n", appimage_path);
263-
exit(EXIT_FAILURE);
264-
}
265-
fullpath[length] = '\0';
266-
267-
sprintf(portable_dir, "%s.%s", fullpath, name);
259+
sprintf(portable_dir, "%s.%s", appimage_fullpath, name);
268260
if (!mkdir(portable_dir, S_IRWXU))
269261
fprintf(stderr, "Portable %s directory created at %s\n", name, portable_dir);
270262
else
@@ -536,7 +528,15 @@ int main(int argc, char *argv[]) {
536528
* functionality specifically for builds used by appimaged.
537529
*/
538530
if (getenv("TARGET_APPIMAGE") == NULL) {
539-
strcpy(appimage_path, "/proc/self/exe");
531+
// for some reason, `fopen("/proc/self/exe", "rb")` tries to open
532+
// the dynamic linker when running under gcompat, even though `readlink()`
533+
// gives the right result, so use `readlink()` here
534+
ssize_t len = readlink("/proc/self/exe", appimage_path, sizeof(appimage_path));
535+
if (len < 0) {
536+
perror("Failed to obtain AppImage path");
537+
exit(EXIT_EXECERROR);
538+
}
539+
appimage_path[len] = '\0';
540540
strcpy(argv0_path, argv[0]);
541541
} else {
542542
strcpy(appimage_path, getenv("TARGET_APPIMAGE"));
@@ -577,6 +577,24 @@ int main(int argc, char *argv[]) {
577577
#endif
578578
}
579579

580+
// calculate full path of AppImage
581+
char appimage_fullpath[PATH_MAX];
582+
583+
if(getenv("TARGET_APPIMAGE") == NULL) {
584+
// If we are operating on this file itself, then we've already
585+
// expanded the symlink at `/proc/self/exe` in order to work
586+
// around the issue with gcompat described above
587+
strcpy(appimage_fullpath, appimage_path);
588+
} else {
589+
char* abspath = realpath(appimage_path, NULL);
590+
if (abspath == NULL) {
591+
perror("Failed to obtain realpath for $TARGET_APPIMAGE");
592+
exit(EXIT_EXECERROR);
593+
}
594+
strcpy(appimage_fullpath, abspath);
595+
free(abspath);
596+
}
597+
580598
// temporary directories are required in a few places
581599
// therefore we implement the detection of the temp base dir at the top of the code to avoid redundancy
582600
char temp_base[PATH_MAX] = P_tmpdir;
@@ -599,16 +617,7 @@ int main(int argc, char *argv[]) {
599617

600618
/* Print the help and then exit */
601619
if(arg && strcmp(arg,"appimage-help")==0) {
602-
char fullpath[PATH_MAX];
603-
604-
ssize_t length = readlink(appimage_path, fullpath, sizeof(fullpath));
605-
if (length < 0) {
606-
fprintf(stderr, "Error getting realpath for %s\n", appimage_path);
607-
exit(EXIT_EXECERROR);
608-
}
609-
fullpath[length] = '\0';
610-
611-
print_help(fullpath);
620+
print_help(appimage_fullpath);
612621
exit(0);
613622
}
614623

@@ -642,28 +651,6 @@ int main(int argc, char *argv[]) {
642651
exit(0);
643652
}
644653

645-
// calculate full path of AppImage
646-
int length;
647-
char fullpath[PATH_MAX];
648-
649-
if(getenv("TARGET_APPIMAGE") == NULL) {
650-
// If we are operating on this file itself
651-
ssize_t len = readlink(appimage_path, fullpath, sizeof(fullpath));
652-
if (len < 0) {
653-
perror("Failed to obtain absolute path");
654-
exit(EXIT_EXECERROR);
655-
}
656-
fullpath[len] = '\0';
657-
} else {
658-
char* abspath = realpath(appimage_path, NULL);
659-
if (abspath == NULL) {
660-
perror("Failed to obtain absolute path");
661-
exit(EXIT_EXECERROR);
662-
}
663-
strcpy(fullpath, abspath);
664-
free(abspath);
665-
}
666-
667654
if (getenv("APPIMAGE_EXTRACT_AND_RUN") != NULL || (arg && strcmp(arg, "appimage-extract-and-run") == 0)) {
668655
char* hexlified_digest = NULL;
669656

@@ -727,7 +714,7 @@ int main(int argc, char *argv[]) {
727714
new_argv[new_argc] = NULL;
728715

729716
/* Setting some environment variables that the app "inside" might use */
730-
setenv("APPIMAGE", fullpath, 1);
717+
setenv("APPIMAGE", appimage_fullpath, 1);
731718
setenv("ARGV0", argv0_path, 1);
732719
setenv("APPDIR", prefix, 1);
733720

@@ -785,8 +772,8 @@ int main(int argc, char *argv[]) {
785772
exit(0);
786773
}
787774

788-
portable_option(arg, appimage_path, "home");
789-
portable_option(arg, appimage_path, "config");
775+
portable_option(arg, appimage_fullpath, "home");
776+
portable_option(arg, appimage_fullpath, "config");
790777

791778
// If there is an argument starting with appimage- (but not appimage-mount which is handled further down)
792779
// then stop here and print an error message
@@ -908,23 +895,23 @@ int main(int argc, char *argv[]) {
908895
}
909896

910897
/* Setting some environment variables that the app "inside" might use */
911-
setenv( "APPIMAGE", fullpath, 1 );
898+
setenv( "APPIMAGE", appimage_fullpath, 1 );
912899
setenv( "ARGV0", argv0_path, 1 );
913900
setenv( "APPDIR", mount_dir, 1 );
914901

915902
char portable_home_dir[PATH_MAX];
916903
char portable_config_dir[PATH_MAX];
917904

918905
/* If there is a directory with the same name as the AppImage plus ".home", then export $HOME */
919-
strcpy (portable_home_dir, fullpath);
906+
strcpy (portable_home_dir, appimage_fullpath);
920907
strcat (portable_home_dir, ".home");
921908
if(is_writable_directory(portable_home_dir)){
922909
fprintf(stderr, "Setting $HOME to %s\n", portable_home_dir);
923910
setenv("HOME",portable_home_dir,1);
924911
}
925912

926913
/* If there is a directory with the same name as the AppImage plus ".config", then export $XDG_CONFIG_HOME */
927-
strcpy (portable_config_dir, fullpath);
914+
strcpy (portable_config_dir, appimage_fullpath);
928915
strcat (portable_config_dir, ".config");
929916
if(is_writable_directory(portable_config_dir)){
930917
fprintf(stderr, "Setting $XDG_CONFIG_HOME to %s\n", portable_config_dir);

0 commit comments

Comments
 (0)