Skip to content

Commit

Permalink
runtime: always use link target for /proc/self/exe
Browse files Browse the repository at this point in the history
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
  • Loading branch information
s-zeid committed Jan 28, 2022
1 parent a2d9cfc commit 91a1da2
Showing 1 changed file with 38 additions and 51 deletions.
89 changes: 38 additions & 51 deletions src/runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ mkdir_p(const char* const path)
}

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

void
portable_option(const char *arg, const char *appimage_path, const char *name)
portable_option(const char *arg, const char *appimage_fullpath, const char *name)
{
char option[32];
sprintf(option, "appimage-portable-%s", name);

if (arg && strcmp(arg, option)==0) {
char portable_dir[PATH_MAX];
char fullpath[PATH_MAX];

ssize_t length = readlink(appimage_path, fullpath, sizeof(fullpath));
if (length < 0) {
fprintf(stderr, "Error getting realpath for %s\n", appimage_path);
exit(EXIT_FAILURE);
}
fullpath[length] = '\0';

sprintf(portable_dir, "%s.%s", fullpath, name);
sprintf(portable_dir, "%s.%s", appimage_fullpath, name);
if (!mkdir(portable_dir, S_IRWXU))
fprintf(stderr, "Portable %s directory created at %s\n", name, portable_dir);
else
Expand Down Expand Up @@ -536,7 +528,15 @@ int main(int argc, char *argv[]) {
* functionality specifically for builds used by appimaged.
*/
if (getenv("TARGET_APPIMAGE") == NULL) {
strcpy(appimage_path, "/proc/self/exe");
// for some reason, `fopen("/proc/self/exe", "rb")` tries to open
// the dynamic linker when running under gcompat, even though `readlink()`
// gives the right result, so use `readlink()` here
ssize_t len = readlink("/proc/self/exe", appimage_path, sizeof(appimage_path));
if (len < 0) {
perror("Failed to obtain AppImage path");
exit(EXIT_EXECERROR);
}
appimage_path[len] = '\0';
strcpy(argv0_path, argv[0]);
} else {
strcpy(appimage_path, getenv("TARGET_APPIMAGE"));
Expand Down Expand Up @@ -577,6 +577,24 @@ int main(int argc, char *argv[]) {
#endif
}

// calculate full path of AppImage
char appimage_fullpath[PATH_MAX];

if(getenv("TARGET_APPIMAGE") == NULL) {
// If we are operating on this file itself, then we've already
// expanded the symlink at `/proc/self/exe` in order to work
// around the issue with gcompat described above
strcpy(appimage_fullpath, appimage_path);
} else {
char* abspath = realpath(appimage_path, NULL);
if (abspath == NULL) {
perror("Failed to obtain realpath for $TARGET_APPIMAGE");
exit(EXIT_EXECERROR);
}
strcpy(appimage_fullpath, abspath);
free(abspath);
}

// temporary directories are required in a few places
// therefore we implement the detection of the temp base dir at the top of the code to avoid redundancy
char temp_base[PATH_MAX] = P_tmpdir;
Expand All @@ -599,16 +617,7 @@ int main(int argc, char *argv[]) {

/* Print the help and then exit */
if(arg && strcmp(arg,"appimage-help")==0) {
char fullpath[PATH_MAX];

ssize_t length = readlink(appimage_path, fullpath, sizeof(fullpath));
if (length < 0) {
fprintf(stderr, "Error getting realpath for %s\n", appimage_path);
exit(EXIT_EXECERROR);
}
fullpath[length] = '\0';

print_help(fullpath);
print_help(appimage_fullpath);
exit(0);
}

Expand Down Expand Up @@ -642,28 +651,6 @@ int main(int argc, char *argv[]) {
exit(0);
}

// calculate full path of AppImage
int length;
char fullpath[PATH_MAX];

if(getenv("TARGET_APPIMAGE") == NULL) {
// If we are operating on this file itself
ssize_t len = readlink(appimage_path, fullpath, sizeof(fullpath));
if (len < 0) {
perror("Failed to obtain absolute path");
exit(EXIT_EXECERROR);
}
fullpath[len] = '\0';
} else {
char* abspath = realpath(appimage_path, NULL);
if (abspath == NULL) {
perror("Failed to obtain absolute path");
exit(EXIT_EXECERROR);
}
strcpy(fullpath, abspath);
free(abspath);
}

if (getenv("APPIMAGE_EXTRACT_AND_RUN") != NULL || (arg && strcmp(arg, "appimage-extract-and-run") == 0)) {
char* hexlified_digest = NULL;

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

/* Setting some environment variables that the app "inside" might use */
setenv("APPIMAGE", fullpath, 1);
setenv("APPIMAGE", appimage_fullpath, 1);
setenv("ARGV0", argv0_path, 1);
setenv("APPDIR", prefix, 1);

Expand Down Expand Up @@ -785,8 +772,8 @@ int main(int argc, char *argv[]) {
exit(0);
}

portable_option(arg, appimage_path, "home");
portable_option(arg, appimage_path, "config");
portable_option(arg, appimage_fullpath, "home");
portable_option(arg, appimage_fullpath, "config");

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

/* Setting some environment variables that the app "inside" might use */
setenv( "APPIMAGE", fullpath, 1 );
setenv( "APPIMAGE", appimage_fullpath, 1 );
setenv( "ARGV0", argv0_path, 1 );
setenv( "APPDIR", mount_dir, 1 );

char portable_home_dir[PATH_MAX];
char portable_config_dir[PATH_MAX];

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

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

0 comments on commit 91a1da2

Please sign in to comment.