1/* 2 * Copyright (c) 2010-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * Copyright (c) 1980, 1986, 1993 25 * The Regents of the University of California. All rights reserved. 26 * 27 * Redistribution and use in source and binary forms, with or without 28 * modification, are permitted provided that the following conditions 29 * are met: 30 * 1. Redistributions of source code must retain the above copyright 31 * notice, this list of conditions and the following disclaimer. 32 * 2. Redistributions in binary form must reproduce the above copyright 33 * notice, this list of conditions and the following disclaimer in the 34 * documentation and/or other materials provided with the distribution. 35 * 3. All advertising materials mentioning features or use of this software 36 * must display the following acknowledgement: 37 * This product includes software developed by the University of 38 * California, Berkeley and its contributors. 39 * 4. Neither the name of the University nor the names of its contributors 40 * may be used to endorse or promote products derived from this software 41 * without specific prior written permission. 42 * 43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53 * SUCH DAMAGE. 54 */ 55 56#include <fstab.h> 57#include <err.h> 58#include <errno.h> 59#include <sys/param.h> 60#include <sys/mount.h> 61#include <sys/stat.h> 62#include <stdarg.h> 63#include <stdio.h> 64#include <ctype.h> 65#include <dirent.h> 66#include <fcntl.h> 67#include <paths.h> 68#include <unistd.h> 69#include <stdlib.h> 70#include <sys/types.h> 71#include <sys/event.h> 72#include <sys/time.h> 73#include <signal.h> 74 75#include <TargetConditionals.h> 76 77#include "fsck.h" 78 79/* Local Static Functions */ 80static int argtoi(int flag, char *req, char *str, int base); 81static void usage(); 82static int startdiskcheck(disk_t* disk); 83 84/* Global Variables */ 85int preen = 0; /* We're checking all fs'es in 'preen' mode */ 86int returntosingle = 0; /* Return a non-zero status to prevent multi-user start up */ 87int hotroot= 0; /* We're checking / (slash or root) */ 88int fscks_running = 0; /* Number of currently running fs checks */ 89int ndisks = 0; /* Total number of disks observed */ 90int debug = 0; /* Output Debugging info */ 91int force_fsck = 0; /* Force an fsck even if the underlying FS is clean */ 92int maximum_running = 0; /* Maximum number of sub-processes we'll allow to be spawned */ 93int quick_check = 0; /* Do a quick check. Quick check returns clean, dirty, or fail */ 94 95/* 96 * The two following globals are mutually exclusive; you cannot assume "yes" and "no." 97 * The last one observed will be the one that is honored. e.g. fsck -fdnyny will result 98 * in assume_yes == 1, and assume_no == 0; 99 */ 100int assume_no = 0; /* If set, assume a "no" response to repair requests */ 101int assume_yes = 0; /* If set, assume a "yes" response to repair requests. */ 102 103disk_t *disklist = NULL; /* Disk struct with embedded list to enum. all disks */ 104part_t *badlist = NULL; /* List of partitions which may have had errors */ 105 106static int argtoi(int flag, char *req, char *str, int base) { 107 char *cp; 108 int ret; 109 110 ret = (int)strtol(str, &cp, base); 111 if (cp == str || *cp) 112 errx(EEXIT, "-%c flag requires a %s", flag, req); 113 return (ret); 114} 115 116static void usage(void) { 117 fprintf(stderr, "fsck usage: fsck [-fdnypq] [-l number]\n"); 118} 119 120#if DEBUG 121void debug_args (void); 122void dump_part (part_t* part); 123void dump_disk (disk_t* disk); 124void dump_fsp (struct fstab *fsp); 125 126void debug_args (void) { 127 if (debug) { 128 printf("debug %d\n", debug); 129 } 130 131 if (force_fsck) { 132 printf("force_fsck %d\n", force_fsck); 133 } 134 135 if (assume_no) { 136 printf("assume_no: %d\n", assume_no); 137 } 138 139 if (assume_yes) { 140 printf("assume_yes: %d\n", assume_yes); 141 } 142 143 if (preen) { 144 printf("preen: %d\n", preen); 145 } 146 147 if (quick_check) { 148 printf("quick check %d\n", quick_check); 149 } 150 151 printf("maximum_running %d\n", maximum_running); 152} 153 154void dump_fsp (struct fstab *fsp) { 155 fprintf (stderr, "**********dumping fstab entry %p**********\n", fsp); 156 fprintf (stderr, "fstab->fs_spec: %s\n", fsp->fs_spec); 157 fprintf (stderr, "fstab->fs_file: %s\n", fsp->fs_file); 158 fprintf (stderr, "fstab->fs_vfstype: %s\n", fsp->fs_vfstype); 159 fprintf (stderr, "fstab->fs_mntops: %s\n", fsp->fs_mntops); 160 fprintf (stderr, "fstab->fs_type: %s\n", fsp->fs_type); 161 fprintf (stderr, "fstab->fs_freq: %d\n", fsp->fs_freq); 162 fprintf (stderr, "fstab->fs_passno: %d\n", fsp->fs_passno); 163 fprintf (stderr, "********** finished dumping fstab entry %p**********\n\n\n", fsp); 164 165} 166 167void dump_disk (disk_t* disk) { 168 part_t *part; 169 fprintf (stderr, "**********dumping disk entry %p**********\n", disk); 170 fprintf (stderr, "disk->name: %s\n", disk->name); 171 fprintf (stderr, "disk->next: %p\n", disk->next); 172 fprintf (stderr, "disk->part: %p\n", disk->part); 173 fprintf (stderr, "disk->pid: %d\n\n", disk->pid); 174 175 part = disk->part; 176 if (part) { 177 fprintf(stderr, "dumping partition entries now... \n"); 178 } 179 while (part) { 180 dump_part (part); 181 part = part->next; 182 } 183 fprintf (stderr, "**********done dumping disk entry %p**********\n\n\n", disk); 184 185} 186 187void dump_part (part_t* part) { 188 fprintf (stderr, "**********dumping partition entry %p**********\n", part); 189 fprintf (stderr, "part->next: %p\n", part->next); 190 fprintf (stderr, "part->name: %s\n", part->name); 191 fprintf (stderr, "part->fsname: %s\n", part->fsname); 192 fprintf (stderr, "part->vfstype: %s\n\n", part->vfstype); 193 fprintf (stderr, "**********done dumping partition entry %p**********\n\n\n", part); 194} 195 196#endif 197 198 199 200int main (int argc, char** argv) { 201 /* for getopt */ 202 extern char *optarg; 203 extern int optind; 204 205 int ch; 206 int ret; 207 208 209 sync(); 210 while ((ch = getopt(argc, argv, "dfpqnNyYl:")) != EOF) { 211 switch (ch) { 212 case 'd': 213 debug++; 214 break; 215 216 case 'l': 217 maximum_running = argtoi('l', "number", optarg, 10); 218 break; 219 220 case 'f': 221 force_fsck++; 222 break; 223 224 case 'N': 225 case 'n': 226 assume_no = 1; 227 assume_yes = 0; 228 break; 229 230 case 'p': 231 preen++; 232 break; 233 234 case 'q': 235 quick_check = 1; 236 break; 237 238 case 'Y': 239 case 'y': 240 assume_yes = 1; 241 assume_no = 0; 242 break; 243 244 default: 245 errx(EEXIT, "%c option?", ch); 246 break; 247 } 248 } 249 argc -= optind; 250 argv += optind; 251 252 /* Install our signal handlers */ 253 if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 254 (void)signal(SIGINT, catchsig); 255 } 256 257 if (preen) { 258 (void)signal(SIGQUIT, catchquit); 259 } 260 261 if (argc) { 262 /* We do not support any extra arguments at this time */ 263 ret = EINVAL; 264 usage(); 265 exit(ret); 266 } 267 268 /* 269 * checkfstab does the bulk of work for fsck. It will scan through the 270 * fstab and iterate through the devices, as needed 271 */ 272 ret = checkfstab(); 273 /* Return a non-zero return status so that we'll stay in single-user */ 274 if (returntosingle) { 275 exit(2); 276 } 277 /* Return the error value obtained from checking all filesystems in checkfstab */ 278 exit(ret); 279 280} 281 282/* 283 * This is now the guts of fsck. 284 * 285 * This function will iterate over all of the elements in the fstab and run 286 * fsck-like binaries on all of the filesystems in question if able. The root filesystem 287 * is checked first, and then non-root filesystems are checked in order. 288 */ 289int checkfstab(void) { 290 int running_status = 0; 291 int ret; 292 293 /* Open the fstab file (or rewind it) */ 294 if (setfsent() == 0) { 295 fprintf(stderr, "Can't open checklist file: %s\n", _PATH_FSTAB); 296 return EEXIT; 297 } 298 299 ret = build_disklist (); 300 /* 301 * If we encountered any errors or if 'preen' was off, 302 * then we must have scanned everything. Either way, return. 303 */ 304 if ((ret) || (preen == 0)) { 305 return ret; 306 } 307 308 if (preen) { 309 /* Otherwise, see if we need to do a cursory fsck against the FS. */ 310 ret = do_diskchecks(); 311 running_status |= ret; 312 } 313 314 315 if (running_status) { 316 part_t *part = NULL; 317 318 if (badlist == NULL) { 319 /* If there were no disk problems, then return the status */ 320 return (running_status); 321 } 322 fprintf(stderr, "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t", 323 badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:"); 324 for (part = badlist; part; part = part->next) { 325 fprintf(stderr, "%s (%s)%s", part->name, part->fsname, part->next ? ", " : "\n"); 326 } 327 return (running_status); 328 } 329 330 (void)endfsent(); 331 return (0); 332 333} 334 335/* 336 * This function builds up the list of disks that fsck will need to 337 * process and check. 338 * 339 * If we're not in 'preen' mode, then we'll go ahead and do the full 340 * check on all of them now. 341 * 342 * If we ARE in 'preen' mode, then we'll just check the root fs, and log 343 * all of the other ones that we encounter by scanning through the fstab 344 * for checking a bit later on. See notes below for checking '/' at boot. 345 */ 346int build_disklist(void) { 347 348 struct fstab *fsp = NULL; 349 int passno = 0; 350 char *name; 351 int retval; 352 int running_status = 0; 353 354 355 /* 356 * We may need to iterate over the elements in the fstab in non-sequential order. 357 * Thus, we take up to two passes to check all fstab fsck-eligible FSes. The first 358 * pass should focus on the root filesystem, which can be inferred from the fsp->fs_passno 359 * field. The library code used to fill in the fsp structure will specify an 360 * fsp->fs_passno == 1 for the root. All other filesystems should get fsp->fs_passno == 2. 361 * (See fstab manpage for more info.) 362 */ 363 for (passno = 1; passno <= 2; passno++) { 364 /* Open or reset the fstab entry */ 365 if (setfsent() == 0) { 366 fprintf(stderr, "Can't open checklist file: %s\n", _PATH_FSTAB); 367 return EEXIT; 368 } 369 /* Iterate through the fs entries returned from fstab */ 370 while ((fsp = getfsent()) != 0) { 371 /* 372 * Determine if the filesystem is worth checking. Ignore it if it 373 * is not checkable. 374 */ 375 if (fs_checkable(fsp) == 0) { 376 continue; 377 } 378 /* 379 * If preen is off, then we will wind up checking everything in order, so 380 * go ahead and just check this item now. 381 * 382 * Otherwise, only work on the root filesystem in the first pass. We can 383 * tell that the fsp represents the root filesystem if fsp->fs_passno == 1. 384 * 385 * NOTE: On Mac OSX, LibInfo, part of Libsystem is in charge of vending us a valid 386 * fstab entry when we're running 'fsck -p' in early boot to ensure the validity of the 387 * boot disk. Since it's before the volume is mounted read-write, getfsent() will probe 388 * the Mach port for directory services. Since it's not up yet, it will determine the 389 * underlying /dev/disk entry for '/' and mechanically construct a fstab entry for / here. 390 * It correctly fills in the passno field below, which will allow us to fork/exec in order 391 * to call fsck_XXX as necessary. 392 * 393 * Once we're booted to multi-user, this block of code shouldn't ever really check anything 394 * unless it's a valid fstab entry because the synthesized fstab entries don't supply a passno 395 * field. Also, they would have to be valid /dev/disk fstab entries as opposed to 396 * UUID or LABEL ones. 397 */ 398 if (preen == 0 || (passno == 1 && fsp->fs_passno == 1)) { 399 /* Take the special device name, and do some cursory checks. */ 400 if ((name = blockcheck(fsp->fs_spec)) != 0) { 401 /* Construct a temporary disk_t for checkfilesys */ 402 disk_t disk; 403 part_t part; 404 405 disk.name = NULL; 406 disk.next = NULL; 407 disk.part = ∂ 408 disk.pid = 0; 409 410 part.next = NULL; 411 part.name = name; 412 part.vfstype = fsp->fs_vfstype; 413 414 /* Run the filesystem check against the filesystem in question */ 415 if ((retval = checkfilesys(&disk, 0)) != 0) { 416 return (retval); 417 } 418 } 419 else { 420 fprintf(stderr, "BAD DISK NAME %s\n", fsp->fs_spec); 421 /* 422 * If we get here, then blockcheck failed (returned NULL). 423 * Presumably, we couldn't stat the disk device. In this case, 424 * just bail out because we couldn't even find all of the 425 * entries in the fstab. 426 */ 427 return EEXIT; 428 } 429 } 430 /* 431 * If we get here, then preen must be ON and we're checking a 432 * non-root filesystem. So we must be on the 2nd pass, and 433 * the passno of the element returned from fstab will be > 1. 434 */ 435 else if (passno == 2 && fsp->fs_passno > 1) { 436 /* 437 * If the block device checks tell us the name is bad, mark it in the status 438 * field and continue 439 */ 440 if ((name = blockcheck(fsp->fs_spec)) == NULL) { 441 fprintf(stderr, "BAD DISK NAME %s\n", fsp->fs_spec); 442 running_status |= 8; 443 continue; 444 } 445 /* 446 * Since we haven't actually done anything yet, add this partition 447 * to the list of devices to check later on. 448 */ 449 addpart(name, fsp->fs_file, fsp->fs_vfstype); 450 } 451 } 452 /* If we're not in preen mode, then we scanned everything already. Just bail out */ 453 if (preen == 0) { 454 break; 455 } 456 } 457 458 return running_status; 459 460} 461 462/* 463 * This function only runs if we're operating in 'preen' mode. If so, 464 * then iterate over our list of non-root filesystems and fork/exec 'fsck_XXX' 465 * on them to actually do the checking. Spawn up to 'maximum_running' processes. 466 * If 'maximum_running' was not set, then default to the number of disk devices 467 * that we encounter. 468 */ 469int do_diskchecks(void) { 470 471 int fsckno = 0; 472 int pid = 0; 473 int exitstatus = 0; 474 int retval = 0; 475 int running_status = 0; 476 disk_t *disk = NULL; 477 disk_t *nextdisk = NULL; 478 479 /* 480 * If we were not specified a maximum number of FS's to check at once, 481 * or the max exceeded the number of disks we observed, then clip it to 482 * the maximum number of disks. 483 */ 484 if ((maximum_running == 0) || (maximum_running > ndisks)) { 485 maximum_running = ndisks; 486 } 487 nextdisk = disklist; 488 489 /* Start as many fscks as we will allow */ 490 for (fsckno = 0; fsckno < maximum_running; ++fsckno) { 491 /* 492 * Run the disk check against the disk devices we have seen. 493 * 'fscks_running' is increased for each disk we actually visit. 494 * If we hit an error then sleep for 10 seconds and just try again. 495 */ 496 while ((retval = startdiskcheck(nextdisk)) && fscks_running > 0) { 497 sleep(10); 498 } 499 if (retval) { 500 return (retval); 501 } 502 nextdisk = nextdisk->next; 503 } 504 505 /* 506 * Once we get limited by 'maximum_running' as to the maximum 507 * number of processes we can spawn at a time, wait until one of our 508 * child processes exits before spawning another one. 509 */ 510 while ((pid = wait(&exitstatus)) != -1) { 511 for (disk = disklist; disk; disk = disk->next) { 512 if (disk->pid == pid) { 513 break; 514 } 515 } 516 if (disk == 0) { 517 /* Couldn't find a new disk to check */ 518 printf("Unknown pid %d\n", pid); 519 continue; 520 } 521 /* Check the WIFEXITED macros */ 522 if (WIFEXITED(exitstatus)) { 523 retval = WEXITSTATUS(exitstatus); 524 } 525 else { 526 retval = 0; 527 } 528 if (WIFSIGNALED(exitstatus)) { 529 printf("%s (%s): EXITED WITH SIGNAL %d\n", 530 disk->part->name, disk->part->fsname, 531 WTERMSIG(exitstatus)); 532 retval = 8; 533 } 534 /* If it hit an error, OR in the value into our running total */ 535 if (retval != 0) { 536 part_t *temp_part = badlist; 537 538 /* Add the bad partition to the bad partition list */ 539 running_status |= retval; 540 badlist = disk->part; 541 disk->part = disk->part->next; 542 if (temp_part) { 543 badlist->next = temp_part; 544 } 545 } else { 546 /* Just move to the next partition */ 547 part_t *temp_part = disk->part; 548 disk->part = disk->part->next; 549 destroy_part (temp_part); 550 } 551 /* 552 * Reset the pid to 0 since this partition was checked. 553 * Decrease the number of running processes. Decrease the 554 * number of disks if we finish one off. 555 */ 556 disk->pid = 0; 557 fscks_running--; 558 559 if (disk->part == NULL) { 560 ndisks--; 561 } 562 563 if (nextdisk == NULL) { 564 if (disk->part) { 565 /* Start the next partition up */ 566 while ((retval = startdiskcheck(disk)) && fscks_running > 0) { 567 sleep(10); 568 } 569 if (retval) { 570 return (retval); 571 } 572 } 573 } 574 else if (fscks_running < maximum_running && fscks_running < ndisks) { 575 /* If there's more room to go, then find the next valid disk */ 576 for ( ;; ) { 577 if ((nextdisk = nextdisk->next) == NULL) { 578 nextdisk = disklist; 579 } 580 if (nextdisk->part != NULL && nextdisk->pid == 0) { 581 break; 582 } 583 } 584 585 while ((retval = startdiskcheck(nextdisk)) && fscks_running > 0) { 586 sleep(10); 587 } 588 if (retval) { 589 return (retval); 590 } 591 } 592 } 593 return running_status; 594 595} 596 597/* 598 * fork/exec in order to spawn a process that will eventually 599 * wait4() on the fsck_XXX process. 600 * 601 * Note: The number of forks/execs here is slightly complicated. 602 * We call fork twice, and exec once. The reason we need three total 603 * processes is that the first will continue on as the main line of execution. 604 * This first fork() will create the second process which calls checkfilesys(). 605 * In checkfilesys() we will call fork again, followed by an exec. Observe that 606 * the second process created here will *immediately* call wait4 on the third 607 * process, fsck_XXX. This is so that we can track error dialogs and exit statuses 608 * and tie them to the specific instance of fsck_XXX that created them. Otherwise, 609 * if we just called fork a bunch of times and waited on the first one to finish, 610 * it would be difficult to tell which process exited first, and whether or not the 611 * exit status is meaningful. 612 * 613 * Also note that after we get our result from checkfilesys(), we immediately exit, 614 * so that this process doesn't linger and accidentally continue on. 615 */ 616static 617int startdiskcheck(disk_t* disk) { 618 619 /* 620 * Split this process into the one that will go 621 * call fsck_XX and the one that won't 622 */ 623 disk->pid = fork(); 624 if (disk->pid < 0) { 625 perror("fork"); 626 return (8); 627 } 628 if (disk->pid == 0) { 629 /* 630 * Call checkfilesys. Note the exit() call. Also note that 631 * we pass 1 to checkfilesys since we are a child process 632 */ 633 exit(checkfilesys(disk, 1)); 634 } 635 else { 636 fscks_running++; 637 } 638 return (0); 639} 640 641 642 643 644/* 645 * Call fork/exec in order to spawn instance of fsck_XXX for the filesystem 646 * of the specified vfstype. This will actually spawn the process that does the 647 * checking of the filesystem in question. 648 */ 649int checkfilesys(disk_t *disk, int child) { 650#define ARGC_MAX 4 /* cmd-name, options, device, NULL-termination */ 651 part_t *part = disk->part; 652 const char *argv[ARGC_MAX]; 653 int argc; 654 int error = 0; 655 struct stat buf; 656 pid_t pid; 657 int status = 0; 658 char options[] = "-pdfnyq"; /* constant strings are not on the stack */ 659 char progname[NAME_MAX]; 660 char execname[MAXPATHLEN + 1]; 661 char* filesys = part->name; 662 char* vfstype = part->vfstype; 663 664 if (preen && child) { 665 (void)signal(SIGQUIT, ignore_single_quit); 666 } 667 /* 668 * If there was a vfstype specified, then we can go ahead and fork/exec 669 * the child fsck process if the fsck_XXX binary exists. 670 */ 671 if (vfstype) { 672 int exitstatus; 673 674 bzero(options, sizeof(options)); 675 snprintf(options, sizeof(options), "-%s%s%s%s%s%s", 676 (preen) ? "p" : "", 677 (debug) ? "d" : "", 678 (force_fsck) ? "f" : "", 679 (assume_no) ? "n" : "", 680 (assume_yes) ? "y" : "", 681 (quick_check) ? "q" : "" 682 ); 683 684 argc = 0; 685 snprintf(progname, sizeof(progname), "fsck_%s", vfstype); 686 argv[argc++] = progname; 687 if (strlen(options) > 1) { 688 argv[argc++] = options; 689 } 690 argv[argc++] = filesys; 691 argv[argc] = NULL; 692 693 /* Create the string to the fsck binary */ 694 (void)snprintf(execname, sizeof(execname), "%s/fsck_%s", _PATH_SBIN, vfstype); 695 696 /* Check that the binary exists */ 697 error = stat (execname, &buf); 698 if (error != 0) { 699 fprintf(stderr, "Filesystem cannot be checked \n"); 700 return EEXIT; 701 } 702 703 pid = fork(); 704 switch (pid) { 705 case -1: 706 /* The fork failed. */ 707 fprintf(stderr, "fork failed for %s \n", filesys); 708 if (preen) { 709 fprintf(stderr, "\n%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 710 filesys); 711 exit(EEXIT); 712 } 713 714 status = EEXIT; 715 break; 716 717 case 0: 718 /* The child */ 719 if (preen) { 720 (void)signal(SIGQUIT, ignore_single_quit); 721 } 722 execv(execname, (char * const *)argv); 723 fprintf(stderr, "error attempting to exec %s\n", execname); 724 _exit(8); 725 break; 726 727 default: 728 /* The parent; child is process "pid" */ 729 waitpid(pid, &exitstatus, 0); 730 if (WIFEXITED(exitstatus)) { 731 status = WEXITSTATUS(exitstatus); 732 } 733 else { 734 status = 0; 735 } 736 if (WIFSIGNALED(exitstatus)) { 737 printf("%s (%s) EXITED WITH SIGNAL %d\n", filesys, vfstype, WTERMSIG(exitstatus)); 738 status = 8; 739 } 740 break; 741 } 742 743 return status; 744 } 745 else { 746 fprintf(stderr, "Filesystem cannot be checked \n"); 747 return EEXIT; 748 } 749} 750 751/* 752 * When preening, allow a single quit to signal 753 * a special exit after filesystem checks complete 754 * so that reboot sequence may be interrupted. 755 */ 756void catchquit(int sig) { 757 extern int returntosingle; 758 759 printf("returning to single-user after filesystem check\n"); 760 returntosingle = 1; 761 (void)signal(SIGQUIT, SIG_DFL); 762} 763 764/* Quit if we catch a signal here. Emit 12 */ 765void catchsig(int sig) { 766 exit (12); 767} 768 769 770/* 771 * Determine whether a filesystem should be checked. 772 * 773 * Zero indicates that no check should be performed. 774 */ 775int fs_checkable(struct fstab *fsp) { 776 777 /* 778 * HFS, MSDOS, exfat, and UDF are allowed for now. 779 */ 780 if (strcmp(fsp->fs_vfstype, "hfs") && 781 strcmp(fsp->fs_vfstype, "msdos") && 782 strcmp(fsp->fs_vfstype, "exfat") && 783 strcmp(fsp->fs_vfstype, "udf")) { 784 return 0; 785 } 786 787 /* if not RW and not RO (SW or XX?), ignore it */ 788 if ((strcmp(fsp->fs_type, FSTAB_RW) && strcmp(fsp->fs_type, FSTAB_RO)) || 789 fsp->fs_passno == 0) { 790 return 0; 791 } 792 793#define DISKARB_LABEL "LABEL=" 794#define DISKARB_UUID "UUID=" 795 /* If LABEL or UUID specified, ignore it */ 796 if ((strncmp(fsp->fs_spec, DISKARB_LABEL, strlen(DISKARB_LABEL)) == 0) 797 || (strncmp(fsp->fs_spec, DISKARB_UUID, strlen(DISKARB_UUID)) == 0)) { 798 return 0; 799 } 800 801 /* Otherwise, it looks fine. Go ahead and check! */ 802 return 1; 803} 804 805/* 806 * Do some cursory checks on the pathname provided to ensure that it's really a block 807 * device. If it is, then generate the raw device name and vend it out. 808 */ 809char *blockcheck (char *origname) { 810 struct stat stslash; 811 struct stat stblock; 812 struct stat stchar; 813 814 char *newname; 815 char *raw; 816 int retried = 0; 817 int error = 0; 818 819#if TARGET_OS_EMBEDDED 820 /* Variables for setting up the kqueue listener*/ 821#define TIMEOUT_SEC 30l 822 struct kevent kev; 823 struct kevent results; 824 struct timespec ts; 825 int slashdev_fd; 826 int kq = -1; 827 int ct; 828 time_t end; 829 time_t now; 830#endif 831 832 hotroot = 0; 833 /* Try to get device info for '/' */ 834 if (stat("/", &stslash) < 0) { 835 perror("/"); 836 /* If we can't get any info on root, then bail out */ 837 printf("Can't stat root\n"); 838 return (origname); 839 } 840 newname = origname; 841 842retry: 843 /* Poke the block device argument */ 844 error = stat(newname, &stblock); 845 if (error < 0) { 846#if TARGET_OS_EMBEDDED 847 /* 848 * If the device node is not present, set up 849 * a kqueue and wait for up to 30 seconds for it to be 850 * published. 851 */ 852 kq = kqueue(); 853 if (kq < 0) { 854 printf("kqueue: could not create kqueue: %d\n", errno); 855 printf("Can't stat %s\n", newname); 856 return NULL; 857 } 858 slashdev_fd = open(_PATH_DEV, O_RDONLY); 859 860 EV_SET(&kev, slashdev_fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_WRITE, 0, NULL); 861 ct = kevent(kq, &kev, 1, NULL, 0, NULL); 862 if (ct != 0) { 863 printf("kevent() failed to register: %d\n", errno); 864 printf("Can't stat %s\n", newname); 865 /* If we can't register the kqueue, bail out */ 866 close (kq); 867 kq = -1; 868 return NULL; 869 } 870 now = time(NULL); 871 end = now + TIMEOUT_SEC; 872 873 ts.tv_nsec = 0; 874 while ((now = time(NULL)) < end) { 875 ts.tv_sec = end - now; 876 ct = kevent(kq, NULL, 0, &results, 1, &ts); 877 if (results.flags & EV_ERROR) { 878 /* If we register any errors, bail out */ 879 printf("kevent: registered errors.\n"); 880 error = -1; 881 close (kq); 882 kq = -1; 883 break; 884 } 885 error = stat (newname, &stblock); 886 if (error == 0) { 887 /* found the item. continue on */ 888 if (kq >= 0) { 889 close (kq); 890 } 891 break; 892 } 893 } 894 if (error != 0) { 895 /* Time out. bail out */ 896 if (kq >= 0) { 897 close(kq); 898 } 899 printf("fsck timed out. Can't stat %s\n", newname); 900 return NULL; 901 } 902 903#else 904 perror(newname); 905 printf("Can't stat %s\n", newname); 906 return (NULL); 907#endif 908 } 909 910 if ((stblock.st_mode & S_IFMT) == S_IFBLK) { 911 /* 912 * If the block device we're checking is the same as '/' then 913 * update hotroot global for debugging. 914 */ 915 if (stslash.st_dev == stblock.st_rdev) { 916 hotroot++; 917 } 918 raw = rawname(newname); 919 if (stat(raw, &stchar) < 0) { 920 perror(raw); 921 printf("Can't stat %s\n", raw); 922 return (origname); 923 } 924 if ((stchar.st_mode & S_IFMT) == S_IFCHR) { 925 return (raw); 926 } else { 927 printf("%s is not a character device\n", raw); 928 return (origname); 929 } 930 } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) { 931 newname = unrawname(newname); 932 retried++; 933 goto retry; 934 } 935 /* 936 * Not a block or character device, return NULL and 937 * let the user decide what to do. 938 */ 939 return (NULL); 940} 941 942 943/* 944 * Generate a raw disk device pathname from a normal one. 945 * 946 * For input /dev/disk1s2, generate /dev/rdisk1s2 947 */ 948char *rawname(char *name) { 949 static char rawbuf[32]; 950 char *dp; 951 952 /* 953 * Search for the last '/' in the pathname. 954 * If it's not there, then bail out 955 */ 956 if ((dp = strrchr(name, '/')) == 0) { 957 return (0); 958 } 959 /* 960 * Insert a NULL in the place of the final '/' so that we can 961 * copy everything BEFORE that last '/' into a separate buffer. 962 */ 963 *dp = 0; 964 (void)strlcpy(rawbuf, name, sizeof(rawbuf)); 965 *dp = '/'; 966 /* Now add an /r to our buffer, then copy everything after the final / */ 967 (void)strlcat(rawbuf, "/r", sizeof(rawbuf)); 968 (void)strlcat(rawbuf, &dp[1], sizeof(rawbuf)); 969 return (rawbuf); 970} 971 972/* 973 * Generate a regular disk device name from a raw one. 974 * 975 * For input /dev/rdisk1s2, generate /dev/disk1s2 976 */ 977char *unrawname(char *name) { 978 char *dp; 979 struct stat stb; 980 int length; 981 982 /* Find the last '/' in the pathname */ 983 if ((dp = strrchr(name, '/')) == 0) { 984 return (name); 985 } 986 987 /* Stat the disk device argument */ 988 if (stat(name, &stb) < 0) { 989 return (name); 990 } 991 992 /* If it's not a character device, error out */ 993 if ((stb.st_mode & S_IFMT) != S_IFCHR) { 994 return (name); 995 } 996 997 /* If it's not a real raw name, then error out */ 998 if (dp[1] != 'r') { 999 return (name); 1000 } 1001 length = strlen(&dp[2]); 1002 length++; /* to account for trailing NULL */ 1003 1004 memmove(&dp[1], &dp[2], length); 1005 return (name); 1006} 1007 1008/* 1009 * Given a pathname to a disk device, generate the relevant disk_t for that 1010 * disk device. It is assumed that this function will be called for each item in the 1011 * fstab that needs to get checked. 1012 */ 1013disk_t *finddisk (char *pathname) { 1014 disk_t *disk; 1015 disk_t **dkp; 1016 char *tmp; 1017 size_t len; 1018 1019 /* 1020 * Find the disk name. It is assumed that the disk name ends with the 1021 * first run of digit(s) in the last component of the path. 1022 */ 1023 tmp = strrchr(pathname, '/'); /* Find the last component of the path */ 1024 if (tmp == NULL) { 1025 tmp = pathname; 1026 } 1027 else { 1028 tmp++; 1029 } 1030 for (; *tmp && !isdigit(*tmp); tmp++) { /* Skip non-digits */ 1031 continue; 1032 } 1033 1034 for (; *tmp && isdigit(*tmp); tmp++){ /* Skip to end of consecutive digits */ 1035 continue; 1036 } 1037 1038 len = tmp - pathname; 1039 if (len == 0) { 1040 len = strlen(pathname); 1041 } 1042 1043 /* Iterate through all known disks to see if this item was already seen before */ 1044 for (disk = disklist, dkp = &disklist; disk; dkp = &disk->next, disk = disk->next) { 1045 if ((strncmp(disk->name, pathname, len) == 0) && 1046 (disk->name[len] == 0)) { 1047 return (disk); 1048 } 1049 } 1050 /* If not, then allocate a new structure and add it to the end of the list */ 1051 if ((*dkp = (disk_t*)malloc(sizeof(disk_t))) == NULL) { 1052 fprintf(stderr, "out of memory"); 1053 exit (8); 1054 } 1055 /* Make 'disk' point to the newly allocated structure */ 1056 disk = *dkp; 1057 if ((disk->name = malloc(len + 1)) == NULL) { 1058 fprintf(stderr, "out of memory"); 1059 exit (8); 1060 } 1061 /* copy the name into place */ 1062 (void)strncpy(disk->name, pathname, len); 1063 disk->name[len] = '\0'; 1064 /* Initialize 'part' and 'next' to NULL for now */ 1065 disk->part = NULL; 1066 disk->next = NULL; 1067 disk->pid = 0; 1068 /* Increase total number of disks observed */ 1069 ndisks++; 1070 1071 /* Bubble out either the newly created disk_t or the one we found */ 1072 return (disk); 1073} 1074 1075 1076/* 1077 * Add this partition to the list of devices to check. 1078 */ 1079void addpart(char *name, char *fsname, char *vfstype) { 1080 disk_t *disk; 1081 part_t *part; 1082 part_t **ppt; 1083 1084 /* Find the disk_t that corresponds to our element */ 1085 disk = finddisk(name); 1086 ppt = &(disk->part); 1087 1088 /* 1089 * Now iterate through all of the partitions of that disk. 1090 * If we see our partition name already in there, then it means the entry 1091 * was in the fstab more than once, which is bad. 1092 */ 1093 for (part = disk->part; part; ppt = &part->next, part = part->next) { 1094 if (strcmp(part->name, name) == 0) { 1095 printf("%s in fstab more than once!\n", name); 1096 return; 1097 } 1098 } 1099 1100 /* Hopefully we get here. Allocate a new partition structure for the disk */ 1101 if ((*ppt = (part_t*)malloc(sizeof(part_t))) == NULL) { 1102 fprintf(stderr, "out of memory"); 1103 exit (8); 1104 } 1105 part = *ppt; 1106 if ((part->name = malloc(strlen(name) + 1)) == NULL) { 1107 fprintf(stderr, "out of memory"); 1108 exit (8); 1109 } 1110 1111 /* Add the name & vfs info to the partition struct */ 1112 (void)strcpy(part->name, name); 1113 if ((part->fsname = malloc(strlen(fsname) + 1)) == NULL) { 1114 fprintf(stderr, "out of memory"); 1115 exit (8); 1116 } 1117 (void)strcpy(part->fsname, fsname); 1118 part->next = NULL; 1119 part->vfstype = strdup(vfstype); 1120 if (part->vfstype == NULL) { 1121 fprintf(stderr, "out of memory"); 1122 exit (8); 1123 } 1124} 1125 1126/* 1127 * Free the partition and its fields. 1128 */ 1129void destroy_part (part_t *part) { 1130 if (part->name) { 1131 free (part->name); 1132 } 1133 1134 if (part->fsname) { 1135 free (part->fsname); 1136 } 1137 1138 if (part->vfstype) { 1139 free (part->vfstype); 1140 } 1141 1142 free (part); 1143} 1144 1145 1146/* 1147 * Ignore a single quit signal; wait and flush just in case. 1148 * Used by child processes in preen mode. 1149 */ 1150void 1151ignore_single_quit(int sig) { 1152 1153 sleep(1); 1154 (void)signal(SIGQUIT, SIG_IGN); 1155 (void)signal(SIGQUIT, SIG_DFL); 1156} 1157 1158 1159 1160