Пример #1
0
/* bundle_name: this is the name for the bundle we want to be loaded
* version: this is the MoM version from which we pull last changed for bundle manifest
* submanifest: where bundle manifest is going to be loaded
*
* Basically we read MoM version then get the submanifest only for our bundle (component)
* put it into submanifest pointer, then dispose MoM data.
*/
static int load_bundle_manifest(const char *bundle_name, int version, struct manifest **submanifest)
{
	struct list *sub_list = NULL;
	struct manifest *mom = NULL;
	int ret = 0;

	*submanifest = NULL;

	swupd_curl_set_current_version(version);
	mom = load_mom(version);
	if (!mom) {
		ret = EMOM_NOTFOUND;
		goto out;
	}

	sub_list = recurse_manifest(mom, bundle_name);
	if (!sub_list) {
		ret = ERECURSE_MANIFEST;
		goto free_out;
	}

	*submanifest = sub_list->data;
	sub_list->data = NULL;
	ret = 0;

free_out:
	free_manifest(mom);
out:
	return ret;
}
Пример #2
0
/* bundle_name: this is the name for the bundle we want to be loaded
* version: this is the MoM version from which we pull last changed for bundle manifest
* submanifest: where bundle manifest is going to be loaded
*
* Basically we read MoM version then get the submanifest only for our bundle (component)
* put it into submanifest pointer, then dispose MoM data.
*/
static int load_bundle_manifest(const char *bundle_name, int version, struct manifest **submanifest)
{
	struct list *sub_list = NULL;
	struct manifest *mom = NULL;
	int ret = 0;

	*submanifest = NULL;

	swupd_curl_set_current_version(version);
	ret = load_manifests(version, version, "MoM", NULL, &mom);
	if (ret != 0) {
		ret = EMOM_NOTFOUND;
		goto out;
	}

	ret = recurse_manifest(mom, bundle_name);
	if (ret != 0) {
		ret = ERECURSE_MANIFEST;
		goto free_out;
	}

	sub_list = list_head(mom->submanifests);
	if (sub_list != NULL) {
		*submanifest = sub_list->data;
		sub_list->data = NULL;
		ret = 0;
	}

free_out:
	free_manifest(mom);
out:
	return ret;
}
Пример #3
0
int check_versions(int *current_version,
		   int *server_version,
		   char *path_prefix)
{

	read_versions(current_version, server_version, path_prefix);

	if (*current_version < 0) {
		fprintf(stderr, "Error: Unable to determine current OS version\n");
		return -1;
	}
	if (*current_version == 0) {
		fprintf(stderr, "Update from version 0 not supported yet.\n");
		return -1;
	}
	if (SWUPD_VERSION_IS_DEVEL(*current_version) || SWUPD_VERSION_IS_RESVD(*current_version)) {
		fprintf(stderr, "Update of dev build not supported %d\n", *current_version);
		return -1;
	}
	swupd_curl_set_current_version(*current_version);

	/* set preferred version and content server urls */
	if (*current_version < 0) {
		have_network = false;
		return -1;
	}

	have_network = true;

	//TODO allow policy layer to send us to intermediate version?

	swupd_curl_set_requested_version(*server_version);

	return 0;
}
Пример #4
0
/*
* list_installable_bundles()
* Parse the full manifest for the current version of the OS and print
*   all available bundles.
*/
int list_installable_bundles()
{
	struct list *list;
	struct file *file;
	struct manifest *MoM = NULL;
	int current_version;
	int lock_fd;
	int ret;

	if (!init_globals()) {
		return EINIT_GLOBALS;
	}

	current_version = read_version_from_subvol_file(path_prefix);

	if (swupd_init(&lock_fd) != 0) {
		printf("Error: Failed updater initialization. Exiting now\n");
		return ECURL_INIT;
	}

	ret = create_required_dirs();
	if (ret != 0) {
		printf("State directory %s cannot be recreated, aborting removal\n", STATE_DIR);
		v_lockfile(lock_fd);
		return EXIT_FAILURE;
	}
	get_mounted_directories();

	if (!check_network()) {
		printf("Error: Network issue, unable to download manifest\n");
		v_lockfile(lock_fd);
		return EXIT_FAILURE;
	}

	swupd_curl_set_current_version(current_version);

	ret = load_manifests(current_version, current_version, "MoM", NULL, &MoM);
	if (ret != 0) {
		v_lockfile(lock_fd);
		return ret;
	}

	list = MoM->manifests;
	while (list) {
		file = list->data;
		list = list->next;
		printf("%s\n", file->filename);
	}

	free_manifest(MoM);
	v_lockfile(lock_fd);
	return 0;
}
Пример #5
0
/*
* list_installable_bundles()
* Parse the full manifest for the current version of the OS and print
*   all available bundles.
*/
int list_installable_bundles()
{
	struct list *list;
	struct file *file;
	struct manifest *MoM = NULL;
	int current_version;
	int lock_fd;
	int ret;

	ret = swupd_init(&lock_fd);
	if (ret != 0) {
		printf("Error: Failed updater initialization. Exiting now\n");
		return ret;
	}

	if (!check_network()) {
		printf("Error: Network issue, unable to download manifest\n");
		v_lockfile(lock_fd);
		return EXIT_FAILURE;
	}

	current_version = get_current_version(path_prefix);
	if (current_version < 0) {
		printf("Error: Unable to determine current OS version\n");
		v_lockfile(lock_fd);
		return ECURRENT_VERSION;
	}

	swupd_curl_set_current_version(current_version);

	MoM = load_mom(current_version);
	if (!MoM) {
		v_lockfile(lock_fd);
		return ret;
	}

	list = MoM->manifests;
	while (list) {
		file = list->data;
		list = list->next;
		printf("%s\n", file->filename);
	}

	free_manifest(MoM);
	v_lockfile(lock_fd);
	return 0;
}
Пример #6
0
/* Bundle install one ore more bundles passed in bundles
 * param as a null terminated array of strings
 */
