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"); return ret; } 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); swupd_deinit(lock_fd); return ret; }
int search_main(int argc, char **argv) { int ret = 0; struct manifest *MoM = NULL; struct list *subs = NULL; if (!parse_options(argc, argv)) { return EINVALID_OPTION; } ret = swupd_init(); if (ret != 0) { fprintf(stderr, "Failed swupd initialization, exiting now.\n"); return ret; } if (!init) { fprintf(stderr, "Searching for '%s'\n\n", search_string); } ret = download_manifests(&MoM, &subs); if (ret != 0) { fprintf(stderr, "Error: Failed to download manifests\n"); goto clean_exit; } if (init) { fprintf(stderr, "Successfully retrieved 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))) { fprintf(stderr, "Error - search string invalid\n"); ret = EXIT_FAILURE; goto clean_exit; } do_search(MoM, search_type, search_string); clean_exit: free_manifest(MoM); free_subscriptions(&subs); swupd_deinit(); return ret; }
/* 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; }
/* 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; }
/* This function does a simple verification of files listed in the * subscribed bundle manifests. If the optional "fix" or "install" parameter * is specified, the disk will be modified at each point during the * sequential comparison of manifest files to disk files, where the disk is * found to not match the manifest. This is notably different from update, * which attempts to atomically (or nearly atomically) activate a set of * pre-computed and validated staged changes as a group. */ int verify_main(int argc, char **argv) { struct manifest *official_manifest = NULL; int ret; int lock_fd; struct list *subs = NULL; copyright_header("software verify"); if (!parse_options(argc, argv)) { return EINVALID_OPTION; } /* parse command line options */ assert(argc >= 0); assert(argv != NULL); ret = swupd_init(&lock_fd); if (ret != 0) { printf("Failed verify initialization, exiting now.\n"); return ret; } /* Gather current manifests */ if (!version) { version = get_current_version(path_prefix); if (version < 0) { printf("Error: Unable to determine current OS version\n"); ret = ECURRENT_VERSION; goto clean_and_exit; } } if (version == -1) { version = get_latest_version(); if (version < 0) { printf("Unable to get latest version for install\n"); ret = EXIT_FAILURE; goto clean_and_exit; } } printf("Verifying version %i\n", version); if (!check_network()) { printf("Error: Network issue, unable to download manifest\n"); ret = ENOSWUPDSERVER; goto clean_and_exit; } read_subscriptions_alt(&subs); /* * FIXME: We need a command line option to override this in case the * certificate is hosed and the admin knows it and wants to recover. */ ret = rm_staging_dir_contents("download"); if (ret != 0) { printf("Failed to remove prior downloads, carrying on anyway\n"); } official_manifest = load_mom(version); if (!official_manifest) { /* This is hit when or if an OS version is specified for --fix which * is not available, or if there is a server error and a manifest is * not provided. */ printf("Unable to download/verify %d Manifest.MoM\n", version); ret = EMOM_NOTFOUND; /* No repair is possible without a manifest, nor is accurate reporting * of the state of the system. Therefore cleanup, report failure and exit */ goto clean_and_exit; } ret = add_included_manifests(official_manifest, &subs); if (ret) { ret = EMANIFEST_LOAD; goto clean_and_exit; } set_subscription_versions(official_manifest, NULL, &subs); official_manifest->submanifests = recurse_manifest(official_manifest, subs, NULL); if (!official_manifest->submanifests) { printf("Error: Cannot load MoM sub-manifests\n"); ret = ERECURSE_MANIFEST; goto clean_and_exit; } official_manifest->files = files_from_bundles(official_manifest->submanifests); official_manifest->files = consolidate_files(official_manifest->files); /* when fixing or installing we need input files. */ if (cmdline_option_fix || cmdline_option_install) { ret = get_required_files(official_manifest, subs); if (ret != 0) { ret = -ret; goto clean_and_exit; } } /* preparation work complete. */ /* * NOTHING ELSE IS ALLOWED TO FAIL/ABORT after this line. * This tool is there to recover a nearly-bricked system. Aborting * from this point forward, for any reason, will result in a bricked system. * * I don't care what your static analysis tools says * I don't care what valgrind tells you * * There shall be no "goto fail;" from this point on. * * *** THE SHOW MUST GO ON *** */ if (cmdline_option_fix || cmdline_option_install) { /* * Next put the files in place that are missing completely. * This is to avoid updating a symlink to a library before the new full file * is already there. It's also the most safe operation, adding files rarely * has unintended side effect. So lets do the safest thing first. */ printf("Adding any missing files\n"); add_missing_files(official_manifest); } if (cmdline_option_quick) { /* quick only replaces missing files, so it is done here */ goto brick_the_system_and_clean_curl; } if (cmdline_option_fix) { bool repair = true; printf("Fixing modified files\n"); deal_with_hash_mismatches(official_manifest, repair); /* removing files could be risky, so only do it if the * prior phases had no problems */ if ((file_not_fixed_count == 0) && (file_not_replaced_count == 0)) { remove_orphaned_files(official_manifest); } } else { bool repair = false; printf("Verifying files\n"); deal_with_hash_mismatches(official_manifest, repair); } free_manifest(official_manifest); brick_the_system_and_clean_curl: /* clean up */ /* * naming convention: All exit goto labels must follow the "brick_the_system_and_FOO:" pattern */ /* report a summary of what we managed to do and not do */ printf("Inspected %i files\n", file_checked_count); if (cmdline_option_fix || cmdline_option_install) { printf(" %i files were missing\n", file_missing_count); if (file_missing_count) { printf(" %i of %i missing files were replaced\n", file_replaced_count, file_missing_count); printf(" %i of %i missing files were not replaced\n", file_not_replaced_count, file_missing_count); } } if (!cmdline_option_quick && file_mismatch_count > 0) { printf(" %i files did not match\n", file_mismatch_count); if (cmdline_option_fix) { printf(" %i of %i files were fixed\n", file_fixed_count, file_mismatch_count); printf(" %i of %i files were not fixed\n", file_not_fixed_count, file_mismatch_count); } } if ((file_not_fixed_count == 0) && (file_not_replaced_count == 0) && cmdline_option_fix && !cmdline_option_quick) { printf(" %i files found which should be deleted\n", file_extraneous_count); if (file_extraneous_count) { printf(" %i of %i files were deleted\n", file_deleted_count, file_extraneous_count); printf(" %i of %i files were not deleted\n", file_not_deleted_count, file_extraneous_count); } } if (cmdline_option_fix || cmdline_option_install) { // always run in a fix or install case need_update_boot = true; need_update_bootloader = true; run_scripts(); } sync(); if ((file_not_fixed_count == 0) && (file_not_replaced_count == 0) && (file_not_deleted_count == 0)) { ret = EXIT_SUCCESS; } else { ret = EXIT_FAILURE; } /* this concludes the critical section, after this point it's clean up time, the disk content is finished and final */ clean_and_exit: telemetry(ret ? TELEMETRY_CRIT : TELEMETRY_INFO, "verify", "fix=%d\nret=%d\n" "current_version=%d\n" "file_replaced_count=%d\n" "file_not_replaced_count=%d\n" "file_missing_count=%d\n" "file_fixed_count=%d\n" "file_not_fixed_count=%d\n" "file_deleted_count=%d\n" "file_not_deleted_count=%d\n" "file_mismatch_count=%d\n" "file_extraneous_count=%d\n", cmdline_option_fix || cmdline_option_install, ret, version, file_replaced_count, file_not_replaced_count, file_missing_count, file_fixed_count, file_not_fixed_count, file_deleted_count, file_not_deleted_count, file_mismatch_count, file_extraneous_count); if (ret == EXIT_SUCCESS) { if (cmdline_option_fix || cmdline_option_install) { printf("Fix successful\n"); } else { /* This is just a verification */ printf("Verify successful\n"); } } else { if (cmdline_option_fix || cmdline_option_install) { printf("Error: Fix did not fully succeed\n"); } else { /* This is just a verification */ printf("Error: Verify did not fully succeed\n"); } } swupd_deinit(lock_fd, &subs); return ret; }