xref: /illumos-gate/usr/src/cmd/rmformat/rmf_slice.c (revision 0c887d2200d72bea8338a67f16c12fc8848ad05f)
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 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * rmf_slice.c :
30  * 	This file contains the functions for parsing a slice file
31  * 	for rmformat.
32  */
33 
34 #include <sys/types.h>
35 #include <ctype.h>
36 #include <sys/vtoc.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <memory.h>
43 #include <dirent.h>
44 #include <sys/fcntl.h>
45 #include <sys/param.h>
46 #include <sys/stat.h>
47 #include <stdio.h>
48 #include <sys/dkio.h>
49 #include <priv.h>
50 #include "rmformat.h"
51 
52 extern void my_perror(char *err_string);
53 
54 static int32_t	last_token_type = 0;
55 #define	spc()	  (last_token_type)
56 
57 
58 /*
59  * This global is used to store the current line # in the
60  * data file. It must be global because the I/O routines
61  * are allowed to side effect it to keep track of backslashed
62  * newlines.
63  */
64 
65 static int32_t	data_lineno;		/* current line # in data file */
66 
67 #define	CHG_MODE_UNDEFINED  (-1)	/* undefined value */
68 #define	CHG_MODE_SET	0		/* set bits by or'ing */
69 #define	CHG_MODE_CLR	1		/* clr bits by and'ing */
70 #define	CHG_MODE_ABS	2		/* set absolute value */
71 
72 
73 #define	TOKEN_SIZE	36		/* max length of a token */
74 typedef char TOKEN[TOKEN_SIZE+1];	/* token type */
75 #define	DATA_INPUT	0		/* 2 modes of input */
76 #define	CMD_INPUT	1
77 #define	WILD_STRING	"$"		/* wildcard character */
78 #define	COMMENT_CHAR	'#'		/* comment character */
79 
80 /*
81  * List of strings with arbitrary matching values
82  */
83 typedef struct slist {
84 	char	*str;
85 	char	*help;
86 	int32_t	value;
87 } slist_t;
88 
89 static slist_t ptag_choices[] = {
90 	{ "unassigned", "",	V_UNASSIGNED	},
91 	{ "boot",	"",	V_BOOT		},
92 	{ "root",	"",	V_ROOT		},
93 	{ "swap",	"",	V_SWAP		},
94 	{ "usr",	"",	V_USR		},
95 	{ "backup",	"",	V_BACKUP	},
96 	{ "stand",	"",	V_STAND		},
97 	{ "var",	"",	V_VAR		},
98 	{ "home",	"",	V_HOME		},
99 	{ "alternates", "",	V_ALTSCTR	},
100 	{ NULL }
101 };
102 
103 
104 /*
105  * Choices for the p_flag vtoc field
106  */
107 static slist_t pflag_choices[] = {
108 	{ "wm", "read-write, mountable",	0	},
109 	{ "wu", "read-write, unmountable",	V_UNMNT	},
110 	{ "rm", "read-only, mountable",		V_RONLY	},
111 	{ "ru", "read-only, unmountable",	V_RONLY|V_UNMNT },
112 	{ NULL }
113 };
114 
115 /*
116  * The definitions are the token types that the data file parser recognizes.
117  */
118 #define	SUP_EOF			-1		/* eof token */
119 #define	SUP_STRING		0		/* string token */
120 #define	SUP_EQL			1		/* equals token */
121 #define	SUP_COMMA		2		/* comma token */
122 #define	SUP_COLON		3		/* colon token */
123 #define	SUP_EOL			4		/* newline token */
124 #define	SUP_OR			5		/* vertical bar */
125 #define	SUP_AND			6		/* ampersand */
126 #define	SUP_TILDE		7		/* tilde */
127 
128 
129 /*
130  *	Prototypes for ANSI C compilers
131  */
132 static int32_t	sup_prxfile(char *file_name, struct vtoc *vt);
133 static int32_t	sup_setpart(struct vtoc *vt);
134 static void	sup_pushchar(int32_t c);
135 static void	clean_token(char *cleantoken, char *token);
136 static void clean_token(char *cleantoken, char *token);
137 static int32_t sup_inputchar();
138 static int32_t sup_gettoken(char *buf);
139 static int32_t sup_get_token(char *buf);
140 static int32_t find_value(slist_t *slist, char *str, int32_t *value);
141 static int32_t check_vtoc_sanity(smedia_handle_t, int32_t fd, struct vtoc *vt);
142 static int32_t str2sector(char *str);
143 static int32_t strcnt(char *s1, char *s2);
144 static int32_t get_fdisk(smedia_handle_t, int32_t fd, int32_t offset,
145 		struct fdisk_info *fdisk);
146 static void erase(smedia_handle_t handle, uint32_t offset, uint32_t size);
147 
148 extern char *myname;
149 extern int64_t my_atoll(char *ptr);
150 extern smmedium_prop_t med_info;
151 
152 static FILE *data_file;
153 
154 static int32_t
155 sup_prxfile(char *file_name, struct vtoc *vt)
156 {
157 	int32_t	status, ret_val;
158 	TOKEN	token;
159 	TOKEN	cleaned;
160 
161 	/*
162 	 * Open the data file.  Return 0 if unable to do so.
163 	 */
164 	data_file = fopen(file_name, "r");
165 	if (data_file == NULL) {
166 		PERROR("Open failed");
167 		return (-1);
168 	}
169 	/*
170 	 * Step through the data file a meta-line at a time.  There are
171 	 * typically several backslashed newlines in each meta-line,
172 	 * so data_lineno will be getting side effected along the way.
173 	 */
174 	data_lineno = 1;
175 	for (;;) {
176 
177 		/*
178 		 * Get the keyword.
179 		 */
180 		status = sup_gettoken(token);
181 		/*
182 		 * If we hit the end of the data file, we're done.
183 		 */
184 		if (status == SUP_EOF)
185 			break;
186 		/*
187 		 * If the line starts with some key character, it's an error.
188 		 */
189 		if (status != SUP_STRING) {
190 			(void) fprintf(stderr,
191 				gettext("Expecting keyword, found '%s'"),
192 			    token);
193 			(void) fprintf(stderr,
194 				gettext("Line no %d\n"), data_lineno);
195 			continue;
196 		}
197 		/*
198 		 * Clean up the token and see which keyword it is.  Call
199 		 * the appropriate routine to process the rest of the line.
200 		 */
201 		clean_token(cleaned, token);
202 		if (strcmp(cleaned, "slices") == 0) {
203 			ret_val = sup_setpart(vt);
204 			(void) fclose(data_file);
205 			return (ret_val);
206 		} else {
207 			(void) fprintf(stderr, gettext("Unknown keyword '%s'"),
208 			    cleaned);
209 			(void) fprintf(stderr,
210 				gettext("Line no %d\n"), data_lineno);
211 			(void) fclose(data_file);
212 			return (-1);
213 		}
214 	}
215 	/*
216 	 * Close the data file.
217 	 */
218 	(void) fclose(data_file);
219 
220 	(void) fprintf(stderr,
221 		gettext("Unexpected end of file (line no %d)\n"), data_lineno);
222 	return (-1);
223 }
224 
225 static int32_t
226 sup_gettoken(char *buf)
227 {
228 	/*
229 	 * Skip end of lines and blank lines.
230 	 */
231 	while ((last_token_type = sup_get_token(buf)) == SUP_EOL)
232 			;
233 	return (last_token_type);
234 }
235 
236 static int32_t
237 sup_get_token(char *buf)
238 {
239 	char	*ptr = buf;
240 	int32_t	c, quoted = 0;
241 
242 	/*
243 	 * Was an end of file detected last try?
244 	 */
245 
246 	if (feof(data_file)) {
247 		return (SUP_EOF);
248 	}
249 
250 	/*
251 	 * Zero out the returned token buffer
252 	 */
253 
254 	bzero(buf, TOKEN_SIZE + 1);
255 
256 	/*
257 	 * Strip off leading white-space.
258 	 */
259 	while (isspace(c = sup_inputchar()))
260 		;
261 
262 	/*
263 	 * Only white spaces and then end of file?
264 	 */
265 
266 	if (feof(data_file)) {
267 		return (SUP_EOF);
268 	}
269 
270 	/*
271 	 * Read in characters until we hit unquoted white-space.
272 	 */
273 	for (; !isspace(c) || quoted; c = sup_inputchar()) {
274 
275 		/*
276 		 * If we hit eof, check if we have anything in buffer.
277 		 * if we have, return STRING, next time we will return EOF
278 		 * else, return EOF here...should not happen.
279 		 */
280 		if (feof(data_file)) {
281 			if (ptr - buf > 0) {
282 				return (SUP_STRING);
283 			} else {
284 				return (SUP_EOF);
285 			}
286 		}
287 
288 		/*
289 		 * If we hit a double quote, change the state of quoting.
290 		 */
291 		if (c == '"') {
292 			quoted = !quoted;
293 			continue;
294 		}
295 		/*
296 		 * If we hit a newline, that delimits a token.
297 		 */
298 		if (c == '\n')
299 			break;
300 		/*
301 		 * If we hit any nonquoted special delimiters, that delimits
302 		 * a token.
303 		 */
304 		if (!quoted && (c == '=' || c == ',' || c == ':' ||
305 			c == '#' || c == '|' || c == '&' || c == '~'))
306 				break;
307 		/*
308 		 * Store the character if there's room left.
309 		 */
310 		if (ptr - buf < TOKEN_SIZE)
311 			*ptr++ = (char)c;
312 	}
313 	/*
314 	 * If we stored characters in the buffer, then we inputted a string.
315 	 * Push the delimiter back into the pipe and return the string.
316 	 */
317 	if (ptr - buf > 0) {
318 		sup_pushchar(c);
319 		return (SUP_STRING);
320 	}
321 	/*
322 	 * We didn't input a string, so we must have inputted a known delimiter.
323 	 * store the delimiter in the buffer, so it will get returned.
324 	 */
325 	buf[0] = c;
326 	/*
327 	 * Switch on the delimiter.  Return the appropriate value for each one.
328 	 */
329 	switch (c) {
330 	case '=':
331 		return (SUP_EQL);
332 	case ':':
333 		return (SUP_COLON);
334 	case ',':
335 		return (SUP_COMMA);
336 	case '\n':
337 		return (SUP_EOL);
338 	case '|':
339 		return (SUP_OR);
340 	case '&':
341 		return (SUP_AND);
342 	case '~':
343 		return (SUP_TILDE);
344 	case '#':
345 		/*
346 		 * For comments, we flush out the rest of the line and return
347 		 * an eol.
348 		 */
349 		while ((c = sup_inputchar()) != '\n' && !feof(data_file))
350 			;
351 		if (feof(data_file))
352 			return (SUP_EOF);
353 		else
354 			return (SUP_EOL);
355 	/*
356 	 * Shouldn't ever get here.
357 	 */
358 	default:
359 		return (SUP_STRING);
360 	}
361 }
362 static int32_t
363 sup_inputchar()
364 {
365 	int32_t	c;
366 
367 	/*
368 	 * Input the character.
369 	 */
370 	c = getc(data_file);
371 	/*
372 	 * If it's not a backslash, return it.
373 	 */
374 
375 	/*
376 	 * It was a backslash.  Get the next character.
377 	 */
378 
379 	if (c == '\\')
380 		c = getc(data_file);
381 
382 	/*
383 	 * If it was a newline, update the line counter and get the next
384 	 * character.
385 	 */
386 	if (c == '\n') {
387 		data_lineno++;
388 	}
389 	/*
390 	 * Return the character.
391 	 */
392 	return (c);
393 }
394 
395 static void
396 sup_pushchar(int32_t c)
397 {
398 
399 	(void) ungetc(c, data_file);
400 	if (c == '\n')
401 		data_lineno--;
402 }
403 
404 static void
405 clean_token(char *cleantoken, char *token)
406 {
407 	char	*ptr;
408 
409 	/*
410 	 * Strip off leading white-space.
411 	 */
412 	for (ptr = token; isspace(*ptr) && (ptr <=
413 	    (token + strlen(token) - 1)); ptr++);
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 vtoc *vt)
430 {
431 	TOKEN	token, cleaned, ident;
432 	int32_t	i, index, status, 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 int32_t
732 str2sector(char *str)
733 {
734 	int32_t mul_factor = 1;
735 	char *s1, *s2, *base;
736 	int32_t num_sectors;
737 	int64_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 = (uint64_t)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 vtoc *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 %d",  (int32_t)vt->v_part[i].p_start);
821 		DPRINTF1("\t size %d ", (int32_t)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 %d",  (int32_t)vt->v_part[i].p_start);
836 		DPRINTF1("\t size %d ", (int32_t)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)	{int32_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 vtoc *vt)
874 {
875 
876 	int32_t i, j;
877 	struct dk_geom dkg;
878 	int32_t num_backup = 0;
879 	long backup_size = 0;
880 	struct part_struct {
881 		long start;
882 		long end;
883 		int32_t num;
884 	} part[NDKMAP];
885 	long min_val, min_slice, num_slices;
886 	long media_size;
887 	int32_t cyl_size;
888 	int sparc_style = 0;	/* sparc_style handling ? */
889 	struct fdisk_info fdisk;
890 	int sol_part;
891 	int total_parts = 0;
892 
893 #ifdef sparc
894 	sparc_style = 1;
895 #endif /* sparc */
896 
897 	if ((med_info.sm_media_type == SM_FLOPPY) ||
898 	    (med_info.sm_media_type == SM_PCMCIA_MEM) ||
899 	    (med_info.sm_media_type == SM_PCMCIA_ATA) ||
900 	    (med_info.sm_media_type == SM_SCSI_FLOPPY)) {
901 		sparc_style = 1;
902 	}
903 
904 	if (sparc_style) {
905 		DPRINTF("sparc style true\n");
906 		if (ioctl(fd, DKIOCGGEOM, &dkg) < 0) {
907 			PERROR("DKIOCGGEOM Failed");
908 			return (-1);
909 		}
910 		media_size = dkg.dkg_ncyl * dkg.dkg_nhead * 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 = fdisk.part[sol_part].numsect;
942 
943 			DPRINTF1("sol_part %d\n", sol_part);
944 			DPRINTF1("media_size %d\n", (int)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 = 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 = 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) : %d, %d", 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 : %d sectors \n"), media_size);
1046 		} else {
1047 
1048 			(void) fprintf(stderr,
1049 			    gettext("Backup slice extends beyond size of FDISK \
1050 Solaris partition\n"));
1051 			(void) fprintf(stderr,
1052 			    gettext(
1053 			"FDISK Solaris partition size : %d sectors \n"),
1054 			    media_size);
1055 		}
1056 		return (-1);
1057 	}
1058 
1059 	/*
1060 	 * If we have only backup slice return success here.
1061 	 */
1062 	if (num_slices == 0)
1063 		return (0);
1064 
1065 	if (backup_size) {
1066 		if (part[num_slices - 1].end > backup_size) {
1067 			(void) fprintf(stderr,
1068 			    gettext("Slice %d extends beyond backup slice.\n"),
1069 			    part[num_slices -1].num);
1070 			return (-1);
1071 		}
1072 	} else {
1073 		if (part[num_slices - 1].end > media_size) {
1074 			if (sparc_style) {
1075 				(void) fprintf(stderr,
1076 				    gettext(
1077 				"Slice %d extends beyond media size\n"),
1078 				    part[num_slices -1].num);
1079 				(void) fprintf(stderr,
1080 					gettext("media size : %d sectors \n"),
1081 				    media_size);
1082 			} else {
1083 				(void) fprintf(stderr,
1084 				    gettext(
1085 		"Slice %d extends beyond FDISK Solaris partition size\n"),
1086 			part[num_slices -1].num);
1087 				(void) fprintf(stderr,
1088 				    gettext("FDISK Solaris partition size : %d \
1089 sectors \n"), media_size);
1090 			}
1091 			return (-1);
1092 		}
1093 	}
1094 
1095 
1096 
1097 	for (i = 0; i < num_slices; i++) {
1098 		if (i == 0)
1099 			continue;
1100 		if (part[i].start <= part[i-1].end) {
1101 			(void) fprintf(stderr,
1102 				gettext("Overlap between slices %d and %d\n"),
1103 				part[i-1].num, part[i].num);
1104 			(void) smedia_release_handle(handle);
1105 			(void) close(fd);
1106 			exit(1);
1107 		}
1108 	}
1109 
1110 	return (0);
1111 }
1112 
1113 
1114 static int32_t
1115 get_fdisk(smedia_handle_t handle, int32_t fd, int32_t offset,
1116 	struct fdisk_info *fdisk)
1117 {
1118 	struct mboot *boot_sec;
1119 	struct ipart *part;
1120 	char *buf;
1121 	int32_t i, ret;
1122 	int	save_errno;
1123 
1124 	/* Read the master boot program */
1125 
1126 	buf = (char *)malloc(med_info.sm_blocksize);
1127 	if (buf == NULL) {
1128 		PERROR("malloc failed");
1129 		exit(1);
1130 	}
1131 	errno = 0;
1132 	ret = ioctl(fd, DKIOCGMBOOT, buf);
1133 	if (ret < 0) {
1134 		if (errno != ENOTTY) {
1135 			PERROR("DKIOCGMBOOT ioctl failed");
1136 			return (-1);
1137 		}
1138 
1139 		/* Turn on privileges. */
1140 		(void) __priv_bracket(PRIV_ON);
1141 
1142 		ret = smedia_raw_read(handle, offset/med_info.sm_blocksize,
1143 			buf, med_info.sm_blocksize);
1144 
1145 		/* Turn off privileges. */
1146 		(void) __priv_bracket(PRIV_OFF);
1147 
1148 		save_errno = errno;
1149 		errno = save_errno;
1150 		if (ret != med_info.sm_blocksize) {
1151 			if (errno == ENOTSUP) {
1152 				errno = 0;
1153 				if (lseek(fd, offset, SEEK_SET)) {
1154 				    PERROR("Seek failed:");
1155 				    free(buf);
1156 				    return (-1);
1157 				}
1158 
1159 				/* Turn on privileges. */
1160 				(void) __priv_bracket(PRIV_ON);
1161 
1162 				ret = read(fd, buf, sizeof (struct mboot));
1163 
1164 				/* Turn off privileges. */
1165 				(void) __priv_bracket(PRIV_OFF);
1166 
1167 				if (ret != sizeof (struct mboot)) {
1168 				    PERROR("Could not read master boot record");
1169 				    free(buf);
1170 				    return (-1);
1171 				}
1172 			} else {
1173 				PERROR("Could not read master boot record");
1174 				free(buf);
1175 				return (-1);
1176 			}
1177 		}
1178 	}
1179 	/* LINTED pointer cast may result in improper alignment */
1180 	boot_sec = (struct mboot *)buf;
1181 
1182 	/* Is this really a master boot record? */
1183 	if (les(boot_sec->signature) != MBB_MAGIC) {
1184 		DPRINTF("fdisk: Invalid master boot file \n");
1185 		DPRINTF2("Bad magic number: is %x, should be %x.\n",
1186 			les(boot_sec->signature), MBB_MAGIC);
1187 		free(buf);
1188 		return (-1);
1189 	}
1190 
1191 	for (i = 0; i < FD_NUMPART; i++) {
1192 		DPRINTF1("part %d\n", i);
1193 		/* LINTED pointer cast may result in improper alignment */
1194 		part = (struct ipart *)&boot_sec->parts[i *
1195 		    sizeof (struct ipart)];
1196 		fdisk->part[i].bootid = part->bootid;
1197 		if (part->bootid && (part->bootid != ACTIVE)) {
1198 			/* Hmmm...not a valid fdisk! */
1199 			return (-1);
1200 		}
1201 		fdisk->part[i].systid = part->systid;
1202 
1203 		/* To avoid the misalign access in sparc */
1204 
1205 		fdisk->part[i].relsect = lel(GET_32(&(part->relsect)));
1206 		fdisk->part[i].numsect = lel(GET_32(&(part->numsect)));
1207 
1208 		DPRINTF1("\tboot id 0x%x\n", part->bootid);
1209 		DPRINTF1("\tsystem id 0x%x\n", part->systid);
1210 		DPRINTF1("\trel sector 0x%x\n", fdisk->part[i].relsect);
1211 		DPRINTF1("\tnum sector 0x%x\n", fdisk->part[i].numsect);
1212 	}
1213 	free(buf);
1214 	return (0);
1215 }
1216 
1217 
1218 /*
1219  * wrrite_defualt_label(int32_t fd)
1220  * 	fd = file descriptor for the device.
1221  *
1222  * For sparc solaris
1223  *	Create a vtoc partition with
1224  *		slice 0 = slice 2 = medium capacity.
1225  *	The cyl, head, sect (CHS) values are computed as done in sd
1226  *	capacity <= 1GB,
1227  *		nhead = 64, nsect = 32
1228  *	capacity > 1gb,
1229  *		nhead = 255, nsect = 63
1230  *
1231  * For x86 solaris
1232  *	Create a fdisk partition,
1233  *		partition 0 covers the full medium, the partition
1234  *		type is set to Solaris.
1235  *	Then create solaris vtoc. The algorithm is same as sparc solaris.
1236  *	But the capacity is reduced by 1 cyl, to leave space for fdisk table.
1237  */
1238 
1239 #ifdef sparc
1240 /*ARGSUSED*/
1241 void
1242 write_default_label(smedia_handle_t handle, int32_t fd)
1243 {
1244 
1245 	struct vtoc v_toc;
1246 	int32_t nhead, numcyl, nsect, capacity;
1247 	int32_t ret;
1248 	char asciilabel[LEN_DKL_ASCII];
1249 	char asciilabel2[LEN_DKL_ASCII] = "DEFAULT\0";
1250 	int32_t acyl = 2;
1251 
1252 
1253 	DPRINTF("Writing default vtoc\n");
1254 	(void) memset(&v_toc, 0, sizeof (v_toc));
1255 
1256 
1257 	v_toc.v_nparts = V_NUMPAR;
1258 	v_toc.v_sanity = VTOC_SANE;
1259 	v_toc.v_version = V_VERSION;
1260 	v_toc.v_sectorsz = DEV_BSIZE;
1261 
1262 	/*
1263 	 * For the head, cyl and number of sector per track,
1264 	 * if the capacity <= 1GB, head = 64, sect = 32.
1265 	 * else head = 255, sect 63
1266 	 * NOTE: the capacity should be equal to C*H*S values.
1267 	 * This will cause some truncation of size due to
1268 	 * round off errors.
1269 	 */
1270 	if (med_info.sm_capacity <= 0x200000) {
1271 		nhead = 64;
1272 		nsect = 32;
1273 	} else {
1274 		nhead = 255;
1275 		nsect = 63;
1276 	}
1277 
1278 	numcyl = med_info.sm_capacity / (nhead * nsect);
1279 	capacity = nhead * nsect * numcyl;
1280 
1281 	v_toc.v_part[0].p_start = 0;
1282 	v_toc.v_part[0].p_size = capacity;
1283 	v_toc.v_part[0].p_tag  = V_ROOT;
1284 	v_toc.v_part[0].p_flag = 0;	/* Mountable */
1285 
1286 	v_toc.v_part[2].p_start = 0;
1287 	v_toc.v_part[2].p_size = capacity;
1288 	v_toc.v_part[2].p_tag  = V_BACKUP;
1289 	v_toc.v_part[2].p_flag = V_UNMNT;
1290 
1291 	/* Create asciilabel for compatibility with format utility */
1292 	(void) snprintf(asciilabel, sizeof (asciilabel),
1293 	    "%s cyl %d alt %d hd %d sec %d",
1294 	    asciilabel2, numcyl, acyl, nhead, nsect);
1295 	(void) memcpy(v_toc.v_asciilabel, asciilabel,
1296 		LEN_DKL_ASCII);
1297 
1298 	errno = 0;
1299 
1300 	/* Turn on privileges. */
1301 	(void) __priv_bracket(PRIV_ON);
1302 
1303 	ret = write_vtoc(fd, &v_toc);
1304 
1305 	/* Turn off privileges. */
1306 	(void) __priv_bracket(PRIV_OFF);
1307 
1308 	if (ret < 0) {
1309 		PERROR("write VTOC failed");
1310 		DPRINTF1("Errno = %d\n", errno);
1311 	}
1312 }
1313 
1314 #else /* !sparc */
1315 #ifdef i386
1316 
1317 void
1318 write_default_label(smedia_handle_t handle, int32_t fd)
1319 {
1320 
1321 	int32_t i, ret;
1322 	struct dk_geom  dkg;
1323 	struct vtoc v_toc;
1324 	int tmp_fd;
1325 	char *fdisk_buf;
1326 	struct mboot boot_code;		/* Buffer for master boot record */
1327 	struct ipart parts[FD_NUMPART];
1328 	int32_t numcyl, nhead, nsect;
1329 	int32_t unixend;
1330 	int32_t blocksize;
1331 	int32_t capacity;
1332 	int	save_errno;
1333 	size_t	bytes_written;
1334 	char asciilabel[LEN_DKL_ASCII];
1335 	char asciilabel2[LEN_DKL_ASCII] = "DEFAULT\0";
1336 	int32_t acyl = 2;
1337 
1338 	DPRINTF("Writing default fdisk table and vtoc\n");
1339 	(void) memset(&v_toc, 0, sizeof (v_toc));
1340 	/*
1341 	 * Try getting disk geometry.
1342 	 */
1343 	if (ioctl(fd, DKIOCGGEOM, &dkg) < 0)
1344 		if (ioctl(fd, DKIOCG_PHYGEOM, &dkg) < 0) {
1345 
1346 			DPRINTF("DKIOCG_PHYGEOM ioctl failed");
1347 			return;
1348 	}
1349 
1350 	tmp_fd = open("/usr/lib/fs/ufs/mboot", O_RDONLY);
1351 	if (tmp_fd <= 0) {
1352 		return;
1353 	}
1354 
1355 	if (read(tmp_fd, &boot_code, sizeof (struct mboot))
1356 			!= sizeof (struct mboot)) {
1357 		(void) close(tmp_fd);
1358 		return;
1359 	}
1360 
1361 	blocksize = med_info.sm_blocksize;
1362 	fdisk_buf = (char *)malloc(blocksize);
1363 	if (fdisk_buf == NULL) {
1364 		DPRINTF("malloc for fdisk_buf failed\n");
1365 		return;
1366 	}
1367 
1368 	(void) memset(&parts, 0, sizeof (parts));
1369 
1370 	for (i = 0; i < FD_NUMPART; i++) {
1371 		parts[i].systid = UNUSED;
1372 		parts[i].numsect = lel(UNUSED);
1373 		parts[i].relsect = lel(UNUSED);
1374 		parts[i].bootid = 0;
1375 	}
1376 
1377 	numcyl = dkg.dkg_ncyl;
1378 	nhead = dkg.dkg_nhead;
1379 	nsect = dkg.dkg_nsect;
1380 
1381 	parts[0].bootid = ACTIVE;
1382 	parts[0].begsect = 1;
1383 
1384 	unixend = numcyl;
1385 
1386 	parts[0].relsect = lel(nhead * nsect);
1387 	parts[0].numsect = lel((long)((numcyl) * nhead * nsect));
1388 	parts[0].systid = SUNIXOS2;   /* Solaris */
1389 	parts[0].beghead = 0;
1390 	parts[0].begcyl = 1;
1391 	parts[0].endhead = nhead - 1;
1392 	parts[0].endsect = (nsect & 0x3f) |
1393 	    (char)((unixend >> 2) & 0x00c0);
1394 	parts[0].endcyl = (char)(unixend & 0x00ff);
1395 
1396 	(void) memcpy(&(boot_code.parts), parts, sizeof (parts));
1397 	(void) memcpy(fdisk_buf, &boot_code, sizeof (boot_code));
1398 
1399 	/* Turn on privileges. */
1400 	(void) __priv_bracket(PRIV_ON);
1401 
1402 	ret = ioctl(fd, DKIOCSMBOOT, fdisk_buf);
1403 
1404 	/* Turn off privileges. */
1405 	(void) __priv_bracket(PRIV_OFF);
1406 
1407 	if (ret == -1) {
1408 		if (errno != ENOTTY) {
1409 			PERROR("DKIOCSMBOOT ioctl Failed");
1410 			return;
1411 		}
1412 
1413 		/* Turn on privileges. */
1414 		(void) __priv_bracket(PRIV_ON);
1415 
1416 		bytes_written = smedia_raw_write(handle, 0, fdisk_buf,
1417 			blocksize);
1418 
1419 		/* Turn off privileges. */
1420 		(void) __priv_bracket(PRIV_OFF);
1421 
1422 		save_errno = errno;
1423 		errno = save_errno;
1424 		if (bytes_written != blocksize) {
1425 			if (errno == ENOTSUP) {
1426 
1427 			    /* Turn on privileges. */
1428 			    (void) __priv_bracket(PRIV_ON);
1429 
1430 			    ret = write(fd, fdisk_buf, blocksize);
1431 
1432 			    /* Turn off privileges. */
1433 			    (void) __priv_bracket(PRIV_OFF);
1434 
1435 			    if (ret != blocksize) {
1436 					return;
1437 			    }
1438 			} else {
1439 				return;
1440 			}
1441 		}
1442 	}
1443 	capacity = (numcyl - 1) * nhead * nsect;
1444 
1445 	v_toc.v_nparts = V_NUMPAR;
1446 	v_toc.v_sanity = VTOC_SANE;
1447 	v_toc.v_version = V_VERSION;
1448 	v_toc.v_sectorsz = DEV_BSIZE;
1449 
1450 	v_toc.v_part[0].p_start = 0;
1451 	v_toc.v_part[0].p_size = capacity;
1452 	v_toc.v_part[0].p_tag  = V_ROOT;
1453 	v_toc.v_part[0].p_flag = 0;	/* Mountable */
1454 
1455 	v_toc.v_part[2].p_start = 0;
1456 	v_toc.v_part[2].p_size = capacity;
1457 	v_toc.v_part[2].p_tag  = V_BACKUP;
1458 	v_toc.v_part[2].p_flag = V_UNMNT;
1459 
1460 	/* Create asciilabel for compatibility with format utility */
1461 	(void) snprintf(asciilabel, sizeof (asciilabel),
1462 	    "%s cyl %d alt %d hd %d sec %d",
1463 	    asciilabel2, numcyl, acyl, nhead, nsect);
1464 	(void) memcpy(v_toc.v_asciilabel, asciilabel,
1465 		LEN_DKL_ASCII);
1466 
1467 	errno = 0;
1468 
1469 
1470 	/* Turn on privileges. */
1471 	(void) __priv_bracket(PRIV_ON);
1472 
1473 	ret = write_vtoc(fd, &v_toc);
1474 
1475 	/* Turn off privileges. */
1476 	(void) __priv_bracket(PRIV_OFF);
1477 
1478 	if (ret < 0) {
1479 		PERROR("write VTOC failed");
1480 		DPRINTF1("Errno = %d\n", errno);
1481 	}
1482 }
1483 
1484 #else	/* !i386 */
1485 
1486 #error One of sparc or i386 must be defined!
1487 
1488 #endif /* i386 */
1489 #endif /* sparc */
1490 
1491 /*
1492  * void overwrite_metadata(int32_t fd, smedia_handle_t handle)
1493  *
1494  * purpose : quick format does not erase the data on Iomega
1495  * zip/jaz media. So, the meta data on the disk should be erased.
1496  *
1497  * If there is a valid fdisk table,
1498  * 	erase first 64K of each partition.
1499  * If there is a valid vtoc,
1500  * 	erase first 64k of each slice.
1501  * Then erase the 0th sector (the home for vtoc and fdisk) of the disk.
1502  * Note that teh vtoc on x86 resides in one of the fdisk partition.
1503  * So delay the erasing of the solaris partition until the vtoc is read.
1504  */
1505 
1506 void
1507 overwrite_metadata(int32_t fd, smedia_handle_t handle)
1508 {
1509 
1510 	struct fdisk_info fdisk;
1511 	uint32_t sol_offset = 0;
1512 	int i, ret;
1513 	struct vtoc t_vtoc;
1514 #ifdef i386
1515 	uint32_t sol_size = 0;
1516 	int32_t active = 0;
1517 #endif /* i386 */
1518 
1519 	/* Get fdisk info. */
1520 	if (get_fdisk(handle, fd, 0, &fdisk) >= 0) {
1521 		/* Got a valid fdisk */
1522 		for (i = 0; i < FD_NUMPART; i++) {
1523 
1524 			if (fdisk.part[i].numsect == 0)
1525 				continue;
1526 			if ((fdisk.part[i].systid == UNUSED) ||
1527 				(fdisk.part[i].systid == 0))
1528 				continue;
1529 #ifdef i386
1530 			if (fdisk.part[i].systid == SUNIXOS ||
1531 			    fdisk.part[i].systid == SUNIXOS2) {
1532 				if (!sol_offset) {
1533 					sol_offset = fdisk.part[i].relsect;
1534 					sol_size = fdisk.part[i].numsect;
1535 					if (fdisk.part[i].bootid == ACTIVE)
1536 						active = 1;
1537 					continue;
1538 				} else if ((fdisk.part[i].bootid == ACTIVE) &&
1539 				    (!active)) {
1540 					erase(handle, sol_offset, sol_size);
1541 					sol_offset = fdisk.part[i].relsect;
1542 					sol_size = fdisk.part[i].numsect;
1543 					active = 1;
1544 					continue;
1545 				}
1546 			}
1547 #endif /* i386 */
1548 			erase(handle, fdisk.part[i].relsect,
1549 			    fdisk.part[i].numsect);
1550 		}
1551 	}
1552 
1553 	(void) memset(&t_vtoc, 0, sizeof (t_vtoc));
1554 
1555 	if (sol_offset) {
1556 		/* fdisk x86 Solaris partition */
1557 		/* VTOC location in solaris partition is DK_LABEL_LOC */
1558 
1559 		/* Turn on privileges. */
1560 		(void) __priv_bracket(PRIV_ON);
1561 
1562 		ret = read_vtoc(fd, &t_vtoc);
1563 
1564 		/* Turn off privileges. */
1565 		(void) __priv_bracket(PRIV_OFF);
1566 
1567 		if (ret < 0) {
1568 			/* No valid vtoc, erase fdisk table. */
1569 			erase(handle, 0, 1);
1570 			return;
1571 		}
1572 	} else {
1573 		/* Sparc Solaris or x86 solaris with faked fdisk */
1574 
1575 		/* Turn on privileges */
1576 		(void) __priv_bracket(PRIV_ON);
1577 
1578 		ret = read_vtoc(fd, &t_vtoc);
1579 
1580 		/* Turn off privileges. */
1581 		(void) __priv_bracket(PRIV_OFF);
1582 
1583 		if (ret < 0) {
1584 			/* No valid vtoc, erase from 0th sector */
1585 			erase(handle, 0, med_info.sm_capacity);
1586 			return;
1587 		}
1588 	}
1589 
1590 	for (i = 0; i < V_NUMPAR; i++) {
1591 		if (t_vtoc.v_part[i].p_size != 0) {
1592 			erase(handle, sol_offset + t_vtoc.v_part[i].p_start,
1593 				t_vtoc.v_part[i].p_size);
1594 			/*
1595 			 * To make the udfs not recognise the partition we will
1596 			 * erase sectors 256, (p_size-256) and psize.
1597 			 */
1598 			erase(handle,
1599 				sol_offset + t_vtoc.v_part[i].p_start + 256,
1600 				1);
1601 			erase(handle,
1602 				(sol_offset + t_vtoc.v_part[i].p_start +
1603 				t_vtoc.v_part[i].p_size - 256),
1604 				1);
1605 			erase(handle,
1606 				(sol_offset + t_vtoc.v_part[i].p_start +
1607 				t_vtoc.v_part[i].p_size - 1),
1608 				1);
1609 		}
1610 	}
1611 
1612 	/*
1613 	 * If x86 fdisk solaris partition, erase the vtoc also.
1614 	 * for sparc, the erasing 0the sector erases vtoc.
1615 	 */
1616 	if (sol_offset) {
1617 		erase(handle, sol_offset, DK_LABEL_LOC + 2);
1618 	}
1619 
1620 	/*
1621 	 * erase the 0th sector, it is not guaranteed to be
1622 	 * erased in the above sequence.
1623 	 */
1624 
1625 	erase(handle, 0, 1);
1626 }
1627 
1628 /*
1629  * void erase(smedia_handle_t handle, uint32_t offset, uint32_t size)
1630  *
1631  * Initialize the media with '0' from offset 'offset' upto 'size'
1632  * or 128 blocks(64k), whichever is smaller.
1633  */
1634 
1635 static void
1636 erase(smedia_handle_t handle, uint32_t offset, uint32_t size)
1637 {
1638 	char *buf;
1639 	int32_t nblocks = size;
1640 	int32_t ret;
1641 
1642 
1643 	nblocks = (nblocks < 128) ? nblocks : 128;
1644 	buf = (char *)malloc(nblocks * med_info.sm_blocksize);
1645 	if (buf == NULL) {
1646 		PERROR("malloc failed");
1647 		return;
1648 	}
1649 	(void) memset(buf, 0, nblocks * med_info.sm_blocksize);
1650 
1651 	/* Turn on privileges. */
1652 	(void) __priv_bracket(PRIV_ON);
1653 
1654 	ret = smedia_raw_write(handle, offset, buf,
1655 	    nblocks * med_info.sm_blocksize);
1656 
1657 	/* Turn off privileges. */
1658 	(void) __priv_bracket(PRIV_OFF);
1659 
1660 	if (ret != (nblocks * med_info.sm_blocksize))
1661 		PERROR("error in writing\n");
1662 
1663 	free(buf);
1664 
1665 }
1666