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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * rmf_slice.c : 31 * This file contains the functions for parsing a slice file 32 * for rmformat. 33 */ 34 35 #include <sys/types.h> 36 #include <ctype.h> 37 #include <sys/vtoc.h> 38 #include <stdlib.h> 39 #include <unistd.h> 40 #include <string.h> 41 #include <fcntl.h> 42 #include <errno.h> 43 #include <memory.h> 44 #include <dirent.h> 45 #include <sys/fcntl.h> 46 #include <sys/param.h> 47 #include <sys/stat.h> 48 #include <stdio.h> 49 #include <sys/dkio.h> 50 #include <priv.h> 51 #include "rmformat.h" 52 53 extern void my_perror(char *err_string); 54 55 static int32_t last_token_type = 0; 56 #define spc() (last_token_type) 57 58 59 /* 60 * This global is used to store the current line # in the 61 * data file. It must be global because the I/O routines 62 * are allowed to side effect it to keep track of backslashed 63 * newlines. 64 */ 65 66 static int32_t data_lineno; /* current line # in data file */ 67 68 #define CHG_MODE_UNDEFINED (-1) /* undefined value */ 69 #define CHG_MODE_SET 0 /* set bits by or'ing */ 70 #define CHG_MODE_CLR 1 /* clr bits by and'ing */ 71 #define CHG_MODE_ABS 2 /* set absolute value */ 72 73 74 #define TOKEN_SIZE 36 /* max length of a token */ 75 typedef char TOKEN[TOKEN_SIZE+1]; /* token type */ 76 #define DATA_INPUT 0 /* 2 modes of input */ 77 #define CMD_INPUT 1 78 #define WILD_STRING "$" /* wildcard character */ 79 #define COMMENT_CHAR '#' /* comment character */ 80 81 /* 82 * List of strings with arbitrary matching values 83 */ 84 typedef struct slist { 85 char *str; 86 char *help; 87 int32_t value; 88 } slist_t; 89 90 static slist_t ptag_choices[] = { 91 { "unassigned", "", V_UNASSIGNED }, 92 { "boot", "", V_BOOT }, 93 { "root", "", V_ROOT }, 94 { "swap", "", V_SWAP }, 95 { "usr", "", V_USR }, 96 { "backup", "", V_BACKUP }, 97 { "stand", "", V_STAND }, 98 { "var", "", V_VAR }, 99 { "home", "", V_HOME }, 100 { "alternates", "", V_ALTSCTR }, 101 { NULL } 102 }; 103 104 105 /* 106 * Choices for the p_flag vtoc field 107 */ 108 static slist_t pflag_choices[] = { 109 { "wm", "read-write, mountable", 0 }, 110 { "wu", "read-write, unmountable", V_UNMNT }, 111 { "rm", "read-only, mountable", V_RONLY }, 112 { "ru", "read-only, unmountable", V_RONLY|V_UNMNT }, 113 { NULL } 114 }; 115 116 /* 117 * The definitions are the token types that the data file parser recognizes. 118 */ 119 #define SUP_EOF -1 /* eof token */ 120 #define SUP_STRING 0 /* string token */ 121 #define SUP_EQL 1 /* equals token */ 122 #define SUP_COMMA 2 /* comma token */ 123 #define SUP_COLON 3 /* colon token */ 124 #define SUP_EOL 4 /* newline token */ 125 #define SUP_OR 5 /* vertical bar */ 126 #define SUP_AND 6 /* ampersand */ 127 #define SUP_TILDE 7 /* tilde */ 128 129 130 /* 131 * Prototypes for ANSI C compilers 132 */ 133 static int32_t sup_prxfile(char *file_name, struct vtoc *vt); 134 static int32_t sup_setpart(struct vtoc *vt); 135 static void sup_pushchar(int32_t c); 136 static void clean_token(char *cleantoken, char *token); 137 static void clean_token(char *cleantoken, char *token); 138 static int32_t sup_inputchar(); 139 static int32_t sup_gettoken(char *buf); 140 static int32_t sup_get_token(char *buf); 141 static int32_t find_value(slist_t *slist, char *str, int32_t *value); 142 static int32_t check_vtoc_sanity(smedia_handle_t, int32_t fd, struct vtoc *vt); 143 static int32_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, uint32_t offset, uint32_t size); 148 149 extern char *myname; 150 extern int64_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 vtoc *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 * Copy it into the clean buffer. 418 */ 419 (void) strcpy(cleantoken, ptr); 420 /* 421 * Strip off trailing white-space. 422 */ 423 for (ptr = cleantoken + strlen(cleantoken) - 1; 424 isspace(*ptr) && (ptr >= cleantoken); ptr--) { 425 *ptr = '\0'; 426 } 427 } 428 429 static int32_t 430 sup_setpart(struct vtoc *vt) 431 { 432 TOKEN token, cleaned, ident; 433 int32_t i, index, status, 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 * Also make sure it is within the legal range of letters. 463 */ 464 /* 465 * Here's the index of the partition we're dealing with 466 */ 467 index = (int32_t)my_atoll(ident); 468 if ((index < 0) || (index > NDKMAP)) { 469 (void) fprintf(stderr, 470 gettext("Unknown partition '%s'"), index); 471 (void) fprintf(stderr, 472 gettext("Line no %d\n"), data_lineno); 473 return (-1); 474 } 475 /* 476 * Check for floppy and PCMCIA_MEM cards. 477 * for floppy, the partition no. can be 0 1 2. 478 * for PCMCIA, the partition no. can be 2 479 */ 480 if (med_info.sm_media_type == SM_FLOPPY) { 481 if ((index < 0) || (index > 2)) { 482 (void) fprintf(stderr, gettext( 483 "Floppy can have partitions 0 1 and 2\n")); 484 return (-1); 485 } 486 } 487 if (med_info.sm_media_type == SM_PCMCIA_MEM) { 488 if (index != 2) { 489 (void) fprintf(stderr, gettext( 490 "PCMCIA Memory cards can have partition 2 only.\n")); 491 return (-1); 492 } 493 } 494 495 DPRINTF1("\n Partition %d: ", index); 496 497 status = sup_gettoken(token); 498 if (status != SUP_EQL) { 499 (void) fprintf(stderr, 500 gettext("Expecting '=', found '%s'"), token); 501 (void) fprintf(stderr, 502 gettext("Line no %d\n"), data_lineno); 503 return (-1); 504 505 } 506 507 508 status = sup_gettoken(token); 509 /* 510 * If we hit a key character, it's an error. 511 */ 512 if (status != SUP_STRING) { 513 (void) fprintf(stderr, 514 gettext("Expecting value, found '%s'"), token); 515 (void) fprintf(stderr, 516 gettext("Line no %d\n"), data_lineno); 517 return (-1); 518 } 519 clean_token(cleaned, token); 520 /* 521 * <tag> may be one of: boot, root, swap, etc. 522 * <flag> consists of two characters: 523 * W (writable) or R (read-only) 524 * M (mountable) or U (unmountable) 525 * 526 * Start with the defaults assigned above: 527 */ 528 529 /* 530 * All other attributes have a pair of numeric values. 531 * Convert the first value to a number. This value 532 * is the starting cylinder number of the partition. 533 */ 534 535 /* Check for valid partition, e.g. > 8 or 16 */ 536 val1 = str2sector(cleaned); 537 if (val1 == -1) { 538 (void) fprintf(stderr, 539 gettext("Invalid partition beggining %s \n"), 540 cleaned); 541 (void) fprintf(stderr, 542 gettext("Line no %d\n"), data_lineno); 543 } 544 545 DPRINTF1(" begins %s", cleaned); 546 /* 547 * Pull in some grammar. 548 */ 549 status = sup_gettoken(token); 550 if (status != SUP_COMMA) { 551 (void) fprintf(stderr, 552 gettext("Expecting ', ', found '%s'"), token); 553 (void) fprintf(stderr, 554 gettext("Line no %d\n"), data_lineno); 555 return (-1); 556 } 557 /* 558 * Pull in the second value. 559 */ 560 status = sup_gettoken(token); 561 if (status != SUP_STRING) { 562 (void) fprintf(stderr, 563 gettext("Expecting value, found '%s'"), token); 564 (void) fprintf(stderr, 565 gettext("Line no %d\n"), data_lineno); 566 return (-1); 567 } 568 clean_token(cleaned, token); 569 570 val2 = str2sector(cleaned); 571 if (val2 == -1) { 572 (void) fprintf(stderr, 573 gettext("Invalid partition size %s \n"), 574 cleaned); 575 (void) fprintf(stderr, 576 gettext("Line no %d\n"), data_lineno); 577 } 578 DPRINTF1(" ends %s ", cleaned); 579 580 /* 581 * Pull in some grammar. 582 */ 583 status = sup_gettoken(token); 584 585 if (status == SUP_COMMA) { 586 /* tags and flags */ 587 status = sup_gettoken(token); 588 if (status != SUP_STRING) { 589 (void) fprintf(stderr, 590 gettext("Expecting value, found '%s'"), 591 token); 592 (void) fprintf(stderr, 593 gettext("Line no %d\n"), data_lineno); 594 return (-1); 595 } 596 clean_token(cleaned, token); 597 if (find_value(pflag_choices, cleaned, &i) == 1) { 598 /* 599 * Found valid tag. Use it and advance parser 600 */ 601 DPRINTF1(" flag = %s", cleaned); 602 vtoc_flag = (ushort_t)i; 603 status = sup_gettoken(token); 604 } else if (find_value(ptag_choices, cleaned, &i) == 1) { 605 DPRINTF1(" tag = %s", cleaned); 606 vtoc_tag = (ushort_t)i; 607 status = sup_gettoken(token); 608 if (status == SUP_COMMA) { 609 (void) fprintf(stderr, 610 gettext("Expecting : got %s\n"), 611 token); 612 (void) fprintf(stderr, 613 gettext("Line no %d\n"), 614 data_lineno); 615 return (-1); 616 } 617 } else { 618 (void) fprintf(stderr, 619 gettext("Invalid flag or tag\n")); 620 (void) fprintf(stderr, 621 gettext("Line no %d\n"), data_lineno); 622 return (-1); 623 } 624 625 626 if (status == SUP_COMMA) { 627 /* Can be tag only */ 628 629 status = sup_gettoken(token); 630 if (status != SUP_STRING) { 631 (void) fprintf(stderr, 632 gettext( 633 "Expecting value, found '%s'"), 634 token); 635 (void) fprintf(stderr, 636 gettext("Line no %d\n"), 637 data_lineno); 638 return (-1); 639 } 640 641 clean_token(cleaned, token); 642 if (find_value(ptag_choices, 643 cleaned, &i) == 1) { 644 DPRINTF1(" tag = %s", cleaned); 645 vtoc_tag = (ushort_t)i; 646 } 647 status = sup_gettoken(token); 648 } 649 } 650 651 /* 652 * Fill in the appropriate map entry with the values. 653 */ 654 vt->v_part[index].p_start = val1; 655 vt->v_part[index].p_size = val2; 656 if (vtoc_tag != 0xFFFF) { 657 vt->v_part[index].p_tag = vtoc_tag; 658 vtoc_tag = 0xFFFF; 659 } 660 if (vtoc_flag != 0xFFFF) { 661 vt->v_part[index].p_flag = vtoc_flag; 662 vtoc_flag = 0xFFFF; 663 } 664 if (status == SUP_EOF) { 665 DPRINTF("\nEnd of file\n"); 666 break; 667 } 668 if (status != SUP_COLON) { 669 (void) fprintf(stderr, 670 gettext("Expecting ':', found '%s'"), token); 671 (void) fprintf(stderr, 672 gettext("Line no %d\n"), data_lineno); 673 return (-1); 674 } 675 676 } 677 return (0); 678 } 679 680 static int32_t 681 find_value(slist_t *slist, char *match_str, int32_t *match_value) 682 { 683 int32_t i; 684 int32_t nmatches; 685 int32_t length; 686 int32_t match_length; 687 688 nmatches = 0; 689 length = 0; 690 691 match_length = strlen(match_str); 692 693 for (; slist->str != NULL; slist++) { 694 /* 695 * See how many characters of the token match 696 */ 697 i = strcnt(match_str, slist->str); 698 /* 699 * If it's not the whole token, then it's not a match. 700 */ 701 if (i < match_length) { 702 continue; 703 } 704 /* 705 * If it ties with another input, remember that. 706 */ 707 if (i == length) 708 nmatches++; 709 /* 710 * If it matches the most so far, record that. 711 */ 712 if (i > length) { 713 *match_value = slist->value; 714 nmatches = 1; 715 length = i; 716 } 717 } 718 719 return (nmatches); 720 } 721 722 static int32_t 723 strcnt(char *s1, char *s2) 724 { 725 int32_t i = 0; 726 727 while ((*s1 != '\0') && (*s1++ == *s2++)) 728 i++; 729 return (i); 730 } 731 732 static int32_t 733 str2sector(char *str) 734 { 735 int32_t mul_factor = 1; 736 char *s1, *s2, *base; 737 int32_t num_sectors; 738 int64_t size; 739 740 base = s2 = (char *)malloc(strlen(str) + 1); 741 if (s2 == NULL) { 742 PERROR("Malloc failed"); 743 return (-1); 744 } 745 *s2 = '\0'; 746 747 748 749 s1 = str; 750 while (*s1) { 751 if ((*s1 != 'x') && ((*s1 < 'A') || (*s1 > 'F')) && 752 ((*s1 < 'a') || (*s1 > 'f')) && ((*s1 < '0') || 753 (*s1 > '9'))) { 754 if (*s1 == 'G') { 755 mul_factor = 1024*1024*1024; 756 s1++; 757 } else if (*s1 == 'M') { 758 mul_factor = 1024*1024; 759 s1++; 760 } else if (*s1 == 'K') { 761 mul_factor = 1024; 762 s1++; 763 } 764 if ((*s1 != 'B') || (*(++s1) != NULL)) { 765 (void) fprintf(stderr, 766 gettext("Extra chars at the end\n")); 767 free(base); 768 return (-1); 769 } 770 break; 771 } else { 772 *s2++ = *s1++; 773 *s2 = '\0'; 774 } 775 } 776 *s2 = NULL; 777 778 size = my_atoll(base); 779 if ((!mul_factor) || (size == -1)) { 780 free(base); 781 return (-1); 782 } 783 num_sectors = (uint64_t)size * (uint64_t)mul_factor /512; 784 785 free(base); 786 return (num_sectors); 787 } 788 789 790 int32_t 791 valid_slice_file(smedia_handle_t handle, int32_t fd, char *file_name, 792 struct vtoc *vt) 793 { 794 struct stat status; 795 int32_t ret_val; 796 if (stat(file_name, &status)) { 797 PERROR(file_name); 798 return (-1); 799 } 800 (void) memset(vt, 0, sizeof (*vt)); 801 /* Set default tag and flag */ 802 #ifdef sparc 803 vt->v_part[0].p_tag = V_ROOT; 804 vt->v_part[1].p_tag = V_SWAP; 805 vt->v_part[2].p_tag = V_BACKUP; 806 vt->v_part[6].p_tag = V_USR; 807 808 vt->v_part[1].p_flag = V_UNMNT; /* Unmountable */ 809 vt->v_part[2].p_flag = V_UNMNT; /* Unmountable */ 810 #endif 811 812 ret_val = sup_prxfile(file_name, vt); 813 if (ret_val < 0) 814 return (-1); 815 816 #ifdef DEBUG 817 { 818 int32_t i; 819 for (i = 0; i < 8; i++) { 820 DPRINTF1("\npart %d\n", i); 821 DPRINTF1("\t start %d", (int32_t)vt->v_part[i].p_start); 822 DPRINTF1("\t size %d ", (int32_t)vt->v_part[i].p_size); 823 DPRINTF1("\t tag %d", vt->v_part[i].p_tag); 824 DPRINTF1("\t flag %d", vt->v_part[i].p_flag); 825 } 826 } 827 #endif /* DEBUG */ 828 if (check_vtoc_sanity(handle, fd, vt) < 0) { 829 return (-1); 830 } 831 #ifdef DEBUG 832 { 833 int32_t i; 834 for (i = 0; i < 8; i++) { 835 DPRINTF1("\npart %d\n", i); 836 DPRINTF1("\t start %d", (int32_t)vt->v_part[i].p_start); 837 DPRINTF1("\t size %d ", (int32_t)vt->v_part[i].p_size); 838 DPRINTF1("\t tag %d", vt->v_part[i].p_tag); 839 DPRINTF1("\t flag %d", vt->v_part[i].p_flag); 840 } 841 } 842 #endif /* DEBUG */ 843 return (0); 844 } 845 846 #define SWAP(a, b) {int32_t tmp; tmp = (a); (a) = (b); (b) = tmp; } 847 848 /* 849 * On x86 Solaris, the partitioning is done in two levels, fdisk and Solaris 850 * VTOC. Where as, on sparc solaris, it is only VTOC. On floppy and PCMCIA 851 * also it is assumed to be only VTOC, no fdisk. 852 * 853 * On sparc, the back up slice can cover the whole medium. But on x86 854 * (SCSI/ATAPI disks), the backup slice can cover the solaris partition 855 * in fdisk table. 856 * Following table describes how is it handled 857 * SPARC: 858 * SCSI/ATAPI, floppy, pcmcia : don't check for fdisk. 859 * DKIOCGGEOM is sufficient. 860 * x86 : floppy, pcmcia : Don't check for fdisk. DKIOCGGEOM is sufficient. 861 * SCSI/ATAPI : Check for fdisk. 862 * if not present, assume that the solaris 863 * partition covers 100% of the medium 864 * (minus one cylinder). 865 * 866 * if present : 867 * check for active solaris partition. 868 * if not found, take the first solaris 869 * partition. 870 * If there are no solaris partitions, its an error, stop. 871 */ 872 873 static int32_t 874 check_vtoc_sanity(smedia_handle_t handle, int32_t fd, struct vtoc *vt) 875 { 876 877 int32_t i, j; 878 struct dk_geom dkg; 879 int32_t num_backup = 0; 880 long backup_size = 0; 881 struct part_struct { 882 long start; 883 long end; 884 int32_t num; 885 } part[NDKMAP]; 886 long min_val, min_slice, num_slices; 887 long media_size; 888 int32_t cyl_size; 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 = dkg.dkg_ncyl * dkg.dkg_nhead * dkg.dkg_nsect; 912 cyl_size = dkg.dkg_nhead * dkg.dkg_nsect; 913 } 914 915 if (!sparc_style) { 916 /* 917 * Try to get the fdisk information if available. 918 */ 919 if (get_fdisk(handle, fd, 0, &fdisk) >= 0) { 920 /* fdisk table on disk */ 921 sol_part = 0xFF; 922 for (i = 0; i < FD_NUMPART; i++) { 923 if (fdisk.part[i].systid == SUNIXOS || 924 fdisk.part[i].systid == SUNIXOS2) { 925 if (sol_part == 0xFF) 926 sol_part = i; 927 total_parts++; 928 if (fdisk.part[i].bootid == ACTIVE) 929 sol_part = i; 930 } 931 } 932 if (sol_part == 0xFF) { 933 /* No Solaris partition */ 934 935 (void) fprintf(stderr, gettext("No FDISK \ 936 Solaris partition found!\n")); 937 return (-1); 938 } 939 if (total_parts > 1) 940 (void) fprintf(stderr, gettext("Multiple FDISK \ 941 Solaris partitions found.\n")); 942 media_size = fdisk.part[sol_part].numsect; 943 944 DPRINTF1("sol_part %d\n", sol_part); 945 DPRINTF1("media_size %d\n", (int)media_size); 946 } else { 947 DPRINTF("Didn't get fdisk\n"); 948 /* 949 * No fdisk partition available. Assume a 100% Solaris. 950 * partition. 951 * Try getting disk geometry. 952 */ 953 if (ioctl(fd, DKIOCGGEOM, &dkg) < 0) 954 if (ioctl(fd, DKIOCG_PHYGEOM, &dkg) < 0) { 955 DPRINTF("DKIOCG_PHYGEOM ioctl failed"); 956 return (-1); 957 } 958 /* On x86 platform 1 cylinder is used for fdisk table */ 959 dkg.dkg_ncyl = dkg.dkg_ncyl - 1; 960 media_size = dkg.dkg_ncyl * dkg.dkg_nhead * 961 dkg.dkg_nsect; 962 } 963 } 964 965 #ifdef DEBUG 966 DPRINTF1("Ncyl %d\n", dkg.dkg_ncyl); 967 DPRINTF1("nhead %d\n", dkg.dkg_nhead); 968 DPRINTF1("nsect %d\n", dkg.dkg_nsect); 969 #endif /* DEBUG */ 970 971 if (media_size == 0) { 972 media_size = med_info.sm_capacity; 973 } 974 975 (void) memset(&part, 0, sizeof (part)); 976 for (i = 0, j = 0; i < NDKMAP; i++) { 977 if (vt->v_part[i].p_tag == V_BACKUP) { 978 if (vt->v_part[i].p_start != 0) { 979 (void) fprintf(stderr, 980 gettext( 981 "Backup slice should start at sector 0\n")); 982 return (-1); 983 } 984 backup_size = vt->v_part[i].p_size; 985 num_backup++; 986 continue; 987 } 988 if (vt->v_part[i].p_size) { 989 990 if (sparc_style) { 991 if (vt->v_part[i].p_start % cyl_size) { 992 (void) fprintf(stderr, 993 gettext( 994 "Slice %d does not start on cylinder boundary\n"), i); 995 (void) fprintf(stderr, 996 gettext( 997 "Cylinder size %d 512 byte sectors\n"), cyl_size); 998 return (-1); 999 } 1000 } 1001 part[j].start = vt->v_part[i].p_start; 1002 part[j].end = vt->v_part[i].p_start + 1003 vt->v_part[i].p_size -1; 1004 part[j].num = i; 1005 j++; 1006 } 1007 } 1008 if (num_backup > 1) { 1009 (void) fprintf(stderr, 1010 gettext("Maximum one backup slice is allowed\n")); 1011 (void) smedia_release_handle(handle); 1012 (void) close(fd); 1013 exit(1); 1014 } 1015 num_slices = j; 1016 1017 for (i = 0; i < num_slices; i++) { 1018 min_val = part[i].start; 1019 min_slice = i; 1020 for (j = i+1; j < num_slices; j++) { 1021 if (part[j].start < min_val) { 1022 min_val = part[j].start; 1023 min_slice = j; 1024 } 1025 } 1026 if (min_slice != i) { 1027 SWAP(part[i].start, part[min_slice].start) 1028 SWAP(part[i].end, part[min_slice].end) 1029 SWAP(part[i].num, part[min_slice].num) 1030 } 1031 } 1032 1033 #ifdef DEBUG 1034 for (i = 0; i < num_slices; i++) { 1035 DPRINTF4("\n %d (%d) : %d, %d", i, part[i].num, 1036 part[i].start, part[i].end); 1037 } 1038 #endif /* DEBUG */ 1039 1040 if (backup_size > media_size) { 1041 if (sparc_style) { 1042 (void) fprintf(stderr, 1043 gettext( 1044 "Backup slice extends beyond size of media\n")); 1045 (void) fprintf(stderr, 1046 gettext("media size : %d sectors \n"), 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 : %d 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 : %d sectors \n"), 1082 media_size); 1083 } else { 1084 (void) fprintf(stderr, 1085 gettext( 1086 "Slice %d extends beyond FDISK Solaris partition size\n"), 1087 part[num_slices -1].num); 1088 (void) fprintf(stderr, 1089 gettext("FDISK Solaris partition size : %d \ 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 /* need the file_dac_read privilege */ 1141 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, 1142 (char *)NULL); 1143 1144 ret = smedia_raw_read(handle, offset/med_info.sm_blocksize, 1145 buf, med_info.sm_blocksize); 1146 1147 /* drop the file_dac_read privilege */ 1148 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, 1149 (char *)NULL); 1150 1151 save_errno = errno; 1152 errno = save_errno; 1153 if (ret != med_info.sm_blocksize) { 1154 if (errno == ENOTSUP) { 1155 errno = 0; 1156 if (lseek(fd, offset, SEEK_SET)) { 1157 PERROR("Seek failed:"); 1158 free(buf); 1159 return (-1); 1160 } 1161 1162 /* need the file_dac_read privilege */ 1163 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, 1164 PRIV_FILE_DAC_READ, (char *)NULL); 1165 1166 ret = read(fd, buf, sizeof (struct mboot)); 1167 1168 /* drop the file_dac_read privilege */ 1169 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, 1170 PRIV_FILE_DAC_READ, (char *)NULL); 1171 1172 if (ret != sizeof (struct mboot)) { 1173 PERROR("Could not read 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 vtoc v_toc; 1251 int32_t nhead, numcyl, nsect, capacity; 1252 int32_t ret; 1253 char asciilabel[LEN_DKL_ASCII]; 1254 char asciilabel2[LEN_DKL_ASCII] = "DEFAULT\0"; 1255 int32_t acyl = 2; 1256 1257 1258 DPRINTF("Writing default vtoc\n"); 1259 (void) memset(&v_toc, 0, sizeof (v_toc)); 1260 1261 1262 v_toc.v_nparts = V_NUMPAR; 1263 v_toc.v_sanity = VTOC_SANE; 1264 v_toc.v_version = V_VERSION; 1265 v_toc.v_sectorsz = DEV_BSIZE; 1266 1267 /* 1268 * For the head, cyl and number of sector per track, 1269 * if the capacity <= 1GB, head = 64, sect = 32. 1270 * else head = 255, sect 63 1271 * NOTE: the capacity should be equal to C*H*S values. 1272 * This will cause some truncation of size due to 1273 * round off errors. 1274 */ 1275 if (med_info.sm_capacity <= 0x200000) { 1276 nhead = 64; 1277 nsect = 32; 1278 } else { 1279 nhead = 255; 1280 nsect = 63; 1281 } 1282 1283 numcyl = med_info.sm_capacity / (nhead * nsect); 1284 capacity = nhead * nsect * numcyl; 1285 1286 v_toc.v_part[0].p_start = 0; 1287 v_toc.v_part[0].p_size = capacity; 1288 v_toc.v_part[0].p_tag = V_ROOT; 1289 v_toc.v_part[0].p_flag = 0; /* Mountable */ 1290 1291 v_toc.v_part[2].p_start = 0; 1292 v_toc.v_part[2].p_size = capacity; 1293 v_toc.v_part[2].p_tag = V_BACKUP; 1294 v_toc.v_part[2].p_flag = V_UNMNT; 1295 1296 /* Create asciilabel for compatibility with format utility */ 1297 (void) snprintf(asciilabel, sizeof (asciilabel), 1298 "%s cyl %d alt %d hd %d sec %d", 1299 asciilabel2, numcyl, acyl, nhead, nsect); 1300 (void) memcpy(v_toc.v_asciilabel, asciilabel, 1301 LEN_DKL_ASCII); 1302 1303 errno = 0; 1304 1305 /* need the file_dac_write privilege */ 1306 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, 1307 (char *)NULL); 1308 1309 ret = write_vtoc(fd, &v_toc); 1310 1311 /* drop the file_dac_write privilege */ 1312 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, 1313 (char *)NULL); 1314 1315 if (ret < 0) { 1316 PERROR("write VTOC failed"); 1317 DPRINTF1("Errno = %d\n", errno); 1318 } 1319 } 1320 1321 #else /* !sparc */ 1322 #ifdef i386 1323 1324 void 1325 write_default_label(smedia_handle_t handle, int32_t fd) 1326 { 1327 1328 int32_t i, ret; 1329 struct dk_geom dkg; 1330 struct vtoc v_toc; 1331 int tmp_fd; 1332 char *fdisk_buf; 1333 struct mboot boot_code; /* Buffer for master boot record */ 1334 struct ipart parts[FD_NUMPART]; 1335 int32_t numcyl, nhead, nsect; 1336 int32_t unixend; 1337 int32_t blocksize; 1338 int32_t capacity; 1339 int save_errno; 1340 size_t bytes_written; 1341 char asciilabel[LEN_DKL_ASCII]; 1342 char asciilabel2[LEN_DKL_ASCII] = "DEFAULT\0"; 1343 int32_t acyl = 2; 1344 1345 DPRINTF("Writing default fdisk table and vtoc\n"); 1346 (void) memset(&v_toc, 0, sizeof (v_toc)); 1347 /* 1348 * Try getting disk geometry. 1349 */ 1350 if (ioctl(fd, DKIOCGGEOM, &dkg) < 0) 1351 if (ioctl(fd, DKIOCG_PHYGEOM, &dkg) < 0) { 1352 1353 DPRINTF("DKIOCG_PHYGEOM ioctl failed"); 1354 return; 1355 } 1356 1357 tmp_fd = open("/usr/lib/fs/ufs/mboot", O_RDONLY); 1358 if (tmp_fd <= 0) { 1359 return; 1360 } 1361 1362 if (read(tmp_fd, &boot_code, sizeof (struct mboot)) 1363 != sizeof (struct mboot)) { 1364 (void) close(tmp_fd); 1365 return; 1366 } 1367 1368 blocksize = med_info.sm_blocksize; 1369 fdisk_buf = (char *)malloc(blocksize); 1370 if (fdisk_buf == NULL) { 1371 DPRINTF("malloc for fdisk_buf failed\n"); 1372 return; 1373 } 1374 1375 (void) memset(&parts, 0, sizeof (parts)); 1376 1377 for (i = 0; i < FD_NUMPART; i++) { 1378 parts[i].systid = UNUSED; 1379 parts[i].numsect = lel(UNUSED); 1380 parts[i].relsect = lel(UNUSED); 1381 parts[i].bootid = 0; 1382 } 1383 1384 numcyl = dkg.dkg_ncyl; 1385 nhead = dkg.dkg_nhead; 1386 nsect = dkg.dkg_nsect; 1387 1388 parts[0].bootid = ACTIVE; 1389 parts[0].begsect = 1; 1390 1391 unixend = numcyl; 1392 1393 parts[0].relsect = lel(nhead * nsect); 1394 parts[0].numsect = lel((long)((numcyl) * nhead * nsect)); 1395 parts[0].systid = SUNIXOS2; /* Solaris */ 1396 parts[0].beghead = 0; 1397 parts[0].begcyl = 1; 1398 parts[0].endhead = nhead - 1; 1399 parts[0].endsect = (nsect & 0x3f) | 1400 (char)((unixend >> 2) & 0x00c0); 1401 parts[0].endcyl = (char)(unixend & 0x00ff); 1402 1403 (void) memcpy(&(boot_code.parts), parts, sizeof (parts)); 1404 (void) memcpy(fdisk_buf, &boot_code, sizeof (boot_code)); 1405 1406 /* need the file_dac_write privilege */ 1407 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, 1408 (char *)NULL); 1409 1410 ret = ioctl(fd, DKIOCSMBOOT, fdisk_buf); 1411 1412 /* drop the file_dac_write privilege */ 1413 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, 1414 (char *)NULL); 1415 1416 if (ret == -1) { 1417 if (errno != ENOTTY) { 1418 PERROR("DKIOCSMBOOT ioctl Failed"); 1419 return; 1420 } 1421 1422 /* need the file_dac_write privilege */ 1423 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, 1424 (char *)NULL); 1425 1426 bytes_written = smedia_raw_write(handle, 0, fdisk_buf, 1427 blocksize); 1428 1429 /* drop the file_dac_write privilege */ 1430 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, 1431 (char *)NULL); 1432 1433 save_errno = errno; 1434 errno = save_errno; 1435 if (bytes_written != blocksize) { 1436 if (errno == ENOTSUP) { 1437 1438 /* need the file_dac_write privilege */ 1439 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, 1440 PRIV_FILE_DAC_WRITE, (char *)NULL); 1441 1442 ret = write(fd, fdisk_buf, blocksize); 1443 1444 /* drop the file_dac_write privilege */ 1445 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, 1446 PRIV_FILE_DAC_WRITE, (char *)NULL); 1447 1448 if (ret != blocksize) { 1449 return; 1450 } 1451 } else { 1452 return; 1453 } 1454 } 1455 } 1456 capacity = (numcyl - 1) * nhead * nsect; 1457 1458 v_toc.v_nparts = V_NUMPAR; 1459 v_toc.v_sanity = VTOC_SANE; 1460 v_toc.v_version = V_VERSION; 1461 v_toc.v_sectorsz = DEV_BSIZE; 1462 1463 v_toc.v_part[0].p_start = 0; 1464 v_toc.v_part[0].p_size = capacity; 1465 v_toc.v_part[0].p_tag = V_ROOT; 1466 v_toc.v_part[0].p_flag = 0; /* Mountable */ 1467 1468 v_toc.v_part[2].p_start = 0; 1469 v_toc.v_part[2].p_size = capacity; 1470 v_toc.v_part[2].p_tag = V_BACKUP; 1471 v_toc.v_part[2].p_flag = V_UNMNT; 1472 1473 /* Create asciilabel for compatibility with format utility */ 1474 (void) snprintf(asciilabel, sizeof (asciilabel), 1475 "%s cyl %d alt %d hd %d sec %d", 1476 asciilabel2, numcyl, acyl, nhead, nsect); 1477 (void) memcpy(v_toc.v_asciilabel, asciilabel, 1478 LEN_DKL_ASCII); 1479 1480 errno = 0; 1481 1482 1483 /* need the file_dac_write privilege */ 1484 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, 1485 (char *)NULL); 1486 1487 ret = write_vtoc(fd, &v_toc); 1488 1489 /* drop the file_dac_write privilege */ 1490 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, 1491 (char *)NULL); 1492 1493 if (ret < 0) { 1494 PERROR("write VTOC failed"); 1495 DPRINTF1("Errno = %d\n", errno); 1496 } 1497 } 1498 1499 #else /* !i386 */ 1500 1501 #error One of sparc or i386 must be defined! 1502 1503 #endif /* i386 */ 1504 #endif /* sparc */ 1505 1506 /* 1507 * void overwrite_metadata(int32_t fd, smedia_handle_t handle) 1508 * 1509 * purpose : quick format does not erase the data on Iomega 1510 * zip/jaz media. So, the meta data on the disk should be erased. 1511 * 1512 * If there is a valid fdisk table, 1513 * erase first 64K of each partition. 1514 * If there is a valid vtoc, 1515 * erase first 64k of each slice. 1516 * Then erase the 0th sector (the home for vtoc and fdisk) of the disk. 1517 * Note that teh vtoc on x86 resides in one of the fdisk partition. 1518 * So delay the erasing of the solaris partition until the vtoc is read. 1519 */ 1520 1521 void 1522 overwrite_metadata(int32_t fd, smedia_handle_t handle) 1523 { 1524 1525 struct fdisk_info fdisk; 1526 uint32_t sol_offset = 0; 1527 int i, ret; 1528 struct vtoc t_vtoc; 1529 #ifdef i386 1530 uint32_t sol_size = 0; 1531 int32_t active = 0; 1532 #endif /* i386 */ 1533 1534 /* Get fdisk info. */ 1535 if (get_fdisk(handle, fd, 0, &fdisk) >= 0) { 1536 /* Got a valid fdisk */ 1537 for (i = 0; i < FD_NUMPART; i++) { 1538 1539 if (fdisk.part[i].numsect == 0) 1540 continue; 1541 if ((fdisk.part[i].systid == UNUSED) || 1542 (fdisk.part[i].systid == 0)) 1543 continue; 1544 #ifdef i386 1545 if (fdisk.part[i].systid == SUNIXOS || 1546 fdisk.part[i].systid == SUNIXOS2) { 1547 if (!sol_offset) { 1548 sol_offset = fdisk.part[i].relsect; 1549 sol_size = fdisk.part[i].numsect; 1550 if (fdisk.part[i].bootid == ACTIVE) 1551 active = 1; 1552 continue; 1553 } else if ((fdisk.part[i].bootid == ACTIVE) && 1554 (!active)) { 1555 erase(handle, sol_offset, sol_size); 1556 sol_offset = fdisk.part[i].relsect; 1557 sol_size = fdisk.part[i].numsect; 1558 active = 1; 1559 continue; 1560 } 1561 } 1562 #endif /* i386 */ 1563 erase(handle, fdisk.part[i].relsect, 1564 fdisk.part[i].numsect); 1565 } 1566 } 1567 1568 (void) memset(&t_vtoc, 0, sizeof (t_vtoc)); 1569 1570 if (sol_offset) { 1571 /* fdisk x86 Solaris partition */ 1572 /* VTOC location in solaris partition is DK_LABEL_LOC */ 1573 1574 /* need the file_dac_read privilege */ 1575 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, 1576 (char *)NULL); 1577 1578 ret = read_vtoc(fd, &t_vtoc); 1579 1580 /* drop the file_dac_read privilege */ 1581 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, 1582 (char *)NULL); 1583 1584 if (ret < 0) { 1585 /* No valid vtoc, erase fdisk table. */ 1586 erase(handle, 0, 1); 1587 return; 1588 } 1589 } else { 1590 /* Sparc Solaris or x86 solaris with faked fdisk */ 1591 1592 /* need the file_dac_read privilege */ 1593 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, 1594 (char *)NULL); 1595 1596 ret = read_vtoc(fd, &t_vtoc); 1597 1598 /* drop the file_dac_read privilege */ 1599 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, 1600 (char *)NULL); 1601 1602 if (ret < 0) { 1603 /* No valid vtoc, erase from 0th sector */ 1604 erase(handle, 0, med_info.sm_capacity); 1605 return; 1606 } 1607 } 1608 1609 for (i = 0; i < V_NUMPAR; i++) { 1610 if (t_vtoc.v_part[i].p_size != 0) { 1611 erase(handle, sol_offset + t_vtoc.v_part[i].p_start, 1612 t_vtoc.v_part[i].p_size); 1613 /* 1614 * To make the udfs not recognise the partition we will 1615 * erase sectors 256, (p_size-256) and psize. 1616 */ 1617 erase(handle, 1618 sol_offset + t_vtoc.v_part[i].p_start + 256, 1619 1); 1620 erase(handle, 1621 (sol_offset + t_vtoc.v_part[i].p_start + 1622 t_vtoc.v_part[i].p_size - 256), 1623 1); 1624 erase(handle, 1625 (sol_offset + t_vtoc.v_part[i].p_start + 1626 t_vtoc.v_part[i].p_size - 1), 1627 1); 1628 } 1629 } 1630 1631 /* 1632 * If x86 fdisk solaris partition, erase the vtoc also. 1633 * for sparc, the erasing 0the sector erases vtoc. 1634 */ 1635 if (sol_offset) { 1636 erase(handle, sol_offset, DK_LABEL_LOC + 2); 1637 } 1638 1639 /* 1640 * erase the 0th sector, it is not guaranteed to be 1641 * erased in the above sequence. 1642 */ 1643 1644 erase(handle, 0, 1); 1645 } 1646 1647 /* 1648 * void erase(smedia_handle_t handle, uint32_t offset, uint32_t size) 1649 * 1650 * Initialize the media with '0' from offset 'offset' upto 'size' 1651 * or 128 blocks(64k), whichever is smaller. 1652 */ 1653 1654 static void 1655 erase(smedia_handle_t handle, uint32_t offset, uint32_t size) 1656 { 1657 char *buf; 1658 int32_t nblocks = size; 1659 int32_t ret; 1660 1661 1662 nblocks = (nblocks < 128) ? nblocks : 128; 1663 buf = (char *)malloc(nblocks * med_info.sm_blocksize); 1664 if (buf == NULL) { 1665 PERROR("malloc failed"); 1666 return; 1667 } 1668 (void) memset(buf, 0, nblocks * med_info.sm_blocksize); 1669 1670 /* need the file_dac_write privilege */ 1671 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, 1672 (char *)NULL); 1673 1674 ret = smedia_raw_write(handle, offset, buf, 1675 nblocks * med_info.sm_blocksize); 1676 1677 /* drop the file_dac_write privilege */ 1678 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, 1679 (char *)NULL); 1680 1681 if (ret != (nblocks * med_info.sm_blocksize)) 1682 PERROR("error in writing\n"); 1683 1684 free(buf); 1685 1686 } 1687