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, const char *, int)); 80 int bread __P((daddr_t, char *, int)); 81 void getsb __P((struct fs *, const char *)); 82 void putsb __P((struct fs *, const 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; 92 const char *name; 93 struct stat st; 94 int Aflag = 0, active = 0; 95 int aflag = 0, dflag = 0, eflag = 0, fflag = 0, mflag = 0; 96 int nflag = 0, oflag = 0, pflag = 0, sflag = 0; 97 int avalue = 0, dvalue = 0, evalue = 0, fvalue = 0; 98 int mvalue = 0, ovalue = 0, svalue = 0; 99 char *nvalue = NULL; 100 struct fstab *fs; 101 const char *chg[2]; 102 char device[MAXPATHLEN]; 103 struct ufs_args args; 104 struct statfs stfs; 105 int found_arg, ch; 106 107 if (argc < 3) 108 usage(); 109 found_arg = 0; /* at least one arg is required */ 110 while ((ch = getopt(argc, argv, "Aa:d:e:f:m:n:o:ps:")) != -1) 111 switch (ch) { 112 case 'A': 113 found_arg = 1; 114 Aflag++; 115 break; 116 case 'a': 117 found_arg = 1; 118 name = "maximum contiguous block count"; 119 avalue = atoi(optarg); 120 if (avalue < 1) 121 errx(10, "%s must be >= 1 (was %s)", name, optarg); 122 aflag = 1; 123 break; 124 case 'd': 125 found_arg = 1; 126 name = "rotational delay between contiguous blocks"; 127 dvalue = atoi(optarg); 128 dflag = 1; 129 break; 130 case 'e': 131 found_arg = 1; 132 name = "maximum blocks per file in a cylinder group"; 133 evalue = atoi(optarg); 134 if (evalue < 1) 135 errx(10, "%s must be >= 1 (was %s)", name, optarg); 136 eflag = 1; 137 break; 138 case 'f': 139 found_arg = 1; 140 name = "average file size"; 141 fvalue = atoi(optarg); 142 if (fvalue < 1) 143 errx(10, "%s must be >= 1 (was %s)", name, optarg); 144 fflag = 1; 145 break; 146 case 'm': 147 found_arg = 1; 148 name = "minimum percentage of free space"; 149 mvalue = atoi(optarg); 150 if (mvalue < 0 || mvalue > 99) 151 errx(10, "bad %s (%s)", name, optarg); 152 mflag = 1; 153 break; 154 case 'n': 155 found_arg = 1; 156 name = "soft updates"; 157 nvalue = optarg; 158 if (strcmp(nvalue, "enable") && strcmp(nvalue, "disable")) { 159 errx(10, "bad %s (options are %s)", 160 name, "`enable' or `disable'"); 161 } 162 nflag = 1; 163 break; 164 case 'o': 165 found_arg = 1; 166 name = "optimization preference"; 167 chg[FS_OPTSPACE] = "space"; 168 chg[FS_OPTTIME] = "time"; 169 if (strcmp(optarg, chg[FS_OPTSPACE]) == 0) 170 ovalue = FS_OPTSPACE; 171 else if (strcmp(optarg, chg[FS_OPTTIME]) == 0) 172 ovalue = FS_OPTTIME; 173 else 174 errx(10, "bad %s (options are `space' or `time')", 175 name); 176 oflag = 1; 177 break; 178 case 'p': 179 found_arg = 1; 180 pflag = 1; 181 break; 182 case 's': 183 found_arg = 1; 184 name = "expected number of files per directory"; 185 svalue = atoi(optarg); 186 if (svalue < 1) 187 errx(10, "%s must be >= 1 (was %s)", name, optarg); 188 sflag = 1; 189 break; 190 default: 191 usage(); 192 } 193 argc -= optind; 194 argv += optind; 195 196 if (found_arg == 0 || argc != 1) 197 usage(); 198 199 special = argv[0]; 200 fs = getfsfile(special); 201 if (fs) { 202 if (statfs(special, &stfs) == 0 && 203 strcmp(special, stfs.f_mntonname) == 0) { 204 active = 1; 205 } 206 special = fs->fs_spec; 207 } 208 again: 209 if (stat(special, &st) < 0) { 210 if (*special != '/') { 211 if (*special == 'r') 212 special++; 213 (void)snprintf(device, sizeof(device), "%s%s", 214 _PATH_DEV, special); 215 special = device; 216 goto again; 217 } 218 err(1, "%s", special); 219 } 220 if (fs == NULL && (st.st_mode & S_IFMT) == S_IFDIR) 221 errx(10, "%s: unknown file system", special); 222 getsb(&sblock, special); 223 224 if (pflag) { 225 printfs(); 226 exit(0); 227 } 228 if (aflag) { 229 name = "maximum contiguous block count"; 230 if (sblock.fs_maxcontig == avalue) { 231 warnx("%s remains unchanged as %d", name, avalue); 232 } 233 else { 234 warnx("%s changes from %d to %d", 235 name, sblock.fs_maxcontig, avalue); 236 sblock.fs_maxcontig = avalue; 237 } 238 } 239 if (dflag) { 240 name = "rotational delay between contiguous blocks"; 241 if (sblock.fs_rotdelay == dvalue) { 242 warnx("%s remains unchanged as %dms", name, dvalue); 243 } 244 else { 245 warnx("%s changes from %dms to %dms", 246 name, sblock.fs_rotdelay, dvalue); 247 sblock.fs_rotdelay = dvalue; 248 } 249 } 250 if (eflag) { 251 name = "maximum blocks per file in a cylinder group"; 252 if (sblock.fs_maxbpg == evalue) { 253 warnx("%s remains unchanged as %d", name, evalue); 254 } 255 else { 256 warnx("%s changes from %d to %d", 257 name, sblock.fs_maxbpg, evalue); 258 sblock.fs_maxbpg = evalue; 259 } 260 } 261 if (fflag) { 262 name = "average file size"; 263 if (sblock.fs_avgfilesize == fvalue) { 264 warnx("%s remains unchanged as %d", name, fvalue); 265 } 266 else { 267 warnx("%s changes from %d to %d", 268 name, sblock.fs_avgfilesize, fvalue); 269 sblock.fs_avgfilesize = fvalue; 270 } 271 } 272 if (mflag) { 273 name = "minimum percentage of free space"; 274 if (sblock.fs_minfree == mvalue) { 275 warnx("%s remains unchanged as %d%%", name, mvalue); 276 } 277 else { 278 warnx("%s changes from %d%% to %d%%", 279 name, sblock.fs_minfree, mvalue); 280 sblock.fs_minfree = mvalue; 281 if (mvalue >= MINFREE && sblock.fs_optim == FS_OPTSPACE) 282 warnx(OPTWARN, "time", ">=", MINFREE); 283 if (mvalue < MINFREE && sblock.fs_optim == FS_OPTTIME) 284 warnx(OPTWARN, "space", "<", MINFREE); 285 } 286 } 287 if (nflag) { 288 name = "soft updates"; 289 if (strcmp(nvalue, "enable") == 0) { 290 if (sblock.fs_flags & FS_DOSOFTDEP) { 291 warnx("%s remains unchanged as enabled", name); 292 } else if (sblock.fs_clean == 0) { 293 warnx("%s cannot be enabled until fsck is run", 294 name); 295 } else { 296 sblock.fs_flags |= FS_DOSOFTDEP; 297 warnx("%s set", name); 298 } 299 } else if (strcmp(nvalue, "disable") == 0) { 300 if ((~sblock.fs_flags & FS_DOSOFTDEP) == FS_DOSOFTDEP) { 301 warnx("%s remains unchanged as disabled", name); 302 } else { 303 sblock.fs_flags &= ~FS_DOSOFTDEP; 304 warnx("%s cleared", name); 305 } 306 } 307 } 308 if (oflag) { 309 name = "optimization preference"; 310 chg[FS_OPTSPACE] = "space"; 311 chg[FS_OPTTIME] = "time"; 312 if (sblock.fs_optim == ovalue) { 313 warnx("%s remains unchanged as %s", name, chg[ovalue]); 314 } 315 else { 316 warnx("%s changes from %s to %s", 317 name, chg[sblock.fs_optim], chg[ovalue]); 318 sblock.fs_optim = ovalue; 319 if (sblock.fs_minfree >= MINFREE && 320 ovalue == FS_OPTSPACE) 321 warnx(OPTWARN, "time", ">=", MINFREE); 322 if (sblock.fs_minfree < MINFREE && 323 ovalue == FS_OPTTIME) 324 warnx(OPTWARN, "space", "<", MINFREE); 325 } 326 } 327 if (sflag) { 328 name = "expected number of files per directory"; 329 if (sblock.fs_avgfpdir == svalue) { 330 warnx("%s remains unchanged as %d", name, svalue); 331 } 332 else { 333 warnx("%s changes from %d to %d", 334 name, sblock.fs_avgfpdir, svalue); 335 sblock.fs_avgfpdir = svalue; 336 } 337 } 338 339 putsb(&sblock, special, Aflag); 340 if (active) { 341 bzero(&args, sizeof(args)); 342 if (mount("ufs", fs->fs_file, 343 stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0) 344 err(9, "%s: reload", special); 345 warnx("file system reloaded"); 346 } 347 exit(0); 348 } 349 350 void 351 usage() 352 { 353 fprintf(stderr, "%s\n%s\n%s\n", 354 "usage: tunefs [-A] [-a maxcontig] [-d rotdelay] [-e maxbpg] [-f avgfilesize]", 355 " [-m minfree] [-p] [-n enable | disable] [-o space | time]", 356 " [-s filesperdir] special | filesystem"); 357 exit(2); 358 } 359 360 void 361 getsb(fs, file) 362 struct fs *fs; 363 const char *file; 364 { 365 366 fi = open(file, O_RDONLY); 367 if (fi < 0) 368 err(3, "cannot open %s", file); 369 if (bread((daddr_t)SBOFF, (char *)fs, SBSIZE)) 370 err(4, "%s: bad super block", file); 371 if (fs->fs_magic != FS_MAGIC) 372 errx(5, "%s: bad magic number", file); 373 dev_bsize = fs->fs_fsize / fsbtodb(fs, 1); 374 } 375 376 void 377 putsb(fs, file, all) 378 struct fs *fs; 379 const char *file; 380 int all; 381 { 382 int i; 383 384 /* 385 * Re-open the device read-write. Use the read-only file 386 * descriptor as an interlock to prevent the device from 387 * being mounted while we are switching mode. 388 */ 389 i = fi; 390 fi = open(file, O_RDWR); 391 close(i); 392 if (fi < 0) 393 err(3, "cannot open %s", file); 394 bwrite((daddr_t)SBOFF / dev_bsize, (const char *)fs, SBSIZE); 395 if (all) 396 for (i = 0; i < fs->fs_ncg; i++) 397 bwrite(fsbtodb(fs, cgsblock(fs, i)), 398 (const char *)fs, SBSIZE); 399 close(fi); 400 } 401 402 void 403 printfs() 404 { 405 warnx("soft updates: (-n) %s", 406 (sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled"); 407 warnx("maximum contiguous block count: (-a) %d", 408 sblock.fs_maxcontig); 409 warnx("rotational delay between contiguous blocks: (-d) %d ms", 410 sblock.fs_rotdelay); 411 warnx("maximum blocks per file in a cylinder group: (-e) %d", 412 sblock.fs_maxbpg); 413 warnx("average file size: (-f) %d", 414 sblock.fs_avgfilesize); 415 warnx("average number of files in a directory: (-s) %d", 416 sblock.fs_avgfpdir); 417 warnx("minimum percentage of free space: (-m) %d%%", 418 sblock.fs_minfree); 419 warnx("optimization preference: (-o) %s", 420 sblock.fs_optim == FS_OPTSPACE ? "space" : "time"); 421 if (sblock.fs_minfree >= MINFREE && 422 sblock.fs_optim == FS_OPTSPACE) 423 warnx(OPTWARN, "time", ">=", MINFREE); 424 if (sblock.fs_minfree < MINFREE && 425 sblock.fs_optim == FS_OPTTIME) 426 warnx(OPTWARN, "space", "<", MINFREE); 427 } 428 429 void 430 bwrite(blk, buf, size) 431 daddr_t blk; 432 const char *buf; 433 int size; 434 { 435 436 if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0) 437 err(6, "FS SEEK"); 438 if (write(fi, buf, size) != size) 439 err(7, "FS WRITE"); 440 } 441 442 int 443 bread(bno, buf, cnt) 444 daddr_t bno; 445 char *buf; 446 int cnt; 447 { 448 int i; 449 450 if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0) 451 return(1); 452 if ((i = read(fi, buf, cnt)) != cnt) { 453 for(i=0; i<sblock.fs_bsize; i++) 454 buf[i] = 0; 455 return (1); 456 } 457 return (0); 458 } 459