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