static void
gabble_jingle_share_set_property (GObject *object,
                                  guint property_id,
                                  const GValue *value,
                                  GParamSpec *pspec)
{
  GabbleJingleShare *self = GABBLE_JINGLE_SHARE (object);
  GabbleJingleSharePrivate *priv = self->priv;

  switch (property_id)
    {
      case PROP_MEDIA_TYPE:
        break;
      case PROP_FILENAME:
        g_free (priv->filename);
        priv->filename = g_value_dup_string (value);
        free_manifest (self);
        /* simulate a media_ready when we know our own filename */
        _wocky_jingle_content_set_media_ready (WOCKY_JINGLE_CONTENT (self));
        break;
      case PROP_FILESIZE:
        priv->filesize = g_value_get_uint64 (value);
        free_manifest (self);
        break;
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
        break;
    }
}
Beispiel #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);
	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;
}
Beispiel #3
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;
}
Beispiel #4
0
int test_prepare_manifest_file(const gchar *dirname, const gchar *filename, gboolean custom_handler) {
	gchar *path = g_build_filename(dirname, filename, NULL);
	RaucManifest *rm = g_new0(RaucManifest, 1);
	RaucImage *img;

	rm->update_compatible = g_strdup("Test Config");
	rm->update_version = g_strdup("2011.03-2");

	if (custom_handler)
		rm->handler_name = g_strdup("custom_handler.sh");

	img = g_new0(RaucImage, 1);

	img->slotclass = g_strdup("rootfs");
	img->filename = g_strdup("rootfs.img");
	rm->images = g_list_append(rm->images, img);

	img = g_new0(RaucImage, 1);

	img->slotclass = g_strdup("appfs");
	img->filename = g_strdup("appfs.img");
	rm->images = g_list_append(rm->images, img);

	g_assert_true(save_manifest_file(path, rm, NULL));

	free_manifest(rm);
	return 0;
}
Beispiel #5
0
/*
 * Try to get the object hash from a manifest file. Caller frees. Returns NULL
 * on failure.
 */
struct file_hash *
manifest_get(struct conf *conf, const char *manifest_path)
{
	int fd;
	gzFile f = NULL;
	struct manifest *mf = NULL;
	struct hashtable *hashed_files = NULL; /* path --> struct file_hash */
	struct hashtable *stated_files = NULL; /* path --> struct file_stats */
	uint32_t i;
	struct file_hash *fh = NULL;

	fd = open(manifest_path, O_RDONLY | O_BINARY);
	if (fd == -1) {
		/* Cache miss. */
		cc_log("No such manifest file");
		goto out;
	}
	f = gzdopen(fd, "rb");
	if (!f) {
		close(fd);
		cc_log("Failed to gzdopen manifest file");
		goto out;
	}
	mf = read_manifest(f);
	if (!mf) {
		cc_log("Error reading manifest file");
		goto out;
	}

	hashed_files = create_hashtable(1000, hash_from_string, strings_equal);
	stated_files = create_hashtable(1000, hash_from_string, strings_equal);

	/* Check newest object first since it's a bit more likely to match. */
	for (i = mf->n_objects; i > 0; i--) {
		if (verify_object(conf, mf, &mf->objects[i - 1],
		                  stated_files, hashed_files)) {
			fh = x_malloc(sizeof(*fh));
			*fh = mf->objects[i - 1].hash;
			goto out;
		}
	}

out:
	if (hashed_files) {
		hashtable_destroy(hashed_files, 1);
	}
	if (stated_files) {
		hashtable_destroy(stated_files, 1);
	}
	if (f) {
		gzclose(f);
	}
	if (mf) {
		free_manifest(mf);
	}
	return fh;
}
Beispiel #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;
}
Beispiel #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;

	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;
}
Beispiel #8
0
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;
}
Beispiel #9
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;
}
Beispiel #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 = 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;
}
Beispiel #11
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;
}
Beispiel #12
0
static void
gabble_jingle_share_dispose (GObject *object)
{
  GabbleJingleShare *self = GABBLE_JINGLE_SHARE (object);
  GabbleJingleSharePrivate *priv = self->priv;

  if (priv->dispose_has_run)
    return;

  DEBUG ("dispose called");
  priv->dispose_has_run = TRUE;

  g_free (priv->filename);
  priv->filename = NULL;

  free_manifest (self);

  if (G_OBJECT_CLASS (gabble_jingle_share_parent_class)->dispose)
    G_OBJECT_CLASS (gabble_jingle_share_parent_class)->dispose (object);
}
Beispiel #13
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;
}
Beispiel #14
0
/*
 * The SelectVersion() routine ensures that an appropriate version of
 * the JRE is running.  The specification for the appropriate version
 * is obtained from either the manifest of a jar file (preferred) or
 * from command line options.
 */
