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 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 * 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 * 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 * 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 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 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 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 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 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 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 * 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 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 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 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 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 * 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 * 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 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 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 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 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 ** 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 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 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 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 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 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 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 * 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 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 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 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 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