/* download_manifests() * Description: To search Clear bundles for a particular entry, a complete set of * manifests must be downloaded. This function does so, asynchronously, using * the curl_multi interface */ int download_manifests(struct manifest **MoM) { struct list *list; struct file *file; char *tarfile, *untard_file, *url; struct manifest *subMan = NULL; int current_version; int ret = 0; double size; current_version = read_version_from_subvol_file(path_prefix); swupd_curl_set_current_version(current_version); ret = load_manifests(current_version, current_version, "MoM", NULL, MoM); if (ret != 0) { printf("Cannot load official manifest MoM for version %i\n", current_version); return ret; } subscription_versions_from_MoM(*MoM, 0); list = (*MoM)->manifests; size = query_total_download_size(list); if (size == -1) { printf("Downloading manifests. Expect a delay, up to 100MB may be downloaded\n"); } else if (size > 0) { printf("Downloading Clear Linux manifests\n"); printf(" %.2f MB total...\n\n", size); } while (list) { file = list->data; list = list->next; create_and_append_subscription(file->filename); string_or_die(&untard_file, "%s/%i/Manifest.%s", STATE_DIR, file->last_change, file->filename); string_or_die(&tarfile, "%s/%i/Manifest.%s.tar", STATE_DIR, file->last_change, file->filename); if (access(untard_file, F_OK) == -1) { /* Do download */ printf(" '%s' manifest...\n", file->filename); ret = load_manifests(current_version, file->last_change, file->filename, NULL, &subMan); if (ret != 0) { printf("Cannot load official manifest MoM for version %i\n", current_version); } free_manifest(subMan); } if (access(untard_file, F_OK) == -1) { string_or_die(&url, "%s/%i/Manifest.%s.tar", preferred_content_url, current_version, file->filename); printf("Error: Failure reading from %s\n", url); free(url); } unlink(tarfile); free(untard_file); free(tarfile); } return ret; }
/* tristate return, -1 for errors, 1 for no errors but no new subscriptions, 0 for no errors and new subscriptions */ int add_subscriptions(struct list *bundles, int current_version, struct manifest *mom) { bool new_bundles = false; char *bundle; int ret; int retries = 0; int timeout = 10; struct file *file; struct list *iter; struct manifest *manifest; srand(time(NULL)); iter = list_head(bundles); while (iter) { bundle = iter->data; iter = iter->next; file = search_bundle_in_manifest(mom, bundle); if (!file) { printf("%s bundle name is invalid, skipping it...\n", bundle); continue; } retry_manifest_download: manifest = load_manifest(current_version, file->last_change, file, mom); if (!manifest) { if (retries < MAX_TRIES) { increment_retries(&retries, &timeout); goto retry_manifest_download; } printf("Unable to download manifest %s version %d, exiting now\n", bundle, file->last_change); ret = -1; goto out; } if (!manifest) { printf("Unable to load manifest %s version %d, exiting now\n", bundle, file->last_change); ret = -1; goto out; } if (manifest->includes) { ret = add_subscriptions(manifest->includes, current_version, mom); if (ret == -1) { free_manifest(manifest); goto out; } else if (ret == 0) { new_bundles = true; } } free_manifest(manifest); if (is_tracked_bundle(bundle)) { continue; } if (component_subscribed(bundle)) { continue; } create_and_append_subscription(bundle); new_bundles = true; } if (new_bundles) { ret = 0; } else { ret = 1; } out: return ret; }
/* Bundle install one ore more bundles passed in bundles * param as a null terminated array of strings */ int install_bundles(char **bundles) { int lock_fd; int ret = 0; int current_version; struct manifest *mom; struct list *iter; struct sub *sub; struct file *file; /* step 1: initialize swupd and get current version from OS */ if (!init_globals()) { return EINIT_GLOBALS; } ret = swupd_init(&lock_fd); if (ret != 0) { printf("Failed updater initialization, exiting now.\n"); return ret; } current_version = read_version_from_subvol_file(path_prefix); swupd_curl_set_current_version(current_version); /* first of all, make sure STATE_DIR is there, recreate if necessary*/ ret = create_required_dirs(); if (ret != 0) { printf("State directory %s cannot be recreated, aborting installation\n", STATE_DIR); goto clean_and_exit; } ret = load_manifests(current_version, current_version, "MoM", NULL, &mom); if (ret != 0) { printf("Cannot load official manifest MoM for version %i\n", current_version); ret = EMOM_NOTFOUND; goto clean_and_exit; } /* step 2: check bundle args are valid if so populate subs struct */ int i; for (i = 0; *bundles; ++bundles) { if (is_tracked_bundle(*bundles)) { printf("%s bundle already installed, skipping it\n", *bundles); continue; } if (!manifest_has_component(mom, *bundles)) { printf("%s bundle name is invalid, skipping it...\n", *bundles); continue; } if (component_subscribed(*bundles)) { continue; } create_and_append_subscription(*bundles); i++; printf("Added bundle %s for installation\n", *bundles); } if (i == 0) { printf("There are no pending bundles to install, exiting now\n"); ret = EBUNDLE_INSTALL; goto clean_manifest_and_exit; } subscription_versions_from_MoM(mom, 0); recurse_manifest(mom, NULL); consolidate_submanifests(mom); /* step 3: download neccessary packs */ ret = rm_staging_dir_contents("download"); printf("Downloading required packs...\n"); ret = download_subscribed_packs(0, current_version, true); if (ret != 0) { printf("pack downloads failed, cannot proceed with the installation, exiting.\n"); goto clean_subs_and_exit; } /* step 4: Install all bundle(s) files into the fs */ printf("Installing bundle(s) files...\n"); iter = list_head(mom->files); while (iter) { file = iter->data; iter = iter->next; if (file->is_deleted || file->do_not_update || ignore(file)) { continue; } ret = do_staging(file); if (ret == 0) { rename_staged_file_to_final(file); } } sync(); /* step 5: create bundle(s) subscription entries to track them * * Strictly speaking each manifest has an entry to write its own bundle filename * and thus tracking automagically, here just making sure. */ iter = list_head(subs); while (iter) { sub = iter->data; iter = iter->next; printf("Tracking %s bundle on the system\n", sub->component); ret = track_bundle_in_system(sub->component); if (ret != 0) { printf("Cannot track %s bundle on the system\n", sub->component); } } /* Run any scripts that are needed to complete update */ run_scripts(); ret = 0; printf("Bundle(s) installation done.\n"); clean_subs_and_exit: free_subscriptions(); clean_manifest_and_exit: free_manifest(mom); clean_and_exit: swupd_curl_cleanup(); v_lockfile(lock_fd); dump_file_descriptor_leaks(); free_globals(); return ret; }
/* download_manifests() * Description: To search Clear bundles for a particular entry, a complete set of * manifests must be downloaded. This function does so, asynchronously, using * the curl_multi interface */ static int download_manifests(struct manifest **MoM, struct list **subs) { struct list *list = NULL; struct file *file = NULL; char *tarfile, *untard_file, *url = NULL; struct manifest *subMan = NULL; int current_version; int ret = 0; double size; bool did_download = false; current_version = get_current_version(path_prefix); if (current_version < 0) { fprintf(stderr, "Error: Unable to determine current OS version\n"); return ECURRENT_VERSION; } *MoM = load_mom(current_version, false, false, NULL); if (!(*MoM)) { fprintf(stderr, "Cannot load official manifest MoM for version %i\n", current_version); return EMOM_LOAD; } list = (*MoM)->manifests; size = query_total_download_size(list); if (size == -1) { fprintf(stderr, "Downloading manifests. Expect a delay, up to 100MB may be downloaded\n"); } else if (size > 0) { fprintf(stderr, "Downloading Clear Linux manifests\n"); fprintf(stderr, " %.2f MB total...\n\n", size); } while (list) { file = list->data; list = list->next; create_and_append_subscription(subs, file->filename); string_or_die(&untard_file, "%s/%i/Manifest.%s", state_dir, file->last_change, file->filename); string_or_die(&tarfile, "%s/%i/Manifest.%s.tar", state_dir, file->last_change, file->filename); if (access(untard_file, F_OK) == -1) { /* Do download */ subMan = load_manifest(file->last_change, file, *MoM, false); if (!subMan) { fprintf(stderr, "Cannot load official manifest MoM for version %i\n", current_version); } else { did_download = true; } free_manifest(subMan); } if (access(untard_file, F_OK) == -1) { string_or_die(&url, "%s/%i/Manifest.%s.tar", content_url, current_version, file->filename); fprintf(stderr, "Error: Failure reading from %s\n", url); free_string(&url); } unlink(tarfile); free_string(&untard_file); free_string(&tarfile); } if (did_download) { fprintf(stderr, "Completed manifests download.\n\n"); } return ret; }