Esempio n. 1
0
/*
 * XXX this code is from NetBSD, but fails in FreeBSD because we
 * don't have blockdevs. I don't think its needed.
 */
const char *
blockcheck(const char *origname)
{
	struct stat stslash, stblock, stchar;
	const char *newname, *raw;
	struct fstab *fsp;
	int retried = 0;

	hot = 0;
	if (stat("/", &stslash) < 0) {
		perror("/");
		printf("Can't stat root\n");
		return (origname);
	}
	newname = origname;
retry:
	if (stat(newname, &stblock) < 0) {
		perror(newname);
		printf("Can't stat %s\n", newname);
		return (origname);
	}
	if (S_ISBLK(stblock.st_mode)) {
		if (stslash.st_dev == stblock.st_rdev)
			hot++;
		raw = rawname(newname);
		if (stat(raw, &stchar) < 0) {
			perror(raw);
			printf("Can't stat %s\n", raw);
			return (origname);
		}
		if (S_ISCHR(stchar.st_mode)) {
			return (raw);
		} else {
			printf("%s is not a character device\n", raw);
			return (origname);
		}
	} else if (S_ISCHR(stblock.st_mode) && !retried) {
		newname = unrawname(newname);
		retried++;
		goto retry;
	} else if ((fsp = getfsfile(newname)) != 0 && !retried) {
		newname = fsp->fs_spec;
		retried++;
		goto retry;
	}
	/*
	 * Not a block or character device, just return name and
	 * let the user decide whether to use it.
	 */
	return (origname);
}
Esempio n. 2
0
/*
 * - given a pathname, determine the pathname to actually check
 * - if a directory
 *   - if it is in mnttab, set devstr to the special (block) name
 *   - if it is in vfstab, set devstr to the special (block) name
 *   - if it has not been found, bail
 * - a file is used as-is, clear rflag
 * - a device is converted to block version (so can search mnttab)
 */
static void
derive_devstr(const caddr_t dev, caddr_t devstr, size_t str_size)
{
	mode_t mode;
	struct stat statb;

	if (stat(dev, &statb) < 0) {
		exitstat = EXNOSTAT;
		errexit("fsck: could not stat %s: %s", dev, strerror(errno));
	}

	mode = statb.st_mode & S_IFMT;
	switch (mode) {
	case S_IFDIR:
		/*
		 * The check_*() routines update devstr with the name.
		 */
		devstr[0] = '\0';
		if (!(check_mnttab(dev, devstr, str_size) ||
		    check_vfstab(dev, devstr, str_size))) {
			exitstat = EXBADPARM;
			errexit(
		    "fsck: could not find mountpoint %s in mnttab nor vfstab",
			    dev);
		}
		break;
	case S_IFREG:
		rflag = 0;
		break;
	case S_IFCHR:
	case S_IFBLK:
		(void) strlcpy(devstr, unrawname(dev), str_size);
		break;
	default:
		exitstat = EXBADPARM;
		errexit("fsck: %s must be a mountpoint, device, or file", dev);
		/* NOTREACHED */
	}
}
/*
 * copied from diskdev_cmds/fsck_hfs/utilities.c, and modified:
 * 1) remove "hotroot"
 * 2) if error, return NULL
 * 3) if not a char device, return NULL (effectively, this is treated
 *    as error even if accessing the block device might have been OK)
 */
