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