1 /***************************************************************************
3 * probe-storage.c : Probe for storage devices
5 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
6 * Use is subject to license terms.
8 * Licensed under the Academic Free License version 2.1
10 **************************************************************************/
22 #include <sys/ioctl.h>
23 #include <sys/types.h>
27 #include <sys/mnttab.h>
29 #include <sys/scsi/scsi.h>
31 #include <sys/efi_partition.h>
39 /** Check if a filesystem on a special device file is mounted
41 * @param device_file Special device file, e.g. /dev/cdrom
42 * @return TRUE iff there is a filesystem system mounted
43 * on the special device file
46 is_mounted (const char *device_file
)
49 dbus_bool_t rc
= FALSE
;
53 if ((f
= fopen ("/etc/mnttab", "r")) == NULL
)
56 bzero(&mp
, sizeof (mp
));
57 bzero(&mpref
, sizeof (mpref
));
58 mpref
.mnt_special
= (char *)device_file
;
59 if (getmntany(f
, &mp
, &mpref
) == 0) {
68 get_cdrom_properties_walker (void *arg
, int profile
, boolean_t is_current
)
70 LibHalChangeSet
*cs
= (LibHalChangeSet
*)arg
;
74 libhal_changeset_set_property_bool (cs
, "storage.cdrom.cdr", TRUE
);
77 libhal_changeset_set_property_bool (cs
, "storage.cdrom.cdrw", TRUE
);
80 libhal_changeset_set_property_bool (cs
, "storage.cdrom.dvd", TRUE
);
83 libhal_changeset_set_property_bool (cs
, "storage.cdrom.dvdr", TRUE
);
86 libhal_changeset_set_property_bool (cs
, "storage.cdrom.dvdram", TRUE
);
89 libhal_changeset_set_property_bool (cs
, "storage.cdrom.dvdrw", TRUE
);
92 libhal_changeset_set_property_bool (cs
, "storage.cdrom.dvdrw", TRUE
);
95 libhal_changeset_set_property_bool (cs
, "storage.cdrom.dvdplusrw", TRUE
);
98 libhal_changeset_set_property_bool (cs
, "storage.cdrom.dvdplusr", TRUE
);
101 libhal_changeset_set_property_bool (cs
, "storage.cdrom.dvdplusrdl", TRUE
);
104 libhal_changeset_set_property_bool (cs
, "storage.cdrom.bd", TRUE
);
108 libhal_changeset_set_property_bool (cs
, "storage.cdrom.bdr", TRUE
);
111 libhal_changeset_set_property_bool (cs
, "storage.cdrom.bdre", TRUE
);
114 libhal_changeset_set_property_bool (cs
, "storage.cdrom.hddvd", TRUE
);
117 libhal_changeset_set_property_bool (cs
, "storage.cdrom.hddvdr", TRUE
);
120 libhal_changeset_set_property_bool (cs
, "storage.cdrom.hddvdrw", TRUE
);
124 return CDUTIL_WALK_CONTINUE
;
130 get_cdrom_properties (int fd
, LibHalChangeSet
*cs
)
134 int read_speed
, write_speed
;
135 intlist_t
*write_speeds
, *write_speeds_mem
, *sp
;
141 libhal_changeset_set_property_bool (cs
, "storage.cdrom.cdr", FALSE
);
142 libhal_changeset_set_property_bool (cs
, "storage.cdrom.cdrw", FALSE
);
143 libhal_changeset_set_property_bool (cs
, "storage.cdrom.dvd", FALSE
);
144 libhal_changeset_set_property_bool (cs
, "storage.cdrom.dvdr", FALSE
);
145 libhal_changeset_set_property_bool (cs
, "storage.cdrom.dvdrw", FALSE
);
146 libhal_changeset_set_property_bool (cs
, "storage.cdrom.dvdram", FALSE
);
147 libhal_changeset_set_property_bool (cs
, "storage.cdrom.dvdplusr", FALSE
);
148 libhal_changeset_set_property_bool (cs
, "storage.cdrom.dvdplusrw", FALSE
);
149 libhal_changeset_set_property_bool (cs
, "storage.cdrom.dvdplusrdl", FALSE
);
150 libhal_changeset_set_property_bool (cs
, "storage.cdrom.bd", FALSE
);
151 libhal_changeset_set_property_bool (cs
, "storage.cdrom.bdr", FALSE
);
152 libhal_changeset_set_property_bool (cs
, "storage.cdrom.bdre", FALSE
);
153 libhal_changeset_set_property_bool (cs
, "storage.cdrom.hddvd", FALSE
);
154 libhal_changeset_set_property_bool (cs
, "storage.cdrom.hddvdr", FALSE
);
155 libhal_changeset_set_property_bool (cs
, "storage.cdrom.hddvdrw", FALSE
);
157 walk_profiles(fd
, get_cdrom_properties_walker
, cs
);
160 libhal_changeset_set_property_bool (cs
, "storage.cdrom.support_media_changed", TRUE
);
162 get_read_write_speeds(fd
, &read_speed
, &write_speed
, &write_speeds
, &n_wspeeds
, &write_speeds_mem
);
164 libhal_changeset_set_property_int (cs
, "storage.cdrom.read_speed", read_speed
);
165 libhal_changeset_set_property_int (cs
, "storage.cdrom.write_speed", write_speed
);
167 if (n_wspeeds
<= 0) {
169 libhal_changeset_set_property_strlist (cs
, "storage.cdrom.write_speeds", (const char **)&wspeeds_mem
);
172 if ((wspeeds
= (char **)calloc(n_wspeeds
+ 1, sizeof (char *))) == NULL
) {
173 free (write_speeds_mem
);
176 if ((wspeeds_mem
= (char *)calloc(n_wspeeds
, WSPLEN
)) == NULL
) {
178 free (write_speeds_mem
);
181 for (i
= 0; i
< n_wspeeds
; i
++) {
182 wspeeds
[i
] = &wspeeds_mem
[i
* WSPLEN
];
185 for (sp
= write_speeds
, i
= 0; sp
!= NULL
; sp
= sp
->next
, i
++) {
186 snprintf (wspeeds
[i
], WSPLEN
, "%d", sp
->val
);
188 libhal_changeset_set_property_strlist (cs
, "storage.cdrom.write_speeds", (const char **)wspeeds
);
192 free (write_speeds_mem
);
196 * Return a copy of a string without trailing spaces. If 'len' is non-zero,
197 * it specifies max length, otherwise the string must be null-terminated.
200 rtrim_copy(char *src
, int len
)
207 if ((dst
= calloc(1, len
+ 1)) != NULL
) {
208 strncpy(dst
, src
, len
);
210 while ((p
>= dst
) && (isspace(*p
))) {
218 get_disk_properties (int fd
, LibHalChangeSet
*cs
)
220 struct scsi_inquiry inq
;
221 struct uscsi_cmd ucmd
;
227 (void) memset(&inq
, 0, sizeof (inq
));
228 (void) memset(&ucmd
, 0, sizeof (ucmd
));
229 (void) memset(&cdb
, 0, sizeof (union scsi_cdb
));
230 cdb
.scc_cmd
= SCMD_INQUIRY
;
231 FORMG0COUNT(&cdb
, sizeof (inq
));
232 ucmd
.uscsi_cdb
= (caddr_t
) & cdb
;
233 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
234 ucmd
.uscsi_bufaddr
= (caddr_t
) & inq
;
235 ucmd
.uscsi_buflen
= sizeof (inq
);
236 ucmd
.uscsi_timeout
= 30;
237 ucmd
.uscsi_flags
= USCSI_READ
;
238 status
= ioctl(fd
, USCSICMD
, &ucmd
);
239 if (status
|| ucmd
.uscsi_status
) {
243 if ((s
= rtrim_copy(inq
.inq_vid
, sizeof (inq
.inq_vid
))) != NULL
) {
244 libhal_changeset_set_property_string (cs
, "storage.vendor", s
);
247 if ((s
= rtrim_copy(inq
.inq_pid
, sizeof (inq
.inq_pid
))) != NULL
) {
248 libhal_changeset_set_property_string (cs
, "storage.model", s
);
251 if ((s
= rtrim_copy(inq
.inq_revision
, sizeof (inq
.inq_revision
))) != NULL
) {
252 libhal_changeset_set_property_string (cs
, "storage.firmware_revision", s
);
255 if ((s
= rtrim_copy(inq
.inq_serial
, sizeof (inq
.inq_serial
))) != NULL
) {
256 libhal_changeset_set_property_string (cs
, "storage.serial", s
);
262 * returns TRUE if diskette is inserted.
263 * also returns write protection status.
266 check_floppy(int fd
, dbus_bool_t
*wprot
)
270 if ((ioctl(fd
, FDGETCHANGE
, &chg
) == 0) && !(chg
& FDGC_CURRENT
)) {
271 *wprot
= ((chg
& FDGC_CURWPROT
) != 0);
281 priv_set_t
*pPrivSet
= NULL
;
282 priv_set_t
*lPrivSet
= NULL
;
285 * Start with the 'basic' privilege set and then remove any
286 * of the 'basic' privileges that will not be needed.
288 if ((pPrivSet
= priv_str_to_set("basic", ",", NULL
)) == NULL
) {
292 /* Clear privileges we will not need from the 'basic' set */
293 (void) priv_delset(pPrivSet
, PRIV_FILE_LINK_ANY
);
294 (void) priv_delset(pPrivSet
, PRIV_PROC_INFO
);
295 (void) priv_delset(pPrivSet
, PRIV_PROC_SESSION
);
296 (void) priv_delset(pPrivSet
, PRIV_PROC_EXEC
);
297 (void) priv_delset(pPrivSet
, PRIV_PROC_FORK
);
300 (void) priv_addset(pPrivSet
, PRIV_SYS_DEVICES
);
302 /* to open logindevperm'd devices */
303 (void) priv_addset(pPrivSet
, PRIV_FILE_DAC_READ
);
305 /* Set the permitted privilege set. */
306 if (setppriv(PRIV_SET
, PRIV_PERMITTED
, pPrivSet
) != 0) {
310 /* Clear the limit set. */
311 if ((lPrivSet
= priv_allocset()) == NULL
) {
315 priv_emptyset(lPrivSet
);
317 if (setppriv(PRIV_SET
, PRIV_LIMIT
, lPrivSet
) != 0) {
321 priv_freeset(lPrivSet
);
325 main (int argc
, char *argv
[])
332 char *raw_device_file
;
333 LibHalContext
*ctx
= NULL
;
336 dbus_bool_t is_cdrom
;
337 dbus_bool_t is_floppy
;
338 struct dk_minfo minfo
;
340 unsigned int block_size
= 512;
341 dbus_bool_t only_check_for_media
;
342 int got_media
= FALSE
;
343 dbus_bool_t is_write_protected
= FALSE
;
344 dbus_bool_t is_mbr
= FALSE
;
345 dbus_bool_t is_smi
= FALSE
;
346 dbus_bool_t is_gpt
= FALSE
;
347 dbus_bool_t is_partitioned
= FALSE
;
348 dbus_bool_t vtoc_slices
= FALSE
;
350 const char *scheme
= "";
353 LibHalChangeSet
*cs
= NULL
;
355 if ((udi
= getenv ("UDI")) == NULL
)
357 if ((device_file
= getenv ("HAL_PROP_BLOCK_DEVICE")) == NULL
)
359 if ((raw_device_file
= getenv ("HAL_PROP_BLOCK_SOLARIS_RAW_DEVICE")) == NULL
)
361 if ((drive_type
= getenv ("HAL_PROP_STORAGE_DRIVE_TYPE")) == NULL
)
368 if (argc
== 2 && strcmp (argv
[1], "--only-check-for-media") == 0)
369 only_check_for_media
= TRUE
;
371 only_check_for_media
= FALSE
;
373 is_cdrom
= (strcmp (drive_type
, "cdrom") == 0);
374 is_floppy
= (strcmp (drive_type
, "floppy") == 0);
376 dbus_error_init (&error
);
377 if ((ctx
= libhal_ctx_init_direct (&error
)) == NULL
)
380 if ((cs
= libhal_device_new_changeset (udi
)) == NULL
) {
381 HAL_DEBUG (("Cannot allocate changeset"));
385 HAL_DEBUG (("Doing probe-storage for %s (drive_type %s) (udi=%s) (--only-check-for-media==%d)",
386 device_file
, drive_type
, udi
, only_check_for_media
));
388 if ((rfd
= open (raw_device_file
, O_RDONLY
| O_NONBLOCK
)) < 0) {
389 HAL_DEBUG (("Cannot open %s: %s", raw_device_file
, strerror (errno
)));
393 if (!only_check_for_media
) {
394 if (strcmp (drive_type
, "cdrom") == 0) {
395 get_cdrom_properties (rfd
, cs
);
396 } else if (strcmp (drive_type
, "disk") == 0) {
397 get_disk_properties (rfd
, cs
);
404 HAL_DEBUG (("Checking for optical disc on %s", raw_device_file
));
405 got_media
= get_media_info(rfd
, &minfo
);
409 block_size
= minfo
.dki_lbsize
;
411 is_write_protected
= TRUE
;
412 } else if (is_floppy
) {
413 HAL_DEBUG (("Checking for floppy on %s", raw_device_file
));
414 if (check_floppy(rfd
, &is_write_protected
)) {
417 /* don't look for partitions on floppy */
420 got_media
= get_media_info(rfd
, &minfo
);
424 block_size
= minfo
.dki_lbsize
;
425 if ((ioctl(rfd
, DKIOCREADONLY
, &rdonly
) == 0) && rdonly
) {
426 is_write_protected
= TRUE
;
430 HAL_DEBUG (("Checking for partitions on %s", device_file
));
432 if ((fd
= open (device_file
, O_RDONLY
| O_NONBLOCK
)) < 0) {
433 HAL_DEBUG (("Cannot open %s: %s", device_file
, strerror (errno
)));
437 dos_cnt
= get_num_dos_drives(fd
, block_size
);
438 is_mbr
= (dos_cnt
> 0);
442 if (read_extvtoc(rfd
, &vtoc
) >= 0) {
443 if (!vtoc_one_slice_entire_disk(&vtoc
)) {
446 /* smi within mbr partition is okay */
451 } else if (!is_cdrom
&& (efi_alloc_and_read(rfd
, &gpt
) >= 0)) {
453 * Note: for some reason efi_read takes very long on cdroms.
454 * Needs more investigation, skip gpt on cdrom for now.
462 is_partitioned
= is_mbr
|| is_smi
|| is_gpt
;
463 libhal_changeset_set_property_bool (cs
, "storage.no_partitions_hint", !is_partitioned
);
464 libhal_changeset_set_property_bool (cs
, "block.no_partitions", !is_partitioned
);
465 libhal_changeset_set_property_string (cs
, "storage.partitioning_scheme", scheme
);
466 libhal_changeset_set_property_bool (cs
, "storage.solaris.vtoc_slices", vtoc_slices
);
467 libhal_changeset_set_property_int (cs
, "storage.solaris.num_dos_partitions", dos_cnt
);
468 /* XXX should only set for removable drives */
469 libhal_changeset_set_property_bool (cs
, "storage.removable.media_available", got_media
);
470 libhal_changeset_set_property_bool (cs
, "storage.removable.solaris.read_only", is_write_protected
);
472 libhal_device_commit_changeset (ctx
, cs
, &error
);
476 libhal_device_free_changeset (cs
);
485 if (dbus_error_is_set(&error
)) {
486 dbus_error_free (&error
);
488 libhal_ctx_shutdown (ctx
, &error
);
489 libhal_ctx_free (ctx
);