int install_bundles_frontend(char **bundles)
{
	int lock_fd;
	int ret = 0;
	int current_version;
	struct list *bundles_list = NULL;
	struct manifest *mom;

	/* initialize swupd and get current version from OS */
	ret = swupd_init(&lock_fd);
	if (ret != 0) {
		printf("Failed updater initialization, exiting now.\n");
		return ret;
	}

	current_version = get_current_version(path_prefix);
	if (current_version < 0) {
		printf("Error: Unable to determine current OS version\n");
		ret = ECURRENT_VERSION;
		goto clean_and_exit;
	}

	swupd_curl_set_current_version(current_version);

	mom = load_mom(current_version);
	if (!mom) {
		printf("Cannot load official manifest MoM for version %i\n", current_version);
		ret = EMOM_NOTFOUND;
		goto clean_and_exit;
	}

	for (; *bundles; ++bundles) {
		bundles_list = list_prepend_data(bundles_list, *bundles);
	}

	ret = install_bundles(bundles_list, current_version, mom);
	list_free_list(bundles_list);

	free_manifest(mom);
clean_and_exit:
	swupd_deinit(lock_fd);

	return ret;
}
Пример #7
0
/*
* list_installable_bundles()
* Parse the full manifest for the current version of the OS and print
*   all available bundles.
*/
int list_installable_bundles()
{
	struct list *list;
	struct file *file;
	struct manifest *MoM = NULL;
	int current_version;
	int lock_fd;
	int ret;

	ret = swupd_init(&lock_fd);
	if (ret != 0) {
		printf("Error: Failed updater initialization. Exiting now\n");
		return ret;
	}

	if (!check_network()) {
		printf("Error: Network issue, unable to download manifest\n");
		v_lockfile(lock_fd);
		return EXIT_FAILURE;
	}

	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) {
		v_lockfile(lock_fd);
		return ret;
	}

	list = MoM->manifests;
	while (list) {
		file = list->data;
		list = list->next;
		printf("%s\n", file->filename);
	}

	free_manifest(MoM);
	v_lockfile(lock_fd);
	return 0;
}
Пример #8
0
/* Bundle install one ore more bundles passed in bundles
 * param as a null terminated array of strings
 */
int install_bundles_frontend(char **bundles)
{
	int lock_fd;
	int ret = 0;
	int current_version;
	struct list *bundles_list = NULL;
	struct manifest *mom;

	/* initialize swupd and get current version from OS */
	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);

	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;
	}

	for (; *bundles; ++bundles) {
		bundles_list = list_prepend_data(bundles_list, *bundles);
	}

	ret = install_bundles(bundles_list, current_version, mom);
	list_free_list(bundles_list);

	free_manifest(mom);
