~ubuntu-branches/debian/sid/hal/sid

« back to all changes in this revision

Viewing changes to hald/linux/blockdev.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2007-10-23 12:33:58 UTC
  • Revision ID: james.westby@ubuntu.com-20071023123358-xaf8mjc5n84d5gtz
Tags: upstream-0.5.10
ImportĀ upstreamĀ versionĀ 0.5.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
67
67
        if (hal_device_property_get_bool (d, "block.is_volume")) {
68
68
                const char *label;
69
69
                const char *uuid;
 
70
                char *volumelabel;
70
71
 
71
72
                label = hal_device_property_get_string (d, "volume.label");
 
73
                /* replace '/'  to avoid trouble if the string get part of the UDI see fd.o #11401 */
 
74
                volumelabel = g_strdup(label);
 
75
                volumelabel = g_strdelimit (volumelabel, "/", '_');
 
76
 
72
77
                uuid = hal_device_property_get_string (d, "volume.uuid");
73
78
 
74
79
                if (uuid != NULL && strlen (uuid) > 0) {
75
80
                        hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
76
81
                                              "/org/freedesktop/Hal/devices/volume_uuid_%s", uuid);
77
 
                } else if (label != NULL && strlen (label) > 0) {
 
82
                } else if (volumelabel != NULL && strlen (volumelabel) > 0) {
78
83
                        hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
79
 
                                              "/org/freedesktop/Hal/devices/volume_label_%s", label);
 
84
                                              "/org/freedesktop/Hal/devices/volume_label_%s", volumelabel);
80
85
                } else if (hal_device_property_get_bool(d, "volume.is_disc") &&
81
86
                           hal_device_property_get_bool(d, "volume.disc.is_blank")) {
82
87
                        /* this should be a empty CD/DVD */
90
95
                                              hal_device_property_get_int (d, "volume.partition.number"),
91
96
                                              hal_device_property_get_uint64 (d, "volume.size"));
92
97
                }
 
98
                g_free(volumelabel);
