Exemplo n.º 1
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;
}
Exemplo n.º 2
0
/* this function is intended to encapsulate the basic swupd
* initializations for the majority of commands, that is:
* 	- Make sure root is the user running the code
*	- Initialize log facility
*	- Get the lock
*	- initialize mounted directories
*	- Initialize curl
*/
int swupd_init(int *lock_fd)
{
	int ret = 0;

	check_root();
	*lock_fd = p_lockfile();
	if (*lock_fd < 0) {
		ret = ELOCK_FILE;
		goto out_fds;
	}

	get_mounted_directories();

	if (swupd_curl_init() != 0) {
		ret = ECURL_INIT;
		goto out_close_lock;
	}

	return ret;

out_close_lock:
	v_lockfile(*lock_fd);
out_fds:
	dump_file_descriptor_leaks();

	return ret;
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
0
void swupd_deinit(void)
{
	terminate_signature();
	swupd_curl_deinit();
	free_globals();
	v_lockfile();
	dump_file_descriptor_leaks();
}
Exemplo n.º 5
0
void swupd_deinit(int lock_fd)
{
	terminate_signature();
	swupd_curl_cleanup();
	free_subscriptions();
	free_globals();
	v_lockfile(lock_fd);
	dump_file_descriptor_leaks();
}
Exemplo n.º 6
0
int search_main(int argc, char **argv)
{
	int ret = 0;
	int lock_fd = 0;
	struct manifest *MoM = NULL;

	if (!parse_options(argc, argv)) {
		return EXIT_FAILURE;
	}

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

	if (!check_network()) {
		printf("Error: Network issue, unable to proceed with update\n");
		ret = EXIT_FAILURE;
		goto clean_exit;
	}

	if (!init) {
		printf("Searching for '%s'\n\n", search_string);
	}

	ret = download_manifests(&MoM);
	if (ret != 0) {
		printf("Error: Failed to download manifests\n");
		goto clean_exit;
	}

	if (init) {
		printf("Successfully retreived manifests. Exiting\n");
		ret = 0;
		goto clean_exit;
	}

	/* Arbitrary upper limit to ensure we aren't getting handed garbage */
	if (!display_files &&
	    ((strlen(search_string) <= 0) || (strlen(search_string) > NAME_MAX))) {
		printf("Error - search string invalid\n");
		ret = EXIT_FAILURE;
		goto clean_exit;
	}

	do_search(MoM, search_type, search_string);

clean_exit:
	free_manifest(MoM);
	free_globals();
	swupd_curl_cleanup();
	v_lockfile(lock_fd);

	return ret;
}
Exemplo n.º 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;
}
Exemplo n.º 8
0
/* this function is intended to encapsulate the basic swupd
* initializations for the majority of commands, that is:
* 	- Make sure root is the user running the code
* 	- Initialize globals
*	- initialize mounted directories
*	- Create necessary directories
*	- Get the lock
*	- Initialize curl
*	- Initialize signature checking
*/
int swupd_init(void)
{
	int ret = 0;

	check_root();
	record_fds();

	/* Check that our system time is reasonably valid before continuing,
	 * or the certificate verification will fail with invalid time */
	if (timecheck) {
		if (!verify_time()) {
			ret = EBADTIME;
			goto out_fds;
		}
	}

	if (!init_globals()) {
		ret = EINIT_GLOBALS;
		goto out_fds;
	}

	get_mounted_directories();

	if (create_required_dirs()) {
		ret = EREQUIRED_DIRS;
		goto out_fds;
	}

	if (p_lockfile() < 0) {
		ret = ELOCK_FILE;
		goto out_fds;
	}

	if (swupd_curl_init() != 0) {
		ret = ECURL_INIT;
		goto out_close_lock;
	}

	/* If --nosigcheck, we do not attempt any signature checking */
	if (sigcheck && !initialize_signature()) {
		ret = ESIGNATURE;
		terminate_signature();
		goto out_close_lock;
	}

	return ret;

out_close_lock:
	v_lockfile();
out_fds:
	dump_file_descriptor_leaks();

	return ret;
}
Exemplo n.º 9
0
/* this function is intended to encapsulate the basic swupd
* initializations for the majority of commands, that is:
* 	- Make sure root is the user running the code
*	- Initialize log facility
*	- Get the lock
*	- initialize mounted directories
*	- Initialize curl
*/
int swupd_init(int *lock_fd)
{
	int ret = 0;

	check_root();

	if (!init_globals()) {
		ret = EINIT_GLOBALS;
		goto out_fds;
	}

	get_mounted_directories();

	if (create_required_dirs()) {
		ret = EREQUIRED_DIRS;
		goto out_fds;
	}

	*lock_fd = p_lockfile();
	if (*lock_fd < 0) {
		ret = ELOCK_FILE;
		goto out_fds;
	}

	if (swupd_curl_init() != 0) {
		ret = ECURL_INIT;
		goto out_close_lock;
	}

	if (!initialize_signature()) {
		ret = ESIGNATURE;
		terminate_signature();
		goto out_close_lock;
	}

	return ret;

out_close_lock:
	v_lockfile(*lock_fd);
out_fds:
	dump_file_descriptor_leaks();

	return ret;
}
Exemplo n.º 10
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;
}
Exemplo n.º 11
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;
}
Exemplo n.º 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;

	/* 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;
}
Exemplo n.º 13
0
int main_update()
{
	int current_version = -1, server_version = -1;
	struct manifest *current_manifest = NULL, *server_manifest = NULL;
	struct list *updates = NULL;
	int ret;
	int lock_fd;
	int retries = 0;
	int timeout = 10;

	srand(time(NULL));

	ret = swupd_init(&lock_fd);
	if (ret != 0) {
		/* being here means we already close log by a previously caught error */
		printf("Updater failed to initialize, exiting now.\n");
		return ret;
	}

	if (!check_network()) {
		printf("Error: Network issue, unable to proceed with update\n");
		ret = EXIT_FAILURE;
		goto clean_curl;
	}

	printf("Update started.\n");
	read_subscriptions_alt();

	if (!signature_initialize(UPDATE_CA_CERTS_PATH "/" SIGNATURE_CA_CERT)) {
		goto clean_curl;
	}

	/* Step 1: get versions */

	ret = check_versions(&current_version, &server_version, path_prefix);

	if (ret < 0) {
		goto clean_curl;
	}
	if (server_version <= current_version) {
		printf("Version on server (%i) is not newer than system version (%i)\n", server_version, current_version);
		ret = EXIT_SUCCESS;
		goto clean_curl;
	}

	printf("Preparing to update from %i to %i\n", current_version, server_version);

	/* Step 2: housekeeping */

	if (rm_staging_dir_contents("download")) {
		goto clean_curl;
	}

