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