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 ((st.st_mode & S_IFMT) != S_IFBLK && 221 (st.st_mode & S_IFMT) != S_IFCHR) 222 errx(10, "%s: not a block or character device", special); 223 getsb(&sblock, special); 224 225 if (pflag) { 226 printfs(); 227 exit(0); 228 } 229 if (aflag) { 230 name = "maximum contiguous block count"; 231 if (sblock.fs_maxcontig == avalue) { 232 warnx("%s remains unchanged as %d", name, avalue); 233 } 234 else { 235 warnx("%s changes from %d to %d", 236 name, sblock.fs_maxcontig, avalue); 237 sblock.fs_maxcontig = avalue; 238 } 239 } 240 if (dflag) { 241 name = "rotational delay between contiguous blocks"; 242 if (sblock.fs_rotdelay == dvalue) { 243 warnx("%s remains unchanged as %dms", name, dvalue); 244 } 245 else { 246 warnx("%s changes from %dms to %dms", 247 name, sblock.fs_rotdelay, dvalue); 248 sblock.fs_rotdelay = dvalue; 249 } 250 } 251 if (eflag) { 252 name = "maximum blocks per file in a cylinder group"; 253 if (sblock.fs_maxbpg == evalue) { 254 warnx("%s remains unchanged as %d", name, evalue); 255 } 256 else { 257 warnx("%s changes from %d to %d", 258 name, sblock.fs_maxbpg, evalue); 259 sblock.fs_maxbpg = evalue; 260 } 261 } 262 if (fflag) { 263 name = "average file size"; 264 if (sblock.fs_avgfilesize == fvalue) { 265 warnx("%s remains unchanged as %d", name, fvalue); 266 } 267 else { 268 warnx("%s changes from %d to %d", 269 name, sblock.fs_avgfilesize, fvalue); 270 sblock.fs_avgfilesize = fvalue; 271 } 272 } 273 if (mflag) { 274 name = "minimum percentage of free space"; 275 if (sblock.fs_minfree == mvalue) { 276 warnx("%s remains unchanged as %d%%", name, mvalue); 277 } 278 else { 279 warnx("%s changes from %d%% to %d%%", 280 name, sblock.fs_minfree, mvalue); 281 sblock.fs_minfree = mvalue; 282 if (mvalue >= MINFREE && sblock.fs_optim == FS_OPTSPACE) 283 warnx(OPTWARN, "time", ">=", MINFREE); 284 if (mvalue < MINFREE && sblock.fs_optim == FS_OPTTIME) 285 warnx(OPTWARN, "space", "<", MINFREE); 286 } 287 } 288 if (nflag) { 289 name = "soft updates"; 290 if (strcmp(nvalue, "enable") == 0) { 291 if (sblock.fs_flags & FS_DOSOFTDEP) { 292 warnx("%s remains unchanged as enabled", name); 293 } else if (sblock.fs_clean == 0) { 294 warnx("%s cannot be enabled until fsck is run", 295 name); 296 } else { 297 sblock.fs_flags |= FS_DOSOFTDEP; 298 warnx("%s set", name); 299 } 300 } else if (strcmp(nvalue, "disable") == 0) { 301 if ((~sblock.fs_flags & FS_DOSOFTDEP) == FS_DOSOFTDEP) { 302 warnx("%s remains unchanged as disabled", name); 303 } else { 304 sblock.fs_flags &= ~FS_DOSOFTDEP; 305 warnx("%s cleared", name); 306 } 307 } 308 } 309 if (oflag) { 310 name = "optimization preference"; 311 chg[FS_OPTSPACE] = "space"; 312 chg[FS_OPTTIME] = "time"; 313 if (sblock.fs_optim == ovalue) { 314 warnx("%s remains unchanged as %s", name, chg[ovalue]); 315 } 316 else { 317 warnx("%s changes from %s to %s", 318 name, chg[sblock.fs_optim], chg[ovalue]); 319 sblock.fs_optim = ovalue; 320 if (sblock.fs_minfree >= MINFREE && 321 ovalue == FS_OPTSPACE) 322 warnx(OPTWARN, "time", ">=", MINFREE); 323 if (sblock.fs_minfree < MINFREE && 324 ovalue == FS_OPTTIME) 325 warnx(OPTWARN, "space", "<", MINFREE); 326 } 327 } 328 if (sflag) { 329 name = "expected number of files per directory"; 330 if (sblock.fs_avgfpdir == svalue) { 331 warnx("%s remains unchanged as %d", name, svalue); 332 } 333 else { 334 warnx("%s changes from %d to %d", 335 name, sblock.fs_avgfpdir, svalue); 336 sblock.fs_avgfpdir = svalue; 337 } 338 } 339 340 putsb(&sblock, special, Aflag); 341 if (active) { 342 bzero(&args, sizeof(args)); 343 if (mount("ufs", fs->fs_file, 344 stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0) 345 err(9, "%s: reload", special); 346 warnx("file system reloaded"); 347 } 348 exit(0); 349 } 350 351 void 352 usage() 353 { 354 fprintf(stderr, "%s\n%s\n%s\n", 355 "usage: tunefs [-A] [-a maxcontig] [-d rotdelay] [-e maxbpg] [-f avgfilesize]", 356 " [-m minfree] [-p] [-n enable | disable] [-o space | time]", 357 " [-s filesperdir] special | filesystem"); 358 exit(2); 359 } 360 361 void 362 getsb(fs, file) 363 struct fs *fs; 364 const char *file; 365 { 366 367 fi = open(file, O_RDONLY); 368 if (fi < 0) 369 err(3, "cannot open %s", file); 370 if (bread((daddr_t)SBOFF, (char *)fs, SBSIZE)) 371 err(4, "%s: bad super block", file); 372 if (fs->fs_magic != FS_MAGIC) 373 err(5, "%s: bad magic number", file); 374 dev_bsize = fs->fs_fsize / fsbtodb(fs, 1); 375 } 376 377 void 378 putsb(fs, file, all) 379 struct fs *fs; 380 const char *file; 381 int all; 382 { 383 int i; 384 385 /* 386 * Re-open the device read-write. Use the read-only file 387 * descriptor as an interlock to prevent the device from 388 * being mounted while we are switching mode. 389 */ 390 i = fi; 391 fi = open(file, O_RDWR); 392 close(i); 393 if (fi < 0) 394 err(3, "cannot open %s", file); 395 bwrite((daddr_t)SBOFF / dev_bsize, (const char *)fs, SBSIZE); 396 if (all) 397 for (i = 0; i < fs->fs_ncg; i++) 398 bwrite(fsbtodb(fs, cgsblock(fs, i)), 399 (const char *)fs, SBSIZE); 400 close(fi); 401 } 402 403 void 404 printfs() 405 { 406 warnx("soft updates: (-n) %s", 407 (sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled"); 408 warnx("maximum contiguous block count: (-a) %d", 409 sblock.fs_maxcontig); 410 warnx("rotational delay between contiguous blocks: (-d) %d ms", 411 sblock.fs_rotdelay); 412 warnx("maximum blocks per file in a cylinder group: (-e) %d", 413 sblock.fs_maxbpg); 414 warnx("average file size: (-f) %d", 415 sblock.fs_avgfilesize); 416 warnx("average number of files in a directory: (-s) %d", 417 sblock.fs_avgfpdir); 418 warnx("minimum percentage of free space: (-m) %d%%", 419 sblock.fs_minfree); 420 warnx("optimization preference: (-o) %s", 421 sblock.fs_optim == FS_OPTSPACE ? "space" : "time"); 422 if (sblock.fs_minfree >= MINFREE && 423 sblock.fs_optim == FS_OPTSPACE) 424 warnx(OPTWARN, "time", ">=", MINFREE); 425 if (sblock.fs_minfree < MINFREE && 426 sblock.fs_optim == FS_OPTTIME) 427 warnx(OPTWARN, "space", "<", MINFREE); 428 } 429 430 void 431 bwrite(blk, buf, size) 432 daddr_t blk; 433 const char *buf; 434 int size; 435 { 436 437 if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0) 438 err(6, "FS SEEK"); 439 if (write(fi, buf, size) != size) 440 err(7, "FS WRITE"); 441 } 442 443 int 444 bread(bno, buf, cnt) 445 daddr_t bno; 446 char *buf; 447 int cnt; 448 { 449 int i; 450 451 if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0) 452 return(1); 453 if ((i = read(fi, buf, cnt)) != cnt) { 454 for(i=0; i<sblock.fs_bsize; i++) 455 buf[i] = 0; 456 return (1); 457 } 458 return (0); 459 } 460