aboutsummaryrefslogtreecommitdiff
path: root/relocation.c
diff options
context:
space:
mode:
Diffstat (limited to 'relocation.c')
-rw-r--r--relocation.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/relocation.c b/relocation.c
new file mode 100644
index 0000000..13ae799
--- /dev/null
+++ b/relocation.c
@@ -0,0 +1,237 @@
+#include "spm.h"
+
+int replace_text(char *data, const char *spattern, const char *sreplacement) {
+ 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\n");
+ return -1;
+ }
+
+ while (*tmp != '\0') {
+ if (strncmp(tmp, spattern, spattern_len) == 0) {
+ memmove(tmp, sreplacement, sreplacement_len);
+ memmove(tmp + sreplacement_len, tmp + spattern_len, data_len - spattern_len);
+ }
+ tmp++;
+ }
+ return 0;
+}
+
+/**
+ * Replace all occurrences of `oldstr` in file `path` with `newstr`
+ * @param filename
+ * @param oldstr
+ * @param newstr
+ * @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) {
+ 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
+ * @return success=array of RelocationEntry, failure=NULL
+ */
+RelocationEntry **prefixes_read(const char *filename) {
+ size_t i = 0;
+ int record_count = 0;
+ int parity = 0;
+ FILE *fp = fopen(filename, "r");
+ if (!fp) {
+ fprintf(SYSERROR);
+ return NULL;
+ }
+ RelocationEntry **entry = NULL;
+ char line[BUFSIZ];
+ memset(line, '\0', BUFSIZ);
+
+ while (fgets(line, BUFSIZ, fp) != NULL) {
+ if (isempty(line)) {
+ 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: %d %% 2 = %d)\n", filename, record_count, parity);
+ return NULL;
+ }
+ record_count /= 2;
+
+ entry = (RelocationEntry **)calloc(record_count + 1, sizeof(RelocationEntry *));
+ if (!entry) {
+ return NULL;
+ }
+ for (int 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;
+ while (fgets(line, BUFSIZ, fp) != NULL) {
+ char *wtf = line;
+ if (isempty(line)) {
+ continue;
+ }
+ if (startswith(line, "#") == 0) {
+ 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(line) + 1, sizeof(char));
+ if (!entry[i]->prefix) {
+ fclose(fp);
+ return NULL;
+ }
+ strncpy(entry[i]->prefix, line, strlen(line));
+ // 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(line) + 1, sizeof(char));
+ if (!entry[i]->path) {
+ fclose(fp);
+ return NULL;
+ }
+ strncpy(entry[i]->path, line, strlen(line));
+ entry[i]->path = strip(entry[i]->path);
+ do_path = 0;
+ }
+ i++;
+ }
+ fclose(fp);
+ return entry;
+}
+
+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];
+
+ 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;
+}
+