tunefs.c revision 203769
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 * 4. 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
30#if 0
31#ifndef lint
32static const char copyright[] =
33"@(#) Copyright (c) 1983, 1993\n\
34	The Regents of the University of California.  All rights reserved.\n";
35#endif /* not lint */
36
37#ifndef lint
38static char sccsid[] = "@(#)tunefs.c	8.2 (Berkeley) 4/19/94";
39#endif /* not lint */
40#endif
41#include <sys/cdefs.h>
42__FBSDID("$FreeBSD: head/sbin/tunefs/tunefs.c 203769 2010-02-11 06:33:35Z mckusick $");
43
44/*
45 * tunefs: change layout parameters to an existing file system.
46 */
47#include <sys/param.h>
48#include <sys/mount.h>
49#include <sys/disklabel.h>
50#include <sys/stat.h>
51
52#include <ufs/ufs/ufsmount.h>
53#include <ufs/ufs/dinode.h>
54#include <ufs/ffs/fs.h>
55
56#include <ctype.h>
57#include <err.h>
58#include <fcntl.h>
59#include <fstab.h>
60#include <libufs.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
70struct uufsd disk;
71#define	sblock disk.d_fs
72
73void usage(void);
74void printfs(void);
75
76int
77main(int argc, char *argv[])
78{
79	char *avalue, *Jvalue, *Lvalue, *lvalue, *Nvalue, *nvalue;
80	const char *special, *on;
81	const char *name;
82	int active;
83	int Aflag, aflag, eflag, evalue, fflag, fvalue, Jflag, Lflag, lflag;
84	int mflag, mvalue, Nflag, nflag, oflag, ovalue, pflag, sflag, svalue;
85	int ch, found_arg, i;
86	const char *chg[2];
87	struct ufs_args args;
88	struct statfs stfs;
89
90	if (argc < 3)
91		usage();
92	Aflag = aflag = eflag = fflag = Jflag = Lflag = lflag = mflag = 0;
93	Nflag = nflag = oflag = pflag = sflag = 0;
94	avalue = Jvalue = Lvalue = lvalue = Nvalue = nvalue = NULL;
95	evalue = fvalue = mvalue = ovalue = svalue = 0;
96	active = 0;
97	found_arg = 0;		/* At least one arg is required. */
98	while ((ch = getopt(argc, argv, "Aa:e:f:J:L:l:m:N:n:o:ps:")) != -1)
99		switch (ch) {
100
101		case 'A':
102			found_arg = 1;
103			Aflag++;
104			break;
105
106		case 'a':
107			found_arg = 1;
108			name = "POSIX.1e ACLs";
109			avalue = optarg;
110			if (strcmp(avalue, "enable") &&
111			    strcmp(avalue, "disable")) {
112				errx(10, "bad %s (options are %s)",
113				    name, "`enable' or `disable'");
114			}
115			aflag = 1;
116			break;
117
118		case 'e':
119			found_arg = 1;
120			name = "maximum blocks per file in a cylinder group";
121			evalue = atoi(optarg);
122			if (evalue < 1)
123				errx(10, "%s must be >= 1 (was %s)",
124				    name, optarg);
125			eflag = 1;
126			break;
127
128		case 'f':
129			found_arg = 1;
130			name = "average file size";
131			fvalue = atoi(optarg);
132			if (fvalue < 1)
133				errx(10, "%s must be >= 1 (was %s)",
134				    name, optarg);
135			fflag = 1;
136			break;
137
138		case 'J':
139			found_arg = 1;
140			name = "gjournaled file system";
141			Jvalue = optarg;
142			if (strcmp(Jvalue, "enable") &&
143			    strcmp(Jvalue, "disable")) {
144				errx(10, "bad %s (options are %s)",
145				    name, "`enable' or `disable'");
146			}
147			Jflag = 1;
148			break;
149
150
151		case 'L':
152			found_arg = 1;
153			name = "volume label";
154			Lvalue = optarg;
155			i = -1;
156			while (isalnum(Lvalue[++i]));
157			if (Lvalue[i] != '\0') {
158				errx(10,
159				"bad %s. Valid characters are alphanumerics.",
160				    name);
161			}
162			if (strlen(Lvalue) >= MAXVOLLEN) {
163				errx(10, "bad %s. Length is longer than %d.",
164				    name, MAXVOLLEN - 1);
165			}
166			Lflag = 1;
167			break;
168
169		case 'l':
170			found_arg = 1;
171			name = "multilabel MAC file system";
172			lvalue = optarg;
173			if (strcmp(lvalue, "enable") &&
174			    strcmp(lvalue, "disable")) {
175				errx(10, "bad %s (options are %s)",
176				    name, "`enable' or `disable'");
177			}
178			lflag = 1;
179			break;
180
181		case 'm':
182			found_arg = 1;
183			name = "minimum percentage of free space";
184			mvalue = atoi(optarg);
185			if (mvalue < 0 || mvalue > 99)
186				errx(10, "bad %s (%s)", name, optarg);
187			mflag = 1;
188			break;
189
190		case 'N':
191			found_arg = 1;
192			name = "NFSv4 ACLs";
193			Nvalue = optarg;
194			if (strcmp(Nvalue, "enable") &&
195			    strcmp(Nvalue, "disable")) {
196				errx(10, "bad %s (options are %s)",
197				    name, "`enable' or `disable'");
198			}
199			Nflag = 1;
200			break;
201
202		case 'n':
203			found_arg = 1;
204			name = "soft updates";
205			nvalue = optarg;
206			if (strcmp(nvalue, "enable") != 0 &&
207			    strcmp(nvalue, "disable") != 0) {
208				errx(10, "bad %s (options are %s)",
209				    name, "`enable' or `disable'");
210			}
211			nflag = 1;
212			break;
213
214		case 'o':
215			found_arg = 1;
216			name = "optimization preference";
217			if (strcmp(optarg, "space") == 0)
218				ovalue = FS_OPTSPACE;
219			else if (strcmp(optarg, "time") == 0)
220				ovalue = FS_OPTTIME;
221			else
222				errx(10,
223				    "bad %s (options are `space' or `time')",
224				    name);
225			oflag = 1;
226			break;
227
228		case 'p':
229			found_arg = 1;
230			pflag = 1;
231			break;
232
233		case 's':
234			found_arg = 1;
235			name = "expected number of files per directory";
236			svalue = atoi(optarg);
237			if (svalue < 1)
238				errx(10, "%s must be >= 1 (was %s)",
239				    name, optarg);
240			sflag = 1;
241			break;
242
243		default:
244			usage();
245		}
246	argc -= optind;
247	argv += optind;
248	if (found_arg == 0 || argc != 1)
249		usage();
250
251	on = special = argv[0];
252	if (ufs_disk_fillout(&disk, special) == -1)
253		goto err;
254	if (disk.d_name != special) {
255		special = disk.d_name;
256		if (statfs(special, &stfs) == 0 &&
257		    strcmp(special, stfs.f_mntonname) == 0)
258			active = 1;
259	}
260
261	if (pflag) {
262		printfs();
263		exit(0);
264	}
265	if (Lflag) {
266		name = "volume label";
267		strlcpy(sblock.fs_volname, Lvalue, MAXVOLLEN);
268	}
269	if (aflag) {
270		name = "POSIX.1e ACLs";
271		if (strcmp(avalue, "enable") == 0) {
272			if (sblock.fs_flags & FS_ACLS) {
273				warnx("%s remains unchanged as enabled", name);
274			} else if (sblock.fs_flags & FS_NFS4ACLS) {
275				warnx("%s and NFSv4 ACLs are mutually "
276				    "exclusive", name);
277			} else {
278				sblock.fs_flags |= FS_ACLS;
279				warnx("%s set", name);
280			}
281		} else if (strcmp(avalue, "disable") == 0) {
282			if ((~sblock.fs_flags & FS_ACLS) ==
283			    FS_ACLS) {
284				warnx("%s remains unchanged as disabled",
285				    name);
286			} else {
287				sblock.fs_flags &= ~FS_ACLS;
288				warnx("%s cleared", name);
289			}
290		}
291	}
292	if (eflag) {
293		name = "maximum blocks per file in a cylinder group";
294		if (sblock.fs_maxbpg == evalue)
295			warnx("%s remains unchanged as %d", name, evalue);
296		else {
297			warnx("%s changes from %d to %d",
298			    name, sblock.fs_maxbpg, evalue);
299			sblock.fs_maxbpg = evalue;
300		}
301	}
302	if (fflag) {
303		name = "average file size";
304		if (sblock.fs_avgfilesize == (unsigned)fvalue) {
305			warnx("%s remains unchanged as %d", name, fvalue);
306		}
307		else {
308			warnx("%s changes from %d to %d",
309					name, sblock.fs_avgfilesize, fvalue);
310			sblock.fs_avgfilesize = fvalue;
311		}
312	}
313	if (Jflag) {
314		name = "gjournal";
315		if (strcmp(Jvalue, "enable") == 0) {
316			if (sblock.fs_flags & FS_GJOURNAL) {
317				warnx("%s remains unchanged as enabled", name);
318			} else {
319				sblock.fs_flags |= FS_GJOURNAL;
320				warnx("%s set", name);
321			}
322		} else if (strcmp(Jvalue, "disable") == 0) {
323			if ((~sblock.fs_flags & FS_GJOURNAL) ==
324			    FS_GJOURNAL) {
325				warnx("%s remains unchanged as disabled",
326				    name);
327			} else {
328				sblock.fs_flags &= ~FS_GJOURNAL;
329				warnx("%s cleared", name);
330			}
331		}
332	}
333	if (lflag) {
334		name = "multilabel";
335		if (strcmp(lvalue, "enable") == 0) {
336			if (sblock.fs_flags & FS_MULTILABEL) {
337				warnx("%s remains unchanged as enabled", name);
338			} else {
339				sblock.fs_flags |= FS_MULTILABEL;
340				warnx("%s set", name);
341			}
342		} else if (strcmp(lvalue, "disable") == 0) {
343			if ((~sblock.fs_flags & FS_MULTILABEL) ==
344			    FS_MULTILABEL) {
345				warnx("%s remains unchanged as disabled",
346				    name);
347			} else {
348				sblock.fs_flags &= ~FS_MULTILABEL;
349				warnx("%s cleared", name);
350			}
351		}
352	}
353	if (mflag) {
354		name = "minimum percentage of free space";
355		if (sblock.fs_minfree == mvalue)
356			warnx("%s remains unchanged as %d%%", name, mvalue);
357		else {
358			warnx("%s changes from %d%% to %d%%",
359				    name, sblock.fs_minfree, mvalue);
360			sblock.fs_minfree = mvalue;
361			if (mvalue >= MINFREE && sblock.fs_optim == FS_OPTSPACE)
362				warnx(OPTWARN, "time", ">=", MINFREE);
363			if (mvalue < MINFREE && sblock.fs_optim == FS_OPTTIME)
364				warnx(OPTWARN, "space", "<", MINFREE);
365		}
366	}
367	if (Nflag) {
368		name = "NFSv4 ACLs";
369		if (strcmp(Nvalue, "enable") == 0) {
370			if (sblock.fs_flags & FS_NFS4ACLS) {
371				warnx("%s remains unchanged as enabled", name);
372			} else if (sblock.fs_flags & FS_ACLS) {
373				warnx("%s and POSIX.1e ACLs are mutually "
374				    "exclusive", name);
375			} else {
376				sblock.fs_flags |= FS_NFS4ACLS;
377				warnx("%s set", name);
378			}
379		} else if (strcmp(Nvalue, "disable") == 0) {
380			if ((~sblock.fs_flags & FS_NFS4ACLS) ==
381			    FS_NFS4ACLS) {
382				warnx("%s remains unchanged as disabled",
383				    name);
384			} else {
385				sblock.fs_flags &= ~FS_NFS4ACLS;
386				warnx("%s cleared", name);
387			}
388		}
389	}
390	if (nflag) {
391 		name = "soft updates";
392 		if (strcmp(nvalue, "enable") == 0) {
393			if (sblock.fs_flags & FS_DOSOFTDEP)
394				warnx("%s remains unchanged as enabled", name);
395			else if (sblock.fs_clean == 0) {
396				warnx("%s cannot be enabled until fsck is run",
397				    name);
398			} else {
399 				sblock.fs_flags |= FS_DOSOFTDEP;
400 				warnx("%s set", name);
401			}
402 		} else if (strcmp(nvalue, "disable") == 0) {
403			if ((~sblock.fs_flags & FS_DOSOFTDEP) == FS_DOSOFTDEP)
404				warnx("%s remains unchanged as disabled", name);
405			else {
406 				sblock.fs_flags &= ~FS_DOSOFTDEP;
407 				warnx("%s cleared", name);
408			}
409 		}
410	}
411	if (oflag) {
412		name = "optimization preference";
413		chg[FS_OPTSPACE] = "space";
414		chg[FS_OPTTIME] = "time";
415		if (sblock.fs_optim == ovalue)
416			warnx("%s remains unchanged as %s", name, chg[ovalue]);
417		else {
418			warnx("%s changes from %s to %s",
419				    name, chg[sblock.fs_optim], chg[ovalue]);
420			sblock.fs_optim = ovalue;
421			if (sblock.fs_minfree >= MINFREE &&
422			    ovalue == FS_OPTSPACE)
423				warnx(OPTWARN, "time", ">=", MINFREE);
424			if (sblock.fs_minfree < MINFREE && ovalue == FS_OPTTIME)
425				warnx(OPTWARN, "space", "<", MINFREE);
426		}
427	}
428	if (sflag) {
429		name = "expected number of files per directory";
430		if (sblock.fs_avgfpdir == (unsigned)svalue) {
431			warnx("%s remains unchanged as %d", name, svalue);
432		}
433		else {
434			warnx("%s changes from %d to %d",
435					name, sblock.fs_avgfpdir, svalue);
436			sblock.fs_avgfpdir = svalue;
437		}
438	}
439
440	if (sbwrite(&disk, Aflag) == -1)
441		goto err;
442	ufs_disk_close(&disk);
443	if (active) {
444		bzero(&args, sizeof(args));
445		if (mount("ufs", on,
446		    stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0)
447			err(9, "%s: reload", special);
448		warnx("file system reloaded");
449	}
450	exit(0);
451err:
452	if (disk.d_error != NULL)
453		errx(11, "%s: %s", special, disk.d_error);
454	else
455		err(12, "%s", special);
456}
457
458void
459usage(void)
460{
461	fprintf(stderr, "%s\n%s\n%s\n%s\n",
462"usage: tunefs [-A] [-a enable | disable] [-e maxbpg] [-f avgfilesize]",
463"              [-J enable | disable ] [-L volname] [-l enable | disable]",
464"              [-m minfree] [-N enable | disable] [-n enable | disable]",
465"              [-o space | time] [-p] [-s avgfpdir] special | filesystem");
466	exit(2);
467}
468
469void
470printfs(void)
471{
472	warnx("POSIX.1e ACLs: (-a)                                %s",
473		(sblock.fs_flags & FS_ACLS)? "enabled" : "disabled");
474	warnx("NFSv4 ACLs: (-N)                                   %s",
475		(sblock.fs_flags & FS_NFS4ACLS)? "enabled" : "disabled");
476	warnx("MAC multilabel: (-l)                               %s",
477		(sblock.fs_flags & FS_MULTILABEL)? "enabled" : "disabled");
478	warnx("soft updates: (-n)                                 %s",
479		(sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled");
480	warnx("gjournal: (-J)                                     %s",
481		(sblock.fs_flags & FS_GJOURNAL)? "enabled" : "disabled");
482	warnx("maximum blocks per file in a cylinder group: (-e)  %d",
483	      sblock.fs_maxbpg);
484	warnx("average file size: (-f)                            %d",
485	      sblock.fs_avgfilesize);
486	warnx("average number of files in a directory: (-s)       %d",
487	      sblock.fs_avgfpdir);
488	warnx("minimum percentage of free space: (-m)             %d%%",
489	      sblock.fs_minfree);
490	warnx("optimization preference: (-o)                      %s",
491	      sblock.fs_optim == FS_OPTSPACE ? "space" : "time");
492	if (sblock.fs_minfree >= MINFREE &&
493	    sblock.fs_optim == FS_OPTSPACE)
494		warnx(OPTWARN, "time", ">=", MINFREE);
495	if (sblock.fs_minfree < MINFREE &&
496	    sblock.fs_optim == FS_OPTTIME)
497		warnx(OPTWARN, "space", "<", MINFREE);
498	warnx("volume label: (-L)                                 %s",
499		sblock.fs_volname);
500}
501