static void
SelectVersion(int argc, char **argv, char **main_class)
{
    char    *arg;
    char    **new_argv;
    char    **new_argp;
    char    *operand;
    char    *version = NULL;
    char    *jre = NULL;
    int     jarflag = 0;
    int     restrict_search = -1;		/* -1 implies not known */
    manifest_info info;
    char    env_entry[MAXNAMELEN + 24] = ENV_ENTRY "=";
    char    *env_in;
    int     res;

    /*
     * If the version has already been selected, set *main_class
     * with the value passed through the environment (if any) and
     * simply return.
     */
    if ((env_in = getenv(ENV_ENTRY)) != NULL) {
	if (*env_in != '\0')
	    *main_class = strdup(env_in);
	return;
    }

    /*
     * Scan through the arguments for options relevant to multiple JRE
     * support.  For reference, the command line syntax is defined as:
     *
     * SYNOPSIS
     *      java [options] class [argument...]
     *
     *      java [options] -jar file.jar [argument...]
     *
     * As the scan is performed, make a copy of the argument list with
     * the version specification options (new to 1.5) removed, so that
     * a version less than 1.5 can be exec'd.
     */
    new_argv = MemAlloc((argc + 1) * sizeof(char*));
    new_argv[0] = argv[0];
    new_argp = &new_argv[1];
    argc--;
    argv++;
    while ((arg = *argv) != 0 && *arg == '-') {
	if (strncmp(arg, "-version:", 9) == 0) {
	    version = arg + 9;
	} else if (strcmp(arg, "-jre-restrict-search") == 0) {
	    restrict_search = 1;
	} else if (strcmp(arg, "-no-jre-restrict-search") == 0) {
	    restrict_search = 0;
	} else {
	    if (strcmp(arg, "-jar") == 0)
		jarflag = 1;
	    /* deal with "unfortunate" classpath syntax */
	    if (strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) {
	        if (argc >= 1) {
		    *new_argp++ = arg;
		    argc--;
		    argv++;
		    arg = *argv;
		}
	    }
	    *new_argp++ = arg;
	}
	argc--;
	argv++;
    }
    if (argc <= 0) {	/* No operand? Possibly legit with -[full]version */
	operand = NULL;
    } else {
	argc--;
	*new_argp++ = operand = *argv++;
    }
    while (argc-- > 0)  /* Copy over [argument...] */
	*new_argp++ = *argv++;
    *new_argp = NULL;

    /*
     * If there is a jar file, read the manifest. If the jarfile can't be
     * read, the manifest can't be read from the jar file, or the manifest
     * is corrupt, issue the appropriate error messages and exit.
     *
     * Even if there isn't a jar file, construct a manifest_info structure
     * containing the command line information.  Its a convenient way to carry
     * this data around.
     */
    if (jarflag && operand) {
	if ((res = parse_manifest(operand, &info)) != 0) {
	    if (res == -1)
		ReportErrorMessage2("Unable to access jarfile %s",
		  operand, JNI_TRUE);
	    else
		ReportErrorMessage2("Invalid or corrupt jarfile %s",
		  operand, JNI_TRUE);
	    exit(1);
	}
    } else {
	info.manifest_version = NULL;
	info.main_class = NULL;
	info.jre_version = NULL;
	info.jre_restrict_search = 0;
    }

    /*
     * The JRE-Version and JRE-Restrict-Search values (if any) from the
     * manifest are overwritten by any specified on the command line.
     */
    if (version != NULL)
	info.jre_version = version;
    if (restrict_search != -1)
	info.jre_restrict_search = restrict_search;

    /*
     * "Valid" returns (other than unrecoverable errors) follow.  Set
     * main_class as a side-effect of this routine.
     */
    if (info.main_class != NULL)
	*main_class = strdup(info.main_class);

    /*
     * If no version selection information is found either on the command
     * line or in the manifest, simply return.
     */
    if (info.jre_version == NULL) {
	free_manifest();
	free(new_argv);
	return;
    }

    /*
     * Check for correct syntax of the version specification (JSR 56).
     */
    if (!valid_version_string(info.jre_version)) {
	ReportErrorMessage2("Syntax error in version specification \"%s\"",
	  info.jre_version, JNI_TRUE);
	exit(1);
    }

    /*
     * Find the appropriate JVM on the system. Just to be as forgiving as
     * possible, if the standard algorithms don't locate an appropriate
     * jre, check to see if the one running will satisfy the requirements.
     * This can happen on systems which haven't been set-up for multiple
     * JRE support.
     */
    jre = LocateJRE(&info);
    if (_launcher_debug)
        printf("JRE-Version = %s, JRE-Restrict-Search = %s Selected = %s\n",
          (info.jre_version?info.jre_version:"null"),
          (info.jre_restrict_search?"true":"false"), (jre?jre:"null"));
    if (jre == NULL) {
	if (acceptable_release(FULL_VERSION, info.jre_version)) {
	    free_manifest();
	    free(new_argv);
	    return;
	} else {
	    ReportErrorMessage2(
	      "Unable to locate JRE meeting specification \"%s\"",
	      info.jre_version, JNI_TRUE);
	    exit(1);
	}
    }

    /*
     * If I'm not the chosen one, exec the chosen one.  Returning from
     * ExecJRE indicates that I am indeed the chosen one.
     *
     * The private environment variable _JAVA_VERSION_SET is used to
     * prevent the chosen one from re-reading the manifest file and
     * using the values found within to override the (potential) command
     * line flags stripped from argv (because the target may not
     * understand them).  Passing the MainClass value is an optimization
     * to avoid locating, expanding and parsing the manifest extra
     * times.
     */
    if (info.main_class != NULL) {
	if (strlen(info.main_class) <= MAXNAMELEN) {
	    (void)strcat(env_entry, info.main_class);
	} else {
	    ReportErrorMessage("Error: main-class: attribute exceeds system limits\n", JNI_TRUE);
	    exit(1);
	}
    }
    (void)putenv(env_entry);
    ExecJRE(jre, new_argv);
    free_manifest();
    free(new_argv);
    return;
}
Beispiel #15
0
static struct manifest *
read_manifest(gzFile f)
{
	struct manifest *mf = create_empty_manifest();

	uint32_t magic;
	READ_INT(4, magic);
	if (magic != MAGIC) {
		cc_log("Manifest file has bad magic number %u", magic);
		goto error;
	}

	READ_BYTE(mf->version);
	if (mf->version != MANIFEST_VERSION) {
		cc_log("Manifest file has unknown version %u", mf->version);
		goto error;
	}

	READ_BYTE(mf->hash_size);
	if (mf->hash_size != 16) {
		// Temporary measure until we support different hash algorithms.
		cc_log("Manifest file has unsupported hash size %u", mf->hash_size);
		goto error;
	}

	READ_INT(2, mf->reserved);

	READ_INT(4, mf->n_files);
	mf->files = x_calloc(mf->n_files, sizeof(*mf->files));
	for (uint32_t i = 0; i < mf->n_files; i++) {
		READ_STR(mf->files[i]);
	}

	READ_INT(4, mf->n_file_infos);
	mf->file_infos = x_calloc(mf->n_file_infos, sizeof(*mf->file_infos));
	for (uint32_t i = 0; i < mf->n_file_infos; i++) {
		READ_INT(4, mf->file_infos[i].index);
		READ_BYTES(mf->hash_size, mf->file_infos[i].hash);
		READ_INT(4, mf->file_infos[i].size);
		READ_INT(8, mf->file_infos[i].mtime);
		READ_INT(8, mf->file_infos[i].ctime);
	}

	READ_INT(4, mf->n_objects);
	mf->objects = x_calloc(mf->n_objects, sizeof(*mf->objects));
	for (uint32_t i = 0; i < mf->n_objects; i++) {
		READ_INT(4, mf->objects[i].n_file_info_indexes);
		mf->objects[i].file_info_indexes =
			x_calloc(mf->objects[i].n_file_info_indexes,
			         sizeof(*mf->objects[i].file_info_indexes));
		for (uint32_t j = 0; j < mf->objects[i].n_file_info_indexes; j++) {
			READ_INT(4, mf->objects[i].file_info_indexes[j]);
		}
		READ_BYTES(mf->hash_size, mf->objects[i].hash.hash);
		READ_INT(4, mf->objects[i].hash.size);
	}

	return mf;

error:
	cc_log("Corrupt manifest file");
	free_manifest(mf);
	return NULL;
}
Beispiel #16
0
/* 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;
}
Beispiel #17
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;
}
Beispiel #18
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 **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;
}
Beispiel #19
0
/* 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;
}
Beispiel #20
0
/* do_search()
 * Description: Perform a lookup of the specified search string in all Clear manifests
 * for the current os release.
 */
