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