xref: /openbsd/sbin/fsck/fsutil.c (revision 404b540a)
1 /*	$OpenBSD: fsutil.c,v 1.16 2007/02/17 15:57:14 grunk Exp $	*/
2 /*	$NetBSD: fsutil.c,v 1.2 1996/10/03 20:06:31 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1990, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 #ifndef lint
33 static const char rcsid[] = "$OpenBSD: fsutil.c,v 1.16 2007/02/17 15:57:14 grunk Exp $";
34 #endif /* not lint */
35 
36 #include <sys/param.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <stdarg.h>
41 #include <errno.h>
42 #include <fstab.h>
43 #include <err.h>
44 
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 
48 #include "fsutil.h"
49 
50 static const char *dev = NULL;
51 static int hot = 0;
52 static int preen = 0;
53 
54 extern char *__progname;
55 
56 static void vmsg(int, const char *, va_list);
57 
58 void
59 setcdevname(const char *cd, int pr)
60 {
61 	dev = cd;
62 	preen = pr;
63 }
64 
65 const char *
66 cdevname(void)
67 {
68 	return dev;
69 }
70 
71 int
72 hotroot(void)
73 {
74 	return hot;
75 }
76 
77 /*VARARGS*/
78 void
79 errexit(const char *fmt, ...)
80 {
81 	va_list ap;
82 
83 	va_start(ap, fmt);
84 	(void) vfprintf(stderr, fmt, ap);
85 	va_end(ap);
86 	exit(8);
87 }
88 
89 static void
90 vmsg(int fatal, const char *fmt, va_list ap)
91 {
92 	if (!fatal && preen)
93 		(void) printf("%s: ", dev);
94 
95 	(void) vprintf(fmt, ap);
96 
97 	if (fatal && preen) {
98 		(void) printf("\n");
99 		(void) printf(
100 		    "%s: UNEXPECTED INCONSISTENCY; RUN %s MANUALLY.\n",
101 		    dev, __progname);
102 		exit(8);
103 	}
104 }
105 
106 /*VARARGS*/
107 void
108 pfatal(const char *fmt, ...)
109 {
110 	va_list ap;
111 
112 	va_start(ap, fmt);
113 	vmsg(1, fmt, ap);
114 	va_end(ap);
115 }
116 
117 /*VARARGS*/
118 void
119 pwarn(const char *fmt, ...)
120 {
121 	va_list ap;
122 
123 	va_start(ap, fmt);
124 	vmsg(0, fmt, ap);
125 	va_end(ap);
126 }
127 
128 void
129 xperror(const char *s)
130 {
131 	pfatal("%s (%s)", s, strerror(errno));
132 }
133 
134 void
135 panic(const char *fmt, ...)
136 {
137 	va_list ap;
138 
139 	va_start(ap, fmt);
140 	vmsg(1, fmt, ap);
141 	va_end(ap);
142 	exit(8);
143 }
144 
145 char *
146 unrawname(char *name)
147 {
148 	char *dp;
149 	struct stat stb;
150 
151 	if ((dp = strrchr(name, '/')) == NULL)
152 		return (name);
153 	if (stat(name, &stb) < 0)
154 		return (name);
155 	if (!S_ISCHR(stb.st_mode))
156 		return (name);
157 	if (dp[1] != 'r')
158 		return (name);
159 	(void)memmove(&dp[1], &dp[2], strlen(&dp[2]) + 1);
160 	return (name);
161 }
162 
163 char *
164 rawname(char *name)
165 {
166 	static char rawbuf[MAXPATHLEN];
167 	char *dp;
168 
169 	if ((dp = strrchr(name, '/')) == NULL)
170 		return (0);
171 	*dp = 0;
172 	(void)strlcpy(rawbuf, name, sizeof rawbuf);
173 	*dp = '/';
174 	(void)strlcat(rawbuf, "/r", sizeof rawbuf);
175 	(void)strlcat(rawbuf, &dp[1], sizeof rawbuf);
176 	return (rawbuf);
177 }
178 
179 char *
180 blockcheck(char *origname)
181 {
182 	struct stat stslash, stblock, stchar;
183 	char *newname, *raw;
184 	struct fstab *fsp;
185 	int retried = 0;
186 
187 	hot = 0;
188 	if (stat("/", &stslash) < 0) {
189 		xperror("/");
190 		printf("Can't stat root\n");
191 		return (origname);
192 	}
193 	newname = origname;
194 retry:
195 	if (stat(newname, &stblock) < 0)
196 		return (origname);
197 
198 	if (S_ISBLK(stblock.st_mode)) {
199 		if (stslash.st_dev == stblock.st_rdev)
200 			hot++;
201 		raw = rawname(newname);
202 		if (stat(raw, &stchar) < 0) {
203 			xperror(raw);
204 			printf("Can't stat %s\n", raw);
205 			return (origname);
206 		}
207 		if (S_ISCHR(stchar.st_mode)) {
208 			return (raw);
209 		} else {
210 			printf("%s is not a character device\n", raw);
211 			return (origname);
212 		}
213 	} else if (S_ISCHR(stblock.st_mode) && !retried) {
214 		newname = unrawname(newname);
215 		retried++;
216 		goto retry;
217 	} else if ((fsp = getfsfile(newname)) != 0 && !retried) {
218 		newname = fsp->fs_spec;
219 		retried++;
220 		goto retry;
221 	}
222 	/*
223 	 * Not a block or character device, just return name and
224 	 * let the user decide whether to use it.
225 	 */
226 	return (origname);
227 }
228 
229 
230 void *
231 emalloc(size_t s)
232 {
233 	void *p;
234 
235 	if (s == 0)
236 		err(1, "malloc failed");
237 	p = malloc(s);
238 	if (p == NULL)
239 		err(1, "malloc failed");
240 	return p;
241 }
242 
243 
244 void *
245 erealloc(void *p, size_t s)
246 {
247 	void *newp;
248 
249 	if (s == 0)
250 		err(1, "realloc failed");
251 	newp = realloc(p, s);
252 	if (newp == NULL) {
253 		if (p)
254 			free(p);
255 		err(1, "realloc failed");
256 	}
257 	return newp;
258 }
259 
260 
261 char *
262 estrdup(const char *s)
263 {
264 	char *p = strdup(s);
265 	if (p == NULL)
266 		err(1, "strdup failed");
267 	return p;
268 }
269