clean_and_exit:
	swupd_curl_cleanup();
	v_lockfile(lock_fd);
	dump_file_descriptor_leaks();
	free_globals();

	return ret;
}
Пример #9
0
/* 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;
}
Пример #10
0
/* 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;
}
Пример #11
0
/*  This function is a fresh new implementation for a bundle
 *  remove without being tied to verify loop, this means
 *  improved speed and space as well as more roubustness and
 *  flexibility. What it does is basically:
 *
 *  1) Read MoM and load all submanifests except the one to be
 *  	removed and then consolidate them.
 *  2) Load the removed bundle submanifest.
 *  3) Order the file list by filename
 *  4) Deduplicate removed submanifest file list that happens
 *  	to be on the MoM (minus bundle to be removed).
 *  5) iterate over to be removed bundle submanifest file list
 *  	performing a unlink(2) for each filename.
 *  6) Done.
 */
int remove_bundle(const char *bundle_name)
{
	int lock_fd;
	int ret = 0;
	int current_version = CURRENT_OS_VERSION;
	struct manifest *current_mom, *bundle_manifest;

	/* Initially we don't support format nor path_prefix
	 * for bundle_rm but eventually that will be added, then
	 * set_format_string() and init_globals() must be pulled out
	 * to the caller to properly initialize in case those opts
	 * passed to the command.
	 */
	set_format_string(NULL);
	if (!init_globals()) {
		return EINIT_GLOBALS;
	}

	ret = swupd_init(&lock_fd);
	if (ret != 0) {
		printf("Failed updater initialization, exiting now.\n");
		return ret;
	}

	/* os-core bundle not allowed to be removed...
	 * although this is going to be caught later because of all files
	 * being marked as 'duplicated' and note removing anything
	 * anyways, better catch here and return success, no extra work to be done.
	 */
	if (strcmp(bundle_name, "os-core") == 0) {
		ret = EBUNDLE_NOT_TRACKED;
		goto out_free_curl;
	}

	if (!is_tracked_bundle(bundle_name)) {
		ret = EBUNDLE_NOT_TRACKED;
		goto out_free_curl;
	}

	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 removal\n", STATE_DIR);
		goto out_free_curl;
	}


	ret = load_manifests(current_version, current_version, "MoM", NULL, &current_mom);
	if (ret != 0) {
		goto out_free_curl;
	}

	/* load all tracked bundles into memory */
	read_subscriptions_alt();
	/* now popout the one to be removed */
	ret =  unload_tracked_bundle(bundle_name);
	if (ret != 0) {
		goto out_free_mom;
	}

	subscription_versions_from_MoM(current_mom, 0);
	/* load all submanifest minus the one to be removed */
	recurse_manifest(current_mom, NULL);
	consolidate_submanifests(current_mom);

	/* Now that we have the consolidated list of all files, load bundle to be removed submanifest*/
	ret = load_bundle_manifest(bundle_name, current_version, &bundle_manifest);
	if (ret != 0) {
		goto out_free_mom;
	}

	/* deduplication needs file list sorted by filename, do so */
	bundle_manifest->files = list_sort(bundle_manifest->files, file_sort_filename);
	deduplicate_files_from_manifest(&bundle_manifest, current_mom);

	printf("Deleting bundle files...\n");
	remove_files_in_manifest_from_fs(bundle_manifest);

	printf("Untracking bundle from system...\n");
	rm_bundle_file(bundle_name);

	printf("Success: Bundle removed\n");

	free_manifest(bundle_manifest);
out_free_mom:
	free_manifest(current_mom);
out_free_curl:

	if (ret) {
		printf("Error: Bundle remove failed\n");
	}

	swupd_curl_cleanup();
	v_lockfile(lock_fd);
	dump_file_descriptor_leaks();

	return ret;
}
Пример #12
0
/*  This function is a fresh new implementation for a bundle
 *  remove without being tied to verify loop, this means
 *  improved speed and space as well as more roubustness and
 *  flexibility. What it does is basically:
 *
 *  1) Read MoM and load all submanifests except the one to be
 *  	removed and then consolidate them.
 *  2) Load the removed bundle submanifest.
 *  3) Order the file list by filename
 *  4) Deduplicate removed submanifest file list that happens
 *  	to be on the MoM (minus bundle to be removed).
 *  5) iterate over to be removed bundle submanifest file list
 *  	performing a unlink(2) for each filename.
 *  6) Done.
 */
