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
27 #include "../osspec.h"
28 #include "../logger.h"
29 #include "../hald.h"
30 #include "../hald_dbus.h"
31 #include "../device_info.h"
32 #include "../util.h"
33 #include "../hald_runner.h"
34 #include "hotplug.h"
35 #include "devinfo.h"
36 #include "devinfo_misc.h"
37 #include "devinfo_storage.h"
38 #include "osspec_solaris.h"
39
40 #ifdef sparc
41 #define WHOLE_DISK "s2"
42 #else
43 #define WHOLE_DISK "p0"
44 #endif
45
46 /* some devices,especially CDROMs, may take a while to be probed (values in ms) */
47 #define DEVINFO_PROBE_STORAGE_TIMEOUT 60000
48 #define DEVINFO_PROBE_VOLUME_TIMEOUT 60000
49
50 typedef struct devinfo_storage_minor {
51 char *devpath;
52 char *devlink;
53 char *slice;
54 dev_t dev;
55 int dosnum; /* dos disk number or -1 */
56 } devinfo_storage_minor_t;
57
58 HalDevice *devinfo_ide_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
59 static HalDevice *devinfo_ide_host_add(HalDevice *parent, di_node_t node, char *devfs_path);
60 static HalDevice *devinfo_ide_device_add(HalDevice *parent, di_node_t node, char *devfs_path);
61 static HalDevice *devinfo_ide_storage_add(HalDevice *parent, di_node_t node, char *devfs_path);
62 HalDevice *devinfo_scsi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
63 static HalDevice *devinfo_scsi_storage_add(HalDevice *parent, di_node_t node, char *devfs_path);
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 = {
106 devinfo_blkdev_add,
107 NULL,
108 NULL,
109 NULL,
110 NULL,
111 NULL
112 };
113 DevinfoDevHandler devinfo_floppy_handler = {
114 devinfo_floppy_add,
115 NULL,
116 NULL,
117 NULL,
118 NULL,
119 NULL
120 };
121 DevinfoDevHandler devinfo_lofi_handler = {
122 devinfo_lofi_add,
123 NULL,
124 NULL,
125 NULL,
126 NULL,
127 NULL
128 };
129 DevinfoDevHandler devinfo_storage_handler = {
130 NULL,
131 NULL,
132 devinfo_storage_hotplug_begin_add,
133 NULL,
134 devinfo_storage_probing_done,
135 devinfo_storage_get_prober
136 };
137 DevinfoDevHandler devinfo_volume_handler = {
138 NULL,
139 NULL,
140 devinfo_volume_hotplug_begin_add,
141 NULL,
142 NULL,
143 devinfo_volume_get_prober
144 };
145
146 /* IDE */
147
148 HalDevice *
devinfo_ide_add(HalDevice * parent,di_node_t node,char * devfs_path,char * device_type)149 devinfo_ide_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
150 {
151 char *s;
152
153 if ((device_type != NULL) && (strcmp(device_type, "ide") == 0)) {
154 return (devinfo_ide_host_add(parent, node, devfs_path));
155 }
156
157 if ((di_prop_lookup_strings (DDI_DEV_T_ANY, node, "class", &s) > 0) &&
158 (strcmp (s, "dada") == 0)) {
159 return (devinfo_ide_device_add(parent, node, devfs_path));
160 }
161
162 return (NULL);
163 }
164
165 static HalDevice *
devinfo_ide_host_add(HalDevice * parent,di_node_t node,char * devfs_path)166 devinfo_ide_host_add(HalDevice *parent, di_node_t node, char *devfs_path)
167 {
168 HalDevice *d;
169
170 d = hal_device_new ();
171
172 devinfo_set_default_properties (d, parent, node, devfs_path);
173 hal_device_property_set_string (d, "info.product", "IDE host controller");
174 hal_device_property_set_string (d, "info.subsystem", "ide_host");
175 hal_device_property_set_int (d, "ide_host.number", 0); /* XXX */
176
177 devinfo_add_enqueue (d, devfs_path, &devinfo_ide_handler);
178
179 return (d);
180 }
181
182 static HalDevice *
devinfo_ide_device_add(HalDevice * parent,di_node_t node,char * devfs_path)183 devinfo_ide_device_add(HalDevice *parent, di_node_t node, char *devfs_path)
184 {
185 HalDevice *d;
186
187 d = hal_device_new();
188
189 devinfo_set_default_properties (d, parent, node, devfs_path);
190 hal_device_property_set_string (parent, "info.product", "IDE device");
191 hal_device_property_set_string (parent, "info.subsystem", "ide");
192 hal_device_property_set_int (parent, "ide.host", 0); /* XXX */
193 hal_device_property_set_int (parent, "ide.channel", 0);
194
195 devinfo_add_enqueue (d, devfs_path, &devinfo_ide_handler);
196
197 return (devinfo_ide_storage_add (d, node, devfs_path));
198 }
199
200 static HalDevice *
devinfo_ide_storage_add(HalDevice * parent,di_node_t node,char * devfs_path)201 devinfo_ide_storage_add(HalDevice *parent, di_node_t node, char *devfs_path)
202 {
203 HalDevice *d;
204 char *s;
205 int *i;
206 char *driver_name;
207 char udi[HAL_PATH_MAX];
208
209 if ((driver_name = di_driver_name (node)) == NULL) {
210 return (NULL);
211 }
212
213 d = hal_device_new ();
214
215 devinfo_set_default_properties (d, parent, node, devfs_path);
216 hal_device_property_set_string (d, "info.category", "storage");
217
218 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
219 "%s/%s%d", hal_device_get_udi (parent), driver_name, di_instance (node));
220 hal_device_set_udi (d, udi);
221 hal_device_property_set_string (d, "info.udi", udi);
222 PROP_STR(d, node, s, "devid", "info.product");
223
224 hal_device_add_capability (d, "storage");
225 hal_device_property_set_string (d, "storage.bus", "ide");
226 hal_device_property_set_int (d, "storage.lun", 0);
227 hal_device_property_set_string (d, "storage.drive_type", "disk");
228
229 PROP_BOOL(d, node, i, "hotpluggable", "storage.hotpluggable");
230 PROP_BOOL(d, node, i, "removable-media", "storage.removable");
231
232 hal_device_property_set_bool (d, "storage.media_check_enabled", FALSE);
233
234 /* XXX */
235 hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
236
237 hal_device_add_capability (d, "block");
238
239 devinfo_storage_minors (d, node, (char *)devfs_path, FALSE);
240
241 return (d);
242 }
243
244 /* SCSI */
245
246 HalDevice *
devinfo_scsi_add(HalDevice * parent,di_node_t node,char * devfs_path,char * device_type)247 devinfo_scsi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
248 {
249 int *i;
250 char *driver_name;
251 HalDevice *d;
252 char udi[HAL_PATH_MAX];
253
254 driver_name = di_driver_name (node);
255 if ((driver_name == NULL) || (strcmp (driver_name, "sd") != 0)) {
256 return (NULL);
257 }
258
259 d = hal_device_new ();
260
261 devinfo_set_default_properties (d, parent, node, devfs_path);
262 hal_device_property_set_string (d, "info.subsystem", "scsi");
263
264 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
265 "%s/%s%d", hal_device_get_udi (parent), di_node_name(node), di_instance (node));
266 hal_device_set_udi (d, udi);
267 hal_device_property_set_string (d, "info.udi", udi);
268
269 hal_device_property_set_int (d, "scsi.host",
270 hal_device_property_get_int (parent, "scsi_host.host"));
271 hal_device_property_set_int (d, "scsi.bus", 0);
272 PROP_INT(d, node, i, "target", "scsi.target");
273 PROP_INT(d, node, i, "lun", "scsi.lun");
274 hal_device_property_set_string (d, "info.product", "SCSI Device");
275
276 devinfo_add_enqueue (d, devfs_path, &devinfo_scsi_handler);
277
278 return (devinfo_scsi_storage_add (d, node, devfs_path));
279 }
280
281 static HalDevice *
devinfo_scsi_storage_add(HalDevice * parent,di_node_t node,char * devfs_path)282 devinfo_scsi_storage_add(HalDevice *parent, di_node_t node, char *devfs_path)
283 {
284 HalDevice *d;
285 int *i;
286 char *s;
287 char udi[HAL_PATH_MAX];
288
289 d = hal_device_new ();
290
291 devinfo_set_default_properties (d, parent, node, devfs_path);
292 hal_device_property_set_string (d, "info.category", "storage");
293
294 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
295 "%s/sd%d", hal_device_get_udi (parent), di_instance (node));
296 hal_device_set_udi (d, udi);
297 hal_device_property_set_string (d, "info.udi", udi);
298 PROP_STR(d, node, s, "inquiry-product-id", "info.product");
299
300 hal_device_add_capability (d, "storage");
301
302 hal_device_property_set_int (d, "storage.lun",
303 hal_device_property_get_int (parent, "scsi.lun"));
304 PROP_BOOL(d, node, i, "hotpluggable", "storage.hotpluggable");
305 PROP_BOOL(d, node, i, "removable-media", "storage.removable");
306 hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
307
308 /*
309 * We have to enable polling not only for drives with removable media,
310 * but also for hotpluggable devices, because when a disk is
311 * unplugged while busy/mounted, there is not sysevent generated.
312 * Instead, the HBA driver (scsa2usb, scsa1394) will notify sd driver
313 * and the latter will report DKIO_DEV_GONE via DKIOCSTATE ioctl.
314 * So we have to enable media check so that hald-addon-storage notices
315 * the "device gone" condition and unmounts all associated volumes.
316 */
317 hal_device_property_set_bool (d, "storage.media_check_enabled",
318 ((di_prop_lookup_ints(DDI_DEV_T_ANY, node, "removable-media", &i) >= 0) ||
319 (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "hotpluggable", &i) >= 0)));
320
321 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type",
322 &i) > 0) {
323 s = devinfo_scsi_dtype2str (*i);
324 hal_device_property_set_string (d, "storage.drive_type", s);
325
326 if (strcmp (s, "cdrom") == 0) {
327 hal_device_add_capability (d, "storage.cdrom");
328 hal_device_property_set_bool (d, "storage.no_partitions_hint", TRUE);
329 hal_device_property_set_bool (d, "storage.requires_eject", TRUE);
330 }
331 }
332
333 hal_device_add_capability (d, "block");
334
335 devinfo_storage_minors (d, node, devfs_path, FALSE);
336
337 return (d);
338 }
339
340 static char *
devinfo_scsi_dtype2str(int dtype)341 devinfo_scsi_dtype2str(int dtype)
342 {
343 char *dtype2str[] = {
344 "disk" , /* DTYPE_DIRECT 0x00 */
345 "tape" , /* DTYPE_SEQUENTIAL 0x01 */
346 "printer", /* DTYPE_PRINTER 0x02 */
347 "processor", /* DTYPE_PROCESSOR 0x03 */
348 "worm" , /* DTYPE_WORM 0x04 */
349 "cdrom" , /* DTYPE_RODIRECT 0x05 */
350 "scanner", /* DTYPE_SCANNER 0x06 */
351 "cdrom" , /* DTYPE_OPTICAL 0x07 */
352 "changer", /* DTYPE_CHANGER 0x08 */
353 "comm" , /* DTYPE_COMM 0x09 */
354 "scsi" , /* DTYPE_??? 0x0A */
355 "scsi" , /* DTYPE_??? 0x0B */
356 "array_ctrl", /* DTYPE_ARRAY_CTRL 0x0C */
357 "esi" , /* DTYPE_ESI 0x0D */
358 "disk" /* DTYPE_RBC 0x0E */
359 };
360
361 if (dtype < NELEM(dtype2str)) {
362 return (dtype2str[dtype]);
363 } else {
364 return ("scsi");
365 }
366
367 }
368
369 /* blkdev */
370
371 HalDevice *
devinfo_blkdev_add(HalDevice * parent,di_node_t node,char * devfs_path,char * device_type)372 devinfo_blkdev_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
373 {
374 int *i;
375 char *driver_name;
376 HalDevice *d;
377 char udi[HAL_PATH_MAX];
378
379 driver_name = di_driver_name (node);
380 if ((driver_name == NULL) || (strcmp (driver_name, "blkdev") != 0)) {
381 return (NULL);
382 }
383
384 d = hal_device_new ();
385
386 devinfo_set_default_properties (d, parent, node, devfs_path);
387 hal_device_property_set_string (d, "info.subsystem", "pseudo");
388
389 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
390 "%s/%s%d", hal_device_get_udi (parent), di_node_name(node), di_instance (node));
391 hal_device_set_udi (d, udi);
392 hal_device_property_set_string (d, "info.udi", udi);
393 hal_device_property_set_string (d, "info.product", "Block Device");
394
395 devinfo_add_enqueue (d, devfs_path, &devinfo_blkdev_handler);
396
397 return (devinfo_blkdev_storage_add (d, node, devfs_path));
398 }
399
400 static HalDevice *
devinfo_blkdev_storage_add(HalDevice * parent,di_node_t node,char * devfs_path)401 devinfo_blkdev_storage_add(HalDevice *parent, di_node_t node, char *devfs_path)
402 {
403 HalDevice *d;
404 char *driver_name;
405 int *i;
406 char *s;
407 char udi[HAL_PATH_MAX];
408
409 d = hal_device_new ();
410
411 devinfo_set_default_properties (d, parent, node, devfs_path);
412 hal_device_property_set_string (d, "info.category", "storage");
413
414 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
415 "%s/blkdev%d", hal_device_get_udi (parent), di_instance (node));
416 hal_device_set_udi (d, udi);
417 hal_device_property_set_string (d, "info.udi", udi);
418
419 hal_device_add_capability (d, "storage");
420
421 hal_device_property_set_int (d, "storage.lun", 0);
422
423 PROP_BOOL(d, node, i, "hotpluggable", "storage.hotpluggable");
424 PROP_BOOL(d, node, i, "removable-media", "storage.removable");
425
426 hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
427 hal_device_property_set_bool (d, "storage.media_check_enabled", TRUE);
428 hal_device_property_set_string (d, "storage.drive_type", "disk");
429
430 hal_device_add_capability (d, "block");
431
432 devinfo_storage_minors (d, node, devfs_path, FALSE);
433
434 return (d);
435 }
436
437 /* floppy */
438
439 HalDevice *
devinfo_floppy_add(HalDevice * parent,di_node_t node,char * devfs_path,char * device_type)440 devinfo_floppy_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
441 {
442 char *driver_name;
443 char *raw;
444 char udi[HAL_PATH_MAX];
445 di_devlink_handle_t devlink_hdl;
446 int major;
447 di_minor_t minor;
448 dev_t dev;
449 HalDevice *d = NULL;
450 char *minor_path = NULL;
451 char *devlink = NULL;
452
453 driver_name = di_driver_name (node);
454 if ((driver_name == NULL) || (strcmp (driver_name, "fd") != 0)) {
455 return (NULL);
456 }
457
458 /*
459 * The only minor node we're interested in is /dev/diskette*
460 */
461 major = di_driver_major(node);
462 if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
463 return (NULL);
464 }
465 minor = DI_MINOR_NIL;
466 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
467 dev = di_minor_devt(minor);
468 if ((major != major(dev)) ||
469 (di_minor_type(minor) != DDM_MINOR) ||
470 (di_minor_spectype(minor) != S_IFBLK) ||
471 ((minor_path = di_devfs_minor_path(minor)) == NULL)) {
472 continue;
473 }
474 if ((devlink = get_devlink(devlink_hdl, "diskette.+" , minor_path)) != NULL) {
475 break;
476 }
477 di_devfs_path_free (minor_path);
478 minor_path = NULL;
479 free(devlink);
480 devlink = NULL;
481 }
482 di_devlink_fini (&devlink_hdl);
483
484 if ((devlink == NULL) || (minor_path == NULL)) {
485 HAL_INFO (("floppy devlink not found %s", devfs_path));
486 goto out;
487 }
488
489 d = hal_device_new ();
490
491 devinfo_set_default_properties (d, parent, node, devfs_path);
492 hal_device_property_set_string (d, "info.category", "storage");
493 hal_device_add_capability (d, "storage");
494 hal_device_property_set_string (d, "storage.bus", "platform");
495 hal_device_property_set_bool (d, "storage.hotpluggable", FALSE);
496 hal_device_property_set_bool (d, "storage.removable", TRUE);
497 hal_device_property_set_bool (d, "storage.requires_eject", TRUE);
498 hal_device_property_set_bool (d, "storage.media_check_enabled", FALSE);
499 hal_device_property_set_string (d, "storage.drive_type", "floppy");
500
501 hal_device_add_capability (d, "block");
502 hal_device_property_set_bool (d, "block.is_volume", FALSE);
503 hal_device_property_set_int (d, "block.major", major(dev));
504 hal_device_property_set_int (d, "block.minor", minor(dev));
505 hal_device_property_set_string (d, "block.device", devlink);
506 raw = dsk_to_rdsk (devlink);
507 hal_device_property_set_string (d, "block.solaris.raw_device", raw);
508 free (raw);
509
510 devinfo_add_enqueue (d, devfs_path, &devinfo_storage_handler);
511
512 /* trigger initial probe-volume */
513 devinfo_floppy_add_volume(d, node);
514
515 out:
516 di_devfs_path_free (minor_path);
517 free(devlink);
518
519 return (d);
520 }
521
522 static void
devinfo_floppy_add_volume(HalDevice * parent,di_node_t node)523 devinfo_floppy_add_volume(HalDevice *parent, di_node_t node)
524 {
525 char *devlink;
526 char *devfs_path;
527 int minor, major;
528 dev_t dev;
529 struct devinfo_storage_minor *m;
530
531 devfs_path = (char *)hal_device_property_get_string (parent, "solaris.devfs_path");
532 devlink = (char *)hal_device_property_get_string (parent, "block.device");
533 major = hal_device_property_get_int (parent, "block.major");
534 minor = hal_device_property_get_int (parent, "block.minor");
535 dev = makedev (major, minor);
536
537 m = devinfo_storage_new_minor (devfs_path, WHOLE_DISK, devlink, dev, -1);
538 devinfo_volume_add (parent, node, m);
539 devinfo_storage_free_minor (m);
540 }
541
542 /*
543 * After reprobing storage, reprobe its volumes.
544 */
545 static void
devinfo_floppy_rescan_probing_done(HalDevice * d,guint32 exit_type,gint return_code,char ** error,gpointer userdata1,gpointer userdata2)546 devinfo_floppy_rescan_probing_done (HalDevice *d, guint32 exit_type, gint return_code,
547 char **error, gpointer userdata1, gpointer userdata2)
548 {
549 void *end_token = (void *) userdata1;
550 const char *devfs_path;
551 di_node_t node;
552 HalDevice *v;
553
554 if (!hal_device_property_get_bool (d, "storage.removable.media_available")) {
555 HAL_INFO (("no floppy media", hal_device_get_udi (d)));
556
557 /* remove child (can only be single volume) */
558 if (((v = hal_device_store_match_key_value_string (hald_get_gdl(),
559 "info.parent", hal_device_get_udi (d))) != NULL) &&
560 ((devfs_path = hal_device_property_get_string (v,
561 "solaris.devfs_path")) != NULL)) {
562 devinfo_remove_enqueue ((char *)devfs_path, NULL);
563 }
564 } else {
565 HAL_INFO (("floppy media found", hal_device_get_udi (d)));
566
567 if ((devfs_path = hal_device_property_get_string(d, "solaris.devfs_path")) == NULL) {
568 HAL_INFO (("no devfs_path", hal_device_get_udi (d)));
569 hotplug_event_process_queue ();
570 return;
571 }
572 if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) {
573 HAL_INFO (("di_init %s failed %d", devfs_path, errno));
574 hotplug_event_process_queue ();
575 return;
576 }
577
578 devinfo_floppy_add_volume (d, node);
579
580 di_fini (node);
581 }
582
583 hotplug_event_process_queue ();
584 }
585
586 /* lofi */
587
588 HalDevice *
devinfo_lofi_add(HalDevice * parent,di_node_t node,char * devfs_path,char * device_type)589 devinfo_lofi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
590 {
591 return (devinfo_lofi_add_major(parent,node, devfs_path, device_type, FALSE, NULL));
592 }
593
594 HalDevice *
devinfo_lofi_add_major(HalDevice * parent,di_node_t node,char * devfs_path,char * device_type,gboolean rescan,HalDevice * lofi_d)595 devinfo_lofi_add_major(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type,
596 gboolean rescan, HalDevice *lofi_d)
597 {
598 char *driver_name;
599 HalDevice *d = NULL;
600 char udi[HAL_PATH_MAX];
601 di_devlink_handle_t devlink_hdl;
602 int major;
603 di_minor_t minor;
604 dev_t dev;
605 char *minor_path = NULL;
606 char *devlink = NULL;
607
608 driver_name = di_driver_name (node);
609 if ((driver_name == NULL) || (strcmp (driver_name, "lofi") != 0)) {
610 return (NULL);
611 }
612
613 if (!rescan) {
614 d = hal_device_new ();
615
616 devinfo_set_default_properties (d, parent, node, devfs_path);
617 hal_device_property_set_string (d, "info.subsystem", "pseudo");
618
619 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
620 "%s/%s%d", hal_device_get_udi (parent), di_node_name(node), di_instance (node));
621 hal_device_set_udi (d, udi);
622 hal_device_property_set_string (d, "info.udi", udi);
623
624 devinfo_add_enqueue (d, devfs_path, &devinfo_lofi_handler);
625 } else {
626 d = lofi_d;
627 }
628
629 /*
630 * Unlike normal storage, as in devinfo_storage_minors(), where
631 * sd instance -> HAL storage, sd minor node -> HAL volume,
632 * lofi always has one instance, lofi minor -> HAL storage.
633 * lofi storage never has slices, but it can have
634 * embedded pcfs partitions that fstyp would recognize
635 */
636 major = di_driver_major(node);
637 if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
638 return (d);
639 }
640 minor = DI_MINOR_NIL;
641 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
642 dev = di_minor_devt(minor);
643 if ((major != major(dev)) ||
644 (di_minor_type(minor) != DDM_MINOR) ||
645 (di_minor_spectype(minor) != S_IFBLK) ||
646 ((minor_path = di_devfs_minor_path(minor)) == NULL)) {
647 continue;
648 }
649 if ((devlink = get_devlink(devlink_hdl, NULL, minor_path)) == NULL) {
650 di_devfs_path_free (minor_path);
651 continue;
652 }
653
654 if (!rescan ||
655 (hal_device_store_match_key_value_string (hald_get_gdl (),
656 "solaris.devfs_path", minor_path) == NULL)) {
657 devinfo_lofi_add_minor(d, node, minor_path, devlink, dev);
658 }
659
660 di_devfs_path_free (minor_path);
661 free(devlink);
662 }
663 di_devlink_fini (&devlink_hdl);
664
665 return (d);
666 }
667
668 static void
devinfo_lofi_add_minor(HalDevice * parent,di_node_t node,char * minor_path,char * devlink,dev_t dev)669 devinfo_lofi_add_minor(HalDevice *parent, di_node_t node, char *minor_path, char *devlink, dev_t dev)
670 {
671 HalDevice *d;
672 char *raw;
673 char *doslink;
674 char dospath[64];
675 struct devinfo_storage_minor *m;
676 int i;
677
678 /* add storage */
679 d = hal_device_new ();
680
681 devinfo_set_default_properties (d, parent, node, minor_path);
682 hal_device_property_set_string (d, "info.category", "storage");
683 hal_device_add_capability (d, "storage");
684 hal_device_property_set_string (d, "storage.bus", "lofi");
685 hal_device_property_set_bool (d, "storage.hotpluggable", TRUE);
686 hal_device_property_set_bool (d, "storage.removable", FALSE);
687 hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
688 hal_device_property_set_string (d, "storage.drive_type", "disk");
689 hal_device_add_capability (d, "block");
690 hal_device_property_set_int (d, "block.major", major(dev));
691 hal_device_property_set_int (d, "block.minor", minor(dev));
692 hal_device_property_set_string (d, "block.device", devlink);
693 raw = dsk_to_rdsk (devlink);
694 hal_device_property_set_string (d, "block.solaris.raw_device", raw);
695 free (raw);
696 hal_device_property_set_bool (d, "block.is_volume", FALSE);
697
698 devinfo_add_enqueue (d, minor_path, &devinfo_storage_handler);
699
700 /* add volumes: one on main device and a few pcfs candidates */
701 m = devinfo_storage_new_minor(minor_path, WHOLE_DISK, devlink, dev, -1);
702 devinfo_volume_add (d, node, m);
703 devinfo_storage_free_minor (m);
704
705 doslink = (char *)calloc (1, strlen (devlink) + sizeof (":NNN") + 1);
706 if (doslink != NULL) {
707 for (i = 1; i < 16; i++) {
708 snprintf(dospath, sizeof (dospath), WHOLE_DISK":%d", i);
709 sprintf(doslink, "%s:%d", devlink, i);
710 m = devinfo_storage_new_minor(minor_path, dospath, doslink, dev, i);
711 devinfo_volume_add (d, node, m);
712 devinfo_storage_free_minor (m);
713 }
714 free (doslink);
715 }
716 }
717
718 void
devinfo_lofi_remove_minor(char * parent_devfs_path,char * name)719 devinfo_lofi_remove_minor(char *parent_devfs_path, char *name)
720 {
721 GSList *i;
722 GSList *devices;
723 HalDevice *d = NULL;
724 const char *devfs_path;
725
726 devices = hal_device_store_match_multiple_key_value_string (hald_get_gdl(),
727 "block.solaris.raw_device", name);
728 for (i = devices; i != NULL; i = g_slist_next (i)) {
729 if (hal_device_has_capability (HAL_DEVICE (i->data), "storage")) {
730 d = HAL_DEVICE (i->data);
731 break;
732 }
733 }
734 g_slist_free (devices);
735
736 if (d == NULL) {
737 HAL_INFO (("device not found %s", name));
738 return;
739 }
740
741 if ((devfs_path = hal_device_property_get_string (d,
742 "solaris.devfs_path")) == NULL) {
743 HAL_INFO (("devfs_path not found %s", hal_device_get_udi (d)));
744 return;
745 }
746
747 if (d != NULL) {
748 devinfo_remove_branch ((char *)devfs_path, d);
749 }
750 }
751
752 /* common storage */
753
754 static void
devinfo_storage_free_minor(struct devinfo_storage_minor * m)755 devinfo_storage_free_minor(struct devinfo_storage_minor *m)
756 {
757 if (m != NULL) {
758 free (m->slice);
759 free (m->devlink);
760 free (m->devpath);
761 free (m);
762 }
763 }
764
765 static struct devinfo_storage_minor *
devinfo_storage_new_minor(char * maindev_path,char * slice,char * devlink,dev_t dev,int dosnum)766 devinfo_storage_new_minor(char *maindev_path, char *slice, char *devlink, dev_t dev, int dosnum)
767 {
768 struct devinfo_storage_minor *m;
769 int pathlen;
770 char *devpath;
771
772 m = (struct devinfo_storage_minor *)calloc (sizeof (struct devinfo_storage_minor), 1);
773 if (m != NULL) {
774 /*
775 * For volume's devfs_path we'll use minor_path/slice instead of
776 * minor_path which we use for parent storage device.
777 */
778 pathlen = strlen (maindev_path) + strlen (slice) + 2;
779 devpath = (char *)calloc (1, pathlen);
780 snprintf(devpath, pathlen, "%s/%s", maindev_path, slice);
781
782 m->devpath = devpath;
783 m->devlink = strdup (devlink);
784 m->slice = strdup (slice);
785 m->dev = dev;
786 m->dosnum = dosnum;
787 if ((m->devpath == NULL) || (m->devlink == NULL)) {
788 devinfo_storage_free_minor (m);
789 m = NULL;
790 }
791 }
792 return (m);
793 }
794
795 /*
796 * Storage minor nodes are potential "volume" objects.
797 * This function also completes building the parent object (main storage device).
798 */
799 static void
devinfo_storage_minors(HalDevice * parent,di_node_t node,gchar * devfs_path,gboolean rescan)800 devinfo_storage_minors(HalDevice *parent, di_node_t node, gchar *devfs_path, gboolean rescan)
801 {
802 di_devlink_handle_t devlink_hdl;
803 gboolean is_cdrom;
804 const char *whole_disk;
805 int major;
806 di_minor_t minor;
807 dev_t dev;
808 char *minor_path = NULL;
809 char *maindev_path = NULL;
810 char *devpath, *devlink;
811 int doslink_len;
812 char *doslink;
813 char dospath[64];
814 char *slice;
815 int pathlen;
816 int i;
817 char *raw;
818 boolean_t maindev_is_d0;
819 GQueue *mq;
820 HalDevice *volume;
821 struct devinfo_storage_minor *m;
822 struct devinfo_storage_minor *maindev = NULL;
823
824 /* for cdroms whole disk is always s2 */
825 is_cdrom = hal_device_has_capability (parent, "storage.cdrom");
826 whole_disk = is_cdrom ? "s2" : WHOLE_DISK;
827
828 major = di_driver_major(node);
829
830 /* the "whole disk" p0/s2/d0 node must come first in the hotplug queue
831 * so we put other minor nodes on the local queue and move to the
832 * hotplug queue up in the end
833 */
834 if ((mq = g_queue_new()) == NULL) {
835 goto err;
836 }
837 if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
838 g_queue_free (mq);
839 goto err;
840 }
841 minor = DI_MINOR_NIL;
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 }
890
891 free (devlink);
892 }
893 di_devlink_fini (&devlink_hdl);
894
895 if (maindev == NULL) {
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 (),
950 "solaris.devfs_path", m->devpath);
951 if ((volume == NULL) || !hal_device_has_capability(volume, "volume")) {
952 devinfo_volume_add (parent, node, m);
953 } else {
954 HAL_INFO(("rescan volume exists %s", m->devpath));
955 }
956 } else {
957 devinfo_volume_add (parent, node, m);
958 }
959 devinfo_storage_free_minor (m);
960 }
961
962 if (maindev_path != NULL) {
963 di_devfs_path_free (maindev_path);
964 }
965
966 return;
967
968 err:
969 if (maindev_path != NULL) {
970 di_devfs_path_free (maindev_path);
971 }
972 if (!rescan) {
973 devinfo_add_enqueue (parent, devfs_path, &devinfo_storage_handler);
974 }
975 }
976
977 HalDevice *
devinfo_volume_add(HalDevice * parent,di_node_t node,devinfo_storage_minor_t * m)978 devinfo_volume_add(HalDevice *parent, di_node_t node, devinfo_storage_minor_t *m)
979 {
980 HalDevice *d;
981 char *raw;
982 char udi[HAL_PATH_MAX];
983 char *devfs_path = m->devpath;
984 char *devlink = m->devlink;
985 dev_t dev = m->dev;
986 int dosnum = m->dosnum;
987 char *slice = m->slice;
988
989 HAL_INFO (("volume_add: devfs_path=%s devlink=%s", devfs_path, devlink));
990 d = hal_device_new ();
991
992 devinfo_set_default_properties (d, parent, node, devfs_path);
993 hal_device_property_set_string (d, "info.category", "volume");
994
995 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
996 "%s/%s", hal_device_get_udi (parent), slice);
997 hal_device_set_udi (d, udi);
998 hal_device_property_set_string (d, "info.udi", udi);
999 hal_device_property_set_string (d, "info.product", slice);
1000
1001 hal_device_add_capability (d, "volume");
1002 hal_device_add_capability (d, "block");
1003 hal_device_property_set_int (d, "block.major", major (dev));
1004 hal_device_property_set_int (d, "block.minor", minor (dev));
1005 hal_device_property_set_string (d, "block.device", devlink);
1006 raw = dsk_to_rdsk (devlink);
1007 hal_device_property_set_string (d, "block.solaris.raw_device", raw);
1008 free (raw);
1009 hal_device_property_set_string (d, "block.solaris.slice", slice);
1010 hal_device_property_set_bool (d, "block.is_volume", TRUE); /* XXX */
1011
1012 hal_device_property_set_string (d, "block.storage_device", hal_device_get_udi (parent));
1013
1014 /* set volume defaults */
1015 hal_device_property_set_string (d, "volume.fstype", "");
1016 hal_device_property_set_string (d, "volume.fsusage", "");
1017 hal_device_property_set_string (d, "volume.fsversion", "");
1018 hal_device_property_set_string (d, "volume.uuid", "");
1019 hal_device_property_set_string (d, "volume.label", "");
1020 hal_device_property_set_string (d, "volume.mount_point", "");
1021 hal_device_property_set_bool (d, "volume.is_mounted", FALSE);
1022 if (strcmp (hal_device_property_get_string (parent, "storage.drive_type"), "cdrom") == 0) {
1023 hal_device_property_set_bool (d, "volume.is_disc", TRUE);
1024 hal_device_add_capability (d, "volume.disc");
1025 } else {
1026 hal_device_property_set_bool (d, "volume.is_disc", FALSE);
1027 }
1028
1029 if (dosnum > 0) {
1030 hal_device_property_set_bool (d, "volume.is_partition", TRUE);
1031 hal_device_property_set_int (d, "volume.partition.number", dosnum);
1032 } else {
1033 hal_device_property_set_bool (d, "volume.is_partition", FALSE);
1034 }
1035
1036 /* prober may override these */
1037 hal_device_property_set_int (d, "volume.block_size", 512);
1038
1039 devinfo_add_enqueue (d, devfs_path, &devinfo_volume_handler);
1040
1041 return (d);
1042 }
1043
1044 static void
devinfo_volume_preprobing_done(HalDevice * d,gpointer userdata1,gpointer userdata2)1045 devinfo_volume_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
1046 {
1047 void *end_token = (void *) userdata1;
1048 char *whole_disk;
1049 char *block_device;
1050 const char *storage_udi;
1051 HalDevice *storage_d;
1052 const char *slice;
1053 int dos_num;
1054
1055 if (hal_device_property_get_bool (d, "info.ignore")) {
1056 HAL_INFO (("Preprobing merged info.ignore==TRUE %s", hal_device_get_udi (d)));
1057 goto skip;
1058 }
1059
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,
1101 devinfo_callouts_probing_done,
1102 (gpointer) end_token, userdata2);
1103
1104 return;
1105
1106 skip:
1107 hal_device_store_remove (hald_get_tdl (), d);
1108 g_object_unref (d);
1109 hotplug_event_end (end_token);
1110 }
1111
1112 static void
devinfo_volume_hotplug_begin_add(HalDevice * d,HalDevice * parent,DevinfoDevHandler * handler,void * end_token)1113 devinfo_volume_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token)
1114 {
1115 HAL_INFO(("Preprobing volume udi=%s", hal_device_get_udi (d)));
1116
1117 if (parent == NULL) {
1118 HAL_INFO (("no parent %s", hal_device_get_udi (d)));
1119 goto skip;
1120 }
1121
1122 if (hal_device_property_get_bool (parent, "info.ignore")) {
1123 HAL_INFO (("Ignoring volume: parent's info.ignore is TRUE"));
1124 goto skip;
1125 }
1126
1127 /* add to TDL so preprobing callouts and prober can access it */
1128 hal_device_store_add (hald_get_tdl (), d);
1129
1130 /* Process preprobe fdi files */
1131 di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE);
1132
1133 /* Run preprobe callouts */
1134 hal_util_callout_device_preprobe (d, devinfo_volume_preprobing_done, end_token, handler);
1135
1136 return;
1137
1138 skip:
1139 g_object_unref (d);
1140 hotplug_event_end (end_token);
1141 }
1142
1143 void
devinfo_storage_hotplug_begin_add(HalDevice * d,HalDevice * parent,DevinfoDevHandler * handler,void * end_token)1144 devinfo_storage_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token)
1145 {
1146 const char *drive_type;
1147 const char *p_udi;
1148 HalDevice *p_d;
1149 HalDevice *phys_d = NULL;
1150 const char *phys_bus;
1151 const char *bus;
1152 static const char *busses[] = { "usb", "ide", "scsi", "ieee1394",
1153 "pseudo" };
1154 int i;
1155
1156 HAL_INFO (("Preprobing udi=%s", hal_device_get_udi (d)));
1157
1158 if (parent == NULL) {
1159 HAL_INFO (("no parent %s", hal_device_get_udi (d)));
1160 goto error;
1161 }
1162
1163 /*
1164 * figure out physical device and bus, except for floppy
1165 */
1166 drive_type = hal_device_property_get_string (d, "storage.drive_type");
1167 if ((drive_type != NULL) && (strcmp (drive_type, "floppy") == 0)) {
1168 goto skip_bus;
1169 }
1170
1171 p_d = parent;
1172 for (;;) {
1173 bus = hal_device_property_get_string (p_d, "info.subsystem");
1174 if (bus != NULL) {
1175 for (i = 0; i < NELEM(busses); i++) {
1176 if (strcmp(bus, busses[i]) == 0) {
1177 phys_d = p_d;
1178 phys_bus = busses[i];
1179 break;
1180 }
1181 }
1182 }
1183 /* up the tree */
1184 p_udi = hal_device_property_get_string (p_d, "info.parent");
1185 if (p_udi == NULL) {
1186 break;
1187 }
1188 p_d = hal_device_store_find (hald_get_gdl (), p_udi);
1189 }
1190 if (phys_d == NULL) {
1191 HAL_INFO (("no physical device %s", hal_device_get_udi (d)));
1192 } else {
1193 hal_device_property_set_string (d, "storage.physical_device", hal_device_get_udi (phys_d));
1194 hal_device_property_set_string (d, "storage.bus", phys_bus);
1195 }
1196
1197 skip_bus:
1198
1199 /* add to TDL so preprobing callouts and prober can access it */
1200 hal_device_store_add (hald_get_tdl (), d);
1201
1202 /* Process preprobe fdi files */
1203 di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE);
1204
1205 /* Run preprobe callouts */
1206 hal_util_callout_device_preprobe (d, devinfo_callouts_preprobing_done, end_token, handler);
1207
1208 return;
1209
1210 error:
1211 g_object_unref (d);
1212 hotplug_event_end (end_token);
1213 }
1214
1215 static void
devinfo_storage_probing_done(HalDevice * d,guint32 exit_type,gint return_code,char ** error,gpointer userdata1,gpointer userdata2)1216 devinfo_storage_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2)
1217 {
1218 void *end_token = (void *) userdata1;
1219
1220 HAL_INFO (("devinfo_storage_probing_done %s", hal_device_get_udi (d)));
1221
1222 /* Discard device if probing reports failure */
1223 if (exit_type != HALD_RUN_SUCCESS || return_code != 0) {
1224 HAL_INFO (("devinfo_storage_probing_done returning exit_type=%d return_code=%d", exit_type, return_code));
1225 hal_device_store_remove (hald_get_tdl (), d);
1226 g_object_unref (d);
1227 hotplug_event_end (end_token);
1228 return;
1229 }
1230
1231 devinfo_storage_set_nicknames (d);
1232
1233 /* Merge properties from .fdi files */
1234 di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION);
1235 di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY);
1236
1237 hal_util_callout_device_add (d, devinfo_callouts_add_done, end_token, NULL);
1238 }
1239
1240 const gchar *
devinfo_storage_get_prober(HalDevice * d,int * timeout)1241 devinfo_storage_get_prober (HalDevice *d, int *timeout)
1242 {
1243 *timeout = DEVINFO_PROBE_STORAGE_TIMEOUT;
1244 return "hald-probe-storage";
1245 }
1246
1247 const gchar *
devinfo_volume_get_prober(HalDevice * d,int * timeout)1248 devinfo_volume_get_prober (HalDevice *d, int *timeout)
1249 {
1250 *timeout = DEVINFO_PROBE_VOLUME_TIMEOUT;
1251 return "hald-probe-volume";
1252 }
1253
1254 /*
1255 * After reprobing storage, reprobe its volumes.
1256 */
1257 static void
devinfo_storage_rescan_probing_done(HalDevice * d,guint32 exit_type,gint return_code,char ** error,gpointer userdata1,gpointer userdata2)1258 devinfo_storage_rescan_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2)
1259 {
1260 void *end_token = (void *) userdata1;
1261 const char *devfs_path_orig = NULL;
1262 char *devfs_path = NULL;
1263 char *p;
1264 di_node_t node;
1265
1266 HAL_INFO (("devinfo_storage_rescan_probing_done %s", hal_device_get_udi (d)));
1267
1268 devfs_path_orig = hal_device_property_get_string (d, "solaris.devfs_path");
1269 if (devfs_path_orig == NULL) {
1270 HAL_INFO (("device has no solaris.devfs_path"));
1271 hotplug_event_process_queue ();
1272 return;
1273 }
1274
1275 /* strip trailing minor part if any */
1276 if (strrchr(devfs_path_orig, ':') != NULL) {
1277 if ((devfs_path = strdup (devfs_path_orig)) != NULL) {
1278 p = strrchr(devfs_path, ':');
1279 *p = '\0';
1280 }
1281 } else {
1282 devfs_path = (char *)devfs_path_orig;
1283 }
1284
1285 if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) {
1286 HAL_INFO (("di_init %s failed %d %s", devfs_path, errno, hal_device_get_udi (d)));
1287 hotplug_event_process_queue ();
1288 return;
1289 } else {
1290 devinfo_storage_minors (d, node, (char *)devfs_path, TRUE);
1291 di_fini (node);
1292 }
1293
1294 if (devfs_path != devfs_path_orig) {
1295 free (devfs_path);
1296 }
1297
1298 hotplug_event_process_queue ();
1299 }
1300
1301 /*
1302 * For removable media devices, check for "storage.removable.media_available".
1303 * For non-removable media devices, assume media is always there.
1304 *
1305 * If media is gone, enqueue remove events for all children volumes.
1306 * If media is there, first reprobe storage, then probe for new volumes (but leave existing volumes alone).
1307 */
1308 gboolean
devinfo_storage_device_rescan(HalDevice * d)1309 devinfo_storage_device_rescan (HalDevice *d)
1310 {
1311 GSList *i;
1312 GSList *volumes;
1313 HalDevice *v;
1314 gchar *v_devfs_path;
1315 const char *drive_type;
1316 gboolean is_floppy;
1317 gboolean media_available;
1318
1319 HAL_INFO (("devinfo_storage_device_rescan udi=%s", hal_device_get_udi (d)));
1320
1321 if (hal_device_property_get_bool (d, "block.is_volume")) {
1322 HAL_INFO (("nothing to do for volume"));
1323 return (FALSE);
1324 }
1325
1326 drive_type = hal_device_property_get_string (d, "storage.drive_type");
1327 is_floppy = (drive_type != NULL) && (strcmp (drive_type, "floppy") == 0);
1328
1329 media_available = !hal_device_property_get_bool (d, "storage.removable") ||
1330 hal_device_property_get_bool (d, "storage.removable.media_available");
1331
1332 if (!media_available && !is_floppy) {
1333 HAL_INFO (("media gone %s", hal_device_get_udi (d)));
1334
1335 volumes = hal_device_store_match_multiple_key_value_string (hald_get_gdl(),
1336 "block.storage_device", hal_device_get_udi (d));
1337 for (i = volumes; i != NULL; i = g_slist_next (i)) {
1338 v = HAL_DEVICE (i->data);
1339 v_devfs_path = (gchar *)hal_device_property_get_string (v, "solaris.devfs_path");
1340 HAL_INFO (("child volume %s", hal_device_get_udi (v)));
1341 if ((v_devfs_path != NULL) && hal_device_has_capability (v, "volume")) {
1342 HAL_INFO (("removing volume %s", hal_device_get_udi (v)));
1343 devinfo_remove_enqueue (v_devfs_path, NULL);
1344 } else {
1345 HAL_INFO (("not a volume %s", hal_device_get_udi (v)));
1346 }
1347 }
1348 g_slist_free (volumes);
1349
1350 hotplug_event_process_queue ();
1351 } else if (is_floppy) {
1352 HAL_INFO (("rescanning floppy %s", hal_device_get_udi (d)));
1353
1354 hald_runner_run (d,
1355 "hald-probe-storage --only-check-for-media", NULL,
1356 DEVINFO_PROBE_STORAGE_TIMEOUT,
1357 devinfo_floppy_rescan_probing_done,
1358 NULL, NULL);
1359 } else {
1360 HAL_INFO (("media available %s", hal_device_get_udi (d)));
1361
1362 hald_runner_run (d,
1363 "hald-probe-storage --only-check-for-media", NULL,
1364 DEVINFO_PROBE_STORAGE_TIMEOUT,
1365 devinfo_storage_rescan_probing_done,
1366 NULL, NULL);
1367 }
1368
1369 return TRUE;
1370 }
1371
1372 static char *
devinfo_volume_get_slice_name(char * devlink)1373 devinfo_volume_get_slice_name (char *devlink)
1374 {
1375 char *part, *slice, *disk;
1376 char *s = NULL;
1377 char *p;
1378
1379 if ((p = strstr(devlink, "/lofi/")) != 0) {
1380 return (p + sizeof ("/lofi/") - 1);
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
is_dos_path(char * path,int * partnum)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
dos_to_dev(char * path,char ** devpath,int * partnum)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
devinfo_storage_cleanup_mountpoint_cb(HalDevice * d,guint32 exit_type,gint return_code,gchar ** error,gpointer data1,gpointer data2)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
devinfo_storage_mnttab_event(HalDevice * hal_volume)1442 devinfo_storage_mnttab_event (HalDevice *hal_volume)
1443 {
1444 FILE *fp = NULL;
1445 struct extmnttab m;
1446 HalDevice *d;
1447 unsigned int major;
1448 unsigned int minor;
1449 GSList *volumes = NULL;
1450 GSList *v;
1451 char *mount_point;
1452 dbus_bool_t is_partition;
1453 const char *fstype;
1454 int partition_number;
1455
1456 if (hal_volume != NULL) {
1457 volumes = g_slist_append (NULL, hal_volume);
1458 } else {
1459 volumes = hal_device_store_match_multiple_key_value_string (hald_get_gdl (), "info.category", "volume");
1460 }
1461 if (volumes == NULL) {
1462 return;
1463 }
1464
1465 if ((fp = fopen(MNTTAB, "r")) == NULL) {
1466 HAL_ERROR (("Open failed %s errno %d", MNTTAB, errno));
1467 return;
1468 }
1469
1470 while (getextmntent(fp, &m, 1) == 0) {
1471 for (v = volumes; v != NULL; v = g_slist_next (v)) {
1472 d = HAL_DEVICE (v->data);
1473 major = hal_device_property_get_int (d, "block.major");
1474 minor = hal_device_property_get_int (d, "block.minor");
1475
1476 /*
1477 * special handling for pcfs, which encodes logical
1478 * drive number into the 6 upper bits of the minor
1479 */
1480 is_partition = hal_device_property_get_bool (d, "volume.is_partition");
1481 partition_number = hal_device_property_get_int (d, "volume.partition.number");
1482 fstype = hal_device_property_get_string (d, "volume.fstype");
1483
1484 if (is_partition && (partition_number > 0) && (strcmp (fstype, "pcfs") == 0)) {
1485 minor |= partition_number << 12;
1486 }
1487
1488 if (m.mnt_major != major || m.mnt_minor != minor) {
1489 continue;
1490 }
1491
1492 /* this volume matches the mnttab entry */
1493 device_property_atomic_update_begin ();
1494 hal_device_property_set_bool (d, "volume.is_mounted", TRUE);
1495 hal_device_property_set_bool (d, "volume.is_mounted_read_only",
1496 hasmntopt ((struct mnttab *)&m, "ro") ? TRUE : FALSE);
1497 hal_device_property_set_string (d, "volume.mount_point", m.mnt_mountp);
1498 device_property_atomic_update_end ();
1499
1500 HAL_INFO (("set %s to be mounted at %s",
1501 hal_device_get_udi (d), m.mnt_mountp));
1502 volumes = g_slist_delete_link (volumes, v);
1503 }
1504 }
1505
1506 /* all remaining volumes are not mounted */
1507 for (v = volumes; v != NULL; v = g_slist_next (v)) {
1508 d = HAL_DEVICE (v->data);
1509 mount_point = g_strdup (hal_device_property_get_string (d, "volume.mount_point"));
1510 if (mount_point == NULL || strlen (mount_point) == 0) {
1511 g_free (mount_point);
1512 continue;
1513 }
1514
1515 device_property_atomic_update_begin ();
1516 hal_device_property_set_bool (d, "volume.is_mounted", FALSE);
1517 hal_device_property_set_bool (d, "volume.is_mounted_read_only", FALSE);
1518 hal_device_property_set_string (d, "volume.mount_point", "");
1519 device_property_atomic_update_end ();
1520
1521 HAL_INFO (("set %s to unmounted", hal_device_get_udi (d)));
1522
1523 /* cleanup if was mounted by us */
1524 if (hal_util_is_mounted_by_hald (mount_point)) {
1525 char *cleanup_stdin;
1526 char *extra_env[2];
1527
1528 HAL_INFO (("Cleaning up '%s'", mount_point));
1529
1530 extra_env[0] = g_strdup_printf ("HALD_CLEANUP=%s", mount_point);
1531 extra_env[1] = NULL;
1532 cleanup_stdin = "\n";
1533
1534 hald_runner_run_method (d,
1535 "hal-storage-cleanup-mountpoint",
1536 extra_env,
1537 cleanup_stdin, TRUE,
1538 0,
1539 devinfo_storage_cleanup_mountpoint_cb,
1540 g_strdup (mount_point), NULL);
1541
1542 g_free (extra_env[0]);
1543 }
1544
1545 g_free (mount_point);
1546 }
1547 g_slist_free (volumes);
1548
1549 (void) fclose (fp);
1550 }
1551
1552 static void
devinfo_volume_force_unmount_cb(HalDevice * d,guint32 exit_type,gint return_code,gchar ** error,gpointer data1,gpointer data2)1553 devinfo_volume_force_unmount_cb (HalDevice *d, guint32 exit_type,
1554 gint return_code, gchar **error,
1555 gpointer data1, gpointer data2)
1556 {
1557 void *end_token = (void *) data1;
1558
1559 HAL_INFO (("devinfo_volume_force_unmount_cb for udi='%s', exit_type=%d, return_code=%d", hal_device_get_udi (d), exit_type, return_code));
1560
1561 if (exit_type == HALD_RUN_SUCCESS && error != NULL &&
1562 error[0] != NULL && error[1] != NULL) {
1563 char *exp_name = NULL;
1564 char *exp_detail = NULL;
1565
1566 exp_name = error[0];
1567 if (error[0] != NULL) {
1568 exp_detail = error[1];
1569 }
1570 HAL_INFO (("failed with '%s' '%s'", exp_name, exp_detail));
1571 }
1572
1573 hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
1574 }
1575
1576 static void
devinfo_volume_force_unmount(HalDevice * d,void * end_token)1577 devinfo_volume_force_unmount (HalDevice *d, void *end_token)
1578 {
1579 const char *device_file;
1580 const char *mount_point;
1581 char *unmount_stdin;
1582 char *extra_env[2];
1583 extra_env[0] = "HAL_METHOD_INVOKED_BY_UID=0";
1584 extra_env[1] = NULL;
1585
1586 device_file = hal_device_property_get_string (d, "block.device");
1587 mount_point = hal_device_property_get_string (d, "volume.mount_point");
1588
1589 if (mount_point == NULL || strlen (mount_point) == 0 || !hal_util_is_mounted_by_hald (mount_point)) {
1590 hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
1591 return;
1592 }
1593
1594 HAL_INFO (("devinfo_volume_force_unmount for udi='%s'", hal_device_get_udi (d)));
1595
1596 unmount_stdin = "\n";
1597
1598 hald_runner_run_method (d,
1599 "hal-storage-unmount",
1600 extra_env,
1601 unmount_stdin, TRUE,
1602 0,
1603 devinfo_volume_force_unmount_cb,
1604 end_token, NULL);
1605 }
1606
1607 void
devinfo_volume_hotplug_begin_remove(HalDevice * d,char * devfs_path,void * end_token)1608 devinfo_volume_hotplug_begin_remove (HalDevice *d, char *devfs_path, void *end_token)
1609 {
1610 if (hal_device_property_get_bool (d, "volume.is_mounted")) {
1611 devinfo_volume_force_unmount (d, end_token);
1612 } else {
1613 hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
1614 }
1615 }
1616
1617
1618 enum {
1619 LEGACY_CDROM,
1620 LEGACY_FLOPPY,
1621 LEGACY_RMDISK
1622 };
1623
1624 static const char *legacy_media_str[] = {
1625 "cdrom",
1626 "floppy",
1627 "rmdisk"
1628 };
1629
1630 struct enum_nick {
1631 const char *type;
1632 GSList *nums;
1633 };
1634
1635 static int
devinfo_storage_get_legacy_media(HalDevice * d)1636 devinfo_storage_get_legacy_media(HalDevice *d)
1637 {
1638 const char *drive_type;
1639
1640 if (hal_device_has_capability (d, "storage.cdrom")) {
1641 return (LEGACY_CDROM);
1642 } else if (((drive_type = hal_device_property_get_string (d,
1643 "storage.drive_type")) != NULL) && (strcmp (drive_type, "floppy") == 0)) {
1644 return (LEGACY_FLOPPY);
1645 } else if (hal_device_property_get_bool (d, "storage.removable") ||
1646 hal_device_property_get_bool (d, "storage.hotpluggable")) {
1647 return (LEGACY_RMDISK);
1648 } else {
1649 return (-1);
1650 }
1651 }
1652
1653 static gboolean
devinfo_storage_foreach_nick(HalDeviceStore * store,HalDevice * d,gpointer user_data)1654 devinfo_storage_foreach_nick (HalDeviceStore *store, HalDevice *d, gpointer user_data)
1655 {
1656 struct enum_nick *en = (struct enum_nick *) user_data;
1657 const char *media_type;
1658 int media_num;
1659
1660 media_type = hal_device_property_get_string (d, "storage.solaris.legacy.media_type");
1661 media_num = hal_device_property_get_int (d, "storage.solaris.legacy.media_num");
1662 if ((media_type != NULL) && (strcmp (media_type, en->type) == 0) &&
1663 (media_num >= 0)) {
1664 en->nums = g_slist_prepend (en->nums, GINT_TO_POINTER(media_num));
1665 }
1666 return TRUE;
1667 }
1668
1669 static void
devinfo_storage_append_nickname(HalDevice * d,const char * media_type,int media_num)1670 devinfo_storage_append_nickname (HalDevice *d, const char *media_type, int media_num)
1671 {
1672 char buf[64];
1673
1674 if (media_num == 0) {
1675 hal_device_property_strlist_append (d, "storage.solaris.nicknames", media_type);
1676 }
1677 snprintf(buf, sizeof (buf), "%s%d", media_type, media_num);
1678 hal_device_property_strlist_append (d, "storage.solaris.nicknames", buf);
1679 }
1680
1681 static void
devinfo_storage_set_nicknames(HalDevice * d)1682 devinfo_storage_set_nicknames (HalDevice *d)
1683 {
1684 int media;
1685 const char *media_type;
1686 int media_num;
1687 GSList *i;
1688 struct enum_nick en;
1689 char buf[64];
1690
1691 if ((media = devinfo_storage_get_legacy_media (d)) < 0) {
1692 return;
1693 }
1694 media_type = legacy_media_str[media];
1695
1696 /* enumerate all storage devices of this media type */
1697 en.type = media_type;
1698 en.nums = NULL;
1699 hal_device_store_foreach (hald_get_gdl (), devinfo_storage_foreach_nick, &en);
1700
1701 /* find a free number */
1702 for (media_num = 0; ; media_num++) {
1703 for (i = en.nums; i != NULL; i = g_slist_next (i)) {
1704 if (GPOINTER_TO_INT (i->data) == media_num) {
1705 break;
1706 }
1707 }
1708 if (i == NULL) {
1709 break;
1710 }
1711 }
1712 g_slist_free (en.nums);
1713
1714 hal_device_property_set_string (d, "storage.solaris.legacy.media_type", media_type);
1715 hal_device_property_set_int (d, "storage.solaris.legacy.media_num", media_num);
1716
1717 /* primary nickname, and also vold-style symdev */
1718 snprintf(buf, sizeof (buf), "%s%d", media_type, media_num);
1719 hal_device_property_set_string (d, "storage.solaris.legacy.symdev", buf);
1720 devinfo_storage_append_nickname(d, media_type, media_num);
1721
1722 /* additional nicknames */
1723 if (media == LEGACY_CDROM) {
1724 devinfo_storage_append_nickname(d, "cd", media_num);
1725 devinfo_storage_append_nickname(d, "sr", media_num);
1726 } else if (media == LEGACY_FLOPPY) {
1727 devinfo_storage_append_nickname(d, "fd", media_num);
1728 devinfo_storage_append_nickname(d, "diskette", media_num);
1729 devinfo_storage_append_nickname(d, "rdiskette", media_num);
1730 }
1731 }
1732