1 1.58 chs /* $NetBSD: tunefs.c,v 1.58 2023/01/07 19:41:30 chs Exp $ */ 2 1.10 cgd 3 1.1 cgd /* 4 1.8 mycroft * Copyright (c) 1983, 1993 5 1.8 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.28 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.11 lukem #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.34 lukem __COPYRIGHT("@(#) Copyright (c) 1983, 1993\ 35 1.34 lukem The Regents of the University of California. All rights reserved."); 36 1.1 cgd #endif /* not lint */ 37 1.1 cgd 38 1.1 cgd #ifndef lint 39 1.10 cgd #if 0 40 1.12 lukem static char sccsid[] = "@(#)tunefs.c 8.3 (Berkeley) 5/3/95"; 41 1.10 cgd #else 42 1.58 chs __RCSID("$NetBSD: tunefs.c,v 1.58 2023/01/07 19:41:30 chs Exp $"); 43 1.10 cgd #endif 44 1.1 cgd #endif /* not lint */ 45 1.1 cgd 46 1.1 cgd /* 47 1.1 cgd * tunefs: change layout parameters to an existing file system. 48 1.1 cgd */ 49 1.1 cgd #include <sys/param.h> 50 1.51 christos #include <sys/statvfs.h> 51 1.8 mycroft 52 1.8 mycroft #include <ufs/ffs/fs.h> 53 1.13 bouyer #include <ufs/ffs/ffs_extern.h> 54 1.35 simonb #include <ufs/ufs/ufs_wapbl.h> 55 1.51 christos #include <ufs/ufs/ufsmount.h> 56 1.43 bouyer #include <ufs/ufs/quota2.h> 57 1.18 bouyer 58 1.18 bouyer #include <machine/bswap.h> 59 1.8 mycroft 60 1.22 lukem #include <err.h> 61 1.8 mycroft #include <errno.h> 62 1.6 cgd #include <fcntl.h> 63 1.1 cgd #include <fstab.h> 64 1.22 lukem #include <paths.h> 65 1.58 chs #include <stdbool.h> 66 1.1 cgd #include <stdio.h> 67 1.6 cgd #include <stdlib.h> 68 1.14 thorpej #include <string.h> 69 1.6 cgd #include <unistd.h> 70 1.25 lukem #include <util.h> 71 1.6 cgd 72 1.6 cgd /* the optimization warning string template */ 73 1.8 mycroft #define OPTWARN "should optimize for %s with minfree %s %d%%" 74 1.1 cgd 75 1.1 cgd union { 76 1.1 cgd struct fs sb; 77 1.47 martin char data[MAXBSIZE]; 78 1.47 martin } sbun, buf; 79 1.1 cgd #define sblock sbun.sb 80 1.1 cgd 81 1.22 lukem int fi; 82 1.27 fvdl long dev_bsize = 512; 83 1.22 lukem int needswap = 0; 84 1.27 fvdl int is_ufs2 = 0; 85 1.56 chs int extattr = 0; 86 1.27 fvdl off_t sblockloc; 87 1.43 bouyer int userquota = 0; 88 1.43 bouyer int groupquota = 0; 89 1.43 bouyer #define Q2_EN (1) 90 1.43 bouyer #define Q2_IGN (0) 91 1.43 bouyer #define Q2_DIS (-1) 92 1.27 fvdl 93 1.27 fvdl static off_t sblock_try[] = SBLOCKSEARCH; 94 1.22 lukem 95 1.25 lukem static void bwrite(daddr_t, char *, int, const char *); 96 1.25 lukem static void bread(daddr_t, char *, int, const char *); 97 1.35 simonb static void change_log_info(long long); 98 1.22 lukem static void getsb(struct fs *, const char *); 99 1.26 lukem static int openpartition(const char *, int, char *, size_t); 100 1.53 christos static int isactive(int, struct statvfs *); 101 1.35 simonb static void show_log_info(void); 102 1.44 joerg __dead static void usage(void); 103 1.6 cgd 104 1.6 cgd int 105 1.22 lukem main(int argc, char *argv[]) 106 1.1 cgd { 107 1.58 chs int ch, aflag, pflag, Aflag, Fflag, Nflag, openflags; 108 1.22 lukem const char *special, *chg[2]; 109 1.26 lukem char device[MAXPATHLEN]; 110 1.48 mlelstv int maxbpg, minfree, optim, secsize; 111 1.58 chs uint32_t i, avgfilesize, avgfpdir; 112 1.58 chs bool active; 113 1.35 simonb long long logfilesize; 114 1.48 mlelstv int secshift, fsbtodb; 115 1.52 christos const char *avalue, *pvalue, *name; 116 1.51 christos struct statvfs sfs; 117 1.22 lukem 118 1.52 christos aflag = pflag = Aflag = Fflag = Nflag = 0; 119 1.52 christos avalue = pvalue = NULL; 120 1.48 mlelstv maxbpg = minfree = optim = secsize = -1; 121 1.24 lukem avgfilesize = avgfpdir = -1; 122 1.35 simonb logfilesize = -1; 123 1.48 mlelstv secshift = 0; 124 1.22 lukem chg[FS_OPTSPACE] = "space"; 125 1.22 lukem chg[FS_OPTTIME] = "time"; 126 1.22 lukem 127 1.52 christos while ((ch = getopt(argc, argv, "AFNa:e:g:h:l:m:o:p:q:S:")) != -1) { 128 1.22 lukem switch (ch) { 129 1.22 lukem 130 1.22 lukem case 'A': 131 1.22 lukem Aflag++; 132 1.22 lukem break; 133 1.22 lukem 134 1.22 lukem case 'F': 135 1.22 lukem Fflag++; 136 1.22 lukem break; 137 1.22 lukem 138 1.22 lukem case 'N': 139 1.22 lukem Nflag++; 140 1.22 lukem break; 141 1.22 lukem 142 1.52 christos case 'a': 143 1.52 christos name = "ACLs"; 144 1.52 christos avalue = optarg; 145 1.52 christos if (strcmp(avalue, "enable") && 146 1.52 christos strcmp(avalue, "disable")) { 147 1.52 christos errx(10, "bad %s (options are %s)", 148 1.52 christos name, "`enable' or `disable'"); 149 1.52 christos } 150 1.52 christos aflag = 1; 151 1.52 christos break; 152 1.52 christos 153 1.22 lukem case 'e': 154 1.35 simonb maxbpg = strsuftoll( 155 1.22 lukem "maximum blocks per file in a cylinder group", 156 1.35 simonb optarg, 1, INT_MAX); 157 1.22 lukem break; 158 1.22 lukem 159 1.24 lukem case 'g': 160 1.35 simonb avgfilesize = strsuftoll("average file size", optarg, 161 1.35 simonb 1, INT_MAX); 162 1.24 lukem break; 163 1.24 lukem 164 1.24 lukem case 'h': 165 1.35 simonb avgfpdir = strsuftoll( 166 1.24 lukem "expected number of files per directory", 167 1.35 simonb optarg, 1, INT_MAX); 168 1.35 simonb break; 169 1.35 simonb 170 1.35 simonb case 'l': 171 1.35 simonb logfilesize = strsuftoll("journal log file size", 172 1.35 simonb optarg, 0, INT_MAX); 173 1.24 lukem break; 174 1.22 lukem 175 1.22 lukem case 'm': 176 1.35 simonb minfree = strsuftoll("minimum percentage of free space", 177 1.35 simonb optarg, 0, 99); 178 1.22 lukem break; 179 1.22 lukem 180 1.22 lukem case 'o': 181 1.22 lukem if (strcmp(optarg, chg[FS_OPTSPACE]) == 0) 182 1.22 lukem optim = FS_OPTSPACE; 183 1.22 lukem else if (strcmp(optarg, chg[FS_OPTTIME]) == 0) 184 1.22 lukem optim = FS_OPTTIME; 185 1.22 lukem else 186 1.22 lukem errx(10, 187 1.22 lukem "bad %s (options are `space' or `time')", 188 1.22 lukem "optimization preference"); 189 1.22 lukem break; 190 1.52 christos 191 1.52 christos case 'p': 192 1.52 christos name = "POSIX1e ACLs"; 193 1.52 christos pvalue = optarg; 194 1.52 christos if (strcmp(pvalue, "enable") && 195 1.52 christos strcmp(pvalue, "disable")) { 196 1.52 christos errx(10, "bad %s (options are %s)", 197 1.52 christos name, "`enable' or `disable'"); 198 1.52 christos } 199 1.52 christos pflag = 1; 200 1.52 christos break; 201 1.52 christos 202 1.43 bouyer case 'q': 203 1.43 bouyer if (strcmp(optarg, "user") == 0) 204 1.43 bouyer userquota = Q2_EN; 205 1.43 bouyer else if (strcmp(optarg, "group") == 0) 206 1.43 bouyer groupquota = Q2_EN; 207 1.43 bouyer else if (strcmp(optarg, "nouser") == 0) 208 1.43 bouyer userquota = Q2_DIS; 209 1.43 bouyer else if (strcmp(optarg, "nogroup") == 0) 210 1.43 bouyer groupquota = Q2_DIS; 211 1.43 bouyer else 212 1.43 bouyer errx(11, "invalid quota type %s", optarg); 213 1.43 bouyer break; 214 1.52 christos 215 1.48 mlelstv case 'S': 216 1.48 mlelstv secsize = strsuftoll("physical sector size", 217 1.48 mlelstv optarg, 0, INT_MAX); 218 1.48 mlelstv secshift = ffs(secsize) - 1; 219 1.48 mlelstv if (secsize != 0 && 1 << secshift != secsize) 220 1.48 mlelstv errx(12, "sector size %d is not a power of two", secsize); 221 1.48 mlelstv break; 222 1.52 christos 223 1.22 lukem default: 224 1.22 lukem usage(); 225 1.22 lukem } 226 1.22 lukem } 227 1.22 lukem argc -= optind; 228 1.22 lukem argv += optind; 229 1.22 lukem if (argc != 1) 230 1.6 cgd usage(); 231 1.22 lukem 232 1.22 lukem special = argv[0]; 233 1.25 lukem openflags = Nflag ? O_RDONLY : O_RDWR; 234 1.26 lukem if (Fflag) 235 1.25 lukem fi = open(special, openflags); 236 1.26 lukem else { 237 1.26 lukem fi = openpartition(special, openflags, device, sizeof(device)); 238 1.25 lukem special = device; 239 1.1 cgd } 240 1.26 lukem if (fi == -1) 241 1.26 lukem err(1, "%s", special); 242 1.53 christos active = !Fflag && isactive(fi, &sfs); 243 1.1 cgd getsb(&sblock, special); 244 1.22 lukem 245 1.23 lukem #define CHANGEVAL(old, new, type, suffix) do \ 246 1.58 chs if ((uint32_t)(new) != (uint32_t)-1) { \ 247 1.23 lukem if ((new) == (old)) \ 248 1.23 lukem warnx("%s remains unchanged at %d%s", \ 249 1.23 lukem (type), (old), (suffix)); \ 250 1.23 lukem else { \ 251 1.23 lukem warnx("%s changes from %d%s to %d%s", \ 252 1.23 lukem (type), (old), (suffix), (new), (suffix)); \ 253 1.23 lukem (old) = (new); \ 254 1.23 lukem } \ 255 1.23 lukem } while (/* CONSTCOND */0) 256 1.23 lukem 257 1.25 lukem warnx("tuning %s", special); 258 1.23 lukem CHANGEVAL(sblock.fs_maxbpg, maxbpg, 259 1.23 lukem "maximum blocks per file in a cylinder group", ""); 260 1.23 lukem CHANGEVAL(sblock.fs_minfree, minfree, 261 1.23 lukem "minimum percentage of free space", "%"); 262 1.22 lukem if (minfree != -1) { 263 1.22 lukem if (minfree >= MINFREE && 264 1.22 lukem sblock.fs_optim == FS_OPTSPACE) 265 1.22 lukem warnx(OPTWARN, "time", ">=", MINFREE); 266 1.22 lukem if (minfree < MINFREE && 267 1.22 lukem sblock.fs_optim == FS_OPTTIME) 268 1.22 lukem warnx(OPTWARN, "space", "<", MINFREE); 269 1.22 lukem } 270 1.22 lukem if (optim != -1) { 271 1.22 lukem if (sblock.fs_optim == optim) { 272 1.22 lukem warnx("%s remains unchanged as %s", 273 1.22 lukem "optimization preference", 274 1.22 lukem chg[optim]); 275 1.22 lukem } else { 276 1.22 lukem warnx("%s changes from %s to %s", 277 1.22 lukem "optimization preference", 278 1.22 lukem chg[sblock.fs_optim], chg[optim]); 279 1.22 lukem sblock.fs_optim = optim; 280 1.22 lukem if (sblock.fs_minfree >= MINFREE && 281 1.22 lukem optim == FS_OPTSPACE) 282 1.22 lukem warnx(OPTWARN, "time", ">=", MINFREE); 283 1.22 lukem if (sblock.fs_minfree < MINFREE && 284 1.22 lukem optim == FS_OPTTIME) 285 1.22 lukem warnx(OPTWARN, "space", "<", MINFREE); 286 1.22 lukem } 287 1.22 lukem } 288 1.48 mlelstv if (secsize != -1) { 289 1.48 mlelstv if (secsize == 0) { 290 1.48 mlelstv secsize = sblock.fs_fsize / FFS_FSBTODB(&sblock, 1); 291 1.48 mlelstv secshift = ffs(secsize) - 1; 292 1.48 mlelstv } 293 1.48 mlelstv 294 1.48 mlelstv if (secshift < DEV_BSHIFT) 295 1.48 mlelstv warnx("sector size must be at least %d", DEV_BSIZE); 296 1.48 mlelstv else if (secshift > sblock.fs_fshift) 297 1.48 mlelstv warnx("sector size %d cannot be larger than fragment size %d", 298 1.48 mlelstv secsize, sblock.fs_fsize); 299 1.48 mlelstv else { 300 1.48 mlelstv fsbtodb = sblock.fs_fshift - secshift; 301 1.48 mlelstv if (fsbtodb == sblock.fs_fsbtodb) { 302 1.48 mlelstv warnx("sector size remains unchanged as %d", 303 1.48 mlelstv sblock.fs_fsize / FFS_FSBTODB(&sblock, 1)); 304 1.48 mlelstv } else { 305 1.48 mlelstv warnx("sector size changed from %d to %d", 306 1.48 mlelstv sblock.fs_fsize / FFS_FSBTODB(&sblock, 1), 307 1.48 mlelstv secsize); 308 1.48 mlelstv sblock.fs_fsbtodb = fsbtodb; 309 1.48 mlelstv } 310 1.48 mlelstv } 311 1.48 mlelstv } 312 1.24 lukem CHANGEVAL(sblock.fs_avgfilesize, avgfilesize, 313 1.24 lukem "average file size", ""); 314 1.24 lukem CHANGEVAL(sblock.fs_avgfpdir, avgfpdir, 315 1.24 lukem "expected number of files per directory", ""); 316 1.1 cgd 317 1.35 simonb if (logfilesize >= 0) 318 1.35 simonb change_log_info(logfilesize); 319 1.43 bouyer if (userquota == Q2_EN || groupquota == Q2_EN) 320 1.43 bouyer sblock.fs_flags |= FS_DOQUOTA2; 321 1.43 bouyer if (sblock.fs_flags & FS_DOQUOTA2) { 322 1.43 bouyer sblock.fs_quota_magic = Q2_HEAD_MAGIC; 323 1.43 bouyer switch(userquota) { 324 1.43 bouyer case Q2_EN: 325 1.43 bouyer if ((sblock.fs_quota_flags & FS_Q2_DO_TYPE(USRQUOTA)) 326 1.43 bouyer == 0) { 327 1.43 bouyer printf("enabling user quotas\n"); 328 1.43 bouyer sblock.fs_quota_flags |= 329 1.43 bouyer FS_Q2_DO_TYPE(USRQUOTA); 330 1.43 bouyer sblock.fs_quotafile[USRQUOTA] = 0; 331 1.43 bouyer } 332 1.43 bouyer break; 333 1.43 bouyer case Q2_DIS: 334 1.43 bouyer if ((sblock.fs_quota_flags & FS_Q2_DO_TYPE(USRQUOTA)) 335 1.43 bouyer != 0) { 336 1.43 bouyer printf("disabling user quotas\n"); 337 1.43 bouyer sblock.fs_quota_flags &= 338 1.43 bouyer ~FS_Q2_DO_TYPE(USRQUOTA); 339 1.43 bouyer } 340 1.43 bouyer } 341 1.43 bouyer switch(groupquota) { 342 1.43 bouyer case Q2_EN: 343 1.43 bouyer if ((sblock.fs_quota_flags & FS_Q2_DO_TYPE(GRPQUOTA)) 344 1.43 bouyer == 0) { 345 1.43 bouyer printf("enabling group quotas\n"); 346 1.43 bouyer sblock.fs_quota_flags |= 347 1.43 bouyer FS_Q2_DO_TYPE(GRPQUOTA); 348 1.43 bouyer sblock.fs_quotafile[GRPQUOTA] = 0; 349 1.43 bouyer } 350 1.43 bouyer break; 351 1.43 bouyer case Q2_DIS: 352 1.43 bouyer if ((sblock.fs_quota_flags & FS_Q2_DO_TYPE(GRPQUOTA)) 353 1.43 bouyer != 0) { 354 1.43 bouyer printf("disabling group quotas\n"); 355 1.43 bouyer sblock.fs_quota_flags &= 356 1.43 bouyer ~FS_Q2_DO_TYPE(GRPQUOTA); 357 1.43 bouyer } 358 1.43 bouyer } 359 1.43 bouyer } 360 1.43 bouyer /* 361 1.43 bouyer * if we disabled all quotas, FS_DOQUOTA2 and associated inode(s) will 362 1.43 bouyer * be cleared by kernel or fsck. 363 1.43 bouyer */ 364 1.52 christos if (aflag) { 365 1.57 chs name = "NFSv4 ACLs"; 366 1.52 christos if (strcmp(avalue, "enable") == 0) { 367 1.56 chs if (is_ufs2 && !extattr) { 368 1.56 chs warnx("%s not supported by this fs", name); 369 1.56 chs } else if (sblock.fs_flags & FS_NFS4ACLS) { 370 1.52 christos warnx("%s remains unchanged as enabled", name); 371 1.52 christos } else if (sblock.fs_flags & FS_POSIX1EACLS) { 372 1.52 christos warnx("%s and POSIX.1e ACLs are mutually " 373 1.52 christos "exclusive", name); 374 1.52 christos } else { 375 1.55 christos sblock.fs_flags |= FS_NFS4ACLS; 376 1.52 christos printf("%s set\n", name); 377 1.52 christos } 378 1.52 christos } else if (strcmp(avalue, "disable") == 0) { 379 1.55 christos if ((~sblock.fs_flags & FS_NFS4ACLS) == FS_NFS4ACLS) { 380 1.52 christos warnx("%s remains unchanged as disabled", 381 1.52 christos name); 382 1.52 christos } else { 383 1.55 christos sblock.fs_flags &= ~FS_NFS4ACLS; 384 1.52 christos printf("%s cleared\n", name); 385 1.52 christos } 386 1.52 christos } 387 1.52 christos } 388 1.52 christos 389 1.52 christos if (pflag) { 390 1.52 christos name = "POSIX1e ACLs"; 391 1.52 christos if (strcmp(pvalue, "enable") == 0) { 392 1.56 chs if (is_ufs2 && !extattr) { 393 1.56 chs warnx("%s not supported by this fs", name); 394 1.56 chs } else if (sblock.fs_flags & FS_POSIX1EACLS) { 395 1.52 christos warnx("%s remains unchanged as enabled", name); 396 1.55 christos } else if (sblock.fs_flags & FS_NFS4ACLS) { 397 1.52 christos warnx("%s and ACLs are mutually " 398 1.52 christos "exclusive", name); 399 1.52 christos } else { 400 1.52 christos sblock.fs_flags |= FS_POSIX1EACLS; 401 1.54 dholland printf("%s set\n", name); 402 1.52 christos } 403 1.52 christos } else if (strcmp(pvalue, "disable") == 0) { 404 1.52 christos if ((~sblock.fs_flags & FS_POSIX1EACLS) == 405 1.52 christos FS_POSIX1EACLS) { 406 1.52 christos warnx("%s remains unchanged as disabled", 407 1.52 christos name); 408 1.52 christos } else { 409 1.52 christos sblock.fs_flags &= ~FS_POSIX1EACLS; 410 1.54 dholland printf("%s cleared\n", name); 411 1.52 christos } 412 1.52 christos } 413 1.52 christos } 414 1.35 simonb 415 1.12 lukem if (Nflag) { 416 1.52 christos printf("%s: current settings of %s\n", getprogname(), special); 417 1.37 simonb printf("\tmaximum contiguous block count %d\n", 418 1.12 lukem sblock.fs_maxcontig); 419 1.37 simonb printf("\tmaximum blocks per file in a cylinder group %d\n", 420 1.12 lukem sblock.fs_maxbpg); 421 1.37 simonb printf("\tminimum percentage of free space %d%%\n", 422 1.12 lukem sblock.fs_minfree); 423 1.37 simonb printf("\toptimization preference: %s\n", chg[sblock.fs_optim]); 424 1.37 simonb printf("\taverage file size: %d\n", sblock.fs_avgfilesize); 425 1.37 simonb printf("\texpected number of files per directory: %d\n", 426 1.24 lukem sblock.fs_avgfpdir); 427 1.35 simonb show_log_info(); 428 1.43 bouyer printf("\tquotas"); 429 1.43 bouyer if (sblock.fs_flags & FS_DOQUOTA2) { 430 1.43 bouyer if (sblock.fs_quota_flags & FS_Q2_DO_TYPE(USRQUOTA)) { 431 1.43 bouyer printf(" user"); 432 1.43 bouyer if (sblock.fs_quota_flags & 433 1.43 bouyer FS_Q2_DO_TYPE(GRPQUOTA)) 434 1.43 bouyer printf(","); 435 1.43 bouyer } 436 1.43 bouyer if (sblock.fs_quota_flags & FS_Q2_DO_TYPE(GRPQUOTA)) 437 1.43 bouyer printf(" group"); 438 1.43 bouyer printf(" enabled\n"); 439 1.43 bouyer } else { 440 1.50 pgoyette printf(" disabled\n"); 441 1.43 bouyer } 442 1.52 christos printf("\tPOSIX.1e ACLs %s\n", 443 1.52 christos (sblock.fs_flags & FS_POSIX1EACLS) ? "enabled" : "disabled"); 444 1.55 christos printf("\tNFS4 ACLs %s\n", 445 1.55 christos (sblock.fs_flags & FS_NFS4ACLS) ? "enabled" : "disabled"); 446 1.52 christos printf("%s: no changes made\n", getprogname()); 447 1.52 christos return 0; 448 1.12 lukem } 449 1.22 lukem 450 1.47 martin memcpy(&buf, (char *)&sblock, SBLOCKSIZE); 451 1.13 bouyer if (needswap) 452 1.47 martin ffs_sb_swap((struct fs*)&buf, (struct fs*)&buf); 453 1.48 mlelstv 454 1.48 mlelstv /* write superblock to original coordinates (use old dev_bsize!) */ 455 1.47 martin bwrite(sblockloc, buf.data, SBLOCKSIZE, special); 456 1.48 mlelstv 457 1.51 christos if (active) { 458 1.51 christos struct ufs_args args; 459 1.51 christos args.fspec = sfs.f_mntfromname; 460 1.51 christos if (mount(MOUNT_FFS, sfs.f_mntonname, sfs.f_flag | MNT_UPDATE, 461 1.51 christos &args, sizeof args) == -1) 462 1.51 christos warn("mount"); 463 1.51 christos else 464 1.51 christos printf("%s: mount of %s on %s updated\n", 465 1.51 christos getprogname(), sfs.f_mntfromname, sfs.f_mntonname); 466 1.51 christos } 467 1.51 christos 468 1.51 christos 469 1.48 mlelstv /* correct dev_bsize from possibly changed superblock data */ 470 1.48 mlelstv dev_bsize = sblock.fs_fsize / FFS_FSBTODB(&sblock, 1); 471 1.48 mlelstv 472 1.1 cgd if (Aflag) 473 1.1 cgd for (i = 0; i < sblock.fs_ncg; i++) 474 1.46 dholland bwrite(FFS_FSBTODB(&sblock, cgsblock(&sblock, i)), 475 1.47 martin buf.data, SBLOCKSIZE, special); 476 1.1 cgd close(fi); 477 1.1 cgd exit(0); 478 1.6 cgd } 479 1.6 cgd 480 1.53 christos static int 481 1.53 christos isactive(int fd, struct statvfs *rsfs) 482 1.53 christos { 483 1.53 christos struct stat st0, st; 484 1.53 christos struct statvfs *sfs; 485 1.53 christos int n; 486 1.53 christos 487 1.53 christos if (fstat(fd, &st0) == -1) { 488 1.53 christos warn("stat"); 489 1.53 christos return 0; 490 1.53 christos } 491 1.53 christos 492 1.53 christos if ((n = getmntinfo(&sfs, 0)) == -1) { 493 1.53 christos warn("getmntinfo"); 494 1.53 christos return 0; 495 1.53 christos } 496 1.53 christos 497 1.53 christos for (int i = 0; i < n; i++) { 498 1.53 christos if (stat(sfs[i].f_mntfromname, &st) == -1) 499 1.53 christos continue; 500 1.53 christos if (st.st_rdev != st0.st_rdev) 501 1.53 christos continue; 502 1.53 christos *rsfs = sfs[i]; 503 1.53 christos return 1; 504 1.53 christos 505 1.53 christos } 506 1.53 christos return 0; 507 1.53 christos } 508 1.53 christos 509 1.35 simonb static void 510 1.35 simonb show_log_info(void) 511 1.35 simonb { 512 1.35 simonb const char *loc; 513 1.36 simonb uint64_t size, blksize, logsize; 514 1.35 simonb int print; 515 1.35 simonb 516 1.35 simonb switch (sblock.fs_journal_location) { 517 1.35 simonb case UFS_WAPBL_JOURNALLOC_NONE: 518 1.35 simonb print = blksize = 0; 519 1.35 simonb /* nothing */ 520 1.35 simonb break; 521 1.35 simonb case UFS_WAPBL_JOURNALLOC_END_PARTITION: 522 1.35 simonb loc = "end of partition"; 523 1.35 simonb size = sblock.fs_journallocs[UFS_WAPBL_EPART_COUNT]; 524 1.35 simonb blksize = sblock.fs_journallocs[UFS_WAPBL_EPART_BLKSZ]; 525 1.35 simonb print = 1; 526 1.35 simonb break; 527 1.35 simonb case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM: 528 1.35 simonb loc = "in filesystem"; 529 1.35 simonb size = sblock.fs_journallocs[UFS_WAPBL_INFS_COUNT]; 530 1.35 simonb blksize = sblock.fs_journallocs[UFS_WAPBL_INFS_BLKSZ]; 531 1.35 simonb print = 1; 532 1.35 simonb break; 533 1.35 simonb default: 534 1.35 simonb loc = "unknown"; 535 1.35 simonb size = blksize = 0; 536 1.35 simonb print = 1; 537 1.35 simonb break; 538 1.35 simonb } 539 1.35 simonb 540 1.35 simonb if (print) { 541 1.36 simonb logsize = size * blksize; 542 1.36 simonb 543 1.37 simonb printf("\tjournal log file location: %s\n", loc); 544 1.37 simonb printf("\tjournal log file size: "); 545 1.36 simonb if (logsize == 0) 546 1.37 simonb printf("0\n"); 547 1.36 simonb else { 548 1.36 simonb char sizebuf[8]; 549 1.36 simonb humanize_number(sizebuf, 6, size * blksize, "B", 550 1.36 simonb HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 551 1.37 simonb printf("%s (%" PRId64 " bytes)", sizebuf, logsize); 552 1.36 simonb } 553 1.37 simonb printf("\n"); 554 1.37 simonb printf("\tjournal log flags:"); 555 1.35 simonb if (sblock.fs_journal_flags & UFS_WAPBL_FLAGS_CREATE_LOG) 556 1.40 bouyer printf(" create-log"); 557 1.35 simonb if (sblock.fs_journal_flags & UFS_WAPBL_FLAGS_CLEAR_LOG) 558 1.37 simonb printf(" clear-log"); 559 1.37 simonb printf("\n"); 560 1.35 simonb } 561 1.35 simonb } 562 1.35 simonb 563 1.35 simonb static void 564 1.35 simonb change_log_info(long long logfilesize) 565 1.6 cgd { 566 1.35 simonb /* 567 1.35 simonb * NOTES: 568 1.35 simonb * - only operate on in-filesystem log sizes 569 1.35 simonb * - can't change size of existing log 570 1.35 simonb * - if current is same, no action 571 1.35 simonb * - if current is zero and new is non-zero, set flag to create log 572 1.35 simonb * on next mount 573 1.35 simonb * - if current is non-zero and new is zero, set flag to clear log 574 1.35 simonb * on next mount 575 1.35 simonb */ 576 1.35 simonb int in_fs_log; 577 1.35 simonb uint64_t old_size; 578 1.35 simonb 579 1.35 simonb old_size = 0; 580 1.35 simonb switch (sblock.fs_journal_location) { 581 1.35 simonb case UFS_WAPBL_JOURNALLOC_END_PARTITION: 582 1.35 simonb in_fs_log = 0; 583 1.35 simonb old_size = sblock.fs_journallocs[UFS_WAPBL_EPART_COUNT] * 584 1.35 simonb sblock.fs_journallocs[UFS_WAPBL_EPART_BLKSZ]; 585 1.35 simonb break; 586 1.35 simonb 587 1.35 simonb case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM: 588 1.35 simonb in_fs_log = 1; 589 1.35 simonb old_size = sblock.fs_journallocs[UFS_WAPBL_INFS_COUNT] * 590 1.35 simonb sblock.fs_journallocs[UFS_WAPBL_INFS_BLKSZ]; 591 1.35 simonb break; 592 1.35 simonb 593 1.35 simonb case UFS_WAPBL_JOURNALLOC_NONE: 594 1.35 simonb default: 595 1.35 simonb in_fs_log = 0; 596 1.35 simonb old_size = 0; 597 1.35 simonb break; 598 1.35 simonb } 599 1.35 simonb 600 1.35 simonb if (logfilesize == 0) { 601 1.35 simonb /* 602 1.35 simonb * Don't clear out the locators - the kernel might need 603 1.35 simonb * these to find the log! Just set the "clear the log" 604 1.35 simonb * flag and let the kernel do the rest. 605 1.35 simonb */ 606 1.35 simonb sblock.fs_journal_flags |= UFS_WAPBL_FLAGS_CLEAR_LOG; 607 1.35 simonb sblock.fs_journal_flags &= ~UFS_WAPBL_FLAGS_CREATE_LOG; 608 1.35 simonb warnx("log file size cleared from %" PRIu64 "", old_size); 609 1.35 simonb return; 610 1.35 simonb } 611 1.8 mycroft 612 1.41 bouyer if (!in_fs_log && logfilesize > 0 && old_size > 0) 613 1.41 bouyer errx(1, "Can't change size of non-in-filesystem log"); 614 1.41 bouyer 615 1.42 bouyer if (old_size == (uint64_t)logfilesize && logfilesize > 0) { 616 1.41 bouyer /* no action */ 617 1.41 bouyer warnx("log file size remains unchanged at %lld", logfilesize); 618 1.41 bouyer return; 619 1.41 bouyer } 620 1.41 bouyer 621 1.35 simonb if (old_size == 0) { 622 1.35 simonb /* create new log of desired size next mount */ 623 1.35 simonb sblock.fs_journal_location = UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM; 624 1.35 simonb sblock.fs_journallocs[UFS_WAPBL_INFS_ADDR] = 0; 625 1.35 simonb sblock.fs_journallocs[UFS_WAPBL_INFS_COUNT] = logfilesize; 626 1.35 simonb sblock.fs_journallocs[UFS_WAPBL_INFS_BLKSZ] = 0; 627 1.35 simonb sblock.fs_journallocs[UFS_WAPBL_INFS_INO] = 0; 628 1.35 simonb sblock.fs_journal_flags |= UFS_WAPBL_FLAGS_CREATE_LOG; 629 1.35 simonb sblock.fs_journal_flags &= ~UFS_WAPBL_FLAGS_CLEAR_LOG; 630 1.35 simonb warnx("log file size set to %lld", logfilesize); 631 1.35 simonb } else { 632 1.35 simonb errx(1, 633 1.35 simonb "Can't change existing log size from %" PRIu64 " to %lld", 634 1.35 simonb old_size, logfilesize); 635 1.35 simonb } 636 1.22 lukem } 637 1.22 lukem 638 1.22 lukem static void 639 1.22 lukem usage(void) 640 1.22 lukem { 641 1.22 lukem 642 1.29 jmmv fprintf(stderr, "usage: tunefs [-AFN] tuneup-options special-device\n"); 643 1.1 cgd fprintf(stderr, "where tuneup-options are:\n"); 644 1.52 christos fprintf(stderr, "\t-a ACLS: `enable' or `disable'\n"); 645 1.1 cgd fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n"); 646 1.24 lukem fprintf(stderr, "\t-g average file size\n"); 647 1.24 lukem fprintf(stderr, "\t-h expected number of files per directory\n"); 648 1.35 simonb fprintf(stderr, "\t-l journal log file size (`0' to clear journal)\n"); 649 1.1 cgd fprintf(stderr, "\t-m minimum percentage of free space\n"); 650 1.52 christos fprintf(stderr, "\t-p POSIX.1e ACLS: `enable' or `disable'\n"); 651 1.23 lukem fprintf(stderr, "\t-o optimization preference (`space' or `time')\n"); 652 1.43 bouyer fprintf(stderr, "\t-q quota type (`[no]user' or `[no]group')\n"); 653 1.48 mlelstv fprintf(stderr, "\t-S sector size\n"); 654 1.8 mycroft exit(2); 655 1.1 cgd } 656 1.1 cgd 657 1.22 lukem static void 658 1.22 lukem getsb(struct fs *fs, const char *file) 659 1.1 cgd { 660 1.27 fvdl int i; 661 1.1 cgd 662 1.30 dsl for (i = 0; ; i++) { 663 1.30 dsl if (sblock_try[i] == -1) 664 1.30 dsl errx(5, "cannot find filesystem superblock"); 665 1.27 fvdl bread(sblock_try[i] / dev_bsize, (char *)fs, SBLOCKSIZE, file); 666 1.27 fvdl switch(fs->fs_magic) { 667 1.56 chs case FS_UFS2EA_MAGIC: 668 1.56 chs extattr = 1; 669 1.56 chs /*FALLTHROUGH*/ 670 1.27 fvdl case FS_UFS2_MAGIC: 671 1.27 fvdl is_ufs2 = 1; 672 1.27 fvdl /*FALLTHROUGH*/ 673 1.27 fvdl case FS_UFS1_MAGIC: 674 1.30 dsl break; 675 1.56 chs case FS_UFS2EA_MAGIC_SWAPPED: 676 1.56 chs extattr = 1; 677 1.56 chs /*FALLTHROUGH*/ 678 1.27 fvdl case FS_UFS2_MAGIC_SWAPPED: 679 1.27 fvdl is_ufs2 = 1; 680 1.27 fvdl /*FALLTHROUGH*/ 681 1.27 fvdl case FS_UFS1_MAGIC_SWAPPED: 682 1.22 lukem warnx("%s: swapping byte order", file); 683 1.13 bouyer needswap = 1; 684 1.21 lukem ffs_sb_swap(fs, fs); 685 1.30 dsl break; 686 1.27 fvdl default: 687 1.30 dsl continue; 688 1.27 fvdl } 689 1.30 dsl if (!is_ufs2 && sblock_try[i] == SBLOCK_UFS2) 690 1.30 dsl continue; 691 1.31 dsl if ((is_ufs2 || fs->fs_old_flags & FS_FLAGS_UPDATED) 692 1.30 dsl && fs->fs_sblockloc != sblock_try[i]) 693 1.30 dsl continue; 694 1.30 dsl break; 695 1.17 ross } 696 1.30 dsl 697 1.46 dholland dev_bsize = fs->fs_fsize / FFS_FSBTODB(fs, 1); 698 1.27 fvdl sblockloc = sblock_try[i] / dev_bsize; 699 1.1 cgd } 700 1.1 cgd 701 1.22 lukem static void 702 1.25 lukem bwrite(daddr_t blk, char *buffer, int size, const char *file) 703 1.1 cgd { 704 1.25 lukem off_t offset; 705 1.8 mycroft 706 1.25 lukem offset = (off_t)blk * dev_bsize; 707 1.25 lukem if (lseek(fi, offset, SEEK_SET) == -1) 708 1.25 lukem err(6, "%s: seeking to %lld", file, (long long)offset); 709 1.22 lukem if (write(fi, buffer, size) != size) 710 1.25 lukem err(7, "%s: writing %d bytes", file, size); 711 1.1 cgd } 712 1.1 cgd 713 1.25 lukem static void 714 1.25 lukem bread(daddr_t blk, char *buffer, int cnt, const char *file) 715 1.1 cgd { 716 1.25 lukem off_t offset; 717 1.25 lukem int i; 718 1.1 cgd 719 1.25 lukem offset = (off_t)blk * dev_bsize; 720 1.25 lukem if (lseek(fi, offset, SEEK_SET) == -1) 721 1.25 lukem err(4, "%s: seeking to %lld", file, (long long)offset); 722 1.25 lukem if ((i = read(fi, buffer, cnt)) != cnt) 723 1.25 lukem errx(5, "%s: short read", file); 724 1.26 lukem } 725 1.26 lukem 726 1.26 lukem static int 727 1.26 lukem openpartition(const char *name, int flags, char *device, size_t devicelen) 728 1.26 lukem { 729 1.49 mlelstv char specname[MAXPATHLEN]; 730 1.49 mlelstv char rawname[MAXPATHLEN]; 731 1.49 mlelstv const char *special, *raw; 732 1.26 lukem struct fstab *fs; 733 1.26 lukem int fd, oerrno; 734 1.26 lukem 735 1.26 lukem fs = getfsfile(name); 736 1.49 mlelstv special = fs ? fs->fs_spec : name; 737 1.49 mlelstv 738 1.49 mlelstv raw = getfsspecname(specname, sizeof(specname), special); 739 1.49 mlelstv if (raw == NULL) 740 1.49 mlelstv err(1, "%s: %s", name, specname); 741 1.49 mlelstv special = getdiskrawname(rawname, sizeof(rawname), raw); 742 1.49 mlelstv if (special == NULL) 743 1.49 mlelstv special = raw; 744 1.49 mlelstv 745 1.49 mlelstv fd = opendisk(special, flags, device, devicelen, 0); 746 1.26 lukem if (fd == -1 && errno == ENOENT) { 747 1.26 lukem oerrno = errno; 748 1.49 mlelstv strlcpy(device, special, devicelen); 749 1.26 lukem errno = oerrno; 750 1.26 lukem } 751 1.26 lukem return (fd); 752 1.1 cgd } 753