~ubuntu-branches/ubuntu/raring/consolekit/raring

« back to all changes in this revision

Viewing changes to src/ck-sysdeps-gnu.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2010-11-20 18:17:28 UTC
  • mfrom: (0.1.16 sid)
  • Revision ID: james.westby@ubuntu.com-20101120181728-8e5bwe4ttgmk4j41
Tags: 0.4.3-2
Add 01-retry-console-open-on-EIO.patch: As reported in LP: #544139,
ConsoleKit sometimes fails to track the active VT. This particular case
was tracked down to a race condition that happens if you try to open
/dev/console while the current TTY is currently being closed. This yields
an -EIO error, in which case CK should just try again. Thanks Colin Watson
for the patch!

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright (C) 2009 Pino Toscano <pino@kde.org>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
18
 *
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
 
 
23
#include <stdlib.h>
 
24
#include <stdio.h>
 
25
#include <unistd.h>
 
26
#include <string.h>
 
27
#include <errno.h>
 
28
 
 
29
#include <hurd.h>
 
30
#include <dirent.h>
 
31
#include <ps.h>
 
32
#include <ttyent.h>
 
33
 
 
34
#ifdef HAVE_PATHS_H
 
35
#include <paths.h>
 
36
#endif /* HAVE_PATHS_H */
 
37
 
 
38
#include "ck-sysdeps.h"
 
39
 
 
40
struct _CkProcessStat
 
41
{
 
42
        struct proc_stat *ps;           /* the statistics of a process */
 
43
};
 
44
 
 
45
static struct ps_context *pc = NULL;
 
46
 
 
47
static gboolean
 
48
get_proc_stat_from_pid (pid_t              pid,
 
49
                        ps_flags_t         flags,
 
50
                        struct proc_stat **res_ps)
 
51
{
 
52
        error_t           err;
 
53
        struct proc_stat *ps;
 
54
 
 
55
        g_assert (pid >= 0);
 
56
        g_assert (res_ps != NULL);
 
57
 
 
58
        if (pc == NULL) {
 
59
                err = ps_context_create (getproc (), &pc);
 
60
                if (err) {
 
61
                    return FALSE;
 
62
                }
 
63
        }
 
64
 
 
65
        err = _proc_stat_create (pid, pc, &ps);
 
66
        if (err) {
 
67
                return FALSE;
 
68
        }
 
69
 
 
70
        err = proc_stat_set_flags (ps, PSTAT_PID | flags);
 
71
        if (err) {
 
72
                return FALSE;
 
73
        }
 
74
 
 
75
        *res_ps = ps;
 
76
        return TRUE;
 
77
}
 
78
 
 
79
 
 
80
pid_t
 
81
ck_process_stat_get_ppid (CkProcessStat *stat)
 
82
{
 
83
        g_return_val_if_fail (stat != NULL, -1);
 
84
 
 
85
        return proc_stat_pid (stat->ps);
 
86
}
 
87
 
 
88
char *
 
89
ck_process_stat_get_cmd (CkProcessStat *stat)
 
90
{
 
91
        g_return_val_if_fail (stat != NULL, NULL);
 
92
 
 
93
        return g_strdup (proc_stat_args (stat->ps));
 
94
}
 
95
 
 
96
char *
 
97
ck_process_stat_get_tty (CkProcessStat *stat)
 
98
{
 
99
        struct ps_tty    *tty;
 
100
 
 
101
        g_return_val_if_fail (stat != NULL, NULL);
 
102
 
 
103
        tty = proc_stat_tty (stat->ps);
 
104
 
 
105
        return tty ? g_strdup (ps_tty_name (tty)) : NULL;
 
106
}
 
107
 
 
108
gboolean
 
109
ck_process_stat_new_for_unix_pid (pid_t           pid,
 
110
                                  CkProcessStat **stat,
 
111
                                  GError        **error)
 
112
{
 
113
        gboolean          res;
 
114
        struct proc_stat *ps;
 
115
        CkProcessStat    *proc;
 
116
 
 
117
        g_return_val_if_fail (pid > 1, FALSE);
 
118
 
 
119
        if (stat == NULL) {
 
120
                return FALSE;
 
121
        }
 
122
 
 
123
        *stat = NULL;
 
124
 
 
125
        res = get_proc_stat_from_pid (pid, PSTAT_ARGS | PSTAT_TTY, &ps);
 
126
        if (!res) {
 
127
                return FALSE;
 
128
        }
 
129
 
 
130
        proc = g_new0 (CkProcessStat, 1);
 
131
        proc->ps = ps;
 
132
        *stat = proc;
 
133
 
 
134
        return TRUE;
 
135
}
 
