diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2020-03-07 01:45:07 -0500 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2020-03-07 01:45:07 -0500 |
commit | 2a9eaa0aa4a046bb2dfd4c2aeb1ebbdcff0770b9 (patch) | |
tree | 374904f82f827222746c8a4ca40664eba6641d7f /src | |
parent | e6d43d723b75ffc489f436238459175eab49d895 (diff) | |
download | spmc-2a9eaa0aa4a046bb2dfd4c2aeb1ebbdcff0770b9.tar.gz |
Refactor RPATH creation:
* Decreased complexity
* Most rpath_* functions accept a FSTree structure now
* Fewer calls to chdir() overall
* Deeply nested libraries are detected
* Libraries are no longer confined to lib/ and /lib64
Diffstat (limited to 'src')
-rw-r--r-- | src/internal_cmd.c | 8 | ||||
-rw-r--r-- | src/relocation.c | 3 | ||||
-rw-r--r-- | src/rpath.c | 190 | ||||
-rw-r--r-- | src/spm.c | 5 |
4 files changed, 104 insertions, 102 deletions
diff --git a/src/internal_cmd.c b/src/internal_cmd.c index 558116d..ef828c8 100644 --- a/src/internal_cmd.c +++ b/src/internal_cmd.c @@ -270,15 +270,19 @@ void rpath_autoset_interface_usage(void) { * @return return value of `rpath_autoset` */ int rpath_autoset_interface(int argc, char **argv) { - if (argc < 2) { + if (argc < 3) { rpath_autoset_interface_usage(); return -1; } char *filename = argv[1]; - int result = rpath_autoset(filename); + const char *topdir = argv[2]; + FSTree *libs = rpath_libraries_available(topdir); + int result = rpath_autoset(filename, libs); + if (result < 0) { fprintf(SYSERROR); } + return result; } diff --git a/src/relocation.c b/src/relocation.c index 2ef72eb..c235abe 100644 --- a/src/relocation.c +++ b/src/relocation.c @@ -387,6 +387,7 @@ void relocate_root(const char *destroot, const char *baseroot) { getcwd(cwd, sizeof(cwd)); chdir(baseroot); { + FSTree *libs = rpath_libraries_available("."); // Rewrite binary prefixes b_record = prefixes_read(SPM_META_PREFIX_BIN); if (b_record) { @@ -395,7 +396,7 @@ void relocate_root(const char *destroot, const char *baseroot) { if (SPM_GLOBAL.verbose) { printf("Relocate RPATH: %s\n", b_record[i]->path); } - rpath_autoset(b_record[i]->path); + rpath_autoset(b_record[i]->path, libs); } if (SPM_GLOBAL.verbose) { printf("Relocate DATA : %s\n", b_record[i]->path); diff --git a/src/rpath.c b/src/rpath.c index fbfdb18..e0f4a7e 100644 --- a/src/rpath.c +++ b/src/rpath.c @@ -120,29 +120,19 @@ char *rpath_get(const char *_filename) { * @param _filename * @return */ -char *rpath_generate(const char *_filename) { - char *origin = "$ORIGIN/../lib:$ORIGIN/"; +char *rpath_generate(const char *_filename, FSTree *tree) { char *filename = realpath(_filename, NULL); - if (!filename) { return NULL; } - char *nearest_lib = rpath_autodetect(filename); - if (!nearest_lib) { - free(filename); - return NULL; - } - - char *result = join((char *[]) {origin, nearest_lib, NULL}, ""); + char *result = rpath_autodetect(filename, tree); if (!result) { free(filename); - free(nearest_lib); return NULL; } free(filename); - free(nearest_lib); return result; } @@ -154,20 +144,8 @@ char *rpath_generate(const char *_filename) { */ int rpath_set(const char *filename, const char *rpath) { int returncode = 0; - /* - char *rpath_orig = rpath_get(filename); - if (!rpath_orig) { - return -1; - } - - // Are the original and new RPATH identical? - if (strcmp(rpath_orig, rpath) == 0) { - free(rpath_orig); - return 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); @@ -184,10 +162,10 @@ int rpath_set(const char *filename, const char *rpath) { * @param _rpath * @return */ -int rpath_autoset(const char *filename) { +int rpath_autoset(const char *filename, FSTree *tree) { int returncode = 0; - char *rpath_new = rpath_generate(filename); + char *rpath_new = rpath_generate(filename, tree); if (!rpath_new) { return -1; } @@ -199,98 +177,118 @@ int rpath_autoset(const char *filename) { } /** - * Using `filename` as a starting point, step backward through the filesystem looking for a lib directory + * Find shared libraries in a directory tree + * + * @param root directory + * @return `FSTree` + */ +FSTree *rpath_libraries_available(const char *root) { + // TODO: Darwin support + FSTree *tree = fstree(root, (char *[]) {".so", 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) { - int has_real_libdir = 0; +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; - int multilib_os = (exists("/lib64") == 0); + + 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; // Change directory to the requested root chdir(start); - char *visit = NULL; // Current directory - char relative[PATH_MAX]; // Generated relative path to lib directory - - // Initialize character arrays; - relative[0] = '\0'; + // Count the relative path distance between the location of the binary, and the top of the root + visit = dirname(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); - while(1) { - StrList *libs = NULL; + // return to calling directory + chdir(cwd); - // Where are we in the file system? - if((visit = getcwd(NULL, PATH_MAX)) == NULL) { - exit(errno); - } + 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; + } - // Using the current visit path, check if it contains a lib directory - char *path = NULL; - if (multilib_os) - path = join((char *[]) {visit, "lib64", NULL}, DIRSEPS); - else - path = join((char *[]) {visit, "lib", NULL}, DIRSEPS); - - if (access(path, F_OK) == 0) { - // Check whether the lib directory contains one of `filename`'s libraries - libs = shlib_deps(filename); - if (libs != NULL) { - for (size_t i = 0; i < strlist_count(libs); i++) { - char *check_path = join((char *[]) {path, strlist_item(libs, i), NULL}, DIRSEPS); - if (exists(check_path) == 0) { - // The library exists so mark it for processing - has_real_libdir = 1; // gate for memory allocation below - break; - } - free(check_path); + 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) { + size_t match_offset = 0; + + // 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); } - strlist_free(libs); + } else { + strcat(relative, ".."); + strcat(relative, DIRSEPS); } - // Stop processing when a good lib directory is found - if (has_real_libdir != 0) { - if (multilib_os) { - strcat(relative, "lib64"); - } else { - strcat(relative, "lib"); - } - free(path); - free(visit); - break; + // fstree relative mode returns truncated absolute paths, so "strip" the absolute path notation + if (startswith(match, "./")) { + match_offset = 2; } - } - // Reaching the top of the file system indicates our search for a lib directory failed - else if (strcmp(visit, "/") == 0) { - free(path); - free(visit); - break; - } - - // Nothing found - // Append another relative path step - strcat(relative, ".."); - strcat(relative, DIRSEPS); - // Step one directory up - chdir(".."); - free(path); - free(visit); - } + // Append the match to the relative path string + strcat(relative, match + match_offset); - // If we found a viable lib directory, allocate memory for it - if (has_real_libdir) { - result = strdup(relative); - if (!result) { - chdir(cwd); // return to calling directory - return NULL; + // 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); + } } } - chdir(cwd); // return to calling directory + // Populate result string + result = join(libs->data, ":"); + + // Clean up + strlist_free(libs); + strlist_free(libs_wanted); free(rootdir); free(cwd); free(start); @@ -29,9 +29,7 @@ void usage(const char *program_name) { } int main(int argc, char *argv[], char *arge[]) { - char program_name[strlen(argv[0]) + 1]; - memset(program_name, '\0', sizeof(program_name) + 1); - strcpy(program_name, basename(argv[0])); + char *program_name = strdup(basename(argv[0])); // not much to see here yet // at the moment this will all be random tests, for better or worse @@ -320,5 +318,6 @@ int main(int argc, char *argv[], char *arge[]) { strlist_free(packages); manifestlist_free(mf); spm_hierarchy_free(rootfs); + free(program_name); return 0; } |