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
searchvfstab(char ** specialp)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
searchmnttab(char ** specialp,char ** mountpointp)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
main(int argc,char * argv[])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
usage()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
getsb(struct fs * fs,char * file)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
bwrite(diskaddr_t blk,char * buf,int size)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
bread(diskaddr_t bno,char * buf,int cnt)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
fatal(char * fmt,char * arg1,char * arg2)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
isnumber(char * s)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