fs_usage.c   [plain text]


/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.0 (the 'License').  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License."
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

/*
cc -I. -DPRIVATE -D__APPLE_PRIVATE -O -o fs_usage fs_usage.c
*/

#define	Default_DELAY	1	/* default delay interval */

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <strings.h>
#include <nlist.h>
#include <fcntl.h>
#include <string.h>
#include <dirent.h>

#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>

#include <libc.h>
#include <termios.h>
#include <sys/ioctl.h>

#ifndef KERNEL_PRIVATE
#define KERNEL_PRIVATE
#include <sys/kdebug.h>
#undef KERNEL_PRIVATE
#else
#include <sys/kdebug.h>
#endif /*KERNEL_PRIVATE*/

#include <sys/sysctl.h>
#include <errno.h>
#import <mach/clock_types.h>
#import <mach/mach_time.h>
#include <err.h>

extern int errno;



#define MAXINDEX 2048

typedef struct LibraryInfo {
     unsigned long address;
     char     *name;
} LibraryInfo;

LibraryInfo frameworkInfo[MAXINDEX];
int numFrameworks = 0;

char seg_addr_table[256]="/AppleInternal/Developer/seg_addr_table";

char *lookup_name();


/* 
   MAXCOLS controls when extra data kicks in.
   MAX_WIDE_MODE_COLS controls -w mode to get even wider data in path.
   If NUMPARMS changes to match the kernel, it will automatically
   get reflected in the -w mode output.
*/
#define NUMPARMS 23
#define PATHLENGTH (NUMPARMS*sizeof(long))
#define MAXCOLS 131
#define MAX_WIDE_MODE_COLS (PATHLENGTH + 80)

struct th_info {
        int  in_filemgr;
        int  thread;
        int  pid;
        int  type;
        int  arg1;
        int  arg2;
        int  arg3;
        int  arg4;
        int  child_thread;
        int  waited;
        double stime;
        long *pathptr;
        char pathname[PATHLENGTH + 1];   /* add room for null terminator */
};

#define MAX_THREADS 512
struct th_info th_state[MAX_THREADS];


int  cur_max = 0;
int  need_new_map = 1;
int  bias_secs;
int  wideflag = 0;
int  columns = 0;
int  select_pid_mode = 0;  /* Flag set indicates that output is restricted
			      to selected pids or commands */

int  one_good_pid = 0;    /* Used to fail gracefully when bad pids given */

char	*arguments = 0;
int     argmax = 0;

/*
 * Network only or filesystem only output filter
 * Default of zero means report all activity - no filtering
 */
#define FILESYS_FILTER    0x01
#define NETWORK_FILTER    0x02
#define CACHEHIT_FILTER   0x04
#define EXEC_FILTER	  0x08
#define DEFAULT_DO_NOT_FILTER  0x00

int filter_mode = CACHEHIT_FILTER;

#define NFS_DEV -1

struct diskrec {
        struct diskrec *next;
        char *diskname;
        int   dev;
};

struct diskio {
        struct diskio *next;
        struct diskio *prev;
        int  type;
        int  bp;
        int  dev;
        int  blkno;
        int  iosize;
        int  io_errno;
        int  issuing_thread;
        int  completion_thread;
        char issuing_command[MAXCOMLEN];
        double issued_time;
        double completed_time;
};

struct diskrec *disk_list = NULL;
struct diskio *free_diskios = NULL;
struct diskio *busy_diskios = NULL;

struct diskio *insert_diskio();
struct diskio *complete_diskio();
void    	free_diskio();
void		print_diskio();
void		format_print();
char           *find_disk_name();
void		cache_disk_names();
int 		ReadSegAddrTable();
void		mark_thread_waited(int);
int		check_filter_mode(struct th_info *, int, int, int, char *);
void		fs_usage_fd_set(unsigned int, unsigned int);
int		fs_usage_fd_isset(unsigned int, unsigned int);
void		fs_usage_fd_clear(unsigned int, unsigned int);
void		init_arguments_buffer();
int	        get_real_command_name(int, char *, int);
void            create_map_entry(int, int, char *);

void		enter_syscall();
void		exit_syscall();
void		extend_syscall();
void		kill_thread_map();

#define TRACE_DATA_NEWTHREAD   0x07000004
#define TRACE_DATA_EXEC        0x07000008
#define TRACE_STRING_NEWTHREAD 0x07010004
#define TRACE_STRING_EXEC      0x07010008

#define MACH_vmfault    0x01300000
#define MACH_pageout    0x01300004
#define MACH_sched      0x01400000
#define MACH_stkhandoff 0x01400008
#define VFS_LOOKUP      0x03010090
#define BSC_exit        0x040C0004

#define P_WrData	0x03020000
#define P_RdData	0x03020008
#define P_WrMeta	0x03020020
#define P_RdMeta	0x03020028
#define P_PgOut		0x03020040
#define P_PgIn		0x03020048
#define P_WrDataAsync	0x03020010
#define P_RdDataAsync	0x03020018
#define P_WrMetaAsync	0x03020030
#define P_RdMetaAsync	0x03020038
#define P_PgOutAsync	0x03020050
#define P_PgInAsync	0x03020058

#define P_WrDataDone	0x03020004
#define P_RdDataDone	0x0302000C
#define P_WrMetaDone	0x03020024
#define P_RdMetaDone	0x0302002C
#define P_PgOutDone	0x03020044
#define P_PgInDone	0x0302004C
#define P_WrDataAsyncDone	0x03020014
#define P_RdDataAsyncDone	0x0302001C
#define P_WrMetaAsyncDone	0x03020034
#define P_RdMetaAsyncDone	0x0302003C
#define P_PgOutAsyncDone	0x03020054
#define P_PgInAsyncDone		0x0302005C


#define MSC_map_fd   0x010c00ac

// Network related codes
#define	BSC_recvmsg  0x040C006C
#define	BSC_sendmsg  0x040C0070
#define	BSC_recvfrom 0x040C0074
#define BSC_accept   0x040C0078
#define BSC_select   0x040C0174
#define BSC_socket   0x040C0184
#define BSC_connect  0x040C0188
#define BSC_bind     0x040C01A0
#define BSC_listen   0x040C01A8
#define	BSC_sendto   0x040C0214
#define BSC_socketpair 0x040C021C

#define BSC_read     0x040C000C
#define BSC_write    0x040C0010
#define BSC_open     0x040C0014
#define BSC_close    0x040C0018
#define BSC_link     0x040C0024
#define BSC_unlink   0x040C0028
#define BSC_chdir    0x040c0030
#define BSC_fchdir   0x040c0034
#define BSC_mknod    0x040C0038	
#define BSC_chmod    0x040C003C	
#define BSC_chown    0x040C0040	
#define BSC_access   0x040C0084	
#define BSC_chflags  0x040C0088	
#define BSC_fchflags 0x040C008C
#define BSC_sync     0x040C0090
#define BSC_dup      0x040C00A4
#define BSC_revoke   0x040C00E0
#define BSC_symlink  0x040C00E4	
#define BSC_readlink 0x040C00E8
#define BSC_execve   0x040C00EC
#define BSC_chroot   0x040C00F4
#define BSC_dup2     0x040C0168
#define BSC_fsync    0x040C017C	
#define BSC_readv    0x040C01E0	
#define BSC_writev   0x040C01E4	
#define BSC_fchown   0x040C01EC	
#define BSC_fchmod   0x040C01F0	
#define BSC_rename   0x040C0200
#define BSC_mkfifo   0x040c0210	
#define BSC_mkdir    0x040C0220	
#define BSC_rmdir    0x040C0224
#define BSC_utimes   0x040C0228
#define BSC_futimes  0x040C022C
#define BSC_pread    0x040C0264
#define BSC_pread_extended    0x040E0264
#define BSC_pwrite   0x040C0268
#define BSC_pwrite_extended   0x040E0268
#define BSC_statfs   0x040C0274	
#define BSC_fstatfs  0x040C0278	
#define BSC_stat     0x040C02F0	
#define BSC_fstat    0x040C02F4	
#define BSC_lstat    0x040C02F8	
#define BSC_pathconf 0x040C02FC	
#define BSC_fpathconf     0x040C0300
#define BSC_getdirentries 0x040C0310
#define BSC_mmap     0x040c0314
#define BSC_lseek    0x040c031c
#define BSC_truncate 0x040C0320
#define BSC_ftruncate     0x040C0324
#define BSC_undelete 0x040C0334
#define BSC_statv    0x040C0364	
#define BSC_lstatv   0x040C0368	
#define BSC_fstatv   0x040C036C	
#define BSC_mkcomplex   0x040C0360	
#define BSC_getattrlist 0x040C0370	
#define BSC_setattrlist 0x040C0374	
#define BSC_getdirentriesattr 0x040C0378	
#define BSC_exchangedata  0x040C037C	
#define BSC_checkuseraccess   0x040C0380	
#define BSC_searchfs    0x040C0384
#define BSC_delete      0x040C0388
#define BSC_copyfile    0x040C038C
#define BSC_getxattr	0x040C03A8
#define BSC_fgetxattr	0x040C03AC
#define BSC_setxattr	0x040C03B0
#define BSC_fsetxattr	0x040C03B4
#define BSC_removexattr	0x040C03B8
#define BSC_fremovexattr      0x040C03BC
#define BSC_listxattr	0x040C03C0
#define BSC_flistxattr	0x040C03C4
#define BSC_fsctl       0x040C03C8
#define BSC_open_extended     0x040C0454
#define BSC_stat_extended     0x040C045C
#define BSC_lstat_extended    0x040C0460
#define BSC_fstat_extended    0x040C0464
#define BSC_chmod_extended    0x040C0468
#define BSC_fchmod_extended   0x040C046C
#define BSC_access_extended   0x040C0470
#define BSC_mkfifo_extended   0x040C048C
#define BSC_mkdir_extended    0x040C0490
#define BSC_load_shared_file  0x040C04A0
#define BSC_lchown	0x040C05B0

// Carbon File Manager support
#define FILEMGR_PBGETCATALOGINFO		 0x1e000020
#define FILEMGR_PBGETCATALOGINFOBULK	 0x1e000024
#define FILEMGR_PBCREATEFILEUNICODE		 0x1e000028
#define FILEMGR_PBCREATEDIRECTORYUNICODE 0x1e00002c
#define FILEMGR_PBCREATEFORK			 0x1e000030
#define FILEMGR_PBDELETEFORK			 0x1e000034
#define FILEMGR_PBITERATEFORK			 0x1e000038
#define FILEMGR_PBOPENFORK				 0x1e00003c
#define FILEMGR_PBREADFORK				 0x1e000040
#define FILEMGR_PBWRITEFORK				 0x1e000044
#define FILEMGR_PBALLOCATEFORK			 0x1e000048
#define FILEMGR_PBDELETEOBJECT			 0x1e00004c
#define FILEMGR_PBEXCHANGEOBJECT		 0x1e000050
#define FILEMGR_PBGETFORKCBINFO			 0x1e000054
#define FILEMGR_PBGETVOLUMEINFO			 0x1e000058
#define FILEMGR_PBMAKEFSREF				 0x1e00005c
#define FILEMGR_PBMAKEFSREFUNICODE		 0x1e000060
#define FILEMGR_PBMOVEOBJECT			 0x1e000064
#define FILEMGR_PBOPENITERATOR			 0x1e000068
#define FILEMGR_PBRENAMEUNICODE			 0x1e00006c
#define FILEMGR_PBSETCATALOGINFO		 0x1e000070
#define FILEMGR_PBSETVOLUMEINFO			 0x1e000074
#define FILEMGR_FSREFMAKEPATH			 0x1e000078
#define FILEMGR_FSPATHMAKEREF			 0x1e00007c

