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