tunefs.c revision 79750
11558Srgrimes/*
21558Srgrimes * Copyright (c) 1983, 1993
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * Redistribution and use in source and binary forms, with or without
61558Srgrimes * modification, are permitted provided that the following conditions
71558Srgrimes * are met:
81558Srgrimes * 1. Redistributions of source code must retain the above copyright
91558Srgrimes *    notice, this list of conditions and the following disclaimer.
101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111558Srgrimes *    notice, this list of conditions and the following disclaimer in the
121558Srgrimes *    documentation and/or other materials provided with the distribution.
131558Srgrimes * 3. All advertising materials mentioning features or use of this software
141558Srgrimes *    must display the following acknowledgement:
151558Srgrimes *	This product includes software developed by the University of
161558Srgrimes *	California, Berkeley and its contributors.
171558Srgrimes * 4. Neither the name of the University nor the names of its contributors
181558Srgrimes *    may be used to endorse or promote products derived from this software
191558Srgrimes *    without specific prior written permission.
201558Srgrimes *
211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311558Srgrimes * SUCH DAMAGE.
321558Srgrimes */
331558Srgrimes
341558Srgrimes#ifndef lint
3538040Scharnierstatic const char copyright[] =
361558Srgrimes"@(#) Copyright (c) 1983, 1993\n\
371558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381558Srgrimes#endif /* not lint */
391558Srgrimes
401558Srgrimes#ifndef lint
4138040Scharnier#if 0
421558Srgrimesstatic char sccsid[] = "@(#)tunefs.c	8.2 (Berkeley) 4/19/94";
4338040Scharnier#endif
4438040Scharnierstatic const char rcsid[] =
4550476Speter  "$FreeBSD: head/sbin/tunefs/tunefs.c 79750 2001-07-15 05:47:47Z dd $";
461558Srgrimes#endif /* not lint */
471558Srgrimes
481558Srgrimes/*
491558Srgrimes * tunefs: change layout parameters to an existing file system.
501558Srgrimes */
511558Srgrimes#include <sys/param.h>
5242873Sluoqi#include <sys/mount.h>
531558Srgrimes#include <sys/stat.h>
541558Srgrimes
551558Srgrimes#include <ufs/ffs/fs.h>
5642873Sluoqi#include <ufs/ufs/ufsmount.h>
571558Srgrimes
581558Srgrimes#include <err.h>
591558Srgrimes#include <fcntl.h>
601558Srgrimes#include <fstab.h>
6138040Scharnier#include <paths.h>
621558Srgrimes#include <stdio.h>
631558Srgrimes#include <stdlib.h>
6458047Ssheldonh#include <string.h>
651558Srgrimes#include <unistd.h>
661558Srgrimes
671558Srgrimes/* the optimization warning string template */
681558Srgrimes#define	OPTWARN	"should optimize for %s with minfree %s %d%%"
691558Srgrimes
701558Srgrimesunion {
711558Srgrimes	struct	fs sb;
721558Srgrimes	char pad[MAXBSIZE];
731558Srgrimes} sbun;
741558Srgrimes#define	sblock sbun.sb
751558Srgrimes
761558Srgrimesint fi;
771558Srgrimeslong dev_bsize = 1;
781558Srgrimes
7979750Sddvoid bwrite __P((daddr_t, const char *, int));
8058047Ssheldonhint bread __P((daddr_t, char *, int));
8179750Sddvoid getsb __P((struct fs *, const char *));
8279750Sddvoid putsb __P((struct fs *, const char *, int));
831558Srgrimesvoid usage __P((void));
849315Sjoergvoid printfs __P((void));
851558Srgrimes
861558Srgrimesint
871558Srgrimesmain(argc, argv)
881558Srgrimes	int argc;
891558Srgrimes	char *argv[];
901558Srgrimes{
9179750Sdd	char *special;
9279750Sdd	const char *name;
931558Srgrimes	struct stat st;
9442873Sluoqi	int Aflag = 0, active = 0;
9575377Smckusick	int aflag = 0, dflag = 0, eflag = 0, fflag = 0, mflag = 0;
9675377Smckusick	int nflag = 0, oflag = 0, pflag = 0, sflag = 0;
9775377Smckusick	int avalue = 0, dvalue = 0, evalue = 0, fvalue = 0;
9875377Smckusick	int mvalue = 0, ovalue = 0, svalue = 0;
9969829Scharnier	char *nvalue = NULL;
1001558Srgrimes	struct fstab *fs;
10179750Sdd	const char *chg[2];
10279750Sdd	char device[MAXPATHLEN];
10342873Sluoqi	struct ufs_args args;
10442873Sluoqi	struct statfs stfs;
10569314Scharnier	int found_arg, ch;
1061558Srgrimes
10769314Scharnier        if (argc < 3)
10869314Scharnier                usage();
10969314Scharnier	found_arg = 0; /* at least one arg is required */
11075377Smckusick	while ((ch = getopt(argc, argv, "Aa:d:e:f:m:n:o:ps:")) != -1)
11169314Scharnier	  switch (ch) {
11269314Scharnier	  case 'A':
11369314Scharnier		found_arg = 1;
11469314Scharnier		Aflag++;
11569314Scharnier		break;
11669314Scharnier	  case 'a':
11769314Scharnier		found_arg = 1;
11869314Scharnier		name = "maximum contiguous block count";
11969829Scharnier		avalue = atoi(optarg);
12069829Scharnier		if (avalue < 1)
12169314Scharnier			errx(10, "%s must be >= 1 (was %s)", name, optarg);
12269829Scharnier		aflag = 1;
12369314Scharnier		break;
12469314Scharnier	  case 'd':
12569314Scharnier		found_arg = 1;
12669314Scharnier		name = "rotational delay between contiguous blocks";
12769829Scharnier		dvalue = atoi(optarg);
12869829Scharnier		dflag = 1;
12969314Scharnier		break;
13069314Scharnier	  case 'e':
13169314Scharnier		found_arg = 1;
13269314Scharnier		name = "maximum blocks per file in a cylinder group";
13369829Scharnier		evalue = atoi(optarg);
13469829Scharnier		if (evalue < 1)
13569314Scharnier			errx(10, "%s must be >= 1 (was %s)", name, optarg);
13669829Scharnier		eflag = 1;
13769314Scharnier		break;
13875377Smckusick	  case 'f':
13975377Smckusick		found_arg = 1;
14075377Smckusick		name = "average file size";
14175377Smckusick		fvalue = atoi(optarg);
14275377Smckusick		if (fvalue < 1)
14375377Smckusick			errx(10, "%s must be >= 1 (was %s)", name, optarg);
14475377Smckusick		fflag = 1;
14575377Smckusick		break;
14669314Scharnier	  case 'm':
14769314Scharnier		found_arg = 1;
14869314Scharnier		name = "minimum percentage of free space";
14969829Scharnier		mvalue = atoi(optarg);
15069829Scharnier		if (mvalue < 0 || mvalue > 99)
15169314Scharnier			errx(10, "bad %s (%s)", name, optarg);
15269829Scharnier		mflag = 1;
15369314Scharnier		break;
15469314Scharnier	  case 'n':
15569314Scharnier		found_arg = 1;
15669314Scharnier 		name = "soft updates";
15769829Scharnier 		nvalue = optarg;
15869829Scharnier                if (strcmp(nvalue, "enable") && strcmp(nvalue, "disable")) {
15969314Scharnier 			errx(10, "bad %s (options are %s)",
16069314Scharnier 			    name, "`enable' or `disable'");
16169314Scharnier 		}
16269829Scharnier		nflag = 1;
16369314Scharnier 		break;
16469314Scharnier	  case 'o':
16569314Scharnier		found_arg = 1;
16669314Scharnier		name = "optimization preference";
16769314Scharnier		chg[FS_OPTSPACE] = "space";
16869314Scharnier		chg[FS_OPTTIME] = "time";
16969314Scharnier		if (strcmp(optarg, chg[FS_OPTSPACE]) == 0)
17069829Scharnier			ovalue = FS_OPTSPACE;
17169314Scharnier		else if (strcmp(optarg, chg[FS_OPTTIME]) == 0)
17269829Scharnier			ovalue = FS_OPTTIME;
17369314Scharnier		else
17469314Scharnier			errx(10, "bad %s (options are `space' or `time')",
1751558Srgrimes					    name);
17669829Scharnier		oflag = 1;
17769314Scharnier		break;
17869314Scharnier	  case 'p':
17971790Sben		found_arg = 1;
18069829Scharnier		pflag = 1;
18169829Scharnier		break;
18275377Smckusick	  case 's':
18375377Smckusick		found_arg = 1;
18475377Smckusick		name = "expected number of files per directory";
18575377Smckusick		svalue = atoi(optarg);
18675377Smckusick		if (svalue < 1)
18775377Smckusick			errx(10, "%s must be >= 1 (was %s)", name, optarg);
18875377Smckusick		sflag = 1;
18975377Smckusick		break;
19069314Scharnier	  default:
19169314Scharnier		usage();
19269314Scharnier	  }
19369314Scharnier	argc -= optind;
19469314Scharnier	argv += optind;
1951558Srgrimes
19669314Scharnier	if (found_arg == 0 || argc != 1)
19769314Scharnier	  usage();
19869314Scharnier
19969829Scharnier	special = argv[0];
20069829Scharnier	fs = getfsfile(special);
20169829Scharnier	if (fs) {
20269829Scharnier		if (statfs(special, &stfs) == 0 &&
20369829Scharnier		    strcmp(special, stfs.f_mntonname) == 0) {
20469829Scharnier			active = 1;
20569829Scharnier		}
20669829Scharnier		special = fs->fs_spec;
20769829Scharnier	}
20869829Scharnieragain:
20969829Scharnier	if (stat(special, &st) < 0) {
21069829Scharnier		if (*special != '/') {
21169829Scharnier			if (*special == 'r')
21269829Scharnier				special++;
21369829Scharnier			(void)sprintf(device, "%s/%s", _PATH_DEV, special);
21469829Scharnier			special = device;
21569829Scharnier			goto again;
21669829Scharnier		}
21769829Scharnier		err(1, "%s", special);
21869829Scharnier	}
21969829Scharnier	if ((st.st_mode & S_IFMT) != S_IFBLK &&
22069829Scharnier	    (st.st_mode & S_IFMT) != S_IFCHR)
22169829Scharnier		errx(10, "%s: not a block or character device", special);
22269829Scharnier	getsb(&sblock, special);
22369829Scharnier
22469829Scharnier	if (pflag) {
22569829Scharnier		printfs();
22669829Scharnier		exit(0);
22769829Scharnier	}
22869829Scharnier	if (aflag) {
22969829Scharnier		name = "maximum contiguous block count";
23069829Scharnier		if (sblock.fs_maxcontig == avalue) {
23169829Scharnier			warnx("%s remains unchanged as %d", name, avalue);
23269829Scharnier		}
23369829Scharnier		else {
23469829Scharnier			warnx("%s changes from %d to %d",
23569829Scharnier					name, sblock.fs_maxcontig, avalue);
23669829Scharnier			sblock.fs_maxcontig = avalue;
23769829Scharnier		}
23869829Scharnier	}
23969829Scharnier	if (dflag) {
24069829Scharnier		name = "rotational delay between contiguous blocks";
24169829Scharnier		if (sblock.fs_rotdelay == dvalue) {
24269829Scharnier			warnx("%s remains unchanged as %dms", name, dvalue);
24369829Scharnier		}
24469829Scharnier		else {
24569829Scharnier			warnx("%s changes from %dms to %dms",
24669829Scharnier				    name, sblock.fs_rotdelay, dvalue);
24769829Scharnier			sblock.fs_rotdelay = dvalue;
24869829Scharnier		}
24969829Scharnier	}
25069829Scharnier	if (eflag) {
25169829Scharnier		name = "maximum blocks per file in a cylinder group";
25269829Scharnier		if (sblock.fs_maxbpg == evalue) {
25369829Scharnier			warnx("%s remains unchanged as %d", name, evalue);
25469829Scharnier		}
25569829Scharnier		else {
25669829Scharnier			warnx("%s changes from %d to %d",
25769829Scharnier					name, sblock.fs_maxbpg, evalue);
25869829Scharnier			sblock.fs_maxbpg = evalue;
25969829Scharnier		}
26069829Scharnier	}
26175377Smckusick	if (fflag) {
26275377Smckusick		name = "average file size";
26375377Smckusick		if (sblock.fs_avgfilesize == fvalue) {
26475377Smckusick			warnx("%s remains unchanged as %d", name, fvalue);
26575377Smckusick		}
26675377Smckusick		else {
26775377Smckusick			warnx("%s changes from %d to %d",
26875377Smckusick					name, sblock.fs_avgfilesize, fvalue);
26975377Smckusick			sblock.fs_avgfilesize = fvalue;
27075377Smckusick		}
27175377Smckusick	}
27269829Scharnier	if (mflag) {
27369829Scharnier		name = "minimum percentage of free space";
27469829Scharnier		if (sblock.fs_minfree == mvalue) {
27569829Scharnier			warnx("%s remains unchanged as %d%%", name, mvalue);
27669829Scharnier		}
27769829Scharnier		else {
27869829Scharnier			warnx("%s changes from %d%% to %d%%",
27969829Scharnier				    name, sblock.fs_minfree, mvalue);
28069829Scharnier			sblock.fs_minfree = mvalue;
28169829Scharnier			if (mvalue >= MINFREE && sblock.fs_optim == FS_OPTSPACE)
28269829Scharnier				warnx(OPTWARN, "time", ">=", MINFREE);
28369829Scharnier			if (mvalue < MINFREE && sblock.fs_optim == FS_OPTTIME)
28469829Scharnier				warnx(OPTWARN, "space", "<", MINFREE);
28569829Scharnier		}
28669829Scharnier	}
28769829Scharnier	if (nflag) {
28869829Scharnier 		name = "soft updates";
28969829Scharnier 		if (strcmp(nvalue, "enable") == 0) {
29075498Smckusick			if (sblock.fs_flags & FS_DOSOFTDEP) {
29169829Scharnier				warnx("%s remains unchanged as enabled", name);
29275498Smckusick			} else if (sblock.fs_clean == 0) {
29375498Smckusick				warnx("%s cannot be enabled until fsck is run",
29475498Smckusick				    name);
29569829Scharnier			} else {
29669829Scharnier 				sblock.fs_flags |= FS_DOSOFTDEP;
29769829Scharnier 				warnx("%s set", name);
29869829Scharnier			}
29969829Scharnier 		} else if (strcmp(nvalue, "disable") == 0) {
30069829Scharnier			if ((~sblock.fs_flags & FS_DOSOFTDEP) == FS_DOSOFTDEP) {
30169829Scharnier				warnx("%s remains unchanged as disabled", name);
30269829Scharnier			} else {
30369829Scharnier 				sblock.fs_flags &= ~FS_DOSOFTDEP;
30469829Scharnier 				warnx("%s cleared", name);
30569829Scharnier			}
30669829Scharnier 		}
30769829Scharnier	}
30869829Scharnier	if (oflag) {
30969829Scharnier		name = "optimization preference";
31069829Scharnier		chg[FS_OPTSPACE] = "space";
31169829Scharnier		chg[FS_OPTTIME] = "time";
31269829Scharnier		if (sblock.fs_optim == ovalue) {
31369829Scharnier			warnx("%s remains unchanged as %s", name, chg[ovalue]);
31469829Scharnier		}
31569829Scharnier		else {
31669829Scharnier			warnx("%s changes from %s to %s",
31769829Scharnier				    name, chg[sblock.fs_optim], chg[ovalue]);
31869829Scharnier			sblock.fs_optim = ovalue;
31969829Scharnier			if (sblock.fs_minfree >= MINFREE &&
32069829Scharnier					ovalue == FS_OPTSPACE)
32169829Scharnier				warnx(OPTWARN, "time", ">=", MINFREE);
32269829Scharnier			if (sblock.fs_minfree < MINFREE &&
32369829Scharnier					ovalue == FS_OPTTIME)
32469829Scharnier				warnx(OPTWARN, "space", "<", MINFREE);
32569829Scharnier		}
32669829Scharnier	}
32775377Smckusick	if (sflag) {
32875377Smckusick		name = "expected number of files per directory";
32975377Smckusick		if (sblock.fs_avgfpdir == svalue) {
33075377Smckusick			warnx("%s remains unchanged as %d", name, svalue);
33175377Smckusick		}
33275377Smckusick		else {
33375377Smckusick			warnx("%s changes from %d to %d",
33475377Smckusick					name, sblock.fs_avgfpdir, svalue);
33575377Smckusick			sblock.fs_avgfpdir = svalue;
33675377Smckusick		}
33775377Smckusick	}
33869829Scharnier
33958047Ssheldonh	putsb(&sblock, special, Aflag);
34042873Sluoqi	if (active) {
34142873Sluoqi		bzero(&args, sizeof(args));
34242873Sluoqi		if (mount("ufs", fs->fs_file,
34342873Sluoqi		    stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0)
34442873Sluoqi			err(9, "%s: reload", special);
34542873Sluoqi		warnx("file system reloaded");
34642873Sluoqi	}
3471558Srgrimes	exit(0);
3481558Srgrimes}
3491558Srgrimes
3501558Srgrimesvoid
3511558Srgrimesusage()
3521558Srgrimes{
35338040Scharnier	fprintf(stderr, "%s\n%s\n%s\n",
35475377Smckusick"usage: tunefs [-A] [-a maxcontig] [-d rotdelay] [-e maxbpg] [-f avgfilesize]",
35575377Smckusick"              [-m minfree] [-p] [-n enable | disable] [-o space | time]",
35675377Smckusick"              [-s filesperdir] special | filesystem");
3571558Srgrimes	exit(2);
3581558Srgrimes}
3591558Srgrimes
3601558Srgrimesvoid
3611558Srgrimesgetsb(fs, file)
36279750Sdd	struct fs *fs;
36379750Sdd	const char *file;
3641558Srgrimes{
3651558Srgrimes
36658047Ssheldonh	fi = open(file, O_RDONLY);
3671558Srgrimes	if (fi < 0)
3681558Srgrimes		err(3, "cannot open %s", file);
3691558Srgrimes	if (bread((daddr_t)SBOFF, (char *)fs, SBSIZE))
3701558Srgrimes		err(4, "%s: bad super block", file);
3711558Srgrimes	if (fs->fs_magic != FS_MAGIC)
3721558Srgrimes		err(5, "%s: bad magic number", file);
3731558Srgrimes	dev_bsize = fs->fs_fsize / fsbtodb(fs, 1);
3741558Srgrimes}
3751558Srgrimes
3761558Srgrimesvoid
37758047Ssheldonhputsb(fs, file, all)
37879750Sdd	struct fs *fs;
37979750Sdd	const char *file;
38058047Ssheldonh	int all;
38158047Ssheldonh{
38258047Ssheldonh	int i;
38358047Ssheldonh
38458047Ssheldonh	/*
38558047Ssheldonh	 * Re-open the device read-write. Use the read-only file
38658047Ssheldonh	 * descriptor as an interlock to prevent the device from
38758047Ssheldonh	 * being mounted while we are switching mode.
38858047Ssheldonh	 */
38958047Ssheldonh	i = fi;
39058047Ssheldonh	fi = open(file, O_RDWR);
39158047Ssheldonh	close(i);
39258047Ssheldonh	if (fi < 0)
39358047Ssheldonh		err(3, "cannot open %s", file);
39479750Sdd	bwrite((daddr_t)SBOFF / dev_bsize, (const char *)fs, SBSIZE);
39558047Ssheldonh	if (all)
39658047Ssheldonh		for (i = 0; i < fs->fs_ncg; i++)
39758047Ssheldonh			bwrite(fsbtodb(fs, cgsblock(fs, i)),
39879750Sdd			    (const char *)fs, SBSIZE);
39958047Ssheldonh	close(fi);
40058047Ssheldonh}
40158047Ssheldonh
40258047Ssheldonhvoid
4039315Sjoergprintfs()
4049315Sjoerg{
40534266Sjulian	warnx("soft updates:  (-n)                                %s",
40634266Sjulian		(sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled");
4079315Sjoerg	warnx("maximum contiguous block count: (-a)               %d",
4089315Sjoerg	      sblock.fs_maxcontig);
4099315Sjoerg	warnx("rotational delay between contiguous blocks: (-d)   %d ms",
4109315Sjoerg	      sblock.fs_rotdelay);
4119315Sjoerg	warnx("maximum blocks per file in a cylinder group: (-e)  %d",
4129315Sjoerg	      sblock.fs_maxbpg);
41375377Smckusick	warnx("average file size: (-f)                            %d",
41475377Smckusick	      sblock.fs_avgfilesize);
41575377Smckusick	warnx("average number of files in a directory: (-s)       %d",
41675377Smckusick	      sblock.fs_avgfpdir);
4179315Sjoerg	warnx("minimum percentage of free space: (-m)             %d%%",
4189315Sjoerg	      sblock.fs_minfree);
4199315Sjoerg	warnx("optimization preference: (-o)                      %s",
4209315Sjoerg	      sblock.fs_optim == FS_OPTSPACE ? "space" : "time");
4219315Sjoerg	if (sblock.fs_minfree >= MINFREE &&
4229315Sjoerg	    sblock.fs_optim == FS_OPTSPACE)
4239315Sjoerg		warnx(OPTWARN, "time", ">=", MINFREE);
4249315Sjoerg	if (sblock.fs_minfree < MINFREE &&
4259315Sjoerg	    sblock.fs_optim == FS_OPTTIME)
4269315Sjoerg		warnx(OPTWARN, "space", "<", MINFREE);
4279315Sjoerg}
4289315Sjoerg
4299315Sjoergvoid
4301558Srgrimesbwrite(blk, buf, size)
4311558Srgrimes	daddr_t blk;
43279750Sdd	const char *buf;
4331558Srgrimes	int size;
4341558Srgrimes{
4351558Srgrimes
4361558Srgrimes	if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0)
4371558Srgrimes		err(6, "FS SEEK");
4381558Srgrimes	if (write(fi, buf, size) != size)
4391558Srgrimes		err(7, "FS WRITE");
4401558Srgrimes}
4411558Srgrimes
4421558Srgrimesint
4431558Srgrimesbread(bno, buf, cnt)
4441558Srgrimes	daddr_t bno;
4451558Srgrimes	char *buf;
4461558Srgrimes	int cnt;
4471558Srgrimes{
4481558Srgrimes	int i;
4491558Srgrimes
4501558Srgrimes	if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0)
4511558Srgrimes		return(1);
4521558Srgrimes	if ((i = read(fi, buf, cnt)) != cnt) {
4531558Srgrimes		for(i=0; i<sblock.fs_bsize; i++)
4541558Srgrimes			buf[i] = 0;
4551558Srgrimes		return (1);
4561558Srgrimes	}
4571558Srgrimes	return (0);
4581558Srgrimes}
459