xref: /netbsd/sbin/newfs_ext2fs/newfs_ext2fs.c (revision 5079dd15)
1*5079dd15Sandvar /*	$NetBSD: newfs_ext2fs.c,v 1.11 2022/04/16 18:15:21 andvar 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
346543a91fSlukem __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1993, 1994\
356543a91fSlukem  The Regents of the University of California.  All rights reserved.");
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*5079dd15Sandvar __RCSID("$NetBSD: newfs_ext2fs.c,v 1.11 2022/04/16 18:15:21 andvar 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>
571b5cd43cStsutsui #include <ufs/ext2fs/ext2fs_dinode.h>
58f8b02b9cStsutsui 
59f8b02b9cStsutsui #include <disktab.h>
60f8b02b9cStsutsui #include <err.h>
61f8b02b9cStsutsui #include <errno.h>
62f8b02b9cStsutsui #include <limits.h>
63f8b02b9cStsutsui #include <paths.h>
64f8b02b9cStsutsui #include <stdio.h>
65f8b02b9cStsutsui #include <stdlib.h>
66f8b02b9cStsutsui #include <string.h>
67f8b02b9cStsutsui #include <unistd.h>
68f8b02b9cStsutsui #include <util.h>
69f8b02b9cStsutsui #include <mntopts.h>
70f8b02b9cStsutsui 
71f8b02b9cStsutsui #include "extern.h"
72f8b02b9cStsutsui #include "partutil.h"
73f8b02b9cStsutsui 
74f8b02b9cStsutsui static int64_t strsuftoi64(const char *, const char *, int64_t, int64_t, int *);
758b0f9554Sperry static void usage(void) __dead;
76f8b02b9cStsutsui 
77f8b02b9cStsutsui /*
78f8b02b9cStsutsui  * For file systems smaller than SMALL_FSSIZE we use the S_DFL_* defaults,
79f8b02b9cStsutsui  * otherwise if less than MEDIUM_FSSIZE use M_DFL_*, otherwise use
80f8b02b9cStsutsui  * L_DFL_*.
81f8b02b9cStsutsui  */
82f8b02b9cStsutsui #define SMALL_FSSIZE	((4 * 1024 * 1024) / sectorsize)	/* 4MB */
83f8b02b9cStsutsui #define S_DFL_BSIZE	1024
84f8b02b9cStsutsui #define MEDIUM_FSSIZE	((512 * 1024 * 1024) / sectorsize)	/* 512MB */
85f8b02b9cStsutsui #define M_DFL_BSIZE	1024
86f8b02b9cStsutsui #define L_DFL_BSIZE	4096
87f8b02b9cStsutsui 
88f8b02b9cStsutsui /*
89f8b02b9cStsutsui  * Each file system has a number of inodes statically allocated.
90f8b02b9cStsutsui  * We allocate one inode slot per 2, 4, or 8 blocks, expecting this
91f8b02b9cStsutsui  * to be far more than we will ever need.
92f8b02b9cStsutsui  */
93f8b02b9cStsutsui #define S_DFL_NINODE(blocks)	((blocks) / 8)
94f8b02b9cStsutsui #define M_DFL_NINODE(blocks)	((blocks) / 4)
95f8b02b9cStsutsui #define L_DFL_NINODE(blocks)	((blocks) / 2)
96f8b02b9cStsutsui 
97f8b02b9cStsutsui /*
98f8b02b9cStsutsui  * Default sector size.
99f8b02b9cStsutsui  */
100f8b02b9cStsutsui #define	DFL_SECSIZE	512
101f8b02b9cStsutsui 
102f8b02b9cStsutsui int	Nflag;			/* run without writing file system */
103a03e2488Smrg int	Oflag = 1;		/* format as REV1 by default */
104f8b02b9cStsutsui int	verbosity;		/* amount of printf() output */
105f8b02b9cStsutsui #define DEFAULT_VERBOSITY 3	/* 4 is traditional behavior of newfs(8) */
106f8b02b9cStsutsui int64_t fssize;			/* file system size */
107f8b02b9cStsutsui uint	sectorsize;		/* bytes/sector */
1081b5cd43cStsutsui uint16_t inodesize = EXT2_REV0_DINODE_SIZE;	/* inode size */
109f8b02b9cStsutsui uint	fsize = 0;		/* fragment size */
110f8b02b9cStsutsui uint	bsize = 0;		/* block size */
111f8b02b9cStsutsui uint	minfree = MINFREE;	/* free space threshold */
112f8b02b9cStsutsui uint	density;		/* number of bytes per inode */
113f8b02b9cStsutsui uint	num_inodes;		/* number of inodes (overrides density) */
114f8b02b9cStsutsui char	*volname = NULL;	/* volume name */
115f8b02b9cStsutsui 
116f8b02b9cStsutsui static char *disktype = NULL;
117f8b02b9cStsutsui static char device[MAXPATHLEN];
118f8b02b9cStsutsui 
119f8b02b9cStsutsui static const char lmsg[] = "%s: can't read disk label";
120f8b02b9cStsutsui 
121f8b02b9cStsutsui int
main(int argc,char * argv[])122f8b02b9cStsutsui main(int argc, char *argv[])
123f8b02b9cStsutsui {
124f8b02b9cStsutsui 	struct disk_geom geo;
125f8b02b9cStsutsui 	struct dkwedge_info dkw;
126f8b02b9cStsutsui 	struct statvfs *mp;
127f8b02b9cStsutsui 	struct stat sb;
128f8b02b9cStsutsui 	int ch, fsi, fso, len, n, Fflag, Iflag, Zflag;
1294016dae3Schristos 	char *s1, *s2, *special;
130f8b02b9cStsutsui 	const char *opstring;
131f8b02b9cStsutsui 	int byte_sized;
132f8b02b9cStsutsui 	uint blocks;			/* number of blocks */
133f8b02b9cStsutsui 
134f8b02b9cStsutsui 	fsi = fso = -1;
135f8b02b9cStsutsui 	Fflag = Iflag = Zflag = 0;
136f8b02b9cStsutsui 	verbosity = -1;
13729055c63Schristos 	opstring = "D:FINO:S:V:Zb:f:i:l:m:n:s:v:";
138f8b02b9cStsutsui 	byte_sized = 0;
139f8b02b9cStsutsui 	while ((ch = getopt(argc, argv, opstring)) != -1)
140f8b02b9cStsutsui 		switch (ch) {
14129055c63Schristos 		case 'D':
14229055c63Schristos 			inodesize = (uint16_t)strtol(optarg, &s1, 0);
14348c2d0eeStsutsui 			if (*s1 || (inodesize != 128 && inodesize != 256))
14429055c63Schristos 				errx(1, "Bad inode size %d "
14529055c63Schristos 				    "(only 128 and 256 supported)", inodesize);
14629055c63Schristos 			break;
147f8b02b9cStsutsui 		case 'F':
148f8b02b9cStsutsui 			Fflag = 1;
149f8b02b9cStsutsui 			break;
150f8b02b9cStsutsui 		case 'I':
151f8b02b9cStsutsui 			Iflag = 1;
152f8b02b9cStsutsui 			break;
153f8b02b9cStsutsui 		case 'N':
154f8b02b9cStsutsui 			Nflag = 1;
155f8b02b9cStsutsui 			if (verbosity == -1)
156f8b02b9cStsutsui 				verbosity = DEFAULT_VERBOSITY;
157f8b02b9cStsutsui 			break;
158f8b02b9cStsutsui 		case 'O':
159f8b02b9cStsutsui 			Oflag = strsuftoi64("format", optarg, 0, 1, NULL);
160f8b02b9cStsutsui 			break;
161f8b02b9cStsutsui 		case 'S':
162f8b02b9cStsutsui 			/*
163f8b02b9cStsutsui 			 * XXX:
164f8b02b9cStsutsui 			 * non-512 byte sectors almost certainly don't work.
165f8b02b9cStsutsui 			 */
166f8b02b9cStsutsui 			sectorsize = strsuftoi64("sector size",
167f8b02b9cStsutsui 			    optarg, 512, 65536, NULL);
168f8b02b9cStsutsui 			if (!powerof2(sectorsize))
169f8b02b9cStsutsui 				errx(EXIT_FAILURE,
170f8b02b9cStsutsui 				    "sector size `%s' is not a power of 2.",
171f8b02b9cStsutsui 				    optarg);
172f8b02b9cStsutsui 			break;
173f8b02b9cStsutsui 		case 'V':
174f8b02b9cStsutsui 			verbosity = strsuftoi64("verbose", optarg, 0, 4, NULL);
175f8b02b9cStsutsui 			break;
176f8b02b9cStsutsui 		case 'Z':
177f8b02b9cStsutsui 			Zflag = 1;
178f8b02b9cStsutsui 			break;
179f8b02b9cStsutsui 		case 'b':
180f8b02b9cStsutsui 			bsize = strsuftoi64("block size",
181ea9dd22aStsutsui 			    optarg, MINBSIZE, EXT2_MAXBSIZE, NULL);
182f8b02b9cStsutsui 			break;
183f8b02b9cStsutsui 		case 'f':
184f8b02b9cStsutsui 			fsize = strsuftoi64("fragment size",
185ea9dd22aStsutsui 			    optarg, MINBSIZE, EXT2_MAXBSIZE, NULL);
186f8b02b9cStsutsui 			break;
187f8b02b9cStsutsui 		case 'i':
188f8b02b9cStsutsui 			density = strsuftoi64("bytes per inode",
189f8b02b9cStsutsui 			    optarg, 1, INT_MAX, NULL);
190f8b02b9cStsutsui 			break;
191f8b02b9cStsutsui 		case 'm':
192f8b02b9cStsutsui 			minfree = strsuftoi64("free space %",
193f8b02b9cStsutsui 			    optarg, 0, 99, NULL);
194f8b02b9cStsutsui 			break;
195f8b02b9cStsutsui 		case 'n':
196f8b02b9cStsutsui 			num_inodes = strsuftoi64("number of inodes",
197f8b02b9cStsutsui 			    optarg, 1, INT_MAX, NULL);
198f8b02b9cStsutsui 			break;
199f8b02b9cStsutsui 		case 's':
200f8b02b9cStsutsui 			fssize = strsuftoi64("file system size",
201f8b02b9cStsutsui 			    optarg, INT64_MIN, INT64_MAX, &byte_sized);
202f8b02b9cStsutsui 			break;
203f8b02b9cStsutsui 		case 'v':
204f8b02b9cStsutsui 			volname = optarg;
205f8b02b9cStsutsui 			if (volname[0] == '\0')
206f8b02b9cStsutsui 				errx(EXIT_FAILURE,
207f8b02b9cStsutsui 				    "Volume name cannot be zero length");
208f8b02b9cStsutsui 			break;
209f8b02b9cStsutsui 		case '?':
210f8b02b9cStsutsui 		default:
211f8b02b9cStsutsui 			usage();
212f8b02b9cStsutsui 		}
213f8b02b9cStsutsui 	argc -= optind;
214f8b02b9cStsutsui 	argv += optind;
215f8b02b9cStsutsui 
216f8b02b9cStsutsui 	if (verbosity == -1)
217f8b02b9cStsutsui 		/* Default to showing cg info */
218f8b02b9cStsutsui 		verbosity = DEFAULT_VERBOSITY;
219f8b02b9cStsutsui 
220f8b02b9cStsutsui 	if (argc != 1)
221f8b02b9cStsutsui 		usage();
222f8b02b9cStsutsui 
223f8b02b9cStsutsui 	memset(&sb, 0, sizeof(sb));
224f8b02b9cStsutsui 	memset(&dkw, 0, sizeof(dkw));
225f8b02b9cStsutsui 	special = argv[0];
226f8b02b9cStsutsui 	if (Fflag) {
227f8b02b9cStsutsui 		int fl;
228f8b02b9cStsutsui 		/*
229f8b02b9cStsutsui 		 * It's a file system image
230f8b02b9cStsutsui 		 * no label, use fixed default for sectorsize.
231f8b02b9cStsutsui 		 */
232f8b02b9cStsutsui 		if (sectorsize == 0)
233f8b02b9cStsutsui 			sectorsize = DFL_SECSIZE;
234f8b02b9cStsutsui 
235f8b02b9cStsutsui 		/* creating image in a regular file */
236f8b02b9cStsutsui 		if (Nflag)
237f8b02b9cStsutsui 			fl = O_RDONLY;
238f8b02b9cStsutsui 		else {
239f8b02b9cStsutsui 			if (fssize > 0)
240f8b02b9cStsutsui 				fl = O_RDWR | O_CREAT;
241f8b02b9cStsutsui 			else
242f8b02b9cStsutsui 				fl = O_RDWR;
243f8b02b9cStsutsui 		}
244f8b02b9cStsutsui 		fsi = open(special, fl, 0777);
245f8b02b9cStsutsui 		if (fsi == -1)
246f8b02b9cStsutsui 			err(EXIT_FAILURE, "can't open file %s", special);
247f8b02b9cStsutsui 		if (fstat(fsi, &sb) == -1)
248f8b02b9cStsutsui 			err(EXIT_FAILURE, "can't fstat opened %s", special);
249f8b02b9cStsutsui 		if (!Nflag)
250f8b02b9cStsutsui 			fso = fsi;
251f8b02b9cStsutsui 	} else {	/* !Fflag */
252f8b02b9cStsutsui 		fsi = opendisk(special, O_RDONLY, device, sizeof(device), 0);
253f8b02b9cStsutsui 		special = device;
254f8b02b9cStsutsui 		if (fsi < 0 || fstat(fsi, &sb) == -1)
255f8b02b9cStsutsui 			err(EXIT_FAILURE, "%s: open for read", special);
256f8b02b9cStsutsui 
257f8b02b9cStsutsui 		if (!Nflag) {
258f8b02b9cStsutsui 			fso = open(special, O_WRONLY, 0);
259f8b02b9cStsutsui 			if (fso < 0)
260f8b02b9cStsutsui 				err(EXIT_FAILURE,
261f8b02b9cStsutsui 				    "%s: open for write", special);
262f8b02b9cStsutsui 
263f8b02b9cStsutsui 			/* Bail if target special is mounted */
264f8b02b9cStsutsui 			n = getmntinfo(&mp, MNT_NOWAIT);
265f8b02b9cStsutsui 			if (n == 0)
266f8b02b9cStsutsui 				err(EXIT_FAILURE, "%s: getmntinfo", special);
267f8b02b9cStsutsui 
268f8b02b9cStsutsui 			len = sizeof(_PATH_DEV) - 1;
269f8b02b9cStsutsui 			s1 = special;
270f8b02b9cStsutsui 			if (strncmp(_PATH_DEV, s1, len) == 0)
271f8b02b9cStsutsui 				s1 += len;
272f8b02b9cStsutsui 
273f8b02b9cStsutsui 			while (--n >= 0) {
274f8b02b9cStsutsui 				s2 = mp->f_mntfromname;
275f8b02b9cStsutsui 				if (strncmp(_PATH_DEV, s2, len) == 0) {
276f8b02b9cStsutsui 					s2 += len - 1;
277f8b02b9cStsutsui 					*s2 = 'r';
278f8b02b9cStsutsui 				}
279f8b02b9cStsutsui 				if (strcmp(s1, s2) == 0 ||
280f8b02b9cStsutsui 				    strcmp(s1, &s2[1]) == 0)
281f8b02b9cStsutsui 					errx(EXIT_FAILURE,
282f8b02b9cStsutsui 					    "%s is mounted on %s",
283f8b02b9cStsutsui 					    special, mp->f_mntonname);
284f8b02b9cStsutsui 				++mp;
285f8b02b9cStsutsui 			}
286f8b02b9cStsutsui 		}
287f8b02b9cStsutsui 
288f8b02b9cStsutsui 		if (getdiskinfo(special, fsi, disktype, &geo, &dkw) == -1)
289f8b02b9cStsutsui 			errx(EXIT_FAILURE, lmsg, special);
290f8b02b9cStsutsui 
291f8b02b9cStsutsui 		if (sectorsize == 0) {
292f8b02b9cStsutsui 			sectorsize = geo.dg_secsize;
293f8b02b9cStsutsui 			if (sectorsize <= 0)
294f8b02b9cStsutsui 				errx(EXIT_FAILURE, "no default sector size");
295f8b02b9cStsutsui 		}
296f8b02b9cStsutsui 
297f8b02b9cStsutsui 		if (dkw.dkw_parent[0]) {
298f8b02b9cStsutsui 			if (dkw.dkw_size == 0)
299f8b02b9cStsutsui 				errx(EXIT_FAILURE,
300f8b02b9cStsutsui 				    "%s partition is unavailable", special);
301f8b02b9cStsutsui 
302f8b02b9cStsutsui 			if (!Iflag) {
303f8b02b9cStsutsui 				static const char m[] =
304f8b02b9cStsutsui 				    "%s partition type is not `%s' (or use -I)";
305f8b02b9cStsutsui 				if (strcmp(dkw.dkw_ptype, DKW_PTYPE_EXT2FS))
306f8b02b9cStsutsui 					errx(EXIT_FAILURE, m,
307f8b02b9cStsutsui 					    special, "Linux Ext2");
308f8b02b9cStsutsui 			}
309f8b02b9cStsutsui 		}
310f8b02b9cStsutsui 	}
311f8b02b9cStsutsui 
312f8b02b9cStsutsui 	if (byte_sized)
313f8b02b9cStsutsui 		fssize /= sectorsize;
314f8b02b9cStsutsui 	if (fssize <= 0) {
315f8b02b9cStsutsui 		if (sb.st_size != 0)
316f8b02b9cStsutsui 			fssize += sb.st_size / sectorsize;
317f8b02b9cStsutsui 		else
318f8b02b9cStsutsui 			fssize += dkw.dkw_size;
319f8b02b9cStsutsui 		if (fssize <= 0)
320f8b02b9cStsutsui 			errx(EXIT_FAILURE,
321f8b02b9cStsutsui 			    "Unable to determine file system size");
322f8b02b9cStsutsui 	}
323f8b02b9cStsutsui 
324f8b02b9cStsutsui 	if (dkw.dkw_parent[0] && fssize > dkw.dkw_size)
325f8b02b9cStsutsui 		errx(EXIT_FAILURE,
326f8b02b9cStsutsui 		    "size %" PRIu64 " exceeds maximum file system size on "
327f8b02b9cStsutsui 		    "`%s' of %" PRIu64 " sectors",
328f8b02b9cStsutsui 		    fssize, special, dkw.dkw_size);
329f8b02b9cStsutsui 
330f8b02b9cStsutsui 	/* XXXLUKEM: only ftruncate() regular files ? (dsl: or at all?) */
331f8b02b9cStsutsui 	if (Fflag && fso != -1
332f8b02b9cStsutsui 	    && ftruncate(fso, (off_t)fssize * sectorsize) == -1)
333f8b02b9cStsutsui 		err(1, "can't ftruncate %s to %" PRId64, special, fssize);
334f8b02b9cStsutsui 
335*5079dd15Sandvar 	if (Zflag && fso != -1) {	/* pre-zero (and de-sparse) the file */
336f8b02b9cStsutsui 		char *buf;
337f8b02b9cStsutsui 		int bufsize, i;
338f8b02b9cStsutsui 		off_t bufrem;
339f8b02b9cStsutsui 		struct statvfs sfs;
340f8b02b9cStsutsui 
341f8b02b9cStsutsui 		if (fstatvfs(fso, &sfs) == -1) {
342f8b02b9cStsutsui 			warn("can't fstatvfs `%s'", special);
343f8b02b9cStsutsui 			bufsize = 8192;
344f8b02b9cStsutsui 		} else
345f8b02b9cStsutsui 			bufsize = sfs.f_iosize;
346f8b02b9cStsutsui 
347f8b02b9cStsutsui 		if ((buf = calloc(1, bufsize)) == NULL)
348f8b02b9cStsutsui 			err(1, "can't malloc buffer of %d",
349f8b02b9cStsutsui 			bufsize);
350f8b02b9cStsutsui 		bufrem = fssize * sectorsize;
351f8b02b9cStsutsui 		if (verbosity > 0)
352f8b02b9cStsutsui 			printf("Creating file system image in `%s', "
353f8b02b9cStsutsui 			    "size %" PRId64 " bytes, in %d byte chunks.\n",
354f8b02b9cStsutsui 			    special, bufrem, bufsize);
355f8b02b9cStsutsui 		while (bufrem > 0) {
356f8b02b9cStsutsui 			i = write(fso, buf, MIN(bufsize, bufrem));
357f8b02b9cStsutsui 			if (i == -1)
358f8b02b9cStsutsui 				err(1, "writing image");
359f8b02b9cStsutsui 			bufrem -= i;
360f8b02b9cStsutsui 		}
361f8b02b9cStsutsui 		free(buf);
362f8b02b9cStsutsui 	}
363f8b02b9cStsutsui 
364f8b02b9cStsutsui 	/* Sort out fragment and block sizes */
365f8b02b9cStsutsui 	if (bsize == 0) {
366f8b02b9cStsutsui 		bsize = fsize;
367f8b02b9cStsutsui 		if (bsize == 0) {
368f8b02b9cStsutsui 			if (fssize < SMALL_FSSIZE)
369f8b02b9cStsutsui 				bsize = S_DFL_BSIZE;
370f8b02b9cStsutsui 			else if (fssize < MEDIUM_FSSIZE)
371f8b02b9cStsutsui 				bsize = M_DFL_BSIZE;
372f8b02b9cStsutsui 			else
373f8b02b9cStsutsui 				bsize = L_DFL_BSIZE;
374f8b02b9cStsutsui 		}
375f8b02b9cStsutsui 	}
376f8b02b9cStsutsui 	if (fsize == 0)
377f8b02b9cStsutsui 		fsize = bsize;
378f8b02b9cStsutsui 
379f8b02b9cStsutsui 	blocks = fssize * sectorsize / bsize;
380f8b02b9cStsutsui 
381f8b02b9cStsutsui 	if (num_inodes == 0) {
382f8b02b9cStsutsui 		if (density != 0)
383f8b02b9cStsutsui 			num_inodes = fssize / density;
384f8b02b9cStsutsui 		else {
385f8b02b9cStsutsui 			if (fssize < SMALL_FSSIZE)
386f8b02b9cStsutsui 				num_inodes = S_DFL_NINODE(blocks);
387f8b02b9cStsutsui 			else if (fssize < MEDIUM_FSSIZE)
388f8b02b9cStsutsui 				num_inodes = M_DFL_NINODE(blocks);
389f8b02b9cStsutsui 			else
390f8b02b9cStsutsui 				num_inodes = L_DFL_NINODE(blocks);
391f8b02b9cStsutsui 		}
392f8b02b9cStsutsui 	}
393f8b02b9cStsutsui 	mke2fs(special, fsi, fso);
394f8b02b9cStsutsui 
395f8b02b9cStsutsui 	if (fsi != -1)
396f8b02b9cStsutsui 		close(fsi);
397f8b02b9cStsutsui 	if (fso != -1 && fso != fsi)
398f8b02b9cStsutsui 		close(fso);
399f8b02b9cStsutsui 	exit(EXIT_SUCCESS);
400f8b02b9cStsutsui }
401f8b02b9cStsutsui 
402f8b02b9cStsutsui static int64_t
strsuftoi64(const char * desc,const char * arg,int64_t min,int64_t max,int * num_suffix)403f8b02b9cStsutsui strsuftoi64(const char *desc, const char *arg, int64_t min, int64_t max,
404f8b02b9cStsutsui     int *num_suffix)
405f8b02b9cStsutsui {
406f8b02b9cStsutsui 	int64_t result, r1;
407f8b02b9cStsutsui 	int shift = 0;
408f8b02b9cStsutsui 	char *ep;
409f8b02b9cStsutsui 
410f8b02b9cStsutsui 	errno = 0;
411f8b02b9cStsutsui 	r1 = strtoll(arg, &ep, 10);
412f8b02b9cStsutsui 	if (ep[0] != '\0' && ep[1] != '\0')
413f8b02b9cStsutsui 		errx(EXIT_FAILURE,
414f8b02b9cStsutsui 		    "%s `%s' is not a valid number.", desc, arg);
415f8b02b9cStsutsui 	switch (ep[0]) {
416f8b02b9cStsutsui 	case '\0':
417f8b02b9cStsutsui 	case 's':
418f8b02b9cStsutsui 	case 'S':
419f8b02b9cStsutsui 		if (num_suffix != NULL)
420f8b02b9cStsutsui 			*num_suffix = 0;
421f8b02b9cStsutsui 		break;
422f8b02b9cStsutsui 	case 'g':
423f8b02b9cStsutsui 	case 'G':
424f8b02b9cStsutsui 		shift += 10;
425f8b02b9cStsutsui 		/* FALLTHROUGH */
426f8b02b9cStsutsui 	case 'm':
427f8b02b9cStsutsui 	case 'M':
428f8b02b9cStsutsui 		shift += 10;
429f8b02b9cStsutsui 		/* FALLTHROUGH */
430f8b02b9cStsutsui 	case 'k':
431f8b02b9cStsutsui 	case 'K':
432f8b02b9cStsutsui 		shift += 10;
433f8b02b9cStsutsui 		/* FALLTHROUGH */
434f8b02b9cStsutsui 	case 'b':
435f8b02b9cStsutsui 	case 'B':
436f8b02b9cStsutsui 		if (num_suffix != NULL)
437f8b02b9cStsutsui 			*num_suffix = 1;
438f8b02b9cStsutsui 		break;
439f8b02b9cStsutsui 	default:
440f8b02b9cStsutsui 		errx(EXIT_FAILURE,
441f8b02b9cStsutsui 		    "`%s' is not a valid suffix for %s.", ep, desc);
442f8b02b9cStsutsui 	}
443f8b02b9cStsutsui 	result = r1 << shift;
444f8b02b9cStsutsui 	if (errno == ERANGE || result >> shift != r1)
445f8b02b9cStsutsui 		errx(EXIT_FAILURE,
446f8b02b9cStsutsui 		    "%s `%s' is too large to convert.", desc, arg);
447f8b02b9cStsutsui 	if (result < min)
448f8b02b9cStsutsui 		errx(EXIT_FAILURE,
449f8b02b9cStsutsui 		    "%s `%s' (%" PRId64 ") is less than the minimum (%"
450f8b02b9cStsutsui 		    PRId64 ").", desc, arg, result, min);
451f8b02b9cStsutsui 	if (result > max)
452f8b02b9cStsutsui 		errx(EXIT_FAILURE,
453f8b02b9cStsutsui 		    "%s `%s' (%" PRId64 ") is greater than the maximum (%"
454f8b02b9cStsutsui 		    PRId64 ").", desc, arg, result, max);
455f8b02b9cStsutsui 	return result;
456f8b02b9cStsutsui }
457f8b02b9cStsutsui 
458f8b02b9cStsutsui static const char help_strings[] =
459dcc33b5cSwiz 	"\t-b bsize\tblock size\n"
46029055c63Schristos 	"\t-D inodesize\tsize of an inode in bytes (128 or 256)\n"
461f8b02b9cStsutsui 	"\t-F \t\tcreate file system image in regular file\n"
462f8b02b9cStsutsui 	"\t-f fsize\tfragment size\n"
463dcc33b5cSwiz 	"\t-I \t\tdo not check that the file system type is `Linux Ext2'\n"
464f8b02b9cStsutsui 	"\t-i density\tnumber of bytes per inode\n"
465f8b02b9cStsutsui 	"\t-m minfree\tminimum free space %\n"
466dcc33b5cSwiz 	"\t-N \t\tdo not create file system, just print out parameters\n"
467f8b02b9cStsutsui 	"\t-n inodes\tnumber of inodes (overrides -i density)\n"
468dcc33b5cSwiz 	"\t-O N\t\tfilesystem revision: 0 ==> REV0, 1 ==> REV1 (default 0)\n"
469dcc33b5cSwiz 	"\t-S secsize\tsector size\n"
470f8b02b9cStsutsui 	"\t-s fssize\tfile system size (sectors)\n"
471dcc33b5cSwiz 	"\t-V verbose\toutput verbosity: 0 ==> none, 4 ==> max\n"
472dcc33b5cSwiz 	"\t-v volname\text2fs volume name\n"
473dcc33b5cSwiz 	"\t-Z \t\tpre-zero the image file\n";
474f8b02b9cStsutsui 
475f8b02b9cStsutsui static void
usage(void)476f8b02b9cStsutsui usage(void)
477f8b02b9cStsutsui {
478f8b02b9cStsutsui 
479f8b02b9cStsutsui 	fprintf(stderr,
480f8b02b9cStsutsui 	    "usage: %s [ fsoptions ] special-device\n", getprogname());
481f8b02b9cStsutsui 	fprintf(stderr, "where fsoptions are:\n");
482f8b02b9cStsutsui 	fprintf(stderr, "%s", help_strings);
483f8b02b9cStsutsui 
484f8b02b9cStsutsui 	exit(EXIT_FAILURE);
485f8b02b9cStsutsui }
486