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