1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27/*	All Rights Reserved	*/
28
29/*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39/*
40 * Copyright (c) 2018, Joyent, Inc.
41 */
42
43/*
44 * The maximum supported file system size (in sectors) is the
45 * number of frags that can be represented in an int32_t field
46 * (INT_MAX) times the maximum number of sectors per frag.  Since
47 * the maximum frag size is MAXBSIZE, the maximum number of sectors
48 * per frag is MAXBSIZE/DEV_BSIZE.
49 */
50#define	FS_MAX	(((diskaddr_t)INT_MAX) * (MAXBSIZE/DEV_BSIZE))
51
52/*
53 * make file system for cylinder-group style file systems
54 *
55 * usage:
56 *
57 *    mkfs [-F FSType] [-V] [-G [-P]] [-M dirname] [-m] [options]
58 *	[-o specific_options]  special size
59 *	[nsect ntrack bsize fsize cpg	minfree	rps nbpi opt apc rotdelay
60 *	  2     3      4     5     6	7	8   9	 10  11  12
61 *	nrpos maxcontig mtb]
62 *	13    14	15
63 *
64 *  where specific_options are:
65 *	N - no create
66 *	nsect - The number of sectors per track
67 *	ntrack - The number of tracks per cylinder
68 *	bsize - block size
69 *	fragsize - fragment size
70 *	cgsize - The number of disk cylinders per cylinder group.
71 *	free - minimum free space
72 *	rps - rotational speed (rev/sec).
73 *	nbpi - number of data bytes per allocated inode
74 *	opt - optimization (space, time)
75 *	apc - number of alternates
76 *	gap - gap size
77 *	nrpos - number of rotational positions
78 *	maxcontig - maximum number of logical blocks that will be
79 *		allocated contiguously before inserting rotational delay
80 *	mtb - if "y", set up file system for eventual growth to over a
81 *		a terabyte
82 * -P Do not grow the file system, but print on stdout the maximal
83 *    size in sectors to which the file system can be increased. The calculated
84 *    size is limited by the value provided by the operand size.
85 *
86 * Note that -P is a project-private interface and together with -G intended
87 * to be used only by the growfs script. It is therefore purposely not
88 * documented in the man page.
89 * The -P option is covered by PSARC case 2003/422.
90 */
91
92/*
93 * The following constants set the defaults used for the number
94 * of sectors/track (fs_nsect), and number of tracks/cyl (fs_ntrak).
95 *
96 *			NSECT		NTRAK
97 *	72MB CDC	18		9
98 *	30MB CDC	18		5
99 *	720KB Diskette	9		2
100 *
101 * However the defaults will be different for disks larger than CHSLIMIT.
102 */
103
104#define	DFLNSECT	32
105#define	DFLNTRAK	16
106
107/*
108 * The following default sectors and tracks values are used for
109 * non-efi disks that are larger than the CHS addressing limit. The
110 * existing default cpg of 16 (DESCPG) holds good for larger disks too.
111 */
112#define	DEF_SECTORS_EFI	128
113#define	DEF_TRACKS_EFI	48
114
115/*
116 * The maximum number of cylinders in a group depends upon how much
117 * information can be stored on a single cylinder. The default is to
118 * use 16 cylinders per group.  This is effectively tradition - it was
119 * the largest value acceptable under SunOs 4.1
120 */
121#define	DESCPG		16	/* desired fs_cpg */
122
123/*
124 * The following two constants set the default block and fragment sizes.
125 * Both constants must be a power of 2 and meet the following constraints:
126 *	MINBSIZE <= DESBLKSIZE <= MAXBSIZE
127 *	DEV_BSIZE <= DESFRAGSIZE <= DESBLKSIZE
128 *	DESBLKSIZE / DESFRAGSIZE <= 8
129 */
130#define	DESBLKSIZE	8192
131#define	DESFRAGSIZE	1024
132
133/*
134 * MINFREE gives the minimum acceptable percentage of file system
135 * blocks which may be free. If the freelist drops below this level
136 * only the superuser may continue to allocate blocks. This may
137 * be set to 0 if no reserve of free blocks is deemed necessary,
138 * however throughput drops by fifty percent if the file system
139 * is run at between 90% and 100% full; thus the default value of
140 * fs_minfree is 10%. With 10% free space, fragmentation is not a
141 * problem, so we choose to optimize for time.
142 */
143#define	MINFREE		10
144#define	DEFAULTOPT	FS_OPTTIME
145
146/*
147 * ROTDELAY gives the minimum number of milliseconds to initiate
148 * another disk transfer on the same cylinder. It is no longer used
149 * and will always default to 0.
150 */
151#define	ROTDELAY	0
152
153/*
154 * MAXBLKPG determines the maximum number of data blocks which are
155 * placed in a single cylinder group. The default is one indirect
156 * block worth of data blocks.
157 */
158#define	MAXBLKPG(bsize)	((bsize) / sizeof (daddr32_t))
159
160/*
161 * Each file system has a number of inodes statically allocated.
162 * We allocate one inode slot per NBPI bytes, expecting this
163 * to be far more than we will ever need.
164 */
165#define	NBPI		2048	/* Number Bytes Per Inode */
166#define	MTB_NBPI	(MB)	/* Number Bytes Per Inode for multi-terabyte */
167
168/*
169 * Disks are assumed to rotate at 60HZ, unless otherwise specified.
170 */
171#define	DEFHZ		60
172
173/*
174 * Cylinder group related limits.
175 *
176 * For each cylinder we keep track of the availability of blocks at different
177 * rotational positions, so that we can lay out the data to be picked
178 * up with minimum rotational latency.  NRPOS is the number of rotational
179 * positions which we distinguish.  With NRPOS 8 the resolution of our
180 * summary information is 2ms for a typical 3600 rpm drive.
181 */
182#define	NRPOS		8	/* number distinct rotational positions */
183
184#ifdef DEBUG
185#define	dprintf(x)	printf x
186#else
187#define	dprintf(x)
188#endif
189
190/*
191 * For the -N option, when calculating the backup superblocks, do not print
192 * them if we are not really sure. We may have to try an alternate method of
193 * arriving at the superblocks. So defer printing till a handful of superblocks
194 * look good.
195 */
196#define	tprintf(x)	if (Nflag && retry) \
197				(void) strncat(tmpbuf, x, strlen(x)); \
198			else \
199				(void) fprintf(stderr, x);
200
201#define	ALTSB		32	/* Location of first backup superblock */
202
203/*
204 * range_check "user_supplied" flag values.
205 */
206#define	RC_DEFAULT	0
207#define	RC_KEYWORD	1
208#define	RC_POSITIONAL	2
209
210/*
211 * ufs hole
212 */
213#define	UFS_HOLE	-1
214
215#ifndef	STANDALONE
216#include	<stdio.h>
217#include	<sys/mnttab.h>
218#endif
219
220#include	<stdlib.h>
221#include	<unistd.h>
222#include	<malloc.h>
223#include	<string.h>
224#include	<strings.h>
225#include	<ctype.h>
226#include	<errno.h>
227#include	<sys/param.h>
228#include	<time.h>
229#include	<sys/types.h>
230#include	<sys/sysmacros.h>
231#include	<sys/vnode.h>
232#include	<sys/fs/ufs_fsdir.h>
233#include	<sys/fs/ufs_inode.h>
234#include	<sys/fs/ufs_fs.h>
235#include	<sys/fs/ufs_log.h>
236#include	<sys/mntent.h>
237#include	<sys/filio.h>
238#include	<limits.h>
239#include	<sys/int_const.h>
240#include	<signal.h>
241#include	<sys/efi_partition.h>
242#include	<fslib.h>
243#include	"roll_log.h"
244
245#define	bcopy(f, t, n)    (void) memcpy(t, f, n)
246#define	bzero(s, n)	(void) memset(s, 0, n)
247#define	bcmp(s, d, n)	memcmp(s, d, n)
248
249#define	index(s, r)	strchr(s, r)
250#define	rindex(s, r)	strrchr(s, r)
251
252#include	<sys/stat.h>
253#include	<sys/statvfs.h>
254#include	<locale.h>
255#include	<fcntl.h>
256#include	<sys/isa_defs.h>	/* for ENDIAN defines */
257#include	<sys/vtoc.h>
258
259#include	<sys/dkio.h>
260#include	<sys/asynch.h>
261
262extern offset_t	llseek();
263extern char	*getfullblkname();
264extern long	lrand48();
265
266extern int	optind;
267extern char	*optarg;
268
269
270/*
271 * The size of a cylinder group is calculated by CGSIZE. The maximum size
272 * is limited by the fact that cylinder groups are at most one block.
273 * Its size is derived from the size of the maps maintained in the
274 * cylinder group and the (struct cg) size.
275 */
276#define	CGSIZE(fs) \
277	/* base cg		*/ (sizeof (struct cg) + \
278	/* blktot size	*/ (fs)->fs_cpg * sizeof (long) + \
279	/* blks size	*/ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof (short) + \
280	/* inode map	*/ howmany((fs)->fs_ipg, NBBY) + \
281	/* block map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY))
282
283/*
284 * We limit the size of the inode map to be no more than a
285 * third of the cylinder group space, since we must leave at
286 * least an equal amount of space for the block map.
287 *
288 * N.B.: MAXIpG must be a multiple of INOPB(fs).
289 */
290#define	MAXIpG(fs)	roundup((fs)->fs_bsize * NBBY / 3, INOPB(fs))
291
292/*
293 * Same as MAXIpG, but parameterized by the block size (b) and the
294 * cylinder group divisor (d), which is the reciprocal of the fraction of the
295 * cylinder group overhead block that is used for the inode map.  So for
296 * example, if d = 5, the macro's computation assumes that 1/5 of the
297 * cylinder group overhead block can be dedicated to the inode map.
298 */
299#define	MAXIpG_B(b, d)	roundup((b) * NBBY / (d), (b) / sizeof (struct dinode))
300
301#define	UMASK		0755
302#define	MAXINOPB	(MAXBSIZE / sizeof (struct dinode))
303#define	POWEROF2(num)	(((num) & ((num) - 1)) == 0)
304#define	MB		(1024*1024)
305#define	BETWEEN(x, l, h)	((x) >= (l) && (x) <= (h))
306
307/*
308 * Used to set the inode generation number. Since both inodes and dinodes
309 * are dealt with, we really need a pointer to an icommon here.
310 */
311#define	IRANDOMIZE(icp)	(icp)->ic_gen = lrand48();
312
313/*
314 * Flags for number()
315 */
316#define	ALLOW_PERCENT	0x01	/* allow trailing `%' on number */
317#define	ALLOW_MS1	0x02	/* allow trailing `ms', state 1 */
318#define	ALLOW_MS2	0x04	/* allow trailing `ms', state 2 */
319#define	ALLOW_END_ONLY	0x08	/* must be at end of number & suffixes */
320
321#define	MAXAIO	1000	/* maximum number of outstanding I/O's we'll manage */
322#define	BLOCK	1	/* block in aiowait */
323#define	NOBLOCK	0	/* don't block in aiowait */
324
325#define	RELEASE 1	/* free an aio buffer after use */
326#define	SAVE	0	/* don't free the buffer */
327
328typedef struct aio_trans {
329	aio_result_t resultbuf;
330	diskaddr_t bno;
331	char *buffer;
332	int size;
333	int release;
334	struct aio_trans *next;
335} aio_trans;
336
337typedef struct aio_results {
338	int max;
339	int outstanding;
340	int maxpend;
341	aio_trans *trans;
342} aio_results;
343
344int aio_inited = 0;
345aio_results results;
346
347/*
348 * Allow up to MAXBUF aio requests that each have a unique buffer.
349 * More aio's might be done, but not using memory through the getbuf()
350 * interface.  This can be raised, but you run into the potential of
351 * using more memory than is physically available on the machine,
352 * and if you start swapping, you can forget about performance.
353 * To prevent this, we also limit the total memory used for a given
354 * type of buffer to MAXBUFMEM.
355 *
356 * Tests indicate a cylinder group's worth of inodes takes:
357 *
358 *	NBPI	Size of Inode Buffer
359 *	 2k	1688k
360 *	 8k	 424k
361 *
362 * initcg() stores all the inodes for a cylinder group in one buffer,
363 * so allowing 20 buffers could take 32 MB if not limited by MAXBUFMEM.
364 */
365#define	MAXBUF		20
366#define	MAXBUFMEM	(8 * 1024 * 1024)
367
368/*
369 * header information for buffers managed by getbuf() and freebuf()
370 */
371typedef struct bufhdr {
372	struct bufhdr *head;
373	struct bufhdr *next;
374} bufhdr;
375
376int bufhdrsize;
377
378bufhdr inodebuf = { NULL, NULL };
379bufhdr cgsumbuf = { NULL, NULL };
380
381#define	SECTORS_PER_TERABYTE	(1LL << 31)
382/*
383 * The following constant specifies an upper limit for file system size
384 * that is actually a lot bigger than we expect to support with UFS. (Since
385 * it's specified in sectors, the file system size would be 2**44 * 512,
386 * which is 2**53, which is 8192 Terabytes.)  However, it's useful
387 * for checking the basic sanity of a size value that is input on the
388 * command line.
389 */
390#define	FS_SIZE_UPPER_LIMIT	0x100000000000LL
391
392/*
393 * Forward declarations
394 */
395static char *getbuf(bufhdr *bufhead, int size);
396static void freebuf(char *buf);
397static void freetrans(aio_trans *transp);
398static aio_trans *get_aiop();
399static aio_trans *wait_for_write(int block);
400static void initcg(int cylno);
401static void fsinit();
402static int makedir(struct direct *protodir, int entries);
403static void iput(struct inode *ip);
404static void rdfs(diskaddr_t bno, int size, char *bf);
405static void wtfs(diskaddr_t bno, int size, char *bf);
406static void awtfs(diskaddr_t bno, int size, char *bf, int release);
407static void wtfs_breakup(diskaddr_t bno, int size, char *bf);
408static int isblock(struct fs *fs, unsigned char *cp, int h);
409static void clrblock(struct fs *fs, unsigned char *cp, int h);
410static void setblock(struct fs *fs, unsigned char *cp, int h);
411static void usage(void) __NORETURN;
412static void dump_fscmd(char *fsys, int fsi);
413static uint64_t number(uint64_t d_value, char *param, int flags);
414static int match(char *s);
415static char checkopt(char *optim);
416static char checkmtb(char *mtbarg);
417static void range_check(long *varp, char *name, long minimum,
418    long maximum, long def_val, int user_supplied);
419static void range_check_64(uint64_t *varp, char *name, uint64_t minimum,
420    uint64_t maximum, uint64_t def_val, int user_supplied);
421static daddr32_t alloc(int size, int mode);
422static diskaddr_t get_max_size(int fd);
423static long get_max_track_size(int fd);
424static void block_sigint(sigset_t *old_mask);
425static void unblock_sigint(sigset_t *old_mask);
426static void recover_from_sigint(int signum);
427static int confirm_abort(void);
428static int getaline(FILE *fp, char *loc, int maxlen);
429static void flush_writes(void);
430static long compute_maxcpg(long, long, long, long, long);
431static int in_64bit_mode(void);
432static int validate_size(int fd, diskaddr_t size);
433static void dump_sblock(void);
434
435/*
436 * Workaround for mkfs to function properly on disks attached to XMIT 2.X
437 * controller. If the address is not aligned at 8 byte boundary, mkfs on
438 * disks attached to XMIT 2.X controller exhibts un-predictable behaviour.
439 */
440#define	XMIT_2_X_ALIGN	8
441#pragma	align XMIT_2_X_ALIGN(fsun, altfsun, cgun)
442
443union {
444	struct fs fs;
445	char pad[SBSIZE];
446} fsun, altfsun;
447#define	sblock	fsun.fs
448#define	altsblock	altfsun.fs
449
450struct	csum *fscs;
451
452union cgun {
453	struct cg cg;
454	char pad[MAXBSIZE];
455} cgun;
456
457#define	acg	cgun.cg
458/*
459 * Size of screen in cols in which to fit output
460 */
461#define	WIDTH	80
462
463struct dinode zino[MAXBSIZE / sizeof (struct dinode)];
464
465/*
466 * file descriptors used for rdfs(fsi) and wtfs(fso).
467 * Initialized to an illegal file descriptor number.
468 */
469int	fsi = -1;
470int	fso = -1;
471
472/*
473 * The BIG parameter is machine dependent.  It should be a longlong integer
474 * constant that can be used by the number parser to check the validity
475 * of numeric parameters.
476 */
477
478#define	BIG		0x7fffffffffffffffLL
479
480/* Used to indicate to number() that a bogus value should cause us to exit */
481#define	NO_DEFAULT	LONG_MIN
482
483/*
484 * INVALIDSBLIMIT is the number of bad backup superblocks that will be
485 * tolerated before we decide to try arriving at a different set of them
486 * using a different logic. This is applicable for non-EFI disks only.
487 */
488#define	INVALIDSBLIMIT	10
489
490/*
491 * The *_flag variables are used to indicate that the user specified
492 * the values, rather than that we made them up ourselves.  We can
493 * complain about the user giving us bogus values.
494 */
495
496/* semi-constants */
497long	sectorsize = DEV_BSIZE;		/* bytes/sector from param.h */
498long	bbsize = BBSIZE;		/* boot block size */
499long	sbsize = SBSIZE;		/* superblock size */
500
501/* parameters */
502diskaddr_t	fssize_db;		/* file system size in disk blocks */
503diskaddr_t	fssize_frag;		/* file system size in frags */
504long	cpg;				/* cylinders/cylinder group */
505int	cpg_flag = RC_DEFAULT;
506long	rotdelay = -1;			/* rotational delay between blocks */
507int	rotdelay_flag = RC_DEFAULT;
508long	maxcontig;			/* max contiguous blocks to allocate */
509int	maxcontig_flag = RC_DEFAULT;
510long	nsect = DFLNSECT;		/* sectors per track */
511int	nsect_flag = RC_DEFAULT;
512long	ntrack = DFLNTRAK;		/* tracks per cylinder group */
513int	ntrack_flag = RC_DEFAULT;
514long	bsize = DESBLKSIZE;		/* filesystem block size */
515int	bsize_flag = RC_DEFAULT;
516long	fragsize = DESFRAGSIZE;		/* filesystem fragment size */
517int	fragsize_flag = RC_DEFAULT;
518long	minfree = MINFREE;		/* fs_minfree */
519int	minfree_flag = RC_DEFAULT;
520long	rps = DEFHZ;			/* revolutions/second of drive */
521int	rps_flag = RC_DEFAULT;
522long	nbpi = NBPI;			/* number of bytes per inode */
523int	nbpi_flag = RC_DEFAULT;
524long	nrpos = NRPOS;			/* number of rotational positions */
525int	nrpos_flag = RC_DEFAULT;
526long	apc = 0;			/* alternate sectors per cylinder */
527int	apc_flag = RC_DEFAULT;
528char	opt = 't';			/* optimization style, `t' or `s' */
529char	mtb = 'n';			/* multi-terabyte format, 'y' or 'n' */
530#define	DEFAULT_SECT_TRAK_CPG	(nsect_flag == RC_DEFAULT && \
531				ntrack_flag == RC_DEFAULT && \
532				cpg_flag == RC_DEFAULT)
533
534long	debug = 0;			/* enable debugging output */
535
536int	spc_flag = 0;			/* alternate sectors specified or */
537					/* found */
538
539/* global state */
540int	Nflag;		/* do not write to disk */
541int	mflag;		/* return the command line used to create this FS */
542int	rflag;		/* report the superblock in an easily-parsed form */
543int	Rflag;		/* dump the superblock in binary */
544char	*fsys;
545time_t	mkfstime;
546char	*string;
547int	label_type;
548
549/*
550 * logging support
551 */
552int	islog;			/* true if ufs logging is enabled */
553int	islogok;		/* true if ufs log state is good */
554int	waslog;			/* true when ufs logging disabled during grow */
555
556/*
557 * growfs defines, globals, and forward references
558 */
559#define	NOTENOUGHSPACE 33
560int		grow;
561#define	GROW_WITH_DEFAULT_TRAK	(grow && ntrack_flag == RC_DEFAULT)
562
563static int	Pflag;		/* probe to which size the fs can be grown */
564int		ismounted;
565char		*directory;
566diskaddr_t	grow_fssize;
567long		grow_fs_size;
568long		grow_fs_ncg;
569diskaddr_t		grow_fs_csaddr;
570long		grow_fs_cssize;
571int		grow_fs_clean;
572struct csum	*grow_fscs;
573diskaddr_t		grow_sifrag;
574int		test;
575int		testforce;
576diskaddr_t		testfrags;
577int		inlockexit;
578int		isbad;
579
580void		lockexit(int) __NORETURN;
581void		randomgeneration(void);
582void		checksummarysize(void);
583int		checksblock(struct fs, int);
584void		growinit(char *);
585void		checkdev(char *, char  *);
586void		checkmount(struct mnttab *, char *);
587struct dinode	*gdinode(ino_t);
588int		csfraginrange(daddr32_t);
589struct csfrag	*findcsfrag(daddr32_t, struct csfrag **);
590void		checkindirect(ino_t, daddr32_t *, daddr32_t, int);
591void		addcsfrag(ino_t, daddr32_t, struct csfrag **);
592void		delcsfrag(daddr32_t, struct csfrag **);
593void		checkdirect(ino_t, daddr32_t *, daddr32_t *, int);
594void		findcsfragino(void);
595void		fixindirect(daddr32_t, int);
596void		fixdirect(caddr_t, daddr32_t, daddr32_t *, int);
597void		fixcsfragino(void);
598void		extendsummaryinfo(void);
599int		notenoughspace(void);
600void		unalloccsfragino(void);
601void		unalloccsfragfree(void);
602void		findcsfragfree(void);
603void		copycsfragino(void);
604void		rdcg(long);
605void		wtcg(void);
606void		flcg(void);
607void		allocfrags(long, daddr32_t *, long *);
608void		alloccsfragino(void);
609void		alloccsfragfree(void);
610void		freefrags(daddr32_t, long, long);
611int		findfreerange(long *, long *);
612void		resetallocinfo(void);
613void		extendcg(long);
614void		ulockfs(void);
615void		wlockfs(void);
616void		clockfs(void);
617void		wtsb(void);
618static int64_t	checkfragallocated(daddr32_t);
619static struct csum	*read_summaryinfo(struct fs *);
620static diskaddr_t	probe_summaryinfo();
621
622int
623main(int argc, char *argv[])
624{
625	long i, mincpc, mincpg, ibpcl;
626	long cylno, rpos, blk, j, warn = 0;
627	long mincpgcnt, maxcpg;
628	uint64_t used, bpcg, inospercg;
629	long mapcramped, inodecramped;
630	long postblsize, rotblsize, totalsbsize;
631	FILE *mnttab;
632	struct mnttab mntp;
633	char *special;
634	struct statvfs64 fs;
635	struct dk_geom dkg;
636	struct dk_minfo dkminfo;
637	char pbuf[sizeof (uint64_t) * 3 + 1];
638	char *tmpbuf;
639	int width, plen;
640	uint64_t num;
641	int c, saverr;
642	diskaddr_t max_fssize;
643	long tmpmaxcontig = -1;
644	struct sigaction sigact;
645	uint64_t nbytes64;
646	int remaining_cg;
647	int do_dot = 0;
648	int use_efi_dflts = 0, retry = 0, isremovable = 0, ishotpluggable = 0;
649	int invalid_sb_cnt, ret, skip_this_sb, cg_too_small;
650	int geom_nsect, geom_ntrack, geom_cpg;
651
652	(void) setlocale(LC_ALL, "");
653
654#if !defined(TEXT_DOMAIN)
655#define	TEXT_DOMAIN "SYS_TEST"
656#endif
657	(void) textdomain(TEXT_DOMAIN);
658
659	while ((c = getopt(argc, argv, "F:bmo:VPGM:T:t:")) != EOF) {
660		switch (c) {
661
662		case 'F':
663			string = optarg;
664			if (strcmp(string, "ufs") != 0)
665				usage();
666			break;
667
668		case 'm':	/* return command line used to create this FS */
669			mflag++;
670			break;
671
672		case 'o':
673			/*
674			 * ufs specific options.
675			 */
676			string = optarg;
677			while (*string != '\0') {
678				if (match("nsect=")) {
679					nsect = number(DFLNSECT, "nsect", 0);
680					nsect_flag = RC_KEYWORD;
681				} else if (match("ntrack=")) {
682					ntrack = number(DFLNTRAK, "ntrack", 0);
683					ntrack_flag = RC_KEYWORD;
684				} else if (match("bsize=")) {
685					bsize = number(DESBLKSIZE, "bsize", 0);
686					bsize_flag = RC_KEYWORD;
687				} else if (match("fragsize=")) {
688					fragsize = number(DESFRAGSIZE,
689					    "fragsize", 0);
690					fragsize_flag = RC_KEYWORD;
691				} else if (match("cgsize=")) {
692					cpg = number(DESCPG, "cgsize", 0);
693					cpg_flag = RC_KEYWORD;
694				} else if (match("free=")) {
695					minfree = number(MINFREE, "free",
696					    ALLOW_PERCENT);
697					minfree_flag = RC_KEYWORD;
698				} else if (match("maxcontig=")) {
699					tmpmaxcontig =
700					    number(-1, "maxcontig", 0);
701					maxcontig_flag = RC_KEYWORD;
702				} else if (match("nrpos=")) {
703					nrpos = number(NRPOS, "nrpos", 0);
704					nrpos_flag = RC_KEYWORD;
705				} else if (match("rps=")) {
706					rps = number(DEFHZ, "rps", 0);
707					rps_flag = RC_KEYWORD;
708				} else if (match("nbpi=")) {
709					nbpi = number(NBPI, "nbpi", 0);
710					nbpi_flag = RC_KEYWORD;
711				} else if (match("opt=")) {
712					opt = checkopt(string);
713				} else if (match("mtb=")) {
714					mtb = checkmtb(string);
715				} else if (match("apc=")) {
716					apc = number(0, "apc", 0);
717					apc_flag = RC_KEYWORD;
718				} else if (match("gap=")) {
719					(void) number(0, "gap", ALLOW_MS1);
720					rotdelay = ROTDELAY;
721					rotdelay_flag = RC_DEFAULT;
722				} else if (match("debug=")) {
723					debug = number(0, "debug", 0);
724				} else if (match("N")) {
725					Nflag++;
726				} else if (match("calcsb")) {
727					rflag++;
728					Nflag++;
729				} else if (match("calcbinsb")) {
730					rflag++;
731					Rflag++;
732					Nflag++;
733				} else if (*string == '\0') {
734					break;
735				} else {
736					(void) fprintf(stderr, gettext(
737					    "illegal option: %s\n"), string);
738					usage();
739				}
740
741				if (*string == ',') string++;
742				if (*string == ' ') string++;
743			}
744			break;
745
746		case 'V':
747			{
748				char	*opt_text;
749				int	opt_count;
750
751				(void) fprintf(stdout, gettext("mkfs -F ufs "));
752				for (opt_count = 1; opt_count < argc;
753				    opt_count++) {
754					opt_text = argv[opt_count];
755					if (opt_text)
756						(void) fprintf(stdout, " %s ",
757						    opt_text);
758				}
759				(void) fprintf(stdout, "\n");
760			}
761			break;
762
763		case 'b':	/* do nothing for this */
764			break;
765
766		case 'M':	/* grow the mounted file system */
767			directory = optarg;
768
769			/* FALLTHROUGH */
770		case 'G':	/* grow the file system */
771			grow = 1;
772			break;
773		case 'P':	/* probe the file system growing size	*/
774			Pflag = 1;
775			grow = 1; /* probe mode implies fs growing	*/
776			break;
777		case 'T':	/* For testing */
778			testforce = 1;
779
780			/* FALLTHROUGH */
781		case 't':
782			test = 1;
783			string = optarg;
784			testfrags = number(NO_DEFAULT, "testfrags", 0);
785			break;
786
787		case '?':
788			usage();
789			break;
790		}
791	}
792#ifdef MKFS_DEBUG
793	/*
794	 * Turning on MKFS_DEBUG causes mkfs to produce a filesystem
795	 * that can be reproduced by setting the time to 0 and seeding
796	 * the random number generator to a constant.
797	 */
798	mkfstime = 0;	/* reproducible results */
799#else
800	(void) time(&mkfstime);
801#endif
802
803	if (optind >= (argc - 1)) {
804		if (optind > (argc - 1)) {
805			(void) fprintf(stderr,
806			    gettext("special not specified\n"));
807			usage();
808		} else if (mflag == 0) {
809			(void) fprintf(stderr,
810			    gettext("size not specified\n"));
811			usage();
812		}
813	}
814	argc -= optind;
815	argv = &argv[optind];
816
817	fsys = argv[0];
818	fsi = open64(fsys, O_RDONLY);
819	if (fsi < 0) {
820		(void) fprintf(stderr, gettext("%s: cannot open\n"), fsys);
821		lockexit(32);
822	}
823
824	if (mflag) {
825		dump_fscmd(fsys, fsi);
826		lockexit(0);
827	}
828
829	/*
830	 * The task of setting all of the configuration parameters for a
831	 * UFS file system is basically a matter of solving n equations
832	 * in m variables.  Typically, m is greater than n, so there is
833	 * usually more than one valid solution.  Since this is usually
834	 * an under-constrained problem, it's not always obvious what the
835	 * "best" configuration is.
836	 *
837	 * In general, the approach is to
838	 * 1. Determine the values for the file system parameters
839	 *    that are externally contrained and therefore not adjustable
840	 *    by mkfs (such as the device's size and maxtransfer size).
841	 * 2. Acquire the user's requested setting for all configuration
842	 *    values that can be set on the command line.
843	 * 3. Determine the final value of all configuration values, by
844	 *    the following approach:
845	 *	- set the file system block size (fs_bsize).  Although
846	 *	  this could be regarded as an adjustable parameter, in
847	 *	  fact, it's pretty much a constant.  At this time, it's
848	 *	  generally set to 8k (with older hardware, it can
849	 *	  sometimes make sense to set it to 4k, but those
850	 *	  situations are pretty rare now).
851	 *	- re-adjust the maximum file system size based on the
852	 *	  value of the file system block size.  Since the
853	 *	  frag size can't be any larger than a file system
854	 *	  block, and the number of frags in the file system
855	 *	  has to fit into 31 bits, the file system block size
856	 *	  affects the maximum file system size.
857	 *	- now that the real maximum file system is known, set the
858	 *	  actual size of the file system to be created to
859	 *	  MIN(requested size, maximum file system size).
860	 *	- now validate, and if necessary, adjust the following
861	 *	  values:
862	 *		rotdelay
863	 *		nsect
864	 *		maxcontig
865	 *		apc
866	 *		frag_size
867	 *		rps
868	 *		minfree
869	 *		nrpos
870	 *		nrack
871	 *		nbpi
872	 *	- calculate maxcpg (the maximum value of the cylinders-per-
873	 *	  cylinder-group configuration parameters).  There are two
874	 *	  algorithms for calculating maxcpg:  an old one, which is
875	 *	  used for file systems of less than 1 terabyte, and a
876	 *	  new one, implemented in the function compute_maxcpg(),
877	 *	  which is used for file systems of greater than 1 TB.
878	 *	  The difference between them is that compute_maxcpg()
879	 *	  really tries to maximize the cpg value.  The old
880	 *	  algorithm fails to take advantage of smaller frags and
881	 *	  lower inode density when determining the maximum cpg,
882	 *	  and thus comes up with much lower numbers in some
883	 *	  configurations.  At some point, we might use the
884	 *	  new algorithm for determining maxcpg for all file
885	 *	  systems, but at this time, the changes implemented for
886	 *	  multi-terabyte UFS are NOT being automatically applied
887	 *	  to UFS file systems of less than a terabyte (in the
888	 *	  interest of not changing existing UFS policy too much
889	 *	  until the ramifications of the changes are well-understood
890	 *	  and have been evaluated for their effects on performance.)
891	 *	- check the current values of the configuration parameters
892	 *	  against the various constraints imposed by UFS.  These
893	 *	  include:
894	 *		* There must be at least one inode in each
895	 *		  cylinder group.
896	 *		* The cylinder group overhead block, which
897	 *		  contains the inode and frag bigmaps, must fit
898	 *		  within one file system block.
899	 *		* The space required for inode maps should
900	 *		  occupy no more than a third of the cylinder
901	 *		  group overhead block.
902	 *		* The rotational position tables have to fit
903	 *		  within the available space in the super block.
904	 *	  Adjust the configuration values that can be adjusted
905	 *	  so that these constraints are satisfied.  The
906	 *	  configuration values that are adjustable are:
907	 *		* frag size
908	 *		* cylinders per group
909	 *		* inode density (can be increased)
910	 *		* number of rotational positions (the rotational
911	 *		  position tables are eliminated altogether if
912	 *		  there isn't enough room for them.)
913	 * 4. Set the values for all the dependent configuration
914	 *    values (those that aren't settable on the command
915	 *    line and which are completely dependent on the
916	 *    adjustable parameters).  This include cpc (cycles
917	 *    per cylinder, spc (sectors-per-cylinder), and many others.
918	 */
919
920	/*
921	 * Figure out the partition size and initialize the label_type.
922	 */
923	max_fssize = get_max_size(fsi);
924
925	/*
926	 * Get and check positional arguments, if any.
927	 */
928	switch (argc - 1) {
929	default:
930		usage();
931		/*NOTREACHED*/
932	case 15:
933		mtb = checkmtb(argv[15]);
934		/* FALLTHROUGH */
935	case 14:
936		string = argv[14];
937		tmpmaxcontig = number(-1, "maxcontig", 0);
938		maxcontig_flag = RC_POSITIONAL;
939		/* FALLTHROUGH */
940	case 13:
941		string = argv[13];
942		nrpos = number(NRPOS, "nrpos", 0);
943		nrpos_flag = RC_POSITIONAL;
944		/* FALLTHROUGH */
945	case 12:
946		string = argv[12];
947		rotdelay = ROTDELAY;
948		rotdelay_flag = RC_DEFAULT;
949		/* FALLTHROUGH */
950	case 11:
951		string = argv[11];
952		apc = number(0, "apc", 0);
953		apc_flag = RC_POSITIONAL;
954		/* FALLTHROUGH */
955	case 10:
956		opt = checkopt(argv[10]);
957		/* FALLTHROUGH */
958	case 9:
959		string = argv[9];
960		nbpi = number(NBPI, "nbpi", 0);
961		nbpi_flag = RC_POSITIONAL;
962		/* FALLTHROUGH */
963	case 8:
964		string = argv[8];
965		rps = number(DEFHZ, "rps", 0);
966		rps_flag = RC_POSITIONAL;
967		/* FALLTHROUGH */
968	case 7:
969		string = argv[7];
970		minfree = number(MINFREE, "free", ALLOW_PERCENT);
971		minfree_flag = RC_POSITIONAL;
972		/* FALLTHROUGH */
973	case 6:
974		string = argv[6];
975		cpg = number(DESCPG, "cgsize", 0);
976		cpg_flag = RC_POSITIONAL;
977		/* FALLTHROUGH */
978	case 5:
979		string = argv[5];
980		fragsize = number(DESFRAGSIZE, "fragsize", 0);
981		fragsize_flag = RC_POSITIONAL;
982		/* FALLTHROUGH */
983	case 4:
984		string = argv[4];
985		bsize = number(DESBLKSIZE, "bsize", 0);
986		bsize_flag = RC_POSITIONAL;
987		/* FALLTHROUGH */
988	case 3:
989		string = argv[3];
990		ntrack = number(DFLNTRAK, "ntrack", 0);
991		ntrack_flag = RC_POSITIONAL;
992		/* FALLTHROUGH */
993	case 2:
994		string = argv[2];
995		nsect = number(DFLNSECT, "nsect", 0);
996		nsect_flag = RC_POSITIONAL;
997		/* FALLTHROUGH */
998	case 1:
999		string = argv[1];
1000		fssize_db = number(max_fssize, "size", 0);
1001	}
1002
1003	/*
1004	 * Initialize the parameters in the same way as newfs so that
1005	 * newfs and mkfs would result in the same file system layout
1006	 * for EFI labelled disks. Do this only in the absence of user
1007	 * specified values for these parameters.
1008	 */
1009	if (label_type == LABEL_TYPE_EFI) {
1010		if (apc_flag == RC_DEFAULT) apc = 0;
1011		if (nrpos_flag == RC_DEFAULT) nrpos = 1;
1012		if (ntrack_flag == RC_DEFAULT) ntrack = DEF_TRACKS_EFI;
1013		if (rps_flag == RC_DEFAULT) rps = DEFHZ;
1014		if (nsect_flag == RC_DEFAULT) nsect = DEF_SECTORS_EFI;
1015	}
1016
1017	if ((maxcontig_flag == RC_DEFAULT) || (tmpmaxcontig == -1) ||
1018	    (maxcontig == -1)) {
1019		long maxtrax = get_max_track_size(fsi);
1020		maxcontig = maxtrax / bsize;
1021
1022	} else {
1023		maxcontig = tmpmaxcontig;
1024	}
1025	dprintf(("DeBuG maxcontig : %ld\n", maxcontig));
1026
1027	if (rotdelay == -1) {	/* default by newfs and mkfs */
1028		rotdelay = ROTDELAY;
1029	}
1030
1031	if (cpg_flag == RC_DEFAULT) { /* If not explicity set, use default */
1032		cpg = DESCPG;
1033	}
1034	dprintf(("DeBuG cpg : %ld\n", cpg));
1035
1036	/*
1037	 * Now that we have the semi-sane args, either positional, via -o,
1038	 * or by defaulting, handle inter-dependencies and range checks.
1039	 */
1040
1041	/*
1042	 * Settle the file system block size first, since it's a fixed
1043	 * parameter once set and so many other parameters, including
1044	 * max_fssize, depend on it.
1045	 */
1046	range_check(&bsize, "bsize", MINBSIZE, MAXBSIZE, DESBLKSIZE,
1047	    bsize_flag);
1048
1049	if (!POWEROF2(bsize)) {
1050		(void) fprintf(stderr,
1051		    gettext("block size must be a power of 2, not %ld\n"),
1052		    bsize);
1053		bsize = DESBLKSIZE;
1054		(void) fprintf(stderr,
1055		    gettext("mkfs: bsize reset to default %ld\n"),
1056		    bsize);
1057	}
1058
1059	if (fssize_db > max_fssize && validate_size(fsi, fssize_db)) {
1060		(void) fprintf(stderr, gettext(
1061		    "Warning: the requested size of this file system\n"
1062		    "(%lld sectors) is greater than the size of the\n"
1063		    "device reported by the driver (%lld sectors).\n"
1064		    "However, a read of the device at the requested size\n"
1065		    "does succeed, so the requested size will be used.\n"),
1066		    fssize_db, max_fssize);
1067		max_fssize = fssize_db;
1068	}
1069	/*
1070	 * Since the maximum allocatable unit (the frag) must be less than
1071	 * or equal to bsize, and the number of frags must be less than or
1072	 * equal to INT_MAX, the total size of the file system (in
1073	 * bytes) must be less than or equal to bsize * INT_MAX.
1074	 */
1075
1076	if (max_fssize > ((diskaddr_t)bsize/DEV_BSIZE) * INT_MAX)
1077		max_fssize = ((diskaddr_t)bsize/DEV_BSIZE) * INT_MAX;
1078
1079	range_check_64(&fssize_db, "size", 1024LL, max_fssize, max_fssize, 1);
1080
1081	if (fssize_db >= SECTORS_PER_TERABYTE) {
1082		mtb = 'y';
1083		if (!in_64bit_mode()) {
1084			(void) fprintf(stderr, gettext(
1085"mkfs:  Warning: Creating a file system greater than 1 terabyte on a\n"
1086"       system running a 32-bit kernel.  This file system will not be\n"
1087"       accessible until the system is rebooted with a 64-bit kernel.\n"));
1088		}
1089	}
1090	dprintf(("DeBuG mtb : %c\n", mtb));
1091
1092	/*
1093	 * With newer and much larger disks, the newfs(1M) and mkfs_ufs(1M)
1094	 * commands had problems in correctly handling the "native" geometries
1095	 * for various storage devices.
1096	 *
1097	 * To handle the new age disks, mkfs_ufs(1M) will use the EFI style
1098	 * for non-EFI disks that are larger than the CHS addressing limit
1099	 * ( > 8GB approx ) and ignore the disk geometry information for
1100	 * these drives. This is what is currently done for multi-terrabyte
1101	 * filesystems on EFI disks.
1102	 *
1103	 * However if the user asked for a specific layout by supplying values
1104	 * for even one of the three parameters (nsect, ntrack, cpg), honour
1105	 * the user supplied parameters.
1106	 *
1107	 * Choosing EFI style or native geometry style can make a lot of
1108	 * difference, because the size of a cylinder group is dependent on
1109	 * this choice. This in turn means that the position of alternate
1110	 * superblocks varies depending on the style chosen. It is not
1111	 * necessary that all disks of size > CHSLIMIT have EFI style layout.
1112	 * There can be disks which are > CHSLIMIT size, but have native
1113	 * geometry style layout, thereby warranting the need for alternate
1114	 * logic in superblock detection.
1115	 */
1116	if (mtb != 'y' && (ntrack == -1 || GROW_WITH_DEFAULT_TRAK ||
1117	    DEFAULT_SECT_TRAK_CPG)) {
1118		/*
1119		 * "-1" indicates that we were called from newfs and ntracks
1120		 * was not specified in newfs command line. Calculate nsect
1121		 * and ntrack in the same manner as newfs.
1122		 *
1123		 * This is required because, the defaults for nsect and ntrack
1124		 * is hardcoded in mkfs, whereas to generate the alternate
1125		 * superblock locations for the -N option, there is a need for
1126		 * the geometry based values that newfs would have arrived at.
1127		 * Newfs would have arrived at these values as below.
1128		 */
1129		if (label_type == LABEL_TYPE_EFI ||
1130		    label_type == LABEL_TYPE_OTHER) {
1131			use_efi_dflts = 1;
1132			retry = 1;
1133		} else if (ioctl(fsi, DKIOCGGEOM, &dkg)) {
1134			dprintf(("%s: Unable to read Disk geometry", fsys));
1135			perror(gettext("Unable to read Disk geometry"));
1136			lockexit(32);
1137		} else {
1138			nsect = dkg.dkg_nsect;
1139			ntrack = dkg.dkg_nhead;
1140#ifdef i386	/* Bug 1170182 */
1141			if (ntrack > 32 && (ntrack % 16) != 0) {
1142				ntrack -= (ntrack % 16);
1143			}
1144#endif
1145			if (ioctl(fsi, DKIOCREMOVABLE, &isremovable)) {
1146				dprintf(("DeBuG Unable to determine if %s is"
1147				    " Removable Media. Proceeding with system"
1148				    " determined parameters.\n", fsys));
1149				isremovable = 0;
1150			}
1151			if (ioctl(fsi, DKIOCHOTPLUGGABLE, &ishotpluggable)) {
1152				dprintf(("DeBuG Unable to determine if %s is"
1153				    " Hotpluggable Media. Proceeding with "
1154				    "system determined parameters.\n", fsys));
1155				ishotpluggable = 0;
1156			}
1157			if ((((diskaddr_t)dkg.dkg_ncyl * dkg.dkg_nhead *
1158			    dkg.dkg_nsect) > CHSLIMIT) || isremovable ||
1159			    ishotpluggable) {
1160				use_efi_dflts = 1;
1161				retry = 1;
1162			}
1163		}
1164	}
1165	dprintf(("DeBuG CHSLIMIT = %d geom = %llu\n", CHSLIMIT,
1166	    (diskaddr_t)dkg.dkg_ncyl * dkg.dkg_nhead * dkg.dkg_nsect));
1167	dprintf(("DeBuG label_type = %d isremovable = %d ishotpluggable = %d "
1168	    "use_efi_dflts = %d\n", label_type, isremovable, ishotpluggable,
1169	    use_efi_dflts));
1170
1171	/*
1172	 * For the newfs -N case, even if the disksize is > CHSLIMIT, do not
1173	 * blindly follow EFI style. If the fs_version indicates a geometry
1174	 * based layout, try that one first. If it fails we can always try the
1175	 * other logic.
1176	 *
1177	 * If we were called from growfs, we will have a problem if we mix
1178	 * and match the filesystem creation and growth styles. For example,
1179	 * if we create using EFI style, we have to also grow using EFI
1180	 * style. So follow the style indicated by the fs_version.
1181	 *
1182	 * Read and verify the primary superblock. If it looks sane, use the
1183	 * fs_version from the superblock. If the primary superblock does
1184	 * not look good, read and verify the first alternate superblock at
1185	 * ALTSB. Use the fs_version to decide whether to use the
1186	 * EFI style logic or the old geometry based logic to calculate
1187	 * the alternate superblock locations.
1188	 */
1189	if ((Nflag && use_efi_dflts) || (grow)) {
1190		if (grow && ntrack_flag != RC_DEFAULT)
1191			goto start_fs_creation;
1192		rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize,
1193		    (char *)&altsblock);
1194		ret = checksblock(altsblock, 1);
1195
1196		if (!ret) {
1197			if (altsblock.fs_magic == MTB_UFS_MAGIC) {
1198				mtb = 'y';
1199				goto start_fs_creation;
1200			}
1201			use_efi_dflts = (altsblock.fs_version ==
1202			    UFS_EFISTYLE4NONEFI_VERSION_2) ? 1 : 0;
1203		} else {
1204			/*
1205			 * The primary superblock didn't help in determining
1206			 * the fs_version. Try the first alternate superblock.
1207			 */
1208			dprintf(("DeBuG checksblock() failed - error : %d"
1209			    " for sb : %d\n", ret, SBOFF/sectorsize));
1210			rdfs((diskaddr_t)ALTSB, (int)sbsize,
1211			    (char *)&altsblock);
1212			ret = checksblock(altsblock, 1);
1213
1214			if (!ret) {
1215				if (altsblock.fs_magic == MTB_UFS_MAGIC) {
1216					mtb = 'y';
1217					goto start_fs_creation;
1218				}
1219				use_efi_dflts = (altsblock.fs_version ==
1220				    UFS_EFISTYLE4NONEFI_VERSION_2) ? 1 : 0;
1221			}
1222			dprintf(("DeBuG checksblock() returned : %d"
1223			    " for sb : %d\n", ret, ALTSB));
1224		}
1225	}
1226
1227	geom_nsect = nsect;
1228	geom_ntrack = ntrack;
1229	geom_cpg = cpg;
1230	dprintf(("DeBuG geom_nsect=%d, geom_ntrack=%d, geom_cpg=%d\n",
1231	    geom_nsect, geom_ntrack, geom_cpg));
1232
1233start_fs_creation:
1234retry_alternate_logic:
1235	invalid_sb_cnt = 0;
1236	cg_too_small = 0;
1237	if (use_efi_dflts) {
1238		nsect = DEF_SECTORS_EFI;
1239		ntrack = DEF_TRACKS_EFI;
1240		cpg = DESCPG;
1241		dprintf(("\nDeBuG Using EFI defaults\n"));
1242	} else {
1243		nsect = geom_nsect;
1244		ntrack = geom_ntrack;
1245		cpg = geom_cpg;
1246		dprintf(("\nDeBuG Using Geometry\n"));
1247		/*
1248		 * 32K based on max block size of 64K, and rotational layout
1249		 * test of nsect <= (256 * sectors/block).  Current block size
1250		 * limit is not 64K, but it's growing soon.
1251		 */
1252		range_check(&nsect, "nsect", 1, 32768, DFLNSECT, nsect_flag);
1253		/*
1254		 * ntrack is the number of tracks per cylinder.
1255		 * The ntrack value must be between 1 and the total number of
1256		 * sectors in the file system.
1257		 */
1258		range_check(&ntrack, "ntrack", 1,
1259		    fssize_db > INT_MAX ? INT_MAX : (uint32_t)fssize_db,
1260		    DFLNTRAK, ntrack_flag);
1261	}
1262
1263	range_check(&apc, "apc", 0, nsect - 1, 0, apc_flag);
1264
1265	if (mtb == 'y')
1266		fragsize = bsize;
1267
1268	range_check(&fragsize, "fragsize", sectorsize, bsize,
1269	    MAX(bsize / MAXFRAG, MIN(DESFRAGSIZE, bsize)), fragsize_flag);
1270
1271	if ((bsize / MAXFRAG) > fragsize) {
1272		(void) fprintf(stderr, gettext(
1273"fragment size %ld is too small, minimum with block size %ld is %ld\n"),
1274		    fragsize, bsize, bsize / MAXFRAG);
1275		(void) fprintf(stderr,
1276		    gettext("mkfs: fragsize reset to minimum %ld\n"),
1277		    bsize / MAXFRAG);
1278		fragsize = bsize / MAXFRAG;
1279	}
1280
1281	if (!POWEROF2(fragsize)) {
1282		(void) fprintf(stderr,
1283		    gettext("fragment size must be a power of 2, not %ld\n"),
1284		    fragsize);
1285		fragsize = MAX(bsize / MAXFRAG, MIN(DESFRAGSIZE, bsize));
1286		(void) fprintf(stderr,
1287		    gettext("mkfs: fragsize reset to %ld\n"),
1288		    fragsize);
1289	}
1290
1291	/* At this point, bsize must be >= fragsize, so no need to check it */
1292
1293	if (bsize < PAGESIZE) {
1294		(void) fprintf(stderr, gettext(
1295		    "WARNING: filesystem block size (%ld) is smaller than "
1296		    "memory page size (%ld).\nResulting filesystem can not be "
1297		    "mounted on this system.\n\n"),
1298		    bsize, (long)PAGESIZE);
1299	}
1300
1301	range_check(&rps, "rps", 1, 1000, DEFHZ, rps_flag);
1302	range_check(&minfree, "free", 0, 99, MINFREE, minfree_flag);
1303	range_check(&nrpos, "nrpos", 1, nsect, MIN(nsect, NRPOS), nrpos_flag);
1304
1305	/*
1306	 * nbpi is variable, but 2MB seems a reasonable upper limit,
1307	 * as 4MB tends to cause problems (using otherwise-default
1308	 * parameters).  The true limit is where we end up with one
1309	 * inode per cylinder group.  If this file system is being
1310	 * configured for multi-terabyte access, nbpi must be at least 1MB.
1311	 */
1312	if (mtb == 'y' && nbpi < MTB_NBPI) {
1313		if (nbpi_flag != RC_DEFAULT)
1314			(void) fprintf(stderr, gettext("mkfs: bad value for "
1315			    "nbpi: must be at least 1048576 for multi-terabyte,"
1316			    " nbpi reset to default 1048576\n"));
1317		nbpi = MTB_NBPI;
1318	}
1319
1320	if (mtb == 'y')
1321		range_check(&nbpi, "nbpi", MTB_NBPI, 2 * MB, MTB_NBPI,
1322		    nbpi_flag);
1323	else
1324		range_check(&nbpi, "nbpi", DEV_BSIZE, 2 * MB, NBPI, nbpi_flag);
1325
1326	/*
1327	 * maxcpg is another variably-limited parameter.  Calculate
1328	 * the limit based on what we've got for its dependent
1329	 * variables.  Effectively, it's how much space is left in the
1330	 * superblock after all the other bits are accounted for.  We
1331	 * only fill in sblock fields so we can use MAXIpG.
1332	 *
1333	 * If the calculation of maxcpg below (for the mtb == 'n'
1334	 * case) is changed, update newfs as well.
1335	 *
1336	 * For old-style, non-MTB format file systems, use the old
1337	 * algorithm for calculating the maximum cylinder group size,
1338	 * even though it limits the cylinder group more than necessary.
1339	 * Since layout can affect performance, we don't want to change
1340	 * the default layout for non-MTB file systems at this time.
1341	 * However, for MTB file systems, use the new maxcpg calculation,
1342	 * which really maxes out the cylinder group size.
1343	 */
1344
1345	sblock.fs_bsize = bsize;
1346	sblock.fs_inopb = sblock.fs_bsize / sizeof (struct dinode);
1347
1348	if (mtb == 'n') {
1349		maxcpg = (bsize - sizeof (struct cg) -
1350		    howmany(MAXIpG(&sblock), NBBY)) /
1351		    (sizeof (long) + nrpos * sizeof (short) +
1352		    nsect / (MAXFRAG * NBBY));
1353	} else {
1354		maxcpg = compute_maxcpg(bsize, fragsize, nbpi, nrpos,
1355		    nsect * ntrack);
1356	}
1357
1358	dprintf(("DeBuG cpg : %ld\n", cpg));
1359	/*
1360	 * Increase the cpg to maxcpg if either newfs was invoked
1361	 * with -T option or if mkfs wants to create a mtb file system
1362	 * and if the user has not specified the cpg.
1363	 */
1364	if (cpg == -1 || (mtb == 'y' && cpg_flag == RC_DEFAULT))
1365		cpg = maxcpg;
1366	dprintf(("DeBuG cpg : %ld\n", cpg));
1367
1368	/*
1369	 * mincpg is variable in complex ways, so we really can't
1370	 * do a sane lower-end limit check at this point.
1371	 */
1372	range_check(&cpg, "cgsize", 1, maxcpg, MIN(maxcpg, DESCPG), cpg_flag);
1373
1374	/*
1375	 * get the controller info
1376	 */
1377	islog = 0;
1378	islogok = 0;
1379	waslog = 0;
1380
1381	/*
1382	 * Do not grow the file system, but print on stdout the maximum
1383	 * size in sectors to which the file system can be increased.
1384	 * The calculated size is limited by fssize_db.
1385	 * Note that we don't lock the filesystem and therefore under rare
1386	 * conditions (the filesystem is mounted, the free block count is
1387	 * almost zero, and the superuser is still changing it) the calculated
1388	 * size can be imprecise.
1389	 */
1390	if (Pflag) {
1391		(void) printf("%llu\n", probe_summaryinfo());
1392		exit(0);
1393	}
1394
1395	/*
1396	 * If we're growing an existing filesystem, then we're about
1397	 * to start doing things that can require recovery efforts if
1398	 * we get interrupted, so make sure we get a chance to do so.
1399	 */
1400	if (grow) {
1401		sigact.sa_handler = recover_from_sigint;
1402		sigemptyset(&sigact.sa_mask);
1403		sigact.sa_flags = SA_RESTART;
1404
1405		if (sigaction(SIGINT, &sigact, (struct sigaction *)NULL) < 0) {
1406			perror(gettext("Could not register SIGINT handler"));
1407			lockexit(3);
1408		}
1409	}
1410
1411	if (!Nflag) {
1412		/*
1413		 * Check if MNTTAB is trustable
1414		 */
1415		if (statvfs64(MNTTAB, &fs) < 0) {
1416			(void) fprintf(stderr, gettext("can't statvfs %s\n"),
1417			    MNTTAB);
1418			exit(32);
1419		}
1420
1421		if (strcmp(MNTTYPE_MNTFS, fs.f_basetype) != 0) {
1422			(void) fprintf(stderr, gettext(
1423			    "%s file system type is not %s, can't mkfs\n"),
1424			    MNTTAB, MNTTYPE_MNTFS);
1425			exit(32);
1426		}
1427
1428		special = getfullblkname(fsys);
1429		checkdev(fsys, special);
1430
1431		/*
1432		 * If we found the block device name,
1433		 * then check the mount table.
1434		 * if mounted, and growing write lock the file system
1435		 *
1436		 */
1437		if ((special != NULL) && (*special != '\0')) {
1438			if ((mnttab = fopen(MNTTAB, "r")) == NULL) {
1439				(void) fprintf(stderr, gettext(
1440				    "can't open %s\n"), MNTTAB);
1441				exit(32);
1442			}
1443			while ((getmntent(mnttab, &mntp)) == 0) {
1444				if (grow) {
1445					checkmount(&mntp, special);
1446					continue;
1447				}
1448				if (strcmp(special, mntp.mnt_special) == 0) {
1449					(void) fprintf(stderr, gettext(
1450					    "%s is mounted, can't mkfs\n"),
1451					    special);
1452					exit(32);
1453				}
1454			}
1455			(void) fclose(mnttab);
1456		}
1457
1458		if (directory && (ismounted == 0)) {
1459			(void) fprintf(stderr, gettext("%s is not mounted\n"),
1460			    special);
1461			lockexit(32);
1462		}
1463
1464		fso = (grow) ? open64(fsys, O_WRONLY) : creat64(fsys, 0666);
1465		if (fso < 0) {
1466			saverr = errno;
1467			(void) fprintf(stderr,
1468			    gettext("%s: cannot create: %s\n"),
1469			    fsys, strerror(saverr));
1470			lockexit(32);
1471		}
1472
1473	} else {
1474
1475		/*
1476		 * For the -N case, a file descriptor is needed for the llseek()
1477		 * in wtfs(). See the comment in wtfs() for more information.
1478		 *
1479		 * Get a file descriptor that's read-only so that this code
1480		 * doesn't accidentally write to the file.
1481		 */
1482		fso = open64(fsys, O_RDONLY);
1483		if (fso < 0) {
1484			saverr = errno;
1485			(void) fprintf(stderr, gettext("%s: cannot open: %s\n"),
1486			    fsys, strerror(saverr));
1487			lockexit(32);
1488		}
1489	}
1490
1491	/*
1492	 * Check the media sector size
1493	 */
1494	if (ioctl(fso, DKIOCGMEDIAINFO, &dkminfo) != -1) {
1495		if (dkminfo.dki_lbsize != 0 &&
1496		    POWEROF2(dkminfo.dki_lbsize / DEV_BSIZE) &&
1497		    dkminfo.dki_lbsize != DEV_BSIZE) {
1498			fprintf(stderr,
1499			    gettext("The device sector size %u is not "
1500			    "supported by ufs!\n"), dkminfo.dki_lbsize);
1501			(void) close(fso);
1502			exit(1);
1503		}
1504	}
1505
1506	/*
1507	 * seed random # generator (for ic_generation)
1508	 */
1509#ifdef MKFS_DEBUG
1510	srand48(12962);	/* reproducible results */
1511#else
1512	srand48((long)(time((time_t *)NULL) + getpid()));
1513#endif
1514
1515	if (grow) {
1516		growinit(fsys);
1517		goto grow00;
1518	}
1519
1520	/*
1521	 * Validate the given file system size.
1522	 * Verify that its last block can actually be accessed.
1523	 *
1524	 * Note: it's ok to use sblock as a buffer because it is immediately
1525	 * overwritten by the rdfs() of the superblock in the next line.
1526	 *
1527	 * ToDo: Because the size checking is done in rdfs()/wtfs(), the
1528	 * error message for specifying an illegal size is very unfriendly.
1529	 * In the future, one could replace the rdfs()/wtfs() calls
1530	 * below with in-line calls to read() or write(). This allows better
1531	 * error messages to be put in place.
1532	 */
1533	rdfs(fssize_db - 1, (int)sectorsize, (char *)&sblock);
1534
1535	/*
1536	 * make the fs unmountable
1537	 */
1538	rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
1539	sblock.fs_magic = -1;
1540	sblock.fs_clean = FSBAD;
1541	sblock.fs_state = FSOKAY - sblock.fs_time;
1542	wtfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
1543	bzero(&sblock, (size_t)sbsize);
1544
1545	sblock.fs_nsect = nsect;
1546	sblock.fs_ntrak = ntrack;
1547
1548	/*
1549	 * Validate specified/determined spc
1550	 * and calculate minimum cylinders per group.
1551	 */
1552
1553	/*
1554	 * sectors/cyl = tracks/cyl * sectors/track
1555	 */
1556	sblock.fs_spc = sblock.fs_ntrak * sblock.fs_nsect;
1557
1558grow00:
1559	if (apc_flag) {
1560		sblock.fs_spc -= apc;
1561	}
1562	/*
1563	 * Have to test for this separately from apc_flag, due to
1564	 * the growfs case....
1565	 */
1566	if (sblock.fs_spc != sblock.fs_ntrak * sblock.fs_nsect) {
1567		spc_flag = 1;
1568	}
1569	if (grow)
1570		goto grow10;
1571
1572	sblock.fs_nrpos = nrpos;
1573	sblock.fs_bsize = bsize;
1574	sblock.fs_fsize = fragsize;
1575	sblock.fs_minfree = minfree;
1576
1577grow10:
1578	if (nbpi < sblock.fs_fsize) {
1579		(void) fprintf(stderr, gettext(
1580		"warning: wasteful data byte allocation / inode (nbpi):\n"));
1581		(void) fprintf(stderr, gettext(
1582		    "%ld smaller than allocatable fragment size of %d\n"),
1583		    nbpi, sblock.fs_fsize);
1584	}
1585	if (grow)
1586		goto grow20;
1587
1588	if (opt == 's')
1589		sblock.fs_optim = FS_OPTSPACE;
1590	else
1591		sblock.fs_optim = FS_OPTTIME;
1592
1593	sblock.fs_bmask = ~(sblock.fs_bsize - 1);
1594	sblock.fs_fmask = ~(sblock.fs_fsize - 1);
1595	/*
1596	 * Planning now for future expansion.
1597	 */
1598#if defined(_BIG_ENDIAN)
1599		sblock.fs_qbmask.val[0] = 0;
1600		sblock.fs_qbmask.val[1] = ~sblock.fs_bmask;
1601		sblock.fs_qfmask.val[0] = 0;
1602		sblock.fs_qfmask.val[1] = ~sblock.fs_fmask;
1603#endif
1604#if defined(_LITTLE_ENDIAN)
1605		sblock.fs_qbmask.val[0] = ~sblock.fs_bmask;
1606		sblock.fs_qbmask.val[1] = 0;
1607		sblock.fs_qfmask.val[0] = ~sblock.fs_fmask;
1608		sblock.fs_qfmask.val[1] = 0;
1609#endif
1610	for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1)
1611		sblock.fs_bshift++;
1612	for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1)
1613		sblock.fs_fshift++;
1614	sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize);
1615	for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1)
1616		sblock.fs_fragshift++;
1617	if (sblock.fs_frag > MAXFRAG) {
1618		(void) fprintf(stderr, gettext(
1619	"fragment size %d is too small, minimum with block size %d is %d\n"),
1620		    sblock.fs_fsize, sblock.fs_bsize,
1621		    sblock.fs_bsize / MAXFRAG);
1622		lockexit(32);
1623	}
1624	sblock.fs_nindir = sblock.fs_bsize / sizeof (daddr32_t);
1625	sblock.fs_inopb = sblock.fs_bsize / sizeof (struct dinode);
1626	sblock.fs_nspf = sblock.fs_fsize / sectorsize;
1627	for (sblock.fs_fsbtodb = 0, i = NSPF(&sblock); i > 1; i >>= 1)
1628		sblock.fs_fsbtodb++;
1629
1630	/*
1631	 * Compute the super-block, cylinder group, and inode blocks.
1632	 * Note that these "blkno" are really fragment addresses.
1633	 * For example, on an 8K/1K (block/fragment) system, fs_sblkno is 16,
1634	 * fs_cblkno is 24, and fs_iblkno is 32. This is why CGSIZE is so
1635	 * important: only 1 FS block is allocated for the cg struct (fragment
1636	 * numbers 24 through 31).
1637	 */
1638	sblock.fs_sblkno =
1639	    roundup(howmany(bbsize + sbsize, sblock.fs_fsize), sblock.fs_frag);
1640	sblock.fs_cblkno = (daddr32_t)(sblock.fs_sblkno +
1641	    roundup(howmany(sbsize, sblock.fs_fsize), sblock.fs_frag));
1642	sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag;
1643
1644	sblock.fs_cgoffset = roundup(
1645	    howmany(sblock.fs_nsect, NSPF(&sblock)), sblock.fs_frag);
1646	for (sblock.fs_cgmask = -1, i = sblock.fs_ntrak; i > 1; i >>= 1)
1647		sblock.fs_cgmask <<= 1;
1648	if (!POWEROF2(sblock.fs_ntrak))
1649		sblock.fs_cgmask <<= 1;
1650	/*
1651	 * Validate specified/determined spc
1652	 * and calculate minimum cylinders per group.
1653	 */
1654
1655	for (sblock.fs_cpc = NSPB(&sblock), i = sblock.fs_spc;
1656	    sblock.fs_cpc > 1 && (i & 1) == 0;
1657	    sblock.fs_cpc >>= 1, i >>= 1)
1658		/* void */;
1659	mincpc = sblock.fs_cpc;
1660
1661	/* if these calculations are changed, check dump_fscmd also */
1662	bpcg = (uint64_t)sblock.fs_spc * sectorsize;
1663	inospercg = (uint64_t)roundup(bpcg / sizeof (struct dinode),
1664	    INOPB(&sblock));
1665	if (inospercg > MAXIpG(&sblock))
1666		inospercg = MAXIpG(&sblock);
1667	used = (uint64_t)(sblock.fs_iblkno + inospercg /
1668	    INOPF(&sblock)) * NSPF(&sblock);
1669	mincpgcnt = (long)howmany((uint64_t)sblock.fs_cgoffset *
1670	    (~sblock.fs_cgmask) + used, sblock.fs_spc);
1671	mincpg = roundup(mincpgcnt, mincpc);
1672	/*
1673	 * Insure that cylinder group with mincpg has enough space
1674	 * for block maps
1675	 */
1676	sblock.fs_cpg = mincpg;
1677	sblock.fs_ipg = (int32_t)inospercg;
1678	mapcramped = 0;
1679
1680	/*
1681	 * Make sure the cg struct fits within the file system block.
1682	 * Use larger block sizes until it fits
1683	 */
1684	while (CGSIZE(&sblock) > sblock.fs_bsize) {
1685		mapcramped = 1;
1686		if (sblock.fs_bsize < MAXBSIZE) {
1687			sblock.fs_bsize <<= 1;
1688			if ((i & 1) == 0) {
1689				i >>= 1;
1690			} else {
1691				sblock.fs_cpc <<= 1;
1692				mincpc <<= 1;
1693				mincpg = roundup(mincpgcnt, mincpc);
1694				sblock.fs_cpg = mincpg;
1695			}
1696			sblock.fs_frag <<= 1;
1697			sblock.fs_fragshift += 1;
1698			if (sblock.fs_frag <= MAXFRAG)
1699				continue;
1700		}
1701
1702		/*
1703		 * Looped far enough. The fragment is now as large as the
1704		 * filesystem block!
1705		 */
1706		if (sblock.fs_fsize == sblock.fs_bsize) {
1707			(void) fprintf(stderr, gettext(
1708		    "There is no block size that can support this disk\n"));
1709			lockexit(32);
1710		}
1711
1712		/*
1713		 * Try a larger fragment. Double the fragment size.
1714		 */
1715		sblock.fs_frag >>= 1;
1716		sblock.fs_fragshift -= 1;
1717		sblock.fs_fsize <<= 1;
1718		sblock.fs_nspf <<= 1;
1719	}
1720	/*
1721	 * Insure that cylinder group with mincpg has enough space for inodes
1722	 */
1723	inodecramped = 0;
1724	used *= sectorsize;
1725	nbytes64 = (uint64_t)mincpg * bpcg - used;
1726	inospercg = (uint64_t)roundup((nbytes64 / nbpi), INOPB(&sblock));
1727	sblock.fs_ipg = (int32_t)inospercg;
1728	while (inospercg > MAXIpG(&sblock)) {
1729		inodecramped = 1;
1730		if (mincpc == 1 || sblock.fs_frag == 1 ||
1731		    sblock.fs_bsize == MINBSIZE)
1732			break;
1733		nbytes64 = (uint64_t)mincpg * bpcg - used;
1734		(void) fprintf(stderr,
1735		    gettext("With a block size of %d %s %lu\n"),
1736		    sblock.fs_bsize, gettext("minimum bytes per inode is"),
1737		    (uint32_t)(nbytes64 / MAXIpG(&sblock) + 1));
1738		sblock.fs_bsize >>= 1;
1739		sblock.fs_frag >>= 1;
1740		sblock.fs_fragshift -= 1;
1741		mincpc >>= 1;
1742		sblock.fs_cpg = roundup(mincpgcnt, mincpc);
1743		if (CGSIZE(&sblock) > sblock.fs_bsize) {
1744			sblock.fs_bsize <<= 1;
1745			break;
1746		}
1747		mincpg = sblock.fs_cpg;
1748		nbytes64 = (uint64_t)mincpg * bpcg - used;
1749		inospercg = (uint64_t)roundup((nbytes64 / nbpi),
1750		    INOPB(&sblock));
1751		sblock.fs_ipg = (int32_t)inospercg;
1752	}
1753	if (inodecramped) {
1754		if (inospercg > MAXIpG(&sblock)) {
1755			nbytes64 = (uint64_t)mincpg * bpcg - used;
1756			(void) fprintf(stderr, gettext(
1757			    "Minimum bytes per inode is %d\n"),
1758			    (uint32_t)(nbytes64 / MAXIpG(&sblock) + 1));
1759		} else if (!mapcramped) {
1760			(void) fprintf(stderr, gettext(
1761	    "With %ld bytes per inode, minimum cylinders per group is %ld\n"),
1762			    nbpi, mincpg);
1763		}
1764	}
1765	if (mapcramped) {
1766		(void) fprintf(stderr, gettext(
1767		    "With %d sectors per cylinder, minimum cylinders "
1768		    "per group is %ld\n"),
1769		    sblock.fs_spc, mincpg);
1770	}
1771	if (inodecramped || mapcramped) {
1772		/*
1773		 * To make this at least somewhat comprehensible in
1774		 * the world of i18n, figure out what we're going to
1775		 * say and then say it all at one time.  The days of
1776		 * needing to scrimp on string space are behind us....
1777		 */
1778		if ((sblock.fs_bsize != bsize) &&
1779		    (sblock.fs_fsize != fragsize)) {
1780			(void) fprintf(stderr, gettext(
1781	    "This requires the block size to be changed from %ld to %d\n"
1782	    "and the fragment size to be changed from %ld to %d\n"),
1783			    bsize, sblock.fs_bsize,
1784			    fragsize, sblock.fs_fsize);
1785		} else if (sblock.fs_bsize != bsize) {
1786			(void) fprintf(stderr, gettext(
1787	    "This requires the block size to be changed from %ld to %d\n"),
1788			    bsize, sblock.fs_bsize);
1789		} else if (sblock.fs_fsize != fragsize) {
1790			(void) fprintf(stderr, gettext(
1791	    "This requires the fragment size to be changed from %ld to %d\n"),
1792			    fragsize, sblock.fs_fsize);
1793		} else {
1794			(void) fprintf(stderr, gettext(
1795	    "Unable to make filesystem fit with the given constraints\n"));
1796		}
1797		(void) fprintf(stderr, gettext(
1798		    "Please re-run mkfs with corrected parameters\n"));
1799		lockexit(32);
1800	}
1801	/*
1802	 * Calculate the number of cylinders per group
1803	 */
1804	sblock.fs_cpg = cpg;
1805	if (sblock.fs_cpg % mincpc != 0) {
1806		(void) fprintf(stderr, gettext(
1807		    "Warning: cylinder groups must have a multiple "
1808		    "of %ld cylinders with the given\n         parameters\n"),
1809		    mincpc);
1810		sblock.fs_cpg = roundup(sblock.fs_cpg, mincpc);
1811		(void) fprintf(stderr, gettext("Rounded cgsize up to %d\n"),
1812		    sblock.fs_cpg);
1813	}
1814	/*
1815	 * Must insure there is enough space for inodes
1816	 */
1817	/* if these calculations are changed, check dump_fscmd also */
1818	nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
1819	sblock.fs_ipg = roundup((uint32_t)(nbytes64 / nbpi), INOPB(&sblock));
1820
1821	/*
1822	 * Slim down cylinders per group, until the inodes can fit.
1823	 */
1824	while (sblock.fs_ipg > MAXIpG(&sblock)) {
1825		inodecramped = 1;
1826		sblock.fs_cpg -= mincpc;
1827		nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
1828		sblock.fs_ipg = roundup((uint32_t)(nbytes64 / nbpi),
1829		    INOPB(&sblock));
1830	}
1831	/*
1832	 * Must insure there is enough space to hold block map.
1833	 * Cut down on cylinders per group, until the cg struct fits in a
1834	 * filesystem block.
1835	 */
1836	while (CGSIZE(&sblock) > sblock.fs_bsize) {
1837		mapcramped = 1;
1838		sblock.fs_cpg -= mincpc;
1839		nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
1840		sblock.fs_ipg = roundup((uint32_t)(nbytes64 / nbpi),
1841		    INOPB(&sblock));
1842	}
1843	sblock.fs_fpg = (sblock.fs_cpg * sblock.fs_spc) / NSPF(&sblock);
1844	if ((sblock.fs_cpg * sblock.fs_spc) % NSPB(&sblock) != 0) {
1845		(void) fprintf(stderr,
1846		gettext("newfs: panic (fs_cpg * fs_spc) %% NSPF != 0\n"));
1847		lockexit(32);
1848	}
1849	if (sblock.fs_cpg < mincpg) {
1850		(void) fprintf(stderr, gettext(
1851"With the given parameters, cgsize must be at least %ld; please re-run mkfs\n"),
1852		    mincpg);
1853		lockexit(32);
1854	}
1855	sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock));
1856grow20:
1857	/*
1858	 * Now have size for file system and nsect and ntrak.
1859	 * Determine number of cylinders and blocks in the file system.
1860	 */
1861	fssize_frag = (int64_t)dbtofsb(&sblock, fssize_db);
1862	if (fssize_frag > INT_MAX) {
1863		(void) fprintf(stderr, gettext(
1864"There are too many fragments in the system, increase fragment size\n"),
1865		    mincpg);
1866		lockexit(32);
1867	}
1868	sblock.fs_size = (int32_t)fssize_frag;
1869	sblock.fs_ncyl = (int32_t)(fssize_frag * NSPF(&sblock) / sblock.fs_spc);
1870	if (fssize_frag * NSPF(&sblock) >
1871	    (uint64_t)sblock.fs_ncyl * sblock.fs_spc) {
1872		sblock.fs_ncyl++;
1873		warn = 1;
1874	}
1875	if (sblock.fs_ncyl < 1) {
1876		(void) fprintf(stderr, gettext(
1877		    "file systems must have at least one cylinder\n"));
1878		lockexit(32);
1879	}
1880	if (grow)
1881		goto grow30;
1882	/*
1883	 * Determine feasability/values of rotational layout tables.
1884	 *
1885	 * The size of the rotational layout tables is limited by the size
1886	 * of the file system block, fs_bsize.  The amount of space
1887	 * available for tables is calculated as (fs_bsize - sizeof (struct
1888	 * fs)).  The size of these tables is inversely proportional to the
1889	 * block size of the file system. The size increases if sectors per
1890	 * track are not powers of two, because more cylinders must be
1891	 * described by the tables before the rotational pattern repeats
1892	 * (fs_cpc).
1893	 */
1894	sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
1895	sblock.fs_sbsize = fragroundup(&sblock, sizeof (struct fs));
1896	sblock.fs_npsect = sblock.fs_nsect;
1897	if (sblock.fs_ntrak == 1) {
1898		sblock.fs_cpc = 0;
1899		goto next;
1900	}
1901	postblsize = sblock.fs_nrpos * sblock.fs_cpc * sizeof (short);
1902	rotblsize = sblock.fs_cpc * sblock.fs_spc / NSPB(&sblock);
1903	totalsbsize = sizeof (struct fs) + rotblsize;
1904
1905	/* do static allocation if nrpos == 8 and fs_cpc == 16  */
1906	if (sblock.fs_nrpos == 8 && sblock.fs_cpc <= 16) {
1907		/* use old static table space */
1908		sblock.fs_postbloff = (char *)(&sblock.fs_opostbl[0][0]) -
1909		    (char *)(&sblock.fs_link);
1910		sblock.fs_rotbloff = &sblock.fs_space[0] -
1911		    (uchar_t *)(&sblock.fs_link);
1912	} else {
1913		/* use 4.3 dynamic table space */
1914		sblock.fs_postbloff = &sblock.fs_space[0] -
1915		    (uchar_t *)(&sblock.fs_link);
1916		sblock.fs_rotbloff = sblock.fs_postbloff + postblsize;
1917		totalsbsize += postblsize;
1918	}
1919	if (totalsbsize > sblock.fs_bsize ||
1920	    sblock.fs_nsect > (1 << NBBY) * NSPB(&sblock)) {
1921		(void) fprintf(stderr, gettext(
1922		    "Warning: insufficient space in super block for\n"
1923		    "rotational layout tables with nsect %d, ntrack %d, "
1924		    "and nrpos %d.\nOmitting tables - file system "
1925		    "performance may be impaired.\n"),
1926		    sblock.fs_nsect, sblock.fs_ntrak, sblock.fs_nrpos);
1927
1928		/*
1929		 * Setting fs_cpc to 0 tells alloccgblk() in ufs_alloc.c to
1930		 * ignore the positional layout table and rotational
1931		 * position table.
1932		 */
1933		sblock.fs_cpc = 0;
1934		goto next;
1935	}
1936	sblock.fs_sbsize = fragroundup(&sblock, totalsbsize);
1937
1938
1939	/*
1940	 * calculate the available blocks for each rotational position
1941	 */
1942	for (cylno = 0; cylno < sblock.fs_cpc; cylno++)
1943		for (rpos = 0; rpos < sblock.fs_nrpos; rpos++)
1944			fs_postbl(&sblock, cylno)[rpos] = -1;
1945	for (i = (rotblsize - 1) * sblock.fs_frag;
1946	    i >= 0; i -= sblock.fs_frag) {
1947		cylno = cbtocylno(&sblock, i);
1948		rpos = cbtorpos(&sblock, i);
1949		blk = fragstoblks(&sblock, i);
1950		if (fs_postbl(&sblock, cylno)[rpos] == -1)
1951			fs_rotbl(&sblock)[blk] = 0;
1952		else
1953			fs_rotbl(&sblock)[blk] =
1954			    fs_postbl(&sblock, cylno)[rpos] - blk;
1955		fs_postbl(&sblock, cylno)[rpos] = blk;
1956	}
1957next:
1958grow30:
1959	/*
1960	 * Compute/validate number of cylinder groups.
1961	 * Note that if an excessively large filesystem is specified
1962	 * (e.g., more than 16384 cylinders for an 8K filesystem block), it
1963	 * does not get detected until checksummarysize()
1964	 */
1965	sblock.fs_ncg = sblock.fs_ncyl / sblock.fs_cpg;
1966	if (sblock.fs_ncyl % sblock.fs_cpg)
1967		sblock.fs_ncg++;
1968	sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock);
1969	i = MIN(~sblock.fs_cgmask, sblock.fs_ncg - 1);
1970	ibpcl = cgdmin(&sblock, i) - cgbase(&sblock, i);
1971	if (ibpcl >= sblock.fs_fpg) {
1972		(void) fprintf(stderr, gettext(
1973		    "inode blocks/cyl group (%d) >= data blocks (%d)\n"),
1974		    cgdmin(&sblock, i) - cgbase(&sblock, i) / sblock.fs_frag,
1975		    sblock.fs_fpg / sblock.fs_frag);
1976		if ((ibpcl < 0) || (sblock.fs_fpg < 0)) {
1977			(void) fprintf(stderr, gettext(
1978	    "number of cylinders per cylinder group (%d) must be decreased.\n"),
1979			    sblock.fs_cpg);
1980		} else {
1981			(void) fprintf(stderr, gettext(
1982	    "number of cylinders per cylinder group (%d) must be increased.\n"),
1983			    sblock.fs_cpg);
1984		}
1985		(void) fprintf(stderr, gettext(
1986"Note that cgsize may have been adjusted to allow struct cg to fit.\n"));
1987		lockexit(32);
1988	}
1989	j = sblock.fs_ncg - 1;
1990	if ((i = fssize_frag - j * sblock.fs_fpg) < sblock.fs_fpg &&
1991	    cgdmin(&sblock, j) - cgbase(&sblock, j) > i) {
1992		(void) fprintf(stderr, gettext(
1993		    "Warning: inode blocks/cyl group (%d) >= data "
1994		    "blocks (%ld) in last\n    cylinder group. This "
1995		    "implies %ld sector(s) cannot be allocated.\n"),
1996		    (cgdmin(&sblock, j) - cgbase(&sblock, j)) / sblock.fs_frag,
1997		    i / sblock.fs_frag, i * NSPF(&sblock));
1998		/*
1999		 * If there is only one cylinder group and that is not even
2000		 * big enough to hold the inodes, exit.
2001		 */
2002		if (sblock.fs_ncg == 1)
2003			cg_too_small = 1;
2004		sblock.fs_ncg--;
2005		sblock.fs_ncyl = sblock.fs_ncg * sblock.fs_cpg;
2006		sblock.fs_size = fssize_frag =
2007		    (int64_t)sblock.fs_ncyl * (int64_t)sblock.fs_spc /
2008		    (int64_t)NSPF(&sblock);
2009		warn = 0;
2010	}
2011	if (warn && !spc_flag) {
2012		(void) fprintf(stderr, gettext(
2013		    "Warning: %d sector(s) in last cylinder unallocated\n"),
2014		    sblock.fs_spc - (uint32_t)(fssize_frag * NSPF(&sblock) -
2015		    (uint64_t)(sblock.fs_ncyl - 1) * sblock.fs_spc));
2016	}
2017	/*
2018	 * fill in remaining fields of the super block
2019	 */
2020
2021	/*
2022	 * The csum records are stored in cylinder group 0, starting at
2023	 * cgdmin, the first data block.
2024	 */
2025	sblock.fs_csaddr = cgdmin(&sblock, 0);
2026	sblock.fs_cssize =
2027	    fragroundup(&sblock, sblock.fs_ncg * sizeof (struct csum));
2028	i = sblock.fs_bsize / sizeof (struct csum);
2029	sblock.fs_csmask = ~(i - 1);
2030	for (sblock.fs_csshift = 0; i > 1; i >>= 1)
2031		sblock.fs_csshift++;
2032	fscs = (struct csum *)calloc(1, sblock.fs_cssize);
2033
2034	checksummarysize();
2035	if (mtb == 'y') {
2036		sblock.fs_magic = MTB_UFS_MAGIC;
2037		sblock.fs_version = MTB_UFS_VERSION_1;
2038	} else {
2039		sblock.fs_magic = FS_MAGIC;
2040		if (use_efi_dflts)
2041			sblock.fs_version = UFS_EFISTYLE4NONEFI_VERSION_2;
2042		else
2043			sblock.fs_version = UFS_VERSION_MIN;
2044	}
2045
2046	if (grow) {
2047		bcopy((caddr_t)grow_fscs, (caddr_t)fscs, (int)grow_fs_cssize);
2048		extendsummaryinfo();
2049		goto grow40;
2050	}
2051	sblock.fs_rotdelay = rotdelay;
2052	sblock.fs_maxcontig = maxcontig;
2053	sblock.fs_maxbpg = MAXBLKPG(sblock.fs_bsize);
2054
2055	sblock.fs_rps = rps;
2056	sblock.fs_cgrotor = 0;
2057	sblock.fs_cstotal.cs_ndir = 0;
2058	sblock.fs_cstotal.cs_nbfree = 0;
2059	sblock.fs_cstotal.cs_nifree = 0;
2060	sblock.fs_cstotal.cs_nffree = 0;
2061	sblock.fs_fmod = 0;
2062	sblock.fs_ronly = 0;
2063	sblock.fs_time = mkfstime;
2064	sblock.fs_state = FSOKAY - sblock.fs_time;
2065	sblock.fs_clean = FSCLEAN;
2066grow40:
2067
2068	/*
2069	 * If all that's needed is a dump of the superblock we
2070	 * would use by default, we've got it now.  So, splat it
2071	 * out and leave.
2072	 */
2073	if (rflag) {
2074		dump_sblock();
2075		lockexit(0);
2076	}
2077	/*
2078	 * Dump out summary information about file system.
2079	 */
2080	(void) fprintf(stderr, gettext(
2081	    "%s:\t%lld sectors in %d cylinders of %d tracks, %d sectors\n"),
2082	    fsys, (uint64_t)sblock.fs_size * NSPF(&sblock), sblock.fs_ncyl,
2083	    sblock.fs_ntrak, sblock.fs_nsect);
2084	(void) fprintf(stderr, gettext(
2085	    "\t%.1fMB in %d cyl groups (%d c/g, %.2fMB/g, %d i/g)\n"),
2086	    (float)sblock.fs_size * sblock.fs_fsize / MB, sblock.fs_ncg,
2087	    sblock.fs_cpg, (float)sblock.fs_fpg * sblock.fs_fsize / MB,
2088	    sblock.fs_ipg);
2089
2090	tmpbuf = calloc(sblock.fs_ncg / 50 + 500, 1);
2091	if (tmpbuf == NULL) {
2092		perror("calloc");
2093		lockexit(32);
2094	}
2095	if (cg_too_small) {
2096		(void) fprintf(stderr, gettext("File system creation failed. "
2097		    "There is only one cylinder group and\nthat is "
2098		    "not even big enough to hold the inodes.\n"));
2099		lockexit(32);
2100	}
2101	/*
2102	 * Now build the cylinders group blocks and
2103	 * then print out indices of cylinder groups.
2104	 */
2105	tprintf(gettext(
2106	    "super-block backups (for fsck -F ufs -o b=#) at:\n"));
2107	for (width = cylno = 0; cylno < sblock.fs_ncg && cylno < 10; cylno++) {
2108		if ((grow == 0) || (cylno >= grow_fs_ncg))
2109			initcg(cylno);
2110		num = fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno));
2111		/*
2112		 * If Nflag and if the disk is larger than the CHSLIMIT,
2113		 * then sanity test the superblocks before reporting. If there
2114		 * are too many superblocks which look insane, we have
2115		 * to retry with alternate logic. If both methods have
2116		 * failed, then our efforts to arrive at alternate
2117		 * superblocks failed, so complain and exit.
2118		 */
2119		if (Nflag && retry) {
2120			skip_this_sb = 0;
2121			rdfs((diskaddr_t)num, sbsize, (char *)&altsblock);
2122			ret = checksblock(altsblock, 1);
2123			if (ret) {
2124				skip_this_sb = 1;
2125				invalid_sb_cnt++;
2126				dprintf(("DeBuG checksblock() failed - error :"
2127				    " %d for sb : %llu invalid_sb_cnt : %d\n",
2128				    ret, num, invalid_sb_cnt));
2129			} else {
2130				/*
2131				 * Though the superblock looks sane, verify if
2132				 * the fs_version in the superblock and the
2133				 * logic that we are using to arrive at the
2134				 * superblocks match.
2135				 */
2136				if (use_efi_dflts && altsblock.fs_version
2137				    != UFS_EFISTYLE4NONEFI_VERSION_2) {
2138					skip_this_sb = 1;
2139					invalid_sb_cnt++;
2140				}
2141			}
2142			if (invalid_sb_cnt >= INVALIDSBLIMIT) {
2143				if (retry > 1) {
2144					(void) fprintf(stderr, gettext(
2145					    "Error determining alternate "
2146					    "superblock locations\n"));
2147					free(tmpbuf);
2148					lockexit(32);
2149				}
2150				retry++;
2151				use_efi_dflts = !use_efi_dflts;
2152				free(tmpbuf);
2153				goto retry_alternate_logic;
2154			}
2155			if (skip_this_sb)
2156				continue;
2157		}
2158		(void) sprintf(pbuf, " %llu,", num);
2159		plen = strlen(pbuf);
2160		if ((width + plen) > (WIDTH - 1)) {
2161			width = plen;
2162			tprintf("\n");
2163		} else {
2164			width += plen;
2165		}
2166		if (Nflag && retry)
2167			(void) strncat(tmpbuf, pbuf, strlen(pbuf));
2168		else
2169			(void) fprintf(stderr, "%s", pbuf);
2170	}
2171	tprintf("\n");
2172
2173	remaining_cg = sblock.fs_ncg - cylno;
2174
2175	/*
2176	 * If there are more than 300 cylinder groups still to be
2177	 * initialized, print a "." for every 50 cylinder groups.
2178	 */
2179	if (remaining_cg > 300) {
2180		tprintf(gettext("Initializing cylinder groups:\n"));
2181		do_dot = 1;
2182	}
2183
2184	/*
2185	 * Now initialize all cylinder groups between the first ten
2186	 * and the last ten.
2187	 *
2188	 * If the number of cylinder groups was less than 10, all of the
2189	 * cylinder group offsets would have printed in the last loop
2190	 * and cylno will already be equal to sblock.fs_ncg and so this
2191	 * loop will not be entered.  If there are less than 20 cylinder
2192	 * groups, cylno is already less than fs_ncg - 10, so this loop
2193	 * won't be entered in that case either.
2194	 */
2195
2196	i = 0;
2197	for (; cylno < sblock.fs_ncg - 10; cylno++) {
2198		if ((grow == 0) || (cylno >= grow_fs_ncg))
2199			initcg(cylno);
2200		if (do_dot && cylno % 50 == 0) {
2201			tprintf(".");
2202			i++;
2203			if (i == WIDTH - 1) {
2204				tprintf("\n");
2205				i = 0;
2206			}
2207		}
2208	}
2209
2210	/*
2211	 * Now print the cylinder group offsets for the last 10
2212	 * cylinder groups, if any are left.
2213	 */
2214
2215	if (do_dot) {
2216		tprintf(gettext(
2217	    "\nsuper-block backups for last 10 cylinder groups at:\n"));
2218	}
2219	for (width = 0; cylno < sblock.fs_ncg; cylno++) {
2220		if ((grow == 0) || (cylno >= grow_fs_ncg))
2221			initcg(cylno);
2222		num = fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno));
2223		if (Nflag && retry) {
2224			skip_this_sb = 0;
2225			rdfs((diskaddr_t)num, sbsize, (char *)&altsblock);
2226			ret = checksblock(altsblock, 1);
2227			if (ret) {
2228				skip_this_sb = 1;
2229				invalid_sb_cnt++;
2230				dprintf(("DeBuG checksblock() failed - error :"
2231				    " %d for sb : %llu invalid_sb_cnt : %d\n",
2232				    ret, num, invalid_sb_cnt));
2233			} else {
2234				/*
2235				 * Though the superblock looks sane, verify if
2236				 * the fs_version in the superblock and the
2237				 * logic that we are using to arrive at the
2238				 * superblocks match.
2239				 */
2240				if (use_efi_dflts && altsblock.fs_version
2241				    != UFS_EFISTYLE4NONEFI_VERSION_2) {
2242					skip_this_sb = 1;
2243					invalid_sb_cnt++;
2244				}
2245			}
2246			if (invalid_sb_cnt >= INVALIDSBLIMIT) {
2247				if (retry > 1) {
2248					(void) fprintf(stderr, gettext(
2249					    "Error determining alternate "
2250					    "superblock locations\n"));
2251					free(tmpbuf);
2252					lockexit(32);
2253				}
2254				retry++;
2255				use_efi_dflts = !use_efi_dflts;
2256				free(tmpbuf);
2257				goto retry_alternate_logic;
2258			}
2259			if (skip_this_sb)
2260				continue;
2261		}
2262		/* Don't print ',' for the last superblock */
2263		if (cylno == sblock.fs_ncg-1)
2264			(void) sprintf(pbuf, " %llu", num);
2265		else
2266			(void) sprintf(pbuf, " %llu,", num);
2267		plen = strlen(pbuf);
2268		if ((width + plen) > (WIDTH - 1)) {
2269			width = plen;
2270			tprintf("\n");
2271		} else {
2272			width += plen;
2273		}
2274		if (Nflag && retry)
2275			(void) strncat(tmpbuf, pbuf, strlen(pbuf));
2276		else
2277			(void) fprintf(stderr, "%s", pbuf);
2278	}
2279	tprintf("\n");
2280	if (Nflag) {
2281		if (retry)
2282			(void) fprintf(stderr, "%s", tmpbuf);
2283		free(tmpbuf);
2284		lockexit(0);
2285	}
2286
2287	free(tmpbuf);
2288	if (grow)
2289		goto grow50;
2290
2291	/*
2292	 * Now construct the initial file system,
2293	 * then write out the super-block.
2294	 */
2295	fsinit();
2296grow50:
2297	/*
2298	 * write the superblock and csum information
2299	 */
2300	wtsb();
2301
2302	/*
2303	 * extend the last cylinder group in the original file system
2304	 */
2305	if (grow) {
2306		extendcg(grow_fs_ncg-1);
2307		wtsb();
2308	}
2309
2310	/*
2311	 * Write out the duplicate super blocks to the first 10
2312	 * cylinder groups (or fewer, if there are fewer than 10
2313	 * cylinder groups).
2314	 */
2315	for (cylno = 0; cylno < sblock.fs_ncg && cylno < 10; cylno++)
2316		awtfs(fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno)),
2317		    (int)sbsize, (char *)&sblock, SAVE);
2318
2319	/*
2320	 * Now write out duplicate super blocks to the remaining
2321	 * cylinder groups.  In the case of multi-terabyte file
2322	 * systems, just write out the super block to the last ten
2323	 * cylinder groups (or however many are left).
2324	 */
2325	if (mtb == 'y') {
2326		if (sblock.fs_ncg <= 10)
2327			cylno = sblock.fs_ncg;
2328		else if (sblock.fs_ncg <= 20)
2329			cylno = 10;
2330		else
2331			cylno = sblock.fs_ncg - 10;
2332	}
2333
2334	for (; cylno < sblock.fs_ncg; cylno++)
2335		awtfs(fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno)),
2336		    (int)sbsize, (char *)&sblock, SAVE);
2337
2338	/*
2339	 * Flush out all the AIO writes we've done.  It's not
2340	 * necessary to do this explicitly, but it's the only
2341	 * way to report any errors from those writes.
2342	 */
2343	flush_writes();
2344
2345	/*
2346	 * set clean flag
2347	 */
2348	if (grow)
2349		sblock.fs_clean = grow_fs_clean;
2350	else
2351		sblock.fs_clean = FSCLEAN;
2352	sblock.fs_time = mkfstime;
2353	sblock.fs_state = FSOKAY - sblock.fs_time;
2354	wtfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
2355	isbad = 0;
2356
2357	if (fsync(fso) == -1) {
2358		saverr = errno;
2359		(void) fprintf(stderr,
2360		    gettext("mkfs: fsync failed on write disk: %s\n"),
2361		    strerror(saverr));
2362		/* we're just cleaning up, so keep going */
2363	}
2364	if (close(fsi) == -1) {
2365		saverr = errno;
2366		(void) fprintf(stderr,
2367		    gettext("mkfs: close failed on read disk: %s\n"),
2368		    strerror(saverr));
2369		/* we're just cleaning up, so keep going */
2370	}
2371	if (close(fso) == -1) {
2372		saverr = errno;
2373		(void) fprintf(stderr,
2374		    gettext("mkfs: close failed on write disk: %s\n"),
2375		    strerror(saverr));
2376		/* we're just cleaning up, so keep going */
2377	}
2378	fsi = fso = -1;
2379
2380#ifndef STANDALONE
2381	lockexit(0);
2382#endif
2383
2384	return (0);
2385}
2386
2387static diskaddr_t
2388get_device_size(int fd)
2389{
2390	struct dk_minfo	disk_info;
2391
2392	if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1)
2393		return (0);
2394
2395	return (disk_info.dki_capacity);
2396}
2397
2398/*
2399 * Figure out how big the partition we're dealing with is.
2400 * The value returned is in disk blocks (sectors);
2401 */
2402static diskaddr_t
2403get_max_size(int fd)
2404{
2405	struct extvtoc vtoc;
2406	dk_gpt_t *efi_vtoc;
2407	diskaddr_t	slicesize;
2408
2409	int index = read_extvtoc(fd, &vtoc);
2410
2411	if (index >= 0) {
2412		label_type = LABEL_TYPE_VTOC;
2413	} else {
2414		if (index == VT_ENOTSUP || index == VT_ERROR) {
2415			/* it might be an EFI label */
2416			index = efi_alloc_and_read(fd, &efi_vtoc);
2417			label_type = LABEL_TYPE_EFI;
2418		}
2419	}
2420
2421	if (index < 0) {
2422		/*
2423		 * Since both attempts to read the label failed, we're
2424		 * going to use DKIOCGMEDIAINFO to get device size.
2425		 */
2426
2427		label_type = LABEL_TYPE_OTHER;
2428		slicesize = get_device_size(fd);
2429		if (slicesize == 0) {
2430			switch (index) {
2431			case VT_ERROR:
2432				break;
2433			case VT_EIO:
2434				errno = EIO;
2435				break;
2436			case VT_EINVAL:
2437				errno = EINVAL;
2438			}
2439			perror(gettext("Can not determine partition size"));
2440			lockexit(32);
2441		}
2442	}
2443
2444	if (label_type == LABEL_TYPE_EFI) {
2445		slicesize = efi_vtoc->efi_parts[index].p_size;
2446		efi_free(efi_vtoc);
2447	} else if (label_type == LABEL_TYPE_VTOC) {
2448		/*
2449		 * In the vtoc struct, p_size is a 32-bit signed quantity.
2450		 * In the dk_gpt struct (efi's version of the vtoc), p_size
2451		 * is an unsigned 64-bit quantity.  By casting the vtoc's
2452		 * psize to an unsigned 32-bit quantity, it will be copied
2453		 * to 'slicesize' (an unsigned 64-bit diskaddr_t) without
2454		 * sign extension.
2455		 */
2456
2457		slicesize = (uint32_t)vtoc.v_part[index].p_size;
2458	}
2459
2460	dprintf(("DeBuG get_max_size index = %d, p_size = %lld, dolimit = %d\n",
2461	    index, slicesize, (slicesize > FS_MAX)));
2462
2463	/*
2464	 * The next line limits a UFS file system to the maximum
2465	 * supported size.
2466	 */
2467
2468	if (slicesize > FS_MAX)
2469		return (FS_MAX);
2470	return (slicesize);
2471}
2472
2473static long
2474get_max_track_size(int fd)
2475{
2476	struct dk_cinfo ci;
2477	long track_size = -1;
2478
2479	if (ioctl(fd, DKIOCINFO, &ci) == 0) {
2480		track_size = ci.dki_maxtransfer * DEV_BSIZE;
2481	}
2482
2483	if ((track_size < 0)) {
2484		int	error = 0;
2485		int	maxphys;
2486		int	gotit = 0;
2487
2488		gotit = fsgetmaxphys(&maxphys, &error);
2489		if (gotit) {
2490			track_size = MIN(MB, maxphys);
2491		} else {
2492			(void) fprintf(stderr, gettext(
2493"Warning: Could not get system value for maxphys. The value for\n"
2494"maxcontig will default to 1MB.\n"));
2495			track_size = MB;
2496		}
2497	}
2498	return (track_size);
2499}
2500
2501/*
2502 * Initialize a cylinder group.
2503 */
2504static void
2505initcg(int cylno)
2506{
2507	diskaddr_t cbase, d;
2508	diskaddr_t dlower;	/* last data block before cg metadata */
2509	diskaddr_t dupper;	/* first data block after cg metadata */
2510	diskaddr_t dmax;
2511	int64_t i;
2512	struct csum *cs;
2513	struct dinode *inode_buffer;
2514	int size;
2515
2516	/*
2517	 * Variables used to store intermediate results as a part of
2518	 * the internal implementation of the cbtocylno() macros.
2519	 */
2520	diskaddr_t bno;		/* UFS block number (not sector number) */
2521	int	cbcylno;	/* current cylinder number */
2522	int	cbcylno_sect;	/* sector offset within cylinder */
2523	int	cbsect_incr;	/* amount to increment sector offset */
2524
2525	/*
2526	 * Variables used to store intermediate results as a part of
2527	 * the internal implementation of the cbtorpos() macros.
2528	 */
2529	short	*cgblks;	/* pointer to array of free blocks in cg */
2530	int	trackrpos;	/* tmp variable for rotation position */
2531	int	trackoff;	/* offset within a track */
2532	int	trackoff_incr;	/* amount to increment trackoff */
2533	int	rpos;		/* rotation position of current block */
2534	int	rpos_incr;	/* amount to increment rpos per block */
2535
2536	union cgun *icgun;	/* local pointer to a cg summary block */
2537#define	icg	(icgun->cg)
2538
2539	icgun = (union cgun *)getbuf(&cgsumbuf, sizeof (union cgun));
2540
2541	/*
2542	 * Determine block bounds for cylinder group.
2543	 * Allow space for super block summary information in first
2544	 * cylinder group.
2545	 */
2546	cbase = cgbase(&sblock, cylno);
2547	dmax = cbase + sblock.fs_fpg;
2548	if (dmax > sblock.fs_size)	/* last cg may be smaller than normal */
2549		dmax = sblock.fs_size;
2550	dlower = cgsblock(&sblock, cylno) - cbase;
2551	dupper = cgdmin(&sblock, cylno) - cbase;
2552	if (cylno == 0)
2553		dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
2554	cs = fscs + cylno;
2555	icg.cg_time = mkfstime;
2556	icg.cg_magic = CG_MAGIC;
2557	icg.cg_cgx = cylno;
2558	/* last one gets whatever's left */
2559	if (cylno == sblock.fs_ncg - 1)
2560		icg.cg_ncyl = sblock.fs_ncyl - (sblock.fs_cpg * cylno);
2561	else
2562		icg.cg_ncyl = sblock.fs_cpg;
2563	icg.cg_niblk = sblock.fs_ipg;
2564	icg.cg_ndblk = dmax - cbase;
2565	icg.cg_cs.cs_ndir = 0;
2566	icg.cg_cs.cs_nffree = 0;
2567	icg.cg_cs.cs_nbfree = 0;
2568	icg.cg_cs.cs_nifree = 0;
2569	icg.cg_rotor = 0;
2570	icg.cg_frotor = 0;
2571	icg.cg_irotor = 0;
2572	icg.cg_btotoff = &icg.cg_space[0] - (uchar_t *)(&icg.cg_link);
2573	icg.cg_boff = icg.cg_btotoff + sblock.fs_cpg * sizeof (long);
2574	icg.cg_iusedoff = icg.cg_boff +
2575	    sblock.fs_cpg * sblock.fs_nrpos * sizeof (short);
2576	icg.cg_freeoff = icg.cg_iusedoff + howmany(sblock.fs_ipg, NBBY);
2577	icg.cg_nextfreeoff = icg.cg_freeoff +
2578	    howmany(sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY);
2579	for (i = 0; i < sblock.fs_frag; i++) {
2580		icg.cg_frsum[i] = 0;
2581	}
2582	bzero((caddr_t)cg_inosused(&icg), icg.cg_freeoff - icg.cg_iusedoff);
2583	icg.cg_cs.cs_nifree += sblock.fs_ipg;
2584	if (cylno == 0)
2585		for (i = 0; i < UFSROOTINO; i++) {
2586			setbit(cg_inosused(&icg), i);
2587			icg.cg_cs.cs_nifree--;
2588		}
2589
2590	/*
2591	 * Initialize all the inodes in the cylinder group using
2592	 * random numbers.
2593	 */
2594	size = sblock.fs_ipg * sizeof (struct dinode);
2595	inode_buffer = (struct dinode *)getbuf(&inodebuf, size);
2596
2597	for (i = 0; i < sblock.fs_ipg; i++) {
2598		IRANDOMIZE(&(inode_buffer[i].di_ic));
2599	}
2600
2601	/*
2602	 * Write all inodes in a single write for performance.
2603	 */
2604	awtfs(fsbtodb(&sblock, (uint64_t)cgimin(&sblock, cylno)), (int)size,
2605	    (char *)inode_buffer, RELEASE);
2606
2607	bzero((caddr_t)cg_blktot(&icg), icg.cg_boff - icg.cg_btotoff);
2608	bzero((caddr_t)cg_blks(&sblock, &icg, 0),
2609	    icg.cg_iusedoff - icg.cg_boff);
2610	bzero((caddr_t)cg_blksfree(&icg), icg.cg_nextfreeoff - icg.cg_freeoff);
2611
2612	if (cylno > 0) {
2613		for (d = 0; d < dlower; d += sblock.fs_frag) {
2614			setblock(&sblock, cg_blksfree(&icg), d/sblock.fs_frag);
2615			icg.cg_cs.cs_nbfree++;
2616			cg_blktot(&icg)[cbtocylno(&sblock, d)]++;
2617			cg_blks(&sblock, &icg, cbtocylno(&sblock, d))
2618			    [cbtorpos(&sblock, d)]++;
2619		}
2620		sblock.fs_dsize += dlower;
2621	}
2622	sblock.fs_dsize += icg.cg_ndblk - dupper;
2623	if ((i = dupper % sblock.fs_frag) != 0) {
2624		icg.cg_frsum[sblock.fs_frag - i]++;
2625		for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) {
2626			setbit(cg_blksfree(&icg), dupper);
2627			icg.cg_cs.cs_nffree++;
2628		}
2629	}
2630
2631	/*
2632	 * WARNING: The following code is somewhat confusing, but
2633	 * results in a substantial performance improvement in mkfs.
2634	 *
2635	 * Instead of using cbtocylno() and cbtorpos() macros, we
2636	 * keep track of all the intermediate state of those macros
2637	 * in some variables.  This allows simple addition to be
2638	 * done to calculate the results as we step through the
2639	 * blocks in an orderly fashion instead of the slower
2640	 * multiplication and division the macros are forced to
2641	 * used so they can support random input.  (Multiplication,
2642	 * division, and remainder operations typically take about
2643	 * 10x as many processor cycles as other operations.)
2644	 *
2645	 * The basic idea is to take code:
2646	 *
2647	 *	for (x = starting_x; x < max; x++)
2648	 *		y = (x * c) / z
2649	 *
2650	 * and rewrite it to take advantage of the fact that
2651	 * the variable x is incrementing in an orderly way:
2652	 *
2653	 *	intermediate = starting_x * c
2654	 *	yval = intermediate / z
2655	 *	for (x = starting_x; x < max; x++) {
2656	 *		y = yval;
2657	 *		intermediate += c
2658	 *		if (intermediate > z) {
2659	 *			yval++;
2660	 *			intermediate -= z
2661	 *		}
2662	 *	}
2663	 *
2664	 * Performance has improved as much as 4X using this code.
2665	 */
2666
2667	/*
2668	 * Initialize the starting points for all the cbtocylno()
2669	 * macro variables and figure out the increments needed each
2670	 * time through the loop.
2671	 */
2672	cbcylno_sect = dupper * NSPF(&sblock);
2673	cbsect_incr = sblock.fs_frag * NSPF(&sblock);
2674	cbcylno = cbcylno_sect / sblock.fs_spc;
2675	cbcylno_sect %= sblock.fs_spc;
2676	cgblks = cg_blks(&sblock, &icg, cbcylno);
2677	bno = dupper / sblock.fs_frag;
2678
2679	/*
2680	 * Initialize the starting points for all the cbtorpos()
2681	 * macro variables and figure out the increments needed each
2682	 * time through the loop.
2683	 *
2684	 * It's harder to simplify the cbtorpos() macro if there were
2685	 * alternate sectors specified (or if they previously existed
2686	 * in the growfs case).  Since this is rare, we just revert to
2687	 * using the macros in this case and skip the variable setup.
2688	 */
2689	if (!spc_flag) {
2690		trackrpos = (cbcylno_sect % sblock.fs_nsect) * sblock.fs_nrpos;
2691		rpos = trackrpos / sblock.fs_nsect;
2692		trackoff = trackrpos % sblock.fs_nsect;
2693		trackoff_incr = cbsect_incr * sblock.fs_nrpos;
2694		rpos_incr = (trackoff_incr / sblock.fs_nsect) % sblock.fs_nrpos;
2695		trackoff_incr = trackoff_incr % sblock.fs_nsect;
2696	}
2697
2698	/*
2699	 * Loop through all the blocks, marking them free and
2700	 * updating totals kept in the superblock and cg summary.
2701	 */
2702	for (d = dupper; d + sblock.fs_frag <= dmax - cbase; ) {
2703		setblock(&sblock, cg_blksfree(&icg),  bno);
2704		icg.cg_cs.cs_nbfree++;
2705
2706		cg_blktot(&icg)[cbcylno]++;
2707
2708		if (!spc_flag)
2709			cgblks[rpos]++;
2710		else
2711			cg_blks(&sblock, &icg, cbtocylno(&sblock, d))
2712			    [cbtorpos(&sblock, d)]++;
2713
2714		d += sblock.fs_frag;
2715		bno++;
2716
2717		/*
2718		 * Increment the sector offset within the cylinder
2719		 * for the cbtocylno() macro reimplementation.  If
2720		 * we're beyond the end of the cylinder, update the
2721		 * cylinder number, calculate the offset in the
2722		 * new cylinder, and update the cgblks pointer
2723		 * to the next rotational position.
2724		 */
2725		cbcylno_sect += cbsect_incr;
2726		if (cbcylno_sect >= sblock.fs_spc) {
2727			cbcylno++;
2728			cbcylno_sect -= sblock.fs_spc;
2729			cgblks += sblock.fs_nrpos;
2730		}
2731
2732		/*
2733		 * If there aren't alternate sectors, increment the
2734		 * rotational position variables for the cbtorpos()
2735		 * reimplementation.  Note that we potentially
2736		 * increment rpos twice.  Once by rpos_incr, and one
2737		 * more time when we wrap to a new track because
2738		 * trackoff >= fs_nsect.
2739		 */
2740		if (!spc_flag) {
2741			trackoff += trackoff_incr;
2742			rpos += rpos_incr;
2743			if (trackoff >= sblock.fs_nsect) {
2744				trackoff -= sblock.fs_nsect;
2745				rpos++;
2746			}
2747			if (rpos >= sblock.fs_nrpos)
2748				rpos -= sblock.fs_nrpos;
2749		}
2750	}
2751
2752	if (d < dmax - cbase) {
2753		icg.cg_frsum[dmax - cbase - d]++;
2754		for (; d < dmax - cbase; d++) {
2755			setbit(cg_blksfree(&icg), d);
2756			icg.cg_cs.cs_nffree++;
2757		}
2758	}
2759	sblock.fs_cstotal.cs_ndir += icg.cg_cs.cs_ndir;
2760	sblock.fs_cstotal.cs_nffree += icg.cg_cs.cs_nffree;
2761	sblock.fs_cstotal.cs_nbfree += icg.cg_cs.cs_nbfree;
2762	sblock.fs_cstotal.cs_nifree += icg.cg_cs.cs_nifree;
2763	*cs = icg.cg_cs;
2764	awtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, cylno)),
2765	    sblock.fs_bsize, (char *)&icg, RELEASE);
2766}
2767
2768/*
2769 * initialize the file system
2770 */
2771struct inode node;
2772
2773#define	LOSTDIR
2774#ifdef LOSTDIR
2775#define	PREDEFDIR 3
2776#else
2777#define	PREDEFDIR 2
2778#endif
2779
2780struct direct root_dir[] = {
2781	{ UFSROOTINO, sizeof (struct direct), 1, "." },
2782	{ UFSROOTINO, sizeof (struct direct), 2, ".." },
2783#ifdef LOSTDIR
2784	{ LOSTFOUNDINO, sizeof (struct direct), 10, "lost+found" },
2785#endif
2786};
2787#ifdef LOSTDIR
2788struct direct lost_found_dir[] = {
2789	{ LOSTFOUNDINO, sizeof (struct direct), 1, "." },
2790	{ UFSROOTINO, sizeof (struct direct), 2, ".." },
2791	{ 0, DIRBLKSIZ, 0, 0 },
2792};
2793#endif
2794char buf[MAXBSIZE];
2795
2796static void
2797fsinit()
2798{
2799	int i;
2800
2801
2802	/*
2803	 * initialize the node
2804	 */
2805	node.i_atime = mkfstime;
2806	node.i_mtime = mkfstime;
2807	node.i_ctime = mkfstime;
2808#ifdef LOSTDIR
2809	/*
2810	 * create the lost+found directory
2811	 */
2812	(void) makedir(lost_found_dir, 2);
2813	for (i = DIRBLKSIZ; i < sblock.fs_bsize; i += DIRBLKSIZ) {
2814		bcopy(&lost_found_dir[2], &buf[i], DIRSIZ(&lost_found_dir[2]));
2815	}
2816	node.i_number = LOSTFOUNDINO;
2817	node.i_smode = IFDIR | 0700;
2818	node.i_nlink = 2;
2819	node.i_size = sblock.fs_bsize;
2820	node.i_db[0] = alloc((int)node.i_size, node.i_mode);
2821	node.i_blocks = btodb(fragroundup(&sblock, (int)node.i_size));
2822	IRANDOMIZE(&node.i_ic);
2823	wtfs(fsbtodb(&sblock, (uint64_t)node.i_db[0]), (int)node.i_size, buf);
2824	iput(&node);
2825#endif
2826	/*
2827	 * create the root directory
2828	 */
2829	node.i_number = UFSROOTINO;
2830	node.i_mode = IFDIR | UMASK;
2831	node.i_nlink = PREDEFDIR;
2832	node.i_size = makedir(root_dir, PREDEFDIR);
2833	node.i_db[0] = alloc(sblock.fs_fsize, node.i_mode);
2834	/* i_size < 2GB because we are initializing the file system */
2835	node.i_blocks = btodb(fragroundup(&sblock, (int)node.i_size));
2836	IRANDOMIZE(&node.i_ic);
2837	wtfs(fsbtodb(&sblock, (uint64_t)node.i_db[0]), sblock.fs_fsize, buf);
2838	iput(&node);
2839}
2840
2841/*
2842 * construct a set of directory entries in "buf".
2843 * return size of directory.
2844 */
2845static int
2846makedir(struct direct *protodir, int entries)
2847{
2848	char *cp;
2849	int i;
2850	ushort_t spcleft;
2851
2852	spcleft = DIRBLKSIZ;
2853	for (cp = buf, i = 0; i < entries - 1; i++) {
2854		protodir[i].d_reclen = DIRSIZ(&protodir[i]);
2855		bcopy(&protodir[i], cp, protodir[i].d_reclen);
2856		cp += protodir[i].d_reclen;
2857		spcleft -= protodir[i].d_reclen;
2858	}
2859	protodir[i].d_reclen = spcleft;
2860	bcopy(&protodir[i], cp, DIRSIZ(&protodir[i]));
2861	return (DIRBLKSIZ);
2862}
2863
2864/*
2865 * allocate a block or frag
2866 */
2867static daddr32_t
2868alloc(int size, int mode)
2869{
2870	int i, frag;
2871	daddr32_t d;
2872
2873	rdfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
2874	    (char *)&acg);
2875	if (acg.cg_magic != CG_MAGIC) {
2876		(void) fprintf(stderr, gettext("cg 0: bad magic number\n"));
2877		lockexit(32);
2878	}
2879	if (acg.cg_cs.cs_nbfree == 0) {
2880		(void) fprintf(stderr,
2881		    gettext("first cylinder group ran out of space\n"));
2882		lockexit(32);
2883	}
2884	for (d = 0; d < acg.cg_ndblk; d += sblock.fs_frag)
2885		if (isblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag))
2886			goto goth;
2887	(void) fprintf(stderr,
2888	    gettext("internal error: can't find block in cyl 0\n"));
2889	lockexit(32);
2890goth:
2891	clrblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag);
2892	acg.cg_cs.cs_nbfree--;
2893	sblock.fs_cstotal.cs_nbfree--;
2894	fscs[0].cs_nbfree--;
2895	if (mode & IFDIR) {
2896		acg.cg_cs.cs_ndir++;
2897		sblock.fs_cstotal.cs_ndir++;
2898		fscs[0].cs_ndir++;
2899	}
2900	cg_blktot(&acg)[cbtocylno(&sblock, d)]--;
2901	cg_blks(&sblock, &acg, cbtocylno(&sblock, d))[cbtorpos(&sblock, d)]--;
2902	if (size != sblock.fs_bsize) {
2903		frag = howmany(size, sblock.fs_fsize);
2904		fscs[0].cs_nffree += sblock.fs_frag - frag;
2905		sblock.fs_cstotal.cs_nffree += sblock.fs_frag - frag;
2906		acg.cg_cs.cs_nffree += sblock.fs_frag - frag;
2907		acg.cg_frsum[sblock.fs_frag - frag]++;
2908		for (i = frag; i < sblock.fs_frag; i++)
2909			setbit(cg_blksfree(&acg), d + i);
2910	}
2911	wtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
2912	    (char *)&acg);
2913	return (d);
2914}
2915
2916/*
2917 * Allocate an inode on the disk
2918 */
2919static void
2920iput(struct inode *ip)
2921{
2922	struct dinode buf[MAXINOPB];
2923	diskaddr_t d;
2924
2925	rdfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
2926	    (char *)&acg);
2927	if (acg.cg_magic != CG_MAGIC) {
2928		(void) fprintf(stderr, gettext("cg 0: bad magic number\n"));
2929		lockexit(32);
2930	}
2931	acg.cg_cs.cs_nifree--;
2932	setbit(cg_inosused(&acg), ip->i_number);
2933	wtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
2934	    (char *)&acg);
2935	sblock.fs_cstotal.cs_nifree--;
2936	fscs[0].cs_nifree--;
2937	if ((int)ip->i_number >= sblock.fs_ipg * sblock.fs_ncg) {
2938		(void) fprintf(stderr,
2939		    gettext("fsinit: inode value out of range (%d).\n"),
2940		    ip->i_number);
2941		lockexit(32);
2942	}
2943	d = fsbtodb(&sblock, (uint64_t)itod(&sblock, (int)ip->i_number));
2944	rdfs(d, sblock.fs_bsize, (char *)buf);
2945	buf[itoo(&sblock, (int)ip->i_number)].di_ic = ip->i_ic;
2946	wtfs(d, sblock.fs_bsize, (char *)buf);
2947}
2948
2949/*
2950 * getbuf()	-- Get a buffer for use in an AIO operation.  Buffer
2951 *		is zero'd the first time returned, left with whatever
2952 *		was in memory after that.  This function actually gets
2953 *		enough memory the first time it's called to support
2954 *		MAXBUF buffers like a slab allocator.  When all the
2955 *		buffers are in use, it waits for an aio to complete
2956 *		and make a buffer available.
2957 *
2958 *		Never returns an error.  Either succeeds or exits.
2959 */
2960static char *
2961getbuf(bufhdr *bufhead, int size)
2962{
2963	bufhdr *pbuf;
2964	bufhdr *prev;
2965	int i;
2966	int buf_size, max_bufs;
2967
2968	/*
2969	 * Initialize all the buffers
2970	 */
2971	if (bufhead->head == NULL) {
2972		/*
2973		 * round up the size of our buffer header to a
2974		 * 16 byte boundary so the address we return to
2975		 * the caller is "suitably aligned".
2976		 */
2977		bufhdrsize = (sizeof (bufhdr) + 15) & ~15;
2978
2979		/*
2980		 * Add in our header to the buffer and round it all up to
2981		 * a 16 byte boundry so each member of the slab is aligned.
2982		 */
2983		buf_size = (size + bufhdrsize + 15) & ~15;
2984
2985		/*
2986		 * Limit number of buffers to lesser of MAXBUFMEM's worth
2987		 * or MAXBUF, whichever is less.
2988		 */
2989		max_bufs = MAXBUFMEM / buf_size;
2990		if (max_bufs > MAXBUF)
2991			max_bufs = MAXBUF;
2992
2993		pbuf = (bufhdr *)calloc(max_bufs, buf_size);
2994		if (pbuf == NULL) {
2995			perror("calloc");
2996			lockexit(32);
2997		}
2998
2999		bufhead->head = bufhead;
3000		prev = bufhead;
3001		for (i = 0; i < max_bufs; i++) {
3002			pbuf->head = bufhead;
3003			prev->next = pbuf;
3004			prev = pbuf;
3005			pbuf = (bufhdr *)((char *)pbuf + buf_size);
3006		}
3007	}
3008
3009	/*
3010	 * Get an available buffer, waiting for I/O if necessary
3011	 */
3012	wait_for_write(NOBLOCK);
3013	while (bufhead->next == NULL)
3014		wait_for_write(BLOCK);
3015
3016	/*
3017	 * Take the buffer off the list
3018	 */
3019	pbuf = bufhead->next;
3020	bufhead->next = pbuf->next;
3021	pbuf->next = NULL;
3022
3023	/*
3024	 * return the empty buffer space just past the header
3025	 */
3026	return ((char *)pbuf + bufhdrsize);
3027}
3028
3029/*
3030 * freebuf()	-- Free a buffer gotten previously through getbuf.
3031 *		Puts the buffer back on the appropriate list for
3032 *		later use.  Never calls free().
3033 *
3034 * Assumes that SIGINT is blocked.
3035 */
3036static void
3037freebuf(char *buf)
3038{
3039	bufhdr *pbuf;
3040	bufhdr *bufhead;
3041
3042	/*
3043	 * get the header for this buffer
3044	 */
3045	pbuf = (bufhdr *)(buf - bufhdrsize);
3046
3047	/*
3048	 * Put it back on the list of available buffers
3049	 */
3050	bufhead = pbuf->head;
3051	pbuf->next = bufhead->next;
3052	bufhead->next = pbuf;
3053}
3054
3055/*
3056 * freetrans()	-- Free a transaction gotten previously through getaiop.
3057 *		Puts the transaction struct back on the appropriate list for
3058 *		later use.  Never calls free().
3059 *
3060 * Assumes that SIGINT is blocked.
3061 */
3062static void
3063freetrans(aio_trans *transp)
3064{
3065	/*
3066	 * free the buffer associated with this AIO if needed
3067	 */
3068	if (transp->release == RELEASE)
3069		freebuf(transp->buffer);
3070
3071	/*
3072	 * Put transaction on the free list
3073	 */
3074	transp->next = results.trans;
3075	results.trans = transp;
3076}
3077
3078/*
3079 * wait_for_write()	-- Wait for an aio write to complete.  Return
3080 *			the transaction structure for that write.
3081 *
3082 * Blocks SIGINT if necessary.
3083 */
3084aio_trans *
3085wait_for_write(int block)
3086{
3087	aio_trans	*transp;
3088	aio_result_t	*resultp;
3089	static struct timeval  zero_wait = { 0, 0 };
3090	sigset_t	old_mask;
3091
3092	/*
3093	 * If we know there aren't any outstanding transactions, just return
3094	 */
3095	if (results.outstanding == 0)
3096		return ((aio_trans *) 0);
3097
3098	block_sigint(&old_mask);
3099
3100	resultp = aiowait(block ? NULL : &zero_wait);
3101	if (resultp == NULL ||
3102	    (resultp == (aio_result_t *)-1 && errno == EINVAL)) {
3103		unblock_sigint(&old_mask);
3104		return ((aio_trans *) 0);
3105	}
3106
3107	results.outstanding--;
3108	transp = (aio_trans *)resultp;
3109
3110	if (resultp->aio_return != transp->size) {
3111		if (resultp->aio_return == -1) {
3112			/*
3113			 * The aiowrite() may have failed because the
3114			 * kernel didn't have enough memory to do the job.
3115			 * Flush all pending writes and try a normal
3116			 * write().  wtfs_breakup() will call exit if it
3117			 * fails, so we don't worry about errors here.
3118			 */
3119			flush_writes();
3120			wtfs_breakup(transp->bno, transp->size, transp->buffer);
3121		} else {
3122			(void) fprintf(stderr, gettext(
3123			    "short write (%d of %d bytes) on sector %lld\n"),
3124			    resultp->aio_return, transp->size,
3125			    transp->bno);
3126			/*
3127			 * Don't unblock SIGINT, to avoid potential
3128			 * looping due to queued interrupts and
3129			 * error handling.
3130			 */
3131			lockexit(32);
3132		}
3133	}
3134
3135	resultp->aio_return = 0;
3136	freetrans(transp);
3137	unblock_sigint(&old_mask);
3138	return (transp);
3139}
3140
3141/*
3142 * flush_writes()	-- flush all the outstanding aio writes.
3143 */
3144static void
3145flush_writes(void)
3146{
3147	while (wait_for_write(BLOCK))
3148		;
3149}
3150
3151/*
3152 * get_aiop()	-- find and return an aio_trans structure on which a new
3153 *		aio can be done.  Blocks on aiowait() if needed.  Reaps
3154 *		all outstanding completed aio's.
3155 *
3156 * Assumes that SIGINT is blocked.
3157 */
3158aio_trans *
3159get_aiop()
3160{
3161	int i;
3162	aio_trans *transp;
3163	aio_trans *prev;
3164
3165	/*
3166	 * initialize aio stuff
3167	 */
3168	if (!aio_inited) {
3169		aio_inited = 1;
3170
3171		results.maxpend = 0;
3172		results.outstanding = 0;
3173		results.max = MAXAIO;
3174
3175		results.trans = (aio_trans *)calloc(results.max,
3176		    sizeof (aio_trans));
3177		if (results.trans == NULL) {
3178			perror("calloc");
3179			lockexit(32);
3180		}
3181
3182		/*
3183		 * Initialize the linked list of aio transaction
3184		 * structures.  Note that the final "next" pointer
3185		 * will be NULL since we got the buffer from calloc().
3186		 */
3187		prev = results.trans;
3188		for (i = 1; i < results.max; i++) {
3189			prev->next = &(results.trans[i]);
3190			prev = prev->next;
3191		}
3192	}
3193
3194	wait_for_write(NOBLOCK);
3195	while (results.trans == NULL)
3196		wait_for_write(BLOCK);
3197	transp = results.trans;
3198	results.trans = results.trans->next;
3199
3200	transp->next = 0;
3201	transp->resultbuf.aio_return = AIO_INPROGRESS;
3202	return (transp);
3203}
3204
3205/*
3206 * read a block from the file system
3207 */
3208static void
3209rdfs(diskaddr_t bno, int size, char *bf)
3210{
3211	int n, saverr;
3212
3213	/*
3214	 * In case we need any data that's pending in an aiowrite(),
3215	 * we wait for them all to complete before doing a read.
3216	 */
3217	flush_writes();
3218
3219	/*
3220	 * Note: the llseek() can succeed, even if the offset is out of range.
3221	 * It's not until the file i/o operation (the read()) that one knows
3222	 * for sure if the raw device can handle the offset.
3223	 */
3224	if (llseek(fsi, (offset_t)bno * sectorsize, 0) < 0) {
3225		saverr = errno;
3226		(void) fprintf(stderr,
3227		    gettext("seek error on sector %lld: %s\n"),
3228		    bno, strerror(saverr));
3229		lockexit(32);
3230	}
3231	n = read(fsi, bf, size);
3232	if (n != size) {
3233		saverr = errno;
3234		if (n == -1)
3235			(void) fprintf(stderr,
3236			    gettext("read error on sector %lld: %s\n"),
3237			    bno, strerror(saverr));
3238		else
3239			(void) fprintf(stderr, gettext(
3240			    "short read (%d of %d bytes) on sector %lld\n"),
3241			    n, size, bno);
3242		lockexit(32);
3243	}
3244}
3245
3246/*
3247 * write a block to the file system
3248 */
3249static void
3250wtfs(diskaddr_t bno, int size, char *bf)
3251{
3252	int n, saverr;
3253
3254	if (fso == -1)
3255		return;
3256
3257	/*
3258	 * Note: the llseek() can succeed, even if the offset is out of range.
3259	 * It's not until the file i/o operation (the write()) that one knows
3260	 * for sure if the raw device can handle the offset.
3261	 */
3262	if (llseek(fso, (offset_t)bno * sectorsize, 0) < 0) {
3263		saverr = errno;
3264		(void) fprintf(stderr,
3265		    gettext("seek error on sector %lld: %s\n"),
3266		    bno, strerror(saverr));
3267		lockexit(32);
3268	}
3269	if (Nflag)
3270		return;
3271	n = write(fso, bf, size);
3272	if (n != size) {
3273		saverr = errno;
3274		if (n == -1)
3275			(void) fprintf(stderr,
3276			    gettext("write error on sector %lld: %s\n"),
3277			    bno, strerror(saverr));
3278		else
3279			(void) fprintf(stderr, gettext(
3280			    "short write (%d of %d bytes) on sector %lld\n"),
3281			    n, size, bno);
3282		lockexit(32);
3283	}
3284}
3285
3286/*
3287 * write a block to the file system -- buffered with aio
3288 */
3289static void
3290awtfs(diskaddr_t bno, int size, char *bf, int release)
3291{
3292	int n;
3293	aio_trans	*transp;
3294	sigset_t	old_mask;
3295
3296	if (fso == -1)
3297		return;
3298
3299	/*
3300	 * We need to keep things consistent if we get interrupted,
3301	 * so defer any expected interrupts for the time being.
3302	 */
3303	block_sigint(&old_mask);
3304
3305	if (Nflag) {
3306		if (release == RELEASE)
3307			freebuf(bf);
3308	} else {
3309		transp = get_aiop();
3310		transp->bno = bno;
3311		transp->buffer = bf;
3312		transp->size = size;
3313		transp->release = release;
3314
3315		n = aiowrite(fso, bf, size, (off_t)bno * sectorsize,
3316		    SEEK_SET, &transp->resultbuf);
3317
3318		if (n < 0) {
3319			/*
3320			 * The aiowrite() may have failed because the
3321			 * kernel didn't have enough memory to do the job.
3322			 * Flush all pending writes and try a normal
3323			 * write().  wtfs_breakup() will call exit if it
3324			 * fails, so we don't worry about errors here.
3325			 */
3326			flush_writes();
3327			wtfs_breakup(transp->bno, transp->size, transp->buffer);
3328			freetrans(transp);
3329		} else {
3330			/*
3331			 * Keep track of our pending writes.
3332			 */
3333			results.outstanding++;
3334			if (results.outstanding > results.maxpend)
3335				results.maxpend = results.outstanding;
3336		}
3337	}
3338
3339	unblock_sigint(&old_mask);
3340}
3341
3342
3343/*
3344 * write a block to the file system, but break it up into sbsize
3345 * chunks to avoid forcing a large amount of memory to be locked down.
3346 * Only used as a fallback when an aio write has failed.
3347 */
3348static void
3349wtfs_breakup(diskaddr_t bno, int size, char *bf)
3350{
3351	int n, saverr;
3352	int wsize;
3353	int block_incr = sbsize / sectorsize;
3354
3355	if (size < sbsize)
3356		wsize = size;
3357	else
3358		wsize = sbsize;
3359
3360	n = 0;
3361	while (size) {
3362		/*
3363		 * Note: the llseek() can succeed, even if the offset is
3364		 * out of range.  It's not until the file i/o operation
3365		 * (the write()) that one knows for sure if the raw device
3366		 * can handle the offset.
3367		 */
3368		if (llseek(fso, (offset_t)bno * sectorsize, 0) < 0) {
3369			saverr = errno;
3370			(void) fprintf(stderr,
3371			    gettext("seek error on sector %lld: %s\n"),
3372			    bno, strerror(saverr));
3373			lockexit(32);
3374		}
3375
3376		n = write(fso, bf, wsize);
3377		if (n == -1) {
3378			saverr = errno;
3379			(void) fprintf(stderr,
3380			    gettext("write error on sector %lld: %s\n"),
3381			    bno, strerror(saverr));
3382			lockexit(32);
3383		}
3384		if (n != wsize) {
3385			saverr = errno;
3386			(void) fprintf(stderr, gettext(
3387			    "short write (%d of %d bytes) on sector %lld\n"),
3388			    n, size, bno);
3389			lockexit(32);
3390		}
3391
3392		bno += block_incr;
3393		bf += wsize;
3394		size -= wsize;
3395		if (size < wsize)
3396			wsize = size;
3397	}
3398}
3399
3400
3401/*
3402 * check if a block is available
3403 */
3404static int
3405isblock(struct fs *fs, unsigned char *cp, int h)
3406{
3407	unsigned char mask;
3408
3409	switch (fs->fs_frag) {
3410	case 8:
3411		return (cp[h] == 0xff);
3412	case 4:
3413		mask = 0x0f << ((h & 0x1) << 2);
3414		return ((cp[h >> 1] & mask) == mask);
3415	case 2:
3416		mask = 0x03 << ((h & 0x3) << 1);
3417		return ((cp[h >> 2] & mask) == mask);
3418	case 1:
3419		mask = 0x01 << (h & 0x7);
3420		return ((cp[h >> 3] & mask) == mask);
3421	default:
3422		(void) fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag);
3423		return (0);
3424	}
3425}
3426
3427/*
3428 * take a block out of the map
3429 */
3430static void
3431clrblock(struct fs *fs, unsigned char *cp, int h)
3432{
3433	switch ((fs)->fs_frag) {
3434	case 8:
3435		cp[h] = 0;
3436		return;
3437	case 4:
3438		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
3439		return;
3440	case 2:
3441		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
3442		return;
3443	case 1:
3444		cp[h >> 3] &= ~(0x01 << (h & 0x7));
3445		return;
3446	default:
3447		(void) fprintf(stderr,
3448		    gettext("clrblock: bad fs_frag value %d\n"), fs->fs_frag);
3449		return;
3450	}
3451}
3452
3453/*
3454 * put a block into the map
3455 */
3456static void
3457setblock(struct fs *fs, unsigned char *cp, int h)
3458{
3459	switch (fs->fs_frag) {
3460	case 8:
3461		cp[h] = 0xff;
3462		return;
3463	case 4:
3464		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
3465		return;
3466	case 2:
3467		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
3468		return;
3469	case 1:
3470		cp[h >> 3] |= (0x01 << (h & 0x7));
3471		return;
3472	default:
3473		(void) fprintf(stderr,
3474		    gettext("setblock: bad fs_frag value %d\n"), fs->fs_frag);
3475		return;
3476	}
3477}
3478
3479static void
3480usage(void)
3481{
3482	(void) fprintf(stderr,
3483	    gettext("ufs usage: mkfs [-F FSType] [-V] [-m] [-o options] "
3484	    "special "				/* param 0 */
3485	    "size(sectors) \\ \n"));		/* param 1 */
3486	(void) fprintf(stderr,
3487	    "[nsect "				/* param 2 */
3488	    "ntrack "				/* param 3 */
3489	    "bsize "				/* param 4 */
3490	    "fragsize "				/* param 5 */
3491	    "cpg "				/* param 6 */
3492	    "free "				/* param 7 */
3493	    "rps "				/* param 8 */
3494	    "nbpi "				/* param 9 */
3495	    "opt "				/* param 10 */
3496	    "apc "				/* param 11 */
3497	    "gap "				/* param 12 */
3498	    "nrpos "				/* param 13 */
3499	    "maxcontig "			/* param 14 */
3500	    "mtb]\n");				/* param 15 */
3501	(void) fprintf(stderr,
3502	    gettext(" -m : dump fs cmd line used to make this partition\n"
3503	    " -V :print this command line and return\n"
3504	    " -o :ufs options: :nsect=%d,ntrack=%d,bsize=%d,fragsize=%d\n"
3505	    " -o :ufs options: :cgsize=%d,free=%d,rps=%d,nbpi=%d,opt=%c\n"
3506	    " -o :ufs options: :apc=%d,gap=%d,nrpos=%d,maxcontig=%d\n"
3507	    " -o :ufs options: :mtb=%c,calcsb,calcbinsb\n"
3508"NOTE that all -o suboptions: must be separated only by commas so as to\n"
3509"be parsed as a single argument\n"),
3510	    nsect, ntrack, bsize, fragsize, cpg, sblock.fs_minfree, rps,
3511	    nbpi, opt, apc, (rotdelay == -1) ? 0 : rotdelay,
3512	    sblock.fs_nrpos, maxcontig, mtb);
3513	lockexit(32);
3514}
3515
3516/*ARGSUSED*/
3517static void
3518dump_fscmd(char *fsys, int fsi)
3519{
3520	int64_t used, bpcg, inospercg;
3521	int64_t nbpi;
3522	uint64_t nbytes64;
3523
3524	bzero((char *)&sblock, sizeof (sblock));
3525	rdfs((diskaddr_t)SBLOCK, SBSIZE, (char *)&sblock);
3526
3527	/*
3528	 * ensure a valid file system and if not, exit with error or else
3529	 * we will end up computing block numbers etc and dividing by zero
3530	 * which will cause floating point errors in this routine.
3531	 */
3532
3533	if ((sblock.fs_magic != FS_MAGIC) &&
3534	    (sblock.fs_magic != MTB_UFS_MAGIC)) {
3535		(void) fprintf(stderr, gettext(
3536		    "[not currently a valid file system - bad superblock]\n"));
3537		lockexit(32);
3538	}
3539
3540	if (sblock.fs_magic == FS_MAGIC &&
3541	    (sblock.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
3542	    sblock.fs_version != UFS_VERSION_MIN)) {
3543		(void) fprintf(stderr, gettext(
3544		    "Unknown version of UFS format: %d\n"), sblock.fs_version);
3545		lockexit(32);
3546	}
3547
3548	if (sblock.fs_magic == MTB_UFS_MAGIC &&
3549	    (sblock.fs_version > MTB_UFS_VERSION_1 ||
3550	    sblock.fs_version < MTB_UFS_VERSION_MIN)) {
3551		(void) fprintf(stderr, gettext(
3552		    "Unknown version of UFS format: %d\n"), sblock.fs_version);
3553		lockexit(32);
3554	}
3555
3556	/*
3557	 * Compute a reasonable nbpi value.
3558	 * The algorithm for "used" is copied from code
3559	 * in main() verbatim.
3560	 * The nbpi equation is taken from main where the
3561	 * fs_ipg value is set for the last time.  The INOPB(...) - 1
3562	 * is used to account for the roundup.
3563	 * The problem is that a range of nbpi values map to
3564	 * the same file system layout.  So it is not possible
3565	 * to calculate the exact value specified when the file
3566	 * system was created.  So instead we determine the top
3567	 * end of the range of values.
3568	 */
3569	bpcg = sblock.fs_spc * sectorsize;
3570	inospercg = (int64_t)roundup(bpcg / sizeof (struct dinode),
3571	    INOPB(&sblock));
3572	if (inospercg > MAXIpG(&sblock))
3573		inospercg = MAXIpG(&sblock);
3574	used = (int64_t)
3575	    (sblock.fs_iblkno + inospercg / INOPF(&sblock)) * NSPF(&sblock);
3576	used *= sectorsize;
3577	nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
3578
3579	/*
3580	 * The top end of the range of values for nbpi may not be
3581	 * a valid command line value for mkfs. Report the bottom
3582	 * end instead.
3583	 */
3584	nbpi = (int64_t)(nbytes64 / (sblock.fs_ipg));
3585
3586	(void) fprintf(stdout, gettext("mkfs -F ufs -o "), fsys);
3587	(void) fprintf(stdout, "nsect=%d,ntrack=%d,",
3588	    sblock.fs_nsect, sblock.fs_ntrak);
3589	(void) fprintf(stdout, "bsize=%d,fragsize=%d,cgsize=%d,free=%d,",
3590	    sblock.fs_bsize, sblock.fs_fsize, sblock.fs_cpg, sblock.fs_minfree);
3591	(void) fprintf(stdout, "rps=%d,nbpi=%lld,opt=%c,apc=%d,gap=%d,",
3592	    sblock.fs_rps, nbpi, (sblock.fs_optim == FS_OPTSPACE) ? 's' : 't',
3593	    (sblock.fs_ntrak * sblock.fs_nsect) - sblock.fs_spc,
3594	    sblock.fs_rotdelay);
3595	(void) fprintf(stdout, "nrpos=%d,maxcontig=%d,mtb=%c ",
3596	    sblock.fs_nrpos, sblock.fs_maxcontig,
3597	    ((sblock.fs_magic == MTB_UFS_MAGIC) ? 'y' : 'n'));
3598	(void) fprintf(stdout, "%s %lld\n", fsys,
3599	    fsbtodb(&sblock, sblock.fs_size));
3600
3601	bzero((char *)&sblock, sizeof (sblock));
3602}
3603
3604/* number ************************************************************* */
3605/*									*/
3606/* Convert a numeric string arg to binary				*/
3607/*									*/
3608/* Args:	d_value - default value, if have parse error		*/
3609/*		param - the name of the argument, for error messages	*/
3610/*		flags - parser state and what's allowed in the arg	*/
3611/* Global arg:  string - pointer to command arg				*/
3612/*									*/
3613/* Valid forms: 123 | 123k | 123*123 | 123x123				*/
3614/*									*/
3615/* Return:	converted number					*/
3616/*									*/
3617/* ******************************************************************** */
3618
3619static uint64_t
3620number(uint64_t d_value, char *param, int flags)
3621{
3622	char *cs;
3623	uint64_t n, t;
3624	uint64_t cut = BIG / 10;    /* limit to avoid overflow */
3625	int minus = 0;
3626
3627	cs = string;
3628	if (*cs == '-') {
3629		minus = 1;
3630		cs += 1;
3631	}
3632	if ((*cs < '0') || (*cs > '9')) {
3633		goto bail_out;
3634	}
3635	n = 0;
3636	while ((*cs >= '0') && (*cs <= '9') && (n <= cut)) {
3637		n = n*10 + *cs++ - '0';
3638	}
3639	if (minus)
3640		n = -n;
3641	for (;;) {
3642		switch (*cs++) {
3643		case 'k':
3644			if (flags & ALLOW_END_ONLY)
3645				goto bail_out;
3646			if (n > (BIG / 1024))
3647				goto overflow;
3648			n *= 1024;
3649			continue;
3650
3651		case '*':
3652		case 'x':
3653			if (flags & ALLOW_END_ONLY)
3654				goto bail_out;
3655			string = cs;
3656			t = number(d_value, param, flags);
3657			if (n > (BIG / t))
3658				goto overflow;
3659			n *= t;
3660			cs = string + 1; /* adjust for -- below */
3661
3662			/* recursion has read rest of expression */
3663			/* FALLTHROUGH */
3664
3665		case ',':
3666		case '\0':
3667			cs--;
3668			string = cs;
3669			return (n);
3670
3671		case '%':
3672			if (flags & ALLOW_END_ONLY)
3673				goto bail_out;
3674			if (flags & ALLOW_PERCENT) {
3675				flags &= ~ALLOW_PERCENT;
3676				flags |= ALLOW_END_ONLY;
3677				continue;
3678			}
3679			goto bail_out;
3680
3681		case 'm':
3682			if (flags & ALLOW_END_ONLY)
3683				goto bail_out;
3684			if (flags & ALLOW_MS1) {
3685				flags &= ~ALLOW_MS1;
3686				flags |= ALLOW_MS2;
3687				continue;
3688			}
3689			goto bail_out;
3690
3691		case 's':
3692			if (flags & ALLOW_END_ONLY)
3693				goto bail_out;
3694			if (flags & ALLOW_MS2) {
3695				flags &= ~ALLOW_MS2;
3696				flags |= ALLOW_END_ONLY;
3697				continue;
3698			}
3699			goto bail_out;
3700
3701		case '0': case '1': case '2': case '3': case '4':
3702		case '5': case '6': case '7': case '8': case '9':
3703overflow:
3704			(void) fprintf(stderr,
3705			    gettext("mkfs: value for %s overflowed\n"),
3706			    param);
3707			while ((*cs != '\0') && (*cs != ','))
3708				cs++;
3709			string = cs;
3710			return (BIG);
3711
3712		default:
3713bail_out:
3714			(void) fprintf(stderr, gettext(
3715			    "mkfs: bad numeric arg for %s: \"%s\"\n"),
3716			    param, string);
3717			while ((*cs != '\0') && (*cs != ','))
3718				cs++;
3719			string = cs;
3720			if (d_value != NO_DEFAULT) {
3721				(void) fprintf(stderr,
3722				    gettext("mkfs: %s reset to default %lld\n"),
3723				    param, d_value);
3724				return (d_value);
3725			}
3726			lockexit(2);
3727
3728		}
3729	} /* never gets here */
3730}
3731
3732/* match ************************************************************** */
3733/*									*/
3734/* Compare two text strings for equality				*/
3735/*									*/
3736/* Arg:	 s - pointer to string to match with a command arg		*/
3737/* Global arg:  string - pointer to command arg				*/
3738/*									*/
3739/* Return:	1 if match, 0 if no match				*/
3740/*		If match, also reset `string' to point to the text	*/
3741/*		that follows the matching text.				*/
3742/*									*/
3743/* ******************************************************************** */
3744
3745static int
3746match(char *s)
3747{
3748	char *cs;
3749
3750	cs = string;
3751	while (*cs++ == *s) {
3752		if (*s++ == '\0') {
3753			goto true;
3754		}
3755	}
3756	if (*s != '\0') {
3757		return (0);
3758	}
3759
3760true:
3761	cs--;
3762	string = cs;
3763	return (1);
3764}
3765
3766/*
3767 * GROWFS ROUTINES
3768 */
3769
3770/* ARGSUSED */
3771void
3772lockexit(int exitstatus)
3773{
3774	if (Pflag) {
3775		/* the probe mode neither changes nor locks the filesystem */
3776		exit(exitstatus);
3777	}
3778
3779	/*
3780	 * flush the dirty cylinder group
3781	 */
3782	if (inlockexit == 0) {
3783		inlockexit = 1;
3784		flcg();
3785	}
3786
3787	if (aio_inited) {
3788		flush_writes();
3789	}
3790
3791	/*
3792	 * make sure the file system is unlocked before exiting
3793	 */
3794	if ((inlockexit == 1) && (!isbad)) {
3795		inlockexit = 2;
3796		ulockfs();
3797		/*
3798		 * if logging was enabled, then re-enable it
3799		 */
3800		if (waslog) {
3801			if (rl_log_control(fsys, _FIOLOGENABLE) != RL_SUCCESS) {
3802				(void) fprintf(stderr, gettext(
3803				    "failed to re-enable logging\n"));
3804			}
3805		}
3806	} else if (grow) {
3807		if (isbad) {
3808			(void) fprintf(stderr, gettext(
3809			    "Filesystem is currently inconsistent.  It "
3810			    "must be repaired with fsck(1M)\nbefore being "
3811			    "used.  Use the following command to "
3812			    "do this:\n\n\tfsck %s\n\n"), fsys);
3813
3814			if (ismounted) {
3815				(void) fprintf(stderr, gettext(
3816				    "You will be told that the filesystem "
3817				    "is already mounted, and asked if you\n"
3818				    "wish to continue.  Answer `yes' to "
3819				    "this question.\n\n"));
3820			}
3821
3822			(void) fprintf(stderr, gettext(
3823			    "One problem should be reported, that the summary "
3824			    "information is bad.\nYou will then be asked if it "
3825			    "should be salvaged.  Answer `yes' to\nthis "
3826			    "question.\n\n"));
3827		}
3828
3829		if (ismounted) {
3830			/*
3831			 * In theory, there's no way to get here without
3832			 * isbad also being set, but be robust in the
3833			 * face of future code changes.
3834			 */
3835			(void) fprintf(stderr, gettext(
3836			    "The filesystem is currently mounted "
3837			    "read-only and write-locked.  "));
3838			if (isbad) {
3839				(void) fprintf(stderr, gettext(
3840				    "After\nrunning fsck, unlock the "
3841				    "filesystem and "));
3842			} else {
3843				(void) fprintf(stderr, gettext(
3844				    "Unlock the filesystem\nand "));
3845			}
3846
3847			(void) fprintf(stderr, gettext(
3848			    "re-enable writing with\nthe following "
3849			    "command:\n\n\tlockfs -u %s\n\n"), directory);
3850		}
3851	}
3852
3853	exit(exitstatus);
3854}
3855
3856void
3857randomgeneration()
3858{
3859	int		 i;
3860	struct dinode	*dp;
3861
3862	/*
3863	 * always perform fsirand(1) function... newfs will notice that
3864	 * the inodes have been randomized and will not call fsirand itself
3865	 */
3866	for (i = 0, dp = zino; i < sblock.fs_inopb; ++i, ++dp)
3867		IRANDOMIZE(&dp->di_ic);
3868}
3869
3870/*
3871 * Check the size of the summary information.
3872 * Fields in sblock are not changed in this function.
3873 *
3874 * For an 8K filesystem block, the maximum number of cylinder groups is 16384.
3875 *     MAXCSBUFS {32}  *   8K  {FS block size}
3876 *                         divided by (sizeof csum) {16}
3877 *
3878 * Note that MAXCSBUFS is not used in the kernel; as of Solaris 2.6 build 32,
3879 * this is the only place where it's referenced.
3880 */
3881void
3882checksummarysize()
3883{
3884	diskaddr_t	dmax;
3885	diskaddr_t	dmin;
3886	int64_t	cg0frags;
3887	int64_t	cg0blocks;
3888	int64_t	maxncg;
3889	int64_t	maxfrags;
3890	uint64_t	fs_size;
3891	uint64_t maxfs_blocks; /* filesystem blocks for max filesystem size */
3892
3893	/*
3894	 * compute the maximum summary info size
3895	 */
3896	dmin = cgdmin(&sblock, 0);
3897	dmax = cgbase(&sblock, 0) + sblock.fs_fpg;
3898	fs_size = (grow) ? grow_fs_size : sblock.fs_size;
3899	if (dmax > fs_size)
3900		dmax = fs_size;
3901	cg0frags  = dmax - dmin;
3902	cg0blocks = cg0frags / sblock.fs_frag;
3903	cg0frags = cg0blocks * sblock.fs_frag;
3904	maxncg   = (longlong_t)cg0blocks *
3905	    (longlong_t)(sblock.fs_bsize / sizeof (struct csum));
3906
3907	maxfs_blocks = FS_MAX;
3908
3909	if (maxncg > ((longlong_t)maxfs_blocks / (longlong_t)sblock.fs_fpg) + 1)
3910		maxncg = ((longlong_t)maxfs_blocks /
3911		    (longlong_t)sblock.fs_fpg) + 1;
3912
3913	maxfrags = maxncg * (longlong_t)sblock.fs_fpg;
3914
3915	if (maxfrags > maxfs_blocks)
3916		maxfrags = maxfs_blocks;
3917
3918
3919	/*
3920	 * remember for later processing in extendsummaryinfo()
3921	 */
3922	if (test)
3923		grow_sifrag = dmin + (cg0blocks * sblock.fs_frag);
3924	if (testfrags == 0)
3925		testfrags = cg0frags;
3926	if (testforce)
3927		if (testfrags > cg0frags) {
3928			(void) fprintf(stderr,
3929			    gettext("Too many test frags (%lld); "
3930			    "try %lld\n"), testfrags, cg0frags);
3931			lockexit(32);
3932		}
3933
3934	/*
3935	 * if summary info is too large (too many cg's) tell the user and exit
3936	 */
3937	if ((longlong_t)sblock.fs_size > maxfrags) {
3938		(void) fprintf(stderr, gettext(
3939		    "Too many cylinder groups with %llu sectors;\n    try "
3940		    "increasing cgsize, or decreasing fssize to %llu\n"),
3941		    fsbtodb(&sblock, (uint64_t)sblock.fs_size),
3942		    fsbtodb(&sblock, (uint64_t)maxfrags));
3943		lockexit(32);
3944	}
3945}
3946
3947/*
3948 * checksblock() has two uses:
3949 *	- One is to sanity test the superblock and is used when newfs(1M)
3950 *	  is invoked with the "-N" option. If any discrepancy was found,
3951 *	  just return whatever error was found and do not exit.
3952 *	- the other use of it is in places where you expect the superblock
3953 *	  to be sane, and if it isn't, then we exit.
3954 * Which of the above two actions to take is indicated with the second argument.
3955 */
3956
3957int
3958checksblock(struct fs sb, int proceed)
3959{
3960	int err = 0;
3961	char *errmsg;
3962
3963	if ((sb.fs_magic != FS_MAGIC) && (sb.fs_magic != MTB_UFS_MAGIC)) {
3964		err = 1;
3965		errmsg = gettext("Bad superblock; magic number wrong\n");
3966	} else if ((sb.fs_magic == FS_MAGIC &&
3967	    (sb.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
3968	    sb.fs_version != UFS_VERSION_MIN)) ||
3969	    (sb.fs_magic == MTB_UFS_MAGIC &&
3970	    (sb.fs_version > MTB_UFS_VERSION_1 ||
3971	    sb.fs_version < MTB_UFS_VERSION_MIN))) {
3972		err = 2;
3973		errmsg = gettext("Unrecognized version of UFS\n");
3974	} else if (sb.fs_ncg < 1) {
3975		err = 3;
3976		errmsg = gettext("Bad superblock; ncg out of range\n");
3977	} else if (sb.fs_cpg < 1) {
3978		err = 4;
3979		errmsg = gettext("Bad superblock; cpg out of range\n");
3980	} else if (sb.fs_ncg * sb.fs_cpg < sb.fs_ncyl ||
3981	    (sb.fs_ncg - 1) * sb.fs_cpg >= sb.fs_ncyl) {
3982		err = 5;
3983		errmsg = gettext("Bad superblock; ncyl out of range\n");
3984	} else if (sb.fs_sbsize <= 0 || sb.fs_sbsize > sb.fs_bsize) {
3985		err = 6;
3986		errmsg = gettext("Bad superblock; superblock size out of "
3987		    "range\n");
3988	}
3989
3990	if (proceed) {
3991		if (err) dprintf(("%s", errmsg));
3992		return (err);
3993	}
3994
3995	if (err) {
3996		fprintf(stderr, "%s", errmsg);
3997		lockexit(32);
3998	}
3999	return (32);
4000}
4001
4002/*
4003 * Roll the embedded log, if any, and set up the global variables
4004 * islog and islogok.
4005 */
4006static void
4007logsetup(char *devstr)
4008{
4009	void		*buf, *ud_buf;
4010	extent_block_t	*ebp;
4011	ml_unit_t	*ul;
4012	ml_odunit_t	*ud;
4013
4014	/*
4015	 * Does the superblock indicate that we are supposed to have a log ?
4016	 */
4017	if (sblock.fs_logbno == 0) {
4018		/*
4019		 * No log present, nothing to do.
4020		 */
4021		islog = 0;
4022		islogok = 0;
4023		return;
4024	} else {
4025		/*
4026		 * There's a log in a yet unknown state, attempt to roll it.
4027		 */
4028		islogok = 0;
4029
4030		/*
4031		 * We failed to roll the log, bail out.
4032		 */
4033		if (rl_roll_log(devstr) != RL_SUCCESS)
4034			return;
4035
4036		islog = 1;
4037
4038		/* log is not okay; check the fs */
4039		if ((FSOKAY != (sblock.fs_state + sblock.fs_time)) ||
4040		    (sblock.fs_clean != FSLOG))
4041			return;
4042
4043		/* get the log allocation block */
4044		buf = (void *)malloc(DEV_BSIZE);
4045		if (buf == (void *) NULL)
4046			return;
4047
4048		ud_buf = (void *)malloc(DEV_BSIZE);
4049		if (ud_buf == (void *) NULL) {
4050			free(buf);
4051			return;
4052		}
4053
4054		rdfs((diskaddr_t)logbtodb(&sblock, sblock.fs_logbno),
4055		    DEV_BSIZE, buf);
4056		ebp = (extent_block_t *)buf;
4057
4058		/* log allocation block is not okay; check the fs */
4059		if (ebp->type != LUFS_EXTENTS) {
4060			free(buf);
4061			free(ud_buf);
4062			return;
4063		}
4064
4065		/* get the log state block(s) */
4066		rdfs((diskaddr_t)logbtodb(&sblock, ebp->extents[0].pbno),
4067		    DEV_BSIZE, ud_buf);
4068		ud = (ml_odunit_t *)ud_buf;
4069		ul = (ml_unit_t *)malloc(sizeof (*ul));
4070		ul->un_ondisk = *ud;
4071
4072		/* log state is okay */
4073		if ((ul->un_chksum == ul->un_head_ident + ul->un_tail_ident) &&
4074		    (ul->un_version == LUFS_VERSION_LATEST) &&
4075		    (ul->un_badlog == 0))
4076			islogok = 1;
4077		free(ud_buf);
4078		free(buf);
4079		free(ul);
4080	}
4081}
4082
4083void
4084growinit(char *devstr)
4085{
4086	int	i;
4087	char	buf[DEV_BSIZE];
4088
4089	/*
4090	 * Read and verify the superblock
4091	 */
4092	rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
4093	(void) checksblock(sblock, 0);
4094	if (sblock.fs_postblformat != FS_DYNAMICPOSTBLFMT) {
4095		(void) fprintf(stderr,
4096		    gettext("old file system format; can't growfs\n"));
4097		lockexit(32);
4098	}
4099
4100	/*
4101	 * can't shrink a file system
4102	 */
4103	grow_fssize = fsbtodb(&sblock, (uint64_t)sblock.fs_size);
4104	if (fssize_db < grow_fssize) {
4105		(void) fprintf(stderr,
4106		    gettext("%lld sectors < current size of %lld sectors\n"),
4107		    fssize_db, grow_fssize);
4108		lockexit(32);
4109	}
4110
4111	/*
4112	 * can't grow a system to over a terabyte unless it was set up
4113	 * as an MTB UFS file system.
4114	 */
4115	if (mtb == 'y' && sblock.fs_magic != MTB_UFS_MAGIC) {
4116		if (fssize_db >= SECTORS_PER_TERABYTE) {
4117			(void) fprintf(stderr, gettext(
4118"File system was not set up with the multi-terabyte format.\n"));
4119			(void) fprintf(stderr, gettext(
4120"Its size cannot be increased to a terabyte or more.\n"));
4121		} else {
4122			(void) fprintf(stderr, gettext(
4123"Cannot convert file system to multi-terabyte format.\n"));
4124		}
4125		lockexit(32);
4126	}
4127
4128	logsetup(devstr);
4129
4130	/*
4131	 * can't growfs when logging device has errors
4132	 */
4133	if ((islog && !islogok) ||
4134	    ((FSOKAY == (sblock.fs_state + sblock.fs_time)) &&
4135	    (sblock.fs_clean == FSLOG && !islog))) {
4136		(void) fprintf(stderr,
4137		    gettext("logging device has errors; can't growfs\n"));
4138		lockexit(32);
4139	}
4140
4141	/*
4142	 * disable ufs logging for growing
4143	 */
4144	if (islog) {
4145		if (rl_log_control(devstr, _FIOLOGDISABLE) != RL_SUCCESS) {
4146			(void) fprintf(stderr, gettext(
4147			    "failed to disable logging\n"));
4148			lockexit(32);
4149		}
4150		islog = 0;
4151		waslog = 1;
4152	}
4153
4154	/*
4155	 * if mounted write lock the file system to be grown
4156	 */
4157	if (ismounted)
4158		wlockfs();
4159
4160	/*
4161	 * refresh dynamic superblock state - disabling logging will have
4162	 * changed the amount of free space available in the file system
4163	 */
4164	rdfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
4165
4166	/*
4167	 * make sure device is big enough
4168	 */
4169	rdfs((diskaddr_t)fssize_db - 1, DEV_BSIZE, buf);
4170	wtfs((diskaddr_t)fssize_db - 1, DEV_BSIZE, buf);
4171
4172	/*
4173	 * read current summary information
4174	 */
4175	grow_fscs = read_summaryinfo(&sblock);
4176
4177	/*
4178	 * save some current size related fields from the superblock
4179	 * These are used in extendsummaryinfo()
4180	 */
4181	grow_fs_size	= sblock.fs_size;
4182	grow_fs_ncg	= sblock.fs_ncg;
4183	grow_fs_csaddr	= (diskaddr_t)sblock.fs_csaddr;
4184	grow_fs_cssize	= sblock.fs_cssize;
4185
4186	/*
4187	 * save and reset the clean flag
4188	 */
4189	if (FSOKAY == (sblock.fs_state + sblock.fs_time))
4190		grow_fs_clean = sblock.fs_clean;
4191	else
4192		grow_fs_clean = FSBAD;
4193	sblock.fs_clean = FSBAD;
4194	sblock.fs_state = FSOKAY - sblock.fs_time;
4195	isbad = 1;
4196	wtfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
4197}
4198
4199void
4200checkdev(char *rdev, char *bdev)
4201{
4202	struct stat64	statarea;
4203
4204	if (stat64(bdev, &statarea) < 0) {
4205		(void) fprintf(stderr, gettext("can't check mount point; "));
4206		(void) fprintf(stderr, gettext("can't stat %s\n"), bdev);
4207		lockexit(32);
4208	}
4209	if ((statarea.st_mode & S_IFMT) != S_IFBLK) {
4210		(void) fprintf(stderr, gettext(
4211		    "can't check mount point; %s is not a block device\n"),
4212		    bdev);
4213		lockexit(32);
4214	}
4215	if (stat64(rdev, &statarea) < 0) {
4216		(void) fprintf(stderr, gettext("can't stat %s\n"), rdev);
4217		lockexit(32);
4218	}
4219	if ((statarea.st_mode & S_IFMT) != S_IFCHR) {
4220		(void) fprintf(stderr,
4221		    gettext("%s is not a character device\n"), rdev);
4222		lockexit(32);
4223	}
4224}
4225
4226void
4227checkmount(struct mnttab *mntp, char *bdevname)
4228{
4229	struct stat64	statdir;
4230	struct stat64	statdev;
4231
4232	if (strcmp(bdevname, mntp->mnt_special) == 0) {
4233		if (stat64(mntp->mnt_mountp, &statdir) == -1) {
4234			(void) fprintf(stderr, gettext("can't stat %s\n"),
4235			    mntp->mnt_mountp);
4236			lockexit(32);
4237		}
4238		if (stat64(mntp->mnt_special, &statdev) == -1) {
4239			(void) fprintf(stderr, gettext("can't stat %s\n"),
4240			    mntp->mnt_special);
4241			lockexit(32);
4242		}
4243		if (statdir.st_dev != statdev.st_rdev) {
4244			(void) fprintf(stderr, gettext(
4245			    "%s is not mounted on %s; mnttab(4) wrong\n"),
4246			    mntp->mnt_special, mntp->mnt_mountp);
4247			lockexit(32);
4248		}
4249		ismounted = 1;
4250		if (directory) {
4251			if (strcmp(mntp->mnt_mountp, directory) != 0) {
4252				(void) fprintf(stderr,
4253				    gettext("%s is mounted on %s, not %s\n"),
4254				    bdevname, mntp->mnt_mountp, directory);
4255				lockexit(32);
4256			}
4257		} else {
4258			if (grow)
4259				(void) fprintf(stderr, gettext(
4260				    "%s is mounted on %s; can't growfs\n"),
4261				    bdevname, mntp->mnt_mountp);
4262			else
4263				(void) fprintf(stderr,
4264				    gettext("%s is mounted, can't mkfs\n"),
4265				    bdevname);
4266			lockexit(32);
4267		}
4268	}
4269}
4270
4271struct dinode	*dibuf	= 0;
4272diskaddr_t	difrag	= 0;
4273
4274struct dinode *
4275gdinode(ino_t ino)
4276{
4277	/*
4278	 * read the block of inodes containing inode number ino
4279	 */
4280	if (dibuf == 0)
4281		dibuf = (struct dinode *)malloc((unsigned)sblock.fs_bsize);
4282	if (itod(&sblock, ino) != difrag) {
4283		difrag = itod(&sblock, ino);
4284		rdfs(fsbtodb(&sblock, (uint64_t)difrag), (int)sblock.fs_bsize,
4285		    (char *)dibuf);
4286	}
4287	return (dibuf + (ino % INOPB(&sblock)));
4288}
4289
4290/*
4291 * structure that manages the frags we need for extended summary info
4292 *	These frags can be:
4293 *		free
4294 *		data  block
4295 *		alloc block
4296 */
4297struct csfrag {
4298	struct csfrag	*next;		/* next entry */
4299	daddr32_t	 ofrag;		/* old frag */
4300	daddr32_t	 nfrag;		/* new frag */
4301	long		 cylno;		/* cylno of nfrag */
4302	long		 frags;		/* number of frags */
4303	long		 size;		/* size in bytes */
4304	ino_t		 ino;		/* inode number */
4305	long		 fixed;		/* Boolean - Already fixed? */
4306};
4307struct csfrag	*csfrag;		/* state unknown */
4308struct csfrag	*csfragino;		/* frags belonging to an inode */
4309struct csfrag	*csfragfree;		/* frags that are free */
4310
4311daddr32_t maxcsfrag	= 0;		/* maximum in range */
4312daddr32_t mincsfrag	= 0x7fffffff;	/* minimum in range */
4313
4314int
4315csfraginrange(daddr32_t frag)
4316{
4317	return ((frag >= mincsfrag) && (frag <= maxcsfrag));
4318}
4319
4320struct csfrag *
4321findcsfrag(daddr32_t frag, struct csfrag **cfap)
4322{
4323	struct csfrag	*cfp;
4324
4325	if (!csfraginrange(frag))
4326		return (NULL);
4327
4328	for (cfp = *cfap; cfp; cfp = cfp->next)
4329		if (cfp->ofrag == frag)
4330			return (cfp);
4331	return (NULL);
4332}
4333
4334void
4335checkindirect(ino_t ino, daddr32_t *fragsp, daddr32_t frag, int level)
4336{
4337	int			i;
4338	int			ne	= sblock.fs_bsize / sizeof (daddr32_t);
4339	daddr32_t			fsb[MAXBSIZE / sizeof (daddr32_t)];
4340
4341	if (frag == 0)
4342		return;
4343
4344	rdfs(fsbtodb(&sblock, frag), (int)sblock.fs_bsize,
4345	    (char *)fsb);
4346
4347	checkdirect(ino, fragsp, fsb, sblock.fs_bsize / sizeof (daddr32_t));
4348
4349	if (level)
4350		for (i = 0; i < ne && *fragsp; ++i)
4351			checkindirect(ino, fragsp, fsb[i], level-1);
4352}
4353
4354void
4355addcsfrag(ino_t ino, daddr32_t frag, struct csfrag **cfap)
4356{
4357	struct csfrag	*cfp, *curr, *prev;
4358
4359	/*
4360	 * establish a range for faster checking in csfraginrange()
4361	 */
4362	if (frag > maxcsfrag)
4363		maxcsfrag = frag;
4364	if (frag < mincsfrag)
4365		mincsfrag = frag;
4366
4367	/*
4368	 * if this frag belongs to an inode and is not the start of a block
4369	 *	then see if it is part of a frag range for this inode
4370	 */
4371	if (ino && (frag % sblock.fs_frag))
4372		for (cfp = *cfap; cfp; cfp = cfp->next) {
4373			if (ino != cfp->ino)
4374				continue;
4375			if (frag != cfp->ofrag + cfp->frags)
4376				continue;
4377			cfp->frags++;
4378			cfp->size += sblock.fs_fsize;
4379			return;
4380		}
4381	/*
4382	 * allocate a csfrag entry and insert it in an increasing order into the
4383	 * specified list
4384	 */
4385	cfp = (struct csfrag *)calloc(1, sizeof (struct csfrag));
4386	cfp->ino	= ino;
4387	cfp->ofrag	= frag;
4388	cfp->frags	= 1;
4389	cfp->size	= sblock.fs_fsize;
4390	for (prev = NULL, curr = *cfap; curr != NULL;
4391	    prev = curr, curr = curr->next) {
4392		if (frag < curr->ofrag) {
4393			cfp->next = curr;
4394			if (prev)
4395				prev->next = cfp;	/* middle element */
4396			else
4397				*cfap = cfp;		/* first element */
4398			break;
4399		}
4400		if (curr->next == NULL) {
4401			curr->next = cfp;		/* last element	*/
4402			break;
4403		}
4404	}
4405	if (*cfap == NULL)	/* will happen only once */
4406		*cfap = cfp;
4407}
4408
4409void
4410delcsfrag(daddr32_t frag, struct csfrag **cfap)
4411{
4412	struct csfrag	*cfp;
4413	struct csfrag	**cfpp;
4414
4415	/*
4416	 * free up entry whose beginning frag matches
4417	 */
4418	for (cfpp = cfap; *cfpp; cfpp = &(*cfpp)->next) {
4419		if (frag == (*cfpp)->ofrag) {
4420			cfp = *cfpp;
4421			*cfpp = (*cfpp)->next;
4422			free((char *)cfp);
4423			return;
4424		}
4425	}
4426}
4427
4428/*
4429 * See whether any of the direct blocks in the array pointed by "db" and of
4430 * length "ne" are within the range of frags needed to extend the cylinder
4431 * summary. If so, remove those frags from the "as-yet-unclassified" list
4432 * (csfrag) and add them to the "owned-by-inode" list (csfragino).
4433 * For each such frag found, decrement the frag count pointed to by fragsp.
4434 * "ino" is the inode that contains (either directly or indirectly) the frags
4435 * being checked.
4436 */
4437void
4438checkdirect(ino_t ino, daddr32_t *fragsp, daddr32_t *db, int ne)
4439{
4440	int	 i;
4441	int	 j;
4442	int	 found;
4443	diskaddr_t	 frag;
4444
4445	/*
4446	 * scan for allocation within the new summary info range
4447	 */
4448	for (i = 0; i < ne && *fragsp; ++i) {
4449		if ((frag = *db++) != 0) {
4450			found = 0;
4451			for (j = 0; j < sblock.fs_frag && *fragsp; ++j) {
4452				if (found || (found = csfraginrange(frag))) {
4453					addcsfrag(ino, frag, &csfragino);
4454					delcsfrag(frag, &csfrag);
4455				}
4456				++frag;
4457				--(*fragsp);
4458			}
4459		}
4460	}
4461}
4462
4463void
4464findcsfragino()
4465{
4466	int		 i;
4467	int		 j;
4468	daddr32_t		 frags;
4469	struct dinode	*dp;
4470
4471	/*
4472	 * scan all old inodes looking for allocations in the new
4473	 * summary info range.  Move the affected frag from the
4474	 * generic csfrag list onto the `owned-by-inode' list csfragino.
4475	 */
4476	for (i = UFSROOTINO; i < grow_fs_ncg*sblock.fs_ipg && csfrag; ++i) {
4477		dp = gdinode((ino_t)i);
4478		switch (dp->di_mode & IFMT) {
4479			case IFSHAD	:
4480			case IFLNK	:
4481			case IFDIR	:
4482			case IFREG	: break;
4483			default		: continue;
4484		}
4485
4486		frags   = dbtofsb(&sblock, dp->di_blocks);
4487
4488		checkdirect((ino_t)i, &frags, &dp->di_db[0], NDADDR+NIADDR);
4489		for (j = 0; j < NIADDR && frags; ++j) {
4490			/* Negate the block if its an fallocate'd block */
4491			if (dp->di_ib[j] < 0 && dp->di_ib[j] != UFS_HOLE)
4492				checkindirect((ino_t)i, &frags,
4493				    -(dp->di_ib[j]), j);
4494			else
4495				checkindirect((ino_t)i, &frags,
4496				    dp->di_ib[j], j);
4497		}
4498	}
4499}
4500
4501void
4502fixindirect(daddr32_t frag, int level)
4503{
4504	int			 i;
4505	int			 ne	= sblock.fs_bsize / sizeof (daddr32_t);
4506	daddr32_t			fsb[MAXBSIZE / sizeof (daddr32_t)];
4507
4508	if (frag == 0)
4509		return;
4510
4511	rdfs(fsbtodb(&sblock, (uint64_t)frag), (int)sblock.fs_bsize,
4512	    (char *)fsb);
4513
4514	fixdirect((caddr_t)fsb, frag, fsb, ne);
4515
4516	if (level)
4517		for (i = 0; i < ne; ++i)
4518			fixindirect(fsb[i], level-1);
4519}
4520
4521void
4522fixdirect(caddr_t bp, daddr32_t frag, daddr32_t *db, int ne)
4523{
4524	int	 i;
4525	struct csfrag	*cfp;
4526
4527	for (i = 0; i < ne; ++i, ++db) {
4528		if (*db == 0)
4529			continue;
4530		if ((cfp = findcsfrag(*db, &csfragino)) == NULL)
4531			continue;
4532		*db = cfp->nfrag;
4533		cfp->fixed = 1;
4534		wtfs(fsbtodb(&sblock, (uint64_t)frag), (int)sblock.fs_bsize,
4535		    bp);
4536	}
4537}
4538
4539void
4540fixcsfragino()
4541{
4542	int		 i;
4543	struct dinode	*dp;
4544	struct csfrag	*cfp;
4545
4546	for (cfp = csfragino; cfp; cfp = cfp->next) {
4547		if (cfp->fixed)
4548			continue;
4549		dp = gdinode((ino_t)cfp->ino);
4550		fixdirect((caddr_t)dibuf, difrag, dp->di_db, NDADDR+NIADDR);
4551		for (i = 0; i < NIADDR; ++i)
4552			fixindirect(dp->di_ib[i], i);
4553	}
4554}
4555
4556/*
4557 * Read the cylinders summary information specified by settings in the
4558 * passed 'fs' structure into a new allocated array of csum structures.
4559 * The caller is responsible for freeing the returned array.
4560 * Return a pointer to an array of csum structures.
4561 */
4562static struct csum *
4563read_summaryinfo(struct	fs *fsp)
4564{
4565	struct csum	*csp;
4566	int		i;
4567
4568	if ((csp = malloc((size_t)fsp->fs_cssize)) == NULL) {
4569		(void) fprintf(stderr, gettext("cannot create csum list,"
4570		    " not enough memory\n"));
4571		exit(32);
4572	}
4573
4574	for (i = 0; i < fsp->fs_cssize; i += fsp->fs_bsize) {
4575		rdfs(fsbtodb(fsp,
4576		    (uint64_t)(fsp->fs_csaddr + numfrags(fsp, i))),
4577		    (int)(fsp->fs_cssize - i < fsp->fs_bsize ?
4578		    fsp->fs_cssize - i : fsp->fs_bsize), ((caddr_t)csp) + i);
4579	}
4580
4581	return (csp);
4582}
4583
4584/*
4585 * Check the allocation of fragments that are to be made part of a csum block.
4586 * A fragment is allocated if it is either in the csfragfree list or, it is
4587 * in the csfragino list and has new frags associated with it.
4588 * Return the number of allocated fragments.
4589 */
4590int64_t
4591checkfragallocated(daddr32_t frag)
4592{
4593	struct	csfrag	*cfp;
4594	/*
4595	 * Since the lists are sorted we can break the search if the asked
4596	 * frag is smaller then the one in the list.
4597	 */
4598	for (cfp = csfragfree; cfp != NULL && frag >= cfp->ofrag;
4599	    cfp = cfp->next) {
4600		if (frag == cfp->ofrag)
4601			return (1);
4602	}
4603	for (cfp = csfragino; cfp != NULL && frag >= cfp->ofrag;
4604	    cfp = cfp->next) {
4605		if (frag == cfp->ofrag && cfp->nfrag != 0)
4606			return (cfp->frags);
4607	}
4608
4609	return (0);
4610}
4611
4612/*
4613 * Figure out how much the filesystem can be grown. The limiting factor is
4614 * the available free space needed to extend the cg summary info block.
4615 * The free space is determined in three steps:
4616 * - Try to extend the cg summary block to the required size.
4617 * - Find free blocks in last cg.
4618 * - Find free space in the last already allocated fragment of the summary info
4619 *   block, and use it for additional csum structures.
4620 * Return the maximum size of the new filesystem or 0 if it can't be grown.
4621 * Please note that this function leaves the global list pointers csfrag,
4622 * csfragfree, and csfragino initialized, and the caller is responsible for
4623 * freeing the lists.
4624 */
4625diskaddr_t
4626probe_summaryinfo()
4627{
4628	/* fragments by which the csum block can be extended. */
4629	int64_t		growth_csum_frags = 0;
4630	/* fragments by which the filesystem can be extended. */
4631	int64_t		growth_fs_frags = 0;
4632	int64_t		new_fs_cssize;	/* size of csum blk in the new FS */
4633	int64_t		new_fs_ncg;	/* number of cg in the new FS */
4634	int64_t		spare_csum;
4635	daddr32_t	oldfrag_daddr;
4636	daddr32_t	newfrag_daddr;
4637	daddr32_t	daddr;
4638	int		i;
4639
4640	/*
4641	 * read and verify the superblock
4642	 */
4643	rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
4644	(void) checksblock(sblock, 0);
4645
4646	/*
4647	 * check how much we can extend the cg summary info block
4648	 */
4649
4650	/*
4651	 * read current summary information
4652	 */
4653	fscs = read_summaryinfo(&sblock);
4654
4655	/*
4656	 * build list of frags needed for cg summary info block extension
4657	 */
4658	oldfrag_daddr = howmany(sblock.fs_cssize, sblock.fs_fsize) +
4659	    sblock.fs_csaddr;
4660	new_fs_ncg = howmany(dbtofsb(&sblock, fssize_db), sblock.fs_fpg);
4661	new_fs_cssize = fragroundup(&sblock, new_fs_ncg * sizeof (struct csum));
4662	newfrag_daddr = howmany(new_fs_cssize, sblock.fs_fsize) +
4663	    sblock.fs_csaddr;
4664	/*
4665	 * add all of the frags that are required to grow the cyl summary to the
4666	 * csfrag list, which is the generic/unknown list, since at this point
4667	 * we don't yet know the state of those frags.
4668	 */
4669	for (daddr = oldfrag_daddr; daddr < newfrag_daddr; daddr++)
4670		addcsfrag((ino_t)0, daddr, &csfrag);
4671
4672	/*
4673	 * filter free fragments and allocate them. Note that the free frags
4674	 * must be allocated first otherwise they could be grabbed by
4675	 * alloccsfragino() for data frags.
4676	 */
4677	findcsfragfree();
4678	alloccsfragfree();
4679
4680	/*
4681	 * filter fragments owned by inodes and allocate them
4682	 */
4683	grow_fs_ncg = sblock.fs_ncg; /* findcsfragino() needs this glob. var. */
4684	findcsfragino();
4685	alloccsfragino();
4686
4687	if (notenoughspace()) {
4688		/*
4689		 * check how many consecutive fragments could be allocated
4690		 * in both lists.
4691		 */
4692		int64_t tmp_frags;
4693		for (daddr = oldfrag_daddr; daddr < newfrag_daddr;
4694		    daddr += tmp_frags) {
4695			if ((tmp_frags = checkfragallocated(daddr)) > 0)
4696				growth_csum_frags += tmp_frags;
4697			else
4698				break;
4699		}
4700	} else {
4701		/*
4702		 * We have all we need for the new desired size,
4703		 * so clean up and report back.
4704		 */
4705		return (fssize_db);
4706	}
4707
4708	/*
4709	 * given the number of fragments by which the csum block can be grown
4710	 * compute by how many new fragments the FS can be increased.
4711	 * It is the number of csum instances per fragment multiplied by
4712	 * `growth_csum_frags' and the number of fragments per cylinder group.
4713	 */
4714	growth_fs_frags = howmany(sblock.fs_fsize, sizeof (struct csum)) *
4715	    growth_csum_frags * sblock.fs_fpg;
4716
4717	/*
4718	 * compute free fragments in the last cylinder group
4719	 */
4720	rdcg(sblock.fs_ncg - 1);
4721	growth_fs_frags += sblock.fs_fpg - acg.cg_ndblk;
4722
4723	/*
4724	 * compute how many csum instances are unused in the old csum block.
4725	 * For each unused csum instance the FS can be grown by one cylinder
4726	 * group without extending the csum block.
4727	 */
4728	spare_csum = howmany(sblock.fs_cssize, sizeof (struct csum)) -
4729	    sblock.fs_ncg;
4730	if (spare_csum > 0)
4731		growth_fs_frags += spare_csum * sblock.fs_fpg;
4732
4733	/*
4734	 * recalculate the new filesystem size in sectors, shorten it by
4735	 * the requested size `fssize_db' if necessary.
4736	 */
4737	if (growth_fs_frags > 0) {
4738		diskaddr_t sect;
4739		sect = (sblock.fs_size + growth_fs_frags) * sblock.fs_nspf;
4740		return ((sect > fssize_db) ? fssize_db : sect);
4741	}
4742
4743	return (0);
4744}
4745
4746void
4747extendsummaryinfo()
4748{
4749	int64_t		i;
4750	int		localtest	= test;
4751	int64_t		frags;
4752	daddr32_t		oldfrag;
4753	daddr32_t		newfrag;
4754
4755	/*
4756	 * if no-write (-N), don't bother
4757	 */
4758	if (Nflag)
4759		return;
4760
4761again:
4762	flcg();
4763	/*
4764	 * summary info did not change size -- do nothing unless in test mode
4765	 */
4766	if (grow_fs_cssize == sblock.fs_cssize)
4767		if (!localtest)
4768			return;
4769
4770	/*
4771	 * build list of frags needed for additional summary information
4772	 */
4773	oldfrag = howmany(grow_fs_cssize, sblock.fs_fsize) + grow_fs_csaddr;
4774	newfrag = howmany(sblock.fs_cssize, sblock.fs_fsize) + grow_fs_csaddr;
4775	/*
4776	 * add all of the frags that are required to grow the cyl summary to the
4777	 * csfrag list, which is the generic/unknown list, since at this point
4778	 * we don't yet know the state of those frags.
4779	 */
4780	for (i = oldfrag, frags = 0; i < newfrag; ++i, ++frags)
4781		addcsfrag((ino_t)0, (diskaddr_t)i, &csfrag);
4782	/*
4783	 * reduce the number of data blocks in the file system (fs_dsize) by
4784	 * the number of frags that need to be added to the cyl summary
4785	 */
4786	sblock.fs_dsize -= (newfrag - oldfrag);
4787
4788	/*
4789	 * In test mode, we move more data than necessary from
4790	 * cylinder group 0.  The lookup/allocate/move code can be
4791	 * better stressed without having to create HUGE file systems.
4792	 */
4793	if (localtest)
4794		for (i = newfrag; i < grow_sifrag; ++i) {
4795			if (frags >= testfrags)
4796				break;
4797			frags++;
4798			addcsfrag((ino_t)0, (diskaddr_t)i, &csfrag);
4799		}
4800
4801	/*
4802	 * move frags to free or inode lists, depending on owner
4803	 */
4804	findcsfragfree();
4805	findcsfragino();
4806
4807	/*
4808	 * if not all frags can be located, file system must be inconsistent
4809	 */
4810	if (csfrag) {
4811		isbad = 1;	/* should already be set, but make sure */
4812		lockexit(32);
4813	}
4814
4815	/*
4816	 * allocate the free frags. Note that the free frags must be allocated
4817	 * first otherwise they could be grabbed by alloccsfragino() for data
4818	 * frags.
4819	 */
4820	alloccsfragfree();
4821	/*
4822	 * allocate extra space for inode frags
4823	 */
4824	alloccsfragino();
4825
4826	/*
4827	 * not enough space
4828	 */
4829	if (notenoughspace()) {
4830		unalloccsfragfree();
4831		unalloccsfragino();
4832		if (localtest && !testforce) {
4833			localtest = 0;
4834			goto again;
4835		}
4836		(void) fprintf(stderr, gettext("Not enough free space\n"));
4837		lockexit(NOTENOUGHSPACE);
4838	}
4839
4840	/*
4841	 * copy the data from old frags to new frags
4842	 */
4843	copycsfragino();
4844
4845	/*
4846	 * fix the inodes to point to the new frags
4847	 */
4848	fixcsfragino();
4849
4850	/*
4851	 * We may have moved more frags than we needed.  Free them.
4852	 */
4853	rdcg((long)0);
4854	for (i = newfrag; i <= maxcsfrag; ++i)
4855		setbit(cg_blksfree(&acg), i-cgbase(&sblock, 0));
4856	wtcg();
4857
4858	flcg();
4859}
4860
4861/*
4862 * Check if all fragments in the `csfragino' list were reallocated.
4863 */
4864int
4865notenoughspace()
4866{
4867	struct csfrag	*cfp;
4868
4869	/*
4870	 * If any element in the csfragino array has a "new frag location"
4871	 * of 0, the allocfrags() function was unsuccessful in allocating
4872	 * space for moving the frag represented by this array element.
4873	 */
4874	for (cfp = csfragino; cfp; cfp = cfp->next)
4875		if (cfp->nfrag == 0)
4876			return (1);
4877	return (0);
4878}
4879
4880void
4881unalloccsfragino()
4882{
4883	struct csfrag	*cfp;
4884
4885	while ((cfp = csfragino) != NULL) {
4886		if (cfp->nfrag)
4887			freefrags(cfp->nfrag, cfp->frags, cfp->cylno);
4888		delcsfrag(cfp->ofrag, &csfragino);
4889	}
4890}
4891
4892void
4893unalloccsfragfree()
4894{
4895	struct csfrag	*cfp;
4896
4897	while ((cfp = csfragfree) != NULL) {
4898		freefrags(cfp->ofrag, cfp->frags, cfp->cylno);
4899		delcsfrag(cfp->ofrag, &csfragfree);
4900	}
4901}
4902
4903/*
4904 * For each frag in the "as-yet-unclassified" list (csfrag), see if
4905 * it's free (i.e., its bit is set in the free frag bit map).  If so,
4906 * move it from the "as-yet-unclassified" list to the csfragfree list.
4907 */
4908void
4909findcsfragfree()
4910{
4911	struct csfrag	*cfp;
4912	struct csfrag	*cfpnext;
4913
4914	/*
4915	 * move free frags onto the free-frag list
4916	 */
4917	rdcg((long)0);
4918	for (cfp = csfrag; cfp; cfp = cfpnext) {
4919		cfpnext = cfp->next;
4920		if (isset(cg_blksfree(&acg), cfp->ofrag - cgbase(&sblock, 0))) {
4921			addcsfrag(cfp->ino, cfp->ofrag, &csfragfree);
4922			delcsfrag(cfp->ofrag, &csfrag);
4923		}
4924	}
4925}
4926
4927void
4928copycsfragino()
4929{
4930	struct csfrag	*cfp;
4931	char		buf[MAXBSIZE];
4932
4933	/*
4934	 * copy data from old frags to newly allocated frags
4935	 */
4936	for (cfp = csfragino; cfp; cfp = cfp->next) {
4937		rdfs(fsbtodb(&sblock, (uint64_t)cfp->ofrag), (int)cfp->size,
4938		    buf);
4939		wtfs(fsbtodb(&sblock, (uint64_t)cfp->nfrag), (int)cfp->size,
4940		    buf);
4941	}
4942}
4943
4944long	curcylno	= -1;
4945int	cylnodirty	= 0;
4946
4947void
4948rdcg(long cylno)
4949{
4950	if (cylno != curcylno) {
4951		flcg();
4952		curcylno = cylno;
4953		rdfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, curcylno)),
4954		    (int)sblock.fs_cgsize, (char *)&acg);
4955	}
4956}
4957
4958void
4959flcg()
4960{
4961	if (cylnodirty) {
4962		if (debug && Pflag) {
4963			(void) fprintf(stderr,
4964			    "Assert: cylnodirty set in probe mode\n");
4965			return;
4966		}
4967		resetallocinfo();
4968		wtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, curcylno)),
4969		    (int)sblock.fs_cgsize, (char *)&acg);
4970		cylnodirty = 0;
4971	}
4972	curcylno = -1;
4973}
4974
4975void
4976wtcg()
4977{
4978	if (!Pflag) {
4979		/* probe mode should never write to disk */
4980		cylnodirty = 1;
4981	}
4982}
4983
4984void
4985allocfrags(long frags, daddr32_t *fragp, long *cylnop)
4986{
4987	int	 i;
4988	int	 j;
4989	long	 bits;
4990	long	 bit;
4991
4992	/*
4993	 * Allocate a free-frag range in an old cylinder group
4994	 */
4995	for (i = 0, *fragp = 0; i < grow_fs_ncg; ++i) {
4996		if (((fscs+i)->cs_nffree < frags) && ((fscs+i)->cs_nbfree == 0))
4997			continue;
4998		rdcg((long)i);
4999		bit = bits = 0;
5000		while (findfreerange(&bit, &bits)) {
5001			if (frags <= bits)  {
5002				for (j = 0; j < frags; ++j)
5003					clrbit(cg_blksfree(&acg), bit+j);
5004				wtcg();
5005				*cylnop = i;
5006				*fragp  = bit + cgbase(&sblock, i);
5007				return;
5008			}
5009			bit += bits;
5010		}
5011	}
5012}
5013
5014/*
5015 * Allocate space for frags that need to be moved in order to free up space for
5016 * expanding the cylinder summary info.
5017 * For each frag that needs to be moved (each frag or range of frags in
5018 * the csfragino list), allocate a new location and store the frag number
5019 * of that new location in the nfrag field of the csfrag struct.
5020 * If a new frag can't be allocated for any element in the csfragino list,
5021 * set the new frag number for that element to 0 and return immediately.
5022 * The notenoughspace() function will detect this condition.
5023 */
5024void
5025alloccsfragino()
5026{
5027	struct csfrag	*cfp;
5028
5029	/*
5030	 * allocate space for inode frag ranges
5031	 */
5032	for (cfp = csfragino; cfp; cfp = cfp->next) {
5033		allocfrags(cfp->frags, &cfp->nfrag, &cfp->cylno);
5034		if (cfp->nfrag == 0)
5035			break;
5036	}
5037}
5038
5039void
5040alloccsfragfree()
5041{
5042	struct csfrag	*cfp;
5043
5044	/*
5045	 * allocate the free frags needed for extended summary info
5046	 */
5047	rdcg((long)0);
5048
5049	for (cfp = csfragfree; cfp; cfp = cfp->next)
5050		clrbit(cg_blksfree(&acg), cfp->ofrag - cgbase(&sblock, 0));
5051
5052	wtcg();
5053}
5054
5055void
5056freefrags(daddr32_t frag, long frags, long cylno)
5057{
5058	int	i;
5059
5060	/*
5061	 * free frags
5062	 */
5063	rdcg(cylno);
5064	for (i = 0; i < frags; ++i) {
5065		setbit(cg_blksfree(&acg), (frag+i) - cgbase(&sblock, cylno));
5066	}
5067	wtcg();
5068}
5069
5070int
5071findfreerange(long *bitp, long *bitsp)
5072{
5073	long	 bit;
5074
5075	/*
5076	 * find a range of free bits in a cylinder group bit map
5077	 */
5078	for (bit = *bitp, *bitsp = 0; bit < acg.cg_ndblk; ++bit)
5079		if (isset(cg_blksfree(&acg), bit))
5080			break;
5081
5082	if (bit >= acg.cg_ndblk)
5083		return (0);
5084
5085	*bitp  = bit;
5086	*bitsp = 1;
5087	for (++bit; bit < acg.cg_ndblk; ++bit, ++(*bitsp)) {
5088		if ((bit % sblock.fs_frag) == 0)
5089			break;
5090		if (isclr(cg_blksfree(&acg), bit))
5091			break;
5092	}
5093	return (1);
5094}
5095
5096void
5097resetallocinfo()
5098{
5099	long	cno;
5100	long	bit;
5101	long	bits;
5102
5103	/*
5104	 * Compute the free blocks/frags info and update the appropriate
5105	 * inmemory superblock, summary info, and cylinder group fields
5106	 */
5107	sblock.fs_cstotal.cs_nffree -= acg.cg_cs.cs_nffree;
5108	sblock.fs_cstotal.cs_nbfree -= acg.cg_cs.cs_nbfree;
5109
5110	acg.cg_cs.cs_nffree = 0;
5111	acg.cg_cs.cs_nbfree = 0;
5112
5113	bzero((caddr_t)acg.cg_frsum, sizeof (acg.cg_frsum));
5114	bzero((caddr_t)cg_blktot(&acg), (int)(acg.cg_iusedoff-acg.cg_btotoff));
5115
5116	bit = bits = 0;
5117	while (findfreerange(&bit, &bits)) {
5118		if (bits == sblock.fs_frag) {
5119			acg.cg_cs.cs_nbfree++;
5120			cno = cbtocylno(&sblock, bit);
5121			cg_blktot(&acg)[cno]++;
5122			cg_blks(&sblock, &acg, cno)[cbtorpos(&sblock, bit)]++;
5123		} else {
5124			acg.cg_cs.cs_nffree += bits;
5125			acg.cg_frsum[bits]++;
5126		}
5127		bit += bits;
5128	}
5129
5130	*(fscs + acg.cg_cgx) = acg.cg_cs;
5131
5132	sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree;
5133	sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree;
5134}
5135
5136void
5137extendcg(long cylno)
5138{
5139	int	i;
5140	diskaddr_t	dupper;
5141	diskaddr_t	cbase;
5142	diskaddr_t	dmax;
5143
5144	/*
5145	 * extend the cylinder group at the end of the old file system
5146	 * if it was partially allocated becase of lack of space
5147	 */
5148	flcg();
5149	rdcg(cylno);
5150
5151	dupper = acg.cg_ndblk;
5152	if (cylno == sblock.fs_ncg - 1)
5153		acg.cg_ncyl = sblock.fs_ncyl - (sblock.fs_cpg * cylno);
5154	else
5155		acg.cg_ncyl = sblock.fs_cpg;
5156	cbase = cgbase(&sblock, cylno);
5157	dmax = cbase + sblock.fs_fpg;
5158	if (dmax > sblock.fs_size)
5159		dmax = sblock.fs_size;
5160	acg.cg_ndblk = dmax - cbase;
5161
5162	for (i = dupper; i < acg.cg_ndblk; ++i)
5163		setbit(cg_blksfree(&acg), i);
5164
5165	sblock.fs_dsize += (acg.cg_ndblk - dupper);
5166
5167	wtcg();
5168	flcg();
5169}
5170
5171struct lockfs	lockfs;
5172int		lockfd;
5173int		islocked;
5174int		lockfskey;
5175char		lockfscomment[128];
5176
5177void
5178ulockfs()
5179{
5180	/*
5181	 * if the file system was locked, unlock it before exiting
5182	 */
5183	if (islocked == 0)
5184		return;
5185
5186	/*
5187	 * first, check if the lock held
5188	 */
5189	lockfs.lf_flags = LOCKFS_MOD;
5190	if (ioctl(lockfd, _FIOLFSS, &lockfs) == -1) {
5191		perror(directory);
5192		lockexit(32);
5193	}
5194
5195	if (LOCKFS_IS_MOD(&lockfs)) {
5196		(void) fprintf(stderr,
5197		    gettext("FILE SYSTEM CHANGED DURING GROWFS!\n"));
5198		(void) fprintf(stderr,
5199		    gettext("   See lockfs(1), umount(1), and fsck(1)\n"));
5200		lockexit(32);
5201	}
5202	/*
5203	 * unlock the file system
5204	 */
5205	lockfs.lf_lock  = LOCKFS_ULOCK;
5206	lockfs.lf_flags = 0;
5207	lockfs.lf_key   = lockfskey;
5208	clockfs();
5209	if (ioctl(lockfd, _FIOLFS, &lockfs) == -1) {
5210		perror(directory);
5211		lockexit(32);
5212	}
5213}
5214
5215void
5216wlockfs()
5217{
5218
5219	/*
5220	 * if no-write (-N), don't bother
5221	 */
5222	if (Nflag)
5223		return;
5224	/*
5225	 * open the mountpoint, and write lock the file system
5226	 */
5227	if ((lockfd = open64(directory, O_RDONLY)) == -1) {
5228		perror(directory);
5229		lockexit(32);
5230	}
5231
5232	/*
5233	 * check if it is already locked
5234	 */
5235	if (ioctl(lockfd, _FIOLFSS, &lockfs) == -1) {
5236		perror(directory);
5237		lockexit(32);
5238	}
5239
5240	if (lockfs.lf_lock != LOCKFS_WLOCK) {
5241		lockfs.lf_lock  = LOCKFS_WLOCK;
5242		lockfs.lf_flags = 0;
5243		lockfs.lf_key   = 0;
5244		clockfs();
5245		if (ioctl(lockfd, _FIOLFS, &lockfs) == -1) {
5246			perror(directory);
5247			lockexit(32);
5248		}
5249	}
5250	islocked = 1;
5251	lockfskey = lockfs.lf_key;
5252}
5253
5254void
5255clockfs()
5256{
5257	time_t	t;
5258	char	*ct;
5259
5260	(void) time(&t);
5261	ct = ctime(&t);
5262	ct[strlen(ct)-1] = '\0';
5263
5264	(void) sprintf(lockfscomment, "%s -- mkfs pid %d", ct, getpid());
5265	lockfs.lf_comlen  = strlen(lockfscomment)+1;
5266	lockfs.lf_comment = lockfscomment;
5267}
5268
5269/*
5270 * Write the csum records and the superblock
5271 */
5272void
5273wtsb()
5274{
5275	long	i;
5276
5277	/*
5278	 * write summary information
5279	 */
5280	for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize)
5281		wtfs(fsbtodb(&sblock, (uint64_t)(sblock.fs_csaddr +
5282		    numfrags(&sblock, i))),
5283		    (int)(sblock.fs_cssize - i < sblock.fs_bsize ?
5284		    sblock.fs_cssize - i : sblock.fs_bsize),
5285		    ((char *)fscs) + i);
5286
5287	/*
5288	 * write superblock
5289	 */
5290	sblock.fs_time = mkfstime;
5291	wtfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
5292}
5293
5294/*
5295 * Verify that the optimization selection is reasonable, and advance
5296 * the global "string" appropriately.
5297 */
5298static char
5299checkopt(char *optim)
5300{
5301	char	opt;
5302	int	limit = strcspn(optim, ",");
5303
5304	switch (limit) {
5305	case 0:	/* missing indicator (have comma or nul) */
5306		(void) fprintf(stderr, gettext(
5307		    "mkfs: missing optimization flag reset to `t' (time)\n"));
5308		opt = 't';
5309		break;
5310
5311	case 1: /* single-character indicator */
5312		opt = *optim;
5313		if ((opt != 's') && (opt != 't')) {
5314			(void) fprintf(stderr, gettext(
5315		    "mkfs: bad optimization value `%c' reset to `t' (time)\n"),
5316			    opt);
5317			opt = 't';
5318		}
5319		break;
5320
5321	default: /* multi-character indicator */
5322		(void) fprintf(stderr, gettext(
5323	    "mkfs: bad optimization value `%*.*s' reset to `t' (time)\n"),
5324		    limit, limit, optim);
5325		opt = 't';
5326		break;
5327	}
5328
5329	string += limit;
5330
5331	return (opt);
5332}
5333
5334/*
5335 * Verify that the mtb selection is reasonable, and advance
5336 * the global "string" appropriately.
5337 */
5338static char
5339checkmtb(char *mtbarg)
5340{
5341	char	mtbc;
5342	int	limit = strcspn(mtbarg, ",");
5343
5344	switch (limit) {
5345	case 0:	/* missing indicator (have comma or nul) */
5346		(void) fprintf(stderr, gettext(
5347		    "mkfs: missing mtb flag reset to `n' (no mtb support)\n"));
5348		mtbc = 'n';
5349		break;
5350
5351	case 1: /* single-character indicator */
5352		mtbc = tolower(*mtbarg);
5353		if ((mtbc != 'y') && (mtbc != 'n')) {
5354			(void) fprintf(stderr, gettext(
5355		    "mkfs: bad mtb value `%c' reset to `n' (no mtb support)\n"),
5356			    mtbc);
5357			mtbc = 'n';
5358		}
5359		break;
5360
5361	default: /* multi-character indicator */
5362		(void) fprintf(stderr, gettext(
5363	    "mkfs: bad mtb value `%*.*s' reset to `n' (no mtb support)\n"),
5364		    limit, limit, mtbarg);
5365		opt = 'n';
5366		break;
5367	}
5368
5369	string += limit;
5370
5371	return (mtbc);
5372}
5373
5374/*
5375 * Verify that a value is in a range.  If it is not, resets it to
5376 * its default value if one is supplied, exits otherwise.
5377 *
5378 * When testing, can compare user_supplied to RC_KEYWORD or RC_POSITIONAL.
5379 */
5380static void
5381range_check(long *varp, char *name, long minimum, long maximum,
5382    long def_val, int user_supplied)
5383{
5384	dprintf(("DeBuG %s : %ld (%ld %ld %ld)\n",
5385	    name, *varp, minimum, maximum, def_val));
5386
5387	if ((*varp < minimum) || (*varp > maximum)) {
5388		if (user_supplied != RC_DEFAULT) {
5389			(void) fprintf(stderr, gettext(
5390	    "mkfs: bad value for %s: %ld must be between %ld and %ld\n"),
5391			    name, *varp, minimum, maximum);
5392		}
5393		if (def_val != NO_DEFAULT) {
5394			if (user_supplied) {
5395				(void) fprintf(stderr,
5396				    gettext("mkfs: %s reset to default %ld\n"),
5397				    name, def_val);
5398			}
5399			*varp = def_val;
5400			dprintf(("DeBuG %s : %ld\n", name, *varp));
5401			return;
5402		}
5403		lockexit(2);
5404		/*NOTREACHED*/
5405	}
5406}
5407
5408/*
5409 * Verify that a value is in a range.  If it is not, resets it to
5410 * its default value if one is supplied, exits otherwise.
5411 *
5412 * When testing, can compare user_supplied to RC_KEYWORD or RC_POSITIONAL.
5413 */
5414static void
5415range_check_64(uint64_t *varp, char *name, uint64_t minimum, uint64_t maximum,
5416    uint64_t def_val, int user_supplied)
5417{
5418	if ((*varp < minimum) || (*varp > maximum)) {
5419		if (user_supplied != RC_DEFAULT) {
5420			(void) fprintf(stderr, gettext(
5421	    "mkfs: bad value for %s: %lld must be between %lld and %lld\n"),
5422			    name, *varp, minimum, maximum);
5423		}
5424		if (def_val != NO_DEFAULT) {
5425			if (user_supplied) {
5426				(void) fprintf(stderr,
5427				    gettext("mkfs: %s reset to default %lld\n"),
5428				    name, def_val);
5429			}
5430			*varp = def_val;
5431			return;
5432		}
5433		lockexit(2);
5434		/*NOTREACHED*/
5435	}
5436}
5437
5438/*
5439 * Blocks SIGINT from delivery.  Returns the previous mask in the
5440 * buffer provided, so that mask may be later restored.
5441 */
5442static void
5443block_sigint(sigset_t *old_mask)
5444{
5445	sigset_t block_mask;
5446
5447	if (sigemptyset(&block_mask) < 0) {
5448		fprintf(stderr, gettext("Could not clear signal mask\n"));
5449		lockexit(3);
5450	}
5451	if (sigaddset(&block_mask, SIGINT) < 0) {
5452		fprintf(stderr, gettext("Could not set signal mask\n"));
5453		lockexit(3);
5454	}
5455	if (sigprocmask(SIG_BLOCK, &block_mask, old_mask) < 0) {
5456		fprintf(stderr, gettext("Could not block SIGINT\n"));
5457		lockexit(3);
5458	}
5459}
5460
5461/*
5462 * Restores the signal mask that was in force before a call
5463 * to block_sigint().  This may actually still have SIGINT blocked,
5464 * if we've been recursively invoked.
5465 */
5466static void
5467unblock_sigint(sigset_t *old_mask)
5468{
5469	if (sigprocmask(SIG_UNBLOCK, old_mask, (sigset_t *)NULL) < 0) {
5470		fprintf(stderr, gettext("Could not restore signal mask\n"));
5471		lockexit(3);
5472	}
5473}
5474
5475/*
5476 * Attempt to be somewhat graceful about being interrupted, rather than
5477 * just silently leaving the filesystem in an unusable state.
5478 *
5479 * The kernel has blocked SIGINT upon entry, so we don't have to worry
5480 * about recursion if the user starts pounding on the keyboard.
5481 */
5482static void
5483recover_from_sigint(int signum)
5484{
5485	if (fso > -1) {
5486		if ((Nflag != 0) || confirm_abort()) {
5487			lockexit(4);
5488		}
5489	}
5490}
5491
5492static int
5493confirm_abort(void)
5494{
5495	char line[80];
5496
5497	printf(gettext("\n\nAborting at this point will leave the filesystem "
5498	    "in an inconsistent\nstate.  If you do choose to stop, "
5499	    "you will be given instructions on how to\nrecover "
5500	    "the filesystem.  Do you wish to cancel the filesystem "
5501	    "grow\noperation (y/n)?"));
5502	if (getaline(stdin, line, sizeof (line)) == EOF)
5503		line[0] = 'y';
5504
5505	printf("\n");
5506	if (line[0] == 'y' || line[0] == 'Y')
5507		return (1);
5508	else {
5509		return (0);
5510	}
5511}
5512
5513static int
5514getaline(FILE *fp, char *loc, int maxlen)
5515{
5516	int n;
5517	char *p, *lastloc;
5518
5519	p = loc;
5520	lastloc = &p[maxlen-1];
5521	while ((n = getc(fp)) != '\n') {
5522		if (n == EOF)
5523			return (EOF);
5524		if (!isspace(n) && p < lastloc)
5525			*p++ = n;
5526	}
5527	*p = 0;
5528	return (p - loc);
5529}
5530
5531/*
5532 * Calculate the maximum value of cylinders-per-group for a file
5533 * system with the characteristics:
5534 *
5535 *	bsize - file system block size
5536 *	fragsize - frag size
5537 *	nbpi - number of bytes of disk space per inode
5538 *	nrpos - number of rotational positions
5539 *	spc - sectors per cylinder
5540 *
5541 * These five characteristic are not adjustable (by this function).
5542 * The only attribute of the file system which IS adjusted by this
5543 * function in order to maximize cylinders-per-group is the proportion
5544 * of the cylinder group overhead block used for the inode map.  The
5545 * inode map cannot occupy more than one-third of the cylinder group
5546 * overhead block, but it's OK for it to occupy less than one-third
5547 * of the overhead block.
5548 *
5549 * The setting of nbpi determines one possible value for the maximum
5550 * size of a cylinder group.  It does so because it determines the total
5551 * number of inodes in the file system (file system size is fixed, and
5552 * nbpi is fixed, so the total number of inodes is fixed too).  The
5553 * cylinder group has to be small enough so that the number of inodes
5554 * in the cylinder group is less than or equal to the number of bits
5555 * in one-third (or whatever proportion is assumed) of a file system
5556 * block.  The details of the calculation are:
5557 *
5558 *     The macro MAXIpG_B(bsize, inode_divisor) determines the maximum
5559 *     number of inodes that can be in a cylinder group, given the
5560 *     proportion of the cylinder group overhead block used for the
5561 *     inode bitmaps (an inode_divisor of 3 means that 1/3 of the
5562 *     block is used for inode bitmaps; an inode_divisor of 12 means
5563 *     that 1/12 of the block is used for inode bitmaps.)
5564 *
5565 *     Once the number of inodes per cylinder group is known, the
5566 *     maximum value of cylinders-per-group (determined by nbpi)
5567 *     is calculated by the formula
5568 *
5569 *     maxcpg_given_nbpi = (size of a cylinder group)/(size of a cylinder)
5570 *
5571 *			 = (inodes-per-cg * nbpi)/(spc * DEV_BSIZE)
5572 *
5573 *     (Interestingly, the size of the file system never enters
5574 *     into this calculation.)
5575 *
5576 * Another possible value for the maximum cylinder group size is determined
5577 * by frag_size and nrpos.  The frags in the cylinder group must be
5578 * representable in the frag bitmaps in the cylinder overhead block and the
5579 * rotational positions for each cylinder must be represented in the
5580 * rotational position tables.  The calculation of the maximum cpg
5581 * value, given the frag and nrpos vales, is:
5582 *
5583 *     maxcpg_given_fragsize =
5584 *	  (available space in the overhead block) / (size of per-cylinder data)
5585 *
5586 *     The available space in the overhead block =
5587 *	  bsize - sizeof (struct cg) - space_used_for_inode_bitmaps
5588 *
5589 *     The size of the per-cylinder data is:
5590 *	    sizeof(long)            # for the "blocks avail per cylinder" field
5591 *	    + nrpos * sizeof(short)   # for the rotational position table entry
5592 *	    + frags-per-cylinder/NBBY # number of bytes to represent this
5593 *				      # cylinder in the frag bitmap
5594 *
5595 * The two calculated maximum values of cylinder-per-group will typically
5596 * turn out to be different, since they are derived from two different
5597 * constraints.  Usually, maxcpg_given_nbpi is much bigger than
5598 * maxcpg_given_fragsize.  But they can be brought together by
5599 * adjusting the proportion of the overhead block dedicated to
5600 * the inode bitmaps.  Decreasing the proportion of the cylinder
5601 * group overhead block used for inode maps will decrease
5602 * maxcpg_given_nbpi and increase maxcpg_given_fragsize.
5603 *
5604 * This function calculates the initial values of maxcpg_given_nbpi
5605 * and maxcpg_given_fragsize assuming that 1/3 of the cg overhead
5606 * block is used for inode bitmaps.  Then it decreases the proportion
5607 * of the cg overhead block used for inode bitmaps (by increasing
5608 * the value of inode_divisor) until maxcpg_given_nbpi and
5609 * maxcpg_given_fragsize are the same, or stop changing, or
5610 * maxcpg_given_nbpi is less than maxcpg_given_fragsize.
5611 *
5612 * The loop terminates when any of the following occur:
5613 *	* maxcpg_given_fragsize is greater than or equal to
5614 *	  maxcpg_given_nbpi
5615 *	* neither maxcpg_given_fragsize nor maxcpg_given_nbpi
5616 *	  change in the expected direction
5617 *
5618 * The loop is guaranteed to terminate because it only continues
5619 * while maxcpg_given_fragsize and maxcpg_given_nbpi are approaching
5620 * each other.  As soon they cross each other, or neither one changes
5621 * in the direction of the other, or one of them moves in the wrong
5622 * direction, the loop completes.
5623 */
5624
5625static long
5626compute_maxcpg(long bsize, long fragsize, long nbpi, long nrpos, long spc)
5627{
5628	int	maxcpg_given_nbpi;	/* in cylinders */
5629	int	maxcpg_given_fragsize;	/* in cylinders */
5630	int	spf;			/* sectors per frag */
5631	int	inode_divisor;
5632	int	old_max_given_frag = 0;
5633	int	old_max_given_nbpi = INT_MAX;
5634
5635	spf = fragsize / DEV_BSIZE;
5636	inode_divisor = 3;
5637
5638	while (1) {
5639		maxcpg_given_nbpi =
5640		    (((int64_t)(MAXIpG_B(bsize, inode_divisor))) * nbpi) /
5641		    (DEV_BSIZE * ((int64_t)spc));
5642		maxcpg_given_fragsize =
5643		    (bsize - (sizeof (struct cg)) - (bsize / inode_divisor)) /
5644		    (sizeof (long) + nrpos * sizeof (short) +
5645		    (spc / spf) / NBBY);
5646
5647		if (maxcpg_given_fragsize >= maxcpg_given_nbpi)
5648			return (maxcpg_given_nbpi);
5649
5650		/*
5651		 * If neither value moves toward the other, return the
5652		 * least of the old values (we use the old instead of the
5653		 * new because: if the old is the same as the new, it
5654		 * doesn't matter which ones we use.  If one of the
5655		 * values changed, but in the wrong direction, the
5656		 * new values are suspect.  Better use the old.  This
5657		 * shouldn't happen, but it's best to check.
5658		 */
5659
5660		if (!(maxcpg_given_nbpi < old_max_given_nbpi) &&
5661		    !(maxcpg_given_fragsize > old_max_given_frag))
5662			return (MIN(old_max_given_nbpi, old_max_given_frag));
5663
5664		/*
5665		 * This is probably impossible, but if one of the maxcpg
5666		 * values moved in the "right" direction and one moved
5667		 * in the "wrong" direction (that is, the two values moved
5668		 * in the same direction), the previous conditional won't
5669		 * recognize that the values aren't converging (since at
5670		 * least one value moved in the "right" direction, the
5671		 * last conditional says "keep going").
5672		 *
5673		 * Just to make absolutely certain that the loop terminates,
5674		 * check for one of the values moving in the "wrong" direction
5675		 * and terminate the loop if it happens.
5676		 */
5677
5678		if (maxcpg_given_nbpi > old_max_given_nbpi ||
5679		    maxcpg_given_fragsize < old_max_given_frag)
5680			return (MIN(old_max_given_nbpi, old_max_given_frag));
5681
5682		old_max_given_nbpi = maxcpg_given_nbpi;
5683		old_max_given_frag = maxcpg_given_fragsize;
5684
5685		inode_divisor++;
5686	}
5687}
5688
5689static int
5690in_64bit_mode(void)
5691{
5692	/*  cmd must be an absolute path, for security */
5693	char *cmd = "/usr/bin/isainfo -b";
5694	char buf[BUFSIZ];
5695	FILE *ptr;
5696	int retval = 0;
5697
5698	putenv("IFS= \t");
5699	if ((ptr = popen(cmd, "r")) != NULL) {
5700		if (fgets(buf, BUFSIZ, ptr) != NULL &&
5701		    strncmp(buf, "64", 2) == 0)
5702			retval = 1;
5703		(void) pclose(ptr);
5704	}
5705	return (retval);
5706}
5707
5708/*
5709 * validate_size
5710 *
5711 * Return 1 if the device appears to be at least "size" sectors long.
5712 * Return 0 if it's shorter or we can't read it.
5713 */
5714
5715static int
5716validate_size(int fd, diskaddr_t size)
5717{
5718	char	buf[DEV_BSIZE];
5719	int rc;
5720
5721	if ((llseek(fd, (offset_t)((size - 1) * DEV_BSIZE), SEEK_SET) == -1) ||
5722	    (read(fd, buf, DEV_BSIZE)) != DEV_BSIZE)
5723		rc = 0;
5724	else
5725		rc = 1;
5726	return (rc);
5727}
5728
5729/*
5730 * Print every field of the calculated superblock, along with
5731 * its value.  To make parsing easier on the caller, the value
5732 * is printed first, then the name.  Additionally, there's only
5733 * one name/value pair per line.  All values are reported in
5734 * hexadecimal (with the traditional 0x prefix), as that's slightly
5735 * easier for humans to read.  Not that they're expected to, but
5736 * debugging happens.
5737 */
5738static void
5739dump_sblock(void)
5740{
5741	int row, column, pending, written;
5742	caddr_t source;
5743
5744	if (Rflag) {
5745		pending = sizeof (sblock);
5746		source = (caddr_t)&sblock;
5747		do {
5748			written = write(fileno(stdout), source, pending);
5749			pending -= written;
5750			source += written;
5751		} while ((pending > 0) && (written > 0));
5752
5753		if (written < 0) {
5754			perror(gettext("Binary dump of superblock failed"));
5755			lockexit(1);
5756		}
5757		return;
5758	} else {
5759		printf("0x%x sblock.fs_link\n", sblock.fs_link);
5760		printf("0x%x sblock.fs_rolled\n", sblock.fs_rolled);
5761		printf("0x%x sblock.fs_sblkno\n", sblock.fs_sblkno);
5762		printf("0x%x sblock.fs_cblkno\n", sblock.fs_cblkno);
5763		printf("0x%x sblock.fs_iblkno\n", sblock.fs_iblkno);
5764		printf("0x%x sblock.fs_dblkno\n", sblock.fs_dblkno);
5765		printf("0x%x sblock.fs_cgoffset\n", sblock.fs_cgoffset);
5766		printf("0x%x sblock.fs_cgmask\n", sblock.fs_cgmask);
5767		printf("0x%x sblock.fs_time\n", sblock.fs_time);
5768		printf("0x%x sblock.fs_size\n", sblock.fs_size);
5769		printf("0x%x sblock.fs_dsize\n", sblock.fs_dsize);
5770		printf("0x%x sblock.fs_ncg\n", sblock.fs_ncg);
5771		printf("0x%x sblock.fs_bsize\n", sblock.fs_bsize);
5772		printf("0x%x sblock.fs_fsize\n", sblock.fs_fsize);
5773		printf("0x%x sblock.fs_frag\n", sblock.fs_frag);
5774		printf("0x%x sblock.fs_minfree\n", sblock.fs_minfree);
5775		printf("0x%x sblock.fs_rotdelay\n", sblock.fs_rotdelay);
5776		printf("0x%x sblock.fs_rps\n", sblock.fs_rps);
5777		printf("0x%x sblock.fs_bmask\n", sblock.fs_bmask);
5778		printf("0x%x sblock.fs_fmask\n", sblock.fs_fmask);
5779		printf("0x%x sblock.fs_bshift\n", sblock.fs_bshift);
5780		printf("0x%x sblock.fs_fshift\n", sblock.fs_fshift);
5781		printf("0x%x sblock.fs_maxcontig\n", sblock.fs_maxcontig);
5782		printf("0x%x sblock.fs_maxbpg\n", sblock.fs_maxbpg);
5783		printf("0x%x sblock.fs_fragshift\n", sblock.fs_fragshift);
5784		printf("0x%x sblock.fs_fsbtodb\n", sblock.fs_fsbtodb);
5785		printf("0x%x sblock.fs_sbsize\n", sblock.fs_sbsize);
5786		printf("0x%x sblock.fs_csmask\n", sblock.fs_csmask);
5787		printf("0x%x sblock.fs_csshift\n", sblock.fs_csshift);
5788		printf("0x%x sblock.fs_nindir\n", sblock.fs_nindir);
5789		printf("0x%x sblock.fs_inopb\n", sblock.fs_inopb);
5790		printf("0x%x sblock.fs_nspf\n", sblock.fs_nspf);
5791		printf("0x%x sblock.fs_optim\n", sblock.fs_optim);
5792#ifdef _LITTLE_ENDIAN
5793		printf("0x%x sblock.fs_state\n", sblock.fs_state);
5794#else
5795		printf("0x%x sblock.fs_npsect\n", sblock.fs_npsect);
5796#endif
5797		printf("0x%x sblock.fs_si\n", sblock.fs_si);
5798		printf("0x%x sblock.fs_trackskew\n", sblock.fs_trackskew);
5799		printf("0x%x sblock.fs_id[0]\n", sblock.fs_id[0]);
5800		printf("0x%x sblock.fs_id[1]\n", sblock.fs_id[1]);
5801		printf("0x%x sblock.fs_csaddr\n", sblock.fs_csaddr);
5802		printf("0x%x sblock.fs_cssize\n", sblock.fs_cssize);
5803		printf("0x%x sblock.fs_cgsize\n", sblock.fs_cgsize);
5804		printf("0x%x sblock.fs_ntrak\n", sblock.fs_ntrak);
5805		printf("0x%x sblock.fs_nsect\n", sblock.fs_nsect);
5806		printf("0x%x sblock.fs_spc\n", sblock.fs_spc);
5807		printf("0x%x sblock.fs_ncyl\n", sblock.fs_ncyl);
5808		printf("0x%x sblock.fs_cpg\n", sblock.fs_cpg);
5809		printf("0x%x sblock.fs_ipg\n", sblock.fs_ipg);
5810		printf("0x%x sblock.fs_fpg\n", sblock.fs_fpg);
5811		printf("0x%x sblock.fs_cstotal\n", sblock.fs_cstotal);
5812		printf("0x%x sblock.fs_fmod\n", sblock.fs_fmod);
5813		printf("0x%x sblock.fs_clean\n", sblock.fs_clean);
5814		printf("0x%x sblock.fs_ronly\n", sblock.fs_ronly);
5815		printf("0x%x sblock.fs_flags\n", sblock.fs_flags);
5816		printf("0x%x sblock.fs_fsmnt\n", sblock.fs_fsmnt);
5817		printf("0x%x sblock.fs_cgrotor\n", sblock.fs_cgrotor);
5818		printf("0x%x sblock.fs_u.fs_csp\n", sblock.fs_u.fs_csp);
5819		printf("0x%x sblock.fs_cpc\n", sblock.fs_cpc);
5820
5821		/*
5822		 * No macros are defined for the dimensions of the
5823		 * opostbl array.
5824		 */
5825		for (row = 0; row < 16; row++) {
5826			for (column = 0; column < 8; column++) {
5827				printf("0x%x sblock.fs_opostbl[%d][%d]\n",
5828				    sblock.fs_opostbl[row][column],
5829				    row, column);
5830			}
5831		}
5832
5833		/*
5834		 * Ditto the size of sparecon.
5835		 */
5836		for (row = 0; row < 51; row++) {
5837			printf("0x%x sblock.fs_sparecon[%d]\n",
5838			    sblock.fs_sparecon[row], row);
5839		}
5840
5841		printf("0x%x sblock.fs_version\n", sblock.fs_version);
5842		printf("0x%x sblock.fs_logbno\n", sblock.fs_logbno);
5843		printf("0x%x sblock.fs_reclaim\n", sblock.fs_reclaim);
5844		printf("0x%x sblock.fs_sparecon2\n", sblock.fs_sparecon2);
5845#ifdef _LITTLE_ENDIAN
5846		printf("0x%x sblock.fs_npsect\n", sblock.fs_npsect);
5847#else
5848		printf("0x%x sblock.fs_state\n", sblock.fs_state);
5849#endif
5850		printf("0x%llx sblock.fs_qbmask\n", sblock.fs_qbmask);
5851		printf("0x%llx sblock.fs_qfmask\n", sblock.fs_qfmask);
5852		printf("0x%x sblock.fs_postblformat\n", sblock.fs_postblformat);
5853		printf("0x%x sblock.fs_nrpos\n", sblock.fs_nrpos);
5854		printf("0x%x sblock.fs_postbloff\n", sblock.fs_postbloff);
5855		printf("0x%x sblock.fs_rotbloff\n", sblock.fs_rotbloff);
5856		printf("0x%x sblock.fs_magic\n", sblock.fs_magic);
5857
5858		/*
5859		 * fs_space isn't of much use in this context, so we'll
5860		 * just ignore it for now.
5861		 */
5862	}
5863}
5864