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