void do_search(struct manifest *MoM, char search_type, char *search_term)
{
	struct list *list;
	struct list *sublist;
	struct file *file;
	struct file *subfile;
	struct manifest *subman = NULL;
	int i, ret;
	bool done_with_bundle, done = false;
	bool hit = false;

	list = MoM->manifests;
	while (list && !done) {
		file = list->data;
		list = list->next;
		done_with_bundle = false;

		/* Load sub-manifest */
		ret = load_manifests(file->last_change, file->last_change, file->filename, NULL, &subman);
		if (ret != 0) {
			printf("Failed to load manifest %s\n", file->filename);
			continue;
		}

		if (display_files) {
			/* Display bundle name. Marked up for pattern matchability */
			printf("--Bundle: %s--\n", file->filename);
		}

		/* Loop through sub-manifest, searching for files matching the desired pattern */
		sublist = subman->files;
		while (sublist && !done_with_bundle) {
			subfile = sublist->data;
			sublist = sublist->next;

			if (!subfile->is_file) {
				continue;
			}

			if (display_files) {
				/* Just display filename */
				file_search(subfile->filename, NULL, NULL);
			} else if (search_type == 'e') {
				/* Search for exact match, not path addition */
				if (file_search(subfile->filename, "", search_term)) {
					report_find(file->filename, subfile->filename);
					hit = true;
					if (!display_all) {
						done = true;
					}

					done_with_bundle = true;
					break;
				}
			} else if (search_type == 'l') {
				/* Check each supported library path for a match */
				for (i = 0; lib_paths[i] != NULL; i++) {
					if (file_search(subfile->filename, lib_paths[i], search_term)) {
						report_find(file->filename, subfile->filename);
						hit = true;
						if (!display_all) {
							done = true;
						}

						done_with_bundle = true;
						break;
					}
				}
			} else if (search_type == 'b') {
				/* Check each supported path for binaries */
				for (i = 0; bin_paths[i] != NULL; i++) {
					if (file_search(subfile->filename, bin_paths[i], search_term)) {
						report_find(file->filename, subfile->filename);
						hit = true;
						if (!display_all) {
							done = true;
						}

						done_with_bundle = true;
						break;
					}
				}
			} else {
				printf("Unrecognized search type. -b or -l supported\n");
				done = true;
				break;
			}
		}

		free_manifest(subman);
	}

	if (!hit) {
		printf("Search term not found.\n");
	}
}
Beispiel #21
0
static void
parse_description (WockyJingleContent *content,
    WockyNode *desc_node, GError **error)
{
  GabbleJingleShare *self = GABBLE_JINGLE_SHARE (content);
  GabbleJingleSharePrivate *priv = self->priv;
  WockyNodeIter i;
  WockyNode *manifest_node = NULL;
  WockyNode *protocol_node = NULL;
  WockyNode *http_node = NULL;
  WockyNode *node;

  DEBUG ("parse description called");

  if (priv->manifest != NULL)
    {
      DEBUG ("Not parsing description, we already have a manifest");
      return;
    }

  manifest_node = wocky_node_get_child (desc_node, "manifest");

  if (manifest_node == NULL)
    {
      g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST,
          "description missing <manifest/> node");
      return;
    }

  protocol_node = wocky_node_get_child (desc_node, "protocol");
  if (protocol_node != NULL)
    http_node = wocky_node_get_child (protocol_node, "http");

  free_manifest (self);
  priv->manifest = g_slice_new0 (GabbleJingleShareManifest);

  /* Build the manifest */
  wocky_node_iter_init (&i, manifest_node, NULL, NULL);
  while (wocky_node_iter_next (&i, &node))
    {
      WockyNode *name = NULL;
      WockyNode *image = NULL;
      gboolean folder;
      const gchar *size;
      GabbleJingleShareManifestEntry *m = NULL;

      if (!wocky_strdiff (node->name, "folder"))
        folder = TRUE;
      else if (!wocky_strdiff (node->name, "file"))
        folder = FALSE;
      else
        continue;

      name = wocky_node_get_child (node, "name");
      if (name == NULL)
        continue;

      m = g_slice_new0 (GabbleJingleShareManifestEntry);
      m->folder = folder;
      m->name = g_strdup (name->content);

      size = wocky_node_get_attribute (node, "size");
      if (size)
        m->size = g_ascii_strtoull (size, NULL, 10);

      image = wocky_node_get_child (node, "image");
      if (image)
        {
          const gchar *width;
          const gchar *height;

          m->image = TRUE;

          width = wocky_node_get_attribute (image, "width");
          if (width)
            m->image_width = g_ascii_strtoull (width, NULL, 10);

          height =wocky_node_get_attribute (image, "height");
          if (height)
            m->image_height = g_ascii_strtoull (height, NULL, 10);
        }
      priv->manifest->entries = g_list_prepend (priv->manifest->entries, m);
    }

  /* Get the source and preview url paths from the protocol/http node */
  if (http_node != NULL)
    {
      /* clear the previously set values */
      wocky_node_iter_init (&i, http_node, "url", NULL);
      while (wocky_node_iter_next (&i, &node))
        {
          const gchar *name = wocky_node_get_attribute (node, "name");
          if (name == NULL)
            continue;

          if (!wocky_strdiff (name, "source-path"))
            {
              const gchar *url = node->content;
              priv->manifest->source_url = g_strdup (url);
            }

          if (!wocky_strdiff (name, "preview-path"))
            {
              const gchar *url = node->content;
              priv->manifest->preview_url = g_strdup (url);
            }
        }
    }

  /* Build the filename/filesize property values based on the new manifest */
  g_free (priv->filename);
  priv->filename = NULL;
  priv->filesize = 0;

  if (g_list_length (priv->manifest->entries) > 0)
    {
      if (g_list_length (priv->manifest->entries) == 1)
        {
          GabbleJingleShareManifestEntry *m = priv->manifest->entries->data;

          if (m->folder)
            priv->filename = g_strdup_printf ("%s.tar", m->name);
          else
            priv->filename = g_strdup (m->name);

          priv->filesize = m->size;
        }
      else
        {
          GList *li;
          gchar *temp;

          priv->filename = g_strdup ("");
          for (li = priv->manifest->entries; li; li = li->next)
            {
              GabbleJingleShareManifestEntry *m = li->data;

              temp = priv->filename;
              priv->filename = g_strdup_printf ("%s%s%s%s",  temp, m->name,
                  m->folder? ".tar":"", li->next == NULL? "": "-");
              g_free (temp);

              priv->filesize += m->size;
            }
          temp = priv->filename;
          priv->filename = g_strdup_printf ("%s.tar", temp);
          g_free (temp);
        }
    }
  _wocky_jingle_content_set_media_ready (content);
}
Beispiel #22
0
// Put the object name into a manifest file given a set of included files.
// Returns true on success, otherwise false.
bool
manifest_put(const char *manifest_path, struct file_hash *object_hash,
             struct hashtable *included_files)
{
	int ret = 0;
	gzFile f2 = NULL;
	struct manifest *mf = NULL;
	char *tmp_file = NULL;

