tunefs.c revision 69314
117683Spst/*
239291Sfenner * Copyright (c) 1983, 1993
317683Spst *	The Regents of the University of California.  All rights reserved.
417683Spst *
517683Spst * Redistribution and use in source and binary forms, with or without
617683Spst * modification, are permitted provided that the following conditions
717683Spst * are met:
817683Spst * 1. Redistributions of source code must retain the above copyright
917683Spst *    notice, this list of conditions and the following disclaimer.
1017683Spst * 2. Redistributions in binary form must reproduce the above copyright
1117683Spst *    notice, this list of conditions and the following disclaimer in the
1217683Spst *    documentation and/or other materials provided with the distribution.
1317683Spst * 3. All advertising materials mentioning features or use of this software
1417683Spst *    must display the following acknowledgement:
1517683Spst *	This product includes software developed by the University of
1617683Spst *	California, Berkeley and its contributors.
1717683Spst * 4. Neither the name of the University nor the names of its contributors
1817683Spst *    may be used to endorse or promote products derived from this software
1917683Spst *    without specific prior written permission.
2017683Spst *
2117683Spst * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22127664Sbms * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23214518Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2417683Spst * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2517683Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2675107Sfenner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2775107Sfenner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2875107Sfenner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2975107Sfenner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3017683Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3117683Spst * SUCH DAMAGE.
3217683Spst */
3317683Spst
3417683Spst#ifndef lint
3517683Spststatic const char copyright[] =
3617683Spst"@(#) Copyright (c) 1983, 1993\n\
3717683Spst	The Regents of the University of California.  All rights reserved.\n";
3817683Spst#endif /* not lint */
3917683Spst
4017683Spst#ifndef lint
4117683Spst#if 0
4217683Spststatic char sccsid[] = "@(#)tunefs.c	8.2 (Berkeley) 4/19/94";
4317683Spst#endif
4417683Spststatic const char rcsid[] =
4517683Spst  "$FreeBSD: head/sbin/tunefs/tunefs.c 69314 2000-11-28 18:17:15Z charnier $";
4617683Spst#endif /* not lint */
4717683Spst
4817683Spst/*
4917683Spst * tunefs: change layout parameters to an existing file system.
5017683Spst */
5117683Spst#include <sys/param.h>
5217683Spst#include <sys/mount.h>
5317683Spst#include <sys/stat.h>
5417683Spst
5517683Spst#include <ufs/ffs/fs.h>
5617683Spst#include <ufs/ufs/ufsmount.h>
5717683Spst
5817683Spst#include <err.h>
5917683Spst#include <fcntl.h>
6017683Spst#include <fstab.h>
61127664Sbms#include <paths.h>
62127664Sbms#include <stdio.h>
6317683Spst#include <stdlib.h>
6417683Spst#include <string.h>
6517683Spst#include <unistd.h>
66146768Ssam
67146768Ssam/* the optimization warning string template */
6817683Spst#define	OPTWARN	"should optimize for %s with minfree %s %d%%"
6917683Spst
7017683Spstunion {
71127664Sbms	struct	fs sb;
72127664Sbms	char pad[MAXBSIZE];
73127664Sbms} sbun;
74127664Sbms#define	sblock sbun.sb
75127664Sbms
76127664Sbmsint fi;
77127664Sbmslong dev_bsize = 1;
78127664Sbms
79127664Sbmsvoid bwrite __P((daddr_t, char *, int));
80127664Sbmsint bread __P((daddr_t, char *, int));
81127664Sbmsvoid getsb __P((struct fs *, char *));
82127664Sbmsvoid putsb __P((struct fs *, char *, int));
8317683Spstvoid usage __P((void));
8417683Spstvoid printfs __P((void));
8517683Spst
8617683Spstint
8717683Spstmain(argc, argv)
8817683Spst	int argc;
89127664Sbms	char *argv[];
9017683Spst{
9117683Spst	char *special, *name, *action;
9217683Spst	struct stat st;
9317683Spst	int i;
9475107Sfenner	int Aflag = 0, active = 0;
9575107Sfenner	struct fstab *fs;
9617683Spst	char *chg[2], device[MAXPATHLEN];
9717683Spst	struct ufs_args args;
9817683Spst	struct statfs stfs;
9917683Spst	int found_arg, ch;
100146768Ssam
101146768Ssam        if (argc < 3)
102146768Ssam                usage();
103240725Skevlo	special = argv[argc - 1];
104146768Ssam	fs = getfsfile(special);
105146768Ssam	if (fs) {
106146768Ssam		if (statfs(special, &stfs) == 0 &&
107146768Ssam		    strcmp(special, stfs.f_mntonname) == 0) {
108146768Ssam			active = 1;
109146768Ssam		}
11017683Spst		special = fs->fs_spec;
11117683Spst	}
11217683Spstagain:
113127664Sbms	if (stat(special, &st) < 0) {
114127664Sbms		if (*special != '/') {
115127664Sbms			if (*special == 'r')
116127664Sbms				special++;
117127664Sbms			(void)sprintf(device, "%s/%s", _PATH_DEV, special);
118127664Sbms			special = device;
119127664Sbms			goto again;
120127664Sbms		}
121127664Sbms		err(1, "%s", special);
122127664Sbms	}
123127664Sbms	if ((st.st_mode & S_IFMT) != S_IFBLK &&
12417683Spst	    (st.st_mode & S_IFMT) != S_IFCHR)
12517683Spst		errx(10, "%s: not a block or character device", special);
12617683Spst	getsb(&sblock, special);
12717683Spst
128127664Sbms	found_arg = 0; /* at least one arg is required */
129127664Sbms	while ((ch = getopt(argc, argv, "Aa:d:e:m:n:o:p")) != -1)
13017683Spst	  switch (ch) {
13117683Spst	  case 'A':
13217683Spst		found_arg = 1;
13317683Spst		Aflag++;
13417683Spst		break;
13517683Spst	  case 'a':
13617683Spst		found_arg = 1;
13717683Spst		name = "maximum contiguous block count";
138127664Sbms		i = atoi(optarg);
139146768Ssam		if (i < 1)
140146768Ssam			errx(10, "%s must be >= 1 (was %s)", name, optarg);
141146768Ssam		if (sblock.fs_maxcontig == i) {
142146768Ssam			warnx("%s remains unchanged as %d", name, i);
143146768Ssam			break;
144146768Ssam		}
145146768Ssam		warnx("%s changes from %d to %d", name, sblock.fs_maxcontig, i);
146146768Ssam		sblock.fs_maxcontig = i;
147146768Ssam		break;
148146768Ssam	  case 'd':
149146768Ssam		found_arg = 1;
150146768Ssam		name = "rotational delay between contiguous blocks";
151146768Ssam		i = atoi(optarg);
152146768Ssam		if (sblock.fs_rotdelay == i) {
153146768Ssam			warnx("%s remains unchanged as %dms", name, i);
154146768Ssam			break;
155146768Ssam		}
156146768Ssam		warnx("%s changes from %dms to %dms",
157127664Sbms				    name, sblock.fs_rotdelay, i);
15817683Spst		sblock.fs_rotdelay = i;
15917683Spst		break;
16017683Spst	  case 'e':
16117683Spst		found_arg = 1;
16217683Spst		name = "maximum blocks per file in a cylinder group";
16375107Sfenner		i = atoi(optarg);
16417683Spst		if (i < 1)
16575107Sfenner			errx(10, "%s must be >= 1 (was %s)", name, optarg);
16675107Sfenner		if (sblock.fs_maxbpg == i) {
16717683Spst			warnx("%s remains unchanged as %d", name, i);
16817683Spst			break;
16917683Spst		}
17098530Sfenner		warnx("%s changes from %d to %d", name, sblock.fs_maxbpg, i);
17198530Sfenner		sblock.fs_maxbpg = i;
17298530Sfenner		break;
17398530Sfenner	  case 'm':
17498530Sfenner		found_arg = 1;
17598530Sfenner		name = "minimum percentage of free space";
17698530Sfenner		i = atoi(optarg);
17798530Sfenner		if (i < 0 || i > 99)
17898530Sfenner			errx(10, "bad %s (%s)", name, optarg);
17998530Sfenner		if (sblock.fs_minfree == i) {
18098530Sfenner			warnx("%s remains unchanged as %d%%", name, i);
18198530Sfenner			break;
18298530Sfenner		}
18317683Spst		warnx("%s changes from %d%% to %d%%",
18417683Spst				    name, sblock.fs_minfree, i);
18517683Spst		sblock.fs_minfree = i;
18617683Spst		if (i >= MINFREE && sblock.fs_optim == FS_OPTSPACE)
18798530Sfenner			warnx(OPTWARN, "time", ">=", MINFREE);
18898530Sfenner		if (i < MINFREE && sblock.fs_optim == FS_OPTTIME)
18998530Sfenner			warnx(OPTWARN, "space", "<", MINFREE);
19098530Sfenner		break;
19198530Sfenner	  case 'n':
19217683Spst		found_arg = 1;
19317683Spst 		name = "soft updates";
19417683Spst 		if (strcmp(optarg, "enable") == 0) {
19517683Spst 			sblock.fs_flags |= FS_DOSOFTDEP;
19617683Spst 			action = "set";
197190225Srpaulo 		} else if (strcmp(optarg, "disable") == 0) {
198190225Srpaulo 			sblock.fs_flags &= ~FS_DOSOFTDEP;
19917683Spst 			action = "cleared";
20017683Spst 		} else {
20117683Spst 			errx(10, "bad %s (options are %s)",
20217683Spst 			    name, "`enable' or `disable'");
20317683Spst 		}
20475107Sfenner 		warnx("%s %s", name, action);
20575107Sfenner 		break;
20675107Sfenner	  case 'o':
20717683Spst		found_arg = 1;
20817683Spst		name = "optimization preference";
20917683Spst		chg[FS_OPTSPACE] = "space";
210190225Srpaulo		chg[FS_OPTTIME] = "time";
21175107Sfenner		if (strcmp(optarg, chg[FS_OPTSPACE]) == 0)
21217683Spst			i = FS_OPTSPACE;
21317683Spst		else if (strcmp(optarg, chg[FS_OPTTIME]) == 0)
21417683Spst			i = FS_OPTTIME;
21575107Sfenner		else
21617683Spst			errx(10, "bad %s (options are `space' or `time')",
217190225Srpaulo					    name);
21817683Spst		if (sblock.fs_optim == i) {
219190225Srpaulo			warnx("%s remains unchanged as %s", name, chg[i]);
22075107Sfenner			break;
22117683Spst		}
22217683Spst		warnx("%s changes from %s to %s",
22375107Sfenner				    name, chg[sblock.fs_optim], chg[i]);
22417683Spst		sblock.fs_optim = i;
225190225Srpaulo		if (sblock.fs_minfree >= MINFREE && i == FS_OPTSPACE)
22675107Sfenner			warnx(OPTWARN, "time", ">=", MINFREE);
22717683Spst		if (sblock.fs_minfree < MINFREE && i == FS_OPTTIME)
22817683Spst			warnx(OPTWARN, "space", "<", MINFREE);
229214518Srpaulo		break;
230214518Srpaulo	  case 'p':
231190225Srpaulo		printfs();
232190225Srpaulo		exit(0);
23317683Spst	  default:
23417683Spst		usage();
23517683Spst	  }
23617683Spst	argc -= optind;
237190225Srpaulo	argv += optind;
238190225Srpaulo
239190225Srpaulo	if (found_arg == 0 || argc != 1)
240190225Srpaulo	  usage();
241190225Srpaulo
242190225Srpaulo	putsb(&sblock, special, Aflag);
243190225Srpaulo	if (active) {
244190225Srpaulo		bzero(&args, sizeof(args));
245190225Srpaulo		if (mount("ufs", fs->fs_file,
246190225Srpaulo		    stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0)
247190225Srpaulo			err(9, "%s: reload", special);
248190225Srpaulo		warnx("file system reloaded");
249190225Srpaulo	}
25017683Spst	exit(0);
25117683Spst}
25275107Sfenner
253146768Ssamvoid
254146768Ssamusage()
255146768Ssam{
256146768Ssam	fprintf(stderr, "%s\n%s\n%s\n",
257146768Ssam"usage: tunefs [-A] [-a maxcontig] [-d rotdelay] [-e maxbpg] [-m minfree]",
258146768Ssam"              [-p] [-n enable | disable] [-o optimize_preference]",
259146768Ssam"              special | filesystem");
260146768Ssam	exit(2);
261146768Ssam}
262146768Ssam
263146768Ssamvoid
264146768Ssamgetsb(fs, file)
265146768Ssam	register struct fs *fs;
266146768Ssam	char *file;
267146768Ssam{
268146768Ssam
269146768Ssam	fi = open(file, O_RDONLY);
270146768Ssam	if (fi < 0)
271146768Ssam		err(3, "cannot open %s", file);
272146768Ssam	if (bread((daddr_t)SBOFF, (char *)fs, SBSIZE))
273146768Ssam		err(4, "%s: bad super block", file);
274146768Ssam	if (fs->fs_magic != FS_MAGIC)
275146768Ssam		err(5, "%s: bad magic number", file);
276146768Ssam	dev_bsize = fs->fs_fsize / fsbtodb(fs, 1);
277146768Ssam}
278146768Ssam
279146768Ssamvoid
280146768Ssamputsb(fs, file, all)
281146768Ssam	register struct fs *fs;
282190225Srpaulo	char *file;
283190225Srpaulo	int all;
284190225Srpaulo{
28517683Spst	int i;
28617683Spst
28775107Sfenner	/*
288190225Srpaulo	 * Re-open the device read-write. Use the read-only file
28939291Sfenner	 * descriptor as an interlock to prevent the device from
29075107Sfenner	 * being mounted while we are switching mode.
291190225Srpaulo	 */
292127664Sbms	i = fi;
293127664Sbms	fi = open(file, O_RDWR);
294190225Srpaulo	close(i);
295127664Sbms	if (fi < 0)
296127664Sbms		err(3, "cannot open %s", file);
297190225Srpaulo	bwrite((daddr_t)SBOFF / dev_bsize, (char *)fs, SBSIZE);
29817683Spst	if (all)
299127664Sbms		for (i = 0; i < fs->fs_ncg; i++)
30017683Spst			bwrite(fsbtodb(fs, cgsblock(fs, i)),
301190225Srpaulo			    (char *)fs, SBSIZE);
30275107Sfenner	close(fi);
30317683Spst}
30417683Spst
305190225Srpaulovoid
306190225Srpauloprintfs()
307190225Srpaulo{
308190225Srpaulo	warnx("soft updates:  (-n)                                %s",
309190225Srpaulo		(sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled");
310190225Srpaulo	warnx("maximum contiguous block count: (-a)               %d",
311190225Srpaulo	      sblock.fs_maxcontig);
312190225Srpaulo	warnx("rotational delay between contiguous blocks: (-d)   %d ms",
313190225Srpaulo	      sblock.fs_rotdelay);
31475107Sfenner	warnx("maximum blocks per file in a cylinder group: (-e)  %d",
31575107Sfenner	      sblock.fs_maxbpg);
31675107Sfenner	warnx("minimum percentage of free space: (-m)             %d%%",
31775107Sfenner	      sblock.fs_minfree);
31875107Sfenner	warnx("optimization preference: (-o)                      %s",
31975107Sfenner	      sblock.fs_optim == FS_OPTSPACE ? "space" : "time");
32075107Sfenner	if (sblock.fs_minfree >= MINFREE &&
321190225Srpaulo	    sblock.fs_optim == FS_OPTSPACE)
32275107Sfenner		warnx(OPTWARN, "time", ">=", MINFREE);
323190225Srpaulo	if (sblock.fs_minfree < MINFREE &&
32475107Sfenner	    sblock.fs_optim == FS_OPTTIME)
32575107Sfenner		warnx(OPTWARN, "space", "<", MINFREE);
32675107Sfenner}
32775107Sfenner
32875107Sfennervoid
32975107Sfennerbwrite(blk, buf, size)
33075107Sfenner	daddr_t blk;
33175107Sfenner	char *buf;
33275107Sfenner	int size;
33375107Sfenner{
33475107Sfenner
33575107Sfenner	if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0)
33675107Sfenner		err(6, "FS SEEK");
33775107Sfenner	if (write(fi, buf, size) != size)
33875107Sfenner		err(7, "FS WRITE");
33975107Sfenner}
34075107Sfenner
34175107Sfennerint
34275107Sfennerbread(bno, buf, cnt)
34375107Sfenner	daddr_t bno;
344190225Srpaulo	char *buf;
345190225Srpaulo	int cnt;
34675107Sfenner{
34717683Spst	int i;
34875107Sfenner
34975107Sfenner	if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0)
35075107Sfenner		return(1);
35175107Sfenner	if ((i = read(fi, buf, cnt)) != cnt) {
35275107Sfenner		for(i=0; i<sblock.fs_bsize; i++)
353190225Srpaulo			buf[i] = 0;
35475107Sfenner		return (1);
35575107Sfenner	}
35675107Sfenner	return (0);
357190225Srpaulo}
35875107Sfenner