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