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 <libhal/libhal.h>
00046
00047 #include "../logger.h"
00048 #include "../device_store.h"
00049 #include "../device_info.h"
00050 #include "linux_common.h"
00051
00065 double
00066 parse_double (const char *str)
00067 {
00069 return atof (str);
00070 }
00071
00078 dbus_int32_t
00079 parse_dec (const char *str)
00080 {
00081 dbus_int32_t value;
00082 value = strtol (str, NULL, 10);
00084 return value;
00085 }
00086
00094 dbus_int32_t
00095 parse_hex (const char *str)
00096 {
00097 dbus_int32_t value;
00098 value = strtol (str, NULL, 16);
00100 return value;
00101 }
00102
00114 long int
00115 find_num (char *pre, char *s, int base)
00116 {
00117 char *where;
00118 int result;
00119
00120 where = strstr (s, pre);
00121 if (where == NULL) {
00122
00123 return LONG_MAX;
00124 }
00125 where += strlen (pre);
00126
00127 result = strtol (where, NULL, base);
00129
00130
00131
00132
00133
00134 return result;
00135 }
00136
00147 double
00148 find_double (char *pre, char *s)
00149 {
00150 char *where;
00151 double result;
00152
00153 where = strstr (s, pre);
00155 if (where == NULL)
00156 DIE (("Didn't find '%s' in '%s'", pre, s));
00157 where += strlen (pre);
00158
00159 result = atof (where);
00160
00161 return result;
00162 }
00163
00174 int
00175 find_bcd2 (char *pre, char *s)
00176 {
00177 int i;
00178 char c;
00179 int digit;
00180 int left, right, result;
00181 int len;
00182 char *str;
00183 dbus_bool_t passed_white_space;
00184 int num_prec;
00185
00186 str = find_string (pre, s);
00187 if (str == NULL || strlen (str) == 0)
00188 return 0xffff;
00189
00190
00191 left = 0;
00192 len = strlen (str);
00193 passed_white_space = FALSE;
00194 for (i = 0; i < len && str[i] != '.'; i++) {
00195 if (isspace (str[i])) {
00196 if (passed_white_space)
00197 break;
00198 else
00199 continue;
00200 }
00201 passed_white_space = TRUE;
00202 left *= 16;
00203 c = str[i];
00204 digit = (int) (c - '0');
00205 left += digit;
00206 }
00207 i++;
00208 right = 0;
00209 num_prec = 0;
00210 for (; i < len; i++) {
00211 if (isspace (str[i]))
00212 break;
00213 if (num_prec == 2)
00214
00215 break;
00216 right *= 16;
00217 c = str[i];
00218 digit = (int) (c - '0');
00219 right += digit;
00220 num_prec++;
00221 }
00222
00223 for (; num_prec < 2; num_prec++)
00224 right *= 16;
00225
00226 result = left * 256 + (right & 255);
00227 return result;
00228 }
00229
00240 char *
00241 find_string (char *pre, char *s)
00242 {
00243 char *where;
00244 static char buf[256];
00245 char *p;
00246
00247 where = strstr (s, pre);
00248 if (where == NULL)
00249 return NULL;
00250 where += strlen (pre);
00251
00252 p = buf;
00253 while (*where != '\n' && *where != '\r') {
00254 char c = *where;
00255
00256
00257
00258
00259 if ((isalnum (c) || isspace (c) || ispunct (c)) && c != 63) {
00260 *p = c;
00261 ++p;
00262 }
00263
00264 ++where;
00265 }
00266 *p = '\0';
00267
00268
00269 --p;
00270 while (isspace (*p)) {
00271 *p = '\0';
00272 --p;
00273 }
00274
00275 return buf;
00276 }
00277
00285 char *
00286 read_single_line (char *filename_format, ...)
00287 {
00288 FILE *f;
00289 int i;
00290 int len;
00291 char filename[512];
00292 static char buf[512];
00293 va_list args;
00294
00295 va_start (args, filename_format);
00296 vsnprintf (filename, 512, filename_format, args);
00297 va_end (args);
00298
00299 f = fopen (filename, "rb");
00300 if (f == NULL)
00301 return NULL;
00302
00303 if (fgets (buf, 512, f) == NULL) {
00304 fclose (f);
00305 return NULL;
00306 }
00307
00308 len = strlen (buf);
00309 for (i = len - 1; i > 0; --i) {
00310 if (buf[i] == '\n' || buf[i] == '\r')
00311 buf[i] = '\0';
00312 else
00313 break;
00314 }
00315
00316 fclose (f);
00317 return buf;
00318 }
00319
00326 const char *
00327 get_last_element (const char *s)
00328 {
00329 int len;
00330 const char *p;
00331
00332 len = strlen (s);
00333 for (p = s + len - 1; p > s; --p) {
00334 if ((*p) == '/')
00335 return p + 1;
00336 }
00337
00338 return s;
00339 }
00340
00341
00342
00343
00344
00345 const char *
00346 udevinfo_path (void)
00347 {
00348 char *possible_paths[] = { "/sbin/udevinfo",
00349 "/usr/bin/udevinfo",
00350 "/usr/sbin/udevinfo",
00351 "/usr/local/sbin/udevinfo"
00352 };
00353 char *path = NULL;
00354 unsigned int i;
00355 struct stat s;
00356 for (i = 0; i < sizeof (possible_paths) / sizeof (char *); i++) {
00357 if (stat (possible_paths[i], &s) == 0
00358 && S_ISREG (s.st_mode)) {
00359 path = possible_paths[i];
00360 break;
00361 }
00362 }
00363 return path;
00364 }
00365
00392 char *
00393 rename_and_merge (HalDevice * d,
00394 ComputeFDI naming_func, const char *namespace)
00395 {
00396 int append_num;
00397 char *computed_udi;
00398 HalDevice *computed_d;
00399
00400
00401
00402 append_num = -1;
00403 tryagain:
00404
00405 computed_udi = (*naming_func) (d, append_num);
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419 computed_d = ds_device_find (computed_udi);
00420 if (computed_d != NULL) {
00421
00422 if ((!ds_property_exists
00423 (computed_d, "info.not_available"))
00424 &&
00425 (!ds_property_get_bool
00426 (computed_d, "info.not_available"))) {
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445 if (ds_device_matches (computed_d, d, namespace)) {
00446 HAL_ERROR (("Found device already present "
00447 "as '%s'!\n", computed_d->udi));
00448 ds_print (d);
00449 ds_print (computed_d);
00450
00451 ds_device_destroy (d);
00452
00453 return NULL;
00454 }
00455
00458 append_num++;
00459 goto tryagain;
00460 }
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471 ds_device_merge (computed_d, d);
00472
00473
00474 ds_device_destroy (d);
00475
00476
00477 ds_property_set_bool (computed_d, "info.not_available",
00478 FALSE);
00479
00480 HAL_INFO (("Device %s is plugged in again",
00481 computed_d->udi));
00482
00483 } else {
00484
00485
00486
00487 ds_device_set_udi (d, computed_udi);
00488 ds_property_set_string (d, "info.udi", computed_udi);
00489
00490
00491 if (di_search_and_merge (d)) {
00492 HAL_INFO (("Found a .fdi file for %s", d->udi));
00493 }
00494
00495 }
00496
00497 return computed_udi;
00498 }
00499
00506 char *
00507 get_parent_sysfs_path (const char *path)
00508 {
00509 int i;
00510 int len;
00511 char *parent_path;
00512
00513
00514 parent_path = strndup (path, SYSFS_PATH_MAX);
00515 if (parent_path == NULL)
00516 DIE (("No memory"));
00517 len = strlen (parent_path);
00518 for (i = len - 1; parent_path[i] != '/'; --i) {
00519 parent_path[i] = '\0';
00520 }
00521 parent_path[i] = '\0';
00522
00523 return parent_path;
00524 }
00525
00534 void
00535 find_and_set_physical_device (HalDevice * device)
00536 {
00537 HalDevice *d;
00538 HalDevice *parent;
00539 const char *parent_udi;
00540
00541 d = device;
00542 do {
00543 parent_udi = ds_property_get_string (d, "info.parent");
00544 if (parent_udi == NULL) {
00545 HAL_ERROR (("Error finding parent for %s\n",
00546 d->udi));
00547 return;
00548 }
00549
00550 parent = ds_device_find (parent_udi);
00551 if (parent == NULL) {
00552 HAL_ERROR (("Error resolving UDI %s\n",
00553 parent_udi));
00554 return;
00555 }
00556
00557 if (!ds_property_exists (parent, "info.physical_device")) {
00558 ds_property_set_string (device,
00559 "info.physical_device",
00560 parent_udi);
00561 return;
00562 }
00563
00564 d = parent;
00565 }
00566 while (TRUE);
00567 }
00568
00569
00570
00571 struct driver_entry_s {
00572 char driver_name[SYSFS_NAME_LEN];
00574 char device_path[SYSFS_PATH_MAX];
00576 struct driver_entry_s *next;
00578 };
00579
00581 static struct driver_entry_s *drivers_table_head = NULL;
00582
00588 static void
00589 drivers_add_entry (const char *driver_name, const char *device_path)
00590 {
00591 struct driver_entry_s *entry;
00592
00593 entry = malloc (sizeof (struct driver_entry_s));
00594 if (entry == NULL)
00595 DIE (("Out of memory"));
00596 strncpy (entry->driver_name, driver_name, SYSFS_NAME_LEN);
00597 strncpy (entry->device_path, device_path, SYSFS_PATH_MAX);
00598 entry->next = drivers_table_head;
00599 drivers_table_head = entry;
00600 }
00601
00609 const char *
00610 drivers_lookup (const char *device_path)
00611 {
00612 struct driver_entry_s *i;
00613
00614 for (i = drivers_table_head; i != NULL; i = i->next) {
00615 if (strcmp (device_path, i->device_path) == 0)
00616 return i->driver_name;
00617 }
00618 return NULL;
00619 }
00620
00626 void
00627 drivers_collect (const char *bus_name)
00628 {
00629 char path[SYSFS_PATH_MAX];
00630 struct sysfs_directory *current;
00631 struct sysfs_link *current2;
00632 struct sysfs_directory *dir;
00633 struct sysfs_directory *dir2;
00634
00635
00636 snprintf (path, SYSFS_PATH_MAX, "%s/bus/%s/drivers",
00637 sysfs_mount_path, bus_name);
00638 dir = sysfs_open_directory (path);
00639 if (dir == NULL) {
00640 HAL_WARNING (("Error opening sysfs directory at %s\n",
00641 path));
00642 goto out;
00643 }
00644 if (sysfs_read_directory (dir) != 0) {
00645 HAL_WARNING (("Error reading sysfs directory at %s\n",
00646 path));
00647 goto out;
00648 }
00649 if (dir->subdirs != NULL) {
00650 dlist_for_each_data (dir->subdirs, current,
00651 struct sysfs_directory) {
00652
00653
00654 dir2 = sysfs_open_directory (current->path);
00655 if (dir2 == NULL)
00656 DIE (("Error opening sysfs directory "
00657 "at %s\n", current->path));
00658 if (sysfs_read_directory (dir2) != 0)
00659 DIE (("Error reading sysfs directory "
00660 "at %s\n", current->path));
00661
00662 if (dir2->links != NULL) {
00663 dlist_for_each_data (dir2->links, current2,
00664 struct sysfs_link) {
00665
00666
00667 drivers_add_entry (current->name,
00668 current2->
00669 target);
00670 }
00671 sysfs_close_directory (dir2);
00672 }
00673 }
00674 }
00675 out:
00676 if (dir != NULL)
00677 sysfs_close_directory (dir);
00678 }
00679