/*
 * dfile.c - Darwin file processing functions for /dev/kmem-based lsof
 */


/*
 * Copyright 2005 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 2005 Purdue Research Foundation.\nAll rights reserved.\n";
#endif


#include "lsof.h"


/*
 * Local definitions
 */

#if	DARWINV>=800
#define	file		fileglob
#define	f_flag		fg_flag
#define	f_type		fg_type
#define	f_count		fg_count
#define	f_ops		fg_ops
#define	f_offset	fg_offset
#define	f_data		fg_data
#endif	/* DARWINV>=800 */

#if	defined(HASPSXSEM)
#define	PSEMNAMLEN	31		/* from kern/posix_sem.c */
#endif	/* defined(HASPSXSEM) */

#if	defined(HASPSXSHM)
#define	PSHMNAMLEN	31		/* from kern/posix_shm.c */
#endif	/* defined(HASPSXSHM) */


/*
 * Local structure definitions
 */

#if	defined(HASPSXSEM)
struct pseminfo {			/* from kern/posix_sem.c */
    unsigned int psem_flags;
    unsigned int psem_usecount;
    mode_t psem_mode;
    uid_t psem_uid;
    gid_t psem_gid;
    char psem_name[PSEMNAMLEN + 1];
    void *psem_semobject;
    struct proc *sem_proc;
};

struct psemnode {
    struct pseminfo *pinfo;
};
#endif	/* defined(HASPSXSEM) */

#if	defined(HASPSXSHM)		/* from kern/posix_shm.c */
struct pshminfo {
    unsigned int pshm_flags;
    unsigned int pshm_usecount;
    off_t pshm_length;
    mode_t pshm_mode;
    uid_t pshm_uid;
    gid_t pshm_gid;
    char pshm_name[PSHMNAMLEN + 1];
    void *pshm_memobject;
};

struct pshmnode {
    off_t mapp_addr;

# if	DARWINV<800
    size_t map_size;
# else	/* DARWINV>=800 */
    user_size_t map_size;
# endif	/* DARWINV>=800 */

    struct pshminfo *pinfo;
};
#endif	/* defined(HASPSXSHM) */


#if	DARWINV>=800
/*
 * 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);
}
#endif	/* DARWINV>=800 */


#if	defined(HASKQUEUE)
/*
 * process_kqueue() -- process kqueue file
 */

void
process_kqueue(ka)
	KA_T ka;			/* kqueue file structure address */
{
	struct kqueue kq;		/* kqueue structure */

	(void) snpf(Lf->type, sizeof(Lf->type), "KQUEUE");
	enter_dev_ch(print_kptr(ka, (char *)NULL, 0));
	if (!ka || kread(ka, (char *)&kq, sizeof(kq)))
	    return;
	(void) snpf(Namech, Namechl, "count=%d, state=%#x", kq.kq_count,
	    kq.kq_state);
	enter_nm(Namech);
}
#endif	/* defined(HASKQUEUE) */


#if	DARWINV>=800
/*
 * process_pipe() - process a file structure whose type is DTYPE_PIPE
 */

void
process_pipe(pa)
	KA_T pa;			/* pipe structure address */
{
	(void) snpf(Lf->type, sizeof(Lf->type), "PIPE");
	enter_dev_ch(print_kptr(pa, (char *)NULL, 0));
	Namech[0] = '\0';
}
#endif	/* DARWINV>=800 */


#if	defined(HASPSXSEM)
/*
 * process_psxsem() -- process POSIX semaphore file
 */

void
process_psxsem(pa)
	KA_T pa;			/* psxsem file structure address */
{
	struct pseminfo pi;
 	struct psemnode pn;

	(void) snpf(Lf->type, sizeof(Lf->type), "PSXSEM");
	enter_dev_ch(print_kptr(pa, (char *)NULL, 0));
	if (!Fsize)
	    Lf->off_def = 1;
	if (pa && !kread(pa, (char *)&pn, sizeof(pn))) {
	    if (pn.pinfo && !kread((KA_T)pn.pinfo, (char *)&pi, sizeof(pi))) {
		if (pi.psem_name[0]) {
		    pi.psem_name[PSEMNAMLEN] = '\0';
		    (void) snpf(Namech, Namechl, "%s", pi.psem_name);
		    enter_nm(Namech);
		}
	    }
	}
}
#endif	/* defined(HASPSXSEM) */


#if	defined(HASPSXSHM)
/*
 * process_psxshm() -- process POSIX shared memory file
 */

