source: proiecte/PPPP/gdm/common/gdm-common.c @ 134

Last change on this file since 134 was 134, checked in by (none), 14 years ago

gdm sources with the modifications for webcam

File size: 12.4 KB
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library 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 GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
20
21#include "config.h"
22
23#include <string.h>
24#include <unistd.h>
25#include <stdlib.h>
26#include <locale.h>
27#include <fcntl.h>
28#include <sys/wait.h>
29
30#include <glib.h>
31#include <glib/gi18n.h>
32#include <glib/gstdio.h>
33
34#include "gdm-common.h"
35
36#ifndef HAVE_MKDTEMP
37#include "mkdtemp.h"
38#endif
39
40const char *
41gdm_make_temp_dir (char *template)
42{
43        return mkdtemp (template);
44}
45
46gboolean
47gdm_is_version_unstable (void)
48{
49        char   **versions;
50        gboolean unstable;
51
52        unstable = FALSE;
53
54        versions = g_strsplit (VERSION, ".", 3);
55        if (versions && versions [0] && versions [1]) {
56                int major;
57                major = atoi (versions [1]);
58                if ((major % 2) != 0) {
59                        unstable = TRUE;
60                }
61        }
62        g_strfreev (versions);
63
64        return unstable;
65}
66
67void
68gdm_set_fatal_warnings_if_unstable (void)
69{
70        if (gdm_is_version_unstable ()) {
71                g_setenv ("G_DEBUG", "fatal_criticals", FALSE);
72                g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL);
73        }
74}
75
76int
77gdm_wait_on_pid (int pid)
78{
79        int status;
80
81 wait_again:
82        errno = 0;
83        if (waitpid (pid, &status, 0) < 0) {
84                if (errno == EINTR) {
85                        goto wait_again;
86                } else if (errno == ECHILD) {
87                        ; /* do nothing, child already reaped */
88                } else {
89                        g_debug ("GdmCommon: waitpid () should not fail");
90                }
91        }
92
93        g_debug ("GdmCommon: process (pid:%d) done (%s:%d)",
94                 (int) pid,
95                 WIFEXITED (status) ? "status"
96                 : WIFSIGNALED (status) ? "signal"
97                 : "unknown",
98                 WIFEXITED (status) ? WEXITSTATUS (status)
99                 : WIFSIGNALED (status) ? WTERMSIG (status)
100                 : -1);
101
102        return status;
103}
104
105int
106gdm_signal_pid (int pid,
107                int signal)
108{
109        int status = -1;
110
111        /* perhaps block sigchld */
112        g_debug ("GdmCommon: sending signal %d to process %d", signal, pid);
113        errno = 0;
114        status = kill (pid, signal);
115
116        if (status < 0) {
117                if (errno == ESRCH) {
118                        g_warning ("Child process %d was already dead.",
119                                   (int)pid);
120                } else {
121                        g_warning ("Couldn't kill child process %d: %s",
122                                   pid,
123                                   g_strerror (errno));
124                }
125        }
126
127        /* perhaps unblock sigchld */
128
129        return status;
130}
131
132/* hex conversion adapted from D-Bus */
133/**
134 * Appends a two-character hex digit to a string, where the hex digit
135 * has the value of the given byte.
136 *
137 * @param str the string
138 * @param byte the byte
139 */
140static void
141_gdm_string_append_byte_as_hex (GString *str,
142                                int      byte)
143{
144        const char hexdigits[16] = {
145                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
146                'a', 'b', 'c', 'd', 'e', 'f'
147        };
148
149        str = g_string_append_c (str, hexdigits[(byte >> 4)]);
150
151        str = g_string_append_c (str, hexdigits[(byte & 0x0f)]);
152}
153
154/**
155 * Encodes a string in hex, the way MD5 and SHA-1 are usually
156 * encoded. (Each byte is two hex digits.)
157 *
158 * @param source the string to encode
159 * @param start byte index to start encoding
160 * @param dest string where encoded data should be placed
161 * @param insert_at where to place encoded data
162 * @returns #TRUE if encoding was successful, #FALSE if no memory etc.
163 */
164gboolean
165gdm_string_hex_encode (const GString *source,
166                       int            start,
167                       GString       *dest,
168                       int            insert_at)
169{
170        GString             *result;
171        const unsigned char *p;
172        const unsigned char *end;
173        gboolean             retval;
174
175        g_return_val_if_fail (source != NULL, FALSE);
176        g_return_val_if_fail (dest != NULL, FALSE);
177        g_return_val_if_fail (source != dest, FALSE);
178        g_return_val_if_fail (start >= 0, FALSE);
179        g_return_val_if_fail (dest >= 0, FALSE);
180        g_assert (start <= source->len);
181
182        result = g_string_new (NULL);
183
184        retval = FALSE;
185
186        p = (const unsigned char*) source->str;
187        end = p + source->len;
188        p += start;
189
190        while (p != end) {
191                _gdm_string_append_byte_as_hex (result, *p);
192                ++p;
193        }
194
195        dest = g_string_insert (dest, insert_at, result->str);
196
197        retval = TRUE;
198
199        g_string_free (result, TRUE);
200
201        return retval;
202}
203
204/**
205 * Decodes a string from hex encoding.
206 *
207 * @param source the string to decode
208 * @param start byte index to start decode
209 * @param end_return return location of the end of the hex data, or #NULL
210 * @param dest string where decoded data should be placed
211 * @param insert_at where to place decoded data
212 * @returns #TRUE if decoding was successful, #FALSE if no memory.
213 */
214gboolean
215gdm_string_hex_decode (const GString *source,
216                       int            start,
217                       int           *end_return,
218                       GString       *dest,
219                       int            insert_at)
220{
221        GString             *result;
222        const unsigned char *p;
223        const unsigned char *end;
224        gboolean             retval;
225        gboolean             high_bits;
226
227        g_return_val_if_fail (source != NULL, FALSE);
228        g_return_val_if_fail (dest != NULL, FALSE);
229        g_return_val_if_fail (source != dest, FALSE);
230        g_return_val_if_fail (start >= 0, FALSE);
231        g_return_val_if_fail (dest >= 0, FALSE);
232
233        g_assert (start <= source->len);
234
235        result = g_string_new (NULL);
236
237        retval = FALSE;
238
239        high_bits = TRUE;
240        p = (const unsigned char*) source->str;
241        end = p + source->len;
242        p += start;
243
244        while (p != end) {
245                unsigned int val;
246
247                switch (*p) {
248                case '0':
249                        val = 0;
250                        break;
251                case '1':
252                        val = 1;
253                        break;
254                case '2':
255                        val = 2;
256                        break;
257                case '3':
258                        val = 3;
259                        break;
260                case '4':
261                        val = 4;
262                        break;
263                case '5':
264                        val = 5;
265                        break;
266                case '6':
267                        val = 6;
268                        break;
269                case '7':
270                        val = 7;
271                        break;
272                case '8':
273                        val = 8;
274                        break;
275                case '9':
276                        val = 9;
277                        break;
278                case 'a':
279                case 'A':
280                        val = 10;
281                        break;
282                case 'b':
283                case 'B':
284                        val = 11;
285                        break;
286                case 'c':
287                case 'C':
288                        val = 12;
289                        break;
290                case 'd':
291                case 'D':
292                        val = 13;
293                        break;
294                case 'e':
295                case 'E':
296                        val = 14;
297                        break;
298                case 'f':
299                case 'F':
300                        val = 15;
301                        break;
302                default:
303                        goto done;
304                }
305
306                if (high_bits) {
307                        result = g_string_append_c (result, val << 4);
308                } else {
309                        int           len;
310                        unsigned char b;
311
312                        len = result->len;
313
314                        b = result->str[len - 1];
315
316                        b |= val;
317
318                        result->str[len - 1] = b;
319                }
320
321                high_bits = !high_bits;
322
323                ++p;
324        }
325
326 done:
327        dest = g_string_insert (dest, insert_at, result->str);
328
329        if (end_return) {
330                *end_return = p - (const unsigned char*) source->str;
331        }
332
333        retval = TRUE;
334
335        g_string_free (result, TRUE);
336
337        return retval;
338}
339
340static gboolean
341_fd_is_character_device (int fd)
342{
343        struct stat file_info;
344
345        if (fstat (fd, &file_info) < 0) {
346                return FALSE;
347        }
348
349        return S_ISCHR (file_info.st_mode);
350}
351
352static gboolean
353_read_bytes (int      fd,
354             char    *bytes,
355             gsize    number_of_bytes,
356             GError **error)
357{
358        size_t bytes_left_to_read;
359        size_t total_bytes_read = 0;
360        gboolean premature_eof;
361
362        bytes_left_to_read = number_of_bytes;
363        premature_eof = FALSE;
364        do {
365                size_t bytes_read = 0;
366
367                errno = 0;
368                bytes_read = read (fd, ((guchar *) bytes) + total_bytes_read,
369                                   bytes_left_to_read);
370
371                if (bytes_read > 0) {
372                        total_bytes_read += bytes_read;
373                        bytes_left_to_read -= bytes_read;
374                } else if (bytes_read == 0) {
375                        premature_eof = TRUE;
376                        break;
377                } else if ((errno != EINTR)) {
378                        break;
379                }
380        } while (bytes_left_to_read > 0);
381
382        if (premature_eof) {
383                g_set_error (error,
384                             G_FILE_ERROR,
385                             g_file_error_from_errno (ENODATA),
386                             "%s", g_strerror (ENODATA));
387
388                return FALSE;
389        } else if (bytes_left_to_read > 0) {
390                g_set_error (error,
391                             G_FILE_ERROR,
392                             g_file_error_from_errno (errno),
393                             "%s", g_strerror (errno));
394                return FALSE;
395        }
396
397        return TRUE;
398}
399
400/**
401 * Pulls a requested number of bytes from /dev/urandom
402 *
403 * @param size number of bytes to pull
404 * @param error error if read fails
405 * @returns The requested number of random bytes or #NULL if fail
406 */
407
408char *
409gdm_generate_random_bytes (gsize    size,
410                           GError **error)
411{
412        int fd;
413        char *bytes;
414        GError *read_error;
415
416        /* We don't use the g_rand_* glib apis because they don't document
417         * how much entropy they are seeded with, and it might be less
418         * than the passed in size.
419         */
420
421        errno = 0;
422        fd = open ("/dev/urandom", O_RDONLY);
423
424        if (fd < 0) {
425                g_set_error (error,
426                             G_FILE_ERROR,
427                             g_file_error_from_errno (errno),
428                             "%s", g_strerror (errno));
429                close (fd);
430                return NULL;
431        }
432
433        if (!_fd_is_character_device (fd)) {
434                g_set_error (error,
435                             G_FILE_ERROR,
436                             g_file_error_from_errno (ENODEV),
437                             _("/dev/urandom is not a character device"));
438                close (fd);
439                return NULL;
440        }
441
442        bytes = g_malloc (size);
443        read_error = NULL;
444        if (!_read_bytes (fd, bytes, size, &read_error)) {
445                g_propagate_error (error, read_error);
446                g_free (bytes);
447                close (fd);
448                return NULL;
449        }
450
451        close (fd);
452        return bytes;
453}
Note: See TracBrowser for help on using the repository browser.