gtk+3: fix dependencies for new gnome/accessibility/at-spi2-core
[oi-userland.git] / components / desktop / mate / mate-control-center / patches / 04-passwd-pty.patch
blob9395fb5415a6607e68dd3800a31e41b8be239b6b
1 diff --git a/capplets/about-me/mate-about-me-password.c b/capplets/about-me/mate-about-me-password.c
2 index abac117..5a82566 100644
3 --- a/capplets/about-me/mate-about-me-password.c
4 +++ b/capplets/about-me/mate-about-me-password.c
5 @@ -27,6 +27,14 @@
6 # include <config.h>
7 #endif
9 +/* This is needed to get ptmx-related functions in GLIBC */
10 +#ifndef _XOPEN_SOURCE
11 +#define _XOPEN_SOURCE 600
12 +#endif
14 +/* This is needed to get pipe2() in GLIBC */
15 +#define _GNU_SOURCE
17 /* Are all of these needed? */
18 #include <gdk/gdkkeysyms.h>
19 #include <pwd.h>
20 @@ -35,6 +43,16 @@
21 #include <errno.h>
22 #include <string.h>
23 #include <sys/wait.h>
24 +#include <sys/stat.h>
25 +#include <fcntl.h>
26 +#include <stropts.h>
27 +#include <termios.h>
29 +#define PASSWD "/usr/bin/passwd"
30 +#define PTMX "/dev/ptmx"
32 +/* /dev/pts/N */
33 +#define PTY_MAX_NAME 20
35 #if __sun
36 #include <sys/types.h>
37 @@ -85,6 +103,9 @@ typedef struct {
38 /* Buffer size for backend output */
39 #define BUFSIZE 64
41 +/* Bufffer size for backend error messages */
42 +#define ERRBUFSIZE 1024
45 * Error handling {{
47 @@ -170,85 +191,178 @@ static gboolean
48 spawn_passwd (PasswordDialog *pdialog, GError **error)
50 gchar *argv[2];
51 - gchar *envp[1];
52 - gint my_stdin, my_stdout, my_stderr;
53 + int pid, pty_m, err_pipe[2];
54 + char slave_name[PTY_MAX_NAME];
55 + char *name;
57 - argv[0] = "/usr/bin/passwd"; /* Is it safe to rely on a hard-coded path? */
58 + argv[0] = PASSWD; /* Is it safe to rely on a hard-coded path? */
59 argv[1] = NULL;
61 - envp[0] = NULL; /* If we pass an empty array as the environment,
62 - * will the childs environment be empty, and the
63 - * locales set to the C default? From the manual:
64 - * "If envp is NULL, the child inherits its
65 - * parent'senvironment."
66 - * If I'm wrong here, we somehow have to set
67 - * the locales here.
68 - */
70 - if (!g_spawn_async_with_pipes (NULL, /* Working directory */
71 - argv, /* Argument vector */
72 - envp, /* Environment */
73 - G_SPAWN_DO_NOT_REAP_CHILD, /* Flags */
74 - NULL, /* Child setup */
75 - NULL, /* Data to child setup */
76 - &pdialog->backend_pid, /* PID */
77 - &my_stdin, /* Stdin */
78 - &my_stdout, /* Stdout */
79 - &my_stderr, /* Stderr */
80 - error)) { /* GError */
82 - /* An error occurred */
83 - free_passwd_resources (pdialog);
85 + pty_m = open(PTMX, O_RDWR|O_NOCTTY);
86 + if (pty_m > 0) {
87 + name = ptsname(pty_m);
88 + if (name && (strlen(name) < PTY_MAX_NAME)) {
89 + strncpy(slave_name, name, PTY_MAX_NAME);
90 + } else {
91 + g_set_error(error,
92 + PASSDLG_ERROR,
93 + PASSDLG_ERROR_BACKEND,
94 + _("Couldn't get slave_name of pty"));
95 + close(pty_m);
96 + return FALSE;
97 + }
98 + } else {
99 + g_set_error (error,
100 + PASSDLG_ERROR,
101 + PASSDLG_ERROR_BACKEND,
102 + _("Couldn't open pseudo-tty"));
103 return FALSE;
106 - /* 2>&1 */
107 - if (dup2 (my_stderr, my_stdout) == -1) {
108 - /* Failed! */
109 + if (grantpt(pty_m) < 0) {
110 g_set_error (error,
111 - PASSDLG_ERROR,
112 - PASSDLG_ERROR_BACKEND,
113 - "%s",
114 - strerror (errno));
116 - /* Clean up */
117 - stop_passwd (pdialog);
119 + PASSDLG_ERROR,
120 + PASSDLG_ERROR_BACKEND,
121 + _("Couldn't set permission on slave device: %s"),
122 + strerror(errno));
123 + close(pty_m);
124 return FALSE;
127 - /* Open IO Channels */
128 - pdialog->backend_stdin = g_io_channel_unix_new (my_stdin);
129 - pdialog->backend_stdout = g_io_channel_unix_new (my_stdout);
131 - /* Set raw encoding */
132 - /* Set nonblocking mode */
133 - if (g_io_channel_set_encoding (pdialog->backend_stdin, NULL, error) != G_IO_STATUS_NORMAL ||
134 - g_io_channel_set_encoding (pdialog->backend_stdout, NULL, error) != G_IO_STATUS_NORMAL ||
135 - g_io_channel_set_flags (pdialog->backend_stdin, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ||
136 - g_io_channel_set_flags (pdialog->backend_stdout, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ) {
137 + if (unlockpt(pty_m) < 0) {
138 + g_set_error (error,
139 + PASSDLG_ERROR,
140 + PASSDLG_ERROR_BACKEND,
141 + _("Couldn't unlock slave device: %s"),
142 + strerror(errno));
143 + close(pty_m);
144 + return FALSE;
147 - /* Clean up */
148 - stop_passwd (pdialog);
149 + if (pipe2(err_pipe, O_CLOEXEC) < 0) {
150 + g_set_error (error,
151 + PASSDLG_ERROR,
152 + PASSDLG_ERROR_BACKEND,
153 + _("Couldn't create error reporting pipe: %s"),
154 + strerror(errno));
155 + close(pty_m);
156 return FALSE;
159 + pid = fork();
160 + if (pid == 0) {
161 + /* Child */
162 + int pty_s, len;
163 + char buf[ERRBUFSIZE];
164 + close(err_pipe[0]);
166 + close(pty_m);
167 + if (setsid() < 0) {
168 + len = snprintf(buf, ERRBUFSIZE, _("Couldn't create new process group: %s"), strerror(errno));
169 + write(err_pipe[1], buf, (len>ERRBUFSIZE) ? ERRBUFSIZE : len );
170 + exit(1);
173 - /* Turn off buffering */
174 - g_io_channel_set_buffered (pdialog->backend_stdin, FALSE);
175 - g_io_channel_set_buffered (pdialog->backend_stdout, FALSE);
176 + /* Now we are a session leader, on System V first open tty will become controlling tty */
177 + pty_s = open(slave_name, O_RDWR);
179 - /* Add IO Channel watcher */
180 - pdialog->backend_stdout_watch_id = g_io_add_watch (pdialog->backend_stdout,
181 - G_IO_IN | G_IO_PRI,
182 - (GIOFunc) io_watch_stdout, pdialog);
183 + if (pty_s < 0) {
184 + len = snprintf(buf, ERRBUFSIZE, _("Couldn't open slave terminal device: %s"), strerror(errno));
185 + write(err_pipe[1], buf, (len>ERRBUFSIZE) ? ERRBUFSIZE : len );
186 + exit(1);
189 +#if defined(TIOCSCTTY) && !defined(__sun)
190 + /* BSD systems need to set controlling tty explicitly. Solaris/illumos can export
191 + TIOCSCTTY when __EXTENSIONS__ are defined, but doesn't need this. */
192 + if (ioctl(pty_s,TIOCSCTTY, NULL) < 0) {
193 + close(pty_s);
194 + len=snprintf(buf, ERRBUFSIZE, _("Couldn't establish controlling terminal: %s"), strerror(errno));
195 + write(err_pipe[1], buf, (len>ERRBUFSIZE) ? ERRBUFSIZE : len );
196 + exit(1);
198 +#endif
200 + /* Set stdin, stdout, stderr to our tty */
201 + dup2(pty_s, 0);
202 + dup2(pty_s, 1);
203 + dup2(pty_s, 2);
205 + execvp(argv[0], argv);
207 + /* Error */
208 + close(pty_s);
209 + len=snprintf(buf, ERRBUFSIZE, _("Couldn't exec passwd: %s"), strerror(errno));
210 + write(err_pipe[1], buf, (len>ERRBUFSIZE) ? ERRBUFSIZE : len );
211 + exit(1);
212 + } else if (pid > 0) {
213 + int rb, pos = 0;
214 + char buf[ERRBUFSIZE];
217 + close(err_pipe[1]);
218 + /* Wait for child to run exec() and read possible error message */
219 + while (pos < ERRBUFSIZE - 1 && ((rb=read(err_pipe[0], &buf[pos], ERRBUFSIZE-1-pos)) > 0)) {
220 + pos += rb;
222 + close(err_pipe[0]);
223 + if (pos > 0) {
224 + /* There were messages in err_pipe */
225 + buf[pos+1] = '\0';
226 + g_set_error (error,
227 + PASSDLG_ERROR,
228 + PASSDLG_ERROR_BACKEND,
229 + buf);
231 + stop_passwd(pdialog);
232 + return FALSE;
233 + }
235 + /* Open IO Channels */
236 + pdialog->backend_stdin = g_io_channel_unix_new (pty_m);
237 + /* g_io_channel_shutdown(pdialog->backend_stdin) will close associated file descriptor (pty_m),
238 + but this will generate warning on g_io_channel_shutdown(pdialog->backend_stdout).
239 + To avoid it, dup() file descriptor */
240 + pdialog->backend_stdout = g_io_channel_unix_new (dup(pty_m));
241 + pdialog->backend_pid = pid;
243 + /* Set raw encoding */
244 + /* Set nonblocking mode */
245 + if (g_io_channel_set_encoding (pdialog->backend_stdin, NULL, error) != G_IO_STATUS_NORMAL ||
246 + g_io_channel_set_encoding (pdialog->backend_stdout, NULL, error) != G_IO_STATUS_NORMAL ||
247 + g_io_channel_set_flags (pdialog->backend_stdin, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ||
248 + g_io_channel_set_flags (pdialog->backend_stdout, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ) {
250 + /* Clean up */
251 + stop_passwd (pdialog);
252 + return FALSE;
255 - /* Add child watcher */
256 - pdialog->backend_child_watch_id = g_child_watch_add (pdialog->backend_pid, (GChildWatchFunc) child_watch_cb, pdialog);
257 + /* Turn off buffering */
258 + g_io_channel_set_buffered (pdialog->backend_stdin, FALSE);
259 + g_io_channel_set_buffered (pdialog->backend_stdout, FALSE);
261 - /* Success! */
262 + /* Add IO Channel watcher */
263 + pdialog->backend_stdout_watch_id = g_io_add_watch (pdialog->backend_stdout,
264 + G_IO_IN | G_IO_PRI,
265 + (GIOFunc) io_watch_stdout, pdialog);
267 + /* Add child watcher */
268 + pdialog->backend_child_watch_id = g_child_watch_add (pdialog->backend_pid, (GChildWatchFunc) child_watch_cb, pdialog);
270 - return TRUE;
271 + /* Success! */
273 + return TRUE;
274 + } else {
275 + /* Error */
276 + g_set_error(error,
277 + PASSDLG_ERROR,
278 + PASSDLG_ERROR_BACKEND,
279 + _("Couldn't fork: %s"),
280 + strerror(errno));
281 + close(pty_m);
282 + return FALSE;
286 /* Stop passwd backend */
287 @@ -822,7 +936,7 @@ passdlg_spawn_passwd (PasswordDialog *pdialog)
289 /* translators: Unable to launch <program>: <error message> */
290 details = g_strdup_printf (_("Unable to launch %s: %s"),
291 - "/usr/bin/passwd", error->message);
292 + PASSWD, error->message);
294 passdlg_error_dialog (GTK_WINDOW (parent),
295 _("Unable to launch backend"),