utilities.c revision 1.39 1 /* $NetBSD: utilities.c,v 1.39 2015/07/24 06:59:32 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(EXIT_FAILURE, "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%jx\n",
122 (uintmax_t)lfs_sb_getidaddr(fs));
123 lfs_writesuper(fs, lfs_sb_getsboff(fs, 0));
124 lfs_writesuper(fs, lfs_sb_getsboff(fs, 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 && (lfs_sb_getpflags(fs) & LFS_PF_CLEAN) == 0) {
142 lfs_sb_setpflags(fs, lfs_sb_getpflags(fs) | 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 lfs_sb_setpflags(fs, lfs_sb_getpflags(fs) | 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", idesc->id_fix);
278 }
279 /* NOTREACHED */
280 }
281