1 /* $NetBSD: fsutil.c,v 1.7 1998/07/30 17:41:03 thorpej 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 * $FreeBSD: src/sbin/fsck/fsutil.c,v 1.2.2.1 2001/08/01 05:47:55 obrien Exp $
32 */
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <errno.h>
39 #include <fstab.h>
40 #include <err.h>
41 #include <paths.h>
42
43 #include <sys/param.h>
44 #include <sys/stat.h>
45 #include <sys/mount.h>
46
47 #include "fsutil.h"
48
49 static const char *dev = NULL;
50 static int hot = 0;
51 static int preen = 0;
52
53 extern char *__progname;
54
55 static void vmsg(int, const char *, va_list) __printflike(2, 0);
56
57 void
setcdevname(const char * cd,int pr)58 setcdevname(const char *cd, int pr)
59 {
60 dev = cd;
61 preen = pr;
62 }
63
64 const char *
cdevname(void)65 cdevname(void)
66 {
67 return dev;
68 }
69
70 int
hotroot(void)71 hotroot(void)
72 {
73 return hot;
74 }
75
76 /*VARARGS*/
77 void
errexit(const char * fmt,...)78 errexit(const char *fmt, ...)
79 {
80 va_list ap;
81
82 va_start(ap, fmt);
83 vfprintf(stderr, fmt, ap);
84 va_end(ap);
85 exit(8);
86 }
87
88 static void
vmsg(int fatal,const char * fmt,va_list ap)89 vmsg(int fatal, const char *fmt, va_list ap)
90 {
91 if (!fatal && preen)
92 printf("%s: ", dev);
93
94 vprintf(fmt, ap);
95
96 if (fatal && preen)
97 printf("\n");
98
99 if (fatal && preen) {
100 printf(
101 "%s: UNEXPECTED INCONSISTENCY; RUN %s MANUALLY.\n",
102 dev, __progname);
103 exit(8);
104 }
105 }
106
107 /*VARARGS*/
108 void
pfatal(const char * fmt,...)109 pfatal(const char *fmt, ...)
110 {
111 va_list ap;
112
113 va_start(ap, fmt);
114 vmsg(1, fmt, ap);
115 va_end(ap);
116 }
117
118 /*VARARGS*/
119 void
pwarn(const char * fmt,...)120 pwarn(const char *fmt, ...)
121 {
122 va_list ap;
123 va_start(ap, fmt);
124 vmsg(0, fmt, ap);
125 va_end(ap);
126 }
127
128 void
perr(const char * fmt,...)129 perr(const char *fmt, ...)
130 {
131 va_list ap;
132
133 va_start(ap, fmt);
134 vmsg(1, fmt, ap);
135 va_end(ap);
136 }
137
138 void
perror(const char * s)139 perror(const char *s)
140 {
141 pfatal("%s (%s)", s, strerror(errno));
142 }
143
144 void
panic(const char * fmt,...)145 panic(const char *fmt, ...)
146 {
147 va_list ap;
148
149 va_start(ap, fmt);
150 vmsg(1, fmt, ap);
151 va_end(ap);
152 exit(8);
153 }
154
155 const char *
unrawname(const char * name)156 unrawname(const char *name)
157 {
158 static char unrawbuf[32];
159 const char *dp;
160 struct stat stb;
161
162 if ((dp = strrchr(name, '/')) == NULL)
163 return (name);
164 if (stat(name, &stb) < 0)
165 return (name);
166 if (!S_ISCHR(stb.st_mode))
167 return (name);
168 if (dp[1] != 'r')
169 return (name);
170 snprintf(unrawbuf, 32, "%.*s/%s", (int)(dp - name), name, dp + 2);
171 return (unrawbuf);
172 }
173
174 const char *
rawname(const char * name)175 rawname(const char *name)
176 {
177 static char rawbuf[32];
178 const char *dp;
179
180 if ((dp = strrchr(name, '/')) == NULL)
181 return (0);
182 snprintf(rawbuf, 32, "%.*s/r%s", (int)(dp - name), name, dp + 1);
183 return (rawbuf);
184 }
185
186 const char *
devcheck(const char * origname)187 devcheck(const char *origname)
188 {
189 struct stat stslash, stchar;
190
191 if (stat("/", &stslash) < 0) {
192 perror("/");
193 printf("Can't stat root\n");
194 return (origname);
195 }
196 if (stat(origname, &stchar) < 0) {
197 perror(origname);
198 printf("Can't stat %s\n", origname);
199 return (origname);
200 }
201 if (!S_ISCHR(stchar.st_mode)) {
202 perror(origname);
203 printf("%s is not a char device\n", origname);
204 }
205 return (origname);
206 }
207
208 /*
209 * Get the mount point information for name.
210 */
211 struct statfs *
getmntpt(const char * name)212 getmntpt(const char *name)
213 {
214 struct stat devstat, mntdevstat;
215 char device[sizeof(_PATH_DEV) - 1 + MNAMELEN];
216 char *devname;
217 struct statfs *mntbuf, *statfsp;
218 int i, mntsize, isdev;
219
220 if (stat(name, &devstat) != 0)
221 return (NULL);
222 if (S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode))
223 isdev = 1;
224 else
225 isdev = 0;
226 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
227 for (i = 0; i < mntsize; i++) {
228 statfsp = &mntbuf[i];
229 devname = statfsp->f_mntfromname;
230 if (*devname != '/') {
231 strcpy(device, _PATH_DEV);
232 strcat(device, devname);
233 strcpy(statfsp->f_mntfromname, device);
234 }
235 if (isdev == 0) {
236 if (strcmp(name, statfsp->f_mntonname))
237 continue;
238 return (statfsp);
239 }
240 if (stat(devname, &mntdevstat) == 0 &&
241 mntdevstat.st_rdev == devstat.st_rdev)
242 return (statfsp);
243 }
244 statfsp = NULL;
245 return (statfsp);
246 }
247
248 #if 0
249 /*
250 * XXX this code is from NetBSD, but fails in FreeBSD because we
251 * don't have blockdevs. I don't think its needed.
252 */
253 const char *
254 blockcheck(const char *origname)
255 {
256 struct stat stslash, stblock, stchar;
257 const char *newname, *raw;
258 struct fstab *fsp;
259 int retried = 0;
260
261 hot = 0;
262 if (stat("/", &stslash) < 0) {
263 perror("/");
264 printf("Can't stat root\n");
265 return (origname);
266 }
267 newname = origname;
268 retry:
269 if (stat(newname, &stblock) < 0) {
270 perror(newname);
271 printf("Can't stat %s\n", newname);
272 return (origname);
273 }
274 if (S_ISBLK(stblock.st_mode)) {
275 if (stslash.st_dev == stblock.st_rdev)
276 hot++;
277 raw = rawname(newname);
278 if (stat(raw, &stchar) < 0) {
279 perror(raw);
280 printf("Can't stat %s\n", raw);
281 return (origname);
282 }
283 if (S_ISCHR(stchar.st_mode)) {
284 return (raw);
285 } else {
286 printf("%s is not a character device\n", raw);
287 return (origname);
288 }
289 } else if (S_ISCHR(stblock.st_mode) && !retried) {
290 newname = unrawname(newname);
291 retried++;
292 goto retry;
293 } else if ((fsp = getfsfile(newname)) != 0 && !retried) {
294 newname = fsp->fs_spec;
295 retried++;
296 goto retry;
297 }
298 /*
299 * Not a block or character device, just return name and
300 * let the user decide whether to use it.
301 */
302 return (origname);
303 }
304 #endif
305
306