load_current_manifests:
	/* Step 3: setup manifests */

	/* get the from/to MoM manifests */
	printf("Querying current manifest.\n");
	ret = load_manifests(current_version, current_version, "MoM", NULL, &current_manifest);
	if (ret) {
		/* TODO: possibly remove this as not getting a "from" manifest is not fatal
		 * - we just don't apply deltas */
		if (retries < MAX_TRIES) {
			increment_retries(&retries, &timeout);
			printf("Retry #%d downloading from/to MoM Manifests\n", retries);
			goto load_current_manifests;
		}
		printf("Failure retrieving manifest from server\n");
		goto clean_exit;
	}

	/*  Reset the retries and timeout for subsequent download calls */
	retries = 0;
	timeout = 10;

load_server_manifests:
	printf("Querying server manifest.\n");

	ret = load_manifests(current_version, server_version, "MoM", NULL, &server_manifest);
	if (ret) {
		if (retries < MAX_TRIES) {
			increment_retries(&retries, &timeout);
			printf("Retry #%d downloading server Manifests\n", retries);
			goto load_server_manifests;
		}
		printf("Failure retrieving manifest from server\n");
		goto clean_exit;
	}

	if (current_manifest == NULL || server_manifest == NULL) {
		printf("Unable to load manifest after retrying (config or network problem?)\n");
		goto clean_exit;
	}

	retries = 0;
	timeout = 10;

	ret = add_included_manifests(server_manifest);
	if (ret) {
		goto clean_exit;
	}

	subscription_versions_from_MoM(current_manifest, 1);
	subscription_versions_from_MoM(server_manifest, 0);

	link_submanifests(current_manifest, server_manifest);

	/* updating subscribed manifests is done as part of recurse_manifest */

	/* read the current collective of manifests that we are subscribed to */
	current_manifest->submanifests = recurse_manifest(current_manifest, NULL);
	if (!current_manifest->submanifests) {
		printf("Cannot load current MoM sub-manifests, (%s), exiting\n", strerror(errno));
		goto clean_exit;
	}

	/* consolidate the current collective manifests down into one in memory */
	current_manifest->files = files_from_bundles(current_manifest->submanifests);

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

	/* read the new collective of manifests that we are subscribed to */
	server_manifest->submanifests = recurse_manifest(server_manifest, NULL);
	if (!server_manifest->submanifests) {
		printf("Error: Cannot load server MoM sub-manifests, (%s), exiting\n", strerror(errno));
		goto clean_exit;
	}

	/* consolidate the new collective manifests down into one in memory */
	server_manifest->files = files_from_bundles(server_manifest->submanifests);

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

	/* prepare for an update process based on comparing two in memory manifests */
	link_manifests(current_manifest, server_manifest);
#if 0
	debug_write_manifest(current_manifest, "debug_manifest_current.txt");
	debug_write_manifest(server_manifest, "debug_manifest_server.txt");
#endif
	/* Step 4: check disk state before attempting update */

	run_preupdate_scripts(server_manifest);

