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