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, char *, int)); 80 int bread __P((daddr_t, char *, int)); 81 void getsb __P((struct fs *, char *)); 82 void putsb __P((struct fs *, 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 *cp, *special, *name, *action; 92 struct stat st; 93 int i; 94 int Aflag = 0, active = 0; 95 struct fstab *fs; 96 char *chg[2], device[MAXPATHLEN]; 97 struct ufs_args args; 98 struct statfs stfs; 99 100 argc--, argv++; 101 if (argc < 2) 102 usage(); 103 special = argv[argc - 1]; 104 fs = getfsfile(special); 105 if (fs) { 106 if (statfs(special, &stfs) == 0 && 107 strcmp(special, stfs.f_mntonname) == 0) { 108 active = 1; 109 } 110 special = fs->fs_spec; 111 } 112 again: 113 if (stat(special, &st) < 0) { 114 if (*special != '/') { 115 if (*special == 'r') 116 special++; 117 (void)sprintf(device, "%s/%s", _PATH_DEV, special); 118 special = device; 119 goto again; 120 } 121 err(1, "%s", special); 122 } 123 if ((st.st_mode & S_IFMT) != S_IFBLK && 124 (st.st_mode & S_IFMT) != S_IFCHR) 125 errx(10, "%s: not a block or character device", special); 126 getsb(&sblock, special); 127 for (; argc > 0 && argv[0][0] == '-'; argc--, argv++) { 128 for (cp = &argv[0][1]; *cp; cp++) 129 switch (*cp) { 130 131 case 'A': 132 Aflag++; 133 continue; 134 135 case 'p': 136 printfs(); 137 exit(0); 138 139 case 'a': 140 name = "maximum contiguous block count"; 141 if (argc < 1) 142 errx(10, "-a: missing %s", name); 143 argc--, argv++; 144 i = atoi(*argv); 145 if (i < 1) 146 errx(10, "%s must be >= 1 (was %s)", 147 name, *argv); 148 warnx("%s changes from %d to %d", 149 name, sblock.fs_maxcontig, i); 150 sblock.fs_maxcontig = i; 151 continue; 152 153 case 'd': 154 name = 155 "rotational delay between contiguous blocks"; 156 if (argc < 1) 157 errx(10, "-d: missing %s", name); 158 argc--, argv++; 159 i = atoi(*argv); 160 warnx("%s changes from %dms to %dms", 161 name, sblock.fs_rotdelay, i); 162 sblock.fs_rotdelay = i; 163 continue; 164 165 case 'e': 166 name = 167 "maximum blocks per file in a cylinder group"; 168 if (argc < 1) 169 errx(10, "-e: missing %s", name); 170 argc--, argv++; 171 i = atoi(*argv); 172 if (i < 1) 173 errx(10, "%s must be >= 1 (was %s)", 174 name, *argv); 175 warnx("%s changes from %d to %d", 176 name, sblock.fs_maxbpg, i); 177 sblock.fs_maxbpg = i; 178 continue; 179 180 case 'm': 181 name = "minimum percentage of free space"; 182 if (argc < 1) 183 errx(10, "-m: missing %s", name); 184 argc--, argv++; 185 i = atoi(*argv); 186 if (i < 0 || i > 99) 187 errx(10, "bad %s (%s)", name, *argv); 188 warnx("%s changes from %d%% to %d%%", 189 name, sblock.fs_minfree, i); 190 sblock.fs_minfree = i; 191 if (i >= MINFREE && 192 sblock.fs_optim == FS_OPTSPACE) 193 warnx(OPTWARN, "time", ">=", MINFREE); 194 if (i < MINFREE && 195 sblock.fs_optim == FS_OPTTIME) 196 warnx(OPTWARN, "space", "<", MINFREE); 197 continue; 198 199 case 'n': 200 name = "soft updates"; 201 if (argc < 1) 202 errx(10, "-n: missing %s", name); 203 argc--, argv++; 204 if (strcmp(*argv, "enable") == 0) { 205 sblock.fs_flags |= FS_DOSOFTDEP; 206 action = "set"; 207 } else if (strcmp(*argv, "disable") == 0) { 208 sblock.fs_flags &= ~FS_DOSOFTDEP; 209 action = "cleared"; 210 } else { 211 errx(10, "bad %s (options are %s)", 212 name, "`enable' or `disable'"); 213 } 214 warnx("%s %s", name, action); 215 continue; 216 217 case 'o': 218 name = "optimization preference"; 219 if (argc < 1) 220 errx(10, "-o: missing %s", name); 221 argc--, argv++; 222 chg[FS_OPTSPACE] = "space"; 223 chg[FS_OPTTIME] = "time"; 224 if (strcmp(*argv, chg[FS_OPTSPACE]) == 0) 225 i = FS_OPTSPACE; 226 else if (strcmp(*argv, chg[FS_OPTTIME]) == 0) 227 i = FS_OPTTIME; 228 else 229 errx(10, "bad %s (options are `space' or `time')", 230 name); 231 if (sblock.fs_optim == i) { 232 warnx("%s remains unchanged as %s", 233 name, chg[i]); 234 continue; 235 } 236 warnx("%s changes from %s to %s", 237 name, chg[sblock.fs_optim], chg[i]); 238 sblock.fs_optim = i; 239 if (sblock.fs_minfree >= MINFREE && 240 i == FS_OPTSPACE) 241 warnx(OPTWARN, "time", ">=", MINFREE); 242 if (sblock.fs_minfree < MINFREE && 243 i == FS_OPTTIME) 244 warnx(OPTWARN, "space", "<", MINFREE); 245 continue; 246 247 default: 248 usage(); 249 } 250 } 251 if (argc != 1) 252 usage(); 253 putsb(&sblock, special, Aflag); 254 if (active) { 255 bzero(&args, sizeof(args)); 256 if (mount("ufs", fs->fs_file, 257 stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0) 258 err(9, "%s: reload", special); 259 warnx("file system reloaded"); 260 } 261 exit(0); 262 } 263 264 void 265 usage() 266 { 267 fprintf(stderr, "%s\n%s\n%s\n", 268 "usage: tunefs [-A] [-a maxcontig] [-d rotdelay] [-e maxbpg] [-m minfree]", 269 " [-p] [-n enable | disable] [-o optimize_preference]", 270 " [special | filesystem]"); 271 exit(2); 272 } 273 274 void 275 getsb(fs, file) 276 register struct fs *fs; 277 char *file; 278 { 279 280 fi = open(file, O_RDONLY); 281 if (fi < 0) 282 err(3, "cannot open %s", file); 283 if (bread((daddr_t)SBOFF, (char *)fs, SBSIZE)) 284 err(4, "%s: bad super block", file); 285 if (fs->fs_magic != FS_MAGIC) 286 err(5, "%s: bad magic number", file); 287 dev_bsize = fs->fs_fsize / fsbtodb(fs, 1); 288 } 289 290 void 291 putsb(fs, file, all) 292 register struct fs *fs; 293 char *file; 294 int all; 295 { 296 int i; 297 298 /* 299 * Re-open the device read-write. Use the read-only file 300 * descriptor as an interlock to prevent the device from 301 * being mounted while we are switching mode. 302 */ 303 i = fi; 304 fi = open(file, O_RDWR); 305 close(i); 306 if (fi < 0) 307 err(3, "cannot open %s", file); 308 bwrite((daddr_t)SBOFF / dev_bsize, (char *)fs, SBSIZE); 309 if (all) 310 for (i = 0; i < fs->fs_ncg; i++) 311 bwrite(fsbtodb(fs, cgsblock(fs, i)), 312 (char *)fs, SBSIZE); 313 close(fi); 314 } 315 316 void 317 printfs() 318 { 319 warnx("soft updates: (-n) %s", 320 (sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled"); 321 warnx("maximum contiguous block count: (-a) %d", 322 sblock.fs_maxcontig); 323 warnx("rotational delay between contiguous blocks: (-d) %d ms", 324 sblock.fs_rotdelay); 325 warnx("maximum blocks per file in a cylinder group: (-e) %d", 326 sblock.fs_maxbpg); 327 warnx("minimum percentage of free space: (-m) %d%%", 328 sblock.fs_minfree); 329 warnx("optimization preference: (-o) %s", 330 sblock.fs_optim == FS_OPTSPACE ? "space" : "time"); 331 if (sblock.fs_minfree >= MINFREE && 332 sblock.fs_optim == FS_OPTSPACE) 333 warnx(OPTWARN, "time", ">=", MINFREE); 334 if (sblock.fs_minfree < MINFREE && 335 sblock.fs_optim == FS_OPTTIME) 336 warnx(OPTWARN, "space", "<", MINFREE); 337 } 338 339 void 340 bwrite(blk, buf, size) 341 daddr_t blk; 342 char *buf; 343 int size; 344 { 345 346 if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0) 347 err(6, "FS SEEK"); 348 if (write(fi, buf, size) != size) 349 err(7, "FS WRITE"); 350 } 351 352 int 353 bread(bno, buf, cnt) 354 daddr_t bno; 355 char *buf; 356 int cnt; 357 { 358 int i; 359 360 if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0) 361 return(1); 362 if ((i = read(fi, buf, cnt)) != cnt) { 363 for(i=0; i<sblock.fs_bsize; i++) 364 buf[i] = 0; 365 return (1); 366 } 367 return (0); 368 } 369