1 1.35 chs /* $NetBSD: quot.c,v 1.35 2022/11/17 06:40:41 chs Exp $ */ 2 1.9 ws 3 1.1 ws /* 4 1.1 ws * Copyright (C) 1991, 1994 Wolfgang Solfrank. 5 1.1 ws * Copyright (C) 1991, 1994 TooLs GmbH. 6 1.1 ws * All rights reserved. 7 1.1 ws * 8 1.1 ws * Redistribution and use in source and binary forms, with or without 9 1.1 ws * modification, are permitted provided that the following conditions 10 1.1 ws * are met: 11 1.1 ws * 1. Redistributions of source code must retain the above copyright 12 1.1 ws * notice, this list of conditions and the following disclaimer. 13 1.1 ws * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 ws * notice, this list of conditions and the following disclaimer in the 15 1.1 ws * documentation and/or other materials provided with the distribution. 16 1.1 ws * 3. All advertising materials mentioning features or use of this software 17 1.1 ws * must display the following acknowledgement: 18 1.1 ws * This product includes software developed by TooLs GmbH. 19 1.1 ws * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 1.1 ws * derived from this software without specific prior written permission. 21 1.1 ws * 22 1.1 ws * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 1.1 ws * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 1.1 ws * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 1.1 ws * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 1.1 ws * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 1.1 ws * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 1.1 ws * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 1.1 ws * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 1.1 ws * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 1.1 ws * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 1.1 ws */ 33 1.2 cgd 34 1.11 lukem #include <sys/cdefs.h> 35 1.2 cgd #ifndef lint 36 1.35 chs __RCSID("$NetBSD: quot.c,v 1.35 2022/11/17 06:40:41 chs Exp $"); 37 1.2 cgd #endif /* not lint */ 38 1.2 cgd 39 1.4 cgd #include <sys/param.h> 40 1.4 cgd #include <sys/mount.h> 41 1.4 cgd #include <sys/time.h> 42 1.18 fvdl #include <ufs/ufs/dinode.h> 43 1.14 fvdl #include <ufs/ffs/fs.h> 44 1.4 cgd 45 1.12 lukem #include <err.h> 46 1.11 lukem #include <errno.h> 47 1.11 lukem #include <fcntl.h> 48 1.11 lukem #include <pwd.h> 49 1.1 ws #include <stdio.h> 50 1.1 ws #include <stdlib.h> 51 1.1 ws #include <string.h> 52 1.8 mrg #include <unistd.h> 53 1.1 ws 54 1.1 ws /* some flags of what to do: */ 55 1.1 ws static char estimate; 56 1.1 ws static char count; 57 1.1 ws static char unused; 58 1.29 christos static void (*func)(int, struct fs *, const char *); 59 1.1 ws static long blocksize; 60 1.1 ws static char *header; 61 1.1 ws 62 1.2 cgd /* 63 1.2 cgd * Original BSD quot doesn't round to number of frags/blocks, 64 1.2 cgd * doesn't account for indirection blocks and gets it totally 65 1.2 cgd * wrong if the size is a multiple of the blocksize. 66 1.9 ws * The new code always counts the number of DEV_BSIZE byte blocks 67 1.2 cgd * instead of the number of kilobytes and converts them to 68 1.2 cgd * kByte when done (on request). 69 1.2 cgd */ 70 1.1 ws #ifdef COMPAT 71 1.16 mycroft #define SIZE(n) ((long long)(n)) 72 1.1 ws #else 73 1.16 mycroft #define SIZE(n) howmany((long long)(n) * DEV_BSIZE, (long long)blocksize) 74 1.1 ws #endif 75 1.1 ws 76 1.1 ws #define INOCNT(fs) ((fs)->fs_ipg) 77 1.18 fvdl #define INOSZ(fs) \ 78 1.18 fvdl (((fs)->fs_magic == FS_UFS1_MAGIC ? sizeof(struct ufs1_dinode) : \ 79 1.18 fvdl sizeof(struct ufs2_dinode)) * INOCNT(fs)) 80 1.18 fvdl 81 1.18 fvdl union dinode { 82 1.18 fvdl struct ufs1_dinode dp1; 83 1.18 fvdl struct ufs2_dinode dp2; 84 1.18 fvdl }; 85 1.18 fvdl #define DIP(fs, dp, field) \ 86 1.18 fvdl (((fs)->fs_magic == FS_UFS1_MAGIC) ? \ 87 1.18 fvdl (dp)->dp1.di_##field : (dp)->dp2.di_##field) 88 1.18 fvdl 89 1.1 ws 90 1.29 christos static int cmpusers(const void *, const void *); 91 1.29 christos static void dofsizes(int, struct fs *, const char *); 92 1.29 christos static void donames(int, struct fs *, const char *); 93 1.29 christos static void douser(int, struct fs *, const char *); 94 1.29 christos static union dinode *get_inode(int, struct fs *, ino_t); 95 1.29 christos static void ffs_oldfscompat(struct fs *); 96 1.29 christos static void initfsizes(void); 97 1.29 christos static void inituser(void); 98 1.29 christos static int isfree(struct fs *, union dinode *); 99 1.29 christos static void quot(const char *, const char *); 100 1.29 christos static void usage(void) __attribute__((__noreturn__)); 101 1.29 christos static struct user *user(uid_t); 102 1.29 christos static void uses(uid_t, daddr_t, time_t); 103 1.29 christos static void usrrehash(void); 104 1.29 christos static int virtualblocks(struct fs *, union dinode *); 105 1.11 lukem 106 1.11 lukem 107 1.18 fvdl static union dinode * 108 1.29 christos get_inode(int fd, struct fs *super, ino_t ino) 109 1.1 ws { 110 1.18 fvdl static char *ipbuf; 111 1.1 ws static ino_t last; 112 1.1 ws 113 1.1 ws if (fd < 0) { /* flush cache */ 114 1.18 fvdl if (ipbuf) { 115 1.18 fvdl free(ipbuf); 116 1.18 fvdl ipbuf = NULL; 117 1.1 ws } 118 1.1 ws return 0; 119 1.1 ws } 120 1.1 ws 121 1.18 fvdl if (!ipbuf || ino < last || ino >= last + INOCNT(super)) { 122 1.18 fvdl if (!ipbuf 123 1.18 fvdl && !(ipbuf = malloc(INOSZ(super)))) 124 1.12 lukem errx(1, "allocate inodes"); 125 1.1 ws last = (ino / INOCNT(super)) * INOCNT(super); 126 1.9 ws if (lseek(fd, 127 1.10 mycroft (off_t)ino_to_fsba(super, last) << super->fs_fshift, 128 1.10 mycroft 0) < 0 || 129 1.29 christos read(fd, ipbuf, INOSZ(super)) != (ssize_t)INOSZ(super)) 130 1.12 lukem errx(1, "read inodes"); 131 1.1 ws } 132 1.18 fvdl 133 1.18 fvdl if (super->fs_magic == FS_UFS1_MAGIC) 134 1.18 fvdl return ((union dinode *) 135 1.18 fvdl &((struct ufs1_dinode *)ipbuf)[ino % INOCNT(super)]); 136 1.18 fvdl return ((union dinode *) 137 1.18 fvdl &((struct ufs2_dinode *)ipbuf)[ino % INOCNT(super)]); 138 1.1 ws } 139 1.1 ws 140 1.1 ws #ifdef COMPAT 141 1.29 christos #define actualblocks(fs, dp) (int)(DIP(fs, dp, blocks) / 2) 142 1.1 ws #else 143 1.29 christos #define actualblocks(fs, dp) (int)(DIP(fs, dp, blocks)) 144 1.1 ws #endif 145 1.1 ws 146 1.9 ws static int 147 1.29 christos virtualblocks(struct fs *super, union dinode *dp) 148 1.1 ws { 149 1.12 lukem off_t nblk, sz; 150 1.1 ws 151 1.18 fvdl sz = DIP(super, dp, size); 152 1.1 ws #ifdef COMPAT 153 1.32 dholland if (ffs_lblkno(super, sz) >= UFS_NDADDR) { 154 1.32 dholland nblk = ffs_blkroundup(super, sz); 155 1.1 ws if (sz == nblk) 156 1.1 ws nblk += super->fs_bsize; 157 1.1 ws } 158 1.1 ws 159 1.1 ws return sz / 1024; 160 1.1 ws #else /* COMPAT */ 161 1.1 ws 162 1.32 dholland if (ffs_lblkno(super, sz) >= UFS_NDADDR) { 163 1.32 dholland nblk = ffs_blkroundup(super, sz); 164 1.32 dholland sz = ffs_lblkno(super, nblk); 165 1.31 dholland sz = howmany(sz - UFS_NDADDR, FFS_NINDIR(super)); 166 1.1 ws while (sz > 0) { 167 1.1 ws nblk += sz * super->fs_bsize; 168 1.9 ws /* One block on this level is in the inode itself */ 169 1.31 dholland sz = howmany(sz - 1, FFS_NINDIR(super)); 170 1.1 ws } 171 1.1 ws } else 172 1.32 dholland nblk = ffs_fragroundup(super, sz); 173 1.1 ws 174 1.9 ws return nblk / DEV_BSIZE; 175 1.1 ws #endif /* COMPAT */ 176 1.1 ws } 177 1.1 ws 178 1.9 ws static int 179 1.18 fvdl isfree(fs, dp) 180 1.18 fvdl struct fs *fs; 181 1.18 fvdl union dinode *dp; 182 1.1 ws { 183 1.1 ws #ifdef COMPAT 184 1.18 fvdl return (DIP(fs, dp, mode) & IFMT) == 0; 185 1.1 ws #else /* COMPAT */ 186 1.18 fvdl switch (DIP(fs, dp, mode) & IFMT) { 187 1.1 ws case IFIFO: 188 1.1 ws case IFLNK: /* should check FASTSYMLINK? */ 189 1.1 ws case IFDIR: 190 1.1 ws case IFREG: 191 1.1 ws return 0; 192 1.1 ws default: 193 1.1 ws return 1; 194 1.1 ws } 195 1.1 ws #endif 196 1.1 ws } 197 1.1 ws 198 1.1 ws static struct user { 199 1.1 ws uid_t uid; 200 1.1 ws char *name; 201 1.1 ws daddr_t space; 202 1.1 ws long count; 203 1.1 ws daddr_t spc30; 204 1.1 ws daddr_t spc60; 205 1.1 ws daddr_t spc90; 206 1.1 ws } *users; 207 1.1 ws static int nusers; 208 1.1 ws 209 1.9 ws static void 210 1.29 christos inituser(void) 211 1.1 ws { 212 1.12 lukem int i; 213 1.12 lukem struct user *usr; 214 1.1 ws 215 1.1 ws if (!nusers) { 216 1.1 ws nusers = 8; 217 1.29 christos if (!(users = calloc(nusers, sizeof(*users)))) 218 1.29 christos err(1, "allocate users"); 219 1.1 ws } else { 220 1.1 ws for (usr = users, i = nusers; --i >= 0; usr++) { 221 1.1 ws usr->space = usr->spc30 = usr->spc60 = usr->spc90 = 0; 222 1.1 ws usr->count = 0; 223 1.1 ws } 224 1.1 ws } 225 1.1 ws } 226 1.1 ws 227 1.9 ws static void 228 1.29 christos usrrehash(void) 229 1.1 ws { 230 1.12 lukem int i; 231 1.12 lukem struct user *usr, *usrn; 232 1.1 ws struct user *svusr; 233 1.1 ws 234 1.1 ws svusr = users; 235 1.1 ws nusers <<= 1; 236 1.29 christos if (!(users = calloc(nusers, sizeof(*users)))) 237 1.29 christos err(1, "allocate users"); 238 1.1 ws for (usr = svusr, i = nusers >> 1; --i >= 0; usr++) { 239 1.9 ws for (usrn = users + (usr->uid&(nusers - 1)); 240 1.9 ws usrn->name; 241 1.9 ws usrn--) { 242 1.1 ws if (usrn <= users) 243 1.1 ws usrn = users + nusers; 244 1.1 ws } 245 1.1 ws *usrn = *usr; 246 1.1 ws } 247 1.1 ws } 248 1.1 ws 249 1.9 ws static struct user * 250 1.29 christos user(uid_t uid) 251 1.1 ws { 252 1.12 lukem struct user *usr; 253 1.12 lukem int i; 254 1.1 ws struct passwd *pwd; 255 1.1 ws 256 1.29 christos for (;;) { 257 1.29 christos for (usr = users + (uid & (nusers - 1)), i = nusers; 258 1.9 ws --i >= 0; 259 1.9 ws usr--) { 260 1.1 ws if (!usr->name) { 261 1.1 ws usr->uid = uid; 262 1.1 ws 263 1.29 christos if (!(pwd = getpwuid(uid))) 264 1.29 christos asprintf(&usr->name, "#%u", uid); 265 1.29 christos else 266 1.29 christos asprintf(&usr->name, "%s", 267 1.29 christos pwd->pw_name); 268 1.12 lukem if (!usr->name) 269 1.12 lukem errx(1, "allocate users"); 270 1.1 ws return usr; 271 1.1 ws } else if (usr->uid == uid) 272 1.1 ws return usr; 273 1.1 ws 274 1.1 ws if (usr <= users) 275 1.1 ws usr = users + nusers; 276 1.1 ws } 277 1.1 ws usrrehash(); 278 1.1 ws } 279 1.1 ws } 280 1.1 ws 281 1.9 ws static int 282 1.9 ws cmpusers(u1, u2) 283 1.11 lukem const void *u1, *u2; 284 1.1 ws { 285 1.28 lukem return ((const struct user *)u2)->space - ((const struct user *)u1)->space; 286 1.1 ws } 287 1.2 cgd 288 1.9 ws #define sortusers(users) (qsort((users), nusers, sizeof(struct user), \ 289 1.9 ws cmpusers)) 290 1.1 ws 291 1.9 ws static void 292 1.9 ws uses(uid, blks, act) 293 1.1 ws uid_t uid; 294 1.1 ws daddr_t blks; 295 1.1 ws time_t act; 296 1.1 ws { 297 1.1 ws static time_t today; 298 1.12 lukem struct user *usr; 299 1.1 ws 300 1.1 ws if (!today) 301 1.1 ws time(&today); 302 1.1 ws 303 1.1 ws usr = user(uid); 304 1.1 ws usr->count++; 305 1.1 ws usr->space += blks; 306 1.1 ws 307 1.1 ws if (today - act > 90L * 24L * 60L * 60L) 308 1.1 ws usr->spc90 += blks; 309 1.1 ws if (today - act > 60L * 24L * 60L * 60L) 310 1.1 ws usr->spc60 += blks; 311 1.1 ws if (today - act > 30L * 24L * 60L * 60L) 312 1.1 ws usr->spc30 += blks; 313 1.1 ws } 314 1.1 ws 315 1.1 ws #ifdef COMPAT 316 1.1 ws #define FSZCNT 500 317 1.1 ws #else 318 1.1 ws #define FSZCNT 512 319 1.1 ws #endif 320 1.1 ws struct fsizes { 321 1.1 ws struct fsizes *fsz_next; 322 1.1 ws daddr_t fsz_first, fsz_last; 323 1.1 ws ino_t fsz_count[FSZCNT]; 324 1.1 ws daddr_t fsz_sz[FSZCNT]; 325 1.1 ws } *fsizes; 326 1.1 ws 327 1.9 ws static void 328 1.9 ws initfsizes() 329 1.1 ws { 330 1.12 lukem struct fsizes *fp; 331 1.12 lukem int i; 332 1.1 ws 333 1.1 ws for (fp = fsizes; fp; fp = fp->fsz_next) { 334 1.1 ws for (i = FSZCNT; --i >= 0;) { 335 1.1 ws fp->fsz_count[i] = 0; 336 1.1 ws fp->fsz_sz[i] = 0; 337 1.1 ws } 338 1.1 ws } 339 1.1 ws } 340 1.1 ws 341 1.9 ws static void 342 1.29 christos dofsizes(int fd, struct fs *super, const char *name) 343 1.1 ws { 344 1.1 ws ino_t inode, maxino; 345 1.18 fvdl union dinode *dp; 346 1.1 ws daddr_t sz, ksz; 347 1.1 ws struct fsizes *fp, **fsp; 348 1.12 lukem int i; 349 1.1 ws 350 1.1 ws maxino = super->fs_ncg * super->fs_ipg - 1; 351 1.1 ws #ifdef COMPAT 352 1.29 christos if (!(fsizes = malloc(sizeof(*fsizes)))) 353 1.29 christos err(1, "alloc fsize structure"); 354 1.1 ws #endif /* COMPAT */ 355 1.1 ws for (inode = 0; inode < maxino; inode++) { 356 1.1 ws errno = 0; 357 1.18 fvdl if ((dp = get_inode(fd, super, inode)) 358 1.1 ws #ifdef COMPAT 359 1.18 fvdl && ((DIP(super, dp, mode) & IFMT) == IFREG 360 1.18 fvdl || (DIP(dp, mode) & IFMT) == IFDIR) 361 1.1 ws #else /* COMPAT */ 362 1.18 fvdl && !isfree(super, dp) 363 1.1 ws #endif /* COMPAT */ 364 1.1 ws ) { 365 1.18 fvdl sz = estimate ? virtualblocks(super, dp) : 366 1.18 fvdl actualblocks(super, dp); 367 1.1 ws #ifdef COMPAT 368 1.1 ws if (sz >= FSZCNT) { 369 1.1 ws fsizes->fsz_count[FSZCNT-1]++; 370 1.1 ws fsizes->fsz_sz[FSZCNT-1] += sz; 371 1.1 ws } else { 372 1.1 ws fsizes->fsz_count[sz]++; 373 1.1 ws fsizes->fsz_sz[sz] += sz; 374 1.1 ws } 375 1.1 ws #else /* COMPAT */ 376 1.1 ws ksz = SIZE(sz); 377 1.11 lukem for (fsp = &fsizes; (fp = *fsp) != NULL; 378 1.11 lukem fsp = &fp->fsz_next) { 379 1.1 ws if (ksz < fp->fsz_last) 380 1.1 ws break; 381 1.1 ws } 382 1.1 ws if (!fp || ksz < fp->fsz_first) { 383 1.29 christos if (!(fp = malloc(sizeof(*fp)))) 384 1.29 christos err(1, "alloc fsize structure"); 385 1.1 ws fp->fsz_next = *fsp; 386 1.1 ws *fsp = fp; 387 1.1 ws fp->fsz_first = (ksz / FSZCNT) * FSZCNT; 388 1.1 ws fp->fsz_last = fp->fsz_first + FSZCNT; 389 1.1 ws for (i = FSZCNT; --i >= 0;) { 390 1.1 ws fp->fsz_count[i] = 0; 391 1.1 ws fp->fsz_sz[i] = 0; 392 1.1 ws } 393 1.1 ws } 394 1.1 ws fp->fsz_count[ksz % FSZCNT]++; 395 1.1 ws fp->fsz_sz[ksz % FSZCNT] += sz; 396 1.1 ws #endif /* COMPAT */ 397 1.12 lukem } else if (errno) 398 1.12 lukem errx(1, "%s", name); 399 1.1 ws } 400 1.1 ws sz = 0; 401 1.1 ws for (fp = fsizes; fp; fp = fp->fsz_next) { 402 1.1 ws for (i = 0; i < FSZCNT; i++) { 403 1.1 ws if (fp->fsz_count[i]) 404 1.16 mycroft printf("%ld\t%ld\t%lld\n", 405 1.11 lukem (long)(fp->fsz_first + i), 406 1.11 lukem (long)fp->fsz_count[i], 407 1.15 mycroft SIZE(sz += fp->fsz_sz[i])); 408 1.1 ws } 409 1.1 ws } 410 1.1 ws } 411 1.1 ws 412 1.9 ws static void 413 1.29 christos douser(int fd, struct fs *super, const char *name) 414 1.1 ws { 415 1.1 ws ino_t inode, maxino; 416 1.1 ws struct user *usr, *usrs; 417 1.18 fvdl union dinode *dp; 418 1.12 lukem int n; 419 1.1 ws 420 1.1 ws maxino = super->fs_ncg * super->fs_ipg - 1; 421 1.1 ws for (inode = 0; inode < maxino; inode++) { 422 1.1 ws errno = 0; 423 1.18 fvdl if ((dp = get_inode(fd, super, inode)) 424 1.18 fvdl && !isfree(super, dp)) 425 1.18 fvdl uses(DIP(super, dp, uid), 426 1.18 fvdl estimate ? virtualblocks(super, dp) : 427 1.18 fvdl actualblocks(super, dp), DIP(super, dp, atime)); 428 1.12 lukem else if (errno) 429 1.12 lukem errx(1, "%s", name); 430 1.1 ws } 431 1.29 christos if (!(usrs = calloc(nusers, sizeof(*usrs)))) 432 1.12 lukem errx(1, "allocate users"); 433 1.29 christos memmove(usrs, users, nusers * sizeof(*usrs)); 434 1.1 ws sortusers(usrs); 435 1.1 ws for (usr = usrs, n = nusers; --n >= 0 && usr->count; usr++) { 436 1.16 mycroft printf("%5lld", SIZE(usr->space)); 437 1.1 ws if (count) 438 1.15 mycroft printf("\t%5ld", usr->count); 439 1.9 ws printf("\t%-8s", usr->name); 440 1.1 ws if (unused) 441 1.16 mycroft printf("\t%5lld\t%5lld\t%5lld", 442 1.10 mycroft SIZE(usr->spc30), SIZE(usr->spc60), 443 1.10 mycroft SIZE(usr->spc90)); 444 1.1 ws printf("\n"); 445 1.1 ws } 446 1.1 ws free(usrs); 447 1.1 ws } 448 1.1 ws 449 1.9 ws static void 450 1.29 christos donames(int fd, struct fs *super, const char *name) 451 1.1 ws { 452 1.1 ws int c; 453 1.33 christos ino_t inode; 454 1.33 christos #ifdef COMPAT 455 1.33 christos ino_t inode1 = -1; 456 1.33 christos #endif 457 1.1 ws ino_t maxino; 458 1.18 fvdl union dinode *dp; 459 1.1 ws 460 1.1 ws maxino = super->fs_ncg * super->fs_ipg - 1; 461 1.1 ws /* first skip the name of the filesystem */ 462 1.1 ws while ((c = getchar()) != EOF && (c < '0' || c > '9')) 463 1.1 ws while ((c = getchar()) != EOF && c != '\n'); 464 1.9 ws ungetc(c, stdin); 465 1.26 kent while (scanf("%" SCNu64, &inode) == 1) { 466 1.28 lukem if (inode > maxino) { 467 1.9 ws #ifndef COMPAT 468 1.26 kent warnx("invalid inode %" PRIu64, inode); 469 1.9 ws #endif 470 1.1 ws return; 471 1.1 ws } 472 1.9 ws #ifdef COMPAT 473 1.9 ws if (inode < inode1) 474 1.9 ws continue; 475 1.9 ws #endif 476 1.1 ws errno = 0; 477 1.18 fvdl if ((dp = get_inode(fd, super, inode)) 478 1.18 fvdl && !isfree(super, dp)) { 479 1.18 fvdl printf("%s\t", user(DIP(super, dp, uid))->name); 480 1.1 ws /* now skip whitespace */ 481 1.1 ws while ((c = getchar()) == ' ' || c == '\t'); 482 1.1 ws /* and print out the remainder of the input line */ 483 1.1 ws while (c != EOF && c != '\n') { 484 1.1 ws putchar(c); 485 1.1 ws c = getchar(); 486 1.1 ws } 487 1.1 ws putchar('\n'); 488 1.33 christos #ifdef COMPAT 489 1.1 ws inode1 = inode; 490 1.33 christos #endif 491 1.1 ws } else { 492 1.12 lukem if (errno) 493 1.12 lukem errx(1, "%s", name); 494 1.1 ws /* skip this line */ 495 1.29 christos while ((c = getchar()) != EOF && c != '\n') 496 1.29 christos continue; 497 1.1 ws } 498 1.1 ws if (c == EOF) 499 1.1 ws break; 500 1.1 ws } 501 1.1 ws } 502 1.1 ws 503 1.9 ws static void 504 1.29 christos usage(void) 505 1.1 ws { 506 1.29 christos const char *p = getprogname(); 507 1.1 ws #ifdef COMPAT 508 1.29 christos fprintf(stderr, "Usage: %s [-nfcvha] [<filesystem> ...]\n", p); 509 1.1 ws #else /* COMPAT */ 510 1.29 christos fprintf(stderr, "Usage: %s [ -acfhknv ] [<filesystem> ... ]\n", p); 511 1.1 ws #endif /* COMPAT */ 512 1.1 ws exit(1); 513 1.1 ws } 514 1.1 ws 515 1.9 ws /* 516 1.9 ws * Sanity checks for old file systems. 517 1.9 ws * Stolen from <sys/lib/libsa/ufs.c> 518 1.9 ws */ 519 1.9 ws static void 520 1.29 christos ffs_oldfscompat(struct fs *fs) 521 1.9 ws { 522 1.9 ws int i; 523 1.9 ws 524 1.34 martin if (fs->fs_magic == FS_UFS1_MAGIC && 525 1.34 martin fs->fs_old_inodefmt < FS_44INODEFMT) { 526 1.18 fvdl quad_t sizepb = fs->fs_bsize; 527 1.18 fvdl 528 1.30 dholland fs->fs_maxfilesize = fs->fs_bsize * UFS_NDADDR - 1; 529 1.30 dholland for (i = 0; i < UFS_NIADDR; i++) { 530 1.31 dholland sizepb *= FFS_NINDIR(fs); 531 1.18 fvdl fs->fs_maxfilesize += sizepb; 532 1.18 fvdl } 533 1.18 fvdl fs->fs_qbmask = ~fs->fs_bmask; 534 1.18 fvdl fs->fs_qfmask = ~fs->fs_fmask; 535 1.18 fvdl } 536 1.9 ws } 537 1.9 ws 538 1.18 fvdl /* 539 1.18 fvdl * Possible superblock locations ordered from most to least likely. 540 1.18 fvdl */ 541 1.18 fvdl static int sblock_try[] = SBLOCKSEARCH; 542 1.18 fvdl static char superblock[SBLOCKSIZE]; 543 1.18 fvdl 544 1.18 fvdl 545 1.29 christos static void 546 1.29 christos quot(const char *name, const char *mp) 547 1.1 ws { 548 1.18 fvdl int fd, i; 549 1.18 fvdl struct fs *fs; 550 1.22 dsl int sbloc; 551 1.1 ws 552 1.11 lukem get_inode(-1, 0, 0); /* flush cache */ 553 1.1 ws inituser(); 554 1.1 ws initfsizes(); 555 1.18 fvdl if ((fd = open(name, 0)) < 0) { 556 1.13 mrg warn("%s", name); 557 1.1 ws return; 558 1.1 ws } 559 1.18 fvdl 560 1.22 dsl for (i = 0; ; i++) { 561 1.22 dsl sbloc = sblock_try[i]; 562 1.22 dsl if (sbloc == -1) { 563 1.22 dsl warnx("%s: not a BSD filesystem", name); 564 1.22 dsl close(fd); 565 1.22 dsl return; 566 1.22 dsl } 567 1.22 dsl if (pread(fd, superblock, SBLOCKSIZE, sbloc) != SBLOCKSIZE) 568 1.18 fvdl continue; 569 1.22 dsl fs = (struct fs *)superblock; 570 1.22 dsl 571 1.22 dsl if (fs->fs_magic != FS_UFS1_MAGIC && 572 1.35 chs fs->fs_magic != FS_UFS2_MAGIC && 573 1.35 chs fs->fs_magic != FS_UFS2EA_MAGIC) 574 1.18 fvdl continue; 575 1.18 fvdl 576 1.23 dsl if (fs->fs_magic == FS_UFS2_MAGIC 577 1.35 chs || fs->fs_magic == FS_UFS2EA_MAGIC 578 1.23 dsl || fs->fs_old_flags & FS_FLAGS_UPDATED) { 579 1.22 dsl /* Not the main superblock */ 580 1.22 dsl if (fs->fs_sblockloc != sbloc) 581 1.22 dsl continue; 582 1.22 dsl } else { 583 1.22 dsl /* might be a first alt. id blocksize 64k */ 584 1.22 dsl if (sbloc == SBLOCK_UFS2) 585 1.22 dsl continue; 586 1.22 dsl } 587 1.22 dsl 588 1.22 dsl if (fs->fs_bsize > MAXBSIZE || 589 1.29 christos (size_t)fs->fs_bsize < sizeof(struct fs)) 590 1.22 dsl continue; 591 1.22 dsl break; 592 1.1 ws } 593 1.22 dsl 594 1.11 lukem ffs_oldfscompat((struct fs *)superblock); 595 1.9 ws printf("%s:", name); 596 1.1 ws if (mp) 597 1.9 ws printf(" (%s)", mp); 598 1.1 ws putchar('\n'); 599 1.18 fvdl (*func)(fd, fs, name); 600 1.1 ws close(fd); 601 1.1 ws } 602 1.1 ws 603 1.9 ws int 604 1.29 christos main(int argc, char **argv) 605 1.1 ws { 606 1.1 ws char all = 0; 607 1.24 christos struct statvfs *mp; 608 1.1 ws char dev[MNAMELEN + 1]; 609 1.1 ws char *nm; 610 1.1 ws int cnt; 611 1.1 ws 612 1.1 ws func = douser; 613 1.1 ws #ifndef COMPAT 614 1.19 simonb header = getbsize(NULL, &blocksize); 615 1.1 ws #endif 616 1.1 ws while (--argc > 0 && **++argv == '-') { 617 1.1 ws while (*++*argv) { 618 1.1 ws switch (**argv) { 619 1.1 ws case 'n': 620 1.1 ws func = donames; 621 1.1 ws break; 622 1.1 ws case 'c': 623 1.1 ws func = dofsizes; 624 1.1 ws break; 625 1.1 ws case 'a': 626 1.1 ws all = 1; 627 1.1 ws break; 628 1.1 ws case 'f': 629 1.1 ws count = 1; 630 1.1 ws break; 631 1.1 ws case 'h': 632 1.1 ws estimate = 1; 633 1.1 ws break; 634 1.1 ws #ifndef COMPAT 635 1.1 ws case 'k': 636 1.1 ws blocksize = 1024; 637 1.1 ws break; 638 1.1 ws #endif /* COMPAT */ 639 1.1 ws case 'v': 640 1.1 ws unused = 1; 641 1.1 ws break; 642 1.1 ws default: 643 1.1 ws usage(); 644 1.1 ws } 645 1.1 ws } 646 1.1 ws } 647 1.1 ws if (all) { 648 1.9 ws cnt = getmntinfo(&mp, MNT_NOWAIT); 649 1.1 ws for (; --cnt >= 0; mp++) { 650 1.27 christos if (!strncmp(mp->f_fstypename, MOUNT_FFS, 651 1.27 christos sizeof(mp->f_fstypename))) { 652 1.11 lukem if ((nm = 653 1.11 lukem strrchr(mp->f_mntfromname, '/')) != NULL) { 654 1.29 christos snprintf(dev, sizeof(dev), "/dev/r%s", 655 1.29 christos nm + 1); 656 1.1 ws nm = dev; 657 1.1 ws } else 658 1.1 ws nm = mp->f_mntfromname; 659 1.9 ws quot(nm, mp->f_mntonname); 660 1.1 ws } 661 1.1 ws } 662 1.1 ws } 663 1.1 ws while (--argc >= 0) 664 1.9 ws quot(*argv++, 0); 665 1.1 ws return 0; 666 1.1 ws } 667