1 1.43 perseant /* $NetBSD: utilities.c,v 1.43 2025/09/14 19:14:30 perseant Exp $ */ 2 1.1 perseant 3 1.1 perseant /* 4 1.1 perseant * Copyright (c) 1980, 1986, 1993 5 1.1 perseant * The Regents of the University of California. All rights reserved. 6 1.1 perseant * 7 1.1 perseant * Redistribution and use in source and binary forms, with or without 8 1.1 perseant * modification, are permitted provided that the following conditions 9 1.1 perseant * are met: 10 1.1 perseant * 1. Redistributions of source code must retain the above copyright 11 1.1 perseant * notice, this list of conditions and the following disclaimer. 12 1.1 perseant * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 perseant * notice, this list of conditions and the following disclaimer in the 14 1.1 perseant * documentation and/or other materials provided with the distribution. 15 1.15 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 perseant * may be used to endorse or promote products derived from this software 17 1.1 perseant * without specific prior written permission. 18 1.1 perseant * 19 1.1 perseant * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 perseant * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 perseant * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 perseant * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 perseant * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 perseant * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 perseant * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 perseant * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 perseant * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 perseant * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 perseant * SUCH DAMAGE. 30 1.1 perseant */ 31 1.1 perseant 32 1.1 perseant #include <sys/param.h> 33 1.1 perseant #include <sys/time.h> 34 1.12 perseant #include <sys/mount.h> 35 1.11 perseant 36 1.12 perseant #define buf ubuf 37 1.12 perseant #define vnode uvnode 38 1.1 perseant #include <ufs/lfs/lfs.h> 39 1.40 dholland #include <ufs/lfs/lfs_accessors.h> 40 1.11 perseant 41 1.11 perseant #include <err.h> 42 1.1 perseant #include <stdio.h> 43 1.1 perseant #include <stdlib.h> 44 1.1 perseant #include <string.h> 45 1.1 perseant #include <ctype.h> 46 1.1 perseant #include <unistd.h> 47 1.30 christos #include <errno.h> 48 1.1 perseant 49 1.1 perseant #include <signal.h> 50 1.1 perseant 51 1.11 perseant #include "bufcache.h" 52 1.22 christos #include "lfs_user.h" 53 1.11 perseant #include "segwrite.h" 54 1.11 perseant 55 1.1 perseant #include "fsutil.h" 56 1.1 perseant #include "fsck.h" 57 1.1 perseant #include "extern.h" 58 1.27 christos #include "exitvalues.h" 59 1.1 perseant 60 1.11 perseant long diskreads, totalreads; /* Disk cache statistics */ 61 1.43 perseant int asked_question = 0; 62 1.1 perseant 63 1.1 perseant int 64 1.41 dholland ftypeok(union lfs_dinode * dp) 65 1.1 perseant { 66 1.41 dholland switch (lfs_dino_getmode(fs, dp) & LFS_IFMT) { 67 1.1 perseant 68 1.34 dholland case LFS_IFDIR: 69 1.34 dholland case LFS_IFREG: 70 1.34 dholland case LFS_IFBLK: 71 1.34 dholland case LFS_IFCHR: 72 1.34 dholland case LFS_IFLNK: 73 1.34 dholland case LFS_IFSOCK: 74 1.34 dholland case LFS_IFIFO: 75 1.1 perseant return (1); 76 1.1 perseant 77 1.1 perseant default: 78 1.1 perseant if (debug) 79 1.41 dholland pwarn("bad file type 0%o\n", lfs_dino_getmode(fs, dp)); 80 1.1 perseant return (0); 81 1.1 perseant } 82 1.1 perseant } 83 1.1 perseant 84 1.1 perseant int 85 1.19 christos reply(const char *question) 86 1.1 perseant { 87 1.11 perseant int persevere; 88 1.11 perseant char c; 89 1.1 perseant 90 1.43 perseant asked_question = 1; 91 1.43 perseant 92 1.1 perseant if (preen) 93 1.36 christos err(EXIT_FAILURE, "INTERNAL ERROR: GOT TO reply()"); 94 1.1 perseant persevere = !strcmp(question, "CONTINUE"); 95 1.16 dsl pwarn("\n"); 96 1.11 perseant if (!persevere && nflag) { 97 1.1 perseant printf("%s? no\n\n", question); 98 1.1 perseant return (0); 99 1.1 perseant } 100 1.1 perseant if (yflag || (persevere && nflag)) { 101 1.1 perseant printf("%s? yes\n\n", question); 102 1.1 perseant return (1); 103 1.1 perseant } 104 1.4 perseant do { 105 1.1 perseant printf("%s? [yn] ", question); 106 1.11 perseant (void) fflush(stdout); 107 1.1 perseant c = getc(stdin); 108 1.1 perseant while (c != '\n' && getc(stdin) != '\n') 109 1.1 perseant if (feof(stdin)) 110 1.1 perseant return (0); 111 1.1 perseant } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 112 1.1 perseant printf("\n"); 113 1.1 perseant if (c == 'y' || c == 'Y') 114 1.1 perseant return (1); 115 1.1 perseant return (0); 116 1.1 perseant } 117 1.1 perseant 118 1.1 perseant static void 119 1.11 perseant write_superblocks(void) 120 1.1 perseant { 121 1.25 perseant if (debug) 122 1.38 dholland pwarn("writing superblocks with lfs_idaddr = 0x%jx\n", 123 1.38 dholland (uintmax_t)lfs_sb_getidaddr(fs)); 124 1.39 dholland lfs_writesuper(fs, lfs_sb_getsboff(fs, 0)); 125 1.39 dholland lfs_writesuper(fs, lfs_sb_getsboff(fs, 1)); 126 1.11 perseant fsmodified = 1; 127 1.1 perseant } 128 1.1 perseant 129 1.1 perseant void 130 1.4 perseant ckfini(int markclean) 131 1.1 perseant { 132 1.12 perseant if (locked_queue_bytes > 0) { 133 1.11 perseant if (preen || reply("WRITE CHANGES TO DISK") == 1) { 134 1.12 perseant if (preen == 0) 135 1.12 perseant pwarn("WRITING CHANGES TO DISK\n"); 136 1.11 perseant lfs_segwrite(fs, SEGM_CKP); 137 1.11 perseant fsdirty = 0; 138 1.11 perseant fsmodified = 1; 139 1.11 perseant } 140 1.11 perseant } 141 1.1 perseant 142 1.39 dholland if (!nflag && (lfs_sb_getpflags(fs) & LFS_PF_CLEAN) == 0) { 143 1.39 dholland lfs_sb_setpflags(fs, lfs_sb_getpflags(fs) | LFS_PF_CLEAN); 144 1.12 perseant fsmodified = 1; 145 1.18 perseant } 146 1.12 perseant 147 1.25 perseant if (fsmodified && (preen || reply("UPDATE SUPERBLOCKS"))) { 148 1.1 perseant sbdirty(); 149 1.11 perseant write_superblocks(); 150 1.1 perseant } 151 1.12 perseant if (markclean && fsmodified) { 152 1.1 perseant /* 153 1.1 perseant * Mark the file system as clean, and sync the superblock. 154 1.1 perseant */ 155 1.1 perseant if (preen) 156 1.1 perseant pwarn("MARKING FILE SYSTEM CLEAN\n"); 157 1.1 perseant else if (!reply("MARK FILE SYSTEM CLEAN")) 158 1.1 perseant markclean = 0; 159 1.1 perseant if (markclean) { 160 1.39 dholland lfs_sb_setpflags(fs, lfs_sb_getpflags(fs) | LFS_PF_CLEAN); 161 1.1 perseant sbdirty(); 162 1.11 perseant write_superblocks(); 163 1.11 perseant if (!preen) 164 1.11 perseant printf( 165 1.11 perseant "\n***** FILE SYSTEM MARKED CLEAN *****\n"); 166 1.1 perseant } 167 1.1 perseant } 168 1.12 perseant 169 1.1 perseant if (debug) 170 1.11 perseant bufstats(); 171 1.11 perseant (void) close(fsreadfd); 172 1.1 perseant } 173 1.1 perseant /* 174 1.1 perseant * Free a previously allocated block 175 1.1 perseant */ 176 1.1 perseant void 177 1.4 perseant freeblk(daddr_t blkno, long frags) 178 1.1 perseant { 179 1.11 perseant struct inodesc idesc; 180 1.1 perseant 181 1.1 perseant idesc.id_blkno = blkno; 182 1.1 perseant idesc.id_numfrags = frags; 183 1.11 perseant (void) pass4check(&idesc); 184 1.1 perseant } 185 1.1 perseant /* 186 1.1 perseant * Find a pathname 187 1.1 perseant */ 188 1.1 perseant void 189 1.14 itojun getpathname(char *namebuf, size_t namebuflen, ino_t curdir, ino_t ino) 190 1.4 perseant { 191 1.11 perseant int len; 192 1.17 perry char *cp; 193 1.11 perseant struct inodesc idesc; 194 1.11 perseant static int busy = 0; 195 1.1 perseant 196 1.33 dholland if (curdir == ino && ino == ULFS_ROOTINO) { 197 1.14 itojun (void) strlcpy(namebuf, "/", namebuflen); 198 1.1 perseant return; 199 1.1 perseant } 200 1.1 perseant if (busy || 201 1.1 perseant (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) { 202 1.14 itojun (void) strlcpy(namebuf, "?", namebuflen); 203 1.1 perseant return; 204 1.1 perseant } 205 1.1 perseant busy = 1; 206 1.1 perseant memset(&idesc, 0, sizeof(struct inodesc)); 207 1.1 perseant idesc.id_type = DATA; 208 1.1 perseant idesc.id_fix = IGNORE; 209 1.1 perseant cp = &namebuf[MAXPATHLEN - 1]; 210 1.1 perseant *cp = '\0'; 211 1.1 perseant if (curdir != ino) { 212 1.1 perseant idesc.id_parent = curdir; 213 1.1 perseant goto namelookup; 214 1.1 perseant } 215 1.33 dholland while (ino != ULFS_ROOTINO) { 216 1.1 perseant idesc.id_number = ino; 217 1.1 perseant idesc.id_func = findino; 218 1.1 perseant idesc.id_name = ".."; 219 1.1 perseant if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 220 1.1 perseant break; 221 1.4 perseant namelookup: 222 1.1 perseant idesc.id_number = idesc.id_parent; 223 1.1 perseant idesc.id_parent = ino; 224 1.1 perseant idesc.id_func = findname; 225 1.1 perseant idesc.id_name = namebuf; 226 1.24 perseant if (ginode(idesc.id_number) == NULL) 227 1.24 perseant break; 228 1.4 perseant if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0) 229 1.1 perseant break; 230 1.1 perseant len = strlen(namebuf); 231 1.1 perseant cp -= len; 232 1.11 perseant memcpy(cp, namebuf, (size_t) len); 233 1.1 perseant *--cp = '/'; 234 1.21 christos if (cp < &namebuf[LFS_MAXNAMLEN]) 235 1.1 perseant break; 236 1.1 perseant ino = idesc.id_number; 237 1.1 perseant } 238 1.1 perseant busy = 0; 239 1.33 dholland if (ino != ULFS_ROOTINO) 240 1.1 perseant *--cp = '?'; 241 1.11 perseant memcpy(namebuf, cp, (size_t) (&namebuf[MAXPATHLEN] - cp)); 242 1.1 perseant } 243 1.1 perseant 244 1.1 perseant /* 245 1.1 perseant * determine whether an inode should be fixed. 246 1.1 perseant */ 247 1.1 perseant int 248 1.19 christos dofix(struct inodesc * idesc, const char *msg) 249 1.1 perseant { 250 1.1 perseant 251 1.1 perseant switch (idesc->id_fix) { 252 1.1 perseant 253 1.11 perseant case DONTKNOW: 254 1.1 perseant if (idesc->id_type == DATA) 255 1.1 perseant direrror(idesc->id_number, msg); 256 1.1 perseant else 257 1.6 is pwarn("%s", msg); 258 1.1 perseant if (preen) { 259 1.1 perseant printf(" (SALVAGED)\n"); 260 1.1 perseant idesc->id_fix = FIX; 261 1.1 perseant return (ALTERED); 262 1.1 perseant } 263 1.1 perseant if (reply("SALVAGE") == 0) { 264 1.1 perseant idesc->id_fix = NOFIX; 265 1.1 perseant return (0); 266 1.1 perseant } 267 1.1 perseant idesc->id_fix = FIX; 268 1.1 perseant return (ALTERED); 269 1.1 perseant 270 1.1 perseant case FIX: 271 1.1 perseant return (ALTERED); 272 1.1 perseant 273 1.1 perseant case NOFIX: 274 1.1 perseant case IGNORE: 275 1.1 perseant return (0); 276 1.1 perseant 277 1.1 perseant default: 278 1.37 christos err(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix); 279 1.1 perseant } 280 1.1 perseant /* NOTREACHED */ 281 1.1 perseant } 282