void *
sol_mainloop_impl_child_watch_add(uint64_t pid, void (*cb)(void *data, uint64_t pid, int status), const void *data)
{
    struct child_wrap_data *wrap_data = malloc(sizeof(*wrap_data));

    SOL_NULL_CHECK(wrap_data, NULL);

    wrap_data->cb = cb;
    wrap_data->data = data;

    return (void *)(long)g_child_watch_add_full(0, pid, on_child, wrap_data, free);
}
Example #2
0
void deja_dup_async_command_run (DejaDupAsyncCommand* self) {
	GPid _tmp7_;
	guint _tmp8_ = 0U;
	GError * _inner_error_ = NULL;
	g_return_if_fail (self != NULL);
	{
		gchar** _tmp0_;
		gint _tmp0__length1;
		gchar** _tmp1_;
		gint _tmp1__length1;
		GPid _tmp2_ = 0;
		gboolean _tmp3_ = FALSE;
		gboolean _tmp4_;
		_tmp0_ = deja_dup_async_command_get_argv (self, &_tmp0__length1);
		_tmp1_ = _tmp0_;
		_tmp1__length1 = _tmp0__length1;
		_tmp3_ = g_spawn_async (NULL, _tmp1_, NULL, ((G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL) | G_SPAWN_DO_NOT_REAP_CHILD) | G_SPAWN_SEARCH_PATH, NULL, NULL, &_tmp2_, &_inner_error_);
		self->priv->pid = _tmp2_;
		_tmp4_ = _tmp3_;
		if (_inner_error_ != NULL) {
			goto __catch0_g_error;
		}
		if (!_tmp4_) {
			g_signal_emit_by_name (self, "done", FALSE);
		}
	}
	goto __finally0;
	__catch0_g_error:
	{
		GError* e = NULL;
		GError* _tmp5_;
		const gchar* _tmp6_;
		e = _inner_error_;
		_inner_error_ = NULL;
		_tmp5_ = e;
		_tmp6_ = _tmp5_->message;
		g_warning ("AsyncCommand.vala:60: %s\n", _tmp6_);
		g_signal_emit_by_name (self, "done", FALSE);
		_g_error_free0 (e);
	}
	__finally0:
	if (_inner_error_ != NULL) {
		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
		g_clear_error (&_inner_error_);
		return;
	}
	_tmp7_ = self->priv->pid;
	_tmp8_ = g_child_watch_add_full (G_PRIORITY_DEFAULT_IDLE, _tmp7_, _deja_dup_async_command_handle_done_gchild_watch_func, g_object_ref (self), g_object_unref);
	self->priv->watch = _tmp8_;
}
Example #3
0
/* Returns pid if succesful, returns -1 if errors happen. */
GPid run_app( const char* cmd, gboolean guarded )
{
    GPid pid = -1;
    wordexp_t we;
    GSpawnFlags flags = guarded ? G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH : G_SPAWN_SEARCH_PATH;

    if( wordexp(cmd, &we, 0) == 0)
    {
        g_spawn_async( NULL, we.we_wordv, NULL, flags, NULL, NULL, &pid, NULL );
        wordfree(&we);
    }

    if(guarded && pid > 0)
    {
        g_child_watch_add_full( G_PRIORITY_DEFAULT_IDLE, pid,
                                (GChildWatchFunc)on_child_exit,
                                g_strdup( cmd ), (GDestroyNotify)g_free );
    }
    return pid;
}
static void
thunar_uca_provider_activated (ThunarUcaProvider *uca_provider,
                               GtkAction         *action)
{
  GtkTreeRowReference *row;
  ThunarUcaContext    *uca_context;
  GtkTreePath         *path;
  GtkTreeIter          iter;
  GtkWidget           *dialog;
  GtkWidget           *window;
  gboolean             succeed;
  GSource             *source;
  GError              *error = NULL;
  GList               *files;
  gchar              **argv;
  gchar               *working_directory = NULL;
  gchar               *filename;
  gchar               *label;
  gchar               *uri;
  gint                 argc;
  gint                 pid;

  g_return_if_fail (THUNAR_UCA_IS_PROVIDER (uca_provider));
  g_return_if_fail (GTK_IS_ACTION (action));

  /* check if the row reference is still valid */
  row = g_object_get_qdata (G_OBJECT (action), thunar_uca_row_quark);
  if (G_UNLIKELY (!gtk_tree_row_reference_valid (row)))
    return;

  /* determine the iterator for the item */
  path = gtk_tree_row_reference_get_path (row);
  gtk_tree_model_get_iter (GTK_TREE_MODEL (uca_provider->model), &iter, path);
  gtk_tree_path_free (path);

  /* determine the files and the window for the action */
  uca_context = g_object_get_qdata (G_OBJECT (action), thunar_uca_context_quark);
  window = thunar_uca_context_get_window (uca_context);
  files = thunar_uca_context_get_files (uca_context);

  /* determine the argc/argv for the item */
  succeed = thunar_uca_model_parse_argv (uca_provider->model, &iter, files, &argc, &argv, &error);
  if (G_LIKELY (succeed))
    {
      /* determine the working from the first file */
      if (G_LIKELY (files != NULL))
        {
          /* determine the filename of the first selected file */
          uri = thunarx_file_info_get_uri (files->data);
          filename = g_filename_from_uri (uri, NULL, NULL);
          if (G_LIKELY (filename != NULL))
            {
              /* if this is a folder action, we just use the filename as working directory */
              if (g_object_get_qdata (G_OBJECT (action), thunar_uca_folder_quark) != NULL)
                {
                  working_directory = filename;
                  filename = NULL;
                }
              else
                {
                  working_directory = g_path_get_dirname (filename);
                }
            }
          g_free (filename);
          g_free (uri);
        }

      /* spawn the command on the window's screen */
      succeed = gdk_spawn_on_screen (gtk_widget_get_screen (GTK_WIDGET (window)), working_directory,
                                     argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
                                     NULL, NULL, &pid, &error);

      /* check if we succeed */
      if (G_LIKELY (succeed))
        {
          /* check if we already have a child watch */
          if (G_UNLIKELY (uca_provider->child_watch_id >= 0))
            {
              /* reset the callback function to g_spawn_close_pid() so the plugin can be
               * safely unloaded and the child will still not become a zombie afterwards.
               */
              source = g_main_context_find_source_by_id (NULL, uca_provider->child_watch_id);
              g_source_set_callback (source, (GSourceFunc) g_spawn_close_pid, NULL, NULL);
            }

          /* schedule the new child watch */
          uca_provider->child_watch_id = g_child_watch_add_full (G_PRIORITY_LOW, pid, thunar_uca_provider_child_watch,
                                                                 uca_provider, thunar_uca_provider_child_watch_destroy);

          /* take over ownership of the working directory as child watch path */
          uca_provider->child_watch_path = working_directory;
          working_directory = NULL;
        }

      /* cleanup */
      g_free (working_directory);
      g_strfreev (argv);
    }

  /* present error message to the user */
  if (G_UNLIKELY (!succeed))
    {
      g_object_get (G_OBJECT (action), "label", &label, NULL);
      dialog = gtk_message_dialog_new ((GtkWindow *) window,
                                       GTK_DIALOG_DESTROY_WITH_PARENT
                                       | GTK_DIALOG_MODAL,
                                       GTK_MESSAGE_ERROR,
                                       GTK_BUTTONS_CLOSE,
                                       _("Failed to launch action \"%s\"."), label);
      gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s.", error->message);
      gtk_dialog_run (GTK_DIALOG (dialog));
      gtk_widget_destroy (dialog);
      g_error_free (error);
      g_free (label);
    }
}
Example #5
0
static gboolean
launch_test_binary (const char *binary,
                    guint       skip_tests)
{
  GTestLogBuffer *tlb;
  GSList *slist, *free_list = NULL;
  GError *error = NULL;
  int argc = 0;
  const gchar **argv;
  GPid pid = 0;
  gint report_pipe[2] = { -1, -1 };
  guint child_report_cb_id = 0;
  gboolean loop_pending;
  gint i = 0;

  if (!g_unix_open_pipe (report_pipe, FD_CLOEXEC, &error))
    {
      if (subtest_mode_fatal)
        g_error ("Failed to open pipe for test binary: %s: %s", binary, error->message);
      else
        g_warning ("Failed to open pipe for test binary: %s: %s", binary, error->message);
      g_clear_error (&error);
      return FALSE;
    }

  /* setup argc */
  for (slist = subtest_args; slist; slist = slist->next)
    argc++;
  /* argc++; */
  if (subtest_quiet)
    argc++;
  if (subtest_verbose)
    argc++;
  if (!subtest_mode_fatal)
    argc++;
  /* Either -m=quick or -m=slow is always appended. */
  argc++;
  if (subtest_mode_perf)
    argc++;
  if (!subtest_mode_undefined)
    argc++;
  if (gtester_list_tests)
    argc++;
  if (subtest_seedstr)
    argc++;
  argc++;
  if (skip_tests)
    argc++;
  for (slist = subtest_paths; slist; slist = slist->next)
    argc++;
  for (slist = skipped_paths; slist; slist = slist->next)
    argc++;

  /* setup argv */
  argv = g_malloc ((argc + 2) * sizeof(gchar *));
  argv[i++] = binary;
  for (slist = subtest_args; slist; slist = slist->next)
    argv[i++] = (gchar*) slist->data;
  /* argv[i++] = "--debug-log"; */
  if (subtest_quiet)
    argv[i++] = "--quiet";
  if (subtest_verbose)
    argv[i++] = "--verbose";
  if (!subtest_mode_fatal)
    argv[i++] = "--keep-going";
  if (subtest_mode_quick)
    argv[i++] = "-m=quick";
  else
    argv[i++] = "-m=slow";
  if (subtest_mode_perf)
    argv[i++] = "-m=perf";
  if (!subtest_mode_undefined)
    argv[i++] = "-m=no-undefined";
  if (gtester_list_tests)
    argv[i++] = "-l";
  if (subtest_seedstr)
    argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--seed=%s", subtest_seedstr));
  argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--GTestLogFD=%u", report_pipe[1]));
  if (skip_tests)
    argv[i++] = queue_gfree (&free_list, g_strdup_printf ("--GTestSkipCount=%u", skip_tests));
  for (slist = subtest_paths; slist; slist = slist->next)
    argv[i++] = queue_gfree (&free_list, g_strdup_printf ("-p=%s", (gchar*) slist->data));
  for (slist = skipped_paths; slist; slist = slist->next)
    argv[i++] = queue_gfree (&free_list, g_strdup_printf ("-s=%s", (gchar*) slist->data));
  argv[i++] = NULL;

  g_spawn_async_with_pipes (NULL, /* g_get_current_dir() */
                            (gchar**) argv,
                            NULL, /* envp */
                            G_SPAWN_DO_NOT_REAP_CHILD, /* G_SPAWN_SEARCH_PATH */
                            unset_cloexec_fdp, &report_pipe[1], /* pre-exec callback */
                            &pid,
                            NULL,       /* standard_input */
                            NULL,       /* standard_output */
                            NULL,       /* standard_error */
                            &error);
  g_slist_foreach (free_list, (void(*)(void*,void*)) g_free, NULL);
  g_slist_free (free_list);
  free_list = NULL;
  close (report_pipe[1]);

  if (!gtester_quiet)
    g_print ("(pid=%lu)\n", (unsigned long) pid);

  if (error)
    {
      close (report_pipe[0]);
      if (subtest_mode_fatal)
        g_error ("Failed to execute test binary: %s: %s", argv[0], error->message);
      else
        g_warning ("Failed to execute test binary: %s: %s", argv[0], error->message);
      g_clear_error (&error);
      g_free (argv);
      return FALSE;
    }
  g_free (argv);

  subtest_running = TRUE;
  subtest_io_pending = TRUE;
  tlb = g_test_log_buffer_new();
  if (report_pipe[0] >= 0)
    {
      ioc_report = g_io_channel_unix_new (report_pipe[0]);
      g_io_channel_set_flags (ioc_report, G_IO_FLAG_NONBLOCK, NULL);
      g_io_channel_set_encoding (ioc_report, NULL, NULL);
      g_io_channel_set_buffered (ioc_report, FALSE);
      child_report_cb_id = g_io_add_watch_full (ioc_report, G_PRIORITY_DEFAULT - 1, G_IO_IN | G_IO_ERR | G_IO_HUP, child_report_cb, tlb, NULL);
      g_io_channel_unref (ioc_report);
    }
  g_child_watch_add_full (G_PRIORITY_DEFAULT + 1, pid, child_watch_cb, NULL, NULL);

  loop_pending = g_main_context_pending (NULL);
  while (subtest_running ||     /* FALSE once child exits */
         subtest_io_pending ||  /* FALSE once ioc_report closes */
         loop_pending)          /* TRUE while idler, etc are running */
    {
      /* g_print ("LOOPSTATE: subtest_running=%d subtest_io_pending=%d\n", subtest_running, subtest_io_pending); */
      /* check for unexpected hangs that are not signalled on report_pipe */
      if (!subtest_running &&   /* child exited */
          subtest_io_pending && /* no EOF detected on report_pipe */
          !loop_pending)        /* no IO events pending however */
        break;
      g_main_context_iteration (NULL, TRUE);
      loop_pending = g_main_context_pending (NULL);
    }

  if (subtest_io_pending)
    g_source_remove (child_report_cb_id);

  close (report_pipe[0]);
  g_test_log_buffer_free (tlb);

  return TRUE;
}
Example #6
0
gboolean
process_run (CommandData *command_data,
             GIOFunc io_callback,
             ProcessFinishCallback finish_callback,
             gpointer user_data,
             GError **error)
{
    ProcessData *data;
    //struct termios term;
    struct winsize win = {
        .ws_col = 80, .ws_row = 24,
        .ws_xpixel = 480, .ws_ypixel = 192,
    };

    data = g_slice_new0 (ProcessData);
    data->localwatchdog = FALSE;
    data->command_data = command_data;
    data->finish_callback = finish_callback;
    data->user_data = user_data;

    data->pid = forkpty (&data->fd, NULL, NULL, &win);
    if (data->pid < 0) {
        /* Failed to fork */
        g_set_error (error, RESTRAINT_PROCESS_ERROR,
                     RESTRAINT_PROCESS_FORK_ERROR,
                     "Failed to fork: %s", g_strerror (errno));
        return FALSE;
    } else if (data->pid == 0) {
        /* Child process. */
        if (command_data->path && (chdir (command_data->path) == -1)) {
            /* command_path was supplied and we failed to chdir to it. */
            g_warning ("Failed to chdir() to %s: %s\n", command_data->path, g_strerror (errno));
            exit (1);
        }
        environ = (gchar **) command_data->environ;

        // Print the command being executed.
        gchar *command = g_strjoinv (" ", (gchar **) command_data->command);
        g_print ("%s\n", command);
        g_free (command);

        /* Spawn the command */
        if (execvp (*command_data->command, (gchar **) command_data->command) == -1) {
            g_warning ("Failed to exec() %s, %s error:%s\n",
                       *command_data->command,
                       command_data->path, g_strerror (errno));
            exit (1);
        }
    }
    /* Parent process. */

    // close file descriptors on exec.  Should prevent leaking fd's to child processes.
    fcntl (data->fd, F_SETFD, FD_CLOEXEC);

    // Localwatchdog handler
    if (command_data->max_time != 0) {
        data->timeout_handler_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
                                                               command_data->max_time,
                                                               process_timeout_callback,
                                                               data,
                                                               NULL);
    }

    // IO handler
    if (io_callback != NULL) {
        GIOChannel *io = g_io_channel_unix_new (data->fd);
        g_io_channel_set_flags (io, G_IO_FLAG_NONBLOCK, NULL);
        // Set Encoding to NULL to keep g_io_channel from trying to decode it.
        g_io_channel_set_encoding (io, NULL, NULL);
        data->io_handler_id = g_io_add_watch_full (io,
                                                   G_PRIORITY_DEFAULT,
                                                   G_IO_IN | G_IO_HUP,
                                                   io_callback,
                                                   data,
                                                   process_io_finish);
    }
    // Monitor pid for return code
    data->pid_handler_id = g_child_watch_add_full (G_PRIORITY_DEFAULT,
                                                   data->pid,
                                                   process_pid_callback,
                                                   data,
                                                   process_pid_finish);
    return TRUE;
}

