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; 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, 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 = oflag = pflag = sflag = 0; 94 avalue = Jvalue = Lvalue = lvalue = 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: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 = "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 = "soft updates"; 193 nvalue = optarg; 194 if (strcmp(nvalue, "enable") != 0 && 195 strcmp(nvalue, "disable") != 0) { 196 errx(10, "bad %s (options are %s)", 197 name, "`enable' or `disable'"); 198 } 199 nflag = 1; 200 break; 201 202 case 'o': 203 found_arg = 1; 204 name = "optimization preference"; 205 if (strcmp(optarg, "space") == 0) 206 ovalue = FS_OPTSPACE; 207 else if (strcmp(optarg, "time") == 0) 208 ovalue = FS_OPTTIME; 209 else 210 errx(10, 211 "bad %s (options are `space' or `time')", 212 name); 213 oflag = 1; 214 break; 215 216 case 'p': 217 found_arg = 1; 218 pflag = 1; 219 break; 220 221 case 's': 222 found_arg = 1; 223 name = "expected number of files per directory"; 224 svalue = atoi(optarg); 225 if (svalue < 1) 226 errx(10, "%s must be >= 1 (was %s)", 227 name, optarg); 228 sflag = 1; 229 break; 230 231 default: 232 usage(); 233 } 234 argc -= optind; 235 argv += optind; 236 if (found_arg == 0 || argc != 1) 237 usage(); 238 239 on = special = argv[0]; 240 if (ufs_disk_fillout(&disk, special) == -1) 241 goto err; 242 if (disk.d_name != special) { 243 special = disk.d_name; 244 if (statfs(special, &stfs) == 0 && 245 strcmp(special, stfs.f_mntonname) == 0) 246 active = 1; 247 } 248 249 if (pflag) { 250 printfs(); 251 exit(0); 252 } 253 if (Lflag) { 254 name = "volume label"; 255 strlcpy(sblock.fs_volname, Lvalue, MAXVOLLEN); 256 } 257 if (aflag) { 258 name = "ACLs"; 259 if (strcmp(avalue, "enable") == 0) { 260 if (sblock.fs_flags & FS_ACLS) { 261 warnx("%s remains unchanged as enabled", name); 262 } else { 263 sblock.fs_flags |= FS_ACLS; 264 warnx("%s set", name); 265 } 266 } else if (strcmp(avalue, "disable") == 0) { 267 if ((~sblock.fs_flags & FS_ACLS) == 268 FS_ACLS) { 269 warnx("%s remains unchanged as disabled", 270 name); 271 } else { 272 sblock.fs_flags &= ~FS_ACLS; 273 warnx("%s cleared", name); 274 } 275 } 276 } 277 if (eflag) { 278 name = "maximum blocks per file in a cylinder group"; 279 if (sblock.fs_maxbpg == evalue) 280 warnx("%s remains unchanged as %d", name, evalue); 281 else { 282 warnx("%s changes from %d to %d", 283 name, sblock.fs_maxbpg, evalue); 284 sblock.fs_maxbpg = evalue; 285 } 286 } 287 if (fflag) { 288 name = "average file size"; 289 if (sblock.fs_avgfilesize == fvalue) { 290 warnx("%s remains unchanged as %d", name, fvalue); 291 } 292 else { 293 warnx("%s changes from %d to %d", 294 name, sblock.fs_avgfilesize, fvalue); 295 sblock.fs_avgfilesize = fvalue; 296 } 297 } 298 if (Jflag) { 299 name = "gjournal"; 300 if (strcmp(Jvalue, "enable") == 0) { 301 if (sblock.fs_flags & FS_GJOURNAL) { 302 warnx("%s remains unchanged as enabled", name); 303 } else { 304 sblock.fs_flags |= FS_GJOURNAL; 305 warnx("%s set", name); 306 } 307 } else if (strcmp(Jvalue, "disable") == 0) { 308 if ((~sblock.fs_flags & FS_GJOURNAL) == 309 FS_GJOURNAL) { 310 warnx("%s remains unchanged as disabled", 311 name); 312 } else { 313 sblock.fs_flags &= ~FS_GJOURNAL; 314 warnx("%s cleared", name); 315 } 316 } 317 } 318 if (lflag) { 319 name = "multilabel"; 320 if (strcmp(lvalue, "enable") == 0) { 321 if (sblock.fs_flags & FS_MULTILABEL) { 322 warnx("%s remains unchanged as enabled", name); 323 } else { 324 sblock.fs_flags |= FS_MULTILABEL; 325 warnx("%s set", name); 326 } 327 } else if (strcmp(lvalue, "disable") == 0) { 328 if ((~sblock.fs_flags & FS_MULTILABEL) == 329 FS_MULTILABEL) { 330 warnx("%s remains unchanged as disabled", 331 name); 332 } else { 333 sblock.fs_flags &= ~FS_MULTILABEL; 334 warnx("%s cleared", name); 335 } 336 } 337 } 338 if (mflag) { 339 name = "minimum percentage of free space"; 340 if (sblock.fs_minfree == mvalue) 341 warnx("%s remains unchanged as %d%%", name, mvalue); 342 else { 343 warnx("%s changes from %d%% to %d%%", 344 name, sblock.fs_minfree, mvalue); 345 sblock.fs_minfree = mvalue; 346 if (mvalue >= MINFREE && sblock.fs_optim == FS_OPTSPACE) 347 warnx(OPTWARN, "time", ">=", MINFREE); 348 if (mvalue < MINFREE && sblock.fs_optim == FS_OPTTIME) 349 warnx(OPTWARN, "space", "<", MINFREE); 350 } 351 } 352 if (nflag) { 353 name = "soft updates"; 354 if (strcmp(nvalue, "enable") == 0) { 355 if (sblock.fs_flags & FS_DOSOFTDEP) 356 warnx("%s remains unchanged as enabled", name); 357 else if (sblock.fs_clean == 0) { 358 warnx("%s cannot be enabled until fsck is run", 359 name); 360 } else { 361 sblock.fs_flags |= FS_DOSOFTDEP; 362 warnx("%s set", name); 363 } 364 } else if (strcmp(nvalue, "disable") == 0) { 365 if ((~sblock.fs_flags & FS_DOSOFTDEP) == FS_DOSOFTDEP) 366 warnx("%s remains unchanged as disabled", name); 367 else { 368 sblock.fs_flags &= ~FS_DOSOFTDEP; 369 warnx("%s cleared", name); 370 } 371 } 372 } 373 if (oflag) { 374 name = "optimization preference"; 375 chg[FS_OPTSPACE] = "space"; 376 chg[FS_OPTTIME] = "time"; 377 if (sblock.fs_optim == ovalue) 378 warnx("%s remains unchanged as %s", name, chg[ovalue]); 379 else { 380 warnx("%s changes from %s to %s", 381 name, chg[sblock.fs_optim], chg[ovalue]); 382 sblock.fs_optim = ovalue; 383 if (sblock.fs_minfree >= MINFREE && 384 ovalue == FS_OPTSPACE) 385 warnx(OPTWARN, "time", ">=", MINFREE); 386 if (sblock.fs_minfree < MINFREE && ovalue == FS_OPTTIME) 387 warnx(OPTWARN, "space", "<", MINFREE); 388 } 389 } 390 if (sflag) { 391 name = "expected number of files per directory"; 392 if (sblock.fs_avgfpdir == svalue) { 393 warnx("%s remains unchanged as %d", name, svalue); 394 } 395 else { 396 warnx("%s changes from %d to %d", 397 name, sblock.fs_avgfpdir, svalue); 398 sblock.fs_avgfpdir = svalue; 399 } 400 } 401 402 if (sbwrite(&disk, Aflag) == -1) 403 goto err; 404 ufs_disk_close(&disk); 405 if (active) { 406 bzero(&args, sizeof(args)); 407 if (mount("ufs", on, 408 stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0) 409 err(9, "%s: reload", special); 410 warnx("file system reloaded"); 411 } 412 exit(0); 413 err: 414 if (disk.d_error != NULL) 415 errx(11, "%s: %s", special, disk.d_error); 416 else 417 err(12, "%s", special); 418 } 419 420 void 421 usage(void) 422 { 423 fprintf(stderr, "%s\n%s\n%s\n%s\n", 424 "usage: tunefs [-A] [-a enable | disable] [-e maxbpg] [-f avgfilesize]", 425 " [-J enable | disable ] [-L volname] [-l enable | disable]", 426 " [-m minfree] [-n enable | disable] [-o space | time] [-p]", 427 " [-s avgfpdir] special | filesystem"); 428 exit(2); 429 } 430 431 void 432 printfs(void) 433 { 434 warnx("ACLs: (-a) %s", 435 (sblock.fs_flags & FS_ACLS)? "enabled" : "disabled"); 436 warnx("MAC multilabel: (-l) %s", 437 (sblock.fs_flags & FS_MULTILABEL)? "enabled" : "disabled"); 438 warnx("soft updates: (-n) %s", 439 (sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled"); 440 warnx("gjournal: (-J) %s", 441 (sblock.fs_flags & FS_GJOURNAL)? "enabled" : "disabled"); 442 warnx("maximum blocks per file in a cylinder group: (-e) %d", 443 sblock.fs_maxbpg); 444 warnx("average file size: (-f) %d", 445 sblock.fs_avgfilesize); 446 warnx("average number of files in a directory: (-s) %d", 447 sblock.fs_avgfpdir); 448 warnx("minimum percentage of free space: (-m) %d%%", 449 sblock.fs_minfree); 450 warnx("optimization preference: (-o) %s", 451 sblock.fs_optim == FS_OPTSPACE ? "space" : "time"); 452 if (sblock.fs_minfree >= MINFREE && 453 sblock.fs_optim == FS_OPTSPACE) 454 warnx(OPTWARN, "time", ">=", MINFREE); 455 if (sblock.fs_minfree < MINFREE && 456 sblock.fs_optim == FS_OPTTIME) 457 warnx(OPTWARN, "space", "<", MINFREE); 458 warnx("volume label: (-L) %s", 459 sblock.fs_volname); 460 } 461