static gboolean dispatch_input (gint fd, GIOCondition cond, gpointer user_data) { CockpitPipe *self = (CockpitPipe *)user_data; gssize ret = 0; gsize len; gboolean eof; g_return_val_if_fail (self->priv->in_source, FALSE); len = self->priv->in_buffer->len; /* * Enable clean shutdown by not reading when we just get * G_IO_HUP. Note that when we get G_IO_ERR we do want to read * just so we can get the appropriate detailed error message. */ if (cond != G_IO_HUP) { g_debug ("%s: reading input", self->priv->name); g_byte_array_set_size (self->priv->in_buffer, len + 1024); ret = read (self->priv->in_fd, self->priv->in_buffer->data + len, 1024); if (ret < 0) { g_byte_array_set_size (self->priv->in_buffer, len); if (errno != EAGAIN && errno != EINTR) { set_problem_from_errno (self, "couldn't read", errno); close_immediately (self, NULL); /* problem already set */ return FALSE; } return TRUE; } } g_byte_array_set_size (self->priv->in_buffer, len + ret); if (ret == 0) { g_debug ("%s: end of input", self->priv->name); stop_input (self); } g_object_ref (self); eof = (self->priv->in_source == NULL); g_signal_emit (self, cockpit_pipe_sig_read, 0, self->priv->in_buffer, eof); if (eof) close_maybe (self); g_object_unref (self); return TRUE; }
static void close_immediately (CockpitPipe *self, const gchar *problem) { if (self->priv->closed) return; if (problem) { g_free (self->priv->problem); self->priv->problem = g_strdup (problem); } self->priv->closed = TRUE; g_debug ("%s: closing pipe%s%s", self->priv->name, self->priv->problem ? ": " : "", self->priv->problem ? self->priv->problem : ""); if (self->priv->in_source) stop_input (self); if (self->priv->out_source) stop_output (self); if (self->priv->err_source) stop_error (self); if (self->priv->in_fd != -1) { close (self->priv->in_fd); self->priv->in_fd = -1; } if (self->priv->out_fd != -1) { close (self->priv->out_fd); self->priv->out_fd = -1; } if (self->priv->err_fd != -1) { close (self->priv->err_fd); self->priv->err_fd = -1; } if (problem && self->priv->pid && !self->priv->exited) { g_debug ("%s: killing child: %d", self->priv->name, (int)self->priv->pid); kill (self->priv->pid, SIGTERM); } /* If not tracking a pid, then we are now closed. */ if (!self->priv->child) { g_debug ("%s: no child process to wait for: closed", self->priv->name); g_signal_emit (self, cockpit_pipe_sig_close, 0, self->priv->problem); } }
static void close_immediately (CockpitStream *self, const gchar *problem) { GError *error = NULL; GIOStream *io; if (self->priv->closed) return; if (problem) { g_free (self->priv->problem); self->priv->problem = g_strdup (problem); } if (self->priv->connecting) { cockpit_connectable_unref (self->priv->connecting); self->priv->connecting = NULL; } self->priv->closed = TRUE; g_debug ("%s: closing stream%s%s", self->priv->name, self->priv->problem ? ": " : "", self->priv->problem ? self->priv->problem : ""); if (self->priv->in_source) stop_input (self); if (self->priv->out_source) stop_output (self); if (self->priv->io) { io = self->priv->io; self->priv->io = NULL; if (self->priv->sig_accept_cert) { g_signal_handler_disconnect (io, self->priv->sig_accept_cert); self->priv->sig_accept_cert = 0; } g_io_stream_close (io, NULL, &error); if (error) { g_message ("%s: close failed: %s", self->priv->name, error->message); g_clear_error (&error); } g_object_unref (io); } g_debug ("%s: closed", self->priv->name); g_signal_emit (self, cockpit_stream_sig_close, 0, self->priv->problem); }
static void close_output (CockpitPipe *self) { if (self->priv->out_fd != -1) { g_debug ("%s: end of output", self->priv->name); /* And if closing, then we need to shutdown the output fd */ if (shutdown (self->priv->out_fd, SHUT_WR) < 0) { if (errno == ENOTSOCK) { g_debug ("%s: not a socket, closing entirely", self->priv->name); close (self->priv->out_fd); if (self->priv->in_fd == self->priv->out_fd) { self->priv->in_fd = -1; if (self->priv->in_source) { g_debug ("%s: and closing input because same fd", self->priv->name); stop_input (self); } } self->priv->out_fd = -1; } else { g_warning ("%s: couldn't shutdown fd: %s", self->priv->name, g_strerror (errno)); close_immediately (self, "internal-error"); } } } close_maybe (self); }
int main(int argc, char *argv[]) { int rc; gamut_opts opts; signal(SIGPIPE, SIG_IGN); memset(&opts, 0, sizeof(opts)); /* Use line buffering for stdout */ setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ); rc = parse_opts(argc, argv, &opts); if(rc < 0) { s_log(G_EMERG, "Error parsing options.\n"); exit(EXIT_FAILURE); } else if(!rc) { usage(argv[0]); exit(EXIT_FAILURE); } /* * In this order, perform these steps (if necessary) * 1. Redirect to a log file * 2. Restore benchmark data from a file * 3. Run the benchmarks * 4. Save the new benchmark data * 5. Quit after benchmarks * 6. Run calibration (if no benchmark data) * 7. Run a trace file and exit * 8. Accept commands from stdin */ /* * 1. Redirect to a log file */ if(redirect_stdout) { redirect_output(); } /* * 2. Restore benchmark data from a file */ if(load_benchmarks) { s_log(G_NOTICE, "Loading benchmark data ... "); load_benchmark_data(); s_log(G_NOTICE, "done.\n"); } /* * 3. Run the benchmarks */ if(run_benchmarks) { s_log(G_NOTICE, "Running %u calibration trials.\n", DEF_BMARK_TRIALS); benchmark_delays(DEF_BMARK_TRIALS); } /* * 4. Save the new benchmark data */ if(save_benchmarks) { s_log(G_NOTICE, "Saving benchmark data ... "); save_benchmark_data(); s_log(G_NOTICE, "done.\n"); /* * 5. Quit after benchmarks */ if(quit_benchmarks) exit(EXIT_SUCCESS); } /* * 6. Run calibration (if no benchmark data is available yet) */ if(!load_benchmarks && !run_benchmarks) { s_log(G_NOTICE, "Calibrating node attributes ... "); benchmark_delays(1); s_log(G_NOTICE, "done.\n"); } init_opts(&opts); start_reaper(&opts); start_input(&opts); execute_gamut(&opts); stop_input(&opts); killall_workers(&opts); stop_reaper(&opts); return 0; }
static gboolean dispatch_input (GPollableInputStream *is, gpointer user_data) { CockpitStream *self = (CockpitStream *)user_data; GError *error = NULL; gboolean read = FALSE; gssize ret = 0; gsize len; gboolean eof; for (;;) { g_return_val_if_fail (self->priv->in_source, FALSE); len = self->priv->in_buffer->len; g_byte_array_set_size (self->priv->in_buffer, len + 1024); ret = g_pollable_input_stream_read_nonblocking (is, self->priv->in_buffer->data + len, 1024, NULL, &error); if (ret < 0) { g_byte_array_set_size (self->priv->in_buffer, len); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { g_error_free (error); break; } else { set_problem_from_error (self, "couldn't read", error); g_error_free (error); close_immediately (self, NULL); return FALSE; } } g_byte_array_set_size (self->priv->in_buffer, len + ret); if (ret == 0) { g_debug ("%s: end of input", self->priv->name); stop_input (self); break; } else if (ret > 0) { g_debug ("%s: read %d bytes", self->priv->name, (int)ret); self->priv->received = TRUE; read = TRUE; } } g_object_ref (self); eof = (self->priv->in_source == NULL); if (eof || read) g_signal_emit (self, cockpit_stream_sig_read, 0, self->priv->in_buffer, eof); if (eof) close_maybe (self); g_object_unref (self); return TRUE; }