aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/fs.c25
-rw-r--r--src/install.c45
-rw-r--r--src/internal_cmd.c92
-rw-r--r--src/mime.c97
-rw-r--r--src/relocation.c51
-rw-r--r--src/spm.c19
-rw-r--r--src/spm_build.c14
8 files changed, 337 insertions, 8 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d866ef0..80fb9d9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -3,7 +3,7 @@ include_directories(
${CMAKE_BINARY_DIR}/include
)
-add_executable(spm spm.c config.c compat.c deps.c fs.c rpath.c find.c shell.c archive.c strings.c relocation.c install.c config_global.c manifest.c checksum.c extern/url.c version_spec.c)
+add_executable(spm spm.c config.c compat.c deps.c fs.c rpath.c find.c shell.c archive.c strings.c relocation.c install.c config_global.c manifest.c checksum.c extern/url.c version_spec.c spm_build.c mime.c internal_cmd.c)
target_link_libraries(spm rt crypto ssl curl)
install(
TARGETS spm
diff --git a/src/fs.c b/src/fs.c
index f561c84..e20b6a7 100644
--- a/src/fs.c
+++ b/src/fs.c
@@ -299,6 +299,11 @@ int rsync(const char *_args, const char *_source, const char *_destination) {
return returncode;
}
+/**
+ * Return the size of a file
+ * @param filename
+ * @return
+ */
long int get_file_size(const char *filename) {
long int result = 0;
FILE *fp = fopen(filename, "rb");
@@ -337,6 +342,26 @@ int mkdirs(const char *_path, mode_t mode) {
return result;
}
+/**
+ * Convert size in bytes to the closest human-readable unit
+ *
+ * NOTE: Caller is responsible for freeing memory
+ *
+ * Example:
+ * ~~~{.c}
+ * char *output;
+ * output = human_readable_size(1); // "1B"
+ * free(output);
+ * output = human_readable_size(1024) // "1.0K"
+ * free(output);
+ * output = human_readable_size(1024000) // "1.0MB"
+ * free(output);
+ * // and so on
+ * ~~~
+ *
+ * @param n size to convert
+ * @return string
+ */
char *human_readable_size(uint64_t n) {
int i;
double result = (double)n;
diff --git a/src/install.c b/src/install.c
index e647d31..7ecb401 100644
--- a/src/install.c
+++ b/src/install.c
@@ -1,5 +1,40 @@
#include "spm.h"
+/**
+ *
+ * @param _path
+ * @return
+ */
+int metadata_remove(const char *_path) {
+ char *metadata[] = {
+ SPM_META_DEPENDS,
+ SPM_META_PREFIX_BIN,
+ SPM_META_PREFIX_TEXT,
+ SPM_META_MANIFEST,
+ NULL,
+ };
+
+ if (exists(_path) != 0) {
+ perror(_path);
+ fprintf(SYSERROR);
+ return -1;
+ }
+
+ for (int i = 0; metadata[i] != NULL; i++) {
+ char path[PATH_MAX];
+ sprintf(path, "%s%c%s", _path, DIRSEP, metadata[i]);
+ if (exists(path) != 0) {
+ continue;
+ }
+ if (unlink(path) < 0) {
+ perror(path);
+ fprintf(SYSERROR);
+ return -1;
+ }
+ }
+ return 0;
+}
+
int install(const char *destroot, const char *_package) {
char *package = find_package(_package);
if (!package) {
@@ -31,7 +66,7 @@ int install(const char *destroot, const char *_package) {
chdir(tmpdir);
{
// Rewrite binary prefixes
- RelocationEntry **b_record = prefixes_read(".SPM_PREFIX_BIN");
+ RelocationEntry **b_record = prefixes_read(SPM_META_PREFIX_BIN);
if (b_record) {
for (int i = 0; b_record[i] != NULL; i++) {
relocate(b_record[i]->path, b_record[i]->prefix, destroot);
@@ -39,7 +74,7 @@ int install(const char *destroot, const char *_package) {
}
// Rewrite text prefixes
- RelocationEntry **t_record = prefixes_read(".SPM_PREFIX_TEXT");
+ RelocationEntry **t_record = prefixes_read(SPM_META_PREFIX_TEXT);
if (t_record) {
for (int i = 0; t_record[i] != NULL; i++) {
file_replace_text(t_record[i]->path, t_record[i]->prefix, destroot);
@@ -51,9 +86,13 @@ int install(const char *destroot, const char *_package) {
}
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);
+
+ // Remove metadata files before copying
+ metadata_remove(source);
+
+ // Copy temporary directory to destination
if (rsync(NULL, source, destroot) != 0) {
exit(1);
}
diff --git a/src/internal_cmd.c b/src/internal_cmd.c
new file mode 100644
index 0000000..3f4d05d
--- /dev/null
+++ b/src/internal_cmd.c
@@ -0,0 +1,92 @@
+#include "spm.h"
+
+static char *internal_commands[] = {
+ "mkprefixbin", "generate prefix manifest (binary)",
+ "mkprefixtext", "generate prefix manifest (text)",
+ NULL, NULL,
+};
+
+void internal_command_list(void) {
+ printf("possible commands:\n");
+ for (int i = 0; internal_commands[i] != NULL; i++) {
+ printf(" %-20s - %-20s\n", internal_commands[i], internal_commands[i + 1]);
+ i++;
+ }
+}
+
+void mkprefix_usage(void) {
+ printf("usage: mkprefix[bin|text] {output_file} {dir} {prefix ...}\n");
+}
+
+int internal_cmd(int argc, char **argv) {
+ int command_valid = 0;
+ char *command = argv[1];
+ if (argc < 2) {
+ internal_command_list();
+ return 1;
+ }
+
+ for (int i = 0; internal_commands[i] != NULL; i++) {
+ if (strcmp(internal_commands[i], command) == 0) {
+ command_valid = 1;
+ break;
+ }
+ }
+
+ if (!command_valid) {
+ fprintf(stderr, "error: '%s' is not a valid command\n", command);
+ internal_command_list();
+ return 1;
+ }
+
+ if (strcmp(command, "mkprefixbin") == 0 || strcmp(command, "mkprefixtext") == 0) {
+ char *outfile = argv[2];
+ char *tree = argv[3];
+
+ int prefix_start = 4;
+ int prefixes;
+ for (int i = prefix_start; i < argc; i++) {
+ prefixes = i;
+ }
+
+ // Check arguments
+ if (!outfile) {
+ fprintf(stderr, "error: missing output file name\n");
+ mkprefix_usage();
+ return -1;
+ }
+ if (!tree) {
+ fprintf(stderr, "error: missing directory path\n");
+ mkprefix_usage();
+ return -1;
+ }
+ if (!prefixes) {
+ fprintf(stderr, "error: missing prefix string(s) (%d, %d)\n", prefix_start, prefixes);
+ mkprefix_usage();
+ return -1;
+ }
+
+ char **prefix = (char **) calloc(prefixes + 1, sizeof(char *));
+ if (!prefix) {
+ perror("prefix array");
+ fprintf(SYSERROR);
+ return -1;
+ }
+
+ // Populate array of prefixes; reusing pointers from argv
+ for (int i = 0; (i + prefix_start) < argc; i++) {
+ prefix[i] = argv[(i + prefix_start)];
+ }
+
+ if (SPM_GLOBAL.verbose) {
+ printf("Generating prefix manifest: %s\n", outfile);
+ }
+
+ if (strcmp(command, "mkprefixbin") == 0) {
+ prefixes_write(outfile, PREFIX_WRITE_BIN, prefix, tree);
+ } else if (strcmp(command, "mkprefixtext") == 0) {
+ prefixes_write(outfile, PREFIX_WRITE_TEXT, prefix, tree);
+ }
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/src/mime.c b/src/mime.c
new file mode 100644
index 0000000..d90cc3f
--- /dev/null
+++ b/src/mime.c
@@ -0,0 +1,97 @@
+#include "spm.h"
+
+Process *file_command(const char *_filename) {
+ char *filename = strdup(_filename);
+ Process *proc_info = NULL;
+ char sh_cmd[PATH_MAX];
+ sh_cmd[0] = '\0';
+#ifdef __APPLE__
+ const char *fmt_cmd = "file -I \"%s\"";
+#else // GNU
+ const char *fmt_cmd = "file -E -i \"%s\"";
+#endif
+
+ strchrdel(filename, "&;|");
+ sprintf(sh_cmd, fmt_cmd, filename);
+ shell(&proc_info, SHELL_OUTPUT, sh_cmd);
+
+#ifdef __APPLE__
+ // Force BSD command to return non-zero when a file can't be found
+ const char *failmsg = ": cannot open";
+ if (strstr(proc_info->output, failmsg) != NULL) {
+ proc_info->returncode = 1;
+ }
+#endif
+ free(filename);
+ return proc_info;
+}
+
+Mime *file_mimetype(const char *filename) {
+ char **output = NULL;
+ char **parts = NULL;
+ Mime *type = NULL;
+ Process *proc = file_command(filename);
+
+ if (proc->returncode != 0) {
+ return NULL;
+ }
+ output = split(proc->output, ":");
+ if (!output || output[1] == NULL) {
+ return NULL;
+ }
+ parts = split(output[1], ";");
+ if (!parts || !parts[0] || !parts[1]) {
+ return NULL;
+ }
+
+ char *what = strdup(parts[0]);
+ what = lstrip(what);
+
+ char *charset = strdup(strchr(parts[1], '=') + 1);
+ charset = lstrip(charset);
+ charset[strlen(charset) - 1] = '\0';
+
+ char *origin = strdup(realpath(filename, NULL));
+
+ type = (Mime *)calloc(1, sizeof(Mime));
+ type->origin = origin;
+ type->type = strdup(what);
+ type->charset = strdup(charset);
+
+ split_free(output);
+ split_free(parts);
+ return type;
+}
+
+void mime_free(Mime *m) {
+ if (m != NULL) {
+ free(m->origin);
+ free(m->type);
+ free(m->charset);
+ free(m);
+ }
+}
+
+int file_is_text(const char *filename) {
+ int result = 0;
+ char *path = normpath(filename);
+ Mime *type = file_mimetype(path);
+ if (startswith(type->type, "text/") == 0) {
+ result = 1;
+ }
+ free(path);
+ mime_free(type);
+ return result;
+}
+
+int file_is_binary(const char *filename) {
+ int result = 0;
+ char *path = normpath(filename);
+ Mime *type = file_mimetype(path);
+ if (startswith(type->type, "application/") == 0 && strcmp(type->charset, "binary") == 0) {
+ result = 1;
+ }
+ free(path);
+ mime_free(type);
+ return result;
+} \ No newline at end of file
diff --git a/src/relocation.c b/src/relocation.c
index 13ae799..87b204e 100644
--- a/src/relocation.c
+++ b/src/relocation.c
@@ -201,6 +201,57 @@ RelocationEntry **prefixes_read(const char *filename) {
return entry;
}
+/**
+ * Generate a prefix manifest
+ *
+ * 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, "/usr/share/man/7");
+ * ~~~
+ *
+ * @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;
+ }
+
+ FSTree *fsdata = fstree(tree);
+ if (!fsdata) {
+ fprintf(SYSERROR);
+ return -1;
+ }
+ for (int i = 0; i < fsdata->files_length; i++) {
+ for (int p = 0; prefix[p] != NULL; p++) {
+ int proceed = 0;
+ if (find_in_file(fsdata->files[i], prefix[p]) == 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]);
+ }
+
+ if (!proceed) {
+ continue;
+ }
+
+ fprintf(fp, "#%s\n%s\n", prefix[p], fsdata->files[i]);
+ }
+ }
+ }
+ fclose(fp);
+ return 0;
+}
+
int relocate(const char *_filename, const char *_oldstr, const char *_newstr) {
int returncode;
Process *proc = NULL;
diff --git a/src/spm.c b/src/spm.c
index b6545aa..bca6353 100644
--- a/src/spm.c
+++ b/src/spm.c
@@ -13,14 +13,15 @@ const int PACKAGE_MAX = 0xff;
void usage(const char *program_name) {
printf(
- "usage: %s [-hVv] [-I|--install {package ...}]\n"
+ "usage: %s [-hVvBIrLS]\n"
" -h, --help show this help message\n"
" -V, --version show version\n"
" -v, --verbose show more information\n"
+ " -B, --build build package(s)\n"
" -I, --install install package(s)\n"
- " -S --search search for a package\n"
- " -L --list list available packages\n"
- " -r --root installation prefix (requires --install)\n"
+ " -r, --root installation prefix (requires --install)\n"
+ " -L, --list list available packages\n"
+ " -S, --search search for a package\n"
, program_name
);
}
@@ -77,6 +78,16 @@ int main(int argc, char *argv[]) {
manifest_free(info);
exit(0);
}
+ else if (strcmp(arg, "--cmd") == 0) {
+ int c = argc - i;
+ char **a = &argv[i];
+ exit(internal_cmd(c, a));
+ }
+ else if (strcmp(arg, "-B") == 0 || strcmp(arg, "--build") == 0) {
+ int c = argc - i;
+ char **a = &argv[i];
+ exit(build(c, a));
+ }
else if (strcmp(arg, "-L") == 0 || strcmp(arg, "--list") == 0) {
RUNTIME_LIST = 1;
}
diff --git a/src/spm_build.c b/src/spm_build.c
new file mode 100644
index 0000000..4cc4c47
--- /dev/null
+++ b/src/spm_build.c
@@ -0,0 +1,14 @@
+#include "spm.h"
+
+int build(int argc, char **argv) {
+ printf("build:\n");
+ printf("argc: %d\n", argc);
+ printf("argv:\n");
+ for (int i = 0; i < argc; i++) {
+ printf("%d: %s\n", i, argv[i]);
+ }
+
+ return 0;
+}
+
+