tunefs.c revision 1.22
1/*	$NetBSD: tunefs.c,v 1.22 2001/08/19 09:39:24 lukem Exp $	*/
2
3/*
4 * Copyright (c) 1983, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the University of
18 *	California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/cdefs.h>
37#ifndef lint
38__COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
39	The Regents of the University of California.  All rights reserved.\n");
40#endif /* not lint */
41
42#ifndef lint
43#if 0
44static char sccsid[] = "@(#)tunefs.c	8.3 (Berkeley) 5/3/95";
45#else
46__RCSID("$NetBSD: tunefs.c,v 1.22 2001/08/19 09:39:24 lukem Exp $");
47#endif
48#endif /* not lint */
49
50/*
51 * tunefs: change layout parameters to an existing file system.
52 */
53#include <sys/param.h>
54#include <sys/stat.h>
55
56#include <ufs/ufs/dinode.h>
57#include <ufs/ffs/fs.h>
58#include <ufs/ffs/ffs_extern.h>
59
60#include <machine/bswap.h>
61
62#include <err.h>
63#include <errno.h>
64#include <fcntl.h>
65#include <fstab.h>
66#include <paths.h>
67#include <stdio.h>
68#include <stdlib.h>
69#include <string.h>
70#include <unistd.h>
71
72/* the optimization warning string template */
73#define	OPTWARN	"should optimize for %s with minfree %s %d%%"
74
75union {
76	struct	fs sb;
77	char pad[MAXBSIZE];
78} sbun;
79#define	sblock sbun.sb
80char buf[MAXBSIZE];
81
82int	fi;
83long	dev_bsize = 1;
84int	needswap = 0;
85
86static	void	bwrite(daddr_t, char *, int);
87static	int	bread(daddr_t, char *, int);
88static	int	getnum(const char *, const char *, int, int);
89static	void	getsb(struct fs *, const char *);
90static	void	usage(void);
91int		main(int, char *[]);
92
93int
94main(int argc, char *argv[])
95{
96#ifdef TUNEFS_SOFTDEP
97	int		softdep;
98#define	OPTSTRING	"AFNa:d:e:m:n:o:t:"
99#else
100#define	OPTSTRING	"AFNa:d:e:m:o:t:"
101#endif
102	struct stat	st;
103	int		i, ch, Aflag, Fflag, Nflag;
104	struct fstab	*fs;
105	const char	*special, *chg[2];
106	char		device[MAXPATHLEN];
107	int		maxbpg, maxcontig, minfree, rotdelay, optim, trackskew;
108
109	Aflag = Fflag = Nflag = 0;
110	maxbpg = maxcontig = minfree = rotdelay = optim = trackskew = -1;
111#ifdef TUNEFS_SOFTDEP
112	softdep = -1;
113#endif
114	chg[FS_OPTSPACE] = "space";
115	chg[FS_OPTTIME] = "time";
116
117	while ((ch = getopt(argc, argv, OPTSTRING)) != -1) {
118		switch (ch) {
119
120		case 'A':
121			Aflag++;
122			break;
123
124		case 'F':
125			Fflag++;
126			break;
127
128		case 'N':
129			Nflag++;
130			break;
131
132		case 'a':
133			maxcontig = getnum(optarg,
134			    "maximum contiguous block count", 1, INT_MAX);
135			break;
136
137		case 'd':
138			rotdelay = getnum(optarg,
139			    "rotational delay between contiguous blocks",
140			    0, INT_MAX);
141			break;
142
143		case 'e':
144			maxbpg = getnum(optarg,
145			    "maximum blocks per file in a cylinder group",
146			    1, INT_MAX);
147			break;
148
149
150		case 'm':
151			minfree = getnum(optarg,
152			    "minimum percentage of free space", 0, 99);
153			break;
154
155#ifdef TUNEFS_SOFTDEP
156		case 'n':
157			if (strcmp(optarg, "enable") == 0)
158				softdep = 1;
159			else if (strcmp(optarg, "disable") == 0)
160				softdep = 0;
161			else {
162				errx(10, "bad soft dependencies "
163					"(options are `enable' or `disable')");
164			}
165			break;
166#endif
167
168		case 'o':
169			if (strcmp(optarg, chg[FS_OPTSPACE]) == 0)
170				optim = FS_OPTSPACE;
171			else if (strcmp(optarg, chg[FS_OPTTIME]) == 0)
172				optim = FS_OPTTIME;
173			else
174				errx(10,
175				    "bad %s (options are `space' or `time')",
176				    "optimization preference");
177			break;
178
179		case 't':
180			trackskew = getnum(optarg,
181			    "track skew in sectors", 0, INT_MAX);
182			break;
183
184		default:
185			usage();
186		}
187	}
188	argc -= optind;
189	argv += optind;
190	if (argc != 1)
191		usage();
192
193	special = argv[0];
194	fs = getfsfile(special);
195	if (fs)
196		special = fs->fs_spec;
197 again:
198	if (stat(special, &st) < 0) {
199		if (!Fflag && *special != '/') {
200			if (*special == 'r')
201				special++;
202			(void)snprintf(device, sizeof(device), "%s/%s",
203			    _PATH_DEV, special);
204			special = device;
205			goto again;
206		}
207		err(1, "%s", special);
208	}
209	if (Fflag) {
210		if (!S_ISREG(st.st_mode))
211			errx(10, "%s: not a regular file", special);
212	} else if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
213		errx(10, "%s: not a block or character device", special);
214	getsb(&sblock, special);
215
216	if (maxcontig != -1) {
217		warnx("%s changes from %d to %d",
218		    "maximum contiguous block count",
219		    sblock.fs_maxcontig, maxcontig);
220		sblock.fs_maxcontig = maxcontig;
221	}
222	if (rotdelay != -1) {
223		warnx("%s changes from %dms to %dms",
224		    "rotational delay between contiguous blocks",
225		    sblock.fs_rotdelay, rotdelay);
226		sblock.fs_rotdelay = rotdelay;
227	}
228	if (maxbpg != -1) {
229		warnx("%s changes from %d to %d",
230		    "maximum blocks per file in a cylinder group",
231		    sblock.fs_maxbpg, maxbpg);
232		sblock.fs_maxbpg = maxbpg;
233	}
234	if (minfree != -1) {
235		warnx("%s changes from %d%% to %d%%",
236		    "minimum percentage of free space",
237		    sblock.fs_minfree, minfree);
238		sblock.fs_minfree = minfree;
239		if (minfree >= MINFREE &&
240		    sblock.fs_optim == FS_OPTSPACE)
241			warnx(OPTWARN, "time", ">=", MINFREE);
242		if (minfree < MINFREE &&
243		    sblock.fs_optim == FS_OPTTIME)
244			warnx(OPTWARN, "space", "<", MINFREE);
245	}
246#ifdef TUNEFS_SOFTDEP
247	if (softdep == 1) {
248		sblock.fs_flags |= FS_DOSOFTDEP;
249		warnx("soft dependencies set");
250	} else if (softdep == 0) {
251		sblock.fs_flags &= ~FS_DOSOFTDEP;
252		warnx("soft dependencies cleared");
253	}
254#endif
255	if (optim != -1) {
256		if (sblock.fs_optim == optim) {
257			warnx("%s remains unchanged as %s",
258			    "optimization preference",
259			    chg[optim]);
260		} else {
261			warnx("%s changes from %s to %s",
262			    "optimization preference",
263			    chg[sblock.fs_optim], chg[optim]);
264			sblock.fs_optim = optim;
265			if (sblock.fs_minfree >= MINFREE &&
266			    optim == FS_OPTSPACE)
267				warnx(OPTWARN, "time", ">=", MINFREE);
268			if (sblock.fs_minfree < MINFREE &&
269			    optim == FS_OPTTIME)
270				warnx(OPTWARN, "space", "<", MINFREE);
271		}
272	}
273	if (trackskew != -1) {
274		warnx("%s changes from %d to %d",
275		    "track skew in sectors", sblock.fs_trackskew, trackskew);
276		sblock.fs_trackskew = trackskew;
277	}
278
279	if (Nflag) {
280		fprintf(stdout, "tunefs: current settings of %s\n", special);
281		fprintf(stdout, "\tmaximum contiguous block count %d\n",
282		    sblock.fs_maxcontig);
283		fprintf(stdout,
284		    "\trotational delay between contiguous blocks %dms\n",
285		    sblock.fs_rotdelay);
286		fprintf(stdout,
287		    "\tmaximum blocks per file in a cylinder group %d\n",
288		    sblock.fs_maxbpg);
289		fprintf(stdout, "\tminimum percentage of free space %d%%\n",
290		    sblock.fs_minfree);
291#ifdef TUNEFS_SOFTDEP
292		fprintf(stdout, "\tsoft dependencies: %s\n",
293		    (sblock.fs_flags & FS_DOSOFTDEP) ? "on" : "off");
294#endif
295		fprintf(stdout, "\toptimization preference: %s\n",
296		    chg[sblock.fs_optim]);
297		fprintf(stdout, "\ttrack skew %d sectors\n",
298			sblock.fs_trackskew);
299		fprintf(stdout, "tunefs: no changes made\n");
300		exit(0);
301	}
302
303	fi = open(special, 1);
304	if (fi < 0)
305		err(3, "cannot open %s for writing", special);
306	memcpy(buf, (char *)&sblock, SBSIZE);
307	if (needswap)
308		ffs_sb_swap((struct fs*)buf, (struct fs*)buf);
309	bwrite((daddr_t)SBOFF / dev_bsize, buf, SBSIZE);
310	if (Aflag)
311		for (i = 0; i < sblock.fs_ncg; i++)
312			bwrite(fsbtodb(&sblock, cgsblock(&sblock, i)),
313			    buf, SBSIZE);
314	close(fi);
315	exit(0);
316}
317
318static int
319getnum(const char *num, const char *desc, int min, int max)
320{
321	long	n;
322	char	*ep;
323
324	n = strtol(num, &ep, 10);
325	if (ep[0] != '\0')
326		errx(1, "Invalid number `%s' for %s", num, desc);
327	if ((int) n < min)
328		errx(1, "%s `%s' too small (minimum is %d)", desc, num, min);
329	if ((int) n > max)
330		errx(1, "%s `%s' too large (maximum is %d)", desc, num, max);
331	return ((int)n);
332}
333
334static void
335usage(void)
336{
337
338	fprintf(stderr, "Usage: tunefs [-AFN] tuneup-options special-device\n");
339	fprintf(stderr, "where tuneup-options are:\n");
340	fprintf(stderr, "\t-d rotational delay between contiguous blocks\n");
341	fprintf(stderr, "\t-a maximum contiguous blocks\n");
342	fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n");
343	fprintf(stderr, "\t-m minimum percentage of free space\n");
344	fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
345#ifdef TUNEFS_SOFTDEP
346	fprintf(stderr, "\t-n soft dependencies (`enable' or `disable')\n");
347#endif
348	fprintf(stderr, "\t-t track skew in sectors\n");
349	exit(2);
350}
351
352static void
353getsb(struct fs *fs, const char *file)
354{
355
356	fi = open(file, 0);
357	if (fi < 0)
358		err(3, "cannot open %s for reading", file);
359	if (bread((daddr_t)SBOFF, (char *)fs, SBSIZE))
360		err(4, "%s: bad super block", file);
361	if (fs->fs_magic != FS_MAGIC) {
362		if (fs->fs_magic == bswap32(FS_MAGIC)) {
363			warnx("%s: swapping byte order", file);
364			needswap = 1;
365			ffs_sb_swap(fs, fs);
366		} else
367			err(5, "%s: bad magic number", file);
368	}
369	dev_bsize = fs->fs_fsize / fsbtodb(fs, 1);
370	close(fi);
371}
372
373static void
374bwrite(daddr_t blk, char *buffer, int size)
375{
376
377	if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0)
378		err(6, "FS SEEK");
379	if (write(fi, buffer, size) != size)
380		err(7, "FS WRITE");
381}
382
383static int
384bread(daddr_t bno, char *buffer, int cnt)
385{
386	int i;
387
388	if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0)
389		return(1);
390	if ((i = read(fi, buffer, cnt)) != cnt) {
391		for(i=0; i<sblock.fs_bsize; i++)
392			buf[i] = 0;
393		return (1);
394	}
395	return (0);
396}
397