+++ /dev/null
-#!/usr/bin/perl -w
-#
-# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
-#
-# @APPLE_LICENSE_HEADER_START@
-#
-# 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.
-#
-# 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.
-#
-# @APPLE_LICENSE_HEADER_END@
-#
-# arch_helper.pl is a perl script that automates the process of wrapping
-# a command (in the DSTROOT) to use the architecture selection feature of
-# the arch command. The first argument is the full path (relative to root)
-# of the command, and the second argument is the DSTROOT. arch_helper.pl
-# will move the command to a new directory in the DSTROOT, create a symbolic
-# link from to old command path to the arch command, and create a plist file
-# in /System/Library/archSettings to default to 32-bit over 64-bit
-# architectures.
-
-use strict;
-use File::Basename ();
-use File::Path ();
-use File::Spec;
-use IO::File;
-
-my $ArchSettings = '/System/Library/archSettings';
-my %Known = (
- '/usr/bin' => '/usr/archexec',
- '/usr/local/bin' => '/usr/local/archexec',
-);
-my $MyName = File::Basename::basename($0);
-
-sub usage {
- print STDERR <<USAGE;
-Usage: $MyName prog_path dstroot
- $MyName takes prog_path (full path relative to the dstroot)
- and dstroot, and moves the program to the corresponding archexec
- directory. It then creates a symbolic from prog_path to the arch
- command. Finally, a plist file is created in
- /System/Library/archSettings to default to using the 32-bit
- architectures.
-USAGE
- exit 1;
-}
-
-usage() unless scalar(@ARGV) == 2;
-my($vol, $dir, $file) = File::Spec->splitpath($ARGV[0]); # unix assumes $vol we be empty
-$dir = File::Spec->canonpath($dir);
-my $new = $Known{$dir};
-die "$MyName: Unsupported directory $dir\n" unless defined($new);
-my $dstroot = $ARGV[1];
-die "$MyName: $dstroot: Not a full path\n" unless File::Spec->file_name_is_absolute($dstroot);
-File::Path::mkpath(File::Spec->join($dstroot, $new), 1, 0755);
-File::Path::mkpath(File::Spec->join($dstroot, $ArchSettings), 1, 0755);
-my $execpath = File::Spec->canonpath(File::Spec->join($new, $file));
-my $do = File::Spec->join($dstroot, $dir, $file);
-my $dn = File::Spec->join($dstroot, $execpath);
-rename($do, $dn) or die "$MyName: Can't move $file to $dn: $!\n";
-print "renamed $do -> $dn\n";
-my $l = File::Spec->abs2rel('/usr/bin/arch', $dir);
-symlink($l, $do) or die "$MyName: Can't symlink $do -> $l: $!\n";
-print "symlink $do -> $l\n";
-my $plist = File::Spec->join($dstroot, $ArchSettings, $file . '.plist');
-my $p = IO::File->new($plist, 'w') or die "$MyName: $plist: $!\n";
-$p->print( <<PLIST );
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>ExecutablePath</key>
- <string>$execpath</string>
- <key>PreferredOrder</key>
- <array>
- <string>i386</string>
- <string>x86_64</string>
- <string>ppc</string>
- <string>ppc64</string>
- </array>
- <key>PropertyListVersion</key>
- <string>1.0</string>
-</dict>
-</plist>
-PLIST
-$p->close();
-print "created $plist\n";
deletes jobs;
.It Nm batch
executes commands when system load levels permit; in other words, when the load average
-drops below _LOADAVG_MX, or the value specified in the invocation of
+drops below _LOADAVG_MX (1.5), or the value specified in the invocation of
.Nm atrun .
.El
.Pp
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/usr.bin/at/at.c,v 1.29 2002/07/22 11:32:16 robert Exp $");
+__FBSDID("$FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/usr.bin/at/at.c,v 1.34 2011/11/06 20:30:21 ed Exp $");
#define _USE_BSD 1
/* File scope variables */
-const char *no_export[] =
-{
+static const char *no_export[] = {
"TERM", "TERMCAP", "DISPLAY", "_"
-} ;
+};
static int send_mail = 0;
+static char *atinput = NULL; /* where to get input from */
+static char atqueue = 0; /* which queue to examine for jobs (atq) */
/* External variables */
extern char **environ;
int fcreated;
char atfile[] = ATJOB_DIR "12345678901234";
-
-char *atinput = (char*)0; /* where to get input from */
-char atqueue = 0; /* which queue to examine for jobs (atq) */
char atverify = 0; /* verify time instead of queuing job */
char *namep;
int posixly_correct; /* Behave as per POSIX */
}
static long
-nextjob()
+nextjob(void)
{
long jobno;
FILE *fid;
- if ((fid = fopen(ATJOB_DIR ".SEQ", "r+")) != (FILE*)0) {
+ if ((fid = fopen(ATJOB_DIR ".SEQ", "r+")) != NULL) {
if (fscanf(fid, "%5lx", &jobno) == 1) {
rewind(fid);
jobno = (1+jobno) % 0xfffff; /* 2^20 jobs enough? */
fclose(fid);
return jobno;
}
- else if ((fid = fopen(ATJOB_DIR ".SEQ", "w")) != (FILE*)0) {
+ else if ((fid = fopen(ATJOB_DIR ".SEQ", "w")) != NULL) {
fprintf(fid, "%05lx\n", jobno = 1);
fclose(fid);
return 1;
while((ch = getc(fp)) != EOF) {
putchar(ch);
}
+ fclose(fp);
}
break;
}
}
}
+ closedir(spool);
} /* process_jobs */
#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/usr.bin/at/parsetime.c,v 1.25 2001/12/10 21:13:01 dwmalone Exp $");
+__FBSDID("$FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/usr.bin/at/parsetime.c,v 1.28 2011/11/06 17:32:29 ed Exp $");
/* System Headers */
/* parse translation table - table driven parsers can be your FRIEND!
*/
-struct {
+static const struct {
const char *name; /* token name */
int value; /* token id */
int plural; /* is this plural? */
} /* ugly case statement */
expect(EOF);
- /* adjust for daylight savings time
+ /* convert back to time_t
*/
runtime.tm_isdst = -1;
runtimer = mktime(&runtime);
- if (runtime.tm_isdst > 0) {
- runtimer -= 3600;
- runtimer = mktime(&runtime);
- }
if (runtimer < 0)
panic("garbled time");
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $FreeBSD: src/usr.bin/at/privs.h,v 1.8 2001/09/04 16:15:51 ru Exp $
+ * $FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/usr.bin/at/privs.h,v 1.10 2011/11/06 20:30:21 ed Exp $
*/
#ifndef _PRIVS_H
.Sh NAME
.Nm atrun
.Nd run jobs queued for later execution
-.Sh SYOPSIS
+.Sh SYNOPSIS
.Nm atrun
.Sh DESCRIPTION
The
#ifndef lint
static const char rcsid[] =
- "$FreeBSD: src/libexec/atrun/atrun.c,v 1.18 2004/07/11 17:37:32 stefanf Exp $";
+ "$FreeBSD: src/libexec/atrun/atrun.c,v 1.27 2009/12/25 10:30:54 ed Exp $";
#endif /* not lint */
/* System Headers */
#include <grp.h>
#include <pwd.h>
#include <signal.h>
+#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
-#include <utmpx.h>
#if 1
#include <paths.h>
#else
#include <getopt.h>
#endif
-
-#if (MAXLOGNAME-1) > _UTX_USERSIZE
-#define LOGNAMESIZE _UTX_USERSIZE
-#else
-#define LOGNAMESIZE (MAXLOGNAME-1)
+#ifdef LOGIN_CAP
+#include <login_cap.h>
+#endif
+#ifdef PAM
+#include <security/pam_appl.h>
+#include <security/openpam.h>
#endif
/* Local headers */
#define MAIN
#include "privs.h"
#include "pathnames.h"
+
/* Macros */
#ifndef ATJOB_DIR
/* File scope variables */
+static const char * const atrun = "atrun"; /* service name for syslog etc. */
static int debug = 0;
-void perr(const char *a);
+void perr(const char *fmt, ...);
+void perrx(const char *fmt, ...);
static void usage(void);
/* Local functions */
pid_t pid;
int fd_out, fd_in;
int queue;
- char mailbuf[LOGNAMESIZE + 1];
- char *fmt = NULL;
+ char mailbuf[MAXLOGNAME], fmt[64];
char *mailname = NULL;
FILE *stream;
int send_mail = 0;
int fflags;
long nuid;
long ngid;
-
+#ifdef PAM
+ pam_handle_t *pamh = NULL;
+ int pam_err;
+ struct pam_conv pamc = {
+ .conv = openpam_nullconv,
+ .appdata_ptr = NULL
+ };
+#endif
PRIV_START
pentry = getpwuid(uid);
if (pentry == NULL)
- {
- syslog(LOG_ERR,"Userid %lu not found - aborting job %s",
- (unsigned long) uid, filename);
- exit(EXIT_FAILURE);
- }
+ perrx("Userid %lu not found - aborting job %s",
+ (unsigned long) uid, filename);
+
+#ifdef PAM
PRIV_START
- stream=fopen(filename, "r");
+ pam_err = pam_start(atrun, pentry->pw_name, &pamc, &pamh);
+ if (pam_err != PAM_SUCCESS)
+ perrx("cannot start PAM: %s", pam_strerror(pamh, pam_err));
+
+ pam_err = pam_acct_mgmt(pamh, PAM_SILENT);
+ /* Expired password shouldn't prevent the job from running. */
+ if (pam_err != PAM_SUCCESS && pam_err != PAM_NEW_AUTHTOK_REQD)
+ perrx("Account %s (userid %lu) unavailable for job %s: %s",
+ pentry->pw_name, (unsigned long)uid,
+ filename, pam_strerror(pamh, pam_err));
+
+ pam_end(pamh, pam_err);
PRIV_END
+#endif /* PAM */
-#ifdef __FreeBSD__
- if (pentry->pw_expire && time(NULL) >= pentry->pw_expire)
- {
- syslog(LOG_ERR, "Userid %lu is expired - aborting job %s",
- (unsigned long) uid, filename);
- exit(EXIT_FAILURE);
- }
-#endif
+ PRIV_START
+
+ stream=fopen(filename, "r");
+
+ PRIV_END
if (stream == NULL)
perr("cannot open input file");
if (lstat(filename, &lbuf) == -1)
perr("error in fstat of input file");
- if (S_ISLNK(lbuf.st_mode)) {
- syslog(LOG_ERR,"Symbolic link encountered in job %s - aborting",
- filename);
- exit(EXIT_FAILURE);
- }
+ if (S_ISLNK(lbuf.st_mode))
+ perrx("Symbolic link encountered in job %s - aborting", filename);
+
if ((lbuf.st_dev != buf.st_dev) || (lbuf.st_ino != buf.st_ino) ||
(lbuf.st_uid != buf.st_uid) || (lbuf.st_gid != buf.st_gid) ||
- (lbuf.st_size!=buf.st_size)) {
- syslog(LOG_ERR,"Somebody changed files from under us for job %s - "
- "aborting",filename);
- exit(EXIT_FAILURE);
- }
- if (buf.st_nlink > 1) {
- syslog(LOG_ERR,"Someboy is trying to run a linked script for job %s",
+ (lbuf.st_size!=buf.st_size))
+ perrx("Somebody changed files from under us for job %s - aborting",
filename);
- exit(EXIT_FAILURE);
- }
+
+ if (buf.st_nlink > 1)
+ perrx("Somebody is trying to run a linked script for job %s", filename);
+
if ((fflags = fcntl(fd_in, F_GETFD)) <0)
perr("error in fcntl");
fcntl(fd_in, F_SETFD, fflags & ~FD_CLOEXEC);
- asprintf(&fmt, "%s%d%s",
- "#!/bin/sh\n# atrun uid=%ld gid=%ld\n# mail %",
- LOGNAMESIZE,
- "s %d");
- if (fscanf(stream, fmt, &nuid, &ngid, mailbuf, &send_mail) != 4) {
- syslog(LOG_ERR,"File %s is in wrong format - aborting", filename);
- exit(EXIT_FAILURE);
- }
- free(fmt);
- if (mailbuf[0] == '-') {
- syslog(LOG_ERR,"illegal mail name %s in %s",mailbuf,filename);
- exit(EXIT_FAILURE);
- }
+ snprintf(fmt, sizeof(fmt),
+ "#!/bin/sh\n# atrun uid=%%ld gid=%%ld\n# mail %%%ds %%d",
+ MAXLOGNAME - 1);
+
+ if (fscanf(stream, fmt, &nuid, &ngid, mailbuf, &send_mail) != 4)
+ perrx("File %s is in wrong format - aborting", filename);
+
+ if (mailbuf[0] == '-')
+ perrx("Illegal mail name %s in %s", mailbuf, filename);
+
mailname = mailbuf;
- if (nuid != uid) {
- syslog(LOG_ERR,"Job %s - userid %ld does not match file uid %lu",
+
+ if (nuid != uid)
+ perrx("Job %s - userid %ld does not match file uid %lu",
filename, nuid, (unsigned long)uid);
- exit(EXIT_FAILURE);
- }
- if (ngid != gid) {
- syslog(LOG_ERR,"Job %s - groupid %ld does not match file gid %lu",
+
+ if (ngid != gid)
+ perrx("Job %s - groupid %ld does not match file gid %lu",
filename, ngid, (unsigned long)gid);
- exit(EXIT_FAILURE);
- }
+
fclose(stream);
+
if (chdir(ATSPOOL_DIR) < 0)
- perr("cannot chdir to " ATSPOOL_DIR);
+ perr("cannot chdir to %s", ATSPOOL_DIR);
/* Create a file to hold the output of the job we are about to run.
* Write the mail header.
close(fd_in);
close(fd_out);
if (chdir(ATJOB_DIR) < 0)
- perr("cannot chdir to " ATJOB_DIR);
+ perr("cannot chdir to %s", ATJOB_DIR);
queue = *filename;
nice(tolower(queue) - 'a');
+#ifdef LOGIN_CAP
+ /*
+ * For simplicity and safety, set all aspects of the user context
+ * except for a selected subset: Don't set priority, which was
+ * set based on the queue file name according to the tradition.
+ * Don't bother to set environment, including path vars, either
+ * because it will be discarded anyway. Although the job file
+ * should set umask, preset it here just in case.
+ */
+ if (setusercontext(NULL, pentry, uid, LOGIN_SETALL &
+ ~(LOGIN_SETPRIORITY | LOGIN_SETPATH | LOGIN_SETENV)) != 0)
+ exit(EXIT_FAILURE); /* setusercontext() logged the error */
+#else /* LOGIN_CAP */
if (setgid(gid) < 0 || setegid(pentry->pw_gid) < 0)
perr("cannot change group");
if (initgroups(pentry->pw_name,pentry->pw_gid))
- perr("cannot delete saved userids");
+ perr("cannot init group access list");
if (setlogin(pentry->pw_name))
perr("cannot set login name");
if (setuid(uid) < 0 || seteuid(uid) < 0)
perr("cannot set user id");
+#endif /* LOGIN_CAP */
if (chdir(pentry->pw_dir))
chdir("/");
{
PRIV_START
+#ifdef LOGIN_CAP
+ /*
+ * This time set full context to run the mailer.
+ */
+ if (setusercontext(NULL, pentry, uid, LOGIN_SETALL) != 0)
+ exit(EXIT_FAILURE); /* setusercontext() logged the error */
+#else /* LOGIN_CAP */
if (setgid(gid) < 0 || setegid(pentry->pw_gid) < 0)
perr("cannot change group");
if (initgroups(pentry->pw_name,pentry->pw_gid))
- perr("cannot delete saved userids");
+ perr("cannot init group access list");
if (setlogin(pentry->pw_name))
perr("cannot set login name");
if (setuid(uid) < 0 || seteuid(uid) < 0)
perr("cannot set user id");
+#endif /* LOGIN_CAP */
if (chdir(pentry->pw_dir))
chdir("/");
/* Needed in gloadavg.c */
void
-perr(const char *a)
+perr(const char *fmt, ...)
{
+ const char * const fmtadd = ": %m";
+ char nfmt[strlen(fmt) + strlen(fmtadd) + 1];
+ va_list ap;
+
+ va_start(ap, fmt);
if (debug)
{
- warn("%s", a);
+ vwarn(fmt, ap);
}
else
- syslog(LOG_ERR, "%s: %m", a);
+ {
+ snprintf(nfmt, sizeof(nfmt), "%s%s", fmt, fmtadd);
+ vsyslog(LOG_ERR, nfmt, ap);
+ }
+ va_end(ap);
+
+ exit(EXIT_FAILURE);
+}
+
+void
+perrx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (debug)
+ vwarnx(fmt, ap);
+ else
+ vsyslog(LOG_ERR, fmt, ap);
+ va_end(ap);
exit(EXIT_FAILURE);
}
RELINQUISH_PRIVS_ROOT(DAEMON_UID, DAEMON_GID)
- openlog("atrun", LOG_PID, LOG_CRON);
+ openlog(atrun, LOG_PID, LOG_CRON);
opterr = 0;
while((c=getopt(argc, argv, "dl:"))!= -1)
}
if (chdir(ATJOB_DIR) != 0)
- perr("cannot change to " ATJOB_DIR);
+ perr("cannot change to %s", ATJOB_DIR);
/* Main loop. Open spool directory for reading and look over all the
* files in there. If the filename indicates that the job should be run
* atrun.
*/
if ((spool = opendir(".")) == NULL)
- perr("cannot read " ATJOB_DIR);
+ perr("cannot read %s", ATJOB_DIR);
now = time(NULL);
run_batch = 0;
while ((dirent = readdir(spool)) != NULL) {
if (stat(dirent->d_name,&buf) != 0)
- perr("cannot stat in " ATJOB_DIR);
+ perr("cannot stat in %s", ATJOB_DIR);
/* We don't want directories
*/
run_time = (time_t) ctm*60;
if ((S_IXUSR & buf.st_mode) && (run_time <=now)) {
- if (isupper(queue) && (strcmp(batch_name,dirent->d_name) > 0)) {
+ if ((isupper(queue) || queue == 'b') && (strcmp(batch_name,dirent->d_name) > 0)) {
run_batch = 1;
- strncpy(batch_name, dirent->d_name, sizeof(batch_name));
+ strlcpy(batch_name, dirent->d_name, sizeof(batch_name));
batch_uid = buf.st_uid;
batch_gid = buf.st_gid;
}
+++ /dev/null
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/*
- * Copyright (c) 1993 Christopher G. Demetriou
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Christopher G. Demetriou.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $Id: atrun.h,v 1.1.1.2 2000/01/11 02:10:06 wsanchez Exp $
- */
-
-#define ATRUN_MAXLOAD 1.5
};
void* idle_thread(void* param __attribute__((unused)));
+void* clean_thread(void *);
int file_check(const char* path, int mode, int uid, int gid, uid_t* owner, gid_t* group);
#define is_file(x) file_check((x), S_IFREG, -1, -1, NULL, NULL)
long delta = (now.tv_sec - idle_globals.lastmsg.tv_sec);
if (delta < idle_globals.timeout) {
// sleep for remainder of timeout
- sleep(idle_globals.timeout - delta);
+ sleep((int)(idle_globals.timeout - delta));
} else {
// timeout has elapsed, attempt to idle exit
__dirhelper_idle_exit(idle_globals.mp);
launch_data_t tmv;
tmv = launch_data_dict_lookup(config, LAUNCH_JOBKEY_TIMEOUT);
if (tmv) {
- idle_timeout = launch_data_get_integer(tmv);
+ idle_timeout = (long)launch_data_get_integer(tmv);
asl_log(NULL, NULL, ASL_LEVEL_DEBUG,
"idle timeout set: %ld seconds", idle_timeout);
}
#include <stdio.h>
#include <stdlib.h>
#include <vis.h>
+#include <sys/sysctl.h>
#include <libproc.h>
void
int
main(int argc, char **argv) {
- char msgbuf[16*1024], *visbuf;
+ char *msgbuf, *visbuf;
+ int msgbufsize;
+ size_t sysctlsize = sizeof(msgbufsize);
long data_size;
if (argc > 1)
usage();
-
- if ((data_size = proc_kmsgbuf(msgbuf, sizeof(msgbuf))) == 0){
+
+ if (sysctlbyname("kern.msgbuf", &msgbufsize, &sysctlsize, NULL, 0)) {
+ perror("Unable to size kernel buffer");
+ }
+
+ msgbuf = malloc(msgbufsize);
+ if (msgbuf == NULL) {
+ perror("Unable to allocate a message buffer");
+ }
+
+ if ((data_size = proc_kmsgbuf(msgbuf, msgbufsize)) == 0){
perror("Unable to obtain kernel buffer");
usage();
}
strvis(visbuf, msgbuf, 0);
printf("%s", visbuf);
free(visbuf);
+ free(msgbuf);
exit(0);
}
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
- <key>Label</key>
- <string>com.apple.dynamic_pager</string>
- <key>ProgramArguments</key>
- <array>
- <string>/sbin/dynamic_pager</string>
- <string>-F</string>
- <string>/private/var/vm/swapfile</string>
- </array>
- <key>OnDemand</key>
- <false/>
- <key>HopefullyExitsLast</key>
- <true/>
- <key>EnableTransactions</key>
- <true/>
+ <key>EnableTransactions</key>
+ <true/>
+ <key>HopefullyExitsLast</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.dynamic_pager</string>
+ <key>OnDemand</key>
+ <false/>
+ <key>POSIXSpawnType</key>
+ <string>Interactive</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/sbin/dynamic_pager</string>
+ <string>-F</string>
+ <string>/private/var/vm/swapfile</string>
+ </array>
</dict>
</plist>
notifications = HI_WAT_ALERT;
sprintf(subfile, "%s%d", fileroot, file_count);
+#if TARGET_OS_EMBEDDED
+ fd = open_dprotected_np(subfile, O_CREAT|O_EXCL|O_RDWR, PROTECTION_CLASS_F, 0, (mode_t)(S_IRUSR|S_IWUSR));
+#else
fd = open(subfile, O_CREAT|O_EXCL|O_RDWR,(mode_t)(S_IRUSR|S_IWUSR));
+#endif
if (fd == -1) {
/* force error recovery below */
error = -1;
}
-#if TARGET_OS_EMBEDDED
- else {
- error = fcntl(fd, F_SETPROTECTIONCLASS, PROTECTION_CLASS_F);
- }
-#endif
if(!error) {
error = fcntl(fd, F_SETSIZE, &filesize);
file_count = 0;
sprintf(subfile, "%s%d", fileroot, file_count);
+#if TARGET_OS_EMBEDDED
+ fd = open_dprotected_np(subfile, O_CREAT|O_EXCL|O_RDWR, PROTECTION_CLASS_F, 0, ((mode_t)(S_IRUSR|S_IWUSR)));
+#else
fd = open(subfile, O_CREAT|O_EXCL|O_RDWR, ((mode_t)(S_IRUSR|S_IWUSR)));
+#endif
if (fd == -1) {
fprintf(stderr, "dynamic_pager: cannot create paging file %s!\n",
subfile);
exit(EXIT_FAILURE);
}
-#if TARGET_OS_EMBEDDED
- error = fcntl(fd, F_SETPROTECTIONCLASS, PROTECTION_CLASS_F);
- if (error == -1) {
- fprintf(stderr, "dynamic_pager: cannot set file protection class!\n");
- unlink(subfile);
- close(fd);
- exit(EXIT_FAILURE);
- }
-#endif
error = fcntl(fd, F_SETSIZE, &filesize);
if(error) {
.Nd report system calls and page faults related to filesystem activity in
real-time
.Sh SYNOPSIS
-.Nm fs_usage [-e] [-w] [-f mode [-f mode] ...] [ pid|cmd [pid|cmd] ...]
+.Nm fs_usage [-e] [-w] [-f mode] [-b] [-t seconds] [-R rawfile [-S start_time] [-E end_time]] [pid | cmd [pid | cmd] ...]
.Sh DESCRIPTION
The
.Nm fs_usage
pertaining to filesystem activity.
It requires root privileges due to the kernel tracing facility it uses to
operate.
-By default the activity monitored includes all system processes except the
+By default, the activity monitored includes all system processes except the
running
.Nm fs_usage
process, Terminal, telnetd, sshd, rlogind, tcsh, csh and sh.
.Fl e
option generates output that excludes sampling
of the running fs_usage tool.
-If a list of process ids or commands is also given,
+If a list of process IDs or commands is also given,
then those processes are also excluded from the sampled output.
.\" ==========
+.It Fl w
+Specifying the
+.Fl w
+option forces a wider, more detailed output,
+regardless of the window size.
+.\" ==========
.It Fl f
Specifying the
.Fl f
.Pa mode
provided.
Multiple filtering options can be specified.
-By default no output filtering occurs.
+By default, no output filtering occurs.
The supported modes are:
.Pp
.Pa network
-Only network related events are displayed.
+Network-related events are displayed.
.Pp
.Pa filesys
-Only file system related events are displayed.
+Filesystem-related events are displayed.
+.Pp
+.Pa pathname
+Pathname-related events are displayed.
.Pp
.Pa exec
-Only exec and spawn events are displayed.
+Exec and spawn events are displayed.
.Pp
-.Pa pathname
-Only pathname related events are displayed.
+.Pa diskio
+Disk I/O events are displayed.
.Pp
.Pa cachehit
-In addition, display CACHE_HIT output.
+In addition, show cache hits.
.\" ==========
-.It Fl w
+.It Fl b
Specifying the
-.Fl w
-option forces a wider, more detailed output,
-regardless of the window size.
+.Fl b
+option annotates disk I/O events with BootCache info (if available).
+.\" ==========
+.It Fl t Ar seconds
+Specifies a run timeout in seconds.
+.Nm fs_usage
+will run for no longer than the timeout specified.
.\" ==========
.It Fl R Ar raw_file
Specifies a raw trace file to process.
skipped.
.\" ==========
.It pid | cmd
-The sampled data can be limited to a list of process ids or commands.
+The sampled data can be limited to a list of process IDs or commands.
When a command name is given, all processes with that name will be sampled.
Using the
.Fl e
option has the opposite effect,
excluding sampled data relating to the given list
-of process ids or commands.
+of process IDs or commands.
.El
.Pp
If you set the DYLD_IMAGE_SUFFIX environment variable to
#include <sys/mman.h>
#include <sys/sysctl.h>
#include <sys/disk.h>
+#include <sys/file.h>
#ifndef KERNEL_PRIVATE
#define KERNEL_PRIVATE
#define MAX_WIDE_MODE_COLS (PATHLENGTH + 80)
#define MAXWIDTH MAX_WIDE_MODE_COLS + 64
+#define MAX_PATHNAMES 3
+#define MAX_SCALL_PATHNAMES 2
typedef struct th_info *th_info_t;
+struct lookup {
+ uintptr_t pathname[NUMPARMS + 1]; /* add room for null terminator */
+};
+
struct th_info {
th_info_t next;
uintptr_t thread;
uintptr_t child_thread;
int in_filemgr;
+ int in_hfs_update;
int pid;
int type;
int arg1;
int arg8;
int waited;
double stime;
+ uint64_t vnodeid;
+ char *nameptr;
uintptr_t *pathptr;
- uintptr_t pathname[NUMPARMS + 1]; /* add room for null terminator */
- uintptr_t pathname2[NUMPARMS + 1]; /* add room for null terminator */
+ int pn_scall_index;
+ int pn_work_index;
+ struct lookup lookups[MAX_PATHNAMES];
};
};
+typedef struct vnode_info * vnode_info_t;
+
+struct vnode_info {
+ vnode_info_t vn_next;
+ uint64_t vn_id;
+ uintptr_t vn_pathname[NUMPARMS + 1];
+};
+
+typedef struct meta_info * meta_info_t;
+
+struct meta_info {
+ meta_info_t m_next;
+ uint64_t m_blkno;
+ char *m_nameptr;
+};
+
#define HASH_SIZE 1024
-#define HASH_MASK 1023
+#define HASH_MASK (HASH_SIZE - 1)
th_info_t th_info_hash[HASH_SIZE];
th_info_t th_info_freelist;
threadmap_t threadmap_freelist;
+#define VN_HASH_SHIFT 3
+#define VN_HASH_SIZE 16384
+#define VN_HASH_MASK (VN_HASH_SIZE - 1)
+
+vnode_info_t vn_info_hash[VN_HASH_SIZE];
+meta_info_t m_info_hash[VN_HASH_SIZE];
+
+
int filemgr_in_progress = 0;
int need_new_map = 1;
int bias_secs = 0;
*/
#define FILESYS_FILTER 0x01
#define NETWORK_FILTER 0x02
-#define CACHEHIT_FILTER 0x04
#define EXEC_FILTER 0x08
#define PATHNAME_FILTER 0x10
+#define DISKIO_FILTER 0x20
#define DEFAULT_DO_NOT_FILTER 0x00
-int filter_mode = CACHEHIT_FILTER;
+int filter_mode = DEFAULT_DO_NOT_FILTER;
+
+boolean_t show_cachehits = FALSE;
#define NFS_DEV -1
#define CS_DEV -2
int blkno;
int iosize;
int io_errno;
+ int is_meta;
+ uint64_t vnodeid;
uintptr_t issuing_thread;
uintptr_t completion_thread;
char issuing_command[MAXCOMLEN];
double issued_time;
double completed_time;
+ uint32_t bc_info;
};
struct diskrec *disk_list = NULL;
struct diskio *insert_diskio();
+struct diskio *find_diskio(int);
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 format_print(struct th_info *, char *, uintptr_t, int, uintptr_t, uintptr_t, uintptr_t, uintptr_t, 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 exit_event(char *, uintptr_t, int, uintptr_t, uintptr_t, uintptr_t, uintptr_t, int, double);
void extend_syscall(uintptr_t, int, kd_buf *);
char *generate_cs_disk_name(int, char *s);
void delete_map_entry(uintptr_t);
threadmap_t find_map_entry(uintptr_t);
+char *add_vnode_name(uint64_t, char *);
+char *find_vnode_name(uint64_t);
+char *find_meta_name(uint64_t);
+void add_meta_name(uint64_t, char *);
+
void getdivisor();
void argtopid();
void set_remove();
#define MACH_stkhandoff 0x01400008
#define MACH_idle 0x01400024
#define VFS_LOOKUP 0x03010090
+#define VFS_ALIAS_VP 0x03010094
#define BSC_thread_terminate 0x040c05a4
+#define HFS_update 0x3018000
+#define HFS_modify_block_end 0x3018004
+
#define Throttled 0x3010184
#define SPEC_ioctl 0x3060000
#define SPEC_unmap_info 0x3060004
#define proc_exit 0x4010004
+#define BC_IO_HIT 0x03070010
+#define BC_IO_HIT_STALLED 0x03070020
+#define BC_IO_MISS 0x03070040
+#define BC_IO_MISS_CUT_THROUGH 0x03070080
+#define BC_PLAYBACK_IO 0x03070100
+#define BC_STR(s) ( \
+ (s == BC_IO_HIT) ? "HIT" : \
+ (s == BC_IO_HIT_STALLED) ? "STALL" : \
+ (s == BC_IO_MISS) ? "MISS" : \
+ (s == BC_IO_MISS_CUT_THROUGH) ? "CUT" : \
+ (s == BC_PLAYBACK_IO) ? "PLBK" : \
+ (s == 0x0) ? "NONE" : "UNKN" )
+
#ifndef DKIO_NOCACHE
#define DKIO_NOCACHE 0x80
#endif
#define P_DISKIO_THROTTLE (DKIO_THROTTLE << 2)
#define P_DISKIO_PASSIVE (DKIO_PASSIVE << 2)
#define P_DISKIO_NOCACHE (DKIO_NOCACHE << 2)
+#define P_DISKIO_TIER_MASK (DKIO_TIER_MASK << 2)
+#define P_DISKIO_TIER_SHIFT (DKIO_TIER_SHIFT + 2)
#define P_DISKIO (FSDBG_CODE(DBG_DKRW, 0))
#define P_DISKIO_DONE (P_DISKIO | (DKIO_DONE << 2))
#define BSC_listen 0x040C01A8
#define BSC_sendto 0x040C0214
#define BSC_socketpair 0x040C021C
+#define BSC_recvmsg_nocancel 0x040c0644
+#define BSC_sendmsg_nocancel 0x040c0648
+#define BSC_recvfrom_nocancel 0x040c064c
+#define BSC_accept_nocancel 0x040c0650
+#define BSC_connect_nocancel 0x040c0664
+#define BSC_sendto_nocancel 0x040c0674
#define BSC_exit 0x040C0004
#define BSC_read 0x040C000C
#define BSC_fchown 0x040C01EC
#define BSC_fchmod 0x040C01F0
#define BSC_rename 0x040C0200
-#define BSC_mkfifo 0x040c0210
+#define BSC_flock 0x040C020C
+#define BSC_mkfifo 0x040C0210
#define BSC_mkdir 0x040C0220
#define BSC_rmdir 0x040C0224
#define BSC_utimes 0x040C0228
#define BSC_fstatfs 0x040C0278
#define BSC_unmount 0x040C027C
#define BSC_mount 0x040C029C
+#define BSC_fdatasync 0x040C02EC
#define BSC_stat 0x040C02F0
#define BSC_fstat 0x040C02F4
#define BSC_lstat 0x040C02F8
#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_open_dprotected_np 0x040C0360
#define BSC_getattrlist 0x040C0370
#define BSC_setattrlist 0x040C0374
#define BSC_getdirentriesattr 0x040C0378
#define BSC_searchfs 0x040C0384
#define BSC_delete 0x040C0388
#define BSC_copyfile 0x040C038C
+#define BSC_fgetattrlist 0x040C0390
+#define BSC_fsetattrlist 0x040C0394
#define BSC_getxattr 0x040C03A8
#define BSC_fgetxattr 0x040C03AC
#define BSC_setxattr 0x040C03B0
#define BSC_flistxattr 0x040C03C4
#define BSC_fsctl 0x040C03C8
#define BSC_posix_spawn 0x040C03D0
+#define BSC_ffsctl 0x040C03D4
#define BSC_open_extended 0x040C0454
+#define BSC_umask_extended 0x040C0458
#define BSC_stat_extended 0x040C045C
#define BSC_lstat_extended 0x040C0460
#define BSC_fstat_extended 0x040C0464
#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_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_guarded_open_np 0x040c06e4
+#define BSC_guarded_close_np 0x040c06e8
+
+#define BSC_fsgetpath 0x040c06ac
#define BSC_msync_extended 0x040e0104
#define BSC_pread_extended 0x040e0264
#define FMT_SYNC_DISK_CS 38
#define FMT_IOCTL_UNMAP 39
#define FMT_UNMAP_INFO 40
+#define FMT_HFS_update 41
+#define FMT_FLOCK 42
#define MAX_BSD_SYSCALL 512
BSC_pwrite_nocancel,
BSC_statfs,
BSC_fstatfs,
+ BSC_fdatasync,
BSC_stat,
BSC_fstat,
BSC_lstat,
BSC_lseek,
BSC_truncate,
BSC_ftruncate,
+ BSC_flock,
BSC_undelete,
- BSC_statv,
- BSC_lstatv,
- BSC_fstatv,
- BSC_mkcomplex,
+ BSC_open_dprotected_np,
BSC_getattrlist,
BSC_setattrlist,
+ BSC_fgetattrlist,
+ BSC_fsetattrlist,
BSC_getdirentriesattr,
BSC_exchangedata,
BSC_checkuseraccess,
BSC_listxattr,
BSC_flistxattr,
BSC_fsctl,
+ BSC_ffsctl,
BSC_open_extended,
+ BSC_umask_extended,
BSC_stat_extended,
BSC_lstat_extended,
BSC_fstat_extended,
BSC_access_extended,
BSC_mkfifo_extended,
BSC_mkdir_extended,
- BSC_load_shared_file,
BSC_aio_fsync,
BSC_aio_return,
BSC_aio_suspend,
BSC_pthread_fchdir,
BSC_getfsstat,
BSC_getfsstat64,
+ BSC_guarded_open_np,
+ BSC_guarded_close_np,
+ BSC_fsgetpath,
0
};
int trace_enabled = 0;
int set_remove_flag = 1;
+int BC_flag = 0;
+
char *RAW_file = (char *)0;
int RAW_flag = 0;
int RAW_fd = 0;
void set_numbufs();
+void set_filter();
void set_init();
void set_enable();
void sample_sc();
set_pidexclude(pids[i], 0);
}
set_remove();
+
exit(0);
}
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, "Usage: %s [-e] [-w] [-f mode] [-b] [-t seconds] [-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, " -f output is based on the mode provided\n");
+ fprintf(stderr, " mode = \"network\" Show network-related events\n");
+ fprintf(stderr, " mode = \"filesys\" Show filesystem-related events\n");
+ fprintf(stderr, " mode = \"pathname\" Show only pathname-related events\n");
+ fprintf(stderr, " mode = \"exec\" Show only exec and spawn events\n");
+ fprintf(stderr, " mode = \"diskio\" Show only disk I/O events\n");
+ fprintf(stderr, " mode = \"cachehit\" In addition, show cache hits\n");
+ fprintf(stderr, " -b annotate disk I/O events with BootCache info (if available)\n");
+ fprintf(stderr, " -t specifies timeout in seconds (for use in automated tools)\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");
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_guarded_open_np:
+ bsd_syscalls[code].sc_name = "guarded_open_np";
+ bsd_syscalls[code].sc_format = FMT_OPEN;
+ break;
+
+ case BSC_open_dprotected_np:
+ bsd_syscalls[code].sc_name = "open_dprotected";
+ 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;
bsd_syscalls[code].sc_format = FMT_FD;
break;
+ case BSC_guarded_close_np:
+ bsd_syscalls[code].sc_name = "guarded_close_np";
+ 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_name = "lstat_extended64";
break;
- case BSC_lstatv:
- bsd_syscalls[code].sc_name = "lstatv";
- break;
-
case BSC_link:
bsd_syscalls[code].sc_name = "link";
break;
bsd_syscalls[code].sc_format = FMT_UMASK;
break;
+ case BSC_umask_extended:
+ bsd_syscalls[code].sc_name = "umask_extended";
+ bsd_syscalls[code].sc_format = FMT_UMASK;
+ break;
+
case BSC_chmod:
bsd_syscalls[code].sc_name = "chmod";
bsd_syscalls[code].sc_format = FMT_CHMOD;
bsd_syscalls[code].sc_name = "fsctl";
break;
+ case BSC_ffsctl:
+ bsd_syscalls[code].sc_name = "ffsctl";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
case BSC_chflags:
bsd_syscalls[code].sc_name = "chflags";
bsd_syscalls[code].sc_format = FMT_CHFLAGS;
bsd_syscalls[code].sc_format = FMT_FD;
break;
+ case BSC_fdatasync:
+ bsd_syscalls[code].sc_name = "fdatasync";
+ 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_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";
+ case BSC_flock:
+ bsd_syscalls[code].sc_name = "flock";
+ bsd_syscalls[code].sc_format = FMT_FLOCK;
break;
case BSC_getattrlist:
bsd_syscalls[code].sc_name = "setattrlist";
break;
+ case BSC_fgetattrlist:
+ bsd_syscalls[code].sc_name = "fgetattrlist";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_fsetattrlist:
+ bsd_syscalls[code].sc_name = "fsetattrlist";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
case BSC_getdirentriesattr:
bsd_syscalls[code].sc_name = "getdirentriesattr";
bsd_syscalls[code].sc_format = FMT_FD;
bsd_syscalls[code].sc_name = "ioctl";
bsd_syscalls[code].sc_format = FMT_IOCTL;
break;
+
+ case BSC_fsgetpath:
+ bsd_syscalls[code].sc_name = "fsgetpath";
+ break;
}
}
int i;
char ch;
+ time_t stop_at_time = 0;
+
if (0 != reexec_to_match_kernel()) {
fprintf(stderr, "Could not re-execute: %d\n", errno);
exit(1);
myname++;
}
- while ((ch = getopt(argc, argv, "ewf:R:S:E:")) != EOF) {
+ while ((ch = getopt(argc, argv, "bewf:R:S:E:t:")) != EOF) {
switch(ch) {
else if (!strcmp(optarg, "filesys"))
filter_mode |= FILESYS_FILTER;
else if (!strcmp(optarg, "cachehit"))
- filter_mode &= ~CACHEHIT_FILTER; /* turns on CACHE_HIT */
+ show_cachehits = TRUE;
else if (!strcmp(optarg, "exec"))
filter_mode |= EXEC_FILTER;
else if (!strcmp(optarg, "pathname"))
filter_mode |= PATHNAME_FILTER;
+ else if (!strcmp(optarg, "diskio"))
+ filter_mode |= DISKIO_FILTER;
break;
+
+ case 'b':
+ BC_flag = 1;
+ break;
+
+ case 't':
+ stop_at_time = time(NULL) + strtoul(optarg, NULL, 10);
+ break;
case 'R':
RAW_flag = 1;
set_remove();
exit_usage(myname);
}
+
+ set_filter();
+
set_enable(1);
init_arguments_buffer();
/*
* main loop
*/
- while (1) {
+ while (stop_at_time == 0 || last_time < stop_at_time) {
if (!RAW_flag)
usleep(1000 * usleep_ms);
quit("trace facility failure, KERN_KDSETUP\n");
}
+#define ENCODE_CSC_LOW(class, subclass) \
+ ( (uint16_t) ( ((class) & 0xff) << 8 ) | ((subclass) & 0xff) )
+
+void
+set_filter(void)
+{
+ uint8_t type_filter_bitmap[KDBG_TYPEFILTER_BITMAP_SIZE];
+ bzero(type_filter_bitmap, sizeof(type_filter_bitmap));
+
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(DBG_TRACE,DBG_TRACE_DATA));
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(DBG_TRACE,DBG_TRACE_STRING));
+
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(DBG_MACH,DBG_MACH_EXCP_SC)); //0x010c
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(DBG_MACH,DBG_MACH_VM)); //0x0130
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(DBG_MACH,DBG_MACH_SCHED)); //0x0140
+
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(DBG_FSYSTEM,DBG_FSRW)); //0x0301
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(DBG_FSYSTEM,DBG_DKRW)); //0x0302
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(DBG_FSYSTEM,DBG_IOCTL)); //0x0306
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(DBG_FSYSTEM,DBG_BOOTCACHE)); //0x0307
+
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(DBG_BSD,DBG_BSD_EXCP_SC)); //0x040c
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(DBG_BSD,DBG_BSD_PROC)); //0x0401
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(DBG_BSD,DBG_BSD_SC_EXTENDED_INFO)); //0x040e
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(DBG_BSD,DBG_BSD_SC_EXTENDED_INFO2)); //0x040f
+
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(DBG_CORESTORAGE,DBG_CS_IO)); //0x0a00
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(DBG_CORESTORAGE, 1)); //0x0a01 for P_SCCS_SYNC_DIS
+
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(FILEMGR_CLASS, 0)); //Carbon File Manager
+ setbit(type_filter_bitmap, ENCODE_CSC_LOW(FILEMGR_CLASS, 1)); //Carbon File Manager
+
+ errno = 0;
+ int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDSET_TYPEFILTER };
+ size_t needed = KDBG_TYPEFILTER_BITMAP_SIZE;
+ if(sysctl(mib, 3, type_filter_bitmap, &needed, NULL, 0)) {
+ quit("trace facility failure, KERN_KDSET_TYPEFILTER\n");
+ }
+}
+
void
set_pidcheck(int pid, int on_off)
{
quit("trace facility failure, KERN_KDSETUP\n");
}
+
void
sample_sc()
{
}
if ((type & P_DISKIO_MASK) == P_DISKIO_DONE) {
if ((dio = complete_diskio(kd[i].arg1, kd[i].arg4, kd[i].arg3, thread, (double)now))) {
+ dio->vnodeid = kd[i].arg2;
print_diskio(dio);
free_diskio(dio);
}
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);
+ print_diskio(dio);
+ free_diskio(dio);
}
}
continue;
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);
+ print_diskio(dio);
+ free_diskio(dio);
}
}
continue;
case TRACE_STRING_EXEC:
if ((ti = find_event(thread, BSC_execve))) {
- if (ti->pathname[0])
+ if (ti->lookups[0].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])
+ if (ti->lookups[0].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)
case MACH_stkhandoff:
mark_thread_waited(thread);
continue;
+
+ case BC_IO_HIT:
+ case BC_IO_HIT_STALLED:
+ case BC_IO_MISS:
+ case BC_IO_MISS_CUT_THROUGH:
+ case BC_PLAYBACK_IO:
+ if ((dio = find_diskio(kd[i].arg1)) != NULL)
+ dio->bc_info = type;
+ continue;
+
+ case HFS_modify_block_end:
+ if ((ti = find_event(thread, 0))) {
+ if (ti->nameptr)
+ add_meta_name(kd[i].arg2, ti->nameptr);
+ }
+ continue;
+
+ case VFS_ALIAS_VP:
+ add_vnode_name(kd[i].arg2, find_vnode_name(kd[i].arg1));
+ 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;
+
+ if (ti->in_hfs_update) {
+ ti->pn_work_index = (MAX_PATHNAMES - 1);
+ } else {
+ if (ti->pn_scall_index < MAX_SCALL_PATHNAMES)
+ ti->pn_work_index = ti->pn_scall_index;
+ else
+ continue;
+ }
+ sargptr = &ti->lookups[ti->pn_work_index].pathname[0];
+
+ ti->vnodeid = kd[i].arg1;
+
*sargptr++ = kd[i].arg2;
*sargptr++ = kd[i].arg3;
*sargptr++ = kd[i].arg4;
} else {
sargptr = ti->pathptr;
- /*
+ /*
* We don't want to overrun our pathname buffer if the
* kernel sends us more VFS_LOOKUP entries than we can
* handle and we only handle 2 pathname lookups for
*/
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;
+
+ if ((uintptr_t)sargptr < (uintptr_t)&ti->lookups[ti->pn_work_index].pathname[NUMPARMS]) {
+
+ *sargptr++ = kd[i].arg1;
+ *sargptr++ = kd[i].arg2;
+ *sargptr++ = kd[i].arg3;
+ *sargptr++ = kd[i].arg4;
+ /*
+ * NULL terminate the 'string'
+ */
+ *sargptr = 0;
}
- *sargptr++ = kd[i].arg1;
- *sargptr++ = kd[i].arg2;
- *sargptr++ = kd[i].arg3;
- *sargptr++ = kd[i].arg4;
- /*
- * NULL terminate the 'string'
- */
- *sargptr = 0;
+ }
+ if (debugid & DBG_FUNC_END) {
- if (debugid & DBG_FUNC_END) {
- if (ti->pathname2[0])
- ti->pathptr = 0;
+ ti->nameptr = add_vnode_name(ti->vnodeid, &ti->lookups[ti->pn_work_index].pathname[0]);
+
+ if (ti->pn_work_index == ti->pn_scall_index) {
+
+ ti->pn_scall_index++;
+
+ if (ti->pn_scall_index < MAX_SCALL_PATHNAMES)
+ ti->pathptr = &ti->lookups[ti->pn_scall_index].pathname[0];
else
- ti->pathptr = ti->pathname2;
- } else
- ti->pathptr = sargptr;
- }
+ ti->pathptr = 0;
+ }
+ } else
+ ti->pathptr = sargptr;
+
continue;
}
continue;
if ((p = filemgr_calls[index].fm_name) == NULL)
- continue;
+ continue;
} else
p = NULL;
exit_event(" THROTTLED", thread, type, 0, 0, 0, 0, FMT_DEFAULT, (double)now);
continue;
+ case HFS_update:
+ exit_event(" HFS_update", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, FMT_HFS_update, (double)now);
+ continue;
+
case SPEC_unmap_info:
- if (check_filter_mode(NULL, SPEC_unmap_info, 0, 0, "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;
ti->arg3 = kd->arg3;
ti->arg4 = kd->arg4;
+ switch (type) {
+
+ case HFS_update:
+ ti->in_hfs_update = 1;
+ break;
+ }
+
if ((type & CLASS_MASK) == FILEMGR_BASE &&
(!RAW_flag || (now >= start_time && now <= end_time))) {
{
int index;
- if (type == MACH_pageout || type == MACH_vmfault || type == MSC_map_fd || type == SPEC_ioctl || type == Throttled || type == P_CS_SYNC_DISK) {
+ switch (type) {
+
+ case P_CS_SYNC_DISK:
+ case MACH_pageout:
+ case MACH_vmfault:
+ case MSC_map_fd:
+ case SPEC_ioctl:
+ case Throttled:
+ case HFS_update:
enter_event_now(thread, type, kd, name, now);
return;
+
}
if ((type & CSC_MASK) == BSC_BASE) {
if (filemgr_calls[index].fm_name)
enter_event_now(thread, type, kd, name, now);
+ return;
}
}
void
-exit_event(char *sc_name, uintptr_t thread, int type, int arg1, int arg2, int arg3, int arg4,
+exit_event(char *sc_name, uintptr_t thread, int type, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4,
int format, double now)
{
th_info_t ti;
if ((ti = find_event(thread, type)) == (struct th_info *)0)
return;
+ ti->nameptr = 0;
+
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);
+ format_print(ti, sc_name, thread, type, arg1, arg2, arg3, arg4, format, now, ti->stime, ti->waited, (char *)&ti->lookups[0].pathname[0], NULL);
+
+ switch (type) {
+ case HFS_update:
+ ti->in_hfs_update = 0;
+ break;
+ }
if ((type & CLASS_MASK) == FILEMGR_BASE) {
ti->in_filemgr = 0;
void
-format_print(struct th_info *ti, char *sc_name, uintptr_t thread, int type, int arg1, int arg2, int arg3, int arg4,
+format_print(struct th_info *ti, char *sc_name, uintptr_t thread, int type, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4,
int format, double now, double stime, int waited, char *pathname, struct diskio *dio)
{
int secs;
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;
+ command_name = "";
+
if (RAW_flag) {
l_usecs = (long long)((now - bias_now) / divisor);
clen += printf(" B=0x%-8x", arg2);
break;
+ case FMT_HFS_update:
+ {
+ char sbuf[7];
+ int sflag = (int)arg2;
+
+ memset(sbuf, '_', 6);
+ sbuf[6] = '\0';
+
+
+ if (sflag & 0x10)
+ sbuf[0] = 'F';
+ if (sflag & 0x08)
+ sbuf[1] = 'M';
+ if (sflag & 0x20)
+ sbuf[2] = 'D';
+ if (sflag & 0x04)
+ sbuf[3] = 'c';
+ if (sflag & 0x01)
+ sbuf[4] = 'a';
+ if (sflag & 0x02)
+ sbuf[5] = 'm';
+
+ clen += printf(" (%s) ", sbuf);
+
+ pathname = find_vnode_name(arg1);
+ nopadding = 1;
+
+ break;
+ }
+
case FMT_DISKIO:
/*
* physical disk I/O
*/
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));
+ else {
+ if (BC_flag)
+ clen += printf(" D=0x%8.8x B=0x%-6x BC:%s /dev/%s ", dio->blkno, dio->iosize, BC_STR(dio->bc_info), find_disk_name(dio->dev));
+ else
+ clen += printf(" D=0x%8.8x B=0x%-6x /dev/%s ", dio->blkno, dio->iosize, find_disk_name(dio->dev));
+
+ if (dio->is_meta)
+ pathname = find_meta_name(dio->blkno);
+ else
+ pathname = find_vnode_name(dio->vnodeid);
+ nopadding = 1;
+ }
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]));
+ clen += printf(" D=0x%8.8x B=0x%-6x /dev/%s", dio->blkno, dio->iosize, generate_cs_disk_name(dio->dev, &cs_diskname[0]));
break;
case FMT_SYNC_DISK_CS:
/*
* physical disk sync cache
*/
- clen += printf(" /dev/%s", generate_cs_disk_name(arg1, &cs_diskname[0]));
+ clen += printf(" /dev/%s", generate_cs_disk_name(arg1, &cs_diskname[0]));
break;
break;
}
+ case FMT_FLOCK:
+ {
+ /*
+ * flock
+ */
+ int mlen = 0;
+
+ buf[0] = '\0';
+
+ if (ti->arg2 & LOCK_SH)
+ mlen += sprintf(&buf[mlen], "LOCK_SH | ");
+ if (ti->arg2 & LOCK_EX)
+ mlen += sprintf(&buf[mlen], "LOCK_EX | ");
+ if (ti->arg2 & LOCK_NB)
+ mlen += sprintf(&buf[mlen], "LOCK_NB | ");
+ if (ti->arg2 & LOCK_UN)
+ mlen += sprintf(&buf[mlen], "LOCK_UN | ");
+
+ if (ti->arg2 & ~(LOCK_SH | LOCK_EX | LOCK_NB | LOCK_UN))
+ mlen += sprintf(&buf[mlen], "UNKNOWN | ");
+
+ if (mlen)
+ buf[mlen - 3] = '\0';
+
+ if (arg1)
+ clen += printf(" F=%-3d[%3d] <%s>", ti->arg1, arg1, buf);
+ else
+ clen += printf(" F=%-3d <%s>", ti->arg1, buf);
+
+ break;
+ }
+
case FMT_FCNTL:
{
/*
/*
* ioctl
*/
- clen += printf(" <DKIOCSYNCHRONIZECACHE> /dev/%s", find_disk_name(arg1));
+ clen += printf(" <DKIOCSYNCHRONIZECACHE> /dev/%s", find_disk_name(arg1));
break;
}
/*
* ioctl
*/
- clen += printf(" <DKIOCUNMAP> /dev/%s", find_disk_name(arg1));
+ 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));
+ clen += printf(" D=0x%8.8x B=0x%-6x /dev/%s", arg2, arg3, find_disk_name(arg1));
break;
}
else if (*pathname != '\0') {
len = sprintf(&buf[0], " %s ", pathname);
- if (format == FMT_MOUNT && ti->pathname2[0]) {
+ if (format == FMT_MOUNT && ti->lookups[1].pathname[0]) {
int len2;
memset(&buf[len], ' ', 2);
- len2 = sprintf(&buf[len+2], " %s ", (char *)ti->pathname2);
+ len2 = sprintf(&buf[len+2], " %s ", (char *)&ti->lookups[1].pathname[0]);
len = len + 2 + len2;
}
} else
}
+void
+add_meta_name(uint64_t blockno, char *pathname) {
+ meta_info_t mi;
+ int hashid;
+
+ hashid = blockno & VN_HASH_MASK;
+
+ for (mi = m_info_hash[hashid]; mi; mi = mi->m_next) {
+ if (mi->m_blkno == blockno)
+ break;
+ }
+ if (mi == NULL) {
+ mi = (meta_info_t)malloc(sizeof(struct meta_info));
+
+ mi->m_next = m_info_hash[hashid];
+ m_info_hash[hashid] = mi;
+ mi->m_blkno = blockno;
+ }
+ mi->m_nameptr = pathname;
+}
+
+char *
+find_meta_name(uint64_t blockno) {
+ meta_info_t mi;
+ int hashid;
+
+ hashid = blockno & VN_HASH_MASK;
+
+ for (mi = m_info_hash[hashid]; mi; mi = mi->m_next) {
+ if (mi->m_blkno == blockno)
+ return (mi->m_nameptr);
+ }
+ return ("");
+}
+
+
+char *
+add_vnode_name(uint64_t vn_id, char *pathname) {
+ vnode_info_t vn;
+ int hashid;
+
+ hashid = (vn_id >> VN_HASH_SHIFT) & VN_HASH_MASK;
+
+ for (vn = vn_info_hash[hashid]; vn; vn = vn->vn_next) {
+ if (vn->vn_id == vn_id)
+ break;
+ }
+ if (vn == NULL) {
+ vn = (vnode_info_t)malloc(sizeof(struct vnode_info));
+
+ vn->vn_next = vn_info_hash[hashid];
+ vn_info_hash[hashid] = vn;
+ vn->vn_id = vn_id;
+ }
+ strcpy(vn->vn_pathname, pathname);
+
+ return (&vn->vn_pathname);
+}
+
+
+char *
+find_vnode_name(uint64_t vn_id) {
+ vnode_info_t vn;
+ int hashid;
+
+ hashid = (vn_id >> VN_HASH_SHIFT) & VN_HASH_MASK;
+
+ for (vn = vn_info_hash[hashid]; vn; vn = vn->vn_next) {
+ if (vn->vn_id == vn_id)
+ return (vn->vn_pathname);
+ }
+ return ("");
+}
+
+
void
delete_event(th_info_t ti_to_delete) {
th_info_t ti;
th_info_t
add_event(uintptr_t thread, int type) {
th_info_t ti;
+ int i;
int hashid;
if ((ti = th_info_freelist))
ti->waited = 0;
ti->in_filemgr = 0;
- ti->pathptr = ti->pathname;
- ti->pathname[0] = 0;
- ti->pathname2[0] = 0;
+ ti->in_hfs_update = 0;
+
+ ti->pathptr = &ti->lookups[0].pathname[0];
+ ti->pn_scall_index = 0;
+ ti->pn_work_index = 0;
+
+ for (i = 0; i < MAX_PATHNAMES; i++)
+ ti->lookups[i].pathname[0] = 0;
return (ti);
}
dio->issued_time = curtime;
dio->issuing_thread = thread;
+ dio->bc_info = 0x0;
+
if ((tme = find_map_entry(thread))) {
strncpy(dio->issuing_command, tme->tm_command, MAXCOMLEN);
dio->issuing_command[MAXCOMLEN-1] = '\0';
return (dio);
}
-
-struct diskio *complete_diskio(int bp, int io_errno, int resid, uintptr_t thread, double curtime)
-{
+struct diskio *find_diskio(int bp) {
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;
-
+ if (dio->bp == bp)
return (dio);
- }
}
- return ((struct diskio *)0);
+
+ return NULL;
+}
+
+
+struct diskio *complete_diskio(int bp, int io_errno, int resid, uintptr_t thread, double curtime)
+{
+ struct diskio *dio;
+
+ if ((dio = find_diskio(bp)) == NULL) return NULL;
+
+ 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;
}
char buf[64];
type = dio->type;
+ dio->is_meta = 0;
if ((type & P_CS_Class) == P_CS_Class) {
switch (type & P_DISKIO_TYPE) {
case P_RdMeta:
+ dio->is_meta = 1;
p = " RdMeta";
len = 8;
break;
case P_WrMeta:
+ dio->is_meta = 1;
p = " WrMeta";
len = 8;
break;
if (type & P_DISKIO_NOCACHE)
buf[len++] = 'N';
- if (type & P_DISKIO_THROTTLE)
+ int tier = (type & P_DISKIO_TIER_MASK) >> P_DISKIO_TIER_SHIFT;
+ if (tier > 0) {
buf[len++] = 'T';
- else if (type & P_DISKIO_PASSIVE)
+ if (tier > 0 && tier < 10)
+ buf[len++] = '0' + tier;
+ }
+
+ if (type & P_DISKIO_PASSIVE)
buf[len++] = 'P';
+
buf[len++] = ']';
}
buf[len] = 0;
* ret = 1 means print the entry
* ret = 0 means don't print the entry
*/
+
+/*
+ * meaning of filter flags:
+ * cachehit turn on display of CACHE_HIT events (which are filtered out by default)
+ *
+ * exec show exec/posix_spawn
+ * pathname show events with a pathname and close()
+ * diskio show disk I/Os
+ * filesys show filesystem events
+ * network show network events
+ *
+ * filters may be combined; default is all filters on (except cachehit)
+ */
int
-check_filter_mode(struct th_info * ti, int type, int error, int retval, char *sc_name)
+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);
+ /* cachehit is special -- it's not on by default */
+ if (sc_name[0] == 'C' && !strcmp(sc_name, "CACHE_HIT")) {
+ if (show_cachehits) return 1;
+ else return 0;
+ }
- if (sc_name[0] == 'C' && !strcmp (sc_name, "CACHE_HIT")) {
- if (filter_mode & CACHEHIT_FILTER)
- /* Do not print if cachehit filter is set */
- return(0);
+ if (filter_mode == DEFAULT_DO_NOT_FILTER)
return(1);
+
+ if (filter_mode & DISKIO_FILTER) {
+ if ((type & P_DISKIO_MASK) == P_DISKIO)
+ 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])
+ if (ti && ti->lookups[0].pathname[0])
return(1);
- if (type == BSC_close || type == BSC_close_nocancel)
+ if (type == BSC_close || type == BSC_close_nocancel ||
+ type == BSC_guarded_close_np)
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);
case BSC_close:
case BSC_close_nocancel:
+ case BSC_guarded_close_np:
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;
+ } else
+ if (filter_mode & FILESYS_FILTER)
+ ret = 1;
break;
case BSC_read:
if (network_fd_isset) {
if (filter_mode & NETWORK_FILTER)
ret = 1;
- } else if (filter_mode & FILESYS_FILTER)
- ret = 1;
+ } else
+ if (filter_mode & FILESYS_FILTER)
+ ret = 1;
break;
case BSC_accept:
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
- <key>Label</key>
- <string>com.apple.getty</string>
- <key>ProgramArguments</key>
- <array>
- <string>/usr/libexec/getty</string>
- <string>std.9600</string>
- <string>console</string>
- </array>
- <key>SessionCreate</key>
- <true/>
- <key>KeepAlive</key>
- <true/>
+ <key>KeepAlive</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.getty</string>
+ <key>POSIXSpawnType</key>
+ <string>Interactive</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/getty</string>
+ <string>std.9600</string>
+ <string>console</string>
+ </array>
+ <key>SessionCreate</key>
+ <true/>
</dict>
</plist>
#include <errno.h>
#include <fcntl.h>
#include <locale.h>
+#ifdef __APPLE__
+#include <util.h>
+#else
#include <libutil.h>
+#endif
#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>
static void putpad(const char *);
static void puts(const char *);
static void timeoverrun(int);
-static char *getline(int);
+static char *getty_getline(int);
static void setttymode(int);
static int opentty(const char *, int);
if ((fd = open(IF, O_RDONLY)) != -1) {
char * cp;
- while ((cp = getline(fd)) != NULL) {
+ while ((cp = getty_getline(fd)) != NULL) {
putf(cp);
}
close(fd);
static char *
-getline(int fd)
+getty_getline(int fd)
{
int i = 0;
static char linebuf[512];
if (sp >= &gettystrs[4] && sp <= &gettystrs[6])
l = 2;
else
- l = strlen(sp->value) + 1;
+ l = (int)strlen(sp->value) + 1;
if ((p = malloc(l)) != NULL) {
strncpy(p, sp->value, l);
p[l-1] = '\0';
uint64_t sample_TOD_secs;
uint32_t sample_TOD_usecs;
+uint64_t cpu_mask;
+
int sample_generation = 0;
int num_i_latency_cpus = 1;
int num_cpus;
int
main(int argc, char *argv[])
{
+ int i;
+
if (0 != reexec_to_match_kernel()) {
fprintf(stderr, "Could not re-execute: %d\n", errno);
exit(1);
num_cpus = 128;
}
+ for (cpu_mask = 0, i = 0; i < num_cpus; i++)
+ cpu_mask |= ((uint64_t)1 << i);
+
if ((my_buffer = malloc(num_entries * sizeof(kd_buf))) == NULL) {
quit("can't allocate memory for tracing info\n");
}
pc_to_string(&pcstring[0], kd->arg2, 58, mode);
- fprintf(fp, "%9.1f %8.1f\t\tINTERRUPT[%2lx] @ %-58.58s %-8x %d %s\n",
+ fprintf(fp, "%9.1f %8.1f\t\tINTERRUPT[%2lx] @ %-58.58s %8x %2d %s\n",
timestamp, delta, kd->arg1, &pcstring[0], thread, cpunum, command);
} else if (type == MACH_vmfault) {
- fprintf(fp, "%9.1f %8.1f\t\t%-28.28s %-8x %d %s\n",
+ fprintf(fp, "%9.1f %8.1f\t\t%-28.28s %8x %2d %s\n",
timestamp, delta, p, thread, cpunum, command);
} else {
- fprintf(fp, "%9.1f %8.1f\t\t%-28.28s %-8lx %-8lx %-8lx %-8lx %-8x %d %s\n",
+ fprintf(fp, "%9.1f %8.1f\t\t%-28.28s %-16lx %-16lx %-16lx %-16lx %8x %2d %s\n",
timestamp, delta, p, kd->arg1, kd->arg2, kd->arg3, kd->arg4,
thread, cpunum, command);
}
} else {
- fprintf(fp, "%9.1f %8.1f\t\t%-8x %-8lx %-8lx %-8lx %-8lx %-8x %d %s\n",
+ fprintf(fp, "%9.1f %8.1f\t\t%-8x %-16lx %-16lx %-16lx %-16lx %8x %2d %s\n",
timestamp, delta, type, kd->arg1, kd->arg2, kd->arg3, kd->arg4,
thread, cpunum, command);
}
if ((p = find_code(type))) {
if (type == INTERRUPT) {
- fprintf(fp, "INTERRUPT %-8x %d %s\n", thread, cpunum, command);
+ fprintf(fp, "INTERRUPT %8x %2d %s\n", thread, cpunum, command);
} else if (type == MACH_vmfault && kd->arg4 <= DBG_PAGEIND_FAULT) {
user_addr = ((uint64_t)kd->arg1 << 32) | (uint32_t)kd->arg2;
- fprintf(fp, "%-28.28s %-10.10s %-16qx %-8x %d %s\n",
+ fprintf(fp, "%-28.28s %-10.10s %-16qx %8x %2d %s\n",
p, fault_name[kd->arg4], user_addr,
thread, cpunum, command);
} else {
- fprintf(fp, "%-28.28s %-8lx %-8lx %-8x %d %s\n",
+ fprintf(fp, "%-28.28s %-16lx %-16lx %8x %2d %s\n",
p, kd->arg1, kd->arg2,
thread, cpunum, command);
}
} else {
- fprintf(fp, "%-8x %-8lx %-8lx %-8x %d %s\n",
+ fprintf(fp, "%-8x %-16lx %-16lx %8x %2d %s\n",
type, kd->arg1, kd->arg2,
thread, cpunum, command);
}
} else {
fprintf(fp, "%9.1f %8.1f\t\t", timestamp, delta);
}
- fprintf(fp, "%-28.28s %-8lx %-8lx %-8lx %-8lx %-8x %d %s\n",
+ fprintf(fp, "%-28.28s %-16lx %-16lx %-16lx %-16lx %8x %2d %s\n",
p, kd->arg1, kd->arg2, kd->arg3, kd->arg4, thread, cpunum, command);
} else {
- fprintf(fp, "%9.1f %8.1f\t\t%-8x %-8lx %-8lx %-8lx %-8lx %-8x %d %s\n",
+ fprintf(fp, "%9.1f %8.1f\t\t%-8x %-16lx %-16lx %-16lx %-16lx %8x %2d %s\n",
timestamp, delta, type, kd->arg1, kd->arg2, kd->arg3, kd->arg4,
thread, cpunum, command);
}
switch (type) {
case CQ_action:
- pc_to_string(&pcstring[0], kd->arg1, 62, KERNEL_MODE);
+ pc_to_string(&pcstring[0], kd->arg1, 84, KERNEL_MODE);
- fprintf(log_fp, "%9.1f %8.1f\t\tCQ_action @ %-62.62s %-8x %d %s\n",
+ fprintf(log_fp, "%9.1f %8.1f\t\tCQ_action @ %-84.84s %8x %2d %s\n",
timestamp, delta, &pcstring[0], thread, cpunum, command);
break;
case TES_action:
- pc_to_string(&pcstring[0], kd->arg1, 61, KERNEL_MODE);
+ pc_to_string(&pcstring[0], kd->arg1, 83, KERNEL_MODE);
- fprintf(log_fp, "%9.1f %8.1f\t\tTES_action @ %-61.61s %-8x %d %s\n",
+ fprintf(log_fp, "%9.1f %8.1f\t\tTES_action @ %-83.83s %8x %2d %s\n",
timestamp, delta, &pcstring[0], thread, cpunum, command);
break;
case IES_action:
- pc_to_string(&pcstring[0], kd->arg1, 61, KERNEL_MODE);
+ pc_to_string(&pcstring[0], kd->arg1, 83, KERNEL_MODE);
- fprintf(log_fp, "%9.1f %8.1f\t\tIES_action @ %-61.61s %-8x %d %s\n",
+ fprintf(log_fp, "%9.1f %8.1f\t\tIES_action @ %-83.83s %8x %2d %s\n",
timestamp, delta, &pcstring[0], thread, cpunum, command);
break;
case IES_filter:
- pc_to_string(&pcstring[0], kd->arg1, 61, KERNEL_MODE);
+ pc_to_string(&pcstring[0], kd->arg1, 83, KERNEL_MODE);
- fprintf(log_fp, "%9.1f %8.1f\t\tIES_filter @ %-61.61s %-8x %d %s\n",
+ fprintf(log_fp, "%9.1f %8.1f\t\tIES_filter @ %-83.83s %8x %2d %s\n",
timestamp, delta, &pcstring[0], thread, cpunum, command);
break;
mode = KERNEL_MODE;
}
- pc_to_string(&pcstring[0], kd->arg2, 62, mode);
+ pc_to_string(&pcstring[0], kd->arg2, 84, mode);
- fprintf(log_fp, "%9.1f %8.1f[%.1f]%s\tDECR_TRAP @ %-62.62s %-8x %d %s\n",
+ fprintf(log_fp, "%9.1f %8.1f[%.1f]%s\tDECR_TRAP @ %-84.84s %8x %2d %s\n",
timestamp, delta, i_latency, p, &pcstring[0], thread, cpunum, command);
break;
case DECR_SET:
- fprintf(log_fp, "%9.1f %8.1f[%.1f] \t%-28.28s %-8x %d %s\n",
+ fprintf(log_fp, "%9.1f %8.1f[%.1f] \t%-28.28s %8x %2d %s\n",
timestamp, delta, (double)kd->arg1/divisor, "DECR_SET", thread, cpunum, command);
break;
sprintf(joe, "%x", reason);
sched_reason = joe;
}
- sprintf(sched_info, "%14.14s @ pri %3lu --> %14.14s @ pri %3lu%s", command, kd->arg3, command1, kd->arg4, p);
+ sprintf(sched_info, "%16.16s @ pri %3lu --> %16.16s @ pri %3lu%s", command, kd->arg3, command1, kd->arg4, p);
- fprintf(log_fp, "%9.1f %8.1f\t\t%-10.10s[%s] %s %-8x %d\n",
+ fprintf(log_fp, "%9.1f %8.1f\t\t%-10.10s[%s] %s %8x %2d\n",
timestamp, delta, "MACH_SCHED", sched_reason, sched_info, thread, cpunum);
break;
clen = 0;
}
- fprintf(log_fp, "%9.1f %8.1f\t\t%-14.14s %-45s %-8lx %-8x %d %s\n",
+ fprintf(log_fp, "%9.1f %8.1f\t\t%-14.14s %-59s %-16lx %8x %2d %s\n",
timestamp, delta, "VFS_LOOKUP",
&p[clen], lkp->lk_dvp, thread, cpunum, command);
fprintf(log_fp, "\n\n%s\n", buf2);
fprintf(log_fp, "%s\n\n", buf1);
- fprintf(log_fp, "RelTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu command\n\n");
+ fprintf(log_fp, "RelTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu command\n\n");
reset_thread_names();
{
kd_buf *kd_start, *kd_stop;
uint64_t now;
+ int count;
+ int cpunum;
+ uint64_t cmask = 0;
double sample_timestamp;
char buf1[128];
- int cpunum = CPU_NUMBER(kd_end);
-
- for (kd_start = kd_beg; (kd_start >= (kd_buf *)my_buffer); kd_start--) {
- if (CPU_NUMBER(kd_start) == cpunum) {
- break;
+ for (count = 0, kd_start = kd_beg; (kd_start >= (kd_buf *)my_buffer); kd_start--) {
+ cpunum = CPU_NUMBER(kd_start);
+
+ cmask |= ((uint64_t)1 << cpunum);
+
+ if (cmask == cpu_mask) {
+ if (count++ > 100)
+ break;
}
}
if (kd_start < (kd_buf *)my_buffer) {
--- /dev/null
+.\" Copyright (c) 2012, Apple Inc. All rights reserved.
+.\"
+.Dd Jul 24, 2012
+.Dt LSMP 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm lsmp
+.Nd Display mach port information for processes on the system
+.Sh SYNOPSIS
+.Nm lsmp
+.Fl h
+.Pp
+.Nm lsmp
+.Ar <pid>
+Show mach port usage for <pid>
+.Pp
+.Nm lsmp
+.Ar -all
+Show mach port usage for all tasks in the system
+.Sh DESCRIPTION
+The
+.Nm lsmp
+ command prints information about every active right in a task's port space, giving a view into the inter-process communication behavior of that task.
+.P
+.nf
+Following is an explanation of each symbol and values from the output.
+name : Task unique name for a port. A "-" signifies that this is a member of a port-set
+ipc-object : A unique identifier for a kernel object. A "+" sign implies that this entry is expanded from above ipc-object.
+rights : Rights corresponding to this name. Possible values are recv, send, send-once and port-set.
+flags : Flags indicating port status.
+ T : Port has tempowner set
+ G : Port is guarded
+ S : Port has strict guarding restrictions
+ I : Port has importance donation flag set
+ R : Port is marked reviving
+ P : Port has task pointer set
+boost : Importance boost count
+reqs : Notifications armed on this port.
+ D : Dead name notification
+ N : No sender notification
+ P : Port Destroy requests
+recv : Number of recv rights for this name.
+send : Number of send rights stored at this name. This does NOT reflect the total number of send rights for this recv right.
+sonce : Number of outstanding send-once rights for this receive right.
+oref : Do send rights exist somewhere for this receive right?
+qlimit : Queue limit for this port. If orefs column shows -> then it indicates the queue limit on the destination port. And a <- indicates this port right is destined to receive messages from process referred in identifier column.
+msgcount : Number of messages enqueued on this port. See qlimit for -> and <- explanations.
+context : Mach port context value.
+identifier : A unique identifier for a kernel object or task's name for this right. This field is described by the type column.
+.fi
+.Sh SEE ALSO
+.Xr ddt 1
+.Xr top 1
--- /dev/null
+/*
+ * Copyright (c) 2002-2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (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.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <unistd.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach_debug/ipc_info.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <libproc.h>
+#include <TargetConditionals.h>
+
+
+#define PROC_NAME_LEN 256
+#define BUFSTR_LEN 30
+
+#if TARGET_OS_EMBEDDED
+#define TASK_FOR_PID_USAGE_MESG "\nPlease check your boot-args to ensure you have access to task_for_pid()."
+#else
+#define TASK_FOR_PID_USAGE_MESG ""
+#endif
+/*
+ * WARNING - these types are copied from xnu/osfmk/kern/ipc_kobject.h
+ * Need to stay in sync to print accurate results.
+ */
+#define IKOT_NONE 0
+#define IKOT_THREAD 1
+#define IKOT_TASK 2
+#define IKOT_HOST 3
+#define IKOT_HOST_PRIV 4
+#define IKOT_PROCESSOR 5
+#define IKOT_PSET 6
+#define IKOT_PSET_NAME 7
+#define IKOT_TIMER 8
+#define IKOT_PAGING_REQUEST 9
+#define IKOT_MIG 10
+#define IKOT_MEMORY_OBJECT 11
+#define IKOT_XMM_PAGER 12
+#define IKOT_XMM_KERNEL 13
+#define IKOT_XMM_REPLY 14
+#define IKOT_UND_REPLY 15
+#define IKOT_HOST_NOTIFY 16
+#define IKOT_HOST_SECURITY 17
+#define IKOT_LEDGER 18
+#define IKOT_MASTER_DEVICE 19
+#define IKOT_TASK_NAME 20
+#define IKOT_SUBSYSTEM 21
+#define IKOT_IO_DONE_QUEUE 22
+#define IKOT_SEMAPHORE 23
+#define IKOT_LOCK_SET 24
+#define IKOT_CLOCK 25
+#define IKOT_CLOCK_CTRL 26
+#define IKOT_IOKIT_SPARE 27
+#define IKOT_NAMED_ENTRY 28
+#define IKOT_IOKIT_CONNECT 29
+#define IKOT_IOKIT_OBJECT 30
+#define IKOT_UPL 31
+#define IKOT_MEM_OBJ_CONTROL 32
+#define IKOT_AU_SESSIONPORT 33
+#define IKOT_FILEPORT 34
+#define IKOT_LABELH 35
+#define IKOT_UNKNOWN 36 /* magic catchall */
+#define IKOT_MAX_TYPE (IKOT_UNKNOWN+1) /* # of IKOT_ types */
+
+#define SHOW_PORT_STATUS_FLAGS(flags) \
+ (flags & MACH_PORT_STATUS_FLAG_TEMPOWNER) ?"T":"-", \
+ (flags & MACH_PORT_STATUS_FLAG_GUARDED) ?"G":"-", \
+ (flags & MACH_PORT_STATUS_FLAG_STRICT_GUARD) ?"S":"-", \
+ (flags & MACH_PORT_STATUS_FLAG_IMP_DONATION) ?"I":"-", \
+ (flags & MACH_PORT_STATUS_FLAG_REVIVE) ?"R":"-", \
+ (flags & MACH_PORT_STATUS_FLAG_TASKPTR) ?"P":"-"
+
+/* private structure to wrap up per-task info */
+typedef struct my_per_task_info {
+ task_t task;
+ pid_t pid;
+ ipc_info_space_t info;
+ ipc_info_name_array_t table;
+ mach_msg_type_number_t tableCount;
+ ipc_info_tree_name_array_t tree;
+ mach_msg_type_number_t treeCount;
+ char processName[PROC_NAME_LEN];
+} my_per_task_info_t;
+
+my_per_task_info_t *psettaskinfo;
+mach_msg_type_number_t taskCount;
+
+static const char *
+kobject_name(natural_t kotype)
+{
+ switch (kotype) {
+ case IKOT_NONE: return "message-queue";
+ case IKOT_THREAD: return "THREAD";
+ case IKOT_TASK: return "TASK";
+ case IKOT_HOST: return "HOST";
+ case IKOT_HOST_PRIV: return "HOST-PRIV";
+ case IKOT_PROCESSOR: return "PROCESSOR";
+ case IKOT_PSET: return "PROCESSOR-SET";
+ case IKOT_PSET_NAME: return "PROCESSOR-SET-NAME";
+ case IKOT_TIMER: return "TIMER";
+ case IKOT_PAGING_REQUEST: return "PAGER-REQUEST";
+ case IKOT_MIG: return "MIG";
+ case IKOT_MEMORY_OBJECT: return "MEMORY-OBJECT";
+ case IKOT_XMM_PAGER: return "XMM-PAGER";
+ case IKOT_XMM_KERNEL: return "XMM-KERNEL";
+ case IKOT_XMM_REPLY: return "XMM-REPLY";
+ case IKOT_UND_REPLY: return "UND-REPLY";
+ case IKOT_HOST_NOTIFY: return "message-queue";
+ case IKOT_HOST_SECURITY: return "HOST-SECURITY";
+ case IKOT_LEDGER: return "LEDGER";
+ case IKOT_MASTER_DEVICE: return "MASTER-DEVICE";
+ case IKOT_TASK_NAME: return "TASK-NAME";
+ case IKOT_SUBSYSTEM: return "SUBSYSTEM";
+ case IKOT_IO_DONE_QUEUE: return "IO-QUEUE-DONE";
+ case IKOT_SEMAPHORE: return "SEMAPHORE";
+ case IKOT_LOCK_SET: return "LOCK-SET";
+ case IKOT_CLOCK: return "CLOCK";
+ case IKOT_CLOCK_CTRL: return "CLOCK-CONTROL";
+ case IKOT_IOKIT_SPARE: return "IOKIT-SPARE";
+ case IKOT_NAMED_ENTRY: return "NAMED-MEMORY";
+ case IKOT_IOKIT_CONNECT: return "IOKIT-CONNECT";
+ case IKOT_IOKIT_OBJECT: return "IOKIT-OBJECT";
+ case IKOT_UPL: return "UPL";
+ case IKOT_MEM_OBJ_CONTROL: return "XMM-CONTROL";
+ case IKOT_AU_SESSIONPORT: return "SESSIONPORT";
+ case IKOT_FILEPORT: return "FILEPORT";
+ case IKOT_LABELH: return "MACF-LABEL";
+ case IKOT_UNKNOWN:
+ default: return "UNKNOWN";
+ }
+}
+
+static void proc_pid_to_name(int pid, char *pname){
+ if (0 == proc_name(pid, pname, PROC_NAME_LEN)) {
+ strcpy(pname, "Unknown Process");
+ }
+}
+
+static int get_recieve_port_status(task_t taskp, mach_port_name_t portname, mach_port_info_ext_t *info){
+ if (info == NULL) {
+ return -1;
+ }
+ mach_msg_type_number_t statusCnt;
+ kern_return_t ret;
+ statusCnt = MACH_PORT_INFO_EXT_COUNT;
+ ret = mach_port_get_attributes(taskp,
+ portname,
+ MACH_PORT_INFO_EXT,
+ (mach_port_info_t)info,
+ &statusCnt);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "mach_port_get_attributes(0x%08x) failed: %s\n",
+ portname,
+ mach_error_string(ret));
+ return -1;
+ }
+
+ return 0;
+}
+
+static void get_receive_port_context(task_t taskp, mach_port_name_t portname, mach_port_context_t *context) {
+ if (context == NULL) {
+ return;
+ }
+
+ kern_return_t ret;
+ ret = mach_port_get_context(taskp, portname, context);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "mach_port_get_context(0x%08x) failed: %s\n",
+ portname,
+ mach_error_string(ret));
+ *context = (mach_port_context_t)0;
+ }
+ return;
+}
+
+static void show_task_mach_ports(my_per_task_info_t *taskinfo){
+ int i, emptycount = 0, portsetcount = 0, sendcount = 0, receivecount = 0, sendoncecount = 0, deadcount = 0, dncount = 0, pid;
+ kern_return_t ret;
+ pid_for_task(taskinfo->task, &pid);
+
+ printf(" name ipc-object rights flags boost reqs recv send sonce oref qlimit msgcount context identifier type\n");
+ printf("--------- ---------- ---------- -------- ----- ---- ----- ----- ----- ---- ------ -------- ------------------ ----------- ------------\n");
+ for (i = 0; i < taskinfo->tableCount; i++) {
+ int j, k;
+ boolean_t found = FALSE;
+ boolean_t send = FALSE;
+ boolean_t sendonce = FALSE;
+ boolean_t dnreq = FALSE;
+ int sendrights = 0;
+ unsigned int kotype = 0;
+ vm_offset_t kobject = (vm_offset_t)0;
+
+ /* skip empty slots in the table */
+ if ((taskinfo->table[i].iin_type & MACH_PORT_TYPE_ALL_RIGHTS) == 0) {
+ emptycount++;
+ continue;
+ }
+
+
+ if (taskinfo->table[i].iin_type == MACH_PORT_TYPE_PORT_SET) {
+ mach_port_name_array_t members;
+ mach_msg_type_number_t membersCnt;
+
+ ret = mach_port_get_set_status(taskinfo->task,
+ taskinfo->table[i].iin_name,
+ &members, &membersCnt);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "mach_port_get_set_status(0x%08x) failed: %s\n",
+ taskinfo->table[i].iin_name,
+ mach_error_string(ret));
+ continue;
+ }
+ printf("0x%08x 0x%08x port-set -------- ----- --- 1 %d members\n",
+ taskinfo->table[i].iin_name,
+ taskinfo->table[i].iin_object,
+ membersCnt);
+ /* get some info for each portset member */
+ for (j = 0; j < membersCnt; j++) {
+ for (k = 0; k < taskinfo->tableCount; k++) {
+ if (taskinfo->table[k].iin_name == members[j]) {
+ mach_port_info_ext_t info;
+ mach_port_status_t port_status;
+ mach_port_context_t port_context = (mach_port_context_t)0;
+ if (0 != get_recieve_port_status(taskinfo->task, taskinfo->table[k].iin_name, &info)) {
+ bzero((void *)&info, sizeof(info));
+ }
+ port_status = info.mpie_status;
+ get_receive_port_context(taskinfo->task, taskinfo->table[k].iin_name, &port_context);
+ printf(" - 0x%08x %s --%s%s%s%s%s%s %5d %s%s%s %5d %5.0d %5.0d %s %6d %8d 0x%016llx 0x%08x (%d) %s\n",
+ taskinfo->table[k].iin_object,
+ (taskinfo->table[k].iin_type & MACH_PORT_TYPE_SEND) ? "recv,send ":"recv ",
+ SHOW_PORT_STATUS_FLAGS(port_status.mps_flags),
+ info.mpie_boost_cnt,
+ (taskinfo->table[k].iin_type & MACH_PORT_TYPE_DNREQUEST) ? "D" : "-",
+ (port_status.mps_nsrequest) ? "N" : "-",
+ (port_status.mps_pdrequest) ? "P" : "-",
+ 1,
+ taskinfo->table[k].iin_urefs,
+ port_status.mps_sorights,
+ (port_status.mps_srights) ? "Y" : "N",
+ port_status.mps_qlimit,
+ port_status.mps_msgcount,
+ (uint64_t)port_context,
+ taskinfo->table[k].iin_name,
+ pid,
+ taskinfo->processName);
+ break;
+ }
+ }
+ }
+
+ ret = vm_deallocate(mach_task_self(), (vm_address_t)members,
+ membersCnt * sizeof(mach_port_name_t));
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "vm_deallocate() failed: %s\n",
+ mach_error_string(ret));
+ exit(1);
+ }
+ portsetcount++;
+ continue;
+ }
+
+ if (taskinfo->table[i].iin_type & MACH_PORT_TYPE_SEND) {
+ send = TRUE;
+ sendrights = taskinfo->table[i].iin_urefs;
+ sendcount++;
+ }
+
+ if (taskinfo->table[i].iin_type & MACH_PORT_TYPE_DNREQUEST) {
+ dnreq = TRUE;
+ dncount++;
+ }
+
+ if (taskinfo->table[i].iin_type & MACH_PORT_TYPE_RECEIVE) {
+ mach_port_status_t status;
+ mach_port_info_ext_t info;
+ mach_port_context_t context = (mach_port_context_t)0;
+ ret = get_recieve_port_status(taskinfo->task, taskinfo->table[i].iin_name, &info);
+ get_receive_port_context(taskinfo->task, taskinfo->table[i].iin_name, &context);
+ /* its ok to fail in fetching attributes */
+ if (ret < 0) {
+ continue;
+ }
+ status = info.mpie_status;
+ printf("0x%08x 0x%08x %s --%s%s%s%s%s%s %5d %s%s%s %5d %5.0d %5.0d %s %6d %8d 0x%016llx \n",
+ taskinfo->table[i].iin_name,
+ taskinfo->table[i].iin_object,
+ (send) ? "recv,send ":"recv ",
+ SHOW_PORT_STATUS_FLAGS(status.mps_flags),
+ info.mpie_boost_cnt,
+ (dnreq) ? "D":"-",
+ (status.mps_nsrequest) ? "N":"-",
+ (status.mps_pdrequest) ? "P":"-",
+ 1,
+ sendrights,
+ status.mps_sorights,
+ (status.mps_srights) ? "Y":"N",
+ status.mps_qlimit,
+ status.mps_msgcount,
+ (uint64_t)context);
+ receivecount++;
+
+ /* show other rights (in this and other tasks) for the port */
+ for (j = 0; j < taskCount; j++) {
+ for (k = 0; k < psettaskinfo->tableCount; k++) {
+ if (&psettaskinfo[j].table[k] == &taskinfo->table[i] ||
+ psettaskinfo[j].table[k].iin_object != taskinfo->table[i].iin_object)
+ continue;
+
+ printf(" + %s -------- ----- %s%s%s %5d <- 0x%08x (%d) %s\n",
+ (psettaskinfo[j].table[k].iin_type & MACH_PORT_TYPE_SEND_ONCE) ?
+ "send-once " : "send ",
+ (psettaskinfo[j].table[k].iin_type & MACH_PORT_TYPE_DNREQUEST) ? "D" : "-",
+ "-",
+ "-",
+ psettaskinfo[j].table[k].iin_urefs,
+ psettaskinfo[j].table[k].iin_name,
+ psettaskinfo[j].pid,
+ psettaskinfo[j].processName);
+ }
+ }
+ continue;
+ }
+ else if (taskinfo->table[i].iin_type & MACH_PORT_TYPE_DEAD_NAME)
+ {
+ printf("0x%08x 0x%08x dead-name -------- ----- --- %5d \n",
+ taskinfo->table[i].iin_name,
+ taskinfo->table[i].iin_object,
+ taskinfo->table[i].iin_urefs);
+ deadcount++;
+ continue;
+ }
+
+ if (taskinfo->table[i].iin_type & MACH_PORT_TYPE_SEND_ONCE) {
+ sendonce = TRUE;
+ sendoncecount++;
+ }
+
+ printf("0x%08x 0x%08x %s -------- ----- %s%s%s %5.0d ",
+ taskinfo->table[i].iin_name,
+ taskinfo->table[i].iin_object,
+ (send) ? "send ":"send-once ",
+ (dnreq) ? "D":"-",
+ "-",
+ "-",
+ (send) ? sendrights : 0);
+
+ /* converting to kobjects is not always supported */
+ ret = mach_port_kernel_object(taskinfo->task,
+ taskinfo->table[i].iin_name,
+ &kotype, (unsigned *)&kobject);
+ if (ret == KERN_SUCCESS && kotype != 0) {
+ printf(" 0x%08x %s\n", (natural_t)kobject, kobject_name(kotype));
+ continue;
+ }
+
+ /* not kobject - find the receive right holder */
+ for (j = 0; j < taskCount && !found; j++) {
+ for (k = 0; k < psettaskinfo[j].tableCount && !found; k++) {
+ if ((psettaskinfo[j].table[k].iin_type & MACH_PORT_TYPE_RECEIVE) &&
+ psettaskinfo[j].table[k].iin_object == taskinfo->table[i].iin_object ) {
+ mach_port_status_t port_status;
+ mach_port_info_ext_t info;
+ mach_port_context_t port_context = (mach_port_context_t)0;
+ if (0 != get_recieve_port_status(psettaskinfo[j].task, psettaskinfo[j].table[k].iin_name, &info)) {
+ bzero((void *)&port_status, sizeof(port_status));
+ }
+ port_status = info.mpie_status;
+ get_receive_port_context(psettaskinfo[j].task, psettaskinfo[j].table[k].iin_name, &port_context);
+ printf(" -> %6d %8d 0x%016llx 0x%08x (%d) %s\n",
+ port_status.mps_qlimit,
+ port_status.mps_msgcount,
+ (uint64_t)port_context,
+ psettaskinfo[j].table[k].iin_name,
+ psettaskinfo[j].pid,
+ psettaskinfo[j].processName);
+ found = TRUE;
+ }
+ }
+ }
+ if (!found)
+ printf(" 0x00000000 (-) Unknown Process\n");
+ }
+ printf("total = %d\n", taskinfo->tableCount + taskinfo->treeCount - emptycount);
+ printf("SEND = %d\n", sendcount);
+ printf("RECEIVE = %d\n", receivecount);
+ printf("SEND_ONCE = %d\n", sendoncecount);
+ printf("PORT_SET = %d\n", portsetcount);
+ printf("DEAD_NAME = %d\n", deadcount);
+ printf("DNREQUEST = %d\n", dncount);
+
+}
+
+int main(int argc, char *argv[]) {
+ int pid;
+ const char * dash_all_str = "-all";
+ const char * dash_h = "-h";
+ int show_all_tasks = 0;
+ kern_return_t ret;
+ my_per_task_info_t aTask;
+ my_per_task_info_t *taskinfo;
+ task_array_t tasks;
+
+ int i ;
+
+ if (argc != 2 || !strncmp(dash_h, argv[1], strlen(dash_h))) {
+ fprintf(stderr, "Usage: %s [ -all | <pid> ]\n", argv[0]);
+ fprintf(stderr, "Lists information about mach ports. Please see man page for description of each column.\n");
+ exit(1);
+ }
+
+ if (strncmp(dash_all_str, argv[1], strlen(dash_all_str)) == 0) {
+ pid = 0;
+ show_all_tasks = 1;
+ } else
+ pid = atoi(argv[1]);
+
+ /* if privileged, get the info for all tasks so we can match ports up */
+ if (geteuid() == 0) {
+ processor_set_name_array_t psets;
+ mach_msg_type_number_t psetCount;
+ mach_port_t pset_priv;
+
+
+ ret = host_processor_sets(mach_host_self(), &psets, &psetCount);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "host_processor_sets() failed: %s\n", mach_error_string(ret));
+ exit(1);
+ }
+ if (psetCount != 1) {
+ fprintf(stderr, "Assertion Failure: pset count greater than one (%d)\n", psetCount);
+ exit(1);
+ }
+
+ /* convert the processor-set-name port to a privileged port */
+ ret = host_processor_set_priv(mach_host_self(), psets[0], &pset_priv);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "host_processor_set_priv() failed: %s\n", mach_error_string(ret));
+ exit(1);
+ }
+ mach_port_deallocate(mach_task_self(), psets[0]);
+ vm_deallocate(mach_task_self(), (vm_address_t)psets, (vm_size_t)psetCount * sizeof(mach_port_t));
+
+ /* convert the processor-set-priv to a list of tasks for the processor set */
+ ret = processor_set_tasks(pset_priv, &tasks, &taskCount);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "processor_set_tasks() failed: %s\n", mach_error_string(ret));
+ exit(1);
+ }
+ mach_port_deallocate(mach_task_self(), pset_priv);
+
+ /* convert each task to structure of pointer for the task info */
+ psettaskinfo = (my_per_task_info_t *)malloc(taskCount * sizeof(my_per_task_info_t));
+ for (i = 0; i < taskCount; i++) {
+ psettaskinfo[i].task = tasks[i];
+ pid_for_task(tasks[i], &psettaskinfo[i].pid);
+ ret = mach_port_space_info(tasks[i], &psettaskinfo[i].info,
+ &psettaskinfo[i].table, &psettaskinfo[i].tableCount,
+ &psettaskinfo[i].tree, &psettaskinfo[i].treeCount);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "mach_port_space_info() failed: pid:%d error: %s\n",psettaskinfo[i].pid, mach_error_string(ret));
+ if (show_all_tasks == 1) {
+ printf("Ignoring failure of mach_port_space_info() for task %d for '-all'\n", tasks[i]);
+ psettaskinfo[i].pid = 0;
+ continue;
+ } else {
+ exit(1);
+ }
+ }
+ proc_pid_to_name(psettaskinfo[i].pid, psettaskinfo[i].processName);
+ if (psettaskinfo[i].pid == pid)
+ taskinfo = &psettaskinfo[i];
+ }
+ }
+ else
+ {
+ fprintf(stderr, "warning: should run as root for best output (cross-ref to other tasks' ports).\n");
+ /* just the one process */
+ ret = task_for_pid(mach_task_self(), pid, &aTask.task);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "task_for_pid() failed: %s %s\n", mach_error_string(ret), TASK_FOR_PID_USAGE_MESG);
+ exit(1);
+ }
+ ret = mach_port_space_info(aTask.task, &aTask.info,
+ &aTask.table, &aTask.tableCount,
+ &aTask.tree, &aTask.treeCount);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "mach_port_space_info() failed: %s\n", mach_error_string(ret));
+ exit(1);
+ }
+ taskinfo = &aTask;
+ psettaskinfo = taskinfo;
+ proc_pid_to_name(psettaskinfo->pid, psettaskinfo->processName);
+ taskCount = 1;
+ }
+
+ if( show_all_tasks == 0){
+ printf("Process (%d) : %s\n", taskinfo->pid, taskinfo->processName);
+ show_task_mach_ports(taskinfo);
+ }else {
+ for (i=0; i < taskCount; i++){
+ if (psettaskinfo[i].pid == 0)
+ continue;
+ printf("Process (%d) : %s\n", psettaskinfo[i].pid, psettaskinfo[i].processName);
+ show_task_mach_ports(&psettaskinfo[i]);
+ printf("\n\n");
+ }
+ }
+
+ if (taskCount > 1){
+ vm_deallocate(mach_task_self(), (vm_address_t)tasks, (vm_size_t)taskCount * sizeof(mach_port_t));
+ free(psettaskinfo);
+ }
+
+ return(0);
+}
--- /dev/null
+.\" Copyright (c) 2012, Apple Inc. All rights reserved.
+.\"
+.Dd June 28, 2012
+.Dt LTOP 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm ltop
+.Nd Display ledger information for processes on the system
+.Sh SYNOPSIS
+.Nm ltop
+.Fl h
+.Pp
+.Nm ltop
+.Fl p Ar pid
+.Sh DESCRIPTION
+The
+.Nm ltop
+command allows the user to print the resource ledger information maintained by kernel for each process. The ledger information provides insights into cpu time, memory usage of a process and also know the limits set on them.
+.Sh SEE ALSO
+.Xr top 1
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <libproc.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <Kernel/kern/ledger.h>
+#include <mach/mach_types.h>
+
+extern int ledger(int cmd, caddr_t arg1, caddr_t arg2, caddr_t arg3);
+
+int pid = -1;
+char *group_print = NULL;
+char *resource_print = NULL;
+
+struct proc_list {
+ int pid;
+ int seen;
+ char command[32];
+ struct ledger *ledger;
+ struct proc_list *next;
+};
+
+struct proc_list *procs = NULL;
+struct ledger_template_info *template = NULL;
+int entry_cnt = 0;
+
+struct ledger {
+ int64_t id;
+ int seen;
+ int64_t entries;
+ struct ledger_entry_info *info;
+ struct ledger_entry_info *old_info;
+ struct ledger *next;
+};
+
+struct ledger *ledgers = NULL;
+
+static void
+get_template_info()
+{
+
+ void *buf;
+ int cnt;
+
+top:
+ /* Allocate enough space to accomodate a few new entries */
+ cnt = entry_cnt + 5;
+ buf = malloc(cnt * sizeof (struct ledger_template_info));
+ if (buf == NULL) {
+ fprintf(stderr, "Out of memory\n");
+ exit (1);
+ }
+
+ if (ledger(LEDGER_TEMPLATE_INFO, (caddr_t)buf, (caddr_t)&cnt, NULL) < 0) {
+ perror("ledger() system call failed");
+ exit(1);
+ }
+
+ /* We underestimated how many entries we needed. Let's try again */
+ if (cnt == entry_cnt + 5) {
+ entry_cnt += 5;
+ free(buf);
+ goto top;
+ }
+ entry_cnt = cnt;
+ template = buf;
+}
+
+/*
+ * Note - this is a destructive operation. Unless we're about to exit, this
+ * needs to be followed by another call to get_template_info().
+ */
+static void
+dump_template_info()
+{
+ int i, j;
+ const char *group = NULL;
+
+ printf("Resources being tracked:\n");
+ printf("\t%10s %15s %8s\n", "GROUP", "RESOURCE", "UNITS");
+ for (i = 0; i < entry_cnt; i++) {
+ if (strlen(template[i].lti_name) == 0)
+ continue;
+
+ group = template[i].lti_group;
+ for (j = i; j < entry_cnt; j++) {
+ if (strcmp(template[j].lti_group, group))
+ continue;
+ printf("\t%10s %15s %8s\n", template[j].lti_group,
+ template[j].lti_name, template[j].lti_units);
+ template[j].lti_name[0] = '\0';
+ }
+ }
+}
+
+static void
+validate_group()
+{
+ int i;
+
+ if (template == NULL)
+ get_template_info();
+
+ for (i = 0; i < entry_cnt; i++)
+ if (!strcmp(group_print, template[i].lti_group))
+ return;
+
+ fprintf(stderr, "No such group: %s\n", group_print);
+ exit (1);
+}
+
+static void
+validate_resource()
+{
+ int i;
+
+ if (template == NULL)
+ get_template_info();
+
+ for (i = 0; i < entry_cnt; i++)
+ if (!strcmp(resource_print, template[i].lti_name))
+ return;
+
+ fprintf(stderr, "No such resource: %s\n", resource_print);
+ exit (1);
+}
+
+static size_t
+get_kern_max_proc(void)
+{
+ int mib[] = { CTL_KERN, KERN_MAXPROC };
+ int max;
+ size_t max_sz = sizeof (max);
+
+ if (sysctl(mib, 2, &max, &max_sz, NULL, 0) < 0) {
+ perror("Failed to get max proc count");
+ exit (1);
+ }
+
+ return (max);
+}
+
+static int
+get_proc_kinfo(pid_t pid, struct kinfo_proc *kinfo)
+{
+ int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };
+ size_t len;
+
+ len = sizeof(struct kinfo_proc);
+ return (sysctl(mib, 4, kinfo, &len, NULL, 0) < 0);
+}
+
+static struct ledger *
+ledger_find(struct ledger_info *li)
+{
+ struct ledger *l;
+
+ for (l = ledgers; l && (li->li_id != l->id); l = l->next)
+ ;
+
+ if (l == NULL) {
+ l = (struct ledger *)malloc(sizeof (*l));
+ if (l == NULL) {
+ fprintf(stderr, "Out of memory");
+ exit (1);
+ }
+ l->id = li->li_id;
+ l->entries = li->li_entries;
+ l->next = ledgers;
+ l->seen = 0;
+ l->info = NULL;
+ l->old_info = NULL;
+ ledgers = l;
+ }
+ return (l);
+
+}
+
+static void
+ledger_update(pid_t pid, struct ledger *l)
+{
+ void *arg;
+ struct ledger_entry_info *lei;
+ int64_t cnt;
+
+ cnt = l->entries;
+ if (cnt > entry_cnt)
+ cnt = entry_cnt;
+ arg = (void *)(long)pid;
+ lei = (struct ledger_entry_info *)malloc((size_t)(cnt * sizeof (*lei)));
+ if (ledger(LEDGER_ENTRY_INFO, arg, (caddr_t)lei, (caddr_t)&cnt) < 0) {
+ perror("ledger_info() failed: ");
+ exit (1);
+ }
+ l->info = lei;
+}
+
+static void
+get_proc_info(int pid)
+{
+ struct ledger_info li;
+ struct ledger *ledgerp;
+ struct proc_list *proc;
+ struct kinfo_proc kinfo;
+ void *arg;
+
+ if (pid == 0)
+ return;
+
+ arg = (void *)(long)pid;
+ errno = 0;
+ if (ledger(LEDGER_INFO, arg, (caddr_t)&li, NULL) < 0) {
+
+ if (errno == ENOENT || errno == ESRCH)
+ return;
+
+ perror("ledger_info() failed: ");
+ exit (1);
+ }
+
+ ledgerp = ledger_find(&li);
+ ledger_update(pid, ledgerp);
+ ledgerp->seen = 1;
+
+ for (proc = procs; proc; proc = proc->next)
+ if (proc->pid == pid)
+ break;
+ if (proc == NULL) {
+ proc = (struct proc_list *)malloc(sizeof (*proc));
+ if (proc == NULL) {
+ fprintf(stderr, "Out of memory\n");
+ exit (1);
+ }
+
+ if (get_proc_kinfo(pid, &kinfo))
+ strlcpy(proc->command, "Error", sizeof (proc->command));
+ else
+ strlcpy(proc->command, kinfo.kp_proc.p_comm,
+ sizeof (proc->command));
+
+ proc->pid = pid;
+ proc->ledger = ledgerp;
+ proc->next = procs;
+ procs = proc;
+ }
+ proc->seen = 1;
+}
+
+static int
+pid_compare(const void *a, const void *b)
+{
+ pid_t *pid_a = (pid_t *)a;
+ pid_t *pid_b = (pid_t *)b;
+
+ return (*pid_b - *pid_a);
+}
+
+static void
+get_all_info()
+{
+ pid_t *pids;
+ int sz, cnt, i;
+
+ if (pid < 0)
+ cnt = (int) get_kern_max_proc();
+ else
+ cnt = 1;
+
+ sz = cnt * sizeof(pid_t);
+ pids = (pid_t *)malloc(sz);
+ if (pids == NULL) {
+ perror("can't allocate memory for proc buffer\n");
+ exit (1);
+ }
+
+ if (pid < 0) {
+ cnt = proc_listallpids(pids, sz);
+ if (cnt < 0) {
+ perror("failed to get list of active pids");
+ exit (1);
+ }
+ qsort(pids, cnt, sizeof (pid_t), pid_compare);
+ } else {
+ pids[0] = pid;
+ }
+
+ for (i = 0; i < cnt; i++)
+ get_proc_info(pids[i]);
+ free(pids);
+}
+
+static void
+print_num(int64_t num, int64_t delta)
+{
+ char suf = ' ';
+ char posneg = ' ';
+
+ if (num == LEDGER_LIMIT_INFINITY) {
+ printf("%10s ", "- ");
+ return;
+ }
+
+ if (llabs(num) > 10000000000) {
+ num /= 1000000000;
+ suf = 'G';
+ } else if (llabs(num) > 10000000) {
+ num /= 1000000;
+ suf = 'M';
+ } else if (llabs(num) > 100000) {
+ num /= 1000;
+ suf = 'K';
+ }
+ posneg = (delta < 0) ? '-' : ((delta > 0) ? '+' : ' ');
+
+ if (suf == ' ') {
+ suf = posneg;
+ posneg = ' ';
+ }
+ printf("%8lld%c%c ", num, suf, posneg);
+}
+
+static void
+dump_all_info()
+{
+ struct ledger_entry_info *info, *old;
+ struct proc_list *p;
+ int line, i;
+ int64_t d;
+
+ printf("\n%5s %10s %15s %10s %10s %10s %10s %10s\n", "PID", "COMMAND",
+ "RESOURCE", "CREDITS", "DEBITS", "BALANCE", "LIMIT", "PERIOD");
+
+ for (p = procs; p; p = p->next) {
+ if (p->seen == 0)
+ continue;
+
+ printf("%5d %10.10s ", p->pid, p->command);
+ line = 0;
+
+ info = p->ledger->info;
+ old = p->ledger->old_info;
+ for (i = 0; i < p->ledger->entries; i++) {
+ if (group_print &&
+ strcmp(group_print, template[i].lti_group))
+ continue;
+
+ if (resource_print &&
+ strcmp(resource_print, template[i].lti_name))
+ continue;
+
+ if (line++)
+ printf(" ");
+ printf("%15s ", template[i].lti_name);
+
+ d = old ? info[i].lei_credit - old[i].lei_credit : 0;
+ print_num(info[i].lei_credit, d);
+
+ d = old ? info[i].lei_debit - old[i].lei_debit : 0;
+ print_num(info[i].lei_debit, d);
+
+ d = old ? info[i].lei_balance - old[i].lei_balance : 0;
+ print_num(info[i].lei_balance, d);
+
+ if (info[i].lei_limit == LEDGER_LIMIT_INFINITY) {
+ printf("%10s %10s", "none", "- ");
+ } else {
+ print_num(info[i].lei_limit, 0);
+ print_num(info[i].lei_refill_period, 0);
+ }
+ printf("\n");
+ }
+ }
+
+ if (line == 0)
+ exit (0);
+}
+
+static void
+cleanup()
+{
+ struct proc_list *p, *pnext, *plast;
+ struct ledger *l, *lnext, *llast;
+
+ plast = NULL;
+ for (p = procs; p; p = pnext) {
+ pnext = p->next;
+ if (p->seen == 0) {
+ if (plast)
+ plast->next = pnext;
+ else
+ procs = pnext;
+
+ free(p);
+ } else {
+ p->seen = 0;
+ }
+ }
+
+ llast = NULL;
+ for (l = ledgers; l; l = lnext) {
+ lnext = l->next;
+ if (l->seen == 0) {
+ if (llast)
+ llast->next = lnext;
+ else
+ ledgers = lnext;
+ free(l->info);
+ if (l->old_info)
+ free(l->old_info);
+ free(l);
+ } else {
+ l->seen = 0;
+ free(l->old_info);
+ l->old_info = l->info;
+ l->info = NULL;
+ }
+ }
+
+ free(template);
+ template = NULL;
+}
+
+static void
+usage()
+{
+ printf("lprint [-hL] [-g group] [-p pid] [-r resource] [interval]\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ int interval = 0;
+
+ while ((c = getopt(argc, argv, "g:hLp:r:")) != -1) {
+ switch (c) {
+ case 'g':
+ group_print = optarg;
+ break;
+
+ case 'h':
+ usage();
+ exit(0);
+
+ case 'L':
+ get_template_info();
+ dump_template_info();
+ exit(0);
+
+ case 'p':
+ pid = atoi(optarg);
+ break;
+
+ case 'r':
+ resource_print = optarg;
+ break;
+
+ default:
+ usage();
+ exit(1);
+ }
+
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc)
+ interval = atoi(argv[0]);
+
+ if (group_print && resource_print) {
+ fprintf(stderr, "Cannot specify both a resource and a group\n");
+ exit (1);
+ }
+
+ if (group_print)
+ validate_group();
+ if (resource_print)
+ validate_resource();
+
+ do {
+ get_template_info();
+ get_all_info();
+ dump_all_info();
+ cleanup();
+ sleep(interval);
+ } while (interval);
+}
--- /dev/null
+.\" Copyright (c) 2013, Apple Inc. All rights reserved.
+.\"
+.Dd Mar 7, 2013
+.Dt MEMORY_PRESSURE 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm memory_pressure
+.Nd Tool to apply real or simulate memory pressure on the system.
+.Sh SYNOPSIS
+.Pp
+.Nm memory_pressure [-l level] | [-p percent_free] | [-S -l level]
+.Sh OPTIONS
+.Pp
+.Ar -l <level>
+Apply real or simulate memory pressure (if specified alongside simulate argument) on the system till low memory notifications corresponding to <level> are generated. Supported values are "warn" and "critical".
+.Pp
+.Ar -p <percent_free>
+Allocate memory till the available memory in the system is <percent_free> of total memory. If the percentage of available memory to total memory on the system drops, the tool will free memory till either the desired percentage is achieved or it runs out of memory to free.
+.Pp
+.Ar -S
+Simulate memory pressure on the system by placing it artificially for <sleep_seconds> duration at the "warn" or "critical" level.
+.Pp
+.Ar -s <sleep_seconds>
+Duration to wait before allocating or freeing memory if applying real pressure. In case of simulating memory pressure, this is the duration the system will be maintained at an artifical memory level.
+.Sh DESCRIPTION
+A tool to apply real or simulate memory pressure on the system
+.Sh SEE ALSO
+.Xr vm_stat 1
--- /dev/null
+/*
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <getopt.h>
+#include <string.h>
+#include <mach/i386/vm_param.h>
+#include <sys/kern_memorystatus.h>
+#include <sys/sysctl.h>
+#include <mach/mach.h>
+#include <mach/task.h>
+#include <mach/thread_act.h>
+#include <mach/thread_policy.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include <assert.h>
+#include <dispatch/private.h>
+
+unsigned long phys_mem = 0; /* amount of physical memory in bytes */
+unsigned int phys_pages = 0; /* number of physical memory pages */
+int sleep_seconds = 1;
+boolean_t quiet_mode_on = FALSE;
+boolean_t simulate_mode_on = FALSE;
+
+void *range_start_addr = NULL;
+void *range_end_addr = NULL;
+void *range_current_addr = NULL;
+
+int start_referencing_pages = 0;
+int start_allocing_pages = 0;
+pthread_cond_t reference_pages_condvar = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t reference_pages_mutex = PTHREAD_MUTEX_INITIALIZER;
+unsigned int desired_level = 0, desired_percent = 0;
+unsigned int percent_for_level = 0;
+int tool_mode = 0;
+
+#define TOOL_MODE_FOR_PERCENT 1
+#define TOOL_MODE_FOR_LEVEL 2
+
+
+char random_data[] = "ffd8ffe000104a46494600010101002400240000ffe100744578696600004d4d002a000000080004011a0005000000010000003e011b0005000000010000004601280003000000010002000087690004000000010000004e00000000000000240000000100000024000000010002a002000400000001000003c0a003000400000001000001ff00000000ffdb00430002020202020102020202020202030306040303030307050504060807080808070808090a0d0b09090c0a08080b0f0b0c0d0e0e0e0e090b10110f0e110d0e0e0effdb004301020202030303060404060e0908090e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0effc000110801ff03c003012200021101031101ffc4001f0000010501010101010100000000000000000102030405060708090a0bffc400b5100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9faffc4001f0100030101010101010101010000000000000102030405060708090a0bffc400b51100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00f9e74fbd37baa2db99e6506391f28371f9519ba67fd9fcabd46cbc1315de8d6776752d7419e049084b152a37283c1dfc8e6bc02db4af18d9df79c9e1bd59a40ae9b65b1761f32953c63ae09c7a1c57656fe24f8896da7c16c9e0bb3748a358d5a4d04b31006324f73c75a00935f7fec9f165ee98b7372e2ddc05795763f2a0f20138ebeb590bac3e70d2b6e1fed1ac6d4ecbc65aa6b973a85c7867528a6998168edec1a38c1c01c2f61c550fec1f16ff00d0bdade4f5ff00447ff0a00eaffb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe66b4f45fed1f1078bb4cd0f4bdf3ea37f7296f6d1ee3f33b1c0cfb7a9f4ae0bfb07c5bff42f6b7ff808ff00e15a9a1c5e3bf0f78c74bd774cd0f5a8751d3ee52e2ddcd9be03a9c8cfb7623d2803d5bc6fe0df11780e0d3ae354bab1bdb1bd678e1bab1b8f36312c6079b112380cac4ae3b9535e7ffdaedff3d5ff00335b3e3af177c4af1f5be9b6da8f8567d36c2c59e486d74fd35e28ccb260c92b003966605b3db71af3cfec1f16ff00d0bdadff00e023ff0085007acf83743d57c6baddd59e9d7062fb3c68d248519c0324ab120c2f3cb38c9ec013dab95b8d427b5bfb8b59a4759a195a3917278652411f98ad9f86fe30f88bf0cb57d56f348f095f5ebdfc2914ab716b200a118918c0ff0068d709a9d878cb55f12ea3aa4fe1cd6127bdba92e2455b47c06772c40e3a64d007d13f09fe1d37c41d135ad7b52d52ef4fd074eba86cff00d1537cd7171310123504e0751927d6be8ed17f65bf0aebde19b4d5ac7c5fe2236b700eddf12060558ab03ee1948fc2be41f84bf123e20fc2d1acd87fc20d77e24f0eeabb1af74cbcb4902974fbb22b0190c3fa0f4afa1748fdad3c51a1691fd9fa57c10b8b4b212bc8b0ac931542c7240c8e067271ef401e9bff000c89a07fd0dbafff00dfb4a3fe191340ff00a1b75fff00bf695c2ffc366f8e7fe88c5cff00df72ff00851ff0d9be39ff00a23173ff007dcbfe1401dd7fc322681ff436ebff00f7ed28ff008644d03fe86dd7ff00efda570bff000d9be39ffa23173ff7dcbfe147fc366f8e7fe88c5cff00df72ff008500775ff0c89a07fd0dbaff00fdfb4a3fe191340ffa1b75ff00fbf695c2ff00c366f8e7fe88c5cffdf72ff851ff000d9be39ffa23173ff7dcbfe1401dd7fc322681ff00436ebfff007ed2be52f8d1f0eeff00e11fc42b2d325d49f51d3afedccf637046d6215b6b2b0f5071f98af733fb6678eb071f062e73fefcbfe15f2a7c5af1cfc4bf8bff001262d7758f0bea76515bc1f67b1b1b7b490a4099c9edcb13c93f4a00fe891bc2fe1c672cda1e96589c92";
+
+#define PAGE_OP_ALLOC 0x1
+#define PAGE_OP_FREE 0x2
+
+#define USE_WIRED_PAGES_FOR_PERCENT_MODE FALSE
+
+#define MAX_RANGE_SIZE 64 * 1024 * 1024 * 1024ULL
+
+void print_vm_statistics(void);
+void munch_for_level(unsigned int, unsigned int);
+void munch_for_percentage(unsigned int, unsigned int, unsigned int);
+
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: memory_pressure [options] [<pages>]\n"
+ " Allocate memory and wait forever.\n"
+ " Options include:\n"
+ " -l <level> - allocate memory until a low memory notification is received (warn OR critical)\n"
+ " -p <percent-free> - allocate memory until percent free is this (or less)\n"
+ " -s <seconds> - how long to sleep between checking for a set percent level\n"
+ " -w <percent-free> - don't allocate, just wait until percent free is this then exit\n"
+ " -v <print VM stats> - print VM statistics every sampling interval\n"
+ " -Q <quiet mode> - reduces the tool's output\n"
+ " -S - simulate the system's memory pressure level without applying any real pressure\n"
+ " \n"
+ );
+ exit(0);
+}
+
+static unsigned int
+read_sysctl_int(const char* name)
+{
+ unsigned int var;
+ size_t var_size;
+ int error;
+
+ var_size = sizeof(var);
+ error = sysctlbyname(name, &var, &var_size, NULL, 0);
+ if( error ) {
+ perror(name);
+ exit(-1);
+ }
+ return var;
+}
+
+static int
+get_percent_free(unsigned int* level)
+{
+ int error;
+
+ error = memorystatus_get_level((user_addr_t) level);
+
+ if( error ) {
+ perror("memorystatus_get_level failed:");
+ exit(-1);
+ }
+ return error;
+}
+
+void
+print_vm_statistics(void)
+{
+ unsigned int count = HOST_VM_INFO64_COUNT;
+ kern_return_t ret = 0;
+ vm_statistics64_data_t vm_stat;;
+
+ if (quiet_mode_on == TRUE) {
+ return;
+ }
+
+ if ((ret = host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&vm_stat, &count) != KERN_SUCCESS)) {
+ fprintf(stderr, "Failed to get statistics. Error %d\n", ret);
+ } else {
+ printf("\nStats: \n");
+ printf("Pages free: %llu \n", (uint64_t) (vm_stat.free_count - vm_stat.speculative_count));
+ printf("Pages purgeable: %llu \n", (uint64_t) (vm_stat.purgeable_count));
+ printf("Pages purged: %llu \n",(uint64_t) (vm_stat.purges));
+
+ printf("\nSwap I/O:\n");
+ printf("Swapins: %llu \n", (uint64_t) (vm_stat.swapins));
+ printf("Swapouts: %llu \n", (uint64_t) (vm_stat.swapouts));
+
+ printf("\nPage Q counts:\n");
+ printf("Pages active: %llu \n", (uint64_t) (vm_stat.active_count));
+ printf("Pages inactive: %llu \n", (uint64_t) (vm_stat.inactive_count));
+ printf("Pages speculative: %llu \n", (uint64_t) (vm_stat.speculative_count));
+ printf("Pages throttled: %llu \n", (uint64_t) (vm_stat.throttled_count));
+ printf("Pages wired down: %llu \n", (uint64_t) (vm_stat.wire_count));
+
+ printf("\nCompressor Stats:\n");
+ printf("Pages used by compressor: %llu \n", (uint64_t) (vm_stat.compressor_page_count));
+ printf("Pages decompressed: %llu \n", (uint64_t) (vm_stat.decompressions));
+ printf("Pages compressed: %llu \n", (uint64_t) (vm_stat.compressions));
+
+ printf("\nFile I/O:\n");
+ printf("Pageins: %llu \n", (uint64_t) (vm_stat.pageins));
+ printf("Pageouts: %llu \n", (uint64_t) (vm_stat.pageouts));
+
+#if 0
+ printf("\"Translation faults\": %llu \n", (uint64_t) (vm_stat.faults));
+ printf("Pages copy-on-write: %llu \n", (uint64_t) (vm_stat.cow_faults));
+ printf("Pages zero filled: %llu \n", (uint64_t) (vm_stat.zero_fill_count));
+ printf("Pages reactivated: %llu \n", (uint64_t) (vm_stat.reactivations));
+#endif
+ printf("\n");
+ }
+}
+
+
+static int
+reached_or_bypassed_desired_result(void)
+{
+ if (tool_mode == TOOL_MODE_FOR_LEVEL) {
+
+ unsigned int current_level = 0;
+
+ current_level = read_sysctl_int("kern.memorystatus_vm_pressure_level");
+
+ if (desired_level > 0 && current_level >= desired_level) {
+ return 1;
+ }
+
+ return 0;
+ }
+
+ if (tool_mode == TOOL_MODE_FOR_PERCENT) {
+
+ unsigned int current_percent = 0;
+
+ get_percent_free(¤t_percent);
+
+ if (desired_percent > 0 && current_percent <= desired_percent) {
+ return 1;
+ }
+
+ return 0;
+ }
+
+ return 0;
+}
+
+static void
+reference_pages(int level)
+{
+ int error;
+ void *addr = NULL;
+ int num_pages = 0;
+
+ error = pthread_mutex_lock(&reference_pages_mutex);
+ addr = range_start_addr;
+again:
+ while(start_referencing_pages == 0) {
+ error = pthread_cond_wait(&reference_pages_condvar, &reference_pages_mutex);
+ }
+
+ start_allocing_pages = 0;
+ pthread_mutex_unlock(&reference_pages_mutex);
+
+ num_pages = 0;
+ for(; addr < range_current_addr;) {
+
+ char p;
+
+ if (reached_or_bypassed_desired_result()) {
+ //printf("stopped referencing after %d pages\n", num_pages);
+ break;
+ }
+
+ p = *(char*) addr;
+ addr += PAGE_SIZE;
+ num_pages++;
+
+ }
+
+ //if (num_pages) {
+ // printf("Referenced %d\n", num_pages);
+ //}
+ error = pthread_mutex_lock(&reference_pages_mutex);
+ start_referencing_pages = 0;
+ start_allocing_pages = 1;
+
+ goto again;
+
+}
+
+static void
+process_pages(int num_pages, int page_op)
+{
+ if (num_pages > 0) {
+
+ int error = 0, i = 0;
+ size_t size = num_pages * PAGE_SIZE;
+
+ if (page_op == PAGE_OP_ALLOC) {
+
+ if (tool_mode == TOOL_MODE_FOR_PERCENT && USE_WIRED_PAGES_FOR_PERCENT_MODE) {
+ error = mlock(range_current_addr, size);
+ if (error == -1) {
+ perror("Failed to lock memory!");
+ exit(-1);
+ }
+
+ memset(range_current_addr, 0xFF, size);
+ range_current_addr += size;
+
+ } else {
+
+ pthread_mutex_lock(&reference_pages_mutex);
+ while (start_allocing_pages == 0) {
+ pthread_mutex_unlock(&reference_pages_mutex);
+ sleep(1);
+ pthread_mutex_lock(&reference_pages_mutex);
+ }
+ pthread_mutex_unlock(&reference_pages_mutex);
+
+ for (i=0; i < num_pages; i++) {
+
+ if (reached_or_bypassed_desired_result()) {
+ //printf("stopped faulting after %d pages\n", i);
+ break;
+ }
+
+ memcpy(range_current_addr, random_data, PAGE_SIZE);
+ range_current_addr += PAGE_SIZE;
+ }
+
+ pthread_mutex_lock(&reference_pages_mutex);
+ start_referencing_pages = 1;
+ pthread_cond_signal(&reference_pages_condvar);
+ pthread_mutex_unlock(&reference_pages_mutex);
+ }
+ } else {
+ if (tool_mode == TOOL_MODE_FOR_PERCENT && USE_WIRED_PAGES_FOR_PERCENT_MODE) {
+ error = munlock(range_current_addr, size);
+ if (error == -1) {
+ perror("Failed to unlock memory!");
+ exit(-1);
+ }
+
+ error = madvise(range_current_addr, size, MADV_FREE);
+ if (error == -1) {
+ perror("Failed to madv_free memory!");
+ exit(-1);
+ }
+
+ range_current_addr -= size;
+
+ } else {
+ pthread_mutex_lock(&reference_pages_mutex);
+ while (start_referencing_pages == 1) {
+ pthread_mutex_unlock(&reference_pages_mutex);
+ sleep(1);
+ pthread_mutex_lock(&reference_pages_mutex);
+ }
+
+ error = madvise(range_current_addr, size, MADV_FREE);
+ if (error == -1) {
+ perror("Failed to madv_free memory!");
+ exit(-1);
+ }
+ range_current_addr -= size;
+ start_referencing_pages = 1;
+ pthread_cond_signal(&reference_pages_condvar);
+ pthread_mutex_unlock(&reference_pages_mutex);
+ }
+ }
+ }
+}
+
+void
+munch_for_level(unsigned int sleep_seconds, unsigned int print_vm_stats)
+{
+
+ unsigned int current_level = 0;
+ unsigned int desired_percent = 0;
+ unsigned int current_percent = 0;
+ unsigned int page_op = PAGE_OP_ALLOC;
+ unsigned int previous_page_op = PAGE_OP_ALLOC;
+ unsigned int pages_to_process = 0;
+ unsigned int stabilized_percentage = 0;
+ boolean_t print_vm_stats_on_page_processing = FALSE;
+ boolean_t ok_to_print_stablity_message = TRUE;
+
+ current_level = read_sysctl_int("kern.memorystatus_vm_pressure_level");
+
+ if (current_level >= desired_level) {
+ return;
+ }
+
+ get_percent_free(¤t_percent);
+
+ if (print_vm_stats) {
+ print_vm_stats_on_page_processing = TRUE;
+ }
+
+ page_op = PAGE_OP_ALLOC;
+ previous_page_op = 0;
+
+ while (1) {
+
+ if (current_percent > percent_for_level) {
+ desired_percent = current_percent - percent_for_level;
+ } else {
+ desired_percent = 1;
+ }
+
+ pages_to_process = (desired_percent * phys_pages) / 100;
+
+ page_op = PAGE_OP_ALLOC;
+
+ if (previous_page_op != page_op) {
+ //printf("%s %d pages.\n", (page_op == PAGE_OP_ALLOC) ? "Allocating" : "Freeing", pages_to_process);
+ printf("\nCMD: %s pages to go from level: %d to level: %d", (page_op == PAGE_OP_ALLOC) ? "Allocating" : "Freeing", current_level, desired_level);
+ previous_page_op = page_op;
+ fflush(stdout);
+ } else {
+ printf(".");
+ fflush(stdout);
+ }
+
+ if (print_vm_stats_on_page_processing == TRUE) {
+ print_vm_statistics();
+ }
+ process_pages(pages_to_process, page_op);
+ ok_to_print_stablity_message = TRUE;
+
+ current_level = read_sysctl_int("kern.memorystatus_vm_pressure_level");
+
+ if (current_level >= desired_level) {
+
+ while(1) {
+ current_level = read_sysctl_int("kern.memorystatus_vm_pressure_level");
+ if (current_level < desired_level) {
+ break;
+ }
+
+ if (current_level > desired_level) {
+ page_op = PAGE_OP_FREE;
+
+ get_percent_free(¤t_percent);
+
+ if (stabilized_percentage > current_percent) {
+ pages_to_process = ((stabilized_percentage - current_percent) * phys_pages) / 100;
+
+ if (previous_page_op != page_op) {
+ printf("\nCMD: %s pages to go from %d to %d level", (page_op == PAGE_OP_ALLOC) ? "Allocating" : "Freeing", current_level, desired_level);
+ previous_page_op = page_op;
+ fflush(stdout);
+ } else {
+ printf(".");
+ fflush(stdout);
+ }
+
+ if (print_vm_stats_on_page_processing == TRUE) {
+ print_vm_statistics();
+ }
+ process_pages(pages_to_process, page_op);
+ ok_to_print_stablity_message = TRUE;
+ }
+ }
+
+ while (current_level == desired_level) {
+ get_percent_free(¤t_percent);
+ if (ok_to_print_stablity_message == TRUE) {
+ print_vm_statistics();
+ printf("\nStabilizing at Percent: %d Level: %d", current_percent, current_level);
+ fflush(stdout);
+ ok_to_print_stablity_message = FALSE;
+ previous_page_op = 0;
+ } else {
+ printf(".");
+ fflush(stdout);
+ }
+
+ stabilized_percentage = current_percent;
+ sleep(sleep_seconds);
+ current_level = read_sysctl_int("kern.memorystatus_vm_pressure_level");
+ }
+ }
+ }
+
+ get_percent_free(¤t_percent);
+ //printf("Percent: %d Level: %d\n", current_percent, current_level);
+ sleep(1);
+
+ if (print_vm_stats) {
+ print_vm_stats_on_page_processing = TRUE;
+ }
+
+ } /* while */
+}
+
+void
+munch_for_percentage(unsigned int sleep_seconds, unsigned int wait_percent_free, unsigned int print_vm_stats)
+{
+
+ int total_pages_allocated = 0;
+ unsigned int current_percent = 0;
+ boolean_t page_op = PAGE_OP_FREE;
+ unsigned int pages_to_process = 0;
+ boolean_t print_vm_stats_on_page_processing = FALSE;
+ boolean_t previous_page_op = 0;
+ boolean_t ok_to_print_stablity_message = TRUE;
+
+ /* Allocate until memory level is hit. */
+
+ get_percent_free(¤t_percent);
+
+ /*
+ * "wait" mode doesn't alloc, it just waits and exits. This is used
+ * while waiting for *other* processes to allocate memory.
+ */
+ if (wait_percent_free) {
+ while (current_percent > wait_percent_free) {
+ sleep(sleep_seconds);
+ get_percent_free (¤t_percent);
+ }
+ return;
+ }
+
+ page_op = PAGE_OP_ALLOC;
+ previous_page_op = 0;
+
+ while (1) {
+
+ if (current_percent > desired_percent) {
+ pages_to_process = ((current_percent - desired_percent) * phys_pages) / 100;
+ page_op = PAGE_OP_ALLOC;
+ } else {
+ pages_to_process = ((desired_percent - current_percent) * phys_pages) / 100;
+ page_op = PAGE_OP_FREE;
+ }
+
+ if (pages_to_process > 0) {
+
+ if (page_op != previous_page_op) {
+ //printf("\n%s %d pages to go from %d%% to %d%% pages free\n", (page_op == PAGE_OP_ALLOC) ? "Allocating" : "Freeing", pages_to_process, current_percent, desired_percent);
+ printf("\nCMD: %s pages to go from %d%% to %d%% percent free", (page_op == PAGE_OP_ALLOC) ? "Allocating" : "Freeing", current_percent, desired_percent);
+ fflush(stdout);
+ previous_page_op = page_op;
+ } else {
+ printf(".");
+ fflush(stdout);
+ }
+
+ if (page_op == PAGE_OP_ALLOC) {
+ total_pages_allocated += pages_to_process;
+ process_pages(pages_to_process, page_op);
+ ok_to_print_stablity_message = TRUE;
+ } else {
+
+ if (total_pages_allocated >= pages_to_process) {
+ total_pages_allocated -= pages_to_process;
+ process_pages(pages_to_process, page_op);
+ ok_to_print_stablity_message = TRUE;
+ } else {
+ get_percent_free(¤t_percent);
+ if (ok_to_print_stablity_message == TRUE) {
+ printf("\nDesired Percent: %d, Current Percent: %d. No pages to free so waiting", desired_percent, current_percent);
+ fflush(stdout);
+ ok_to_print_stablity_message = FALSE;
+ }
+ }
+ }
+
+ //printf("kernel memorystatus: %d%% free, allocated %d pages total. Requested: %d\n", current_percent, total_pages_allocated, desired_percent);
+ if (print_vm_stats) {
+ print_vm_stats_on_page_processing = TRUE;
+ }
+ } else {
+ if (ok_to_print_stablity_message == TRUE) {
+ print_vm_statistics();
+ printf("\nStable at percent free: %d", current_percent);
+ fflush(stdout);
+ ok_to_print_stablity_message = FALSE;
+ } else {
+ printf(".");
+ fflush(stdout);
+ }
+ print_vm_stats_on_page_processing = FALSE;
+ }
+
+ if (print_vm_stats_on_page_processing) {
+
+ print_vm_statistics();
+
+ if (print_vm_stats_on_page_processing == TRUE) {
+ print_vm_stats_on_page_processing = FALSE;
+ }
+ }
+
+ sleep(sleep_seconds);
+
+ get_percent_free(¤t_percent);
+ } /* while */
+}
+
+int
+main(int argc, char * const argv[])
+{
+ int opt;
+ unsigned int wait_percent_free = 0;
+ unsigned int current_percent = 0;
+ unsigned int print_vm_stats = 0;
+ char level[10];
+
+ while ((opt = getopt(argc, argv, "hl:p:s:w:vQS")) != -1) {
+ switch (opt) {
+ case 'h':
+ usage();
+ break;
+ case 'l':
+ strlcpy(level, optarg, 9);
+
+ if (strncasecmp(level, "normal", 6) == 0) {
+ desired_level = DISPATCH_MEMORYSTATUS_PRESSURE_NORMAL;
+ percent_for_level = 90;
+ } else if (strncasecmp(level, "warn", 4) == 0) {
+ desired_level = DISPATCH_MEMORYSTATUS_PRESSURE_WARN;
+ percent_for_level = 60;
+
+ } else if (strncasecmp(level, "critical", 8) == 0) {
+ desired_level = DISPATCH_MEMORYSTATUS_PRESSURE_CRITICAL;
+ percent_for_level = 30;
+
+ } else {
+ printf("Incorrect level. Allowed \"normal\" or \"warn\" or \"critical\". Specified: %s\n", level);
+ exit(0);
+ }
+ break;
+ case 'p':
+ desired_percent = atoi(optarg);
+ break;
+ case 's':
+ sleep_seconds = atoi(optarg);
+ break;
+ case 'w':
+ wait_percent_free = atoi(optarg);
+ break;
+ case 'v':
+ print_vm_stats = 1;
+ break;
+ case 'Q':
+ quiet_mode_on = TRUE;
+ break;
+ case 'S':
+ simulate_mode_on = TRUE;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (simulate_mode_on == TRUE && desired_level == 0) {
+ printf("Expected level with -l along with \"simulated\" mode.\n");
+ return 0;
+ }
+
+ phys_mem = read_sysctl_int("hw.physmem");
+ phys_pages = (unsigned int) (phys_mem / PAGE_SIZE);
+
+ printf("The system has %ld (%d pages with a page size of %d).\n", phys_mem, phys_pages, PAGE_SIZE);
+
+ print_vm_statistics();
+
+ get_percent_free(¤t_percent);
+ printf("System-wide memory free percentage: %d%%\n", current_percent);
+
+ if (desired_percent == 0 && wait_percent_free == 0 && desired_level == 0) {
+ return 0;
+ }
+
+ if (simulate_mode_on == TRUE) {
+
+ /*
+ We use the sysctl "kern.memorypressure_manual_trigger" for this mode. Here's a blurb:
+
+ Supported behaviors when using the manual trigger tests.
+
+ #define TEST_LOW_MEMORY_TRIGGER_ONE 1 most suitable app is notified
+ #define TEST_LOW_MEMORY_TRIGGER_ALL 2 all apps are notified
+ #define TEST_PURGEABLE_TRIGGER_ONE 3
+ #define TEST_PURGEABLE_TRIGGER_ALL 4
+ #define TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ONE 5
+ #define TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL 6
+
+ So, for example, to simulate one app getting a poke when the "pressure" reaches critical levels: "sudo sysctl -w kern.memorypressure_manual_trigger = level"
+ where level is calculated as: ((TEST_LOW_MEMORY_TRIGGER_ONE << 16) | NOTE_MEMORYSTATUS_PRESSURE_CRITICAL), which will be "65540".
+
+ For this tool, currently, we only support the "TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL" options.
+ */
+
+#define TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL 6
+
+ unsigned int var = 0;
+ size_t var_size = 0;
+ int error = 0;
+
+ var_size = sizeof(var);
+
+ var = ((TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL << 16) | desired_level);
+
+ error = sysctlbyname("kern.memorypressure_manual_trigger", NULL, 0, &var, var_size);
+
+ if(error) {
+ perror("sysctl: kern.memorypressure_manual_trigger failed ");
+ exit(-1);
+ }
+
+ printf("Waiting %d seconds before resetting system state\n", sleep_seconds);
+
+ sleep(sleep_seconds);
+
+ var_size = sizeof(var);
+
+ var = ((TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL << 16) | DISPATCH_MEMORYSTATUS_PRESSURE_NORMAL);
+
+ error = sysctlbyname("kern.memorypressure_manual_trigger", NULL, 0, &var, var_size);
+
+ if(error) {
+ perror("sysctl: kern.memorypressure_manual_trigger failed ");
+ exit(-1);
+ }
+
+ printf("Reset system state\n");
+
+ } else {
+ range_start_addr = mmap(NULL, MAX_RANGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, 0);
+
+ if (range_start_addr == MAP_FAILED) {
+ perror("mmap failed");
+ } else {
+
+ int error = 0;
+ pthread_t thread = NULL;
+
+ error = pthread_create(&thread, NULL, (void*) reference_pages, NULL);
+
+ range_current_addr = range_start_addr;
+ range_end_addr = range_start_addr + MAX_RANGE_SIZE;
+ start_allocing_pages = 1;
+
+ if (desired_level) {
+ tool_mode = TOOL_MODE_FOR_LEVEL;
+ munch_for_level(sleep_seconds, print_vm_stats);
+ } else {
+ tool_mode = TOOL_MODE_FOR_PERCENT;
+ munch_for_percentage(sleep_seconds, wait_percent_free, print_vm_stats);
+ }
+ }
+ }
+
+ return 0;
+}
#ifndef __APPLE__
#include <login_cap.h>
#endif /* !__APPLE__ */
+#ifdef __APPLE__
+#include <membership.h>
+#endif /* __APPLE__ */
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
.B -d
.IR name
] [
+.B -c
+] [
.IR name
[=
.IR value
.B \-f
options, since arguments are processed in order.
.TP
+.B \-c
+Delete all of the firmware variables.
+.TP
.B \-p
Print all of the firmware variables.
.SH EXAMPLES
/*
- * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2012 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
{
warnx("(usage: %s)", message);
- printf("%s [-x] [-p] [-f filename] [-d name] name[=value] ...\n", gToolName);
+ printf("%s [-x] [-p] [-f filename] [-d name] [-c] name[=value] ...\n", gToolName);
printf("\t-x use XML format for printing or reading variables\n");
printf("\t (must appear before -p or -f)\n");
printf("\t-p print all firmware variables\n");
--- /dev/null
+.Dd September 20, 2005
+.Dt purge 8
+.Sh NAME
+.Nm purge
+.Nd force disk cache to be purged (flushed and emptied)
+.Sh SYNOPSIS
+.Nm purge
+.Sh DESCRIPTION
+.Nm Purge
+can be used to approximate initial boot conditions with a cold disk buffer cache for performance analysis. It does not affect anonymous memory that has been allocated through malloc, vm_allocate, etc.
+.Pp
+.Sh SEE ALSO
+.Xr sync 8 ,
+.Xr malloc 3
--- /dev/null
+/*
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <stdio.h>
+
+int
+main(int argc, char **argv)
+{
+ int rv = syscall(SYS_vfs_purge);
+
+ if (rv) {
+ perror("Unable to purge disk buffers");
+
+ return 1;
+ }
+
+ return 0;
+}
#include <mach/mach_port.h> // allocate
#include <mach/mach.h> // task_self, etc
#include <servers/bootstrap.h> // bootstrap
+#include <bootstrap_priv.h>
#include <reboot2.h>
#include <utmpx.h>
#include <sys/time.h>
{
struct utmpx utx;
bzero(&utx, sizeof(utx));
- utx.ut_type = BOOT_TIME;
+ utx.ut_type = SHUTDOWN_TIME;
gettimeofday(&utx.ut_tv, NULL);
pututxline(&utx);
int busyStatus = ELAST + 1;
mountpoint_t busyVol;
- macherr = bootstrap_look_up(bootstrap_port, KEXTD_SERVER_NAME, &kxport);
+ macherr = bootstrap_look_up2(bootstrap_port, KEXTD_SERVER_NAME, &kxport, 0, BOOTSTRAP_PRIVILEGED_SERVER);
if (macherr) goto finish;
// allocate a port to pass to kextd (in case we die)
#include <mach/mach_port.h> // allocate
#include <mach/mach.h> // task_self, etc
#include <servers/bootstrap.h> // bootstrap
+#include <bootstrap_priv.h>
#include <reboot2.h>
#include <utmpx.h>
#include <sys/sysctl.h>
int busyStatus = ELAST + 1;
mountpoint_t busyVol;
- macherr = bootstrap_look_up(bootstrap_port, KEXTD_SERVER_NAME, &kxport);
+ macherr = bootstrap_look_up2(bootstrap_port, KEXTD_SERVER_NAME, &kxport, 0, BOOTSTRAP_PRIVILEGED_SERVER);
if (macherr) goto finish;
// allocate a port to pass to kextd (in case we die)
buildPhases = (
);
dependencies = (
+ ADA9007E1767A31300161ADF /* PBXTargetDependency */,
+ C625B29116D6F38700168EF7 /* PBXTargetDependency */,
+ B3F0E6DF16E97142008FAD09 /* PBXTargetDependency */,
+ 55CCB17816B851E900B56979 /* PBXTargetDependency */,
+ C96F50BA15BDFDA7008682F7 /* PBXTargetDependency */,
+ 1523FE6F1595069900661E82 /* PBXTargetDependency */,
BA0A861A1396B41F00D2272C /* PBXTargetDependency */,
BA0A861613968ECA00D2272C /* PBXTargetDependency */,
BA959E8813968D8A00CA9C60 /* PBXTargetDependency */,
BA7248051397C1350008497A /* ShellScript */,
BA959E8113968C8E00CA9C60 /* ShellScript */,
BA28FB881396DA67004986CB /* CopyFiles */,
- BA28FB8A1396DA8E004986CB /* CopyFiles */,
+ FD0AA4911630C39500606589 /* ShellScript */,
);
dependencies = (
);
buildPhases = (
);
dependencies = (
+ ADA900801767A31900161ADF /* PBXTargetDependency */,
+ C625B29316D6F39000168EF7 /* PBXTargetDependency */,
+ 55CCB17A16B851F300B56979 /* PBXTargetDependency */,
+ C96F50BC15BDFDB1008682F7 /* PBXTargetDependency */,
+ 1523FE711595069F00661E82 /* PBXTargetDependency */,
BA0A861C1396B42600D2272C /* PBXTargetDependency */,
BA0A861813968ED500D2272C /* PBXTargetDependency */,
BA959E9213968DA900CA9C60 /* PBXTargetDependency */,
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
+ 1523FE6C1595056C00661E82 /* ltop.c in Sources */ = {isa = PBXBuildFile; fileRef = 1523FE6B1595056C00661E82 /* ltop.c */; };
+ 1523FE6D1595058100661E82 /* ltop.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1523FE6A1595056C00661E82 /* ltop.1 */; };
+ 55CCB16E16B84EDA00B56979 /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ 55CCB17416B84EF800B56979 /* vm_purgeable_stat.c in Sources */ = {isa = PBXBuildFile; fileRef = 55CCB16916B84ED100B56979 /* vm_purgeable_stat.c */; };
+ 55CCB17616B84F3600B56979 /* vm_purgeable_stat.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 55CCB16816B84ED100B56979 /* vm_purgeable_stat.1 */; };
+ ADA9007B1767A02D00161ADF /* purge.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = ADA900791767A02700161ADF /* purge.8 */; };
+ ADA9007C1767A03200161ADF /* purge.c in Sources */ = {isa = PBXBuildFile; fileRef = ADA9007A1767A02700161ADF /* purge.c */; };
+ B3C10B9416E9876F006896A0 /* memory_pressure.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = B3C10B9316E983D4006896A0 /* memory_pressure.1 */; };
+ B3F0E6D016E96FC2008FAD09 /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ B3F0E6DD16E9706E008FAD09 /* memory_pressure.c in Sources */ = {isa = PBXBuildFile; fileRef = B3F0E6DC16E9706E008FAD09 /* memory_pressure.c */; };
BA0A860B13968E8500D2272C /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
BA0A861313968EAD00D2272C /* zprint.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2E61372FAFA0025925C /* zprint.c */; };
BA0A861413968EB100D2272C /* zprint.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2E51372FAFA0025925C /* zprint.1 */; };
BA28FB891396DA8A004986CB /* private in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA28FB851396DA01004986CB /* private */; };
- BA28FB8B1396DAA3004986CB /* zoneinfo in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA28FB861396DA01004986CB /* zoneinfo */; };
- BA4B79BC1373A51300003422 /* dirhelper.defs in Sources */ = {isa = PBXBuildFile; fileRef = BA4B79AA1373A49400003422 /* dirhelper.defs */; settings = {ATTRIBUTES = (Server, Client, ); }; };
+ BA4B79BC1373A51300003422 /* dirhelper.defs in Sources */ = {isa = PBXBuildFile; fileRef = BA4B79AA1373A49400003422 /* dirhelper.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; };
BA4B79BD1373A51E00003422 /* dirhelper.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD21D1372FAFA0025925C /* dirhelper.c */; };
BA4B79C01373A53700003422 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B79BF1373A53700003422 /* libbsm.dylib */; };
BA4B79C11373A55000003422 /* dirhelper.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD21C1372FAFA0025925C /* dirhelper.8 */; };
BA4FD325137301200025925C /* arch.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1E51372FAFA0025925C /* arch.c */; };
BA4FD3261373012C0025925C /* arch.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD1E41372FAFA0025925C /* arch.1 */; };
BA4FD3271373012F0025925C /* machine.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD1E71372FAFA0025925C /* machine.1 */; };
- BA4FD32D137304C70025925C /* arch_helper.pl in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD1E61372FAFA0025925C /* arch_helper.pl */; };
BA4FD343137307580025925C /* at.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD1EB1372FAFA0025925C /* at.1 */; };
BA4FD344137307750025925C /* at.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1EC1372FAFA0025925C /* at.c */; };
BA4FD345137307750025925C /* panic.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1EE1372FAFA0025925C /* panic.c */; };
BAE58A50137D69DA0049DD3B /* sc_usage.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2AF1372FAFA0025925C /* sc_usage.c */; };
BAE58A51137D69E30049DD3B /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A9313765F8B00003422 /* libncurses.dylib */; };
BAE58A52137D69ED0049DD3B /* sc_usage.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2AE1372FAFA0025925C /* sc_usage.1 */; };
+ C625B28B16D6F27E00168EF7 /* taskpolicy.c in Sources */ = {isa = PBXBuildFile; fileRef = C625B28A16D6F27E00168EF7 /* taskpolicy.c */; };
+ C625B28D16D6F27E00168EF7 /* taskpolicy.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C625B28C16D6F27E00168EF7 /* taskpolicy.8 */; };
C65BF57A144BD7C5009028A3 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766D13739D27001BB39F /* CoreFoundation.framework */; };
+ C96F50B215BDCEC3008682F7 /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ C96F50BD15BDFEFB008682F7 /* lsmp.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C96F50AC15BDCBF0008682F7 /* lsmp.1 */; };
+ C96F50BE15BDFF03008682F7 /* lsmp.c in Sources */ = {isa = PBXBuildFile; fileRef = C96F50AD15BDCE8E008682F7 /* lsmp.c */; };
+ C9779F6E159A2A0C009436FD /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
+ 1523FE6E1595069900661E82 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 1523FE5A1595048900661E82;
+ remoteInfo = ltop;
+ };
+ 1523FE701595069F00661E82 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 1523FE5A1595048900661E82;
+ remoteInfo = ltop;
+ };
+ 55CCB17716B851E900B56979 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 55CCB16A16B84EDA00B56979;
+ remoteInfo = vm_purgeable_stat;
+ };
+ 55CCB17916B851F300B56979 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 55CCB16A16B84EDA00B56979;
+ remoteInfo = vm_purgeable_stat;
+ };
+ ADA9007D1767A31300161ADF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = ADA9006F17679A8C00161ADF;
+ remoteInfo = purge;
+ };
+ ADA9007F1767A31900161ADF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = ADA9006F17679A8C00161ADF;
+ remoteInfo = purge;
+ };
+ B3F0E6DE16E97142008FAD09 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = B3F0E6CC16E96FC2008FAD09;
+ remoteInfo = memory_pressure;
+ };
BA0A861513968ECA00D2272C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
remoteGlobalIDString = BAE58A45137D69A60049DD3B;
remoteInfo = sc_usage;
};
+ C625B29016D6F38700168EF7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C625B28716D6F27E00168EF7;
+ remoteInfo = taskpolicy;
+ };
+ C625B29216D6F39000168EF7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C625B28716D6F27E00168EF7;
+ remoteInfo = taskpolicy;
+ };
+ C96F50B915BDFDA7008682F7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C96F50AE15BDCEC3008682F7;
+ remoteInfo = lsmp;
+ };
+ C96F50BB15BDFDB1008682F7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C96F50AE15BDCEC3008682F7;
+ remoteInfo = lsmp;
+ };
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
- BA0A860C13968E8500D2272C /* CopyFiles */ = {
+ 1523FE5F1595048900661E82 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/local/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 1523FE6D1595058100661E82 /* ltop.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 55CCB16F16B84EDA00B56979 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/local/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 55CCB17616B84F3600B56979 /* vm_purgeable_stat.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ ADA9007317679A8C00161ADF /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ ADA9007B1767A02D00161ADF /* purge.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ B3F0E6D116E96FC2008FAD09 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1;
dstSubfolderSpec = 0;
files = (
- BA0A861413968EB100D2272C /* zprint.1 in CopyFiles */,
+ B3C10B9416E9876F006896A0 /* memory_pressure.1 in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 1;
};
- BA28FB881396DA67004986CB /* CopyFiles */ = {
+ BA0A860C13968E8500D2272C /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
- buildActionMask = 8;
- dstPath = /;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
dstSubfolderSpec = 0;
files = (
- BA28FB891396DA8A004986CB /* private in CopyFiles */,
+ BA0A861413968EB100D2272C /* zprint.1 in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 1;
};
- BA28FB8A1396DA8E004986CB /* CopyFiles */ = {
+ BA28FB881396DA67004986CB /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
- dstPath = /usr/share;
+ dstPath = /;
dstSubfolderSpec = 0;
files = (
- BA28FB8B1396DAA3004986CB /* zoneinfo in CopyFiles */,
+ BA28FB891396DA8A004986CB /* private in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 1;
};
);
runOnlyForDeploymentPostprocessing = 1;
};
- BA4FD32C137304B50025925C /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 8;
- dstPath = /AppleInternal/Developer/Tools;
- dstSubfolderSpec = 0;
- files = (
- BA4FD32D137304C70025925C /* arch_helper.pl in CopyFiles */,
- );
- runOnlyForDeploymentPostprocessing = 1;
- };
BA4FD33C1373073E0025925C /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
);
runOnlyForDeploymentPostprocessing = 1;
};
+ C625B28616D6F27E00168EF7 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ C625B28D16D6F27E00168EF7 /* taskpolicy.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ C96F50B315BDCEC3008682F7 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/local/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ C96F50BD15BDFEFB008682F7 /* lsmp.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 1523FE631595048900661E82 /* ltop */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ltop; sourceTree = BUILT_PRODUCTS_DIR; };
+ 1523FE6A1595056C00661E82 /* ltop.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = ltop.1; sourceTree = "<group>"; };
+ 1523FE6B1595056C00661E82 /* ltop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ltop.c; sourceTree = "<group>"; };
+ 55CCB16816B84ED100B56979 /* vm_purgeable_stat.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = vm_purgeable_stat.1; sourceTree = "<group>"; };
+ 55CCB16916B84ED100B56979 /* vm_purgeable_stat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vm_purgeable_stat.c; sourceTree = "<group>"; };
+ 55CCB17316B84EDA00B56979 /* vm_purgeable_stat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = vm_purgeable_stat; sourceTree = BUILT_PRODUCTS_DIR; };
+ ADA9007717679A8C00161ADF /* purge */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = purge; sourceTree = BUILT_PRODUCTS_DIR; };
+ ADA900791767A02700161ADF /* purge.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = purge.8; sourceTree = "<group>"; };
+ ADA9007A1767A02700161ADF /* purge.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = purge.c; sourceTree = "<group>"; };
+ B3C10B9316E983D4006896A0 /* memory_pressure.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = memory_pressure.1; sourceTree = "<group>"; };
+ B3F0E6D516E96FC2008FAD09 /* memory_pressure */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = memory_pressure; sourceTree = BUILT_PRODUCTS_DIR; };
+ B3F0E6DC16E9706E008FAD09 /* memory_pressure.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = memory_pressure.c; sourceTree = "<group>"; };
BA0A861013968E8500D2272C /* zprint */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = zprint; sourceTree = BUILT_PRODUCTS_DIR; };
BA28FB851396DA01004986CB /* private */ = {isa = PBXFileReference; lastKnownFileType = folder; path = private; sourceTree = BUILT_PRODUCTS_DIR; };
BA28FB861396DA01004986CB /* zoneinfo */ = {isa = PBXFileReference; lastKnownFileType = folder; path = zoneinfo; sourceTree = BUILT_PRODUCTS_DIR; };
BA473DB31377B2230005CC19 /* login */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = login; sourceTree = BUILT_PRODUCTS_DIR; };
- BA4B79AA1373A49400003422 /* dirhelper.defs */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.mig; name = dirhelper.defs; path = ../../../../../../usr/local/include/dirhelper.defs; sourceTree = SDKROOT; };
+ BA4B79AA1373A49400003422 /* dirhelper.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; name = dirhelper.defs; path = usr/local/include/dirhelper.defs; sourceTree = SDKROOT; };
BA4B79BA1373A4E500003422 /* dirhelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dirhelper; sourceTree = BUILT_PRODUCTS_DIR; };
BA4B79BF1373A53700003422 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = /usr/lib/libbsm.dylib; sourceTree = "<absolute>"; };
BA4B79CD1373A72800003422 /* dmesg */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dmesg; sourceTree = BUILT_PRODUCTS_DIR; };
BA4FD1E11372FAFA0025925C /* APPLE_LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = APPLE_LICENSE; sourceTree = "<group>"; };
BA4FD1E41372FAFA0025925C /* arch.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = arch.1; sourceTree = "<group>"; };
BA4FD1E51372FAFA0025925C /* arch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = arch.c; sourceTree = "<group>"; };
- BA4FD1E61372FAFA0025925C /* arch_helper.pl */ = {isa = PBXFileReference; lastKnownFileType = text.script.perl; path = arch_helper.pl; sourceTree = "<group>"; };
BA4FD1E71372FAFA0025925C /* machine.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = machine.1; sourceTree = "<group>"; };
BA4FD1E91372FAFA0025925C /* LEGAL */ = {isa = PBXFileReference; lastKnownFileType = text; path = LEGAL; sourceTree = "<group>"; };
BA4FD1EB1372FAFA0025925C /* at.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = at.1; sourceTree = "<group>"; };
BAE58A2513799FFA0049DD3B /* sadc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sadc; sourceTree = BUILT_PRODUCTS_DIR; };
BAE58A3D1379A3F60049DD3B /* sar */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sar; sourceTree = BUILT_PRODUCTS_DIR; };
BAE58A4E137D69A60049DD3B /* sc_usage */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sc_usage; sourceTree = BUILT_PRODUCTS_DIR; };
+ C625B28816D6F27E00168EF7 /* taskpolicy */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = taskpolicy; sourceTree = BUILT_PRODUCTS_DIR; };
+ C625B28A16D6F27E00168EF7 /* taskpolicy.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = taskpolicy.c; sourceTree = "<group>"; };
+ C625B28C16D6F27E00168EF7 /* taskpolicy.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = taskpolicy.8; sourceTree = "<group>"; };
+ C96F50AC15BDCBF0008682F7 /* lsmp.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = lsmp.1; path = lsmp.tproj/lsmp.1; sourceTree = SOURCE_ROOT; };
+ C96F50AD15BDCE8E008682F7 /* lsmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lsmp.c; path = lsmp.tproj/lsmp.c; sourceTree = SOURCE_ROOT; };
+ C96F50B715BDCEC3008682F7 /* lsmp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lsmp; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
+ 1523FE5D1595048900661E82 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C9779F6E159A2A0C009436FD /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 55CCB16D16B84EDA00B56979 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 55CCB16E16B84EDA00B56979 /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ ADA9007217679A8C00161ADF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B3F0E6CF16E96FC2008FAD09 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B3F0E6D016E96FC2008FAD09 /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
BA0A860A13968E8500D2272C /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C625B28516D6F27E00168EF7 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C96F50B115BDCEC3008682F7 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C96F50B215BDCEC3008682F7 /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 1523FE691595056C00661E82 /* ltop.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 1523FE6A1595056C00661E82 /* ltop.1 */,
+ 1523FE6B1595056C00661E82 /* ltop.c */,
+ );
+ path = ltop.tproj;
+ sourceTree = "<group>";
+ };
+ 55CCB16716B84ED100B56979 /* vm_purgeable_stat.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 55CCB16816B84ED100B56979 /* vm_purgeable_stat.1 */,
+ 55CCB16916B84ED100B56979 /* vm_purgeable_stat.c */,
+ );
+ path = vm_purgeable_stat.tproj;
+ sourceTree = "<group>";
+ };
+ ADA900781767A02700161ADF /* purge.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ ADA900791767A02700161ADF /* purge.8 */,
+ ADA9007A1767A02700161ADF /* purge.c */,
+ );
+ path = purge.tproj;
+ sourceTree = "<group>";
+ };
+ B3F0E6DA16E9706E008FAD09 /* memory_pressure.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ B3C10B9316E983D4006896A0 /* memory_pressure.1 */,
+ B3F0E6DC16E9706E008FAD09 /* memory_pressure.c */,
+ );
+ path = memory_pressure.tproj;
+ sourceTree = "<group>";
+ };
BA0A86491396D3CE00D2272C /* Generated zoneinfo Files */ = {
isa = PBXGroup;
children = (
BA2DE9161372FA9100D1913C = {
isa = PBXGroup;
children = (
+ ADA900781767A02700161ADF /* purge.tproj */,
+ B3F0E6DA16E9706E008FAD09 /* memory_pressure.tproj */,
+ 55CCB16716B84ED100B56979 /* vm_purgeable_stat.tproj */,
+ C96F50AA15BDCBA2008682F7 /* lsmp.tproj */,
BA4FD1E11372FAFA0025925C /* APPLE_LICENSE */,
BA4FD2FB1372FB710025925C /* BSD.xcconfig */,
BA4FD1D91372FAFA0025925C /* ac.tproj */,
BA4FD24F1372FAFA0025925C /* iostat.tproj */,
BA4FD2551372FAFA0025925C /* latency.tproj */,
BA4FD2591372FAFA0025925C /* login.tproj */,
+ 1523FE691595056C00661E82 /* ltop.tproj */,
BA4FD2651372FAFA0025925C /* makekey.tproj */,
BA4FD2691372FAFA0025925C /* mean.tproj */,
BA4FD26C1372FAFA0025925C /* mkfile.tproj */,
BA4FD2D51372FAFA0025925C /* zic.tproj */,
BA4FD2E31372FAFA0025925C /* zprint.tproj */,
BA4B7A0D1373BBB600003422 /* Libraries */,
+ C625B28916D6F27E00168EF7 /* taskpolicy.tproj */,
BA4FD2F01372FB3D0025925C /* Products */,
);
sourceTree = "<group>";
children = (
BA4FD1E41372FAFA0025925C /* arch.1 */,
BA4FD1E51372FAFA0025925C /* arch.c */,
- BA4FD1E61372FAFA0025925C /* arch_helper.pl */,
BA4FD1E71372FAFA0025925C /* machine.1 */,
);
path = arch.tproj;
BA9BF4EB139683EB0018C7BB /* zdump */,
BA9BF4F7139684B40018C7BB /* zic */,
BA0A861013968E8500D2272C /* zprint */,
+ 1523FE631595048900661E82 /* ltop */,
+ C96F50B715BDCEC3008682F7 /* lsmp */,
+ 55CCB17316B84EDA00B56979 /* vm_purgeable_stat */,
+ C625B28816D6F27E00168EF7 /* taskpolicy */,
+ B3F0E6D516E96FC2008FAD09 /* memory_pressure */,
+ ADA9007717679A8C00161ADF /* purge */,
);
name = Products;
sourceTree = "<group>";
};
+ C625B28916D6F27E00168EF7 /* taskpolicy.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ C625B28A16D6F27E00168EF7 /* taskpolicy.c */,
+ C625B28C16D6F27E00168EF7 /* taskpolicy.8 */,
+ );
+ path = taskpolicy.tproj;
+ sourceTree = "<group>";
+ };
+ C96F50AA15BDCBA2008682F7 /* lsmp.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ C96F50AC15BDCBF0008682F7 /* lsmp.1 */,
+ C96F50AD15BDCE8E008682F7 /* lsmp.c */,
+ );
+ name = lsmp.tproj;
+ path = ac.tproj;
+ sourceTree = "<group>";
+ };
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
+ 1523FE5A1595048900661E82 /* ltop */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1523FE611595048900661E82 /* Build configuration list for PBXNativeTarget "ltop" */;
+ buildPhases = (
+ 1523FE5B1595048900661E82 /* Sources */,
+ 1523FE5D1595048900661E82 /* Frameworks */,
+ 1523FE5F1595048900661E82 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ltop;
+ productName = ac;
+ productReference = 1523FE631595048900661E82 /* ltop */;
+ productType = "com.apple.product-type.tool";
+ };
+ 55CCB16A16B84EDA00B56979 /* vm_purgeable_stat */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 55CCB17116B84EDA00B56979 /* Build configuration list for PBXNativeTarget "vm_purgeable_stat" */;
+ buildPhases = (
+ 55CCB16B16B84EDA00B56979 /* Sources */,
+ 55CCB16D16B84EDA00B56979 /* Frameworks */,
+ 55CCB16F16B84EDA00B56979 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = vm_purgeable_stat;
+ productName = ac;
+ productReference = 55CCB17316B84EDA00B56979 /* vm_purgeable_stat */;
+ productType = "com.apple.product-type.tool";
+ };
+ ADA9006F17679A8C00161ADF /* purge */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = ADA9007517679A8C00161ADF /* Build configuration list for PBXNativeTarget "purge" */;
+ buildPhases = (
+ ADA9007017679A8C00161ADF /* Sources */,
+ ADA9007217679A8C00161ADF /* Frameworks */,
+ ADA9007317679A8C00161ADF /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = purge;
+ productName = purge;
+ productReference = ADA9007717679A8C00161ADF /* purge */;
+ productType = "com.apple.product-type.tool";
+ };
+ B3F0E6CC16E96FC2008FAD09 /* memory_pressure */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = B3F0E6D316E96FC2008FAD09 /* Build configuration list for PBXNativeTarget "memory_pressure" */;
+ buildPhases = (
+ B3F0E6CD16E96FC2008FAD09 /* Sources */,
+ B3F0E6CF16E96FC2008FAD09 /* Frameworks */,
+ B3F0E6D116E96FC2008FAD09 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = memory_pressure;
+ productName = ac;
+ productReference = B3F0E6D516E96FC2008FAD09 /* memory_pressure */;
+ productType = "com.apple.product-type.tool";
+ };
BA0A860713968E8500D2272C /* zprint */ = {
isa = PBXNativeTarget;
buildConfigurationList = BA0A860E13968E8500D2272C /* Build configuration list for PBXNativeTarget "zprint" */;
BA4FD31B137300ED0025925C /* Sources */,
BA4FD31D137300ED0025925C /* Frameworks */,
BA4FD31E137300ED0025925C /* CopyFiles */,
- BA4FD32C137304B50025925C /* CopyFiles */,
);
buildRules = (
);
productReference = BAE58A4E137D69A60049DD3B /* sc_usage */;
productType = "com.apple.product-type.tool";
};
+ C625B28716D6F27E00168EF7 /* taskpolicy */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C625B28F16D6F27E00168EF7 /* Build configuration list for PBXNativeTarget "taskpolicy" */;
+ buildPhases = (
+ C625B28416D6F27E00168EF7 /* Sources */,
+ C625B28516D6F27E00168EF7 /* Frameworks */,
+ C625B28616D6F27E00168EF7 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = taskpolicy;
+ productName = taskpolicy;
+ productReference = C625B28816D6F27E00168EF7 /* taskpolicy */;
+ productType = "com.apple.product-type.tool";
+ };
+ C96F50AE15BDCEC3008682F7 /* lsmp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C96F50B515BDCEC3008682F7 /* Build configuration list for PBXNativeTarget "lsmp" */;
+ buildPhases = (
+ C96F50AF15BDCEC3008682F7 /* Sources */,
+ C96F50B115BDCEC3008682F7 /* Frameworks */,
+ C96F50B315BDCEC3008682F7 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = lsmp;
+ productName = ac;
+ productReference = C96F50B715BDCEC3008682F7 /* lsmp */;
+ productType = "com.apple.product-type.tool";
+ };
/* End PBXNativeTarget section */
/* Begin PBXProject section */
BA4B7A6913765D3E00003422 /* iostat */,
BA4B7A7D13765F3C00003422 /* latency */,
BA473DA01377B2230005CC19 /* login */,
+ 1523FE5A1595048900661E82 /* ltop */,
BACC1D011377B3E6007728F4 /* makekey */,
BACC1D0D1377B481007728F4 /* mean */,
BACC1D3D1377B6E2007728F4 /* mkfile */,
BA9BF4EF139684B40018C7BB /* zic */,
BA959E7E13968C8E00CA9C60 /* zoneinfo */,
BA0A860713968E8500D2272C /* zprint */,
+ C96F50AE15BDCEC3008682F7 /* lsmp */,
+ 55CCB16A16B84EDA00B56979 /* vm_purgeable_stat */,
+ C625B28716D6F27E00168EF7 /* taskpolicy */,
+ B3F0E6CC16E96FC2008FAD09 /* memory_pressure */,
+ ADA9006F17679A8C00161ADF /* purge */,
);
};
/* End PBXProject section */
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
- shellScript = "set -x\nset -e\n\nmkdir -p \"${DSTROOT}/usr/local/include/mach\"\n\nxcrun -sdk \"${SDKROOT}\" mig ${OTHER_MIGFLAGS} -arch ${CURRENT_ARCH} -user /dev/null -header \"${DSTROOT}/usr/local/include/mach/backing_store_triggers.h\" -server /dev/null -sheader /dev/null \"${SRCROOT}/dynamic_pager.tproj/backing_store_triggers.defs\"\n\nxcrun -sdk \"${SDKROOT}\" mig ${OTHER_MIGFLAGS} -arch ${CURRENT_ARCH} -user /dev/null -header /dev/null -server /dev/null -sheader \"${DSTROOT}/usr/local/include/mach/backing_store_alerts_server.h\" \"${SRCROOT}/dynamic_pager.tproj/backing_store_alerts.defs\"\n\n";
+ shellScript = "set -x\nset -e\n\nmkdir -p \"${DSTROOT}/usr/local/include/mach\"\n\n# A better solution would be to create a header using all of the archs, but this works for now.\nset -- ${ARCHS}\narch=$1\n\ninstall -m 0644 \"${DERIVED_SOURCES_DIR}\"/\"${arch}\"/backing_store_triggers.h \"${DSTROOT}\"/usr/local/include/mach/backing_store_triggers.h\ninstall -m 0644 \"${DERIVED_SOURCES_DIR}\"/\"${arch}\"/backing_store_alertsServer.h \"${DSTROOT}\"/usr/local/include/mach/backing_store_alerts_server.h\n";
showEnvVarsInLog = 0;
};
BA4B79F91373B6A400003422 /* ShellScript */ = {
shellScript = "set -x\nset -e\n\nmkdir -p \"${DSTROOT}/private/var/log/sa\"\nmkdir -p \"${DSTROOT}/usr/lib/sa\"\ninstall \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\ninstall \"${SCRIPT_INPUT_FILE_1}\" \"${SCRIPT_OUTPUT_FILE_1}\"\n";
showEnvVarsInLog = 0;
};
+ FD0AA4911630C39500606589 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". ${SRCROOT}/zic.tproj/install_zoneinfo.sh";
+ showEnvVarsInLog = 0;
+ };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
+ 1523FE5B1595048900661E82 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1523FE6C1595056C00661E82 /* ltop.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 55CCB16B16B84EDA00B56979 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 55CCB17416B84EF800B56979 /* vm_purgeable_stat.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ ADA9007017679A8C00161ADF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ ADA9007C1767A03200161ADF /* purge.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B3F0E6CD16E96FC2008FAD09 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B3F0E6DD16E9706E008FAD09 /* memory_pressure.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
BA0A860813968E8500D2272C /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C625B28416D6F27E00168EF7 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C625B28B16D6F27E00168EF7 /* taskpolicy.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C96F50AF15BDCEC3008682F7 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C96F50BE15BDFF03008682F7 /* lsmp.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
+ 1523FE6F1595069900661E82 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 1523FE5A1595048900661E82 /* ltop */;
+ targetProxy = 1523FE6E1595069900661E82 /* PBXContainerItemProxy */;
+ };
+ 1523FE711595069F00661E82 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 1523FE5A1595048900661E82 /* ltop */;
+ targetProxy = 1523FE701595069F00661E82 /* PBXContainerItemProxy */;
+ };
+ 55CCB17816B851E900B56979 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 55CCB16A16B84EDA00B56979 /* vm_purgeable_stat */;
+ targetProxy = 55CCB17716B851E900B56979 /* PBXContainerItemProxy */;
+ };
+ 55CCB17A16B851F300B56979 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 55CCB16A16B84EDA00B56979 /* vm_purgeable_stat */;
+ targetProxy = 55CCB17916B851F300B56979 /* PBXContainerItemProxy */;
+ };
+ ADA9007E1767A31300161ADF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = ADA9006F17679A8C00161ADF /* purge */;
+ targetProxy = ADA9007D1767A31300161ADF /* PBXContainerItemProxy */;
+ };
+ ADA900801767A31900161ADF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = ADA9006F17679A8C00161ADF /* purge */;
+ targetProxy = ADA9007F1767A31900161ADF /* PBXContainerItemProxy */;
+ };
+ B3F0E6DF16E97142008FAD09 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = B3F0E6CC16E96FC2008FAD09 /* memory_pressure */;
+ targetProxy = B3F0E6DE16E97142008FAD09 /* PBXContainerItemProxy */;
+ };
BA0A861613968ECA00D2272C /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = BA0A860713968E8500D2272C /* zprint */;
target = BAE58A45137D69A60049DD3B /* sc_usage */;
targetProxy = BAE58A55137D6A050049DD3B /* PBXContainerItemProxy */;
};
+ C625B29116D6F38700168EF7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C625B28716D6F27E00168EF7 /* taskpolicy */;
+ targetProxy = C625B29016D6F38700168EF7 /* PBXContainerItemProxy */;
+ };
+ C625B29316D6F39000168EF7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C625B28716D6F27E00168EF7 /* taskpolicy */;
+ targetProxy = C625B29216D6F39000168EF7 /* PBXContainerItemProxy */;
+ };
+ C96F50BA15BDFDA7008682F7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C96F50AE15BDCEC3008682F7 /* lsmp */;
+ targetProxy = C96F50B915BDFDA7008682F7 /* PBXContainerItemProxy */;
+ };
+ C96F50BC15BDFDB1008682F7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C96F50AE15BDCEC3008682F7 /* lsmp */;
+ targetProxy = C96F50BB15BDFDB1008682F7 /* PBXContainerItemProxy */;
+ };
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
+ 1523FE621595048900661E82 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = ltop;
+ };
+ name = Release;
+ };
+ 55CCB17216B84EDA00B56979 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = vm_purgeable_stat;
+ };
+ name = Release;
+ };
+ ADA9007617679A8C00161ADF /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = purge;
+ };
+ name = Release;
+ };
+ B3F0E6D416E96FC2008FAD09 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = memory_pressure;
+ };
+ name = Release;
+ };
BA0A860F13968E8500D2272C /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
INSTALL_PATH = /usr/libexec;
PRODUCT_NAME = getty;
};
};
name = Release;
};
+ C625B28E16D6F27E00168EF7 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ C96F50B615BDCEC3008682F7 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = lsmp;
+ };
+ name = Release;
+ };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
+ 1523FE611595048900661E82 /* Build configuration list for PBXNativeTarget "ltop" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1523FE621595048900661E82 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 55CCB17116B84EDA00B56979 /* Build configuration list for PBXNativeTarget "vm_purgeable_stat" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 55CCB17216B84EDA00B56979 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ ADA9007517679A8C00161ADF /* Build configuration list for PBXNativeTarget "purge" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ ADA9007617679A8C00161ADF /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ B3F0E6D316E96FC2008FAD09 /* Build configuration list for PBXNativeTarget "memory_pressure" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B3F0E6D416E96FC2008FAD09 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
BA0A860E13968E8500D2272C /* Build configuration list for PBXNativeTarget "zprint" */ = {
isa = XCConfigurationList;
buildConfigurations = (
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ C625B28F16D6F27E00168EF7 /* Build configuration list for PBXNativeTarget "taskpolicy" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C625B28E16D6F27E00168EF7 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C96F50B515BDCEC3008682F7 /* Build configuration list for PBXNativeTarget "lsmp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C96F50B615BDCEC3008682F7 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
/* End XCConfigurationList section */
};
rootObject = BA2DE9181372FA9100D1913C /* Project object */;
--- /dev/null
+.Dd 2/21/13\r
+.Dt taskpolicy 8\r
+.Os Darwin\r
+.Sh NAME\r
+.Nm taskpolicy\r
+.Nd execute a program with an altered I/O or scheduling policy\r
+.Sh SYNOPSIS\r
+.Nm\r
+.Op Fl d Ar policy\r
+.Op Fl b\r
+.Ar program\r
+.Oo\r
+.Ar arg1\r
+.Op Ar ...\r
+.Oc\r
+.Sh DESCRIPTION\r
+The\r
+.Nm\r
+program uses the\r
+.Xr setiopolicy_np 3\r
+and\r
+.Xr setpriority 2\r
+APIs to execute a program with altered I/O or scheduling policies. All\r
+children of the specified program also inherit these policies.\r
+.Pp\r
+.Nm\r
+accepts the following flags and arguments:\r
+.Bl -tag -width "d policy " -offset indent\r
+.It Fl d Ar policy\r
+Run the program after calling\r
+.Xr setiopolicy_np 3\r
+with an iotype of IOPOL_TYPE_DISK, a scope of IOPOL_SCOPE_PROCESS, and the\r
+specified policy. The argument can either be an integer, or a symbolic string\r
+like "default" or "throttle", which is interpreted case-insensitively.\r
+.It Fl g Ar policy\r
+Run the program after calling\r
+.Xr setiopolicy_np 3\r
+with an iotype of IOPOL_TYPE_DISK, a scope of IOPOL_SCOPE_DARWIN_BG, and the\r
+specified policy. The argument is interpreted in the same manor as\r
+.Fl d .\r
+.It Fl b\r
+Run the program after calling\r
+.Xr setpriority 2\r
+with a priority of PRIO_DARWIN_BG.\r
+.El\r
+.Pp\r
+.Sh SEE ALSO \r
+.Xr setpriority 2 ,\r
+.Xr setiopolicy_np 3\r
--- /dev/null
+/*
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <err.h>
+#include <sys/errno.h>
+#include <stdbool.h>
+#include <sysexits.h>
+#include <mach/mach.h>
+#include <mach/task_policy.h>
+
+#define QOS_PARAMETER_LATENCY 0
+#define QOS_PARAMETER_THROUGHPUT 1
+
+static void usage(void);
+static int parse_disk_policy(const char *strpolicy);
+static int parse_qos_tier(const char *strpolicy, int parameter);
+
+int main(int argc, char * argv[])
+{
+ int ch, ret;
+ bool flagx = false, flagX = false, flagb = false;
+ int flagd = -1, flagg = -1;
+ struct task_qos_policy qosinfo = { LATENCY_QOS_TIER_UNSPECIFIED, THROUGHPUT_QOS_TIER_UNSPECIFIED };
+
+ while ((ch = getopt(argc, argv, "xXbd:g:t:l:")) != -1) {
+ switch (ch) {
+ case 'x':
+ flagx = true;
+ break;
+ case 'X':
+ flagX = true;
+ break;
+ case 'b':
+ flagb = true;
+ break;
+ case 'd':
+ flagd = parse_disk_policy(optarg);
+ if (flagd == -1) {
+ warnx("Could not parse '%s' as a disk policy", optarg);
+ usage();
+ }
+ break;
+ case 'g':
+ flagg = parse_disk_policy(optarg);
+ if (flagg == -1) {
+ warnx("Could not parse '%s' as a disk policy", optarg);
+ usage();
+ }
+ break;
+ case 't':
+ qosinfo.task_throughput_qos_tier = parse_qos_tier(optarg, QOS_PARAMETER_THROUGHPUT);
+ if (qosinfo.task_throughput_qos_tier == -1) {
+ warnx("Could not parse '%s' as a qos tier", optarg);
+ usage();
+ }
+ break;
+ case 'l':
+ qosinfo.task_latency_qos_tier = parse_qos_tier(optarg, QOS_PARAMETER_LATENCY);
+ if (qosinfo.task_latency_qos_tier == -1) {
+ warnx("Could not parse '%s' as a qos tier", optarg);
+ usage();
+ }
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0) {
+ usage();
+ }
+
+ if (flagx && flagX){
+ warnx("Incompatible options -x, -X");
+ usage();
+ }
+
+ if (flagx) {
+ ret = setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY, IOPOL_SCOPE_PROCESS, IOPOL_VFS_HFS_CASE_SENSITIVITY_FORCE_CASE_SENSITIVE);
+ if (ret == -1) {
+ err(EX_SOFTWARE, "setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY...)");
+ }
+ }
+
+ if (flagX) {
+ ret = setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY, IOPOL_SCOPE_PROCESS, IOPOL_VFS_HFS_CASE_SENSITIVITY_DEFAULT);
+ if (ret == -1) {
+ err(EX_SOFTWARE, "setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY...)");
+ }
+ }
+
+ if (flagb) {
+ ret = setpriority(PRIO_DARWIN_PROCESS, 0, PRIO_DARWIN_BG);
+ if (ret == -1) {
+ err(EX_SOFTWARE, "setpriority()");
+ }
+ }
+
+ if (flagd >= 0) {
+ ret = setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, flagd);
+ if (ret == -1) {
+ err(EX_SOFTWARE, "setiopolicy_np(...IOPOL_SCOPE_PROCESS...)");
+ }
+ }
+
+ if (flagg >= 0){
+ ret = setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_DARWIN_BG, flagg);
+ if (ret == -1) {
+ err(EX_SOFTWARE, "setiopolicy_np(...IOPOL_SCOPE_DARWIN_BG...)");
+ }
+ }
+
+ if (qosinfo.task_latency_qos_tier != LATENCY_QOS_TIER_UNSPECIFIED ||
+ qosinfo.task_throughput_qos_tier != THROUGHPUT_QOS_TIER_UNSPECIFIED){
+ ret = task_policy_set(mach_task_self(), TASK_OVERRIDE_QOS_POLICY, (task_policy_t)&qosinfo, TASK_QOS_POLICY_COUNT);
+ if (ret != KERN_SUCCESS){
+ err(EX_SOFTWARE, "task_policy_set(...TASK_OVERRIDE_QOS_POLICY...)");
+ }
+ }
+
+ ret = execvp(argv[0], argv);
+ if (ret == -1) {
+ err(EX_NOINPUT, "Could not execute %s", argv[0]);
+ }
+
+ return EX_OSERR;
+}
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: %s [-x|-X] [-d <policy>] [-g policy] [-b] [-t <tier>] [-l <tier>] <program> [<pargs> [...]]\n", getprogname());
+ exit(EX_USAGE);
+}
+
+static int parse_disk_policy(const char *strpolicy)
+{
+ long policy;
+ char *endptr = NULL;
+
+ /* first try as an integer */
+ policy = strtol(strpolicy, &endptr, 0);
+ if (endptr && (endptr[0] == '\0') && (strpolicy[0] != '\0')) {
+ /* parsed complete string as a number */
+ return (int)policy;
+ }
+
+ if (0 == strcasecmp(strpolicy, "DEFAULT") ) {
+ return IOPOL_DEFAULT;
+ } else if (0 == strcasecmp(strpolicy, "IMPORTANT")) {
+ return IOPOL_IMPORTANT;
+ } else if (0 == strcasecmp(strpolicy, "PASSIVE")) {
+ return IOPOL_PASSIVE;
+ } else if (0 == strcasecmp(strpolicy, "THROTTLE")) {
+ return IOPOL_THROTTLE;
+ } else if (0 == strcasecmp(strpolicy, "UTILITY")) {
+ return IOPOL_UTILITY;
+ } else if (0 == strcasecmp(strpolicy, "STANDARD")) {
+ return IOPOL_STANDARD;
+ } else {
+ return -1;
+ }
+}
+
+static int parse_qos_tier(const char *strtier, int parameter){
+ long policy;
+ char *endptr = NULL;
+
+ /* first try as an integer */
+ policy = strtol(strtier, &endptr, 0);
+ if (endptr && (endptr[0] == '\0') && (strtier[0] != '\0')) {
+ switch (policy) {
+ case 0:
+ return parameter ? THROUGHPUT_QOS_TIER_0 : LATENCY_QOS_TIER_0;
+ break;
+ case 1:
+ return parameter ? THROUGHPUT_QOS_TIER_1 : LATENCY_QOS_TIER_1;
+ break;
+ case 2:
+ return parameter ? THROUGHPUT_QOS_TIER_2 : LATENCY_QOS_TIER_2;
+ break;
+ case 3:
+ return parameter ? THROUGHPUT_QOS_TIER_3 : LATENCY_QOS_TIER_3;
+ break;
+ case 4:
+ return parameter ? THROUGHPUT_QOS_TIER_4 : LATENCY_QOS_TIER_4;
+ break;
+ case 5:
+ return parameter ? THROUGHPUT_QOS_TIER_5 : LATENCY_QOS_TIER_5;
+ break;
+ default:
+ return -1;
+ break;
+ }
+ }
+
+ return -1;
+}
.Fl t
.Op Fl R Ar rawfile
.Op Fl o Ar OutputFilename
-.Op Ar CodeFilename
+.Op Fl N
+.Op Ar ExtraCodeFilename1 ExtraCodeFilename2 ...
.Sh DESCRIPTION
The
.Nm trace
#include <string.h>
#include <paths.h>
#include <err.h>
+#include <stdarg.h>
+#include <inttypes.h>
#include <libutil.h>
+#ifndef KERNEL_PRIVATE
+#define KERNEL_PRIVATE
#include <sys/kdebug.h>
+#undef KERNEL_PRIVATE
+#else
+#include <sys/kdebug.h>
+#endif /*KERNEL_PRIVATE*/
+#include <sys/param.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
int remove_flag=0;
int bufset_flag=0;
int bufget_flag=0;
-int class_flag=0;
-int subclass_flag=0;
+int filter_flag=0;
+int filter_file_flag=0;
+int filter_alloced=0;
int trace_flag=0;
int nowrap_flag=0;
int freerun_flag=0;
int verbose_flag=0;
+int usage_flag=0;
int pid_flag=0;
int pid_exflag=0;
int ppt_flag=0;
-unsigned int class=0;
-unsigned int class2=0;
-unsigned int subclass=0;
+int done_with_args=0;
+int no_default_codes_flag=0;
+
unsigned int value1=0;
unsigned int value2=0;
unsigned int value3=0;
unsigned int value4=0;
+
pid_t pid=0;
int reenable=0;
extern char **environ;
+uint8_t* type_filter_bitmap;
+
#define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
#define DBG_FUNC_MASK 0xfffffffc
int nthreads = 0;
kd_threadmap *mapptr = 0;
+kd_cpumap_header* cpumap_header = NULL;
+kd_cpumap* cpumap = NULL;
+
/*
If NUMPARMS changes from the kernel,
then PATHLENGTH will also reflect the change
char *debug_string;
} code_type_t;
-code_type_t * codesc = 0;
+code_type_t* codesc = 0;
+size_t codesc_idx = 0; // Index into first empty codesc entry
+
typedef struct event *event_t;
int codenum = 0;
int codeindx_cache = 0;
-char codefile[] = "codes";
-char *cfile = (char *)0;
-
static void quit(char *);
static int match_debugid(unsigned int, char *, int *);
static void usage(int short_help);
static int argtoi(int flag, char *req, char *str, int base);
-static int parse_codefile(char *filename);
-static int read_command_map(int, int);
+static int parse_codefile(const char *filename);
+static void codesc_find_dupes(void);
+static int read_command_map(int, uint32_t);
+static void read_cpu_map(int);
static void find_thread_command(kd_buf *, char **);
static void create_map_entry(uintptr_t, char *);
static void getdivisor();
static void set_freerun();
static void get_bufinfo(kbufinfo_t *);
static void set_init();
-static void set_class();
static void set_kval_list();
-static void set_subclass();
static void readtrace(char *);
static void log_trace();
static void Log_trace();
static threadmap_t find_thread_entry(uintptr_t);
+static void saw_filter_class(uint8_t class);
+static void saw_filter_end_range(uint8_t end_class);
+static void saw_filter_subclass(uint8_t subclass);
+static void filter_done_parsing(void);
+
+static void set_filter(void);
+static void set_filter_class(uint8_t class);
+static void set_filter_range(uint8_t class, uint8_t end);
+static void set_filter_subclass(uint8_t class, uint8_t subclass);
+static void parse_filter_file(char *filename);
+
+static void quit_args(const char *fmt, ...) __printflike(1, 2);
#ifndef KERN_KDWRITETR
#define KERN_KDWRITETR 17
#define RAW_VERSION1 0x55aa0101
#endif
+#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(*x)))
+
+#define EXTRACT_CLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF00 ) >> 8 ) )
+#define EXTRACT_SUBCLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF ) ) )
+
+#define ENCODE_CSC_LOW(class, subclass) \
+ ( (uint16_t) ( ((class) & 0xff) << 8 ) | ((subclass) & 0xff) )
RAW_header raw_header;
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
- quit("trace facility failure, KERN_KDENABLE\n");
+ quit_args("trace facility failure, KERN_KDENABLE: %s\n", strerror(errno));
}
void set_remove()
if (errno == EBUSY)
quit("the trace facility is currently in use...\n fs_usage, sc_usage, trace, and latency use this feature.\n\n");
else
- quit("trace facility failure, KERN_KDREMOVE\n");
+ quit_args("trace facility failure, KERN_KDREMOVE: %s\n", strerror(errno));
}
}
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
- quit("trace facility failure, KERN_KDSETBUF\n");
+ quit_args("trace facility failure, KERN_KDSETBUF: %s\n", strerror(errno));
mib[0] = CTL_KERN;
mib[1] = KERN_KDEBUG;
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
- quit("trace facility failure, KERN_KDSETUP\n");
+ quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno));
}
void set_nowrap()
mib[4] = 0;
mib[5] = 0; /* no flags */
if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
- quit("trace facility failure, KDBG_NOWRAP\n");
+ quit_args("trace facility failure, KDBG_NOWRAP: %s\n", strerror(errno));
}
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
- quit("trace facility failure, KDBG_FREERUN\n");
+ quit_args("trace facility failure, KDBG_FREERUN: %s\n", strerror(errno));
}
void get_bufinfo(kbufinfo_t *val)
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 3, val, &needed, 0, 0) < 0)
- quit("trace facility failure, KERN_KDGETBUF\n");
+ quit_args("trace facility failure, KERN_KDGETBUF: %s\n", strerror(errno));
}
void set_init()
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
- quit("trace facility failure, KERN_KDSETREG (rangetype)\n");
+ quit_args("trace facility failure, KERN_KDSETREG (rangetype): %s\n", strerror(errno));
mib[0] = CTL_KERN;
mib[1] = KERN_KDEBUG;
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
- quit("trace facility failure, KERN_KDSETUP\n");
+ quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno));
}
-void set_class()
+static void
+set_filter(void)
{
- kd_regtype kr;
-
- kr.type = KDBG_CLASSTYPE;
- kr.value1 = class;
- kr.value2 = class2;
- 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 (classtype)\n");
+ errno = 0;
+ int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDSET_TYPEFILTER };
+ size_t needed = KDBG_TYPEFILTER_BITMAP_SIZE;
+
+ if(sysctl(mib, ARRAYSIZE(mib), type_filter_bitmap, &needed, NULL, 0)) {
+ quit_args("trace facility failure, KERN_KDSET_TYPEFILTER: %s\n", strerror(errno));
+ }
}
void set_kval_list()
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
- quit("trace facility failure, KERN_KDSETREG (valcheck)\n");
-}
-
-void set_subclass()
-{
- kd_regtype kr;
-
- kr.type = KDBG_SUBCLSTYPE;
- kr.value1 = class;
- kr.value2 = subclass;
- 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 (subclstype)\n");
+ quit_args("trace facility failure, KERN_KDSETREG (valcheck): %s\n", strerror(errno));
}
mib[5] = 0;
if (sysctl(mib, 3, buffer, &needed, NULL, 0) < 0)
- quit("trace facility failure, KERN_KDREADTR\n");
+ quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno));
}
quit("can't allocate memory for tracing info\n");
read_command_map(0, 0);
+ read_cpu_map(0);
raw_header.version_no = RAW_VERSION1;
raw_header.thread_count = total_threads;
write(fd, (char *)mapptr, size);
pad_size = 4096 - ((sizeof(RAW_header) + size) & 4095);
+
+ if (cpumap_header) {
+ size_t cpumap_size = sizeof(kd_cpumap_header) + cpumap_header->cpu_count * sizeof(kd_cpumap);
+ if (pad_size >= cpumap_size) {
+ write(fd, (char *)cpumap_header, cpumap_size);
+ pad_size -= cpumap_size;
+ }
+ }
+
memset(pad_buf, 0, pad_size);
-
write(fd, pad_buf, pad_size);
for (;;) {
set_numbufs(nbufs);
set_init();
- if (class_flag)
- set_class();
-
- if (subclass_flag)
- set_subclass();
+ if (filter_flag)
+ set_filter();
if (kval_flag)
set_kval_list();
char pad_buf[4096];
read_command_map(0, 0);
+ read_cpu_map(0);
raw_header.version_no = RAW_VERSION1;
raw_header.thread_count = total_threads;
write(fd, (char *)mapptr, size);
pad_size = 4096 - ((sizeof(RAW_header) + size) & 4095);
- memset(pad_buf, 0, pad_size);
-
+
+ if (cpumap_header) {
+ size_t cpumap_size = sizeof(kd_cpumap_header) + cpumap_header->cpu_count * sizeof(kd_cpumap);
+ if (pad_size >= cpumap_size) {
+ write(fd, (char *)cpumap_header, cpumap_size);
+ pad_size -= cpumap_size;
+ }
+ }
+
+ memset(pad_buf, 0, pad_size);
write(fd, pad_buf, pad_size);
}
sample_window_abs = (uint64_t)((double)US_TO_SLEEP * divisor);
}
}
count_of_names = raw_header.thread_count;
- trace_time = raw_header.TOD_secs;
+ trace_time = (time_t) (raw_header.TOD_secs);
printf("%s\n", ctime(&trace_time));
}
kd = (kd_buf *)buffer;
read_command_map(fd, count_of_names);
+ read_cpu_map(fd);
for (;;) {
uint32_t count;
mib[4] = 0;
mib[5] = 0;
if (sysctl(mib, 3, buffer, &needed, NULL, 0) < 0)
- quit("trace facility failure, KERN_KDREADTR\n");
+ quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno));
if (needed == 0)
break;
last_event_time = x;
ending_event = FALSE;
- find_thread_command(kdp, &command);
+ /*
+ * Is this event from an IOP? If so, there will be no
+ * thread command, label it with the symbolic IOP name
+ */
+ if (cpumap && (cpunum < cpumap_header->cpu_count) && (cpumap[cpunum].flags & KDBG_CPUMAP_IS_IOP)) {
+ command = cpumap[cpunum].name;
+ } else {
+ find_thread_command(kdp, &command);
+ }
/*
* The internal use TRACE points clutter the output.
int ch;
int i;
char *output_filename = NULL;
+ char *filter_filename = NULL;
+ unsigned int parsed_arg;
for (i = 1; i < argc; i++) {
if (strcmp("-X", argv[i]) == 0) {
output_file = stdout;
output_fd = 1;
- while ((ch = getopt(argc, argv, "hedEk:irb:gc:p:s:tR:L:l:S:F:a:x:Xnfvo:P")) != EOF)
+ while ((ch = getopt(argc, argv, "hedEk:irb:gc:p:s:tR:L:l:S:F:a:x:Xnfvo:PT:N")) != EOF)
{
switch(ch)
{
case 'h': /* help */
- usage(LONG_HELP);
+ usage_flag=1;
break;
case 'S':
secs_to_run = argtoi('S', "decimal number", optarg, 10);
break;
case 'k':
if (kval_flag == 0)
- value1 = argtoul('k', "hex number", optarg, 16);
+ value1 = (unsigned int) argtoul('k', "hex number", optarg, 16);
else if (kval_flag == 1)
- value2 = argtoul('k', "hex number", optarg, 16);
+ value2 = (unsigned int) argtoul('k', "hex number", optarg, 16);
else if (kval_flag == 2)
- value3 = argtoul('k', "hex number", optarg, 16);
+ value3 = (unsigned int) argtoul('k', "hex number", optarg, 16);
else if (kval_flag == 3)
- value4 = argtoul('k', "hex number", optarg, 16);
+ value4 = (unsigned int) argtoul('k', "hex number", optarg, 16);
else
{
fprintf(stderr, "A maximum of four values can be specified with -k\n");
nbufs = argtoi('b', "decimal number", optarg, 10);
break;
case 'c':
- class_flag = 1;
- class = argtoi('c', "decimal number", optarg, 10);
- class2 = class+1;
+ filter_flag = 1;
+ parsed_arg = argtoi('c', "decimal, hex, or octal number", optarg, 0);
+ if (parsed_arg > 0xFF)
+ quit_args("argument '-c %s' parsed as %u, "
+ "class value must be 0-255\n", optarg, parsed_arg);
+ saw_filter_class(parsed_arg);
break;
case 's':
- subclass_flag = 1;
- subclass = argtoi('s', "decimal number", optarg, 10);
+ filter_flag = 1;
+ parsed_arg = argtoi('s', "decimal, hex, or octal number", optarg, 0);
+ if (parsed_arg > 0xFF)
+ quit_args("argument '-s %s' parsed as %u, "
+ "subclass value must be 0-255\n", optarg, parsed_arg);
+ saw_filter_subclass(parsed_arg);
break;
case 'p':
- if (class_flag != 1)
- { fprintf(stderr, "-p must follow -c\n");
- exit(1);
- }
- class2 = argtoi('p', "decimal number", optarg, 10);
+ filter_flag = 1;
+ parsed_arg = argtoi('p', "decimal, hex, or octal number", optarg, 0);
+ if (parsed_arg > 0xFF)
+ quit_args("argument '-p %s' parsed as %u, "
+ "end range value must be 0-255\n", optarg, parsed_arg);
+ saw_filter_end_range(parsed_arg);
break;
case 'P':
ppt_flag = 1;
break;
case 'X':
break;
+ case 'N':
+ no_default_codes_flag = 1;
+ break;
+ case 'T':
+ filter_flag = 1;
+
+ // Flush out any unclosed -c argument
+ filter_done_parsing();
+
+ parse_filter_file(optarg);
+ break;
default:
usage(SHORT_HELP);
}
}
argc -= optind;
+ if (!no_default_codes_flag)
+ {
+ if (verbose_flag)
+ printf("Adding default code file /usr/share/misc/trace.codes. Use '-N' to skip this.\n");
+ parse_codefile("/usr/share/misc/trace.codes");
+ }
+
if (argc)
{
if (!execute_flag)
{
- cfile = argv[optind];
- if (verbose_flag)
- printf("Code file is %s \n", cfile);
- if (parse_codefile(cfile) == -1)
- cfile = (char *)0;
+ while (argc--)
+ {
+ const char *cfile = argv[optind++];
+ if (verbose_flag) printf("Adding code file %s \n", cfile);
+ parse_codefile(cfile);
+ }
}
}
else
{
if (execute_flag)
- {
- printf("-E flag needs an executable to launch\n");
- exit(1);
- }
+ quit_args("-E flag needs an executable to launch\n");
}
+
+ if (usage_flag)
+ usage(LONG_HELP);
+
getdivisor();
if (pid_flag && pid_exflag)
- {
- fprintf(stderr, "Can't use both -a and -x flag together\n");
- exit(1);
- }
+ quit_args("Can't use both -a and -x flag together\n");
- if (subclass_flag && !class_flag) {
- fprintf(stderr,"Must define a class ('c') with the subclass ('s') option\n");
- usage(SHORT_HELP);
- }
-
- if (kval_flag && (subclass_flag || class_flag))
- {
- fprintf(stderr,"Don't use class or subclass with the 'k' code options.\n");
- usage(SHORT_HELP);
- }
+ if (kval_flag && filter_flag)
+ quit_args("Cannot use -k flag with -c, -s, or -p\n");
if (output_filename && !trace_flag && !readRAW_flag)
- {
- fprintf(stderr, "When using 'o' option, must use the 't' or 'R' option too\n");
- usage(SHORT_HELP);
- }
+ quit_args("When using 'o' option, must use the 't' or 'R' option too\n");
+
+ filter_done_parsing();
+
+ done_with_args = 1;
if (LogRAW_flag) {
get_bufinfo(&bufinfo);
if (bufinfo.flags & KDBG_VALCHECK)
printf("\tCollecting specific code values is enabled\n");
- else
+ else
printf("\tCollecting specific code values is disabled\n");
-
+
+ if (bufinfo.flags & KDBG_TYPEFILTER_CHECK)
+ printf("\tCollection based on a filter is enabled\n");
+ else
+ printf("\tCollection based on a filter is disabled\n");
+
if (bufinfo.flags & KDBG_PIDCHECK)
printf("\tCollection based on pid is enabled\n");
else
if (init_flag)
set_init();
- if (class_flag)
- set_class();
-
- if (subclass_flag)
- set_subclass();
+ if (filter_flag)
+ set_filter();
if (kval_flag)
set_kval_list();
} /* end main */
+static void
+quit_args(const char *fmt, ...)
+{
+ char buffer[1024];
+
+ if (reenable == 1)
+ {
+ reenable = 0;
+ set_enable(1); /* re-enable kernel logging */
+ }
+
+ va_list args;
+
+ va_start (args, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, args);
+
+ fprintf(stderr, "trace error: %s", buffer);
+
+ va_end(args);
+
+ if (!done_with_args)
+ usage(SHORT_HELP);
+
+ exit(1);
+}
+
void
quit(char *s)
if (short_help)
{
- (void)fprintf(stderr, " usage: trace -h\n");
+ (void)fprintf(stderr, " usage: trace -h [-v]\n");
(void)fprintf(stderr, " usage: trace -i [-b numbufs]\n");
(void)fprintf(stderr, " usage: trace -g\n");
(void)fprintf(stderr, " usage: trace -d [-a pid | -x pid ]\n");
(void)fprintf(stderr, " usage: trace -n\n");
(void)fprintf(stderr,
- " usage: trace -e [ -c class [-p class] [-s subclass] ] [-a pid | -x pid] |\n");
+ " usage: trace -e [ -c class [[-s subclass]... | -p class ]]... | \n");
(void)fprintf(stderr,
- " [-k code | -k code | -k code | -k code] [-P] \n\n");
+ " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter] \n");
+ (void)fprintf(stderr,
+ " [-a pid | -x pid] \n\n");
(void)fprintf(stderr,
- " usage: trace -E [ -c class [-p class] [-s subclass] ] |\n");
+ " usage: trace -E [ -c class [[-s subclass]... | -p class ]]... | \n");
(void)fprintf(stderr,
- " [-k code | -k code | -k code | -k code] [-P]\n");
+ " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter] \n");
(void)fprintf(stderr,
" executable_path [optional args to executable] \n\n");
(void)fprintf(stderr,
" usage: trace -l RawFilename\n");
(void)fprintf(stderr,
- " usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [CodeFilename]\n");
+ " usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...]\n");
+ (void)fprintf(stderr,
+ " usage: trace -t [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...]\n");
(void)fprintf(stderr,
- " usage: trace -t [-o OutputFilename] [CodeFilename]\n");
+ " Trace will import /usr/share/misc/trace.codes as a default codefile unless -N is specified. Extra codefiles specified are used in addition to the default codefile.\n");
exit(1);
}
- /* Only get here of printing long usage list */
- (void)fprintf(stderr, "usage: trace -h\n");
+ /* Only get here if printing long usage info */
+ (void)fprintf(stderr, "usage: trace -h [-v]\n");
(void)fprintf(stderr, "\tPrint this long command help.\n\n");
+ (void)fprintf(stderr, "\t -v Print extra information about tracefilter and code files.\n\n");
(void)fprintf(stderr, "usage: trace -i [-b numbufs]\n");
(void)fprintf(stderr, "\tInitialize the kernel trace buffer.\n\n");
(void)fprintf(stderr, "\tDisables kernel buffer wrap around.\n\n");
(void)fprintf(stderr,
- "usage: trace -e [ -c class [-p class] [-s subclass] ] [-a pid | -x pid] |\n");
+ "usage: trace -e [ -c class [[-s subclass]... | -p class ]]... |\n");
(void)fprintf(stderr,
- " [-k code | -k code | -k code | -k code] \n\n");
- (void)fprintf(stderr, "\tEnable/start collection of kernel trace elements.\n");
- (void)fprintf(stderr, "\tEnter values in decimal notation unless otherwise noted..\n\n");
- (void)fprintf(stderr, "\t -c class Restrict trace collection to given class.\n\n");
- (void)fprintf(stderr, "\t -p class Restrict trace collection to given class range.\n");
- (void)fprintf(stderr, "\t Must provide class with -c first.\n\n");
- (void)fprintf(stderr, "\t -s subclass Restrict trace collection to given subclass.\n");
- (void)fprintf(stderr, "\t Must provide class with -c.\n\n");
+ " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter]\n");
+ (void) fprintf(stderr,
+ " [-a pid | -x pid]\n\n");
+ (void)fprintf(stderr, "\t Enable/start collection of kernel trace elements. \n\n");
+ (void)fprintf(stderr, "\t By default, trace collects all tracepoints. \n");
+ (void)fprintf(stderr, "\t The following arguments may be used to restrict collection \n");
+ (void)fprintf(stderr, "\t to a limited set of tracepoints. \n\n");
+ (void)fprintf(stderr, "\t Multiple classes can be specified by repeating -c. \n");
+ (void)fprintf(stderr, "\t Multiple subclasses can be specified by repeating -s after -c. \n");
+ (void)fprintf(stderr, "\t Classes, subclasses, and class ranges can be entered \n");
+ (void)fprintf(stderr, "\t in hex (0xXX), decimal (XX), or octal (0XX). \n\n");
+ (void)fprintf(stderr, "\t -c class Restrict trace collection to given class. \n\n");
+ (void)fprintf(stderr, "\t -p class Restrict trace collection to given class range. \n");
+ (void)fprintf(stderr, "\t Must provide class with -c first. \n\n");
+ (void)fprintf(stderr, "\t -s subclass Restrict trace collection to given subclass. \n");
+ (void)fprintf(stderr, "\t Must provide class with -c first. \n\n");
(void)fprintf(stderr, "\t -a pid Restrict trace collection to the given process.\n\n");
(void)fprintf(stderr, "\t -x pid Exclude the given process from trace collection.\n\n");
(void)fprintf(stderr, "\t -k code Restrict trace collection up to four specific codes.\n");
- (void)fprintf(stderr, "\t Enter codes in hex values.\n\n");
+ (void)fprintf(stderr, "\t Enter codes in hex (0xXXXXXXXX). \n\n");
(void)fprintf(stderr, "\t -P Enable restricted PPT trace points only.\n\n");
+ (void)fprintf(stderr, "\t -T tracefilter Read class and subclass restrictions from a \n");
+ (void)fprintf(stderr, "\t tracefilter description file. \n");
+ (void)fprintf(stderr, "\t Run trace -h -v for more info on this file. \n\n");
(void)fprintf(stderr,
- "usage: trace -E [ -c class [-p class] [-s subclass] ] |\n");
+ "usage: trace -E [ -c class [[-s subclass]... | -p class ]]... |\n");
(void)fprintf(stderr,
- " [-k code | -k code | -k code | -k code] \n");
+ " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter]\n");
(void)fprintf(stderr,
" executable_path [optional args to executable] \n\n");
(void)fprintf(stderr, "\tLaunch the given executable and enable/start\n");
(void)fprintf(stderr, "\tcollection of kernel trace elements for that process.\n");
(void)fprintf(stderr, "\tSee -e(enable) flag for option descriptions.\n\n");
- (void)fprintf(stderr,
- "usage: trace -t [-o OutputFilename] [CodeFilename] \n");
+ (void)fprintf(stderr, "usage: trace -t [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...] \n");
(void)fprintf(stderr, "\tCollect the kernel buffer trace data and print it.\n\n");
+ (void)fprintf(stderr, "\t -N Do not import /usr/share/misc/trace.codes (for raw hex tracing or supplying an alternate set of codefiles)\n");
(void)fprintf(stderr, "\t -o OutputFilename Print trace output to OutputFilename. Default is stdout.\n\n");
(void)fprintf(stderr,
- "usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [CodeFilename] \n");
+ "usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...] \n");
(void)fprintf(stderr, "\tRead raw trace file and print it.\n\n");
- (void)fprintf(stderr, "\t -X Force trace to interpret trace data as 32 bit. Default is to match the current systems bit width.\n");
- (void)fprintf(stderr, "\t -F frequency Specify the frequency of the clock used to timestamp entries in RawFilename\n");
+ (void)fprintf(stderr, "\t -X Force trace to interpret trace data as 32 bit. \n");
+ (void)fprintf(stderr, "\t Default is to match the bit width of the current system. \n");
+ (void)fprintf(stderr, "\t -N Do not import /usr/share/misc/trace.codes (for raw hex tracing or supplying an alternate set of codefiles)\n");
+ (void)fprintf(stderr, "\t -F frequency Specify the frequency of the clock used to timestamp entries in RawFilename.\n\t Use command \"sysctl hw.tbfrequency\" on the target device, to get target frequency.\n");
(void)fprintf(stderr, "\t -o OutputFilename Print trace output to OutputFilename. Default is stdout.\n\n");
(void)fprintf(stderr,
"usage: trace -L RawFilename [-S SecsToRun]\n");
- (void)fprintf(stderr, "\tContinuously collect the kernel buffer trace data in the raw format and write it to RawFilename.\n\n");
+ (void)fprintf(stderr, "\tContinuously collect the kernel buffer trace data in the raw format \n");
+ (void)fprintf(stderr, "\tand write it to RawFilename. \n");
+
+ (void)fprintf(stderr, "\t-L implies -r -i if tracing isn't currently enabled.\n");
+ (void)fprintf(stderr, "\tOptions passed to -e(enable) are also accepted by -L. (except -a -x -P)\n\n");
(void)fprintf(stderr, "\t -S SecsToRun Specify the number of seconds to collect trace data.\n\n");
(void)fprintf(stderr,
"usage: trace -l RawFilename\n");
(void)fprintf(stderr, "\tCollect the existing kernel buffer trace data in the raw format.\n\n");
+ if (verbose_flag) {
+ (void)fprintf(stderr,
+ "Code file: \n"
+ "\t A code file consists of a list of tracepoints, one per line, \n"
+ "\t with one tracepoint code in hex, followed by a tab, \n"
+ "\t followed by the tracepoint's name. \n\n"
+
+ "\t Example tracepoint: \n"
+ "\t 0x010c007c\tMSC_mach_msg_trap \n"
+ "\t This describes the tracepoint with the following info: \n"
+ "\t Name: MSC_mach_msg_trap \n"
+ "\t Class: 0x01 (Mach events) \n"
+ "\t Subclass: 0x0c (Mach system calls) \n"
+ "\t Code: 0x007c (Mach syscall number 31) \n\n"
+
+ "\t See /usr/include/sys/kdebug.h for the currently defined \n"
+ "\t class and subclass values. \n"
+ "\t See /usr/share/misc/trace.codes for the currently allocated \n"
+ "\t system tracepoints in trace code file format. \n"
+ "\t This codefile is useful with the -R argument to trace. \n"
+ "\n");
+
+ (void)fprintf(stderr,
+ "Tracefilter description file: \n"
+ "\t A tracefilter description file consists of a list of \n"
+ "\t class and subclass filters in hex, one per line, \n"
+ "\t which are applied as if they were passed with -c and -s. \n"
+ "\t Pass -v to see what classes and subclasses are being set. \n\n"
+
+ "\t File syntax: \n"
+ "\t Class filter: \n"
+ "\t C 0xXX \n"
+ "\t Subclass filter (includes class): \n"
+ "\t S 0xXXXX \n"
+ "\t Comment: \n"
+ "\t # This is a comment \n\n"
+
+ "\t For example, to trace Mach events (class 1):\n"
+ "\t C 0x01 \n"
+ "\t or to trace Mach system calls (class 1 subclass 13): \n"
+ "\t S 0x010C \n"
+ "\n");
+ }
+
exit(1);
}
}
+/*
+ * Filter args parsing state machine:
+ *
+ * Allowed args:
+ * -c -p
+ * -c -s (-s)*
+ * -c (-c)*
+ * every -c goes back to start
+ *
+ * Valid transitions:
+ * start -> class (first -c)
+ * class -> range (-c -p)
+ * class -> sub (-c -s)
+ * class -> class (-c -c)
+ * range -> class (-c -p -c)
+ * sub -> class (-c -s -c)
+ * * -> start (on filter_done_parsing)
+ *
+ * Need to call filter_done_parsing after
+ * calling saw_filter_*
+ * to flush out any class flag waiting to see if
+ * there is a -s flag coming up
+ */
+
+
+// What type of flag did I last see?
+enum {
+ FILTER_MODE_START,
+ FILTER_MODE_CLASS,
+ FILTER_MODE_CLASS_RANGE,
+ FILTER_MODE_SUBCLASS
+} filter_mode = FILTER_MODE_START;
+
+uint8_t filter_current_class = 0;
+uint8_t filter_current_subclass = 0;
+uint8_t filter_current_class_range = 0;
+
+static void
+saw_filter_class(uint8_t class)
+{
+ switch(filter_mode) {
+ case FILTER_MODE_START:
+ case FILTER_MODE_CLASS_RANGE:
+ case FILTER_MODE_SUBCLASS:
+ filter_mode = FILTER_MODE_CLASS;
+ filter_current_class = class;
+ filter_current_subclass = 0;
+ filter_current_class_range = 0;
+ // the case of a lone -c is taken care of
+ // by filter_done_parsing
+ break;
+ case FILTER_MODE_CLASS:
+ filter_mode = FILTER_MODE_CLASS;
+ // set old class, remember new one
+ set_filter_class(filter_current_class);
+ filter_current_class = class;
+ filter_current_subclass = 0;
+ filter_current_class_range = 0;
+ break;
+ default:
+ quit_args("invalid case in saw_filter_class\n");
+ }
+}
+
+static void
+saw_filter_end_range(uint8_t end_class)
+{
+ switch(filter_mode) {
+ case FILTER_MODE_CLASS:
+ filter_mode = FILTER_MODE_CLASS_RANGE;
+ filter_current_class_range = end_class;
+ set_filter_range(filter_current_class, filter_current_class_range);
+ break;
+ case FILTER_MODE_START:
+ quit_args("must provide '-c class' before '-p 0x%x'\n",
+ end_class);
+ case FILTER_MODE_CLASS_RANGE:
+ quit_args("extra range end '-p 0x%x'"
+ " for class '-c 0x%x'\n",
+ end_class, filter_current_class);
+ case FILTER_MODE_SUBCLASS:
+ quit_args("cannot provide both range end '-p 0x%x'"
+ " and subclass '-s 0x%x'"
+ " for class '-c 0x%x'\n",
+ end_class, filter_current_subclass,
+ filter_current_class);
+ default:
+ quit_args("invalid case in saw_filter_end_range\n");
+ }
+}
+
+static void
+saw_filter_subclass(uint8_t subclass)
+{
+ switch(filter_mode) {
+ case FILTER_MODE_CLASS:
+ case FILTER_MODE_SUBCLASS:
+ filter_mode = FILTER_MODE_SUBCLASS;
+ filter_current_subclass = subclass;
+ set_filter_subclass(filter_current_class, filter_current_subclass);
+ break;
+ case FILTER_MODE_START:
+ quit_args("must provide '-c class'"
+ " before subclass '-s 0x%x'\n", subclass);
+ case FILTER_MODE_CLASS_RANGE:
+ quit_args("cannot provide both range end '-p 0x%x'"
+ " and subclass '-s 0x%x'"
+ " for the same class '-c 0x%x'\n",
+ filter_current_class_range,
+ subclass, filter_current_class);
+ default:
+ quit_args("invalid case in saw_filter_subclass\n");
+ }
+}
+
+static void
+filter_done_parsing(void)
+{
+ switch(filter_mode) {
+ case FILTER_MODE_CLASS:
+ // flush out the current class
+ set_filter_class(filter_current_class);
+ filter_mode = FILTER_MODE_START;
+ filter_current_class = 0;
+ filter_current_subclass = 0;
+ filter_current_class_range = 0;
+ break;
+ case FILTER_MODE_SUBCLASS:
+ case FILTER_MODE_START:
+ case FILTER_MODE_CLASS_RANGE:
+ filter_mode = FILTER_MODE_START;
+ filter_current_class = 0;
+ filter_current_subclass = 0;
+ filter_current_class_range = 0;
+ break;
+ default:
+ quit_args("invalid case in filter_done_parsing\n");
+ }
+}
+
+/* Tell set_filter_subclass not to print every. single. subclass. */
+static boolean_t setting_class = FALSE;
+static boolean_t setting_range = FALSE;
+
+static void
+set_filter_subclass(uint8_t class, uint8_t subclass)
+{
+ if (!filter_alloced) {
+ type_filter_bitmap = (uint8_t *) calloc(1, KDBG_TYPEFILTER_BITMAP_SIZE);
+ if (type_filter_bitmap == NULL)
+ quit_args("Could not allocate type_filter_bitmap.\n");
+ filter_alloced = 1;
+ }
+
+ uint16_t csc = ENCODE_CSC_LOW(class, subclass);
+
+ if (verbose_flag && !setting_class)
+ printf("tracing subclass: 0x%4.4x\n", csc);
+
+ if (verbose_flag && isset(type_filter_bitmap, csc))
+ printf("class %u (0x%2.2x), subclass %u (0x%2.2x) set twice.\n",
+ class, class, subclass, subclass);
+
+ setbit(type_filter_bitmap, csc);
+}
+
+static void
+set_filter_class(uint8_t class)
+{
+ if (verbose_flag && !setting_range)
+ printf("tracing class: 0x%2.2x\n", class);
+
+ setting_class = TRUE;
+
+ for (int i = 0; i < 256; i++)
+ set_filter_subclass(class, i);
+
+ setting_class = FALSE;
+}
+
+static void
+set_filter_range(uint8_t class, uint8_t end)
+{
+ if (verbose_flag)
+ printf("tracing range: 0x%2.2x - 0x%2.2x\n", class, end);
+
+ setting_range = TRUE;
+
+ for (int i = class; i <= end; i++)
+ set_filter_class(i);
+
+ setting_range = FALSE;
+}
+
+/*
+ * Syntax of filter file:
+ * Hexadecimal numbers only
+ * Class:
+ * C 0xXX
+ * Subclass (includes class):
+ * S 0xXXXX
+ * Comment:
+ * # <string>
+ * TBD: Class ranges?
+ * TBD: K for -k flag?
+ */
+
+static void
+parse_filter_file(char *filename) {
+ FILE* file;
+ uint32_t current_line = 0;
+ uint32_t parsed_arg = 0;
+ int rval;
+
+ char line[256];
+
+ if ( (file = fopen(filename, "r")) == NULL ) {
+ quit_args("Failed to open filter description file %s: %s\n",
+ filename, strerror(errno));
+ }
+
+ if (verbose_flag)
+ printf("Parsing typefilter file: %s\n", filename);
+
+ while( fgets(line, sizeof(line), file) != NULL ) {
+ current_line++;
+
+ switch (line[0]) {
+ case 'C':
+ rval = sscanf(line, "C 0x%x\n", &parsed_arg);
+ if (rval != 1)
+ quit_args("invalid line %d of file %s: %s\n",
+ current_line, filename, line);
+ if (parsed_arg > 0xFF)
+ quit_args("line %d of file %s: %s\n"
+ "parsed as 0x%x, "
+ "class value must be 0x0-0xFF\n",
+ current_line, filename, line, parsed_arg);
+ set_filter_class((uint8_t)parsed_arg);
+ break;
+ case 'S':
+ rval = sscanf(line, "S 0x%x\n", &parsed_arg);
+ if (rval != 1)
+ quit_args("invalid line %d of file %s: %s\n",
+ current_line, filename, line);
+ if (parsed_arg > 0xFFFF)
+ quit_args("line %d of file %s: %s\n"
+ "parsed as 0x%x, "
+ "value must be 0x0-0xFFFF\n",
+ current_line, filename, line, parsed_arg);
+ set_filter_subclass(EXTRACT_CLASS_LOW(parsed_arg),
+ EXTRACT_SUBCLASS_LOW(parsed_arg));
+ break;
+ case '#':
+ // comment
+ break;
+ case '\n':
+ // empty line
+ break;
+ case '\0':
+ // end of file
+ break;
+ default:
+ quit_args("Invalid filter description file: %s\n"
+ "could not parse line %d: %s\n",
+ filename, current_line, line);
+ }
+ }
+
+ fclose(file);
+}
+
+
/*
* Find the debugid code in the list and return its index
*/
static int
-parse_codefile(char *filename)
+parse_codefile(const char *filename)
{
int fd;
- int i, j, count, line;
+ int i, j, line;
+ size_t count;
struct stat stat_buf;
unsigned long file_size;
char *file_addr, *endp;
* so it has to be handled specially.
*/
file_size = stat_buf.st_size;
-
+
if (stat_buf.st_size != 0)
{
if ((file_addr = mmap(0, stat_buf.st_size, PROT_READ|PROT_WRITE,
}
else
{
- printf("Error: Zero sized file: %s\n", filename);
+ // Skip empty files
close(fd);
- return(-1);
+ return(0);
}
close(fd);
*/
count++;
- if ((codesc = (code_type_t *)malloc(count * sizeof(code_type_t))) == 0 ) {
- printf("Failed to allocate buffer for code descriptions\n");
- return(-1);
- }
+ // Grow the size of codesc to store new entries.
+ size_t total_count = codesc_idx + count;
+ code_type_t *new_codesc = (code_type_t *)realloc(codesc, (total_count) * sizeof(code_type_t));
- bzero((char *)codesc, count * sizeof(code_type_t));
- codenum = 0;
+ if (new_codesc == NULL) {
+ printf("Failed to grow/allocate buffer. Skipping file %s\n", filename);
+ return (-1);
+ }
+ codesc = new_codesc;
+ bzero((char *)(codesc + codesc_idx), count * sizeof(code_type_t));
- for (line = 1, i = 0, j = 0; j < file_size && i < count ; i++)
+ for (line = 1, j = 0; j < file_size && codesc_idx < total_count; codesc_idx++)
{
/* Skip blank lines */
while (file_addr[j] == '\n')
j++;
/* Get the debugid code */
- codesc[i].debugid = strtoul(file_addr + j, &endp, 16);
+ codesc[codesc_idx].debugid = strtoul(file_addr + j, &endp, 16);
j = endp - file_addr;
- if (codesc[i].debugid == 0)
+ if (codesc[codesc_idx].debugid == 0)
{
/* We didn't find a debugid code - skip this line */
if (verbose_flag)
printf("Error: while parsing line %d, skip\n", line);
while (file_addr[j] != '\n' && j < file_size)
j++;
- i--;
+ codesc_idx--;
line++;
continue;
}
{
/* missing debugid string - skip */
if (verbose_flag)
- printf("Error: while parsing line %d, (0x%x) skip\n", line, codesc[i].debugid);
-
+ printf("Error: while parsing line %d, (0x%x) skip\n", line, codesc[codesc_idx].debugid);
+
j++;
- i--;
+ codesc_idx--;
line++;
continue;
}
/* Next is the debugid string terminated by a newline */
- codesc[i].debug_string = &file_addr[j];
+ codesc[codesc_idx].debug_string = &file_addr[j];
/* Null out the newline terminator */
while ((j < file_size) && (file_addr[j] != '\n'))
}
/* sort */
- qsort((void *)codesc, codenum, sizeof(code_type_t), debugid_compar);
+ qsort((void *)codesc, codesc_idx, sizeof(code_type_t), debugid_compar);
if (verbose_flag)
{
- printf("Sorted %d codes in %s\n", codenum, filename);
+ printf("Sorted %zd codes in %s\n", codesc_idx, filename);
printf("lowbound [%6d]: 0x%8x %s\n", 0, codesc[0].debugid, codesc[0].debug_string);
- printf("highbound [%6d]: 0x%8x %s\n\n", codenum-1, codesc[codenum-1].debugid, codesc[codenum-1].debug_string);
+ printf("highbound [%6zd]: 0x%8x %s\n\n", codesc_idx - 1, codesc[codesc_idx - 1].debugid, codesc[codesc_idx - 1].debug_string);
}
+ codesc_find_dupes();
#if 0
/* Dump the codefile */
- for (i = 0; i < codenum; i++)
+ for (i = 0; i < codesc_idx; i++)
printf("[%d] 0x%x %s\n",i+1, codesc[i].debugid, codesc[i].debug_string);
#endif
return(0);
}
+static void codesc_find_dupes(void)
+{
+ boolean_t found_dupes = FALSE;
+ if (codesc_idx == 0)
+ {
+ return;
+ }
+ uint32_t last_debugid = codesc[0].debugid;
+ for(int i = 1; i < codesc_idx; i++)
+ {
+ if(codesc[i].debugid == last_debugid)
+ {
+ found_dupes = TRUE;
+ if (verbose_flag) {
+ fprintf(stderr, "WARNING: The debugid 0x%"PRIx32" (%s) has already been defined as '%s'.\n", codesc[i].debugid, codesc[i].debug_string, codesc[i - 1].debug_string);
+ }
+ }
+ last_debugid = codesc[i].debugid;
+ }
+ if (found_dupes)
+ {
+ fprintf(stderr, "WARNING: One or more duplicate entries found in your codefiles, which will lead to unpredictable decoding behavior. Re-run with -v for more info\n");
+ }
+}
int match_debugid(unsigned int xx, char * debugstr, int * yy)
}
}
+void
+read_cpu_map(int fd)
+{
+ if (cpumap_header) {
+ free(cpumap_header);
+ cpumap_header = NULL;
+ cpumap = NULL;
+ }
+
+ /*
+ * To fit in the padding space of a VERSION1 file, the max possible
+ * cpumap size is one page.
+ */
+ cpumap_header = malloc(PAGE_SIZE);
+
+ if (readRAW_flag) {
+ /*
+ * cpu maps exist in a RAW_VERSION1+ header only
+ */
+ if (raw_header.version_no == RAW_VERSION1) {
+ off_t base_offset = lseek(fd, (off_t)0, SEEK_CUR);
+ off_t aligned_offset = (base_offset + (4095)) & ~4095; /* <rdar://problem/13500105> */
+
+ size_t padding_bytes = (size_t)(aligned_offset - base_offset);
+
+ if (read(fd, cpumap_header, padding_bytes) == padding_bytes) {
+ if (cpumap_header->version_no == RAW_VERSION1) {
+ cpumap = (kd_cpumap*)&cpumap_header[1];
+ }
+ }
+ }
+ } else {
+ int mib[3];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDCPUMAP;
+
+ size_t temp = PAGE_SIZE;
+ if (sysctl(mib, 3, cpumap_header, &temp, NULL, 0) == 0) {
+ if (PAGE_SIZE >= temp) {
+ if (cpumap_header->version_no == RAW_VERSION1) {
+ cpumap = (kd_cpumap*)&cpumap_header[1];
+ }
+ }
+ }
+ }
+
+ if (!cpumap) {
+ printf("Can't read the cpu map -- this is not fatal\n");
+ free(cpumap_header);
+ cpumap_header = NULL;
+ } else if (verbose_flag) {
+ /* Dump the initial cpumap */
+ printf("\nCPU\tName\n");
+ for (int i = 0; i < cpumap_header->cpu_count; i++) {
+ printf ("%2d\t%s\n", cpumap[i].cpu_id, cpumap[i].name);
+ }
+ printf("\n");
+ }
+}
int
-read_command_map(int fd, int count)
+read_command_map(int fd, uint32_t count)
{
int i;
size_t size;
}
}
if (readRAW_flag) {
- off_t offset;
-
if (read(fd, mapptr, size) != size) {
if (verbose_flag)
printf("Can't read the thread map -- this is not fatal\n");
free(mapptr);
mapptr = 0;
- return(size);
- }
- if (raw_header.version_no != RAW_VERSION0) {
- offset = lseek(fd, (off_t)0, SEEK_CUR);
- offset = (offset + (4095)) & ~4095;
-
- lseek(fd, offset, SEEK_SET);
+ return (int)size;
}
} else {
/* Now read the threadmap */
return(0);
}
}
- for (i = 0; i < total_threads; i++)
- create_map_entry(mapptr[i].thread, &mapptr[i].command[0]);
+ for (i = 0; i < total_threads; i++) {
+ if (mapptr[i].thread)
+ create_map_entry(mapptr[i].thread, &mapptr[i].command[0]);
+ }
if (verbose_flag) {
/* Dump the initial map */
printf("Size of maptable returned is %ld, thus %ld entries\n", size, (size/sizeof(kd_threadmap)));
printf("Thread Command\n");
- for (i = 0; i < total_threads; i++)
- {
+ for (i = 0; i < total_threads; i++) {
printf ("0x%lx %s\n",
mapptr[i].thread,
mapptr[i].command);
}
}
- return(size);
+ return (int)size;
}
--- /dev/null
+.\" Copyright (c) 2013, Apple Inc. All rights reserved.
+.\"
+.Dd Jan 16, 2013
+.Dt VM_PURGEABLE_STAT 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm vm_purgeable_stat
+.Nd Display purgeable memory information for processes on the system
+.Sh SYNOPSIS
+.Pp
+.Nm vm_purgeable_stat
+.Ar -s <interval>
+Show summary view for system-wide purgeable memory use. The <interval> specifies the refresh interval in secs.
+.Pp
+.Nm vm_purgeable_stat
+.Ar -p <pid>
+Show purgeable memory information for process <pid>
+.Pp
+.Nm vm_purgeable_stat
+.Ar -a
+Show purgeable memory information for all processes in the system
+.Sh DESCRIPTION
+The
+.Nm vm_purgeable_stat
+command prints information about the purgeable memory usage in the system. It shows the counts and sizes of purgeable objects in the system.
+.P
+.nf
+Following is an explanation of columns:
+Process-Name: Name of the process
+FIFO-PX : FIFO Purgeable objects at priority X. Each entry is of the form <count>/<size>
+OBSOLETE : Obselete Purgeable Objects. Each entry is of the form <count>/<size>
+LIFO-PX : LIFO Purgeable objects at priority X. Each entry is of the form <count>/<size>
+.fi
+.Sh SEE ALSO
+.Xr vm_stat 1
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <mach/mach.h>
+#include <mach/mach_types.h>
+#include <mach/task.h>
+#include <libproc.h>
+#include <mach/vm_purgable.h>
+
+#define USAGE "Usage: vm_purgeable_stat [-a | -p <pid> | -s <interval>]\n"
+#define PRIV_ERR_MSG "The option specified needs root priveleges."
+#define PROC_NAME_LEN 256
+#define KB 1024
+#define PURGEABLE_PRIO_LEVELS VM_VOLATILE_GROUP_SHIFT
+
+static inline int purge_info_size_adjust(uint64_t size);
+static inline char purge_info_unit(uint64_t size);
+void print_header(int summary_view);
+int get_system_tasks(task_array_t *tasks, mach_msg_type_number_t *count);
+int get_task_from_pid(int pid, task_t *task);
+void print_purge_info_task(task_t task, int pid);
+void print_purge_info_task_array(task_array_t tasks, mach_msg_type_number_t count);
+void print_purge_info_summary(int sleep_duration);
+
+static inline int purge_info_size_adjust(uint64_t size)
+{
+ while(size > KB)
+ size /= KB;
+ return (int)size;
+}
+
+static inline char purge_info_unit(uint64_t size)
+{
+ char sizes[] = {'B', 'K', 'M', 'G', 'T'};
+ int index = 0;
+
+ while(size > KB) {
+ index++;
+ size /= KB;
+ }
+ return sizes[index];
+}
+
+void print_header(int summary_view)
+{
+ if (!summary_view)
+ printf("%20s ", "Process-Name");
+
+ printf("%9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s\n",
+ "FIFO-P0", "FIFO-P1", "FIFO-P2", "FIFO-P3",
+ "FIFO-P4", "FIFO-P5", "FIFO-P6", "FIFO-P7",
+ "OBSOLETE",
+ "LIFO-P0", "LIFO-P1", "LIFO-P2", "LIFO-P3",
+ "LIFO-P4", "LIFO-P5", "LIFO-P6", "LIFO-P7"
+ );
+}
+
+int get_task_from_pid(int pid, task_t *task)
+{
+ kern_return_t kr;
+ if (geteuid() != 0) {
+ fprintf(stderr, "%s\n", PRIV_ERR_MSG);
+ return -1;
+ }
+ kr = task_for_pid(mach_task_self(), pid, task);
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "Failed to get task port for pid: %d\n", pid);
+ return -1;
+ }
+ return 0;
+}
+
+int get_system_tasks(task_array_t *tasks, mach_msg_type_number_t *count)
+{
+ processor_set_name_array_t psets;
+ mach_msg_type_number_t psetCount;
+ mach_port_t pset_priv;
+ kern_return_t ret;
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "%s\n", PRIV_ERR_MSG);
+ return -1;
+ }
+
+ ret = host_processor_sets(mach_host_self(), &psets, &psetCount);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "host_processor_sets() failed: %s\n", mach_error_string(ret));
+ return -1;
+ }
+ if (psetCount != 1) {
+ fprintf(stderr, "Assertion Failure: pset count greater than one (%d)\n", psetCount);
+ return -1;
+ }
+
+ /* convert the processor-set-name port to a privileged port */
+ ret = host_processor_set_priv(mach_host_self(), psets[0], &pset_priv);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "host_processor_set_priv() failed: %s\n", mach_error_string(ret));
+ return -1;
+ }
+ mach_port_deallocate(mach_task_self(), psets[0]);
+ vm_deallocate(mach_task_self(), (vm_address_t)psets, (vm_size_t)psetCount * sizeof(mach_port_t));
+
+ /* convert the processor-set-priv to a list of tasks for the processor set */
+ ret = processor_set_tasks(pset_priv, tasks, count);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "processor_set_tasks() failed: %s\n", mach_error_string(ret));
+ return -1;
+ }
+ mach_port_deallocate(mach_task_self(), pset_priv);
+ return 0;
+}
+
+void print_purge_info_task(task_t task, int pid)
+{
+ task_purgable_info_t info;
+ kern_return_t kr;
+ int i;
+ char pname[PROC_NAME_LEN];
+
+ kr = task_purgable_info(task, &info);
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "(pid: %d) task_purgable_info() failed: %s\n", pid, mach_error_string(kr));
+ return;
+ }
+ if (0 == proc_name(pid, pname, PROC_NAME_LEN))
+ strncpy(pname, "Unknown", 7);
+ pname[20] = 0;
+ printf("%20s ", pname);
+ for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
+ printf("%4u/%3d%c ", (unsigned)info.fifo_data[i].count, purge_info_size_adjust(info.fifo_data[i].size), purge_info_unit(info.fifo_data[i].size));
+ printf("%4u/%3d%c ", (unsigned)info.obsolete_data.count, purge_info_size_adjust(info.obsolete_data.size), purge_info_unit(info.obsolete_data.size));
+ for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
+ printf("%4u/%3d%c ", (unsigned)info.lifo_data[i].count, purge_info_size_adjust(info.lifo_data[i].size), purge_info_unit(info.lifo_data[i].size));
+ printf("\n");
+ return;
+}
+
+void print_purge_info_task_array(task_array_t tasks, mach_msg_type_number_t count)
+{
+ int i;
+ int pid;
+
+ for (i=0; i<count; i++) {
+ if (KERN_SUCCESS != pid_for_task(tasks[i], &pid))
+ continue;
+ print_purge_info_task(tasks[i], pid);
+ }
+ return;
+}
+
+void print_purge_info_summary(int sleep_duration)
+{
+ host_purgable_info_data_t info;
+ mach_msg_type_number_t count;
+ kern_return_t result;
+ int i;
+
+ while(1) {
+ count = HOST_VM_PURGABLE_COUNT;
+ result = host_info(mach_host_self(), HOST_VM_PURGABLE, (host_info_t)&info, &count);
+ if (result != KERN_SUCCESS)
+ break;
+ for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
+ printf("%4u/%3d%c ", (unsigned)info.fifo_data[i].count, purge_info_size_adjust(info.fifo_data[i].size), purge_info_unit(info.fifo_data[i].size));
+ printf("%4u/%3d%c ", (unsigned)info.obsolete_data.count, purge_info_size_adjust(info.obsolete_data.size), purge_info_unit(info.obsolete_data.size));
+ for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
+ printf("%4u/%3d%c ", (unsigned)info.lifo_data[i].count, purge_info_size_adjust(info.lifo_data[i].size), purge_info_unit(info.lifo_data[i].size));
+ printf("\n");
+ sleep(sleep_duration);
+ }
+ return;
+}
+
+int main(int argc, char *argv[])
+{
+
+ char ch;
+ int pid;
+ int sleep_duration;
+ task_array_t tasks;
+ task_t task;
+ mach_msg_type_number_t taskCount;
+ int noargs = 1;
+
+ while(1) {
+ ch = getopt(argc, argv, "ahp:s:");
+ if (ch == -1)
+ break;
+ noargs = 0;
+ switch(ch) {
+ case 'a':
+ if (get_system_tasks(&tasks, &taskCount) < 0)
+ break;
+ print_header(0);
+ print_purge_info_task_array(tasks, taskCount);
+ break;
+
+ case 'p':
+ pid = (int)strtol(optarg, NULL, 10);
+ if (pid < 0)
+ break;
+ if (get_task_from_pid(pid, &task) < 0)
+ break;
+ print_header(0);
+ print_purge_info_task(task, pid);
+ break;
+ case 's':
+ sleep_duration = (int)strtol(optarg, NULL, 10);
+ if (sleep_duration < 0)
+ break;
+ print_header(1);
+ print_purge_info_summary(sleep_duration);
+ break;
+ case '?':
+ case 'h':
+ default:
+ printf("%s", USAGE);
+ }
+ break;
+ }
+ if (noargs)
+ printf("%s", USAGE);
+ return 0;
+}
+
+
.Nd show Mach virtual memory statistics
.Sh SYNOPSIS
.Nm vm_stat
-.Op Ar interval
+.Oo
+.Op Fl c Ar count
+.Ar interval
+.Oc
.Sh DESCRIPTION
.Nm vm_stat
displays Mach virtual memory statistics. If the optional
.Ar interval
count of 1 displays the values per second). However, the first line
of output following each banner displays the system-wide totals for
-each statistic. The following values are displayed:
+each statistic.
+If a
+.Ar count
+is provided, the command will terminate after
+.Ar count
+intervals.
+The following values are displayed:
.Bl -tag -width indent
.It Pages free
the total number of free pages in the system.
the total number of pages currently in use and pageable.
.It Pages inactive
the total number of pages on the inactive list.
+.It Pages speculative
+the total number of pages on the speculative list.
+.It Pages throttled
+the total number of pages on the throttled list (not wired but not pageable).
.It Pages wired down
the total number of pages wired down. That is, pages that cannot be
paged out.
+.It Pages purgeable
+the total number of purgeable pages.
.It Translation faults
the number of times the "vm_fault" routine has been called.
.It Pages copy-on-write
.It Pages reactivated
the total number of pages that have been moved from the inactive list
to the active list (reactivated).
+.It Pages purged
+the total number of pages that have been purged.
+.It File-backed pages
+the total number of pages that are file-backed (non-swap)
+.It Anonymous pages
+the total number of pages that are anonymous
+.It Uncompressed pages
+the total number of pages (uncompressed) held within the compressor
+.It Pages used by VM compressor:
+the number of pages used to store compressed VM pages.
+.It Pages decompressed
+the total number of pages that have been decompressed by the VM compressor.
+.It Pages compressed
+the total number of pages that have been compressed by the VM compressor.
.It Pageins
-the number of requests for pages from a pager (such as the inode pager).
+the total number of requests for pages from a pager (such as the inode pager).
.It Pageouts
-the number of pages that have been paged out.
+the total number of pages that have been paged out.
+.It Swapins
+the total number of compressed pages that have been swapped out to disk.
+.It Swapouts
+the total number of compressed pages that have been swapped back in from disk.
.El
.Pp
If
.Ar interval
is not specified, then
.Nm vm_stat
-displays all accumulated statistics along with the page size and the
-object cache performance.
+displays all accumulated statistics along with the page size.
************************************************************************
*/
+#include <err.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <mach/mach.h>
vm_statistics64_data_t vm_stat, last;
-natural_t percent;
-int delay;
char *pgmname;
mach_port_t myHost;
vm_size_t pageSize = 4096; /* set to 4k default */
main(int argc, char *argv[])
{
- pgmname = argv[0];
- delay = 0;
+ double delay = 0.0;
+ int count = 0;
+ pgmname = argv[0];
setlinebuf (stdout);
- if (argc == 2) {
- if (sscanf(argv[1], "%d", &delay) != 1)
- usage();
- if (delay < 0)
+ int c;
+ while ((c = getopt (argc, argv, "c:")) != -1) {
+ switch (c) {
+ case 'c':
+ count = (int)strtol(optarg, NULL, 10);
+ if (count < 1) {
+ warnx("count must be positive");
+ usage();
+ }
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ argc -= optind; argv += optind;
+
+ if (argc == 1) {
+ delay = strtod(argv[0], NULL);
+ if (delay < 0.0)
usage();
+ } else if (argc > 1) {
+ usage();
}
myHost = mach_host_self();
pageSize = 4096;
}
- if (delay == 0) {
+ if (delay == 0.0) {
snapshot();
- }
- else {
- while (1) {
+ } else {
+ print_stats();
+ for (int i = 1; i < count || count == 0; i++ ){
+ usleep((int)(delay * USEC_PER_SEC));
print_stats();
- sleep(delay);
}
}
exit(EXIT_SUCCESS);
void
usage(void)
{
- fprintf(stderr, "usage: %s [ repeat-interval ]\n", pgmname);
+ fprintf(stderr, "usage: %s [[-c count] interval]\n", pgmname);
exit(EXIT_FAILURE);
}
sspstat("Pages active:", (uint64_t) (vm_stat.active_count));
sspstat("Pages inactive:", (uint64_t) (vm_stat.inactive_count));
sspstat("Pages speculative:", (uint64_t) (vm_stat.speculative_count));
+ sspstat("Pages throttled:", (uint64_t) (vm_stat.throttled_count));
sspstat("Pages wired down:", (uint64_t) (vm_stat.wire_count));
+ sspstat("Pages purgeable:", (uint64_t) (vm_stat.purgeable_count));
sspstat("\"Translation faults\":", (uint64_t) (vm_stat.faults));
sspstat("Pages copy-on-write:", (uint64_t) (vm_stat.cow_faults));
sspstat("Pages zero filled:", (uint64_t) (vm_stat.zero_fill_count));
sspstat("Pages reactivated:", (uint64_t) (vm_stat.reactivations));
+ sspstat("Pages purged:", (uint64_t) (vm_stat.purges));
+ sspstat("File-backed pages:", (uint64_t) (vm_stat.external_page_count));
+ sspstat("Anonymous pages:", (uint64_t) (vm_stat.internal_page_count));
+ sspstat("Pages stored in compressor:", (uint64_t) (vm_stat.total_uncompressed_pages_in_compressor));
+ sspstat("Pages occupied by compressor:", (uint64_t) (vm_stat.compressor_page_count));
+ sspstat("Decompressions:", (uint64_t) (vm_stat.decompressions));
+ sspstat("Compressions:", (uint64_t) (vm_stat.compressions));
sspstat("Pageins:", (uint64_t) (vm_stat.pageins));
sspstat("Pageouts:", (uint64_t) (vm_stat.pageouts));
-#if defined(__ppc__) /* vm_statistics are still 32-bit on ppc */
- printf("Object cache: %u hits of %u lookups (%u%% hit rate)\n",
-#else
- printf("Object cache: %llu hits of %llu lookups (%u%% hit rate)\n",
-#endif
- vm_stat.hits, vm_stat.lookups, percent);
-
+ sspstat("Swapins:", (uint64_t) (vm_stat.swapins));
+ sspstat("Swapouts:", (uint64_t) (vm_stat.swapouts));
}
void
sspstat(char *str, uint64_t n)
{
- printf("%-25s %16llu.\n", str, n);
+ printf("%-30s %16llu.\n", str, n);
}
void
{
get_stats(&vm_stat);
printf("Mach Virtual Memory Statistics: ");
- printf("(page size of %d bytes, cache hits %u%%)\n",
- (int) (pageSize), percent);
- printf("%6s %6s %6s %8s %6s %8s %8s %8s %8s %8s %8s\n",
- "free",
- "active",
- "spec",
- "inactive",
- "wire",
- "faults",
- "copy",
- "0fill",
- "reactive",
- "pageins",
- "pageout");
+ printf("(page size of %d bytes)\n",
+ (int) (pageSize));
+ printf("%8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %11s %9s %8s %8s %8s %8s %8s %8s %8s %8s\n",
+ "free",
+ "active",
+ "specul",
+ "inactive",
+ "throttle",
+ "wired",
+ "prgable",
+ "faults",
+ "copy",
+ "0fill",
+ "reactive",
+ "purged",
+ "file-backed",
+ "anonymous",
+ "cmprssed",
+ "cmprssor",
+ "dcomprs",
+ "comprs",
+ "pageins",
+ "pageout",
+ "swapins",
+ "swapouts");
bzero(&last, sizeof(last));
}
count = 0;
get_stats(&vm_stat);
- pstat((uint64_t) (vm_stat.free_count - vm_stat.speculative_count), 6);
- pstat((uint64_t) (vm_stat.active_count), 6);
- pstat((uint64_t) (vm_stat.speculative_count), 6);
+ pstat((uint64_t) (vm_stat.free_count - vm_stat.speculative_count), 8);
+ pstat((uint64_t) (vm_stat.active_count), 8);
+ pstat((uint64_t) (vm_stat.speculative_count), 8);
pstat((uint64_t) (vm_stat.inactive_count), 8);
- pstat((uint64_t) (vm_stat.wire_count), 6);
+ pstat((uint64_t) (vm_stat.throttled_count), 8);
+ pstat((uint64_t) (vm_stat.wire_count), 8);
+ pstat((uint64_t) (vm_stat.purgeable_count), 8);
pstat((uint64_t) (vm_stat.faults - last.faults), 8);
pstat((uint64_t) (vm_stat.cow_faults - last.cow_faults), 8);
pstat((uint64_t) (vm_stat.zero_fill_count - last.zero_fill_count), 8);
pstat((uint64_t) (vm_stat.reactivations - last.reactivations), 8);
+ pstat((uint64_t) (vm_stat.purges - last.purges), 8);
+ pstat((uint64_t) (vm_stat.external_page_count), 11);
+ pstat((uint64_t) (vm_stat.internal_page_count), 9);
+ pstat((uint64_t) (vm_stat.total_uncompressed_pages_in_compressor), 8);
+ pstat((uint64_t) (vm_stat.compressor_page_count), 8);
+ pstat((uint64_t) (vm_stat.decompressions - last.decompressions), 8);
+ pstat((uint64_t) (vm_stat.compressions - last.compressions), 8);
pstat((uint64_t) (vm_stat.pageins - last.pageins), 8);
pstat((uint64_t) (vm_stat.pageouts - last.pageouts), 8);
+ pstat((uint64_t) (vm_stat.swapins - last.swapins), 8);
+ pstat((uint64_t) (vm_stat.swapouts - last.swapouts), 8);
putchar('\n');
last = vm_stat;
}
width = sizeof(buf) -1;
}
- unsigned long long nb = n * (unsigned long long)pageSize;
-
/* Now that we have the speculative field, there is really not enough
space, but we were actually overflowing three or four fields before
anyway. So any field that overflows we drop some insignifigant
fprintf(stderr, "%s: failed to get statistics. error %d\n", pgmname, ret);
exit(EXIT_FAILURE);
}
- if (stat->lookups == 0)
- percent = 0;
- else {
- /*
- * We have limited precision with the 32-bit natural_t fields
- * in the vm_statistics structure. There's nothing we can do
- * about counter overflows, but we can avoid percentage
- * calculation overflows by doing the computation in floating
- * point arithmetic ...
- */
- percent = (natural_t)(((double)stat->hits*100)/stat->lookups);
- }
}
if [ "${PLATFORM_NAME}" = "iphoneos" ]; then
mkdir -p "${PRIVATEDIR}/var/db"
mkdir -p -m a+rwx "${PRIVATEDIR}/var/db/timezone"
- ln -hfs "/usr/share/zoneinfo/${LOCALTIME}" "${PRIVATEDIR}/var/db/timezone/localtime"
+
+ # This link must precisely start with TZDIR followed by a slash. radar:13532660
+ ln -hfs "/var/db/timezone/zoneinfo/${LOCALTIME}" "${PRIVATEDIR}/var/db/timezone/localtime"
else
mkdir -p "${PRIVATEDIR}/etc"
ln -hfs "/usr/share/zoneinfo/${LOCALTIME}" "${PRIVATEDIR}/etc/localtime"
--- /dev/null
+#!/bin/sh
+
+if [ "${PLATFORM_NAME}" = "iphoneos" ]; then
+ditto "${BUILT_PRODUCTS_DIR}/zoneinfo" "${DSTROOT}/usr/share/zoneinfo.default"
+ln -hfs "/var/db/timezone/zoneinfo" "${DSTROOT}/usr/share/zoneinfo"
+else
+ditto "${BUILT_PRODUCTS_DIR}/zoneinfo" "${DSTROOT}/usr/share/zoneinfo"
+fi