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, *Lvalue, *lvalue, *nvalue; 80 const char *special, *on; 81 const char *name; 82 int active; 83 int Aflag, aflag, eflag, evalue, fflag, fvalue, 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 = Lflag = lflag = mflag = 0; 93 nflag = oflag = pflag = sflag = 0; 94 avalue = 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: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 'L': 139 found_arg = 1; 140 name = "volume label"; 141 Lvalue = optarg; 142 i = -1; 143 while (isalnum(Lvalue[++i])); 144 if (Lvalue[i] != '\0') { 145 errx(10, 146 "bad %s. Valid characters are alphanumerics.", 147 name); 148 } 149 if (strlen(Lvalue) >= MAXVOLLEN) { 150 errx(10, "bad %s. Length is longer than %d.", 151 name, MAXVOLLEN - 1); 152 } 153 Lflag = 1; 154 break; 155 156 case 'l': 157 found_arg = 1; 158 name = "multilabel MAC file system"; 159 lvalue = optarg; 160 if (strcmp(lvalue, "enable") && 161 strcmp(lvalue, "disable")) { 162 errx(10, "bad %s (options are %s)", 163 name, "`enable' or `disable'"); 164 } 165 lflag = 1; 166 break; 167 168 case 'm': 169 found_arg = 1; 170 name = "minimum percentage of free space"; 171 mvalue = atoi(optarg); 172 if (mvalue < 0 || mvalue > 99) 173 errx(10, "bad %s (%s)", name, optarg); 174 mflag = 1; 175 break; 176 177 case 'n': 178 found_arg = 1; 179 name = "soft updates"; 180 nvalue = optarg; 181 if (strcmp(nvalue, "enable") != 0 && 182 strcmp(nvalue, "disable") != 0) { 183 errx(10, "bad %s (options are %s)", 184 name, "`enable' or `disable'"); 185 } 186 nflag = 1; 187 break; 188 189 case 'o': 190 found_arg = 1; 191 name = "optimization preference"; 192 if (strcmp(optarg, "space") == 0) 193 ovalue = FS_OPTSPACE; 194 else if (strcmp(optarg, "time") == 0) 195 ovalue = FS_OPTTIME; 196 else 197 errx(10, 198 "bad %s (options are `space' or `time')", 199 name); 200 oflag = 1; 201 break; 202 203 case 'p': 204 found_arg = 1; 205 pflag = 1; 206 break; 207 208 case 's': 209 found_arg = 1; 210 name = "expected number of files per directory"; 211 svalue = atoi(optarg); 212 if (svalue < 1) 213 errx(10, "%s must be >= 1 (was %s)", 214 name, optarg); 215 sflag = 1; 216 break; 217 218 default: 219 usage(); 220 } 221 argc -= optind; 222 argv += optind; 223 if (found_arg == 0 || argc != 1) 224 usage(); 225 226 on = special = argv[0]; 227 if (ufs_disk_fillout(&disk, special) == -1) 228 goto err; 229 if (disk.d_name != special) { 230 special = disk.d_name; 231 if (statfs(special, &stfs) == 0 && 232 strcmp(special, stfs.f_mntonname) == 0) 233 active = 1; 234 } 235 236 if (pflag) { 237 printfs(); 238 exit(0); 239 } 240 if (Lflag) { 241 name = "volume label"; 242 strlcpy(sblock.fs_volname, Lvalue, MAXVOLLEN); 243 } 244 if (aflag) { 245 name = "ACLs"; 246 if (strcmp(avalue, "enable") == 0) { 247 if (sblock.fs_flags & FS_ACLS) { 248 warnx("%s remains unchanged as enabled", name); 249 } else { 250 sblock.fs_flags |= FS_ACLS; 251 warnx("%s set", name); 252 } 253 } else if (strcmp(avalue, "disable") == 0) { 254 if ((~sblock.fs_flags & FS_ACLS) == 255 FS_ACLS) { 256 warnx("%s remains unchanged as disabled", 257 name); 258 } else { 259 sblock.fs_flags &= ~FS_ACLS; 260 warnx("%s cleared", name); 261 } 262 } 263 } 264 if (eflag) { 265 name = "maximum blocks per file in a cylinder group"; 266 if (sblock.fs_maxbpg == evalue) 267 warnx("%s remains unchanged as %d", name, evalue); 268 else { 269 warnx("%s changes from %d to %d", 270 name, sblock.fs_maxbpg, evalue); 271 sblock.fs_maxbpg = evalue; 272 } 273 } 274 if (fflag) { 275 name = "average file size"; 276 if (sblock.fs_avgfilesize == fvalue) { 277 warnx("%s remains unchanged as %d", name, fvalue); 278 } 279 else { 280 warnx("%s changes from %d to %d", 281 name, sblock.fs_avgfilesize, fvalue); 282 sblock.fs_avgfilesize = fvalue; 283 } 284 } 285 if (lflag) { 286 name = "multilabel"; 287 if (strcmp(lvalue, "enable") == 0) { 288 if (sblock.fs_flags & FS_MULTILABEL) { 289 warnx("%s remains unchanged as enabled", name); 290 } else { 291 sblock.fs_flags |= FS_MULTILABEL; 292 warnx("%s set", name); 293 } 294 } else if (strcmp(lvalue, "disable") == 0) { 295 if ((~sblock.fs_flags & FS_MULTILABEL) == 296 FS_MULTILABEL) { 297 warnx("%s remains unchanged as disabled", 298 name); 299 } else { 300 sblock.fs_flags &= ~FS_MULTILABEL; 301 warnx("%s cleared", name); 302 } 303 } 304 } 305 if (mflag) { 306 name = "minimum percentage of free space"; 307 if (sblock.fs_minfree == mvalue) 308 warnx("%s remains unchanged as %d%%", name, mvalue); 309 else { 310 warnx("%s changes from %d%% to %d%%", 311 name, sblock.fs_minfree, mvalue); 312 sblock.fs_minfree = mvalue; 313 if (mvalue >= MINFREE && sblock.fs_optim == FS_OPTSPACE) 314 warnx(OPTWARN, "time", ">=", MINFREE); 315 if (mvalue < MINFREE && sblock.fs_optim == FS_OPTTIME) 316 warnx(OPTWARN, "space", "<", MINFREE); 317 } 318 } 319 if (nflag) { 320 name = "soft updates"; 321 if (strcmp(nvalue, "enable") == 0) { 322 if (sblock.fs_flags & FS_DOSOFTDEP) 323 warnx("%s remains unchanged as enabled", name); 324 else if (sblock.fs_clean == 0) { 325 warnx("%s cannot be enabled until fsck is run", 326 name); 327 } else { 328 sblock.fs_flags |= FS_DOSOFTDEP; 329 warnx("%s set", name); 330 } 331 } else if (strcmp(nvalue, "disable") == 0) { 332 if ((~sblock.fs_flags & FS_DOSOFTDEP) == FS_DOSOFTDEP) 333 warnx("%s remains unchanged as disabled", name); 334 else { 335 sblock.fs_flags &= ~FS_DOSOFTDEP; 336 warnx("%s cleared", name); 337 } 338 } 339 } 340 if (oflag) { 341 name = "optimization preference"; 342 chg[FS_OPTSPACE] = "space"; 343 chg[FS_OPTTIME] = "time"; 344 if (sblock.fs_optim == ovalue) 345 warnx("%s remains unchanged as %s", name, chg[ovalue]); 346 else { 347 warnx("%s changes from %s to %s", 348 name, chg[sblock.fs_optim], chg[ovalue]); 349 sblock.fs_optim = ovalue; 350 if (sblock.fs_minfree >= MINFREE && 351 ovalue == FS_OPTSPACE) 352 warnx(OPTWARN, "time", ">=", MINFREE); 353 if (sblock.fs_minfree < MINFREE && ovalue == FS_OPTTIME) 354 warnx(OPTWARN, "space", "<", MINFREE); 355 } 356 } 357 if (sflag) { 358 name = "expected number of files per directory"; 359 if (sblock.fs_avgfpdir == svalue) { 360 warnx("%s remains unchanged as %d", name, svalue); 361 } 362 else { 363 warnx("%s changes from %d to %d", 364 name, sblock.fs_avgfpdir, svalue); 365 sblock.fs_avgfpdir = svalue; 366 } 367 } 368 369 if (sbwrite(&disk, Aflag) == -1) 370 goto err; 371 ufs_disk_close(&disk); 372 if (active) { 373 bzero(&args, sizeof(args)); 374 if (mount("ufs", on, 375 stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0) 376 err(9, "%s: reload", special); 377 warnx("file system reloaded"); 378 } 379 exit(0); 380 err: 381 if (disk.d_error != NULL) 382 errx(11, "%s: %s", special, disk.d_error); 383 else 384 err(12, "%s", special); 385 } 386 387 void 388 usage(void) 389 { 390 fprintf(stderr, "%s\n%s\n%s\n%s\n", 391 "usage: tunefs [-A] [-a enable | disable] [-e maxbpg] [-f avgfilesize]", 392 " [-L volname] [-l enable | disable] [-m minfree]", 393 " [-n enable | disable] [-o space | time] [-p]", 394 " [-s avgfpdir] special | filesystem"); 395 exit(2); 396 } 397 398 void 399 printfs(void) 400 { 401 warnx("ACLs: (-a) %s", 402 (sblock.fs_flags & FS_ACLS)? "enabled" : "disabled"); 403 warnx("MAC multilabel: (-l) %s", 404 (sblock.fs_flags & FS_MULTILABEL)? "enabled" : "disabled"); 405 warnx("soft updates: (-n) %s", 406 (sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled"); 407 warnx("maximum blocks per file in a cylinder group: (-e) %d", 408 sblock.fs_maxbpg); 409 warnx("average file size: (-f) %d", 410 sblock.fs_avgfilesize); 411 warnx("average number of files in a directory: (-s) %d", 412 sblock.fs_avgfpdir); 413 warnx("minimum percentage of free space: (-m) %d%%", 414 sblock.fs_minfree); 415 warnx("optimization preference: (-o) %s", 416 sblock.fs_optim == FS_OPTSPACE ? "space" : "time"); 417 if (sblock.fs_minfree >= MINFREE && 418 sblock.fs_optim == FS_OPTSPACE) 419 warnx(OPTWARN, "time", ">=", MINFREE); 420 if (sblock.fs_minfree < MINFREE && 421 sblock.fs_optim == FS_OPTTIME) 422 warnx(OPTWARN, "space", "<", MINFREE); 423 warnx("volume label: (-L) %s", 424 sblock.fs_volname); 425 } 426