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 #include <ctype.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <getopt.h>
00035 #include <assert.h>
00036 #include <unistd.h>
00037 #include <stdarg.h>
00038
00039 #include <dbus/dbus.h>
00040 #include <dbus/dbus-glib.h>
00041
00042 #include "../osspec.h"
00043 #include "../logger.h"
00044 #include "../hald.h"
00045
00046 #include "common.h"
00047 #include "bus_device.h"
00048 #include "class_device.h"
00049
00050 #include "libsysfs/libsysfs.h"
00051
00052 extern ClassDeviceHandler input_class_handler;
00053 extern ClassDeviceHandler net_class_handler;
00054 extern ClassDeviceHandler printer_class_handler;
00055 extern ClassDeviceHandler scsi_host_class_handler;
00056 extern ClassDeviceHandler scsi_device_class_handler;
00057 extern ClassDeviceHandler scsi_generic_class_handler;
00058 extern ClassDeviceHandler block_class_handler;
00059 extern ClassDeviceHandler pcmcia_socket_class_handler;
00060
00061
00062
00063
00064
00065
00066 extern BusDeviceHandler pci_bus_handler;
00067 extern BusDeviceHandler usb_bus_handler;
00068 extern BusDeviceHandler usbif_bus_handler;
00069 extern BusDeviceHandler ide_host_bus_handler;
00070 extern BusDeviceHandler ide_bus_handler;
00071
00072
00073
00074
00075
00076
00077
00078 static ClassDeviceHandler* class_device_handlers[] = {
00079 &input_class_handler,
00080 &net_class_handler,
00081 &printer_class_handler,
00082 &scsi_host_class_handler,
00083 &scsi_device_class_handler,
00084 &scsi_generic_class_handler,
00085 &block_class_handler,
00086 &pcmcia_socket_class_handler,
00087
00088
00089 NULL
00090 };
00091
00092 static BusDeviceHandler* bus_device_handlers[] = {
00093 &pci_bus_handler,
00094 &usb_bus_handler,
00095 &usbif_bus_handler,
00096 &ide_host_bus_handler,
00097 &ide_bus_handler,
00098 NULL
00099 };
00100
00109 char sysfs_mount_path[SYSFS_PATH_MAX];
00110
00125 static void
00126 visit_class_device (const char *path, dbus_bool_t visit_children)
00127 {
00128 int i;
00129 struct sysfs_class_device *class_device;
00130 struct sysfs_directory *subdir;
00131
00132 class_device = sysfs_open_class_device (path);
00133 if (class_device == NULL) {
00134 HAL_WARNING (("Coulnd't get sysfs class device object at "
00135 "path %s", path));
00136 return;
00137 }
00138
00139 HAL_INFO (("*** classname=%s path=%s",
00140 class_device->classname,
00141 class_device->path));
00142
00143 for (i=0; class_device_handlers[i] != NULL; i++) {
00144 ClassDeviceHandler *ch = class_device_handlers[i];
00145 if (ch->accept (ch, path, class_device, is_probing))
00146 ch->visit (ch, path, class_device, is_probing);
00147 }
00148
00149
00150 if (visit_children && class_device->directory != NULL &&
00151 class_device->directory->subdirs != NULL) {
00152 dlist_for_each_data (class_device->directory->subdirs,
00153 subdir, struct sysfs_directory) {
00154 char newpath[SYSFS_PATH_MAX];
00155 snprintf (newpath, SYSFS_PATH_MAX, "%s/%s", path,
00156 subdir->name);
00157 visit_class_device (newpath, TRUE);
00158 }
00159 }
00160
00161 sysfs_close_class_device (class_device);
00162 }
00163
00174 static void
00175 visit_class (const char *class_name, dbus_bool_t visit_children)
00176 {
00177 struct sysfs_class *cls = NULL;
00178 struct sysfs_class_device *cur = NULL;
00179
00180 cls = sysfs_open_class (class_name);
00181 if (cls == NULL) {
00182 HAL_ERROR (("Error opening class %s\n", class_name));
00183 return;
00184 }
00185
00186 if (cls->devices != NULL) {
00187 dlist_for_each_data (cls->devices, cur,
00188 struct sysfs_class_device) {
00189 visit_class_device (cur->path, visit_children);
00190 }
00191 }
00192
00193 sysfs_close_class (cls);
00194 }
00195
00209 static void
00210 visit_device (const char *path, dbus_bool_t visit_children)
00211 {
00212 int i;
00213 struct sysfs_device *device;
00214 struct sysfs_directory *subdir;
00215
00216 device = sysfs_open_device (path);
00217 if (device == NULL) {
00218 HAL_WARNING (("Coulnd't get sysfs device object at path %s",
00219 path));
00220 return;
00221 }
00222
00223 HAL_INFO (("$$$ busname=%s path=%s", device->bus, device->path));
00224
00225
00226
00227 for (i=0; bus_device_handlers[i] != NULL; i++) {
00228 BusDeviceHandler *bh = bus_device_handlers[i];
00229 if (bh->accept (bh, path, device, is_probing))
00230 bh->visit (bh, path, device, is_probing);
00231 }
00232
00233
00234 if (visit_children && device->directory->subdirs != NULL) {
00235 dlist_for_each_data (device->directory->subdirs, subdir,
00236 struct sysfs_directory) {
00237 char newpath[SYSFS_PATH_MAX];
00238 snprintf (newpath, SYSFS_PATH_MAX, "%s/%s", path,
00239 subdir->name);
00240 visit_device (newpath, TRUE);
00241 }
00242 }
00243
00244 sysfs_close_device (device);
00245 }
00246
00247
00253 static gboolean
00254 osspec_timer_handler (gpointer data)
00255 {
00256 int i;
00257
00258 for (i=0; bus_device_handlers[i] != NULL; i++) {
00259 BusDeviceHandler *bh = bus_device_handlers[i];
00260 bh->tick (bh);
00261 }
00262
00263 for (i=0; class_device_handlers[i] != NULL; i++) {
00264 ClassDeviceHandler *ch = class_device_handlers[i];
00265 ch->tick (ch);
00266 }
00267
00268 return TRUE;
00269 }
00270
00271
00272 void
00273 osspec_init (DBusConnection * dbus_connection)
00274 {
00275 int i;
00276 int rc;
00277 DBusError error;
00278
00279
00280 rc = sysfs_get_mnt_path (sysfs_mount_path, SYSFS_PATH_MAX);
00281 if (rc != 0) {
00282 DIE (("Couldn't get mount path for sysfs"));
00283 }
00284 HAL_INFO (("Mountpoint for sysfs is %s", sysfs_mount_path));
00285
00286 for (i=0; bus_device_handlers[i] != NULL; i++) {
00287 BusDeviceHandler *bh = bus_device_handlers[i];
00288 bh->init (bh);
00289 }
00290
00291 for (i=0; class_device_handlers[i] != NULL; i++) {
00292 ClassDeviceHandler *ch = class_device_handlers[i];
00293 ch->init (ch);
00294 }
00295
00296
00297 dbus_error_init (&error);
00298 dbus_bus_add_match (dbus_connection,
00299 "type='signal',"
00300 "interface='org.kernel.udev.NodeMonitor',"
00301
00302 "path='/org/kernel/udev/NodeMonitor'", &error);
00303 if (dbus_error_is_set (&error)) {
00304 HAL_WARNING (("Cannot subscribe to udev signals, error=%s",
00305 error.message));
00306 }
00307
00308
00309 g_timeout_add (2000, osspec_timer_handler, NULL);
00310 }
00311
00313 dbus_bool_t is_probing;
00314
00315
00316 void
00317 osspec_probe ()
00318 {
00319 int i;
00320 char path[SYSFS_PATH_MAX];
00321 struct sysfs_directory *current;
00322 struct sysfs_directory *dir;
00323
00324 is_probing = TRUE;
00325
00326
00327 strncpy (path, sysfs_mount_path, SYSFS_PATH_MAX);
00328 strncat (path, SYSFS_DEVICES_DIR, SYSFS_PATH_MAX);
00329
00330 dir = sysfs_open_directory (path);
00331 if (dir == NULL) {
00332 DIE (("Error opening sysfs directory at %s\n", path));
00333 }
00334 if (sysfs_read_directory (dir) != 0) {
00335 DIE (("Error reading sysfs directory at %s\n", path));
00336 }
00337 if (dir->subdirs != NULL) {
00338 dlist_for_each_data (dir->subdirs, current,
00339 struct sysfs_directory) {
00340 visit_device (current->path, TRUE);
00341 }
00342 }
00343 sysfs_close_directory (dir);
00344
00345 for (i=0; class_device_handlers[i] != NULL; i++) {
00346 ClassDeviceHandler *ch = class_device_handlers[i];
00347 visit_class (ch->sysfs_class_name, TRUE);
00349 }
00350
00351 is_probing = FALSE;
00352
00353
00354
00355
00356 for (i=0; bus_device_handlers[i] != NULL; i++) {
00357 BusDeviceHandler *bh = bus_device_handlers[i];
00358 bh->detection_done (bh);
00359 }
00360
00361 for (i=0; class_device_handlers[i] != NULL; i++) {
00362 ClassDeviceHandler *ch = class_device_handlers[i];
00363 ch->detection_done (ch);
00364 }
00365 }
00366
00367 static void
00368 remove_device (const char *path, const char *subsystem)
00369
00370 { HalDevice *d;
00371
00372 d = hal_device_store_match_key_value_string (hald_get_gdl (),
00373 "linux.sysfs_path",
00374 path);
00375
00376 if (d == NULL) {
00377 HAL_WARNING (("Couldn't remove device @ %s on hotplug remove",
00378 path));
00379 } else {
00380
00381
00382
00383 hal_device_store_remove (hald_get_gdl (), d);
00384 }
00385 }
00386
00387 static void
00388 remove_class_device (const char *path, const char *subsystem)
00389 {
00390 int i;
00391 const char *bus_name;
00392 HalDevice *d;
00393
00394 d = hal_device_store_match_key_value_string (hald_get_gdl (),
00395 "linux.sysfs_path",
00396 path);
00397
00398 if (d == NULL) {
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411 HAL_WARNING (("Removal of class device @ %s on "
00412 "hotplug remove is not yet implemented", path));
00413
00414 } else {
00415
00416
00417
00418 bus_name = hal_device_property_get_string (d, "info.bus");
00419
00420 for (i=0; class_device_handlers[i] != NULL; i++) {
00421 ClassDeviceHandler *ch = class_device_handlers[i];
00422
00423
00424 if (strcmp (ch->hal_class_name, bus_name) == 0) {
00425 ch->removed (ch, path, d);
00426 }
00427 }
00428
00429 hal_device_store_remove (hald_get_gdl (), d);
00430 }
00431
00432
00433
00434
00435 remove_device (path, subsystem);
00436 }
00437
00446 static DBusHandlerResult
00447 handle_hotplug (DBusConnection * connection, DBusMessage * message)
00448 {
00449 DBusMessageIter iter;
00450 DBusMessageIter dict_iter;
00451 dbus_bool_t is_add;
00452 char *subsystem;
00453 char sysfs_devpath[SYSFS_PATH_MAX];
00454 char sysfs_devpath_wo_mp[SYSFS_PATH_MAX];
00455
00456 sysfs_devpath[0] = '\0';
00457
00458 dbus_message_iter_init (message, &iter);
00459
00460 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING) {
00462 dbus_message_unref (message);
00463 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00464 }
00465 subsystem = dbus_message_iter_get_string (&iter);
00466
00467 dbus_message_iter_next (&iter);
00468 dbus_message_iter_init_dict_iterator (&iter, &dict_iter);
00469
00470 is_add = FALSE;
00471
00472 do {
00473 char *key;
00474 char *value;
00475
00476 key = dbus_message_iter_get_dict_key (&dict_iter);
00477 value = dbus_message_iter_get_string (&dict_iter);
00478
00479
00480
00481 if (strcmp (key, "ACTION") == 0) {
00482 if (strcmp (value, "add") == 0) {
00483 is_add = TRUE;
00484 }
00485 } else if (strcmp (key, "DEVPATH") == 0) {
00486 strncpy (sysfs_devpath, sysfs_mount_path,
00487 SYSFS_PATH_MAX);
00488 strncat (sysfs_devpath, value, SYSFS_PATH_MAX);
00489 strncpy (sysfs_devpath_wo_mp, value, SYSFS_PATH_MAX);
00490 }
00491 } while (dbus_message_iter_has_next (&dict_iter) &&
00492 dbus_message_iter_next (&dict_iter));
00493
00494
00495 if (sysfs_devpath[0] == '\0')
00496 goto out;
00497
00498 HAL_INFO (("HotplugEvent %s, subsystem=%s devpath=%s foo=%s",
00499 (is_add ? "add" : "remove"), subsystem,
00500 sysfs_devpath[0] != '\0' ? sysfs_devpath : "(none)",
00501 sysfs_devpath_wo_mp));
00502
00503
00504 if (strncmp (sysfs_devpath_wo_mp, "/block", 6)==0 ||
00505 strncmp (sysfs_devpath_wo_mp, "/class", 6)==0 ) {
00506
00507 if (is_add)
00508 visit_class_device (sysfs_devpath, FALSE);
00509 else
00510 remove_class_device (sysfs_devpath, subsystem);
00511 } else {
00512
00513 if (is_add)
00514 visit_device (sysfs_devpath, FALSE);
00515 else
00516 remove_device (sysfs_devpath, subsystem);
00517 }
00518
00519
00520 out:
00521 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00522 }
00523
00524
00525 static void handle_udev_node_created_found_device (HalDevice * d,
00526 void *data1,
00527 void *data2);
00528
00529 static void
00530 udev_node_created_cb (HalDeviceStore *store, HalDevice *device,
00531 gpointer user_data)
00532 {
00533 const char *filename = user_data;
00534
00535 handle_udev_node_created_found_device (device, (void*) filename, NULL);
00536 }
00537
00538
00547 static DBusHandlerResult
00548 handle_device_event (DBusConnection * connection,
00549 DBusMessage * message)
00550 {
00551 dbus_bool_t is_add;
00552 char *filename;
00553 char *sysfs_path;
00554 char sysfs_dev_path[SYSFS_PATH_MAX];
00555
00556 if (dbus_message_get_args (message, NULL,
00557 DBUS_TYPE_BOOLEAN, &is_add,
00558 DBUS_TYPE_STRING, &filename,
00559 DBUS_TYPE_STRING, &sysfs_path,
00560 DBUS_TYPE_INVALID)) {
00561 strncpy (sysfs_dev_path, sysfs_mount_path, SYSFS_PATH_MAX);
00562 strncat (sysfs_dev_path, sysfs_path, SYSFS_PATH_MAX);
00563
00564 if (is_add ) {
00565
00566 HAL_INFO (("DeviceEvent add devpath=%s devfile=%s",
00567 sysfs_dev_path, filename));
00568
00569 hal_device_store_match_key_value_string_async (
00570 hald_get_tdl (),
00571 ".udev.sysfs_path",
00572 sysfs_dev_path,
00573 udev_node_created_cb, filename,
00574 HAL_LINUX_HOTPLUG_TIMEOUT);
00575
00576
00577
00578
00579 } else {
00580 dbus_free (filename);
00581 }
00582
00583 dbus_free (sysfs_path);
00584 }
00585
00586 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00587 }
00588
00595 static void
00596 handle_udev_node_created_found_device (HalDevice * d,
00597 void *data1, void *data2)
00598 {
00599 int i;
00600 const char *sysfs_class_name;
00601 char *dev_file = (char *) data1;
00602
00603 if (d != NULL) {
00604 HAL_INFO (("dev_file=%s is for udi=%s", dev_file, d->udi));
00605
00606 sysfs_class_name =
00607 hal_device_property_get_string (d, ".udev.class_name");
00608
00609
00610
00611 for (i=0; class_device_handlers[i] != NULL; i++) {
00612 ClassDeviceHandler *ch = class_device_handlers[i];
00613 if (strcmp (ch->sysfs_class_name, sysfs_class_name) == 0) {
00614 ch->udev_event (ch, d, dev_file);
00615 }
00616 }
00617 } else {
00618 HAL_WARNING (("No HAL device corresponding to device file %s",
00619 dev_file));
00620 }
00621
00622 dbus_free (dev_file);
00623 }
00624
00633 DBusHandlerResult
00634 osspec_filter_function (DBusConnection * connection,
00635 DBusMessage * message, void *user_data)
00636 {
00637
00638 if (dbus_message_is_method_call (message,
00639 "org.freedesktop.Hal.Linux.Hotplug",
00640 "HotplugEvent") &&
00641 strcmp (dbus_message_get_path (message),
00642 "/org/freedesktop/Hal/Linux/Hotplug") == 0) {
00643 return handle_hotplug (connection, message);
00644 } else if (dbus_message_is_method_call (message,
00645 "org.freedesktop.Hal.Linux.Hotplug",
00646 "DeviceEvent") &&
00647 strcmp (dbus_message_get_path (message),
00648 "/org/freedesktop/Hal/Linux/Hotplug") == 0) {
00649 return handle_device_event (connection, message);
00650 }
00651
00652 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00653 }
00654