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