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