#define FILEMGR_PBGETCATINFO			 0x1e010000
#define FILEMGR_PBGETCATINFOLITE		 0x1e010004
#define FILEMGR_PBHGETFINFO				 0x1e010008
#define FILEMGR_PBXGETVOLINFO			 0x1e01000c
#define FILEMGR_PBHCREATE				 0x1e010010
#define FILEMGR_PBHOPENDF				 0x1e010014
#define FILEMGR_PBHOPENRF				 0x1e010018
#define FILEMGR_PBHGETDIRACCESS			 0x1e01001c
#define FILEMGR_PBHSETDIRACCESS			 0x1e010020
#define FILEMGR_PBHMAPID				 0x1e010024
#define FILEMGR_PBHMAPNAME				 0x1e010028
#define FILEMGR_PBCLOSE					 0x1e01002c
#define FILEMGR_PBFLUSHFILE				 0x1e010030
#define FILEMGR_PBGETEOF				 0x1e010034
#define FILEMGR_PBSETEOF				 0x1e010038
#define FILEMGR_PBGETFPOS				 0x1e01003c
#define FILEMGR_PBREAD					 0x1e010040
#define FILEMGR_PBWRITE					 0x1e010044
#define FILEMGR_PBGETFCBINFO			 0x1e010048
#define FILEMGR_PBSETFINFO				 0x1e01004c
#define FILEMGR_PBALLOCATE				 0x1e010050
#define FILEMGR_PBALLOCCONTIG			 0x1e010054
#define FILEMGR_PBSETFPOS				 0x1e010058
#define FILEMGR_PBSETCATINFO			 0x1e01005c
#define FILEMGR_PBGETVOLPARMS			 0x1e010060
#define FILEMGR_PBSETVINFO				 0x1e010064
#define FILEMGR_PBMAKEFSSPEC			 0x1e010068
#define FILEMGR_PBHGETVINFO				 0x1e01006c
#define FILEMGR_PBCREATEFILEIDREF		 0x1e010070
#define FILEMGR_PBDELETEFILEIDREF		 0x1e010074
#define FILEMGR_PBRESOLVEFILEIDREF		 0x1e010078
#define FILEMGR_PBFLUSHVOL				 0x1e01007c
#define FILEMGR_PBHRENAME				 0x1e010080
#define FILEMGR_PBCATMOVE				 0x1e010084
#define FILEMGR_PBEXCHANGEFILES			 0x1e010088
#define FILEMGR_PBHDELETE				 0x1e01008c
#define FILEMGR_PBDIRCREATE				 0x1e010090
#define FILEMGR_PBCATSEARCH				 0x1e010094
#define FILEMGR_PBHSETFLOCK				 0x1e010098
#define FILEMGR_PBHRSTFLOCK				 0x1e01009c
#define FILEMGR_PBLOCKRANGE				 0x1e0100a0
#define FILEMGR_PBUNLOCKRANGE			 0x1e0100a4


#define FILEMGR_CLASS   0x1e

#define MAX_PIDS 32
int    pids[MAX_PIDS];

int    num_of_pids = 0;
int    exclude_pids = 0;
int    exclude_default_pids = 1;

struct kinfo_proc *kp_buffer = 0;
int kp_nentries = 0;

#define SAMPLE_SIZE 60000

#define DBG_ZERO_FILL_FAULT   1
#define DBG_PAGEIN_FAULT      2
#define DBG_COW_FAULT         3
#define DBG_CACHE_HIT_FAULT   4

#define DBG_FUNC_ALL	(DBG_FUNC_START | DBG_FUNC_END)
#define DBG_FUNC_MASK	0xfffffffc

double divisor = 0.0;       /* Trace divisor converts to microseconds */

int mib[6];
size_t needed;
char  *my_buffer;

kbufinfo_t bufinfo = {0, 0, 0, 0, 0};

int total_threads = 0;
kd_threadmap *mapptr = 0;	/* pointer to list of threads */

/* defines for tracking file descriptor state */
#define FS_USAGE_FD_SETSIZE 256		/* Initial number of file descriptors per
					   thread that we will track */

#define FS_USAGE_NFDBITS      (sizeof (unsigned long) * 8)
#define FS_USAGE_NFDBYTES(n)  (((n) / FS_USAGE_NFDBITS) * sizeof (unsigned long))

typedef struct {
    unsigned int   fd_valid;       /* set if this is a valid entry */
    unsigned int   fd_thread;
    unsigned int   fd_setsize;     /* this is a bit count */
    unsigned long  *fd_setptr;     /* file descripter bitmap */
} fd_threadmap;

fd_threadmap *fdmapptr = 0;	/* pointer to list of threads for fd tracking */

int trace_enabled = 0;
int set_remove_flag = 1;

void set_numbufs();
void set_init();
void set_enable();
void sample_sc();
int quit();

/*
 *  signal handlers
 */

void leave()			/* exit under normal conditions -- INT handler */
{
        int i;
	void set_enable();
	void set_pidcheck();
	void set_pidexclude();
	void set_remove();

	set_enable(0);

	if (exclude_pids == 0) {
	        for (i = 0; i < num_of_pids; i++)
		        set_pidcheck(pids[i], 0);
	}
	else {
	        for (i = 0; i < num_of_pids; i++)
		        set_pidexclude(pids[i], 0);
	}
	set_remove();
	exit(0);
}


void get_screenwidth()
{
        struct winsize size;

	columns = MAXCOLS;

	if (isatty(1)) {
	        if (ioctl(1, TIOCGWINSZ, &size) != -1)
		        columns = size.ws_col;
	}
}


void sigwinch()
{
        if (!wideflag)
	        get_screenwidth();
}

int
exit_usage(char *myname) {

        fprintf(stderr, "Usage: %s [-e] [-w] [-f mode] [pid | cmd [pid | cmd]....]\n", myname);
	fprintf(stderr, "  -e    exclude the specified list of pids from the sample\n");
	fprintf(stderr, "        and exclude fs_usage by default\n");
	fprintf(stderr, "  -w    force wider, detailed, output\n");
	fprintf(stderr, "  -f    Output is based on the mode provided\n");
	fprintf(stderr, "          mode = \"network\"  Show only network related output\n");
	fprintf(stderr, "          mode = \"filesys\"  Show only file system related output\n");
	fprintf(stderr, "          mode = \"exec\"     Show only execs\n");
	fprintf(stderr, "          mode = \"cachehit\" In addition, show cachehits\n");
	fprintf(stderr, "  pid   selects process(s) to sample\n");
	fprintf(stderr, "  cmd   selects process(s) matching command string to sample\n");
	fprintf(stderr, "\n%s will handle a maximum list of %d pids.\n\n", myname, MAX_PIDS);
	fprintf(stderr, "By default (no options) the following processes are excluded from the output:\n");
	fprintf(stderr, "fs_usage, Terminal, telnetd, sshd, rlogind, tcsh, csh, sh\n\n");

	exit(1);
}

int
main(argc, argv)
	int	argc;
	char	*argv[];
{
	char	*myname = "fs_usage";
	int     i;
	char    ch;
	void getdivisor();
	void argtopid();
	void set_remove();
	void set_pidcheck();
	void set_pidexclude();
	int quit();

        if ( geteuid() != 0 ) {
            fprintf(stderr, "'fs_usage' must be run as root...\n");
            exit(1);
        }
	get_screenwidth();

	/* get our name */
	if (argc > 0) {
		if ((myname = rindex(argv[0], '/')) == 0) {
			myname = argv[0];
		}
		else {
			myname++;
		}
	}

	
       while ((ch = getopt(argc, argv, "ewf:")) != EOF) {
               switch(ch) {
                case 'e':
		    exclude_pids = 1;
		    exclude_default_pids = 0;
		    break;
                case 'w':
		    wideflag = 1;
		    if ((uint)columns < MAX_WIDE_MODE_COLS)
		      columns = MAX_WIDE_MODE_COLS;
		    break;
	       case 'f':
		   if (!strcmp(optarg, "network"))
		       filter_mode |= NETWORK_FILTER;
		   else if (!strcmp(optarg, "filesys"))
		       filter_mode |= FILESYS_FILTER;
		   else if (!strcmp(optarg, "cachehit"))
		       filter_mode &= ~CACHEHIT_FILTER;   /* turns on CACHE_HIT */
		   else if (!strcmp(optarg, "exec"))
		       filter_mode |= EXEC_FILTER;
		   break;
		       
	       default:
		 exit_usage(myname);		 
	       }
       }

        argc -= optind;
        argv += optind;

	/* If we process any list of pids/cmds, then turn off the defaults */
	if (argc > 0)
	  exclude_default_pids = 0;

	while (argc > 0 && num_of_pids < (MAX_PIDS - 1)) {
	  select_pid_mode++;
	  argtopid(argv[0]);
	  argc--;
	  argv++;
	}

	/* Exclude a set of default pids */
	if (exclude_default_pids)
	  {
	    argtopid("Terminal");
	    argtopid("telnetd");
	    argtopid("telnet");
	    argtopid("sshd");
	    argtopid("rlogind");
	    argtopid("tcsh");
	    argtopid("csh");
	    argtopid("sh");
	    exclude_pids = 1;
	  }

	if (exclude_pids)
	  {
	    if (num_of_pids < (MAX_PIDS - 1))
	        pids[num_of_pids++] = getpid();
	    else
	      exit_usage(myname);
	  }

#if 0
	for (i = 0; i < num_of_pids; i++)
	  {
	    if (exclude_pids)
	      fprintf(stderr, "exclude pid %d\n", pids[i]);
	    else
	      fprintf(stderr, "pid %d\n", pids[i]);
	  }
#endif

	/* set up signal handlers */
	signal(SIGINT, leave);
	signal(SIGQUIT, leave);
	signal(SIGHUP, leave);
	signal(SIGTERM, leave);
	signal(SIGWINCH, sigwinch);

	if ((my_buffer = malloc(SAMPLE_SIZE * sizeof(kd_buf))) == (char *)0)
	    quit("can't allocate memory for tracing info\n");

	ReadSegAddrTable();
        cache_disk_names();

	set_remove();
	set_numbufs(SAMPLE_SIZE);
	set_init();

	if (exclude_pids == 0) {
	        for (i = 0; i < num_of_pids; i++)
		        set_pidcheck(pids[i], 1);
	} else {
	        for (i = 0; i < num_of_pids; i++)
		        set_pidexclude(pids[i], 1);
	}

	if (select_pid_mode && !one_good_pid)
	  {
	    /* 
	       An attempt to restrict output to a given
	       pid or command has failed. Exit gracefully
	    */
	    set_remove();
	    exit_usage(myname);
	  }

	set_enable(1);
	getdivisor();
	init_arguments_buffer();


	/* main loop */

	while (1) {
	        usleep(1000 * 20);

		sample_sc();
	}
}

void
find_proc_names()
{
        size_t			bufSize = 0;
	struct kinfo_proc       *kp;
	int quit();

	mib[0] = CTL_KERN;
	mib[1] = KERN_PROC;
	mib[2] = KERN_PROC_ALL;
	mib[3] = 0;

	if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0)
		quit("trace facility failure, KERN_PROC_ALL\n");

	if((kp = (struct kinfo_proc *)malloc(bufSize)) == (struct kinfo_proc *)0)
	    quit("can't allocate memory for proc buffer\n");
	
	if (sysctl(mib, 4, kp, &bufSize, NULL, 0) < 0)
		quit("trace facility failure, KERN_PROC_ALL\n");

        kp_nentries = bufSize/ sizeof(struct kinfo_proc);
	kp_buffer = kp;
}


struct th_info *find_thread(int thread, int type) {
       struct th_info *ti;

       for (ti = th_state; ti < &th_state[cur_max]; ti++) {
	       if (ti->thread == thread) {
		       if (type == ti->type)
			       return(ti);
		       if (ti->in_filemgr) {
			       if (type == -1)
				       return(ti);
			       continue;
		       }
		       if (type == 0)
			       return(ti);
	       }
       }
       return ((struct th_info *)0);
}


void
mark_thread_waited(int thread) {
       struct th_info *ti;

       for (ti = th_state; ti < &th_state[cur_max]; ti++) {
	       if (ti->thread == thread) {
                    ti->waited = 1;
	       }
       }
}


void
set_enable(int val) 
{
	mib[0] = CTL_KERN;
	mib[1] = KERN_KDEBUG;
	mib[2] = KERN_KDENABLE;		/* protocol */
	mib[3] = val;
	mib[4] = 0;
	mib[5] = 0;		        /* no flags */
	if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
		quit("trace facility failure, KERN_KDENABLE\n");

	if (val)
	  trace_enabled = 1;
	else
	  trace_enabled = 0;
}

void
set_numbufs(int nbufs) 
{
	mib[0] = CTL_KERN;
	mib[1] = KERN_KDEBUG;
	mib[2] = KERN_KDSETBUF;
	mib[3] = nbufs;
	mib[4] = 0;
	mib[5] = 0;		        /* no flags */
	if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
		quit("trace facility failure, KERN_KDSETBUF\n");

	mib[0] = CTL_KERN;
	mib[1] = KERN_KDEBUG;
	mib[2] = KERN_KDSETUP;		
	mib[3] = 0;
	mib[4] = 0;
	mib[5] = 0;		        /* no flags */
	if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
		quit("trace facility failure, KERN_KDSETUP\n");
}

