GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/tunefs/tunefs.c Lines: 0 108 0.0 %
Date: 2016-12-06 Branches: 0 94 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: tunefs.c,v 1.41 2016/05/28 23:44:27 tb Exp $	*/
2
/*	$NetBSD: tunefs.c,v 1.33 2005/01/19 20:46:16 xtraeme Exp $	*/
3
4
/*
5
 * Copyright (c) 1983, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
/*
34
 * tunefs: change layout parameters to an existing file system.
35
 */
36
#include <sys/param.h>	/* DEV_BSIZE MAXBSIZE */
37
38
#include <ufs/ufs/dinode.h>
39
#include <ufs/ffs/fs.h>
40
#include <ufs/ffs/ffs_extern.h>
41
42
#include <err.h>
43
#include <errno.h>
44
#include <fcntl.h>
45
#include <fstab.h>
46
#include <paths.h>
47
#include <stdio.h>
48
#include <stdlib.h>
49
#include <string.h>
50
#include <unistd.h>
51
#include <limits.h>
52
#include <util.h>
53
54
/* the optimization warning string template */
55
#define	OPTWARN	"should optimize for %s with minfree %s %d%%"
56
57
union {
58
	struct	fs sb;
59
	char pad[MAXBSIZE];
60
} sbun;
61
#define	sblock sbun.sb
62
char buf[MAXBSIZE];
63
64
int	fi;
65
int	is_ufs2 = 0;
66
off_t	sblockloc;
67
68
static off_t sblock_try[] = SBLOCKSEARCH;
69
70
static	void	bwrite(daddr_t, char *, int, const char *);
71
static	void	bread(daddr_t, char *, int, const char *);
72
static	int	getnum(const char *, const char *, int, int);
73
static	void	getsb(struct fs *, const char *);
74
static	int	openpartition(char *, int, char **);
75
static	void	usage(void);
76
77
int
78
main(int argc, char *argv[])
79
{
80
#define	OPTSTRING	"AFNe:g:h:m:o:"
81
	int		i, ch, Aflag, Fflag, Nflag, openflags;
82
	char		*special;
83
	const char	*chg[2];
84
	int		maxbpg, minfree, optim;
85
	int		avgfilesize, avgfpdir;
86
87
	Aflag = Fflag = Nflag = 0;
88
	maxbpg = minfree = optim = -1;
89
	avgfilesize = avgfpdir = -1;
90
	chg[FS_OPTSPACE] = "space";
91
	chg[FS_OPTTIME] = "time";
92
93
	while ((ch = getopt(argc, argv, OPTSTRING)) != -1) {
94
		switch (ch) {
95
96
		case 'A':
97
			Aflag = 1;
98
			break;
99
100
		case 'F':
101
			Fflag = 1;
102
			break;
103
104
		case 'N':
105
			Nflag = 1;
106
			break;
107
108
		case 'e':
109
			maxbpg = getnum(optarg,
110
			    "maximum blocks per file in a cylinder group",
111
			    1, INT_MAX);
112
			break;
113
114
		case 'g':
115
			avgfilesize = getnum(optarg,
116
			    "average file size", 1, INT_MAX);
117
			break;
118
119
		case 'h':
120
			avgfpdir = getnum(optarg,
121
			    "expected number of files per directory",
122
			    1, INT_MAX);
123
			break;
124
125
		case 'm':
126
			minfree = getnum(optarg,
127
			    "minimum percentage of free space", 0, 99);
128
			break;
129
130
		case 'o':
131
			if (strcmp(optarg, chg[FS_OPTSPACE]) == 0)
132
				optim = FS_OPTSPACE;
133
			else if (strcmp(optarg, chg[FS_OPTTIME]) == 0)
134
				optim = FS_OPTTIME;
135
			else
136
				errx(10,
137
				    "bad %s (options are `space' or `time')",
138
				    "optimization preference");
139
			break;
140
141
		default:
142
			usage();
143
		}
144
	}
145
	argc -= optind;
146
	argv += optind;
147
	if (argc != 1)
148
		usage();
149
150
	special = argv[0];
151
	openflags = Nflag ? O_RDONLY : O_RDWR;
152
	if (Fflag)
153
		fi = open(special, openflags);
154
	else
155
		fi = openpartition(special, openflags, &special);
156
	if (fi == -1)
157
		err(1, "%s", special);
158
159
	if (pledge("stdio rpath cpath wpath", NULL) == -1)
160
		err(1, "pledge");
161
162
	getsb(&sblock, special);
163
164
#define CHANGEVAL(old, new, type, suffix) do				\
165
	if ((new) != -1) {						\
166
		if ((new) == (old))					\
167
			warnx("%s remains unchanged at %d%s",		\
168
			    (type), (old), (suffix));			\
169
		else {							\
170
			warnx("%s changes from %d%s to %d%s",		\
171
			    (type), (old), (suffix), (new), (suffix));	\
172
			(old) = (new);					\
173
		}							\
174
	} while (/* CONSTCOND */0)
175
176
	warnx("tuning %s", special);
177
	CHANGEVAL(sblock.fs_maxbpg, maxbpg,
178
	    "maximum blocks per file in a cylinder group", "");
179
	CHANGEVAL(sblock.fs_minfree, minfree,
180
	    "minimum percentage of free space", "%");
181
	if (minfree != -1) {
182
		if (minfree >= MINFREE &&
183
		    sblock.fs_optim == FS_OPTSPACE)
184
			warnx(OPTWARN, "time", ">=", MINFREE);
185
		if (minfree < MINFREE &&
186
		    sblock.fs_optim == FS_OPTTIME)
187
			warnx(OPTWARN, "space", "<", MINFREE);
188
	}
189
	if (optim != -1) {
190
		if (sblock.fs_optim == optim) {
191
			warnx("%s remains unchanged as %s",
192
			    "optimization preference",
193
			    chg[optim]);
194
		} else {
195
			warnx("%s changes from %s to %s",
196
			    "optimization preference",
197
			    chg[sblock.fs_optim], chg[optim]);
198
			sblock.fs_optim = optim;
199
			if (sblock.fs_minfree >= MINFREE &&
200
			    optim == FS_OPTSPACE)
201
				warnx(OPTWARN, "time", ">=", MINFREE);
202
			if (sblock.fs_minfree < MINFREE &&
203
			    optim == FS_OPTTIME)
204
				warnx(OPTWARN, "space", "<", MINFREE);
205
		}
206
	}
207
	CHANGEVAL(sblock.fs_avgfilesize, avgfilesize,
208
	    "average file size", "");
209
	CHANGEVAL(sblock.fs_avgfpdir, avgfpdir,
210
	    "expected number of files per directory", "");
211
212
	if (Nflag) {
213
		fprintf(stdout, "tunefs: current settings of %s\n", special);
214
		fprintf(stdout, "\tmaximum contiguous block count %d\n",
215
		    sblock.fs_maxcontig);
216
		fprintf(stdout,
217
		    "\tmaximum blocks per file in a cylinder group %d\n",
218
		    sblock.fs_maxbpg);
219
		fprintf(stdout, "\tminimum percentage of free space %d%%\n",
220
		    sblock.fs_minfree);
221
		fprintf(stdout, "\toptimization preference: %s\n",
222
		    chg[sblock.fs_optim]);
223
		fprintf(stdout, "\taverage file size: %d\n",
224
		    sblock.fs_avgfilesize);
225
		fprintf(stdout,
226
		    "\texpected number of files per directory: %d\n",
227
		    sblock.fs_avgfpdir);
228
		fprintf(stdout, "tunefs: no changes made\n");
229
		exit(0);
230
	}
231
232
	memcpy(buf, (char *)&sblock, SBLOCKSIZE);
233
	bwrite(sblockloc, buf, SBLOCKSIZE, special);
234
	if (Aflag)
235
		for (i = 0; i < sblock.fs_ncg; i++)
236
			bwrite(fsbtodb(&sblock, cgsblock(&sblock, i)),
237
			    buf, SBLOCKSIZE, special);
238
	close(fi);
239
	exit(0);
240
}
241
242
static int
243
getnum(const char *num, const char *desc, int min, int max)
244
{
245
	int		n;
246
	const char	*errstr;
247
248
	n = strtonum(num, min, max, &errstr);
249
	if (errstr != NULL)
250
		errx(1, "Invalid number `%s' for %s: %s", num, desc, errstr);
251
	return (n);
252
}
253
254
static void
255
usage(void)
256
{
257
	extern char *__progname;
258
259
	fprintf(stderr,
260
	    "usage: %s [-AFN] [-e maxbpg] [-g avgfilesize] "
261
	    "[-h avgfpdir] [-m minfree]\n"
262
	    "\t[-o optimize_preference] special | filesys\n",
263
	    __progname);
264
265
	exit(2);
266
}
267
268
static void
269
getsb(struct fs *fs, const char *file)
270
{
271
	int i;
272
273
	for (i = 0; ; i++) {
274
		if (sblock_try[i] == -1)
275
			errx(5, "cannot find filesystem superblock");
276
		bread(sblock_try[i] / DEV_BSIZE, (char *)fs, SBLOCKSIZE, file);
277
		switch(fs->fs_magic) {
278
		case FS_UFS2_MAGIC:
279
			is_ufs2 = 1;
280
			/*FALLTHROUGH*/
281
		case FS_UFS1_MAGIC:
282
			break;
283
		default:
284
			continue;
285
		}
286
		if (!is_ufs2 && sblock_try[i] == SBLOCK_UFS2)
287
			continue;
288
		if ((is_ufs2 || fs->fs_flags & FS_FLAGS_UPDATED)
289
		    && fs->fs_sblockloc != sblock_try[i])
290
			continue;
291
		break;
292
	}
293
294
	sblockloc = sblock_try[i] / DEV_BSIZE;
295
}
296
297
static void
298
bwrite(daddr_t blk, char *buffer, int size, const char *file)
299
{
300
	if (pwrite(fi, buffer, size, blk * DEV_BSIZE) != size)
301
		err(7, "%s: writing %d bytes @ %lld", file, size,
302
		    (long long)(blk * DEV_BSIZE));
303
}
304
305
static void
306
bread(daddr_t blk, char *buffer, int cnt, const char *file)
307
{
308
	if ((pread(fi, buffer, cnt, (off_t)blk * DEV_BSIZE)) != cnt)
309
		errx(5, "%s: reading %d bytes @ %lld", file, cnt,
310
		    (long long)(blk * DEV_BSIZE));
311
}
312
313
static int
314
openpartition(char *name, int flags, char **devicep)
315
{
316
	char		rawspec[PATH_MAX], *p;
317
	struct fstab	*fs;
318
	int		fd;
319
320
	fs = getfsfile(name);
321
	if (fs) {
322
		if ((p = strrchr(fs->fs_spec, '/')) != NULL) {
323
			snprintf(rawspec, sizeof(rawspec), "%.*s/r%s",
324
			    (int)(p - fs->fs_spec), fs->fs_spec, p + 1);
325
			name = rawspec;
326
		} else
327
			name = fs->fs_spec;
328
	}
329
	fd = opendev(name, flags, 0, devicep);
330
	if (fd == -1 && errno == ENOENT)
331
		devicep = &name;
332
	return (fd);
333
}