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