aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2019-12-11 01:49:30 -0500
committerJoseph Hunkeler <jhunkeler@gmail.com>2019-12-11 01:49:30 -0500
commit07c2c5067927464afcb34ced4ffa65cc41a59339 (patch)
tree060164ae260fc48631819b662f43c22db8ec36b9
parentacbd792900767949c5836e3fc401b134ab93e144 (diff)
downloadspmc-07c2c5067927464afcb34ced4ffa65cc41a59339.tar.gz
Implement binary and text relocation
-rw-r--r--spm.c218
-rw-r--r--spm.h10
2 files changed, 225 insertions, 3 deletions
diff --git a/spm.c b/spm.c
index 51d7890..6a4fe91 100644
--- a/spm.c
+++ b/spm.c
@@ -1191,6 +1191,55 @@ int rmdirs(const char *_path) {
return 0;
}
+/**
+ * Replace all occurrences of `_oldstr` in `_oldbuf` with `_newstr`
+ * @param _oldbuf
+ * @param _oldstr
+ * @param _newstr
+ * @return
+ */
+char *replace_text(char *_oldbuf, const char *_oldstr, const char *_newstr) {
+ int occurrences = 0;
+ size_t _oldstr_len = strlen(_oldstr);
+ size_t _newstr_len = strlen(_newstr);
+ size_t _oldbuf_len = strlen(_oldbuf);
+
+ // Determine the number of times _oldstr occurs in _oldbuf.
+ char *tmp = _oldbuf;
+ while (*tmp) {
+ if (strstr(tmp, _oldstr) == tmp) {
+ occurrences++;
+ // Move pointer past last occurrence
+ tmp += _oldstr_len - 1;
+ }
+ tmp++;
+ }
+
+ int i = 0;
+ char *result = (char *)calloc(1, ((occurrences * _newstr_len) + _oldbuf_len) + 1);
+ if (!result) {
+ return NULL;
+ }
+
+ // Continuously scan until _oldstr has been completely removed
+ while (strstr(_oldbuf, _oldstr) != NULL) {
+ // Search for _oldstr in _oldbuf
+ if (strstr(_oldbuf, _oldstr) == _oldbuf) {
+ // Copy replacement string into result buffer
+ strncpy(&result[i], _newstr, _newstr_len);
+ i += _newstr_len;
+ _oldbuf += _oldstr_len;
+ }
+ else {
+ // Write non-matches to result buffer
+ result[i++] = *_oldbuf++;
+ }
+
+ }
+
+ return result;
+}
+
int install(const char *destroot, const char *_package) {
char *package = find_package(_package);
if (!package) {
@@ -1204,24 +1253,155 @@ int install(const char *destroot, const char *_package) {
}
}
+ char cwd[PATH_MAX];
char source[PATH_MAX];
char template[PATH_MAX];
char suffix[PATH_MAX] = "spm_destroot_XXXXXX";
sprintf(template, "%s%c%s", TMP_DIR, DIRSEP, suffix);
+ // Create a new temporary directory and extract the request package into it
char *tmpdir = mkdtemp(template);
tar_extract_archive(package, tmpdir);
- // do things
+ getcwd(cwd, sizeof(cwd));
+
+ chdir(tmpdir);
+ {
+ RelocationEntry **b_record = read_prefixes(".SPM_PREFIX_BIN");
+ if (!b_record) {
+ fprintf(SYSERROR);
+ exit(1);
+ }
+
+ // Rewrite binary prefixes
+ for (int i = 0; b_record[i] != NULL; i++) {
+ relocate(b_record[i]->prefix, destroot, b_record[i]->path);
+ }
+ free_prefixes(b_record);
+
+
+ RelocationEntry **t_record = read_prefixes(".SPM_PREFIX_TEXT");
+ if (!t_record) {
+ fprintf(SYSERROR);
+ exit(1);
+ }
+
+ // Rewrite text prefixes
+ for (int i = 0; t_record[i] != NULL; i++) {
+ long int t_record_len = get_file_size(t_record[i]->path);
+ char *data_orig = (char *)calloc(t_record_len + 1, sizeof(char));
+ FILE *fp = fopen(t_record[i]->path, "r+");
+ fread(data_orig, t_record_len, sizeof(char), fp);
+ rewind(fp);
+
+ char *data_new = replace_text(data_orig, t_record[i]->prefix, destroot);
+ t_record_len = strlen(data_new);
+ fwrite(data_new, t_record_len, sizeof(char), fp);
+ free(data_orig);
+ free(data_new);
+ fclose(fp);
+ }
+ free_prefixes(t_record);
+ }
+ chdir(cwd);
+
+ // Append a trailing slash to tmpdir to direct rsync to copy files, not the directory, into destroot
sprintf(source, "%s%c", tmpdir, DIRSEP);
- char *wtf = source;
if (rsync(NULL, source, destroot) != 0) {
exit(1);
}
rmdirs(tmpdir);
+
free(package);
}
+/**
+ * Free memory allocated by `read_prefixes` function
+ * @param entry array of RelocationEntry
+ */
+void free_prefixes(RelocationEntry **entry) {
+ if (!entry) {
+ return;
+ }
+ for (int i = 0; entry[i] != NULL; i++) {
+ free(entry[i]);
+ }
+ free(entry);
+}
+
+/**
+ * Parse a prefix file
+ *
+ * The file format is as follows:
+ *
+ * ~~~
+ * #prefix
+ * path
+ * #prefix
+ * path
+ * #...N
+ * ...N
+ * ~~~
+ * @param filename
+ * @return success=array of RelocationEntry, failure=NULL
+ */
+RelocationEntry **read_prefixes(const char *filename) {
+ const int initial_records = 2;
+ size_t i = 0;
+ FILE *fp = fopen(filename, "r");
+ if (!fp) {
+ fprintf(SYSERROR);
+ return NULL;
+ }
+ char prefix[BUFSIZ];
+ char path[BUFSIZ];
+ RelocationEntry **entry = NULL;
+
+ // Initialize the relocation entry array
+ entry = (RelocationEntry **)calloc(initial_records, sizeof(RelocationEntry *));
+ if (!entry) {
+ return NULL;
+ }
+
+ // Read two lines at a time from the prefix file
+ while (fgets(prefix, BUFSIZ, fp) != NULL && fgets(path, BUFSIZ, fp) != NULL) {
+ // Allocate a relocation record
+ entry[i] = (RelocationEntry *)calloc(1, sizeof(RelocationEntry));
+ if (!entry[i]) {
+ free_prefixes(entry);
+ fclose(fp);
+ return NULL;
+ }
+
+ // Populate prefix data (a prefix starts with a #)
+ entry[i]->prefix = (char *)calloc(strlen(prefix) + 1, sizeof(char));
+ if (!entry[i]->prefix) {
+ free_prefixes(entry);
+ fclose(fp);
+ return NULL;
+ }
+ strncpy(entry[i]->prefix, prefix, strlen(prefix));
+ // Remove prefix delimiter and whitespace
+ strchrdel(entry[i]->prefix, "#");
+ entry[i]->prefix = strip(entry[i]->prefix);
+
+ // Populate path data
+ entry[i]->path = (char *)calloc(strlen(path) + 1, sizeof(char));
+ if (!entry[i]->path) {
+ free_prefixes(entry);
+ fclose(fp);
+ return NULL;
+ }
+ strncpy(entry[i]->path, path, strlen(path));
+ entry[i]->path = strip(entry[i]->path);
+
+ entry = (RelocationEntry **) reallocarray(entry, initial_records + i, sizeof(RelocationEntry *));
+ i++;
+ }
+ fclose(fp);
+ return entry;
+}
+
void init_config_global(void) {
SPM_GLOBAL.user_config_basedir = NULL;
SPM_GLOBAL.user_config_file = NULL;
@@ -1362,6 +1542,40 @@ int rsync(const char *_args, const char *_source, const char *_destination) {
return returncode;
}
+int relocate(const char *_oldstr, const char *_newstr, const char *_filename) {
+ int returncode;
+ Process *proc = NULL;
+ char *oldstr = strdup(_oldstr);
+ char *newstr = strdup(_newstr);
+ char *filename = strdup(_filename);
+ char cmd[PATH_MAX];
+
+ memset(cmd, '\0', sizeof(cmd));
+ sprintf(cmd, "reloc \"%s\" \"%s\" \"%s\" \"%s\"", oldstr, newstr, filename, filename);
+
+ // sanitize command
+ strchrdel(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, proc->output);
+ }
+
+ shell_free(proc);
+ free(oldstr);
+ free(newstr);
+ free(filename);
+ return returncode;
+}
+
int main(int argc, char *argv[]) {
// not much to see here yet
// at the moment this will all be random tests, for better or worse
diff --git a/spm.h b/spm.h
index c5b0b58..6dd6b9c 100644
--- a/spm.h
+++ b/spm.h
@@ -68,12 +68,19 @@ typedef struct {
char *output;
} Process;
+typedef struct {
+ char *prefix;
+ char *path;
+} RelocationEntry;
+
void shell(Process **proc_info, u_int64_t option, const char *fmt, ...);
void shell_free(Process *proc_info);
int tar_extract_archive(const char *_archive, const char *_destination);
int tar_extract_file(const char *archive, const char* filename, const char *destination);
int rsync(const char *_args, const char *_source, const char *_destination);
-int errglob(const char *epath, int eerrno);
+int relocate(const char *_oldstr, const char *_newstr, const char *_filename);
+RelocationEntry **read_prefixes(const char *filename);
+void free_prefixes(RelocationEntry **entry);
int num_chars(const char *sptr, int ch);
int startswith(const char *sptr, const char *pattern);
@@ -92,6 +99,7 @@ int fstrstr(const char *filename, const char *pattern);
char *find_executable(const char *program);
char *find_file(const char *root, const char *filename);
char *find_package(const char *filename);
+int errglob(const char *epath, int eerrno);
Process *patchelf(const char *_filename, const char *_args);
char *libdir_nearest(const char *filename);