/* Child watcher */ static void child_watch_cb (GPid pid, gint status, PasswordDialog *pdialog) { if (WIFEXITED (status)) { if (WEXITSTATUS (status) >= 255) { g_warning (_("Child exited unexpectedly")); } } free_passwd_resources (pdialog); }
/* Child watcher */ static void child_watch_cb (GPid pid, gint status, PasswdHandler *passwd_handler) { if (WIFEXITED (status)) { if (WEXITSTATUS (status) >= 255) { g_warning ("Child exited unexpectedly"); } if (WEXITSTATUS (status) == 0) { if (passwd_handler->backend_state == PASSWD_STATE_RETYPE) { passwd_handler->backend_state = PASSWD_STATE_DONE; if (passwd_handler->chpasswd_cb) passwd_handler->chpasswd_cb (passwd_handler, NULL, passwd_handler->chpasswd_cb_data); } } } free_passwd_resources (passwd_handler); }
/* Stop passwd backend */ static void stop_passwd (PasswordDialog *pdialog) { /* This is the standard way of returning from the dialog with passwd. * If we return this way we can safely kill passwd as it has completed * its task. */ if (pdialog->backend_pid != -1) { kill (pdialog->backend_pid, 9); } /* We must run free_passwd_resources here and not let our child * watcher do it, since it will access invalid memory after the * dialog has been closed and cleaned up. * * If we had more than a single thread we'd need to remove * the child watch before trying to kill the child. */ free_passwd_resources (pdialog); }
/* 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 occured */ 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, 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; }
/* 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; }