| /* |
| * dnode.c - SCO OpenServer node functions for lsof |
| */ |
| |
| |
| /* |
| * Copyright 1995 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 1995 Purdue Research Foundation.\nAll rights reserved.\n"; |
| static char *rcsid = "$Id: dnode.c,v 1.21 2006/03/28 22:09:23 abe Exp $"; |
| #endif |
| |
| |
| #include "lsof.h" |
| |
| |
| _PROTOTYPE(static struct l_dev * finddev,(dev_t *dev, dev_t *rdev, int stream)); |
| |
| |
| /* |
| * finddev() - look up device by device number |
| */ |
| |
| static struct l_dev * |
| finddev(dev, rdev, stream) |
| dev_t *dev; /* device */ |
| dev_t *rdev; /* raw device */ |
| int stream; /* stream if 1 */ |
| { |
| struct clone *c; |
| struct l_dev *dp; |
| /* |
| * Search device table for match. |
| */ |
| |
| #if defined(HASDCACHE) |
| |
| finddev_again: |
| |
| #endif /* defined(HASDCACHE) */ |
| |
| if ((dp = lkupdev(dev, rdev, 0, 0))) |
| return(dp); |
| /* |
| * Search for clone. |
| */ |
| if (stream && Clone) { |
| for (c = Clone; c; c = c->next) { |
| if (GET_MAJ_DEV(*rdev) == GET_MIN_DEV(Devtp[c->dx].rdev)) { |
| |
| #if defined(HASDCACHE) |
| if (DCunsafe && !Devtp[c->dx].v && !vfy_dev(&Devtp[c->dx])) |
| goto finddev_again; |
| #endif /* defined(HASDCACHE) */ |
| |
| return(&Devtp[c->dx]); |
| } |
| } |
| } |
| return((struct l_dev *)NULL); |
| } |
| |
| |
| /* |
| * process_node() - process node |
| */ |
| |
| void |
| process_node(na) |
| KA_T na; /* inode kernel space address */ |
| { |
| char *cp, tbuf[32]; |
| short dl; |
| struct l_dev *dp; |
| unsigned char *fa = (unsigned char *)NULL; |
| struct filock fl; |
| KA_T flf, flp; |
| int fp, lp; |
| struct inode i; |
| short ity, udpsf, udpsl; |
| int j, k, l; |
| KA_T ka, qp; |
| unsigned char *la = (unsigned char *)NULL; |
| struct mounts *lm; |
| struct module_info mi; |
| unsigned short *n; |
| KA_T p; |
| struct inpcb pcb; |
| int port; |
| int pt = -1; |
| struct queue q; |
| struct qinit qi; |
| struct stdata sd; |
| char *tn; |
| int type; |
| struct udpdev udp; |
| short udptm = 0; |
| |
| #if defined(HAS_NFS) |
| struct rnode r; |
| #endif /* defined(HAS_NFS) */ |
| |
| #if OSRV>=500 |
| short hpps = 0; |
| unsigned short *n1; |
| struct pipeinode pi; |
| #endif /* OSRV>=500 */ |
| |
| /* |
| * Read the inode. |
| */ |
| if ( ! na) { |
| enter_nm("no inode address"); |
| return; |
| } |
| if (readinode(na, &i)) { |
| enter_nm(Namech); |
| return; |
| } |
| |
| #if defined(HASNCACHE) |
| Lf->na = na; |
| #endif /* defined(HASNCACHE) */ |
| |
| #if defined(HASFSTRUCT) |
| Lf->fna = na; |
| Lf->fsv |= FSV_NI; |
| #endif /* defined(HASFSTRUCT) */ |
| |
| /* |
| * Identify the node type. |
| */ |
| if (HaveSockdev && (i.i_ftype & IFMT) == IFCHR |
| && GET_MAJ_DEV(i.i_rdev) == Sockdev) |
| { |
| |
| /* |
| * Process a socket. |
| */ |
| process_socket(&i); |
| return; |
| } |
| if (Selinet) |
| return; |
| ity = i.i_fstyp; |
| type = i.i_ftype & IFMT; |
| if (ity < 1 || ity > Fsinfomax || !Fsinfo[ity-1]) { |
| |
| #if OSRV>=500 |
| if (ity) { |
| #endif /* OSRV>=500 */ |
| |
| (void) snpf(Namech,Namechl,"unknown fstyp (%d) in inode",ity); |
| enter_nm(Namech); |
| return; |
| |
| #if OSRV>=500 |
| } |
| #endif /* OSRV>=500 */ |
| |
| } |
| if (ity && strcasecmp(Fsinfo[ity-1], "HS") == 0) |
| Ntype = N_HSFS; |
| |
| #if defined(HAS_NFS) |
| else if (ity && strcasecmp(Fsinfo[ity-1], "NFS") == 0) { |
| |
| /* |
| * Get information on NFS file. |
| */ |
| Ntype = N_NFS; |
| Lf->is_nfs = 1; |
| if (Fnfs) |
| Lf->sf |= SELNFS; |
| if (!i.i_fsptr || readrnode((KA_T)i.i_fsptr, &r)) { |
| (void) snpf(Namech, Namechl, "can't read rnode (%s)", |
| print_kptr((KA_T)i.i_fsptr, (char *)NULL, 0)); |
| enter_nm(Namech); |
| return; |
| } |
| |
| # if defined(HASNCACHE) |
| Lf->na = (KA_T)i.i_fsptr; |
| # endif /* defined(HASNCACHE) */ |
| |
| } |
| #endif /* defined(HAS_NFS) */ |
| |
| else { |
| |
| /* |
| * Determine the node type from the inode file type. |
| */ |
| switch (type) { |
| case IFBLK: |
| Ntype = N_BLK; |
| break; |
| case IFCHR: |
| Ntype = N_CHR; |
| break; |
| case IFIFO: |
| Ntype = N_FIFO; |
| break; |
| case IFMPB: |
| case IFMPC: |
| Ntype = N_MPC; |
| break; |
| case IFNAM: |
| Ntype = N_NM; |
| break; |
| } |
| } |
| /* |
| * Obtain lock information. |
| */ |
| if ((flf = (KA_T)i.i_filocks)) { |
| flp = flf; |
| do { |
| if ((kread(flp, (char *)&fl, sizeof(fl)))) |
| break; |
| if (fl.set.l_pid != (pid_t)Lp->pid) |
| continue; |
| if (fl.set.l_whence == (short)0 && fl.set.l_start == (off_t)0 |
| && fl.set.l_len == 0x7fffffff) |
| l = 1; |
| else |
| l = 0; |
| |
| #if OSRV<500 |
| if (i.i_flag & IXLOCKED) |
| #else /* OSRV>=500 */ |
| if (fl.flags & F_XOUT) |
| #endif /* OSRV<500 */ |
| |
| Lf->lock = l ? 'X' : 'x'; |
| else if (fl.set.l_type == F_RDLCK) |
| Lf->lock = l ? 'R' : 'r'; |
| else if (fl.set.l_type == F_WRLCK) |
| Lf->lock = l ? 'W' : 'w'; |
| else if (fl.set.l_type == (F_RDLCK | F_WRLCK)) |
| Lf->lock = 'u'; |
| break; |
| } while ((flp = (KA_T)fl.next) && flp != flf); |
| } |
| |
| #if OSRV>=500 |
| /* |
| * See if a FIFO node is an HPPS node -- 3.2v5.0.0 and higher. |
| */ |
| if (Ntype == N_FIFO && ity && strcasecmp(Fsinfo[ity-1], "HPPS") == 0) |
| { |
| hpps = 1; |
| if (i.i_fsptr) { |
| enter_dev_ch(print_kptr((KA_T)i.i_fsptr, (char )NULL, 0)); |
| if (kread((KA_T)i.i_fsptr, (char *)&pi, sizeof(pi)) == 0) |
| hpps = 2; |
| } |
| } |
| #endif /* OSRV>=500 */ |
| |
| /* |
| * Determine the device. |
| */ |
| switch (Ntype) { |
| case N_BLK: |
| Lf->dev = i.i_dev; |
| Lf->rdev = i.i_rdev; |
| Lf->dev_def = Lf->rdev_def = 1; |
| break; |
| case N_FIFO: |
| case N_HSFS: |
| case N_NM: |
| case N_REGLR: |
| |
| #if OSRV>=500 |
| if (hpps) |
| break; |
| #endif /* OSRV>=500 */ |
| |
| Lf->dev = i.i_dev; |
| Lf->dev_def = 1; |
| break; |
| case N_CHR: |
| Lf->dev = i.i_dev; |
| Lf->rdev = i.i_rdev; |
| Lf->dev_def = Lf->rdev_def = 1; |
| if (i.i_sptr) { |
| |
| /* |
| * Namech may be: |
| * /dev/* name if it exists for i.i_rdev; |
| * cdevsw[].d_name if it exists for GET_MAJ_DEV(i.i_rdev); |
| * "STR:" otherwise. |
| */ |
| (void) snpf(Namech, Namechl, "STR:"); |
| Lf->is_stream = 1; |
| k = strlen(Namech); |
| cp = (char *)NULL; |
| if ((dp = finddev(&Lf->dev, &Lf->rdev, 1))) { |
| (void) snpf(&Namech[k], Namechl - k, dp->name); |
| k += strlen(dp->name); |
| if ((cp = strrchr(dp->name, '/'))) |
| cp++; |
| } else if ((j = GET_MAJ_DEV(i.i_rdev)) |
| < Cdevcnt && (cp = Cdevsw[j])) |
| { |
| (void) snpf(Namech, Namechl, "%s", cp); |
| k += strlen(cp); |
| } |
| /* |
| * Get the module names of all queue elements of the stream's |
| * sd_wrq queue. Skip module names that end in "head", |
| * match the last component of the /dev name, or match the |
| * cdevsw[].d_name. |
| */ |
| p = (KA_T)NULL; |
| if (!kread((KA_T)i.i_sptr, (char *)&sd, sizeof(sd))) { |
| dl = sizeof(tbuf) - 1; |
| tbuf[dl] = '\0'; |
| qp = (KA_T)sd.sd_wrq; |
| for (j = 0; qp && j < 20; j++, qp = (KA_T)q.q_next) { |
| if (kread(qp, (char *)&q, sizeof(q))) |
| break; |
| if (!(ka = (KA_T)q.q_qinfo) |
| || kread(ka, (char *)&qi, sizeof(qi))) |
| continue; |
| if (!(ka = (KA_T)qi.qi_minfo) |
| || kread(ka, (char *)&mi, sizeof(mi))) |
| continue; |
| if (!(ka = (KA_T)mi.mi_idname) |
| || kread(ka, tbuf, dl)) |
| continue; |
| if ((l = strlen(tbuf)) < 1) |
| continue; |
| if (l >= 4 && strcmp(&tbuf[l - 4], "head") == 0) |
| continue; |
| if (cp && strcmp(cp, tbuf) == 0) { |
| if (q.q_ptr && pt < 0) { |
| |
| /* |
| * If this is a TCP or UDP module and the |
| * queue structure has a private pointer in |
| * q_ptr, save it as a PCB address. |
| */ |
| if (strcasecmp(cp, "tcp") == 0) { |
| pt = 0; |
| (void) snpf(Lf->iproto, |
| sizeof(Lf->iproto), "TCP"); |
| } else if (strcasecmp(cp, "udp") == 0) { |
| pt = 1; |
| (void) snpf(Lf->iproto, |
| sizeof(Lf->iproto), "UDP"); |
| } |
| if (pt >= 0) |
| p = (KA_T)q.q_ptr; |
| else |
| pt = -1; |
| } |
| continue; |
| } |
| if (k) { |
| if ((k + 2) > (Namechl - 1)) |
| break; |
| (void) snpf(&Namech[k], Namechl - k, "->"); |
| k += 2; |
| } |
| if ((k + l) > (Namechl - 1)) |
| break; |
| (void) snpf(&Namech[k], Namechl - k, tbuf); |
| k += l; |
| } |
| } |
| if (p && pt >= 0) { |
| |
| /* |
| * If the stream has a TCP or UDP module with a PCB pointer, |
| * print any associated local and foreign Internet addresses. |
| */ |
| if (kread(p, (char *)&pcb, sizeof(pcb))) |
| break; |
| if (Fnet) |
| Lf->sf |= SELNET; |
| if ((k + 1) > (Namechl - 1)) |
| break; |
| if (pt == 1 && pcb.inp_ppcb) { |
| |
| /* |
| * If this is a UDP stream, get the udpdev structure at the |
| * PCB's per-protocol address. It may contain addresses. |
| */ |
| if (kread((KA_T)pcb.inp_ppcb, (char *)&udp, sizeof(udp)) |
| == 0) { |
| |
| #if OSRV>=500 |
| if (udp.ud_lsin.sin_addr.s_addr != INADDR_ANY |
| || udp.ud_lsin.sin_port != 0) |
| udpsl = 1; |
| else |
| udpsl = 0; |
| #endif /* OSRV>=500 */ |
| |
| if (udp.ud_fsin.sin_addr.s_addr != INADDR_ANY |
| || udp.ud_fsin.sin_port != 0) |
| udpsf = 1; |
| else |
| udpsf = 0; |
| } |
| } else |
| udpsf = udpsl = 0; |
| /* |
| * Enter the local address from the PCB. If there is none, |
| * and if this is a 5.0.0 or greater UDP stream, and if it |
| * has a local address set, use it. |
| */ |
| la = (unsigned char *)&pcb.inp_laddr; |
| lp = (int)ntohs(pcb.inp_lport); |
| |
| #if OSRV>=500 |
| if (((struct in_addr *)la)->s_addr == INADDR_ANY |
| && lp == 0 && udpsl) { |
| la = (unsigned char *)&udp.ud_lsin.sin_addr; |
| lp = (int)ntohs(udp.ud_lsin.sin_port); |
| } |
| |
| #endif /* OSRV>=500 */ |
| |
| /* |
| * Enter the foreign address from the PCB. If there is |
| * none, and if this is a 5.0.0 or greater UDP stream, and |
| * if it has a local address set, use it. |
| */ |
| if (pcb.inp_faddr.s_addr!=INADDR_ANY || pcb.inp_fport!=0) { |
| fa = (unsigned char *)&pcb.inp_faddr; |
| fp = (int)ntohs(pcb.inp_fport); |
| } else if (udpsf) { |
| fa = (unsigned char *)&udp.ud_fsin.sin_addr; |
| fp = (int)ntohs(udp.ud_fsin.sin_port); |
| udptm = 1; |
| } |
| if (fa || la) { |
| (void) ent_inaddr(la, lp, fa, fp, AF_INET); |
| if (udptm && !Lf->nma) |
| (void) udp_tm(udp.ud_ftime); |
| } |
| if (!i.i_number) |
| Lf->inp_ty = 2; |
| } |
| } else { |
| if (ity) { |
| if (strcasecmp(Fsinfo[ity-1], "COM") == 0) |
| Ntype = N_COM; |
| else |
| Ntype = N_CHR; |
| } else { |
| Ntype = N_CHR; |
| if (!finddev(&i.i_dev, &i.i_rdev, 0) |
| && HaveEventMajor |
| && GET_MAJ_DEV(i.i_rdev) == EventMajor) |
| (void) snpf(Namech, Namechl, |
| "clone %d:/dev/event", GET_MIN_DEV(i.i_rdev)); |
| } |
| } |
| break; |
| |
| #if defined(HAS_NFS) |
| case N_NFS: |
| |
| #if OSRV<500 |
| Lf->dev = (dev_t)_makedev(~GET_MAJ_DEV(i.i_dev), |
| GET_MIN_DEV(i.i_dev)); |
| Lf->rdev = (dev_t)_makedev(~GET_MAJ_DEV(i.i_rdev), |
| GET_MIN_DEV(i.i_rdev)); |
| #else /* OSRV>=500 */ |
| Lf->dev = i.i_dev; |
| Lf->rdev = i.i_rdev; |
| #endif /* OSRV<500 */ |
| |
| Lf->dev_def = Lf->rdev_def = 1; |
| break; |
| #endif /* defined(HAS_NFS) */ |
| |
| } |
| /* |
| * Determine the inode number. |
| */ |
| switch (Ntype) { |
| case N_HSFS: |
| |
| #if OSRV<500 |
| /* |
| * High Sierra inode numbers for versions below 5.0.0, as reported |
| * by "ls -i" and stat(2), are the lower 16 bits of i_number. |
| */ |
| if ((Lf->inode = (unsigned long)(i.i_number & 0xffff))) |
| #else /* OSRV>=500 */ |
| if ((Lf->inode = (unsigned long)i.i_number)) |
| #endif /* OSRV<500 */ |
| |
| Lf->inp_ty = 1; |
| break; |
| |
| #if defined(HAS_NFS) |
| case N_NFS: |
| |
| #if OSRV<500 |
| n = (unsigned short *)&r.r_fh.fh_pad[14]; |
| if ((Lf->inode = (unsigned long)ntohs(*n))) |
| Lf->inp_ty = 1; |
| else if ((Lf->inode = (unsigned long)r.r_fh.fh_u.fh_fgen_u)) |
| #else /* OSRV>=500 */ |
| n = (unsigned short *)&r.r_fh.fh_u.fh_fid_u[4]; |
| n1 = (unsigned short *)&r.r_fh.fh_u.fh_fid_u[2]; |
| if ((Lf->inode = (unsigned long)*n)) |
| Lf->inp_ty = 1; |
| else if ((Lf->inode = (unsigned long)*n1)) |
| #endif /* OSRV<500 */ |
| |
| Lf->inp_ty = 1; |
| break; |
| #endif /* defined(HAS_NFS) */ |
| |
| case N_BLK: |
| case N_CHR: |
| case N_COM: |
| case N_FIFO: |
| case N_NM: |
| case N_REGLR: |
| |
| #if OSRV>=500 |
| /* |
| * Inodes for some 5.0.x HPPS FIFOs have an i_number that is the same |
| * as i_fsptr. If it is, ignore it, because i_fsptr has already been |
| * recorded for the DEVICE column. |
| */ |
| if (hpps && i.i_fsptr && i.i_number |
| && (unsigned long)i.i_fsptr == (unsigned long)i.i_number) |
| break; |
| #endif /* OSRV>=500 */ |
| |
| if (i.i_number) { |
| Lf->inode = (unsigned long)i.i_number; |
| Lf->inp_ty = 1; |
| } |
| break; |
| } |
| /* |
| * Determine the file size. |
| */ |
| if (Foffset) |
| Lf->off_def = 1; |
| else { |
| switch (Ntype) { |
| case N_BLK: |
| if (!Fsize) |
| Lf->off_def = 1; |
| break; |
| case N_CHR: |
| case N_COM: |
| if (!Fsize) |
| Lf->off_def = 1; |
| break; |
| case N_FIFO: |
| |
| #if OSRV>=500 |
| if (hpps == 2) { |
| Lf->sz = (SZOFFTYPE)pi.count; |
| Lf->sz_def = 1; |
| break; |
| } |
| #endif /* OSRV>=500 */ |
| |
| if (!Fsize) |
| Lf->off_def = 1; |
| break; |
| case N_HSFS: |
| |
| #if defined(HAS_NFS) |
| case N_NFS: |
| Lf->sz = (SZOFFTYPE)i.i_size; |
| Lf->sz_def = 1; |
| break; |
| #endif /* defined(HAS_NFS) */ |
| |
| case N_REGLR: |
| if (type == IFREG || type == IFDIR) { |
| Lf->sz = (SZOFFTYPE)i.i_size; |
| Lf->sz_def = 1; |
| } |
| break; |
| } |
| } |
| /* |
| * Record link count. |
| */ |
| if (Fnlink) { |
| Lf->nlink = (long)i.i_nlink; |
| Lf->nlink_def = 1; |
| if (Nlink && (Lf->nlink < Nlink)) |
| Lf->sf |= SELNLINK; |
| } |
| /* |
| * Format the type name. |
| */ |
| switch (type) { |
| case IFDIR: |
| tn = "DIR"; |
| break; |
| case IFBLK: |
| tn = "BLK"; |
| break; |
| case IFCHR: |
| tn = "CHR"; |
| break; |
| case IFREG: |
| tn = "REG"; |
| break; |
| case IFMPC: |
| tn = "MPC"; |
| break; |
| case IFMPB: |
| tn = "MPB"; |
| break; |
| case IFNAM: |
| if (i.i_rdev == S_INSEM) |
| tn = "XSEM"; |
| else if (i.i_rdev == S_INSHD) |
| tn = "XSD"; |
| else { |
| tn = "XNAM"; |
| (void) snpf(Namech, Namechl, |
| "unknown Xenix special file type: %x", i.i_rdev); |
| } |
| break; |
| case IFIFO: |
| tn = "FIFO"; |
| break; |
| |
| #if defined(IFLNK) |
| case IFLNK: |
| tn = "LINK"; |
| break; |
| #endif /* defined(IFLNK) */ |
| |
| default: |
| (void) snpf(Lf->type, sizeof(Lf->type), "%04o", |
| ((type >> 12) & 0xfff)); |
| tn = NULL; |
| } |
| if (tn) |
| (void) snpf(Lf->type, sizeof(Lf->type), "%s", tn); |
| /* |
| * Save the file system names. |
| */ |
| switch (Ntype) { |
| case N_BLK: |
| case N_CHR: |
| case N_FIFO: |
| case N_HSFS: |
| |
| #if defined(HAS_NFS) |
| case N_NFS: |
| #endif /* defined(HAS_NFS) */ |
| |
| case N_NM: |
| case N_REGLR: |
| if (Lf->dev_def) { |
| |
| /* |
| * Defer the local mount info table search until printname(). |
| */ |
| Lf->lmi_srch = 1; |
| } |
| break; |
| } |
| Lf->ntype = Ntype; |
| |
| #if defined(HASBLKDEV) |
| /* |
| * If this is a IFBLK file and it's missing an inode number, try to |
| * supply one. |
| */ |
| if ((Lf->inp_ty == 0) && (type == IFBLK)) |
| find_bl_ino(); |
| #endif /* defined(HASBLKDEV) */ |
| |
| /* |
| * If this is a IFCHR file and it's missing an inode number, try to |
| * supply one. |
| */ |
| if ((Lf->inp_ty == 0) && (type == IFCHR)) |
| find_ch_ino(); |
| /* |
| * Test for specified file. |
| */ |
| if (Sfile && is_file_named((char *)NULL, |
| ((type == IFCHR) || (type == IFBLK) || (type == IFNAM)) ? 1 |
| : 0)) |
| Lf->sf |= SELNM; |
| |
| #if OSRV>=500 |
| /* |
| * If this is an HPPS node and no other name characters have been |
| * entered, enter HPPS as the name. |
| */ |
| if (hpps && Namech[0] == '\0') |
| (void) snpf(Namech, Namechl, "HPPS"); |
| #endif /* OSRV>=500 */ |
| |
| /* |
| * Enter name characters. |
| */ |
| if (Namech[0]) |
| enter_nm(Namech); |
| } |