Avoid thread-unsafe PrintInode in threaded code
[openafs.git] / src / vol / listinodes.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
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
8  */
9
10 /*
11
12         System:         VICE-TWO
13         Module:         listinodes.c
14         Institution:    The Information Technology Center, Carnegie-Mellon University
15
16  */
17
18 #define ITC                     /* Required by inode.h */
19
20 #include <afsconfig.h>
21 #include <afs/param.h>
22
23 #include <string.h>
24
25
26 #ifndef AFS_NAMEI_ENV
27 #if defined(AFS_LINUX20_ENV) || defined(AFS_SUN4_ENV)
28 /* ListViceInodes
29  *
30  * Return codes:
31  * 0 - success
32  * -1 - Unable to read the inodes.
33  * -2 - Unable to completely write temp file. Produces warning message in log.
34  */
35 int
36 ListViceInodes(char *devname, char *mountedOn, FILE *inodeFile,
37                afs_uint32 (*judgeInode) (), afs_uint32 judgeParam, int *forcep, int forceR,
38                char *wpath, void *rock)
39 {
40     Log("ListViceInodes not implemented for this platform!\n");
41     return -1;
42 }
43 #else
44 #include <ctype.h>
45 #include <sys/param.h>
46 #if defined(AFS_SGI_ENV)
47 #else
48 #ifdef  AFS_OSF_ENV
49 #include <ufs/fs.h>
50 #else /* AFS_OSF_ENV */
51 #ifdef AFS_VFSINCL_ENV
52 #define VFS
53 #ifdef    AFS_SUN5_ENV
54 #include <sys/fs/ufs_fs.h>
55 #else
56 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
57 #include <ufs/ufs/dinode.h>
58 #include <ufs/ffs/fs.h>
59 #define itod ino_to_fsba
60 #else
61 #include <ufs/fs.h>
62 #endif
63 #endif
64 #else /* AFS_VFSINCL_ENV */
65 #ifdef  AFS_AIX_ENV
66 #include <sys/filsys.h>
67 #else
68 #include <sys/fs.h>
69 #endif
70 #endif /* AFS_VFSINCL_ENV */
71 #endif /* AFS_OSF_ENV */
72 #include <sys/time.h>
73 #ifdef AFS_VFSINCL_ENV
74 #include <sys/vnode.h>
75 #ifdef    AFS_SUN5_ENV
76 #include <sys/fs/ufs_inode.h>
77 #else
78 #if !defined(AFS_DARWIN_ENV)
79 #include <ufs/inode.h>
80 #endif
81 #endif
82 #else /* AFS_VFSINCL_ENV */
83 #ifdef  AFS_OSF_ENV
84 #include <ufs/inode.h>
85 #else /* AFS_OSF_ENV */
86 #include <sys/inode.h>
87 #endif
88 #endif /* AFS_VFSINCL_ENV */
89 #endif /* AFS_SGI_ENV */
90 #include <afs/osi_inode.h>
91 #include <sys/file.h>
92 #include <stdio.h>
93 #include <rx/xdr.h>
94 #include <afs/afsint.h>
95 #include "nfs.h"
96 #include <afs/afssyscalls.h>
97 #include "viceinode.h"
98 #include <sys/stat.h>
99 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
100 #include <sys/ino.h>
101 #endif
102 #ifdef AFS_PTHREAD_ENV
103 #include <assert.h>
104 #else /* AFS_PTHREAD_ENV */
105 #include <afs/assert.h>
106 #endif /* AFS_PTHREAD_ENV */
107 #if defined(AFS_HPUX101_ENV)
108 #include <unistd.h>
109 #endif
110 #include "lock.h"
111 #include "ihandle.h"
112 #include "vnode.h"
113 #include "volume.h"
114 #include "volinodes.h"
115 #include "partition.h"
116 #include "fssync.h"
117 #include "volume_inline.h"
118
119 /*@+fcnmacros +macrofcndecl@*/
120 #ifdef O_LARGEFILE
121 #ifdef S_SPLINT_S
122 extern off64_t afs_lseek(int FD, off64_t O, int F);
123 #endif /*S_SPLINT_S */
124 #define afs_lseek(FD, O, F)   lseek64(FD, (off64_t) (O), F)
125 #define afs_stat      stat64
126 #define afs_fstat     fstat64
127 #define afs_open      open64
128 #define afs_fopen     fopen64
129 #else /* !O_LARGEFILE */
130 #ifdef S_SPLINT_S
131 extern off_t afs_lseek(int FD, off_t O, int F);
132 #endif /*S_SPLINT_S */
133 #define afs_lseek(FD, O, F)   lseek(FD, (off_t) (O), F)
134 #define afs_stat      stat
135 #define afs_fstat     fstat
136 #define afs_open      open
137 #define afs_fopen     fopen
138 #endif /* !O_LARGEFILE */
139 /*@=fcnmacros =macrofcndecl@*/
140
141 /* Notice:  parts of this module have been cribbed from vfsck.c */
142
143 #define ROOTINODE       2
144 static char *partition;
145 int Testing=0;
146 int pfd;
147
148 #ifdef  AFS_AIX32_ENV
149 #include <jfs/filsys.h>
150
151 #ifndef FSBSIZE
152 #define FSBSIZE         (4096)  /* filesystem block size        */
153 #define FSBSHIFT        (12)    /* log2(FSBSIZE)                */
154 #define FSBMASK         (FSBSIZE - 1)   /* FSBSIZE mask                 */
155
156 #define MIN_FSIZE       DISKMAP_B       /* minimum fs size (FSblocks)   */
157 #define LAST_RSVD_I     15      /* last reserved inode          */
158 #endif
159
160 #ifndef INOPB
161 /*
162  * This will hopefully eventually make it into the system include files
163  */
164 #define INOPB           (FSBSIZE / sizeof (struct dinode))
165 #endif
166
167 #ifdef AFS_AIX41_ENV
168 int fragsize;
169 int iagsize;
170 int ag512;
171 int agblocks;
172 #endif /* AFS_AIX41_ENV */
173
174 /*
175  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
176  XX This was lifted from some `com/cmd/fs/fshlpr_aix3/Fs.h', which indicated X
177  XX a longing to see it make it into a readily accessible include file. XXXXXX
178  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
179  *
180  * itoo - inode number to offset within disk block
181  */
182 #undef itoo
183 #define itoo(x)         (int) ((unsigned)(x) % INOPB)
184
185 int Bsize = FSBSIZE;            /* block size for this system                   */
186 daddr_t fmax;                   /* total number of blocks n file system         */
187 ino_t imax, inum;               /* total number of I-nodes in file system       */
188
189 static struct superblock fs;
190 struct dinode *ginode();
191
192
193 int
194 ListViceInodes(char *devname, char *mountedOn, FILE *inodeFile,
195                int (*judgeInode) (), afs_uint32 judgeParam, int *forcep, int forceR,
196                char *wpath, void *rock)
197 {
198     char dev[50], rdev[51];
199     struct stat status;
200     struct dinode *p;
201     struct ViceInodeInfo info;
202     struct stat root_inode;
203     int ninodes = 0, err = 0;
204
205     pfd = -1;                   /* initialize so we don't close on error output below. */
206     *forcep = 0;
207     sync();
208     sleep(1);                   /* simulate operator    */
209     sync();
210     sleep(1);
211     sync();
212     sleep(1);
213
214     partition = mountedOn;
215     sprintf(dev, "/dev/%s", devname);
216     sprintf(rdev, "/dev/r%s", devname);
217
218     if (stat(mountedOn, &root_inode) < 0) {
219         Log("cannot stat: %s\n", mountedOn);
220         return -1;
221     }
222
223     if (root_inode.st_ino != ROOTDIR_I) {
224         Log("%s is not root of a filesystem\n", mountedOn);
225         return -1;
226     }
227
228
229     /*
230      * done with the superblock, now try to read the raw device.
231      */
232     if (ReadSuper(&fs, dev) < 0)
233         return -1;
234
235     switch (fs.s_fmod) {
236     default:
237     case FM_CLEAN:              /* clean and unmounted                  */
238         Log("Most peculiar - Super blk in FM_CLEAN state!\n");
239         goto out;
240     case FM_MOUNT:              /* mounted cleanly                      */
241         break;
242
243     case FM_MDIRTY:             /* dirty when mounted or commit fail    */
244     case FM_LOGREDO:            /* log redo attempted but failed        */
245         Log("File system %s is in a bad state.\n", rdev);
246         Log("Call your IBM representative.\n");
247         return -1;
248     }
249 #ifdef AFS_AIX42_ENV
250     if (IsBigFilesFileSystem(&fs, (char *)0)) {
251         Log("%s is a big files filesystem, can't salvage.\n", mountedOn);
252         return -1;
253     }
254 #else
255     if (strncmp(fs.s_magic, fsv3magic, strlen(fsv3magic)) != 0) {
256 #ifdef  AFS_AIX41_ENV
257         if ((strncmp(fs.s_magic, fsv3pmagic, strlen(fsv3pmagic)) != 0)
258             || (fs.s_version != fsv3pvers)) {
259             Log("Super block doesn't have the problem magic (%s vs v3magic %s v3pmagic %s)\n", fs.s_magic, fsv3magic, fsv3pmagic);
260             return -1;
261         }
262 #else
263         Log("Super block doesn't have the problem magic (%s vs v3magic %s)\n",
264             fs.s_magic, fsv3magic);
265         return -1;
266 #endif
267     }
268 #endif
269
270 #ifdef AFS_AIX41_ENV
271     fragsize = (fs.s_fragsize) ? fs.s_fragsize : FSBSIZE;
272     iagsize = (fs.s_iagsize) ? fs.s_iagsize : fs.s_agsize;
273     ag512 = fragsize * fs.s_agsize / 512;
274     agblocks = fragsize * fs.s_agsize >> BSHIFT;
275 #endif /* AFS_AIX41_ENV */
276
277     fmax = fs.s_fsize / (FSBSIZE / 512);        /* first invalid blk num */
278
279     pfd = afs_open(rdev, O_RDONLY);
280     if (pfd < 0) {
281         Log("Unable to open `%s' inode for reading\n", rdev);
282         return -1;
283     }
284
285     /*
286      * calculate the maximum number of inodes possible
287      */
288 #ifdef AFS_AIX41_ENV
289     imax = iagsize * (fs.s_fsize / ag512) - 1;
290 #else /* AFS_AIX41_ENV */
291     imax =
292         ((fmax / fs.s_agsize +
293           ((fmax % fs.s_agsize) >= fs.s_agsize / INOPB ? 1 : 0))
294          * fs.s_agsize) - 1;
295 #endif /* AFS_AIX41_ENV */
296
297     /*
298      * check for "FORCESALVAGE" equivalent:
299      *      LAST_RSVD_I is a vice inode, with dead beef, and
300      *      di_nlink == 2 to indicate the FORCE.
301      */
302     assert(p = ginode(LAST_RSVD_I));
303
304     if (p->di_vicemagic == VICEMAGIC && p->di_vicep1 == 0xdeadbeef
305         && p->di_nlink == 2) {
306         *forcep = 1;
307         idec(root_inode.st_dev, LAST_RSVD_I, 0xdeadbeef);
308     }
309
310     for (inum = LAST_RSVD_I + 1; inum <= imax; ++inum) {
311         if ((p = ginode(inum)) == NULL || p->di_vicemagic != VICEMAGIC
312             || (p->di_mode & IFMT) != IFREG)
313             continue;
314
315         info.inodeNumber = inum;
316         info.byteCount = p->di_size;
317         info.linkCount = p->di_nlink;
318         info.u.param[0] = p->di_vicep1;
319         info.u.param[1] = p->di_vicep2;
320         info.u.param[2] = p->di_vicep3;
321         info.u.param[3] = p->di_vicep4;
322
323         if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
324             continue;
325
326         if (inodeFile) {
327             if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
328                 Log("Error writing inode file for partition %s\n", partition);
329                 goto out;
330             }
331         }
332         ++ninodes;
333     }
334
335     if (inodeFile) {
336         if (fflush(inodeFile) == EOF) {
337             Log("Unable to successfully flush inode file for %s\n", partition);
338             err = -2;
339             goto out1;
340         }
341         if (fsync(fileno(inodeFile)) == -1) {
342             Log("Unable to successfully fsync inode file for %s\n", partition);
343             err = -2;
344             goto out1;
345         }
346
347         /*
348          * Paranoia:  check that the file is really the right size
349          */
350         if (fstat(fileno(inodeFile), &status) == -1) {
351             Log("Unable to successfully stat inode file for %s\n", partition);
352             err = -2;
353             goto out1;
354         }
355         if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
356             Log("Wrong size (%d instead of %d) in inode file for %s\n",
357                 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
358                 partition);
359             err = -2;
360             goto out1;
361         }
362     }
363     close(pfd);
364     return 0;
365
366   out:
367     err = -1;
368   out1:
369     if (pfd >= 0)
370         close(pfd);
371
372     return err;
373 }
374
375 /* Read in the superblock for devName */
376 int
377 ReadSuper(struct superblock *fs, char *devName)
378 {
379     int pfd;
380
381     pfd = afs_open(devName, O_RDONLY);
382     if (pfd < 0) {
383         Log("Unable to open inode on %s for reading superblock.\n", devName);
384         return -1;
385     }
386
387     if (bread(pfd, fs, SUPER_B, sizeof(struct superblock)) < 0) {
388         Log("Unable to read superblock on %s.\n", devName);
389         return -1;
390     }
391     close(pfd);
392     return (0);
393 }
394
395 #ifdef AFS_AIX42_ENV
396 /* IsBigFilesFileSystem returns 1 if it's a big files filesystem, 0 otherwise. */
397 int
398 IsBigFilesFileSystem(struct superblock *sb)
399 {
400     if ((strncmp(sb->s_magic, fsv3pmagic, 4) == 0)
401         && (sb->s_version == fsbigfile)
402         && (sb->s_bigexp))
403         return 1;
404     else
405         return 0;
406 }
407 #endif
408
409 struct dinode *
410 ginode(inum)
411 {
412     int ag;
413     daddr_t pblk;
414     struct dinode *dp;
415     static char buf[FSBSIZE];
416     static daddr_t last_blk = -1;
417
418 #ifdef AFS_AIX41_ENV
419     ag = inum / iagsize;
420     pblk =
421         (ag ==
422          0) ? INODES_B + inum / INOPB : ag * agblocks + (inum -
423                                                          ag * iagsize) /
424         INOPB;
425 #else /* AFS_AIX41_ENV */
426     ag = inum / fs.s_agsize;
427     pblk =
428         (ag ==
429          0) ? INODES_B + inum / INOPB : ag * fs.s_agsize + (inum -
430                                                             ag *
431                                                             fs.s_agsize) /
432         INOPB;
433 #endif /* AFS_AIX41_ENV */
434
435     if (last_blk != pblk) {
436         if (bread(pfd, buf, pblk, sizeof(buf)) < 0) {
437             last_blk = -1;
438             return 0;
439         }
440         last_blk = pblk;
441     }
442
443     dp = (struct dinode *)buf;
444     dp += itoo(inum);
445     return (dp);
446 }
447
448 #else /* !AFS_AIX31_ENV       */
449
450 #if defined(AFS_SGI_ENV)
451
452 /* libefs.h includes <assert.h>, which we don't want */
453 #define __ASSERT_H__
454
455 #ifdef AFS_SGI_XFS_IOPS_ENV
456 #include <dirent.h>
457 #include <afs/xfsattrs.h>
458 /* xfs_ListViceInodes
459  *
460  * xfs_ListViceInodes verifies and correct the XFS namespace as it collects
461  * the inode information. The name is required for the idec operation to work.
462  * Steps 2 and 3 below are for the AFS_XFS_NAME_VERS == 1. If the name space
463  * changes, the algorithm will need to change.
464  * 1) If the parent inode number does not match the directory's inod number,
465  *    change it in the attribute.
466  * 2) If the unqifier in the attribute does not match the name, rename the
467  *    file. This is done by doing an exclusive open, incrementing the tag
468  *    number until a file can be created. If the tag changes, then the
469  *    attribute will need updating.
470  * 3) If the tag in the attribute does not match the name, change the
471  *    attribute.
472  * 4) Verify uid = RW volume id and gid = XFS_VICEMAGIC.
473  *
474  */
475
476 /* xfs_VerifyInode
477  *
478  * Does the verifications listed above.
479  * We can't change the names until the readdir is complete, so we set the
480  * rename flag if the file needs renaming.
481  */
482 int
483 xfs_VerifyInode(char *dir, uint64_t pino, char *name, i_list_inode_t * info,
484                 int *rename)
485 {
486     char path[1024];
487     int vno;
488     int update_pino = 0;
489     int update_tag = 0;
490     int update_chown = 0;
491     int retCode = 0;
492     char tmpName[32];
493     b64_string_t stmp;
494     int tag;
495     afs_ino_str_t stmp;
496
497     *rename = 0;
498     (void)sprintf(path, "%s/%s", dir, name);
499     /* Verify uid and gid fields */
500     if (info->ili_magic != XFS_VICEMAGIC) {
501         Log("%s  magic for %s/%s (inode %s) from %d to %d\n",
502             Testing ? "Would have changed" : "Changing", dir, name,
503             PrintInode(stmp, info->ili_info.inodeNumber), info->ili_magic,
504             XFS_VICEMAGIC);
505         if (!Testing)
506             update_chown = 1;
507     }
508
509     vno = info->ili_info.param[0];
510     if (info->ili_vno != AFS_XFS_VNO_CLIP(vno)) {
511         Log("%s volume id for %s/%s (inode %s) from %d to %d\n",
512             Testing ? "Would have changed" : "Changing", dir, name,
513             PrintInode(stmp, info->ili_info.inodeNumber), info->ili_vno,
514             AFS_XFS_VNO_CLIP(vno));
515         if (!Testing)
516             update_chown = 1;
517     }
518
519     if (update_chown) {
520         if (chown(path, AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC) < 0) {
521             Log("Can't chown %s to uid=%d, gid=0x%x\n", path,
522                 AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC);
523             retCode = -1;
524         }
525     }
526
527     /* Check Parent inode number. */
528     if (info->ili_pino != pino) {
529         afs_ino_str_t sino, sipino, spino;
530         (void)PrintInode(sino, info->ili_info.inodeNumber);
531         (void)PrintInode(sipino, info->ili_pino);
532         (void)PrintInode(spino, pino);
533         Log("%s parent ino for %s (inode %s) from %s to %s.\n",
534             Testing ? "Would have changed" : "Changing", path, sino, sipino,
535             spino);
536         if (!Testing)
537             update_pino = 1;
538     }
539
540     /* Verify the file name. */
541     (void)strcpy(tmpName, ".");
542     (void)strcat(tmpName, int_to_base64(stmp, info->ili_info.param[2]));
543     if (strncmp(name, tmpName, strlen(tmpName))) {
544         Log("%s name %s (inode %s) in directory %s, unique=%d, tag=%d\n",
545             Testing ? "Would have returned bad" : "Bad", name,
546             PrintInode(stmp, info->ili_info.inodeNumber), dir,
547             info->ili_info.param[2], info->ili_tag);
548         if (!Testing)
549             *rename = 1;
550     }
551
552     if (!*rename) {
553         /* update the tag? */
554         (void)strcat(tmpName, ".");
555         (void)strcat(tmpName, int_to_base64(stmp, info->ili_tag));
556         if (strcmp(name, tmpName)) {
557             char *p;
558             (void)strcpy(tmpName, name);
559             p = strchr(tmpName + 1, '.');
560             if (!p) {
561                 Log("No tag found on name %s (inode %s)in directory, %s.\n",
562                     name, PrintInode(stmp, info->ili_info.inodeNumber), dir,
563                     Testing ? "would have renamed" : "will rename");
564                 if (!Testing)
565                     *rename = 1;
566             } else {
567                 tag = base64_to_int(p + 1);
568                 Log("%s the tag for %s (inode %s) from %d to %d.\n",
569                     Testing ? "Would have changed" : "Will change", path,
570                     PrintInode(stmp, info->ili_info.inodeNumber), dir, tag,
571                     info->ili_tag);
572                 if (!Testing)
573                     update_tag = 1;
574             }
575         }
576     }
577
578     if (update_pino || update_tag) {
579         afs_xfs_attr_t attrs;
580         int length;
581
582         length = SIZEOF_XFS_ATTR_T;
583         if (attr_get(path, AFS_XFS_ATTR, (char *)&attrs, &length, ATTR_ROOT) <
584             0) {
585             Log("Can't get AFS attribute for %s\n", path);
586             return -1;
587         }
588         if (update_pino)
589             attrs.at_pino = pino;
590         if (update_tag)
591             attrs.at_tag = tag;
592         if (attr_set
593             (path, AFS_XFS_ATTR, (char *)&attrs, length,
594              ATTR_ROOT | ATTR_REPLACE) < 0) {
595             Log("Can't set AFS attribute into %s\n", path);
596             retCode = -1;
597         }
598     }
599
600     return retCode;
601 }
602
603 typedef struct {
604     int uniq;
605     char name[28];
606 } xfs_Rename_t;
607
608 int
609 xfs_RenameFiles(char *dir, xfs_Rename_t * renames, int n_renames)
610 {
611     int i, j;
612     char opath[128], nbase[128], npath[128];
613     afs_xfs_attr_t attrs;
614     int length = SIZEOF_XFS_ATTR_T;
615     b64_string_t stmp;
616     int tag;
617     int fd;
618
619     for (i = 0; i < n_renames; i++) {
620         (void)sprintf(opath, "%s/%s", dir, renames[i].name);
621         (void)sprintf(nbase, "%s/.%s", dir,
622                       int_to_base64(stmp, renames[i].uniq));
623         for (tag = 2, j = 0; j < 64; tag++, j++) {
624             (void)sprintf(npath, "%s.%s", nbase, int_to_base64(stmp, tag));
625             fd = afs_open(npath, O_CREAT | O_EXCL | O_RDWR, 0);
626             if (fd > 0) {
627                 close(fd);
628                 break;
629             }
630         }
631         if (j != 64) {
632             Log("Can't find a new name for %s\n", opath);
633             return -1;
634         }
635         if (rename(opath, npath) < 0) {
636             Log("Can't rename %s to %s\n", opath, npath);
637             return -1;
638         }
639         Log("Renamed %s to %s\n", opath, npath);
640         return 0;
641     }
642 }
643
644
645 int
646 xfs_ListViceInodes(char *devname, char *mountedOn, FILE *inodeFile,
647                    int (*judgeInode) (), afs_uint32 judgeParam, int *forcep,
648                    int forceR, char *wpath, void *rock)
649 {
650     i_list_inode_t info;
651     int info_size = sizeof(i_list_inode_t);
652     int fd;
653     DIR *top_dirp;
654     dirent64_t *top_direntp;
655     DIR *vol_dirp;
656     dirent64_t *vol_direntp;
657     struct stat64 sdirbuf;
658     struct stat64 sfilebuf;
659     afs_xfs_attr_t attrs;
660     afs_xfs_dattr_t dattrs;
661     int length;
662     char vol_dirname[1024];
663     int ninodes = 0;
664     int code = 0;
665     xfs_Rename_t *renames = (xfs_Rename_t *) 0;
666     int rename;
667 #define N_RENAME_STEP 64
668     int n_renames = 0;
669     int n_avail = 0;
670     uint64_t pino;
671     struct stat status;
672     int errors = 0;
673
674     *forcep = 0;
675
676     if (stat64(mountedOn, &sdirbuf) < 0) {
677         perror("xfs_ListViceInodes: stat64");
678         return -1;
679     }
680
681     if ((top_dirp = opendir(mountedOn)) == NULL) {
682         Log("Can't open directory %s to read inodes.\n", mountedOn);
683         return -1;
684     }
685
686     while (top_direntp = readdir64(top_dirp)) {
687         /* Only descend directories with the AFSDIR attribute set.
688          * Could also verify the contents of the atribute, but currently
689          * they are not used.
690          * Performance could be improved for single volume salvages by
691          * only going through the directory containing the volume's inodes.
692          * But I'm being complete as a first pass.
693          */
694         (void)sprintf(vol_dirname, "%s/%s", mountedOn, top_direntp->d_name);
695         length = SIZEOF_XFS_DATTR_T;
696         if (attr_get
697             (vol_dirname, AFS_XFS_DATTR, (char *)&dattrs, &length, ATTR_ROOT))
698             continue;
699
700         if ((vol_dirp = opendir(vol_dirname)) == NULL) {
701             if (errno == ENOTDIR)
702                 continue;
703             Log("Can't open directory %s to read inodes.\n", vol_dirname);
704             goto err1_exit;
705         }
706
707         pino = top_direntp->d_ino;
708         n_renames = 0;
709         while (vol_direntp = readdir64(vol_dirp)) {
710             if (vol_direntp->d_name[1] == '\0'
711                 || vol_direntp->d_name[1] == '.')
712                 continue;
713
714             info.ili_version = AFS_XFS_ILI_VERSION;
715             info_size = sizeof(i_list_inode_t);
716             code =
717                 ilistinode64(sdirbuf.st_dev, vol_direntp->d_ino, &info,
718                              &info_size);
719             if (code) {
720                 /* Where possible, give more explicit messages. */
721                 switch (errno) {
722                 case ENXIO:
723                 case ENOSYS:
724                     Log("%s (device id %d) is not on an XFS filesystem.\n",
725                         vol_dirname, sdirbuf.st_dev);
726                     goto err1_exit;
727                     break;
728                 case EINVAL:
729                 case E2BIG:
730                     if (info_size != sizeof(i_list_inode_t)
731                         || info.ili_version != AFS_XFS_ILI_VERSION) {
732                         Log("Version skew between kernel and salvager.\n");
733                         goto err1_exit;
734                     }
735                     break;
736                 }
737                 /* Continue, so we collect all the errors in the first pass. */
738                 Log("Error listing inode named %s/%s: %s\n", vol_dirname,
739                     vol_direntp->d_name, strerror(errno));
740                 errors++;
741                 continue;
742             }
743
744             if (info.ili_attr_version != AFS_XFS_ATTR_VERS) {
745                 Log("Unrecognized XFS attribute version %d in %s/%s. Upgrade salvager\n", info.ili_attr_version, vol_dirname, vol_direntp->d_name);
746                 goto err1_exit;
747             }
748
749             if (judgeInode && (*judgeInode) (&info.ili_info, judgeParam, rock) == 0)
750                 continue;
751
752             rename = 0;
753             if (xfs_VerifyInode
754                 (vol_dirname, pino, vol_direntp->d_name, &info,
755                  &rename) < 0) {
756                 errors++;
757             }
758
759             if (rename) {
760                 /* Add this name to the list of items to rename. */
761                 if (n_renames >= n_avail) {
762                     n_avail += N_RENAME_STEP;
763                     if (n_avail == N_RENAME_STEP)
764                         renames = (xfs_Rename_t *)
765                             malloc(n_avail * sizeof(xfs_Rename_t));
766                     else
767                         renames = (xfs_Rename_t *)
768                             realloc((char *)renames,
769                                     n_avail * sizeof(xfs_Rename_t));
770                     if (!renames) {
771                         Log("Can't %salloc %lu bytes for rename list.\n",
772                             (n_avail == N_RENAME_STEP) ? "m" : "re",
773                             n_avail * sizeof(xfs_Rename_t));
774                         goto err1_exit;
775                     }
776                 }
777                 (void)strcpy(renames[n_renames].name, vol_direntp->d_name);
778                 renames[n_renames].uniq = info.ili_info.param[2];
779                 n_renames++;
780             }
781
782             if (inodeFile) {
783                 if (fwrite
784                     (&info.ili_info, sizeof(vice_inode_info_t), 1, inodeFile)
785                     != 1) {
786                     Log("Error writing inode file for partition %s\n", mountedOn);
787                     goto err1_exit;
788                 }
789             }
790             ninodes++;
791
792         }                       /* end while vol_direntp */
793
794         closedir(vol_dirp);
795         vol_dirp = (DIR *) 0;
796         if (n_renames) {
797             Log("Renaming files.\n");
798             if (xfs_RenameFiles(vol_dirname, renames, n_renames) < 0) {
799                 goto err1_exit;
800             }
801         }
802     }
803
804     closedir(top_dirp);
805     if (renames)
806         free((char *)renames);
807     if (inodeFile) {
808         if (fflush(inodeFile) == EOF) {
809             ("Unable to successfully flush inode file for %s\n", mountedOn);
810             return errors ? -1 : -2;
811         }
812         if (fsync(fileno(inodeFile)) == -1) {
813             Log("Unable to successfully fsync inode file for %s\n", mountedOn);
814             return errors ? -1 : -2;
815         }
816         /*
817          * Paranoia:  check that the file is really the right size
818          */
819         if (fstat(fileno(inodeFile), &status) == -1) {
820             Log("Unable to successfully stat inode file for %s\n", partition);
821             return errors ? -1 : -2;
822         }
823         if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
824             Log("Wrong size (%d instead of %d) in inode file for %s\n",
825                 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
826                 partition);
827             return errors ? -1 : -2;
828         }
829     }
830
831     if (errors) {
832         Log("Errors encontered listing inodes, not salvaging partition.\n");
833         return -1;
834     }
835
836     return 0;
837
838   err1_exit:
839     if (vol_dirp)
840         closedir(vol_dirp);
841     if (top_dirp)
842         closedir(top_dirp);
843     if (renames)
844         free((char *)renames);
845     return -1;
846 }
847
848 #endif
849
850 int
851 ListViceInodes(char *devname, char *mountedOn, FILE *inodeFile,
852                int (*judgeInode) (), afs_uint32 judgeParam, int *forcep, int forceR,
853                char *wpath, void *rock)
854 {
855     char dev[50], rdev[51];
856     struct stat status;
857     struct efs_dinode *p;
858     struct ViceInodeInfo info;
859     struct stat root_inode;
860     int ninodes = 0, err = 0;
861     struct efs_dinode *dinodeBuf = NULL;
862     int last_cgno;
863     ino_t imax, inum;           /* total number of I-nodes in file system */
864
865     *forcep = 0;
866     sync();
867     sleep(1);                   /* simulate operator    */
868     sync();
869     sleep(1);
870     sync();
871     sleep(1);
872
873     if (stat(mountedOn, &root_inode) < 0) {
874         Log("cannot stat: %s\n", mountedOn);
875         return -1;
876     }
877 #ifdef AFS_SGI_XFS_IOPS_ENV
878     if (!strcmp("xfs", root_inode.st_fstype)) {
879         return xfs_ListViceInodes(devname, mountedOn, inodeFile, judgeInode,
880                                   judgeParam, forcep, forceR, wpath, rock);
881     } else
882 #endif
883     {
884         Log("%s is not root of a filesystem\n", mountedOn);
885         return -1;
886     }
887 }
888
889 #else /* AFS_SGI_ENV */
890
891 #ifdef AFS_HPUX_ENV
892 #define SPERB   (MAXBSIZE / sizeof(short))
893 #define MAXNINDIR (MAXBSIZE / sizeof(daddr_t))
894
895 struct bufarea {
896     struct bufarea *b_next;     /* must be first */
897     daddr_t b_bno;
898     int b_size;
899     union {
900         char b_buf[MAXBSIZE];   /* buffer space */
901         short b_lnks[SPERB];    /* link counts */
902         daddr_t b_indir[MAXNINDIR];     /* indirect block */
903         struct fs b_fs;         /* super block */
904         struct cg b_cg;         /* cylinder group */
905     } b_un;
906     char b_dirty;
907 };
908 typedef struct bufarea BUFAREA;
909
910 BUFAREA sblk;
911 #define sblock sblk.b_un.b_fs
912 #endif /* AFS_HPUX_ENV */
913
914 extern char *afs_rawname();
915 int
916 ListViceInodes(char *devname, char *mountedOn, FILE *inodeFile,
917                int (*judgeInode) (), afs_uint32 judgeParam, int *forcep, int forceR,
918                char *wpath, void *rock)
919 {
920     union {
921 #ifdef  AFS_AIX_ENV
922         struct filsys fs;
923         char block[BSIZE];
924 #else                           /* !AFS_AIX_ENV */
925         struct fs fs;
926         char block[SBSIZE];
927 #endif
928     } super;
929     int i, c, e, bufsize, code, err = 0;
930     char dev[50], rdev[100], err1[512], *ptr1;
931     struct dinode *inodes = NULL, *einodes, *dptr;
932     struct stat status;
933     int ninodes = 0;
934     struct dinode *p;
935     struct ViceInodeInfo info;
936
937     *forcep = 0;
938     partition = mountedOn;
939     sprintf(rdev, "%s/%s", wpath, devname);
940     ptr1 = afs_rawname(rdev);
941     strcpy(rdev, ptr1);
942
943     sync();
944     /* Bletch:  this is terrible;  is there a better way to do this? Does this work? vfsck doesn't even sleep!! */
945 #ifdef  AFS_AIX_ENV
946     sleep(5);                   /* Trying a smaller one for aix */
947 #else
948     sleep(10);
949 #endif
950
951     pfd = afs_open(rdev, O_RDONLY);
952     if (pfd <= 0) {
953         sprintf(err1, "Could not open device %s to get inode list\n", rdev);
954         perror(err1);
955         return -1;
956     }
957 #ifdef  AFS_AIX_ENV
958     if (bread(pfd, (char *)&super.fs, SUPERB, sizeof super.fs) == -1) {
959 #else
960 #ifdef AFS_HPUX_ENV
961     if (bread(pfd, (char *)&sblock, SBLOCK, SBSIZE) == -1) {
962 #else
963     if (bread(pfd, super.block, SBLOCK, SBSIZE) == -1) {
964 #endif /* AFS_HPUX_ENV */
965 #endif
966         Log("Unable to read superblock, partition %s\n", partition);
967         goto out;
968     }
969
970 #ifdef  AFS_AIX_ENV
971     /*
972      * char *FSlabel(), *fslabel=0;
973      * fslabel = FSlabel(&super.fs);
974      */
975     if (super.fs.s_bsize == 0)
976         super.fs.s_bsize = 512;
977     if (super.fs.s_bsize != BSIZE) {
978         Log("SuperBlk: Cluster size not %d; run vfsck\n", BSIZE);
979         goto out;
980     }
981     fmax = super.fs.s_fsize;    /* first invalid blk num */
982     imax = ((ino_t) super.fs.s_isize - (SUPERB + 1)) * INOPB;
983     if (imax == 0) {
984         Log("Size check: imax==0!\n");
985         goto out;
986     }
987     if (GetAuxInodeFile(partition, &status) == 0) {
988         Log("Can't access Aux inode file for partition %s, aborting\n",
989             partition);
990         goto out;
991     }
992     for (inum = 1; inum <= imax; inum++) {
993         struct dauxinode *auxp;
994         if ((auxp = IsAfsInode(inum)) == NULL) {
995             /* Not an afs inode, keep going */
996             continue;
997         }
998         if ((p = ginode(inum)) == NULL)
999             continue;
1000         /* deleted/non-existent inode when di_mode == 0 */
1001         if (!p->di_mode)
1002             continue;
1003         info.inodeNumber = (int)inum;
1004         info.byteCount = p->di_size;
1005         info.linkCount = p->di_nlink;
1006         info.u.param[0] = auxp->aux_param1;
1007         info.u.param[1] = auxp->aux_param2;
1008         info.u.param[2] = auxp->aux_param3;
1009         info.u.param[3] = auxp->aux_param4;
1010         if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
1011             continue;
1012         if (inodeFile) {
1013             if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
1014                 Log("Error writing inode file for partition %s\n", partition);
1015                 goto out;
1016             }
1017         }
1018         ninodes++;
1019     }
1020 #else
1021     /*
1022      * run a few consistency checks of the superblock
1023      * (Cribbed from vfsck)
1024      */
1025 #ifdef AFS_HPUX_ENV
1026 #if defined(FD_FSMAGIC)
1027     if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)
1028         && (sblock.fs_magic != FD_FSMAGIC)
1029 #if     defined(AFS_HPUX101_ENV)
1030         && (sblock.fs_magic != FD_FSMAGIC_2)
1031 #endif
1032         ) {
1033 #else
1034     if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)) {
1035 #endif
1036         Log("There's something wrong with the superblock for partition %s; bad magic (%d) run vfsck\n", partition, sblock.fs_magic);
1037         goto out;
1038     }
1039     if (sblock.fs_ncg < 1) {
1040         Log("There's something wrong with the superblock for partition %s; NCG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_ncg);
1041         goto out;
1042     }
1043     if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG) {
1044         Log("There's something wrong with the superblock for partition %s; CPG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_cpg);
1045         goto out;
1046     }
1047     if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl
1048         || (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
1049         Log("There's something wrong with the superblock for partition %s; NCYL LESS THAN NCG*CPG run vfsck\n", partition);
1050         goto out;
1051     }
1052     if (sblock.fs_sbsize > SBSIZE) {
1053         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);
1054         goto out;
1055     }
1056 #else
1057     if ((super.fs.fs_magic != FS_MAGIC)
1058         || (super.fs.fs_ncg < 1)
1059 #if     defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1060         || (super.fs.fs_cpg < 1)
1061 #else
1062         || (super.fs.fs_cpg < 1 || super.fs.fs_cpg > MAXCPG)
1063 #endif
1064         || (super.fs.fs_ncg * super.fs.fs_cpg < super.fs.fs_ncyl
1065             || (super.fs.fs_ncg - 1) * super.fs.fs_cpg >= super.fs.fs_ncyl)
1066         || (super.fs.fs_sbsize > SBSIZE)) {
1067         Log("There's something wrong with the superblock for partition %s; run vfsck\n", partition);
1068         goto out;
1069     }
1070 #endif /* AFS_HPUX_ENV */
1071
1072 #ifdef AFS_HPUX_ENV
1073     bufsize = sblock.fs_ipg * sizeof(struct dinode);
1074 #else
1075     bufsize = super.fs.fs_ipg * sizeof(struct dinode);
1076 #endif /* AFS_HPUX_ENV */
1077     inodes = (struct dinode *)malloc(bufsize);
1078     einodes = (struct dinode *)(((char *)inodes) + bufsize);
1079     if (inodes == NULL) {
1080         Log("Unable to allocate enough memory to scan inodes; help!\n");
1081         goto out;
1082     }
1083     Log("Scanning inodes on device %s...\n", rdev);
1084 #ifdef AFS_HPUX_ENV
1085     for (c = 0; c < sblock.fs_ncg; c++) {
1086         i = c * sblock.fs_ipg;
1087         e = i + sblock.fs_ipg;
1088 #if     defined(AFS_HPUX102_ENV)
1089         if (afs_lseek(pfd, dbtoo(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1090             -1) {
1091 #else
1092         if (afs_lseek(pfd, dbtob(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1093             -1) {
1094 #endif
1095 #else
1096     for (c = 0; c < super.fs.fs_ncg; c++) {
1097         daddr_t dblk1;
1098 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1099         daddr_t f1;
1100 #if defined(AFS_DARWIN_ENV)
1101 #define offset_t off_t
1102 #define llseek lseek
1103 #endif
1104         offset_t off;
1105 #endif /* AFS_SUN5_ENV */
1106         i = c * super.fs.fs_ipg;
1107         e = i + super.fs.fs_ipg;
1108 #ifdef  AFS_OSF_ENV
1109         dblk1 = fsbtodb(&super.fs, itod(&super.fs, i));
1110         if (afs_lseek(pfd, (off_t) ((off_t) dblk1 * DEV_BSIZE), L_SET) == -1) {
1111 #else
1112 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1113         f1 = fsbtodb(&super.fs, itod(&super.fs, i));
1114         off = (offset_t) f1 << DEV_BSHIFT;
1115         if (llseek(pfd, off, L_SET) == -1) {
1116 #else
1117         if (afs_lseek(pfd, dbtob(fsbtodb(&super.fs, itod(&super.fs, i))), L_SET)
1118             == -1) {
1119 #endif /* AFS_SUN5_ENV */
1120 #endif /* AFS_OSF_ENV */
1121 #endif /* AFS_HPUX_ENV */
1122             Log("Error reading inodes for partition %s; run vfsck\n",
1123                 partition);
1124             goto out;
1125         }
1126         while (i < e) {
1127             if (!forceR) {
1128                 if (read(pfd, inodes, bufsize) != bufsize) {
1129                     Log("Error reading inodes for partition %s; run vfsck\n",
1130                         partition);
1131                     goto out;
1132                 }
1133             } else {
1134                 int bj, bk;
1135                 dptr = inodes;
1136                 for (bj = bk = 0; bj < bufsize; bj = bj + 512, bk++) {
1137                     if ((code = read(pfd, dptr, 512)) != 512) {
1138                         Log("Error reading inode %d? for partition %s (errno = %d); run vfsck\n", bk + i, partition, errno);
1139                         if (afs_lseek(pfd, 512, L_SET) == -1) {
1140                             Log("Lseek failed\n");
1141                             goto out;
1142                         }
1143                         dptr->di_mode = 0;
1144                         dptr++;
1145                         dptr->di_mode = 0;
1146                         dptr++;
1147                         dptr->di_mode = 0;
1148                         dptr++;
1149                         dptr->di_mode = 0;
1150                         dptr++;
1151                     } else
1152                         dptr += 4;
1153                 }
1154             }
1155             for (p = inodes; p < einodes && i < e; i++, p++) {
1156 #ifdef notdef
1157                 Log("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1158                     i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1159                     p->di_size, p->di_nlink);
1160                 printf
1161                     ("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1162                      i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1163                      p->di_size, p->di_nlink);
1164 #endif
1165 #ifdef AFS_OSF_ENV
1166 #ifdef AFS_3DISPARES
1167                 /* Check to see if this inode is a pre-"OSF1 4.0D" inode */
1168                 if ((p->di_uid || p->di_gid)
1169                     && !(p->di_flags & (IC_XUID | IC_XGID))) {
1170                     Log("Found unconverted inode %d: Use 'fs_conv_dux40D convert' on partition %s\n", i, partition);
1171                     goto out;
1172                 }
1173 #else
1174                 assert(0);      /* define AFS_3DISPARES in param.h */
1175 #endif
1176 #endif
1177 #if     defined(AFS_SUN56_ENV)
1178                 /* if this is a pre-sol2.6 unconverted inode, bail out */
1179                 {
1180                     afs_uint32 p1, p2, p3, p4;
1181                     int p5;
1182                     quad *q;
1183
1184                     q = (quad *) & (p->di_ic.ic_lsize);
1185                     p1 = p->di_gen;
1186                     p2 = p->di_ic.ic_flags;
1187                     p3 = q->val[0];
1188                     p4 = p->di_ic.ic_uid;
1189                     p5 = p->di_ic.ic_gid;
1190
1191                     if ((p2 || p3) && !p4 && (p5 == -2)) {
1192                         Log("Found unconverted inode %d\n", i);
1193                         Log("You should run the AFS file conversion utility\n");
1194                         goto out;
1195                     }
1196                 }
1197 #endif
1198                 if (IS_DVICEMAGIC(p) && (p->di_mode & IFMT) == IFREG) {
1199                     afs_uint32 p2 = p->di_vicep2, p3 = DI_VICEP3(p);
1200
1201                     info.u.param[0] = p->di_vicep1;
1202 #ifdef  AFS_3DISPARES
1203                     if (((p2 >> 3) == INODESPECIAL) && (p2 & 0x3)) {
1204                         info.u.param[1] = INODESPECIAL;
1205                         info.u.param[2] = p3;
1206                         info.u.param[3] = p2 & 0x3;
1207                     } else {
1208                         info.u.param[1] = ((p2 >> 27) << 16) + (p3 & 0xffff);
1209                         info.u.param[2] = (p2 & 0x3fffff);
1210                         info.u.param[3] =
1211                             (((p2 >> 22) & 0x1f) << 16) + (p3 >> 16);
1212                     }
1213 #else
1214                     info.u.param[1] = p->di_vicep2;
1215                     info.u.param[2] = DI_VICEP3(p);
1216                     info.u.param[3] = p->di_vicep4;
1217 #endif
1218                     info.inodeNumber = i;
1219                     info.byteCount = p->di_size;
1220                     info.linkCount = p->di_nlink;
1221                     if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
1222                         continue;
1223                     if (inodeFile) {
1224                         if (fwrite(&info, sizeof info, 1, inodeFile) != 1) {
1225                             Log("Error writing inode file for partition %s\n",
1226                                 partition);
1227                             goto out;
1228                         }
1229                     }
1230                     ninodes++;
1231                 }
1232             }
1233         }
1234     }
1235     if (inodes)
1236         free(inodes);
1237 #endif
1238     if (inodeFile) {
1239         if (fflush(inodeFile) == EOF) {
1240             Log("Unable to successfully flush inode file for %s\n", partition);
1241             err = -2;
1242             goto out1;
1243         }
1244         if (fsync(fileno(inodeFile)) == -1) {
1245             Log("Unable to successfully fsync inode file for %s\n", partition);
1246             err = -2;
1247             goto out1;
1248         }
1249
1250         /*
1251          * Paranoia:  check that the file is really the right size
1252          */
1253         if (fstat(fileno(inodeFile), &status) == -1) {
1254             Log("Unable to successfully stat inode file for %s\n", partition);
1255             err = -2;
1256             goto out1;
1257         }
1258         if (status.st_size != ninodes * sizeof(struct ViceInodeInfo)) {
1259             Log("Wrong size (%d instead of %d) in inode file for %s\n",
1260                 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
1261                 partition);
1262             err = -2;
1263             goto out1;
1264         }
1265     }
1266     close(pfd);
1267     return 0;
1268
1269   out:
1270     err = -1;
1271   out1:
1272     close(pfd);
1273     if (inodes)
1274         free(inodes);
1275     return err;
1276 }
1277 #endif /* !AFS_SGI_ENV */
1278 #endif /* !AFS_AIX31_ENV       */
1279
1280 #ifdef AFS_DARWIN_ENV
1281 #undef dbtob
1282 #define dbtob(db) ((unsigned)(db) << DEV_BSHIFT)
1283 #endif
1284
1285 int
1286 bread(int fd, char *buf, daddr_t blk, afs_int32 size)
1287 {
1288 #ifdef  AFS_AIX_ENV
1289 #ifdef  AFS_AIX41_ENV
1290     offset_t off = (offset_t) blk << FSBSHIFT;
1291     if (llseek(fd, off, 0) < 0) {
1292         Log("Unable to seek to offset %llu for block %u\n", off, blk);
1293         return -1;
1294     }
1295 #else /* AFS_AIX41_ENV */
1296     if (afs_lseek(fd, blk * Bsize, 0) < 0) {
1297         Log("Unable to seek to offset %u for block %u\n", blk * Bsize, blk);
1298     }
1299 #endif /* AFS_AIX41_ENV */
1300 #else
1301     if (afs_lseek(fd, (off_t) dbtob(blk), L_SET) < 0) {
1302         Log("Unable to seek to offset %u for block %u\n", dbtob(blk), blk);
1303     }
1304 #endif
1305     if (read(fd, buf, size) != size) {
1306         Log("Unable to read block %d, partition %s\n", blk, partition);
1307         return -1;
1308     }
1309     return 0;
1310 }
1311
1312 #endif /* AFS_LINUX20_ENV */
1313 static afs_int32
1314 convertVolumeInfo(int fdr, int fdw, afs_uint32 vid)
1315 {
1316     struct VolumeDiskData vd;
1317     char *p;
1318
1319     if (read(fdr, &vd, sizeof(struct VolumeDiskData)) !=
1320         sizeof(struct VolumeDiskData)) {
1321         Log("1 convertiVolumeInfo: read failed for %lu with code %d\n", vid,
1322             errno);
1323         return -1;
1324     }
1325     vd.restoredFromId = vd.id;  /* remember the RO volume here */
1326     vd.cloneId = vd.id;
1327     vd.id = vd.parentId;
1328     vd.type = RWVOL;
1329     vd.dontSalvage = 0;
1330     vd.inUse = 0;
1331     vd.uniquifier += 5000;      /* just in case there are still file copies
1332                                    from the old RW volume around */
1333
1334     p = strrchr(vd.name, '.');
1335     if (p && !strcmp(p, ".readonly")) {
1336         memset(p, 0, 9);
1337     }
1338
1339     if (write(fdw, &vd, sizeof(struct VolumeDiskData)) !=
1340         sizeof(struct VolumeDiskData)) {
1341         Log("1 convertiVolumeInfo: write failed for %lu with code %d\n", vid,
1342             errno);
1343         return -1;
1344     }
1345     return 0;
1346 }
1347
1348 struct specino {
1349     afs_int32 inodeType;
1350     Inode inodeNumber;
1351     Inode ninodeNumber;
1352 };
1353
1354
1355 int
1356 UpdateThisVolume(struct ViceInodeInfo *inodeinfo, VolumeId singleVolumeNumber,
1357                  struct specino *specinos)
1358 {
1359     struct dinode *p;
1360     if ((inodeinfo->u.vnode.vnodeNumber == INODESPECIAL) &&
1361         (inodeinfo->u.vnode.volumeId == singleVolumeNumber)) {
1362         specinos[inodeinfo->u.special.type].inodeNumber =
1363             inodeinfo->inodeNumber;
1364     }
1365     return 0; /* We aren't using a result file, we're caching */
1366 }
1367
1368 static char *
1369 getDevName(char *pbuffer, char *wpath)
1370 {
1371     char pbuf[128], *ptr;
1372     strcpy(pbuf, pbuffer);
1373     ptr = (char *)strrchr(pbuf, '/');
1374     if (ptr) {
1375         *ptr = '\0';
1376         strcpy(wpath, pbuf);
1377     } else
1378         return NULL;
1379     ptr = (char *)strrchr(pbuffer, '/');
1380     if (ptr) {
1381         strcpy(pbuffer, ptr + 1);
1382         return pbuffer;
1383     } else
1384         return NULL;
1385 }
1386
1387 #ifdef FSSYNC_BUILD_CLIENT
1388 int
1389 inode_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId)
1390 {
1391     char dir_name[512], oldpath[512], newpath[512];
1392     char volname[20];
1393     char headername[16];
1394     char *name;
1395     int fd, err, forcep, j;
1396     ssize_t len, nBytes;
1397     struct dirent *dp;
1398     struct DiskPartition64 *partP;
1399     struct ViceInodeInfo info;
1400     struct VolumeDiskHeader h;
1401     IHandle_t *ih, *ih2;
1402     FdHandle_t *fdP, *fdP2;
1403     char wpath[100];
1404     char tmpDevName[100];
1405     char buffer[128];
1406     struct specino specinos[VI_LINKTABLE+1];
1407     Inode nearInode = 0;
1408 # ifdef AFS_DEMAND_ATTACH_FS
1409     int locktype = 0;
1410 # endif /* AFS_DEMAND_ATTACH_FS */
1411     int code = 0;
1412
1413     memset(&specinos, 0, sizeof(specinos));
1414
1415     /* now do the work */
1416
1417     for (partP = DiskPartitionList; partP && strcmp(partP->name, pname);
1418          partP = partP->next);
1419     if (!partP) {
1420         Log("1 inode_ConvertROtoRWvolume: Couldn't find DiskPartition for %s\n", pname);
1421         code = EIO;
1422         goto done;
1423     }
1424
1425 #ifdef AFS_DEMAND_ATTACH_FS
1426     locktype = VVolLockType(V_VOLUPD, 1);
1427     code = VLockVolumeByIdNB(volumeId, partP, locktype);
1428     if (code) {
1429         locktype = 0;
1430         code = EIO;
1431         goto done;
1432     }
1433 #endif
1434
1435     if (VReadVolumeDiskHeader(volumeId, partP, &h)) {
1436         Log("1 inode_ConvertROtoRWvolume: Couldn't read header for RO-volume %lu.\n",
1437             afs_printable_uint32_lu(volumeId));
1438         return EIO;
1439     }
1440
1441     FSYNC_VolOp(volumeId, pname, FSYNC_VOL_BREAKCBKS, 0, NULL);
1442
1443     strcpy(tmpDevName, partP->devName);
1444     name = getDevName(tmpDevName, wpath);
1445
1446     if ((err = ListViceInodes(name, VPartitionPath(partP),
1447                               NULL, UpdateThisVolume, volumeId,
1448                               &forcep, 0, wpath, &specinos)) < 0)
1449     {
1450         Log("1 inode_ConvertROtoRWvolume: Couldn't get special inodes\n");
1451         code = EIO;
1452         goto done;
1453     }
1454
1455 #if defined(NEARINODE_HINT)
1456     nearInodeHash(volumeId, nearInode);
1457     nearInode %= partP->f_files;
1458 #endif
1459
1460     for (j = VI_VOLINFO; j < VI_LINKTABLE+1; j++) {
1461         if (specinos[j].inodeNumber > 0) {
1462             specinos[j].ninodeNumber =
1463                 IH_CREATE(NULL, partP->device, VPartitionPath(partP),
1464                           nearInode, h.parent, INODESPECIAL, j, h.parent);
1465             IH_INIT(ih, partP->device, volumeId,
1466                     specinos[j].inodeNumber);
1467             fdP = IH_OPEN(ih);
1468             if (!fdP) {
1469                 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j, volumeId);
1470                 code = -1;
1471                 goto done;
1472             }
1473
1474             IH_INIT(ih2, partP->device, h.parent, specinos[j].ninodeNumber);
1475             fdP2 = IH_OPEN(ih2);
1476             if (!fdP2) {
1477                 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j, h.parent);
1478                 code = -1;
1479                 goto done;
1480             }
1481
1482             if (j == VI_VOLINFO)
1483                 convertVolumeInfo(fdP->fd_fd, fdP2->fd_fd, ih2->ih_vid);
1484             else {
1485                 while (1) {
1486                     len = read(fdP->fd_fd, buffer, sizeof(buffer));
1487                     if (len < 0)
1488                         return errno;
1489                     if (len == 0)
1490                         break;
1491                     nBytes = write(fdP2->fd_fd, buffer, len);
1492                     if (nBytes != len) {
1493                         code = -1;
1494                         goto done;
1495                     }
1496                 }
1497             }
1498
1499             FDH_CLOSE(fdP);
1500             FDH_CLOSE(fdP2);
1501
1502             /* Unlink the old special inode; otherwise we will get duplicate
1503              * special inodes if we recreate the RO again */
1504             if (IH_DEC(ih, specinos[j].inodeNumber, volumeId) == -1) {
1505                 afs_ino_str_t stmp;
1506                 Log("IH_DEC failed: %x, %s, %u errno %d\n", ih,
1507                     PrintInode(stmp, specinos[j].inodeNumber), volumeId, errno);
1508             }
1509
1510             IH_RELEASE(ih);
1511             IH_RELEASE(ih2);
1512         }
1513     }
1514
1515     h.id = h.parent;
1516 #ifdef AFS_64BIT_IOPS_ENV
1517     h.volumeInfo_lo = (afs_int32)specinos[VI_VOLINFO].ninodeNumber & 0xffffffff;
1518     h.volumeInfo_hi = (afs_int32)(specinos[VI_VOLINFO].ninodeNumber >> 32) && 0xffffffff;
1519     h.smallVnodeIndex_lo = (afs_int32)specinos[VI_SMALLINDEX].ninodeNumber & 0xffffffff;
1520     h.smallVnodeIndex_hi = (afs_int32)(specinos[VI_SMALLINDEX].ninodeNumber >> 32) & 0xffffffff;
1521     h.largeVnodeIndex_lo = (afs_int32)specinos[VI_LARGEINDEX].ninodeNumber & 0xffffffff;
1522     h.largeVnodeIndex_hi = (afs_int32)(specinos[VI_LARGEINDEX].ninodeNumber >> 32) & 0xffffffff;
1523     if (specinos[VI_LINKTABLE].ninodeNumber) {
1524         h.linkTable_lo = (afs_int32)specinos[VI_LINKTABLE].ninodeNumber & 0xffffffff;
1525         h.linkTable_hi = (afs_int32)specinos[VI_LINKTABLE].ninodeNumber & 0xffffffff;
1526     }
1527 #else
1528     h.volumeInfo_lo = specinos[VI_VOLINFO].ninodeNumber;
1529     h.smallVnodeIndex_lo = specinos[VI_SMALLINDEX].ninodeNumber;
1530     h.largeVnodeIndex_lo = specinos[VI_LARGEINDEX].ninodeNumber;
1531     if (specinos[VI_LINKTABLE].ninodeNumber) {
1532         h.linkTable_lo = specinos[VI_LINKTABLE].ninodeNumber;
1533     }
1534 #endif
1535
1536     if (VCreateVolumeDiskHeader(&h, partP)) {
1537         Log("1 inode_ConvertROtoRWvolume: Couldn't write header for RW-volume %lu\n",
1538             afs_printable_uint32_lu(h.id));
1539         code = EIO;
1540         goto done;
1541     }
1542
1543     if (VDestroyVolumeDiskHeader(partP, volumeId, h.parent)) {
1544         Log("1 inode_ConvertROtoRWvolume: Couldn't unlink header for RO-volume %lu\n",
1545             afs_printable_uint32_lu(volumeId));
1546     }
1547
1548     FSYNC_VolOp(volumeId, pname, FSYNC_VOL_DONE, 0, NULL);
1549     FSYNC_VolOp(h.id, pname, FSYNC_VOL_ON, 0, NULL);
1550
1551  done:
1552 # ifdef AFS_DEMAND_ATTACH_FS
1553     if (locktype) {
1554         VUnlockVolumeById(volumeId, partP);
1555     }
1556 # endif /* AFS_DEMAND_ATTACH_FS */
1557     return code;
1558 }
1559 #endif /* FSSYNC_BUILD_CLIENT */
1560 #endif /* AFS_NAMEI_ENV */