File indexing completed on 2024-11-10 04:05:17

0001 /**
0002  * SPDX-FileCopyrightText: 2022 Dmitry Kazakov <dimula73@gmail.com>
0003  * SPDX-FileCopyrightText: 2004-2018 Simon Peter
0004  * SPDX-FileCopyrightText: 2010 RazZziel
0005  *
0006  * SPDX-License-Identifier: MIT
0007  */
0008 
0009 #define _GNU_SOURCE
0010 
0011 #include <limits.h>
0012 #include <link.h>
0013 #include <stdlib.h>
0014 #include <string.h>
0015 #include <stdio.h>
0016 #include <libgen.h>
0017 #include <unistd.h>
0018 #include <errno.h>
0019 
0020 void split_version(const char *version, int values[4])
0021 {
0022     char *ver = strdup(version);
0023     
0024     // printf("     ver: %s\n", ver);
0025                         
0026     int index = 0;
0027     char *token = strtok(ver, ".");
0028             
0029     while (token && index < 4) {
0030         const int value = atoi(token);
0031         
0032         // printf("value: %s -> %d\n", token, value);
0033         
0034         values[index] = value;
0035         index++;
0036         token = strtok(0, ".");
0037     }
0038     
0039     while (index < 4) {
0040         values[index] = 0;
0041         index++;
0042     }
0043         
0044     free (ver);
0045 }
0046 
0047 int needs_replace_library(const char *library, const char *base_library)
0048 {
0049     int base_value[4];
0050     int value[4];
0051             
0052     split_version(base_library, base_value);
0053     split_version(library, value);
0054                         
0055     int result = 0;
0056             
0057     for (int i = 0; i < 4; i++) {
0058         if (base_value[i] < value[i]) {
0059             break;
0060         } else if (base_value[i] > value[i]) {
0061             result = 1;
0062             break;
0063          }
0064     }
0065         
0066     return result;
0067 }
0068 
0069 #define die(...)                                    \
0070     do {                                            \
0071         fprintf(stderr, "Error: " __VA_ARGS__);     \
0072         exit(1);                                    \
0073     } while(0);
0074 
0075 #define SET_NEW_ENV(str,len,fmt,...)                \
0076     format = fmt;                                   \
0077     length = strlen(format) + (len);                \
0078     char *str = calloc(length, sizeof(char));     \
0079     snprintf(str, length, format, __VA_ARGS__);   \
0080     putenv(str);
0081 
0082 void try_replace_library(const char *library_name, const char *fallback_dir_name)
0083 {
0084     char buf[PATH_MAX] = "";
0085     char real_library_path[PATH_MAX];
0086 
0087     void *handle = dlopen(library_name, RTLD_LAZY);
0088 
0089     if (handle) {
0090          struct link_map *info;
0091          int result = dlinfo(handle, RTLD_DI_LINKMAP, &info);
0092 
0093          if (result == 0) {
0094             if (realpath(info->l_name, real_library_path)) {
0095                 // noop
0096             } else {
0097                 die("Couldn't resolve the name of system %s", library_name);
0098             }
0099          } else {
0100             die("Couldn't get info for %s", library_name);
0101          }
0102     } else {
0103          die("Couldn't load %s", library_name);
0104     }
0105 
0106     char appdir_buf[PATH_MAX] = "";
0107     char *appdir = dirname(realpath("/proc/self/exe", appdir_buf));
0108     if (!appdir) {
0109          die("Could not access /proc/self/exe\n");
0110     }
0111 
0112     char fallback_library[PATH_MAX] = "";
0113     snprintf(fallback_library, PATH_MAX, "%s/usr/%s/%s", appdir, fallback_dir_name, library_name);
0114 
0115     if (realpath(fallback_library, buf)) {
0116          strcpy(fallback_library, buf);
0117     } else {
0118          die("Could not access $(APPDIR)/usr/%s/%s\n", fallback_dir_name, library_name);
0119     }
0120 
0121 
0122     const int version_offset = strlen(library_name) + 1;
0123     char *fallback_library_name = strstr(fallback_library, library_name);
0124     char *real_library_name = strstr(real_library_path, library_name);
0125 
0126 //    printf("fallback_library_name %s\n", fallback_library_name);
0127 //    printf("real_library_name %s\n", real_library_name);
0128 
0129     char *old_env;
0130     size_t length;
0131     const char *format;
0132 
0133     if (needs_replace_library(real_library_name + version_offset, fallback_library_name + version_offset)) {
0134          printf("Replacing %s with the fallback version: %s -> %s\n", library_name, real_library_name, fallback_library_name);
0135 
0136          old_env = getenv("LD_LIBRARY_PATH");
0137          if (!old_env) old_env = "";
0138 
0139          SET_NEW_ENV(new_ld_library_path,
0140                      strlen(appdir) + strlen(fallback_dir_name) + strlen(old_env),
0141                      "LD_LIBRARY_PATH=%s/usr/%s/:%s", appdir, fallback_dir_name, old_env);
0142          old_env = getenv("LD_LIBRARY_PATH") ?: "";
0143     }
0144 }
0145 
0146 
0147 int main(int argc, char **argv)
0148 {
0149     char appdir_buf[PATH_MAX] = "";
0150     char *appdir = dirname(realpath("/proc/self/exe", appdir_buf));
0151     if (!appdir) {
0152          die("Could not access /proc/self/exe\n");
0153     }
0154 
0155     try_replace_library("libstdc++.so.6", "libstdcpp-fallback");
0156 
0157     char exec_path[PATH_MAX] = "";
0158     strcpy(exec_path, appdir);
0159     strcat(exec_path, "/usr/bin/krita");
0160 
0161     char *exec_args[argc + 1];
0162     exec_args[0] = exec_path;
0163 
0164     for (int i = 1; i < argc; i++) {
0165        exec_args[i] = argv[i];
0166     }
0167 
0168     exec_args[argc] = 0;
0169 
0170     int ret = execvp(exec_path, exec_args);
0171 
0172     if (ret == -1) {
0173         int error = errno;
0174         die("Error executing '%s': %s\n", exec_path, strerror(error));
0175     }
0176 
0177     return 0;
0178 }