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
main(int argc,char * argv[])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
checkfilesys(char * filesys)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
check_sanity(char * filename)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 *
unrawname(char * name)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 *
rawname(char * name)381 rawname(char *name)
382 {
383 char *dp;
384
385 if ((dp = getfullrawname(name)) == NULL)
386 return ("");
387 return (dp);
388 }
389
390 char *
hasvfsopt(struct vfstab * vfs,char * opt)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
usage()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