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