xref: /titanic_50/usr/src/cmd/lofiadm/main.c (revision 3d7072f8bd27709dba14f6fe336f149d25d9e207)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51d8ed0f0Svikram  * Common Development and Distribution License (the "License").
61d8ed0f0Svikram  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*3d7072f8Seschrock  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
231d8ed0f0Svikram  * Use is subject to license terms.
24*3d7072f8Seschrock  */
25*3d7072f8Seschrock 
26*3d7072f8Seschrock /*
277c478bd9Sstevel@tonic-gate  * lofiadm - administer lofi(7d). Very simple, add and remove file<->device
287c478bd9Sstevel@tonic-gate  * associations, and display status. All the ioctls are private between
297c478bd9Sstevel@tonic-gate  * lofi and lofiadm, and so are very simple - device information is
307c478bd9Sstevel@tonic-gate  * communicated via a minor number.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <sys/param.h>
377c478bd9Sstevel@tonic-gate #include <sys/lofi.h>
387c478bd9Sstevel@tonic-gate #include <sys/stat.h>
397c478bd9Sstevel@tonic-gate #include <stdio.h>
407c478bd9Sstevel@tonic-gate #include <fcntl.h>
417c478bd9Sstevel@tonic-gate #include <locale.h>
427c478bd9Sstevel@tonic-gate #include <string.h>
437c478bd9Sstevel@tonic-gate #include <errno.h>
447c478bd9Sstevel@tonic-gate #include <stdlib.h>
457c478bd9Sstevel@tonic-gate #include <unistd.h>
467c478bd9Sstevel@tonic-gate #include <stropts.h>
471d8ed0f0Svikram #include <libdevinfo.h>
487c478bd9Sstevel@tonic-gate #include "utils.h"
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate static const char USAGE[] =
517c478bd9Sstevel@tonic-gate 	"Usage: %s -a file [ device ]\n"
527c478bd9Sstevel@tonic-gate 	"       %s -d file | device \n"
537c478bd9Sstevel@tonic-gate 	"       %s [ device | file ]\n";
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate static const char *pname;
567c478bd9Sstevel@tonic-gate static int	addflag = 0;
577c478bd9Sstevel@tonic-gate static int	deleteflag = 0;
587c478bd9Sstevel@tonic-gate static int	errflag = 0;
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #define	FORMAT "%-20s     %s\n"
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * Print the list of all the mappings. Including a header.
647c478bd9Sstevel@tonic-gate  */
657c478bd9Sstevel@tonic-gate static void
667c478bd9Sstevel@tonic-gate print_mappings(int fd)
677c478bd9Sstevel@tonic-gate {
687c478bd9Sstevel@tonic-gate 	struct lofi_ioctl li;
697c478bd9Sstevel@tonic-gate 	int	minor;
707c478bd9Sstevel@tonic-gate 	int	maxminor;
717c478bd9Sstevel@tonic-gate 	char	path[MAXPATHLEN + 1];
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	li.li_minor = 0;
747c478bd9Sstevel@tonic-gate 	if (ioctl(fd, LOFI_GET_MAXMINOR, &li) == -1) {
757c478bd9Sstevel@tonic-gate 		perror("ioctl");
767c478bd9Sstevel@tonic-gate 		exit(E_ERROR);
777c478bd9Sstevel@tonic-gate 	}
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	maxminor = li.li_minor;
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	(void) printf(FORMAT, "Block Device", "File");
827c478bd9Sstevel@tonic-gate 	for (minor = 1; minor <= maxminor; minor++) {
837c478bd9Sstevel@tonic-gate 		li.li_minor = minor;
847c478bd9Sstevel@tonic-gate 		if (ioctl(fd, LOFI_GET_FILENAME, &li) == -1) {
857c478bd9Sstevel@tonic-gate 			if (errno == ENXIO)
867c478bd9Sstevel@tonic-gate 				continue;
877c478bd9Sstevel@tonic-gate 			perror("ioctl");
887c478bd9Sstevel@tonic-gate 			break;
897c478bd9Sstevel@tonic-gate 		}
907c478bd9Sstevel@tonic-gate 		(void) snprintf(path, sizeof (path), "/dev/%s/%d",
917c478bd9Sstevel@tonic-gate 		    LOFI_BLOCK_NAME, minor);
927c478bd9Sstevel@tonic-gate 		(void) printf(FORMAT, path, li.li_filename);
937c478bd9Sstevel@tonic-gate 	}
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate static void
977c478bd9Sstevel@tonic-gate usage(void)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(USAGE), pname, pname, pname);
1007c478bd9Sstevel@tonic-gate 	exit(E_USAGE);
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate  * Translate a lofi device name to a minor number. We might be asked
1057c478bd9Sstevel@tonic-gate  * to do this when there is no association (such as when the user specifies
1067c478bd9Sstevel@tonic-gate  * a particular device), so we can only look at the string.
1077c478bd9Sstevel@tonic-gate  */
1087c478bd9Sstevel@tonic-gate static int
1097c478bd9Sstevel@tonic-gate name_to_minor(const char *devicename)
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate 	int	minor;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	if (sscanf(devicename, "/dev/" LOFI_BLOCK_NAME "/%d", &minor) == 1) {
1147c478bd9Sstevel@tonic-gate 		return (minor);
1157c478bd9Sstevel@tonic-gate 	}
1167c478bd9Sstevel@tonic-gate 	if (sscanf(devicename, "/dev/" LOFI_CHAR_NAME "/%d", &minor) == 1) {
1177c478bd9Sstevel@tonic-gate 		return (minor);
1187c478bd9Sstevel@tonic-gate 	}
1197c478bd9Sstevel@tonic-gate 	return (0);
1207c478bd9Sstevel@tonic-gate }
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate /*
1237c478bd9Sstevel@tonic-gate  * This might be the first time we've used this minor number. If so,
1247c478bd9Sstevel@tonic-gate  * it might also be that the /dev links are in the process of being created
1257c478bd9Sstevel@tonic-gate  * by devfsadmd (or that they'll be created "soon"). We cannot return
1267c478bd9Sstevel@tonic-gate  * until they're there or the invoker of lofiadm might try to use them
1277c478bd9Sstevel@tonic-gate  * and not find them. This can happen if a shell script is running on
1287c478bd9Sstevel@tonic-gate  * an MP.
1297c478bd9Sstevel@tonic-gate  */
1307c478bd9Sstevel@tonic-gate static int sleeptime = 2;	/* number of seconds to sleep between stat's */
1317c478bd9Sstevel@tonic-gate static int maxsleep = 120;	/* maximum number of seconds to sleep */
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate static void
1347c478bd9Sstevel@tonic-gate wait_until_dev_complete(int minor)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	struct stat64 buf;
1377c478bd9Sstevel@tonic-gate 	int	cursleep;
1387c478bd9Sstevel@tonic-gate 	char	blkpath[MAXPATHLEN + 1];
1397c478bd9Sstevel@tonic-gate 	char	charpath[MAXPATHLEN + 1];
1401d8ed0f0Svikram 	di_devlink_handle_t hdl;
1411d8ed0f0Svikram 
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	(void) snprintf(blkpath, sizeof (blkpath), "/dev/%s/%d",
1447c478bd9Sstevel@tonic-gate 	    LOFI_BLOCK_NAME, minor);
1457c478bd9Sstevel@tonic-gate 	(void) snprintf(charpath, sizeof (charpath), "/dev/%s/%d",
1467c478bd9Sstevel@tonic-gate 	    LOFI_CHAR_NAME, minor);
1471d8ed0f0Svikram 
1481d8ed0f0Svikram 	/* Check if links already present */
1491d8ed0f0Svikram 	if (stat64(blkpath, &buf) == 0 && stat64(charpath, &buf) == 0)
1501d8ed0f0Svikram 		return;
1511d8ed0f0Svikram 
1521d8ed0f0Svikram 	/* First use di_devlink_init() */
1531d8ed0f0Svikram 	if (hdl = di_devlink_init("lofi", DI_MAKE_LINK)) {
1541d8ed0f0Svikram 		(void) di_devlink_fini(&hdl);
1551d8ed0f0Svikram 		goto out;
1561d8ed0f0Svikram 	}
1571d8ed0f0Svikram 
1581d8ed0f0Svikram 	/*
1591d8ed0f0Svikram 	 * Under normal conditions, di_devlink_init(DI_MAKE_LINK) above will
1601d8ed0f0Svikram 	 * only fail if the caller is non-root. In that case, wait for
1611d8ed0f0Svikram 	 * link creation via sysevents.
1621d8ed0f0Svikram 	 */
1637c478bd9Sstevel@tonic-gate 	cursleep = 0;
1647c478bd9Sstevel@tonic-gate 	while (cursleep < maxsleep) {
1657c478bd9Sstevel@tonic-gate 		if ((stat64(blkpath, &buf) == -1) ||
1667c478bd9Sstevel@tonic-gate 		    (stat64(charpath, &buf) == -1)) {
1677c478bd9Sstevel@tonic-gate 			(void) sleep(sleeptime);
1687c478bd9Sstevel@tonic-gate 			cursleep += sleeptime;
1697c478bd9Sstevel@tonic-gate 			continue;
1707c478bd9Sstevel@tonic-gate 		}
1717c478bd9Sstevel@tonic-gate 		return;
1727c478bd9Sstevel@tonic-gate 	}
1731d8ed0f0Svikram 
1747c478bd9Sstevel@tonic-gate 	/* one last try */
1751d8ed0f0Svikram 
1761d8ed0f0Svikram out:
1777c478bd9Sstevel@tonic-gate 	if (stat64(blkpath, &buf) == -1) {
1787c478bd9Sstevel@tonic-gate 		die(gettext("%s was not created"), blkpath);
1797c478bd9Sstevel@tonic-gate 	}
1807c478bd9Sstevel@tonic-gate 	if (stat64(charpath, &buf) == -1) {
1817c478bd9Sstevel@tonic-gate 		die(gettext("%s was not created"), charpath);
1827c478bd9Sstevel@tonic-gate 	}
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate /*
1867c478bd9Sstevel@tonic-gate  * Add a device association. If devicename is NULL, let the driver
1877c478bd9Sstevel@tonic-gate  * pick a device.
1887c478bd9Sstevel@tonic-gate  */
1897c478bd9Sstevel@tonic-gate static void
1907c478bd9Sstevel@tonic-gate add_mapping(int lfd, const char *devicename, const char *filename)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate 	struct lofi_ioctl li;
1937c478bd9Sstevel@tonic-gate 	int	minor;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	if (devicename == NULL) {
1967c478bd9Sstevel@tonic-gate 		/* pick one */
1977c478bd9Sstevel@tonic-gate 		li.li_minor = 0;
1987c478bd9Sstevel@tonic-gate 		(void) strcpy(li.li_filename, filename);
1997c478bd9Sstevel@tonic-gate 		minor = ioctl(lfd, LOFI_MAP_FILE, &li);
2007c478bd9Sstevel@tonic-gate 		if (minor == -1) {
2017c478bd9Sstevel@tonic-gate 			die(gettext("could not map file %s"), filename);
2027c478bd9Sstevel@tonic-gate 		}
2037c478bd9Sstevel@tonic-gate 		wait_until_dev_complete(minor);
2047c478bd9Sstevel@tonic-gate 		/* print one picked */
2057c478bd9Sstevel@tonic-gate 		(void) printf("/dev/%s/%d\n", LOFI_BLOCK_NAME, minor);
2067c478bd9Sstevel@tonic-gate 		return;
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 	/* use device we were given */
2097c478bd9Sstevel@tonic-gate 	minor = name_to_minor(devicename);
2107c478bd9Sstevel@tonic-gate 	if (minor == 0) {
2117c478bd9Sstevel@tonic-gate 		die(gettext("malformed device name %s\n"), devicename);
2127c478bd9Sstevel@tonic-gate 	}
2137c478bd9Sstevel@tonic-gate 	(void) strcpy(li.li_filename, filename);
2147c478bd9Sstevel@tonic-gate 	li.li_minor = minor;
2157c478bd9Sstevel@tonic-gate 	if (ioctl(lfd, LOFI_MAP_FILE_MINOR, &li) == -1) {
2167c478bd9Sstevel@tonic-gate 		die(gettext("could not map file %s to %s"), filename,
2177c478bd9Sstevel@tonic-gate 		    devicename);
2187c478bd9Sstevel@tonic-gate 	}
2197c478bd9Sstevel@tonic-gate 	wait_until_dev_complete(minor);
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate /*
2237c478bd9Sstevel@tonic-gate  * Remove an association. Delete by device name if non-NULL, or by
2247c478bd9Sstevel@tonic-gate  * filename otherwise.
2257c478bd9Sstevel@tonic-gate  */
2267c478bd9Sstevel@tonic-gate static void
227*3d7072f8Seschrock delete_mapping(int lfd, const char *devicename, const char *filename,
228*3d7072f8Seschrock     boolean_t force)
2297c478bd9Sstevel@tonic-gate {
2307c478bd9Sstevel@tonic-gate 	struct lofi_ioctl li;
2317c478bd9Sstevel@tonic-gate 
232*3d7072f8Seschrock 	li.li_force = force;
2337c478bd9Sstevel@tonic-gate 	if (devicename == NULL) {
2347c478bd9Sstevel@tonic-gate 		/* delete by filename */
2357c478bd9Sstevel@tonic-gate 		(void) strcpy(li.li_filename, filename);
2367c478bd9Sstevel@tonic-gate 		li.li_minor = 0;
2377c478bd9Sstevel@tonic-gate 		if (ioctl(lfd, LOFI_UNMAP_FILE, &li) == -1) {
2387c478bd9Sstevel@tonic-gate 			die(gettext("could not unmap file %s"), filename);
2397c478bd9Sstevel@tonic-gate 		}
2407c478bd9Sstevel@tonic-gate 		return;
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 	/* delete by device */
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	li.li_minor = name_to_minor(devicename);
2457c478bd9Sstevel@tonic-gate 	if (li.li_minor == 0) {
2467c478bd9Sstevel@tonic-gate 		die(gettext("malformed device name %s\n"), devicename);
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 	if (ioctl(lfd, LOFI_UNMAP_FILE_MINOR, &li) == -1) {
2497c478bd9Sstevel@tonic-gate 		die(gettext("could not unmap device %s"), devicename);
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate static void
2547c478bd9Sstevel@tonic-gate print_one_mapping(int lfd, const char *devicename, const char *filename)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	struct lofi_ioctl li;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	if (devicename == NULL) {
2597c478bd9Sstevel@tonic-gate 		/* given filename, print devicename */
2607c478bd9Sstevel@tonic-gate 		li.li_minor = 0;
2617c478bd9Sstevel@tonic-gate 		(void) strcpy(li.li_filename, filename);
2627c478bd9Sstevel@tonic-gate 		if (ioctl(lfd, LOFI_GET_MINOR, &li) == -1) {
2637c478bd9Sstevel@tonic-gate 			die(gettext("could not find device for %s"), filename);
2647c478bd9Sstevel@tonic-gate 		}
2657c478bd9Sstevel@tonic-gate 		(void) printf("/dev/%s/%d\n", LOFI_BLOCK_NAME, li.li_minor);
2667c478bd9Sstevel@tonic-gate 		return;
2677c478bd9Sstevel@tonic-gate 	}
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	/* given devicename, print filename */
2707c478bd9Sstevel@tonic-gate 	li.li_minor = name_to_minor(devicename);
2717c478bd9Sstevel@tonic-gate 	if (li.li_minor == 0) {
2727c478bd9Sstevel@tonic-gate 		die(gettext("malformed device name %s\n"), devicename);
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 	if (ioctl(lfd, LOFI_GET_FILENAME, &li) == -1) {
2757c478bd9Sstevel@tonic-gate 		die(gettext("could not find filename for %s"), devicename);
2767c478bd9Sstevel@tonic-gate 	}
2777c478bd9Sstevel@tonic-gate 	(void) printf("%s\n", li.li_filename);
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate int
2817c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
2827c478bd9Sstevel@tonic-gate {
2837c478bd9Sstevel@tonic-gate 	int	lfd;
2847c478bd9Sstevel@tonic-gate 	int	c;
2857c478bd9Sstevel@tonic-gate 	int	error;
2867c478bd9Sstevel@tonic-gate 	struct stat64 buf;
2877c478bd9Sstevel@tonic-gate 	const char *devicename = NULL;
2887c478bd9Sstevel@tonic-gate 	const char *filename = NULL;
2897c478bd9Sstevel@tonic-gate 	int	openflag;
2907c478bd9Sstevel@tonic-gate 	int	minor;
2917c478bd9Sstevel@tonic-gate 	int	fd = -1;
2927c478bd9Sstevel@tonic-gate 	static char *lofictl = "/dev/" LOFI_CTL_NAME;
293*3d7072f8Seschrock 	boolean_t force = B_FALSE;
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	pname = getpname(argv[0]);
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2987c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2997c478bd9Sstevel@tonic-gate 
300*3d7072f8Seschrock 	while ((c = getopt(argc, argv, "a:d:f")) != EOF) {
3017c478bd9Sstevel@tonic-gate 		switch (c) {
3027c478bd9Sstevel@tonic-gate 		case 'a':
3037c478bd9Sstevel@tonic-gate 			addflag = 1;
3047c478bd9Sstevel@tonic-gate 			filename = optarg;
3057c478bd9Sstevel@tonic-gate 			fd = open64(filename, O_RDONLY);
3067c478bd9Sstevel@tonic-gate 			if (fd == -1) {
3077c478bd9Sstevel@tonic-gate 				die(gettext("open: %s"), filename);
3087c478bd9Sstevel@tonic-gate 			}
3097c478bd9Sstevel@tonic-gate 			error = fstat64(fd, &buf);
3107c478bd9Sstevel@tonic-gate 			if (error == -1) {
3117c478bd9Sstevel@tonic-gate 				die(gettext("fstat: %s"), filename);
3127c478bd9Sstevel@tonic-gate 			} else if (!S_ISLOFIABLE(buf.st_mode)) {
3137c478bd9Sstevel@tonic-gate 				die(gettext("%s is not a regular file, "
3147c478bd9Sstevel@tonic-gate 				    "block, or character device\n"),
3157c478bd9Sstevel@tonic-gate 				    filename);
3167c478bd9Sstevel@tonic-gate 			} else if ((buf.st_size % DEV_BSIZE) != 0) {
3177c478bd9Sstevel@tonic-gate 				die(gettext("size of %s is not a multiple "
3187c478bd9Sstevel@tonic-gate 				    "of %d\n"),
3197c478bd9Sstevel@tonic-gate 				    filename, DEV_BSIZE);
3207c478bd9Sstevel@tonic-gate 			}
3217c478bd9Sstevel@tonic-gate 			(void) close(fd);
3227c478bd9Sstevel@tonic-gate 			minor = name_to_minor(filename);
3237c478bd9Sstevel@tonic-gate 			if (minor != 0) {
3247c478bd9Sstevel@tonic-gate 				die(gettext("cannot use " LOFI_DRIVER_NAME
3257c478bd9Sstevel@tonic-gate 				    " on itself\n"), devicename);
3267c478bd9Sstevel@tonic-gate 			}
3277c478bd9Sstevel@tonic-gate 			if (((argc - optind) > 0) && (*argv[optind] != '-')) {
3287c478bd9Sstevel@tonic-gate 				/* optional device */
3297c478bd9Sstevel@tonic-gate 				devicename = argv[optind];
3307c478bd9Sstevel@tonic-gate 				optind++;
3317c478bd9Sstevel@tonic-gate 			}
3327c478bd9Sstevel@tonic-gate 			break;
3337c478bd9Sstevel@tonic-gate 		case 'd':
3347c478bd9Sstevel@tonic-gate 			deleteflag = 1;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 			minor = name_to_minor(optarg);
3377c478bd9Sstevel@tonic-gate 			if (minor != 0)
3387c478bd9Sstevel@tonic-gate 				devicename = optarg;
3397c478bd9Sstevel@tonic-gate 			else
3407c478bd9Sstevel@tonic-gate 				filename = optarg;
3417c478bd9Sstevel@tonic-gate 			break;
342*3d7072f8Seschrock 		case 'f':
343*3d7072f8Seschrock 			force = B_TRUE;
344*3d7072f8Seschrock 			break;
3457c478bd9Sstevel@tonic-gate 		case '?':
3467c478bd9Sstevel@tonic-gate 		default:
3477c478bd9Sstevel@tonic-gate 			errflag = 1;
3487c478bd9Sstevel@tonic-gate 			break;
3497c478bd9Sstevel@tonic-gate 		}
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 	if (errflag || (addflag && deleteflag))
3527c478bd9Sstevel@tonic-gate 		usage();
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	switch (argc - optind) {
3557c478bd9Sstevel@tonic-gate 	case 0: /* no more args */
3567c478bd9Sstevel@tonic-gate 		break;
3577c478bd9Sstevel@tonic-gate 	case 1: /* one arg without options means print the association */
3587c478bd9Sstevel@tonic-gate 		if (addflag || deleteflag)
3597c478bd9Sstevel@tonic-gate 			usage();
3607c478bd9Sstevel@tonic-gate 		minor = name_to_minor(argv[optind]);
3617c478bd9Sstevel@tonic-gate 		if (minor != 0)
3627c478bd9Sstevel@tonic-gate 			devicename = argv[optind];
3637c478bd9Sstevel@tonic-gate 		else
3647c478bd9Sstevel@tonic-gate 			filename = argv[optind];
3657c478bd9Sstevel@tonic-gate 		break;
3667c478bd9Sstevel@tonic-gate 	default:
3677c478bd9Sstevel@tonic-gate 		usage();
3687c478bd9Sstevel@tonic-gate 		break;
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	if (filename && !valid_abspath(filename))
3727c478bd9Sstevel@tonic-gate 		exit(E_ERROR);
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	/*
3757c478bd9Sstevel@tonic-gate 	 * Here, we know the arguments are correct, the filename is an
3767c478bd9Sstevel@tonic-gate 	 * absolute path, it exists and is a regular file. We don't yet
3777c478bd9Sstevel@tonic-gate 	 * know that the device name is ok or not.
3787c478bd9Sstevel@tonic-gate 	 */
3797c478bd9Sstevel@tonic-gate 	/*
3807c478bd9Sstevel@tonic-gate 	 * Now to the real work.
3817c478bd9Sstevel@tonic-gate 	 */
3827c478bd9Sstevel@tonic-gate 	openflag = O_EXCL;
3837c478bd9Sstevel@tonic-gate 	if (addflag || deleteflag)
3847c478bd9Sstevel@tonic-gate 		openflag |= O_RDWR;
3857c478bd9Sstevel@tonic-gate 	else
3867c478bd9Sstevel@tonic-gate 		openflag |= O_RDONLY;
3877c478bd9Sstevel@tonic-gate 	lfd = open(lofictl, openflag);
3887c478bd9Sstevel@tonic-gate 	if (lfd == -1) {
3897c478bd9Sstevel@tonic-gate 		if ((errno == EPERM) || (errno == EACCES)) {
3907c478bd9Sstevel@tonic-gate 			die("you do not have permission to perform "
3917c478bd9Sstevel@tonic-gate 			    "that operation.\n");
3927c478bd9Sstevel@tonic-gate 		} else {
3937c478bd9Sstevel@tonic-gate 			die("%s", lofictl);
3947c478bd9Sstevel@tonic-gate 		}
3957c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
3967c478bd9Sstevel@tonic-gate 	}
3977c478bd9Sstevel@tonic-gate 	if (addflag)
3987c478bd9Sstevel@tonic-gate 		add_mapping(lfd, devicename, filename);
3997c478bd9Sstevel@tonic-gate 	else if (deleteflag)
400*3d7072f8Seschrock 		delete_mapping(lfd, devicename, filename, force);
4017c478bd9Sstevel@tonic-gate 	else if (filename || devicename)
4027c478bd9Sstevel@tonic-gate 		print_one_mapping(lfd, devicename, filename);
4037c478bd9Sstevel@tonic-gate 	else
4047c478bd9Sstevel@tonic-gate 		print_mappings(lfd);
4057c478bd9Sstevel@tonic-gate 	(void) close(lfd);
4067c478bd9Sstevel@tonic-gate 	return (E_SUCCESS);
4077c478bd9Sstevel@tonic-gate }
408