1 /***************************************************************************
2 *
3 * devinfo_storage.c : storage devices
4 *
5 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
6 * Copyright 2013 Garrett D'Amore <garrett@damore.org>
7 *
8 * Licensed under the Academic Free License version 2.1
9 *
10 **************************************************************************/
11
12 #ifdef HAVE_CONFIG_H
13 # include <config.h>
14 #endif
15
16 #include <stdio.h>
17 #include <string.h>
18 #include <strings.h>
19 #include <ctype.h>
20 #include <libdevinfo.h>
21 #include <sys/types.h>
22 #include <sys/mkdev.h>
23 #include <sys/stat.h>
24 #include <sys/mntent.h>
25 #include <sys/mnttab.h>
26
64 HalDevice *devinfo_blkdev_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
65 static HalDevice *devinfo_blkdev_storage_add(HalDevice *parent, di_node_t node, char *devfs_path);
66 HalDevice *devinfo_floppy_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
67 static void devinfo_floppy_add_volume(HalDevice *parent, di_node_t node);
68 static HalDevice *devinfo_lofi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
69 static void devinfo_lofi_add_minor(HalDevice *parent, di_node_t node, char *minor_path, char *devlink, dev_t dev);
70 static void devinfo_storage_minors(HalDevice *parent, di_node_t node, gchar *devfs_path, gboolean);
71 static struct devinfo_storage_minor *devinfo_storage_new_minor(char *maindev_path, char *slice,
72 char *devlink, dev_t dev, int dosnum);
73 static void devinfo_storage_free_minor(struct devinfo_storage_minor *m);
74 HalDevice *devinfo_volume_add(HalDevice *parent, di_node_t node, devinfo_storage_minor_t *m);
75 static void devinfo_volume_preprobing_done(HalDevice *d, gpointer userdata1, gpointer userdata2);
76 static void devinfo_volume_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token);
77 static void devinfo_storage_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token);
78 static void devinfo_storage_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2);
79 const gchar *devinfo_volume_get_prober (HalDevice *d, int *timeout);
80 const gchar *devinfo_storage_get_prober (HalDevice *d, int *timeout);
81
82 static char *devinfo_scsi_dtype2str(int dtype);
83 static char *devinfo_volume_get_slice_name (char *devlink);
84 static gboolean dos_to_dev(char *path, char **devpath, int *partnum);
85 static gboolean is_dos_path(char *path, int *partnum);
86
87 static void devinfo_storage_set_nicknames (HalDevice *d);
88
89 DevinfoDevHandler devinfo_ide_handler = {
90 devinfo_ide_add,
91 NULL,
92 NULL,
93 NULL,
94 NULL,
95 NULL
96 };
97 DevinfoDevHandler devinfo_scsi_handler = {
98 devinfo_scsi_add,
99 NULL,
100 NULL,
101 NULL,
102 NULL,
103 NULL
104 };
105 DevinfoDevHandler devinfo_blkdev_handler = {
842 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
843 dev = di_minor_devt(minor);
844 if ((major != major(dev)) ||
845 (di_minor_type(minor) != DDM_MINOR) ||
846 (di_minor_spectype(minor) != S_IFBLK) ||
847 ((minor_path = di_devfs_minor_path(minor)) == NULL)) {
848 continue;
849 }
850 if ((devlink = get_devlink(devlink_hdl, NULL, minor_path)) == NULL) {
851 di_devfs_path_free (minor_path);
852 continue;
853 }
854
855 slice = devinfo_volume_get_slice_name (devlink);
856 if (strlen (slice) < 2) {
857 free (devlink);
858 di_devfs_path_free (minor_path);
859 continue;
860 }
861
862 /* ignore p1..N - we'll use p0:N instead */
863 if ((strlen (slice) > 1) && (slice[0] == 'p') && isdigit(slice[1]) &&
864 ((atol(&slice[1])) > 0)) {
865 free (devlink);
866 di_devfs_path_free (minor_path);
867 continue;
868 }
869
870 m = devinfo_storage_new_minor(minor_path, slice, devlink, dev, -1);
871 if (m == NULL) {
872 free (devlink);
873 di_devfs_path_free (minor_path);
874 continue;
875 }
876
877 /* main device is either s2/p0 or d0, the latter taking precedence */
878 if ((strcmp (slice, "d0") == 0) ||
879 (((strcmp (slice, whole_disk) == 0) && (maindev == NULL)))) {
880 if (maindev_path != NULL) {
881 di_devfs_path_free (maindev_path);
882 }
883 maindev_path = minor_path;
884 maindev = m;
885 g_queue_push_head (mq, maindev);
886 } else {
887 di_devfs_path_free (minor_path);
888 g_queue_push_tail (mq, m);
889 }
896 /* shouldn't typically happen */
897 while (!g_queue_is_empty (mq)) {
898 devinfo_storage_free_minor (g_queue_pop_head (mq));
899 }
900 goto err;
901 }
902
903 /* first enqueue main storage device */
904 if (!rescan) {
905 hal_device_property_set_int (parent, "block.major", major);
906 hal_device_property_set_int (parent, "block.minor", minor(maindev->dev));
907 hal_device_property_set_string (parent, "block.device", maindev->devlink);
908 raw = dsk_to_rdsk (maindev->devlink);
909 hal_device_property_set_string (parent, "block.solaris.raw_device", raw);
910 free (raw);
911 hal_device_property_set_bool (parent, "block.is_volume", FALSE);
912 hal_device_property_set_string (parent, "solaris.devfs_path", maindev_path);
913 devinfo_add_enqueue (parent, maindev_path, &devinfo_storage_handler);
914 }
915
916 /* add virtual dos volumes to enable pcfs probing */
917 if (!is_cdrom) {
918 doslink_len = strlen (maindev->devlink) + sizeof (":NNN") + 1;
919 if ((doslink = (char *)calloc (1, doslink_len)) != NULL) {
920 for (i = 1; i < 16; i++) {
921 snprintf(dospath, sizeof (dospath), "%s:%d", maindev->slice, i);
922 snprintf(doslink, doslink_len, "%s:%d", maindev->devlink, i);
923 m = devinfo_storage_new_minor(maindev_path, dospath, doslink, maindev->dev, i);
924 g_queue_push_tail (mq, m);
925 }
926 free (doslink);
927 }
928 }
929
930 maindev_is_d0 = (strcmp (maindev->slice, "d0") == 0);
931
932 /* enqueue all volumes */
933 while (!g_queue_is_empty (mq)) {
934 m = g_queue_pop_head (mq);
935
936 /* if main device is d0, we'll throw away s2/p0 */
937 if (maindev_is_d0 && (strcmp (m->slice, whole_disk) == 0)) {
938 devinfo_storage_free_minor (m);
939 continue;
940 }
941 /* don't do p0 on cdrom */
942 if (is_cdrom && (strcmp (m->slice, "p0") == 0)) {
943 devinfo_storage_free_minor (m);
944 continue;
945 }
946 if (rescan) {
947 /* in rescan mode, don't reprobe existing volumes */
948 /* XXX detect volume removal? */
949 volume = hal_device_store_match_key_value_string (hald_get_gdl (),
1060 /*
1061 * Optimizations: only probe if there's a chance to find something
1062 */
1063 block_device = (char *)hal_device_property_get_string (d, "block.device");
1064 storage_udi = hal_device_property_get_string (d, "block.storage_device");
1065 slice = hal_device_property_get_string(d, "block.solaris.slice");
1066 if ((block_device == NULL) || (storage_udi == NULL) ||
1067 (slice == NULL) || (strlen (slice) < 2)) {
1068 HAL_INFO (("Malformed volume properties %s", hal_device_get_udi (d)));
1069 goto skip;
1070 }
1071 storage_d = hal_device_store_match_key_value_string (hald_get_gdl (), "info.udi", storage_udi);
1072 if (storage_d == NULL) {
1073 HAL_INFO (("Storage device not found %s", hal_device_get_udi (d)));
1074 goto skip;
1075 }
1076
1077 whole_disk = hal_device_has_capability (storage_d,
1078 "storage.cdrom") ? "s2" : WHOLE_DISK;
1079
1080 if (is_dos_path(block_device, &dos_num)) {
1081 /* don't probe more dos volumes than probe-storage found */
1082 if ((hal_device_property_get_bool (storage_d, "storage.no_partitions_hint") ||
1083 (dos_num > hal_device_property_get_int (storage_d, "storage.solaris.num_dos_partitions")))) {
1084 HAL_INFO (("%d > %d %s", dos_num, hal_device_property_get_int (storage_d,
1085 "storage.solaris.num_dos_partitions"), hal_device_get_udi (storage_d)));
1086 goto skip;
1087 }
1088 } else {
1089 /* if no VTOC slices found, don't probe slices except s2 */
1090 if ((slice[0] == 's') && (isdigit(slice[1])) && ((strcmp (slice, whole_disk)) != 0) &&
1091 !hal_device_property_get_bool (storage_d, "storage.solaris.vtoc_slices")) {
1092 HAL_INFO (("Not probing slice %s", hal_device_get_udi (d)));
1093 goto skip;
1094 }
1095 }
1096
1097 HAL_INFO(("Probing udi=%s", hal_device_get_udi (d)));
1098 hald_runner_run (d,
1099 "hald-probe-volume", NULL,
1100 DEVINFO_PROBE_VOLUME_TIMEOUT,
1381 }
1382
1383 part = strrchr(devlink, 'p');
1384 slice = strrchr(devlink, 's');
1385 disk = strrchr(devlink, 'd');
1386
1387 if ((part != NULL) && (part > slice) && (part > disk)) {
1388 s = part;
1389 } else if ((slice != NULL) && (slice > disk)) {
1390 s = slice;
1391 } else {
1392 s = disk;
1393 }
1394 if ((s != NULL) && isdigit(s[1])) {
1395 return (s);
1396 } else {
1397 return ("");
1398 }
1399 }
1400
1401 static gboolean
1402 is_dos_path(char *path, int *partnum)
1403 {
1404 char *p;
1405
1406 if ((p = strrchr (path, ':')) == NULL) {
1407 return (FALSE);
1408 }
1409 return ((*partnum = atoi(p + 1)) != 0);
1410 }
1411
1412 static gboolean
1413 dos_to_dev(char *path, char **devpath, int *partnum)
1414 {
1415 char *p;
1416
1417 if ((p = strrchr (path, ':')) == NULL) {
1418 return (FALSE);
1419 }
1420 if ((*partnum = atoi(p + 1)) == 0) {
1421 return (FALSE);
1422 }
1423 p[0] = '\0';
1424 *devpath = strdup(path);
1425 p[0] = ':';
1426 return (*devpath != NULL);
1427 }
1428
1429 static void
1430 devinfo_storage_cleanup_mountpoint_cb (HalDevice *d, guint32 exit_type,
1431 gint return_code, gchar **error,
1432 gpointer data1, gpointer data2)
1433 {
1434 char *mount_point = (char *) data1;
1435
1436 HAL_INFO (("Cleaned up mount point '%s'", mount_point));
1437 g_free (mount_point);
1438 }
1439
1440
1441 void
1442 devinfo_storage_mnttab_event (HalDevice *hal_volume)
1443 {
1444 FILE *fp = NULL;
1445 struct extmnttab m;
1446 HalDevice *d;
|
1 /***************************************************************************
2 *
3 * devinfo_storage.c : storage devices
4 *
5 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
6 * Copyright 2013 Garrett D'Amore <garrett@damore.org>
7 * Copyright 2014 Andrew Stormont.
8 *
9 * Licensed under the Academic Free License version 2.1
10 *
11 **************************************************************************/
12
13 #ifdef HAVE_CONFIG_H
14 # include <config.h>
15 #endif
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <strings.h>
20 #include <ctype.h>
21 #include <libdevinfo.h>
22 #include <sys/types.h>
23 #include <sys/mkdev.h>
24 #include <sys/stat.h>
25 #include <sys/mntent.h>
26 #include <sys/mnttab.h>
27
65 HalDevice *devinfo_blkdev_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
66 static HalDevice *devinfo_blkdev_storage_add(HalDevice *parent, di_node_t node, char *devfs_path);
67 HalDevice *devinfo_floppy_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
68 static void devinfo_floppy_add_volume(HalDevice *parent, di_node_t node);
69 static HalDevice *devinfo_lofi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
70 static void devinfo_lofi_add_minor(HalDevice *parent, di_node_t node, char *minor_path, char *devlink, dev_t dev);
71 static void devinfo_storage_minors(HalDevice *parent, di_node_t node, gchar *devfs_path, gboolean);
72 static struct devinfo_storage_minor *devinfo_storage_new_minor(char *maindev_path, char *slice,
73 char *devlink, dev_t dev, int dosnum);
74 static void devinfo_storage_free_minor(struct devinfo_storage_minor *m);
75 HalDevice *devinfo_volume_add(HalDevice *parent, di_node_t node, devinfo_storage_minor_t *m);
76 static void devinfo_volume_preprobing_done(HalDevice *d, gpointer userdata1, gpointer userdata2);
77 static void devinfo_volume_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token);
78 static void devinfo_storage_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token);
79 static void devinfo_storage_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2);
80 const gchar *devinfo_volume_get_prober (HalDevice *d, int *timeout);
81 const gchar *devinfo_storage_get_prober (HalDevice *d, int *timeout);
82
83 static char *devinfo_scsi_dtype2str(int dtype);
84 static char *devinfo_volume_get_slice_name (char *devlink);
85 static boolean_t is_dos_slice(const char *slice, int *partnum);
86
87 static void devinfo_storage_set_nicknames (HalDevice *d);
88
89 DevinfoDevHandler devinfo_ide_handler = {
90 devinfo_ide_add,
91 NULL,
92 NULL,
93 NULL,
94 NULL,
95 NULL
96 };
97 DevinfoDevHandler devinfo_scsi_handler = {
98 devinfo_scsi_add,
99 NULL,
100 NULL,
101 NULL,
102 NULL,
103 NULL
104 };
105 DevinfoDevHandler devinfo_blkdev_handler = {
842 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
843 dev = di_minor_devt(minor);
844 if ((major != major(dev)) ||
845 (di_minor_type(minor) != DDM_MINOR) ||
846 (di_minor_spectype(minor) != S_IFBLK) ||
847 ((minor_path = di_devfs_minor_path(minor)) == NULL)) {
848 continue;
849 }
850 if ((devlink = get_devlink(devlink_hdl, NULL, minor_path)) == NULL) {
851 di_devfs_path_free (minor_path);
852 continue;
853 }
854
855 slice = devinfo_volume_get_slice_name (devlink);
856 if (strlen (slice) < 2) {
857 free (devlink);
858 di_devfs_path_free (minor_path);
859 continue;
860 }
861
862 m = devinfo_storage_new_minor(minor_path, slice, devlink, dev, -1);
863 if (m == NULL) {
864 free (devlink);
865 di_devfs_path_free (minor_path);
866 continue;
867 }
868
869 /* main device is either s2/p0 or d0, the latter taking precedence */
870 if ((strcmp (slice, "d0") == 0) ||
871 (((strcmp (slice, whole_disk) == 0) && (maindev == NULL)))) {
872 if (maindev_path != NULL) {
873 di_devfs_path_free (maindev_path);
874 }
875 maindev_path = minor_path;
876 maindev = m;
877 g_queue_push_head (mq, maindev);
878 } else {
879 di_devfs_path_free (minor_path);
880 g_queue_push_tail (mq, m);
881 }
888 /* shouldn't typically happen */
889 while (!g_queue_is_empty (mq)) {
890 devinfo_storage_free_minor (g_queue_pop_head (mq));
891 }
892 goto err;
893 }
894
895 /* first enqueue main storage device */
896 if (!rescan) {
897 hal_device_property_set_int (parent, "block.major", major);
898 hal_device_property_set_int (parent, "block.minor", minor(maindev->dev));
899 hal_device_property_set_string (parent, "block.device", maindev->devlink);
900 raw = dsk_to_rdsk (maindev->devlink);
901 hal_device_property_set_string (parent, "block.solaris.raw_device", raw);
902 free (raw);
903 hal_device_property_set_bool (parent, "block.is_volume", FALSE);
904 hal_device_property_set_string (parent, "solaris.devfs_path", maindev_path);
905 devinfo_add_enqueue (parent, maindev_path, &devinfo_storage_handler);
906 }
907
908 maindev_is_d0 = (strcmp (maindev->slice, "d0") == 0);
909
910 /* enqueue all volumes */
911 while (!g_queue_is_empty (mq)) {
912 m = g_queue_pop_head (mq);
913
914 /* if main device is d0, we'll throw away s2/p0 */
915 if (maindev_is_d0 && (strcmp (m->slice, whole_disk) == 0)) {
916 devinfo_storage_free_minor (m);
917 continue;
918 }
919 /* don't do p0 on cdrom */
920 if (is_cdrom && (strcmp (m->slice, "p0") == 0)) {
921 devinfo_storage_free_minor (m);
922 continue;
923 }
924 if (rescan) {
925 /* in rescan mode, don't reprobe existing volumes */
926 /* XXX detect volume removal? */
927 volume = hal_device_store_match_key_value_string (hald_get_gdl (),
1038 /*
1039 * Optimizations: only probe if there's a chance to find something
1040 */
1041 block_device = (char *)hal_device_property_get_string (d, "block.device");
1042 storage_udi = hal_device_property_get_string (d, "block.storage_device");
1043 slice = hal_device_property_get_string(d, "block.solaris.slice");
1044 if ((block_device == NULL) || (storage_udi == NULL) ||
1045 (slice == NULL) || (strlen (slice) < 2)) {
1046 HAL_INFO (("Malformed volume properties %s", hal_device_get_udi (d)));
1047 goto skip;
1048 }
1049 storage_d = hal_device_store_match_key_value_string (hald_get_gdl (), "info.udi", storage_udi);
1050 if (storage_d == NULL) {
1051 HAL_INFO (("Storage device not found %s", hal_device_get_udi (d)));
1052 goto skip;
1053 }
1054
1055 whole_disk = hal_device_has_capability (storage_d,
1056 "storage.cdrom") ? "s2" : WHOLE_DISK;
1057
1058 if (is_dos_slice(slice, &dos_num)) {
1059 /* don't probe more dos volumes than probe-storage found */
1060 if ((hal_device_property_get_bool (storage_d, "storage.no_partitions_hint") ||
1061 (dos_num > hal_device_property_get_int (storage_d, "storage.solaris.num_dos_partitions")))) {
1062 HAL_INFO (("%d > %d %s", dos_num, hal_device_property_get_int (storage_d,
1063 "storage.solaris.num_dos_partitions"), hal_device_get_udi (storage_d)));
1064 goto skip;
1065 }
1066 } else {
1067 /* if no VTOC slices found, don't probe slices except s2 */
1068 if ((slice[0] == 's') && (isdigit(slice[1])) && ((strcmp (slice, whole_disk)) != 0) &&
1069 !hal_device_property_get_bool (storage_d, "storage.solaris.vtoc_slices")) {
1070 HAL_INFO (("Not probing slice %s", hal_device_get_udi (d)));
1071 goto skip;
1072 }
1073 }
1074
1075 HAL_INFO(("Probing udi=%s", hal_device_get_udi (d)));
1076 hald_runner_run (d,
1077 "hald-probe-volume", NULL,
1078 DEVINFO_PROBE_VOLUME_TIMEOUT,
1359 }
1360
1361 part = strrchr(devlink, 'p');
1362 slice = strrchr(devlink, 's');
1363 disk = strrchr(devlink, 'd');
1364
1365 if ((part != NULL) && (part > slice) && (part > disk)) {
1366 s = part;
1367 } else if ((slice != NULL) && (slice > disk)) {
1368 s = slice;
1369 } else {
1370 s = disk;
1371 }
1372 if ((s != NULL) && isdigit(s[1])) {
1373 return (s);
1374 } else {
1375 return ("");
1376 }
1377 }
1378
1379 static boolean_t
1380 is_dos_slice(const char *slice, int *partnum)
1381 {
1382 char *p;
1383
1384 if ((p = strrchr(slice, 'p')) == NULL &&
1385 (p = strrchr(slice, ':')) == NULL) {
1386 return (B_FALSE);
1387 }
1388
1389 return ((*partnum = atoi(p + 1)) != 0);
1390 }
1391
1392 static void
1393 devinfo_storage_cleanup_mountpoint_cb (HalDevice *d, guint32 exit_type,
1394 gint return_code, gchar **error,
1395 gpointer data1, gpointer data2)
1396 {
1397 char *mount_point = (char *) data1;
1398
1399 HAL_INFO (("Cleaned up mount point '%s'", mount_point));
1400 g_free (mount_point);
1401 }
1402
1403
1404 void
1405 devinfo_storage_mnttab_event (HalDevice *hal_volume)
1406 {
1407 FILE *fp = NULL;
1408 struct extmnttab m;
1409 HalDevice *d;
|