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 #include <errno.h>
00039 #include <sys/types.h>
00040 #include <sys/stat.h>
00041 #include <signal.h>
00042
00043 #include <glib.h>
00044
00045 #define _GNU_SOURCE 1
00046 #include <linux/fcntl.h>
00047 #include <linux/kdev_t.h>
00048 #include <linux/cdrom.h>
00049 #include <linux/fs.h>
00050
00051 #include "../logger.h"
00052 #include "../device_store.h"
00053 #include "../hald.h"
00054 #include "linux_class_block.h"
00055 #include "linux_dvd_rw_utils.h"
00056
00057
00058 static void etc_mtab_process_all_block_devices (dbus_bool_t force);
00059 static dbus_bool_t detect_media (HalDevice * d);
00060
00077 static char *
00078 block_compute_udi (HalDevice * d, int append_num)
00079 {
00080 char *format;
00081 static char buf[256];
00082
00083 if (append_num == -1)
00084 format = "/org/freedesktop/Hal/devices/block_%d_%d";
00085 else
00086 format = "/org/freedesktop/Hal/devices/block_%d_%d-%d";
00087
00088 snprintf (buf, 256, format,
00089 ds_property_get_int (d, "block.major"),
00090 ds_property_get_int (d, "block.minor"), append_num);
00091
00092 return buf;
00093 }
00094
00095
00096 static void visit_class_device_block_got_parent (HalDevice * parent,
00097 void *data1, void *data2);
00098
00107 void
00108 visit_class_device_block (const char *path,
00109 struct sysfs_class_device *class_device)
00110 {
00111 HalDevice *d;
00112 char *parent_sysfs_path;
00113 char attr_name[SYSFS_NAME_LEN];
00114 struct sysfs_attribute *cur;
00115 dbus_bool_t is_disk = FALSE;
00116 dbus_bool_t not_partition = FALSE;
00117
00118 if (sysfs_get_classdev_attr (class_device, "dev") == NULL) {
00119
00120
00121
00122 return;
00123 }
00124
00125 d = ds_device_new ();
00126 ds_property_set_string (d, "info.bus", "block");
00127 ds_property_set_string (d, "linux.sysfs_path", path);
00128 ds_property_set_string (d, "linux.sysfs_path_device", path);
00129
00130 ds_add_capability (d, "block");
00131
00132 dlist_for_each_data (sysfs_get_classdev_attributes (class_device),
00133 cur, struct sysfs_attribute) {
00134 if (sysfs_get_name_from_path
00135 (cur->path, attr_name, SYSFS_NAME_LEN) != 0)
00136 continue;
00137
00138 if (strcmp (attr_name, "dev") == 0) {
00139 int major, minor;
00140 if (sscanf (cur->value, "%d:%d", &major, &minor) ==
00141 2) {
00142 is_disk = TRUE;
00143 ds_property_set_int (d, "block.major",
00144 major);
00145 ds_property_set_int (d, "block.minor",
00146 minor);
00147 }
00148 } else if (strcmp (attr_name, "size") == 0) {
00149 ds_property_set_int (d, "block.size",
00150 parse_dec (cur->value));
00151 } else if (strcmp (attr_name, "start") == 0) {
00152 ds_property_set_int (d, "block.start",
00153 parse_dec (cur->value));
00154 } else if (strcmp (attr_name, "range") == 0) {
00155 not_partition = TRUE;
00156 }
00157 }
00158 ds_property_set_bool (d, "block.is_volume", !not_partition);
00159
00161 ds_property_set_int (d, "block.block_size", 512);
00162
00163 if (class_device->sysdevice == NULL) {
00164
00165
00166
00167
00168
00169
00170
00171
00172 parent_sysfs_path = get_parent_sysfs_path (path);
00173 } else {
00174
00175
00176
00177
00178
00179 parent_sysfs_path = class_device->sysdevice->path;
00180 }
00181
00182
00183
00184
00185
00186
00187 ds_device_async_find_by_key_value_string
00188 ("linux.sysfs_path_device", parent_sysfs_path, TRUE,
00189 visit_class_device_block_got_parent, (void *) d,
00190 NULL,
00191 is_probing ? 0 : HAL_LINUX_HOTPLUG_TIMEOUT);
00192
00193
00194
00195
00196
00197 }
00198
00199 static char *
00200 strip_space (char *str)
00201 {
00202 int i, len;
00203
00204 len = strlen (str);
00205 for (i = len - 1; i > 0 && isspace (str[i]); --i)
00206 str[i] = '\0';
00207
00208 return str;
00209 }
00210
00218 static void
00219 visit_class_device_block_got_parent (HalDevice * parent,
00220 void *data1, void *data2)
00221 {
00222 char *new_udi = NULL;
00223 HalDevice *new_d = NULL;
00224 HalDevice *d = (HalDevice *) data1;
00225
00226 HAL_INFO (("data2=0x%08x, d=0x%08x, d->udi=%s, parent->udi=%s, parent->in_gdl=%d", data2, d, d->udi, parent != NULL ? parent->udi : "no parent", parent != NULL ? parent->in_gdl : 42));
00227 HAL_INFO (("d: linux.sysfs_path=%s",
00228 ds_property_get_string (d, "linux.sysfs_path")));
00229 HAL_INFO (("d: linux.sysfs_path_device=%s",
00230 ds_property_get_string (d, "linux.sysfs_path_device")));
00231
00232 if (parent == NULL) {
00233 HAL_WARNING (("No parent for block device!"));
00234 ds_device_destroy (d);
00235 return;
00236 }
00237 ds_property_set_string (d, "info.parent", parent->udi);
00238
00239
00240
00241
00242 if (is_probing) {
00243 int i;
00244 const char *path;
00245 int sysfs_mount_path_len;
00246 char sysfs_path_trunc[SYSFS_NAME_LEN];
00247 char *udev_argv[7] =
00248 { udevinfo_path (), "-r", "-q", "name", "-p",
00249 sysfs_path_trunc, NULL
00250 };
00251 char *udev_stdout;
00252 char *udev_stderr;
00253 int udev_exitcode;
00254
00255 path = ds_property_get_string (d, "linux.sysfs_path");
00256
00257
00258 sysfs_mount_path_len = strlen (sysfs_mount_path);
00259 if (strlen (path) > sysfs_mount_path_len) {
00260 strncpy (sysfs_path_trunc,
00261 path + sysfs_mount_path_len,
00262 SYSFS_NAME_LEN);
00263 }
00264 HAL_INFO (("*** sysfs_path_trunc = '%s'",
00265 sysfs_path_trunc));
00266
00267
00268 if (udev_argv[0] == NULL || g_spawn_sync ("/",
00269 udev_argv,
00270 NULL,
00271 0,
00272 NULL,
00273 NULL,
00274 &udev_stdout,
00275 &udev_stderr,
00276 &udev_exitcode,
00277 NULL) != TRUE) {
00278 HAL_ERROR (("Couldn't invoke udevinfo"));
00279 goto error;
00280 }
00281
00282 if (udev_exitcode != 0) {
00283 HAL_ERROR (("%s returned %d", udevinfo_path (),
00284 udev_exitcode));
00285 goto error;
00286 }
00287
00288
00289 for (i = 0; udev_stdout[i] != 0; i++) {
00290 if (udev_stdout[i] == '\r'
00291 || udev_stdout[i] == '\n') {
00292 udev_stdout[i] = 0;
00293 break;
00294 }
00295 }
00296
00297 HAL_INFO (("device file = '%s'", udev_stdout));
00298
00299 ds_property_set_string (d, "block.device", udev_stdout);
00300
00302 } else {
00303 error:
00304
00305 if (!ds_property_exists (d, "block.device")) {
00306 ds_property_set_string (d, "block.device", "");
00307 }
00308 }
00309
00310
00311
00312 if (ds_property_get_bool (d, "block.is_volume")) {
00313
00314 find_and_set_physical_device (d);
00315 ds_property_set_bool (d, "info.virtual", TRUE);
00316 ds_add_capability (d, "volume");
00317 ds_property_set_string (d, "info.category", "volume");
00318
00319
00320
00322 ds_property_set_string (d, "info.product", "Volume");
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334 } else {
00335 dbus_bool_t removable_media = FALSE;
00336
00337
00338 ds_property_set_bool (d, "storage.cdr", FALSE);
00339 ds_property_set_bool (d, "storage.cdrw", FALSE);
00340 ds_property_set_bool (d, "storage.dvd", FALSE);
00341 ds_property_set_bool (d, "storage.dvdr", FALSE);
00342 ds_property_set_bool (d, "storage.dvdram", FALSE);
00343
00344
00345
00346
00347 ds_property_set_string (d, "info.category", "block");
00348
00349 HAL_INFO (("Bus type is %s!",
00350 ds_property_get_string (parent, "info.bus")));
00351
00352 if (strcmp
00353 (ds_property_get_string (parent, "info.bus"),
00354 "ide") == 0) {
00355 const char *ide_name;
00356 char *model;
00357 char *media;
00358
00359 ide_name =
00360 get_last_element (ds_property_get_string
00361 (d, "linux.sysfs_path"));
00362
00363 model =
00364 read_single_line ("/proc/ide/%s/model",
00365 ide_name);
00366 if (model != NULL) {
00367 ds_property_set_string (d, "storage.model",
00368 model);
00369 ds_property_set_string (d, "info.product",
00370 model);
00371 }
00372
00373
00374
00375
00376
00377
00378
00379
00384 media =
00385 read_single_line ("/proc/ide/%s/media",
00386 ide_name);
00387 if (media != NULL) {
00388 ds_property_set_string (d, "storage.media",
00389 media);
00390
00391
00392 if (strcmp (media, "disk") == 0) {
00393 ds_add_capability (d, "storage");
00394 ds_property_set_string (d,
00395 "info.category",
00396 "storage");
00397 } else if (strcmp (media, "cdrom") == 0) {
00398 ds_add_capability (d, "storage");
00399 ds_add_capability (d,
00400 "storage.removable");
00401 ds_property_set_string (d,
00402 "info.category",
00403 "storage.removable");
00404
00405 removable_media = TRUE;
00406 } else if (strcmp (media, "floppy") == 0) {
00407 ds_add_capability (d, "storage");
00408 ds_add_capability (d,
00409 "storage.removable");
00410 ds_property_set_string (d,
00411 "info.category",
00412 "storage.removable");
00413 removable_media = TRUE;
00414 } else if (strcmp (media, "tape") == 0) {
00415 ds_add_capability (d, "storage");
00416 ds_add_capability (d,
00417 "storage.removable");
00418 ds_property_set_string (d,
00419 "info.category",
00420 "storage.removable");
00421 removable_media = TRUE;
00422 }
00423
00424 }
00425
00426 }
00427 else if (strcmp (ds_property_get_string (parent,"info.bus"),
00428 "scsi_device") == 0) {
00429 const char *sysfs_path;
00430 char attr_path[SYSFS_PATH_MAX];
00431 struct sysfs_attribute *attr;
00432
00433 sysfs_path = ds_property_get_string (
00434 d,
00435 "linux.sysfs_path");
00436
00437 snprintf (attr_path, SYSFS_PATH_MAX,
00438 "%s/device/vendor", sysfs_path);
00439
00440 attr = sysfs_open_attribute (attr_path);
00441
00442 if (sysfs_read_attribute (attr) >= 0) {
00443 ds_property_set_string (d, "info.vendor",
00444 strip_space (attr->
00445 value));
00446 sysfs_close_attribute (attr);
00447 }
00448
00449 snprintf (attr_path, SYSFS_PATH_MAX,
00450 "%s/device/model", sysfs_path);
00451
00452 attr = sysfs_open_attribute (attr_path);
00453
00454 if (sysfs_read_attribute (attr) >= 0) {
00455 ds_property_set_string (d, "info.product",
00456 strip_space (attr->
00457 value));
00458 sysfs_close_attribute (attr);
00459 }
00460
00461 snprintf (attr_path, SYSFS_PATH_MAX,
00462 "%s/device/type", sysfs_path);
00463
00464 attr = sysfs_open_attribute (attr_path);
00465
00466 if (sysfs_read_attribute (attr) >= 0) {
00467 int type = parse_dec (attr->value);
00468
00469 switch (type) {
00470 case 0:
00471 ds_add_capability (d, "storage");
00472 ds_property_set_string (
00473 d, "info.category", "storage");
00474 ds_property_set_string (
00475 d, "storage.media", "disk");
00476 break;
00477 case 1:
00478 ds_add_capability (d, "storage");
00479 ds_add_capability (
00480 d, "storage.removable");
00481 ds_property_set_string (
00482 d, "info.category",
00483 "storage.removable");
00484 ds_property_set_string (
00485 d,
00486 "storage.media", "tape");
00487 removable_media = TRUE;
00488 break;
00489 case 5:
00490 ds_add_capability (d, "storage");
00491 ds_add_capability (
00492 d, "storage.removable");
00493 ds_property_set_string (
00494 d, "storage.media", "cdrom");
00495 ds_property_set_string (
00496 d, "info.category",
00497 "storage.removable");
00498 removable_media = TRUE;
00499 break;
00500 default:
00502 HAL_WARNING (("Don't know how to "
00503 "handle SCSI type %d",
00504 type));
00505 }
00506 }
00507 } else {
00515 ds_property_set_string (d, "storage.media",
00516 "flash");
00517
00518 ds_add_capability (d, "storage");
00519 ds_property_set_string (d, "info.category",
00520 "storage");
00521
00522
00523 ds_property_set_string (d, "info.product", "Disk");
00524
00525 }
00526
00527 ds_property_set_bool (d, "storage.removable",
00528 removable_media);
00529
00530
00531
00532
00533
00534
00535
00536 }
00537
00538
00539 etc_mtab_process_all_block_devices (TRUE);
00540
00541 new_udi = rename_and_merge (d, block_compute_udi, "block");
00542 if (new_udi != NULL) {
00543 new_d = ds_device_find (new_udi);
00544 if (new_d != NULL) {
00545 linux_class_block_check_if_ready_to_add (new_d);
00546 }
00547 }
00548 }
00549
00555 void
00556 linux_class_block_check_if_ready_to_add (HalDevice * d)
00557 {
00558 const char *parent;
00559 const char *device_file;
00560
00561
00562
00563
00564
00565
00566
00567 parent = ds_property_get_string (d, "info.parent");
00568 if (parent == NULL)
00569 return;
00570
00571 device_file = ds_property_get_string (d, "block.device");
00572 HAL_INFO (("Entering, udi=%s, device_file=%s", d->udi,
00573 device_file));
00574
00575 if (device_file != NULL && strcmp (device_file, "") != 0) {
00576 const char *media;
00577
00578
00579
00580
00581 media = ds_property_get_string (d, "storage.media");
00582 if (media != NULL && strcmp (media, "cdrom") == 0) {
00583 int fd, capabilities;
00584
00585
00586 fd = open (device_file, O_RDONLY | O_NONBLOCK);
00587
00588 ioctl (fd, CDROM_SET_OPTIONS, CDO_USE_FFLAGS);
00589
00590 if (fd >= 0) {
00591 capabilities =
00592 ioctl (fd, CDROM_GET_CAPABILITY, 0);
00593
00594 if (capabilities >= 0) {
00595 int read_speed, write_speed;
00596
00597 if (capabilities & CDC_CD_R) {
00598 ds_add_capability (
00599 d,
00600 "storage.cdr");
00601 ds_property_set_bool (
00602 d,
00603 "storage.cdr", TRUE);
00604 }
00605 if (capabilities & CDC_CD_RW) {
00606 ds_add_capability (
00607 d,
00608 "storage.cdrw");
00609 ds_property_set_bool (
00610 d,
00611 "storage.cdrw", TRUE);
00612 }
00613 if (capabilities & CDC_DVD) {
00614 int profile;
00615
00616 ds_add_capability (
00617 d,
00618 "storage.dvd");
00619 ds_property_set_bool (
00620 d,
00621 "storage.dvd", TRUE);
00622
00623 profile =
00624 get_dvd_r_rw_profile (fd);
00625 HAL_WARNING (("profile %d\n", profile));
00626 if (profile == 2) {
00627 ds_add_capability
00628 (d, "storage.dvdplusr");
00629 ds_property_set_bool
00630 (d, "storage.dvdplusr",
00631 TRUE);
00632 ds_add_capability
00633 (d, "storage.dvdplusrw");
00634 ds_property_set_bool
00635 (d, "storage.dvdplusrw",
00636 TRUE);
00637 } else if (profile == 0) {
00638 ds_add_capability
00639 (d, "storage.dvdplusr");
00640 ds_property_set_bool
00641 (d, "storage.dvdplusr",
00642 TRUE);
00643 } else if (profile == 1) {
00644 ds_add_capability
00645 (d, "storage.dvdplusrw");
00646 ds_property_set_bool
00647 (d, "storage.dvdplusrw",
00648 TRUE);
00649 }
00650 }
00651 if (capabilities & CDC_DVD_R) {
00652 ds_add_capability (d, "storage.dvdr");
00653 ds_property_set_bool (d, "storage.dvdr",
00654 TRUE);
00655 }
00656 if (capabilities & CDC_DVD_RAM) {
00657 ds_add_capability (d, "storage.dvdram");
00658 ds_property_set_bool (d, "storage.dvdram",
00659 TRUE);
00660 }
00661
00662
00663 if (ioctl (fd, CDROM_MEDIA_CHANGED)
00664 >= 0) {
00665 ds_property_set_bool (d, "storage.cdrom.support_media_changed",
00666 TRUE);
00667 }
00668
00669 if (get_read_write_speed
00670 (fd, &read_speed,
00671 &write_speed) >= 0) {
00672 ds_property_set_int (d, "storage.cdrom.read_speed",
00673 read_speed);
00674 if (write_speed > 0)
00675 ds_property_set_int
00676 (d, "storage.cdrom.write_speed",
00677 write_speed);
00678 }
00679 }
00680 close (fd);
00681 }
00682 }
00683
00684 if (ds_property_get_bool (d, "block.is_volume")) {
00685
00686 ds_property_set_string (d, "block.storage_device",
00687 parent);
00688 } else {
00689
00690
00691
00692
00693
00694 ds_property_set_string (d, "block.storage_device",
00695 d->udi);
00696 }
00697
00698
00699 ds_gdl_add (d);
00700
00701
00702 detect_media (d);
00703 }
00704 }
00705
00706
00707
00708 #define MOUNT_POINT_MAX 256
00709 #define MOUNT_POINT_STRING_SIZE 128
00710
00712 struct mount_point_s {
00713 int major;
00714 int minor;
00715 char device[MOUNT_POINT_STRING_SIZE];
00716 char mount_point[MOUNT_POINT_STRING_SIZE];
00718 char fs_type[MOUNT_POINT_STRING_SIZE];
00719 };
00720
00722 static struct mount_point_s mount_points[MOUNT_POINT_MAX];
00723
00725 static int num_mount_points;
00726
00727 static int etc_fd = -1;
00728
00729
00735 static void
00736 etc_mtab_process_line (char *s)
00737 {
00738 int i;
00739 char *p;
00740 char *delim = " \t\n";
00741 char buf[256];
00742 char *bufp = buf;
00743 struct stat stat_buf;
00744 int major = 0;
00745 int minor = 0;
00746 char *device = NULL;
00747 char *mount_point = NULL;
00748 char *fs_type = NULL;
00749
00750 i = 0;
00751 p = strtok_r (s, delim, &bufp);
00752 while (p != NULL) {
00753
00754 switch (i) {
00755 case 0:
00756 if (strcmp (p, "none") == 0)
00757 return;
00758 if (p[0] != '/')
00759 return;
00760 device = p;
00761
00762
00763 if (stat (p, &stat_buf) != 0) {
00764 return;
00765 }
00766 major = MAJOR (stat_buf.st_rdev);
00767 minor = MINOR (stat_buf.st_rdev);
00768 break;
00769
00770 case 1:
00771 mount_point = p;
00772 break;
00773
00774 case 2:
00775 fs_type = p;
00776 break;
00777
00778 case 3:
00779 break;
00780
00781 case 4:
00782 break;
00783
00784 case 5:
00785 break;
00786 }
00787
00788 p = strtok_r (NULL, delim, &bufp);
00789 i++;
00790 }
00791
00795 if (num_mount_points == MOUNT_POINT_MAX)
00796 return;
00797
00798 mount_points[num_mount_points].major = major;
00799 mount_points[num_mount_points].minor = minor;
00800 strncpy (mount_points[num_mount_points].device, device,
00801 MOUNT_POINT_STRING_SIZE);
00802 strncpy (mount_points[num_mount_points].mount_point, mount_point,
00803 MOUNT_POINT_STRING_SIZE);
00804 strncpy (mount_points[num_mount_points].fs_type, fs_type,
00805 MOUNT_POINT_STRING_SIZE);
00806
00807 num_mount_points++;
00808 }
00809
00811 static time_t etc_mtab_mtime = 0;
00812
00813
00823 static dbus_bool_t
00824 read_etc_mtab (dbus_bool_t force)
00825 {
00826 int fd;
00827 char buf[256];
00828 FILE *f;
00829 struct stat stat_buf;
00830
00831 num_mount_points = 0;
00832
00833 fd = open ("/etc/mtab", O_RDONLY);
00834
00835 if (fd == -1) {
00836 HAL_ERROR (("Cannot open /etc/mtab"));
00837 return FALSE;
00838 }
00839
00840 if (fstat (fd, &stat_buf) != 0) {
00841 HAL_ERROR (("Cannot fstat /etc/mtab fd, errno=%d", errno));
00842 return FALSE;
00843 }
00844
00845 if (!force && etc_mtab_mtime == stat_buf.st_mtime) {
00846
00847 return FALSE;
00848 }
00849
00850 etc_mtab_mtime = stat_buf.st_mtime;
00851
00852
00853
00854 f = fdopen (fd, "r");
00855
00856 if (f == NULL) {
00857 HAL_ERROR (("Cannot fdopen /etc/mtab fd"));
00858 return FALSE;
00859 }
00860
00861 while (!feof (f)) {
00862 if (fgets (buf, 256, f) == NULL)
00863 break;
00864
00865 etc_mtab_process_line (buf);
00866 }
00867
00868 fclose (f);
00869
00870 close (fd);
00871
00872 return TRUE;
00873 }
00874
00875 static void sigio_handler (int sig);
00876
00878 static dbus_bool_t have_setup_watcher = FALSE;
00879
00886 static void
00887 etc_mtab_process_all_block_devices (dbus_bool_t force)
00888 {
00889 int i;
00890 const char *bus;
00891 HalDevice *d;
00892 int major, minor;
00893 dbus_bool_t found_mount_point;
00894 struct mount_point_s *mp;
00895 HalDeviceIterator diter;
00896
00897
00898 if (!have_setup_watcher) {
00899 have_setup_watcher = TRUE;
00900
00901 signal (SIGIO, sigio_handler);
00902 etc_fd = open ("/etc", O_RDONLY);
00903 fcntl (etc_fd, F_NOTIFY, DN_MODIFY | DN_MULTISHOT);
00904 }
00905
00906
00907 if (!read_etc_mtab (force))
00908 return;
00909
00910 HAL_INFO (("/etc/mtab changed, processing all block devices"));
00911
00912
00913 for (ds_device_iter_begin (&diter);
00914 ds_device_iter_has_more (&diter);
00915 ds_device_iter_next (&diter)) {
00916
00917 d = ds_device_iter_get (&diter);
00918
00919 bus = ds_property_get_string (d, "info.bus");
00920 if (bus == NULL || strcmp (bus, "block") != 0 ||
00921 !ds_property_get_bool (d, "block.is_volume"))
00922 continue;
00923
00924 major = ds_property_get_int (d, "block.major");
00925 minor = ds_property_get_int (d, "block.minor");
00926
00927
00928 found_mount_point = FALSE;
00929 for (i = 0; i < num_mount_points; i++) {
00930 mp = &mount_points[i];
00931
00932 if (mp->major == major && mp->minor == minor) {
00933 const char *existing_block_device;
00934 dbus_bool_t was_mounted;
00935
00936 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));
00937
00938 property_atomic_update_begin ();
00939
00940 existing_block_device =
00941 ds_property_get_string (d,
00942 "block.device");
00943
00944 was_mounted =
00945 ds_property_get_bool (d,
00946 "block.is_mounted");
00947
00948
00949 ds_property_set_string (d,
00950 "block.mount_point",
00951 mp->mount_point);
00952 ds_property_set_string (d, "block.fstype",
00953 mp->fs_type);
00954 ds_property_set_bool (d,
00955 "block.is_mounted",
00956 TRUE);
00957
00958
00959 if (existing_block_device == NULL ||
00960 (existing_block_device != NULL &&
00961 strcmp (existing_block_device,
00962 "") == 0)) {
00963 ds_property_set_string (d,
00964 "block.device",
00965 mp->
00966 device);
00967 }
00968
00969 property_atomic_update_end ();
00970
00971 if (!was_mounted) {
00972 emit_condition (d,
00973 "BlockMountEvent",
00974 DBUS_TYPE_STRING,
00975 ds_property_get_string
00976 (d,
00977 "block.device"),
00978 DBUS_TYPE_STRING,
00979 mp->mount_point,
00980 DBUS_TYPE_STRING,
00981 mp->fs_type,
00982 DBUS_TYPE_INVALID);
00983 }
00984
00985 found_mount_point = TRUE;
00986 break;
00987 }
00988 }
00989
00990
00991 if (!found_mount_point) {
00992 dbus_bool_t was_mounted;
00993
00994 property_atomic_update_begin ();
00995
00996 was_mounted =
00997 ds_property_get_bool (d, "block.is_mounted");
00998
00999 ds_property_set_bool (d, "block.is_mounted",
01000 FALSE);
01001 ds_property_set_string (d, "block.mount_point",
01002 "");
01003 ds_property_set_string (d, "block.fstype", "");
01004
01005 property_atomic_update_end ();
01006
01007 if (was_mounted) {
01008 emit_condition (d, "BlockUnmountEvent",
01009 DBUS_TYPE_STRING,
01010 ds_property_get_string (d,
01011 "block.device"),
01012 DBUS_TYPE_INVALID);
01013 }
01014
01015 }
01016 }
01017 }
01018
01019
01021 static dbus_bool_t sigio_etc_changed = FALSE;
01022
01027 static void
01028 sigio_handler (int sig)
01029 {
01030
01031
01032
01033
01034
01035 sigio_etc_changed = TRUE;
01036 }
01037
01041 void
01042 linux_class_block_init ()
01043 {
01044 }
01045
01051 static void
01052 force_unmount (HalDevice * d)
01053 {
01054 const char *device_file;
01055 const char *device_mount_point;
01056 const char *umount_argv[4] = { "/bin/umount", "-l", NULL, NULL };
01057 char *umount_stdout;
01058 char *umount_stderr;
01059 int umount_exitcode;
01060
01061 device_file = ds_property_get_string (d, "block.device");
01062 device_mount_point =
01063 ds_property_get_string (d, "block.mount_point");
01064
01065 umount_argv[2] = device_file;
01066
01067 if (ds_property_exists (d, "block.is_volume") &&
01068 ds_property_get_bool (d, "block.is_volume") &&
01069 device_mount_point != NULL &&
01070 strlen (device_mount_point) > 0) {
01071 HAL_INFO (("attempting /bin/umount -l %s", device_file));
01072
01073
01074 if (g_spawn_sync ("/",
01075 (char **) umount_argv,
01076 NULL,
01077 0,
01078 NULL,
01079 NULL,
01080 &umount_stdout,
01081 &umount_stderr,
01082 &umount_exitcode, NULL) != TRUE) {
01083 HAL_ERROR (("Couldn't invoke /bin/umount"));
01084 }
01085
01086 if (umount_exitcode != 0) {
01087 HAL_INFO (("/bin/umount returned %d",
01088 umount_exitcode));
01089 } else {
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099 HAL_INFO (("Goint to emit BlockForcedUnmountPartition('%s', '%s', TRUE)", device_file, device_mount_point));
01100 emit_condition (d, "BlockForcedUnmountPartition",
01101 DBUS_TYPE_STRING, device_file,
01102 DBUS_TYPE_STRING,
01103 device_mount_point,
01104 DBUS_TYPE_BOOLEAN, TRUE,
01105 DBUS_TYPE_INVALID);
01106
01107
01108
01109
01110
01111
01112 property_atomic_update_begin ();
01113 ds_property_set_string (d, "block.mount_point",
01114 "");
01115 ds_property_set_string (d, "block.fstype", "");
01116 ds_property_set_bool (d, "block.is_mounted",
01117 FALSE);
01118 property_atomic_update_end ();
01119 }
01120 }
01121 }
01122
01128 static void
01129 force_unmount_of_all_childs (HalDevice * d)
01130 {
01131 int fd;
01132 int num_childs;
01133 const char *device_file;
01134 HalDevice *child;
01135 HalDevice **childs;
01136
01137 device_file = ds_property_get_string (d, "block.device");
01138
01139 childs =
01140 ds_device_find_multiple_by_key_value_string ("info.parent",
01141 d->udi, TRUE,
01142 &num_childs);
01143 if (childs != NULL) {
01144 int n;
01145
01146 for (n = 0; n < num_childs; n++) {
01147 child = childs[n];
01148
01149 force_unmount (child);
01150
01151 }
01152
01153 free (childs);
01154
01155 HAL_INFO (("Rereading partition table for %s",
01156 device_file));
01157 fd = open (device_file, O_RDONLY | O_NONBLOCK);
01158 if (fd != -1) {
01159 ioctl (fd, BLKRRPART);
01160 }
01161 close (fd);
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172 HAL_INFO (("Goint to emit BlockForcedUnmount('%s')",
01173 device_file));
01174 emit_condition (d, "BlockForcedUnmount",
01175 DBUS_TYPE_STRING, device_file,
01176 DBUS_TYPE_INVALID);
01177
01178 }
01179 }
01180
01181
01182
01187 void
01188 linux_class_block_removed (HalDevice * d)
01189 {
01190 if (ds_property_exists (d, "block.is_volume")) {
01191 if (ds_property_get_bool (d, "block.is_volume")) {
01192 force_unmount (d);
01193 } else {
01194 force_unmount_of_all_childs (d);
01195 }
01196 }
01197 }
01198
01207 static dbus_bool_t
01208 detect_media (HalDevice * d)
01209 {
01210 int fd;
01211 dbus_bool_t is_cdrom;
01212 const char *device_file;
01213 HalDevice *child;
01214
01215
01216
01217
01218 if (!d->in_gdl ||
01219 (!ds_property_exists (d, "block.is_volume")) ||
01220 (!ds_property_exists (d, "block.device")) ||
01221 ds_property_get_bool (d, "block.is_volume"))
01222 return FALSE;
01223
01224 device_file = ds_property_get_string (d, "block.device");
01225 if (device_file == NULL)
01226 return FALSE;
01227
01228
01229 is_cdrom = ds_property_exists (d, "storage.media") &&
01230 strcmp (ds_property_get_string (d, "storage.media"),
01231 "cdrom") == 0
01232 && ds_property_get_bool (d,
01233 "storage.cdrom.support_media_changed");
01234
01235 if (!is_cdrom) {
01236 fd = open (device_file, O_RDONLY);
01237
01238 if (fd == -1) {
01239
01240 HAL_WARNING (("open(\"%s\", O_RDONLY) failed, "
01241 "errno=%d", device_file, errno));
01242
01243 if (errno == ENOMEDIUM) {
01244 force_unmount_of_all_childs (d);
01245 }
01246
01247 }
01248
01249 }
01250 else {
01251 int drive;
01252 dbus_bool_t got_disc = FALSE;
01253
01254 fd = open (device_file, O_RDONLY | O_NONBLOCK | O_EXCL);
01255
01256 if (fd == -1) {
01257
01258 HAL_WARNING (("open(\"%s\", O_RDONLY|O_NONBLOCK|O_EXCL) failed, " "errno=%d", device_file, errno));
01259 return FALSE;
01260 }
01261
01262 drive = ioctl (fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
01263 switch (drive) {
01264
01265 case CDS_NO_INFO:
01266 case CDS_NO_DISC:
01267 case CDS_TRAY_OPEN:
01268 case CDS_DRIVE_NOT_READY:
01269 break;
01270
01271 case CDS_DISC_OK:
01272 got_disc = TRUE;
01273 break;
01274
01275 default:
01276 break;
01277 }
01278
01279 if (!got_disc) {
01280
01281 child =
01282 ds_device_find_by_key_value_string
01283 ("info.parent", d->udi, TRUE);
01284
01285 if (child != NULL) {
01286 HAL_INFO (("Removing volume for optical device %s", device_file));
01287 ds_device_destroy (child);
01288
01289 close (fd);
01290
01291
01292 return TRUE;
01293 }
01294
01295 close (fd);
01296 return FALSE;
01297 }
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307 close (fd);
01308
01309 child = ds_device_find_by_key_value_string ("info.parent",
01310 d->udi, TRUE);
01311 if (child == NULL) {
01312 char udi[256];
01313
01314
01315 HAL_INFO (("Adding volume for optical device %s",
01316 device_file));
01317
01318 child = ds_device_new ();
01319
01320
01321 ds_device_merge (child, d);
01322
01323
01324 ds_property_set_string (child, "info.parent",
01325 d->udi);
01326 ds_property_set_bool (child, "block.is_volume",
01327 TRUE);
01328 ds_property_set_string (child, "info.capabilities",
01329 "block volume");
01330 ds_property_set_string (child, "info.category",
01331 "volume");
01332 ds_property_set_string (child, "info.product",
01333 "Disc");
01334
01335
01336 strncpy (udi,
01337 ds_property_get_string (d, "info.udi"),
01338 256);
01339 strncat (udi, "-disc", 256);
01340 ds_property_set_string (child, "info.udi", udi);
01341 ds_device_set_udi (child, udi);
01342
01343
01344 ds_gdl_add (child);
01345
01346
01347 return TRUE;
01348 }
01349
01350 }
01351
01352 close (fd);
01353
01354 return FALSE;
01355 }
01356
01362 static gboolean
01363 media_detect_timer_handler (gpointer data)
01364 {
01365 int fd;
01366 const char *device_file;
01367 HalDevice *d;
01368 HalDeviceIterator iter;
01369
01370
01371
01372
01373 for (ds_device_iter_begin (&iter);
01374 ds_device_iter_has_more (&iter);
01375 ds_device_iter_next (&iter)) {
01376 d = ds_device_iter_get (&iter);
01377
01381 if (detect_media (d))
01382 break;
01383 }
01384
01385
01386 if (sigio_etc_changed) {
01387
01388 sigio_etc_changed = FALSE;
01389
01390 HAL_INFO (("Directory /etc changed"));
01391
01392 etc_mtab_process_all_block_devices (FALSE);
01393 }
01394
01395 HAL_INFO (("exiting"));
01396
01397 return TRUE;
01398 }
01399
01400
01405 void
01406 linux_class_block_detection_done ()
01407 {
01408 g_timeout_add (2000, media_detect_timer_handler, NULL);
01409
01410 etc_mtab_process_all_block_devices (TRUE);
01411 }
01412
01416 void
01417 linux_class_block_shutdown ()
01418 {
01419
01420 }