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