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