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