diff options
Diffstat (limited to 'lib/internal_cmd.c')
-rw-r--r-- | lib/internal_cmd.c | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/lib/internal_cmd.c b/lib/internal_cmd.c new file mode 100644 index 0000000..a192ccf --- /dev/null +++ b/lib/internal_cmd.c @@ -0,0 +1,401 @@ +/** + * @file internal_cmd.c + */ +#include "spm.h" + +/** + * List of valid internal commands + */ +static char *internal_commands[] = { + "mkprefixbin", "generate prefix manifest (binary)", + "mkprefixtext", "generate prefix manifest (text)", + "mkmanifest", "generate package repository manifest", + "mkruntime", "emit runtime environment (stdout)", + "mirror_clone", "mirror a mirror", + "rpath_set", "modify binary RPATH", + "rpath_autoset", "determine nearest lib directory and set RPATH", + "get_package_ext", "show the default archive extension", + "get_sys_target", "show this system's arch/platform", + "check_rt_env", "check the integrity of the calling runtime environment", + NULL, NULL, +}; + +/** + * + */ +void mkprefix_interface_usage(void) { + printf("usage: mkprefix[bin|text] {output_file} {dir} {prefix ...}\n"); +} + +/** + * Create prefix manifests from the CLI + * @param argc + * @param argv + * @return return value of `prefixes_write` + */ +int mkprefix_interface(int argc, char **argv) { + char *command = argv[0]; + char *outfile = argv[1]; + char *tree = argv[2]; + + size_t prefix_start = 3; + size_t prefixes = 0; + for (size_t i = prefix_start; i < (size_t) argc; i++) { + prefixes = i; + } + + // Check arguments + if (!outfile) { + fprintf(stderr, "error: missing output file name\n"); + mkprefix_interface_usage(); + return -1; + } + if (!tree) { + fprintf(stderr, "error: missing directory path\n"); + mkprefix_interface_usage(); + return -1; + } + if (!prefixes) { + fprintf(stderr, "error: missing prefix string(s)\n"); + mkprefix_interface_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 (size_t i = 0; (i + prefix_start) < (size_t) argc; i++) { + prefix[i] = argv[(i + prefix_start)]; + } + + if (SPM_GLOBAL.verbose) { + printf("Generating prefix manifest: %s\n", outfile); + } + + int result = 0; + if (strcmp(command, "mkprefixbin") == 0) { + result = prefixes_write(outfile, PREFIX_WRITE_BIN, prefix, tree); + } else if (strcmp(command, "mkprefixtext") == 0) { + result = prefixes_write(outfile, PREFIX_WRITE_TEXT, prefix, tree); + } + return result; +} + +/** + * + */ +void mkmanifest_interface_usage(void) { + printf("usage: mkmanifest [package_dir] [output_dir]\n"); +} + +/** + * Generate a named package manifest + * @param argc + * @param argv + * @return value of `manifest_write` + */ +int mkmanifest_interface(int argc, char **argv) { + Manifest *manifest = NULL; + int result = 0; + char *pkgdir = NULL; + + if (argc < 2) { + mkmanifest_interface_usage(); + return -1; + } + + if ((pkgdir = expandpath(argv[1])) == NULL) { + fprintf(stderr, "bad path\n"); + return -2; + } + + if (exists(pkgdir) != 0) { + fprintf(stderr, "'%s': does not exist\n", pkgdir); + return -3; + } + + manifest = manifest_from(pkgdir); + if (manifest == NULL) { + fprintf(stderr, "no packages\n"); + return -4; + } + + result = manifest_write(manifest, pkgdir); + if (result != 0) { + fprintf(stderr, "an error occurred while writing manifest data\n"); + manifest_free(manifest); + return -5; + } + + free(pkgdir); + manifest_free(manifest); + return result; +} + +/** + * + */ +void mkruntime_interface_usage(void) { + printf("usage: mkruntime {root_dir}\n"); +} + +/** + * + * @param argc + * @param argv + * @return + */ +int mkruntime_interface(int argc, char **argv) { + if (argc < 2) { + mkruntime_interface_usage(); + return -1; + } + + RuntimeEnv *rt = runtime_copy(__environ); + if (rt == NULL) { + return -1; + } + + char *root = argv[1]; + SPM_Hierarchy *fs = spm_hierarchy_init(root); + char *spm_pkgconfigdir = join((char *[]) {fs->libdir, "pkgconfig", NULL}, DIRSEPS); + + runtime_set(rt, "SPM_BIN", fs->bindir); + runtime_set(rt, "SPM_INCLUDE", fs->includedir); + runtime_set(rt, "SPM_LIB", fs->libdir); + runtime_set(rt, "SPM_LIB64", "${SPM_LIB}64"); + runtime_set(rt, "SPM_DATA", fs->datadir); + runtime_set(rt, "SPM_MAN", fs->mandir); + runtime_set(rt, "SPM_LOCALSTATE", fs->localstatedir); + runtime_set(rt, "SPM_PKGCONFIG", spm_pkgconfigdir); + runtime_set(rt, "SPM_PKGCONFIG", "${SPM_PKGCONFIG}:${SPM_LIB64}/pkgconfig:${SPM_DATA}/pkgconfig"); + runtime_set(rt, "SPM_META_DEPENDS", SPM_META_DEPENDS); + runtime_set(rt, "SPM_META_PREFIX_BIN", SPM_META_PREFIX_BIN); + runtime_set(rt, "SPM_META_PREFIX_TEXT", SPM_META_PREFIX_TEXT); + runtime_set(rt, "SPM_META_DESCRIPTOR", SPM_META_DESCRIPTOR); + runtime_set(rt, "SPM_META_FILELIST", SPM_META_FILELIST); + runtime_set(rt, "SPM_META_PREFIX_PLACEHOLDER", SPM_META_PREFIX_PLACEHOLDER); + + runtime_set(rt, "PATH", "$SPM_BIN:$PATH"); + runtime_set(rt, "MANPATH", "$SPM_MAN:$MANPATH"); + runtime_set(rt, "PKG_CONFIG_PATH", "$SPM_PKGCONFIG:$PKG_CONFIG_PATH"); + runtime_set(rt, "ACLOCAL_PATH", "${SPM_DATA}/aclocal"); + + char *spm_ccpath = join((char *[]) {fs->bindir, "gcc"}, DIRSEPS); + if (exists(spm_ccpath) == 0) { + runtime_set(rt, "CC", "$SPM_BIN/gcc"); + } + + runtime_set(rt, "CFLAGS", "-I$SPM_INCLUDE $CFLAGS"); + runtime_set(rt, "LDFLAGS", "-Wl,-rpath=$SPM_LIB:$SPM_LIB64 -L$SPM_LIB -L$SPM_LIB64 $LDFLAGS"); + runtime_export(rt, NULL); + runtime_free(rt); + + free(spm_pkgconfigdir); + free(spm_ccpath); + spm_hierarchy_free(fs); + return 0; +} + +/** + * + */ +void mirror_clone_interface_usage(void) { + printf("usage: mirror_clone {url} {output_dir}\n"); +} + +/** + * Mirror packages referenced by a remote manifest + * @param argc + * @param argv + * @return value of `manifest_write` + */ +int mirror_clone_interface(int argc, char **argv) { + if (argc < 3) { + mirror_clone_interface_usage(); + return -1; + } + char *url = argv[1]; + char *path = argv[2]; + + Manifest *manifest = manifest_read(url); + if (manifest == NULL) { + return -2; + } + + mirror_clone(manifest, path); + manifest_free(manifest); + return 0; +} +/** + * + */ +void rpath_set_interface_usage(void) { + printf("usage: rpath_set {file} {rpath}\n"); +} + +/** + * Set a RPATH from the CLI + * @param argc + * @param argv + * @return return value of `rpath_set` + */ +int rpath_set_interface(int argc, char **argv) { + if (argc < 3) { + rpath_set_interface_usage(); + return -1; + } + char *filename = argv[1]; + char *rpath = argv[2]; + int result = rpath_set(filename, rpath); + if (result < 0) { + fprintf(SYSERROR); + } + return result; +} + +/** + * + */ +void rpath_autoset_interface_usage(void) { + printf("usage: rpath_autoset {file} {topdir}\n"); +} + +/** + * Set a RPATH automatically from the CLI + * @param argc + * @param argv + * @return return value of `rpath_autoset` + */ +int rpath_autoset_interface(int argc, char **argv) { + if (argc < 3) { + rpath_autoset_interface_usage(); + return -1; + } + char *filename = argv[1]; + const char *topdir = argv[2]; + + if (exists(filename) != 0) { + perror(filename); + return -1; + } + + if (exists(topdir) != 0) { + perror(topdir); + return -1; + } + + FSTree *libs = rpath_libraries_available(topdir); + int result = rpath_autoset(filename, libs); + + if (result < 0) { + fprintf(SYSERROR); + } + + return result; +} + +/** + * Dump the default package extension for SPM archives to `stdout` + * @return + */ +int get_package_ext_interface(void) { + puts(SPM_PACKAGE_EXTENSION); + return 0; +} + +/** + * Dump the system arch/platform (i.e. Linux/x86_64) + * @return + */ +int get_sys_target_interface(void) { + puts(SPM_GLOBAL.repo_target); + return 0; +} +/** + * Execute builtin runtime check. + * + * On failure this function will EXIT the program with a non-zero value + * + * @return + */ +int check_runtime_environment_interface(void) { + check_runtime_environment(); + return 0; +} + +/** + * Show a listing of valid internal commands + */ +void internal_command_list(void) { + printf("possible commands:\n"); + for (size_t i = 0; internal_commands[i] != NULL; i += 2) { + printf(" %-20s - %-20s\n", internal_commands[i], internal_commands[i + 1]); + } +} + +/** + * Execute an internal command + * @param argc + * @param argv + * @return success=0, failure=1, error=-1 + */ +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; + } + + // Strip the first argument (this level) before passing it along to the interface + int arg_count = argc - 1; + char **arg_array = &argv[1]; + + if (strcmp(command, "mkprefixbin") == 0 || strcmp(command, "mkprefixtext") == 0) { + return mkprefix_interface(arg_count, arg_array); + } + else if (strcmp(command, "mkmanifest") == 0) { + return mkmanifest_interface(arg_count, arg_array); + } + else if (strcmp(command, "mkruntime") == 0) { + return mkruntime_interface(arg_count, arg_array); + } + else if (strcmp(command, "mirror_clone") == 0) { + return mirror_clone_interface(arg_count, arg_array); + } + else if (strcmp(command, "rpath_set") == 0) { + return rpath_set_interface(arg_count, arg_array); + } + else if (strcmp(command, "rpath_autoset") == 0) { + return rpath_autoset_interface(arg_count, arg_array); + } + else if (strcmp(command, "get_package_ext") == 0) { + return get_package_ext_interface(); + } + else if (strcmp(command, "get_sys_target") == 0) { + return get_sys_target_interface(); + } + else if (strcmp(command, "check_rt_env") == 0) { + return check_runtime_environment_interface(); + } + return 0; +} |