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_slice.c :
  30  *      This file contains the functions for parsing a slice file
  31  *      for rmformat.
  32  */
  33 
  34 #include <sys/types.h>
  35 #include <ctype.h>
  36 #include <sys/vtoc.h>
  37 #include <stdlib.h>
  38 #include <unistd.h>
  39 #include <string.h>
  40 #include <fcntl.h>
  41 #include <errno.h>
  42 #include <memory.h>
  43 #include <dirent.h>
  44 #include <sys/fcntl.h>
  45 #include <sys/param.h>
  46 #include <sys/stat.h>
  47 #include <stdio.h>
  48 #include <sys/dkio.h>
  49 #include <priv_utils.h>
  50 #include "rmformat.h"
  51 
  52 extern void my_perror(char *err_string);
  53 
  54 static int32_t  last_token_type = 0;
  55 #define spc()     (last_token_type)
  56 
  57 
  58 /*
  59  * This global is used to store the current line # in the
  60  * data file. It must be global because the I/O routines
  61  * are allowed to side effect it to keep track of backslashed
  62  * newlines.
  63  */
  64 
  65 static int32_t  data_lineno;            /* current line # in data file */
  66 
  67 #define CHG_MODE_UNDEFINED  (-1)        /* undefined value */
  68 #define CHG_MODE_SET    0               /* set bits by or'ing */
  69 #define CHG_MODE_CLR    1               /* clr bits by and'ing */
  70 #define CHG_MODE_ABS    2               /* set absolute value */
  71 
  72 
  73 #define TOKEN_SIZE      36              /* max length of a token */
  74 typedef char TOKEN[TOKEN_SIZE+1];       /* token type */
  75 #define DATA_INPUT      0               /* 2 modes of input */
  76 #define CMD_INPUT       1
  77 #define WILD_STRING     "$"             /* wildcard character */
  78 #define COMMENT_CHAR    '#'             /* comment character */
  79 
  80 /*
  81  * List of strings with arbitrary matching values
  82  */
  83 typedef struct slist {
  84         char    *str;
  85         char    *help;
  86         int32_t value;
  87 } slist_t;
  88 
  89 static slist_t ptag_choices[] = {
  90         { "unassigned", "",     V_UNASSIGNED    },
  91         { "boot",       "",     V_BOOT          },
  92         { "root",       "",     V_ROOT          },
  93         { "swap",       "",     V_SWAP          },
  94         { "usr",        "",     V_USR           },
  95         { "backup",     "",     V_BACKUP        },
  96         { "stand",      "",     V_STAND         },
  97         { "var",        "",     V_VAR           },
  98         { "home",       "",     V_HOME          },
  99         { "alternates", "",     V_ALTSCTR       },
 100         { NULL }
 101 };
 102 
 103 
 104 /*
 105  * Choices for the p_flag vtoc field
 106  */
 107 static slist_t pflag_choices[] = {
 108         { "wm", "read-write, mountable",        0       },
 109         { "wu", "read-write, unmountable",      V_UNMNT },
 110         { "rm", "read-only, mountable",         V_RONLY },
 111         { "ru", "read-only, unmountable",       V_RONLY|V_UNMNT },
 112         { NULL }
 113 };
 114 
 115 /*
 116  * The definitions are the token types that the data file parser recognizes.
 117  */
 118 #define SUP_EOF                 -1              /* eof token */
 119 #define SUP_STRING              0               /* string token */
 120 #define SUP_EQL                 1               /* equals token */
 121 #define SUP_COMMA               2               /* comma token */
 122 #define SUP_COLON               3               /* colon token */
 123 #define SUP_EOL                 4               /* newline token */
 124 #define SUP_OR                  5               /* vertical bar */
 125 #define SUP_AND                 6               /* ampersand */
 126 #define SUP_TILDE               7               /* tilde */
 127 
 128 
 129 /*
 130  *      Prototypes for ANSI C compilers
 131  */
 132 static int32_t  sup_prxfile(char *file_name, struct extvtoc *vt);
 133 static int32_t  sup_setpart(struct extvtoc *vt);
 134 static void     sup_pushchar(int32_t c);
 135 static void     clean_token(char *cleantoken, char *token);
 136 static void clean_token(char *cleantoken, char *token);
 137 static int32_t sup_inputchar();
 138 static int32_t sup_gettoken(char *buf);
 139 static int32_t sup_get_token(char *buf);
 140 static int32_t find_value(slist_t *slist, char *str, int32_t *value);
 141 static int32_t check_vtoc_sanity(smedia_handle_t, int32_t fd,
 142                 struct extvtoc *vt);
 143 static uint64_t str2sector(char *str);
 144 static int32_t strcnt(char *s1, char *s2);
 145 static int32_t get_fdisk(smedia_handle_t, int32_t fd, int32_t offset,
 146                 struct fdisk_info *fdisk);
 147 static void erase(smedia_handle_t handle, diskaddr_t offset, diskaddr_t size);
 148 
 149 extern char *myname;
 150 extern uint64_t my_atoll(char *ptr);
 151 extern smmedium_prop_t med_info;
 152 
 153 static FILE *data_file;
 154 
 155 static int32_t
 156 sup_prxfile(char *file_name, struct extvtoc *vt)
 157 {
 158         int32_t status, ret_val;
 159         TOKEN   token;
 160         TOKEN   cleaned;
 161 
 162         /*
 163          * Open the data file.  Return 0 if unable to do so.
 164          */
 165         data_file = fopen(file_name, "r");
 166         if (data_file == NULL) {
 167                 PERROR("Open failed");
 168                 return (-1);
 169         }
 170         /*
 171          * Step through the data file a meta-line at a time.  There are
 172          * typically several backslashed newlines in each meta-line,
 173          * so data_lineno will be getting side effected along the way.
 174          */
 175         data_lineno = 1;
 176         for (;;) {
 177 
 178                 /*
 179                  * Get the keyword.
 180                  */
 181                 status = sup_gettoken(token);
 182                 /*
 183                  * If we hit the end of the data file, we're done.
 184                  */
 185                 if (status == SUP_EOF)
 186                         break;
 187                 /*
 188                  * If the line starts with some key character, it's an error.
 189                  */
 190                 if (status != SUP_STRING) {
 191                         (void) fprintf(stderr,
 192                             gettext("Expecting keyword, found '%s'"),
 193                             token);
 194                         (void) fprintf(stderr,
 195                             gettext("Line no %d\n"), data_lineno);
 196                         continue;
 197                 }
 198                 /*
 199                  * Clean up the token and see which keyword it is.  Call
 200                  * the appropriate routine to process the rest of the line.
 201                  */
 202                 clean_token(cleaned, token);
 203                 if (strcmp(cleaned, "slices") == 0) {
 204                         ret_val = sup_setpart(vt);
 205                         (void) fclose(data_file);
 206                         return (ret_val);
 207                 } else {
 208                         (void) fprintf(stderr, gettext("Unknown keyword '%s'"),
 209                             cleaned);
 210                         (void) fprintf(stderr,
 211                             gettext("Line no %d\n"), data_lineno);
 212                         (void) fclose(data_file);
 213                         return (-1);
 214                 }
 215         }
 216         /*
 217          * Close the data file.
 218          */
 219         (void) fclose(data_file);
 220 
 221         (void) fprintf(stderr,
 222             gettext("Unexpected end of file (line no %d)\n"), data_lineno);
 223         return (-1);
 224 }
 225 
 226 static int32_t
 227 sup_gettoken(char *buf)
 228 {
 229         /*
 230          * Skip end of lines and blank lines.
 231          */
 232         while ((last_token_type = sup_get_token(buf)) == SUP_EOL)
 233                         ;
 234         return (last_token_type);
 235 }
 236 
 237 static int32_t
 238 sup_get_token(char *buf)
 239 {
 240         char    *ptr = buf;
 241         int32_t c, quoted = 0;
 242 
 243         /*
 244          * Was an end of file detected last try?
 245          */
 246 
 247         if (feof(data_file)) {
 248                 return (SUP_EOF);
 249         }
 250 
 251         /*
 252          * Zero out the returned token buffer
 253          */
 254 
 255         bzero(buf, TOKEN_SIZE + 1);
 256 
 257         /*
 258          * Strip off leading white-space.
 259          */
 260         while (isspace(c = sup_inputchar()))
 261                 ;
 262 
 263         /*
 264          * Only white spaces and then end of file?
 265          */
 266 
 267         if (feof(data_file)) {
 268                 return (SUP_EOF);
 269         }
 270 
 271         /*
 272          * Read in characters until we hit unquoted white-space.
 273          */
 274         for (; !isspace(c) || quoted; c = sup_inputchar()) {
 275 
 276                 /*
 277                  * If we hit eof, check if we have anything in buffer.
 278                  * if we have, return STRING, next time we will return EOF
 279                  * else, return EOF here...should not happen.
 280                  */
 281                 if (feof(data_file)) {
 282                         if (ptr - buf > 0) {
 283                                 return (SUP_STRING);
 284                         } else {
 285                                 return (SUP_EOF);
 286                         }
 287                 }
 288 
 289                 /*
 290                  * If we hit a double quote, change the state of quoting.
 291                  */
 292                 if (c == '"') {
 293                         quoted = !quoted;
 294                         continue;
 295                 }
 296                 /*
 297                  * If we hit a newline, that delimits a token.
 298                  */
 299                 if (c == '\n')
 300                         break;
 301                 /*
 302                  * If we hit any nonquoted special delimiters, that delimits
 303                  * a token.
 304                  */
 305                 if (!quoted && (c == '=' || c == ',' || c == ':' ||
 306                     c == '#' || c == '|' || c == '&' || c == '~'))
 307                                 break;
 308                 /*
 309                  * Store the character if there's room left.
 310                  */
 311                 if (ptr - buf < TOKEN_SIZE)
 312                         *ptr++ = (char)c;
 313         }
 314         /*
 315          * If we stored characters in the buffer, then we inputted a string.
 316          * Push the delimiter back into the pipe and return the string.
 317          */
 318         if (ptr - buf > 0) {
 319                 sup_pushchar(c);
 320                 return (SUP_STRING);
 321         }
 322         /*
 323          * We didn't input a string, so we must have inputted a known delimiter.
 324          * store the delimiter in the buffer, so it will get returned.
 325          */
 326         buf[0] = c;
 327         /*
 328          * Switch on the delimiter.  Return the appropriate value for each one.
 329          */
 330         switch (c) {
 331         case '=':
 332                 return (SUP_EQL);
 333         case ':':
 334                 return (SUP_COLON);
 335         case ',':
 336                 return (SUP_COMMA);
 337         case '\n':
 338                 return (SUP_EOL);
 339         case '|':
 340                 return (SUP_OR);
 341         case '&':
 342                 return (SUP_AND);
 343         case '~':
 344                 return (SUP_TILDE);
 345         case '#':
 346                 /*
 347                  * For comments, we flush out the rest of the line and return
 348                  * an eol.
 349                  */
 350                 while ((c = sup_inputchar()) != '\n' && !feof(data_file))
 351                         ;
 352                 if (feof(data_file))
 353                         return (SUP_EOF);
 354                 else
 355                         return (SUP_EOL);
 356         /*
 357          * Shouldn't ever get here.
 358          */
 359         default:
 360                 return (SUP_STRING);
 361         }
 362 }
 363 static int32_t
 364 sup_inputchar()
 365 {
 366         int32_t c;
 367 
 368         /*
 369          * Input the character.
 370          */
 371         c = getc(data_file);
 372         /*
 373          * If it's not a backslash, return it.
 374          */
 375 
 376         /*
 377          * It was a backslash.  Get the next character.
 378          */
 379 
 380         if (c == '\\')
 381                 c = getc(data_file);
 382 
 383         /*
 384          * If it was a newline, update the line counter and get the next
 385          * character.
 386          */
 387         if (c == '\n') {
 388                 data_lineno++;
 389         }
 390         /*
 391          * Return the character.
 392          */
 393         return (c);
 394 }
 395 
 396 static void
 397 sup_pushchar(int32_t c)
 398 {
 399 
 400         (void) ungetc(c, data_file);
 401         if (c == '\n')
 402                 data_lineno--;
 403 }
 404 
 405 static void
 406 clean_token(char *cleantoken, char *token)
 407 {
 408         char    *ptr;
 409 
 410         /*
 411          * Strip off leading white-space.
 412          */
 413         for (ptr = token; isspace(*ptr) && (ptr <=
 414             (token + strlen(token) - 1)); ptr++)
 415                 ;
 416 
 417         /*
 418          * Copy it into the clean buffer.
 419          */
 420         (void) strcpy(cleantoken, ptr);
 421         /*
 422          * Strip off trailing white-space.
 423          */
 424         for (ptr = cleantoken + strlen(cleantoken) - 1;
 425             isspace(*ptr) && (ptr >= cleantoken); ptr--) {
 426                 *ptr = '\0';
 427         }
 428 }
 429 
 430 static int32_t
 431 sup_setpart(struct extvtoc *vt)
 432 {
 433         TOKEN   token, cleaned, ident;
 434         int32_t i, index, status;
 435         uint64_t        val1, val2;
 436         ushort_t        vtoc_tag = 0xFFFF;
 437         ushort_t        vtoc_flag = 0xFFFF;
 438 
 439         /*
 440          * Pull in some grammar.
 441          */
 442 
 443                 status = sup_gettoken(token);
 444 
 445                 if (status != SUP_COLON) {
 446                         (void) fprintf(stderr,
 447                             gettext("Expecting ':', found '%s'"), token);
 448                         (void) fprintf(stderr,
 449                             gettext("Line no %d\n"), data_lineno);
 450                         return (-1);
 451                 }
 452 
 453         for (;;) {
 454                 status = sup_gettoken(token);
 455                 if (status != SUP_STRING) {
 456                         (void) fprintf(stderr,
 457                             gettext("Expecting string, found '%s'"), token);
 458                         (void) fprintf(stderr,
 459                             gettext("Line no %d\n"), data_lineno);
 460                         return (-1);
 461                 }
 462                 clean_token(ident, token);
 463                 /*
 464                  * Here's the index of the partition we're dealing with
 465                  */
 466                 index = (int32_t)my_atoll(ident);
 467                 if ((index < 0) || (index >= NDKMAP)) {
 468                         (void) fprintf(stderr,
 469                             gettext("Unknown partition %d"), index);
 470                         (void) fprintf(stderr,
 471                             gettext("Line no %d\n"), data_lineno);
 472                         return (-1);
 473                 }
 474                 /*
 475                  * Check for floppy and PCMCIA_MEM cards.
 476                  * for floppy, the partition no. can be 0 1 2.
 477                  * for PCMCIA, the partition no. can be 2
 478                  */
 479                 if (med_info.sm_media_type == SM_FLOPPY) {
 480                         if ((index < 0) || (index > 2)) {
 481                                 (void) fprintf(stderr, gettext(
 482                         "Floppy can have partitions 0 1 and 2\n"));
 483                                 return (-1);
 484                         }
 485                 }
 486                 if (med_info.sm_media_type == SM_PCMCIA_MEM) {
 487                         if (index != 2) {
 488                                 (void) fprintf(stderr, gettext(
 489                         "PCMCIA Memory cards can have partition 2 only.\n"));
 490                                 return (-1);
 491                         }
 492                 }
 493 
 494                 DPRINTF1("\n Partition %d: ", index);
 495 
 496                 status = sup_gettoken(token);
 497                 if (status != SUP_EQL) {
 498                         (void) fprintf(stderr,
 499                             gettext("Expecting '=', found '%s'"), token);
 500                         (void) fprintf(stderr,
 501                             gettext("Line no %d\n"), data_lineno);
 502                         return (-1);
 503 
 504                 }
 505 
 506 
 507                 status = sup_gettoken(token);
 508                 /*
 509                  * If we hit a key character, it's an error.
 510                  */
 511                 if (status != SUP_STRING) {
 512                         (void) fprintf(stderr,
 513                             gettext("Expecting value, found '%s'"), token);
 514                         (void) fprintf(stderr,
 515                             gettext("Line no %d\n"), data_lineno);
 516                         return (-1);
 517                 }
 518                 clean_token(cleaned, token);
 519                 /*
 520                  * <tag> may be one of: boot, root, swap, etc.
 521                  * <flag> consists of two characters:
 522                  *      W (writable) or R (read-only)
 523                  *      M (mountable) or U (unmountable)
 524                  *
 525                  * Start with the defaults assigned above:
 526                  */
 527 
 528                 /*
 529                  * All other attributes have a pair of numeric values.
 530                  * Convert the first value to a number.  This value
 531                  * is the starting cylinder number of the partition.
 532                  */
 533 
 534                 /* Check for valid partition, e.g. > 8 or 16 */
 535                 val1 = str2sector(cleaned);
 536                 if (val1 == -1) {
 537                         (void) fprintf(stderr,
 538                             gettext("Invalid partition beggining %s \n"),
 539                             cleaned);
 540                         (void) fprintf(stderr,
 541                             gettext("Line no %d\n"), data_lineno);
 542                 }
 543 
 544                 DPRINTF1(" begins %s", cleaned);
 545                 /*
 546                  * Pull in some grammar.
 547                  */
 548                 status = sup_gettoken(token);
 549                 if (status != SUP_COMMA) {
 550                         (void) fprintf(stderr,
 551                             gettext("Expecting ', ', found '%s'"), token);
 552                         (void) fprintf(stderr,
 553                             gettext("Line no %d\n"), data_lineno);
 554                         return (-1);
 555                 }
 556                 /*
 557                  * Pull in the second value.
 558                  */
 559                 status = sup_gettoken(token);
 560                 if (status != SUP_STRING) {
 561                         (void) fprintf(stderr,
 562                             gettext("Expecting value, found '%s'"), token);
 563                         (void) fprintf(stderr,
 564                             gettext("Line no %d\n"), data_lineno);
 565                         return (-1);
 566                 }
 567                 clean_token(cleaned, token);
 568 
 569                 val2 = str2sector(cleaned);
 570                 if (val2 == -1) {
 571                         (void) fprintf(stderr,
 572                             gettext("Invalid partition size %s \n"),
 573                             cleaned);
 574                         (void) fprintf(stderr,
 575                             gettext("Line no %d\n"), data_lineno);
 576                 }
 577                 DPRINTF1(" ends %s ", cleaned);
 578 
 579                 /*
 580                  * Pull in some grammar.
 581                  */
 582                 status = sup_gettoken(token);
 583 
 584                 if (status == SUP_COMMA) {
 585                         /* tags and flags  */
 586                         status = sup_gettoken(token);
 587                         if (status != SUP_STRING) {
 588                                 (void) fprintf(stderr,
 589                                     gettext("Expecting value, found '%s'"),
 590                                     token);
 591                                 (void) fprintf(stderr,
 592                                     gettext("Line no %d\n"), data_lineno);
 593                                 return (-1);
 594                         }
 595                         clean_token(cleaned, token);
 596                         if (find_value(pflag_choices, cleaned, &i) == 1) {
 597                                 /*
 598                                  * Found valid tag. Use it and advance parser
 599                                  */
 600                                 DPRINTF1(" flag = %s", cleaned);
 601                                 vtoc_flag = (ushort_t)i;
 602                                 status = sup_gettoken(token);
 603                         } else if (find_value(ptag_choices, cleaned, &i) == 1) {
 604                                 DPRINTF1(" tag = %s", cleaned);
 605                                 vtoc_tag = (ushort_t)i;
 606                                 status = sup_gettoken(token);
 607                                 if (status == SUP_COMMA) {
 608                                         (void) fprintf(stderr,
 609                                             gettext("Expecting : got %s\n"),
 610                                             token);
 611                                         (void) fprintf(stderr,
 612                                             gettext("Line no %d\n"),
 613                                             data_lineno);
 614                                         return (-1);
 615                                 }
 616                         } else {
 617                                 (void) fprintf(stderr,
 618                                     gettext("Invalid flag or tag\n"));
 619                                 (void) fprintf(stderr,
 620                                     gettext("Line no %d\n"), data_lineno);
 621                                 return (-1);
 622                         }
 623 
 624 
 625                         if (status == SUP_COMMA) {
 626                                         /* Can be tag only */
 627 
 628                                         status = sup_gettoken(token);
 629                                         if (status != SUP_STRING) {
 630                                                 (void) fprintf(stderr,
 631                                                     gettext("Expecting value"
 632                                                     ", found '%s'"),
 633                                                     token);
 634                                                 (void) fprintf(stderr,
 635                                                     gettext("Line no %d\n"),
 636                                                     data_lineno);
 637                                                 return (-1);
 638                                         }
 639 
 640                                         clean_token(cleaned, token);
 641                                         if (find_value(ptag_choices,
 642                                             cleaned, &i) == 1) {
 643                                                 DPRINTF1(" tag = %s", cleaned);
 644                                                 vtoc_tag = (ushort_t)i;
 645                                         }
 646                         status = sup_gettoken(token);
 647                         }
 648                 }
 649 
 650                 /*
 651                  * Fill in the appropriate map entry with the values.
 652                  */
 653                 vt->v_part[index].p_start = val1;
 654                 vt->v_part[index].p_size = val2;
 655                 if (vtoc_tag != 0xFFFF) {
 656                         vt->v_part[index].p_tag = vtoc_tag;
 657                         vtoc_tag = 0xFFFF;
 658                 }
 659                 if (vtoc_flag != 0xFFFF) {
 660                         vt->v_part[index].p_flag = vtoc_flag;
 661                         vtoc_flag = 0xFFFF;
 662                 }
 663                 if (status == SUP_EOF) {
 664                         DPRINTF("\nEnd of file\n");
 665                         break;
 666                 }
 667                 if (status != SUP_COLON) {
 668                         (void) fprintf(stderr,
 669                             gettext("Expecting ':', found '%s'"), token);
 670                         (void) fprintf(stderr,
 671                             gettext("Line no %d\n"), data_lineno);
 672                         return (-1);
 673                 }
 674 
 675         }
 676         return (0);
 677 }
 678 
 679 static int32_t
 680 find_value(slist_t *slist, char *match_str, int32_t *match_value)
 681 {
 682         int32_t i;
 683         int32_t nmatches;
 684         int32_t length;
 685         int32_t match_length;
 686 
 687         nmatches = 0;
 688         length = 0;
 689 
 690         match_length = strlen(match_str);
 691 
 692         for (; slist->str != NULL; slist++) {
 693                 /*
 694                  * See how many characters of the token match
 695                  */
 696                 i = strcnt(match_str, slist->str);
 697                 /*
 698                  * If it's not the whole token, then it's not a match.
 699                  */
 700                 if (i  < match_length) {
 701                         continue;
 702                 }
 703                 /*
 704                  * If it ties with another input, remember that.
 705                  */
 706                 if (i == length)
 707                         nmatches++;
 708                 /*
 709                  * If it matches the most so far, record that.
 710                  */
 711                 if (i > length) {
 712                         *match_value = slist->value;
 713                         nmatches = 1;
 714                         length = i;
 715                 }
 716         }
 717 
 718         return (nmatches);
 719 }
 720 
 721 static int32_t
 722 strcnt(char     *s1, char *s2)
 723 {
 724         int32_t i = 0;
 725 
 726         while ((*s1 != '\0') && (*s1++ == *s2++))
 727                 i++;
 728         return (i);
 729 }
 730 
 731 static uint64_t
 732 str2sector(char *str)
 733 {
 734         int32_t mul_factor = 1;
 735         char *s1, *s2, *base;
 736         uint64_t num_sectors;
 737         uint64_t size;
 738 
 739         base = s2 = (char *)malloc(strlen(str) + 1);
 740         if (s2 == NULL) {
 741                 PERROR("Malloc failed");
 742                 return (-1);
 743         }
 744         *s2 = '\0';
 745 
 746 
 747 
 748         s1 = str;
 749         while (*s1) {
 750                 if ((*s1 != 'x') && ((*s1 < 'A') || (*s1 > 'F')) &&
 751                     ((*s1 < 'a') || (*s1 > 'f')) && ((*s1 < '0') ||
 752                     (*s1 > '9'))) {
 753                         if (*s1 == 'G') {
 754                                         mul_factor = 1024*1024*1024;
 755                                         s1++;
 756                         } else if (*s1 == 'M') {
 757                                         mul_factor = 1024*1024;
 758                                         s1++;
 759                         } else if (*s1 == 'K') {
 760                                         mul_factor = 1024;
 761                                         s1++;
 762                         }
 763                         if ((*s1 != 'B') || (*(++s1) != NULL)) {
 764                                 (void) fprintf(stderr,
 765                                     gettext("Extra chars at the end\n"));
 766                                 free(base);
 767                                 return (-1);
 768                         }
 769                         break;
 770                 } else {
 771                         *s2++ = *s1++;
 772                         *s2 = '\0';
 773                 }
 774         }
 775         *s2 = NULL;
 776 
 777         size = my_atoll(base);
 778         if ((!mul_factor) || (size == -1)) {
 779                 free(base);
 780                 return (-1);
 781         }
 782         num_sectors = size * (uint64_t)mul_factor /512;
 783 
 784         free(base);
 785         return (num_sectors);
 786 }
 787 
 788 
 789 int32_t
 790 valid_slice_file(smedia_handle_t handle, int32_t fd, char *file_name,
 791         struct extvtoc *vt)
 792 {
 793         struct stat status;
 794         int32_t ret_val;
 795         if (stat(file_name, &status)) {
 796                 PERROR(file_name);
 797                 return (-1);
 798         }
 799         (void) memset(vt, 0, sizeof (*vt));
 800         /* Set default tag and flag */
 801 #ifdef sparc
 802         vt->v_part[0].p_tag = V_ROOT;
 803         vt->v_part[1].p_tag = V_SWAP;
 804         vt->v_part[2].p_tag = V_BACKUP;
 805         vt->v_part[6].p_tag = V_USR;
 806 
 807         vt->v_part[1].p_flag = V_UNMNT; /* Unmountable */
 808         vt->v_part[2].p_flag = V_UNMNT; /* Unmountable */
 809 #endif
 810 
 811         ret_val = sup_prxfile(file_name, vt);
 812         if (ret_val < 0)
 813                 return (-1);
 814 
 815 #ifdef DEBUG
 816 {
 817         int32_t i;
 818         for (i = 0; i < 8; i++) {
 819                 DPRINTF1("\npart %d\n", i);
 820                 DPRINTF1("\t start %llu",  vt->v_part[i].p_start);
 821                 DPRINTF1("\t size %llu ", vt->v_part[i].p_size);
 822                 DPRINTF1("\t tag %d", vt->v_part[i].p_tag);
 823                 DPRINTF1("\t flag %d", vt->v_part[i].p_flag);
 824         }
 825 }
 826 #endif /* DEBUG */
 827         if (check_vtoc_sanity(handle, fd, vt) < 0) {
 828                 return (-1);
 829         }
 830 #ifdef DEBUG
 831 {
 832         int32_t i;
 833         for (i = 0; i < 8; i++) {
 834                 DPRINTF1("\npart %d\n", i);
 835                 DPRINTF1("\t start %llu",  vt->v_part[i].p_start);
 836                 DPRINTF1("\t size %llu ", vt->v_part[i].p_size);
 837                 DPRINTF1("\t tag %d", vt->v_part[i].p_tag);
 838                 DPRINTF1("\t flag %d", vt->v_part[i].p_flag);
 839         }
 840 }
 841 #endif /* DEBUG */
 842         return (0);
 843 }
 844 
 845 #define SWAP(a, b)      {diskaddr_t tmp; tmp = (a); (a) = (b); (b) = tmp; }
 846 
 847 /*
 848  * On x86 Solaris, the partitioning is done in two levels, fdisk and Solaris
 849  * VTOC. Where as, on sparc solaris, it is only VTOC. On floppy and PCMCIA
 850  * also it is assumed to be only VTOC, no fdisk.
 851  *
 852  * On sparc, the back up slice can cover the whole medium. But on x86
 853  * (SCSI/ATAPI disks), the backup slice can cover the solaris partition
 854  * in fdisk table.
 855  *      Following table describes how is it handled
 856  * SPARC:
 857  *      SCSI/ATAPI, floppy, pcmcia : don't check for fdisk.
 858  *                              DKIOCGGEOM is sufficient.
 859  * x86 : floppy, pcmcia : Don't check for fdisk. DKIOCGGEOM is sufficient.
 860  *      SCSI/ATAPI : Check for fdisk.
 861  *                      if not present, assume that the solaris
 862  *                              partition covers 100% of the medium
 863  *                              (minus one cylinder).
 864  *
 865  *              if present :
 866  *                              check for active solaris partition.
 867  *                              if not found, take the first solaris
 868  *                                      partition.
 869  *                      If there are no solaris partitions, its an error, stop.
 870  */
 871 
 872 static int32_t
 873 check_vtoc_sanity(smedia_handle_t handle, int32_t fd, struct extvtoc *vt)
 874 {
 875 
 876         int32_t i, j;
 877         struct dk_geom dkg;
 878         int32_t num_backup = 0;
 879         diskaddr_t backup_size = 0;
 880         struct part_struct {
 881                 diskaddr_t start;
 882                 diskaddr_t end;
 883                 int32_t num;
 884         } part[NDKMAP];
 885         diskaddr_t min_val;
 886         int32_t min_slice, num_slices;
 887         diskaddr_t media_size;
 888         uint32_t cyl_size = 0;
 889         int sparc_style = 0;    /* sparc_style handling ? */
 890         struct fdisk_info fdisk;
 891         int sol_part;
 892         int total_parts = 0;
 893 
 894 #ifdef sparc
 895         sparc_style = 1;
 896 #endif /* sparc */
 897 
 898         if ((med_info.sm_media_type == SM_FLOPPY) ||
 899             (med_info.sm_media_type == SM_PCMCIA_MEM) ||
 900             (med_info.sm_media_type == SM_PCMCIA_ATA) ||
 901             (med_info.sm_media_type == SM_SCSI_FLOPPY)) {
 902                 sparc_style = 1;
 903         }
 904 
 905         if (sparc_style) {
 906                 DPRINTF("sparc style true\n");
 907                 if (ioctl(fd, DKIOCGGEOM, &dkg) < 0) {
 908                         PERROR("DKIOCGGEOM Failed");
 909                         return (-1);
 910                 }
 911                 media_size = (diskaddr_t)dkg.dkg_ncyl * dkg.dkg_nhead *
 912                     dkg.dkg_nsect;
 913                 cyl_size = dkg.dkg_nhead * dkg.dkg_nsect;
 914         }
 915 
 916         if (!sparc_style) {
 917         /*
 918          * Try to get the fdisk information if available.
 919          */
 920                 if (get_fdisk(handle, fd, 0, &fdisk) >= 0) {
 921                         /* fdisk table on disk */
 922                         sol_part = 0xFF;
 923                         for (i = 0; i < FD_NUMPART; i++) {
 924                                 if (fdisk.part[i].systid == SUNIXOS ||
 925                                     fdisk.part[i].systid == SUNIXOS2) {
 926                                         if (sol_part == 0xFF)
 927                                                 sol_part = i;
 928                                         total_parts++;
 929                                         if (fdisk.part[i].bootid == ACTIVE)
 930                                                 sol_part = i;
 931                                 }
 932                         }
 933                         if (sol_part == 0xFF) {
 934                                 /* No Solaris partition */
 935 
 936                                 (void) fprintf(stderr, gettext("No FDISK \
 937 Solaris partition found!\n"));
 938                                 return (-1);
 939                         }
 940                         if (total_parts > 1)
 941                                 (void) fprintf(stderr, gettext("Multiple FDISK \
 942 Solaris partitions found.\n"));
 943                         media_size = (diskaddr_t)fdisk.part[sol_part].numsect;
 944 
 945                         DPRINTF1("sol_part %d\n", sol_part);
 946                         DPRINTF1("media_size %llu\n", media_size);
 947                 } else {
 948                         DPRINTF("Didn't get fdisk\n");
 949                         /*
 950                          * No fdisk partition available. Assume a 100% Solaris.
 951                          * partition.
 952                          * Try getting disk geometry.
 953                          */
 954                         if (ioctl(fd, DKIOCGGEOM, &dkg) < 0)
 955                                 if (ioctl(fd, DKIOCG_PHYGEOM, &dkg) < 0) {
 956                                         DPRINTF("DKIOCG_PHYGEOM ioctl failed");
 957                                         return (-1);
 958                         }
 959                         /* On x86 platform 1 cylinder is used for fdisk table */
 960                         dkg.dkg_ncyl = dkg.dkg_ncyl - 1;
 961                         media_size = (diskaddr_t)dkg.dkg_ncyl * dkg.dkg_nhead *
 962                             dkg.dkg_nsect;
 963                 }
 964         }
 965 
 966 #ifdef DEBUG
 967         DPRINTF1("Ncyl %d\n", dkg.dkg_ncyl);
 968         DPRINTF1("nhead %d\n", dkg.dkg_nhead);
 969         DPRINTF1("nsect %d\n", dkg.dkg_nsect);
 970 #endif /* DEBUG */
 971 
 972         if (media_size == 0) {
 973                 media_size = (uint32_t)med_info.sm_capacity;
 974         }
 975 
 976         (void) memset(&part, 0, sizeof (part));
 977         for (i = 0, j = 0; i < NDKMAP; i++) {
 978                 if (vt->v_part[i].p_tag == V_BACKUP) {
 979                         if (vt->v_part[i].p_start != 0) {
 980                                 (void) fprintf(stderr,
 981                                     gettext(
 982                         "Backup slice should start at sector 0\n"));
 983                         return (-1);
 984                         }
 985                         backup_size = vt->v_part[i].p_size;
 986                         num_backup++;
 987                         continue;
 988                 }
 989                 if (vt->v_part[i].p_size) {
 990 
 991                         if (sparc_style) {
 992                                 if (vt->v_part[i].p_start % cyl_size) {
 993                                         (void) fprintf(stderr,
 994                                             gettext(
 995                         "Slice %d does not start on cylinder boundary\n"), i);
 996                                         (void) fprintf(stderr,
 997                                             gettext(
 998                         "Cylinder size %d 512 byte sectors\n"), cyl_size);
 999                                         return (-1);
1000                                 }
1001                         }
1002                         part[j].start = vt->v_part[i].p_start;
1003                         part[j].end = vt->v_part[i].p_start +
1004                             vt->v_part[i].p_size -1;
1005                         part[j].num = i;
1006                         j++;
1007                 }
1008         }
1009         if (num_backup > 1) {
1010                 (void) fprintf(stderr,
1011                     gettext("Maximum one backup slice is allowed\n"));
1012                 (void) smedia_release_handle(handle);
1013                 (void) close(fd);
1014                 exit(1);
1015         }
1016         num_slices = j;
1017 
1018         for (i = 0; i < num_slices; i++) {
1019                 min_val = part[i].start;
1020                 min_slice = i;
1021                 for (j = i+1; j < num_slices; j++) {
1022                         if (part[j].start < min_val) {
1023                                 min_val = part[j].start;
1024                                 min_slice = j;
1025                         }
1026                 }
1027                 if (min_slice != i) {
1028                         SWAP(part[i].start, part[min_slice].start)
1029                         SWAP(part[i].end, part[min_slice].end)
1030                         SWAP(part[i].num, part[min_slice].num)
1031                 }
1032         }
1033 
1034 #ifdef DEBUG
1035         for (i = 0; i < num_slices; i++) {
1036                 DPRINTF4("\n %d (%d) : %llu, %llu", i, part[i].num,
1037                     part[i].start, part[i].end);
1038         }
1039 #endif /* DEBUG */
1040 
1041         if (backup_size > media_size) {
1042                 if (sparc_style) {
1043                         (void) fprintf(stderr,
1044                             gettext(
1045                         "Backup slice extends beyond size of media\n"));
1046                         (void) fprintf(stderr,
1047                             gettext("media size : %llu sectors \n"),
1048                             media_size);
1049                 } else {
1050 
1051                         (void) fprintf(stderr,
1052                             gettext("Backup slice extends beyond size of FDISK \
1053 Solaris partition\n"));
1054                         (void) fprintf(stderr,
1055                             gettext(
1056                         "FDISK Solaris partition size : %llu sectors \n"),
1057                             media_size);
1058                 }
1059                 return (-1);
1060         }
1061 
1062         /*
1063          * If we have only backup slice return success here.
1064          */
1065         if (num_slices == 0)
1066                 return (0);
1067 
1068         if (backup_size) {
1069                 if (part[num_slices - 1].end > backup_size) {
1070                         (void) fprintf(stderr,
1071                             gettext("Slice %d extends beyond backup slice.\n"),
1072                             part[num_slices -1].num);
1073                         return (-1);
1074                 }
1075         } else {
1076                 if (part[num_slices - 1].end > media_size) {
1077                         if (sparc_style) {
1078                                 (void) fprintf(stderr,
1079                                     gettext(
1080                                 "Slice %d extends beyond media size\n"),
1081                                     part[num_slices -1].num);
1082                                 (void) fprintf(stderr,
1083                                     gettext("media size : %llu sectors \n"),
1084                                     media_size);
1085                         } else {
1086                                 (void) fprintf(stderr,
1087                                     gettext("Slice %d extends beyond FDISK"
1088                                     " Solaris partition size\n"),
1089                                     part[num_slices -1].num);
1090                                 (void) fprintf(stderr, gettext(
1091                                     "FDISK Solaris partition size : %llu "
1092                                     "sectors \n"), media_size);
1093                         }
1094                         return (-1);
1095                 }
1096         }
1097 
1098 
1099 
1100         for (i = 0; i < num_slices; i++) {
1101                 if (i == 0)
1102                         continue;
1103                 if (part[i].start <= part[i-1].end) {
1104                         (void) fprintf(stderr,
1105                             gettext("Overlap between slices %d and %d\n"),
1106                             part[i-1].num, part[i].num);
1107                         (void) smedia_release_handle(handle);
1108                         (void) close(fd);
1109                         exit(1);
1110                 }
1111         }
1112 
1113         return (0);
1114 }
1115 
1116 
1117 static int32_t
1118 get_fdisk(smedia_handle_t handle, int32_t fd, int32_t offset,
1119         struct fdisk_info *fdisk)
1120 {
1121         struct mboot *boot_sec;
1122         struct ipart *part;
1123         char *buf;
1124         int32_t i, ret;
1125         int     save_errno;
1126 
1127         /* Read the master boot program */
1128 
1129         buf = (char *)malloc(med_info.sm_blocksize);
1130         if (buf == NULL) {
1131                 PERROR("malloc failed");
1132                 exit(1);
1133         }
1134         errno = 0;
1135         ret = ioctl(fd, DKIOCGMBOOT, buf);
1136         if (ret < 0) {
1137                 if (errno != ENOTTY) {
1138                         PERROR("DKIOCGMBOOT ioctl failed");
1139                         return (-1);
1140                 }
1141 
1142                 /* Turn on privileges. */
1143                 (void) __priv_bracket(PRIV_ON);
1144 
1145                 ret = smedia_raw_read(handle,
1146                     (diskaddr_t)offset/med_info.sm_blocksize,
1147                     buf, med_info.sm_blocksize);
1148 
1149                 /* Turn off privileges. */
1150                 (void) __priv_bracket(PRIV_OFF);
1151 
1152                 save_errno = errno;
1153                 errno = save_errno;
1154                 if (ret != med_info.sm_blocksize) {
1155                         if (errno == ENOTSUP) {
1156                                 errno = 0;
1157                                 if (lseek(fd, offset, SEEK_SET)) {
1158                                         PERROR("Seek failed:");
1159                                         free(buf);
1160                                         return (-1);
1161                                 }
1162 
1163                                 /* Turn on privileges. */
1164                                 (void) __priv_bracket(PRIV_ON);
1165 
1166                                 ret = read(fd, buf, sizeof (struct mboot));
1167 
1168                                 /* Turn off privileges. */
1169                                 (void) __priv_bracket(PRIV_OFF);
1170 
1171                                 if (ret != sizeof (struct mboot)) {
1172                                         PERROR("Could not read "
1173                                             "master boot record");
1174                                         free(buf);
1175                                         return (-1);
1176                                 }
1177                         } else {
1178                                 PERROR("Could not read master boot record");
1179                                 free(buf);
1180                                 return (-1);
1181                         }
1182                 }
1183         }
1184         /* LINTED pointer cast may result in improper alignment */
1185         boot_sec = (struct mboot *)buf;
1186 
1187         /* Is this really a master boot record? */
1188         if (les(boot_sec->signature) != MBB_MAGIC) {
1189                 DPRINTF("fdisk: Invalid master boot file \n");
1190                 DPRINTF2("Bad magic number: is %x, should be %x.\n",
1191                     les(boot_sec->signature), MBB_MAGIC);
1192                 free(buf);
1193                 return (-1);
1194         }
1195 
1196         for (i = 0; i < FD_NUMPART; i++) {
1197                 DPRINTF1("part %d\n", i);
1198                 /* LINTED pointer cast may result in improper alignment */
1199                 part = (struct ipart *)&boot_sec->parts[i *
1200                     sizeof (struct ipart)];
1201                 fdisk->part[i].bootid = part->bootid;
1202                 if (part->bootid && (part->bootid != ACTIVE)) {
1203                         /* Hmmm...not a valid fdisk! */
1204                         return (-1);
1205                 }
1206                 fdisk->part[i].systid = part->systid;
1207 
1208                 /* To avoid the misalign access in sparc */
1209 
1210                 fdisk->part[i].relsect = lel(GET_32(&(part->relsect)));
1211                 fdisk->part[i].numsect = lel(GET_32(&(part->numsect)));
1212 
1213                 DPRINTF1("\tboot id 0x%x\n", part->bootid);
1214                 DPRINTF1("\tsystem id 0x%x\n", part->systid);
1215                 DPRINTF1("\trel sector 0x%x\n", fdisk->part[i].relsect);
1216                 DPRINTF1("\tnum sector 0x%x\n", fdisk->part[i].numsect);
1217         }
1218         free(buf);
1219         return (0);
1220 }
1221 
1222 
1223 /*
1224  * wrrite_defualt_label(int32_t fd)
1225  *      fd = file descriptor for the device.
1226  *
1227  * For sparc solaris
1228  *      Create a vtoc partition with
1229  *              slice 0 = slice 2 = medium capacity.
1230  *      The cyl, head, sect (CHS) values are computed as done in sd
1231  *      capacity <= 1GB,
1232  *              nhead = 64, nsect = 32
1233  *      capacity > 1gb,
1234  *              nhead = 255, nsect = 63
1235  *
1236  * For x86 solaris
1237  *      Create a fdisk partition,
1238  *              partition 0 covers the full medium, the partition
1239  *              type is set to Solaris.
1240  *      Then create solaris vtoc. The algorithm is same as sparc solaris.
1241  *      But the capacity is reduced by 1 cyl, to leave space for fdisk table.
1242  */
1243 
1244 #ifdef sparc
1245 /*ARGSUSED*/
1246 void
1247 write_default_label(smedia_handle_t handle, int32_t fd)
1248 {
1249 
1250         struct extvtoc v_toc;
1251         uint32_t nhead, numcyl, nsect;
1252         diskaddr_t capacity;
1253         int32_t ret;
1254         char asciilabel[LEN_DKL_ASCII];
1255         char asciilabel2[LEN_DKL_ASCII] = "DEFAULT\0";
1256         uint32_t acyl = 2;
1257 
1258 
1259         DPRINTF("Writing default vtoc\n");
1260         (void) memset(&v_toc, 0, sizeof (v_toc));
1261 
1262 
1263         v_toc.v_nparts = V_NUMPAR;
1264         v_toc.v_sanity = VTOC_SANE;
1265         v_toc.v_version = V_VERSION;
1266         v_toc.v_sectorsz = DEV_BSIZE;
1267 
1268         /*
1269          * For the head, cyl and number of sector per track,
1270          * if the capacity <= 1GB, head = 64, sect = 32.
1271          * else head = 255, sect 63
1272          * NOTE: the capacity should be equal to C*H*S values.
1273          * This will cause some truncation of size due to
1274          * round off errors.
1275          */
1276         if ((uint32_t)med_info.sm_capacity <= 0x200000) {
1277                 nhead = 64;
1278                 nsect = 32;
1279         } else {
1280                 nhead = 255;
1281                 nsect = 63;
1282         }
1283 
1284         numcyl = (uint32_t)med_info.sm_capacity / (nhead * nsect);
1285         capacity = (diskaddr_t)nhead * nsect * numcyl;
1286 
1287         v_toc.v_part[0].p_start = 0;
1288         v_toc.v_part[0].p_size = capacity;
1289         v_toc.v_part[0].p_tag  = V_ROOT;
1290         v_toc.v_part[0].p_flag = 0;     /* Mountable */
1291 
1292         v_toc.v_part[2].p_start = 0;
1293         v_toc.v_part[2].p_size = capacity;
1294         v_toc.v_part[2].p_tag  = V_BACKUP;
1295         v_toc.v_part[2].p_flag = V_UNMNT;
1296 
1297         /* Create asciilabel for compatibility with format utility */
1298         (void) snprintf(asciilabel, sizeof (asciilabel),
1299             "%s cyl %d alt %d hd %d sec %d",
1300             asciilabel2, numcyl, acyl, nhead, nsect);
1301         (void) memcpy(v_toc.v_asciilabel, asciilabel,
1302             LEN_DKL_ASCII);
1303 
1304         errno = 0;
1305 
1306         /* Turn on privileges. */
1307         (void) __priv_bracket(PRIV_ON);
1308 
1309         ret = write_extvtoc(fd, &v_toc);
1310 
1311         /* Turn off privileges. */
1312         (void) __priv_bracket(PRIV_OFF);
1313 
1314         if (ret < 0) {
1315                 PERROR("write VTOC failed");
1316                 DPRINTF1("Errno = %d\n", errno);
1317         }
1318 }
1319 
1320 #else /* !sparc */
1321 #ifdef i386
1322 
1323 void
1324 write_default_label(smedia_handle_t handle, int32_t fd)
1325 {
1326 
1327         int32_t i, ret;
1328         struct dk_geom  dkg;
1329         struct extvtoc v_toc;
1330         int tmp_fd;
1331         char *fdisk_buf;
1332         struct mboot boot_code;         /* Buffer for master boot record */
1333         struct ipart parts[FD_NUMPART];
1334         uint32_t numcyl, nhead, nsect;
1335         uint32_t unixend;
1336         uint32_t blocksize;
1337         diskaddr_t capacity;
1338         int     save_errno;
1339         size_t  bytes_written;
1340         char asciilabel[LEN_DKL_ASCII];
1341         char asciilabel2[LEN_DKL_ASCII] = "DEFAULT\0";
1342         uint32_t acyl = 2;
1343 
1344         DPRINTF("Writing default fdisk table and vtoc\n");
1345         (void) memset(&v_toc, 0, sizeof (v_toc));
1346         /*
1347          * Try getting disk geometry.
1348          */
1349         if (ioctl(fd, DKIOCGGEOM, &dkg) < 0)
1350                 if (ioctl(fd, DKIOCG_PHYGEOM, &dkg) < 0) {
1351 
1352                         DPRINTF("DKIOCG_PHYGEOM ioctl failed");
1353                         return;
1354         }
1355 
1356         tmp_fd = open("/usr/lib/fs/ufs/mboot", O_RDONLY);
1357         if (tmp_fd <= 0) {
1358                 return;
1359         }
1360 
1361         if (read(tmp_fd, &boot_code, sizeof (struct mboot))
1362                         != sizeof (struct mboot)) {
1363                 (void) close(tmp_fd);
1364                 return;
1365         }
1366 
1367         blocksize = med_info.sm_blocksize;
1368         fdisk_buf = (char *)malloc(blocksize);
1369         if (fdisk_buf == NULL) {
1370                 DPRINTF("malloc for fdisk_buf failed\n");
1371                 return;
1372         }
1373 
1374         (void) memset(&parts, 0, sizeof (parts));
1375 
1376         for (i = 0; i < FD_NUMPART; i++) {
1377                 parts[i].systid = UNUSED;
1378                 parts[i].numsect = lel(UNUSED);
1379                 parts[i].relsect = lel(UNUSED);
1380                 parts[i].bootid = 0;
1381         }
1382 
1383         numcyl = dkg.dkg_ncyl;
1384         nhead = dkg.dkg_nhead;
1385         nsect = dkg.dkg_nsect;
1386 
1387         parts[0].bootid = ACTIVE;
1388         parts[0].begsect = 1;
1389 
1390         unixend = numcyl;
1391 
1392         parts[0].relsect = lel(nhead * nsect);
1393         parts[0].numsect = lel(((diskaddr_t)numcyl * nhead * nsect));
1394         parts[0].systid = SUNIXOS2;   /* Solaris */
1395         parts[0].beghead = 0;
1396         parts[0].begcyl = 1;
1397         parts[0].endhead = nhead - 1;
1398         parts[0].endsect = (nsect & 0x3f) |
1399             (char)((unixend >> 2) & 0x00c0);
1400         parts[0].endcyl = (char)(unixend & 0x00ff);
1401 
1402         (void) memcpy(&(boot_code.parts), parts, sizeof (parts));
1403         (void) memcpy(fdisk_buf, &boot_code, sizeof (boot_code));
1404 
1405         /* Turn on privileges. */
1406         (void) __priv_bracket(PRIV_ON);
1407 
1408         ret = ioctl(fd, DKIOCSMBOOT, fdisk_buf);
1409 
1410         /* Turn off privileges. */
1411         (void) __priv_bracket(PRIV_OFF);
1412 
1413         if (ret == -1) {
1414                 if (errno != ENOTTY) {
1415                         PERROR("DKIOCSMBOOT ioctl Failed");
1416                         return;
1417                 }
1418 
1419                 /* Turn on privileges. */
1420                 (void) __priv_bracket(PRIV_ON);
1421 
1422                 bytes_written = smedia_raw_write(handle, (diskaddr_t)0,
1423                     fdisk_buf, blocksize);
1424 
1425                 /* Turn off privileges. */
1426                 (void) __priv_bracket(PRIV_OFF);
1427 
1428                 save_errno = errno;
1429                 errno = save_errno;
1430                 if (bytes_written != blocksize) {
1431                         if (errno == ENOTSUP) {
1432 
1433                             /* Turn on privileges. */
1434                                 (void) __priv_bracket(PRIV_ON);
1435 
1436                                 ret = write(fd, fdisk_buf, blocksize);
1437 
1438                             /* Turn off privileges. */
1439                                 (void) __priv_bracket(PRIV_OFF);
1440 
1441                                 if (ret != blocksize) {
1442                                         return;
1443                                 }
1444                         } else {
1445                                 return;
1446                         }
1447                 }
1448         }
1449         capacity = (diskaddr_t)(numcyl - 1) * nhead * nsect;
1450 
1451         v_toc.v_nparts = V_NUMPAR;
1452         v_toc.v_sanity = VTOC_SANE;
1453         v_toc.v_version = V_VERSION;
1454         v_toc.v_sectorsz = DEV_BSIZE;
1455 
1456         v_toc.v_part[0].p_start = 0;
1457         v_toc.v_part[0].p_size = capacity;
1458         v_toc.v_part[0].p_tag  = V_ROOT;
1459         v_toc.v_part[0].p_flag = 0;     /* Mountable */
1460 
1461         v_toc.v_part[2].p_start = 0;
1462         v_toc.v_part[2].p_size = capacity;
1463         v_toc.v_part[2].p_tag  = V_BACKUP;
1464         v_toc.v_part[2].p_flag = V_UNMNT;
1465 
1466         /* Create asciilabel for compatibility with format utility */
1467         (void) snprintf(asciilabel, sizeof (asciilabel),
1468             "%s cyl %d alt %d hd %d sec %d",
1469             asciilabel2, numcyl, acyl, nhead, nsect);
1470         (void) memcpy(v_toc.v_asciilabel, asciilabel,
1471             LEN_DKL_ASCII);
1472 
1473         errno = 0;
1474 
1475 
1476         /* Turn on privileges. */
1477         (void) __priv_bracket(PRIV_ON);
1478 
1479         ret = write_extvtoc(fd, &v_toc);
1480 
1481         /* Turn off privileges. */
1482         (void) __priv_bracket(PRIV_OFF);
1483 
1484         if (ret < 0) {
1485                 PERROR("write VTOC failed");
1486                 DPRINTF1("Errno = %d\n", errno);
1487         }
1488 }
1489 
1490 #else   /* !i386 */
1491 
1492 #error One of sparc or i386 must be defined!
1493 
1494 #endif /* i386 */
1495 #endif /* sparc */
1496 
1497 /*
1498  * void overwrite_metadata(int32_t fd, smedia_handle_t handle)
1499  *
1500  * purpose : quick format does not erase the data on Iomega
1501  * zip/jaz media. So, the meta data on the disk should be erased.
1502  *
1503  * If there is a valid fdisk table,
1504  *      erase first 64K of each partition.
1505  * If there is a valid vtoc,
1506  *      erase first 64k of each slice.
1507  * Then erase the 0th sector (the home for vtoc and fdisk) of the disk.
1508  * Note that teh vtoc on x86 resides in one of the fdisk partition.
1509  * So delay the erasing of the solaris partition until the vtoc is read.
1510  */
1511 
1512 void
1513 overwrite_metadata(int32_t fd, smedia_handle_t handle)
1514 {
1515 
1516         struct fdisk_info fdisk;
1517         diskaddr_t sol_offset = 0;
1518         int i, ret;
1519         struct extvtoc t_vtoc;
1520 #ifdef i386
1521         diskaddr_t sol_size = 0;
1522         int32_t active = 0;
1523 #endif /* i386 */
1524 
1525         /* Get fdisk info. */
1526         if (get_fdisk(handle, fd, 0, &fdisk) >= 0) {
1527                 /* Got a valid fdisk */
1528                 for (i = 0; i < FD_NUMPART; i++) {
1529 
1530                         if (fdisk.part[i].numsect == 0)
1531                                 continue;
1532                         if ((fdisk.part[i].systid == UNUSED) ||
1533                             (fdisk.part[i].systid == 0))
1534                                 continue;
1535 #ifdef i386
1536                         if (fdisk.part[i].systid == SUNIXOS ||
1537                             fdisk.part[i].systid == SUNIXOS2) {
1538                                 if (!sol_offset) {
1539                                         sol_offset = fdisk.part[i].relsect;
1540                                         sol_size = fdisk.part[i].numsect;
1541                                         if (fdisk.part[i].bootid == ACTIVE)
1542                                                 active = 1;
1543                                         continue;
1544                                 } else if ((fdisk.part[i].bootid == ACTIVE) &&
1545                                     (!active)) {
1546                                         erase(handle, sol_offset, sol_size);
1547                                         sol_offset = fdisk.part[i].relsect;
1548                                         sol_size = fdisk.part[i].numsect;
1549                                         active = 1;
1550                                         continue;
1551                                 }
1552                         }
1553 #endif /* i386 */
1554                         erase(handle, (diskaddr_t)fdisk.part[i].relsect,
1555                             (diskaddr_t)fdisk.part[i].numsect);
1556                 }
1557         }
1558 
1559         (void) memset(&t_vtoc, 0, sizeof (t_vtoc));
1560 
1561         if (sol_offset) {
1562                 /* fdisk x86 Solaris partition */
1563                 /* VTOC location in solaris partition is DK_LABEL_LOC */
1564 
1565                 /* Turn on privileges. */
1566                 (void) __priv_bracket(PRIV_ON);
1567 
1568                 ret = read_extvtoc(fd, &t_vtoc);
1569 
1570                 /* Turn off privileges. */
1571                 (void) __priv_bracket(PRIV_OFF);
1572 
1573                 if (ret < 0) {
1574                         /* No valid vtoc, erase fdisk table. */
1575                         erase(handle, (diskaddr_t)0, (diskaddr_t)1);
1576                         return;
1577                 }
1578         } else {
1579                 /* Sparc Solaris or x86 solaris with faked fdisk */
1580 
1581                 /* Turn on privileges */
1582                 (void) __priv_bracket(PRIV_ON);
1583 
1584                 ret = read_extvtoc(fd, &t_vtoc);
1585 
1586                 /* Turn off privileges. */
1587                 (void) __priv_bracket(PRIV_OFF);
1588 
1589                 if (ret < 0) {
1590                         /* No valid vtoc, erase from 0th sector */
1591                         erase(handle, (diskaddr_t)0,
1592                             (uint32_t)med_info.sm_capacity);
1593                         return;
1594                 }
1595         }
1596 
1597         for (i = 0; i < V_NUMPAR; i++) {
1598                 if (t_vtoc.v_part[i].p_size != 0) {
1599                         erase(handle, sol_offset + t_vtoc.v_part[i].p_start,
1600                             t_vtoc.v_part[i].p_size);
1601                         /*
1602                          * To make the udfs not recognise the partition we will
1603                          * erase sectors 256, (p_size-256) and psize.
1604                          */
1605                         erase(handle,
1606                             sol_offset + t_vtoc.v_part[i].p_start + 256,
1607                             (diskaddr_t)1);
1608                         erase(handle,
1609                             (sol_offset + t_vtoc.v_part[i].p_start +
1610                             t_vtoc.v_part[i].p_size - 256),
1611                             (diskaddr_t)1);
1612                         erase(handle,
1613                             (sol_offset + t_vtoc.v_part[i].p_start +
1614                             t_vtoc.v_part[i].p_size - 1),
1615                             (diskaddr_t)1);
1616                 }
1617         }
1618 
1619         /*
1620          * If x86 fdisk solaris partition, erase the vtoc also.
1621          * for sparc, the erasing 0the sector erases vtoc.
1622          */
1623         if (sol_offset) {
1624                 erase(handle, sol_offset, (diskaddr_t)DK_LABEL_LOC + 2);
1625         }
1626 
1627         /*
1628          * erase the 0th sector, it is not guaranteed to be
1629          * erased in the above sequence.
1630          */
1631 
1632         erase(handle, (diskaddr_t)0, (diskaddr_t)1);
1633 }
1634 
1635 /*
1636  * void erase(smedia_handle_t handle, uint32_t offset, uint32_t size)
1637  *
1638  * Initialize the media with '0' from offset 'offset' upto 'size'
1639  * or 128 blocks(64k), whichever is smaller.
1640  */
1641 
1642 static void
1643 erase(smedia_handle_t handle, diskaddr_t offset, diskaddr_t size)
1644 {
1645         char *buf;
1646         diskaddr_t nblocks = size;
1647         int32_t ret;
1648 
1649 
1650         nblocks = (nblocks < 128) ? nblocks : 128;
1651         buf = (char *)malloc(nblocks * med_info.sm_blocksize);
1652         if (buf == NULL) {
1653                 PERROR("malloc failed");
1654                 return;
1655         }
1656         (void) memset(buf, 0, (size_t)nblocks * med_info.sm_blocksize);
1657 
1658         /* Turn on privileges. */
1659         (void) __priv_bracket(PRIV_ON);
1660 
1661         ret = smedia_raw_write(handle, offset, buf,
1662             (size_t)nblocks * med_info.sm_blocksize);
1663 
1664         /* Turn off privileges. */
1665         (void) __priv_bracket(PRIV_OFF);
1666 
1667         if (ret != (nblocks * med_info.sm_blocksize))
1668                 PERROR("error in writing\n");
1669 
1670         free(buf);
1671 
1672 }