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)
112 #include "partition.h"
114 /*@+fcnmacros +macrofcndecl@*/
117 extern off64_t afs_lseek(int FD, off64_t O, int F);
118 #endif /*S_SPLINT_S */
119 #define afs_lseek(FD, O, F) lseek64(FD, (off64_t) (O), F)
120 #define afs_stat stat64
121 #define afs_fstat fstat64
122 #define afs_open open64
123 #define afs_fopen fopen64
124 #else /* !O_LARGEFILE */
126 extern off_t afs_lseek(int FD, off_t O, int F);
127 #endif /*S_SPLINT_S */
128 #define afs_lseek(FD, O, F) lseek(FD, (off_t) (O), F)
129 #define afs_stat stat
130 #define afs_fstat fstat
131 #define afs_open open
132 #define afs_fopen fopen
133 #endif /* !O_LARGEFILE */
134 /*@=fcnmacros =macrofcndecl@*/
136 /* Notice: parts of this module have been cribbed from vfsck.c */
139 static char *partition;
144 #include <jfs/filsys.h>
147 #define FSBSIZE (4096) /* filesystem block size */
148 #define FSBSHIFT (12) /* log2(FSBSIZE) */
149 #define FSBMASK (FSBSIZE - 1) /* FSBSIZE mask */
151 #define MIN_FSIZE DISKMAP_B /* minimum fs size (FSblocks) */
152 #define LAST_RSVD_I 15 /* last reserved inode */
157 * This will hopefully eventually make it into the system include files
159 #define INOPB (FSBSIZE / sizeof (struct dinode))
167 #endif /* AFS_AIX41_ENV */
170 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
171 XX This was lifted from some `com/cmd/fs/fshlpr_aix3/Fs.h', which indicated X
172 XX a longing to see it make it into a readily accessible include file. XXXXXX
173 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
175 * itoo - inode number to offset within disk block
178 #define itoo(x) (int) ((unsigned)(x) % INOPB)
180 int Bsize = FSBSIZE; /* block size for this system */
181 daddr_t fmax; /* total number of blocks n file system */
182 ino_t imax, inum; /* total number of I-nodes in file system */
184 static struct superblock fs;
185 struct dinode *ginode();
189 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
190 int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
191 char *wpath, void *rock)
193 FILE *inodeFile = NULL;
194 char dev[50], rdev[51];
197 struct ViceInodeInfo info;
198 struct stat root_inode;
199 int ninodes = 0, err = 0;
201 pfd = -1; /* initialize so we don't close on error output below. */
204 sleep(1); /* simulate operator */
210 partition = mountedOn;
211 sprintf(dev, "/dev/%s", devname);
212 sprintf(rdev, "/dev/r%s", devname);
214 if (stat(mountedOn, &root_inode) < 0) {
215 Log("cannot stat: %s\n", mountedOn);
219 if (root_inode.st_ino != ROOTDIR_I) {
220 Log("%s is not root of a filesystem\n", mountedOn);
226 * done with the superblock, now try to read the raw device.
228 if (ReadSuper(&fs, dev) < 0)
233 case FM_CLEAN: /* clean and unmounted */
234 Log("Most peculiar - Super blk in FM_CLEAN state!\n");
236 case FM_MOUNT: /* mounted cleanly */
239 case FM_MDIRTY: /* dirty when mounted or commit fail */
240 case FM_LOGREDO: /* log redo attempted but failed */
241 Log("File system %s is in a bad state.\n", rdev);
242 Log("Call your IBM representative.\n");
246 if (IsBigFilesFileSystem(&fs, (char *)0)) {
247 Log("%s is a big files filesystem, can't salvage.\n", mountedOn);
251 if (strncmp(fs.s_magic, fsv3magic, strlen(fsv3magic)) != 0) {
253 if ((strncmp(fs.s_magic, fsv3pmagic, strlen(fsv3pmagic)) != 0)
254 || (fs.s_version != fsv3pvers)) {
255 Log("Super block doesn't have the problem magic (%s vs v3magic %s v3pmagic %s)\n", fs.s_magic, fsv3magic, fsv3pmagic);
259 Log("Super block doesn't have the problem magic (%s vs v3magic %s)\n",
260 fs.s_magic, fsv3magic);
267 fragsize = (fs.s_fragsize) ? fs.s_fragsize : FSBSIZE;
268 iagsize = (fs.s_iagsize) ? fs.s_iagsize : fs.s_agsize;
269 ag512 = fragsize * fs.s_agsize / 512;
270 agblocks = fragsize * fs.s_agsize >> BSHIFT;
271 #endif /* AFS_AIX41_ENV */
273 fmax = fs.s_fsize / (FSBSIZE / 512); /* first invalid blk num */
275 pfd = afs_open(rdev, O_RDONLY);
277 Log("Unable to open `%s' inode for reading\n", rdev);
281 inodeFile = fopen(resultFile, "w");
282 if (inodeFile == NULL) {
283 Log("Unable to create inode description file %s\n", resultFile);
288 * calculate the maximum number of inodes possible
291 imax = iagsize * (fs.s_fsize / ag512) - 1;
292 #else /* AFS_AIX41_ENV */
294 ((fmax / fs.s_agsize +
295 ((fmax % fs.s_agsize) >= fs.s_agsize / INOPB ? 1 : 0))
297 #endif /* AFS_AIX41_ENV */
300 * check for "FORCESALVAGE" equivalent:
301 * LAST_RSVD_I is a vice inode, with dead beef, and
302 * di_nlink == 2 to indicate the FORCE.
304 assert(p = ginode(LAST_RSVD_I));
306 if (p->di_vicemagic == VICEMAGIC && p->di_vicep1 == 0xdeadbeef
307 && p->di_nlink == 2) {
309 idec(root_inode.st_dev, LAST_RSVD_I, 0xdeadbeef);
312 for (inum = LAST_RSVD_I + 1; inum <= imax; ++inum) {
313 if ((p = ginode(inum)) == NULL || p->di_vicemagic != VICEMAGIC
314 || (p->di_mode & IFMT) != IFREG)
317 info.inodeNumber = inum;
318 info.byteCount = p->di_size;
319 info.linkCount = p->di_nlink;
320 info.u.param[0] = p->di_vicep1;
321 info.u.param[1] = p->di_vicep2;
322 info.u.param[2] = p->di_vicep3;
323 info.u.param[3] = p->di_vicep4;
325 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
328 if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
329 Log("Error writing inode file for partition %s\n", partition);
335 if (fflush(inodeFile) == EOF) {
336 Log("Unable to successfully flush inode file for %s\n", partition);
340 if (fsync(fileno(inodeFile)) == -1) {
341 Log("Unable to successfully fsync inode file for %s\n", partition);
345 if (fclose(inodeFile) == EOF) {
346 Log("Unable to successfully close inode file for %s\n", partition);
352 * Paranoia: check that the file is really the right size
354 if (stat(resultFile, &status) == -1) {
355 Log("Unable to successfully stat inode file for %s\n", partition);
359 if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
360 Log("Wrong size (%d instead of %d) in inode file for %s\n",
361 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
380 /* Read in the superblock for devName */
382 ReadSuper(struct superblock *fs, char *devName)
386 pfd = afs_open(devName, O_RDONLY);
388 Log("Unable to open inode on %s for reading superblock.\n", devName);
392 if (bread(pfd, fs, SUPER_B, sizeof(struct superblock)) < 0) {
393 Log("Unable to read superblock on %s.\n", devName);
401 /* IsBigFilesFileSystem returns 1 if it's a big files filesystem, 0 otherwise. */
403 IsBigFilesFileSystem(struct superblock *sb)
405 if ((strncmp(sb->s_magic, fsv3pmagic, 4) == 0)
406 && (sb->s_version == fsbigfile)
420 static char buf[FSBSIZE];
421 static daddr_t last_blk = -1;
427 0) ? INODES_B + inum / INOPB : ag * agblocks + (inum -
430 #else /* AFS_AIX41_ENV */
431 ag = inum / fs.s_agsize;
434 0) ? INODES_B + inum / INOPB : ag * fs.s_agsize + (inum -
438 #endif /* AFS_AIX41_ENV */
440 if (last_blk != pblk) {
441 if (bread(pfd, buf, pblk, sizeof(buf)) < 0) {
448 dp = (struct dinode *)buf;
453 #else /* !AFS_AIX31_ENV */
455 #if defined(AFS_SGI_ENV)
457 /* libefs.h includes <assert.h>, which we don't want */
460 #ifdef AFS_SGI_EFS_IOPS_ENV
461 #include "sgiefs/libefs.h"
464 /* afs_efs_figet() replaces the SGI library routine because we are malloc'ing
465 * memory for all the inodes on all the cylinder groups without releasing
466 * it when we're done. Using afs_efs_figet ensures more efficient use of
470 afs_efs_figet(EFS_MOUNT * mp, struct efs_dinode *dinodeBuf, int *last_cgno,
473 int cgno = EFS_ITOCG(mp->m_fs, inum);
476 if (cgno != *last_cgno) {
478 (mp->m_fd, (char *)dinodeBuf, EFS_CGIMIN(mp->m_fs, cgno),
479 mp->m_fs->fs_cgisize) != mp->m_fs->fs_cgisize) {
480 Log("Unable to read inodes for cylinder group %d.\n", cgno);
486 return dinodeBuf + (inum % (mp->m_fs->fs_cgisize * EFS_INOPBB));
491 efs_ListViceInodes(char *devname, char *mountedOn, char *resultFile,
492 int (*judgeInode) (), int judgeParam, int *forcep,
493 int forceR, char *wpath, void *rock)
495 FILE *inodeFile = NULL;
496 char dev[50], rdev[51];
498 struct efs_dinode *p;
499 struct ViceInodeInfo info;
500 int ninodes = 0, err = 0;
501 struct efs_dinode *dinodeBuf = NULL;
504 ino_t imax, inum; /* total number of I-nodes in file system */
508 partition = mountedOn;
509 sprintf(dev, "/dev/dsk/%s", devname);
510 sprintf(rdev, "/dev/rdsk/%s", devname);
517 if ((stat(rdev, &status) == -1)
518 || ((mp = efs_mount(rdev, O_RDONLY)) == NULL)) {
519 sprintf(rdev, "/dev/r%s", devname);
520 mp = efs_mount(rdev, O_RDONLY);
523 Log("Unable to open `%s' inode for reading\n", rdev);
527 inodeFile = fopen(resultFile, "w");
528 if (inodeFile == NULL) {
529 Log("Unable to create inode description file %s\n", resultFile);
533 /* Allocate space for one cylinder group's worth of inodes. */
534 dinodeBuf = (struct efs_dinode *)malloc(mp->m_fs->fs_cgisize * BBSIZE);
536 Log("Unable to malloc %lu bytes for inode buffer.\n",
537 mp->m_fs->fs_cgisize * BBSIZE);
542 * calculate the maximum number of inodes possible
544 imax = mp->m_fs->fs_ncg * mp->m_fs->fs_ipcg;
547 for (inum = 2; inum < imax; ++inum) {
548 p = afs_efs_figet(mp, dinodeBuf, &last_cgno, inum);
550 Log("Unable to read all inodes from partition.\n");
553 if (!IS_DVICEMAGIC(p) || !((p->di_mode & IFMT) == IFREG)) {
556 #if defined(AFS_SGI_EXMAG)
559 dmag(p, 0) << 24 | dmag(p, 1) << 16 | dmag(p, 2) << 8 | dmag(p,
562 if ((p)->di_version == EFS_IVER_AFSSPEC) {
563 info.u.param[1] = INODESPECIAL;
565 info.u.param[2] = dmag(p, 8);
568 dmag(p, 4) << 24 | dmag(p, 5) << 16 | dmag(p,
575 dmag(p, 4) << 16 | dmag(p, 5) << 8 | dmag(p, 6) << 0;
578 dmag(p, 7) << 16 | dmag(p, 8) << 8 | dmag(p, 9) << 0;
581 dmag(p, 10) << 16 | dmag(p, 11) << 8 | (p)->di_spare;
586 info.inodeNumber = inum;
587 info.byteCount = p->di_size;
588 info.linkCount = p->di_nlink;
590 Log("Ino=%d, bytes=%d, linkCnt=%d, [%x,%x,%x,%x]\n", inum, p->di_size,
591 p->di_nlink, info.u.param[0], info.u.param[1], info.u.param[2],
594 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
597 if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
598 Log("Error writing inode file for partition %s\n", partition);
604 if (fflush(inodeFile) == EOF) {
605 Log("Unable to successfully flush inode file for %s\n", partition);
609 if (fsync(fileno(inodeFile)) == -1) {
610 Log("Unable to successfully fsync inode file for %s\n", partition);
614 if (fclose(inodeFile) == EOF) {
615 Log("Unable to successfully close inode file for %s\n", partition);
621 * Paranoia: check that the file is really the right size
623 if (stat(resultFile, &status) == -1) {
624 Log("Unable to successfully stat inode file for %s\n", partition);
628 if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
629 Log("Wrong size (%d instead of %d) in inode file for %s\n",
630 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
653 #endif /* AFS_SGI_EFS_IOPS_ENV */
655 #ifdef AFS_SGI_XFS_IOPS_ENV
657 #include <afs/xfsattrs.h>
658 /* xfs_ListViceInodes
660 * xfs_ListViceInodes verifies and correct the XFS namespace as it collects
661 * the inode information. The name is required for the idec operation to work.
662 * Steps 2 and 3 below are for the AFS_XFS_NAME_VERS == 1. If the name space
663 * changes, the algorithm will need to change.
664 * 1) If the parent inode number does not match the directory's inod number,
665 * change it in the attribute.
666 * 2) If the unqifier in the attribute does not match the name, rename the
667 * file. This is done by doing an exclusive open, incrementing the tag
668 * number until a file can be created. If the tag changes, then the
669 * attribute will need updating.
670 * 3) If the tag in the attribute does not match the name, change the
672 * 4) Verify uid = RW volume id and gid = XFS_VICEMAGIC.
678 * Does the verifications listed above.
679 * We can't change the names until the readdir is complete, so we set the
680 * rename flag if the file needs renaming.
683 xfs_VerifyInode(char *dir, uint64_t pino, char *name, i_list_inode_t * info,
690 int update_chown = 0;
697 (void)sprintf(path, "%s/%s", dir, name);
698 /* Verify uid and gid fields */
699 if (info->ili_magic != XFS_VICEMAGIC) {
700 Log("%s magic for %s/%s (inode %s) from %d to %d\n",
701 Testing ? "Would have changed" : "Changing", dir, name,
702 PrintInode(NULL, info->ili_info.inodeNumber), info->ili_magic,
708 vno = info->ili_info.param[0];
709 if (info->ili_vno != AFS_XFS_VNO_CLIP(vno)) {
710 Log("%s volume id for %s/%s (inode %s) from %d to %d\n",
711 Testing ? "Would have changed" : "Changing", dir, name,
712 PrintInode(NULL, info->ili_info.inodeNumber), info->ili_vno,
713 AFS_XFS_VNO_CLIP(vno));
719 if (chown(path, AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC) < 0) {
720 Log("Can't chown %s to uid=%d, gid=0x%x\n", path,
721 AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC);
726 /* Check Parent inode number. */
727 if (info->ili_pino != pino) {
728 afs_ino_str_t sino, sipino, spino;
729 (void)PrintInode(sino, info->ili_info.inodeNumber);
730 (void)PrintInode(sipino, info->ili_pino);
731 (void)PrintInode(spino, pino);
732 Log("%s parent ino for %s (inode %s) from %s to %s.\n",
733 Testing ? "Would have changed" : "Changing", path, sino, sipino,
739 /* Verify the file name. */
740 (void)strcpy(tmpName, ".");
741 (void)strcat(tmpName, int_to_base64(stmp, info->ili_info.param[2]));
742 if (strncmp(name, tmpName, strlen(tmpName))) {
743 Log("%s name %s (inode %s) in directory %s, unique=%d, tag=%d\n",
744 Testing ? "Would have returned bad" : "Bad", name,
745 PrintInode(NULL, info->ili_info.inodeNumber), dir,
746 info->ili_info.param[2], info->ili_tag);
752 /* update the tag? */
753 (void)strcat(tmpName, ".");
754 (void)strcat(tmpName, int_to_base64(stmp, info->ili_tag));
755 if (strcmp(name, tmpName)) {
757 (void)strcpy(tmpName, name);
758 p = strchr(tmpName + 1, '.');
760 Log("No tag found on name %s (inode %s)in directory, %s.\n",
761 name, PrintInode(NULL, info->ili_info.inodeNumber), dir,
762 Testing ? "would have renamed" : "will rename");
766 tag = base64_to_int(p + 1);
767 Log("%s the tag for %s (inode %s) from %d to %d.\n",
768 Testing ? "Would have changed" : "Will change", path,
769 PrintInode(NULL, info->ili_info.inodeNumber), dir, tag,
777 if (update_pino || update_tag) {
778 afs_xfs_attr_t attrs;
781 length = SIZEOF_XFS_ATTR_T;
782 if (attr_get(path, AFS_XFS_ATTR, (char *)&attrs, &length, ATTR_ROOT) <
784 Log("Can't get AFS attribute for %s\n", path);
788 attrs.at_pino = pino;
792 (path, AFS_XFS_ATTR, (char *)&attrs, length,
793 ATTR_ROOT | ATTR_REPLACE) < 0) {
794 Log("Can't set AFS attribute into %s\n", path);
808 xfs_RenameFiles(char *dir, xfs_Rename_t * renames, int n_renames)
811 char opath[128], nbase[128], npath[128];
812 afs_xfs_attr_t attrs;
813 int length = SIZEOF_XFS_ATTR_T;
818 for (i = 0; i < n_renames; i++) {
819 (void)sprintf(opath, "%s/%s", dir, renames[i].name);
820 (void)sprintf(nbase, "%s/.%s", dir,
821 int_to_base64(stmp, renames[i].uniq));
822 for (tag = 2, j = 0; j < 64; tag++, j++) {
823 (void)sprintf(npath, "%s.%s", nbase, int_to_base64(stmp, tag));
824 fd = afs_open(npath, O_CREAT | O_EXCL | O_RDWR, 0);
831 Log("Can't find a new name for %s\n", opath);
834 if (rename(opath, npath) < 0) {
835 Log("Can't rename %s to %s\n", opath, npath);
838 Log("Renamed %s to %s\n", opath, npath);
845 xfs_ListViceInodes(char *devname, char *mountedOn, char *resultFile,
846 int (*judgeInode) (), int judgeParam, int *forcep,
847 int forceR, char *wpath, void *rock)
849 FILE *inodeFile = NULL;
851 int info_size = sizeof(i_list_inode_t);
854 dirent64_t *top_direntp;
856 dirent64_t *vol_direntp;
857 struct stat64 sdirbuf;
858 struct stat64 sfilebuf;
859 afs_xfs_attr_t attrs;
860 afs_xfs_dattr_t dattrs;
862 char vol_dirname[1024];
865 xfs_Rename_t *renames = (xfs_Rename_t *) 0;
867 #define N_RENAME_STEP 64
876 if (stat64(mountedOn, &sdirbuf) < 0) {
877 perror("xfs_ListViceInodes: stat64");
881 inodeFile = fopen(resultFile, "w");
882 if (inodeFile == NULL) {
883 Log("Unable to create inode description file %s\n", resultFile);
887 if ((top_dirp = opendir(mountedOn)) == NULL) {
888 Log("Can't open directory %s to read inodes.\n", mountedOn);
892 while (top_direntp = readdir64(top_dirp)) {
893 /* Only descend directories with the AFSDIR attribute set.
894 * Could also verify the contents of the atribute, but currently
896 * Performance could be improved for single volume salvages by
897 * only going through the directory containing the volume's inodes.
898 * But I'm being complete as a first pass.
900 (void)sprintf(vol_dirname, "%s/%s", mountedOn, top_direntp->d_name);
901 length = SIZEOF_XFS_DATTR_T;
903 (vol_dirname, AFS_XFS_DATTR, (char *)&dattrs, &length, ATTR_ROOT))
906 if ((vol_dirp = opendir(vol_dirname)) == NULL) {
907 if (errno == ENOTDIR)
909 Log("Can't open directory %s to read inodes.\n", vol_dirname);
913 pino = top_direntp->d_ino;
915 while (vol_direntp = readdir64(vol_dirp)) {
916 if (vol_direntp->d_name[1] == '\0'
917 || vol_direntp->d_name[1] == '.')
920 info.ili_version = AFS_XFS_ILI_VERSION;
921 info_size = sizeof(i_list_inode_t);
923 ilistinode64(sdirbuf.st_dev, vol_direntp->d_ino, &info,
926 /* Where possible, give more explicit messages. */
930 Log("%s (device id %d) is not on an XFS filesystem.\n",
931 vol_dirname, sdirbuf.st_dev);
936 if (info_size != sizeof(i_list_inode_t)
937 || info.ili_version != AFS_XFS_ILI_VERSION) {
938 Log("Version skew between kernel and salvager.\n");
943 /* Continue, so we collect all the errors in the first pass. */
944 Log("Error listing inode named %s/%s: %s\n", vol_dirname,
945 vol_direntp->d_name, strerror(errno));
950 if (info.ili_attr_version != AFS_XFS_ATTR_VERS) {
951 Log("Unrecognized XFS attribute version %d in %s/%s. Upgrade salvager\n", info.ili_attr_version, vol_dirname, vol_direntp->d_name);
955 if (judgeInode && (*judgeInode) (&info.ili_info, judgeParam, rock) == 0)
960 (vol_dirname, pino, vol_direntp->d_name, &info,
966 /* Add this name to the list of items to rename. */
967 if (n_renames >= n_avail) {
968 n_avail += N_RENAME_STEP;
969 if (n_avail == N_RENAME_STEP)
970 renames = (xfs_Rename_t *)
971 malloc(n_avail * sizeof(xfs_Rename_t));
973 renames = (xfs_Rename_t *)
974 realloc((char *)renames,
975 n_avail * sizeof(xfs_Rename_t));
977 Log("Can't %salloc %lu bytes for rename list.\n",
978 (n_avail == N_RENAME_STEP) ? "m" : "re",
979 n_avail * sizeof(xfs_Rename_t));
983 (void)strcpy(renames[n_renames].name, vol_direntp->d_name);
984 renames[n_renames].uniq = info.ili_info.param[2];
989 (&info.ili_info, sizeof(vice_inode_info_t), 1, inodeFile)
991 Log("Error writing inode file for partition %s\n", mountedOn);
996 } /* end while vol_direntp */
999 vol_dirp = (DIR *) 0;
1001 Log("Renaming files.\n");
1002 if (xfs_RenameFiles(vol_dirname, renames, n_renames) < 0) {
1010 free((char *)renames);
1011 if (fflush(inodeFile) == EOF) {
1012 ("Unable to successfully flush inode file for %s\n", mountedOn);
1014 return errors ? -1 : -2;
1016 if (fsync(fileno(inodeFile)) == -1) {
1017 Log("Unable to successfully fsync inode file for %s\n", mountedOn);
1019 return errors ? -1 : -2;
1021 if (fclose(inodeFile) == EOF) {
1022 Log("Unable to successfully close inode file for %s\n", mountedOn);
1023 return errors ? -1 : -2;
1026 * Paranoia: check that the file is really the right size
1028 if (stat(resultFile, &status) == -1) {
1029 Log("Unable to successfully stat inode file for %s\n", partition);
1030 return errors ? -1 : -2;
1032 if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
1033 Log("Wrong size (%d instead of %d) in inode file for %s\n",
1034 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
1036 return errors ? -1 : -2;
1040 Log("Errors encontered listing inodes, not salvaging partition.\n");
1052 free((char *)renames);
1061 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
1062 int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
1063 char *wpath, void *rock)
1065 FILE *inodeFile = NULL;
1066 char dev[50], rdev[51];
1068 struct efs_dinode *p;
1069 struct ViceInodeInfo info;
1070 struct stat root_inode;
1071 int ninodes = 0, err = 0;
1072 struct efs_dinode *dinodeBuf = NULL;
1074 #ifdef AFS_SGI_EFS_IOPS_ENV
1077 ino_t imax, inum; /* total number of I-nodes in file system */
1081 sleep(1); /* simulate operator */
1087 if (stat(mountedOn, &root_inode) < 0) {
1088 Log("cannot stat: %s\n", mountedOn);
1091 #ifdef AFS_SGI_XFS_IOPS_ENV
1092 if (!strcmp("xfs", root_inode.st_fstype)) {
1093 return xfs_ListViceInodes(devname, mountedOn, resultFile, judgeInode,
1094 judgeParam, forcep, forceR, wpath, rock);
1097 #ifdef AFS_SGI_EFS_IOPS_ENV
1098 if (root_inode.st_ino == EFS_ROOTINO) {
1099 return efs_ListViceInodes(devname, mountedOn, resultFile, judgeInode,
1100 judgeParam, forcep, forceR, wpath, rock);
1104 Log("%s is not root of a filesystem\n", mountedOn);
1109 #else /* AFS_SGI_ENV */
1112 #define SPERB (MAXBSIZE / sizeof(short))
1113 #define MAXNINDIR (MAXBSIZE / sizeof(daddr_t))
1116 struct bufarea *b_next; /* must be first */
1120 char b_buf[MAXBSIZE]; /* buffer space */
1121 short b_lnks[SPERB]; /* link counts */
1122 daddr_t b_indir[MAXNINDIR]; /* indirect block */
1123 struct fs b_fs; /* super block */
1124 struct cg b_cg; /* cylinder group */
1128 typedef struct bufarea BUFAREA;
1131 #define sblock sblk.b_un.b_fs
1132 #endif /* AFS_HPUX_ENV */
1134 extern char *afs_rawname();
1136 ListViceInodes(char *devname, char *mountedOn, char *resultFile,
1137 int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
1138 char *wpath, void *rock)
1144 #else /* !AFS_AIX_ENV */
1149 int i, c, e, bufsize, code, err = 0;
1150 FILE *inodeFile = NULL;
1151 char dev[50], rdev[100], err1[512], *ptr1;
1152 struct dinode *inodes = NULL, *einodes, *dptr;
1156 struct ViceInodeInfo info;
1159 partition = mountedOn;
1160 sprintf(rdev, "%s/%s", wpath, devname);
1161 ptr1 = afs_rawname(rdev);
1165 /* Bletch: this is terrible; is there a better way to do this? Does this work? vfsck doesn't even sleep!! */
1167 sleep(5); /* Trying a smaller one for aix */
1172 pfd = afs_open(rdev, O_RDONLY);
1174 sprintf(err1, "Could not open device %s to get inode list\n", rdev);
1179 if (bread(pfd, (char *)&super.fs, SUPERB, sizeof super.fs) == -1) {
1182 if (bread(pfd, (char *)&sblock, SBLOCK, SBSIZE) == -1) {
1184 if (bread(pfd, super.block, SBLOCK, SBSIZE) == -1) {
1185 #endif /* AFS_HPUX_ENV */
1187 Log("Unable to read superblock, partition %s\n", partition);
1191 inodeFile = fopen(resultFile, "w");
1192 if (inodeFile == NULL) {
1193 Log("Unable to create inode description file %s\n", resultFile);
1198 * char *FSlabel(), *fslabel=0;
1199 * fslabel = FSlabel(&super.fs);
1201 if (super.fs.s_bsize == 0)
1202 super.fs.s_bsize = 512;
1203 if (super.fs.s_bsize != BSIZE) {
1204 Log("SuperBlk: Cluster size not %d; run vfsck\n", BSIZE);
1207 fmax = super.fs.s_fsize; /* first invalid blk num */
1208 imax = ((ino_t) super.fs.s_isize - (SUPERB + 1)) * INOPB;
1210 Log("Size check: imax==0!\n");
1213 if (GetAuxInodeFile(partition, &status) == 0) {
1214 Log("Can't access Aux inode file for partition %s, aborting\n",
1218 for (inum = 1; inum <= imax; inum++) {
1219 struct dauxinode *auxp;
1220 if ((auxp = IsAfsInode(inum)) == NULL) {
1221 /* Not an afs inode, keep going */
1224 if ((p = ginode(inum)) == NULL)
1226 /* deleted/non-existent inode when di_mode == 0 */
1229 info.inodeNumber = (int)inum;
1230 info.byteCount = p->di_size;
1231 info.linkCount = p->di_nlink;
1232 info.u.param[0] = auxp->aux_param1;
1233 info.u.param[1] = auxp->aux_param2;
1234 info.u.param[2] = auxp->aux_param3;
1235 info.u.param[3] = auxp->aux_param4;
1236 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
1238 if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
1239 Log("Error writing inode file for partition %s\n", partition);
1246 * run a few consistency checks of the superblock
1247 * (Cribbed from vfsck)
1250 #if defined(FD_FSMAGIC)
1251 if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)
1252 && (sblock.fs_magic != FD_FSMAGIC)
1253 #if defined(AFS_HPUX101_ENV)
1254 && (sblock.fs_magic != FD_FSMAGIC_2)
1258 if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)) {
1260 Log("There's something wrong with the superblock for partition %s; bad magic (%d) run vfsck\n", partition, sblock.fs_magic);
1263 if (sblock.fs_ncg < 1) {
1264 Log("There's something wrong with the superblock for partition %s; NCG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_ncg);
1267 if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG) {
1268 Log("There's something wrong with the superblock for partition %s; CPG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_cpg);
1271 if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl
1272 || (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
1273 Log("There's something wrong with the superblock for partition %s; NCYL LESS THAN NCG*CPG run vfsck\n", partition);
1276 if (sblock.fs_sbsize > SBSIZE) {
1277 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);
1281 if ((super.fs.fs_magic != FS_MAGIC)
1282 || (super.fs.fs_ncg < 1)
1283 #if defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1284 || (super.fs.fs_cpg < 1)
1286 || (super.fs.fs_cpg < 1 || super.fs.fs_cpg > MAXCPG)
1288 || (super.fs.fs_ncg * super.fs.fs_cpg < super.fs.fs_ncyl
1289 || (super.fs.fs_ncg - 1) * super.fs.fs_cpg >= super.fs.fs_ncyl)
1290 || (super.fs.fs_sbsize > SBSIZE)) {
1291 Log("There's something wrong with the superblock for partition %s; run vfsck\n", partition);
1294 #endif /* AFS_HPUX_ENV */
1297 bufsize = sblock.fs_ipg * sizeof(struct dinode);
1299 bufsize = super.fs.fs_ipg * sizeof(struct dinode);
1300 #endif /* AFS_HPUX_ENV */
1301 inodes = (struct dinode *)malloc(bufsize);
1302 einodes = (struct dinode *)(((char *)inodes) + bufsize);
1303 if (inodes == NULL) {
1304 Log("Unable to allocate enough memory to scan inodes; help!\n");
1307 Log("Scanning inodes on device %s...\n", rdev);
1309 for (c = 0; c < sblock.fs_ncg; c++) {
1310 i = c * sblock.fs_ipg;
1311 e = i + sblock.fs_ipg;
1312 #if defined(AFS_HPUX102_ENV)
1313 if (afs_lseek(pfd, dbtoo(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1316 if (afs_lseek(pfd, dbtob(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1320 for (c = 0; c < super.fs.fs_ncg; c++) {
1322 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1324 #if defined(AFS_DARWIN_ENV)
1325 #define offset_t off_t
1326 #define llseek lseek
1329 #endif /* AFS_SUN5_ENV */
1330 i = c * super.fs.fs_ipg;
1331 e = i + super.fs.fs_ipg;
1333 dblk1 = fsbtodb(&super.fs, itod(&super.fs, i));
1334 if (afs_lseek(pfd, (off_t) ((off_t) dblk1 * DEV_BSIZE), L_SET) == -1) {
1336 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1337 f1 = fsbtodb(&super.fs, itod(&super.fs, i));
1338 off = (offset_t) f1 << DEV_BSHIFT;
1339 if (llseek(pfd, off, L_SET) == -1) {
1341 if (afs_lseek(pfd, dbtob(fsbtodb(&super.fs, itod(&super.fs, i))), L_SET)
1343 #endif /* AFS_SUN5_ENV */
1344 #endif /* AFS_OSF_ENV */
1345 #endif /* AFS_HPUX_ENV */
1346 Log("Error reading inodes for partition %s; run vfsck\n",
1352 if (read(pfd, inodes, bufsize) != bufsize) {
1353 Log("Error reading inodes for partition %s; run vfsck\n",
1358 register int bj, bk;
1360 for (bj = bk = 0; bj < bufsize; bj = bj + 512, bk++) {
1361 if ((code = read(pfd, dptr, 512)) != 512) {
1362 Log("Error reading inode %d? for partition %s (errno = %d); run vfsck\n", bk + i, partition, errno);
1363 if (afs_lseek(pfd, 512, L_SET) == -1) {
1364 Log("Lseek failed\n");
1379 for (p = inodes; p < einodes && i < e; i++, p++) {
1381 Log("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1382 i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1383 p->di_size, p->di_nlink);
1385 ("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1386 i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1387 p->di_size, p->di_nlink);
1390 #ifdef AFS_3DISPARES
1391 /* Check to see if this inode is a pre-"OSF1 4.0D" inode */
1392 if ((p->di_uid || p->di_gid)
1393 && !(p->di_flags & (IC_XUID | IC_XGID))) {
1394 Log("Found unconverted inode %d: Use 'fs_conv_dux40D convert' on partition %s\n", i, partition);
1398 assert(0); /* define AFS_3DISPARES in param.h */
1401 #if defined(AFS_SUN56_ENV)
1402 /* if this is a pre-sol2.6 unconverted inode, bail out */
1404 afs_uint32 p1, p2, p3, p4;
1408 q = (quad *) & (p->di_ic.ic_lsize);
1410 p2 = p->di_ic.ic_flags;
1412 p4 = p->di_ic.ic_uid;
1413 p5 = p->di_ic.ic_gid;
1415 if ((p2 || p3) && !p4 && (p5 == -2)) {
1416 Log("Found unconverted inode %d\n", i);
1417 Log("You should run the AFS file conversion utility\n");
1422 if (IS_DVICEMAGIC(p) && (p->di_mode & IFMT) == IFREG) {
1423 afs_uint32 p2 = p->di_vicep2, p3 = DI_VICEP3(p);
1425 info.u.param[0] = p->di_vicep1;
1426 #ifdef AFS_3DISPARES
1427 if (((p2 >> 3) == INODESPECIAL) && (p2 & 0x3)) {
1428 info.u.param[1] = INODESPECIAL;
1429 info.u.param[2] = p3;
1430 info.u.param[3] = p2 & 0x3;
1432 info.u.param[1] = ((p2 >> 27) << 16) + (p3 & 0xffff);
1433 info.u.param[2] = (p2 & 0x3fffff);
1435 (((p2 >> 22) & 0x1f) << 16) + (p3 >> 16);
1438 info.u.param[1] = p->di_vicep2;
1439 info.u.param[2] = DI_VICEP3(p);
1440 info.u.param[3] = p->di_vicep4;
1442 info.inodeNumber = i;
1443 info.byteCount = p->di_size;
1444 info.linkCount = p->di_nlink;
1445 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
1447 if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
1448 Log("Error writing inode file for partition %s\n",
1460 if (fflush(inodeFile) == EOF) {
1461 Log("Unable to successfully flush inode file for %s\n", partition);
1465 if (fsync(fileno(inodeFile)) == -1) {
1466 Log("Unable to successfully fsync inode file for %s\n", partition);
1470 if (fclose(inodeFile) == EOF) {
1471 Log("Unable to successfully close inode file for %s\n", partition);
1477 * Paranoia: check that the file is really the right size
1479 if (stat(resultFile, &status) == -1) {
1480 Log("Unable to successfully stat inode file for %s\n", partition);
1484 if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
1485 Log("Wrong size (%d instead of %d) in inode file for %s\n",
1486 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
1504 #endif /* !AFS_SGI_ENV */
1505 #endif /* !AFS_AIX31_ENV */
1507 #ifdef AFS_DARWIN_ENV
1509 #define dbtob(db) ((unsigned)(db) << DEV_BSHIFT)
1513 bread(int fd, char *buf, daddr_t blk, afs_int32 size)
1516 #ifdef AFS_AIX41_ENV
1517 offset_t off = (offset_t) blk << FSBSHIFT;
1518 if (llseek(fd, off, 0) < 0) {
1519 Log("Unable to seek to offset %llu for block %u\n", off, blk);
1522 #else /* AFS_AIX41_ENV */
1523 if (afs_lseek(fd, blk * Bsize, 0) < 0) {
1524 Log("Unable to seek to offset %u for block %u\n", blk * Bsize, blk);
1526 #endif /* AFS_AIX41_ENV */
1528 if (afs_lseek(fd, (off_t) dbtob(blk), L_SET) < 0) {
1529 Log("Unable to seek to offset %u for block %u\n", dbtob(blk), blk);
1532 if (read(fd, buf, size) != size) {
1533 Log("Unable to read block %d, partition %s\n", blk, partition);
1539 #endif /* AFS_LINUX20_ENV */
1540 #endif /* AFS_NAMEI_ENV */