diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2020-03-18 22:25:27 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2020-03-18 22:25:27 -0400 |
commit | ccaeb7092b5ad40b1b3833c987ba3ec4d47f0bb8 (patch) | |
tree | ae167772a9a2343aa77bf8944b56abe853f6a2ec /src/relocation.c | |
parent | 3731bb4679ee8716d4f579d5744c36a2d1b4a257 (diff) | |
download | spmc-ccaeb7092b5ad40b1b3833c987ba3ec4d47f0bb8.tar.gz |
Refactor project: build/install libspm[_static.a].so to make unit testing possible
Diffstat (limited to 'src/relocation.c')
-rw-r--r-- | src/relocation.c | 440 |
1 files changed, 0 insertions, 440 deletions
diff --git a/src/relocation.c b/src/relocation.c deleted file mode 100644 index f22a25d..0000000 --- a/src/relocation.c +++ /dev/null @@ -1,440 +0,0 @@ -/** - * @file relocation.c - */ -#include "spm.h" - -const char *METADATA_FILES[] = { - SPM_META_DEPENDS, - SPM_META_PREFIX_BIN, - SPM_META_PREFIX_TEXT, - SPM_META_DESCRIPTOR, - SPM_META_FILELIST, - NULL, -}; - -/** - * Replace all occurrences of `spattern` with `sreplacement` in `data` - * - * ~~~{.c} - * char *str = (char *)calloc(100, sizeof(char)); - * strcpy(str, "This are a test."); - * replace_text(str, "are", "is"); - * // str is: "This is a test." - * free(str); - * ~~~ - * - * @param data string to modify - * @param spattern string value to replace - * @param sreplacement replacement string value - * @return success=0, error=-1 - */ -int replace_text(char *data, const char *spattern, const char *sreplacement) { - if (data == NULL || spattern == NULL || sreplacement == NULL) { - return -1; - } - - char *tmp = data; - size_t data_len = strlen(data); - size_t spattern_len = strlen(spattern); - size_t sreplacement_len = strlen(sreplacement); - - if (sreplacement_len > spattern_len) { - fprintf(stderr, "replacement string too long: %zu > %zu\n '%s'\n '%s'\n", sreplacement_len, spattern_len, sreplacement, spattern); - return -1; - } - - while (*tmp != '\0') { - if (strncmp(tmp, spattern, spattern_len) == 0) { - if (sreplacement_len == 1) { - *tmp = *sreplacement; - } else { - memmove(tmp, sreplacement, sreplacement_len); - memmove(tmp + sreplacement_len, tmp + spattern_len, data_len - spattern_len); - memset(tmp + sreplacement_len + (data_len - spattern_len), '\0', 1); - } - } - tmp++; - } - return 0; -} - -/** - * Replace all occurrences of `oldstr` in file `path` with `newstr` - * @param filename file to modify - * @param oldstr string to replace - * @param newstr replacement string - * @return success=0, failure=-1, or value of `ferror()` - */ -int file_replace_text(char *filename, const char *spattern, const char *sreplacement) { - char data[BUFSIZ]; - char tempfile[PATH_MAX]; - FILE *fp = NULL; - if ((fp = fopen(filename, "r")) == NULL) { - perror(filename); - return -1; - } - - sprintf(tempfile, "%s.spmfrt", filename); - FILE *tfp = NULL; - if ((tfp = fopen(tempfile, "w+")) == NULL) { - fclose(fp); - perror(tempfile); - return -1; - } - - // Zero the data buffer - memset(data, '\0', BUFSIZ); - while(fgets(data, BUFSIZ, fp) != NULL) { - replace_text(data, spattern, sreplacement); - fprintf(tfp, "%s", data); - } - fclose(fp); - rewind(tfp); - - // Truncate the original file - if ((fp = fopen(filename, "w+")) == NULL) { - perror(filename); - return -1; - } - // Zero the data buffer once more - memset(data, '\0', BUFSIZ); - // Dump the contents of the temporary file into the original file - while(fgets(data, BUFSIZ, tfp) != NULL) { - fprintf(fp, "%s", data); - } - fclose(fp); - fclose(tfp); - - // Remove temporary file - unlink(tempfile); - return 0; -} - -/** - * Free memory allocated by `prefixes_read` function - * @param entry array of RelocationEntry - */ -void prefixes_free(RelocationEntry **entry) { - if (!entry) { - return; - } - for (int i = 0; entry[i] != NULL; i++) { - if (entry[i]->prefix) free(entry[i]->prefix); - if (entry[i]->path) free(entry[i]->path); - if (entry[i]) free(entry[i]); - } - free(entry); -} - -/** - * Parse a prefix file - * - * The file format is as follows: - * - * ~~~ - * #prefix - * path - * #prefix - * path - * #...N - * ...N - * ~~~ - * @param filename path to prefix manifest - * @return success=array of RelocationEntry, failure=NULL - */ -RelocationEntry **prefixes_read(const char *filename) { - size_t record_count = 0; - size_t parity = 0; - FILE *fp = fopen(filename, "r"); - if (!fp) { - fprintf(SYSERROR); - return NULL; - } - RelocationEntry **entry = NULL; - char line[BUFSIZ]; - char *lptr = line; - memset(lptr, '\0', BUFSIZ); - - while (fgets(lptr, BUFSIZ, fp) != NULL) { - if (isempty(lptr)) { - continue; - } - record_count++; - } - rewind(fp); - - // Initialize the relocation entry array - if (record_count == 0) { - return NULL; - } - - parity = record_count % 2; - if (parity != 0) { - fprintf(stderr, "%s: records are not divisible by 2 (got: %zu %% 2 = %zu)\n", filename, record_count, parity); - return NULL; - } - record_count /= 2; - - entry = (RelocationEntry **)calloc(record_count + 1, sizeof(RelocationEntry *)); - if (!entry) { - return NULL; - } - for (size_t i = 0; i < record_count; i++) { - entry[i] = (RelocationEntry *) calloc(1, sizeof(RelocationEntry)); - if (!entry[i]) { - return NULL; - } - } - - int do_prefix = 0; - int do_path = 0; - size_t i = 0; - while (fgets(lptr, BUFSIZ, fp) != NULL) { - if (isempty(lptr)) { - continue; - } - if (startswith(lptr, "#")) { - do_prefix = 1; - } - else { - do_path = 1; - } - - // Allocate a relocation record - if (!entry[i]) { - fclose(fp); - return NULL; - } - - - if (do_prefix) { - // Populate prefix data (a prefix starts with a #) - entry[i]->prefix = (char *) calloc(strlen(lptr) + 1, sizeof(char)); - if (!entry[i]->prefix) { - fclose(fp); - return NULL; - } - strncpy(entry[i]->prefix, lptr, strlen(lptr)); - // Remove prefix delimiter and whitespace - strchrdel(entry[i]->prefix, "#"); - entry[i]->prefix = strip(entry[i]->prefix); - do_prefix = 0; - continue; - } - - else if (do_path) { - // Populate path data - entry[i]->path = (char *) calloc(strlen(lptr) + 1, sizeof(char)); - if (!entry[i]->path) { - fclose(fp); - return NULL; - } - strncpy(entry[i]->path, lptr, strlen(lptr)); - entry[i]->path = strip(entry[i]->path); - do_path = 0; - } - i++; - } - fclose(fp); - return entry; -} - -/** - * Determine if `filename` is a SPM metadata file - * - * Example: - * - * ~~~{.c} - * #include "spm.h" - * - * int main() { - * if (file_is_metadata(".SPM_DEPENDS")) { - * // file is metadata - * } else { - * // file is not metadata - * } - * } - * ~~~ - * - * @param filename - * @return 0=no, 1=yes - */ -int file_is_metadata(const char *filename) { - for (size_t i = 0; METADATA_FILES[i] != NULL; i++) { - if (strstr(filename, METADATA_FILES[i]) != NULL) { - return 1; - } - } - return 0; -} - -/** - * Scan `tree` for files containing `prefix`. Matches are recorded in `output_file` with the following format: - * - * ~~~ - * #prefix - * path - * #prefix - * path - * #...N - * ...N - * ~~~ - * - * Example: - * ~~~{.c} - * char **prefixes = {"/usr", "/var", NULL}; - * prefixes_write("binary.manifest", PREFIX_WRITE_BIN, prefixes, "/usr/bin"); - * prefixes_write("text.manifest", PREFIX_WRITE_TEXT, prefixes, "/etc"); - * ~~~ - * - * @param output_file file path to create - * @param mode `PREFIX_WRITE_BIN`, `PREFIX_WRITE_TEXT` - * @param prefix array of prefix strings - * @param tree directory to scan - * @return success=0, failure=1, error=-1 - */ -int prefixes_write(const char *output_file, int mode, char **prefix, const char *tree) { - FILE *fp = fopen(output_file, "w+"); - if (!fp) { - perror(output_file); - fprintf(SYSERROR); - return -1; - } - - char *cwd = getcwd(NULL, PATH_MAX); - chdir(tree); - { - FSTree *fsdata = fstree(".", NULL, SPM_FSTREE_FLT_RELATIVE); - if (!fsdata) { - fclose(fp); - fprintf(SYSERROR); - return -1; - } - for (size_t i = 0; i < fsdata->files_length; i++) { - if (file_is_metadata(fsdata->files[i])) { - continue; - } - for (int p = 0; prefix[p] != NULL; p++) { - if (find_in_file(fsdata->files[i], prefix[p]) == 0) { - int proceed = 0; - if (mode == PREFIX_WRITE_BIN) { - proceed = file_is_binary(fsdata->files[i]); - } else if (mode == PREFIX_WRITE_TEXT) { - proceed = file_is_text(fsdata->files[i]); - } - - // file_is_* functions return NULL when they encounter anything but a regular file - if (!proceed) { - continue; - } - // Record in file - fprintf(fp, "#%s\n%s\n", prefix[p], fsdata->files[i]); - } - } - } - } chdir(cwd); - free(cwd); - fclose(fp); - return 0; -} - -/** - * Wrapper for `reloc` program. Replace text in binary data. - * @param _filename - * @param _oldstr - * @param _newstr - * @return - */ -int relocate(const char *_filename, const char *_oldstr, const char *_newstr) { - int returncode; - Process *proc = NULL; - char *oldstr = strdup(_oldstr); - char *newstr = strdup(_newstr); - char *filename = strdup(_filename); - char cmd[PATH_MAX]; - - // sanitize command - strchrdel(oldstr, SHELL_INVALID); - strchrdel(newstr, SHELL_INVALID); - strchrdel(filename, SHELL_INVALID); - - memset(cmd, '\0', sizeof(cmd)); - sprintf(cmd, "reloc \"%s\" \"%s\" \"%s\" \"%s\" 2>&1", oldstr, newstr, filename, filename); - - if (SPM_GLOBAL.verbose > 1) { - printf(" EXEC : %s\n", cmd); - } - - shell(&proc, SHELL_OUTPUT, cmd); - if (!proc) { - free(oldstr); - free(newstr); - free(filename); - return -1; - } - - returncode = proc->returncode; - if (returncode != 0 && proc->output) { - fprintf(stderr, "%s\n", proc->output); - } - - shell_free(proc); - free(oldstr); - free(newstr); - free(filename); - return returncode; -} - -/** - * Parse package metadata and set `baseroot` binaries/text to point to `destroot`. - * `baseroot` should be a temporary directory because its contents are modified - * - * @param destroot - * @param baseroot - */ -void relocate_root(const char *destroot, const char *baseroot) { - RelocationEntry **b_record = NULL; - RelocationEntry **t_record = NULL; - char cwd[PATH_MAX]; - - 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) { - for (int i = 0; b_record[i] != NULL; i++) { - if (file_is_binexec(b_record[i]->path)) { - if (SPM_GLOBAL.verbose) { - printf("Relocate RPATH: %s\n", b_record[i]->path); - } - rpath_autoset(b_record[i]->path, libs); - } - if (SPM_GLOBAL.verbose) { - printf("Relocate DATA : %s\n", b_record[i]->path); - } - relocate(b_record[i]->path, b_record[i]->prefix, destroot); - } - } - - // Rewrite text prefixes - t_record = prefixes_read(SPM_META_PREFIX_TEXT); - if (t_record) { - for (int i = 0; t_record[i] != NULL; i++) { - if (SPM_GLOBAL.verbose) { - printf("Relocate TEXT : %s\n", t_record[i]->path); - } - if (SPM_GLOBAL.verbose > 1) { - printf(" EDIT : '%s' -> '%s'\n", t_record[i]->prefix, destroot); - } - file_replace_text(t_record[i]->path, t_record[i]->prefix, destroot); - } - } - - prefixes_free(b_record); - prefixes_free(t_record); - } - chdir(cwd); -} - |