	// We don't bother to acquire a lock when writing the manifest to disk. A
	// race between two processes will only result in one lost entry, which is
	// not a big deal, and it's also very unlikely.

	int fd1 = open(manifest_path, O_RDONLY | O_BINARY);
	if (fd1 == -1) {
		// New file.
		mf = create_empty_manifest();
	} else {
		gzFile f1 = gzdopen(fd1, "rb");
		if (!f1) {
			cc_log("Failed to gzdopen manifest file");
			close(fd1);
			goto out;
		}
		mf = read_manifest(f1);
		gzclose(f1);
		if (!mf) {
			cc_log("Failed to read manifest file; deleting it");
			x_unlink(manifest_path);
			mf = create_empty_manifest();
		}
	}

	if (mf->n_objects > MAX_MANIFEST_ENTRIES) {
		// Normally, there shouldn't be many object entries in the manifest since
		// new entries are added only if an include file has changed but not the
		// source file, and you typically change source files more often than
		// header files. However, it's certainly possible to imagine cases where
		// the manifest will grow large (for instance, a generated header file that
		// changes for every build), and this must be taken care of since
		// processing an ever growing manifest eventually will take too much time.
		// A good way of solving this would be to maintain the object entries in
		// LRU order and discarding the old ones. An easy way is to throw away all
		// entries when there are too many. Let's do that for now.
		cc_log("More than %u entries in manifest file; discarding",
		       MAX_MANIFEST_ENTRIES);
		free_manifest(mf);
		mf = create_empty_manifest();
	} else if (mf->n_file_infos > MAX_MANIFEST_FILE_INFO_ENTRIES) {
		// Rarely, file_info entries can grow large in pathological cases where
		// many included files change, but the main file does not. This also puts
		// an upper bound on the number of file_info entries.
		cc_log("More than %u file_info entries in manifest file; discarding",
		       MAX_MANIFEST_FILE_INFO_ENTRIES);
		free_manifest(mf);
		mf = create_empty_manifest();
	}

