1*5b133f3fSguenther /* $OpenBSD: utilities.c,v 1.55 2023/03/08 04:43:06 guenther Exp $ */
287304b87Stholo /* $NetBSD: utilities.c,v 1.18 1996/09/27 22:45:20 christos Exp $ */
3df930be7Sderaadt
4df930be7Sderaadt /*
5df930be7Sderaadt * Copyright (c) 1980, 1986, 1993
6df930be7Sderaadt * The Regents of the University of California. All rights reserved.
7df930be7Sderaadt *
8df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
9df930be7Sderaadt * modification, are permitted provided that the following conditions
10df930be7Sderaadt * are met:
11df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
12df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
13df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
14df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
15df930be7Sderaadt * documentation and/or other materials provided with the distribution.
161ef0d710Smillert * 3. Neither the name of the University nor the names of its contributors
17df930be7Sderaadt * may be used to endorse or promote products derived from this software
18df930be7Sderaadt * without specific prior written permission.
19df930be7Sderaadt *
20df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30df930be7Sderaadt * SUCH DAMAGE.
31df930be7Sderaadt */
32df930be7Sderaadt
3378eb0b7eSderaadt #include <sys/param.h> /* DEV_BSIZE isset setbit clrbit */
34df930be7Sderaadt #include <sys/time.h>
35af9e537cSd #include <sys/uio.h>
36df930be7Sderaadt #include <ufs/ufs/dinode.h>
37df930be7Sderaadt #include <ufs/ufs/dir.h>
38df930be7Sderaadt #include <ufs/ffs/fs.h>
3949f464a0Sotto #include <signal.h>
40df930be7Sderaadt #include <stdio.h>
41df930be7Sderaadt #include <stdlib.h>
42df930be7Sderaadt #include <string.h>
43df930be7Sderaadt #include <ctype.h>
44df930be7Sderaadt #include <unistd.h>
45b9fc9a72Sderaadt #include <limits.h>
46d4a55c7bSderaadt #include <errno.h>
47af9e537cSd #include <fcntl.h>
48af9e537cSd #include <paths.h>
49df930be7Sderaadt
5087304b87Stholo #include "fsutil.h"
51df930be7Sderaadt #include "fsck.h"
52df930be7Sderaadt #include "extern.h"
53df930be7Sderaadt
54df930be7Sderaadt long diskreads, totalreads; /* Disk cache statistics */
552062fcb1Sotto static struct bufarea cgblk; /* backup buffer for cylinder group blocks */
56df930be7Sderaadt
571abdbfdeSderaadt static void rwerror(char *, daddr_t);
5887304b87Stholo
59df930be7Sderaadt int
ftypeok(union dinode * dp)602fffe0e0Smillert ftypeok(union dinode *dp)
61df930be7Sderaadt {
622fffe0e0Smillert switch (DIP(dp, di_mode) & IFMT) {
63df930be7Sderaadt case IFDIR:
64df930be7Sderaadt case IFREG:
65df930be7Sderaadt case IFBLK:
66df930be7Sderaadt case IFCHR:
67df930be7Sderaadt case IFLNK:
68df930be7Sderaadt case IFSOCK:
69df930be7Sderaadt case IFIFO:
70df930be7Sderaadt return (1);
71df930be7Sderaadt default:
72df930be7Sderaadt if (debug)
732fffe0e0Smillert printf("bad file type 0%o\n", DIP(dp, di_mode));
74df930be7Sderaadt return (0);
75df930be7Sderaadt }
76df930be7Sderaadt }
77df930be7Sderaadt
78df930be7Sderaadt int
reply(char * question)7960d6b16fSgluk reply(char *question)
80df930be7Sderaadt {
813883fb93Sderaadt int persevere, c;
82df930be7Sderaadt
83df930be7Sderaadt if (preen)
84df930be7Sderaadt pfatal("INTERNAL ERROR: GOT TO reply()");
85df930be7Sderaadt persevere = !strcmp(question, "CONTINUE");
86df930be7Sderaadt printf("\n");
87df930be7Sderaadt if (!persevere && (nflag || fswritefd < 0)) {
88df930be7Sderaadt printf("%s? no\n\n", question);
89767b3369Sart resolved = 0;
90df930be7Sderaadt return (0);
91df930be7Sderaadt }
92df930be7Sderaadt if (yflag || (persevere && nflag)) {
93df930be7Sderaadt printf("%s? yes\n\n", question);
94df930be7Sderaadt return (1);
95df930be7Sderaadt }
963883fb93Sderaadt
97df930be7Sderaadt do {
98daaa95b6Sderaadt printf("%s? [Fyn?] ", question);
99df930be7Sderaadt (void) fflush(stdout);
100df930be7Sderaadt c = getc(stdin);
101daaa95b6Sderaadt if (c == 'F') {
102daaa95b6Sderaadt yflag = 1;
103daaa95b6Sderaadt return (1);
104daaa95b6Sderaadt }
105767b3369Sart while (c != '\n' && getc(stdin) != '\n') {
106767b3369Sart if (feof(stdin)) {
107767b3369Sart resolved = 0;
108df930be7Sderaadt return (0);
109767b3369Sart }
110767b3369Sart }
111df930be7Sderaadt } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
112df930be7Sderaadt printf("\n");
113df930be7Sderaadt if (c == 'y' || c == 'Y')
114df930be7Sderaadt return (1);
115767b3369Sart resolved = 0;
116df930be7Sderaadt return (0);
117df930be7Sderaadt }
118df930be7Sderaadt
119df930be7Sderaadt /*
1204d91232bSotto * Look up state information for an inode.
1214d91232bSotto */
1224d91232bSotto struct inostat *
inoinfo(ino_t inum)1234d91232bSotto inoinfo(ino_t inum)
1244d91232bSotto {
1254d91232bSotto static struct inostat unallocated = { USTATE, 0, 0 };
1264d91232bSotto struct inostatlist *ilp;
1274d91232bSotto int iloff;
1284d91232bSotto
1294d91232bSotto if (inum > maxino)
1303b92bd08Sderaadt errexit("inoinfo: inumber %llu out of range",
1313b92bd08Sderaadt (unsigned long long)inum);
1324d91232bSotto ilp = &inostathead[inum / sblock.fs_ipg];
1334d91232bSotto iloff = inum % sblock.fs_ipg;
1344d91232bSotto if (iloff >= ilp->il_numalloced)
1354d91232bSotto return (&unallocated);
1364d91232bSotto return (&ilp->il_stat[iloff]);
1374d91232bSotto }
1384d91232bSotto
1394d91232bSotto /*
140df930be7Sderaadt * Malloc buffers and set up cache.
141df930be7Sderaadt */
142df930be7Sderaadt void
bufinit(void)14360d6b16fSgluk bufinit(void)
144df930be7Sderaadt {
145e073c79dSmpech struct bufarea *bp;
146df930be7Sderaadt long bufcnt, i;
147df930be7Sderaadt char *bufp;
148df930be7Sderaadt
14989203baaSkstailey pbp = pdirbp = NULL;
150df930be7Sderaadt bufp = malloc((unsigned int)sblock.fs_bsize);
151df930be7Sderaadt if (bufp == 0)
152df930be7Sderaadt errexit("cannot allocate buffer pool\n");
153df930be7Sderaadt cgblk.b_un.b_buf = bufp;
154df930be7Sderaadt initbarea(&cgblk);
155df930be7Sderaadt bufhead.b_next = bufhead.b_prev = &bufhead;
156df930be7Sderaadt bufcnt = MAXBUFSPACE / sblock.fs_bsize;
157df930be7Sderaadt if (bufcnt < MINBUFS)
158df930be7Sderaadt bufcnt = MINBUFS;
159df930be7Sderaadt for (i = 0; i < bufcnt; i++) {
16060d6b16fSgluk bp = malloc(sizeof(struct bufarea));
161df930be7Sderaadt bufp = malloc((unsigned int)sblock.fs_bsize);
162df930be7Sderaadt if (bp == NULL || bufp == NULL) {
163d9d929a5Sdhill free(bp);
164d9d929a5Sdhill free(bufp);
1654435eaddSderaadt if (i >= MINBUFS)
166df930be7Sderaadt break;
167df930be7Sderaadt errexit("cannot allocate buffer pool\n");
168df930be7Sderaadt }
169df930be7Sderaadt bp->b_un.b_buf = bufp;
170df930be7Sderaadt bp->b_prev = &bufhead;
171df930be7Sderaadt bp->b_next = bufhead.b_next;
172df930be7Sderaadt bufhead.b_next->b_prev = bp;
173df930be7Sderaadt bufhead.b_next = bp;
174df930be7Sderaadt initbarea(bp);
175df930be7Sderaadt }
176df930be7Sderaadt bufhead.b_size = i; /* save number of buffers */
177df930be7Sderaadt }
178df930be7Sderaadt
179df930be7Sderaadt /*
1802062fcb1Sotto * Manage cylinder group buffers.
1812062fcb1Sotto */
1822062fcb1Sotto static struct bufarea *cgbufs; /* header for cylinder group cache */
1832062fcb1Sotto static int flushtries; /* number of tries to reclaim memory */
1842062fcb1Sotto struct bufarea *
cglookup(u_int cg)1852062fcb1Sotto cglookup(u_int cg)
1862062fcb1Sotto {
1872062fcb1Sotto struct bufarea *cgbp;
1882062fcb1Sotto struct cg *cgp;
1892062fcb1Sotto
1902062fcb1Sotto if (cgbufs == NULL) {
1912062fcb1Sotto cgbufs = calloc(sblock.fs_ncg, sizeof(struct bufarea));
1922062fcb1Sotto if (cgbufs == NULL)
1932062fcb1Sotto errexit("cannot allocate cylinder group buffers");
1942062fcb1Sotto }
1952062fcb1Sotto cgbp = &cgbufs[cg];
1962062fcb1Sotto if (cgbp->b_un.b_cg != NULL)
1972062fcb1Sotto return (cgbp);
1982062fcb1Sotto cgp = NULL;
1992062fcb1Sotto if (flushtries == 0)
2002062fcb1Sotto cgp = malloc((unsigned int)sblock.fs_cgsize);
2012062fcb1Sotto if (cgp == NULL) {
2022062fcb1Sotto getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
2032062fcb1Sotto return (&cgblk);
2042062fcb1Sotto }
2052062fcb1Sotto cgbp->b_un.b_cg = cgp;
2062062fcb1Sotto initbarea(cgbp);
2072062fcb1Sotto getblk(cgbp, cgtod(&sblock, cg), sblock.fs_cgsize);
2082062fcb1Sotto return (cgbp);
2092062fcb1Sotto }
2102062fcb1Sotto
2112062fcb1Sotto
2122062fcb1Sotto /*
213df930be7Sderaadt * Manage a cache of directory blocks.
214df930be7Sderaadt */
215df930be7Sderaadt struct bufarea *
getdatablk(daddr_t blkno,long size)2161abdbfdeSderaadt getdatablk(daddr_t blkno, long size)
217df930be7Sderaadt {
218e073c79dSmpech struct bufarea *bp;
219df930be7Sderaadt
220df930be7Sderaadt for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
221df930be7Sderaadt if (bp->b_bno == fsbtodb(&sblock, blkno))
222df930be7Sderaadt goto foundit;
223df930be7Sderaadt for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
224df930be7Sderaadt if ((bp->b_flags & B_INUSE) == 0)
225df930be7Sderaadt break;
226df930be7Sderaadt if (bp == &bufhead)
227df930be7Sderaadt errexit("deadlocked buffer pool\n");
228df930be7Sderaadt getblk(bp, blkno, size);
229898bdbabStedu /* FALLTHROUGH */
230df930be7Sderaadt foundit:
231df930be7Sderaadt totalreads++;
232df930be7Sderaadt bp->b_prev->b_next = bp->b_next;
233df930be7Sderaadt bp->b_next->b_prev = bp->b_prev;
234df930be7Sderaadt bp->b_prev = &bufhead;
235df930be7Sderaadt bp->b_next = bufhead.b_next;
236df930be7Sderaadt bufhead.b_next->b_prev = bp;
237df930be7Sderaadt bufhead.b_next = bp;
238df930be7Sderaadt bp->b_flags |= B_INUSE;
239df930be7Sderaadt return (bp);
240df930be7Sderaadt }
241df930be7Sderaadt
242df930be7Sderaadt void
getblk(struct bufarea * bp,daddr_t blk,long size)2431abdbfdeSderaadt getblk(struct bufarea *bp, daddr_t blk, long size)
244df930be7Sderaadt {
2451abdbfdeSderaadt daddr_t dblk;
246df930be7Sderaadt
247df930be7Sderaadt dblk = fsbtodb(&sblock, blk);
248df930be7Sderaadt if (bp->b_bno != dblk) {
249df930be7Sderaadt flush(fswritefd, bp);
250df930be7Sderaadt diskreads++;
251df930be7Sderaadt bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size);
252df930be7Sderaadt bp->b_bno = dblk;
253df930be7Sderaadt bp->b_size = size;
254df930be7Sderaadt }
255df930be7Sderaadt }
256df930be7Sderaadt
257df930be7Sderaadt void
flush(int fd,struct bufarea * bp)25860d6b16fSgluk flush(int fd, struct bufarea *bp)
259df930be7Sderaadt {
260e073c79dSmpech int i, j;
261df930be7Sderaadt
262df930be7Sderaadt if (!bp->b_dirty)
263df930be7Sderaadt return;
264df930be7Sderaadt if (bp->b_errs != 0)
2654f17ce5eSotto pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n",
26617af71c1Skrw (bp->b_errs == bp->b_size / DEV_BSIZE) ? "" : "PARTIALLY ",
267bb4f4faeSkrw (long long)bp->b_bno);
268df930be7Sderaadt bp->b_dirty = 0;
269df930be7Sderaadt bp->b_errs = 0;
270df930be7Sderaadt bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
271df930be7Sderaadt if (bp != &sblk)
272df930be7Sderaadt return;
273df930be7Sderaadt for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
274b2e9ad3dSgluk bwrite(fswritefd, (char *)sblock.fs_csp + i,
2752fffe0e0Smillert fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
276df930be7Sderaadt sblock.fs_cssize - i < sblock.fs_bsize ?
277df930be7Sderaadt sblock.fs_cssize - i : sblock.fs_bsize);
278df930be7Sderaadt }
279df930be7Sderaadt }
280df930be7Sderaadt
28187304b87Stholo static void
rwerror(char * mesg,daddr_t blk)2821abdbfdeSderaadt rwerror(char *mesg, daddr_t blk)
283df930be7Sderaadt {
284df930be7Sderaadt
285df930be7Sderaadt if (preen == 0)
286df930be7Sderaadt printf("\n");
287bb4f4faeSkrw pfatal("CANNOT %s: BLK %lld", mesg, (long long)blk);
288df930be7Sderaadt if (reply("CONTINUE") == 0)
289df930be7Sderaadt errexit("Program terminated\n");
290df930be7Sderaadt }
291df930be7Sderaadt
292df930be7Sderaadt void
ckfini(int markclean)29360d6b16fSgluk ckfini(int markclean)
294df930be7Sderaadt {
295e073c79dSmpech struct bufarea *bp, *nbp;
296df930be7Sderaadt int cnt = 0;
29749f464a0Sotto sigset_t oset, nset;
2982fffe0e0Smillert int64_t sblockloc;
29949f464a0Sotto
30049f464a0Sotto sigemptyset(&nset);
30149f464a0Sotto sigaddset(&nset, SIGINT);
30249f464a0Sotto sigprocmask(SIG_BLOCK, &nset, &oset);
303df930be7Sderaadt
304df930be7Sderaadt if (fswritefd < 0) {
305df930be7Sderaadt (void)close(fsreadfd);
3063883fb93Sderaadt fsreadfd = -1;
30749f464a0Sotto sigprocmask(SIG_SETMASK, &oset, NULL);
308df930be7Sderaadt return;
309df930be7Sderaadt }
3102fffe0e0Smillert if (sblock.fs_magic == FS_UFS1_MAGIC) {
3112fffe0e0Smillert sblockloc = SBLOCK_UFS1;
3122fffe0e0Smillert sblock.fs_ffs1_time = sblock.fs_time;
3132fffe0e0Smillert sblock.fs_ffs1_size = sblock.fs_size;
3142fffe0e0Smillert sblock.fs_ffs1_dsize = sblock.fs_dsize;
3152fffe0e0Smillert sblock.fs_ffs1_csaddr = sblock.fs_csaddr;
3162fffe0e0Smillert sblock.fs_ffs1_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir;
3172fffe0e0Smillert sblock.fs_ffs1_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree;
3182fffe0e0Smillert sblock.fs_ffs1_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree;
3192fffe0e0Smillert sblock.fs_ffs1_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree;
320363b8579Spedro /* Force update on next mount */
321363b8579Spedro sblock.fs_ffs1_flags &= ~FS_FLAGS_UPDATED;
3222fffe0e0Smillert } else
3232fffe0e0Smillert sblockloc = SBLOCK_UFS2;
324df930be7Sderaadt flush(fswritefd, &sblk);
32517af71c1Skrw if (havesb && sblk.b_bno != sblockloc / DEV_BSIZE && !preen &&
3262fffe0e0Smillert reply("UPDATE STANDARD SUPERBLOCK")) {
32717af71c1Skrw sblk.b_bno = sblockloc / DEV_BSIZE;
328df930be7Sderaadt sbdirty();
329df930be7Sderaadt flush(fswritefd, &sblk);
330df930be7Sderaadt }
331df930be7Sderaadt flush(fswritefd, &cgblk);
332df930be7Sderaadt free(cgblk.b_un.b_buf);
333df930be7Sderaadt for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) {
334df930be7Sderaadt cnt++;
335df930be7Sderaadt flush(fswritefd, bp);
336df930be7Sderaadt nbp = bp->b_prev;
337df930be7Sderaadt free(bp->b_un.b_buf);
33860d6b16fSgluk free(bp);
339df930be7Sderaadt }
340df930be7Sderaadt if (bufhead.b_size != cnt)
341df930be7Sderaadt errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt);
3422062fcb1Sotto if (cgbufs != NULL) {
3432062fcb1Sotto for (cnt = 0; cnt < sblock.fs_ncg; cnt++) {
3442062fcb1Sotto if (cgbufs[cnt].b_un.b_cg == NULL)
3452062fcb1Sotto continue;
3462062fcb1Sotto flush(fswritefd, &cgbufs[cnt]);
3472062fcb1Sotto free(cgbufs[cnt].b_un.b_cg);
3482062fcb1Sotto }
3492062fcb1Sotto free(cgbufs);
3502062fcb1Sotto }
35189203baaSkstailey pbp = pdirbp = NULL;
352df930be7Sderaadt if (markclean && (sblock.fs_clean & FS_ISCLEAN) == 0) {
353df930be7Sderaadt /*
354df930be7Sderaadt * Mark the file system as clean, and sync the superblock.
355df930be7Sderaadt */
356df930be7Sderaadt if (preen)
357df930be7Sderaadt pwarn("MARKING FILE SYSTEM CLEAN\n");
358df930be7Sderaadt else if (!reply("MARK FILE SYSTEM CLEAN"))
359df930be7Sderaadt markclean = 0;
360df930be7Sderaadt if (markclean) {
361df930be7Sderaadt sblock.fs_clean = FS_ISCLEAN;
362df930be7Sderaadt sbdirty();
363df930be7Sderaadt flush(fswritefd, &sblk);
364df930be7Sderaadt }
365df930be7Sderaadt }
366df930be7Sderaadt if (debug)
367df930be7Sderaadt printf("cache missed %ld of %ld (%d%%)\n", diskreads,
368df930be7Sderaadt totalreads, (int)(diskreads * 100 / totalreads));
369df930be7Sderaadt (void)close(fsreadfd);
3703883fb93Sderaadt fsreadfd = -1;
371df930be7Sderaadt (void)close(fswritefd);
3723883fb93Sderaadt fswritefd = -1;
37349f464a0Sotto sigprocmask(SIG_SETMASK, &oset, NULL);
374df930be7Sderaadt }
375df930be7Sderaadt
376df930be7Sderaadt int
bread(int fd,char * buf,daddr_t blk,long size)3771abdbfdeSderaadt bread(int fd, char *buf, daddr_t blk, long size)
378df930be7Sderaadt {
379df930be7Sderaadt char *cp;
380df930be7Sderaadt int i, errs;
381df930be7Sderaadt off_t offset;
382df930be7Sderaadt
383df930be7Sderaadt offset = blk;
38417af71c1Skrw offset *= DEV_BSIZE;
3851593d282Skrw if (pread(fd, buf, size, offset) == size)
386df930be7Sderaadt return (0);
387df930be7Sderaadt rwerror("READ", blk);
388df930be7Sderaadt errs = 0;
389df930be7Sderaadt memset(buf, 0, (size_t)size);
390df930be7Sderaadt printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
391df930be7Sderaadt for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
3921593d282Skrw if (pread(fd, cp, secsize, offset + i) != secsize) {
39317af71c1Skrw if (secsize != DEV_BSIZE)
3944f17ce5eSotto printf(" %lld (%lld),",
3955480ff59Skrw (long long)(offset + i) / secsize,
3965480ff59Skrw (long long)blk + i / DEV_BSIZE);
397df930be7Sderaadt else
3985480ff59Skrw printf(" %lld,", (long long)blk +
3995480ff59Skrw i / DEV_BSIZE);
400df930be7Sderaadt errs++;
401df930be7Sderaadt }
402df930be7Sderaadt }
403df930be7Sderaadt printf("\n");
404df930be7Sderaadt return (errs);
405df930be7Sderaadt }
406df930be7Sderaadt
407df930be7Sderaadt void
bwrite(int fd,char * buf,daddr_t blk,long size)4081abdbfdeSderaadt bwrite(int fd, char *buf, daddr_t blk, long size)
409df930be7Sderaadt {
410df930be7Sderaadt int i;
411df930be7Sderaadt char *cp;
412df930be7Sderaadt off_t offset;
413df930be7Sderaadt
414df930be7Sderaadt if (fd < 0)
415df930be7Sderaadt return;
416df930be7Sderaadt offset = blk;
41717af71c1Skrw offset *= DEV_BSIZE;
4181593d282Skrw if (pwrite(fd, buf, size, offset) == size) {
419df930be7Sderaadt fsmodified = 1;
420df930be7Sderaadt return;
421df930be7Sderaadt }
422df930be7Sderaadt rwerror("WRITE", blk);
423df930be7Sderaadt printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
42417af71c1Skrw for (cp = buf, i = 0; i < size; i += secsize, cp += secsize)
4251593d282Skrw if (pwrite(fd, cp, secsize, offset + i) != secsize) {
42617af71c1Skrw if (secsize != DEV_BSIZE)
42717af71c1Skrw printf(" %lld (%lld),",
4285480ff59Skrw (long long)(offset + i) / secsize,
4295480ff59Skrw (long long)blk + i / DEV_BSIZE);
43017af71c1Skrw else
4315480ff59Skrw printf(" %lld,", (long long)blk +
4325480ff59Skrw i / DEV_BSIZE);
433df930be7Sderaadt }
434df930be7Sderaadt printf("\n");
435df930be7Sderaadt return;
436df930be7Sderaadt }
437df930be7Sderaadt
438df930be7Sderaadt /*
439df930be7Sderaadt * allocate a data block with the specified number of fragments
440df930be7Sderaadt */
4416a0422b3Sguenther daddr_t
allocblk(int frags)4426a0422b3Sguenther allocblk(int frags)
443df930be7Sderaadt {
4446a0422b3Sguenther daddr_t i, baseblk;
4456a0422b3Sguenther int j, k, cg;
4462062fcb1Sotto struct bufarea *cgbp;
4472062fcb1Sotto struct cg *cgp;
448df930be7Sderaadt
449df930be7Sderaadt if (frags <= 0 || frags > sblock.fs_frag)
450df930be7Sderaadt return (0);
451df930be7Sderaadt for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) {
452df930be7Sderaadt for (j = 0; j <= sblock.fs_frag - frags; j++) {
453df930be7Sderaadt if (testbmap(i + j))
454df930be7Sderaadt continue;
455df930be7Sderaadt for (k = 1; k < frags; k++)
456df930be7Sderaadt if (testbmap(i + j + k))
457df930be7Sderaadt break;
458df930be7Sderaadt if (k < frags) {
459df930be7Sderaadt j += k;
460df930be7Sderaadt continue;
461df930be7Sderaadt }
462767b3369Sart cg = dtog(&sblock, i + j);
4632062fcb1Sotto cgbp = cglookup(cg);
4642062fcb1Sotto cgp = cgbp->b_un.b_cg;
465767b3369Sart if (!cg_chkmagic(cgp))
466767b3369Sart pfatal("CG %d: BAD MAGIC NUMBER\n", cg);
467767b3369Sart baseblk = dtogd(&sblock, i + j);
468767b3369Sart
469767b3369Sart for (k = 0; k < frags; k++) {
470df930be7Sderaadt setbmap(i + j + k);
471767b3369Sart clrbit(cg_blksfree(cgp), baseblk + k);
472767b3369Sart }
473df930be7Sderaadt n_blks += frags;
474767b3369Sart if (frags == sblock.fs_frag)
475767b3369Sart cgp->cg_cs.cs_nbfree--;
476767b3369Sart else
477767b3369Sart cgp->cg_cs.cs_nffree -= frags;
478df930be7Sderaadt return (i + j);
479df930be7Sderaadt }
480df930be7Sderaadt }
481df930be7Sderaadt return (0);
482df930be7Sderaadt }
483df930be7Sderaadt
484df930be7Sderaadt /*
485df930be7Sderaadt * Free a previously allocated block
486df930be7Sderaadt */
487df930be7Sderaadt void
freeblk(daddr_t blkno,int frags)4886a0422b3Sguenther freeblk(daddr_t blkno, int frags)
489df930be7Sderaadt {
490df930be7Sderaadt struct inodesc idesc;
491df930be7Sderaadt
492df930be7Sderaadt idesc.id_blkno = blkno;
493df930be7Sderaadt idesc.id_numfrags = frags;
494df930be7Sderaadt (void)pass4check(&idesc);
495df930be7Sderaadt }
496df930be7Sderaadt
497df930be7Sderaadt /*
498df930be7Sderaadt * Find a pathname
499df930be7Sderaadt */
500df930be7Sderaadt void
getpathname(char * namebuf,size_t namebuflen,ino_t curdir,ino_t ino)50159b30be9Sderaadt getpathname(char *namebuf, size_t namebuflen, ino_t curdir, ino_t ino)
502df930be7Sderaadt {
503df930be7Sderaadt int len;
504e073c79dSmpech char *cp;
505df930be7Sderaadt struct inodesc idesc;
506df930be7Sderaadt static int busy = 0;
507df930be7Sderaadt
508df930be7Sderaadt if (curdir == ino && ino == ROOTINO) {
50959b30be9Sderaadt (void)strlcpy(namebuf, "/", namebuflen);
510df930be7Sderaadt return;
511df930be7Sderaadt }
512df930be7Sderaadt if (busy ||
5134aab0ea5Sotto (GET_ISTATE(curdir) != DSTATE && GET_ISTATE(curdir) != DFOUND)) {
51459b30be9Sderaadt (void)strlcpy(namebuf, "?", namebuflen);
515df930be7Sderaadt return;
516df930be7Sderaadt }
517df930be7Sderaadt busy = 1;
518df930be7Sderaadt memset(&idesc, 0, sizeof(struct inodesc));
519df930be7Sderaadt idesc.id_type = DATA;
520df930be7Sderaadt idesc.id_fix = IGNORE;
521b9fc9a72Sderaadt cp = &namebuf[PATH_MAX - 1];
522df930be7Sderaadt *cp = '\0';
523df930be7Sderaadt if (curdir != ino) {
524df930be7Sderaadt idesc.id_parent = curdir;
525df930be7Sderaadt goto namelookup;
526df930be7Sderaadt }
527df930be7Sderaadt while (ino != ROOTINO) {
528df930be7Sderaadt idesc.id_number = ino;
529df930be7Sderaadt idesc.id_func = findino;
530df930be7Sderaadt idesc.id_name = "..";
531df930be7Sderaadt if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
532df930be7Sderaadt break;
533df930be7Sderaadt namelookup:
534df930be7Sderaadt idesc.id_number = idesc.id_parent;
535df930be7Sderaadt idesc.id_parent = ino;
536df930be7Sderaadt idesc.id_func = findname;
537df930be7Sderaadt idesc.id_name = namebuf;
538df930be7Sderaadt if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
539df930be7Sderaadt break;
540df930be7Sderaadt len = strlen(namebuf);
541df930be7Sderaadt cp -= len;
542b3f5508eSmillert memmove(cp, namebuf, (size_t)len);
543df930be7Sderaadt *--cp = '/';
544df930be7Sderaadt if (cp < &namebuf[MAXNAMLEN])
545df930be7Sderaadt break;
546df930be7Sderaadt ino = idesc.id_number;
547df930be7Sderaadt }
548df930be7Sderaadt busy = 0;
549df930be7Sderaadt if (ino != ROOTINO)
550df930be7Sderaadt *--cp = '?';
551b3f5508eSmillert memmove(namebuf, cp, (size_t)(&namebuf[PATH_MAX] - cp));
552df930be7Sderaadt }
553df930be7Sderaadt
554df930be7Sderaadt void
catch(int signo)55519988433Sderaadt catch(int signo)
556df930be7Sderaadt {
5576d85caccSderaadt ckfini(0); /* XXX signal race */
5586d85caccSderaadt _exit(12);
559df930be7Sderaadt }
560df930be7Sderaadt
561df930be7Sderaadt /*
562df930be7Sderaadt * When preening, allow a single quit to signal
563df930be7Sderaadt * a special exit after filesystem checks complete
564df930be7Sderaadt * so that reboot sequence may be interrupted.
565df930be7Sderaadt */
566df930be7Sderaadt void
catchquit(int signo)56719988433Sderaadt catchquit(int signo)
568df930be7Sderaadt {
56942dc680dSderaadt extern volatile sig_atomic_t returntosingle;
5709d5ab9dfSguenther static const char message[] =
5719d5ab9dfSguenther "returning to single-user after filesystem check\n";
572df930be7Sderaadt
5739d5ab9dfSguenther write(STDOUT_FILENO, message, sizeof(message)-1);
574df930be7Sderaadt returntosingle = 1;
575df930be7Sderaadt (void)signal(SIGQUIT, SIG_DFL);
576df930be7Sderaadt }
577df930be7Sderaadt
578df930be7Sderaadt /*
579df930be7Sderaadt * Ignore a single quit signal; wait and flush just in case.
580df930be7Sderaadt * Used by child processes in preen.
581df930be7Sderaadt */
582df930be7Sderaadt void
voidquit(int signo)58319988433Sderaadt voidquit(int signo)
584df930be7Sderaadt {
58519988433Sderaadt int save_errno = errno;
586df930be7Sderaadt
587df930be7Sderaadt sleep(1);
588df930be7Sderaadt (void)signal(SIGQUIT, SIG_IGN);
589df930be7Sderaadt (void)signal(SIGQUIT, SIG_DFL);
59019988433Sderaadt errno = save_errno;
591df930be7Sderaadt }
592df930be7Sderaadt
593df930be7Sderaadt /*
594df930be7Sderaadt * determine whether an inode should be fixed.
595df930be7Sderaadt */
596df930be7Sderaadt int
dofix(struct inodesc * idesc,char * msg)59760d6b16fSgluk dofix(struct inodesc *idesc, char *msg)
598df930be7Sderaadt {
599df930be7Sderaadt switch (idesc->id_fix) {
600df930be7Sderaadt
601df930be7Sderaadt case DONTKNOW:
602df930be7Sderaadt if (idesc->id_type == DATA)
603df930be7Sderaadt direrror(idesc->id_number, msg);
604df930be7Sderaadt else
6052cc28a79Saaron pwarn("%s", msg);
606df930be7Sderaadt if (preen) {
607df930be7Sderaadt printf(" (SALVAGED)\n");
608df930be7Sderaadt idesc->id_fix = FIX;
609df930be7Sderaadt return (ALTERED);
610df930be7Sderaadt }
611df930be7Sderaadt if (reply("SALVAGE") == 0) {
612df930be7Sderaadt idesc->id_fix = NOFIX;
613df930be7Sderaadt return (0);
614df930be7Sderaadt }
615df930be7Sderaadt idesc->id_fix = FIX;
616df930be7Sderaadt return (ALTERED);
617df930be7Sderaadt
618df930be7Sderaadt case FIX:
619df930be7Sderaadt return (ALTERED);
620df930be7Sderaadt
621df930be7Sderaadt case NOFIX:
622df930be7Sderaadt case IGNORE:
623df930be7Sderaadt return (0);
624df930be7Sderaadt
625df930be7Sderaadt default:
626abbb3558Sotto errexit("UNKNOWN INODESC FIX MODE %u\n", idesc->id_fix);
627df930be7Sderaadt }
628df930be7Sderaadt /* NOTREACHED */
629df930be7Sderaadt }
630af9e537cSd
631379d1969Sderaadt int (* info_fn)(char *, size_t) = NULL;
632af9e537cSd char *info_filesys = "?";
633af9e537cSd
634af9e537cSd void
catchinfo(int signo)635379d1969Sderaadt catchinfo(int signo)
636af9e537cSd {
6373aa8caa7Sderaadt static int info_fd;
6383aa8caa7Sderaadt int save_errno = errno;
639af9e537cSd struct iovec iov[4];
6403883fb93Sderaadt char buf[1024];
641af9e537cSd
6423aa8caa7Sderaadt if (signo == 0) {
6433aa8caa7Sderaadt info_fd = open(_PATH_TTY, O_WRONLY);
6443aa8caa7Sderaadt signal(SIGINFO, catchinfo);
6453aa8caa7Sderaadt } else if (info_fd > 0 && info_fn != NULL && info_fn(buf, sizeof buf)) {
646af9e537cSd iov[0].iov_base = info_filesys;
647af9e537cSd iov[0].iov_len = strlen(info_filesys);
648af9e537cSd iov[1].iov_base = ": ";
649af9e537cSd iov[1].iov_len = sizeof ": " - 1;
650af9e537cSd iov[2].iov_base = buf;
651af9e537cSd iov[2].iov_len = strlen(buf);
652af9e537cSd iov[3].iov_base = "\n";
653af9e537cSd iov[3].iov_len = sizeof "\n" - 1;
654af9e537cSd
6553aa8caa7Sderaadt writev(info_fd, iov, 4);
656af9e537cSd }
657d4a55c7bSderaadt errno = save_errno;
658af9e537cSd }
6592062fcb1Sotto /*
6602062fcb1Sotto * Attempt to flush a cylinder group cache entry.
6612062fcb1Sotto * Return whether the flush was successful.
6622062fcb1Sotto */
6632062fcb1Sotto static int
flushentry(void)6642062fcb1Sotto flushentry(void)
6652062fcb1Sotto {
6662062fcb1Sotto struct bufarea *cgbp;
6672062fcb1Sotto
6682062fcb1Sotto if (flushtries == sblock.fs_ncg || cgbufs == NULL)
6692062fcb1Sotto return (0);
6702062fcb1Sotto cgbp = &cgbufs[flushtries++];
6712062fcb1Sotto if (cgbp->b_un.b_cg == NULL)
6722062fcb1Sotto return (0);
6732062fcb1Sotto flush(fswritefd, cgbp);
6742062fcb1Sotto free(cgbp->b_un.b_buf);
6752062fcb1Sotto cgbp->b_un.b_buf = NULL;
6762062fcb1Sotto return (1);
6772062fcb1Sotto }
6782062fcb1Sotto
6792062fcb1Sotto /*
6802062fcb1Sotto * Wrapper for malloc() that flushes the cylinder group cache to try
6812062fcb1Sotto * to get space.
6822062fcb1Sotto */
6832062fcb1Sotto void *
Malloc(size_t size)6842062fcb1Sotto Malloc(size_t size)
6852062fcb1Sotto {
6862062fcb1Sotto void *retval;
6872062fcb1Sotto
6882062fcb1Sotto while ((retval = malloc(size)) == NULL)
6892062fcb1Sotto if (flushentry() == 0)
6902062fcb1Sotto break;
6912062fcb1Sotto return (retval);
6922062fcb1Sotto }
6932062fcb1Sotto
6942062fcb1Sotto /*
6952062fcb1Sotto * Wrapper for calloc() that flushes the cylinder group cache to try
6962062fcb1Sotto * to get space.
6972062fcb1Sotto */
6982062fcb1Sotto void*
Calloc(size_t cnt,size_t size)6992062fcb1Sotto Calloc(size_t cnt, size_t size)
7002062fcb1Sotto {
7012062fcb1Sotto void *retval;
7022062fcb1Sotto
7032062fcb1Sotto while ((retval = calloc(cnt, size)) == NULL)
7042062fcb1Sotto if (flushentry() == 0)
7052062fcb1Sotto break;
7062062fcb1Sotto return (retval);
7072062fcb1Sotto }
7082062fcb1Sotto
7092062fcb1Sotto /*
7102062fcb1Sotto * Wrapper for reallocarray() that flushes the cylinder group cache to try
7112062fcb1Sotto * to get space.
7122062fcb1Sotto */
7132062fcb1Sotto void*
Reallocarray(void * p,size_t cnt,size_t size)7142062fcb1Sotto Reallocarray(void *p, size_t cnt, size_t size)
7152062fcb1Sotto {
7162062fcb1Sotto void *retval;
7172062fcb1Sotto
7182062fcb1Sotto while ((retval = reallocarray(p, cnt, size)) == NULL)
7192062fcb1Sotto if (flushentry() == 0)
7202062fcb1Sotto break;
7212062fcb1Sotto return (retval);
7222062fcb1Sotto }
723