xref: /illumos-gate/usr/src/cmd/fs.d/ufs/tunefs/tunefs.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 /*
30  * University Copyright- Copyright (c) 1982, 1986, 1988
31  * The Regents of the University of California
32  * All Rights Reserved
33  *
34  * University Acknowledgment- Portions of this document are derived from
35  * software developed by the University of California, Berkeley, and its
36  * contributors.
37  */
38 
39 #pragma ident	"%Z%%M%	%I%	%E% SMI"
40 
41 /*
42  * tunefs: change layout parameters to an existing file system.
43  */
44 
45 #include <string.h>
46 #include <unistd.h>
47 #include <stdlib.h>
48 #include <ustat.h>
49 #include <sys/param.h>
50 #include <sys/types.h>
51 #include <time.h>
52 #include <sys/mntent.h>
53 
54 #define	bcopy(f, t, n)    memcpy(t, f, n)
55 #define	bzero(s, n)	memset(s, 0, n)
56 #define	bcmp(s, d, n)	memcmp(s, d, n)
57 
58 #define	index(s, r)	strchr(s, r)
59 #define	rindex(s, r)	strrchr(s, r)
60 
61 #include <sys/sysmacros.h>
62 #include <sys/stat.h>
63 #include <sys/fs/ufs_fs.h>
64 #include <sys/vnode.h>
65 #include <sys/fs/ufs_inode.h>
66 #include <fcntl.h>
67 #include <stdio.h>
68 #include <sys/mnttab.h>
69 #include <sys/vfstab.h>
70 #include <sys/ustat.h>
71 #include <sys/filio.h>
72 #include <sys/fs/ufs_filio.h>
73 
74 extern offset_t llseek();
75 
76 union {
77 	struct	fs sb;
78 	char pad[SBSIZE];
79 } sbun;
80 #define	sblock sbun.sb
81 
82 int fi;
83 struct ustat ustatarea;
84 extern int	optind;
85 extern char	*optarg;
86 
87 static void usage();
88 static void getsb(struct fs *, char *);
89 static void bwrite(diskaddr_t, char *, int);
90 static void fatal();
91 static int bread(diskaddr_t, char *, int);
92 static int isnumber(char *);
93 
94 extern char *getfullrawname(), *getfullblkname();
95 
96 static void
97 searchvfstab(char **specialp)
98 {
99 	FILE *vfstab;
100 	struct vfstab vfsbuf;
101 	char *blockspecial;
102 
103 	blockspecial = getfullblkname(*specialp);
104 	if (blockspecial == NULL)
105 		blockspecial = *specialp;
106 
107 	if ((vfstab = fopen(VFSTAB, "r")) == NULL) {
108 		fprintf(stderr, "%s: ", VFSTAB);
109 		perror("open");
110 	}
111 	while (getvfsent(vfstab, &vfsbuf) == NULL)
112 		if (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UFS) == 0)
113 			if ((strcmp(vfsbuf.vfs_mountp, *specialp) == 0) ||
114 			    (strcmp(vfsbuf.vfs_special, *specialp) == 0) ||
115 			    (strcmp(vfsbuf.vfs_special, blockspecial) == 0) ||
116 			    (strcmp(vfsbuf.vfs_fsckdev, *specialp) == 0)) {
117 				*specialp = strdup(vfsbuf.vfs_special);
118 				return;
119 			}
120 	fclose(vfstab);
121 }
122 
123 static void
124 searchmnttab(char **specialp, char **mountpointp)
125 {
126 	FILE *mnttab;
127 	struct mnttab mntbuf;
128 	char *blockspecial;
129 
130 	blockspecial = getfullblkname(*specialp);
131 	if (blockspecial == NULL)
132 		blockspecial = *specialp;
133 
134 	if ((mnttab = fopen(MNTTAB, "r")) == NULL)
135 		return;
136 	while (getmntent(mnttab, &mntbuf) == NULL)
137 		if (strcmp(mntbuf.mnt_fstype, MNTTYPE_UFS) == 0)
138 			if ((strcmp(mntbuf.mnt_mountp, *specialp) == 0) ||
139 			    (strcmp(mntbuf.mnt_special, blockspecial) == 0) ||
140 			    (strcmp(mntbuf.mnt_special, *specialp) == 0)) {
141 				*specialp = strdup(mntbuf.mnt_special);
142 				*mountpointp = strdup(mntbuf.mnt_mountp);
143 				return;
144 			}
145 	fclose(mnttab);
146 }
147 
148 int
149 main(int argc, char *argv[])
150 {
151 	char *special, *name, *mountpoint = NULL;
152 	struct stat64 st;
153 	int i, mountfd;
154 	int Aflag = 0;
155 	char *chg[2];
156 	int	opt;
157 	struct fiotune fiotune;
158 
159 
160 	if (argc < 3)
161 		usage();
162 	special = argv[argc - 1];
163 
164 	/*
165 	 * For performance, don't search mnttab unless necessary
166 	 */
167 
168 	if (stat64(special, &st) >= 0) {
169 		/*
170 		 * If mounted directory, search mnttab for special
171 		 */
172 		if ((st.st_mode & S_IFMT) == S_IFDIR) {
173 			if (st.st_ino == UFSROOTINO)
174 				searchmnttab(&special, &mountpoint);
175 		/*
176 		 * If mounted device, search mnttab for mountpoint
177 		 */
178 		} else if ((st.st_mode & S_IFMT) == S_IFBLK ||
179 			    (st.st_mode & S_IFMT) == S_IFCHR) {
180 				if (ustat(st.st_rdev, &ustatarea) >= 0)
181 					searchmnttab(&special, &mountpoint);
182 		}
183 	}
184 	/*
185 	 * Doesn't appear to be mounted; take ``unmounted'' path
186 	 */
187 	if (mountpoint == NULL)
188 		searchvfstab(&special);
189 
190 	if ((special = getfullrawname(special)) == NULL) {
191 		fprintf(stderr, "tunefs: malloc failed\n");
192 		exit(32);
193 	}
194 
195 	if (*special == '\0') {
196 		fprintf(stderr, "tunefs: Could not find raw device for %s\n",
197 		    argv[argc -1]);
198 		exit(32);
199 	}
200 
201 	if (stat64(special, &st) < 0) {
202 		fprintf(stderr, "tunefs: "); perror(special);
203 		exit(31+1);
204 	}
205 
206 	/*
207 	 * If a mountpoint has been found then we will ioctl() the file
208 	 * system instead of writing to the file system's device
209 	 */
210 	/* ustat() ok because max number of UFS inodes can fit in ino_t */
211 	if (ustat(st.st_rdev, &ustatarea) >= 0) {
212 		if (mountpoint == NULL) {
213 			printf("%s is mounted, can't tunefs\n", special);
214 			exit(32);
215 		}
216 	} else
217 		mountpoint = NULL;
218 
219 	if ((st.st_mode & S_IFMT) != S_IFBLK &&
220 	    (st.st_mode & S_IFMT) != S_IFCHR)
221 		fatal("%s: not a block or character device", special);
222 	getsb(&sblock, special);
223 	while ((opt = getopt(argc, argv, "o:m:e:d:a:AV")) != EOF) {
224 		switch (opt) {
225 
226 		case 'A':
227 			Aflag++;
228 			continue;
229 
230 		case 'a':
231 			name = "maximum contiguous block count";
232 			if (!isnumber(optarg))
233 				fatal("%s: %s must be >= 1", *argv, name);
234 			i = atoi(optarg);
235 			if (i < 1)
236 				fatal("%s: %s must be >= 1", *argv, name);
237 			fprintf(stdout, "%s changes from %d to %d\n",
238 				name, sblock.fs_maxcontig, i);
239 			sblock.fs_maxcontig = i;
240 			continue;
241 
242 		case 'd':
243 			sblock.fs_rotdelay = 0;
244 			continue;
245 
246 		case 'e':
247 			name =
248 			    "maximum blocks per file in a cylinder group";
249 			if (!isnumber(optarg))
250 				fatal("%s: %s must be >= 1", *argv, name);
251 			i = atoi(optarg);
252 			if (i < 1)
253 				fatal("%s: %s must be >= 1", *argv, name);
254 			fprintf(stdout, "%s changes from %d to %d\n",
255 				name, sblock.fs_maxbpg, i);
256 			sblock.fs_maxbpg = i;
257 			continue;
258 
259 		case 'm':
260 			name = "minimum percentage of free space";
261 			if (!isnumber(optarg))
262 				fatal("%s: bad %s", *argv, name);
263 			i = atoi(optarg);
264 			if (i < 0 || i > 99)
265 				fatal("%s: bad %s", *argv, name);
266 			fprintf(stdout,
267 				"%s changes from %d%% to %d%%\n",
268 				name, sblock.fs_minfree, i);
269 			sblock.fs_minfree = i;
270 			continue;
271 
272 		case 'o':
273 			name = "optimization preference";
274 			chg[FS_OPTSPACE] = "space";
275 			chg[FS_OPTTIME] = "time";
276 			if (strcmp(optarg, chg[FS_OPTSPACE]) == 0)
277 				i = FS_OPTSPACE;
278 			else if (strcmp(optarg, chg[FS_OPTTIME]) == 0)
279 				i = FS_OPTTIME;
280 			else
281 			fatal("%s: bad %s (options are `space' or `time')",
282 					optarg, name);
283 			if (sblock.fs_optim == i) {
284 				fprintf(stdout,
285 					"%s remains unchanged as %s\n",
286 					name, chg[i]);
287 				continue;
288 			}
289 			fprintf(stdout,
290 				"%s changes from %s to %s\n",
291 				name, chg[sblock.fs_optim], chg[i]);
292 			sblock.fs_optim = i;
293 			continue;
294 
295 		case 'V':
296 			{
297 				char	*opt_text;
298 				int	opt_count;
299 
300 				(void) fprintf(stdout, "tunefs -F ufs ");
301 				for (opt_count = 1; opt_count < argc;
302 				    opt_count++) {
303 					opt_text = argv[opt_count];
304 					if (opt_text)
305 						(void) fprintf(stdout, " %s ",
306 						    opt_text);
307 				}
308 				(void) fprintf(stdout, "\n");
309 			}
310 			break;
311 
312 		default:
313 			usage();
314 		}
315 	}
316 	if ((argc - optind) != 1)
317 		usage();
318 	if (mountpoint) {
319 		mountfd = open(mountpoint, O_RDONLY);
320 		if (mountfd == -1) {
321 			perror(mountpoint);
322 			fprintf(stderr,
323 				"tunefs: can't tune %s\n", mountpoint);
324 			exit(32);
325 		}
326 		fiotune.maxcontig = sblock.fs_maxcontig;
327 		fiotune.rotdelay = sblock.fs_rotdelay;
328 		fiotune.maxbpg = sblock.fs_maxbpg;
329 		fiotune.minfree = sblock.fs_minfree;
330 		fiotune.optim = sblock.fs_optim;
331 		if (ioctl(mountfd, _FIOTUNE, &fiotune) == -1) {
332 			perror(mountpoint);
333 			fprintf(stderr,
334 				"tunefs: can't tune %s\n", mountpoint);
335 			exit(32);
336 		}
337 		close(mountfd);
338 	} else {
339 		bwrite((diskaddr_t)SBLOCK, (char *)&sblock, SBSIZE);
340 
341 		if (Aflag)
342 			for (i = 0; i < sblock.fs_ncg; i++)
343 				bwrite(fsbtodb(&sblock, cgsblock(&sblock, i)),
344 				    (char *)&sblock, SBSIZE);
345 	}
346 
347 	close(fi);
348 	return (0);
349 }
350 
351 void
352 usage()
353 {
354 	fprintf(stderr, "ufs usage: tunefs tuneup-options special-device\n");
355 	fprintf(stderr, "where tuneup-options are:\n");
356 	fprintf(stderr, "\t-a maximum contiguous blocks\n");
357 	fprintf(stderr, "\t-d rotational delay between contiguous blocks\n");
358 	fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n");
359 	fprintf(stderr, "\t-m minimum percentage of free space\n");
360 	fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
361 	exit(31+2);
362 }
363 
364 void
365 getsb(struct fs *fs, char *file)
366 {
367 
368 	fi = open64(file, O_RDWR);
369 	if (fi < 0) {
370 		fprintf(stderr, "Cannot open ");
371 		perror(file);
372 		exit(31+3);
373 	}
374 	if (bread((diskaddr_t)SBLOCK, (char *)fs, SBSIZE)) {
375 		fprintf(stderr, "Bad super block ");
376 		perror(file);
377 		exit(31+4);
378 	}
379 	if ((fs->fs_magic != FS_MAGIC) && (fs->fs_magic != MTB_UFS_MAGIC)) {
380 		fprintf(stderr, "%s: bad magic number\n", file);
381 		exit(31+5);
382 	}
383 	if (fs->fs_magic == FS_MAGIC &&
384 	    (fs->fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
385 	    fs->fs_version != UFS_VERSION_MIN)) {
386 		fprintf(stderr, "%s: unrecognized ufs version: %d\n", file,
387 		    fs->fs_version);
388 		exit(31+5);
389 	}
390 	if (fs->fs_magic == MTB_UFS_MAGIC &&
391 	    (fs->fs_version > MTB_UFS_VERSION_1 ||
392 	    fs->fs_version < MTB_UFS_VERSION_MIN)) {
393 		fprintf(stderr, "%s: unrecognized ufs version: %d\n", file,
394 		    fs->fs_version);
395 		exit(31+5);
396 	}
397 }
398 
399 void
400 bwrite(diskaddr_t blk, char *buf, int size)
401 {
402 	if (llseek(fi, (offset_t)blk * DEV_BSIZE, 0) < 0) {
403 		perror("FS SEEK");
404 		exit(31+6);
405 	}
406 	if (write(fi, buf, size) != size) {
407 		perror("FS WRITE");
408 		exit(31+7);
409 	}
410 }
411 
412 int
413 bread(diskaddr_t bno, char *buf, int cnt)
414 {
415 	int	i;
416 
417 	if (llseek(fi, (offset_t)bno * DEV_BSIZE, 0) < 0) {
418 		fprintf(stderr, "bread: ");
419 		perror("llseek");
420 		return (1);
421 	}
422 	if ((i = read(fi, buf, cnt)) != cnt) {
423 		perror("read");
424 		for (i = 0; i < sblock.fs_bsize; i++)
425 			buf[i] = 0;
426 		return (1);
427 	}
428 	return (0);
429 }
430 
431 /* VARARGS1 */
432 void
433 fatal(char *fmt, char *arg1, char *arg2)
434 {
435 	fprintf(stderr, "tunefs: ");
436 	fprintf(stderr, fmt, arg1, arg2);
437 	putc('\n', stderr);
438 	exit(31+10);
439 }
440 
441 
442 int
443 isnumber(char *s)
444 {
445 	int c;
446 
447 	while (c = *s++)
448 		if (c < '0' || c > '9')
449 			return (0);
450 	return (1);
451 }
452