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