xref: /illumos-gate/usr/src/cmd/fs.d/ufs/newfs/newfs.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate 
23*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
24*7c478bd9Sstevel@tonic-gate 	/* from UCB 5.2 9/11/85 */
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate /*
27*7c478bd9Sstevel@tonic-gate  * newfs: friendly front end to mkfs
28*7c478bd9Sstevel@tonic-gate  *
29*7c478bd9Sstevel@tonic-gate  * Copyright 1991, 1997, 2001-2003 Sun Microsystems, Inc.  All rights reserved.
30*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
35*7c478bd9Sstevel@tonic-gate #include <locale.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/buf.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include <errno.h>
44*7c478bd9Sstevel@tonic-gate #include <stdio.h>
45*7c478bd9Sstevel@tonic-gate #include <string.h>
46*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
47*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
48*7c478bd9Sstevel@tonic-gate #include <stdio.h>
49*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
50*7c478bd9Sstevel@tonic-gate #include <unistd.h>
51*7c478bd9Sstevel@tonic-gate #include <limits.h>
52*7c478bd9Sstevel@tonic-gate #include <libintl.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/vtoc.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/efi_partition.h>
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate #include <fslib.h>
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate static unsigned int number(char *, char *, int, int);
61*7c478bd9Sstevel@tonic-gate static int64_t number64(char *, char *, int, int64_t);
62*7c478bd9Sstevel@tonic-gate static diskaddr_t getdiskbydev(char *);
63*7c478bd9Sstevel@tonic-gate static int  yes(void);
64*7c478bd9Sstevel@tonic-gate static int  notrand(char *);
65*7c478bd9Sstevel@tonic-gate static void usage();
66*7c478bd9Sstevel@tonic-gate static diskaddr_t get_device_size(int, char *);
67*7c478bd9Sstevel@tonic-gate static diskaddr_t brute_force_get_device_size(int);
68*7c478bd9Sstevel@tonic-gate static int validate_size(char *disk, diskaddr_t size);
69*7c478bd9Sstevel@tonic-gate static void exenv(void);
70*7c478bd9Sstevel@tonic-gate static struct fs *read_sb(char *);
71*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
72*7c478bd9Sstevel@tonic-gate static void fatal(char *fmt, ...);
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate #define	EPATH "PATH=/usr/sbin:/sbin:"
75*7c478bd9Sstevel@tonic-gate #define	CPATH "/sbin"					/* an EPATH element */
76*7c478bd9Sstevel@tonic-gate #define	MB (1024 * 1024)
77*7c478bd9Sstevel@tonic-gate #define	GBSEC ((1024 * 1024 * 1024) / DEV_BSIZE)	/* sectors in a GB */
78*7c478bd9Sstevel@tonic-gate #define	MINFREESEC ((64 * 1024 * 1024) / DEV_BSIZE)	/* sectors in 64 MB */
79*7c478bd9Sstevel@tonic-gate #define	MINCPG (16)	/* traditional */
80*7c478bd9Sstevel@tonic-gate #define	MAXDEFDENSITY (8 * 1024)	/* arbitrary */
81*7c478bd9Sstevel@tonic-gate #define	MINDENSITY (2 * 1024)	/* traditional */
82*7c478bd9Sstevel@tonic-gate #define	MIN_MTB_DENSITY (1024 * 1024)
83*7c478bd9Sstevel@tonic-gate #define	POWEROF2(num)	(((num) & ((num) - 1)) == 0)
84*7c478bd9Sstevel@tonic-gate #define	SECTORS_PER_TERABYTE	(1LL << 31)
85*7c478bd9Sstevel@tonic-gate /*
86*7c478bd9Sstevel@tonic-gate  * The following constant specifies an upper limit for file system size
87*7c478bd9Sstevel@tonic-gate  * that is actually a lot bigger than we expect to support with UFS. (Since
88*7c478bd9Sstevel@tonic-gate  * it's specified in sectors, the file system size would be 2**44 * 512,
89*7c478bd9Sstevel@tonic-gate  * which is 2**53, which is 8192 Terabytes.)  However, it's useful
90*7c478bd9Sstevel@tonic-gate  * for checking the basic sanity of a size value that is input on the
91*7c478bd9Sstevel@tonic-gate  * command line.
92*7c478bd9Sstevel@tonic-gate  */
93*7c478bd9Sstevel@tonic-gate #define	FS_SIZE_UPPER_LIMIT	0x100000000000LL
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate /* For use with number() */
96*7c478bd9Sstevel@tonic-gate #define	NR_NONE		0
97*7c478bd9Sstevel@tonic-gate #define	NR_PERCENT	0x01
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate /*
100*7c478bd9Sstevel@tonic-gate  * The following two constants set the default block and fragment sizes.
101*7c478bd9Sstevel@tonic-gate  * Both constants must be a power of 2 and meet the following constraints:
102*7c478bd9Sstevel@tonic-gate  *	MINBSIZE <= DESBLKSIZE <= MAXBSIZE
103*7c478bd9Sstevel@tonic-gate  *	DEV_BSIZE <= DESFRAGSIZE <= DESBLKSIZE
104*7c478bd9Sstevel@tonic-gate  *	DESBLKSIZE / DESFRAGSIZE <= 8
105*7c478bd9Sstevel@tonic-gate  */
106*7c478bd9Sstevel@tonic-gate #define	DESBLKSIZE	8192
107*7c478bd9Sstevel@tonic-gate #define	DESFRAGSIZE	1024
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate static int	Nflag;		/* run mkfs without writing file system */
110*7c478bd9Sstevel@tonic-gate static int	Tflag;		/* set up file system for growth to over 1 TB */
111*7c478bd9Sstevel@tonic-gate static int	verbose;	/* show mkfs line before exec */
112*7c478bd9Sstevel@tonic-gate static int	fsize = 0;		/* fragment size */
113*7c478bd9Sstevel@tonic-gate static int	fsize_flag = 0;	/* fragment size was specified on cmd line */
114*7c478bd9Sstevel@tonic-gate static int	bsize;		/* block size */
115*7c478bd9Sstevel@tonic-gate static int	ntracks;	/* # tracks/cylinder */
116*7c478bd9Sstevel@tonic-gate static int	ntracks_set = 0; /* true if the user specified ntracks */
117*7c478bd9Sstevel@tonic-gate static int	optim = FS_OPTTIME;	/* optimization, t(ime) or s(pace) */
118*7c478bd9Sstevel@tonic-gate static int	nsectors;	/* # sectors/track */
119*7c478bd9Sstevel@tonic-gate static int	cpg;		/* cylinders/cylinder group */
120*7c478bd9Sstevel@tonic-gate static int	cpg_set = 0;	/* true if the user specified cpg */
121*7c478bd9Sstevel@tonic-gate static int	minfree = -1;	/* free space threshold */
122*7c478bd9Sstevel@tonic-gate static int	rpm;		/* revolutions/minute of drive */
123*7c478bd9Sstevel@tonic-gate static int	rpm_set = 0;	/* true if the user specified rpm */
124*7c478bd9Sstevel@tonic-gate static int	nrpos = 8;	/* # of distinguished rotational positions */
125*7c478bd9Sstevel@tonic-gate 				/* 8 is the historical default */
126*7c478bd9Sstevel@tonic-gate static int	nrpos_set = 0;	/* true if the user specified nrpos */
127*7c478bd9Sstevel@tonic-gate static int	density = 0;	/* number of bytes per inode */
128*7c478bd9Sstevel@tonic-gate static int	apc;		/* alternates per cylinder */
129*7c478bd9Sstevel@tonic-gate static int	apc_set = 0;	/* true if the user specified apc */
130*7c478bd9Sstevel@tonic-gate static int 	rot = -1;	/* rotational delay (msecs) */
131*7c478bd9Sstevel@tonic-gate static int	rot_set = 0;	/* true if the user specified rot */
132*7c478bd9Sstevel@tonic-gate static int 	maxcontig = -1;	/* maximum number of contig blocks */
133*7c478bd9Sstevel@tonic-gate static int	label_type;	/* see types below */
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate #define	LABEL_TYPE_VTOC		1
136*7c478bd9Sstevel@tonic-gate #define	LABEL_TYPE_EFI		2
137*7c478bd9Sstevel@tonic-gate #define	LABEL_TYPE_OTHER	3
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate static char	device[MAXPATHLEN];
140*7c478bd9Sstevel@tonic-gate static char	cmd[BUFSIZ];
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate extern	char	*getfullrawname(); /* from libadm */
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate int
145*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
146*7c478bd9Sstevel@tonic-gate {
147*7c478bd9Sstevel@tonic-gate 	char *special, *name;
148*7c478bd9Sstevel@tonic-gate 	struct stat64 st;
149*7c478bd9Sstevel@tonic-gate 	int status;
150*7c478bd9Sstevel@tonic-gate 	int option;
151*7c478bd9Sstevel@tonic-gate 	struct fs *sbp;	/* Pointer to superblock (if present) */
152*7c478bd9Sstevel@tonic-gate 	diskaddr_t actual_fssize;
153*7c478bd9Sstevel@tonic-gate 	diskaddr_t max_possible_fssize;
154*7c478bd9Sstevel@tonic-gate 	diskaddr_t req_fssize = 0;
155*7c478bd9Sstevel@tonic-gate 	diskaddr_t fssize = 0;
156*7c478bd9Sstevel@tonic-gate 	char	*req_fssize_str = NULL; /* requested size argument */
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
161*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
162*7c478bd9Sstevel@tonic-gate #endif
163*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	opterr = 0;	/* We print our own errors, disable getopt's message */
166*7c478bd9Sstevel@tonic-gate 	while ((option = getopt(argc, argv, "vNs:C:d:t:o:a:b:f:c:m:n:r:i:T"))
167*7c478bd9Sstevel@tonic-gate 	    != EOF) {
168*7c478bd9Sstevel@tonic-gate 		switch (option) {
169*7c478bd9Sstevel@tonic-gate 		case 'v':
170*7c478bd9Sstevel@tonic-gate 			verbose++;
171*7c478bd9Sstevel@tonic-gate 			break;
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate 		case 'N':
174*7c478bd9Sstevel@tonic-gate 			Nflag++;
175*7c478bd9Sstevel@tonic-gate 			break;
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 		case 's':
178*7c478bd9Sstevel@tonic-gate 			/*
179*7c478bd9Sstevel@tonic-gate 			 * The maximum file system size is a lot smaller
180*7c478bd9Sstevel@tonic-gate 			 * than FS_SIZE_UPPER_LIMIT, but until we find out
181*7c478bd9Sstevel@tonic-gate 			 * the device size and block size, we don't know
182*7c478bd9Sstevel@tonic-gate 			 * what it is.  So save the requested size in a
183*7c478bd9Sstevel@tonic-gate 			 * string so that we can print it out later if we
184*7c478bd9Sstevel@tonic-gate 			 * determine it's too big.
185*7c478bd9Sstevel@tonic-gate 			 */
186*7c478bd9Sstevel@tonic-gate 			req_fssize = number64("fssize", optarg, NR_NONE,
187*7c478bd9Sstevel@tonic-gate 			    FS_SIZE_UPPER_LIMIT);
188*7c478bd9Sstevel@tonic-gate 			if (req_fssize < 1024)
189*7c478bd9Sstevel@tonic-gate 				fatal(gettext(
190*7c478bd9Sstevel@tonic-gate 				    "%s: fssize must be at least 1024"),
191*7c478bd9Sstevel@tonic-gate 				    optarg);
192*7c478bd9Sstevel@tonic-gate 			req_fssize_str = strdup(optarg);
193*7c478bd9Sstevel@tonic-gate 			if (req_fssize_str == NULL)
194*7c478bd9Sstevel@tonic-gate 				fatal(gettext(
195*7c478bd9Sstevel@tonic-gate 				    "Insufficient memory for string copy."));
196*7c478bd9Sstevel@tonic-gate 			break;
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 		case 'C':
199*7c478bd9Sstevel@tonic-gate 			maxcontig = number("maxcontig", optarg, NR_NONE, -1);
200*7c478bd9Sstevel@tonic-gate 			if (maxcontig < 0)
201*7c478bd9Sstevel@tonic-gate 				fatal(gettext("%s: bad maxcontig"), optarg);
202*7c478bd9Sstevel@tonic-gate 			break;
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 		case 'd':
205*7c478bd9Sstevel@tonic-gate 			rot = number("rotdelay", optarg, NR_NONE, 0);
206*7c478bd9Sstevel@tonic-gate 			rot_set = 1;
207*7c478bd9Sstevel@tonic-gate 			if (rot < 0 || rot > 1000)
208*7c478bd9Sstevel@tonic-gate 				fatal(gettext(
209*7c478bd9Sstevel@tonic-gate 				    "%s: bad rotational delay"), optarg);
210*7c478bd9Sstevel@tonic-gate 			break;
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 		case 't':
213*7c478bd9Sstevel@tonic-gate 			ntracks = number("ntrack", optarg, NR_NONE, 16);
214*7c478bd9Sstevel@tonic-gate 			ntracks_set = 1;
215*7c478bd9Sstevel@tonic-gate 			if ((ntracks < 0) ||
216*7c478bd9Sstevel@tonic-gate 			    (ntracks > INT_MAX))
217*7c478bd9Sstevel@tonic-gate 				fatal(gettext("%s: bad total tracks"), optarg);
218*7c478bd9Sstevel@tonic-gate 			break;
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 		case 'o':
221*7c478bd9Sstevel@tonic-gate 			if (strcmp(optarg, "space") == 0)
222*7c478bd9Sstevel@tonic-gate 			    optim = FS_OPTSPACE;
223*7c478bd9Sstevel@tonic-gate 			else if (strcmp(optarg, "time") == 0)
224*7c478bd9Sstevel@tonic-gate 			    optim = FS_OPTTIME;
225*7c478bd9Sstevel@tonic-gate 			else
226*7c478bd9Sstevel@tonic-gate 			    fatal(gettext(
227*7c478bd9Sstevel@tonic-gate "%s: bad optimization preference (options are `space' or `time')"),
228*7c478bd9Sstevel@tonic-gate 				optarg);
229*7c478bd9Sstevel@tonic-gate 			break;
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 		case 'a':
232*7c478bd9Sstevel@tonic-gate 			apc = number("apc", optarg, NR_NONE, 0);
233*7c478bd9Sstevel@tonic-gate 			apc_set = 1;
234*7c478bd9Sstevel@tonic-gate 			if (apc < 0 || apc > 32768) /* see mkfs.c */
235*7c478bd9Sstevel@tonic-gate 				fatal(gettext(
236*7c478bd9Sstevel@tonic-gate 				    "%s: bad alternates per cyl"), optarg);
237*7c478bd9Sstevel@tonic-gate 			break;
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 		case 'b':
240*7c478bd9Sstevel@tonic-gate 			bsize = number("bsize", optarg, NR_NONE, DESBLKSIZE);
241*7c478bd9Sstevel@tonic-gate 			if (bsize < MINBSIZE || bsize > MAXBSIZE)
242*7c478bd9Sstevel@tonic-gate 				fatal(gettext(
243*7c478bd9Sstevel@tonic-gate 				    "%s: bad block size"), optarg);
244*7c478bd9Sstevel@tonic-gate 			break;
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 		case 'f':
247*7c478bd9Sstevel@tonic-gate 			fsize = number("fragsize", optarg, NR_NONE,
248*7c478bd9Sstevel@tonic-gate 				DESFRAGSIZE);
249*7c478bd9Sstevel@tonic-gate 			fsize_flag++;
250*7c478bd9Sstevel@tonic-gate 			/* xxx ought to test against bsize for upper limit */
251*7c478bd9Sstevel@tonic-gate 			if (fsize < DEV_BSIZE)
252*7c478bd9Sstevel@tonic-gate 				fatal(gettext("%s: bad frag size"), optarg);
253*7c478bd9Sstevel@tonic-gate 			break;
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 		case 'c':
256*7c478bd9Sstevel@tonic-gate 			cpg = number("cpg", optarg, NR_NONE, 16);
257*7c478bd9Sstevel@tonic-gate 			cpg_set = 1;
258*7c478bd9Sstevel@tonic-gate 			if (cpg < 1)
259*7c478bd9Sstevel@tonic-gate 				fatal(gettext("%s: bad cylinders/group"),
260*7c478bd9Sstevel@tonic-gate 				    optarg);
261*7c478bd9Sstevel@tonic-gate 			break;
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 		case 'm':
264*7c478bd9Sstevel@tonic-gate 			minfree = number("minfree", optarg, NR_PERCENT, 10);
265*7c478bd9Sstevel@tonic-gate 			if (minfree < 0 || minfree > 99)
266*7c478bd9Sstevel@tonic-gate 				fatal(gettext("%s: bad free space %%"), optarg);
267*7c478bd9Sstevel@tonic-gate 			break;
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 		case 'n':
270*7c478bd9Sstevel@tonic-gate 			nrpos = number("nrpos", optarg, NR_NONE, 8);
271*7c478bd9Sstevel@tonic-gate 			nrpos_set = 1;
272*7c478bd9Sstevel@tonic-gate 			if (nrpos <= 0)
273*7c478bd9Sstevel@tonic-gate 				fatal(gettext(
274*7c478bd9Sstevel@tonic-gate 				    "%s: bad number of rotational positions"),
275*7c478bd9Sstevel@tonic-gate 				    optarg);
276*7c478bd9Sstevel@tonic-gate 			break;
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 		case 'r':
279*7c478bd9Sstevel@tonic-gate 			rpm = number("rpm", optarg, NR_NONE, 3600);
280*7c478bd9Sstevel@tonic-gate 			rpm_set = 1;
281*7c478bd9Sstevel@tonic-gate 			if (rpm < 0)
282*7c478bd9Sstevel@tonic-gate 				fatal(gettext("%s: bad revs/minute"), optarg);
283*7c478bd9Sstevel@tonic-gate 			break;
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 		case 'i':
286*7c478bd9Sstevel@tonic-gate 			/* xxx ought to test against fsize */
287*7c478bd9Sstevel@tonic-gate 			density = number("nbpi", optarg, NR_NONE, 2048);
288*7c478bd9Sstevel@tonic-gate 			if (density < DEV_BSIZE)
289*7c478bd9Sstevel@tonic-gate 				fatal(gettext("%s: bad bytes per inode"),
290*7c478bd9Sstevel@tonic-gate 				    optarg);
291*7c478bd9Sstevel@tonic-gate 			break;
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 		case 'T':
294*7c478bd9Sstevel@tonic-gate 			Tflag++;
295*7c478bd9Sstevel@tonic-gate 			break;
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 		default:
298*7c478bd9Sstevel@tonic-gate 			usage();
299*7c478bd9Sstevel@tonic-gate 			fatal(gettext("-%c: unknown flag"), optopt);
300*7c478bd9Sstevel@tonic-gate 		}
301*7c478bd9Sstevel@tonic-gate 	}
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	/* At this point, there should only be one argument left:	*/
304*7c478bd9Sstevel@tonic-gate 	/* The raw-special-device itself. If not, print usage message.	*/
305*7c478bd9Sstevel@tonic-gate 	if ((argc - optind) != 1) {
306*7c478bd9Sstevel@tonic-gate 		usage();
307*7c478bd9Sstevel@tonic-gate 		exit(1);
308*7c478bd9Sstevel@tonic-gate 	}
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	name = argv[optind];
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	special = getfullrawname(name);
313*7c478bd9Sstevel@tonic-gate 	if (special == NULL) {
314*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("newfs: malloc failed\n"));
315*7c478bd9Sstevel@tonic-gate 		exit(1);
316*7c478bd9Sstevel@tonic-gate 	}
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	if (*special == '\0') {
319*7c478bd9Sstevel@tonic-gate 		if (strchr(name, '/') != NULL) {
320*7c478bd9Sstevel@tonic-gate 			if (stat64(name, &st) < 0) {
321*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
322*7c478bd9Sstevel@tonic-gate 				    gettext("newfs: %s: %s\n"),
323*7c478bd9Sstevel@tonic-gate 				    name, strerror(errno));
324*7c478bd9Sstevel@tonic-gate 				exit(2);
325*7c478bd9Sstevel@tonic-gate 			}
326*7c478bd9Sstevel@tonic-gate 			fatal(gettext("%s: not a raw disk device"), name);
327*7c478bd9Sstevel@tonic-gate 		}
328*7c478bd9Sstevel@tonic-gate 		(void) sprintf(device, "/dev/rdsk/%s", name);
329*7c478bd9Sstevel@tonic-gate 		if ((special = getfullrawname(device)) == NULL) {
330*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
331*7c478bd9Sstevel@tonic-gate 			    gettext("newfs: malloc failed\n"));
332*7c478bd9Sstevel@tonic-gate 			exit(1);
333*7c478bd9Sstevel@tonic-gate 		}
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 		if (*special == '\0') {
336*7c478bd9Sstevel@tonic-gate 			(void) sprintf(device, "/dev/%s", name);
337*7c478bd9Sstevel@tonic-gate 			if ((special = getfullrawname(device)) == NULL) {
338*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
339*7c478bd9Sstevel@tonic-gate 				    gettext("newfs: malloc failed\n"));
340*7c478bd9Sstevel@tonic-gate 				exit(1);
341*7c478bd9Sstevel@tonic-gate 			}
342*7c478bd9Sstevel@tonic-gate 			if (*special == '\0')
343*7c478bd9Sstevel@tonic-gate 				fatal(gettext(
344*7c478bd9Sstevel@tonic-gate 				    "%s: not a raw disk device"), name);
345*7c478bd9Sstevel@tonic-gate 		}
346*7c478bd9Sstevel@tonic-gate 	}
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 	/*
349*7c478bd9Sstevel@tonic-gate 	 * getdiskbydev() determines the characteristics of the special
350*7c478bd9Sstevel@tonic-gate 	 * device on which the file system will be built.  In the case
351*7c478bd9Sstevel@tonic-gate 	 * of devices with SMI labels (that is, non-EFI labels), the
352*7c478bd9Sstevel@tonic-gate 	 * following characteristics are set (if they were not already
353*7c478bd9Sstevel@tonic-gate 	 * set on the command line, since the command line settings
354*7c478bd9Sstevel@tonic-gate 	 * take precedence):
355*7c478bd9Sstevel@tonic-gate 	 *
356*7c478bd9Sstevel@tonic-gate 	 *	nsectors - sectors per track
357*7c478bd9Sstevel@tonic-gate 	 *	ntracks - tracks per cylinder
358*7c478bd9Sstevel@tonic-gate 	 *	rpm - disk revolutions per minute
359*7c478bd9Sstevel@tonic-gate 	 *
360*7c478bd9Sstevel@tonic-gate 	 *	apc is NOT set
361*7c478bd9Sstevel@tonic-gate 	 *
362*7c478bd9Sstevel@tonic-gate 	 * getdiskbydev() also sets the following quantities for all
363*7c478bd9Sstevel@tonic-gate 	 * devices, if not already set:
364*7c478bd9Sstevel@tonic-gate 	 *
365*7c478bd9Sstevel@tonic-gate 	 *	bsize - file system block size
366*7c478bd9Sstevel@tonic-gate 	 *	maxcontig
367*7c478bd9Sstevel@tonic-gate 	 *	label_type (efi, vtoc, or other)
368*7c478bd9Sstevel@tonic-gate 	 *
369*7c478bd9Sstevel@tonic-gate 	 * getdiskbydev() returns the actual size of the device, in
370*7c478bd9Sstevel@tonic-gate 	 * sectors.
371*7c478bd9Sstevel@tonic-gate 	 */
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	actual_fssize = getdiskbydev(special);
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 	if (req_fssize == 0) {
376*7c478bd9Sstevel@tonic-gate 		fssize = actual_fssize;
377*7c478bd9Sstevel@tonic-gate 	} else {
378*7c478bd9Sstevel@tonic-gate 		/*
379*7c478bd9Sstevel@tonic-gate 		 * If the user specified a size larger than what we've
380*7c478bd9Sstevel@tonic-gate 		 * determined as the actual size of the device, see if the
381*7c478bd9Sstevel@tonic-gate 		 * size specified by the user can be read.  If so, use it,
382*7c478bd9Sstevel@tonic-gate 		 * since some devices and volume managers may not support
383*7c478bd9Sstevel@tonic-gate 		 * the vtoc and EFI interfaces we use to determine device
384*7c478bd9Sstevel@tonic-gate 		 * size.
385*7c478bd9Sstevel@tonic-gate 		 */
386*7c478bd9Sstevel@tonic-gate 		if (req_fssize > actual_fssize &&
387*7c478bd9Sstevel@tonic-gate 		    validate_size(special, req_fssize)) {
388*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
389*7c478bd9Sstevel@tonic-gate "Warning: the requested size of this file system\n"
390*7c478bd9Sstevel@tonic-gate "(%lld sectors) is greater than the size of the\n"
391*7c478bd9Sstevel@tonic-gate "device reported by the driver (%lld sectors).\n"
392*7c478bd9Sstevel@tonic-gate "However, a read of the device at the requested size\n"
393*7c478bd9Sstevel@tonic-gate "does succeed, so the requested size will be used.\n"),
394*7c478bd9Sstevel@tonic-gate 			    req_fssize, actual_fssize);
395*7c478bd9Sstevel@tonic-gate 			fssize = req_fssize;
396*7c478bd9Sstevel@tonic-gate 		} else {
397*7c478bd9Sstevel@tonic-gate 			fssize = MIN(req_fssize, actual_fssize);
398*7c478bd9Sstevel@tonic-gate 		}
399*7c478bd9Sstevel@tonic-gate 	}
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 	if (label_type == LABEL_TYPE_VTOC) {
402*7c478bd9Sstevel@tonic-gate 		if (nsectors < 0)
403*7c478bd9Sstevel@tonic-gate 			fatal(gettext("%s: no default #sectors/track"),
404*7c478bd9Sstevel@tonic-gate 			    special);
405*7c478bd9Sstevel@tonic-gate 		if (ntracks < 0)
406*7c478bd9Sstevel@tonic-gate 			fatal(gettext("%s: no default #tracks"), special);
407*7c478bd9Sstevel@tonic-gate 		if (rpm < 0)
408*7c478bd9Sstevel@tonic-gate 			fatal(gettext(
409*7c478bd9Sstevel@tonic-gate 			    "%s: no default revolutions/minute value"),
410*7c478bd9Sstevel@tonic-gate 			    special);
411*7c478bd9Sstevel@tonic-gate 		if (rpm < 60) {
412*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
413*7c478bd9Sstevel@tonic-gate 			    gettext("Warning: setting rpm to 60\n"));
414*7c478bd9Sstevel@tonic-gate 			rpm = 60;
415*7c478bd9Sstevel@tonic-gate 		}
416*7c478bd9Sstevel@tonic-gate 	}
417*7c478bd9Sstevel@tonic-gate 	if (label_type == LABEL_TYPE_EFI || label_type == LABEL_TYPE_OTHER) {
418*7c478bd9Sstevel@tonic-gate 		if (ntracks_set)
419*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
420*7c478bd9Sstevel@tonic-gate "Warning: ntracks is obsolete for this device and will be ignored.\n"));
421*7c478bd9Sstevel@tonic-gate 		if (cpg_set)
422*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
423*7c478bd9Sstevel@tonic-gate "Warning: cylinders/group is obsolete for this device and will be ignored.\n"));
424*7c478bd9Sstevel@tonic-gate 		if (rpm_set)
425*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
426*7c478bd9Sstevel@tonic-gate "Warning: rpm is obsolete for this device and will be ignored.\n"));
427*7c478bd9Sstevel@tonic-gate 		if (rot_set)
428*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
429*7c478bd9Sstevel@tonic-gate "Warning: rotational delay is obsolete for this device and"
430*7c478bd9Sstevel@tonic-gate " will be ignored.\n"));
431*7c478bd9Sstevel@tonic-gate 		if (nrpos_set)
432*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
433*7c478bd9Sstevel@tonic-gate "Warning: number of rotational positions is obsolete for this device and\n"
434*7c478bd9Sstevel@tonic-gate "will be ignored.\n"));
435*7c478bd9Sstevel@tonic-gate 		if (apc_set)
436*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
437*7c478bd9Sstevel@tonic-gate "Warning: number of alternate sectors per cylinder is obsolete for this\n"
438*7c478bd9Sstevel@tonic-gate "device and will be ignored.\n"));
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 		/*
441*7c478bd9Sstevel@tonic-gate 		 * We need these for the call to mkfs, even though they are
442*7c478bd9Sstevel@tonic-gate 		 * meaningless.
443*7c478bd9Sstevel@tonic-gate 		 */
444*7c478bd9Sstevel@tonic-gate 		rpm = 60;
445*7c478bd9Sstevel@tonic-gate 		nrpos = 1;
446*7c478bd9Sstevel@tonic-gate 		apc = 0;
447*7c478bd9Sstevel@tonic-gate 		rot = -1;
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 		/*
450*7c478bd9Sstevel@tonic-gate 		 * These values are set to produce a file system with
451*7c478bd9Sstevel@tonic-gate 		 * a cylinder group size of 48MB.   For disks with
452*7c478bd9Sstevel@tonic-gate 		 * non-EFI labels, most geometries result in cylinder
453*7c478bd9Sstevel@tonic-gate 		 * groups of around 40 - 50 MB, so we arbitrarily choose
454*7c478bd9Sstevel@tonic-gate 		 * 48MB for disks with EFI labels.  mkfs will reduce
455*7c478bd9Sstevel@tonic-gate 		 * cylinders per group even further if necessary.
456*7c478bd9Sstevel@tonic-gate 		 */
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 		cpg = 16;
459*7c478bd9Sstevel@tonic-gate 		nsectors = 128;
460*7c478bd9Sstevel@tonic-gate 		ntracks = 48;
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 		/*
463*7c478bd9Sstevel@tonic-gate 		 * mkfs produces peculiar results for file systems
464*7c478bd9Sstevel@tonic-gate 		 * that are smaller than one cylinder so don't allow
465*7c478bd9Sstevel@tonic-gate 		 * them to be created (this check is only made for
466*7c478bd9Sstevel@tonic-gate 		 * disks with EFI labels.  Eventually, it should probably
467*7c478bd9Sstevel@tonic-gate 		 * be enforced for all disks.)
468*7c478bd9Sstevel@tonic-gate 		 */
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 		if (fssize < nsectors * ntracks) {
471*7c478bd9Sstevel@tonic-gate 			fatal(gettext(
472*7c478bd9Sstevel@tonic-gate 			    "file system size must be at least %d sectors"),
473*7c478bd9Sstevel@tonic-gate 			    nsectors * ntracks);
474*7c478bd9Sstevel@tonic-gate 		}
475*7c478bd9Sstevel@tonic-gate 	}
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	if (fssize > INT_MAX)
478*7c478bd9Sstevel@tonic-gate 		Tflag = 1;
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	/*
481*7c478bd9Sstevel@tonic-gate 	 * If the user requested that the file system be set up for
482*7c478bd9Sstevel@tonic-gate 	 * eventual growth to over a terabyte, or if it's already greater
483*7c478bd9Sstevel@tonic-gate 	 * than a terabyte, set the inode density (nbpi) to MIN_MTB_DENSITY
484*7c478bd9Sstevel@tonic-gate 	 * (unless the user has specified a larger nbpi), set the frag size
485*7c478bd9Sstevel@tonic-gate 	 * equal to the block size, and set the cylinders-per-group value
486*7c478bd9Sstevel@tonic-gate 	 * passed to mkfs to -1, which tells mkfs to make cylinder groups
487*7c478bd9Sstevel@tonic-gate 	 * as large as possible.
488*7c478bd9Sstevel@tonic-gate 	 */
489*7c478bd9Sstevel@tonic-gate 	if (Tflag) {
490*7c478bd9Sstevel@tonic-gate 		if (density < MIN_MTB_DENSITY)
491*7c478bd9Sstevel@tonic-gate 			density = MIN_MTB_DENSITY;
492*7c478bd9Sstevel@tonic-gate 		fsize = bsize;
493*7c478bd9Sstevel@tonic-gate 		cpg = -1; 	/* says make cyl groups as big as possible */
494*7c478bd9Sstevel@tonic-gate 	} else {
495*7c478bd9Sstevel@tonic-gate 		if (fsize == 0)
496*7c478bd9Sstevel@tonic-gate 			fsize = DESFRAGSIZE;
497*7c478bd9Sstevel@tonic-gate 	}
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	if (!POWEROF2(fsize)) {
500*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
501*7c478bd9Sstevel@tonic-gate 		    "newfs: fragment size must a power of 2, not %d\n"), fsize);
502*7c478bd9Sstevel@tonic-gate 		fsize = bsize/8;
503*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
504*7c478bd9Sstevel@tonic-gate 		    "newfs: fragsize reset to %ld\n"), fsize);
505*7c478bd9Sstevel@tonic-gate 	}
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	/*
508*7c478bd9Sstevel@tonic-gate 	 * The file system is limited in size by the fragment size.
509*7c478bd9Sstevel@tonic-gate 	 * The number of fragments in the file system must fit into
510*7c478bd9Sstevel@tonic-gate 	 * a signed 32-bit quantity, so the number of sectors in the
511*7c478bd9Sstevel@tonic-gate 	 * file system is INT_MAX * the number of sectors in a frag.
512*7c478bd9Sstevel@tonic-gate 	 */
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	max_possible_fssize = ((uint64_t)fsize)/DEV_BSIZE * INT_MAX;
515*7c478bd9Sstevel@tonic-gate 	if (fssize > max_possible_fssize)
516*7c478bd9Sstevel@tonic-gate 		fssize = max_possible_fssize;
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 	/*
519*7c478bd9Sstevel@tonic-gate 	 * Now fssize is the final size of the file system (in sectors).
520*7c478bd9Sstevel@tonic-gate 	 * If it's less than what the user requested, print a message.
521*7c478bd9Sstevel@tonic-gate 	 */
522*7c478bd9Sstevel@tonic-gate 	if (fssize < req_fssize) {
523*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
524*7c478bd9Sstevel@tonic-gate 		    "newfs: requested size of %s disk blocks is too large.\n"),
525*7c478bd9Sstevel@tonic-gate 		    req_fssize_str);
526*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
527*7c478bd9Sstevel@tonic-gate 		    "newfs: Resetting size to %lld\n"), fssize);
528*7c478bd9Sstevel@tonic-gate 	}
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 	/*
531*7c478bd9Sstevel@tonic-gate 	 * fssize now equals the size (in sectors) of the file system
532*7c478bd9Sstevel@tonic-gate 	 * that will be created.
533*7c478bd9Sstevel@tonic-gate 	 */
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	/* XXX - following defaults are both here and in mkfs */
536*7c478bd9Sstevel@tonic-gate 	if (density <= 0) {
537*7c478bd9Sstevel@tonic-gate 		if (fssize < GBSEC)
538*7c478bd9Sstevel@tonic-gate 			density = MINDENSITY;
539*7c478bd9Sstevel@tonic-gate 		else
540*7c478bd9Sstevel@tonic-gate 			density = (int)((((longlong_t)fssize + (GBSEC - 1)) /
541*7c478bd9Sstevel@tonic-gate 						GBSEC) * MINDENSITY);
542*7c478bd9Sstevel@tonic-gate 		if (density <= 0)
543*7c478bd9Sstevel@tonic-gate 			density = MINDENSITY;
544*7c478bd9Sstevel@tonic-gate 		if (density > MAXDEFDENSITY)
545*7c478bd9Sstevel@tonic-gate 			density = MAXDEFDENSITY;
546*7c478bd9Sstevel@tonic-gate 	}
547*7c478bd9Sstevel@tonic-gate 	if (cpg == 0) {
548*7c478bd9Sstevel@tonic-gate 		/*
549*7c478bd9Sstevel@tonic-gate 		 * maxcpg calculation adapted from mkfs
550*7c478bd9Sstevel@tonic-gate 		 * In the case of disks with EFI labels, cpg has
551*7c478bd9Sstevel@tonic-gate 		 * already been set, so we won't enter this code.
552*7c478bd9Sstevel@tonic-gate 		 */
553*7c478bd9Sstevel@tonic-gate 		long maxcpg, maxipg;
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 		maxipg = roundup(bsize * NBBY / 3,
556*7c478bd9Sstevel@tonic-gate 		    bsize / sizeof (struct inode));
557*7c478bd9Sstevel@tonic-gate 		maxcpg = (bsize - sizeof (struct cg) - howmany(maxipg, NBBY)) /
558*7c478bd9Sstevel@tonic-gate 		    (sizeof (long) + nrpos * sizeof (short) +
559*7c478bd9Sstevel@tonic-gate 			nsectors / (MAXFRAG * NBBY));
560*7c478bd9Sstevel@tonic-gate 		cpg = (fssize / GBSEC) * 32;
561*7c478bd9Sstevel@tonic-gate 		if (cpg > maxcpg)
562*7c478bd9Sstevel@tonic-gate 			cpg = maxcpg;
563*7c478bd9Sstevel@tonic-gate 		if (cpg <= 0)
564*7c478bd9Sstevel@tonic-gate 			cpg = MINCPG;
565*7c478bd9Sstevel@tonic-gate 	}
566*7c478bd9Sstevel@tonic-gate 	if (minfree < 0) {
567*7c478bd9Sstevel@tonic-gate 		minfree = ((float)MINFREESEC / fssize) * 100;
568*7c478bd9Sstevel@tonic-gate 		if (minfree > 10)
569*7c478bd9Sstevel@tonic-gate 			minfree = 10;
570*7c478bd9Sstevel@tonic-gate 		if (minfree <= 0)
571*7c478bd9Sstevel@tonic-gate 			minfree = 1;
572*7c478bd9Sstevel@tonic-gate 	}
573*7c478bd9Sstevel@tonic-gate #ifdef i386	/* Bug 1170182 */
574*7c478bd9Sstevel@tonic-gate 	if (ntracks > 32 && (ntracks % 16) != 0) {
575*7c478bd9Sstevel@tonic-gate 		ntracks -= (ntracks % 16);
576*7c478bd9Sstevel@tonic-gate 	}
577*7c478bd9Sstevel@tonic-gate #endif
578*7c478bd9Sstevel@tonic-gate 	/*
579*7c478bd9Sstevel@tonic-gate 	 * Confirmation
580*7c478bd9Sstevel@tonic-gate 	 */
581*7c478bd9Sstevel@tonic-gate 	if (isatty(fileno(stdin)) && !Nflag) {
582*7c478bd9Sstevel@tonic-gate 		/*
583*7c478bd9Sstevel@tonic-gate 		 * If we can read a valid superblock, report the mount
584*7c478bd9Sstevel@tonic-gate 		 * point on which this filesystem was last mounted.
585*7c478bd9Sstevel@tonic-gate 		 */
586*7c478bd9Sstevel@tonic-gate 		if (((sbp = read_sb(special)) != 0) &&
587*7c478bd9Sstevel@tonic-gate 		    (*sbp->fs_fsmnt != '\0')) {
588*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext(
589*7c478bd9Sstevel@tonic-gate 			    "newfs: %s last mounted as %s\n"),
590*7c478bd9Sstevel@tonic-gate 			    special, sbp->fs_fsmnt);
591*7c478bd9Sstevel@tonic-gate 		}
592*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext(
593*7c478bd9Sstevel@tonic-gate 		    "newfs: construct a new file system %s: (y/n)? "),
594*7c478bd9Sstevel@tonic-gate 		    special);
595*7c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
596*7c478bd9Sstevel@tonic-gate 		if (!yes())
597*7c478bd9Sstevel@tonic-gate 			exit(0);
598*7c478bd9Sstevel@tonic-gate 	}
599*7c478bd9Sstevel@tonic-gate 	/*
600*7c478bd9Sstevel@tonic-gate 	 * If alternates-per-cylinder is ever implemented:
601*7c478bd9Sstevel@tonic-gate 	 * need to get apc from dp->d_apc if no -a switch???
602*7c478bd9Sstevel@tonic-gate 	 */
603*7c478bd9Sstevel@tonic-gate 	(void) sprintf(cmd,
604*7c478bd9Sstevel@tonic-gate 	"mkfs -F ufs %s%s %lld %d %d %d %d %d %d %d %d %s %d %d %d %d %s",
605*7c478bd9Sstevel@tonic-gate 	    Nflag ? "-o N " : "", special,
606*7c478bd9Sstevel@tonic-gate 	    fssize, nsectors, ntracks, bsize, fsize, cpg, minfree, rpm/60,
607*7c478bd9Sstevel@tonic-gate 	    density, optim == FS_OPTSPACE ? "s" : "t", apc, rot, nrpos,
608*7c478bd9Sstevel@tonic-gate 	    maxcontig, Tflag ? "y" : "n");
609*7c478bd9Sstevel@tonic-gate 	if (verbose) {
610*7c478bd9Sstevel@tonic-gate 		(void) printf("%s\n", cmd);
611*7c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
612*7c478bd9Sstevel@tonic-gate 	}
613*7c478bd9Sstevel@tonic-gate 	exenv();
614*7c478bd9Sstevel@tonic-gate 	if (status = system(cmd))
615*7c478bd9Sstevel@tonic-gate 		exit(status >> 8);
616*7c478bd9Sstevel@tonic-gate 	if (Nflag)
617*7c478bd9Sstevel@tonic-gate 		exit(0);
618*7c478bd9Sstevel@tonic-gate 	(void) sprintf(cmd, "/usr/sbin/fsirand %s", special);
619*7c478bd9Sstevel@tonic-gate 	if (notrand(special) && (status = system(cmd)) != 0)
620*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
621*7c478bd9Sstevel@tonic-gate 		    gettext("%s: failed, status = %d\n"),
622*7c478bd9Sstevel@tonic-gate 		    cmd, status);
623*7c478bd9Sstevel@tonic-gate 	return (0);
624*7c478bd9Sstevel@tonic-gate }
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate static void
627*7c478bd9Sstevel@tonic-gate exenv(void)
628*7c478bd9Sstevel@tonic-gate {
629*7c478bd9Sstevel@tonic-gate 	char *epath;				/* executable file path */
630*7c478bd9Sstevel@tonic-gate 	char *cpath;				/* current path */
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 	if ((cpath = getenv("PATH")) == NULL) {
633*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("newfs: no PATH in env\n"));
634*7c478bd9Sstevel@tonic-gate 		/*
635*7c478bd9Sstevel@tonic-gate 		 * Background: the Bourne shell interpolates "." into
636*7c478bd9Sstevel@tonic-gate 		 * the path where said path starts with a colon, ends
637*7c478bd9Sstevel@tonic-gate 		 * with a colon, or has two adjacent colons.  Thus,
638*7c478bd9Sstevel@tonic-gate 		 * the path ":/sbin::/usr/sbin:" is equivalent to
639*7c478bd9Sstevel@tonic-gate 		 * ".:/sbin:.:/usr/sbin:.".  Now, we have no cpath,
640*7c478bd9Sstevel@tonic-gate 		 * and epath ends in a colon (to make for easy
641*7c478bd9Sstevel@tonic-gate 		 * catenation in the normal case).  By the above, if
642*7c478bd9Sstevel@tonic-gate 		 * we use "", then "." becomes part of path.  That's
643*7c478bd9Sstevel@tonic-gate 		 * bad, so use CPATH (which is just a duplicate of some
644*7c478bd9Sstevel@tonic-gate 		 * element in EPATH).  No point in opening ourselves
645*7c478bd9Sstevel@tonic-gate 		 * up to a Trojan horse attack when we don't have to....
646*7c478bd9Sstevel@tonic-gate 		 */
647*7c478bd9Sstevel@tonic-gate 		cpath = CPATH;
648*7c478bd9Sstevel@tonic-gate 	}
649*7c478bd9Sstevel@tonic-gate 	if ((epath = malloc(strlen(EPATH) + strlen(cpath) + 1)) == NULL) {
650*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("newfs: malloc failed\n"));
651*7c478bd9Sstevel@tonic-gate 		exit(1);
652*7c478bd9Sstevel@tonic-gate 	}
653*7c478bd9Sstevel@tonic-gate 	(void) strcpy(epath, EPATH);
654*7c478bd9Sstevel@tonic-gate 	(void) strcat(epath, cpath);
655*7c478bd9Sstevel@tonic-gate 	if (putenv(epath) < 0) {
656*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("newfs: putenv failed\n"));
657*7c478bd9Sstevel@tonic-gate 		exit(1);
658*7c478bd9Sstevel@tonic-gate 	}
659*7c478bd9Sstevel@tonic-gate }
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate static int
662*7c478bd9Sstevel@tonic-gate yes(void)
663*7c478bd9Sstevel@tonic-gate {
664*7c478bd9Sstevel@tonic-gate 	int	i, b;
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 	i = b = getchar();
667*7c478bd9Sstevel@tonic-gate 	while (b != '\n' && b != '\0' && b != EOF)
668*7c478bd9Sstevel@tonic-gate 		b = getchar();
669*7c478bd9Sstevel@tonic-gate 	return (i == 'y');
670*7c478bd9Sstevel@tonic-gate }
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate /*
673*7c478bd9Sstevel@tonic-gate  * xxx Caller must run fmt through gettext(3) for us, if we ever
674*7c478bd9Sstevel@tonic-gate  * xxx go the i18n route....
675*7c478bd9Sstevel@tonic-gate  */
676*7c478bd9Sstevel@tonic-gate static void
677*7c478bd9Sstevel@tonic-gate fatal(char *fmt, ...)
678*7c478bd9Sstevel@tonic-gate {
679*7c478bd9Sstevel@tonic-gate 	va_list pvar;
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "newfs: ");
682*7c478bd9Sstevel@tonic-gate 	va_start(pvar, fmt);
683*7c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, pvar);
684*7c478bd9Sstevel@tonic-gate 	va_end(pvar);
685*7c478bd9Sstevel@tonic-gate 	(void) putc('\n', stderr);
686*7c478bd9Sstevel@tonic-gate 	exit(10);
687*7c478bd9Sstevel@tonic-gate }
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate static diskaddr_t
690*7c478bd9Sstevel@tonic-gate getdiskbydev(char *disk)
691*7c478bd9Sstevel@tonic-gate {
692*7c478bd9Sstevel@tonic-gate 	struct dk_geom g;
693*7c478bd9Sstevel@tonic-gate 	struct dk_cinfo ci;
694*7c478bd9Sstevel@tonic-gate 	diskaddr_t actual_size;
695*7c478bd9Sstevel@tonic-gate 	int fd;
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 	if ((fd = open64(disk, 0)) < 0) {
698*7c478bd9Sstevel@tonic-gate 		perror(disk);
699*7c478bd9Sstevel@tonic-gate 		exit(1);
700*7c478bd9Sstevel@tonic-gate 	}
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate 	/*
703*7c478bd9Sstevel@tonic-gate 	 * get_device_size() determines the actual size of the
704*7c478bd9Sstevel@tonic-gate 	 * device, and also the disk's attributes, such as geometry.
705*7c478bd9Sstevel@tonic-gate 	 */
706*7c478bd9Sstevel@tonic-gate 	actual_size = get_device_size(fd, disk);
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	if (label_type == LABEL_TYPE_VTOC) {
709*7c478bd9Sstevel@tonic-gate 		if (ioctl(fd, DKIOCGGEOM, &g))
710*7c478bd9Sstevel@tonic-gate 			fatal(gettext(
711*7c478bd9Sstevel@tonic-gate 			    "%s: Unable to read Disk geometry"), disk);
712*7c478bd9Sstevel@tonic-gate 		if (nsectors == 0)
713*7c478bd9Sstevel@tonic-gate 			nsectors = g.dkg_nsect;
714*7c478bd9Sstevel@tonic-gate 		if (ntracks == 0)
715*7c478bd9Sstevel@tonic-gate 			ntracks = g.dkg_nhead;
716*7c478bd9Sstevel@tonic-gate 		if (rpm == 0)
717*7c478bd9Sstevel@tonic-gate 			rpm = ((int)g.dkg_rpm <= 0) ? 3600: g.dkg_rpm;
718*7c478bd9Sstevel@tonic-gate 	}
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 	if (bsize == 0)
721*7c478bd9Sstevel@tonic-gate 		bsize = DESBLKSIZE;
722*7c478bd9Sstevel@tonic-gate 	/*
723*7c478bd9Sstevel@tonic-gate 	 * Adjust maxcontig by the device's maxtransfer. If maxtransfer
724*7c478bd9Sstevel@tonic-gate 	 * information is not available, default to the min of a MB and
725*7c478bd9Sstevel@tonic-gate 	 * maxphys.
726*7c478bd9Sstevel@tonic-gate 	 */
727*7c478bd9Sstevel@tonic-gate 	if (maxcontig == -1 && ioctl(fd, DKIOCINFO, &ci) == 0) {
728*7c478bd9Sstevel@tonic-gate 		maxcontig = ci.dki_maxtransfer * DEV_BSIZE;
729*7c478bd9Sstevel@tonic-gate 		if (maxcontig < 0) {
730*7c478bd9Sstevel@tonic-gate 			int	error, gotit, maxphys;
731*7c478bd9Sstevel@tonic-gate 			gotit = fsgetmaxphys(&maxphys, &error);
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 			/*
734*7c478bd9Sstevel@tonic-gate 			 * If we cannot get the maxphys value, default
735*7c478bd9Sstevel@tonic-gate 			 * to ufs_maxmaxphys (MB).
736*7c478bd9Sstevel@tonic-gate 			 */
737*7c478bd9Sstevel@tonic-gate 			if (gotit) {
738*7c478bd9Sstevel@tonic-gate 				maxcontig = MIN(maxphys, MB);
739*7c478bd9Sstevel@tonic-gate 			} else {
740*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
741*7c478bd9Sstevel@tonic-gate "Warning: Could not get system value for maxphys. The value for maxcontig\n"
742*7c478bd9Sstevel@tonic-gate "will default to 1MB.\n"));
743*7c478bd9Sstevel@tonic-gate 			maxcontig = MB;
744*7c478bd9Sstevel@tonic-gate 			}
745*7c478bd9Sstevel@tonic-gate 		}
746*7c478bd9Sstevel@tonic-gate 		maxcontig /= bsize;
747*7c478bd9Sstevel@tonic-gate 	}
748*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
749*7c478bd9Sstevel@tonic-gate 	return (actual_size);
750*7c478bd9Sstevel@tonic-gate }
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate /*
753*7c478bd9Sstevel@tonic-gate  * Figure out how big the partition we're dealing with is.
754*7c478bd9Sstevel@tonic-gate  */
755*7c478bd9Sstevel@tonic-gate static diskaddr_t
756*7c478bd9Sstevel@tonic-gate get_device_size(int fd, char *name)
757*7c478bd9Sstevel@tonic-gate {
758*7c478bd9Sstevel@tonic-gate 	struct vtoc vtoc;
759*7c478bd9Sstevel@tonic-gate 	dk_gpt_t *efi_vtoc;
760*7c478bd9Sstevel@tonic-gate 	diskaddr_t	slicesize;
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate 	int index = read_vtoc(fd, &vtoc);
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 	if (index >= 0) {
765*7c478bd9Sstevel@tonic-gate 		label_type = LABEL_TYPE_VTOC;
766*7c478bd9Sstevel@tonic-gate 	} else {
767*7c478bd9Sstevel@tonic-gate 		if (index == VT_ENOTSUP || index == VT_ERROR) {
768*7c478bd9Sstevel@tonic-gate 			/* it might be an EFI label */
769*7c478bd9Sstevel@tonic-gate 			index = efi_alloc_and_read(fd, &efi_vtoc);
770*7c478bd9Sstevel@tonic-gate 			if (index >= 0)
771*7c478bd9Sstevel@tonic-gate 				label_type = LABEL_TYPE_EFI;
772*7c478bd9Sstevel@tonic-gate 		}
773*7c478bd9Sstevel@tonic-gate 	}
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate 	if (index < 0) {
776*7c478bd9Sstevel@tonic-gate 		/*
777*7c478bd9Sstevel@tonic-gate 		 * Since both attempts to read the label failed, we're
778*7c478bd9Sstevel@tonic-gate 		 * going to fall back to a brute force approach to
779*7c478bd9Sstevel@tonic-gate 		 * determining the device's size:  see how far out we can
780*7c478bd9Sstevel@tonic-gate 		 * perform reads on the device.
781*7c478bd9Sstevel@tonic-gate 		 */
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 		slicesize = brute_force_get_device_size(fd);
784*7c478bd9Sstevel@tonic-gate 		if (slicesize == 0) {
785*7c478bd9Sstevel@tonic-gate 			switch (index) {
786*7c478bd9Sstevel@tonic-gate 			case VT_ERROR:
787*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
788*7c478bd9Sstevel@tonic-gate 				    "newfs: %s: %s\n"), name, strerror(errno));
789*7c478bd9Sstevel@tonic-gate 				exit(10);
790*7c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
791*7c478bd9Sstevel@tonic-gate 			case VT_EIO:
792*7c478bd9Sstevel@tonic-gate 				fatal(gettext(
793*7c478bd9Sstevel@tonic-gate 				    "%s: I/O error accessing VTOC"), name);
794*7c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
795*7c478bd9Sstevel@tonic-gate 			case VT_EINVAL:
796*7c478bd9Sstevel@tonic-gate 				fatal(gettext(
797*7c478bd9Sstevel@tonic-gate 				    "%s: Invalid field in VTOC"), name);
798*7c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
799*7c478bd9Sstevel@tonic-gate 			default:
800*7c478bd9Sstevel@tonic-gate 				fatal(gettext(
801*7c478bd9Sstevel@tonic-gate 				    "%s: unknown error accessing VTOC"),
802*7c478bd9Sstevel@tonic-gate 				    name);
803*7c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
804*7c478bd9Sstevel@tonic-gate 			}
805*7c478bd9Sstevel@tonic-gate 		} else {
806*7c478bd9Sstevel@tonic-gate 			label_type = LABEL_TYPE_OTHER;
807*7c478bd9Sstevel@tonic-gate 		}
808*7c478bd9Sstevel@tonic-gate 	}
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	if (label_type == LABEL_TYPE_EFI) {
811*7c478bd9Sstevel@tonic-gate 		slicesize = efi_vtoc->efi_parts[index].p_size;
812*7c478bd9Sstevel@tonic-gate 		efi_free(efi_vtoc);
813*7c478bd9Sstevel@tonic-gate 	} else if (label_type == LABEL_TYPE_VTOC) {
814*7c478bd9Sstevel@tonic-gate 		/*
815*7c478bd9Sstevel@tonic-gate 		 * In the vtoc struct, p_size is a 32-bit signed quantity.
816*7c478bd9Sstevel@tonic-gate 		 * In the dk_gpt struct (efi's version of the vtoc), p_size
817*7c478bd9Sstevel@tonic-gate 		 * is an unsigned 64-bit quantity.  By casting the vtoc's
818*7c478bd9Sstevel@tonic-gate 		 * psize to an unsigned 32-bit quantity, it will be copied
819*7c478bd9Sstevel@tonic-gate 		 * to 'slicesize' (an unsigned 64-bit diskaddr_t) without
820*7c478bd9Sstevel@tonic-gate 		 * sign extension.
821*7c478bd9Sstevel@tonic-gate 		 */
822*7c478bd9Sstevel@tonic-gate 
823*7c478bd9Sstevel@tonic-gate 		slicesize = (uint32_t)vtoc.v_part[index].p_size;
824*7c478bd9Sstevel@tonic-gate 	}
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate 	return (slicesize);
827*7c478bd9Sstevel@tonic-gate }
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate /*
830*7c478bd9Sstevel@tonic-gate  * brute_force_get_device_size
831*7c478bd9Sstevel@tonic-gate  *
832*7c478bd9Sstevel@tonic-gate  * Determine the size of the device by seeing how far we can
833*7c478bd9Sstevel@tonic-gate  * read.  Doing an llseek( , , SEEK_END) would probably work
834*7c478bd9Sstevel@tonic-gate  * in most cases, but we've seen at least one third-party driver
835*7c478bd9Sstevel@tonic-gate  * which doesn't correctly support the SEEK_END option when the
836*7c478bd9Sstevel@tonic-gate  * the device is greater than a terabyte.
837*7c478bd9Sstevel@tonic-gate  */
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate static diskaddr_t
840*7c478bd9Sstevel@tonic-gate brute_force_get_device_size(int fd)
841*7c478bd9Sstevel@tonic-gate {
842*7c478bd9Sstevel@tonic-gate 	diskaddr_t	min_fail = 0;
843*7c478bd9Sstevel@tonic-gate 	diskaddr_t	max_succeed = 0;
844*7c478bd9Sstevel@tonic-gate 	diskaddr_t	cur_db_off;
845*7c478bd9Sstevel@tonic-gate 	char 		buf[DEV_BSIZE];
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 	/*
848*7c478bd9Sstevel@tonic-gate 	 * First, see if we can read the device at all, just to
849*7c478bd9Sstevel@tonic-gate 	 * eliminate errors that have nothing to do with the
850*7c478bd9Sstevel@tonic-gate 	 * device's size.
851*7c478bd9Sstevel@tonic-gate 	 */
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 	if (((llseek(fd, (offset_t)0, SEEK_SET)) == -1) ||
854*7c478bd9Sstevel@tonic-gate 	    ((read(fd, buf, DEV_BSIZE)) == -1))
855*7c478bd9Sstevel@tonic-gate 		return (0);  /* can't determine size */
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	/*
858*7c478bd9Sstevel@tonic-gate 	 * Now, go sequentially through the multiples of 4TB
859*7c478bd9Sstevel@tonic-gate 	 * to find the first read that fails (this isn't strictly
860*7c478bd9Sstevel@tonic-gate 	 * the most efficient way to find the actual size if the
861*7c478bd9Sstevel@tonic-gate 	 * size really could be anything between 0 and 2**64 bytes.
862*7c478bd9Sstevel@tonic-gate 	 * We expect the sizes to be less than 16 TB for some time,
863*7c478bd9Sstevel@tonic-gate 	 * so why do a bunch of reads that are larger than that?
864*7c478bd9Sstevel@tonic-gate 	 * However, this algorithm *will* work for sizes of greater
865*7c478bd9Sstevel@tonic-gate 	 * than 16 TB.  We're just not optimizing for those sizes.)
866*7c478bd9Sstevel@tonic-gate 	 */
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate 	for (cur_db_off = SECTORS_PER_TERABYTE * 4;
869*7c478bd9Sstevel@tonic-gate 	    min_fail == 0 && cur_db_off < FS_SIZE_UPPER_LIMIT;
870*7c478bd9Sstevel@tonic-gate 	    cur_db_off += 4 * SECTORS_PER_TERABYTE) {
871*7c478bd9Sstevel@tonic-gate 		if (((llseek(fd, (offset_t)(cur_db_off * DEV_BSIZE),
872*7c478bd9Sstevel@tonic-gate 		    SEEK_SET)) == -1) ||
873*7c478bd9Sstevel@tonic-gate 		    ((read(fd, buf, DEV_BSIZE)) != DEV_BSIZE))
874*7c478bd9Sstevel@tonic-gate 			min_fail = cur_db_off;
875*7c478bd9Sstevel@tonic-gate 		else
876*7c478bd9Sstevel@tonic-gate 			max_succeed = cur_db_off;
877*7c478bd9Sstevel@tonic-gate 	}
878*7c478bd9Sstevel@tonic-gate 
879*7c478bd9Sstevel@tonic-gate 	if (min_fail == 0)
880*7c478bd9Sstevel@tonic-gate 		return (0);
881*7c478bd9Sstevel@tonic-gate 
882*7c478bd9Sstevel@tonic-gate 	/*
883*7c478bd9Sstevel@tonic-gate 	 * We now know that the size of the device is less than
884*7c478bd9Sstevel@tonic-gate 	 * min_fail and greater than or equal to max_succeed.  Now
885*7c478bd9Sstevel@tonic-gate 	 * keep splitting the difference until the actual size in
886*7c478bd9Sstevel@tonic-gate 	 * sectors in known.  We also know that the difference
887*7c478bd9Sstevel@tonic-gate 	 * between max_succeed and min_fail at this time is
888*7c478bd9Sstevel@tonic-gate 	 * 4 * SECTORS_PER_TERABYTE, which is a power of two, which
889*7c478bd9Sstevel@tonic-gate 	 * simplifies the math below.
890*7c478bd9Sstevel@tonic-gate 	 */
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate 	while (min_fail - max_succeed > 1) {
893*7c478bd9Sstevel@tonic-gate 		cur_db_off = max_succeed + (min_fail - max_succeed)/2;
894*7c478bd9Sstevel@tonic-gate 		if (((llseek(fd, (offset_t)(cur_db_off * DEV_BSIZE),
895*7c478bd9Sstevel@tonic-gate 		    SEEK_SET)) == -1) ||
896*7c478bd9Sstevel@tonic-gate 		    ((read(fd, buf, DEV_BSIZE)) != DEV_BSIZE))
897*7c478bd9Sstevel@tonic-gate 			min_fail = cur_db_off;
898*7c478bd9Sstevel@tonic-gate 		else
899*7c478bd9Sstevel@tonic-gate 			max_succeed = cur_db_off;
900*7c478bd9Sstevel@tonic-gate 	}
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 	/* the size is the last successfully read sector offset plus one */
903*7c478bd9Sstevel@tonic-gate 	return (max_succeed + 1);
904*7c478bd9Sstevel@tonic-gate }
905*7c478bd9Sstevel@tonic-gate 
906*7c478bd9Sstevel@tonic-gate /*
907*7c478bd9Sstevel@tonic-gate  * validate_size
908*7c478bd9Sstevel@tonic-gate  *
909*7c478bd9Sstevel@tonic-gate  * Return 1 if the device appears to be at least "size" sectors long.
910*7c478bd9Sstevel@tonic-gate  * Return 0 if it's shorter or we can't read it.
911*7c478bd9Sstevel@tonic-gate  */
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate static int
914*7c478bd9Sstevel@tonic-gate validate_size(char *disk, diskaddr_t size)
915*7c478bd9Sstevel@tonic-gate {
916*7c478bd9Sstevel@tonic-gate 	char 		buf[DEV_BSIZE];
917*7c478bd9Sstevel@tonic-gate 	int fd, rc;
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate 	if ((fd = open64(disk, O_RDONLY)) < 0) {
920*7c478bd9Sstevel@tonic-gate 		perror(disk);
921*7c478bd9Sstevel@tonic-gate 		exit(1);
922*7c478bd9Sstevel@tonic-gate 	}
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate 	if ((llseek(fd, (offset_t)((size - 1) * DEV_BSIZE), SEEK_SET) == -1) ||
925*7c478bd9Sstevel@tonic-gate 	    (read(fd, buf, DEV_BSIZE)) != DEV_BSIZE)
926*7c478bd9Sstevel@tonic-gate 		rc = 0;
927*7c478bd9Sstevel@tonic-gate 	else
928*7c478bd9Sstevel@tonic-gate 		rc = 1;
929*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
930*7c478bd9Sstevel@tonic-gate 	return (rc);
931*7c478bd9Sstevel@tonic-gate }
932*7c478bd9Sstevel@tonic-gate 
933*7c478bd9Sstevel@tonic-gate /*
934*7c478bd9Sstevel@tonic-gate  * read_sb(char * rawdev) - Attempt to read the superblock from a raw device
935*7c478bd9Sstevel@tonic-gate  *
936*7c478bd9Sstevel@tonic-gate  * Returns:
937*7c478bd9Sstevel@tonic-gate  *	0 :
938*7c478bd9Sstevel@tonic-gate  *		Could not read a valid superblock for a variety of reasons.
939*7c478bd9Sstevel@tonic-gate  *		Since 'newfs' handles any fatal conditions, we're not going
940*7c478bd9Sstevel@tonic-gate  *		to make any guesses as to why this is failing or what should
941*7c478bd9Sstevel@tonic-gate  *		be done about it.
942*7c478bd9Sstevel@tonic-gate  *
943*7c478bd9Sstevel@tonic-gate  *	struct fs *:
944*7c478bd9Sstevel@tonic-gate  *		A pointer to (what we think is) a valid superblock. The
945*7c478bd9Sstevel@tonic-gate  *		space for the superblock is static (inside the function)
946*7c478bd9Sstevel@tonic-gate  *		since we will only be reading the values from it.
947*7c478bd9Sstevel@tonic-gate  */
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate struct fs *
950*7c478bd9Sstevel@tonic-gate read_sb(char *fsdev)
951*7c478bd9Sstevel@tonic-gate {
952*7c478bd9Sstevel@tonic-gate 	static struct fs	sblock;
953*7c478bd9Sstevel@tonic-gate 	struct stat64		statb;
954*7c478bd9Sstevel@tonic-gate 	int			dskfd;
955*7c478bd9Sstevel@tonic-gate 	char			*bufp = NULL;
956*7c478bd9Sstevel@tonic-gate 	int			bufsz = 0;
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	if (stat64(fsdev, &statb) < 0)
959*7c478bd9Sstevel@tonic-gate 		return (0);
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 	if ((dskfd = open64(fsdev, O_RDONLY)) < 0)
962*7c478bd9Sstevel@tonic-gate 		return (0);
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate 	/*
965*7c478bd9Sstevel@tonic-gate 	 * We need a buffer whose size is a multiple of DEV_BSIZE in order
966*7c478bd9Sstevel@tonic-gate 	 * to read from a raw device (which we were probably passed).
967*7c478bd9Sstevel@tonic-gate 	 */
968*7c478bd9Sstevel@tonic-gate 	bufsz = ((sizeof (sblock) / DEV_BSIZE) + 1) * DEV_BSIZE;
969*7c478bd9Sstevel@tonic-gate 	if ((bufp = malloc(bufsz)) == NULL) {
970*7c478bd9Sstevel@tonic-gate 		(void) close(dskfd);
971*7c478bd9Sstevel@tonic-gate 		return (0);
972*7c478bd9Sstevel@tonic-gate 	}
973*7c478bd9Sstevel@tonic-gate 
974*7c478bd9Sstevel@tonic-gate 	if (llseek(dskfd, (offset_t)SBOFF, SEEK_SET) < 0 ||
975*7c478bd9Sstevel@tonic-gate 	    read(dskfd, bufp, bufsz) < 0) {
976*7c478bd9Sstevel@tonic-gate 		(void) close(dskfd);
977*7c478bd9Sstevel@tonic-gate 		free(bufp);
978*7c478bd9Sstevel@tonic-gate 		return (0);
979*7c478bd9Sstevel@tonic-gate 	}
980*7c478bd9Sstevel@tonic-gate 	(void) close(dskfd);	/* Done with the file */
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate 	(void) memcpy(&sblock, bufp, sizeof (sblock));
983*7c478bd9Sstevel@tonic-gate 	free(bufp);	/* Don't need this anymore */
984*7c478bd9Sstevel@tonic-gate 
985*7c478bd9Sstevel@tonic-gate 	if (((sblock.fs_magic != FS_MAGIC) &&
986*7c478bd9Sstevel@tonic-gate 	    (sblock.fs_magic != MTB_UFS_MAGIC)) ||
987*7c478bd9Sstevel@tonic-gate 	    sblock.fs_ncg < 1 || sblock.fs_cpg < 1)
988*7c478bd9Sstevel@tonic-gate 		return (0);
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate 	if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
991*7c478bd9Sstevel@tonic-gate 	    (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
992*7c478bd9Sstevel@tonic-gate 		return (0);
993*7c478bd9Sstevel@tonic-gate 
994*7c478bd9Sstevel@tonic-gate 	if (sblock.fs_sbsize < 0 || sblock.fs_sbsize > SBSIZE)
995*7c478bd9Sstevel@tonic-gate 		return (0);
996*7c478bd9Sstevel@tonic-gate 
997*7c478bd9Sstevel@tonic-gate 	return (&sblock);
998*7c478bd9Sstevel@tonic-gate }
999*7c478bd9Sstevel@tonic-gate 
1000*7c478bd9Sstevel@tonic-gate /*
1001*7c478bd9Sstevel@tonic-gate  * Read the UFS file system on the raw device SPECIAL.  If it does not
1002*7c478bd9Sstevel@tonic-gate  * appear to be a UFS file system, return non-zero, indicating that
1003*7c478bd9Sstevel@tonic-gate  * fsirand should be called (and it will spit out an error message).
1004*7c478bd9Sstevel@tonic-gate  * If it is a UFS file system, take a look at the inodes in the first
1005*7c478bd9Sstevel@tonic-gate  * cylinder group.  If they appear to be randomized (non-zero), return
1006*7c478bd9Sstevel@tonic-gate  * zero, which will cause fsirand to not be called.  If the inode generation
1007*7c478bd9Sstevel@tonic-gate  * counts are all zero, then we must call fsirand, so return non-zero.
1008*7c478bd9Sstevel@tonic-gate  */
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate #define	RANDOMIZED	0
1011*7c478bd9Sstevel@tonic-gate #define	NOT_RANDOMIZED	1
1012*7c478bd9Sstevel@tonic-gate 
1013*7c478bd9Sstevel@tonic-gate static int
1014*7c478bd9Sstevel@tonic-gate notrand(char *special)
1015*7c478bd9Sstevel@tonic-gate {
1016*7c478bd9Sstevel@tonic-gate 	long fsbuf[SBSIZE / sizeof (long)];
1017*7c478bd9Sstevel@tonic-gate 	struct dinode dibuf[MAXBSIZE/sizeof (struct dinode)];
1018*7c478bd9Sstevel@tonic-gate 	struct fs *fs;
1019*7c478bd9Sstevel@tonic-gate 	struct dinode *dip;
1020*7c478bd9Sstevel@tonic-gate 	offset_t seekaddr;
1021*7c478bd9Sstevel@tonic-gate 	int bno, inum;
1022*7c478bd9Sstevel@tonic-gate 	int fd;
1023*7c478bd9Sstevel@tonic-gate 
1024*7c478bd9Sstevel@tonic-gate 	fs = (struct fs *)fsbuf;
1025*7c478bd9Sstevel@tonic-gate 	if ((fd = open64(special, 0)) == -1)
1026*7c478bd9Sstevel@tonic-gate 		return (NOT_RANDOMIZED);
1027*7c478bd9Sstevel@tonic-gate 	if (llseek(fd, (offset_t)SBLOCK * DEV_BSIZE, 0) == -1 ||
1028*7c478bd9Sstevel@tonic-gate 	    read(fd, (char *)fs, SBSIZE) != SBSIZE ||
1029*7c478bd9Sstevel@tonic-gate 	    ((fs->fs_magic != FS_MAGIC) && (fs->fs_magic != MTB_UFS_MAGIC))) {
1030*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1031*7c478bd9Sstevel@tonic-gate 		return (NOT_RANDOMIZED);
1032*7c478bd9Sstevel@tonic-gate 	}
1033*7c478bd9Sstevel@tonic-gate 
1034*7c478bd9Sstevel@tonic-gate 	/* looks like a UFS file system; read the first cylinder group */
1035*7c478bd9Sstevel@tonic-gate 	bsize = INOPB(fs) * sizeof (struct dinode);
1036*7c478bd9Sstevel@tonic-gate 	inum = 0;
1037*7c478bd9Sstevel@tonic-gate 	while (inum < fs->fs_ipg) {
1038*7c478bd9Sstevel@tonic-gate 		bno = itod(fs, inum);
1039*7c478bd9Sstevel@tonic-gate 		seekaddr = (offset_t)fsbtodb(fs, bno) * DEV_BSIZE;
1040*7c478bd9Sstevel@tonic-gate 		if (llseek(fd, seekaddr, 0) == -1 ||
1041*7c478bd9Sstevel@tonic-gate 		    read(fd, (char *)dibuf, bsize) != bsize) {
1042*7c478bd9Sstevel@tonic-gate 			(void) close(fd);
1043*7c478bd9Sstevel@tonic-gate 			return (NOT_RANDOMIZED);
1044*7c478bd9Sstevel@tonic-gate 		}
1045*7c478bd9Sstevel@tonic-gate 		for (dip = dibuf; dip < &dibuf[INOPB(fs)]; dip++) {
1046*7c478bd9Sstevel@tonic-gate 			if (dip->di_gen != 0) {
1047*7c478bd9Sstevel@tonic-gate 				(void) close(fd);
1048*7c478bd9Sstevel@tonic-gate 				return (RANDOMIZED);
1049*7c478bd9Sstevel@tonic-gate 			}
1050*7c478bd9Sstevel@tonic-gate 			inum++;
1051*7c478bd9Sstevel@tonic-gate 		}
1052*7c478bd9Sstevel@tonic-gate 	}
1053*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
1054*7c478bd9Sstevel@tonic-gate 	return (NOT_RANDOMIZED);
1055*7c478bd9Sstevel@tonic-gate }
1056*7c478bd9Sstevel@tonic-gate 
1057*7c478bd9Sstevel@tonic-gate static void
1058*7c478bd9Sstevel@tonic-gate usage(void)
1059*7c478bd9Sstevel@tonic-gate {
1060*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
1061*7c478bd9Sstevel@tonic-gate 	    "usage: newfs [ -v ] [ mkfs-options ] raw-special-device\n"));
1062*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("where mkfs-options are:\n"));
1063*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
1064*7c478bd9Sstevel@tonic-gate 	    "\t-N do not create file system, just print out parameters\n"));
1065*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
1066*7c478bd9Sstevel@tonic-gate "\t-T configure file system for eventual growth to over a terabyte\n"));
1067*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\t-s file system size (sectors)\n"));
1068*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\t-b block size\n"));
1069*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\t-f frag size\n"));
1070*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\t-t tracks/cylinder\n"));
1071*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\t-c cylinders/group\n"));
1072*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\t-m minimum free space %%\n"));
1073*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
1074*7c478bd9Sstevel@tonic-gate 	    "\t-o optimization preference (`space' or `time')\n"));
1075*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\t-r revolutions/minute\n"));
1076*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\t-i number of bytes per inode\n"));
1077*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
1078*7c478bd9Sstevel@tonic-gate 	    "\t-a number of alternates per cylinder\n"));
1079*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\t-C maxcontig\n"));
1080*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("\t-d rotational delay\n"));
1081*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
1082*7c478bd9Sstevel@tonic-gate 	    "\t-n number of rotational positions\n"));
1083*7c478bd9Sstevel@tonic-gate }
1084*7c478bd9Sstevel@tonic-gate 
1085*7c478bd9Sstevel@tonic-gate /*
1086*7c478bd9Sstevel@tonic-gate  * Error-detecting version of atoi(3).  Adapted from mkfs' number().
1087*7c478bd9Sstevel@tonic-gate  */
1088*7c478bd9Sstevel@tonic-gate static unsigned int
1089*7c478bd9Sstevel@tonic-gate number(char *param, char *value, int flags, int def_value)
1090*7c478bd9Sstevel@tonic-gate {
1091*7c478bd9Sstevel@tonic-gate 	char *cs;
1092*7c478bd9Sstevel@tonic-gate 	int n;
1093*7c478bd9Sstevel@tonic-gate 	int cut = INT_MAX / 10;    /* limit to avoid overflow */
1094*7c478bd9Sstevel@tonic-gate 	int minus = 0;
1095*7c478bd9Sstevel@tonic-gate 
1096*7c478bd9Sstevel@tonic-gate 	cs = value;
1097*7c478bd9Sstevel@tonic-gate 	if (*cs == '-') {
1098*7c478bd9Sstevel@tonic-gate 		minus = 1;
1099*7c478bd9Sstevel@tonic-gate 		cs += 1;
1100*7c478bd9Sstevel@tonic-gate 	}
1101*7c478bd9Sstevel@tonic-gate 	if ((*cs < '0') || (*cs > '9')) {
1102*7c478bd9Sstevel@tonic-gate 		goto bail_out;
1103*7c478bd9Sstevel@tonic-gate 	}
1104*7c478bd9Sstevel@tonic-gate 	n = 0;
1105*7c478bd9Sstevel@tonic-gate 	while ((*cs >= '0') && (*cs <= '9') && (n <= cut)) {
1106*7c478bd9Sstevel@tonic-gate 		n = n*10 + *cs++ - '0';
1107*7c478bd9Sstevel@tonic-gate 	}
1108*7c478bd9Sstevel@tonic-gate 	if (minus)
1109*7c478bd9Sstevel@tonic-gate 	    n = -n;
1110*7c478bd9Sstevel@tonic-gate 	for (;;) {
1111*7c478bd9Sstevel@tonic-gate 		switch (*cs++) {
1112*7c478bd9Sstevel@tonic-gate 		case '\0':
1113*7c478bd9Sstevel@tonic-gate 			return (n);
1114*7c478bd9Sstevel@tonic-gate 
1115*7c478bd9Sstevel@tonic-gate 		case '0': case '1': case '2': case '3': case '4':
1116*7c478bd9Sstevel@tonic-gate 		case '5': case '6': case '7': case '8': case '9':
1117*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
1118*7c478bd9Sstevel@tonic-gate 			    "newfs: value for %s overflowed, using %d\n"),
1119*7c478bd9Sstevel@tonic-gate 			    param, def_value);
1120*7c478bd9Sstevel@tonic-gate 			return (def_value);
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 		case '%':
1123*7c478bd9Sstevel@tonic-gate 			if (flags & NR_PERCENT)
1124*7c478bd9Sstevel@tonic-gate 				break;
1125*7c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
1126*7c478bd9Sstevel@tonic-gate 
1127*7c478bd9Sstevel@tonic-gate 		default:
1128*7c478bd9Sstevel@tonic-gate bail_out:
1129*7c478bd9Sstevel@tonic-gate 			fatal(gettext("bad numeric arg for %s: \"%s\""),
1130*7c478bd9Sstevel@tonic-gate 			    param, value);
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate 		}
1133*7c478bd9Sstevel@tonic-gate 	}
1134*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
1135*7c478bd9Sstevel@tonic-gate }
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate /*
1138*7c478bd9Sstevel@tonic-gate  * Error-detecting version of atoi(3).  Adapted from mkfs' number().
1139*7c478bd9Sstevel@tonic-gate  */
1140*7c478bd9Sstevel@tonic-gate static int64_t
1141*7c478bd9Sstevel@tonic-gate number64(char *param, char *value, int flags, int64_t def_value)
1142*7c478bd9Sstevel@tonic-gate {
1143*7c478bd9Sstevel@tonic-gate 	char *cs;
1144*7c478bd9Sstevel@tonic-gate 	int64_t n;
1145*7c478bd9Sstevel@tonic-gate 	int64_t cut = FS_SIZE_UPPER_LIMIT/ 10;    /* limit to avoid overflow */
1146*7c478bd9Sstevel@tonic-gate 	int minus = 0;
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate 	cs = value;
1149*7c478bd9Sstevel@tonic-gate 	if (*cs == '-') {
1150*7c478bd9Sstevel@tonic-gate 		minus = 1;
1151*7c478bd9Sstevel@tonic-gate 		cs += 1;
1152*7c478bd9Sstevel@tonic-gate 	}
1153*7c478bd9Sstevel@tonic-gate 	if ((*cs < '0') || (*cs > '9')) {
1154*7c478bd9Sstevel@tonic-gate 		goto bail_out;
1155*7c478bd9Sstevel@tonic-gate 	}
1156*7c478bd9Sstevel@tonic-gate 	n = 0;
1157*7c478bd9Sstevel@tonic-gate 	while ((*cs >= '0') && (*cs <= '9') && (n <= cut)) {
1158*7c478bd9Sstevel@tonic-gate 		n = n*10 + *cs++ - '0';
1159*7c478bd9Sstevel@tonic-gate 	}
1160*7c478bd9Sstevel@tonic-gate 	if (minus)
1161*7c478bd9Sstevel@tonic-gate 	    n = -n;
1162*7c478bd9Sstevel@tonic-gate 	for (;;) {
1163*7c478bd9Sstevel@tonic-gate 		switch (*cs++) {
1164*7c478bd9Sstevel@tonic-gate 		case '\0':
1165*7c478bd9Sstevel@tonic-gate 			return (n);
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 		case '0': case '1': case '2': case '3': case '4':
1168*7c478bd9Sstevel@tonic-gate 		case '5': case '6': case '7': case '8': case '9':
1169*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
1170*7c478bd9Sstevel@tonic-gate 			    "newfs: value for %s overflowed, using %d\n"),
1171*7c478bd9Sstevel@tonic-gate 			    param, def_value);
1172*7c478bd9Sstevel@tonic-gate 			return (def_value);
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 		case '%':
1175*7c478bd9Sstevel@tonic-gate 			if (flags & NR_PERCENT)
1176*7c478bd9Sstevel@tonic-gate 				break;
1177*7c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
1178*7c478bd9Sstevel@tonic-gate 
1179*7c478bd9Sstevel@tonic-gate 		default:
1180*7c478bd9Sstevel@tonic-gate bail_out:
1181*7c478bd9Sstevel@tonic-gate 			fatal(gettext("bad numeric arg for %s: \"%s\""),
1182*7c478bd9Sstevel@tonic-gate 			    param, value);
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 		}
1185*7c478bd9Sstevel@tonic-gate 	}
1186*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
1187*7c478bd9Sstevel@tonic-gate }
1188