xref: /netbsd/sbin/newfs_ext2fs/newfs_ext2fs.c (revision 8b0f9554)
1*8b0f9554Sperry /*	$NetBSD: newfs_ext2fs.c,v 1.3 2007/12/15 19:44:47 perry Exp $	*/
2f8b02b9cStsutsui 
3f8b02b9cStsutsui /*
4f8b02b9cStsutsui  * Copyright (c) 1983, 1989, 1993, 1994
5f8b02b9cStsutsui  *	The Regents of the University of California.  All rights reserved.
6f8b02b9cStsutsui  *
7f8b02b9cStsutsui  * Redistribution and use in source and binary forms, with or without
8f8b02b9cStsutsui  * modification, are permitted provided that the following conditions
9f8b02b9cStsutsui  * are met:
10f8b02b9cStsutsui  * 1. Redistributions of source code must retain the above copyright
11f8b02b9cStsutsui  *    notice, this list of conditions and the following disclaimer.
12f8b02b9cStsutsui  * 2. Redistributions in binary form must reproduce the above copyright
13f8b02b9cStsutsui  *    notice, this list of conditions and the following disclaimer in the
14f8b02b9cStsutsui  *    documentation and/or other materials provided with the distribution.
15f8b02b9cStsutsui  * 3. Neither the name of the University nor the names of its contributors
16f8b02b9cStsutsui  *    may be used to endorse or promote products derived from this software
17f8b02b9cStsutsui  *    without specific prior written permission.
18f8b02b9cStsutsui  *
19f8b02b9cStsutsui  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20f8b02b9cStsutsui  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21f8b02b9cStsutsui  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22f8b02b9cStsutsui  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23f8b02b9cStsutsui  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24f8b02b9cStsutsui  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25f8b02b9cStsutsui  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26f8b02b9cStsutsui  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27f8b02b9cStsutsui  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28f8b02b9cStsutsui  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29f8b02b9cStsutsui  * SUCH DAMAGE.
30f8b02b9cStsutsui  */
31f8b02b9cStsutsui 
32f8b02b9cStsutsui #include <sys/cdefs.h>
33f8b02b9cStsutsui #ifndef lint
34f8b02b9cStsutsui __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1993, 1994\n\
35f8b02b9cStsutsui 	The Regents of the University of California.  All rights reserved.\n");
36f8b02b9cStsutsui #endif /* not lint */
37f8b02b9cStsutsui 
38f8b02b9cStsutsui #ifndef lint
39f8b02b9cStsutsui #if 0
40f8b02b9cStsutsui static char sccsid[] = "@(#)newfs.c	8.13 (Berkeley) 5/1/95";
41f8b02b9cStsutsui #else
42*8b0f9554Sperry __RCSID("$NetBSD: newfs_ext2fs.c,v 1.3 2007/12/15 19:44:47 perry Exp $");
43f8b02b9cStsutsui #endif
44f8b02b9cStsutsui #endif /* not lint */
45f8b02b9cStsutsui 
46f8b02b9cStsutsui /*
47f8b02b9cStsutsui  * newfs: friendly front end to mke2fs
48f8b02b9cStsutsui  */
49f8b02b9cStsutsui #include <sys/param.h>
50f8b02b9cStsutsui #include <sys/ioctl.h>
51f8b02b9cStsutsui #include <sys/disklabel.h>
52f8b02b9cStsutsui #include <sys/disk.h>
53f8b02b9cStsutsui #include <sys/file.h>
54f8b02b9cStsutsui #include <sys/mount.h>
55f8b02b9cStsutsui 
56f8b02b9cStsutsui #include <ufs/ext2fs/ext2fs.h>
57f8b02b9cStsutsui 
58f8b02b9cStsutsui #include <disktab.h>
59f8b02b9cStsutsui #include <err.h>
60f8b02b9cStsutsui #include <errno.h>
61f8b02b9cStsutsui #include <limits.h>
62f8b02b9cStsutsui #include <paths.h>
63f8b02b9cStsutsui #include <stdio.h>
64f8b02b9cStsutsui #include <stdlib.h>
65f8b02b9cStsutsui #include <string.h>
66f8b02b9cStsutsui #include <unistd.h>
67f8b02b9cStsutsui #include <util.h>
68f8b02b9cStsutsui #include <mntopts.h>
69f8b02b9cStsutsui 
70f8b02b9cStsutsui #include "extern.h"
71f8b02b9cStsutsui #include "partutil.h"
72f8b02b9cStsutsui 
73f8b02b9cStsutsui static int64_t strsuftoi64(const char *, const char *, int64_t, int64_t, int *);
74*8b0f9554Sperry static void usage(void) __dead;
75f8b02b9cStsutsui 
76f8b02b9cStsutsui /*
77f8b02b9cStsutsui  * For file systems smaller than SMALL_FSSIZE we use the S_DFL_* defaults,
78f8b02b9cStsutsui  * otherwise if less than MEDIUM_FSSIZE use M_DFL_*, otherwise use
79f8b02b9cStsutsui  * L_DFL_*.
80f8b02b9cStsutsui  */
81f8b02b9cStsutsui #define SMALL_FSSIZE	((4 * 1024 * 1024) / sectorsize)	/* 4MB */
82f8b02b9cStsutsui #define S_DFL_BSIZE	1024
83f8b02b9cStsutsui #define MEDIUM_FSSIZE	((512 * 1024 * 1024) / sectorsize)	/* 512MB */
84f8b02b9cStsutsui #define M_DFL_BSIZE	1024
85f8b02b9cStsutsui #define L_DFL_BSIZE	4096
86f8b02b9cStsutsui 
87f8b02b9cStsutsui /*
88f8b02b9cStsutsui  * Each file system has a number of inodes statically allocated.
89f8b02b9cStsutsui  * We allocate one inode slot per 2, 4, or 8 blocks, expecting this
90f8b02b9cStsutsui  * to be far more than we will ever need.
91f8b02b9cStsutsui  */
92f8b02b9cStsutsui #define S_DFL_NINODE(blocks)	((blocks) / 8)
93f8b02b9cStsutsui #define M_DFL_NINODE(blocks)	((blocks) / 4)
94f8b02b9cStsutsui #define L_DFL_NINODE(blocks)	((blocks) / 2)
95f8b02b9cStsutsui 
96f8b02b9cStsutsui /*
97f8b02b9cStsutsui  * Default sector size.
98f8b02b9cStsutsui  */
99f8b02b9cStsutsui #define	DFL_SECSIZE	512
100f8b02b9cStsutsui 
101f8b02b9cStsutsui int	Nflag;			/* run without writing file system */
102f8b02b9cStsutsui int	Oflag = 0;		/* format as conservative REV0 by default */
103f8b02b9cStsutsui int	verbosity;		/* amount of printf() output */
104f8b02b9cStsutsui #define DEFAULT_VERBOSITY 3	/* 4 is traditional behavior of newfs(8) */
105f8b02b9cStsutsui int64_t fssize;			/* file system size */
106f8b02b9cStsutsui uint	sectorsize;		/* bytes/sector */
107f8b02b9cStsutsui uint	fsize = 0;		/* fragment size */
108f8b02b9cStsutsui uint	bsize = 0;		/* block size */
109f8b02b9cStsutsui uint	minfree = MINFREE;	/* free space threshold */
110f8b02b9cStsutsui uint	density;		/* number of bytes per inode */
111f8b02b9cStsutsui uint	num_inodes;		/* number of inodes (overrides density) */
112f8b02b9cStsutsui char	*volname = NULL;	/* volume name */
113f8b02b9cStsutsui 
114f8b02b9cStsutsui static char *disktype = NULL;
115f8b02b9cStsutsui static char device[MAXPATHLEN];
116f8b02b9cStsutsui 
117f8b02b9cStsutsui static const char lmsg[] = "%s: can't read disk label";
118f8b02b9cStsutsui 
119f8b02b9cStsutsui int
120f8b02b9cStsutsui main(int argc, char *argv[])
121f8b02b9cStsutsui {
122f8b02b9cStsutsui 	struct disk_geom geo;
123f8b02b9cStsutsui 	struct dkwedge_info dkw;
124f8b02b9cStsutsui 	struct statvfs *mp;
125f8b02b9cStsutsui 	struct stat sb;
126f8b02b9cStsutsui 	int ch, fsi, fso, len, n, Fflag, Iflag, Zflag;
127f8b02b9cStsutsui 	char *cp, *s1, *s2, *special;
128f8b02b9cStsutsui 	const char *opstring;
129f8b02b9cStsutsui 	int byte_sized;
130f8b02b9cStsutsui 	uint blocks;			/* number of blocks */
131f8b02b9cStsutsui 
132f8b02b9cStsutsui 	cp = NULL;
133f8b02b9cStsutsui 	fsi = fso = -1;
134f8b02b9cStsutsui 	Fflag = Iflag = Zflag = 0;
135f8b02b9cStsutsui 	verbosity = -1;
136f8b02b9cStsutsui 	opstring = "FINO:S:V:Zb:f:i:l:m:n:s:v:";
137f8b02b9cStsutsui 	byte_sized = 0;
138f8b02b9cStsutsui 	while ((ch = getopt(argc, argv, opstring)) != -1)
139f8b02b9cStsutsui 		switch (ch) {
140f8b02b9cStsutsui 		case 'F':
141f8b02b9cStsutsui 			Fflag = 1;
142f8b02b9cStsutsui 			break;
143f8b02b9cStsutsui 		case 'I':
144f8b02b9cStsutsui 			Iflag = 1;
145f8b02b9cStsutsui 			break;
146f8b02b9cStsutsui 		case 'N':
147f8b02b9cStsutsui 			Nflag = 1;
148f8b02b9cStsutsui 			if (verbosity == -1)
149f8b02b9cStsutsui 				verbosity = DEFAULT_VERBOSITY;
150f8b02b9cStsutsui 			break;
151f8b02b9cStsutsui 		case 'O':
152f8b02b9cStsutsui 			Oflag = strsuftoi64("format", optarg, 0, 1, NULL);
153f8b02b9cStsutsui 			break;
154f8b02b9cStsutsui 		case 'S':
155f8b02b9cStsutsui 			/*
156f8b02b9cStsutsui 			 * XXX:
157f8b02b9cStsutsui 			 * non-512 byte sectors almost certainly don't work.
158f8b02b9cStsutsui 			 */
159f8b02b9cStsutsui 			sectorsize = strsuftoi64("sector size",
160f8b02b9cStsutsui 			    optarg, 512, 65536, NULL);
161f8b02b9cStsutsui 			if (!powerof2(sectorsize))
162f8b02b9cStsutsui 				errx(EXIT_FAILURE,
163f8b02b9cStsutsui 				    "sector size `%s' is not a power of 2.",
164f8b02b9cStsutsui 				    optarg);
165f8b02b9cStsutsui 			break;
166f8b02b9cStsutsui 		case 'V':
167f8b02b9cStsutsui 			verbosity = strsuftoi64("verbose", optarg, 0, 4, NULL);
168f8b02b9cStsutsui 			break;
169f8b02b9cStsutsui 		case 'Z':
170f8b02b9cStsutsui 			Zflag = 1;
171f8b02b9cStsutsui 			break;
172f8b02b9cStsutsui 		case 'b':
173f8b02b9cStsutsui 			bsize = strsuftoi64("block size",
174ea9dd22aStsutsui 			    optarg, MINBSIZE, EXT2_MAXBSIZE, NULL);
175f8b02b9cStsutsui 			break;
176f8b02b9cStsutsui 		case 'f':
177f8b02b9cStsutsui 			fsize = strsuftoi64("fragment size",
178ea9dd22aStsutsui 			    optarg, MINBSIZE, EXT2_MAXBSIZE, NULL);
179f8b02b9cStsutsui 			break;
180f8b02b9cStsutsui 		case 'i':
181f8b02b9cStsutsui 			density = strsuftoi64("bytes per inode",
182f8b02b9cStsutsui 			    optarg, 1, INT_MAX, NULL);
183f8b02b9cStsutsui 			break;
184f8b02b9cStsutsui 		case 'm':
185f8b02b9cStsutsui 			minfree = strsuftoi64("free space %",
186f8b02b9cStsutsui 			    optarg, 0, 99, NULL);
187f8b02b9cStsutsui 			break;
188f8b02b9cStsutsui 		case 'n':
189f8b02b9cStsutsui 			num_inodes = strsuftoi64("number of inodes",
190f8b02b9cStsutsui 			    optarg, 1, INT_MAX, NULL);
191f8b02b9cStsutsui 			break;
192f8b02b9cStsutsui 		case 's':
193f8b02b9cStsutsui 			fssize = strsuftoi64("file system size",
194f8b02b9cStsutsui 			    optarg, INT64_MIN, INT64_MAX, &byte_sized);
195f8b02b9cStsutsui 			break;
196f8b02b9cStsutsui 		case 'v':
197f8b02b9cStsutsui 			volname = optarg;
198f8b02b9cStsutsui 			if (volname[0] == '\0')
199f8b02b9cStsutsui 				errx(EXIT_FAILURE,
200f8b02b9cStsutsui 				    "Volume name cannot be zero length");
201f8b02b9cStsutsui 			break;
202f8b02b9cStsutsui 		case '?':
203f8b02b9cStsutsui 		default:
204f8b02b9cStsutsui 			usage();
205f8b02b9cStsutsui 		}
206f8b02b9cStsutsui 	argc -= optind;
207f8b02b9cStsutsui 	argv += optind;
208f8b02b9cStsutsui 
209f8b02b9cStsutsui 	if (verbosity == -1)
210f8b02b9cStsutsui 		/* Default to showing cg info */
211f8b02b9cStsutsui 		verbosity = DEFAULT_VERBOSITY;
212f8b02b9cStsutsui 
213f8b02b9cStsutsui 	if (argc != 1)
214f8b02b9cStsutsui 		usage();
215f8b02b9cStsutsui 
216f8b02b9cStsutsui 	memset(&sb, 0, sizeof(sb));
217f8b02b9cStsutsui 	memset(&dkw, 0, sizeof(dkw));
218f8b02b9cStsutsui 	special = argv[0];
219f8b02b9cStsutsui 	if (Fflag) {
220f8b02b9cStsutsui 		int fl;
221f8b02b9cStsutsui 		/*
222f8b02b9cStsutsui 		 * It's a file system image
223f8b02b9cStsutsui 		 * no label, use fixed default for sectorsize.
224f8b02b9cStsutsui 		 */
225f8b02b9cStsutsui 		if (sectorsize == 0)
226f8b02b9cStsutsui 			sectorsize = DFL_SECSIZE;
227f8b02b9cStsutsui 
228f8b02b9cStsutsui 		/* creating image in a regular file */
229f8b02b9cStsutsui 		if (Nflag)
230f8b02b9cStsutsui 			fl = O_RDONLY;
231f8b02b9cStsutsui 		else {
232f8b02b9cStsutsui 			if (fssize > 0)
233f8b02b9cStsutsui 				fl = O_RDWR | O_CREAT;
234f8b02b9cStsutsui 			else
235f8b02b9cStsutsui 				fl = O_RDWR;
236f8b02b9cStsutsui 		}
237f8b02b9cStsutsui 		fsi = open(special, fl, 0777);
238f8b02b9cStsutsui 		if (fsi == -1)
239f8b02b9cStsutsui 			err(EXIT_FAILURE, "can't open file %s", special);
240f8b02b9cStsutsui 		if (fstat(fsi, &sb) == -1)
241f8b02b9cStsutsui 			err(EXIT_FAILURE, "can't fstat opened %s", special);
242f8b02b9cStsutsui 		if (!Nflag)
243f8b02b9cStsutsui 			fso = fsi;
244f8b02b9cStsutsui 	} else {	/* !Fflag */
245f8b02b9cStsutsui 		fsi = opendisk(special, O_RDONLY, device, sizeof(device), 0);
246f8b02b9cStsutsui 		special = device;
247f8b02b9cStsutsui 		if (fsi < 0 || fstat(fsi, &sb) == -1)
248f8b02b9cStsutsui 			err(EXIT_FAILURE, "%s: open for read", special);
249f8b02b9cStsutsui 
250f8b02b9cStsutsui 		if (!Nflag) {
251f8b02b9cStsutsui 			fso = open(special, O_WRONLY, 0);
252f8b02b9cStsutsui 			if (fso < 0)
253f8b02b9cStsutsui 				err(EXIT_FAILURE,
254f8b02b9cStsutsui 				    "%s: open for write", special);
255f8b02b9cStsutsui 
256f8b02b9cStsutsui 			/* Bail if target special is mounted */
257f8b02b9cStsutsui 			n = getmntinfo(&mp, MNT_NOWAIT);
258f8b02b9cStsutsui 			if (n == 0)
259f8b02b9cStsutsui 				err(EXIT_FAILURE, "%s: getmntinfo", special);
260f8b02b9cStsutsui 
261f8b02b9cStsutsui 			len = sizeof(_PATH_DEV) - 1;
262f8b02b9cStsutsui 			s1 = special;
263f8b02b9cStsutsui 			if (strncmp(_PATH_DEV, s1, len) == 0)
264f8b02b9cStsutsui 				s1 += len;
265f8b02b9cStsutsui 
266f8b02b9cStsutsui 			while (--n >= 0) {
267f8b02b9cStsutsui 				s2 = mp->f_mntfromname;
268f8b02b9cStsutsui 				if (strncmp(_PATH_DEV, s2, len) == 0) {
269f8b02b9cStsutsui 					s2 += len - 1;
270f8b02b9cStsutsui 					*s2 = 'r';
271f8b02b9cStsutsui 				}
272f8b02b9cStsutsui 				if (strcmp(s1, s2) == 0 ||
273f8b02b9cStsutsui 				    strcmp(s1, &s2[1]) == 0)
274f8b02b9cStsutsui 					errx(EXIT_FAILURE,
275f8b02b9cStsutsui 					    "%s is mounted on %s",
276f8b02b9cStsutsui 					    special, mp->f_mntonname);
277f8b02b9cStsutsui 				++mp;
278f8b02b9cStsutsui 			}
279f8b02b9cStsutsui 		}
280f8b02b9cStsutsui 
281f8b02b9cStsutsui 		if (getdiskinfo(special, fsi, disktype, &geo, &dkw) == -1)
282f8b02b9cStsutsui 			errx(EXIT_FAILURE, lmsg, special);
283f8b02b9cStsutsui 
284f8b02b9cStsutsui 		if (sectorsize == 0) {
285f8b02b9cStsutsui 			sectorsize = geo.dg_secsize;
286f8b02b9cStsutsui 			if (sectorsize <= 0)
287f8b02b9cStsutsui 				errx(EXIT_FAILURE, "no default sector size");
288f8b02b9cStsutsui 		}
289f8b02b9cStsutsui 
290f8b02b9cStsutsui 		if (dkw.dkw_parent[0]) {
291f8b02b9cStsutsui 			if (dkw.dkw_size == 0)
292f8b02b9cStsutsui 				errx(EXIT_FAILURE,
293f8b02b9cStsutsui 				    "%s partition is unavailable", special);
294f8b02b9cStsutsui 
295f8b02b9cStsutsui 			if (!Iflag) {
296f8b02b9cStsutsui 				static const char m[] =
297f8b02b9cStsutsui 				    "%s partition type is not `%s' (or use -I)";
298f8b02b9cStsutsui 				if (strcmp(dkw.dkw_ptype, DKW_PTYPE_EXT2FS))
299f8b02b9cStsutsui 					errx(EXIT_FAILURE, m,
300f8b02b9cStsutsui 					    special, "Linux Ext2");
301f8b02b9cStsutsui 			}
302f8b02b9cStsutsui 		}
303f8b02b9cStsutsui 	}
304f8b02b9cStsutsui 
305f8b02b9cStsutsui 	if (byte_sized)
306f8b02b9cStsutsui 		fssize /= sectorsize;
307f8b02b9cStsutsui 	if (fssize <= 0) {
308f8b02b9cStsutsui 		if (sb.st_size != 0)
309f8b02b9cStsutsui 			fssize += sb.st_size / sectorsize;
310f8b02b9cStsutsui 		else
311f8b02b9cStsutsui 			fssize += dkw.dkw_size;
312f8b02b9cStsutsui 		if (fssize <= 0)
313f8b02b9cStsutsui 			errx(EXIT_FAILURE,
314f8b02b9cStsutsui 			    "Unable to determine file system size");
315f8b02b9cStsutsui 	}
316f8b02b9cStsutsui 
317f8b02b9cStsutsui 	if (dkw.dkw_parent[0] && fssize > dkw.dkw_size)
318f8b02b9cStsutsui 		errx(EXIT_FAILURE,
319f8b02b9cStsutsui 		    "size %" PRIu64 " exceeds maximum file system size on "
320f8b02b9cStsutsui 		    "`%s' of %" PRIu64 " sectors",
321f8b02b9cStsutsui 		    fssize, special, dkw.dkw_size);
322f8b02b9cStsutsui 
323f8b02b9cStsutsui 	/* XXXLUKEM: only ftruncate() regular files ? (dsl: or at all?) */
324f8b02b9cStsutsui 	if (Fflag && fso != -1
325f8b02b9cStsutsui 	    && ftruncate(fso, (off_t)fssize * sectorsize) == -1)
326f8b02b9cStsutsui 		err(1, "can't ftruncate %s to %" PRId64, special, fssize);
327f8b02b9cStsutsui 
328f8b02b9cStsutsui 	if (Zflag && fso != -1) {	/* pre-zero (and de-sparce) the file */
329f8b02b9cStsutsui 		char *buf;
330f8b02b9cStsutsui 		int bufsize, i;
331f8b02b9cStsutsui 		off_t bufrem;
332f8b02b9cStsutsui 		struct statvfs sfs;
333f8b02b9cStsutsui 
334f8b02b9cStsutsui 		if (fstatvfs(fso, &sfs) == -1) {
335f8b02b9cStsutsui 			warn("can't fstatvfs `%s'", special);
336f8b02b9cStsutsui 			bufsize = 8192;
337f8b02b9cStsutsui 		} else
338f8b02b9cStsutsui 			bufsize = sfs.f_iosize;
339f8b02b9cStsutsui 
340f8b02b9cStsutsui 		if ((buf = calloc(1, bufsize)) == NULL)
341f8b02b9cStsutsui 			err(1, "can't malloc buffer of %d",
342f8b02b9cStsutsui 			bufsize);
343f8b02b9cStsutsui 		bufrem = fssize * sectorsize;
344f8b02b9cStsutsui 		if (verbosity > 0)
345f8b02b9cStsutsui 			printf("Creating file system image in `%s', "
346f8b02b9cStsutsui 			    "size %" PRId64 " bytes, in %d byte chunks.\n",
347f8b02b9cStsutsui 			    special, bufrem, bufsize);
348f8b02b9cStsutsui 		while (bufrem > 0) {
349f8b02b9cStsutsui 			i = write(fso, buf, MIN(bufsize, bufrem));
350f8b02b9cStsutsui 			if (i == -1)
351f8b02b9cStsutsui 				err(1, "writing image");
352f8b02b9cStsutsui 			bufrem -= i;
353f8b02b9cStsutsui 		}
354f8b02b9cStsutsui 		free(buf);
355f8b02b9cStsutsui 	}
356f8b02b9cStsutsui 
357f8b02b9cStsutsui 	/* Sort out fragment and block sizes */
358f8b02b9cStsutsui 	if (bsize == 0) {
359f8b02b9cStsutsui 		bsize = fsize;
360f8b02b9cStsutsui 		if (bsize == 0) {
361f8b02b9cStsutsui 			if (fssize < SMALL_FSSIZE)
362f8b02b9cStsutsui 				bsize = S_DFL_BSIZE;
363f8b02b9cStsutsui 			else if (fssize < MEDIUM_FSSIZE)
364f8b02b9cStsutsui 				bsize = M_DFL_BSIZE;
365f8b02b9cStsutsui 			else
366f8b02b9cStsutsui 				bsize = L_DFL_BSIZE;
367f8b02b9cStsutsui 		}
368f8b02b9cStsutsui 	}
369f8b02b9cStsutsui 	if (fsize == 0)
370f8b02b9cStsutsui 		fsize = bsize;
371f8b02b9cStsutsui 
372f8b02b9cStsutsui 	blocks = fssize * sectorsize / bsize;
373f8b02b9cStsutsui 
374f8b02b9cStsutsui 	if (num_inodes == 0) {
375f8b02b9cStsutsui 		if (density != 0)
376f8b02b9cStsutsui 			num_inodes = fssize / density;
377f8b02b9cStsutsui 		else {
378f8b02b9cStsutsui 			if (fssize < SMALL_FSSIZE)
379f8b02b9cStsutsui 				num_inodes = S_DFL_NINODE(blocks);
380f8b02b9cStsutsui 			else if (fssize < MEDIUM_FSSIZE)
381f8b02b9cStsutsui 				num_inodes = M_DFL_NINODE(blocks);
382f8b02b9cStsutsui 			else
383f8b02b9cStsutsui 				num_inodes = L_DFL_NINODE(blocks);
384f8b02b9cStsutsui 		}
385f8b02b9cStsutsui 	}
386f8b02b9cStsutsui 	mke2fs(special, fsi, fso);
387f8b02b9cStsutsui 
388f8b02b9cStsutsui 	if (fsi != -1)
389f8b02b9cStsutsui 		close(fsi);
390f8b02b9cStsutsui 	if (fso != -1 && fso != fsi)
391f8b02b9cStsutsui 		close(fso);
392f8b02b9cStsutsui 	exit(EXIT_SUCCESS);
393f8b02b9cStsutsui }
394f8b02b9cStsutsui 
395f8b02b9cStsutsui static int64_t
396f8b02b9cStsutsui strsuftoi64(const char *desc, const char *arg, int64_t min, int64_t max,
397f8b02b9cStsutsui     int *num_suffix)
398f8b02b9cStsutsui {
399f8b02b9cStsutsui 	int64_t result, r1;
400f8b02b9cStsutsui 	int shift = 0;
401f8b02b9cStsutsui 	char *ep;
402f8b02b9cStsutsui 
403f8b02b9cStsutsui 	errno = 0;
404f8b02b9cStsutsui 	r1 = strtoll(arg, &ep, 10);
405f8b02b9cStsutsui 	if (ep[0] != '\0' && ep[1] != '\0')
406f8b02b9cStsutsui 		errx(EXIT_FAILURE,
407f8b02b9cStsutsui 		    "%s `%s' is not a valid number.", desc, arg);
408f8b02b9cStsutsui 	switch (ep[0]) {
409f8b02b9cStsutsui 	case '\0':
410f8b02b9cStsutsui 	case 's':
411f8b02b9cStsutsui 	case 'S':
412f8b02b9cStsutsui 		if (num_suffix != NULL)
413f8b02b9cStsutsui 			*num_suffix = 0;
414f8b02b9cStsutsui 		break;
415f8b02b9cStsutsui 	case 'g':
416f8b02b9cStsutsui 	case 'G':
417f8b02b9cStsutsui 		shift += 10;
418f8b02b9cStsutsui 		/* FALLTHROUGH */
419f8b02b9cStsutsui 	case 'm':
420f8b02b9cStsutsui 	case 'M':
421f8b02b9cStsutsui 		shift += 10;
422f8b02b9cStsutsui 		/* FALLTHROUGH */
423f8b02b9cStsutsui 	case 'k':
424f8b02b9cStsutsui 	case 'K':
425f8b02b9cStsutsui 		shift += 10;
426f8b02b9cStsutsui 		/* FALLTHROUGH */
427f8b02b9cStsutsui 	case 'b':
428f8b02b9cStsutsui 	case 'B':
429f8b02b9cStsutsui 		if (num_suffix != NULL)
430f8b02b9cStsutsui 			*num_suffix = 1;
431f8b02b9cStsutsui 		break;
432f8b02b9cStsutsui 	default:
433f8b02b9cStsutsui 		errx(EXIT_FAILURE,
434f8b02b9cStsutsui 		    "`%s' is not a valid suffix for %s.", ep, desc);
435f8b02b9cStsutsui 	}
436f8b02b9cStsutsui 	result = r1 << shift;
437f8b02b9cStsutsui 	if (errno == ERANGE || result >> shift != r1)
438f8b02b9cStsutsui 		errx(EXIT_FAILURE,
439f8b02b9cStsutsui 		    "%s `%s' is too large to convert.", desc, arg);
440f8b02b9cStsutsui 	if (result < min)
441f8b02b9cStsutsui 		errx(EXIT_FAILURE,
442f8b02b9cStsutsui 		    "%s `%s' (%" PRId64 ") is less than the minimum (%"
443f8b02b9cStsutsui 		    PRId64 ").", desc, arg, result, min);
444f8b02b9cStsutsui 	if (result > max)
445f8b02b9cStsutsui 		errx(EXIT_FAILURE,
446f8b02b9cStsutsui 		    "%s `%s' (%" PRId64 ") is greater than the maximum (%"
447f8b02b9cStsutsui 		    PRId64 ").", desc, arg, result, max);
448f8b02b9cStsutsui 	return result;
449f8b02b9cStsutsui }
450f8b02b9cStsutsui 
451f8b02b9cStsutsui static const char help_strings[] =
452f8b02b9cStsutsui 	"\t-F \t\tcreate file system image in regular file\n"
453f8b02b9cStsutsui 	"\t-I \t\tdo not check that the file system type is `Linux Ext2'\n"
454f8b02b9cStsutsui 	"\t-N \t\tdo not create file system, just print out parameters\n"
455f8b02b9cStsutsui 	"\t-O N\t\tfilesystem revision: 0 ==> REV0, 1 ==> REV1 (default 0)\n"
456f8b02b9cStsutsui 	"\t-S secsize\tsector size\n"
457f8b02b9cStsutsui 	"\t-V verbose\toutput verbosity: 0 ==> none, 4 ==> max\n"
458f8b02b9cStsutsui 	"\t-Z \t\tpre-zero the image file\n"
459f8b02b9cStsutsui 	"\t-b bsize\tblock size\n"
460f8b02b9cStsutsui 	"\t-f fsize\tfragment size\n"
461f8b02b9cStsutsui 	"\t-i density\tnumber of bytes per inode\n"
462f8b02b9cStsutsui 	"\t-m minfree\tminimum free space %\n"
463f8b02b9cStsutsui 	"\t-n inodes\tnumber of inodes (overrides -i density)\n"
464f8b02b9cStsutsui 	"\t-s fssize\tfile system size (sectors)\n"
465f8b02b9cStsutsui 	"\t-v volname\text2fs volume name\n";
466f8b02b9cStsutsui 
467f8b02b9cStsutsui static void
468f8b02b9cStsutsui usage(void)
469f8b02b9cStsutsui {
470f8b02b9cStsutsui 
471f8b02b9cStsutsui 	fprintf(stderr,
472f8b02b9cStsutsui 	    "usage: %s [ fsoptions ] special-device\n", getprogname());
473f8b02b9cStsutsui 	fprintf(stderr, "where fsoptions are:\n");
474f8b02b9cStsutsui 	fprintf(stderr, "%s", help_strings);
475f8b02b9cStsutsui 
476f8b02b9cStsutsui 	exit(EXIT_FAILURE);
477f8b02b9cStsutsui }
478