fsutil.c revision 1.25 1 /* $NetBSD: fsutil.c,v 1.25 2015/06/21 03:58:36 dholland 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.25 2015/06/21 03:58:36 dholland 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 <fcntl.h>
46 #include <unistd.h>
47 #include <err.h>
48 #include <util.h>
49
50 #include <sys/types.h>
51 #include <sys/stat.h>
52
53 #include "fsutil.h"
54 #include "exitvalues.h"
55
56 volatile sig_atomic_t returntosingle;
57
58 static const char *dev = NULL;
59 static int hot = 0;
60 static int preen = 0;
61 int quiet;
62 #define F_ERROR 0x80000000
63
64 void
65 setcdevname(const char *cd, int pr)
66 {
67
68 dev = cd;
69 preen = pr;
70 }
71
72 const char *
73 cdevname(void)
74 {
75
76 return dev;
77 }
78
79 int
80 hotroot(void)
81 {
82
83 return hot;
84 }
85
86 /*VARARGS*/
87 void
88 errexit(const char *fmt, ...)
89 {
90 va_list ap;
91
92 va_start(ap, fmt);
93 (void) vfprintf(stderr, fmt, ap);
94 va_end(ap);
95 (void)fprintf(stderr, "\n");
96 exit(FSCK_EXIT_CHECK_FAILED);
97 }
98
99 void
100 vmsg(int fatal, const char *fmt, va_list ap)
101 {
102 int serr = fatal & F_ERROR;
103 int serrno = errno;
104 fatal &= ~F_ERROR;
105
106 if (!fatal && preen)
107 (void)printf("%s: ", dev);
108 if (quiet && !preen) {
109 (void)printf("** %s (vmsg)\n", dev);
110 quiet = 0;
111 }
112
113 (void) vprintf(fmt, ap);
114 if (serr)
115 printf(" (%s)", strerror(serrno));
116
117 if (fatal && preen)
118 (void) printf("\n");
119
120 if (fatal && preen) {
121 (void) printf(
122 "%s: UNEXPECTED INCONSISTENCY; RUN %s MANUALLY.\n",
123 dev, getprogname());
124 exit(FSCK_EXIT_CHECK_FAILED);
125 }
126 }
127
128 /*VARARGS*/
129 void
130 pfatal(const char *fmt, ...)
131 {
132 va_list ap;
133
134 va_start(ap, fmt);
135 vmsg(1, fmt, ap);
136 va_end(ap);
137 }
138
139 /*VARARGS*/
140 void
141 pwarn(const char *fmt, ...)
142 {
143 va_list ap;
144
145 va_start(ap, fmt);
146 vmsg(0, fmt, ap);
147 va_end(ap);
148 }
149
150 void
151 perr(const char *fmt, ...)
152 {
153 va_list ap;
154
155 va_start(ap, fmt);
156 vmsg(1 | F_ERROR, fmt, ap);
157 va_end(ap);
158 }
159
160 void
161 panic(const char *fmt, ...)
162 {
163 va_list ap;
164
165 va_start(ap, fmt);
166 vmsg(1, fmt, ap);
167 va_end(ap);
168 exit(FSCK_EXIT_CHECK_FAILED);
169 }
170
171 const char *
172 blockcheck(const char *origname)
173 {
174 struct stat stslash, stblock, stchar;
175 const char *newname, *raw, *cooked;
176 struct fstab *fsp;
177 int retried = 0;
178 ssize_t len;
179 char cbuf[MAXPATHLEN];
180 static char buf[MAXPATHLEN];
181
182 hot = 0;
183 if (stat("/", &stslash) < 0) {
184 perr("Can't stat `/'");
185 return (origname);
186 }
187 len = readlink(origname, cbuf, sizeof(cbuf)-1);
188 if (len == -1) {
189 newname = origname;
190 } else {
191 cbuf[len] = '\0';
192 newname = cbuf;
193 }
194 retry:
195 if (stat(newname, &stblock) < 0) {
196 perr("Can't stat `%s'", newname);
197 return origname;
198 }
199 if (S_ISBLK(stblock.st_mode)) {
200 if (stslash.st_dev == stblock.st_rdev)
201 hot++;
202 raw = getdiskrawname(buf, sizeof(buf), newname);
203 if (raw == NULL) {
204 perr("Can't convert to raw `%s'", newname);
205 return origname;
206 }
207 if (stat(raw, &stchar) < 0) {
208 perr("Can't stat `%s'", raw);
209 return origname;
210 }
211 if (S_ISCHR(stchar.st_mode)) {
212 return raw;
213 } else {
214 perr("%s is not a character device\n", raw);
215 return origname;
216 }
217 } else if (S_ISCHR(stblock.st_mode) && !retried) {
218 cooked = getdiskcookedname(cbuf, sizeof(cbuf), newname);
219 if (cooked == NULL) {
220 perr("Can't convert to cooked `%s'", newname);
221 return origname;
222 } else
223 newname = cooked;
224 retried++;
225 goto retry;
226 } else if ((fsp = getfsfile(newname)) != 0 && !retried) {
227 newname = getfsspecname(cbuf, sizeof(cbuf), fsp->fs_spec);
228 if (newname == NULL)
229 perr("%s", buf);
230 retried++;
231 goto retry;
232 }
233 /*
234 * Not a block or character device, just return name and
235 * let the user decide whether to use it.
236 */
237 return origname;
238 }
239
240 const char *
241 print_mtime(time_t t)
242 {
243 static char b[128];
244 char *p = ctime(&t);
245 if (p != NULL)
246 (void)snprintf(b, sizeof(b), "%12.12s %4.4s ", &p[4], &p[20]);
247 else
248 (void)snprintf(b, sizeof(b), "%lld ", (long long)t);
249 return b;
250 }
251
252
253 void
254 catch(int n)
255 {
256 if (ckfinish) (*ckfinish)(0);
257 _exit(FSCK_EXIT_SIGNALLED);
258 }
259
260 /*
261 * When preening, allow a single quit to signal
262 * a special exit after filesystem checks complete
263 * so that reboot sequence may be interrupted.
264 */
265 void
266 catchquit(int n)
267 {
268 static const char msg[] =
269 "returning to single-user after filesystem check\n";
270 int serrno = errno;
271
272 (void)write(STDOUT_FILENO, msg, sizeof(msg) - 1);
273 returntosingle = 1;
274 (void)signal(SIGQUIT, SIG_DFL);
275 errno = serrno;
276 }
277
278 /*
279 * Ignore a single quit signal; wait and flush just in case.
280 * Used by child processes in preen.
281 */
282 void
283 voidquit(int n)
284 {
285 int serrno = errno;
286
287 sleep(1);
288 (void)signal(SIGQUIT, SIG_IGN);
289 (void)signal(SIGQUIT, SIG_DFL);
290 errno = serrno;
291 }
292