xref: /titanic_41/usr/src/cmd/rmformat/rmf_slice.c (revision 9f758caf94c37c3ad28c48cfe503f9fc830a66d5)
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 2008 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 	 * Copy it into the clean buffer.
416 	 */
417 	(void) strcpy(cleantoken, ptr);
418 	/*
419 	 * Strip off trailing white-space.
420 	 */
421 	for (ptr = cleantoken + strlen(cleantoken) - 1;
422 			isspace(*ptr) && (ptr >= cleantoken); ptr--) {
423 		*ptr = '\0';
424 	}
425 }
426 
427 static int32_t
428 sup_setpart(struct extvtoc *vt)
429 {
430 	TOKEN	token, cleaned, ident;
431 	int32_t	i, index, status;
432 	uint64_t	val1, val2;
433 	ushort_t	vtoc_tag = 0xFFFF;
434 	ushort_t	vtoc_flag = 0xFFFF;
435 
436 	/*
437 	 * Pull in some grammar.
438 	 */
439 
440 		status = sup_gettoken(token);
441 
442 		if (status != SUP_COLON) {
443 			(void) fprintf(stderr,
444 				gettext("Expecting ':', found '%s'"), token);
445 			(void) fprintf(stderr,
446 				gettext("Line no %d\n"), data_lineno);
447 			return (-1);
448 		}
449 
450 	for (;;) {
451 		status = sup_gettoken(token);
452 		if (status != SUP_STRING) {
453 			(void) fprintf(stderr,
454 				gettext("Expecting string, found '%s'"), token);
455 			(void) fprintf(stderr,
456 				gettext("Line no %d\n"), data_lineno);
457 			return (-1);
458 		}
459 		clean_token(ident, token);
460 		/*
461 		 * Also make sure it is within the legal range of letters.
462 		 */
463 		/*
464 		 * Here's the index of the partition we're dealing with
465 		 */
466 		index = (int32_t)my_atoll(ident);
467 		if ((index < 0) || (index > NDKMAP)) {
468 			(void) fprintf(stderr,
469 				gettext("Unknown partition '%s'"), index);
470 			(void) fprintf(stderr,
471 				gettext("Line no %d\n"), data_lineno);
472 			return (-1);
473 		}
474 		/*
475 		 * Check for floppy and PCMCIA_MEM cards.
476 		 * for floppy, the partition no. can be 0 1 2.
477 		 * for PCMCIA, the partition no. can be 2
478 		 */
479 		if (med_info.sm_media_type == SM_FLOPPY) {
480 			if ((index < 0) || (index > 2)) {
481 				(void) fprintf(stderr, gettext(
482 			"Floppy can have partitions 0 1 and 2\n"));
483 				return (-1);
484 			}
485 		}
486 		if (med_info.sm_media_type == SM_PCMCIA_MEM) {
487 			if (index != 2) {
488 				(void) fprintf(stderr, gettext(
489 			"PCMCIA Memory cards can have partition 2 only.\n"));
490 				return (-1);
491 			}
492 		}
493 
494 		DPRINTF1("\n Partition %d: ", index);
495 
496 		status = sup_gettoken(token);
497 		if (status != SUP_EQL) {
498 			(void) fprintf(stderr,
499 				gettext("Expecting '=', found '%s'"), token);
500 			(void) fprintf(stderr,
501 				gettext("Line no %d\n"), data_lineno);
502 			return (-1);
503 
504 		}
505 
506 
507 		status = sup_gettoken(token);
508 		/*
509 		 * If we hit a key character, it's an error.
510 		 */
511 		if (status != SUP_STRING) {
512 			(void) fprintf(stderr,
513 				gettext("Expecting value, found '%s'"), token);
514 			(void) fprintf(stderr,
515 				gettext("Line no %d\n"), data_lineno);
516 			return (-1);
517 		}
518 		clean_token(cleaned, token);
519 		/*
520 		 * <tag> may be one of: boot, root, swap, etc.
521 		 * <flag> consists of two characters:
522 		 *	W (writable) or R (read-only)
523 		 *	M (mountable) or U (unmountable)
524 		 *
525 		 * Start with the defaults assigned above:
526 		 */
527 
528 		/*
529 		 * All other attributes have a pair of numeric values.
530 		 * Convert the first value to a number.  This value
531 		 * is the starting cylinder number of the partition.
532 		 */
533 
534 		/* Check for valid partition, e.g. > 8 or 16 */
535 		val1 = str2sector(cleaned);
536 		if (val1 == -1) {
537 			(void) fprintf(stderr,
538 				gettext("Invalid partition beggining %s \n"),
539 			    cleaned);
540 			(void) fprintf(stderr,
541 				gettext("Line no %d\n"), data_lineno);
542 		}
543 
544 		DPRINTF1(" begins %s", cleaned);
545 		/*
546 		 * Pull in some grammar.
547 		 */
548 		status = sup_gettoken(token);
549 		if (status != SUP_COMMA) {
550 			(void) fprintf(stderr,
551 				gettext("Expecting ', ', found '%s'"), token);
552 			(void) fprintf(stderr,
553 				gettext("Line no %d\n"), data_lineno);
554 			return (-1);
555 		}
556 		/*
557 		 * Pull in the second value.
558 		 */
559 		status = sup_gettoken(token);
560 		if (status != SUP_STRING) {
561 			(void) fprintf(stderr,
562 				gettext("Expecting value, found '%s'"), token);
563 			(void) fprintf(stderr,
564 				gettext("Line no %d\n"), data_lineno);
565 			return (-1);
566 		}
567 		clean_token(cleaned, token);
568 
569 		val2 = str2sector(cleaned);
570 		if (val2 == -1) {
571 			(void) fprintf(stderr,
572 				gettext("Invalid partition size %s \n"),
573 			    cleaned);
574 			(void) fprintf(stderr,
575 				gettext("Line no %d\n"), data_lineno);
576 		}
577 		DPRINTF1(" ends %s ", cleaned);
578 
579 		/*
580 		 * Pull in some grammar.
581 		 */
582 		status = sup_gettoken(token);
583 
584 		if (status == SUP_COMMA) {
585 			/* tags and flags  */
586 			status = sup_gettoken(token);
587 			if (status != SUP_STRING) {
588 				(void) fprintf(stderr,
589 					gettext("Expecting value, found '%s'"),
590 				    token);
591 				(void) fprintf(stderr,
592 					gettext("Line no %d\n"), data_lineno);
593 				return (-1);
594 			}
595 			clean_token(cleaned, token);
596 			if (find_value(pflag_choices, cleaned, &i) == 1) {
597 				/*
598 				 * Found valid tag. Use it and advance parser
599 				 */
600 				DPRINTF1(" flag = %s", cleaned);
601 				vtoc_flag = (ushort_t)i;
602 				status = sup_gettoken(token);
603 			} else if (find_value(ptag_choices, cleaned, &i) == 1) {
604 				DPRINTF1(" tag = %s", cleaned);
605 				vtoc_tag = (ushort_t)i;
606 				status = sup_gettoken(token);
607 				if (status == SUP_COMMA) {
608 					(void) fprintf(stderr,
609 						gettext("Expecting : got %s\n"),
610 					    token);
611 					(void) fprintf(stderr,
612 						gettext("Line no %d\n"),
613 					    data_lineno);
614 					return (-1);
615 				}
616 			} else {
617 				(void) fprintf(stderr,
618 					gettext("Invalid flag or tag\n"));
619 				(void) fprintf(stderr,
620 					gettext("Line no %d\n"), data_lineno);
621 				return (-1);
622 			}
623 
624 
625 			if (status == SUP_COMMA) {
626 					/* Can be tag only */
627 
628 					status = sup_gettoken(token);
629 					if (status != SUP_STRING) {
630 						(void) fprintf(stderr,
631 						    gettext(
632 					"Expecting value, found '%s'"),
633 						token);
634 						(void) fprintf(stderr,
635 							gettext("Line no %d\n"),
636 						    data_lineno);
637 						return (-1);
638 					}
639 
640 					clean_token(cleaned, token);
641 					if (find_value(ptag_choices,
642 					    cleaned, &i) == 1) {
643 						DPRINTF1(" tag = %s", cleaned);
644 						vtoc_tag = (ushort_t)i;
645 					}
646 			status = sup_gettoken(token);
647 			}
648 		}
649 
650 		/*
651 		 * Fill in the appropriate map entry with the values.
652 		 */
653 		vt->v_part[index].p_start = val1;
654 		vt->v_part[index].p_size = val2;
655 		if (vtoc_tag != 0xFFFF) {
656 			vt->v_part[index].p_tag = vtoc_tag;
657 			vtoc_tag = 0xFFFF;
658 		}
659 		if (vtoc_flag != 0xFFFF) {
660 			vt->v_part[index].p_flag = vtoc_flag;
661 			vtoc_flag = 0xFFFF;
662 		}
663 		if (status == SUP_EOF) {
664 			DPRINTF("\nEnd of file\n");
665 			break;
666 		}
667 		if (status != SUP_COLON) {
668 			(void) fprintf(stderr,
669 				gettext("Expecting ':', found '%s'"), token);
670 			(void) fprintf(stderr,
671 				gettext("Line no %d\n"), data_lineno);
672 			return (-1);
673 		}
674 
675 	}
676 	return (0);
677 }
678 
679 static int32_t
680 find_value(slist_t *slist, char *match_str, int32_t *match_value)
681 {
682 	int32_t	i;
683 	int32_t	nmatches;
684 	int32_t	length;
685 	int32_t	match_length;
686 
687 	nmatches = 0;
688 	length = 0;
689 
690 	match_length = strlen(match_str);
691 
692 	for (; slist->str != NULL; slist++) {
693 		/*
694 		 * See how many characters of the token match
695 		 */
696 		i = strcnt(match_str, slist->str);
697 		/*
698 		 * If it's not the whole token, then it's not a match.
699 		 */
700 		if (i  < match_length) {
701 			continue;
702 		}
703 		/*
704 		 * If it ties with another input, remember that.
705 		 */
706 		if (i == length)
707 			nmatches++;
708 		/*
709 		 * If it matches the most so far, record that.
710 		 */
711 		if (i > length) {
712 			*match_value = slist->value;
713 			nmatches = 1;
714 			length = i;
715 		}
716 	}
717 
718 	return (nmatches);
719 }
720 
721 static int32_t
722 strcnt(char	*s1, char *s2)
723 {
724 	int32_t	i = 0;
725 
726 	while ((*s1 != '\0') && (*s1++ == *s2++))
727 		i++;
728 	return (i);
729 }
730 
731 static uint64_t
732 str2sector(char *str)
733 {
734 	int32_t mul_factor = 1;
735 	char *s1, *s2, *base;
736 	uint64_t num_sectors;
737 	uint64_t size;
738 
739 	base = s2 = (char *)malloc(strlen(str) + 1);
740 	if (s2 == NULL) {
741 		PERROR("Malloc failed");
742 		return (-1);
743 	}
744 	*s2 = '\0';
745 
746 
747 
748 	s1 = str;
749 	while (*s1) {
750 		if ((*s1 != 'x') && ((*s1 < 'A') || (*s1 > 'F')) &&
751 			((*s1 < 'a') || (*s1 > 'f')) && ((*s1 < '0') ||
752 			(*s1 > '9'))) {
753 			if (*s1 == 'G') {
754 					mul_factor = 1024*1024*1024;
755 					s1++;
756 			} else if (*s1 == 'M') {
757 					mul_factor = 1024*1024;
758 					s1++;
759 			} else if (*s1 == 'K') {
760 					mul_factor = 1024;
761 					s1++;
762 			}
763 			if ((*s1 != 'B') || (*(++s1) != NULL)) {
764 				(void) fprintf(stderr,
765 					gettext("Extra chars at the end\n"));
766 				free(base);
767 				return (-1);
768 			}
769 			break;
770 		} else {
771 			*s2++ = *s1++;
772 			*s2 = '\0';
773 		}
774 	}
775 	*s2 = NULL;
776 
777 	size = my_atoll(base);
778 	if ((!mul_factor) || (size == -1)) {
779 		free(base);
780 		return (-1);
781 	}
782 	num_sectors = size * (uint64_t)mul_factor /512;
783 
784 	free(base);
785 	return (num_sectors);
786 }
787 
788 
789 int32_t
790 valid_slice_file(smedia_handle_t handle, int32_t fd, char *file_name,
791 	struct extvtoc *vt)
792 {
793 	struct stat status;
794 	int32_t ret_val;
795 	if (stat(file_name, &status)) {
796 		PERROR(file_name);
797 		return (-1);
798 	}
799 	(void) memset(vt, 0, sizeof (*vt));
800 	/* Set default tag and flag */
801 #ifdef sparc
802 	vt->v_part[0].p_tag = V_ROOT;
803 	vt->v_part[1].p_tag = V_SWAP;
804 	vt->v_part[2].p_tag = V_BACKUP;
805 	vt->v_part[6].p_tag = V_USR;
806 
807 	vt->v_part[1].p_flag = V_UNMNT; /* Unmountable */
808 	vt->v_part[2].p_flag = V_UNMNT; /* Unmountable */
809 #endif
810 
811 	ret_val = sup_prxfile(file_name, vt);
812 	if (ret_val < 0)
813 		return (-1);
814 
815 #ifdef DEBUG
816 {
817 	int32_t i;
818 	for (i = 0; i < 8; i++) {
819 		DPRINTF1("\npart %d\n", i);
820 		DPRINTF1("\t start %llu",  vt->v_part[i].p_start);
821 		DPRINTF1("\t size %llu ", vt->v_part[i].p_size);
822 		DPRINTF1("\t tag %d", vt->v_part[i].p_tag);
823 		DPRINTF1("\t flag %d", vt->v_part[i].p_flag);
824 	}
825 }
826 #endif /* DEBUG */
827 	if (check_vtoc_sanity(handle, fd, vt) < 0) {
828 		return (-1);
829 	}
830 #ifdef DEBUG
831 {
832 	int32_t i;
833 	for (i = 0; i < 8; i++) {
834 		DPRINTF1("\npart %d\n", i);
835 		DPRINTF1("\t start %llu",  vt->v_part[i].p_start);
836 		DPRINTF1("\t size %llu ", vt->v_part[i].p_size);
837 		DPRINTF1("\t tag %d", vt->v_part[i].p_tag);
838 		DPRINTF1("\t flag %d", vt->v_part[i].p_flag);
839 	}
840 }
841 #endif /* DEBUG */
842 	return (0);
843 }
844 
845 #define	SWAP(a, b)	{diskaddr_t tmp; tmp = (a); (a) = (b); (b) = tmp; }
846 
847 /*
848  * On x86 Solaris, the partitioning is done in two levels, fdisk and Solaris
849  * VTOC. Where as, on sparc solaris, it is only VTOC. On floppy and PCMCIA
850  * also it is assumed to be only VTOC, no fdisk.
851  *
852  * On sparc, the back up slice can cover the whole medium. But on x86
853  * (SCSI/ATAPI disks), the backup slice can cover the solaris partition
854  * in fdisk table.
855  *	Following table describes how is it handled
856  * SPARC:
857  * 	SCSI/ATAPI, floppy, pcmcia : don't check for fdisk.
858  *				DKIOCGGEOM is sufficient.
859  * x86 : floppy, pcmcia : Don't check for fdisk. DKIOCGGEOM is sufficient.
860  * 	SCSI/ATAPI : Check for fdisk.
861  *			if not present, assume that the solaris
862  *				partition covers 100% of the medium
863  * 				(minus one cylinder).
864  *
865  * 		if present :
866  *				check for active solaris partition.
867  * 				if not found, take the first solaris
868  *					partition.
869  *			If there are no solaris partitions, its an error, stop.
870  */
871 
872 static int32_t
873 check_vtoc_sanity(smedia_handle_t handle, int32_t fd, struct extvtoc *vt)
874 {
875 
876 	int32_t i, j;
877 	struct dk_geom dkg;
878 	int32_t num_backup = 0;
879 	diskaddr_t backup_size = 0;
880 	struct part_struct {
881 		diskaddr_t start;
882 		diskaddr_t end;
883 		int32_t num;
884 	} part[NDKMAP];
885 	diskaddr_t min_val;
886 	int32_t min_slice, num_slices;
887 	diskaddr_t media_size;
888 	uint32_t cyl_size;
889 	int sparc_style = 0;	/* sparc_style handling ? */
890 	struct fdisk_info fdisk;
891 	int sol_part;
892 	int total_parts = 0;
893 
894 #ifdef sparc
895 	sparc_style = 1;
896 #endif /* sparc */
897 
898 	if ((med_info.sm_media_type == SM_FLOPPY) ||
899 	    (med_info.sm_media_type == SM_PCMCIA_MEM) ||
900 	    (med_info.sm_media_type == SM_PCMCIA_ATA) ||
901 	    (med_info.sm_media_type == SM_SCSI_FLOPPY)) {
902 		sparc_style = 1;
903 	}
904 
905 	if (sparc_style) {
906 		DPRINTF("sparc style true\n");
907 		if (ioctl(fd, DKIOCGGEOM, &dkg) < 0) {
908 			PERROR("DKIOCGGEOM Failed");
909 			return (-1);
910 		}
911 		media_size = (diskaddr_t)dkg.dkg_ncyl * dkg.dkg_nhead *
912 		    dkg.dkg_nsect;
913 		cyl_size = dkg.dkg_nhead * dkg.dkg_nsect;
914 	}
915 
916 	if (!sparc_style) {
917 	/*
918 	 * Try to get the fdisk information if available.
919 	 */
920 		if (get_fdisk(handle, fd, 0, &fdisk) >= 0) {
921 			/* fdisk table on disk */
922 			sol_part = 0xFF;
923 			for (i = 0; i < FD_NUMPART; i++) {
924 				if (fdisk.part[i].systid == SUNIXOS ||
925 				    fdisk.part[i].systid == SUNIXOS2) {
926 					if (sol_part == 0xFF)
927 						sol_part = i;
928 					total_parts++;
929 					if (fdisk.part[i].bootid == ACTIVE)
930 						sol_part = i;
931 				}
932 			}
933 			if (sol_part == 0xFF) {
934 				/* No Solaris partition */
935 
936 				(void) fprintf(stderr, gettext("No FDISK \
937 Solaris partition found!\n"));
938 				return (-1);
939 			}
940 			if (total_parts > 1)
941 				(void) fprintf(stderr, gettext("Multiple FDISK \
942 Solaris partitions found.\n"));
943 			media_size = (diskaddr_t)fdisk.part[sol_part].numsect;
944 
945 			DPRINTF1("sol_part %d\n", sol_part);
946 			DPRINTF1("media_size %llu\n", media_size);
947 		} else {
948 			DPRINTF("Didn't get fdisk\n");
949 			/*
950 			 * No fdisk partition available. Assume a 100% Solaris.
951 			 * partition.
952 			 * Try getting disk geometry.
953 			 */
954 			if (ioctl(fd, DKIOCGGEOM, &dkg) < 0)
955 				if (ioctl(fd, DKIOCG_PHYGEOM, &dkg) < 0) {
956 					DPRINTF("DKIOCG_PHYGEOM ioctl failed");
957 					return (-1);
958 			}
959 			/* On x86 platform 1 cylinder is used for fdisk table */
960 			dkg.dkg_ncyl = dkg.dkg_ncyl - 1;
961 			media_size = (diskaddr_t)dkg.dkg_ncyl * dkg.dkg_nhead *
962 			    dkg.dkg_nsect;
963 		}
964 	}
965 
966 #ifdef DEBUG
967 	DPRINTF1("Ncyl %d\n", dkg.dkg_ncyl);
968 	DPRINTF1("nhead %d\n", dkg.dkg_nhead);
969 	DPRINTF1("nsect %d\n", dkg.dkg_nsect);
970 #endif /* DEBUG */
971 
972 	if (media_size == 0) {
973 		media_size = (uint32_t)med_info.sm_capacity;
974 	}
975 
976 	(void) memset(&part, 0, sizeof (part));
977 	for (i = 0, j = 0; i < NDKMAP; i++) {
978 		if (vt->v_part[i].p_tag == V_BACKUP) {
979 			if (vt->v_part[i].p_start != 0) {
980 				(void) fprintf(stderr,
981 				    gettext(
982 			"Backup slice should start at sector 0\n"));
983 			return (-1);
984 			}
985 			backup_size = vt->v_part[i].p_size;
986 			num_backup++;
987 			continue;
988 		}
989 		if (vt->v_part[i].p_size) {
990 
991 			if (sparc_style) {
992 				if (vt->v_part[i].p_start % cyl_size) {
993 					(void) fprintf(stderr,
994 					    gettext(
995 			"Slice %d does not start on cylinder boundary\n"), i);
996 					(void) fprintf(stderr,
997 					    gettext(
998 			"Cylinder size %d 512 byte sectors\n"), cyl_size);
999 					return (-1);
1000 				}
1001 			}
1002 			part[j].start = vt->v_part[i].p_start;
1003 			part[j].end = vt->v_part[i].p_start +
1004 			    vt->v_part[i].p_size -1;
1005 			part[j].num = i;
1006 			j++;
1007 		}
1008 	}
1009 	if (num_backup > 1) {
1010 		(void) fprintf(stderr,
1011 			gettext("Maximum one backup slice is allowed\n"));
1012 		(void) smedia_release_handle(handle);
1013 		(void) close(fd);
1014 		exit(1);
1015 	}
1016 	num_slices = j;
1017 
1018 	for (i = 0; i < num_slices; i++) {
1019 		min_val = part[i].start;
1020 		min_slice = i;
1021 		for (j = i+1; j < num_slices; j++) {
1022 			if (part[j].start < min_val) {
1023 				min_val = part[j].start;
1024 				min_slice = j;
1025 			}
1026 		}
1027 		if (min_slice != i) {
1028 			SWAP(part[i].start, part[min_slice].start)
1029 			SWAP(part[i].end, part[min_slice].end)
1030 			SWAP(part[i].num, part[min_slice].num)
1031 		}
1032 	}
1033 
1034 #ifdef DEBUG
1035 	for (i = 0; i < num_slices; i++) {
1036 		DPRINTF4("\n %d (%d) : %llu, %llu", i, part[i].num,
1037 		    part[i].start, part[i].end);
1038 	}
1039 #endif /* DEBUG */
1040 
1041 	if (backup_size > media_size) {
1042 		if (sparc_style) {
1043 			(void) fprintf(stderr,
1044 			    gettext(
1045 			"Backup slice extends beyond size of media\n"));
1046 			(void) fprintf(stderr,
1047 			    gettext("media size : %llu sectors \n"),
1048 				media_size);
1049 		} else {
1050 
1051 			(void) fprintf(stderr,
1052 			    gettext("Backup slice extends beyond size of FDISK \
1053 Solaris partition\n"));
1054 			(void) fprintf(stderr,
1055 			    gettext(
1056 			"FDISK Solaris partition size : %llu sectors \n"),
1057 			    media_size);
1058 		}
1059 		return (-1);
1060 	}
1061 
1062 	/*
1063 	 * If we have only backup slice return success here.
1064 	 */
1065 	if (num_slices == 0)
1066 		return (0);
1067 
1068 	if (backup_size) {
1069 		if (part[num_slices - 1].end > backup_size) {
1070 			(void) fprintf(stderr,
1071 			    gettext("Slice %d extends beyond backup slice.\n"),
1072 			    part[num_slices -1].num);
1073 			return (-1);
1074 		}
1075 	} else {
1076 		if (part[num_slices - 1].end > media_size) {
1077 			if (sparc_style) {
1078 				(void) fprintf(stderr,
1079 				    gettext(
1080 				"Slice %d extends beyond media size\n"),
1081 				    part[num_slices -1].num);
1082 				(void) fprintf(stderr,
1083 				    gettext("media size : %llu sectors \n"),
1084 				    media_size);
1085 			} else {
1086 				(void) fprintf(stderr,
1087 				    gettext(
1088 		"Slice %d extends beyond FDISK Solaris partition size\n"),
1089 			part[num_slices -1].num);
1090 				(void) fprintf(stderr, gettext(
1091 				    "FDISK Solaris partition size : %llu "
1092 				    "sectors \n"), media_size);
1093 			}
1094 			return (-1);
1095 		}
1096 	}
1097 
1098 
1099 
1100 	for (i = 0; i < num_slices; i++) {
1101 		if (i == 0)
1102 			continue;
1103 		if (part[i].start <= part[i-1].end) {
1104 			(void) fprintf(stderr,
1105 				gettext("Overlap between slices %d and %d\n"),
1106 				part[i-1].num, part[i].num);
1107 			(void) smedia_release_handle(handle);
1108 			(void) close(fd);
1109 			exit(1);
1110 		}
1111 	}
1112 
1113 	return (0);
1114 }
1115 
1116 
1117 static int32_t
1118 get_fdisk(smedia_handle_t handle, int32_t fd, int32_t offset,
1119 	struct fdisk_info *fdisk)
1120 {
1121 	struct mboot *boot_sec;
1122 	struct ipart *part;
1123 	char *buf;
1124 	int32_t i, ret;
1125 	int	save_errno;
1126 
1127 	/* Read the master boot program */
1128 
1129 	buf = (char *)malloc(med_info.sm_blocksize);
1130 	if (buf == NULL) {
1131 		PERROR("malloc failed");
1132 		exit(1);
1133 	}
1134 	errno = 0;
1135 	ret = ioctl(fd, DKIOCGMBOOT, buf);
1136 	if (ret < 0) {
1137 		if (errno != ENOTTY) {
1138 			PERROR("DKIOCGMBOOT ioctl failed");
1139 			return (-1);
1140 		}
1141 
1142 		/* Turn on privileges. */
1143 		(void) __priv_bracket(PRIV_ON);
1144 
1145 		ret = smedia_raw_read(handle,
1146 		    (diskaddr_t)offset/med_info.sm_blocksize,
1147 		    buf, med_info.sm_blocksize);
1148 
1149 		/* Turn off privileges. */
1150 		(void) __priv_bracket(PRIV_OFF);
1151 
1152 		save_errno = errno;
1153 		errno = save_errno;
1154 		if (ret != med_info.sm_blocksize) {
1155 			if (errno == ENOTSUP) {
1156 				errno = 0;
1157 				if (lseek(fd, offset, SEEK_SET)) {
1158 				    PERROR("Seek failed:");
1159 				    free(buf);
1160 				    return (-1);
1161 				}
1162 
1163 				/* Turn on privileges. */
1164 				(void) __priv_bracket(PRIV_ON);
1165 
1166 				ret = read(fd, buf, sizeof (struct mboot));
1167 
1168 				/* Turn off privileges. */
1169 				(void) __priv_bracket(PRIV_OFF);
1170 
1171 				if (ret != sizeof (struct mboot)) {
1172 				    PERROR("Could not read master boot record");
1173 				    free(buf);
1174 				    return (-1);
1175 				}
1176 			} else {
1177 				PERROR("Could not read master boot record");
1178 				free(buf);
1179 				return (-1);
1180 			}
1181 		}
1182 	}
1183 	/* LINTED pointer cast may result in improper alignment */
1184 	boot_sec = (struct mboot *)buf;
1185 
1186 	/* Is this really a master boot record? */
1187 	if (les(boot_sec->signature) != MBB_MAGIC) {
1188 		DPRINTF("fdisk: Invalid master boot file \n");
1189 		DPRINTF2("Bad magic number: is %x, should be %x.\n",
1190 			les(boot_sec->signature), MBB_MAGIC);
1191 		free(buf);
1192 		return (-1);
1193 	}
1194 
1195 	for (i = 0; i < FD_NUMPART; i++) {
1196 		DPRINTF1("part %d\n", i);
1197 		/* LINTED pointer cast may result in improper alignment */
1198 		part = (struct ipart *)&boot_sec->parts[i *
1199 		    sizeof (struct ipart)];
1200 		fdisk->part[i].bootid = part->bootid;
1201 		if (part->bootid && (part->bootid != ACTIVE)) {
1202 			/* Hmmm...not a valid fdisk! */
1203 			return (-1);
1204 		}
1205 		fdisk->part[i].systid = part->systid;
1206 
1207 		/* To avoid the misalign access in sparc */
1208 
1209 		fdisk->part[i].relsect = lel(GET_32(&(part->relsect)));
1210 		fdisk->part[i].numsect = lel(GET_32(&(part->numsect)));
1211 
1212 		DPRINTF1("\tboot id 0x%x\n", part->bootid);
1213 		DPRINTF1("\tsystem id 0x%x\n", part->systid);
1214 		DPRINTF1("\trel sector 0x%x\n", fdisk->part[i].relsect);
1215 		DPRINTF1("\tnum sector 0x%x\n", fdisk->part[i].numsect);
1216 	}
1217 	free(buf);
1218 	return (0);
1219 }
1220 
1221 
1222 /*
1223  * wrrite_defualt_label(int32_t fd)
1224  * 	fd = file descriptor for the device.
1225  *
1226  * For sparc solaris
1227  *	Create a vtoc partition with
1228  *		slice 0 = slice 2 = medium capacity.
1229  *	The cyl, head, sect (CHS) values are computed as done in sd
1230  *	capacity <= 1GB,
1231  *		nhead = 64, nsect = 32
1232  *	capacity > 1gb,
1233  *		nhead = 255, nsect = 63
1234  *
1235  * For x86 solaris
1236  *	Create a fdisk partition,
1237  *		partition 0 covers the full medium, the partition
1238  *		type is set to Solaris.
1239  *	Then create solaris vtoc. The algorithm is same as sparc solaris.
1240  *	But the capacity is reduced by 1 cyl, to leave space for fdisk table.
1241  */
1242 
1243 #ifdef sparc
1244 /*ARGSUSED*/
1245 void
1246 write_default_label(smedia_handle_t handle, int32_t fd)
1247 {
1248 
1249 	struct extvtoc v_toc;
1250 	uint32_t nhead, numcyl, nsect;
1251 	diskaddr_t capacity;
1252 	int32_t ret;
1253 	char asciilabel[LEN_DKL_ASCII];
1254 	char asciilabel2[LEN_DKL_ASCII] = "DEFAULT\0";
1255 	uint32_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 ((uint32_t)med_info.sm_capacity <= 0x200000) {
1276 		nhead = 64;
1277 		nsect = 32;
1278 	} else {
1279 		nhead = 255;
1280 		nsect = 63;
1281 	}
1282 
1283 	numcyl = (uint32_t)med_info.sm_capacity / (nhead * nsect);
1284 	capacity = (diskaddr_t)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 	/* Turn on privileges. */
1306 	(void) __priv_bracket(PRIV_ON);
1307 
1308 	ret = write_extvtoc(fd, &v_toc);
1309 
1310 	/* Turn off privileges. */
1311 	(void) __priv_bracket(PRIV_OFF);
1312 
1313 	if (ret < 0) {
1314 		PERROR("write VTOC failed");
1315 		DPRINTF1("Errno = %d\n", errno);
1316 	}
1317 }
1318 
1319 #else /* !sparc */
1320 #ifdef i386
1321 
1322 void
1323 write_default_label(smedia_handle_t handle, int32_t fd)
1324 {
1325 
1326 	int32_t i, ret;
1327 	struct dk_geom  dkg;
1328 	struct extvtoc v_toc;
1329 	int tmp_fd;
1330 	char *fdisk_buf;
1331 	struct mboot boot_code;		/* Buffer for master boot record */
1332 	struct ipart parts[FD_NUMPART];
1333 	uint32_t numcyl, nhead, nsect;
1334 	uint32_t unixend;
1335 	uint32_t blocksize;
1336 	diskaddr_t capacity;
1337 	int	save_errno;
1338 	size_t	bytes_written;
1339 	char asciilabel[LEN_DKL_ASCII];
1340 	char asciilabel2[LEN_DKL_ASCII] = "DEFAULT\0";
1341 	uint32_t acyl = 2;
1342 
1343 	DPRINTF("Writing default fdisk table and vtoc\n");
1344 	(void) memset(&v_toc, 0, sizeof (v_toc));
1345 	/*
1346 	 * Try getting disk geometry.
1347 	 */
1348 	if (ioctl(fd, DKIOCGGEOM, &dkg) < 0)
1349 		if (ioctl(fd, DKIOCG_PHYGEOM, &dkg) < 0) {
1350 
1351 			DPRINTF("DKIOCG_PHYGEOM ioctl failed");
1352 			return;
1353 	}
1354 
1355 	tmp_fd = open("/usr/lib/fs/ufs/mboot", O_RDONLY);
1356 	if (tmp_fd <= 0) {
1357 		return;
1358 	}
1359 
1360 	if (read(tmp_fd, &boot_code, sizeof (struct mboot))
1361 			!= sizeof (struct mboot)) {
1362 		(void) close(tmp_fd);
1363 		return;
1364 	}
1365 
1366 	blocksize = med_info.sm_blocksize;
1367 	fdisk_buf = (char *)malloc(blocksize);
1368 	if (fdisk_buf == NULL) {
1369 		DPRINTF("malloc for fdisk_buf failed\n");
1370 		return;
1371 	}
1372 
1373 	(void) memset(&parts, 0, sizeof (parts));
1374 
1375 	for (i = 0; i < FD_NUMPART; i++) {
1376 		parts[i].systid = UNUSED;
1377 		parts[i].numsect = lel(UNUSED);
1378 		parts[i].relsect = lel(UNUSED);
1379 		parts[i].bootid = 0;
1380 	}
1381 
1382 	numcyl = dkg.dkg_ncyl;
1383 	nhead = dkg.dkg_nhead;
1384 	nsect = dkg.dkg_nsect;
1385 
1386 	parts[0].bootid = ACTIVE;
1387 	parts[0].begsect = 1;
1388 
1389 	unixend = numcyl;
1390 
1391 	parts[0].relsect = lel(nhead * nsect);
1392 	parts[0].numsect = lel(((diskaddr_t)numcyl * nhead * nsect));
1393 	parts[0].systid = SUNIXOS2;   /* Solaris */
1394 	parts[0].beghead = 0;
1395 	parts[0].begcyl = 1;
1396 	parts[0].endhead = nhead - 1;
1397 	parts[0].endsect = (nsect & 0x3f) |
1398 	    (char)((unixend >> 2) & 0x00c0);
1399 	parts[0].endcyl = (char)(unixend & 0x00ff);
1400 
1401 	(void) memcpy(&(boot_code.parts), parts, sizeof (parts));
1402 	(void) memcpy(fdisk_buf, &boot_code, sizeof (boot_code));
1403 
1404 	/* Turn on privileges. */
1405 	(void) __priv_bracket(PRIV_ON);
1406 
1407 	ret = ioctl(fd, DKIOCSMBOOT, fdisk_buf);
1408 
1409 	/* Turn off privileges. */
1410 	(void) __priv_bracket(PRIV_OFF);
1411 
1412 	if (ret == -1) {
1413 		if (errno != ENOTTY) {
1414 			PERROR("DKIOCSMBOOT ioctl Failed");
1415 			return;
1416 		}
1417 
1418 		/* Turn on privileges. */
1419 		(void) __priv_bracket(PRIV_ON);
1420 
1421 		bytes_written = smedia_raw_write(handle, (diskaddr_t)0,
1422 		    fdisk_buf, blocksize);
1423 
1424 		/* Turn off privileges. */
1425 		(void) __priv_bracket(PRIV_OFF);
1426 
1427 		save_errno = errno;
1428 		errno = save_errno;
1429 		if (bytes_written != blocksize) {
1430 			if (errno == ENOTSUP) {
1431 
1432 			    /* Turn on privileges. */
1433 			    (void) __priv_bracket(PRIV_ON);
1434 
1435 			    ret = write(fd, fdisk_buf, blocksize);
1436 
1437 			    /* Turn off privileges. */
1438 			    (void) __priv_bracket(PRIV_OFF);
1439 
1440 			    if (ret != blocksize) {
1441 					return;
1442 			    }
1443 			} else {
1444 				return;
1445 			}
1446 		}
1447 	}
1448 	capacity = (diskaddr_t)(numcyl - 1) * nhead * nsect;
1449 
1450 	v_toc.v_nparts = V_NUMPAR;
1451 	v_toc.v_sanity = VTOC_SANE;
1452 	v_toc.v_version = V_VERSION;
1453 	v_toc.v_sectorsz = DEV_BSIZE;
1454 
1455 	v_toc.v_part[0].p_start = 0;
1456 	v_toc.v_part[0].p_size = capacity;
1457 	v_toc.v_part[0].p_tag  = V_ROOT;
1458 	v_toc.v_part[0].p_flag = 0;	/* Mountable */
1459 
1460 	v_toc.v_part[2].p_start = 0;
1461 	v_toc.v_part[2].p_size = capacity;
1462 	v_toc.v_part[2].p_tag  = V_BACKUP;
1463 	v_toc.v_part[2].p_flag = V_UNMNT;
1464 
1465 	/* Create asciilabel for compatibility with format utility */
1466 	(void) snprintf(asciilabel, sizeof (asciilabel),
1467 	    "%s cyl %d alt %d hd %d sec %d",
1468 	    asciilabel2, numcyl, acyl, nhead, nsect);
1469 	(void) memcpy(v_toc.v_asciilabel, asciilabel,
1470 		LEN_DKL_ASCII);
1471 
1472 	errno = 0;
1473 
1474 
1475 	/* Turn on privileges. */
1476 	(void) __priv_bracket(PRIV_ON);
1477 
1478 	ret = write_extvtoc(fd, &v_toc);
1479 
1480 	/* Turn off privileges. */
1481 	(void) __priv_bracket(PRIV_OFF);
1482 
1483 	if (ret < 0) {
1484 		PERROR("write VTOC failed");
1485 		DPRINTF1("Errno = %d\n", errno);
1486 	}
1487 }
1488 
1489 #else	/* !i386 */
1490 
1491 #error One of sparc or i386 must be defined!
1492 
1493 #endif /* i386 */
1494 #endif /* sparc */
1495 
1496 /*
1497  * void overwrite_metadata(int32_t fd, smedia_handle_t handle)
1498  *
1499  * purpose : quick format does not erase the data on Iomega
1500  * zip/jaz media. So, the meta data on the disk should be erased.
1501  *
1502  * If there is a valid fdisk table,
1503  * 	erase first 64K of each partition.
1504  * If there is a valid vtoc,
1505  * 	erase first 64k of each slice.
1506  * Then erase the 0th sector (the home for vtoc and fdisk) of the disk.
1507  * Note that teh vtoc on x86 resides in one of the fdisk partition.
1508  * So delay the erasing of the solaris partition until the vtoc is read.
1509  */
1510 
1511 void
1512 overwrite_metadata(int32_t fd, smedia_handle_t handle)
1513 {
1514 
1515 	struct fdisk_info fdisk;
1516 	diskaddr_t sol_offset = 0;
1517 	int i, ret;
1518 	struct extvtoc t_vtoc;
1519 #ifdef i386
1520 	diskaddr_t sol_size = 0;
1521 	int32_t active = 0;
1522 #endif /* i386 */
1523 
1524 	/* Get fdisk info. */
1525 	if (get_fdisk(handle, fd, 0, &fdisk) >= 0) {
1526 		/* Got a valid fdisk */
1527 		for (i = 0; i < FD_NUMPART; i++) {
1528 
1529 			if (fdisk.part[i].numsect == 0)
1530 				continue;
1531 			if ((fdisk.part[i].systid == UNUSED) ||
1532 				(fdisk.part[i].systid == 0))
1533 				continue;
1534 #ifdef i386
1535 			if (fdisk.part[i].systid == SUNIXOS ||
1536 			    fdisk.part[i].systid == SUNIXOS2) {
1537 				if (!sol_offset) {
1538 					sol_offset = fdisk.part[i].relsect;
1539 					sol_size = fdisk.part[i].numsect;
1540 					if (fdisk.part[i].bootid == ACTIVE)
1541 						active = 1;
1542 					continue;
1543 				} else if ((fdisk.part[i].bootid == ACTIVE) &&
1544 				    (!active)) {
1545 					erase(handle, sol_offset, sol_size);
1546 					sol_offset = fdisk.part[i].relsect;
1547 					sol_size = fdisk.part[i].numsect;
1548 					active = 1;
1549 					continue;
1550 				}
1551 			}
1552 #endif /* i386 */
1553 			erase(handle, (diskaddr_t)fdisk.part[i].relsect,
1554 			    (diskaddr_t)fdisk.part[i].numsect);
1555 		}
1556 	}
1557 
1558 	(void) memset(&t_vtoc, 0, sizeof (t_vtoc));
1559 
1560 	if (sol_offset) {
1561 		/* fdisk x86 Solaris partition */
1562 		/* VTOC location in solaris partition is DK_LABEL_LOC */
1563 
1564 		/* Turn on privileges. */
1565 		(void) __priv_bracket(PRIV_ON);
1566 
1567 		ret = read_extvtoc(fd, &t_vtoc);
1568 
1569 		/* Turn off privileges. */
1570 		(void) __priv_bracket(PRIV_OFF);
1571 
1572 		if (ret < 0) {
1573 			/* No valid vtoc, erase fdisk table. */
1574 			erase(handle, (diskaddr_t)0, (diskaddr_t)1);
1575 			return;
1576 		}
1577 	} else {
1578 		/* Sparc Solaris or x86 solaris with faked fdisk */
1579 
1580 		/* Turn on privileges */
1581 		(void) __priv_bracket(PRIV_ON);
1582 
1583 		ret = read_extvtoc(fd, &t_vtoc);
1584 
1585 		/* Turn off privileges. */
1586 		(void) __priv_bracket(PRIV_OFF);
1587 
1588 		if (ret < 0) {
1589 			/* No valid vtoc, erase from 0th sector */
1590 			erase(handle, (diskaddr_t)0,
1591 			    (uint32_t)med_info.sm_capacity);
1592 			return;
1593 		}
1594 	}
1595 
1596 	for (i = 0; i < V_NUMPAR; i++) {
1597 		if (t_vtoc.v_part[i].p_size != 0) {
1598 			erase(handle, sol_offset + t_vtoc.v_part[i].p_start,
1599 				t_vtoc.v_part[i].p_size);
1600 			/*
1601 			 * To make the udfs not recognise the partition we will
1602 			 * erase sectors 256, (p_size-256) and psize.
1603 			 */
1604 			erase(handle,
1605 			    sol_offset + t_vtoc.v_part[i].p_start + 256,
1606 			    (diskaddr_t)1);
1607 			erase(handle,
1608 			    (sol_offset + t_vtoc.v_part[i].p_start +
1609 			    t_vtoc.v_part[i].p_size - 256),
1610 			    (diskaddr_t)1);
1611 			erase(handle,
1612 			    (sol_offset + t_vtoc.v_part[i].p_start +
1613 			    t_vtoc.v_part[i].p_size - 1),
1614 			    (diskaddr_t)1);
1615 		}
1616 	}
1617 
1618 	/*
1619 	 * If x86 fdisk solaris partition, erase the vtoc also.
1620 	 * for sparc, the erasing 0the sector erases vtoc.
1621 	 */
1622 	if (sol_offset) {
1623 		erase(handle, sol_offset, (diskaddr_t)DK_LABEL_LOC + 2);
1624 	}
1625 
1626 	/*
1627 	 * erase the 0th sector, it is not guaranteed to be
1628 	 * erased in the above sequence.
1629 	 */
1630 
1631 	erase(handle, (diskaddr_t)0, (diskaddr_t)1);
1632 }
1633 
1634 /*
1635  * void erase(smedia_handle_t handle, uint32_t offset, uint32_t size)
1636  *
1637  * Initialize the media with '0' from offset 'offset' upto 'size'
1638  * or 128 blocks(64k), whichever is smaller.
1639  */
1640 
1641 static void
1642 erase(smedia_handle_t handle, diskaddr_t offset, diskaddr_t size)
1643 {
1644 	char *buf;
1645 	diskaddr_t nblocks = size;
1646 	int32_t ret;
1647 
1648 
1649 	nblocks = (nblocks < 128) ? nblocks : 128;
1650 	buf = (char *)malloc(nblocks * med_info.sm_blocksize);
1651 	if (buf == NULL) {
1652 		PERROR("malloc failed");
1653 		return;
1654 	}
1655 	(void) memset(buf, 0, (size_t)nblocks * med_info.sm_blocksize);
1656 
1657 	/* Turn on privileges. */
1658 	(void) __priv_bracket(PRIV_ON);
1659 
1660 	ret = smedia_raw_write(handle, offset, buf,
1661 	    (size_t)nblocks * med_info.sm_blocksize);
1662 
1663 	/* Turn off privileges. */
1664 	(void) __priv_bracket(PRIV_OFF);
1665 
1666 	if (ret != (nblocks * med_info.sm_blocksize))
1667 		PERROR("error in writing\n");
1668 
1669 	free(buf);
1670 
1671 }
1672