xref: /netbsd-src/sbin/fsck_lfs/utilities.c (revision 6d322f2f4598f0d8a138f10ea648ec4fabe41f8b)
1 /* $NetBSD: utilities.c,v 1.35 2013/06/08 02:16:03 dholland Exp $	 */
2 
3 /*
4  * Copyright (c) 1980, 1986, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/param.h>
33 #include <sys/time.h>
34 #include <sys/mount.h>
35 
36 #define buf ubuf
37 #define vnode uvnode
38 #include <ufs/lfs/lfs.h>
39 
40 #include <err.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <ctype.h>
45 #include <unistd.h>
46 #include <errno.h>
47 
48 #include <signal.h>
49 
50 #include "bufcache.h"
51 #include "vnode.h"
52 #include "lfs_user.h"
53 #include "segwrite.h"
54 
55 #include "fsutil.h"
56 #include "fsck.h"
57 #include "extern.h"
58 #include "exitvalues.h"
59 
60 long diskreads, totalreads;	/* Disk cache statistics */
61 
62 extern off_t locked_queue_bytes;
63 
64 int
65 ftypeok(struct ulfs1_dinode * dp)
66 {
67 	switch (dp->di_mode & LFS_IFMT) {
68 
69 	case LFS_IFDIR:
70 	case LFS_IFREG:
71 	case LFS_IFBLK:
72 	case LFS_IFCHR:
73 	case LFS_IFLNK:
74 	case LFS_IFSOCK:
75 	case LFS_IFIFO:
76 		return (1);
77 
78 	default:
79 		if (debug)
80 			pwarn("bad file type 0%o\n", dp->di_mode);
81 		return (0);
82 	}
83 }
84 
85 int
86 reply(const char *question)
87 {
88 	int persevere;
89 	char c;
90 
91 	if (preen)
92 		err(1, "INTERNAL ERROR: GOT TO reply()");
93 	persevere = !strcmp(question, "CONTINUE");
94 	pwarn("\n");
95 	if (!persevere && nflag) {
96 		printf("%s? no\n\n", question);
97 		return (0);
98 	}
99 	if (yflag || (persevere && nflag)) {
100 		printf("%s? yes\n\n", question);
101 		return (1);
102 	}
103 	do {
104 		printf("%s? [yn] ", question);
105 		(void) fflush(stdout);
106 		c = getc(stdin);
107 		while (c != '\n' && getc(stdin) != '\n')
108 			if (feof(stdin))
109 				return (0);
110 	} while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
111 	printf("\n");
112 	if (c == 'y' || c == 'Y')
113 		return (1);
114 	return (0);
115 }
116 
117 static void
118 write_superblocks(void)
119 {
120 	if (debug)
121 		pwarn("writing superblocks with lfs_idaddr = 0x%x\n",
122 			(int)fs->lfs_idaddr);
123 	lfs_writesuper(fs, fs->lfs_sboffs[0]);
124 	lfs_writesuper(fs, fs->lfs_sboffs[1]);
125 	fsmodified = 1;
126 }
127 
128 void
129 ckfini(int markclean)
130 {
131 	if (locked_queue_bytes > 0) {
132 		if (preen || reply("WRITE CHANGES TO DISK") == 1) {
133 			if (preen == 0)
134 				pwarn("WRITING CHANGES TO DISK\n");
135 			lfs_segwrite(fs, SEGM_CKP);
136 			fsdirty = 0;
137 			fsmodified = 1;
138 		}
139 	}
140 
141 	if (!nflag && (fs->lfs_pflags & LFS_PF_CLEAN) == 0) {
142 		fs->lfs_pflags |= LFS_PF_CLEAN;
143 		fsmodified = 1;
144 	}
145 
146 	if (fsmodified && (preen || reply("UPDATE SUPERBLOCKS"))) {
147 		sbdirty();
148 		write_superblocks();
149 	}
150 	if (markclean && fsmodified) {
151 		/*
152 		 * Mark the file system as clean, and sync the superblock.
153 		 */
154 		if (preen)
155 			pwarn("MARKING FILE SYSTEM CLEAN\n");
156 		else if (!reply("MARK FILE SYSTEM CLEAN"))
157 			markclean = 0;
158 		if (markclean) {
159 			fs->lfs_pflags |= LFS_PF_CLEAN;
160 			sbdirty();
161 			write_superblocks();
162 			if (!preen)
163 				printf(
164 					"\n***** FILE SYSTEM MARKED CLEAN *****\n");
165 		}
166 	}
167 
168 	if (debug)
169 		bufstats();
170 	(void) close(fsreadfd);
171 }
172 /*
173  * Free a previously allocated block
174  */
175 void
176 freeblk(daddr_t blkno, long frags)
177 {
178 	struct inodesc idesc;
179 
180 	idesc.id_blkno = blkno;
181 	idesc.id_numfrags = frags;
182 	(void) pass4check(&idesc);
183 }
184 /*
185  * Find a pathname
186  */
187 void
188 getpathname(char *namebuf, size_t namebuflen, ino_t curdir, ino_t ino)
189 {
190 	int len;
191 	char *cp;
192 	struct inodesc idesc;
193 	static int busy = 0;
194 
195 	if (curdir == ino && ino == ULFS_ROOTINO) {
196 		(void) strlcpy(namebuf, "/", namebuflen);
197 		return;
198 	}
199 	if (busy ||
200 	    (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) {
201 		(void) strlcpy(namebuf, "?", namebuflen);
202 		return;
203 	}
204 	busy = 1;
205 	memset(&idesc, 0, sizeof(struct inodesc));
206 	idesc.id_type = DATA;
207 	idesc.id_fix = IGNORE;
208 	cp = &namebuf[MAXPATHLEN - 1];
209 	*cp = '\0';
210 	if (curdir != ino) {
211 		idesc.id_parent = curdir;
212 		goto namelookup;
213 	}
214 	while (ino != ULFS_ROOTINO) {
215 		idesc.id_number = ino;
216 		idesc.id_func = findino;
217 		idesc.id_name = "..";
218 		if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
219 			break;
220 namelookup:
221 		idesc.id_number = idesc.id_parent;
222 		idesc.id_parent = ino;
223 		idesc.id_func = findname;
224 		idesc.id_name = namebuf;
225 		if (ginode(idesc.id_number) == NULL)
226 			break;
227 		if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0)
228 			break;
229 		len = strlen(namebuf);
230 		cp -= len;
231 		memcpy(cp, namebuf, (size_t) len);
232 		*--cp = '/';
233 		if (cp < &namebuf[LFS_MAXNAMLEN])
234 			break;
235 		ino = idesc.id_number;
236 	}
237 	busy = 0;
238 	if (ino != ULFS_ROOTINO)
239 		*--cp = '?';
240 	memcpy(namebuf, cp, (size_t) (&namebuf[MAXPATHLEN] - cp));
241 }
242 
243 /*
244  * determine whether an inode should be fixed.
245  */
246 int
247 dofix(struct inodesc * idesc, const char *msg)
248 {
249 
250 	switch (idesc->id_fix) {
251 
252 	case DONTKNOW:
253 		if (idesc->id_type == DATA)
254 			direrror(idesc->id_number, msg);
255 		else
256 			pwarn("%s", msg);
257 		if (preen) {
258 			printf(" (SALVAGED)\n");
259 			idesc->id_fix = FIX;
260 			return (ALTERED);
261 		}
262 		if (reply("SALVAGE") == 0) {
263 			idesc->id_fix = NOFIX;
264 			return (0);
265 		}
266 		idesc->id_fix = FIX;
267 		return (ALTERED);
268 
269 	case FIX:
270 		return (ALTERED);
271 
272 	case NOFIX:
273 	case IGNORE:
274 		return (0);
275 
276 	default:
277 		err(EEXIT, "UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
278 	}
279 	/* NOTREACHED */
280 }
281