xref: /netbsd-src/sbin/fsck/fsutil.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: fsutil.c,v 1.16 2006/08/26 18:14:28 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1990, 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/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: fsutil.c,v 1.16 2006/08/26 18:14:28 christos Exp $");
35 #endif /* not lint */
36 
37 #include <sys/param.h>
38 
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <stdarg.h>
43 #include <errno.h>
44 #include <fstab.h>
45 #include <err.h>
46 
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 
50 #include "fsutil.h"
51 
52 static const char *dev = NULL;
53 static int hot = 0;
54 static int preen = 0;
55 int quiet;
56 #define F_ERROR	0x80000000
57 
58 void
59 setcdevname(const char *cd, int pr)
60 {
61 
62 	dev = cd;
63 	preen = pr;
64 }
65 
66 const char *
67 cdevname(void)
68 {
69 
70 	return dev;
71 }
72 
73 int
74 hotroot(void)
75 {
76 
77 	return hot;
78 }
79 
80 /*VARARGS*/
81 void
82 errexit(const char *fmt, ...)
83 {
84 	va_list ap;
85 
86 	va_start(ap, fmt);
87 	(void) vfprintf(stderr, fmt, ap);
88 	va_end(ap);
89 	exit(8);
90 }
91 
92 void
93 vmsg(int fatal, const char *fmt, va_list ap)
94 {
95 	int serr = fatal & F_ERROR;
96 	int serrno = errno;
97 	fatal &= ~F_ERROR;
98 
99 	if (!fatal && preen)
100 		(void)printf("%s: ", dev);
101 	if (quiet && !preen) {
102 		(void)printf("** %s (vmsg)\n", dev);
103 		quiet = 0;
104 	}
105 
106 	(void) vprintf(fmt, ap);
107 	if (serr)
108 		printf(" (%s)", strerror(serrno));
109 
110 	if (fatal && preen)
111 		(void) printf("\n");
112 
113 	if (fatal && preen) {
114 		(void) printf(
115 		    "%s: UNEXPECTED INCONSISTENCY; RUN %s MANUALLY.\n",
116 		    dev, getprogname());
117 		exit(8);
118 	}
119 }
120 
121 /*VARARGS*/
122 void
123 pfatal(const char *fmt, ...)
124 {
125 	va_list ap;
126 
127 	va_start(ap, fmt);
128 	vmsg(1, fmt, ap);
129 	va_end(ap);
130 }
131 
132 /*VARARGS*/
133 void
134 pwarn(const char *fmt, ...)
135 {
136 	va_list ap;
137 
138 	va_start(ap, fmt);
139 	vmsg(0, fmt, ap);
140 	va_end(ap);
141 }
142 
143 void
144 perr(const char *fmt, ...)
145 {
146 	va_list ap;
147 
148 	va_start(ap, fmt);
149 	vmsg(1 | F_ERROR, fmt, ap);
150 	va_end(ap);
151 }
152 
153 void
154 panic(const char *fmt, ...)
155 {
156 	va_list ap;
157 
158 	va_start(ap, fmt);
159 	vmsg(1, fmt, ap);
160 	va_end(ap);
161 	exit(8);
162 }
163 
164 const char *
165 unrawname(const char *name)
166 {
167 	static char unrawbuf[MAXPATHLEN];
168 	const char *dp;
169 	struct stat stb;
170 
171 	if ((dp = strrchr(name, '/')) == 0)
172 		return (name);
173 	if (stat(name, &stb) < 0)
174 		return (name);
175 	if (!S_ISCHR(stb.st_mode))
176 		return (name);
177 	if (dp[1] != 'r')
178 		return (name);
179 	(void)snprintf(unrawbuf, sizeof(unrawbuf), "%.*s/%s",
180 	    (int)(dp - name), name, dp + 2);
181 	return (unrawbuf);
182 }
183 
184 const char *
185 rawname(const char *name)
186 {
187 	static char rawbuf[MAXPATHLEN];
188 	const char *dp;
189 
190 	if ((dp = strrchr(name, '/')) == 0)
191 		return (0);
192 	(void)snprintf(rawbuf, sizeof(rawbuf), "%.*s/r%s",
193 	    (int)(dp - name), name, dp + 1);
194 	return (rawbuf);
195 }
196 
197 const char *
198 blockcheck(const char *origname)
199 {
200 	struct stat stslash, stblock, stchar;
201 	const char *newname, *raw;
202 	struct fstab *fsp;
203 	int retried = 0;
204 
205 	hot = 0;
206 	if (stat("/", &stslash) < 0) {
207 		perr("Can't stat `/'");
208 		return (origname);
209 	}
210 	newname = origname;
211 retry:
212 	if (stat(newname, &stblock) < 0) {
213 		perr("Can't stat `%s'", newname);
214 		return (origname);
215 	}
216 	if (S_ISBLK(stblock.st_mode)) {
217 		if (stslash.st_dev == stblock.st_rdev)
218 			hot++;
219 		raw = rawname(newname);
220 		if (stat(raw, &stchar) < 0) {
221 			perr("Can't stat `%s'", raw);
222 			return (origname);
223 		}
224 		if (S_ISCHR(stchar.st_mode)) {
225 			return (raw);
226 		} else {
227 			printf("%s is not a character device\n", raw);
228 			return (origname);
229 		}
230 	} else if (S_ISCHR(stblock.st_mode) && !retried) {
231 		newname = unrawname(newname);
232 		retried++;
233 		goto retry;
234 	} else if ((fsp = getfsfile(newname)) != 0 && !retried) {
235 		newname = fsp->fs_spec;
236 		retried++;
237 		goto retry;
238 	}
239 	/*
240 	 * Not a block or character device, just return name and
241 	 * let the user decide whether to use it.
242 	 */
243 	return (origname);
244 }
245