1 /* $NetBSD: fsck_v7fs.c,v 1.3 2025/12/31 10:03:53 nia Exp $ */ 2 3 /*- 4 * Copyright (c) 2004, 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __RCSID("$NetBSD: fsck_v7fs.c,v 1.3 2025/12/31 10:03:53 nia Exp $"); 35 #endif /* not lint */ 36 37 #include <sys/types.h> 38 #include <sys/disklabel.h> 39 #include <sys/ioctl.h> 40 #include <sys/stat.h> 41 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <endian.h> 46 #include <unistd.h> 47 #include <fcntl.h> 48 #include <err.h> 49 50 #include <fs/v7fs/v7fs.h> 51 #include "v7fs_impl.h" 52 #include "fsck_v7fs.h" 53 #include "progress.h" 54 55 static void usage(void) __dead; 56 static void catopt(char **, const char *); 57 58 enum fsck_operate fsck_operate; 59 bool verbose = true; 60 #define VPRINTF(fmt, args...) { if (verbose) printf(fmt, ##args); } 61 62 int 63 main(int argc, char **argv) 64 { 65 const char *device; 66 struct disklabel d; 67 struct partition *p; 68 struct stat st; 69 int Fflag = 0; 70 int part; 71 int fd, ch; 72 int endian = BYTE_ORDER; 73 int openflags = O_RDWR; 74 size_t part_sectors; 75 int fsck_flags = 0; 76 char *options = 0; 77 bool progress_bar_enable = false; 78 79 fsck_operate = ASK; 80 81 if (argc < 2) 82 usage(); 83 84 while ((ch = getopt(argc, argv, "pPqynfx:dFB:o:")) != -1) { 85 switch (ch) { 86 /* 87 * generic fsck options 88 */ 89 case 'd': /* Not supported */ 90 break; 91 case 'f': /* Always forced */ 92 break; 93 case 'p': 94 fsck_operate = PREEN; 95 break; 96 case 'y': 97 fsck_operate = ALWAYS_YES; 98 break; 99 case 'n': 100 fsck_operate = ALWAYS_NO; 101 openflags = O_RDONLY; 102 break; 103 case 'P': 104 progress_bar_enable = true; 105 break; 106 case 'q': /* Not supported */ 107 break; 108 case 'x': /* Not supported */ 109 break; 110 /* 111 * v7fs fsck options 112 */ 113 case 'F': 114 Fflag = 1; 115 break; 116 case 'B': 117 switch (optarg[0]) { 118 case 'l': 119 endian = LITTLE_ENDIAN; 120 break; 121 case 'b': 122 endian = BIG_ENDIAN; 123 break; 124 case 'p': 125 endian = PDP_ENDIAN; 126 break; 127 } 128 break; 129 case 'o': /* datablock, freeblock duplication check */ 130 if (*optarg) 131 catopt(&options, optarg); 132 break; 133 default: 134 usage(); 135 /*NOTREACHED*/ 136 } 137 } 138 139 argc -= optind; 140 argv += optind; 141 142 if (argc != 1) 143 usage(); 144 device = argv[0]; 145 146 if (options) { 147 if (strstr(options, "data")) 148 fsck_flags |= V7FS_FSCK_DATABLOCK_DUP; 149 if (strstr(options, "free")) 150 fsck_flags |= V7FS_FSCK_FREEBLOCK_DUP; 151 } 152 153 if (Fflag) { 154 if ((fd = open(device, openflags)) == -1) { 155 pfatal("%s", device); 156 } 157 if (fstat(fd, &st)) { 158 pfatal("stat"); 159 } 160 part_sectors = st.st_size >> V7FS_BSHIFT; 161 setcdevname(device, fsck_operate == PREEN); 162 } else { 163 /* blockcheck sets 'hot' */ 164 device = blockcheck(device); 165 setcdevname(device, fsck_operate == PREEN); 166 167 if ((fd = open(device, openflags)) == -1) { 168 pfatal("%s", device); 169 } 170 part = DISKPART(st.st_rdev); 171 172 if (ioctl(fd, DIOCGDINFO, &d) == -1) { 173 pfatal("DIOCGDINFO"); 174 } 175 p = &d.d_partitions[part]; 176 part_sectors = p->p_size; 177 VPRINTF("partition=%d size=%d offset=%d fstype=%d secsize=%d\n", 178 part, p->p_size, p->p_offset, p->p_fstype, d.d_secsize); 179 if (p->p_fstype != FS_V7) { 180 pfatal("not a Version 7 partition."); 181 } 182 } 183 184 progress_switch(progress_bar_enable); 185 progress_init(); 186 progress(&(struct progress_arg){ .cdev = device }); 187 188 struct v7fs_mount_device mount; 189 mount.device.fd = fd; 190 mount.endian = endian; 191 mount.sectors = part_sectors; 192 int error = v7fs_fsck(&mount, fsck_flags); 193 194 close(fd); 195 196 return error; 197 } 198 199 static void 200 catopt(char **sp, const char *o) 201 { 202 char *s, *n; 203 204 s = *sp; 205 if (s) { 206 if (asprintf(&n, "%s,%s", s, o) < 0) 207 err(1, "asprintf"); 208 free(s); 209 s = n; 210 } else 211 s = strdup(o); 212 *sp = s; 213 } 214 215 static void 216 usage(void) 217 { 218 219 (void)fprintf(stderr, "usage: %s [-ynpP] [-o options] [-B endian] " 220 "special-device\n", 221 getprogname()); 222 (void)fprintf(stderr, "usage: %s -F [-ynpP] [-o options] [-B endian] " 223 "file\n", 224 getprogname()); 225 226 exit(FSCK_EXIT_USAGE); 227 } 228