aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/install.c204
1 files changed, 167 insertions, 37 deletions
diff --git a/src/install.c b/src/install.c
index cf22d23..3603af5 100644
--- a/src/install.c
+++ b/src/install.c
@@ -46,10 +46,11 @@ void install_show_package(ManifestPackage *package) {
* The destination is created if it does not exist.
* @param _destroot directory to install package
* @param _package name of archive to install (not a path)
- * @return success=0, error=-1 (general), -2 (unable to create `destroot`)
+ * @return success=0, exists=1, error=-1 (general), -2 (unable to create `destroot`)
*/
-int install(const char *destroot, const char *_package) {
+int install(const char *destroot, const char *tmpdir, const char *_package) {
char *package = strdup(_package);
+
if (!package) {
fprintf(SYSERROR);
return -1;
@@ -61,66 +62,195 @@ int install(const char *destroot, const char *_package) {
}
if (mkdirs(destroot, 0755) != 0) {
fprintf(SYSERROR);
+ free(package);
return -2;
}
}
- char source[PATH_MAX];
- char template[PATH_MAX];
+ if (SPM_GLOBAL.verbose) {
+ printf("Extracting archive: %s\n", package);
+ }
- // circumvent -Wformat-truncation
- char *suffix = (char *) calloc(PATH_MAX, sizeof(char));
- if (!suffix) {
- perror("suffix");
- fprintf(SYSERROR);
+ if (tar_extract_archive(package, tmpdir) != 0) {
+ fprintf(stderr, "%s: %s\n", package, strerror(errno));
+ free(package);
return -1;
}
- strcpy(suffix, "spm_destroot_XXXXXX");
- snprintf(template, PATH_MAX, "%s%c%s", TMP_DIR, DIRSEP, suffix);
- free(suffix);
- // Create a new temporary directory and extract the requested package into it
- char *tmpdir = mkdtemp(template);
- if (exists(tmpdir) != 0) {
- fprintf(stderr, "Failed to create temporary storage directory\n");
+ free(package);
+ return 0;
+}
+
+int install_package_record(char *from_root, char *package_name) {
+ RuntimeEnv *rt = runtime_copy(__environ);
+ char *records_topdir = normpath(runtime_expand_var(rt, "$SPM_LOCALSTATE/db/records"));
+ char *records_pkgdir = join((char *[]) {records_topdir, package_name, NULL}, DIRSEPS);
+ char *descriptor = join((char *[]) {from_root, SPM_META_DESCRIPTOR, NULL}, DIRSEPS);
+ char *filelist = join((char *[]) {from_root, SPM_META_FILELIST, NULL}, DIRSEPS);
+
+ if (exists(records_pkgdir) != 0) {
+ if (mkdirs(records_pkgdir, 0755) != 0) {
+ return -1;
+ }
+ }
+
+ if (exists(descriptor) != 0) {
+ fprintf(stderr, "Missing: %s\n", descriptor);
+ return 1;
+ }
+
+ if (exists(filelist) != 0) {
+ fprintf(stderr, "Missing: %s\n", filelist);
+ return 2;
+ }
+
+ if (rsync(NULL, descriptor, records_pkgdir) != 0) {
+ fprintf(stderr, "Failed to copy '%s' to '%s'\n", descriptor, records_pkgdir);
+ return 3;
+ }
+
+ if (rsync(NULL, filelist, records_pkgdir) != 0) {
+ fprintf(stderr, "Failed to copy '%s' to '%s'\n", filelist, records_pkgdir);
+ return 4;
+ }
+
+ free(records_topdir);
+ free(records_pkgdir);
+ free(descriptor);
+ free(filelist);
+ runtime_free(rt);
+ return 0;
+}
+
+int is_installed(const char *rootdir, char *package_name) {
+ RuntimeEnv *rt = runtime_copy(__environ);
+ char *records_topdir = normpath(runtime_expand_var(rt, "$SPM_LOCALSTATE/db/records"));
+ char *records_pkgdir = join((char *[]) {records_topdir, package_name, NULL}, DIRSEPS);
+ int result = 1; // 1 == exists
+
+ if (exists(records_pkgdir) != 0) {
+ // does not exist
+ result = 0;
+ }
+
+ free(records_topdir);
+ free(records_pkgdir);
+ // exists
+ return result;
+}
+
+/**
+ * Perform a full package installation
+ * @param mf
+ * @param rootdir
+ * @param packages
+ * @return 0=success, -1=failed to create storage, -2=denied by user
+ */
+int do_install(ManifestList *mf, const char *rootdir, StrList *packages) {
+ size_t num_requirements = 0;
+ ManifestPackage **requirements = NULL;
+ char source[PATH_MAX];
+ char *tmpdir = spm_mkdtemp("spm_destroot");
+
+ if (tmpdir == NULL) {
+ perror("Could not create temporary destination root");
fprintf(SYSERROR);
- exit(errno);
+ return -1;
}
if (SPM_GLOBAL.verbose) {
- printf("Extracting archive: %s\n", package);
+ printf("Installation root: %s\n", rootdir);
}
- if (tar_extract_archive(package, tmpdir) != 0) {
- fprintf(stderr, "%s: %s\n", package, strerror(errno));
- return -1;
+
+ // Produce a dependency tree from requested package(s)
+ for (size_t i = 0; i < strlist_count(packages); i++) {
+ requirements = resolve_dependencies(mf, strlist_item(packages, i));
+ if (requirements != NULL) {
+ for (size_t c = 0; requirements[c] != NULL; c++) {
+ num_requirements++;
+ }
+ }
}
- // Relocate temporary directory
- relocate_root(destroot, tmpdir);
+ // Append requested package(s) to requirements array
+ for (size_t i = 0; i < strlist_count(packages); i++) {
+ char *name = strlist_item(packages, i);
+ ManifestPackage *package = manifestlist_search(mf, name);
+ requirements[i + num_requirements] = package;
+ }
- // Append a trailing slash to tmpdir to direct rsync to copy files, not the directory, into destroot
- sprintf(source, "%s%c", tmpdir, DIRSEP);
+ // Install packages
+ printf("Requested package(s):\n");
+ for (size_t i = 0; requirements !=NULL && requirements[i] != NULL; i++) {
+ install_show_package(requirements[i]);
+ }
- // Remove metadata files before copying
- if (SPM_GLOBAL.verbose) {
- printf("Removing metadata\n");
+ if (SPM_GLOBAL.prompt_user) {
+ int user_choice;
+ int status_choice;
+ printf("\nProceed with installation? [Y/n] ");
+ while ((user_choice = getchar())) {
+ status_choice = spm_user_yesno(user_choice, 1);
+ if (status_choice == 0) { // No
+ exit(-2);
+ } else if (status_choice == 1) { // Yes
+ break;
+ } else { // Only triggers when spm_user_yesno's second argument is zero
+ puts("Please answer 'y' or 'n'...");
+ }
+ }
+ puts("");
}
- metadata_remove(source);
- // Copy temporary directory to destination
- if (SPM_GLOBAL.verbose) {
- printf("Installing tree: '%s' => '%s'\n", source, destroot);
+ printf("Installing package(s):\n");
+ size_t num_installed = 0;
+ for (size_t i = 0; requirements != NULL && requirements[i] != NULL; i++) {
+ char *package_path = join((char *[]) {requirements[i]->origin, SPM_GLOBAL.repo_target, requirements[i]->archive, NULL}, DIRSEPS);
+
+ if (is_installed(rootdir, requirements[i]->name)) {
+ printf(" -> %s is already installed\n", requirements[i]->name);
+ free(package_path);
+ continue;
+ }
+
+ install_show_package(requirements[i]);
+ install(rootdir, tmpdir, package_path);
+ install_package_record(tmpdir, requirements[i]->name);
+ num_installed++;
+ free(package_path);
+ }
+
+ // free requirements array
+ for (size_t i = 0; requirements != NULL && requirements[i] != NULL; i++) {
+ manifest_package_free(requirements[i]);
}
- if (rsync(NULL, source, destroot) != 0) {
- exit(1);
+ if (num_installed != 0) {
+ // Relocate installation root
+ relocate_root(rootdir, tmpdir);
+
+ // 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
+ if (SPM_GLOBAL.verbose) {
+ printf("Removing metadata\n");
+ }
+ metadata_remove(source);
+
+ // Copy temporary directory to destination
+ if (SPM_GLOBAL.verbose) {
+ printf("Installing tree: '%s' => '%s'\n", source, rootdir);
+ }
+
+ if (rsync(NULL, source, rootdir) != 0) {
+ exit(1);
+ }
}
if (SPM_GLOBAL.verbose) {
printf("Removing temporary storage: '%s'\n", tmpdir);
}
rmdirs(tmpdir);
-
- free(package);
return 0;
-}
+} \ No newline at end of file