xref: /illumos-gate/usr/src/cmd/rmvolmgr/rmm_common.c (revision 541dca7e13d4dc4a2c80da05484accd283b3fe88)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdio.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <strings.h>
30 #include <stdarg.h>
31 #include <fcntl.h>
32 #include <libintl.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <ctype.h>
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/mnttab.h>
40 
41 #include <dbus/dbus.h>
42 #include <dbus/dbus-glib.h>
43 #include <dbus/dbus-glib-lowlevel.h>
44 #include <libhal.h>
45 #include <libhal-storage.h>
46 
47 #include "rmm_common.h"
48 
49 #define	RMM_PRINT_DEVICE_WIDTH	20
50 
51 extern int rmm_debug;
52 
53 static const char *action_strings[] = {
54 	"eject",
55 	"mount",
56 	"remount",
57 	"unmount",
58 	"clear_mounts",
59 	"closetray"
60 };
61 
62 
63 LibHalContext *
rmm_hal_init(LibHalDeviceAdded devadd_cb,LibHalDeviceRemoved devrem_cb,LibHalDevicePropertyModified propmod_cb,LibHalDeviceCondition cond_cb,DBusError * error,rmm_error_t * rmm_error)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)
67 {
68 	DBusConnection	*dbus_conn;
69 	LibHalContext	*ctx;
70 	char		**devices;
71 	int		nr;
72 
73 	dbus_error_init(error);
74 
75 	/*
76 	 * setup D-Bus connection
77 	 */
78 	if (!(dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, error))) {
79 		dbgprintf("cannot get system bus: %s\n",
80 		    rmm_strerror(error, -1));
81 		*rmm_error = RMM_EDBUS_CONNECT;
82 		return (NULL);
83 	}
84 	rmm_dbus_error_free(error);
85 
86 	dbus_connection_setup_with_g_main(dbus_conn, NULL);
87 	dbus_connection_set_exit_on_disconnect(dbus_conn, B_TRUE);
88 
89 	if ((ctx = libhal_ctx_new()) == NULL) {
90 		dbgprintf("libhal_ctx_new failed");
91 		*rmm_error = RMM_EHAL_CONNECT;
92 		return (NULL);
93 	}
94 
95 	libhal_ctx_set_dbus_connection(ctx, dbus_conn);
96 
97 	/*
98 	 * register callbacks
99 	 */
100 	if (devadd_cb != NULL) {
101 		libhal_ctx_set_device_added(ctx, devadd_cb);
102 	}
103 	if (devrem_cb != NULL) {
104 		libhal_ctx_set_device_removed(ctx, devrem_cb);
105 	}
106 	if (propmod_cb != NULL) {
107 		libhal_ctx_set_device_property_modified(ctx, propmod_cb);
108 		if (!libhal_device_property_watch_all(ctx, error)) {
109 			dbgprintf("property_watch_all failed %s",
110 			    rmm_strerror(error, -1));
111 			libhal_ctx_free(ctx);
112 			*rmm_error = RMM_EHAL_CONNECT;
113 			return (NULL);
114 		}
115 	}
116 	if (cond_cb != NULL) {
117 		libhal_ctx_set_device_condition(ctx, cond_cb);
118 	}
119 
120 	if (!libhal_ctx_init(ctx, error)) {
121 		dbgprintf("libhal_ctx_init failed: %s",
122 		    rmm_strerror(error, -1));
123 		libhal_ctx_free(ctx);
124 		*rmm_error = RMM_EHAL_CONNECT;
125 		return (NULL);
126 	}
127 	rmm_dbus_error_free(error);
128 
129 	/*
130 	 * The above functions do not guarantee that HAL is actually running.
131 	 * Check by invoking a method.
132 	 */
133 	if (!(devices = libhal_get_all_devices(ctx, &nr, error))) {
134 		dbgprintf("HAL is not running: %s", rmm_strerror(error, -1));
135 		libhal_ctx_shutdown(ctx, NULL);
136 		libhal_ctx_free(ctx);
137 		*rmm_error = RMM_EHAL_CONNECT;
138 		return (NULL);
139 	} else {
140 		rmm_dbus_error_free(error);
141 		libhal_free_string_array(devices);
142 	}
143 
144 	return (ctx);
145 }
146 
147 
148 void
rmm_hal_fini(LibHalContext * hal_ctx)149 rmm_hal_fini(LibHalContext *hal_ctx)
150 {
151 	DBusConnection	*dbus_conn = libhal_ctx_get_dbus_connection(hal_ctx);
152 
153 	(void) dbus_connection_unref(dbus_conn);
154 	(void) libhal_ctx_free(hal_ctx);
155 }
156 
157 
158 /*
159  * find volume from any type of name, similar to the old media_findname()
160  * returns the LibHalDrive object and a list of LibHalVolume objects.
161  */
162 LibHalDrive *
rmm_hal_volume_find(LibHalContext * hal_ctx,const char * name,DBusError * error,GSList ** volumes)163 rmm_hal_volume_find(LibHalContext *hal_ctx, const char *name, DBusError *error,
164     GSList **volumes)
165 {
166 	LibHalDrive	*drive;
167 	char		*p;
168 	char		lastc;
169 
170 	*volumes = NULL;
171 
172 	/* temporarily remove trailing slash */
173 	p = (char *)name + strlen(name) - 1;
174 	if (*p == '/') {
175 		lastc = *p;
176 		*p = '\0';
177 	} else {
178 		p = NULL;
179 	}
180 
181 	if (name[0] == '/') {
182 		if (((drive = rmm_hal_volume_findby(hal_ctx,
183 		    "info.udi", name, volumes)) != NULL) ||
184 		    ((drive = rmm_hal_volume_findby(hal_ctx,
185 		    "block.device", name, volumes)) != NULL) ||
186 		    ((drive = rmm_hal_volume_findby(hal_ctx,
187 		    "block.solaris.raw_device", name, volumes)) != NULL) ||
188 		    ((drive = rmm_hal_volume_findby(hal_ctx,
189 		    "volume.mount_point", name, volumes)) != NULL)) {
190 			goto out;
191 		} else {
192 			goto out;
193 		}
194 	}
195 
196 	/* try volume label */
197 	if ((drive = rmm_hal_volume_findby(hal_ctx,
198 	    "volume.label", name, volumes)) != NULL) {
199 		goto out;
200 	}
201 
202 	drive = rmm_hal_volume_findby_nickname(hal_ctx, name, volumes);
203 
204 out:
205 	if (p != NULL) {
206 		*p = lastc;
207 	}
208 	return (drive);
209 }
210 
211 /*
212  * find default volume. Returns volume pointer and name in 'name'.
213  */
214 LibHalDrive *
rmm_hal_volume_find_default(LibHalContext * hal_ctx,DBusError * error,const char ** name_out,GSList ** volumes)215 rmm_hal_volume_find_default(LibHalContext *hal_ctx, DBusError *error,
216     const char **name_out, GSList **volumes)
217 {
218 	LibHalDrive	*drive;
219 	static const char *names[] = { "floppy", "cdrom", "rmdisk" };
220 	int		i;
221 
222 	*volumes = NULL;
223 
224 	for (i = 0; i < NELEM(names); i++) {
225 		if ((drive = rmm_hal_volume_findby_nickname(hal_ctx,
226 		    names[i], volumes)) != NULL) {
227 			/*
228 			 * Skip floppy if it has no media.
229 			 * XXX might want to actually check for media
230 			 * every time instead of relying on volcheck.
231 			 */
232 			if ((strcmp(names[i], "floppy") != 0) ||
233 			    libhal_device_get_property_bool(hal_ctx,
234 			    libhal_drive_get_udi(drive),
235 			    "storage.removable.media_available", NULL)) {
236 				*name_out = names[i];
237 				break;
238 			}
239 		}
240 		rmm_dbus_error_free(error);
241 	}
242 
243 	return (drive);
244 }
245 
246 /*
247  * find volume by property=value
248  * returns the LibHalDrive object and a list of LibHalVolume objects.
249  * XXX add support for multiple properties, reduce D-Bus traffic
250  */
251 LibHalDrive *
rmm_hal_volume_findby(LibHalContext * hal_ctx,const char * property,const char * value,GSList ** volumes)252 rmm_hal_volume_findby(LibHalContext *hal_ctx, const char *property,
253     const char *value, GSList **volumes)
254 {
255 	DBusError	error;
256 	LibHalDrive	*drive = NULL;
257 	LibHalVolume	*v = NULL;
258 	char		**udis;
259 	int		num_udis;
260 	int		i;
261 	int		i_drive = -1;
262 
263 	*volumes = NULL;
264 
265 	dbus_error_init(&error);
266 
267 	/* get all devices with property=value */
268 	if ((udis = libhal_manager_find_device_string_match(hal_ctx, property,
269 	    value, &num_udis, &error)) == NULL) {
270 		rmm_dbus_error_free(&error);
271 		return (NULL);
272 	}
273 
274 	/* find volumes and drives among these devices */
275 	for (i = 0; i < num_udis; i++) {
276 		rmm_dbus_error_free(&error);
277 		if (libhal_device_query_capability(hal_ctx, udis[i], "volume",
278 		    &error)) {
279 			v = libhal_volume_from_udi(hal_ctx, udis[i]);
280 			if (v != NULL) {
281 				*volumes = g_slist_prepend(*volumes, v);
282 			}
283 		} else if ((*volumes == NULL) &&
284 		    libhal_device_query_capability(hal_ctx, udis[i], "storage",
285 		    &error)) {
286 			i_drive = i;
287 		}
288 	}
289 
290 	if (*volumes != NULL) {
291 		/* used prepend, preserve original order */
292 		*volumes = g_slist_reverse(*volumes);
293 
294 		v = (LibHalVolume *)(*volumes)->data;
295 		drive = libhal_drive_from_udi(hal_ctx,
296 		    libhal_volume_get_storage_device_udi(v));
297 		if (drive == NULL) {
298 			rmm_volumes_free (*volumes);
299 			*volumes = NULL;
300 		}
301 	} else if (i_drive >= 0) {
302 		drive = libhal_drive_from_udi(hal_ctx, udis[i_drive]);
303 	}
304 
305 	libhal_free_string_array(udis);
306 	rmm_dbus_error_free(&error);
307 
308 	return (drive);
309 }
310 
311 static void
rmm_print_nicknames_one(LibHalDrive * d,LibHalVolume * v,const char * device,char ** drive_nicknames)312 rmm_print_nicknames_one(LibHalDrive *d, LibHalVolume *v,
313     const char *device, char **drive_nicknames)
314 {
315 	const char	*volume_label = NULL;
316 	const char	*mount_point = NULL;
317 	boolean_t	comma;
318 	int		i;
319 
320 	(void) printf("%-*s ", RMM_PRINT_DEVICE_WIDTH, device);
321 	comma = B_FALSE;
322 
323 	if (drive_nicknames != NULL) {
324 		for (i = 0; drive_nicknames[i] != NULL; i++) {
325 			(void) printf("%s%s", comma ? "," : "",
326 			    drive_nicknames[i]);
327 			comma = B_TRUE;
328 		}
329 	}
330 
331 	if ((v != NULL) &&
332 	    ((volume_label = libhal_volume_get_label(v)) != NULL) &&
333 	    (strlen(volume_label) > 0)) {
334 		(void) printf("%s%s", comma ? "," : "", volume_label);
335 		comma = B_TRUE;
336 	}
337 
338 	if ((v != NULL) &&
339 	    ((mount_point = libhal_volume_get_mount_point(v)) != NULL) &&
340 	    (strlen(mount_point) > 0)) {
341 		(void) printf("%s%s", comma ? "," : "", mount_point);
342 		comma = B_TRUE;
343 	}
344 
345 	(void) printf("\n");
346 }
347 
348 /*
349  * print nicknames for each available volume
350  *
351  * print_mask:
352  *   RMM_PRINT_MOUNTABLE	print only mountable volumes
353  *   RMM_PRINT_EJECTABLE	print volume-less ejectable drives
354  */
355 void
rmm_print_volume_nicknames(LibHalContext * hal_ctx,DBusError * error,int print_mask)356 rmm_print_volume_nicknames(LibHalContext *hal_ctx, DBusError *error,
357     int print_mask)
358 {
359 	char		**udis;
360 	int		num_udis;
361 	GSList		*volumes = NULL;
362 	LibHalDrive	*d, *d_tmp;
363 	LibHalVolume	*v;
364 	const char	*device;
365 	char		**nicknames;
366 	int		i;
367 	GSList		*j;
368 	int		nprinted;
369 
370 	dbus_error_init(error);
371 
372 	if ((udis = libhal_find_device_by_capability(hal_ctx, "storage",
373 	    &num_udis, error)) == NULL) {
374 		rmm_dbus_error_free(error);
375 		return;
376 	}
377 
378 	for (i = 0; i < num_udis; i++) {
379 		if ((d = libhal_drive_from_udi(hal_ctx, udis[i])) == NULL) {
380 			continue;
381 		}
382 
383 		/* find volumes belonging to this drive */
384 		if ((d_tmp = rmm_hal_volume_findby(hal_ctx,
385 		    "block.storage_device", udis[i], &volumes)) != NULL) {
386 			libhal_drive_free(d_tmp);
387 		}
388 
389 		nicknames = libhal_device_get_property_strlist(hal_ctx,
390 		    udis[i], "storage.solaris.nicknames", NULL);
391 
392 		nprinted = 0;
393 		for (j = volumes; j != NULL; j = g_slist_next(j)) {
394 			v = (LibHalVolume *)(j->data);
395 
396 			if ((device = libhal_volume_get_device_file(v)) ==
397 			    NULL) {
398 				continue;
399 			}
400 			if ((print_mask & RMM_PRINT_MOUNTABLE) &&
401 			    (libhal_volume_get_fsusage(v) !=
402 			    LIBHAL_VOLUME_USAGE_MOUNTABLE_FILESYSTEM)) {
403 				continue;
404 			}
405 
406 			rmm_print_nicknames_one(d, v, device, nicknames);
407 			nprinted++;
408 		}
409 
410 		if ((nprinted == 0) &&
411 		    (print_mask & RMM_PRINT_EJECTABLE) &&
412 		    libhal_drive_requires_eject(d) &&
413 		    ((device = libhal_drive_get_device_file(d)) != NULL)) {
414 			rmm_print_nicknames_one(d, NULL, device, nicknames);
415 		}
416 
417 		libhal_free_string_array(nicknames);
418 		libhal_drive_free(d);
419 		rmm_volumes_free(volumes);
420 		volumes = NULL;
421 	}
422 
423 	libhal_free_string_array(udis);
424 }
425 
426 /*
427  * find volume by nickname
428  * returns the LibHalDrive object and a list of LibHalVolume objects.
429  */
430 LibHalDrive *
rmm_hal_volume_findby_nickname(LibHalContext * hal_ctx,const char * name,GSList ** volumes)431 rmm_hal_volume_findby_nickname(LibHalContext *hal_ctx, const char *name,
432     GSList **volumes)
433 {
434 	DBusError	error;
435 	LibHalDrive	*drive = NULL;
436 	LibHalDrive	*drive_tmp;
437 	char		**udis;
438 	int		num_udis;
439 	char		**nicknames;
440 	int		i, j;
441 
442 	*volumes = NULL;
443 
444 	dbus_error_init(&error);
445 
446 	if ((udis = libhal_find_device_by_capability(hal_ctx, "storage",
447 	    &num_udis, &error)) == NULL) {
448 		rmm_dbus_error_free(&error);
449 		return (NULL);
450 	}
451 
452 	/* find a drive by nickname */
453 	for (i = 0; (i < num_udis) && (drive == NULL); i++) {
454 		if ((nicknames = libhal_device_get_property_strlist(hal_ctx,
455 		    udis[i], "storage.solaris.nicknames", &error)) == NULL) {
456 			rmm_dbus_error_free(&error);
457 			continue;
458 		}
459 		for (j = 0; (nicknames[j] != NULL) && (drive == NULL); j++) {
460 			if (strcmp(nicknames[j], name) == 0) {
461 				drive = libhal_drive_from_udi(hal_ctx, udis[i]);
462 			}
463 		}
464 		libhal_free_string_array(nicknames);
465 	}
466 	libhal_free_string_array(udis);
467 
468 	if (drive != NULL) {
469 		/* found the drive, now find its volumes */
470 		if ((drive_tmp = rmm_hal_volume_findby(hal_ctx,
471 		    "block.storage_device", libhal_drive_get_udi(drive),
472 		    volumes)) != NULL) {
473 			libhal_drive_free(drive_tmp);
474 		}
475 	}
476 
477 	rmm_dbus_error_free(&error);
478 
479 	return (drive);
480 }
481 
482 void
rmm_volumes_free(GSList * volumes)483 rmm_volumes_free(GSList *volumes)
484 {
485 	GSList	*i;
486 
487 	for (i = volumes; i != NULL; i = g_slist_next(i)) {
488 		libhal_volume_free((LibHalVolume *)(i->data));
489 	}
490 	g_slist_free(volumes);
491 }
492 
493 /*
494  * Call HAL's Mount() method on the given device
495  */
496 boolean_t
rmm_hal_mount(LibHalContext * hal_ctx,const char * udi,char ** opts,int num_opts,char * mountpoint,DBusError * error)497 rmm_hal_mount(LibHalContext *hal_ctx, const char *udi,
498     char **opts, int num_opts, char *mountpoint, DBusError *error)
499 {
500 	DBusConnection	*dbus_conn = libhal_ctx_get_dbus_connection(hal_ctx);
501 	DBusMessage	*dmesg, *reply;
502 	char		*fstype;
503 
504 	dbgprintf("mounting %s...\n", udi);
505 
506 	if (!(dmesg = dbus_message_new_method_call("org.freedesktop.Hal", udi,
507 	    "org.freedesktop.Hal.Device.Volume", "Mount"))) {
508 		dbgprintf(
509 		    "mount failed for %s: cannot create dbus message\n", udi);
510 		return (B_FALSE);
511 	}
512 
513 	fstype = "";
514 	if (mountpoint == NULL) {
515 		mountpoint = "";
516 	}
517 
518 	if (!dbus_message_append_args(dmesg, DBUS_TYPE_STRING, &mountpoint,
519 	    DBUS_TYPE_STRING, &fstype,
520 	    DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &opts, num_opts,
521 	    DBUS_TYPE_INVALID)) {
522 		dbgprintf("mount failed for %s: cannot append args\n", udi);
523 		dbus_message_unref(dmesg);
524 		return (B_FALSE);
525 	}
526 
527 	dbus_error_init(error);
528 	if (!(reply = dbus_connection_send_with_reply_and_block(dbus_conn,
529 	    dmesg, RMM_MOUNT_TIMEOUT, error))) {
530 		dbgprintf("mount failed for %s: %s\n", udi, error->message);
531 		dbus_message_unref(dmesg);
532 		return (B_FALSE);
533 	}
534 
535 	dbgprintf("mounted %s\n", udi);
536 
537 	dbus_message_unref(dmesg);
538 	dbus_message_unref(reply);
539 
540 	rmm_dbus_error_free(error);
541 
542 	return (B_TRUE);
543 }
544 
545 
546 /*
547  * Call HAL's Unmount() method on the given device
548  */
549 boolean_t
rmm_hal_unmount(LibHalContext * hal_ctx,const char * udi,DBusError * error)550 rmm_hal_unmount(LibHalContext *hal_ctx, const char *udi, DBusError *error)
551 {
552 	DBusConnection *dbus_conn = libhal_ctx_get_dbus_connection(hal_ctx);
553 	DBusMessage *dmesg, *reply;
554 	char **opts = NULL;
555 
556 	dbgprintf("unmounting %s...\n", udi);
557 
558 	if (!(dmesg = dbus_message_new_method_call("org.freedesktop.Hal", udi,
559 	    "org.freedesktop.Hal.Device.Volume", "Unmount"))) {
560 		dbgprintf(
561 		    "unmount failed %s: cannot create dbus message\n", udi);
562 		return (B_FALSE);
563 	}
564 
565 	if (!dbus_message_append_args(dmesg, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
566 	    &opts, 0, DBUS_TYPE_INVALID)) {
567 		dbgprintf("unmount failed %s: cannot append args\n", udi);
568 		dbus_message_unref(dmesg);
569 		return (B_FALSE);
570 	}
571 
572 	dbus_error_init(error);
573 	if (!(reply = dbus_connection_send_with_reply_and_block(dbus_conn,
574 	    dmesg, RMM_UNMOUNT_TIMEOUT, error))) {
575 		dbgprintf("unmount failed for %s: %s\n", udi, error->message);
576 		dbus_message_unref(dmesg);
577 		return (B_FALSE);
578 	}
579 
580 	dbgprintf("unmounted %s\n", udi);
581 
582 	dbus_message_unref(dmesg);
583 	dbus_message_unref(reply);
584 
585 	rmm_dbus_error_free(error);
586 
587 	return (B_TRUE);
588 }
589 
590 
591 /*
592  * Call HAL's Eject() method on the given device
593  */
594 boolean_t
rmm_hal_eject(LibHalContext * hal_ctx,const char * udi,DBusError * error)595 rmm_hal_eject(LibHalContext *hal_ctx, const char *udi, DBusError *error)
596 {
597 	DBusConnection	*dbus_conn = libhal_ctx_get_dbus_connection(hal_ctx);
598 	DBusMessage	*dmesg, *reply;
599 	char		**options = NULL;
600 	uint_t		num_options = 0;
601 
602 	dbgprintf("ejecting %s...\n", udi);
603 
604 	if (!(dmesg = dbus_message_new_method_call("org.freedesktop.Hal", udi,
605 	    "org.freedesktop.Hal.Device.Storage", "Eject"))) {
606 		dbgprintf("eject %s: cannot create dbus message\n", udi);
607 		return (B_FALSE);
608 	}
609 
610 	if (!dbus_message_append_args(dmesg,
611 	    DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &options, num_options,
612 	    DBUS_TYPE_INVALID)) {
613 		dbgprintf("eject %s: cannot append args to dbus message ", udi);
614 		dbus_message_unref(dmesg);
615 		return (B_FALSE);
616 	}
617 
618 	dbus_error_init(error);
619 	if (!(reply = dbus_connection_send_with_reply_and_block(dbus_conn,
620 	    dmesg, RMM_EJECT_TIMEOUT, error))) {
621 		dbgprintf("eject %s: %s\n", udi, error->message);
622 		dbus_message_unref(dmesg);
623 		return (B_FALSE);
624 	}
625 
626 	dbgprintf("ejected %s\n", udi);
627 
628 	dbus_message_unref(dmesg);
629 	dbus_message_unref(reply);
630 
631 	rmm_dbus_error_free(error);
632 
633 	return (B_TRUE);
634 }
635 
636 /*
637  * Call HAL's CloseTray() method on the given device
638  */
639 boolean_t
rmm_hal_closetray(LibHalContext * hal_ctx,const char * udi,DBusError * error)640 rmm_hal_closetray(LibHalContext *hal_ctx, const char *udi, DBusError *error)
641 {
642 	DBusConnection	*dbus_conn = libhal_ctx_get_dbus_connection(hal_ctx);
643 	DBusMessage	*dmesg, *reply;
644 	char		**options = NULL;
645 	uint_t		num_options = 0;
646 
647 	dbgprintf("closing tray %s...\n", udi);
648 
649 	if (!(dmesg = dbus_message_new_method_call("org.freedesktop.Hal", udi,
650 	    "org.freedesktop.Hal.Device.Storage", "CloseTray"))) {
651 		dbgprintf(
652 		    "closetray failed for %s: cannot create dbus message\n",
653 		    udi);
654 		return (B_FALSE);
655 	}
656 
657 	if (!dbus_message_append_args(dmesg,
658 	    DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &options, num_options,
659 	    DBUS_TYPE_INVALID)) {
660 		dbgprintf("closetray %s: cannot append args to dbus message ",
661 		    udi);
662 		dbus_message_unref(dmesg);
663 		return (B_FALSE);
664 	}
665 
666 	dbus_error_init(error);
667 	if (!(reply = dbus_connection_send_with_reply_and_block(dbus_conn,
668 	    dmesg, RMM_CLOSETRAY_TIMEOUT, error))) {
669 		dbgprintf("closetray failed for %s: %s\n", udi, error->message);
670 		dbus_message_unref(dmesg);
671 		return (B_FALSE);
672 	}
673 
674 	dbgprintf("closetray ok %s\n", udi);
675 
676 	dbus_message_unref(dmesg);
677 	dbus_message_unref(reply);
678 
679 	rmm_dbus_error_free(error);
680 
681 	return (B_TRUE);
682 }
683 
684 /*
685  * Call HAL's Rescan() method on the given device
686  */
687 boolean_t
rmm_hal_rescan(LibHalContext * hal_ctx,const char * udi,DBusError * error)688 rmm_hal_rescan(LibHalContext *hal_ctx, const char *udi, DBusError *error)
689 {
690 	DBusConnection	*dbus_conn = libhal_ctx_get_dbus_connection(hal_ctx);
691 	DBusMessage	*dmesg, *reply;
692 
693 	dbgprintf("rescanning %s...\n", udi);
694 
695 	if (!(dmesg = dbus_message_new_method_call("org.freedesktop.Hal", udi,
696 	    "org.freedesktop.Hal.Device", "Rescan"))) {
697 		dbgprintf("rescan failed for %s: cannot create dbus message\n",
698 		    udi);
699 		return (B_FALSE);
700 	}
701 
702 	dbus_error_init(error);
703 	if (!(reply = dbus_connection_send_with_reply_and_block(dbus_conn,
704 	    dmesg, -1, error))) {
705 		dbgprintf("rescan failed for %s: %s\n", udi, error->message);
706 		dbus_message_unref(dmesg);
707 		return (B_FALSE);
708 	}
709 
710 	dbgprintf("rescan ok %s\n", udi);
711 
712 	dbus_message_unref(dmesg);
713 	dbus_message_unref(reply);
714 
715 	rmm_dbus_error_free(error);
716 
717 	return (B_TRUE);
718 }
719 
720 boolean_t
rmm_hal_claim_branch(LibHalContext * hal_ctx,const char * udi)721 rmm_hal_claim_branch(LibHalContext *hal_ctx, const char *udi)
722 {
723 	DBusError error;
724 	DBusConnection	*dbus_conn = libhal_ctx_get_dbus_connection(hal_ctx);
725 	DBusMessage *dmesg, *reply;
726 	const char *claimed_by = "rmvolmgr";
727 
728 	dbgprintf("claiming branch %s...\n", udi);
729 
730 	if (!(dmesg = dbus_message_new_method_call("org.freedesktop.Hal",
731 	    "/org/freedesktop/Hal/Manager", "org.freedesktop.Hal.Manager",
732 	    "ClaimBranch"))) {
733 		dbgprintf("cannot create dbus message\n");
734 		return (B_FALSE);
735 	}
736 
737 	if (!dbus_message_append_args(dmesg, DBUS_TYPE_STRING, &udi,
738 	    DBUS_TYPE_STRING, &claimed_by, DBUS_TYPE_INVALID)) {
739 		dbgprintf("cannot append args to dbus message\n");
740 		dbus_message_unref(dmesg);
741 		return (B_FALSE);
742 	}
743 
744 	dbus_error_init(&error);
745 	if (!(reply = dbus_connection_send_with_reply_and_block(dbus_conn,
746 	    dmesg, -1, &error))) {
747 		dbgprintf("cannot send dbus message\n");
748 		dbus_message_unref(dmesg);
749 		rmm_dbus_error_free(&error);
750 		return (B_FALSE);
751 	}
752 
753 	dbgprintf("claim branch ok %s\n", udi);
754 
755 	dbus_message_unref(dmesg);
756 	dbus_message_unref(reply);
757 
758 	return (B_TRUE);
759 }
760 
761 boolean_t
rmm_hal_unclaim_branch(LibHalContext * hal_ctx,const char * udi)762 rmm_hal_unclaim_branch(LibHalContext *hal_ctx, const char *udi)
763 {
764 	DBusError error;
765 	DBusConnection	*dbus_conn = libhal_ctx_get_dbus_connection(hal_ctx);
766 	DBusMessage *dmesg, *reply;
767 	const char *claimed_by = "rmvolmgr";
768 
769 	dbgprintf("unclaiming branch %s...\n", udi);
770 
771 	if (!(dmesg = dbus_message_new_method_call("org.freedesktop.Hal",
772 	    "/org/freedesktop/Hal/Manager", "org.freedesktop.Hal.Manager",
773 	    "UnclaimBranch"))) {
774 		dbgprintf("cannot create dbus message\n");
775 		return (B_FALSE);
776 	}
777 
778 	if (!dbus_message_append_args(dmesg, DBUS_TYPE_STRING, &udi,
779 	    DBUS_TYPE_STRING, &claimed_by, DBUS_TYPE_INVALID)) {
780 		dbgprintf("cannot append args to dbus message\n");
781 		dbus_message_unref(dmesg);
782 		return (B_FALSE);
783 	}
784 
785 	dbus_error_init(&error);
786 	if (!(reply = dbus_connection_send_with_reply_and_block(dbus_conn,
787 	    dmesg, -1, &error))) {
788 		dbgprintf("cannot send dbus message\n");
789 		dbus_message_unref(dmesg);
790 		rmm_dbus_error_free(&error);
791 		return (B_FALSE);
792 	}
793 
794 	dbgprintf("unclaim branch ok %s\n", udi);
795 
796 	dbus_message_unref(dmesg);
797 	dbus_message_unref(reply);
798 
799 	return (B_TRUE);
800 }
801 
802 static boolean_t
rmm_action_one(LibHalContext * hal_ctx,const char * name,action_t action,const char * dev,const char * udi,LibHalVolume * v,char ** opts,int num_opts,char * mountpoint)803 rmm_action_one(LibHalContext *hal_ctx, const char *name, action_t action,
804     const char *dev, const char *udi, LibHalVolume *v,
805     char **opts, int num_opts, char *mountpoint)
806 {
807 	char		dev_str[MAXPATHLEN];
808 	char		*mountp;
809 	DBusError	error;
810 	boolean_t	ret = B_FALSE;
811 
812 	if (strcmp(name, dev) == 0) {
813 		(void) snprintf(dev_str, sizeof (dev_str), name);
814 	} else {
815 		(void) snprintf(dev_str, sizeof (dev_str), "%s %s", name, dev);
816 	}
817 
818 	dbus_error_init(&error);
819 
820 	switch (action) {
821 	case EJECT:
822 		ret = rmm_hal_eject(hal_ctx, udi, &error);
823 		break;
824 	case INSERT:
825 	case REMOUNT:
826 		if (libhal_volume_is_mounted(v)) {
827 			goto done;
828 		}
829 		ret = rmm_hal_mount(hal_ctx, udi,
830 		    opts, num_opts, mountpoint, &error);
831 		break;
832 	case UNMOUNT:
833 		if (!libhal_volume_is_mounted(v)) {
834 			goto done;
835 		}
836 		ret = rmm_hal_unmount(hal_ctx, udi, &error);
837 		break;
838 	case CLOSETRAY:
839 		ret = rmm_hal_closetray(hal_ctx, udi, &error);
840 		break;
841 	}
842 
843 	if (!ret) {
844 		(void) fprintf(stderr, gettext("%s of %s failed: %s\n"),
845 		    action_strings[action], dev_str, rmm_strerror(&error, -1));
846 		goto done;
847 	}
848 
849 	switch (action) {
850 	case EJECT:
851 		(void) printf(gettext("%s ejected\n"), dev_str);
852 		break;
853 	case INSERT:
854 	case REMOUNT:
855 		mountp = rmm_get_mnttab_mount_point(dev);
856 		if (mountp != NULL) {
857 			(void) printf(gettext("%s mounted at %s\n"),
858 			    dev_str, mountp);
859 			free(mountp);
860 		}
861 		break;
862 	case UNMOUNT:
863 		(void) printf(gettext("%s unmounted\n"), dev_str);
864 		break;
865 	case CLOSETRAY:
866 		(void) printf(gettext("%s tray closed\n"), dev_str);
867 		break;
868 	}
869 
870 done:
871 	rmm_dbus_error_free(&error);
872 	return (ret);
873 }
874 
875 /*
876  * top level action routine
877  *
878  * If non-null 'aa' is passed, it will be used, otherwise a local copy
879  * will be created.
880  */
881 boolean_t
rmm_action(LibHalContext * hal_ctx,const char * name,action_t action,struct action_arg * aap,char ** opts,int num_opts,char * mountpoint)882 rmm_action(LibHalContext *hal_ctx, const char *name, action_t action,
883     struct action_arg *aap, char **opts, int num_opts, char *mountpoint)
884 {
885 	DBusError	error;
886 	GSList		*volumes, *i;
887 	LibHalDrive	*d;
888 	LibHalVolume	*v;
889 	const char	*udi, *d_udi;
890 	const char	*dev, *d_dev;
891 	struct action_arg aa_local;
892 	boolean_t	ret = B_FALSE;
893 
894 	dbgprintf("rmm_action %s %s\n", name, action_strings[action]);
895 
896 	if (aap == NULL) {
897 		bzero(&aa_local, sizeof (aa_local));
898 		aap = &aa_local;
899 	}
900 
901 	dbus_error_init(&error);
902 
903 	/* find the drive and its volumes */
904 	d = rmm_hal_volume_find(hal_ctx, name, &error, &volumes);
905 	rmm_dbus_error_free(&error);
906 	if (d == NULL) {
907 		(void) fprintf(stderr, gettext("cannot find '%s'\n"), name);
908 		return (B_FALSE);
909 	}
910 	d_udi = libhal_drive_get_udi(d);
911 	d_dev = libhal_drive_get_device_file(d);
912 	if ((d_udi == NULL) || (d_dev == NULL)) {
913 		goto out;
914 	}
915 
916 	/*
917 	 * For those drives that do not require media eject,
918 	 * EJECT turns into UNMOUNT.
919 	 */
920 	if ((action == EJECT) && !libhal_drive_requires_eject(d)) {
921 		action = UNMOUNT;
922 	}
923 
924 	/* per drive action */
925 	if ((action == EJECT) || (action == CLOSETRAY)) {
926 		ret = rmm_action_one(hal_ctx, name, action, d_dev, d_udi, NULL,
927 		    opts, num_opts, NULL);
928 
929 		if (!ret || (action == CLOSETRAY)) {
930 			goto out;
931 		}
932 	}
933 
934 	/* per volume action */
935 	for (i = volumes; i != NULL; i = g_slist_next(i)) {
936 		v = (LibHalVolume *)i->data;
937 		udi = libhal_volume_get_udi(v);
938 		dev = libhal_volume_get_device_file(v);
939 
940 		if ((udi == NULL) || (dev == NULL)) {
941 			continue;
942 		}
943 		if (aap == &aa_local) {
944 			if (!rmm_volume_aa_from_prop(hal_ctx, udi, v, aap)) {
945 				dbgprintf("rmm_volume_aa_from_prop failed %s\n",
946 				    udi);
947 				continue;
948 			}
949 		}
950 		aap->aa_action = action;
951 
952 		/* ejected above, just need postprocess */
953 		if (action != EJECT) {
954 			ret = rmm_action_one(hal_ctx, name, action, dev, udi, v,
955 			    opts, num_opts, mountpoint);
956 		}
957 		if (ret) {
958 			(void) vold_postprocess(hal_ctx, udi, aap);
959 		}
960 
961 		if (aap == &aa_local) {
962 			rmm_volume_aa_free(aap);
963 		}
964 	}
965 
966 out:
967 	rmm_volumes_free(volumes);
968 	libhal_drive_free(d);
969 
970 	return (ret);
971 }
972 
973 
974 /*
975  * rescan by name
976  * if name is NULL, rescan all drives
977  */
978 boolean_t
rmm_rescan(LibHalContext * hal_ctx,const char * name,boolean_t query)979 rmm_rescan(LibHalContext *hal_ctx, const char *name, boolean_t query)
980 {
981 	DBusError	error;
982 	GSList		*volumes;
983 	LibHalDrive	*drive = NULL;
984 	const char	*drive_udi;
985 	char		**udis;
986 	int		num_udis;
987 	char		*nickname;
988 	char		**nicks = NULL;
989 	boolean_t	do_free_udis = FALSE;
990 	int		i;
991 	boolean_t	ret = B_FALSE;
992 
993 	dbgprintf("rmm_rescan %s\n", name != NULL ? name : "all");
994 
995 	dbus_error_init(&error);
996 
997 	if (name != NULL) {
998 		if ((drive = rmm_hal_volume_find(hal_ctx, name, &error,
999 		    &volumes)) == NULL) {
1000 			rmm_dbus_error_free(&error);
1001 			(void) fprintf(stderr,
1002 			    gettext("cannot find '%s'\n"), name);
1003 			return (B_FALSE);
1004 		}
1005 		rmm_dbus_error_free(&error);
1006 		g_slist_free(volumes);
1007 
1008 		drive_udi = libhal_drive_get_udi(drive);
1009 		udis = (char **)&drive_udi;
1010 		num_udis = 1;
1011 	} else {
1012 		if ((udis = libhal_find_device_by_capability(hal_ctx,
1013 		    "storage", &num_udis, &error)) == NULL) {
1014 			rmm_dbus_error_free(&error);
1015 			return (B_TRUE);
1016 		}
1017 		rmm_dbus_error_free(&error);
1018 		do_free_udis = TRUE;
1019 	}
1020 
1021 	for (i = 0; i < num_udis; i++) {
1022 		if (name == NULL) {
1023 			nicks = libhal_device_get_property_strlist(hal_ctx,
1024 			    udis[i], "storage.solaris.nicknames", NULL);
1025 			if (nicks != NULL) {
1026 				nickname = nicks[0];
1027 			} else {
1028 				nickname = "";
1029 			}
1030 		}
1031 		if (!(ret = rmm_hal_rescan(hal_ctx, udis[i], &error))) {
1032 			(void) fprintf(stderr,
1033 			    gettext("rescan of %s failed: %s\n"),
1034 			    name ? name : nickname,
1035 			    rmm_strerror(&error, -1));
1036 			libhal_free_string_array(nicks);
1037 			continue;
1038 		}
1039 		if (query) {
1040 			ret = libhal_device_get_property_bool(hal_ctx, udis[i],
1041 			    "storage.removable.media_available", NULL);
1042 			if (ret) {
1043 				printf(gettext("%s is available\n"),
1044 				    name ? name : nickname);
1045 			} else {
1046 				printf(gettext("%s is not available\n"),
1047 				    name ? name : nickname);
1048 			}
1049 		}
1050 		libhal_free_string_array(nicks);
1051 	}
1052 
1053 	if (drive != NULL) {
1054 		libhal_drive_free(drive);
1055 	}
1056 	if (do_free_udis) {
1057 		libhal_free_string_array(udis);
1058 	}
1059 
1060 	return (ret);
1061 }
1062 
1063 
1064 /*
1065  * set action_arg from volume properties
1066  */
1067 boolean_t
rmm_volume_aa_from_prop(LibHalContext * hal_ctx,const char * udi_arg,LibHalVolume * volume_arg,struct action_arg * aap)1068 rmm_volume_aa_from_prop(LibHalContext *hal_ctx, const char *udi_arg,
1069     LibHalVolume *volume_arg, struct action_arg *aap)
1070 {
1071 	LibHalVolume	*volume = volume_arg;
1072 	const char	*udi = udi_arg;
1073 	const char	*drive_udi;
1074 	char		*volume_label;
1075 	char		*mountpoint;
1076 	int		len;
1077 	int		ret = B_FALSE;
1078 
1079 	/* at least udi or volume must be supplied */
1080 	if ((udi == NULL) && (volume == NULL)) {
1081 		return (B_FALSE);
1082 	}
1083 	if (volume == NULL) {
1084 		if ((volume = libhal_volume_from_udi(hal_ctx, udi)) == NULL) {
1085 			dbgprintf("cannot get volume %s\n", udi);
1086 			goto out;
1087 		}
1088 	}
1089 	if (udi == NULL) {
1090 		if ((udi = libhal_volume_get_udi(volume)) == NULL) {
1091 			dbgprintf("cannot get udi\n");
1092 			goto out;
1093 		}
1094 	}
1095 	drive_udi = libhal_volume_get_storage_device_udi(volume);
1096 
1097 	if (!(aap->aa_symdev = libhal_device_get_property_string(hal_ctx,
1098 	    drive_udi, "storage.solaris.legacy.symdev", NULL))) {
1099 		dbgprintf("property %s not found %s\n",
1100 		    "storage.solaris.legacy.symdev", drive_udi);
1101 		goto out;
1102 	}
1103 	if (!(aap->aa_media = libhal_device_get_property_string(hal_ctx,
1104 	    drive_udi, "storage.solaris.legacy.media_type", NULL))) {
1105 		dbgprintf("property %s not found %s\n",
1106 		    "storage.solaris.legacy.media_type", drive_udi);
1107 		goto out;
1108 	}
1109 
1110 	/* name is derived from volume label */
1111 	aap->aa_name = NULL;
1112 	if ((volume_label = (char *)libhal_device_get_property_string(hal_ctx,
1113 	    udi, "volume.label", NULL)) != NULL) {
1114 		if ((len = strlen(volume_label)) > 0) {
1115 			aap->aa_name = rmm_vold_convert_volume_label(
1116 			    volume_label, len);
1117 			if (strlen(aap->aa_name) == 0) {
1118 				free(aap->aa_name);
1119 				aap->aa_name = NULL;
1120 			}
1121 		}
1122 		libhal_free_string(volume_label);
1123 	}
1124 	/* if no label, then unnamed_<mediatype> */
1125 	if (aap->aa_name == NULL) {
1126 		aap->aa_name = (char *)calloc(1, sizeof ("unnamed_floppyNNNN"));
1127 		if (aap->aa_name == NULL) {
1128 			goto out;
1129 		}
1130 		(void) snprintf(aap->aa_name, sizeof ("unnamed_floppyNNNN"),
1131 		    "unnamed_%s", aap->aa_media);
1132 	}
1133 
1134 	if (!(aap->aa_path = libhal_device_get_property_string(hal_ctx, udi,
1135 	    "block.device", NULL))) {
1136 		dbgprintf("property %s not found %s\n", "block.device", udi);
1137 		goto out;
1138 	}
1139 	if (!(aap->aa_rawpath = libhal_device_get_property_string(hal_ctx, udi,
1140 	    "block.solaris.raw_device", NULL))) {
1141 		dbgprintf("property %s not found %s\n",
1142 		    "block.solaris.raw_device", udi);
1143 		goto out;
1144 	}
1145 	if (!(aap->aa_type = libhal_device_get_property_string(hal_ctx, udi,
1146 	    "volume.fstype", NULL))) {
1147 		dbgprintf("property %s not found %s\n", "volume.fstype", udi);
1148 		goto out;
1149 	}
1150 	if (!libhal_device_get_property_bool(hal_ctx, udi,
1151 	    "volume.is_partition", NULL)) {
1152 		aap->aa_partname = NULL;
1153 	} else if (!(aap->aa_partname = libhal_device_get_property_string(
1154 	    hal_ctx, udi, "block.solaris.slice", NULL))) {
1155 		dbgprintf("property %s not found %s\n",
1156 		    "block.solaris.slice", udi);
1157 		goto out;
1158 	}
1159 	if (!(mountpoint = libhal_device_get_property_string(hal_ctx, udi,
1160 	    "volume.mount_point", NULL))) {
1161 		dbgprintf("property %s not found %s\n",
1162 		    "volume.mount_point", udi);
1163 		goto out;
1164 	}
1165 	/*
1166 	 * aa_mountpoint can be reallocated in rmm_volume_aa_update_mountpoint()
1167 	 * won't have to choose between free() or libhal_free_string() later on
1168 	 */
1169 	aap->aa_mountpoint = strdup(mountpoint);
1170 	libhal_free_string(mountpoint);
1171 	if (aap->aa_mountpoint == NULL) {
1172 		dbgprintf("mountpoint is NULL %s\n", udi);
1173 		goto out;
1174 	}
1175 
1176 	ret = B_TRUE;
1177 
1178 out:
1179 	if ((volume != NULL) && (volume != volume_arg)) {
1180 		libhal_volume_free(volume);
1181 	}
1182 	if (!ret) {
1183 		rmm_volume_aa_free(aap);
1184 	}
1185 	return (ret);
1186 }
1187 
1188 /* ARGSUSED */
1189 void
rmm_volume_aa_update_mountpoint(LibHalContext * hal_ctx,const char * udi,struct action_arg * aap)1190 rmm_volume_aa_update_mountpoint(LibHalContext *hal_ctx, const char *udi,
1191     struct action_arg *aap)
1192 {
1193 	if (aap->aa_mountpoint != NULL) {
1194 		free(aap->aa_mountpoint);
1195 	}
1196 	aap->aa_mountpoint = rmm_get_mnttab_mount_point(aap->aa_path);
1197 }
1198 
1199 void
rmm_volume_aa_free(struct action_arg * aap)1200 rmm_volume_aa_free(struct action_arg *aap)
1201 {
1202 	if (aap->aa_symdev != NULL) {
1203 		libhal_free_string(aap->aa_symdev);
1204 		aap->aa_symdev = NULL;
1205 	}
1206 	if (aap->aa_name != NULL) {
1207 		free(aap->aa_name);
1208 		aap->aa_name = NULL;
1209 	}
1210 	if (aap->aa_path != NULL) {
1211 		libhal_free_string(aap->aa_path);
1212 		aap->aa_path = NULL;
1213 	}
1214 	if (aap->aa_rawpath != NULL) {
1215 		libhal_free_string(aap->aa_rawpath);
1216 		aap->aa_rawpath = NULL;
1217 	}
1218 	if (aap->aa_type != NULL) {
1219 		libhal_free_string(aap->aa_type);
1220 		aap->aa_type = NULL;
1221 	}
1222 	if (aap->aa_media != NULL) {
1223 		libhal_free_string(aap->aa_media);
1224 		aap->aa_media = NULL;
1225 	}
1226 	if (aap->aa_partname != NULL) {
1227 		libhal_free_string(aap->aa_partname);
1228 		aap->aa_partname = NULL;
1229 	}
1230 	if (aap->aa_mountpoint != NULL) {
1231 		free(aap->aa_mountpoint);
1232 		aap->aa_mountpoint = NULL;
1233 	}
1234 }
1235 
1236 /*
1237  * get device's mount point from mnttab
1238  */
1239 char *
rmm_get_mnttab_mount_point(const char * special)1240 rmm_get_mnttab_mount_point(const char *special)
1241 {
1242 	char		*mount_point = NULL;
1243 	FILE		*f;
1244 	struct mnttab	mnt;
1245 	struct mnttab	mpref = { NULL, NULL, NULL, NULL, NULL };
1246 
1247 	if ((f = fopen(MNTTAB, "r")) != NULL) {
1248 		mpref.mnt_special = (char *)special;
1249 		if (getmntany(f, &mnt, &mpref) == 0) {
1250 			mount_point = strdup(mnt.mnt_mountp);
1251 		}
1252 		fclose(f);
1253 	}
1254 
1255 	return (mount_point);
1256 }
1257 
1258 
1259 /*
1260  * get human readable string from error values
1261  */
1262 const char *
rmm_strerror(DBusError * dbus_error,int rmm_error)1263 rmm_strerror(DBusError *dbus_error, int rmm_error)
1264 {
1265 	const char	*str;
1266 
1267 	if ((dbus_error != NULL) && dbus_error_is_set(dbus_error)) {
1268 		str = dbus_error->message;
1269 	} else {
1270 		switch (rmm_error) {
1271 		case RMM_EOK:
1272 			str = gettext("success");
1273 			break;
1274 		case RMM_EDBUS_CONNECT:
1275 			str = gettext("cannot connect to D-Bus");
1276 			break;
1277 		case RMM_EHAL_CONNECT:
1278 			str = gettext("cannot connect to HAL");
1279 			break;
1280 		default:
1281 			str = gettext("undefined error");
1282 			break;
1283 		}
1284 	}
1285 
1286 	return (str);
1287 }
1288 
1289 void
rmm_dbus_error_free(DBusError * error)1290 rmm_dbus_error_free(DBusError *error)
1291 {
1292 	if (error != NULL && dbus_error_is_set(error)) {
1293 		dbus_error_free(error);
1294 	}
1295 }
1296 
1297 static int
rmm_vold_isbadchar(int c)1298 rmm_vold_isbadchar(int c)
1299 {
1300 	int	ret_val = 0;
1301 
1302 
1303 	switch (c) {
1304 	case '/':
1305 	case ';':
1306 	case '|':
1307 		ret_val = 1;
1308 		break;
1309 	default:
1310 		if (iscntrl(c) || isspace(c)) {
1311 			ret_val = 1;
1312 		}
1313 	}
1314 
1315 	return (ret_val);
1316 }
1317 
1318 char *
rmm_vold_convert_volume_label(const char * name,size_t len)1319 rmm_vold_convert_volume_label(const char *name, size_t len)
1320 {
1321 	char	buf[MAXNAMELEN+1];
1322 	char	*s = buf;
1323 	int	i;
1324 
1325 	if (len > MAXNAMELEN) {
1326 		len = MAXNAMELEN;
1327 	}
1328 
1329 	for (i = 0; i < len; i++) {
1330 		if (name[i] == '\0') {
1331 			break;
1332 		}
1333 		if (isgraph((int)name[i])) {
1334 			if (isupper((int)name[i])) {
1335 				*s++ = tolower((int)name[i]);
1336 			} else if (rmm_vold_isbadchar((int)name[i])) {
1337 				*s++ = '_';
1338 			} else {
1339 				*s++ = name[i];
1340 			}
1341 		}
1342 	}
1343 	*s = '\0';
1344 	s = strdup(buf);
1345 
1346 	return (s);
1347 }
1348 
1349 /*
1350  * swiped from mkdir.c
1351  */
1352 int
makepath(char * dir,mode_t mode)1353 makepath(char *dir, mode_t mode)
1354 {
1355 	int		err;
1356 	char		*slash;
1357 
1358 
1359 	if ((mkdir(dir, mode) == 0) || (errno == EEXIST)) {
1360 		return (0);
1361 	}
1362 	if (errno != ENOENT) {
1363 		return (-1);
1364 	}
1365 	if ((slash = strrchr(dir, '/')) == NULL) {
1366 		return (-1);
1367 	}
1368 	*slash = '\0';
1369 	err = makepath(dir, mode);
1370 	*slash++ = '/';
1371 
1372 	if (err || (*slash == '\0')) {
1373 		return (err);
1374 	}
1375 
1376 	return (mkdir(dir, mode));
1377 }
1378 
1379 
1380 void
dbgprintf(const char * fmt,...)1381 dbgprintf(const char *fmt, ...)
1382 {
1383 
1384 	va_list		ap;
1385 	const char	*p;
1386 	char		msg[BUFSIZ];
1387 	char		*errmsg = strerror(errno);
1388 	char		*s;
1389 
1390 	if (rmm_debug == 0) {
1391 		return;
1392 	}
1393 
1394 	(void) memset(msg, 0, BUFSIZ);
1395 
1396 	/* scan for %m and replace with errno msg */
1397 	s = &msg[strlen(msg)];
1398 	p = fmt;
1399 
1400 	while (*p != '\0') {
1401 		if ((*p == '%') && (*(p+1) == 'm')) {
1402 			(void) strcat(s, errmsg);
1403 			p += 2;
1404 			s += strlen(errmsg);
1405 			continue;
1406 		}
1407 		*s++ = *p++;
1408 	}
1409 	*s = '\0';	/* don't forget the null byte */
1410 
1411 	va_start(ap, fmt);
1412 	(void) vfprintf(stderr, msg, ap);
1413 	va_end(ap);
1414 }
1415