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 }