	tmp_file = format("%s.tmp", manifest_path);
	int fd2 = create_tmp_fd(&tmp_file);
	f2 = gzdopen(fd2, "wb");
	if (!f2) {
		cc_log("Failed to gzdopen %s", tmp_file);
		goto out;
	}

	add_object_entry(mf, object_hash, included_files);
	if (write_manifest(f2, mf)) {
		gzclose(f2);
		f2 = NULL;
		if (x_rename(tmp_file, manifest_path) == 0) {
			ret = 1;
		} else {
			cc_log("Failed to rename %s to %s", tmp_file, manifest_path);
			goto out;
		}
	} else {
		cc_log("Failed to write manifest file");
		goto out;
	}

out:
	if (mf) {
		free_manifest(mf);
	}
	if (tmp_file) {
		free(tmp_file);
	}
	if (f2) {
		gzclose(f2);
	}
	return ret;
}
Beispiel #23
0
/*
 * Put the object name into a manifest file given a set of included files.
 * Returns true on success, otherwise false.
 */
bool
manifest_put(const char *manifest_path, struct file_hash *object_hash,
             struct hashtable *included_files)
{
	int ret = 0;
	int fd1;
	int fd2;
	gzFile f2 = NULL;
	struct manifest *mf = NULL;
	char *tmp_file = NULL;

