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