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