xref: /openbsd/sbin/fsck/fsutil.c (revision 34c2ea26)
1*34c2ea26Sderaadt /*	$OpenBSD: fsutil.c,v 1.21 2015/05/29 15:57:36 deraadt Exp $	*/
287304b87Stholo /*	$NetBSD: fsutil.c,v 1.2 1996/10/03 20:06:31 christos Exp $	*/
387304b87Stholo 
487304b87Stholo /*
587304b87Stholo  * Copyright (c) 1990, 1993
687304b87Stholo  *	The Regents of the University of California.  All rights reserved.
787304b87Stholo  *
887304b87Stholo  * Redistribution and use in source and binary forms, with or without
987304b87Stholo  * modification, are permitted provided that the following conditions
1087304b87Stholo  * are met:
1187304b87Stholo  * 1. Redistributions of source code must retain the above copyright
1287304b87Stholo  *    notice, this list of conditions and the following disclaimer.
1387304b87Stholo  * 2. Redistributions in binary form must reproduce the above copyright
1487304b87Stholo  *    notice, this list of conditions and the following disclaimer in the
1587304b87Stholo  *    documentation and/or other materials provided with the distribution.
161ef0d710Smillert  * 3. Neither the name of the University nor the names of its contributors
1787304b87Stholo  *    may be used to endorse or promote products derived from this software
1887304b87Stholo  *    without specific prior written permission.
1987304b87Stholo  *
2087304b87Stholo  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2187304b87Stholo  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2287304b87Stholo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2387304b87Stholo  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2487304b87Stholo  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2587304b87Stholo  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2687304b87Stholo  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2787304b87Stholo  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2887304b87Stholo  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2987304b87Stholo  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3087304b87Stholo  * SUCH DAMAGE.
3187304b87Stholo  */
3287304b87Stholo 
3387304b87Stholo #include <stdio.h>
3487304b87Stholo #include <string.h>
3587304b87Stholo #include <stdlib.h>
3687304b87Stholo #include <stdarg.h>
3787304b87Stholo #include <errno.h>
3887304b87Stholo #include <fstab.h>
39b9fc9a72Sderaadt #include <limits.h>
4087304b87Stholo #include <err.h>
4187304b87Stholo 
4287304b87Stholo #include <sys/types.h>
4387304b87Stholo #include <sys/stat.h>
4487304b87Stholo 
4587304b87Stholo #include "fsutil.h"
4687304b87Stholo 
4787304b87Stholo static const char *dev = NULL;
48e729ad4aSjsing static const char *origdev = NULL;
4987304b87Stholo static int hot = 0;
5087304b87Stholo static int preen = 0;
5187304b87Stholo 
5287304b87Stholo extern char *__progname;
5387304b87Stholo 
54c72b5b24Smillert static void vmsg(int, const char *, va_list);
5587304b87Stholo 
5687304b87Stholo void
57e729ad4aSjsing setcdevname(const char *cd, const char *ocd, int pr)
5887304b87Stholo {
5987304b87Stholo 	dev = cd;
60e729ad4aSjsing 	origdev = ocd;
6187304b87Stholo 	preen = pr;
6287304b87Stholo }
6387304b87Stholo 
6487304b87Stholo const char *
65bc52e260Sderaadt cdevname(void)
6687304b87Stholo {
6787304b87Stholo 	return dev;
6887304b87Stholo }
6987304b87Stholo 
7087304b87Stholo int
71bc52e260Sderaadt hotroot(void)
7287304b87Stholo {
7387304b87Stholo 	return hot;
7487304b87Stholo }
7587304b87Stholo 
7687304b87Stholo /*VARARGS*/
7787304b87Stholo void
7887304b87Stholo errexit(const char *fmt, ...)
7987304b87Stholo {
8087304b87Stholo 	va_list ap;
8187304b87Stholo 
8287304b87Stholo 	va_start(ap, fmt);
8387304b87Stholo 	(void) vfprintf(stderr, fmt, ap);
8487304b87Stholo 	va_end(ap);
8587304b87Stholo 	exit(8);
8687304b87Stholo }
8787304b87Stholo 
8887304b87Stholo static void
89bc52e260Sderaadt vmsg(int fatal, const char *fmt, va_list ap)
9087304b87Stholo {
91e729ad4aSjsing 	if (!fatal && preen) {
92e729ad4aSjsing 		if (origdev)
93e729ad4aSjsing 			printf("%s (%s): ", dev, origdev);
94e729ad4aSjsing 		else
95e729ad4aSjsing 			printf("%s: ", dev);
96e729ad4aSjsing 	}
9787304b87Stholo 
9887304b87Stholo 	(void) vprintf(fmt, ap);
99986047b3Sthib 
10087304b87Stholo 	if (fatal && preen) {
101e729ad4aSjsing 		printf("\n");
102e729ad4aSjsing 		if (origdev)
103e729ad4aSjsing 			printf("%s (%s): ", dev, origdev);
104e729ad4aSjsing 		else
105e729ad4aSjsing 			printf("%s: ", dev);
106e729ad4aSjsing 		printf("UNEXPECTED INCONSISTENCY; RUN %s MANUALLY.\n",
107e729ad4aSjsing 		    __progname);
10887304b87Stholo 		exit(8);
10987304b87Stholo 	}
11087304b87Stholo }
11187304b87Stholo 
11287304b87Stholo /*VARARGS*/
11387304b87Stholo void
11487304b87Stholo pfatal(const char *fmt, ...)
11587304b87Stholo {
11687304b87Stholo 	va_list ap;
11787304b87Stholo 
11887304b87Stholo 	va_start(ap, fmt);
11987304b87Stholo 	vmsg(1, fmt, ap);
12087304b87Stholo 	va_end(ap);
12187304b87Stholo }
12287304b87Stholo 
12387304b87Stholo /*VARARGS*/
12487304b87Stholo void
12587304b87Stholo pwarn(const char *fmt, ...)
12687304b87Stholo {
12787304b87Stholo 	va_list ap;
12887304b87Stholo 
12987304b87Stholo 	va_start(ap, fmt);
13087304b87Stholo 	vmsg(0, fmt, ap);
13187304b87Stholo 	va_end(ap);
13287304b87Stholo }
13387304b87Stholo 
13487304b87Stholo void
135dd133929Sthib xperror(const char *s)
13687304b87Stholo {
13787304b87Stholo 	pfatal("%s (%s)", s, strerror(errno));
13887304b87Stholo }
13987304b87Stholo 
14087304b87Stholo void
14187304b87Stholo panic(const char *fmt, ...)
14287304b87Stholo {
14387304b87Stholo 	va_list ap;
14487304b87Stholo 
14587304b87Stholo 	va_start(ap, fmt);
14687304b87Stholo 	vmsg(1, fmt, ap);
14787304b87Stholo 	va_end(ap);
14887304b87Stholo 	exit(8);
14987304b87Stholo }
15087304b87Stholo 
15187304b87Stholo char *
152bc52e260Sderaadt unrawname(char *name)
15387304b87Stholo {
15487304b87Stholo 	char *dp;
15587304b87Stholo 	struct stat stb;
15687304b87Stholo 
157f4be0e98Sderaadt 	if ((dp = strrchr(name, '/')) == NULL)
15887304b87Stholo 		return (name);
15987304b87Stholo 	if (stat(name, &stb) < 0)
16087304b87Stholo 		return (name);
16187304b87Stholo 	if (!S_ISCHR(stb.st_mode))
16287304b87Stholo 		return (name);
16387304b87Stholo 	if (dp[1] != 'r')
16487304b87Stholo 		return (name);
16536286464Sderaadt 	(void)memmove(&dp[1], &dp[2], strlen(&dp[2]) + 1);
16687304b87Stholo 	return (name);
16787304b87Stholo }
16887304b87Stholo 
16987304b87Stholo char *
170bc52e260Sderaadt rawname(char *name)
17187304b87Stholo {
172b9fc9a72Sderaadt 	static char rawbuf[PATH_MAX];
17387304b87Stholo 	char *dp;
17487304b87Stholo 
175f4be0e98Sderaadt 	if ((dp = strrchr(name, '/')) == NULL)
17687304b87Stholo 		return (0);
17787304b87Stholo 	*dp = 0;
178f4be0e98Sderaadt 	(void)strlcpy(rawbuf, name, sizeof rawbuf);
17987304b87Stholo 	*dp = '/';
180f4be0e98Sderaadt 	(void)strlcat(rawbuf, "/r", sizeof rawbuf);
181f4be0e98Sderaadt 	(void)strlcat(rawbuf, &dp[1], sizeof rawbuf);
18287304b87Stholo 	return (rawbuf);
18387304b87Stholo }
18487304b87Stholo 
18587304b87Stholo char *
186bc52e260Sderaadt blockcheck(char *origname)
18787304b87Stholo {
18887304b87Stholo 	struct stat stslash, stblock, stchar;
18987304b87Stholo 	char *newname, *raw;
19087304b87Stholo 	struct fstab *fsp;
19187304b87Stholo 	int retried = 0;
19287304b87Stholo 
19387304b87Stholo 	hot = 0;
19487304b87Stholo 	if (stat("/", &stslash) < 0) {
195dd133929Sthib 		xperror("/");
19687304b87Stholo 		printf("Can't stat root\n");
19787304b87Stholo 		return (origname);
19887304b87Stholo 	}
19987304b87Stholo 	newname = origname;
20087304b87Stholo retry:
2017cbafe7eSgrunk 	if (stat(newname, &stblock) < 0)
20287304b87Stholo 		return (origname);
2037cbafe7eSgrunk 
20487304b87Stholo 	if (S_ISBLK(stblock.st_mode)) {
20587304b87Stholo 		if (stslash.st_dev == stblock.st_rdev)
20687304b87Stholo 			hot++;
20787304b87Stholo 		raw = rawname(newname);
20887304b87Stholo 		if (stat(raw, &stchar) < 0) {
209dd133929Sthib 			xperror(raw);
21087304b87Stholo 			printf("Can't stat %s\n", raw);
21187304b87Stholo 			return (origname);
21287304b87Stholo 		}
21387304b87Stholo 		if (S_ISCHR(stchar.st_mode)) {
21487304b87Stholo 			return (raw);
21587304b87Stholo 		} else {
21687304b87Stholo 			printf("%s is not a character device\n", raw);
21787304b87Stholo 			return (origname);
21887304b87Stholo 		}
21987304b87Stholo 	} else if (S_ISCHR(stblock.st_mode) && !retried) {
22087304b87Stholo 		newname = unrawname(newname);
22187304b87Stholo 		retried++;
22287304b87Stholo 		goto retry;
22387304b87Stholo 	} else if ((fsp = getfsfile(newname)) != 0 && !retried) {
22487304b87Stholo 		newname = fsp->fs_spec;
22587304b87Stholo 		retried++;
22687304b87Stholo 		goto retry;
22787304b87Stholo 	}
22887304b87Stholo 	/*
22987304b87Stholo 	 * Not a block or character device, just return name and
23087304b87Stholo 	 * let the user decide whether to use it.
23187304b87Stholo 	 */
23287304b87Stholo 	return (origname);
23387304b87Stholo }
23487304b87Stholo 
23587304b87Stholo 
23687304b87Stholo void *
237bc52e260Sderaadt emalloc(size_t s)
23887304b87Stholo {
239b166fb0eSderaadt 	void *p;
240b166fb0eSderaadt 
241b166fb0eSderaadt 	if (s == 0)
242b166fb0eSderaadt 		err(1, "malloc failed");
243b166fb0eSderaadt 	p = malloc(s);
24487304b87Stholo 	if (p == NULL)
24587304b87Stholo 		err(1, "malloc failed");
24687304b87Stholo 	return p;
24787304b87Stholo }
24887304b87Stholo 
24987304b87Stholo 
25087304b87Stholo void *
251119ae1adSderaadt ereallocarray(void *p, size_t n, size_t s)
25287304b87Stholo {
2537428f312Sderaadt 	void *newp;
2547428f312Sderaadt 
255*34c2ea26Sderaadt 	if (n == 0 || s == 0) {
256*34c2ea26Sderaadt 		free(p);
257b166fb0eSderaadt 		err(1, "realloc failed");
258*34c2ea26Sderaadt 	}
259119ae1adSderaadt 	newp = reallocarray(p, n, s);
2607428f312Sderaadt 	if (newp == NULL) {
2617428f312Sderaadt 		free(p);
26287304b87Stholo 		err(1, "realloc failed");
2637428f312Sderaadt 	}
2647428f312Sderaadt 	return newp;
26587304b87Stholo }
26687304b87Stholo 
26787304b87Stholo 
26887304b87Stholo char *
269bc52e260Sderaadt estrdup(const char *s)
27087304b87Stholo {
27187304b87Stholo 	char *p = strdup(s);
27287304b87Stholo 	if (p == NULL)
27387304b87Stholo 		err(1, "strdup failed");
27487304b87Stholo 	return p;
27587304b87Stholo }
276