136
 
 
137
void
 
138
ck_process_stat_free (CkProcessStat *stat)
 
139
{
 
140
        _proc_stat_free (stat->ps);
 
141
 
 
142
        g_free (stat);
 
143
}
 
144
 
 
145
GHashTable *
 
146
ck_unix_pid_get_env_hash (pid_t pid)
 
147
{
 
148
        struct proc_stat *ps;
 
149
        char             *env_p;
 
150
        size_t            env_index;
 
151
        size_t            env_l;
 
152
        gboolean          res;
 
153
        GHashTable       *hash;
 
154
 
 
155
        g_return_val_if_fail (pid > 1, NULL);
 
156
 
 
157
        res = get_proc_stat_from_pid (pid, PSTAT_ENV, &ps);
 
158
        if (!res) {
 
159
                return NULL;
 
160
        }
 
161
 
 
162
        hash = g_hash_table_new_full (g_str_hash,
 
163
                                      g_str_equal,
 
164
                                      g_free,
 
165
                                      g_free);
 
166
 
 
167
        env_index = 0;
 
168
        env_l = 0;
 
169
        env_p = proc_stat_env (ps);
 
170
        while (env_index < proc_stat_env_len (ps)) {
 
171
                env_l = strlen (env_p);
 
172
                env_index += env_l + 1;
 
173
                if (env_l) {
 
174
                        char **vals;
 
175
                        vals = g_strsplit (env_p, "=", 2);
 
176
                        if (vals != NULL) {
 
177
                                g_hash_table_insert (hash,
 
178
                                                     g_strdup (vals[0]),
 
179
                                                     g_strdup (vals[1]));
 
180
                                g_strfreev (vals);
 
181
                        }
 
182
                }
 
183
                env_p = env_p + env_l + 1;
 
184
        }
 
185
 
 
186
        _proc_stat_free (ps);
 
187
 
 
188
        return hash;
 
189
}
 
190
 
 
191
char *
 
192
ck_unix_pid_get_env (pid_t       pid,
 
193
                     const char *var)
 
194
{
 
195
        struct proc_stat *ps;
 
196
        char             *env_p;
 
197
        size_t            env_index;
 
198
        size_t            env_l;
 
199
        char             *prefix;
 
200
        int               prefix_len;
 
201
        char             *val;
 
202
        gboolean          res;
 
203
 
 
204
        g_return_val_if_fail (pid > 1, NULL);
 
205
 
 
206
        val = NULL;
 
207
 
 
208
        res = get_proc_stat_from_pid (pid, PSTAT_ENV, &ps);
 
209
        if (!res) {
 
210
                return NULL;
 
211
        }
 
212
 
 
213
        prefix = g_strdup_printf ("%s=", var);
 
214
        prefix_len = strlen (prefix);
 
215
 
 
216
        env_index = 0;
 
217
        env_l = 0;
 
218
        env_p = proc_stat_env (ps);
 
219
        while (env_index < proc_stat_env_len (ps)) {
 
220
                env_l = strlen (env_p);
 
221
                env_index += env_l + 1;
 
222
                if (env_l && g_str_has_prefix (env_p, prefix)) {
 
223
                        val = g_strdup (env_p + prefix_len);
 
224
                        break;
 
225
                }
 
226
                env_p = env_p + env_l + 1;
 
227
        }
 
228
 
 
229
        g_free (prefix);
 
230
 
 
231
        _proc_stat_free (ps);
 
232
 
 
233
        return val;
 
234
}
 
235
 
 
236
uid_t
 
237
ck_unix_pid_get_uid (pid_t pid)
 
238
{
 
239
        struct proc_stat *ps;
 
240
        gboolean          res;
 
241
        uid_t             uid;
 
242
 
 
243
        g_return_val_if_fail (pid > 1, 0);
 
244
 
 
245
        res = get_proc_stat_from_pid (pid, PSTAT_OWNER_UID, &ps);
 
246
        if (!res) {
 
247
                return 0;
 
248
        }
 
249
 
 
250
        uid = proc_stat_owner_uid (ps);
 
251
 
 
252
        _proc_stat_free (ps);
 
253
 
 
254
        return uid;
 
255
}
 
256
 
 
257
pid_t
 
258
ck_unix_pid_get_ppid (pid_t pid)
 
