static void sysroot_output_cb (RpmOstreeOutputType type, void *data, void *opaque) { RpmostreedSysroot *self = RPMOSTREED_SYSROOT (opaque); glnx_unref_object RpmostreedTransaction *transaction = NULL; transaction = rpmostreed_transaction_monitor_ref_active_transaction (self->transaction_monitor); if (!transaction) { rpmostree_output_default_handler (type, data, opaque); return; } switch (type) { case RPMOSTREE_OUTPUT_TASK_BEGIN: rpmostree_transaction_emit_task_begin (RPMOSTREE_TRANSACTION (transaction), ((RpmOstreeOutputTaskBegin*)data)->text); break; case RPMOSTREE_OUTPUT_TASK_END: rpmostree_transaction_emit_task_end (RPMOSTREE_TRANSACTION (transaction), ((RpmOstreeOutputTaskEnd*)data)->text); break; case RPMOSTREE_OUTPUT_PERCENT_PROGRESS: rpmostree_transaction_emit_percent_progress (RPMOSTREE_TRANSACTION (transaction), ((RpmOstreeOutputPercentProgress*)data)->text, ((RpmOstreeOutputPercentProgress*)data)->percentage); break; case RPMOSTREE_OUTPUT_PERCENT_PROGRESS_END: rpmostree_transaction_emit_progress_end (RPMOSTREE_TRANSACTION (transaction)); break; } }
static gboolean sysroot_stdout_ready_cb (GPollableInputStream *pollable_stream, StdoutClosure *closure) { glnx_unref_object RpmostreedSysroot *sysroot = NULL; glnx_unref_object RpmostreedTransaction *transaction = NULL; GMemoryInputStream *memory_stream; GBufferedInputStream *buffered_stream; char buffer[1024]; gconstpointer stream_buffer; gsize stream_buffer_size; gsize total_bytes_read = 0; gboolean have_line = FALSE; GError *local_error = NULL; sysroot = g_weak_ref_get (&closure->sysroot); if (sysroot != NULL) transaction = rpmostreed_transaction_monitor_ref_active_transaction (sysroot->transaction_monitor); /* XXX Would very much like g_buffered_input_stream_fill_nonblocking(). * Much of this function is a clumsy and inefficient attempt to * achieve the same thing. * * See: https://bugzilla.gnome.org/726797 */ buffered_stream = G_BUFFERED_INPUT_STREAM (closure->data_stream); memory_stream = (GMemoryInputStream *) g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (buffered_stream)); while (local_error == NULL) { gssize n_read; n_read = g_pollable_input_stream_read_nonblocking (pollable_stream, buffer, sizeof (buffer), NULL, &local_error); if (n_read > 0) { /* XXX Gotta use GBytes so the data gets copied. */ g_autoptr(GBytes) bytes = g_bytes_new (buffer, n_read); g_memory_input_stream_add_bytes (memory_stream, bytes); total_bytes_read += n_read; } } if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) goto out; g_clear_error (&local_error); read_another_line: /* Fill the buffered stream with the data we just put in the * memory stream, then peek at the buffer to see if it's safe * to call g_data_input_stream_read_line() without blocking. * * XXX Oye, there's gotta be an easier way to do this... */ /* This should never fail since it's just reading from memory. */ g_buffered_input_stream_fill (buffered_stream, total_bytes_read, NULL, NULL); stream_buffer = g_buffered_input_stream_peek_buffer (buffered_stream, &stream_buffer_size); have_line = (memchr (stream_buffer, '\n', stream_buffer_size) != NULL); if (have_line) { g_autofree char *line = NULL; gsize length; line = g_data_input_stream_read_line (closure->data_stream, &length, NULL, &local_error); if (local_error != NULL) goto out; /* If there's an active transaction, forward the line to the * transaction's owner through the "Message" signal. Otherwise * dump it to the non-redirected standard output stream. */ if (transaction != NULL) { rpmostree_transaction_emit_message (RPMOSTREE_TRANSACTION (transaction), line); } else { /* This is essentially puts(), don't care about errors. */ g_output_stream_write_all (closure->real_stdout, line, length, NULL, NULL, NULL); g_output_stream_write_all (closure->real_stdout, "\n", 1, NULL, NULL, NULL); } goto read_another_line; } out: if (local_error != NULL) { g_warning ("Failed to read stdout pipe: %s", local_error->message); g_clear_error (&local_error); } return G_SOURCE_CONTINUE; }
static gboolean package_diff_transaction_execute (RpmostreedTransaction *transaction, GCancellable *cancellable, GError **error) { PackageDiffTransaction *self; OstreeSysroot *sysroot; glnx_unref_object OstreeSysrootUpgrader *upgrader = NULL; glnx_unref_object OstreeAsyncProgress *progress = NULL; glnx_unref_object OstreeRepo *repo = NULL; g_autoptr(GKeyFile) origin = NULL; g_autofree gchar *origin_description = NULL; OstreeSysrootUpgraderPullFlags upgrader_flags = 0; gboolean upgrading = FALSE; gboolean changed = FALSE; gboolean ret = FALSE; self = (PackageDiffTransaction *) transaction; sysroot = rpmostreed_transaction_get_sysroot (transaction); upgrader = ostree_sysroot_upgrader_new_for_os (sysroot, self->osname, cancellable, error); if (upgrader == NULL) goto out; if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) goto out; origin = ostree_sysroot_upgrader_dup_origin (upgrader); /* Determine if we're upgrading before we set the refspec. */ upgrading = (self->refspec == NULL && self->revision == NULL); if (self->refspec != NULL) { if (!change_upgrader_refspec (sysroot, upgrader, self->refspec, cancellable, NULL, NULL, error)) goto out; } else if (origin != NULL) { self->refspec = g_key_file_get_string (origin, "origin", "refspec", NULL); if (self->refspec == NULL) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Could not find refspec for booted deployment"); } } else { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Booted deployment has no origin"); goto out; } progress = ostree_async_progress_new (); rpmostreed_transaction_connect_download_progress (transaction, progress); rpmostreed_transaction_connect_signature_progress (transaction, repo); if (self->revision != NULL) { g_autofree char *checksum = NULL; g_autofree char *version = NULL; upgrader_flags |= OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER; if (!rpmostreed_parse_revision (self->revision, &checksum, &version, error)) goto out; if (version != NULL) { rpmostreed_transaction_emit_message_printf (transaction, "Resolving version '%s'", version); if (!rpmostreed_repo_lookup_version (repo, self->refspec, version, progress, cancellable, &checksum, error)) goto out; } g_key_file_set_string (origin, "origin", "override-commit", checksum); if (!ostree_sysroot_upgrader_set_origin (upgrader, origin, cancellable, error)) goto out; } else if (upgrading) { if (g_key_file_remove_key (origin, "origin", "override-commit", NULL)) { if (!ostree_sysroot_upgrader_set_origin (upgrader, origin, cancellable, error)) goto out; } } origin_description = ostree_sysroot_upgrader_get_origin_description (upgrader); if (origin_description != NULL) rpmostreed_transaction_emit_message_printf (transaction, "Updating from: %s", origin_description); if (!ostree_sysroot_upgrader_pull_one_dir (upgrader, "/usr/share/rpm", 0, upgrader_flags, progress, &changed, cancellable, error)) goto out; rpmostree_transaction_emit_progress_end (RPMOSTREE_TRANSACTION (transaction)); if (!changed) { if (upgrading) rpmostreed_transaction_emit_message_printf (transaction, "No upgrade available."); else rpmostreed_transaction_emit_message_printf (transaction, "No change."); } ret = TRUE; out: return ret; }