1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static const char copyright[] = 36 "@(#) Copyright (c) 1983, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)tunefs.c 8.2 (Berkeley) 4/19/94"; 43 #endif 44 static const char rcsid[] = 45 "$FreeBSD$"; 46 #endif /* not lint */ 47 48 /* 49 * tunefs: change layout parameters to an existing file system. 50 */ 51 #include <sys/param.h> 52 #include <sys/mount.h> 53 #include <sys/stat.h> 54 55 #include <ufs/ffs/fs.h> 56 #include <ufs/ufs/ufsmount.h> 57 58 #include <err.h> 59 #include <fcntl.h> 60 #include <fstab.h> 61 #include <paths.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <unistd.h> 66 67 /* the optimization warning string template */ 68 #define OPTWARN "should optimize for %s with minfree %s %d%%" 69 70 union { 71 struct fs sb; 72 char pad[MAXBSIZE]; 73 } sbun; 74 #define sblock sbun.sb 75 76 int fi; 77 long dev_bsize = 1; 78 79 void bwrite __P((daddr_t, char *, int)); 80 int bread __P((daddr_t, char *, int)); 81 void getsb __P((struct fs *, char *)); 82 void putsb __P((struct fs *, char *, int)); 83 void usage __P((void)); 84 void printfs __P((void)); 85 86 int 87 main(argc, argv) 88 int argc; 89 char *argv[]; 90 { 91 char *special, *name; 92 struct stat st; 93 int Aflag = 0, active = 0; 94 int aflag = 0, dflag = 0, eflag = 0, fflag = 0, mflag = 0; 95 int nflag = 0, oflag = 0, pflag = 0, sflag = 0; 96 int avalue = 0, dvalue = 0, evalue = 0, fvalue = 0; 97 int mvalue = 0, ovalue = 0, svalue = 0; 98 char *nvalue = NULL; 99 struct fstab *fs; 100 char *chg[2], device[MAXPATHLEN]; 101 struct ufs_args args; 102 struct statfs stfs; 103 int found_arg, ch; 104 105 if (argc < 3) 106 usage(); 107 found_arg = 0; /* at least one arg is required */ 108 while ((ch = getopt(argc, argv, "Aa:d:e:f:m:n:o:ps:")) != -1) 109 switch (ch) { 110 case 'A': 111 found_arg = 1; 112 Aflag++; 113 break; 114 case 'a': 115 found_arg = 1; 116 name = "maximum contiguous block count"; 117 avalue = atoi(optarg); 118 if (avalue < 1) 119 errx(10, "%s must be >= 1 (was %s)", name, optarg); 120 aflag = 1; 121 break; 122 case 'd': 123 found_arg = 1; 124 name = "rotational delay between contiguous blocks"; 125 dvalue = atoi(optarg); 126 dflag = 1; 127 break; 128 case 'e': 129 found_arg = 1; 130 name = "maximum blocks per file in a cylinder group"; 131 evalue = atoi(optarg); 132 if (evalue < 1) 133 errx(10, "%s must be >= 1 (was %s)", name, optarg); 134 eflag = 1; 135 break; 136 case 'f': 137 found_arg = 1; 138 name = "average file size"; 139 fvalue = atoi(optarg); 140 if (fvalue < 1) 141 errx(10, "%s must be >= 1 (was %s)", name, optarg); 142 fflag = 1; 143 break; 144 case 'm': 145 found_arg = 1; 146 name = "minimum percentage of free space"; 147 mvalue = atoi(optarg); 148 if (mvalue < 0 || mvalue > 99) 149 errx(10, "bad %s (%s)", name, optarg); 150 mflag = 1; 151 break; 152 case 'n': 153 found_arg = 1; 154 name = "soft updates"; 155 nvalue = optarg; 156 if (strcmp(nvalue, "enable") && strcmp(nvalue, "disable")) { 157 errx(10, "bad %s (options are %s)", 158 name, "`enable' or `disable'"); 159 } 160 nflag = 1; 161 break; 162 case 'o': 163 found_arg = 1; 164 name = "optimization preference"; 165 chg[FS_OPTSPACE] = "space"; 166 chg[FS_OPTTIME] = "time"; 167 if (strcmp(optarg, chg[FS_OPTSPACE]) == 0) 168 ovalue = FS_OPTSPACE; 169 else if (strcmp(optarg, chg[FS_OPTTIME]) == 0) 170 ovalue = FS_OPTTIME; 171 else 172 errx(10, "bad %s (options are `space' or `time')", 173 name); 174 oflag = 1; 175 break; 176 case 'p': 177 found_arg = 1; 178 pflag = 1; 179 break; 180 case 's': 181 found_arg = 1; 182 name = "expected number of files per directory"; 183 svalue = atoi(optarg); 184 if (svalue < 1) 185 errx(10, "%s must be >= 1 (was %s)", name, optarg); 186 sflag = 1; 187 break; 188 default: 189 usage(); 190 } 191 argc -= optind; 192 argv += optind; 193 194 if (found_arg == 0 || argc != 1) 195 usage(); 196 197 special = argv[0]; 198 fs = getfsfile(special); 199 if (fs) { 200 if (statfs(special, &stfs) == 0 && 201 strcmp(special, stfs.f_mntonname) == 0) { 202 active = 1; 203 } 204 special = fs->fs_spec; 205 } 206 again: 207 if (stat(special, &st) < 0) { 208 if (*special != '/') { 209 if (*special == 'r') 210 special++; 211 (void)sprintf(device, "%s/%s", _PATH_DEV, special); 212 special = device; 213 goto again; 214 } 215 err(1, "%s", special); 216 } 217 if ((st.st_mode & S_IFMT) != S_IFBLK && 218 (st.st_mode & S_IFMT) != S_IFCHR) 219 errx(10, "%s: not a block or character device", special); 220 getsb(&sblock, special); 221 222 if (pflag) { 223 printfs(); 224 exit(0); 225 } 226 if (aflag) { 227 name = "maximum contiguous block count"; 228 if (sblock.fs_maxcontig == avalue) { 229 warnx("%s remains unchanged as %d", name, avalue); 230 } 231 else { 232 warnx("%s changes from %d to %d", 233 name, sblock.fs_maxcontig, avalue); 234 sblock.fs_maxcontig = avalue; 235 } 236 } 237 if (dflag) { 238 name = "rotational delay between contiguous blocks"; 239 if (sblock.fs_rotdelay == dvalue) { 240 warnx("%s remains unchanged as %dms", name, dvalue); 241 } 242 else { 243 warnx("%s changes from %dms to %dms", 244 name, sblock.fs_rotdelay, dvalue); 245 sblock.fs_rotdelay = dvalue; 246 } 247 } 248 if (eflag) { 249 name = "maximum blocks per file in a cylinder group"; 250 if (sblock.fs_maxbpg == evalue) { 251 warnx("%s remains unchanged as %d", name, evalue); 252 } 253 else { 254 warnx("%s changes from %d to %d", 255 name, sblock.fs_maxbpg, evalue); 256 sblock.fs_maxbpg = evalue; 257 } 258 } 259 if (fflag) { 260 name = "average file size"; 261 if (sblock.fs_avgfilesize == fvalue) { 262 warnx("%s remains unchanged as %d", name, fvalue); 263 } 264 else { 265 warnx("%s changes from %d to %d", 266 name, sblock.fs_avgfilesize, fvalue); 267 sblock.fs_avgfilesize = fvalue; 268 } 269 } 270 if (mflag) { 271 name = "minimum percentage of free space"; 272 if (sblock.fs_minfree == mvalue) { 273 warnx("%s remains unchanged as %d%%", name, mvalue); 274 } 275 else { 276 warnx("%s changes from %d%% to %d%%", 277 name, sblock.fs_minfree, mvalue); 278 sblock.fs_minfree = mvalue; 279 if (mvalue >= MINFREE && sblock.fs_optim == FS_OPTSPACE) 280 warnx(OPTWARN, "time", ">=", MINFREE); 281 if (mvalue < MINFREE && sblock.fs_optim == FS_OPTTIME) 282 warnx(OPTWARN, "space", "<", MINFREE); 283 } 284 } 285 if (nflag) { 286 name = "soft updates"; 287 if (strcmp(nvalue, "enable") == 0) { 288 if (sblock.fs_flags & FS_DOSOFTDEP) { 289 warnx("%s remains unchanged as enabled", name); 290 } else if (sblock.fs_clean == 0) { 291 warnx("%s cannot be enabled until fsck is run", 292 name); 293 } else { 294 sblock.fs_flags |= FS_DOSOFTDEP; 295 warnx("%s set", name); 296 } 297 } else if (strcmp(nvalue, "disable") == 0) { 298 if ((~sblock.fs_flags & FS_DOSOFTDEP) == FS_DOSOFTDEP) { 299 warnx("%s remains unchanged as disabled", name); 300 } else { 301 sblock.fs_flags &= ~FS_DOSOFTDEP; 302 warnx("%s cleared", name); 303 } 304 } 305 } 306 if (oflag) { 307 name = "optimization preference"; 308 chg[FS_OPTSPACE] = "space"; 309 chg[FS_OPTTIME] = "time"; 310 if (sblock.fs_optim == ovalue) { 311 warnx("%s remains unchanged as %s", name, chg[ovalue]); 312 } 313 else { 314 warnx("%s changes from %s to %s", 315 name, chg[sblock.fs_optim], chg[ovalue]); 316 sblock.fs_optim = ovalue; 317 if (sblock.fs_minfree >= MINFREE && 318 ovalue == FS_OPTSPACE) 319 warnx(OPTWARN, "time", ">=", MINFREE); 320 if (sblock.fs_minfree < MINFREE && 321 ovalue == FS_OPTTIME) 322 warnx(OPTWARN, "space", "<", MINFREE); 323 } 324 } 325 if (sflag) { 326 name = "expected number of files per directory"; 327 if (sblock.fs_avgfpdir == svalue) { 328 warnx("%s remains unchanged as %d", name, svalue); 329 } 330 else { 331 warnx("%s changes from %d to %d", 332 name, sblock.fs_avgfpdir, svalue); 333 sblock.fs_avgfpdir = svalue; 334 } 335 } 336 337 putsb(&sblock, special, Aflag); 338 if (active) { 339 bzero(&args, sizeof(args)); 340 if (mount("ufs", fs->fs_file, 341 stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0) 342 err(9, "%s: reload", special); 343 warnx("file system reloaded"); 344 } 345 exit(0); 346 } 347 348 void 349 usage() 350 { 351 fprintf(stderr, "%s\n%s\n%s\n", 352 "usage: tunefs [-A] [-a maxcontig] [-d rotdelay] [-e maxbpg] [-f avgfilesize]", 353 " [-m minfree] [-p] [-n enable | disable] [-o space | time]", 354 " [-s filesperdir] special | filesystem"); 355 exit(2); 356 } 357 358 void 359 getsb(fs, file) 360 register struct fs *fs; 361 char *file; 362 { 363 364 fi = open(file, O_RDONLY); 365 if (fi < 0) 366 err(3, "cannot open %s", file); 367 if (bread((daddr_t)SBOFF, (char *)fs, SBSIZE)) 368 err(4, "%s: bad super block", file); 369 if (fs->fs_magic != FS_MAGIC) 370 err(5, "%s: bad magic number", file); 371 dev_bsize = fs->fs_fsize / fsbtodb(fs, 1); 372 } 373 374 void 375 putsb(fs, file, all) 376 register struct fs *fs; 377 char *file; 378 int all; 379 { 380 int i; 381 382 /* 383 * Re-open the device read-write. Use the read-only file 384 * descriptor as an interlock to prevent the device from 385 * being mounted while we are switching mode. 386 */ 387 i = fi; 388 fi = open(file, O_RDWR); 389 close(i); 390 if (fi < 0) 391 err(3, "cannot open %s", file); 392 bwrite((daddr_t)SBOFF / dev_bsize, (char *)fs, SBSIZE); 393 if (all) 394 for (i = 0; i < fs->fs_ncg; i++) 395 bwrite(fsbtodb(fs, cgsblock(fs, i)), 396 (char *)fs, SBSIZE); 397 close(fi); 398 } 399 400 void 401 printfs() 402 { 403 warnx("soft updates: (-n) %s", 404 (sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled"); 405 warnx("maximum contiguous block count: (-a) %d", 406 sblock.fs_maxcontig); 407 warnx("rotational delay between contiguous blocks: (-d) %d ms", 408 sblock.fs_rotdelay); 409 warnx("maximum blocks per file in a cylinder group: (-e) %d", 410 sblock.fs_maxbpg); 411 warnx("average file size: (-f) %d", 412 sblock.fs_avgfilesize); 413 warnx("average number of files in a directory: (-s) %d", 414 sblock.fs_avgfpdir); 415 warnx("minimum percentage of free space: (-m) %d%%", 416 sblock.fs_minfree); 417 warnx("optimization preference: (-o) %s", 418 sblock.fs_optim == FS_OPTSPACE ? "space" : "time"); 419 if (sblock.fs_minfree >= MINFREE && 420 sblock.fs_optim == FS_OPTSPACE) 421 warnx(OPTWARN, "time", ">=", MINFREE); 422 if (sblock.fs_minfree < MINFREE && 423 sblock.fs_optim == FS_OPTTIME) 424 warnx(OPTWARN, "space", "<", MINFREE); 425 } 426 427 void 428 bwrite(blk, buf, size) 429 daddr_t blk; 430 char *buf; 431 int size; 432 { 433 434 if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0) 435 err(6, "FS SEEK"); 436 if (write(fi, buf, size) != size) 437 err(7, "FS WRITE"); 438 } 439 440 int 441 bread(bno, buf, cnt) 442 daddr_t bno; 443 char *buf; 444 int cnt; 445 { 446 int i; 447 448 if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0) 449 return(1); 450 if ((i = read(fi, buf, cnt)) != cnt) { 451 for(i=0; i<sblock.fs_bsize; i++) 452 buf[i] = 0; 453 return (1); 454 } 455 return (0); 456 } 457