1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1980, 1986, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #if 0 33 #ifndef lint 34 static const char copyright[] = 35 "@(#) Copyright (c) 1980, 1986, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37 #endif /* not lint */ 38 39 #ifndef lint 40 static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/14/95"; 41 #endif /* not lint */ 42 #endif 43 #include <sys/cdefs.h> 44 #define _WANT_P_OSREL 45 #include <sys/param.h> 46 #include <sys/file.h> 47 #include <sys/mount.h> 48 #include <sys/resource.h> 49 #include <sys/stat.h> 50 #include <sys/sysctl.h> 51 #include <sys/uio.h> 52 #include <sys/disklabel.h> 53 54 #include <ufs/ufs/dinode.h> 55 #include <ufs/ffs/fs.h> 56 57 #include <err.h> 58 #include <errno.h> 59 #include <fstab.h> 60 #include <grp.h> 61 #include <inttypes.h> 62 #include <libufs.h> 63 #include <mntopts.h> 64 #include <paths.h> 65 #include <stdint.h> 66 #include <string.h> 67 #include <time.h> 68 69 #include "fsck.h" 70 71 static int restarts; 72 73 static void usage(void) __dead2; 74 static intmax_t argtoimax(int flag, const char *req, const char *str, int base); 75 static int checkfilesys(char *filesys); 76 static int setup_bkgrdchk(struct statfs *mntp, int sbrdfailed, char **filesys); 77 78 int 79 main(int argc, char *argv[]) 80 { 81 int ch; 82 struct rlimit rlimit; 83 struct itimerval itimerval; 84 int fsret; 85 int ret = 0; 86 87 sync(); 88 skipclean = 1; 89 inoopt = 0; 90 while ((ch = getopt(argc, argv, "b:Bc:CdEfFm:npRrSyZz")) != -1) { 91 switch (ch) { 92 case 'b': 93 skipclean = 0; 94 bflag = argtoimax('b', "number", optarg, 10); 95 printf("Alternate super block location: %jd\n", bflag); 96 break; 97 98 case 'B': 99 bkgrdflag = 1; 100 break; 101 102 case 'c': 103 skipclean = 0; 104 cvtlevel = argtoimax('c', "conversion level", optarg, 105 10); 106 if (cvtlevel < 3) 107 errx(EEXIT, "cannot do level %d conversion", 108 cvtlevel); 109 break; 110 111 case 'd': 112 debug++; 113 break; 114 115 case 'E': 116 Eflag++; 117 break; 118 119 case 'f': 120 skipclean = 0; 121 break; 122 123 case 'F': 124 bkgrdcheck = 1; 125 break; 126 127 case 'm': 128 lfmode = argtoimax('m', "mode", optarg, 8); 129 if (lfmode &~ 07777) 130 errx(EEXIT, "bad mode to -m: %o", lfmode); 131 printf("** lost+found creation mode %o\n", lfmode); 132 break; 133 134 case 'n': 135 nflag++; 136 yflag = 0; 137 break; 138 139 case 'p': 140 preen++; 141 /*FALLTHROUGH*/ 142 143 case 'C': 144 ckclean++; 145 break; 146 147 case 'R': 148 wantrestart = 1; 149 break; 150 case 'r': 151 inoopt++; 152 break; 153 154 case 'S': 155 surrender = 1; 156 break; 157 158 case 'y': 159 yflag++; 160 nflag = 0; 161 break; 162 163 case 'Z': 164 Zflag++; 165 break; 166 167 case 'z': 168 zflag++; 169 break; 170 171 default: 172 usage(); 173 } 174 } 175 argc -= optind; 176 argv += optind; 177 178 if (!argc) 179 usage(); 180 181 if (bkgrdflag && cvtlevel > 0) { 182 pfatal("CANNOT CONVERT A SNAPSHOT\n"); 183 exit(EEXIT); 184 } 185 186 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 187 (void)signal(SIGINT, catch); 188 if (ckclean) 189 (void)signal(SIGQUIT, catchquit); 190 signal(SIGINFO, infohandler); 191 if (bkgrdflag) { 192 signal(SIGALRM, alarmhandler); 193 itimerval.it_interval.tv_sec = 5; 194 itimerval.it_interval.tv_usec = 0; 195 itimerval.it_value.tv_sec = 5; 196 itimerval.it_value.tv_usec = 0; 197 setitimer(ITIMER_REAL, &itimerval, NULL); 198 } 199 /* 200 * Push up our allowed memory limit so we can cope 201 * with huge file systems. 202 */ 203 if (getrlimit(RLIMIT_DATA, &rlimit) == 0) { 204 rlimit.rlim_cur = rlimit.rlim_max; 205 (void)setrlimit(RLIMIT_DATA, &rlimit); 206 } 207 while (argc > 0) { 208 if ((fsret = checkfilesys(*argv)) == ERESTART) 209 continue; 210 ret |= fsret; 211 argc--; 212 argv++; 213 } 214 215 if (returntosingle) 216 ret = 2; 217 exit(ret); 218 } 219 220 static intmax_t 221 argtoimax(int flag, const char *req, const char *str, int base) 222 { 223 char *cp; 224 intmax_t ret; 225 226 ret = strtoimax(str, &cp, base); 227 if (cp == str || *cp) 228 errx(EEXIT, "-%c flag requires a %s", flag, req); 229 return (ret); 230 } 231 232 /* 233 * Check the specified file system. 234 */ 235 /* ARGSUSED */ 236 static int 237 checkfilesys(char *filesys) 238 { 239 ufs2_daddr_t n_ffree, n_bfree; 240 struct dups *dp; 241 struct statfs *mntp; 242 intmax_t blks, files; 243 size_t size; 244 int sbreadfailed, ofsmodified; 245 246 fsutilinit(); 247 fsckinit(); 248 249 cdevname = filesys; 250 if (debug && ckclean) 251 pwarn("starting\n"); 252 /* 253 * Make best effort to get the disk name. Check first to see 254 * if it is listed among the mounted file systems. Failing that 255 * check to see if it is listed in /etc/fstab. 256 */ 257 mntp = getmntpoint(filesys); 258 if (mntp != NULL) 259 filesys = mntp->f_mntfromname; 260 else 261 filesys = blockcheck(filesys); 262 /* 263 * If -F flag specified, check to see whether a background check 264 * is possible and needed. If possible and needed, exit with 265 * status zero. Otherwise exit with status non-zero. A non-zero 266 * exit status will cause a foreground check to be run. 267 */ 268 sblock_init(); 269 sbreadfailed = 0; 270 if (openfilesys(filesys) == 0 || readsb() == 0) 271 sbreadfailed = 1; 272 if (bkgrdcheck) { 273 if (sbreadfailed) 274 exit(3); /* Cannot read superblock */ 275 if ((sblock.fs_flags & FS_NEEDSFSCK) == FS_NEEDSFSCK) 276 exit(4); /* Earlier background failed */ 277 if ((sblock.fs_flags & FS_SUJ) == FS_SUJ) { 278 maxino = sblock.fs_ncg * sblock.fs_ipg; 279 maxfsblock = sblock.fs_size; 280 bufinit(); 281 preen = 1; 282 if (suj_check(filesys) == 0) 283 exit(4); /* Journal good, run it now */ 284 } 285 if ((sblock.fs_flags & FS_DOSOFTDEP) == 0) 286 exit(5); /* Not running soft updates */ 287 size = MIBSIZE; 288 if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0) 289 exit(6); /* Lacks kernel support */ 290 if ((mntp == NULL && sblock.fs_clean == 1) || 291 (mntp != NULL && (sblock.fs_flags & FS_UNCLEAN) == 0)) 292 exit(7); /* Filesystem clean, report it now */ 293 exit(0); 294 } 295 if (ckclean && skipclean) { 296 /* 297 * If file system is gjournaled, check it here. 298 */ 299 if (sbreadfailed) 300 exit(3); /* Cannot read superblock */ 301 if (bkgrdflag == 0 && 302 (nflag || (fswritefd = open(filesys, O_WRONLY)) < 0)) { 303 fswritefd = -1; 304 if (preen) 305 pfatal("NO WRITE ACCESS"); 306 printf(" (NO WRITE)"); 307 } 308 if ((sblock.fs_flags & FS_GJOURNAL) != 0) { 309 if (sblock.fs_clean == 1) { 310 pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); 311 exit(0); 312 } 313 if ((sblock.fs_flags & 314 (FS_UNCLEAN | FS_NEEDSFSCK)) == 0) { 315 bufinit(); 316 gjournal_check(filesys); 317 if (chkdoreload(mntp, pwarn) == 0) 318 exit(0); 319 exit(4); 320 } else { 321 pfatal("FULL FSCK NEEDED, CANNOT RUN FAST " 322 "FSCK\n"); 323 } 324 } 325 close(fswritefd); 326 fswritefd = -1; 327 } 328 if (bkgrdflag) { 329 switch (setup_bkgrdchk(mntp, sbreadfailed, &filesys)) { 330 case -1: /* filesystem clean */ 331 goto clean; 332 case 0: /* cannot do background, give up */ 333 exit(EEXIT); 334 case 1: /* doing background check, preen rules apply */ 335 preen = 1; 336 break; 337 } 338 } 339 340 switch (setup(filesys)) { 341 case 0: 342 if (preen) 343 pfatal("CAN'T CHECK FILE SYSTEM."); 344 return (EEXIT); 345 case -1: 346 clean: 347 pwarn("clean, %ld free ", (long)(sblock.fs_cstotal.cs_nffree + 348 sblock.fs_frag * sblock.fs_cstotal.cs_nbfree)); 349 printf("(%jd frags, %jd blocks, %.1f%% fragmentation)\n", 350 (intmax_t)sblock.fs_cstotal.cs_nffree, 351 (intmax_t)sblock.fs_cstotal.cs_nbfree, 352 sblock.fs_cstotal.cs_nffree * 100.0 / sblock.fs_dsize); 353 return (0); 354 } 355 /* 356 * Determine if we can and should do journal recovery. 357 */ 358 if (bkgrdflag == 0 && (sblock.fs_flags & FS_SUJ) == FS_SUJ) { 359 if ((sblock.fs_flags & FS_NEEDSFSCK) != FS_NEEDSFSCK && 360 skipclean) { 361 sujrecovery = 1; 362 if (suj_check(filesys) == 0) { 363 pwarn("\n**** FILE SYSTEM MARKED CLEAN ****\n"); 364 if (chkdoreload(mntp, pwarn) == 0) 365 exit(0); 366 exit(4); 367 } 368 sujrecovery = 0; 369 pwarn("Skipping journal, " 370 "falling through to full fsck\n"); 371 } 372 if (fswritefd != -1) { 373 /* 374 * Write the superblock so we don't try to recover the 375 * journal on another pass. If this is the only change 376 * to the filesystem, we do not want it to be called 377 * out as modified. 378 */ 379 sblock.fs_mtime = time(NULL); 380 sbdirty(); 381 ofsmodified = fsmodified; 382 flush(fswritefd, &sblk); 383 fsmodified = ofsmodified; 384 } 385 } 386 /* 387 * If the filesystem was run on an old kernel that did not 388 * support check hashes, clear the check-hash flags so that 389 * we do not try to verify them. 390 */ 391 if ((sblock.fs_flags & FS_METACKHASH) == 0) 392 sblock.fs_metackhash = 0; 393 /* 394 * If we are running on a kernel that can provide check hashes 395 * that are not yet enabled for the filesystem and we are 396 * running manually without the -y flag, offer to add any 397 * supported check hashes that are not already enabled. 398 */ 399 ckhashadd = 0; 400 if (preen == 0 && yflag == 0 && sblock.fs_magic != FS_UFS1_MAGIC && 401 fswritefd != -1 && getosreldate() >= P_OSREL_CK_CYLGRP) { 402 if ((sblock.fs_metackhash & CK_CYLGRP) == 0 && 403 reply("ADD CYLINDER GROUP CHECK-HASH PROTECTION") != 0) { 404 ckhashadd |= CK_CYLGRP; 405 sblock.fs_metackhash |= CK_CYLGRP; 406 } 407 if ((sblock.fs_metackhash & CK_SUPERBLOCK) == 0 && 408 getosreldate() >= P_OSREL_CK_SUPERBLOCK && 409 reply("ADD SUPERBLOCK CHECK-HASH PROTECTION") != 0) { 410 ckhashadd |= CK_SUPERBLOCK; 411 sblock.fs_metackhash |= CK_SUPERBLOCK; 412 } 413 if ((sblock.fs_metackhash & CK_INODE) == 0 && 414 getosreldate() >= P_OSREL_CK_INODE && 415 reply("ADD INODE CHECK-HASH PROTECTION") != 0) { 416 ckhashadd |= CK_INODE; 417 sblock.fs_metackhash |= CK_INODE; 418 } 419 #ifdef notyet 420 if ((sblock.fs_metackhash & CK_INDIR) == 0 && 421 getosreldate() >= P_OSREL_CK_INDIR && 422 reply("ADD INDIRECT BLOCK CHECK-HASH PROTECTION") != 0) { 423 ckhashadd |= CK_INDIR; 424 sblock.fs_metackhash |= CK_INDIR; 425 } 426 if ((sblock.fs_metackhash & CK_DIR) == 0 && 427 getosreldate() >= P_OSREL_CK_DIR && 428 reply("ADD DIRECTORY CHECK-HASH PROTECTION") != 0) { 429 ckhashadd |= CK_DIR; 430 sblock.fs_metackhash |= CK_DIR; 431 } 432 #endif /* notyet */ 433 if (ckhashadd != 0) { 434 sblock.fs_flags |= FS_METACKHASH; 435 sbdirty(); 436 } 437 } 438 /* 439 * Cleared if any questions answered no. Used to decide if 440 * the superblock should be marked clean. 441 */ 442 resolved = 1; 443 /* 444 * 1: scan inodes tallying blocks used 445 */ 446 if (preen == 0 || debug) { 447 printf("** Last Mounted on %s\n", sblock.fs_fsmnt); 448 if (mntp != NULL && mntp->f_flags & MNT_ROOTFS) 449 printf("** Root file system\n"); 450 printf("** Phase 1 - Check Blocks and Sizes\n"); 451 } 452 clock_gettime(CLOCK_REALTIME_PRECISE, &startprog); 453 pass1(); 454 IOstats("Pass1"); 455 456 /* 457 * 1b: locate first references to duplicates, if any 458 */ 459 if (duplist) { 460 if (preen || usedsoftdep) 461 pfatal("INTERNAL ERROR: DUPS WITH %s%s%s", 462 preen ? "-p" : "", 463 (preen && usedsoftdep) ? " AND " : "", 464 usedsoftdep ? "SOFTUPDATES" : ""); 465 if (preen == 0 || debug) 466 printf("** Phase 1b - Rescan For More DUPS\n"); 467 pass1b(); 468 IOstats("Pass1b"); 469 } 470 471 /* 472 * 2: traverse directories from root to mark all connected directories 473 */ 474 if (preen == 0 || debug) 475 printf("** Phase 2 - Check Pathnames\n"); 476 pass2(); 477 IOstats("Pass2"); 478 479 /* 480 * 3: scan inodes looking for disconnected directories 481 */ 482 if (preen == 0 || debug) 483 printf("** Phase 3 - Check Connectivity\n"); 484 pass3(); 485 IOstats("Pass3"); 486 487 /* 488 * 4: scan inodes looking for disconnected files; check reference counts 489 */ 490 if (preen == 0 || debug) 491 printf("** Phase 4 - Check Reference Counts\n"); 492 pass4(); 493 IOstats("Pass4"); 494 495 /* 496 * 5: check and repair resource counts in cylinder groups 497 */ 498 if (preen == 0 || debug) 499 printf("** Phase 5 - Check Cyl groups\n"); 500 snapflush(std_checkblkavail); 501 if (cgheader_corrupt) { 502 printf("PHASE 5 SKIPPED DUE TO CORRUPT CYLINDER GROUP " 503 "HEADER(S)\n\n"); 504 } else { 505 pass5(); 506 IOstats("Pass5"); 507 } 508 509 /* 510 * print out summary statistics 511 */ 512 n_ffree = sblock.fs_cstotal.cs_nffree; 513 n_bfree = sblock.fs_cstotal.cs_nbfree; 514 files = maxino - UFS_ROOTINO - sblock.fs_cstotal.cs_nifree - n_files; 515 blks = n_blks + 516 sblock.fs_ncg * (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); 517 blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); 518 blks += howmany(sblock.fs_cssize, sblock.fs_fsize); 519 blks = maxfsblock - (n_ffree + sblock.fs_frag * n_bfree) - blks; 520 if (bkgrdflag && (files > 0 || blks > 0)) { 521 countdirs = sblock.fs_cstotal.cs_ndir - countdirs; 522 pwarn("Reclaimed: %ld directories, %jd files, %jd fragments\n", 523 countdirs, files - countdirs, blks); 524 } 525 pwarn("%ld files, %jd used, %ju free ", 526 (long)n_files, (intmax_t)n_blks, 527 (uintmax_t)n_ffree + sblock.fs_frag * n_bfree); 528 printf("(%ju frags, %ju blocks, %.1f%% fragmentation)\n", 529 (uintmax_t)n_ffree, (uintmax_t)n_bfree, 530 n_ffree * 100.0 / sblock.fs_dsize); 531 if (debug) { 532 if (files < 0) 533 printf("%jd inodes missing\n", -files); 534 if (blks < 0) 535 printf("%jd blocks missing\n", -blks); 536 if (duplist != NULL) { 537 printf("The following duplicate blocks remain:"); 538 for (dp = duplist; dp; dp = dp->next) 539 printf(" %jd,", (intmax_t)dp->dup); 540 printf("\n"); 541 } 542 } 543 duplist = (struct dups *)0; 544 muldup = (struct dups *)0; 545 inocleanup(); 546 if (fsmodified) { 547 sblock.fs_time = time(NULL); 548 sbdirty(); 549 } 550 if (cvtlevel && (sblk.b_flags & B_DIRTY) != 0) { 551 /* 552 * Write out the duplicate super blocks 553 */ 554 if (sbput(fswritefd, &sblock, sblock.fs_ncg) == 0) 555 fsmodified = 1; 556 } 557 if (rerun) 558 resolved = 0; 559 560 /* 561 * Check to see if the file system is mounted read-write. 562 */ 563 if (bkgrdflag == 0 && mntp != NULL && (mntp->f_flags & MNT_RDONLY) == 0) 564 resolved = 0; 565 ckfini(resolved); 566 567 if (fsmodified && !preen) 568 printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); 569 if (rerun) { 570 if (wantrestart && (restarts++ < 10) && 571 (preen || reply("RESTART"))) 572 return (ERESTART); 573 printf("\n***** PLEASE RERUN FSCK *****\n"); 574 } 575 if (chkdoreload(mntp, pwarn) != 0) { 576 if (!fsmodified) 577 return (0); 578 if (!preen) 579 printf("\n***** REBOOT NOW *****\n"); 580 sync(); 581 return (4); 582 } 583 return (rerun ? ERERUN : 0); 584 } 585 586 /* 587 * If we are to do a background check: 588 * Get the mount point information of the file system 589 * If already clean, return -1 590 * Check that kernel supports background fsck 591 * Find or create the snapshot directory 592 * Create the snapshot file 593 * Open snapshot 594 * If anything fails print reason and return 0 which exits 595 */ 596 static int 597 setup_bkgrdchk(struct statfs *mntp, int sbreadfailed, char **filesys) 598 { 599 struct stat snapdir; 600 struct group *grp; 601 struct iovec *iov; 602 char errmsg[255]; 603 int iovlen; 604 size_t size; 605 606 /* Get the mount point information of the file system */ 607 if (mntp == NULL) { 608 pwarn("NOT MOUNTED, CANNOT RUN IN BACKGROUND\n"); 609 return (0); 610 } 611 if ((mntp->f_flags & MNT_RDONLY) != 0) { 612 pwarn("MOUNTED READ-ONLY, CANNOT RUN IN BACKGROUND\n"); 613 return (0); 614 } 615 if ((mntp->f_flags & MNT_SOFTDEP) == 0) { 616 pwarn("NOT USING SOFT UPDATES, CANNOT RUN IN BACKGROUND\n"); 617 return (0); 618 } 619 if (sbreadfailed) { 620 pwarn("SUPERBLOCK READ FAILED, CANNOT RUN IN BACKGROUND\n"); 621 return (0); 622 } 623 if ((sblock.fs_flags & FS_NEEDSFSCK) != 0) { 624 pwarn("FULL FSCK NEEDED, CANNOT RUN IN BACKGROUND\n"); 625 return (0); 626 } 627 if (skipclean && ckclean && 628 (sblock.fs_flags & (FS_UNCLEAN|FS_NEEDSFSCK)) == 0) { 629 /* 630 * file system is clean; 631 * skip snapshot and report it clean 632 */ 633 pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); 634 return (-1); 635 } 636 /* Check that kernel supports background fsck */ 637 size = MIBSIZE; 638 if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0|| 639 sysctlnametomib("vfs.ffs.adjblkcnt", adjblkcnt, &size) < 0|| 640 sysctlnametomib("vfs.ffs.setsize", setsize, &size) < 0 || 641 sysctlnametomib("vfs.ffs.freefiles", freefiles, &size) < 0|| 642 sysctlnametomib("vfs.ffs.freedirs", freedirs, &size) < 0 || 643 sysctlnametomib("vfs.ffs.freeblks", freeblks, &size) < 0) { 644 pwarn("KERNEL LACKS BACKGROUND FSCK SUPPORT\n"); 645 return (0); 646 } 647 /* 648 * When kernel lacks runtime bgfsck superblock summary 649 * adjustment functionality, it does not mean we can not 650 * continue, as old kernels will recompute the summary at 651 * mount time. However, it will be an unexpected softupdates 652 * inconsistency if it turns out that the summary is still 653 * incorrect. Set a flag so subsequent operation can know this. 654 */ 655 bkgrdsumadj = 1; 656 if (sysctlnametomib("vfs.ffs.adjndir", adjndir, &size) < 0 || 657 sysctlnametomib("vfs.ffs.adjnbfree", adjnbfree, &size) < 0 || 658 sysctlnametomib("vfs.ffs.adjnifree", adjnifree, &size) < 0 || 659 sysctlnametomib("vfs.ffs.adjnffree", adjnffree, &size) < 0 || 660 sysctlnametomib("vfs.ffs.adjnumclusters", adjnumclusters, 661 &size) < 0) { 662 bkgrdsumadj = 0; 663 pwarn("KERNEL LACKS RUNTIME SUPERBLOCK SUMMARY ADJUSTMENT " 664 "SUPPORT\n"); 665 } 666 /* Find or create the snapshot directory */ 667 snprintf(snapname, sizeof snapname, "%s/.snap", 668 mntp->f_mntonname); 669 if (stat(snapname, &snapdir) < 0) { 670 if (errno != ENOENT) { 671 pwarn("CANNOT FIND SNAPSHOT DIRECTORY %s: %s, CANNOT " 672 "RUN IN BACKGROUND\n", snapname, strerror(errno)); 673 return (0); 674 } 675 if ((grp = getgrnam("operator")) == NULL || 676 mkdir(snapname, 0770) < 0 || 677 chown(snapname, -1, grp->gr_gid) < 0 || 678 chmod(snapname, 0770) < 0) { 679 pwarn("CANNOT CREATE SNAPSHOT DIRECTORY %s: %s, " 680 "CANNOT RUN IN BACKGROUND\n", snapname, 681 strerror(errno)); 682 return (0); 683 } 684 } else if (!S_ISDIR(snapdir.st_mode)) { 685 pwarn("%s IS NOT A DIRECTORY, CANNOT RUN IN BACKGROUND\n", 686 snapname); 687 return (0); 688 } 689 /* Create the snapshot file */ 690 iov = NULL; 691 iovlen = 0; 692 errmsg[0] = '\0'; 693 snprintf(snapname, sizeof snapname, "%s/.snap/fsck_snapshot", 694 mntp->f_mntonname); 695 build_iovec(&iov, &iovlen, "fstype", "ffs", 4); 696 build_iovec(&iov, &iovlen, "from", snapname, (size_t)-1); 697 build_iovec(&iov, &iovlen, "fspath", mntp->f_mntonname, (size_t)-1); 698 build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 699 build_iovec(&iov, &iovlen, "update", NULL, 0); 700 build_iovec(&iov, &iovlen, "snapshot", NULL, 0); 701 /* Create snapshot, removing old snapshot if it exists */ 702 while (nmount(iov, iovlen, mntp->f_flags) < 0) { 703 if (errno == EEXIST && unlink(snapname) == 0) 704 continue; 705 pwarn("CANNOT CREATE SNAPSHOT %s: %s %s\n", snapname, 706 strerror(errno), errmsg); 707 return (0); 708 } 709 /* Open snapshot */ 710 if (openfilesys(snapname) == 0) { 711 unlink(snapname); 712 pwarn("CANNOT OPEN SNAPSHOT %s: %s, CANNOT RUN IN " 713 "BACKGROUND\n", snapname, strerror(errno)); 714 return (0); 715 } 716 free(sblock.fs_csp); 717 free(sblock.fs_si); 718 if (readsb() == 0) { 719 pwarn("CANNOT READ SNAPSHOT SUPERBLOCK\n"); 720 return (0); 721 } 722 *filesys = snapname; 723 cmd.version = FFS_CMD_VERSION; 724 cmd.handle = fsreadfd; 725 return (1); 726 } 727 728 static void 729 usage(void) 730 { 731 (void) fprintf(stderr, 732 "usage: %s [-BCdEFfnpRrSyZ] [-b block] [-c level] [-m mode] filesystem ...\n", 733 getprogname()); 734 exit(1); 735 } 736 737 void 738 infohandler(int sig __unused) 739 { 740 got_siginfo = 1; 741 } 742 743 void 744 alarmhandler(int sig __unused) 745 { 746 got_sigalarm = 1; 747 } 748