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
sup_prxfile(char * file_name,struct extvtoc * vt)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
sup_gettoken(char * buf)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
sup_get_token(char * buf)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
sup_inputchar()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
sup_pushchar(int32_t c)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
clean_token(char * cleantoken,char * token)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
sup_setpart(struct extvtoc * vt)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
find_value(slist_t * slist,char * match_str,int32_t * match_value)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
strcnt(char * s1,char * s2)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
str2sector(char * str)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
valid_slice_file(smedia_handle_t handle,int32_t fd,char * file_name,struct extvtoc * vt)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
check_vtoc_sanity(smedia_handle_t handle,int32_t fd,struct extvtoc * vt)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
get_fdisk(smedia_handle_t handle,int32_t fd,int32_t offset,struct fdisk_info * fdisk)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
write_default_label(smedia_handle_t handle,int32_t fd)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
write_default_label(smedia_handle_t handle,int32_t fd)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
overwrite_metadata(int32_t fd,smedia_handle_t handle)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
erase(smedia_handle_t handle,diskaddr_t offset,diskaddr_t size)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 }
1671