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