1 1.27 joerg /* $NetBSD: fsutil.c,v 1.27 2020/04/03 19:36:32 joerg Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (c) 1990, 1993 5 1.1 christos * The Regents of the University of California. All rights reserved. 6 1.1 christos * 7 1.1 christos * Redistribution and use in source and binary forms, with or without 8 1.1 christos * modification, are permitted provided that the following conditions 9 1.1 christos * are met: 10 1.1 christos * 1. Redistributions of source code must retain the above copyright 11 1.1 christos * notice, this list of conditions and the following disclaimer. 12 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 christos * notice, this list of conditions and the following disclaimer in the 14 1.1 christos * documentation and/or other materials provided with the distribution. 15 1.13 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 christos * may be used to endorse or promote products derived from this software 17 1.1 christos * without specific prior written permission. 18 1.1 christos * 19 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 christos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 christos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 christos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 christos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 christos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 christos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 christos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 christos * SUCH DAMAGE. 30 1.1 christos */ 31 1.4 lukem 32 1.4 lukem #include <sys/cdefs.h> 33 1.1 christos #ifndef lint 34 1.27 joerg __RCSID("$NetBSD: fsutil.c,v 1.27 2020/04/03 19:36:32 joerg Exp $"); 35 1.1 christos #endif /* not lint */ 36 1.1 christos 37 1.26 dholland /* 38 1.26 dholland * used by sbin/fsck 39 1.26 dholland * used by sbin/fsck_ext2fs 40 1.26 dholland * used by sbin/fsck_ffs 41 1.26 dholland * used by sbin/fsck_lfs 42 1.26 dholland * used by sbin/fsck_msdos 43 1.26 dholland * used by sbin/fsck_v7fs 44 1.26 dholland * used by sbin/fsdb 45 1.26 dholland * used by usr.sbin/quotacheck 46 1.26 dholland */ 47 1.26 dholland 48 1.11 lukem #include <sys/param.h> 49 1.11 lukem 50 1.1 christos #include <stdio.h> 51 1.1 christos #include <string.h> 52 1.1 christos #include <stdlib.h> 53 1.1 christos #include <stdarg.h> 54 1.1 christos #include <errno.h> 55 1.1 christos #include <fstab.h> 56 1.20 christos #include <fcntl.h> 57 1.20 christos #include <unistd.h> 58 1.1 christos #include <err.h> 59 1.21 christos #include <util.h> 60 1.1 christos 61 1.1 christos #include <sys/types.h> 62 1.1 christos #include <sys/stat.h> 63 1.1 christos 64 1.1 christos #include "fsutil.h" 65 1.17 christos #include "exitvalues.h" 66 1.1 christos 67 1.25 dholland volatile sig_atomic_t returntosingle; 68 1.25 dholland 69 1.27 joerg void (*ckfinish)(int); 70 1.27 joerg 71 1.1 christos static const char *dev = NULL; 72 1.1 christos static int hot = 0; 73 1.1 christos static int preen = 0; 74 1.27 joerg int quiet; /* don't report clean filesystems */ 75 1.15 christos #define F_ERROR 0x80000000 76 1.1 christos 77 1.1 christos void 78 1.10 lukem setcdevname(const char *cd, int pr) 79 1.1 christos { 80 1.10 lukem 81 1.1 christos dev = cd; 82 1.1 christos preen = pr; 83 1.1 christos } 84 1.1 christos 85 1.1 christos const char * 86 1.10 lukem cdevname(void) 87 1.1 christos { 88 1.10 lukem 89 1.1 christos return dev; 90 1.1 christos } 91 1.1 christos 92 1.1 christos int 93 1.10 lukem hotroot(void) 94 1.1 christos { 95 1.10 lukem 96 1.1 christos return hot; 97 1.1 christos } 98 1.1 christos 99 1.1 christos /*VARARGS*/ 100 1.1 christos void 101 1.1 christos errexit(const char *fmt, ...) 102 1.1 christos { 103 1.1 christos va_list ap; 104 1.3 christos 105 1.1 christos va_start(ap, fmt); 106 1.1 christos (void) vfprintf(stderr, fmt, ap); 107 1.1 christos va_end(ap); 108 1.18 lukem (void)fprintf(stderr, "\n"); 109 1.17 christos exit(FSCK_EXIT_CHECK_FAILED); 110 1.1 christos } 111 1.1 christos 112 1.12 perseant void 113 1.10 lukem vmsg(int fatal, const char *fmt, va_list ap) 114 1.1 christos { 115 1.15 christos int serr = fatal & F_ERROR; 116 1.15 christos int serrno = errno; 117 1.15 christos fatal &= ~F_ERROR; 118 1.10 lukem 119 1.1 christos if (!fatal && preen) 120 1.14 dsl (void)printf("%s: ", dev); 121 1.14 dsl if (quiet && !preen) { 122 1.14 dsl (void)printf("** %s (vmsg)\n", dev); 123 1.14 dsl quiet = 0; 124 1.14 dsl } 125 1.1 christos 126 1.1 christos (void) vprintf(fmt, ap); 127 1.15 christos if (serr) 128 1.15 christos printf(" (%s)", strerror(serrno)); 129 1.1 christos 130 1.1 christos if (fatal && preen) 131 1.1 christos (void) printf("\n"); 132 1.1 christos 133 1.1 christos if (fatal && preen) { 134 1.1 christos (void) printf( 135 1.1 christos "%s: UNEXPECTED INCONSISTENCY; RUN %s MANUALLY.\n", 136 1.9 cgd dev, getprogname()); 137 1.17 christos exit(FSCK_EXIT_CHECK_FAILED); 138 1.1 christos } 139 1.1 christos } 140 1.1 christos 141 1.1 christos /*VARARGS*/ 142 1.1 christos void 143 1.1 christos pfatal(const char *fmt, ...) 144 1.1 christos { 145 1.1 christos va_list ap; 146 1.3 christos 147 1.1 christos va_start(ap, fmt); 148 1.1 christos vmsg(1, fmt, ap); 149 1.1 christos va_end(ap); 150 1.1 christos } 151 1.1 christos 152 1.1 christos /*VARARGS*/ 153 1.1 christos void 154 1.1 christos pwarn(const char *fmt, ...) 155 1.1 christos { 156 1.1 christos va_list ap; 157 1.10 lukem 158 1.1 christos va_start(ap, fmt); 159 1.1 christos vmsg(0, fmt, ap); 160 1.1 christos va_end(ap); 161 1.1 christos } 162 1.1 christos 163 1.1 christos void 164 1.15 christos perr(const char *fmt, ...) 165 1.1 christos { 166 1.15 christos va_list ap; 167 1.10 lukem 168 1.15 christos va_start(ap, fmt); 169 1.15 christos vmsg(1 | F_ERROR, fmt, ap); 170 1.15 christos va_end(ap); 171 1.1 christos } 172 1.1 christos 173 1.1 christos void 174 1.1 christos panic(const char *fmt, ...) 175 1.1 christos { 176 1.1 christos va_list ap; 177 1.3 christos 178 1.1 christos va_start(ap, fmt); 179 1.1 christos vmsg(1, fmt, ap); 180 1.1 christos va_end(ap); 181 1.17 christos exit(FSCK_EXIT_CHECK_FAILED); 182 1.1 christos } 183 1.1 christos 184 1.6 mycroft const char * 185 1.10 lukem blockcheck(const char *origname) 186 1.1 christos { 187 1.1 christos struct stat stslash, stblock, stchar; 188 1.23 christos const char *newname, *raw, *cooked; 189 1.1 christos struct fstab *fsp; 190 1.1 christos int retried = 0; 191 1.24 mlelstv ssize_t len; 192 1.23 christos char cbuf[MAXPATHLEN]; 193 1.22 christos static char buf[MAXPATHLEN]; 194 1.1 christos 195 1.1 christos hot = 0; 196 1.1 christos if (stat("/", &stslash) < 0) { 197 1.15 christos perr("Can't stat `/'"); 198 1.1 christos return (origname); 199 1.1 christos } 200 1.24 mlelstv len = readlink(origname, cbuf, sizeof(cbuf)-1); 201 1.24 mlelstv if (len == -1) { 202 1.24 mlelstv newname = origname; 203 1.24 mlelstv } else { 204 1.24 mlelstv cbuf[len] = '\0'; 205 1.24 mlelstv newname = cbuf; 206 1.24 mlelstv } 207 1.1 christos retry: 208 1.1 christos if (stat(newname, &stblock) < 0) { 209 1.15 christos perr("Can't stat `%s'", newname); 210 1.23 christos return origname; 211 1.1 christos } 212 1.1 christos if (S_ISBLK(stblock.st_mode)) { 213 1.1 christos if (stslash.st_dev == stblock.st_rdev) 214 1.1 christos hot++; 215 1.22 christos raw = getdiskrawname(buf, sizeof(buf), newname); 216 1.22 christos if (raw == NULL) { 217 1.22 christos perr("Can't convert to raw `%s'", newname); 218 1.22 christos return origname; 219 1.22 christos } 220 1.1 christos if (stat(raw, &stchar) < 0) { 221 1.15 christos perr("Can't stat `%s'", raw); 222 1.23 christos return origname; 223 1.1 christos } 224 1.1 christos if (S_ISCHR(stchar.st_mode)) { 225 1.23 christos return raw; 226 1.1 christos } else { 227 1.23 christos perr("%s is not a character device\n", raw); 228 1.23 christos return origname; 229 1.1 christos } 230 1.1 christos } else if (S_ISCHR(stblock.st_mode) && !retried) { 231 1.23 christos cooked = getdiskcookedname(cbuf, sizeof(cbuf), newname); 232 1.23 christos if (cooked == NULL) { 233 1.22 christos perr("Can't convert to cooked `%s'", newname); 234 1.22 christos return origname; 235 1.22 christos } else 236 1.23 christos newname = cooked; 237 1.1 christos retried++; 238 1.1 christos goto retry; 239 1.1 christos } else if ((fsp = getfsfile(newname)) != 0 && !retried) { 240 1.23 christos newname = getfsspecname(cbuf, sizeof(cbuf), fsp->fs_spec); 241 1.21 christos if (newname == NULL) 242 1.21 christos perr("%s", buf); 243 1.1 christos retried++; 244 1.1 christos goto retry; 245 1.1 christos } 246 1.1 christos /* 247 1.1 christos * Not a block or character device, just return name and 248 1.1 christos * let the user decide whether to use it. 249 1.1 christos */ 250 1.23 christos return origname; 251 1.1 christos } 252 1.19 christos 253 1.19 christos const char * 254 1.19 christos print_mtime(time_t t) 255 1.19 christos { 256 1.19 christos static char b[128]; 257 1.19 christos char *p = ctime(&t); 258 1.19 christos if (p != NULL) 259 1.19 christos (void)snprintf(b, sizeof(b), "%12.12s %4.4s ", &p[4], &p[20]); 260 1.19 christos else 261 1.19 christos (void)snprintf(b, sizeof(b), "%lld ", (long long)t); 262 1.19 christos return b; 263 1.19 christos } 264 1.20 christos 265 1.20 christos 266 1.20 christos void 267 1.20 christos catch(int n) 268 1.20 christos { 269 1.20 christos if (ckfinish) (*ckfinish)(0); 270 1.20 christos _exit(FSCK_EXIT_SIGNALLED); 271 1.20 christos } 272 1.20 christos 273 1.20 christos /* 274 1.20 christos * When preening, allow a single quit to signal 275 1.20 christos * a special exit after filesystem checks complete 276 1.20 christos * so that reboot sequence may be interrupted. 277 1.20 christos */ 278 1.20 christos void 279 1.20 christos catchquit(int n) 280 1.20 christos { 281 1.20 christos static const char msg[] = 282 1.20 christos "returning to single-user after filesystem check\n"; 283 1.20 christos int serrno = errno; 284 1.20 christos 285 1.20 christos (void)write(STDOUT_FILENO, msg, sizeof(msg) - 1); 286 1.20 christos returntosingle = 1; 287 1.20 christos (void)signal(SIGQUIT, SIG_DFL); 288 1.20 christos errno = serrno; 289 1.20 christos } 290 1.20 christos 291 1.20 christos /* 292 1.20 christos * Ignore a single quit signal; wait and flush just in case. 293 1.20 christos * Used by child processes in preen. 294 1.20 christos */ 295 1.20 christos void 296 1.20 christos voidquit(int n) 297 1.20 christos { 298 1.20 christos int serrno = errno; 299 1.20 christos 300 1.20 christos sleep(1); 301 1.20 christos (void)signal(SIGQUIT, SIG_IGN); 302 1.20 christos (void)signal(SIGQUIT, SIG_DFL); 303 1.20 christos errno = serrno; 304 1.20 christos } 305