tunefs.c revision 75498
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 75498 2001-04-13 23:54:49Z mckusick $";
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
7958047Ssheldonhvoid bwrite __P((daddr_t, char *, int));
8058047Ssheldonhint bread __P((daddr_t, char *, int));
8158047Ssheldonhvoid getsb __P((struct fs *, char *));
8258047Ssheldonhvoid putsb __P((struct fs *, char *, int));
831558Srgrimesvoid usage __P((void));
849315Sjoergvoid printfs __P((void));
851558Srgrimes
861558Srgrimesint
871558Srgrimesmain(argc, argv)
881558Srgrimes	int argc;
891558Srgrimes	char *argv[];
901558Srgrimes{
9169829Scharnier	char *special, *name;
921558Srgrimes	struct stat st;
9342873Sluoqi	int Aflag = 0, active = 0;
9475377Smckusick	int aflag = 0, dflag = 0, eflag = 0, fflag = 0, mflag = 0;
9575377Smckusick	int nflag = 0, oflag = 0, pflag = 0, sflag = 0;
9675377Smckusick	int avalue = 0, dvalue = 0, evalue = 0, fvalue = 0;
9775377Smckusick	int mvalue = 0, ovalue = 0, svalue = 0;
9869829Scharnier	char *nvalue = NULL;
991558Srgrimes	struct fstab *fs;
1001558Srgrimes	char *chg[2], device[MAXPATHLEN];
10142873Sluoqi	struct ufs_args args;
10242873Sluoqi	struct statfs stfs;
10369314Scharnier	int found_arg, ch;
1041558Srgrimes
10569314Scharnier        if (argc < 3)
10669314Scharnier                usage();
10769314Scharnier	found_arg = 0; /* at least one arg is required */
10875377Smckusick	while ((ch = getopt(argc, argv, "Aa:d:e:f:m:n:o:ps:")) != -1)
10969314Scharnier	  switch (ch) {
11069314Scharnier	  case 'A':
11169314Scharnier		found_arg = 1;
11269314Scharnier		Aflag++;
11369314Scharnier		break;
11469314Scharnier	  case 'a':
11569314Scharnier		found_arg = 1;
11669314Scharnier		name = "maximum contiguous block count";
11769829Scharnier		avalue = atoi(optarg);
11869829Scharnier		if (avalue < 1)
11969314Scharnier			errx(10, "%s must be >= 1 (was %s)", name, optarg);
12069829Scharnier		aflag = 1;
12169314Scharnier		break;
12269314Scharnier	  case 'd':
12369314Scharnier		found_arg = 1;
12469314Scharnier		name = "rotational delay between contiguous blocks";
12569829Scharnier		dvalue = atoi(optarg);
12669829Scharnier		dflag = 1;
12769314Scharnier		break;
12869314Scharnier	  case 'e':
12969314Scharnier		found_arg = 1;
13069314Scharnier		name = "maximum blocks per file in a cylinder group";
13169829Scharnier		evalue = atoi(optarg);
13269829Scharnier		if (evalue < 1)
13369314Scharnier			errx(10, "%s must be >= 1 (was %s)", name, optarg);
13469829Scharnier		eflag = 1;
13569314Scharnier		break;
13675377Smckusick	  case 'f':
13775377Smckusick		found_arg = 1;
13875377Smckusick		name = "average file size";
13975377Smckusick		fvalue = atoi(optarg);
14075377Smckusick		if (fvalue < 1)
14175377Smckusick			errx(10, "%s must be >= 1 (was %s)", name, optarg);
14275377Smckusick		fflag = 1;
14375377Smckusick		break;
14469314Scharnier	  case 'm':
14569314Scharnier		found_arg = 1;
14669314Scharnier		name = "minimum percentage of free space";
14769829Scharnier		mvalue = atoi(optarg);
14869829Scharnier		if (mvalue < 0 || mvalue > 99)
14969314Scharnier			errx(10, "bad %s (%s)", name, optarg);
15069829Scharnier		mflag = 1;
15169314Scharnier		break;
15269314Scharnier	  case 'n':
15369314Scharnier		found_arg = 1;
15469314Scharnier 		name = "soft updates";
15569829Scharnier 		nvalue = optarg;
15669829Scharnier                if (strcmp(nvalue, "enable") && strcmp(nvalue, "disable")) {
15769314Scharnier 			errx(10, "bad %s (options are %s)",
15869314Scharnier 			    name, "`enable' or `disable'");
15969314Scharnier 		}
16069829Scharnier		nflag = 1;
16169314Scharnier 		break;
16269314Scharnier	  case 'o':
16369314Scharnier		found_arg = 1;
16469314Scharnier		name = "optimization preference";
16569314Scharnier		chg[FS_OPTSPACE] = "space";
16669314Scharnier		chg[FS_OPTTIME] = "time";
16769314Scharnier		if (strcmp(optarg, chg[FS_OPTSPACE]) == 0)
16869829Scharnier			ovalue = FS_OPTSPACE;
16969314Scharnier		else if (strcmp(optarg, chg[FS_OPTTIME]) == 0)
17069829Scharnier			ovalue = FS_OPTTIME;
17169314Scharnier		else
17269314Scharnier			errx(10, "bad %s (options are `space' or `time')",
1731558Srgrimes					    name);
17469829Scharnier		oflag = 1;
17569314Scharnier		break;
17669314Scharnier	  case 'p':
17771790Sben		found_arg = 1;
17869829Scharnier		pflag = 1;
17969829Scharnier		break;
18075377Smckusick	  case 's':
18175377Smckusick		found_arg = 1;
18275377Smckusick		name = "expected number of files per directory";
18375377Smckusick		svalue = atoi(optarg);
18475377Smckusick		if (svalue < 1)
18575377Smckusick			errx(10, "%s must be >= 1 (was %s)", name, optarg);
18675377Smckusick		sflag = 1;
18775377Smckusick		break;
18869314Scharnier	  default:
18969314Scharnier		usage();
19069314Scharnier	  }
19169314Scharnier	argc -= optind;
19269314Scharnier	argv += optind;
1931558Srgrimes
19469314Scharnier	if (found_arg == 0 || argc != 1)
19569314Scharnier	  usage();
19669314Scharnier
19769829Scharnier	special = argv[0];
19869829Scharnier	fs = getfsfile(special);
19969829Scharnier	if (fs) {
20069829Scharnier		if (statfs(special, &stfs) == 0 &&
20169829Scharnier		    strcmp(special, stfs.f_mntonname) == 0) {
20269829Scharnier			active = 1;
20369829Scharnier		}
20469829Scharnier		special = fs->fs_spec;
20569829Scharnier	}
20669829Scharnieragain:
20769829Scharnier	if (stat(special, &st) < 0) {
20869829Scharnier		if (*special != '/') {
20969829Scharnier			if (*special == 'r')
21069829Scharnier				special++;
21169829Scharnier			(void)sprintf(device, "%s/%s", _PATH_DEV, special);
21269829Scharnier			special = device;
21369829Scharnier			goto again;
21469829Scharnier		}
21569829Scharnier		err(1, "%s", special);
21669829Scharnier	}
21769829Scharnier	if ((st.st_mode & S_IFMT) != S_IFBLK &&
21869829Scharnier	    (st.st_mode & S_IFMT) != S_IFCHR)
21969829Scharnier		errx(10, "%s: not a block or character device", special);
22069829Scharnier	getsb(&sblock, special);
22169829Scharnier
22269829Scharnier	if (pflag) {
22369829Scharnier		printfs();
22469829Scharnier		exit(0);
22569829Scharnier	}
22669829Scharnier	if (aflag) {
22769829Scharnier		name = "maximum contiguous block count";
22869829Scharnier		if (sblock.fs_maxcontig == avalue) {
22969829Scharnier			warnx("%s remains unchanged as %d", name, avalue);
23069829Scharnier		}
23169829Scharnier		else {
23269829Scharnier			warnx("%s changes from %d to %d",
23369829Scharnier					name, sblock.fs_maxcontig, avalue);
23469829Scharnier			sblock.fs_maxcontig = avalue;
23569829Scharnier		}
23669829Scharnier	}
23769829Scharnier	if (dflag) {
23869829Scharnier		name = "rotational delay between contiguous blocks";
23969829Scharnier		if (sblock.fs_rotdelay == dvalue) {
24069829Scharnier			warnx("%s remains unchanged as %dms", name, dvalue);
24169829Scharnier		}
24269829Scharnier		else {
24369829Scharnier			warnx("%s changes from %dms to %dms",
24469829Scharnier				    name, sblock.fs_rotdelay, dvalue);
24569829Scharnier			sblock.fs_rotdelay = dvalue;
24669829Scharnier		}
24769829Scharnier	}
24869829Scharnier	if (eflag) {
24969829Scharnier		name = "maximum blocks per file in a cylinder group";
25069829Scharnier		if (sblock.fs_maxbpg == evalue) {
25169829Scharnier			warnx("%s remains unchanged as %d", name, evalue);
25269829Scharnier		}
25369829Scharnier		else {
25469829Scharnier			warnx("%s changes from %d to %d",
25569829Scharnier					name, sblock.fs_maxbpg, evalue);
25669829Scharnier			sblock.fs_maxbpg = evalue;
25769829Scharnier		}
25869829Scharnier	}
25975377Smckusick	if (fflag) {
26075377Smckusick		name = "average file size";
26175377Smckusick		if (sblock.fs_avgfilesize == fvalue) {
26275377Smckusick			warnx("%s remains unchanged as %d", name, fvalue);
26375377Smckusick		}
26475377Smckusick		else {
26575377Smckusick			warnx("%s changes from %d to %d",
26675377Smckusick					name, sblock.fs_avgfilesize, fvalue);
26775377Smckusick			sblock.fs_avgfilesize = fvalue;
26875377Smckusick		}
26975377Smckusick	}
27069829Scharnier	if (mflag) {
27169829Scharnier		name = "minimum percentage of free space";
27269829Scharnier		if (sblock.fs_minfree == mvalue) {
27369829Scharnier			warnx("%s remains unchanged as %d%%", name, mvalue);
27469829Scharnier		}
27569829Scharnier		else {
27669829Scharnier			warnx("%s changes from %d%% to %d%%",
27769829Scharnier				    name, sblock.fs_minfree, mvalue);
27869829Scharnier			sblock.fs_minfree = mvalue;
27969829Scharnier			if (mvalue >= MINFREE && sblock.fs_optim == FS_OPTSPACE)
28069829Scharnier				warnx(OPTWARN, "time", ">=", MINFREE);
28169829Scharnier			if (mvalue < MINFREE && sblock.fs_optim == FS_OPTTIME)
28269829Scharnier				warnx(OPTWARN, "space", "<", MINFREE);
28369829Scharnier		}
28469829Scharnier	}
28569829Scharnier	if (nflag) {
28669829Scharnier 		name = "soft updates";
28769829Scharnier 		if (strcmp(nvalue, "enable") == 0) {
28875498Smckusick			if (sblock.fs_flags & FS_DOSOFTDEP) {
28969829Scharnier				warnx("%s remains unchanged as enabled", name);
29075498Smckusick			} else if (sblock.fs_clean == 0) {
29175498Smckusick				warnx("%s cannot be enabled until fsck is run",
29275498Smckusick				    name);
29369829Scharnier			} else {
29469829Scharnier 				sblock.fs_flags |= FS_DOSOFTDEP;
29569829Scharnier 				warnx("%s set", name);
29669829Scharnier			}
29769829Scharnier 		} else if (strcmp(nvalue, "disable") == 0) {
29869829Scharnier			if ((~sblock.fs_flags & FS_DOSOFTDEP) == FS_DOSOFTDEP) {
29969829Scharnier				warnx("%s remains unchanged as disabled", name);
30069829Scharnier			} else {
30169829Scharnier 				sblock.fs_flags &= ~FS_DOSOFTDEP;
30269829Scharnier 				warnx("%s cleared", name);
30369829Scharnier			}
30469829Scharnier 		}
30569829Scharnier	}
30669829Scharnier	if (oflag) {
30769829Scharnier		name = "optimization preference";
30869829Scharnier		chg[FS_OPTSPACE] = "space";
30969829Scharnier		chg[FS_OPTTIME] = "time";
31069829Scharnier		if (sblock.fs_optim == ovalue) {
31169829Scharnier			warnx("%s remains unchanged as %s", name, chg[ovalue]);
31269829Scharnier		}
31369829Scharnier		else {
31469829Scharnier			warnx("%s changes from %s to %s",
31569829Scharnier				    name, chg[sblock.fs_optim], chg[ovalue]);
31669829Scharnier			sblock.fs_optim = ovalue;
31769829Scharnier			if (sblock.fs_minfree >= MINFREE &&
31869829Scharnier					ovalue == FS_OPTSPACE)
31969829Scharnier				warnx(OPTWARN, "time", ">=", MINFREE);
32069829Scharnier			if (sblock.fs_minfree < MINFREE &&
32169829Scharnier					ovalue == FS_OPTTIME)
32269829Scharnier				warnx(OPTWARN, "space", "<", MINFREE);
32369829Scharnier		}
32469829Scharnier	}
32575377Smckusick	if (sflag) {
32675377Smckusick		name = "expected number of files per directory";
32775377Smckusick		if (sblock.fs_avgfpdir == svalue) {
32875377Smckusick			warnx("%s remains unchanged as %d", name, svalue);
32975377Smckusick		}
33075377Smckusick		else {
33175377Smckusick			warnx("%s changes from %d to %d",
33275377Smckusick					name, sblock.fs_avgfpdir, svalue);
33375377Smckusick			sblock.fs_avgfpdir = svalue;
33475377Smckusick		}
33575377Smckusick	}
33669829Scharnier
33758047Ssheldonh	putsb(&sblock, special, Aflag);
33842873Sluoqi	if (active) {
33942873Sluoqi		bzero(&args, sizeof(args));
34042873Sluoqi		if (mount("ufs", fs->fs_file,
34142873Sluoqi		    stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0)
34242873Sluoqi			err(9, "%s: reload", special);
34342873Sluoqi		warnx("file system reloaded");
34442873Sluoqi	}
3451558Srgrimes	exit(0);
3461558Srgrimes}
3471558Srgrimes
3481558Srgrimesvoid
3491558Srgrimesusage()
3501558Srgrimes{
35138040Scharnier	fprintf(stderr, "%s\n%s\n%s\n",
35275377Smckusick"usage: tunefs [-A] [-a maxcontig] [-d rotdelay] [-e maxbpg] [-f avgfilesize]",
35375377Smckusick"              [-m minfree] [-p] [-n enable | disable] [-o space | time]",
35475377Smckusick"              [-s filesperdir] special | filesystem");
3551558Srgrimes	exit(2);
3561558Srgrimes}
3571558Srgrimes
3581558Srgrimesvoid
3591558Srgrimesgetsb(fs, file)
3601558Srgrimes	register struct fs *fs;
3611558Srgrimes	char *file;
3621558Srgrimes{
3631558Srgrimes
36458047Ssheldonh	fi = open(file, O_RDONLY);
3651558Srgrimes	if (fi < 0)
3661558Srgrimes		err(3, "cannot open %s", file);
3671558Srgrimes	if (bread((daddr_t)SBOFF, (char *)fs, SBSIZE))
3681558Srgrimes		err(4, "%s: bad super block", file);
3691558Srgrimes	if (fs->fs_magic != FS_MAGIC)
3701558Srgrimes		err(5, "%s: bad magic number", file);
3711558Srgrimes	dev_bsize = fs->fs_fsize / fsbtodb(fs, 1);
3721558Srgrimes}
3731558Srgrimes
3741558Srgrimesvoid
37558047Ssheldonhputsb(fs, file, all)
37658047Ssheldonh	register struct fs *fs;
37758047Ssheldonh	char *file;
37858047Ssheldonh	int all;
37958047Ssheldonh{
38058047Ssheldonh	int i;
38158047Ssheldonh
38258047Ssheldonh	/*
38358047Ssheldonh	 * Re-open the device read-write. Use the read-only file
38458047Ssheldonh	 * descriptor as an interlock to prevent the device from
38558047Ssheldonh	 * being mounted while we are switching mode.
38658047Ssheldonh	 */
38758047Ssheldonh	i = fi;
38858047Ssheldonh	fi = open(file, O_RDWR);
38958047Ssheldonh	close(i);
39058047Ssheldonh	if (fi < 0)
39158047Ssheldonh		err(3, "cannot open %s", file);
39258047Ssheldonh	bwrite((daddr_t)SBOFF / dev_bsize, (char *)fs, SBSIZE);
39358047Ssheldonh	if (all)
39458047Ssheldonh		for (i = 0; i < fs->fs_ncg; i++)
39558047Ssheldonh			bwrite(fsbtodb(fs, cgsblock(fs, i)),
39658047Ssheldonh			    (char *)fs, SBSIZE);
39758047Ssheldonh	close(fi);
39858047Ssheldonh}
39958047Ssheldonh
40058047Ssheldonhvoid
4019315Sjoergprintfs()
4029315Sjoerg{
40334266Sjulian	warnx("soft updates:  (-n)                                %s",
40434266Sjulian		(sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled");
4059315Sjoerg	warnx("maximum contiguous block count: (-a)               %d",
4069315Sjoerg	      sblock.fs_maxcontig);
4079315Sjoerg	warnx("rotational delay between contiguous blocks: (-d)   %d ms",
4089315Sjoerg	      sblock.fs_rotdelay);
4099315Sjoerg	warnx("maximum blocks per file in a cylinder group: (-e)  %d",
4109315Sjoerg	      sblock.fs_maxbpg);
41175377Smckusick	warnx("average file size: (-f)                            %d",
41275377Smckusick	      sblock.fs_avgfilesize);
41375377Smckusick	warnx("average number of files in a directory: (-s)       %d",
41475377Smckusick	      sblock.fs_avgfpdir);
4159315Sjoerg	warnx("minimum percentage of free space: (-m)             %d%%",
4169315Sjoerg	      sblock.fs_minfree);
4179315Sjoerg	warnx("optimization preference: (-o)                      %s",
4189315Sjoerg	      sblock.fs_optim == FS_OPTSPACE ? "space" : "time");
4199315Sjoerg	if (sblock.fs_minfree >= MINFREE &&
4209315Sjoerg	    sblock.fs_optim == FS_OPTSPACE)
4219315Sjoerg		warnx(OPTWARN, "time", ">=", MINFREE);
4229315Sjoerg	if (sblock.fs_minfree < MINFREE &&
4239315Sjoerg	    sblock.fs_optim == FS_OPTTIME)
4249315Sjoerg		warnx(OPTWARN, "space", "<", MINFREE);
4259315Sjoerg}
4269315Sjoerg
4279315Sjoergvoid
4281558Srgrimesbwrite(blk, buf, size)
4291558Srgrimes	daddr_t blk;
4301558Srgrimes	char *buf;
4311558Srgrimes	int size;
4321558Srgrimes{
4331558Srgrimes
4341558Srgrimes	if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0)
4351558Srgrimes		err(6, "FS SEEK");
4361558Srgrimes	if (write(fi, buf, size) != size)
4371558Srgrimes		err(7, "FS WRITE");
4381558Srgrimes}
4391558Srgrimes
4401558Srgrimesint
4411558Srgrimesbread(bno, buf, cnt)
4421558Srgrimes	daddr_t bno;
4431558Srgrimes	char *buf;
4441558Srgrimes	int cnt;
4451558Srgrimes{
4461558Srgrimes	int i;
4471558Srgrimes
4481558Srgrimes	if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0)
4491558Srgrimes		return(1);
4501558Srgrimes	if ((i = read(fi, buf, cnt)) != cnt) {
4511558Srgrimes		for(i=0; i<sblock.fs_bsize; i++)
4521558Srgrimes			buf[i] = 0;
4531558Srgrimes		return (1);
4541558Srgrimes	}
4551558Srgrimes	return (0);
4561558Srgrimes}
457