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