/
githubmirror
/
lsof
Обзор
Документация
Войти
/
githubmirror
/
lsof
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
lib/dialects/aix/dfile.c
748 строк
24 KB
Jiajie Chen
Move hashSfile static state to lsof_context
31 мар 2026, 13:14
31 мар 2026, 13:14
dd692bd
Код
Авторство
О чём код?
/* * dfile.c - AIX file processing functions for lsof */ /* * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana * 47907. All rights reserved. * * Written by Victor A. Abell * * This software is not subject to any license of the American Telephone * and Telegraph Company or the Regents of the University of California. * * Permission is granted to anyone to use this software for any purpose on * any computer system, and to alter it and redistribute it freely, subject * to the following restrictions: * * 1. Neither the authors nor Purdue University are responsible for any * consequences of the use of this software. * * 2. The origin of this software must not be misrepresented, either by * explicit claim or by omission. Credit to the authors and Purdue * University must appear in documentation and sources. * * 3. Altered versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 4. This notice may not be removed or altered. */ #ifndef lint static char copyright[] = "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; #endif #include "common.h" /* * Local structures */ /* * Local static variables */ static struct hsfile *HbyMPC = /* hash by MPC file buckets */ (struct hsfile *)NULL; static int HbyMPCCt = 0; /* HbyMPC entry count */ /* * Local definitions */ #define SFDIHASH \ 4094 /* Sfile hash by (device,inode) number \ * pair bucket count (power of 2!) */ #define SFFSHASH \ 128 /* Sfile hash by file system device \ * number bucket count (power of 2!) */ #define SFHASHDEVINO(maj, min, ino, mod) \ ((int)(((int)((((int)(maj + 1)) * ((int)((min + 1)))) + ino) * 31415) & \ (mod - 1))) /* hash for Sfile by major device, * minor device, and inode, modulo m * (m must be a power of 2) */ #define SFMPCHASH 1024 /* Sfile hash by MPC device number */ #define SFNMHASH \ 4096 /* Sfile hash by name bucket count \ (power of 2!) */ #define SFRDHASH \ 1024 /* Sfile hash by raw device number \ * bucket count (power of 2!) */ #define SFHASHRDEVI(maj, min, rmaj, rmin, ino, mod) \ ((int)(((int)((((int)(maj + 1)) * ((int)((min + 1)))) + \ ((int)(rmaj + 1) * (int)(rmin + 1)) + ino) * \ 31415) & \ (mod - 1))) /* hash for Sfile by major device, * minor device, major raw device, * minor raw device, and inode, modulo * mod (mod must be a power of 2) */ /* * hashSfile() - hash Sfile entries for use in is_file_named() searches */ void hashSfile(struct lsof_context *ctx) { int i; struct sfile *s; struct hsfile *sh, *sn; /* * Do nothing if there are no file search arguments cached or if the * hashes have already been constructed. */ if (!Sfile || Hs) return; /* * Allocate hash buckets by (device,inode), file system device, MPC device, * and file name. */ if (!(HbyFdi = (struct hsfile *)calloc((MALLOC_S)SFDIHASH, sizeof(struct hsfile)))) { (void)fprintf( stderr, "%s: can't allocate space for %d (dev,ino) hash buckets\n", Pn, SFDIHASH); Error(ctx); } if (!(HbyFrd = (struct hsfile *)calloc((MALLOC_S)SFRDHASH, sizeof(struct hsfile)))) { (void)fprintf(stderr, "%s: can't allocate space for %d rdev hash buckets\n", Pn, SFRDHASH); Error(ctx); } if (!(HbyFsd = (struct hsfile *)calloc((MALLOC_S)SFFSHASH, sizeof(struct hsfile)))) { (void)fprintf(stderr, "%s: can't allocate space for %d file sys hash buckets\n", Pn, SFFSHASH); Error(ctx); } if (!(HbyMPC = (struct hsfile *)calloc((MALLOC_S)SFMPCHASH, sizeof(struct hsfile)))) { (void)fprintf(stderr, "%s: can't allocate space for %d MPC file hash buckets\n", Pn, SFMPCHASH); Error(ctx); } if (!(HbyNm = (struct hsfile *)calloc((MALLOC_S)SFNMHASH, sizeof(struct hsfile)))) { (void)fprintf(stderr, "%s: can't allocate space for %d name hash buckets\n", Pn, SFNMHASH); Error(ctx); } Hs++; /* * Scan the Sfile chain, building file, file system, MPC file, and file * name hash bucket chains. */ for (s = Sfile; s; s = s->next) { for (i = 0; i < 4; i++) { if (i == 0) { if (!s->aname) continue; sh = &HbyNm[hashbyname(s->aname, SFNMHASH)]; HbyNmCt++; } else if (i == 1) { if (s->type) { sh = &HbyFdi[SFHASHDEVINO(GET_MAJ_DEV(s->dev), GET_MIN_DEV(s->dev), s->i, SFDIHASH)]; HbyFdiCt++; } else { sh = &HbyFsd[SFHASHDEVINO( GET_MAJ_DEV(s->dev), GET_MIN_DEV(s->dev), 0, SFFSHASH)]; HbyFsdCt++; } } else if (i == 2) { if (s->type && (s->ch < 0) && (s->mode == S_IFCHR)) { sh = &HbyMPC[SFHASHDEVINO(GET_MAJ_DEV(s->dev), GET_MIN_DEV(s->dev), 0, SFMPCHASH)]; HbyMPCCt++; } else continue; } else if (i == 3) { if (s->type && (((s->mode == S_IFCHR) && (s->ch < 0)) || ((s->mode == S_IFBLK)))) { sh = &HbyFrd[SFHASHRDEVI( GET_MAJ_DEV(s->dev), GET_MIN_DEV(s->dev), GET_MAJ_DEV(s->rdev), GET_MIN_DEV(s->rdev), s->i, SFRDHASH)]; HbyFrdCt++; } else continue; } if (!sh->s) { sh->s = s; sh->next = (struct hsfile *)NULL; continue; } else { if (!(sn = (struct hsfile *)malloc( (MALLOC_S)sizeof(struct hsfile)))) { (void)fprintf(stderr, "%s: can't allocate hsfile bucket for: %s\n", Pn, s->aname); Error(ctx); } sn->s = s; sn->next = sh->next; sh->next = sn; } } } } /* * is_file_named() - is file named? */ int is_file_named(struct lsof_context *ctx, /* context */ char *p, /* path name; NULL = search by device * and inode (from *Lf) */ enum vtype ty, /* vnode type */ chan_t ch, /* gnode channel */ int ic) /* is clone file (4.1.4 and above) */ { int dmaj, dmin, maj, min, rmaj, rmin; static int dsplit = 0; char *ep; int f = 0; struct sfile *s; struct hsfile *sh; size_t sz; /* * Split the device numbers into their major and minor numbers. * * THis is necessitated by 64 bit AIX architectures, which store two * different types of device numbers in 64 bit dev_t's. The two types can't * be compared directly, but must be compared by extracting their major and * minor numbers and comparing them. */ readdev(ctx, 0); if (!dsplit) { dmaj = GET_MAJ_DEV(DevDev); dmin = GET_MIN_DEV(DevDev); dsplit = 1; } if (Lf->dev_def) { maj = GET_MAJ_DEV(Lf->dev); min = GET_MIN_DEV(Lf->dev); } if (Lf->rdev_def) { rmaj = GET_MAJ_DEV(Lf->rdev); rmin = GET_MIN_DEV(Lf->rdev); } #if AIXV >= 4140 /* * Check for a clone match. */ if (ic && HbyFdiCt && CloneMaj >= 0 && (Lf->dev_def && (maj = dmaj) && (min == dmin)) && Lf->rdev_def && (Lf->inp_ty == 1 || Lf->inp_ty == 3)) { for (sh = &HbyFdi[SFHASHDEVINO(CloneMaj, rmaj, Lf->inode, SFDIHASH)]; sh; sh = sh->next) { if ((s = sh->s) && (GET_MAJ_DEV(s->rdev) == CloneMaj) && (GET_MIN_DEV(s->rdev) == rmaj) && (s->i == Lf->inode)) { f = 3; break; } } } #endif /* AIXV>=4140 */ /* * Check for a path name match, as requested. */ if (!f && p && HbyNmCt) { for (sh = &HbyNm[hashbyname(p, SFNMHASH)]; sh; sh = sh->next) { if ((s = sh->s) && strcmp(p, s->aname) == 0) { f = 2; break; } } } /* * Check for a regular AIX multiplexed file, matching the channel if * it was supplied by the caller. */ if (!f && HbyMPCCt && ty == VMPC && (Lf->dev_def && (maj == dmaj) && (min == dmin)) && Lf->rdev_def) { for (sh = &HbyMPC[SFHASHDEVINO(rmaj, rmin, 0, SFMPCHASH)]; sh; sh = sh->next) { if ((s = sh->s) && (GET_MAJ_DEV(s->dev) == rmaj) && (GET_MIN_DEV(s->dev) == rmin) && (s->ch < 0 || ch == s->ch)) { f = 1; break; } } } /* * Check for a regular file. */ if (!f && HbyFdiCt && Lf->dev_def && (Lf->inp_ty == 1 || Lf->inp_ty == 3)) { for (sh = &HbyFdi[SFHASHDEVINO(maj, min, Lf->inode, SFDIHASH)]; sh; sh = sh->next) { if ((s = sh->s) && (maj == GET_MAJ_DEV(s->dev)) && (min == GET_MIN_DEV(s->dev)) && (Lf->inode == s->i)) { f = 1; break; } } } /* * Check for a file system. */ if (!f && HbyFsdCt && Lf->dev_def) { for (sh = &HbyFsd[SFHASHDEVINO(maj, min, 0, SFFSHASH)]; sh; sh = sh->next) { if ((s = sh->s) && (maj == GET_MAJ_DEV(s->dev)) && (min == GET_MIN_DEV(s->dev))) { f = 1; break; } } } /* * Check for a character or block device file. */ if (!f && HbyFrdCt && ((ty == VCHR) || (ty == VBLK)) && (Lf->dev_def && (maj == dmaj) && (min == dmin)) && Lf->rdev_def && (Lf->inp_ty == 1 || Lf->inp_ty == 3)) { for (sh = &HbyFrd[SFHASHRDEVI(maj, min, rmaj, rmin, Lf->inode, SFRDHASH)]; sh; sh = sh->next) { if ((s = sh->s) && (GET_MAJ_DEV(s->rdev) == rmaj) && (GET_MIN_DEV(s->rdev) == rmin) && (((ty == VCHR) && (s->mode == S_IFCHR) && (s->ch < 0)) || ((ty == VBLK) && (s->mode == S_IFBLK)))) { f = 1; break; } } } /* * Convert the name if a match occurred. */ if (f) { if (f == 2) { (void)snpf(Namech, Namechl, "%s", p); #if AIXV >= 4140 } else if (f == 3 && ClonePtc >= 0 && (maj == ClonePtc)) { (void)snpf(Namech, Namechl, "%s/%d", s->name, min); #endif /* AIXV>=4140 */ } else if (s->type) { /* * If the search argument isn't a file system, propagate it * to Namech[]; otherwise, let printname() compose the name. */ (void)snpf(Namech, Namechl, "%s", s->name); if (ty == VMPC && s->ch < 0) { ep = endnm(ctx, &sz); (void)snpf(ep, sz, "/%d", ch); } if (s->devnm) { ep = endnm(ctx, &sz); (void)snpf(ep, sz, " (%s)", s->devnm); } } s->f = 1; return (1); } return (0); } /* * print_dev() - print device */ char *print_dev(struct lfile *lf, /* file whose device to be printed */ dev_t *dev) /* pointer to device to be printed */ { static char buf[128]; int maj = GET_MAJ_DEV(*dev); int min = GET_MIN_DEV(*dev); #if AIXV >= 3200 if (*dev & SDEV_REMOTE) { (void)snpf(buf, sizeof(buf), "NFS,%d", (min & ~SDEV_REMOTE)); return (buf); } #endif /* AIXV>=3200 */ (void)snpf(buf, sizeof(buf), "%d,%d", maj, min); return (buf); } /* * process_file() - process file structure */ void process_file(struct lsof_context *ctx, /* context */ KA_T fp) /* kernel file structure address */ { struct file f; int flag; char tbuf[32]; struct vnode v; struct gnode g; #if defined(FILEPTR) /* * Save file structure address for process_node(). */ FILEPTR = &f; #endif /* defined(FILEPTR) */ /* * Read file structure. */ if (kread(ctx, (KA_T)fp, (char *)&f, sizeof(f))) { (void)snpf(Namech, Namechl, "can't read file struct from %s", print_kptr(fp, (char *)NULL, 0)); enter_nm(ctx, Namech); return; } Lf->off = (SZOFFTYPE)f.f_offset; Lf->off_def = 1; if (f.f_count) { /* * Construct access code. */ if ((flag = (f.f_flag & (FREAD | FWRITE))) == FREAD) Lf->access = LSOF_FILE_ACCESS_READ; else if (flag == FWRITE) Lf->access = LSOF_FILE_ACCESS_WRITE; else if (flag == (FREAD | FWRITE)) Lf->access = LSOF_FILE_ACCESS_READ_WRITE; #if defined(HASFSTRUCT) /* * Save file structure values. */ # if !defined(HASNOFSCOUNT) Lf->fct = (long)f.f_count; Lf->fsv |= FSV_CT; # endif /* !defined(HASNOFSCOUNT) */ # if !defined(HASNOFSADDR) Lf->fsa = fp; Lf->fsv |= FSV_FA; # endif /* !defined(HASNOFSADDR) */ # if !defined(HASNOFSFLAGS) Lf->ffg = (long)f.f_flag; Lf->fsv |= FSV_FG; # endif /* !defined(HASNOFSFLAGS) */ # if !defined(HASNOFSNADDR) Lf->fna = (KA_T)f.f_data; Lf->fsv |= FSV_NI; # endif /* !defined(HASNOFSNADDR) */ #endif /* defined(HASFSTRUCT) */ /* * Process structure by its type. */ switch (f.f_type) { #if defined(DTYPE_PIPE) case DTYPE_PIPE: # if defined(HASPIPEFN) if (!Selinet) HASPIPEFN(ctx, (KA_T)f.f_data); # endif /* defined(HASPIPEFN) */ return; #endif /* defined(DTYPE_PIPE) */ #if defined(DTYPE_PTS) case DTYPE_PTS: # if defined(HASPTSFN) HASPTSFN(ctx, (KA_T)f.f_data); # endif /* defined(HASPTSFN) */ return; #endif /* defined(DTYPE_PTS) */ #if defined(DTYPE_FIFO) case DTYPE_FIFO: #endif /* defined(DTYPE_FIFO) */ #if defined(DTYPE_GNODE) case DTYPE_GNODE: #endif /* defined(DTYPE_GNODE) */ #if defined(DTYPE_INODE) case DTYPE_INODE: #endif /* defined(DTYPE_INODE) */ #if defined(DTYPE_PORT) case DTYPE_PORT: #endif /* defined(DTYPE_PORT) */ #if defined(DTYPE_VNODE) case DTYPE_VNODE: /* * AIX-specific: Capture filename from file structure. * * AIX limitation: The kernel doesn't provide an accessible name * cache, so we can only obtain the leaf filename from f_fnamep. * We'll combine this with the filesystem mount point (if available) * after calling process_node() to provide partial path context. * * Full path reconstruction is not possible on AIX without expensive * userspace filesystem scanning. */ { char leafname[MAXPATHLEN]; int have_leaf = 0; /* Try to read the leaf filename from the file structure */ if (f.f_vnode && f.f_fnamep && !kread(ctx, (KA_T)f.f_vnode, (char *)&v, sizeof(v)) && v.v_gnode && !kread(ctx, (KA_T)v.v_gnode, (char *)&g, sizeof(g)) && (g.gn_type == VREG || g.gn_type == VDIR)) { if (!kread(ctx, (KA_T)f.f_fnamep, leafname, sizeof(leafname) - 1)) { leafname[sizeof(leafname) - 1] = '\0'; /* Only use if we got a non-empty string */ if (leafname[0]) { have_leaf = 1; } } } /* Process the node to get vfs/mount info and other metadata */ # if defined(HASF_VNODE) process_node(ctx, (KA_T)f.f_vnode); # else /* !defined(HASF_VNODE) */ process_node(ctx, (KA_T)f.f_data); # endif /* defined(HASF_VNODE) */ /* * If we have a leaf name, combine it with mount point info. * This provides better context than just the leaf name alone. * Use ellipsis (...) to indicate missing path components * between the mount point and the leaf filename. */ if (have_leaf) { if (Lf->fsdir && Lf->fsdir[0] && strcmp(Lf->fsdir, "/") != 0) { /* We have a non-root mount point, show mount/.../leaf */ (void)snpf(Namech, Namechl, "%s/.../%s", Lf->fsdir, leafname); } else if (Lf->fsdir && strcmp(Lf->fsdir, "/") == 0) { /* Root filesystem, show /.../leaf */ (void)snpf(Namech, Namechl, "/.../%s", leafname); } else { /* No mount point info, just show .../leaf */ (void)snpf(Namech, Namechl, ".../%s", leafname); } /* Enter the name we constructed */ enter_nm(ctx, Namech); } } #endif /* defined(DTYPE_VNODE) */ return; case DTYPE_SOCKET: process_socket(ctx, (KA_T)f.f_data); return; #if defined(HASKQUEUE) case DTYPE_KQUEUE: process_kqueue(ctx, (KA_T)f.f_data); return; #endif /* defined(HASKQUEUE) */ #if defined(HASPSXSEM) case DTYPE_PSXSEM: process_psxsem(ctx, (KA_T)f.f_data); return; #endif /* defined(HASPSXSEM) */ #if defined(HASPSXSHM) case DTYPE_PSXSHM: process_psxshm(ctx, (KA_T)f.f_data); return; #endif /* defined(HASPSXSHM) */ #if defined(HASPRIVFILETYPE) case PRIVFILETYPE: HASPRIVFILETYPE(ctx, (KA_T)f.f_data); return; #endif /* defined(HASPRIVFILETYPE) */ default: #if defined(X_BADFILEOPS) if (X_bfopsa && f.f_ops && (X_bfopsa == (KA_T)f.f_ops)) { (void)snpf(Namech, Namechl, "no more information; ty=%d file may be closing", (int)f.f_type); enter_nm(ctx, Namech); return; } #endif /* defined(X_BADFILEOPS) */ if (f.f_type || f.f_ops) { (void)snpf(Namech, Namechl, "%s file struct, ty=%d, op=%s", print_kptr(fp, tbuf, sizeof(tbuf)), (int)f.f_type, print_kptr((KA_T)f.f_ops, (char *)NULL, 0)); enter_nm(ctx, Namech); return; } } } enter_nm(ctx, "no more information"); } /* * readvfs() - read vfs structure */ struct l_vfs *readvfs(struct lsof_context *ctx, /* context */ struct vnode *vn) /* vnode */ { struct gfs g; void *mp; char *s1, *s2; uint ul; struct vfs v; struct vmount *vm; struct l_vfs *vp; if (!vn->v_vfsp) return ((struct l_vfs *)NULL); for (vp = Lvfs; vp; vp = vp->next) { if ((KA_T)vn->v_vfsp == vp->addr) return (vp); } if (!(vp = (struct l_vfs *)malloc((MALLOC_S)sizeof(struct l_vfs)))) { (void)fprintf(stderr, "%s: PID %d, no space for vfs\n", Pn, Lp->pid); Error(ctx); } vp->dir = (char *)NULL; vp->fsname = (char *)NULL; /* * Read the vfs structure. */ if (kread(ctx, (KA_T)vn->v_vfsp, (char *)&v, sizeof(v))) { vfs_exit: (void)free((FREE_P *)vp); return ((struct l_vfs *)NULL); } /* * Locate AIX mount information. */ if (!v.vfs_gfs || kread(ctx, (KA_T)v.vfs_gfs, (char *)&g, sizeof(g))) goto vfs_exit; if (!v.vfs_mdata || kread(ctx, (KA_T)((char *)v.vfs_mdata + offsetof(struct vmount, vmt_length)), (char *)&ul, sizeof(ul))) goto vfs_exit; if (!(mp = (void *)malloc((MALLOC_S)ul))) { (void)fprintf(stderr, "%s: PID %d, no space for mount data\n", Pn, Lp->pid); Error(ctx); } if (kread(ctx, (KA_T)v.vfs_mdata, (char *)mp, (int)ul)) { (void)free((FREE_P *)mp); goto vfs_exit; } vm = (struct vmount *)mp; vp->vmt_flags = vm->vmt_flags; vp->vmt_gfstype = vm->vmt_gfstype; #if AIXV >= 3200 if ((vp->vmt_flags & MNT_REMOTE) # if defined(HAS_SANFS) && defined(MNT_SANFS) && (vp->vmt_gfstype != MNT_SANFS) # endif /* defined(HAS_SANFS) && defined(MNT_SANFS) */ ) { vp->dev = 0x80000000 | vm->vmt_vfsnumber; # if AIXA >= 1 vp->dev |= 0x8000000000000000; # endif /* AIXA>=1 */ } else #endif /* AIXV>=3200 */ #if defined(HAS_AFS) if (vm->vmt_gfstype == MNT_AFS) vp->dev = AFSDEV; else #endif /* defined(HAS_AFS) */ #if AIXA > 1 if (vm->vmt_gfstype == MNT_PROCFS) { /* * !!!DEBUG!!! !!!DEBUG!!! !!!DEBUG!!! !!!DEBUG!!! !!!DEBUG!!! * * The following *hack* is required to make the vmount structure's * device number match what stat(2) errnoneously returns in ia64 * AIX >= 5. * * REMOVE THIS CODE WHEN STAT(2) IS FIXED!!! */ vp->dev = (dev_t)(vm->vmt_fsid.fsid_dev & 0x7fffffffffffffff); /* * !!!DEBUG!!! !!!DEBUG!!! !!!DEBUG!!! !!!DEBUG!!! !!!DEBUG!!! */ } else #endif /* AIXA>1 */ vp->dev = (dev_t)vm->vmt_fsid.fsid_dev; if ((s1 = vmt2dataptr(vm, VMT_STUB))) { if (!(vp->dir = mkstrcpy(s1, (MALLOC_S *)NULL))) { readvfs_aix1: (void)fprintf(stderr, "%s: PID %d, readvfs, no space\n", Pn, Lp->pid); Error(ctx); } } else vp->dir = (char *)NULL; s1 = vmt2dataptr(vm, VMT_HOST); if (!(s2 = vmt2dataptr(vm, VMT_OBJECT)) || *s1 == '\0') s2 = g.gfs_name; if (!s1 && !s2) vp->fsname = (char *)NULL; else { if (vm->vmt_flags & MNT_REMOTE) { if (!(vp->fsname = mkstrcat(s1 ? s1 : "", -1, (s1 && *s1) ? ":" : "", -1, s2, -1, (MALLOC_S *)NULL))) goto readvfs_aix1; } else { if (!(vp->fsname = mkstrcpy(s2, (MALLOC_S *)NULL))) goto readvfs_aix1; } } (void)free((FREE_P *)mp); vp->next = Lvfs; vp->addr = (KA_T)vn->v_vfsp; #if defined(HAS_AFS) if (!AFSVfsp && vm->vmt_gfstype == MNT_AFS) AFSVfsp = (KA_T)vn->v_vfsp; #endif /* defined(HAS_AFS) */ Lvfs = vp; return (vp); }