1/* $NetBSD$ */ 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$"); 35#endif /* not lint */ 36 37#include <stdio.h> 38#include <stdlib.h> 39#include <string.h> 40#include <unistd.h> 41#include <fcntl.h> 42#include <err.h> 43#include <sys/ioctl.h> 44#include <sys/disklabel.h> 45 46#include <fs/v7fs/v7fs.h> 47#include "v7fs_impl.h" 48#include "fsck_v7fs.h" 49#include "progress.h" 50 51static void usage(void) __dead; 52static void catopt(char **, const char *); 53 54enum fsck_operate fsck_operate; 55bool verbose = true; 56#define VPRINTF(fmt, args...) { if (verbose) printf(fmt, ##args); } 57 58int 59main(int argc, char **argv) 60{ 61 const char *device; 62 struct disklabel d; 63 struct partition *p; 64 struct stat st; 65 int Fflag = 0; 66 int part; 67 int fd, ch; 68 int endian = _BYTE_ORDER; 69 int openflags = O_RDWR; 70 size_t part_sectors; 71 int fsck_flags = 0; 72 char *options = 0; 73 bool progress_bar_enable = false; 74 75 fsck_operate = ASK; 76 77 if (argc < 2) 78 usage(); 79 80 while ((ch = getopt(argc, argv, "pPqynfx:dFB:o:")) != -1) { 81 switch (ch) { 82 /* 83 * generic fsck options 84 */ 85 case 'd': /* Not supported */ 86 break; 87 case 'f': /* Always forced */ 88 break; 89 case 'p': 90 fsck_operate = PREEN; 91 break; 92 case 'y': 93 fsck_operate = ALWAYS_YES; 94 break; 95 case 'n': 96 fsck_operate = ALWAYS_NO; 97 openflags = O_RDONLY; 98 break; 99 case 'P': 100 progress_bar_enable = true; 101 break; 102 case 'q': /* Not supported */ 103 break; 104 case 'x': /* Not supported */ 105 break; 106 /* 107 * v7fs fsck options 108 */ 109 case 'F': 110 Fflag = 1; 111 break; 112 case 'B': 113 switch (optarg[0]) { 114 case 'l': 115 endian = _LITTLE_ENDIAN; 116 break; 117 case 'b': 118 endian = _BIG_ENDIAN; 119 break; 120 case 'p': 121 endian = _PDP_ENDIAN; 122 break; 123 } 124 break; 125 case 'o': /* datablock, freeblock duplication check */ 126 if (*optarg) 127 catopt(&options, optarg); 128 break; 129 default: 130 usage(); 131 /*NOTREACHED*/ 132 } 133 } 134 135 argc -= optind; 136 argv += optind; 137 138 if (argc != 1) 139 usage(); 140 device = argv[0]; 141 142 if (options) { 143 if (strstr(options, "data")) 144 fsck_flags |= V7FS_FSCK_DATABLOCK_DUP; 145 if (strstr(options, "free")) 146 fsck_flags |= V7FS_FSCK_FREEBLOCK_DUP; 147 } 148 149 if (Fflag) { 150 if ((fd = open(device, openflags)) == -1) { 151 pfatal("%s", device); 152 } 153 if (fstat(fd, &st)) { 154 pfatal("stat"); 155 } 156 part_sectors = st.st_size >> V7FS_BSHIFT; 157 setcdevname(device, fsck_operate == PREEN); 158 } else { 159 /* blockcheck sets 'hot' */ 160 device = blockcheck(device); 161 setcdevname(device, fsck_operate == PREEN); 162 163 if ((fd = open(device, openflags)) == -1) { 164 pfatal("%s", device); 165 } 166 part = DISKPART(st.st_rdev); 167 168 if (ioctl(fd, DIOCGDINFO, &d) == -1) { 169 pfatal("DIOCGDINFO"); 170 } 171 p = &d.d_partitions[part]; 172 part_sectors = p->p_size; 173 VPRINTF("partition=%d size=%d offset=%d fstype=%d secsize=%d\n", 174 part, p->p_size, p->p_offset, p->p_fstype, d.d_secsize); 175 if (p->p_fstype != FS_V7) { 176 pfatal("not a Version 7 partition."); 177 } 178 } 179 180 progress_switch(progress_bar_enable); 181 progress_init(); 182 progress(&(struct progress_arg){ .cdev = device }); 183 184 struct v7fs_mount_device mount; 185 mount.device.fd = fd; 186 mount.endian = endian; 187 mount.sectors = part_sectors; 188 int error = v7fs_fsck(&mount, fsck_flags); 189 190 close(fd); 191 192 return error; 193} 194 195static void 196catopt(char **sp, const char *o) 197{ 198 char *s, *n; 199 200 s = *sp; 201 if (s) { 202 if (asprintf(&n, "%s,%s", s, o) < 0) 203 err(1, "asprintf"); 204 free(s); 205 s = n; 206 } else 207 s = strdup(o); 208 *sp = s; 209} 210 211static void 212usage(void) 213{ 214 215 (void)fprintf(stderr, "usage: %s [-ynpP] [-o options] [-B endian] " 216 "special-device\n", 217 getprogname()); 218 (void)fprintf(stderr, "usage: %s -F [-ynpP] [-o options] [-B endian] " 219 "file\n", 220 getprogname()); 221 222 exit(FSCK_EXIT_USAGE); 223} 224