93
99
        } else {
94
100
                const char *model;
95
101
                const char *serial;
165
171
        struct mntent mnt;
166
172
        struct mntent *mnte;
167
173
        char buf[1024];
168
 
        unsigned int major;
169
 
        unsigned int minor;
170
 
        dev_t devt = makedev(0, 0);
171
174
        GSList *volumes = NULL;
172
175
        GSList *volume;
173
176
 
174
177
        /* open /proc/mounts */
175
 
        g_snprintf (buf, sizeof (buf), "%s/mounts", get_hal_proc_path ());
 
178
        g_snprintf (buf, sizeof (buf), "%s/mounts", "/proc");
176
179
        if ((f = setmntent (buf, "r")) == NULL) {
177
180
                HAL_ERROR (("Could not open /proc/mounts"));
178
181
                return;
189
192
        /* loop over /proc/mounts */
190
193
        while ((mnte = getmntent_r (f, &mnt, buf, sizeof(buf))) != NULL) {
191
194
                struct stat statbuf;
192
 
                gboolean use_device_name_for_match;
193
 
 
194
 
                /*HAL_INFO ((" * /proc/mounts contain dev %s - type %s", mnt.mnt_fsname, mnt.mnt_type));*/
195
 
 
196
 
                /* If this is a nfs mount (fstype == 'nfs') ignore the mount. Reason:
197
 
                 *  1. we don't list nfs devices in HAL
198
 
                 *  2. more problematic: stat on mountpoints with 'stale nfs handle' never come
199
 
                 *     back and block complete HAL and all applications using HAL fail.
 
195
                dev_t devt;
 
196
 
 
197
                /* HAL_INFO ((" * /proc/mounts contain dev %s - type %s", mnt.mnt_fsname, mnt.mnt_type)); */
 
198
 
 
199
                /* We don't handle nfs mounts in HAL and stat() on mountpoints,
 
200
                 * and we would block on 'stale nfs handle'.
200
201
                 */
201
202
                if (strcmp(mnt.mnt_type, "nfs") == 0)
202
203
                        continue;
203
204
 
204
 
                use_device_name_for_match = FALSE;
205
 
                /* get major:minor of special device file */
206
 
                if (stat (mnt.mnt_fsname, &statbuf) != 0) {
207
 
                        /* DING DING DING... device node may have been deleted by udev 
208
 
                         * but device is still mounted and we haven't processed the uevent
209
 
                         * for that deletion from udev.. 
210
 
                         * 
211
 
                         * So in this case... fall back to comparing on device names 
212
 
                         * rather than pretending the device is not mounted as that's
213
 
                         * what will happen if we just skip this /proc/mounts entry.
214
 
                         *
215
 
                         * The reason it's nicer to compare on major:minor is that
216
 
                         * /proc/mounts is broken - it contains the *device name*
217
 
                         * passed to mount(2) which in some cases may be a symlink
218
 
                         * (on many distros it's common to see /proc/mounts contain
219
 
                         * /dev/root as the device for /). Sigh...
220
 
                         */
221
 
                        use_device_name_for_match = TRUE;
222
 
                } else {
 
205
                /* skip plain names, we look for device nodes */
 
206
                if (mnt.mnt_fsname[0] != '/')
 
207
                        continue;
 
208
 
 
209
                /*
 
210
                 * We can't just stat() the mountpoint, because it breaks all sorts
 
211
                 * non-disk filesystems. So assume, that the names in /proc/mounts
 
212
                 * are existing device-files used to mount the filesystem.
 
213
                 */
 
214
                devt = makedev(0, 0);
 
215
                if (stat (mnt.mnt_fsname, &statbuf) == 0) {
 
216
                        /* not a device node */
223
217
                        if (major (statbuf.st_rdev) == 0)
224
218
                                continue;
 
219
 
 
220
                        /* found major/minor */
 
221
                        devt = statbuf.st_rdev;
 
222
                } else {
 
223
                        /* The root filesystem may be mounted by a device name that doesn't
 
224
                         * exist in the real root, like /dev/root, which the kernel uses
 
225
                         * internally, when no initramfs image is used. For "/", it is safe
 
226
                         * to get the major/minor by stat()'ing the mount-point.
 
227
                         */
 
228
                        if (strcmp (mnt.mnt_dir, "/") == 0 && stat ("/", &statbuf) == 0)
 
229
                                devt = statbuf.st_dev;
 
230
 
 
231
                        /* DING DING DING... the device-node may not exist, or is
 
232
                         * already deleted, but the device may be still mounted.
 
233
                         *
 
234
                         * We will fall back to looking up the device-name, instead
 
235
                         * of using major/minor.
 
236
                         */
225
237
                }
226
238
 
227
 
                /*HAL_INFO (("* found mounts dev %s (%i:%i)", mnt.mnt_fsname, major (statbuf.st_rdev), minor (statbuf.st_rdev)));*/
228
 
                /* match against all hal volumes */
 
239
                /* HAL_INFO (("* found mounts dev %s (%i:%i)", mnt.mnt_fsname,
 
240
                           major (devt), minor (devt))); */
 
241
 
229
242
                for (volume = volumes; volume != NULL; volume = g_slist_next (volume)) {
230
243
                        HalDevice *dev;
231
244
                        gboolean is_match;
233
246
                        is_match = FALSE;
234
247
                        dev = HAL_DEVICE (volume->data);
235
248
 
236
 
                        if (use_device_name_for_match) {
 
249
                        /* lookup dev_t or devname of known hal devices */
 
250
                        if (major (devt) == 0) {
237
251
                                const char *device_name;
238
252
 
239
253
                                device_name = hal_device_property_get_string (dev, "block.device");
243
257
                                if (strcmp (device_name, mnt.mnt_fsname) == 0)
244
258
                                        is_match = TRUE;
245
259
                        } else {
246
 
                                major = hal_device_property_get_int (dev, "block.major");
247
 
                                if (major == 0)
 
260
                                unsigned int majornum;
 
261
                                unsigned int minornum;
 
262
 
 
263
                                majornum = hal_device_property_get_int (dev, "block.major");
 
264
                                if (majornum == 0)
248
265
                                        continue;
249
 
                                minor = hal_device_property_get_int (dev, "block.minor");
250
 
                                devt = makedev (major, minor);
251
 
                                /*HAL_INFO (("  match %s (%i:%i)", hal_device_get_udi (dev), major, minor));*/
 
266
                                minornum = hal_device_property_get_int (dev, "block.minor");
 
267
                                /* HAL_INFO (("  match %s (%i:%i)", hal_device_get_udi (dev), majornum, minornum)); */
252
268
 
253
 
                                if (statbuf.st_rdev == devt)
 
269
                                if (majornum == major (devt) && minornum == minor (devt))
254
270
                                        is_match = TRUE;
255
271
                        }
256
272
 
262
278
                                                              hasmntopt (&mnt, MNTOPT_RO) ? TRUE : FALSE);
263
279
                                hal_device_property_set_string (dev, "volume.mount_point", mnt.mnt_dir);
264
280
                                device_property_atomic_update_end ();
265
 
                                /*HAL_INFO (("  set %s to be mounted at %s (%s)",
266
 
                                  hal_device_get_udi (dev), mnt.mnt_dir,
267
 
                                           hasmntopt (&mnt, MNTOPT_RO) ? "ro" : "rw"));*/
 
281
                                /* HAL_INFO (("  set %s to be mounted at %s (%s)", hal_device_get_udi (dev),
 
282
                                           mnt.mnt_dir, hasmntopt (&mnt, MNTOPT_RO) ? "ro" : "rw")); */
268
283
                                volumes = g_slist_delete_link (volumes, volume);
269
284
                                break;
270
285
                        }
626
641
        return f;
627
642
}
628
643
 
 
644
static gboolean
 
645
refresh_md_state (HalDevice *d);
 
646
 
 
647
static gboolean
 
648
md_check_sync_timeout (gpointer user_data)
 
649
{
 
650
        HalDevice *d;
 
651
        char *sysfs_path = (char *) user_data;
 
652
 
 
653
        HAL_INFO (("In md_check_sync_timeout for sysfs path %s", sysfs_path));
 
654
 
 
655
        d = hal_device_store_match_key_value_string (hald_get_gdl (), 
 
656
                                                     "storage.linux_raid.sysfs_path", 
 
657
                                                     sysfs_path);
 
658
        if (d == NULL)
 
659
                d = hal_device_store_match_key_value_string (hald_get_tdl (), 
 
660
                                                             "storage.linux_raid.sysfs_path", 
 
661
                                                             sysfs_path);
 
662
        if (d == NULL) {
 
663
                HAL_WARNING (("Cannot find md device with sysfs path '%s'", sysfs_path));
 
664
                goto out;
 
665
        }
 
666
 
 
667
        refresh_md_state (d);
 
668
        
 
669
out:
 
670
        g_free (sysfs_path);
 
671
        return FALSE;
 
672
}
 
673
 
 
674
static gboolean
 
675
refresh_md_state (HalDevice *d)
 
676
{
 
677
        int n;
 
678
        char *sync_action;
 
679
        int num_components;
 
680
        gboolean ret;
 
681
        const char *sysfs_path;
 
682
 
 
683
        ret = FALSE;
 
684
 
 
685
        sysfs_path = hal_device_property_get_string (d, "storage.linux_raid.sysfs_path");
 
686
        if (sysfs_path == NULL) {
 
687
                HAL_WARNING (("Cannot get sysfs_path for udi %s", hal_device_get_udi (d)));
 
688
                goto error;
 
689
        }
 
690
 
 
691
        HAL_INFO (("In refresh_md_state() for '%s'", sysfs_path));
 
692
 
 
693
        sync_action = hal_util_get_string_from_file (sysfs_path, "md/sync_action");
 
694
        if (sync_action == NULL) {
 
695
                HAL_WARNING (("Cannot get sync_action for %s", sysfs_path));
 
696
                goto error;
 
697
        }
 
698
        if (strcmp (sync_action, "idle") == 0) {
 
699
                hal_device_property_set_bool (d, "storage.linux_raid.is_syncing", FALSE);
 
700
                hal_device_property_remove (d, "storage.linux_raid.sync.action");
 
701
                hal_device_property_remove (d, "storage.linux_raid.sync.speed");
 
702
                hal_device_property_remove (d, "storage.linux_raid.sync.progress");
 
703
        } else {
 
704
                int speed;
 
705
                char *str_completed;
 
706
 
 
707
                hal_device_property_set_bool (d, "storage.linux_raid.is_syncing", TRUE);
 
708
 
 
709
                hal_device_property_set_string (d, "storage.linux_raid.sync.action", sync_action);
 
710
 
 
711
                if (!hal_util_get_int_from_file (sysfs_path, "md/sync_speed", &speed, 10)) {
 
712
                        HAL_WARNING (("Cannot get sync_speed for %s", sysfs_path));
 
713
                } else {
 
714
                        hal_device_property_set_uint64 (d, "storage.linux_raid.sync.speed", speed);
 
715
                }
 
716
 
 
717
 
 
718
                if ((str_completed = hal_util_get_string_from_file (sysfs_path, "md/sync_completed")) == NULL) {
 
719
                        HAL_WARNING (("Cannot get sync_completed for %s", sysfs_path));
 
720
                } else {
 
721
                        long long int sync_pos, sync_total;
 
722
 
 
723
                        if (sscanf (str_completed, "%lld / %lld", &sync_pos, &sync_total) != 2) {
 
724
                                HAL_WARNING (("Malformed sync_completed '%s'", str_completed));
 
725
                        } else {
 
726
                                double sync_progress;
 
727
                                sync_progress = ((double) sync_pos) / ((double) sync_total);
 
728
                                hal_device_property_set_double (d, "storage.linux_raid.sync.progress", sync_progress);
 
729
                        }
 
730
                }
 
731
 
 
732
                /* check again in two seconds */
 
733
                g_timeout_add (2000, md_check_sync_timeout, g_strdup (sysfs_path));
 
734
        }
 
735
        
 
736
        if (!hal_util_get_int_from_file (sysfs_path, "md/raid_disks", &num_components, 0)) {
 
737
                HAL_WARNING (("Cannot get number of RAID components"));
 
738
                goto error;
 
739
        }
 
740
        hal_device_property_set_int (d, "storage.linux_raid.num_components", num_components);
 
741
        
 
742
        /* add all components */
 
743
        for (n = 0; n < num_components; n++) {
 
744
                char *s;
 
745
                char *link;
 
746
                char *target;
 
747
                HalDevice *slave_volume;
 
748
                const char *slave_volume_stordev_udi;
 
749
                HalDevice *slave_volume_stordev;
 
750
 
 
751
                s = g_strdup_printf ("%s/md/rd%d", sysfs_path, n);
 
752
                if (!g_file_test (s, G_FILE_TEST_IS_SYMLINK)) {
 
753
                        g_free (s);
 
754
                        break;
 
755
                }
 
756
                g_free (s);
 
757
                
 
758
                link = g_strdup_printf ("%s/md/rd%d/block", sysfs_path, n);
 
759
                target = resolve_symlink (link);
 
760
                if (target == NULL) {
 
761
                        HAL_WARNING (("Cannot resolve %s", link));
 
762
                        g_free (link);
 
763
                        goto error;
 
764
                }
 
765
                HAL_INFO (("link->target: '%s' -> '%s'", link, target));
 
766
                
 
767
                slave_volume = hal_device_store_match_key_value_string (hald_get_gdl (), "linux.sysfs_path", target);
 
768
                if (slave_volume == NULL) {
 
769
                        HAL_WARNING (("No volume for sysfs path %s", target));
 
770
                        g_free (target);
 
771
                        g_free (link);
 
772
                        goto error;
 
773
                }
 
774
                
 
775
                
 
776
                slave_volume_stordev_udi = hal_device_property_get_string (slave_volume, "block.storage_device");
 
777
                if (slave_volume_stordev_udi == NULL) {
 
778
                        HAL_WARNING (("No storage device for slave"));
 
779
                        g_free (target);
 
780
                        g_free (link);
 
781
                        goto error;
 
782
                }
 
783
                slave_volume_stordev = hal_device_store_find (hald_get_gdl (), slave_volume_stordev_udi);
 
784
                if (slave_volume_stordev == NULL) {
 
785
                        HAL_WARNING (("No storage device for slave"));
 
786
                        g_free (target);
 
787
                        g_free (link);
 
788
                        goto error;
 
789
                }
 
790
                
 
791
                
 
792
                hal_device_property_strlist_add (d, "storage.linux_raid.components", hal_device_get_udi (slave_volume));
 
793
                
 
794
                /* derive 
 
795
                 *
 
796
                 * - hotpluggability (is that a word?) 
 
797
                 * - array uuid
 
798
                 *
 
799
                 * Hmm.. every raid member (PV) get the array UUID. That's
 
800
                 * probably.. wrong. TODO: check with Kay.
 
801
                 *
 
802
                 * from component 0.
 
803
                 */
 
804
                if (n == 0) {
 
805
                        const char *uuid;
 
806
 
 
807
                        hal_device_property_set_bool (
 
808
                                d, "storage.hotpluggable",
 
809
                                hal_device_property_get_bool (slave_volume_stordev, "storage.hotpluggable"));
 
810
 
 
811
                        
 
812
                        uuid = hal_device_property_get_string (
 
813
                                slave_volume, "volume.uuid");
 
814
                        if (uuid != NULL) {
 
815
                                hal_device_property_set_string (
 
816
                                        d, "storage.serial", uuid);
 
817
                        }
 
818
                }
 
819
                
 
820
                g_free (target);
 
821
                g_free (link);
 
822
                
 
823
        } /* for all components */
 
824
 
 
825
        hal_device_property_set_int (d, "storage.linux_raid.num_components_active", n);
 
826
        
 
827
        /* TODO: add more state here */
 
828
 
 
829
        ret = TRUE;
 
830
 
 
831
error:
 
832
        return ret;
 
833
}
 
834
 
 
835
 
629
836
void
630
837
hotplug_event_begin_add_blockdev (const gchar *sysfs_path, const gchar *device_file, gboolean is_partition,
631
838
                                  HalDevice *parent, void *end_token)
638
845
        char *sysfs_path_real = NULL;
639
846
        int floppy_num;
640
847
        gboolean is_device_mapper;
 
848
        gboolean is_md_device;
 
849
        int md_number;
641
850
 
642
851
        is_device_mapper = FALSE;
 
852
        is_fakevolume = FALSE;
 
853
        is_md_device = FALSE;
643
854
 
644
855
        HAL_INFO (("block_add: sysfs_path=%s dev=%s is_part=%d, parent=0x%08x", 
645
856
                   sysfs_path, device_file, is_partition, parent));
650
861
        }
651
862
 
652
863
        if (strcmp (hal_util_get_last_element (sysfs_path), "fakevolume") == 0) {
 
864
                HAL_INFO (("Handling %s as fakevolume - sysfs_path_real=%s", device_file, sysfs_path_real));
653
865
                is_fakevolume = TRUE;
654
866
                sysfs_path_real = hal_util_get_parent_path (sysfs_path);
655
 
                HAL_INFO (("Handling %s as fakevolume - sysfs_path_real=%s", device_file, sysfs_path_real));
 
867
        } else if (sscanf (hal_util_get_last_element (sysfs_path), "md%d", &md_number) == 1) {
 
868
                HAL_INFO (("Handling %s as MD device", device_file));
 
869
                is_md_device = TRUE;
 
870
                sysfs_path_real = g_strdup (sysfs_path);
 
871
                /* set parent to root computer device object */
 
872
                parent = hal_device_store_find (hald_get_gdl (), "/org/freedesktop/Hal/devices/computer");
 
873
                if (parent == NULL)
 
874
                        d = hal_device_store_find (hald_get_tdl (), "/org/freedesktop/Hal/devices/computer");
656
875
        } else {
657
 
                is_fakevolume = FALSE;
658
876
                sysfs_path_real = g_strdup (sysfs_path);
659
877
        }
660
878
        
670
888
        d = hal_device_new ();
671
889
 
672
890
        /* OK, no parent... it might a device-mapper device => check slaves/ subdir in sysfs */
673
 
        if (parent == NULL && !is_partition && !is_fakevolume) {
 
891
        if (parent == NULL && !is_partition && !is_fakevolume && !hotplug_event->reposted) {
674
892
                DIR * dir;
675
893
                struct dirent *dp;
676
894
                char path[HAL_PATH_MAX];
677
895
 
678
896
                g_snprintf (path, HAL_PATH_MAX, "%s/slaves", sysfs_path);
679
 
                HAL_INFO (("Looking in %s", path));
 
897
                HAL_INFO (("Looking in %s for Device Mapper", path));
680
898
 
681
899
                if ((dir = opendir (path)) == NULL) {
682
900
                        HAL_WARNING (("Unable to open %s: %s", path, strerror(errno)));
725
943
                        closedir(dir);
726
944
                        HAL_INFO (("Done looking in %s", path));
727
945
                }
728
 
                
 
946
 
729
947
        }
730
948
 
731
949
        if (parent == NULL) {
856
1074
                                }
857
1075
                        }
858
1076
 
 
1077
                        if (strcmp (udi_it, "/org/freedesktop/Hal/devices/computer") == 0) {
 
1078
                                        physdev = d_it;
 
1079
                                        physdev_udi = udi_it;
 
1080
                                        if (is_md_device) {
 
1081
                                                char *level;
 
1082
                                                char *model_name;
 
1083
 
 
1084
                                                hal_device_property_set_string (d, "storage.bus", "linux_raid");
 
1085
 
 
1086
                                                level = hal_util_get_string_from_file (sysfs_path_real, "md/level");
 
1087
                                                if (level == NULL)
 
1088
                                                        goto error;
 
1089
                                                hal_device_property_set_string (d, "storage.linux_raid.level", level);
 
1090
 
 
1091
                                                hal_device_property_set_string (d, "storage.linux_raid.sysfs_path", sysfs_path_real);
 
1092
 
 
1093
                                                hal_device_property_set_string (d, "storage.vendor", "Linux");
 
1094
                                                if (strcmp (level, "linear") == 0) {
 
1095
                                                        model_name = g_strdup ("Software RAID (Linear)");
 
1096
                                                } else if (strcmp (level, "raid0") == 0) {
 
1097
                                                        model_name = g_strdup ("Software RAID-0 (Stripe)");
 
1098
                                                } else if (strcmp (level, "raid1") == 0) {
 
1099
                                                        model_name = g_strdup ("Software RAID-1 (Mirror)");
 
1100
                                                } else if (strcmp (level, "raid5") == 0) {
 
1101
                                                        model_name = g_strdup ("Software RAID-5");
 
1102
                                                } else {
 
1103
                                                        model_name = g_strdup_printf ("Software RAID (%s)", level);
 
1104
                                                }
 
1105
                                                hal_device_property_set_string (d, "storage.model", model_name);
 
1106
                                                g_free (model_name);
 
1107
 
 
1108
                                                hal_util_set_string_from_file (
 
1109
                                                        d, "storage.firmware_version", 
 
1110
                                                        sysfs_path_real, "md/metadata_version");
 
1111
                                                
 
1112
                                                hal_device_add_capability (d, "storage.linux_raid");
 
1113
 
 
1114
                                                if (!refresh_md_state (d))
 
1115
                                                        goto error;
 
1116
 
 
1117
                                                is_hotpluggable = hal_device_property_get_bool (
 
1118
                                                        d, "storage.hotpluggable");
 
1119
 
 
1120
                                        }
 
1121
                                        break;
 
1122
                        }
 
1123
 
859
1124
                        /* Check info.subsystem */
860
1125
                        if ((bus = hal_device_property_get_string (d_it, "info.subsystem")) != NULL) {
861
1126
                                if (strcmp (bus, "scsi") == 0) {
918
1183
                hal_device_property_set_string (d, "storage.originating_device", physdev_udi);
919
1184
                hal_device_property_set_string (d, "storage.physical_device", physdev_udi);
920
1185
 
921
 
                if (!hal_util_get_int_from_file (sysfs_path, "removable", (gint *) &is_removable, 10)) {
 
1186
                if (!hal_util_get_int_from_file (sysfs_path_real, "removable", (gint *) &is_removable, 10)) {
922
1187
                        HAL_WARNING (("Cannot get 'removable' file"));
923
 
                        goto error;
 
1188
                        is_removable = FALSE;
924
1189
                }
925
1190
 
926
1191
                hal_device_property_set_bool (d, "storage.removable.media_available", FALSE);
928
1193
                /* set storage.size only if we have fixed media */
929
1194
                if (!is_removable) {
930
1195
                        guint64 num_blocks;
931
 
                        if (hal_util_get_uint64_from_file (sysfs_path, "size", &num_blocks, 0)) {
 
1196
                        if (hal_util_get_uint64_from_file (sysfs_path_real, "size", &num_blocks, 0)) {
932
1197
                                /* TODO: sane to assume this is always 512 for non-removable? 
933
1198
                                 * I think genhd.c guarantees this... */
934
1199
                                hal_device_property_set_uint64 (d, "storage.size", num_blocks * 512);
937
1202
                        hal_device_property_set_uint64 (d, "storage.size", 0);
938
1203
                }
939
1204
 
 
1205
                if (is_removable) {
 
1206
                        int sysfs_capability;
 
1207
                        gboolean support_an;
 
1208
 
 
1209
                        support_an = 
 
1210
                                hal_util_get_int_from_file (sysfs_path, "capability", &sysfs_capability, 16) &&
 
1211
                                (sysfs_capability&4) != 0;
 
1212
                        
 
1213
                        hal_device_property_set_bool (d, "storage.removable.support_async_notification", support_an);
 
1214
                }
 
1215
 
940
1216
                /* by default, do checks for media if, and only if, the removable file is set to 1
941
1217
                 *
942
1218
                 * Problematic buses, like IDE, may override this.
955
1231
                        char buf[256];
956
1232
                        gchar *media;
957
1233
                        gchar *model;
 
1234
                        struct stat st;
958
1235
 
959
1236
                        /* Be conservative and don't poll IDE drives at all (except CD-ROM's, see below) */
960
1237
                        hal_device_property_set_bool (d, "storage.media_check_enabled", FALSE);
963
1240
                         *
964
1241
                         * "disk", "cdrom", "tape", "floppy", "UNKNOWN"
965
1242
                         */
966
 
                        snprintf (buf, sizeof (buf), "%s/ide/%s", get_hal_proc_path (), hal_util_get_last_element (sysfs_path));
 
1243
                        snprintf (buf, sizeof (buf), "/proc/ide/%s", hal_util_get_last_element (sysfs_path_real));
 
1244
                        if (stat(buf, &st)) {
 
1245
                                /*
 
1246
                                 * /proc/ide does not exist; try with sysfs
 
1247
                                 */
 
1248
                                snprintf (buf, sizeof (buf), "%s/%s", sysfs_path_real, "device");
 
1249
                        }
967
1250
                        if ((media = hal_util_get_string_from_file (buf, "media")) != NULL) {
968
1251
                                if (strcmp (media, "disk") == 0 ||
969
1252
                                    strcmp (media, "cdrom") == 0 ||
1152
1435
        if (d != NULL)
1153
1436
                g_object_unref (d);
1154
1437
out:
1155
 
        hotplug_event_end (end_token);
 
1438
        hotplug_event_end (end_token);
1156
1439
        g_free (sysfs_path_real);
 
1440
        return;
1157
1441
}
1158
1442
 
 
1443
 
1159
1444
static void
1160
1445
force_unmount_cb (HalDevice *d, guint32 exit_type, 
1161
1446
                  gint return_code, gchar **error,
1272
1557
        ;
1273
1558
}
1274
1559
 
 
1560
void 
 
1561
hotplug_event_refresh_blockdev (gchar *sysfs_path, HalDevice *d, void *end_token)
 
1562
{
 
1563
        HAL_INFO (("block_change: sysfs_path=%s", sysfs_path));
 
1564
 
 
1565
        if (hal_device_property_get_bool (d, "storage.removable.support_async_notification")) {
 
1566
                blockdev_rescan_device (d);
 
1567
        }
 
1568
 
 
1569
        /* done with change event */
 
1570
        hotplug_event_end (end_token);
 
1571
}
 
1572
 
 
1573
 
1275
1574
static void 
1276
1575
block_rescan_storage_done (HalDevice *d, guint32 exit_type, 
1277
1576
                           gint return_code, gchar **error,
1325
1624
 
1326
1625
        ret = FALSE;
1327
1626
 
1328
 
        HAL_INFO (("Entering, udi=%s", hal_device_get_udi (d)));
 
1627
        HAL_INFO (("blockdev_rescan_device: udi=%s", hal_device_get_udi (d)));
1329
1628
 
1330
1629
        /* This only makes sense on storage devices */
1331
1630
        if (hal_device_property_get_bool (d, "block.is_volume")) {
1403
1702
 
1404
1703
        return hotplug_event;
1405
1704
}
 
1705
 
 
1706
static GSList *md_devs = NULL;
 
1707
 
 
1708
static char *
 
1709
udev_get_device_file_for_sysfs_path (const char *sysfs_path)
 
1710
{
 
1711
        char *ret;
 
1712
        char *u_stdout;
 
1713
        int u_exit_status;
 
1714
        const char *argv[] = {"/usr/bin/udevinfo", "--root", "--query", "name", "--path", NULL, NULL};
 
1715
        GError *g_error;
 
1716
 
 
1717
        ret = NULL;
 
1718
        argv[5] = sysfs_path;
 
1719
 
 
1720
        g_error = NULL;
 
1721
 
 
1722
        if (!g_spawn_sync("/", 
 
1723
                          (char **) argv, 
 
1724
                          NULL,           /* envp */
 
1725
                          0,              /* flags */
 
1726
                          NULL,           /* child_setup */
 
1727
                          NULL,           /* user_data */
 
1728
                          &u_stdout,
 
1729
                          NULL,           /* stderr */
 
1730
                          &u_exit_status,
 
1731
                          &g_error)) {
 
1732
                HAL_ERROR (("Error spawning udevinfo: %s", g_error->message));
 
1733
                g_error_free (g_error);
 
1734
                goto out;
 
1735
        }
 
1736
 
 
1737
        if (u_exit_status != 0) {
 
1738
                HAL_ERROR (("udevinfo returned exit code %d", u_exit_status));
 
1739
                g_free (u_stdout);
 
1740
                goto out;
 
1741
        }
 
1742
 
 
1743
        ret = u_stdout;
 
1744
        g_strchomp (ret);
 
1745
        HAL_INFO (("Got '%s'", ret));
 
1746
 
 
1747
out:
 
1748
        return ret;
 
1749
}
 
1750
 
 
1751
 
 
1752
void 
 
1753
blockdev_process_mdstat (void)
 
1754
{
 
1755
        HotplugEvent *hotplug_event;
 
1756
        GIOChannel *channel;
 
1757
        GSList *read_md_devs;
 
1758
        GSList *i;
 
1759
        GSList *j;
 
1760
        GSList *k;
 
1761
 
 
1762
        channel = get_mdstat_channel ();
 
1763
        if (channel == NULL)
 
1764
                goto error;
 
1765
 
 
1766
        if (g_io_channel_seek (channel, 0, G_SEEK_SET) != G_IO_ERROR_NONE) {
 
1767
                HAL_ERROR (("Cannot seek in /proc/mdstat"));
 
1768
                goto error;
 
1769
        }
 
1770
 
 
1771
        read_md_devs = NULL;
 
1772
        while (TRUE) {
 
1773
                int num;
 
1774
                char *line;
 
1775
 
 
1776
                if (g_io_channel_read_line (channel, &line, NULL, NULL, NULL) != G_IO_STATUS_NORMAL)
 
1777
                        break;
 
1778
 
 
1779
                if (sscanf (line, "md%d : ", &num) == 1) {
 
1780
                        char *sysfs_path;
 
1781
                        sysfs_path = g_strdup_printf ("/sys/block/md%d", num);
 
1782
                        read_md_devs = g_slist_prepend (read_md_devs, sysfs_path);
 
1783
                }
 
1784
 
 
1785
                g_free (line);
 
1786
        }
 
1787
 
 
1788
        /* now compute the delta */
 
1789
 
 
1790
        /* add devices */
 
1791
        for (i = read_md_devs; i != NULL; i = i->next) {
 
1792
                gboolean should_add = TRUE;
 
1793
 
 
1794
                for (j = md_devs; j != NULL && should_add; j = j->next) {
 
1795
                        if (strcmp (i->data, j->data) == 0) {
 
1796
                                should_add = FALSE;
 
1797
                        }
 
1798
                }
 
1799
 
 
1800
                if (should_add) {
 
1801
                        char *sysfs_path = i->data;
 
1802
                        char *device_file;
 
1803
                        int num_tries;
 
1804
 
 
1805
                        num_tries = 0;
 
1806
                retry_add:
 
1807
                        device_file = udev_get_device_file_for_sysfs_path (sysfs_path);
 
1808
                        if (device_file == NULL) {
 
1809
                                if (num_tries <= 6) {
 
1810
                                        int num_ms;
 
1811
                                        num_ms = 10 * (1<<num_tries);
 
1812
                                        HAL_INFO (("spinning %d ms waiting for device file for sysfs path %s", 
 
1813
                                                   num_ms, sysfs_path));
 
1814
                                        usleep (1000 * num_ms);
 
1815
                                        num_tries++;
 
1816
                                        goto retry_add;
 
1817
                                } else {
 
1818
                                        HAL_ERROR (("Cannot get device file for sysfs path %s", sysfs_path));
 
1819
                                }
 
1820
                        } else {
 
1821
                                HAL_INFO (("Adding md device at '%s' ('%s')", sysfs_path, device_file));
 
1822
 
 
1823
                                hotplug_event = g_new0 (HotplugEvent, 1);
 
1824
                                hotplug_event->action = HOTPLUG_ACTION_ADD;
 
1825
                                hotplug_event->type = HOTPLUG_EVENT_SYSFS_BLOCK;
 
1826
                                g_strlcpy (hotplug_event->sysfs.subsystem, "block", sizeof (hotplug_event->sysfs.subsystem));
 
1827
                                g_strlcpy (hotplug_event->sysfs.sysfs_path, sysfs_path, sizeof (hotplug_event->sysfs.sysfs_path));
 
1828
                                g_strlcpy (hotplug_event->sysfs.device_file, device_file, sizeof (hotplug_event->sysfs.device_file));
 
1829
                                hotplug_event->sysfs.net_ifindex = -1;
 
1830
                                hotplug_event_enqueue (hotplug_event);
 
1831
                                
 
1832
                                md_devs = g_slist_prepend (md_devs, g_strdup (sysfs_path));
 
1833
 
 
1834
                                g_free (device_file);
 
1835
                        }
 
1836
 
 
1837
                }
 
1838
        }
 
1839
 
 
1840
        /* remove devices */
 
1841
        for (i = md_devs; i != NULL; i = k) {
 
1842
                gboolean should_remove = TRUE;
 
1843
 
 
1844
                k = i->next;
 
1845
 
 
1846
                for (j = read_md_devs; j != NULL && should_remove; j = j->next) {
 
1847
                        if (strcmp (i->data, j->data) == 0) {
 
1848
                                should_remove = FALSE;
 
1849
                        }
 
1850
                }
 
1851
 
 
1852
                if (should_remove) {
 
1853
                        char *sysfs_path = i->data;
 
1854
                        char *device_file;
 
1855
                        int num_tries;
 
1856
                        
 
1857
                        num_tries = 0;
 
1858
                retry_rem:
 
1859
                        device_file = udev_get_device_file_for_sysfs_path (sysfs_path);
 
1860
                        if (device_file == NULL) {
 
1861
                                if (num_tries <= 6) {
 
1862
                                        int num_ms;
 
1863
                                        num_ms = 10 * (1<<num_tries);
 
1864
                                        HAL_INFO (("spinning %d ms waiting for device file for sysfs path %s", 
 
1865
                                                   num_ms, sysfs_path));
 
1866
                                        usleep (1000 * num_ms);
 
1867
                                        num_tries++;
 
1868
                                        goto retry_rem;
 
1869
                                } else {
 
1870
                                        HAL_ERROR (("Cannot get device file for sysfs path %s", sysfs_path));
 
1871
                                }
 
1872
                        } else {
 
1873
                                
 
1874
                                HAL_INFO (("Removing md device at '%s' ('%s')", sysfs_path, device_file));
 
1875
 
 
1876
                                hotplug_event = g_new0 (HotplugEvent, 1);
 
1877
                                hotplug_event->action = HOTPLUG_ACTION_REMOVE;
 
1878
                                hotplug_event->type = HOTPLUG_EVENT_SYSFS_BLOCK;
 
1879
                                g_strlcpy (hotplug_event->sysfs.subsystem, "block", sizeof (hotplug_event->sysfs.subsystem));
 
1880
                                g_strlcpy (hotplug_event->sysfs.sysfs_path, sysfs_path, sizeof (hotplug_event->sysfs.sysfs_path));
 
1881
                                g_strlcpy (hotplug_event->sysfs.device_file, device_file, sizeof (hotplug_event->sysfs.device_file));
 
1882
                                hotplug_event->sysfs.net_ifindex = -1;
 
1883
                                hotplug_event_enqueue (hotplug_event);
 
1884
                                
 
1885
                                md_devs = g_slist_remove_link (md_devs, i);
 
1886
                                g_free (i->data);
 
1887
                                g_slist_free (i);
 
1888
 
 
1889
                                g_free (device_file);
 
1890
                        }
 
1891
 
 
1892
                }
 
1893
        }
 
1894
 
 
1895
        g_slist_foreach (read_md_devs, (GFunc) g_free, NULL);
 
1896
        g_slist_free (read_md_devs);
 
1897
 
 
1898
        /* finally, refresh all md devices */
 
1899
        for (i = md_devs; i != NULL; i = i->next) {
 
1900
                char *sysfs_path = i->data;
 
1901
                HalDevice *d;
 
1902
 
 
1903
                d = hal_device_store_match_key_value_string (hald_get_gdl (), 
 
1904
                                                             "storage.linux_raid.sysfs_path", 
 
1905
                                                             sysfs_path);
 
1906
                if (d == NULL)
 
1907
                        d = hal_device_store_match_key_value_string (hald_get_tdl (), 
 
1908
                                                                     "storage.linux_raid.sysfs_path", 
 
1909
                                                                     sysfs_path);
 
1910
                if (d != NULL)
 
1911
                        refresh_md_state (d);
 
1912
        }
 
1913
        
 
1914
 
 
1915
        hotplug_event_process_queue ();
 
1916
 
 
1917
error:
 
1918
        ;
 
1919
}