static gchar * spawn_dbus_daemon (const gchar *binary, const gchar *configuration, const gchar *listen_address, TestUser user, GPid *daemon_pid) { GError *error = NULL; GString *address; gint address_fd; GPtrArray *argv; #ifdef DBUS_UNIX const struct passwd *pwd = NULL; #endif if (user != TEST_USER_ME) { #ifdef DBUS_UNIX if (getuid () != 0) { g_test_skip ("cannot use alternative uid when not uid 0"); return NULL; } switch (user) { case TEST_USER_ROOT: break; case TEST_USER_MESSAGEBUS: pwd = getpwnam (DBUS_USER); if (pwd == NULL) { gchar *message = g_strdup_printf ("user '%s' does not exist", DBUS_USER); g_test_skip (message); g_free (message); return NULL; } break; case TEST_USER_OTHER: pwd = getpwnam (DBUS_TEST_USER); if (pwd == NULL) { gchar *message = g_strdup_printf ("user '%s' does not exist", DBUS_TEST_USER); g_test_skip (message); g_free (message); return NULL; } break; default: g_assert_not_reached (); } #else g_test_skip ("cannot use alternative uid on Windows"); return NULL; #endif } argv = g_ptr_array_new_with_free_func (g_free); g_ptr_array_add (argv, g_strdup (binary)); g_ptr_array_add (argv, g_strdup (configuration)); g_ptr_array_add (argv, g_strdup ("--nofork")); g_ptr_array_add (argv, g_strdup ("--print-address=1")); /* stdout */ if (listen_address != NULL) g_ptr_array_add (argv, g_strdup (listen_address)); #ifdef DBUS_UNIX g_ptr_array_add (argv, g_strdup ("--systemd-activation")); #endif g_ptr_array_add (argv, NULL); g_spawn_async_with_pipes (NULL, /* working directory */ (gchar **) argv->pdata, NULL, /* envp */ G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, #ifdef DBUS_UNIX child_setup, (gpointer) pwd, #else NULL, NULL, #endif daemon_pid, NULL, /* child's stdin = /dev/null */ &address_fd, NULL, /* child's stderr = our stderr */ &error); g_assert_no_error (error); g_ptr_array_free (argv, TRUE); address = g_string_new (NULL); /* polling until the dbus-daemon writes out its address is a bit stupid, * but at least it's simple, unlike dbus-launch... in principle we could * use select() here, but life's too short */ while (1) { gssize bytes; gchar buf[4096]; gchar *newline; bytes = read (address_fd, buf, sizeof (buf)); if (bytes > 0) g_string_append_len (address, buf, bytes); newline = strchr (address->str, '\n'); if (newline != NULL) { if ((newline > address->str) && ('\r' == newline[-1])) newline -= 1; g_string_truncate (address, newline - address->str); break; } g_usleep (G_USEC_PER_SEC / 10); } g_close (address_fd, NULL); return g_string_free (address, FALSE); }
static gboolean egg_desktop_file_launchv (EggDesktopFile *desktop_file, GSList *documents, va_list args, GError **error) { EggDesktopFileLaunchOption option; GSList *translated_documents = NULL, *docs = NULL; char *command, **argv; int argc, i, screen_num; gboolean success, current_success; GdkDisplay *display; char *startup_id; GPtrArray *env = NULL; char **variables = NULL; GdkScreen *screen = NULL; int workspace = -1; const char *directory = NULL; guint32 launch_time = (guint32)-1; GSpawnFlags flags = G_SPAWN_SEARCH_PATH; GSpawnChildSetupFunc setup_func = NULL; gpointer setup_data = NULL; GPid *ret_pid = NULL; int *ret_stdin = NULL, *ret_stdout = NULL, *ret_stderr = NULL; char **ret_startup_id = NULL; if (documents && desktop_file->document_code == 0) { g_set_error (error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, _("Application does not accept documents on command line")); return FALSE; } /* Read the options: technically it's incorrect for the caller to * NULL-terminate the list of options (rather than 0-terminating * it), but NULL-terminating lets us use G_GNUC_NULL_TERMINATED, * it's more consistent with other glib/gtk methods, and it will * work as long as sizeof (int) <= sizeof (NULL), and NULL is * represented as 0. (Which is true everywhere we care about.) */ while ((option = va_arg (args, EggDesktopFileLaunchOption))) { switch (option) { case EGG_DESKTOP_FILE_LAUNCH_CLEARENV: if (env) g_ptr_array_free (env, TRUE); env = g_ptr_array_new (); break; case EGG_DESKTOP_FILE_LAUNCH_PUTENV: variables = va_arg (args, char **); for (i = 0; variables[i]; i++) env = array_putenv (env, variables[i]); break; case EGG_DESKTOP_FILE_LAUNCH_SCREEN: screen = va_arg (args, GdkScreen *); break; case EGG_DESKTOP_FILE_LAUNCH_WORKSPACE: workspace = va_arg (args, int); break; case EGG_DESKTOP_FILE_LAUNCH_DIRECTORY: directory = va_arg (args, const char *); break; case EGG_DESKTOP_FILE_LAUNCH_TIME: launch_time = va_arg (args, guint32); break; case EGG_DESKTOP_FILE_LAUNCH_FLAGS: flags |= va_arg (args, GSpawnFlags); /* Make sure they didn't set any flags that don't make sense. */ flags &= ~G_SPAWN_FILE_AND_ARGV_ZERO; break; case EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC: setup_func = va_arg (args, GSpawnChildSetupFunc); setup_data = va_arg (args, gpointer); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_PID: ret_pid = va_arg (args, GPid *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE: ret_stdin = va_arg (args, int *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE: ret_stdout = va_arg (args, int *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE: ret_stderr = va_arg (args, int *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID: ret_startup_id = va_arg (args, char **); break; default: g_set_error (error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION, _("Unrecognized launch option: %d"), GPOINTER_TO_INT (option)); success = FALSE; goto out; } } if (screen) { display = gdk_screen_get_display (screen); char *display_name = g_strdup (gdk_display_get_name (display)); char *display_env = g_strdup_printf ("DISPLAY=%s", display_name); env = array_putenv (env, display_env); g_free (display_name); g_free (display_env); } else { display = gdk_display_get_default (); screen = gdk_display_get_default_screen (display); } screen_num = gdk_x11_screen_get_screen_number (screen); translated_documents = translate_document_list (desktop_file, documents); docs = translated_documents; success = FALSE; do { command = parse_exec (desktop_file, &docs, error); if (!command) goto out; if (!g_shell_parse_argv (command, &argc, &argv, error)) { g_free (command); goto out; } g_free (command); startup_id = start_startup_notification (display, desktop_file, argv[0], screen_num, workspace, launch_time); if (startup_id) { char *startup_id_env = g_strdup_printf ("DESKTOP_STARTUP_ID=%s", startup_id); env = array_putenv (env, startup_id_env); g_free (startup_id_env); } if (env != NULL) g_ptr_array_add (env, NULL); current_success = g_spawn_async_with_pipes (directory, argv, env ? (char **)(env->pdata) : NULL, flags, setup_func, setup_data, ret_pid, ret_stdin, ret_stdout, ret_stderr, error); g_strfreev (argv); if (startup_id) { if (current_success) { set_startup_notification_timeout (display, startup_id); if (ret_startup_id) *ret_startup_id = startup_id; else g_free (startup_id); } else g_free (startup_id); } else if (ret_startup_id) *ret_startup_id = NULL; if (current_success) { /* If we successfully launch any instances of the app, make * sure we return TRUE and don't set @error. */ success = TRUE; error = NULL; /* Also, only set the output params on the first one */ ret_pid = NULL; ret_stdin = ret_stdout = ret_stderr = NULL; ret_startup_id = NULL; } } while (docs && current_success); out: if (env) { g_strfreev ((char **)env->pdata); g_ptr_array_free (env, FALSE); } free_document_list (translated_documents); return success; }
/* Spawns a process and puts the result into buffers while occasionally running busy_func. * The idea being that busy_func can do things to keep the gui alive while the function * blocks until the script terminates */ gboolean spawn_script(const gchar *wdir, gchar **argv, gchar **envp, gchar *standard_input, gchar **standard_output, gchar **standard_error, gint *exit_code, GError **error, int busy_func(void*), void *busy_data) { int nstdin, nstdout, nstderr; FILE *fstdin=NULL, *fstdout=NULL, *fstderr=NULL; GString *sstdout, *sstderr; GPid pid; gboolean ret; int c; GSpawnFlags sf; sf = 0; if (!(ret = g_spawn_async_with_pipes(wdir, argv, envp, sf, NULL, NULL, &pid, &nstdin, &nstdout, &nstderr, error))) { return ret; } if (!((fstdin = fdopen(nstdin, "ab")) && (fstdout = fdopen(nstdout, "rb")) && (fstderr = fdopen(nstderr, "rb")))) { fprintf(stderr, "spawn_script fdopen failed\n"); exit(1); } fprintf(fstdin, standard_input); fclose(fstdin); sstdout = g_string_new(""); sstderr = g_string_new(""); while ((c = fgetc(fstdout)) != EOF) { sstdout = g_string_append_c(sstdout, c); if (busy_func && !busy_func(busy_data)) { // terminate script and return } } while ((c = fgetc(fstderr)) != EOF) { sstderr = g_string_append_c(sstderr, c); } fclose(fstdout); fclose(fstderr); g_spawn_close_pid(pid); *standard_output = sstdout->str; *standard_error = sstderr->str; g_string_free(sstdout, FALSE); g_string_free(sstderr, FALSE); /* Frees struct, not character data */ // *exit_code = return ret; }
/* Spawn passwd backend * Returns: TRUE on success, FALSE otherwise and sets error appropriately */ static gboolean spawn_passwd (PasswordDialog *pdialog, GError **error) { gchar *argv[2]; gchar *envp[1]; gint my_stdin, my_stdout, my_stderr; argv[0] = "/usr/bin/passwd"; /* Is it safe to rely on a hard-coded path? */ argv[1] = NULL; envp[0] = NULL; /* If we pass an empty array as the environment, * will the childs environment be empty, and the * locales set to the C default? From the manual: * "If envp is NULL, the child inherits its * parent'senvironment." * If I'm wrong here, we somehow have to set * the locales here. */ if (!g_spawn_async_with_pipes (NULL, /* Working directory */ argv, /* Argument vector */ envp, /* Environment */ G_SPAWN_DO_NOT_REAP_CHILD, /* Flags */ NULL, /* Child setup */ NULL, /* Data to child setup */ &pdialog->backend_pid, /* PID */ &my_stdin, /* Stdin */ &my_stdout, /* Stdout */ &my_stderr, /* Stderr */ error)) { /* GError */ /* An error occurred */ free_passwd_resources (pdialog); return FALSE; } /* 2>&1 */ if (dup2 (my_stderr, my_stdout) == -1) { /* Failed! */ g_set_error (error, PASSDLG_ERROR, PASSDLG_ERROR_BACKEND, "%s", strerror (errno)); /* Clean up */ stop_passwd (pdialog); return FALSE; } /* Open IO Channels */ pdialog->backend_stdin = g_io_channel_unix_new (my_stdin); pdialog->backend_stdout = g_io_channel_unix_new (my_stdout); /* Set raw encoding */ /* Set nonblocking mode */ if (g_io_channel_set_encoding (pdialog->backend_stdin, NULL, error) != G_IO_STATUS_NORMAL || g_io_channel_set_encoding (pdialog->backend_stdout, NULL, error) != G_IO_STATUS_NORMAL || g_io_channel_set_flags (pdialog->backend_stdin, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL || g_io_channel_set_flags (pdialog->backend_stdout, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ) { /* Clean up */ stop_passwd (pdialog); return FALSE; } /* Turn off buffering */ g_io_channel_set_buffered (pdialog->backend_stdin, FALSE); g_io_channel_set_buffered (pdialog->backend_stdout, FALSE); /* Add IO Channel watcher */ pdialog->backend_stdout_watch_id = g_io_add_watch (pdialog->backend_stdout, G_IO_IN | G_IO_PRI, (GIOFunc) io_watch_stdout, pdialog); /* Add child watcher */ pdialog->backend_child_watch_id = g_child_watch_add (pdialog->backend_pid, (GChildWatchFunc) child_watch_cb, pdialog); /* Success! */ return TRUE; }
void GwSpawn::run() { describe(); // Working directory. const gchar *workingdirectory = NULL; if (!myworkingdirectory.empty()) workingdirectory = myworkingdirectory.c_str(); // Store arguments in argv. char *argv[myarguments.size() + 2]; // I know these casts are ugly. To do: figure out a better way. argv[0] = (char *)myprogram.c_str(); for (unsigned int i = 0; i < myarguments.size(); i++) { argv[i + 1] = (char *)myarguments[i].c_str(); } // Terminate argv. argv[myarguments.size() + 1] = NULL; // Spawn flags. int flags = G_SPAWN_SEARCH_PATH; if (mydevnull) { flags |= (G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL); } // Possible pipes. gint standard_input_filedescriptor = 0; gint standard_output_filedescriptor; gint standard_error_filedescriptor; gint *standard_input_filedescriptor_pointer = NULL; gint *standard_output_filedescriptor_pointer = NULL; gint *standard_error_filedescriptor_pointer = NULL; gchar *standard_output = NULL; gchar *standard_error = NULL; gchar **standard_output_pointer = NULL; gchar **standard_error_pointer = NULL; if (myread) { standard_output_filedescriptor_pointer = &standard_output_filedescriptor; standard_error_filedescriptor_pointer = &standard_error_filedescriptor; standard_output_pointer = &standard_output; standard_error_pointer = &standard_error; } if (!mywrite.empty()) { standard_input_filedescriptor_pointer = &standard_input_filedescriptor; } // Spawn process. if (myasync) { result = g_spawn_async_with_pipes(workingdirectory, argv, NULL, (GSpawnFlags) flags, NULL, NULL, &pid, standard_input_filedescriptor_pointer, standard_output_filedescriptor_pointer, standard_error_filedescriptor_pointer, NULL); // Handle writing to stdin. if (standard_input_filedescriptor) { tiny_spawn_write(standard_input_filedescriptor, mywrite); close(standard_input_filedescriptor); } } else { result = g_spawn_sync(workingdirectory, argv, NULL, (GSpawnFlags) flags, NULL, NULL, standard_output_pointer, standard_error_pointer, &exitstatus, NULL); } // Handle case we didn't spawn the process. if (!result) { exitstatus = -1; ustring message = myprogram; message.append(_(" didn't spawn")); gw_critical(message); return; } // Handle progress function. if (myprogress || standard_input_filedescriptor) { ProgressWindow *progresswindow = NULL; if (myprogress) progresswindow = new ProgressWindow(mytext, myallowcancel); ustring filename = gw_build_filename("/proc", convert_to_string(pid)); while (g_file_test(filename.c_str(), G_FILE_TEST_EXISTS)) { if (progresswindow) { progresswindow->pulse(); if (progresswindow->cancel) { unix_kill(pid); cancelled = true; } } g_usleep(500000); } // Close pid. g_spawn_close_pid(pid); if (progresswindow) { delete progresswindow; } } // Handle reading the output. if (myread) { // In async mode we've got file descriptors, and in sync mode we have // gchar * output. // If async mode, read the output and close the descriptors. if (myasync) { GIOChannel *channel_out = g_io_channel_unix_new(standard_output_filedescriptor); g_io_channel_read_to_end(channel_out, &standard_output, NULL, NULL); g_io_channel_shutdown(channel_out, false, NULL); GIOChannel *channel_err = g_io_channel_unix_new(standard_error_filedescriptor); g_io_channel_read_to_end(channel_err, &standard_error, NULL, NULL); g_io_channel_shutdown(channel_err, false, NULL); } ParseLine parse_out(standard_output); standardout = parse_out.lines; ParseLine parse_err(standard_error); standarderr = parse_err.lines; // Free data. if (standard_output) g_free(standard_output); if (standard_error) g_free(standard_error); } }
static gint nm_openconnect_start_openconnect_binary (NMOPENCONNECTPlugin *plugin, NMSettingVPN *s_vpn, GError **error) { NMOPENCONNECTPluginPrivate *priv = NM_OPENCONNECT_PLUGIN_GET_PRIVATE (plugin); GPid pid; const char **openconnect_binary = NULL; GPtrArray *openconnect_argv; GSource *openconnect_watch; gint stdin_fd; const char *props_vpn_gw, *props_cookie, *props_cacert, *props_mtu, *props_gwcert, *props_proxy; /* Find openconnect */ openconnect_binary = openconnect_binary_paths; while (*openconnect_binary != NULL) { if (g_file_test (*openconnect_binary, G_FILE_TEST_EXISTS)) break; openconnect_binary++; } if (!*openconnect_binary) { g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED, "%s", _("Could not find openconnect binary.")); return -1; } /* The actual gateway to use (after redirection) comes from the auth dialog, so it's in the secrets hash not the properties */ props_vpn_gw = nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_GATEWAY); if (!props_vpn_gw || !strlen (props_vpn_gw) ) { g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED, "%s", _("No VPN gateway specified.")); return -1; } props_cookie = nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_COOKIE); if (!props_cookie || !strlen (props_cookie)) { g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED, "%s", _("No WebVPN cookie provided.")); return -1; } props_gwcert = nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_GWCERT); props_cacert = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_CACERT); props_mtu = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_MTU); props_proxy = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_PROXY); openconnect_argv = g_ptr_array_new (); g_ptr_array_add (openconnect_argv, (gpointer) (*openconnect_binary)); if (props_gwcert && strlen(props_gwcert)) { g_ptr_array_add (openconnect_argv, (gpointer) "--servercert"); g_ptr_array_add (openconnect_argv, (gpointer) props_gwcert); } else if (props_cacert && strlen(props_cacert)) { g_ptr_array_add (openconnect_argv, (gpointer) "--cafile"); g_ptr_array_add (openconnect_argv, (gpointer) props_cacert); } if (props_mtu && strlen(props_mtu)) { g_ptr_array_add (openconnect_argv, (gpointer) "--mtu"); g_ptr_array_add (openconnect_argv, (gpointer) props_mtu); } if (props_proxy && strlen(props_proxy)) { g_ptr_array_add (openconnect_argv, (gpointer) "--proxy"); g_ptr_array_add (openconnect_argv, (gpointer) props_proxy); } g_ptr_array_add (openconnect_argv, (gpointer) "--syslog"); g_ptr_array_add (openconnect_argv, (gpointer) "--cookie-on-stdin"); g_ptr_array_add (openconnect_argv, (gpointer) "--script"); g_ptr_array_add (openconnect_argv, (gpointer) NM_OPENCONNECT_HELPER_PATH); priv->tun_name = create_persistent_tundev (); if (priv->tun_name) { g_ptr_array_add (openconnect_argv, (gpointer) "--interface"); g_ptr_array_add (openconnect_argv, (gpointer) priv->tun_name); } g_ptr_array_add (openconnect_argv, (gpointer) props_vpn_gw); if (debug) g_ptr_array_add (openconnect_argv, (gpointer) "--verbose"); g_ptr_array_add (openconnect_argv, NULL); if (!g_spawn_async_with_pipes (NULL, (char **) openconnect_argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD, openconnect_drop_child_privs, priv->tun_name, &pid, &stdin_fd, NULL, NULL, error)) { g_ptr_array_free (openconnect_argv, TRUE); g_warning ("openconnect failed to start. error: '%s'", (*error)->message); return -1; } g_ptr_array_free (openconnect_argv, TRUE); g_message ("openconnect started with pid %d", pid); if (write(stdin_fd, props_cookie, strlen(props_cookie)) != strlen(props_cookie) || write(stdin_fd, "\n", 1) != 1) { g_warning ("openconnect didn't eat the cookie we fed it"); return -1; } close(stdin_fd); NM_OPENCONNECT_PLUGIN_GET_PRIVATE (plugin)->pid = pid; openconnect_watch = g_child_watch_source_new (pid); g_source_set_callback (openconnect_watch, (GSourceFunc) openconnect_watch_cb, plugin, NULL); g_source_attach (openconnect_watch, NULL); g_source_unref (openconnect_watch); return 0; }
static gboolean on_handle_stream_socket (CockpitWebServer *server, const gchar *path, GIOStream *io_stream, GHashTable *headers, GByteArray *input, gpointer user_data) { CockpitTransport *transport; const gchar *query = NULL; CockpitCreds *creds; int session_stdin = -1; int session_stdout = -1; GError *error = NULL; GPid pid = 0; gchar *value; gchar **env; gchar **argv; if (!g_str_has_prefix (path, "/cockpit/socket")) return FALSE; if (path[15] == '?') { query = path + 16; } else if (path[15] != '\0') { return FALSE; } if (service) { g_object_ref (service); } else { g_clear_object (&bridge); value = g_strdup_printf ("%d", server_port); env = g_environ_setenv (g_get_environ (), "COCKPIT_TEST_SERVER_PORT", value, TRUE); argv = g_strdupv (bridge_argv); if (query) argv[g_strv_length (argv) - 1] = g_strdup (query); g_spawn_async_with_pipes (NULL, argv, env, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &session_stdin, &session_stdout, NULL, &error); g_strfreev (env); g_free (argv); g_free (value); if (error) { g_critical ("couldn't run bridge %s: %s", bridge_argv[0], error->message); return FALSE; } bridge = g_object_new (COCKPIT_TYPE_PIPE, "name", "test-server-bridge", "in-fd", session_stdout, "out-fd", session_stdin, "pid", pid, NULL); creds = cockpit_creds_new (g_get_user_name (), "test", COCKPIT_CRED_CSRF_TOKEN, "myspecialtoken", NULL); transport = cockpit_pipe_transport_new (bridge); service = cockpit_web_service_new (creds, transport); cockpit_creds_unref (creds); g_object_unref (transport); /* Clear the pointer automatically when service is done */ g_object_add_weak_pointer (G_OBJECT (service), (gpointer *)&service); } cockpit_web_service_socket (service, path, io_stream, headers, input); /* Keeps ref on itself until it closes */ g_object_unref (service); return TRUE; }
/* Spawn passwd backend * Returns: TRUE on success, FALSE otherwise and sets error appropriately */ static gboolean spawn_passwd (PasswdHandler *passwd_handler, GError **error) { gchar *argv[2]; gchar **envp; gint my_stdin, my_stdout, my_stderr; argv[0] = "/usr/bin/passwd"; /* Is it safe to rely on a hard-coded path? */ argv[1] = NULL; envp = g_get_environ (); envp = g_environ_setenv (envp, "LC_ALL", "C", TRUE); if (!g_spawn_async_with_pipes (NULL, /* Working directory */ argv, /* Argument vector */ envp, /* Environment */ G_SPAWN_DO_NOT_REAP_CHILD, /* Flags */ ignore_sigpipe, /* Child setup */ NULL, /* Data to child setup */ &passwd_handler->backend_pid, /* PID */ &my_stdin, /* Stdin */ &my_stdout, /* Stdout */ &my_stderr, /* Stderr */ error)) { /* GError */ /* An error occured */ free_passwd_resources (passwd_handler); g_strfreev (envp); return FALSE; } g_strfreev (envp); /* 2>&1 */ if (dup2 (my_stderr, my_stdout) == -1) { /* Failed! */ g_set_error_literal (error, PASSWD_ERROR, PASSWD_ERROR_BACKEND, strerror (errno)); /* Clean up */ stop_passwd (passwd_handler); return FALSE; } /* Open IO Channels */ passwd_handler->backend_stdin = g_io_channel_unix_new (my_stdin); passwd_handler->backend_stdout = g_io_channel_unix_new (my_stdout); /* Set raw encoding */ /* Set nonblocking mode */ if (g_io_channel_set_encoding (passwd_handler->backend_stdin, NULL, error) != G_IO_STATUS_NORMAL || g_io_channel_set_encoding (passwd_handler->backend_stdout, NULL, error) != G_IO_STATUS_NORMAL || g_io_channel_set_flags (passwd_handler->backend_stdin, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL || g_io_channel_set_flags (passwd_handler->backend_stdout, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ) { /* Clean up */ stop_passwd (passwd_handler); return FALSE; } /* Turn off buffering */ g_io_channel_set_buffered (passwd_handler->backend_stdin, FALSE); g_io_channel_set_buffered (passwd_handler->backend_stdout, FALSE); /* Add IO Channel watcher */ passwd_handler->backend_stdout_watch_id = g_io_add_watch (passwd_handler->backend_stdout, G_IO_IN | G_IO_PRI, (GIOFunc) io_watch_stdout, passwd_handler); /* Add child watcher */ passwd_handler->backend_child_watch_id = g_child_watch_add (passwd_handler->backend_pid, (GChildWatchFunc) child_watch_cb, passwd_handler); /* Success! */ return TRUE; }
static BraseroBurnResult brasero_process_start (BraseroJob *job, GError **error) { BraseroProcessPrivate *priv = BRASERO_PROCESS_PRIVATE (job); BraseroProcess *process = BRASERO_PROCESS (job); int stdout_pipe, stderr_pipe; BraseroProcessClass *klass; BraseroBurnResult result; gboolean read_stdout; /* that's to make sure programs are not translated */ gchar *envp [] = { "LANG=C", "LANGUAGE=C", "LC_ALL=C", NULL}; if (priv->pid) return BRASERO_BURN_RUNNING; /* ask the arguments for the program */ result = brasero_process_ask_argv (job, error); if (result != BRASERO_BURN_OK) return result; if (priv->working_directory) { BRASERO_JOB_LOG (process, "Launching command in %s", priv->working_directory); } else { BRASERO_JOB_LOG (process, "Launching command"); } klass = BRASERO_PROCESS_GET_CLASS (process); /* only watch stdout coming from the last object in the queue */ read_stdout = (klass->stdout_func && brasero_job_get_fd_out (BRASERO_JOB (process), NULL) != BRASERO_BURN_OK); priv->process_finished = FALSE; priv->return_status = 0; if (!g_spawn_async_with_pipes (priv->working_directory, (gchar **) priv->argv->pdata, (gchar **) envp, G_SPAWN_SEARCH_PATH| G_SPAWN_DO_NOT_REAP_CHILD, brasero_process_setup, process, &priv->pid, NULL, read_stdout ? &stdout_pipe : NULL, &stderr_pipe, error)) { return BRASERO_BURN_ERR; } /* error channel */ priv->std_error = brasero_process_setup_channel (process, stderr_pipe, &priv->io_err, (GIOFunc) brasero_process_read_stderr); if (read_stdout) priv->std_out = brasero_process_setup_channel (process, stdout_pipe, &priv->io_out, (GIOFunc) brasero_process_read_stdout); return BRASERO_BURN_OK; }
static gint run_command (struct _CamelSExp *f, gint argc, struct _CamelSExpResult **argv, FilterMessageSearch *fms) { CamelMimeMessage *message; CamelStream *stream; gint i; gint pipe_to_child; GPid child_pid; GError *error = NULL; GPtrArray *args; child_watch_data_t child_watch_data; GSource *source; GMainContext *context; if (argc < 1 || argv[0]->value.string[0] == '\0') return 0; args = g_ptr_array_new (); for (i = 0; i < argc; i++) g_ptr_array_add (args, argv[i]->value.string); g_ptr_array_add (args, NULL); if (!g_spawn_async_with_pipes (NULL, (gchar **) args->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, child_setup_func, NULL, &child_pid, &pipe_to_child, NULL, NULL, &error)) { g_ptr_array_free (args, TRUE); g_set_error ( fms->error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Failed to create child process '%s': %s"), argv[0]->value.string, error->message); g_error_free (error); return -1; } g_ptr_array_free (args, TRUE); message = camel_filter_search_get_message (fms, f); stream = camel_stream_fs_new_with_fd (pipe_to_child); camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (message), stream, fms->cancellable, NULL); camel_stream_flush (stream, fms->cancellable, NULL); g_object_unref (stream); context = g_main_context_new (); child_watch_data.loop = g_main_loop_new (context, FALSE); g_main_context_unref (context); source = g_child_watch_source_new (child_pid); g_source_set_callback (source, (GSourceFunc) child_watch, &child_watch_data, NULL); g_source_attach (source, g_main_loop_get_context (child_watch_data.loop)); g_source_unref (source); g_main_loop_run (child_watch_data.loop); g_main_loop_unref (child_watch_data.loop); #ifndef G_OS_WIN32 if (WIFEXITED (child_watch_data.child_status)) return WEXITSTATUS (child_watch_data.child_status); else return -1; #else return child_watch_data.child_status; #endif }
int main( int argc, char *argv[]) { glob_t gbuf; int grc, i; GString *cmd; GError *err = NULL; GMainLoop *loop; GPtrArray *child_args = NULL; /* parse options */ parse_options(&argc, &argv); /* set up logging */ if (!logc_setup(&err)) { air_opterr("%s", err->message); } if (fd_nextdir == NULL) { air_opterr("The --nextdir switch is required"); } child_args = g_ptr_array_sized_new(64); for (i=1; i < argc; i++) { /* Double dash indicates end of filedaemon's arguments */ if (!strncmp(argv[i], "--", strlen(argv[i])) ) continue; g_ptr_array_add(child_args, g_strdup(argv[i])); } g_ptr_array_add(child_args, NULL); if (child_args->len > 1) { if (fd_faildir == NULL) { air_opterr("The --faildir switch is required"); } } cmd = g_string_new(""); loop = g_main_loop_new(NULL, FALSE); /* We need an input glob */ if (!fd_inspec) { air_opterr("Input glob must be specified"); } /* If an output destination is provided, make sure it's a directory */ if (fd_outspec && !g_file_test(fd_outspec, G_FILE_TEST_IS_DIR )) { air_opterr("Output is not a directory"); } /* Options check out; daemonize */ if (!fd_nodaemon) { if (!daemonize()) { goto end; } } while (1) { /* Evaluate glob expression */ grc = glob(fd_inspec, 0, NULL, &gbuf); if (grc == GLOB_NOSPACE) { g_error("Out of memory: glob allocation failure"); } #ifdef GLOB_NOMATCH /* HaX0riffic! Simulate behavior without NOMATCH where we have it. */ else if (grc == GLOB_NOMATCH) { gbuf.gl_pathc = 0; gbuf.gl_pathv = NULL; } #endif /* Iterate over glob paths, enqueueing. */ for (i = 0; i < gbuf.gl_pathc; i++) { char **child_envp = {NULL}; GError *child_err = NULL; GString *filename_in = NULL; GString *filename_out = NULL; GString *filename_lock = NULL; GIOChannel *file_in = NULL; GIOChannel *file_out = NULL; GIOChannel *child_stdin = NULL; gint child_stdin_fd = -1; GIOChannel *child_stdout = NULL; gint child_stdout_fd = -1; GPid child_pid; int len; fd_read_data_t read_data; fd_write_data_t write_data; filename_in = g_string_new(gbuf.gl_pathv[i]); /* Skip non-regular files */ if (!g_file_test(filename_in->str, G_FILE_TEST_IS_REGULAR) ) { g_string_free(filename_in, TRUE); continue; } /* Skip lockfiles */ if (!strcmp(".lock", filename_in->str + strlen(filename_in->str) - 5)) { g_string_free(filename_in, TRUE); continue; } /* Generate lock path */ if (!filename_lock) filename_lock = g_string_new(""); g_string_printf(filename_lock, "%s.lock", filename_in->str); /* Skip files locked at queue time */ if (g_file_test(filename_lock->str, G_FILE_TEST_IS_REGULAR)) { g_debug("file %s is locked", filename_in->str); g_string_free(filename_in, TRUE); g_string_free(filename_lock, TRUE); continue; } if (child_args->len == 1) { /* Do move or delete */ GString *destpath = g_string_new(""); char *dbase = NULL; /* Calculate move destination path */ dbase = g_path_get_basename(filename_in->str); g_string_printf(destpath, "%s/%s", fd_nextdir, dbase); if (dbase) free(dbase); /* Do link */ g_message("moving %s -> %s", filename_in->str, fd_nextdir); if (link(filename_in->str, destpath->str) < 0) g_critical( "error moving input file to destination directory: %s", strerror(errno)); /* Do delete */ if (unlink(filename_in->str) < 0) { g_critical("error deleting input file"); } g_string_free(destpath, TRUE); g_string_free(filename_in, TRUE); g_string_free(filename_lock, TRUE); continue; } if (fd_lock) { fd_lock_file(filename_in->str); } file_in = g_io_channel_new_file(filename_in->str, "r", &err); if (file_in == NULL) { g_critical("Cannot open input file!"); } g_io_channel_set_encoding(file_in, NULL, &err); if (err) { g_critical("error setting input encoding!"); } g_io_channel_set_buffer_size(file_in, fd_bufsize); filename_out = g_string_new(""); if (fd_outspec == NULL) { g_string_printf(filename_out, "%s", gbuf.gl_pathv[i]); } else { g_string_printf(filename_out, "%s/%s", fd_outspec, gbuf.gl_pathv[i]); } len = filename_out->len; if (g_strrstr(filename_out->str, ".")) { while (len-- > 0 && !g_str_has_suffix(filename_out->str, ".") ) { g_string_set_size(filename_out, filename_out->len - 1); } g_string_set_size(filename_out, filename_out->len - 1); } if (fd_outext) { g_string_append_printf(filename_out, ".%s", fd_outext); } else { g_string_append(filename_out, ".out"); } g_message("%d: %s -> %s", i, filename_in->str, filename_out->str); file_out = g_io_channel_new_file(filename_out->str, "w", &err); if (file_out == NULL) { g_error("Cannot open output file!"); } g_io_channel_set_encoding(file_out, NULL, &err); if (err) { g_error("error setting output encoding!"); } g_io_channel_set_buffer_size(file_out, fd_bufsize); if (!g_spawn_async_with_pipes(".", (gchar **) child_args->pdata, child_envp, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &child_pid, &child_stdin_fd, &child_stdout_fd, NULL, &child_err)) { g_error("error spawning process: %s", (child_err && child_err->message ? child_err-> message : "unknown error")); } g_debug("spawned process %d", i); /* Watch for process exit status */ g_child_watch_add(child_pid, on_child_exit, filename_in->str); child_stdin = g_io_channel_unix_new(child_stdin_fd); if (child_stdin == NULL) { g_error("Cannot open child stdin!"); } g_io_channel_set_encoding(child_stdin, NULL, &err); if (err) { g_error("error setting child stdin encoding!"); } g_io_channel_set_buffer_size(child_stdin, fd_bufsize); child_stdout = g_io_channel_unix_new(child_stdout_fd); if (child_stdout == NULL) { g_error("Cannot open child stdout!"); } g_io_channel_set_encoding(child_stdout, NULL, &err); if (err) { g_error("error setting child stdout encoding!"); } g_io_channel_set_buffer_size(child_stdout, fd_bufsize); write_data.infile = file_in; write_data.buf = g_malloc(g_io_channel_get_buffer_size(file_in)); if (write_data.buf == NULL) { g_error("error allocating file_in buffer"); } if (!g_io_add_watch(child_stdin, G_IO_OUT | G_IO_PRI | G_IO_HUP | G_IO_ERR, write_to_child, &write_data)) g_error("Cannot add watch on GIOChannel!"); read_data.outfile = file_out; read_data.loop = loop; read_data.buf = g_malloc(g_io_channel_get_buffer_size(file_out)); if (write_data.buf == NULL) { g_error("error allocating file_in buffer"); } if (!g_io_add_watch(child_stdout, G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR, read_from_child, &read_data)) g_error("Cannot add watch on GIOChannel!"); g_main_loop_run(loop); if (fd_lock) { fd_unlock_file(filename_in->str); } if (read_data.buf) { g_free(read_data.buf); } if (write_data.buf) { g_free(write_data.buf); } g_string_free(filename_in, TRUE); g_string_free(filename_out, TRUE); g_string_free(filename_lock, TRUE); } sleep(fd_poll_delay); } end: return 0; }
static gboolean exec_skype() { #ifdef INSTANTBIRD return FALSE; #else GError *error; #ifdef USE_XVFB_SERVER PurpleAccount *acct = NULL; int skype_stdin; gchar **skype_list; gchar *command; if (!getenv("SKYPEDISPLAY")) setenv("SKYPEDISPLAY", ":25", 0); unsetenv("DBUS_SESSION_BUS_ADDRESS"); command = g_strconcat("Xvfb ", //"Xnest ", //Uncomment if using Xnest getenv("SKYPEDISPLAY"), " -ac -terminate -tst -xinerama", " -render -shmem -screen 0 320x240x16", //Dont use me if using Xnest NULL); if (g_spawn_command_line_async(command, NULL)) { acct = skype_get_account(NULL); skype_debug_info("skype_x11", "acct: %d\n", acct); if (acct && acct->username && acct->username[0] != '\0' && acct->password && acct->password[0] != '\0') { g_free(command); command = g_strconcat("skype --pipelogin -display ", getenv("SKYPEDISPLAY"), NULL); g_shell_parse_argv(command, NULL, &skype_list, NULL); if (g_spawn_async_with_pipes(NULL, skype_list, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &skype_stdin, NULL, NULL, NULL)) { g_strfreev(skype_list); write(skype_stdin, acct->username, strlen(acct->username)); write(skype_stdin, " ", 1); write(skype_stdin, acct->password, strlen(acct->password)); write(skype_stdin, "\n", 1); fsync(skype_stdin); skype_debug_info("skype_x11", "pipelogin worked\n"); g_free(command); return TRUE; } g_strfreev(skype_list); } } g_free(command); #endif if (g_spawn_command_line_async("skype --disable-cleanlooks", &error)) { return TRUE; } else { skype_debug_error("skype", "Could not start skype: %s\n", error->message); return FALSE; } #endif }
int main (int argc, char **argv) { const PangoViewer *view; gpointer instance; PangoContext *context; int run; int width, height; gpointer surface; g_type_init(); setlocale (LC_ALL, ""); parse_options (argc, argv); view = opt_viewer; g_assert (view->id); instance = view->create (view); context = view->get_context (instance); do_output (context, NULL, NULL, NULL, NULL, &width, &height); surface = view->create_surface (instance, width, height); for (run = 0; run < MAX(1,opt_runs); run++) view->render (instance, surface, context, width, height, NULL); if (opt_output) { if (!view->write) fail ("%s viewer backend does not support writing", view->name); else { FILE *stream; if (view->write_suffix && g_str_has_suffix (opt_output, view->write_suffix)) { stream = g_fopen (opt_output, "wb"); if (!stream) fail ("Cannot open output file %s: %s\n", opt_output, g_strerror (errno)); } else { int fd; const gchar *convert_argv[4] = {"convert", "-", "%s"}; GError *error; convert_argv[2] = opt_output; if (!g_spawn_async_with_pipes (NULL, (gchar **)convert_argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, NULL, &fd, NULL, NULL, &error)) fail ("When running ImageMagick 'convert' command: %s\n", error->message); stream = fdopen (fd, "wb"); } view->write (instance, surface, stream, width, height); fclose (stream); } } if (opt_display) { char *title; title = get_options_string (); if (view->display) { gpointer window = NULL; gpointer state = NULL; if (view->create_window) window = view->create_window (instance, title, width, height); while (1) { state = view->display (instance, surface, window, width, height, state); if (!state) break; view->render (instance, surface, context, width, height, state); } if (view->destroy_window) view->destroy_window (instance, window); } else { int fd; FILE *stream; const gchar *display_argv[5] = {"display", "-title", "%s", "-"}; GError *error = NULL; GPid pid; if (!view->write) fail ("%s viewer backend does not support displaying or writing", view->name); display_argv[2] = title; if (!g_spawn_async_with_pipes (NULL, (gchar **)display_argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &pid, &fd, NULL, NULL, &error)) fail ("When running ImageMagick 'display' command: %s\n", error->message); stream = fdopen (fd, "wb"); view->write (instance, surface, stream, width, height); fclose (stream); #ifdef G_OS_UNIX waitpid (pid, NULL, 0); #endif g_spawn_close_pid (pid); } g_free (title); } view->destroy_surface (instance, surface); g_object_unref (context); view->destroy (instance); finalize (); return 0; }
static void display_fortune_dialog (FishApplet *fish) { GError *error = NULL; gboolean user_command; int output; const char *charset; int argc; char **argv; GdkScreen *screen; char *display; /* if there is still a pipe, close it */ if (fish->source_id) g_source_remove (fish->source_id); fish->source_id = 0; fish_close_channel (fish); user_command = locate_fortune_command (fish, &argc, &argv); if (!argv) return; if (!fish->fortune_dialog) { GtkWidget *scrolled; GtkWidget *vbox; GdkScreen *screen; int screen_width; int screen_height; fish->fortune_dialog = gtk_dialog_new_with_buttons ( "", NULL, 0, _("_Speak again"), FISH_RESPONSE_SPEAK, _("_Close"), GTK_RESPONSE_CLOSE, NULL); gtk_window_set_icon_name (GTK_WINDOW (fish->fortune_dialog), FISH_ICON); gtk_dialog_set_default_response ( GTK_DIALOG (fish->fortune_dialog), GTK_RESPONSE_CLOSE); g_signal_connect (fish->fortune_dialog, "delete_event", G_CALLBACK (delete_event), fish); g_signal_connect (fish->fortune_dialog, "response", G_CALLBACK (handle_fortune_response), fish); gtk_window_set_wmclass (GTK_WINDOW (fish->fortune_dialog), "fish", "Fish"); screen = gtk_widget_get_screen (GTK_WIDGET (fish)); screen_width = gdk_screen_get_width (screen); screen_height = gdk_screen_get_height (screen); gtk_window_set_default_size (GTK_WINDOW (fish->fortune_dialog), MIN (600, screen_width * 0.9), MIN (350, screen_height * 0.9)); fish->fortune_view = gtk_text_view_new (); gtk_text_view_set_editable (GTK_TEXT_VIEW (fish->fortune_view), FALSE); gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (fish->fortune_view), FALSE); gtk_text_view_set_left_margin (GTK_TEXT_VIEW (fish->fortune_view), 10); gtk_text_view_set_right_margin (GTK_TEXT_VIEW (fish->fortune_view), 10); fish->fortune_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (fish->fortune_view)); gtk_text_buffer_create_tag (GTK_TEXT_BUFFER (fish->fortune_buffer), "monospace_tag", "family", "Monospace", NULL); scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), GTK_SHADOW_IN); gtk_container_add (GTK_CONTAINER (scrolled), fish->fortune_view); fish->fortune_label = gtk_label_new (""); gtk_label_set_ellipsize (GTK_LABEL (fish->fortune_label), PANGO_ELLIPSIZE_MIDDLE); fish->fortune_cmd_label = gtk_label_new (""); gtk_misc_set_alignment (GTK_MISC (fish->fortune_cmd_label), 0, 0.5); vbox = gtk_dialog_get_content_area (GTK_DIALOG (fish->fortune_dialog)); gtk_box_pack_start (GTK_BOX (vbox), fish->fortune_label, FALSE, FALSE, 6); gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 6); gtk_box_pack_start (GTK_BOX (vbox), fish->fortune_cmd_label, FALSE, FALSE, 6); update_fortune_dialog (fish); /* We don't show_all for the dialog since fortune_cmd_label * might need to be hidden * The dialog will be shown with gtk_window_present later */ gtk_widget_show (scrolled); gtk_widget_show (fish->fortune_view); gtk_widget_show (fish->fortune_label); } if (!user_command) { char *command; char * text; command = g_markup_printf_escaped ("<tt>%s</tt>", argv[0]); text = g_strdup_printf (_("The configured command is not " "working and has been replaced by: " "%s"), command); gtk_label_set_markup (GTK_LABEL (fish->fortune_cmd_label), text); g_free (command); g_free (text); gtk_widget_show (fish->fortune_cmd_label); } else { gtk_widget_hide (fish->fortune_cmd_label); } clear_fortune_text (fish); screen = gtk_widget_get_screen (GTK_WIDGET (fish)); display = gdk_screen_make_display_name (screen); g_spawn_async_with_pipes (NULL, /* working directory */ argv, NULL, /* envp */ G_SPAWN_SEARCH_PATH|G_SPAWN_STDERR_TO_DEV_NULL, set_environment, &display, NULL, /* child pid */ NULL, /* stdin */ &output, NULL, /* stderr */ &error); g_free (display); if (error) { char *message; message = g_strdup_printf (_("Unable to execute '%s'\n\nDetails: %s"), argv[0], error->message); something_fishy_going_on (fish, message); g_free (message); g_error_free (error); g_strfreev (argv); return; } fish->io_channel = g_io_channel_unix_new (output); /* set the correct encoding if the locale is not using UTF-8 */ if (!g_get_charset (&charset)) g_io_channel_set_encoding(fish->io_channel, charset, &error); if (error) { char *message; message = g_strdup_printf (_("Unable to read from '%s'\n\nDetails: %s"), argv[0], error->message); something_fishy_going_on (fish, message); g_free (message); g_error_free (error); g_strfreev (argv); return; } g_strfreev (argv); fish->source_id = g_io_add_watch (fish->io_channel, G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, fish_read_output, fish); gtk_window_set_screen (GTK_WINDOW (fish->fortune_dialog), gtk_widget_get_screen (GTK_WIDGET (fish))); gtk_window_present (GTK_WINDOW (fish->fortune_dialog)); }
/// Reads from espeak's stdout. static gpointer worker (WorkerData *data) { // Spawn eSpeak GError *error = NULL; gint child_in, child_out; if (!g_spawn_async_with_pipes (NULL, data->cmdline, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &child_in, &child_out, NULL, &error)) g_error ("g_spawn() failed: %s", error->message); data->child_stdin = fdopen (child_in, "wb"); if (!data->child_stdin) perror ("fdopen"); FILE *child_stdout = fdopen (child_out, "rb"); if (!child_stdout) perror ("fdopen"); // Spawn a writer thread g_mutex_lock (data->dict_mutex); data->iterator = stardict_iterator_new (data->dict, data->start_entry); g_mutex_unlock (data->dict_mutex); GThread *writer = g_thread_new ("write worker", (GThreadFunc) worker_writer, data); // Read the output g_mutex_lock (data->remaining_mutex); guint32 remaining = data->remaining; g_mutex_unlock (data->remaining_mutex); data->output = NULL; gpointer *output_end = &data->output; while (remaining) { static gchar next[sizeof (gpointer)]; GString *s = g_string_new (NULL); g_string_append_len (s, next, sizeof next); gint c; while ((c = fgetc (child_stdout)) != EOF && c != '\n') g_string_append_c (s, c); if (c == EOF) g_error ("eSpeak process died too soon"); gchar *translation = g_string_free (s, FALSE); *output_end = translation; output_end = (gpointer *) translation; // We limit progress reporting so that // the mutex doesn't spin like crazy if ((--remaining & 255) != 0) continue; g_mutex_lock (data->remaining_mutex); data->remaining = remaining; g_cond_broadcast (data->remaining_cond); g_mutex_unlock (data->remaining_mutex); } if (fgetc (child_stdout) != EOF) { g_printerr ("Error: eSpeak has written more lines than it should. " "The output would be corrupt, aborting.\n"); exit (EXIT_FAILURE); } fclose (child_stdout); return g_thread_join (writer); }
gboolean ck_job_execute (CkJob *job, GError **error) { GError *local_error; gboolean res; GIOChannel *channel; int standard_output; int standard_error; int argc; char **argv; g_debug ("Executing %s", job->priv->command); local_error = NULL; if (! g_shell_parse_argv (job->priv->command, &argc, &argv, &local_error)) { g_debug ("Could not parse command: %s", local_error->message); g_propagate_error (error, local_error); return FALSE; } local_error = NULL; res = g_spawn_async_with_pipes (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &job->priv->child_pid, NULL, &standard_output, &standard_error, &local_error); g_strfreev (argv); if (! res) { g_debug ("Could not start command '%s': %s", job->priv->command, local_error->message); g_propagate_error (error, local_error); return FALSE; } /* output channel */ channel = g_io_channel_unix_new (standard_output); g_io_channel_set_close_on_unref (channel, TRUE); g_io_channel_set_flags (channel, g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK, NULL); job->priv->out_watch_id = g_io_add_watch (channel, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)out_watch, job); g_io_channel_unref (channel); /* error channel */ channel = g_io_channel_unix_new (standard_error); g_io_channel_set_close_on_unref (channel, TRUE); g_io_channel_set_flags (channel, g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK, NULL); job->priv->err_watch_id = g_io_add_watch (channel, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)error_watch, job); g_io_channel_unref (channel); return res; }
/** * connman_task_run: * @task: task structure * @function: exit callback * @user_data: optional exit user data * @fd: optional spawn with pipe * * Execute program specified by #task */ int connman_task_run(struct connman_task *task, connman_task_exit_t function, void *user_data, int *stdin_fd, int *stdout_fd, int *stderr_fd) { GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD; bool result; char **argv, **envp; DBG("task %p", task); if (task->pid > 0) return -EALREADY; if (!stdout_fd) flags |= G_SPAWN_STDOUT_TO_DEV_NULL; if (!stderr_fd) flags |= G_SPAWN_STDERR_TO_DEV_NULL; task->exit_func = function; task->exit_data = user_data; if (g_ptr_array_index(task->argv, task->argv->len - 1)) g_ptr_array_add(task->argv, NULL); if (task->envp->len == 0 || g_ptr_array_index(task->envp, task->envp->len - 1)) { if (g_hash_table_size(task->notify) > 0) { const char *busname; char *str; busname = dbus_bus_get_unique_name(connection); str = g_strdup_printf("CONNMAN_BUSNAME=%s", busname); g_ptr_array_add(task->envp, str); str = g_strdup_printf("CONNMAN_INTERFACE=%s", CONNMAN_TASK_INTERFACE); g_ptr_array_add(task->envp, str); str = g_strdup_printf("CONNMAN_PATH=%s", task->path); g_ptr_array_add(task->envp, str); } g_ptr_array_add(task->envp, NULL); } argv = (char **) task->argv->pdata; envp = (char **) task->envp->pdata; result = g_spawn_async_with_pipes(NULL, argv, envp, flags, task_setup, task, &task->pid, stdin_fd, stdout_fd, stderr_fd, NULL); if (!result) { connman_error("Failed to spawn %s", argv[0]); return -EIO; } task->child_watch = g_child_watch_add(task->pid, task_died, task); return 0; }
int main(int argc, char** argv) { GError *err = NULL; GMappedFile *map; char *buf = NULL, *pbuf = NULL, *data = NULL, *end; gsize len = 0; char *extract_path; gtk_init( &argc, &argv ); /* load the executable file itself */ map = g_mapped_file_new( argv[0], FALSE, NULL ); if( !map ) return 1; buf = g_mapped_file_get_contents(map); len = g_mapped_file_get_length( map ); /* find the data */ magic[0] = '_'; for( pbuf = buf, end = buf + len - magic_len; G_LIKELY( pbuf < end ); ++pbuf ) { if( G_UNLIKELY( 0 == memcmp( pbuf, magic, magic_len ) ) ) { data = pbuf + magic_len + 1; break; } } if( G_UNLIKELY( ! data ) ) { g_mapped_file_free( map ); show_error( "檔案損毀,請重新下載。" ); return 1; /* error! no data found */ } len -= (data - buf); /* skip ourself */ extract_path = g_strconcat( "/tmp/Lazybuntu-", g_get_user_name(), NULL ); g_mkdir_with_parents( extract_path, 0755 ); /* FIXME: is 0755 OK? */ cmdv[3] = extract_path; if( g_spawn_async_with_pipes( NULL, cmdv, NULL, G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &std_in, NULL, NULL, &err ) ) { int status = 0; write( std_in, data, len ); close( std_in ); waitpid( pid, &status, 0 ); g_spawn_close_pid( pid ); } else { show_error( err->message ); g_error_free( err ); } g_mapped_file_free( map ); g_chdir( extract_path ); g_free( extract_path ); g_chdir( "Lazybuntu" ); execl( "Lazybuntu", NULL ); show_error("錯誤,無法執行 Lazybuntu!"); return 0; }
static void execute_current_command (ExecuteData *exec_data) { FrProcess *process = exec_data->process; FrCommandInfo *info; GList *scan; char **argv; int out_fd, err_fd; int i = 0; GError *error; debug (DEBUG_INFO, "%d/%d) ", process->priv->current_command, process->priv->n_comm); info = g_ptr_array_index (process->priv->comm, process->priv->current_command); argv = g_new (char *, g_list_length (info->args) + 1); for (scan = info->args; scan; scan = scan->next) argv[i++] = scan->data; argv[i] = NULL; #ifdef DEBUG { int j; if (process->priv->use_standard_locale) g_print ("\tLC_MESSAGES=C\n"); if (info->dir != NULL) g_print ("\tcd %s\n", info->dir); if (info->ignore_error) g_print ("\t[ignore error]\n"); g_print ("\t"); for (j = 0; j < i; j++) g_print ("%s ", argv[j]); g_print ("\n"); } #endif if (info->begin_func != NULL) (*info->begin_func) (info->begin_data); if (! g_spawn_async_with_pipes (info->dir, argv, NULL, (G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD), child_setup, process, &process->priv->command_pid, NULL, &out_fd, &err_fd, &error)) { exec_data->error = fr_error_new (FR_ERROR_SPAWN, 0, error); _fr_process_execute_complete_in_idle (exec_data); g_error_free (error); g_free (argv); return; } g_free (argv); fr_channel_data_set_fd (&process->out, out_fd, _fr_process_get_charset (process)); fr_channel_data_set_fd (&process->err, err_fd, _fr_process_get_charset (process)); process->priv->check_timeout = g_timeout_add (REFRESH_RATE, check_child, exec_data); }
/* * __vte_pty_spawn: * @pty: a #VtePty * @directory: the name of a directory the command should start in, or %NULL * to use the cwd * @argv: child's argument vector * @envv: a list of environment variables to be added to the environment before * starting the process, or %NULL * @spawn_flags: flags from #GSpawnFlags * @child_setup: function to run in the child just before exec() * @child_setup_data: user data for @child_setup * @child_pid: a location to store the child PID, or %NULL * @error: return location for a #GError, or %NULL * * Uses g_spawn_async() to spawn the command in @argv. The child's environment will * be the parent environment with the variables in @envv set afterwards. * * Enforces the vte_terminal_watch_child() requirements by adding * %G_SPAWN_DO_NOT_REAP_CHILD to @spawn_flags. * * Note that the %G_SPAWN_LEAVE_DESCRIPTORS_OPEN flag is not supported; * it will be cleared! * * If spawning the command in @working_directory fails because the child * is unable to chdir() to it, falls back trying to spawn the command * in the parent's working directory. * * Returns: %TRUE on success, or %FALSE on failure with @error filled in */ gboolean __vte_pty_spawn (VtePty *pty, const char *directory, char **argv, char **envv, GSpawnFlags spawn_flags, GSpawnChildSetupFunc child_setup, gpointer child_setup_data, GPid *child_pid /* out */, GError **error) { VtePtyPrivate *priv = pty->priv; VtePtyChildSetupData *data = &priv->child_setup_data; gboolean ret = TRUE; gboolean inherit_envv; char **envp2; gint i; GError *err = NULL; spawn_flags |= G_SPAWN_DO_NOT_REAP_CHILD; /* FIXMEchpe: Enforce this until I've checked our code to make sure * it doesn't leak out internal FDs into the child this way. */ spawn_flags &= ~G_SPAWN_LEAVE_DESCRIPTORS_OPEN; inherit_envv = (spawn_flags & VTE_SPAWN_NO_PARENT_ENVV) == 0; spawn_flags &= ~VTE_SPAWN_NO_PARENT_ENVV; /* add the given environment to the childs */ envp2 = __vte_pty_merge_environ (envv, inherit_envv); _VTE_DEBUG_IF (VTE_DEBUG_MISC) { g_printerr ("Spawing command:\n"); for (i = 0; argv[i] != NULL; i++) { g_printerr (" argv[%d] = %s\n", i, argv[i]); } for (i = 0; envp2[i] != NULL; i++) { g_printerr (" env[%d] = %s\n", i, envp2[i]); } g_printerr (" directory: %s\n", directory ? directory : "(none)"); } data->extra_child_setup = child_setup; data->extra_child_setup_data = child_setup_data; ret = g_spawn_async_with_pipes(directory, argv, envp2, spawn_flags, (GSpawnChildSetupFunc) vte_pty_child_setup, pty, child_pid, NULL, NULL, NULL, &err); if (!ret && directory != NULL && g_error_matches(err, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR)) { /* try spawning in our working directory */ g_clear_error(&err); ret = g_spawn_async_with_pipes(NULL, argv, envp2, spawn_flags, (GSpawnChildSetupFunc) vte_pty_child_setup, pty, child_pid, NULL, NULL, NULL, &err); } g_strfreev (envp2); data->extra_child_setup = NULL; data->extra_child_setup_data = NULL; if (ret) return TRUE; g_propagate_error (error, err); return FALSE; }
/* * starts gdb, collects commands and start the first one */ static gboolean run(const gchar* file, const gchar* commandline, GList* env, GList *witer, GList *biter, const gchar* terminal_device, dbg_callbacks* callbacks) { GError *err = NULL; const gchar *exclude[] = { "LANG", NULL }; gchar **gdb_env = utils_copy_environment(exclude, "LANG", "C", NULL); gchar *working_directory = g_path_get_dirname(file); GList *lines, *iter; GList *commands = NULL; GString *command; int bp_index; queue_item *item; dbg_cbs = callbacks; /* spawn GDB */ if (!g_spawn_async_with_pipes(working_directory, (gchar**)gdb_args, gdb_env, GDB_SPAWN_FLAGS, NULL, NULL, &gdb_pid, &gdb_in, &gdb_out, NULL, &err)) { dbg_cbs->report_error(_("Failed to spawn gdb process")); g_free(working_directory); g_strfreev(gdb_env); return FALSE; } g_free(working_directory); g_strfreev(gdb_env); /* move gdb to it's own process group */ setpgid(gdb_pid, 0); /* set handler for gdb process exit event */ gdb_src_id = g_child_watch_add(gdb_pid, on_gdb_exit, NULL); /* create GDB GIO chanels */ gdb_ch_in = g_io_channel_unix_new(gdb_in); gdb_ch_out = g_io_channel_unix_new(gdb_out); /* reading starting gdb messages */ lines = read_until_prompt(); for (iter = lines; iter; iter = iter->next) { gchar *unescaped = g_strcompress((gchar*)iter->data); if (strlen(unescaped)) { colorize_message((gchar*)iter->data); } } g_list_foreach(lines, (GFunc)g_free, NULL); g_list_free(lines); /* add initial watches to the list */ while (witer) { gchar *name = (gchar*)witer->data; variable *var = variable_new(name, VT_WATCH); watches = g_list_append(watches, var); witer = witer->next; } /* collect commands */ /* loading file */ command = g_string_new(""); g_string_printf(command, "-file-exec-and-symbols \"%s\"", file); commands = add_to_queue(commands, _("~\"Loading target file.\\n\""), command->str, _("Error loading file"), FALSE); g_string_free(command, TRUE); /* setting asyncronous mode */ commands = add_to_queue(commands, NULL, "-gdb-set target-async 1", _("Error configuring GDB"), FALSE); /* setting null-stop array printing */ commands = add_to_queue(commands, NULL, "-interpreter-exec console \"set print null-stop\"", _("Error configuring GDB"), FALSE); /* enable pretty printing */ commands = add_to_queue(commands, NULL, "-enable-pretty-printing", _("Error configuring GDB"), FALSE); /* set locale */ command = g_string_new(""); g_string_printf(command, "-gdb-set environment LANG=%s", g_getenv("LANG")); commands = add_to_queue(commands, NULL, command->str, NULL, FALSE); g_string_free(command, TRUE); /* set arguments */ command = g_string_new(""); g_string_printf(command, "-exec-arguments %s", commandline); commands = add_to_queue(commands, NULL, command->str, NULL, FALSE); g_string_free(command, TRUE); /* set passed evironment */ iter = env; while (iter) { gchar *name, *value; name = (gchar*)iter->data; iter = iter->next; value = (gchar*)iter->data; command = g_string_new(""); g_string_printf(command, "-gdb-set environment %s=%s", name, value); commands = add_to_queue(commands, NULL, command->str, NULL, FALSE); g_string_free(command, TRUE); iter = iter->next; } /* set breaks */ bp_index = 1; while (biter) { breakpoint *bp = (breakpoint*)biter->data; GString *error_message = g_string_new(""); command = g_string_new(""); g_string_printf(command, "-break-insert -f \"\\\"%s\\\":%i\"", bp->file, bp->line); g_string_printf(error_message, _("Breakpoint at %s:%i cannot be set\nDebugger message: %s"), bp->file, bp->line, "%s"); commands = add_to_queue(commands, NULL, command->str, error_message->str, TRUE); g_string_free(command, TRUE); if (bp->hitscount) { command = g_string_new(""); g_string_printf(command, "-break-after %i %i", bp_index, bp->hitscount); commands = add_to_queue(commands, NULL, command->str, error_message->str, TRUE); g_string_free(command, TRUE); } if (strlen(bp->condition)) { command = g_string_new(""); g_string_printf (command, "-break-condition %i %s", bp_index, bp->condition); commands = add_to_queue(commands, NULL, command->str, error_message->str, TRUE); g_string_free(command, TRUE); } if (!bp->enabled) { command = g_string_new(""); g_string_printf (command, "-break-disable %i", bp_index); commands = add_to_queue(commands, NULL, command->str, error_message->str, TRUE); g_string_free(command, TRUE); } g_string_free(error_message, TRUE); bp_index++; biter = biter->next; } /* set debugging terminal */ command = g_string_new("-inferior-tty-set "); g_string_append(command, terminal_device); commands = add_to_queue(commands, NULL, command->str, NULL, FALSE); g_string_free(command, TRUE); /* connect read callback to the output chanel */ gdb_id_out = g_io_add_watch(gdb_ch_out, G_IO_IN, on_read_async_output, commands); item = (queue_item*)commands->data; /* send message to debugger messages window */ if (item->message) { dbg_cbs->send_message(item->message->str, "grey"); } /* send first command */ gdb_input_write_line(item->command->str); return TRUE; }
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 (pipe (report_pipe) < 0) { if (subtest_mode_fatal) g_error ("Failed to open pipe for test binary: %s: %s", binary, g_strerror (errno)); else g_warning ("Failed to open pipe for test binary: %s: %s", binary, g_strerror (errno)); 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++; if (subtest_mode_quick) argc++; else argc++; if (subtest_mode_perf) argc++; if (gtester_list_tests) argc++; if (subtest_seedstr) argc++; argc++; if (skip_tests) argc++; for (slist = subtest_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 (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)); 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); } g_source_remove (child_report_cb_id); close (report_pipe[0]); g_test_log_buffer_free (tlb); return TRUE; }
char * netstatus_sysdeps_read_iface_statistics (const char *iface, gulong *in_packets, gulong *out_packets, gulong *in_bytes, gulong *out_bytes) { GError *error; char *command_line; char **argv; char *error_message = NULL; int pipe_out; g_return_val_if_fail (iface != NULL, NULL); g_return_val_if_fail (in_packets != NULL, NULL); g_return_val_if_fail (out_packets != NULL, NULL); g_return_val_if_fail (in_bytes != NULL, NULL); g_return_val_if_fail (out_bytes != NULL, NULL); *in_packets = -1; *out_packets = -1; *in_bytes = -1; *out_bytes = -1; error = NULL; command_line = g_strdup_printf ("/usr/bin/netstat -n -I %s -b -f inet", iface); if (!g_shell_parse_argv (command_line, NULL, &argv, &error)) { error_message = g_strdup_printf (_("Could not parse command line '%s': %s"), command_line, error->message); g_error_free (error); g_free (command_line); return error_message; } g_free (command_line); error = NULL; if (g_spawn_async_with_pipes (NULL, argv, NULL, 0, NULL, NULL, NULL, NULL, &pipe_out, NULL, &error)) { GIOChannel *channel; char *buf; int prx_idx, ptx_idx; int brx_idx, btx_idx; channel = g_io_channel_unix_new (pipe_out); g_io_channel_read_line (channel, &buf, NULL, NULL, NULL); parse_header (buf, &prx_idx, &ptx_idx, &brx_idx, &btx_idx); g_free (buf); if (prx_idx == -1 || ptx_idx == -1 || brx_idx == -1 || btx_idx == -1) { error_message = g_strdup (_("Could not parse 'netstat' output. Unknown format")); goto error_shutdown; } g_io_channel_read_line (channel, &buf, NULL, NULL, NULL); if (!parse_stats (buf, prx_idx, ptx_idx, in_packets, out_packets, brx_idx, btx_idx, in_bytes, out_bytes)) { error_message = g_strdup_printf (_("Could not parse interface statistics from '%s'. " "prx_idx = %d; ptx_idx = %d; brx_idx = %d; btx_idx = %d;"), buf, prx_idx, ptx_idx, brx_idx, btx_idx); } else if (*in_packets == -1 || *out_packets == -1 || *in_bytes == -1 || *out_bytes == -1) { error_message = g_strdup_printf ("Could not obtain information on interface '%s' from netstat", iface); } g_free (buf); error_shutdown: g_io_channel_unref (channel); close (pipe_out); } else { error_message = g_strdup_printf ("Error running /usr/bin/netstat for '%s': %s", iface, error->message); g_error_free (error); } g_strfreev (argv); return error_message; }
/** * Execute synchronously an external command, read its output and invoke * a user-provided filter function on every line of it. */ int execute_shell_command(char **cmd, parse_cb_t cb_func, void *cb_arg) { struct exec_ctx ctx = { 0 }; GPid pid; GError *err_desc = NULL; GSpawnFlags flags = G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD; GIOChannel *out_chan = NULL; GIOChannel *err_chan = NULL; struct io_chan_arg out_args; struct io_chan_arg err_args; char *log_cmd; int p_stdout; int p_stderr; bool success; int rc = 0; ctx.gctx = g_main_context_new(); g_main_context_push_thread_default(ctx.gctx); ctx.loop = g_main_loop_new(ctx.gctx, false); ctx.ref = 0; ctx.rc = 0; DisplayLog(LVL_DEBUG, TAG, "Spawning external command \"%s\"", cmd[0]); success = g_spawn_async_with_pipes(NULL, /* Working dir */ cmd, /* Parameters */ NULL, /* Environment */ flags, /* Execution directives */ NULL, /* Child setup function */ NULL, /* Child setup arg */ &pid, /* Child PID */ NULL, /* STDIN (unused) */ cb_func ? &p_stdout : NULL, /* STDOUT */ cb_func ? &p_stderr : NULL, /* STDERR */ &err_desc); if (!success) { rc = -ECHILD; log_cmd = concat_cmd(cmd); DisplayLog(LVL_MAJOR, TAG, "Failed to execute \"%s\": %s", log_cmd, err_desc->message); free(log_cmd); goto out_free; } /* register a watcher in the loop, thus increase refcount of our exec_ctx */ ctx_incref(&ctx); g_child_watch_add_tothread(pid, watch_child_cb, &ctx); if (cb_func != NULL) { out_args.ident = STDOUT_FILENO; out_args.cb = cb_func; out_args.udata = cb_arg; out_args.exec_ctx = &ctx; err_args.ident = STDERR_FILENO; err_args.cb = cb_func; err_args.udata = cb_arg; err_args.exec_ctx = &ctx; out_chan = g_io_channel_unix_new(p_stdout); err_chan = g_io_channel_unix_new(p_stderr); /* instruct the refcount system to close the channels when unused */ g_io_channel_set_close_on_unref(out_chan, true); g_io_channel_set_close_on_unref(err_chan, true); if ((rc = iochan_null_enc(out_chan)) || (rc = iochan_null_enc(err_chan))) goto out_free; /* update refcount for the two watchers */ ctx_incref(&ctx); ctx_incref(&ctx); g_io_add_watch_tothread(out_chan, G_IO_IN | G_IO_HUP, readline_cb, &out_args); g_io_add_watch_tothread(err_chan, G_IO_IN | G_IO_HUP, readline_cb, &err_args); } g_main_loop_run(ctx.loop); out_free: g_main_loop_unref(ctx.loop); g_main_context_pop_thread_default(ctx.gctx); g_main_context_unref(ctx.gctx); if (err_desc) g_error_free(err_desc); return rc ? rc : ctx.rc; }
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; }
static void exec_spawn_process (ExecCmd *e, GSpawnChildSetupFunc child_setup) { /* Make sure that the args are null terminated */ g_ptr_array_add(e->args, NULL); exec_print_cmd(e); gint std_out = 0, std_err = 0; GError *err = NULL; const GSpawnFlags flags = (GSpawnFlags) (G_SPAWN_SEARCH_PATH | G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_DO_NOT_REAP_CHILD); if (g_spawn_async_with_pipes(NULL, (gchar**) e->args->pdata, NULL, flags, child_setup, e, &e->pid, NULL, &std_out, &std_err, &err)) { g_debug("exec_spawn_process - spawed process with pid [" FMT_PID "]\n", e->pid); if (!e->piped) { GIOChannel* const char_out = g_io_channel_unix_new(std_out); g_io_channel_set_encoding(char_out, NULL, NULL); g_io_channel_set_buffered(char_out, FALSE); g_io_channel_set_flags(char_out, G_IO_FLAG_NONBLOCK, NULL); guint const chan_out_id = g_io_add_watch(char_out, (GIOCondition)(G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI | G_IO_NVAL), exec_channel_callback, (gpointer) e); GIOChannel* const chan_err = g_io_channel_unix_new(std_err); g_io_channel_set_encoding(chan_err, NULL, NULL); g_io_channel_set_buffered(chan_err, FALSE); g_io_channel_set_flags(chan_err, G_IO_FLAG_NONBLOCK, NULL); guint const chan_err_id = g_io_add_watch(chan_err, (GIOCondition)(G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI | G_IO_NVAL), exec_channel_callback, (gpointer) e); while (exec_cmd_get_state(e) == RUNNING) gtk_main_iteration(); g_source_remove(chan_out_id); g_source_remove(chan_err_id); g_io_channel_shutdown(char_out, FALSE, NULL); g_io_channel_unref(char_out); g_io_channel_shutdown(chan_err, FALSE, NULL); g_io_channel_unref(chan_err); } else { while ((waitpid(e->pid, &e->exit_code, WNOHANG) != -1) && (exec_cmd_get_state(e) == RUNNING)) g_usleep(500000); } /* If the process was cancelled then we kill off the child */ if (exec_cmd_get_state(e) == CANCELLED) { g_debug("exec_spawn_process - killing process with pid [" FMT_PID "]\n", e->pid); gint ret = kill(e->pid, SIGQUIT); g_debug("exec_spawn_process - SIGQUIT returned [%d]\n", ret); if (ret != 0) { ret = kill(e->pid, SIGTERM); g_debug("exec_spawn_process - SIGTERM returned [%d]\n", ret); if (ret != 0) { ret = kill(e->pid, SIGKILL); g_debug("exec_spawn_process - SIGKILL returned [%d]\n", ret); } } } /* Reap the child so we don't get a zombie */ waitpid(e->pid, &e->exit_code, 0); g_spawn_close_pid(e->pid); close(std_out); close(std_err); exec_cmd_set_state(e, (e->exit_code == 0) ? COMPLETED : FAILED); g_debug("exec_spawn_process - child [" FMT_PID "] exitcode [%d]\n", e->pid, e->exit_code); } else { if (err != NULL) g_warning("exec_spawn_process - failed to spawn process [%d] [%s]\n", err->code, err->message); exec_cmd_set_state(e, FAILED); if (err != NULL) g_error_free(err); } }
if (!spawn_parse_argv(command_line, &cl_argc, &cl_argv, error)) return FALSE; if (argv) for (argc = 0; argv[argc]; argc++); full_argv = g_renew(gchar *, cl_argv, cl_argc + argc + 1); memcpy(full_argv + cl_argc, argv, argc * sizeof(gchar *)); full_argv[cl_argc + argc] = NULL; } else full_argv = argv; spawned = g_spawn_async_with_pipes(working_directory, full_argv, envp, G_SPAWN_SEARCH_PATH | (child_pid ? G_SPAWN_DO_NOT_REAP_CHILD : 0), NULL, NULL, child_pid, stdin_fd, stdout_fd, stderr_fd, &gerror); if (!spawned) { gint en = 0; const gchar *message = gerror->message; /* try to cut glib citing of the program name or working directory: they may be long, and only the caller knows whether they're UTF-8. We lose the exact chdir error. */ switch (gerror->code) { #ifdef EACCES case G_SPAWN_ERROR_ACCES : en = EACCES; break; #endif #ifdef EPERM
void gvfs_udisks2_utils_spawn (guint timeout_seconds, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, const gchar *command_line_format, ...) { va_list var_args; SpawnData *data; GError *error; gint child_argc; gchar **child_argv = NULL; data = g_slice_new0 (SpawnData); data->simple = g_simple_async_result_new (NULL, callback, user_data, gvfs_udisks2_utils_spawn); data->main_context = g_main_context_get_thread_default (); if (data->main_context != NULL) g_main_context_ref (data->main_context); data->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL; va_start (var_args, command_line_format); data->command_line = g_strdup_vprintf (command_line_format, var_args); va_end (var_args); data->child_stdout = g_string_new (NULL); data->child_stderr = g_string_new (NULL); data->child_stdout_fd = -1; data->child_stderr_fd = -1; /* the life-cycle of SpawnData is tied to its GSimpleAsyncResult */ g_simple_async_result_set_op_res_gpointer (data->simple, data, (GDestroyNotify) spawn_data_free); error = NULL; if (data->cancellable != NULL) { /* could already be cancelled */ error = NULL; if (g_cancellable_set_error_if_cancelled (data->cancellable, &error)) { g_simple_async_result_take_error (data->simple, error); g_simple_async_result_complete_in_idle (data->simple); g_object_unref (data->simple); goto out; } data->cancellable_handler_id = g_cancellable_connect (data->cancellable, G_CALLBACK (on_cancelled), data, NULL); } error = NULL; if (!g_shell_parse_argv (data->command_line, &child_argc, &child_argv, &error)) { g_prefix_error (&error, "Error parsing command-line `%s': ", data->command_line); g_simple_async_result_take_error (data->simple, error); g_simple_async_result_complete_in_idle (data->simple); g_object_unref (data->simple); goto out; } error = NULL; if (!g_spawn_async_with_pipes (NULL, /* working directory */ child_argv, NULL, /* envp */ G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, /* child_setup */ NULL, /* child_setup's user_data */ &(data->child_pid), NULL, /* gint *stdin_fd */ &(data->child_stdout_fd), &(data->child_stderr_fd), &error)) { g_prefix_error (&error, "Error spawning command-line `%s': ", data->command_line); g_simple_async_result_take_error (data->simple, error); g_simple_async_result_complete_in_idle (data->simple); g_object_unref (data->simple); goto out; } if (timeout_seconds > 0) { data->timeout_source = g_timeout_source_new_seconds (timeout_seconds); g_source_set_priority (data->timeout_source, G_PRIORITY_DEFAULT); g_source_set_callback (data->timeout_source, timeout_cb, data, NULL); g_source_attach (data->timeout_source, data->main_context); g_source_unref (data->timeout_source); } data->child_watch_source = g_child_watch_source_new (data->child_pid); g_source_set_callback (data->child_watch_source, (GSourceFunc) child_watch_cb, data, NULL); g_source_attach (data->child_watch_source, data->main_context); g_source_unref (data->child_watch_source); data->child_stdout_channel = g_io_channel_unix_new (data->child_stdout_fd); g_io_channel_set_flags (data->child_stdout_channel, G_IO_FLAG_NONBLOCK, NULL); data->child_stdout_source = g_io_create_watch (data->child_stdout_channel, G_IO_IN); g_source_set_callback (data->child_stdout_source, (GSourceFunc) read_child_stdout, data, NULL); g_source_attach (data->child_stdout_source, data->main_context); g_source_unref (data->child_stdout_source); data->child_stderr_channel = g_io_channel_unix_new (data->child_stderr_fd); g_io_channel_set_flags (data->child_stderr_channel, G_IO_FLAG_NONBLOCK, NULL); data->child_stderr_source = g_io_create_watch (data->child_stderr_channel, G_IO_IN); g_source_set_callback (data->child_stderr_source, (GSourceFunc) read_child_stderr, data, NULL); g_source_attach (data->child_stderr_source, data->main_context); g_source_unref (data->child_stderr_source); out: g_strfreev (child_argv); }