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. 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 * @(#) Copyright (c) 1983, 1993 The Regents of the University of California. All rights reserved. 30 * @(#)tunefs.c 8.2 (Berkeley) 4/19/94 31 * $FreeBSD: src/sbin/tunefs/tunefs.c,v 1.11.2.5 2001/10/14 21:50:39 iedowse Exp $ 32 * $DragonFly: src/sbin/tunefs/tunefs.c,v 1.7 2006/04/03 01:58:49 dillon Exp $ 33 */ 34 35 /* 36 * tunefs: change layout parameters to an existing file system. 37 */ 38 #include <sys/param.h> 39 #include <sys/mount.h> 40 #include <sys/stat.h> 41 42 #include <vfs/ufs/dinode.h> 43 #include <vfs/ufs/fs.h> 44 #include <vfs/ufs/ufsmount.h> 45 46 #include <err.h> 47 #include <fcntl.h> 48 #include <fstab.h> 49 #include <paths.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.h> 54 55 /* the optimization warning string template */ 56 #define OPTWARN "should optimize for %s with minfree %s %d%%" 57 58 union { 59 struct fs sb; 60 char pad[MAXBSIZE]; 61 } sbun; 62 #define sblock sbun.sb 63 64 int fi; 65 long dev_bsize = 1; 66 67 void bwrite(daddr_t, const char *, int); 68 int bread(daddr_t, char *, int); 69 void getsb(struct fs *, const char *); 70 void putsb(struct fs *, const char *, int); 71 void usage(void); 72 void printfs(void); 73 74 int 75 main(int argc, char **argv) 76 { 77 char *cp, *special; 78 const char *name, *action; 79 struct stat st; 80 int i; 81 int Aflag = 0, active = 0; 82 struct fstab *fs; 83 const char *chg[2]; 84 char device[MAXPATHLEN]; 85 struct ufs_args args; 86 struct statfs stfs; 87 88 argc--, argv++; 89 if (argc < 2) 90 usage(); 91 special = argv[argc - 1]; 92 fs = getfsfile(special); 93 if (fs) { 94 if (statfs(special, &stfs) == 0 && 95 strcmp(special, stfs.f_mntonname) == 0) { 96 active = 1; 97 } 98 special = fs->fs_spec; 99 } 100 again: 101 if (stat(special, &st) < 0) { 102 if (*special != '/') { 103 if (*special == 'r') 104 special++; 105 snprintf(device, sizeof(device), "%s%s", 106 _PATH_DEV, special); 107 special = device; 108 goto again; 109 } 110 err(1, "%s", special); 111 } 112 if (fs == NULL && (st.st_mode & S_IFMT) == S_IFDIR) 113 errx(10, "%s: unknown file system", special); 114 getsb(&sblock, special); 115 for (; argc > 0 && argv[0][0] == '-'; argc--, argv++) { 116 for (cp = &argv[0][1]; *cp; cp++) 117 switch (*cp) { 118 119 case 'A': 120 Aflag++; 121 continue; 122 123 case 'p': 124 printfs(); 125 exit(0); 126 127 case 'a': 128 name = "maximum contiguous block count"; 129 if (argc < 1) 130 errx(10, "-a: missing %s", name); 131 argc--, argv++; 132 i = atoi(*argv); 133 if (i < 1) 134 errx(10, "%s must be >= 1 (was %s)", 135 name, *argv); 136 warnx("%s changes from %d to %d", 137 name, sblock.fs_maxcontig, i); 138 sblock.fs_maxcontig = i; 139 continue; 140 141 case 'd': 142 name = 143 "rotational delay between contiguous blocks"; 144 if (argc < 1) 145 errx(10, "-d: missing %s", name); 146 argc--, argv++; 147 i = atoi(*argv); 148 warnx("%s changes from %dms to %dms", 149 name, sblock.fs_rotdelay, i); 150 sblock.fs_rotdelay = i; 151 continue; 152 153 case 'e': 154 name = 155 "maximum blocks per file in a cylinder group"; 156 if (argc < 1) 157 errx(10, "-e: missing %s", name); 158 argc--, argv++; 159 i = atoi(*argv); 160 if (i < 1) 161 errx(10, "%s must be >= 1 (was %s)", 162 name, *argv); 163 warnx("%s changes from %d to %d", 164 name, sblock.fs_maxbpg, i); 165 sblock.fs_maxbpg = i; 166 continue; 167 168 case 'f': 169 name = "average file size"; 170 if (argc < 1) 171 errx(10, "-a: missing %s", name); 172 argc--, argv++; 173 i = atoi(*argv); 174 if (i < 1) 175 errx(10, "%s must be >= 1 (was %s)", name, *argv); 176 if (sblock.fs_avgfilesize == i) { 177 warnx("%s remains unchanged as %d", 178 name, i); 179 } else { 180 warnx("%s changes from %d to %d", 181 name, sblock.fs_avgfilesize, i); 182 sblock.fs_avgfilesize = i; 183 } 184 break; 185 186 case 'm': 187 name = "minimum percentage of free space"; 188 if (argc < 1) 189 errx(10, "-m: missing %s", name); 190 argc--, argv++; 191 i = atoi(*argv); 192 if (i < 0 || i > 99) 193 errx(10, "bad %s (%s)", name, *argv); 194 warnx("%s changes from %d%% to %d%%", 195 name, sblock.fs_minfree, i); 196 sblock.fs_minfree = i; 197 if (i >= MINFREE && 198 sblock.fs_optim == FS_OPTSPACE) 199 warnx(OPTWARN, "time", ">=", MINFREE); 200 if (i < MINFREE && 201 sblock.fs_optim == FS_OPTTIME) 202 warnx(OPTWARN, "space", "<", MINFREE); 203 continue; 204 205 case 'n': 206 name = "soft updates"; 207 if (argc < 1) 208 errx(10, "-n: missing %s", name); 209 argc--, argv++; 210 if (strcmp(*argv, "enable") == 0) { 211 sblock.fs_flags |= FS_DOSOFTDEP; 212 action = "set"; 213 } else if (strcmp(*argv, "disable") == 0) { 214 sblock.fs_flags &= ~FS_DOSOFTDEP; 215 action = "cleared"; 216 } else { 217 errx(10, "bad %s (options are %s)", 218 name, "`enable' or `disable'"); 219 } 220 warnx("%s %s", name, action); 221 continue; 222 223 case 'o': 224 name = "optimization preference"; 225 if (argc < 1) 226 errx(10, "-o: missing %s", name); 227 argc--, argv++; 228 chg[FS_OPTSPACE] = "space"; 229 chg[FS_OPTTIME] = "time"; 230 if (strcmp(*argv, chg[FS_OPTSPACE]) == 0) 231 i = FS_OPTSPACE; 232 else if (strcmp(*argv, chg[FS_OPTTIME]) == 0) 233 i = FS_OPTTIME; 234 else 235 errx(10, "bad %s (options are `space' or `time')", 236 name); 237 if (sblock.fs_optim == i) { 238 warnx("%s remains unchanged as %s", 239 name, chg[i]); 240 continue; 241 } 242 warnx("%s changes from %s to %s", 243 name, chg[sblock.fs_optim], chg[i]); 244 sblock.fs_optim = i; 245 if (sblock.fs_minfree >= MINFREE && 246 i == FS_OPTSPACE) 247 warnx(OPTWARN, "time", ">=", MINFREE); 248 if (sblock.fs_minfree < MINFREE && 249 i == FS_OPTTIME) 250 warnx(OPTWARN, "space", "<", MINFREE); 251 continue; 252 253 case 's': 254 name = "expected number of files per directory"; 255 if (argc < 1) 256 errx(10, "-a: missing %s", name); 257 argc--, argv++; 258 i = atoi(*argv); 259 if (i < 1) 260 errx(10, "%s must be >= 1 (was %s)", name, *argv); 261 if (sblock.fs_avgfpdir == i) { 262 warnx("%s remains unchanged as %d", 263 name, i); 264 } else { 265 warnx("%s changes from %d to %d", 266 name, sblock.fs_avgfpdir, i); 267 sblock.fs_avgfpdir = i; 268 } 269 break; 270 271 default: 272 usage(); 273 } 274 } 275 if (argc != 1) 276 usage(); 277 putsb(&sblock, special, Aflag); 278 if (active) { 279 bzero(&args, sizeof(args)); 280 if (mount("ufs", fs->fs_file, 281 stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0) 282 err(9, "%s: reload", special); 283 warnx("file system reloaded"); 284 } 285 exit(0); 286 } 287 288 void 289 usage(void) 290 { 291 fprintf(stderr, "%s\n%s\n%s\n", 292 "usage: tunefs [-Ap] [-a maxcontig] [-d rotdelay] [-e maxbpg] [-f avgfilesize]", 293 " [-m minfree] [-n enable | disable] [-o space | time]", 294 " [-s filesperdir] {special | filesystem}"); 295 exit(2); 296 } 297 298 void 299 getsb(struct fs *fs, const char *file) 300 { 301 302 fi = open(file, O_RDONLY); 303 if (fi < 0) 304 err(3, "cannot open %s", file); 305 if (bread((daddr_t)SBOFF, (char *)fs, SBSIZE)) 306 err(4, "%s: bad super block", file); 307 if (fs->fs_magic != FS_MAGIC) 308 errx(5, "%s: bad magic number", file); 309 dev_bsize = fs->fs_fsize / fsbtodb(fs, 1); 310 } 311 312 void 313 putsb(struct fs *fs, const char *file, int all) 314 { 315 int i; 316 317 /* 318 * Re-open the device read-write. Use the read-only file 319 * descriptor as an interlock to prevent the device from 320 * being mounted while we are switching mode. 321 */ 322 i = fi; 323 fi = open(file, O_RDWR); 324 close(i); 325 if (fi < 0) 326 err(3, "cannot open %s", file); 327 bwrite((daddr_t)SBOFF / dev_bsize, (const char *)fs, SBSIZE); 328 if (all) 329 for (i = 0; i < fs->fs_ncg; i++) 330 bwrite(fsbtodb(fs, cgsblock(fs, i)), 331 (const char *)fs, SBSIZE); 332 close(fi); 333 } 334 335 void 336 printfs(void) 337 { 338 warnx("soft updates: (-n) %s", 339 (sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled"); 340 warnx("maximum contiguous block count: (-a) %d", 341 sblock.fs_maxcontig); 342 warnx("rotational delay between contiguous blocks: (-d) %d ms", 343 sblock.fs_rotdelay); 344 warnx("maximum blocks per file in a cylinder group: (-e) %d", 345 sblock.fs_maxbpg); 346 warnx("average file size: (-f) %d", 347 sblock.fs_avgfilesize); 348 warnx("average number of files in a directory: (-s) %d", 349 sblock.fs_avgfpdir); 350 warnx("minimum percentage of free space: (-m) %d%%", 351 sblock.fs_minfree); 352 warnx("optimization preference: (-o) %s", 353 sblock.fs_optim == FS_OPTSPACE ? "space" : "time"); 354 if (sblock.fs_minfree >= MINFREE && 355 sblock.fs_optim == FS_OPTSPACE) 356 warnx(OPTWARN, "time", ">=", MINFREE); 357 if (sblock.fs_minfree < MINFREE && 358 sblock.fs_optim == FS_OPTTIME) 359 warnx(OPTWARN, "space", "<", MINFREE); 360 } 361 362 void 363 bwrite(daddr_t blk, const char *buf, int size) 364 { 365 366 if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0) 367 err(6, "FS SEEK"); 368 if (write(fi, buf, size) != size) 369 err(7, "FS WRITE"); 370 } 371 372 int 373 bread(daddr_t bno, char *buf, int cnt) 374 { 375 int i; 376 377 if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0) 378 return(1); 379 if ((i = read(fi, buf, cnt)) != cnt) { 380 for(i=0; i<sblock.fs_bsize; i++) 381 buf[i] = 0; 382 return (1); 383 } 384 return (0); 385 } 386