void
process_psxshm(pa)
	KA_T pa;			/* psxshm file structure address */
{
	struct pshminfo pi;
	struct pshmnode pn;
	int pns = 0;

	(void) snpf(Lf->type, sizeof(Lf->type), "PSXSHM");
	enter_dev_ch(print_kptr(pa, (char *)NULL, 0));
	if (pa && !kread(pa, (char *)&pn, sizeof(pn))) {
	    pns = 1;
	    if (pn.pinfo && !kread((KA_T)pn.pinfo, (char *)&pi, sizeof(pi))) {
		if (pi.pshm_name[0]) {
		    pi.pshm_name[PSEMNAMLEN] = '\0';
		    (void) snpf(Namech, Namechl, "%s", pi.pshm_name);
		    enter_nm(Namech);
		} else if (pi.pshm_memobject) {
		    (void) snpf(Namech, Namechl, "obj=%s",
			print_kptr((KA_T)pi.pshm_memobject, (char *)NULL, 0));
		    enter_nm(Namech);
		}
	    }
	}
	if (Foffset)
	    Lf->off_def = 1;
	else if (pns) {
	    Lf->sz = (SZOFFTYPE)pn.map_size;
	    Lf->sz_def = 1;
	}
}
#endif	/* defined(HASPSXSHM) */


/*
 * process_file() - process file
 */

/*
 * The caller may define:
 *
 *	FILEPTR	as the name of the location to store a pointer
 *			to the current file struct -- e.g.,
 *
 *			struct file *foobar;
 *			#define FILEPTR	foobar
 */

void
process_file(fp)
	KA_T fp;			/* kernel file structure address */
{

#if	DARWINV<800
	struct file f;
#else	/* DARWINV>=800 */
	struct fileglob f;
	struct fileproc fileproc;
#endif	/* DARWINV>=800 */

	int flag;

#if	defined(FILEPTR)
/*
 * Save file structure address for process_node().
 */
	FILEPTR = &f;
#endif	/* defined(FILEPTR) */

/*
 * Read file structure.
 */

#if	DARWINV<800
	if (kread((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(Namech);
	    return;
	}
#else	/* DARWINV>=800 */
	if (kread((KA_T)fp, (char *)&fileproc, sizeof(fileproc))) {
	    (void) snpf(Namech, Namechl, "can't read fileproc struct from %s",
		print_kptr(fp, (char *)NULL, 0));
	    enter_nm(Namech);
	    return;
	}
	if (kread((KA_T)fileproc.f_fglob, (char *)&f, sizeof(f))) {
	    (void) snpf(Namech, Namechl, "can't read fileglob struct from %s",
		print_kptr((KA_T)fileproc.f_fglob, (char *)NULL, 0));
	    enter_nm(Namech);
	    return;
	}
#endif	/* DARWINV>=800 */

	Lf->off = (SZOFFTYPE)f.f_offset;
	if (f.f_count) {

	/*
	 * Construct access code.
	 */
	    if ((flag = (f.f_flag & (FREAD | FWRITE))) == FREAD)
		Lf->access = 'r';
	    else if (flag == FWRITE)
		Lf->access = 'w';
	    else if (flag == (FREAD | FWRITE))
		Lf->access = 'u';

#if	defined(HASFSTRUCT)
	/*
	 * Save file structure values.
	 */
	    if (Fsv & FSV_CT) {
		Lf->fct = (long)f.f_count;
		Lf->fsv |= FSV_CT;
	    }
	    if (Fsv & FSV_FA) {
		Lf->fsa = fp;
		Lf->fsv |= FSV_FA;
	    }
	    if (Fsv & FSV_FG) {
		Lf->ffg = (long)f.f_flag;
		Lf->fsv |= FSV_FG;
	    }
	    if (Fsv & FSV_NI) {
		Lf->fna = (KA_T)f.f_data;
		Lf->fsv |= FSV_NI;
	    }
#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((KA_T)f.f_data);
# endif	/* defined(HASPIPEFN) */
		return;
#endif	/* defined(DTYPE_PIPE) */

	    case DTYPE_VNODE:
		if (!Selinet)
		    process_node((KA_T)f.f_data);
		return;
	    case DTYPE_SOCKET:
		process_socket((KA_T)f.f_data);
		return;

#if	defined(HASKQUEUE)
	    case DTYPE_KQUEUE:
		process_kqueue((KA_T)f.f_data);
		return;
#endif	/* defined(HASKQUEUE) */

#if	defined(HASPSXSEM)
	    case DTYPE_PSXSEM:
		process_psxsem((KA_T)f.f_data);
		return;
#endif	/* defined(HASPSXSEM) */

#if	defined(HASPSXSHM)
	    case DTYPE_PSXSHM:
		process_psxshm((KA_T)f.f_data);
		return;
#endif	/* defined(HASPSXSHM) */

#if	defined(HASPRIVFILETYPE)
	    case PRIVFILETYPE:
		HASPRIVFILETYPE((KA_T)f.f_data);
		return;
#endif	/* defined(HASPRIVFILETYPE) */

	    default:
		if (f.f_type || f.f_ops) {
		    (void) snpf(Namech, Namechl,
			"%s file struct, ty=%#x, op=%p",
			print_kptr(fp, (char *)NULL, 0), f.f_type, f.f_ops);
		    enter_nm(Namech);
		    return;
		}
	    }
	}
	enter_nm("no more information");
}