int remove_bundle(const char *bundle_name)
{
	int lock_fd;
	int ret = 0;
	int current_version = CURRENT_OS_VERSION;
	struct manifest *current_mom, *bundle_manifest = NULL;

	ret = swupd_init(&lock_fd);
	if (ret != 0) {
		printf("Failed updater initialization, exiting now.\n");
		return ret;
	}

	/* os-core bundle not allowed to be removed...
	 * although this is going to be caught later because of all files
	 * being marked as 'duplicated' and note removing anything
	 * anyways, better catch here and return success, no extra work to be done.
	 */
	if (strcmp(bundle_name, "os-core") == 0) {
		ret = EBUNDLE_NOT_TRACKED;
		goto out_free_curl;
	}

	if (!is_tracked_bundle(bundle_name)) {
		ret = EBUNDLE_NOT_TRACKED;
		goto out_free_curl;
	}

	current_version = get_current_version(path_prefix);
	if (current_version < 0) {
		printf("Error: Unable to determine current OS version\n");
		ret = ECURRENT_VERSION;
		goto out_free_curl;
	}

	swupd_curl_set_current_version(current_version);

	current_mom = load_mom(current_version);
	if (!current_mom) {
		printf("Unable to download/verify %d Manifest.MoM\n", current_version);
		ret = EMOM_NOTFOUND;
		goto out_free_curl;
	}

	if (!search_bundle_in_manifest(current_mom, bundle_name)) {
		printf("Bundle name is invalid, aborting removal\n");
		ret = EBUNDLE_REMOVE;
		goto out_free_mom;
	}

	/* load all tracked bundles into memory */
	read_subscriptions_alt();
	/* now popout the one to be removed */
	ret = unload_tracked_bundle(bundle_name);
	if (ret != 0) {
		goto out_free_mom;
	}

	subscription_versions_from_MoM(current_mom, 0);

	/* load all submanifest minus the one to be removed */
	current_mom->submanifests = recurse_manifest(current_mom, NULL);
	if (!current_mom->submanifests) {
		printf("Error: Cannot load MoM sub-manifests\n");
		ret = ERECURSE_MANIFEST;
		goto out_free_mom;
	}

	if (is_included(bundle_name, current_mom)) {
		printf("Error: bundle requested to be removed is required by other installed bundles\n");
		ret = EBUNDLE_REMOVE;
		goto out_free_mom;
	}

	current_mom->files = files_from_bundles(current_mom->submanifests);

	current_mom->files = consolidate_files(current_mom->files);

	/* Now that we have the consolidated list of all files, load bundle to be removed submanifest*/
	ret = load_bundle_manifest(bundle_name, current_version, &bundle_manifest);
	if (ret != 0 || !bundle_manifest) {
		printf("Error: Cannot load %s sub-manifest (ret = %d)\n", bundle_name, ret);
		goto out_free_mom;
	}

	/* deduplication needs file list sorted by filename, do so */
	bundle_manifest->files = list_sort(bundle_manifest->files, file_sort_filename);
	deduplicate_files_from_manifest(&bundle_manifest, current_mom);

	printf("Deleting bundle files...\n");
	remove_files_in_manifest_from_fs(bundle_manifest);

	printf("Untracking bundle from system...\n");
	rm_bundle_file(bundle_name);

	printf("Success: Bundle removed\n");

	free_manifest(bundle_manifest);
out_free_mom:
	free_manifest(current_mom);
out_free_curl:

	if (ret) {
		printf("Error: Bundle remove failed\n");
	}

	swupd_deinit(lock_fd);

	return ret;
}
Пример #13
0
/* 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 *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) {
		printf("Error: Unable to determine current OS version\n");
		return ECURRENT_VERSION;
	}

	swupd_curl_set_current_version(current_version);

	*MoM = load_mom(current_version);
	if (!(*MoM)) {
		printf("Cannot load official manifest MoM for version %i\n", current_version);
		return EMOM_NOTFOUND;
	}

	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);

			subMan = load_manifest(current_version, file->last_change, file, *MoM);
			if (!subMan) {
				printf("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);

			printf("Error: Failure reading from %s\n", url);
			free(url);
		}

		unlink(tarfile);
		free(untard_file);
		free(tarfile);
	}

	if (did_download) {
		printf("Completed manifests download.\n\n");
	}

	return ret;
}