char *
blockcheck(char *origname)
{
	struct stat stblock, stchar;
	char *newname, *raw;
	int retried;

	retried = 0;
	newname = origname;
retry:
	if (stat(newname, &stblock) < 0) {
		perror(newname);
		fprintf(stderr, "Can't stat %s\n", newname);
		return NULL;
	}
	if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
		raw = rawname(newname);
		if (stat(raw, &stchar) < 0) {
			perror(raw);
			fprintf(stderr, "Can't stat %s\n", raw);
			return NULL;
		}
		if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
			return (raw);
		} else {
			fprintf(stderr, "%s is not a character device\n", raw);
			return NULL;
		}
	} else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
		newname = unrawname(newname);
		retried++;
		goto retry;
	}
	/* not a block or character device */
	return NULL;
}
Esempio n. 4
0
int
setup(char *dev)
{
	long cg, size, asked, i, j, bmapsize;
	struct disklabel *lp;
	off_t sizepb;
	struct stat statb;
	struct fs proto;
	int doskipclean;
	int32_t maxsymlinklen, nindir, inopb;
	u_int64_t maxfilesize;
	char *realdev;

	havesb = 0;
	fswritefd = fsreadfd = -1;
	doskipclean = skipclean;
	if ((fsreadfd = opendev(dev, O_RDONLY, 0, &realdev)) < 0) {
		printf("Can't open %s: %s\n", dev, strerror(errno));
		return (0);
	}
	if (strncmp(dev, realdev, PATH_MAX) != 0) {
		blockcheck(unrawname(realdev));
		strlcpy(rdevname, realdev, sizeof(rdevname));
		setcdevname(rdevname, dev, preen);
	}
	if (fstat(fsreadfd, &statb) < 0) {
		printf("Can't stat %s: %s\n", realdev, strerror(errno));
		close(fsreadfd);
		return (0);
	}
	if (!S_ISCHR(statb.st_mode)) {
		pfatal("%s is not a character device", realdev);
		if (reply("CONTINUE") == 0) {
			close(fsreadfd);
			return (0);
		}
	}
	if (preen == 0) {
		printf("** %s", realdev);
		if (strncmp(dev, realdev, PATH_MAX) != 0)
			printf(" (%s)", dev);
	}
	if (nflag || (fswritefd = opendev(dev, O_WRONLY, 0, NULL)) < 0) {
		fswritefd = -1;
		if (preen)
			pfatal("NO WRITE ACCESS");
		printf(" (NO WRITE)");
	}
	if (preen == 0)
		printf("\n");
	fsmodified = 0;
	lfdir = 0;
	initbarea(&sblk);
	initbarea(&asblk);
	sblk.b_un.b_buf = malloc(SBSIZE);
	asblk.b_un.b_buf = malloc(SBSIZE);
	if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
		errexit("cannot allocate space for superblock\n");
	if ((lp = getdisklabel(NULL, fsreadfd)) != NULL)
		dev_bsize = secsize = lp->d_secsize;
	else
		dev_bsize = secsize = DEV_BSIZE;
	/*
	 * Read in the superblock, looking for alternates if necessary
	 */
	if (readsb(1) == 0) {
		if (bflag || preen || calcsb(realdev, fsreadfd, &proto) == 0)
			return(0);
		if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
			return (0);
		for (i = 0; i < sizeof(altsbtry) / sizeof(altsbtry[0]); i++) {
			bflag = altsbtry[i];
			/* proto partially setup by calcsb */
			if (readsb(0) != 0 &&
			    proto.fs_fsize == sblock.fs_fsize &&
			    proto.fs_bsize == sblock.fs_bsize)
				goto found;
		}
		for (cg = 0; cg < proto.fs_ncg; cg++) {
			bflag = fsbtodb(&proto, cgsblock(&proto, cg));
			if (readsb(0) != 0)
				break;
		}
		if (cg >= proto.fs_ncg) {
			printf("%s %s\n%s %s\n%s %s\n",
			    "SEARCH FOR ALTERNATE SUPER-BLOCK",
			    "FAILED. YOU MUST USE THE",
			    "-b OPTION TO FSCK_FFS TO SPECIFY THE",
			    "LOCATION OF AN ALTERNATE",
			    "SUPER-BLOCK TO SUPPLY NEEDED",
			    "INFORMATION; SEE fsck_ffs(8).");
			return(0);
		}
found:
		doskipclean = 0;
		pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
	}
	if (debug)
		printf("clean = %d\n", sblock.fs_clean);
	if (sblock.fs_clean & FS_ISCLEAN) {
		if (doskipclean) {
			pwarn("%sile system is clean; not checking\n",
			    preen ? "f" : "** F");
			return (-1);
		}
		if (!preen)
			pwarn("** File system is already clean\n");
	}
	maxfsblock = sblock.fs_size;
	maxino = sblock.fs_ncg * sblock.fs_ipg;
	sizepb = sblock.fs_bsize;
	maxfilesize = sblock.fs_bsize * NDADDR - 1;
	for (i = 0; i < NIADDR; i++) {
		sizepb *= NINDIR(&sblock);
		maxfilesize += sizepb;
	}
	/*
	 * Check and potentially fix certain fields in the super block.
	 */
	if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) {
		pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
		if (reply("SET TO DEFAULT") == 1) {
			sblock.fs_optim = FS_OPTTIME;
			sbdirty();
		}
	}
	if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) {
		pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
		    sblock.fs_minfree);
		if (reply("SET TO DEFAULT") == 1) {
			sblock.fs_minfree = 10;
			sbdirty();
		}
	}
	if (sblock.fs_npsect < sblock.fs_nsect ||
	    sblock.fs_npsect > sblock.fs_nsect*2) {
		pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK",
		    sblock.fs_npsect);
		sblock.fs_npsect = sblock.fs_nsect;
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("SET TO DEFAULT") == 1) {
			sbdirty();
			dirty(&asblk);
		}
	}
	if (sblock.fs_bmask != ~(sblock.fs_bsize - 1)) {
		pwarn("INCORRECT BMASK=%x IN SUPERBLOCK",
		    sblock.fs_bmask);
		sblock.fs_bmask = ~(sblock.fs_bsize - 1);
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
			dirty(&asblk);
		}
	}
	if (sblock.fs_fmask != ~(sblock.fs_fsize - 1)) {
		pwarn("INCORRECT FMASK=%x IN SUPERBLOCK",
		    sblock.fs_fmask);
		sblock.fs_fmask = ~(sblock.fs_fsize - 1);
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
			dirty(&asblk);
		}
	}
	if (1 << sblock.fs_bshift != sblock.fs_bsize) {
		pwarn("INCORRECT BSHIFT=%d IN SUPERBLOCK", sblock.fs_bshift);
		sblock.fs_bshift = ffs(sblock.fs_bsize) - 1;
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
			dirty(&asblk);
		}
	}
	if (1 << sblock.fs_fshift != sblock.fs_fsize) {
		pwarn("INCORRECT FSHIFT=%d IN SUPERBLOCK", sblock.fs_fshift);
		sblock.fs_fshift = ffs(sblock.fs_fsize) - 1;
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
			dirty(&asblk);
		}
	}
	if (sblock.fs_inodefmt < FS_44INODEFMT) {
		pwarn("Format of filesystem is too old.\n");
		pwarn("Must update to modern format using a version of fsck\n");
		pfatal("from before release 5.0 with the command ``fsck -c 2''\n");
		exit(8);
	}
	if (sblock.fs_maxfilesize != maxfilesize) {
		pwarn("INCORRECT MAXFILESIZE=%llu IN SUPERBLOCK",
		    (unsigned long long)sblock.fs_maxfilesize);
		sblock.fs_maxfilesize = maxfilesize;
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
			dirty(&asblk);
		}
	}
	maxsymlinklen = sblock.fs_magic == FS_UFS1_MAGIC ?
	    MAXSYMLINKLEN_UFS1 : MAXSYMLINKLEN_UFS2;
	if (sblock.fs_maxsymlinklen != maxsymlinklen) {
		pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK",
		    sblock.fs_maxsymlinklen);
		sblock.fs_maxsymlinklen = maxsymlinklen;
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
			dirty(&asblk);
		}
	}
	if (sblock.fs_qbmask != ~sblock.fs_bmask) {
		pwarn("INCORRECT QBMASK=%lx IN SUPERBLOCK",
		    (unsigned long)sblock.fs_qbmask);
		sblock.fs_qbmask = ~sblock.fs_bmask;
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
			dirty(&asblk);
		}
	}
	if (sblock.fs_qfmask != ~sblock.fs_fmask) {
		pwarn("INCORRECT QFMASK=%lx IN SUPERBLOCK",
		    (unsigned long)sblock.fs_qfmask);
		sblock.fs_qfmask = ~sblock.fs_fmask;
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
			dirty(&asblk);
		}
	}
	if (sblock.fs_cgsize != fragroundup(&sblock, CGSIZE(&sblock))) {
		pwarn("INCONSISTENT CGSIZE=%d\n", sblock.fs_cgsize);
		sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock));
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
			dirty(&asblk);
		}
	}
	if (sblock.fs_magic == FS_UFS2_MAGIC)
		inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode);
	else
		inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode);
	if (INOPB(&sblock) != inopb) {
		pwarn("INCONSISTENT INOPB=%d\n", INOPB(&sblock));
		sblock.fs_inopb = inopb;
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
			dirty(&asblk);
		}
	}
	if (sblock.fs_magic == FS_UFS2_MAGIC)
		nindir = sblock.fs_bsize / sizeof(int64_t);
	else
		nindir = sblock.fs_bsize / sizeof(int32_t);
	if (NINDIR(&sblock) != nindir) {
		pwarn("INCONSISTENT NINDIR=%d\n", NINDIR(&sblock));
		sblock.fs_nindir = nindir;
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
			dirty(&asblk);
		}
	}
	if (asblk.b_dirty && !bflag) {
		memcpy(&altsblock, &sblock, (size_t)sblock.fs_sbsize);
		flush(fswritefd, &asblk);
	}
	/*
	 * read in the summary info.
	 */
	asked = 0;
	sblock.fs_csp = calloc(1, sblock.fs_cssize);
	if (sblock.fs_csp == NULL) {
		printf("cannot alloc %u bytes for cylinder group summary area\n",
		    (unsigned)sblock.fs_cssize);
		goto badsblabel;
	}
	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
		size = sblock.fs_cssize - i < sblock.fs_bsize ?
		    sblock.fs_cssize - i : sblock.fs_bsize;
		if (bread(fsreadfd, (char *)sblock.fs_csp + i,
		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
		    size) != 0 && !asked) {
			pfatal("BAD SUMMARY INFORMATION");
			if (reply("CONTINUE") == 0) {
				ckfini(0);
				errexit("%s", "");
			}
			asked++;
		}
	}
	/*
	 * allocate and initialize the necessary maps
	 */
	bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t));
	blockmap = calloc((unsigned)bmapsize, sizeof(char));
	if (blockmap == NULL) {
		printf("cannot alloc %u bytes for blockmap\n",
		    (unsigned)bmapsize);
		goto badsblabel;
	}
	inostathead = calloc((unsigned)(sblock.fs_ncg),
	    sizeof(struct inostatlist));
	if (inostathead == NULL) {
		printf("cannot alloc %u bytes for inostathead\n",
		    (unsigned)(sizeof(struct inostatlist) * (sblock.fs_ncg)));
		goto badsblabel;
	}
	numdirs = MAX(sblock.fs_cstotal.cs_ndir, 128);
	inplast = 0;
	listmax = numdirs + 10;
	inpsort = calloc((unsigned)listmax, sizeof(struct inoinfo *));
	if (inpsort == NULL) {
		printf("cannot alloc %zu bytes for inpsort\n",
		    (unsigned)listmax * sizeof(struct inoinfo *));
		goto badsblabel;
	}
	inphead = calloc((unsigned)numdirs, sizeof(struct inoinfo *));
	if (inphead == NULL) {
		printf("cannot alloc %zu bytes for inphead\n",
		    (unsigned)numdirs * sizeof(struct inoinfo *));
		goto badsblabel;
	}
	bufinit();
	if (sblock.fs_flags & FS_DOSOFTDEP)
		usedsoftdep = 1;
	else
		usedsoftdep = 0;
	return (1);

badsblabel:
	ckfini(0);
	return (0);
}