2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
14 Institution: The Information Technology Center, Carnegie-Mellon University
18 #define ITC /* Required by inode.h */
20 #include <afsconfig.h>
21 #include <afs/param.h>
29 #if defined(AFS_LINUX20_ENV) || defined(AFS_SUN4_ENV)
34 * -1 - Unable to read the inodes.
35 * -2 - Unable to completely write temp file. Produces warning message in log.
38 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
39 int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
40 char *wpath, void *rock)
42 Log("ListViceInodes not implemented for this platform!\n");
47 #include <sys/param.h>
48 #if defined(AFS_SGI_ENV)
52 #else /* AFS_OSF_ENV */
53 #ifdef AFS_VFSINCL_ENV
56 #include <sys/fs/ufs_fs.h>
58 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
59 #include <ufs/ufs/dinode.h>
60 #include <ufs/ffs/fs.h>
61 #define itod ino_to_fsba
66 #else /* AFS_VFSINCL_ENV */
68 #include <sys/filsys.h>
72 #endif /* AFS_VFSINCL_ENV */
73 #endif /* AFS_OSF_ENV */
75 #ifdef AFS_VFSINCL_ENV
76 #include <sys/vnode.h>
78 #include <sys/fs/ufs_inode.h>
80 #if !defined(AFS_DARWIN_ENV)
81 #include <ufs/inode.h>
84 #else /* AFS_VFSINCL_ENV */
86 #include <ufs/inode.h>
87 #else /* AFS_OSF_ENV */
88 #include <sys/inode.h>
90 #endif /* AFS_VFSINCL_ENV */
91 #endif /* AFS_SGI_ENV */
92 #include <afs/osi_inode.h>
96 #include <afs/afsint.h>
98 #include <afs/afssyscalls.h>
99 #include "viceinode.h"
100 #include <sys/stat.h>
101 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
104 #ifdef AFS_PTHREAD_ENV
106 #else /* AFS_PTHREAD_ENV */
107 #include <afs/assert.h>
108 #endif /* AFS_PTHREAD_ENV */
109 #if defined(AFS_HPUX101_ENV)
116 #include "volinodes.h"
117 #include "partition.h"
120 /*@+fcnmacros +macrofcndecl@*/
123 extern off64_t afs_lseek(int FD, off64_t O, int F);
124 #endif /*S_SPLINT_S */
125 #define afs_lseek(FD, O, F) lseek64(FD, (off64_t) (O), F)
126 #define afs_stat stat64
127 #define afs_fstat fstat64
128 #define afs_open open64
129 #define afs_fopen fopen64
130 #else /* !O_LARGEFILE */
132 extern off_t afs_lseek(int FD, off_t O, int F);
133 #endif /*S_SPLINT_S */
134 #define afs_lseek(FD, O, F) lseek(FD, (off_t) (O), F)
135 #define afs_stat stat
136 #define afs_fstat fstat
137 #define afs_open open
138 #define afs_fopen fopen
139 #endif /* !O_LARGEFILE */
140 /*@=fcnmacros =macrofcndecl@*/
142 /* Notice: parts of this module have been cribbed from vfsck.c */
145 static char *partition;
150 #include <jfs/filsys.h>
153 #define FSBSIZE (4096) /* filesystem block size */
154 #define FSBSHIFT (12) /* log2(FSBSIZE) */
155 #define FSBMASK (FSBSIZE - 1) /* FSBSIZE mask */
157 #define MIN_FSIZE DISKMAP_B /* minimum fs size (FSblocks) */
158 #define LAST_RSVD_I 15 /* last reserved inode */
163 * This will hopefully eventually make it into the system include files
165 #define INOPB (FSBSIZE / sizeof (struct dinode))
173 #endif /* AFS_AIX41_ENV */
176 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
177 XX This was lifted from some `com/cmd/fs/fshlpr_aix3/Fs.h', which indicated X
178 XX a longing to see it make it into a readily accessible include file. XXXXXX
179 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
181 * itoo - inode number to offset within disk block
184 #define itoo(x) (int) ((unsigned)(x) % INOPB)
186 int Bsize = FSBSIZE; /* block size for this system */
187 daddr_t fmax; /* total number of blocks n file system */
188 ino_t imax, inum; /* total number of I-nodes in file system */
190 static struct superblock fs;
191 struct dinode *ginode();
195 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
196 int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
197 char *wpath, void *rock)
199 FILE *inodeFile = NULL;
200 char dev[50], rdev[51];
203 struct ViceInodeInfo info;
204 struct stat root_inode;
205 int ninodes = 0, err = 0;
207 pfd = -1; /* initialize so we don't close on error output below. */
210 sleep(1); /* simulate operator */
216 partition = mountedOn;
217 sprintf(dev, "/dev/%s", devname);
218 sprintf(rdev, "/dev/r%s", devname);
220 if (stat(mountedOn, &root_inode) < 0) {
221 Log("cannot stat: %s\n", mountedOn);
225 if (root_inode.st_ino != ROOTDIR_I) {
226 Log("%s is not root of a filesystem\n", mountedOn);
232 * done with the superblock, now try to read the raw device.
234 if (ReadSuper(&fs, dev) < 0)
239 case FM_CLEAN: /* clean and unmounted */
240 Log("Most peculiar - Super blk in FM_CLEAN state!\n");
242 case FM_MOUNT: /* mounted cleanly */
245 case FM_MDIRTY: /* dirty when mounted or commit fail */
246 case FM_LOGREDO: /* log redo attempted but failed */
247 Log("File system %s is in a bad state.\n", rdev);
248 Log("Call your IBM representative.\n");
252 if (IsBigFilesFileSystem(&fs, (char *)0)) {
253 Log("%s is a big files filesystem, can't salvage.\n", mountedOn);
257 if (strncmp(fs.s_magic, fsv3magic, strlen(fsv3magic)) != 0) {
259 if ((strncmp(fs.s_magic, fsv3pmagic, strlen(fsv3pmagic)) != 0)
260 || (fs.s_version != fsv3pvers)) {
261 Log("Super block doesn't have the problem magic (%s vs v3magic %s v3pmagic %s)\n", fs.s_magic, fsv3magic, fsv3pmagic);
265 Log("Super block doesn't have the problem magic (%s vs v3magic %s)\n",
266 fs.s_magic, fsv3magic);
273 fragsize = (fs.s_fragsize) ? fs.s_fragsize : FSBSIZE;
274 iagsize = (fs.s_iagsize) ? fs.s_iagsize : fs.s_agsize;
275 ag512 = fragsize * fs.s_agsize / 512;
276 agblocks = fragsize * fs.s_agsize >> BSHIFT;
277 #endif /* AFS_AIX41_ENV */
279 fmax = fs.s_fsize / (FSBSIZE / 512); /* first invalid blk num */
281 pfd = afs_open(rdev, O_RDONLY);
283 Log("Unable to open `%s' inode for reading\n", rdev);
288 inodeFile = fopen(resultFile, "w");
289 if (inodeFile == NULL) {
290 Log("Unable to create inode description file %s\n", resultFile);
296 * calculate the maximum number of inodes possible
299 imax = iagsize * (fs.s_fsize / ag512) - 1;
300 #else /* AFS_AIX41_ENV */
302 ((fmax / fs.s_agsize +
303 ((fmax % fs.s_agsize) >= fs.s_agsize / INOPB ? 1 : 0))
305 #endif /* AFS_AIX41_ENV */
308 * check for "FORCESALVAGE" equivalent:
309 * LAST_RSVD_I is a vice inode, with dead beef, and
310 * di_nlink == 2 to indicate the FORCE.
312 assert(p = ginode(LAST_RSVD_I));
314 if (p->di_vicemagic == VICEMAGIC && p->di_vicep1 == 0xdeadbeef
315 && p->di_nlink == 2) {
317 idec(root_inode.st_dev, LAST_RSVD_I, 0xdeadbeef);
320 for (inum = LAST_RSVD_I + 1; inum <= imax; ++inum) {
321 if ((p = ginode(inum)) == NULL || p->di_vicemagic != VICEMAGIC
322 || (p->di_mode & IFMT) != IFREG)
325 info.inodeNumber = inum;
326 info.byteCount = p->di_size;
327 info.linkCount = p->di_nlink;
328 info.u.param[0] = p->di_vicep1;
329 info.u.param[1] = p->di_vicep2;
330 info.u.param[2] = p->di_vicep3;
331 info.u.param[3] = p->di_vicep4;
333 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
337 if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
338 Log("Error writing inode file for partition %s\n", partition);
346 if (fflush(inodeFile) == EOF) {
347 Log("Unable to successfully flush inode file for %s\n", partition);
351 if (fsync(fileno(inodeFile)) == -1) {
352 Log("Unable to successfully fsync inode file for %s\n", partition);
356 if (fclose(inodeFile) == EOF) {
357 Log("Unable to successfully close inode file for %s\n", partition);
363 * Paranoia: check that the file is really the right size
365 if (stat(resultFile, &status) == -1) {
366 Log("Unable to successfully stat inode file for %s\n", partition);
370 if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
371 Log("Wrong size (%d instead of %d) in inode file for %s\n",
372 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
392 /* Read in the superblock for devName */
394 ReadSuper(struct superblock *fs, char *devName)
398 pfd = afs_open(devName, O_RDONLY);
400 Log("Unable to open inode on %s for reading superblock.\n", devName);
404 if (bread(pfd, fs, SUPER_B, sizeof(struct superblock)) < 0) {
405 Log("Unable to read superblock on %s.\n", devName);
413 /* IsBigFilesFileSystem returns 1 if it's a big files filesystem, 0 otherwise. */
415 IsBigFilesFileSystem(struct superblock *sb)
417 if ((strncmp(sb->s_magic, fsv3pmagic, 4) == 0)
418 && (sb->s_version == fsbigfile)
432 static char buf[FSBSIZE];
433 static daddr_t last_blk = -1;
439 0) ? INODES_B + inum / INOPB : ag * agblocks + (inum -
442 #else /* AFS_AIX41_ENV */
443 ag = inum / fs.s_agsize;
446 0) ? INODES_B + inum / INOPB : ag * fs.s_agsize + (inum -
450 #endif /* AFS_AIX41_ENV */
452 if (last_blk != pblk) {
453 if (bread(pfd, buf, pblk, sizeof(buf)) < 0) {
460 dp = (struct dinode *)buf;
465 #else /* !AFS_AIX31_ENV */
467 #if defined(AFS_SGI_ENV)
469 /* libefs.h includes <assert.h>, which we don't want */
472 #ifdef AFS_SGI_XFS_IOPS_ENV
474 #include <afs/xfsattrs.h>
475 /* xfs_ListViceInodes
477 * xfs_ListViceInodes verifies and correct the XFS namespace as it collects
478 * the inode information. The name is required for the idec operation to work.
479 * Steps 2 and 3 below are for the AFS_XFS_NAME_VERS == 1. If the name space
480 * changes, the algorithm will need to change.
481 * 1) If the parent inode number does not match the directory's inod number,
482 * change it in the attribute.
483 * 2) If the unqifier in the attribute does not match the name, rename the
484 * file. This is done by doing an exclusive open, incrementing the tag
485 * number until a file can be created. If the tag changes, then the
486 * attribute will need updating.
487 * 3) If the tag in the attribute does not match the name, change the
489 * 4) Verify uid = RW volume id and gid = XFS_VICEMAGIC.
495 * Does the verifications listed above.
496 * We can't change the names until the readdir is complete, so we set the
497 * rename flag if the file needs renaming.
500 xfs_VerifyInode(char *dir, uint64_t pino, char *name, i_list_inode_t * info,
507 int update_chown = 0;
514 (void)sprintf(path, "%s/%s", dir, name);
515 /* Verify uid and gid fields */
516 if (info->ili_magic != XFS_VICEMAGIC) {
517 Log("%s magic for %s/%s (inode %s) from %d to %d\n",
518 Testing ? "Would have changed" : "Changing", dir, name,
519 PrintInode(NULL, info->ili_info.inodeNumber), info->ili_magic,
525 vno = info->ili_info.param[0];
526 if (info->ili_vno != AFS_XFS_VNO_CLIP(vno)) {
527 Log("%s volume id for %s/%s (inode %s) from %d to %d\n",
528 Testing ? "Would have changed" : "Changing", dir, name,
529 PrintInode(NULL, info->ili_info.inodeNumber), info->ili_vno,
530 AFS_XFS_VNO_CLIP(vno));
536 if (chown(path, AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC) < 0) {
537 Log("Can't chown %s to uid=%d, gid=0x%x\n", path,
538 AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC);
543 /* Check Parent inode number. */
544 if (info->ili_pino != pino) {
545 afs_ino_str_t sino, sipino, spino;
546 (void)PrintInode(sino, info->ili_info.inodeNumber);
547 (void)PrintInode(sipino, info->ili_pino);
548 (void)PrintInode(spino, pino);
549 Log("%s parent ino for %s (inode %s) from %s to %s.\n",
550 Testing ? "Would have changed" : "Changing", path, sino, sipino,
556 /* Verify the file name. */
557 (void)strcpy(tmpName, ".");
558 (void)strcat(tmpName, int_to_base64(stmp, info->ili_info.param[2]));
559 if (strncmp(name, tmpName, strlen(tmpName))) {
560 Log("%s name %s (inode %s) in directory %s, unique=%d, tag=%d\n",
561 Testing ? "Would have returned bad" : "Bad", name,
562 PrintInode(NULL, info->ili_info.inodeNumber), dir,
563 info->ili_info.param[2], info->ili_tag);
569 /* update the tag? */
570 (void)strcat(tmpName, ".");
571 (void)strcat(tmpName, int_to_base64(stmp, info->ili_tag));
572 if (strcmp(name, tmpName)) {
574 (void)strcpy(tmpName, name);
575 p = strchr(tmpName + 1, '.');
577 Log("No tag found on name %s (inode %s)in directory, %s.\n",
578 name, PrintInode(NULL, info->ili_info.inodeNumber), dir,
579 Testing ? "would have renamed" : "will rename");
583 tag = base64_to_int(p + 1);
584 Log("%s the tag for %s (inode %s) from %d to %d.\n",
585 Testing ? "Would have changed" : "Will change", path,
586 PrintInode(NULL, info->ili_info.inodeNumber), dir, tag,
594 if (update_pino || update_tag) {
595 afs_xfs_attr_t attrs;
598 length = SIZEOF_XFS_ATTR_T;
599 if (attr_get(path, AFS_XFS_ATTR, (char *)&attrs, &length, ATTR_ROOT) <
601 Log("Can't get AFS attribute for %s\n", path);
605 attrs.at_pino = pino;
609 (path, AFS_XFS_ATTR, (char *)&attrs, length,
610 ATTR_ROOT | ATTR_REPLACE) < 0) {
611 Log("Can't set AFS attribute into %s\n", path);
625 xfs_RenameFiles(char *dir, xfs_Rename_t * renames, int n_renames)
628 char opath[128], nbase[128], npath[128];
629 afs_xfs_attr_t attrs;
630 int length = SIZEOF_XFS_ATTR_T;
635 for (i = 0; i < n_renames; i++) {
636 (void)sprintf(opath, "%s/%s", dir, renames[i].name);
637 (void)sprintf(nbase, "%s/.%s", dir,
638 int_to_base64(stmp, renames[i].uniq));
639 for (tag = 2, j = 0; j < 64; tag++, j++) {
640 (void)sprintf(npath, "%s.%s", nbase, int_to_base64(stmp, tag));
641 fd = afs_open(npath, O_CREAT | O_EXCL | O_RDWR, 0);
648 Log("Can't find a new name for %s\n", opath);
651 if (rename(opath, npath) < 0) {
652 Log("Can't rename %s to %s\n", opath, npath);
655 Log("Renamed %s to %s\n", opath, npath);
662 xfs_ListViceInodes(char *devname, char *mountedOn, char *resultFile,
663 int (*judgeInode) (), int judgeParam, int *forcep,
664 int forceR, char *wpath, void *rock)
666 FILE *inodeFile = NULL;
668 int info_size = sizeof(i_list_inode_t);
671 dirent64_t *top_direntp;
673 dirent64_t *vol_direntp;
674 struct stat64 sdirbuf;
675 struct stat64 sfilebuf;
676 afs_xfs_attr_t attrs;
677 afs_xfs_dattr_t dattrs;
679 char vol_dirname[1024];
682 xfs_Rename_t *renames = (xfs_Rename_t *) 0;
684 #define N_RENAME_STEP 64
693 if (stat64(mountedOn, &sdirbuf) < 0) {
694 perror("xfs_ListViceInodes: stat64");
699 inodeFile = fopen(resultFile, "w");
700 if (inodeFile == NULL) {
701 Log("Unable to create inode description file %s\n", resultFile);
706 if ((top_dirp = opendir(mountedOn)) == NULL) {
707 Log("Can't open directory %s to read inodes.\n", mountedOn);
711 while (top_direntp = readdir64(top_dirp)) {
712 /* Only descend directories with the AFSDIR attribute set.
713 * Could also verify the contents of the atribute, but currently
715 * Performance could be improved for single volume salvages by
716 * only going through the directory containing the volume's inodes.
717 * But I'm being complete as a first pass.
719 (void)sprintf(vol_dirname, "%s/%s", mountedOn, top_direntp->d_name);
720 length = SIZEOF_XFS_DATTR_T;
722 (vol_dirname, AFS_XFS_DATTR, (char *)&dattrs, &length, ATTR_ROOT))
725 if ((vol_dirp = opendir(vol_dirname)) == NULL) {
726 if (errno == ENOTDIR)
728 Log("Can't open directory %s to read inodes.\n", vol_dirname);
732 pino = top_direntp->d_ino;
734 while (vol_direntp = readdir64(vol_dirp)) {
735 if (vol_direntp->d_name[1] == '\0'
736 || vol_direntp->d_name[1] == '.')
739 info.ili_version = AFS_XFS_ILI_VERSION;
740 info_size = sizeof(i_list_inode_t);
742 ilistinode64(sdirbuf.st_dev, vol_direntp->d_ino, &info,
745 /* Where possible, give more explicit messages. */
749 Log("%s (device id %d) is not on an XFS filesystem.\n",
750 vol_dirname, sdirbuf.st_dev);
755 if (info_size != sizeof(i_list_inode_t)
756 || info.ili_version != AFS_XFS_ILI_VERSION) {
757 Log("Version skew between kernel and salvager.\n");
762 /* Continue, so we collect all the errors in the first pass. */
763 Log("Error listing inode named %s/%s: %s\n", vol_dirname,
764 vol_direntp->d_name, strerror(errno));
769 if (info.ili_attr_version != AFS_XFS_ATTR_VERS) {
770 Log("Unrecognized XFS attribute version %d in %s/%s. Upgrade salvager\n", info.ili_attr_version, vol_dirname, vol_direntp->d_name);
774 if (judgeInode && (*judgeInode) (&info.ili_info, judgeParam, rock) == 0)
779 (vol_dirname, pino, vol_direntp->d_name, &info,
785 /* Add this name to the list of items to rename. */
786 if (n_renames >= n_avail) {
787 n_avail += N_RENAME_STEP;
788 if (n_avail == N_RENAME_STEP)
789 renames = (xfs_Rename_t *)
790 malloc(n_avail * sizeof(xfs_Rename_t));
792 renames = (xfs_Rename_t *)
793 realloc((char *)renames,
794 n_avail * sizeof(xfs_Rename_t));
796 Log("Can't %salloc %lu bytes for rename list.\n",
797 (n_avail == N_RENAME_STEP) ? "m" : "re",
798 n_avail * sizeof(xfs_Rename_t));
802 (void)strcpy(renames[n_renames].name, vol_direntp->d_name);
803 renames[n_renames].uniq = info.ili_info.param[2];
809 (&info.ili_info, sizeof(vice_inode_info_t), 1, inodeFile)
811 Log("Error writing inode file for partition %s\n", mountedOn);
817 } /* end while vol_direntp */
820 vol_dirp = (DIR *) 0;
822 Log("Renaming files.\n");
823 if (xfs_RenameFiles(vol_dirname, renames, n_renames) < 0) {
831 free((char *)renames);
833 if (fflush(inodeFile) == EOF) {
834 ("Unable to successfully flush inode file for %s\n", mountedOn);
836 return errors ? -1 : -2;
838 if (fsync(fileno(inodeFile)) == -1) {
839 Log("Unable to successfully fsync inode file for %s\n", mountedOn);
841 return errors ? -1 : -2;
843 if (fclose(inodeFile) == EOF) {
844 Log("Unable to successfully close inode file for %s\n", mountedOn);
845 return errors ? -1 : -2;
848 * Paranoia: check that the file is really the right size
850 if (stat(resultFile, &status) == -1) {
851 Log("Unable to successfully stat inode file for %s\n", partition);
852 return errors ? -1 : -2;
854 if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
855 Log("Wrong size (%d instead of %d) in inode file for %s\n",
856 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
858 return errors ? -1 : -2;
863 Log("Errors encontered listing inodes, not salvaging partition.\n");
875 free((char *)renames);
884 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
885 int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
886 char *wpath, void *rock)
888 FILE *inodeFile = NULL;
889 char dev[50], rdev[51];
891 struct efs_dinode *p;
892 struct ViceInodeInfo info;
893 struct stat root_inode;
894 int ninodes = 0, err = 0;
895 struct efs_dinode *dinodeBuf = NULL;
897 ino_t imax, inum; /* total number of I-nodes in file system */
901 sleep(1); /* simulate operator */
907 if (stat(mountedOn, &root_inode) < 0) {
908 Log("cannot stat: %s\n", mountedOn);
911 #ifdef AFS_SGI_XFS_IOPS_ENV
912 if (!strcmp("xfs", root_inode.st_fstype)) {
913 return xfs_ListViceInodes(devname, mountedOn, resultFile, judgeInode,
914 judgeParam, forcep, forceR, wpath, rock);
918 Log("%s is not root of a filesystem\n", mountedOn);
923 #else /* AFS_SGI_ENV */
926 #define SPERB (MAXBSIZE / sizeof(short))
927 #define MAXNINDIR (MAXBSIZE / sizeof(daddr_t))
930 struct bufarea *b_next; /* must be first */
934 char b_buf[MAXBSIZE]; /* buffer space */
935 short b_lnks[SPERB]; /* link counts */
936 daddr_t b_indir[MAXNINDIR]; /* indirect block */
937 struct fs b_fs; /* super block */
938 struct cg b_cg; /* cylinder group */
942 typedef struct bufarea BUFAREA;
945 #define sblock sblk.b_un.b_fs
946 #endif /* AFS_HPUX_ENV */
948 extern char *afs_rawname();
950 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
951 int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
952 char *wpath, void *rock)
958 #else /* !AFS_AIX_ENV */
963 int i, c, e, bufsize, code, err = 0;
964 FILE *inodeFile = NULL;
965 char dev[50], rdev[100], err1[512], *ptr1;
966 struct dinode *inodes = NULL, *einodes, *dptr;
970 struct ViceInodeInfo info;
973 partition = mountedOn;
974 sprintf(rdev, "%s/%s", wpath, devname);
975 ptr1 = afs_rawname(rdev);
979 /* Bletch: this is terrible; is there a better way to do this? Does this work? vfsck doesn't even sleep!! */
981 sleep(5); /* Trying a smaller one for aix */
986 pfd = afs_open(rdev, O_RDONLY);
988 sprintf(err1, "Could not open device %s to get inode list\n", rdev);
993 if (bread(pfd, (char *)&super.fs, SUPERB, sizeof super.fs) == -1) {
996 if (bread(pfd, (char *)&sblock, SBLOCK, SBSIZE) == -1) {
998 if (bread(pfd, super.block, SBLOCK, SBSIZE) == -1) {
999 #endif /* AFS_HPUX_ENV */
1001 Log("Unable to read superblock, partition %s\n", partition);
1006 inodeFile = fopen(resultFile, "w");
1007 if (inodeFile == NULL) {
1008 Log("Unable to create inode description file %s\n", resultFile);
1014 * char *FSlabel(), *fslabel=0;
1015 * fslabel = FSlabel(&super.fs);
1017 if (super.fs.s_bsize == 0)
1018 super.fs.s_bsize = 512;
1019 if (super.fs.s_bsize != BSIZE) {
1020 Log("SuperBlk: Cluster size not %d; run vfsck\n", BSIZE);
1023 fmax = super.fs.s_fsize; /* first invalid blk num */
1024 imax = ((ino_t) super.fs.s_isize - (SUPERB + 1)) * INOPB;
1026 Log("Size check: imax==0!\n");
1029 if (GetAuxInodeFile(partition, &status) == 0) {
1030 Log("Can't access Aux inode file for partition %s, aborting\n",
1034 for (inum = 1; inum <= imax; inum++) {
1035 struct dauxinode *auxp;
1036 if ((auxp = IsAfsInode(inum)) == NULL) {
1037 /* Not an afs inode, keep going */
1040 if ((p = ginode(inum)) == NULL)
1042 /* deleted/non-existent inode when di_mode == 0 */
1045 info.inodeNumber = (int)inum;
1046 info.byteCount = p->di_size;
1047 info.linkCount = p->di_nlink;
1048 info.u.param[0] = auxp->aux_param1;
1049 info.u.param[1] = auxp->aux_param2;
1050 info.u.param[2] = auxp->aux_param3;
1051 info.u.param[3] = auxp->aux_param4;
1052 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
1055 if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
1056 Log("Error writing inode file for partition %s\n", partition);
1064 * run a few consistency checks of the superblock
1065 * (Cribbed from vfsck)
1068 #if defined(FD_FSMAGIC)
1069 if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)
1070 && (sblock.fs_magic != FD_FSMAGIC)
1071 #if defined(AFS_HPUX101_ENV)
1072 && (sblock.fs_magic != FD_FSMAGIC_2)
1076 if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)) {
1078 Log("There's something wrong with the superblock for partition %s; bad magic (%d) run vfsck\n", partition, sblock.fs_magic);
1081 if (sblock.fs_ncg < 1) {
1082 Log("There's something wrong with the superblock for partition %s; NCG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_ncg);
1085 if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG) {
1086 Log("There's something wrong with the superblock for partition %s; CPG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_cpg);
1089 if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl
1090 || (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
1091 Log("There's something wrong with the superblock for partition %s; NCYL LESS THAN NCG*CPG run vfsck\n", partition);
1094 if (sblock.fs_sbsize > SBSIZE) {
1095 Log("There's something wrong with the superblock for partition %s; bsize too large (%d vs. %d) run vfsck\n", partition, sblock.fs_sbsize, sblock.fs_bsize);
1099 if ((super.fs.fs_magic != FS_MAGIC)
1100 || (super.fs.fs_ncg < 1)
1101 #if defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1102 || (super.fs.fs_cpg < 1)
1104 || (super.fs.fs_cpg < 1 || super.fs.fs_cpg > MAXCPG)
1106 || (super.fs.fs_ncg * super.fs.fs_cpg < super.fs.fs_ncyl
1107 || (super.fs.fs_ncg - 1) * super.fs.fs_cpg >= super.fs.fs_ncyl)
1108 || (super.fs.fs_sbsize > SBSIZE)) {
1109 Log("There's something wrong with the superblock for partition %s; run vfsck\n", partition);
1112 #endif /* AFS_HPUX_ENV */
1115 bufsize = sblock.fs_ipg * sizeof(struct dinode);
1117 bufsize = super.fs.fs_ipg * sizeof(struct dinode);
1118 #endif /* AFS_HPUX_ENV */
1119 inodes = (struct dinode *)malloc(bufsize);
1120 einodes = (struct dinode *)(((char *)inodes) + bufsize);
1121 if (inodes == NULL) {
1122 Log("Unable to allocate enough memory to scan inodes; help!\n");
1125 Log("Scanning inodes on device %s...\n", rdev);
1127 for (c = 0; c < sblock.fs_ncg; c++) {
1128 i = c * sblock.fs_ipg;
1129 e = i + sblock.fs_ipg;
1130 #if defined(AFS_HPUX102_ENV)
1131 if (afs_lseek(pfd, dbtoo(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1134 if (afs_lseek(pfd, dbtob(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1138 for (c = 0; c < super.fs.fs_ncg; c++) {
1140 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1142 #if defined(AFS_DARWIN_ENV)
1143 #define offset_t off_t
1144 #define llseek lseek
1147 #endif /* AFS_SUN5_ENV */
1148 i = c * super.fs.fs_ipg;
1149 e = i + super.fs.fs_ipg;
1151 dblk1 = fsbtodb(&super.fs, itod(&super.fs, i));
1152 if (afs_lseek(pfd, (off_t) ((off_t) dblk1 * DEV_BSIZE), L_SET) == -1) {
1154 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1155 f1 = fsbtodb(&super.fs, itod(&super.fs, i));
1156 off = (offset_t) f1 << DEV_BSHIFT;
1157 if (llseek(pfd, off, L_SET) == -1) {
1159 if (afs_lseek(pfd, dbtob(fsbtodb(&super.fs, itod(&super.fs, i))), L_SET)
1161 #endif /* AFS_SUN5_ENV */
1162 #endif /* AFS_OSF_ENV */
1163 #endif /* AFS_HPUX_ENV */
1164 Log("Error reading inodes for partition %s; run vfsck\n",
1170 if (read(pfd, inodes, bufsize) != bufsize) {
1171 Log("Error reading inodes for partition %s; run vfsck\n",
1176 register int bj, bk;
1178 for (bj = bk = 0; bj < bufsize; bj = bj + 512, bk++) {
1179 if ((code = read(pfd, dptr, 512)) != 512) {
1180 Log("Error reading inode %d? for partition %s (errno = %d); run vfsck\n", bk + i, partition, errno);
1181 if (afs_lseek(pfd, 512, L_SET) == -1) {
1182 Log("Lseek failed\n");
1197 for (p = inodes; p < einodes && i < e; i++, p++) {
1199 Log("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1200 i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1201 p->di_size, p->di_nlink);
1203 ("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1204 i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1205 p->di_size, p->di_nlink);
1208 #ifdef AFS_3DISPARES
1209 /* Check to see if this inode is a pre-"OSF1 4.0D" inode */
1210 if ((p->di_uid || p->di_gid)
1211 && !(p->di_flags & (IC_XUID | IC_XGID))) {
1212 Log("Found unconverted inode %d: Use 'fs_conv_dux40D convert' on partition %s\n", i, partition);
1216 assert(0); /* define AFS_3DISPARES in param.h */
1219 #if defined(AFS_SUN56_ENV)
1220 /* if this is a pre-sol2.6 unconverted inode, bail out */
1222 afs_uint32 p1, p2, p3, p4;
1226 q = (quad *) & (p->di_ic.ic_lsize);
1228 p2 = p->di_ic.ic_flags;
1230 p4 = p->di_ic.ic_uid;
1231 p5 = p->di_ic.ic_gid;
1233 if ((p2 || p3) && !p4 && (p5 == -2)) {
1234 Log("Found unconverted inode %d\n", i);
1235 Log("You should run the AFS file conversion utility\n");
1240 if (IS_DVICEMAGIC(p) && (p->di_mode & IFMT) == IFREG) {
1241 afs_uint32 p2 = p->di_vicep2, p3 = DI_VICEP3(p);
1243 info.u.param[0] = p->di_vicep1;
1244 #ifdef AFS_3DISPARES
1245 if (((p2 >> 3) == INODESPECIAL) && (p2 & 0x3)) {
1246 info.u.param[1] = INODESPECIAL;
1247 info.u.param[2] = p3;
1248 info.u.param[3] = p2 & 0x3;
1250 info.u.param[1] = ((p2 >> 27) << 16) + (p3 & 0xffff);
1251 info.u.param[2] = (p2 & 0x3fffff);
1253 (((p2 >> 22) & 0x1f) << 16) + (p3 >> 16);
1256 info.u.param[1] = p->di_vicep2;
1257 info.u.param[2] = DI_VICEP3(p);
1258 info.u.param[3] = p->di_vicep4;
1260 info.inodeNumber = i;
1261 info.byteCount = p->di_size;
1262 info.linkCount = p->di_nlink;
1263 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
1266 if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
1267 Log("Error writing inode file for partition %s\n",
1281 if (fflush(inodeFile) == EOF) {
1282 Log("Unable to successfully flush inode file for %s\n", partition);
1286 if (fsync(fileno(inodeFile)) == -1) {
1287 Log("Unable to successfully fsync inode file for %s\n", partition);
1291 if (fclose(inodeFile) == EOF) {
1292 Log("Unable to successfully close inode file for %s\n", partition);
1298 * Paranoia: check that the file is really the right size
1300 if (stat(resultFile, &status) == -1) {
1301 Log("Unable to successfully stat inode file for %s\n", partition);
1305 if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
1306 Log("Wrong size (%d instead of %d) in inode file for %s\n",
1307 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
1326 #endif /* !AFS_SGI_ENV */
1327 #endif /* !AFS_AIX31_ENV */
1329 #ifdef AFS_DARWIN_ENV
1331 #define dbtob(db) ((unsigned)(db) << DEV_BSHIFT)
1335 bread(int fd, char *buf, daddr_t blk, afs_int32 size)
1338 #ifdef AFS_AIX41_ENV
1339 offset_t off = (offset_t) blk << FSBSHIFT;
1340 if (llseek(fd, off, 0) < 0) {
1341 Log("Unable to seek to offset %llu for block %u\n", off, blk);
1344 #else /* AFS_AIX41_ENV */
1345 if (afs_lseek(fd, blk * Bsize, 0) < 0) {
1346 Log("Unable to seek to offset %u for block %u\n", blk * Bsize, blk);
1348 #endif /* AFS_AIX41_ENV */
1350 if (afs_lseek(fd, (off_t) dbtob(blk), L_SET) < 0) {
1351 Log("Unable to seek to offset %u for block %u\n", dbtob(blk), blk);
1354 if (read(fd, buf, size) != size) {
1355 Log("Unable to read block %d, partition %s\n", blk, partition);
1361 #endif /* AFS_LINUX20_ENV */
1363 convertVolumeInfo(int fdr, int fdw, afs_uint32 vid)
1365 struct VolumeDiskData vd;
1368 if (read(fdr, &vd, sizeof(struct VolumeDiskData)) !=
1369 sizeof(struct VolumeDiskData)) {
1370 Log("1 convertiVolumeInfo: read failed for %lu with code %d\n", vid,
1374 vd.restoredFromId = vd.id; /* remember the RO volume here */
1376 vd.id = vd.parentId;
1380 vd.uniquifier += 5000; /* just in case there are still file copies
1381 from the old RW volume around */
1383 p = strrchr(vd.name, '.');
1384 if (p && !strcmp(p, ".readonly")) {
1388 if (write(fdw, &vd, sizeof(struct VolumeDiskData)) !=
1389 sizeof(struct VolumeDiskData)) {
1390 Log("1 convertiVolumeInfo: write failed for %lu with code %d\n", vid,
1398 afs_int32 inodeType;
1405 UpdateThisVolume(struct ViceInodeInfo *inodeinfo, VolumeId singleVolumeNumber,
1406 struct specino *specinos)
1409 if ((inodeinfo->u.vnode.vnodeNumber == INODESPECIAL) &&
1410 (inodeinfo->u.vnode.volumeId == singleVolumeNumber)) {
1411 specinos[inodeinfo->u.special.type].inodeNumber =
1412 inodeinfo->inodeNumber;
1414 return 0; /* We aren't using a result file, we're caching */
1418 getDevName(char *pbuffer, char *wpath)
1420 char pbuf[128], *ptr;
1421 strcpy(pbuf, pbuffer);
1422 ptr = (char *)strrchr(pbuf, '/');
1425 strcpy(wpath, pbuf);
1428 ptr = (char *)strrchr(pbuffer, '/');
1430 strcpy(pbuffer, ptr + 1);
1437 inode_ConvertROtoRWvolume(char *pname, afs_int32 volumeId)
1439 char dir_name[512], oldpath[512], newpath[512];
1441 char headername[16];
1443 int fd, err, forcep, len, j, code;
1445 struct DiskPartition *partP;
1446 struct ViceInodeInfo info;
1447 struct VolumeDiskHeader h;
1448 IHandle_t *ih, *ih2;
1449 FdHandle_t *fdP, *fdP2;
1451 char tmpDevName[100];
1453 struct specino specinos[VI_LINKTABLE+1];
1454 Inode nearInode = 0;
1456 memset(&specinos, 0, sizeof(specinos));
1458 (void)afs_snprintf(headername, sizeof headername, VFORMAT, volumeId);
1459 (void)afs_snprintf(oldpath, sizeof oldpath, "%s/%s", pname, headername);
1460 fd = open(oldpath, O_RDONLY);
1462 Log("1 inode_ConvertROtoRWvolume: Couldn't open header for RO-volume %lu.\n", volumeId);
1465 if (read(fd, &h, sizeof(h)) != sizeof(h)) {
1466 Log("1 inode_ConvertROtoRWvolume: Couldn't read header for RO-volume %lu.\n", volumeId);
1471 FSYNC_askfs(volumeId, pname, FSYNC_RESTOREVOLUME, 0);
1473 /* now do the work */
1475 for (partP = DiskPartitionList; partP && strcmp(partP->name, pname);
1476 partP = partP->next);
1478 Log("1 inode_ConvertROtoRWvolume: Couldn't find DiskPartition for %s\n", pname);
1482 strcpy(tmpDevName, partP->devName);
1483 name = getDevName(tmpDevName, wpath);
1485 if ((err = ListViceInodes(name, VPartitionPath(partP),
1486 NULL, UpdateThisVolume, volumeId,
1487 &forcep, 0, wpath, &specinos)) < 0)
1489 Log("1 inode_ConvertROtoRWvolume: Couldn't get special inodes\n");
1493 #if defined(NEARINODE_HINT)
1494 nearInodeHash(volumeId, nearInode);
1495 nearInode %= partP->f_files;
1498 for (j = VI_VOLINFO; j < VI_LINKTABLE+1; j++) {
1499 if (specinos[j].inodeNumber > 0) {
1500 specinos[j].ninodeNumber =
1501 IH_CREATE(NULL, partP->device, VPartitionPath(partP),
1502 nearInode, h.parent, INODESPECIAL, j, h.parent);
1503 IH_INIT(ih, partP->device, volumeId,
1504 specinos[j].inodeNumber);
1507 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j, volumeId);
1511 IH_INIT(ih2, partP->device, h.parent, specinos[j].ninodeNumber);
1512 fdP2 = IH_OPEN(ih2);
1514 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j, h.parent);
1518 if (j == VI_VOLINFO)
1519 convertVolumeInfo(fdP->fd_fd, fdP2->fd_fd, ih2->ih_vid);
1522 len = read(fdP->fd_fd, buffer, sizeof(buffer));
1527 code = write(fdP2->fd_fd, buffer, len);
1541 #ifdef AFS_64BIT_IOPS_ENV
1542 h.volumeInfo_lo = (afs_int32)specinos[VI_VOLINFO].ninodeNumber & 0xffffffff;
1543 h.volumeInfo_hi = (afs_int32)(specinos[VI_VOLINFO].ninodeNumber >> 32) && 0xffffffff;
1544 h.smallVnodeIndex_lo = (afs_int32)specinos[VI_SMALLINDEX].ninodeNumber & 0xffffffff;
1545 h.smallVnodeIndex_hi = (afs_int32)(specinos[VI_SMALLINDEX].ninodeNumber >> 32) & 0xffffffff;
1546 h.largeVnodeIndex_lo = (afs_int32)specinos[VI_LARGEINDEX].ninodeNumber & 0xffffffff;
1547 h.largeVnodeIndex_hi = (afs_int32)(specinos[VI_LARGEINDEX].ninodeNumber >> 32) & 0xffffffff;
1548 if (specinos[VI_LINKTABLE].ninodeNumber) {
1549 h.linkTable_lo = (afs_int32)specinos[VI_LINKTABLE].ninodeNumber & 0xffffffff;
1550 h.linkTable_hi = (afs_int32)specinos[VI_LINKTABLE].ninodeNumber & 0xffffffff;
1553 h.volumeInfo_lo = specinos[VI_VOLINFO].ninodeNumber;
1554 h.smallVnodeIndex_lo = specinos[VI_SMALLINDEX].ninodeNumber;
1555 h.largeVnodeIndex_lo = specinos[VI_LARGEINDEX].ninodeNumber;
1556 if (specinos[VI_LINKTABLE].ninodeNumber) {
1557 h.linkTable_lo = specinos[VI_LINKTABLE].ninodeNumber;
1561 (void)afs_snprintf(headername, sizeof headername, VFORMAT, h.id);
1562 (void)afs_snprintf(newpath, sizeof newpath, "%s/%s", pname, headername);
1563 fd = open(newpath, O_CREAT | O_EXCL | O_RDWR, 0644);
1565 Log("1 inode_ConvertROtoRWvolume: Couldn't create header for RW-volume %lu.\n", h.id);
1568 if (write(fd, &h, sizeof(h)) != sizeof(h)) {
1569 Log("1 inode_ConvertROtoRWvolume: Couldn't write header for RW-volume %lu.\n", h.id);
1574 if (unlink(oldpath) < 0) {
1575 Log("1 inode_ConvertROtoRWvolume: Couldn't unlink RO header, error = %d\n", errno);
1577 FSYNC_askfs(volumeId, pname, FSYNC_DONE, 0);
1578 FSYNC_askfs(h.id, pname, FSYNC_ON, 0);
1581 #endif /* AFS_NAMEI_ENV */