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