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