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