static void g_unix_input_stream_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GUnixInputStream *unix_stream; unix_stream = G_UNIX_INPUT_STREAM (object); switch (prop_id) { case PROP_FD: unix_stream->priv->fd = g_value_get_int (value); if (lseek (unix_stream->priv->fd, 0, SEEK_CUR) == -1 && errno == ESPIPE) unix_stream->priv->is_pipe_or_socket = TRUE; else unix_stream->priv->is_pipe_or_socket = FALSE; break; case PROP_CLOSE_FD: unix_stream->priv->close_fd = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean g_unix_input_stream_close (GInputStream *stream, GCancellable *cancellable, GError **error) { GUnixInputStream *unix_stream; int res; unix_stream = G_UNIX_INPUT_STREAM (stream); if (!unix_stream->priv->close_fd) return TRUE; /* This might block during the close. Doesn't seem to be a way to avoid it though. */ res = close (unix_stream->priv->fd); if (res == -1) { int errsv = errno; g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), _("Error closing file descriptor: %s"), g_strerror (errsv)); } return res != -1; }
static gboolean do_console_raw_local_read(GObject *stream, gpointer opaque) { GUnixInputStream *localStdin = G_UNIX_INPUT_STREAM(stream); GVirSandboxConsoleRaw *console = GVIR_SANDBOX_CONSOLE_RAW(opaque); GVirSandboxConsoleRawPrivate *priv = console->priv; GError *err = NULL; gssize ret = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM(localStdin), priv->localToConsole + priv->localToConsoleOffset, priv->localToConsoleLength - priv->localToConsoleOffset, NULL, &err); if (ret < 0) { g_debug("Error from local read %s", err ? err->message : ""); do_console_raw_close(console, err); g_error_free(err); goto cleanup; } if (ret == 0) priv->localEOF = TRUE; else if (priv->localToConsole[priv->localToConsoleOffset] == CONTROL(gvir_sandbox_console_get_escape(GVIR_SANDBOX_CONSOLE(console)))) { do_console_raw_close(console, err); goto cleanup; } priv->localToConsoleOffset += ret; priv->localStdinSource = NULL; do_console_raw_update_events(console); cleanup: return FALSE; }
static void g_unix_input_stream_read_async (GInputStream *stream, void *buffer, gsize count, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GSource *source; GUnixInputStream *unix_stream; ReadAsyncData *data; unix_stream = G_UNIX_INPUT_STREAM (stream); data = g_new0 (ReadAsyncData, 1); data->count = count; data->buffer = buffer; data->callback = callback; data->user_data = user_data; data->cancellable = cancellable; data->stream = unix_stream; source = _g_fd_source_new (unix_stream->priv->fd, G_IO_IN, cancellable); g_source_set_name (source, "GUnixInputStream"); g_source_set_callback (source, (GSourceFunc)read_async_cb, data, g_free); g_source_attach (source, g_main_context_get_thread_default ()); g_source_unref (source); }
static gssize g_unix_input_stream_read (GInputStream *stream, void *buffer, gsize count, GCancellable *cancellable, GError **error) { GUnixInputStream *unix_stream; gssize res; GPollFD poll_fds[2]; int poll_ret; unix_stream = G_UNIX_INPUT_STREAM (stream); if (g_cancellable_make_pollfd (cancellable, &poll_fds[1])) { poll_fds[0].fd = unix_stream->priv->fd; poll_fds[0].events = G_IO_IN; do poll_ret = g_poll (poll_fds, 2, -1); while (poll_ret == -1 && errno == EINTR); g_cancellable_release_fd (cancellable); if (poll_ret == -1) { int errsv = errno; g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), _("Error reading from unix: %s"), g_strerror (errsv)); return -1; } } while (1) { if (g_cancellable_set_error_if_cancelled (cancellable, error)) return -1; res = read (unix_stream->priv->fd, buffer, count); if (res == -1) { int errsv = errno; if (errsv == EINTR) continue; g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), _("Error reading from unix: %s"), g_strerror (errsv)); } break; } return res; }
static gboolean close_async_cb (CloseAsyncData *data) { GUnixInputStream *unix_stream; GSimpleAsyncResult *simple; GError *error = NULL; gboolean result; int res; unix_stream = G_UNIX_INPUT_STREAM (data->stream); if (!unix_stream->priv->close_fd) { result = TRUE; goto out; } while (1) { res = close (unix_stream->priv->fd); if (res == -1) { int errsv = errno; g_set_error (&error, G_IO_ERROR, g_io_error_from_errno (errsv), _("Error closing unix: %s"), g_strerror (errsv)); } break; } result = res != -1; out: simple = g_simple_async_result_new (G_OBJECT (data->stream), data->callback, data->user_data, g_unix_input_stream_close_async); if (!result) { g_simple_async_result_set_from_error (simple, error); g_error_free (error); } /* Complete immediately, not in idle, since we're already in a mainloop callout */ g_simple_async_result_complete (simple); g_object_unref (simple); return FALSE; }
static GSource * g_unix_input_stream_pollable_create_source (GPollableInputStream *stream, GCancellable *cancellable) { GUnixInputStream *unix_stream = G_UNIX_INPUT_STREAM (stream); GSource *inner_source, *pollable_source; pollable_source = g_pollable_source_new (G_OBJECT (stream)); inner_source = _g_fd_source_new (unix_stream->priv->fd, G_IO_IN, cancellable); g_source_set_dummy_callback (inner_source); g_source_add_child_source (pollable_source, inner_source); g_source_unref (inner_source); return pollable_source; }
static gboolean g_unix_input_stream_pollable_is_readable (GPollableInputStream *stream) { GUnixInputStream *unix_stream = G_UNIX_INPUT_STREAM (stream); GPollFD poll_fd; gint result; poll_fd.fd = unix_stream->priv->fd; poll_fd.events = G_IO_IN; do result = g_poll (&poll_fd, 1, 0); while (result == -1 && errno == EINTR); return poll_fd.revents != 0; }
gboolean gvir_sandbox_console_attach_stdio(GVirSandboxConsole *console_, GError **error) { GInputStream *localStdin = g_unix_input_stream_new(STDIN_FILENO, FALSE); GOutputStream *localStdout = g_unix_output_stream_new(STDOUT_FILENO, FALSE); GOutputStream *localStderr = g_unix_output_stream_new(STDERR_FILENO, FALSE); gboolean ret; ret = gvir_sandbox_console_attach(console_, G_UNIX_INPUT_STREAM(localStdin), G_UNIX_OUTPUT_STREAM(localStdout), G_UNIX_OUTPUT_STREAM(localStderr), error); g_object_unref(localStdin); g_object_unref(localStdout); g_object_unref(localStderr); return ret; }
static gssize g_unix_input_stream_read_finish (GInputStream *stream, GAsyncResult *result, GError **error) { GUnixInputStream *unix_stream = G_UNIX_INPUT_STREAM (stream); GSimpleAsyncResult *simple; gssize nread; if (!unix_stream->priv->is_pipe_or_socket) { return G_INPUT_STREAM_CLASS (g_unix_input_stream_parent_class)-> read_finish (stream, result, error); } simple = G_SIMPLE_ASYNC_RESULT (result); g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_unix_input_stream_read_async); nread = g_simple_async_result_get_op_res_gssize (simple); return nread; }
static void g_unix_input_stream_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GUnixInputStream *unix_stream; unix_stream = G_UNIX_INPUT_STREAM (object); switch (prop_id) { case PROP_FD: g_value_set_int (value, unix_stream->priv->fd); break; case PROP_CLOSE_FD: g_value_set_boolean (value, unix_stream->priv->close_fd); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } }
static gboolean g_unix_input_stream_pollable_can_poll (GPollableInputStream *stream) { return G_UNIX_INPUT_STREAM (stream)->priv->is_pipe_or_socket; }
static gssize g_unix_input_stream_read (GInputStream *stream, void *buffer, gsize count, GCancellable *cancellable, GError **error) { GUnixInputStream *unix_stream; gssize res = -1; GPollFD poll_fds[2]; int nfds; int poll_ret; unix_stream = G_UNIX_INPUT_STREAM (stream); poll_fds[0].fd = unix_stream->priv->fd; poll_fds[0].events = G_IO_IN; if (unix_stream->priv->is_pipe_or_socket && g_cancellable_make_pollfd (cancellable, &poll_fds[1])) nfds = 2; else nfds = 1; while (1) { poll_fds[0].revents = poll_fds[1].revents = 0; do poll_ret = g_poll (poll_fds, nfds, -1); while (poll_ret == -1 && errno == EINTR); if (poll_ret == -1) { int errsv = errno; g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), _("Error reading from file descriptor: %s"), g_strerror (errsv)); break; } if (g_cancellable_set_error_if_cancelled (cancellable, error)) break; if (!poll_fds[0].revents) continue; res = read (unix_stream->priv->fd, buffer, count); if (res == -1) { int errsv = errno; if (errsv == EINTR || errsv == EAGAIN) continue; g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), _("Error reading from file descriptor: %s"), g_strerror (errsv)); } break; } if (nfds == 2) g_cancellable_release_fd (cancellable); return res; }
static gboolean gvir_sandbox_console_open_remote(GVirSandboxConsoleRaw *console, GError **error) { GVirSandboxConsoleRawPrivate *priv = console->priv; GVirConnection *conn = NULL; GVirDomain *dom = NULL; gchar *devname = NULL; gboolean ret = FALSE; GVirConfigDomain *conf = NULL; GList *devices = NULL, *tmp; g_object_get(console, "connection", &conn, "domain", &dom, "devname", &devname, NULL); if (!gvir_sandbox_console_get_direct(GVIR_SANDBOX_CONSOLE(console))) { priv->console = gvir_connection_get_stream(conn, 0); if (!gvir_domain_open_console(dom, priv->console, devname, 0, error)) { g_object_unref(priv->console); priv->console = NULL; goto cleanup; } } else { const gchar *pty = NULL; if (!(conf = gvir_domain_get_config(dom, 0, error))) goto cleanup; if (!(devices = gvir_config_domain_get_devices(conf))) { g_set_error(error, GVIR_SANDBOX_CONSOLE_RAW_ERROR, 0, "%s", _("No devices found for domain")); goto cleanup; } tmp = devices; while (tmp && !pty) { GVirConfigDomainDevice *dev = tmp->data; const gchar *alias = gvir_config_domain_device_get_alias(dev); if (alias && g_str_equal(alias, devname) && GVIR_CONFIG_IS_DOMAIN_CHARDEV(dev)) { GVirConfigDomainChardev *cdev = GVIR_CONFIG_DOMAIN_CHARDEV(dev); GVirConfigDomainChardevSource *csrc = gvir_config_domain_chardev_get_source(cdev); if (GVIR_CONFIG_IS_DOMAIN_CHARDEV_SOURCE_PTY(csrc)) { GVirConfigDomainChardevSourcePty *csrcpty = GVIR_CONFIG_DOMAIN_CHARDEV_SOURCE_PTY(csrc); pty = gvir_config_domain_chardev_source_pty_get_path(csrcpty); break; } } tmp = tmp->next; } if (!pty) { g_set_error(error, GVIR_SANDBOX_CONSOLE_RAW_ERROR, 0, _("No device %s found for domain"), devname); goto cleanup; } if ((priv->consolePty = open(pty, O_NOCTTY|O_RDWR)) < 0) { g_set_error(error, GVIR_SANDBOX_CONSOLE_RAW_ERROR, 0, _("Unable to open console %s"), pty); goto cleanup; } priv->consoleInput = G_UNIX_INPUT_STREAM(g_unix_input_stream_new(priv->consolePty, FALSE)); priv->consoleOutput = G_UNIX_OUTPUT_STREAM(g_unix_output_stream_new(priv->consolePty, FALSE)); } ret = TRUE; cleanup: if (conf) g_object_unref(conf); if (conn) g_object_unref(conn); if (dom) g_object_unref(dom); g_free(devname); return ret; }