1 /***************************************************************************
2 * CVSID: $Id$
3 *
4 * util.c - Various utilities
5 *
6 * Copyright (C) 2004 David Zeuthen, <david@fubar.dk>
7 *
8 * Licensed under the Academic Free License version 2.1
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 *
24 **************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <time.h>
35 #include <ctype.h>
36 #include <stdint.h>
37 #include <sys/stat.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <signal.h>
41 #include <sys/wait.h>
42 #include <sys/file.h>
43
44 #include <glib.h>
45 #include <dbus/dbus.h>
46 #include <dbus/dbus-glib.h>
47
48 #include "osspec.h"
49 #include "logger.h"
50 #include "hald.h"
51 #include "hald_runner.h"
52 #include "hald_dbus.h"
53 #include "device_info.h"
54
55 #include "util.h"
56
57 /** Determine whether the given character is valid as the first character
58 * in a name.
59 */
60 #define VALID_INITIAL_NAME_CHARACTER(c) \
61 (((c) >= 'A' && (c) <= 'Z') || \
62 ((c) >= 'a' && (c) <= 'z') || \
63 ((c) == '_'))
64
65 /** Determine whether the given character is valid as a second or later
66 * character in a name.
67 */
68 #define VALID_NAME_CHARACTER(c) \
69 (((c) >= '0' && (c) <= '9') || \
70 ((c) >= 'A' && (c) <= 'Z') || \
71 ((c) >= 'a' && (c) <= 'z') || \
72 ((c) == '_'))
73
74 gboolean
hal_util_remove_trailing_slash(gchar * path)75 hal_util_remove_trailing_slash (gchar *path)
76 {
77 gchar *c = NULL;
78
79 if (path == NULL) {
80 return FALSE;
81 }
82
83 c = strrchr (path, '/');
84 if (c == NULL) {
85 HAL_WARNING (("Invalid path %s", path));
86 return 1;
87 }
88 if (*(c+1) == '\0')
89 *c = '\0';
90
91 return TRUE;
92 }
93
94 /** Given a path, /foo/bar/bat/foobar, return the last element, e.g.
95 * foobar.
96 *
97 * @param path Path
98 * @return Pointer into given string
99 */
100 const gchar *
hal_util_get_last_element(const gchar * s)101 hal_util_get_last_element (const gchar *s)
102 {
103 int len;
104 const gchar *p;
105
106 len = strlen (s);
107 for (p = s + len - 1; p > s; --p) {
108 if ((*p) == '/')
109 return p + 1;
110 }
111
112 return s;
113 }
114
115 /** Given a path, this functions finds the path representing the
116 * parent directory by truncation.
117 *
118 * @param path Path
119 * @return Path for parent or NULL. Must be freed by caller
120 */
121 gchar *
hal_util_get_parent_path(const gchar * path)122 hal_util_get_parent_path (const gchar *path)
123 {
124 guint i;
125 guint len;
126 gchar *parent_path;
127
128 /* Find parent device by truncating our own path */
129 parent_path = g_strndup (path, HAL_PATH_MAX);
130 len = strlen (parent_path);
131 for (i = len - 1; parent_path[i] != '/'; --i) {
132 parent_path[i] = '\0';
133 }
134 parent_path[i] = '\0';
135
136 return parent_path;
137 }
138
139 gchar *
hal_util_get_normalized_path(const gchar * path1,const gchar * path2)140 hal_util_get_normalized_path (const gchar *path1, const gchar *path2)
141 {
142 int len1;
143 int len2;
144 const gchar *p1;
145 const gchar *p2;
146 gchar buf[HAL_PATH_MAX];
147
148 len1 = strlen (path1);
149 len2 = strlen (path2);
150
151 p1 = path1 + len1;
152
153 p2 = path2;
154 while (p2 < path2 + len2 && strncmp (p2, "../", 3) == 0) {
155 p2 += 3;
156
157 while (p1 >= path1 && *(--p1)!='/')
158 ;
159 }
160
161 if ((p1-path1) < 0) {
162 HAL_ERROR (("Could not normalize '%s' and '%s', return 'NULL'", path1, path2));
163 return NULL;
164 }
165
166 strncpy (buf, path1, (p1-path1));
167 buf[p1-path1] = '\0';
168
169 return g_strdup_printf ("%s/%s", buf, p2);
170 }
171
172 gboolean
hal_util_get_int_from_file(const gchar * directory,const gchar * file,gint * result,gint base)173 hal_util_get_int_from_file (const gchar *directory, const gchar *file, gint *result, gint base)
174 {
175 FILE *f;
176 char buf[64];
177 gchar path[HAL_PATH_MAX];
178 gboolean ret;
179
180 f = NULL;
181 ret = FALSE;
182
183 g_snprintf (path, sizeof (path), "%s/%s", directory, file);
184
185 f = fopen (path, "rb");
186 if (f == NULL) {
187 HAL_ERROR (("Cannot open '%s'", path));
188 goto out;
189 }
190
191 if (fgets (buf, sizeof (buf), f) == NULL) {
192 HAL_ERROR (("Cannot read from '%s'", path));
193 goto out;
194 }
195
196 /* TODO: handle error condition */
197 *result = strtol (buf, NULL, base);
198 ret = TRUE;
199
200 out:
201 if (f != NULL)
202 fclose (f);
203
204 return ret;
205 }
206
207 gboolean
hal_util_set_int_from_file(HalDevice * d,const gchar * key,const gchar * directory,const gchar * file,gint base)208 hal_util_set_int_from_file (HalDevice *d, const gchar *key, const gchar *directory, const gchar *file, gint base)
209 {
210 gint value;
211 gboolean ret;
212
213 ret = FALSE;
214
215 if (hal_util_get_int_from_file (directory, file, &value, base))
216 ret = hal_device_property_set_int (d, key, value);
217
218 return ret;
219 }
220
221
222 gboolean
hal_util_get_uint64_from_file(const gchar * directory,const gchar * file,guint64 * result,gint base)223 hal_util_get_uint64_from_file (const gchar *directory, const gchar *file, guint64 *result, gint base)
224 {
225 FILE *f;
226 char buf[64];
227 gchar path[HAL_PATH_MAX];
228 gboolean ret;
229
230 f = NULL;
231 ret = FALSE;
232
233 g_snprintf (path, sizeof (path), "%s/%s", directory, file);
234
235 f = fopen (path, "rb");
236 if (f == NULL) {
237 HAL_ERROR (("Cannot open '%s'", path));
238 goto out;
239 }
240
241 if (fgets (buf, sizeof (buf), f) == NULL) {
242 HAL_ERROR (("Cannot read from '%s'", path));
243 goto out;
244 }
245
246 /* TODO: handle error condition */
247 *result = strtoll (buf, NULL, base);
248
249 ret = TRUE;
250
251 out:
252 if (f != NULL)
253 fclose (f);
254
255 return ret;
256 }
257
258 gboolean
hal_util_set_uint64_from_file(HalDevice * d,const gchar * key,const gchar * directory,const gchar * file,gint base)259 hal_util_set_uint64_from_file (HalDevice *d, const gchar *key, const gchar *directory, const gchar *file, gint base)
260 {
261 guint64 value;
262 gboolean ret;
263
264 ret = FALSE;
265
266 if (hal_util_get_uint64_from_file (directory, file, &value, base))
267 ret = hal_device_property_set_uint64 (d, key, value);
268
269 return ret;
270 }
271
272 gboolean
hal_util_get_bcd2_from_file(const gchar * directory,const gchar * file,gint * result)273 hal_util_get_bcd2_from_file (const gchar *directory, const gchar *file, gint *result)
274 {
275 FILE *f;
276 char buf[64];
277 gchar path[HAL_PATH_MAX];
278 gboolean ret;
279 gint digit;
280 gint left, right;
281 gboolean passed_white_space;
282 gint num_prec;
283 gsize len;
284 gchar c;
285 guint i;
286
287 f = NULL;
288 ret = FALSE;
289
290 g_snprintf (path, sizeof (path), "%s/%s", directory, file);
291
292 f = fopen (path, "rb");
293 if (f == NULL) {
294 HAL_ERROR (("Cannot open '%s'", path));
295 goto out;
296 }
297
298 if (fgets (buf, sizeof (buf), f) == NULL) {
299 HAL_ERROR (("Cannot read from '%s'", path));
300 goto out;
301 }
302
303 left = 0;
304 len = strlen (buf);
305 passed_white_space = FALSE;
306 for (i = 0; i < len && buf[i] != '.'; i++) {
307 if (g_ascii_isspace (buf[i])) {
308 if (passed_white_space)
309 break;
310 else
311 continue;
312 }
313 passed_white_space = TRUE;
314 left *= 16;
315 c = buf[i];
316 digit = (int) (c - '0');
317 left += digit;
318 }
319 i++;
320 right = 0;
321 num_prec = 0;
322 for (; i < len; i++) {
323 if (g_ascii_isspace (buf[i]))
324 break;
325 if (num_prec == 2) /* Only care about two digits
326 * of precision */
327 break;
328 right *= 16;
329 c = buf[i];
330 digit = (int) (c - '0');
331 right += digit;
332 num_prec++;
333 }
334
335 for (; num_prec < 2; num_prec++)
336 right *= 16;
337
338 *result = left * 256 + (right & 255);
339 ret = TRUE;
340
341 out:
342 if (f != NULL)
343 fclose (f);
344
345 return ret;
346 }
347
348 gboolean
hal_util_set_bcd2_from_file(HalDevice * d,const gchar * key,const gchar * directory,const gchar * file)349 hal_util_set_bcd2_from_file (HalDevice *d, const gchar *key, const gchar *directory, const gchar *file)
350 {
351 gint value;
352 gboolean ret;
353
354 ret = FALSE;
355
356 if (hal_util_get_bcd2_from_file (directory, file, &value))
357 ret = hal_device_property_set_int (d, key, value);
358
359 return ret;
360 }
361
362 gchar *
hal_util_get_string_from_file(const gchar * directory,const gchar * file)363 hal_util_get_string_from_file (const gchar *directory, const gchar *file)
364 {
365 FILE *f;
366 static gchar buf[256];
367 gchar path[HAL_PATH_MAX];
368 gchar *result;
369 gsize len;
370 gint i;
371
372 f = NULL;
373 result = NULL;
374
375 g_snprintf (path, sizeof (path), "%s/%s", directory, file);
376
377 f = fopen (path, "rb");
378 if (f == NULL) {
379 HAL_ERROR (("Cannot open '%s'", path));
380 goto out;
381 }
382
383 buf[0] = '\0';
384 if (fgets (buf, sizeof (buf), f) == NULL) {
385 HAL_ERROR (("Cannot read from '%s'", path));
386 goto out;
387 }
388
389 len = strlen (buf);
390 if (len>0)
391 buf[len-1] = '\0';
392
393 /* Clear remaining whitespace */
394 for (i = len - 2; i >= 0; --i) {
395 if (!g_ascii_isspace (buf[i]))
396 break;
397 buf[i] = '\0';
398 }
399
400 result = buf;
401
402 out:
403 if (f != NULL)
404 fclose (f);
405
406 return result;
407 }
408
409 gboolean
hal_util_set_string_from_file(HalDevice * d,const gchar * key,const gchar * directory,const gchar * file)410 hal_util_set_string_from_file (HalDevice *d, const gchar *key, const gchar *directory, const gchar *file)
411 {
412 gchar *buf;
413 gboolean ret;
414
415 ret = FALSE;
416
417 if ((buf = hal_util_get_string_from_file (directory, file)) != NULL)
418 ret = hal_device_property_set_string (d, key, buf);
419
420 return ret;
421 }
422
423 void
hal_util_compute_udi(HalDeviceStore * store,gchar * dst,gsize dstsize,const gchar * format,...)424 hal_util_compute_udi (HalDeviceStore *store, gchar *dst, gsize dstsize, const gchar *format, ...)
425 {
426 guint i;
427 va_list args;
428 gchar buf[256];
429
430 va_start (args, format);
431 g_vsnprintf (buf, sizeof (buf), format, args);
432 va_end (args);
433
434 g_strcanon (buf,
435 "/_"
436 "abcdefghijklmnopqrstuvwxyz"
437 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
438 "1234567890", '_');
439
440 g_strlcpy (dst, buf, dstsize);
441 if (hal_device_store_find (store, dst) == NULL)
442 goto out;
443
444 for (i = 0; ; i++) {
445 g_snprintf (dst, dstsize, "%s_%d", buf, i);
446 if (hal_device_store_find (store, dst) == NULL)
447 goto out;
448 }
449
450 out:
451 ;
452 }
453
454
455 gboolean
hal_util_path_ascend(gchar * path)456 hal_util_path_ascend (gchar *path)
457 {
458 gchar *p;
459
460 if (path == NULL)
461 return FALSE;
462
463 p = strrchr (path, '/');
464 if (p == NULL)
465 return FALSE;
466
467 *p = '\0';
468 return TRUE;
469 }
470
471 static gboolean _grep_can_reuse = FALSE;
472
473 void
hal_util_grep_discard_existing_data(void)474 hal_util_grep_discard_existing_data (void)
475 {
476 _grep_can_reuse = FALSE;
477 }
478
479 /** Given a directory and filename, open the file and search for the
480 * first line that starts with the given linestart string. Returns
481 * the rest of the line as a string if found.
482 *
483 * @param directory Directory, e.g. "/proc/acpi/battery/BAT0"
484 * @param file File, e.g. "info"
485 * @param linestart Start of line, e.g. "serial number"
486 * @param reuse Whether we should reuse the file contents
487 * if the file is the same; can be cleared
488 * with hal_util_grep_discard_existing_data()
489 * @return NULL if not found, otherwise the remainder
490 * of the line, e.g. ": 21805" if
491 * the file /proc/acpi/battery/BAT0 contains
492 * this line "serial number: 21805"
493 * The string is only valid until the next
494 * invocation of this function.
495 */
496 gchar *
hal_util_grep_file(const gchar * directory,const gchar * file,const gchar * linestart,gboolean reuse)497 hal_util_grep_file (const gchar *directory, const gchar *file, const gchar *linestart, gboolean reuse)
498 {
499 static gchar buf[2048];
500 static unsigned int bufsize;
501 static gchar filename[HAL_PATH_MAX];
502 static gchar oldfilename[HAL_PATH_MAX];
503 gchar *result;
504 gsize linestart_len;
505 gchar *p;
506
507 result = NULL;
508
509 /* TODO: use reuse and _grep_can_reuse parameters to avoid loading
510 * the file again and again
511 */
512
513 if (file != NULL && strlen (file) > 0)
514 snprintf (filename, sizeof (filename), "%s/%s", directory, file);
515 else
516 strncpy (filename, directory, sizeof (filename));
517
518 if (_grep_can_reuse && reuse && strcmp (oldfilename, filename) == 0) {
519 /* just reuse old file; e.g. bufsize, buf */
520 /*HAL_INFO (("hal_util_grep_file: reusing buf for %s", filename));*/
521 } else {
522 FILE *f;
523
524 f = fopen (filename, "r");
525 if (f == NULL)
526 goto out;
527 bufsize = fread (buf, sizeof (char), sizeof (buf) - 1, f);
528 buf[bufsize] = '\0';
529 fclose (f);
530
531 /*HAL_INFO (("hal_util_grep_file: read %s of %d bytes", filename, bufsize));*/
532 }
533
534 /* book keeping */
535 _grep_can_reuse = TRUE;
536 strncpy (oldfilename, filename, sizeof(oldfilename));
537
538 linestart_len = strlen (linestart);
539
540 /* analyze buf */
541 p = buf;
542 do {
543 unsigned int linelen;
544 static char line[256];
545
546 for (linelen = 0; p[linelen] != '\n' && p[linelen] != '\0'; linelen++)
547 ;
548
549 if (linelen < sizeof (line)) {
550
551 strncpy (line, p, linelen);
552 line[linelen] = '\0';
553
554 if (strncmp (line, linestart, linestart_len) == 0) {
555 result = line + linestart_len;
556 goto out;
557 }
558 }
559
560 p += linelen + 1;
561
562 } while (p < buf + bufsize);
563
564 out:
565 return result;
566 }
567
568 gchar *
hal_util_grep_string_elem_from_file(const gchar * directory,const gchar * file,const gchar * linestart,guint elem,gboolean reuse)569 hal_util_grep_string_elem_from_file (const gchar *directory, const gchar *file,
570 const gchar *linestart, guint elem, gboolean reuse)
571 {
572 gchar *line;
573 gchar *res;
574 static gchar buf[256];
575 gchar **tokens;
576 guint i, j;
577
578 res = NULL;
579 tokens = NULL;
580
581 if (((line = hal_util_grep_file (directory, file, linestart, reuse)) == NULL) || (strlen (line) == 0))
582 goto out;
583
584 tokens = g_strsplit_set (line, " \t:", 0);
585 for (i = 0, j = 0; tokens[i] != NULL; i++) {
586 if (strlen (tokens[i]) == 0)
587 continue;
588 if (j == elem) {
589 strncpy (buf, tokens[i], sizeof (buf));
590 res = buf;
591 goto out;
592 }
593 j++;
594 }
595
596 out:
597 if (tokens != NULL)
598 g_strfreev (tokens);
599
600 return res;
601 }
602
603 gint
hal_util_grep_int_elem_from_file(const gchar * directory,const gchar * file,const gchar * linestart,guint elem,guint base,gboolean reuse)604 hal_util_grep_int_elem_from_file (const gchar *directory, const gchar *file,
605 const gchar *linestart, guint elem, guint base, gboolean reuse)
606 {
607 gchar *endptr;
608 gchar *strvalue;
609 int value;
610
611 value = G_MAXINT;
612
613 strvalue = hal_util_grep_string_elem_from_file (directory, file, linestart, elem, reuse);
614 if (strvalue == NULL)
615 goto out;
616
617 value = strtol (strvalue, &endptr, base);
618 if (endptr == strvalue) {
619 value = G_MAXINT;
620 goto out;
621 }
622
623 out:
624 return value;
625 }
626
627 /** Get a string value from a formatted text file and assign it to
628 * a property on a device object.
629 *
630 * Example: Given that the file /proc/acpi/battery/BAT0/info contains
631 * the line
632 *
633 * "design voltage: 10800 mV"
634 *
635 * then hal_util_set_string_elem_from_file (d, "battery.foo",
636 * "/proc/acpi/battery/BAT0", "info", "design voltage", 1) will assign
637 * the string "mV" to the property "battery.foo" on d.
638 *
639 * @param d Device object
640 * @param key Property name
641 * @param directory Directory, e.g. "/proc/acpi/battery/BAT0"
642 * @param file File, e.g. "info"
643 * @param linestart Start of line, e.g. "design voltage"
644 * @param elem Element number after linestart to extract
645 * excluding whitespace and ':' characters.
646 * @return TRUE, if, and only if, the value could be
647 * extracted and the property was set
648 */
649 gboolean
hal_util_set_string_elem_from_file(HalDevice * d,const gchar * key,const gchar * directory,const gchar * file,const gchar * linestart,guint elem,gboolean reuse)650 hal_util_set_string_elem_from_file (HalDevice *d, const gchar *key,
651 const gchar *directory, const gchar *file,
652 const gchar *linestart, guint elem, gboolean reuse)
653 {
654 gboolean res;
655 gchar *value;
656
657 res = FALSE;
658
659 if ((value = hal_util_grep_string_elem_from_file (directory, file, linestart, elem, reuse)) == NULL)
660 goto out;
661
662 res = hal_device_property_set_string (d, key, value);
663 out:
664 return res;
665 }
666
667 /** Get an integer value from a formatted text file and assign it to
668 * a property on a device object.
669 *
670 * Example: Given that the file /proc/acpi/battery/BAT0/info contains
671 * the line
672 *
673 * "design voltage: 10800 mV"
674 *
675 * then hal_util_set_int_elem_from_file (d, "battery.foo",
676 * "/proc/acpi/battery/BAT0", "info", "design voltage", 0) will assign
677 * the integer 10800 to the property "battery.foo" on d.
678 *
679 * @param d Device object
680 * @param key Property name
681 * @param directory Directory, e.g. "/proc/acpi/battery/BAT0"
682 * @param file File, e.g. "info"
683 * @param linestart Start of line, e.g. "design voltage"
684 * @param elem Element number after linestart to extract
685 * excluding whitespace and ':' characters.
686 * @return TRUE, if, and only if, the value could be
687 * extracted and the property was set
688 */
689 gboolean
hal_util_set_int_elem_from_file(HalDevice * d,const gchar * key,const gchar * directory,const gchar * file,const gchar * linestart,guint elem,guint base,gboolean reuse)690 hal_util_set_int_elem_from_file (HalDevice *d, const gchar *key,
691 const gchar *directory, const gchar *file,
692 const gchar *linestart, guint elem, guint base, gboolean reuse)
693 {
694 gchar *endptr;
695 gboolean res;
696 gchar *strvalue;
697 int value;
698
699 res = FALSE;
700
701 strvalue = hal_util_grep_string_elem_from_file (directory, file, linestart, elem, reuse);
702 if (strvalue == NULL)
703 goto out;
704
705 value = strtol (strvalue, &endptr, base);
706 if (endptr == strvalue)
707 goto out;
708
709 res = hal_device_property_set_int (d, key, value);
710
711 out:
712 return res;
713
714 }
715
716 /** Get a value from a formatted text file, test it against a given
717 * value, and set a boolean property on a device object with the
718 * test result.
719 *
720 * Example: Given that the file /proc/acpi/battery/BAT0/info contains
721 * the line
722 *
723 * "present: yes"
724 *
725 * then hal_util_set_bool_elem_from_file (d, "battery.baz",
726 * "/proc/acpi/battery/BAT0", "info", "present", 0, "yes") will assign
727 * the boolean TRUE to the property "battery.baz" on d.
728 *
729 * If, instead, the line was
730 *
731 * "present: no"
732 *
733 * the value assigned will be FALSE.
734 *
735 * @param d Device object
736 * @param key Property name
737 * @param directory Directory, e.g. "/proc/acpi/battery/BAT0"
738 * @param file File, e.g. "info"
739 * @param linestart Start of line, e.g. "design voltage"
740 * @param elem Element number after linestart to extract
741 * excluding whitespace and ':' characters.
742 * @param expected Value to test against
743 * @return TRUE, if, and only if, the value could be
744 * extracted and the property was set
745 */
746 gboolean
hal_util_set_bool_elem_from_file(HalDevice * d,const gchar * key,const gchar * directory,const gchar * file,const gchar * linestart,guint elem,const gchar * expected,gboolean reuse)747 hal_util_set_bool_elem_from_file (HalDevice *d, const gchar *key,
748 const gchar *directory, const gchar *file,
749 const gchar *linestart, guint elem, const gchar *expected, gboolean reuse)
750 {
751 gchar *line;
752 gboolean res;
753 gchar **tokens;
754 guint i, j;
755
756 res = FALSE;
757 tokens = NULL;
758
759 if (((line = hal_util_grep_file (directory, file, linestart, reuse)) == NULL) || (strlen (line) == 0))
760 goto out;
761
762 tokens = g_strsplit_set (line, " \t:", 0);
763
764 for (i = 0, j = 0; tokens[i] != NULL; i++) {
765 if (strlen (tokens[i]) == 0)
766 continue;
767 if (j == elem) {
768 hal_device_property_set_bool (d, key, strcmp (tokens[i], expected) == 0);
769 res = TRUE;
770 goto out;
771 }
772 j++;
773 }
774
775
776 out:
777 if (tokens != NULL)
778 g_strfreev (tokens);
779
780 return res;
781 }
782
783 gchar **
hal_util_dup_strv_from_g_slist(GSList * strlist)784 hal_util_dup_strv_from_g_slist (GSList *strlist)
785 {
786 guint j;
787 guint len;
788 gchar **strv;
789 GSList *i;
790
791 len = g_slist_length (strlist);
792 strv = g_new (char *, len + 1);
793
794 for (i = strlist, j = 0; i != NULL; i = g_slist_next (i), j++) {
795 strv[j] = g_strdup ((const gchar *) i->data);
796 }
797 strv[j] = NULL;
798
799 return strv;
800 }
801
802 /* -------------------------------------------------------------------------------------------------------------- */
803
804 typedef struct {
805 HalDevice *d;
806 gchar **programs;
807 gchar **extra_env;
808 guint next_program;
809
810 HalCalloutsDone callback;
811 gpointer userdata1;
812 gpointer userdata2;
813
814 } Callout;
815
816 static void callout_do_next (Callout *c);
817
818 static void
callout_terminated(HalDevice * d,guint32 exit_type,gint return_code,gchar ** error,gpointer data1,gpointer data2)819 callout_terminated (HalDevice *d, guint32 exit_type,
820 gint return_code, gchar **error,
821 gpointer data1, gpointer data2)
822 {
823 Callout *c;
824
825 c = (Callout *) data1;
826 callout_do_next (c);
827 }
828
829 static void
callout_do_next(Callout * c)830 callout_do_next (Callout *c)
831 {
832
833 /* Check if we're done */
834 if (c->programs[c->next_program] == NULL) {
835 HalDevice *d;
836 gpointer userdata1;
837 gpointer userdata2;
838 HalCalloutsDone callback;
839
840 d = c->d;
841 userdata1 = c->userdata1;
842 userdata2 = c->userdata2;
843 callback = c->callback;
844
845 g_strfreev (c->programs);
846 g_strfreev (c->extra_env);
847 g_free (c);
848
849 callback (d, userdata1, userdata2);
850
851 } else {
852 hald_runner_run(c->d, c->programs[c->next_program], c->extra_env,
853 HAL_HELPER_TIMEOUT, callout_terminated,
854 (gpointer)c, NULL);
855 c->next_program++;
856 }
857 }
858
859 static void
hal_callout_device(HalDevice * d,HalCalloutsDone callback,gpointer userdata1,gpointer userdata2,GSList * programs,gchar ** extra_env)860 hal_callout_device (HalDevice *d, HalCalloutsDone callback, gpointer userdata1, gpointer userdata2,
861 GSList *programs, gchar **extra_env)
862 {
863 Callout *c;
864
865 c = g_new0 (Callout, 1);
866 c->d = d;
867 c->callback = callback;
868 c->userdata1 = userdata1;
869 c->userdata2 = userdata2;
870 c->programs = hal_util_dup_strv_from_g_slist (programs);
871 c->extra_env = g_strdupv (extra_env);
872 c->next_program = 0;
873
874 callout_do_next (c);
875 }
876
877 void
hal_util_callout_device_add(HalDevice * d,HalCalloutsDone callback,gpointer userdata1,gpointer userdata2)878 hal_util_callout_device_add (HalDevice *d, HalCalloutsDone callback, gpointer userdata1, gpointer userdata2)
879 {
880 GSList *programs;
881 gchar *extra_env[2] = {"HALD_ACTION=add", NULL};
882
883 if ((programs = hal_device_property_get_strlist (d, "info.callouts.add")) == NULL) {
884 callback (d, userdata1, userdata2);
885 goto out;
886 }
887
888 HAL_INFO (("Add callouts for udi=%s", d->udi));
889
890 hal_callout_device (d, callback, userdata1, userdata2, programs, extra_env);
891 out:
892 ;
893 }
894
895 void
hal_util_callout_device_remove(HalDevice * d,HalCalloutsDone callback,gpointer userdata1,gpointer userdata2)896 hal_util_callout_device_remove (HalDevice *d, HalCalloutsDone callback, gpointer userdata1, gpointer userdata2)
897 {
898 GSList *programs;
899 gchar *extra_env[2] = {"HALD_ACTION=remove", NULL};
900
901 if ((programs = hal_device_property_get_strlist (d, "info.callouts.remove")) == NULL) {
902 callback (d, userdata1, userdata2);
903 goto out;
904 }
905
906 HAL_INFO (("Remove callouts for udi=%s", d->udi));
907
908 hal_callout_device (d, callback, userdata1, userdata2, programs, extra_env);
909 out:
910 ;
911 }
912
913 void
hal_util_callout_device_preprobe(HalDevice * d,HalCalloutsDone callback,gpointer userdata1,gpointer userdata2)914 hal_util_callout_device_preprobe (HalDevice *d, HalCalloutsDone callback, gpointer userdata1, gpointer userdata2)
915 {
916 GSList *programs;
917 gchar *extra_env[2] = {"HALD_ACTION=preprobe", NULL};
918
919 if ((programs = hal_device_property_get_strlist (d, "info.callouts.preprobe")) == NULL) {
920 callback (d, userdata1, userdata2);
921 goto out;
922 }
923
924 HAL_INFO (("Preprobe callouts for udi=%s", d->udi));
925
926 hal_callout_device (d, callback, userdata1, userdata2, programs, extra_env);
927 out:
928 ;
929 }
930
931 gchar *
hal_util_strdup_valid_utf8(const char * str)932 hal_util_strdup_valid_utf8 (const char *str)
933 {
934 char *endchar;
935 char *newstr;
936 unsigned int count = 0;
937
938 if (str == NULL)
939 return NULL;
940
941 newstr = g_strdup (str);
942
943 while (!g_utf8_validate (newstr, -1, (const char **) &endchar)) {
944 *endchar = '?';
945 count++;
946 }
947
948 if (strlen(newstr) == count)
949 return NULL;
950 else
951 return newstr;
952 }
953
954 void
hal_util_hexdump(const void * mem,unsigned int size)955 hal_util_hexdump (const void *mem, unsigned int size)
956 {
957 unsigned int i;
958 unsigned int j;
959 unsigned int n;
960 const char *buf = (const char *) mem;
961
962 n = 0;
963 printf ("Dumping %d=0x%x bytes\n", size, size);
964 while (n < size) {
965
966 printf ("0x%04x: ", n);
967
968 j = n;
969 for (i = 0; i < 16; i++) {
970 if (j >= size)
971 break;
972 printf ("%02x ", buf[j]);
973 j++;
974 }
975
976 for ( ; i < 16; i++) {
977 printf (" ");
978 }
979
980 printf (" ");
981
982 j = n;
983 for (i = 0; i < 16; i++) {
984 if (j >= size)
985 break;
986 printf ("%c", isprint(buf[j]) ? buf[j] : '.');
987 j++;
988 }
989
990 printf ("\n");
991
992 n += 16;
993 }
994 }
995
996 gboolean
hal_util_is_mounted_by_hald(const char * mount_point)997 hal_util_is_mounted_by_hald (const char *mount_point)
998 {
999 int i;
1000 FILE *hal_mtab;
1001 int hal_mtab_len;
1002 int num_read;
1003 char *hal_mtab_buf;
1004 char **lines;
1005 gboolean found;
1006
1007 hal_mtab = NULL;
1008 hal_mtab_buf = NULL;
1009 found = FALSE;
1010
1011 /*HAL_DEBUG (("examining /media/.hal-mtab for %s", mount_point));*/
1012
1013 hal_mtab = fopen ("/media/.hal-mtab", "r");
1014 if (hal_mtab == NULL) {
1015 HAL_ERROR (("Cannot open /media/.hal-mtab"));
1016 goto out;
1017 }
1018 if (fseek (hal_mtab, 0L, SEEK_END) != 0) {
1019 HAL_ERROR (("Cannot seek to end of /media/.hal-mtab"));
1020 goto out;
1021 }
1022 hal_mtab_len = ftell (hal_mtab);
1023 if (hal_mtab_len < 0) {
1024 HAL_ERROR (("Cannot determine size of /media/.hal-mtab"));
1025 goto out;
1026 }
1027 rewind (hal_mtab);
1028
1029 hal_mtab_buf = g_new0 (char, hal_mtab_len + 1);
1030 num_read = fread (hal_mtab_buf, 1, hal_mtab_len, hal_mtab);
1031 if (num_read != hal_mtab_len) {
1032 HAL_ERROR (("Cannot read from /media/.hal-mtab"));
1033 goto out;
1034 }
1035 fclose (hal_mtab);
1036 hal_mtab = NULL;
1037
1038 /*HAL_DEBUG (("hal_mtab = '%s'\n", hal_mtab_buf));*/
1039
1040 lines = g_strsplit (hal_mtab_buf, "\n", 0);
1041 g_free (hal_mtab_buf);
1042 hal_mtab_buf = NULL;
1043
1044 /* find the entry we're going to unmount */
1045 for (i = 0; lines[i] != NULL && !found; i++) {
1046 char **line_elements;
1047
1048 /*HAL_DEBUG ((" line = '%s'", lines[i]));*/
1049
1050 if ((lines[i])[0] == '#')
1051 continue;
1052
1053 line_elements = g_strsplit (lines[i], "\t", 6);
1054 if (g_strv_length (line_elements) == 6) {
1055 /*
1056 HAL_DEBUG ((" devfile = '%s'", line_elements[0]));
1057 HAL_DEBUG ((" uid = '%s'", line_elements[1]));
1058 HAL_DEBUG ((" session id = '%s'", line_elements[2]));
1059 HAL_DEBUG ((" fs = '%s'", line_elements[3]));
1060 HAL_DEBUG ((" options = '%s'", line_elements[4]));
1061 HAL_DEBUG ((" mount_point = '%s'", line_elements[5]));
1062 HAL_DEBUG ((" (comparing against '%s')", mount_point));
1063 */
1064
1065 if (strcmp (line_elements[5], mount_point) == 0) {
1066 found = TRUE;
1067 /*HAL_INFO (("device at '%s' is indeed mounted by HAL's Mount()", mount_point));*/
1068 }
1069
1070 }
1071
1072 g_strfreev (line_elements);
1073 }
1074
1075 g_strfreev (lines);
1076
1077 out:
1078 if (hal_mtab != NULL)
1079 fclose (hal_mtab);
1080 if (hal_mtab_buf != NULL)
1081 g_free (hal_mtab_buf);
1082
1083 return found;
1084 }
1085
1086 void
hal_util_branch_claim(HalDeviceStore * store,HalDevice * root,dbus_bool_t claimed,const char * service,int uid)1087 hal_util_branch_claim (HalDeviceStore *store, HalDevice *root, dbus_bool_t claimed,
1088 const char *service, int uid)
1089 {
1090 GSList *children;
1091 GSList *i;
1092 HalDevice *d;
1093
1094 if (claimed) {
1095 hal_device_property_set_bool (root, "info.claimed", claimed);
1096 hal_device_property_set_string (root, "info.claimed.service", service);
1097 hal_device_property_set_int (root, "info.claimed.uid", uid);
1098 } else {
1099 hal_device_property_remove (root, "info.claimed");
1100 hal_device_property_remove (root, "info.claimed.service");
1101 hal_device_property_remove (root, "info.claimed.uid");
1102 }
1103
1104
1105 children = hal_device_store_match_multiple_key_value_string (store,
1106 "info.parent", root->udi);
1107
1108 for (i = children; i != NULL; i = g_slist_next (i)) {
1109 d = HAL_DEVICE (i->data);
1110 hal_util_branch_claim (store, d, claimed, service, uid);
1111 }
1112
1113 g_slist_free (children);
1114 }
1115
1116 /** Given an interface name, check if it is valid.
1117 * @param name A given interface name
1118 * @return TRUE if name is valid, otherwise FALSE
1119 */
1120 gboolean
is_valid_interface_name(const char * name)1121 is_valid_interface_name(const char *name) {
1122
1123 const char *end;
1124 const char *last_dot;
1125
1126 last_dot = NULL;
1127
1128 if (strlen(name) == 0)
1129 return FALSE;
1130
1131 end = name + strlen(name);
1132
1133 if (*name == '.') /* disallow starting with a . */
1134 return FALSE;
1135 else if (!VALID_INITIAL_NAME_CHARACTER (*name))
1136 return FALSE;
1137 else
1138 name++;
1139
1140 while (name != end) {
1141 if (*name == '.') {
1142 if ((name + 1) == end)
1143 return FALSE;
1144 else if (!VALID_INITIAL_NAME_CHARACTER (*(name + 1)))
1145 return FALSE;
1146 last_dot = name;
1147 name++; /* we just validated the next char, so skip two */
1148 } else if (!VALID_NAME_CHARACTER (*name))
1149 return FALSE;
1150 name++;
1151 }
1152 if (last_dot == NULL)
1153 return FALSE;
1154
1155 return TRUE;
1156 }
1157