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