check for exit caused by uncaught signal
[unix-history] / usr / src / sbin / fsck / main.c
/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1980 Regents of the University of California.\n\
All rights reserved.\n";
#endif not lint
#ifndef lint
static char sccsid[] = "@(#)main.c 5.10 (Berkeley) %G%";
#endif not lint
#include <sys/param.h>
#include <sys/inode.h>
#include <sys/fs.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fstab.h>
#include <strings.h>
#include <ctype.h>
#include "fsck.h"
char *rawname(), *unrawname(), *blockcheck();
int catch(), catchquit(), voidquit();
int returntosingle;
int (*signal())();
main(argc, argv)
int argc;
char *argv[];
{
struct fstab *fsp;
int pid, passno, anygtr, sumstatus;
char *name;
struct worklist {
int pid; /* pid of child doing the check */
struct worklist *next; /* next in list */
char name[MAXMNTLEN];/* name of file system */
} *listhead = 0, *freelist = 0, *badlist = 0;
register struct worklist *wp, *pwp;
sync();
while (--argc > 0 && **++argv == '-') {
switch (*++*argv) {
case 'p':
preen++;
break;
case 'b':
if (argv[0][1] != '\0') {
bflag = atoi(argv[0]+1);
} else {
bflag = atoi(*++argv);
argc--;
}
printf("Alternate super block location: %d\n", bflag);
break;
case 'c':
cvtflag++;
break;
case 'd':
debug++;
break;
case 'm':
if (!isdigit(argv[1][0]))
errexit("-m flag requires a mode\n");
sscanf(*++argv, "%o", &lfmode);
if (lfmode &~ 07777)
errexit("bad mode to -m: %o\n", lfmode);
argc--;
printf("** lost+found creation mode %o\n", lfmode);
break;
case 'n': /* default no answer flag */
case 'N':
nflag++;
yflag = 0;
break;
case 'y': /* default yes answer flag */
case 'Y':
yflag++;
nflag = 0;
break;
default:
errexit("%c option?\n", **argv);
}
}
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
(void)signal(SIGINT, catch);
if (preen)
(void)signal(SIGQUIT, catchquit);
if (argc) {
while (argc-- > 0) {
hotroot = 0;
checkfilesys(*argv++);
}
exit(0);
}
sumstatus = 0;
passno = 1;
do {
anygtr = 0;
if (setfsent() == 0)
errexit("Can't open checklist file: %s\n", FSTAB);
while ((fsp = getfsent()) != 0) {
if (strcmp(fsp->fs_type, FSTAB_RW) &&
strcmp(fsp->fs_type, FSTAB_RO) &&
strcmp(fsp->fs_type, FSTAB_RQ))
continue;
if (preen == 0 ||
passno == 1 && fsp->fs_passno == passno) {
name = blockcheck(fsp->fs_spec);
if (name != NULL)
checkfilesys(name);
else if (preen)
exit(8);
} else if (fsp->fs_passno > passno) {
anygtr = 1;
} else if (fsp->fs_passno == passno) {
name = blockcheck(fsp->fs_spec);
if (name == NULL) {
pwarn("BAD DISK NAME %s\n",
fsp->fs_spec);
sumstatus |= 8;
continue;
}
pid = fork();
if (pid < 0) {
perror("fork");
exit(8);
}
if (pid == 0) {
(void)signal(SIGQUIT, voidquit);
checkfilesys(name);
exit(0);
} else {
if (freelist == 0) {
wp = (struct worklist *) malloc
(sizeof(struct worklist));
} else {
wp = freelist;
freelist = wp->next;
}
wp->next = listhead;
listhead = wp;
wp->pid = pid;
sprintf(wp->name, "%s (%s)", name,
fsp->fs_file);
}
}
}
if (preen) {
union wait status;
while ((pid = wait(&status)) != -1) {
if (status.w_termsig)
sumstatus |= 8;
else
sumstatus |= status.w_retcode;
pwp = 0;
for (wp = listhead; wp; pwp = wp, wp = wp->next)
if (wp->pid == pid)
break;
if (wp == 0) {
printf("Unknown pid %d\n", pid);
continue;
}
if (pwp == 0)
listhead = wp->next;
else
pwp->next = wp->next;
if (status.w_termsig) {
printf("%s: EXITED WITH SIGNAL %d\n",
wp->name, status.w_termsig);
status.w_retcode = 8;
}
if (status.w_retcode != 0) {
wp->next = badlist;
badlist = wp;
} else {
wp->next = freelist;
freelist = wp;
}
}
}
passno++;
} while (anygtr);
if (sumstatus) {
if (badlist == 0)
exit(8);
printf("THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:");
for (wp = badlist; wp; wp = wp->next)
printf("%s%s", wp->name, wp->next ? ", " : "\n");
exit(8);
}
(void)endfsent();
if (returntosingle)
exit(2);
exit(0);
}
checkfilesys(filesys)
char *filesys;
{
daddr_t n_ffree, n_bfree;
struct dups *dp;
struct zlncnt *zlnp;
devname = filesys;
if (setup(filesys) == 0) {
if (preen)
pfatal("CAN'T CHECK FILE SYSTEM.");
return;
}
/*
* 1: scan inodes tallying blocks used
*/
if (preen == 0) {
printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
if (hotroot)
printf("** Root file system\n");
printf("** Phase 1 - Check Blocks and Sizes\n");
}
pass1();
/*
* 1b: locate first references to duplicates, if any
*/
if (duplist) {
if (preen)
pfatal("INTERNAL ERROR: dups with -p");
printf("** Phase 1b - Rescan For More DUPS\n");
pass1b();
}
/*
* 2: traverse directories from root to mark all connected directories
*/
if (preen == 0)
printf("** Phase 2 - Check Pathnames\n");
pass2();
/*
* 3: scan inodes looking for disconnected directories
*/
if (preen == 0)
printf("** Phase 3 - Check Connectivity\n");
pass3();
/*
* 4: scan inodes looking for disconnected files; check reference counts
*/
if (preen == 0)
printf("** Phase 4 - Check Reference Counts\n");
pass4();
/*
* 5: check and repair resource counts in cylinder groups
*/
if (preen == 0)
printf("** Phase 5 - Check Cyl groups\n");
pass5();
/*
* print out summary statistics
*/
n_ffree = sblock.fs_cstotal.cs_nffree;
n_bfree = sblock.fs_cstotal.cs_nbfree;
pwarn("%d files, %d used, %d free ",
n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree);
printf("(%d frags, %d blocks, %.1f%% fragmentation)\n",
n_ffree, n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize);
if (debug && (n_files -= imax - ROOTINO - sblock.fs_cstotal.cs_nifree))
printf("%d files missing\n", n_files);
if (debug) {
n_blks += sblock.fs_ncg *
(cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
if (n_blks -= fmax - (n_ffree + sblock.fs_frag * n_bfree))
printf("%d blocks missing\n", n_blks);
if (duplist != NULL) {
printf("The following duplicate blocks remain:");
for (dp = duplist; dp; dp = dp->next)
printf(" %d,", dp->dup);
printf("\n");
}
if (zlnhead != NULL) {
printf("The following zero link count inodes remain:");
for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
printf(" %d,", zlnp->zlncnt);
printf("\n");
}
}
zlnhead = (struct zlncnt *)0;
duplist = (struct dups *)0;
if (dfile.mod) {
(void)time(&sblock.fs_time);
sbdirty();
}
ckfini();
free(blockmap);
free(statemap);
free((char *)lncntp);
if (!dfile.mod)
return;
if (!preen) {
printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
if (hotroot)
printf("\n***** REBOOT UNIX *****\n");
}
if (hotroot) {
sync();
exit(4);
}
}
char *
blockcheck(name)
char *name;
{
struct stat stslash, stblock, stchar;
char *raw;
int looped = 0;
hotroot = 0;
if (stat("/", &stslash) < 0){
perror("/");
printf("Can't stat root\n");
return (0);
}
retry:
if (stat(name, &stblock) < 0){
perror(name);
printf("Can't stat %s\n", name);
return (0);
}
if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
if (stslash.st_dev == stblock.st_rdev) {
hotroot++;
return (name);
}
raw = rawname(name);
if (stat(raw, &stchar) < 0){
perror(raw);
printf("Can't stat %s\n", raw);
return (name);
}
if ((stchar.st_mode & S_IFMT) == S_IFCHR)
return (raw);
else {
printf("%s is not a character device\n", raw);
return (name);
}
} else if ((stblock.st_mode & S_IFMT) == S_IFCHR) {
if (looped) {
printf("Can't make sense out of name %s\n", name);
return (0);
}
name = unrawname(name);
looped++;
goto retry;
}
printf("Can't make sense out of name %s\n", name);
return (0);
}
char *
unrawname(cp)
char *cp;
{
char *dp = rindex(cp, '/');
struct stat stb;
if (dp == 0)
return (cp);
if (stat(cp, &stb) < 0)
return (cp);
if ((stb.st_mode&S_IFMT) != S_IFCHR)
return (cp);
if (*(dp+1) != 'r')
return (cp);
(void)strcpy(dp+1, dp+2);
return (cp);
}
char *
rawname(cp)
char *cp;
{
static char rawbuf[32];
char *dp = rindex(cp, '/');
if (dp == 0)
return (0);
*dp = 0;
(void)strcpy(rawbuf, cp);
*dp = '/';
(void)strcat(rawbuf, "/r");
(void)strcat(rawbuf, dp+1);
return (rawbuf);
}