aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2020-03-07 01:45:07 -0500
committerJoseph Hunkeler <jhunkeler@gmail.com>2020-03-07 01:45:07 -0500
commit2a9eaa0aa4a046bb2dfd4c2aeb1ebbdcff0770b9 (patch)
tree374904f82f827222746c8a4ca40664eba6641d7f /src
parente6d43d723b75ffc489f436238459175eab49d895 (diff)
downloadspmc-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.c8
-rw-r--r--src/relocation.c3
-rw-r--r--src/rpath.c190
-rw-r--r--src/spm.c5
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);
diff --git a/src/spm.c b/src/spm.c
index 7f153a8..f398f0e 100644
--- a/src/spm.c
+++ b/src/spm.c
@@ -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;
}