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