download_packs:
	/* Step 5: get the packs and untar */
	ret = download_subscribed_packs(false);
	if (ret) {
		// packs don't always exist, tolerate that but not ENONET
		if (retries < MAX_TRIES) {
			increment_retries(&retries, &timeout);
			printf("Retry #%d downloading packs\n", retries);
			goto download_packs;
		}
		printf("No network, or server unavailable for pack downloads\n");
		goto clean_exit;
	}

	/* Step 6: some more housekeeping */

	/* TODO: consider trying to do less sorting of manifests */

	updates = create_update_list(current_manifest, server_manifest);

	link_renames(updates, current_manifest); /* TODO: Have special lists for candidate and renames */

	print_statistics(current_version, server_version);

	/* Step 7: apply the update */

	ret = update_loop(updates, server_manifest);
	if (ret == 0) {
		ret = update_device_latest_version(server_version);
		printf("Update was applied.\n");
	}

	delete_motd();

	/* Run any scripts that are needed to complete update */
	run_scripts();

clean_exit:
	list_free_list(updates);
	free_manifest(current_manifest);
	free_manifest(server_manifest);

clean_curl:
	signature_terminate();
	swupd_curl_cleanup();
	free_subscriptions();
	free_globals();
	v_lockfile(lock_fd);
	dump_file_descriptor_leaks();

	if ((current_version < server_version) && (ret == 0)) {
		printf("Update successful. System updated from version %d to version %d\n",
		       current_version, server_version);
	} else if (ret == 0) {
		printf("Update complete. System already up-to-date at version %d\n", current_version);
	}

	return ret;
}
Exemplo n.º 14
0
static void clean_deinit(void)
{
	free_globals();
	v_lockfile();
}
Exemplo n.º 15
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;

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

	ret = load_manifests(current_version, current_version, "MoM", NULL, &current_mom);
	if (ret != 0) {
		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 */
	ret = recurse_manifest(current_mom, NULL);
	if (ret != 0) {
		printf("Error: Cannot load MoM sub-manifests (ret = %d)\n", ret);
		ret = ERECURSE_MANIFEST;
		goto out_free_mom;
	}

	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) {
		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_curl_cleanup();
	v_lockfile(lock_fd);
	dump_file_descriptor_leaks();

	return ret;
}
Exemplo n.º 16
0
/* Attempt to get a write lock protecting the file test/protected_data using
 * p_lockfile(). If successful, no two processess should be able to hold the
 * lock similtaneously.
 */
static void work(int id)
{
	int lock_fd;
	int successes = 0;

	FILE *file;
	char buffer[LINE_MAX];

	while (successes < NUM_ACCESS) {
		int prev_id = -1;
		char prev_action = ' ';
		char c = ' ';

		// Sleep for a random amount of time, up to half a second so
		// not all processes attempt to access lock at once.
		usleep(rand() % 500000);

		// Attempt to access the lock
		lock_fd = p_lockfile();
		if (lock_fd < 0) {
			printf("process %i unable to acquire lock\n", id);
			fflush(stdout);

			continue;
		}

		printf("process %i acquired lock\n", id);

		file = fopen(PROTECTED_FILE, "a+");

		fseek(file, 0, SEEK_END);

		// Check if file is empty
		if (ftell(file) != 0) {
			// Go to start of last line
			while (c != '\n' && fseek(file, -2, SEEK_CUR) == 0) {
				c = getc(file);
			}

			// If the file only has one line, return to start of file
			if (c != '\n') {
				rewind(file);
			}

			// Read last line of protected_data
			sscanf(fgets(buffer, LINE_MAX, file), "%i%c\n", &prev_id, &prev_action);
		}

		fprintf(file, "%ip\n", id);
		fflush(file);

		if (prev_action == 'p') {
			printf("process %i accessed lock being held by process %i\n", id, prev_id);
			printf("process %i aborting\n\n", id);
			return;
		}

		// Sleep for up to a fifth of a second while holding lock. During this time
		// other processes should try to access lock and fail. This sleep is shorter
		// than the one before attempting to get the lock because we don't need to
		// wait for all other processes to attempt to access lock, just some of them
		usleep(rand() % 200000);

		fseek(file, 0, SEEK_END);

		if (ftell(file) == 0) {
			printf("process %i failed to write to protected_data", id);
			printf("process %i aborting\n\n", id);
		} else {
			char c = ' ';
			while (c != '\n' && fseek(file, -2, SEEK_CUR) == 0) {
				c = getc(file);
			}

			if (c != '\n') {
				rewind(file);
			}

			sscanf(fgets(buffer, LINE_MAX, file), "%i%c\n", &prev_id, &prev_action);
		}

		// Log that this thread released the lock
		fprintf(file, "%iv\n", id);
		fclose(file);

		if (prev_action != 'p' || prev_id != id) {
			if (prev_id == -1) {
				printf("process %i released lock without holding it\n", id);
			} else {
				printf("process %i and process %i held lock similtaneously\n", id, prev_id);
			}
			printf("process %i aborting\n\n", id);
			return;
		}

		printf("process %i released lock\n\n", id);
		v_lockfile(lock_fd);
		successes++;
	}
	return;
}