xref: /illumos-gate/usr/src/cmd/fs.d/udfs/fsck/main.c (revision 7c478bd9)
1 /*
2  * Copyright 1999 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 void
91 main(argc, argv)
92 	int	argc;
93 	char	*argv[];
94 {
95 	int	c;
96 	char	*suboptions,	*value;
97 	int	suboption;
98 
99 	(void) setlocale(LC_ALL, "");
100 
101 	while ((c = getopt(argc, argv, "mnNo:VyYz")) != EOF) {
102 		switch (c) {
103 
104 		case 'm':
105 			mflag++;
106 			break;
107 
108 		case 'n':	/* default no answer flag */
109 		case 'N':
110 			nflag++;
111 			yflag = 0;
112 			break;
113 
114 		case 'o':
115 			/*
116 			 * udfs specific options.
117 			 */
118 			suboptions = optarg;
119 			while (*suboptions != '\0') {
120 				suboption = getsubopt(&suboptions,
121 						subopts, &value);
122 				switch (suboption) {
123 
124 				case PREEN:
125 					preen++;
126 					break;
127 
128 				case DEBUG:
129 					debug++;
130 					break;
131 
132 				case READ_ONLY:
133 					break;
134 
135 				case ONLY_WRITES:
136 					/* check only writable filesystems */
137 					wflag++;
138 					break;
139 
140 				case FORCE:
141 					fflag++;
142 					break;
143 
144 				case STATS:
145 					sflag++;
146 					break;
147 
148 				default:
149 					usage();
150 				}
151 			}
152 			break;
153 
154 		case 'V':
155 			{
156 				int	opt_count;
157 				char	*opt_text;
158 
159 				(void) fprintf(stdout, "fsck -F udfs ");
160 				for (opt_count = 1; opt_count < argc;
161 								opt_count++) {
162 					opt_text = argv[opt_count];
163 					if (opt_text)
164 						(void) fprintf(stdout, " %s ",
165 								opt_text);
166 				}
167 				(void) fprintf(stdout, "\n");
168 			}
169 			break;
170 
171 		case 'y':	/* default yes answer flag */
172 		case 'Y':
173 			yflag++;
174 			nflag = 0;
175 			break;
176 
177 		case '?':
178 			usage();
179 		}
180 	}
181 	argc -= optind;
182 	argv = &argv[optind];
183 	rflag++; /* check raw devices */
184 	if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
185 		(void) signal(SIGINT, catch);
186 	}
187 
188 	if (preen) {
189 		(void) signal(SIGQUIT, catchquit);
190 	}
191 
192 	if (argc) {
193 		while (argc-- > 0) {
194 			if (wflag && !writable(*argv)) {
195 				(void) fprintf(stderr,
196 					gettext("not writeable '%s'\n"), *argv);
197 				argv++;
198 			} else
199 				checkfilesys(*argv++);
200 		}
201 		exit(exitstat);
202 	}
203 }
204 
205 
206 static void
207 checkfilesys(filesys)
208 	char *filesys;
209 {
210 	char *devstr;
211 
212 	mountfd = -1;
213 	mountedfs = 0;
214 	iscorrupt = 1;
215 
216 	if ((devstr = setup(filesys)) == 0) {
217 		if (iscorrupt == 0)
218 			return;
219 		if (preen)
220 			pfatal(gettext("CAN'T CHECK FILE SYSTEM."));
221 		if ((exitstat == 0) && (mflag))
222 			exitstat = 32;
223 		exit(exitstat);
224 	}
225 	else
226 		devname = devstr;
227 	if (mflag)
228 		check_sanity(filesys);	/* this never returns */
229 	iscorrupt = 0;
230 	/*
231 	 * 1: scan inodes tallying blocks used
232 	 */
233 	if (preen == 0) {
234 		if (mountedfs)
235 			(void) printf(gettext("** Currently Mounted on %s\n"),
236 				mountpoint);
237 		if (mflag) {
238 			(void) printf(
239 				gettext("** Phase 1 - Sanity Check only\n"));
240 			return;
241 		} else
242 			(void) printf(
243 				gettext("** Phase 1 - Check Directories "
244 				"and Blocks\n"));
245 	}
246 	pass1();
247 	if (sflag) {
248 		if (preen)
249 			(void) printf("%s: ", devname);
250 		else
251 			(void) printf("** ");
252 	}
253 	if (debug)
254 		(void) printf("pass1 isdirty %d\n", isdirty);
255 	if (debug)
256 		printfree();
257 	dofreemap();
258 	dolvint();
259 
260 	/*
261 	 * print out summary statistics
262 	 */
263 	pwarn(gettext("%d files, %d dirs, %d used, %d free\n"), n_files, n_dirs,
264 		n_blks, part_len - n_blks);
265 	if (iscorrupt)
266 		exitstat = 36;
267 	if (!fsmodified)
268 		return;
269 	if (!preen)
270 		(void) printf(
271 			gettext("\n***** FILE SYSTEM WAS MODIFIED *****\n"));
272 
273 	if (mountedfs) {
274 		exitstat = 40;
275 	}
276 }
277 
278 
279 /*
280  * exit 0 - file system is unmounted and okay
281  * exit 32 - file system is unmounted and needs checking
282  * exit 33 - file system is mounted
283  *	for root file system
284  * exit 34 - cannot stat device
285  */
286 
287 static void
288 check_sanity(filename)
289 char	*filename;
290 {
291 	struct stat stbd, stbr;
292 	struct ustat usb;
293 	char *devname;
294 	struct vfstab vfsbuf;
295 	FILE *vfstab;
296 	int is_root = 0;
297 	int is_usr = 0;
298 	int is_block = 0;
299 
300 	if (stat(filename, &stbd) < 0) {
301 		(void) fprintf(stderr,
302 			gettext("udfs fsck: sanity check failed : cannot stat "
303 			"%s\n"), filename);
304 		exit(34);
305 	}
306 
307 	if ((stbd.st_mode & S_IFMT) == S_IFBLK)
308 		is_block = 1;
309 	else if ((stbd.st_mode & S_IFMT) == S_IFCHR)
310 		is_block = 0;
311 	else {
312 		(void) fprintf(stderr,
313 			gettext("udfs fsck: sanity check failed: %s not "
314 			"block or character device\n"), filename);
315 		exit(34);
316 	}
317 
318 	/*
319 	 * Determine if this is the root file system via vfstab. Give up
320 	 * silently on failures. The whole point of this is not to care
321 	 * if the root file system is already mounted.
322 	 *
323 	 * XXX - similar for /usr. This should be fixed to simply return
324 	 * a new code indicating, mounted and needs to be checked.
325 	 */
326 	if ((vfstab = fopen(VFSTAB, "r")) != 0) {
327 		if (getvfsfile(vfstab, &vfsbuf, "/") == 0) {
328 			if (is_block)
329 				devname = vfsbuf.vfs_special;
330 			else
331 				devname = vfsbuf.vfs_fsckdev;
332 			if (stat(devname, &stbr) == 0)
333 				if (stbr.st_rdev == stbd.st_rdev)
334 					is_root = 1;
335 		}
336 		if (getvfsfile(vfstab, &vfsbuf, "/usr") == 0) {
337 			if (is_block)
338 				devname = vfsbuf.vfs_special;
339 			else
340 				devname = vfsbuf.vfs_fsckdev;
341 			if (stat(devname, &stbr) == 0)
342 				if (stbr.st_rdev == stbd.st_rdev)
343 					is_usr = 1;
344 		}
345 	}
346 
347 
348 	/*
349 	 * XXX - only works if filename is a block device or if
350 	 * character and block device has the same dev_t value
351 	 */
352 	if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) {
353 		(void) fprintf(stderr,
354 			gettext("udfs fsck: sanity check: %s "
355 			"already mounted\n"), filename);
356 		exit(33);
357 	}
358 
359 	if (lvintp->lvid_int_type == LVI_CLOSE) {
360 		(void) fprintf(stderr,
361 			gettext("udfs fsck: sanity check: %s okay\n"),
362 			filename);
363 	} else {
364 		(void) fprintf(stderr,
365 			gettext("udfs fsck: sanity check: %s needs checking\n"),
366 			filename);
367 		exit(32);
368 	}
369 	exit(0);
370 }
371 
372 char *
373 unrawname(name)
374 	char *name;
375 {
376 	char *dp;
377 
378 
379 	if ((dp = getfullblkname(name)) == NULL)
380 		return ("");
381 	return (dp);
382 }
383 
384 char *
385 rawname(name)
386 	char *name;
387 {
388 	char *dp;
389 
390 	if ((dp = getfullrawname(name)) == NULL)
391 		return ("");
392 	return (dp);
393 }
394 
395 char *
396 hasvfsopt(vfs, opt)
397 	register struct vfstab *vfs;
398 	register char *opt;
399 {
400 	char *f, *opts;
401 	static char *tmpopts;
402 
403 	if (vfs->vfs_mntopts == NULL)
404 		return (NULL);
405 	if (tmpopts == 0) {
406 		tmpopts = (char *)calloc(256, sizeof (char));
407 		if (tmpopts == 0)
408 			return (0);
409 	}
410 	(void) strncpy(tmpopts, vfs->vfs_mntopts, (sizeof (tmpopts) - 1));
411 	opts = tmpopts;
412 	f = mntopt(&opts);
413 	for (; *f; f = mntopt(&opts)) {
414 		if (strncmp(opt, f, strlen(opt)) == 0)
415 			return (f - tmpopts + vfs->vfs_mntopts);
416 	}
417 	return (NULL);
418 }
419 
420 static void
421 usage()
422 {
423 	(void) fprintf(stderr, gettext("udfs usage: fsck [-F udfs] "
424 		"[generic options] [-o p,w,s] [special ....]\n"));
425 	exit(31+1);
426 }
427