void
process_pid_callback (GPid pid, gint status, gpointer user_data)
{
    ProcessData *process_data = (ProcessData *) user_data;

    process_data->pid_result = status;
}
Example #7
0
/**
 * _gcr_gnupg_process_run_async:
 * @self: The process
 * @argv: (array zero-terminated=1): The arguments for the process, not including executable, terminated with %NULL.
 * @envp: (allow-none) (array zero-terminated=1): The environment for new process, terminated with %NULL.
 * @flags: Flags for starting the process.
 * @cancellable: (allow-none): Cancellation object
 * @callback: Will be called when operation completes.
 * @user_data: (closure): Data passed to callback.
 *
 * Run the gpg process. Only one 'run' operation can run per GcrGnupgProcess
 * object. The GcrGnupgProcess:output_data and GcrGnupgProcess:error_line
 * signals will be emitted when data is received from the gpg process.
 *
 * Unless the %GCR_GNUPG_PROCESS_RESPECT_LOCALE flag is specified, the process
 * will be run in the 'C' locale. If the %GCR_GNUPG_PROCESS_WITH_STATUS or
 * %GCR_GNUPG_PROCESS_WITH_ATTRIBUTES flags are set, then the gpg process
 * will be status and attribute output respectively. The
 * GcrGnupgProcess:status_record and GcrGnupgProcess:attribute_data signals
 * will provide this data.
 */
