xref: /illumos-gate/usr/src/cmd/rmformat/rmf_misc.c (revision fcabbd87549f01117a5d466ddcaaf1fa39ee2c14)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * rmf_misc.c :
29  *	Miscelleneous routines for rmformat.
30  */
31 
32 #include <sys/types.h>
33 #include <stdio.h>
34 #include <sys/mnttab.h>
35 #include <volmgt.h>
36 #include <sys/dkio.h>
37 #include <sys/fdio.h>
38 #include <sys/vtoc.h>
39 #include <sys/termios.h>
40 #include <sys/mount.h>
41 #include <ctype.h>
42 #include <signal.h>
43 #include <sys/wait.h>
44 #include <dirent.h>
45 #include <priv_utils.h>
46 #include <stdarg.h>
47 #include "rmformat.h"
48 
49 /*
50  * Definitions.
51  */
52 #define	SENSE_KEY(rqbuf)	(rqbuf[2] & 0xf) /* scsi error category */
53 #define	ASC(rqbuf)		(rqbuf[12])	/* additional sense code */
54 #define	ASCQ(rqbuf)		(rqbuf[13])	/* ASC qualifier */
55 
56 #define	DEFAULT_SCSI_TIMEOUT	60
57 #define	INQUIRY_CMD		0x12
58 #define	RQBUFLEN		32
59 #define	CD_RW			1		/* CD_RW/CD-R	*/
60 #define	WRITE_10_CMD		0x2A
61 #define	READ_INFO_CMD		0x51
62 #define	SYNC_CACHE_CMD		0x35
63 #define	CLOSE_TRACK_CMD		0x5B
64 #define	MODE_SENSE_10_CMD	0x5A
65 #define	DEVFS_PREFIX		"/devices"
66 
67 int		uscsi_error;		 /* used for debugging failed uscsi */
68 char		rqbuf[RQBUFLEN];
69 static uint_t	total_retries;
70 static struct	uscsi_cmd uscmd;
71 static char	ucdb[16];
72 uchar_t		uscsi_status, rqstatus, rqresid;
73 int		total_devices_found = 0;
74 int		removable_found = 0;
75 
76 extern char	*global_intr_msg;
77 extern int	vol_running;
78 extern char	*dev_name;
79 extern int32_t	m_flag;
80 
81 /*
82  * ON-private functions from libvolmgt
83  */
84 int	_dev_mounted(char *path);
85 
86 /*
87  * Function prototypes.
88  */
89 static int		my_umount(char *mountp);
90 static int		my_volrmmount(char *real_name);
91 static int		vol_name_to_dev_node(char *vname, char *found);
92 static int		vol_lookup(char *supplied, char *found);
93 static device_t		*get_device(char *user_supplied, char *node);
94 static char		*get_physical_name(char *path);
95 static int		lookup_device(char *supplied, char *found);
96 static void		fini_device(device_t *dev);
97 static int		is_cd(char *node);
98 void			*my_zalloc(size_t size);
99 void			err_msg(char *fmt, ...);
100 int			inquiry(int fd, uchar_t *inq);
101 struct uscsi_cmd	*get_uscsi_cmd(void);
102 int			uscsi(int fd, struct uscsi_cmd *scmd);
103 int			get_mode_page(int fd, int page_no, int pc, int buf_len,
104 			    uchar_t *buffer);
105 int			mode_sense(int fd, uchar_t pc, int dbd, int page_len,
106 			    uchar_t *buffer);
107 uint16_t		read_scsi16(void *addr);
108 int			check_device(device_t *dev, int cond);
109 static void		get_media_info(device_t *t_dev, char *sdev,
110 			    char *pname, char *sn);
111 
112 extern void		process_p_flag(smedia_handle_t handle, int32_t fd);
113 
114 void
115 my_perror(char *err_string)
116 {
117 
118 	int error_no;
119 	if (errno == 0)
120 		return;
121 
122 	error_no = errno;
123 	(void) fprintf(stderr, "%s", err_string);
124 	(void) fprintf(stderr, gettext(" : "));
125 	errno = error_no;
126 	perror("");
127 }
128 
129 int32_t
130 get_confirmation()
131 {
132 	char c;
133 
134 	(void) fprintf(stderr, gettext("Do you want to continue? (y/n)"));
135 	c = getchar();
136 	if (c == 'y' || c == 'Y')
137 		return (1);
138 	else if (c == 'n' || c == 'N')
139 		return (0);
140 	else {
141 		(void) fprintf(stderr, gettext("Invalid choice\n"));
142 		return (0);
143 	}
144 }
145 
146 
147 void
148 get_passwd(struct smwp_state *wp, int32_t confirm)
149 {
150 	char passwd[256], re_passwd[256];
151 	int32_t len;
152 	struct termios tio;
153 	int32_t echo_off = 0;
154 	FILE *in, *out;
155 	char *buf;
156 
157 
158 	in = fopen("/dev/tty", "r+");
159 	if (in == NULL) {
160 		in = stdin;
161 		out = stderr;
162 	} else {
163 		out = in;
164 	}
165 
166 	/* Turn echoing off if it is on now.  */
167 
168 	if (tcgetattr(fileno(in), &tio) < 0) {
169 		PERROR("Echo off ioctl failed");
170 		exit(1);
171 	}
172 	if (tio.c_lflag & ECHO) {
173 		tio.c_lflag &= ~ECHO;
174 		/* echo_off = tcsetattr(fileno(in), TCSAFLUSH, &tio) == 0; */
175 		echo_off = tcsetattr(fileno(in), TCSAFLUSH, &tio) == 0;
176 		tio.c_lflag |= ECHO;
177 	}
178 
179 	/* CONSTCOND */
180 	while (1) {
181 		(void) fputs(
182 		    gettext("Please enter password (32 chars maximum):"),
183 		    out);
184 		(void) fflush(out);
185 		buf = fgets(passwd, (size_t)256, in);
186 		rewind(in);
187 		if (buf == NULL) {
188 			PERROR("Error reading password");
189 			continue;
190 		}
191 		len = strlen(passwd);
192 		(void) fputc('\n', out);
193 		len--;	/* To offset the \n */
194 		if ((len <= 0) || (len > 32)) {
195 			(void) fprintf(stderr,
196 			    gettext("Invalid length of password \n"));
197 			(void) fputs("Try again\n", out);
198 			continue;
199 		}
200 
201 		if (!confirm)
202 			break;
203 
204 		(void) fputs("Please reenter password:", out);
205 		(void) fflush(out);
206 		buf = fgets(re_passwd, (size_t)256, in);
207 		rewind(in);
208 		(void) fputc('\n', out);
209 		if ((buf == NULL) || strcmp(passwd, re_passwd)) {
210 			(void) fputs("passwords did not match\n", out);
211 			(void) fputs("Try again\n", out);
212 		} else {
213 			break;
214 		}
215 	}
216 	wp->sm_passwd_len = len;
217 	(void) strncpy(wp->sm_passwd, passwd, wp->sm_passwd_len);
218 	wp->sm_version = SMWP_STATE_V_1;
219 
220 	/* Restore echoing.  */
221 	if (echo_off)
222 		(void) tcsetattr(fileno(in), TCSAFLUSH, &tio);
223 
224 }
225 
226 int32_t
227 check_and_unmount_vold(char *device_name, int32_t flag)
228 {
229 	char *real_name;
230 	char *nm;
231 	char tmp_path_name[PATH_MAX];
232 	struct stat stat_buf;
233 	int32_t ret_val = 0;
234 	struct	mnttab	*mntp;
235 	FILE	*fp;
236 	int nl;
237 
238 	DPRINTF1("Device name %s\n", device_name);
239 
240 	if (volmgt_running() == 0) {
241 		DPRINTF("Vold not running\n");
242 		return (0);
243 	}
244 	if ((nm = volmgt_symname(device_name)) == NULL) {
245 		DPRINTF("path not managed\n");
246 		real_name = media_findname(device_name);
247 	} else {
248 		DPRINTF1("path managed as %s\n", nm);
249 		real_name = media_findname(nm);
250 		DPRINTF1("real name %s\n", real_name);
251 	}
252 
253 	if (real_name == NULL)
254 		return (-1);
255 
256 	/*
257 	 * To find out whether the device has been mounted by
258 	 * volume manager...
259 	 *
260 	 * Convert the real name to a block device address.
261 	 * Do a partial match with the mnttab entries.
262 	 * Make sure the match is in the beginning to avoid if
263 	 * anybody puts a label similiar to volume manager path names.
264 	 * Then use "volrmmount -e <dev_name>" if -U flag is set.
265 	 */
266 
267 	nl = strlen("/vol/dev/");
268 
269 	if (strncmp(real_name, "/vol/dev/", nl) != 0)
270 			return (0);
271 	if (real_name[nl] == 'r') {
272 		(void) snprintf(tmp_path_name, PATH_MAX, "%s%s", "/vol/dev/",
273 		    &real_name[nl + 1]);
274 	} else {
275 		(void) snprintf(tmp_path_name, PATH_MAX, "%s", real_name);
276 	}
277 	DPRINTF1("%s \n", tmp_path_name);
278 	ret_val = stat(tmp_path_name, &stat_buf);
279 	if (ret_val < 0) {
280 		PERROR("Could not stat");
281 		return (-1);
282 	}
283 
284 	fp = fopen("/etc/mnttab", "r");
285 
286 	if (fp == NULL) {
287 		PERROR("Could not open /etc/mnttab");
288 		return (-1);
289 	}
290 
291 	mntp = (struct mnttab *)malloc(sizeof (struct mnttab));
292 	if (mntp == NULL) {
293 		PERROR("malloc failed");
294 		(void) fclose(fp);
295 		return (-1);
296 	}
297 	errno = 0;
298 	while (getmntent(fp, mntp) == 0) {
299 		if (errno != 0) {
300 			PERROR("Error with mnttab");
301 			(void) fclose(fp);
302 			return (-1);
303 		}
304 		/* Is it a probable entry? */
305 		DPRINTF1(" %s \n", mntp->mnt_special);
306 		if (strstr(mntp->mnt_special, tmp_path_name) !=
307 		    mntp->mnt_special) {
308 			/* Skip to next entry */
309 			continue;
310 		} else {
311 			DPRINTF1("Found!! %s\n", mntp->mnt_special);
312 			ret_val = 1;
313 			break;
314 		}
315 	}
316 
317 	if (ret_val == 1) {
318 		if (flag) {
319 			if (my_volrmmount(real_name) < 0) {
320 				ret_val = -1;
321 			}
322 		} else {
323 			ret_val = -1;
324 		}
325 	}
326 	(void) fclose(fp);
327 	free(mntp);
328 	return (ret_val);
329 }
330 
331 /*
332  * This routine checks if a device has mounted partitions. The
333  * device name is assumed to be /dev/rdsk/cNtNdNsN. So, this can
334  * be used for SCSI and PCMCIA cards.
335  * Returns
336  *	 0 : if not mounted
337  *	 1 : if successfully unmounted
338  *	-1 : Any error or umount failed
339  */
340 
341 int32_t
342 check_and_unmount_scsi(char *device_name, int32_t flag)
343 {
344 
345 	struct	mnttab	*mntrefp;
346 	struct	mnttab	*mntp;
347 	FILE	*fp;
348 	char block_dev_name[PATH_MAX];
349 	char tmp_name[PATH_MAX];
350 	int32_t  i, j;
351 	int32_t unmounted = 0;
352 
353 	/*
354 	 * If the device name is not a character special, anyway we
355 	 * can not progress further
356 	 */
357 
358 	if (strncmp(device_name, "/dev/rdsk/c", strlen("/dev/rdsk/c")) != 0)
359 		return (0);
360 
361 	(void) snprintf(block_dev_name, PATH_MAX, "/dev/%s",
362 	    &device_name[strlen("/dev/r")]);
363 	fp = fopen("/etc/mnttab", "r");
364 
365 	if (fp == NULL) {
366 		PERROR("Could not open /etc/mnttab");
367 		return (-1);
368 	}
369 
370 	mntrefp = (struct mnttab *)malloc(sizeof (struct mnttab));
371 	if (mntrefp == NULL) {
372 		PERROR("malloc failed");
373 		(void) fclose(fp);
374 		return (-1);
375 	}
376 
377 	mntp = (struct mnttab *)malloc(sizeof (struct mnttab));
378 	if (mntp == NULL) {
379 		PERROR("malloc failed");
380 		(void) fclose(fp);
381 		free(mntrefp);
382 		return (-1);
383 	}
384 
385 	/* Try all the partitions */
386 
387 	(void) snprintf(tmp_name, PATH_MAX, "/dev/%s",
388 	    &device_name[strlen("/dev/r")]);
389 
390 	tmp_name[strlen("/dev/dsk/c0t0d0s")] = '\0';
391 
392 	errno = 0;
393 	while (getmntent(fp, mntp) == 0) {
394 		if (errno != 0) {
395 			PERROR("Error with mnttab");
396 			(void) fclose(fp);
397 			return (-1);
398 		}
399 		/* Is it a probable entry? */
400 		if (strncmp(mntp->mnt_special, tmp_name, strlen(tmp_name))) {
401 			/* Skip to next entry */
402 			continue;
403 		}
404 		for (i = 0; i < NDKMAP; i++) {
405 			/* Check for ufs style mount devices */
406 			(void) snprintf(block_dev_name, PATH_MAX,
407 			    "%s%d", tmp_name, i);
408 
409 			if (strcmp(mntp->mnt_special, block_dev_name) == 0) {
410 				if (flag) {
411 					if (my_umount(mntp->mnt_mountp) < 0) {
412 						(void) fclose(fp);
413 						return (-1);
414 					}
415 					unmounted = 1;
416 				} else {
417 					(void) fclose(fp);
418 					return (-1);
419 				}
420 				/* Skip to next entry */
421 				continue;
422 			}
423 
424 			/* Try for :1 -> :24 for pcfs */
425 
426 			for (j = 1; j < 24; j++) {
427 				(void) snprintf(block_dev_name, PATH_MAX,
428 				    "%s%d:%d", tmp_name, i, j);
429 
430 				if (strcmp(mntp->mnt_special,
431 				    block_dev_name) == 0) {
432 					if (flag) {
433 						if (my_umount(mntp->mnt_mountp)
434 						    < 0) {
435 							(void) fclose(fp);
436 							return (-1);
437 						}
438 						unmounted = 1;
439 					} else {
440 						(void) fclose(fp);
441 						return (-1);
442 					}
443 					/* Skip to next entry */
444 					continue;
445 				}
446 				(void) snprintf(block_dev_name, PATH_MAX,
447 				    "%s%d:%c", tmp_name, i, 'b' + j);
448 
449 				if (strcmp(mntp->mnt_special,
450 				    block_dev_name) == 0) {
451 					if (flag) {
452 						if (my_umount(mntp->mnt_mountp)
453 						    < 0) {
454 							(void) fclose(fp);
455 							return (-1);
456 						}
457 						unmounted = 1;
458 					} else {
459 						(void) fclose(fp);
460 						return (-1);
461 					}
462 					/* Skip to next entry */
463 					continue;
464 				}
465 			}
466 		}
467 
468 	}
469 
470 	if (unmounted)
471 		return (1);
472 	return (0);
473 }
474 
475 /*
476  * This routine checks if a device has mounted partitions. The
477  * device name is assumed to be /dev/rdiskette. So, this can
478  * be used for Floppy controllers
479  * Returns
480  *	 0 : if not mounted
481  *	 1 : if successfully unmounted
482  *	-1 : Any error or unmount failed
483  */
484 
485 int32_t
486 check_and_unmount_floppy(int32_t fd, int32_t flag)
487 {
488 	FILE	*fp = NULL;
489 	int32_t	mfd;
490 	struct dk_cinfo dkinfo, dkinfo_tmp;
491 	struct mnttab	mnt_record;
492 	struct mnttab	*mp = &mnt_record;
493 	struct stat	stbuf;
494 	char	raw_device[PATH_MAX];
495 	int32_t	found = 0;
496 
497 
498 	if (ioctl(fd, DKIOCINFO, &dkinfo) < 0) {
499 		return (-1);
500 	}
501 
502 	if ((fp = fopen(MNTTAB, "r")) == NULL) {
503 		PERROR("Could not open /etc/mnttab");
504 		(void) close(fd);
505 		exit(3);
506 	}
507 
508 	while (getmntent(fp, mp) == 0) {
509 		if (strstr(mp->mnt_special, "/dev/fd") == NULL &&
510 		    strstr(mp->mnt_special, "/dev/disket") == NULL &&
511 		    strstr(mp->mnt_special, "/dev/c") == NULL) {
512 			continue;
513 		}
514 
515 		(void) strcpy(raw_device, "/dev/r");
516 		(void) strcat(raw_device, mp->mnt_special + strlen("/dev/"));
517 
518 
519 		/*
520 		 * Attempt to open the device.	If it fails, skip it.
521 		 */
522 
523 		/* Turn on the privileges. */
524 		(void) __priv_bracket(PRIV_ON);
525 
526 		mfd = open(raw_device, O_RDWR | O_NDELAY);
527 
528 		/* Turn off the privileges. */
529 		(void) __priv_bracket(PRIV_OFF);
530 
531 		if (mfd < 0) {
532 			continue;
533 		}
534 
535 		/*
536 		 * Must be a character device
537 		 */
538 		if (fstat(mfd, &stbuf) < 0 || !S_ISCHR(stbuf.st_mode)) {
539 			(void) close(mfd);
540 			continue;
541 		}
542 		/*
543 		 * Attempt to read the configuration info on the disk.
544 		 */
545 		if (ioctl(mfd, DKIOCINFO, &dkinfo_tmp) < 0) {
546 			(void) close(mfd);
547 			continue;
548 		}
549 		/*
550 		 * Finished with the opened device
551 		 */
552 		(void) close(mfd);
553 
554 		/*
555 		 * If it's not the disk we're interested in, it doesn't apply.
556 		 */
557 		if (dkinfo.dki_ctype != dkinfo_tmp.dki_ctype ||
558 		    dkinfo.dki_cnum != dkinfo_tmp.dki_cnum ||
559 		    dkinfo.dki_unit != dkinfo_tmp.dki_unit) {
560 				continue;
561 		}
562 		/*
563 		 * It's a mount on the disk we're checking.  If we are
564 		 * checking whole disk, then we found trouble.	We can
565 		 * quit searching.
566 		 */
567 
568 		if (flag) {
569 			if (my_umount(mp->mnt_mountp) < 0) {
570 				return (-1);
571 			}
572 			found = 1;
573 		} else {
574 			return (-1);
575 		}
576 	}
577 	return (found);
578 }
579 
580 
581 int32_t
582 my_open(char *device_name, int32_t flags)
583 {
584 	char *real_name;
585 	char *nm;
586 	char tmp_path_name[PATH_MAX];
587 	struct stat stat_buf;
588 	int32_t ret_val;
589 	int32_t fd;
590 	int32_t have_read_priv = 0;
591 	DIR *dirp;
592 	struct dirent *dp;
593 
594 	DPRINTF1("Device name %s\n", device_name);
595 
596 	if ((nm = volmgt_symname(device_name)) == NULL) {
597 		DPRINTF("path not managed\n");
598 		real_name = media_findname(device_name);
599 	} else {
600 		DPRINTF1("path managed as %s\n", nm);
601 		real_name = media_findname(nm);
602 		DPRINTF1("real name %s\n", real_name);
603 	}
604 
605 	if (real_name == NULL)
606 		return (-1);
607 
608 	(void) strcpy(tmp_path_name, real_name);
609 	ret_val = stat(tmp_path_name, &stat_buf);
610 	if (ret_val < 0) {
611 		PERROR("Could not stat");
612 		return (-1);
613 	}
614 	if (S_ISDIR(stat_buf.st_mode)) {
615 
616 		/*
617 		 * Open the directory and look for the
618 		 * first non '.' entry.
619 		 * Since raw_read and raw_writes are used, we don't
620 		 * need to access the backup slice.
621 		 * For PCMCIA Memory cards, raw_read and raw_writes are
622 		 * not supported, but that is not a problem as, only slice2
623 		 * is allowed on PCMCIA memory cards.
624 		 */
625 
626 		/*
627 		 * First make sure we are operating with a /vol/....
628 		 * Otherwise it can dangerous,
629 		 * e.g. rmformat -s /dev/rdsk
630 		 * We should not look into the directory contents here.
631 		 */
632 		if (strncmp(tmp_path_name, "/vol/dev/", strlen("/vol/dev/"))
633 		    != 0) {
634 			(void) fprintf(stderr, gettext("The specified device \
635 is not a raw device.\n"));
636 			exit(1);
637 		}
638 
639 		/* Turn on the privileges. */
640 		(void) __priv_bracket(PRIV_ON);
641 
642 		dirp = opendir(tmp_path_name);
643 
644 		/* Turn off the privileges. */
645 		(void) __priv_bracket(PRIV_OFF);
646 
647 		if (dirp == NULL) {
648 			return (-1);
649 		}
650 
651 		/* Turn on the privileges. */
652 		(void) __priv_bracket(PRIV_ON);
653 		have_read_priv = 1;
654 
655 		while ((dp = readdir(dirp)) != NULL) {
656 
657 			/* Turn off the privileges. */
658 			(void) __priv_bracket(PRIV_OFF);
659 			have_read_priv = 0;
660 
661 			DPRINTF1("Found %s\n", dp->d_name);
662 			if ((strcmp(dp->d_name, ".") != 0) &&
663 			    (strcmp(dp->d_name, "..") != 0)) {
664 				size_t len = strlen(tmp_path_name);
665 
666 				(void) snprintf(tmp_path_name + len,
667 				    PATH_MAX - len, "/%s", dp->d_name);
668 
669 				DPRINTF1("tmp_pathname is %s\n", tmp_path_name);
670 				break;
671 			}
672 
673 			/* Turn on the privileges. */
674 			(void) __priv_bracket(PRIV_ON);
675 			have_read_priv = 1;
676 		}
677 
678 		if (have_read_priv) {
679 			/* drop the file_dac_read privilege */
680 			(void) __priv_bracket(PRIV_OFF);
681 			have_read_priv = 0;
682 		}
683 
684 		(void) closedir(dirp);
685 	}
686 
687 
688 	if (volmgt_running() == 0) {
689 		/* Turn on privileges. */
690 		(void) __priv_bracket(PRIV_ON);
691 		have_read_priv = 1;
692 	}
693 
694 	fd = open(tmp_path_name, flags);
695 
696 	if (have_read_priv) {
697 		/* Turn off privileges. */
698 		(void) __priv_bracket(PRIV_OFF);
699 		have_read_priv = 0;
700 	}
701 
702 	DPRINTF1("path opened %s\n", tmp_path_name);
703 
704 	return (fd);
705 }
706 
707 uint64_t
708 my_atoll(char *ptr)
709 {
710 	char *tmp_ptr = ptr;
711 	int32_t base = 10;
712 	uint64_t ret_val;
713 
714 	while (*tmp_ptr) {
715 		if (isdigit(*tmp_ptr))
716 			tmp_ptr++;
717 		else {
718 			base = 16;
719 			break;
720 		}
721 	}
722 	tmp_ptr = ptr;
723 	if (base == 16) {
724 		if (strlen(tmp_ptr) < 3) {
725 			return (-1);
726 		}
727 		if (*tmp_ptr++ != '0' || (*tmp_ptr != 'x' && *tmp_ptr != 'X')) {
728 			return (-1);
729 		}
730 		tmp_ptr++;
731 		while (*tmp_ptr) {
732 			if (isxdigit(*tmp_ptr))
733 				tmp_ptr++;
734 			else {
735 				return (-1);
736 			}
737 		}
738 	}
739 	ret_val = (uint64_t)strtoull(ptr, (char **)NULL, 0);
740 	return (ret_val);
741 }
742 
743 int32_t
744 write_sunos_label(int32_t fd, int32_t media_type)
745 {
746 
747 	struct extvtoc v_toc;
748 	int32_t ret;
749 
750 	(void) memset(&v_toc, 0, sizeof (struct extvtoc));
751 
752 	/* Initialize the vtoc information */
753 
754 	if (media_type == SM_FLOPPY) {
755 		struct fd_char fdchar;
756 		int32_t mult_factor;
757 
758 		if (ioctl(fd, FDIOGCHAR, &fdchar) < 0) {
759 			PERROR("FDIOGCHAR failed");
760 			return (-1);
761 		}
762 
763 		/* SPARC and x86 fd drivers use fdc_medium differently */
764 #if defined(__sparc)
765 		mult_factor = (fdchar.fdc_medium) ? 2 : 1;
766 #elif defined(__x86)
767 		mult_factor = (fdchar.fdc_medium == 5) ? 2 : 1;
768 #else
769 #error  No Platform defined
770 #endif /* defined(__sparc) */
771 
772 		/* initialize the vtoc structure */
773 		v_toc.v_nparts = 3;
774 
775 		v_toc.v_part[0].p_start = 0;
776 		v_toc.v_part[0].p_size = (fdchar.fdc_ncyl - 1) * 2 *
777 		    fdchar.fdc_secptrack * mult_factor;
778 		v_toc.v_part[1].p_start = (fdchar.fdc_ncyl - 1) * 2 *
779 		    fdchar.fdc_secptrack * mult_factor;
780 		v_toc.v_part[1].p_size = 2 * fdchar.fdc_secptrack * mult_factor;
781 
782 		v_toc.v_part[2].p_start = 0;
783 		v_toc.v_part[2].p_size = fdchar.fdc_ncyl * 2 *
784 		    fdchar.fdc_secptrack * mult_factor;
785 
786 	} else if (media_type == SM_SCSI_FLOPPY) {
787 
788 		smedia_handle_t handle;
789 		smmedium_prop_t med_info;
790 		struct dk_geom dkgeom;
791 
792 
793 		/*
794 		 * call smedia_get_medium_property to get the
795 		 * correct media information, since DKIOCGMEDIAINFO
796 		 * may fail for unformatted media.
797 		 */
798 
799 		handle = smedia_get_handle(fd);
800 		if (handle == NULL) {
801 			(void) fprintf(stderr,
802 			gettext("Failed to get libsmedia handle.\n"));
803 
804 			(void) close(fd);
805 			return (-1);
806 		}
807 
808 
809 		if (smedia_get_medium_property(handle, &med_info) < 0) {
810 			(void) fprintf(stderr,
811 			    gettext("Get medium property failed \n"));
812 
813 			(void) smedia_release_handle(handle);
814 			(void) close(fd);
815 			return (-1);
816 		}
817 
818 		/* Fill in our own geometry information */
819 
820 		dkgeom.dkg_pcyl = med_info.sm_pcyl;
821 		dkgeom.dkg_ncyl = med_info.sm_pcyl;
822 		dkgeom.dkg_nhead = med_info.sm_nhead;
823 		dkgeom.dkg_nsect = med_info.sm_nsect;
824 		dkgeom.dkg_acyl = 0;
825 		dkgeom.dkg_bcyl = 0;
826 		dkgeom.dkg_intrlv = 0;
827 		dkgeom.dkg_apc = 0;
828 
829 		/*
830 		 * Try to set vtoc, if not successful we will
831 		 * continue to use the faked geometry information.
832 		 */
833 
834 		(void) ioctl(fd, DKIOCSGEOM, &dkgeom);
835 
836 		(void) smedia_release_handle(handle);
837 
838 		/* we want the same partitioning as used for normal floppies */
839 
840 		v_toc.v_part[0].p_start = 0;
841 		v_toc.v_part[0].p_size =  (diskaddr_t)(dkgeom.dkg_ncyl - 1) *
842 		    dkgeom.dkg_nhead * dkgeom.dkg_nsect;
843 
844 		v_toc.v_part[1].p_start = (diskaddr_t)(dkgeom.dkg_ncyl - 1) *
845 		    dkgeom.dkg_nhead * dkgeom.dkg_nsect;
846 		v_toc.v_part[1].p_size =  dkgeom.dkg_nhead * dkgeom.dkg_nsect;
847 
848 		v_toc.v_part[2].p_start = 0;
849 		v_toc.v_part[2].p_size = (diskaddr_t)dkgeom.dkg_ncyl *
850 		    dkgeom.dkg_nhead * dkgeom.dkg_nsect;
851 
852 		/* both write_vtoc and DKIOCSVTOC require V_NUMPAR partitions */
853 		v_toc.v_nparts = V_NUMPAR;
854 
855 	} else {
856 
857 		return (0);
858 	}
859 
860 	v_toc.v_sanity = VTOC_SANE;
861 	v_toc.v_version = V_VERSION;
862 
863 	/*
864 	 * The label structure is set up for DEV_BSIZE(512 byte) blocks,
865 	 * even though a medium density diskette has 1024 byte blocks
866 	 * See dklabel.h for more details.
867 	 */
868 	v_toc.v_sectorsz = DEV_BSIZE;
869 
870 	/* let the fd driver finish constructing the label and writing it. */
871 
872 
873 	/* Turn on the privileges. */
874 	(void) __priv_bracket(PRIV_ON);
875 
876 	ret = write_extvtoc(fd, &v_toc);
877 
878 	/* Turn off the privileges. */
879 	(void) __priv_bracket(PRIV_OFF);
880 
881 	if (ret < 0) {
882 		PERROR("Write vtoc");
883 		DPRINTF1("Write vtoc failed errno:%d\n", errno);
884 		return (-1);
885 	}
886 
887 	return (0);
888 }
889 
890 static void
891 intr_sig_handler()
892 {
893 	char c;
894 
895 	(void) fprintf(stderr, gettext(global_intr_msg));
896 	(void) fprintf(stderr,
897 	    gettext("\nDo you want to stop formatting?(y/n)"));
898 	(void) fflush(stdout);
899 	rewind(stdin);
900 	while ((c = getchar()) == -1)
901 		;
902 	if (c == 'y' || c == 'Y') {
903 		(void) fprintf(stderr, gettext("Format interrupted\n"));
904 		exit(1);
905 	} else if (c == 'n' || c == 'N')
906 		return;
907 	else {
908 		(void) fprintf(stderr, gettext("Did not interrupt\n"));
909 		return;
910 	}
911 }
912 
913 static struct sigaction act, oact;
914 void
915 trap_SIGINT(void)
916 {
917 
918 	act.sa_handler = intr_sig_handler;
919 	(void) memset(&act.sa_mask, 0, sizeof (sigset_t));
920 	act.sa_flags = SA_RESTART; /* | SA_NODEFER; */
921 	if (sigaction(SIGINT, &act, &oact) < 0) {
922 		DPRINTF("sigset failed\n");
923 		return;
924 	}
925 }
926 
927 void
928 release_SIGINT(void)
929 {
930 	if (sigaction(SIGINT, &oact, (struct sigaction *)NULL) < 0) {
931 		DPRINTF("sigunset failed\n");
932 		return;
933 	}
934 }
935 
936 int32_t
937 verify(smedia_handle_t handle, int32_t fd, diskaddr_t start_sector,
938     uint32_t nblocks, char *buf,
939     int32_t flag, int32_t blocksize, int32_t no_raw_rw)
940 {
941 	uint64_t ret;
942 
943 	DPRINTF("ANALYSE MEDIA \n");
944 
945 
946 	if ((flag == VERIFY_READ) && (!no_raw_rw)) {
947 
948 		/* Turn on the privileges. */
949 		(void) __priv_bracket(PRIV_ON);
950 
951 		ret = smedia_raw_read(handle, start_sector, buf, nblocks *
952 		    blocksize);
953 
954 		/* Turn off the privileges. */
955 		(void) __priv_bracket(PRIV_OFF);
956 
957 		if (ret != (nblocks * blocksize))
958 			return (-1);
959 		return (0);
960 
961 	} else if ((flag == VERIFY_WRITE) && (!no_raw_rw)) {
962 
963 		/* Turn on privileges. */
964 		(void) __priv_bracket(PRIV_ON);
965 
966 		ret = smedia_raw_write(handle, start_sector, buf, nblocks *
967 		    blocksize);
968 
969 		/* Turn off the privileges. */
970 		(void) __priv_bracket(PRIV_OFF);
971 
972 		if (ret != (blocksize * nblocks))
973 			return (-1);
974 		return (0);
975 
976 	} else if ((flag == VERIFY_READ) && (no_raw_rw)) {
977 		ret = llseek(fd, start_sector * blocksize, SEEK_SET);
978 		if (ret != start_sector * blocksize) {
979 			(void) fprintf(stderr, gettext("Seek failed\n"));
980 			return (-2);
981 		}
982 
983 		/* Turn on the privileges. */
984 		(void) __priv_bracket(PRIV_ON);
985 
986 		ret = read(fd, buf, nblocks * blocksize);
987 
988 		/* Turn off the privileges. */
989 		(void) __priv_bracket(PRIV_OFF);
990 
991 		if (ret != nblocks * blocksize) {
992 			return (-1);
993 		}
994 		return (0);
995 	} else if ((flag == VERIFY_WRITE) && (no_raw_rw)) {
996 		ret = llseek(fd, start_sector * blocksize, SEEK_SET);
997 		if (ret != start_sector * blocksize) {
998 			(void) fprintf(stderr, gettext("Seek failed\n"));
999 			return (-2);
1000 		}
1001 
1002 		/* Turn on the privileges. */
1003 		(void) __priv_bracket(PRIV_ON);
1004 
1005 		ret = write(fd, buf, nblocks * blocksize);
1006 
1007 		/* Turn off the privileges. */
1008 		(void) __priv_bracket(PRIV_OFF);
1009 
1010 		if (ret != nblocks * blocksize) {
1011 			return (-1);
1012 		}
1013 		return (0);
1014 	} else {
1015 		DPRINTF("Illegal parameter to verify_analysis!\n");
1016 		return (-1);
1017 	}
1018 }
1019 
1020 static int
1021 my_umount(char *mountp)
1022 {
1023 	pid_t	pid;	/* forked proc's pid */
1024 	int	rval;	/* proc's return value */
1025 
1026 
1027 	/* create a child to unmount the path */
1028 
1029 	/* Turn on the privileges */
1030 	(void) __priv_bracket(PRIV_ON);
1031 
1032 	pid = fork();
1033 
1034 	/* Turn off the privileges. */
1035 	(void) __priv_bracket(PRIV_OFF);
1036 
1037 	if (pid < 0) {
1038 		PERROR("fork failed");
1039 		exit(0);
1040 	}
1041 
1042 	if (pid == 0) {
1043 		/* the child */
1044 		/* get rid of those nasty err messages */
1045 		DPRINTF1("call_unmount_prog: calling %s \n", mountp);
1046 
1047 		/* Turn on the priviliges. */
1048 		(void) __priv_bracket(PRIV_ON);
1049 
1050 		if (execl("/usr/sbin/umount", "/usr/sbin/umount", mountp,
1051 		    NULL) < 0) {
1052 			perror("exec failed");
1053 			/* Turn off the privileges */
1054 			(void) __priv_bracket(PRIV_OFF);
1055 			exit(-1);
1056 		}
1057 	}
1058 
1059 	/* wait for the umount command to exit */
1060 	rval = 0;
1061 	if (waitpid(pid, &rval, 0) == pid) {
1062 		if (WIFEXITED(rval)) {
1063 			if (WEXITSTATUS(rval) == 0) {
1064 				DPRINTF("umount : Success\n");
1065 				return (1);
1066 			}
1067 		}
1068 	}
1069 	return (-1);
1070 }
1071 
1072 static int
1073 my_volrmmount(char *real_name)
1074 {
1075 	int pid, rval;
1076 
1077 	/* Turn on the privileges. */
1078 	(void) __priv_bracket(PRIV_ON);
1079 
1080 	pid = fork();
1081 
1082 	/* Turn off the privileges. */
1083 	(void) __priv_bracket(PRIV_OFF);
1084 
1085 	/* create a child to unmount the path */
1086 	if (pid < 0) {
1087 		PERROR("fork failed");
1088 		exit(0);
1089 	}
1090 
1091 	if (pid == 0) {
1092 		/* the child */
1093 		/* get rid of those nasty err messages */
1094 		DPRINTF1("call_unmount_prog: calling %s \n",
1095 		    "/usr/bin/volrmmount");
1096 
1097 		/* Turn on the privileges. */
1098 		(void) __priv_bracket(PRIV_ON);
1099 		if (execl("/usr/bin/volrmmount", "/usr/bin/volrmmount", "-e",
1100 		    real_name, NULL) < 0) {
1101 			PERROR("volrmmount exec failed");
1102 			/* Turn off the privileges */
1103 			(void) __priv_bracket(PRIV_OFF);
1104 			exit(-1);
1105 		}
1106 	} else if (waitpid(pid, &rval, 0) == pid) {
1107 		if (WIFEXITED(rval)) {
1108 			if (WEXITSTATUS(rval) == 0) {
1109 				DPRINTF("volrmmount: Success\n");
1110 				return (1);
1111 			}
1112 		}
1113 	}
1114 	return (-1);
1115 }
1116 
1117 int
1118 find_device(int defer, char *tmpstr)
1119 {
1120 	DIR *dir;
1121 	struct dirent *dirent;
1122 	char sdev[PATH_MAX], dev[PATH_MAX], *pname;
1123 	device_t *t_dev;
1124 	int removable = 0;
1125 	int device_type = 0;
1126 	int hotpluggable = 0;
1127 	struct dk_minfo mediainfo;
1128 	static int found = 0;
1129 
1130 	dir = opendir("/dev/rdsk");
1131 	if (dir == NULL)
1132 		return (-1);
1133 
1134 	total_devices_found = 0;
1135 	while ((dirent = readdir(dir)) != NULL) {
1136 		if (dirent->d_name[0] == '.') {
1137 			continue;
1138 		}
1139 		(void) snprintf(sdev, PATH_MAX, "/dev/rdsk/%s",
1140 		    dirent->d_name);
1141 #ifdef sparc
1142 		if (!strstr(sdev, "s2")) {
1143 			continue;
1144 		}
1145 #else /* x86 */
1146 		if (vol_running) {
1147 			if (!(strstr(sdev, "s2") || strstr(sdev, "p0"))) {
1148 				continue;
1149 			}
1150 		} else {
1151 			if (!strstr(sdev, "p0")) {
1152 				continue;
1153 			}
1154 		}
1155 #endif
1156 		if (!lookup_device(sdev, dev)) {
1157 			continue;
1158 		}
1159 		if ((t_dev = get_device(NULL, dev)) == NULL) {
1160 			continue;
1161 		}
1162 		total_devices_found++;
1163 
1164 		if ((!defer) && !found) {
1165 			char *sn, *tmpbuf;
1166 			/*
1167 			 * dev_name is an optional command line input.
1168 			 */
1169 			if (dev_name) {
1170 				if (strstr(dirent->d_name, tmpstr)) {
1171 					found = 1;
1172 				} else if (!vol_running) {
1173 					continue;
1174 				}
1175 			}
1176 			/*
1177 			 * volmgt_symname() returns NULL if the device
1178 			 * is not managed by volmgt.
1179 			 */
1180 			sn = volmgt_symname(sdev);
1181 
1182 			if (vol_running && (sn != NULL)) {
1183 				if (strstr(sn, "dev") == NULL) {
1184 					tmpbuf = (char *)my_zalloc(PATH_MAX);
1185 					(void) strcpy(tmpbuf,
1186 					    "/vol/dev/aliases/");
1187 					(void) strcat(tmpbuf, sn);
1188 					free(sn);
1189 					sn = tmpbuf;
1190 				}
1191 				if (dev_name && !found) {
1192 					if (!strstr(tmpbuf, tmpstr)) {
1193 						continue;
1194 					} else {
1195 						found = 1;
1196 					}
1197 				}
1198 			}
1199 
1200 			/*
1201 			 * Get device type information for CD/DVD devices.
1202 			 */
1203 			if (is_cd(dev)) {
1204 				if (check_device(t_dev,
1205 				    CHECK_DEVICE_IS_DVD_WRITABLE)) {
1206 					device_type = DK_DVDR;
1207 				} else if (check_device(t_dev,
1208 				    CHECK_DEVICE_IS_DVD_READABLE)) {
1209 					device_type = DK_DVDROM;
1210 				} else if (check_device(t_dev,
1211 				    CHECK_DEVICE_IS_CD_WRITABLE)) {
1212 					device_type = DK_CDR;
1213 				} else {
1214 					device_type = DK_CDROM;
1215 				}
1216 			} else {
1217 				device_type = ioctl(t_dev->d_fd,
1218 				    DKIOCGMEDIAINFO, &mediainfo);
1219 				if (device_type < 0)
1220 					device_type = 0;
1221 				else
1222 					device_type = mediainfo.dki_media_type;
1223 			}
1224 
1225 			if (!ioctl(t_dev->d_fd, DKIOCREMOVABLE, &removable) &&
1226 			    !ioctl(t_dev->d_fd, DKIOCHOTPLUGGABLE,
1227 			    &hotpluggable)) {
1228 				if (removable || hotpluggable) {
1229 					removable_found++;
1230 					pname = get_physical_name(sdev);
1231 					if (sn) {
1232 						(void) printf("  %4d. "
1233 						    "Volmgt Node: %s\n",
1234 						    removable_found, sn);
1235 						(void) printf("        "
1236 						    "Logical Node: %s\n", sdev);
1237 						(void) printf("        "
1238 						    "Physical Node: %s\n",
1239 						    pname);
1240 					} else {
1241 						(void) printf("  %4d. "
1242 						    "Logical Node: %s\n",
1243 						    removable_found, sdev);
1244 						(void) printf("        "
1245 						    "Physical Node: %s\n",
1246 						    pname);
1247 					}
1248 					(void) printf("        Connected "
1249 					    "Device: %-8.8s %-16.16s "
1250 					    "%-4.4s\n",
1251 					    &t_dev->d_inq[8],
1252 					    &t_dev->d_inq[16],
1253 					    &t_dev->d_inq[32]);
1254 					(void) printf("        Device "
1255 					    "Type: ");
1256 				} else
1257 					continue;
1258 			} else
1259 				continue;
1260 
1261 			switch (device_type) {
1262 				case DK_CDROM:
1263 					(void) printf("CD Reader\n");
1264 					break;
1265 				case DK_CDR:
1266 				case DK_CDRW:
1267 					(void) printf("CD Reader/Writer\n");
1268 					break;
1269 				case DK_DVDROM:
1270 					(void) printf("DVD Reader\n");
1271 					break;
1272 				case DK_DVDR:
1273 				case DK_DVDRAM:
1274 					(void) printf("DVD Reader/Writer\n");
1275 					break;
1276 				case DK_FIXED_DISK:
1277 					if (strstr((const char *)
1278 					    &t_dev->d_inq[16], "FD") ||
1279 					    strstr((const char *)
1280 					    &t_dev->d_inq[16], "LS-120"))
1281 						(void) printf("Floppy "
1282 						    "drive\n");
1283 					else
1284 						(void) printf("Removable\n");
1285 					break;
1286 				case DK_FLOPPY:
1287 					(void) printf("Floppy drive\n");
1288 					break;
1289 				case DK_ZIP:
1290 					(void) printf("Zip drive\n");
1291 					break;
1292 				case DK_JAZ:
1293 					(void) printf("Jaz drive\n");
1294 					break;
1295 				default:
1296 					(void) printf("<Unknown>\n");
1297 					DPRINTF1("\t   %d\n", device_type);
1298 					break;
1299 			}
1300 			get_media_info(t_dev, sdev, pname, sn);
1301 		}
1302 		fini_device(t_dev);
1303 	}
1304 
1305 	(void) closedir(dir);
1306 	return (removable_found);
1307 }
1308 
1309 /*
1310  * Returns a device_t handle for a node returned by lookup_device()
1311  * and takes the user supplied name and stores it inside the node.
1312  */
1313 static device_t *
1314 get_device(char *user_supplied, char *node)
1315 {
1316 	device_t *dev;
1317 	int fd;
1318 	char devnode[PATH_MAX];
1319 	int size;
1320 
1321 	/*
1322 	 * we need to resolve any link paths to avoid fake files
1323 	 * such as /dev/rdsk/../../export/file.
1324 	 */
1325 	size = resolvepath(node, devnode, PATH_MAX);
1326 	if ((size <= 0) || (size >= (PATH_MAX - 1)))
1327 		return (NULL);
1328 
1329 	/* resolvepath may not return a null terminated string */
1330 	devnode[size] = '\0';
1331 
1332 
1333 	/* the device node must be in /devices/ or /vol/dev/rdsk */
1334 
1335 	if ((strncmp(devnode, "/devices/", 9) != 0) &&
1336 	    (strncmp(devnode, "/vol/dev/rdsk", 13) != 0))
1337 		return (NULL);
1338 
1339 	/* Turn on the privileges. */
1340 	(void) __priv_bracket(PRIV_ON);
1341 
1342 	/*
1343 	 * Since we are currently running with the user euid it is
1344 	 * safe to try to open the file without checking access.
1345 	 */
1346 
1347 	fd = open(devnode, O_RDONLY|O_NDELAY);
1348 
1349 	/* Turn off the privileges. */
1350 	(void) __priv_bracket(PRIV_OFF);
1351 
1352 	if (fd < 0) {
1353 		return (NULL);
1354 	}
1355 
1356 	dev = (device_t *)my_zalloc(sizeof (device_t));
1357 
1358 	dev->d_node = (char *)my_zalloc(strlen(devnode) + 1);
1359 	(void) strcpy(dev->d_node, devnode);
1360 
1361 	dev->d_fd = fd;
1362 
1363 	dev->d_inq = (uchar_t *)my_zalloc(INQUIRY_DATA_LENGTH);
1364 
1365 	/* Turn on privileges. */
1366 	(void) __priv_bracket(PRIV_ON);
1367 	if (!inquiry(fd, dev->d_inq)) {
1368 		DPRINTF1("USCSI ioctl failed %d\n",
1369 		    uscsi_error);
1370 		free(dev->d_inq);
1371 		free(dev->d_node);
1372 		(void) close(dev->d_fd);
1373 		free(dev);
1374 		/* Turn off privileges. */
1375 		(void) __priv_bracket(PRIV_OFF);
1376 		return (NULL);
1377 	}
1378 	/* Turn off privileges. */
1379 	(void) __priv_bracket(PRIV_OFF);
1380 
1381 	if (user_supplied) {
1382 		dev->d_name = (char *)my_zalloc(strlen(user_supplied) + 1);
1383 		(void) strcpy(dev->d_name, user_supplied);
1384 	}
1385 	return (dev);
1386 }
1387 
1388 /*
1389  * Check for device specific characteristics.
1390  */
1391 int
1392 check_device(device_t *dev, int cond)
1393 {
1394 	uchar_t page_code[4];
1395 
1396 	/* Look at the capabilities page for this information */
1397 	if (cond & CHECK_DEVICE_IS_CD_WRITABLE) {
1398 		if (get_mode_page(dev->d_fd, 0x2a, 0, 4, page_code) &&
1399 		    (page_code[3] & 1)) {
1400 			return (1);
1401 		}
1402 	}
1403 
1404 	if (cond & CHECK_DEVICE_IS_DVD_WRITABLE) {
1405 		if (get_mode_page(dev->d_fd, 0x2a, 0, 4, page_code) &&
1406 		    (page_code[3] & 0x10)) {
1407 			return (1);
1408 		}
1409 	}
1410 
1411 	if (cond & CHECK_DEVICE_IS_DVD_READABLE) {
1412 		if (get_mode_page(dev->d_fd, 0x2a, 0, 4, page_code) &&
1413 		    (page_code[2] & 0x8)) {
1414 			return (1);
1415 		}
1416 	}
1417 
1418 	return (0);
1419 }
1420 
1421 /*
1422  * Builds an open()able device path from a user supplied node which can be
1423  * of the * form of /dev/[r]dsk/cxtxdx[sx] or cxtxdx[sx] or volmgt-name like
1424  * cdrom[n].
1425  * Returns the path found in 'found' and returns 1. Otherwise returns 0.
1426  */
1427 int
1428 lookup_device(char *supplied, char *found)
1429 {
1430 	struct stat statbuf;
1431 	int fd;
1432 	char tmpstr[PATH_MAX];
1433 
1434 	/* Turn on privileges */
1435 	(void) __priv_bracket(PRIV_ON);
1436 
1437 	/* If everything is fine and proper, no need to analyze */
1438 	if ((stat(supplied, &statbuf) == 0) && S_ISCHR(statbuf.st_mode) &&
1439 	    ((fd = open(supplied, O_RDONLY|O_NDELAY)) >= 0)) {
1440 		(void) close(fd);
1441 		(void) strlcpy(found, supplied, PATH_MAX);
1442 		/* Turn off privilege */
1443 		(void) __priv_bracket(PRIV_OFF);
1444 		return (1);
1445 	}
1446 
1447 	/* Turn off privileges. */
1448 	(void) __priv_bracket(PRIV_OFF);
1449 
1450 	if (strncmp(supplied, "/dev/rdsk/", 10) == 0)
1451 		return (vol_lookup(supplied, found));
1452 	if (strncmp(supplied, "/dev/dsk/", 9) == 0) {
1453 		(void) snprintf(tmpstr, PATH_MAX, "/dev/rdsk/%s",
1454 		    (char *)strrchr(supplied, '/'));
1455 
1456 		if ((fd = open(tmpstr, O_RDONLY|O_NDELAY)) >= 0) {
1457 			(void) close(fd);
1458 			(void) strlcpy(found, supplied, PATH_MAX);
1459 			return (1);
1460 		}
1461 		if ((access(tmpstr, F_OK) == 0) && vol_running)
1462 			return (vol_lookup(tmpstr, found));
1463 		else
1464 			return (0);
1465 	}
1466 	if ((strncmp(supplied, "cdrom", 5) != 0) &&
1467 	    (strlen(supplied) < 32)) {
1468 		(void) snprintf(tmpstr, sizeof (tmpstr), "/dev/rdsk/%s",
1469 		    supplied);
1470 		if (access(tmpstr, F_OK) < 0) {
1471 			(void) strcat(tmpstr, "s2");
1472 		}
1473 		if ((fd = open(tmpstr, O_RDONLY|O_NDELAY)) >= 0) {
1474 			(void) close(fd);
1475 			(void) strlcpy(found, tmpstr, PATH_MAX);
1476 			return (1);
1477 		}
1478 		if ((access(tmpstr, F_OK) == 0) && vol_running)
1479 			return (vol_lookup(tmpstr, found));
1480 	}
1481 	return (vol_name_to_dev_node(supplied, found));
1482 }
1483 
1484 int
1485 is_cd(char *node)
1486 {
1487 	int fd;
1488 	struct dk_cinfo cinfo;
1489 
1490 	fd = open(node, O_RDONLY|O_NDELAY);
1491 	if (fd < 0)
1492 		return (0);
1493 	if (ioctl(fd, DKIOCINFO, &cinfo) < 0) {
1494 		(void) close(fd);
1495 		return (0);
1496 	}
1497 	if (cinfo.dki_ctype != DKC_CDROM)
1498 		return (0);
1499 	return (1);
1500 }
1501 
1502 void
1503 print_header(void)
1504 {
1505 	/* l10n_NOTE : Column spacing should be kept same */
1506 	(void) printf(gettext("    Node			       "
1507 	    "Connected Device"));
1508 	/* l10n_NOTE : Column spacing should be kept same */
1509 	(void) printf(gettext("			Device type\n"));
1510 	(void) printf(
1511 	    "---------------------------+---------------------------");
1512 	(void) printf("-----+----------------\n");
1513 }
1514 
1515 void
1516 print_divider(void)
1517 {
1518 	(void) printf(
1519 	    "---------------------------+---------------------------");
1520 	(void) printf("-----+----------------\n");
1521 }
1522 
1523 static void
1524 fini_device(device_t *dev)
1525 {
1526 	free(dev->d_inq);
1527 	free(dev->d_node);
1528 	(void) close(dev->d_fd);
1529 	if (dev->d_name)
1530 		free(dev->d_name);
1531 	free(dev);
1532 }
1533 
1534 void *
1535 my_zalloc(size_t size)
1536 {
1537 	void *ret;
1538 
1539 	ret = malloc(size);
1540 	if (ret == NULL) {
1541 
1542 		/* Lets wait a sec. and try again */
1543 		if (errno == EAGAIN) {
1544 			(void) sleep(1);
1545 			ret = malloc(size);
1546 		}
1547 
1548 		if (ret == NULL) {
1549 			(void) err_msg("%s\n", gettext(strerror(errno)));
1550 			(void) err_msg(gettext(
1551 			    "Memory allocation failure, Exiting...\n"));
1552 			exit(1);
1553 		}
1554 	}
1555 	(void) memset(ret, 0, size);
1556 	return (ret);
1557 }
1558 
1559 static int
1560 vol_name_to_dev_node(char *vname, char *found)
1561 {
1562 	struct stat statbuf;
1563 	char *p1;
1564 	int i;
1565 
1566 	if (vname == NULL)
1567 		return (0);
1568 	if (vol_running)
1569 		(void) volmgt_check(vname);
1570 	p1 = media_findname(vname);
1571 	if (p1 == NULL)
1572 		return (0);
1573 	if (stat(p1, &statbuf) < 0) {
1574 		free(p1);
1575 		return (0);
1576 	}
1577 	if (S_ISDIR(statbuf.st_mode)) {
1578 		for (i = 0; i < 16; i++) {
1579 			(void) snprintf(found, PATH_MAX, "%s/s%d", p1, i);
1580 			if (access(found, F_OK) >= 0)
1581 				break;
1582 		}
1583 		if (i == 16) {
1584 			free(p1);
1585 			return (0);
1586 		}
1587 	} else {
1588 		(void) strlcpy(found, p1, PATH_MAX);
1589 	}
1590 	free(p1);
1591 	return (1);
1592 }
1593 
1594 /*
1595  * Searches for volume manager's equivalent char device for the
1596  * supplied pathname which is of the form of /dev/rdsk/cxtxdxsx
1597  */
1598 static int
1599 vol_lookup(char *supplied, char *found)
1600 {
1601 	char tmpstr[PATH_MAX], tmpstr1[PATH_MAX], *p;
1602 	int i, ret;
1603 
1604 	(void) strlcpy(tmpstr, supplied, PATH_MAX);
1605 	if ((p = volmgt_symname(tmpstr)) == NULL) {
1606 		if (strstr(tmpstr, "s2") != NULL) {
1607 			*((char *)(strrchr(tmpstr, 's') + 1)) = 0;
1608 			for (i = 0; i < 16; i++) {
1609 				(void) snprintf(tmpstr1, PATH_MAX, "%s%d",
1610 				    tmpstr, i);
1611 				if ((p = volmgt_symname(tmpstr1)) != NULL)
1612 					break;
1613 			}
1614 		} else if (strstr(tmpstr, "p0") != NULL) {
1615 			*((char *)(strrchr(tmpstr, 'p') + 1)) = 0;
1616 			for (i = 0; i < 5; i++) {
1617 				(void) snprintf(tmpstr1, PATH_MAX, "%s%d",
1618 				    tmpstr, i);
1619 				if ((p = volmgt_symname(tmpstr1)) != NULL)
1620 					break;
1621 			}
1622 		} else
1623 			return (0);
1624 		if (p == NULL)
1625 			return (0);
1626 	}
1627 
1628 	ret = vol_name_to_dev_node(p, found);
1629 	free(p);
1630 	return (ret);
1631 }
1632 
1633 /*PRINTFLIKE1*/
1634 void
1635 err_msg(char *fmt, ...)
1636 {
1637 	va_list ap;
1638 
1639 	va_start(ap, fmt);
1640 	(void) vfprintf(stderr, fmt, ap);
1641 	va_end(ap);
1642 }
1643 
1644 int
1645 inquiry(int fd, uchar_t *inq)
1646 {
1647 	struct uscsi_cmd *scmd;
1648 
1649 	scmd = get_uscsi_cmd();
1650 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
1651 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
1652 	scmd->uscsi_cdb[0] = INQUIRY_CMD;
1653 	scmd->uscsi_cdb[4] = INQUIRY_DATA_LENGTH;
1654 	scmd->uscsi_cdblen = 6;
1655 	scmd->uscsi_bufaddr = (char *)inq;
1656 	scmd->uscsi_buflen = INQUIRY_DATA_LENGTH;
1657 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
1658 		return (0);
1659 	return (1);
1660 }
1661 
1662 struct uscsi_cmd *
1663 get_uscsi_cmd(void)
1664 {
1665 	(void) memset(&uscmd, 0, sizeof (uscmd));
1666 	(void) memset(ucdb, 0, 16);
1667 	uscmd.uscsi_cdb = ucdb;
1668 	return (&uscmd);
1669 }
1670 
1671 int
1672 uscsi(int fd, struct uscsi_cmd *scmd)
1673 {
1674 	int ret, global_rqsense;
1675 	int retries, max_retries = 5;
1676 	int i;
1677 
1678 	/* set up for request sense extensions */
1679 	if (!(scmd->uscsi_flags & USCSI_RQENABLE)) {
1680 		scmd->uscsi_flags |= USCSI_RQENABLE;
1681 		scmd->uscsi_rqlen = RQBUFLEN;
1682 		scmd->uscsi_rqbuf = rqbuf;
1683 		global_rqsense = 1;
1684 	} else {
1685 		global_rqsense = 0;
1686 	}
1687 
1688 	/*
1689 	 * The device may be busy or slow and fail with a not ready status.
1690 	 * we'll allow a limited number of retries to give the drive time
1691 	 * to recover.
1692 	 */
1693 	for (retries = 0; retries < max_retries; retries++) {
1694 
1695 		scmd->uscsi_status = 0;
1696 
1697 		if (global_rqsense)
1698 			(void) memset(rqbuf, 0, RQBUFLEN);
1699 
1700 		DPRINTF("cmd:[");
1701 		for (i = 0; i < scmd->uscsi_cdblen; i++)
1702 			DPRINTF1("0x%02x ",
1703 			    (uchar_t)scmd->uscsi_cdb[i]);
1704 		DPRINTF("]\n");
1705 
1706 		/*
1707 		 * We need to have root privledges in order to use
1708 		 * uscsi commands on the device.
1709 		 */
1710 
1711 		ret = ioctl(fd, USCSICMD, scmd);
1712 
1713 		/* maintain consistency in case of sgen */
1714 		if ((ret == 0) && (scmd->uscsi_status == 2)) {
1715 			ret = -1;
1716 			errno = EIO;
1717 		}
1718 
1719 		/* if error and extended request sense, retrieve errors */
1720 		if (global_rqsense && (ret < 0) && (scmd->uscsi_status == 2)) {
1721 			/*
1722 			 * The drive is not ready to recieve commands but
1723 			 * may be in the process of becoming ready.
1724 			 * sleep for a short time then retry command.
1725 			 * SENSE/ASC = 2/4 : not ready
1726 			 * ASCQ = 0  Not Reportable.
1727 			 * ASCQ = 1  Becoming ready.
1728 			 */
1729 			if ((SENSE_KEY(rqbuf) == 2) && (ASC(rqbuf) == 4) &&
1730 			    ((ASCQ(rqbuf) == 0) || (ASCQ(rqbuf) == 1))) {
1731 				total_retries++;
1732 				(void) sleep(3);
1733 				continue;
1734 			}
1735 
1736 			/*
1737 			 * Device is not ready to transmit or a device reset
1738 			 * has occurred. wait for a short period of time then
1739 			 * retry the command.
1740 			 */
1741 			if ((SENSE_KEY(rqbuf) == 6) && ((ASC(rqbuf) == 0x28) ||
1742 			    (ASC(rqbuf) == 0x29))) {
1743 				(void) sleep(3);
1744 				total_retries++;
1745 				continue;
1746 			}
1747 
1748 			DPRINTF3("cmd: 0x%02x ret:%i status:%02x ",
1749 			    (uchar_t)scmd->uscsi_cdb[0], ret,
1750 			    scmd->uscsi_status);
1751 			DPRINTF3(" sense: %02x ASC: %02x ASCQ:%02x\n",
1752 			    (uchar_t)SENSE_KEY(rqbuf),
1753 			    (uchar_t)ASC(rqbuf), (uchar_t)ASCQ(rqbuf));
1754 		}
1755 
1756 		/* no errors we'll return */
1757 		break;
1758 	}
1759 
1760 	/* store the error status for later debug printing */
1761 	if ((ret < 0) && (global_rqsense)) {
1762 		uscsi_status = scmd->uscsi_status;
1763 		rqstatus = scmd->uscsi_rqstatus;
1764 		rqresid = scmd->uscsi_rqresid;
1765 
1766 	}
1767 
1768 	DPRINTF1("total retries: %d\n", total_retries);
1769 
1770 	return (ret);
1771 }
1772 
1773 /*
1774  * will get the mode page only i.e. will strip off the header.
1775  */
1776 int
1777 get_mode_page(int fd, int page_no, int pc, int buf_len, uchar_t *buffer)
1778 {
1779 	int ret;
1780 	uchar_t byte2, *buf;
1781 	uint_t header_len, page_len, copy_cnt;
1782 
1783 	byte2 = (uchar_t)(((pc << 6) & 0xC0) | (page_no & 0x3f));
1784 	buf = (uchar_t *)my_zalloc(256);
1785 
1786 	/* Ask 254 bytes only to make our IDE driver happy */
1787 	ret = mode_sense(fd, byte2, 1, 254, buf);
1788 	if (ret == 0) {
1789 		free(buf);
1790 		return (0);
1791 	}
1792 
1793 	header_len = 8 + read_scsi16(&buf[6]);
1794 	page_len = buf[header_len + 1] + 2;
1795 
1796 	copy_cnt = (page_len > buf_len) ? buf_len : page_len;
1797 	(void) memcpy(buffer, &buf[header_len], copy_cnt);
1798 	free(buf);
1799 
1800 	return (1);
1801 }
1802 
1803 int
1804 mode_sense(int fd, uchar_t pc, int dbd, int page_len, uchar_t *buffer)
1805 {
1806 	struct uscsi_cmd *scmd;
1807 
1808 	scmd = get_uscsi_cmd();
1809 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
1810 	scmd->uscsi_buflen = page_len;
1811 	scmd->uscsi_bufaddr = (char *)buffer;
1812 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
1813 	scmd->uscsi_cdblen = 0xa;
1814 	scmd->uscsi_cdb[0] = MODE_SENSE_10_CMD;
1815 	if (dbd) {
1816 		/* don't return any block descriptors */
1817 		scmd->uscsi_cdb[1] = 0x8;
1818 	}
1819 	/* the page code we want */
1820 	scmd->uscsi_cdb[2] = pc;
1821 	/* allocation length */
1822 	scmd->uscsi_cdb[7] = (page_len >> 8) & 0xff;
1823 	scmd->uscsi_cdb[8] = page_len & 0xff;
1824 
1825 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
1826 		return (0);
1827 	return (1);
1828 }
1829 
1830 uint16_t
1831 read_scsi16(void *addr)
1832 {
1833 	uchar_t *ad = (uchar_t *)addr;
1834 	uint16_t ret;
1835 
1836 	ret = ((((uint16_t)ad[0]) << 8) | ad[1]);
1837 	return (ret);
1838 }
1839 
1840 /*
1841  * Allocate space for and return a pointer to a string
1842  * on the stack.  If the string is null, create
1843  * an empty string.
1844  * Use destroy_data() to free when no longer used.
1845  */
1846 char *
1847 alloc_string(char *s)
1848 {
1849 	char    *ns;
1850 
1851 	if (s == (char *)NULL) {
1852 		ns = (char *)my_zalloc(1);
1853 	} else {
1854 		ns = (char *)my_zalloc(strlen(s) + 1);
1855 		(void) strcpy(ns, s);
1856 	}
1857 	return (ns);
1858 }
1859 
1860 /*
1861  * Follow symbolic links from the logical device name to
1862  * the /devfs physical device name.  To be complete, we
1863  * handle the case of multiple links.  This function
1864  * either returns NULL (no links, or some other error),
1865  * or the physical device name, alloc'ed on the heap.
1866  *
1867  * Note that the standard /devices prefix is stripped from
1868  * the final pathname, if present.  The trailing options
1869  * are also removed (":c, raw").
1870  */
1871 static char *
1872 get_physical_name(char *path)
1873 {
1874 	struct stat	stbuf;
1875 	int		i;
1876 	int		level;
1877 	char		*p;
1878 	char		s[MAXPATHLEN];
1879 	char		buf[MAXPATHLEN];
1880 	char		dir[MAXPATHLEN];
1881 	char		savedir[MAXPATHLEN];
1882 	char		*result = NULL;
1883 
1884 	if (getcwd(savedir, sizeof (savedir)) == NULL) {
1885 		DPRINTF1("getcwd() failed - %s\n", strerror(errno));
1886 		return (NULL);
1887 	}
1888 
1889 	(void) strcpy(s, path);
1890 	if ((p = strrchr(s, '/')) != NULL) {
1891 		*p = 0;
1892 	}
1893 	if (s[0] == 0) {
1894 		(void) strcpy(s, "/");
1895 	}
1896 	if (chdir(s) == -1) {
1897 		DPRINTF2("cannot chdir() to %s - %s\n",
1898 		    s, strerror(errno));
1899 		goto exit;
1900 	}
1901 
1902 	level = 0;
1903 	(void) strcpy(s, path);
1904 	for (;;) {
1905 		/*
1906 		 * See if there's a real file out there.  If not,
1907 		 * we have a dangling link and we ignore it.
1908 		 */
1909 		if (stat(s, &stbuf) == -1) {
1910 			goto exit;
1911 		}
1912 		if (lstat(s, &stbuf) == -1) {
1913 			DPRINTF2("%s: lstat() failed - %s\n",
1914 			    s, strerror(errno));
1915 			goto exit;
1916 		}
1917 		/*
1918 		 * If the file is not a link, we're done one
1919 		 * way or the other.  If there were links,
1920 		 * return the full pathname of the resulting
1921 		 * file.
1922 		 */
1923 		if (!S_ISLNK(stbuf.st_mode)) {
1924 			if (level > 0) {
1925 				/*
1926 				 * Strip trailing options from the
1927 				 * physical device name
1928 				 */
1929 				if ((p = strrchr(s, ':')) != NULL) {
1930 					*p = 0;
1931 				}
1932 				/*
1933 				 * Get the current directory, and
1934 				 * glue the pieces together.
1935 				 */
1936 				if (getcwd(dir, sizeof (dir)) == NULL) {
1937 					DPRINTF1("getcwd() failed - %s\n",
1938 					    strerror(errno));
1939 					goto exit;
1940 				}
1941 				(void) strcat(dir, "/");
1942 				(void) strcat(dir, s);
1943 				/*
1944 				 * If we have the standard fixed
1945 				 * /devices prefix, remove it.
1946 				 */
1947 				p = (strstr(dir, DEVFS_PREFIX) == dir) ?
1948 				    dir+strlen(DEVFS_PREFIX) : dir;
1949 				result = alloc_string(p);
1950 			}
1951 			goto exit;
1952 		}
1953 		i = readlink(s, buf, sizeof (buf));
1954 		if (i == -1) {
1955 			DPRINTF2("%s: readlink() failed - %s\n",
1956 			    s, strerror(errno));
1957 			goto exit;
1958 		}
1959 		level++;
1960 		buf[i] = 0;
1961 
1962 		/*
1963 		 * Break up the pathname into the directory
1964 		 * reference, if applicable and simple filename.
1965 		 * chdir()'ing to the directory allows us to
1966 		 * handle links with relative pathnames correctly.
1967 		 */
1968 		(void) strcpy(dir, buf);
1969 		if ((p = strrchr(dir, '/')) != NULL) {
1970 			*p = 0;
1971 			if (chdir(dir) == -1) {
1972 				DPRINTF2("cannot chdir() to %s - %s\n",
1973 				    dir, strerror(errno));
1974 				goto exit;
1975 			}
1976 			(void) strcpy(s, p+1);
1977 		} else {
1978 			(void) strcpy(s, buf);
1979 		}
1980 	}
1981 
1982 exit:
1983 	if (chdir(savedir) == -1) {
1984 		(void) printf("cannot chdir() to %s - %s\n",
1985 		    savedir, strerror(errno));
1986 	}
1987 
1988 	return (result);
1989 }
1990 
1991 static void
1992 get_media_info(device_t *t_dev, char *sdev, char *pname, char *sn)
1993 {
1994 	struct dk_cinfo cinfo;
1995 	struct extvtoc vtocinfo;
1996 	float size;
1997 	int32_t fd;
1998 	smedia_handle_t handle;
1999 	struct dk_minfo mediainfo;
2000 	int device_type;
2001 
2002 	device_type = ioctl(t_dev->d_fd, DKIOCGMEDIAINFO, &mediainfo);
2003 
2004 	/*
2005 	 * Determine bus type.
2006 	 */
2007 	if (!ioctl(t_dev->d_fd, DKIOCINFO, &cinfo)) {
2008 		if (strstr(cinfo.dki_cname, "usb") || strstr(pname, "usb")) {
2009 			(void) printf("\tBus: USB\n");
2010 		} else if (strstr(cinfo.dki_cname, "firewire") ||
2011 		    strstr(pname, "firewire")) {
2012 			(void) printf("\tBus: Firewire\n");
2013 		} else if (strstr(cinfo.dki_cname, "ide") ||
2014 		    strstr(pname, "ide")) {
2015 			(void) printf("\tBus: IDE\n");
2016 		} else if (strstr(cinfo.dki_cname, "scsi") ||
2017 		    strstr(pname, "scsi")) {
2018 			(void) printf("\tBus: SCSI\n");
2019 		} else {
2020 			(void) printf("\tBus: <Unknown>\n");
2021 		}
2022 	} else {
2023 		(void) printf("\tBus: <Unknown>\n");
2024 	}
2025 
2026 	/*
2027 	 * Calculate size of media.
2028 	 */
2029 	if (!device_type &&
2030 	    (!ioctl(t_dev->d_fd, DKIOCGMEDIAINFO, &mediainfo))) {
2031 		size = (mediainfo.dki_lbsize*
2032 		    mediainfo.dki_capacity)/(1024.0*1024.0);
2033 		if (size < 1000) {
2034 			(void) printf("\tSize: %.1f MB\n", size);
2035 		} else {
2036 			size = size/1000;
2037 			(void) printf("\tSize: %.1f GB\n", size);
2038 		}
2039 	} else {
2040 		(void) printf("\tSize: <Unknown>\n");
2041 	}
2042 
2043 	/*
2044 	 * Print label.
2045 	 */
2046 	if (!device_type && (read_extvtoc(t_dev->d_fd,  &vtocinfo) >= 0)) {
2047 		if (*vtocinfo.v_volume) {
2048 			(void) printf("\tLabel: %s\n", vtocinfo.v_volume);
2049 		} else {
2050 			(void) printf("\tLabel: <None>\n");
2051 		}
2052 	} else {
2053 		(void) printf("\tLabel: <Unknown>\n");
2054 	}
2055 
2056 	/*
2057 	 * Acess permissions.
2058 	 */
2059 	if (device_type) {
2060 		(void) printf("\tAccess permissions: <Unknown>\n");
2061 		return;
2062 	}
2063 
2064 	(void) fprintf(stdout, gettext("\tAccess permissions: "));
2065 	if (sn) {
2066 		/*
2067 		 * Set dev_name for process_p_flag().
2068 		 */
2069 		dev_name = sn;
2070 		fd = my_open(sn, O_RDONLY|O_NDELAY);
2071 	} else {
2072 		dev_name = sdev;
2073 		fd = my_open(sdev, O_RDONLY|O_NDELAY);
2074 	}
2075 	if (fd < 0)  {
2076 		(void) printf("<Unknown>\n");
2077 		DPRINTF("Could not open device.\n");
2078 		(void) close(fd);
2079 	} else {
2080 		/* register the fd with the libsmedia */
2081 		handle = smedia_get_handle(fd);
2082 		if (handle == NULL) {
2083 			(void) printf("<Unknown>\n");
2084 			DPRINTF("Failed to get libsmedia handle.\n");
2085 			(void) close(fd);
2086 		} else {
2087 			process_p_flag(handle, fd);
2088 		}
2089 	}
2090 	/* Clear dev_name */
2091 	dev_name = NULL;
2092 }
2093