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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * $FreeBSD: src/sbin/fsck/fsutil.c,v 1.2.2.1 2001/08/01 05:47:55 obrien Exp $ 36 * $DragonFly: src/sbin/fsck/fsutil.c,v 1.3 2003/09/28 14:39:17 hmp Exp $ 37 * 38 * $NetBSD: fsutil.c,v 1.7 1998/07/30 17:41:03 thorpej Exp $ 39 */ 40 41 #include <sys/cdefs.h> 42 43 #include <stdio.h> 44 #include <string.h> 45 #include <stdlib.h> 46 #if __STDC__ 47 #include <stdarg.h> 48 #else 49 #include <varargs.h> 50 #endif 51 #include <errno.h> 52 #include <fstab.h> 53 #include <err.h> 54 #include <paths.h> 55 56 #include <sys/param.h> 57 #include <sys/stat.h> 58 #include <sys/mount.h> 59 60 #include "fsutil.h" 61 62 static const char *dev = NULL; 63 static int hot = 0; 64 static int preen = 0; 65 66 extern char *__progname; 67 68 static void vmsg __P((int, const char *, va_list)); 69 70 void 71 setcdevname(const char *cd, int pr) 72 { 73 dev = cd; 74 preen = pr; 75 } 76 77 const char * 78 cdevname(void) 79 { 80 return dev; 81 } 82 83 int 84 hotroot(void) 85 { 86 return hot; 87 } 88 89 /*VARARGS*/ 90 void 91 errexit(const char *fmt, ...) 92 { 93 va_list ap; 94 95 va_start(ap, fmt); 96 (void) vfprintf(stderr, fmt, ap); 97 va_end(ap); 98 exit(8); 99 } 100 101 static void 102 vmsg(int fatal, const char *fmt, va_list ap) 103 { 104 if (!fatal && preen) 105 (void) printf("%s: ", dev); 106 107 (void) vprintf(fmt, ap); 108 109 if (fatal && preen) 110 (void) printf("\n"); 111 112 if (fatal && preen) { 113 (void) printf( 114 "%s: UNEXPECTED INCONSISTENCY; RUN %s MANUALLY.\n", 115 dev, __progname); 116 exit(8); 117 } 118 } 119 120 /*VARARGS*/ 121 void 122 pfatal(const char *fmt, ...) 123 { 124 va_list ap; 125 126 va_start(ap, fmt); 127 vmsg(1, fmt, ap); 128 va_end(ap); 129 } 130 131 /*VARARGS*/ 132 void 133 pwarn(const char *fmt, ...) 134 { 135 va_list ap; 136 va_start(ap, fmt); 137 vmsg(0, fmt, ap); 138 va_end(ap); 139 } 140 141 void 142 perror(const char *s) 143 { 144 pfatal("%s (%s)", s, strerror(errno)); 145 } 146 147 void 148 panic(const char *fmt, ...) 149 { 150 va_list ap; 151 152 va_start(ap, fmt); 153 vmsg(1, fmt, ap); 154 va_end(ap); 155 exit(8); 156 } 157 158 const char * 159 unrawname(const char *name) 160 { 161 static char unrawbuf[32]; 162 const char *dp; 163 struct stat stb; 164 165 if ((dp = strrchr(name, '/')) == 0) 166 return (name); 167 if (stat(name, &stb) < 0) 168 return (name); 169 if (!S_ISCHR(stb.st_mode)) 170 return (name); 171 if (dp[1] != 'r') 172 return (name); 173 (void)snprintf(unrawbuf, 32, "%.*s/%s", (int)(dp - name), name, dp + 2); 174 return (unrawbuf); 175 } 176 177 const char * 178 rawname(const char *name) 179 { 180 static char rawbuf[32]; 181 const char *dp; 182 183 if ((dp = strrchr(name, '/')) == 0) 184 return (0); 185 (void)snprintf(rawbuf, 32, "%.*s/r%s", (int)(dp - name), name, dp + 1); 186 return (rawbuf); 187 } 188 189 const char * 190 devcheck(const char *origname) 191 { 192 struct stat stslash, stchar; 193 194 if (stat("/", &stslash) < 0) { 195 perror("/"); 196 printf("Can't stat root\n"); 197 return (origname); 198 } 199 if (stat(origname, &stchar) < 0) { 200 perror(origname); 201 printf("Can't stat %s\n", origname); 202 return (origname); 203 } 204 if (!S_ISCHR(stchar.st_mode)) { 205 perror(origname); 206 printf("%s is not a char device\n", origname); 207 } 208 return (origname); 209 } 210 211 /* 212 * Get the mount point information for name. 213 */ 214 struct statfs * 215 getmntpt(const char *name) 216 { 217 struct stat devstat, mntdevstat; 218 char device[sizeof(_PATH_DEV) - 1 + MNAMELEN]; 219 char *devname; 220 struct statfs *mntbuf, *statfsp; 221 int i, mntsize, isdev; 222 223 if (stat(name, &devstat) != 0) 224 return (NULL); 225 if (S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode)) 226 isdev = 1; 227 else 228 isdev = 0; 229 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 230 for (i = 0; i < mntsize; i++) { 231 statfsp = &mntbuf[i]; 232 devname = statfsp->f_mntfromname; 233 if (*devname != '/') { 234 strcpy(device, _PATH_DEV); 235 strcat(device, devname); 236 strcpy(statfsp->f_mntfromname, device); 237 } 238 if (isdev == 0) { 239 if (strcmp(name, statfsp->f_mntonname)) 240 continue; 241 return (statfsp); 242 } 243 if (stat(devname, &mntdevstat) == 0 && 244 mntdevstat.st_rdev == devstat.st_rdev) 245 return (statfsp); 246 } 247 statfsp = NULL; 248 return (statfsp); 249 } 250 251 #if 0 252 /* 253 * XXX this code is from NetBSD, but fails in FreeBSD because we 254 * don't have blockdevs. I don't think its needed. 255 */ 256 const char * 257 blockcheck(const char *origname) 258 { 259 struct stat stslash, stblock, stchar; 260 const char *newname, *raw; 261 struct fstab *fsp; 262 int retried = 0; 263 264 hot = 0; 265 if (stat("/", &stslash) < 0) { 266 perror("/"); 267 printf("Can't stat root\n"); 268 return (origname); 269 } 270 newname = origname; 271 retry: 272 if (stat(newname, &stblock) < 0) { 273 perror(newname); 274 printf("Can't stat %s\n", newname); 275 return (origname); 276 } 277 if (S_ISBLK(stblock.st_mode)) { 278 if (stslash.st_dev == stblock.st_rdev) 279 hot++; 280 raw = rawname(newname); 281 if (stat(raw, &stchar) < 0) { 282 perror(raw); 283 printf("Can't stat %s\n", raw); 284 return (origname); 285 } 286 if (S_ISCHR(stchar.st_mode)) { 287 return (raw); 288 } else { 289 printf("%s is not a character device\n", raw); 290 return (origname); 291 } 292 } else if (S_ISCHR(stblock.st_mode) && !retried) { 293 newname = unrawname(newname); 294 retried++; 295 goto retry; 296 } else if ((fsp = getfsfile(newname)) != 0 && !retried) { 297 newname = fsp->fs_spec; 298 retried++; 299 goto retry; 300 } 301 /* 302 * Not a block or character device, just return name and 303 * let the user decide whether to use it. 304 */ 305 return (origname); 306 } 307 #endif 308 309 310 void * 311 emalloc(size_t s) 312 { 313 void *p; 314 315 p = malloc(s); 316 if (p == NULL) 317 err(1, "malloc failed"); 318 return (p); 319 } 320 321 322 void * 323 erealloc(void *p, size_t s) 324 { 325 void *q; 326 327 q = realloc(p, s); 328 if (q == NULL) 329 err(1, "realloc failed"); 330 return (q); 331 } 332 333 334 char * 335 estrdup(const char *s) 336 { 337 char *p; 338 339 p = strdup(s); 340 if (p == NULL) 341 err(1, "strdup failed"); 342 return (p); 343 } 344