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