Home | History | Annotate | Line # | Download | only in fsck
preen.c revision 1.11
      1  1.11      cgd /*	$NetBSD: preen.c,v 1.11 1995/03/18 14:55:59 cgd Exp $	*/
      2  1.11      cgd 
      3   1.1      cgd /*
      4   1.6  mycroft  * Copyright (c) 1990, 1993
      5   1.6  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.1      cgd  * 3. All advertising materials mentioning features or use of this software
     16   1.1      cgd  *    must display the following acknowledgement:
     17   1.1      cgd  *	This product includes software developed by the University of
     18   1.1      cgd  *	California, Berkeley and its contributors.
     19   1.1      cgd  * 4. Neither the name of the University nor the names of its contributors
     20   1.1      cgd  *    may be used to endorse or promote products derived from this software
     21   1.1      cgd  *    without specific prior written permission.
     22   1.1      cgd  *
     23   1.1      cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24   1.1      cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25   1.1      cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26   1.1      cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27   1.1      cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28   1.1      cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29   1.1      cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30   1.1      cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31   1.1      cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32   1.1      cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33   1.1      cgd  * SUCH DAMAGE.
     34   1.1      cgd  */
     35   1.1      cgd 
     36   1.1      cgd #ifndef lint
     37  1.11      cgd #if 0
     38  1.11      cgd static char sccsid[] = "@(#)preen.c	8.3 (Berkeley) 12/6/94";
     39  1.11      cgd #else
     40  1.11      cgd static char rcsid[] = "$NetBSD: preen.c,v 1.11 1995/03/18 14:55:59 cgd Exp $";
     41  1.11      cgd #endif
     42   1.1      cgd #endif /* not lint */
     43   1.1      cgd 
     44   1.1      cgd #include <sys/param.h>
     45   1.1      cgd #include <sys/stat.h>
     46   1.1      cgd #include <sys/wait.h>
     47   1.1      cgd #include <fstab.h>
     48   1.1      cgd #include <string.h>
     49   1.1      cgd #include <stdio.h>
     50   1.1      cgd #include <stdlib.h>
     51   1.1      cgd #include <ctype.h>
     52   1.9      cgd #include <unistd.h>
     53   1.1      cgd 
     54   1.1      cgd struct part {
     55   1.1      cgd 	struct	part *next;		/* forward link of partitions on disk */
     56   1.1      cgd 	char	*name;			/* device name */
     57   1.1      cgd 	char	*fsname;		/* mounted filesystem name */
     58   1.1      cgd 	long	auxdata;		/* auxillary data for application */
     59   1.1      cgd } *badlist, **badnext = &badlist;
     60   1.1      cgd 
     61   1.1      cgd struct disk {
     62   1.1      cgd 	char	*name;			/* disk base name */
     63   1.1      cgd 	struct	disk *next;		/* forward link for list of disks */
     64   1.1      cgd 	struct	part *part;		/* head of list of partitions on disk */
     65   1.1      cgd 	int	pid;			/* If != 0, pid of proc working on */
     66   1.1      cgd } *disks;
     67   1.1      cgd 
     68   1.1      cgd int	nrun, ndisks;
     69   1.1      cgd char	hotroot;
     70   1.1      cgd 
     71   1.9      cgd char	*rawname(), *unrawname(), *blockcheck();
     72   1.9      cgd void addpart __P((char *, char *, long));
     73   1.9      cgd int startdisk __P((struct disk *, int (*)() ));
     74   1.9      cgd 
     75   1.9      cgd int
     76   1.1      cgd checkfstab(preen, maxrun, docheck, chkit)
     77   1.1      cgd 	int preen, maxrun;
     78   1.1      cgd 	int (*docheck)(), (*chkit)();
     79   1.1      cgd {
     80   1.1      cgd 	register struct fstab *fsp;
     81   1.1      cgd 	register struct disk *dk, *nextdisk;
     82   1.1      cgd 	register struct part *pt;
     83   1.1      cgd 	int ret, pid, retcode, passno, sumstatus, status;
     84   1.1      cgd 	long auxdata;
     85   1.1      cgd 	char *name;
     86   1.1      cgd 
     87   1.1      cgd 	sumstatus = 0;
     88   1.1      cgd 	for (passno = 1; passno <= 2; passno++) {
     89   1.1      cgd 		if (setfsent() == 0) {
     90   1.1      cgd 			fprintf(stderr, "Can't open checklist file: %s\n",
     91   1.1      cgd 			    _PATH_FSTAB);
     92   1.1      cgd 			return (8);
     93   1.1      cgd 		}
     94   1.1      cgd 		while ((fsp = getfsent()) != 0) {
     95   1.1      cgd 			if ((auxdata = (*docheck)(fsp)) == 0)
     96   1.1      cgd 				continue;
     97   1.1      cgd 			if (preen == 0 || passno == 1 && fsp->fs_passno == 1) {
     98   1.1      cgd 				if (name = blockcheck(fsp->fs_spec)) {
     99   1.1      cgd 					if (sumstatus = (*chkit)(name,
    100   1.1      cgd 					    fsp->fs_file, auxdata, 0))
    101   1.1      cgd 						return (sumstatus);
    102   1.1      cgd 				} else if (preen)
    103   1.1      cgd 					return (8);
    104   1.1      cgd 			} else if (passno == 2 && fsp->fs_passno > 1) {
    105   1.1      cgd 				if ((name = blockcheck(fsp->fs_spec)) == NULL) {
    106   1.1      cgd 					fprintf(stderr, "BAD DISK NAME %s\n",
    107   1.1      cgd 						fsp->fs_spec);
    108   1.1      cgd 					sumstatus |= 8;
    109   1.1      cgd 					continue;
    110   1.1      cgd 				}
    111   1.1      cgd 				addpart(name, fsp->fs_file, auxdata);
    112   1.1      cgd 			}
    113   1.1      cgd 		}
    114   1.1      cgd 		if (preen == 0)
    115   1.1      cgd 			return (0);
    116   1.1      cgd 	}
    117   1.1      cgd 	if (preen) {
    118   1.1      cgd 		if (maxrun == 0)
    119   1.1      cgd 			maxrun = ndisks;
    120   1.1      cgd 		if (maxrun > ndisks)
    121   1.1      cgd 			maxrun = ndisks;
    122   1.1      cgd 		nextdisk = disks;
    123   1.1      cgd 		for (passno = 0; passno < maxrun; ++passno) {
    124   1.1      cgd 			while (ret = startdisk(nextdisk, chkit) && nrun > 0)
    125   1.1      cgd 				sleep(10);
    126   1.1      cgd 			if (ret)
    127   1.1      cgd 				return (ret);
    128   1.1      cgd 			nextdisk = nextdisk->next;
    129   1.1      cgd 		}
    130   1.1      cgd 		while ((pid = wait(&status)) != -1) {
    131   1.1      cgd 			for (dk = disks; dk; dk = dk->next)
    132   1.1      cgd 				if (dk->pid == pid)
    133   1.1      cgd 					break;
    134   1.1      cgd 			if (dk == 0) {
    135   1.1      cgd 				printf("Unknown pid %d\n", pid);
    136   1.1      cgd 				continue;
    137   1.1      cgd 			}
    138   1.1      cgd 			if (WIFEXITED(status))
    139   1.1      cgd 				retcode = WEXITSTATUS(status);
    140   1.1      cgd 			else
    141   1.1      cgd 				retcode = 0;
    142   1.1      cgd 			if (WIFSIGNALED(status)) {
    143   1.1      cgd 				printf("%s (%s): EXITED WITH SIGNAL %d\n",
    144   1.1      cgd 					dk->part->name, dk->part->fsname,
    145   1.1      cgd 					WTERMSIG(status));
    146   1.1      cgd 				retcode = 8;
    147   1.1      cgd 			}
    148   1.1      cgd 			if (retcode != 0) {
    149   1.1      cgd 				sumstatus |= retcode;
    150   1.1      cgd 				*badnext = dk->part;
    151   1.1      cgd 				badnext = &dk->part->next;
    152   1.1      cgd 				dk->part = dk->part->next;
    153   1.1      cgd 				*badnext = NULL;
    154   1.1      cgd 			} else
    155   1.1      cgd 				dk->part = dk->part->next;
    156   1.1      cgd 			dk->pid = 0;
    157   1.1      cgd 			nrun--;
    158   1.1      cgd 			if (dk->part == NULL)
    159   1.1      cgd 				ndisks--;
    160   1.1      cgd 
    161   1.1      cgd 			if (nextdisk == NULL) {
    162   1.1      cgd 				if (dk->part) {
    163   1.1      cgd 					while (ret = startdisk(dk, chkit) &&
    164   1.1      cgd 					    nrun > 0)
    165   1.1      cgd 						sleep(10);
    166   1.1      cgd 					if (ret)
    167   1.1      cgd 						return (ret);
    168   1.1      cgd 				}
    169   1.1      cgd 			} else if (nrun < maxrun && nrun < ndisks) {
    170   1.1      cgd 				for ( ;; ) {
    171   1.1      cgd 					if ((nextdisk = nextdisk->next) == NULL)
    172   1.1      cgd 						nextdisk = disks;
    173   1.1      cgd 					if (nextdisk->part != NULL &&
    174   1.1      cgd 					    nextdisk->pid == 0)
    175   1.1      cgd 						break;
    176   1.1      cgd 				}
    177   1.1      cgd 				while (ret = startdisk(nextdisk, chkit) &&
    178   1.1      cgd 				    nrun > 0)
    179   1.1      cgd 					sleep(10);
    180   1.1      cgd 				if (ret)
    181   1.1      cgd 					return (ret);
    182   1.1      cgd 			}
    183   1.1      cgd 		}
    184   1.1      cgd 	}
    185   1.1      cgd 	if (sumstatus) {
    186   1.1      cgd 		if (badlist == 0)
    187   1.1      cgd 			return (sumstatus);
    188   1.1      cgd 		fprintf(stderr, "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
    189   1.1      cgd 			badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:");
    190   1.1      cgd 		for (pt = badlist; pt; pt = pt->next)
    191   1.1      cgd 			fprintf(stderr, "%s (%s)%s", pt->name, pt->fsname,
    192   1.1      cgd 			    pt->next ? ", " : "\n");
    193   1.1      cgd 		return (sumstatus);
    194   1.1      cgd 	}
    195   1.1      cgd 	(void)endfsent();
    196   1.1      cgd 	return (0);
    197   1.1      cgd }
    198   1.1      cgd 
    199   1.1      cgd struct disk *
    200   1.1      cgd finddisk(name)
    201   1.1      cgd 	char *name;
    202   1.1      cgd {
    203   1.1      cgd 	register struct disk *dk, **dkp;
    204   1.1      cgd 	register char *p;
    205   1.1      cgd 	size_t len;
    206   1.1      cgd 
    207   1.1      cgd 	for (p = name + strlen(name) - 1; p >= name; --p)
    208   1.1      cgd 		if (isdigit(*p)) {
    209   1.1      cgd 			len = p - name + 1;
    210   1.1      cgd 			break;
    211   1.1      cgd 		}
    212   1.1      cgd 	if (p < name)
    213   1.1      cgd 		len = strlen(name);
    214   1.1      cgd 
    215   1.1      cgd 	for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) {
    216   1.1      cgd 		if (strncmp(dk->name, name, len) == 0 &&
    217   1.1      cgd 		    dk->name[len] == 0)
    218   1.1      cgd 			return (dk);
    219   1.1      cgd 	}
    220   1.1      cgd 	if ((*dkp = (struct disk *)malloc(sizeof(struct disk))) == NULL) {
    221   1.1      cgd 		fprintf(stderr, "out of memory");
    222   1.1      cgd 		exit (8);
    223   1.1      cgd 	}
    224   1.1      cgd 	dk = *dkp;
    225   1.1      cgd 	if ((dk->name = malloc(len + 1)) == NULL) {
    226   1.1      cgd 		fprintf(stderr, "out of memory");
    227   1.1      cgd 		exit (8);
    228   1.1      cgd 	}
    229   1.1      cgd 	(void)strncpy(dk->name, name, len);
    230   1.1      cgd 	dk->name[len] = '\0';
    231   1.1      cgd 	dk->part = NULL;
    232   1.1      cgd 	dk->next = NULL;
    233   1.1      cgd 	dk->pid = 0;
    234   1.1      cgd 	ndisks++;
    235   1.1      cgd 	return (dk);
    236   1.1      cgd }
    237   1.1      cgd 
    238   1.9      cgd void
    239   1.1      cgd addpart(name, fsname, auxdata)
    240   1.1      cgd 	char *name, *fsname;
    241   1.1      cgd 	long auxdata;
    242   1.1      cgd {
    243   1.1      cgd 	struct disk *dk = finddisk(name);
    244   1.1      cgd 	register struct part *pt, **ppt = &dk->part;
    245   1.1      cgd 
    246   1.1      cgd 	for (pt = dk->part; pt; ppt = &pt->next, pt = pt->next)
    247   1.1      cgd 		if (strcmp(pt->name, name) == 0) {
    248   1.1      cgd 			printf("%s in fstab more than once!\n", name);
    249   1.1      cgd 			return;
    250   1.1      cgd 		}
    251   1.1      cgd 	if ((*ppt = (struct part *)malloc(sizeof(struct part))) == NULL) {
    252   1.1      cgd 		fprintf(stderr, "out of memory");
    253   1.1      cgd 		exit (8);
    254   1.1      cgd 	}
    255   1.1      cgd 	pt = *ppt;
    256   1.1      cgd 	if ((pt->name = malloc(strlen(name) + 1)) == NULL) {
    257   1.1      cgd 		fprintf(stderr, "out of memory");
    258   1.1      cgd 		exit (8);
    259   1.1      cgd 	}
    260   1.1      cgd 	(void)strcpy(pt->name, name);
    261   1.1      cgd 	if ((pt->fsname = malloc(strlen(fsname) + 1)) == NULL) {
    262   1.1      cgd 		fprintf(stderr, "out of memory");
    263   1.1      cgd 		exit (8);
    264   1.1      cgd 	}
    265   1.1      cgd 	(void)strcpy(pt->fsname, fsname);
    266   1.1      cgd 	pt->next = NULL;
    267   1.1      cgd 	pt->auxdata = auxdata;
    268   1.1      cgd }
    269   1.1      cgd 
    270   1.9      cgd int
    271   1.1      cgd startdisk(dk, checkit)
    272   1.1      cgd 	register struct disk *dk;
    273   1.1      cgd 	int (*checkit)();
    274   1.1      cgd {
    275   1.1      cgd 	register struct part *pt = dk->part;
    276   1.1      cgd 
    277   1.1      cgd 	dk->pid = fork();
    278   1.1      cgd 	if (dk->pid < 0) {
    279   1.1      cgd 		perror("fork");
    280   1.1      cgd 		return (8);
    281   1.1      cgd 	}
    282   1.1      cgd 	if (dk->pid == 0)
    283   1.1      cgd 		exit((*checkit)(pt->name, pt->fsname, pt->auxdata, 1));
    284   1.1      cgd 	nrun++;
    285   1.1      cgd 	return (0);
    286   1.1      cgd }
    287   1.1      cgd 
    288   1.1      cgd char *
    289  1.10  mycroft blockcheck(origname)
    290  1.10  mycroft 	char *origname;
    291   1.1      cgd {
    292   1.1      cgd 	struct stat stslash, stblock, stchar;
    293  1.10  mycroft 	char *newname, *raw;
    294   1.1      cgd 	int retried = 0;
    295   1.1      cgd 
    296   1.1      cgd 	hotroot = 0;
    297   1.1      cgd 	if (stat("/", &stslash) < 0) {
    298   1.1      cgd 		perror("/");
    299   1.1      cgd 		printf("Can't stat root\n");
    300  1.10  mycroft 		return (origname);
    301   1.1      cgd 	}
    302  1.10  mycroft 	newname = origname;
    303   1.1      cgd retry:
    304  1.10  mycroft 	if (stat(newname, &stblock) < 0) {
    305  1.10  mycroft 		perror(newname);
    306  1.10  mycroft 		printf("Can't stat %s\n", newname);
    307  1.10  mycroft 		return (origname);
    308   1.1      cgd 	}
    309   1.8  mycroft 	if (S_ISBLK(stblock.st_mode)) {
    310   1.1      cgd 		if (stslash.st_dev == stblock.st_rdev)
    311   1.1      cgd 			hotroot++;
    312  1.10  mycroft 		raw = rawname(newname);
    313   1.1      cgd 		if (stat(raw, &stchar) < 0) {
    314   1.1      cgd 			perror(raw);
    315   1.1      cgd 			printf("Can't stat %s\n", raw);
    316  1.10  mycroft 			return (origname);
    317   1.1      cgd 		}
    318   1.8  mycroft 		if (S_ISCHR(stchar.st_mode)) {
    319   1.1      cgd 			return (raw);
    320   1.1      cgd 		} else {
    321   1.1      cgd 			printf("%s is not a character device\n", raw);
    322  1.10  mycroft 			return (origname);
    323   1.1      cgd 		}
    324   1.8  mycroft 	} else if (S_ISCHR(stblock.st_mode) && !retried) {
    325  1.10  mycroft 		newname = unrawname(newname);
    326   1.1      cgd 		retried++;
    327   1.1      cgd 		goto retry;
    328   1.1      cgd 	}
    329  1.10  mycroft 	/*
    330  1.10  mycroft 	 * Not a block or character device, just return name and
    331  1.10  mycroft 	 * let the user decide whether to use it.
    332  1.10  mycroft 	 */
    333  1.10  mycroft 	return (origname);
    334   1.1      cgd }
    335   1.1      cgd 
    336   1.1      cgd char *
    337   1.1      cgd unrawname(name)
    338   1.1      cgd 	char *name;
    339   1.1      cgd {
    340   1.1      cgd 	char *dp;
    341   1.1      cgd 	struct stat stb;
    342   1.1      cgd 
    343   1.7  mycroft 	if ((dp = strrchr(name, '/')) == 0)
    344   1.1      cgd 		return (name);
    345   1.1      cgd 	if (stat(name, &stb) < 0)
    346   1.1      cgd 		return (name);
    347   1.8  mycroft 	if (!S_ISCHR(stb.st_mode))
    348   1.1      cgd 		return (name);
    349   1.1      cgd 	if (dp[1] != 'r')
    350   1.1      cgd 		return (name);
    351   1.1      cgd 	(void)strcpy(&dp[1], &dp[2]);
    352   1.1      cgd 	return (name);
    353   1.1      cgd }
    354   1.1      cgd 
    355   1.1      cgd char *
    356   1.1      cgd rawname(name)
    357   1.1      cgd 	char *name;
    358   1.1      cgd {
    359   1.1      cgd 	static char rawbuf[32];
    360   1.1      cgd 	char *dp;
    361   1.1      cgd 
    362   1.7  mycroft 	if ((dp = strrchr(name, '/')) == 0)
    363   1.1      cgd 		return (0);
    364   1.1      cgd 	*dp = 0;
    365   1.1      cgd 	(void)strcpy(rawbuf, name);
    366   1.1      cgd 	*dp = '/';
    367   1.1      cgd 	(void)strcat(rawbuf, "/r");
    368   1.1      cgd 	(void)strcat(rawbuf, &dp[1]);
    369   1.1      cgd 	return (rawbuf);
    370   1.1      cgd }
    371