xref: /titanic_44/usr/src/cmd/stmsboot/stmsboot_util.c (revision 40e5e17b3361b3eea56a9723071c406894a20b78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <stropts.h>
38 #include <strings.h>
39 #include <dirent.h>
40 #include <sys/param.h>
41 #include <sys/scsi/adapters/scsi_vhci.h>
42 #include <libdevinfo.h>
43 #include <libgen.h>
44 #include <dlfcn.h>
45 #include <link.h>
46 #include <locale.h>
47 #include <libintl.h>
48 #include <sys/syscall.h>
49 #include <sys/vfstab.h>
50 #include <sys/mount.h>
51 #include <devid.h>
52 #include <sys/libdevid.h>
53 
54 #define	VHCI_CTL_NODE	"/devices/scsi_vhci:devctl"
55 #define	SLASH_DEVICES	"/devices/"
56 
57 #ifdef	sparc
58 #define	DISK_NODE_NAME	"ssd"
59 #define	DISK_DRV_NAME	"ssd"
60 #define	SLASH_DISK_AT	"/ssd@"
61 #define	DISK_AT_G	"ssd@g"
62 #else	/* sparc */
63 #define	DISK_NODE_NAME	"disk"
64 #define	DISK_DRV_NAME	"sd"
65 #define	SLASH_DISK_AT	"/disk@"
66 #define	DISK_AT_G	"disk@g"
67 #endif
68 
69 #define	SLASH_FP_AT	"/fp@"
70 #define	SLASH_SCSI_VHCI	"/scsi_vhci"
71 #define	DEV_DSK		"/dev/dsk/"
72 #define	DEV_RDSK	"/dev/rdsk/"
73 #define	SYS_FILENAME_LEN	256
74 
75 /*
76  * Save directory is the directory in which system files are saved.
77  * Save directory must be under the root filesystem, as this program is
78  * typically run before any other filesystems are mounted.
79  */
80 #define	SAVE_DIR	"/etc/mpxio"
81 
82 /* fcp driver publishes this property */
83 #define	NODE_WWN_PROP	"node-wwn"
84 
85 typedef enum {
86 	CLIENT_TYPE_UNKNOWN,
87 	CLIENT_TYPE_PHCI,
88 	CLIENT_TYPE_VHCI
89 } client_type_t;
90 
91 struct devlink_cbarg {
92 	char *devlink;
93 	size_t len;
94 };
95 
96 static di_node_t devinfo_root = DI_NODE_NIL;
97 static di_devlink_handle_t devlink_hdl = NULL;
98 static int vhci_fd = -1;
99 static int patch_vfstab, cap_m_option, debug;
100 static int list_option, list_guid_mappings, list_controllernum = -1;
101 static char *mapdev = "";
102 static char *map_vhciname = "";
103 static char *stmsboot = "stmsboot";
104 
105 static int make_temp(char *, char *, char *, size_t);
106 static void commit_change(char *, char *, char *, int);
107 static int map_devname(char *, char *, size_t, int);
108 static int update_vfstab(char *, char *);
109 static int list_mappings(int, int);
110 static int canopen(char *);
111 static void logerr(char *, ...);
112 static void logdmsg(char *, ...);
113 static void *s_malloc(const size_t);
114 static char *s_strdup(const char *);
115 static void s_strlcpy(char *, const char *, size_t);
116 static int map_openable_vhciname(char *, char *, size_t);
117 /*
118  * Using an exit function not marked __NORETURN causes a warning with gcc.
119  * To suppress the warning, use __NORETURN attribute.
120  */
121 static void clean_exit(int)__NORETURN;
122 
123 /*
124  * Print usage and exit.
125  */
126 static void
127 usage(char *argv0)
128 {
129 	char *progname;
130 
131 	progname = strrchr(argv0, '/');
132 	if (progname != NULL)
133 		progname++;
134 	else
135 		progname = argv0;
136 
137 	/*
138 	 * -u	update /etc/vfstab
139 	 * -m devname
140 	 *	if devname is phci based name and not open-able, map it to
141 	 *	vhci based /devices name.
142 	 *	if devname is vhci based name and not open-able, map it to
143 	 *	phci based /devices name.
144 	 * -M devname
145 	 *	same as -m except that /dev link is printed instead of
146 	 *	/devices name.
147 	 * -l controller
148 	 *	list non-STMS to STMS device name mappings for the specific
149 	 *	controller
150 	 * -L	list non-STMS to STMS device name mappings for all controllers
151 	 * -p devname
152 	 *	if devname is vhci based name and open-able, get the first
153 	 *	onlined phci based name without /devices prefix.
154 	 *	Used in stmsboot to update the phci based bootpath.
155 	 */
156 	(void) fprintf(stderr, gettext("usage: %s -u | -m devname | "
157 	    "-M devname | -l controller | -L | -p devname\n"), progname);
158 	exit(2);
159 }
160 
161 /*
162  * Parse command line arguments.
163  */
164 static void
165 parse_args(int argc, char *argv[])
166 {
167 	char opt;
168 	int n = 0;
169 
170 	if (argc == 1) {
171 		usage(argv[0]);
172 		/*NOTREACHED*/
173 	}
174 
175 	while ((opt = getopt(argc, argv, "udm:M:Ll:gp:")) != EOF) {
176 		switch (opt) {
177 		case 'u':
178 			patch_vfstab = 1;
179 			n++;
180 			break;
181 
182 		case 'd':
183 			debug = 1;
184 			break;
185 
186 		case 'm':
187 			mapdev = s_strdup(optarg);
188 			n++;
189 			break;
190 
191 		case 'M':
192 			mapdev = s_strdup(optarg);
193 			cap_m_option = 1;
194 			n++;
195 			break;
196 
197 		case 'L':
198 			list_option = 1;
199 			n++;
200 			break;
201 
202 		case 'l':
203 			list_option = 1;
204 			list_controllernum = (int)atol(optarg);
205 			if (list_controllernum < 0) {
206 				logerr(gettext("controller number %d is "
207 				    "invalid\n"), list_controllernum);
208 				clean_exit(1);
209 			}
210 			n++;
211 			break;
212 
213 		case 'g':
214 			/*
215 			 * private option to display non-STMS device name
216 			 * to GUID mappings.
217 			 */
218 			list_guid_mappings = 1;
219 			n++;
220 			break;
221 		case 'p':
222 			/*
223 			 * map openable vhci based name to phci base name
224 			 */
225 			map_vhciname = s_strdup(optarg);
226 			n++;
227 			break;
228 
229 		default:
230 			usage(argv[0]);
231 			/*NOTREACHED*/
232 		}
233 	}
234 
235 	if (n != 1)
236 		usage(argv[0]);
237 		/*NOTREACHED*/
238 }
239 
240 int
241 main(int argc, char *argv[])
242 {
243 	char save_vfstab[SYS_FILENAME_LEN], tmp_vfstab[SYS_FILENAME_LEN];
244 	int vfstab_updated;
245 
246 	(void) setlocale(LC_ALL, "");
247 	(void) textdomain(TEXT_DOMAIN);
248 
249 	if (getuid() != 0) {
250 		logerr(gettext("must be super-user to run this program\n"));
251 		clean_exit(1);
252 	}
253 
254 	parse_args(argc, argv);
255 	(void) umask(022);
256 
257 	/*
258 	 * NOTE: The mpxio boot-up script executes this program with the
259 	 * mapping (-m) option before the /usr is even mounted and when the
260 	 * root filesystem is still mounted read-only.
261 	 */
262 	if (*mapdev != '\0') {
263 		char newname[MAXPATHLEN];
264 
265 		if (map_devname(mapdev, newname, sizeof (newname),
266 		    cap_m_option) == 0) {
267 			(void) printf("%s\n", newname);
268 			clean_exit(0);
269 		}
270 		clean_exit(1);
271 	}
272 	if (*map_vhciname != '\0') {
273 		char newname[MAXPATHLEN];
274 
275 		if (map_openable_vhciname(map_vhciname, newname,
276 		    sizeof (newname)) == 0) {
277 			(void) printf("%s\n", newname);
278 			clean_exit(0);
279 		}
280 		clean_exit(1);
281 	}
282 
283 	if (list_option || list_guid_mappings) {
284 		if (list_mappings(list_controllernum, list_guid_mappings) == 0)
285 			clean_exit(0);
286 		clean_exit(1);
287 	}
288 
289 	/* create a directory where a copy of the system files are saved */
290 	if (patch_vfstab) {
291 		if (mkdirp(SAVE_DIR, 0755) != 0 && errno != EEXIST) {
292 			logerr(gettext("mkdirp: failed to create %1$s: %2$s\n"),
293 			    SAVE_DIR, strerror(errno));
294 			clean_exit(1);
295 		}
296 
297 		if (make_temp(VFSTAB, save_vfstab, tmp_vfstab,
298 		    SYS_FILENAME_LEN) != 0)
299 			clean_exit(1);
300 
301 		/* build new vfstab without modifying the existing one */
302 		if ((vfstab_updated = update_vfstab(VFSTAB, tmp_vfstab))
303 		    == -1) {
304 			logerr(gettext("failed to update %s\n"), VFSTAB);
305 			clean_exit(1);
306 		}
307 
308 		commit_change(VFSTAB, save_vfstab, tmp_vfstab, vfstab_updated);
309 	}
310 
311 	clean_exit(0);
312 }
313 
314 /*
315  * Make saved and temporary filenames in SAVE_DIR.
316  *
317  * ex: if the filename is /etc/vfstab then the save_filename and tmp_filename
318  * would be SAVE_DIR/vfstab and SAVE_DIR/vfstab.tmp respectively.
319  *
320  * Returns 0 on success, -1 on failure.
321  */
322 static int
323 make_temp(char *filename, char *save_filename, char *tmp_filename, size_t len)
324 {
325 	char *ptr;
326 
327 	if ((ptr = strrchr(filename, '/')) == NULL) {
328 		logdmsg("invalid file %s\n", filename);
329 		return (-1);
330 	}
331 	(void) snprintf(save_filename, len, "%s%s", SAVE_DIR, ptr);
332 	(void) snprintf(tmp_filename, len, "%s%s.tmp", SAVE_DIR, ptr);
333 	logdmsg("make_temp: %s: save = %s, temp = %s\n", filename,
334 	    save_filename, tmp_filename);
335 	return (0);
336 }
337 
338 /*
339  * Commit the changes made to the system file
340  */
341 static void
342 commit_change(char *filename, char *save_filename, char *tmp_filename,
343     int updated)
344 {
345 	int x;
346 
347 	if (updated) {
348 		/* save the original */
349 		if ((x = rename(filename, save_filename)) != 0) {
350 			logerr(gettext("rename %1$s to %2$s failed: %3$s\n"),
351 			    filename, save_filename, strerror(errno));
352 		}
353 
354 		/* now rename the new file to the actual file */
355 		if (rename(tmp_filename, filename) != 0) {
356 			logerr(gettext("rename %1$s to %2$s failed: %3$s\n"),
357 			    tmp_filename, filename, strerror(errno));
358 
359 			/* restore the original */
360 			if (x == 0 && rename(save_filename, filename) != 0) {
361 				logerr(
362 				    gettext("rename %1$s to %2$s failed: %3$s\n"
363 				    "%4$s is a copy of the original %5$s file"
364 				    "\n"),
365 				    save_filename, filename, strerror(errno),
366 				    save_filename, filename);
367 			}
368 		} else
369 			(void) printf(gettext("%1$s: %2$s has been updated.\n"),
370 			    stmsboot, filename);
371 	} else {
372 		/* remove the temp file */
373 		(void) unlink(tmp_filename);
374 		(void) printf(gettext("%1$s: %2$s was not modified as no "
375 		    "changes were needed.\n"), stmsboot, filename);
376 	}
377 }
378 
379 /*
380  * Get the GUID of the device.
381  *
382  * physpath	/devices name without the /devices prefix and minor name
383  *		component.
384  * guid		caller supplied buffer where the GUID will be placed on return
385  * guid_len	length of the caller supplied guid buffer.
386  * no_dealy_flag if set open the device with O_NDELAY
387  * node		di_node corresponding to physpath if already available,
388  *		otherwise pass DI_NODE_NIL.
389  *
390  * Returns 0 on success, -1 on failure.
391  */
392 static int
393 get_guid(char *physpath, char *guid, int guid_len, int no_delay_flag,
394 	di_node_t node)
395 {
396 	int		fd;
397 	ddi_devid_t	devid;
398 	int		rv	= -1;
399 	char		*i_guid	= NULL;
400 	char		physpath_raw[MAXPATHLEN];
401 	uchar_t		*wwnp;
402 	int		i, n, snapshot_taken = 0;
403 
404 	logdmsg("get_guid: physpath = %s\n", physpath);
405 
406 #ifdef sparc
407 	(void) snprintf(physpath_raw, MAXPATHLEN,
408 	    "/devices%s:a,raw", physpath);
409 #else
410 	(void) snprintf(physpath_raw, MAXPATHLEN,
411 	    "/devices%s:c,raw", physpath);
412 #endif
413 
414 	*guid = '\0';
415 
416 	if (no_delay_flag)
417 		no_delay_flag = O_NDELAY;
418 
419 	/*
420 	 * Open the raw device
421 	 * Without the O_DELAY flag, the open will fail on standby paths of
422 	 * T3 if its mp_support mode is "mpxio".
423 	 */
424 	if ((fd = open(physpath_raw, O_RDONLY | no_delay_flag)) == -1) {
425 		logdmsg("get_guid: failed to open %s: %s\n", physpath_raw,
426 		    strerror(errno));
427 		return (-1);
428 	}
429 
430 	if (devid_get(fd, &devid) == 0) {
431 		i_guid = devid_to_guid(devid);
432 		devid_free(devid);
433 
434 		if (i_guid != NULL) {
435 			s_strlcpy(guid, i_guid, guid_len);
436 			devid_free_guid(i_guid);
437 			rv = 0;
438 			goto out;
439 		} else
440 			logdmsg("get_guid: devid_to_guid() failed\n");
441 	} else
442 		logdmsg("get_guid: devid_get() failed: %s\n", strerror(errno));
443 
444 	/* fallback to node name as the guid as this is what fcp driver does */
445 	if (node == DI_NODE_NIL) {
446 		if ((node = di_init(physpath, DINFOCPYALL | DINFOFORCE))
447 		    == DI_NODE_NIL) {
448 			logdmsg("get_guid: di_init on %s failed: %s\n",
449 			    physpath, strerror(errno));
450 			goto out;
451 		}
452 		snapshot_taken = 1;
453 	}
454 
455 	if ((n = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, NODE_WWN_PROP,
456 	    &wwnp)) == -1) {
457 		logdmsg("get_guid: di_prop_lookup_bytes() failed to lookup "
458 		    "%s: %s\n", NODE_WWN_PROP, strerror(errno));
459 		goto out;
460 	}
461 
462 	if (guid_len >= ((n * 2) + 1)) {
463 		for (i = 0; i < n; i++) {
464 			(void) sprintf(guid + (i * 2), "%02x", (uint_t)(*wwnp));
465 			wwnp++;
466 		}
467 		rv = 0;
468 	} else
469 		logerr(gettext("insufficient buffer size: need %1$d "
470 		    "bytes, passed %2$d bytes\n"), (n * 2) + 1, guid_len);
471 
472 out:
473 	if (snapshot_taken)
474 		di_fini(node);
475 
476 	(void) close(fd);
477 	logdmsg("get_guid: GUID = %s\n", guid);
478 	return (rv);
479 }
480 
481 /*
482  * Given client_name return whether it is a phci or vhci based name.
483  * client_name is /devices name of a client without the /devices prefix.
484  *
485  * client_name			Return value
486  * on sparc:
487  * .../fp@xxx/ssd@yyy		CLIENT_TYPE_PHCI
488  * .../scsi_vhci/ssd@yyy	CLIENT_TYPE_VHCI
489  * other			CLIENT_TYPE_UNKNOWN
490  * on x86:
491  * .../fp@xxx/disk@yyy		CLIENT_TYPE_PHCI
492  * .../scsi_vhci/disk@yyy	CLIENT_TYPE_VHCI
493  * other			CLIENT_TYPE_UNKNOWN
494  */
495 static client_type_t
496 client_name_type(char *client_name)
497 {
498 	client_type_t client_type = CLIENT_TYPE_UNKNOWN;
499 	char *p1, *p2;
500 
501 	if (*client_name != '/')
502 		return (CLIENT_TYPE_UNKNOWN);
503 
504 	if ((p1 = strrchr(client_name, '/')) == NULL ||
505 	    strncmp(p1, SLASH_DISK_AT, sizeof (SLASH_DISK_AT) - 1) != 0)
506 		return (CLIENT_TYPE_UNKNOWN);
507 
508 	*p1 = '\0';
509 
510 	if ((p2 = strrchr(client_name, '/')) != NULL) {
511 		if (strncmp(p2, SLASH_FP_AT, sizeof (SLASH_FP_AT) - 1) == 0)
512 			client_type = CLIENT_TYPE_PHCI;
513 		else if (strncmp(p2, SLASH_SCSI_VHCI,
514 		    sizeof (SLASH_SCSI_VHCI) - 1) == 0)
515 			client_type = CLIENT_TYPE_VHCI;
516 	}
517 
518 	*p1 = '/';
519 	return (client_type);
520 }
521 
522 /*
523  * Map phci based client name to vhci based client name.
524  *
525  * phci_name
526  *	phci based client /devices name without the /devices prefix and
527  *	minor name component.
528  *	ex:
529  *	for sparc: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
530  *	for x86: /pci@8,600000/SUNW,qlc@4/fp@0,0/disk@w2100002037cd9f72,0
531  *
532  * vhci_name
533  *	Caller supplied buffer where vhci /devices name will be placed on
534  *	return (without the /devices prefix and minor name component).
535  *	ex:
536  *	for sparc: /scsi_vhci/ssd@g2000002037cd9f72
537  *	for x86: /scsi_vhci/disk@g2000002037cd9f72
538  *
539  * vhci_name_len
540  *	Length of the caller supplied vhci_name buffer.
541  *
542  * Returns 0 on success, -1 on failure.
543  */
544 static int
545 phci_to_vhci(char *phci_name, char *vhci_name, size_t vhci_name_len)
546 {
547 	sv_iocdata_t ioc;
548 	char *slash;
549 	char vhci_name_buf[MAXPATHLEN];
550 	char phci_name_buf[MAXPATHLEN];
551 	char addr_buf[MAXNAMELEN];
552 
553 	logdmsg("phci_to_vhci: client = %s\n", phci_name);
554 
555 	s_strlcpy(phci_name_buf, phci_name, MAXPATHLEN);
556 
557 	if (client_name_type(phci_name_buf) != CLIENT_TYPE_PHCI ||
558 	    (slash = strrchr(phci_name_buf, '/')) == NULL ||
559 	    strncmp(slash, SLASH_DISK_AT, sizeof (SLASH_DISK_AT) - 1) != 0) {
560 		logdmsg("phci_to_vhci: %s is not of CLIENT_TYPE_PHCI\n",
561 		    phci_name);
562 		return (-1);
563 	}
564 
565 	if (vhci_fd < 0) {
566 		if ((vhci_fd = open(VHCI_CTL_NODE, O_RDWR)) < 0)
567 			return (-1);
568 	}
569 
570 	*slash = '\0';
571 	s_strlcpy(addr_buf, slash + sizeof (SLASH_DISK_AT) - 1, MAXNAMELEN);
572 
573 	bzero(&ioc, sizeof (sv_iocdata_t));
574 	ioc.client = vhci_name_buf;
575 	ioc.phci = phci_name_buf;
576 	ioc.addr = addr_buf;
577 
578 	if (ioctl(vhci_fd, SCSI_VHCI_GET_CLIENT_NAME, &ioc) != 0) {
579 		logdmsg("SCSI_VHCI_GET_CLIENT_NAME on %s "
580 		    "failed: %s\n", phci_name, strerror(errno));
581 		return (-1);
582 	}
583 
584 	s_strlcpy(vhci_name, vhci_name_buf, vhci_name_len);
585 	logdmsg("phci_to_vhci: %s maps to %s\n", phci_name, vhci_name);
586 	return (0);
587 }
588 
589 /*
590  * Map vhci based client name to phci based client name.
591  * If the client has multiple paths, only one of the paths with which client
592  * can be accessed is returned. This function does not use SCSI_VHCI ioctls
593  * as it is called on mpxio disabled paths.
594  *
595  * vhci_name
596  *	vhci based client /devices name without the /devices prefix and
597  *	minor name component.
598  *	ex:
599  *	sparc: /scsi_vhci/ssd@g2000002037cd9f72
600  *	x86: /scsi_vhci/disk@g2000002037cd9f72
601  *
602  * phci_name
603  *	Caller supplied buffer where phci /devices name will be placed on
604  *	return (without the /devices prefix and minor name component).
605  *	ex:
606  *	sparc: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
607  *	x86: /pci@8,600000/SUNW,qlc@4/fp@0,0/disk@w2100002037cd9f72,0
608  *
609  * phci_name_len
610  *	Length of the caller supplied phci_name buffer.
611  *
612  * Returns 0 on success, -1 on failure.
613  */
614 static int
615 vhci_to_phci(char *vhci_name, char *phci_name, size_t phci_name_len)
616 {
617 	di_node_t node, parent;
618 	char *vhci_guid, *devfspath;
619 	char phci_guid[MAXPATHLEN];
620 	char *parent_name, *node_name;
621 
622 	logdmsg("vhci_to_phci: client = %s\n", vhci_name);
623 
624 	if (client_name_type(vhci_name) != CLIENT_TYPE_VHCI) {
625 		logdmsg("vhci_to_phci: %s is not of CLIENT_TYPE_VHCI\n",
626 		    vhci_name);
627 		return (-1);
628 	}
629 
630 	if ((vhci_guid = strrchr(vhci_name, '@')) == NULL ||
631 	    *(++vhci_guid) != 'g') {
632 		logerr(gettext("couldn't get guid from %s\n"), vhci_name);
633 		return (-1);
634 	}
635 
636 	/* point to guid */
637 	++vhci_guid;
638 
639 	/*
640 	 * Get devinfo snapshot and walk all ssd nodes whose parent is fp.
641 	 * For each node get the guid and match it with vhci_guid.
642 	 */
643 	if (devinfo_root == DI_NODE_NIL) {
644 		logdmsg("vhci_to_phci: taking devinfo snapshot\n");
645 		if ((devinfo_root = di_init("/", DINFOCPYALL | DINFOFORCE))
646 		    == DI_NODE_NIL) {
647 			logerr(gettext("di_init failed: %s\n"),
648 			    strerror(errno));
649 			return (-1);
650 		}
651 		logdmsg("vhci_to_phci: done taking devinfo snapshot\n");
652 	}
653 
654 	for (node = di_drv_first_node(DISK_DRV_NAME, devinfo_root);
655 	    node != DI_NODE_NIL; node = di_drv_next_node(node)) {
656 		if ((node_name = di_node_name(node)) == NULL ||
657 		    strcmp(node_name, DISK_NODE_NAME) != 0 ||
658 		    (parent = di_parent_node(node)) == DI_NODE_NIL ||
659 		    (parent_name = di_node_name(parent)) == NULL ||
660 		    strcmp(parent_name, "fp") != 0 ||
661 		    (devfspath = di_devfs_path(node)) == NULL)
662 			continue;
663 
664 		/*
665 		 * Don't set no_delay_flag to have get_guid() fail on
666 		 * standby paths of T3. So we'll find the preferred paths.
667 		 */
668 		if (get_guid(devfspath, phci_guid,
669 		    sizeof (phci_guid), 0, node) == 0 &&
670 		    strcmp(phci_guid, vhci_guid) == 0) {
671 			s_strlcpy(phci_name, devfspath, phci_name_len);
672 			di_devfs_path_free(devfspath);
673 			logdmsg("vhci_to_phci: %s maps to %s\n", vhci_name,
674 			    phci_name);
675 			return (0);
676 		}
677 
678 		di_devfs_path_free(devfspath);
679 	}
680 
681 	logdmsg("vhci_to_phci: couldn't get phci name for %s\n", vhci_name);
682 	return (-1);
683 }
684 
685 /*
686  * Map vhci based client name to phci based client name.
687  * If the client has multiple paths, only one of the paths with which client
688  * can be accessed is returned.
689  * This function uses SCSI_VHCI ioctls to get the phci paths
690  *
691  * vhci_name
692  *	vhci based client /devices name without the /devices prefix and
693  *	minor name component.
694  *	ex:
695  *	sparc: /scsi_vhci/ssd@g2000002037cd9f72
696  *	x86: /scsi_vhci/disk@g2000002037cd9f72
697  *
698  * phci_name
699  *	Caller supplied buffer where phci /devices name will be placed on
700  *	return (without the /devices prefix and minor name component).
701  *	ex:
702  *	sparc: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
703  *	x86: /pci@8,600000/SUNW,qlc@4/fp@0,0/disk@w2100002037cd9f72,0
704  *
705  * phci_name_len
706  *	Length of the caller supplied phci_name buffer.
707  *
708  * Returns 0 on success, -1 on failure.
709  */
710 
711 static int
712 vhci_to_phci_by_ioctl(char *vhci_name, char *phci_name, size_t phci_name_len)
713 {
714 	sv_iocdata_t	ioc;
715 	uint_t npaths;
716 	char *node_name, *at;
717 	char vhci_name_buf[MAXPATHLEN];
718 	int  ret;
719 	sv_path_info_t *pi;
720 
721 	logdmsg("vhci_to_phci_by_ioctl: client = %s\n", vhci_name);
722 
723 	if (vhci_fd < 0) {
724 		if ((vhci_fd = open(VHCI_CTL_NODE, O_RDWR)) < 0)
725 			return (-1);
726 	}
727 
728 	(void) strlcpy(vhci_name_buf, vhci_name, MAXPATHLEN);
729 
730 	/* first get the number paths */
731 	bzero(&ioc, sizeof (sv_iocdata_t));
732 	ioc.client = vhci_name_buf;
733 	ioc.ret_elem = &npaths;
734 	if ((ret = ioctl(vhci_fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO,
735 	    &ioc)) != 0 || npaths == 0) {
736 		logdmsg("SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO on %s "
737 		    "failed: %s\n", vhci_name,
738 		    ret?strerror(errno):"got 0 paths");
739 		return (-1);
740 	}
741 
742 	/* now allocate memory for the path information and get all paths */
743 	bzero(&ioc, sizeof (sv_iocdata_t));
744 	ioc.client = vhci_name_buf;
745 	ioc.buf_elem = npaths;
746 	ioc.ret_elem = &npaths;
747 	if ((ioc.ret_buf = (sv_path_info_t *)calloc(npaths,
748 	    sizeof (sv_path_info_t))) == NULL)
749 		return (-1);
750 	if ((ret = ioctl(vhci_fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO,
751 	    &ioc)) != 0 || npaths == 0) {
752 		logdmsg("SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO on %s "
753 		    "failed: %s\n", vhci_name,
754 		    ret?strerror(errno):"got 0 paths");
755 		goto out;
756 	}
757 
758 	if (ioc.buf_elem < npaths)
759 		npaths = ioc.buf_elem;
760 	if ((node_name = strrchr(vhci_name_buf, '/')) == NULL ||
761 	    (at = strchr(node_name, '@')) == NULL)
762 		goto out;
763 
764 	node_name++;
765 	*at = '\0';
766 
767 	/*
768 	 * return the first online paths as non-online paths may
769 	 * not be accessible in the target environment.
770 	 */
771 	pi = (sv_path_info_t *)ioc.ret_buf;
772 	while (npaths--) {
773 		if (MDI_PATHINFO_STATE_ONLINE == pi->ret_state) {
774 			(void) snprintf(phci_name, phci_name_len, "%s/%s@%s",
775 			    pi->device.ret_phci, node_name,
776 			    pi->ret_addr);
777 			logdmsg("vhci_to_phci_by_ioctl: %s maps to %s\n",
778 			    vhci_name, phci_name);
779 			free(ioc.ret_buf);
780 			return (0);
781 		}
782 		pi++;
783 	}
784 
785 out:
786 	logdmsg("vhci_to_phci_by_ioctl: couldn't get phci name for %s\n",
787 	    vhci_name);
788 	free(ioc.ret_buf);
789 	return (-1);
790 
791 }
792 
793 /*
794  * Map physname from phci name space to vhci name space or vice-versa
795  *
796  * physname
797  *	phci or vhci based client /devices name without the /devices prefix and
798  *	minor name component.
799  *
800  * new_physname
801  *	Caller supplied buffer where the mapped physical name is stored on
802  *	return (without the /devices prefix and minor name component).
803  *
804  * len
805  *	Length of the caller supplied new_physname buffer.
806  *
807  * Returns 0 on success, -1 on failure.
808  */
809 static int
810 map_physname(char *physname, char *new_physname, size_t len)
811 {
812 	int type;
813 	int rv;
814 
815 	if ((type = client_name_type(physname)) == CLIENT_TYPE_VHCI)
816 		rv = vhci_to_phci(physname, new_physname, len);
817 	else if (type == CLIENT_TYPE_PHCI)
818 		rv = phci_to_vhci(physname, new_physname, len);
819 	else
820 		rv = -1;
821 
822 	return (rv);
823 }
824 
825 /*
826  * Given a phci or vhci devname which is either a /dev link or /devices name
827  * get the corresponding physical node path (without the /devices prefix)
828  * and minor name.
829  *
830  * Returns 0 on success, -1 on failure.
831  */
832 static int
833 get_physname_minor(char *devname, char *physname, int physname_len,
834     char *minorname, int minorname_len)
835 {
836 	int linksize;
837 	char buf[MAXPATHLEN];
838 	char *p, *m;
839 
840 	if (strncmp(devname, DEV_DSK, sizeof (DEV_DSK) - 1) == 0 ||
841 	    strncmp(devname, DEV_RDSK, sizeof (DEV_RDSK) - 1) == 0) {
842 		if ((linksize = readlink(devname, buf, MAXPATHLEN))
843 		    > 0 && linksize <= (MAXPATHLEN - 1)) {
844 			buf[linksize] = '\0';
845 		} else
846 			return (-1);
847 	} else
848 		s_strlcpy(buf, devname, MAXPATHLEN);
849 
850 	if ((p = strstr(buf, SLASH_DEVICES)) == NULL)
851 		return (-1);
852 
853 	/* point to '/' after /devices */
854 	p += sizeof (SLASH_DEVICES) - 2;
855 
856 	if ((m = strrchr(p, ':')) == NULL) {
857 		logdmsg("get_physname_minor: no minor name component in %s\n",
858 		    buf);
859 		return (-1);
860 	}
861 
862 	*m = '\0';
863 	m++;
864 
865 	if (client_name_type(p) == CLIENT_TYPE_UNKNOWN)
866 		return (-1);
867 
868 	s_strlcpy(physname, p, physname_len);
869 	s_strlcpy(minorname, m, minorname_len);
870 	logdmsg("get_physname_minor: %s: physname = %s, minor = %s\n",
871 	    devname, physname, minorname);
872 	return (0);
873 }
874 
875 static int
876 devlink_callback(di_devlink_t devlink, void *argptr)
877 {
878 	const char *link;
879 	struct devlink_cbarg *argp = argptr;
880 
881 	if ((link = di_devlink_path(devlink)) != NULL) {
882 		s_strlcpy(argp->devlink, link, argp->len);
883 		return (DI_WALK_TERMINATE);
884 	}
885 
886 	return (DI_WALK_CONTINUE);
887 }
888 
889 /*
890  * Lookup the /dev link corresponding to physname and minorname.
891  *
892  * physname	client /devices path without the /devices prefix and minor
893  *		name component.
894  * minorname	client minor name.
895  * devlink	caller supplied buffer where the /dev link is placed on return.
896  * len		caller supplied devlink buffer length
897  *
898  * Returns 0 on success, -1 on failure.
899  */
900 static int
901 lookup_devlink(char *physname, char *minorname, char *devlink, size_t len)
902 {
903 	char buf[MAXPATHLEN];
904 	struct devlink_cbarg arg;
905 
906 	if (devlink_hdl == NULL) {
907 		logdmsg("lookup_devlink: taking devlink snapshot\n");
908 		if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
909 			logerr(gettext("di_devlink_init failed: %s\n"),
910 			    strerror(errno));
911 			clean_exit(1);
912 		}
913 	}
914 
915 	*devlink = '\0';
916 	(void) snprintf(buf, MAXPATHLEN, "%s:%s", physname, minorname);
917 	arg.devlink = devlink;
918 	arg.len = len;
919 	if (di_devlink_walk(devlink_hdl, NULL, buf, DI_PRIMARY_LINK, &arg,
920 	    devlink_callback) != 0) {
921 		logdmsg("lookup_devlink: di_devlink_walk on %s failed: %s\n",
922 		    buf, strerror(errno));
923 		return (-1);
924 	}
925 
926 	if (*devlink == '\0') {
927 		logdmsg("lookup_devlink: failed to lookup devlink for %s\n",
928 		    buf);
929 		return (-1);
930 	}
931 
932 	logdmsg("lookup_devlink: /dev link for %s:%s = %s\n", physname,
933 	    minorname, devlink);
934 	return (0);
935 }
936 
937 /*
938  * open infile for reading and return its file pointer in *fp_in.
939  * open outfile for writing and return its file pointer in *fp_out.
940  *
941  * Returns 0 on success, -1 on failure.
942  */
943 static int
944 open_in_out_files(char *infile, char *outfile, FILE **fp_in, FILE **fp_out)
945 {
946 	FILE *fin = NULL;
947 	FILE *fout = NULL;
948 	struct stat sbuf;
949 
950 	if ((fin = fopen(infile, "r")) == NULL) {
951 		logerr(gettext("failed to fopen %1$s: %2$s\n"),
952 		    infile, strerror(errno));
953 		goto out;
954 	}
955 
956 	if (fstat(fileno(fin), &sbuf) != 0) {
957 		logerr(gettext("fstat failed on %1$s: %2$s\n"),
958 		    infile, strerror(errno));
959 		goto out;
960 	}
961 
962 	if ((fout = fopen(outfile, "w")) == NULL) {
963 		logerr(gettext("failed to fopen %1$s: %2$s\n"),
964 		    outfile, strerror(errno));
965 		goto out;
966 	}
967 
968 	if (fchmod(fileno(fout), (sbuf.st_mode & 0777)) != 0) {
969 		logerr(gettext("failed to fchmod %1$s to 0%2$o: %3$s\n"),
970 		    outfile, sbuf.st_mode & 0777, strerror(errno));
971 		goto out;
972 	}
973 
974 	if (fchown(fileno(fout), sbuf.st_uid, sbuf.st_gid) != 0) {
975 		logerr(gettext("failed to fchown %1$s to uid %2$d and "
976 		    "gid %3$d: %4$s\n"),
977 		    outfile, sbuf.st_uid, sbuf.st_gid, strerror(errno));
978 		goto out;
979 	}
980 
981 	*fp_in = fin;
982 	*fp_out = fout;
983 	return (0);
984 
985 out:
986 	if (fin != NULL)
987 		(void) fclose(fin);
988 	if (fout != NULL)
989 		(void) fclose(fout);
990 	return (-1);
991 }
992 
993 /*
994  * If the devname is a phci based name and not open-able, map it to vhci
995  * based name. If the devname is a vhci based name and not open-able, map it
996  * to phci based name.
997  *
998  * devname	either a /dev link or /devices name to client device
999  * new_devname	caller supplied buffer where the mapped device name is
1000  *		placed on return.
1001  * len		caller supplied new_devname buffer length
1002  * devlink_flag	pass 1 if requesting the /dev link to the mapped device.
1003  *		pass 0 if requesting the /devices name of the mapped device.
1004  *
1005  * Returns 0 on success, -1 on failure.
1006  */
1007 static int
1008 map_devname(char *devname, char *new_devname, size_t len, int devlink_flag)
1009 {
1010 	char physname[MAXPATHLEN];
1011 	char minor[MAXNAMELEN];
1012 	char new_physname[MAXPATHLEN];
1013 
1014 	if (get_physname_minor(devname, physname, sizeof (physname),
1015 	    minor, sizeof (minor)) == 0 &&
1016 	    canopen(devname) == 0 &&
1017 	    map_physname(physname, new_physname, sizeof (new_physname)) == 0) {
1018 
1019 		if (devlink_flag) {
1020 			if (lookup_devlink(new_physname, minor, new_devname,
1021 			    len) == 0)
1022 				return (0);
1023 		} else {
1024 			(void) snprintf(new_devname, len, "/devices%s:%s",
1025 			    new_physname, minor);
1026 			return (0);
1027 		}
1028 	}
1029 
1030 	return (-1);
1031 }
1032 
1033 /*
1034  * If the devname is a vhci based name and open-able, map it to phci
1035  * based name.
1036  *
1037  * devname	either a /dev link or /devices name to client device
1038  * new_devname	caller supplied buffer where the mapped device name without
1039  *		/devices prefix is placed on return.
1040  * len		caller supplied new_devname buffer length
1041  */
1042 static int
1043 map_openable_vhciname(char *devname, char *new_devname, size_t len)
1044 {
1045 	char physname[MAXPATHLEN];
1046 	char minor[MAXNAMELEN];
1047 	char new_physname[MAXPATHLEN];
1048 
1049 	if (get_physname_minor(devname, physname, sizeof (physname),
1050 	    minor, sizeof (minor)) == 0 &&
1051 	    canopen(devname) == 1 &&
1052 	    client_name_type(physname) == CLIENT_TYPE_VHCI &&
1053 	    vhci_to_phci_by_ioctl(physname, new_physname,
1054 		sizeof (new_physname)) == 0) {
1055 		(void) snprintf(new_devname, len, "%s:%s",
1056 		    new_physname, minor);
1057 		return (0);
1058 	}
1059 
1060 	return (-1);
1061 }
1062 /*
1063  * Make a new /etc/vfstab:
1064  * Read vfstab_in, convert the device name entries to appropriate vhci or phci
1065  * based names, and write to vfstab_out. Only device names whose physical
1066  * paths are either phci or vhci based names and not open-able are considered
1067  * for conversion. Open-able device name entries are not converted as it
1068  * means that the device is already accessible; hence no need to convert.
1069  *
1070  * Returns:
1071  * 	0	successful but vfstab_out contents are the same as vfstab_in
1072  *	1	successful and vfstab_out changed from vfstab_in
1073  *	-1	failed
1074  */
1075 static int
1076 update_vfstab(char *vfstab_in, char *vfstab_out)
1077 {
1078 	FILE *fp_in, *fp_out;
1079 	char *buf, *tmpbuf;
1080 	char *vfs_cache[2];
1081 	int idx = 0, count = 0;
1082 	int rv = -1;
1083 	int vfstab_updated = 0;
1084 	int i;
1085 	char cdev[MAXPATHLEN];
1086 	char bdev[MAXPATHLEN];
1087 	char mntpt[MAXPATHLEN];
1088 	char fstype[512];
1089 	char fsckpass[512];
1090 	char mntboot[512];
1091 	char mntopt[MAX_MNTOPT_STR];
1092 	char phys_bdev[MAXPATHLEN], phys_cdev[MAXPATHLEN];
1093 	char bdev_minor[MAXNAMELEN], cdev_minor[MAXNAMELEN];
1094 	char new_physname[MAXPATHLEN];
1095 	char new_bdevlink[MAXPATHLEN], new_cdevlink[MAXPATHLEN];
1096 	char fmt[80];
1097 
1098 	if (open_in_out_files(vfstab_in, vfstab_out, &fp_in, &fp_out) != 0)
1099 		return (-1);
1100 
1101 	/*
1102 	 * Read one line at time from vfstab_in. If no conversion is needed
1103 	 * for the line simply write the line to vfstab_out. If conversion is
1104 	 * needed, first write the existing line as a comment to vfstab_out
1105 	 * and then write the converted line.
1106 	 *
1107 	 * To avoid commented entries piling up in vfstab in case if the
1108 	 * user runs stmsboot multiple times to switch on and off from mpxio,
1109 	 * add the commented line only if not already there. To do this
1110 	 * cache the last two vfstab lines processed and add the commented
1111 	 * entry only if it is not found in the cache. We only need to cache
1112 	 * the last two lines because a device can have at most two names -
1113 	 * one mpxio and one non-mpxio name. Therefore for any device name
1114 	 * entry we at most add two comments - one with mpxio name and one
1115 	 * with non-mpxio name - no matter how many times stmsboot is run.
1116 	 */
1117 	buf = (char *)s_malloc(VFS_LINE_MAX);
1118 	tmpbuf = (char *)s_malloc(VFS_LINE_MAX);
1119 	vfs_cache[0] = (char *)s_malloc(VFS_LINE_MAX);
1120 	vfs_cache[1] = (char *)s_malloc(VFS_LINE_MAX);
1121 
1122 	(void) snprintf(fmt, sizeof (fmt),
1123 	    "%%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds", sizeof (bdev) - 1,
1124 	    sizeof (cdev) - 1, sizeof (mntpt) - 1, sizeof (fstype) - 1,
1125 	    sizeof (fsckpass) - 1, sizeof (mntboot) - 1, sizeof (mntopt) - 1);
1126 
1127 	while (fgets(buf, VFS_LINE_MAX, fp_in) != NULL) {
1128 		if (strlen(buf) == (VFS_LINE_MAX - 1) &&
1129 		    buf[VFS_LINE_MAX-2] != '\n') {
1130 			logerr(gettext("%1$s line size too long, "
1131 			    "exceeded %2$d: \"%3$s\"\n"),
1132 			    VFSTAB, VFS_LINE_MAX - 2, buf);
1133 			goto out;
1134 		}
1135 
1136 		/* LINTED - format specifier */
1137 		if ((sscanf(buf, fmt, bdev, cdev, mntpt,
1138 		    fstype, fsckpass, mntboot, mntopt) != 7) ||
1139 		    (bdev[0] == '#') ||
1140 		    (get_physname_minor(bdev, phys_bdev, sizeof (phys_bdev),
1141 		    bdev_minor, sizeof (bdev_minor)) != 0) ||
1142 
1143 		    (strcmp(fstype, "swap") != 0 &&
1144 		    ((get_physname_minor(cdev, phys_cdev, sizeof (phys_cdev),
1145 		    cdev_minor, sizeof (cdev_minor)) != 0) ||
1146 		    (strcmp(phys_bdev, phys_cdev) != 0))) ||
1147 
1148 		    canopen(bdev) ||
1149 		    (map_physname(phys_bdev, new_physname,
1150 		    sizeof (new_physname)) != 0) ||
1151 		    (lookup_devlink(new_physname, bdev_minor, new_bdevlink,
1152 		    sizeof (new_bdevlink)) != 0) ||
1153 
1154 		    (strcmp(fstype, "swap") != 0 &&
1155 		    (lookup_devlink(new_physname, cdev_minor, new_cdevlink,
1156 		    sizeof (new_cdevlink)) != 0))) {
1157 
1158 			/* cache the last two entries */
1159 			(void) strlcpy(vfs_cache[idx], buf, VFS_LINE_MAX);
1160 			idx = (idx == 0) ? 1 : 0;
1161 			if (count < 2)
1162 				count++;
1163 
1164 			if (fputs(buf, fp_out) == EOF) {
1165 				logerr(gettext("fputs \"%1$s\" to %2$s "
1166 				    "failed: %3$s\n"),
1167 				    buf, vfstab_out, strerror(errno));
1168 				goto out;
1169 			}
1170 
1171 		} else {
1172 			/*
1173 			 * comment the entry in vfstab only if it is not
1174 			 * already in the cache.
1175 			 */
1176 			if (client_name_type(phys_bdev) == CLIENT_TYPE_VHCI)
1177 				(void) snprintf(tmpbuf, VFS_LINE_MAX,
1178 				    "# mpxio: %s", buf);
1179 			else
1180 				(void) snprintf(tmpbuf, VFS_LINE_MAX,
1181 				    "# non-mpxio: %s", buf);
1182 
1183 			for (i = 0; i < count; i++) {
1184 				if (strcmp(vfs_cache[i], tmpbuf) == 0)
1185 					break;
1186 			}
1187 
1188 			if (i == count) {
1189 				if (fputs(tmpbuf, fp_out) == EOF) {
1190 					logerr(gettext("fputs \"%1$s\" to %2$s "
1191 					    "failed: %3$s\n"), tmpbuf,
1192 					    vfstab_out, strerror(errno));
1193 					goto out;
1194 				}
1195 			}
1196 
1197 			count = 0;
1198 			idx = 0;
1199 
1200 			if (fprintf(fp_out, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
1201 			    new_bdevlink,
1202 			    (strcmp(fstype, "swap") != 0) ? new_cdevlink : cdev,
1203 			    mntpt, fstype, fsckpass, mntboot, mntopt) < 0) {
1204 				logerr(gettext("fprintf failed to write to "
1205 				    "%1$s: %2$s\n"),
1206 				    vfstab_out, strerror(errno));
1207 				goto out;
1208 			}
1209 			vfstab_updated = 1;
1210 		}
1211 	}
1212 
1213 	rv = vfstab_updated;
1214 out:
1215 	(void) fclose(fp_in);
1216 	(void) fclose(fp_out);
1217 	free(buf);
1218 	free(tmpbuf);
1219 	free(vfs_cache[0]);
1220 	free(vfs_cache[1]);
1221 	return (rv);
1222 }
1223 
1224 /*
1225  * if guidmap is 0, list non-STMS to STMS device name mappings for the
1226  * specified controller.
1227  * if guidmap is 1, list non-STMS to GUID mappings for the specified controller.
1228  * If controller is -1 list mappings for all controllers.
1229  *
1230  * Returns 0 on success, -1 on failure.
1231  */
1232 static int
1233 list_mappings(int controller, int guidmap)
1234 {
1235 	int cnum, len, mapped;
1236 	int header = 1;
1237 	char *p1, *p2;
1238 	DIR *dirp;
1239 	struct dirent *direntry;
1240 	char devname[MAXPATHLEN];
1241 	char physname[MAXPATHLEN];
1242 	char new_devname[MAXPATHLEN];
1243 	char new_physname[MAXPATHLEN];
1244 	char guid[MAXPATHLEN];
1245 	char minor[MAXNAMELEN];
1246 
1247 	if ((dirp = opendir("/dev/rdsk")) == NULL)
1248 		return (-1);
1249 
1250 	while ((direntry = readdir(dirp)) != NULL) {
1251 		if (strcmp(direntry->d_name, ".") == 0 ||
1252 		    strcmp(direntry->d_name, "..") == 0 ||
1253 		    (len = strlen(direntry->d_name)) < 2 ||
1254 		    strcmp(direntry->d_name + len - 2, "s0") != 0 ||
1255 		    sscanf(direntry->d_name, "c%dt", &cnum) != 1 ||
1256 		    (controller != -1 && controller != cnum))
1257 			continue;
1258 
1259 		(void) snprintf(devname, MAXPATHLEN, "/dev/rdsk/%s",
1260 		    direntry->d_name);
1261 
1262 		if (get_physname_minor(devname, physname, sizeof (physname),
1263 		    minor, sizeof (minor)) != 0 ||
1264 		    client_name_type(physname) != CLIENT_TYPE_PHCI)
1265 			continue;
1266 
1267 		/*
1268 		 * First try phci_to_vhci() mapping. It will work if the
1269 		 * device is under MPxIO control. If the device is not under
1270 		 * MPxIO, phci_to_vhci() will fail in which case try to lookup
1271 		 * if an old mapping exists using guid lookup.
1272 		 */
1273 		mapped = 1;
1274 		if (phci_to_vhci(physname, new_physname,
1275 		    sizeof (new_physname)) != 0) {
1276 			if (get_guid(physname, guid, sizeof (guid), 1,
1277 			    DI_NODE_NIL) == 0)
1278 				(void) snprintf(new_physname, MAXPATHLEN,
1279 				    "/scsi_vhci/%s%s", DISK_AT_G, guid);
1280 			else
1281 				mapped = 0;
1282 		}
1283 
1284 		if (mapped == 0)
1285 			continue;
1286 
1287 		/* strip the slice number part */
1288 		devname[strlen(devname) - 2] = '\0';
1289 
1290 		if (guidmap == 0) {
1291 			if (lookup_devlink(new_physname, minor,
1292 			    new_devname, sizeof (new_devname)) != 0)
1293 				continue;
1294 
1295 			/* strip the slice number part */
1296 			new_devname[strlen(new_devname) - 2] = '\0';
1297 
1298 			if (header) {
1299 				(void) printf(
1300 				    gettext("non-STMS device name\t\t\t"
1301 				    "STMS device name\n"
1302 				    "------------------------------------------"
1303 				    "------------------------\n"));
1304 				header = 0;
1305 			}
1306 			(void) printf("%s\t\t%s\n", devname, new_devname);
1307 		} else {
1308 			/* extract guid part */
1309 			if ((p1 = strstr(new_physname, DISK_AT_G)) == NULL) {
1310 				logdmsg("invalid vhci: %s\n", new_physname);
1311 				continue;
1312 			}
1313 			p1 += sizeof (DISK_AT_G) - 1;
1314 			if ((p2 = strrchr(p1, ':')) != NULL)
1315 				*p2 = '\0';
1316 
1317 			if (header) {
1318 				(void) printf(
1319 				    gettext("non-STMS device name\t\t\tGUID\n"
1320 				    "------------------------------------------"
1321 				    "------------------------\n"));
1322 				header = 0;
1323 			}
1324 			(void) printf("%s\t\t%s\n", devname, p1);
1325 		}
1326 	}
1327 
1328 	(void) closedir(dirp);
1329 	return (0);
1330 }
1331 
1332 /*
1333  * Check if the file can be opened.
1334  *
1335  * Return 1 if the file can be opened, 0 otherwise.
1336  */
1337 static int
1338 canopen(char *filename)
1339 {
1340 	int fd;
1341 
1342 	if ((fd = open(filename, O_RDONLY)) == -1)
1343 		return (0);
1344 
1345 	(void) close(fd);
1346 	return (1);
1347 }
1348 
1349 static void
1350 logerr(char *msg, ...)
1351 {
1352 	va_list ap;
1353 
1354 	(void) fprintf(stderr, "%s: ", stmsboot);
1355 	va_start(ap, msg);
1356 	/* LINTED - format specifier */
1357 	(void) vfprintf(stderr, msg, ap);
1358 	va_end(ap);
1359 }
1360 
1361 /* log debug message */
1362 static void
1363 logdmsg(char *msg, ...)
1364 {
1365 	va_list ap;
1366 
1367 	if (debug) {
1368 		va_start(ap, msg);
1369 		/* LINTED - format specifier */
1370 		(void) vprintf(msg, ap);
1371 		va_end(ap);
1372 	}
1373 }
1374 
1375 static void *
1376 s_malloc(const size_t size)
1377 {
1378 	void *rp;
1379 
1380 	if ((rp = malloc(size)) == NULL) {
1381 		logerr(gettext("malloc failed to allocate %d bytes\n"), size);
1382 		clean_exit(1);
1383 	}
1384 	return (rp);
1385 }
1386 
1387 static char *
1388 s_strdup(const char *ptr)
1389 {
1390 	void *rp;
1391 
1392 	if ((rp = strdup(ptr)) == NULL) {
1393 		logerr(gettext("strdup failed to dup %s\n"), ptr);
1394 		clean_exit(1);
1395 	}
1396 	return (rp);
1397 }
1398 
1399 static void
1400 s_strlcpy(char *dst, const char *src, size_t dstsize)
1401 {
1402 	int n;
1403 
1404 	if ((n = strlcpy(dst, src, dstsize)) >= dstsize) {
1405 		logerr(gettext("strlcpy: destination buffer size is %1$d "
1406 		    "bytes, need to at least %2$d bytes\n"), dstsize, n + 1);
1407 		clean_exit(1);
1408 	}
1409 }
1410 
1411 static void
1412 clean_exit(int status)
1413 {
1414 	if (devinfo_root != DI_NODE_NIL)
1415 		di_fini(devinfo_root);
1416 
1417 	if (devlink_hdl != NULL)
1418 		(void) di_devlink_fini(&devlink_hdl);
1419 
1420 	if (vhci_fd != -1)
1421 		(void) close(vhci_fd);
1422 
1423 	exit(status);
1424 }
1425