void
_gcr_gnupg_process_run_async (GcrGnupgProcess *self, const gchar **argv, const gchar **envp,
                              GcrGnupgProcessFlags flags, GCancellable *cancellable,
                              GAsyncReadyCallback callback, gpointer user_data)
{
	GError *error = NULL;
	GPtrArray *args;
	GPtrArray *envs;
	int child_fds[NUM_FDS];
	int status_fds[2] = { -1, -1 };
	int attribute_fds[2] = { -1, -1 };
	int output_fd = -1;
	int error_fd = -1;
	int input_fd = -1;
	GnupgSource *gnupg_source;
	GSource *source;
	GPid pid;
	guint i;

	g_return_if_fail (GCR_IS_GNUPG_PROCESS (self));
	g_return_if_fail (argv);
	g_return_if_fail (callback);
	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));

	g_return_if_fail (self->pv->running == FALSE);
	g_return_if_fail (self->pv->complete == FALSE);
	g_return_if_fail (self->pv->executable);

	self->pv->async_callback = callback;
	self->pv->user_data = user_data;

	for (i = 0; i < NUM_FDS; i++)
		child_fds[i] = -1;

	/* The command needs to be updated with these status and attribute fds */
	args = g_ptr_array_new_with_free_func (g_free);
	g_ptr_array_add (args, g_strdup (self->pv->executable));

	/* Spawn/child will close all other attributes, besides thesthose in child_fds */
	child_fds[FD_INPUT] = 0;
	child_fds[FD_OUTPUT] = 1;
	child_fds[FD_ERROR] = 2;

	if (flags & GCR_GNUPG_PROCESS_WITH_STATUS) {
		if (pipe (status_fds) < 0)
			g_return_if_reached ();
		child_fds[FD_STATUS] = status_fds[1];
		g_ptr_array_add (args, g_strdup ("--status-fd"));
		g_ptr_array_add (args, g_strdup_printf ("%d", child_fds[FD_STATUS]));
	}
	if (flags & GCR_GNUPG_PROCESS_WITH_ATTRIBUTES) {
		if (pipe (attribute_fds) < 0)
			g_return_if_reached ();
		child_fds[FD_ATTRIBUTE] = attribute_fds[1];
		g_ptr_array_add (args, g_strdup ("--attribute-fd"));
		g_ptr_array_add (args, g_strdup_printf ("%d", child_fds[FD_ATTRIBUTE]));
	}

	if (self->pv->directory) {
		g_ptr_array_add (args, g_strdup ("--homedir"));
		g_ptr_array_add (args, g_strdup (self->pv->directory));
	}

	/* All the remaining arguments */
	for (i = 0; argv[i] != NULL; i++)
		g_ptr_array_add (args, g_strdup (argv[i]));
	g_ptr_array_add (args, NULL);

	envs = g_ptr_array_new ();
	for (i = 0; envp && envp[i] != NULL; i++) {
		if (flags & GCR_GNUPG_PROCESS_RESPECT_LOCALE ||
		    !g_str_has_prefix (envp[i], "LOCALE="))
			g_ptr_array_add (envs, (gpointer)envp[i]);
	}
	if (!(flags & GCR_GNUPG_PROCESS_RESPECT_LOCALE))
		g_ptr_array_add (envs, (gpointer)"LOCALE=C");
	g_ptr_array_add (envs, NULL);

	gchar *command = g_strjoinv (" ", (gchar**)args->pdata);
	gchar *environ = g_strjoinv (", ", (gchar**)envs->pdata);
	g_debug ("running command: %s", command);
	g_debug ("process environment: %s", environ);
	g_free (command);
	g_free (environ);

	g_spawn_async_with_pipes (self->pv->directory, (gchar**)args->pdata,
	                          (gchar**)envs->pdata, G_SPAWN_DO_NOT_REAP_CHILD,
	                          on_gnupg_process_child_setup, child_fds,
	                          &pid, &input_fd, &output_fd, &error_fd, &error);

	g_ptr_array_free (args, TRUE);
	g_ptr_array_free (envs, TRUE);

	/* Close 'wrong' ends of extra file descriptors */
	close_fd (&(status_fds[1]));
	close_fd (&(attribute_fds[1]));

	self->pv->complete = FALSE;
	self->pv->running = TRUE;

	if (error) {
		close_fd (&(status_fds[0]));
		close_fd (&(attribute_fds[0]));
		g_assert (!self->pv->error);
		self->pv->error = error;
		complete_run_process (self);
		run_async_ready_callback_later (self);
		return;
	}

	g_debug ("process started: %d", (int)pid);

	source = g_source_new (&gnupg_source_funcs, sizeof (GnupgSource));

	/* Initialize the source */
	gnupg_source = (GnupgSource*)source;
	for (i = 0; i < NUM_FDS; i++)
		gnupg_source->polls[i].fd = -1;
	gnupg_source->error_buf = g_string_sized_new (128);
	gnupg_source->status_buf = g_string_sized_new (128);
	gnupg_source->process = g_object_ref (self);
	gnupg_source->child_pid = pid;

	gnupg_source->polls[FD_INPUT].fd = input_fd;
	if (input_fd >= 0) {
		gnupg_source->polls[FD_INPUT].events = G_IO_HUP | G_IO_OUT;
		g_source_add_poll (source, &gnupg_source->polls[FD_INPUT]);
	}
	gnupg_source->polls[FD_OUTPUT].fd = output_fd;
	if (output_fd >= 0) {
		gnupg_source->polls[FD_OUTPUT].events = G_IO_HUP | G_IO_IN;
		g_source_add_poll (source, &gnupg_source->polls[FD_OUTPUT]);
	}
	gnupg_source->polls[FD_ERROR].fd = error_fd;
	if (error_fd >= 0) {
		gnupg_source->polls[FD_ERROR].events = G_IO_HUP | G_IO_IN;
		g_source_add_poll (source, &gnupg_source->polls[FD_ERROR]);
	}
	gnupg_source->polls[FD_STATUS].fd = status_fds[0];
	if (status_fds[0] >= 0) {
		gnupg_source->polls[FD_STATUS].events = G_IO_HUP | G_IO_IN;
		g_source_add_poll (source, &gnupg_source->polls[FD_STATUS]);
	}
	gnupg_source->polls[FD_ATTRIBUTE].fd = attribute_fds[0];
	if (attribute_fds[0] >= 0) {
		gnupg_source->polls[FD_ATTRIBUTE].events = G_IO_HUP | G_IO_IN;
		g_source_add_poll (source, &gnupg_source->polls[FD_ATTRIBUTE]);
	}

	if (cancellable) {
		gnupg_source->cancellable = g_object_ref (cancellable);
		gnupg_source->cancel_sig = g_cancellable_connect (cancellable,
		                                                  G_CALLBACK (on_cancellable_cancelled),
		                                                  g_source_ref (source),
		                                                  (GDestroyNotify)g_source_unref);
	}

	g_assert (self->pv->source_sig == 0);
	g_source_set_callback (source, unused_callback, NULL, NULL);
	self->pv->source_sig = g_source_attach (source, g_main_context_default ());

	/* This assumes the outstanding reference to source */
	g_assert (gnupg_source->child_sig == 0);
	gnupg_source->child_sig = g_child_watch_add_full (G_PRIORITY_DEFAULT, pid,
	                                                  on_gnupg_process_child_exited,
	                                                  g_source_ref (source),
	                                                  (GDestroyNotify)g_source_unref);

	/* source is unreffed in complete_if_source_is_done() */
}
Example #8
0
GPid
storage_daemon_spawn_for_variant (StorageDaemon *daemon,
                                  const gchar **argv,
                                  const GVariantType *type,
                                  void (*callback) (GPid, GVariant *, GError *, gpointer),
                                  gpointer user_data)
{
  GError *error = NULL;
  struct VariantReaderData *data;
  gchar *prog = NULL;
  GPid pid;
  gint output_fd;
  gchar *cmd;

  /*
   * This is so we can override the location of storaged-lvm-helper
   * during testing.
   */

  if (!strchr (argv[0], '/'))
    {
      prog = storage_daemon_get_resource_path (daemon, TRUE, argv[0]);
      argv[0] = prog;
    }

  cmd = g_strjoinv (" ", (gchar **)argv);
  g_debug ("spawning for variant: %s", cmd);
  g_free (cmd);

  if (!g_spawn_async_with_pipes (NULL,
                                 (gchar **)argv,
                                 NULL,
                                 G_SPAWN_DO_NOT_REAP_CHILD,
                                 NULL,
                                 NULL,
                                 &pid,
                                 NULL,
                                 &output_fd,
                                 NULL,
                                 &error))
    {
      callback (0, NULL, error, user_data);
      g_error_free (error);
      return 0;
    }

  data = g_new0 (struct VariantReaderData, 1);

  data->type = type;
  data->callback = callback;
  data->user_data = user_data;

  data->pid = pid;
  data->output = g_byte_array_new ();
  data->output_channel = g_io_channel_unix_new (output_fd);
  g_io_channel_set_encoding (data->output_channel, NULL, NULL);
  g_io_channel_set_flags (data->output_channel, G_IO_FLAG_NONBLOCK, NULL);
  data->output_watch = g_io_add_watch (data->output_channel, G_IO_IN, variant_reader_child_output, data);

  g_child_watch_add_full (G_PRIORITY_DEFAULT_IDLE,
                          pid, variant_reader_watch_child, data, variant_reader_destroy);

  g_free (prog);
  return pid;
}
Example #9
0
void
process_run (const gchar *command,
             const gchar **envp,
             const gchar *path,
             guint64 max_time,
             GIOFunc io_callback,
             ProcessFinishCallback finish_callback,
             GCancellable *cancellable,
             gpointer user_data)
{
    ProcessData *process_data;
    //struct termios term;
    struct winsize win = {
        .ws_col = 80, .ws_row = 24,
        .ws_xpixel = 480, .ws_ypixel = 192,
    };

    process_data = g_slice_new0 (ProcessData);
    process_data->localwatchdog = FALSE;
    process_data->command = g_strsplit (command, " ", 0);
    process_data->path = path;
    process_data->max_time = max_time;
    process_data->io_callback = io_callback;
    process_data->finish_callback = finish_callback;
    process_data->user_data = user_data;
    process_data->io = NULL;
    process_data->cancellable = cancellable;

    if (fflush (stdout) != 0)
        g_warning ("Failed to flush stdout: %s\n", g_strerror (errno));
    if (fflush (stderr) != 0)
        g_warning ("Failed to flush stderr: %s\n", g_strerror (errno));

    process_data->pid = forkpty (&process_data->fd, NULL, NULL, &win);
    if (process_data->pid < 0) {
        /* Failed to fork */
        g_set_error (&process_data->error, RESTRAINT_PROCESS_ERROR,
                     RESTRAINT_PROCESS_FORK_ERROR,
                     "Failed to fork: %s", g_strerror (errno));
        g_idle_add (process_pid_finish, process_data);
        return;
    } else if (process_data->pid == 0) {
        /* Child process. */

        // Flush any input that hasn't been read
        if (fflush (stdin) != 0)
            g_warning ("Failed to flush stdin: %s\n", g_strerror (errno));

        setbuf (stdout, NULL);
        setbuf (stderr, NULL);
        if (process_data->path && (chdir (process_data->path) == -1)) {
            /* command_path was supplied and we failed to chdir to it. */
            g_warning ("Failed to chdir() to %s: %s\n", process_data->path, g_strerror (errno));
            exit (1);
        }
        if (envp)
            environ = (gchar **) envp;

        // Print the command being executed.
        gchar *pcommand = g_strjoinv (" ", (gchar **) process_data->command);
        g_print ("%s\n", pcommand);
        g_free (pcommand);

        /* Spawn the command */
        if (execvp (*process_data->command, (gchar **) process_data->command) == -1) {
            g_warning ("Failed to exec() %s, %s error:%s\n",
                       *process_data->command,
                       process_data->path, g_strerror (errno));
            exit (1);
        }
    }
    /* Parent process. */

    // If we get the cancel signal kill any running process
    if (process_data->cancellable) {
        process_data->cancel_handler = g_cancellable_connect (process_data->cancellable,
                                                              G_CALLBACK(process_cancelled_cb),
                                                              process_data,
                                                              NULL);
    }

    // close file descriptors on exec.  Should prevent leaking fd's to child processes.
    if (fcntl (process_data->fd, F_SETFD, FD_CLOEXEC) < 0) {
        g_warning("Failed to set close on exec");
    }

    // Localwatchdog handler
    if (process_data->max_time != 0) {
        process_data->timeout_handler_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
                                                               process_data->max_time,
                                                               process_timeout_callback,
                                                               process_data,
                                                               NULL);
    }

    // IO handler
    if (io_callback != NULL) {
        GIOChannel *io = g_io_channel_unix_new (process_data->fd);
        g_io_channel_set_flags (io, G_IO_FLAG_NONBLOCK, NULL);
        // Set Encoding to NULL to keep g_io_channel from trying to decode it.
        g_io_channel_set_encoding (io, NULL, NULL);
        // Disable Buffering
        g_io_channel_set_buffered (io, FALSE);

        process_data->io = io;
        process_data->io_handler_id = g_io_add_watch_full (io,
                                                   G_PRIORITY_DEFAULT,
                                                   G_IO_IN | G_IO_HUP | G_IO_NVAL,
                                                   process_io_cb,
                                                   process_data,
                                                   process_io_finish);
    }
    // Monitor pid for return code
    process_data->pid_handler_id = g_child_watch_add_full (G_PRIORITY_DEFAULT,
                                                   process_data->pid,
                                                   process_pid_callback,
                                                   process_data,
                                                   NULL);
}

void
process_pid_callback (GPid pid, gint status, gpointer user_data)
{
    ProcessData *process_data = (ProcessData *) user_data;

    process_data->pid_result = status;
    process_data->pid = 0;
    if (process_data->fd != -1 ) {
        close (process_data->fd);
        process_data->fd = -1;
    }
    if (process_data->finish_handler_id == 0) {
        process_data->finish_handler_id = g_idle_add (process_pid_finish, process_data);
    }
}