	/*
	 * We don't bother to acquire a lock when writing the manifest to disk. A
	 * race between two processes will only result in one lost entry, which is
	 * not a big deal, and it's also very unlikely.
	 */

	fd1 = open(manifest_path, O_RDONLY | O_BINARY);
	if (fd1 == -1) {
		/* New file. */
		mf = create_empty_manifest();
	} else {
		gzFile f1 = gzdopen(fd1, "rb");
		if (!f1) {
			cc_log("Failed to gzdopen manifest file");
			close(fd1);
			goto out;
		}
		mf = read_manifest(f1);
		gzclose(f1);
		if (!mf) {
			cc_log("Failed to read manifest file; deleting it");
			x_unlink(manifest_path);
			mf = create_empty_manifest();
		}
	}

	if (mf->n_objects > MAX_MANIFEST_ENTRIES) {
		/*
		 * Normally, there shouldn't be many object entries in the manifest since
		 * new entries are added only if an include file has changed but not the
		 * source file, and you typically change source files more often than
		 * header files. However, it's certainly possible to imagine cases where
		 * the manifest will grow large (for instance, a generated header file that
		 * changes for every build), and this must be taken care of since
		 * processing an ever growing manifest eventually will take too much time.
		 * A good way of solving this would be to maintain the object entries in
		 * LRU order and discarding the old ones. An easy way is to throw away all
		 * entries when there are too many. Let's do that for now.
		 */
		cc_log("More than %u entries in manifest file; discarding",
		       MAX_MANIFEST_ENTRIES);
		free_manifest(mf);
		mf = create_empty_manifest();
	}

