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* block_compute_udi(HalDevice* d, int append_num)
00078 {
00079 char* format;
00080 static char buf[256];
00081
00082 if( append_num==-1 )
00083 format = "/org/freedesktop/Hal/devices/block_%d_%d";
00084 else
00085 format = "/org/freedesktop/Hal/devices/block_%d_%d-%d";
00086
00087 snprintf(buf, 256, format,
00088 ds_property_get_int(d, "block.major"),
00089 ds_property_get_int(d, "block.minor"),
00090 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 visit_class_device_block(const char* path,
00108 struct sysfs_class_device* class_device)
00109 {
00110 HalDevice* d;
00111 char* parent_sysfs_path;
00112 char attr_name[SYSFS_NAME_LEN];
00113 struct sysfs_attribute* cur;
00114 dbus_bool_t is_disk = FALSE;
00115 dbus_bool_t not_partition = FALSE;
00116
00117 if( sysfs_get_classdev_attr(class_device, "dev")==NULL )
00118 {
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), cur,
00133 struct sysfs_attribute)
00134 {
00135 if( sysfs_get_name_from_path(cur->path,
00136 attr_name, SYSFS_NAME_LEN) != 0 )
00137 continue;
00138
00139 if( strcmp(attr_name, "dev")==0 )
00140 {
00141 int major, minor;
00142 if( sscanf(cur->value, "%d:%d", &major, &minor)==2 )
00143 {
00144 is_disk = TRUE;
00145 ds_property_set_int(d, "block.major", major);
00146 ds_property_set_int(d, "block.minor", minor);
00147 }
00148 }
00149 else if( strcmp(attr_name, "size")==0 )
00150 {
00151 ds_property_set_int(d, "block.size",
00152 parse_dec(cur->value));
00153 }
00154 else if( strcmp(attr_name, "start")==0 )
00155 {
00156 ds_property_set_int(d, "block.start",
00157 parse_dec(cur->value));
00158 }
00159 else if( strcmp(attr_name, "range")==0 )
00160 {
00161 not_partition = TRUE;
00162 }
00163 }
00164 ds_property_set_bool(d, "block.is_volume", !not_partition);
00165
00167 ds_property_set_int(d, "block.block_size", 512);
00168
00169 if( class_device->sysdevice==NULL )
00170 {
00171
00172
00173
00174
00175
00176
00177
00178 parent_sysfs_path = get_parent_sysfs_path(path);
00179 }
00180 else
00181 {
00182
00183
00184
00185
00186
00187 parent_sysfs_path = class_device->sysdevice->path;
00188 }
00189
00190
00191
00192
00193
00194
00195 ds_device_async_find_by_key_value_string("linux.sysfs_path_device",
00196 parent_sysfs_path,
00197 TRUE,
00198 visit_class_device_block_got_parent,
00199 (void*) d,
00200 NULL,
00201 is_probing ? 0 :
00202 HAL_LINUX_HOTPLUG_TIMEOUT);
00203
00204
00205
00206
00207
00208 }
00209
00217 static void visit_class_device_block_got_parent(HalDevice* parent,
00218 void* data1, void* data2)
00219 {
00220 char* new_udi = NULL;
00221 HalDevice* new_d = NULL;
00222 HalDevice* d = (HalDevice*) data1;
00223
00224 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 ));
00225 HAL_INFO(("d: linux.sysfs_path=%s", ds_property_get_string(d, "linux.sysfs_path")));
00226 HAL_INFO(("d: linux.sysfs_path_device=%s", ds_property_get_string(d, "linux.sysfs_path_device")));
00227
00228 if( parent==NULL )
00229 {
00230 HAL_WARNING(("No parent for block device!"));
00231 ds_device_destroy(d);
00232 return;
00233 }
00234 ds_property_set_string(d, "info.parent", parent->udi);
00235
00236
00237
00238
00239 if( is_probing )
00240 {
00241 int i;
00242 const char* path;
00243 int sysfs_mount_path_len;
00244 char sysfs_path_trunc[SYSFS_NAME_LEN];
00245 char* udev_argv[7] = {"/sbin/udev", "-r", "-q", "name", "-p",
00246 sysfs_path_trunc, NULL};
00247 char* udev_stdout;
00248 char* udev_stderr;
00249 int udev_exitcode;
00250
00251 path = ds_property_get_string(d, "linux.sysfs_path");
00252
00253
00254 sysfs_mount_path_len = strlen(sysfs_mount_path);
00255 if( strlen(path)>sysfs_mount_path_len )
00256 {
00257 strncpy(sysfs_path_trunc, path + sysfs_mount_path_len,
00258 SYSFS_NAME_LEN);
00259 }
00260 HAL_INFO(("*** sysfs_path_trunc = '%s'", sysfs_path_trunc));
00261
00262
00263 if( g_spawn_sync("/",
00264 udev_argv,
00265 NULL,
00266 0,
00267 NULL,
00268 NULL,
00269 &udev_stdout,
00270 &udev_stderr,
00271 &udev_exitcode,
00272 NULL)!=TRUE )
00273 {
00274 HAL_ERROR(("Couldn't invoke /sbin/udev"));
00275 goto error;
00276 }
00277
00278 if( udev_exitcode!=0 )
00279 {
00280 HAL_ERROR(("/sbin/udev returned %d", udev_exitcode));
00281 goto error;
00282 }
00283
00284
00285 for(i=0; udev_stdout[i]!=0; i++)
00286 {
00287 if( udev_stdout[i]=='\r' || udev_stdout[i]=='\n' )
00288 {
00289 udev_stdout[i]=0;
00290 break;
00291 }
00292 }
00293
00294 HAL_INFO(("device file = '%s'", udev_stdout));
00295
00296 ds_property_set_string(d, "block.device", udev_stdout);
00297
00299 }
00300 else
00301 {
00302 error:
00303
00304 if( !ds_property_exists(d, "block.device") )
00305 {
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
00315 find_and_set_physical_device(d);
00316 ds_property_set_bool(d, "info.virtual", TRUE);
00317 ds_add_capability(d, "volume");
00318 ds_property_set_string(d, "info.category", "volume");
00319
00320
00321
00323 ds_property_set_string(d, "info.product", "Volume");
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334 }
00335 else
00336 {
00337 dbus_bool_t removable_media = FALSE;
00338
00339
00340 ds_property_set_bool(d, "storage.cdr", FALSE);
00341 ds_property_set_bool(d, "storage.cdrw", FALSE);
00342 ds_property_set_bool(d, "storage.dvd", FALSE);
00343 ds_property_set_bool(d, "storage.dvdr", FALSE);
00344 ds_property_set_bool(d, "storage.dvdram", FALSE);
00345
00346
00347 ds_property_set_string(d, "info.category", "block");
00348
00349 if( strcmp(ds_property_get_string(parent, "info.bus"), "ide")==0 )
00350 {
00351 const char* ide_name;
00352 char* model;
00353 char* media;
00354
00355 ide_name = get_last_element(
00356 ds_property_get_string(d, "linux.sysfs_path"));
00357
00358 model = read_single_line("/proc/ide/%s/model", ide_name);
00359 if( model!=NULL )
00360 {
00361 ds_property_set_string(d, "storage.model", model);
00362 ds_property_set_string(d, "info.product", model);
00363 }
00364
00365
00366
00367
00368
00369
00370
00375 media = read_single_line("/proc/ide/%s/media", ide_name);
00376 if( media!=NULL )
00377 {
00378 ds_property_set_string(d, "storage.media", media);
00379
00380
00381 if( strcmp(media, "disk")==0 )
00382 {
00383 ds_add_capability(d, "storage");
00384 ds_property_set_string(d, "info.category",
00385 "storage");
00386 }
00387 else if( strcmp(media, "cdrom")==0 )
00388 {
00389 ds_add_capability(d, "storage");
00390 ds_add_capability(d, "storage.removable");
00391 ds_property_set_string(d, "info.category",
00392 "storage.removable");
00393
00394 removable_media = TRUE;
00395 }
00396 else if( strcmp(media, "floppy")==0 )
00397 {
00398 ds_add_capability(d, "storage");
00399 ds_add_capability(d, "storage.removable");
00400 ds_property_set_string(d, "info.category",
00401 "storage.removable");
00402 removable_media = TRUE;
00403 }
00404 else if( strcmp(media, "tape")==0 )
00405 {
00406 ds_add_capability(d, "storage");
00407 ds_add_capability(d, "storage.removable");
00408 ds_property_set_string(d, "info.category",
00409 "storage.removable");
00410 removable_media = TRUE;
00411 }
00412
00413 }
00414
00415 }
00416 else
00417 {
00429 ds_property_set_string(d, "storage.media", "flash");
00430
00431 ds_add_capability(d, "storage");
00432 ds_property_set_string(d, "info.category",
00433 "storage");
00434
00435
00436 ds_property_set_string(d, "info.product", "Disk");
00437
00438 }
00439
00440 ds_property_set_bool(d, "storage.removable", removable_media);
00441
00442
00443
00444
00445
00446
00447
00448 }
00449
00450
00451 etc_mtab_process_all_block_devices(TRUE);
00452
00453 new_udi = rename_and_merge(d, block_compute_udi, "block");
00454 if( new_udi!=NULL )
00455 {
00456 new_d = ds_device_find(new_udi);
00457 if( new_d!=NULL )
00458 {
00459 linux_class_block_check_if_ready_to_add(new_d);
00460 }
00461 }
00462 }
00463
00469 void linux_class_block_check_if_ready_to_add(HalDevice* d)
00470 {
00471 const char* parent;
00472 const char* device_file;
00473
00474
00475
00476
00477
00478
00479
00480 parent = ds_property_get_string(d, "info.parent");
00481 if( parent==NULL )
00482 return;
00483
00484 device_file = ds_property_get_string(d, "block.device");
00485 HAL_INFO(("Entering, udi=%s, device_file=%s", d->udi, device_file));
00486
00487 if( device_file!=NULL && strcmp(device_file, "")!=0 )
00488 {
00489 char* media;
00490
00491
00492
00493
00494 media = ds_property_get_string(d, "storage.media");
00495 if( media!=NULL && strcmp(media, "cdrom")==0 )
00496 {
00497 int fd, capabilities;
00498
00499
00500 fd = open(device_file, O_RDONLY|O_NONBLOCK);
00501
00502 ioctl(fd, CDROM_SET_OPTIONS, CDO_USE_FFLAGS);
00503
00504 if( fd>=0 )
00505 {
00506 capabilities = ioctl (fd, CDROM_GET_CAPABILITY, 0);
00507
00508 if (capabilities >= 0)
00509 {
00510 int read_speed, write_speed;
00511
00512 if (capabilities & CDC_CD_R)
00513 {
00514 ds_add_capability(d, "storage.cdr");
00515 ds_property_set_bool(d, "storage.cdr", TRUE);
00516 }
00517 if (capabilities & CDC_CD_RW)
00518 {
00519 ds_add_capability(d, "storage.cdrw");
00520 ds_property_set_bool(d, "storage.cdrw", TRUE);
00521 }
00522 if (capabilities & CDC_DVD)
00523 {
00524 int profile;
00525
00526 ds_add_capability(d, "storage.dvd");
00527 ds_property_set_bool(d, "storage.dvd", TRUE);
00528
00529 profile = get_dvd_r_rw_profile (fd);
00530 HAL_WARNING (("profile %d\n", profile));
00531 if (profile == 2)
00532 {
00533 ds_add_capability(d, "storage.dvdplusr");
00534 ds_property_set_bool(d, "storage.dvdplusr", TRUE);
00535 ds_add_capability(d, "storage.dvdplusrw");
00536 ds_property_set_bool(d, "storage.dvdplusrw", TRUE);
00537 } else if (profile == 0) {
00538 ds_add_capability(d, "storage.dvdplusr");
00539 ds_property_set_bool(d, "storage.dvdplusr", TRUE);
00540 } else if (profile == 1) {
00541 ds_add_capability(d, "storage.dvdplusrw");
00542 ds_property_set_bool(d, "storage.dvdplusrw", TRUE);
00543 }
00544 }
00545 if (capabilities & CDC_DVD_R)
00546 {
00547 ds_add_capability(d, "storage.dvdr");
00548 ds_property_set_bool(d, "storage.dvdr", TRUE);
00549 }
00550 if (capabilities & CDC_DVD_RAM)
00551 {
00552 ds_add_capability(d, "storage.dvdram");
00553 ds_property_set_bool(d, "storage.dvdram", TRUE);
00554 }
00555
00556
00557 if( ioctl(fd, CDROM_MEDIA_CHANGED)>=0 )
00558 {
00559 ds_property_set_bool(d,
00560 "storage.cdrom.support_media_changed", TRUE);
00561 }
00562
00563 if( get_read_write_speed(fd, &read_speed, &write_speed)>=0)
00564 {
00565 ds_property_set_int(d, "storage.cdrom.read_speed",
00566 read_speed);
00567 if( write_speed>0 )
00568 ds_property_set_int(d, "storage.cdrom.write_speed",
00569 write_speed);
00570 }
00571 }
00572 close (fd);
00573 }
00574 }
00575
00576 if( ds_property_get_bool(d, "block.is_volume") )
00577 {
00578
00579 ds_property_set_string(d, "block.storage_device", parent);
00580 }
00581 else
00582 {
00583
00584
00585
00586
00587
00588 ds_property_set_string(d, "block.storage_device", d->udi);
00589 }
00590
00591
00592 ds_gdl_add(d);
00593
00594
00595 detect_media(d);
00596 }
00597 }
00598
00599
00600
00601 #define MOUNT_POINT_MAX 256
00602 #define MOUNT_POINT_STRING_SIZE 128
00603
00605 struct mount_point_s
00606 {
00607 int major;
00608 int minor;
00609 char device[MOUNT_POINT_STRING_SIZE];
00610 char mount_point[MOUNT_POINT_STRING_SIZE];
00611 char fs_type[MOUNT_POINT_STRING_SIZE];
00612 };
00613
00615 static struct mount_point_s mount_points[MOUNT_POINT_MAX];
00616
00618 static int num_mount_points;
00619
00620 static int etc_fd = -1;
00621
00622
00628 static void etc_mtab_process_line(char* s)
00629 {
00630 int i;
00631 char* p;
00632 char* delim = " \t\n";
00633 char buf[256];
00634 char* bufp = buf;
00635 struct stat stat_buf;
00636 int major = 0;
00637 int minor = 0;
00638 char* device = NULL;
00639 char* mount_point = NULL;
00640 char* fs_type = NULL;
00641
00642 i=0;
00643 p = strtok_r(s, delim, &bufp);
00644 while( p!=NULL )
00645 {
00646
00647 switch(i)
00648 {
00649 case 0:
00650 if( strcmp(p, "none")==0 )
00651 return;
00652 if( p[0]!='/' )
00653 return;
00654 device = p;
00655
00656
00657 if( stat(p, &stat_buf)!=0 )
00658 {
00659 return;
00660 }
00661 major = MAJOR(stat_buf.st_rdev);
00662 minor = MINOR(stat_buf.st_rdev);
00663 break;
00664
00665 case 1:
00666 mount_point = p;
00667 break;
00668
00669 case 2:
00670 fs_type = p;
00671 break;
00672
00673 case 3:
00674 break;
00675
00676 case 4:
00677 break;
00678
00679 case 5:
00680 break;
00681 }
00682
00683 p = strtok_r(NULL, delim, &bufp);
00684 i++;
00685 }
00686
00690 if( num_mount_points==MOUNT_POINT_MAX )
00691 return;
00692
00693 mount_points[num_mount_points].major = major;
00694 mount_points[num_mount_points].minor = minor;
00695 strncpy(mount_points[num_mount_points].device, device,
00696 MOUNT_POINT_STRING_SIZE);
00697 strncpy(mount_points[num_mount_points].mount_point, mount_point,
00698 MOUNT_POINT_STRING_SIZE);
00699 strncpy(mount_points[num_mount_points].fs_type, fs_type,
00700 MOUNT_POINT_STRING_SIZE);
00701
00702 num_mount_points++;
00703 }
00704
00706 static time_t etc_mtab_mtime = 0;
00707
00708
00718 static dbus_bool_t read_etc_mtab(dbus_bool_t force)
00719 {
00720 int fd;
00721 char buf[256];
00722 FILE* f;
00723 struct stat stat_buf;
00724
00725 num_mount_points=0;
00726
00727 fd = open("/etc/mtab", O_RDONLY);
00728
00729 if( fd==-1 )
00730 {
00731 HAL_ERROR(("Cannot open /etc/mtab"));
00732 return FALSE;
00733 }
00734
00735 if( fstat(fd, &stat_buf)!=0 )
00736 {
00737 HAL_ERROR(("Cannot fstat /etc/mtab fd, errno=%d", errno));
00738 return FALSE;
00739 }
00740
00741 if( !force && etc_mtab_mtime==stat_buf.st_mtime )
00742 {
00743
00744 return FALSE;
00745 }
00746
00747 etc_mtab_mtime = stat_buf.st_mtime;
00748
00749
00750
00751 f = fdopen(fd, "r");
00752
00753 if( f==NULL )
00754 {
00755 HAL_ERROR(("Cannot fdopen /etc/mtab fd"));
00756 return FALSE;
00757 }
00758
00759 while( !feof(f) )
00760 {
00761 if( fgets(buf, 256, f)==NULL )
00762 break;
00763
00764 etc_mtab_process_line(buf);
00765 }
00766
00767 fclose(f);
00768
00769 close(fd);
00770
00771 return TRUE;
00772 }
00773
00774 static void sigio_handler(int sig);
00775
00777 static dbus_bool_t have_setup_watcher = FALSE;
00778
00785 static void etc_mtab_process_all_block_devices(dbus_bool_t force)
00786 {
00787 int i;
00788 const char* bus;
00789 HalDevice* d;
00790 int major, minor;
00791 dbus_bool_t found_mount_point;
00792 struct mount_point_s* mp;
00793 HalDeviceIterator diter;
00794
00795
00796 if( !have_setup_watcher )
00797 {
00798 have_setup_watcher = TRUE;
00799
00800 signal(SIGIO, sigio_handler);
00801 etc_fd = open("/etc", O_RDONLY);
00802 fcntl(etc_fd, F_NOTIFY, DN_MODIFY|DN_MULTISHOT);
00803 }
00804
00805
00806 if( !read_etc_mtab(force) )
00807 return;
00808
00809 HAL_INFO(("/etc/mtab changed, processing all block devices"));
00810
00811
00812 for(ds_device_iter_begin(&diter);
00813 ds_device_iter_has_more(&diter);
00814 ds_device_iter_next(&diter))
00815 {
00816
00817 d = ds_device_iter_get(&diter);
00818
00819 bus = ds_property_get_string(d, "info.bus");
00820 if( bus==NULL || strcmp(bus, "block")!=0 ||
00821 !ds_property_get_bool(d, "block.is_volume") )
00822 continue;
00823
00824 major = ds_property_get_int(d, "block.major");
00825 minor = ds_property_get_int(d, "block.minor");
00826
00827
00828 found_mount_point = FALSE;
00829 for(i=0; i<num_mount_points; i++)
00830 {
00831 mp = &mount_points[i];
00832
00833 if( mp->major==major && mp->minor==minor )
00834 {
00835 const char* existing_block_device;
00836 dbus_bool_t was_mounted;
00837
00838 HAL_INFO((
00839 "%s mounted at %s, major:minor=%d:%d, fstype=%s, udi=%s",
00840 mp->device, mp->mount_point, mp->major, mp->minor,
00841 mp->fs_type, d->udi));
00842
00843 property_atomic_update_begin();
00844
00845 existing_block_device = ds_property_get_string(d,
00846 "block.device");
00847
00848 was_mounted = ds_property_get_bool(d, "block.is_mounted");
00849
00850
00851 ds_property_set_string(d, "block.mount_point",mp->mount_point);
00852 ds_property_set_string(d, "block.fstype", mp->fs_type);
00853 ds_property_set_bool(d, "block.is_mounted", TRUE);
00854
00855
00856 if( existing_block_device==NULL ||
00857 (existing_block_device!=NULL &&
00858 strcmp(existing_block_device, "")==0) )
00859 {
00860 ds_property_set_string(d, "block.device", mp->device);
00861 }
00862
00863 property_atomic_update_end();
00864
00865 if( !was_mounted )
00866 {
00867 emit_condition(d, "BlockMountEvent",
00868 DBUS_TYPE_STRING,
00869 ds_property_get_string(d, "block.device"),
00870 DBUS_TYPE_STRING, mp->mount_point,
00871 DBUS_TYPE_STRING, mp->fs_type,
00872 DBUS_TYPE_INVALID);
00873 }
00874
00875 found_mount_point = TRUE;
00876 break;
00877 }
00878 }
00879
00880
00881 if( !found_mount_point )
00882 {
00883 dbus_bool_t was_mounted;
00884
00885 property_atomic_update_begin();
00886
00887 was_mounted = ds_property_get_bool(d, "block.is_mounted");
00888
00889 ds_property_set_bool(d, "block.is_mounted", FALSE);
00890 ds_property_set_string(d, "block.mount_point", "");
00891 ds_property_set_string(d, "block.fstype", "");
00892
00893 property_atomic_update_end();
00894
00895 if( was_mounted )
00896 {
00897 emit_condition(d, "BlockUnmountEvent",
00898 DBUS_TYPE_STRING,
00899 ds_property_get_string(d, "block.device"),
00900 DBUS_TYPE_INVALID);
00901 }
00902
00903 }
00904 }
00905 }
00906
00907
00909 static dbus_bool_t sigio_etc_changed = FALSE;
00910
00915 static void sigio_handler(int sig)
00916 {
00917
00918
00919
00920
00921
00922 sigio_etc_changed = TRUE;
00923 }
00924
00928 void linux_class_block_init()
00929 {
00930 }
00931
00937 static void force_unmount(HalDevice* d)
00938 {
00939 const char* device_file;
00940 const char* device_mount_point;
00941 const char* umount_argv[4] = {"/bin/umount", "-l", NULL, NULL};
00942 char* umount_stdout;
00943 char* umount_stderr;
00944 int umount_exitcode;
00945
00946 device_file = ds_property_get_string(d, "block.device");
00947 device_mount_point = ds_property_get_string(d, "block.mount_point");
00948
00949 umount_argv[2] = device_file;
00950
00951 if( ds_property_exists(d, "block.is_volume") &&
00952 ds_property_get_bool(d, "block.is_volume") &&
00953 device_mount_point!=NULL &&
00954 strlen(device_mount_point)>0 )
00955 {
00956 HAL_INFO(("attempting /bin/umount -l %s", device_file));
00957
00958
00959 if( g_spawn_sync("/",
00960 umount_argv,
00961 NULL,
00962 0,
00963 NULL,
00964 NULL,
00965 &umount_stdout,
00966 &umount_stderr,
00967 &umount_exitcode,
00968 NULL)!=TRUE )
00969 {
00970 HAL_ERROR(("Couldn't invoke /bin/umount"));
00971 }
00972
00973 if( umount_exitcode!=0 )
00974 {
00975 HAL_INFO(("/bin/umount returned %d", umount_exitcode));
00976 }
00977 else
00978 {
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988 HAL_INFO(("Goint to emit BlockForcedUnmountPartition('%s', '%s', TRUE)",
00989 device_file, device_mount_point));
00990 emit_condition(
00991 d, "BlockForcedUnmountPartition",
00992 DBUS_TYPE_STRING, device_file,
00993 DBUS_TYPE_STRING, device_mount_point,
00994 DBUS_TYPE_BOOLEAN, TRUE,
00995 DBUS_TYPE_INVALID);
00996
00997
00998
00999
01000
01001
01002 property_atomic_update_begin();
01003 ds_property_set_string(d, "block.mount_point", "");
01004 ds_property_set_string(d, "block.fstype", "");
01005 ds_property_set_bool(d, "block.is_mounted", FALSE);
01006 property_atomic_update_end();
01007 }
01008 }
01009 }
01010
01016 static void force_unmount_of_all_childs(HalDevice* d)
01017 {
01018 int fd;
01019 int num_childs;
01020 const char* device_file;
01021 HalDevice* child;
01022 HalDevice** childs;
01023
01024 device_file = ds_property_get_string(d, "block.device");
01025
01026 childs = ds_device_find_multiple_by_key_value_string("info.parent",
01027 d->udi,
01028 TRUE,
01029 &num_childs);
01030 if( childs!=NULL )
01031 {
01032 int n;
01033
01034 for(n=0; n<num_childs; n++)
01035 {
01036 child = childs[n];
01037
01038 force_unmount(child);
01039
01040 }
01041
01042 free(childs);
01043
01044 HAL_INFO(("Rereading partition table for %s", device_file));
01045 fd = open(device_file, O_RDONLY|O_NONBLOCK);
01046 if( fd!=-1 )
01047 {
01048 ioctl(fd, BLKRRPART);
01049 }
01050 close(fd);
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061 HAL_INFO(("Goint to emit BlockForcedUnmount('%s')",
01062 device_file));
01063 emit_condition(d, "BlockForcedUnmount",
01064 DBUS_TYPE_STRING, device_file,
01065 DBUS_TYPE_INVALID);
01066
01067 }
01068 }
01069
01070
01071
01076 void linux_class_block_removed(HalDevice* d)
01077 {
01078 if( ds_property_exists(d, "block.is_volume") )
01079 {
01080 if( ds_property_get_bool(d, "block.is_volume") )
01081 {
01082 force_unmount(d);
01083 }
01084 else
01085 {
01086 force_unmount_of_all_childs(d);
01087 }
01088 }
01089 }
01090
01099 static dbus_bool_t detect_media(HalDevice* d)
01100 {
01101 int fd;
01102 dbus_bool_t is_cdrom;
01103 const char* device_file;
01104 HalDevice* child;
01105
01106
01107
01108
01109 if( !d->in_gdl ||
01110 (!ds_property_exists(d, "block.is_volume")) ||
01111 (!ds_property_exists(d, "block.device")) ||
01112 ds_property_get_bool(d, "block.is_volume") )
01113 return FALSE;
01114
01115 device_file = ds_property_get_string(d, "block.device");
01116 if( device_file==NULL )
01117 return FALSE;
01118
01119
01120 is_cdrom = ds_property_exists(d, "storage.media") &&
01121 strcmp(ds_property_get_string(d, "storage.media"), "cdrom")==0 &&
01122 ds_property_get_bool(d, "storage.cdrom.support_media_changed");
01123
01124 if( !is_cdrom )
01125 {
01126 fd = open(device_file, O_RDONLY);
01127
01128 if( fd==-1 )
01129 {
01130
01131 HAL_WARNING(("open(\"%s\", O_RDONLY) failed, "
01132 "errno=%d", device_file, errno));
01133
01134 if( errno==ENOMEDIUM )
01135 {
01136 force_unmount_of_all_childs(d);
01137 }
01138
01139 }
01140
01141 }
01142 else
01143 {
01144 int drive;
01145 dbus_bool_t got_disc = FALSE;
01146
01147 fd = open(device_file, O_RDONLY|O_NONBLOCK|O_EXCL);
01148
01149 if( fd==-1 )
01150 {
01151
01152 HAL_WARNING(("open(\"%s\", O_RDONLY|O_NONBLOCK|O_EXCL) failed, "
01153 "errno=%d", device_file, errno));
01154 return FALSE;
01155 }
01156
01157 drive = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
01158 switch( drive )
01159 {
01160
01161 case CDS_NO_INFO:
01162 case CDS_NO_DISC:
01163 case CDS_TRAY_OPEN:
01164 case CDS_DRIVE_NOT_READY:
01165 break;
01166
01167 case CDS_DISC_OK:
01168 got_disc = TRUE;
01169 break;
01170
01171 default:
01172 break;
01173 }
01174
01175 if( !got_disc )
01176 {
01177
01178 child = ds_device_find_by_key_value_string("info.parent",
01179 d->udi,
01180 TRUE);
01181
01182 if( child!=NULL )
01183 {
01184 HAL_INFO(("Removing volume for optical device %s",
01185 device_file));
01186 ds_device_destroy(child);
01187
01188 close(fd);
01189
01190
01191 return TRUE;
01192 }
01193
01194 close(fd);
01195 return FALSE;
01196 }
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206 close(fd);
01207
01208 child = ds_device_find_by_key_value_string("info.parent",
01209 d->udi,
01210 TRUE);
01211 if( child==NULL )
01212 {
01213 char udi[256];
01214
01215
01216 HAL_INFO(("Adding volume for optical device %s",
01217 device_file));
01218
01219 child = ds_device_new();
01220
01221
01222 ds_device_merge(child, d);
01223
01224
01225 ds_property_set_string(child, "info.parent", d->udi);
01226 ds_property_set_bool(child, "block.is_volume", TRUE);
01227 ds_property_set_string(child, "info.capabilities",
01228 "block volume");
01229 ds_property_set_string(child, "info.category",
01230 "volume");
01231 ds_property_set_string(child, "info.product",
01232 "Disc");
01233
01234
01235 strncpy(udi, ds_property_get_string(d, "info.udi"),
01236 256);
01237 strncat(udi, "-disc", 256);
01238 ds_property_set_string(child, "info.udi", udi);
01239 ds_device_set_udi(child, udi);
01240
01241
01242 ds_gdl_add(child);
01243
01244
01245 return TRUE;
01246 }
01247
01248 }
01249
01250 close(fd);
01251
01252 return FALSE;
01253 }
01254
01260 static gboolean media_detect_timer_handler(gpointer data)
01261 {
01262 int fd;
01263 const char* device_file;
01264 HalDevice* d;
01265 HalDeviceIterator iter;
01266
01267
01268
01269
01270 for(ds_device_iter_begin(&iter);
01271 ds_device_iter_has_more(&iter);
01272 ds_device_iter_next(&iter))
01273 {
01274 d = ds_device_iter_get(&iter);
01275
01279 if( detect_media(d) )
01280 break;
01281 }
01282
01283
01284 if( sigio_etc_changed )
01285 {
01286
01287 sigio_etc_changed = FALSE;
01288
01289 HAL_INFO(("Directory /etc changed"));
01290
01291 etc_mtab_process_all_block_devices(FALSE);
01292 }
01293
01294 HAL_INFO(("exiting"));
01295
01296 return TRUE;
01297 }
01298
01299
01304 void linux_class_block_detection_done()
01305 {
01306 g_timeout_add(2000, media_detect_timer_handler, NULL);
01307
01308 etc_mtab_process_all_block_devices(TRUE);
01309 }
01310
01314 void linux_class_block_shutdown()
01315 {
01316
01317 }
01318