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 #include <errno.h>
00042 #include <signal.h>
00043 #include <fcntl.h>
00044 #include <sys/types.h>
00045 #include <sys/stat.h>
00046 #include <sys/ioctl.h>
00047 #include <linux/kdev_t.h>
00048 #include <linux/cdrom.h>
00049 #include <linux/fs.h>
00050 #include <glib.h>
00051
00052 #include "../hald.h"
00053 #include "../hald_dbus.h"
00054 #include "../logger.h"
00055 #include "../device_store.h"
00056 #include "class_device.h"
00057 #include "common.h"
00058
00059 #include "linux_dvd_rw_utils.h"
00060
00068 typedef struct {
00069 HalDevice *device;
00070 ClassDeviceHandler *handler;
00071 } AsyncInfo;
00072
00073 static void
00074 block_class_visit (ClassDeviceHandler *self,
00075 const char *path,
00076 struct sysfs_class_device *class_device,
00077 dbus_bool_t is_probing)
00078 {
00079 HalDevice *d;
00080 char *parent_sysfs_path;
00081 AsyncInfo *ai;
00082
00083
00084 if (strcmp (class_device->classname, "block") != 0)
00085 return;
00086
00087 d = hal_device_new ();
00088 hal_device_store_add (hald_get_tdl (), d);
00089 hal_device_property_set_string (d, "info.bus", self->hal_class_name);
00090 hal_device_property_set_string (d, "linux.sysfs_path", path);
00091 hal_device_property_set_string (d, "linux.sysfs_path_device", path);
00092
00093 if (class_device->sysdevice == NULL) {
00094 parent_sysfs_path = get_parent_sysfs_path (path);
00095 hal_device_property_set_bool (d, "block.is_volume", TRUE);
00096 } else {
00097 parent_sysfs_path = class_device->sysdevice->path;
00098 hal_device_property_set_bool (d, "block.is_volume", FALSE);
00099 }
00100
00101
00102 hal_device_property_set_string (d, ".udev.sysfs_path", path);
00103 hal_device_property_set_string (d, ".udev.class_name", "block");
00104
00105
00106 hal_device_property_set_string (d, ".target_dev", "block.device");
00107
00108
00109 if (self->require_device_file && is_probing) {
00110 char dev_file[SYSFS_PATH_MAX];
00111
00112 if (!class_device_get_device_file (path, dev_file,
00113 SYSFS_PATH_MAX)) {
00114 HAL_WARNING (("Couldn't get device file for class "
00115 "device with sysfs path", path));
00116 return;
00117 }
00118
00119
00120
00121 self->udev_event (self, d, dev_file);
00122 }
00123
00124
00125
00126 ai = g_new0 (AsyncInfo, 1);
00127 ai->device = d;
00128 ai->handler = self;
00129
00130 hal_device_store_match_key_value_string_async (
00131 hald_get_gdl (),
00132 "linux.sysfs_path_device",
00133 parent_sysfs_path,
00134 class_device_got_parent_device, ai,
00135 is_probing ? 0 : HAL_LINUX_HOTPLUG_TIMEOUT);
00136 }
00137
00138
00139 static char *
00140 strip_space (char *str)
00141 {
00142 int i, len;
00143
00144 len = strlen (str);
00145 for (i = len - 1; i > 0 && isspace (str[i]); --i)
00146 str[i] = '\0';
00147
00148 return str;
00149 }
00150
00151
00152 static void
00153 cdrom_check(HalDevice *d, const char *device_file)
00154 {
00155 int fd, capabilities;
00156 int read_speed, write_speed;
00157
00158
00159 fd = open (device_file, O_RDONLY | O_NONBLOCK);
00160 if (fd < 0)
00161 return;
00162
00163 ioctl (fd, CDROM_SET_OPTIONS, CDO_USE_FFLAGS);
00164
00165 capabilities = ioctl (fd, CDROM_GET_CAPABILITY, 0);
00166 if (capabilities < 0) {
00167 close(fd);
00168 return;
00169 }
00170
00171 if (capabilities & CDC_CD_R) {
00172 hal_device_add_capability (d, "storage.cdr");
00173 hal_device_property_set_bool (d, "storage.cdr", TRUE);
00174 }
00175
00176 if (capabilities & CDC_CD_RW) {
00177 hal_device_add_capability (d, "storage.cdrw");
00178 hal_device_property_set_bool (d, "storage.cdrw", TRUE);
00179 }
00180 if (capabilities & CDC_DVD) {
00181 int profile;
00182
00183 hal_device_add_capability (d, "storage.dvd");
00184 hal_device_property_set_bool (d, "storage.dvd", TRUE);
00185
00186 profile = get_dvd_r_rw_profile (fd);
00187 HAL_INFO (("profile %d\n", profile));
00188 if (profile == 2) {
00189 hal_device_add_capability (d, "storage.dvdplusr");
00190 hal_device_property_set_bool (d, "storage.dvdplusr", TRUE);
00191 hal_device_add_capability (d, "storage.dvdplusrw");
00192 hal_device_property_set_bool (d, "storage.dvdplusrw", TRUE);
00193 } else if (profile == 0) {
00194 hal_device_add_capability(d, "storage.dvdplusr");
00195 hal_device_property_set_bool(d, "storage.dvdplusr",
00196 TRUE);
00197 } else if (profile == 1) {
00198 hal_device_add_capability (d, "storage.dvdplusrw");
00199 hal_device_property_set_bool (d, "storage.dvdplusrw", TRUE);
00200 }
00201 }
00202 if (capabilities & CDC_DVD_R) {
00203 hal_device_add_capability (d, "storage.dvdr");
00204 hal_device_property_set_bool (d, "storage.dvdr", TRUE);
00205 }
00206 if (capabilities & CDC_DVD_RAM) {
00207 hal_device_add_capability (d, "storage.dvdram");
00208 hal_device_property_set_bool (d, "storage.dvdram", TRUE);
00209 }
00210
00211
00212 if (ioctl (fd, CDROM_MEDIA_CHANGED) >= 0) {
00213 hal_device_property_set_bool (d, "storage.cdrom.support_media_changed", TRUE);
00214 }
00215
00216 if (get_read_write_speed(fd, &read_speed, &write_speed) >= 0) {
00217 hal_device_property_set_int (d, "storage.cdrom.read_speed", read_speed);
00218 if (write_speed > 0)
00219 hal_device_property_set_int(d, "storage.cdrom.write_speed", write_speed);
00220 }
00221
00222 close (fd);
00223 }
00224
00230 static void
00231 force_unmount (HalDevice * d)
00232 {
00233 const char *device_file;
00234 const char *device_mount_point;
00235 const char *umount_argv[4] = { "/bin/umount", "-l", NULL, NULL };
00236 char *umount_stdout;
00237 char *umount_stderr;
00238 int umount_exitcode;
00239
00240 device_file = hal_device_property_get_string (d, "block.device");
00241 device_mount_point =
00242 hal_device_property_get_string (d, "block.mount_point");
00243
00244 umount_argv[2] = device_file;
00245
00246 if (hal_device_has_property (d, "block.is_volume") &&
00247 hal_device_property_get_bool (d, "block.is_volume") &&
00248 device_mount_point != NULL &&
00249 strlen (device_mount_point) > 0) {
00250 HAL_INFO (("attempting /bin/umount -l %s", device_file));
00251
00252
00253 if (g_spawn_sync ("/",
00254 (char **) umount_argv,
00255 NULL,
00256 0,
00257 NULL,
00258 NULL,
00259 &umount_stdout,
00260 &umount_stderr,
00261 &umount_exitcode, NULL) != TRUE) {
00262 HAL_ERROR (("Couldn't invoke /bin/umount"));
00263 }
00264
00265 if (umount_exitcode != 0) {
00266 HAL_INFO (("/bin/umount returned %d",
00267 umount_exitcode));
00268 } else {
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 HAL_INFO (("Goint to emit BlockForcedUnmountPartition('%s', '%s', TRUE)", device_file, device_mount_point));
00279 device_send_signal_condition (d,
00280 "BlockForcedUnmountPartition",
00281 DBUS_TYPE_STRING,
00282 device_file,
00283 DBUS_TYPE_STRING,
00284 device_mount_point,
00285 DBUS_TYPE_BOOLEAN,
00286 TRUE,
00287 DBUS_TYPE_INVALID);
00288
00289
00290
00291
00292
00293
00294 device_property_atomic_update_begin ();
00295 hal_device_property_set_string (d, "block.mount_point",
00296 "");
00297 hal_device_property_set_string (d, "block.fstype", "");
00298 hal_device_property_set_bool (d, "block.is_mounted",
00299 FALSE);
00300 device_property_atomic_update_end ();
00301 }
00302 }
00303 }
00304
00310 static void
00311 force_unmount_of_all_childs (HalDevice * d)
00312 {
00313 int fd;
00314 const char *device_file;
00315 GSList *children;
00316
00317 device_file = hal_device_property_get_string (d, "block.device");
00318
00319 children = hal_device_store_match_multiple_key_value_string (
00320 hald_get_gdl (),
00321 "info.parent",
00322 hal_device_get_udi (d));
00323
00324 if (children != NULL) {
00325 GSList *iter;
00326
00327 for (iter = children; iter != NULL; iter = iter->next) {
00328 HalDevice *child = HAL_DEVICE (iter->data);
00329
00330 force_unmount (child);
00331
00332 }
00333
00334 g_slist_free (children);
00335
00336 HAL_INFO (("Rereading partition table for %s",
00337 device_file));
00338 fd = open (device_file, O_RDONLY | O_NONBLOCK);
00339 if (fd != -1) {
00340 ioctl (fd, BLKRRPART);
00341 }
00342 close (fd);
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353 HAL_INFO (("Goint to emit BlockForcedUnmount('%s')",
00354 device_file));
00355 device_send_signal_condition (d, "BlockForcedUnmount",
00356 DBUS_TYPE_STRING, device_file,
00357 DBUS_TYPE_INVALID);
00358
00359 }
00360 }
00361
00362
00371 static dbus_bool_t
00372 detect_media (HalDevice * d)
00373 {
00374 int fd;
00375 dbus_bool_t is_cdrom;
00376 const char *device_file;
00377 HalDevice *child;
00378
00379
00380 if (!hal_device_store_find (hald_get_gdl (),
00381 hal_device_get_udi (d)))
00382 return FALSE;
00383
00384
00385 if (!hal_device_has_property (d, "block.is_volume") ||
00386 !hal_device_has_property (d, "block.device") ||
00387 hal_device_property_get_bool (d, "block.is_volume"))
00388 return FALSE;
00389
00390 device_file = hal_device_property_get_string (d, "block.device");
00391 if (device_file == NULL)
00392 return FALSE;
00393
00394
00395 is_cdrom = hal_device_has_property (d, "storage.media") &&
00396 strcmp (hal_device_property_get_string (d, "storage.media"),
00397 "cdrom") == 0
00398 && hal_device_property_get_bool (d,
00399 "storage.cdrom.support_media_changed");
00400
00401 if (!is_cdrom) {
00402 fd = open (device_file, O_RDONLY);
00403
00404 if (fd == -1) {
00405
00406 HAL_WARNING (("open(\"%s\", O_RDONLY) failed, "
00407 "errno=%d", device_file, errno));
00408
00409 if (errno == ENOMEDIUM) {
00410 force_unmount_of_all_childs (d);
00411 }
00412
00413 }
00414
00415 }
00416 else {
00417 int drive;
00418 dbus_bool_t got_disc = FALSE;
00419
00420 fd = open (device_file, O_RDONLY | O_NONBLOCK | O_EXCL);
00421
00422 if (fd == -1) {
00423
00424 HAL_WARNING (("open(\"%s\", O_RDONLY|O_NONBLOCK|O_EXCL) failed, " "errno=%d", device_file, errno));
00425 return FALSE;
00426 }
00427
00428 drive = ioctl (fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
00429 switch (drive) {
00430
00431 case CDS_NO_INFO:
00432 case CDS_NO_DISC:
00433 case CDS_TRAY_OPEN:
00434 case CDS_DRIVE_NOT_READY:
00435 break;
00436
00437 case CDS_DISC_OK:
00438 got_disc = TRUE;
00439 break;
00440
00441 default:
00442 break;
00443 }
00444
00445 if (!got_disc) {
00446
00447 child = hal_device_store_match_key_value_string (
00448 hald_get_gdl (), "info.parent",
00449 hal_device_get_udi (d));
00450
00451 if (child != NULL) {
00452 HAL_INFO (("Removing volume for optical device %s", device_file));
00453 hal_device_store_remove (hald_get_gdl (), child);
00454 g_object_unref (child);
00455
00456 close (fd);
00457
00458
00459 return TRUE;
00460 }
00461
00462 close (fd);
00463 return FALSE;
00464 }
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 child = hal_device_store_match_key_value_string (
00475 hald_get_gdl (), "info.parent",
00476 hal_device_get_udi (d));
00477
00478 if (child == NULL) {
00479 int type;
00480 char udi[256];
00481
00482
00483 HAL_INFO (("Adding volume for optical device %s",
00484 device_file));
00485
00486 child = hal_device_new ();
00487
00488
00489 hal_device_merge (child, d);
00490
00491
00492 hal_device_property_set_string (child, "info.parent",
00493 d->udi);
00494 hal_device_property_set_bool (child, "block.is_volume",
00495 TRUE);
00496 hal_device_property_set_string (child, "info.capabilities",
00497 "block volume");
00498 hal_device_property_set_string (child, "info.category",
00499 "volume");
00500 hal_device_property_set_string (child, "info.product",
00501 "Disc");
00502
00503
00504 strncpy (udi,
00505 hal_device_property_get_string (d, "info.udi"),
00506 256);
00507 strncat (udi, "-disc", 256);
00508 hal_device_property_set_string (child, "info.udi", udi);
00509 hal_device_set_udi (child, udi);
00510
00511
00512 type = ioctl (fd, CDROM_DISC_STATUS, CDSL_CURRENT);
00513 close(fd);
00514 switch (type) {
00515 case CDS_AUDIO:
00516 hal_device_property_set_string (child,
00517 "storage.cdrom.media_type",
00518 "audio");
00519 break;
00520 case CDS_MIXED:
00521 hal_device_property_set_string (child,
00522 "storage.cdrom.media_type",
00523 "mixed");
00524 break;
00525 case CDS_DATA_1:
00526 case CDS_DATA_2:
00527 case CDS_XA_2_1:
00528 case CDS_XA_2_2:
00529 hal_device_property_set_string (child,
00530 "storage.cdrom.media_type",
00531 "data");
00532 break;
00533 case CDS_NO_INFO:
00534 hal_device_property_set_string (child,
00535 "storage.cdrom.media_type",
00536 "blank");
00537 break;
00538
00539 default:
00540 hal_device_property_set_string (child,
00541 "storage.cdrom.media_type",
00542 "unknown");
00543 break;
00544 }
00545
00546
00547
00548 hal_device_store_add (hald_get_gdl (), child);
00549 g_object_unref (child);
00550
00551
00552 return TRUE;
00553 }
00554
00555 }
00556
00557 close (fd);
00558
00559 return FALSE;
00560 }
00561
00562 static void
00563 block_class_got_udi (ClassDeviceHandler *self,
00564 HalDevice *d,
00565 const char *udi)
00566 {
00567 const char *stordev_udi;
00568 char temp_prefix[] = "/org/freedesktop/Hal/devices/temp";
00569
00570
00571
00572 stordev_udi = hal_device_property_get_string (d,
00573 "block.storage_device");
00574
00575 if (strncmp (stordev_udi, temp_prefix, strlen(temp_prefix)) == 0) {
00576 hal_device_property_set_string (d,
00577 "block.storage_device",
00578 udi);
00579 }
00580 }
00581
00582 static dbus_bool_t
00583 detect_fs_fat (HalDevice *d)
00584 {
00585 int i, len;
00586 int fd;
00587 const char *device_file;
00588 unsigned char data[512];
00589 char label[12];
00590 dbus_bool_t matched = FALSE;
00591
00592
00593
00594
00595
00596 device_file = hal_device_property_get_string (d, "block.device");
00597
00598 fd = open (device_file, O_RDONLY);
00599 if (fd < 0)
00600 return FALSE;
00601
00602 if (512 != read (fd, data, 512))
00603 goto out;
00604
00605
00606
00607 if (data[510] != 0x55 &&
00608 data[511] != 0xaa)
00609 goto out;
00610
00611 memset (label, 0, 12);
00612
00613 if (data[82] == 'F' &&
00614 data[83] == 'A' &&
00615 data[84] == 'T' &&
00616 data[85] == '3' &&
00617 data[86] == '2' ) {
00618
00619 memcpy (label, data+71, 11);
00620 hal_device_property_set_string (d, "block.fstype", "vfat");
00621 matched = TRUE;
00622 } else if (data[54] == 'F' &&
00623 data[55] == 'A' &&
00624 data[56] == 'T' ) {
00625
00626 memcpy (label, data+43, 11);
00627 hal_device_property_set_string (d, "block.fstype", "vfat");
00628 matched = TRUE;
00629 }
00630
00631 len = strlen (label);
00632 for (i=len-1; i>=0 && isspace (label[i]); --i)
00633 label[i] = '\0';
00634 hal_device_property_set_string (d, "block.volume_label", label);
00635
00636 out:
00637 close (fd);
00638 return matched;
00639 }
00640
00641 static void
00642 detect_fs (HalDevice *d)
00643 {
00644 if (detect_fs_fat(d))
00645 return;
00646 }
00647
00648 static void
00649 block_class_pre_process (ClassDeviceHandler *self,
00650 HalDevice *d,
00651 const char *sysfs_path,
00652 struct sysfs_class_device *class_device)
00653 {
00654 int major, minor;
00655 HalDevice *parent;
00656 HalDevice *stordev = NULL;
00657 HalDevice *physdev = NULL;
00658 HalDevice *scsidev = NULL;
00659 const char *stordev_udi;
00660 const char *device_file;
00661 dbus_bool_t has_removable_media = FALSE;
00662 dbus_bool_t is_hotpluggable = FALSE;
00663
00664 parent = hal_device_store_find (hald_get_gdl (),
00665 hal_device_property_get_string (
00666 d, "info.parent"));
00667 assert (parent != NULL);
00668
00669
00670 hal_device_property_set_string (d, "info.category", "block");
00671 hal_device_add_capability (d, "block");
00672
00673 class_device_get_major_minor (sysfs_path, &major, &minor);
00674 hal_device_property_set_int (d, "block.major", major);
00675 hal_device_property_set_int (d, "block.minor", minor);
00676
00677 device_file = hal_device_property_get_string (d, "block.device");
00678
00679
00680 if (hal_device_property_get_bool (d, "block.is_volume")) {
00681
00682 stordev_udi = hal_device_property_get_string (
00683 parent, "block.storage_device");
00684 stordev = hal_device_store_find (hald_get_gdl (), stordev_udi);
00685 } else {
00686 const char *udi_it;
00687 const char *physdev_udi = NULL;
00688
00689
00690 stordev_udi = d->udi;
00691 stordev = d;
00692
00693
00694 hal_device_property_set_string (
00695 stordev, "storage.bus", "unknown");
00696
00697
00698
00699
00700
00701 udi_it = parent->udi;
00702
00703 while (udi_it != NULL) {
00704 HalDevice *d_it;
00705 const char *bus;
00706
00707
00708 d_it = hal_device_store_find (hald_get_gdl (), udi_it);
00709 assert (d_it != NULL);
00710
00711
00712 bus = hal_device_property_get_string (d_it,"info.bus");
00713
00714 if (strcmp (bus, "scsi_device") == 0) {
00715 scsidev = d_it;
00716 }
00717
00718 if (strcmp (bus, "usb") == 0) {
00719 physdev = d_it;
00720 physdev_udi = udi_it;
00721 is_hotpluggable = TRUE;
00722 hal_device_property_set_string (
00723 stordev, "storage.bus", "usb");
00724
00725 break;
00726 } else if (strcmp (bus, "ieee1394") == 0) {
00727 physdev = d_it;
00728 physdev_udi = udi_it;
00729 is_hotpluggable = TRUE;
00730 hal_device_property_set_string (
00731 stordev, "storage.bus", "ieee1394");
00732 break;
00733 } else if (strcmp (bus, "ide") == 0) {
00734 physdev = d_it;
00735 physdev_udi = udi_it;
00736 hal_device_property_set_string (
00737 stordev, "storage.bus", "ide");
00738 break;
00739 }
00740
00741
00742 udi_it = hal_device_property_get_string (
00743 d_it, "info.parent");
00744 }
00745
00746 if (physdev_udi != NULL) {
00747 hal_device_property_set_string (
00748 stordev,
00749 "storage.physical_device",
00750 physdev_udi);
00751 }
00752 }
00753
00754 hal_device_property_set_string (d, "block.storage_device",
00755 stordev_udi);
00756
00757 if (hal_device_property_get_bool (d, "block.is_volume")) {
00758
00759 find_and_set_physical_device (d);
00760 hal_device_property_set_bool (d, "info.virtual", TRUE);
00761 hal_device_add_capability (d, "volume");
00762 hal_device_property_set_string (d, "info.category", "volume");
00763
00764
00765
00767 hal_device_property_set_string (d, "info.product", "Volume");
00768
00769
00770 detect_fs (d);
00771
00772
00773
00774
00775 return;
00776 }
00777
00778
00779 hal_device_property_set_bool (stordev, "storage.cdr", FALSE);
00780 hal_device_property_set_bool (stordev, "storage.cdrw", FALSE);
00781 hal_device_property_set_bool (stordev, "storage.dvd", FALSE);
00782 hal_device_property_set_bool (stordev, "storage.dvdr", FALSE);
00783 hal_device_property_set_bool (stordev, "storage.dvdram", FALSE);
00784
00785
00786
00787
00788 hal_device_property_set_string (d, "info.category", "block");
00789
00790 HAL_INFO (("Bus type is %s!",
00791 hal_device_property_get_string (parent, "info.bus")));
00792
00793 if (strcmp (hal_device_property_get_string (parent, "info.bus"),
00794 "ide") == 0) {
00795 const char *ide_name;
00796 char *model;
00797 char *media;
00798
00799 ide_name = get_last_element (hal_device_property_get_string
00800 (d, "linux.sysfs_path"));
00801
00802 model = read_single_line ("/proc/ide/%s/model", ide_name);
00803 if (model != NULL) {
00804 hal_device_property_set_string (stordev,
00805 "storage.model",
00806 model);
00807 hal_device_property_set_string (d,
00808 "info.product",
00809 model);
00810 }
00811
00812
00813
00814
00815
00816
00817
00818
00823 media = read_single_line ("/proc/ide/%s/media",
00824 ide_name);
00825 if (media != NULL) {
00826 hal_device_property_set_string (stordev,
00827 "storage.media",
00828 media);
00829
00830
00831 if (strcmp (media, "disk") == 0) {
00832
00833 } else if (strcmp (media, "cdrom") == 0) {
00834 has_removable_media = TRUE;
00835 } else if (strcmp (media, "floppy") == 0) {
00836 has_removable_media = TRUE;
00837 } else if (strcmp (media, "tape") == 0) {
00838 has_removable_media = TRUE;
00839 }
00840
00841 }
00842
00843 } else if (strcmp (hal_device_property_get_string (parent,
00844 "info.bus"),
00845 "scsi_device") == 0) {
00846 const char *sysfs_path;
00847 char attr_path[SYSFS_PATH_MAX];
00848 struct sysfs_attribute *attr;
00849
00850 sysfs_path = hal_device_property_get_string (
00851 d, "linux.sysfs_path");
00852
00853 snprintf (attr_path, SYSFS_PATH_MAX,
00854 "%s/device/vendor", sysfs_path);
00855 attr = sysfs_open_attribute (attr_path);
00856 if (sysfs_read_attribute (attr) >= 0) {
00857 hal_device_property_set_string (d, "info.vendor",
00858 strip_space (attr->
00859 value));
00860 sysfs_close_attribute (attr);
00861 }
00862
00863 snprintf (attr_path, SYSFS_PATH_MAX,
00864 "%s/device/model", sysfs_path);
00865 attr = sysfs_open_attribute (attr_path);
00866 if (sysfs_read_attribute (attr) >= 0) {
00867 strip_space (attr->value);
00868 hal_device_property_set_string (d,
00869 "info.product",
00870 attr->value);
00871 hal_device_property_set_string (stordev,
00872 "storage.model",
00873 attr->value);
00874 sysfs_close_attribute (attr);
00875 }
00876
00877 snprintf (attr_path, SYSFS_PATH_MAX,
00878 "%s/device/type", sysfs_path);
00879 attr = sysfs_open_attribute (attr_path);
00880 if (sysfs_read_attribute (attr) >= 0) {
00881 int type = parse_dec (attr->value);
00882 switch (type) {
00883 case 0:
00884 hal_device_property_set_string (
00885 stordev,
00886 "storage.media",
00887 "disk");
00888 break;
00889 case 1:
00890 has_removable_media = TRUE;
00891 hal_device_property_set_string (
00892 stordev,
00893 "storage.media",
00894 "tape");
00895 has_removable_media = TRUE;
00896 break;
00897 case 5:
00898 hal_device_property_set_string (
00899 stordev,
00900 "storage.media",
00901 "cdrom");
00902 has_removable_media = TRUE;
00903 break;
00904 default:
00906 HAL_WARNING (("Don't know how to "
00907 "handle SCSI type %d",
00908 type));
00909 }
00910 }
00911 } else {
00918 hal_device_property_set_string (
00919 stordev,
00920 "storage.media",
00921 "flash");
00922
00923
00924 hal_device_property_set_string (d, "info.product", "Disk");
00925
00926 }
00927
00928
00929 hal_device_property_set_bool (
00930 stordev,
00931 "storage.removable",
00932 has_removable_media);
00933
00934 if (has_removable_media) {
00935 hal_device_add_capability (
00936 stordev,
00937 "storage.removable");
00938 }
00939
00940
00941 if (hal_device_has_property (stordev, "storage.media") &&
00942 strcmp (hal_device_property_get_string (stordev, "storage.media"),
00943 "cdrom") == 0) {
00944 cdrom_check (stordev, device_file);
00945 }
00946
00947 hal_device_property_set_string (stordev, "info.category", "storage");
00948 hal_device_add_capability (stordev, "storage");
00949
00950 hal_device_property_set_bool (stordev, "storage.hotpluggable",
00951 is_hotpluggable);
00952 if (is_hotpluggable) {
00953 hal_device_add_capability (stordev, "storage.hotpluggable");
00954 }
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970 if (physdev != NULL) {
00971
00972
00973 hal_device_merge_with_rewrite (stordev, physdev,
00974 "storage.", "storage.");
00975
00976
00977
00978 if (scsidev != NULL) {
00979 int lun;
00980 char propname[64];
00981
00982 lun = hal_device_property_get_int (
00983 scsidev, "scsi_device.lun");
00984
00985
00986
00987 snprintf (propname, sizeof (propname),
00988 "storage_lun%d.", lun);
00989
00990 hal_device_merge_with_rewrite (stordev, physdev,
00991 "storage.", propname);
00992 }
00993 }
00994
00995
00996 detect_media (d);
00997 }
00998
00999 static char *
01000 block_class_compute_udi (HalDevice * d, int append_num)
01001 {
01002 char *format;
01003 static char buf[256];
01004
01005 if (append_num == -1)
01006 format = "/org/freedesktop/Hal/devices/block_%d_%d";
01007 else
01008 format = "/org/freedesktop/Hal/devices/block_%d_%d-%d";
01009
01010 snprintf (buf, 256, format,
01011 hal_device_property_get_int (d, "block.major"),
01012 hal_device_property_get_int (d, "block.minor"), append_num);
01013
01014 return buf;
01015 }
01016
01017
01018
01019 #define MOUNT_POINT_MAX 256
01020 #define MOUNT_POINT_STRING_SIZE 128
01021
01023 struct mount_point_s {
01024 int major;
01025 int minor;
01026 char device[MOUNT_POINT_STRING_SIZE];
01027 char mount_point[MOUNT_POINT_STRING_SIZE];
01029 char fs_type[MOUNT_POINT_STRING_SIZE];
01030 };
01031
01033 static struct mount_point_s mount_points[MOUNT_POINT_MAX];
01034
01036 static int num_mount_points;
01037
01038 static int etc_fd = -1;
01039
01040
01046 static void
01047 etc_mtab_process_line (char *s)
01048 {
01049 int i;
01050 char *p;
01051 char *delim = " \t\n";
01052 char buf[256];
01053 char *bufp = buf;
01054 struct stat stat_buf;
01055 int major = 0;
01056 int minor = 0;
01057 char *device = NULL;
01058 char *mount_point = NULL;
01059 char *fs_type = NULL;
01060
01061 i = 0;
01062 p = strtok_r (s, delim, &bufp);
01063 while (p != NULL) {
01064
01065 switch (i) {
01066 case 0:
01067 if (strcmp (p, "none") == 0)
01068 return;
01069 if (p[0] != '/')
01070 return;
01071 device = p;
01072
01073
01074 if (stat (p, &stat_buf) != 0) {
01075 return;
01076 }
01077 major = MAJOR (stat_buf.st_rdev);
01078 minor = MINOR (stat_buf.st_rdev);
01079 break;
01080
01081 case 1:
01082 mount_point = p;
01083 break;
01084
01085 case 2:
01086 fs_type = p;
01087 break;
01088
01089 case 3:
01090 break;
01091
01092 case 4:
01093 break;
01094
01095 case 5:
01096 break;
01097 }
01098
01099 p = strtok_r (NULL, delim, &bufp);
01100 i++;
01101 }
01102
01106 if (num_mount_points == MOUNT_POINT_MAX)
01107 return;
01108
01109 mount_points[num_mount_points].major = major;
01110 mount_points[num_mount_points].minor = minor;
01111 strncpy (mount_points[num_mount_points].device, device,
01112 MOUNT_POINT_STRING_SIZE);
01113 strncpy (mount_points[num_mount_points].mount_point, mount_point,
01114 MOUNT_POINT_STRING_SIZE);
01115 strncpy (mount_points[num_mount_points].fs_type, fs_type,
01116 MOUNT_POINT_STRING_SIZE);
01117
01118 num_mount_points++;
01119 }
01120
01122 static time_t etc_mtab_mtime = 0;
01123
01124
01134 static dbus_bool_t
01135 read_etc_mtab (dbus_bool_t force)
01136 {
01137 int fd;
01138 char buf[256];
01139 FILE *f;
01140 struct stat stat_buf;
01141
01142 num_mount_points = 0;
01143
01144 fd = open ("/etc/mtab", O_RDONLY);
01145
01146 if (fd == -1) {
01147 HAL_ERROR (("Cannot open /etc/mtab"));
01148 return FALSE;
01149 }
01150
01151 if (fstat (fd, &stat_buf) != 0) {
01152 HAL_ERROR (("Cannot fstat /etc/mtab fd, errno=%d", errno));
01153 return FALSE;
01154 }
01155
01156 if (!force && etc_mtab_mtime == stat_buf.st_mtime) {
01157
01158 return FALSE;
01159 }
01160
01161 etc_mtab_mtime = stat_buf.st_mtime;
01162
01163
01164
01165 f = fdopen (fd, "r");
01166
01167 if (f == NULL) {
01168 HAL_ERROR (("Cannot fdopen /etc/mtab fd"));
01169 return FALSE;
01170 }
01171
01172 while (!feof (f)) {
01173 if (fgets (buf, 256, f) == NULL)
01174 break;
01175
01176 etc_mtab_process_line (buf);
01177 }
01178
01179 fclose (f);
01180
01181 close (fd);
01182
01183 return TRUE;
01184 }
01185
01186 static void sigio_handler (int sig);
01187
01189 static dbus_bool_t have_setup_watcher = FALSE;
01190
01191 static gboolean
01192 foreach_block_device (HalDeviceStore *store, HalDevice *d,
01193 gpointer user_data)
01194 {
01195 const char *bus;
01196 int major, minor;
01197 dbus_bool_t found_mount_point;
01198 struct mount_point_s *mp;
01199 int i;
01200
01201 bus = hal_device_property_get_string (d, "info.bus");
01202 if (bus == NULL ||
01203 strncmp (bus, "block", 5) != 0 ||
01204 !hal_device_property_get_bool (d, "block.is_volume"))
01205 return TRUE;
01206
01207 major = hal_device_property_get_int (d, "block.major");
01208 minor = hal_device_property_get_int (d, "block.minor");
01209
01210
01211 found_mount_point = FALSE;
01212 for (i = 0; i < num_mount_points; i++) {
01213 mp = &mount_points[i];
01214
01215 if (mp->major == major && mp->minor == minor) {
01216 const char *existing_block_device;
01217 dbus_bool_t was_mounted;
01218
01219 HAL_INFO (("%s mounted at %s, major:minor=%d:%d, fstype=%s, udi=%s", mp->device, mp->mount_point, mp->major, mp->minor, mp->fs_type, d->udi));
01220
01221 device_property_atomic_update_begin ();
01222
01223 existing_block_device =
01224 hal_device_property_get_string (d,
01225 "block.device");
01226
01227 was_mounted =
01228 hal_device_property_get_bool (d,
01229 "block.is_mounted");
01230
01231
01232 hal_device_property_set_string (d,
01233 "block.mount_point",
01234 mp->mount_point);
01235 hal_device_property_set_string (d, "block.fstype",
01236 mp->fs_type);
01237 hal_device_property_set_bool (d,
01238 "block.is_mounted",
01239 TRUE);
01240
01241
01242 if (existing_block_device == NULL ||
01243 (existing_block_device != NULL &&
01244 strcmp (existing_block_device,
01245 "") == 0)) {
01246 hal_device_property_set_string (d,
01247 "block.device",
01248 mp->
01249 device);
01250 }
01251
01252 device_property_atomic_update_end ();
01253
01254 if (!was_mounted) {
01255 device_send_signal_condition (
01256 d,
01257 "BlockMountEvent",
01258 DBUS_TYPE_STRING,
01259 hal_device_property_get_string (
01260 d,
01261 "block.device"),
01262 DBUS_TYPE_STRING,
01263 mp->mount_point,
01264 DBUS_TYPE_STRING,
01265 mp->fs_type,
01266 DBUS_TYPE_INVALID);
01267 }
01268
01269 found_mount_point = TRUE;
01270 break;
01271 }
01272 }
01273
01274
01275 if (!found_mount_point) {
01276 dbus_bool_t was_mounted;
01277
01278 device_property_atomic_update_begin ();
01279
01280 was_mounted =
01281 hal_device_property_get_bool (d, "block.is_mounted");
01282
01283 hal_device_property_set_bool (d, "block.is_mounted",
01284 FALSE);
01285 hal_device_property_set_string (d, "block.mount_point",
01286 "");
01287 hal_device_property_set_string (d, "block.fstype", "");
01288
01289 device_property_atomic_update_end ();
01290
01291 if (was_mounted) {
01292 device_send_signal_condition (
01293 d, "BlockUnmountEvent",
01294 DBUS_TYPE_STRING,
01295 hal_device_property_get_string (
01296 d,
01297 "block.device"),
01298 DBUS_TYPE_INVALID);
01299 }
01300
01301 }
01302
01303 return TRUE;
01304 }
01305
01312 static void
01313 etc_mtab_process_all_block_devices (dbus_bool_t force)
01314 {
01315
01316 if (!have_setup_watcher) {
01317 have_setup_watcher = TRUE;
01318
01319 signal (SIGIO, sigio_handler);
01320 etc_fd = open ("/etc", O_RDONLY);
01321 fcntl (etc_fd, F_NOTIFY, DN_MODIFY | DN_MULTISHOT);
01322 }
01323
01324
01325 if (!read_etc_mtab (force))
01326 return;
01327
01328 HAL_INFO (("/etc/mtab changed, processing all block devices"));
01329
01330 hal_device_store_foreach (hald_get_gdl (), foreach_block_device, NULL);
01331 }
01332
01333
01335 static dbus_bool_t sigio_etc_changed = FALSE;
01336
01341 static void
01342 sigio_handler (int sig)
01343 {
01344
01345
01346
01347
01348
01349 sigio_etc_changed = TRUE;
01350 }
01351
01352
01353 static void
01354 block_class_removed (ClassDeviceHandler* self,
01355 const char *sysfs_path,
01356 HalDevice *d)
01357 {
01358 if (hal_device_has_property (d, "block.is_volume")) {
01359 if (hal_device_property_get_bool (d, "block.is_volume")) {
01360 force_unmount (d);
01361 } else {
01362 force_unmount_of_all_childs (d);
01363 }
01364 }
01365 }
01366
01367
01368 static gboolean
01369 foreach_detect_media (HalDeviceStore *store, HalDevice *device,
01370 gpointer user_data)
01371 {
01375 if (detect_media (device))
01376 return FALSE;
01377 else
01378 return TRUE;
01379 }
01380
01381 static void
01382 block_class_tick (ClassDeviceHandler *self)
01383 {
01384
01385
01386 hal_device_store_foreach (hald_get_gdl (), foreach_detect_media, NULL);
01387
01388
01389 if (sigio_etc_changed) {
01390
01391 sigio_etc_changed = FALSE;
01392
01393 HAL_INFO (("Directory /etc changed"));
01394
01395 etc_mtab_process_all_block_devices (FALSE);
01396 }
01397
01398
01399 }
01400
01401 static void
01402 block_class_detection_done (ClassDeviceHandler *self)
01403 {
01404 etc_mtab_process_all_block_devices (TRUE);
01405 }
01406
01408 ClassDeviceHandler block_class_handler = {
01409 class_device_init,
01410 block_class_detection_done,
01411 class_device_shutdown,
01412 block_class_tick,
01413 class_device_accept,
01414 block_class_visit,
01415 block_class_removed,
01416 class_device_udev_event,
01417 class_device_get_device_file_target,
01418 block_class_pre_process,
01419 class_device_post_merge,
01420 block_class_got_udi,
01421 block_class_compute_udi,
01422 "block",
01423 "block",
01424 TRUE,
01425 FALSE
01426 };
01427