void
set_pidcheck(int pid, int on_off) 
{
        kd_regtype kr;

	kr.type = KDBG_TYPENONE;
	kr.value1 = pid;
	kr.value2 = on_off;
	needed = sizeof(kd_regtype);
	mib[0] = CTL_KERN;
	mib[1] = KERN_KDEBUG;
	mib[2] = KERN_KDPIDTR;
	mib[3] = 0;
	mib[4] = 0;
	mib[5] = 0;

	if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) {
	        if (on_off == 1)
		        fprintf(stderr, "pid %d does not exist\n", pid);
	}
	else {
	  one_good_pid++;
	}
}

/* 
   on_off == 0 turns off pid exclusion
   on_off == 1 turns on pid exclusion
*/
void
set_pidexclude(int pid, int on_off) 
{
        kd_regtype kr;

	one_good_pid++;

	kr.type = KDBG_TYPENONE;
	kr.value1 = pid;
	kr.value2 = on_off;
	needed = sizeof(kd_regtype);
	mib[0] = CTL_KERN;
	mib[1] = KERN_KDEBUG;
	mib[2] = KERN_KDPIDEX;
	mib[3] = 0;
	mib[4] = 0;
	mib[5] = 0;

	if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) {
	        if (on_off == 1)
		          fprintf(stderr, "pid %d does not exist\n", pid);
	}
}

void
get_bufinfo(kbufinfo_t *val)
{
        needed = sizeof (*val);
	mib[0] = CTL_KERN;
	mib[1] = KERN_KDEBUG;
	mib[2] = KERN_KDGETBUF;		
	mib[3] = 0;
	mib[4] = 0;
	mib[5] = 0;		/* no flags */

	if (sysctl(mib, 3, val, &needed, 0, 0) < 0)
		quit("trace facility failure, KERN_KDGETBUF\n");  

}

void
set_remove() 
{
        errno = 0;

	mib[0] = CTL_KERN;
	mib[1] = KERN_KDEBUG;
	mib[2] = KERN_KDREMOVE;		/* protocol */
	mib[3] = 0;
	mib[4] = 0;
	mib[5] = 0;		/* no flags */
	if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
	  {
	    set_remove_flag = 0;

	    if (errno == EBUSY)
		quit("the trace facility is currently in use...\n          fs_usage, sc_usage, and latency use this feature.\n\n");
	    else
		quit("trace facility failure, KERN_KDREMOVE\n");
	  }
}

void
set_init() 
{       kd_regtype kr;

	kr.type = KDBG_RANGETYPE;
	kr.value1 = 0;
	kr.value2 = -1;
	needed = sizeof(kd_regtype);
	mib[0] = CTL_KERN;
	mib[1] = KERN_KDEBUG;
	mib[2] = KERN_KDSETREG;		
	mib[3] = 0;
	mib[4] = 0;
	mib[5] = 0;		/* no flags */

	if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
		quit("trace facility failure, KERN_KDSETREG\n");

	mib[0] = CTL_KERN;
	mib[1] = KERN_KDEBUG;
	mib[2] = KERN_KDSETUP;		
	mib[3] = 0;
	mib[4] = 0;
	mib[5] = 0;		/* no flags */

	if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
		quit("trace facility failure, KERN_KDSETUP\n");
}

