xref: /illumos-gate/usr/src/cmd/fs.d/udfs/fsck/main.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7 /*	  All Rights Reserved  	*/
8 
9 /*
10  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms are permitted
14  * provided that: (1) source distributions retain this entire copyright
15  * notice and comment, and (2) distributions including binaries display
16  * the following acknowledgement:  ``This product includes software
17  * developed by the University of California, Berkeley and its contributors''
18  * in the documentation or other materials provided with the distribution
19  * and in all advertising materials mentioning features or use of this
20  * software. Neither the name of the University nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>	/* use isdigit macro rather than 4.1 libc routine */
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <signal.h>
36 #include <malloc.h>
37 #include <ustat.h>
38 #include <sys/param.h>
39 #include <sys/types.h>
40 #include <sys/sysmacros.h>
41 #include <sys/mntent.h>
42 #include <sys/vnode.h>
43 #include <sys/stat.h>
44 #include <sys/wait.h>
45 #include <sys/mnttab.h>
46 #include <sys/signal.h>
47 #include <sys/vfstab.h>
48 #include <sys/fs/udf_volume.h>
49 #include "fsck.h"
50 #include <locale.h>
51 
52 extern int32_t	writable(char *);
53 extern void	pfatal(char *, ...);
54 extern void	printfree();
55 extern void	pwarn(char *, ...);
56 
57 extern void	pass1();
58 extern void	dofreemap();
59 extern void	dolvint();
60 extern char	*getfullblkname();
61 extern char	*getfullrawname();
62 
63 static int	mflag = 0;		/* sanity check only */
64 
65 char	*mntopt();
66 void	catch(), catchquit(), voidquit();
67 int	returntosingle;
68 static void	checkfilesys();
69 static void	check_sanity();
70 static void	usage();
71 
72 static char *subopts [] = {
73 #define	PREEN		0
74 	"p",
75 #define	DEBUG		1
76 	"d",
77 #define	READ_ONLY	2
78 	"r",
79 #define	ONLY_WRITES	3
80 	"w",
81 #define	FORCE		4	/* force checking, even if clean */
82 	"f",
83 #define	STATS		5	/* print time and busy stats */
84 	"s",
85 	NULL
86 };
87 
88 uint32_t ecma_version = 2;
89 
90 int
91 main(int argc, char *argv[])
92 {
93 	int	c;
94 	char	*suboptions,	*value;
95 	int	suboption;
96 
97 	(void) setlocale(LC_ALL, "");
98 
99 	while ((c = getopt(argc, argv, "mnNo:VyYz")) != EOF) {
100 		switch (c) {
101 
102 		case 'm':
103 			mflag++;
104 			break;
105 
106 		case 'n':	/* default no answer flag */
107 		case 'N':
108 			nflag++;
109 			yflag = 0;
110 			break;
111 
112 		case 'o':
113 			/*
114 			 * udfs specific options.
115 			 */
116 			suboptions = optarg;
117 			while (*suboptions != '\0') {
118 				suboption = getsubopt(&suboptions,
119 						subopts, &value);
120 				switch (suboption) {
121 
122 				case PREEN:
123 					preen++;
124 					break;
125 
126 				case DEBUG:
127 					debug++;
128 					break;
129 
130 				case READ_ONLY:
131 					break;
132 
133 				case ONLY_WRITES:
134 					/* check only writable filesystems */
135 					wflag++;
136 					break;
137 
138 				case FORCE:
139 					fflag++;
140 					break;
141 
142 				case STATS:
143 					sflag++;
144 					break;
145 
146 				default:
147 					usage();
148 				}
149 			}
150 			break;
151 
152 		case 'V':
153 			{
154 				int	opt_count;
155 				char	*opt_text;
156 
157 				(void) fprintf(stdout, "fsck -F udfs ");
158 				for (opt_count = 1; opt_count < argc;
159 								opt_count++) {
160 					opt_text = argv[opt_count];
161 					if (opt_text)
162 						(void) fprintf(stdout, " %s ",
163 								opt_text);
164 				}
165 				(void) fprintf(stdout, "\n");
166 			}
167 			break;
168 
169 		case 'y':	/* default yes answer flag */
170 		case 'Y':
171 			yflag++;
172 			nflag = 0;
173 			break;
174 
175 		case '?':
176 			usage();
177 		}
178 	}
179 	argc -= optind;
180 	argv = &argv[optind];
181 	rflag++; /* check raw devices */
182 	if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
183 		(void) signal(SIGINT, catch);
184 	}
185 
186 	if (preen) {
187 		(void) signal(SIGQUIT, catchquit);
188 	}
189 
190 	if (argc) {
191 		while (argc-- > 0) {
192 			if (wflag && !writable(*argv)) {
193 				(void) fprintf(stderr,
194 					gettext("not writeable '%s'\n"), *argv);
195 				argv++;
196 			} else
197 				checkfilesys(*argv++);
198 		}
199 		exit(exitstat);
200 	}
201 	return (0);
202 }
203 
204 
205 static void
206 checkfilesys(char *filesys)
207 {
208 	char *devstr;
209 
210 	mountfd = -1;
211 	mountedfs = 0;
212 	iscorrupt = 1;
213 
214 	if ((devstr = setup(filesys)) == 0) {
215 		if (iscorrupt == 0)
216 			return;
217 		if (preen)
218 			pfatal(gettext("CAN'T CHECK FILE SYSTEM."));
219 		if ((exitstat == 0) && (mflag))
220 			exitstat = 32;
221 		exit(exitstat);
222 	}
223 	else
224 		devname = devstr;
225 	if (mflag)
226 		check_sanity(filesys);	/* this never returns */
227 	iscorrupt = 0;
228 	/*
229 	 * 1: scan inodes tallying blocks used
230 	 */
231 	if (preen == 0) {
232 		if (mountedfs)
233 			(void) printf(gettext("** Currently Mounted on %s\n"),
234 				mountpoint);
235 		if (mflag) {
236 			(void) printf(
237 				gettext("** Phase 1 - Sanity Check only\n"));
238 			return;
239 		} else
240 			(void) printf(
241 				gettext("** Phase 1 - Check Directories "
242 				"and Blocks\n"));
243 	}
244 	pass1();
245 	if (sflag) {
246 		if (preen)
247 			(void) printf("%s: ", devname);
248 		else
249 			(void) printf("** ");
250 	}
251 	if (debug)
252 		(void) printf("pass1 isdirty %d\n", isdirty);
253 	if (debug)
254 		printfree();
255 	dofreemap();
256 	dolvint();
257 
258 	/*
259 	 * print out summary statistics
260 	 */
261 	pwarn(gettext("%d files, %d dirs, %d used, %d free\n"), n_files, n_dirs,
262 		n_blks, part_len - n_blks);
263 	if (iscorrupt)
264 		exitstat = 36;
265 	if (!fsmodified)
266 		return;
267 	if (!preen)
268 		(void) printf(
269 			gettext("\n***** FILE SYSTEM WAS MODIFIED *****\n"));
270 
271 	if (mountedfs) {
272 		exitstat = 40;
273 	}
274 }
275 
276 
277 /*
278  * exit 0 - file system is unmounted and okay
279  * exit 32 - file system is unmounted and needs checking
280  * exit 33 - file system is mounted
281  *	for root file system
282  * exit 34 - cannot stat device
283  */
284 
285 static void
286 check_sanity(char *filename)
287 {
288 	struct stat stbd, stbr;
289 	struct ustat usb;
290 	char *devname;
291 	struct vfstab vfsbuf;
292 	FILE *vfstab;
293 	int is_root = 0;
294 	int is_usr = 0;
295 	int is_block = 0;
296 
297 	if (stat(filename, &stbd) < 0) {
298 		(void) fprintf(stderr,
299 			gettext("udfs fsck: sanity check failed : cannot stat "
300 			"%s\n"), filename);
301 		exit(34);
302 	}
303 
304 	if ((stbd.st_mode & S_IFMT) == S_IFBLK)
305 		is_block = 1;
306 	else if ((stbd.st_mode & S_IFMT) == S_IFCHR)
307 		is_block = 0;
308 	else {
309 		(void) fprintf(stderr,
310 			gettext("udfs fsck: sanity check failed: %s not "
311 			"block or character device\n"), filename);
312 		exit(34);
313 	}
314 
315 	/*
316 	 * Determine if this is the root file system via vfstab. Give up
317 	 * silently on failures. The whole point of this is not to care
318 	 * if the root file system is already mounted.
319 	 *
320 	 * XXX - similar for /usr. This should be fixed to simply return
321 	 * a new code indicating, mounted and needs to be checked.
322 	 */
323 	if ((vfstab = fopen(VFSTAB, "r")) != 0) {
324 		if (getvfsfile(vfstab, &vfsbuf, "/") == 0) {
325 			if (is_block)
326 				devname = vfsbuf.vfs_special;
327 			else
328 				devname = vfsbuf.vfs_fsckdev;
329 			if (stat(devname, &stbr) == 0)
330 				if (stbr.st_rdev == stbd.st_rdev)
331 					is_root = 1;
332 		}
333 		if (getvfsfile(vfstab, &vfsbuf, "/usr") == 0) {
334 			if (is_block)
335 				devname = vfsbuf.vfs_special;
336 			else
337 				devname = vfsbuf.vfs_fsckdev;
338 			if (stat(devname, &stbr) == 0)
339 				if (stbr.st_rdev == stbd.st_rdev)
340 					is_usr = 1;
341 		}
342 	}
343 
344 
345 	/*
346 	 * XXX - only works if filename is a block device or if
347 	 * character and block device has the same dev_t value
348 	 */
349 	if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) {
350 		(void) fprintf(stderr,
351 			gettext("udfs fsck: sanity check: %s "
352 			"already mounted\n"), filename);
353 		exit(33);
354 	}
355 
356 	if (lvintp->lvid_int_type == LVI_CLOSE) {
357 		(void) fprintf(stderr,
358 			gettext("udfs fsck: sanity check: %s okay\n"),
359 			filename);
360 	} else {
361 		(void) fprintf(stderr,
362 			gettext("udfs fsck: sanity check: %s needs checking\n"),
363 			filename);
364 		exit(32);
365 	}
366 	exit(0);
367 }
368 
369 char *
370 unrawname(char *name)
371 {
372 	char *dp;
373 
374 
375 	if ((dp = getfullblkname(name)) == NULL)
376 		return ("");
377 	return (dp);
378 }
379 
380 char *
381 rawname(char *name)
382 {
383 	char *dp;
384 
385 	if ((dp = getfullrawname(name)) == NULL)
386 		return ("");
387 	return (dp);
388 }
389 
390 char *
391 hasvfsopt(struct vfstab *vfs, char *opt)
392 {
393 	char *f, *opts;
394 	static char *tmpopts;
395 
396 	if (vfs->vfs_mntopts == NULL)
397 		return (NULL);
398 	if (tmpopts == 0) {
399 		tmpopts = (char *)calloc(256, sizeof (char));
400 		if (tmpopts == 0)
401 			return (0);
402 	}
403 	(void) strncpy(tmpopts, vfs->vfs_mntopts, (sizeof (tmpopts) - 1));
404 	opts = tmpopts;
405 	f = mntopt(&opts);
406 	for (; *f; f = mntopt(&opts)) {
407 		if (strncmp(opt, f, strlen(opt)) == 0)
408 			return (f - tmpopts + vfs->vfs_mntopts);
409 	}
410 	return (NULL);
411 }
412 
413 static void
414 usage()
415 {
416 	(void) fprintf(stderr, gettext("udfs usage: fsck [-F udfs] "
417 		"[generic options] [-o p,w,s] [special ....]\n"));
418 	exit(31+1);
419 }
420