#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <strings.h>
#include <nlist.h>
#include <fcntl.h>
#include <aio.h>
#include <string.h>
#include <dirent.h>
#include <libc.h>
#include <termios.h>
#include <errno.h>
#include <err.h>
#include <libutil.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/mman.h>
#include <sys/sysctl.h>
#include <sys/disk.h>
#ifndef KERNEL_PRIVATE
#define KERNEL_PRIVATE
#include <sys/kdebug.h>
#undef KERNEL_PRIVATE
#else
#include <sys/kdebug.h>
#endif
#import <mach/clock_types.h>
#import <mach/mach_time.h>
#define F_OPENFROM 56
#define F_UNLINKFROM 57
#define F_CHECK_OPENEVT 58
#ifndef RAW_VERSION1
typedef struct {
int version_no;
int thread_count;
uint64_t TOD_secs;
uint32_t TOD_usecs;
} RAW_header;
#define RAW_VERSION0 0x55aa0000
#define RAW_VERSION1 0x55aa0101
#endif
#define MAXINDEX 2048
typedef struct LibraryRange {
uint64_t b_address;
uint64_t e_address;
} LibraryRange;
LibraryRange framework32;
LibraryRange framework64;
#define TEXT_R 0
#define DATA_R 1
#define OBJC_R 2
#define IMPORT_R 3
#define UNICODE_R 4
#define IMAGE_R 5
#define LINKEDIT_R 6
char *frameworkType[] = {
"<TEXT> ",
"<DATA> ",
"<OBJC> ",
"<IMPORT> ",
"<UNICODE> ",
"<IMAGE> ",
"<LINKEDIT>",
};
typedef struct LibraryInfo {
uint64_t b_address;
uint64_t e_address;
int r_type;
char *name;
} LibraryInfo;
LibraryInfo frameworkInfo[MAXINDEX];
int numFrameworks = 0;
#define NUMPARMS 23
#define PATHLENGTH (NUMPARMS*sizeof(uintptr_t))
#define MAXCOLS 132
#define MAX_WIDE_MODE_COLS (PATHLENGTH + 80)
#define MAXWIDTH MAX_WIDE_MODE_COLS + 64
typedef struct th_info *th_info_t;
struct th_info {
th_info_t next;
uintptr_t thread;
uintptr_t child_thread;
int in_filemgr;
int pid;
int type;
int arg1;
int arg2;
int arg3;
int arg4;
int arg5;
int arg6;
int arg7;
int arg8;
int waited;
double stime;
uintptr_t *pathptr;
uintptr_t pathname[NUMPARMS + 1];
uintptr_t pathname2[NUMPARMS + 1];
};
typedef struct threadmap * threadmap_t;
struct threadmap {
threadmap_t tm_next;
uintptr_t tm_thread;
unsigned int tm_setsize;
unsigned long *tm_setptr;
char tm_command[MAXCOMLEN + 1];
};
#define HASH_SIZE 1024
#define HASH_MASK 1023
th_info_t th_info_hash[HASH_SIZE];
th_info_t th_info_freelist;
threadmap_t threadmap_hash[HASH_SIZE];
threadmap_t threadmap_freelist;
int filemgr_in_progress = 0;
int need_new_map = 1;
int bias_secs = 0;
long last_time;
int wideflag = 0;
int columns = 0;
int one_good_pid = 0;
int select_pid_mode = 0;
char *arguments = 0;
int argmax = 0;
#define USLEEP_MIN 1
#define USLEEP_BEHIND 2
#define USLEEP_MAX 32
int usleep_ms = USLEEP_MIN;
#define FILESYS_FILTER 0x01
#define NETWORK_FILTER 0x02
#define CACHEHIT_FILTER 0x04
#define EXEC_FILTER 0x08
#define PATHNAME_FILTER 0x10
#define DEFAULT_DO_NOT_FILTER 0x00
int filter_mode = CACHEHIT_FILTER;
#define NFS_DEV -1
#define CS_DEV -2
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;
uintptr_t issuing_thread;
uintptr_t 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();
int check_filter_mode(struct th_info *, int, int, int, char *);
void format_print(struct th_info *, char *, uintptr_t, int, int, int, int, int, int, double, double, int, char *, struct diskio *);
void enter_event_now(uintptr_t, int, kd_buf *, char *, double);
void enter_event(uintptr_t, int, kd_buf *, char *, double);
void exit_event(char *, uintptr_t, int, int, int, int, int, int, double);
void extend_syscall(uintptr_t, int, kd_buf *);
char *generate_cs_disk_name(int, char *s);
char *find_disk_name(int);
void cache_disk_names();
void recache_disk_names();
void lookup_name(uint64_t user_addr, char **type, char **name);
int ReadSharedCacheMap(const char *, LibraryRange *, char *);
void SortFrameworkAddresses();
void fs_usage_fd_set(uintptr_t, unsigned int);
int fs_usage_fd_isset(uintptr_t, unsigned int);
void fs_usage_fd_clear(uintptr_t, unsigned int);
void init_arguments_buffer();
int get_real_command_name(int, char *, int);
void delete_all_events();
void delete_event(th_info_t);
th_info_t add_event(uintptr_t, int);
th_info_t find_event(uintptr_t, int);
void mark_thread_waited(uintptr_t);
void read_command_map();
void delete_all_map_entries();
void create_map_entry(uintptr_t, int, char *);
void delete_map_entry(uintptr_t);
threadmap_t find_map_entry(uintptr_t);
void getdivisor();
void argtopid();
void set_remove();
void set_pidcheck();
void set_pidexclude();
int quit();
#define CLASS_MASK 0xff000000
#define CSC_MASK 0xffff0000
#define BSC_INDEX(type) ((type >> 2) & 0x3fff)
#define TRACE_DATA_NEWTHREAD 0x07000004
#define TRACE_DATA_EXEC 0x07000008
#define TRACE_STRING_NEWTHREAD 0x07010004
#define TRACE_STRING_EXEC 0x07010008
#define MACH_vmfault 0x01300008
#define MACH_pageout 0x01300004
#define MACH_sched 0x01400000
#define MACH_stkhandoff 0x01400008
#define MACH_idle 0x01400024
#define VFS_LOOKUP 0x03010090
#define BSC_thread_terminate 0x040c05a4
#define Throttled 0x3010184
#define SPEC_ioctl 0x3060000
#define SPEC_unmap_info 0x3060004
#define proc_exit 0x4010004
#ifndef DKIO_NOCACHE
#define DKIO_NOCACHE 0x80
#endif
#define P_DISKIO_READ (DKIO_READ << 2)
#define P_DISKIO_ASYNC (DKIO_ASYNC << 2)
#define P_DISKIO_META (DKIO_META << 2)
#define P_DISKIO_PAGING (DKIO_PAGING << 2)
#define P_DISKIO_THROTTLE (DKIO_THROTTLE << 2)
#define P_DISKIO_PASSIVE (DKIO_PASSIVE << 2)
#define P_DISKIO_NOCACHE (DKIO_NOCACHE << 2)
#define P_DISKIO (FSDBG_CODE(DBG_DKRW, 0))
#define P_DISKIO_DONE (P_DISKIO | (DKIO_DONE << 2))
#define P_DISKIO_TYPE (P_DISKIO | P_DISKIO_READ | P_DISKIO_META | P_DISKIO_PAGING)
#define P_DISKIO_MASK (CSC_MASK | 0x4)
#define P_WrData (P_DISKIO)
#define P_RdData (P_DISKIO | P_DISKIO_READ)
#define P_WrMeta (P_DISKIO | P_DISKIO_META)
#define P_RdMeta (P_DISKIO | P_DISKIO_META | P_DISKIO_READ)
#define P_PgOut (P_DISKIO | P_DISKIO_PAGING)
#define P_PgIn (P_DISKIO | P_DISKIO_PAGING | P_DISKIO_READ)
#define P_CS_Class 0x0a000000 // DBG_CORESTORAGE
#define P_CS_Type_Mask 0xfffffff0
#define P_CS_IO_Done 0x00000004
#define P_CS_ReadChunk 0x0a000200 // chopped up request
#define P_CS_WriteChunk 0x0a000210
#define P_CS_MetaRead 0x0a000300 // meta data
#define P_CS_MetaWrite 0x0a000310
#define P_CS_TransformRead 0x0a000500 // background transform
#define P_CS_TransformWrite 0x0a000510
#define P_CS_MigrationRead 0x0a000600 // composite disk block migration
#define P_CS_MigrationWrite 0x0a000610
#define P_CS_SYNC_DISK 0x0a010000
#define MSC_map_fd 0x010c00ac
#define BSC_BASE 0x040C0000
#define MSC_BASE 0x010C0000
#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_exit 0x040C0004
#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_getfsstat 0x040C0048
#define BSC_access 0x040C0084
#define BSC_chflags 0x040C0088
#define BSC_fchflags 0x040C008C
#define BSC_sync 0x040C0090
#define BSC_dup 0x040C00A4
#define BSC_ioctl 0x040C00D8
#define BSC_revoke 0x040C00E0
#define BSC_symlink 0x040C00E4
#define BSC_readlink 0x040C00E8
#define BSC_execve 0x040C00EC
#define BSC_umask 0x040C00F0
#define BSC_chroot 0x040C00F4
#define BSC_msync 0x040C0104
#define BSC_dup2 0x040C0168
#define BSC_fcntl 0x040C0170
#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_pwrite 0x040C0268
#define BSC_statfs 0x040C0274
#define BSC_fstatfs 0x040C0278
#define BSC_unmount 0x040C027C
#define BSC_mount 0x040C029C
#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_posix_spawn 0x040C03D0
#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_aio_fsync 0x040C04E4
#define BSC_aio_return 0x040C04E8
#define BSC_aio_suspend 0x040C04EC
#define BSC_aio_cancel 0x040C04F0
#define BSC_aio_error 0x040C04F4
#define BSC_aio_read 0x040C04F8
#define BSC_aio_write 0x040C04FC
#define BSC_lio_listio 0x040C0500
#define BSC_sendfile 0x040C0544
#define BSC_stat64 0x040C0548
#define BSC_fstat64 0x040C054C
#define BSC_lstat64 0x040C0550
#define BSC_stat64_extended 0x040C0554
#define BSC_lstat64_extended 0x040C0558
#define BSC_fstat64_extended 0x040C055C
#define BSC_getdirentries64 0x040C0560
#define BSC_statfs64 0x040C0564
#define BSC_fstatfs64 0x040C0568
#define BSC_getfsstat64 0x040C056C
#define BSC_pthread_chdir 0x040C0570
#define BSC_pthread_fchdir 0x040C0574
#define BSC_lchown 0x040C05B0
#define BSC_read_nocancel 0x040c0630
#define BSC_write_nocancel 0x040c0634
#define BSC_open_nocancel 0x040c0638
#define BSC_close_nocancel 0x040c063c
#define BSC_recvmsg_nocancel 0x040c0644
#define BSC_sendmsg_nocancel 0x040c0648
#define BSC_recvfrom_nocancel 0x040c064c
#define BSC_accept_nocancel 0x040c0650
#define BSC_msync_nocancel 0x040c0654
#define BSC_fcntl_nocancel 0x040c0658
#define BSC_select_nocancel 0x040c065c
#define BSC_fsync_nocancel 0x040c0660
#define BSC_connect_nocancel 0x040c0664
#define BSC_readv_nocancel 0x040c066c
#define BSC_writev_nocancel 0x040c0670
#define BSC_sendto_nocancel 0x040c0674
#define BSC_pread_nocancel 0x040c0678
#define BSC_pwrite_nocancel 0x040c067c
#define BSC_aio_suspend_nocancel 0x40c0694
#define BSC_msync_extended 0x040e0104
#define BSC_pread_extended 0x040e0264
#define BSC_pwrite_extended 0x040e0268
#define BSC_mmap_extended 0x040e0314
#define BSC_mmap_extended2 0x040f0314
#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 FILEMGR_BASE 0x1e000000
#define FMT_DEFAULT 0
#define FMT_FD 1
#define FMT_FD_IO 2
#define FMT_FD_2 3
#define FMT_SOCKET 4
#define FMT_PGIN 5
#define FMT_PGOUT 6
#define FMT_CACHEHIT 7
#define FMT_DISKIO 8
#define FMT_LSEEK 9
#define FMT_PREAD 10
#define FMT_FTRUNC 11
#define FMT_TRUNC 12
#define FMT_SELECT 13
#define FMT_OPEN 14
#define FMT_AIO_FSYNC 15
#define FMT_AIO_RETURN 16
#define FMT_AIO_SUSPEND 17
#define FMT_AIO_CANCEL 18
#define FMT_AIO 19
#define FMT_LIO_LISTIO 20
#define FMT_MSYNC 21
#define FMT_FCNTL 22
#define FMT_ACCESS 23
#define FMT_CHMOD 24
#define FMT_FCHMOD 25
#define FMT_CHMOD_EXT 26
#define FMT_FCHMOD_EXT 27
#define FMT_CHFLAGS 28
#define FMT_FCHFLAGS 29
#define FMT_IOCTL 30
#define FMT_MMAP 31
#define FMT_UMASK 32
#define FMT_SENDFILE 33
#define FMT_IOCTL_SYNC 34
#define FMT_MOUNT 35
#define FMT_UNMOUNT 36
#define FMT_DISKIO_CS 37
#define FMT_SYNC_DISK_CS 38
#define FMT_IOCTL_UNMAP 39
#define FMT_UNMAP_INFO 40
#define MAX_BSD_SYSCALL 512
struct bsd_syscall {
char *sc_name;
int sc_format;
} bsd_syscalls[MAX_BSD_SYSCALL];
int bsd_syscall_types[] = {
BSC_recvmsg,
BSC_recvmsg_nocancel,
BSC_sendmsg,
BSC_sendmsg_nocancel,
BSC_recvfrom,
BSC_recvfrom_nocancel,
BSC_accept,
BSC_accept_nocancel,
BSC_select,
BSC_select_nocancel,
BSC_socket,
BSC_connect,
BSC_connect_nocancel,
BSC_bind,
BSC_listen,
BSC_sendto,
BSC_sendto_nocancel,
BSC_socketpair,
BSC_read,
BSC_read_nocancel,
BSC_write,
BSC_write_nocancel,
BSC_open,
BSC_open_nocancel,
BSC_close,
BSC_close_nocancel,
BSC_link,
BSC_unlink,
BSC_chdir,
BSC_fchdir,
BSC_mknod,
BSC_chmod,
BSC_chown,
BSC_access,
BSC_chflags,
BSC_fchflags,
BSC_sync,
BSC_dup,
BSC_revoke,
BSC_symlink,
BSC_readlink,
BSC_exit,
BSC_execve,
BSC_posix_spawn,
BSC_umask,
BSC_chroot,
BSC_dup2,
BSC_fsync,
BSC_fsync_nocancel,
BSC_readv,
BSC_readv_nocancel,
BSC_writev,
BSC_writev_nocancel,
BSC_fchown,
BSC_fchmod,
BSC_rename,
BSC_mkfifo,
BSC_mkdir,
BSC_rmdir,
BSC_utimes,
BSC_futimes,
BSC_pread,
BSC_pread_nocancel,
BSC_pwrite,
BSC_pwrite_nocancel,
BSC_statfs,
BSC_fstatfs,
BSC_stat,
BSC_fstat,
BSC_lstat,
BSC_mount,
BSC_unmount,
BSC_pathconf,
BSC_fpathconf,
BSC_getdirentries,
BSC_mmap,
BSC_lseek,
BSC_truncate,
BSC_ftruncate,
BSC_undelete,
BSC_statv,
BSC_lstatv,
BSC_fstatv,
BSC_mkcomplex,
BSC_getattrlist,
BSC_setattrlist,
BSC_getdirentriesattr,
BSC_exchangedata,
BSC_checkuseraccess,
BSC_searchfs,
BSC_delete,
BSC_copyfile,
BSC_getxattr,
BSC_fgetxattr,
BSC_setxattr,
BSC_fsetxattr,
BSC_removexattr,
BSC_fremovexattr,
BSC_listxattr,
BSC_flistxattr,
BSC_fsctl,
BSC_open_extended,
BSC_stat_extended,
BSC_lstat_extended,
BSC_fstat_extended,
BSC_chmod_extended,
BSC_fchmod_extended,
BSC_access_extended,
BSC_mkfifo_extended,
BSC_mkdir_extended,
BSC_load_shared_file,
BSC_aio_fsync,
BSC_aio_return,
BSC_aio_suspend,
BSC_aio_suspend_nocancel,
BSC_aio_cancel,
BSC_aio_error,
BSC_aio_read,
BSC_aio_write,
BSC_lio_listio,
BSC_lchown,
BSC_sendfile,
BSC_msync,
BSC_msync_nocancel,
BSC_fcntl,
BSC_fcntl_nocancel,
BSC_ioctl,
BSC_stat64,
BSC_fstat64,
BSC_lstat64,
BSC_stat64_extended,
BSC_lstat64_extended,
BSC_fstat64_extended,
BSC_getdirentries64,
BSC_statfs64,
BSC_fstatfs64,
BSC_pthread_chdir,
BSC_pthread_fchdir,
BSC_getfsstat,
BSC_getfsstat64,
0
};
#define MAX_FILEMGR 512
struct filemgr_call {
char *fm_name;
} filemgr_calls[MAX_FILEMGR];
int filemgr_call_types[] = {
FILEMGR_PBGETCATALOGINFO,
FILEMGR_PBGETCATALOGINFOBULK,
FILEMGR_PBCREATEFILEUNICODE,
FILEMGR_PBCREATEDIRECTORYUNICODE,
FILEMGR_PBCREATEFORK,
FILEMGR_PBDELETEFORK,
FILEMGR_PBITERATEFORK,
FILEMGR_PBOPENFORK,
FILEMGR_PBREADFORK,
FILEMGR_PBWRITEFORK,
FILEMGR_PBALLOCATEFORK,
FILEMGR_PBDELETEOBJECT,
FILEMGR_PBEXCHANGEOBJECT,
FILEMGR_PBGETFORKCBINFO,
FILEMGR_PBGETVOLUMEINFO,
FILEMGR_PBMAKEFSREF,
FILEMGR_PBMAKEFSREFUNICODE,
FILEMGR_PBMOVEOBJECT,
FILEMGR_PBOPENITERATOR,
FILEMGR_PBRENAMEUNICODE,
FILEMGR_PBSETCATALOGINFO,
FILEMGR_PBSETVOLUMEINFO,
FILEMGR_FSREFMAKEPATH,
FILEMGR_FSPATHMAKEREF,
FILEMGR_PBGETCATINFO,
FILEMGR_PBGETCATINFOLITE,
FILEMGR_PBHGETFINFO,
FILEMGR_PBXGETVOLINFO,
FILEMGR_PBHCREATE,
FILEMGR_PBHOPENDF,
FILEMGR_PBHOPENRF,
FILEMGR_PBHGETDIRACCESS,
FILEMGR_PBHSETDIRACCESS,
FILEMGR_PBHMAPID,
FILEMGR_PBHMAPNAME,
FILEMGR_PBCLOSE,
FILEMGR_PBFLUSHFILE,
FILEMGR_PBGETEOF,
FILEMGR_PBSETEOF,
FILEMGR_PBGETFPOS,
FILEMGR_PBREAD,
FILEMGR_PBWRITE,
FILEMGR_PBGETFCBINFO,
FILEMGR_PBSETFINFO,
FILEMGR_PBALLOCATE,
FILEMGR_PBALLOCCONTIG,
FILEMGR_PBSETFPOS,
FILEMGR_PBSETCATINFO,
FILEMGR_PBGETVOLPARMS,
FILEMGR_PBSETVINFO,
FILEMGR_PBMAKEFSSPEC,
FILEMGR_PBHGETVINFO,
FILEMGR_PBCREATEFILEIDREF,
FILEMGR_PBDELETEFILEIDREF,
FILEMGR_PBRESOLVEFILEIDREF,
FILEMGR_PBFLUSHVOL,
FILEMGR_PBHRENAME,
FILEMGR_PBCATMOVE,
FILEMGR_PBEXCHANGEFILES,
FILEMGR_PBHDELETE,
FILEMGR_PBDIRCREATE,
FILEMGR_PBCATSEARCH,
FILEMGR_PBHSETFLOCK,
FILEMGR_PBHRSTFLOCK,
FILEMGR_PBLOCKRANGE,
FILEMGR_PBUNLOCKRANGE,
0
};
#define MAX_PIDS 256
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 EVENT_BASE 60000
int num_events = EVENT_BASE;
#define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
#define DBG_FUNC_MASK 0xfffffffc
double divisor = 0.0;
int mib[6];
size_t needed;
char *my_buffer;
kbufinfo_t bufinfo = {0, 0, 0, 0, 0};
#define FS_USAGE_FD_SETSIZE 256
#define FS_USAGE_NFDBITS (sizeof (unsigned long) * 8)
#define FS_USAGE_NFDBYTES(n) (((n) / FS_USAGE_NFDBITS) * sizeof (unsigned long))
int trace_enabled = 0;
int set_remove_flag = 1;
char *RAW_file = (char *)0;
int RAW_flag = 0;
int RAW_fd = 0;
uint64_t sample_TOD_secs;
uint32_t sample_TOD_usecs;
double bias_now = 0.0;
double start_time = 0.0;
double end_time = 999999999999.9;
void set_numbufs();
void set_init();
void set_enable();
void sample_sc();
int quit();
void leave()
{
int i;
void set_enable();
void set_pidcheck();
void set_pidexclude();
void set_remove();
fflush(0);
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);
}
int
quit(s)
char *s;
{
if (trace_enabled)
set_enable(0);
if (set_remove_flag)
set_remove();
fprintf(stderr, "fs_usage: ");
if (s)
fprintf(stderr, "%s", s);
exit(1);
}
void get_screenwidth()
{
struct winsize size;
columns = MAXCOLS;
if (isatty(1)) {
if (ioctl(1, TIOCGWINSZ, &size) != -1) {
columns = size.ws_col;
if (columns > MAXWIDTH)
columns = MAXWIDTH;
}
}
}
void sigwinch()
{
if (!wideflag)
get_screenwidth();
}
void getdivisor()
{
struct mach_timebase_info mti;
mach_timebase_info(&mti);
divisor = ((double)mti.denom / (double)mti.numer) * 1000;
}
int
exit_usage(char *myname) {
fprintf(stderr, "Usage: %s [-e] [-w] [-f mode] [-R rawfile [-S start_time] [-E end_time]] [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 = \"pathname\" Show only pathname related output\n");
fprintf(stderr, " mode = \"exec\" Show only execs\n");
fprintf(stderr, " mode = \"cachehit\" In addition, show cachehits\n");
fprintf(stderr, " -R specifies a raw trace file to process\n");
fprintf(stderr, " -S if -R is specified, selects a start point in microseconds\n");
fprintf(stderr, " -E if -R is specified, selects an end point in microseconds\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 filemgr_index(type) {
if (type & 0x10000)
return (((type >> 2) & 0x3fff) + 256);
return (((type >> 2) & 0x3fff));
}
void init_tables(void)
{ int i;
int type;
int code;
for (i = 0; i < MAX_BSD_SYSCALL; i++) {
bsd_syscalls[i].sc_name = NULL;
bsd_syscalls[i].sc_format = FMT_DEFAULT;
}
for (i = 0; i < MAX_FILEMGR; i++) {
filemgr_calls[i].fm_name = NULL;
}
for (i = 0; (type = bsd_syscall_types[i]); i++) {
code = BSC_INDEX(type);
if (code >= MAX_BSD_SYSCALL) {
printf("BSD syscall init (%x): type exceeds table size\n", type);
continue;
}
switch (type) {
case BSC_sendfile:
bsd_syscalls[code].sc_name = "sendfile";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_recvmsg:
case BSC_recvmsg_nocancel:
bsd_syscalls[code].sc_name = "recvmsg";
bsd_syscalls[code].sc_format = FMT_FD_IO;
break;
case BSC_sendmsg:
case BSC_sendmsg_nocancel:
bsd_syscalls[code].sc_name = "sendmsg";
bsd_syscalls[code].sc_format = FMT_FD_IO;
break;
case BSC_recvfrom:
case BSC_recvfrom_nocancel:
bsd_syscalls[code].sc_name = "recvfrom";
bsd_syscalls[code].sc_format = FMT_FD_IO;
break;
case BSC_sendto:
case BSC_sendto_nocancel:
bsd_syscalls[code].sc_name = "sendto";
bsd_syscalls[code].sc_format = FMT_FD_IO;
break;
case BSC_select:
case BSC_select_nocancel:
bsd_syscalls[code].sc_name = "select";
bsd_syscalls[code].sc_format = FMT_SELECT;
break;
case BSC_accept:
case BSC_accept_nocancel:
bsd_syscalls[code].sc_name = "accept";
bsd_syscalls[code].sc_format = FMT_FD_2;
break;
case BSC_socket:
bsd_syscalls[code].sc_name = "socket";
bsd_syscalls[code].sc_format = FMT_SOCKET;
break;
case BSC_connect:
case BSC_connect_nocancel:
bsd_syscalls[code].sc_name = "connect";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_bind:
bsd_syscalls[code].sc_name = "bind";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_listen:
bsd_syscalls[code].sc_name = "listen";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_mmap:
bsd_syscalls[code].sc_name = "mmap";
bsd_syscalls[code].sc_format = FMT_MMAP;
break;
case BSC_socketpair:
bsd_syscalls[code].sc_name = "socketpair";
break;
case BSC_getxattr:
bsd_syscalls[code].sc_name = "getxattr";
break;
case BSC_setxattr:
bsd_syscalls[code].sc_name = "setxattr";
break;
case BSC_removexattr:
bsd_syscalls[code].sc_name = "removexattr";
break;
case BSC_listxattr:
bsd_syscalls[code].sc_name = "listxattr";
break;
case BSC_stat:
bsd_syscalls[code].sc_name = "stat";
break;
case BSC_stat64:
bsd_syscalls[code].sc_name = "stat64";
break;
case BSC_stat_extended:
bsd_syscalls[code].sc_name = "stat_extended";
break;
case BSC_stat64_extended:
bsd_syscalls[code].sc_name = "stat_extended64";
break;
case BSC_mount:
bsd_syscalls[code].sc_name = "mount";
bsd_syscalls[code].sc_format = FMT_MOUNT;
break;
case BSC_unmount:
bsd_syscalls[code].sc_name = "unmount";
bsd_syscalls[code].sc_format = FMT_UNMOUNT;
break;
case BSC_exit:
bsd_syscalls[code].sc_name = "exit";
break;
case BSC_execve:
bsd_syscalls[code].sc_name = "execve";
break;
case BSC_posix_spawn:
bsd_syscalls[code].sc_name = "posix_spawn";
break;
case BSC_load_shared_file:
bsd_syscalls[code].sc_name = "load_sf";
break;
case BSC_open:
case BSC_open_nocancel:
bsd_syscalls[code].sc_name = "open";
bsd_syscalls[code].sc_format = FMT_OPEN;
break;
case BSC_open_extended:
bsd_syscalls[code].sc_name = "open_extended";
bsd_syscalls[code].sc_format = FMT_OPEN;
break;
case BSC_dup:
bsd_syscalls[code].sc_name = "dup";
bsd_syscalls[code].sc_format = FMT_FD_2;
break;
case BSC_dup2:
bsd_syscalls[code].sc_name = "dup2";
bsd_syscalls[code].sc_format = FMT_FD_2;
break;
case BSC_close:
case BSC_close_nocancel:
bsd_syscalls[code].sc_name = "close";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_read:
case BSC_read_nocancel:
bsd_syscalls[code].sc_name = "read";
bsd_syscalls[code].sc_format = FMT_FD_IO;
break;
case BSC_write:
case BSC_write_nocancel:
bsd_syscalls[code].sc_name = "write";
bsd_syscalls[code].sc_format = FMT_FD_IO;
break;
case BSC_fgetxattr:
bsd_syscalls[code].sc_name = "fgetxattr";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_fsetxattr:
bsd_syscalls[code].sc_name = "fsetxattr";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_fremovexattr:
bsd_syscalls[code].sc_name = "fremovexattr";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_flistxattr:
bsd_syscalls[code].sc_name = "flistxattr";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_fstat:
bsd_syscalls[code].sc_name = "fstat";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_fstat64:
bsd_syscalls[code].sc_name = "fstat64";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_fstat_extended:
bsd_syscalls[code].sc_name = "fstat_extended";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_fstat64_extended:
bsd_syscalls[code].sc_name = "fstat64_extended";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_lstat:
bsd_syscalls[code].sc_name = "lstat";
break;
case BSC_lstat64:
bsd_syscalls[code].sc_name = "lstat64";
break;
case BSC_lstat_extended:
bsd_syscalls[code].sc_name = "lstat_extended";
break;
case BSC_lstat64_extended:
bsd_syscalls[code].sc_name = "lstat_extended64";
break;
case BSC_lstatv:
bsd_syscalls[code].sc_name = "lstatv";
break;
case BSC_link:
bsd_syscalls[code].sc_name = "link";
break;
case BSC_unlink:
bsd_syscalls[code].sc_name = "unlink";
break;
case BSC_mknod:
bsd_syscalls[code].sc_name = "mknod";
break;
case BSC_umask:
bsd_syscalls[code].sc_name = "umask";
bsd_syscalls[code].sc_format = FMT_UMASK;
break;
case BSC_chmod:
bsd_syscalls[code].sc_name = "chmod";
bsd_syscalls[code].sc_format = FMT_CHMOD;
break;
case BSC_chmod_extended:
bsd_syscalls[code].sc_name = "chmod_extended";
bsd_syscalls[code].sc_format = FMT_CHMOD_EXT;
break;
case BSC_fchmod:
bsd_syscalls[code].sc_name = "fchmod";
bsd_syscalls[code].sc_format = FMT_FCHMOD;
break;
case BSC_fchmod_extended:
bsd_syscalls[code].sc_name = "fchmod_extended";
bsd_syscalls[code].sc_format = FMT_FCHMOD_EXT;
break;
case BSC_chown:
bsd_syscalls[code].sc_name = "chown";
break;
case BSC_lchown:
bsd_syscalls[code].sc_name = "lchown";
break;
case BSC_fchown:
bsd_syscalls[code].sc_name = "fchown";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_access:
bsd_syscalls[code].sc_name = "access";
bsd_syscalls[code].sc_format = FMT_ACCESS;
break;
case BSC_access_extended:
bsd_syscalls[code].sc_name = "access_extended";
break;
case BSC_chdir:
bsd_syscalls[code].sc_name = "chdir";
break;
case BSC_pthread_chdir:
bsd_syscalls[code].sc_name = "pthread_chdir";
break;
case BSC_chroot:
bsd_syscalls[code].sc_name = "chroot";
break;
case BSC_utimes:
bsd_syscalls[code].sc_name = "utimes";
break;
case BSC_delete:
bsd_syscalls[code].sc_name = "delete-Carbon";
break;
case BSC_undelete:
bsd_syscalls[code].sc_name = "undelete";
break;
case BSC_revoke:
bsd_syscalls[code].sc_name = "revoke";
break;
case BSC_fsctl:
bsd_syscalls[code].sc_name = "fsctl";
break;
case BSC_chflags:
bsd_syscalls[code].sc_name = "chflags";
bsd_syscalls[code].sc_format = FMT_CHFLAGS;
break;
case BSC_fchflags:
bsd_syscalls[code].sc_name = "fchflags";
bsd_syscalls[code].sc_format = FMT_FCHFLAGS;
break;
case BSC_fchdir:
bsd_syscalls[code].sc_name = "fchdir";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_pthread_fchdir:
bsd_syscalls[code].sc_name = "pthread_fchdir";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_futimes:
bsd_syscalls[code].sc_name = "futimes";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_sync:
bsd_syscalls[code].sc_name = "sync";
break;
case BSC_symlink:
bsd_syscalls[code].sc_name = "symlink";
break;
case BSC_readlink:
bsd_syscalls[code].sc_name = "readlink";
break;
case BSC_fsync:
case BSC_fsync_nocancel:
bsd_syscalls[code].sc_name = "fsync";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_readv:
case BSC_readv_nocancel:
bsd_syscalls[code].sc_name = "readv";
bsd_syscalls[code].sc_format = FMT_FD_IO;
break;
case BSC_writev:
case BSC_writev_nocancel:
bsd_syscalls[code].sc_name = "writev";
bsd_syscalls[code].sc_format = FMT_FD_IO;
break;
case BSC_pread:
case BSC_pread_nocancel:
bsd_syscalls[code].sc_name = "pread";
bsd_syscalls[code].sc_format = FMT_PREAD;
break;
case BSC_pwrite:
case BSC_pwrite_nocancel:
bsd_syscalls[code].sc_name = "pwrite";
bsd_syscalls[code].sc_format = FMT_PREAD;
break;
case BSC_mkdir:
bsd_syscalls[code].sc_name = "mkdir";
break;
case BSC_mkdir_extended:
bsd_syscalls[code].sc_name = "mkdir_extended";
break;
case BSC_mkfifo:
bsd_syscalls[code].sc_name = "mkfifo";
break;
case BSC_mkfifo_extended:
bsd_syscalls[code].sc_name = "mkfifo_extended";
break;
case BSC_rmdir:
bsd_syscalls[code].sc_name = "rmdir";
break;
case BSC_statfs:
bsd_syscalls[code].sc_name = "statfs";
break;
case BSC_statfs64:
bsd_syscalls[code].sc_name = "statfs64";
break;
case BSC_getfsstat:
bsd_syscalls[code].sc_name = "getfsstat";
break;
case BSC_getfsstat64:
bsd_syscalls[code].sc_name = "getfsstat64";
break;
case BSC_fstatfs:
bsd_syscalls[code].sc_name = "fstatfs";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_fstatfs64:
bsd_syscalls[code].sc_name = "fstatfs64";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_pathconf:
bsd_syscalls[code].sc_name = "pathconf";
break;
case BSC_fpathconf:
bsd_syscalls[code].sc_name = "fpathconf";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_getdirentries:
bsd_syscalls[code].sc_name = "getdirentries";
bsd_syscalls[code].sc_format = FMT_FD_IO;
break;
case BSC_getdirentries64:
bsd_syscalls[code].sc_name = "getdirentries64";
bsd_syscalls[code].sc_format = FMT_FD_IO;
break;
case BSC_lseek:
bsd_syscalls[code].sc_name = "lseek";
bsd_syscalls[code].sc_format = FMT_LSEEK;
break;
case BSC_truncate:
bsd_syscalls[code].sc_name = "truncate";
bsd_syscalls[code].sc_format = FMT_TRUNC;
break;
case BSC_ftruncate:
bsd_syscalls[code].sc_name = "ftruncate";
bsd_syscalls[code].sc_format = FMT_FTRUNC;
break;
case BSC_statv:
bsd_syscalls[code].sc_name = "statv";
break;
case BSC_fstatv:
bsd_syscalls[code].sc_name = "fstatv";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_mkcomplex:
bsd_syscalls[code].sc_name = "mkcomplex";
break;
case BSC_getattrlist:
bsd_syscalls[code].sc_name = "getattrlist";
break;
case BSC_setattrlist:
bsd_syscalls[code].sc_name = "setattrlist";
break;
case BSC_getdirentriesattr:
bsd_syscalls[code].sc_name = "getdirentriesattr";
bsd_syscalls[code].sc_format = FMT_FD;
break;
case BSC_exchangedata:
bsd_syscalls[code].sc_name = "exchangedata";
break;
case BSC_rename:
bsd_syscalls[code].sc_name = "rename";
break;
case BSC_copyfile:
bsd_syscalls[code].sc_name = "copyfile";
break;
case BSC_checkuseraccess:
bsd_syscalls[code].sc_name = "checkuseraccess";
break;
case BSC_searchfs:
bsd_syscalls[code].sc_name = "searchfs";
break;
case BSC_aio_fsync:
bsd_syscalls[code].sc_name = "aio_fsync";
bsd_syscalls[code].sc_format = FMT_AIO_FSYNC;
break;
case BSC_aio_return:
bsd_syscalls[code].sc_name = "aio_return";
bsd_syscalls[code].sc_format = FMT_AIO_RETURN;
break;
case BSC_aio_suspend:
case BSC_aio_suspend_nocancel:
bsd_syscalls[code].sc_name = "aio_suspend";
bsd_syscalls[code].sc_format = FMT_AIO_SUSPEND;
break;
case BSC_aio_cancel:
bsd_syscalls[code].sc_name = "aio_cancel";
bsd_syscalls[code].sc_format = FMT_AIO_CANCEL;
break;
case BSC_aio_error:
bsd_syscalls[code].sc_name = "aio_error";
bsd_syscalls[code].sc_format = FMT_AIO;
break;
case BSC_aio_read:
bsd_syscalls[code].sc_name = "aio_read";
bsd_syscalls[code].sc_format = FMT_AIO;
break;
case BSC_aio_write:
bsd_syscalls[code].sc_name = "aio_write";
bsd_syscalls[code].sc_format = FMT_AIO;
break;
case BSC_lio_listio:
bsd_syscalls[code].sc_name = "lio_listio";
bsd_syscalls[code].sc_format = FMT_LIO_LISTIO;
break;
case BSC_msync:
case BSC_msync_nocancel:
bsd_syscalls[code].sc_name = "msync";
bsd_syscalls[code].sc_format = FMT_MSYNC;
break;
case BSC_fcntl:
case BSC_fcntl_nocancel:
bsd_syscalls[code].sc_name = "fcntl";
bsd_syscalls[code].sc_format = FMT_FCNTL;
break;
case BSC_ioctl:
bsd_syscalls[code].sc_name = "ioctl";
bsd_syscalls[code].sc_format = FMT_IOCTL;
break;
}
}
for (i = 0; (type = filemgr_call_types[i]); i++) {
char * p;
code = filemgr_index(type);
if (code >= MAX_FILEMGR) {
printf("FILEMGR call init (%x): type exceeds table size\n", type);
continue;
}
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;
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 = NULL;
break;
}
filemgr_calls[code].fm_name = p;
}
}
int
main(argc, argv)
int argc;
char *argv[];
{
char *myname = "fs_usage";
int i;
char ch;
if (0 != reexec_to_match_kernel()) {
fprintf(stderr, "Could not re-execute: %d\n", errno);
exit(1);
}
get_screenwidth();
if (argc > 0) {
if ((myname = rindex(argv[0], '/')) == 0)
myname = argv[0];
else
myname++;
}
while ((ch = getopt(argc, argv, "ewf:R:S:E:")) != 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;
else if (!strcmp(optarg, "exec"))
filter_mode |= EXEC_FILTER;
else if (!strcmp(optarg, "pathname"))
filter_mode |= PATHNAME_FILTER;
break;
case 'R':
RAW_flag = 1;
RAW_file = optarg;
break;
case 'S':
start_time = atof(optarg);
break;
case 'E':
end_time = atof(optarg);
break;
default:
exit_usage(myname);
}
}
if (!RAW_flag) {
if ( geteuid() != 0 ) {
fprintf(stderr, "'fs_usage' must be run as root...\n");
exit(1);
}
}
argc -= optind;
argv += optind;
if (exclude_pids || (!exclude_pids && argc == 0)) {
if (num_of_pids < (MAX_PIDS - 1))
pids[num_of_pids++] = getpid();
}
if (argc > 0)
exclude_default_pids = 0;
while (argc > 0 && num_of_pids < (MAX_PIDS - 1)) {
select_pid_mode++;
argtopid(argv[0]);
argc--;
argv++;
}
if (exclude_default_pids) {
argtopid("Terminal");
argtopid("telnetd");
argtopid("telnet");
argtopid("sshd");
argtopid("rlogind");
argtopid("tcsh");
argtopid("csh");
argtopid("sh");
exclude_pids = 1;
}
#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
if (!RAW_flag) {
struct sigaction osa;
int num_cpus;
size_t len;
signal(SIGINT, leave);
signal(SIGQUIT, leave);
sigaction(SIGHUP, (struct sigaction *)NULL, &osa);
if (osa.sa_handler == SIG_DFL)
signal(SIGHUP, leave);
signal(SIGTERM, leave);
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
mib[2] = 0;
len = sizeof(num_cpus);
sysctl(mib, 2, &num_cpus, &len, NULL, 0);
num_events = EVENT_BASE * num_cpus;
}
signal(SIGWINCH, sigwinch);
if ((my_buffer = malloc(num_events * sizeof(kd_buf))) == (char *)0)
quit("can't allocate memory for tracing info\n");
if (ReadSharedCacheMap("/var/db/dyld/dyld_shared_cache_i386.map", &framework32, "/var/db/dyld/dyld_shared_cache_i386")) {
ReadSharedCacheMap("/var/db/dyld/dyld_shared_cache_x86_64.map", &framework64, "/var/db/dyld/dyld_shared_cache_x86_64");
} else {
ReadSharedCacheMap("/var/db/dyld/dyld_shared_cache_ppc.map", &framework32, "/var/db/dyld/dyld_shared_cache_ppc");
ReadSharedCacheMap("/var/db/dyld/dyld_shared_cache_ppc64.map", &framework64, "/var/db/dyld/dyld_shared_cache_ppc64");
}
SortFrameworkAddresses();
cache_disk_names();
if (!RAW_flag) {
set_remove();
set_numbufs(num_events);
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) {
set_remove();
exit_usage(myname);
}
set_enable(1);
init_arguments_buffer();
}
getdivisor();
init_tables();
while (1) {
if (!RAW_flag)
usleep(1000 * usleep_ms);
sample_sc();
last_time = time((long *)0);
}
}
void
find_proc_names()
{
size_t bufSize = 0;
struct kinfo_proc *kp;
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;
}
void
set_enable(int val)
{
mib[0] = CTL_KERN;
mib[1] = KERN_KDEBUG;
mib[2] = KERN_KDENABLE;
mib[3] = val;
mib[4] = 0;
mib[5] = 0;
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;
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;
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++;
}
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;
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;
mib[3] = 0;
mib[4] = 0;
mib[5] = 0;
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;
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;
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;
uint32_t my_buffer_size = 0;
if (!RAW_flag)
get_bufinfo(&bufinfo);
else
my_buffer_size = num_events * sizeof(kd_buf);
if (need_new_map) {
read_command_map();
need_new_map = 0;
}
if (!RAW_flag) {
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;
if (sysctl(mib, 3, my_buffer, &needed, NULL, 0) < 0)
quit("trace facility failure, KERN_KDREADTR\n");
count = needed;
if (count > (num_events / 8)) {
if (usleep_ms > USLEEP_BEHIND)
usleep_ms = USLEEP_BEHIND;
else if (usleep_ms > USLEEP_MIN)
usleep_ms /= 2;
} else if (count < (num_events / 16)) {
if (usleep_ms < USLEEP_MAX)
usleep_ms *= 2;
}
if (bufinfo.flags & KDBG_WRAPPED) {
fprintf(stderr, "fs_usage: buffer overrun, events generated too quickly: %d\n", count);
delete_all_events();
need_new_map = 1;
set_enable(0);
set_enable(1);
}
} else {
int bytes_read;
if ((bytes_read = read(RAW_fd, my_buffer, my_buffer_size)) < sizeof(kd_buf))
exit(0);
count = bytes_read / sizeof(kd_buf);
}
kd = (kd_buf *)my_buffer;
#if 0
fprintf(stderr, "READTR returned %d items\n", count);
#endif
for (i = 0; i < count; i++) {
uint32_t debugid;
uintptr_t thread;
int type;
int index;
uintptr_t *sargptr;
uint64_t now;
long long l_usecs;
int secs;
long curr_time;
th_info_t ti;
struct diskio *dio;
thread = kd[i].arg5;
debugid = kd[i].debugid;
type = kd[i].debugid & DBG_FUNC_MASK;
now = kdbg_get_timestamp(&kd[i]);
if (i == 0 && !RAW_flag) {
curr_time = time((long *)0);
if (bias_secs == 0 || curr_time < last_time || curr_time > (last_time + 2)) {
l_usecs = (long long)(now / divisor);
secs = l_usecs / 1000000;
bias_secs = curr_time - secs;
}
}
if (RAW_flag && bias_now == 0.0)
bias_now = now;
if ((type & P_DISKIO_MASK) == P_DISKIO) {
insert_diskio(type, kd[i].arg1, kd[i].arg2, kd[i].arg3, kd[i].arg4, thread, (double)now);
continue;
}
if ((type & P_DISKIO_MASK) == P_DISKIO_DONE) {
if ((dio = complete_diskio(kd[i].arg1, kd[i].arg4, kd[i].arg3, thread, (double)now))) {
print_diskio(dio);
free_diskio(dio);
}
continue;
}
if ((type & CLASS_MASK) == P_CS_Class) {
int cs_type = type & P_CS_Type_Mask; bool start = (type & P_CS_IO_Done) != P_CS_IO_Done;
switch (cs_type) {
case P_CS_ReadChunk:
case P_CS_WriteChunk:
case P_CS_MetaRead:
case P_CS_MetaWrite:
if (start) {
insert_diskio(cs_type, kd[i].arg2, kd[i].arg1, kd[i].arg3, kd[i].arg4, thread, (double)now);
} else {
if ((dio = complete_diskio(kd[i].arg2, kd[i].arg4, kd[i].arg3, thread, (double)now))) {
print_diskio(dio);
free_diskio(dio);
}
}
continue;
case P_CS_TransformRead:
case P_CS_TransformWrite:
case P_CS_MigrationRead:
case P_CS_MigrationWrite:
if (start) {
insert_diskio(cs_type, kd[i].arg2, CS_DEV, kd[i].arg3, kd[i].arg4, thread, (double)now);
} else {
if ((dio = complete_diskio(kd[i].arg2, kd[i].arg4, kd[i].arg3, thread, (double)now))) {
print_diskio(dio);
free_diskio(dio);
}
}
continue;
case P_CS_SYNC_DISK:
if (start) {
enter_event(thread, cs_type, &kd[i], NULL, (double)now);
} else {
exit_event(" SyncCacheCS", thread, cs_type, kd[i].arg1, 0, 0, 0, FMT_SYNC_DISK_CS, (double)now);
}
continue;
}
continue; }
switch (type) {
case TRACE_DATA_NEWTHREAD:
if (kd[i].arg1) {
if ((ti = add_event(thread, TRACE_DATA_NEWTHREAD)) == NULL)
continue;
ti->child_thread = kd[i].arg1;
ti->pid = kd[i].arg2;
}
continue;
case TRACE_STRING_NEWTHREAD:
if ((ti = find_event(thread, TRACE_DATA_NEWTHREAD)) == (struct th_info *)0)
continue;
create_map_entry(ti->child_thread, ti->pid, (char *)&kd[i].arg1);
delete_event(ti);
continue;
case TRACE_DATA_EXEC:
if ((ti = add_event(thread, TRACE_DATA_EXEC)) == NULL)
continue;
ti->pid = kd[i].arg1;
continue;
case TRACE_STRING_EXEC:
if ((ti = find_event(thread, BSC_execve))) {
if (ti->pathname[0])
exit_event("execve", thread, BSC_execve, 0, 0, 0, 0, FMT_DEFAULT, (double)now);
} else if ((ti = find_event(thread, BSC_posix_spawn))) {
if (ti->pathname[0])
exit_event("posix_spawn", thread, BSC_posix_spawn, 0, 0, 0, 0, FMT_DEFAULT, (double)now);
}
if ((ti = find_event(thread, TRACE_DATA_EXEC)) == (struct th_info *)0)
continue;
create_map_entry(thread, ti->pid, (char *)&kd[i].arg1);
delete_event(ti);
continue;
case BSC_thread_terminate:
delete_map_entry(thread);
continue;
case BSC_exit:
continue;
case proc_exit:
kd[i].arg1 = kd[i].arg2 >> 8;
type = BSC_exit;
break;
case BSC_mmap:
if (kd[i].arg4 & MAP_ANON)
continue;
break;
case MACH_idle:
case MACH_sched:
case MACH_stkhandoff:
mark_thread_waited(thread);
continue;
case VFS_LOOKUP:
if ((ti = find_event(thread, 0)) == (struct th_info *)0)
continue;
if (debugid & DBG_FUNC_START) {
if (ti->pathname2[0])
continue;
if (ti->pathname[0] == 0)
sargptr = ti->pathname;
else
sargptr = ti->pathname2;
*sargptr++ = kd[i].arg2;
*sargptr++ = kd[i].arg3;
*sargptr++ = kd[i].arg4;
*sargptr = 0;
ti->pathptr = sargptr;
} else {
sargptr = ti->pathptr;
if (sargptr == 0)
continue;
if (ti->pathname2[0]) {
if ((uintptr_t)sargptr >= (uintptr_t)&ti->pathname2[NUMPARMS])
continue;
} else {
if ((uintptr_t)sargptr >= (uintptr_t)&ti->pathname[NUMPARMS])
continue;
}
*sargptr++ = kd[i].arg1;
*sargptr++ = kd[i].arg2;
*sargptr++ = kd[i].arg3;
*sargptr++ = kd[i].arg4;
*sargptr = 0;
if (debugid & DBG_FUNC_END) {
if (ti->pathname2[0])
ti->pathptr = 0;
else
ti->pathptr = ti->pathname2;
} else
ti->pathptr = sargptr;
}
continue;
}
if (debugid & DBG_FUNC_START) {
char * p;
if ((type & CLASS_MASK) == FILEMGR_BASE) {
index = filemgr_index(type);
if (index >= MAX_FILEMGR)
continue;
if ((p = filemgr_calls[index].fm_name) == NULL)
continue;
} else
p = NULL;
enter_event(thread, type, &kd[i], p, (double)now);
continue;
}
switch (type) {
case Throttled:
exit_event(" THROTTLED", thread, type, 0, 0, 0, 0, FMT_DEFAULT, (double)now);
continue;
case SPEC_unmap_info:
if (check_filter_mode(NULL, SPEC_unmap_info, 0, 0, "SPEC_unmap_info"))
format_print(NULL, " TrimExtent", thread, type, kd[i].arg1, kd[i].arg2, kd[i].arg3, 0, FMT_UNMAP_INFO, now, now, 0, "", NULL);
continue;
case SPEC_ioctl:
if (kd[i].arg2 == DKIOCSYNCHRONIZECACHE)
exit_event("IOCTL", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, FMT_IOCTL_SYNC, (double)now);
else if (kd[i].arg2 == DKIOCUNMAP)
exit_event("IOCTL", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, FMT_IOCTL_UNMAP, (double)now);
else {
if ((ti = find_event(thread, type)))
delete_event(ti);
}
continue;
case MACH_pageout:
if (kd[i].arg2)
exit_event("PAGE_OUT_ANON", thread, type, 0, kd[i].arg1, 0, 0, FMT_PGOUT, (double)now);
else
exit_event("PAGE_OUT_FILE", thread, type, 0, kd[i].arg1, 0, 0, FMT_PGOUT, (double)now);
continue;
case MACH_vmfault:
if (kd[i].arg4 == DBG_PAGEIN_FAULT)
exit_event("PAGE_IN", thread, type, 0, kd[i].arg1, kd[i].arg2, 0, FMT_PGIN, (double)now);
else if (kd[i].arg4 == DBG_PAGEINV_FAULT)
exit_event("PAGE_IN_FILE", thread, type, 0, kd[i].arg1, kd[i].arg2, 0, FMT_PGIN, (double)now);
else if (kd[i].arg4 == DBG_PAGEIND_FAULT)
exit_event("PAGE_IN_ANON", thread, type, 0, kd[i].arg1, kd[i].arg2, 0, FMT_PGIN, (double)now);
else if (kd[i].arg4 == DBG_CACHE_HIT_FAULT)
exit_event("CACHE_HIT", thread, type, 0, kd[i].arg1, kd[i].arg2, 0, FMT_CACHEHIT, (double)now);
else {
if ((ti = find_event(thread, type)))
delete_event(ti);
}
continue;
case MSC_map_fd:
exit_event("map_fd", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, FMT_FD, (double)now);
continue;
case BSC_mmap_extended:
case BSC_mmap_extended2:
case BSC_msync_extended:
case BSC_pread_extended:
case BSC_pwrite_extended:
extend_syscall(thread, type, &kd[i]);
continue;
}
if ((type & CSC_MASK) == BSC_BASE) {
if ((index = BSC_INDEX(type)) >= MAX_BSD_SYSCALL)
continue;
if (bsd_syscalls[index].sc_name) {
exit_event(bsd_syscalls[index].sc_name, thread, type, kd[i].arg1, kd[i].arg2, kd[i].arg3, kd[i].arg4,
bsd_syscalls[index].sc_format, (double)now);
if (type == BSC_exit)
delete_map_entry(thread);
}
} else if ((type & CLASS_MASK) == FILEMGR_BASE) {
if ((index = filemgr_index(type)) >= MAX_FILEMGR)
continue;
if (filemgr_calls[index].fm_name) {
exit_event(filemgr_calls[index].fm_name, thread, type, kd[i].arg1, kd[i].arg2, kd[i].arg3, kd[i].arg4,
FMT_DEFAULT, (double)now);
}
}
}
fflush(0);
}
void
enter_event_now(uintptr_t thread, int type, kd_buf *kd, char *name, double now)
{
th_info_t ti;
threadmap_t tme;
int secs;
int usecs;
long long l_usecs;
long curr_time;
int clen = 0;
int tsclen = 0;
int nmclen = 0;
int argsclen = 0;
char buf[MAXWIDTH];
if ((ti = add_event(thread, type)) == NULL)
return;
ti->stime = now;
ti->arg1 = kd->arg1;
ti->arg2 = kd->arg2;
ti->arg3 = kd->arg3;
ti->arg4 = kd->arg4;
if ((type & CLASS_MASK) == FILEMGR_BASE &&
(!RAW_flag || (now >= start_time && now <= end_time))) {
filemgr_in_progress++;
ti->in_filemgr = 1;
if (RAW_flag) {
l_usecs = (long long)((now - bias_now) / divisor);
l_usecs += (sample_TOD_secs * 1000000) + sample_TOD_usecs;
} else
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], ".%06ld", (long)usecs);
tsclen = strlen(buf);
}
printf("%s", buf);
tme = find_map_entry(thread);
if (tme) {
sprintf(buf, " %-25.25s ", name);
nmclen = strlen(buf);
printf("%s", buf);
sprintf(buf, "(%d, 0x%lx, 0x%lx, 0x%lx)", (short)kd->arg1, kd->arg2, kd->arg3, kd->arg4);
argsclen = strlen(buf);
if (columns > MAXCOLS || wideflag) {
clen = columns - (tsclen + nmclen + argsclen + 20 + 11);
} else
clen = columns - (tsclen + nmclen + argsclen + 12);
if (clen > 0) {
printf("%s", buf);
memset(buf, ' ', clen);
buf[clen] = '\0';
printf("%s", buf);
}
else if ((argsclen + clen) > 0) {
memset(buf, ' ', (argsclen + clen));
buf[argsclen + clen] = '\0';
printf("%s", buf);
}
if (columns > MAXCOLS || wideflag)
printf("%s.%d\n", tme->tm_command, (int)thread);
else
printf("%-12.12s\n", tme->tm_command);
} else
printf(" %-24.24s (%5d, %#lx, 0x%lx, 0x%lx)\n", name, (short)kd->arg1, kd->arg2, kd->arg3, kd->arg4);
}
}
void
enter_event(uintptr_t thread, int type, kd_buf *kd, char *name, double now)
{
int index;
if (type == MACH_pageout || type == MACH_vmfault || type == MSC_map_fd || type == SPEC_ioctl || type == Throttled || type == P_CS_SYNC_DISK) {
enter_event_now(thread, type, kd, name, now);
return;
}
if ((type & CSC_MASK) == BSC_BASE) {
if ((index = BSC_INDEX(type)) >= MAX_BSD_SYSCALL)
return;
if (bsd_syscalls[index].sc_name)
enter_event_now(thread, type, kd, name, now);
return;
}
if ((type & CLASS_MASK) == FILEMGR_BASE) {
if ((index = filemgr_index(type)) >= MAX_FILEMGR)
return;
if (filemgr_calls[index].fm_name)
enter_event_now(thread, type, kd, name, now);
}
}
void
extend_syscall(uintptr_t thread, int type, kd_buf *kd)
{
th_info_t ti;
switch (type) {
case BSC_mmap_extended:
if ((ti = find_event(thread, BSC_mmap)) == (struct th_info *)0)
return;
ti->arg8 = ti->arg3;
ti->arg1 = kd->arg1;
ti->arg3 = kd->arg2;
ti->arg5 = kd->arg3;
break;
case BSC_mmap_extended2:
if ((ti = find_event(thread, BSC_mmap)) == (struct th_info *)0)
return;
ti->arg2 = kd->arg1;
ti->arg4 = kd->arg2;
ti->arg6 = kd->arg3;
ti->arg7 = kd->arg4;
break;
case BSC_msync_extended:
if ((ti = find_event(thread, BSC_msync)) == (struct th_info *)0) {
if ((ti = find_event(thread, BSC_msync_nocancel)) == (struct th_info *)0)
return;
}
ti->arg4 = kd->arg1;
ti->arg5 = kd->arg2;
break;
case BSC_pread_extended:
if ((ti = find_event(thread, BSC_pread)) == (struct th_info *)0) {
if ((ti = find_event(thread, BSC_pread_nocancel)) == (struct th_info *)0)
return;
}
ti->arg1 = kd->arg1;
ti->arg2 = kd->arg2;
ti->arg3 = kd->arg3;
ti->arg4 = kd->arg4;
break;
case BSC_pwrite_extended:
if ((ti = find_event(thread, BSC_pwrite)) == (struct th_info *)0) {
if ((ti = find_event(thread, BSC_pwrite_nocancel)) == (struct th_info *)0)
return;
}
ti->arg1 = kd->arg1;
ti->arg2 = kd->arg2;
ti->arg3 = kd->arg3;
ti->arg4 = kd->arg4;
break;
default:
return;
}
}
void
exit_event(char *sc_name, uintptr_t thread, int type, int arg1, int arg2, int arg3, int arg4,
int format, double now)
{
th_info_t ti;
if ((ti = find_event(thread, type)) == (struct th_info *)0)
return;
if (check_filter_mode(ti, type, arg1, arg2, sc_name))
format_print(ti, sc_name, thread, type, arg1, arg2, arg3, arg4, format, now, ti->stime, ti->waited, (char *)ti->pathname, NULL);
if ((type & CLASS_MASK) == FILEMGR_BASE) {
ti->in_filemgr = 0;
if (filemgr_in_progress > 0)
filemgr_in_progress--;
}
delete_event(ti);
}
void
get_mode_nibble(char * buf, int smode, int special, char x_on, char x_off)
{
if (smode & 04)
buf[0] = 'r';
if (smode & 02)
buf[1] = 'w';
if (smode & 01) {
if (special)
buf[2] = x_on;
else
buf[2] = 'x';
} else {
if (special)
buf[2] = x_off;
}
}
void
get_mode_string(int mode, char *buf)
{
memset(buf, '-', 9);
buf[9] = '\0';
get_mode_nibble(&buf[6], mode, (mode & 01000), 't', 'T');
get_mode_nibble(&buf[3], (mode>>3), (mode & 02000), 's', 'S');
get_mode_nibble(&buf[0], (mode>>6), (mode & 04000), 's', 'S');
}
int clip_64bit(char *s, uint64_t value)
{
int clen = 0;
if ( (value & 0xff00000000000000LL) )
clen = printf("%s0x%16.16qx", s, value);
else if ( (value & 0x00ff000000000000LL) )
clen = printf("%s0x%14.14qx ", s, value);
else if ( (value & 0x0000ff0000000000LL) )
clen = printf("%s0x%12.12qx ", s, value);
else if ( (value & 0x000000ff00000000LL) )
clen = printf("%s0x%10.10qx ", s, value);
else
clen = printf("%s0x%8.8qx ", s, value);
return (clen);
}
void
format_print(struct th_info *ti, char *sc_name, uintptr_t thread, int type, int arg1, int arg2, int arg3, int arg4,
int format, double now, double stime, int waited, char *pathname, struct diskio *dio)
{
int secs;
int usecs;
int nopadding = 0;
long long l_usecs;
long curr_time;
char *command_name;
int in_filemgr = 0;
int len = 0;
int clen = 0;
int tlen = 0;
int class;
uint64_t user_addr;
uint64_t user_size;
char *framework_name;
char *framework_type;
char *p1;
char *p2;
char buf[MAXWIDTH];
char cs_diskname[32];
command_name = "";
static char timestamp[32];
static int last_timestamp = -1;
static int timestamp_len = 0;
if (RAW_flag) {
l_usecs = (long long)((now - bias_now) / divisor);
if ((double)l_usecs < start_time || (double)l_usecs > end_time)
return;
l_usecs += (sample_TOD_secs * 1000000) + sample_TOD_usecs;
}
else
l_usecs = (long long)(now / divisor);
secs = l_usecs / 1000000;
curr_time = bias_secs + secs;
class = type >> 24;
if (dio)
command_name = dio->issuing_command;
else {
threadmap_t tme;
if ((tme = find_map_entry(thread)))
command_name = tme->tm_command;
}
if (last_timestamp != curr_time) {
timestamp_len = sprintf(timestamp, "%-8.8s", &(ctime(&curr_time)[11]));
last_timestamp = curr_time;
}
if (columns > MAXCOLS || wideflag) {
int usec;
tlen = timestamp_len;
nopadding = 0;
usec = (l_usecs - (long long)((long long)secs * 1000000));
sprintf(×tamp[tlen], ".%06ld", (long)usec);
tlen += 7;
timestamp[tlen] = '\0';
if (filemgr_in_progress) {
if (class != FILEMGR_CLASS) {
if (find_event(thread, -1))
in_filemgr = 1;
}
}
} else
nopadding = 1;
if ((class == FILEMGR_CLASS) && (columns > MAXCOLS || wideflag))
clen = printf("%s %-20.20s", timestamp, sc_name);
else if (in_filemgr)
clen = printf("%s %-15.15s", timestamp, sc_name);
else
clen = printf("%s %-17.17s", timestamp, sc_name);
framework_name = NULL;
if (columns > MAXCOLS || wideflag) {
off_t offset_reassembled = 0LL;
switch (format) {
case FMT_DEFAULT:
if (arg1)
clen += printf(" [%3d] ", arg1);
else
clen += printf(" ");
break;
case FMT_FD:
if (arg1)
clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
else
clen += printf(" F=%-3d", ti->arg1);
break;
case FMT_FD_2:
if (arg1)
clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
else
clen += printf(" F=%-3d F=%-3d", ti->arg1, arg2);
break;
case FMT_FD_IO:
if (arg1)
clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
else
clen += printf(" F=%-3d B=0x%-6x", ti->arg1, arg2);
break;
case FMT_PGIN:
user_addr = ((uint64_t)arg2 << 32) | (uint32_t)arg3;
lookup_name(user_addr, &framework_type, &framework_name);
clen += clip_64bit(" A=", user_addr);
break;
case FMT_CACHEHIT:
user_addr = ((uint64_t)arg2 << 32) | (uint32_t)arg3;
lookup_name(user_addr, &framework_type, &framework_name);
clen += clip_64bit(" A=", user_addr);
break;
case FMT_PGOUT:
clen += printf(" B=0x%-8x", arg2);
break;
case FMT_DISKIO:
if (dio->io_errno)
clen += printf(" D=0x%8.8x [%3d]", dio->blkno, dio->io_errno);
else
clen += printf(" D=0x%8.8x B=0x%-10x /dev/%s", dio->blkno, dio->iosize, find_disk_name(dio->dev));
break;
case FMT_DISKIO_CS:
if (dio->io_errno)
clen += printf(" D=0x%8.8x [%3d]", dio->blkno, dio->io_errno);
else
clen += printf(" D=0x%8.8x B=0x%-10x /dev/%s", dio->blkno, dio->iosize, generate_cs_disk_name(dio->dev, &cs_diskname[0]));
break;
case FMT_SYNC_DISK_CS:
clen += printf(" /dev/%s", generate_cs_disk_name(arg1, &cs_diskname[0]));
break;
case FMT_MSYNC:
{
int mlen = 0;
buf[0] = '\0';
if (ti->arg3 & MS_ASYNC)
mlen += sprintf(&buf[mlen], "MS_ASYNC | ");
else
mlen += sprintf(&buf[mlen], "MS_SYNC | ");
if (ti->arg3 & MS_INVALIDATE)
mlen += sprintf(&buf[mlen], "MS_INVALIDATE | ");
if (ti->arg3 & MS_KILLPAGES)
mlen += sprintf(&buf[mlen], "MS_KILLPAGES | ");
if (ti->arg3 & MS_DEACTIVATE)
mlen += sprintf(&buf[mlen], "MS_DEACTIVATE | ");
if (ti->arg3 & ~(MS_ASYNC | MS_SYNC | MS_INVALIDATE | MS_KILLPAGES | MS_DEACTIVATE))
mlen += sprintf(&buf[mlen], "UNKNOWN | ");
if (mlen)
buf[mlen - 3] = '\0';
if (arg1)
clen += printf(" [%3d]", arg1);
user_addr = (((off_t)(unsigned int)(ti->arg4)) << 32) | (unsigned int)(ti->arg1);
clen += clip_64bit(" A=", user_addr);
user_size = (((off_t)(unsigned int)(ti->arg5)) << 32) | (unsigned int)(ti->arg2);
clen += printf(" B=0x%-16qx <%s>", user_size, buf);
break;
}
case FMT_FCNTL:
{
char *p = NULL;
int fd = -1;
if (arg1)
clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
else
clen += printf(" F=%-3d", ti->arg1);
switch(ti->arg2) {
case F_DUPFD:
p = "DUPFD";
break;
case F_GETFD:
p = "GETFD";
break;
case F_SETFD:
p = "SETFD";
break;
case F_GETFL:
p = "GETFL";
break;
case F_SETFL:
p = "SETFL";
break;
case F_GETOWN:
p = "GETOWN";
break;
case F_SETOWN:
p = "SETOWN";
break;
case F_GETLK:
p = "GETLK";
break;
case F_SETLK:
p = "SETLK";
break;
case F_SETLKW:
p = "SETLKW";
break;
case F_PREALLOCATE:
p = "PREALLOCATE";
break;
case F_SETSIZE:
p = "SETSIZE";
break;
case F_RDADVISE:
p = "RDADVISE";
break;
case F_GETPATH:
p = "GETPATH";
break;
case F_FULLFSYNC:
p = "FULLFSYNC";
break;
case F_PATHPKG_CHECK:
p = "PATHPKG_CHECK";
break;
case F_OPENFROM:
p = "OPENFROM";
if (arg1 == 0)
fd = arg2;
break;
case F_UNLINKFROM:
p = "UNLINKFROM";
break;
case F_CHECK_OPENEVT:
p = "CHECK_OPENEVT";
break;
case F_NOCACHE:
if (ti->arg3)
p = "CACHING OFF";
else
p = "CACHING ON";
break;
case F_GLOBAL_NOCACHE:
if (ti->arg3)
p = "CACHING OFF (GLOBAL)";
else
p = "CACHING ON (GLOBAL)";
break;
}
if (p) {
if (fd == -1)
clen += printf(" <%s>", p);
else
clen += printf(" <%s> F=%d", p, fd);
} else
clen += printf(" <CMD=%d>", ti->arg2);
break;
}
case FMT_IOCTL:
{
if (arg1)
clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
else
clen += printf(" F=%-3d", ti->arg1);
clen += printf(" <CMD=0x%x>", ti->arg2);
break;
}
case FMT_IOCTL_SYNC:
{
clen += printf(" <DKIOCSYNCHRONIZECACHE> /dev/%s", find_disk_name(arg1));
break;
}
case FMT_IOCTL_UNMAP:
{
clen += printf(" <DKIOCUNMAP> /dev/%s", find_disk_name(arg1));
break;
}
case FMT_UNMAP_INFO:
{
clen += printf(" D=0x%8.8x B=0x%-10x /dev/%s", arg2, arg3, find_disk_name(arg1));
break;
}
case FMT_SELECT:
if (arg1)
clen += printf(" [%3d]", arg1);
else
clen += printf(" S=%-3d", arg2);
break;
case FMT_LSEEK:
case FMT_PREAD:
clen += printf(" F=%-3d", ti->arg1);
if (arg1)
clen += printf("[%3d] ", arg1);
else {
if (format == FMT_PREAD)
clen += printf(" B=0x%-8x ", arg2);
else
clen += printf(" ");
}
if (format == FMT_PREAD)
offset_reassembled = (((off_t)(unsigned int)(ti->arg3)) << 32) | (unsigned int)(ti->arg4);
else
#ifdef __ppc__
offset_reassembled = (((off_t)(unsigned int)(arg2)) << 32) | (unsigned int)(arg3);
#else
offset_reassembled = (((off_t)(unsigned int)(arg3)) << 32) | (unsigned int)(arg2);
#endif
clen += clip_64bit("O=", offset_reassembled);
if (format == FMT_LSEEK) {
char *mode;
if (ti->arg4 == SEEK_SET)
mode = "SEEK_SET";
else if (ti->arg4 == SEEK_CUR)
mode = "SEEK_CUR";
else if (ti->arg4 == SEEK_END)
mode = "SEEK_END";
else
mode = "UNKNOWN";
clen += printf(" <%s>", mode);
}
break;
case FMT_MMAP:
clen += printf(" F=%-3d ", ti->arg1);
if (arg1)
clen += printf("[%3d] ", arg1);
else {
user_addr = (((off_t)(unsigned int)(ti->arg2)) << 32) | (unsigned int)(ti->arg3);
clen += clip_64bit("A=", user_addr);
offset_reassembled = (((off_t)(unsigned int)(ti->arg6)) << 32) | (unsigned int)(ti->arg7);
clen += clip_64bit("O=", offset_reassembled);
user_size = (((off_t)(unsigned int)(ti->arg4)) << 32) | (unsigned int)(ti->arg5);
clen += printf("B=0x%-16qx", user_size);
clen += printf(" <");
if (ti->arg8 & PROT_READ)
clen += printf("READ");
if (ti->arg8 & PROT_WRITE)
clen += printf("|WRITE");
if (ti->arg8 & PROT_EXEC)
clen += printf("|EXEC");
clen += printf(">");
}
break;
case FMT_TRUNC:
case FMT_FTRUNC:
if (format == FMT_FTRUNC)
clen += printf(" F=%-3d", ti->arg1);
else
clen += printf(" ");
if (arg1)
clen += printf("[%3d]", arg1);
#ifdef __ppc__
offset_reassembled = (((off_t)(unsigned int)(ti->arg2)) << 32) | (unsigned int)(ti->arg3);
#else
offset_reassembled = (((off_t)(unsigned int)(ti->arg3)) << 32) | (unsigned int)(ti->arg2);
#endif
clen += clip_64bit(" O=", offset_reassembled);
nopadding = 1;
break;
case FMT_FCHFLAGS:
case FMT_CHFLAGS:
{
int mlen = 0;
if (format == FMT_FCHFLAGS) {
if (arg1)
clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
else
clen += printf(" F=%-3d", ti->arg1);
} else {
if (arg1)
clen += printf(" [%3d] ", arg1);
}
buf[mlen++] = ' ';
buf[mlen++] = '<';
if (ti->arg2 & UF_NODUMP)
mlen += sprintf(&buf[mlen], "UF_NODUMP | ");
if (ti->arg2 & UF_IMMUTABLE)
mlen += sprintf(&buf[mlen], "UF_IMMUTABLE | ");
if (ti->arg2 & UF_APPEND)
mlen += sprintf(&buf[mlen], "UF_APPEND | ");
if (ti->arg2 & UF_OPAQUE)
mlen += sprintf(&buf[mlen], "UF_OPAQUE | ");
if (ti->arg2 & SF_ARCHIVED)
mlen += sprintf(&buf[mlen], "SF_ARCHIVED | ");
if (ti->arg2 & SF_IMMUTABLE)
mlen += sprintf(&buf[mlen], "SF_IMMUTABLE | ");
if (ti->arg2 & SF_APPEND)
mlen += sprintf(&buf[mlen], "SF_APPEND | ");
if (ti->arg2 == 0)
mlen += sprintf(&buf[mlen], "CLEAR_ALL_FLAGS | ");
else if (ti->arg2 & ~(UF_NODUMP | UF_IMMUTABLE | UF_APPEND | SF_ARCHIVED | SF_IMMUTABLE | SF_APPEND))
mlen += sprintf(&buf[mlen], "UNKNOWN | ");
if (mlen >= 3)
mlen -= 3;
buf[mlen++] = '>';
buf[mlen] = '\0';
if (mlen < 19) {
memset(&buf[mlen], ' ', 19 - mlen);
mlen = 19;
}
clen += printf("%s", buf);
nopadding = 1;
break;
}
case FMT_UMASK:
case FMT_FCHMOD:
case FMT_FCHMOD_EXT:
case FMT_CHMOD:
case FMT_CHMOD_EXT:
{
int mode;
if (format == FMT_FCHMOD || format == FMT_FCHMOD_EXT) {
if (arg1)
clen += printf(" F=%-3d[%3d] ", ti->arg1, arg1);
else
clen += printf(" F=%-3d ", ti->arg1);
} else {
if (arg1)
clen += printf(" [%3d] ", arg1);
else
clen += printf(" ");
}
if (format == FMT_UMASK)
mode = ti->arg1;
else if (format == FMT_FCHMOD || format == FMT_CHMOD)
mode = ti->arg2;
else
mode = ti->arg4;
get_mode_string(mode, &buf[0]);
if (arg1 == 0)
clen += printf("<%s> ", buf);
else
clen += printf("<%s>", buf);
break;
}
case FMT_ACCESS:
{
char mode[5];
memset(mode, '_', 4);
mode[4] = '\0';
if (ti->arg2 & R_OK)
mode[0] = 'R';
if (ti->arg2 & W_OK)
mode[1] = 'W';
if (ti->arg2 & X_OK)
mode[2] = 'X';
if (ti->arg2 == F_OK)
mode[3] = 'F';
if (arg1)
clen += printf(" [%3d] (%s) ", arg1, mode);
else
clen += printf(" (%s) ", mode);
nopadding = 1;
break;
}
case FMT_MOUNT:
{
if (arg1)
clen += printf(" [%3d] <FLGS=0x%x> ", arg1, ti->arg3);
else
clen += printf(" <FLGS=0x%x> ", ti->arg3);
nopadding = 1;
break;
}
case FMT_UNMOUNT:
{
char *mountflag;
if (ti->arg2 & MNT_FORCE)
mountflag = "<FORCE>";
else
mountflag = "";
if (arg1)
clen += printf(" [%3d] %s ", arg1, mountflag);
else
clen += printf(" %s ", mountflag);
nopadding = 1;
break;
}
case FMT_OPEN:
{
char mode[7];
memset(mode, '_', 6);
mode[6] = '\0';
if (ti->arg2 & O_RDWR) {
mode[0] = 'R';
mode[1] = 'W';
} else if (ti->arg2 & O_WRONLY)
mode[1] = 'W';
else
mode[0] = 'R';
if (ti->arg2 & O_CREAT)
mode[2] = 'C';
if (ti->arg2 & O_APPEND)
mode[3] = 'A';
if (ti->arg2 & O_TRUNC)
mode[4] = 'T';
if (ti->arg2 & O_EXCL)
mode[5] = 'E';
if (arg1)
clen += printf(" [%3d] (%s) ", arg1, mode);
else
clen += printf(" F=%-3d (%s) ", arg2, mode);
nopadding = 1;
break;
}
case FMT_SOCKET:
{
char *domain;
char *type;
switch (ti->arg1) {
case AF_UNIX:
domain = "AF_UNIX";
break;
case AF_INET:
domain = "AF_INET";
break;
case AF_ISO:
domain = "AF_ISO";
break;
case AF_NS:
domain = "AF_NS";
break;
case AF_IMPLINK:
domain = "AF_IMPLINK";
break;
default:
domain = "UNKNOWN";
break;
}
switch (ti->arg2) {
case SOCK_STREAM:
type = "SOCK_STREAM";
break;
case SOCK_DGRAM:
type = "SOCK_DGRAM";
break;
case SOCK_RAW:
type = "SOCK_RAW";
break;
case SOCK_SEQPACKET:
type = "SOCK_SEQPACKET";
break;
case SOCK_RDM:
type = "SOCK_RDM";
break;
default:
type = "UNKNOWN";
break;
}
if (arg1)
clen += printf(" [%3d] <%s, %s, 0x%x>", arg1, domain, type, ti->arg3);
else
clen += printf(" F=%-3d <%s, %s, 0x%x>", arg2, domain, type, ti->arg3);
break;
}
case FMT_AIO_FSYNC:
{
char *op;
if (ti->arg1 == O_SYNC || ti->arg1 == 0)
op = "AIO_FSYNC";
#if O_DSYNC
else if (ti->arg1 == O_DSYNC)
op = "AIO_DSYNC";
#endif
else
op = "UNKNOWN";
if (arg1)
clen += printf(" [%3d] P=0x%8.8x <%s>", arg1, ti->arg2, op);
else
clen += printf(" P=0x%8.8x <%s>", ti->arg2, op);
break;
}
case FMT_AIO_RETURN:
if (arg1)
clen += printf(" [%3d] P=0x%8.8x", arg1, ti->arg1);
else
clen += printf(" P=0x%8.8x B=0x%-8x", ti->arg1, arg2);
break;
case FMT_AIO_SUSPEND:
if (arg1)
clen += printf(" [%3d] N=%d", arg1, ti->arg2);
else
clen += printf(" N=%d", ti->arg2);
break;
case FMT_AIO_CANCEL:
if (ti->arg2) {
if (arg1)
clen += printf(" [%3d] P=0x%8.8x", arg1, ti->arg2);
else
clen += printf(" P=0x%8.8x", ti->arg2);
} else {
if (arg1)
clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
else
clen += printf(" F=%-3d", ti->arg1);
}
break;
case FMT_AIO:
if (arg1)
clen += printf(" [%3d] P=0x%8.8x", arg1, ti->arg1);
else
clen += printf(" P=0x%8.8x", ti->arg1);
break;
case FMT_LIO_LISTIO:
{
char *op;
if (ti->arg1 == LIO_NOWAIT)
op = "LIO_NOWAIT";
else if (ti->arg1 == LIO_WAIT)
op = "LIO_WAIT";
else
op = "UNKNOWN";
if (arg1)
clen += printf(" [%3d] N=%d <%s>", arg1, ti->arg3, op);
else
clen += printf(" N=%d <%s>", ti->arg3, op);
break;
}
}
}
if (columns > MAXCOLS || wideflag)
clen = columns - (clen + 14 + 20 + 11);
else
clen = columns - (clen + 14 + 12);
if (class != FILEMGR_CLASS && !nopadding)
clen -= 3;
if (framework_name)
len = sprintf(&buf[0], " %s %s ", framework_type, framework_name);
else if (*pathname != '\0') {
len = sprintf(&buf[0], " %s ", pathname);
if (format == FMT_MOUNT && ti->pathname2[0]) {
int len2;
memset(&buf[len], ' ', 2);
len2 = sprintf(&buf[len+2], " %s ", (char *)ti->pathname2);
len = len + 2 + len2;
}
} else
len = 0;
if (clen > len) {
memset(&buf[len], ' ', clen - len);
buf[clen] = '\0';
pathname = buf;
} else if (clen == len) {
pathname = buf;
} else if ((clen > 0) && (clen < len)) {
buf[len-clen] = ' ';
pathname = &buf[len - clen];
} else {
pathname = "";
}
usecs = (unsigned long)(((now - stime) + (divisor-1)) / divisor);
secs = usecs / 1000000;
usecs -= secs * 1000000;
if (class != FILEMGR_CLASS && !nopadding)
p1 = " ";
else
p1 = "";
if (waited)
p2 = " W";
else
p2 = " ";
if (columns > MAXCOLS || wideflag)
printf("%s%s %3ld.%06ld%s %s.%d\n", p1, pathname, (unsigned long)secs, (unsigned long)usecs, p2, command_name, (int)thread);
else
printf("%s%s %3ld.%06ld%s %-12.12s\n", p1, pathname, (unsigned long)secs, (unsigned long)usecs, p2, command_name);
}
void
delete_event(th_info_t ti_to_delete) {
th_info_t ti;
th_info_t ti_prev;
int hashid;
hashid = ti_to_delete->thread & HASH_MASK;
if ((ti = th_info_hash[hashid])) {
if (ti == ti_to_delete)
th_info_hash[hashid] = ti->next;
else {
ti_prev = ti;
for (ti = ti->next; ti; ti = ti->next) {
if (ti == ti_to_delete) {
ti_prev->next = ti->next;
break;
}
ti_prev = ti;
}
}
if (ti) {
ti->next = th_info_freelist;
th_info_freelist = ti;
}
}
}
th_info_t
add_event(uintptr_t thread, int type) {
th_info_t ti;
int hashid;
if ((ti = th_info_freelist))
th_info_freelist = ti->next;
else
ti = (th_info_t)malloc(sizeof(struct th_info));
hashid = thread & HASH_MASK;
ti->next = th_info_hash[hashid];
th_info_hash[hashid] = ti;
ti->thread = thread;
ti->type = type;
ti->waited = 0;
ti->in_filemgr = 0;
ti->pathptr = ti->pathname;
ti->pathname[0] = 0;
ti->pathname2[0] = 0;
return (ti);
}
th_info_t
find_event(uintptr_t thread, int type) {
th_info_t ti;
int hashid;
hashid = thread & HASH_MASK;
for (ti = th_info_hash[hashid]; ti; ti = ti->next) {
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 ((th_info_t) 0);
}
void
delete_all_events() {
th_info_t ti = 0;
th_info_t ti_next = 0;
int i;
for (i = 0; i < HASH_SIZE; i++) {
for (ti = th_info_hash[i]; ti; ti = ti_next) {
ti_next = ti->next;
ti->next = th_info_freelist;
th_info_freelist = ti;
}
th_info_hash[i] = 0;
}
}
void
mark_thread_waited(uintptr_t thread) {
th_info_t ti;
int hashid;
hashid = thread & HASH_MASK;
for (ti = th_info_hash[hashid]; ti; ti = ti->next) {
if (ti->thread == thread)
ti->waited = 1;
}
}
void read_command_map()
{
size_t size;
int i;
int total_threads = 0;
kd_threadmap *mapptr = 0;
delete_all_map_entries();
if (!RAW_flag) {
total_threads = bufinfo.nkdthreads;
size = bufinfo.nkdthreads * sizeof(kd_threadmap);
if (size) {
if ((mapptr = (kd_threadmap *) malloc(size))) {
int mib[6];
bzero (mapptr, size);
mib[0] = CTL_KERN;
mib[1] = KERN_KDEBUG;
mib[2] = KERN_KDTHRMAP;
mib[3] = 0;
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 3, mapptr, &size, NULL, 0) < 0) {
free(mapptr);
return;
}
}
}
} else {
RAW_header header;
off_t offset;
RAW_fd = open(RAW_file, O_RDONLY);
if (RAW_fd < 0) {
perror("Can't open RAW file");
exit(1);
}
if (read(RAW_fd, &header, sizeof(RAW_header)) != sizeof(RAW_header)) {
perror("read failed");
exit(2);
}
if (header.version_no != RAW_VERSION1) {
header.version_no = RAW_VERSION0;
header.TOD_secs = time((long *)0);
header.TOD_usecs = 0;
lseek(RAW_fd, (off_t)0, SEEK_SET);
if (read(RAW_fd, &header.thread_count, sizeof(int)) != sizeof(int)) {
perror("read failed");
exit(2);
}
}
sample_TOD_secs = header.TOD_secs;
sample_TOD_usecs = header.TOD_usecs;
total_threads = header.thread_count;
size = total_threads * sizeof(kd_threadmap);
if (size) {
if ((mapptr = (kd_threadmap *) malloc(size))) {
bzero (mapptr, size);
if (read(RAW_fd, mapptr, size) != size) {
free(mapptr);
return;
}
}
}
if (header.version_no != RAW_VERSION0) {
offset = lseek(RAW_fd, (off_t)0, SEEK_CUR);
offset = (offset + (4095)) & ~4095;
lseek(RAW_fd, offset, SEEK_SET);
}
}
for (i = 0; i < total_threads; i++)
create_map_entry(mapptr[i].thread, mapptr[i].valid, &mapptr[i].command[0]);
free(mapptr);
}
void delete_all_map_entries()
{
threadmap_t tme = 0;
threadmap_t tme_next = 0;
int i;
for (i = 0; i < HASH_SIZE; i++) {
for (tme = threadmap_hash[i]; tme; tme = tme_next) {
if (tme->tm_setptr)
free(tme->tm_setptr);
tme_next = tme->tm_next;
tme->tm_next = threadmap_freelist;
threadmap_freelist = tme;
}
threadmap_hash[i] = 0;
}
}
void create_map_entry(uintptr_t thread, int pid, char *command)
{
threadmap_t tme;
int hashid;
if ((tme = threadmap_freelist))
threadmap_freelist = tme->tm_next;
else
tme = (threadmap_t)malloc(sizeof(struct threadmap));
tme->tm_thread = thread;
tme->tm_setsize = 0;
tme->tm_setptr = 0;
(void)strncpy (tme->tm_command, command, MAXCOMLEN);
tme->tm_command[MAXCOMLEN] = '\0';
hashid = thread & HASH_MASK;
tme->tm_next = threadmap_hash[hashid];
threadmap_hash[hashid] = tme;
if (pid != 0 && pid != 1) {
if (!strncmp(command, "LaunchCFMA", 10))
(void)get_real_command_name(pid, tme->tm_command, MAXCOMLEN);
}
}
threadmap_t
find_map_entry(uintptr_t thread)
{
threadmap_t tme;
int hashid;
hashid = thread & HASH_MASK;
for (tme = threadmap_hash[hashid]; tme; tme = tme->tm_next) {
if (tme->tm_thread == thread)
return (tme);
}
return (0);
}
void
delete_map_entry(uintptr_t thread)
{
threadmap_t tme = 0;
threadmap_t tme_prev;
int hashid;
hashid = thread & HASH_MASK;
if ((tme = threadmap_hash[hashid])) {
if (tme->tm_thread == thread)
threadmap_hash[hashid] = tme->tm_next;
else {
tme_prev = tme;
for (tme = tme->tm_next; tme; tme = tme->tm_next) {
if (tme->tm_thread == thread) {
tme_prev->tm_next = tme->tm_next;
break;
}
tme_prev = tme;
}
}
if (tme) {
if (tme->tm_setptr)
free(tme->tm_setptr);
tme->tm_next = threadmap_freelist;
threadmap_freelist = tme;
}
}
}
void
fs_usage_fd_set(uintptr_t thread, unsigned int fd)
{
threadmap_t tme;
if ((tme = find_map_entry(thread)) == 0)
return;
if (tme->tm_setptr == (unsigned long *)0) {
if ((tme->tm_setptr = (unsigned long *)malloc(FS_USAGE_NFDBYTES(FS_USAGE_FD_SETSIZE))) == 0)
return;
tme->tm_setsize = FS_USAGE_FD_SETSIZE;
bzero(tme->tm_setptr, (FS_USAGE_NFDBYTES(FS_USAGE_FD_SETSIZE)));
}
while (tme->tm_setsize <= fd) {
int n;
n = tme->tm_setsize * 2;
tme->tm_setptr = (unsigned long *)realloc(tme->tm_setptr, (FS_USAGE_NFDBYTES(n)));
bzero(&tme->tm_setptr[(tme->tm_setsize/FS_USAGE_NFDBITS)], (FS_USAGE_NFDBYTES(tme->tm_setsize)));
tme->tm_setsize = n;
}
tme->tm_setptr[fd/FS_USAGE_NFDBITS] |= (1 << ((fd) % FS_USAGE_NFDBITS));
}
int
fs_usage_fd_isset(uintptr_t thread, unsigned int fd)
{
threadmap_t tme;
int ret = 0;
if ((tme = find_map_entry(thread))) {
if (tme->tm_setptr && fd < tme->tm_setsize)
ret = tme->tm_setptr[fd/FS_USAGE_NFDBITS] & (1 << (fd % FS_USAGE_NFDBITS));
}
return (ret);
}
void
fs_usage_fd_clear(uintptr_t thread, unsigned int fd)
{
threadmap_t tme;
if ((tme = find_map_entry(thread))) {
if (tme->tm_setptr && fd < tme->tm_setsize)
tme->tm_setptr[fd/FS_USAGE_NFDBITS] &= ~(1 << (fd % FS_USAGE_NFDBITS));
}
}
void
argtopid(char *str)
{
char *cp;
int ret;
int i;
ret = (int)strtol(str, &cp, 10);
if (cp == str || *cp) {
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 (!strncmp(str, kp_buffer[i].kp_proc.p_comm,
sizeof(kp_buffer[i].kp_proc.p_comm) -1))
pids[num_of_pids++] = kp_buffer[i].kp_proc.p_pid;
}
}
}
else if (num_of_pids < (MAX_PIDS - 1))
pids[num_of_pids++] = ret;
}
void
lookup_name(uint64_t user_addr, char **type, char **name)
{
int i;
int start, last;
*name = NULL;
*type = NULL;
if (numFrameworks) {
if ((user_addr >= framework32.b_address && user_addr < framework32.e_address) ||
(user_addr >= framework64.b_address && user_addr < framework64.e_address)) {
start = 0;
last = numFrameworks;
for (i = numFrameworks / 2; start < last; i = start + ((last - start) / 2)) {
if (user_addr > frameworkInfo[i].e_address)
start = i+1;
else
last = i;
}
if (start < numFrameworks &&
user_addr >= frameworkInfo[start].b_address && user_addr < frameworkInfo[start].e_address) {
*type = frameworkType[frameworkInfo[start].r_type];
*name = frameworkInfo[start].name;
}
}
}
}
static int compareFrameworkAddress(const void *aa, const void *bb)
{
LibraryInfo *a = (LibraryInfo *)aa;
LibraryInfo *b = (LibraryInfo *)bb;
if (a->b_address < b->b_address) return -1;
if (a->b_address == b->b_address) return 0;
return 1;
}
int scanline(char *inputstring, char **argv, int maxtokens)
{
int n = 0;
char **ap = argv, *p, *val;
for (p = inputstring; n < maxtokens && p != NULL; ) {
while ((val = strsep(&p, " \t")) != NULL && *val == '\0');
*ap++ = val;
n++;
}
*ap = 0;
return n;
}
int ReadSharedCacheMap(const char *path, LibraryRange *lr, char *linkedit_name)
{
uint64_t b_address, e_address;
char buf[1024];
char *fnp;
FILE *fd;
char frameworkName[256];
char *tokens[64];
int ntokens;
int type;
int linkedit_found = 0;
char *substring, *ptr;
bzero(buf, sizeof(buf));
bzero(tokens, sizeof(tokens));
lr->b_address = 0;
lr->e_address = 0;
if ((fd = fopen(path, "r")) == 0)
return 0;
while (fgets(buf, 1023, fd)) {
if (strncmp(buf, "mapping", 7))
break;
}
buf[strlen(buf)-1] = 0;
frameworkName[0] = 0;
for (;;) {
if ((substring = strrchr(buf, '.')))
{
while ( *substring != '/')
substring--;
substring++;
strncpy(frameworkName, substring, 256);
frameworkName[255] = 0;
substring = frameworkName;
while ( *substring != '/' && *substring)
substring++;
*substring = 0;
}
else
{
ptr = buf;
substring = ptr;
while (*ptr) {
if (*ptr == '/')
substring = ptr + 1;
ptr++;
}
strncpy(frameworkName, substring, 256);
frameworkName[255] = 0;
}
fnp = (char *)malloc(strlen(frameworkName) + 1);
strcpy(fnp, frameworkName);
while (fgets(buf, 1023, fd) && numFrameworks < (MAXINDEX - 2)) {
buf[strlen(buf)-1] = 0;
ntokens = scanline(buf, tokens, 64);
if (ntokens < 4)
continue;
if (strncmp(tokens[0], "__TEXT", 6) == 0)
type = TEXT_R;
else if (strncmp(tokens[0], "__DATA", 6) == 0)
type = DATA_R;
else if (strncmp(tokens[0], "__OBJC", 6) == 0)
type = OBJC_R;
else if (strncmp(tokens[0], "__IMPORT", 8) == 0)
type = IMPORT_R;
else if (strncmp(tokens[0], "__UNICODE", 9) == 0)
type = UNICODE_R;
else if (strncmp(tokens[0], "__IMAGE", 7) == 0)
type = IMAGE_R;
else if (strncmp(tokens[0], "__LINKEDIT", 10) == 0)
type = LINKEDIT_R;
else
type = -1;
if (type == LINKEDIT_R && linkedit_found)
break;
if (type != -1) {
b_address = strtoull(tokens[1], 0, 16);
e_address = strtoull(tokens[3], 0, 16);
frameworkInfo[numFrameworks].b_address = b_address;
frameworkInfo[numFrameworks].e_address = e_address;
frameworkInfo[numFrameworks].r_type = type;
if (type == LINKEDIT_R) {
frameworkInfo[numFrameworks].name = linkedit_name;
linkedit_found = 1;
} else
frameworkInfo[numFrameworks].name = fnp;
#if 0
printf("%s(%d): %qx-%qx\n", frameworkInfo[numFrameworks].name, type, b_address, e_address);
#endif
if (lr->b_address == 0 || b_address < lr->b_address)
lr->b_address = b_address;
if (lr->e_address == 0 || e_address > lr->e_address)
lr->e_address = e_address;
numFrameworks++;
}
if (type == LINKEDIT_R)
break;
}
if (fgets(buf, 1023, fd) == 0)
break;
buf[strlen(buf)-1] = 0;
}
fclose(fd);
#if 0
printf("%s range, %qx-%qx\n", path, lr->b_address, lr->e_address);
#endif
return 1;
}
void
SortFrameworkAddresses()
{
frameworkInfo[numFrameworks].b_address = frameworkInfo[numFrameworks - 1].b_address + 0x800000;
frameworkInfo[numFrameworks].e_address = frameworkInfo[numFrameworks].b_address;
frameworkInfo[numFrameworks].name = (char *)0;
qsort(frameworkInfo, numFrameworks, sizeof(LibraryInfo), compareFrameworkAddress);
}
struct diskio *insert_diskio(int type, int bp, int dev, int blkno, int io_size, uintptr_t thread, double curtime)
{
struct diskio *dio;
threadmap_t tme;
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 ((tme = find_map_entry(thread))) {
strncpy(dio->issuing_command, tme->tm_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, uintptr_t thread, double curtime)
{
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)
{
char *p = NULL;
int len = 0;
int type;
int format = FMT_DISKIO;
char buf[64];
type = dio->type;
if ((type & P_CS_Class) == P_CS_Class) {
switch (type) {
case P_CS_ReadChunk:
p = " RdChunkCS";
len = 13;
format = FMT_DISKIO_CS;
break;
case P_CS_WriteChunk:
p = " WrChunkCS";
len = 13;
format = FMT_DISKIO_CS;
break;
case P_CS_MetaRead:
p = " RdMetaCS";
len = 10;
format = FMT_DISKIO_CS;
break;
case P_CS_MetaWrite:
p = " WrMetaCS";
len = 10;
format = FMT_DISKIO_CS;
break;
case P_CS_TransformRead:
p = " RdBgTfCS";
len = 10;
break;
case P_CS_TransformWrite:
p = " WrBgTfCS";
len = 10;
break;
case P_CS_MigrationRead:
p = " RdBgMigrCS";
len = 12;
break;
case P_CS_MigrationWrite:
p = " WrBgMigrCS";
len = 12;
break;
}
strncpy(buf, p, len);
} else {
switch (type & P_DISKIO_TYPE) {
case P_RdMeta:
p = " RdMeta";
len = 8;
break;
case P_WrMeta:
p = " WrMeta";
len = 8;
break;
case P_RdData:
p = " RdData";
len = 8;
break;
case P_WrData:
p = " WrData";
len = 8;
break;
case P_PgIn:
p = " PgIn";
len = 6;
break;
case P_PgOut:
p = " PgOut";
len = 7;
break;
default:
p = " ";
len = 2;
break;
}
strncpy(buf, p, len);
buf[len++] = '[';
if (type & P_DISKIO_ASYNC)
buf[len++] = 'A';
else
buf[len++] = 'S';
if (type & P_DISKIO_NOCACHE)
buf[len++] = 'N';
if (type & P_DISKIO_THROTTLE)
buf[len++] = 'T';
else if (type & P_DISKIO_PASSIVE)
buf[len++] = 'P';
buf[len++] = ']';
}
buf[len] = 0;
if (check_filter_mode(NULL, type, 0, 0, buf))
format_print(NULL, buf, dio->issuing_thread, type, 0, 0, 0, 0, format, 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;
snprintf(nbuf, MAXPATHLEN, "%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);
}
void recache_disk_names()
{
struct diskrec *dnp, *next_dnp;
for (dnp = disk_list; dnp; dnp = next_dnp) {
next_dnp = dnp->next;
free(dnp->diskname);
free(dnp);
}
disk_list = NULL;
cache_disk_names();
}
char *find_disk_name(int dev)
{
struct diskrec *dnp;
int i;
if (dev == NFS_DEV)
return ("NFS");
if (dev == CS_DEV)
return ("CS");
for (i = 0; i < 2; i++) {
for (dnp = disk_list; dnp; dnp = dnp->next) {
if (dnp->dev == dev)
return (dnp->diskname);
}
recache_disk_names();
}
return ("NOTFOUND");
}
char *generate_cs_disk_name(int dev, char *s)
{
if (dev == -1)
return ("UNKNOWN");
sprintf(s, "disk%ds%d", (dev >> 16) & 0xffff, dev & 0xffff);
return (s);
}
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 (sc_name[0] == 'C' && !strcmp (sc_name, "CACHE_HIT")) {
if (filter_mode & CACHEHIT_FILTER)
return(0);
return(1);
}
if (filter_mode & EXEC_FILTER) {
if (type == BSC_execve || type == BSC_posix_spawn)
return(1);
return(0);
}
if (filter_mode & PATHNAME_FILTER) {
if (ti && ti->pathname[0])
return(1);
if (type == BSC_close || type == BSC_close_nocancel)
return(1);
return(0);
}
if ( !(filter_mode & (FILESYS_FILTER | NETWORK_FILTER)))
return(1);
if (ti == (struct th_info *)0) {
if (filter_mode & FILESYS_FILTER)
return(1);
return(0);
}
switch (type) {
case BSC_close:
case BSC_close_nocancel:
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:
case BSC_read_nocancel:
case BSC_write_nocancel:
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_accept_nocancel:
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:
case BSC_sendto_nocancel:
case BSC_recvfrom_nocancel:
case BSC_recvmsg_nocancel:
case BSC_sendmsg_nocancel:
case BSC_connect_nocancel:
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_select_nocancel:
case BSC_socketpair:
if (filter_mode & NETWORK_FILTER)
ret = 1;
break;
case BSC_dup:
case BSC_dup2:
fd = ti->arg1;
network_fd_isset = fs_usage_fd_isset(ti->thread, fd);
if (error == 0 && network_fd_isset) {
fd = retval;
fs_usage_fd_set(ti->thread, fd);
}
break;
default:
if (filter_mode & FILESYS_FILTER)
ret = 1;
break;
}
return(ret);
}
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
if (argmax > 8192) {
argmax = 8192;
}
#endif
arguments = (char *)malloc(argmax);
}
int
get_real_command_name(int pid, char *cbuf, int csize)
{
char *cp;
int mib[4];
char *command_beg, *command, *command_end;
if (cbuf == NULL)
return(0);
if (arguments)
bzero(arguments, argmax);
else
return(0);
mib[0] = CTL_KERN;
mib[1] = KERN_PROCARGS2;
mib[2] = pid;
mib[3] = 0;
if (sysctl(mib, 3, arguments, (size_t *)&argmax, NULL, 0) < 0)
return(0);
for (cp = arguments; cp < &arguments[argmax]; cp++) {
if (*cp == '\0') {
break;
}
}
if (cp == &arguments[argmax])
return(0);
for (; cp < &arguments[argmax]; cp++) {
if (*cp != '\0') {
break;
}
}
if (cp == &arguments[argmax])
return(0);
command_beg = cp;
for (; cp < &arguments[argmax]; cp++) {
if (*cp == '\0') {
break;
}
}
if (cp == &arguments[argmax])
return(0);
command_end = command = cp;
for (command--; command >= command_beg; command--) {
if (*command == '/') {
command++;
break;
}
}
(void) strncpy(cbuf, (char *)command, csize);
cbuf[csize-1] = '\0';
return(1);
}