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 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #if 0 31 #ifndef lint 32 static const char copyright[] = 33 "@(#) Copyright (c) 1983, 1993\n\ 34 The Regents of the University of California. All rights reserved.\n"; 35 #endif /* not lint */ 36 37 #ifndef lint 38 static char sccsid[] = "@(#)tunefs.c 8.2 (Berkeley) 4/19/94"; 39 #endif /* not lint */ 40 #endif 41 #include <sys/cdefs.h> 42 __FBSDID("$FreeBSD$"); 43 44 /* 45 * tunefs: change layout parameters to an existing file system. 46 */ 47 #include <sys/param.h> 48 #include <sys/mount.h> 49 #include <sys/disklabel.h> 50 #include <sys/stat.h> 51 52 #include <ufs/ufs/ufsmount.h> 53 #include <ufs/ufs/dinode.h> 54 #include <ufs/ffs/fs.h> 55 56 #include <ctype.h> 57 #include <err.h> 58 #include <fcntl.h> 59 #include <fstab.h> 60 #include <libufs.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 struct uufsd disk; 71 #define sblock disk.d_fs 72 73 void usage(void); 74 void printfs(void); 75 76 int 77 main(int argc, char *argv[]) 78 { 79 char *avalue, *Jvalue, *Lvalue, *lvalue, *Nvalue, *nvalue; 80 const char *special, *on; 81 const char *name; 82 int active; 83 int Aflag, aflag, eflag, evalue, fflag, fvalue, Jflag, Lflag, lflag; 84 int mflag, mvalue, Nflag, nflag, oflag, ovalue, pflag, sflag, svalue; 85 int ch, found_arg, i; 86 const char *chg[2]; 87 struct ufs_args args; 88 struct statfs stfs; 89 90 if (argc < 3) 91 usage(); 92 Aflag = aflag = eflag = fflag = Jflag = Lflag = lflag = mflag = 0; 93 Nflag = nflag = oflag = pflag = sflag = 0; 94 avalue = Jvalue = Lvalue = lvalue = Nvalue = nvalue = NULL; 95 evalue = fvalue = mvalue = ovalue = svalue = 0; 96 active = 0; 97 found_arg = 0; /* At least one arg is required. */ 98 while ((ch = getopt(argc, argv, "Aa:e:f:J:L:l:m:N:n:o:ps:")) != -1) 99 switch (ch) { 100 101 case 'A': 102 found_arg = 1; 103 Aflag++; 104 break; 105 106 case 'a': 107 found_arg = 1; 108 name = "POSIX.1e ACLs"; 109 avalue = optarg; 110 if (strcmp(avalue, "enable") && 111 strcmp(avalue, "disable")) { 112 errx(10, "bad %s (options are %s)", 113 name, "`enable' or `disable'"); 114 } 115 aflag = 1; 116 break; 117 118 case 'e': 119 found_arg = 1; 120 name = "maximum blocks per file in a cylinder group"; 121 evalue = atoi(optarg); 122 if (evalue < 1) 123 errx(10, "%s must be >= 1 (was %s)", 124 name, optarg); 125 eflag = 1; 126 break; 127 128 case 'f': 129 found_arg = 1; 130 name = "average file size"; 131 fvalue = atoi(optarg); 132 if (fvalue < 1) 133 errx(10, "%s must be >= 1 (was %s)", 134 name, optarg); 135 fflag = 1; 136 break; 137 138 case 'J': 139 found_arg = 1; 140 name = "gjournaled file system"; 141 Jvalue = optarg; 142 if (strcmp(Jvalue, "enable") && 143 strcmp(Jvalue, "disable")) { 144 errx(10, "bad %s (options are %s)", 145 name, "`enable' or `disable'"); 146 } 147 Jflag = 1; 148 break; 149 150 151 case 'L': 152 found_arg = 1; 153 name = "volume label"; 154 Lvalue = optarg; 155 i = -1; 156 while (isalnum(Lvalue[++i])); 157 if (Lvalue[i] != '\0') { 158 errx(10, 159 "bad %s. Valid characters are alphanumerics.", 160 name); 161 } 162 if (strlen(Lvalue) >= MAXVOLLEN) { 163 errx(10, "bad %s. Length is longer than %d.", 164 name, MAXVOLLEN - 1); 165 } 166 Lflag = 1; 167 break; 168 169 case 'l': 170 found_arg = 1; 171 name = "multilabel MAC file system"; 172 lvalue = optarg; 173 if (strcmp(lvalue, "enable") && 174 strcmp(lvalue, "disable")) { 175 errx(10, "bad %s (options are %s)", 176 name, "`enable' or `disable'"); 177 } 178 lflag = 1; 179 break; 180 181 case 'm': 182 found_arg = 1; 183 name = "minimum percentage of free space"; 184 mvalue = atoi(optarg); 185 if (mvalue < 0 || mvalue > 99) 186 errx(10, "bad %s (%s)", name, optarg); 187 mflag = 1; 188 break; 189 190 case 'N': 191 found_arg = 1; 192 name = "NFSv4 ACLs"; 193 Nvalue = optarg; 194 if (strcmp(Nvalue, "enable") && 195 strcmp(Nvalue, "disable")) { 196 errx(10, "bad %s (options are %s)", 197 name, "`enable' or `disable'"); 198 } 199 Nflag = 1; 200 break; 201 202 case 'n': 203 found_arg = 1; 204 name = "soft updates"; 205 nvalue = optarg; 206 if (strcmp(nvalue, "enable") != 0 && 207 strcmp(nvalue, "disable") != 0) { 208 errx(10, "bad %s (options are %s)", 209 name, "`enable' or `disable'"); 210 } 211 nflag = 1; 212 break; 213 214 case 'o': 215 found_arg = 1; 216 name = "optimization preference"; 217 if (strcmp(optarg, "space") == 0) 218 ovalue = FS_OPTSPACE; 219 else if (strcmp(optarg, "time") == 0) 220 ovalue = FS_OPTTIME; 221 else 222 errx(10, 223 "bad %s (options are `space' or `time')", 224 name); 225 oflag = 1; 226 break; 227 228 case 'p': 229 found_arg = 1; 230 pflag = 1; 231 break; 232 233 case 's': 234 found_arg = 1; 235 name = "expected number of files per directory"; 236 svalue = atoi(optarg); 237 if (svalue < 1) 238 errx(10, "%s must be >= 1 (was %s)", 239 name, optarg); 240 sflag = 1; 241 break; 242 243 default: 244 usage(); 245 } 246 argc -= optind; 247 argv += optind; 248 if (found_arg == 0 || argc != 1) 249 usage(); 250 251 on = special = argv[0]; 252 if (ufs_disk_fillout(&disk, special) == -1) 253 goto err; 254 if (disk.d_name != special) { 255 special = disk.d_name; 256 if (statfs(special, &stfs) == 0 && 257 strcmp(special, stfs.f_mntonname) == 0) 258 active = 1; 259 } 260 261 if (pflag) { 262 printfs(); 263 exit(0); 264 } 265 if (Lflag) { 266 name = "volume label"; 267 strlcpy(sblock.fs_volname, Lvalue, MAXVOLLEN); 268 } 269 if (aflag) { 270 name = "POSIX.1e ACLs"; 271 if (strcmp(avalue, "enable") == 0) { 272 if (sblock.fs_flags & FS_ACLS) { 273 warnx("%s remains unchanged as enabled", name); 274 } else if (sblock.fs_flags & FS_NFS4ACLS) { 275 warnx("%s and NFSv4 ACLs are mutually " 276 "exclusive", name); 277 } else { 278 sblock.fs_flags |= FS_ACLS; 279 warnx("%s set", name); 280 } 281 } else if (strcmp(avalue, "disable") == 0) { 282 if ((~sblock.fs_flags & FS_ACLS) == 283 FS_ACLS) { 284 warnx("%s remains unchanged as disabled", 285 name); 286 } else { 287 sblock.fs_flags &= ~FS_ACLS; 288 warnx("%s cleared", name); 289 } 290 } 291 } 292 if (eflag) { 293 name = "maximum blocks per file in a cylinder group"; 294 if (sblock.fs_maxbpg == evalue) 295 warnx("%s remains unchanged as %d", name, evalue); 296 else { 297 warnx("%s changes from %d to %d", 298 name, sblock.fs_maxbpg, evalue); 299 sblock.fs_maxbpg = evalue; 300 } 301 } 302 if (fflag) { 303 name = "average file size"; 304 if (sblock.fs_avgfilesize == fvalue) { 305 warnx("%s remains unchanged as %d", name, fvalue); 306 } 307 else { 308 warnx("%s changes from %d to %d", 309 name, sblock.fs_avgfilesize, fvalue); 310 sblock.fs_avgfilesize = fvalue; 311 } 312 } 313 if (Jflag) { 314 name = "gjournal"; 315 if (strcmp(Jvalue, "enable") == 0) { 316 if (sblock.fs_flags & FS_GJOURNAL) { 317 warnx("%s remains unchanged as enabled", name); 318 } else { 319 sblock.fs_flags |= FS_GJOURNAL; 320 warnx("%s set", name); 321 } 322 } else if (strcmp(Jvalue, "disable") == 0) { 323 if ((~sblock.fs_flags & FS_GJOURNAL) == 324 FS_GJOURNAL) { 325 warnx("%s remains unchanged as disabled", 326 name); 327 } else { 328 sblock.fs_flags &= ~FS_GJOURNAL; 329 warnx("%s cleared", name); 330 } 331 } 332 } 333 if (lflag) { 334 name = "multilabel"; 335 if (strcmp(lvalue, "enable") == 0) { 336 if (sblock.fs_flags & FS_MULTILABEL) { 337 warnx("%s remains unchanged as enabled", name); 338 } else { 339 sblock.fs_flags |= FS_MULTILABEL; 340 warnx("%s set", name); 341 } 342 } else if (strcmp(lvalue, "disable") == 0) { 343 if ((~sblock.fs_flags & FS_MULTILABEL) == 344 FS_MULTILABEL) { 345 warnx("%s remains unchanged as disabled", 346 name); 347 } else { 348 sblock.fs_flags &= ~FS_MULTILABEL; 349 warnx("%s cleared", name); 350 } 351 } 352 } 353 if (mflag) { 354 name = "minimum percentage of free space"; 355 if (sblock.fs_minfree == mvalue) 356 warnx("%s remains unchanged as %d%%", name, mvalue); 357 else { 358 warnx("%s changes from %d%% to %d%%", 359 name, sblock.fs_minfree, mvalue); 360 sblock.fs_minfree = mvalue; 361 if (mvalue >= MINFREE && sblock.fs_optim == FS_OPTSPACE) 362 warnx(OPTWARN, "time", ">=", MINFREE); 363 if (mvalue < MINFREE && sblock.fs_optim == FS_OPTTIME) 364 warnx(OPTWARN, "space", "<", MINFREE); 365 } 366 } 367 if (Nflag) { 368 name = "NFSv4 ACLs"; 369 if (strcmp(Nvalue, "enable") == 0) { 370 if (sblock.fs_flags & FS_NFS4ACLS) { 371 warnx("%s remains unchanged as enabled", name); 372 } else if (sblock.fs_flags & FS_ACLS) { 373 warnx("%s and POSIX.1e ACLs are mutually " 374 "exclusive", name); 375 } else { 376 sblock.fs_flags |= FS_NFS4ACLS; 377 warnx("%s set", name); 378 } 379 } else if (strcmp(Nvalue, "disable") == 0) { 380 if ((~sblock.fs_flags & FS_NFS4ACLS) == 381 FS_NFS4ACLS) { 382 warnx("%s remains unchanged as disabled", 383 name); 384 } else { 385 sblock.fs_flags &= ~FS_NFS4ACLS; 386 warnx("%s cleared", name); 387 } 388 } 389 } 390 if (nflag) { 391 name = "soft updates"; 392 if (strcmp(nvalue, "enable") == 0) { 393 if (sblock.fs_flags & FS_DOSOFTDEP) 394 warnx("%s remains unchanged as enabled", name); 395 else if (sblock.fs_clean == 0) { 396 warnx("%s cannot be enabled until fsck is run", 397 name); 398 } else { 399 sblock.fs_flags |= FS_DOSOFTDEP; 400 warnx("%s set", name); 401 } 402 } else if (strcmp(nvalue, "disable") == 0) { 403 if ((~sblock.fs_flags & FS_DOSOFTDEP) == FS_DOSOFTDEP) 404 warnx("%s remains unchanged as disabled", name); 405 else { 406 sblock.fs_flags &= ~FS_DOSOFTDEP; 407 warnx("%s cleared", name); 408 } 409 } 410 } 411 if (oflag) { 412 name = "optimization preference"; 413 chg[FS_OPTSPACE] = "space"; 414 chg[FS_OPTTIME] = "time"; 415 if (sblock.fs_optim == ovalue) 416 warnx("%s remains unchanged as %s", name, chg[ovalue]); 417 else { 418 warnx("%s changes from %s to %s", 419 name, chg[sblock.fs_optim], chg[ovalue]); 420 sblock.fs_optim = ovalue; 421 if (sblock.fs_minfree >= MINFREE && 422 ovalue == FS_OPTSPACE) 423 warnx(OPTWARN, "time", ">=", MINFREE); 424 if (sblock.fs_minfree < MINFREE && ovalue == FS_OPTTIME) 425 warnx(OPTWARN, "space", "<", MINFREE); 426 } 427 } 428 if (sflag) { 429 name = "expected number of files per directory"; 430 if (sblock.fs_avgfpdir == svalue) { 431 warnx("%s remains unchanged as %d", name, svalue); 432 } 433 else { 434 warnx("%s changes from %d to %d", 435 name, sblock.fs_avgfpdir, svalue); 436 sblock.fs_avgfpdir = svalue; 437 } 438 } 439 440 if (sbwrite(&disk, Aflag) == -1) 441 goto err; 442 ufs_disk_close(&disk); 443 if (active) { 444 bzero(&args, sizeof(args)); 445 if (mount("ufs", on, 446 stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0) 447 err(9, "%s: reload", special); 448 warnx("file system reloaded"); 449 } 450 exit(0); 451 err: 452 if (disk.d_error != NULL) 453 errx(11, "%s: %s", special, disk.d_error); 454 else 455 err(12, "%s", special); 456 } 457 458 void 459 usage(void) 460 { 461 fprintf(stderr, "%s\n%s\n%s\n%s\n", 462 "usage: tunefs [-A] [-a enable | disable] [-e maxbpg] [-f avgfilesize]", 463 " [-J enable | disable ] [-L volname] [-l enable | disable]", 464 " [-m minfree] [-N enable | disable] [-n enable | disable]", 465 " [-o space | time] [-p] [-s avgfpdir] special | filesystem"); 466 exit(2); 467 } 468 469 void 470 printfs(void) 471 { 472 warnx("POSIX.1e ACLs: (-a) %s", 473 (sblock.fs_flags & FS_ACLS)? "enabled" : "disabled"); 474 warnx("NFSv4 ACLs: (-N) %s", 475 (sblock.fs_flags & FS_NFS4ACLS)? "enabled" : "disabled"); 476 warnx("MAC multilabel: (-l) %s", 477 (sblock.fs_flags & FS_MULTILABEL)? "enabled" : "disabled"); 478 warnx("soft updates: (-n) %s", 479 (sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled"); 480 warnx("gjournal: (-J) %s", 481 (sblock.fs_flags & FS_GJOURNAL)? "enabled" : "disabled"); 482 warnx("maximum blocks per file in a cylinder group: (-e) %d", 483 sblock.fs_maxbpg); 484 warnx("average file size: (-f) %d", 485 sblock.fs_avgfilesize); 486 warnx("average number of files in a directory: (-s) %d", 487 sblock.fs_avgfpdir); 488 warnx("minimum percentage of free space: (-m) %d%%", 489 sblock.fs_minfree); 490 warnx("optimization preference: (-o) %s", 491 sblock.fs_optim == FS_OPTSPACE ? "space" : "time"); 492 if (sblock.fs_minfree >= MINFREE && 493 sblock.fs_optim == FS_OPTSPACE) 494 warnx(OPTWARN, "time", ">=", MINFREE); 495 if (sblock.fs_minfree < MINFREE && 496 sblock.fs_optim == FS_OPTTIME) 497 warnx(OPTWARN, "space", "<", MINFREE); 498 warnx("volume label: (-L) %s", 499 sblock.fs_volname); 500 } 501