1/* $NetBSD: utilities.c,v 1.30 2010/01/07 04:21:28 christos 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#include <ufs/ufs/inode.h>
37#include <ufs/ufs/dir.h>
38#define buf ubuf
39#define vnode uvnode
40#include <ufs/lfs/lfs.h>
41
42#include <err.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <ctype.h>
47#include <unistd.h>
48#include <errno.h>
49
50#include <signal.h>
51
52#include "bufcache.h"
53#include "vnode.h"
54#include "lfs_user.h"
55#include "segwrite.h"
56
57#include "fsutil.h"
58#include "fsck.h"
59#include "extern.h"
60#include "exitvalues.h"
61
62long diskreads, totalreads;	/* Disk cache statistics */
63
64extern off_t locked_queue_bytes;
65
66int
67ftypeok(struct ufs1_dinode * dp)
68{
69	switch (dp->di_mode & IFMT) {
70
71	case IFDIR:
72	case IFREG:
73	case IFBLK:
74	case IFCHR:
75	case IFLNK:
76	case IFSOCK:
77	case IFIFO:
78		return (1);
79
80	default:
81		if (debug)
82			pwarn("bad file type 0%o\n", dp->di_mode);
83		return (0);
84	}
85}
86
87int
88reply(const char *question)
89{
90	int persevere;
91	char c;
92
93	if (preen)
94		err(1, "INTERNAL ERROR: GOT TO reply()");
95	persevere = !strcmp(question, "CONTINUE");
96	pwarn("\n");
97	if (!persevere && nflag) {
98		printf("%s? no\n\n", question);
99		return (0);
100	}
101	if (yflag || (persevere && nflag)) {
102		printf("%s? yes\n\n", question);
103		return (1);
104	}
105	do {
106		printf("%s? [yn] ", question);
107		(void) fflush(stdout);
108		c = getc(stdin);
109		while (c != '\n' && getc(stdin) != '\n')
110			if (feof(stdin))
111				return (0);
112	} while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
113	printf("\n");
114	if (c == 'y' || c == 'Y')
115		return (1);
116	return (0);
117}
118
119static void
120write_superblocks(void)
121{
122	if (debug)
123		pwarn("writing superblocks with lfs_idaddr = 0x%x\n",
124			(int)fs->lfs_idaddr);
125	lfs_writesuper(fs, fs->lfs_sboffs[0]);
126	lfs_writesuper(fs, fs->lfs_sboffs[1]);
127	fsmodified = 1;
128}
129
130void
131ckfini(int markclean)
132{
133	if (locked_queue_bytes > 0) {
134		if (preen || reply("WRITE CHANGES TO DISK") == 1) {
135			if (preen == 0)
136				pwarn("WRITING CHANGES TO DISK\n");
137			lfs_segwrite(fs, SEGM_CKP);
138			fsdirty = 0;
139			fsmodified = 1;
140		}
141	}
142
143	if (!nflag && (fs->lfs_pflags & LFS_PF_CLEAN) == 0) {
144		fs->lfs_pflags |= LFS_PF_CLEAN;
145		fsmodified = 1;
146	}
147
148	if (fsmodified && (preen || reply("UPDATE SUPERBLOCKS"))) {
149		sbdirty();
150		write_superblocks();
151	}
152	if (markclean && fsmodified) {
153		/*
154		 * Mark the file system as clean, and sync the superblock.
155		 */
156		if (preen)
157			pwarn("MARKING FILE SYSTEM CLEAN\n");
158		else if (!reply("MARK FILE SYSTEM CLEAN"))
159			markclean = 0;
160		if (markclean) {
161			fs->lfs_pflags |= LFS_PF_CLEAN;
162			sbdirty();
163			write_superblocks();
164			if (!preen)
165				printf(
166					"\n***** FILE SYSTEM MARKED CLEAN *****\n");
167		}
168	}
169
170	if (debug)
171		bufstats();
172	(void) close(fsreadfd);
173}
174/*
175 * Free a previously allocated block
176 */
177void
178freeblk(daddr_t blkno, long frags)
179{
180	struct inodesc idesc;
181
182	idesc.id_blkno = blkno;
183	idesc.id_numfrags = frags;
184	(void) pass4check(&idesc);
185}
186/*
187 * Find a pathname
188 */
189void
190getpathname(char *namebuf, size_t namebuflen, ino_t curdir, ino_t ino)
191{
192	int len;
193	char *cp;
194	struct inodesc idesc;
195	static int busy = 0;
196
197	if (curdir == ino && ino == ROOTINO) {
198		(void) strlcpy(namebuf, "/", namebuflen);
199		return;
200	}
201	if (busy ||
202	    (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) {
203		(void) strlcpy(namebuf, "?", namebuflen);
204		return;
205	}
206	busy = 1;
207	memset(&idesc, 0, sizeof(struct inodesc));
208	idesc.id_type = DATA;
209	idesc.id_fix = IGNORE;
210	cp = &namebuf[MAXPATHLEN - 1];
211	*cp = '\0';
212	if (curdir != ino) {
213		idesc.id_parent = curdir;
214		goto namelookup;
215	}
216	while (ino != ROOTINO) {
217		idesc.id_number = ino;
218		idesc.id_func = findino;
219		idesc.id_name = "..";
220		if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
221			break;
222namelookup:
223		idesc.id_number = idesc.id_parent;
224		idesc.id_parent = ino;
225		idesc.id_func = findname;
226		idesc.id_name = namebuf;
227		if (ginode(idesc.id_number) == NULL)
228			break;
229		if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0)
230			break;
231		len = strlen(namebuf);
232		cp -= len;
233		memcpy(cp, namebuf, (size_t) len);
234		*--cp = '/';
235		if (cp < &namebuf[LFS_MAXNAMLEN])
236			break;
237		ino = idesc.id_number;
238	}
239	busy = 0;
240	if (ino != ROOTINO)
241		*--cp = '?';
242	memcpy(namebuf, cp, (size_t) (&namebuf[MAXPATHLEN] - cp));
243}
244
245/*
246 * determine whether an inode should be fixed.
247 */
248int
249dofix(struct inodesc * idesc, const char *msg)
250{
251
252	switch (idesc->id_fix) {
253
254	case DONTKNOW:
255		if (idesc->id_type == DATA)
256			direrror(idesc->id_number, msg);
257		else
258			pwarn("%s", msg);
259		if (preen) {
260			printf(" (SALVAGED)\n");
261			idesc->id_fix = FIX;
262			return (ALTERED);
263		}
264		if (reply("SALVAGE") == 0) {
265			idesc->id_fix = NOFIX;
266			return (0);
267		}
268		idesc->id_fix = FIX;
269		return (ALTERED);
270
271	case FIX:
272		return (ALTERED);
273
274	case NOFIX:
275	case IGNORE:
276		return (0);
277
278	default:
279		err(EEXIT, "UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
280	}
281	/* NOTREACHED */
282}
283