--- src/usr.bin/fstat/fstat.c.orig Sat Jan 14 02:18:03 2006 +++ src/usr.bin/fstat/fstat.c Sun Aug 12 13:35:06 2007 @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -69,7 +70,9 @@ #include #include #include +#include #undef _KERNEL + #include #include #include @@ -108,6 +111,9 @@ #define TRACE -4 #define MMAP -5 #define JDIR -6 +#define UNIONUNDEF -7 +#define UNIONLOWER -8 +#define UNIONUPPER -9 DEVS *devs; @@ -147,6 +153,8 @@ void dommap(struct kinfo_proc *kp); void vtrans(struct vnode *vp, int i, int flag); int ufs_filestat(struct vnode *vp, struct filestat *fsp); +int unionfs_filestat(struct vnode *vp, struct filestat *fsp); +struct vnode *unionfs_filestat_new(struct vnode *vp, int *i); int nfs_filestat(struct vnode *vp, struct filestat *fsp); int devfs_filestat(struct vnode *vp, struct filestat *fsp); char *getmnton(struct mount *m); @@ -314,6 +322,15 @@ case JDIR: \ printf(" jail"); \ break; \ + case UNIONUNDEF: \ + printf(" undf"); \ + break; \ + case UNIONLOWER: \ + printf(" ulow"); \ + break; \ + case UNIONUPPER: \ + printf(" uup"); \ + break; \ default: \ printf(" %4d", i); \ break; \ @@ -490,6 +507,9 @@ struct filestat fst; char rw[3], mode[15], tagstr[12], *tagptr; const char *badtype, *filename; + struct vnode *unionvp = NULL; + int unionflag = 0; + int unionfiletype = 0; filename = badtype = NULL; if (!KVM_READ(vp, &vn, sizeof (struct vnode))) { @@ -524,6 +544,17 @@ } else if (!strcmp("isofs", tagstr)) { if (!isofs_filestat(&vn, &fst)) badtype = "error"; + } else if (!strcmp("unionfs", tagstr)) { + if (!unionfs_filestat(&vn, &fst)) + badtype = "error"; + /* also diplay vnode of interest */ + unionvp = unionfs_filestat_new(&vn,&unionfiletype); + if (unionvp == NULL) { + unionflag = 0; + } + else { + unionflag = 1; + } } else { static char unknown[32]; snprintf(unknown, sizeof unknown, "?(%s)", tagstr); @@ -586,7 +617,36 @@ printf(" %2s", rw); if (filename && !fsflg) printf(" %s", filename); + if ( unionflag == 1 && unionvp != NULL ) { + if (!KVM_READ(unionvp, &vn, sizeof (struct vnode))) { + dprintf(stderr, "can't read vnode at %p for pid %d\n", + (void *)vp, Pid); + return; + } + switch (unionfiletype) { + case UNIONLOWER: + printf(" unionlower"); + break; + case UNIONUPPER: + printf(" unionupper"); + break; + default: + printf(" unionundef"); + } +#if 0 + /* need some more logic to do this lookup */ + if (nflg) + /* lookup fst.fsid for vnode */ + (void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid)); + else { +#endif + (void)printf(" %-8s", getmnton(vn.v_mount)); +#if 0 + } +#endif + } putchar('\n'); + } int @@ -620,6 +680,88 @@ return 1; } + +int +unionfs_filestat(struct vnode *vp, struct filestat *fsp) +{ + struct unionfs_node unode; + struct vnode lower; + struct vnode upper; + int res; + + if (!KVM_READ(VTOUNIONFS(vp), &unode, sizeof (unode))) { + dprintf(stderr, "can't read unionfs_node at %p for pid %d\n", + (void *)VTOUNIONFS(vp), Pid); + return 0; + } + + /* find the vnode of the file, if it exists */ + if (unode.un_uppervp != NULL ) { + if (!KVM_READ(unode.un_uppervp, &upper, + sizeof (struct vnode))) { + dprintf(stderr, + "can't read upper vnode at %p for pid %d\n", + (void *)vp, Pid); + return 0; + } + /* fprintf(stderr,"found upper vnode\n"); */ + res = ufs_filestat(&upper, fsp); + } + else if (unode.un_lowervp != NULL ) { + if (!KVM_READ(unode.un_lowervp, &lower, + sizeof (struct vnode))) { + dprintf(stderr, + "can't read lower vnode at %p for pid %d\n", + (void *)vp, Pid); + return 0; + } + /* fprintf(stderr,"found lower vnode\n"); */ + res = ufs_filestat(&lower, fsp); + } + else { + /* neither lower or upper exist */ + dprintf(stderr, "neither lower nor upper vnode defined\n"); + fsp->fsid = 0; + fsp->fileid = 0; + fsp->mode = 0; + fsp->size = 0; + fsp->rdev = 0; + return 0; + } + + return res; +} + +struct vnode * +unionfs_filestat_new(struct vnode *vp, int *i) +{ + struct unionfs_node unode; + + if (!KVM_READ(VTOUNIONFS(vp), &unode, sizeof (unode))) { + dprintf(stderr, "can't read unionfs_node at %p for pid %d\n", + (void *)VTOUNIONFS(vp), Pid); + return 0; + } + + /* find the vnode of the file, if it exists */ + if (unode.un_uppervp != NULL ) { + *i = UNIONUPPER; + return (unode.un_uppervp); + } + else if (unode.un_lowervp != NULL ) { + *i = UNIONLOWER; + return (unode.un_lowervp); + } + else { + /* neither lower or upper exist */ + dprintf(stderr, "neither lower nor upper vnode defined\n"); + *i = UNIONUNDEF; + return (NULL); + } + +} + + int devfs_filestat(struct vnode *vp, struct filestat *fsp)