*
* @APPLE_LICENSE_HEADER_START@
*
- * Copyright (c) 1999-2003 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 2.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.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * "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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
+ * 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. -DKERNEL_PRIVATE -O -o fs_usage fs_usage.c
+cc -I. -DPRIVATE -D__APPLE_PRIVATE -O -o fs_usage fs_usage.c
*/
#define Default_DELAY 1 /* default delay interval */
#include <sys/sysctl.h>
#include <errno.h>
#import <mach/clock_types.h>
+#import <mach/mach_time.h>
#include <err.h>
extern int errno;
* Network only or filesystem only output filter
* Default of zero means report all activity - no filtering
*/
-#define FILESYS_FILTER 1
-#define NETWORK_FILTER 2
-#define CACHEHIT_FILTER 4
-#define DEFAULT_DO_NOT_FILTER 0
-int filter_mode = DEFAULT_DO_NOT_FILTER;
+#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
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 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_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
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 filtered based on the mode provided\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 = \"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);
else if (!strcmp(optarg, "filesys"))
filter_mode |= FILESYS_FILTER;
else if (!strcmp(optarg, "cachehit"))
- filter_mode |= CACHEHIT_FILTER; /* turns off CACHE_HIT */
+ filter_mode &= ~CACHEHIT_FILTER; /* turns on CACHE_HIT */
+ else if (!strcmp(optarg, "exec"))
+ filter_mode |= EXEC_FILTER;
break;
default:
/* main loop */
while (1) {
- usleep(1000 * 25);
+ usleep(1000 * 20);
sample_sc();
}
count = needed;
if (bufinfo.flags & KDBG_WRAPPED) {
- fprintf(stderr, "buffer wrapped count = %d\n", count);
+ fprintf(stderr, "fs_usage: buffer overrun, events generated too quickly\n");
for (i = 0; i < cur_max; i++) {
th_state[i].thread = 0;
long curr_time;
struct th_info *ti;
struct diskio *dio;
- void enter_syscall();
- void exit_syscall();
- void extend_syscall();
- void kill_thread_map();
+
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)
else
{
create_map_entry(thread, ti->pid, (char *)&kd[i].arg1);
+
if (ti == &th_state[cur_max - 1])
cur_max--;
ti->thread = 0;
handle.
*/
- if ((long *)sargptr >= (long *)&ti->pathname[PATHLENGTH])
- continue;
-
+ 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,
vfslookup entries.
*/
- if (debugid & DBG_FUNC_START)
- {
+ if (debugid & DBG_FUNC_START) {
(long *)ti->pathptr = (long *)&ti->pathname[PATHLENGTH];
continue;
- }
+ }
*sargptr++ = kd[i].arg1;
*sargptr++ = kd[i].arg2;
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;
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;
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;
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;
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_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_mknod:
case BSC_chmod:
case BSC_chown:
+ case BSC_lchown:
case BSC_access:
case BSC_chflags:
case BSC_fchflags:
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 (i >= cur_max)
cur_max = i + 1;
-
if ((type >> 24) == FILEMGR_CLASS) {
ti->in_filemgr = 1;
void getdivisor()
{
+ struct mach_timebase_info mti;
- unsigned int delta;
- unsigned int abs_to_ns_num;
- unsigned int abs_to_ns_denom;
- unsigned int proc_to_abs_num;
- unsigned int proc_to_abs_denom;
+ mach_timebase_info(&mti);
- extern void MKGetTimeBaseInfo(unsigned int *, unsigned int *, unsigned int *, unsigned int *, unsigned int *);
-
- MKGetTimeBaseInfo (&delta, &abs_to_ns_num, &abs_to_ns_denom,
- &proc_to_abs_num, &proc_to_abs_denom);
-
- divisor = ((double)abs_to_ns_denom / (double)abs_to_ns_num) * 1000;
+ divisor = ((double)mti.denom / (double)mti.numer) * 1000;
}
}
}
- if (mapptr && (filter_mode != DEFAULT_DO_NOT_FILTER))
+ if (mapptr && (filter_mode & (NETWORK_FILTER | FILESYS_FILTER)))
{
if (fdmapptr)
{
{
map = &mapptr[i]; /* Reuse this entry, the thread has been
* reassigned */
- if(filter_mode && fdmapptr)
+ if ((filter_mode & (NETWORK_FILTER | FILESYS_FILTER)) && fdmapptr)
{
fdmap = &fdmapptr[i];
if (fdmap->fd_thread != thread) /* This shouldn't happen */
{
if (mapptr[i].valid == 0 )
map = &mapptr[i]; /* Reuse this invalid entry */
- if (filter_mode && fdmapptr)
+ if ((filter_mode & (NETWORK_FILTER | FILESYS_FILTER)) && fdmapptr)
{
fdmap = &fdmapptr[i];
}
bzero(&mapptr[total_threads], total_threads*sizeof(kd_threadmap));
map = &mapptr[total_threads];
- if (filter_mode && fdmapptr)
+ 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));
map->command[0] = '\0';
}
- if (filter_mode)
+ if ((filter_mode & (NETWORK_FILTER | FILESYS_FILTER)))
{
if ((fdmap = find_fd_thread_map(thread)))
{
if (filter_mode == DEFAULT_DO_NOT_FILTER)
return(1);
- if (filter_mode & CACHEHIT_FILTER)
+ 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)
{
- /* Do not print if cachehit filter is set */
- if (!strcmp (sc_name, "CACHE_HIT"))
- return(0);
+ if (!strcmp (sc_name, "execve"))
+ return(1);
+ return(0);
}
+ if ( !(filter_mode & (FILESYS_FILTER | NETWORK_FILTER)))
+ return(1);
+
if (ti == (struct th_info *)0)
{