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