4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
36 #include <sys/param.h>
37 #include <sys/types.h>
39 #include <sys/mnttab.h>
41 #include <dbus/dbus.h>
42 #include <dbus/dbus-glib.h>
43 #include <dbus/dbus-glib-lowlevel.h>
45 #include <libhal-storage.h>
47 #include "rmm_common.h"
49 #define RMM_PRINT_DEVICE_WIDTH 20
53 static const char *action_strings
[] = {
64 rmm_hal_init(LibHalDeviceAdded devadd_cb
, LibHalDeviceRemoved devrem_cb
,
65 LibHalDevicePropertyModified propmod_cb
, LibHalDeviceCondition cond_cb
,
66 DBusError
*error
, rmm_error_t
*rmm_error
)
68 DBusConnection
*dbus_conn
;
73 dbus_error_init(error
);
76 * setup D-Bus connection
78 if (!(dbus_conn
= dbus_bus_get(DBUS_BUS_SYSTEM
, error
))) {
79 dprintf("cannot get system bus: %s\n", rmm_strerror(error
, -1));
80 *rmm_error
= RMM_EDBUS_CONNECT
;
83 rmm_dbus_error_free(error
);
85 dbus_connection_setup_with_g_main(dbus_conn
, NULL
);
86 dbus_connection_set_exit_on_disconnect(dbus_conn
, B_TRUE
);
88 if ((ctx
= libhal_ctx_new()) == NULL
) {
89 dprintf("libhal_ctx_new failed");
90 *rmm_error
= RMM_EHAL_CONNECT
;
94 libhal_ctx_set_dbus_connection(ctx
, dbus_conn
);
99 if (devadd_cb
!= NULL
) {
100 libhal_ctx_set_device_added(ctx
, devadd_cb
);
102 if (devrem_cb
!= NULL
) {
103 libhal_ctx_set_device_removed(ctx
, devrem_cb
);
105 if (propmod_cb
!= NULL
) {
106 libhal_ctx_set_device_property_modified(ctx
, propmod_cb
);
107 if (!libhal_device_property_watch_all(ctx
, error
)) {
108 dprintf("property_watch_all failed %s",
109 rmm_strerror(error
, -1));
110 libhal_ctx_free(ctx
);
111 *rmm_error
= RMM_EHAL_CONNECT
;
115 if (cond_cb
!= NULL
) {
116 libhal_ctx_set_device_condition(ctx
, cond_cb
);
119 if (!libhal_ctx_init(ctx
, error
)) {
120 dprintf("libhal_ctx_init failed: %s", rmm_strerror(error
, -1));
121 libhal_ctx_free(ctx
);
122 *rmm_error
= RMM_EHAL_CONNECT
;
125 rmm_dbus_error_free(error
);
128 * The above functions do not guarantee that HAL is actually running.
129 * Check by invoking a method.
131 if (!(devices
= libhal_get_all_devices(ctx
, &nr
, error
))) {
132 dprintf("HAL is not running: %s", rmm_strerror(error
, -1));
133 libhal_ctx_shutdown(ctx
, NULL
);
134 libhal_ctx_free(ctx
);
135 *rmm_error
= RMM_EHAL_CONNECT
;
138 rmm_dbus_error_free(error
);
139 libhal_free_string_array(devices
);
147 rmm_hal_fini(LibHalContext
*hal_ctx
)
149 DBusConnection
*dbus_conn
= libhal_ctx_get_dbus_connection(hal_ctx
);
151 (void) dbus_connection_unref(dbus_conn
);
152 (void) libhal_ctx_free(hal_ctx
);
157 * find volume from any type of name, similar to the old media_findname()
158 * returns the LibHalDrive object and a list of LibHalVolume objects.
161 rmm_hal_volume_find(LibHalContext
*hal_ctx
, const char *name
, DBusError
*error
,
170 /* temporarily remove trailing slash */
171 p
= (char *)name
+ strlen(name
) - 1;
179 if (name
[0] == '/') {
180 if (((drive
= rmm_hal_volume_findby(hal_ctx
,
181 "info.udi", name
, volumes
)) != NULL
) ||
182 ((drive
= rmm_hal_volume_findby(hal_ctx
,
183 "block.device", name
, volumes
)) != NULL
) ||
184 ((drive
= rmm_hal_volume_findby(hal_ctx
,
185 "block.solaris.raw_device", name
, volumes
)) != NULL
) ||
186 ((drive
= rmm_hal_volume_findby(hal_ctx
,
187 "volume.mount_point", name
, volumes
)) != NULL
)) {
194 /* try volume label */
195 if ((drive
= rmm_hal_volume_findby(hal_ctx
,
196 "volume.label", name
, volumes
)) != NULL
) {
200 drive
= rmm_hal_volume_findby_nickname(hal_ctx
, name
, volumes
);
210 * find default volume. Returns volume pointer and name in 'name'.
213 rmm_hal_volume_find_default(LibHalContext
*hal_ctx
, DBusError
*error
,
214 const char **name_out
, GSList
**volumes
)
217 static const char *names
[] = { "floppy", "cdrom", "rmdisk" };
222 for (i
= 0; i
< NELEM(names
); i
++) {
223 if ((drive
= rmm_hal_volume_findby_nickname(hal_ctx
,
224 names
[i
], volumes
)) != NULL
) {
226 * Skip floppy if it has no media.
227 * XXX might want to actually check for media
228 * every time instead of relying on volcheck.
230 if ((strcmp(names
[i
], "floppy") != 0) ||
231 libhal_device_get_property_bool(hal_ctx
,
232 libhal_drive_get_udi(drive
),
233 "storage.removable.media_available", NULL
)) {
234 *name_out
= names
[i
];
238 rmm_dbus_error_free(error
);
245 * find volume by property=value
246 * returns the LibHalDrive object and a list of LibHalVolume objects.
247 * XXX add support for multiple properties, reduce D-Bus traffic
250 rmm_hal_volume_findby(LibHalContext
*hal_ctx
, const char *property
,
251 const char *value
, GSList
**volumes
)
254 LibHalDrive
*drive
= NULL
;
255 LibHalVolume
*v
= NULL
;
263 dbus_error_init(&error
);
265 /* get all devices with property=value */
266 if ((udis
= libhal_manager_find_device_string_match(hal_ctx
, property
,
267 value
, &num_udis
, &error
)) == NULL
) {
268 rmm_dbus_error_free(&error
);
272 /* find volumes and drives among these devices */
273 for (i
= 0; i
< num_udis
; i
++) {
274 rmm_dbus_error_free(&error
);
275 if (libhal_device_query_capability(hal_ctx
, udis
[i
], "volume",
277 v
= libhal_volume_from_udi(hal_ctx
, udis
[i
]);
279 *volumes
= g_slist_prepend(*volumes
, v
);
281 } else if ((*volumes
== NULL
) &&
282 libhal_device_query_capability(hal_ctx
, udis
[i
], "storage",
288 if (*volumes
!= NULL
) {
289 /* used prepend, preserve original order */
290 *volumes
= g_slist_reverse(*volumes
);
292 v
= (LibHalVolume
*)(*volumes
)->data
;
293 drive
= libhal_drive_from_udi(hal_ctx
,
294 libhal_volume_get_storage_device_udi(v
));
296 rmm_volumes_free (*volumes
);
299 } else if (i_drive
>= 0) {
300 drive
= libhal_drive_from_udi(hal_ctx
, udis
[i_drive
]);
303 libhal_free_string_array(udis
);
304 rmm_dbus_error_free(&error
);
310 rmm_print_nicknames_one(LibHalDrive
*d
, LibHalVolume
*v
,
311 const char *device
, char **drive_nicknames
)
313 const char *volume_label
= NULL
;
314 const char *mount_point
= NULL
;
318 (void) printf("%-*s ", RMM_PRINT_DEVICE_WIDTH
, device
);
321 if (drive_nicknames
!= NULL
) {
322 for (i
= 0; drive_nicknames
[i
] != NULL
; i
++) {
323 (void) printf("%s%s", comma
? "," : "",
330 ((volume_label
= libhal_volume_get_label(v
)) != NULL
) &&
331 (strlen(volume_label
) > 0)) {
332 (void) printf("%s%s", comma
? "," : "", volume_label
);
337 ((mount_point
= libhal_volume_get_mount_point(v
)) != NULL
) &&
338 (strlen(mount_point
) > 0)) {
339 (void) printf("%s%s", comma
? "," : "", mount_point
);
347 * print nicknames for each available volume
350 * RMM_PRINT_MOUNTABLE print only mountable volumes
351 * RMM_PRINT_EJECTABLE print volume-less ejectable drives
354 rmm_print_volume_nicknames(LibHalContext
*hal_ctx
, DBusError
*error
,
359 GSList
*volumes
= NULL
;
360 LibHalDrive
*d
, *d_tmp
;
368 dbus_error_init(error
);
370 if ((udis
= libhal_find_device_by_capability(hal_ctx
, "storage",
371 &num_udis
, error
)) == NULL
) {
372 rmm_dbus_error_free(error
);
376 for (i
= 0; i
< num_udis
; i
++) {
377 if ((d
= libhal_drive_from_udi(hal_ctx
, udis
[i
])) == NULL
) {
381 /* find volumes belonging to this drive */
382 if ((d_tmp
= rmm_hal_volume_findby(hal_ctx
,
383 "block.storage_device", udis
[i
], &volumes
)) != NULL
) {
384 libhal_drive_free(d_tmp
);
387 nicknames
= libhal_device_get_property_strlist(hal_ctx
,
388 udis
[i
], "storage.solaris.nicknames", NULL
);
391 for (j
= volumes
; j
!= NULL
; j
= g_slist_next(j
)) {
392 v
= (LibHalVolume
*)(j
->data
);
394 if ((device
= libhal_volume_get_device_file(v
)) ==
398 if ((print_mask
& RMM_PRINT_MOUNTABLE
) &&
399 (libhal_volume_get_fsusage(v
) !=
400 LIBHAL_VOLUME_USAGE_MOUNTABLE_FILESYSTEM
)) {
404 rmm_print_nicknames_one(d
, v
, device
, nicknames
);
408 if ((nprinted
== 0) &&
409 (print_mask
& RMM_PRINT_EJECTABLE
) &&
410 libhal_drive_requires_eject(d
) &&
411 ((device
= libhal_drive_get_device_file(d
)) != NULL
)) {
412 rmm_print_nicknames_one(d
, NULL
, device
, nicknames
);
415 libhal_free_string_array(nicknames
);
416 libhal_drive_free(d
);
417 rmm_volumes_free(volumes
);
421 libhal_free_string_array(udis
);
425 * find volume by nickname
426 * returns the LibHalDrive object and a list of LibHalVolume objects.
429 rmm_hal_volume_findby_nickname(LibHalContext
*hal_ctx
, const char *name
,
433 LibHalDrive
*drive
= NULL
;
434 LibHalDrive
*drive_tmp
;
442 dbus_error_init(&error
);
444 if ((udis
= libhal_find_device_by_capability(hal_ctx
, "storage",
445 &num_udis
, &error
)) == NULL
) {
446 rmm_dbus_error_free(&error
);
450 /* find a drive by nickname */
451 for (i
= 0; (i
< num_udis
) && (drive
== NULL
); i
++) {
452 if ((nicknames
= libhal_device_get_property_strlist(hal_ctx
,
453 udis
[i
], "storage.solaris.nicknames", &error
)) == NULL
) {
454 rmm_dbus_error_free(&error
);
457 for (j
= 0; (nicknames
[j
] != NULL
) && (drive
== NULL
); j
++) {
458 if (strcmp(nicknames
[j
], name
) == 0) {
459 drive
= libhal_drive_from_udi(hal_ctx
, udis
[i
]);
462 libhal_free_string_array(nicknames
);
464 libhal_free_string_array(udis
);
467 /* found the drive, now find its volumes */
468 if ((drive_tmp
= rmm_hal_volume_findby(hal_ctx
,
469 "block.storage_device", libhal_drive_get_udi(drive
),
471 libhal_drive_free(drive_tmp
);
475 rmm_dbus_error_free(&error
);
481 rmm_volumes_free(GSList
*volumes
)
485 for (i
= volumes
; i
!= NULL
; i
= g_slist_next(i
)) {
486 libhal_volume_free((LibHalVolume
*)(i
->data
));
488 g_slist_free(volumes
);
492 * Call HAL's Mount() method on the given device
495 rmm_hal_mount(LibHalContext
*hal_ctx
, const char *udi
,
496 char **opts
, int num_opts
, char *mountpoint
, DBusError
*error
)
498 DBusConnection
*dbus_conn
= libhal_ctx_get_dbus_connection(hal_ctx
);
499 DBusMessage
*dmesg
, *reply
;
502 dprintf("mounting %s...\n", udi
);
504 if (!(dmesg
= dbus_message_new_method_call("org.freedesktop.Hal", udi
,
505 "org.freedesktop.Hal.Device.Volume", "Mount"))) {
507 "mount failed for %s: cannot create dbus message\n", udi
);
512 if (mountpoint
== NULL
) {
516 if (!dbus_message_append_args(dmesg
, DBUS_TYPE_STRING
, &mountpoint
,
517 DBUS_TYPE_STRING
, &fstype
,
518 DBUS_TYPE_ARRAY
, DBUS_TYPE_STRING
, &opts
, num_opts
,
519 DBUS_TYPE_INVALID
)) {
520 dprintf("mount failed for %s: cannot append args\n", udi
);
521 dbus_message_unref(dmesg
);
525 dbus_error_init(error
);
526 if (!(reply
= dbus_connection_send_with_reply_and_block(dbus_conn
,
527 dmesg
, RMM_MOUNT_TIMEOUT
, error
))) {
528 dprintf("mount failed for %s: %s\n", udi
, error
->message
);
529 dbus_message_unref(dmesg
);
533 dprintf("mounted %s\n", udi
);
535 dbus_message_unref(dmesg
);
536 dbus_message_unref(reply
);
538 rmm_dbus_error_free(error
);
545 * Call HAL's Unmount() method on the given device
548 rmm_hal_unmount(LibHalContext
*hal_ctx
, const char *udi
, DBusError
*error
)
550 DBusConnection
*dbus_conn
= libhal_ctx_get_dbus_connection(hal_ctx
);
551 DBusMessage
*dmesg
, *reply
;
554 dprintf("unmounting %s...\n", udi
);
556 if (!(dmesg
= dbus_message_new_method_call("org.freedesktop.Hal", udi
,
557 "org.freedesktop.Hal.Device.Volume", "Unmount"))) {
559 "unmount failed %s: cannot create dbus message\n", udi
);
563 if (!dbus_message_append_args(dmesg
, DBUS_TYPE_ARRAY
, DBUS_TYPE_STRING
,
564 &opts
, 0, DBUS_TYPE_INVALID
)) {
565 dprintf("unmount failed %s: cannot append args\n", udi
);
566 dbus_message_unref(dmesg
);
570 dbus_error_init(error
);
571 if (!(reply
= dbus_connection_send_with_reply_and_block(dbus_conn
,
572 dmesg
, RMM_UNMOUNT_TIMEOUT
, error
))) {
573 dprintf("unmount failed for %s: %s\n", udi
, error
->message
);
574 dbus_message_unref(dmesg
);
578 dprintf("unmounted %s\n", udi
);
580 dbus_message_unref(dmesg
);
581 dbus_message_unref(reply
);
583 rmm_dbus_error_free(error
);
590 * Call HAL's Eject() method on the given device
593 rmm_hal_eject(LibHalContext
*hal_ctx
, const char *udi
, DBusError
*error
)
595 DBusConnection
*dbus_conn
= libhal_ctx_get_dbus_connection(hal_ctx
);
596 DBusMessage
*dmesg
, *reply
;
597 char **options
= NULL
;
598 uint_t num_options
= 0;
600 dprintf("ejecting %s...\n", udi
);
602 if (!(dmesg
= dbus_message_new_method_call("org.freedesktop.Hal", udi
,
603 "org.freedesktop.Hal.Device.Storage", "Eject"))) {
604 dprintf("eject %s: cannot create dbus message\n", udi
);
608 if (!dbus_message_append_args(dmesg
,
609 DBUS_TYPE_ARRAY
, DBUS_TYPE_STRING
, &options
, num_options
,
610 DBUS_TYPE_INVALID
)) {
611 dprintf("eject %s: cannot append args to dbus message ", udi
);
612 dbus_message_unref(dmesg
);
616 dbus_error_init(error
);
617 if (!(reply
= dbus_connection_send_with_reply_and_block(dbus_conn
,
618 dmesg
, RMM_EJECT_TIMEOUT
, error
))) {
619 dprintf("eject %s: %s\n", udi
, error
->message
);
620 dbus_message_unref(dmesg
);
624 dprintf("ejected %s\n", udi
);
626 dbus_message_unref(dmesg
);
627 dbus_message_unref(reply
);
629 rmm_dbus_error_free(error
);
635 * Call HAL's CloseTray() method on the given device
638 rmm_hal_closetray(LibHalContext
*hal_ctx
, const char *udi
, DBusError
*error
)
640 DBusConnection
*dbus_conn
= libhal_ctx_get_dbus_connection(hal_ctx
);
641 DBusMessage
*dmesg
, *reply
;
642 char **options
= NULL
;
643 uint_t num_options
= 0;
645 dprintf("closing tray %s...\n", udi
);
647 if (!(dmesg
= dbus_message_new_method_call("org.freedesktop.Hal", udi
,
648 "org.freedesktop.Hal.Device.Storage", "CloseTray"))) {
650 "closetray failed for %s: cannot create dbus message\n",
655 if (!dbus_message_append_args(dmesg
,
656 DBUS_TYPE_ARRAY
, DBUS_TYPE_STRING
, &options
, num_options
,
657 DBUS_TYPE_INVALID
)) {
658 dprintf("closetray %s: cannot append args to dbus message ",
660 dbus_message_unref(dmesg
);
664 dbus_error_init(error
);
665 if (!(reply
= dbus_connection_send_with_reply_and_block(dbus_conn
,
666 dmesg
, RMM_CLOSETRAY_TIMEOUT
, error
))) {
667 dprintf("closetray failed for %s: %s\n", udi
, error
->message
);
668 dbus_message_unref(dmesg
);
672 dprintf("closetray ok %s\n", udi
);
674 dbus_message_unref(dmesg
);
675 dbus_message_unref(reply
);
677 rmm_dbus_error_free(error
);
683 * Call HAL's Rescan() method on the given device
686 rmm_hal_rescan(LibHalContext
*hal_ctx
, const char *udi
, DBusError
*error
)
688 DBusConnection
*dbus_conn
= libhal_ctx_get_dbus_connection(hal_ctx
);
689 DBusMessage
*dmesg
, *reply
;
691 dprintf("rescanning %s...\n", udi
);
693 if (!(dmesg
= dbus_message_new_method_call("org.freedesktop.Hal", udi
,
694 "org.freedesktop.Hal.Device", "Rescan"))) {
695 dprintf("rescan failed for %s: cannot create dbus message\n",
700 dbus_error_init(error
);
701 if (!(reply
= dbus_connection_send_with_reply_and_block(dbus_conn
,
702 dmesg
, -1, error
))) {
703 dprintf("rescan failed for %s: %s\n", udi
, error
->message
);
704 dbus_message_unref(dmesg
);
708 dprintf("rescan ok %s\n", udi
);
710 dbus_message_unref(dmesg
);
711 dbus_message_unref(reply
);
713 rmm_dbus_error_free(error
);
719 rmm_hal_claim_branch(LibHalContext
*hal_ctx
, const char *udi
)
722 DBusConnection
*dbus_conn
= libhal_ctx_get_dbus_connection(hal_ctx
);
723 DBusMessage
*dmesg
, *reply
;
724 const char *claimed_by
= "rmvolmgr";
726 dprintf("claiming branch %s...\n", udi
);
728 if (!(dmesg
= dbus_message_new_method_call("org.freedesktop.Hal",
729 "/org/freedesktop/Hal/Manager", "org.freedesktop.Hal.Manager",
731 dprintf("cannot create dbus message\n");
735 if (!dbus_message_append_args(dmesg
, DBUS_TYPE_STRING
, &udi
,
736 DBUS_TYPE_STRING
, &claimed_by
, DBUS_TYPE_INVALID
)) {
737 dprintf("cannot append args to dbus message\n");
738 dbus_message_unref(dmesg
);
742 dbus_error_init(&error
);
743 if (!(reply
= dbus_connection_send_with_reply_and_block(dbus_conn
,
744 dmesg
, -1, &error
))) {
745 dprintf("cannot send dbus message\n");
746 dbus_message_unref(dmesg
);
747 rmm_dbus_error_free(&error
);
751 dprintf("claim branch ok %s\n", udi
);
753 dbus_message_unref(dmesg
);
754 dbus_message_unref(reply
);
760 rmm_hal_unclaim_branch(LibHalContext
*hal_ctx
, const char *udi
)
763 DBusConnection
*dbus_conn
= libhal_ctx_get_dbus_connection(hal_ctx
);
764 DBusMessage
*dmesg
, *reply
;
765 const char *claimed_by
= "rmvolmgr";
767 dprintf("unclaiming branch %s...\n", udi
);
769 if (!(dmesg
= dbus_message_new_method_call("org.freedesktop.Hal",
770 "/org/freedesktop/Hal/Manager", "org.freedesktop.Hal.Manager",
772 dprintf("cannot create dbus message\n");
776 if (!dbus_message_append_args(dmesg
, DBUS_TYPE_STRING
, &udi
,
777 DBUS_TYPE_STRING
, &claimed_by
, DBUS_TYPE_INVALID
)) {
778 dprintf("cannot append args to dbus message\n");
779 dbus_message_unref(dmesg
);
783 dbus_error_init(&error
);
784 if (!(reply
= dbus_connection_send_with_reply_and_block(dbus_conn
,
785 dmesg
, -1, &error
))) {
786 dprintf("cannot send dbus message\n");
787 dbus_message_unref(dmesg
);
788 rmm_dbus_error_free(&error
);
792 dprintf("unclaim branch ok %s\n", udi
);
794 dbus_message_unref(dmesg
);
795 dbus_message_unref(reply
);
801 rmm_action_one(LibHalContext
*hal_ctx
, const char *name
, action_t action
,
802 const char *dev
, const char *udi
, LibHalVolume
*v
,
803 char **opts
, int num_opts
, char *mountpoint
)
805 char dev_str
[MAXPATHLEN
];
808 boolean_t ret
= B_FALSE
;
810 if (strcmp(name
, dev
) == 0) {
811 (void) snprintf(dev_str
, sizeof (dev_str
), name
);
813 (void) snprintf(dev_str
, sizeof (dev_str
), "%s %s", name
, dev
);
816 dbus_error_init(&error
);
820 ret
= rmm_hal_eject(hal_ctx
, udi
, &error
);
824 if (libhal_volume_is_mounted(v
)) {
827 ret
= rmm_hal_mount(hal_ctx
, udi
,
828 opts
, num_opts
, mountpoint
, &error
);
831 if (!libhal_volume_is_mounted(v
)) {
834 ret
= rmm_hal_unmount(hal_ctx
, udi
, &error
);
837 ret
= rmm_hal_closetray(hal_ctx
, udi
, &error
);
842 (void) fprintf(stderr
, gettext("%s of %s failed: %s\n"),
843 action_strings
[action
], dev_str
, rmm_strerror(&error
, -1));
849 (void) printf(gettext("%s ejected\n"), dev_str
);
853 mountp
= rmm_get_mnttab_mount_point(dev
);
854 if (mountp
!= NULL
) {
855 (void) printf(gettext("%s mounted at %s\n"),
861 (void) printf(gettext("%s unmounted\n"), dev_str
);
864 (void) printf(gettext("%s tray closed\n"), dev_str
);
869 rmm_dbus_error_free(&error
);
874 * top level action routine
876 * If non-null 'aa' is passed, it will be used, otherwise a local copy
880 rmm_action(LibHalContext
*hal_ctx
, const char *name
, action_t action
,
881 struct action_arg
*aap
, char **opts
, int num_opts
, char *mountpoint
)
887 const char *udi
, *d_udi
;
888 const char *dev
, *d_dev
;
889 struct action_arg aa_local
;
890 boolean_t ret
= B_FALSE
;
892 dprintf("rmm_action %s %s\n", name
, action_strings
[action
]);
895 bzero(&aa_local
, sizeof (aa_local
));
899 dbus_error_init(&error
);
901 /* find the drive and its volumes */
902 d
= rmm_hal_volume_find(hal_ctx
, name
, &error
, &volumes
);
903 rmm_dbus_error_free(&error
);
905 (void) fprintf(stderr
, gettext("cannot find '%s'\n"), name
);
908 d_udi
= libhal_drive_get_udi(d
);
909 d_dev
= libhal_drive_get_device_file(d
);
910 if ((d_udi
== NULL
) || (d_dev
== NULL
)) {
915 * For those drives that do not require media eject,
916 * EJECT turns into UNMOUNT.
918 if ((action
== EJECT
) && !libhal_drive_requires_eject(d
)) {
922 /* per drive action */
923 if ((action
== EJECT
) || (action
== CLOSETRAY
)) {
924 ret
= rmm_action_one(hal_ctx
, name
, action
, d_dev
, d_udi
, NULL
,
925 opts
, num_opts
, NULL
);
927 if (!ret
|| (action
== CLOSETRAY
)) {
932 /* per volume action */
933 for (i
= volumes
; i
!= NULL
; i
= g_slist_next(i
)) {
934 v
= (LibHalVolume
*)i
->data
;
935 udi
= libhal_volume_get_udi(v
);
936 dev
= libhal_volume_get_device_file(v
);
938 if ((udi
== NULL
) || (dev
== NULL
)) {
941 if (aap
== &aa_local
) {
942 if (!rmm_volume_aa_from_prop(hal_ctx
, udi
, v
, aap
)) {
943 dprintf("rmm_volume_aa_from_prop failed %s\n",
948 aap
->aa_action
= action
;
950 /* ejected above, just need postprocess */
951 if (action
!= EJECT
) {
952 ret
= rmm_action_one(hal_ctx
, name
, action
, dev
, udi
, v
,
953 opts
, num_opts
, mountpoint
);
956 (void) vold_postprocess(hal_ctx
, udi
, aap
);
959 if (aap
== &aa_local
) {
960 rmm_volume_aa_free(aap
);
965 rmm_volumes_free(volumes
);
966 libhal_drive_free(d
);
974 * if name is NULL, rescan all drives
977 rmm_rescan(LibHalContext
*hal_ctx
, const char *name
, boolean_t query
)
981 LibHalDrive
*drive
= NULL
;
982 const char *drive_udi
;
987 boolean_t do_free_udis
= FALSE
;
989 boolean_t ret
= B_FALSE
;
991 dprintf("rmm_rescan %s\n", name
!= NULL
? name
: "all");
993 dbus_error_init(&error
);
996 if ((drive
= rmm_hal_volume_find(hal_ctx
, name
, &error
,
997 &volumes
)) == NULL
) {
998 rmm_dbus_error_free(&error
);
999 (void) fprintf(stderr
,
1000 gettext("cannot find '%s'\n"), name
);
1003 rmm_dbus_error_free(&error
);
1004 g_slist_free(volumes
);
1006 drive_udi
= libhal_drive_get_udi(drive
);
1007 udis
= (char **)&drive_udi
;
1010 if ((udis
= libhal_find_device_by_capability(hal_ctx
,
1011 "storage", &num_udis
, &error
)) == NULL
) {
1012 rmm_dbus_error_free(&error
);
1015 rmm_dbus_error_free(&error
);
1016 do_free_udis
= TRUE
;
1019 for (i
= 0; i
< num_udis
; i
++) {
1021 nicks
= libhal_device_get_property_strlist(hal_ctx
,
1022 udis
[i
], "storage.solaris.nicknames", NULL
);
1023 if (nicks
!= NULL
) {
1024 nickname
= nicks
[0];
1029 if (!(ret
= rmm_hal_rescan(hal_ctx
, udis
[i
], &error
))) {
1030 (void) fprintf(stderr
,
1031 gettext("rescan of %s failed: %s\n"),
1032 name
? name
: nickname
,
1033 rmm_strerror(&error
, -1));
1034 libhal_free_string_array(nicks
);
1038 ret
= libhal_device_get_property_bool(hal_ctx
, udis
[i
],
1039 "storage.removable.media_available", NULL
);
1041 printf(gettext("%s is available\n"),
1042 name
? name
: nickname
);
1044 printf(gettext("%s is not available\n"),
1045 name
? name
: nickname
);
1048 libhal_free_string_array(nicks
);
1051 if (drive
!= NULL
) {
1052 libhal_drive_free(drive
);
1055 libhal_free_string_array(udis
);
1063 * set action_arg from volume properties
1066 rmm_volume_aa_from_prop(LibHalContext
*hal_ctx
, const char *udi_arg
,
1067 LibHalVolume
*volume_arg
, struct action_arg
*aap
)
1069 LibHalVolume
*volume
= volume_arg
;
1070 const char *udi
= udi_arg
;
1071 const char *drive_udi
;
1077 /* at least udi or volume must be supplied */
1078 if ((udi
== NULL
) && (volume
== NULL
)) {
1081 if (volume
== NULL
) {
1082 if ((volume
= libhal_volume_from_udi(hal_ctx
, udi
)) == NULL
) {
1083 dprintf("cannot get volume %s\n", udi
);
1088 if ((udi
= libhal_volume_get_udi(volume
)) == NULL
) {
1089 dprintf("cannot get udi\n");
1093 drive_udi
= libhal_volume_get_storage_device_udi(volume
);
1095 if (!(aap
->aa_symdev
= libhal_device_get_property_string(hal_ctx
,
1096 drive_udi
, "storage.solaris.legacy.symdev", NULL
))) {
1097 dprintf("property %s not found %s\n",
1098 "storage.solaris.legacy.symdev", drive_udi
);
1101 if (!(aap
->aa_media
= libhal_device_get_property_string(hal_ctx
,
1102 drive_udi
, "storage.solaris.legacy.media_type", NULL
))) {
1103 dprintf("property %s not found %s\n",
1104 "storage.solaris.legacy.media_type", drive_udi
);
1108 /* name is derived from volume label */
1109 aap
->aa_name
= NULL
;
1110 if ((volume_label
= (char *)libhal_device_get_property_string(hal_ctx
,
1111 udi
, "volume.label", NULL
)) != NULL
) {
1112 if ((len
= strlen(volume_label
)) > 0) {
1113 aap
->aa_name
= rmm_vold_convert_volume_label(
1115 if (strlen(aap
->aa_name
) == 0) {
1117 aap
->aa_name
= NULL
;
1120 libhal_free_string(volume_label
);
1122 /* if no label, then unnamed_<mediatype> */
1123 if (aap
->aa_name
== NULL
) {
1124 aap
->aa_name
= (char *)calloc(1, sizeof ("unnamed_floppyNNNN"));
1125 if (aap
->aa_name
== NULL
) {
1128 (void) snprintf(aap
->aa_name
, sizeof ("unnamed_floppyNNNN"),
1129 "unnamed_%s", aap
->aa_media
);
1132 if (!(aap
->aa_path
= libhal_device_get_property_string(hal_ctx
, udi
,
1133 "block.device", NULL
))) {
1134 dprintf("property %s not found %s\n", "block.device", udi
);
1137 if (!(aap
->aa_rawpath
= libhal_device_get_property_string(hal_ctx
, udi
,
1138 "block.solaris.raw_device", NULL
))) {
1139 dprintf("property %s not found %s\n",
1140 "block.solaris.raw_device", udi
);
1143 if (!(aap
->aa_type
= libhal_device_get_property_string(hal_ctx
, udi
,
1144 "volume.fstype", NULL
))) {
1145 dprintf("property %s not found %s\n", "volume.fstype", udi
);
1148 if (!libhal_device_get_property_bool(hal_ctx
, udi
,
1149 "volume.is_partition", NULL
)) {
1150 aap
->aa_partname
= NULL
;
1151 } else if (!(aap
->aa_partname
= libhal_device_get_property_string(
1152 hal_ctx
, udi
, "block.solaris.slice", NULL
))) {
1153 dprintf("property %s not found %s\n",
1154 "block.solaris.slice", udi
);
1157 if (!(mountpoint
= libhal_device_get_property_string(hal_ctx
, udi
,
1158 "volume.mount_point", NULL
))) {
1159 dprintf("property %s not found %s\n",
1160 "volume.mount_point", udi
);
1164 * aa_mountpoint can be reallocated in rmm_volume_aa_update_mountpoint()
1165 * won't have to choose between free() or libhal_free_string() later on
1167 aap
->aa_mountpoint
= strdup(mountpoint
);
1168 libhal_free_string(mountpoint
);
1169 if (aap
->aa_mountpoint
== NULL
) {
1170 dprintf("mountpoint is NULL %s\n", udi
);
1177 if ((volume
!= NULL
) && (volume
!= volume_arg
)) {
1178 libhal_volume_free(volume
);
1181 rmm_volume_aa_free(aap
);
1188 rmm_volume_aa_update_mountpoint(LibHalContext
*hal_ctx
, const char *udi
,
1189 struct action_arg
*aap
)
1191 if (aap
->aa_mountpoint
!= NULL
) {
1192 free(aap
->aa_mountpoint
);
1194 aap
->aa_mountpoint
= rmm_get_mnttab_mount_point(aap
->aa_path
);
1198 rmm_volume_aa_free(struct action_arg
*aap
)
1200 if (aap
->aa_symdev
!= NULL
) {
1201 libhal_free_string(aap
->aa_symdev
);
1202 aap
->aa_symdev
= NULL
;
1204 if (aap
->aa_name
!= NULL
) {
1206 aap
->aa_name
= NULL
;
1208 if (aap
->aa_path
!= NULL
) {
1209 libhal_free_string(aap
->aa_path
);
1210 aap
->aa_path
= NULL
;
1212 if (aap
->aa_rawpath
!= NULL
) {
1213 libhal_free_string(aap
->aa_rawpath
);
1214 aap
->aa_rawpath
= NULL
;
1216 if (aap
->aa_type
!= NULL
) {
1217 libhal_free_string(aap
->aa_type
);
1218 aap
->aa_type
= NULL
;
1220 if (aap
->aa_media
!= NULL
) {
1221 libhal_free_string(aap
->aa_media
);
1222 aap
->aa_media
= NULL
;
1224 if (aap
->aa_partname
!= NULL
) {
1225 libhal_free_string(aap
->aa_partname
);
1226 aap
->aa_partname
= NULL
;
1228 if (aap
->aa_mountpoint
!= NULL
) {
1229 free(aap
->aa_mountpoint
);
1230 aap
->aa_mountpoint
= NULL
;
1235 * get device's mount point from mnttab
1238 rmm_get_mnttab_mount_point(const char *special
)
1240 char *mount_point
= NULL
;
1243 struct mnttab mpref
= { NULL
, NULL
, NULL
, NULL
, NULL
};
1245 if ((f
= fopen(MNTTAB
, "r")) != NULL
) {
1246 mpref
.mnt_special
= (char *)special
;
1247 if (getmntany(f
, &mnt
, &mpref
) == 0) {
1248 mount_point
= strdup(mnt
.mnt_mountp
);
1253 return (mount_point
);
1258 * get human readable string from error values
1261 rmm_strerror(DBusError
*dbus_error
, int rmm_error
)
1265 if ((dbus_error
!= NULL
) && dbus_error_is_set(dbus_error
)) {
1266 str
= dbus_error
->message
;
1268 switch (rmm_error
) {
1270 str
= gettext("success");
1272 case RMM_EDBUS_CONNECT
:
1273 str
= gettext("cannot connect to D-Bus");
1275 case RMM_EHAL_CONNECT
:
1276 str
= gettext("cannot connect to HAL");
1279 str
= gettext("undefined error");
1288 rmm_dbus_error_free(DBusError
*error
)
1290 if (error
!= NULL
&& dbus_error_is_set(error
)) {
1291 dbus_error_free(error
);
1296 rmm_vold_isbadchar(int c
)
1308 if (iscntrl(c
) || isspace(c
)) {
1317 rmm_vold_convert_volume_label(const char *name
, size_t len
)
1319 char buf
[MAXNAMELEN
+1];
1323 if (len
> MAXNAMELEN
) {
1327 for (i
= 0; i
< len
; i
++) {
1328 if (name
[i
] == '\0') {
1331 if (isgraph((int)name
[i
])) {
1332 if (isupper((int)name
[i
])) {
1333 *s
++ = tolower((int)name
[i
]);
1334 } else if (rmm_vold_isbadchar((int)name
[i
])) {
1348 * swiped from mkdir.c
1351 makepath(char *dir
, mode_t mode
)
1357 if ((mkdir(dir
, mode
) == 0) || (errno
== EEXIST
)) {
1360 if (errno
!= ENOENT
) {
1363 if ((slash
= strrchr(dir
, '/')) == NULL
) {
1367 err
= makepath(dir
, mode
);
1370 if (err
|| (*slash
== '\0')) {
1374 return (mkdir(dir
, mode
));
1379 dprintf(const char *fmt
, ...)
1385 char *errmsg
= strerror(errno
);
1388 if (rmm_debug
== 0) {
1392 (void) memset(msg
, 0, BUFSIZ
);
1394 /* scan for %m and replace with errno msg */
1395 s
= &msg
[strlen(msg
)];
1398 while (*p
!= '\0') {
1399 if ((*p
== '%') && (*(p
+1) == 'm')) {
1400 (void) strcat(s
, errmsg
);
1402 s
+= strlen(errmsg
);
1407 *s
= '\0'; /* don't forget the null byte */
1410 (void) vfprintf(stderr
, msg
, ap
);