	tmp_file = format("%s.tmp.%s", manifest_path, tmp_string());
	fd2 = safe_create_wronly(tmp_file);
	if (fd2 == -1) {
		cc_log("Failed to open %s", tmp_file);
		goto out;
	}
	f2 = gzdopen(fd2, "wb");
	if (!f2) {
		cc_log("Failed to gzdopen %s", tmp_file);
		goto out;
	}

	add_object_entry(mf, object_hash, included_files);
	if (write_manifest(f2, mf)) {
		gzclose(f2);
		f2 = NULL;
		if (x_rename(tmp_file, manifest_path) == 0) {
			ret = 1;
		} else {
			cc_log("Failed to rename %s to %s", tmp_file, manifest_path);
			goto out;
		}
	} else {
		cc_log("Failed to write manifest file");
		goto out;
	}

out:
	if (mf) {
		free_manifest(mf);
	}
	if (tmp_file) {
		free(tmp_file);
	}
	if (f2) {
		gzclose(f2);
	}
	return ret;
}
Beispiel #24
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;
}
Beispiel #25
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;
}
Beispiel #26
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;
}
Beispiel #27
0
bool
manifest_dump(const char *manifest_path, FILE *stream)
{
	struct manifest *mf = NULL;
	gzFile f = NULL;
	bool ret = false;

	int fd = open(manifest_path, O_RDONLY | O_BINARY);
	if (fd == -1) {
		fprintf(stderr, "No such manifest file: %s\n", manifest_path);
		goto out;
	}
	f = gzdopen(fd, "rb");
	if (!f) {
		fprintf(stderr, "Failed to dzopen manifest file\n");
		close(fd);
		goto out;
	}
	mf = read_manifest(f);
	if (!mf) {
		fprintf(stderr, "Error reading manifest file\n");
		goto out;
	}

	fprintf(stream, "Magic: %c%c%c%c\n",
	        (MAGIC >> 24) & 0xFF,
	        (MAGIC >> 16) & 0xFF,
	        (MAGIC >> 8) & 0xFF,
	        MAGIC & 0xFF);
	fprintf(stream, "Version: %u\n", mf->version);
	fprintf(stream, "Hash size: %u\n", (unsigned)mf->hash_size);
	fprintf(stream, "Reserved field: %u\n", (unsigned)mf->reserved);
	fprintf(stream, "File paths (%u):\n", (unsigned)mf->n_files);
	for (unsigned i = 0; i < mf->n_files; ++i) {
		fprintf(stream, "  %u: %s\n", i, mf->files[i]);
	}
	fprintf(stream, "File infos (%u):\n", (unsigned)mf->n_file_infos);
	for (unsigned i = 0; i < mf->n_file_infos; ++i) {
		char *hash;
		fprintf(stream, "  %u:\n", i);
		fprintf(stream, "    Path index: %u\n", mf->file_infos[i].index);
		hash = format_hash_as_string(mf->file_infos[i].hash, -1);
		fprintf(stream, "    Hash: %s\n", hash);
		free(hash);
		fprintf(stream, "    Size: %u\n", mf->file_infos[i].size);
		fprintf(stream, "    Mtime: %lld\n", (long long)mf->file_infos[i].mtime);
		fprintf(stream, "    Ctime: %lld\n", (long long)mf->file_infos[i].ctime);
	}
	fprintf(stream, "Results (%u):\n", (unsigned)mf->n_objects);
	for (unsigned i = 0; i < mf->n_objects; ++i) {
		char *hash;
		fprintf(stream, "  %u:\n", i);
		fprintf(stream, "    File info indexes:");
		for (unsigned j = 0; j < mf->objects[i].n_file_info_indexes; ++j) {
			fprintf(stream, " %u", mf->objects[i].file_info_indexes[j]);
		}
		fprintf(stream, "\n");
		hash = format_hash_as_string(mf->objects[i].hash.hash, -1);
		fprintf(stream, "    Hash: %s\n", hash);
		free(hash);
		fprintf(stream, "    Size: %u\n", (unsigned)mf->objects[i].hash.size);
	}

	ret = true;

out:
	if (mf) {
		free_manifest(mf);
	}
	if (f) {
		gzclose(f);
	}
	return ret;
}
Beispiel #28
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;
}
Beispiel #29
0
/* do_search()
 * Description: Perform a lookup of the specified search string in all Clear manifests
 * for the current os release.
 */
