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