1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
33 */
34
35 #pragma ident "%Z%%M% %I% %E% SMI"
36
37 /*
38 *
39 * fsck.c
40 *
41 * Cachefs fsck program.
42 */
43
44 #include <locale.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <assert.h>
49 #include <stdarg.h>
50 #include <unistd.h>
51 #include <limits.h>
52 #include <errno.h>
53 #include <wait.h>
54 #include <ctype.h>
55 #include <fcntl.h>
56 #include <ftw.h>
57 #include <dirent.h>
58 #include <search.h>
59 #include <sys/types.h>
60 #include <sys/uio.h>
61 #include <sys/param.h>
62 #include <sys/stat.h>
63 #include <sys/fcntl.h>
64 #include <sys/mount.h>
65 #include <sys/mntent.h>
66 #include <sys/mnttab.h>
67 #include <sys/mman.h>
68 #include <sys/fs/cachefs_fs.h>
69 #include <syslog.h>
70 #include "../common/subr.h"
71 #include "res.h"
72
73 char *cfs_opts[] = {
74 #define CFSOPT_PREEN 0
75 "preen",
76 #define CFSOPT_NOCLEAN 1
77 "noclean",
78 #define CFSOPT_VERBOSE 2
79 "verbose",
80 #define CFSOPT_NONOCLEAN 3
81 "nonoclean",
82
83 NULL
84 };
85
86 extern int dlog_ck(char *dir_path, ino64_t *maxlocalfilenop);
87
88 /* forward references */
89 void usage(char *msgp);
90 void pr_err(char *fmt, ...);
91 int cfs_check(char *cachedirp, int noclean, int mflag, int verbose,
92 int nonoclean);
93 int cache_label_file(char *cachedirp, struct cache_label *clabelp);
94 int cache_permissions(char *cachedirp);
95 int cache_check_dir(char *cachedirp, char *namep);
96 int process_fsdir(char *cachedirp, char *namep, res *resp, int verbose);
97 int process_fsinfo(char *namep, ino64_t maxlocalfileno,
98 cachefs_fsinfo_t *fsinfop, int verbose);
99 int process_fsgroup(char *dirp, char *namep, res *resp, ino64_t base,
100 int fgsize, ino64_t fsid, int local, int verbose);
101 int tree_remove(const char *namep, const struct stat64 *statp, int type,
102 struct FTW *ftwp);
103 int cache_upgrade(char *cachedirp, int lockid);
104 int file_remove(const char *namep, const struct stat64 *statp, int verbose);
105 void cache_backmnt_cleanup(char *cachedirp, char *backmnt_namep);
106
107 #define FLAGS_FTW (FTW_PHYS | FTW_MOUNT | FTW_DEPTH)
108
109 static int S_verbose = 0;
110 static char S_lostfound[MAXPATHLEN];
111 static int S_move_lostfound = 0;
112
113 /*
114 *
115 * main
116 *
117 * Description:
118 * Main routine for the cachefs fsck program.
119 * Arguments:
120 * argc number of command line arguments
121 * argv list of command line arguments
122 * Returns:
123 * Returns:
124 * 0 file system is okay and does not need checking
125 * 1 problem unrelated to the file system
126 * 32 file system is unmounted and needs checking (fsck
127 * -m only)
128 * 33 file system is already mounted
129 * 34 cannot stat device
130 * 36 uncorrectable errors detected - terminate normally
131 * 37 a signal was caught during processing
132 * 39 uncorrectable errors detected - terminate immediately
133 * 40 for root mounted fs, same as 0
134 * Preconditions:
135 */
136
137 int
main(int argc,char ** argv)138 main(int argc, char **argv)
139 {
140 int xx;
141 int c;
142 char *optionp;
143 char *valuep;
144 int mflag;
145 int noclean;
146 char *cachedirp;
147 int lockid;
148 int verbose;
149 int nonoclean;
150
151 (void) setlocale(LC_ALL, "");
152 #if !defined(TEXT_DOMAIN)
153 #define TEXT_DOMAIN "SYS_TEST"
154 #endif
155 (void) textdomain(TEXT_DOMAIN);
156
157 /* verify root running command */
158 if (getuid() != 0) {
159 fprintf(stderr, gettext(
160 "fsck -F cachefs: must be run by root\n"));
161 return (1);
162 }
163
164 /* process command line options */
165 optionp = NULL;
166 mflag = 0;
167 noclean = 0;
168 verbose = 0;
169 nonoclean = 0;
170 while ((c = getopt(argc, argv, "mnNo:yY")) != EOF) {
171 switch (c) {
172 case 'm': /* check but do not repair */
173 mflag = 1;
174 break;
175
176 case 'n': /* answer no to questions */
177 case 'N':
178 /* ignored */
179 break;
180
181 case 'o':
182 optionp = optarg;
183 while (*optionp) {
184 xx = getsubopt(&optionp, cfs_opts, &valuep);
185 switch (xx) {
186 case CFSOPT_PREEN:
187 /* preen is the default mode */
188 break;
189 case CFSOPT_NOCLEAN:
190 noclean = 1;
191 break;
192 case CFSOPT_VERBOSE:
193 verbose++;
194 S_verbose++;
195 break;
196 case CFSOPT_NONOCLEAN:
197 nonoclean = 1;
198 break;
199 default:
200 case -1:
201 pr_err(gettext("unknown option %s"),
202 valuep);
203 return (1);
204 }
205 }
206 break;
207
208 case 'y': /* answer yes to questions */
209 case 'Y':
210 /* ignored, this is the default */
211 break;
212
213 default:
214 usage("invalid option");
215 return (1);
216 }
217 }
218
219 /* verify fsck device is specified */
220 if (argc - optind < 1) {
221 usage(gettext("must specify cache directory"));
222 return (1);
223 }
224
225 /* save cache directory */
226 cachedirp = argv[argc - 1];
227
228 /* ensure cache directory exists */
229 if (access(cachedirp, F_OK) != 0) {
230 pr_err(gettext("Cache directory %s does not exist."),
231 cachedirp);
232 return (39);
233 }
234
235 /* lock the cache directory non-shared */
236 lockid = cachefs_dir_lock(cachedirp, 0);
237 if (lockid == -1) {
238 /* exit if could not get the lock */
239 return (1);
240 }
241
242 /* is the cache directory in use */
243 if (cachefs_inuse(cachedirp)) {
244 if (noclean) {
245 pr_err(gettext("Cache directory %s is in use."),
246 cachedirp);
247 xx = 33;
248 } else {
249 /* assume if in use that it is clean */
250 xx = 0;
251 }
252 cachefs_dir_unlock(lockid);
253 return (xx);
254 }
255
256 xx = cache_upgrade(cachedirp, lockid);
257 if (xx != 0) {
258 /* check the file system */
259 xx = cfs_check(cachedirp, noclean, mflag, verbose, nonoclean);
260 }
261
262 /* unlock the cache directory */
263 cachefs_dir_unlock(lockid);
264
265 /* inform if files moved to lost+found */
266 if (S_move_lostfound) {
267 pr_err(gettext("Files recovered to %s"), S_lostfound);
268 }
269
270 /* return the status of the file system checking */
271 return (xx);
272 }
273
274 /*
275 *
276 * usage
277 *
278 * Description:
279 * Prints a short usage message.
280 * Arguments:
281 * msgp message to include with the usage message
282 * Returns:
283 * Preconditions:
284 */
285
286 void
usage(char * msgp)287 usage(char *msgp)
288 {
289 if (msgp) {
290 pr_err("%s", msgp);
291 }
292
293 (void) fprintf(stderr,
294 gettext("Usage: fsck -F cachefs [ -o specific_options ] [ -m ] "
295 "cachedir\n"));
296 }
297
298 /*
299 *
300 * pr_err
301 *
302 * Description:
303 * Prints an error message to stderr.
304 * Arguments:
305 * fmt printf style format
306 * ... arguments for fmt
307 * Returns:
308 * Preconditions:
309 * precond(fmt)
310 */
311
312 void
pr_err(char * fmt,...)313 pr_err(char *fmt, ...)
314 {
315 va_list ap;
316
317 va_start(ap, fmt);
318 (void) fprintf(stderr, gettext("fsck -F cachefs: "));
319 (void) vfprintf(stderr, fmt, ap);
320 (void) fprintf(stderr, "\n");
321 va_end(ap);
322 }
323
324 /*
325 *
326 * cache_upgrade
327 *
328 * Description:
329 *
330 * See if the current cache is out of date. If it is, do
331 * whatever magic is necessary to upgrade it. All such magic
332 * should be encapsulated here!
333 *
334 * Arguments:
335 *
336 * cachedirp name of the cache directory to check
337 *
338 * Returns:
339 * Returns:
340 * 0 cache was upgraded and shouldn't be checked
341 * 1 problem unrelated to the file system
342 * 36 uncorrectable errors detected - terminate normally
343 * 39 uncorrectable errors detected - terminate immediately
344 * 50 cache was already up-to-date (maybe we should fsck it)
345 * 51 cache was upgraded (but you should do fsck)
346 * Preconditions:
347 * precond(cachedirp)
348 */
349
350 int
cache_upgrade(char * cachedirp,int lockid)351 cache_upgrade(char *cachedirp, int lockid)
352 {
353 #ifdef CFSRLDEBUG
354 static int canupgrade[] = {1, 2, 3, 103, 104, 105, 106, 107,
355 4, 5, 108, 6, 7, 8, 0};
356 #else /* CFSRLDEBUG */
357 static int canupgrade[] = {1, 2, 3, 103, 104, 105, 106, 107,
358 4, 108, 5, 109, 110, 6, 111, 0};
359 #endif /* CFSRLDEBUG */
360 char labelpath[MAXPATHLEN];
361 struct cache_label clabel;
362 int i;
363
364 if (((int)strlen(cachedirp) + (int)strlen(CACHELABEL_NAME) + 2)
365 >= MAXPATHLEN)
366 return (1);
367
368 (void) sprintf(labelpath, "%s/%s", cachedirp, CACHELABEL_NAME);
369
370 if (cachefs_label_file_get(labelpath, &clabel) != 0)
371 return (1);
372
373 /* nothing to do if we're current */
374 if (clabel.cl_cfsversion == CFSVERSION)
375 return (50);
376
377 /* see if it's an old version that we know how to upgrade */
378 for (i = 0; canupgrade[i] != 0; i++)
379 if (clabel.cl_cfsversion == canupgrade[i])
380 break;
381 if (canupgrade[i] == 0)
382 return (36);
383
384 syslog(LOG_USER | LOG_INFO,
385 gettext("fsck -F cachefs: Recreating cache %s"), cachedirp);
386
387 /* currently, to `upgrade' we delete the old cache */
388 if (cachefs_delete_all_cache(cachedirp) != 0)
389 return (36);
390
391 /* do any magic necessary to convert the old label to the new one */
392 clabel.cl_cfsversion = CFSVERSION;
393
394 /* create the new cache! */
395 if (cachefs_create_cache(cachedirp, NULL, &clabel) != 0)
396 return (36);
397
398 return (0);
399 }
400
401 /*
402 *
403 * cfs_check
404 *
405 * Description:
406 * This routine performs the actual checking of the cache
407 * file system.
408 * The file system must be inactive when this routine is called.
409 * Arguments:
410 * cachedirp name of the cache directory to check
411 * noclean 1 means ignore clean flag
412 * mflag 1 means no fixes, only check if mountable
413 * verbose indicate level of verbosity for diagnostics
414 * nonoclean 1 means honor clean flag; don't by default
415 * Returns:
416 * Returns:
417 * 0 file system is okay and does not need checking
418 * 1 problem unrelated to the file system
419 * 32 file system is unmounted and needs checking
420 * 33 file system is already mounted
421 * 34 cannot stat device
422 * 36 uncorrectable errors detected - terminate normally
423 * 37 a signal was caught during processing
424 * 39 uncorrectable errors detected - terminate immediately
425 * 40 for root mounted fs, same as 0, XXX
426 * Preconditions:
427 * precond(cachedirp)
428 */
429
430 int
cfs_check(char * cachedirp,int noclean,int mflag,int verbose,int nonoclean)431 cfs_check(char *cachedirp, int noclean, int mflag, int verbose, int nonoclean)
432 {
433 DIR *dp;
434 struct dirent64 *dep;
435 char buf[MAXPATHLEN];
436 struct stat64 statinfo;
437 int xx;
438 char *namep;
439 res *resp;
440 struct cache_label clabel;
441
442 /* if checking the clean flag is sufficient */
443 if ((noclean == 0) && (nonoclean || mflag)) {
444 /* if the clean flag is set */
445 if (cachefs_clean_flag_test(cachedirp)) {
446 if (verbose) {
447 pr_err(gettext("Cache %s is clean"), cachedirp);
448 }
449 return (0);
450 }
451 }
452
453 /* if mflag specified then go no farther */
454 if (mflag)
455 return (32);
456
457 /* check the cache label file for correctness */
458 xx = cache_label_file(cachedirp, &clabel);
459 if (xx)
460 return (xx);
461
462 /* make sure the kernel lock file exists */
463 sprintf(buf, "%s/%s", cachedirp, CACHEFS_LOCK_FILE);
464 xx = open(buf, O_RDWR | O_CREAT, 0700);
465 if (xx == -1) {
466 pr_err(gettext("Cannot create lock file %s"), buf);
467 return (39);
468 }
469 close(xx);
470
471 /* fix permissions on the cache directory */
472 xx = cache_permissions(cachedirp);
473 if (xx)
474 return (xx);
475
476 /* make the back file system mount directory if necessary */
477 xx = cache_check_dir(cachedirp, BACKMNT_NAME);
478 if (xx)
479 return (xx);
480
481 /* clean out junk in the back file system mount directory */
482 cache_backmnt_cleanup(cachedirp, BACKMNT_NAME);
483
484 /* make the lost+found directory if necessary */
485 xx = cache_check_dir(cachedirp, CACHEFS_LOSTFOUND_NAME);
486 if (xx)
487 return (xx);
488
489 /* construct the path to the lost and found directory for file_remove */
490 sprintf(S_lostfound, "%s/%s", cachedirp, CACHEFS_LOSTFOUND_NAME);
491
492 /* construct the path name of the resource file */
493 namep = RESOURCE_NAME;
494 xx = strlen(cachedirp) + strlen(namep) + 3;
495 if (xx >= MAXPATHLEN) {
496 pr_err(gettext("Path name too long %s/%s"),
497 cachedirp, namep);
498 return (39);
499 }
500 sprintf(buf, "%s/%s", cachedirp, namep);
501
502 /* make a res object to operate on the resource file */
503 resp = res_create(buf, clabel.cl_maxinodes, verbose);
504 if (resp == NULL) {
505 pr_err(gettext("Could not process resource file %s: %s"),
506 buf, strerror(errno));
507 return (39);
508 }
509
510 /* open the cache directory */
511 if ((dp = opendir(cachedirp)) == NULL) {
512 pr_err(gettext("Cannot open directory %s: %s"), cachedirp,
513 strerror(errno));
514 res_destroy(resp);
515 return (39);
516 }
517
518 /* mark all directories */
519 while ((dep = readdir64(dp)) != NULL) {
520 /* ignore . and .. */
521 if ((strcmp(dep->d_name, ".") == 0) ||
522 (strcmp(dep->d_name, "..") == 0))
523 continue;
524
525 /* check path length */
526 xx = strlen(cachedirp) + strlen(dep->d_name) + 3;
527 if (xx >= MAXPATHLEN) {
528 pr_err(gettext("Path name too long %s/%s"),
529 cachedirp, dep->d_name);
530 closedir(dp);
531 res_destroy(resp);
532 return (39);
533 }
534
535 /* stat the file */
536 sprintf(buf, "%s/%s", cachedirp, dep->d_name);
537 xx = lstat64(buf, &statinfo);
538 if (xx == -1) {
539 if (errno != ENOENT) {
540 pr_err(gettext("Cannot stat %s: %s"), cachedirp,
541 strerror(errno));
542 closedir(dp);
543 res_destroy(resp);
544 return (39);
545 }
546 continue;
547 }
548
549 /* if a directory */
550 if (S_ISDIR(statinfo.st_mode)) {
551 xx = chmod(buf, 0700);
552 if (xx == -1) {
553 pr_err(gettext("Cannot chmod %s: %s"), buf,
554 strerror(errno));
555 closedir(dp);
556 res_destroy(resp);
557 return (39);
558 }
559 }
560 }
561
562 /* process files in the cache directory */
563 rewinddir(dp);
564 while ((dep = readdir64(dp)) != NULL) {
565 /* ignore . and .. */
566 if ((strcmp(dep->d_name, ".") == 0) ||
567 (strcmp(dep->d_name, "..") == 0))
568 continue;
569
570 /* stat the file */
571 sprintf(buf, "%s/%s", cachedirp, dep->d_name);
572 xx = lstat64(buf, &statinfo);
573 if (xx == -1) {
574 if (errno != ENOENT) {
575 pr_err(gettext("Cannot stat %s: %s"), cachedirp,
576 strerror(errno));
577 closedir(dp);
578 res_destroy(resp);
579 return (39);
580 }
581 continue;
582 }
583
584 /* ignore directories */
585 if (S_ISDIR(statinfo.st_mode))
586 continue;
587
588 /* if not a link */
589 if (!S_ISLNK(statinfo.st_mode)) {
590 /*
591 * XXX make sure a valid file
592 * Update file and block counts for this file.
593 * This file will be <2GB.
594 */
595 res_addfile(resp, (long)statinfo.st_size);
596 continue;
597 }
598
599 /* process the file system cache directory */
600 xx = process_fsdir(cachedirp, dep->d_name, resp, verbose);
601 if (xx) {
602 closedir(dp);
603 res_destroy(resp);
604 return (xx);
605 }
606 }
607
608 /* look for directories that do not belong */
609 rewinddir(dp);
610 while ((dep = readdir64(dp)) != NULL) {
611 /* ignore . and .. */
612 if ((strcmp(dep->d_name, ".") == 0) ||
613 (strcmp(dep->d_name, "..") == 0))
614 continue;
615
616 /* stat the file */
617 sprintf(buf, "%s/%s", cachedirp, dep->d_name);
618 xx = lstat64(buf, &statinfo);
619 if (xx == -1) {
620 if (errno != ENOENT) {
621 pr_err(gettext("Cannot stat %s: %s"), cachedirp,
622 strerror(errno));
623 closedir(dp);
624 res_destroy(resp);
625 return (39);
626 }
627 continue;
628 }
629
630 /* XXX should we unlink extraneous regular files? */
631
632 /* ignore all but directories */
633 if (!S_ISDIR(statinfo.st_mode))
634 continue;
635
636 /* ignore directories we have checked */
637 if ((statinfo.st_mode & S_IAMB) != 0700)
638 continue;
639
640 /* ignore the mount directory */
641 if (strcmp(dep->d_name, BACKMNT_NAME) == 0)
642 continue;
643
644 /* ignore the lost+found directory */
645 if (strcmp(dep->d_name, CACHEFS_LOSTFOUND_NAME) == 0)
646 continue;
647
648 /* remove the directory */
649 xx = nftw64(buf, tree_remove, 3, FLAGS_FTW);
650 if (xx != 0) {
651 pr_err(gettext("Error walking tree %s."), namep);
652 closedir(dp);
653 res_destroy(resp);
654 return (39);
655 }
656
657 if (verbose)
658 pr_err(gettext("Directory removed: %s"), buf);
659 }
660
661 /* close the directory */
662 closedir(dp);
663
664 /* add one file and one block for the cache directory itself */
665 res_addfile(resp, 1);
666
667 /* finish off the resource file processing */
668 xx = res_done(resp);
669 if (xx == -1) {
670 pr_err(gettext("Could not finish resource file %s: %s"),
671 buf, strerror(errno));
672 return (39);
673 }
674 res_destroy(resp);
675
676 /* return success */
677 return (0);
678 }
679
680 /*
681 *
682 * cache_label_file
683 *
684 * Description:
685 * This routine performs the checking and fixing up of the
686 * cache label file.
687 * Arguments:
688 * cachedirp name of the cache directory to check
689 * clabelp cache label contents put here if not NULL
690 * Returns:
691 * 0 file system is okay and does not need checking
692 * 1 problem unrelated to the file system
693 * 32 file system is unmounted and needs checking
694 * 33 file system is already mounted
695 * 34 cannot stat device
696 * 36 uncorrectable errors detected - terminate normally
697 * 37 a signal was caught during processing
698 * 39 uncorrectable errors detected - terminate immediately
699 * Preconditions:
700 * precond(cachedirp)
701 */
702
703 int
cache_label_file(char * cachedirp,struct cache_label * clabelp)704 cache_label_file(char *cachedirp, struct cache_label *clabelp)
705 {
706 int xx;
707 char buf1[MAXPATHLEN];
708 char buf2[MAXPATHLEN];
709 char *namep;
710 struct cache_label clabel1, clabel2;
711
712 namep = CACHELABEL_NAME;
713
714 /* see if path name is too long */
715 xx = strlen(cachedirp) + strlen(namep) + 10;
716 if (xx >= MAXPATHLEN) {
717 pr_err(gettext("Cache directory name %s is too long"),
718 cachedirp);
719 return (39);
720 }
721
722 /* make a path to the cache label file and its backup copy */
723 sprintf(buf1, "%s/%s", cachedirp, namep);
724 sprintf(buf2, "%s/%s.dup", cachedirp, namep);
725
726 /* get the contents of the cache label file */
727 xx = cachefs_label_file_get(buf1, &clabel1);
728 if (xx == -1) {
729 /* get the backup cache label file contents */
730 xx = cachefs_label_file_get(buf2, &clabel2);
731 if (xx == -1) {
732 pr_err(gettext("Run `cfsadmin -d all %s'\n"
733 "and then run\n"
734 "`cfsadmin -c %s'\n"), cachedirp, cachedirp);
735 return (39);
736 }
737
738 /* write the cache label file */
739 xx = cachefs_label_file_put(buf1, &clabel2);
740 if (xx == -1) {
741 pr_err(gettext("Run `cfsadmin -d all %s'\n"
742 "and then run\n"
743 "`cfsadmin -c %s'\n"), cachedirp, cachedirp);
744 return (39);
745 }
746 pr_err(gettext("Cache label file %s repaired."), buf1);
747
748 /* copy out the contents to the caller */
749 if (clabelp)
750 *clabelp = clabel2;
751
752 /* return success */
753 return (0);
754 }
755
756 /* get the contents of the backup cache label file */
757 xx = cachefs_label_file_get(buf2, &clabel2);
758 if (xx == -1) {
759 /* write the backup cache label file */
760 xx = cachefs_label_file_put(buf2, &clabel1);
761 if (xx == -1) {
762 return (39);
763 }
764 pr_err(gettext("Cache label file %s repaired."), buf2);
765 }
766
767 /* copy out the contents to the caller */
768 if (clabelp)
769 *clabelp = clabel1;
770
771 /* return success */
772 return (0);
773 }
774
775 /*
776 *
777 * cache_permissions
778 *
779 * Description:
780 * Checks the permissions on the cache directory and fixes
781 * them if necessary.
782 * Arguments:
783 * cachedirp name of the cache directory to check
784 * Returns:
785 * 0 file system is okay and does not need checking
786 * 1 problem unrelated to the file system
787 * 32 file system is unmounted and needs checking
788 * 33 file system is already mounted
789 * 34 cannot stat device
790 * 36 uncorrectable errors detected - terminate normally
791 * 37 a signal was caught during processing
792 * 39 uncorrectable errors detected - terminate immediately
793 * Preconditions:
794 * precond(cachedirp)
795 */
796
797 int
cache_permissions(char * cachedirp)798 cache_permissions(char *cachedirp)
799 {
800 int xx;
801 struct stat64 statinfo;
802
803 /* get info about the cache directory */
804 xx = lstat64(cachedirp, &statinfo);
805 if (xx == -1) {
806 pr_err(gettext("Could not stat %s: %s"), cachedirp,
807 strerror(errno));
808 return (34);
809 }
810
811 /* check the mode bits */
812 if ((statinfo.st_mode & S_IAMB) != 0) {
813
814 /* fix the mode bits */
815 xx = chmod(cachedirp, 0);
816 if (xx == -1) {
817 pr_err(gettext("Could not set modes bits on "
818 "cache directory %s: %s"),
819 cachedirp, strerror(errno));
820 return (36);
821 }
822 pr_err(gettext("Mode bits reset on cache directory %s"),
823 cachedirp);
824 }
825
826 /* return success */
827 return (0);
828 }
829
830 /*
831 *
832 * cache_check_dir
833 *
834 * Description:
835 * Checks for the existance of the directory
836 * and creates it if necessary.
837 * Arguments:
838 * cachedirp name of the cache directory containing the dir
839 * namep name of dir
840 * Returns:
841 * 0 file system is okay and does not need checking
842 * 1 problem unrelated to the file system
843 * 32 file system is unmounted and needs checking
844 * 33 file system is already mounted
845 * 34 cannot stat device
846 * 36 uncorrectable errors detected - terminate normally
847 * 37 a signal was caught during processing
848 * 39 uncorrectable errors detected - terminate immediately
849 * Preconditions:
850 * precond(cachedirp)
851 * precond(dirp)
852 */
853
854 int
cache_check_dir(char * cachedirp,char * namep)855 cache_check_dir(char *cachedirp, char *namep)
856 {
857 int xx;
858 char buf[MAXPATHLEN];
859 struct stat64 statinfo;
860
861 /* see if path name is too long */
862 xx = strlen(cachedirp) + strlen(namep) + 3;
863 if (xx >= MAXPATHLEN) {
864 pr_err(gettext("Cache directory name %s is too long"),
865 cachedirp);
866 return (39);
867 }
868
869 /* make the pathname of the directory */
870 sprintf(buf, "%s/%s", cachedirp, namep);
871
872 /* get info on the directory */
873 xx = lstat64(buf, &statinfo);
874 if (xx == -1) {
875 /* if an error other than it does not exist */
876 if (errno != ENOENT) {
877 pr_err(gettext("Error on lstat(2) of %s: %s"),
878 buf, strerror(errno));
879 return (39);
880 }
881
882 /* make the directory */
883 xx = mkdir(buf, 0);
884 if (xx == -1) {
885 pr_err(gettext("Could not create directory %s"),
886 buf);
887 return (39);
888 }
889 pr_err(gettext("Created directory %s"), buf);
890 }
891
892 /* else see if really a directory */
893 else if (!S_ISDIR(statinfo.st_mode)) {
894 /* get rid of the file */
895 xx = unlink(buf);
896 if (xx == -1) {
897 pr_err(gettext("Cannot remove %s: %s"), buf,
898 strerror(errno));
899 return (39);
900 }
901
902 /* make the directory */
903 xx = mkdir(buf, 0);
904 if (xx == -1) {
905 pr_err(gettext("Could not create directory %s"),
906 buf);
907 return (39);
908 }
909 pr_err(gettext("Created directory %s"), buf);
910 }
911
912 /* return success */
913 return (0);
914 }
915
916 /*
917 *
918 * process_fsdir
919 *
920 * Description:
921 * Performs the necessary checking and repair on the
922 * specified file system cache directory.
923 * Calls res_addfile and res_addident as appropriate.
924 * Arguments:
925 * cachedirp name of cache directory
926 * namep name of link file for the file system cache
927 * resp res object for res_addfile and res_addident calls
928 * verbose indicate level of verbosity for diagnostics
929 * Returns:
930 * 0 file system is okay and does not need checking
931 * 1 problem unrelated to the file system
932 * 32 file system is unmounted and needs checking
933 * 33 file system is already mounted
934 * 34 cannot stat device
935 * 36 uncorrectable errors detected - terminate normally
936 * 37 a signal was caught during processing
937 * 39 uncorrectable errors detected - terminate immediately
938 * Preconditions:
939 * precond(cachedirp)
940 * precond(namep && is a sym link)
941 * precond(resp)
942 */
943
944 int
process_fsdir(char * cachedirp,char * namep,res * resp,int verbose)945 process_fsdir(char *cachedirp, char *namep, res *resp, int verbose)
946 {
947 DIR *dp;
948 struct dirent64 *dep;
949 char linkpath[MAXPATHLEN];
950 char dirpath[MAXPATHLEN];
951 char attrpath[MAXPATHLEN];
952 char buf[MAXPATHLEN];
953 int xx;
954 struct stat64 statinfo;
955 char *atp = ATTRCACHE_NAME;
956 int fd;
957 ino64_t base;
958 int local;
959 char *strp;
960 ino64_t fsid;
961 int error = 0;
962 int hashsize = 0;
963 ENTRY hitem;
964 ino64_t maxlocalfileno;
965 cachefs_fsinfo_t fsinfo;
966 time32_t btime;
967
968 /* construct the path to the sym link */
969 xx = strlen(cachedirp) + strlen(namep) + 3;
970 if (xx >= MAXPATHLEN) {
971 pr_err(gettext("Pathname too long %s/%s"), cachedirp, namep);
972 error = 39;
973 goto out;
974 }
975 sprintf(linkpath, "%s/%s", cachedirp, namep);
976
977 /* read the contents of the link */
978 xx = readlink(linkpath, buf, sizeof (buf));
979 if (xx == -1) {
980 pr_err(gettext("Unable to read link %s: %s"), linkpath,
981 strerror(errno));
982 error = 39;
983 goto out;
984 }
985 buf[xx] = '\0';
986
987 /* do a one time check on lengths of files */
988 xx = strlen(cachedirp) + strlen(buf) + 20 + 20;
989 if (xx >= MAXPATHLEN) {
990 pr_err(gettext("Pathname too long %s/%s"), cachedirp, buf);
991 error = 39;
992 goto out;
993 }
994
995 /* construct the path to the directory */
996 sprintf(dirpath, "%s/%s", cachedirp, buf);
997
998 /* stat the directory */
999 xx = lstat64(dirpath, &statinfo);
1000 if ((xx == -1) || (strtoull(buf, NULL, 16) != statinfo.st_ino)) {
1001 if ((xx == -1) && (errno != ENOENT)) {
1002 pr_err(gettext("Could not stat %s: %s"), dirpath,
1003 strerror(errno));
1004 error = 39;
1005 } else
1006 error = -1;
1007 goto out;
1008 }
1009 fsid = statinfo.st_ino;
1010
1011 /*
1012 * Check for a disconnect log(dlog) file and verify it.
1013 */
1014 xx = dlog_ck(dirpath, &maxlocalfileno);
1015 if (xx) {
1016 error = -1;
1017 goto out;
1018 }
1019
1020 /* process the fsinfo file */
1021 sprintf(buf, "%s/%s", dirpath, CACHEFS_FSINFO);
1022 xx = process_fsinfo(buf, maxlocalfileno, &fsinfo, verbose);
1023 if (xx) {
1024 error = -1;
1025 pr_err(gettext("Cannot update fsinfo file %s"), buf);
1026 goto out;
1027 }
1028
1029 /* create the unmount file in the cachedir */
1030 sprintf(buf, "%s/%s", dirpath, CACHEFS_UNMNT_FILE);
1031 /* this file will be < 2GB */
1032 fd = open(buf, O_CREAT | O_RDWR, 0666);
1033 if (fd == -1) {
1034 pr_err(gettext("Cannot create unmnt file %s: %s"), buf,
1035 strerror(errno));
1036 error = -1;
1037 goto out;
1038 }
1039 btime = get_boottime();
1040 if (write(fd, &btime, sizeof (btime)) == -1) {
1041 pr_err(gettext("Cannot write cachedir unmnt file %s: %s"), buf,
1042 strerror(errno));
1043 error = -1;
1044 goto out;
1045 }
1046 close(fd);
1047
1048 /* create the unmount file */
1049 sprintf(buf, "%s/%s", dirpath, CACHEFS_UNMNT_FILE);
1050 /* this file will be < 2GB */
1051 fd = open(buf, O_CREAT | O_RDWR, 0666);
1052 if (fd == -1) {
1053 pr_err(gettext("Cannot create unmnt file %s: %s"), buf,
1054 strerror(errno));
1055 error = -1;
1056 goto out;
1057 }
1058 close(fd);
1059
1060 /* construct the name to the attrcache directory */
1061 sprintf(attrpath, "%s/%s", dirpath, atp);
1062
1063 /* open the attrcache directory */
1064 if ((dp = opendir(attrpath)) == NULL) {
1065 pr_err(gettext("Cannot open directory %s: %s"), attrpath,
1066 strerror(errno));
1067 error = -1;
1068 goto out;
1069 }
1070
1071 /* make one pass, counting how big to make the hash table */
1072 while (readdir64(dp) != NULL)
1073 ++hashsize;
1074 if (hcreate(hashsize + 1000) == 0) {
1075 pr_err(gettext("Cannot allocate heap space."));
1076 (void) closedir(dp);
1077 hashsize = 0;
1078 error = 39;
1079 goto out;
1080 }
1081 rewinddir(dp);
1082
1083 /* loop reading the contents of the directory */
1084 while ((dep = readdir64(dp)) != NULL) {
1085 /* ignore . and .. */
1086 if ((strcmp(dep->d_name, ".") == 0) ||
1087 (strcmp(dep->d_name, "..") == 0))
1088 continue;
1089
1090 /* check for a reasonable name */
1091 xx = strlen(dep->d_name);
1092 if ((xx != 16) && (xx != 17)) {
1093 /* bad file */
1094 pr_err(gettext("Unknown file %s/%s"),
1095 attrpath, dep->d_name);
1096 closedir(dp);
1097 error = 39;
1098 goto out;
1099 }
1100
1101 /* derive the base number from the file name */
1102 if (*(dep->d_name) == 'L') {
1103 local = 1;
1104 base = strtoull(dep->d_name + 1, &strp, 16);
1105 } else {
1106 local = 0;
1107 base = strtoull(dep->d_name, &strp, 16);
1108 }
1109 if (*strp != '\0') {
1110 /* bad file */
1111 pr_err(gettext("Unknown file %s/%s"),
1112 attrpath, dep->d_name);
1113 closedir(dp);
1114 error = 39;
1115 goto out;
1116 }
1117
1118 /* process the file group */
1119 error = process_fsgroup(dirpath, dep->d_name, resp,
1120 base, fsinfo.fi_fgsize, fsid, local, verbose);
1121 if (error) {
1122 closedir(dp);
1123 goto out;
1124 }
1125 }
1126 closedir(dp);
1127
1128 /* open the fscache directory */
1129 if ((dp = opendir(dirpath)) == NULL) {
1130 pr_err(gettext("Cannot open directory %s: %s"), dirpath,
1131 strerror(errno));
1132 error = 39;
1133 goto out;
1134 }
1135
1136 /* loop reading the contents of the directory */
1137 while ((dep = readdir64(dp)) != NULL) {
1138 /* ignore . and .. */
1139 if ((strcmp(dep->d_name, ".") == 0) ||
1140 (strcmp(dep->d_name, "..") == 0))
1141 continue;
1142
1143 /* ignore cachefs special files */
1144 xx = strncmp(dep->d_name, CACHEFS_PREFIX, CACHEFS_PREFIX_LEN);
1145 if (xx == 0)
1146 continue;
1147
1148 hitem.key = dep->d_name;
1149 hitem.data = NULL;
1150 if (hsearch(hitem, FIND) == NULL) {
1151 sprintf(buf, "%s/%s", dirpath, dep->d_name);
1152 if (verbose) {
1153 printf("Unreferenced dir %s\n", buf);
1154 }
1155 xx = nftw64(buf, tree_remove, 3, FLAGS_FTW);
1156 if (xx != 0) {
1157 pr_err(gettext("Could not remove %s"), buf);
1158 error = 39;
1159 closedir(dp);
1160 goto out;
1161 }
1162 }
1163 }
1164 closedir(dp);
1165
1166 /* add the info file to the resource */
1167 res_addfile(resp, 1);
1168
1169 /* add the directory to the resources */
1170 res_addfile(resp, 1);
1171
1172 /* add the sym link to the resources */
1173 res_addfile(resp, 1);
1174
1175 /* change the mode on the directory to indicate we visited it */
1176 xx = chmod(dirpath, 0777);
1177 if (xx == -1) {
1178 pr_err(gettext("Cannot chmod %s: %s"), dirpath,
1179 strerror(errno));
1180 error = 39;
1181 goto out;
1182 }
1183
1184 out:
1185 /* free up the heap allocated by the hash functions */
1186 if (hashsize != 0)
1187 hdestroy();
1188
1189 if (error == -1) {
1190 /* remove the sym link */
1191 xx = unlink(linkpath);
1192 if (xx == -1) {
1193 pr_err(gettext("Unable to remove %s: %s"), linkpath,
1194 strerror(errno));
1195 error = 39;
1196 } else {
1197 error = 0;
1198 }
1199 }
1200
1201 return (error);
1202 }
1203
1204 /*
1205 * Processes and fixes up the fsinfo file.
1206 */
1207 int
process_fsinfo(char * namep,ino64_t maxlocalfileno,cachefs_fsinfo_t * fsinfop,int verbose)1208 process_fsinfo(char *namep, ino64_t maxlocalfileno, cachefs_fsinfo_t *fsinfop,
1209 int verbose)
1210 {
1211 int fd;
1212 int error;
1213 cachefs_fsinfo_t fsinfo;
1214 int xx;
1215
1216 /* open the info file; this file will be <2GB */
1217 fd = open(namep, O_RDWR);
1218 if (fd == -1) {
1219 error = errno;
1220 if (verbose)
1221 pr_err(gettext("Could not open %s: %s"),
1222 namep, strerror(errno));
1223 if (error != ENOENT)
1224 return (-1);
1225
1226 /* try to create the info file */
1227 fd = open(namep, O_RDWR | O_CREAT, 0666);
1228 if (fd == -1) {
1229 if (verbose)
1230 pr_err(gettext("Could not create %s: %s"),
1231 namep, strerror(errno));
1232 return (-1);
1233 }
1234
1235 }
1236
1237 /* read the contents of the info file */
1238 xx = read(fd, &fsinfo, sizeof (fsinfo));
1239 if (xx != sizeof (fsinfo)) {
1240 memset(&fsinfo, 0, sizeof (fsinfo));
1241 }
1242
1243 /* fix up the fields as necessary */
1244 if (fsinfo.fi_popsize < DEF_POP_SIZE)
1245 fsinfo.fi_popsize = DEF_POP_SIZE;
1246 if (fsinfo.fi_fgsize < DEF_FILEGRP_SIZE)
1247 fsinfo.fi_fgsize = DEF_FILEGRP_SIZE;
1248 if (fsinfo.fi_localfileno < maxlocalfileno)
1249 fsinfo.fi_localfileno = maxlocalfileno;
1250
1251 /* write back the info to the file */
1252 if (lseek(fd, 0, SEEK_SET) == -1) {
1253 if (verbose)
1254 pr_err(gettext("Could not lseek %s: %s"),
1255 namep, strerror(errno));
1256 close(fd);
1257 return (-1);
1258 }
1259 xx = write(fd, &fsinfo, sizeof (fsinfo));
1260 if (xx != sizeof (fsinfo)) {
1261 if (verbose)
1262 pr_err(gettext("Could not write %s: %s"),
1263 namep, strerror(errno));
1264 close(fd);
1265 return (-1);
1266 }
1267
1268 if (fsync(fd) == -1) {
1269 pr_err(gettext("Could not sync %s: %s"),
1270 namep, strerror(errno));
1271 (void) close(fd);
1272 return (-1);
1273 }
1274 (void) close(fd);
1275 *fsinfop = fsinfo;
1276 return (0);
1277 }
1278
1279 /*
1280 *
1281 * process_fsgroup
1282 *
1283 * Description:
1284 * Performs the necessary checking and repair on the
1285 * specified file group directory.
1286 * Calls res_addfile and res_addident as appropriate.
1287 * Arguments:
1288 * dirpath pathname to fscache directory
1289 * namep name of fsgroup
1290 * resp res object for res_addfile and res_addident calls
1291 * base base offset for file numbers in this directory
1292 * fgsize size of the file groups
1293 * fsid file system id
1294 * local 1 if fsgroup dir is a local dir
1295 * verbose indicate level of verbosity for diagnostics
1296 * Returns:
1297 * 0 file system is okay and does not need checking
1298 * 1 problem unrelated to the file system
1299 * 32 file system is unmounted and needs checking
1300 * 33 file system is already mounted
1301 * 34 cannot stat device
1302 * 36 uncorrectable errors detected - terminate normally
1303 * 37 a signal was caught during processing
1304 * 39 uncorrectable errors detected - terminate immediately
1305 * Preconditions:
1306 * precond(dirp)
1307 * precond(namep)
1308 * precond(resp)
1309 * precond(fgsize > 0)
1310 */
1311
1312 int
process_fsgroup(char * dirp,char * namep,res * resp,ino64_t base,int fgsize,ino64_t fsid,int local,int verbose)1313 process_fsgroup(char *dirp, char *namep, res *resp, ino64_t base, int fgsize,
1314 ino64_t fsid, int local, int verbose)
1315 {
1316 DIR *dp;
1317 struct dirent64 *dep;
1318 char buf[MAXPATHLEN];
1319 char attrfile[MAXPATHLEN];
1320 char attrdir[MAXPATHLEN];
1321 int xx;
1322 struct stat64 statinfo;
1323 char *atp = ATTRCACHE_NAME;
1324 void *addrp = MAP_FAILED;
1325 struct attrcache_header *ahp;
1326 struct attrcache_index *startp = NULL;
1327 struct attrcache_index *aip;
1328 uchar_t *bitp;
1329 int offlen;
1330 int bitlen;
1331 int fd;
1332 int offentry;
1333 int size;
1334 struct cachefs_metadata *metap;
1335 int index;
1336 char *strp;
1337 uint_t offset;
1338 int error = 0;
1339 ENTRY hitem;
1340 int nffs;
1341 int rlno;
1342 rl_entry_t ent;
1343 enum cachefs_rl_type which;
1344
1345 /* construct the name to the attribute file and front file dir */
1346 sprintf(attrfile, "%s/%s/%s", dirp, atp, namep);
1347 sprintf(attrdir, "%s/%s", dirp, namep);
1348
1349 /* get the size of the attribute file */
1350 xx = lstat64(attrfile, &statinfo);
1351 if (xx == -1) {
1352 pr_err(gettext("Could not stat %s: %s"), attrfile,
1353 strerror(errno));
1354 error = 39;
1355 goto out;
1356 }
1357
1358 offlen = sizeof (struct attrcache_index) * fgsize;
1359 bitlen = (sizeof (uchar_t) * fgsize + 7) / 8;
1360 /* attrfile will be <2GB */
1361 size = (int)statinfo.st_size;
1362 offentry = sizeof (struct attrcache_header) + offlen + bitlen;
1363
1364 /* if the attribute file is the wrong size */
1365 if (size < offentry) {
1366 error = -1;
1367 goto out;
1368 }
1369
1370 /* open the attribute file */
1371 fd = open(attrfile, O_RDWR);
1372 if (fd == -1) {
1373 pr_err(gettext("Could not open %s: %s"),
1374 attrfile, strerror(errno));
1375 error = 39;
1376 goto out;
1377 }
1378
1379 /* mmap the file into our address space */
1380 addrp = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1381 if (addrp == MAP_FAILED) {
1382 pr_err(gettext("Could not map %s: %s"),
1383 attrfile, strerror(errno));
1384 close(fd);
1385 error = 39;
1386 goto out;
1387 }
1388 close(fd);
1389
1390 /* set up pointers into mapped file */
1391 ahp = (struct attrcache_header *)addrp;
1392 startp = (struct attrcache_index *)(ahp + 1);
1393 bitp = (uchar_t *)((char *)startp + offlen);
1394
1395 /* clear the bitmap */
1396 memset(bitp, 0, bitlen);
1397
1398 /* fix number of allocated blocks value if necessary */
1399 xx = (size + MAXBSIZE - 1) / MAXBSIZE;
1400 if (xx != ahp->ach_nblks) {
1401 if (verbose) {
1402 pr_err(gettext("File %s size wrong, old %d new %d:"
1403 "corrected."),
1404 attrfile, ahp->ach_nblks, xx);
1405 }
1406 ahp->ach_nblks = xx;
1407 }
1408 ahp->ach_nffs = 0;
1409 nffs = 0;
1410
1411 /* verify sanity of attribute file */
1412 ahp->ach_count = 0;
1413 for (index = 0; index < fgsize; index++) {
1414
1415 /* get next entry to work on */
1416 aip = startp + index;
1417
1418 /* save offset to data */
1419 offset = aip->ach_offset;
1420 aip->ach_offset = 0;
1421
1422 /* if entry not in use */
1423 if (aip->ach_written == 0)
1424 continue;
1425 aip->ach_written = 0;
1426
1427 /* if offset is out of range or invalid */
1428 if ((offset < offentry) ||
1429 ((size - sizeof (struct cachefs_metadata)) < offset) ||
1430 (offset & 3)) {
1431 if (verbose)
1432 pr_err(gettext("Offset %d invalid - index %d"),
1433 offset, index);
1434 continue;
1435 }
1436
1437 /* get pointer to meta data */
1438 metap = (struct cachefs_metadata *)((char *)addrp + offset);
1439
1440 /* sanity check the meta data */
1441 if ((metap->md_vattr.va_nodeid != (base + (ino64_t)index)) ||
1442 ((metap->md_flags & (MD_FILE | MD_POPULATED)) ==
1443 MD_POPULATED) ||
1444 ((metap->md_flags & MD_FILE) && (metap->md_rlno == 0)) ||
1445 (metap->md_rltype < CACHEFS_RL_START) ||
1446 (metap->md_rltype > CACHEFS_RL_END)) {
1447 if (verbose) {
1448 pr_err(gettext("Metadata corrupted %d"), index);
1449 }
1450 continue;
1451 }
1452
1453 /* if there is a front file */
1454 if (metap->md_flags & MD_FILE) {
1455 /* make sure front file is still there */
1456 if (local)
1457 sprintf(buf, "%s/L%016llx", attrdir,
1458 base + (ino64_t)index);
1459 else
1460 sprintf(buf, "%s/%016llx", attrdir,
1461 base + (ino64_t)index);
1462 if (access(buf, F_OK)) {
1463 if (verbose) {
1464 pr_err(gettext("File error %s %s"),
1465 buf, strerror(errno));
1466 }
1467 continue;
1468 }
1469 nffs++;
1470
1471 /* make sure default ACL directory holder is there */
1472 if (metap->md_flags & MD_ACLDIR) {
1473 sprintf(buf, (local) ?
1474 "%s/L%016llx.d" : "%s/%016llx.d",
1475 attrdir, base + (ino64_t)index);
1476 if (access(buf, F_OK)) {
1477 if (verbose) {
1478 pr_err(gettext(
1479 "File error %s %s"),
1480 buf, strerror(errno));
1481 }
1482 continue;
1483 }
1484 }
1485 }
1486
1487 /* if using a rl slot */
1488 if (metap->md_rlno) {
1489 /* make sure not on an unusable list */
1490 if ((metap->md_rltype == CACHEFS_RL_NONE) ||
1491 (metap->md_rltype == CACHEFS_RL_FREE)) {
1492 if (verbose) {
1493 pr_err(gettext("Bad list %d, %d"),
1494 metap->md_rltype, index);
1495 }
1496 continue;
1497 }
1498
1499 /* move from the active to the gc list */
1500 if (metap->md_rltype == CACHEFS_RL_ACTIVE)
1501 metap->md_rltype = CACHEFS_RL_GC;
1502
1503 /* move from the mf to the modified list */
1504 if (metap->md_rltype == CACHEFS_RL_MF)
1505 metap->md_rltype = CACHEFS_RL_MODIFIED;
1506
1507 /* add to the resource file */
1508 ent.rl_attrc = 0;
1509 ent.rl_local = local;
1510 ent.rl_fsid = fsid;
1511 ent.rl_fileno = base + (ino64_t)index;
1512 ent.rl_current = metap->md_rltype;
1513 xx = res_addident(resp, metap->md_rlno, &ent,
1514 metap->md_frontblks * MAXBSIZE,
1515 (metap->md_flags & MD_FILE) ? 1 : 0);
1516 if (xx == -1) {
1517 if (verbose) {
1518 pr_err(gettext(
1519 "File %s, bad rlno"), attrfile);
1520 }
1521 continue;
1522 }
1523 ahp->ach_nffs++;
1524 }
1525
1526 /* mark entry as valid */
1527 aip->ach_written = 1;
1528 aip->ach_offset = offset;
1529
1530 /* set bitmap for this entry */
1531 xx = (offset - offentry) / sizeof (struct cachefs_metadata);
1532 bitp[xx/8] |= 1 << (xx % 8);
1533
1534 /* bump number of active entries */
1535 ahp->ach_count += 1;
1536 }
1537
1538 /* loop reading the contents of the front file directory */
1539 dp = opendir(attrdir);
1540 while (dp && ((dep = readdir64(dp)) != NULL)) {
1541 int acldir;
1542
1543 /* ignore . and .. */
1544 if ((strcmp(dep->d_name, ".") == 0) ||
1545 (strcmp(dep->d_name, "..") == 0))
1546 continue;
1547
1548 acldir = 0;
1549 xx = strlen(dep->d_name);
1550 /* check for valid ACL directory */
1551 if ((xx > 2) && (strcmp(dep->d_name + xx - 2, ".d") == 0)) {
1552 acldir = 1;
1553 } else if ((xx != 16) && (xx != 17)) {
1554 /*
1555 * Bad file.
1556 * Front file dir name is based on 64 bit inode number.
1557 */
1558 pr_err(gettext("Unknown file %s/%s"),
1559 attrdir, dep->d_name);
1560 closedir(dp);
1561 error = 39;
1562 goto out;
1563 }
1564
1565 sprintf(buf, "%s/%s", attrdir, dep->d_name);
1566
1567 /* determine index into file group */
1568 if (*(dep->d_name) == 'L') {
1569 index = (int)(strtoull(dep->d_name + 1, &strp,
1570 16) - base);
1571 } else {
1572 index = (int)(strtoull(dep->d_name, &strp, 16) - base);
1573 }
1574
1575 /* verify a valid file */
1576 if (((! acldir) && (*strp != '\0')) ||
1577 ((acldir) && (strcmp(strp, ".d") != 0)) ||
1578 (index < 0) || (fgsize <= index) ||
1579 (startp[index].ach_written == 0)) {
1580 /* remove the file */
1581 xx = file_remove(buf, NULL, verbose);
1582 if (xx == -1) {
1583 error = 39;
1584 goto out;
1585 }
1586 continue;
1587 }
1588
1589 /* verify file should be there */
1590 aip = startp + index;
1591 offset = aip->ach_offset;
1592 metap = (struct cachefs_metadata *)((char *)addrp + offset);
1593 if (((metap->md_flags & MD_FILE) == 0) ||
1594 ((acldir) && ((metap->md_flags & MD_ACLDIR) == 0))) {
1595 /* remove the file */
1596 if (acldir)
1597 xx = rmdir(buf);
1598 else
1599 xx = file_remove(buf, NULL, verbose);
1600 if (xx == -1) {
1601 error = 39;
1602 goto out;
1603 }
1604 continue;
1605 }
1606 if (! acldir)
1607 nffs--;
1608 }
1609
1610 /* close the directory */
1611 if (dp)
1612 closedir(dp);
1613
1614 /* if we did not find the correct number of front files in the dir */
1615 rlno = ahp->ach_rlno;
1616 if (nffs != 0) {
1617 if (verbose) {
1618 pr_err(gettext("Front file mismatch %d in %s"),
1619 nffs, attrdir);
1620 }
1621 error = -1;
1622 goto out;
1623 }
1624
1625 /* add the attrcache file to the resouce file */
1626 which = (ahp->ach_nffs == 0) ? CACHEFS_RL_GC : CACHEFS_RL_ATTRFILE;
1627 ahp->ach_rl_current = which;
1628 ent.rl_attrc = 1;
1629 ent.rl_local = local;
1630 ent.rl_fsid = fsid;
1631 ent.rl_fileno = base;
1632 ent.rl_current = which;
1633 error = res_addident(resp, rlno, &ent, size, 1);
1634 if (error == -1) {
1635 if (verbose) {
1636 pr_err(gettext("%s bad rlno %d\n"), attrfile, rlno);
1637 }
1638 goto out;
1639 } else if (ahp->ach_nffs > 0) {
1640 /* add the directory to the resources */
1641 res_addfile(resp, 1);
1642
1643 /* indicate that the file group directory is okay */
1644 hitem.key = strdup(namep);
1645 hitem.data = NULL;
1646 if (hsearch(hitem, ENTER) == NULL) {
1647 pr_err(gettext("Hash table full"));
1648 error = 39;
1649 goto out;
1650 }
1651 }
1652
1653 out:
1654 if (error == -1) {
1655 if (startp) {
1656 /* clear idents we created for this attrcache file */
1657 for (index = 0; index < fgsize; index++) {
1658 aip = startp + index;
1659 if (aip->ach_written == 0)
1660 continue;
1661 metap = (struct cachefs_metadata *)((char *)
1662 addrp + aip->ach_offset);
1663 if (metap->md_rlno != 0) {
1664 /* clear the resource file idents */
1665 res_clearident(resp, metap->md_rlno,
1666 (metap->md_frontblks * MAXBSIZE),
1667 (metap->md_flags & MD_FILE) ? 1:0);
1668 if (verbose) {
1669 pr_err(gettext("Removed %d"),
1670 metap->md_rlno);
1671 }
1672 }
1673 }
1674 }
1675
1676 /* nuke the attrcache file */
1677 xx = unlink(attrfile);
1678 if (xx == -1) {
1679 pr_err(gettext("Unable to remove %s"), attrfile);
1680 error = 39;
1681 } else {
1682 error = 0;
1683 if (verbose) {
1684 pr_err(gettext("Removed attrcache %s"),
1685 attrfile);
1686 }
1687 }
1688 }
1689
1690 if (msync(addrp, size, MS_SYNC) == -1) {
1691 pr_err(gettext("Unable to sync %s"), attrfile);
1692 error = 39;
1693 }
1694
1695 /* unmap the attribute file */
1696 if (addrp != MAP_FAILED)
1697 munmap(addrp, size);
1698
1699 return (error);
1700 }
1701
1702 /*
1703 *
1704 * tree_remove
1705 *
1706 * Description:
1707 * Called via the nftw64(3c) routine, this routine removes
1708 * the specified file.
1709 * Arguments:
1710 * namep pathname to the file
1711 * statp stat info on the file
1712 * type ftw type information
1713 * ftwp pointer to additional ftw information
1714 * Returns:
1715 * Returns 0 for success or -1 if an error occurs.
1716 * Preconditions:
1717 * precond(namep)
1718 * precond(statp)
1719 * precond(ftwp)
1720 */
1721
1722 int
tree_remove(const char * namep,const struct stat64 * statp,int type,struct FTW * ftwp)1723 tree_remove(const char *namep, const struct stat64 *statp, int type,
1724 struct FTW *ftwp)
1725 {
1726 int xx;
1727
1728 switch (type) {
1729 case FTW_D:
1730 case FTW_DP:
1731 case FTW_DNR:
1732 xx = rmdir(namep);
1733 if (xx != 0) {
1734 pr_err(gettext("Could not remove directory %s: %s"),
1735 namep, strerror(errno));
1736 return (-1);
1737 }
1738 #if 0
1739 pr_err(gettext("Directory %s removed."), namep);
1740 #endif
1741 break;
1742
1743 default:
1744 xx = file_remove(namep, statp, S_verbose);
1745 #if 0
1746 pr_err(gettext("File %s removed."), namep);
1747 #endif
1748 break;
1749 }
1750
1751 /* return success */
1752 return (0);
1753 }
1754
1755 /*
1756 *
1757 * file_remove
1758 *
1759 * Description:
1760 * Removes the specified file.
1761 * If the file is a local file or has been modified locally
1762 * then it is moved to lost+found.
1763 * Should only be called for non-directory files.
1764 * Arguments:
1765 * namep pathname to the file
1766 * statp stat info on the file or NULL
1767 * verbose 1 means be verbose about what is being removed
1768 * Returns:
1769 * Returns 0 for success or -1 if an error occurs.
1770 * Preconditions:
1771 * precond(namep)
1772 */
1773
1774 int
file_remove(const char * namep,const struct stat64 * statp,int verbose)1775 file_remove(const char *namep, const struct stat64 *statp, int verbose)
1776 {
1777 int xx;
1778 int ii;
1779 struct stat64 statinfo;
1780 int dolf = 0;
1781 char newname[MAXPATHLEN * 2];
1782 char *strp;
1783
1784 /* get stat info on the file if we were not passed it */
1785 if (statp == NULL) {
1786 xx = stat64(namep, &statinfo);
1787 if (xx) {
1788 if (verbose) {
1789 pr_err(gettext("stat failed %s %d"),
1790 namep, errno);
1791 }
1792 return (-1);
1793 }
1794 statp = &statinfo;
1795 }
1796
1797 /* ignore directories */
1798 if (S_ISDIR(statp->st_mode)) {
1799 errno = EINVAL;
1800 return (-1);
1801 }
1802
1803 /* if a local file then move to lost+found */
1804 strp = strrchr(namep, '/');
1805 if (strp == NULL) {
1806 errno = EINVAL;
1807 return (-1);
1808 }
1809 strp++;
1810 if (*strp == 'L')
1811 dolf = 1;
1812
1813 /* if a modified file then move to lost+found */
1814 if ((statp->st_mode & S_IAMB) == 0766)
1815 dolf = 1;
1816
1817 /* if moving to lost+found */
1818 if (dolf) {
1819 sprintf(newname, "%s/%s", S_lostfound, strp);
1820 xx = stat64(newname, &statinfo);
1821 for (ii = 1; ((ii < 1000) && (xx == 0)); ii++) {
1822 sprintf(newname, "%s/%s_%d", S_lostfound, strp, ii);
1823 xx = stat64(newname, &statinfo);
1824 }
1825 xx = rename(namep, newname);
1826 if (xx) {
1827 pr_err(gettext("Could not move file %s to %s: %s"),
1828 namep, newname, strerror(errno));
1829 exit(-1);
1830 }
1831 S_move_lostfound = 1;
1832 return (0);
1833 }
1834
1835 /* remove the file */
1836 xx = unlink(namep);
1837 if (xx == -1) {
1838 pr_err(gettext("Could not remove file %s: %s"),
1839 namep, strerror(errno));
1840 } else if (verbose) {
1841 pr_err(gettext("Removed %s"), namep);
1842 }
1843
1844 return (0);
1845 }
1846
1847 void
cache_backmnt_cleanup(char * cachedirp,char * backmnt_namep)1848 cache_backmnt_cleanup(char *cachedirp, char *backmnt_namep)
1849 {
1850 DIR *dirp;
1851 struct dirent *entp;
1852 char dirname[MAXPATHLEN * 2];
1853
1854 /* open the directory */
1855 sprintf(dirname, "%s/%s", cachedirp, backmnt_namep);
1856 dirp = opendir(dirname);
1857 if (dirp == NULL)
1858 return;
1859
1860 /*
1861 * Try to remove everything in the directory with rmdir.
1862 * Should only be empty directories in here at this point.
1863 * If not, do not worry about it.
1864 */
1865 for (;;) {
1866 /* get the next dir entry */
1867 entp = readdir(dirp);
1868 if (entp == NULL)
1869 break;
1870
1871 /*
1872 * Try and remove the directory.
1873 * This will fail if there is anything in the dir,
1874 * like a mounted file system.
1875 */
1876 rmdir(entp->d_name);
1877 }
1878 closedir(dirp);
1879 }
1880