static void do_search(struct manifest *MoM, char search_type, char *search_term)
{
	struct list *list;
	struct list *sublist;
	struct file *file;
	struct file *subfile;
	struct list *bundle_info = NULL;
	struct manifest *subman = NULL;
	int i;
	bool done_with_bundle, done_with_search = false;
	bool hit = false;
	bool man_load_failures = false;
	long hit_count = 0;

	list = MoM->manifests;
	while (list && !done_with_search) {
		file = list->data;
		list = list->next;
		done_with_bundle = false;

		/* Load sub-manifest */
		subman = load_manifest(file->last_change, file, MoM, false);
		if (!subman) {
			fprintf(stderr, "Failed to load manifest %s\n", file->filename);
			man_load_failures = true;
			continue;
		}

		/* record contentsize and includes for install size calculation */
		struct bundle_result *bundle = NULL;
		bundle = calloc(sizeof(struct bundle_result), 1);
		ON_NULL_ABORT(bundle);
		/* copy relevant information over for future use */
		strncpy(bundle->bundle_name, subman->component, BUNDLE_NAME_MAXLEN - 1);
		bundle->topsize = subman->contentsize;
		/* do a deep copy of the includes list */
		bundle->includes = list_deep_clone_strs(subman->includes);
		bundle_info = list_prepend_data(bundle_info, bundle);

		if (display_files) {
			/* Display bundle name. Marked up for pattern matchability */
			fprintf(stderr, "--Bundle: %s--\n", file->filename);
		}

		/* Loop through sub-manifest, searching for files matching the desired pattern */
		sublist = subman->files;
		while (sublist && !done_with_bundle) {
			subfile = sublist->data;
			sublist = sublist->next;

			if ((!subfile->is_file) && (!subfile->is_link)) {
				continue;
			}

			if (display_files) {
				/* Just display filename */
				file_search(subfile->filename, NULL, NULL);
			} else if (search_type == '0') {
				/* Search for exact match, not path addition */
				if (file_search(subfile->filename, "", search_term)) {
					report_find(file->filename, subfile->filename, search_term);
					hit = true;
				}
			} else if (search_type == 'l') {
				/* Check each supported library path for a match */
				for (i = 0; lib_paths[i] != NULL; i++) {
					if (file_search(subfile->filename, lib_paths[i], search_term)) {
						report_find(file->filename, subfile->filename, search_term);
						hit = true;
					}
				}
			} else if (search_type == 'b') {
				/* Check each supported path for binaries */
				for (i = 0; bin_paths[i] != NULL; i++) {
					if (file_search(subfile->filename, bin_paths[i], search_term)) {
						report_find(file->filename, subfile->filename, search_term);
						hit = true;
					}
				}
			} else {
				fprintf(stderr, "Unrecognized search type. -b or -l supported\n");
				done_with_search = true;
				break;
			}

			/* Determine the level of completion we've reached */
			if (hit) {
				if (scope == 'b') {
					done_with_bundle = true;
				} else if (scope == 'o') {
					done_with_bundle = true;
					done_with_search = true;
				}

				hit_count++;
			}
			hit = false;
		}

		free_manifest(subman);
	}

	if (!hit_count) {
		fprintf(stderr, "Search term not found.\n");
	}

	bool display_size = (scope != 'o' && !man_load_failures);
	if (display_size) {
		apply_size_penalty(bundle_info);
	}
	list_free_list_and_data(bundle_info, free_bundle_result_data);

	if (num_results != INT_MAX) {
		sort_results();
	} else {
		results = list_sort(results, bundle_size_cmp);
	}

	if (csv_format) {
		print_csv_results();
	} else {
		print_final_results(display_size);
	}
	list_free_list_and_data(results, free_bundle_result_data);
}