void
sample_sc()
{
	kd_buf *kd;
	int i, count;
	size_t needed;
	void read_command_map();
	void create_map_entry();

        /* Get kernel buffer information */
	get_bufinfo(&bufinfo);

	if (need_new_map) {
	        read_command_map();
	        need_new_map = 0;
	}
	needed = bufinfo.nkdbufs * sizeof(kd_buf);
	mib[0] = CTL_KERN;
	mib[1] = KERN_KDEBUG;
	mib[2] = KERN_KDREADTR;		
	mib[3] = 0;
	mib[4] = 0;
	mib[5] = 0;		/* no flags */

	if (sysctl(mib, 3, my_buffer, &needed, NULL, 0) < 0)
                quit("trace facility failure, KERN_KDREADTR\n");
	count = needed;

	if (bufinfo.flags & KDBG_WRAPPED) {
	        fprintf(stderr, "fs_usage: buffer overrun, events generated too quickly\n");

	        for (i = 0; i < cur_max; i++) {
			th_state[i].thread = 0;
			th_state[i].pid = 0;
			th_state[i].pathptr = (long *)0;
			th_state[i].pathname[0] = 0;
		}
		cur_max = 0;
		need_new_map = 1;
		
		set_enable(0);
		set_enable(1);
	}
	kd = (kd_buf *)my_buffer;
#if 0
	fprintf(stderr, "READTR returned %d items\n", count);
#endif
	for (i = 0; i < count; i++) {
	        int debugid, thread;
		int type, n;
		long *sargptr;
		uint64_t now;
		long long l_usecs;
		int secs;
		long curr_time;
		struct th_info *ti;
                struct diskio  *dio;


		thread  = kd[i].arg5;
		debugid = kd[i].debugid;
		type    = kd[i].debugid & DBG_FUNC_MASK;

                now = kd[i].timestamp & KDBG_TIMESTAMP_MASK;

		if (i == 0)
		{
		    /*
		     * Compute bias seconds after each trace buffer read.
		     * This helps resync timestamps with the system clock
		     * in the event of a system sleep.
		     */
		    l_usecs = (long long)(now / divisor);
		    secs = l_usecs / 1000000;
		    curr_time = time((long *)0);
		    bias_secs = curr_time - secs;
		}


		switch (type) {

                case P_RdMeta:
                case P_WrMeta:
                case P_RdData:
                case P_WrData:
                case P_PgIn:
                case P_PgOut:
                case P_RdMetaAsync:
                case P_WrMetaAsync:
                case P_RdDataAsync:
                case P_WrDataAsync:
                case P_PgInAsync:
                case P_PgOutAsync:
                    insert_diskio(type, kd[i].arg1, kd[i].arg2, kd[i].arg3, kd[i].arg4, thread, (double)now);
                    continue;
                
                case P_RdMetaDone:
                case P_WrMetaDone:
                case P_RdDataDone:
                case P_WrDataDone:
                case P_PgInDone:
                case P_PgOutDone:
                case P_RdMetaAsyncDone:
                case P_WrMetaAsyncDone:
                case P_RdDataAsyncDone:
                case P_WrDataAsyncDone:
                case P_PgInAsyncDone:
                case P_PgOutAsyncDone:
                    if ((dio = complete_diskio(kd[i].arg1, kd[i].arg4, kd[i].arg3, thread, (double)now))) {
                        print_diskio(dio);
                        free_diskio(dio);
                    }
                    continue;


		case TRACE_DATA_NEWTHREAD:
		    
		    for (n = 0, ti = th_state; ti < &th_state[MAX_THREADS]; ti++, n++) {
		        if (ti->thread == 0)
		           break;
		    }
		    if (ti == &th_state[MAX_THREADS])
		        continue;
		    if (n >= cur_max)
		        cur_max = n + 1;

		    ti->thread = thread;
		    ti->child_thread = kd[i].arg1;
		    ti->pid = kd[i].arg2;
		    continue;

		case TRACE_STRING_NEWTHREAD:
		    if ((ti = find_thread(thread, 0)) == (struct th_info *)0)
		            continue;
		    if (ti->child_thread == 0)
		            continue;
		    create_map_entry(ti->child_thread, ti->pid, (char *)&kd[i].arg1);

		    if (ti == &th_state[cur_max - 1])
		        cur_max--;
		    ti->child_thread = 0;
		    ti->thread = 0;
		    ti->pid = 0;
		    continue;
	
		case TRACE_DATA_EXEC:

		    for (n = 0, ti = th_state; ti < &th_state[MAX_THREADS]; ti++, n++) {
		        if (ti->thread == 0)
		           break;
		    }
		    if (ti == &th_state[MAX_THREADS])
		        continue;
		    if (n >= cur_max)
		        cur_max = n + 1;

		    ti->thread = thread;
		    ti->pid = kd[i].arg1;
		    continue;	    

		case TRACE_STRING_EXEC:
		    if ((ti = find_thread(thread, 0)) == (struct th_info *)0)
		    {
			/* this is for backwards compatibility */
			create_map_entry(thread, 0, (char *)&kd[i].arg1);
		    }
		    else
		    {
			create_map_entry(thread, ti->pid, (char *)&kd[i].arg1);

			if (ti == &th_state[cur_max - 1])
			    cur_max--;
			ti->thread = 0;
			ti->pid = 0;
		    }
		    continue;

		case BSC_exit:
		    kill_thread_map(thread);
		    continue;

		case MACH_sched:
		case MACH_stkhandoff:
                    mark_thread_waited(thread);
		    continue;

		case VFS_LOOKUP:
		    if ((ti = find_thread(thread, 0)) == (struct th_info *)0)
		            continue;

		    if (!ti->pathptr) {
			    sargptr = (long *)&ti->pathname[0];
			    memset(&ti->pathname[0], 0, (PATHLENGTH + 1));
			    *sargptr++ = kd[i].arg2;
			    *sargptr++ = kd[i].arg3;
			    *sargptr++ = kd[i].arg4;
			    ti->pathptr = sargptr;
		    } else {
		            sargptr = ti->pathptr;

			    /* 
			       We don't want to overrun our pathname buffer if the
			       kernel sends us more VFS_LOOKUP entries than we can
			       handle.
			    */

			    if ((long *)sargptr >= (long *)&ti->pathname[PATHLENGTH]) {
				continue;
			    }
                            /*
			      We need to detect consecutive vfslookup entries.
			      So, if we get here and find a START entry,
			      fake the pathptr so we can bypass all further
			      vfslookup entries.
			    */

			    if (debugid & DBG_FUNC_START) {
				(long *)ti->pathptr = (long *)&ti->pathname[PATHLENGTH];
				continue;
			    }

			    *sargptr++ = kd[i].arg1;
			    *sargptr++ = kd[i].arg2;
			    *sargptr++ = kd[i].arg3;
			    *sargptr++ = kd[i].arg4;
			    ti->pathptr = sargptr;
		    }
		    continue;
		}

		if (debugid & DBG_FUNC_START) {
		       char *p;

		       switch (type) {
			   case FILEMGR_PBGETCATALOGINFO:
					p = "GetCatalogInfo";
					break;
			   case FILEMGR_PBGETCATALOGINFOBULK:
					p = "GetCatalogInfoBulk";
					break;
			   case FILEMGR_PBCREATEFILEUNICODE:
					p = "CreateFileUnicode";
					break;
			   case FILEMGR_PBCREATEDIRECTORYUNICODE:
					p = "CreateDirectoryUnicode";
					break;
			   case FILEMGR_PBCREATEFORK:
					p = "PBCreateFork";
					break;
			   case FILEMGR_PBDELETEFORK:
					p = "PBDeleteFork";
					break;
			   case FILEMGR_PBITERATEFORK:
					p = "PBIterateFork";
					break;
			   case FILEMGR_PBOPENFORK:
					p = "PBOpenFork";
					break;
			   case FILEMGR_PBREADFORK:
					p = "PBReadFork";
					break;
			   case FILEMGR_PBWRITEFORK:
					p = "PBWriteFork";
					break;
			   case FILEMGR_PBALLOCATEFORK:
					p = "PBAllocateFork";
					break;
			   case FILEMGR_PBDELETEOBJECT:
					p = "PBDeleteObject";
					break;
			   case FILEMGR_PBEXCHANGEOBJECT:
					p = "PBExchangeObject";
					break;
			   case FILEMGR_PBGETFORKCBINFO:
					p = "PBGetForkCBInfo";
					break;
			   case FILEMGR_PBGETVOLUMEINFO:
					p = "PBGetVolumeInfo";
					break;
			   case FILEMGR_PBMAKEFSREF:
					p = "PBMakeFSRef";
					break;
			   case FILEMGR_PBMAKEFSREFUNICODE:
					p = "PBMakeFSRefUnicode";
					break;
			   case FILEMGR_PBMOVEOBJECT:
					p = "PBMoveObject";
					break;
			   case FILEMGR_PBOPENITERATOR:
					p = "PBOpenIterator";
					break;
			   case FILEMGR_PBRENAMEUNICODE:
					p = "PBRenameUnicode";
					break;
			   case FILEMGR_PBSETCATALOGINFO:
					p = "SetCatalogInfo";
					break;
			   case FILEMGR_PBSETVOLUMEINFO:
					p = "SetVolumeInfo";
					break;
			   case FILEMGR_FSREFMAKEPATH:
					p = "FSRefMakePath";
					break;
			   case FILEMGR_FSPATHMAKEREF:
					p = "FSPathMakeRef";
					break;
			   // SPEC based calls
			   case FILEMGR_PBGETCATINFO:
					p = "GetCatInfo";
					break;
			   case FILEMGR_PBGETCATINFOLITE:
					p = "GetCatInfoLite";
					break;
			   case FILEMGR_PBHGETFINFO:
					p = "PBHGetFInfo";
					break;
			   case FILEMGR_PBXGETVOLINFO:
					p = "PBXGetVolInfo";
					break;
			   case FILEMGR_PBHCREATE:
					p = "PBHCreate";
					break;
			   case FILEMGR_PBHOPENDF:
					p = "PBHOpenDF";
					break;
			   case FILEMGR_PBHOPENRF:
					p = "PBHOpenRF";
					break;
			   case FILEMGR_PBHGETDIRACCESS:
					p = "PBHGetDirAccess";
					break;
			   case FILEMGR_PBHSETDIRACCESS:
					p = "PBHSetDirAccess";
					break;
			   case FILEMGR_PBHMAPID:
					p = "PBHMapID";
					break;
			   case FILEMGR_PBHMAPNAME:
					p = "PBHMapName";
					break;
			   case FILEMGR_PBCLOSE:
					p = "PBClose";
					break;
			   case FILEMGR_PBFLUSHFILE:
					p = "PBFlushFile";
					break;
			   case FILEMGR_PBGETEOF:
					p = "PBGetEOF";
					break;
			   case FILEMGR_PBSETEOF:
					p = "PBSetEOF";
					break;
			   case FILEMGR_PBGETFPOS:
					p = "PBGetFPos";
					break;
			   case FILEMGR_PBREAD:
					p = "PBRead";
					break;
			   case FILEMGR_PBWRITE:
					p = "PBWrite";
					break;
			   case FILEMGR_PBGETFCBINFO:
					p = "PBGetFCBInfo";
					break;
			   case FILEMGR_PBSETFINFO:
					p = "PBSetFInfo";
					break;
			   case FILEMGR_PBALLOCATE:
					p = "PBAllocate";
					break;
			   case FILEMGR_PBALLOCCONTIG:
					p = "PBAllocContig";
					break;
			   case FILEMGR_PBSETFPOS:
					p = "PBSetFPos";
					break;
			   case FILEMGR_PBSETCATINFO:
					p = "PBSetCatInfo";
					break;
			   case FILEMGR_PBGETVOLPARMS:
					p = "PBGetVolParms";
					break;
			   case FILEMGR_PBSETVINFO:
					p = "PBSetVInfo";
					break;
			   case FILEMGR_PBMAKEFSSPEC:
					p = "PBMakeFSSpec";
					break;
			   case FILEMGR_PBHGETVINFO:
					p = "PBHGetVInfo";
					break;
			   case FILEMGR_PBCREATEFILEIDREF:
					p = "PBCreateFileIDRef";
					break;
			   case FILEMGR_PBDELETEFILEIDREF:
					p = "PBDeleteFileIDRef";
					break;
			   case FILEMGR_PBRESOLVEFILEIDREF:
					p = "PBResolveFileIDRef";
					break;
			   case FILEMGR_PBFLUSHVOL:
					p = "PBFlushVol";
					break;
			   case FILEMGR_PBHRENAME:
					p = "PBHRename";
					break;
			   case FILEMGR_PBCATMOVE:
					p = "PBCatMove";
					break;
			   case FILEMGR_PBEXCHANGEFILES:
					p = "PBExchangeFiles";
					break;
			   case FILEMGR_PBHDELETE:
					p = "PBHDelete";
					break;
			   case FILEMGR_PBDIRCREATE:
					p = "PBDirCreate";
					break;
			   case FILEMGR_PBCATSEARCH:
					p = "PBCatSearch";
					break;
			   case FILEMGR_PBHSETFLOCK:
					p = "PBHSetFlock";
					break;
			   case FILEMGR_PBHRSTFLOCK:
					p = "PBHRstFLock";
					break;
			   case FILEMGR_PBLOCKRANGE:
					p = "PBLockRange";
					break;
			   case FILEMGR_PBUNLOCKRANGE:
					p = "PBUnlockRange";
					break;
			   default:
			    		p = (char *)0;
					break;
			}
		        enter_syscall(thread, type, &kd[i], p, (double)now);
			continue;
		}
		
		switch (type) {
		    
		case BSC_pread_extended:
		case BSC_pwrite_extended:
		    extend_syscall(thread, type, &kd[i], (double)now);

		case MACH_pageout:
		    if (kd[i].arg2) 
		            exit_syscall("PAGE_OUT_D", thread, type, 0, kd[i].arg1, 0, 4, (double)now);
		    else
		            exit_syscall("PAGE_OUT_V", thread, type, 0, kd[i].arg1, 0, 4, (double)now);
		    break;

		case MACH_vmfault:
		    if (kd[i].arg2 == DBG_PAGEIN_FAULT)
		            exit_syscall("PAGE_IN", thread, type, kd[i].arg4, kd[i].arg1, 0, 6, (double)now);
                    else if (kd[i].arg2 == DBG_CACHE_HIT_FAULT)
		            exit_syscall("CACHE_HIT", thread, type, 0, kd[i].arg1, 0, 2, (double)now);
		    else {
		            if ((ti = find_thread(thread, type))) {
			            if (ti == &th_state[cur_max - 1])
				            cur_max--;
				    ti->thread = 0;
			    }
		    }
		    break;

		case MSC_map_fd:
		    exit_syscall("map_fd", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_mmap:
		    exit_syscall("mmap", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
		    
		case BSC_recvmsg:
		    exit_syscall("recvmsg", thread, type, kd[i].arg1, kd[i].arg2, 1, 1, (double)now);
		    break;

		case BSC_sendmsg:
		    exit_syscall("sendmsg", thread, type, kd[i].arg1, kd[i].arg2, 1, 1, (double)now);
		    break;

		case BSC_recvfrom:
		    exit_syscall("recvfrom", thread, type, kd[i].arg1, kd[i].arg2, 1, 1, (double)now);
		    break;

		case BSC_accept:
		    exit_syscall("accept", thread, type, kd[i].arg1, kd[i].arg2, 2, 0, (double)now);
		    break;
		    
		case BSC_select:
		    exit_syscall("select", thread, type, kd[i].arg1, kd[i].arg2, 0, 8, (double)now);
		    break;
		    
		case BSC_socket:
		    exit_syscall("socket", thread, type, kd[i].arg1, kd[i].arg2, 2, 0, (double)now);
		    break;

		case BSC_connect:
		    exit_syscall("connect", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_bind:
		    exit_syscall("bind", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_listen:
		    exit_syscall("listen", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_sendto:
		    exit_syscall("sendto", thread, type, kd[i].arg1, kd[i].arg2, 1, 1, (double)now);
		    break;

		case BSC_socketpair:
		    exit_syscall("socketpair", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
		    
		case BSC_getxattr:
		    exit_syscall("getxattr", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_setxattr:
		    exit_syscall("setxattr", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_removexattr:
		    exit_syscall("removexattr", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_listxattr:
		    exit_syscall("listxattr", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_stat:
		    exit_syscall("stat", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_stat_extended:
		    exit_syscall("stat_extended", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_execve:
		    exit_syscall("execve", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_load_shared_file:
		    exit_syscall("load_sf", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_open:
		    exit_syscall("open", thread, type, kd[i].arg1, kd[i].arg2, 2, 0, (double)now);
		    break;

		case BSC_open_extended:
		    exit_syscall("open_extended", thread, type, kd[i].arg1, kd[i].arg2, 2, 0, (double)now);
		    break;

		case BSC_dup:
		    exit_syscall("dup", thread, type, kd[i].arg1, kd[i].arg2, 2, 0, (double)now);
		    break;

		case BSC_dup2:
		    exit_syscall("dup2", thread, type, kd[i].arg1, kd[i].arg2, 2, 0, (double)now);
		    break;		    

		case BSC_close:
		    exit_syscall("close", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_read:
		    exit_syscall("read", thread, type, kd[i].arg1, kd[i].arg2, 1, 1, (double)now);
		    break;

		case BSC_write:
		    exit_syscall("write", thread, type, kd[i].arg1, kd[i].arg2, 1, 1, (double)now);
		    break;

		case BSC_fgetxattr:
		    exit_syscall("fgetxattr", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_fsetxattr:
		    exit_syscall("fsetxattr", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_fremovexattr:
		    exit_syscall("fremovexattr", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_flistxattr:
		    exit_syscall("flistxattr", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_fstat:
		    exit_syscall("fstat", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_fstat_extended:
		    exit_syscall("fstat_extended", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_lstat:
		    exit_syscall("lstat", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_lstat_extended:
		    exit_syscall("lstat_extended", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_link:
		    exit_syscall("link", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_unlink:
		    exit_syscall("unlink", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_mknod:
		    exit_syscall("mknod", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_chmod:
		    exit_syscall("chmod", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_chmod_extended:
		    exit_syscall("chmod_extended", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_chown:
		    exit_syscall("chown", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_lchown:
		    exit_syscall("lchown", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_access:
		    exit_syscall("access", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_access_extended:
		    exit_syscall("access_extended", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_chdir:
		    exit_syscall("chdir", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_chroot:
		    exit_syscall("chroot", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_utimes:
		    exit_syscall("utimes", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_delete:
		    exit_syscall("delete", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_undelete:
		    exit_syscall("undelete", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_revoke:
		    exit_syscall("revoke", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_fsctl:
		    exit_syscall("fsctl", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_chflags:
		    exit_syscall("chflags", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_fchflags:
		    exit_syscall("fchflags", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;
                    
		case BSC_fchdir:
		    exit_syscall("fchdir", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;
                    
		case BSC_futimes:
		    exit_syscall("futimes", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_sync:
		    exit_syscall("sync", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_symlink:
		    exit_syscall("symlink", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_readlink:
		    exit_syscall("readlink", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_fsync:
		    exit_syscall("fsync", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_readv:
		    exit_syscall("readv", thread, type, kd[i].arg1, kd[i].arg2, 1, 1, (double)now);
		    break;

		case BSC_writev:
		    exit_syscall("writev", thread, type, kd[i].arg1, kd[i].arg2, 1, 1, (double)now);
		    break;

		case BSC_pread:
		    exit_syscall("pread", thread, type, kd[i].arg1, kd[i].arg2, 1, 9, (double)now);
		    break;

		case BSC_pwrite:
		    exit_syscall("pwrite", thread, type, kd[i].arg1, kd[i].arg2, 1, 9, (double)now);
		    break;

		case BSC_fchown:
		    exit_syscall("fchown", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_fchmod:
		    exit_syscall("fchmod", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_fchmod_extended:
		    exit_syscall("fchmod_extended", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_mkdir:
		    exit_syscall("mkdir", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_mkdir_extended:
		    exit_syscall("mkdir_extended", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
		case BSC_mkfifo:
		    exit_syscall("mkfifo", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_mkfifo_extended:
		    exit_syscall("mkfifo_extended", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_rmdir:
		    exit_syscall("rmdir", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_statfs:
		    exit_syscall("statfs", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_fstatfs:
		    exit_syscall("fstatfs", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_pathconf:
		    exit_syscall("pathconf", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_fpathconf:
		    exit_syscall("fpathconf", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_getdirentries:
		    exit_syscall("getdirentries", thread, type, kd[i].arg1, kd[i].arg2, 1, 1, (double)now);
		    break;

		case BSC_lseek:
		    exit_syscall("lseek", thread, type, kd[i].arg1, kd[i].arg3, 1, 5, (double)now);
		    break;

		case BSC_truncate:
		    exit_syscall("truncate", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_ftruncate:
		    exit_syscall("ftruncate", thread, type, kd[i].arg1, kd[i].arg2, 1, 3, (double)now);
		    break;

		case BSC_statv:
		    exit_syscall("statv", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_lstatv:
		    exit_syscall("lstatv", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_fstatv:
		    exit_syscall("fstatv", thread, type, kd[i].arg1, kd[i].arg2, 1, 0, (double)now);
		    break;

		case BSC_mkcomplex:
		    exit_syscall("mkcomplex", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_getattrlist:
		    exit_syscall("getattrlist", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_setattrlist:
		    exit_syscall("setattrlist", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_getdirentriesattr:
		    exit_syscall("getdirentriesattr", thread, type, kd[i].arg1, kd[i].arg2, 0, 1, (double)now);
		    break;


		case BSC_exchangedata:
		    exit_syscall("exchangedata", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
                    
 		case BSC_rename:
		    exit_syscall("rename", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

 		case BSC_copyfile:
		    exit_syscall("copyfile", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;


		case BSC_checkuseraccess:
		    exit_syscall("checkuseraccess", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

		case BSC_searchfs:
		    exit_syscall("searchfs", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;

	   case FILEMGR_PBGETCATALOGINFO:
		    exit_syscall("GetCatalogInfo", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBGETCATALOGINFOBULK:
		    exit_syscall("GetCatalogInfoBulk", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBCREATEFILEUNICODE:
		    exit_syscall("CreateFileUnicode", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBCREATEDIRECTORYUNICODE:
		    exit_syscall("CreateDirectoryUnicode", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBCREATEFORK:
		    exit_syscall("PBCreateFork", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBDELETEFORK:
		    exit_syscall("PBDeleteFork", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBITERATEFORK:
		    exit_syscall("PBIterateFork", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBOPENFORK:
		    exit_syscall("PBOpenFork", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBREADFORK:
		    exit_syscall("PBReadFork", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBWRITEFORK:
		    exit_syscall("PBWriteFork", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBALLOCATEFORK:
		    exit_syscall("PBAllocateFork", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBDELETEOBJECT:
		    exit_syscall("PBDeleteObject", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBEXCHANGEOBJECT:
		    exit_syscall("PBExchangeObject", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBGETFORKCBINFO:
		    exit_syscall("PBGetForkCBInfo", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBGETVOLUMEINFO:
		    exit_syscall("PBGetVolumeInfo", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBMAKEFSREF:
		    exit_syscall("PBMakeFSRef", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBMAKEFSREFUNICODE:
		    exit_syscall("PBMakeFSRefUnicode", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBMOVEOBJECT:
		    exit_syscall("PBMoveObject", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBOPENITERATOR:
		    exit_syscall("PBOpenIterator", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBRENAMEUNICODE:
		    exit_syscall("PBRenameUnicode", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBSETCATALOGINFO:
		    exit_syscall("PBSetCatalogInfo", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBSETVOLUMEINFO:
		    exit_syscall("PBSetVolumeInfo", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_FSREFMAKEPATH:
		    exit_syscall("FSRefMakePath", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_FSPATHMAKEREF:
		    exit_syscall("FSPathMakeRef", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBGETCATINFO:
		    exit_syscall("GetCatInfo", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBGETCATINFOLITE:
		    exit_syscall("GetCatInfoLite", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBHGETFINFO:
		    exit_syscall("PBHGetFInfo", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBXGETVOLINFO:
		    exit_syscall("PBXGetVolInfo", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBHCREATE:
		    exit_syscall("PBHCreate", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBHOPENDF:
		    exit_syscall("PBHOpenDF", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBHOPENRF:
		    exit_syscall("PBHOpenRF", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBHGETDIRACCESS:
		    exit_syscall("PBHGetDirAccess", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBHSETDIRACCESS:
		    exit_syscall("PBHSetDirAccess", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBHMAPID:
		    exit_syscall("PBHMapID", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBHMAPNAME:
		    exit_syscall("PBHMapName", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBCLOSE:
		    exit_syscall("PBClose", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBFLUSHFILE:
		    exit_syscall("PBFlushFile", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBGETEOF:
		    exit_syscall("PBGetEOF", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBSETEOF:
		    exit_syscall("PBSetEOF", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBGETFPOS:
		    exit_syscall("PBGetFPos", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBREAD:
		    exit_syscall("PBRead", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBWRITE:
		    exit_syscall("PBWrite", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBGETFCBINFO:
		    exit_syscall("PBGetFCBInfo", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBSETFINFO:
		    exit_syscall("PBSetFInfo", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBALLOCATE:
		    exit_syscall("PBAllocate", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBALLOCCONTIG:
		    exit_syscall("PBAllocContig", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBSETFPOS:
		    exit_syscall("PBSetFPos", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBSETCATINFO:
		    exit_syscall("PBSetCatInfo", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBGETVOLPARMS:
		    exit_syscall("PBGetVolParms", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBSETVINFO:
		    exit_syscall("PBSetVInfo", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBMAKEFSSPEC:
		    exit_syscall("PBMakeFSSpec", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBHGETVINFO:
		    exit_syscall("PBHGetVInfo", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBCREATEFILEIDREF:
		    exit_syscall("PBCreateFileIDRef", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBDELETEFILEIDREF:
		    exit_syscall("PBDeleteFileIDRef", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBRESOLVEFILEIDREF:
		    exit_syscall("PBResolveFileIDRef", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBFLUSHVOL:
		    exit_syscall("PBFlushVol", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBHRENAME:
		    exit_syscall("PBHRename", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBCATMOVE:
		    exit_syscall("PBCatMove", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBEXCHANGEFILES:
		    exit_syscall("PBExchangeFiles", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBHDELETE:
		    exit_syscall("PBHDelete", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBDIRCREATE:
		    exit_syscall("PBDirCreate", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBCATSEARCH:
		    exit_syscall("PBCatSearch", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBHSETFLOCK:
		    exit_syscall("PBHSetFLock", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBHRSTFLOCK:
		    exit_syscall("PBHRstFLock", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBLOCKRANGE:
		    exit_syscall("PBLockRange", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
	   case FILEMGR_PBUNLOCKRANGE:
		    exit_syscall("PBUnlockRange", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, (double)now);
		    break;
		default:
		    break;
		}
	}
	fflush(0);
}

void
enter_syscall(int thread, int type, kd_buf *kd, char *name, double now)
{
       struct th_info *ti;
       int    i;
       int    secs;
       int    usecs;
       long long l_usecs;
       long curr_time;
       kd_threadmap *map;
       kd_threadmap *find_thread_map();
       int clen = 0;
       int tsclen = 0;
       int nmclen = 0;
       int argsclen = 0;
       char buf[MAXCOLS];

       switch (type) {

       case MACH_pageout:
       case MACH_vmfault:
       case MSC_map_fd:
       case BSC_mmap:
       case BSC_recvmsg:
       case BSC_sendmsg:
       case BSC_recvfrom:
       case BSC_accept:
       case BSC_select:
       case BSC_socket:
       case BSC_connect:
       case BSC_bind:
       case BSC_listen:
       case BSC_sendto:
       case BSC_socketpair:
       case BSC_execve:
       case BSC_getxattr:
       case BSC_fgetxattr:
       case BSC_setxattr:
       case BSC_fsetxattr:
       case BSC_removexattr:
       case BSC_fremovexattr:
       case BSC_listxattr:
       case BSC_flistxattr:
       case BSC_open_extended:
       case BSC_stat_extended:
       case BSC_lstat_extended:
       case BSC_fstat_extended:
       case BSC_chmod_extended:
       case BSC_fchmod_extended:
       case BSC_access_extended:
       case BSC_mkfifo_extended:
       case BSC_mkdir_extended:
       case BSC_stat:
       case BSC_load_shared_file:
       case BSC_open:
       case BSC_dup:
       case BSC_dup2:
       case BSC_close:
       case BSC_read:
       case BSC_write:
       case BSC_fstat:
       case BSC_lstat:
       case BSC_link:
       case BSC_unlink:
       case BSC_mknod:
       case BSC_chmod:
       case BSC_chown:
       case BSC_lchown:
       case BSC_access:
       case BSC_chflags:
       case BSC_fchflags:
       case BSC_fchdir:
       case BSC_futimes:
       case BSC_chdir:
       case BSC_utimes:
       case BSC_chroot:
       case BSC_undelete:
       case BSC_delete:
       case BSC_revoke:
       case BSC_fsctl:
       case BSC_copyfile:
       case BSC_sync:
       case BSC_symlink:
       case BSC_readlink:
       case BSC_fsync:
       case BSC_readv:
       case BSC_writev:
       case BSC_pread:
       case BSC_pwrite:
       case BSC_fchown:
       case BSC_fchmod:
       case BSC_rename:
       case BSC_mkdir:
       case BSC_mkfifo:
       case BSC_rmdir:
       case BSC_statfs:
       case BSC_fstatfs:
       case BSC_pathconf:
       case BSC_fpathconf:
       case BSC_getdirentries:
       case BSC_lseek:
       case BSC_truncate:
       case BSC_ftruncate:
       case BSC_statv:
       case BSC_lstatv:
       case BSC_fstatv:
       case BSC_mkcomplex:
       case BSC_getattrlist:
       case BSC_setattrlist:
       case BSC_getdirentriesattr:
       case BSC_exchangedata:
       case BSC_checkuseraccess:
       case BSC_searchfs:
	   case FILEMGR_PBGETCATALOGINFO:
	   case FILEMGR_PBGETCATALOGINFOBULK:
	   case FILEMGR_PBCREATEFILEUNICODE:
	   case FILEMGR_PBCREATEDIRECTORYUNICODE:
	   case FILEMGR_PBCREATEFORK:
	   case FILEMGR_PBDELETEFORK:
	   case FILEMGR_PBITERATEFORK:
	   case FILEMGR_PBOPENFORK:
	   case FILEMGR_PBREADFORK:
	   case FILEMGR_PBWRITEFORK:
	   case FILEMGR_PBALLOCATEFORK:
	   case FILEMGR_PBDELETEOBJECT:
	   case FILEMGR_PBEXCHANGEOBJECT:
	   case FILEMGR_PBGETFORKCBINFO:
	   case FILEMGR_PBGETVOLUMEINFO:
	   case FILEMGR_PBMAKEFSREF:
	   case FILEMGR_PBMAKEFSREFUNICODE:
	   case FILEMGR_PBMOVEOBJECT:
	   case FILEMGR_PBOPENITERATOR:
	   case FILEMGR_PBRENAMEUNICODE:
	   case FILEMGR_PBSETCATALOGINFO:
	   case FILEMGR_PBSETVOLUMEINFO:
	   case FILEMGR_FSREFMAKEPATH:
	   case FILEMGR_FSPATHMAKEREF:

	   case FILEMGR_PBGETCATINFO:
	   case FILEMGR_PBGETCATINFOLITE:
	   case FILEMGR_PBHGETFINFO:
	   case FILEMGR_PBXGETVOLINFO:
	   case FILEMGR_PBHCREATE:
	   case FILEMGR_PBHOPENDF:
	   case FILEMGR_PBHOPENRF:
	   case FILEMGR_PBHGETDIRACCESS:
	   case FILEMGR_PBHSETDIRACCESS:
	   case FILEMGR_PBHMAPID:
	   case FILEMGR_PBHMAPNAME:
	   case FILEMGR_PBCLOSE:
	   case FILEMGR_PBFLUSHFILE:
	   case FILEMGR_PBGETEOF:
	   case FILEMGR_PBSETEOF:
	   case FILEMGR_PBGETFPOS:
	   case FILEMGR_PBREAD:
	   case FILEMGR_PBWRITE:
	   case FILEMGR_PBGETFCBINFO:
	   case FILEMGR_PBSETFINFO:
	   case FILEMGR_PBALLOCATE:
	   case FILEMGR_PBALLOCCONTIG:
	   case FILEMGR_PBSETFPOS:
	   case FILEMGR_PBSETCATINFO:
	   case FILEMGR_PBGETVOLPARMS:
	   case FILEMGR_PBSETVINFO:
	   case FILEMGR_PBMAKEFSSPEC:
	   case FILEMGR_PBHGETVINFO:
	   case FILEMGR_PBCREATEFILEIDREF:
	   case FILEMGR_PBDELETEFILEIDREF:
	   case FILEMGR_PBRESOLVEFILEIDREF:
	   case FILEMGR_PBFLUSHVOL:
	   case FILEMGR_PBHRENAME:
	   case FILEMGR_PBCATMOVE:
	   case FILEMGR_PBEXCHANGEFILES:
	   case FILEMGR_PBHDELETE:
	   case FILEMGR_PBDIRCREATE:
	   case FILEMGR_PBCATSEARCH:
	   case FILEMGR_PBHSETFLOCK:
	   case FILEMGR_PBHRSTFLOCK:
	   case FILEMGR_PBLOCKRANGE:
	   case FILEMGR_PBUNLOCKRANGE:

	   if ((ti = find_thread(thread, BSC_execve))) {
		    if (ti->pathptr) {
		            exit_syscall("execve", thread, BSC_execve, 0, 0, 0, 0, (double)now);
		    }
	   }
	   for (i = 0, ti = th_state; ti < &th_state[MAX_THREADS]; ti++, i++) {
	           if (ti->thread == 0)
		           break;
	   }
	   if (ti == &th_state[MAX_THREADS])
	           return;
	   if (i >= cur_max)
	           cur_max = i + 1;
                   
	   if ((type >> 24) == FILEMGR_CLASS) {
		   ti->in_filemgr = 1;

		   l_usecs = (long long)(now / divisor);
		   secs = l_usecs / 1000000;
		   curr_time = bias_secs + secs;
		   
		   sprintf(buf, "%-8.8s", &(ctime(&curr_time)[11]));
		   tsclen = strlen(buf);

		   if (columns > MAXCOLS || wideflag) {
		           usecs = l_usecs - (long long)((long long)secs * 1000000);
			   sprintf(&buf[tsclen], ".%03ld", (long)usecs / 1000);
			   tsclen = strlen(buf);
		   }

		   /* Print timestamp column */
		   printf("%s", buf);

		   map = find_thread_map(thread);
		   if (map) {
		       sprintf(buf, "  %-25.25s ", name);
		       nmclen = strlen(buf);
		       printf("%s", buf);

		       sprintf(buf, "(%d, 0x%x, 0x%x, 0x%x)", (short)kd->arg1, kd->arg2, kd->arg3, kd->arg4);
		       argsclen = strlen(buf);
		       
		       /*
			 Calculate white space out to command
		       */
		       if (columns > MAXCOLS || wideflag)
			 {
			   clen = columns - (tsclen + nmclen + argsclen + 20);
			 }
		       else
			 clen = columns - (tsclen + nmclen + argsclen + 12);

		       if(clen > 0)
			 {
			   printf("%s", buf);   /* print the kdargs */
			   memset(buf, ' ', clen);
			   buf[clen] = '\0';
			   printf("%s", buf);
			 }
		       else if ((argsclen + clen) > 0)
			 {
			   /* no room so wipe out the kdargs */
			   memset(buf, ' ', (argsclen + clen));
			   buf[argsclen + clen] = '\0';
			   printf("%s", buf);
			 }

		       if (columns > MAXCOLS || wideflag)
			   printf("%-20.20s\n", map->command); 
		       else
			   printf("%-12.12s\n", map->command); 
		   } else
			   printf("  %-24.24s (%5d, %#x, 0x%x, 0x%x)\n",         name, (short)kd->arg1, kd->arg2, kd->arg3, kd->arg4);
	   } else {
			   ti->in_filemgr = 0;
	   }
	   ti->thread = thread;
	   ti->waited = 0;
	   ti->type   = type;
	   ti->stime  = now;
	   ti->arg1   = kd->arg1;
	   ti->arg2   = kd->arg2;
	   ti->arg3   = kd->arg3;
	   ti->arg4   = kd->arg4;
	   ti->pathptr = (long *)0;
	   ti->pathname[0] = 0;
	   break;

       default:
	   break;
       }
       fflush (0);
}

/*
 * Handle system call extended trace data.
 * pread and pwrite:
 *     Wipe out the kd args that were collected upon syscall_entry
 *     because it is the extended info that we really want, and it
 *     is all we really need.
*/

void
extend_syscall(int thread, int type, kd_buf *kd, char *name, double now)
{
       struct th_info *ti;

       switch (type) {
       case BSC_pread_extended:
	   if ((ti = find_thread(thread, BSC_pread)) == (struct th_info *)0)
	       return;
	   ti->arg1   = kd->arg1;  /* the fd */
	   ti->arg2   = kd->arg2;  /* nbytes */
	   ti->arg3   = kd->arg3;  /* top half offset */
	   ti->arg4   = kd->arg4;  /* bottom half offset */	   
	   break;
       case BSC_pwrite_extended:
	   if ((ti = find_thread(thread, BSC_pwrite)) == (struct th_info *)0)
	       return;
	   ti->arg1   = kd->arg1;  /* the fd */
	   ti->arg2   = kd->arg2;  /* nbytes */
	   ti->arg3   = kd->arg3;  /* top half offset */
	   ti->arg4   = kd->arg4;  /* bottom half offset */
	   break;
       default:
	   return;
       }
}

void
exit_syscall(char *sc_name, int thread, int type, int error, int retval,
	                    int has_fd, int has_ret, double now)
{
    struct th_info *ti;
      
    if ((ti = find_thread(thread, type)) == (struct th_info *)0)
        return;

    if (check_filter_mode(ti, type, error, retval, sc_name))
	format_print(ti, sc_name, thread, type, error, retval, has_fd, has_ret, now, ti->stime, ti->waited, ti->pathname, NULL);

    if (ti == &th_state[cur_max - 1])
        cur_max--;
    ti->thread = 0;
}



void
format_print(struct th_info *ti, char *sc_name, int thread, int type, int error, int retval,
	                    int has_fd, int has_ret, double now, double stime, int waited, char *pathname, struct diskio *dio)
{
       int secs;
       int usecs;
       int nopadding;
       long long l_usecs;
       long curr_time;
       char *command_name;
       kd_threadmap *map;
       kd_threadmap *find_thread_map();
       int len = 0;
       int clen = 0;
       char *framework_name;
       char buf[MAXCOLS];
      
       command_name = "";
       
       if (dio)
            command_name = dio->issuing_command;
       else {
	   if ((map = find_thread_map(thread)))
                command_name = map->command;
       }
       
       l_usecs = (long long)(now / divisor);
       secs = l_usecs / 1000000;
       curr_time = bias_secs + secs;
       sprintf(buf, "%-8.8s", &(ctime(&curr_time)[11]));
       clen = strlen(buf);

       if (columns > MAXCOLS || wideflag) {
	       nopadding = 0;
	       usecs = l_usecs - (long long)((long long)secs * 1000000);
	       sprintf(&buf[clen], ".%03ld", (long)usecs / 1000);
	       clen = strlen(buf);
               
	       if ((type >> 24) != FILEMGR_CLASS) {
		   if (find_thread(thread, -1)) {
		       sprintf(&buf[clen], "   ");
		       clen = strlen(buf);
		       nopadding = 1;
		   }
	       }
       } else
	       nopadding = 1;

       if (((type >> 24) == FILEMGR_CLASS) && (columns > MAXCOLS || wideflag))
	       sprintf(&buf[clen], "  %-18.18s", sc_name);
       else
	       sprintf(&buf[clen], "  %-15.15s", sc_name);

       clen = strlen(buf);
       
       framework_name = (char *)0;

       if (columns > MAXCOLS || wideflag) {
            if (has_ret == 7) {
                sprintf(&buf[clen], " D=0x%8.8x", dio->blkno);
                
                clen = strlen(buf);
                
                if (dio->io_errno)
                    sprintf(&buf[clen], "  [%3d]       ", dio->io_errno);
                else
                    sprintf(&buf[clen], "  B=0x%-6x   /dev/%s", dio->iosize, find_disk_name(dio->dev));
            } else {

		off_t offset_reassembled = 0LL;
		
	       if (has_fd == 2 && error == 0)
		       sprintf(&buf[clen], " F=%-3d", retval);
	       else if (has_fd == 1)
		       sprintf(&buf[clen], " F=%-3d", ti->arg1);
	       else if (has_ret != 2 && has_ret != 6)
		       sprintf(&buf[clen], "      ");

	       clen = strlen(buf);

	       if (has_ret == 2 || has_ret == 6)
		       framework_name = lookup_name(retval);

	       if (error && has_ret != 6)
		       sprintf(&buf[clen], "[%3d]       ", error);
	       else if (has_ret == 3)
		       sprintf(&buf[clen], "O=0x%8.8x", ti->arg3);
	       else if (has_ret == 5)
		       sprintf(&buf[clen], "O=0x%8.8x", retval);
	       else if (has_ret == 2) 
		       sprintf(&buf[clen], " A=0x%8.8x              ", retval);
	       else if (has_ret == 6) 
		       sprintf(&buf[clen], " A=0x%8.8x  B=0x%-8x", retval, error);
	       else if (has_ret == 1)
		       sprintf(&buf[clen], "  B=0x%-6x", retval);
	       else if (has_ret == 4)
		       sprintf(&buf[clen], "B=0x%-8x", retval);
	       else if (has_ret == 8)  /* BSC_select */
		       sprintf(&buf[clen], "  S=%-3d     ", retval);	       
	       else if (has_ret == 9)  /* BSC_pread, BSC_pwrite */
	       {
		   sprintf(&buf[clen], "B=0x%-8x", retval);
		   clen = strlen(buf);
		   offset_reassembled = (((off_t)(unsigned int)(ti->arg3)) << 32) | (unsigned int)(ti->arg4);
		   if ((offset_reassembled >> 32) != 0)
		       sprintf(&buf[clen], "O=0x%16.16qx", (off_t)offset_reassembled);
		   else
		       sprintf(&buf[clen], "O=0x%8.8qx", (off_t)offset_reassembled);
	       }
	       else
		       sprintf(&buf[clen], "            ");
            }
            clen = strlen(buf);
       }
       printf("%s", buf);

       /*
	 Calculate space available to print pathname
       */
       if (columns > MAXCOLS || wideflag)
	 clen =  columns - (clen + 13 + 20);
       else
	 clen =  columns - (clen + 13 + 12);

       if ((type >> 24) != FILEMGR_CLASS && !nopadding)
	 clen -= 3;

       if (framework_name)
	 sprintf(&buf[0], " %s ", framework_name);
       else
	 sprintf(&buf[0], " %s ", pathname);
       len = strlen(buf);
       
       if (clen > len)
	 {
	   /* 
	      Add null padding if column length
	      is wider than the pathname length.
	   */
	   memset(&buf[len], ' ', clen - len);
	   buf[clen] = '\0';
	   printf("%s", buf);
	 }
       else if (clen == len)
	 {
	   printf("%s", buf);
	 }
       else if ((clen > 0) && (clen < len))
	 {
	   /* This prints the tail end of the pathname */
	   buf[len-clen] = ' ';
	   printf("%s", &buf[len - clen]);
	 }

       usecs = (unsigned long)((now - stime) / divisor);
       secs = usecs / 1000000;
       usecs -= secs * 1000000;

       if ((type >> 24) != FILEMGR_CLASS && !nopadding)
	       printf("   ");
	       
       printf(" %2ld.%06ld", (unsigned long)secs, (unsigned long)usecs);
       
       if (waited)
	       printf(" W");
       else
	       printf("  ");

       if (columns > MAXCOLS || wideflag)
               printf(" %-20.20s", command_name);
       else
               printf(" %-12.12s", command_name);

       printf("\n");
       fflush (0);
}

int
quit(s)
char *s;
{
        if (trace_enabled)
	       set_enable(0);

	/* 
	   This flag is turned off when calling
	   quit() due to a set_remove() failure.
	*/
	if (set_remove_flag)
	        set_remove();

        fprintf(stderr, "fs_usage: ");
	if (s)
		fprintf(stderr, "%s", s);

	exit(1);
}


void getdivisor()
{
    struct mach_timebase_info mti;

    mach_timebase_info(&mti);

    divisor = ((double)mti.denom / (double)mti.numer) * 1000;
}


void read_command_map()
{
    size_t size;
    int i;
    int prev_total_threads;
    int mib[6];
  
    if (mapptr) {
	free(mapptr);
	mapptr = 0;
    }

    prev_total_threads = total_threads;
    total_threads = bufinfo.nkdthreads;
    size = bufinfo.nkdthreads * sizeof(kd_threadmap);

    if (size)
    {
        if ((mapptr = (kd_threadmap *) malloc(size)))
	{
	     bzero (mapptr, size);
 
	     /* Now read the threadmap */
	     mib[0] = CTL_KERN;
	     mib[1] = KERN_KDEBUG;
	     mib[2] = KERN_KDTHRMAP;
	     mib[3] = 0;
	     mib[4] = 0;
	     mib[5] = 0;		/* no flags */
	     if (sysctl(mib, 3, mapptr, &size, NULL, 0) < 0)
	     {
		 /* This is not fatal -- just means I cant map command strings */
		 free(mapptr);
		 mapptr = 0;
	     }
	}
    }

    if (mapptr && (filter_mode & (NETWORK_FILTER | FILESYS_FILTER)))
    {
	if (fdmapptr)
	{
	    /* We accept the fact that we lose file descriptor state if the
	       kd_buffer wraps */
	    for (i = 0; i < prev_total_threads; i++)
	    {
		if (fdmapptr[i].fd_setptr)
		    free (fdmapptr[i].fd_setptr);
	    }
	    free(fdmapptr);
	    fdmapptr = 0;
	}

	size = total_threads * sizeof(fd_threadmap);
	if ((fdmapptr = (fd_threadmap *) malloc(size)))
	{
	    bzero (fdmapptr, size);
	    /* reinitialize file descriptor state map */
	    for (i = 0; i < total_threads; i++)
	    {
		fdmapptr[i].fd_thread = mapptr[i].thread;
		fdmapptr[i].fd_valid = mapptr[i].valid;
		fdmapptr[i].fd_setsize = 0;
		fdmapptr[i].fd_setptr = 0;
	    }
	}
    }

    /* Resolve any LaunchCFMApp command names */
    if (mapptr && arguments)
    {
	for (i=0; i < total_threads; i++)
	{
	    int pid;

	    pid = mapptr[i].valid;
	    
	    if (pid == 0 || pid == 1)
		continue;
	    else if (!strncmp(mapptr[i].command,"LaunchCFMA", 10))
	    {
		(void)get_real_command_name(pid, mapptr[i].command, sizeof(mapptr[i].command));
	    }
	}
    }
}


void create_map_entry(int thread, int pid, char *command)
{
    int i, n;
    kd_threadmap *map;
    fd_threadmap *fdmap = 0;

    if (!mapptr)
        return;

    for (i = 0, map = 0; !map && i < total_threads; i++)
    {
        if ((int)mapptr[i].thread == thread )
	{
	    map = &mapptr[i];   /* Reuse this entry, the thread has been
				 * reassigned */
	    if ((filter_mode & (NETWORK_FILTER | FILESYS_FILTER)) && fdmapptr)
	    {
		fdmap = &fdmapptr[i];
		if (fdmap->fd_thread != thread)    /* This shouldn't happen */
		    fdmap = (fd_threadmap *)0;
	    }
	}
    }

    if (!map)   /* look for invalid entries that I can reuse*/
    {
        for (i = 0, map = 0; !map && i < total_threads; i++)
	{
	    if (mapptr[i].valid == 0 )	
	        map = &mapptr[i];   /* Reuse this invalid entry */
	    if ((filter_mode & (NETWORK_FILTER | FILESYS_FILTER)) && fdmapptr)
	    {
		fdmap = &fdmapptr[i];
	    }
	}
    }
  
    if (!map)
    {
        /* If reach here, then this is a new thread and 
	 * there are no invalid entries to reuse
	 * Double the size of the thread map table.
	 */

        n = total_threads * 2;
	mapptr = (kd_threadmap *) realloc(mapptr, n * sizeof(kd_threadmap));
	bzero(&mapptr[total_threads], total_threads*sizeof(kd_threadmap));
	map = &mapptr[total_threads];

	if ((filter_mode & (NETWORK_FILTER | FILESYS_FILTER)) && fdmapptr)
	{
	    fdmapptr = (fd_threadmap *)realloc(fdmapptr, n * sizeof(fd_threadmap));
	    bzero(&fdmapptr[total_threads], total_threads*sizeof(fd_threadmap));
	    fdmap = &fdmapptr[total_threads];	    
	}
	
	total_threads = n;
    }

    map->valid = 1;
    map->thread = thread;
    /*
      The trace entry that returns the command name will hold
      at most, MAXCOMLEN chars, and in that case, is not
      guaranteed to be null terminated.
    */
    (void)strncpy (map->command, command, MAXCOMLEN);
    map->command[MAXCOMLEN] = '\0';

    if (fdmap)
    {
	fdmap->fd_valid = 1;
	fdmap->fd_thread = thread;
	if (fdmap->fd_setptr)
	{
	    free(fdmap->fd_setptr);
	    fdmap->fd_setptr = (unsigned long *)0;
	}
	fdmap->fd_setsize = 0;
    }

    if (pid == 0 || pid == 1)
	return;
    else if (!strncmp(map->command, "LaunchCFMA", 10))
	(void)get_real_command_name(pid, map->command, sizeof(map->command));
}


kd_threadmap *find_thread_map(int thread)
{
    int i;
    kd_threadmap *map;

    if (!mapptr)
        return((kd_threadmap *)0);

    for (i = 0; i < total_threads; i++)
    {
        map = &mapptr[i];
	if (map->valid && ((int)map->thread == thread))
	{
	    return(map);
	}
    }
    return ((kd_threadmap *)0);
}

fd_threadmap *find_fd_thread_map(int thread)
{
    int i;
    fd_threadmap *fdmap = 0;

    if (!fdmapptr)
        return((fd_threadmap *)0);

    for (i = 0; i < total_threads; i++)
    {
        fdmap = &fdmapptr[i];
	if (fdmap->fd_valid && ((int)fdmap->fd_thread == thread))
	{
	    return(fdmap);
	}
    }
    return ((fd_threadmap *)0);
}


void
kill_thread_map(int thread)
{
    kd_threadmap *map;
    fd_threadmap *fdmap;

    if ((map = find_thread_map(thread))) {
        map->valid = 0;
	map->thread = 0;
	map->command[0] = '\0';
    }

    if ((filter_mode & (NETWORK_FILTER | FILESYS_FILTER)))
    {
	if ((fdmap = find_fd_thread_map(thread)))
	{
	    fdmap->fd_valid = 0;
	    fdmap->fd_thread = 0;
	    if (fdmap->fd_setptr)
	    {
		free (fdmap->fd_setptr);
		fdmap->fd_setptr = (unsigned long *)0;
	    }
	    fdmap->fd_setsize = 0;
	}	
    }
}

void
argtopid(str)
        char *str;
{
        char *cp;
        int ret;
	int i;

        ret = (int)strtol(str, &cp, 10);
        if (cp == str || *cp) {
	  /* Assume this is a command string and find matching pids */
	        if (!kp_buffer)
		        find_proc_names();

	        for (i=0; i < kp_nentries && num_of_pids < (MAX_PIDS - 1); i++) {
		      if(kp_buffer[i].kp_proc.p_stat == 0)
		          continue;
		      else {
			  if(!strcmp(str, kp_buffer[i].kp_proc.p_comm))
			    pids[num_of_pids++] = kp_buffer[i].kp_proc.p_pid;
		      }
		}
	}
	else if (num_of_pids < (MAX_PIDS - 1))
	        pids[num_of_pids++] = ret;

        return;
}



char *lookup_name(unsigned long addr) 
{       
        register int i;
	register int start, last;


	if (numFrameworks == 0 || addr < frameworkInfo[0].address || addr > frameworkInfo[numFrameworks].address)
	        return (0);

	start = 0;
	last  = numFrameworks;

	for (i = numFrameworks / 2; i >= 0 && i < numFrameworks; ) {

	        if (addr >= frameworkInfo[i].address && addr < frameworkInfo[i+1].address)
		        return(frameworkInfo[i].name);

		if (addr >= frameworkInfo[i].address) {
		        start = i;
		        i = start + ((last - i) / 2);
		} else {
		        last = i;
		        i = start + ((i - start) / 2);
		}
	}
	return (0);
}


/*
 * Comparison routines for sorting
 */
static int compareFrameworkAddress(const void  *aa, const void *bb)
{
    LibraryInfo *a = (LibraryInfo *)aa;
    LibraryInfo *b = (LibraryInfo *)bb;

    if (a->address < b->address) return -1;
    if (a->address == b->address) return 0;
    return 1;
}


int scanline(char *inputstring,char **argv)
{
     int n = 0;
     char **ap = argv, *p, *val;  

     for (p = inputstring; p != NULL; ) 
     {
        while ((val = strsep(&p, " \t")) != NULL && *val == '\0');
        *ap++ = val;
        n++; 
     }
     *ap = 0;
     return n;
}


int ReadSegAddrTable()
{
    char buf[1024];

    FILE *fd;
    unsigned long frameworkAddress, frameworkDataAddress, previousFrameworkAddress;
    char frameworkName[256];
    char *tokens[64];
    int  ntokens;
    char *substring,*ptr;
    int  founddylib = 0;


    bzero(buf, sizeof(buf));
    bzero(tokens, sizeof(tokens));
    
    numFrameworks = 0;

    if ((fd = fopen(seg_addr_table, "r")) == 0)
    {
        return 0;
    }
    fgets(buf, 1023, fd);

    if (*buf == '#')
    {
        founddylib = 0;
        frameworkName[0] = 0;
        previousFrameworkAddress = 0;

        while (fgets(buf, 1023, fd) && numFrameworks < (MAXINDEX - 2))
        {
	    /*
	     * Get rid of EOL
	     */
	    buf[strlen(buf)-1] = 0;

	    if (strncmp(buf, "# dyld:", 7) == 0) {
	        /*
		 * the next line in the file will contain info about dyld
		 */
	        founddylib = 1;
		continue;
	    }
	    /*
	     * This is a split library line: parse it into 3 tokens
	     */
	    ntokens = scanline(buf, tokens);

	    if (ntokens < 3)
	        continue;

	    frameworkAddress     = strtoul(tokens[0], 0, 16);
	    frameworkDataAddress = strtoul(tokens[1], 0, 16);

	    if (founddylib) {
	        /*
		 * dyld entry is of a different form from the std split library
		 * it consists of a base address and a size instead of a code
		 * and data base address
		 */
	        frameworkInfo[numFrameworks].address   = frameworkAddress;
		frameworkInfo[numFrameworks+1].address = frameworkAddress + frameworkDataAddress;

		frameworkInfo[numFrameworks].name   = (char *)"dylib";
		frameworkInfo[numFrameworks+1].name = (char *)0;

		numFrameworks += 2;
		founddylib = 0;

		continue;
	    }  

	    /*
	     * Make sure that we have 2 addresses and a path
	     */
	    if (!frameworkAddress)
	        continue;
	    if (!frameworkDataAddress)
	        continue;
	    if (*tokens[2] != '/')
	        continue;
	    if (frameworkAddress == previousFrameworkAddress) 
	        continue;
	    previousFrameworkAddress = frameworkAddress;

            /*
	     * Extract lib name from path name
	     */
	    if ((substring = strrchr(tokens[2], '.')))
	    {		
	        /*
		 * There is a ".": name is whatever is between the "/" around the "." 
		 */
	      while ( *substring != '/') {		    /* find "/" before "." */
		    substring--;
		}
		substring++;
		strcpy(frameworkName, substring);           /* copy path from "/" */
		substring = frameworkName;

		while ( *substring != '/' && *substring)    /* find "/" after "." and stop string there */
		    substring++;
		*substring = 0;
	    }
	    else 
	    {
	        /*
		 * No ".": take segment after last "/"
		 */
	        ptr = tokens[2];
		substring = ptr;

		while (*ptr) 
		{
		    if (*ptr == '/')
		        substring = ptr + 1;
		    ptr++;
		}
		strcpy(frameworkName, substring);
	    }
	    frameworkInfo[numFrameworks].address   = frameworkAddress;
	    frameworkInfo[numFrameworks+1].address = frameworkDataAddress;

	    frameworkInfo[numFrameworks].name = (char *)malloc(strlen(frameworkName) + 1);
	    strcpy(frameworkInfo[numFrameworks].name, frameworkName);
	    frameworkInfo[numFrameworks+1].name = frameworkInfo[numFrameworks].name;

	    numFrameworks += 2;
        }
    }
    frameworkInfo[numFrameworks].address = frameworkInfo[numFrameworks - 1].address + 0x800000;
    frameworkInfo[numFrameworks].name = (char *)0;

    fclose(fd);

    qsort(frameworkInfo, numFrameworks, sizeof(LibraryInfo), compareFrameworkAddress);

    return 1;
}


struct diskio *insert_diskio(int type, int bp, int dev, int blkno, int io_size, int thread, double curtime)
{
    register struct diskio *dio;
    register kd_threadmap  *map;
    
    if ((dio = free_diskios))
        free_diskios = dio->next;
    else {
        if ((dio = (struct diskio *)malloc(sizeof(struct diskio))) == NULL)
            return (NULL);
    }
    dio->prev = NULL;
    
    dio->type = type;
    dio->bp = bp;
    dio->dev = dev;
    dio->blkno = blkno;
    dio->iosize = io_size;
    dio->issued_time = curtime;
    dio->issuing_thread = thread;
    
    if ((map = find_thread_map(thread)))
    {
        strncpy(dio->issuing_command, map->command, MAXCOMLEN);
	dio->issuing_command[MAXCOMLEN-1] = '\0';
    }
    else
        strcpy(dio->issuing_command, "");
    
    dio->next = busy_diskios;
    if (dio->next)
        dio->next->prev = dio;
    busy_diskios = dio;

    return (dio);
}


struct diskio *complete_diskio(int bp, int io_errno, int resid, int thread, double curtime)
{
    register struct diskio *dio;
    
    for (dio = busy_diskios; dio; dio = dio->next) {
        if (dio->bp == bp) {
        
            if (dio == busy_diskios) {
                if ((busy_diskios = dio->next))
                    dio->next->prev = NULL;
            } else {
                if (dio->next)
                    dio->next->prev = dio->prev;
                dio->prev->next = dio->next;
            }
            dio->iosize -= resid;
            dio->io_errno = io_errno;
            dio->completed_time = curtime;
            dio->completion_thread = thread;
            
	    return (dio);
        }    
    }
    return ((struct diskio *)0);
}


void free_diskio(struct diskio *dio)
{
    dio->next = free_diskios;
    free_diskios = dio;
}


void print_diskio(struct diskio *dio)
{
    register char  *p;

    switch (dio->type) {

        case P_RdMeta:
            p = "  RdMeta";
            break;
        case P_WrMeta:
            p = "  WrMeta";
            break;
        case P_RdData:
            p = "  RdData";
            break;
        case P_WrData:
            p = "  WrData";
            break;        
        case P_PgIn:
            p = "  PgIn";
            break;
        case P_PgOut:
            p = "  PgOut";
            break;
        case P_RdMetaAsync:
            p = "  RdMeta[async]";
            break;
        case P_WrMetaAsync:
            p = "  WrMeta[async]";
            break;
        case P_RdDataAsync:
            p = "  RdData[async]";
            break;
        case P_WrDataAsync:
            p = "  WrData[async]";
            break;        
        case P_PgInAsync:
            p = "  PgIn[async]";
            break;
        case P_PgOutAsync:
            p = "  PgOut[async]";
            break;
        default:
            p = "  ";
	    break;
    }
    if (check_filter_mode(NULL, dio->type,0, 0, p))
	format_print(NULL, p, dio->issuing_thread, dio->type, 0, 0, 0, 7, dio->completed_time, dio->issued_time, 1, "", dio);
}


void cache_disk_names()
{
    struct stat    st;
    DIR            *dirp = NULL;
    struct dirent  *dir;
    struct diskrec *dnp;


    if ((dirp = opendir("/dev")) == NULL)
        return;
        
    while ((dir = readdir(dirp)) != NULL) {
        char nbuf[MAXPATHLEN];
        
        if (dir->d_namlen < 5 || strncmp("disk", dir->d_name, 4))
            continue;
        sprintf(nbuf, "%s/%s", "/dev", dir->d_name);
        
	if (stat(nbuf, &st) < 0)
            continue;

        if ((dnp = (struct diskrec *)malloc(sizeof(struct diskrec))) == NULL)
            continue;
            
        if ((dnp->diskname = (char *)malloc(dir->d_namlen + 1)) == NULL) {
            free(dnp);
            continue;
        }
        strncpy(dnp->diskname, dir->d_name, dir->d_namlen);
        dnp->diskname[dir->d_namlen] = 0;
        dnp->dev = st.st_rdev;
        
        dnp->next = disk_list;
        disk_list = dnp;
    }
    (void) closedir(dirp);
}


char *find_disk_name(int dev)
{
    struct diskrec *dnp;
    
    if (dev == NFS_DEV)
        return ("NFS");
        
    for (dnp = disk_list; dnp; dnp = dnp->next) {
        if (dnp->dev == dev)
            return (dnp->diskname);
    }
    return ("NOTFOUND");
}

void
fs_usage_fd_set(thread, fd)
    unsigned int thread;
    unsigned int fd;
{
    int n;
    fd_threadmap *fdmap;

    if(!(fdmap = find_fd_thread_map(thread)))
	return;

    /* If the map is not allocated, then now is the time */
    if (fdmap->fd_setptr == (unsigned long *)0)
    {
	fdmap->fd_setptr = (unsigned long *)malloc(FS_USAGE_NFDBYTES(FS_USAGE_FD_SETSIZE));
	if (fdmap->fd_setptr)
	{
	    fdmap->fd_setsize = FS_USAGE_FD_SETSIZE;
	    bzero(fdmap->fd_setptr,(FS_USAGE_NFDBYTES(FS_USAGE_FD_SETSIZE)));
	}
	else
	    return;
    }

    /* If the map is not big enough, then reallocate it */
    while (fdmap->fd_setsize < fd)
    {
	fprintf(stderr, "reallocating bitmap for threadid %d, fd = %d, setsize = %d\n",
	  thread, fd, fdmap->fd_setsize);
	n = fdmap->fd_setsize * 2;
	fdmap->fd_setptr = (unsigned long *)realloc(fdmap->fd_setptr, (FS_USAGE_NFDBYTES(n)));
	bzero(&fdmap->fd_setptr[(fdmap->fd_setsize/FS_USAGE_NFDBITS)], (FS_USAGE_NFDBYTES(fdmap->fd_setsize)));
	fdmap->fd_setsize = n;
    }

    /* set the bit */
    fdmap->fd_setptr[fd/FS_USAGE_NFDBITS] |= (1 << ((fd) % FS_USAGE_NFDBITS));

    return;
}

/*
  Return values:
  0 : File Descriptor bit is not set
  1 : File Descriptor bit is set
*/
    
int
fs_usage_fd_isset(thread, fd)
    unsigned int thread;
    unsigned int fd;
{
    int ret = 0;
    fd_threadmap *fdmap;

    if(!(fdmap = find_fd_thread_map(thread)))
	return(ret);

    if (fdmap->fd_setptr == (unsigned long *)0)
	return (ret);

    if (fd < fdmap->fd_setsize)
	ret = fdmap->fd_setptr[fd/FS_USAGE_NFDBITS] & (1 << (fd % FS_USAGE_NFDBITS));
    
    return (ret);
}
    
void
fs_usage_fd_clear(thread, fd)
    unsigned int thread;
    unsigned int fd;
{
    fd_threadmap *map;

    if (!(map = find_fd_thread_map(thread)))
	return;

    if (map->fd_setptr == (unsigned long *)0)
	return;

    /* clear the bit */
    if (fd < map->fd_setsize)
	map->fd_setptr[fd/FS_USAGE_NFDBITS] &= ~(1 << (fd % FS_USAGE_NFDBITS));
    
    return;
}


/*
 * ret = 1 means print the entry
 * ret = 0 means don't print the entry
 */
int
check_filter_mode(struct th_info * ti, int type, int error, int retval, char *sc_name)
{
    int ret = 0;
    int network_fd_isset = 0;
    unsigned int fd;

    if (filter_mode == DEFAULT_DO_NOT_FILTER)
	return(1);

    if (!strcmp (sc_name, "CACHE_HIT")) {
            if (filter_mode & CACHEHIT_FILTER)
	            /* Do not print if cachehit filter is set */
	            return(0);
	    return (1);
    }
	
    if (filter_mode & EXEC_FILTER)
    {
	if (!strcmp (sc_name, "execve"))
	    return(1);
	return(0);
    }
    if ( !(filter_mode & (FILESYS_FILTER | NETWORK_FILTER)))
	return(1);

	
    if (ti == (struct th_info *)0)
    {
	if(filter_mode & FILESYS_FILTER)
	    ret = 1;
	else
	    ret = 0;
	return(ret);
    }

    switch (type) {
    case BSC_close:
	fd = ti->arg1;
	network_fd_isset = fs_usage_fd_isset(ti->thread, fd);
	if (error == 0)
	{
	    fs_usage_fd_clear(ti->thread,fd);
	}
	
	if (network_fd_isset)
	{
	    if (filter_mode & NETWORK_FILTER)
		ret = 1;
	}
	else if (filter_mode & FILESYS_FILTER)
	    ret = 1;
	break;
    case BSC_read:
    case BSC_write:
	/* we don't care about error in this case */
	fd = ti->arg1;
	network_fd_isset = fs_usage_fd_isset(ti->thread, fd);
	if (network_fd_isset)
	{
	    if (filter_mode & NETWORK_FILTER)
		ret = 1;
	}
	else if (filter_mode & FILESYS_FILTER)
	    ret = 1;	
	break;
    case BSC_accept:
    case BSC_socket:
	fd = retval;
	if (error == 0)
	    fs_usage_fd_set(ti->thread, fd);
	if (filter_mode & NETWORK_FILTER)
	    ret = 1;
	break;
    case BSC_recvfrom:
    case BSC_sendto:
    case BSC_recvmsg:
    case BSC_sendmsg:
    case BSC_connect:
    case BSC_bind:
    case BSC_listen:	    
	fd = ti->arg1;
	if (error == 0)
	    fs_usage_fd_set(ti->thread, fd);
	if (filter_mode & NETWORK_FILTER)
	    ret = 1;
	break;
    case BSC_select:
    case BSC_socketpair:
	/* Cannot determine info about file descriptors */
	if (filter_mode & NETWORK_FILTER)
	    ret = 1;
	break;
    case BSC_dup:
    case BSC_dup2:
	ret=0;   /* We track these cases for fd state only */
	fd = ti->arg1;  /* oldd */
	network_fd_isset = fs_usage_fd_isset(ti->thread, fd);
	if (error == 0 && network_fd_isset)
	{
	    /* then we are duping a socket descriptor */
	    fd = retval;  /* the new fd */
	    fs_usage_fd_set(ti->thread, fd);
	}
	break;

    default:
	if (filter_mode & FILESYS_FILTER)
	    ret = 1;
	break;
    }

    return(ret);
}

/*
 * Allocate a buffer that is large enough to hold the maximum arguments
 * to execve().  This is used when getting the arguments to programs
 * when we see LaunchCFMApps.  If this fails, it is not fatal, we will
 * simply not resolve the command name.
 */

void
init_arguments_buffer()
{

    int     mib[2];
    size_t  size;

    mib[0] = CTL_KERN;
    mib[1] = KERN_ARGMAX;
    size = sizeof(argmax);
    if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1)
	return;

#if 1
    /* Hack to avoid kernel bug. */
    if (argmax > 8192) {
	argmax = 8192;
    }
#endif

    arguments = (char *)malloc(argmax);
    
    return;
}


int
get_real_command_name(int pid, char *cbuf, int csize)
{
    /*
     *      Get command and arguments.
     */
    char  *cp;
    int             mib[4];
    char    *command_beg, *command, *command_end;

    if (cbuf == NULL) {
	return(0);
    }

    if (arguments)
	bzero(arguments, argmax);
    else
	return(0);

    /*
     * A sysctl() is made to find out the full path that the command
     * was called with.
     */
    mib[0] = CTL_KERN;
    mib[1] = KERN_PROCARGS;
    mib[2] = pid;
    mib[3] = 0;

    if (sysctl(mib, 3, arguments, (size_t *)&argmax, NULL, 0) < 0) {
	return(0);
    }

    /* Skip the saved exec_path. */
    for (cp = arguments; cp < &arguments[argmax]; cp++) {
	if (*cp == '\0') {
	    /* End of exec_path reached. */
	    break;
	}
    }
    if (cp == &arguments[argmax]) {
	return(0);
    }

    /* Skip trailing '\0' characters. */
    for (; cp < &arguments[argmax]; cp++) {
	if (*cp != '\0') {
	    /* Beginning of first argument reached. */
	    break;
	}
    }
    if (cp == &arguments[argmax]) {
	return(0);
    }
    command_beg = cp;

    /*
     * Make sure that the command is '\0'-terminated.  This protects
     * against malicious programs; under normal operation this never
     * ends up being a problem..
     */
    for (; cp < &arguments[argmax]; cp++) {
	if (*cp == '\0') {
	    /* End of first argument reached. */
	    break;
	}
    }
    if (cp == &arguments[argmax]) {
	return(0);
    }
    command_end = command = cp;

    /* Get the basename of command. */
    for (command--; command >= command_beg; command--) {
	if (*command == '/') {
	    command++;
	    break;
	}
    }

    (void) strncpy(cbuf, (char *)command, csize);
    cbuf[csize-1] = '\0';

    return(1);
}