blob: b3c9da663b585c043c8fb97db131ceaa2ce304a3 [file] [log] [blame]
/*
* 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.7 2011/08/07 22:52:30 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);
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);
}
/*
* 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);
}
/*
* 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);
}