dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / fs.d / ufs / tunefs / tunefs.c
blobb1c1b89b5e3c61eb6d3804809a4b14c3a644393b
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
40 * tunefs: change layout parameters to an existing file system.
43 #include <string.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46 #include <ustat.h>
47 #include <sys/param.h>
48 #include <sys/types.h>
49 #include <time.h>
50 #include <sys/mntent.h>
52 #define bcopy(f, t, n) memcpy(t, f, n)
53 #define bzero(s, n) memset(s, 0, n)
54 #define bcmp(s, d, n) memcmp(s, d, n)
56 #define index(s, r) strchr(s, r)
57 #define rindex(s, r) strrchr(s, r)
59 #include <sys/sysmacros.h>
60 #include <sys/stat.h>
61 #include <sys/fs/ufs_fs.h>
62 #include <sys/vnode.h>
63 #include <sys/fs/ufs_inode.h>
64 #include <fcntl.h>
65 #include <stdio.h>
66 #include <sys/mnttab.h>
67 #include <sys/vfstab.h>
68 #include <sys/ustat.h>
69 #include <sys/filio.h>
70 #include <sys/fs/ufs_filio.h>
72 extern offset_t llseek();
74 union {
75 struct fs sb;
76 char pad[SBSIZE];
77 } sbun;
78 #define sblock sbun.sb
80 int fi;
81 struct ustat ustatarea;
82 extern int optind;
83 extern char *optarg;
85 static void usage();
86 static void getsb(struct fs *, char *);
87 static void bwrite(diskaddr_t, char *, int);
88 static void fatal();
89 static int bread(diskaddr_t, char *, int);
90 static int isnumber(char *);
92 extern char *getfullrawname(), *getfullblkname();
94 static void
95 searchvfstab(char **specialp)
97 FILE *vfstab;
98 struct vfstab vfsbuf;
99 char *blockspecial;
101 blockspecial = getfullblkname(*specialp);
102 if (blockspecial == NULL)
103 blockspecial = *specialp;
105 if ((vfstab = fopen(VFSTAB, "r")) == NULL) {
106 fprintf(stderr, "%s: ", VFSTAB);
107 perror("open");
109 while (getvfsent(vfstab, &vfsbuf) == 0)
110 if (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UFS) == 0)
111 if ((strcmp(vfsbuf.vfs_mountp, *specialp) == 0) ||
112 (strcmp(vfsbuf.vfs_special, *specialp) == 0) ||
113 (strcmp(vfsbuf.vfs_special, blockspecial) == 0) ||
114 (strcmp(vfsbuf.vfs_fsckdev, *specialp) == 0)) {
115 *specialp = strdup(vfsbuf.vfs_special);
116 return;
118 fclose(vfstab);
121 static void
122 searchmnttab(char **specialp, char **mountpointp)
124 FILE *mnttab;
125 struct mnttab mntbuf;
126 char *blockspecial;
128 blockspecial = getfullblkname(*specialp);
129 if (blockspecial == NULL)
130 blockspecial = *specialp;
132 if ((mnttab = fopen(MNTTAB, "r")) == NULL)
133 return;
134 while (getmntent(mnttab, &mntbuf) == 0)
135 if (strcmp(mntbuf.mnt_fstype, MNTTYPE_UFS) == 0)
136 if ((strcmp(mntbuf.mnt_mountp, *specialp) == 0) ||
137 (strcmp(mntbuf.mnt_special, blockspecial) == 0) ||
138 (strcmp(mntbuf.mnt_special, *specialp) == 0)) {
139 *specialp = strdup(mntbuf.mnt_special);
140 *mountpointp = strdup(mntbuf.mnt_mountp);
141 return;
143 fclose(mnttab);
147 main(int argc, char *argv[])
149 char *special, *name, *mountpoint = NULL;
150 struct stat64 st;
151 int i, mountfd;
152 int Aflag = 0;
153 char *chg[2];
154 int opt;
155 struct fiotune fiotune;
158 if (argc < 3)
159 usage();
160 special = argv[argc - 1];
163 * For performance, don't search mnttab unless necessary
166 if (stat64(special, &st) >= 0) {
168 * If mounted directory, search mnttab for special
170 if ((st.st_mode & S_IFMT) == S_IFDIR) {
171 if (st.st_ino == UFSROOTINO)
172 searchmnttab(&special, &mountpoint);
174 * If mounted device, search mnttab for mountpoint
176 } else if ((st.st_mode & S_IFMT) == S_IFBLK ||
177 (st.st_mode & S_IFMT) == S_IFCHR) {
178 if (ustat(st.st_rdev, &ustatarea) >= 0)
179 searchmnttab(&special, &mountpoint);
183 * Doesn't appear to be mounted; take ``unmounted'' path
185 if (mountpoint == NULL)
186 searchvfstab(&special);
188 if ((special = getfullrawname(special)) == NULL) {
189 fprintf(stderr, "tunefs: malloc failed\n");
190 exit(32);
193 if (*special == '\0') {
194 fprintf(stderr, "tunefs: Could not find raw device for %s\n",
195 argv[argc -1]);
196 exit(32);
199 if (stat64(special, &st) < 0) {
200 fprintf(stderr, "tunefs: "); perror(special);
201 exit(31+1);
205 * If a mountpoint has been found then we will ioctl() the file
206 * system instead of writing to the file system's device
208 /* ustat() ok because max number of UFS inodes can fit in ino_t */
209 if (ustat(st.st_rdev, &ustatarea) >= 0) {
210 if (mountpoint == NULL) {
211 printf("%s is mounted, can't tunefs\n", special);
212 exit(32);
214 } else
215 mountpoint = NULL;
217 if ((st.st_mode & S_IFMT) != S_IFBLK &&
218 (st.st_mode & S_IFMT) != S_IFCHR)
219 fatal("%s: not a block or character device", special);
220 getsb(&sblock, special);
221 while ((opt = getopt(argc, argv, "o:m:e:d:a:AV")) != EOF) {
222 switch (opt) {
224 case 'A':
225 Aflag++;
226 continue;
228 case 'a':
229 name = "maximum contiguous block count";
230 if (!isnumber(optarg))
231 fatal("%s: %s must be >= 1", *argv, name);
232 i = atoi(optarg);
233 if (i < 1)
234 fatal("%s: %s must be >= 1", *argv, name);
235 fprintf(stdout, "%s changes from %d to %d\n",
236 name, sblock.fs_maxcontig, i);
237 sblock.fs_maxcontig = i;
238 continue;
240 case 'd':
241 sblock.fs_rotdelay = 0;
242 continue;
244 case 'e':
245 name =
246 "maximum blocks per file in a cylinder group";
247 if (!isnumber(optarg))
248 fatal("%s: %s must be >= 1", *argv, name);
249 i = atoi(optarg);
250 if (i < 1)
251 fatal("%s: %s must be >= 1", *argv, name);
252 fprintf(stdout, "%s changes from %d to %d\n",
253 name, sblock.fs_maxbpg, i);
254 sblock.fs_maxbpg = i;
255 continue;
257 case 'm':
258 name = "minimum percentage of free space";
259 if (!isnumber(optarg))
260 fatal("%s: bad %s", *argv, name);
261 i = atoi(optarg);
262 if (i < 0 || i > 99)
263 fatal("%s: bad %s", *argv, name);
264 fprintf(stdout,
265 "%s changes from %d%% to %d%%\n",
266 name, sblock.fs_minfree, i);
267 sblock.fs_minfree = i;
268 continue;
270 case 'o':
271 name = "optimization preference";
272 chg[FS_OPTSPACE] = "space";
273 chg[FS_OPTTIME] = "time";
274 if (strcmp(optarg, chg[FS_OPTSPACE]) == 0)
275 i = FS_OPTSPACE;
276 else if (strcmp(optarg, chg[FS_OPTTIME]) == 0)
277 i = FS_OPTTIME;
278 else
279 fatal("%s: bad %s (options are `space' or `time')",
280 optarg, name);
281 if (sblock.fs_optim == i) {
282 fprintf(stdout,
283 "%s remains unchanged as %s\n",
284 name, chg[i]);
285 continue;
287 fprintf(stdout,
288 "%s changes from %s to %s\n",
289 name, chg[sblock.fs_optim], chg[i]);
290 sblock.fs_optim = i;
291 continue;
293 case 'V':
295 char *opt_text;
296 int opt_count;
298 (void) fprintf(stdout, "tunefs -F ufs ");
299 for (opt_count = 1; opt_count < argc;
300 opt_count++) {
301 opt_text = argv[opt_count];
302 if (opt_text)
303 (void) fprintf(stdout, " %s ",
304 opt_text);
306 (void) fprintf(stdout, "\n");
308 break;
310 default:
311 usage();
314 if ((argc - optind) != 1)
315 usage();
316 if (mountpoint) {
317 mountfd = open(mountpoint, O_RDONLY);
318 if (mountfd == -1) {
319 perror(mountpoint);
320 fprintf(stderr,
321 "tunefs: can't tune %s\n", mountpoint);
322 exit(32);
324 fiotune.maxcontig = sblock.fs_maxcontig;
325 fiotune.rotdelay = sblock.fs_rotdelay;
326 fiotune.maxbpg = sblock.fs_maxbpg;
327 fiotune.minfree = sblock.fs_minfree;
328 fiotune.optim = sblock.fs_optim;
329 if (ioctl(mountfd, _FIOTUNE, &fiotune) == -1) {
330 perror(mountpoint);
331 fprintf(stderr,
332 "tunefs: can't tune %s\n", mountpoint);
333 exit(32);
335 close(mountfd);
336 } else {
337 bwrite((diskaddr_t)SBLOCK, (char *)&sblock, SBSIZE);
339 if (Aflag)
340 for (i = 0; i < sblock.fs_ncg; i++)
341 bwrite(fsbtodb(&sblock, cgsblock(&sblock, i)),
342 (char *)&sblock, SBSIZE);
345 close(fi);
346 return (0);
349 void
350 usage()
352 fprintf(stderr, "ufs usage: tunefs tuneup-options special-device\n");
353 fprintf(stderr, "where tuneup-options are:\n");
354 fprintf(stderr, "\t-a maximum contiguous blocks\n");
355 fprintf(stderr, "\t-d rotational delay between contiguous blocks\n");
356 fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n");
357 fprintf(stderr, "\t-m minimum percentage of free space\n");
358 fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
359 exit(31+2);
362 void
363 getsb(struct fs *fs, char *file)
366 fi = open64(file, O_RDWR);
367 if (fi < 0) {
368 fprintf(stderr, "Cannot open ");
369 perror(file);
370 exit(31+3);
372 if (bread((diskaddr_t)SBLOCK, (char *)fs, SBSIZE)) {
373 fprintf(stderr, "Bad super block ");
374 perror(file);
375 exit(31+4);
377 if ((fs->fs_magic != FS_MAGIC) && (fs->fs_magic != MTB_UFS_MAGIC)) {
378 fprintf(stderr, "%s: bad magic number\n", file);
379 exit(31+5);
381 if (fs->fs_magic == FS_MAGIC &&
382 (fs->fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
383 fs->fs_version != UFS_VERSION_MIN)) {
384 fprintf(stderr, "%s: unrecognized ufs version: %d\n", file,
385 fs->fs_version);
386 exit(31+5);
388 if (fs->fs_magic == MTB_UFS_MAGIC &&
389 (fs->fs_version > MTB_UFS_VERSION_1 ||
390 fs->fs_version < MTB_UFS_VERSION_MIN)) {
391 fprintf(stderr, "%s: unrecognized ufs version: %d\n", file,
392 fs->fs_version);
393 exit(31+5);
397 void
398 bwrite(diskaddr_t blk, char *buf, int size)
400 if (llseek(fi, (offset_t)blk * DEV_BSIZE, 0) < 0) {
401 perror("FS SEEK");
402 exit(31+6);
404 if (write(fi, buf, size) != size) {
405 perror("FS WRITE");
406 exit(31+7);
411 bread(diskaddr_t bno, char *buf, int cnt)
413 int i;
415 if (llseek(fi, (offset_t)bno * DEV_BSIZE, 0) < 0) {
416 fprintf(stderr, "bread: ");
417 perror("llseek");
418 return (1);
420 if ((i = read(fi, buf, cnt)) != cnt) {
421 perror("read");
422 for (i = 0; i < sblock.fs_bsize; i++)
423 buf[i] = 0;
424 return (1);
426 return (0);
429 /* VARARGS1 */
430 void
431 fatal(char *fmt, char *arg1, char *arg2)
433 fprintf(stderr, "tunefs: ");
434 fprintf(stderr, fmt, arg1, arg2);
435 putc('\n', stderr);
436 exit(31+10);
441 isnumber(char *s)
443 int c;
445 while (c = *s++)
446 if (c < '0' || c > '9')
447 return (0);
448 return (1);