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