259
{
 
260
        struct proc_stat *ps;
 
261
        gboolean          res;
 
262
        pid_t             ppid;
 
263
 
 
264
        g_return_val_if_fail (pid > 1, 0);
 
265
 
 
266
        res = get_proc_stat_from_pid (pid, PSTAT_PROC_INFO, &ps);
 
267
        if (!res) {
 
268
                return 0;
 
269
        }
 
270
 
 
271
        ppid = proc_stat_proc_info (ps)->ppid;
 
272
 
 
273
        _proc_stat_free (ps);
 
274
 
 
275
        return ppid;
 
276
}
 
277
 
 
278
gboolean
 
279
ck_unix_pid_get_login_session_id (pid_t  pid,
 
280
                                  char **idp)
 
281
{
 
282
        g_return_val_if_fail (pid > 1, FALSE);
 
283
 
 
284
        return FALSE;
 
285
}
 
286
 
 
287
gboolean
 
288
ck_get_max_num_consoles (guint *num)
 
289
{
 
290
        int      max_consoles;
 
291
        int      res;
 
292
        gboolean ret;
 
293
        struct ttyent *t;
 
294
 
 
295
        ret = FALSE;
 
296
        max_consoles = 0;
 
297
 
 
298
        res = setttyent ();
 
299
        if (res == 0) {
 
300
                goto done;
 
301
        }
 
302
 
 
303
        while ((t = getttyent ()) != NULL) {
 
304
                if (t->ty_status & TTY_ON && strncmp (t->ty_name, "tty", 3) == 0)
 
305
                        max_consoles++;
 
306
        }
 
307
 
 
308
        /* Increment one more so that all consoles are properly counted
 
309
         * this is arguable a bug in vt_add_watches().
 
310
         */
 
311
        max_consoles++;
 
312
 
 
313
        ret = TRUE;
 
314
 
 
315
        endttyent ();
 
316
 
 
317
done:
 
318
        if (num != NULL) {
 
319
                *num = max_consoles;
 
320
        }
 
321
 
 
322
        return ret;
 
323
}
 
324
 
 
325
gboolean
 
326
ck_supports_activatable_consoles (void)
 
327
{
 
328
        return TRUE;
 
329
}
 
330
 
 
331
char *
 
332
ck_get_console_device_for_num (guint num)
 
333
{
 
334
        char *device;
 
335
 
 
336
        device = g_strdup_printf (_PATH_TTY "%u", num);
 
337
 
 
338
        return device;
 
339
}
 
340
 
 
341
gboolean
 
342
ck_get_console_num_from_device (const char *device,
 
343
                                guint      *num)
 
344
{
 
345
        guint    n;
 
346
        gboolean ret;
 
347
 
 
348
        n = 0;
 
349
        ret = FALSE;
 
350
 
 
351
        if (device == NULL) {
 
352
                return FALSE;
 
353
        }
 
354
 
 
355
        if (sscanf (device, _PATH_TTY "%u", &n) == 1) {
 
356
                ret = TRUE;
 
357
        }
 
358
 
 
359
        if (num != NULL) {
 
360
                *num = n;
 
361
        }
 
362
 
 
363
        return ret;
 
364
}
 
365
 
 
366
gboolean
 
367
ck_get_active_console_num (int    console_fd,
 
368
                           guint *num)
 
369
{
 
370
        gboolean       ret;
 
371
        int            res;
 
372
        long           cur_active;
 
373
        char           buf[30];
 
374
        guint          active;
 
375
 
 
376
        g_assert (console_fd != -1);
 
377
 
 
378
        active = 0;
 
379
        ret = FALSE;
 
380
 
 
381
        res = readlink ("/dev/cons/vcs", buf, sizeof (buf));
 
382
        if (res > 0) {
 
383
                /* the resolved path is like "/dev/vcs/$number", so skip
 
384
                   the non-number part at the start */
 
385
                const char *p = buf;
 
386
                while ((*p) && ((*p < '0') || (*p > '9'))) {
 
387
                        ++p;
 
388
                }
 
389
                if (*p) {
 
390
                        cur_active = strtol (p, NULL, 10);
 
391
                        g_debug ("Current VT: tty%ld", cur_active);
 
392
                        active = cur_active;
 
393
                        ret = TRUE;
 
394
                }
 
395
        }
 
396
 
 
397
        if (num != NULL) {
 
398
                *num = active;
 
399
        }
 
400
 
 
401
        return ret;
 
402
}