xref: /netbsd-src/sbin/fsck_v7fs/fsck_v7fs.c (revision 9878dfd06c4f0b41e96080b9d986c2e348978718)
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