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.
32 #include <sys/types.h>
41 #include <sys/syscall.h>
43 #include <priv_utils.h>
45 #include <dbus/dbus.h>
46 #include <dbus/dbus-glib.h>
47 #include <dbus/dbus-glib-lowlevel.h>
50 #include "rmm_common.h"
52 char *progname
= "rmvolmgr";
54 #define RMVOLMGR_FMRI "svc:/system/filesystem/rmvolmgr:default"
56 typedef struct managed_volume
{
62 static GSList
*managed_volumes
;
64 static GMainLoop
*mainloop
;
65 static LibHalContext
*hal_ctx
;
66 static int sigexit_pipe
[2];
67 static GIOChannel
*sigexit_ioch
;
69 static boolean_t opt_c
; /* disable CDE compatibility */
70 static boolean_t opt_n
; /* disable legacy mountpoint symlinks */
71 static boolean_t opt_s
; /* system instance */
73 /* SMF property "eject_button" */
74 static boolean_t rmm_prop_eject_button
= B_TRUE
;
76 static void get_smf_properties();
77 static void rmm_device_added(LibHalContext
*ctx
, const char *udi
);
78 static void rmm_device_removed(LibHalContext
*ctx
, const char *udi
);
79 static void rmm_property_modified(LibHalContext
*ctx
, const char *udi
,
80 const char *key
, dbus_bool_t is_removed
, dbus_bool_t is_added
);
81 static void rmm_device_condition(LibHalContext
*ctx
, const char *udi
,
82 const char *name
, const char *detail
);
83 static void rmm_mount_all();
84 static void rmm_unmount_all();
85 static void sigexit(int signo
);
86 static gboolean
sigexit_ioch_func(GIOChannel
*source
, GIOCondition condition
,
92 (void) fprintf(stderr
, gettext("\nusage: rmvolmgr [-v]\n"));
96 rmvolmgr(int argc
, char **argv
)
98 const char *opts
= "chnsv";
101 rmm_error_t rmm_error
;
104 while ((c
= getopt(argc
, argv
, opts
)) != EOF
) {
129 if (geteuid() != 0) {
130 (void) fprintf(stderr
,
131 gettext("system instance must have euid 0\n"));
135 get_smf_properties();
138 rmm_vold_actions_enabled
= B_FALSE
;
141 rmm_vold_mountpoints_enabled
= B_FALSE
;
146 * Drop unused privileges. Remain root for HAL interaction
147 * and to create legacy symlinks.
149 * Need PRIV_FILE_DAC_WRITE to write to users'
150 * /tmp/.removable/notify* files.
152 if (__init_daemon_priv(PU_RESETGROUPS
|PU_CLEARLIMITSET
,
154 rmm_vold_actions_enabled
? PRIV_FILE_DAC_WRITE
: NULL
,
156 (void) fprintf(stderr
,
157 gettext("failed to drop privileges"));
160 /* basic privileges we don't need */
161 (void) priv_set(PRIV_OFF
, PRIV_PERMITTED
, PRIV_PROC_EXEC
,
162 PRIV_PROC_INFO
, PRIV_FILE_LINK_ANY
, PRIV_PROC_SESSION
,
167 rmm_vold_actions_enabled
= B_FALSE
;
170 rmm_vold_mountpoints_enabled
= B_FALSE
;
174 daemonize
= (getenv("RMVOLMGR_NODAEMON") == NULL
);
176 if (daemonize
&& daemon(0, 0) < 0) {
177 dprintf("daemonizing failed: %s", strerror(errno
));
182 __fini_daemon_priv(PRIV_PROC_FORK
, NULL
);
186 * signal mainloop integration using pipes
188 if (pipe(sigexit_pipe
) != 0) {
189 dprintf("pipe failed %s\n", strerror(errno
));
192 sigexit_ioch
= g_io_channel_unix_new(sigexit_pipe
[0]);
193 if (sigexit_ioch
== NULL
) {
194 dprintf("g_io_channel_unix_new failed\n");
197 g_io_add_watch(sigexit_ioch
, G_IO_IN
, sigexit_ioch_func
, NULL
);
198 signal(SIGTERM
, sigexit
);
199 signal(SIGINT
, sigexit
);
200 signal(SIGHUP
, SIG_IGN
);
201 signal(SIGUSR1
, SIG_IGN
);
202 signal(SIGUSR2
, SIG_IGN
);
204 if ((hal_ctx
= rmm_hal_init(rmm_device_added
, rmm_device_removed
,
205 rmm_property_modified
, rmm_device_condition
,
206 &error
, &rmm_error
)) == NULL
) {
207 dbus_error_free(&error
);
211 /* user instance should claim devices */
213 if (!rmm_hal_claim_branch(hal_ctx
, HAL_BRANCH_LOCAL
)) {
214 (void) fprintf(stderr
,
215 gettext("cannot claim branch\n"));
222 if ((mainloop
= g_main_loop_new(NULL
, B_FALSE
)) == NULL
) {
223 dprintf("Cannot create main loop\n");
227 g_main_loop_run(mainloop
);
235 scf_simple_prop_t
*prop
;
238 if ((prop
= scf_simple_prop_get(NULL
, RMVOLMGR_FMRI
,
239 "rmvolmgr", "legacy_mountpoints")) != NULL
) {
240 if ((val
= scf_simple_prop_next_boolean(prop
)) != NULL
) {
241 rmm_vold_mountpoints_enabled
= (*val
!= 0);
243 scf_simple_prop_free(prop
);
246 if ((prop
= scf_simple_prop_get(NULL
, RMVOLMGR_FMRI
,
247 "rmvolmgr", "cde_compatible")) != NULL
) {
248 if ((val
= scf_simple_prop_next_boolean(prop
)) != NULL
) {
249 rmm_vold_actions_enabled
= (*val
!= 0);
251 scf_simple_prop_free(prop
);
254 if ((prop
= scf_simple_prop_get(NULL
, RMVOLMGR_FMRI
,
255 "rmvolmgr", "eject_button")) != NULL
) {
256 if ((val
= scf_simple_prop_next_boolean(prop
)) != NULL
) {
257 rmm_prop_eject_button
= (*val
!= 0);
259 scf_simple_prop_free(prop
);
267 dprintf("signal to exit %d\n", signo
);
269 write(sigexit_pipe
[1], "s", 1);
274 sigexit_ioch_func(GIOChannel
*source
, GIOCondition condition
,
279 GError
*error
= NULL
;
281 if (g_io_channel_read_chars(source
, buf
, 1, &bytes_read
, &error
) !=
282 G_IO_STATUS_NORMAL
) {
283 dprintf("g_io_channel_read_chars failed %s", error
->message
);
288 dprintf("signal to exit\n");
292 g_main_loop_quit(mainloop
);
297 static managed_volume_t
*
298 rmm_managed_alloc(LibHalContext
*ctx
, const char *udi
)
302 if ((v
= calloc(1, sizeof (managed_volume_t
))) == NULL
) {
305 if ((v
->udi
= strdup(udi
)) == NULL
) {
309 if (!rmm_volume_aa_from_prop(ctx
, udi
, NULL
, &v
->aa
)) {
319 rmm_managed_free(managed_volume_t
*v
)
321 rmm_volume_aa_free(&v
->aa
);
327 rmm_managed_compare_udi(gconstpointer a
, gconstpointer b
)
329 const managed_volume_t
*va
= a
;
332 return (strcmp(va
->udi
, udi
));
336 volume_should_mount(const char *udi
)
338 char *storage_device
= NULL
;
341 if (libhal_device_get_property_bool(hal_ctx
, udi
,
342 "volume.ignore", NULL
)) {
346 /* get the backing storage device */
347 if (!(storage_device
= libhal_device_get_property_string(hal_ctx
, udi
,
348 "block.storage_device", NULL
))) {
349 dprintf("cannot get block.storage_device\n");
353 /* we handle either removable or hotpluggable */
354 if (!libhal_device_get_property_bool(hal_ctx
, storage_device
,
355 "storage.removable", NULL
) &&
356 !libhal_device_get_property_bool(hal_ctx
, storage_device
,
357 "storage.hotpluggable", NULL
)) {
361 /* ignore if claimed by another volume manager */
362 if (libhal_device_get_property_bool(hal_ctx
, storage_device
,
363 "info.claimed", NULL
)) {
370 libhal_free_string(storage_device
);
375 volume_added(const char *udi
)
380 dprintf("volume added %s\n", udi
);
382 l
= g_slist_find_custom(managed_volumes
, udi
, rmm_managed_compare_udi
);
383 v
= (l
!= NULL
) ? l
->data
: NULL
;
386 dprintf("already managed %s\n", udi
);
389 if (!volume_should_mount(udi
)) {
390 dprintf("should not mount %s\n", udi
);
393 if ((v
= rmm_managed_alloc(hal_ctx
, udi
)) == NULL
) {
396 if (rmm_action(hal_ctx
, udi
, INSERT
, &v
->aa
, 0, 0, 0)) {
398 managed_volumes
= g_slist_prepend(managed_volumes
, v
);
400 dprintf("rmm_action failed %s\n", udi
);
406 volume_removed(const char *udi
)
411 dprintf("volume removed %s\n", udi
);
413 l
= g_slist_find_custom(managed_volumes
, udi
, rmm_managed_compare_udi
);
414 v
= (l
!= NULL
) ? l
->data
: NULL
;
419 /* HAL will unmount, just do the vold legacy stuff */
420 v
->aa
.aa_action
= EJECT
;
421 (void) vold_postprocess(hal_ctx
, udi
, &v
->aa
);
424 managed_volumes
= g_slist_delete_link(managed_volumes
, l
);
429 rmm_device_added(LibHalContext
*ctx
, const char *udi
)
431 if (libhal_device_query_capability(hal_ctx
, udi
, "volume", NULL
)) {
438 rmm_device_removed(LibHalContext
*ctx
, const char *udi
)
440 if (libhal_device_query_capability(hal_ctx
, udi
, "volume", NULL
)) {
447 rmm_property_modified(LibHalContext
*ctx
, const char *udi
, const char *key
,
448 dbus_bool_t is_removed
, dbus_bool_t is_added
)
453 boolean_t is_mounted
;
455 if (strcmp(key
, "volume.is_mounted") != 0) {
458 is_mounted
= libhal_device_get_property_bool(hal_ctx
, udi
, key
, NULL
);
460 l
= g_slist_find_custom(managed_volumes
, udi
, rmm_managed_compare_udi
);
461 v
= (l
!= NULL
) ? l
->data
: NULL
;
464 dprintf("Mounted: %s\n", udi
);
467 /* volume mounted by us is already taken care of */
472 if ((v
= rmm_managed_alloc(ctx
, udi
)) == NULL
) {
475 managed_volumes
= g_slist_prepend(managed_volumes
, v
);
478 v
->aa
.aa_action
= INSERT
;
479 (void) vold_postprocess(hal_ctx
, udi
, &v
->aa
);
482 dprintf("Unmounted: %s\n", udi
);
488 v
->aa
.aa_action
= EJECT
;
489 (void) vold_postprocess(hal_ctx
, udi
, &v
->aa
);
492 managed_volumes
= g_slist_delete_link(managed_volumes
, l
);
497 storage_eject_pressed(const char *udi
)
501 /* ignore if disabled via SMF or claimed by another volume manager */
502 if (!rmm_prop_eject_button
||
503 libhal_device_get_property_bool(hal_ctx
, udi
, "info.claimed",
508 dbus_error_init(&error
);
509 (void) rmm_hal_eject(hal_ctx
, udi
, &error
);
510 rmm_dbus_error_free(&error
);
515 rmm_device_condition(LibHalContext
*ctx
, const char *udi
,
516 const char *name
, const char *detail
)
518 if ((strcmp(name
, "EjectPressed") == 0) &&
519 libhal_device_query_capability(hal_ctx
, udi
, "storage", NULL
)) {
520 storage_eject_pressed(udi
);
525 * Mount all mountable volumes
536 dbus_error_init(&error
);
538 /* get all volumes */
539 if ((udis
= libhal_find_device_by_capability(hal_ctx
, "volume",
540 &num_udis
, &error
)) == NULL
) {
541 dprintf("mount_all: no volumes found\n");
545 for (i
= 0; i
< num_udis
; i
++) {
546 /* skip if already mounted */
547 if (libhal_device_get_property_bool(hal_ctx
, udis
[i
],
548 "volume.is_mounted", NULL
)) {
549 dprintf("mount_all: %s already mounted\n", udis
[i
]);
552 if (!volume_should_mount(udis
[i
])) {
555 if ((v
= rmm_managed_alloc(hal_ctx
, udis
[i
])) == NULL
) {
558 if (rmm_action(hal_ctx
, udis
[i
], INSERT
, &v
->aa
, 0, 0, 0)) {
560 managed_volumes
= g_slist_prepend(managed_volumes
, v
);
568 libhal_free_string_array(udis
);
570 rmm_dbus_error_free(&error
);
574 * Mount all volumes mounted by this program
582 for (i
= managed_volumes
; i
!= NULL
; i
= managed_volumes
) {
583 v
= (managed_volume_t
*)i
->data
;
585 if (v
->my
&& libhal_device_get_property_bool(hal_ctx
, v
->udi
,
586 "volume.is_mounted", NULL
)) {
587 (void) rmm_action(hal_ctx
, v
->udi
, UNMOUNT
,
591 managed_volumes
= g_slist_remove(managed_volumes
, v
);
597 main(int argc
, char **argv
)
599 vold_init(argc
, argv
);
601 return (rmvolmgr(argc
, argv
));