00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifdef HAVE_CONFIG_H
00027 # include <config.h>
00028 #endif
00029
00030 #define _GNU_SOURCE 1
00031
00032 #include <ctype.h>
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <getopt.h>
00037 #include <assert.h>
00038 #include <unistd.h>
00039 #include <stdarg.h>
00040 #include <limits.h>
00041
00042 #include <sys/types.h>
00043 #include <sys/stat.h>
00044
00045 #include "../logger.h"
00046 #include "../device_store.h"
00047 #include "../device_info.h"
00048 #include "../hald.h"
00049 #include "common.h"
00050
00064 double
00065 parse_double (const char *str)
00066 {
00068 return atof (str);
00069 }
00070
00077 dbus_int32_t
00078 parse_dec (const char *str)
00079 {
00080 dbus_int32_t value;
00081 value = strtol (str, NULL, 10);
00083 return value;
00084 }
00085
00093 dbus_int32_t
00094 parse_hex (const char *str)
00095 {
00096 dbus_int32_t value;
00097 value = strtol (str, NULL, 16);
00099 return value;
00100 }
00101
00113 long int
00114 find_num (char *pre, char *s, int base)
00115 {
00116 char *where;
00117 int result;
00118
00119 where = strstr (s, pre);
00120 if (where == NULL) {
00121
00122 return LONG_MAX;
00123 }
00124 where += strlen (pre);
00125
00126 result = strtol (where, NULL, base);
00128
00129
00130
00131
00132
00133 return result;
00134 }
00135
00146 double
00147 find_double (char *pre, char *s)
00148 {
00149 char *where;
00150 double result;
00151
00152 where = strstr (s, pre);
00154 if (where == NULL)
00155 DIE (("Didn't find '%s' in '%s'", pre, s));
00156 where += strlen (pre);
00157
00158 result = atof (where);
00159
00160 return result;
00161 }
00162
00173 int
00174 find_bcd2 (char *pre, char *s)
00175 {
00176 int i;
00177 char c;
00178 int digit;
00179 int left, right, result;
00180 int len;
00181 char *str;
00182 dbus_bool_t passed_white_space;
00183 int num_prec;
00184
00185 str = find_string (pre, s);
00186 if (str == NULL || strlen (str) == 0)
00187 return 0xffff;
00188
00189
00190 left = 0;
00191 len = strlen (str);
00192 passed_white_space = FALSE;
00193 for (i = 0; i < len && str[i] != '.'; i++) {
00194 if (isspace (str[i])) {
00195 if (passed_white_space)
00196 break;
00197 else
00198 continue;
00199 }
00200 passed_white_space = TRUE;
00201 left *= 16;
00202 c = str[i];
00203 digit = (int) (c - '0');
00204 left += digit;
00205 }
00206 i++;
00207 right = 0;
00208 num_prec = 0;
00209 for (; i < len; i++) {
00210 if (isspace (str[i]))
00211 break;
00212 if (num_prec == 2)
00213
00214 break;
00215 right *= 16;
00216 c = str[i];
00217 digit = (int) (c - '0');
00218 right += digit;
00219 num_prec++;
00220 }
00221
00222 for (; num_prec < 2; num_prec++)
00223 right *= 16;
00224
00225 result = left * 256 + (right & 255);
00226 return result;
00227 }
00228
00239 char *
00240 find_string (char *pre, char *s)
00241 {
00242 char *where;
00243 static char buf[256];
00244 char *p;
00245
00246 where = strstr (s, pre);
00247 if (where == NULL)
00248 return NULL;
00249 where += strlen (pre);
00250
00251 p = buf;
00252 while (*where != '\n' && *where != '\r') {
00253 char c = *where;
00254
00255
00256
00257
00258 if ((isalnum (c) || isspace (c) || ispunct (c)) && c != 63) {
00259 *p = c;
00260 ++p;
00261 }
00262
00263 ++where;
00264 }
00265 *p = '\0';
00266
00267
00268 --p;
00269 while (isspace (*p)) {
00270 *p = '\0';
00271 --p;
00272 }
00273
00274 return buf;
00275 }
00276
00284 char *
00285 read_single_line (char *filename_format, ...)
00286 {
00287 FILE *f;
00288 int i;
00289 int len;
00290 char filename[512];
00291 static char buf[512];
00292 va_list args;
00293
00294 va_start (args, filename_format);
00295 vsnprintf (filename, 512, filename_format, args);
00296 va_end (args);
00297
00298 f = fopen (filename, "rb");
00299 if (f == NULL)
00300 return NULL;
00301
00302 if (fgets (buf, 512, f) == NULL) {
00303 fclose (f);
00304 return NULL;
00305 }
00306
00307 len = strlen (buf);
00308 for (i = len - 1; i > 0; --i) {
00309 if (buf[i] == '\n' || buf[i] == '\r')
00310 buf[i] = '\0';
00311 else
00312 break;
00313 }
00314
00315 fclose (f);
00316 return buf;
00317 }
00318
00325 const char *
00326 get_last_element (const char *s)
00327 {
00328 int len;
00329 const char *p;
00330
00331 len = strlen (s);
00332 for (p = s + len - 1; p > s; --p) {
00333 if ((*p) == '/')
00334 return p + 1;
00335 }
00336
00337 return s;
00338 }
00339
00340
00341
00342
00343
00344 const char *
00345 udevinfo_path (void)
00346 {
00347 char *possible_paths[] = { "/sbin/udevinfo",
00348 "/usr/bin/udevinfo",
00349 "/usr/sbin/udevinfo",
00350 "/usr/local/sbin/udevinfo"
00351 };
00352 char *path = NULL;
00353 unsigned int i;
00354 struct stat s;
00355 for (i = 0; i < sizeof (possible_paths) / sizeof (char *); i++) {
00356 if (stat (possible_paths[i], &s) == 0
00357 && S_ISREG (s.st_mode)) {
00358 path = possible_paths[i];
00359 break;
00360 }
00361 }
00362 return path;
00363 }
00364
00391 char *
00392 rename_and_merge (HalDevice * d,
00393 ComputeFDI naming_func, const char *namespace)
00394 {
00395 int append_num;
00396 char *computed_udi;
00397 HalDevice *computed_d;
00398
00399
00400
00401 append_num = -1;
00402 tryagain:
00403
00404 computed_udi = (*naming_func) (d, append_num);
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418 computed_d = hal_device_store_find (hald_get_gdl (), computed_udi);
00419 if (computed_d != NULL) {
00420
00421 if ((!hal_device_has_property
00422 (computed_d, "info.not_available"))
00423 &&
00424 (!hal_device_property_get_bool
00425 (computed_d, "info.not_available"))) {
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444 if (hal_device_matches (computed_d, d, namespace)) {
00445 HAL_ERROR (("Found device already present "
00446 "as '%s'!\n", computed_d->udi));
00447 hal_device_print (d);
00448 hal_device_print (computed_d);
00449
00450 hal_device_store_remove (hald_get_tdl (), d);
00451 g_object_unref (d);
00452
00453 return NULL;
00454 }
00455
00458 append_num++;
00459 goto tryagain;
00460 } else {
00461
00462 append_num++;
00463 goto tryagain;
00464 }
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 hal_device_merge (computed_d, d);
00476
00477
00478 hal_device_property_set_bool (computed_d, "info.not_available",
00479 FALSE);
00480
00481 HAL_INFO (("Device %s is plugged in again",
00482 computed_d->udi));
00483
00484 } else {
00485
00486
00487
00488
00489 hal_device_set_udi (d, computed_udi);
00490 hal_device_property_set_string (d, "info.udi", computed_udi);
00491
00492
00493 if (di_search_and_merge (d)) {
00494 HAL_INFO (("Found a .fdi file for %s", d->udi));
00495 }
00496
00497 }
00498
00499 return computed_udi;
00500 }
00501
00508 char *
00509 get_parent_sysfs_path (const char *path)
00510 {
00511 int i;
00512 int len;
00513 char *parent_path;
00514
00515
00516 parent_path = strndup (path, SYSFS_PATH_MAX);
00517 if (parent_path == NULL)
00518 DIE (("No memory"));
00519 len = strlen (parent_path);
00520 for (i = len - 1; parent_path[i] != '/'; --i) {
00521 parent_path[i] = '\0';
00522 }
00523 parent_path[i] = '\0';
00524
00525 return parent_path;
00526 }
00527
00536 void
00537 find_and_set_physical_device (HalDevice * device)
00538 {
00539 HalDevice *d;
00540 HalDevice *parent;
00541 const char *parent_udi;
00542
00543 d = device;
00544 do {
00545 parent_udi = hal_device_property_get_string (d,
00546 "info.parent");
00547 if (parent_udi == NULL) {
00548 HAL_ERROR (("Error finding parent for %s\n",
00549 d->udi));
00550 return;
00551 }
00552
00553 parent = hal_device_store_find (hald_get_gdl (), parent_udi);
00554 if (parent == NULL) {
00555 HAL_ERROR (("Error resolving UDI %s\n",
00556 parent_udi));
00557 return;
00558 }
00559
00560 if (!hal_device_has_property (parent,
00561 "info.physical_device")) {
00562 hal_device_property_set_string (device,
00563 "info.physical_device",
00564 parent_udi);
00565 return;
00566 }
00567
00568 d = parent;
00569 }
00570 while (TRUE);
00571 }
00572
00584 dbus_bool_t
00585 class_device_get_major_minor (const char *sysfs_path, int *major, int *minor)
00586 {
00587 struct sysfs_attribute *attr;
00588 char attr_path[SYSFS_PATH_MAX];
00589
00590 snprintf (attr_path, SYSFS_PATH_MAX, "%s/dev", sysfs_path);
00591 attr = sysfs_open_attribute (attr_path);
00592 if (sysfs_read_attribute (attr) >= 0) {
00593 if (sscanf (attr->value, "%d:%d", major, minor) != 2) {
00594 HAL_WARNING (("Could not parse '%s'", attr->value));
00595 sysfs_close_attribute (attr);
00596 return TRUE;
00597 }
00598 sysfs_close_attribute (attr);
00599 return TRUE;
00600 }
00601
00602 return FALSE;
00603 }
00604
00613 dbus_bool_t
00614 class_device_get_device_file (const char *sysfs_path,
00615 char *dev_file, int dev_file_length)
00616 {
00617 int i;
00618 unsigned int sysfs_mount_path_len;
00619 char sysfs_path_trunc[SYSFS_NAME_LEN];
00620 char *udev_argv[7] = { (char *) udevinfo_path (),
00621 "-r", "-q", "name", "-p",
00622 sysfs_path_trunc, NULL };
00623 char *udev_stdout;
00624 char *udev_stderr;
00625 int udev_exitcode;
00626
00627
00628
00629 sysfs_mount_path_len = strlen (sysfs_mount_path);
00630 if (strlen (sysfs_path) > sysfs_mount_path_len) {
00631 strncpy (sysfs_path_trunc, sysfs_path + sysfs_mount_path_len,
00632 SYSFS_NAME_LEN);
00633 }
00634
00635
00636
00637
00638 if (udev_argv[0] == NULL || g_spawn_sync ("/",
00639 udev_argv,
00640 NULL,
00641 0,
00642 NULL,
00643 NULL,
00644 &udev_stdout,
00645 &udev_stderr,
00646 &udev_exitcode,
00647 NULL) != TRUE) {
00648 HAL_ERROR (("Couldn't invoke %s", udevinfo_path ()));
00649 return FALSE;
00650 }
00651
00652 if (udev_exitcode != 0) {
00653 HAL_ERROR (("%s returned %d", udevinfo_path (),
00654 udev_exitcode));
00655 return FALSE;
00656 }
00657
00658
00659 for (i = 0; udev_stdout[i] != 0; i++) {
00660 if (udev_stdout[i] == '\r' || udev_stdout[i] == '\n') {
00661 udev_stdout[i] = 0;
00662 break;
00663 }
00664 }
00665
00666
00667
00668 strncpy (dev_file, udev_stdout, dev_file_length);
00669 return TRUE;
00670 }
00671
00672
00673
00674 struct driver_entry_s {
00675 char driver_name[SYSFS_NAME_LEN];
00677 char device_path[SYSFS_PATH_MAX];
00679 struct driver_entry_s *next;
00681 };
00682
00684 static struct driver_entry_s *drivers_table_head = NULL;
00685
00691 static void
00692 drivers_add_entry (const char *driver_name, const char *device_path)
00693 {
00694 struct driver_entry_s *entry;
00695
00696 entry = malloc (sizeof (struct driver_entry_s));
00697 if (entry == NULL)
00698 DIE (("Out of memory"));
00699 strncpy (entry->driver_name, driver_name, SYSFS_NAME_LEN);
00700 strncpy (entry->device_path, device_path, SYSFS_PATH_MAX);
00701 entry->next = drivers_table_head;
00702 drivers_table_head = entry;
00703 }
00704
00712 const char *
00713 drivers_lookup (const char *device_path)
00714 {
00715 struct driver_entry_s *i;
00716
00717 for (i = drivers_table_head; i != NULL; i = i->next) {
00718 if (strcmp (device_path, i->device_path) == 0)
00719 return i->driver_name;
00720 }
00721 return NULL;
00722 }
00723
00729 void
00730 drivers_collect (const char *bus_name)
00731 {
00732 char path[SYSFS_PATH_MAX];
00733 struct sysfs_directory *current;
00734 struct sysfs_link *current2;
00735 struct sysfs_directory *dir;
00736 struct sysfs_directory *dir2;
00737
00738
00739 snprintf (path, SYSFS_PATH_MAX, "%s/bus/%s/drivers",
00740 sysfs_mount_path, bus_name);
00741 dir = sysfs_open_directory (path);
00742 if (dir == NULL) {
00743 HAL_WARNING (("Error opening sysfs directory at %s\n",
00744 path));
00745 goto out;
00746 }
00747 if (sysfs_read_directory (dir) != 0) {
00748 HAL_WARNING (("Error reading sysfs directory at %s\n",
00749 path));
00750 goto out;
00751 }
00752 if (dir->subdirs != NULL) {
00753 dlist_for_each_data (dir->subdirs, current,
00754 struct sysfs_directory) {
00755
00756
00757 dir2 = sysfs_open_directory (current->path);
00758 if (dir2 == NULL)
00759 DIE (("Error opening sysfs directory "
00760 "at %s\n", current->path));
00761 if (sysfs_read_directory (dir2) != 0)
00762 DIE (("Error reading sysfs directory "
00763 "at %s\n", current->path));
00764
00765 if (dir2->links != NULL) {
00766 dlist_for_each_data (dir2->links, current2,
00767 struct sysfs_link) {
00768
00769
00770 drivers_add_entry (current->name,
00771 current2->
00772 target);
00773 }
00774 sysfs_close_directory (dir2);
00775 }
00776 }
00777 }
00778 out:
00779 if (dir != NULL)
00780 sysfs_close_directory (dir);
00781 }
00782