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 /* 40 * tunefs: change layout parameters to an existing file system. 41 */ 42 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> 51 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) 55 56 #define index(s, r) strchr(s, r) 57 #define rindex(s, r) strrchr(s, r) 58 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> 71 72 extern offset_t llseek(); 73 74 union { 75 struct fs sb; 76 char pad[SBSIZE]; 77 } sbun; 78 #define sblock sbun.sb 79 80 int fi; 81 struct ustat ustatarea; 82 extern int optind; 83 extern char *optarg; 84 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 *); 91 92 extern char *getfullrawname(), *getfullblkname(); 93 94 static void 95 searchvfstab(char **specialp) 96 { 97 FILE *vfstab; 98 struct vfstab vfsbuf; 99 char *blockspecial; 100 101 blockspecial = getfullblkname(*specialp); 102 if (blockspecial == NULL) 103 blockspecial = *specialp; 104 105 if ((vfstab = fopen(VFSTAB, "r")) == NULL) { 106 fprintf(stderr, "%s: ", VFSTAB); 107 perror("open"); 108 } 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; 117 } 118 fclose(vfstab); 119 } 120 121 static void 122 searchmnttab(char **specialp, char **mountpointp) 123 { 124 FILE *mnttab; 125 struct mnttab mntbuf; 126 char *blockspecial; 127 128 blockspecial = getfullblkname(*specialp); 129 if (blockspecial == NULL) 130 blockspecial = *specialp; 131 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; 142 } 143 fclose(mnttab); 144 } 145 146 int 147 main(int argc, char *argv[]) 148 { 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; 156 157 158 if (argc < 3) 159 usage(); 160 special = argv[argc - 1]; 161 162 /* 163 * For performance, don't search mnttab unless necessary 164 */ 165 166 if (stat64(special, &st) >= 0) { 167 /* 168 * If mounted directory, search mnttab for special 169 */ 170 if ((st.st_mode & S_IFMT) == S_IFDIR) { 171 if (st.st_ino == UFSROOTINO) 172 searchmnttab(&special, &mountpoint); 173 /* 174 * If mounted device, search mnttab for mountpoint 175 */ 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); 180 } 181 } 182 /* 183 * Doesn't appear to be mounted; take ``unmounted'' path 184 */ 185 if (mountpoint == NULL) 186 searchvfstab(&special); 187 188 if ((special = getfullrawname(special)) == NULL) { 189 fprintf(stderr, "tunefs: malloc failed\n"); 190 exit(32); 191 } 192 193 if (*special == '\0') { 194 fprintf(stderr, "tunefs: Could not find raw device for %s\n", 195 argv[argc -1]); 196 exit(32); 197 } 198 199 if (stat64(special, &st) < 0) { 200 fprintf(stderr, "tunefs: "); perror(special); 201 exit(31+1); 202 } 203 204 /* 205 * If a mountpoint has been found then we will ioctl() the file 206 * system instead of writing to the file system's device 207 */ 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); 213 } 214 } else 215 mountpoint = NULL; 216 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) { 223 224 case 'A': 225 Aflag++; 226 continue; 227 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; 239 240 case 'd': 241 sblock.fs_rotdelay = 0; 242 continue; 243 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; 256 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; 269 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; 286 } 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; 292 293 case 'V': 294 { 295 char *opt_text; 296 int opt_count; 297 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); 305 } 306 (void) fprintf(stdout, "\n"); 307 } 308 break; 309 310 default: 311 usage(); 312 } 313 } 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); 323 } 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); 334 } 335 close(mountfd); 336 } else { 337 bwrite((diskaddr_t)SBLOCK, (char *)&sblock, SBSIZE); 338 339 if (Aflag) 340 for (i = 0; i < sblock.fs_ncg; i++) 341 bwrite(fsbtodb(&sblock, cgsblock(&sblock, i)), 342 (char *)&sblock, SBSIZE); 343 } 344 345 close(fi); 346 return (0); 347 } 348 349 void 350 usage() 351 { 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); 360 } 361 362 void 363 getsb(struct fs *fs, char *file) 364 { 365 366 fi = open64(file, O_RDWR); 367 if (fi < 0) { 368 fprintf(stderr, "Cannot open "); 369 perror(file); 370 exit(31+3); 371 } 372 if (bread((diskaddr_t)SBLOCK, (char *)fs, SBSIZE)) { 373 fprintf(stderr, "Bad super block "); 374 perror(file); 375 exit(31+4); 376 } 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); 380 } 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); 387 } 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); 394 } 395 } 396 397 void 398 bwrite(diskaddr_t blk, char *buf, int size) 399 { 400 if (llseek(fi, (offset_t)blk * DEV_BSIZE, 0) < 0) { 401 perror("FS SEEK"); 402 exit(31+6); 403 } 404 if (write(fi, buf, size) != size) { 405 perror("FS WRITE"); 406 exit(31+7); 407 } 408 } 409 410 int 411 bread(diskaddr_t bno, char *buf, int cnt) 412 { 413 int i; 414 415 if (llseek(fi, (offset_t)bno * DEV_BSIZE, 0) < 0) { 416 fprintf(stderr, "bread: "); 417 perror("llseek"); 418 return (1); 419 } 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); 425 } 426 return (0); 427 } 428 429 /* VARARGS1 */ 430 void 431 fatal(char *fmt, char *arg1, char *arg2) 432 { 433 fprintf(stderr, "tunefs: "); 434 fprintf(stderr, fmt, arg1, arg2); 435 putc('\n', stderr); 436 exit(31+10); 437 } 438 439 440 int 441 isnumber(char *s) 442 { 443 int c; 444 445 while (c = *s++) 446 if (c < '0' || c > '9') 447 return (0); 448 return (1); 449 } 450