summaryrefslogtreecommitdiff
path: root/dialects/darwin/libproc/dfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'dialects/darwin/libproc/dfile.c')
-rw-r--r--dialects/darwin/libproc/dfile.c682
1 files changed, 682 insertions, 0 deletions
diff --git a/dialects/darwin/libproc/dfile.c b/dialects/darwin/libproc/dfile.c
new file mode 100644
index 0000000..bd8d81a
--- /dev/null
+++ b/dialects/darwin/libproc/dfile.c
@@ -0,0 +1,682 @@
+/*
+ * dfile.c -- Darwin file processing functions for libproc-based lsof
+ */
+
+
+/*
+ * Portions Copyright 2005-2007 Apple Inc. All rights reserved.
+ *
+ * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Allan Nathanson, Apple Inc., and Victor A. Abell, Purdue
+ * University.
+ *
+ * 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 Apple Inc. 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, Apple
+ * Inc. 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 2005-2007 Apple Inc. and Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dfile.c,v 1.8 2012/04/10 16:41:04 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+/*
+ * enter_file_info() -- enter file information
+ */
+
+void
+enter_file_info(pfi)
+ struct proc_fileinfo *pfi; /* pointer to process file info */
+{
+ int f;
+/*
+ * Construct access code
+ */
+ f = pfi->fi_openflags & (FREAD | FWRITE);
+ if (f == FREAD)
+ Lf->access = 'r';
+ else if (f == FWRITE)
+ Lf->access = 'w';
+ else if (f == (FREAD | FWRITE))
+ Lf->access = 'u';
+/*
+ * Save the offset / size
+ */
+ Lf->off = (SZOFFTYPE)pfi->fi_offset;
+ if (Foffset)
+ Lf->off_def = 1;
+/*
+ * Save file structure information as requested.
+ */
+ if (Fsv & FSV_FG) {
+ Lf->ffg = (long)pfi->fi_openflags;
+ Lf->fsv |= FSV_FG;
+ }
+}
+
+
+/*
+ * enter_vnode_info() -- enter vnode information
+ */
+
+void
+enter_vnode_info(vip)
+ struct vnode_info_path *vip; /* pointer to vnode info with path */
+{
+ char buf[32], *cp;
+ dev_t dev = 0;
+ int devs = 0;
+ struct mounts *mp;
+/*
+ * Derive file type.
+ */
+ switch ((int)(vip->vip_vi.vi_stat.vst_mode & S_IFMT)) {
+ case S_IFIFO:
+ cp = "FIFO";
+ Ntype = N_FIFO;
+ break;
+ case S_IFCHR:
+ cp = "CHR";
+ Ntype = N_CHR;
+ break;
+ case S_IFDIR:
+ cp = "DIR";
+ Ntype = N_REGLR;
+ break;
+ case S_IFBLK:
+ cp = "BLK";
+ Ntype = N_BLK;
+ break;
+ case S_IFREG:
+ cp = "REG";
+ Ntype = N_REGLR;
+ break;
+ default:
+ (void) snpf(buf, sizeof(buf), "%04o",
+ (((vip->vip_vi.vi_stat.vst_mode & S_IFMT) >> 12) & 0xfff));
+ cp = buf;
+ Ntype = N_REGLR;
+ }
+ if (!Lf->type[0])
+ (void) snpf(Lf->type, sizeof(Lf->type), "%s", cp);
+ Lf->ntype = Ntype;
+/*
+ * Save device number and path
+ */
+ switch (Ntype) {
+ case N_FIFO:
+ break;
+ case N_CHR:
+ case N_BLK:
+ Lf->rdev = vip->vip_vi.vi_stat.vst_rdev;
+ Lf->rdev_def = 1;
+ /* fall through */
+ default:
+ Lf->dev = dev = vip->vip_vi.vi_stat.vst_dev;
+ Lf->dev_def = devs = 1;
+ }
+/*
+ * Save path name.
+ */
+ vip->vip_path[sizeof(vip->vip_path) - 1] = '\0';
+ if (vip->vip_path[0] != '\0') {
+ Lf->V_path = mkstrcpy(vip->vip_path, (MALLOC_S *)NULL);
+ }
+/*
+ * Save node number.
+ */
+ Lf->inode = (INODETYPE)vip->vip_vi.vi_stat.vst_ino;
+ Lf->inp_ty = 1;
+/*
+ * Save link count, as requested.
+ */
+ if (Fnlink) {
+ Lf->nlink = vip->vip_vi.vi_stat.vst_nlink;
+ Lf->nlink_def = 1;
+ if (Nlink && (Lf->nlink < Nlink))
+ Lf->sf |= SELNLINK;
+ }
+/*
+ * If a device number is defined, locate file system and save its identity.
+ */
+ if (devs) {
+ for (mp = readmnt(); mp; mp = mp->next) {
+ if (dev == mp->dev) {
+ Lf->fsdir = mp->dir;
+ Lf->fsdev = mp->fsname;
+ if (mp->is_nfs && Fnfs)
+ Lf->sf |= SELNFS;
+ break;
+ }
+ }
+ }
+/*
+ * Save the file size.
+ */
+ switch (Ntype) {
+ case N_CHR:
+ case N_FIFO:
+ Lf->off_def = 1;
+ break;
+ default:
+ Lf->sz = (SZOFFTYPE)vip->vip_vi.vi_stat.vst_size;
+ Lf->sz_def = 1;
+ }
+/*
+ * Test for specified file.
+ */
+ if (Sfile && is_file_named(NULL,
+ ((Ntype == N_CHR) || (Ntype == N_BLK) ? 1
+ : 0)))
+ {
+ Lf->sf |= SELNM;
+ }
+/*
+ * Enter name characters.
+ */
+ if (!Lf->nm && Namech[0])
+ enter_nm(Namech);
+}
+
+
+/*
+ * err2nm() -- convert errno to a message in Namech
+ */
+
+void
+err2nm(pfx)
+ char *pfx; /* Namech message prefix */
+{
+ char *sfx;
+
+ switch (errno) {
+ case EBADF:
+
+ /*
+ * The file descriptor is no longer available.
+ */
+ sfx = "FD unavailable";
+ break;
+ case ESRCH:
+
+ /*
+ * The process is no longer available.
+ */
+ sfx = "process unavailable";
+ break;
+ default:
+
+ /*
+ * All other errors are reported with strerror() information.
+ */
+ sfx = strerror(errno);
+ }
+ (void) snpf(Namech, Namechl, "%s: %s", pfx, sfx);
+ enter_nm(Namech);
+}
+
+
+/*
+ * print_nm() -- print Name column
+ */
+void
+print_nm(lf)
+ struct lfile *lf;
+{
+ printname(0);
+#ifdef PROC_PIDLISTFILEPORTS
+ if (lf->fileport) {
+ (void) printf(" (fileport=0x%04x)", lf->fileport);
+ }
+#endif /* PROC_PIDLISTFILEPORTS */
+ putchar('\n');
+}
+
+
+/*
+ * print_v_path() -- print vnode's path
+ */
+
+int
+print_v_path(lf)
+ struct lfile *lf;
+{
+ if (lf->V_path) {
+ safestrprt(lf->V_path, stdout, 0);
+ return(1);
+ }
+ return(0);
+}
+
+
+/*
+ * process_atalk() -- process an Apple Talk file
+ */
+
+void
+process_atalk(pid, fd)
+ int pid; /* PID */
+ int32_t fd; /* FD */
+{
+ (void) snpf(Lf->type, sizeof(Lf->type), "ATALK");
+ return;
+}
+
+
+/*
+ * process_fsevents() -- process a file system events file
+ */
+
+void
+process_fsevents(pid, fd)
+ int pid; /* PID */
+ int32_t fd; /* FD */
+{
+ (void) snpf(Lf->type, sizeof(Lf->type), "FSEVENTS");
+}
+
+
+/*
+ * process_kqueue() -- process a kernel queue file
+ */
+
+void
+process_kqueue(pid, fd)
+ int pid; /* PID */
+ int32_t fd; /* FD */
+{
+ struct kqueue_fdinfo kq;
+ int nb;
+/*
+ * Get the kernel queue file information.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "KQUEUE");
+ nb = proc_pidfdinfo(pid, fd, PROC_PIDFDKQUEUEINFO, &kq, sizeof(kq));
+ if (nb <= 0) {
+ (void) err2nm("kqueue");
+ return;
+ } else if (nb < sizeof(kq)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDKQUEUEINFO);\n",
+ Pn, pid, fd);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(kq), nb);
+ Exit(1);
+ }
+/*
+ * Enter the kernel queue file information.
+ */
+ enter_file_info(&kq.pfi);
+/*
+ * Enter queue counts as NAME column information.
+ */
+ (void) snpf(Namech, Namechl,
+ "count=%" SZOFFPSPEC "u, state=%#x",
+ (SZOFFTYPE)kq.kqueueinfo.kq_stat.vst_size,
+ kq.kqueueinfo.kq_state);
+ enter_nm(Namech);
+}
+
+
+/*
+ * process_pipe() -- process pipe file
+ */
+
+static void
+process_pipe_common(pi)
+ struct pipe_fdinfo *pi;
+{
+ char dev_ch[32], *ep;
+ size_t sz;
+
+ (void) snpf(Lf->type, sizeof(Lf->type), "PIPE");
+/*
+ * Enter the pipe handle as the device.
+ */
+ (void) snpf(dev_ch, sizeof(dev_ch), "%s",
+ print_kptr((KA_T)pi->pipeinfo.pipe_handle, (char *)NULL, 0));
+ enter_dev_ch(dev_ch);
+/*
+ * Enable offset or size reporting.
+ */
+ if (Foffset)
+ Lf->off_def = 1;
+ else {
+ Lf->sz = (SZOFFTYPE)pi->pipeinfo.pipe_stat.vst_blksize;
+ Lf->sz_def = 1;
+ }
+/*
+ * If there is a peer handle, enter it in as NAME column information.
+ */
+ if (pi->pipeinfo.pipe_peerhandle) {
+ (void) snpf(Namech, Namechl, "->%s",
+ print_kptr((KA_T)pi->pipeinfo.pipe_peerhandle, (char *)NULL, 0));
+ enter_nm(Namech);
+ } else
+ Namech[0] = '\0';
+/*
+ * If the pipe has a count, add it to the NAME column.
+ */
+ if (pi->pipeinfo.pipe_stat.vst_size) {
+ ep = endnm(&sz);
+ (void) snpf(ep, sz, ", cnt=%" SZOFFPSPEC "u",
+ (SZOFFTYPE)pi->pipeinfo.pipe_stat.vst_size);
+ }
+}
+
+
+void
+process_pipe(pid, fd)
+ int pid; /* PID */
+ int32_t fd; /* FD */
+{
+ int nb;
+ struct pipe_fdinfo pi;
+/*
+ * Get pipe file information.
+ */
+ nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPIPEINFO, &pi, sizeof(pi));
+ if (nb <= 0) {
+ (void) err2nm("pipe");
+ return;
+ } else if (nb < sizeof(pi)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPIPEINFO);\n",
+ Pn, pid, fd);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(pi), nb);
+ Exit(1);
+ }
+
+ process_pipe_common(&pi);
+}
+
+
+#ifdef PROC_PIDLISTFILEPORTS
+void
+process_fileport_pipe(pid, fp)
+ int pid; /* PID */
+ uint32_t fp; /* FILEPORT */
+{
+ int nb;
+ struct pipe_fdinfo pi;
+/*
+ * Get pipe file information.
+ */
+ nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTPIPEINFO, &pi, sizeof(pi));
+ if (nb <= 0) {
+ (void) err2nm("pipe");
+ return;
+ } else if (nb < sizeof(pi)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FILEPORT %u; proc_pidfileportinfo(PROC_PIDFILEPORTPIPEINFO);\n",
+ Pn, pid, fp);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(pi), nb);
+ Exit(1);
+ }
+
+ process_pipe_common(&pi);
+}
+#endif /* PROC_PIDLISTFILEPORTS */
+
+
+/*
+ * process_psem() -- process a POSIX semaphore file
+ */
+
+void
+process_psem(pid, fd)
+ int pid; /* PID */
+ int32_t fd; /* FD */
+{
+ int nb;
+ struct psem_fdinfo ps;
+/*
+ * Get the sempaphore file information.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "PSXSEM");
+ nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPSEMINFO, &ps, sizeof(ps));
+ if (nb <= 0) {
+ (void) err2nm("semaphore");
+ return;
+ } else if (nb < sizeof(ps)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPSEMINFO);\n",
+ Pn, pid, fd);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(ps), nb);
+ Exit(1);
+ }
+/*
+ * Enter the semaphore file information.
+ */
+ enter_file_info(&ps.pfi);
+/*
+ * If there is a semaphore file name, enter it.
+ */
+ if (ps.pseminfo.psem_name[0]) {
+ ps.pseminfo.psem_name[sizeof(ps.pseminfo.psem_name) - 1] = '\0';
+ (void) snpf(Namech, Namechl, "%s", ps.pseminfo.psem_name);
+ enter_nm(Namech);
+ }
+/*
+ * Unless file size has been specifically requested, enable the printing of
+ * file offset.
+ */
+ if (!Fsize)
+ Lf->off_def = 1;
+}
+
+
+/*
+ * process_pshm() -- process POSIX shared memory file
+ */
+
+static void
+process_pshm_common(ps)
+ struct pshm_fdinfo *ps;
+{
+ (void) snpf(Lf->type, sizeof(Lf->type), "PSXSHM");
+/*
+ * Enter the POSIX shared memory file information.
+ */
+ enter_file_info(&ps->pfi);
+/*
+ * If the POSIX shared memory file has a path name, enter it; otherwise, if it
+ * has a mapping address, enter that.
+ */
+ if (ps->pshminfo.pshm_name[0]) {
+ ps->pshminfo.pshm_name[sizeof(ps->pshminfo.pshm_name) - 1] = '\0';
+ (void) snpf(Namech, Namechl, "%s", ps->pshminfo.pshm_name);
+ enter_nm(Namech);
+ } else if (ps->pshminfo.pshm_mappaddr) {
+ (void) snpf(Namech, Namechl, "obj=%s",
+ print_kptr((KA_T)ps->pshminfo.pshm_mappaddr, (char *)NULL, 0));
+ enter_nm(Namech);
+ }
+/*
+ * Enable offset or size reporting.
+ */
+ if (Foffset)
+ Lf->off_def = 1;
+ else {
+ Lf->sz = (SZOFFTYPE)ps->pshminfo.pshm_stat.vst_size;
+ Lf->sz_def = 1;
+ }
+}
+
+
+void
+process_pshm(pid, fd)
+ int pid; /* PID */
+ int32_t fd; /* FD */
+{
+ int nb;
+ struct pshm_fdinfo ps;
+/*
+ * Get the POSIX shared memory file information.
+ */
+ nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPSHMINFO, &ps, sizeof(ps));
+ if (nb <= 0) {
+ (void) err2nm("POSIX shared memory");
+ return;
+ } else if (nb < sizeof(ps)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPSHMINFO);\n",
+ Pn, pid, fd);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(ps), nb);
+ Exit(1);
+ }
+
+ process_pshm_common(&ps);
+}
+
+
+#ifdef PROC_PIDLISTFILEPORTS
+void
+process_fileport_pshm(pid, fp)
+ int pid; /* PID */
+ uint32_t fp; /* FILEPORT */
+{
+ int nb;
+ struct pshm_fdinfo ps;
+/*
+ * Get the POSIX shared memory file information.
+ */
+ nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTPSHMINFO, &ps, sizeof(ps));
+ if (nb <= 0) {
+ (void) err2nm("POSIX shared memory");
+ return;
+ } else if (nb < sizeof(ps)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FILEPORT %u; proc_pidfileportinfo(PROC_PIDFILEPORTPSHMINFO);\n",
+ Pn, pid, fp);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(ps), nb);
+ Exit(1);
+ }
+
+ process_pshm_common(&ps);
+}
+#endif /* PROC_PIDLISTFILEPORTS */
+
+
+/*
+ * process_vnode() -- process a vnode file
+ */
+
+static void
+process_vnode_common(vi)
+ struct vnode_fdinfowithpath *vi;
+{
+/*
+ * Enter the file and vnode information.
+ */
+ enter_file_info(&vi->pfi);
+ enter_vnode_info(&vi->pvip);
+}
+
+
+void
+process_vnode(pid, fd)
+ int pid; /* PID */
+ int32_t fd; /* FD */
+{
+ int nb;
+ struct vnode_fdinfowithpath vi;
+
+ nb = proc_pidfdinfo(pid, fd, PROC_PIDFDVNODEPATHINFO, &vi, sizeof(vi));
+ if (nb <= 0) {
+ if (errno == ENOENT) {
+
+ /*
+ * The file descriptor's vnode may have been revoked. This is a
+ * bit of a hack, since an ENOENT error might not always mean the
+ * descriptor's vnode has been revoked. As the libproc API
+ * matures, this code may need to be revisited.
+ */
+ enter_nm("(revoked)");
+ } else
+ (void) err2nm("vnode");
+ return;
+ } else if (nb < sizeof(vi)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FD %d: proc_pidfdinfo(PROC_PIDFDVNODEPATHINFO);\n",
+ Pn, pid, fd);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(vi), nb);
+ Exit(1);
+ }
+
+ process_vnode_common(&vi);
+}
+
+
+#ifdef PROC_PIDLISTFILEPORTS
+void
+process_fileport_vnode(pid, fp)
+ int pid; /* PID */
+ uint32_t fp; /* FILEPORT */
+{
+ int nb;
+ struct vnode_fdinfowithpath vi;
+
+ nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTVNODEPATHINFO, &vi, sizeof(vi));
+ if (nb <= 0) {
+ if (errno == ENOENT) {
+
+ /*
+ * The file descriptor's vnode may have been revoked. This is a
+ * bit of a hack, since an ENOENT error might not always mean the
+ * descriptor's vnode has been revoked. As the libproc API
+ * matures, this code may need to be revisited.
+ */
+ enter_nm("(revoked)");
+ } else
+ (void) err2nm("vnode");
+ return;
+ } else if (nb < sizeof(vi)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FILEPORT %u: proc_pidfdinfo(PROC_PIDFDVNODEPATHINFO);\n",
+ Pn, pid, fp);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(vi), nb);
+ Exit(1);
+ }
+
+ process_vnode_common(&vi);
+}
+#endif /* PROC_PIDLISTFILEPORTS */