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