aboutsummaryrefslogtreecommitdiff
path: root/src/rpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpath.c')
-rw-r--r--src/rpath.c303
1 files changed, 0 insertions, 303 deletions
diff --git a/src/rpath.c b/src/rpath.c
deleted file mode 100644
index 4d4d801..0000000
--- a/src/rpath.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/**
- * @file rpath.c
- */
-#include "spm.h"
-
-/**
- * Wrapper function to execute `patchelf` with arguments
- * @param _filename Path of file to modify
- * @param _args Arguments to pass to `patchelf`
- * @return success=Process struct, failure=NULL
- */
-Process *patchelf(const char *_filename, const char *_args) {
- char *filename = strdup(_filename);
- char *args = strdup(_args);
- Process *proc_info = NULL;
- char sh_cmd[PATH_MAX];
- sh_cmd[0] = '\0';
-
- strchrdel(args, SHELL_INVALID);
- strchrdel(filename, SHELL_INVALID);
- sprintf(sh_cmd, "patchelf %s %s 2>&1", args, filename);
-
- if (SPM_GLOBAL.verbose > 1) {
- printf(" EXEC : %s\n", sh_cmd);
- }
-
- shell(&proc_info, SHELL_OUTPUT, sh_cmd);
-
- free(filename);
- free(args);
- return proc_info;
-}
-
-/**
- * Determine whether a RPATH or RUNPATH is present in file
- *
- * TODO: Replace with OS-native solution(s)
- *
- * @param _filename path to executable or library
- * @return -1=OS error, 0=has rpath, 1=not found
- */
-int has_rpath(const char *_filename) {
- int result = 1; // default: not found
-
- char *filename = strdup(_filename);
- if (!filename) {
- return -1;
- }
-
- // sanitize input path
- strchrdel(filename, SHELL_INVALID);
-
- Process *pe = patchelf(filename, "--print-rpath");
- strip(pe->output);
- if (!isempty(pe->output)) {
- result = 0;
- }
- else {
- // something went wrong with patchelf other than
- // what we're looking for
- result = -1;
- }
-
- free(filename);
- shell_free(pe);
- return result;
-}
-
-/**
- * Returns a RPATH or RUNPATH if one is defined in `_filename`
- *
- * TODO: Replace with OS-native solution(s)
- *
- * @param _filename path to executable or library
- * @return RPATH string, NULL=error (caller is responsible for freeing memory)
- */
-char *rpath_get(const char *_filename) {
- if ((has_rpath(_filename)) != 0) {
- return strdup("");
- }
- char *filename = strdup(_filename);
- if (!filename) {
- return NULL;
- }
- char *path = strdup(filename);
- if (!path) {
- free(filename);
- return NULL;
- }
-
- char *rpath = NULL;
-
- // sanitize input path
- strchrdel(path, SHELL_INVALID);
-
- Process *pe = patchelf(filename, "--print-rpath");
- if (pe->returncode != 0) {
- fprintf(stderr, "patchelf error: %s %s\n", path, strip(pe->output));
- return NULL;
- }
-
- rpath = (char *)calloc(strlen(pe->output) + 1, sizeof(char));
- if (!rpath) {
- free(filename);
- free(path);
- shell_free(pe);
- return NULL;
- }
-
- strncpy(rpath, pe->output, strlen(pe->output));
- strip(rpath);
-
- free(filename);
- free(path);
- shell_free(pe);
- return rpath;
-}
-
-/**
- * Generate a RPATH in the form of:
- *
- * `$ORIGIN/relative/path/to/lib/from/_filename/path`
- *
- * @param _filename
- * @return
- */
-char *rpath_generate(const char *_filename, FSTree *tree) {
- char *filename = realpath(_filename, NULL);
- if (!filename) {
- return NULL;
- }
-
- char *result = rpath_autodetect(filename, tree);
- if (!result) {
- free(filename);
- return NULL;
- }
-
- free(filename);
- return result;
-}
-
-/**
- * Set the RPATH of an executable
- * @param filename
- * @param rpath
- * @return
- */
-int rpath_set(const char *filename, const char *rpath) {
- int returncode = 0;
- char args[PATH_MAX];
-
- memset(args, '\0', PATH_MAX);
- sprintf(args, "--set-rpath '%s'", rpath); // note: rpath requires single-quotes
- Process *pe = patchelf(filename, args);
- if (pe != NULL) {
- returncode = pe->returncode;
- }
- shell_free(pe);
- return returncode;
-}
-
-/**
- * Automatically detect the nearest lib directory and set the RPATH of an executable
- * @param filename
- * @param _rpath
- * @return
- */
-int rpath_autoset(const char *filename, FSTree *tree) {
- int returncode = 0;
-
- char *rpath_new = rpath_generate(filename, tree);
- if (!rpath_new) {
- return -1;
- }
-
- returncode = rpath_set(filename, rpath_new);
- free(rpath_new);
-
- return returncode;
-}
-
-/**
- * Find shared libraries in a directory tree
- *
- * @param root directory
- * @return `FSTree`
- */
-FSTree *rpath_libraries_available(const char *root) {
- FSTree *tree = fstree(root, (char *[]) {SPM_SHLIB_EXTENSION, NULL}, SPM_FSTREE_FLT_CONTAINS | SPM_FSTREE_FLT_RELATIVE);
- if (tree == NULL) {
- perror(root);
- fprintf(SYSERROR);
- return NULL;
- }
- return tree;
-}
-
-/**
- * Compute a RPATH based on the location `filename` relative to the shared libraries it requires
- *
- * @param filename path to file (or a directory)
- * @return success=relative path from `filename` to nearest lib directory, failure=NULL
- */
-char *rpath_autodetect(const char *filename, FSTree *tree) {
- const char *origin = "$ORIGIN";
- char *rootdir = dirname(filename);
- char *start = realpath(rootdir, NULL);
- char *cwd = realpath(".", NULL);
- char *result = NULL;
-
- char *visit = NULL; // Current directory
- char _relative[PATH_MAX] = {0,}; // Generated relative path to lib directory
- char *relative = _relative; // Pointer to relative path
- size_t depth_to_root = 0;
-
- // BUG: Perl dumps its shared library in a strange place.
- // This function returns `$ORIGIN/../../../CORE` which is not what we want to see.
- // TODO: We WANT to see this: `$ORIGIN/../lib/perl5/xx.xx.xx/<arch>/CORE` not just the basename()
-
- // Change directory to the requested root
- chdir(start);
-
- // Count the relative path distance between the location of the binary, and the top of the root
- visit = strdup(start);
- for (depth_to_root = 0; strcmp(tree->root, visit) != 0; depth_to_root++) {
- // Copy the current visit pointer
- char *prev = visit;
- // Walk back another directory level
- visit = dirname(visit);
- // Free previous visit pointer
- if (prev) free(prev);
- }
- free(visit);
-
- // return to calling directory
- chdir(cwd);
-
- StrList *libs = strlist_init();
- if (libs == NULL) {
- fprintf(stderr, "failed to initialize library StrList\n");
- fprintf(SYSERROR);
- return NULL;
- }
-
- StrList *libs_wanted = shlib_deps(filename);
- if (libs_wanted == NULL) {
- fprintf(stderr, "failed to retrieve list of share libraries from: %s\n", filename);
- fprintf(SYSERROR);
- return NULL;
- }
-
- for (size_t i = 0; i < strlist_count(libs_wanted); i++) {
- // zero out relative path string
- memset(_relative, '\0', sizeof(_relative));
- // Get the shared library name we are going to look for in the tree
- char *shared_library = strlist_item(libs_wanted, i);
-
- // Is the the shared library in the tree?
- char *match = NULL;
- if ((match = dirname(strstr_array(tree->files, shared_library))) != NULL) {
- // Begin generating the relative path string
- strcat(relative, origin);
- strcat(relative, DIRSEPS);
-
- // Append the number of relative levels to the relative path string
- if (depth_to_root) {
- for (size_t d = 0; d < depth_to_root; d++) {
- strcat(relative, "..");
- strcat(relative, DIRSEPS);
- }
- } else {
- strcat(relative, "..");
- strcat(relative, DIRSEPS);
- }
- // Append the match to the relative path string
- strcat(relative, basename(match));
-
- // Append relative path to array of libraries (if it isn't already in there)
- if (strstr_array(libs->data, relative) == NULL) {
- strlist_append(libs, relative);
- }
- }
- }
-
- // Some programs do not require local libraries provided by SPM (i.e. libc)
- // Inject "likely" defaults here
- if (strlist_count(libs) == 0) {
- strlist_append(libs, "$ORIGIN/../lib");
- strlist_append(libs, "$ORIGIN/../lib64");
- }
-
- // Populate result string
- result = join(libs->data, ":");
-
- // Clean up
- strlist_free(libs);
- strlist_free(libs_wanted);
- free(rootdir);
- free(cwd);
- free(start);
- return result;
-}