static void test_g_variant_dict (void) { g_autoptr(GVariant) data = g_variant_new_from_data (G_VARIANT_TYPE ("a{sv}"), "", 0, FALSE, NULL, NULL); g_auto(GVariantDict) stackval; g_autoptr(GVariantDict) val = g_variant_dict_new (data); g_variant_dict_init (&stackval, data); g_assert (val != NULL); }
enum connection_type connection_type_from_properties(GVariant *properties) { enum connection_type type = CONNECTION_TYPE_UNKNOWN; GVariantDict *dict = g_variant_dict_new(properties); GVariant *type_v = g_variant_dict_lookup_value(dict, "Type", NULL); if(type_v) { const gchar *type_s; type_s = g_variant_get_string(type_v, NULL); type = connection_type_from_string(type_s); g_variant_unref(type_v); } g_variant_dict_unref(dict); return type; }
static void parse_configuration (Setting *setting) { GVariantDict *dict = NULL; GVariant *value = NULL; LoomSetting *loom_setting = LOOM_SETTING (setting); dict = g_variant_dict_new (setting->configuration); value = g_variant_dict_lookup_value (dict, "address", G_VARIANT_TYPE_STRING); loom_setting_set_address (loom_setting, g_variant_get_string (value, NULL)); if (g_variant_dict_contains (dict, "router")) { value = g_variant_dict_lookup_value (dict, "router", G_VARIANT_TYPE_STRING); loom_setting_set_router (loom_setting, g_variant_get_string (value, NULL)); } if (g_variant_dict_contains (dict, "nameservers")) { value = g_variant_dict_lookup_value (dict, "nameservers", G_VARIANT_TYPE_STRING_ARRAY); gchar **strv = g_variant_dup_strv (value, NULL); loom_setting_set_name_servers (loom_setting, (const gchar **)strv); g_strfreev (strv); } if (g_variant_dict_contains (dict, "domain")) { value = g_variant_dict_lookup_value (dict, "domains", G_VARIANT_TYPE_STRING); loom_setting_set_domain (loom_setting, g_variant_get_string (value, NULL)); } if (g_variant_dict_contains (dict, "searches")) { value = g_variant_dict_lookup_value (dict, "searches", G_VARIANT_TYPE_STRING_ARRAY); gchar **strv = g_variant_dup_strv (value, NULL); loom_setting_set_searches (loom_setting, (const gchar **)strv); g_strfreev (strv); } g_variant_dict_unref (dict); }
static gboolean validate_configuration (GVariant *configuration, GError **error) { GVariantDict *dict = NULL; GVariant *value = NULL; dict = g_variant_dict_new (configuration); if (g_variant_dict_contains (dict, "address")) { value = g_variant_dict_lookup_value (dict, "address", G_VARIANT_TYPE_STRING); if (value == NULL) { g_variant_dict_unref (dict); *error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, _("'address' entry must be a string")); return FALSE; } if (!validate_address ("address", g_variant_get_string (value, NULL), TRUE, error)) { g_variant_dict_unref (dict); return FALSE; } } else { g_variant_dict_unref (dict); *error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, _("'address' entry is required")); return FALSE; } if (g_variant_dict_contains (dict, "router")) { value = g_variant_dict_lookup_value (dict, "router", G_VARIANT_TYPE_STRING); if (value == NULL) { g_variant_dict_unref (dict); *error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, _("'router' entry must be a string")); return FALSE; } if (!validate_address ("router", g_variant_get_string (value, NULL), FALSE, error)) { g_variant_dict_unref (dict); return FALSE; } } if (g_variant_dict_contains (dict, "nameservers")) { value = g_variant_dict_lookup_value (dict, "nameservers", G_VARIANT_TYPE_STRING_ARRAY); if (value == NULL) { g_variant_dict_unref (dict); *error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, _("'nameservers' entry must be a string array")); return FALSE; } gsize len; gs_strfreev gchar **nameservers = g_variant_dup_strv (value, &len); for (gsize i = 0; i < len; i++) { if (!validate_address ("nameservers", nameservers[i], FALSE, error)) { g_variant_dict_unref (dict); return FALSE; } } } if (g_variant_dict_contains (dict, "domain")) { value = g_variant_dict_lookup_value (dict, "domain", G_VARIANT_TYPE_STRING); if (value == NULL) { g_variant_dict_unref (dict); *error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, _("'domain' entry must be a string")); return FALSE; } if (!validate_domainname ("domain", g_variant_get_string (value, NULL), error)) { g_variant_dict_unref (dict); return FALSE; } } if (g_variant_dict_contains (dict, "searches")) { value = g_variant_dict_lookup_value (dict, "searches", G_VARIANT_TYPE_STRING_ARRAY); if (value == NULL) { g_variant_dict_unref (dict); *error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, _("'searches' entry must be a string array")); return FALSE; } gsize len; gs_strfreev gchar **searches = g_variant_dup_strv (value, &len); for (gsize i = 0; i < len; i++) { if (!validate_domainname ("searches", searches[i], error)) { g_variant_dict_unref (dict); return FALSE; } } } g_variant_dict_unref (dict); return TRUE; }
OstreeDeltaEndianness _ostree_delta_get_endianness (GVariant *superblock, gboolean *out_was_heuristic) { guint8 endianness_char; g_autoptr(GVariant) delta_meta = NULL; g_autoptr(GVariantDict) delta_metadict = NULL; guint64 total_size = 0; guint64 total_usize = 0; guint total_objects = 0; delta_meta = g_variant_get_child_value (superblock, 0); delta_metadict = g_variant_dict_new (delta_meta); if (out_was_heuristic) *out_was_heuristic = FALSE; if (g_variant_dict_lookup (delta_metadict, "ostree.endianness", "y", &endianness_char)) { switch (endianness_char) { case 'l': return OSTREE_DELTA_ENDIAN_LITTLE; case 'B': return OSTREE_DELTA_ENDIAN_BIG; default: return OSTREE_DELTA_ENDIAN_INVALID; } } if (out_was_heuristic) *out_was_heuristic = TRUE; { g_autoptr(GVariant) meta_entries = NULL; guint n_parts; guint i; gboolean is_byteswapped = FALSE; g_variant_get_child (superblock, 6, "@a" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT, &meta_entries); n_parts = g_variant_n_children (meta_entries); for (i = 0; i < n_parts; i++) { g_autoptr(GVariant) objects = NULL; guint64 size, usize; guint n_objects; g_variant_get_child (meta_entries, i, "(u@aytt@ay)", NULL, NULL, &size, &usize, &objects); n_objects = (guint)(g_variant_get_size (objects) / OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN); total_objects += n_objects; total_size += size; total_usize += usize; if (size > usize) { double ratio = ((double)size)/((double)usize); /* This should really never happen where compressing things makes it more than 50% bigger. */ if (ratio > 1.2) { is_byteswapped = TRUE; break; } } } if (!is_byteswapped) { /* If the average object size is greater than 4GiB, let's assume * we're dealing with opposite endianness. I'm fairly confident * no one is going to be shipping peta- or exa- byte size ostree * deltas, period. Past the gigabyte scale you really want * bittorrent or something. */ if ((total_size / total_objects) > G_MAXUINT32) { is_byteswapped = TRUE; } } if (is_byteswapped) { switch (G_BYTE_ORDER) { case G_BIG_ENDIAN: return OSTREE_DELTA_ENDIAN_LITTLE; case G_LITTLE_ENDIAN: return OSTREE_DELTA_ENDIAN_BIG; default: g_assert_not_reached (); } } return OSTREE_DELTA_ENDIAN_INVALID; } }
gboolean rpmostree_container_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GError **error) { int exit_status = EXIT_FAILURE; GOptionContext *context = g_option_context_new ("NAME"); g_auto(ROContainerContext) rocctx_data = RO_CONTAINER_CONTEXT_INIT; ROContainerContext *rocctx = &rocctx_data; g_autoptr(RpmOstreeInstall) install = NULL; const char *name; g_autofree char *commit_checksum = NULL; g_autofree char *new_commit_checksum = NULL; g_autoptr(GVariant) commit = NULL; g_autoptr(GVariant) metadata = NULL; g_autoptr(GVariant) input_packages_v = NULL; g_autoptr(RpmOstreeTreespec) treespec = NULL; guint current_version; guint new_version; g_autofree char *previous_state_sha512 = NULL; const char *target_current_root; const char *target_new_root; if (!rpmostree_option_context_parse (context, assemble_option_entries, &argc, &argv, RPM_OSTREE_BUILTIN_FLAG_LOCAL_CMD, cancellable, NULL, error)) goto out; if (argc < 1) { rpmostree_usage_error (context, "NAME must be specified", error); goto out; } name = argv[1]; if (!roc_context_init (rocctx, error)) goto out; target_current_root = glnx_readlinkat_malloc (rocctx->roots_dfd, name, cancellable, error); if (!target_current_root) { g_prefix_error (error, "Reading app link %s: ", name); goto out; } if (!parse_app_version (target_current_root, ¤t_version, error)) goto out; { g_autoptr(GVariantDict) metadata_dict = NULL; g_autoptr(GVariant) spec_v = NULL; g_autoptr(GVariant) previous_sha512_v = NULL; if (!ostree_repo_resolve_rev (rocctx->repo, name, FALSE, &commit_checksum, error)) goto out; if (!ostree_repo_load_variant (rocctx->repo, OSTREE_OBJECT_TYPE_COMMIT, commit_checksum, &commit, error)) goto out; metadata = g_variant_get_child_value (commit, 0); metadata_dict = g_variant_dict_new (metadata); spec_v = _rpmostree_vardict_lookup_value_required (metadata_dict, "rpmostree.spec", (GVariantType*)"a{sv}", error); if (!spec_v) goto out; treespec = rpmostree_treespec_new (spec_v); previous_sha512_v = _rpmostree_vardict_lookup_value_required (metadata_dict, "rpmostree.state-sha512", (GVariantType*)"s", error); if (!previous_sha512_v) goto out; previous_state_sha512 = g_variant_dup_string (previous_sha512_v, NULL); } new_version = current_version == 0 ? 1 : 0; if (new_version == 0) target_new_root = glnx_strjoina (name, ".0"); else target_new_root = glnx_strjoina (name, ".1"); if (!roc_context_prepare_for_root (rocctx, name, treespec, cancellable, error)) goto out; /* --- Downloading metadata --- */ if (!rpmostree_context_download_metadata (rocctx->ctx, cancellable, error)) goto out; /* --- Resolving dependencies --- */ if (!rpmostree_context_prepare_install (rocctx->ctx, &install, cancellable, error)) goto out; { g_autofree char *new_state_sha512 = rpmostree_context_get_state_sha512 (rocctx->ctx); if (strcmp (new_state_sha512, previous_state_sha512) == 0) { g_print ("No changes in inputs to %s (%s)\n", name, commit_checksum); exit_status = EXIT_SUCCESS; goto out; } } /* --- Download and import as necessary --- */ if (!rpmostree_context_download_import (rocctx->ctx, install, cancellable, error)) goto out; { glnx_fd_close int tmpdir_dfd = -1; if (!glnx_opendirat (rocctx->userroot_dfd, "tmp", TRUE, &tmpdir_dfd, error)) goto out; if (!rpmostree_context_assemble_commit (rocctx->ctx, tmpdir_dfd, name, install, &new_commit_checksum, cancellable, error)) goto out; } g_print ("Checking out %s @ %s...\n", name, new_commit_checksum); { OstreeRepoCheckoutOptions opts = { OSTREE_REPO_CHECKOUT_MODE_USER, OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES, }; /* For now... to be crash safe we'd need to duplicate some of the * boot-uuid/fsync gating at a higher level. */ opts.disable_fsync = TRUE; if (!ostree_repo_checkout_tree_at (rocctx->repo, &opts, rocctx->roots_dfd, target_new_root, new_commit_checksum, cancellable, error)) goto out; } g_print ("Checking out %s @ %s...done\n", name, new_commit_checksum); if (!symlink_at_replace (target_new_root, rocctx->roots_dfd, name, cancellable, error)) goto out; g_print ("Creating current symlink...done\n"); exit_status = EXIT_SUCCESS; out: return exit_status; }
int rpmostree_builtin_initramfs (int argc, char **argv, RpmOstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = g_option_context_new ("- Enable or disable local initramfs regeneration"); _cleanup_peer_ GPid peer_pid = 0; glnx_unref_object RPMOSTreeSysroot *sysroot_proxy = NULL; if (!rpmostree_option_context_parse (context, option_entries, &argc, &argv, invocation, cancellable, NULL, NULL, &sysroot_proxy, &peer_pid, error)) return EXIT_FAILURE; glnx_unref_object RPMOSTreeOS *os_proxy = NULL; if (!rpmostree_load_os_proxy (sysroot_proxy, opt_osname, cancellable, &os_proxy, error)) return EXIT_FAILURE; if (!(opt_enable || opt_disable)) { GVariantIter iter; g_autoptr(GVariant) deployments = rpmostree_sysroot_dup_deployments (sysroot_proxy); if (opt_reboot) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "--reboot must be used with --enable or --disable"); return EXIT_FAILURE; } g_variant_iter_init (&iter, deployments); while (TRUE) { gboolean cur_regenerate; g_autoptr(GVariant) child = g_variant_iter_next_value (&iter); g_autoptr(GVariantDict) dict = NULL; g_autofree char **initramfs_args = NULL; gboolean is_booted; if (child == NULL) break; dict = g_variant_dict_new (child); if (!g_variant_dict_lookup (dict, "booted", "b", &is_booted)) continue; if (!is_booted) continue; if (!g_variant_dict_lookup (dict, "regenerate-initramfs", "b", &cur_regenerate)) cur_regenerate = FALSE; if (cur_regenerate) { g_variant_dict_lookup (dict, "initramfs-args", "^a&s", &initramfs_args); } g_print ("Initramfs regeneration: %s\n", cur_regenerate ? "enabled" : "disabled"); if (initramfs_args) { g_print ("Initramfs args: "); for (char **iter = initramfs_args; iter && *iter; iter++) g_print ("%s ", *iter); g_print ("\n"); } } } else if (opt_enable && opt_disable) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Cannot simultaenously specify --enable and --disable"); return EXIT_FAILURE; } else { char *empty_strv[] = {NULL}; if (opt_disable && opt_add_arg) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Cannot simultaenously specify --disable and --arg"); return EXIT_FAILURE; } if (!opt_add_arg) opt_add_arg = empty_strv; g_autofree char *transaction_address = NULL; if (!rpmostree_os_call_set_initramfs_state_sync (os_proxy, opt_enable, (const char *const*)opt_add_arg, get_args_variant (), &transaction_address, cancellable, error)) return EXIT_FAILURE; if (!rpmostree_transaction_get_response_sync (sysroot_proxy, transaction_address, cancellable, error)) return EXIT_FAILURE; g_print ("Initramfs regeneration is now: %s\n", opt_enable ? "enabled" : "disabled"); } return EXIT_SUCCESS; }
int rpmostree_builtin_status (int argc, char **argv, GCancellable *cancellable, GError **error) { int exit_status = EXIT_FAILURE; GOptionContext *context = g_option_context_new ("- Get the version of the booted system"); glnx_unref_object RPMOSTreeOS *os_proxy = NULL; glnx_unref_object RPMOSTreeSysroot *sysroot_proxy = NULL; g_autoptr(GVariant) booted_deployment = NULL; g_autoptr(GVariant) deployments = NULL; g_autoptr(GVariant) booted_signatures = NULL; g_autoptr(GPtrArray) deployment_dicts = NULL; GVariantIter iter; GVariant *child; g_autofree gchar *booted_id = NULL; const guint CSUM_DISP_LEN = 10; /* number of checksum characters to display */ guint i, n; guint max_timestamp_len = 19; /* length of timestamp "YYYY-MM-DD HH:MM:SS" */ guint max_id_len = CSUM_DISP_LEN; /* length of checksum ID */ guint max_osname_len = 0; /* maximum length of osname - determined in code */ guint max_refspec_len = 0; /* maximum length of refspec - determined in code */ guint max_version_len = 0; /* maximum length of version - determined in code */ guint buffer = 5; /* minimum space between end of one entry and new column */ if (!rpmostree_option_context_parse (context, option_entries, &argc, &argv, RPM_OSTREE_BUILTIN_FLAG_NONE, cancellable, &sysroot_proxy, error)) goto out; if (!rpmostree_load_os_proxy (sysroot_proxy, NULL, cancellable, &os_proxy, error)) goto out; booted_deployment = rpmostree_os_dup_booted_deployment (os_proxy); if (booted_deployment) { GVariantDict dict; g_variant_dict_init (&dict, booted_deployment); g_variant_dict_lookup (&dict, "id", "s", &booted_id); booted_signatures = g_variant_dict_lookup_value (&dict, "signatures", G_VARIANT_TYPE ("av")); g_variant_dict_clear (&dict); } deployment_dicts = g_ptr_array_new_with_free_func ((GDestroyNotify) g_variant_dict_unref); deployments = rpmostree_sysroot_dup_deployments (sysroot_proxy); g_variant_iter_init (&iter, deployments); while ((child = g_variant_iter_next_value (&iter)) != NULL) { GVariantDict *dict = g_variant_dict_new (child); /* Takes ownership of the dictionary */ g_ptr_array_add (deployment_dicts, dict); /* find lengths for use in column output */ if (!opt_pretty) { gchar *origin_refspec = NULL; /* borrowed */ gchar *os_name = NULL; /* borrowed */ gchar *version_string = NULL; /* borrowed */ /* osname should always be present. */ if (g_variant_dict_lookup (dict, "osname", "&s", &os_name)) max_osname_len = MAX (max_osname_len, strlen (os_name)); else { const char *id = NULL; g_variant_dict_lookup (dict, "id", "&s", &id); g_critical ("Deployment '%s' missing osname", id != NULL ? id : "?"); } if (g_variant_dict_lookup (dict, "version", "&s", &version_string)) max_version_len = MAX (max_version_len, strlen (version_string)); if (g_variant_dict_lookup (dict, "origin", "&s", &origin_refspec)) max_refspec_len = MAX (max_refspec_len, strlen (origin_refspec)); } g_variant_unref (child); } if (!opt_pretty) { /* print column headers */ g_print (" %-*s", max_timestamp_len+buffer,"TIMESTAMP (UTC)"); if (max_version_len) g_print ("%-*s", max_version_len+buffer,"VERSION"); g_print ("%-*s%-*s%-*s\n", max_id_len+buffer, "ID", max_osname_len+buffer, "OSNAME", max_refspec_len+buffer, "REFSPEC"); } /* header for "pretty" row output */ else printchar ("=", 60); n = deployment_dicts->len; /* print entries for each deployment */ for (i = 0; i < n; i++) { GVariantDict *dict; g_autoptr(GDateTime) timestamp = NULL; g_autofree char *timestamp_string = NULL; g_autofree gchar *truncated_csum = NULL; g_autoptr(GVariant) signatures = NULL; gchar *id = NULL; /* borrowed */ gchar *origin_refspec = NULL; /* borrowed */ gchar *os_name = NULL; /* borrowed */ gchar *version_string = NULL; /* borrowed */ gchar *checksum = NULL; /* borrowed */ guint64 t = 0; gint serial; gboolean is_booted = FALSE; dict = g_ptr_array_index (deployment_dicts, i); g_variant_dict_lookup (dict, "id", "&s", &id); g_variant_dict_lookup (dict, "osname", "&s", &os_name); g_variant_dict_lookup (dict, "serial", "i", &serial); g_variant_dict_lookup (dict, "checksum", "s", &checksum); g_variant_dict_lookup (dict, "version", "s", &version_string); g_variant_dict_lookup (dict, "timestamp", "t", &t); g_variant_dict_lookup (dict, "origin", "s", &origin_refspec); signatures = g_variant_dict_lookup_value (dict, "signatures", G_VARIANT_TYPE ("av")); is_booted = g_strcmp0 (booted_id, id) == 0; timestamp = g_date_time_new_from_unix_utc (t); if (timestamp != NULL) timestamp_string = g_date_time_format (timestamp, "%Y-%m-%d %T"); else timestamp_string = g_strdup_printf ("(invalid)"); /* truncate checksum */ truncated_csum = g_strndup (checksum, CSUM_DISP_LEN); /* print deployment info column */ if (!opt_pretty) { g_print ("%c %-*s", is_booted ? '*' : ' ', max_timestamp_len+buffer, timestamp_string); if (max_version_len) g_print ("%-*s", max_version_len+buffer, version_string ? version_string : ""); g_print ("%-*s%-*s%-*s\n", max_id_len+buffer, truncated_csum, max_osname_len+buffer, os_name, max_refspec_len+buffer, origin_refspec); } /* print "pretty" row info */ else { guint tab = 11; char *title = NULL; if (i==0) title = "DEFAULT ON BOOT"; else if (is_booted || n <= 2) title = "NON-DEFAULT ROLLBACK TARGET"; else title = "NON-DEFAULT DEPLOYMENT"; g_print (" %c %s\n", is_booted ? '*' : ' ', title); printchar ("-", 40); if (version_string) g_print (" %-*s%-*s\n", tab, "version", tab, version_string); g_print (" %-*s%-*s\n %-*s%-*s.%d\n %-*s%-*s\n %-*s%-*s\n", tab, "timestamp", tab, timestamp_string, tab, "id", tab, checksum, serial, tab, "osname", tab, os_name, tab, "refspec", tab, origin_refspec); if (signatures != NULL) rpmostree_print_signatures (signatures, " GPG: "); printchar ("=", 60); } } /* Print any signatures for the booted deployment, but only in NON-pretty * mode. We save this for the end to preserve the tabular formatting for * deployments. */ if (!opt_pretty && booted_signatures != NULL) { guint n_sigs = g_variant_n_children (booted_signatures); if (n_sigs > 0) { /* XXX If we ever add internationalization, use ngettext() here. */ g_print ("\nGPG: Found %u signature%s on the booted deployment (*):\n", n_sigs, n_sigs == 1 ? "" : "s"); rpmostree_print_signatures (booted_signatures, " "); } } exit_status = EXIT_SUCCESS; out: /* Does nothing if using the message bus. */ rpmostree_cleanup_peer (); return exit_status; }