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