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 struct stat stslash, stblock, stchar; 173 const char *newname, *raw, *cooked; 174 struct fstab *fsp; 175 int retried = 0; 176 ssize_t len; 177 char cbuf[MAXPATHLEN]; 178 static char buf[MAXPATHLEN]; 179 180 hot = 0; 181 if (stat("/", &stslash) < 0) { 182 perr("Can't stat `/'"); 183 return (origname); 184 } 185 len = readlink(origname, cbuf, sizeof(cbuf)-1); 186 if (len == -1) { 187 newname = origname; 188 } else { 189 cbuf[len] = '\0'; 190 newname = cbuf; 191 } 192 retry: 193 if (stat(newname, &stblock) < 0) { 194 perr("Can't stat `%s'", newname); 195 return origname; 196 } 197 if (S_ISBLK(stblock.st_mode)) { 198 if (stslash.st_dev == stblock.st_rdev) 199 hot++; 200 raw = getdiskrawname(buf, sizeof(buf), newname); 201 if (raw == NULL) { 202 perr("Can't convert to raw `%s'", newname); 203 return origname; 204 } 205 if (stat(raw, &stchar) < 0) { 206 perr("Can't stat `%s'", raw); 207 return origname; 208 } 209 if (S_ISCHR(stchar.st_mode)) { 210 return raw; 211 } else { 212 perr("%s is not a character device\n", raw); 213 return origname; 214 } 215 } else if (S_ISCHR(stblock.st_mode) && !retried) { 216 cooked = getdiskcookedname(cbuf, sizeof(cbuf), newname); 217 if (cooked == NULL) { 218 perr("Can't convert to cooked `%s'", newname); 219 return origname; 220 } else 221 newname = cooked; 222 retried++; 223 goto retry; 224 } else if ((fsp = getfsfile(newname)) != 0 && !retried) { 225 newname = getfsspecname(cbuf, sizeof(cbuf), fsp->fs_spec); 226 if (newname == NULL) 227 perr("%s", buf); 228 retried++; 229 goto retry; 230 } 231 /* 232 * Not a block or character device, just return name and 233 * let the user decide whether to use it. 234 */ 235 return origname; 236 } 237 238 const char * 239 print_mtime(time_t t) 240 { 241 static char b[128]; 242 char *p = ctime(&t); 243 if (p != NULL) 244 (void)snprintf(b, sizeof(b), "%12.12s %4.4s ", &p[4], &p[20]); 245 else 246 (void)snprintf(b, sizeof(b), "%lld ", (long long)t); 247 return b; 248 } 249 250 251 void 252 catch(int n) 253 { 254 if (ckfinish) (*ckfinish)(0); 255 _exit(FSCK_EXIT_SIGNALLED); 256 } 257 258 /* 259 * When preening, allow a single quit to signal 260 * a special exit after filesystem checks complete 261 * so that reboot sequence may be interrupted. 262 */ 263 void 264 catchquit(int n) 265 { 266 static const char msg[] = 267 "returning to single-user after filesystem check\n"; 268 int serrno = errno; 269 270 (void)write(STDOUT_FILENO, msg, sizeof(msg) - 1); 271 returntosingle = 1; 272 (void)signal(SIGQUIT, SIG_DFL); 273 errno = serrno; 274 } 275 276 /* 277 * Ignore a single quit signal; wait and flush just in case. 278 * Used by child processes in preen. 279 */ 280 void 281 voidquit(int n) 282 { 283 int serrno = errno; 284 285 sleep(1); 286 (void)signal(SIGQUIT, SIG_IGN); 287 (void)signal(SIGQUIT, SIG_DFL); 288 errno = serrno; 289 } 290