utilities.c revision 1.11 1 /* $NetBSD: utilities.c,v 1.11 2003/03/28 08:09:55 perseant 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. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/param.h>
37 #include <sys/time.h>
38
39 #include <ufs/ufs/dinode.h>
40 #include <ufs/ufs/dir.h>
41 #include <sys/mount.h>
42 #include <ufs/lfs/lfs.h>
43
44 #include <err.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <ctype.h>
49 #include <unistd.h>
50
51 #include <signal.h>
52
53 #include "bufcache.h"
54 #include "vnode.h"
55 #include "lfs.h"
56 #include "segwrite.h"
57
58 #include "fsutil.h"
59 #include "fsck.h"
60 #include "extern.h"
61
62 long diskreads, totalreads; /* Disk cache statistics */
63
64 extern int returntosingle;
65 extern off_t locked_queue_bytes;
66
67 int
68 ftypeok(struct dinode * dp)
69 {
70 switch (dp->di_mode & IFMT) {
71
72 case IFDIR:
73 case IFREG:
74 case IFBLK:
75 case IFCHR:
76 case IFLNK:
77 case IFSOCK:
78 case IFIFO:
79 return (1);
80
81 default:
82 if (debug)
83 pwarn("bad file type 0%o\n", dp->di_mode);
84 return (0);
85 }
86 }
87
88 int
89 reply(char *question)
90 {
91 int persevere;
92 char c;
93
94 if (preen)
95 err(1, "INTERNAL ERROR: GOT TO reply()");
96 persevere = !strcmp(question, "CONTINUE");
97 printf("\n");
98 if (!persevere && nflag) {
99 printf("%s? no\n\n", question);
100 return (0);
101 }
102 if (yflag || (persevere && nflag)) {
103 printf("%s? yes\n\n", question);
104 return (1);
105 }
106 do {
107 printf("%s? [yn] ", question);
108 (void) fflush(stdout);
109 c = getc(stdin);
110 while (c != '\n' && getc(stdin) != '\n')
111 if (feof(stdin))
112 return (0);
113 } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
114 printf("\n");
115 if (c == 'y' || c == 'Y')
116 return (1);
117 return (0);
118 }
119
120 static void
121 write_superblocks(void)
122 {
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 (!nflag && locked_queue_bytes > 0) {
132 if (preen || reply("WRITE CHANGES TO DISK") == 1) {
133 lfs_segwrite(fs, SEGM_CKP);
134 fsdirty = 0;
135 fsmodified = 1;
136 }
137 }
138
139 if (fsdirty && !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
140 sbdirty();
141 write_superblocks();
142 }
143 if (markclean && (fs->lfs_pflags & LFS_PF_CLEAN) == 0) {
144 /*
145 * Mark the file system as clean, and sync the superblock.
146 */
147 if (preen)
148 pwarn("MARKING FILE SYSTEM CLEAN\n");
149 else if (!reply("MARK FILE SYSTEM CLEAN"))
150 markclean = 0;
151 if (markclean) {
152 fs->lfs_pflags |= LFS_PF_CLEAN;
153 sbdirty();
154 write_superblocks();
155 if (!preen)
156 printf(
157 "\n***** FILE SYSTEM MARKED CLEAN *****\n");
158 }
159 }
160 if (debug)
161 bufstats();
162 (void) close(fsreadfd);
163 }
164 /*
165 * Free a previously allocated block
166 */
167 void
168 freeblk(daddr_t blkno, long frags)
169 {
170 struct inodesc idesc;
171
172 idesc.id_blkno = blkno;
173 idesc.id_numfrags = frags;
174 (void) pass4check(&idesc);
175 }
176 /*
177 * Find a pathname
178 */
179 void
180 getpathname(char *namebuf, ino_t curdir, ino_t ino)
181 {
182 int len;
183 register char *cp;
184 struct inodesc idesc;
185 static int busy = 0;
186
187 if (curdir == ino && ino == ROOTINO) {
188 (void) strcpy(namebuf, "/");
189 return;
190 }
191 if (busy ||
192 (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) {
193 (void) strcpy(namebuf, "?");
194 return;
195 }
196 busy = 1;
197 memset(&idesc, 0, sizeof(struct inodesc));
198 idesc.id_type = DATA;
199 idesc.id_fix = IGNORE;
200 cp = &namebuf[MAXPATHLEN - 1];
201 *cp = '\0';
202 if (curdir != ino) {
203 idesc.id_parent = curdir;
204 goto namelookup;
205 }
206 while (ino != ROOTINO) {
207 idesc.id_number = ino;
208 idesc.id_func = findino;
209 idesc.id_name = "..";
210 if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
211 break;
212 namelookup:
213 idesc.id_number = idesc.id_parent;
214 idesc.id_parent = ino;
215 idesc.id_func = findname;
216 idesc.id_name = namebuf;
217 if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0)
218 break;
219 len = strlen(namebuf);
220 cp -= len;
221 memcpy(cp, namebuf, (size_t) len);
222 *--cp = '/';
223 if (cp < &namebuf[MAXNAMLEN])
224 break;
225 ino = idesc.id_number;
226 }
227 busy = 0;
228 if (ino != ROOTINO)
229 *--cp = '?';
230 memcpy(namebuf, cp, (size_t) (&namebuf[MAXPATHLEN] - cp));
231 }
232
233 void
234 catch(int n)
235 {
236 ckfini(0);
237 exit(12);
238 }
239 /*
240 * When preening, allow a single quit to signal
241 * a special exit after filesystem checks complete
242 * so that reboot sequence may be interrupted.
243 */
244 void
245 catchquit(int n)
246 {
247 printf("returning to single-user after filesystem check\n");
248 returntosingle = 1;
249 (void) signal(SIGQUIT, SIG_DFL);
250 }
251 /*
252 * Ignore a single quit signal; wait and flush just in case.
253 * Used by child processes in preen.
254 */
255 void
256 voidquit(int n)
257 {
258
259 sleep(1);
260 (void) signal(SIGQUIT, SIG_IGN);
261 (void) signal(SIGQUIT, SIG_DFL);
262 }
263 /*
264 * determine whether an inode should be fixed.
265 */
266 int
267 dofix(struct inodesc * idesc, char *msg)
268 {
269
270 switch (idesc->id_fix) {
271
272 case DONTKNOW:
273 if (idesc->id_type == DATA)
274 direrror(idesc->id_number, msg);
275 else
276 pwarn("%s", msg);
277 if (preen) {
278 printf(" (SALVAGED)\n");
279 idesc->id_fix = FIX;
280 return (ALTERED);
281 }
282 if (reply("SALVAGE") == 0) {
283 idesc->id_fix = NOFIX;
284 return (0);
285 }
286 idesc->id_fix = FIX;
287 return (ALTERED);
288
289 case FIX:
290 return (ALTERED);
291
292 case NOFIX:
293 case IGNORE:
294 return (0);
295
296 default:
297 err(8, "UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
298 }
299 /* NOTREACHED */
300 }
301