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