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