int berase(struct uufsd *disk, ufs2_daddr_t blockno, ufs2_daddr_t size) { int rv; ERROR(disk, NULL); rv = ufs_disk_write(disk); if (rv == -1) { ERROR(disk, "failed to open disk for writing"); return(rv); } return (berase_helper(disk, blockno, size)); }
int berase(struct uufsd *disk, ufs2_daddr_t blockno, ufs2_daddr_t size) { off_t ioarg[2]; int rv; ERROR(disk, NULL); rv = ufs_disk_write(disk); if (rv == -1) { ERROR(disk, "failed to open disk for writing"); return(rv); } ioarg[0] = blockno * disk->d_bsize; ioarg[1] = size; rv = ioctl(disk->d_fd, DIOCGDELETE, ioarg); return (rv); }
ssize_t bwrite(struct uufsd *disk, ufs2_daddr_t blockno, const void *data, size_t size) { ssize_t cnt; int rv; void *p2 = NULL; ERROR(disk, NULL); rv = ufs_disk_write(disk); if (rv == -1) { ERROR(disk, "failed to open disk for writing"); return (-1); } /* * XXX: various disk controllers require alignment of our buffer * XXX: which is stricter than struct alignment. * XXX: Bounce the buffer if not 64 byte aligned. * XXX: this can be removed if/when the kernel is fixed */ if (((intptr_t)data) & 0x3f) { p2 = malloc(size); if (p2 == NULL) { ERROR(disk, "allocate bounce buffer"); return (-1); } memcpy(p2, data, size); data = p2; } cnt = pwrite(disk->d_fd, data, size, (off_t)(blockno * disk->d_bsize)); if (p2 != NULL) free(p2); if (cnt == -1) { ERROR(disk, "write error to block device"); return (-1); } if ((size_t)cnt != size) { ERROR(disk, "short write to block device"); return (-1); } return (cnt); }
int main(int argc, char *argv[]) { struct partition *pp; struct disklabel *lp; struct partition oldpartition; struct stat st; char *cp, *special; intmax_t reserved; int ch, i, rval; off_t mediasize; char part_name; /* partition name, default to full disk */ part_name = 'c'; reserved = 0; while ((ch = getopt(argc, argv, "EJL:NO:RS:T:UXa:b:c:d:e:f:g:h:i:jlm:no:p:r:s:t")) != -1) switch (ch) { case 'E': Eflag = 1; break; case 'J': Jflag = 1; break; case 'L': volumelabel = optarg; i = -1; while (isalnum(volumelabel[++i])); if (volumelabel[i] != '\0') { errx(1, "bad volume label. Valid characters are alphanumerics."); } if (strlen(volumelabel) >= MAXVOLLEN) { errx(1, "bad volume label. Length is longer than %d.", MAXVOLLEN); } Lflag = 1; break; case 'N': Nflag = 1; break; case 'O': if ((Oflag = atoi(optarg)) < 1 || Oflag > 2) errx(1, "%s: bad file system format value", optarg); break; case 'R': Rflag = 1; break; case 'S': rval = expand_number_int(optarg, §orsize); if (rval < 0 || sectorsize <= 0) errx(1, "%s: bad sector size", optarg); break; case 'T': disktype = optarg; break; case 'j': jflag = 1; /* fall through to enable soft updates */ case 'U': Uflag = 1; break; case 'X': Xflag++; break; case 'a': rval = expand_number_int(optarg, &maxcontig); if (rval < 0 || maxcontig <= 0) errx(1, "%s: bad maximum contiguous blocks", optarg); break; case 'b': rval = expand_number_int(optarg, &bsize); if (rval < 0) errx(1, "%s: bad block size", optarg); if (bsize < MINBSIZE) errx(1, "%s: block size too small, min is %d", optarg, MINBSIZE); if (bsize > MAXBSIZE) errx(1, "%s: block size too large, max is %d", optarg, MAXBSIZE); break; case 'c': rval = expand_number_int(optarg, &maxblkspercg); if (rval < 0 || maxblkspercg <= 0) errx(1, "%s: bad blocks per cylinder group", optarg); break; case 'd': rval = expand_number_int(optarg, &maxbsize); if (rval < 0 || maxbsize < MINBSIZE) errx(1, "%s: bad extent block size", optarg); break; case 'e': rval = expand_number_int(optarg, &maxbpg); if (rval < 0 || maxbpg <= 0) errx(1, "%s: bad blocks per file in a cylinder group", optarg); break; case 'f': rval = expand_number_int(optarg, &fsize); if (rval < 0 || fsize <= 0) errx(1, "%s: bad fragment size", optarg); break; case 'g': rval = expand_number_int(optarg, &avgfilesize); if (rval < 0 || avgfilesize <= 0) errx(1, "%s: bad average file size", optarg); break; case 'h': rval = expand_number_int(optarg, &avgfilesperdir); if (rval < 0 || avgfilesperdir <= 0) errx(1, "%s: bad average files per dir", optarg); break; case 'i': rval = expand_number_int(optarg, &density); if (rval < 0 || density <= 0) errx(1, "%s: bad bytes per inode", optarg); break; case 'l': lflag = 1; break; case 'm': if ((minfree = atoi(optarg)) < 0 || minfree > 99) errx(1, "%s: bad free space %%", optarg); break; case 'n': nflag = 1; break; case 'o': if (strcmp(optarg, "space") == 0) opt = FS_OPTSPACE; else if (strcmp(optarg, "time") == 0) opt = FS_OPTTIME; else errx(1, "%s: unknown optimization preference: use `space' or `time'", optarg); break; case 'r': errno = 0; reserved = strtoimax(optarg, &cp, 0); if (errno != 0 || cp == optarg || *cp != '\0' || reserved < 0) errx(1, "%s: bad reserved size", optarg); break; case 'p': is_file = 1; part_name = optarg[0]; break; case 's': errno = 0; fssize = strtoimax(optarg, &cp, 0); if (errno != 0 || cp == optarg || *cp != '\0' || fssize < 0) errx(1, "%s: bad file system size", optarg); break; case 't': tflag = 1; break; case '?': default: usage(); } argc -= optind; argv += optind; if (argc != 1) usage(); special = argv[0]; if (!special[0]) err(1, "empty file/special name"); cp = strrchr(special, '/'); if (cp == 0) { /* * No path prefix; try prefixing _PATH_DEV. */ snprintf(device, sizeof(device), "%s%s", _PATH_DEV, special); special = device; } if (is_file) { /* bypass ufs_disk_fillout_blank */ bzero( &disk, sizeof(disk)); disk.d_bsize = 1; disk.d_name = special; disk.d_fd = open(special, O_RDONLY); if (disk.d_fd < 0 || (!Nflag && ufs_disk_write(&disk) == -1)) errx(1, "%s: ", special); } else if (ufs_disk_fillout_blank(&disk, special) == -1 || (!Nflag && ufs_disk_write(&disk) == -1)) { if (disk.d_error != NULL) errx(1, "%s: %s", special, disk.d_error); else err(1, "%s", special); } if (fstat(disk.d_fd, &st) < 0) err(1, "%s", special); if ((st.st_mode & S_IFMT) != S_IFCHR) { warn("%s: not a character-special device", special); is_file = 1; /* assume it is a file */ dkname = special; if (sectorsize == 0) sectorsize = 512; mediasize = st.st_size; /* set fssize from the partition */ } else { if (sectorsize == 0) if (ioctl(disk.d_fd, DIOCGSECTORSIZE, §orsize) == -1) sectorsize = 0; /* back out on error for safety */ if (sectorsize && ioctl(disk.d_fd, DIOCGMEDIASIZE, &mediasize) != -1) getfssize(&fssize, special, mediasize / sectorsize, reserved); } pp = NULL; lp = getdisklabel(special); if (lp != NULL) { if (!is_file) /* already set for files */ part_name = special[strlen(special) - 1]; if ((part_name < 'a' || part_name - 'a' >= MAXPARTITIONS) && !isdigit(part_name)) errx(1, "%s: can't figure out file system partition", special); cp = &part_name; if (isdigit(*cp)) pp = &lp->d_partitions[RAW_PART]; else pp = &lp->d_partitions[*cp - 'a']; oldpartition = *pp; if (pp->p_size == 0) errx(1, "%s: `%c' partition is unavailable", special, *cp); if (pp->p_fstype == FS_BOOT) errx(1, "%s: `%c' partition overlaps boot program", special, *cp); getfssize(&fssize, special, pp->p_size, reserved); if (sectorsize == 0) sectorsize = lp->d_secsize; if (fsize == 0) fsize = pp->p_fsize; if (bsize == 0) bsize = pp->p_frag * pp->p_fsize; if (is_file) part_ofs = pp->p_offset; } if (sectorsize <= 0) errx(1, "%s: no default sector size", special); if (fsize <= 0) fsize = MAX(DFL_FRAGSIZE, sectorsize); if (bsize <= 0) bsize = MIN(DFL_BLKSIZE, 8 * fsize); if (minfree < MINFREE && opt != FS_OPTSPACE) { fprintf(stderr, "Warning: changing optimization to space "); fprintf(stderr, "because minfree is less than %d%%\n", MINFREE); opt = FS_OPTSPACE; } realsectorsize = sectorsize; if (sectorsize != DEV_BSIZE) { /* XXX */ int secperblk = sectorsize / DEV_BSIZE; sectorsize = DEV_BSIZE; fssize *= secperblk; if (pp != NULL) pp->p_size *= secperblk; } mkfs(pp, special); if (!unlabeled) { if (realsectorsize != DEV_BSIZE) pp->p_size /= realsectorsize / DEV_BSIZE; if (!Nflag && bcmp(pp, &oldpartition, sizeof(oldpartition))) rewritelabel(special, lp); } ufs_disk_close(&disk); if (!jflag) exit(0); if (execlp("tunefs", "newfs", "-j", "enable", special, NULL) < 0) err(1, "Cannot enable soft updates journaling, tunefs"); /* NOT REACHED */ }
/* * Read in a superblock finding an alternate if necessary. * Return 1 if successful, 0 if unsuccessful, -1 if file system * is already clean (ckclean and preen mode only). */ int setup(char *dev) { long cg, asked, i, j; long bmapsize; struct stat statb; struct fs proto; size_t size; havesb = 0; fswritefd = -1; cursnapshot = 0; if (stat(dev, &statb) < 0) { printf("Can't stat %s: %s\n", dev, strerror(errno)); if (bkgrdflag) { unlink(snapname); bkgrdflag = 0; } return (0); } if ((statb.st_mode & S_IFMT) != S_IFCHR && (statb.st_mode & S_IFMT) != S_IFBLK) { if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) { unlink(snapname); printf("background fsck lacks a snapshot\n"); exit(EEXIT); } if ((statb.st_flags & SF_SNAPSHOT) != 0 && cvtlevel == 0) { cursnapshot = statb.st_ino; } else { if (cvtlevel == 0 || (statb.st_flags & SF_SNAPSHOT) == 0) { if (preen && bkgrdflag) { unlink(snapname); bkgrdflag = 0; } pfatal("%s is not a disk device", dev); if (reply("CONTINUE") == 0) { if (bkgrdflag) { unlink(snapname); bkgrdflag = 0; } return (0); } } else { if (bkgrdflag) { unlink(snapname); bkgrdflag = 0; } pfatal("cannot convert a snapshot"); exit(EEXIT); } } } if ((fsreadfd = open(dev, O_RDONLY)) < 0 || ufs_disk_fillout(&disk, dev) < 0) { if (bkgrdflag) { unlink(snapname); bkgrdflag = 0; } printf("Can't open %s: %s\n", dev, strerror(errno)); return (0); } if (bkgrdflag) { unlink(snapname); size = MIBSIZE; if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0|| sysctlnametomib("vfs.ffs.adjblkcnt", adjblkcnt, &size) < 0|| sysctlnametomib("vfs.ffs.freefiles", freefiles, &size) < 0|| sysctlnametomib("vfs.ffs.freedirs", freedirs, &size) < 0 || sysctlnametomib("vfs.ffs.freeblks", freeblks, &size) < 0) { pfatal("kernel lacks background fsck support\n"); exit(EEXIT); } /* * When kernel is lack of runtime bgfsck superblock summary * adjustment functionality, it does not mean we can not * continue, as old kernels will recompute the summary at * mount time. However, it will be an unexpected softupdates * inconsistency if it turns out that the summary is still * incorrect. Set a flag so subsequent operation can know * this. */ bkgrdsumadj = 1; if (sysctlnametomib("vfs.ffs.adjndir", adjndir, &size) < 0 || sysctlnametomib("vfs.ffs.adjnbfree", adjnbfree, &size) < 0 || sysctlnametomib("vfs.ffs.adjnifree", adjnifree, &size) < 0 || sysctlnametomib("vfs.ffs.adjnffree", adjnffree, &size) < 0 || sysctlnametomib("vfs.ffs.adjnumclusters", adjnumclusters, &size) < 0) { bkgrdsumadj = 0; pwarn("kernel lacks runtime superblock summary adjustment support"); } cmd.version = FFS_CMD_VERSION; cmd.handle = fsreadfd; fswritefd = -1; } if (preen == 0) printf("** %s", dev); if (bkgrdflag == 0 && (nflag || ufs_disk_write(&disk) < 0 || (fswritefd = dup(disk.d_fd)) < 0)) { fswritefd = -1; if (preen) pfatal("NO WRITE ACCESS"); printf(" (NO WRITE)"); } if (preen == 0) printf("\n"); /* * Read in the superblock, looking for alternates if necessary */ if (readsb(1) == 0) { skipclean = 0; if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0) return(0); if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) return (0); 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 TO SPECIFY THE", "LOCATION OF AN ALTERNATE", "SUPER-BLOCK TO SUPPLY NEEDED", "INFORMATION; SEE fsck_ffs(8)."); bflag = 0; return(0); } pwarn("USING ALTERNATE SUPERBLOCK AT %jd\n", bflag); bflag = 0; } if (skipclean && ckclean && sblock.fs_clean) { pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); return (-1); } maxfsblock = sblock.fs_size; maxino = sblock.fs_ncg * sblock.fs_ipg; /* * 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_magic == FS_UFS1_MAGIC && sblock.fs_old_inodefmt < FS_44INODEFMT) { pwarn("Format of file system is too old.\n"); pwarn("Must update to modern format using a version of fsck\n"); pfatal("from before 2002 with the command ``fsck -c 2''\n"); exit(EEXIT); } if (asblk.b_dirty && !bflag) { memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize); flush(fswritefd, &asblk); } if (preen == 0 && yflag == 0 && sblock.fs_magic == FS_UFS2_MAGIC && fswritefd != -1 && chkrecovery(fsreadfd) == 0 && reply("SAVE DATA TO FIND ALTERNATE SUPERBLOCKS") != 0) saverecovery(fsreadfd, fswritefd); /* * 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 cg summary info\n", (unsigned)sblock.fs_cssize); goto badsb; } for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { size = MIN(sblock.fs_cssize - i, sblock.fs_bsize); readcnt[sblk.b_type]++; if (blread(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); exit(EEXIT); } asked++; } } /* * allocate and initialize the necessary maps */ bmapsize = roundup(howmany(maxfsblock, CHAR_BIT), sizeof(short)); blockmap = Calloc((unsigned)bmapsize, sizeof (char)); if (blockmap == NULL) { printf("cannot alloc %u bytes for blockmap\n", (unsigned)bmapsize); goto badsb; } inostathead = Calloc(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 badsb; } numdirs = MAX(sblock.fs_cstotal.cs_ndir, 128); dirhash = numdirs; inplast = 0; listmax = numdirs + 10; inpsort = (struct inoinfo **)Calloc(listmax, sizeof(struct inoinfo *)); inphead = (struct inoinfo **)Calloc(numdirs, sizeof(struct inoinfo *)); if (inpsort == NULL || inphead == NULL) { printf("cannot alloc %ju bytes for inphead\n", (uintmax_t)numdirs * sizeof(struct inoinfo *)); goto badsb; } bufinit(); if (sblock.fs_flags & FS_DOSOFTDEP) usedsoftdep = 1; else usedsoftdep = 0; return (1); badsb: ckfini(0); return (0); }