xref: /titanic_44/usr/src/cmd/stmsboot/stmsboot_util.c (revision 80ab886d233f514d54c2a6bdeb9fdfd951bd6881)
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*80ab886dSwesolows  * Common Development and Distribution License (the "License").
6*80ab886dSwesolows  * 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  */
21*80ab886dSwesolows 
227c478bd9Sstevel@tonic-gate /*
23*80ab886dSwesolows  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <stdarg.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/stat.h>
347c478bd9Sstevel@tonic-gate #include <fcntl.h>
357c478bd9Sstevel@tonic-gate #include <errno.h>
367c478bd9Sstevel@tonic-gate #include <unistd.h>
377c478bd9Sstevel@tonic-gate #include <stropts.h>
387c478bd9Sstevel@tonic-gate #include <strings.h>
397c478bd9Sstevel@tonic-gate #include <dirent.h>
407c478bd9Sstevel@tonic-gate #include <sys/param.h>
417c478bd9Sstevel@tonic-gate #include <sys/scsi/adapters/scsi_vhci.h>
427c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
437c478bd9Sstevel@tonic-gate #include <libgen.h>
447c478bd9Sstevel@tonic-gate #include <dlfcn.h>
457c478bd9Sstevel@tonic-gate #include <link.h>
467c478bd9Sstevel@tonic-gate #include <locale.h>
477c478bd9Sstevel@tonic-gate #include <libintl.h>
487c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
497c478bd9Sstevel@tonic-gate #include <sys/vfstab.h>
507c478bd9Sstevel@tonic-gate #include <sys/mount.h>
517c478bd9Sstevel@tonic-gate #include <devid.h>
527c478bd9Sstevel@tonic-gate #include <sys/libdevid.h>
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #define	VHCI_CTL_NODE	"/devices/scsi_vhci:devctl"
557c478bd9Sstevel@tonic-gate #define	SLASH_DEVICES	"/devices/"
567c478bd9Sstevel@tonic-gate #define	SLASH_SSD_AT	"/ssd@"
577c478bd9Sstevel@tonic-gate #define	SLASH_FP_AT	"/fp@"
587c478bd9Sstevel@tonic-gate #define	SLASH_SCSI_VHCI	"/scsi_vhci"
597c478bd9Sstevel@tonic-gate #define	DEV_DSK		"/dev/dsk/"
607c478bd9Sstevel@tonic-gate #define	DEV_RDSK	"/dev/rdsk/"
617c478bd9Sstevel@tonic-gate #define	SYS_FILENAME_LEN	256
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate  * Save directory is the directory in which system files are saved.
657c478bd9Sstevel@tonic-gate  * Save directory must be under the root filesystem, as this program is
667c478bd9Sstevel@tonic-gate  * typically run before any other filesystems are mounted.
677c478bd9Sstevel@tonic-gate  */
687c478bd9Sstevel@tonic-gate #define	SAVE_DIR	"/etc/mpxio"
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /* fcp driver publishes this property */
717c478bd9Sstevel@tonic-gate #define	NODE_WWN_PROP	"node-wwn"
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate typedef enum {
747c478bd9Sstevel@tonic-gate 	CLIENT_TYPE_UNKNOWN,
757c478bd9Sstevel@tonic-gate 	CLIENT_TYPE_PHCI,
767c478bd9Sstevel@tonic-gate 	CLIENT_TYPE_VHCI
777c478bd9Sstevel@tonic-gate } client_type_t;
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate struct devlink_cbarg {
807c478bd9Sstevel@tonic-gate 	char *devlink;
817c478bd9Sstevel@tonic-gate 	size_t len;
827c478bd9Sstevel@tonic-gate };
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate static di_node_t devinfo_root = DI_NODE_NIL;
857c478bd9Sstevel@tonic-gate static di_devlink_handle_t devlink_hdl = NULL;
867c478bd9Sstevel@tonic-gate static int vhci_fd = -1;
877c478bd9Sstevel@tonic-gate static int patch_vfstab, cap_m_option, debug;
887c478bd9Sstevel@tonic-gate static int list_option, list_guid_mappings, list_controllernum = -1;
897c478bd9Sstevel@tonic-gate static char *mapdev = "";
907c478bd9Sstevel@tonic-gate static char *stmsboot = "stmsboot";
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate static int make_temp(char *, char *, char *, size_t);
937c478bd9Sstevel@tonic-gate static void commit_change(char *, char *, char *, int);
947c478bd9Sstevel@tonic-gate static int map_devname(char *, char *, size_t, int);
957c478bd9Sstevel@tonic-gate static int update_vfstab(char *, char *);
967c478bd9Sstevel@tonic-gate static int list_mappings(int, int);
977c478bd9Sstevel@tonic-gate static int canopen(char *);
987c478bd9Sstevel@tonic-gate static void logerr(char *, ...);
997c478bd9Sstevel@tonic-gate static void logdmsg(char *, ...);
1007c478bd9Sstevel@tonic-gate static void *s_malloc(const size_t);
1017c478bd9Sstevel@tonic-gate static char *s_strdup(const char *);
1027c478bd9Sstevel@tonic-gate static void s_strlcpy(char *, const char *, size_t);
103264d6c47Seota /*
104264d6c47Seota  * Using an exit function not marked __NORETURN causes a warning with gcc.
105264d6c47Seota  * To suppress the warning, use __NORETURN attribute.
106264d6c47Seota  */
107264d6c47Seota static void clean_exit(int)__NORETURN;
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate /*
1107c478bd9Sstevel@tonic-gate  * Print usage and exit.
1117c478bd9Sstevel@tonic-gate  */
1127c478bd9Sstevel@tonic-gate static void
1137c478bd9Sstevel@tonic-gate usage(char *argv0)
1147c478bd9Sstevel@tonic-gate {
1157c478bd9Sstevel@tonic-gate 	char *progname;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	progname = strrchr(argv0, '/');
1187c478bd9Sstevel@tonic-gate 	if (progname != NULL)
1197c478bd9Sstevel@tonic-gate 		progname++;
1207c478bd9Sstevel@tonic-gate 	else
1217c478bd9Sstevel@tonic-gate 		progname = argv0;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	/*
1247c478bd9Sstevel@tonic-gate 	 * -u	update /etc/vfstab
1257c478bd9Sstevel@tonic-gate 	 * -m devname
1267c478bd9Sstevel@tonic-gate 	 *	if devname is phci based name and not open-able, map it to
1277c478bd9Sstevel@tonic-gate 	 *	vhci based /devices name.
1287c478bd9Sstevel@tonic-gate 	 *	if devname is vhci based name and not open-able, map it to
1297c478bd9Sstevel@tonic-gate 	 *	phci based /devices name.
1307c478bd9Sstevel@tonic-gate 	 * -M devname
1317c478bd9Sstevel@tonic-gate 	 *	same as -m except that /dev link is printed instead of
1327c478bd9Sstevel@tonic-gate 	 *	/devices name.
1337c478bd9Sstevel@tonic-gate 	 * -l controller
1347c478bd9Sstevel@tonic-gate 	 *	list non-STMS to STMS device name mappings for the specific
1357c478bd9Sstevel@tonic-gate 	 *	controller
1367c478bd9Sstevel@tonic-gate 	 * -L	list non-STMS to STMS device name mappings for all controllers
1377c478bd9Sstevel@tonic-gate 	 */
1387c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("usage: %s -u | -m devname | "
1397c478bd9Sstevel@tonic-gate 	    "-M devname | -l controller | -L\n"), progname);
1407c478bd9Sstevel@tonic-gate 	exit(2);
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate /*
1447c478bd9Sstevel@tonic-gate  * Parse command line arguments.
1457c478bd9Sstevel@tonic-gate  */
1467c478bd9Sstevel@tonic-gate static void
1477c478bd9Sstevel@tonic-gate parse_args(int argc, char *argv[])
1487c478bd9Sstevel@tonic-gate {
1497c478bd9Sstevel@tonic-gate 	char opt;
1507c478bd9Sstevel@tonic-gate 	int n = 0;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	if (argc == 1) {
1537c478bd9Sstevel@tonic-gate 		usage(argv[0]);
1547c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
1557c478bd9Sstevel@tonic-gate 	}
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "udm:M:Ll:g")) != EOF) {
1587c478bd9Sstevel@tonic-gate 		switch (opt) {
1597c478bd9Sstevel@tonic-gate 		case 'u':
1607c478bd9Sstevel@tonic-gate 			patch_vfstab = 1;
1617c478bd9Sstevel@tonic-gate 			n++;
1627c478bd9Sstevel@tonic-gate 			break;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 		case 'd':
1657c478bd9Sstevel@tonic-gate 			debug = 1;
1667c478bd9Sstevel@tonic-gate 			break;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 		case 'm':
1697c478bd9Sstevel@tonic-gate 			mapdev = s_strdup(optarg);
1707c478bd9Sstevel@tonic-gate 			n++;
1717c478bd9Sstevel@tonic-gate 			break;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 		case 'M':
1747c478bd9Sstevel@tonic-gate 			mapdev = s_strdup(optarg);
1757c478bd9Sstevel@tonic-gate 			cap_m_option = 1;
1767c478bd9Sstevel@tonic-gate 			n++;
1777c478bd9Sstevel@tonic-gate 			break;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 		case 'L':
1807c478bd9Sstevel@tonic-gate 			list_option = 1;
1817c478bd9Sstevel@tonic-gate 			n++;
1827c478bd9Sstevel@tonic-gate 			break;
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 		case 'l':
1857c478bd9Sstevel@tonic-gate 			list_option = 1;
1867c478bd9Sstevel@tonic-gate 			list_controllernum = (int)atol(optarg);
1877c478bd9Sstevel@tonic-gate 			if (list_controllernum < 0) {
1887c478bd9Sstevel@tonic-gate 				logerr(gettext("controller number %d is "
1897c478bd9Sstevel@tonic-gate 				    "invalid\n"), list_controllernum);
1907c478bd9Sstevel@tonic-gate 				clean_exit(1);
1917c478bd9Sstevel@tonic-gate 			}
1927c478bd9Sstevel@tonic-gate 			n++;
1937c478bd9Sstevel@tonic-gate 			break;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 		case 'g':
1967c478bd9Sstevel@tonic-gate 			/*
1977c478bd9Sstevel@tonic-gate 			 * private option to display non-STMS device name
1987c478bd9Sstevel@tonic-gate 			 * to GUID mappings.
1997c478bd9Sstevel@tonic-gate 			 */
2007c478bd9Sstevel@tonic-gate 			list_guid_mappings = 1;
2017c478bd9Sstevel@tonic-gate 			n++;
2027c478bd9Sstevel@tonic-gate 			break;
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 		default:
2057c478bd9Sstevel@tonic-gate 			usage(argv[0]);
2067c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
2077c478bd9Sstevel@tonic-gate 		}
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	if (n != 1)
2117c478bd9Sstevel@tonic-gate 		usage(argv[0]);
2127c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate 
215*80ab886dSwesolows int
2167c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	char save_vfstab[SYS_FILENAME_LEN], tmp_vfstab[SYS_FILENAME_LEN];
2197c478bd9Sstevel@tonic-gate 	int vfstab_updated;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2227c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	if (getuid() != 0) {
2257c478bd9Sstevel@tonic-gate 		logerr(gettext("must be super-user to run this program\n"));
2267c478bd9Sstevel@tonic-gate 		clean_exit(1);
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	parse_args(argc, argv);
2307c478bd9Sstevel@tonic-gate 	(void) umask(022);
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	/*
2337c478bd9Sstevel@tonic-gate 	 * NOTE: The mpxio boot-up script executes this program with the
2347c478bd9Sstevel@tonic-gate 	 * mapping (-m) option before the /usr is even mounted and when the
2357c478bd9Sstevel@tonic-gate 	 * root filesystem is still mounted read-only.
2367c478bd9Sstevel@tonic-gate 	 */
2377c478bd9Sstevel@tonic-gate 	if (*mapdev != '\0') {
2387c478bd9Sstevel@tonic-gate 		char newname[MAXPATHLEN];
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 		if (map_devname(mapdev, newname, sizeof (newname),
2417c478bd9Sstevel@tonic-gate 		    cap_m_option) == 0) {
2427c478bd9Sstevel@tonic-gate 			(void) printf("%s\n", newname);
2437c478bd9Sstevel@tonic-gate 			clean_exit(0);
2447c478bd9Sstevel@tonic-gate 		}
2457c478bd9Sstevel@tonic-gate 		clean_exit(1);
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	if (list_option || list_guid_mappings) {
2497c478bd9Sstevel@tonic-gate 		if (list_mappings(list_controllernum, list_guid_mappings) == 0)
2507c478bd9Sstevel@tonic-gate 			clean_exit(0);
2517c478bd9Sstevel@tonic-gate 		clean_exit(1);
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	/* create a directory where a copy of the system files are saved */
2557c478bd9Sstevel@tonic-gate 	if (patch_vfstab) {
2567c478bd9Sstevel@tonic-gate 		if (mkdirp(SAVE_DIR, 0755) != 0 && errno != EEXIST) {
2577c478bd9Sstevel@tonic-gate 			logerr(gettext("mkdirp: failed to create %1$s: %2$s\n"),
2587c478bd9Sstevel@tonic-gate 			    SAVE_DIR, strerror(errno));
2597c478bd9Sstevel@tonic-gate 			clean_exit(1);
2607c478bd9Sstevel@tonic-gate 		}
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 		if (make_temp(VFSTAB, save_vfstab, tmp_vfstab,
2637c478bd9Sstevel@tonic-gate 		    SYS_FILENAME_LEN) != 0)
2647c478bd9Sstevel@tonic-gate 			clean_exit(1);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 		/* build new vfstab without modifying the existing one */
2677c478bd9Sstevel@tonic-gate 		if ((vfstab_updated = update_vfstab(VFSTAB, tmp_vfstab))
2687c478bd9Sstevel@tonic-gate 		    == -1) {
2697c478bd9Sstevel@tonic-gate 			logerr(gettext("failed to update %s\n"), VFSTAB);
2707c478bd9Sstevel@tonic-gate 			clean_exit(1);
2717c478bd9Sstevel@tonic-gate 		}
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 		commit_change(VFSTAB, save_vfstab, tmp_vfstab, vfstab_updated);
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	clean_exit(0);
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate  * Make saved and temporary filenames in SAVE_DIR.
2817c478bd9Sstevel@tonic-gate  *
2827c478bd9Sstevel@tonic-gate  * ex: if the filename is /etc/vfstab then the save_filename and tmp_filename
2837c478bd9Sstevel@tonic-gate  * would be SAVE_DIR/vfstab and SAVE_DIR/vfstab.tmp respectively.
2847c478bd9Sstevel@tonic-gate  *
2857c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
2867c478bd9Sstevel@tonic-gate  */
2877c478bd9Sstevel@tonic-gate static int
2887c478bd9Sstevel@tonic-gate make_temp(char *filename, char *save_filename, char *tmp_filename, size_t len)
2897c478bd9Sstevel@tonic-gate {
2907c478bd9Sstevel@tonic-gate 	char *ptr;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	if ((ptr = strrchr(filename, '/')) == NULL) {
2937c478bd9Sstevel@tonic-gate 		logdmsg("invalid file %s\n", filename);
2947c478bd9Sstevel@tonic-gate 		return (-1);
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 	(void) snprintf(save_filename, len, "%s%s", SAVE_DIR, ptr);
2977c478bd9Sstevel@tonic-gate 	(void) snprintf(tmp_filename, len, "%s%s.tmp", SAVE_DIR, ptr);
2987c478bd9Sstevel@tonic-gate 	logdmsg("make_temp: %s: save = %s, temp = %s\n", filename,
2997c478bd9Sstevel@tonic-gate 	    save_filename, tmp_filename);
3007c478bd9Sstevel@tonic-gate 	return (0);
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate /*
3047c478bd9Sstevel@tonic-gate  * Commit the changes made to the system file
3057c478bd9Sstevel@tonic-gate  */
3067c478bd9Sstevel@tonic-gate static void
3077c478bd9Sstevel@tonic-gate commit_change(char *filename, char *save_filename, char *tmp_filename,
3087c478bd9Sstevel@tonic-gate     int updated)
3097c478bd9Sstevel@tonic-gate {
3107c478bd9Sstevel@tonic-gate 	int x;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	if (updated) {
3137c478bd9Sstevel@tonic-gate 		/* save the original */
3147c478bd9Sstevel@tonic-gate 		if ((x = rename(filename, save_filename)) != 0) {
3157c478bd9Sstevel@tonic-gate 			logerr(gettext("rename %1$s to %2$s failed: %3$s\n"),
3167c478bd9Sstevel@tonic-gate 			    filename, save_filename, strerror(errno));
3177c478bd9Sstevel@tonic-gate 		}
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 		/* now rename the new file to the actual file */
3207c478bd9Sstevel@tonic-gate 		if (rename(tmp_filename, filename) != 0) {
3217c478bd9Sstevel@tonic-gate 			logerr(gettext("rename %1$s to %2$s failed: %3$s\n"),
3227c478bd9Sstevel@tonic-gate 			    tmp_filename, filename, strerror(errno));
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 			/* restore the original */
3257c478bd9Sstevel@tonic-gate 			if (x == 0 && rename(save_filename, filename) != 0) {
3267c478bd9Sstevel@tonic-gate 				logerr(
3277c478bd9Sstevel@tonic-gate 				    gettext("rename %1$s to %2$s failed: %3$s\n"
3287c478bd9Sstevel@tonic-gate 				    "%4$s is a copy of the original %5$s file"
3297c478bd9Sstevel@tonic-gate 				    "\n"),
3307c478bd9Sstevel@tonic-gate 				    save_filename, filename, strerror(errno),
3317c478bd9Sstevel@tonic-gate 				    save_filename, filename);
3327c478bd9Sstevel@tonic-gate 			}
3337c478bd9Sstevel@tonic-gate 		} else
3347c478bd9Sstevel@tonic-gate 			(void) printf(gettext("%1$s: %2$s has been updated.\n"),
3357c478bd9Sstevel@tonic-gate 			    stmsboot, filename);
3367c478bd9Sstevel@tonic-gate 	} else {
3377c478bd9Sstevel@tonic-gate 		/* remove the temp file */
3387c478bd9Sstevel@tonic-gate 		(void) unlink(tmp_filename);
3397c478bd9Sstevel@tonic-gate 		(void) printf(gettext("%1$s: %2$s was not modified as no "
3407c478bd9Sstevel@tonic-gate 		    "changes were needed.\n"), stmsboot, filename);
3417c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate /*
3457c478bd9Sstevel@tonic-gate  * Get the GUID of the device.
3467c478bd9Sstevel@tonic-gate  *
3477c478bd9Sstevel@tonic-gate  * physpath	/devices name without the /devices prefix and minor name
3487c478bd9Sstevel@tonic-gate  *		component.
3497c478bd9Sstevel@tonic-gate  * guid		caller supplied buffer where the GUID will be placed on return
3507c478bd9Sstevel@tonic-gate  * guid_len	length of the caller supplied guid buffer.
3517c478bd9Sstevel@tonic-gate  * no_dealy_flag if set open the device with O_NDELAY
3527c478bd9Sstevel@tonic-gate  * node		di_node corresponding to physpath if already available,
3537c478bd9Sstevel@tonic-gate  *		otherwise pass DI_NODE_NIL.
3547c478bd9Sstevel@tonic-gate  *
3557c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
3567c478bd9Sstevel@tonic-gate  */
3577c478bd9Sstevel@tonic-gate static int
3587c478bd9Sstevel@tonic-gate get_guid(char *physpath, char *guid, int guid_len, int no_delay_flag,
3597c478bd9Sstevel@tonic-gate 	di_node_t node)
3607c478bd9Sstevel@tonic-gate {
3617c478bd9Sstevel@tonic-gate 	int		fd;
3627c478bd9Sstevel@tonic-gate 	ddi_devid_t	devid;
3637c478bd9Sstevel@tonic-gate 	int		rv	= -1;
3647c478bd9Sstevel@tonic-gate 	char		*i_guid	= NULL;
3657c478bd9Sstevel@tonic-gate 	char		physpath_raw[MAXPATHLEN];
3667c478bd9Sstevel@tonic-gate 	uchar_t		*wwnp;
3677c478bd9Sstevel@tonic-gate 	int		i, n, snapshot_taken = 0;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	logdmsg("get_guid: physpath = %s\n", physpath);
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	(void) snprintf(physpath_raw, MAXPATHLEN,
3727c478bd9Sstevel@tonic-gate 	    "/devices%s:a,raw", physpath);
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	*guid = '\0';
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	if (no_delay_flag)
3777c478bd9Sstevel@tonic-gate 		no_delay_flag = O_NDELAY;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	/*
3807c478bd9Sstevel@tonic-gate 	 * Open the raw device
3817c478bd9Sstevel@tonic-gate 	 * Without the O_DELAY flag, the open will fail on standby paths of
3827c478bd9Sstevel@tonic-gate 	 * T3 if its mp_support mode is "mpxio".
3837c478bd9Sstevel@tonic-gate 	 */
3847c478bd9Sstevel@tonic-gate 	if ((fd = open(physpath_raw, O_RDONLY | no_delay_flag)) == -1) {
3857c478bd9Sstevel@tonic-gate 		logdmsg("get_guid: failed to open %s: %s\n", physpath_raw,
3867c478bd9Sstevel@tonic-gate 		    strerror(errno));
3877c478bd9Sstevel@tonic-gate 		return (-1);
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	if (devid_get(fd, &devid) == 0) {
3917c478bd9Sstevel@tonic-gate 		i_guid = devid_to_guid(devid);
3927c478bd9Sstevel@tonic-gate 		devid_free(devid);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 		if (i_guid != NULL) {
3957c478bd9Sstevel@tonic-gate 			s_strlcpy(guid, i_guid, guid_len);
3967c478bd9Sstevel@tonic-gate 			devid_free_guid(i_guid);
3977c478bd9Sstevel@tonic-gate 			rv = 0;
3987c478bd9Sstevel@tonic-gate 			goto out;
3997c478bd9Sstevel@tonic-gate 		} else
4007c478bd9Sstevel@tonic-gate 			logdmsg("get_guid: devid_to_guid() failed\n");
4017c478bd9Sstevel@tonic-gate 	} else
4027c478bd9Sstevel@tonic-gate 		logdmsg("get_guid: devid_get() failed: %s\n", strerror(errno));
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	/* fallback to node name as the guid as this is what fcp driver does */
4057c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
4067c478bd9Sstevel@tonic-gate 		if ((node = di_init(physpath, DINFOCPYALL | DINFOFORCE))
4077c478bd9Sstevel@tonic-gate 		    == DI_NODE_NIL) {
4087c478bd9Sstevel@tonic-gate 			logdmsg("get_guid: di_init on %s failed: %s\n",
4097c478bd9Sstevel@tonic-gate 			    physpath, strerror(errno));
4107c478bd9Sstevel@tonic-gate 			goto out;
4117c478bd9Sstevel@tonic-gate 		}
4127c478bd9Sstevel@tonic-gate 		snapshot_taken = 1;
4137c478bd9Sstevel@tonic-gate 	}
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	if ((n = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, NODE_WWN_PROP,
4167c478bd9Sstevel@tonic-gate 	    &wwnp)) == -1) {
4177c478bd9Sstevel@tonic-gate 		logdmsg("get_guid: di_prop_lookup_bytes() failed to lookup "
4187c478bd9Sstevel@tonic-gate 		    "%s: %s\n", NODE_WWN_PROP, strerror(errno));
4197c478bd9Sstevel@tonic-gate 		goto out;
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	if (guid_len >= ((n * 2) + 1)) {
4237c478bd9Sstevel@tonic-gate 		for (i = 0; i < n; i++) {
4247c478bd9Sstevel@tonic-gate 			(void) sprintf(guid + (i * 2), "%02x", (uint_t)(*wwnp));
4257c478bd9Sstevel@tonic-gate 			wwnp++;
4267c478bd9Sstevel@tonic-gate 		}
4277c478bd9Sstevel@tonic-gate 		rv = 0;
4287c478bd9Sstevel@tonic-gate 	} else
4297c478bd9Sstevel@tonic-gate 		logerr(gettext("insufficient buffer size: need %1$d "
4307c478bd9Sstevel@tonic-gate 		    "bytes, passed %2$d bytes\n"), (n * 2) + 1, guid_len);
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate out:
4337c478bd9Sstevel@tonic-gate 	if (snapshot_taken)
4347c478bd9Sstevel@tonic-gate 		di_fini(node);
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	(void) close(fd);
4377c478bd9Sstevel@tonic-gate 	logdmsg("get_guid: GUID = %s\n", guid);
4387c478bd9Sstevel@tonic-gate 	return (rv);
4397c478bd9Sstevel@tonic-gate }
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate /*
4427c478bd9Sstevel@tonic-gate  * Given client_name return whether it is a phci or vhci based name.
4437c478bd9Sstevel@tonic-gate  * client_name is /devices name of a client without the /devices prefix.
4447c478bd9Sstevel@tonic-gate  *
4457c478bd9Sstevel@tonic-gate  * client_name			Return value
4467c478bd9Sstevel@tonic-gate  * .../fp@xxx/ssd@yyy		CLIENT_TYPE_PHCI
4477c478bd9Sstevel@tonic-gate  * .../scsi_vhci/ssd@yyy	CLIENT_TYPE_VHCI
4487c478bd9Sstevel@tonic-gate  * other			CLIENT_TYPE_UNKNOWN
4497c478bd9Sstevel@tonic-gate  */
4507c478bd9Sstevel@tonic-gate static client_type_t
4517c478bd9Sstevel@tonic-gate client_name_type(char *client_name)
4527c478bd9Sstevel@tonic-gate {
4537c478bd9Sstevel@tonic-gate 	client_type_t client_type = CLIENT_TYPE_UNKNOWN;
4547c478bd9Sstevel@tonic-gate 	char *p1, *p2;
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	if (*client_name != '/')
4577c478bd9Sstevel@tonic-gate 		return (CLIENT_TYPE_UNKNOWN);
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	/* we only care for ssd devices */
4607c478bd9Sstevel@tonic-gate 	if ((p1 = strrchr(client_name, '/')) == NULL ||
4617c478bd9Sstevel@tonic-gate 	    strncmp(p1, SLASH_SSD_AT, sizeof (SLASH_SSD_AT) - 1) != 0)
4627c478bd9Sstevel@tonic-gate 		return (CLIENT_TYPE_UNKNOWN);
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	*p1 = '\0';
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	if ((p2 = strrchr(client_name, '/')) != NULL) {
4677c478bd9Sstevel@tonic-gate 		if (strncmp(p2, SLASH_FP_AT, sizeof (SLASH_FP_AT) - 1) == 0)
4687c478bd9Sstevel@tonic-gate 			client_type = CLIENT_TYPE_PHCI;
4697c478bd9Sstevel@tonic-gate 		else if (strncmp(p2, SLASH_SCSI_VHCI,
4707c478bd9Sstevel@tonic-gate 		    sizeof (SLASH_SCSI_VHCI) - 1) == 0)
4717c478bd9Sstevel@tonic-gate 			client_type = CLIENT_TYPE_VHCI;
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	*p1 = '/';
4757c478bd9Sstevel@tonic-gate 	return (client_type);
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate /*
4797c478bd9Sstevel@tonic-gate  * Map phci based client name to vhci based client name.
4807c478bd9Sstevel@tonic-gate  *
4817c478bd9Sstevel@tonic-gate  * phci_name
4827c478bd9Sstevel@tonic-gate  *	phci based client /devices name without the /devices prefix and
4837c478bd9Sstevel@tonic-gate  *	minor name component.
4847c478bd9Sstevel@tonic-gate  *	ex: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
4857c478bd9Sstevel@tonic-gate  *
4867c478bd9Sstevel@tonic-gate  * vhci_name
4877c478bd9Sstevel@tonic-gate  *	Caller supplied buffer where vhci /devices name will be placed on
4887c478bd9Sstevel@tonic-gate  *	return (without the /devices prefix and minor name component).
4897c478bd9Sstevel@tonic-gate  *	ex: /scsi_vhci/ssd@g2000002037cd9f72
4907c478bd9Sstevel@tonic-gate  *
4917c478bd9Sstevel@tonic-gate  * vhci_name_len
4927c478bd9Sstevel@tonic-gate  *	Length of the caller supplied vhci_name buffer.
4937c478bd9Sstevel@tonic-gate  *
4947c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
4957c478bd9Sstevel@tonic-gate  */
4967c478bd9Sstevel@tonic-gate static int
4977c478bd9Sstevel@tonic-gate phci_to_vhci(char *phci_name, char *vhci_name, size_t vhci_name_len)
4987c478bd9Sstevel@tonic-gate {
4997c478bd9Sstevel@tonic-gate 	sv_iocdata_t ioc;
5007c478bd9Sstevel@tonic-gate 	char *slash;
5017c478bd9Sstevel@tonic-gate 	char vhci_name_buf[MAXPATHLEN];
5027c478bd9Sstevel@tonic-gate 	char phci_name_buf[MAXPATHLEN];
5037c478bd9Sstevel@tonic-gate 	char addr_buf[MAXNAMELEN];
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	logdmsg("phci_to_vhci: client = %s\n", phci_name);
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	s_strlcpy(phci_name_buf, phci_name, MAXPATHLEN);
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	if (client_name_type(phci_name_buf) != CLIENT_TYPE_PHCI ||
5107c478bd9Sstevel@tonic-gate 	    (slash = strrchr(phci_name_buf, '/')) == NULL ||
5117c478bd9Sstevel@tonic-gate 	    strncmp(slash, SLASH_SSD_AT, sizeof (SLASH_SSD_AT) - 1) != 0) {
5127c478bd9Sstevel@tonic-gate 		logdmsg("phci_to_vhci: %s is not of CLIENT_TYPE_PHCI\n",
5137c478bd9Sstevel@tonic-gate 		    phci_name);
5147c478bd9Sstevel@tonic-gate 		return (-1);
5157c478bd9Sstevel@tonic-gate 	}
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	if (vhci_fd < 0) {
5187c478bd9Sstevel@tonic-gate 		if ((vhci_fd = open(VHCI_CTL_NODE, O_RDWR)) < 0)
5197c478bd9Sstevel@tonic-gate 			return (-1);
5207c478bd9Sstevel@tonic-gate 	}
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	*slash = '\0';
5237c478bd9Sstevel@tonic-gate 	s_strlcpy(addr_buf, slash + sizeof (SLASH_SSD_AT) - 1, MAXNAMELEN);
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	bzero(&ioc, sizeof (sv_iocdata_t));
5267c478bd9Sstevel@tonic-gate 	ioc.client = vhci_name_buf;
5277c478bd9Sstevel@tonic-gate 	ioc.phci = phci_name_buf;
5287c478bd9Sstevel@tonic-gate 	ioc.addr = addr_buf;
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	if (ioctl(vhci_fd, SCSI_VHCI_GET_CLIENT_NAME, &ioc) != 0) {
5317c478bd9Sstevel@tonic-gate 		logdmsg("SCSI_VHCI_GET_CLIENT_NAME on %s "
5327c478bd9Sstevel@tonic-gate 		    "failed: %s\n", phci_name, strerror(errno));
5337c478bd9Sstevel@tonic-gate 		return (-1);
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	s_strlcpy(vhci_name, vhci_name_buf, vhci_name_len);
5377c478bd9Sstevel@tonic-gate 	logdmsg("phci_to_vhci: %s maps to %s\n", phci_name, vhci_name);
5387c478bd9Sstevel@tonic-gate 	return (0);
5397c478bd9Sstevel@tonic-gate }
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate /*
5427c478bd9Sstevel@tonic-gate  * Map vhci based client name to phci based client name.
5437c478bd9Sstevel@tonic-gate  * If the client has multiple paths, only one of the paths with which client
5447c478bd9Sstevel@tonic-gate  * can be accessed is returned. This function does not use SCSI_VHCI ioctls
5457c478bd9Sstevel@tonic-gate  * as it is called on mpxio disabled paths.
5467c478bd9Sstevel@tonic-gate  *
5477c478bd9Sstevel@tonic-gate  * vhci_name
5487c478bd9Sstevel@tonic-gate  *	vhci based client /devices name without the /devices prefix and
5497c478bd9Sstevel@tonic-gate  *	minor name component.
5507c478bd9Sstevel@tonic-gate  *	ex: /scsi_vhci/ssd@g2000002037cd9f72
5517c478bd9Sstevel@tonic-gate  *
5527c478bd9Sstevel@tonic-gate  * phci_name
5537c478bd9Sstevel@tonic-gate  *	Caller supplied buffer where phci /devices name will be placed on
5547c478bd9Sstevel@tonic-gate  *	return (without the /devices prefix and minor name component).
5557c478bd9Sstevel@tonic-gate  *	ex: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
5567c478bd9Sstevel@tonic-gate  *
5577c478bd9Sstevel@tonic-gate  * phci_name_len
5587c478bd9Sstevel@tonic-gate  *	Length of the caller supplied phci_name buffer.
5597c478bd9Sstevel@tonic-gate  *
5607c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
5617c478bd9Sstevel@tonic-gate  */
5627c478bd9Sstevel@tonic-gate static int
5637c478bd9Sstevel@tonic-gate vhci_to_phci(char *vhci_name, char *phci_name, size_t phci_name_len)
5647c478bd9Sstevel@tonic-gate {
5657c478bd9Sstevel@tonic-gate 	di_node_t node, parent;
5667c478bd9Sstevel@tonic-gate 	char *vhci_guid, *devfspath;
5677c478bd9Sstevel@tonic-gate 	char phci_guid[MAXPATHLEN];
5687c478bd9Sstevel@tonic-gate 	char *parent_name, *node_name;
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	logdmsg("vhci_to_phci: client = %s\n", vhci_name);
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	if (client_name_type(vhci_name) != CLIENT_TYPE_VHCI) {
5737c478bd9Sstevel@tonic-gate 		logdmsg("vhci_to_phci: %s is not of CLIENT_TYPE_VHCI\n",
5747c478bd9Sstevel@tonic-gate 		    vhci_name);
5757c478bd9Sstevel@tonic-gate 		return (-1);
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	if ((vhci_guid = strrchr(vhci_name, '@')) == NULL ||
5797c478bd9Sstevel@tonic-gate 	    *(++vhci_guid) != 'g') {
5807c478bd9Sstevel@tonic-gate 		logerr(gettext("couldn't get guid from %s\n"), vhci_name);
5817c478bd9Sstevel@tonic-gate 		return (-1);
5827c478bd9Sstevel@tonic-gate 	}
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	/* point to guid */
5857c478bd9Sstevel@tonic-gate 	++vhci_guid;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	/*
5887c478bd9Sstevel@tonic-gate 	 * Get devinfo snapshot and walk all ssd nodes whose parent is fp.
5897c478bd9Sstevel@tonic-gate 	 * For each node get the guid and match it with vhci_guid.
5907c478bd9Sstevel@tonic-gate 	 */
5917c478bd9Sstevel@tonic-gate 	if (devinfo_root == DI_NODE_NIL) {
5927c478bd9Sstevel@tonic-gate 		logdmsg("vhci_to_phci: taking devinfo snapshot\n");
5937c478bd9Sstevel@tonic-gate 		if ((devinfo_root = di_init("/", DINFOCPYALL | DINFOFORCE))
5947c478bd9Sstevel@tonic-gate 		    == DI_NODE_NIL) {
5957c478bd9Sstevel@tonic-gate 			logerr(gettext("di_init failed: %s\n"),
5967c478bd9Sstevel@tonic-gate 			    strerror(errno));
5977c478bd9Sstevel@tonic-gate 			return (-1);
5987c478bd9Sstevel@tonic-gate 		}
5997c478bd9Sstevel@tonic-gate 		logdmsg("vhci_to_phci: done taking devinfo snapshot\n");
6007c478bd9Sstevel@tonic-gate 	}
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	for (node = di_drv_first_node("ssd", devinfo_root);
6037c478bd9Sstevel@tonic-gate 	    node != DI_NODE_NIL; node = di_drv_next_node(node)) {
6047c478bd9Sstevel@tonic-gate 		if ((node_name = di_node_name(node)) == NULL ||
6057c478bd9Sstevel@tonic-gate 		    strcmp(node_name, "ssd") != 0 ||
6067c478bd9Sstevel@tonic-gate 		    (parent = di_parent_node(node)) == DI_NODE_NIL ||
6077c478bd9Sstevel@tonic-gate 		    (parent_name = di_node_name(parent)) == NULL ||
6087c478bd9Sstevel@tonic-gate 		    strcmp(parent_name, "fp") != 0 ||
6097c478bd9Sstevel@tonic-gate 		    (devfspath = di_devfs_path(node)) == NULL)
6107c478bd9Sstevel@tonic-gate 			continue;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 		/*
6137c478bd9Sstevel@tonic-gate 		 * Don't set no_delay_flag to have get_guid() fail on
6147c478bd9Sstevel@tonic-gate 		 * standby paths of T3. So we'll find the preferred paths.
6157c478bd9Sstevel@tonic-gate 		 */
6167c478bd9Sstevel@tonic-gate 		if (get_guid(devfspath, phci_guid,
6177c478bd9Sstevel@tonic-gate 		    sizeof (phci_guid), 0, node) == 0 &&
6187c478bd9Sstevel@tonic-gate 		    strcmp(phci_guid, vhci_guid) == 0) {
6197c478bd9Sstevel@tonic-gate 			s_strlcpy(phci_name, devfspath, phci_name_len);
6207c478bd9Sstevel@tonic-gate 			di_devfs_path_free(devfspath);
6217c478bd9Sstevel@tonic-gate 			logdmsg("vhci_to_phci: %s maps to %s\n", vhci_name,
6227c478bd9Sstevel@tonic-gate 			    phci_name);
6237c478bd9Sstevel@tonic-gate 			return (0);
6247c478bd9Sstevel@tonic-gate 		}
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
6277c478bd9Sstevel@tonic-gate 	}
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	logdmsg("vhci_to_phci: couldn't get phci name for %s\n", vhci_name);
6307c478bd9Sstevel@tonic-gate 	return (-1);
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate /*
6347c478bd9Sstevel@tonic-gate  * Map physname from phci name space to vhci name space or vice-versa
6357c478bd9Sstevel@tonic-gate  *
6367c478bd9Sstevel@tonic-gate  * physname
6377c478bd9Sstevel@tonic-gate  *	phci or vhci based client /devices name without the /devices prefix and
6387c478bd9Sstevel@tonic-gate  *	minor name component.
6397c478bd9Sstevel@tonic-gate  *
6407c478bd9Sstevel@tonic-gate  * new_physname
6417c478bd9Sstevel@tonic-gate  *	Caller supplied buffer where the mapped physical name is stored on
6427c478bd9Sstevel@tonic-gate  *	return (without the /devices prefix and minor name component).
6437c478bd9Sstevel@tonic-gate  *
6447c478bd9Sstevel@tonic-gate  * len
6457c478bd9Sstevel@tonic-gate  *	Length of the caller supplied new_physname buffer.
6467c478bd9Sstevel@tonic-gate  *
6477c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
6487c478bd9Sstevel@tonic-gate  */
6497c478bd9Sstevel@tonic-gate static int
6507c478bd9Sstevel@tonic-gate map_physname(char *physname, char *new_physname, size_t len)
6517c478bd9Sstevel@tonic-gate {
6527c478bd9Sstevel@tonic-gate 	int type;
6537c478bd9Sstevel@tonic-gate 	int rv;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	if ((type = client_name_type(physname)) == CLIENT_TYPE_VHCI)
6567c478bd9Sstevel@tonic-gate 		rv = vhci_to_phci(physname, new_physname, len);
6577c478bd9Sstevel@tonic-gate 	else if (type == CLIENT_TYPE_PHCI)
6587c478bd9Sstevel@tonic-gate 		rv = phci_to_vhci(physname, new_physname, len);
6597c478bd9Sstevel@tonic-gate 	else
6607c478bd9Sstevel@tonic-gate 		rv = -1;
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	return (rv);
6637c478bd9Sstevel@tonic-gate }
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate /*
6667c478bd9Sstevel@tonic-gate  * Given a phci or vhci devname which is either a /dev link or /devices name
6677c478bd9Sstevel@tonic-gate  * get the corresponding physical node path (without the /devices prefix)
6687c478bd9Sstevel@tonic-gate  * and minor name.
6697c478bd9Sstevel@tonic-gate  *
6707c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
6717c478bd9Sstevel@tonic-gate  */
6727c478bd9Sstevel@tonic-gate static int
6737c478bd9Sstevel@tonic-gate get_physname_minor(char *devname, char *physname, int physname_len,
6747c478bd9Sstevel@tonic-gate     char *minorname, int minorname_len)
6757c478bd9Sstevel@tonic-gate {
6767c478bd9Sstevel@tonic-gate 	int linksize;
6777c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
6787c478bd9Sstevel@tonic-gate 	char *p, *m;
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	if (strncmp(devname, DEV_DSK, sizeof (DEV_DSK) - 1) == 0 ||
6817c478bd9Sstevel@tonic-gate 	    strncmp(devname, DEV_RDSK, sizeof (DEV_RDSK) - 1) == 0) {
6827c478bd9Sstevel@tonic-gate 		if ((linksize = readlink(devname, buf, MAXPATHLEN))
6837c478bd9Sstevel@tonic-gate 		    > 0 && linksize <= (MAXPATHLEN - 1)) {
6847c478bd9Sstevel@tonic-gate 			buf[linksize] = '\0';
6857c478bd9Sstevel@tonic-gate 		} else
6867c478bd9Sstevel@tonic-gate 			return (-1);
6877c478bd9Sstevel@tonic-gate 	} else
6887c478bd9Sstevel@tonic-gate 		s_strlcpy(buf, devname, MAXPATHLEN);
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	if ((p = strstr(buf, SLASH_DEVICES)) == NULL)
6917c478bd9Sstevel@tonic-gate 		return (-1);
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	/* point to '/' after /devices */
6947c478bd9Sstevel@tonic-gate 	p += sizeof (SLASH_DEVICES) - 2;
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	if ((m = strrchr(p, ':')) == NULL) {
6977c478bd9Sstevel@tonic-gate 		logdmsg("get_physname_minor: no minor name component in %s\n",
6987c478bd9Sstevel@tonic-gate 		    buf);
6997c478bd9Sstevel@tonic-gate 		return (-1);
7007c478bd9Sstevel@tonic-gate 	}
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	*m = '\0';
7037c478bd9Sstevel@tonic-gate 	m++;
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	if (client_name_type(p) == CLIENT_TYPE_UNKNOWN)
7067c478bd9Sstevel@tonic-gate 		return (-1);
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	s_strlcpy(physname, p, physname_len);
7097c478bd9Sstevel@tonic-gate 	s_strlcpy(minorname, m, minorname_len);
7107c478bd9Sstevel@tonic-gate 	logdmsg("get_physname_minor: %s: physname = %s, minor = %s\n",
7117c478bd9Sstevel@tonic-gate 	    devname, physname, minorname);
7127c478bd9Sstevel@tonic-gate 	return (0);
7137c478bd9Sstevel@tonic-gate }
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate static int
7167c478bd9Sstevel@tonic-gate devlink_callback(di_devlink_t devlink, void *argptr)
7177c478bd9Sstevel@tonic-gate {
7187c478bd9Sstevel@tonic-gate 	const char *link;
7197c478bd9Sstevel@tonic-gate 	struct devlink_cbarg *argp = argptr;
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	if ((link = di_devlink_path(devlink)) != NULL) {
7227c478bd9Sstevel@tonic-gate 		s_strlcpy(argp->devlink, link, argp->len);
7237c478bd9Sstevel@tonic-gate 		return (DI_WALK_TERMINATE);
7247c478bd9Sstevel@tonic-gate 	}
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
7277c478bd9Sstevel@tonic-gate }
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate /*
7307c478bd9Sstevel@tonic-gate  * Lookup the /dev link corresponding to physname and minorname.
7317c478bd9Sstevel@tonic-gate  *
7327c478bd9Sstevel@tonic-gate  * physname	client /devices path without the /devices prefix and minor
7337c478bd9Sstevel@tonic-gate  *		name component.
7347c478bd9Sstevel@tonic-gate  * minorname	client minor name.
7357c478bd9Sstevel@tonic-gate  * devlink	caller supplied buffer where the /dev link is placed on return.
7367c478bd9Sstevel@tonic-gate  * len		caller supplied devlink buffer length
7377c478bd9Sstevel@tonic-gate  *
7387c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
7397c478bd9Sstevel@tonic-gate  */
7407c478bd9Sstevel@tonic-gate static int
7417c478bd9Sstevel@tonic-gate lookup_devlink(char *physname, char *minorname, char *devlink, size_t len)
7427c478bd9Sstevel@tonic-gate {
7437c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
7447c478bd9Sstevel@tonic-gate 	struct devlink_cbarg arg;
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	if (devlink_hdl == NULL) {
7477c478bd9Sstevel@tonic-gate 		logdmsg("lookup_devlink: taking devlink snapshot\n");
7487c478bd9Sstevel@tonic-gate 		if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
7497c478bd9Sstevel@tonic-gate 			logerr(gettext("di_devlink_init failed: %s\n"),
7507c478bd9Sstevel@tonic-gate 			    strerror(errno));
7517c478bd9Sstevel@tonic-gate 			clean_exit(1);
7527c478bd9Sstevel@tonic-gate 		}
7537c478bd9Sstevel@tonic-gate 	}
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	*devlink = '\0';
7567c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, MAXPATHLEN, "%s:%s", physname, minorname);
7577c478bd9Sstevel@tonic-gate 	arg.devlink = devlink;
7587c478bd9Sstevel@tonic-gate 	arg.len = len;
7597c478bd9Sstevel@tonic-gate 	if (di_devlink_walk(devlink_hdl, NULL, buf, DI_PRIMARY_LINK, &arg,
7607c478bd9Sstevel@tonic-gate 	    devlink_callback) != 0) {
7617c478bd9Sstevel@tonic-gate 		logdmsg("lookup_devlink: di_devlink_walk on %s failed: %s\n",
7627c478bd9Sstevel@tonic-gate 		    buf, strerror(errno));
7637c478bd9Sstevel@tonic-gate 		return (-1);
7647c478bd9Sstevel@tonic-gate 	}
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	if (*devlink == '\0') {
7677c478bd9Sstevel@tonic-gate 		logdmsg("lookup_devlink: failed to lookup devlink for %s\n",
7687c478bd9Sstevel@tonic-gate 		    buf);
7697c478bd9Sstevel@tonic-gate 		return (-1);
7707c478bd9Sstevel@tonic-gate 	}
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	logdmsg("lookup_devlink: /dev link for %s:%s = %s\n", physname,
7737c478bd9Sstevel@tonic-gate 	    minorname, devlink);
7747c478bd9Sstevel@tonic-gate 	return (0);
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate /*
7787c478bd9Sstevel@tonic-gate  * open infile for reading and return its file pointer in *fp_in.
7797c478bd9Sstevel@tonic-gate  * open outfile for writing and return its file pointer in *fp_out.
7807c478bd9Sstevel@tonic-gate  *
7817c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
7827c478bd9Sstevel@tonic-gate  */
7837c478bd9Sstevel@tonic-gate static int
7847c478bd9Sstevel@tonic-gate open_in_out_files(char *infile, char *outfile, FILE **fp_in, FILE **fp_out)
7857c478bd9Sstevel@tonic-gate {
7867c478bd9Sstevel@tonic-gate 	FILE *fin = NULL;
7877c478bd9Sstevel@tonic-gate 	FILE *fout = NULL;
7887c478bd9Sstevel@tonic-gate 	struct stat sbuf;
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	if ((fin = fopen(infile, "r")) == NULL) {
7917c478bd9Sstevel@tonic-gate 		logerr(gettext("failed to fopen %1$s: %2$s\n"),
7927c478bd9Sstevel@tonic-gate 		    infile, strerror(errno));
7937c478bd9Sstevel@tonic-gate 		goto out;
7947c478bd9Sstevel@tonic-gate 	}
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 	if (fstat(fileno(fin), &sbuf) != 0) {
7977c478bd9Sstevel@tonic-gate 		logerr(gettext("fstat failed on %1$s: %2$s\n"),
7987c478bd9Sstevel@tonic-gate 		    infile, strerror(errno));
7997c478bd9Sstevel@tonic-gate 		goto out;
8007c478bd9Sstevel@tonic-gate 	}
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	if ((fout = fopen(outfile, "w")) == NULL) {
8037c478bd9Sstevel@tonic-gate 		logerr(gettext("failed to fopen %1$s: %2$s\n"),
8047c478bd9Sstevel@tonic-gate 		    outfile, strerror(errno));
8057c478bd9Sstevel@tonic-gate 		goto out;
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	if (fchmod(fileno(fout), (sbuf.st_mode & 0777)) != 0) {
8097c478bd9Sstevel@tonic-gate 		logerr(gettext("failed to fchmod %1$s to 0%2$o: %3$s\n"),
8107c478bd9Sstevel@tonic-gate 		    outfile, sbuf.st_mode & 0777, strerror(errno));
8117c478bd9Sstevel@tonic-gate 		goto out;
8127c478bd9Sstevel@tonic-gate 	}
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	if (fchown(fileno(fout), sbuf.st_uid, sbuf.st_gid) != 0) {
8157c478bd9Sstevel@tonic-gate 		logerr(gettext("failed to fchown %1$s to uid %2$d and "
8167c478bd9Sstevel@tonic-gate 		    "gid %3$d: %4$s\n"),
8177c478bd9Sstevel@tonic-gate 		    outfile, sbuf.st_uid, sbuf.st_gid, strerror(errno));
8187c478bd9Sstevel@tonic-gate 		goto out;
8197c478bd9Sstevel@tonic-gate 	}
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	*fp_in = fin;
8227c478bd9Sstevel@tonic-gate 	*fp_out = fout;
8237c478bd9Sstevel@tonic-gate 	return (0);
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate out:
8267c478bd9Sstevel@tonic-gate 	if (fin != NULL)
8277c478bd9Sstevel@tonic-gate 		(void) fclose(fin);
8287c478bd9Sstevel@tonic-gate 	if (fout != NULL)
8297c478bd9Sstevel@tonic-gate 		(void) fclose(fout);
8307c478bd9Sstevel@tonic-gate 	return (-1);
8317c478bd9Sstevel@tonic-gate }
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate /*
8347c478bd9Sstevel@tonic-gate  * If the devname is a phci based name and not open-able, map it to vhci
8357c478bd9Sstevel@tonic-gate  * based name. If the devname is a vhci based name and not open-able, map it
8367c478bd9Sstevel@tonic-gate  * to phci based name.
8377c478bd9Sstevel@tonic-gate  *
8387c478bd9Sstevel@tonic-gate  * devname	either a /dev link or /devices name to client device
8397c478bd9Sstevel@tonic-gate  * new_devname	caller supplied buffer where the mapped device name is
8407c478bd9Sstevel@tonic-gate  *		placed on return.
8417c478bd9Sstevel@tonic-gate  * len		caller supplied new_devname buffer length
8427c478bd9Sstevel@tonic-gate  * devlink_flag	pass 1 if requesting the /dev link to the mapped device.
8437c478bd9Sstevel@tonic-gate  *		pass 0 if requesting the /devices name of the mapped device.
8447c478bd9Sstevel@tonic-gate  *
8457c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
8467c478bd9Sstevel@tonic-gate  */
8477c478bd9Sstevel@tonic-gate static int
8487c478bd9Sstevel@tonic-gate map_devname(char *devname, char *new_devname, size_t len, int devlink_flag)
8497c478bd9Sstevel@tonic-gate {
8507c478bd9Sstevel@tonic-gate 	char physname[MAXPATHLEN];
8517c478bd9Sstevel@tonic-gate 	char minor[MAXNAMELEN];
8527c478bd9Sstevel@tonic-gate 	char new_physname[MAXNAMELEN];
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	if (get_physname_minor(devname, physname, sizeof (physname),
8557c478bd9Sstevel@tonic-gate 	    minor, sizeof (minor)) == 0 &&
8567c478bd9Sstevel@tonic-gate 	    canopen(devname) == 0 &&
8577c478bd9Sstevel@tonic-gate 	    map_physname(physname, new_physname, sizeof (new_physname)) == 0) {
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 		if (devlink_flag) {
8607c478bd9Sstevel@tonic-gate 			if (lookup_devlink(new_physname, minor, new_devname,
8617c478bd9Sstevel@tonic-gate 			    len) == 0)
8627c478bd9Sstevel@tonic-gate 				return (0);
8637c478bd9Sstevel@tonic-gate 		} else {
8647c478bd9Sstevel@tonic-gate 			(void) snprintf(new_devname, len, "/devices%s:%s",
8657c478bd9Sstevel@tonic-gate 			    new_physname, minor);
8667c478bd9Sstevel@tonic-gate 			return (0);
8677c478bd9Sstevel@tonic-gate 		}
8687c478bd9Sstevel@tonic-gate 	}
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	return (-1);
8717c478bd9Sstevel@tonic-gate }
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate /*
8747c478bd9Sstevel@tonic-gate  * Make a new /etc/vfstab:
8757c478bd9Sstevel@tonic-gate  * Read vfstab_in, convert the device name entries to appropriate vhci or phci
8767c478bd9Sstevel@tonic-gate  * based names, and write to vfstab_out. Only device names whose physical
8777c478bd9Sstevel@tonic-gate  * paths are either phci or vhci based names and not open-able are considered
8787c478bd9Sstevel@tonic-gate  * for conversion. Open-able device name entries are not converted as it
8797c478bd9Sstevel@tonic-gate  * means that the device is already accessible; hence no need to convert.
8807c478bd9Sstevel@tonic-gate  *
8817c478bd9Sstevel@tonic-gate  * Returns:
8827c478bd9Sstevel@tonic-gate  * 	0	successful but vfstab_out contents are the same as vfstab_in
8837c478bd9Sstevel@tonic-gate  *	1	successful and vfstab_out changed from vfstab_in
8847c478bd9Sstevel@tonic-gate  *	-1	failed
8857c478bd9Sstevel@tonic-gate  */
8867c478bd9Sstevel@tonic-gate static int
8877c478bd9Sstevel@tonic-gate update_vfstab(char *vfstab_in, char *vfstab_out)
8887c478bd9Sstevel@tonic-gate {
8897c478bd9Sstevel@tonic-gate 	FILE *fp_in, *fp_out;
8907c478bd9Sstevel@tonic-gate 	char *buf, *tmpbuf;
8917c478bd9Sstevel@tonic-gate 	char *vfs_cache[2];
8927c478bd9Sstevel@tonic-gate 	int idx = 0, count = 0;
8937c478bd9Sstevel@tonic-gate 	int rv = -1;
8947c478bd9Sstevel@tonic-gate 	int vfstab_updated = 0;
8957c478bd9Sstevel@tonic-gate 	int i;
8967c478bd9Sstevel@tonic-gate 	char cdev[MAXPATHLEN];
8977c478bd9Sstevel@tonic-gate 	char bdev[MAXPATHLEN];
8987c478bd9Sstevel@tonic-gate 	char mntpt[MAXPATHLEN];
8997c478bd9Sstevel@tonic-gate 	char fstype[512];
9007c478bd9Sstevel@tonic-gate 	char fsckpass[512];
9017c478bd9Sstevel@tonic-gate 	char mntboot[512];
9027c478bd9Sstevel@tonic-gate 	char mntopt[MAX_MNTOPT_STR];
9037c478bd9Sstevel@tonic-gate 	char phys_bdev[MAXPATHLEN], phys_cdev[MAXPATHLEN];
9047c478bd9Sstevel@tonic-gate 	char bdev_minor[MAXNAMELEN], cdev_minor[MAXNAMELEN];
9057c478bd9Sstevel@tonic-gate 	char new_physname[MAXPATHLEN];
9067c478bd9Sstevel@tonic-gate 	char new_bdevlink[MAXPATHLEN], new_cdevlink[MAXPATHLEN];
9077c478bd9Sstevel@tonic-gate 	char fmt[80];
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	if (open_in_out_files(vfstab_in, vfstab_out, &fp_in, &fp_out) != 0)
9107c478bd9Sstevel@tonic-gate 		return (-1);
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	/*
9137c478bd9Sstevel@tonic-gate 	 * Read one line at time from vfstab_in. If no conversion is needed
9147c478bd9Sstevel@tonic-gate 	 * for the line simply write the line to vfstab_out. If conversion is
9157c478bd9Sstevel@tonic-gate 	 * needed, first write the existing line as a comment to vfstab_out
9167c478bd9Sstevel@tonic-gate 	 * and then write the converted line.
9177c478bd9Sstevel@tonic-gate 	 *
9187c478bd9Sstevel@tonic-gate 	 * To avoid commented entries piling up in vfstab in case if the
9197c478bd9Sstevel@tonic-gate 	 * user runs stmsboot multiple times to switch on and off from mpxio,
9207c478bd9Sstevel@tonic-gate 	 * add the commented line only if not already there. To do this
9217c478bd9Sstevel@tonic-gate 	 * cache the last two vfstab lines processed and add the commented
9227c478bd9Sstevel@tonic-gate 	 * entry only if it is not found in the cache. We only need to cache
9237c478bd9Sstevel@tonic-gate 	 * the last two lines because a device can have at most two names -
9247c478bd9Sstevel@tonic-gate 	 * one mpxio and one non-mpxio name. Therefore for any device name
9257c478bd9Sstevel@tonic-gate 	 * entry we at most add two comments - one with mpxio name and one
9267c478bd9Sstevel@tonic-gate 	 * with non-mpxio name - no matter how many times stmsboot is run.
9277c478bd9Sstevel@tonic-gate 	 */
9287c478bd9Sstevel@tonic-gate 	buf = (char *)s_malloc(VFS_LINE_MAX);
9297c478bd9Sstevel@tonic-gate 	tmpbuf = (char *)s_malloc(VFS_LINE_MAX);
9307c478bd9Sstevel@tonic-gate 	vfs_cache[0] = (char *)s_malloc(VFS_LINE_MAX);
9317c478bd9Sstevel@tonic-gate 	vfs_cache[1] = (char *)s_malloc(VFS_LINE_MAX);
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	(void) snprintf(fmt, sizeof (fmt),
9347c478bd9Sstevel@tonic-gate 	    "%%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds", sizeof (bdev) - 1,
9357c478bd9Sstevel@tonic-gate 	    sizeof (cdev) - 1, sizeof (mntpt) - 1, sizeof (fstype) - 1,
9367c478bd9Sstevel@tonic-gate 	    sizeof (fsckpass) - 1, sizeof (mntboot) - 1, sizeof (mntopt) - 1);
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	while (fgets(buf, VFS_LINE_MAX, fp_in) != NULL) {
9397c478bd9Sstevel@tonic-gate 		if (strlen(buf) == (VFS_LINE_MAX - 1) &&
9407c478bd9Sstevel@tonic-gate 		    buf[VFS_LINE_MAX-2] != '\n') {
9417c478bd9Sstevel@tonic-gate 			logerr(gettext("%1$s line size too long, "
9427c478bd9Sstevel@tonic-gate 			    "exceeded %2$d: \"%3$s\"\n"),
9437c478bd9Sstevel@tonic-gate 			    VFSTAB, VFS_LINE_MAX - 2, buf);
9447c478bd9Sstevel@tonic-gate 			goto out;
9457c478bd9Sstevel@tonic-gate 		}
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 		/* LINTED - format specifier */
9487c478bd9Sstevel@tonic-gate 		if ((sscanf(buf, fmt, bdev, cdev, mntpt,
9497c478bd9Sstevel@tonic-gate 		    fstype, fsckpass, mntboot, mntopt) != 7) ||
9507c478bd9Sstevel@tonic-gate 		    (bdev[0] == '#') ||
9517c478bd9Sstevel@tonic-gate 		    (get_physname_minor(bdev, phys_bdev, sizeof (phys_bdev),
9527c478bd9Sstevel@tonic-gate 		    bdev_minor, sizeof (bdev_minor)) != 0) ||
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 		    (strcmp(fstype, "swap") != 0 &&
9557c478bd9Sstevel@tonic-gate 		    ((get_physname_minor(cdev, phys_cdev, sizeof (phys_cdev),
9567c478bd9Sstevel@tonic-gate 		    cdev_minor, sizeof (cdev_minor)) != 0) ||
9577c478bd9Sstevel@tonic-gate 		    (strcmp(phys_bdev, phys_cdev) != 0))) ||
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 		    canopen(bdev) ||
9607c478bd9Sstevel@tonic-gate 		    (map_physname(phys_bdev, new_physname,
9617c478bd9Sstevel@tonic-gate 		    sizeof (new_physname)) != 0) ||
9627c478bd9Sstevel@tonic-gate 		    (lookup_devlink(new_physname, bdev_minor, new_bdevlink,
9637c478bd9Sstevel@tonic-gate 		    sizeof (new_bdevlink)) != 0) ||
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 		    (strcmp(fstype, "swap") != 0 &&
9667c478bd9Sstevel@tonic-gate 		    (lookup_devlink(new_physname, cdev_minor, new_cdevlink,
9677c478bd9Sstevel@tonic-gate 		    sizeof (new_cdevlink)) != 0))) {
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 			/* cache the last two entries */
9707c478bd9Sstevel@tonic-gate 			(void) strlcpy(vfs_cache[idx], buf, VFS_LINE_MAX);
9717c478bd9Sstevel@tonic-gate 			idx = (idx == 0) ? 1 : 0;
9727c478bd9Sstevel@tonic-gate 			if (count < 2)
9737c478bd9Sstevel@tonic-gate 				count++;
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 			if (fputs(buf, fp_out) == EOF) {
9767c478bd9Sstevel@tonic-gate 				logerr(gettext("fputs \"%1$s\" to %2$s "
9777c478bd9Sstevel@tonic-gate 				    "failed: %3$s\n"),
9787c478bd9Sstevel@tonic-gate 				    buf, vfstab_out, strerror(errno));
9797c478bd9Sstevel@tonic-gate 				goto out;
9807c478bd9Sstevel@tonic-gate 			}
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 		} else {
9837c478bd9Sstevel@tonic-gate 			/*
9847c478bd9Sstevel@tonic-gate 			 * comment the entry in vfstab only if it is not
9857c478bd9Sstevel@tonic-gate 			 * already in the cache.
9867c478bd9Sstevel@tonic-gate 			 */
9877c478bd9Sstevel@tonic-gate 			if (client_name_type(phys_bdev) == CLIENT_TYPE_VHCI)
9887c478bd9Sstevel@tonic-gate 				(void) snprintf(tmpbuf, VFS_LINE_MAX,
9897c478bd9Sstevel@tonic-gate 				    "# mpxio: %s", buf);
9907c478bd9Sstevel@tonic-gate 			else
9917c478bd9Sstevel@tonic-gate 				(void) snprintf(tmpbuf, VFS_LINE_MAX,
9927c478bd9Sstevel@tonic-gate 				    "# non-mpxio: %s", buf);
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 			for (i = 0; i < count; i++) {
9957c478bd9Sstevel@tonic-gate 				if (strcmp(vfs_cache[i], tmpbuf) == 0)
9967c478bd9Sstevel@tonic-gate 					break;
9977c478bd9Sstevel@tonic-gate 			}
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 			if (i == count) {
10007c478bd9Sstevel@tonic-gate 				if (fputs(tmpbuf, fp_out) == EOF) {
10017c478bd9Sstevel@tonic-gate 					logerr(gettext("fputs \"%1$s\" to %2$s "
10027c478bd9Sstevel@tonic-gate 					    "failed: %3$s\n"), tmpbuf,
10037c478bd9Sstevel@tonic-gate 					    vfstab_out, strerror(errno));
10047c478bd9Sstevel@tonic-gate 					goto out;
10057c478bd9Sstevel@tonic-gate 				}
10067c478bd9Sstevel@tonic-gate 			}
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 			count = 0;
10097c478bd9Sstevel@tonic-gate 			idx = 0;
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 			if (fprintf(fp_out, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
10127c478bd9Sstevel@tonic-gate 			    new_bdevlink,
10137c478bd9Sstevel@tonic-gate 			    (strcmp(fstype, "swap") != 0) ? new_cdevlink : cdev,
10147c478bd9Sstevel@tonic-gate 			    mntpt, fstype, fsckpass, mntboot, mntopt) < 0) {
10157c478bd9Sstevel@tonic-gate 				logerr(gettext("fprintf failed to write to "
10167c478bd9Sstevel@tonic-gate 				    "%1$s: %2$s\n"),
10177c478bd9Sstevel@tonic-gate 				    vfstab_out, strerror(errno));
10187c478bd9Sstevel@tonic-gate 				goto out;
10197c478bd9Sstevel@tonic-gate 			}
10207c478bd9Sstevel@tonic-gate 			vfstab_updated = 1;
10217c478bd9Sstevel@tonic-gate 		}
10227c478bd9Sstevel@tonic-gate 	}
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	rv = vfstab_updated;
10257c478bd9Sstevel@tonic-gate out:
10267c478bd9Sstevel@tonic-gate 	(void) fclose(fp_in);
10277c478bd9Sstevel@tonic-gate 	(void) fclose(fp_out);
10287c478bd9Sstevel@tonic-gate 	free(buf);
10297c478bd9Sstevel@tonic-gate 	free(tmpbuf);
10307c478bd9Sstevel@tonic-gate 	free(vfs_cache[0]);
10317c478bd9Sstevel@tonic-gate 	free(vfs_cache[1]);
10327c478bd9Sstevel@tonic-gate 	return (rv);
10337c478bd9Sstevel@tonic-gate }
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate /*
10367c478bd9Sstevel@tonic-gate  * if guidmap is 0, list non-STMS to STMS device name mappings for the
10377c478bd9Sstevel@tonic-gate  * specified controller.
10387c478bd9Sstevel@tonic-gate  * if guidmap is 1, list non-STMS to GUID mappings for the specified controller.
10397c478bd9Sstevel@tonic-gate  * If controller is -1 list mappings for all controllers.
10407c478bd9Sstevel@tonic-gate  *
10417c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
10427c478bd9Sstevel@tonic-gate  */
10437c478bd9Sstevel@tonic-gate static int
10447c478bd9Sstevel@tonic-gate list_mappings(int controller, int guidmap)
10457c478bd9Sstevel@tonic-gate {
10467c478bd9Sstevel@tonic-gate 	int cnum, len, mapped;
10477c478bd9Sstevel@tonic-gate 	int header = 1;
10487c478bd9Sstevel@tonic-gate 	char *p1, *p2;
10497c478bd9Sstevel@tonic-gate 	DIR *dirp;
10507c478bd9Sstevel@tonic-gate 	struct dirent *direntry;
10517c478bd9Sstevel@tonic-gate 	char devname[MAXPATHLEN];
10527c478bd9Sstevel@tonic-gate 	char physname[MAXPATHLEN];
10537c478bd9Sstevel@tonic-gate 	char new_devname[MAXPATHLEN];
10547c478bd9Sstevel@tonic-gate 	char new_physname[MAXPATHLEN];
10557c478bd9Sstevel@tonic-gate 	char guid[MAXPATHLEN];
10567c478bd9Sstevel@tonic-gate 	char minor[MAXNAMELEN];
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 	if ((dirp = opendir("/dev/rdsk")) == NULL)
10597c478bd9Sstevel@tonic-gate 		return (-1);
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 	while ((direntry = readdir(dirp)) != NULL) {
10627c478bd9Sstevel@tonic-gate 		if (strcmp(direntry->d_name, ".") == 0 ||
10637c478bd9Sstevel@tonic-gate 		    strcmp(direntry->d_name, "..") == 0 ||
10647c478bd9Sstevel@tonic-gate 		    (len = strlen(direntry->d_name)) < 2 ||
10657c478bd9Sstevel@tonic-gate 		    strcmp(direntry->d_name + len - 2, "s0") != 0 ||
10667c478bd9Sstevel@tonic-gate 		    sscanf(direntry->d_name, "c%dt", &cnum) != 1 ||
10677c478bd9Sstevel@tonic-gate 		    (controller != -1 && controller != cnum))
10687c478bd9Sstevel@tonic-gate 			continue;
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 		(void) snprintf(devname, MAXPATHLEN, "/dev/rdsk/%s",
10717c478bd9Sstevel@tonic-gate 		    direntry->d_name);
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 		if (get_physname_minor(devname, physname, sizeof (physname),
10747c478bd9Sstevel@tonic-gate 		    minor, sizeof (minor)) != 0 ||
10757c478bd9Sstevel@tonic-gate 		    client_name_type(physname) != CLIENT_TYPE_PHCI)
10767c478bd9Sstevel@tonic-gate 			continue;
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate 		/*
10797c478bd9Sstevel@tonic-gate 		 * First try phci_to_vhci() mapping. It will work if the
10807c478bd9Sstevel@tonic-gate 		 * device is under MPxIO control. If the device is not under
10817c478bd9Sstevel@tonic-gate 		 * MPxIO, phci_to_vhci() will fail in which case try to lookup
10827c478bd9Sstevel@tonic-gate 		 * if an old mapping exists using guid lookup.
10837c478bd9Sstevel@tonic-gate 		 */
10847c478bd9Sstevel@tonic-gate 		mapped = 1;
10857c478bd9Sstevel@tonic-gate 		if (phci_to_vhci(physname, new_physname,
10867c478bd9Sstevel@tonic-gate 		    sizeof (new_physname)) != 0) {
10877c478bd9Sstevel@tonic-gate 			if (get_guid(physname, guid, sizeof (guid), 1,
10887c478bd9Sstevel@tonic-gate 			    DI_NODE_NIL) == 0)
10897c478bd9Sstevel@tonic-gate 				(void) snprintf(new_physname, MAXPATHLEN,
10907c478bd9Sstevel@tonic-gate 				    "/scsi_vhci/ssd@g%s", guid);
10917c478bd9Sstevel@tonic-gate 			else
10927c478bd9Sstevel@tonic-gate 				mapped = 0;
10937c478bd9Sstevel@tonic-gate 		}
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 		if (mapped == 0)
10967c478bd9Sstevel@tonic-gate 			continue;
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 		/* strip the slice number part */
10997c478bd9Sstevel@tonic-gate 		devname[strlen(devname) - 2] = '\0';
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 		if (guidmap == 0) {
11027c478bd9Sstevel@tonic-gate 			if (lookup_devlink(new_physname, minor,
11037c478bd9Sstevel@tonic-gate 			    new_devname, sizeof (new_devname)) != 0)
11047c478bd9Sstevel@tonic-gate 				continue;
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate 			/* strip the slice number part */
11077c478bd9Sstevel@tonic-gate 			new_devname[strlen(new_devname) - 2] = '\0';
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 			if (header) {
11107c478bd9Sstevel@tonic-gate 				(void) printf(
11117c478bd9Sstevel@tonic-gate 				    gettext("non-STMS device name\t\t\t"
11127c478bd9Sstevel@tonic-gate 				    "STMS device name\n"
11137c478bd9Sstevel@tonic-gate 				    "------------------------------------------"
11147c478bd9Sstevel@tonic-gate 				    "------------------------\n"));
11157c478bd9Sstevel@tonic-gate 				header = 0;
11167c478bd9Sstevel@tonic-gate 			}
11177c478bd9Sstevel@tonic-gate 			(void) printf("%s\t\t%s\n", devname, new_devname);
11187c478bd9Sstevel@tonic-gate 		} else {
11197c478bd9Sstevel@tonic-gate 			/* extract guid part */
11207c478bd9Sstevel@tonic-gate 			if ((p1 = strstr(new_physname, "ssd@g")) == NULL) {
11217c478bd9Sstevel@tonic-gate 				logdmsg("invalid vhci: %s\n", new_physname);
11227c478bd9Sstevel@tonic-gate 				continue;
11237c478bd9Sstevel@tonic-gate 			}
11247c478bd9Sstevel@tonic-gate 			p1 += sizeof ("ssd@g") - 1;
11257c478bd9Sstevel@tonic-gate 			if ((p2 = strrchr(p1, ':')) != NULL)
11267c478bd9Sstevel@tonic-gate 				*p2 = '\0';
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 			if (header) {
11297c478bd9Sstevel@tonic-gate 				(void) printf(
11307c478bd9Sstevel@tonic-gate 				    gettext("non-STMS device name\t\t\tGUID\n"
11317c478bd9Sstevel@tonic-gate 				    "------------------------------------------"
11327c478bd9Sstevel@tonic-gate 				    "------------------------\n"));
11337c478bd9Sstevel@tonic-gate 				header = 0;
11347c478bd9Sstevel@tonic-gate 			}
11357c478bd9Sstevel@tonic-gate 			(void) printf("%s\t\t%s\n", devname, p1);
11367c478bd9Sstevel@tonic-gate 		}
11377c478bd9Sstevel@tonic-gate 	}
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	(void) closedir(dirp);
11407c478bd9Sstevel@tonic-gate 	return (0);
11417c478bd9Sstevel@tonic-gate }
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate /*
11447c478bd9Sstevel@tonic-gate  * Check if the file can be opened.
11457c478bd9Sstevel@tonic-gate  *
11467c478bd9Sstevel@tonic-gate  * Return 1 if the file can be opened, 0 otherwise.
11477c478bd9Sstevel@tonic-gate  */
11487c478bd9Sstevel@tonic-gate static int
11497c478bd9Sstevel@tonic-gate canopen(char *filename)
11507c478bd9Sstevel@tonic-gate {
11517c478bd9Sstevel@tonic-gate 	int fd;
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	if ((fd = open(filename, O_RDONLY)) == -1)
11547c478bd9Sstevel@tonic-gate 		return (0);
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	(void) close(fd);
11577c478bd9Sstevel@tonic-gate 	return (1);
11587c478bd9Sstevel@tonic-gate }
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate static void
11617c478bd9Sstevel@tonic-gate logerr(char *msg, ...)
11627c478bd9Sstevel@tonic-gate {
11637c478bd9Sstevel@tonic-gate 	va_list ap;
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: ", stmsboot);
11667c478bd9Sstevel@tonic-gate 	va_start(ap, msg);
11677c478bd9Sstevel@tonic-gate 	/* LINTED - format specifier */
11687c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, msg, ap);
11697c478bd9Sstevel@tonic-gate 	va_end(ap);
11707c478bd9Sstevel@tonic-gate }
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate /* log debug message */
11737c478bd9Sstevel@tonic-gate static void
11747c478bd9Sstevel@tonic-gate logdmsg(char *msg, ...)
11757c478bd9Sstevel@tonic-gate {
11767c478bd9Sstevel@tonic-gate 	va_list ap;
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 	if (debug) {
11797c478bd9Sstevel@tonic-gate 		va_start(ap, msg);
11807c478bd9Sstevel@tonic-gate 		/* LINTED - format specifier */
11817c478bd9Sstevel@tonic-gate 		(void) vprintf(msg, ap);
11827c478bd9Sstevel@tonic-gate 		va_end(ap);
11837c478bd9Sstevel@tonic-gate 	}
11847c478bd9Sstevel@tonic-gate }
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate static void *
11877c478bd9Sstevel@tonic-gate s_malloc(const size_t size)
11887c478bd9Sstevel@tonic-gate {
11897c478bd9Sstevel@tonic-gate 	void *rp;
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	if ((rp = malloc(size)) == NULL) {
11927c478bd9Sstevel@tonic-gate 		logerr(gettext("malloc failed to allocate %d bytes\n"), size);
11937c478bd9Sstevel@tonic-gate 		clean_exit(1);
11947c478bd9Sstevel@tonic-gate 	}
11957c478bd9Sstevel@tonic-gate 	return (rp);
11967c478bd9Sstevel@tonic-gate }
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate static char *
11997c478bd9Sstevel@tonic-gate s_strdup(const char *ptr)
12007c478bd9Sstevel@tonic-gate {
12017c478bd9Sstevel@tonic-gate 	void *rp;
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 	if ((rp = strdup(ptr)) == NULL) {
12047c478bd9Sstevel@tonic-gate 		logerr(gettext("strdup failed to dup %s\n"), ptr);
12057c478bd9Sstevel@tonic-gate 		clean_exit(1);
12067c478bd9Sstevel@tonic-gate 	}
12077c478bd9Sstevel@tonic-gate 	return (rp);
12087c478bd9Sstevel@tonic-gate }
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate static void
12117c478bd9Sstevel@tonic-gate s_strlcpy(char *dst, const char *src, size_t dstsize)
12127c478bd9Sstevel@tonic-gate {
12137c478bd9Sstevel@tonic-gate 	int n;
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	if ((n = strlcpy(dst, src, dstsize)) >= dstsize) {
12167c478bd9Sstevel@tonic-gate 		logerr(gettext("strlcpy: destination buffer size is %1$d "
12177c478bd9Sstevel@tonic-gate 		    "bytes, need to at least %2$d bytes\n"), dstsize, n + 1);
12187c478bd9Sstevel@tonic-gate 		clean_exit(1);
12197c478bd9Sstevel@tonic-gate 	}
12207c478bd9Sstevel@tonic-gate }
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate static void
12237c478bd9Sstevel@tonic-gate clean_exit(int status)
12247c478bd9Sstevel@tonic-gate {
12257c478bd9Sstevel@tonic-gate 	if (devinfo_root != DI_NODE_NIL)
12267c478bd9Sstevel@tonic-gate 		di_fini(devinfo_root);
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 	if (devlink_hdl != NULL)
12297c478bd9Sstevel@tonic-gate 		(void) di_devlink_fini(&devlink_hdl);
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	if (vhci_fd != -1)
12327c478bd9Sstevel@tonic-gate 		(void) close(vhci_fd);
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	exit(status);
12357c478bd9Sstevel@tonic-gate }
1236