--- /dev/null
+ APPLE PUBLIC SOURCE LICENSE
+ Version 1.0 - March 16, 1999
+
+Please read this License carefully before downloading this software.
+By downloading and using this software, you are agreeing to be bound
+by the terms of this License. If you do not or cannot agree to the
+terms of this License, please do not download or use the software.
+
+1. General; Definitions. This License applies to any program or other
+ work which Apple Computer, Inc. ("Apple") publicly announces as
+ subject to this Apple Public Source License and which contains a
+ notice placed by Apple identifying such program or work as "Original
+ Code" and stating that it is subject to the terms of this Apple
+ Public Source License version 1.0 (or subsequent version thereof),
+ as it may be revised from time to time by Apple ("License"). As
+ used in this License:
+
+1.1 "Applicable Patents" mean: (a) in the case where Apple is the
+ grantor of rights, (i) patents or patent applications that are now
+ or hereafter acquired, owned by or assigned to Apple and (ii) whose
+ claims cover subject matter contained in the Original Code, but only
+ to the extent necessary to use, reproduce and/or distribute the
+ Original Code without infringement; and (b) in the case where You
+ are the grantor of rights, (i) patents and patent applications that
+ are now or hereafter acquired, owned by or assigned to You and (ii)
+ whose claims cover subject matter in Your Modifications, taken alone
+ or in combination with Original Code.
+
+1.2 "Covered Code" means the Original Code, Modifications, the
+ combination of Original Code and any Modifications, and/or any
+ respective portions thereof.
+
+1.3 "Deploy" means to use, sublicense or distribute Covered Code other
+ than for Your internal research and development (R&D), and includes
+ without limitation, any and all internal use or distribution of
+ Covered Code within Your business or organization except for R&D
+ use, as well as direct or indirect sublicensing or distribution of
+ Covered Code by You to any third party in any form or manner.
+
+1.4 "Larger Work" means a work which combines Covered Code or portions
+ thereof with code not governed by the terms of this License.
+
+1.5 "Modifications" mean any addition to, deletion from, and/or change
+ to, the substance and/or structure of Covered Code. When code is
+ released as a series of files, a Modification is: (a) any addition
+ to or deletion from the contents of a file containing Covered Code;
+ and/or (b) any new file or other representation of computer program
+ statements that contains any part of Covered Code.
+
+1.6 "Original Code" means the Source Code of a program or other work
+ as originally made available by Apple under this License, including
+ the Source Code of any updates or upgrades to such programs or works
+ made available by Apple under this License, and that has been
+ expressly identified by Apple as such in the header file(s) of such
+ work.
+
+1.7 "Source Code" means the human readable form of a program or other
+ work that is suitable for making modifications to it, including all
+ modules it contains, plus any associated interface definition files,
+ scripts used to control compilation and installation of an
+ executable (object code).
+
+1.8 "You" or "Your" means an individual or a legal entity exercising
+ rights under this License. For legal entities, "You" or "Your"
+ includes any entity which controls, is controlled by, or is under
+ common control with, You, where "control" means (a) the power,
+ direct or indirect, to cause the direction or management of such
+ entity, whether by contract or otherwise, or (b) ownership of fifty
+ percent (50%) or more of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. Permitted Uses; Conditions & Restrictions. Subject to the terms
+ and conditions of this License, Apple hereby grants You, effective
+ on the date You accept this License and download the Original Code,
+ a world-wide, royalty-free, non-exclusive license, to the extent of
+ Apple's Applicable Patents and copyrights covering the Original
+ Code, to do the following:
+
+2.1 You may use, copy, modify and distribute Original Code, with or
+ without Modifications, solely for Your internal research and
+ development, provided that You must in each instance:
+
+(a) retain and reproduce in all copies of Original Code the copyright
+and other proprietary notices and disclaimers of Apple as they appear
+in the Original Code, and keep intact all notices in the Original Code
+that refer to this License;
+
+(b) include a copy of this License with every copy of Source Code of
+Covered Code and documentation You distribute, and You may not offer
+or impose any terms on such Source Code that alter or restrict this
+License or the recipients' rights hereunder, except as permitted under
+Section 6; and
+
+(c) completely and accurately document all Modifications that you have
+made and the date of each such Modification, designate the version of
+the Original Code you used, prominently include a file carrying such
+information with the Modifications, and duplicate the notice in
+Exhibit A in each file of the Source Code of all such Modifications.
+
+2.2 You may Deploy Covered Code, provided that You must in each
+ instance:
+
+(a) satisfy all the conditions of Section 2.1 with respect to the
+Source Code of the Covered Code;
+
+(b) make all Your Deployed Modifications publicly available in Source
+Code form via electronic distribution (e.g. download from a web site)
+under the terms of this License and subject to the license grants set
+forth in Section 3 below, and any additional terms You may choose to
+offer under Section 6. You must continue to make the Source Code of
+Your Deployed Modifications available for as long as you Deploy the
+Covered Code or twelve (12) months from the date of initial
+Deployment, whichever is longer;
+
+(c) must notify Apple and other third parties of how to obtain Your
+Deployed Modifications by filling out and submitting the required
+information found at
+http://www.apple.com/publicsource/modifications.html; and
+
+(d) if you Deploy Covered Code in object code, executable form only,
+include a prominent notice, in the code itself as well as in related
+documentation, stating that Source Code of the Covered Code is
+available under the terms of this License with information on how and
+where to obtain such Source Code.
+
+3. Your Grants. In consideration of, and as a condition to, the
+ licenses granted to You under this License:
+
+(a) You hereby grant to Apple and all third parties a non-exclusive,
+royalty-free license, under Your Applicable Patents and other
+intellectual property rights owned or controlled by You, to use,
+reproduce, modify, distribute and Deploy Your Modifications of the
+same scope and extent as Apple's licenses under Sections 2.1 and 2.2;
+and
+
+(b) You hereby grant to Apple and its subsidiaries a non-exclusive,
+worldwide, royalty-free, perpetual and irrevocable license, under Your
+Applicable Patents and other intellectual property rights owned or
+controlled by You, to use, reproduce, execute, compile, display,
+perform, modify or have modified (for Apple and/or its subsidiaries),
+sublicense and distribute Your Modifications, in any form, through
+multiple tiers of distribution.
+
+4. Larger Works. You may create a Larger Work by combining Covered
+ Code with other code not governed by the terms of this License and
+ distribute the Larger Work as a single product. In each such
+ instance, You must make sure the requirements of this License are
+ fulfilled for the Covered Code or any portion thereof.
+
+5. Limitations on Patent License. Except as expressly stated in
+ Section 2, no other patent rights, express or implied, are granted
+ by Apple herein. Modifications and/or Larger Works may require
+ additional patent licenses from Apple which Apple may grant in its
+ sole discretion.
+
+6. Additional Terms. You may choose to offer, and to charge a fee
+ for, warranty, support, indemnity or liability obligations and/or
+ other rights consistent with the scope of the license granted herein
+ ("Additional Terms") to one or more recipients of Covered
+ Code. However, You may do so only on Your own behalf and as Your
+ sole responsibility, and not on behalf of Apple. You must obtain the
+ recipient's agreement that any such Additional Terms are offered by
+ You alone, and You hereby agree to indemnify, defend and hold Apple
+ harmless for any liability incurred by or claims asserted against
+ Apple by reason of any such Additional Terms.
+
+7. Versions of the License. Apple may publish revised and/or new
+ versions of this License from time to time. Each version will be
+ given a distinguishing version number. Once Original Code has been
+ published under a particular version of this License, You may
+ continue to use it under the terms of that version. You may also
+ choose to use such Original Code under the terms of any subsequent
+ version of this License published by Apple. No one other than Apple
+ has the right to modify the terms applicable to Covered Code created
+ under this License.
+
+8. NO WARRANTY OR SUPPORT. The Original Code may contain in whole or
+ in part pre-release, untested, or not fully tested works. The
+ Original Code may contain errors that could cause failures or loss
+ of data, and may be incomplete or contain inaccuracies. You
+ expressly acknowledge and agree that use of the Original Code, or
+ any portion thereof, is at Your sole and entire risk. THE ORIGINAL
+ CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT
+ OF ANY KIND AND APPLE AND APPLE'S LICENSOR(S) (FOR THE PURPOSES OF
+ SECTIONS 8 AND 9, APPLE AND APPLE'S LICENSOR(S) ARE COLLECTIVELY
+ REFERRED TO AS "APPLE") EXPRESSLY DISCLAIM ALL WARRANTIES AND/OR
+ CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY OR
+ SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT OF THIRD PARTY RIGHTS. APPLE DOES NOT WARRANT THAT
+ THE FUNCTIONS CONTAINED IN THE ORIGINAL CODE WILL MEET YOUR
+ REQUIREMENTS, OR THAT THE OPERATION OF THE ORIGINAL CODE WILL BE
+ UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN THE ORIGINAL CODE
+ WILL BE CORRECTED. NO ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN
+ BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE SHALL CREATE A
+ WARRANTY OR IN ANY WAY INCREASE THE SCOPE OF THIS WARRANTY. You
+ acknowledge that the Original Code is not intended for use in the
+ operation of nuclear facilities, aircraft navigation, communication
+ systems, or air traffic control machines in which case the failure
+ of the Original Code could lead to death, personal injury, or severe
+ physical or environmental damage.
+
+9. Liability.
+
+9.1 Infringement. If any of the Original Code becomes the subject of
+ a claim of infringement ("Affected Original Code"), Apple may, at
+ its sole discretion and option: (a) attempt to procure the rights
+ necessary for You to continue using the Affected Original Code; (b)
+ modify the Affected Original Code so that it is no longer
+ infringing; or (c) terminate Your rights to use the Affected
+ Original Code, effective immediately upon Apple's posting of a
+ notice to such effect on the Apple web site that is used for
+ implementation of this License.
+
+9.2 LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES SHALL APPLE BE
+ LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
+ DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR YOUR USE OR
+ INABILITY TO USE THE ORIGINAL CODE, OR ANY PORTION THEREOF, WHETHER
+ UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE),
+ PRODUCTS LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF
+ THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF
+ ESSENTIAL PURPOSE OF ANY REMEDY. In no event shall Apple's total
+ liability to You for all damages under this License exceed the
+ amount of fifty dollars ($50.00).
+
+10. Trademarks. This License does not grant any rights to use the
+ trademarks or trade names "Apple", "Apple Computer", "Mac OS X",
+ "Mac OS X Server" or any other trademarks or trade names belonging
+ to Apple (collectively "Apple Marks") and no Apple Marks may be
+ used to endorse or promote products derived from the Original Code
+ other than as permitted by and in strict compliance at all times
+ with Apple's third party trademark usage guidelines which are
+ posted at http://www.apple.com/legal/guidelinesfor3rdparties.html.
+
+11. Ownership. Apple retains all rights, title and interest in and to
+ the Original Code and any Modifications made by or on behalf of
+ Apple ("Apple Modifications"), and such Apple Modifications will
+ not be automatically subject to this License. Apple may, at its
+ sole discretion, choose to license such Apple Modifications under
+ this License, or on different terms from those contained in this
+ License or may choose not to license them at all. Apple's
+ development, use, reproduction, modification, sublicensing and
+ distribution of Covered Code will not be subject to this License.
+
+12. Termination.
+
+12.1 Termination. This License and the rights granted hereunder will
+ terminate:
+
+(a) automatically without notice from Apple if You fail to comply with
+any term(s) of this License and fail to cure such breach within 30
+days of becoming aware of such breach; (b) immediately in the event of
+the circumstances described in Sections 9.1 and/or 13.6(b); or (c)
+automatically without notice from Apple if You, at any time during the
+term of this License, commence an action for patent infringement
+against Apple.
+
+12.2 Effect of Termination. Upon termination, You agree to
+ immediately stop any further use, reproduction, modification and
+ distribution of the Covered Code, or Affected Original Code in the
+ case of termination under Section 9.1, and to destroy all copies of
+ the Covered Code or Affected Original Code (in the case of
+ termination under Section 9.1) that are in your possession or
+ control. All sublicenses to the Covered Code which have been
+ properly granted prior to termination shall survive any termination
+ of this License. Provisions which, by their nature, should remain
+ in effect beyond the termination of this License shall survive,
+ including but not limited to Sections 3, 5, 8, 9, 10, 11, 12.2 and
+ 13. Neither party will be liable to the other for compensation,
+ indemnity or damages of any sort solely as a result of terminating
+ this License in accordance with its terms, and termination of this
+ License will be without prejudice to any other right or remedy of
+ either party.
+
+13. Miscellaneous.
+
+13.1 Export Law Assurances. You may not use or otherwise export or
+ re-export the Original Code except as authorized by United States
+ law and the laws of the jurisdiction in which the Original Code was
+ obtained. In particular, but without limitation, the Original Code
+ may not be exported or re-exported (a) into (or to a national or
+ resident of) any U.S. embargoed country or (b) to anyone on the
+ U.S. Treasury Department's list of Specially Designated Nationals
+ or the U.S. Department of Commerce's Table of Denial Orders. By
+ using the Original Code, You represent and warrant that You are not
+ located in, under control of, or a national or resident of any such
+ country or on any such list.
+
+13.2 Government End Users. The Covered Code is a "commercial item" as
+ defined in FAR 2.101. Government software and technical data
+ rights in the Covered Code include only those rights customarily
+ provided to the public as defined in this License. This customary
+ commercial license in technical data and software is provided in
+ accordance with FAR 12.211 (Technical Data) and 12.212 (Computer
+ Software) and, for Department of Defense purchases, DFAR
+ 252.227-7015 (Technical Data -- Commercial Items) and 227.7202-3
+ (Rights in Commercial Computer Software or Computer Software
+ Documentation). Accordingly, all U.S. Government End Users acquire
+ Covered Code with only those rights set forth herein.
+
+13.3 Relationship of Parties. This License will not be construed as
+ creating an agency, partnership, joint venture or any other form of
+ legal association between You and Apple, and You will not represent
+ to the contrary, whether expressly, by implication, appearance or
+ otherwise.
+
+13.4 Independent Development. Nothing in this License will impair
+ Apple's right to acquire, license, develop, have others develop for
+ it, market and/or distribute technology or products that perform
+ the same or similar functions as, or otherwise compete with,
+ Modifications, Larger Works, technology or products that You may
+ develop, produce, market or distribute.
+
+13.5 Waiver; Construction. Failure by Apple to enforce any provision
+ of this License will not be deemed a waiver of future enforcement
+ of that or any other provision. Any law or regulation which
+ provides that the language of a contract shall be construed against
+ the drafter will not apply to this License.
+
+13.6 Severability. (a) If for any reason a court of competent
+ jurisdiction finds any provision of this License, or portion
+ thereof, to be unenforceable, that provision of the License will be
+ enforced to the maximum extent permissible so as to effect the
+ economic benefits and intent of the parties, and the remainder of
+ this License will continue in full force and effect. (b)
+ Notwithstanding the foregoing, if applicable law prohibits or
+ restricts You from fully and/or specifically complying with
+ Sections 2 and/or 3 or prevents the enforceability of either of
+ those Sections, this License will immediately terminate and You
+ must immediately discontinue any use of the Covered Code and
+ destroy all copies of it that are in your possession or control.
+
+13.7 Dispute Resolution. Any litigation or other dispute resolution
+ between You and Apple relating to this License shall take place in
+ the Northern District of California, and You and Apple hereby
+ consent to the personal jurisdiction of, and venue in, the state
+ and federal courts within that District with respect to this
+ License. The application of the United Nations Convention on
+ Contracts for the International Sale of Goods is expressly
+ excluded.
+
+13.8 Entire Agreement; Governing Law. This License constitutes the
+ entire agreement between the parties with respect to the subject
+ matter hereof. This License shall be governed by the laws of the
+ United States and the State of California, except that body of
+ California law concerning conflicts of law.
+
+Where You are located in the province of Quebec, Canada, the following
+clause applies: The parties hereby confirm that they have requested
+that this License and all related documents be drafted in English. Les
+parties ont exige que le present contrat et tous les documents
+connexes soient rediges en anglais.
+
+EXHIBIT A.
+
+"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."
--- /dev/null
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)ac.8 8.2 (Berkeley) 4/19/94
+.\"
+.Dd April 19, 1994
+.Dt AC 8
+.Os BSD 4
+.Sh NAME
+.Nm ac
+.Nd display connect-time accounting
+.Sh SYNOPSIS
+.Nm ac
+.Op Fl d
+.Op Fl p
+.Op Fl w Ar file
+.Op Ar users ...
+.Sh DESCRIPTION
+A record of individual
+login and logout times are written to the system log by
+.Xr login 8
+and
+.Xr launchd 8 ,
+respectively.
+The program
+.Nm ac
+examines these records
+and writes the accumulated connect time (in decimal hours)
+for all logins to the standard output.
+.Pp
+Options available:
+.Bl -tag -width people
+.It Fl d
+Display the connect times in 24 hour chunks.
+.It Fl p
+Display individual user totals.
+.It Fl w Ar file
+Read raw connect time data from
+.Ar file ,
+instead of the system log.
+.It Ar users ...
+Display totals for the given individuals
+only.
+.El
+.Pp
+If no arguments are given,
+.Nm ac
+displays the total amount of login time
+for all active accounts on the system.
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr utmpx 5 ,
+.Xr launchd 8 ,
+.Xr sa 8
+.Sh HISTORY
+An
+.Nm ac
+command appeared in Version 6 AT&T UNIX.
--- /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) 1994 Christopher G. Demetriou.
+ * @(#)Copyright (c) 1994, Simon J. Gerraty.
+ *
+ * This is free software. It comes with NO WARRANTY.
+ * Permission to use, modify and distribute this source code
+ * is granted subject to the following conditions.
+ * 1/ that the above copyright notice and this notice
+ * are preserved in all copies and that due credit be given
+ * to the author.
+ * 2/ that any changes to this code are clearly commented
+ * as such so that the author does not get blamed for bugs
+ * other than his own.
+ */
+
+#ifndef lint
+#include <sys/cdefs.h>
+__unused static char rcsid[] = "$Id: ac.c,v 1.2 2006/02/07 05:51:22 lindak Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utmpx.h>
+#include <unistd.h>
+
+#define UT_NAMESIZE 8 /* from utmp.h; only for formatting */
+
+/*
+ * this is for our list of currently logged in sessions
+ */
+struct utmp_list {
+ struct utmp_list *next;
+ struct utmpx usr;
+};
+
+/*
+ * this is for our list of users that are accumulating time.
+ */
+struct user_list {
+ struct user_list *next;
+ char name[_UTX_USERSIZE+1];
+ time_t secs;
+};
+
+/*
+ * this is for chosing whether to ignore a login
+ */
+struct tty_list {
+ struct tty_list *next;
+ char name[_UTX_USERSIZE+3];
+ int len;
+ int ret;
+};
+
+/*
+ * globals - yes yuk
+ */
+#ifdef CONSOLE_TTY
+static char *Console = CONSOLE_TTY;
+#endif
+static time_t Total = 0;
+static time_t FirstTime = 0;
+static int Flags = 0;
+static struct user_list *Users = NULL;
+static struct tty_list *Ttys = NULL;
+
+#define NEW(type) (type *)malloc(sizeof (type))
+
+#define AC_W 1 /* not _PATH_WTMP */
+#define AC_D 2 /* daily totals (ignore -p) */
+#define AC_P 4 /* per-user totals */
+#define AC_U 8 /* specified users only */
+#define AC_T 16 /* specified ttys only */
+
+#ifdef DEBUG
+static int Debug = 0;
+#endif
+
+int main __P((int, char **));
+int ac __P((void));
+struct tty_list *add_tty __P((char *));
+int do_tty __P((char *));
+struct utmp_list *log_in __P((struct utmp_list *, struct utmpx *));
+struct utmp_list *log_out __P((struct utmp_list *, struct utmpx *));
+int on_console __P((struct utmp_list *));
+void show __P((char *, time_t));
+void show_today __P((struct user_list *, struct utmp_list *,
+ time_t));
+void show_users __P((struct user_list *));
+struct user_list *update_user __P((struct user_list *, char *, time_t));
+void usage __P((void));
+
+struct tty_list *
+add_tty(name)
+ char *name;
+{
+ struct tty_list *tp;
+ register char *rcp;
+
+ Flags |= AC_T;
+
+ if ((tp = NEW(struct tty_list)) == NULL)
+ err(1, "malloc");
+ tp->len = 0; /* full match */
+ tp->ret = 1; /* do if match */
+ if (*name == '!') { /* don't do if match */
+ tp->ret = 0;
+ name++;
+ }
+ (void)strncpy(tp->name, name, sizeof (tp->name) - 1);
+ tp->name[sizeof (tp->name) - 1] = '\0';
+ if ((rcp = strchr(tp->name, '*')) != NULL) { /* wild card */
+ *rcp = '\0';
+ tp->len = strlen(tp->name); /* match len bytes only */
+ }
+ tp->next = Ttys;
+ Ttys = tp;
+ return Ttys;
+}
+
+/*
+ * should we process the named tty?
+ */
+int
+do_tty(name)
+ char *name;
+{
+ struct tty_list *tp;
+ int def_ret = 0;
+
+ for (tp = Ttys; tp != NULL; tp = tp->next) {
+ if (tp->ret == 0) /* specific don't */
+ def_ret = 1; /* default do */
+ if (tp->len != 0) {
+ if (strncmp(name, tp->name, tp->len) == 0)
+ return tp->ret;
+ } else {
+ if (strncmp(name, tp->name, sizeof (tp->name)) == 0)
+ return tp->ret;
+ }
+ }
+ return def_ret;
+}
+
+#ifdef CONSOLE_TTY
+/*
+ * is someone logged in on Console?
+ */
+int
+on_console(head)
+ struct utmp_list *head;
+{
+ struct utmp_list *up;
+
+ for (up = head; up; up = up->next) {
+ if (strncmp(up->usr.ut_line, Console,
+ sizeof (up->usr.ut_line)) == 0)
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+/*
+ * update user's login time
+ */
+struct user_list *
+update_user(head, name, secs)
+ struct user_list *head;
+ char *name;
+ time_t secs;
+{
+ struct user_list *up;
+
+ for (up = head; up != NULL; up = up->next) {
+ if (strncmp(up->name, name, sizeof (up->name)) == 0) {
+ up->secs += secs;
+ Total += secs;
+ return head;
+ }
+ }
+ /*
+ * not found so add new user unless specified users only
+ */
+ if (Flags & AC_U)
+ return head;
+
+ if ((up = NEW(struct user_list)) == NULL)
+ err(1, "malloc");
+ up->next = head;
+ (void)strncpy(up->name, name, sizeof (up->name) - 1);
+ up->name[sizeof (up->name) - 1] = '\0'; /* paranoid! */
+ up->secs = secs;
+ Total += secs;
+ return up;
+}
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *fp;
+ int c;
+
+ fp = NULL;
+ while ((c = getopt(argc, argv, "Dc:dpt:w:")) != EOF) {
+ switch (c) {
+#ifdef DEBUG
+ case 'D':
+ Debug++;
+ break;
+#endif
+ case 'c':
+#ifdef CONSOLE_TTY
+ Console = optarg;
+#else
+ usage(); /* XXX */
+#endif
+ break;
+ case 'd':
+ Flags |= AC_D;
+ break;
+ case 'p':
+ Flags |= AC_P;
+ break;
+ case 't': /* only do specified ttys */
+ add_tty(optarg);
+ break;
+ case 'w':
+ wtmpxname(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+ if (optind < argc) {
+ /*
+ * initialize user list
+ */
+ for (; optind < argc; optind++) {
+ Users = update_user(Users, argv[optind], 0L);
+ }
+ Flags |= AC_U; /* freeze user list */
+ }
+ if (Flags & AC_D)
+ Flags &= ~AC_P;
+ ac();
+
+ return 0;
+}
+
+/*
+ * print login time in decimal hours
+ */
+void
+show(name, secs)
+ char *name;
+ time_t secs;
+{
+ (void)printf("\t%-*s %8.2f\n", UT_NAMESIZE, name,
+ ((double)secs / 3600));
+}
+
+void
+show_users(list)
+ struct user_list *list;
+{
+ struct user_list *lp;
+
+ for (lp = list; lp; lp = lp->next)
+ show(lp->name, lp->secs);
+}
+
+/*
+ * print total login time for 24hr period in decimal hours
+ */
+void
+show_today(users, logins, secs)
+ struct user_list *users;
+ struct utmp_list *logins;
+ time_t secs;
+{
+ struct user_list *up;
+ struct utmp_list *lp;
+ char date[64];
+ time_t yesterday = secs - 1;
+
+ (void)strftime(date, sizeof (date), "%b %e total",
+ localtime(&yesterday));
+
+ /* restore the missing second */
+ yesterday++;
+
+ for (lp = logins; lp != NULL; lp = lp->next) {
+ secs = yesterday - lp->usr.ut_tv.tv_sec;
+ Users = update_user(Users, lp->usr.ut_user, secs);
+ lp->usr.ut_tv.tv_sec = yesterday; /* as if they just logged in */
+ }
+ secs = 0;
+ for (up = users; up != NULL; up = up->next) {
+ secs += up->secs;
+ up->secs = 0; /* for next day */
+ }
+ if (secs)
+ (void)printf("%s %11.2f\n", date, ((double)secs / 3600));
+}
+
+/*
+ * log a user out and update their times.
+ * if ut_line is "~", we log all users out as the system has
+ * been shut down.
+ */
+struct utmp_list *
+log_out(head, up)
+ struct utmp_list *head;
+ struct utmpx *up;
+{
+ struct utmp_list *lp, *lp2, *tlp;
+ time_t secs;
+
+ for (lp = head, lp2 = NULL; lp != NULL; )
+ if (up->ut_type == BOOT_TIME || up->ut_type == SHUTDOWN_TIME || strncmp(lp->usr.ut_line, up->ut_line,
+ sizeof (up->ut_line)) == 0) {
+ secs = up->ut_tv.tv_sec - lp->usr.ut_tv.tv_sec;
+ Users = update_user(Users, lp->usr.ut_user, secs);
+#ifdef DEBUG
+ if (Debug)
+ printf("%-.*s %-.*s: %-.*s logged out (%2d:%02d:%02d)\n",
+ 19, ctime(&up->ut_tv.tv_sec),
+ (int)sizeof (lp->usr.ut_line), lp->usr.ut_line,
+ (int)sizeof (lp->usr.ut_user), lp->usr.ut_user,
+ secs / 3600, (secs % 3600) / 60, secs % 60);
+#endif
+ /*
+ * now lose it
+ */
+ tlp = lp;
+ lp = lp->next;
+ if (tlp == head)
+ head = lp;
+ else if (lp2 != NULL)
+ lp2->next = lp;
+ free(tlp);
+ } else {
+ lp2 = lp;
+ lp = lp->next;
+ }
+ return head;
+}
+
+
+/*
+ * if do_tty says ok, login a user
+ */
+struct utmp_list *
+log_in(head, up)
+ struct utmp_list *head;
+ struct utmpx *up;
+{
+ struct utmp_list *lp;
+
+ /*
+ * this could be a login. if we're not dealing with
+ * the console name, say it is.
+ *
+ * If we are, and if ut_host==":0.0" we know that it
+ * isn't a real login. _But_ if we have not yet recorded
+ * someone being logged in on Console - due to the wtmp
+ * file starting after they logged in, we'll pretend they
+ * logged in, at the start of the wtmp file.
+ */
+
+#ifdef CONSOLE_TTY
+ if (up->ut_host[0] == ':') {
+ /*
+ * SunOS 4.0.2 does not treat ":0.0" as special but we
+ * do.
+ */
+ if (on_console(head))
+ return head;
+ /*
+ * ok, no recorded login, so they were here when wtmp
+ * started! Adjust ut_tv.tv_sec!
+ */
+ up->ut_tv.tv_sec = FirstTime;
+ /*
+ * this allows us to pick the right logout
+ */
+ (void)strncpy(up->ut_line, Console, sizeof (up->ut_line) - 1);
+ up->ut_line[sizeof (up->ut_line) - 1] = '\0'; /* paranoid! */
+ }
+#endif
+ /*
+ * If we are doing specified ttys only, we ignore
+ * anything else.
+ */
+ if (Flags & AC_T)
+ if (!do_tty(up->ut_line))
+ return head;
+
+ /*
+ * go ahead and log them in
+ */
+ if ((lp = NEW(struct utmp_list)) == NULL)
+ err(1, "malloc");
+ lp->next = head;
+ head = lp;
+ memmove((char *)&lp->usr, (char *)up, sizeof (struct utmpx));
+#ifdef DEBUG
+ if (Debug) {
+ printf("%-.*s %-.*s: %-.*s logged in", 19,
+ ctime(&lp->usr.ut_tv.tv_sec), (int)sizeof (up->ut_line),
+ up->ut_line, (int)sizeof (up->ut_user), up->ut_user);
+ if (*up->ut_host)
+ printf(" (%-.*s)", (int)sizeof (up->ut_host), up->ut_host);
+ putchar('\n');
+ }
+#endif
+ return head;
+}
+
+int
+ac()
+{
+ struct utmp_list *lp, *head = NULL;
+ struct utmpx *u, end;
+ struct tm *ltm;
+ time_t secs = 0;
+ int day = -1;
+
+ setutxent_wtmp(1); /* read in forward direction */
+ while ((u = getutxent_wtmp()) != NULL) {
+ if (!FirstTime)
+ FirstTime = u->ut_tv.tv_sec;
+ if (Flags & AC_D) {
+ ltm = localtime(&u->ut_tv.tv_sec);
+ if (day >= 0 && day != ltm->tm_yday) {
+ day = ltm->tm_yday;
+ /*
+ * print yesterday's total
+ */
+ secs = u->ut_tv.tv_sec;
+ secs -= ltm->tm_sec;
+ secs -= 60 * ltm->tm_min;
+ secs -= 3600 * ltm->tm_hour;
+ show_today(Users, head, secs);
+ } else
+ day = ltm->tm_yday;
+ }
+ switch(u->ut_type) {
+ case OLD_TIME:
+ secs = u->ut_tv.tv_sec;
+ break;
+ case NEW_TIME:
+ secs -= u->ut_tv.tv_sec;
+ /*
+ * adjust time for those logged in
+ */
+ for (lp = head; lp != NULL; lp = lp->next)
+ lp->usr.ut_tv.tv_sec -= secs;
+ break;
+ case BOOT_TIME: /* reboot or shutdown */
+ case SHUTDOWN_TIME:
+ head = log_out(head, u);
+ FirstTime = u->ut_tv.tv_sec; /* shouldn't be needed */
+ break;
+ case USER_PROCESS:
+ /*
+ * if they came in on tty[p-y]*, then it is only
+ * a login session if the ut_host field is non-empty
+ */
+ if (strncmp(u->ut_line, "tty", 3) != 0 ||
+ strchr("pqrstuvwxy", u->ut_line[3]) == 0 ||
+ *u->ut_host != '\0')
+ head = log_in(head, u);
+ break;
+ case DEAD_PROCESS:
+ head = log_out(head, u);
+ break;
+ }
+ }
+ endutxent_wtmp();
+ bzero(&end, sizeof(end));
+ end.ut_tv.tv_sec = time((time_t *)0);
+ end.ut_type = SHUTDOWN_TIME;
+
+ if (Flags & AC_D) {
+ ltm = localtime(&end.ut_tv.tv_sec);
+ if (day >= 0 && day != ltm->tm_yday) {
+ /*
+ * print yesterday's total
+ */
+ secs = end.ut_tv.tv_sec;
+ secs -= ltm->tm_sec;
+ secs -= 60 * ltm->tm_min;
+ secs -= 3600 * ltm->tm_hour;
+ show_today(Users, head, secs);
+ }
+ }
+ /*
+ * anyone still logged in gets time up to now
+ */
+ head = log_out(head, &end);
+
+ if (Flags & AC_D)
+ show_today(Users, head, time((time_t *)0));
+ else {
+ if (Flags & AC_P)
+ show_users(Users);
+ show("total", Total);
+ }
+ return 0;
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+#ifdef CONSOLE_TTY
+ "ac [-dp] [-c console] [-t tty] [-w wtmp] [users ...]\n");
+#else
+ "ac [-dp] [-t tty] [-w wtmp] [users ...]\n");
+#endif
+ exit(1);
+}
--- /dev/null
+.\" $FreeBSD: src/usr.sbin/accton/accton.8,v 1.13 2004/04/16 09:31:17 brueffer Exp $
+.\"
+.Dd May 21, 1993
+.Dt ACCTON 8
+.Os
+.Sh NAME
+.Nm accton
+.Nd enable/disable system accounting
+.Sh SYNOPSIS
+.Nm
+.Op Ar acctfile
+.Sh DESCRIPTION
+The
+.Nm
+utility is used
+for switching system accounting on or off.
+If called with the argument
+.Ar acctfile ,
+system accounting is enabled.
+The
+.Ar acctfile
+specified must exist prior to starting system accounting, or
+.Nm
+will return an error.
+A record of every process that is started by the
+.Xr execve 2
+system call and then later exits the system is stored in
+.Ar acctfile .
+The
+.Xr sa 8
+command may be used to examine the accounting records.
+If no arguments are given, system accounting is disabled.
+.Sh FILES
+.Bl -tag -width /var/account/acct
+.It Pa /var/account/acct
+default accounting file
+.El
+.Sh SEE ALSO
+.Xr lastcomm 1 ,
+.Xr acct 2 ,
+.Xr acct 5 ,
+.Xr sa 8
--- /dev/null
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)accton.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/accton/accton.c,v 1.8 2004/08/07 04:19:37 imp Exp $");
+
+#include <sys/types.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch(ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch(argc) {
+ case 0:
+ if (acct(NULL))
+ err(1, NULL);
+ break;
+ case 1:
+ if (acct(*argv))
+ err(1, "%s", *argv);
+ break;
+ default:
+ usage();
+ }
+ exit(0);
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr, "usage: accton [file]\n");
+ exit(1);
+}
--- /dev/null
+.\" Copyright (c) 1994 SigmaSoft, Th. Lockert
+.\" 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 SigmaSoft, Th. Lockert.
+.\" 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.
+.\"
+.\" $OpenBSD: arch.1,v 1.2 1996/06/29 20:29:34 tholo Exp $
+.\"
+.\" Modifications made 8/20/97 (c) Apple Computer, Inc.
+.\" Modifications made 11/12/06 (c) Apple Computer, Inc.
+
+.Dd July 8, 2010
+.Dt ARCH 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm arch
+.Nd print architecture type or run selected architecture of a universal binary
+.Sh SYNOPSIS
+.Nm arch
+.Nm arch
+.Op Fl 32
+.Op Fl 64
+.Oo
+.Oo Fl Ns Ar arch_name | Fl arch Ar arch_name Oc Ns ...
+.Oc
+.Op Fl c
+.Oo Fl d Ar envname Oc Ns ...
+.Oo Fl e Ar envname=value Oc Ns ...
+.Op Fl h
+.Ar prog
+.Op Ar args No ...
+.Sh DESCRIPTION
+The
+.Nm arch
+command with no arguments, displays the machine's architecture type.
+.Pp
+The other use of the
+.Nm arch
+command it to run a selected architecture of a universal binary.
+A universal binary contains code that can run on different architectures.
+By default, the operating system will select the architecture that most closely
+matches the processor type.
+This means that an intel architecture is selected on intel processors and a
+powerpc architecture is selected on powerpc processors.
+A 64-bit architecture is preferred over a 32-bit architecture on a 64-bit
+processor, while only 32-bit architectures can run on a 32-bit processor.
+.Pp
+When the most natural architecture is unavailable, the operating system will
+try to pick another architecture.
+On 64-bit processors, a 32-bit architecture is tried.
+If this is also unavailable, the operating system on an intel processor will
+try running a 32-bit powerpc architecture.
+Otherwise, no architecture is run, and an error results.
+.Pp
+The
+.Nm arch
+command can be used to alter the operating system's normal selection order.
+The most common use is to select the 32-bit architecture on a 64-bit processor,
+even if a 64-bit architecture is available.
+.Pp
+The
+.Ar arch_name
+argument must be one of the currently supported architectures:
+.Bl -tag -width x86_64 -offset indent
+.It i386
+32-bit intel
+.It x86_64
+64-bit intel
+.El
+.Pp
+Either prefix the architecture with a hyphen, or (for compatibility with
+other commands), use
+.Fl arch
+followed by the architecture.
+.Pp
+If more than one architecture is specified, the operating system will try each
+one in order, skipping an architecture that is not supported on the current
+processor, or is unavailable in the universal binary.
+.Pp
+The other options are:
+.Bl -tag -width ".Fl e Ar envname=value"
+.It Fl 32
+Add the native 32-bit architecture to the list of architectures.
+.It Fl 64
+Add the native 64-bit architecture to the list of architectures.
+.It Fl c
+Clears the environment that will be passed to the command to be run.
+.It Fl d Ar envname
+Deletes the named environment variable from the environment that will be passed
+to the command to be run.
+.It Fl e Ar envname=value
+Assigns the given value to the named environment variable in the environment
+that will be passed to the command to be run.
+Any existing environment variable with the same name will be replaced.
+.It Fl h
+Prints a usage message and exits.
+.El
+.Pp
+The
+.Ar prog
+argument is the command to run, followed by any arguments to pass to the
+command.
+It can be a full or partial path, while a lone name will be looked up in the user's
+command search path.
+.Pp
+If no architectures are specified on the command line, the
+.Nm arch
+command takes the basename of the
+.Ar prog
+argument and searches for the first property list file with that basename and
+the
+.Pa \&.plist
+suffix, in the
+.Pa archSettings
+sub-directory in each of the standard domains, in the following order:
+.Bl -tag -width ".Pa /Network/Library/archSettings" -offset indent
+.It ~/Library/archSettings
+User settings
+.It /Library/archSettings
+Local settings
+.It /Network/Library/archSettings
+Network settings
+.It /System/Library/archSettings
+System settings
+.El
+.Pp
+This property list contains the architecture order preferences, as well
+as the full path to the real executable.
+For examples of the property list format, look at the files in
+.Pa /System/Library/archSettings .
+.Ss Example
+On an intel processor:
+.Bd -literal -offset indent
+% perl -MConfig -e 'printf "%s\\n", $Config{byteorder}'
+1234
+.Ed
+.Pp
+shows the intel little endian byte order.
+.Ss Making links to the arch command
+When a link is made to
+.Nm arch
+command with a different name, that name is used to find
+the corresponding property list file.
+Thus, other commands can be wrapped so that they have custom architecture
+selection order.
+.Pp
+Because of some internal logic in the code, hard links to the
+.Nm arch
+command may not work quite right.
+It is best to avoid using hard links, and only use symbolic links to the
+.Nm arch
+command.
+.Ss Environment
+The environment variable
+.Ev ARCHPREFERENCE
+can be used to provide architecture order preferences.
+It is checked before looking for the corresponding property list file.
+.Pp
+The value of the environment variable
+.Ev ARCHPREFERENCE
+is composed of one or more specifiers, separated by semicolons.
+A specifier is made up of one, two or three fields, separated by colons.
+Architectures specified in order, are separated by commas and make up the last
+(mandatory) field.
+The first field, if specified, is a name of a program, which selects this
+specifier if that name matches the program name in question.
+If the name field is empty or there is no name field, the specifier matches
+any program name.
+Thus, ordering of specifiers is important, and the one with no name should
+be last.
+.Pp
+When the
+.Nm arch
+command is called directly, the
+.Ar prog
+name provides the path information to the executable (possibly via the command
+search path).
+When a name is specified in a
+.Ev ARCHPREFERENCE
+specifier, the path information can alternately be specified as a second
+field following the name.
+When the
+.Nm arch
+command is called indirectly via a link, this path information must be
+specified.
+If not specified as a second field in a specifier, the executable path will
+be looked up in the corresponding property list file.
+.Ss Example ARCHPREFERENCE Values
+.Bl -tag -width " "
+.It i386,x86_64
+A specifier that matches any name.
+.It foo:i386,x86_64
+A specifier that matches the program named
+.Nm foo
+(the full executable path is in the
+.Pa foo.plist
+file).
+.It foo:/op/bin/boo:i386,x86_64
+A specifier with all fields specified.
+.It baz:i386;x86_64
+A specifier for
+.Nm baz
+and a second specifier that would match any other name.
+.El
+.Sh BUGS
+Running the
+.Nm arch
+command on an interpreter script may not work if the interpreter is a link
+to the arch command, especially if a 64-bit architecture is specified (since the
+.Nm arch
+command is 2-way universal, 32-bit only).
+.Sh SEE ALSO
+.Xr machine 1
--- /dev/null
+/*
+ * Copyright (c) 1999, 2006, 2011 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 <sys/cdefs.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <spawn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <paths.h>
+#include <err.h>
+#include <mach/mach.h>
+#include <mach-o/arch.h>
+#include <limits.h>
+#include <sys/fcntl.h>
+#include <glob.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <NSSystemDirectories.h>
+
+#ifndef ARCH_PROG
+#define ARCH_PROG "arch"
+#endif
+#ifndef MACHINE_PROG
+#define MACHINE_PROG "machine"
+#endif
+
+#define kKeyExecPath "ExecutablePath"
+#define kKeyPlistVersion "PropertyListVersion"
+#define kKeyPrefOrder "PreferredOrder"
+#define kPlistExtension ".plist"
+#define kSettingsDir "archSettings"
+
+static const char envname[] = "ARCHPREFERENCE";
+
+/* The CPU struct contains the argument buffer to posix_spawnattr_setbinpref_np */
+
+typedef struct {
+ cpu_type_t *buf;
+ int errs;
+ size_t count;
+ size_t capacity;
+} CPU;
+
+typedef struct {
+ const char *arch;
+ cpu_type_t cpu;
+} CPUTypes;
+
+static const CPUTypes knownArchs[] = {
+#if defined(__i386__) || defined(__x86_64__)
+ {"i386", CPU_TYPE_I386},
+ {"x86_64", CPU_TYPE_X86_64},
+#elif defined(__arm__)
+ {"arm", CPU_TYPE_ARM},
+#else
+#error "Unsupported architecture"
+#endif
+};
+
+/* environment SPI */
+char **_copyenv(char **env);
+int _setenvp(const char *name, const char *value, int rewrite, char ***envp, void *state);
+int _unsetenvp(const char *name, char ***envp, void *state);
+
+/* copy of environment */
+char **envCopy = NULL;
+extern char **environ;
+
+/*
+ * The native 32 and 64-bit architectures (this is relative to the architecture
+ * the arch command is running. NULL means unsupported.
+ */
+#if defined(__i386__) || defined(__x86_64__)
+#define NATIVE_32 "i386"
+#define NATIVE_64 "x86_64"
+#elif defined(__arm__)
+#define NATIVE_32 "arm"
+#define NATIVE_64 NULL
+#else
+#error "Unsupported architecture"
+#endif
+bool unrecognizednative32seen = false;
+bool unrecognizednative64seen = false;
+
+/*
+ * arch - perform the original behavior of the arch and machine commands.
+ * The archcmd flag is non-zero for the arch command, zero for the machine
+ * command. This routine never returns.
+ */
+static void __dead2
+arch(int archcmd)
+{
+ const NXArchInfo *arch = NXGetLocalArchInfo();
+
+ if(!arch)
+ errx(-1, "Unknown architecture.");
+ if(archcmd) {
+ arch = NXGetArchInfoFromCpuType(arch->cputype, CPU_SUBTYPE_MULTIPLE);
+ if(!arch)
+ errx(-1, "Unknown architecture.");
+ }
+ printf("%s%s", arch->name, (isatty(STDIN_FILENO) ? "\n" : ""));
+ exit(0);
+}
+
+/*
+ * spawnIt - run the posix_spawn command. cpu is the auto-sizing CPU structure.
+ * pflag is non-zero to call posix_spawnp; zero means to call posix_spawn.
+ * str is the name/path to pass to posix_spawn{,p}, and argv are
+ * the argument arrays to pass. This routine never returns.
+ */
+static void __dead2
+spawnIt(CPU *cpu, int pflag, const char *str, char **argv)
+{
+ posix_spawnattr_t attr;
+ pid_t pid;
+ int ret;
+ size_t copied;
+ size_t count = cpu->count;
+ cpu_type_t *prefs = cpu->buf;
+
+ if(count == 0) {
+ if(unrecognizednative32seen)
+ warnx("Unsupported native 32-bit architecture");
+ if(unrecognizednative64seen)
+ warnx("Unsupported native 64-bit architecture");
+ exit(1);
+ }
+
+ if(unrecognizednative32seen)
+ fprintf(stderr, "warning: unsupported native 32-bit architecture\n");
+ if(unrecognizednative64seen)
+ fprintf(stderr, "warning: unsupported native 64-bit architecture\n");
+
+ if((ret = posix_spawnattr_init(&attr)) != 0)
+ errc(1, ret, "posix_spawnattr_init");
+ /* do the equivalent of exec, rather than creating a separate process */
+ if((ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC)) != 0)
+ errc(1, ret, "posix_spawnattr_setflags");
+ if((ret = posix_spawnattr_setbinpref_np(&attr, count, prefs, &copied)) != 0)
+ errc(1, ret, "posix_spawnattr_setbinpref_np");
+ if(copied != count)
+ errx(1, "posix_spawnattr_setbinpref_np only copied %lu of %lu", copied, count);
+ if(pflag)
+ ret = posix_spawnp(&pid, str, NULL, &attr, argv, envCopy ? envCopy : environ);
+ else
+ ret = posix_spawn(&pid, str, NULL, &attr, argv, envCopy ? envCopy : environ);
+ errc(1, ret, "posix_spawn%s: %s", (pflag ? "p" : ""), str);
+}
+
+/*
+ * initCPU - initialize a CPU structure, a dynamically expanding CPU types
+ * array.
+ */
+static void
+initCPU(CPU *cpu)
+{
+ cpu->errs = 0;
+ cpu->count = 0;
+ cpu->capacity = 1;
+ cpu->buf = (cpu_type_t *)malloc(cpu->capacity * sizeof(cpu_type_t));
+ if(!cpu->buf)
+ err(1, "Failed to malloc CPU buffer");
+}
+
+/*
+ * addCPU - add a new CPU type value to the CPU structure, expanding
+ * the array as necessary.
+ */
+static void
+addCPU(CPU *cpu, cpu_type_t n)
+{
+ if(cpu->count == cpu->capacity) {
+ cpu_type_t *newcpubuf;
+
+ cpu->capacity *= 2;
+ newcpubuf = (cpu_type_t *)realloc(cpu->buf, cpu->capacity * sizeof(cpu_type_t));
+ if(!newcpubuf)
+ err(1, "Out of memory realloc-ing CPU structure");
+ cpu->buf = newcpubuf;
+ }
+ cpu->buf[cpu->count++] = n;
+}
+
+/*
+ * addCPUbyname - add a new CPU type, given by name, to the CPU structure,
+ * expanding the array as necessary. The name is converted to a type value
+ * by the ArchDict dictionary.
+ */
+static void
+addCPUbyname(CPU *cpu, const char *name)
+{
+ int i;
+
+ for (i=0; i < sizeof(knownArchs)/sizeof(knownArchs[0]); i++) {
+ if (0 == strcasecmp(name, knownArchs[i].arch)) {
+ addCPU(cpu, knownArchs[i].cpu);
+ return;
+ }
+ }
+
+ /* Didn't match a string in knownArchs */
+ warnx("Unknown architecture: %s", name);
+ cpu->errs++;
+}
+
+/*
+ * useEnv - parse the environment variable for CPU preferences. Use name
+ * to look for program-specific preferences, and append any CPU types to cpu.
+ * Returns the number of CPU types. Returns any specified execute path in
+ * execpath.
+ *
+ * The environment variable ARCHPREFERENCE has the format:
+ * spec[;spec]...
+ * a semicolon separated list of specifiers. Each specifier has the format:
+ * [prog:[execpath:]]type[,type]...
+ * a comma separate list of CPU type names, optionally proceeded by a program
+ * name and an execpath. If program name exist, that types only apply to that
+ * program. If execpath is specified, it is returned. If no program name
+ * exists, then it applies to all programs. So ordering of the specifiers is
+ * important, as the default (no program name) specifier must be last.
+ */
+static size_t
+useEnv(CPU *cpu, const char *name, char **execpath)
+{
+ char *val = getenv(envname);
+ if(!val)
+ return 0;
+
+ /* cp will point to the basename of name */
+ const char *cp = strrchr(name, '/');
+ if(cp) {
+ cp++;
+ if(!*cp)
+ errx(1, "%s: no name after last slash", name);
+ } else
+ cp = name;
+ /* make a copy of the environment variable value, so we can modify it */
+ val = strdup(val);
+ if(!val)
+ err(1, "Can't copy environment %s", envname);
+ char *str = val;
+ char *blk;
+ /* for each specifier */
+ while((blk = strsep(&str, ";")) != NULL) {
+ if(*blk == 0)
+ continue; /* two adjacent semicolons */
+ /* now split on colons */
+ char *n = strsep(&blk, ":");
+ if(blk) {
+ char *p = strsep(&blk, ":");
+ if(!blk) { /* there is only one colon, so no execpath */
+ blk = p;
+ p = NULL;
+ } else if(!*p) /* two consecutive colons, so no execpath */
+ p = NULL;
+ if(!*blk)
+ continue; /* no cpu list, so skip */
+ /* if the name matches, or there is no name, process the cpus */
+ if(!*n || strcmp(n, cp) == 0) {
+ if(cpu->count == 0) { /* only if we haven't processed architectures */
+ char *t;
+ while((t = strsep(&blk, ",")) != NULL)
+ addCPUbyname(cpu, t);
+ }
+ *execpath = (*n ? p : NULL); /* only use the exec path is name is set */
+ break;
+ }
+ } else { /* no colons at all, so process as default */
+ if(cpu->count == 0) { /* only if we haven't processed architectures */
+ blk = n;
+ while((n = strsep(&blk, ",")) != NULL)
+ addCPUbyname(cpu, n);
+ }
+ *execpath = NULL;
+ break;
+ }
+ }
+ if(cpu->errs) /* errors during addCPUbyname are fatal */
+ exit(1);
+ return cpu->count; /* return count of architectures */
+}
+
+/*
+ * spawnFromPreference - called when argv[0] is not "arch" or "machine", or
+ * argv[0] was arch, but no commandline architectures were specified.
+ * If the environment variable ARCHPREFERENCE is specified, and there is a
+ * match to argv[0], use the specified cpu preferences. If no exec path
+ * is specified in ARCHPREFERENCE, or no match is found in ARCHPREFERENCE,
+ * get any additional information from a .plist file with the name of argv[0].
+ * This routine never returns.
+ */
+static void __dead2
+spawnFromPreferences(CPU *cpu, int needexecpath, char **argv)
+{
+ char *epath = NULL;
+ char fpath[PATH_MAX];
+ char execpath2[PATH_MAX];
+ CFDictionaryRef plist = NULL;
+ NSSearchPathEnumerationState state;
+ size_t count, i;
+ const char *prog = strrchr(*argv, '/');
+
+ if(prog)
+ prog++;
+ else
+ prog = *argv;
+ if(!*prog)
+ errx(1, "Not program name specified");
+
+ /* check the environment variable first */
+ if((count = useEnv(cpu, prog, &epath)) > 0) {
+ /* if we were called as arch, use posix_spawnp */
+ if(!needexecpath)
+ spawnIt(cpu, 1, (epath ? epath : *argv), argv);
+ /* otherwise, if we have the executable path, call posix_spawn */
+ if(epath)
+ spawnIt(cpu, 0, epath, argv);
+ }
+
+ state = NSStartSearchPathEnumeration(NSLibraryDirectory, NSAllDomainsMask);
+ while ((state = NSGetNextSearchPathEnumeration(state, fpath))) {
+
+ CFURLRef url;
+ CFReadStreamRef stream;
+
+ if (fpath[0] == '~') {
+ glob_t pglob;
+ int gret;
+
+ bzero(&pglob, sizeof(pglob));
+
+ gret = glob(fpath, GLOB_TILDE, NULL, &pglob);
+ if (gret == 0) {
+ int i;
+ for (i=0; i < pglob.gl_pathc; i++) {
+ /* take the first glob expansion */
+ strlcpy(fpath, pglob.gl_pathv[i], sizeof(fpath));
+ break;
+ }
+ }
+ globfree(&pglob);
+ }
+
+ // Handle path
+ strlcat(fpath, "/" kSettingsDir "/", sizeof(fpath));
+ strlcat(fpath, prog, sizeof(fpath));
+ strlcat(fpath, kPlistExtension, sizeof(fpath));
+ // printf("component: %s\n", fpath);
+
+ int fd, ret;
+ size_t length;
+ ssize_t rsize;
+ struct stat sb;
+ void *buffer;
+ fd = open(fpath, O_RDONLY, 0);
+ if (fd >= 0) {
+ ret = fstat(fd, &sb);
+ if (ret == 0) {
+ if (sb.st_size <= SIZE_T_MAX) {
+ length = (size_t)sb.st_size;
+ buffer = malloc(length); /* ownership transferred to CFData */
+ if (buffer) {
+ rsize = read(fd, buffer, length);
+ if (rsize == length) {
+ CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buffer, length, kCFAllocatorMalloc);
+ if (data) {
+ buffer = NULL;
+ plist = CFPropertyListCreateWithData(kCFAllocatorDefault, data, kCFPropertyListImmutable, NULL, NULL);
+ CFRelease(data);
+ }
+ }
+ if (buffer) {
+ free(buffer);
+ }
+ }
+ }
+ }
+ close(fd);
+ }
+
+ if (plist) {
+ break;
+ }
+ }
+
+ if (plist) {
+ if (CFGetTypeID(plist) != CFDictionaryGetTypeID())
+ errx(1, "%s: plist not a dictionary", fpath);
+ } else {
+ errx(1, "Can't find any plists for %s", prog);
+ }
+
+
+ int errs = 0; /* scan for all errors and fail later */
+ do { /* begin block */
+ /* check the plist version */
+ CFStringRef vers = CFDictionaryGetValue(plist, CFSTR(kKeyPlistVersion));
+ if(!vers) {
+ warnx("%s: No key %s", fpath, kKeyPlistVersion);
+ errs++;
+ } else if(CFGetTypeID(vers) != CFStringGetTypeID()) {
+ warnx("%s: %s is not a string", fpath, kKeyPlistVersion);
+ errs++;
+ } else if(!CFEqual(vers, CFSTR("1.0"))) {
+ warnx("%s: %s not 1.0", fpath, kKeyPlistVersion);
+ errs++;
+ }
+ /* get the execpath */
+ CFStringRef execpath = CFDictionaryGetValue(plist, CFSTR(kKeyExecPath));
+ if(!execpath) {
+ warnx("%s: No key %s", fpath, kKeyExecPath);
+ errs++;
+ } else if(CFGetTypeID(execpath) != CFStringGetTypeID()) {
+ warnx("%s: %s is not a string", fpath, kKeyExecPath);
+ errs++;
+ }
+ if (!CFStringGetFileSystemRepresentation(execpath, execpath2, sizeof(execpath2))) {
+ warnx("%s: could not get exec path", fpath);
+ errs++;
+ }
+ /* if we already got cpu preferences from ARCHPREFERENCE, we are done */
+ if(count > 0)
+ break;
+ /* otherwise, parse the cpu preferences from the plist */
+ CFArrayRef p = CFDictionaryGetValue(plist, CFSTR(kKeyPrefOrder));
+ if(!p) {
+ warnx("%s: No key %s", fpath, kKeyPrefOrder);
+ errs++;
+ } else if(CFGetTypeID(p) != CFArrayGetTypeID()) {
+ warnx("%s: %s is not an array", fpath, kKeyPrefOrder);
+ errs++;
+ } else if((count = CFArrayGetCount(p)) == 0) {
+ warnx("%s: no entries in %s", fpath, kKeyPrefOrder);
+ errs++;
+ } else {
+ /* finally build the cpu type array */
+ for(i = 0; i < count; i++) {
+ CFStringRef a = CFArrayGetValueAtIndex(p, i);
+ if(CFGetTypeID(a) != CFStringGetTypeID()) {
+ warnx("%s: entry %lu of %s is not a string", fpath, i, kKeyPrefOrder);
+ errs++;
+ } else {
+ char astr[128];
+ if (CFStringGetCString(a, astr, sizeof(astr), kCFStringEncodingASCII)) {
+ addCPUbyname(cpu, astr);
+ }
+ }
+ }
+ }
+ } while(0); /* end block */
+ if(errs) /* exit if there were any reported errors */
+ exit(1);
+
+ CFRelease(plist);
+
+ /* call posix_spawn */
+ spawnIt(cpu, 0, execpath2, argv);
+}
+
+static void __dead2
+usage(int ret)
+{
+ fprintf(stderr,
+ "Usage: %s\n"
+ " Display the machine's architecture type\n"
+ "Usage: %s {-arch_name | -arch arch_name} ... [-c] [-d envname] ... [-e envname=value] ... [-h] prog [arg ...]\n"
+ " Run prog with any arguments, using the given architecture\n"
+ " order. If no architectures are specified, use the\n"
+ " ARCHPREFERENCE environment variable, or a property list file.\n"
+ " -c will clear out all environment variables before running prog.\n"
+ " -d will delete the given environment variable before running prog.\n"
+ " -e will add the given environment variable/value before running prog.\n"
+ " -h will print usage message and exit.\n",
+ ARCH_PROG, ARCH_PROG);
+ exit(ret);
+}
+
+/*
+ * wrapped - check the path to see if it is a link to /usr/bin/arch.
+ */
+static int
+wrapped(const char *name)
+{
+ size_t lp, ln;
+ char *p;
+ char *bp = NULL;
+ char *cur, *path;
+ char buf[MAXPATHLEN], rpbuf[MAXPATHLEN];
+ struct stat sb;
+
+ ln = strlen(name);
+
+ do { /* begin block */
+ /* If it's an absolute or relative path name, it's easy. */
+ if(index(name, '/')) {
+ if(stat(name, &sb) == 0 && S_ISREG(sb.st_mode) && access(name, X_OK) == 0) {
+ bp = (char *)name;
+ break;
+ }
+ errx(1, "%s isn't executable", name);
+ }
+
+ /* search the PATH, looking for name */
+ if((path = getenv("PATH")) == NULL)
+ path = _PATH_DEFPATH;
+
+ cur = alloca(strlen(path) + 1);
+ if(cur == NULL)
+ err(1, "alloca");
+ strcpy(cur, path);
+ while((p = strsep(&cur, ":")) != NULL) {
+ /*
+ * It's a SHELL path -- double, leading and trailing colons
+ * mean the current directory.
+ */
+ if(*p == '\0') {
+ p = ".";
+ lp = 1;
+ } else
+ lp = strlen(p);
+
+ /*
+ * If the path is too long complain. This is a possible
+ * security issue; given a way to make the path too long
+ * the user may execute the wrong program.
+ */
+ if(lp + ln + 2 > sizeof(buf)) {
+ warn("%s: path too long", p);
+ continue;
+ }
+ bcopy(p, buf, lp);
+ buf[lp] = '/';
+ bcopy(name, buf + lp + 1, ln);
+ buf[lp + ln + 1] = '\0';
+ if(stat(buf, &sb) == 0 && S_ISREG(sb.st_mode) && access(buf, X_OK) == 0) {
+ bp = buf;
+ break;
+ }
+ }
+ if(p == NULL)
+ errx(1, "Can't find %s in PATH", name);
+ } while(0); /* end block */
+ if(realpath(bp, rpbuf) == NULL)
+ errx(1, "realpath failed on %s", bp);
+ return (strcmp(rpbuf, "/usr/bin/" ARCH_PROG) == 0);
+}
+
+/*
+ * spawnFromArgs - called when arch has arguments specified. The arch command
+ * line arguments are:
+ * % arch [[{-xxx | -arch xxx}]...] prog [arg]...
+ * where xxx is a cpu name, and the command to execute and its arguments follow.
+ * If no commandline cpu names are given, the environment variable
+ * ARCHPREFERENCE is used. This routine never returns.
+ */
+
+#define MATCHARG(a,m) ({ \
+ const char *arg = *(a); \
+ if(arg[1] == '-') arg++; \
+ strcmp(arg, (m)) == 0; \
+})
+
+#define MATCHARGWITHVALUE(a,m,n,e) ({ \
+ const char *ret = NULL; \
+ const char *arg = *(a); \
+ if(arg[1] == '-') arg++; \
+ if(strcmp(arg, (m)) == 0) { \
+ if(*++(a) == NULL) { \
+ warnx(e); \
+ usage(1); \
+ } \
+ ret = *(a); \
+ } else if(strncmp(arg, (m), (n)) == 0 && arg[n] == '=') { \
+ ret = arg + (n) + 1; \
+ } \
+ ret; \
+})
+
+#define MAKEENVCOPY(e) \
+ if(!envCopy) { \
+ envCopy = _copyenv(environ); \
+ if(envCopy == NULL) \
+ errx(1, (e)); \
+ }
+
+static void __dead2
+spawnFromArgs(CPU *cpu, char **argv)
+{
+ const char *ap, *ret;
+
+ /* process arguments */
+ for(argv++; *argv && **argv == '-'; argv++) {
+ if((ret = MATCHARGWITHVALUE(argv, "-arch", 5, "-arch without architecture"))) {
+ ap = ret;
+ } else if(MATCHARG(argv, "-32")) {
+ ap = NATIVE_32;
+ if(!ap) {
+ unrecognizednative32seen = true;
+ continue;
+ }
+ } else if(MATCHARG(argv, "-64")) {
+ ap = NATIVE_64;
+ if(!ap) {
+ unrecognizednative64seen = true;
+ continue;
+ }
+ } else if(MATCHARG(argv, "-c")) {
+ free(envCopy);
+ envCopy = _copyenv(NULL); // create empty environment
+ if(!envCopy)
+ errx(1, "Out of memory processing -c");
+ continue;
+ } else if((ret = MATCHARGWITHVALUE(argv, "-d", 2, "-d without envname"))) {
+ MAKEENVCOPY("Out of memory processing -d");
+ _unsetenvp(ret, &envCopy, NULL);
+ continue;
+ } else if((ret = MATCHARGWITHVALUE(argv, "-e", 2, "-e without envname=value"))) {
+ MAKEENVCOPY("Out of memory processing -e");
+ const char *cp = strchr(ret, '=');
+ if(!cp) {
+ warnx("-e %s: no equal sign", ret);
+ usage(1);
+ }
+ cp++; // skip to value
+ /*
+ * _setenvp() only uses the name before any equal sign found in
+ * the first argument.
+ */
+ _setenvp(ret, cp, 1, &envCopy, NULL);
+ continue;
+ } else if(MATCHARG(argv, "-h")) {
+ usage(0);
+ } else {
+ ap = *argv + 1;
+ if(*ap == '-') ap++;
+ }
+ addCPUbyname(cpu, ap);
+ }
+ if(cpu->errs)
+ exit(1);
+ if(!*argv || !**argv) {
+ warnx("No command to execute");
+ usage(1);
+ }
+ /* if the program is already a link to arch, then force execpath */
+ int needexecpath = wrapped(*argv);
+
+ /*
+ * If we don't have any architecutures, try ARCHPREFERENCE and plist
+ * files.
+ */
+ if((cpu->count == 0) || needexecpath)
+ spawnFromPreferences(cpu, needexecpath, argv); /* doesn't return */
+
+ /*
+ * Call posix_spawnp on the program name.
+ */
+ spawnIt(cpu, 1, *argv, argv);
+}
+
+
+/* the main() routine */
+int
+main(int argc, char **argv)
+{
+ const char *prog = getprogname();
+ int my_name_is_arch;
+ CPU cpu;
+
+ if(strcmp(prog, MACHINE_PROG) == 0) {
+ if(argc > 1)
+ errx(-1, "no arguments accepted");
+ arch(0); /* the "machine" command was called */
+ } else if((my_name_is_arch = (strcmp(prog, ARCH_PROG) == 0))) {
+ if(argc == 1)
+ arch(1); /* the "arch" command with no arguments was called */
+ }
+
+ initCPU(&cpu);
+
+ if(my_name_is_arch)
+ spawnFromArgs(&cpu, argv);
+ else
+ spawnFromPreferences(&cpu, 1, argv);
+
+ /* should never get here */
+ errx(1, "returned from spawn");
+}
--- /dev/null
+.\" $OpenBSD: machine.1,v 1.2 1996/06/26 05:36:23 deraadt Exp $
+.\" Copyright (c) 1980, 1990 The Regents of the University of California.
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" from: @(#)machine.1 5.5 (Berkeley) 7/26/91
+.\"
+.Dd July 26, 1991
+.Dt MACHINE 1
+.Os
+.Sh NAME
+.Nm machine
+.Nd print machine type
+.Sh SYNOPSIS
+.Nm machine
+.Sh DESCRIPTION
+The
+.Nm machine
+command displays the machine type.
+.Sh SEE ALSO
+.Xr arch 1 ,
+.Xr make 1
--- /dev/null
+-----BEGIN PGP SIGNED MESSAGE-----
+
+Sorry for the long wait, but there still were a few things to
+be ironed out in at, which I've finally done :-)
+
+The FreeBSD team does have my permission to use at, version 2.9,
+under the BSD license.
+
+You'll find it on sunsite.unc.edu's Incoming, hopefully; the
+md5 checksum is
+
+3ba2ca3c0e87e1a04feae2c6c1376b0d at-2.9.tgz
+
+Best regards
+ Thomas
+- --
+Thomas Koenig, Thomas.Koenig@ciw.uni-karlsruhe.de, ig25@dkauni2.bitnet.
+The joy of engineering is to find a straight line on a double
+logarithmic diagram.
+
+-----BEGIN PGP SIGNATURE-----
+Version: 2.6.2i
+
+iQCVAwUBMCjVrPBu+cbJcKCVAQFNiQP/dpWP57s/E8plVGUD3zfgOXDmKUvg8U7a
+VwRzJrIMuSgnSJs0wkpvcomc3NLicipfX7hhWLh/xatPM2YbF7O5HZoNdvWvexD2
+1Y67zJ+0HFb1mPnSBOrS5RFiQAe3KqmGec6E14Rih/qNoFQZBVRFXZ4xxuwP+0Rs
+e2U+TVTUz6A=
+=TvyW
+-----END PGP SIGNATURE-----
--- /dev/null
+.\" $FreeBSD: src/usr.bin/at/at.man,v 1.34 2003/03/26 02:38:18 keramida Exp $
+.Dd January 13, 2002
+.Dt "AT" 1
+.Os
+.Sh NAME
+.Nm at ,
+.Nm batch ,
+.Nm atq ,
+.Nm atrm
+.Nd queue, examine, or delete jobs for later execution
+.Sh SYNOPSIS
+.Nm at
+.Op Fl q Ar queue
+.Op Fl f Ar file
+.Op Fl mldbv
+.Ar time
+.Nm at
+.Op Fl q Ar queue
+.Op Fl f Ar file
+.Op Fl mldbv
+.Fl t
+.Sm off
+.Op Oo Ar CC Oc Ar YY
+.Ar MM DD hh mm Op . Ar SS
+.Sm on
+.Nm at
+.Fl c Ar job Op Ar job ...
+.Nm at
+.Fl l Op Ar job ...
+.Nm at
+.Fl l
+.Fl q Ar queue
+.Nm at
+.Fl r Ar job Op Ar job ...
+.Pp
+.Nm atq
+.Op Fl q Ar queue
+.Op Fl v
+.Pp
+.Nm atrm
+.Ar job
+.Op Ar job ...
+.Pp
+.Nm batch
+.Op Fl q Ar queue
+.Op Fl f Ar file
+.Op Fl mv
+.Op Ar time
+.Sh DESCRIPTION
+The
+.Nm at
+and
+.Nm batch
+utilities
+read commands from standard input or a specified file.
+The commands are executed at a later time, using
+.Xr sh 1 .
+.Bl -tag -width indent
+.It Nm at
+executes commands at a specified time;
+.It Nm atq
+lists the user's pending jobs, unless the user is the superuser; in that
+case, everybody's jobs are listed;
+.It Nm atrm
+deletes jobs;
+.It Nm batch
+executes commands when system load levels permit; in other words, when the load average
+drops below _LOADAVG_MX (1.5), or the value specified in the invocation of
+.Nm atrun .
+.El
+.Pp
+The
+.Nm at
+utility allows some moderately complex
+.Ar time
+specifications.
+It accepts times of the form
+.Ar HHMM
+or
+.Ar HH:MM
+to run a job at a specific time of day.
+(If that time is already past, the next day is assumed.)
+As an alternative, the following keywords may be specified:
+.Em midnight ,
+.Em noon ,
+or
+.Em teatime
+(4pm)
+and time-of-day may be suffixed with
+.Em AM
+or
+.Em PM
+for running in the morning or the evening.
+The day on which the job is to be run may also be specified
+by giving a date in the form
+.Ar \%month-name day
+with an optional
+.Ar year ,
+or giving a date of the forms
+.Ar DD.MM.YYYY ,
+.Ar DD.MM.YY ,
+.Ar MM/DD/YYYY ,
+.Ar MM/DD/YY ,
+.Ar MMDDYYYY , or
+.Ar MMDDYY .
+The specification of a date must follow the specification of
+the time of day.
+Time can also be specified as:
+.Op Em now
+.Em + Ar count \%time-units ,
+where the time-units can be
+.Em minutes ,
+.Em hours ,
+.Em days ,
+.Em weeks ,
+.Em months
+or
+.Em years
+and
+.Nm at
+may be told to run the job today by suffixing the time with
+.Em today
+and to run the job tomorrow by suffixing the time with
+.Em tomorrow .
+.Pp
+For example, to run a job at 4pm three days from now, use
+.Nm at Ar 4pm + 3 days ,
+to run a job at 10:00am on July 31, use
+.Nm at Ar 10am Jul 31
+and to run a job at 1am tomorrow, use
+.Nm at Ar 1am tomorrow .
+.Pp
+The
+.Nm at
+utility also supports the
+.Tn POSIX
+time format (see
+.Fl t
+option).
+.Pp
+For both
+.Nm at
+and
+.Nm batch ,
+commands are read from standard input or the file specified
+with the
+.Fl f
+option.
+The working directory, the environment (except for the variables
+.Ev TERM ,
+.Ev TERMCAP ,
+.Ev DISPLAY
+and
+.Em _ ) ,
+and the
+.Ar umask
+are retained from the time of invocation.
+An
+.Nm at
+or
+.Nm batch
+command invoked from a
+.Xr su 1
+shell will retain the current userid.
+The user will be mailed standard error and standard output from his
+commands, if any.
+Mail will be sent using the command
+.Xr sendmail 8 .
+If
+.Nm at
+is executed from a
+.Xr su 1
+shell, the owner of the login shell will receive the mail.
+.Pp
+The superuser may use these commands in any case.
+For other users, permission to use
+.Nm at
+is determined by the files
+.Pa _PERM_PATH/at.allow
+and
+.Pa _PERM_PATH/at.deny .
+.Pp
+If the file
+.Pa _PERM_PATH/at.allow
+exists, only usernames mentioned in it are allowed to use
+.Nm at .
+In these two files,
+a user is considered to be listed
+only if the user name has no blank or other characters
+before it on its line and a newline character immediately after the name,
+even at the end of the file.
+Other lines are ignored and may be used for comments.
+.Pp
+If
+.Pa _PERM_PATH/at.allow
+does not exist,
+.Pa _PERM_PATH/at.deny
+is checked, every username not mentioned in it is then allowed
+to use
+.Nm at .
+.Pp
+If neither exists, only the superuser is allowed use of
+.Nm at .
+.Sh IMPLEMENTATION NOTES
+Note that
+.Nm at
+is implemented through the
+.Xr launchd 8
+daemon periodically invoking
+.Xr atrun 8 ,
+which is disabled by default.
+See
+.Xr atrun 8
+for information about enabling
+.Nm atrun .
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl b
+Is an alias for
+.Nm batch .
+.It Fl c
+Cat the jobs listed on the command line to standard output.
+.It Fl d
+Is an alias for
+.Nm atrm
+(this option is deprecated; use
+.Fl r
+instead).
+.It Fl f Ar file
+Read the job from
+.Ar file
+rather than standard input.
+.It Fl l
+With no arguments, list all jobs for the invoking user.
+If one or more
+job numbers are given, list only those jobs.
+.It Fl m
+Send mail to the user when the job has completed even if there was no
+output.
+.It Fl q Ar queue
+Use the specified queue.
+A queue designation consists of a single letter; valid queue designations
+range from
+.Ar a
+to
+.Ar z
+and
+.Ar A
+to
+.Ar Z .
+The
+.Ar _DEFAULT_AT_QUEUE
+queue (a) is the default for
+.Nm at
+and the
+.Ar _DEFAULT_BATCH_QUEUE
+queue (b) is the default for
+.Nm batch .
+Queues with higher letters run with increased niceness.
+If a job is submitted to a queue designated with an uppercase letter, it
+is treated as if it had been submitted to batch at that time.
+If
+.Nm atq
+is given a specific queue, it will only show jobs pending in that queue.
+.It Fl r
+Remove the specified jobs.
+.It Fl t
+Specify the job time using the \*[Px] time format.
+The argument should be in the form
+.Sm off
+.Op Oo Ar CC Oc Ar YY
+.Ar MM DD hh mm Op . Ar SS
+.Sm on
+where each pair of letters represents the following:
+.Pp
+.Bl -tag -width indent -compact -offset indent
+.It Ar CC
+The first two digits of the year (the century).
+.It Ar YY
+The second two digits of the year.
+.It Ar MM
+The month of the year, from 1 to 12.
+.It Ar DD
+the day of the month, from 1 to 31.
+.It Ar hh
+The hour of the day, from 0 to 23.
+.It Ar mm
+The minute of the hour, from 0 to 59.
+.It Ar SS
+The second of the minute, from 0 to 61.
+.El
+.Pp
+If the
+.Ar CC
+and
+.Ar YY
+letter pairs are not specified, the values default to the current
+year.
+If the
+.Ar SS
+letter pair is not specified, the value defaults to 0.
+.It Fl v
+For
+.Nm atq ,
+shows completed but not yet deleted jobs in the queue; otherwise
+shows the time the job will be executed.
+.El
+.Sh FILES
+.Bl -tag -width _ATJOB_DIR/_LOCKFILE -compact
+.It Pa _ATJOB_DIR
+directory containing job files
+(/usr/lib/cron/jobs/)
+.It Pa _ATJOB_DIR/_LOCKFILE
+job-creation lock file
+(/usr/lib/cron/jobs/...)
+.It Pa _ATSPOOL_DIR
+directory containing output spool files
+(/usr/lib/cron/spool/)
+.It Pa _PERM_PATH/at.allow
+allow permission control
+(/usr/lib/cron/at.allow)
+.It Pa _PERM_PATH/at.deny
+deny permission control
+(/usr/lib/cron/at.deny)
+.It Pa /var/run/utmpx
+login records
+.El
+.Sh SEE ALSO
+.Xr nice 1 ,
+.Xr sh 1 ,
+.Xr umask 2 ,
+.Xr compat 5 ,
+.Xr atrun 8 ,
+.Xr cron 8 ,
+.Xr sendmail 8
+.Sh BUGS
+If the file
+.Pa /var/run/utmpx
+is not available or corrupted,
+or if the user is not logged on at the time
+.Nm at
+is invoked, the mail is sent to the userid found
+in the environment variable
+.Ev LOGNAME .
+If that is undefined or empty, the current userid is assumed.
+.Pp
+The
+.Nm at
+and
+.Nm batch
+utilities
+as presently implemented are not suitable when users are competing for
+resources.
+If this is the case, another batch system such as
+.Em nqs
+may be more suitable.
+.Pp
+Specifying a date past 2038 may not work on some systems.
+.Sh AUTHORS
+At was mostly written by
+.An Thomas Koenig Aq ig25@rz.uni-karlsruhe.de .
+The time parsing routines are by
+.An David Parsons Aq orc@pell.chi.il.us ,
+with minor enhancements by
+.An Joe Halpin Aq joe.halpin@attbi.com .
--- /dev/null
+/*
+ * at.c : Put file into atrun queue
+ * Copyright (C) 1993, 1994 Thomas Koenig
+ *
+ * Atrun & Atq modifications
+ * Copyright (C) 1993 David Parsons
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER 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.
+ */
+
+#include <sys/cdefs.h>
+__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
+
+/* System Headers */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifndef __FreeBSD__
+#include <getopt.h>
+#endif
+#include <glob.h>
+#ifdef __FreeBSD__
+#include <locale.h>
+#endif
+#include <pwd.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else /* !__APPLE */
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+/* Local headers */
+
+#include "at.h"
+#include "panic.h"
+#include "parsetime.h"
+#include "pathnames.h"
+#include "perm.h"
+
+#define MAIN
+#include "privs.h"
+
+/* Macros */
+
+#ifndef ATJOB_DIR
+#define ATJOB_DIR _PATH_ATJOBS
+#endif
+
+#ifndef LFILE
+#define LFILE ATJOB_DIR ".lockfile"
+#endif
+
+#ifndef ATJOB_MX
+#define ATJOB_MX 255
+#endif
+
+#define ALARMC 10 /* Number of seconds to wait for timeout */
+
+#define SIZE 255
+#define TIMESIZE 50
+
+enum { ATQ, ATRM, AT, BATCH, CAT }; /* what program we want to run */
+
+/* File scope variables */
+
+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 atverify = 0; /* verify time instead of queuing job */
+char *namep;
+int posixly_correct; /* Behave as per POSIX */
+/* http://www.opengroup.org/onlinepubs/009695399/utilities/at.html */
+
+/* Function declarations */
+
+static void sigc(int signo);
+static void alarmc(int signo);
+static char *cwdname(void);
+static void writefile(time_t runtimer, char queue);
+static void list_jobs(long *, int);
+static long nextjob(void);
+static time_t ttime(const char *arg);
+static int in_job_list(long, long *, int);
+static long *get_job_list(int, char *[], int *);
+
+/* Signal catching functions */
+
+static void sigc(int signo __unused)
+{
+/* If the user presses ^C, remove the spool file and exit
+ */
+ if (fcreated)
+ {
+ PRIV_START
+ unlink(atfile);
+ PRIV_END
+ }
+
+ _exit(EXIT_FAILURE);
+}
+
+static void alarmc(int signo __unused)
+{
+ char buf[1024];
+
+ /* Time out after some seconds. */
+ strlcpy(buf, namep, sizeof(buf));
+ strlcat(buf, ": file locking timed out\n", sizeof(buf));
+ write(STDERR_FILENO, buf, strlen(buf));
+ sigc(0);
+}
+
+/* Local functions */
+
+static char *cwdname(void)
+{
+/* Read in the current directory; the name will be overwritten on
+ * subsequent calls.
+ */
+ static char *ptr = NULL;
+ static size_t size = SIZE;
+
+ if (ptr == NULL)
+ if ((ptr = malloc(size)) == NULL)
+ errx(EXIT_FAILURE, "virtual memory exhausted");
+
+ while (1)
+ {
+ if (ptr == NULL)
+ panic("out of memory");
+
+ if (getcwd(ptr, size-1) != NULL)
+ return ptr;
+
+ if (errno != ERANGE)
+ perr("cannot get directory");
+
+ free (ptr);
+ size += SIZE;
+ if ((ptr = malloc(size)) == NULL)
+ errx(EXIT_FAILURE, "virtual memory exhausted");
+ }
+}
+
+static long
+nextjob(void)
+{
+ long jobno;
+ FILE *fid;
+
+ if ((fid = fopen(ATJOB_DIR ".SEQ", "r+")) != NULL) {
+ if (fscanf(fid, "%5lx", &jobno) == 1) {
+ rewind(fid);
+ jobno = (1+jobno) % 0xfffff; /* 2^20 jobs enough? */
+ fprintf(fid, "%05lx\n", jobno);
+ }
+ else
+ jobno = EOF;
+ fclose(fid);
+ return jobno;
+ }
+ else if ((fid = fopen(ATJOB_DIR ".SEQ", "w")) != NULL) {
+ fprintf(fid, "%05lx\n", jobno = 1);
+ fclose(fid);
+ return 1;
+ }
+ return EOF;
+}
+
+static void
+writefile(time_t runtimer, char queue)
+{
+/* This does most of the work if at or batch are invoked for writing a job.
+ */
+ long jobno;
+ char *ap, *ppos, *mailname;
+ struct passwd *pass_entry;
+ struct stat statbuf;
+ int fdes, lockdes, fd2;
+ FILE *fp, *fpin;
+ struct sigaction act;
+ char **atenv;
+ int ch;
+ mode_t cmask;
+ struct flock lock;
+ char * oldpwd_str = NULL;
+
+#ifdef __FreeBSD__
+ (void) setlocale(LC_TIME, "");
+#endif
+
+/* Install the signal handler for SIGINT; terminate after removing the
+ * spool file if necessary
+ */
+ act.sa_handler = sigc;
+ sigemptyset(&(act.sa_mask));
+ act.sa_flags = 0;
+
+ sigaction(SIGINT, &act, NULL);
+
+ ppos = atfile + strlen(ATJOB_DIR);
+
+ /* Loop over all possible file names for running something at this
+ * particular time, see if a file is there; the first empty slot at any
+ * particular time is used. Lock the file LFILE first to make sure
+ * we're alone when doing this.
+ */
+
+ PRIV_START
+
+ if ((lockdes = open(LFILE, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR)) < 0)
+ perr("cannot open lockfile " LFILE);
+
+ lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0;
+ lock.l_len = 0;
+
+ act.sa_handler = alarmc;
+ sigemptyset(&(act.sa_mask));
+ act.sa_flags = 0;
+
+ /* Set an alarm so a timeout occurs after ALARMC seconds, in case
+ * something is seriously broken.
+ */
+ sigaction(SIGALRM, &act, NULL);
+ alarm(ALARMC);
+ fcntl(lockdes, F_SETLKW, &lock);
+ alarm(0);
+
+ if ((jobno = nextjob()) == EOF)
+ perr("cannot generate job number");
+
+ sprintf(ppos, "%c%5lx%8lx", queue,
+ jobno, (unsigned long) (runtimer/60));
+
+ for(ap=ppos; *ap != '\0'; ap ++)
+ if (*ap == ' ')
+ *ap = '0';
+
+ if (stat(atfile, &statbuf) != 0)
+ if (errno != ENOENT)
+ perr("cannot access " ATJOB_DIR);
+
+ /* Create the file. The x bit is only going to be set after it has
+ * been completely written out, to make sure it is not executed in the
+ * meantime. To make sure they do not get deleted, turn off their r
+ * bit. Yes, this is a kluge.
+ */
+ cmask = umask(S_IRUSR | S_IWUSR | S_IXUSR);
+ if ((fdes = creat(atfile, O_WRONLY)) == -1)
+ perr("cannot create atjob file");
+
+ if ((fd2 = dup(fdes)) <0)
+ perr("error in dup() of job file");
+
+ if(fchown(fd2, real_uid, real_gid) != 0)
+ perr("cannot give away file");
+
+ PRIV_END
+
+ /* We no longer need suid root; now we just need to be able to write
+ * to the directory, if necessary.
+ */
+
+ REDUCE_PRIV(DAEMON_UID, DAEMON_GID)
+
+ /* We've successfully created the file; let's set the flag so it
+ * gets removed in case of an interrupt or error.
+ */
+ fcreated = 1;
+
+ /* Now we can release the lock, so other people can access it
+ */
+ lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = 0;
+ lock.l_len = 0;
+ fcntl(lockdes, F_SETLKW, &lock);
+ close(lockdes);
+
+ if((fp = fdopen(fdes, "w")) == NULL)
+ panic("cannot reopen atjob file");
+
+ /* Get the userid to mail to, first by trying getlogin(),
+ * then from LOGNAME, finally from getpwuid().
+ */
+ mailname = getlogin();
+ if (mailname == NULL)
+ mailname = getenv("LOGNAME");
+
+ if ((mailname == NULL) || (mailname[0] == '\0')
+ || (strlen(mailname) >= MAXLOGNAME) || (getpwnam(mailname)==NULL))
+ {
+ pass_entry = getpwuid(real_uid);
+ if (pass_entry != NULL)
+ mailname = pass_entry->pw_name;
+ }
+
+ if (atinput != (char *) NULL)
+ {
+ fpin = freopen(atinput, "r", stdin);
+ if (fpin == NULL)
+ perr("cannot open input file");
+ }
+ fprintf(fp, "#!/bin/sh\n# atrun uid=%ld gid=%ld\n# mail %.*s %d\n",
+ (long) real_uid, (long) real_gid, MAXLOGNAME - 1, mailname,
+ send_mail);
+
+ /* Write out the umask at the time of invocation
+ */
+ fprintf(fp, "umask %lo\n", (unsigned long) cmask);
+
+ /* Write out the environment. Anything that may look like a
+ * special character to the shell is quoted, except for \n, which is
+ * done with a pair of "'s. Don't export the no_export list (such
+ * as TERM or DISPLAY) because we don't want these.
+ */
+ for (atenv= environ; *atenv != NULL; atenv++)
+ {
+ int export = 1;
+ char *eqp;
+
+ eqp = strchr(*atenv, '=');
+ if (ap == NULL)
+ eqp = *atenv;
+ else
+ {
+ size_t i;
+
+ if(strncmp(*atenv, "OLDPWD", (size_t) (eqp-*atenv)) == 0) {
+ oldpwd_str = *atenv;
+ }
+ if (!posixly_correct) {
+ /* Test 891 expects TERM, etc. to show up in "at" env
+ so exclude them only when not posixly_correct */
+ for (i=0; i<sizeof(no_export)/sizeof(no_export[0]); i++)
+ {
+ export = export
+ && (strncmp(*atenv, no_export[i],
+ (size_t) (eqp-*atenv)) != 0);
+ }
+ }
+ eqp++;
+ }
+
+ if (export)
+ {
+ fwrite(*atenv, sizeof(char), eqp-*atenv, fp);
+ for(ap = eqp;*ap != '\0'; ap++)
+ {
+ if (*ap == '\n')
+ fprintf(fp, "\"\n\"");
+ else
+ {
+ if (!isalnum(*ap)) {
+ switch (*ap) {
+ case '%': case '/': case '{': case '[':
+ case ']': case '=': case '}': case '@':
+ case '+': case '#': case ',': case '.':
+ case ':': case '-': case '_':
+ break;
+ default:
+ fputc('\\', fp);
+ break;
+ }
+ }
+ fputc(*ap, fp);
+ }
+ }
+ fputs("; export ", fp);
+ fwrite(*atenv, sizeof(char), eqp-*atenv -1, fp);
+ fputc('\n', fp);
+
+ }
+ }
+ /* Cd to the directory at the time and write out all the
+ * commands the user supplies from stdin.
+ */
+ fprintf(fp, "cd ");
+ for (ap = cwdname(); *ap != '\0'; ap++)
+ {
+ if (*ap == '\n')
+ fprintf(fp, "\"\n\"");
+ else
+ {
+ if (*ap != '/' && !isalnum(*ap))
+ fputc('\\', fp);
+
+ fputc(*ap, fp);
+ }
+ }
+ /* Test cd's exit status: die if the original directory has been
+ * removed, become unreadable or whatever
+ */
+ fprintf(fp, " || {\n\t echo 'Execution directory "
+ "inaccessible' >&2\n\t exit 1\n}\n");
+
+ /* Put OLDPWD back, since the cd has set it */
+ /* Although this is added to fix conformance test at.ex 891, it seems like */
+ /* the right thing to do always, so the code is not posix_pedantic only */
+ if (oldpwd_str) {
+ fprintf(fp, "%s; export OLDPWD\n", oldpwd_str);
+ } else {
+ fprintf(fp, "unset OLDPWD\n");
+ }
+
+ while((ch = getchar()) != EOF)
+ fputc(ch, fp);
+
+ fprintf(fp, "\n");
+ if (ferror(fp))
+ panic("output error");
+
+ if (ferror(stdin))
+ panic("input error");
+
+ fclose(fp);
+
+ /* Set the x bit so that we're ready to start executing
+ */
+
+ if (fchmod(fd2, S_IRUSR | S_IWUSR | S_IXUSR) < 0)
+ perr("cannot give away file");
+
+ close(fd2);
+ if (posixly_correct) {
+ struct tm runtime;
+ char timestr[TIMESIZE];
+ runtime = *localtime(&runtimer);
+ strftime(timestr, TIMESIZE, "%a %b %e %T %Y", &runtime);
+ fprintf(stderr, "job %ld at %s\n", jobno, timestr);
+ } else
+ fprintf(stderr, "Job %ld will be executed using /bin/sh\n", jobno);
+}
+
+static int
+in_job_list(long job, long *joblist, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ if (job == joblist[i])
+ return 1;
+
+ return 0;
+}
+
+static void
+list_one_job(char *name, long *joblist, int len, int *first)
+{
+ struct stat buf;
+ struct tm runtime;
+ unsigned long ctm;
+ char queue;
+ long jobno;
+ time_t runtimer;
+ char timestr[TIMESIZE];
+
+ if (stat(name, &buf) != 0)
+ perr("cannot stat in " ATJOB_DIR);
+
+ /* See it's a regular file and has its x bit turned on and
+ * is the user's
+ */
+ if (!S_ISREG(buf.st_mode)
+ || ((buf.st_uid != real_uid) && ! (real_uid == 0))
+ || !(S_IXUSR & buf.st_mode || atverify))
+ return;
+
+ if(sscanf(name, "%c%5lx%8lx", &queue, &jobno, &ctm)!=3)
+ return;
+
+ /* If jobs are given, only list those jobs */
+ if (joblist && !in_job_list(jobno, joblist, len))
+ return;
+
+ if (atqueue && (queue != atqueue))
+ return;
+
+ runtimer = 60*(time_t) ctm;
+ runtime = *localtime(&runtimer);
+ strftime(timestr, TIMESIZE, "%a %b %e %T %Y", &runtime);
+ if (*first) {
+ if (!posixly_correct)
+ printf("Date\t\t\t\tOwner\t\tQueue\tJob#\n");
+ *first=0;
+ }
+ if (posixly_correct)
+ printf("%ld\t%s\n", jobno, timestr);
+ else {
+ struct passwd *pw = getpwuid(buf.st_uid);
+
+ printf("%s\t%s\t%c%s\t%s\n",
+ timestr,
+ pw ? pw->pw_name : "???",
+ queue,
+ (S_IXUSR & buf.st_mode) ? "":"(done)",
+ name);
+ }
+}
+
+static void
+list_jobs(long *joblist, int len)
+{
+ /* List all a user's jobs in the queue, by looping through ATJOB_DIR,
+ * or everybody's if we are root
+ */
+ DIR *spool;
+ struct dirent *dirent;
+ int first=1;
+
+#ifdef __FreeBSD__
+ (void) setlocale(LC_TIME, "");
+#endif
+
+ PRIV_START
+
+ if (chdir(ATJOB_DIR) != 0)
+ perr("cannot change to " ATJOB_DIR);
+
+ if (joblist) { /* Force order to match POSIX */
+ char jobglob[32];
+ glob_t g;
+ int i;
+
+ sprintf(jobglob, "?%05lx*", joblist[0]);
+ g.gl_offs = 0;
+ glob(jobglob, GLOB_DOOFFS, NULL, &g);
+ for (i = 1; i < len; i++) {
+ sprintf(jobglob, "?%05lx*", joblist[i]);
+ glob(jobglob, GLOB_DOOFFS | GLOB_APPEND, NULL, &g);
+ }
+ for (i = 0; i < g.gl_pathc; i++) {
+ list_one_job(g.gl_pathv[i], joblist, len, &first);
+ }
+ globfree(&g);
+ } else {
+ if ((spool = opendir(".")) == NULL)
+ perr("cannot open " ATJOB_DIR);
+
+ /* Loop over every file in the directory
+ */
+ while((dirent = readdir(spool)) != NULL) {
+ list_one_job(dirent->d_name, joblist, len, &first);
+ }
+ closedir(spool);
+ }
+ PRIV_END
+}
+
+static void
+process_jobs(int argc, char **argv, int what)
+{
+ /* Delete every argument (job - ID) given
+ */
+ int i;
+ struct stat buf;
+ DIR *spool;
+ struct dirent *dirent;
+ unsigned long ctm;
+ char queue;
+ long jobno;
+
+ PRIV_START
+
+ if (chdir(ATJOB_DIR) != 0)
+ perr("cannot change to " ATJOB_DIR);
+
+ if ((spool = opendir(".")) == NULL)
+ perr("cannot open " ATJOB_DIR);
+
+ PRIV_END
+
+ /* Loop over every file in the directory
+ */
+ while((dirent = readdir(spool)) != NULL) {
+
+ PRIV_START
+ if (stat(dirent->d_name, &buf) != 0)
+ perr("cannot stat in " ATJOB_DIR);
+ PRIV_END
+
+ if(sscanf(dirent->d_name, "%c%5lx%8lx", &queue, &jobno, &ctm)!=3)
+ continue;
+
+ for (i=optind; i < argc; i++) {
+ if (atoi(argv[i]) == jobno || strcmp(argv[i], dirent->d_name)==0) {
+ if ((buf.st_uid != real_uid) && !(real_uid == 0))
+ errx(EXIT_FAILURE, "%s: not owner", argv[i]);
+ switch (what) {
+ case ATRM:
+
+ PRIV_START
+
+ if (unlink(dirent->d_name) != 0)
+ perr(dirent->d_name);
+
+ PRIV_END
+
+ break;
+
+ case CAT:
+ {
+ FILE *fp;
+ int ch;
+
+ PRIV_START
+
+ fp = fopen(dirent->d_name,"r");
+
+ PRIV_END
+
+ if (!fp) {
+ perr("cannot open file");
+ }
+ while((ch = getc(fp)) != EOF) {
+ putchar(ch);
+ }
+ fclose(fp);
+ }
+ break;
+
+ default:
+ errx(EXIT_FAILURE, "internal error, process_jobs = %d",
+ what);
+ }
+ }
+ }
+ }
+ closedir(spool);
+} /* process_jobs */
+
+#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
+
+static time_t
+ttime(const char *arg)
+{
+ /*
+ * This is pretty much a copy of stime_arg1() from touch.c. I changed
+ * the return value and the argument list because it's more convenient
+ * (IMO) to do everything in one place. - Joe Halpin
+ */
+ struct timeval tv[2];
+ time_t now;
+ struct tm *t;
+ int yearset;
+ char *p;
+
+ if (gettimeofday(&tv[0], NULL))
+ panic("Cannot get current time");
+
+ /* Start with the current time. */
+ now = tv[0].tv_sec;
+ if ((t = localtime(&now)) == NULL)
+ panic("localtime");
+ /* [[CC]YY]MMDDhhmm[.SS] */
+ if ((p = strchr(arg, '.')) == NULL)
+ t->tm_sec = 0; /* Seconds defaults to 0. */
+ else {
+ if (strlen(p + 1) != 2)
+ goto terr;
+ *p++ = '\0';
+ t->tm_sec = ATOI2(p);
+ }
+
+ yearset = 0;
+ switch(strlen(arg)) {
+ case 12: /* CCYYMMDDhhmm */
+ t->tm_year = ATOI2(arg);
+ t->tm_year *= 100;
+ yearset = 1;
+ /* FALLTHROUGH */
+ case 10: /* YYMMDDhhmm */
+ if (yearset) {
+ yearset = ATOI2(arg);
+ t->tm_year += yearset;
+ } else {
+ yearset = ATOI2(arg);
+ t->tm_year = yearset + 2000;
+ }
+ t->tm_year -= 1900; /* Convert to UNIX time. */
+ /* FALLTHROUGH */
+ case 8: /* MMDDhhmm */
+ t->tm_mon = ATOI2(arg);
+ --t->tm_mon; /* Convert from 01-12 to 00-11 */
+ t->tm_mday = ATOI2(arg);
+ t->tm_hour = ATOI2(arg);
+ t->tm_min = ATOI2(arg);
+ break;
+ default:
+ goto terr;
+ }
+
+ t->tm_isdst = -1; /* Figure out DST. */
+ tv[0].tv_sec = tv[1].tv_sec = mktime(t);
+ if (tv[0].tv_sec != -1)
+ return tv[0].tv_sec;
+ else
+terr:
+ panic(
+ "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]");
+}
+
+static long *
+get_job_list(int argc, char *argv[], int *joblen)
+{
+ int i, len;
+ long *joblist;
+ char *ep;
+
+ joblist = NULL;
+ len = argc;
+ if (len > 0) {
+ if ((joblist = malloc(len * sizeof(*joblist))) == NULL)
+ panic("out of memory");
+
+ for (i = 0; i < argc; i++) {
+ errno = 0;
+ if ((joblist[i] = strtol(argv[i], &ep, 10)) < 0 ||
+ ep == argv[i] || *ep != '\0' || errno)
+ panic("invalid job number");
+ }
+ }
+
+ *joblen = len;
+ return joblist;
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ char queue = DEFAULT_AT_QUEUE;
+ char queue_set = 0;
+ char *pgm;
+
+ int program = AT; /* our default program */
+ const char *options = "q:f:t:rmvldbc"; /* default options for at */
+ time_t timer;
+ long *joblist;
+ int joblen;
+
+ posixly_correct = COMPAT_MODE("bin/at", "Unix2003");
+ joblist = NULL;
+ joblen = 0;
+ timer = -1;
+ RELINQUISH_PRIVS
+
+ if (argv[0] == NULL)
+ usage();
+ /* Eat any leading paths
+ */
+ if ((pgm = strrchr(argv[0], '/')) == NULL)
+ pgm = argv[0];
+ else
+ pgm++;
+
+ namep = pgm;
+
+ /* find out what this program is supposed to do
+ */
+ if (strcmp(pgm, "atq") == 0) {
+ program = ATQ;
+ options = "q:v";
+ }
+ else if (strcmp(pgm, "atrm") == 0) {
+ program = ATRM;
+ options = "";
+ }
+ else if (strcmp(pgm, "batch") == 0) {
+ program = BATCH;
+ options = "f:q:mv";
+ }
+
+ /* process whatever options we can process
+ */
+ opterr=1;
+ while ((c=getopt(argc, argv, options)) != -1)
+ switch (c) {
+ case 'v': /* verify time settings */
+ atverify = 1;
+ break;
+
+ case 'm': /* send mail when job is complete */
+ send_mail = 1;
+ break;
+
+ case 'f':
+ atinput = optarg;
+ break;
+
+ case 'q': /* specify queue */
+ if (strlen(optarg) > 1)
+ usage();
+
+ atqueue = queue = *optarg;
+ if (!(islower(queue)||isupper(queue)))
+ usage();
+
+ queue_set = 1;
+ break;
+
+ case 'd':
+ warnx("-d is deprecated; use -r instead");
+ /* fall through to 'r' */
+
+ case 'r':
+ if (program != AT)
+ usage();
+
+ program = ATRM;
+ options = "";
+ break;
+
+ case 't':
+ if (program != AT)
+ usage();
+ timer = ttime(optarg);
+ break;
+
+ case 'l':
+ if (program != AT)
+ usage();
+
+ program = ATQ;
+ options = "q:";
+ break;
+
+ case 'b':
+ if (program != AT)
+ usage();
+
+ program = BATCH;
+ options = "f:q:mv";
+ break;
+
+ case 'c':
+ program = CAT;
+ options = "";
+ break;
+
+ default:
+ usage();
+ break;
+ }
+ /* end of options eating
+ */
+
+ /* select our program
+ */
+ if(!check_permission())
+ errx(EXIT_FAILURE, "you do not have permission to use this program");
+ switch (program) {
+ case ATQ:
+
+ REDUCE_PRIV(DAEMON_UID, DAEMON_GID)
+
+ if (queue_set == 0)
+ joblist = get_job_list(argc - optind, argv + optind, &joblen);
+ list_jobs(joblist, joblen);
+ break;
+
+ case ATRM:
+
+ REDUCE_PRIV(DAEMON_UID, DAEMON_GID)
+
+ process_jobs(argc, argv, ATRM);
+ break;
+
+ case CAT:
+
+ process_jobs(argc, argv, CAT);
+ break;
+
+ case AT:
+ /*
+ * If timer is > -1, then the user gave the time with -t. In that
+ * case, it's already been set. If not, set it now.
+ */
+ if (timer == -1)
+ timer = parsetime(argc, argv);
+
+ if (atverify)
+ {
+ struct tm *tm = localtime(&timer);
+ fprintf(stderr, "%s\n", asctime(tm));
+ }
+ writefile(timer, queue);
+ break;
+
+ case BATCH:
+ if (queue_set)
+ queue = toupper(queue);
+ else
+ queue = DEFAULT_BATCH_QUEUE;
+
+ if (argc > optind)
+ timer = parsetime(argc, argv);
+ else
+ timer = time(NULL);
+
+ if (atverify)
+ {
+ struct tm *tm = localtime(&timer);
+ fprintf(stderr, "%s\n", asctime(tm));
+ }
+
+ writefile(timer, queue);
+ break;
+
+ default:
+ panic("internal error");
+ break;
+ }
+ exit(EXIT_SUCCESS);
+}
--- /dev/null
+/*
+ * at.h - header for at(1)
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER 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.
+ *
+ * $FreeBSD: src/usr.bin/at/at.h,v 1.5 2001/07/24 14:15:51 obrien Exp $
+ */
+
+extern int fcreated;
+extern char *namep;
+extern char atfile[];
+extern char atverify;
--- /dev/null
+/*
+ * panic.c - terminate fast in case of error
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/at/panic.c,v 1.17 2002/05/16 00:47:14 tjr Exp $");
+
+/* System Headers */
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Local headers */
+
+#include "panic.h"
+#include "privs.h"
+#include "at.h"
+
+/* External variables */
+
+/* Global functions */
+
+void
+panic(const char *a)
+{
+/* Something fatal has happened, print error message and exit.
+ */
+ if (fcreated) {
+ PRIV_START
+ unlink(atfile);
+ PRIV_END
+ }
+
+ errx(EXIT_FAILURE, "%s", a);
+}
+
+void
+perr(const char *a)
+{
+/* Some operating system error; print error message and exit.
+ */
+ int serrno = errno;
+
+ if (fcreated) {
+ PRIV_START
+ unlink(atfile);
+ PRIV_END
+ }
+
+ errno = serrno;
+ err(EXIT_FAILURE, "%s", a);
+}
+
+void
+usage(void)
+{
+ /* Print usage and exit. */
+ fprintf(stderr, "usage: at [-q x] [-f file] [-m] time\n"
+ " at -c job [job ...]\n"
+ " at [-f file] -t [[CC]YY]MMDDhhmm[.SS]\n"
+ " at -r job [job ...]\n"
+ " at -l -q queuename\n"
+ " at -l [job ...]\n"
+ " atq [-q x] [-v]\n"
+ " atrm job [job ...]\n"
+ " batch [-f file] [-m]\n");
+ exit(EXIT_FAILURE);
+}
--- /dev/null
+/*
+ * panic.h - header for at(1)
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER 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.
+ *
+ * $FreeBSD: src/usr.bin/at/panic.h,v 1.6 2002/01/13 20:21:08 mike Exp $
+ */
+
+#include <sys/cdefs.h>
+
+void panic(const char *a) __dead2;
+void perr(const char *a) __dead2;
+void usage(void) __dead2;
--- /dev/null
+/*
+ * parsetime.c - parse time for at(1)
+ * Copyright (C) 1993, 1994 Thomas Koenig
+ *
+ * modifications for English-language times
+ * Copyright (C) 1993 David Parsons
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER 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.
+ *
+ * at [NOW] PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS
+ * DOT ::= ':'|'.'
+ * /NUMBER [DOT NUMBER] [AM|PM]\ /[MONTH NUMBER [NUMBER]] \
+ * |NOON | |[TOMORROW] |
+ * |MIDNIGHT | |[DAY OF WEEK] |
+ * \TEATIME / |NUMBER [SLASH NUMBER [SLASH NUMBER]]|
+ * \PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS/
+ */
+
+#include <sys/cdefs.h>
+__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 */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+#ifndef __FreeBSD__
+#include <getopt.h>
+#endif
+
+/* Local headers */
+
+#include "at.h"
+#include "panic.h"
+#include "parsetime.h"
+
+
+/* Structures and unions */
+
+enum { /* symbols */
+ MIDNIGHT, NOON, TEATIME,
+ PM, AM, TOMORROW, TODAY, NOW,
+ MINUTES, HOURS, DAYS, WEEKS, MONTHS, YEARS,
+ NUMBER, PLUS, DOT, COMMA, SLASH, ID, JUNK,
+ JAN, FEB, MAR, APR, MAY, JUN,
+ JUL, AUG, SEP, OCT, NOV, DEC,
+ SUN, MON, TUE, WED, THU, FRI, SAT,
+ UTC
+ };
+
+/* parse translation table - table driven parsers can be your FRIEND!
+ */
+static const struct {
+ const char *name; /* token name */
+ int value; /* token id */
+ int plural; /* is this plural? */
+} Specials[] = {
+ { "midnight", MIDNIGHT,0 }, /* 00:00:00 of today or tomorrow */
+ { "noon", NOON,0 }, /* 12:00:00 of today or tomorrow */
+ { "teatime", TEATIME,0 }, /* 16:00:00 of today or tomorrow */
+ { "am", AM,0 }, /* morning times for 0-12 clock */
+ { "pm", PM,0 }, /* evening times for 0-12 clock */
+ { "tomorrow", TOMORROW,0 }, /* execute 24 hours from time */
+ { "today", TODAY, 0 }, /* execute today - don't advance time */
+ { "now", NOW,0 }, /* opt prefix for PLUS */
+
+ { "minute", MINUTES,0 }, /* minutes multiplier */
+ { "minutes", MINUTES,1 }, /* (pluralized) */
+ { "hour", HOURS,0 }, /* hours ... */
+ { "hours", HOURS,1 }, /* (pluralized) */
+ { "day", DAYS,0 }, /* days ... */
+ { "days", DAYS,1 }, /* (pluralized) */
+ { "week", WEEKS,0 }, /* week ... */
+ { "weeks", WEEKS,1 }, /* (pluralized) */
+ { "month", MONTHS,0 }, /* month ... */
+ { "months", MONTHS,1 }, /* (pluralized) */
+ { "year", YEARS,0 }, /* year ... */
+ { "years", YEARS,1 }, /* (pluralized) */
+ { "jan", JAN,0 },
+ { "feb", FEB,0 },
+ { "mar", MAR,0 },
+ { "apr", APR,0 },
+ { "may", MAY,0 },
+ { "jun", JUN,0 },
+ { "jul", JUL,0 },
+ { "aug", AUG,0 },
+ { "sep", SEP,0 },
+ { "oct", OCT,0 },
+ { "nov", NOV,0 },
+ { "dec", DEC,0 },
+ { "january", JAN,0 },
+ { "february", FEB,0 },
+ { "march", MAR,0 },
+ { "april", APR,0 },
+ { "may", MAY,0 },
+ { "june", JUN,0 },
+ { "july", JUL,0 },
+ { "august", AUG,0 },
+ { "september", SEP,0 },
+ { "october", OCT,0 },
+ { "november", NOV,0 },
+ { "december", DEC,0 },
+ { "sunday", SUN, 0 },
+ { "sun", SUN, 0 },
+ { "monday", MON, 0 },
+ { "mon", MON, 0 },
+ { "tuesday", TUE, 0 },
+ { "tue", TUE, 0 },
+ { "wednesday", WED, 0 },
+ { "wed", WED, 0 },
+ { "thursday", THU, 0 },
+ { "thu", THU, 0 },
+ { "friday", FRI, 0 },
+ { "fri", FRI, 0 },
+ { "saturday", SAT, 0 },
+ { "sat", SAT, 0 },
+ { "utc", UTC, 0 },
+} ;
+
+/* File scope variables */
+
+static char **scp; /* scanner - pointer at arglist */
+static char scc; /* scanner - count of remaining arguments */
+static char *sct; /* scanner - next char pointer in current argument */
+static int need; /* scanner - need to advance to next argument */
+
+static char *sc_token; /* scanner - token buffer */
+static size_t sc_len; /* scanner - length of token buffer */
+static int sc_tokid; /* scanner - token id */
+static int sc_tokplur; /* scanner - is token plural? */
+
+/* Local functions */
+
+/*
+ * parse a token, checking if it's something special to us
+ */
+static int
+parse_token(char *arg)
+{
+ size_t i;
+
+ for (i=0; i<(sizeof Specials/sizeof Specials[0]); i++)
+ if (strcasecmp(Specials[i].name, arg) == 0) {
+ sc_tokplur = Specials[i].plural;
+ return sc_tokid = Specials[i].value;
+ }
+
+ /* not special - must be some random id */
+ return ID;
+} /* parse_token */
+
+
+/*
+ * init_scanner() sets up the scanner to eat arguments
+ */
+static void
+init_scanner(int argc, char **argv)
+{
+ scp = argv;
+ scc = argc;
+ need = 1;
+ sc_len = 1;
+ while (argc-- > 0)
+ sc_len += strlen(*argv++);
+
+ if ((sc_token = malloc(sc_len)) == NULL)
+ errx(EXIT_FAILURE, "virtual memory exhausted");
+} /* init_scanner */
+
+/*
+ * token() fetches a token from the input stream
+ */
+static int
+token(void)
+{
+ int idx;
+
+ while (1) {
+ memset(sc_token, 0, sc_len);
+ sc_tokid = EOF;
+ sc_tokplur = 0;
+ idx = 0;
+
+ /* if we need to read another argument, walk along the argument list;
+ * when we fall off the arglist, we'll just return EOF forever
+ */
+ if (need) {
+ if (scc < 1)
+ return sc_tokid;
+ sct = *scp;
+ scp++;
+ scc--;
+ need = 0;
+ }
+ /* eat whitespace now - if we walk off the end of the argument,
+ * we'll continue, which puts us up at the top of the while loop
+ * to fetch the next argument in
+ */
+ while (isspace(*sct))
+ ++sct;
+ if (!*sct) {
+ need = 1;
+ continue;
+ }
+
+ /* preserve the first character of the new token
+ */
+ sc_token[0] = *sct++;
+
+ /* then see what it is
+ */
+ if (isdigit(sc_token[0])) {
+ while (isdigit(*sct))
+ sc_token[++idx] = *sct++;
+ sc_token[++idx] = 0;
+ return sc_tokid = NUMBER;
+ }
+ else if (isalpha(sc_token[0])) {
+ while (isalpha(*sct))
+ sc_token[++idx] = *sct++;
+ sc_token[++idx] = 0;
+ return parse_token(sc_token);
+ }
+ else if (sc_token[0] == ':' || sc_token[0] == '.')
+ return sc_tokid = DOT;
+ else if (sc_token[0] == '+')
+ return sc_tokid = PLUS;
+ else if (sc_token[0] == '/')
+ return sc_tokid = SLASH;
+ else if (sc_token[0] == ',')
+ return sc_tokid = COMMA;
+ else
+ return sc_tokid = JUNK;
+ } /* while (1) */
+} /* token */
+
+
+/*
+ * plonk() gives an appropriate error message if a token is incorrect
+ */
+static void
+plonk(int tok)
+{
+ panic((tok == EOF) ? "incomplete time"
+ : "garbled time");
+} /* plonk */
+
+
+/*
+ * expect() gets a token and dies most horribly if it's not the token we want
+ */
+static void
+expect(int desired)
+{
+ if (token() != desired)
+ plonk(sc_tokid); /* and we die here... */
+} /* expect */
+
+
+/*
+ * plus() parses a now + time
+ *
+ * at [NOW] PLUS NUMBER [MINUTES|HOURS|DAYS|WEEKS|MONTHS|YEARS]
+ *
+ */
+
+static void
+plus(struct tm *tm)
+{
+ int delay;
+ int expectplur;
+
+ expect(NUMBER);
+
+ delay = atoi(sc_token);
+ expectplur = (delay != 1) ? 1 : 0;
+
+ switch (token()) {
+ case YEARS:
+ tm->tm_year += delay;
+ break;
+ case MONTHS:
+ tm->tm_mon += delay;
+ break;
+ case WEEKS:
+ delay *= 7;
+ case DAYS:
+ tm->tm_mday += delay;
+ break;
+ case HOURS:
+ tm->tm_hour += delay;
+ break;
+ case MINUTES:
+ tm->tm_min += delay;
+ break;
+ default:
+ plonk(sc_tokid);
+ break;
+ }
+
+ if (expectplur != sc_tokplur)
+ warnx("pluralization is wrong");
+
+ tm->tm_isdst = -1;
+ if (mktime(tm) < 0)
+ plonk(sc_tokid);
+
+} /* plus */
+
+
+/*
+ * tod() computes the time of day
+ * [NUMBER [DOT NUMBER] [AM|PM]] [UTC]
+ */
+static void
+tod(struct tm *tm)
+{
+ int hour, minute = 0;
+ size_t tlen;
+
+ hour = atoi(sc_token);
+ tlen = strlen(sc_token);
+
+ /* first pick out the time of day - if it's 4 digits, we assume
+ * a HHMM time, otherwise it's HH DOT MM time
+ */
+ if (token() == DOT) {
+ expect(NUMBER);
+ minute = atoi(sc_token);
+ if (minute > 59)
+ panic("garbled time");
+ token();
+ }
+ else if (tlen == 4) {
+ minute = hour%100;
+ if (minute > 59)
+ panic("garbled time");
+ hour = hour/100;
+ }
+
+ /* check if an AM or PM specifier was given
+ */
+ switch (sc_tokid) {
+ case AM:
+ case PM:
+ if (hour > 12)
+ panic("garbled time");
+
+ if (sc_tokid == PM) {
+ if (hour != 12) /* 12:xx PM is 12:xx, not 24:xx */
+ hour += 12;
+ } else {
+ if (hour == 12) /* 12:xx AM is 00:xx, not 12:xx */
+ hour = 0;
+ }
+ if (UTC != token())
+ break; /* else fallthrough */
+
+ case UTC:
+ hour += tm->tm_gmtoff/(60*60);
+ while (hour < 0)
+ hour += 24;
+ minute += (tm->tm_gmtoff/60);
+ while (minute < 0)
+ minute += 60;
+ tm->tm_gmtoff = 0;
+ token();
+ break;
+ default:
+ if (hour > 23)
+ panic("garbled time");
+ break;
+ }
+
+ /* if we specify an absolute time, we don't want to bump the day even
+ * if we've gone past that time - but if we're specifying a time plus
+ * a relative offset, it's okay to bump things
+ * If minutes are the same assume tomorrow was meant
+ */
+ if ((sc_tokid == EOF || sc_tokid == PLUS) &&
+ ((tm->tm_hour > hour) || ((tm->tm_hour == hour) && (tm->tm_min >= minute)))) {
+ tm->tm_mday++;
+ tm->tm_wday++;
+ }
+
+ tm->tm_hour = hour;
+ tm->tm_min = minute;
+ if (tm->tm_hour == 24) {
+ tm->tm_hour = 0;
+ tm->tm_mday++;
+ }
+} /* tod */
+
+
+/*
+ * assign_date() assigns a date, wrapping to next year if needed
+ */
+static void
+assign_date(struct tm *tm, long mday, long mon, long year)
+{
+ /*
+ * Convert year into tm_year format (year - 1900).
+ * We may be given the year in 2 digit, 4 digit, or tm_year format.
+ */
+ if (year != -1) {
+ if (year >= TM_YEAR_BASE)
+ year -= TM_YEAR_BASE; /* convert from 4 digit year */
+ else if (year < 100) {
+ /* convert from 2 digit year */
+ struct tm *lt;
+ time_t now;
+
+ time(&now);
+ lt = localtime(&now);
+
+ /* Convert to tm_year assuming current century */
+ year += (lt->tm_year / 100) * 100;
+
+ if (year == lt->tm_year - 1) year++;
+ else if (year < lt->tm_year)
+ year += 100; /* must be in next century */
+ }
+ }
+
+ if (year < 0 &&
+ (tm->tm_mon > mon ||(tm->tm_mon == mon && tm->tm_mday > mday)))
+ year = tm->tm_year + 1;
+
+ tm->tm_mday = mday;
+ tm->tm_mon = mon;
+
+ if (year >= 0)
+ tm->tm_year = year;
+} /* assign_date */
+
+
+/*
+ * month() picks apart a month specification
+ *
+ * /[<month> NUMBER [NUMBER]] \
+ * |[TOMORROW] |
+ * |[DAY OF WEEK] |
+ * |NUMBER [SLASH NUMBER [SLASH NUMBER]]|
+ * \PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS/
+ */
+static void
+month(struct tm *tm)
+{
+ long year= (-1);
+ long mday = 0, wday, mon;
+ int tlen;
+
+ switch (sc_tokid) {
+ case PLUS:
+ plus(tm);
+ break;
+
+ case TOMORROW:
+ /* do something tomorrow */
+ tm->tm_mday ++;
+ tm->tm_wday ++;
+ case TODAY: /* force ourselves to stay in today - no further processing */
+ token();
+ break;
+
+ case JAN: case FEB: case MAR: case APR: case MAY: case JUN:
+ case JUL: case AUG: case SEP: case OCT: case NOV: case DEC:
+ /* do month mday [,year]
+ */
+ mon = (sc_tokid-JAN);
+ expect(NUMBER);
+ mday = atol(sc_token);
+ if (token() == COMMA) {
+ if (token() == NUMBER) {
+ year = atol(sc_token);
+ token();
+ }
+ }
+ assign_date(tm, mday, mon, year);
+ if (sc_tokid == PLUS)
+ plus(tm);
+ break;
+
+ case SUN: case MON: case TUE:
+ case WED: case THU: case FRI:
+ case SAT:
+ /* do a particular day of the week
+ */
+ wday = (sc_tokid-SUN);
+
+ mday = tm->tm_mday;
+
+ /* if this day is < today, then roll to next week
+ */
+ if (wday < tm->tm_wday)
+ mday += 7 - (tm->tm_wday - wday);
+ else
+ mday += (wday - tm->tm_wday);
+
+ tm->tm_wday = wday;
+
+ assign_date(tm, mday, tm->tm_mon, tm->tm_year);
+ break;
+
+ case NUMBER:
+ /* get numeric MMDDYY, mm/dd/yy, or dd.mm.yy
+ */
+ tlen = strlen(sc_token);
+ mon = atol(sc_token);
+ token();
+
+ if (sc_tokid == SLASH || sc_tokid == DOT) {
+ int sep;
+
+ sep = sc_tokid;
+ expect(NUMBER);
+ mday = atol(sc_token);
+ if (token() == sep) {
+ expect(NUMBER);
+ year = atol(sc_token);
+ token();
+ }
+
+ /* flip months and days for European timing
+ */
+ if (sep == DOT) {
+ int x = mday;
+ mday = mon;
+ mon = x;
+ }
+ }
+ else if (tlen == 6 || tlen == 8) {
+ if (tlen == 8) {
+ year = (mon % 10000) - TM_YEAR_BASE;
+ mon /= 10000;
+ }
+ else {
+ year = mon % 100;
+ mon /= 100;
+ }
+ mday = mon % 100;
+ mon /= 100;
+ }
+ else
+ panic("garbled time");
+
+ mon--;
+ if (mon < 0 || mon > 11 || mday < 1 || mday > 31)
+ panic("garbled time");
+
+ assign_date(tm, mday, mon, year);
+ break;
+ } /* case */
+} /* month */
+
+
+/* Global functions */
+
+time_t
+parsetime(int argc, char **argv)
+{
+/* Do the argument parsing, die if necessary, and return the time the job
+ * should be run.
+ */
+ time_t nowtimer, runtimer;
+ struct tm nowtime, runtime;
+ int hr = 0;
+ /* this MUST be initialized to zero for midnight/noon/teatime */
+
+ nowtimer = time(NULL);
+ nowtime = *localtime(&nowtimer);
+
+ runtime = nowtime;
+ runtime.tm_sec = 0;
+ runtime.tm_isdst = 0;
+
+ if (argc <= optind)
+ usage();
+
+ init_scanner(argc-optind, argv+optind);
+
+ switch (token()) {
+ case NOW:
+ if (scc < 1) {
+ return nowtimer;
+ }
+ /* now is optional prefix for PLUS tree */
+ expect(PLUS);
+ case PLUS:
+ plus(&runtime);
+ break;
+
+ case NUMBER:
+ tod(&runtime);
+ month(&runtime);
+ break;
+
+ /* evil coding for TEATIME|NOON|MIDNIGHT - we've initialised
+ * hr to zero up above, then fall into this case in such a
+ * way so we add +12 +4 hours to it for teatime, +12 hours
+ * to it for noon, and nothing at all for midnight, then
+ * set our runtime to that hour before leaping into the
+ * month scanner
+ */
+ case TEATIME:
+ hr += 4;
+ case NOON:
+ hr += 12;
+ case MIDNIGHT:
+ if (runtime.tm_hour >= hr) {
+ runtime.tm_mday++;
+ runtime.tm_wday++;
+ }
+ runtime.tm_hour = hr;
+ runtime.tm_min = 0;
+ token();
+ /* FALLTHROUGH to month setting */
+ default:
+ month(&runtime);
+ break;
+ } /* ugly case statement */
+ expect(EOF);
+
+ /* convert back to time_t
+ */
+ runtime.tm_isdst = -1;
+ runtimer = mktime(&runtime);
+
+ if (runtimer < 0)
+ panic("garbled time");
+
+ if (nowtimer > runtimer)
+ panic("trying to travel back in time");
+
+ return runtimer;
+} /* parsetime */
--- /dev/null
+/*
+ * at.h - header for at(1)
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER 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.
+ */
+
+time_t parsetime(int argc, char **argv);
--- /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: pathnames.h,v 1.2 2005/07/30 01:30:01 lindak Exp $
+ */
+
+#ifndef _PATHNAMES_H_
+#define _PATHNAMES_H_
+
+#include <paths.h>
+
+#define _PATH_ATJOBS "/usr/lib/cron/jobs/"
+#define _PATH_ATSPOOL "/usr/lib/cron/spool/"
+/* Note: _PATH_LOCKFILE appears to be unused; /usr/lib/cron/jobs/.lockfile
+ is the file currently being used by at.*/
+#define _PATH_LOCKFILE "/usr/lib/cron/.lockfile"
+#define _PATH_AT "/usr/lib/cron/"
+
+#endif /* !_PATHNAMES_H_ */
--- /dev/null
+/*
+ * perm.c - check user permission for at(1)
+ * Copyright (C) 1994 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/at/perm.c,v 1.13 2001/12/10 21:13:01 dwmalone Exp $");
+
+/* System Headers */
+
+#include <sys/types.h>
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Local headers */
+
+#include "at.h"
+#include "panic.h"
+#include "perm.h"
+#include "privs.h"
+
+/* Macros */
+
+#define MAXUSERID 10
+
+/* Structures and unions */
+
+/* Function declarations */
+
+static int check_for_user(FILE *fp,const char *name);
+
+/* Local functions */
+
+static int check_for_user(FILE *fp,const char *name)
+{
+ char *buffer;
+ size_t len;
+ int found = 0;
+
+ len = strlen(name);
+ if ((buffer = malloc(len+2)) == NULL)
+ errx(EXIT_FAILURE, "virtual memory exhausted");
+
+ while(fgets(buffer, len+2, fp) != NULL)
+ {
+ if ((strncmp(name, buffer, len) == 0) &&
+ (buffer[len] == '\n'))
+ {
+ found = 1;
+ break;
+ }
+ }
+ fclose(fp);
+ free(buffer);
+ return found;
+}
+/* Global functions */
+int check_permission(void)
+{
+ FILE *fp;
+ uid_t uid = geteuid();
+ struct passwd *pentry;
+
+ if (uid==0)
+ return 1;
+
+ if ((pentry = getpwuid(uid)) == NULL)
+ err(EXIT_FAILURE, "cannot access user database");
+
+ PRIV_START
+
+ fp=fopen(PERM_PATH "at.allow","r");
+
+ PRIV_END
+
+ if (fp != NULL)
+ {
+ return check_for_user(fp, pentry->pw_name);
+ }
+ else if (errno == ENOENT)
+ {
+
+ PRIV_START
+
+ fp=fopen(PERM_PATH "at.deny", "r");
+
+ PRIV_END
+
+ if (fp != NULL)
+ {
+ return !check_for_user(fp, pentry->pw_name);
+ }
+ else if (errno != ENOENT)
+ warn("at.deny");
+ }
+ else
+ warn("at.allow");
+ return 0;
+}
--- /dev/null
+/*
+ * perm.h - header for at(1)
+ * Copyright (C) 1994 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER 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.
+ *
+ * $FreeBSD: src/usr.bin/at/perm.h,v 1.4 2001/12/02 12:26:18 markm Exp $
+ */
+
+int check_permission(void);
--- /dev/null
+/*
+ * privs.h - header for privileged operations
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER 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.
+ *
+ * $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
+#define _PRIVS_H
+
+#include <unistd.h>
+
+/* Relinquish privileges temporarily for a setuid or setgid program
+ * with the option of getting them back later. This is done by
+ * utilizing POSIX saved user and group IDs. Call RELINQUISH_PRIVS once
+ * at the beginning of the main program. This will cause all operations
+ * to be executed with the real userid. When you need the privileges
+ * of the setuid/setgid invocation, call PRIV_START; when you no longer
+ * need it, call PRIV_END. Note that it is an error to call PRIV_START
+ * and not PRIV_END within the same function.
+ *
+ * Use RELINQUISH_PRIVS_ROOT(a,b) if your program started out running
+ * as root, and you want to drop back the effective userid to a
+ * and the effective group id to b, with the option to get them back
+ * later.
+ *
+ * If you no longer need root privileges, but those of some other
+ * userid/groupid, you can call REDUCE_PRIV(a,b) when your effective
+ * is the user's.
+ *
+ * Problems: Do not use return between PRIV_START and PRIV_END; this
+ * will cause the program to continue running in an unprivileged
+ * state.
+ *
+ * It is NOT safe to call exec(), system() or popen() with a user-
+ * supplied program (i.e. without carefully checking PATH and any
+ * library load paths) with relinquished privileges; the called program
+ * can acquire them just as easily. Set both effective and real userid
+ * to the real userid before calling any of them.
+ */
+
+#ifndef MAIN
+extern
+#endif
+uid_t real_uid, effective_uid;
+
+#ifndef MAIN
+extern
+#endif
+gid_t real_gid, effective_gid;
+
+#define RELINQUISH_PRIVS { \
+ real_uid = getuid(); \
+ effective_uid = geteuid(); \
+ real_gid = getgid(); \
+ effective_gid = getegid(); \
+ setegid(real_gid); \
+ seteuid(real_uid); \
+}
+
+#define RELINQUISH_PRIVS_ROOT(a, b) { \
+ real_uid = (a); \
+ effective_uid = geteuid(); \
+ real_gid = (b); \
+ effective_gid = getegid(); \
+ setegid(real_gid); \
+ seteuid(real_uid); \
+}
+
+#define PRIV_START { \
+ if (seteuid(0)<0) perr("cannot regain privs"); \
+ if (setegid(effective_gid)<0) perr("cannot reset gid"); \
+ if (seteuid(effective_uid)<0) perr("cannot reset uid"); \
+}
+
+#define PRIV_END { \
+ if (seteuid(0)<0) perr("cannot regain privs"); \
+ if (setegid(real_gid)<0) perr("cannot reset gid"); \
+ if (seteuid(real_uid)<0) perr("cannot reset uid"); \
+}
+
+#define REDUCE_PRIV(a, b) { \
+ PRIV_START \
+ effective_uid = (a); \
+ effective_gid = (b); \
+ setregid((gid_t)-1, effective_gid); \
+ setreuid((uid_t)-1, effective_uid); \
+ PRIV_END \
+}
+#endif
--- /dev/null
+.\"
+.\" 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.
+.\" 3. 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.8,v 1.1 1999/05/02 04:21:19 wsanchez Exp $
+.\"
+.Dd March 9, 2008
+.Dt ATRUN 8
+.Os "Mac OS X"
+.Sh NAME
+.Nm atrun
+.Nd run jobs queued for later execution
+.Sh SYNOPSIS
+.Nm atrun
+.Sh DESCRIPTION
+The
+.Nm atrun
+utility runs commands queued by
+.Xr at 1 .
+It is invoked periodically by
+.Xr launchd 8
+as specified in the
+.Pa com.apple.atrun.plist
+property list.
+By default the property list contains the
+.Em Disabled
+key set to true, so
+.Nm atrun
+is never invoked.
+.Pp
+Execute the following command as root to enable
+.Nm atrun :
+.Dl "launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist"
+.Pp
+.Sh FILES
+.Bl -tag -width /var/at/lockfile -compact
+.It Pa /var/at/jobs
+Directory containing job files
+.It Pa /var/at/spool
+Directory containing output spool files
+.It Pa /var/at/lockfile
+Job-creation lock file.
+.El
+.Sh SEE ALSO
+.Xr at 1 ,
+.Xr launchd 8
+.Sh AUTHOR
+.Bl -tag
+Thomas Koenig, ig25@rz.uni-karlsruhe.de
+.El
--- /dev/null
+/*
+ * atrun.c - run jobs queued by at; run with root privileges.
+ * Copyright (C) 1993, 1994 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER 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.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/atrun/atrun.c,v 1.27 2009/12/25 10:30:54 ed Exp $";
+#endif /* not lint */
+
+/* System Headers */
+
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+#if 1
+#include <paths.h>
+#else
+#include <getopt.h>
+#endif
+#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
+#define ATJOB_DIR _PATH_ATJOBS
+#endif
+
+#ifndef ATSPOOL_DIR
+#define ATSPOOL_DIR _PATH_ATSPOOL
+#endif
+
+#ifndef LOADAVG_MX
+#define LOADAVG_MX 1.5
+#endif
+
+/* File scope variables */
+
+static const char * const atrun = "atrun"; /* service name for syslog etc. */
+static int debug = 0;
+
+void perr(const char *fmt, ...);
+void perrx(const char *fmt, ...);
+static void usage(void);
+
+/* Local functions */
+static int
+write_string(int fd, const char* a)
+{
+ return write(fd, a, strlen(a));
+}
+
+#undef DEBUG_FORK
+#ifdef DEBUG_FORK
+static pid_t
+myfork(void)
+{
+ pid_t res;
+ res = fork();
+ if (res == 0)
+ kill(getpid(),SIGSTOP);
+ return res;
+}
+
+#define fork myfork
+#endif
+
+static void
+run_file(const char *filename, uid_t uid, gid_t gid)
+{
+/* Run a file by spawning off a process which redirects I/O,
+ * spawns a subshell, then waits for it to complete and sends
+ * mail to the user.
+ */
+ pid_t pid;
+ int fd_out, fd_in;
+ int queue;
+ char mailbuf[MAXLOGNAME], fmt[64];
+ char *mailname = NULL;
+ FILE *stream;
+ int send_mail = 0;
+ struct stat buf, lbuf;
+ off_t size;
+ struct passwd *pentry;
+ 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
+
+ if (chmod(filename, S_IRUSR) != 0)
+ {
+ perr("cannot change file permissions");
+ }
+
+ PRIV_END
+
+ pid = fork();
+ if (pid == -1)
+ perr("cannot fork");
+
+ else if (pid != 0)
+ return;
+
+#ifdef __APPLE__
+ {
+ pid_t pg = setsid();
+ if (pg == -1) syslog(LOG_ERR,"setsid() failed: %m");
+ }
+#endif
+
+ /* Let's see who we mail to. Hopefully, we can read it from
+ * the command file; if not, send it to the owner, or, failing that,
+ * to root.
+ */
+
+ pentry = getpwuid(uid);
+ if (pentry == NULL)
+ perrx("Userid %lu not found - aborting job %s",
+ (unsigned long) uid, filename);
+
+#ifdef PAM
+ PRIV_START
+
+ 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 */
+
+ PRIV_START
+
+ stream=fopen(filename, "r");
+
+ PRIV_END
+
+ if (stream == NULL)
+ perr("cannot open input file");
+
+ if ((fd_in = dup(fileno(stream))) <0)
+ perr("error duplicating input file descriptor");
+
+ if (fstat(fd_in, &buf) == -1)
+ perr("error in fstat of input file descriptor");
+
+ if (lstat(filename, &lbuf) == -1)
+ perr("error in fstat of input file");
+
+ 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))
+ perrx("Somebody changed files from under us for job %s - aborting",
+ filename);
+
+ 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);
+
+ 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)
+ perrx("Job %s - userid %ld does not match file uid %lu",
+ filename, nuid, (unsigned long)uid);
+
+ if (ngid != gid)
+ perrx("Job %s - groupid %ld does not match file gid %lu",
+ filename, ngid, (unsigned long)gid);
+
+ fclose(stream);
+
+ if (chdir(ATSPOOL_DIR) < 0)
+ 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.
+ */
+ if((fd_out=open(filename,
+ O_WRONLY | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR)) < 0)
+ perr("cannot create output file");
+
+ write_string(fd_out, "Subject: Output from your job ");
+ write_string(fd_out, filename);
+ write_string(fd_out, "\n\n");
+ fstat(fd_out, &buf);
+ size = buf.st_size;
+
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+
+ pid = fork();
+ if (pid < 0)
+ perr("error in fork");
+
+ else if (pid == 0)
+ {
+ char *nul = NULL;
+ char **nenvp = &nul;
+
+ /* Set up things for the child; we want standard input from the input file,
+ * and standard output and error sent to our output file.
+ */
+
+ if (lseek(fd_in, (off_t) 0, SEEK_SET) < 0)
+ perr("error in lseek");
+
+ if (dup(fd_in) != STDIN_FILENO)
+ perr("error in I/O redirection");
+
+ if (dup(fd_out) != STDOUT_FILENO)
+ perr("error in I/O redirection");
+
+ if (dup(fd_out) != STDERR_FILENO)
+ perr("error in I/O redirection");
+
+ close(fd_in);
+ close(fd_out);
+ if (chdir(ATJOB_DIR) < 0)
+ perr("cannot chdir to %s", ATJOB_DIR);
+
+ queue = *filename;
+
+ PRIV_START
+
+ 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 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("/");
+
+ if(execle("/bin/sh","sh",(char *) NULL, nenvp) != 0)
+ perr("exec failed for /bin/sh");
+
+ PRIV_END
+ }
+ /* We're the parent. Let's wait.
+ */
+ close(fd_in);
+ close(fd_out);
+ waitpid(pid, (int *) NULL, 0);
+
+ /* Send mail. Unlink the output file first, so it is deleted after
+ * the run.
+ */
+ stat(filename, &buf);
+ if (open(filename, O_RDONLY) != STDIN_FILENO)
+ perr("open of jobfile failed");
+
+ unlink(filename);
+ if ((buf.st_size != size) || send_mail)
+ {
+ 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 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("/");
+
+#if 1
+ execl(_PATH_SENDMAIL, "sendmail", "-F", "Atrun Service",
+ "-odi", "-oem",
+ mailname, (char *) NULL);
+#else
+ execl(MAIL_CMD, MAIL_CMD, mailname, (char *) NULL);
+#endif
+ perr("exec failed for mail command");
+
+ PRIV_END
+ }
+ exit(EXIT_SUCCESS);
+}
+
+/* Global functions */
+
+/* Needed in gloadavg.c */
+void
+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)
+ {
+ vwarn(fmt, ap);
+ }
+ else
+ {
+ 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);
+}
+
+int
+main(int argc, char *argv[])
+{
+/* Browse through ATJOB_DIR, checking all the jobfiles wether they should
+ * be executed and or deleted. The queue is coded into the first byte of
+ * the job filename, the date (in minutes since Eon) as a hex number in the
+ * following eight bytes, followed by a dot and a serial number. A file
+ * which has not been executed yet is denoted by its execute - bit set.
+ * For those files which are to be executed, run_file() is called, which forks
+ * off a child which takes care of I/O redirection, forks off another child
+ * for execution and yet another one, optionally, for sending mail.
+ * Files which already have run are removed during the next invocation.
+ */
+ DIR *spool;
+ struct dirent *dirent;
+ struct stat buf;
+ unsigned long ctm;
+ unsigned long jobno;
+ char queue;
+ time_t now, run_time;
+ char batch_name[] = "Z2345678901234";
+ uid_t batch_uid;
+ gid_t batch_gid;
+ int c;
+ int run_batch;
+ double load_avg = LOADAVG_MX, la;
+
+/* We don't need root privileges all the time; running under uid and gid daemon
+ * is fine.
+ */
+
+ RELINQUISH_PRIVS_ROOT(DAEMON_UID, DAEMON_GID)
+
+ openlog(atrun, LOG_PID, LOG_CRON);
+
+ opterr = 0;
+ while((c=getopt(argc, argv, "dl:"))!= -1)
+ {
+ switch (c)
+ {
+ case 'l':
+ if (sscanf(optarg, "%lf", &load_avg) != 1)
+ perr("garbled option -l");
+ if (load_avg <= 0.)
+ load_avg = LOADAVG_MX;
+ break;
+
+ case 'd':
+ debug ++;
+ break;
+
+ case '?':
+ default:
+ usage();
+ }
+ }
+
+ if (chdir(ATJOB_DIR) != 0)
+ 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
+ * and the x bit is set, fork off a child which sets its user and group
+ * id to that of the files and exec a /bin/sh which executes the shell
+ * script. Unlink older files if they should no longer be run. For
+ * deletion, their r bit has to be turned on.
+ *
+ * Also, pick the oldest batch job to run, at most one per invocation of
+ * atrun.
+ */
+ if ((spool = opendir(".")) == NULL)
+ perr("cannot read %s", ATJOB_DIR);
+
+ now = time(NULL);
+ run_batch = 0;
+ batch_uid = (uid_t) -1;
+ batch_gid = (gid_t) -1;
+
+ while ((dirent = readdir(spool)) != NULL) {
+ if (stat(dirent->d_name,&buf) != 0)
+ perr("cannot stat in %s", ATJOB_DIR);
+
+ /* We don't want directories
+ */
+ if (!S_ISREG(buf.st_mode))
+ continue;
+
+ if (sscanf(dirent->d_name,"%c%5lx%8lx",&queue,&jobno,&ctm) != 3)
+ continue;
+
+ run_time = (time_t) ctm*60;
+
+ if ((S_IXUSR & buf.st_mode) && (run_time <=now)) {
+ if ((isupper(queue) || queue == 'b') && (strcmp(batch_name,dirent->d_name) > 0)) {
+ run_batch = 1;
+ strlcpy(batch_name, dirent->d_name, sizeof(batch_name));
+ batch_uid = buf.st_uid;
+ batch_gid = buf.st_gid;
+ }
+
+ /* The file is executable and old enough
+ */
+ if (islower(queue))
+ run_file(dirent->d_name, buf.st_uid, buf.st_gid);
+ }
+ /* Delete older files
+ */
+ if ((run_time < now) && !(S_IXUSR & buf.st_mode) && (S_IRUSR & buf.st_mode))
+ unlink(dirent->d_name);
+ }
+ /* run the single batch file, if any
+ */
+ if (run_batch && (getloadavg(&la, 1) == 1) && la < load_avg)
+ run_file(batch_name, batch_uid, batch_gid);
+
+ closelog();
+#if __APPLE__
+ // allow enough time for child processes to call setsid(2)
+ sleep(1);
+#endif
+ exit(EXIT_SUCCESS);
+}
+
+static void
+usage(void)
+{
+ if (debug)
+ fprintf(stderr, "usage: atrun [-l load_avg] [-d]\n");
+ else
+ syslog(LOG_ERR, "usage: atrun [-l load_avg] [-d]");
+
+ exit(EXIT_FAILURE);
+}
--- /dev/null
+<?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>Label</key>
+ <string>com.apple.atrun</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/atrun</string>
+ </array>
+ <key>StartInterval</key>
+ <integer>30</integer>
+ <key>Disabled</key>
+ <true/>
+</dict>
+</plist>
--- /dev/null
+/*
+ * gloadavg.c - get load average for Linux
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER 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.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/atrun/gloadavg.c,v 1.5 1999/08/28 00:09:12 peter Exp $";
+#endif /* not lint */
+
+#ifndef __FreeBSD__
+#define _POSIX_SOURCE 1
+
+/* System Headers */
+
+#include <stdio.h>
+#else
+#include <stdlib.h>
+#endif
+
+/* Local headers */
+
+#include "gloadavg.h"
+
+/* Global functions */
+
+void perr(const char *a);
+
+double
+gloadavg(void)
+/* return the current load average as a floating point number, or <0 for
+ * error
+ */
+{
+ double result;
+#ifndef __FreeBSD__
+ FILE *fp;
+
+ if((fp=fopen(PROC_DIR "loadavg","r")) == NULL)
+ result = -1.0;
+ else
+ {
+ if(fscanf(fp,"%lf",&result) != 1)
+ result = -1.0;
+ fclose(fp);
+ }
+#else
+ if (getloadavg(&result, 1) != 1)
+ perr("error in getloadavg");
+#endif
+ return result;
+}
--- /dev/null
+/*
+ * gloadavg.h - header for atrun(8)
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER 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.
+ */
+
+double gloadavg(void);
+#if 0
+static char atrun_h_rcsid[] = "$FreeBSD: src/libexec/atrun/gloadavg.h,v 1.4 1999/08/28 00:09:12 peter Exp $";
+#endif
--- /dev/null
+.Dd July 20, 2004
+.Dt CHKPASSWD 8
+.Os Darwin
+.Sh NAME
+.Nm chkpasswd
+.Nd verifies user password against various systems
+.Sh SYNOPSIS
+.Nm chkpasswd
+.Op Fl i Ar infosystem Op Fl l Ar location
+.Op Fl c
+.Op Ar name
+.Sh DESCRIPTION
+.Nm chkpasswd
+verifies a supplied username and password against file, NIS,
+or OpenDirectory infosystems.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.\" ==========
+.It Fl c
+The supplied password is compared verbatim without first being encrypted.
+.\" ==========
+.It Fl i Ar infosystem
+Specify the system against which to check the password
+(default is PAM). Valid systems:
+.Bl -tag -width "opendirectory"
+.It Ar file
+File-based passwords
+.It Ar nis
+NIS/YP authentication
+.It Ar opendirectory
+OpenDirectory (Directory Services) authentication.
+If no
+.Fl l
+option is specified, the search node is used.
+.It Ar PAM
+Pluggable Authentication Modules
+.El
+.Pp
+.\" ==========
+.It Fl l Ar location
+Specify a location; varies based on infosystem type:
+.Bl -tag -width "for opendirectory"
+.It for file
+Filename (default: /etc/master.passwd).
+.It for nis
+NIS domainname.
+.It for opendirectory
+A directory node name such as /Local/Default.
+.It for PAM
+Unused.
+.El
+.Pp
+.El
+.Ar name
+username
+.Sh SEE ALSO
+.Xr dscl 1 ,
+.Xr passwd 5
--- /dev/null
+# chkpasswd: auth account
+auth required pam_opendirectory.so
+account required pam_opendirectory.so
+password required pam_permit.so
+session required pam_permit.so
--- /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@
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <errno.h>
+#include <string.h>
+#include "stringops.h"
+
+#define TEMP_FILE "/tmp/.pwtmp"
+
+#define _PASSWD_FILE "/etc/master.passwd"
+#define _COMPAT_FILE "/etc/passwd"
+#define _PASSWD_FIELDS 10
+#define BUFSIZE 8192
+
+extern void checkpasswd(char *, char *);
+
+char *
+_getline(FILE *fp)
+{
+ static char s[BUFSIZE];
+ int len;
+
+ s[0] = '\0';
+
+ fgets(s, BUFSIZE, fp);
+ if (s == NULL || s[0] == '\0') return NULL;
+
+ if (s[0] == '#') return s;
+
+ len = strlen(s) - 1;
+ s[len] = '\0';
+
+ return s;
+}
+
+struct passwd *
+parse_user(char *line)
+{
+ static struct passwd pw = {0};
+ char **tokens;
+ int i, len;
+
+ if (pw.pw_name != NULL) free(pw.pw_name);
+ pw.pw_name = NULL;
+ if (pw.pw_passwd != NULL) free(pw.pw_passwd);
+ pw.pw_passwd = NULL;
+ if (pw.pw_gecos != NULL) free(pw.pw_gecos);
+ pw.pw_gecos = NULL;
+ if (pw.pw_dir != NULL) free(pw.pw_dir);
+ pw.pw_dir = NULL;
+ if (pw.pw_shell != NULL) free(pw.pw_shell);
+ pw.pw_shell = NULL;
+
+ if (pw.pw_class != NULL) free(pw.pw_class);
+ pw.pw_class = NULL;
+
+ if (line == NULL) return (struct passwd *)NULL;
+ tokens = explode(line, ':');
+ len = listLength(tokens);
+
+ if (len != _PASSWD_FIELDS)
+ {
+ freeList(tokens);
+ return (struct passwd *)NULL;
+ }
+
+ i = 0;
+ pw.pw_name = tokens[i++];
+ pw.pw_passwd = tokens[i++];
+ pw.pw_uid = atoi(tokens[i]);
+ free(tokens[i++]);
+ pw.pw_gid = atoi(tokens[i]);
+ free(tokens[i++]);
+ pw.pw_class = tokens[i++];
+ pw.pw_change = atoi(tokens[i]);
+ free(tokens[i++]);
+ pw.pw_expire = atoi(tokens[i]);
+ free(tokens[i++]);
+ pw.pw_gecos = tokens[i++];
+ pw.pw_dir = tokens[i++];
+ pw.pw_shell = tokens[i++];
+
+ return &pw;
+}
+
+struct passwd *
+find_user(char *uname, FILE *fp)
+{
+ char *line;
+ struct passwd *pw;
+
+ rewind(fp);
+
+ while (NULL != (line = _getline(fp)))
+ {
+ if (line[0] == '#') continue;
+ pw = parse_user(line);
+ if (pw == (struct passwd *)NULL) continue;
+ if (!strcmp(uname, pw->pw_name)) return pw;
+ }
+
+ pw = parse_user(NULL);
+ return (struct passwd *)NULL;
+}
+
+void
+rewrite_file(char *pwname, FILE *fp, struct passwd *newpw)
+{
+ char *line;
+ struct passwd *pw;
+ FILE *tfp, *cfp;
+ char fname[256];
+
+ sprintf(fname, "%s.%d", TEMP_FILE, getpid());
+
+ tfp = fopen(fname, "w+");
+ if (tfp == NULL)
+ {
+ fprintf(stderr, "can't write temporary file \"%s\": ", fname);
+ perror("");
+ exit(1);
+ }
+
+ cfp = NULL;
+ if (!strcmp(pwname, _PASSWD_FILE))
+ {
+ cfp = fopen(_COMPAT_FILE, "w");
+ if (cfp == NULL)
+ {
+ fprintf(stderr, "warning: can't write compatability file \"%s\": ",
+ _COMPAT_FILE);
+ perror("");
+ }
+ }
+
+ if (cfp != NULL)
+ {
+ fprintf(cfp, "#\n");
+ fprintf(cfp, "# 4.3BSD-compatable User Database\n");
+ fprintf(cfp, "#\n");
+ fprintf(cfp, "# Note that this file is not consulted for login.\n");
+ fprintf(cfp, "# It only exisits for compatability with 4.3BSD utilities.\n");
+ fprintf(cfp, "#\n");
+ fprintf(cfp, "# This file is automatically re-written by various system utilities.\n");
+ fprintf(cfp, "# Do not edit this file. Changes will be lost.\n");
+ fprintf(cfp, "#\n");
+ }
+
+ rewind(fp);
+
+ while (NULL != (line = _getline(fp)))
+ {
+ if (line[0] == '#')
+ {
+ fprintf(tfp, "%s", line);
+ continue;
+ }
+
+ pw = parse_user(line);
+ if (pw == (struct passwd *)NULL)
+ {
+ fprintf(stderr, "warning: bad format for entry: \"%s\"\n", line);
+ fprintf(tfp, "%s\n", line);
+ if (cfp != NULL) fprintf(cfp, "%s\n", line);
+ continue;
+ }
+
+ if (strcmp(newpw->pw_name, pw->pw_name))
+ {
+ fprintf(tfp, "%s\n", line);
+ if (cfp != NULL) fprintf(cfp, "%s\n", line);
+ continue;
+ }
+
+ fprintf(tfp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
+ newpw->pw_name, newpw->pw_passwd, newpw->pw_uid, newpw->pw_gid,
+ newpw->pw_class, newpw->pw_change, newpw->pw_expire,
+ newpw->pw_gecos, newpw->pw_dir, newpw->pw_shell);
+ if (cfp != NULL)
+ {
+ fprintf(cfp, "%s:",newpw->pw_name);
+ if ((newpw->pw_passwd == NULL) || (newpw->pw_passwd[0] == '\0'))
+ fprintf(cfp, ":");
+ else
+ fprintf(cfp, "*:");
+ fprintf(cfp, "%d:%d:%s:%s:%s\n",
+ newpw->pw_uid, newpw->pw_gid, newpw->pw_gecos,
+ newpw->pw_dir, newpw->pw_shell);
+ }
+ }
+
+ if (cfp != NULL) fclose(cfp);
+ fclose(fp);
+ if (unlink(pwname) < 0)
+ {
+ fprintf(stderr, "can't update \"%s\": ", pwname);
+ perror("");
+ }
+
+ rewind(tfp);
+
+ fp = fopen(pwname, "w");
+ if (fp == NULL)
+ {
+ fprintf(stderr, "ERROR: lost file \"%s\"\n", pwname);
+ fprintf(stderr, "new passwd file is \"%s\"\n", fname);
+ perror("open");
+ exit(1);
+ }
+
+ while (NULL != (line = _getline(tfp)))
+ {
+ fprintf(fp, "%s", line);
+ if (line[0] != '#') fprintf(fp, "\n");
+ }
+ fclose(fp);
+ fclose(tfp);
+ unlink(fname);
+}
+
+int
+file_check_passwd(char *uname, char *locn)
+{
+ FILE *fp;
+ char *fname;
+ struct passwd *pw;
+
+ fname = _PASSWD_FILE;
+ if (locn != NULL) fname = locn;
+
+ if (access(fname,R_OK) || (fp = fopen(fname, "r")) == NULL)
+ {
+ fprintf(stderr, "can't read file \"%s\": ", fname);
+ perror("");
+ exit(1);
+ }
+
+
+ pw = find_user(uname, fp);
+ if (pw == (struct passwd *)NULL)
+ {
+ fprintf(stderr, "user %s not found in file %s\n", uname, fname);
+ exit(1);
+ }
+
+ checkpasswd(uname, pw->pw_passwd);
+ fclose(fp);
+
+ return 0;
+}
--- /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) 1998 by Apple Computer, Inc.
+ * Portions Copyright (c) 1988 by Sun Microsystems, Inc.
+ * Portions Copyright (c) 1988 The Regents of the University of California.
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+
+/* update a user's password in NIS. This was based on the Sun implementation
+ * we used in NEXTSTEP, although I've added some stuff from OpenBSD. And
+ * it uses the API to support Rhapsody's proprietry infosystem switch.
+ * lukeh
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pwd.h>
+#include <netinet/in.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yppasswd.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <errno.h>
+
+extern int getrpcport(char *, int, int, int);
+extern void checkpasswd(char *, char *);
+
+static struct passwd *ypgetpwnam(char *name, char *domain);
+
+int nis_check_passwd(char *uname, char *domain)
+{
+ int port;
+ char *master;
+ struct passwd *pwd;
+
+ if (domain == NULL)
+ {
+ if (yp_get_default_domain(&domain) != 0)
+ {
+ (void)fprintf(stderr, "can't get domain\n");
+ exit(1);
+ }
+ }
+
+ if (yp_master(domain, "passwd.byname", &master) != 0)
+ {
+ (void)fprintf(stderr, "can't get master for passwd file\n");
+ exit(1);
+ }
+
+ port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE,
+ IPPROTO_UDP);
+ if (port == 0)
+ {
+ (void)fprintf(stderr, "%s is not running yppasswd daemon\n",
+ master);
+ exit(1);
+ }
+ if (port >= IPPORT_RESERVED)
+ {
+ (void)fprintf(stderr,
+ "yppasswd daemon is not running on privileged port\n");
+ exit(1);
+ }
+
+ pwd = ypgetpwnam(uname, domain);
+ if (pwd == NULL)
+ {
+ (void)fprintf(stderr, "user %s not found\n", uname);
+ exit(1);
+ }
+
+ checkpasswd(uname, pwd->pw_passwd);
+ return(0);
+}
+
+static char *
+pwskip(register char *p)
+{
+ while (*p && *p != ':' && *p != '\n')
+ ++p;
+ if (*p)
+ *p++ = 0;
+ return (p);
+}
+
+struct passwd *
+interpret(struct passwd *pwent, char *line)
+{
+ register char *p = line;
+
+ pwent->pw_passwd = "*";
+ pwent->pw_uid = 0;
+ pwent->pw_gid = 0;
+ pwent->pw_gecos = "";
+ pwent->pw_dir = "";
+ pwent->pw_shell = "";
+#ifndef __SLICK__
+ pwent->pw_change = 0;
+ pwent->pw_expire = 0;
+ pwent->pw_class = "";
+#endif
+
+ /* line without colon separators is no good, so ignore it */
+ if(!strchr(p, ':'))
+ return(NULL);
+
+ pwent->pw_name = p;
+ p = pwskip(p);
+ pwent->pw_passwd = p;
+ p = pwskip(p);
+ pwent->pw_uid = (uid_t)strtoul(p, NULL, 10);
+ p = pwskip(p);
+ pwent->pw_gid = (gid_t)strtoul(p, NULL, 10);
+ p = pwskip(p);
+ pwent->pw_gecos = p;
+ p = pwskip(p);
+ pwent->pw_dir = p;
+ p = pwskip(p);
+ pwent->pw_shell = p;
+ while (*p && *p != '\n')
+ p++;
+ *p = '\0';
+ return (pwent);
+}
+
+
+static struct passwd *
+ypgetpwnam(char *nam, char *domain)
+{
+ static struct passwd pwent;
+ char *val;
+ int reason, vallen;
+ static char *__yplin = NULL;
+
+ reason = yp_match(domain, "passwd.byname", nam, strlen(nam),
+ &val, &vallen);
+ switch(reason) {
+ case 0:
+ break;
+ default:
+ return (NULL);
+ break;
+ }
+ val[vallen] = '\0';
+ if (__yplin)
+ free(__yplin);
+ __yplin = (char *)malloc(vallen + 1);
+ strcpy(__yplin, val);
+ free(val);
+
+ return(interpret(&pwent, __yplin));
+}
--- /dev/null
+/*
+ * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
+ * Portions Copyright (c) 1988 by Sun Microsystems, Inc.
+ * Portions Copyright (c) 1988 The Regents of the University of California.
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pwd.h>
+#include <netinet/in.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yppasswd.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <errno.h>
+
+#include <OpenDirectory/OpenDirectory.h>
+
+//-------------------------------------------------------------------------------------
+// od_check_passwd
+//-------------------------------------------------------------------------------------
+
+int od_check_passwd(const char *uname, const char *domain)
+{
+ int authenticated = 0;
+
+ ODSessionRef session = NULL;
+ ODNodeRef node = NULL;
+ ODRecordRef rec = NULL;
+ CFStringRef user = NULL;
+ CFStringRef location = NULL;
+ CFStringRef password = NULL;
+
+ if (uname) user = CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8);
+ if (domain) location = CFStringCreateWithCString(NULL, domain, kCFStringEncodingUTF8);
+
+ if (user) {
+ printf("Checking password for %s.\n", uname);
+ char* p = getpass("Password:");
+ if (p) password = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8);
+ }
+
+ if (password) {
+ session = ODSessionCreate(NULL, NULL, NULL);
+ if (session) {
+ if (location) {
+ node = ODNodeCreateWithName(NULL, session, location, NULL);
+ } else {
+ node = ODNodeCreateWithNodeType(NULL, session, kODNodeTypeAuthentication, NULL);
+ }
+ if (node) {
+ rec = ODNodeCopyRecord(node, kODRecordTypeUsers, user, NULL, NULL);
+ }
+ if (rec) {
+ authenticated = ODRecordVerifyPassword(rec, password, NULL);
+ }
+ }
+ }
+
+ if (!authenticated) {
+ fprintf(stderr, "Sorry\n");
+ exit(1);
+ }
+
+ return 0;
+}
+
+
+
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 1999-2008 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@
+ */
+#include <stdio.h>
+
+#include <security/pam_appl.h>
+#include <security/openpam.h> /* for openpam_ttyconv() */
+
+extern char* progname;
+static pam_handle_t *pamh;
+static struct pam_conv pamc;
+
+//-------------------------------------------------------------------------------------
+// pam_check_passwd
+//-------------------------------------------------------------------------------------
+
+int pam_check_passwd(char* uname)
+{
+ int retval = PAM_SUCCESS;
+
+ /* Initialize PAM. */
+ pamc.conv = &openpam_ttyconv;
+ pam_start(progname, uname, &pamc, &pamh);
+
+ printf("Checking password for %s.\n", uname);
+
+ /* Authenticate. */
+ if (PAM_SUCCESS != (retval = pam_authenticate(pamh, 0)))
+ goto pamerr;
+
+ /* Authorize. */
+ if (PAM_SUCCESS != (retval = pam_acct_mgmt(pamh, 0)) && PAM_NEW_AUTHTOK_REQD != retval)
+ goto pamerr;
+
+ /* Change the password. */
+ if (PAM_NEW_AUTHTOK_REQD == retval && PAM_SUCCESS != (retval = pam_chauthtok(pamh, 0)))
+ goto pamerr;
+
+ /* Set the credentials. */
+ if (PAM_SUCCESS != (retval = pam_setcred(pamh, PAM_ESTABLISH_CRED)))
+ goto pamerr;
+
+ /* Open the session. */
+ if (PAM_SUCCESS != (retval = pam_open_session(pamh, 0)))
+ goto pamerr;
+
+ /* Close the session. */
+ if (PAM_SUCCESS != (retval = pam_close_session(pamh, 0)))
+ goto pamerr;
+
+pamerr:
+ /* Print an error, if needed. */
+ if (PAM_SUCCESS != retval)
+ fprintf(stderr, "Sorry\n");
+
+ /* Terminate PAM. */
+ pam_end(pamh, retval);
+ return retval;
+}
--- /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@
+ */
+#define INFO_FILE 1
+#define INFO_NIS 2
+#define INFO_OPEN_DIRECTORY 3
+#define INFO_PAM 4
+
+#ifndef __SLICK__
+#define _PASSWD_FILE "/etc/master.passwd"
+#else
+#define _PASSWD_FILE "/etc/passwd"
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <pwd.h>
+#include <libc.h>
+#include <ctype.h>
+#include <string.h>
+#include <pwd.h>
+#include "stringops.h"
+
+#ifdef __SLICK__
+#define _PASSWORD_LEN 8
+#endif
+
+const char* progname = "chkpasswd";
+
+static int literal = 0;
+
+extern int file_check_passwd(char *, char *);
+extern int nis_check_passwd(char *, char *);
+extern int od_check_passwd(char *, char *);
+extern int pam_check_passwd(char *);
+
+void
+checkpasswd(char *name, char *old_pw)
+{
+ int isNull;
+ char *p;
+
+ printf("Checking password for %s.\n", name);
+
+ p = "";
+ isNull = 0;
+ if (old_pw == NULL) isNull = 1;
+ if ((isNull == 0) && (old_pw[0] == '\0')) isNull = 1;
+ if (isNull == 0)
+ {
+ p = getpass("Password:");
+ sleep(1); // make sure this doesn't go too quickly
+ if (strcmp(literal ? p : crypt(p, old_pw), old_pw))
+ {
+ errno = EACCES;
+ fprintf(stderr, "Sorry\n");
+ exit(1);
+ }
+ }
+ return;
+}
+
+void
+usage()
+{
+ fprintf(stderr, "usage: chkpasswd [-i infosystem] [-l location] [-c] [name]\n");
+ fprintf(stderr, " infosystem:\n");
+ fprintf(stderr, " file\n");
+ fprintf(stderr, " NIS\n");
+ fprintf(stderr, " OpenDirectory\n");
+ fprintf(stderr, " location (for infosystem):\n");
+ fprintf(stderr, " file location is path to file (default is %s)\n", _PASSWD_FILE);
+ fprintf(stderr, " NIS location is NIS domain name\n");
+ fprintf(stderr, " OpenDirectory location is directory node name\n");
+ fprintf(stderr, " -c: supplied password is compared verbatim without first\n");
+ fprintf(stderr, " being crypted\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ char* user = NULL;
+ char* locn = NULL;
+ int infosystem, ch;
+
+ infosystem = INFO_PAM;
+
+ while ((ch = getopt(argc, argv, "ci:l:")) != -1) {
+ switch(ch) {
+ case 'i':
+ if (!strcasecmp(optarg, "file")) {
+ infosystem = INFO_FILE;
+ } else if (!strcasecmp(optarg, "NIS")) {
+ infosystem = INFO_NIS;
+ } else if (!strcasecmp(optarg, "YP")) {
+ infosystem = INFO_NIS;
+ } else if (!strcasecmp(optarg, "opendirectory")) {
+ infosystem = INFO_OPEN_DIRECTORY;
+ } else if (!strcasecmp(optarg, "PAM")) {
+ infosystem = INFO_PAM;
+ } else {
+ fprintf(stderr, "%s: Unknown info system \'%s\'.\n",
+ progname, optarg);
+ usage();
+ }
+ break;
+ case 'l':
+ locn = optarg;
+ break;
+ case 'c':
+ literal++;
+ break;
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 1) {
+ usage();
+ } else if (argc == 1) {
+ user = argv[0];
+ }
+
+ if (user == NULL) {
+ struct passwd* pw = getpwuid(getuid());
+ if (pw != NULL && pw->pw_name != NULL) {
+ user = strdup(pw->pw_name);
+ }
+ if (user == NULL) {
+ fprintf(stderr, "you don't have a login name\n");
+ exit(1);
+ }
+ }
+
+ switch (infosystem)
+ {
+ case INFO_FILE:
+ file_check_passwd(user, locn);
+ break;
+ case INFO_NIS:
+ nis_check_passwd(user, locn);
+ break;
+ case INFO_OPEN_DIRECTORY:
+ od_check_passwd(user, locn);
+ break;
+ case INFO_PAM:
+ pam_check_passwd(user);
+ break;
+ }
+
+ exit(0);
+}
+
--- /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@
+ */
+#import <string.h>
+#import <stdlib.h>
+#import <stdio.h>
+#import <stdarg.h>
+#import "stringops.h"
+
+char *copyString(char *s)
+{
+ int len;
+ char *t;
+
+ if (s == NULL) return NULL;
+
+ len = strlen(s) + 1;
+ t = malloc(len);
+ bcopy(s, t, len);
+ return t;
+}
+
+char *concatString(char *s, char *t)
+{
+ int len;
+
+ if (t == NULL) return s;
+
+ len = strlen(s) + strlen(t) + 1;
+ s = realloc(s, len);
+ strcat(s, t);
+ return s;
+}
+
+char **insertString(char *s, char **l, unsigned int x)
+{
+ int i, len;
+
+ if (s == NULL) return l;
+ if (l == NULL)
+ {
+ l = (char **)malloc(2 * sizeof(char *));
+ l[0] = copyString(s);
+ l[1] = NULL;
+ return l;
+ }
+
+ for (i = 0; l[i] != NULL; i++);
+ len = i + 1; /* count the NULL on the end of the list too! */
+
+ l = (char **)realloc(l, (len + 1) * sizeof(char *));
+
+ if ((x >= (len - 1)) || (x == IndexNull))
+ {
+ l[len - 1] = copyString(s);
+ l[len] = NULL;
+ return l;
+ }
+
+ for (i = len; i > x; i--) l[i] = l[i - 1];
+ l[x] = copyString(s);
+ return l;
+}
+
+char **appendString(char *s, char **l)
+{
+ return insertString(s, l, IndexNull);
+}
+
+void freeList(char **l)
+{
+ int i;
+
+ if (l == NULL) return;
+ for (i = 0; l[i] != NULL; i++)
+ {
+ if (l[i] != NULL) free(l[i]);
+ l[i] = NULL;
+ }
+ if (l != NULL) free(l);
+}
+
+void freeString(char *s)
+{
+ if (s == NULL) return;
+ free(s);
+}
+
+unsigned int listLength(char **l)
+{
+ int i;
+
+ if (l == NULL) return 0;
+ for (i = 0; l[i] != NULL; i++);
+ return i;
+}
+
+unsigned int listIndex(char *s,char **l)
+{
+ int i;
+
+ if (l == NULL) return IndexNull;
+ for (i = 0; l[i] != NULL; i++)
+ {
+ if (strcmp(s, l[i]) == 0) return i;
+ }
+ return IndexNull;
+}
+
+char *prefix(char *s, char c)
+{
+ int i;
+ char *t;
+
+ if (s == NULL) return NULL;
+
+ for (i = 0; ((s[i] != '\0') && (s[i] != c)); i++);
+ if (i == 0) return NULL;
+ if (s[i] == '\0') return copyString(s);
+
+ t = malloc(i + 1);
+ bcopy(s, t, i);
+ t[i] = '\0';
+ return t;
+}
+
+char *postfix(char *s, char c)
+{
+ int i, len;
+ char *t;
+
+ if (s == NULL) return NULL;
+
+ for (i = 0; ((s[i] != '\0') && (s[i] != c)); i++);
+ if (s[i] == '\0') return NULL;
+ len = strlen(s) - i;
+ if (len == 1) return NULL;
+
+ t = malloc(len);
+ len--;
+ bcopy((s + i + 1), t, len);
+ t[len] = '\0';
+ return t;
+}
+
+char *presuffix(char *s, char c)
+{
+ int i, len;
+ char *t;
+
+ if (s == NULL) return NULL;
+
+ len = strlen(s);
+ for (i = len - 1; ((i >= 0) && (s[i] != c)); i--);
+ if (i == 0) return NULL;
+ if (s[0] == '\0') return NULL;
+
+ t = malloc(i + 1);
+ bcopy(s, t, i);
+ t[i] = '\0';
+ return t;
+}
+
+char *suffix(char *s, char c)
+{
+ int i, len;
+ char *t;
+
+ if (s == NULL) return NULL;
+
+ len = strlen(s);
+ for (i = len - 1; ((i >= 0) && (s[i] != c)); i--);
+ if (i == 0) return NULL;
+ len -= i;
+ if (len == 1) return NULL;
+ t = malloc(len);
+ len--;
+ bcopy((s + i + 1), t, len);
+ t[len] = '\0';
+ return t;
+}
+
+char *lowerCase(char *s)
+{
+ int i;
+ char *t;
+
+ if (s == NULL) return NULL;
+ t = malloc(strlen(s) + 1);
+
+ for (i = 0; s[i] != '\0'; i++)
+ {
+ if ((s[i] >= 'A') && (s[i] <= 'Z')) t[i] = s[i] + 32;
+ else t[i] = s[i];
+ }
+ t[i] = '\0';
+ return t;
+}
+
+char **explode(char *s, char c)
+{
+ char **l = NULL;
+ char *p, *t;
+ int i, n;
+
+ if (s == NULL) return NULL;
+
+ p = s;
+ while (p[0] != '\0')
+ {
+ for (i = 0; ((p[i] != '\0') && p[i] != c); i++);
+ n = i;
+ t = malloc(n + 1);
+ for (i = 0; i < n; i++) t[i] = p[i];
+ t[n] = '\0';
+ l = appendString(t, l);
+ free(t);
+ t = NULL;
+ if (p[i] == '\0') return l;
+ if (p[i + 1] == '\0') l = appendString("", l);
+ p = p + i + 1;
+ }
+ return l;
+}
--- /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@
+ */
+#define streq(A, B) (strcmp(A, B) == 0)
+#define IndexNull (unsigned int)-1
+char *copyString(char *);
+char *concatString(char *, char *);
+char **insertString(char *, char **, unsigned int);
+char **appendString(char *, char **);
+void freeList(char **);
+void freeString(char *);
+unsigned int listLength(char **);
+unsigned int listIndex(char *,char **);
+char *prefix(char *, char);
+char *postfix(char *, char);
+char *presuffix(char *, char);
+char *suffix(char *, char);
+char *lowerCase(char *);
+char **explode(char *, char);
--- /dev/null
+chpass.1 - FreeBSD file with references to yp items deleted
--- /dev/null
+.\" Copyright (c) 1988, 1990, 1993
+.\" The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)chpass.1 8.2 (Berkeley) 12/30/93
+.\" $FreeBSD: src/usr.bin/chpass/chpass.1,v 1.38.2.1 2005/09/24 01:59:39 keramida Exp $
+.\"
+.Dd December 30, 1993
+.Dt CHPASS 1
+.Os
+.Sh NAME
+.Nm chpass ,
+.Nm chfn ,
+.Nm chsh
+.\".Nm ypchpass ,
+.\".Nm ypchfn ,
+.\".Nm ypchsh
+.Nd add or change user database information
+.Sh SYNOPSIS
+.Nm
+.\".Op Fl a Ar list
+.\".Op Fl p Ar encpass
+.\".Op Fl e Ar expiretime
+.Op Fl l Ar location
+.Op Fl u Ar authname
+.Op Fl s Ar newshell
+.Op user
+.Sh DESCRIPTION
+The
+.Nm
+utility
+allows editing of the user database information associated
+with
+.Ar user
+or, by default, the current user.
+.Pp
+The
+.Nm
+utility
+.Em cannot
+change the user's password on Open Directory
+systems. Use the
+.Xr passwd 1
+utility instead.
+.Pp
+The
+.Nm chfn ,
+and
+.Nm chsh
+.\".Nm ypchpass ,
+.\".Nm ypchfn
+.\"and
+.\".Nm ypchsh
+utilities behave identically to
+.Nm .
+(There is only one program.)
+.Pp
+The information is formatted and supplied to an editor for changes.
+.Pp
+Only the information that the user is allowed to change is displayed.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.\".It Fl a
+.\"The super-user is allowed to directly supply a user database
+.\"entry, in the format specified by
+.\".Xr passwd 5 ,
+.\"as an argument.
+.\"This argument must be a colon
+.\".Pq Dq \&:
+.\"separated list of all the
+.\"user database fields, although they may be empty.
+.\".It Fl p
+.\"The super-user is allowed to directly supply an encrypted password field,
+.\"in the format used by
+.\".Xr crypt 3 ,
+.\"as an argument.
+.\".It Fl e Ar expiretime
+.\"Change the account expire time.
+.\"This option is used to set the expire time
+.\"from a script as if it were done in the interactive editor.
+.It Fl l Ar location
+If not specified,
+.Nm
+will perform a search for the user record on all available
+Open Directory nodes.
+When specified,
+.Nm
+will edit the user record on the directory node at the given
+.Ar location .
+.It Fl u Ar authname
+The user name to use when authenticating to the directory node containing the
+user.
+.It Fl s Ar newshell
+Attempt to change the user's shell to
+.Ar newshell .
+.El
+.Pp
+Possible display items are as follows:
+.Pp
+.Bl -tag -width "Other Information:" -compact -offset indent
+.It Login:
+user's login name
+.\".It Password:
+.\"user's encrypted password
+.It Uid:
+user's login
+.It Gid:
+user's login group
+.It Generated uid:
+user's UUID
+.\".It Class:
+.\"user's general classification
+.\".It Change:
+.\"password change time
+.\".It Expire:
+.\"account expiration time
+.It Full Name:
+user's real name
+.It Office Location:
+user's office location
+.It Office Phone:
+user's office phone
+.It Home Phone:
+user's home phone
+.\".It Other Information:
+.\"any locally defined parameters for user
+.It Home Directory:
+user's home directory
+.It Shell:
+user's login shell
+.Pp
+.\".It NOTE(1) -
+.\"In the actual master.passwd file, these fields are comma-delimited
+.\"fields embedded in the FullName field.
+.El
+.Pp
+The
+.Ar login
+field is the user name used to access the computer account.
+.\".Pp
+.\"The
+.\".Ar password
+.\"field contains the encrypted form of the user's password.
+.Pp
+The
+.Ar uid
+field is the number associated with the
+.Ar login
+field.
+Both of these fields should be unique across the system (and often
+across a group of systems) as they control file access.
+.Pp
+While it is possible to have multiple entries with identical login names
+and/or identical user id's, it is usually a mistake to do so.
+Routines
+that manipulate these files will often return only one of the multiple
+entries, and that one by random selection.
+.Pp
+The
+.Ar group
+field is the group that the user will be placed in at login.
+Since
+.Bx
+supports multiple groups (see
+.Xr groups 1 )
+this field currently has little special meaning.
+This field may be filled in with either a number or a group name (see
+.Xr group 5 ) .
+.Pp
+The
+.Ar generated uid
+field is the globally unique identifier (UUID) for the user.
+.\".Pp
+.\"The
+.\".Ar class
+.\"field references class descriptions in
+.\".Pa /etc/login.conf
+.\"and is typically used to initialize the user's system resource limits
+.\"when they login.
+.\".Pp
+.\"The
+.\".Ar change
+.\"field is the date by which the password must be changed.
+.\".Pp
+.\"The
+.\".Ar expire
+.\"field is the date on which the account expires.
+.\".Pp
+.\"Both the
+.\".Ar change
+.\"and
+.\".Ar expire
+.\"fields should be entered in the form
+.\".Dq month day year
+.\"where
+.\".Ar month
+.\"is the month name (the first three characters are sufficient),
+.\".Ar day
+.\"is the day of the month, and
+.\".Ar year
+.\"is the year.
+.\".Pp
+.\"Five fields are available for storing the user's
+.\".Ar full name , office location ,
+.\".Ar work
+.\"and
+.\".Ar home telephone
+.\"numbers and finally
+.\".Ar other information
+.\"which is a single comma delimited string to represent any additional
+.\"gcos fields (typically used for site specific user information).
+.\"Note that
+.\".Xr finger 1
+.\"will display the office location and office phone together under the
+.\"heading
+.\".Ar Office: .
+The
+.Ar full name
+field contains the full name of the user.
+.Pp
+The user's
+.Ar home directory
+is the full
+.Ux
+path name where the user
+will be placed at login.
+.Pp
+The
+.Ar shell
+field is the command interpreter the user prefers.
+If the
+.Ar shell
+field is empty, the Bourne shell,
+.Pa /bin/sh ,
+is assumed.
+When altering a login shell, and not the super-user, the user
+may not change from a non-standard shell or to a non-standard
+shell.
+Non-standard is defined as a shell not found in
+.Pa /etc/shells .
+.Pp
+The
+.Ar picture
+field is the path to a picture to be displayed for the user.
+.Sh OPEN DIRECTORY
+User database entries are under the control of
+.Xr DirectoryService 8
+and may be physically located in many different places,
+including the local Directory Service node,
+and remote LDAP servers.
+This version of
+.Nm
+uses Open Directory to change user database information.
+It does not interact with the historic flat file
+database
+.Pa /etc/master.passwd
+.
+.Sh ENVIRONMENT
+The
+.Xr vi 1
+editor will be used unless the environment variable
+.Ev EDITOR
+is set to
+an alternate editor.
+When the editor terminates, the information is re-read and used to
+update the user database itself.
+Only the user, or the super-user, may edit the information associated
+with the user.
+.Sh FILES
+.Bl -tag -width /etc/chpass.XXXXXX -compact
+.It Pa /etc/chpass.XXXXXX
+temporary copy of the data to edit
+.It Pa /etc/shells
+the list of approved shells
+.El
+.Sh SEE ALSO
+.\".Xr finger 1 ,
+.Xr login 1 ,
+.Xr passwd 1 ,
+.Xr getusershell 3 ,
+.Xr passwd 5
+.Rs
+.%A Robert Morris
+.%A Ken Thompson
+.%T "UNIX Password security"
+.Re
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.3 Reno .
--- /dev/null
+/*
+ * Copyright (c) 1999-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@
+ */
+/*-
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#if 0
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)chpass.c 8.4 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/chpass/chpass.c,v 1.27.8.1 2006/09/29 06:13:20 marck Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef YP
+#include <ypclnt.h>
+#endif
+
+#ifndef OPEN_DIRECTORY
+#include <pw_scan.h>
+#include <libutil.h>
+#endif
+
+#include "chpass.h"
+
+int master_mode;
+
+#ifdef OPEN_DIRECTORY
+#include "open_directory.h"
+char *progname = NULL;
+CFStringRef DSPath = NULL;
+#endif /* OPEN_DIRECTORY */
+
+static void baduser(void);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW, NEWEXP } op;
+#ifndef OPEN_DIRECTORY
+ struct passwd lpw, *old_pw, *pw;
+ int ch, pfd, tfd;
+ const char *password;
+#else
+ struct passwd *old_pw, *pw;
+ int ch, tfd;
+ char tfn[MAXPATHLEN];
+ char *tmpdir;
+#endif
+ char *arg = NULL;
+ uid_t uid;
+#ifdef YP
+ struct ypclnt *ypclnt;
+ const char *yp_domain = NULL, *yp_host = NULL;
+#endif
+#ifdef OPEN_DIRECTORY
+ CFStringRef username = NULL;
+ CFStringRef authname = NULL;
+ CFStringRef location = NULL;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) progname++;
+ else progname = argv[0];
+#endif /* OPEN_DIRECTORY */
+
+ pw = old_pw = NULL;
+ op = EDITENTRY;
+#ifdef OPEN_DIRECTORY
+ while ((ch = getopt(argc, argv, "a:s:l:u:")) != -1)
+#else /* OPEN_DIRECTORY */
+#ifdef YP
+ while ((ch = getopt(argc, argv, "a:p:s:e:d:h:loy")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "a:p:s:e:")) != -1)
+#endif
+#endif /* OPEN_DIRECTORY */
+ switch (ch) {
+ case 'a':
+ op = LOADENTRY;
+ arg = optarg;
+ break;
+ case 's':
+ op = NEWSH;
+ arg = optarg;
+ break;
+#ifndef OPEN_DIRECTORY
+ case 'p':
+ op = NEWPW;
+ arg = optarg;
+ break;
+ case 'e':
+ op = NEWEXP;
+ arg = optarg;
+ break;
+#ifdef YP
+ case 'd':
+ yp_domain = optarg;
+ break;
+ case 'h':
+ yp_host = optarg;
+ break;
+ case 'l':
+ case 'o':
+ case 'y':
+ /* compatibility */
+ break;
+#endif
+#else /* OPEN_DIRECTORY */
+ case 'l':
+ location = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
+ break;
+ case 'u':
+ authname = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
+ break;
+#endif
+ case '?':
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 1)
+ usage();
+
+ uid = getuid();
+
+ if (op == EDITENTRY || op == NEWSH || op == NEWPW || op == NEWEXP) {
+ if (argc == 0) {
+ if ((pw = getpwuid(uid)) == NULL)
+ errx(1, "unknown user: uid %lu",
+ (unsigned long)uid);
+ } else {
+ if ((pw = getpwnam(*argv)) == NULL)
+ errx(1, "unknown user: %s", *argv);
+#ifndef OPEN_DIRECTORY
+ if (uid != 0 && uid != pw->pw_uid)
+ baduser();
+#endif
+ }
+
+#ifndef OPEN_DIRECTORY
+ /* Make a copy for later verification */
+ if ((pw = pw_dup(pw)) == NULL ||
+ (old_pw = pw_dup(pw)) == NULL)
+ err(1, "pw_dup");
+#endif
+ }
+
+#if OPEN_DIRECTORY
+ master_mode = (uid == 0);
+
+ /*
+ * Find the user record and copy its details.
+ */
+ username = CFStringCreateWithCString(NULL, pw->pw_name, kCFStringEncodingUTF8);
+
+ if (strcmp(progname, "chsh") == 0 || op == NEWSH) {
+ cfprintf(stderr, "Changing shell for %@.\n", username);
+ } else if (strcmp(progname, "chfn") == 0) {
+ cfprintf(stderr, "Changing finger information for %@.\n", username);
+ } else if (strcmp(progname, "chpass") == 0) {
+ cfprintf(stderr, "Changing account information for %@.\n", username);
+ }
+
+ /*
+ * odGetUser updates DSPath global variable, performs authentication
+ * if necessary, and extracts the attributes.
+ */
+ CFDictionaryRef attrs_orig = NULL;
+ CFDictionaryRef attrs = NULL;
+ ODRecordRef rec = odGetUser(location, authname, username, &attrs_orig);
+
+ if (!rec || !attrs_orig) exit(1);
+#endif /* OPEN_DIRECTORY */
+
+#ifdef YP
+ if (pw != NULL && (pw->pw_fields & _PWF_SOURCE) == _PWF_NIS) {
+ ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host);
+ master_mode = (ypclnt != NULL &&
+ ypclnt_connect(ypclnt) != -1 &&
+ ypclnt_havepasswdd(ypclnt) == 1);
+ ypclnt_free(ypclnt);
+ } else
+#endif
+ master_mode = (uid == 0);
+
+ if (op == NEWSH) {
+ /* protect p_shell -- it thinks NULL is /bin/sh */
+ if (!arg[0])
+ usage();
+ if (p_shell(arg, pw, (ENTRY *)NULL) == -1)
+ exit(1);
+#ifdef OPEN_DIRECTORY
+ else {
+ ENTRY* ep;
+
+ setrestricted(attrs_orig);
+
+ for (ep = list; ep->prompt; ep++) {
+ if (strncasecmp(ep->prompt, "shell", ep->len) == 0) {
+ if (!ep->restricted) {
+ CFStringRef shell = CFStringCreateWithCString(NULL, arg, kCFStringEncodingUTF8);
+ if (shell) {
+ attrs = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (attrs) CFDictionarySetValue((CFMutableDictionaryRef)attrs, kODAttributeTypeUserShell, shell);
+ CFRelease(shell);
+ }
+ } else {
+ warnx("shell is restricted");
+ exit(1);
+ }
+ }
+ }
+ }
+#endif
+ }
+
+#ifndef OPEN_DIRECTORY
+ if (op == NEWEXP) {
+ if (uid) /* only root can change expire */
+ baduser();
+ if (p_expire(arg, pw, (ENTRY *)NULL) == -1)
+ exit(1);
+ }
+#endif
+
+ if (op == LOADENTRY) {
+ if (uid)
+ baduser();
+#ifdef OPEN_DIRECTORY
+ warnx("-a is not supported for Open Directory.");
+ exit(1);
+#else
+ pw = &lpw;
+ old_pw = NULL;
+ if (!__pw_scan(arg, pw, _PWSCAN_WARN|_PWSCAN_MASTER))
+ exit(1);
+#endif /* OPEN_DIRECTORY */
+ }
+
+#ifndef OPEN_DIRECTORY
+ if (op == NEWPW) {
+ if (uid)
+ baduser();
+
+ if (strchr(arg, ':'))
+ errx(1, "invalid format for password");
+ pw->pw_passwd = arg;
+ }
+#endif /* OPEN_DIRECTORY */
+
+ if (op == EDITENTRY) {
+#ifdef OPEN_DIRECTORY
+ setrestricted(attrs_orig);
+ tmpdir = getenv("TMPDIR");
+ if (!tmpdir)
+ tmpdir = P_tmpdir; // defined in the system headers, defaults to /tmp
+ snprintf(tfn, sizeof(tfn), "%s/%s.XXXXXX", tmpdir, progname);
+ if ((tfd = mkstemp(tfn)) == -1)
+ err(1, "%s", tfn);
+ attrs = (CFMutableDictionaryRef)edit(tfn, attrs_orig);
+ (void)unlink(tfn);
+#else
+ /*
+ * We don't really need pw_*() here, but pw_edit() (used
+ * by edit()) is just too useful...
+ */
+ if (pw_init(NULL, NULL))
+ err(1, "pw_init()");
+ if ((tfd = pw_tmp(-1)) == -1) {
+ pw_fini();
+ err(1, "pw_tmp()");
+ }
+ free(pw);
+ pw = edit(pw_tempname(), old_pw);
+ pw_fini();
+ if (pw == NULL)
+ err(1, "edit()");
+ /*
+ * pw_equal does not check for crypted passwords, so we
+ * should do it explicitly
+ */
+ if (pw_equal(old_pw, pw) &&
+ strcmp(old_pw->pw_passwd, pw->pw_passwd) == 0)
+ errx(0, "user information unchanged");
+#endif /* OPEN_DIRECTORY */
+ }
+
+#ifndef OPEN_DIRECTORY
+ if (old_pw && !master_mode) {
+ password = getpass("Password: ");
+ if (strcmp(crypt(password, old_pw->pw_passwd),
+ old_pw->pw_passwd) != 0)
+ baduser();
+ } else {
+ password = "";
+ }
+#endif
+
+#ifdef OPEN_DIRECTORY
+ odUpdateUser(rec, attrs_orig, attrs);
+
+ if (rec) CFRelease(rec);
+
+ exit(0);
+ return 0;
+#else /* OPEN_DIRECTORY */
+ exit(0);
+ if (old_pw != NULL)
+ pw->pw_fields |= (old_pw->pw_fields & _PWF_SOURCE);
+ switch (pw->pw_fields & _PWF_SOURCE) {
+#ifdef YP
+ case _PWF_NIS:
+ ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host);
+ if (ypclnt == NULL ||
+ ypclnt_connect(ypclnt) == -1 ||
+ ypclnt_passwd(ypclnt, pw, password) == -1) {
+ warnx("%s", ypclnt->error);
+ ypclnt_free(ypclnt);
+ exit(1);
+ }
+ ypclnt_free(ypclnt);
+ errx(0, "NIS user information updated");
+#endif /* YP */
+ case 0:
+ case _PWF_FILES:
+ if (pw_init(NULL, NULL))
+ err(1, "pw_init()");
+ if ((pfd = pw_lock()) == -1) {
+ pw_fini();
+ err(1, "pw_lock()");
+ }
+ if ((tfd = pw_tmp(-1)) == -1) {
+ pw_fini();
+ err(1, "pw_tmp()");
+ }
+ if (pw_copy(pfd, tfd, pw, old_pw) == -1) {
+ pw_fini();
+ err(1, "pw_copy");
+ }
+ if (pw_mkdb(pw->pw_name) == -1) {
+ pw_fini();
+ err(1, "pw_mkdb()");
+ }
+ pw_fini();
+ errx(0, "user information updated");
+ break;
+ default:
+ errx(1, "unsupported passwd source");
+ }
+#endif /* OPEN_DIRECTORY */
+}
+
+static void
+baduser(void)
+{
+
+ errx(1, "%s", strerror(EACCES));
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr,
+ "usage: chpass%s %s [user]\n",
+#ifdef OPEN_DIRECTORY
+ "",
+ "[-l location] [-u authname] [-s shell]");
+#else /* OPEN_DIRECTORY */
+#ifdef YP
+ " [-d domain] [-h host]",
+#else
+ "",
+#endif
+ "[-a list] [-p encpass] [-s shell] [-e mmm dd yy]");
+#endif /* OPEN_DIRECTORY */
+ exit(1);
+}
--- /dev/null
+/*
+ * Copyright (c) 1999-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@
+ */
+/*
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * @(#)chpass.h 8.4 (Berkeley) 4/2/94
+ * $FreeBSD: src/usr.bin/chpass/chpass.h,v 1.7 2004/01/18 21:46:39 charnier Exp $
+ */
+
+#ifdef OPEN_DIRECTORY
+#include "open_directory.h"
+
+extern char* progname;
+extern CFStringRef DSPath;
+#endif /* OPEN_DIRECTORY */
+
+struct passwd;
+
+typedef struct _entry {
+ const char *prompt;
+#ifdef OPEN_DIRECTORY
+ void (*display)();
+#endif
+ int (*func)(char *, struct passwd *, struct _entry *);
+ int restricted;
+ size_t len;
+#if OPEN_DIRECTORY
+ char *except;
+ const CFStringRef *attrName;
+#else /* OPEN_DIRECTORY */
+ char *except, *save;
+#endif /* OPEN_DIRECTORY */
+} ENTRY;
+
+/* Field numbers. */
+#define E_BPHONE 8
+#define E_HPHONE 9
+#define E_LOCATE 10
+#define E_NAME 7
+#define E_OTHER 11
+#define E_SHELL 13
+
+extern ENTRY list[];
+extern int master_mode;
+
+#ifdef OPEN_DIRECTORY
+/* edit.c */
+void display_time(CFDictionaryRef, CFStringRef, const char*, FILE *);
+void display_string(CFDictionaryRef, CFStringRef, const char*, FILE *);
+CFDictionaryRef edit(const char *tfn, CFDictionaryRef pw);
+
+/* util.c */
+int cfprintf(FILE* file, const char* format, ...);
+int editfile(const char* tfn);
+#endif /* OPEN_DIRECTORY */
+
+int atot(char *, time_t *);
+#ifndef OPEN_DIRECTORY
+struct passwd *edit(const char *, struct passwd *);
+#endif /* OPEN_DIRECTORY */
+int ok_shell(char *);
+char *dup_shell(char *);
+int p_change(char *, struct passwd *, ENTRY *);
+int p_class(char *, struct passwd *, ENTRY *);
+int p_expire(char *, struct passwd *, ENTRY *);
+int p_gecos(char *, struct passwd *, ENTRY *);
+int p_gid(char *, struct passwd *, ENTRY *);
+int p_hdir(char *, struct passwd *, ENTRY *);
+int p_login(char *, struct passwd *, ENTRY *);
+int p_passwd(char *, struct passwd *, ENTRY *);
+int p_shell(char *, struct passwd *, ENTRY *);
+int p_uid(char *, struct passwd *, ENTRY *);
+#ifdef OPEN_DIRECTORY
+int p_uuid(char *, struct passwd *, ENTRY *);
+#endif /* OPEN_DIRECTORY */
+char *ttoa(time_t);
--- /dev/null
+/*
+ * Copyright (c) 1999-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@
+ */
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#if 0
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)edit.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/chpass/edit.c,v 1.23 2003/04/09 18:18:42 des Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef OPEN_DIRECTORY
+#include <pw_scan.h>
+#include <libutil.h>
+#endif
+
+#include "chpass.h"
+
+#ifdef OPEN_DIRECTORY
+static int display(const char *tfn, CFDictionaryRef attrs);
+static CFDictionaryRef verify(const char *tfn, CFDictionaryRef attrs);
+#else
+static int display(const char *tfn, struct passwd *pw);
+static struct passwd *verify(const char *tfn, struct passwd *pw);
+#endif
+
+#ifdef OPEN_DIRECTORY
+CFDictionaryRef
+edit(const char *tfn, CFDictionaryRef pw)
+#else
+struct passwd *
+edit(const char *tfn, struct passwd *pw)
+#endif
+{
+#ifdef OPEN_DIRECTORY
+ CFDictionaryRef npw;
+#else
+ struct passwd *npw;
+#endif
+ char *line;
+ size_t len;
+
+ if (display(tfn, pw) == -1)
+ return (NULL);
+ for (;;) {
+#ifdef OPEN_DIRECTORY
+ switch (editfile(tfn)) {
+#else
+ switch (pw_edit(1)) {
+#endif
+ case -1:
+ return (NULL);
+ case 0:
+#ifdef OPEN_DIRECTORY
+ return (NULL);
+#else
+ return (pw_dup(pw));
+#endif
+ default:
+ break;
+ }
+ if ((npw = verify(tfn, pw)) != NULL)
+ return (npw);
+#ifndef OPEN_DIRECTORY
+ free(npw);
+#endif
+ printf("re-edit the password file? ");
+ fflush(stdout);
+ if ((line = fgetln(stdin, &len)) == NULL) {
+ warn("fgetln()");
+ return (NULL);
+ }
+ if (len > 0 && (*line == 'N' || *line == 'n'))
+ return (NULL);
+ }
+}
+
+/*
+ * display --
+ * print out the file for the user to edit; strange side-effect:
+ * set conditional flag if the user gets to edit the shell.
+ */
+#if OPEN_DIRECTORY
+static int
+display(const char *tfn, CFDictionaryRef attrs)
+#else
+static int
+display(const char *tfn, struct passwd *pw)
+#endif
+{
+ FILE *fp;
+#ifndef OPEN_DIRECTORY
+ char *bp, *gecos, *p;
+#endif
+
+ if ((fp = fopen(tfn, "w")) == NULL) {
+ warn("%s", tfn);
+ return (-1);
+ }
+
+#ifdef OPEN_DIRECTORY
+ CFArrayRef values = CFDictionaryGetValue(attrs, kODAttributeTypeRecordName);
+ CFStringRef username = (values && CFArrayGetCount(values)) > 0 ? CFArrayGetValueAtIndex(values, 0) : NULL;
+
+ (void)cfprintf(fp,
+ "# Changing user information for %@.\n"
+ "# Use \"passwd\" to change the password.\n"
+ "##\n"
+ "# Open Directory%s%@\n"
+ "##\n",
+ username,
+ DSPath ? ": " : "",
+ DSPath ? DSPath : CFSTR(""));
+
+ int ndisplayed = 0;
+ ENTRY* ep;
+ for (ep = list; ep->prompt; ep++)
+ if (!ep->restricted) {
+ ep->display(attrs, *ep->attrName, ep->prompt, fp);
+ ndisplayed++;
+ }
+ if(!ndisplayed) {
+ (void)fprintf(fp, "###################################\n");
+ (void)fprintf(fp, "# No fields are available to change\n");
+ (void)fprintf(fp, "###################################\n");
+ }
+#else OPEN_DIRECTORY
+ (void)fprintf(fp,
+ "#Changing user information for %s.\n", pw->pw_name);
+ if (master_mode) {
+ (void)fprintf(fp, "Login: %s\n", pw->pw_name);
+ (void)fprintf(fp, "Password: %s\n", pw->pw_passwd);
+ (void)fprintf(fp, "Uid [#]: %lu\n", (unsigned long)pw->pw_uid);
+ (void)fprintf(fp, "Gid [# or name]: %lu\n",
+ (unsigned long)pw->pw_gid);
+ (void)fprintf(fp, "Change [month day year]: %s\n",
+ ttoa(pw->pw_change));
+ (void)fprintf(fp, "Expire [month day year]: %s\n",
+ ttoa(pw->pw_expire));
+ (void)fprintf(fp, "Class: %s\n", pw->pw_class);
+ (void)fprintf(fp, "Home directory: %s\n", pw->pw_dir);
+ (void)fprintf(fp, "Shell: %s\n",
+ *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
+ }
+ /* Only admin can change "restricted" shells. */
+#if 0
+ else if (ok_shell(pw->pw_shell))
+ /*
+ * Make shell a restricted field. Ugly with a
+ * necklace, but there's not much else to do.
+ */
+#else
+ else if ((!list[E_SHELL].restricted && ok_shell(pw->pw_shell)) ||
+ master_mode)
+ /*
+ * If change not restrict (table.c) and standard shell
+ * OR if root, then allow editing of shell.
+ */
+#endif
+ (void)fprintf(fp, "Shell: %s\n",
+ *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
+ else
+ list[E_SHELL].restricted = 1;
+
+ if ((bp = gecos = strdup(pw->pw_gecos)) == NULL) {
+ warn(NULL);
+ fclose(fp);
+ return (-1);
+ }
+
+ p = strsep(&bp, ",");
+ p = strdup(p ? p : "");
+ list[E_NAME].save = p;
+ if (!list[E_NAME].restricted || master_mode)
+ (void)fprintf(fp, "Full Name: %s\n", p);
+
+ p = strsep(&bp, ",");
+ p = strdup(p ? p : "");
+ list[E_LOCATE].save = p;
+ if (!list[E_LOCATE].restricted || master_mode)
+ (void)fprintf(fp, "Office Location: %s\n", p);
+
+ p = strsep(&bp, ",");
+ p = strdup(p ? p : "");
+ list[E_BPHONE].save = p;
+ if (!list[E_BPHONE].restricted || master_mode)
+ (void)fprintf(fp, "Office Phone: %s\n", p);
+
+ p = strsep(&bp, ",");
+ p = strdup(p ? p : "");
+ list[E_HPHONE].save = p;
+ if (!list[E_HPHONE].restricted || master_mode)
+ (void)fprintf(fp, "Home Phone: %s\n", p);
+
+ bp = strdup(bp ? bp : "");
+ list[E_OTHER].save = bp;
+ if (!list[E_OTHER].restricted || master_mode)
+ (void)fprintf(fp, "Other information: %s\n", bp);
+
+ free(gecos);
+#endif /* OPEN_DIRECTORY */
+
+ (void)fchown(fileno(fp), getuid(), getgid());
+ (void)fclose(fp);
+ return (0);
+}
+
+#ifdef OPEN_DIRECTORY
+static CFDictionaryRef
+verify(const char* tfn, CFDictionaryRef pw)
+#else
+static struct passwd *
+verify(const char *tfn, struct passwd *pw)
+#endif
+{
+#ifdef OPEN_DIRECTORY
+ CFMutableDictionaryRef npw;
+#else
+ struct passwd *npw;
+#endif
+ ENTRY *ep;
+ char *buf, *p, *val;
+ struct stat sb;
+ FILE *fp;
+ int line;
+ size_t len;
+
+#ifdef OPEN_DIRECTORY
+ if ((npw = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == NULL)
+ return (NULL);
+#else
+ if ((pw = pw_dup(pw)) == NULL)
+ return (NULL);
+#endif
+ if ((fp = fopen(tfn, "r")) == NULL ||
+ fstat(fileno(fp), &sb) == -1) {
+ warn("%s", tfn);
+#ifndef OPEN_DIRECTORY
+ free(pw);
+#endif
+ return (NULL);
+ }
+ if (sb.st_size == 0) {
+ warnx("corrupted temporary file");
+ fclose(fp);
+#ifndef OPEN_DIRECTORY
+ free(pw);
+#endif
+ return (NULL);
+ }
+ val = NULL;
+ for (line = 1; (buf = fgetln(fp, &len)) != NULL; ++line) {
+ if (*buf == '\0' || *buf == '#')
+ continue;
+ while (len > 0 && isspace(buf[len - 1]))
+ --len;
+ for (ep = list;; ++ep) {
+ if (!ep->prompt) {
+ warnx("%s: unrecognized field on line %d",
+ tfn, line);
+ goto bad;
+ }
+ if (ep->len > len)
+ continue;
+ if (strncasecmp(buf, ep->prompt, ep->len) != 0)
+ continue;
+ if (ep->restricted && !master_mode) {
+ warnx("%s: you may not change the %s field",
+ tfn, ep->prompt);
+ goto bad;
+ }
+ for (p = buf; p < buf + len && *p != ':'; ++p)
+ /* nothing */ ;
+ if (*p != ':') {
+ warnx("%s: line %d corrupted", tfn, line);
+ goto bad;
+ }
+ while (++p < buf + len && isspace(*p))
+ /* nothing */ ;
+ free(val);
+ asprintf(&val, "%.*s", (int)(buf + len - p), p);
+ if (val == NULL)
+ goto bad;
+ if (ep->except && strpbrk(val, ep->except)) {
+ warnx("%s: invalid character in \"%s\" field '%s'",
+ tfn, ep->prompt, val);
+ goto bad;
+ }
+#ifdef OPEN_DIRECTORY
+ if ((ep->func)(val, NULL, NULL))
+ goto bad;
+ {
+ CFStringRef str = CFStringCreateWithCString(NULL, val, kCFStringEncodingUTF8);
+ if (str) {
+ CFDictionarySetValue(npw, *ep->attrName, str);
+ CFRelease(str);
+ }
+ }
+#else
+ if ((ep->func)(val, pw, ep))
+ goto bad;
+#endif
+ break;
+ }
+ }
+ free(val);
+ fclose(fp);
+
+#ifndef OPEN_DIRECTORY
+ /* Build the gecos field. */
+ len = asprintf(&p, "%s,%s,%s,%s,%s", list[E_NAME].save,
+ list[E_LOCATE].save, list[E_BPHONE].save,
+ list[E_HPHONE].save, list[E_OTHER].save);
+ if (p == NULL) {
+ warn("asprintf()");
+ free(pw);
+ return (NULL);
+ }
+ while (len > 0 && p[len - 1] == ',')
+ p[--len] = '\0';
+ pw->pw_gecos = p;
+ buf = pw_make(pw);
+ free(pw);
+ free(p);
+ if (buf == NULL) {
+ warn("pw_make()");
+ return (NULL);
+ }
+ npw = pw_scan(buf, PWSCAN_WARN|PWSCAN_MASTER);
+#endif /* !OPEN_DIRECTORY */
+ free(buf);
+ return (npw);
+bad:
+#ifndef OPEN_DIRECTORY
+ free(pw);
+#endif
+ free(val);
+ fclose(fp);
+ return (NULL);
+}
--- /dev/null
+/*
+ * Copyright (c) 1999-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@
+ */
+/*
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#if 0
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)field.c 8.4 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/chpass/field.c,v 1.9 2004/01/18 21:46:39 charnier Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "chpass.h"
+
+/* ARGSUSED */
+int
+p_login(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ if (!*p) {
+ warnx("empty login field");
+ return (-1);
+ }
+ if (*p == '-') {
+ warnx("login names may not begin with a hyphen");
+ return (-1);
+ }
+#ifndef OPEN_DIRECTORY
+ if (!(pw->pw_name = strdup(p))) {
+ warnx("can't save entry");
+ return (-1);
+ }
+#endif
+ if (strchr(p, '.'))
+ warnx("\'.\' is dangerous in a login name");
+ for (; *p; ++p)
+ if (isupper(*p)) {
+ warnx("upper-case letters are dangerous in a login name");
+ break;
+ }
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_passwd(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+#ifndef OPEN_DIRECTORY
+ if (!(pw->pw_passwd = strdup(p))) {
+ warnx("can't save password entry");
+ return (-1);
+ }
+#endif
+
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_uid(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ uid_t id;
+ char *np;
+
+ if (!*p) {
+ warnx("empty uid field");
+ return (-1);
+ }
+ if (!isdigit(*p)) {
+ warnx("illegal uid");
+ return (-1);
+ }
+ errno = 0;
+ id = strtoul(p, &np, 10);
+ if (*np || (id == (uid_t)ULONG_MAX && errno == ERANGE)) {
+ warnx("illegal uid");
+ return (-1);
+ }
+#ifndef OPEN_DIRECTORY
+ pw->pw_uid = id;
+#endif
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_gid(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ struct group *gr;
+ gid_t id;
+ char *np;
+
+ if (!*p) {
+ warnx("empty gid field");
+ return (-1);
+ }
+ if (!isdigit(*p)) {
+ if (!(gr = getgrnam(p))) {
+ warnx("unknown group %s", p);
+ return (-1);
+ }
+#ifndef OPEN_DIRECTORY
+ pw->pw_gid = gr->gr_gid;
+#endif
+ return (0);
+ }
+ errno = 0;
+ id = strtoul(p, &np, 10);
+ if (*np || (id == (uid_t)ULONG_MAX && errno == ERANGE)) {
+ warnx("illegal gid");
+ return (-1);
+ }
+#ifndef OPEN_DIRECTORY
+ pw->pw_gid = id;
+#endif
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_class(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+#ifndef OPEN_DIRECTORY
+ if (!(pw->pw_class = strdup(p))) {
+ warnx("can't save entry");
+ return (-1);
+ }
+#endif
+
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_change(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+#ifndef OPEN_DIRECTORY
+ if (!atot(p, &pw->pw_change))
+ return (0);
+ warnx("illegal date for change field");
+#endif
+ return (-1);
+}
+
+/* ARGSUSED */
+int
+p_expire(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+#ifndef OPEN_DIRECTORY
+ if (!atot(p, &pw->pw_expire))
+ return (0);
+ warnx("illegal date for expire field");
+#endif
+ return (-1);
+}
+
+/* ARGSUSED */
+int
+p_gecos(char *p, struct passwd *pw __unused, ENTRY *ep)
+{
+#ifndef OPEN_DIRECTORY
+ if (!(ep->save = strdup(p))) {
+ warnx("can't save entry");
+ return (-1);
+ }
+#endif
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_hdir(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ if (!*p) {
+ warnx("empty home directory field");
+ return (-1);
+ }
+#ifndef OPEN_DIRECTORY
+ if (!(pw->pw_dir = strdup(p))) {
+ warnx("can't save entry");
+ return (-1);
+ }
+#endif
+ return (0);
+}
+
+
+/* ARGSUSED */
+int
+p_shell(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ struct stat sbuf;
+#ifdef OPEN_DIRECTORY
+ struct passwd lpw;
+ pw = &lpw;
+ memset(pw, 0, sizeof(lpw));
+ pw->pw_shell = p;
+#endif
+
+#ifndef OPEN_DIRECTORY
+ if (!*p) {
+ pw->pw_shell = strdup(_PATH_BSHELL);
+ return (0);
+ }
+ /* only admin can change from or to "restricted" shells */
+ if (!master_mode && pw->pw_shell && !ok_shell(pw->pw_shell)) {
+ warnx("%s: current shell non-standard", pw->pw_shell);
+ return (-1);
+ }
+#endif /* !OPEN_DIRECTORY */
+ if (!ok_shell(p)) {
+ if (!master_mode) {
+ warnx("%s: non-standard shell", p);
+ return (-1);
+ }
+#ifndef OPEN_DIRECTORY
+ pw->pw_shell = strdup(p);
+#endif
+ }
+#ifndef OPEN_DIRECTORY
+ else
+ pw->pw_shell = dup_shell(p);
+ if (!pw->pw_shell) {
+ warnx("can't save entry");
+ return (-1);
+ }
+#endif
+ if (stat(pw->pw_shell, &sbuf) < 0) {
+ if (errno == ENOENT)
+ warnx("WARNING: shell '%s' does not exist",
+ pw->pw_shell);
+ else
+ warn("WARNING: can't stat shell '%s'", pw->pw_shell);
+ return (0);
+ }
+ if (!S_ISREG(sbuf.st_mode)) {
+ warnx("WARNING: shell '%s' is not a regular file",
+ pw->pw_shell);
+ return (0);
+ }
+ if ((sbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) == 0) {
+ warnx("WARNING: shell '%s' is not executable", pw->pw_shell);
+ return (0);
+ }
+ return (0);
+}
+
+
+#ifdef OPEN_DIRECTORY
+#include <uuid/uuid.h>
+/* ARGSUSED */
+int
+p_uuid(char *p, struct passwd *pw __unused, ENTRY *ep)
+{
+ uuid_t uu;
+ if (uuid_parse(p, uu) != 0) {
+ warnx("invalid UUID");
+ return (-1);
+ }
+ return (0);
+}
+
+void
+display_string(CFDictionaryRef attrs, CFStringRef attrName, const char* prompt, FILE *fp)
+{
+ CFTypeRef value = CFSTR("");
+ CFArrayRef values = CFDictionaryGetValue(attrs, attrName);
+ if (values) {
+ value = CFArrayGetCount(values) > 0 ? CFArrayGetValueAtIndex(values, 0) : NULL;
+ if (value && CFGetTypeID(value) != CFStringGetTypeID()) value = NULL;
+ }
+ cfprintf(fp, "%s: %@\n", prompt, value);
+}
+#endif /* OPEN_DIRECTORY */
--- /dev/null
+#ifdef OPEN_DIRECTORY
+#include "open_directory.h"
+#include "chpass.h"
+#include <err.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <sys/sysctl.h>
+#include <OpenDirectory/OpenDirectory.h>
+#include <OpenDirectory/OpenDirectoryPriv.h>
+
+/*---------------------------------------------------------------------------
+ * PUBLIC setrestricted - sets the restricted flag
+ *---------------------------------------------------------------------------*/
+void
+setrestricted(CFDictionaryRef attrs)
+{
+ const char* user_allowed[] = { "shell", "full name", "office location", "office phone", "home phone", "picture", NULL };
+ const char* root_restricted[] = { "password", "change", "expire", "class", NULL };
+ ENTRY* ep;
+ const char** pp;
+ int restrict_by_default = !master_mode;
+
+ // for ordinary users, everything is restricted except for the values
+ // expressly permitted above
+ // for root, everything is permitted except for the values expressly
+ // restricted above
+
+ for (ep = list; ep->prompt; ep++) {
+ ep->restricted = restrict_by_default;
+ pp = restrict_by_default ? user_allowed : root_restricted;
+ for (; *pp; pp++) {
+ if (strncasecmp(ep->prompt, *pp, ep->len) == 0) {
+ ep->restricted = !restrict_by_default;
+ break;
+ }
+ }
+
+ // If not root, then it is only permitted to change the shell
+ // when the original value is one of the approved shells.
+ // Otherwise, the assumption is that root has given this user
+ // a restricted shell which they must not change away from.
+ if (restrict_by_default && strcmp(ep->prompt, "shell") == 0) {
+ ep->restricted = 1;
+ CFArrayRef values = CFDictionaryGetValue(attrs, kODAttributeTypeUserShell);
+ CFTypeRef value = values && CFArrayGetCount(values) > 0 ? CFArrayGetValueAtIndex(values, 0) : NULL;
+ if (value && CFGetTypeID(value) == CFStringGetTypeID()) {
+ size_t size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value), kCFStringEncodingUTF8)+1;
+ char* shell = malloc(size);
+ if (CFStringGetCString(value, shell, size, kCFStringEncodingUTF8)) {
+ if (ok_shell(shell)) {
+ ep->restricted = 0;
+ }
+ }
+ }
+ }
+ }
+}
+
+static CFStringRef
+prompt_passwd(CFStringRef user)
+{
+ CFStringRef result = NULL;
+ CFStringRef prompt = CFStringCreateWithFormat(NULL, NULL, CFSTR("Password for %@: "), user);
+ size_t prompt_size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(prompt), kCFStringEncodingUTF8);
+ char* buf = malloc(prompt_size);
+ CFStringGetCString(prompt, buf, prompt_size, kCFStringEncodingUTF8);
+ char* pass = getpass(buf);
+ result = CFStringCreateWithCString(NULL, pass, kCFStringEncodingUTF8);
+ memset(pass, 0, strlen(pass));
+ free(buf);
+ CFRelease(prompt);
+ return result;
+}
+
+static void
+show_error(CFErrorRef error) {
+ if (error) {
+ CFStringRef desc = CFErrorCopyDescription(error);
+ if (desc) {
+ cfprintf(stderr, "%s: %@", progname, desc);
+ CFRelease(desc);
+ }
+ desc = CFErrorCopyFailureReason(error);
+ if (desc) cfprintf(stderr, " %@", desc);
+
+ desc = CFErrorCopyRecoverySuggestion(error);
+ if (desc) cfprintf(stderr, " %@", desc);
+
+ fprintf(stderr, "\n");
+ }
+}
+
+ODRecordRef
+odGetUser(CFStringRef location, CFStringRef authname, CFStringRef user, CFDictionaryRef* attrs)
+{
+ ODNodeRef node = NULL;
+ ODRecordRef rec = NULL;
+ CFErrorRef error = NULL;
+
+ assert(attrs);
+
+ /*
+ * Open the specified node, or perform a search.
+ * Copy the record and put the record's location into DSPath.
+ */
+ if (location) {
+ node = ODNodeCreateWithName(NULL, kODSessionDefault, location, &error);
+ } else {
+ node = ODNodeCreateWithNodeType(NULL, kODSessionDefault, kODNodeTypeAuthentication, &error);
+ }
+ if (node) {
+ CFTypeRef vals[] = { kODAttributeTypeStandardOnly };
+ CFArrayRef desiredAttrs = CFArrayCreate(NULL, vals, 1, &kCFTypeArrayCallBacks);
+ rec = ODNodeCopyRecord(node, kODRecordTypeUsers, user, desiredAttrs, &error);
+ if (desiredAttrs) CFRelease(desiredAttrs);
+ CFRelease(node);
+ }
+ if (rec) {
+ *attrs = ODRecordCopyDetails(rec, NULL, &error);
+ if (*attrs) {
+ CFArrayRef values = CFDictionaryGetValue(*attrs, kODAttributeTypeMetaNodeLocation);
+ DSPath = (values && CFArrayGetCount(values) > 0) ? CFArrayGetValueAtIndex(values, 0) : NULL;
+ }
+
+ /*
+ * Prompt for a password if -u was specified,
+ * or if we are not root,
+ * or if we are updating something not on the
+ * local node.
+ */
+ if (authname || !master_mode ||
+ (DSPath && CFStringCompareWithOptions(DSPath, CFSTR("/Local/"), CFRangeMake(0, 7), 0) != kCFCompareEqualTo)) {
+
+ CFStringRef password = NULL;
+
+ if (!authname) authname = user;
+
+ password = prompt_passwd(authname);
+ if (!ODRecordSetNodeCredentials(rec, authname, password, &error)) {
+ CFRelease(rec);
+ rec = NULL;
+ }
+ }
+ }
+
+ if (error) show_error(error);
+ return rec;
+}
+
+void
+odUpdateUser(ODRecordRef rec, CFDictionaryRef attrs_orig, CFDictionaryRef attrs)
+{
+ CFErrorRef error = NULL;
+ int updated = 0;
+ ENTRY* ep;
+
+ for (ep = list; ep->prompt; ep++) {
+
+ // Nothing to update
+ if (!rec || !attrs_orig || !attrs) break;
+
+ // No need to update if entry is restricted
+ if (ep->restricted) continue;
+
+ CFArrayRef values_orig = CFDictionaryGetValue(attrs_orig, *ep->attrName);
+ CFTypeRef value_orig = values_orig && CFArrayGetCount(values_orig) ? CFArrayGetValueAtIndex(values_orig, 0) : NULL;
+ CFTypeRef value = CFDictionaryGetValue(attrs, *ep->attrName);
+
+ // No need to update if both values are the same
+ if (value == value_orig) continue;
+
+ // No need to update if strings are equal
+ if (value && value_orig) {
+ if (CFGetTypeID(value_orig) == CFStringGetTypeID() &&
+ CFStringCompare(value_orig, value, 0) == kCFCompareEqualTo) continue;
+ }
+
+ // No need to update if empty string replaces NULL
+ if (!value_orig && value) {
+ if (CFStringGetLength(value) == 0) continue;
+ }
+
+ // Needs update
+ if (value) {
+ // if new value is an empty string, send an empty dictionary which will delete the property.
+ CFIndex count = CFEqual(value, CFSTR("")) ? 0 : 1;
+ CFTypeRef vals[] = { value };
+ CFArrayRef values = CFArrayCreate(NULL, vals, count, &kCFTypeArrayCallBacks);
+ if (values && ODRecordSetValue(rec, *ep->attrName, values, &error)) {
+ updated = 1;
+ }
+ if (values) CFRelease(values);
+ if (error) show_error(error);
+ }
+ }
+
+ if (updated) {
+ updated = ODRecordSynchronize(rec, &error);
+ if (error) show_error(error);
+ }
+ if (!updated) {
+ fprintf(stderr, "%s: no changes made\n", progname);
+ }
+}
+#endif /* OPEN_DIRECTORY */
--- /dev/null
+#ifndef _OPEN_DIRECTORY_H_
+#define _OPEN_DIRECTORY_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <OpenDirectory/OpenDirectory.h>
+
+extern void setrestricted(CFDictionaryRef attrs);
+
+ODRecordRef odGetUser(CFStringRef location, CFStringRef authname, CFStringRef user, CFDictionaryRef* attrs);
+
+void odUpdateUser(ODRecordRef rec, CFDictionaryRef attrs_orig, CFDictionaryRef attrs);
+
+#endif /* _OPEN_DIRECTORY_H_ */
--- /dev/null
+/*
+ * Copyright (c) 1999 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@
+ */
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+/*
+ * This module is used to copy the master password file, replacing a single
+ * record, by chpass(1) and passwd(1).
+ */
+
+#include <err.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <pw_util.h>
+#include "pw_copy.h"
+
+extern char *tempname;
+
+void
+pw_copy(ffd, tfd, pw)
+ int ffd, tfd;
+ struct passwd *pw;
+{
+ FILE *from, *to;
+ int done;
+ char *p, buf[8192];
+
+ if (!(from = fdopen(ffd, "r")))
+ pw_error(_PATH_MASTERPASSWD, 1, 1);
+ if (!(to = fdopen(tfd, "w")))
+ pw_error(tempname, 1, 1);
+
+ for (done = 0; fgets(buf, sizeof(buf), from);) {
+ if (!strchr(buf, '\n')) {
+ warnx("%s: line too long", _PATH_MASTERPASSWD);
+ pw_error(NULL, 0, 1);
+ }
+#if defined(__APPLE__)
+ if (done || (buf[0] == '#')) {
+#else
+ if (done) {
+#endif
+ (void)fprintf(to, "%s", buf);
+ if (ferror(to))
+ goto err;
+ continue;
+ }
+ if (!(p = strchr(buf, ':'))) {
+ warnx("%s: corrupted entry", _PATH_MASTERPASSWD);
+ pw_error(NULL, 0, 1);
+ }
+ *p = '\0';
+ if (strcmp(buf, pw->pw_name)) {
+ *p = ':';
+ (void)fprintf(to, "%s", buf);
+ if (ferror(to))
+ goto err;
+ continue;
+ }
+ (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
+ pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
+ pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos,
+ pw->pw_dir, pw->pw_shell);
+ done = 1;
+ if (ferror(to))
+ goto err;
+ }
+ if (!done)
+ (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
+ pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
+ pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos,
+ pw->pw_dir, pw->pw_shell);
+
+ if (ferror(to))
+err: pw_error(NULL, 1, 1);
+ (void)fclose(to);
+}
--- /dev/null
+/*
+ * Copyright (c) 1999 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@
+ */
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+void pw_copy __P((int, int, struct passwd *));
--- /dev/null
+/*
+ * Copyright (c) 1999-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@
+ */
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#if 0
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)table.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/chpass/table.c,v 1.10 2003/05/03 19:44:45 obrien Exp $");
+#endif
+
+#include <sys/types.h>
+#include <stddef.h>
+#include "chpass.h"
+
+char e1[] = ": ";
+char e2[] = ":,";
+
+#ifdef OPEN_DIRECTORY
+#include "open_directory.h"
+
+ENTRY list[] = {
+ { "Login", display_string, p_login, 1, 5, e1, &kODAttributeTypeRecordName, },
+ { "Password", display_string, p_passwd, 1, 8, e1, &kODAttributeTypePassword, },
+ { "Uid [#]", display_string, p_uid, 1, 3, e1, &kODAttributeTypeUniqueID, },
+ { "Gid [# or name]", display_string, p_gid, 1, 3, e1, &kODAttributeTypePrimaryGroupID, },
+ { "Generated uid", display_string, p_uuid, 1, 13, NULL, &kODAttributeTypeGUID, },
+#if 0
+ { "Change [month day year]", display_time, p_change, 1, 6, NULL, CFSTR(kDS1AttrChange), },
+ { "Expire [month day year]", display_time, p_expire, 1, 6, NULL, kODAttributeTypeExpire, },
+ { "Class", display_string, p_class, 0, 5, e1, CFSTR(""), "Class" },
+#endif
+ { "Home directory", display_string, p_hdir, 1, 14, e1, &kODAttributeTypeNFSHomeDirectory, },
+ { "Shell", display_string, p_shell, 1, 5, e1, &kODAttributeTypeUserShell, },
+ { "Full Name", display_string, p_gecos, 1, 9, e2, &kODAttributeTypeFullName, },
+ { "Office Location", display_string, p_gecos, 1, 8, e2, &kODAttributeTypeBuilding, },
+ { "Office Phone", display_string, p_gecos, 1, 12, e2, &kODAttributeTypePhoneNumber, },
+ { "Home Phone", display_string, p_gecos, 1, 10, e2, &kODAttributeTypeHomePhoneNumber, },
+ { NULL, NULL, NULL, 0, 0, NULL, NULL,},
+};
+#else /* OPEN_DIRECTORY */
+ENTRY list[] = {
+ { "login", p_login, 1, 5, e1, NULL },
+ { "password", p_passwd, 1, 8, e1, NULL },
+ { "uid", p_uid, 1, 3, e1, NULL },
+ { "gid", p_gid, 1, 3, e1, NULL },
+ { "class", p_class, 1, 5, e1, NULL },
+ { "change", p_change, 1, 6, NULL, NULL },
+ { "expire", p_expire, 1, 6, NULL, NULL },
+#ifdef RESTRICT_FULLNAME_CHANGE /* do not allow fullname changes */
+ { "full name", p_gecos, 1, 9, e2, NULL },
+#else
+ { "full name", p_gecos, 0, 9, e2, NULL },
+#endif
+ { "office phone", p_gecos, 0, 12, e2, NULL },
+ { "home phone", p_gecos, 0, 10, e2, NULL },
+ { "office location", p_gecos, 0, 15, e2, NULL },
+ { "other information", p_gecos, 0, 11, e1, NULL },
+ { "home directory", p_hdir, 1, 14, e1, NULL },
+ { "shell", p_shell, 0, 5, e1, NULL },
+ { NULL, NULL, 0, 0, NULL, NULL },
+};
+#endif /* OPEN_DIRECTORY */
--- /dev/null
+/*
+ * Copyright (c) 1999-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@
+ */
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#if 0
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)util.c 8.4 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/chpass/util.c,v 1.13 2004/01/18 21:46:39 charnier Exp $");
+#endif
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+
+#include "chpass.h"
+
+#if OPEN_DIRECTORY
+#include <err.h>
+#include <paths.h>
+#include <sys/stat.h>
+#include "open_directory.h"
+
+char* tempname;
+#endif /* OPEN_DIRECTORY */
+
+static const char *months[] =
+ { "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November",
+ "December", NULL };
+
+char *
+ttoa(time_t tval)
+{
+ struct tm *tp;
+ static char tbuf[50];
+
+ if (tval) {
+ tp = localtime(&tval);
+ (void)sprintf(tbuf, "%s %d, %d", months[tp->tm_mon],
+ tp->tm_mday, tp->tm_year + TM_YEAR_BASE);
+ }
+ else
+ *tbuf = '\0';
+ return (tbuf);
+}
+
+int
+atot(char *p, time_t *store)
+{
+ static struct tm *lt;
+ char *t;
+ const char **mp;
+ time_t tval;
+ int day, month, year;
+
+ if (!*p) {
+ *store = 0;
+ return (0);
+ }
+ if (!lt) {
+ unsetenv("TZ");
+ (void)time(&tval);
+ lt = localtime(&tval);
+ }
+ if (!(t = strtok(p, " \t")))
+ goto bad;
+ if (isdigit(*t)) {
+ month = atoi(t);
+ } else {
+ for (mp = months;; ++mp) {
+ if (!*mp)
+ goto bad;
+ if (!strncasecmp(*mp, t, 3)) {
+ month = mp - months + 1;
+ break;
+ }
+ }
+ }
+ if (!(t = strtok((char *)NULL, " \t,")) || !isdigit(*t))
+ goto bad;
+ day = atoi(t);
+ if (!(t = strtok((char *)NULL, " \t,")) || !isdigit(*t))
+ goto bad;
+ year = atoi(t);
+ if (day < 1 || day > 31 || month < 1 || month > 12)
+ goto bad;
+ /* Allow two digit years 1969-2068 */
+ if (year < 69)
+ year += 2000;
+ else if (year < 100)
+ year += TM_YEAR_BASE;
+ if (year < EPOCH_YEAR)
+bad: return (1);
+ lt->tm_year = year - TM_YEAR_BASE;
+ lt->tm_mon = month - 1;
+ lt->tm_mday = day;
+ lt->tm_hour = 0;
+ lt->tm_min = 0;
+ lt->tm_sec = 0;
+ lt->tm_isdst = -1;
+ if ((tval = mktime(lt)) < 0)
+ return (1);
+ *store = tval;
+ return (0);
+}
+
+int
+ok_shell(char *name)
+{
+#ifdef __APPLE__
+ char *sh;
+#else
+ char *p, *sh;
+#endif
+
+ setusershell();
+ while ((sh = getusershell())) {
+ if (!strcmp(name, sh)) {
+ endusershell();
+ return (1);
+ }
+#ifndef __APPLE__
+ /* allow just shell name, but use "real" path */
+ if ((p = strrchr(sh, '/')) && strcmp(name, p + 1) == 0) {
+ endusershell();
+ return (1);
+ }
+#endif
+ }
+ endusershell();
+ return (0);
+}
+
+char *
+dup_shell(char *name)
+{
+ char *p, *sh, *ret;
+
+ setusershell();
+ while ((sh = getusershell())) {
+ if (!strcmp(name, sh)) {
+ endusershell();
+ return (strdup(name));
+ }
+ /* allow just shell name, but use "real" path */
+ if ((p = strrchr(sh, '/')) && strcmp(name, p + 1) == 0) {
+ ret = strdup(sh);
+ endusershell();
+ return (ret);
+ }
+ }
+ endusershell();
+ return (NULL);
+}
+
+#if OPEN_DIRECTORY
+int
+cfprintf(FILE* file, const char* format, ...) {
+ char* cstr;
+ int result = 0;
+ va_list args;
+ va_start(args, format);
+ CFStringRef formatStr = CFStringCreateWithCStringNoCopy(NULL, format, kCFStringEncodingUTF8, kCFAllocatorNull);
+ if (formatStr) {
+ CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, formatStr, args);
+ if (str) {
+ size_t size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1;
+ va_end(args);
+ cstr = malloc(size);
+ if (cstr && CFStringGetCString(str, cstr, size, kCFStringEncodingUTF8)) {
+ result = fprintf(file, "%s", cstr);
+ free(cstr);
+ }
+ CFRelease(str);
+ }
+ CFRelease(formatStr);
+ }
+ return result;
+}
+
+/*
+ * Edit the temp file. Return -1 on error, >0 if the file was modified, 0
+ * if it was not.
+ */
+int
+editfile(const char* tfn)
+{
+ struct sigaction sa, sa_int, sa_quit;
+ sigset_t oldsigset, sigset;
+ struct stat st1, st2;
+ const char *p, *editor;
+ int pstat;
+ pid_t editpid;
+
+ if ((editor = getenv("EDITOR")) == NULL)
+ editor = _PATH_VI;
+ if (p = strrchr(editor, '/'))
+ ++p;
+ else
+ p = editor;
+
+ if (stat(tfn, &st1) == -1)
+ return (-1);
+ sa.sa_handler = SIG_IGN;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(SIGINT, &sa, &sa_int);
+ sigaction(SIGQUIT, &sa, &sa_quit);
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ switch ((editpid = fork())) {
+ case -1:
+ return (-1);
+ case 0:
+ sigaction(SIGINT, &sa_int, NULL);
+ sigaction(SIGQUIT, &sa_quit, NULL);
+ sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+ errno = 0;
+ if (!master_mode) {
+ (void)setgid(getgid());
+ (void)setuid(getuid());
+ }
+ execlp(editor, p, tfn, (char *)NULL);
+ _exit(errno);
+ default:
+ /* parent */
+ break;
+ }
+ for (;;) {
+ if (waitpid(editpid, &pstat, WUNTRACED) == -1) {
+ if (errno == EINTR)
+ continue;
+ unlink(tfn);
+ editpid = -1;
+ break;
+ } else if (WIFSTOPPED(pstat)) {
+ raise(WSTOPSIG(pstat));
+ } else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) {
+ editpid = -1;
+ break;
+ } else {
+ unlink(tfn);
+ editpid = -1;
+ break;
+ }
+ }
+ sigaction(SIGINT, &sa_int, NULL);
+ sigaction(SIGQUIT, &sa_quit, NULL);
+ sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+ if (stat(tfn, &st2) == -1)
+ return (-1);
+ return (st1.st_mtime != st2.st_mtime);
+}
+
+void
+pw_error(char *name, int err, int eval)
+{
+ if (err)
+ warn("%s", name);
+ exit(eval);
+}
+
+#endif /* OPEN_DIRECTORY */
--- /dev/null
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <servers/bootstrap.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "dirhelper.h"
+
+#define DIRHELPER_BOOTSTRAP_NAME "com.apple.bsd.dirhelper"
+
+int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
+{
+ kern_return_t kr;
+ mach_port_t mp;
+
+ kr = bootstrap_look_up(bootstrap_port, DIRHELPER_BOOTSTRAP_NAME, &mp);
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "bootstrap_look_up(): %s\n", bootstrap_strerror(kr));
+ exit(EXIT_FAILURE);
+ }
+
+ kr = __dirhelper_create_user_local(mp);
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "dirhelper_create_user_local(): %s\n", mach_error_string(kr));
+ exit(EXIT_FAILURE);
+ }
+
+ exit(EXIT_SUCCESS);
+}
--- /dev/null
+<?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>Label</key>
+ <string>com.apple.bsd.dirhelper</string>
+ <key>MachServices</key>
+ <dict>
+ <key>com.apple.bsd.dirhelper</key>
+ <true/>
+ </dict>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/dirhelper</string>
+ </array>
+ <key>RunAtLoad</key>
+ <true/>
+ <key>TimeOut</key>
+ <integer>30</integer>
+ <key>StartCalendarInterval</key>
+ <dict>
+ <key>Hour</key>
+ <integer>3</integer>
+ <key>Minute</key>
+ <integer>35</integer>
+ </dict>
+ <key>EnvironmentVariables</key>
+ <dict>
+ <key>CLEAN_FILES_OLDER_THAN_DAYS</key>
+ <string>3</string>
+ </dict>
+</dict>
+</plist>
--- /dev/null
+.\"
+.\" Copyright (c) 2006-2007 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@
+.\"
+.Dd November 1, 2006
+.Dt dirhelper 8
+.Os "Mac OS X"
+.Sh NAME
+.Nm dirhelper
+.Nd helper for special directory creation
+.Sh SYNOPSIS
+.Nm dirhelper
+.Sh DESCRIPTION
+The
+.Nm dirhelper
+command is a launch-on-demand helper for special
+directory creation. It is launched in a privileged
+context via
+.Nm launchd
+in order to create special directories where the user
+would not otherwise have permission to do so.
+.Pp
+The
+.Nm dirhelper
+command should not be invoked directly. It will exit
+automatically after a period of inactivity.
+.Sh FILES
+.Bl -tag -width "/System/Library/LaunchDaemons/com.apple.bsd.dirhelper.plist" -compact
+.It Pa /System/Library/LaunchDaemons/com.apple.bsd.dirhelper.plist
+.El
+.Sh SEE ALSO
+.Xr launchd 8 ,
+.Xr launchd.plist 5
--- /dev/null
+/*
+ * Copyright (c) 2006-2007, 2010 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 <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <sys/kauth.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <servers/bootstrap.h>
+
+#include <bsm/libbsm.h>
+
+#include <asl.h>
+#include <membership.h>
+#include <launch.h>
+#include <dirhelper_priv.h>
+
+#include "dirhelper.h"
+#include "dirhelperServer.h"
+/*
+ * Uncomment the next line to define BOOTDEBUG, which will write timing
+ * info for clean_directories() to a file, /Debug.
+ */
+//#define BOOTDEBUG
+#ifdef BOOTDEBUG
+#include <mach/mach_time.h>
+#endif //BOOTDEBUG
+
+// globals for idle exit
+struct idle_globals {
+ mach_port_t mp;
+ long timeout;
+ struct timeval lastmsg;
+};
+
+struct idle_globals idle_globals;
+
+// argument structure for clean_thread
+struct clean_args {
+ const char** dirs;
+ int machineBoot;
+};
+
+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)
+#define is_directory(x) file_check((x), S_IFDIR, -1, -1, NULL, NULL)
+#define is_directory_get_owner_group(x,o,g) file_check((x), S_IFDIR, -1, -1, (o), (g))
+#define is_root_wheel_directory(x) file_check((x), S_IFDIR, 0, 0, NULL, NULL)
+
+int is_safeboot(void);
+
+void clean_files_older_than(const char* path, time_t when);
+void clean_directories(const char* names[], int);
+
+kern_return_t
+do___dirhelper_create_user_local(
+ mach_port_t server_port __attribute__((unused)),
+ audit_token_t au_tok)
+{
+ int res = 0;
+ uid_t euid;
+ gid_t gid = 0;
+ struct passwd* pwd = NULL;
+
+ gettimeofday(&idle_globals.lastmsg, NULL);
+
+ audit_token_to_au32(au_tok,
+ NULL, // audit uid
+ &euid, // euid
+ NULL, // egid
+ NULL, // ruid
+ NULL, // rgid
+ NULL, // remote_pid
+ NULL, // asid
+ NULL); // aud_tid_t
+
+ // Look-up the primary gid of the user. We'll use this for chown(2)
+ // so that the created directory is owned by a group that the user
+ // belongs to, avoiding warnings if files are moved outside this dir.
+ pwd = getpwuid(euid);
+ if (pwd) gid = pwd->pw_gid;
+
+ do { // begin block
+ char path[PATH_MAX];
+ char *next;
+
+ if (__user_local_dirname(euid, DIRHELPER_USER_LOCAL, path, sizeof(path)) == NULL) {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR,
+ "__user_local_dirname: %s", strerror(errno));
+ break;
+ }
+
+ // All dirhelper directories are now at the same level, so
+ // we need to remove the DIRHELPER_TOP_STR suffix to get the
+ // parent directory.
+ path[strlen(path) - (sizeof(DIRHELPER_TOP_STR) - 1)] = 0;
+
+ //
+ // 1. Starting with VAR_FOLDERS_PATH, make each subdirectory
+ // in path, ignoring failure if it already exists.
+ // 2. Change ownership of directory to the user.
+ //
+ next = path + strlen(VAR_FOLDERS_PATH);
+ while ((next = strchr(next, '/')) != NULL) {
+ *next = 0; // temporarily truncate
+ res = mkdir(path, 0755);
+ if (res != 0 && errno != EEXIST) {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR,
+ "mkdir(%s): %s", path, strerror(errno));
+ break;
+ }
+ *next++ = '/'; // restore the slash and increment
+ }
+ if(next || res) // an error occurred
+ break;
+ res = chown(path, euid, gid);
+ if (res != 0) {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR,
+ "chown(%s): %s", path, strerror(errno));
+ }
+ } while(0); // end block
+ return KERN_SUCCESS;
+}
+
+kern_return_t
+do___dirhelper_idle_exit(
+ mach_port_t server_port __attribute__((unused)),
+ audit_token_t au_tok __attribute__((unused))) {
+
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ long delta = now.tv_sec - idle_globals.lastmsg.tv_sec;
+ if (delta >= idle_globals.timeout) {
+ asl_log(NULL, NULL, ASL_LEVEL_DEBUG,
+ "idle exit after %ld seconds", delta);
+ exit(EXIT_SUCCESS);
+ }
+
+ return KERN_SUCCESS;
+}
+
+void*
+idle_thread(void* param __attribute__((unused))) {
+ for(;;) {
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ long delta = (now.tv_sec - idle_globals.lastmsg.tv_sec);
+ if (delta < idle_globals.timeout) {
+ // sleep for remainder of timeout
+ sleep((int)(idle_globals.timeout - delta));
+ } else {
+ // timeout has elapsed, attempt to idle exit
+ __dirhelper_idle_exit(idle_globals.mp);
+ }
+ }
+ return NULL;
+}
+
+// If when == 0, all files are removed. Otherwise, only regular files that were both created _and_ last modified before `when`.
+void
+clean_files_older_than(const char* path, time_t when) {
+ FTS* fts;
+
+ char* path_argv[] = { (char*)path, NULL };
+ fts = fts_open(path_argv, FTS_PHYSICAL | FTS_XDEV, NULL);
+ if (fts) {
+ FTSENT* ent;
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "Cleaning " VAR_FOLDERS_PATH "%s", path);
+ while ((ent = fts_read(fts))) {
+ switch(ent->fts_info) {
+ case FTS_F:
+ case FTS_DEFAULT:
+ if (when == 0) {
+#if DEBUG
+ asl_log(NULL, NULL, ASL_LEVEL_ALERT, "unlink(" VAR_FOLDERS_PATH "%s)", ent->fts_path);
+#endif
+ (void)unlink(ent->fts_path);
+ } else if (S_ISREG(ent->fts_statp->st_mode) && (ent->fts_statp->st_birthtime < when) && (ent->fts_statp->st_atime < when)) {
+ int fd = open(ent->fts_path, O_RDONLY | O_NONBLOCK);
+ if (fd != -1) {
+ // Obtain an exclusive lock so
+ // that we can avoid a race with other processes
+ // attempting to open or modify the file.
+ int res = flock(fd, LOCK_EX | LOCK_NB);
+ if (res == 0) {
+ struct stat sb;
+ res = fstat(fd, &sb);
+ if ((res == 0) && (sb.st_birthtime < when) && (sb.st_atime < when)) {
+#if DEBUG
+ asl_log(NULL, NULL, ASL_LEVEL_ALERT, "unlink(" VAR_FOLDERS_PATH "%s)", ent->fts_path);
+#endif
+ (void)unlink(ent->fts_path);
+ }
+ (void)flock(fd, LOCK_UN);
+ }
+ close(fd);
+ }
+ }
+ break;
+
+ case FTS_SL:
+ case FTS_SLNONE:
+ if (when == 0) {
+#if DEBUG
+ asl_log(NULL, NULL, ASL_LEVEL_ALERT, "unlink(" VAR_FOLDERS_PATH "%s)", ent->fts_path);
+#endif
+ (void)unlink(ent->fts_path);
+ }
+ break;
+
+ case FTS_DP:
+ if (when == 0) {
+#if DEBUG
+ asl_log(NULL, NULL, ASL_LEVEL_ALERT, "rmdir(" VAR_FOLDERS_PATH "%s)", ent->fts_path);
+#endif
+ (void)rmdir(ent->fts_path);
+ }
+ break;
+
+ case FTS_ERR:
+ case FTS_NS:
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, VAR_FOLDERS_PATH "%s: %s", ent->fts_path, strerror(ent->fts_errno));
+ break;
+
+ default:
+ break;
+ }
+ }
+ fts_close(fts);
+ } else {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, VAR_FOLDERS_PATH "%s: %s", path, strerror(errno));
+ }
+}
+
+int
+file_check(const char* path, int mode, int uid, int gid, uid_t* owner, gid_t* group) {
+ int check = 1;
+ struct stat sb;
+ if (lstat(path, &sb) == 0) {
+ check = check && ((sb.st_mode & S_IFMT) == mode);
+ check = check && ((sb.st_uid == (uid_t)uid) || uid == -1);
+ check = check && ((sb.st_gid == (gid_t)gid) || gid == -1);
+ if (check) {
+ if (owner) *owner = sb.st_uid;
+ if (group) *group = sb.st_gid;
+ }
+ } else {
+ if (errno != ENOENT) {
+ /* This will print a shorter path after chroot() */
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s: %s", path, strerror(errno));
+ }
+ check = 0;
+ }
+ return check;
+}
+
+int
+is_safeboot(void) {
+ uint32_t sb = 0;
+ size_t sbsz = sizeof(sb);
+
+ if (sysctlbyname("kern.safeboot", &sb, &sbsz, NULL, 0) != 0) {
+ return 0;
+ } else {
+ return (int)sb;
+ }
+}
+
+void *
+clean_thread(void *a) {
+ struct clean_args* args = (struct clean_args*)a;
+ DIR* d;
+ time_t when = 0;
+ int i;
+
+ if (!args->machineBoot) {
+ struct timeval now;
+ long days = 3;
+ const char* str = getenv("CLEAN_FILES_OLDER_THAN_DAYS");
+ if (str) {
+ days = strtol(str, NULL, 0);
+ }
+ (void)gettimeofday(&now, NULL);
+ for (i = 0; args->dirs[i]; i++)
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "Cleaning %s older than %ld days", args->dirs[i], days);
+
+ when = now.tv_sec - (days * 60 * 60 * 24);
+ }
+
+ // Look up the boot time
+ struct timespec boottime;
+ size_t len = sizeof(boottime);
+ if (sysctlbyname("kern.boottime", &boottime, &len, NULL, 0) == -1) {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s: %s", "sysctl kern.boottime", strerror(errno));
+ return NULL;
+ }
+
+ if (!is_root_wheel_directory(VAR_FOLDERS_PATH)) {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s: %s", VAR_FOLDERS_PATH, "invalid ownership");
+ return NULL;
+ }
+
+ if (chroot(VAR_FOLDERS_PATH)) {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "chroot(%s) failed: %s",
+ VAR_FOLDERS_PATH, strerror(errno));
+ }
+ chdir("/");
+ if ((d = opendir("/"))) {
+ struct dirent* e;
+ char path[PATH_MAX];
+
+ // /var/folders/*
+ while ((e = readdir(d))) {
+ if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) continue;
+
+ snprintf(path, sizeof(path), "%s%s", "/", e->d_name);
+ if (is_root_wheel_directory(path)) {
+ DIR* d2 = opendir(path);
+ if (d2) {
+ struct dirent* e2;
+
+ // /var/folders/*/*
+ while ((e2 = readdir(d2))) {
+ char dirbuf[PATH_MAX];
+ uid_t owner;
+ gid_t group;
+ if (strcmp(e2->d_name, ".") == 0 || strcmp(e2->d_name, "..") == 0) continue;
+ snprintf(dirbuf, sizeof(dirbuf),
+ "%s/%s", path, e2->d_name);
+ if (!is_directory_get_owner_group(dirbuf, &owner, &group)) continue;
+ if (pthread_setugid_np(owner, group) != 0) {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR,
+ "skipping %s: pthread_setugid_np(%u, %u): %s",
+ dirbuf, owner, group, strerror(errno));
+ continue;
+ }
+ for (i = 0; args->dirs[i]; i++) {
+ const char *name = args->dirs[i];
+ snprintf(dirbuf, sizeof(dirbuf),
+ "%s/%s/%s", path, e2->d_name, name);
+ if (is_directory(dirbuf)) {
+ // at boot time we clean all files,
+ // otherwise only clean regular files.
+ clean_files_older_than(dirbuf, when);
+ }
+ }
+ if (pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) != 0) {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR,
+ "%s: pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE): %s",
+ dirbuf, strerror(errno));
+ }
+ }
+ closedir(d2);
+ } else {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s: %s", path, strerror(errno));
+ }
+ }
+ }
+
+ closedir(d);
+ } else {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s: %s", VAR_FOLDERS_PATH, strerror(errno));
+ }
+ return NULL;
+}
+
+void
+clean_directories(const char* dirs[], int machineBoot) {
+ struct clean_args args;
+ pthread_t t;
+ int ret;
+#ifdef BOOTDEBUG
+ double ratio;
+ struct mach_timebase_info info;
+ uint64_t begin, end;
+ FILE *debug;
+
+ mach_timebase_info(&info);
+ ratio = (double)info.numer / ((double)info.denom * NSEC_PER_SEC);
+ begin = mach_absolute_time();
+ if((debug = fopen("/Debug", "a")) != NULL) {
+ fprintf(debug, "clean_directories: machineBoot=%d\n", machineBoot);
+ }
+#endif //BOOTDEBUG
+
+ args.dirs = dirs;
+ args.machineBoot = machineBoot;
+ ret = pthread_create(&t, NULL, clean_thread, &args);
+ if (ret == 0) {
+ ret = pthread_join(t, NULL);
+ if (ret) {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "clean_directories: pthread_join: %s",
+ strerror(ret));
+ }
+ } else {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "clean_directories: pthread_create: %s",
+ strerror(ret));
+ }
+#ifdef BOOTDEBUG
+ end = mach_absolute_time();
+ if(debug) {
+ fprintf(debug, "clean_directories: %f secs\n", ratio * (end - begin));
+ fclose(debug);
+ }
+#endif //BOOTDEBUG
+}
+
+int
+main(int argc, char* argv[]) {
+ mach_msg_size_t mxmsgsz = MAX_TRAILER_SIZE;
+ kern_return_t kr;
+ long idle_timeout = 30; // default 30 second timeout
+
+#ifdef BOOTDEBUG
+ {
+ FILE *debug;
+ int i;
+ if((debug = fopen("/Debug", "a")) != NULL) {
+ for(i = 0; i < argc; i++) {
+ fprintf(debug, " %s", argv[i]);
+ }
+ fputc('\n', debug);
+ fclose(debug);
+ }
+ }
+#endif //BOOTDEBUG
+ // Clean up TemporaryItems directory when launched at boot.
+ // It is safe to clean all file types at this time.
+ if (argc > 1 && strcmp(argv[1], "-machineBoot") == 0) {
+ const char *dirs[5];
+ int i = 0;
+ dirs[i++] = DIRHELPER_TEMP_STR;
+ dirs[i++] = "TemporaryItems";
+ dirs[i++] = "Cleanup At Startup";
+ if (is_safeboot()) {
+ dirs[i++] = DIRHELPER_CACHE_STR;
+ }
+ dirs[i] = NULL;
+ clean_directories(dirs, 1);
+ exit(EXIT_SUCCESS);
+ } else if (argc > 1 && strcmp(argv[1], "-cleanTemporaryItems") == 0) {
+ const char *dirs[] = {
+ DIRHELPER_TEMP_STR,
+ "TemporaryItems",
+ NULL
+ };
+ clean_directories(dirs, 0);
+ exit(EXIT_SUCCESS);
+ } else if (argc > 1) {
+ exit(EXIT_FAILURE);
+ }
+
+ launch_data_t config = NULL, checkin = NULL;
+ checkin = launch_data_new_string(LAUNCH_KEY_CHECKIN);
+ config = launch_msg(checkin);
+ if (!config || launch_data_get_type(config) == LAUNCH_DATA_ERRNO) {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "launchd checkin failed");
+ exit(EXIT_FAILURE);
+ }
+
+ launch_data_t tmv;
+ tmv = launch_data_dict_lookup(config, LAUNCH_JOBKEY_TIMEOUT);
+ if (tmv) {
+ idle_timeout = (long)launch_data_get_integer(tmv);
+ asl_log(NULL, NULL, ASL_LEVEL_DEBUG,
+ "idle timeout set: %ld seconds", idle_timeout);
+ }
+
+ launch_data_t svc;
+ svc = launch_data_dict_lookup(config, LAUNCH_JOBKEY_MACHSERVICES);
+ if (!svc) {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "no mach services");
+ exit(EXIT_FAILURE);
+ }
+
+ svc = launch_data_dict_lookup(svc, DIRHELPER_BOOTSTRAP_NAME);
+ if (!svc) {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "no mach service: %s",
+ DIRHELPER_BOOTSTRAP_NAME);
+ exit(EXIT_FAILURE);
+ }
+
+ mach_port_t mp = launch_data_get_machport(svc);
+ if (mp == MACH_PORT_NULL) {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "NULL mach service: %s",
+ DIRHELPER_BOOTSTRAP_NAME);
+ exit(EXIT_FAILURE);
+ }
+
+ // insert a send right so we can send our idle exit message
+ kr = mach_port_insert_right(mach_task_self(), mp, mp,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if (kr != KERN_SUCCESS) {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR, "send right failed: %s",
+ mach_error_string(kr));
+ exit(EXIT_FAILURE);
+ }
+
+ // spawn a thread for our idle timeout
+ pthread_t thread;
+ idle_globals.mp = mp;
+ idle_globals.timeout = idle_timeout;
+ gettimeofday(&idle_globals.lastmsg, NULL);
+ pthread_create(&thread, NULL, &idle_thread, NULL);
+
+ // look to see if we have any messages queued. if not, assume
+ // we were launched because of the calendar interval, and attempt
+ // to clean the temporary items.
+ mach_msg_type_number_t status_count = MACH_PORT_RECEIVE_STATUS_COUNT;
+ mach_port_status_t status;
+ kr = mach_port_get_attributes(mach_task_self(), mp,
+ MACH_PORT_RECEIVE_STATUS, (mach_port_info_t)&status, &status_count);
+ if (kr == KERN_SUCCESS && status.mps_msgcount == 0) {
+ const char *dirs[] = {
+ DIRHELPER_TEMP_STR,
+ "TemporaryItems",
+ NULL
+ };
+ clean_directories(dirs, 0);
+ exit(EXIT_SUCCESS);
+ }
+
+ // main event loop
+
+ kr = mach_msg_server(dirhelper_server, mxmsgsz, mp,
+ MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) |
+ MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0));
+ if (kr != KERN_SUCCESS) {
+ asl_log(NULL, NULL, ASL_LEVEL_ERR,
+ "mach_msg_server(mp): %s", mach_error_string(kr));
+ exit(EXIT_FAILURE);
+ }
+
+ exit(EXIT_SUCCESS);
+}
--- /dev/null
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)dmesg.8 8.1 (Berkeley) 6/5/93
+.\"
+.Dd June 5, 1993
+.Dt DMESG 8
+.Os BSD 4
+.Sh NAME
+.Nm dmesg
+.Nd "display the system message buffer"
+.Sh SYNOPSIS
+.Nm dmesg
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Sh DESCRIPTION
+.Nm Dmesg
+displays the contents of the system message buffer.
+This command needs to be run as root.
+.Pp
+.Sh SEE ALSO
+.Xr syslogd 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
--- /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) 1991, 1993
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <vis.h>
+#include <sys/sysctl.h>
+#include <libproc.h>
+
+void
+usage() {
+ (void)fprintf(stderr, "usage: sudo dmesg\n");
+ exit(1);
+}
+
+int
+main(int argc, char **argv) {
+ char *msgbuf, *visbuf;
+ int msgbufsize;
+ size_t sysctlsize = sizeof(msgbufsize);
+ long data_size;
+
+ if (argc > 1)
+ usage();
+
+ 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();
+ }
+
+ visbuf = malloc(data_size*4);
+ strvis(visbuf, msgbuf, 0);
+ printf("%s", visbuf);
+ free(visbuf);
+ free(msgbuf);
+ exit(0);
+}
+
--- /dev/null
+/*
+ * File: dynamic_pager.tproj/backing_store_alerts.defs
+ * Author: Chris Youngworth
+ * Date: Oct, 1999
+ *
+ * Exported alerts from the dynamic_pager facility.
+ */
+
+subsystem
+
+ backing_store_alerts 1000;
+
+#ifndef __MigTypeCheck
+#define __MigTypeCheck 1
+#endif
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+
+simpleroutine backing_store_alert(
+ alert_port : mach_port_t;
+ in flags : int);
--- /dev/null
+/*
+ * File: dynamic_pager.tproj/backing_store_triggers.defs
+ * Author: Chris Youngworth
+ * Date: Oct, 1999
+ *
+ * Exported client calls to the dynamic_pager facility.
+ */
+subsystem
+
+ backing_store_triggers 1200;
+
+
+#ifndef __MigTypeCheck
+#define __MigTypeCheck 1
+#endif
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+
+simpleroutine backing_store_triggers(
+ dynamic_pager : mach_port_t;
+ in hi_wat : int;
+ in flags : int;
+ in trigger_port : mach_port_t);
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <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>
--- /dev/null
+#include <default_pager/default_pager_alerts.defs>
--- /dev/null
+.\" Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+.\"
+.Dd July 8, 2003
+.Dt dynamic_pager 8
+.Os "Mac OS X"
+.Sh NAME
+.Nm dynamic_pager
+.Nd external storage manager for dynamic pager
+.Sh SYNOPSIS
+.Nm dynamic_pager
+.Op Fl F Ar filename
+.Op Fl S Ar filesize
+.Op Fl H Ar high-water-trigger
+.Op Fl L Ar low-water-trigger
+.Op Fl P Ar priority
+.Sh DESCRIPTION
+The
+.Nm dynamic_pager
+daemon manages a pool of external swap files
+which the kernel uses to support demand paging.
+This pool is expanded with new swap files
+as load on the system increases.
+It is contracted when the swapping resources are no longer needed. The
+.Nm dynamic_pager
+daemon also provides a notification service
+for those applications which wish to receive notices
+when the external paging pool expands or contracts.
+.Sh OPTIONS
+.Bl -tag -width Ds
+.\" ==========
+.It Fl F
+The base name of the
+.Ar filename
+to use for the external paging files. By default this is
+.Pa /private/var/vm/swapfile .
+.\" ==========
+.It Fl H
+If there are less than
+.Ar high-water-trigger
+bytes free in the external paging files, the kernel will signal
+.Nm dynamic_pager
+to add a new external paging file.
+.\" ==========
+.It Fl L
+If there are more than
+.Ar low-water-trigger
+bytes free in the external paging files, the kernel will coalese in-use pages
+and signal
+.Nm dynamic_pager
+to discard an external paging file.
+.Ar Low-water-trigger
+must be greater than
+.Ar high-water-trigger
++
+.Ar filesize .
+.\" ==========
+.It Fl P
+This option is currently unimplemented.
+.\" ==========
+.It Fl S
+The fixed
+.Ar filesize
+[in bytes] to use for the paging files. By default
+.Nm dynamic_pager
+uses variable sized paging files, using larger sized files as paging demands
+increase. The
+.Fl S ,
+.Fl H
+and
+.Fl L
+options disable that default and cause
+.Nm dynamic_pager
+to use a series of fixed sized external paging files.
+.El
+.Sh FILES
+.Bl -tag -width /Library/Preferences/com.apple.virtualMemory.plist -compact
+.It Pa /private/var/vm/swapfile*
+Default external paging files.
+.It Pa /Library/Preferences/com.apple.virtualMemory.plist
+Configuration file.
+.El
+.Sh XML PROPERTY LIST KEYS
+The following keys can be specified in the configuration file. Please see
+.Xr plist 5
+for more information about property list files.
+.Pp
+.Bl -ohang
+.It Sy UseEncryptedSwap <boolean>
+This optional key activates encrypted swap (aka Secure VM), so that all data is encrypted before being written to a swap file. The default is on for portable computers and off for other computers.
+.El
--- /dev/null
+/* File created by Chris Youngworth, Apple Computer 2/11/99 */
+
+
+#define mig_external
+
+#include <mach/port.h>
+#include <mach/mach_error.h>
+#include <mach/mach_traps.h>
+#include <mach/mach.h>
+#ifndef MACH_BSD
+#define MACH_BSD
+#endif
+#include <mach/mach_syscalls.h>
+#include <mach/mach_traps.h>
+#include <mach/mig_errors.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/gmon.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <nlist.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <paths.h>
+#include <dirent.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include <default_pager/default_pager_types.h>
+#include <default_pager_alertsServer.h>
+#include <backing_store_alerts.h>
+#include <backing_store_triggersServer.h>
+
+/*
+ * HI_WATER_DEFAULT set to this funny value to
+ * match the size that the low space application
+ * is asking for... need to keep MINIMUM_SIZE
+ * above this value.
+ */
+#define HI_WATER_DEFAULT 40000000
+#define MINIMUM_SIZE (1024 * 1024 * 64)
+#define MAXIMUM_SIZE (1024 * 1024 * 1024)
+
+#define MAX_LIMITS 8
+
+#if TARGET_OS_EMBEDDED
+
+#include <System/sys/content_protection.h>
+
+#define USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS 1
+#include <SystemConfiguration/SystemConfiguration.h>
+
+enum {
+ VM_PAGING_MODE_DISABLED = 0,
+ VM_PAGING_MODE_FREEZE,
+ VM_PAGING_MODE_DYNAMIC
+};
+
+#define VM_FREEZE_SYSCTL "vm.freeze_enabled"
+#define FREEZE_FIXED_SWAP_SIZE (128 * 1024 * 1024)
+#endif
+
+struct limit {
+ unsigned int size;
+ unsigned int low_water;
+} limits[MAX_LIMITS];
+
+
+int debug = 0;
+int max_valid = 0;
+int file_count = 0;
+unsigned int hi_water;
+unsigned int local_hi_water;
+int priority = 0;
+int options = 0;
+char fileroot[512];
+
+
+/* global parameters for application notification option */
+mach_port_t trigger_port = MACH_PORT_NULL;
+mach_port_t notify_port = MACH_PORT_NULL;
+unsigned int notify_high = 0;
+unsigned int bs_recovery;
+
+/*
+void setprof __P((struct kvmvars *kvp, int state));
+void dumpstate __P((struct kvmvars *kvp));
+void reset __P((struct kvmvars *kvp));
+*/
+
+
+
+mach_msg_return_t
+server_alert_loop(
+ mach_msg_size_t max_size,
+ mach_port_t rcv_name,
+ mach_msg_options_t options)
+{
+ mig_reply_error_t *bufRequest = 0, *bufReply = 0;
+ register mach_msg_return_t mr;
+ register kern_return_t kr;
+
+ if ((kr = vm_allocate(mach_task_self(),
+ (vm_address_t *)&bufRequest,
+ max_size + MAX_TRAILER_SIZE,
+ TRUE)) != KERN_SUCCESS)
+ return kr;
+ mlock(bufRequest, max_size + MAX_TRAILER_SIZE);
+ if ((kr = vm_allocate(mach_task_self(),
+ (vm_address_t *)&bufReply,
+ max_size + MAX_TRAILER_SIZE,
+ TRUE)) != KERN_SUCCESS)
+ return kr;
+ mlock(bufReply, max_size + MAX_TRAILER_SIZE);
+ while(TRUE) {
+ mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|options,
+ 0, max_size, rcv_name,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ if (mr == MACH_MSG_SUCCESS) {
+ /* we have a request message */
+
+ if(!(default_pager_alerts_server(
+ &bufRequest->Head, &bufReply->Head)))
+ backing_store_triggers_server(
+ &bufRequest->Head, &bufReply->Head);
+
+ if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
+ bufReply->RetCode != KERN_SUCCESS) {
+ if (bufReply->RetCode == MIG_NO_REPLY)
+ /*
+ * This return code is a little tricky--
+ * it appears that the demux routine found an
+ * error of some sort, but since that error
+ * would not normally get returned either to
+ * the local user or the remote one, we pretend it's
+ * ok.
+ */
+
+ bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
+ mach_msg_destroy(&bufRequest->Head);
+ continue;
+ }
+
+ if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) {
+ /* no reply port, so destroy the reply */
+ if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
+ mach_msg_destroy(&bufReply->Head);
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ (void)vm_deallocate(mach_task_self(),
+ (vm_address_t) bufRequest,
+ max_size + MAX_TRAILER_SIZE);
+ (void)vm_deallocate(mach_task_self(),
+ (vm_address_t) bufReply,
+ max_size + MAX_TRAILER_SIZE);
+ return KERN_FAILURE;
+
+}
+
+
+kern_return_t
+backing_store_triggers(dynamic_pager, hi_wat, flags, port)
+ mach_port_t dynamic_pager;
+ int hi_wat;
+ int flags;
+ mach_port_t port;
+{
+ int cur_limits;
+
+ if (file_count > max_valid)
+ cur_limits = max_valid;
+ else
+ cur_limits = file_count;
+
+ if((hi_wat + limits[cur_limits].size) > limits[cur_limits].low_water)
+ return KERN_FAILURE; /* let ipc system clean up port */
+
+ /* If there was a previous registration, throw it away */
+ if (notify_port != MACH_PORT_NULL) {
+ mach_port_deallocate(mach_task_self(), notify_port);
+ notify_port = MACH_PORT_NULL;
+ }
+
+ notify_port = port;
+ notify_high = hi_wat;
+ if(hi_water < notify_high) {
+ local_hi_water = notify_high;
+ } else {
+ local_hi_water = hi_water;
+ }
+ if(notify_high > hi_water) {
+ default_pager_space_alert(trigger_port, HI_WAT_ALERT);
+ }
+ return KERN_SUCCESS;
+}
+
+
+kern_return_t
+default_pager_space_alert(alert_port, flags)
+ mach_port_t alert_port;
+ int flags;
+{
+ char subfile[512];
+ off_t filesize;
+ int error=0, fd=0;
+ kern_return_t ret;
+ int cur_limits;
+ unsigned int cur_size;
+ unsigned int notifications;
+
+
+ if(flags & HI_WAT_ALERT) {
+
+ file_count++;
+
+ if (file_count > max_valid)
+ cur_limits = max_valid;
+ else
+ cur_limits = file_count;
+
+ cur_size = limits[cur_limits].size;
+ filesize = cur_size;
+
+ /*
+ * because the LO_WAT threshold changes relative to
+ * the size of the swap file we're creating
+ * we need to reset the LO_WAT_ALERT threshold each
+ * time we create a new swap file
+ */
+ if (limits[cur_limits].low_water)
+ notifications = HI_WAT_ALERT | LO_WAT_ALERT;
+ else
+ 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(!error) {
+ error = fcntl(fd, F_SETSIZE, &filesize);
+ if(error) {
+ error = ftruncate(fd, filesize);
+ }
+ if(error)
+ unlink(subfile);
+ close(fd);
+ }
+
+ if(error == -1) {
+ file_count--;
+
+ if (file_count > max_valid)
+ cur_limits = max_valid;
+ else
+ cur_limits = file_count;
+
+ if (limits[cur_limits].low_water)
+ notifications = HI_WAT_ALERT | LO_WAT_ALERT;
+ else
+ notifications = HI_WAT_ALERT;
+
+ notifications |= SWAP_FILE_CREATION_ERROR;
+
+ local_hi_water = local_hi_water>>2;
+ if(notify_high >= (local_hi_water)) {
+ if(notify_port != MACH_PORT_NULL) {
+ /* notify monitoring app of */
+ /* backing store shortage */
+ backing_store_alert(notify_port,
+ HI_WAT_ALERT);
+ mach_port_deallocate(mach_task_self(),
+ notify_port);
+ notify_port = MACH_PORT_NULL;
+ notify_high = 0;
+ }
+ }
+ } else {
+ if(hi_water < notify_high) {
+ if(local_hi_water < notify_high) {
+ bs_recovery = notify_high - local_hi_water;
+ }
+ local_hi_water = notify_high;
+ } else {
+ if(local_hi_water < hi_water) {
+ bs_recovery = hi_water - local_hi_water;
+ }
+ local_hi_water = hi_water;
+ }
+ ret = macx_swapon((uint64_t)(uintptr_t)subfile,
+ flags, cur_size, priority);
+
+ if(ret) {
+ unlink(subfile);
+ file_count--;
+
+ if (file_count > max_valid)
+ cur_limits = max_valid;
+ else
+ cur_limits = file_count;
+
+ if (limits[cur_limits].low_water)
+ notifications = HI_WAT_ALERT | LO_WAT_ALERT;
+ else
+ notifications = HI_WAT_ALERT;
+
+ local_hi_water = local_hi_water>>2;
+ if(notify_high >= (local_hi_water)) {
+ if(notify_port != MACH_PORT_NULL) {
+ /* notify monitoring app of */
+ /* backing store shortage */
+ backing_store_alert(
+ notify_port,
+ HI_WAT_ALERT);
+ mach_port_deallocate(
+ mach_task_self(),
+ notify_port);
+ notify_port = MACH_PORT_NULL;
+ notify_high = 0;
+ }
+ }
+ } else if(bs_recovery <= cur_size) {
+ if((bs_recovery != 0) && (notify_port)) {
+ backing_store_alert(notify_port,
+ LO_WAT_ALERT);
+ mach_port_deallocate(mach_task_self(),
+ notify_port);
+ notify_port = MACH_PORT_NULL;
+ notify_high = 0;
+ bs_recovery = 0;
+ }
+ } else
+ bs_recovery = bs_recovery-cur_size;
+ }
+ macx_triggers(local_hi_water, limits[cur_limits].low_water, notifications, alert_port);
+ }
+ if(flags & LO_WAT_ALERT) {
+ sprintf(subfile, "%s%d", fileroot, file_count);
+ if(hi_water < notify_high) {
+ local_hi_water = notify_high;
+ } else {
+ local_hi_water = hi_water;
+ }
+ if((bs_recovery != 0) && (notify_port != MACH_PORT_NULL)) {
+ backing_store_alert(notify_port, LO_WAT_ALERT);
+ mach_port_deallocate(mach_task_self(), notify_port);
+ notify_port = MACH_PORT_NULL;
+ notify_high = 0;
+ bs_recovery = 0;
+ }
+ if((error = macx_swapoff((uint64_t)(uintptr_t)subfile,
+ flags)) == 0) {
+
+ unlink(subfile);
+ file_count--;
+
+ if (file_count > max_valid)
+ cur_limits = max_valid;
+ else
+ cur_limits = file_count;
+ } else {
+ if (file_count > max_valid)
+ cur_limits = max_valid;
+ else
+ cur_limits = file_count;
+ }
+ /*
+ * only need to reset the LO_WAT_ALERT... the HI_WAT size is fixed,
+ * it doesn't change even if the swap file size shrinks or grows
+ */
+ macx_triggers(local_hi_water, limits[cur_limits].low_water, LO_WAT_ALERT, alert_port);
+ }
+ return KERN_SUCCESS;
+}
+
+void
+wait_on_paging_trigger(trigger_port)
+ mach_port_t trigger_port;
+{
+ kern_return_t result;
+ result = server_alert_loop(4096, trigger_port, MACH_MSG_OPTION_NONE);
+ if (result != KERN_SUCCESS) {
+ fprintf(stderr, "dynamic_pager: default pager alert failed\n");
+ exit(EXIT_FAILURE);
+ }
+ exit(EXIT_SUCCESS);
+}
+
+void
+paging_setup(flags, size, priority, low, high, encrypted)
+ int flags;
+ int size;
+ int priority;
+ int low;
+ int high;
+ boolean_t encrypted;
+{
+ off_t filesize = size;
+ char subfile[512];
+ int error, fd = 0;
+
+ 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);
+ }
+
+
+ error = fcntl(fd, F_SETSIZE, &filesize);
+ if(error) {
+ error = ftruncate(fd, filesize);
+ }
+ close(fd);
+
+ if (error == -1) {
+ fprintf(stderr, "dynamic_pager: cannot extend paging file size %s to %llu!\n",
+ subfile, filesize);
+ exit(EXIT_FAILURE);
+ }
+
+ if (macx_triggers(0, 0,
+ (encrypted
+ ? SWAP_ENCRYPT_ON
+ : SWAP_ENCRYPT_OFF),
+ MACH_PORT_NULL) != 0) {
+ fprintf(stderr,
+ "dynamic_pager: warning: "
+ "could not turn encrypted swap %s\n",
+ (encrypted ? "on" : "off"));
+ }
+
+ macx_swapon((uint64_t)(uintptr_t)subfile, flags, size, priority);
+
+ if(hi_water) {
+ mach_msg_type_name_t poly;
+
+ if (mach_port_allocate(mach_task_self(),
+ MACH_PORT_RIGHT_RECEIVE,
+ &trigger_port) != KERN_SUCCESS) {
+ fprintf(stderr,"dynamic_pager: allocation of trigger port failed\n");
+ exit(EXIT_FAILURE);
+ }
+ /* create a send right on our local port */
+ mach_port_extract_right(mach_task_self(), trigger_port,
+ MACH_MSG_TYPE_MAKE_SEND, &trigger_port, &poly);
+ macx_triggers(high, low, HI_WAT_ALERT, trigger_port);
+
+ if(low) {
+ macx_triggers(high, low, LO_WAT_ALERT, trigger_port);
+ }
+ /* register control port for applications wishing to */
+ /* get backing store notifications or change dynamic */
+ /* pager settings. */
+ set_dp_control_port(mach_host_self(), trigger_port);
+ wait_on_paging_trigger(trigger_port);
+ }
+ exit(EXIT_SUCCESS);
+}
+
+static void
+clean_swap_directory(const char *path)
+{
+ DIR *dir;
+ struct dirent *entry;
+ char buf[1024];
+
+ dir = opendir(path);
+ if (dir == NULL) {
+ fprintf(stderr,"dynamic_pager: cannot open swap directory %s\n", path);
+ exit(EXIT_FAILURE);
+ }
+
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_namlen>= 4 && strncmp(entry->d_name, "swap", 4) == 0) {
+ snprintf(buf, sizeof buf, "%s/%s", path, entry->d_name);
+ unlink(buf);
+ }
+ }
+
+ closedir(dir);
+}
+
+#define VM_PREFS_PLIST "/Library/Preferences/com.apple.virtualMemory.plist"
+#define VM_PREFS_DISABLE_ENCRYPT_SWAP_KEY "DisableEncryptedSwap"
+
+static boolean_t
+should_encrypt_swap(void)
+{
+ CFPropertyListRef propertyList;
+ CFTypeID propertyListType;
+ CFStringRef errorString;
+ CFDataRef resourceData;
+ SInt32 errorCode;
+ CFURLRef fileURL;
+ CFTypeRef disable_encrypted_swap;
+ boolean_t should_encrypt = TRUE;
+ boolean_t explicit_value = FALSE;
+
+ fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)VM_PREFS_PLIST, strlen(VM_PREFS_PLIST), false);
+ if (fileURL == NULL) {
+ /*fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), VM_PREFS_PLIST);*/
+ goto done;
+ }
+
+ if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) {
+ /*fprintf(stderr, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), VM_PREFS_PLIST, (int)errorCode);*/
+ CFRelease(fileURL);
+ goto done;
+ }
+
+ CFRelease(fileURL);
+ propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainers, &errorString);
+ if (propertyList == NULL) {
+ /*fprintf(stderr, "%s: cannot get XML propertyList %s\n", getprogname(), VM_PREFS_PLIST);*/
+ CFRelease(resourceData);
+ goto done;
+ }
+
+ propertyListType = CFGetTypeID(propertyList);
+
+ if (propertyListType == CFDictionaryGetTypeID()) {
+ disable_encrypted_swap = (CFTypeRef) CFDictionaryGetValue((CFDictionaryRef) propertyList, CFSTR(VM_PREFS_DISABLE_ENCRYPT_SWAP_KEY));
+ if (disable_encrypted_swap == NULL) {
+ /* no value: use the default value i.e. encrypted swap ON */
+ } else if (CFGetTypeID(disable_encrypted_swap) != CFBooleanGetTypeID()) {
+ fprintf(stderr, "%s: wrong type for key \"%s\"\n",
+ getprogname(), VM_PREFS_DISABLE_ENCRYPT_SWAP_KEY);
+ /* bogus value, assume it's "true" for safety's sake */
+ should_encrypt = TRUE;
+ explicit_value = TRUE;
+ } else {
+ should_encrypt = CFBooleanGetValue((CFBooleanRef)disable_encrypted_swap) ? FALSE : TRUE;
+ explicit_value = TRUE;
+ }
+ }
+ else {
+ /*fprintf(stderr, "%s: invalid propertyList type %d (not a dictionary)\n", getprogname(), propertyListType);*/
+ }
+ CFRelease(resourceData);
+ CFRelease(propertyList);
+
+done:
+ if (! explicit_value) {
+#if TARGET_OS_EMBEDDED
+ should_encrypt = FALSE;
+#endif
+ }
+
+ return should_encrypt;
+}
+
+#if TARGET_OS_EMBEDDED
+
+#define VM_PREFS_PAGING_MODE_PLIST "com.apple.virtualMemoryMode.plist"
+#define VM_PREFS_PAGING_MODE_KEY "Mode"
+
+static uint32_t
+get_paging_mode(void)
+{
+ SCPreferencesRef paging_prefs;
+ uint32_t paging_mode;
+
+ paging_mode = VM_PAGING_MODE_FREEZE; /* default */
+
+ paging_prefs = SCPreferencesCreate(NULL, CFSTR("dynamic_pager"), CFSTR(VM_PREFS_PAGING_MODE_PLIST));
+ if (paging_prefs) {
+ CFNumberRef value;
+
+ value = SCPreferencesGetValue(paging_prefs, CFSTR(VM_PREFS_PAGING_MODE_KEY));
+
+ if (value && (CFGetTypeID( value ) == CFNumberGetTypeID() ) ) {
+ CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &paging_mode);
+ }
+
+ CFRelease(paging_prefs);
+ }
+
+ return paging_mode;
+}
+
+#endif
+
+int
+main(int argc, char **argv)
+{
+ extern char *optarg;
+ extern int optind;
+ char default_filename[] = "/private/var/vm/swapfile";
+ int ch;
+ int variable_sized = 1,flags=0;
+ boolean_t encrypted_swap;
+ static char tmp[1024];
+ struct statfs sfs;
+ char *q;
+#if TARGET_OS_EMBEDDED
+ int err;
+ uint32_t paging_mode;
+ size_t paging_mode_length;
+#endif
+
+/*
+ setlinebuf(stdout);
+ setlinebuf(stderr);
+*/
+
+ seteuid(getuid());
+ strcpy(fileroot, default_filename);
+
+retry:
+ limits[0].size = 20000000;
+ limits[0].low_water = 0;
+
+ hi_water = 0;
+ local_hi_water = 0;
+
+ encrypted_swap = should_encrypt_swap();
+
+ while ((ch = getopt(argc, argv, "EF:L:H:S:P:QO:")) != EOF) {
+ switch((char)ch) {
+
+ case 'E':
+ encrypted_swap = TRUE;
+ break;
+
+ case 'F':
+ strncpy(fileroot, optarg, 500);
+ break;
+
+ case 'L':
+ variable_sized = 0;
+ limits[0].low_water = atoi(optarg);
+ break;
+ case 'H':
+ variable_sized = 0;
+ hi_water = atoi(optarg);
+ break;
+ case 'S':
+ variable_sized = 0;
+ limits[0].size = atoi(optarg);
+ break;
+ case 'P':
+ priority = atoi(optarg);
+ break;
+
+ case 'Q':
+ /* just query for "encrypted swap" default value */
+ fprintf(stdout,
+ "dynamic_pager: encrypted swap will be %s\n",
+ encrypted_swap ? "ON": "OFF");
+ exit(0);
+
+ default:
+ (void)fprintf(stderr,
+ "usage: dynamic_pager [-F filename] [-L low water alert trigger] [-H high water alert trigger] [-S file size] [-P priority]\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /*
+ * get rid of the filename at the end of the swap file specification
+ * we only want the portion of the pathname that should already exist
+ */
+ strcpy(tmp, fileroot);
+ if ((q = strrchr(tmp, '/')))
+ *q = 0;
+
+ /*
+ * Remove all files in the swap directory.
+ */
+ clean_swap_directory(tmp);
+
+#if TARGET_OS_EMBEDDED
+ paging_mode = get_paging_mode();
+ paging_mode_length = sizeof(paging_mode);
+
+ switch (paging_mode) {
+ case VM_PAGING_MODE_DISABLED:
+ /* Paging disabled; nothing to do here so exit */
+ exit(EXIT_SUCCESS);
+
+ case VM_PAGING_MODE_FREEZE:
+ /* Freeze mode; one swap file of fixed size, so enable and override defaults if set */
+ err = sysctlbyname(VM_FREEZE_SYSCTL, NULL, 0, &paging_mode, paging_mode_length);
+ if (err < 0) {
+ (void)fprintf(stderr, "dynamic_pager: cannot set %s\n", VM_FREEZE_SYSCTL);
+ exit(EXIT_FAILURE);
+ }
+ variable_sized = 0;
+ limits[0].size = FREEZE_FIXED_SWAP_SIZE;
+ break;
+
+ case VM_PAGING_MODE_DYNAMIC:
+ /* Dynamic paging selected; proceed normally */
+ break;
+
+ default:
+ /* Invalid option */
+ (void)fprintf(stderr, "dynamic_pager: invalid paging_mode %d\n", paging_mode);
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ if (statfs(tmp, &sfs) == -1) {
+ /*
+ * Setup the swap directory.
+ */
+ if (mkdir(tmp, 0755) == -1) {
+ (void)fprintf(stderr, "dynamic_pager: cannot create swap directory %s\n", tmp);
+ exit(EXIT_FAILURE);
+ }
+ }
+ chown(tmp, 0, 0);
+
+ if (variable_sized) {
+ int i;
+ int mib[4];
+ size_t len;
+ unsigned int size;
+ u_int64_t memsize;
+ u_int64_t fs_limit = 0;
+
+ /*
+ * if we get here, then none of the following options were specified... -L, H, or -S
+ * drop into a new mode that scales the size of the swap file based on how much free
+ * space is left on the volume being used for swap and the amount of physical ram
+ * installed on the system...
+ * basically, we'll pick a maximum size that doesn't exceed the following limits...
+ * 1/8 the remaining free space of the swap volume
+ * the size of phsyical ram
+ * MAXIMUM_SIZE - currently set to 1 Gbyte...
+ * once we have the maximum, we'll create a list of sizes and low_water limits
+ * we'll start with 2 files of MINIMUM_SIZE - currently 64 Mbytes...
+ * subsequent entries will double in size up to the calculated maximum... the low_water
+ * limit will be the sum of the current file size and the previous file size for each entry...
+ * as we add or delete files, we'll use the current file_count as an index into this
+ * table... if it's beyond the table size, we'll use the last entry
+ * the table entry will determine the size of the file to be created and the new low_water mark...
+ * the high_water mark is set to HI_WATER_DEFAULT which must be smaller than MINIMUM_SIZE...
+ * currently it is set to 40,000,000 to match the size being requested by the application
+ * monitoring low space conditions... having it set to the same size keeps us from creating
+ * an additional swap file when it really isn't necessary
+ */
+
+ if (statfs(tmp, &sfs) == -1) {
+ /*
+ * We really can't get filesystem status,
+ * so let's not limit the swap files...
+ */
+ fs_limit = (u_int64_t) -1;
+ }
+
+ if (fs_limit != (u_int64_t) -1) {
+ /*
+ * Limit the maximum size of a swap file to 1/8 the free
+ * space available on the filesystem where the swap files
+ * are to reside. This will allow us to allocate and
+ * deallocate in finer increments on systems without much
+ * free space.
+ */
+ fs_limit = ((u_int64_t)sfs.f_bfree * (u_int64_t)sfs.f_bsize) / 8;
+ }
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_MEMSIZE;
+ len = sizeof(u_int64_t);
+
+ if (sysctl(mib, 2, &memsize, &len, NULL, 0) < 0) {
+ /*
+ * if the sysctl fails for some reason
+ * use the starting size as the default
+ */
+ memsize = MINIMUM_SIZE;
+ }
+ if (memsize > fs_limit)
+ /*
+ * clip based on filesystem space available
+ */
+ memsize = fs_limit;
+
+ /*
+ * further limit the maximum size of a swap file
+ */
+ if (memsize <= MINIMUM_SIZE) {
+ (void)fprintf(stderr, "dynamic_pager: Need more space on the disk to enable swapping.\n");
+ sleep(30);
+ goto retry;
+ } else if (memsize <= (MINIMUM_SIZE*2)) {
+ (void)fprintf(stderr, "dynamic_pager: Activating emergency swap file immediately.\n");
+ flags |= USE_EMERGENCY_SWAP_FILE_FIRST;
+ } else if (memsize > MAXIMUM_SIZE) {
+ memsize = MAXIMUM_SIZE;
+ }
+
+ size = MINIMUM_SIZE;
+
+ /*
+ * start small and work our way up to the maximum
+ * sized allowed... this way, we don't tie up too
+ * much disk space if we never do any real paging
+ */
+ for (max_valid = 0, i = 0; i < MAX_LIMITS; i++) {
+ limits[i].size = size;
+
+ if (i == 0)
+ limits[i].low_water = size * 2;
+ else {
+ if ((limits[i - 1].size / 2) > HI_WATER_DEFAULT)
+ limits[i].low_water = size + (limits[i - 1].size / 2);
+ else
+ limits[i].low_water = size + limits[i - 1].size;
+ }
+
+ if (i) {
+ /*
+ * make the first 2 files the same size
+ */
+ size = size * 2;
+ if (size > memsize)
+ break;
+ }
+ max_valid++;
+ }
+ if (max_valid >= MAX_LIMITS)
+ max_valid = MAX_LIMITS - 1;
+
+ hi_water = HI_WATER_DEFAULT;
+ }
+ local_hi_water = hi_water;
+
+ if((limits[0].low_water != 0) && (limits[0].low_water <= (limits[0].size + hi_water))) {
+ (void)fprintf(stderr, "dynamic_pager: low water trigger must be larger than size + hi_water\n");
+ exit(EXIT_FAILURE);
+ }
+ argc -= optind;
+ argv += optind;
+
+ paging_setup(flags, limits[0].size, priority, limits[0].low_water, hi_water,
+ encrypted_swap);
+
+ return (0);
+}
--- /dev/null
+.\" Copyright (c) 2000, Apple Computer, Inc. All rights reserved.
+.\"
+.Dd November 7, 2002
+.Dt FS_USAGE 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm fs_usage
+.Nd report system calls and page faults related to filesystem activity in
+real-time
+.Sh SYNOPSIS
+.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
+utility presents an ongoing display of system call usage information
+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
+running
+.Nm fs_usage
+process, Terminal, telnetd, sshd, rlogind, tcsh, csh and sh.
+These defaults can be overridden such that output is limited to include or
+exclude a list of processes specified by the user.
+.Pp
+The output presented by
+.Nm fs_usage
+is formatted according to the size of your window.
+A narrow window will display fewer columns of data.
+Use a wide window for maximum data display.
+You may override the window formatting restrictions
+by forcing a wide display with the
+.Fl w
+option.
+In this case, the data displayed will wrap
+when the window is not wide enough.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.\" ==========
+.It Fl e
+Specifying the
+.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,
+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
+option turns on output filtering based on the
+.Pa mode
+provided.
+Multiple filtering options can be specified.
+By default, no output filtering occurs.
+The supported modes are:
+.Pp
+.Pa network
+Network-related events are displayed.
+.Pp
+.Pa filesys
+Filesystem-related events are displayed.
+.Pp
+.Pa pathname
+Pathname-related events are displayed.
+.Pp
+.Pa exec
+Exec and spawn events are displayed.
+.Pp
+.Pa diskio
+Disk I/O events are displayed.
+.Pp
+.Pa cachehit
+In addition, show cache hits.
+.\" ==========
+.It Fl b
+Specifying the
+.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.
+.\" ==========
+.It Fl S Ar start_time
+If
+.Fl R
+is selected, specifies the start time in microseconds to
+begin processing entries from the raw trace file. Entries
+with timestamps before the specified start time will be
+skipped.
+.\" ==========
+.It Fl E Ar end_time
+If
+.Fl R
+is selected, specifies the ending time in microseconds to
+stop processing entries from the raw trace file. Entries
+with timestamps beyond the specified ending time will be
+skipped.
+.\" ==========
+.It pid | cmd
+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.
+.El
+.Pp
+If you set the DYLD_IMAGE_SUFFIX environment variable to
+.Dq Li _debug ,
+then an application will use the debug version of all libraries,
+including the Carbon FileManager.
+See
+.Xr dyld 1 .
+When
+.Nm fs_usage
+is run against a Carbon Application launched in this environment,
+then the high-level Carbon FileManager calls
+will be displayed bracketing the system calls that they are built on.
+.Pp
+The data columns displayed are as follows:
+.Bl -tag -width Ds
+.Pp
+.It TIMESTAMP
+TOD when call occurred.
+Wide mode will have microsecond granularity.
+.It CALL
+The name of the network or filesystem related call, page-in, page-out,
+or physical disk access.
+.It FILE DESCRIPTOR
+Of the form F=x, x is a file descriptor.
+Depending on the type of system call,
+this will be either an input value or a return value.
+.It BYTE COUNT
+Of the form B=x, x is the number of bytes requested by the call.
+.It [ERRNO]
+On error, the errno is displayed in brackets.
+.It PATHNAME
+Pathname of the file accessed (up to the last 28 bytes).
+.It FAULT ADDRESS
+Of the form A=0xnnnnnnnn,
+where 0xnnnnnnnn is the address being faulted.
+.It DISK BLOCK NUMBER
+Of the form D=0xnnnnnnnn,
+where 0xnnnnnnnn is the block number
+of the physical disk block being read or written.
+.It OFFSET
+Of the form O=0xnnnnnnnn, where 0xnnnnnnnn is a file offset.
+.It SELECT RETURN
+Of the form S=x, x is the number of ready descriptors returned
+by the select() system call.
+If S=0, the time limit expired.
+.It TIME INTERVAL(W)
+The elapsed time spent in the system call.
+A
+.Sq Li W
+after the elapsed time indicates the process was scheduled out
+during this file activity.
+In this case, the elapsed time includes the wait time.
+.It PROCESS NAME
+The process that made the system call. Wide mode will append the
+thread id to the process name (i.e Mail.nnn).
+.El
+.Pp
+.Sh SAMPLE USAGE
+.Pp
+fs_usage -w -f filesys Mail
+.Pp
+.Nm fs_usage
+will display file system related data
+for all instances of processes named Mail.
+Maximum data output will be displayed in the window.
+.Sh SEE ALSO
+.Xr dyld 1 ,
+.Xr latency 1 ,
+.Xr sc_usage 1 ,
+.Xr top 1
--- /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@
+ */
+
+/*
+cc -I/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders -DPRIVATE -D__APPLE_PRIVATE -arch x86_64 -arch i386 -O -lutil -o fs_usage fs_usage.c
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <strings.h>
+#include <nlist.h>
+#include <fcntl.h>
+#include <aio.h>
+#include <string.h>
+#include <dirent.h>
+#include <libc.h>
+#include <termios.h>
+#include <errno.h>
+#include <err.h>
+#include <libutil.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <sys/disk.h>
+#include <sys/file.h>
+
+#ifndef KERNEL_PRIVATE
+#define KERNEL_PRIVATE
+#include <sys/kdebug.h>
+#undef KERNEL_PRIVATE
+#else
+#include <sys/kdebug.h>
+#endif /*KERNEL_PRIVATE*/
+
+#import <mach/clock_types.h>
+#import <mach/mach_time.h>
+
+
+
+#define F_OPENFROM 56 /* SPI: open a file relative to fd (must be a dir) */
+#define F_UNLINKFROM 57 /* SPI: open a file relative to fd (must be a dir) */
+#define F_CHECK_OPENEVT 58 /* SPI: if a process is marked OPENEVT, or in O_EVTONLY on opens of this vnode */
+
+
+#ifndef RAW_VERSION1
+typedef struct {
+ int version_no;
+ int thread_count;
+ uint64_t TOD_secs;
+ uint32_t TOD_usecs;
+} RAW_header;
+
+#define RAW_VERSION0 0x55aa0000
+#define RAW_VERSION1 0x55aa0101
+#endif
+
+
+#define MAXINDEX 2048
+
+typedef struct LibraryRange {
+ uint64_t b_address;
+ uint64_t e_address;
+} LibraryRange;
+
+LibraryRange framework32;
+LibraryRange framework64;
+
+
+#define TEXT_R 0
+#define DATA_R 1
+#define OBJC_R 2
+#define IMPORT_R 3
+#define UNICODE_R 4
+#define IMAGE_R 5
+#define LINKEDIT_R 6
+
+
+char *frameworkType[] = {
+ "<TEXT> ",
+ "<DATA> ",
+ "<OBJC> ",
+ "<IMPORT> ",
+ "<UNICODE> ",
+ "<IMAGE> ",
+ "<LINKEDIT>",
+};
+
+
+typedef struct LibraryInfo {
+ uint64_t b_address;
+ uint64_t e_address;
+ int r_type;
+ char *name;
+} LibraryInfo;
+
+LibraryInfo frameworkInfo[MAXINDEX];
+int numFrameworks = 0;
+
+
+/*
+ * MAXCOLS controls when extra data kicks in.
+ * MAX_WIDE_MODE_COLS controls -w mode to get even wider data in path.
+ * If NUMPARMS changes to match the kernel, it will automatically
+ * get reflected in the -w mode output.
+ */
+#define NUMPARMS 23
+#define PATHLENGTH (NUMPARMS*sizeof(uintptr_t))
+
+#define MAXCOLS 132
+#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 arg2;
+ int arg3;
+ int arg4;
+ int arg5;
+ int arg6;
+ int arg7;
+ int arg8;
+ int waited;
+ double stime;
+ uint64_t vnodeid;
+ char *nameptr;
+ uintptr_t *pathptr;
+ int pn_scall_index;
+ int pn_work_index;
+ struct lookup lookups[MAX_PATHNAMES];
+};
+
+
+typedef struct threadmap * threadmap_t;
+
+struct threadmap {
+ threadmap_t tm_next;
+
+ uintptr_t tm_thread;
+ unsigned int tm_setsize; /* this is a bit count */
+ unsigned long *tm_setptr; /* file descripter bitmap */
+ char tm_command[MAXCOMLEN + 1];
+};
+
+
+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 (HASH_SIZE - 1)
+
+th_info_t th_info_hash[HASH_SIZE];
+th_info_t th_info_freelist;
+
+threadmap_t threadmap_hash[HASH_SIZE];
+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;
+long last_time;
+int wideflag = 0;
+int columns = 0;
+
+int one_good_pid = 0; /* Used to fail gracefully when bad pids given */
+int select_pid_mode = 0; /* Flag set indicates that output is restricted
+ to selected pids or commands */
+
+char *arguments = 0;
+int argmax = 0;
+
+
+#define USLEEP_MIN 1
+#define USLEEP_BEHIND 2
+#define USLEEP_MAX 32
+int usleep_ms = USLEEP_MIN;
+
+/*
+ * Network only or filesystem only output filter
+ * Default of zero means report all activity - no filtering
+ */
+#define FILESYS_FILTER 0x01
+#define NETWORK_FILTER 0x02
+#define EXEC_FILTER 0x08
+#define PATHNAME_FILTER 0x10
+#define DISKIO_FILTER 0x20
+#define DEFAULT_DO_NOT_FILTER 0x00
+
+int filter_mode = DEFAULT_DO_NOT_FILTER;
+
+boolean_t show_cachehits = FALSE;
+
+#define NFS_DEV -1
+#define CS_DEV -2
+
+struct diskrec {
+ struct diskrec *next;
+ char *diskname;
+ int dev;
+};
+
+struct diskio {
+ struct diskio *next;
+ struct diskio *prev;
+ int type;
+ int bp;
+ int dev;
+ int blkno;
+ int iosize;
+ int io_errno;
+ 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 *free_diskios = NULL;
+struct diskio *busy_diskios = 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, 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, 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);
+char *find_disk_name(int);
+void cache_disk_names();
+void recache_disk_names();
+
+void lookup_name(uint64_t user_addr, char **type, char **name);
+int ReadSharedCacheMap(const char *, LibraryRange *, char *);
+void SortFrameworkAddresses();
+
+void fs_usage_fd_set(uintptr_t, unsigned int);
+int fs_usage_fd_isset(uintptr_t, unsigned int);
+void fs_usage_fd_clear(uintptr_t, unsigned int);
+
+void init_arguments_buffer();
+int get_real_command_name(int, char *, int);
+
+void delete_all_events();
+void delete_event(th_info_t);
+th_info_t add_event(uintptr_t, int);
+th_info_t find_event(uintptr_t, int);
+void mark_thread_waited(uintptr_t);
+
+void read_command_map();
+void delete_all_map_entries();
+void create_map_entry(uintptr_t, int, char *);
+void delete_map_entry(uintptr_t);
+threadmap_t find_map_entry(uintptr_t);
+
+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();
+void set_pidcheck();
+void set_pidexclude();
+int quit();
+
+
+#define CLASS_MASK 0xff000000
+#define CSC_MASK 0xffff0000
+#define BSC_INDEX(type) ((type >> 2) & 0x3fff)
+
+
+#define TRACE_DATA_NEWTHREAD 0x07000004
+#define TRACE_DATA_EXEC 0x07000008
+#define TRACE_STRING_NEWTHREAD 0x07010004
+#define TRACE_STRING_EXEC 0x07010008
+
+#define MACH_vmfault 0x01300008
+#define MACH_pageout 0x01300004
+#define MACH_sched 0x01400000
+#define MACH_stkhandoff 0x01400008
+#define MACH_idle 0x01400024
+#define VFS_LOOKUP 0x03010090
+#define 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_READ (DKIO_READ << 2)
+#define P_DISKIO_ASYNC (DKIO_ASYNC << 2)
+#define P_DISKIO_META (DKIO_META << 2)
+#define P_DISKIO_PAGING (DKIO_PAGING << 2)
+#define P_DISKIO_THROTTLE (DKIO_THROTTLE << 2)
+#define P_DISKIO_PASSIVE (DKIO_PASSIVE << 2)
+#define P_DISKIO_NOCACHE (DKIO_NOCACHE << 2)
+#define P_DISKIO_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 P_DISKIO_TYPE (P_DISKIO | P_DISKIO_READ | P_DISKIO_META | P_DISKIO_PAGING)
+#define P_DISKIO_MASK (CSC_MASK | 0x4)
+
+#define P_WrData (P_DISKIO)
+#define P_RdData (P_DISKIO | P_DISKIO_READ)
+#define P_WrMeta (P_DISKIO | P_DISKIO_META)
+#define P_RdMeta (P_DISKIO | P_DISKIO_META | P_DISKIO_READ)
+#define P_PgOut (P_DISKIO | P_DISKIO_PAGING)
+#define P_PgIn (P_DISKIO | P_DISKIO_PAGING | P_DISKIO_READ)
+
+#define P_CS_Class 0x0a000000 // DBG_CORESTORAGE
+#define P_CS_Type_Mask 0xfffffff0
+#define P_CS_IO_Done 0x00000004
+
+#define P_CS_ReadChunk 0x0a000200 // chopped up request
+#define P_CS_WriteChunk 0x0a000210
+#define P_CS_MetaRead 0x0a000300 // meta data
+#define P_CS_MetaWrite 0x0a000310
+#define P_CS_TransformRead 0x0a000500 // background transform
+#define P_CS_TransformWrite 0x0a000510
+#define P_CS_MigrationRead 0x0a000600 // composite disk block migration
+#define P_CS_MigrationWrite 0x0a000610
+#define P_CS_SYNC_DISK 0x0a010000
+
+#define MSC_map_fd 0x010c00ac
+
+#define BSC_BASE 0x040C0000
+#define MSC_BASE 0x010C0000
+
+// Network related codes
+#define BSC_recvmsg 0x040C006C
+#define BSC_sendmsg 0x040C0070
+#define BSC_recvfrom 0x040C0074
+#define BSC_accept 0x040C0078
+#define BSC_select 0x040C0174
+#define BSC_socket 0x040C0184
+#define BSC_connect 0x040C0188
+#define BSC_bind 0x040C01A0
+#define BSC_listen 0x040C01A8
+#define BSC_sendto 0x040C0214
+#define BSC_socketpair 0x040C021C
+#define BSC_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_write 0x040C0010
+#define BSC_open 0x040C0014
+#define BSC_close 0x040C0018
+#define BSC_link 0x040C0024
+#define BSC_unlink 0x040C0028
+#define BSC_chdir 0x040c0030
+#define BSC_fchdir 0x040c0034
+#define BSC_mknod 0x040C0038
+#define BSC_chmod 0x040C003C
+#define BSC_chown 0x040C0040
+#define BSC_getfsstat 0x040C0048
+#define BSC_access 0x040C0084
+#define BSC_chflags 0x040C0088
+#define BSC_fchflags 0x040C008C
+#define BSC_sync 0x040C0090
+#define BSC_dup 0x040C00A4
+#define BSC_ioctl 0x040C00D8
+#define BSC_revoke 0x040C00E0
+#define BSC_symlink 0x040C00E4
+#define BSC_readlink 0x040C00E8
+#define BSC_execve 0x040C00EC
+#define BSC_umask 0x040C00F0
+#define BSC_chroot 0x040C00F4
+#define BSC_msync 0x040C0104
+#define BSC_dup2 0x040C0168
+#define BSC_fcntl 0x040C0170
+#define BSC_fsync 0x040C017C
+#define BSC_readv 0x040C01E0
+#define BSC_writev 0x040C01E4
+#define BSC_fchown 0x040C01EC
+#define BSC_fchmod 0x040C01F0
+#define BSC_rename 0x040C0200
+#define BSC_flock 0x040C020C
+#define BSC_mkfifo 0x040C0210
+#define BSC_mkdir 0x040C0220
+#define BSC_rmdir 0x040C0224
+#define BSC_utimes 0x040C0228
+#define BSC_futimes 0x040C022C
+#define BSC_pread 0x040C0264
+#define BSC_pwrite 0x040C0268
+#define BSC_statfs 0x040C0274
+#define BSC_fstatfs 0x040C0278
+#define BSC_unmount 0x040C027C
+#define BSC_mount 0x040C029C
+#define BSC_fdatasync 0x040C02EC
+#define BSC_stat 0x040C02F0
+#define BSC_fstat 0x040C02F4
+#define BSC_lstat 0x040C02F8
+#define BSC_pathconf 0x040C02FC
+#define BSC_fpathconf 0x040C0300
+#define BSC_getdirentries 0x040C0310
+#define BSC_mmap 0x040c0314
+#define BSC_lseek 0x040c031c
+#define BSC_truncate 0x040C0320
+#define BSC_ftruncate 0x040C0324
+#define BSC_undelete 0x040C0334
+#define BSC_open_dprotected_np 0x040C0360
+#define BSC_getattrlist 0x040C0370
+#define BSC_setattrlist 0x040C0374
+#define BSC_getdirentriesattr 0x040C0378
+#define BSC_exchangedata 0x040C037C
+#define BSC_checkuseraccess 0x040C0380
+#define BSC_searchfs 0x040C0384
+#define BSC_delete 0x040C0388
+#define BSC_copyfile 0x040C038C
+#define BSC_fgetattrlist 0x040C0390
+#define BSC_fsetattrlist 0x040C0394
+#define BSC_getxattr 0x040C03A8
+#define BSC_fgetxattr 0x040C03AC
+#define BSC_setxattr 0x040C03B0
+#define BSC_fsetxattr 0x040C03B4
+#define BSC_removexattr 0x040C03B8
+#define BSC_fremovexattr 0x040C03BC
+#define BSC_listxattr 0x040C03C0
+#define BSC_flistxattr 0x040C03C4
+#define BSC_fsctl 0x040C03C8
+#define BSC_posix_spawn 0x040C03D0
+#define BSC_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_chmod_extended 0x040C0468
+#define BSC_fchmod_extended 0x040C046C
+#define BSC_access_extended 0x040C0470
+#define BSC_mkfifo_extended 0x040C048C
+#define BSC_mkdir_extended 0x040C0490
+#define BSC_aio_fsync 0x040C04E4
+#define BSC_aio_return 0x040C04E8
+#define BSC_aio_suspend 0x040C04EC
+#define BSC_aio_cancel 0x040C04F0
+#define BSC_aio_error 0x040C04F4
+#define BSC_aio_read 0x040C04F8
+#define BSC_aio_write 0x040C04FC
+#define BSC_lio_listio 0x040C0500
+#define BSC_sendfile 0x040C0544
+#define BSC_stat64 0x040C0548
+#define BSC_fstat64 0x040C054C
+#define BSC_lstat64 0x040C0550
+#define BSC_stat64_extended 0x040C0554
+#define BSC_lstat64_extended 0x040C0558
+#define BSC_fstat64_extended 0x040C055C
+#define BSC_getdirentries64 0x040C0560
+#define BSC_statfs64 0x040C0564
+#define BSC_fstatfs64 0x040C0568
+#define BSC_getfsstat64 0x040C056C
+#define BSC_pthread_chdir 0x040C0570
+#define BSC_pthread_fchdir 0x040C0574
+#define BSC_lchown 0x040C05B0
+
+#define BSC_read_nocancel 0x040c0630
+#define BSC_write_nocancel 0x040c0634
+#define BSC_open_nocancel 0x040c0638
+#define BSC_close_nocancel 0x040c063c
+#define BSC_msync_nocancel 0x040c0654
+#define BSC_fcntl_nocancel 0x040c0658
+#define BSC_select_nocancel 0x040c065c
+#define BSC_fsync_nocancel 0x040c0660
+#define BSC_readv_nocancel 0x040c066c
+#define BSC_writev_nocancel 0x040c0670
+#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 BSC_pwrite_extended 0x040e0268
+#define BSC_mmap_extended 0x040e0314
+#define BSC_mmap_extended2 0x040f0314
+
+// Carbon File Manager support
+#define FILEMGR_PBGETCATALOGINFO 0x1e000020
+#define FILEMGR_PBGETCATALOGINFOBULK 0x1e000024
+#define FILEMGR_PBCREATEFILEUNICODE 0x1e000028
+#define FILEMGR_PBCREATEDIRECTORYUNICODE 0x1e00002c
+#define FILEMGR_PBCREATEFORK 0x1e000030
+#define FILEMGR_PBDELETEFORK 0x1e000034
+#define FILEMGR_PBITERATEFORK 0x1e000038
+#define FILEMGR_PBOPENFORK 0x1e00003c
+#define FILEMGR_PBREADFORK 0x1e000040
+#define FILEMGR_PBWRITEFORK 0x1e000044
+#define FILEMGR_PBALLOCATEFORK 0x1e000048
+#define FILEMGR_PBDELETEOBJECT 0x1e00004c
+#define FILEMGR_PBEXCHANGEOBJECT 0x1e000050
+#define FILEMGR_PBGETFORKCBINFO 0x1e000054
+#define FILEMGR_PBGETVOLUMEINFO 0x1e000058
+#define FILEMGR_PBMAKEFSREF 0x1e00005c
+#define FILEMGR_PBMAKEFSREFUNICODE 0x1e000060
+#define FILEMGR_PBMOVEOBJECT 0x1e000064
+#define FILEMGR_PBOPENITERATOR 0x1e000068
+#define FILEMGR_PBRENAMEUNICODE 0x1e00006c
+#define FILEMGR_PBSETCATALOGINFO 0x1e000070
+#define FILEMGR_PBSETVOLUMEINFO 0x1e000074
+#define FILEMGR_FSREFMAKEPATH 0x1e000078
+#define FILEMGR_FSPATHMAKEREF 0x1e00007c
+
+#define FILEMGR_PBGETCATINFO 0x1e010000
+#define FILEMGR_PBGETCATINFOLITE 0x1e010004
+#define FILEMGR_PBHGETFINFO 0x1e010008
+#define FILEMGR_PBXGETVOLINFO 0x1e01000c
+#define FILEMGR_PBHCREATE 0x1e010010
+#define FILEMGR_PBHOPENDF 0x1e010014
+#define FILEMGR_PBHOPENRF 0x1e010018
+#define FILEMGR_PBHGETDIRACCESS 0x1e01001c
+#define FILEMGR_PBHSETDIRACCESS 0x1e010020
+#define FILEMGR_PBHMAPID 0x1e010024
+#define FILEMGR_PBHMAPNAME 0x1e010028
+#define FILEMGR_PBCLOSE 0x1e01002c
+#define FILEMGR_PBFLUSHFILE 0x1e010030
+#define FILEMGR_PBGETEOF 0x1e010034
+#define FILEMGR_PBSETEOF 0x1e010038
+#define FILEMGR_PBGETFPOS 0x1e01003c
+#define FILEMGR_PBREAD 0x1e010040
+#define FILEMGR_PBWRITE 0x1e010044
+#define FILEMGR_PBGETFCBINFO 0x1e010048
+#define FILEMGR_PBSETFINFO 0x1e01004c
+#define FILEMGR_PBALLOCATE 0x1e010050
+#define FILEMGR_PBALLOCCONTIG 0x1e010054
+#define FILEMGR_PBSETFPOS 0x1e010058
+#define FILEMGR_PBSETCATINFO 0x1e01005c
+#define FILEMGR_PBGETVOLPARMS 0x1e010060
+#define FILEMGR_PBSETVINFO 0x1e010064
+#define FILEMGR_PBMAKEFSSPEC 0x1e010068
+#define FILEMGR_PBHGETVINFO 0x1e01006c
+#define FILEMGR_PBCREATEFILEIDREF 0x1e010070
+#define FILEMGR_PBDELETEFILEIDREF 0x1e010074
+#define FILEMGR_PBRESOLVEFILEIDREF 0x1e010078
+#define FILEMGR_PBFLUSHVOL 0x1e01007c
+#define FILEMGR_PBHRENAME 0x1e010080
+#define FILEMGR_PBCATMOVE 0x1e010084
+#define FILEMGR_PBEXCHANGEFILES 0x1e010088
+#define FILEMGR_PBHDELETE 0x1e01008c
+#define FILEMGR_PBDIRCREATE 0x1e010090
+#define FILEMGR_PBCATSEARCH 0x1e010094
+#define FILEMGR_PBHSETFLOCK 0x1e010098
+#define FILEMGR_PBHRSTFLOCK 0x1e01009c
+#define FILEMGR_PBLOCKRANGE 0x1e0100a0
+#define FILEMGR_PBUNLOCKRANGE 0x1e0100a4
+
+
+#define FILEMGR_CLASS 0x1e
+#define FILEMGR_BASE 0x1e000000
+
+#define FMT_DEFAULT 0
+#define FMT_FD 1
+#define FMT_FD_IO 2
+#define FMT_FD_2 3
+#define FMT_SOCKET 4
+#define FMT_PGIN 5
+#define FMT_PGOUT 6
+#define FMT_CACHEHIT 7
+#define FMT_DISKIO 8
+#define FMT_LSEEK 9
+#define FMT_PREAD 10
+#define FMT_FTRUNC 11
+#define FMT_TRUNC 12
+#define FMT_SELECT 13
+#define FMT_OPEN 14
+#define FMT_AIO_FSYNC 15
+#define FMT_AIO_RETURN 16
+#define FMT_AIO_SUSPEND 17
+#define FMT_AIO_CANCEL 18
+#define FMT_AIO 19
+#define FMT_LIO_LISTIO 20
+#define FMT_MSYNC 21
+#define FMT_FCNTL 22
+#define FMT_ACCESS 23
+#define FMT_CHMOD 24
+#define FMT_FCHMOD 25
+#define FMT_CHMOD_EXT 26
+#define FMT_FCHMOD_EXT 27
+#define FMT_CHFLAGS 28
+#define FMT_FCHFLAGS 29
+#define FMT_IOCTL 30
+#define FMT_MMAP 31
+#define FMT_UMASK 32
+#define FMT_SENDFILE 33
+#define FMT_IOCTL_SYNC 34
+#define FMT_MOUNT 35
+#define FMT_UNMOUNT 36
+#define FMT_DISKIO_CS 37
+#define FMT_SYNC_DISK_CS 38
+#define FMT_IOCTL_UNMAP 39
+#define FMT_UNMAP_INFO 40
+#define FMT_HFS_update 41
+#define FMT_FLOCK 42
+
+#define MAX_BSD_SYSCALL 512
+
+struct bsd_syscall {
+ char *sc_name;
+ int sc_format;
+} bsd_syscalls[MAX_BSD_SYSCALL];
+
+
+int bsd_syscall_types[] = {
+ BSC_recvmsg,
+ BSC_recvmsg_nocancel,
+ BSC_sendmsg,
+ BSC_sendmsg_nocancel,
+ BSC_recvfrom,
+ BSC_recvfrom_nocancel,
+ BSC_accept,
+ BSC_accept_nocancel,
+ BSC_select,
+ BSC_select_nocancel,
+ BSC_socket,
+ BSC_connect,
+ BSC_connect_nocancel,
+ BSC_bind,
+ BSC_listen,
+ BSC_sendto,
+ BSC_sendto_nocancel,
+ BSC_socketpair,
+ BSC_read,
+ BSC_read_nocancel,
+ BSC_write,
+ BSC_write_nocancel,
+ BSC_open,
+ BSC_open_nocancel,
+ BSC_close,
+ BSC_close_nocancel,
+ BSC_link,
+ BSC_unlink,
+ BSC_chdir,
+ BSC_fchdir,
+ BSC_mknod,
+ BSC_chmod,
+ BSC_chown,
+ BSC_access,
+ BSC_chflags,
+ BSC_fchflags,
+ BSC_sync,
+ BSC_dup,
+ BSC_revoke,
+ BSC_symlink,
+ BSC_readlink,
+ BSC_exit,
+ BSC_execve,
+ BSC_posix_spawn,
+ BSC_umask,
+ BSC_chroot,
+ BSC_dup2,
+ BSC_fsync,
+ BSC_fsync_nocancel,
+ BSC_readv,
+ BSC_readv_nocancel,
+ BSC_writev,
+ BSC_writev_nocancel,
+ BSC_fchown,
+ BSC_fchmod,
+ BSC_rename,
+ BSC_mkfifo,
+ BSC_mkdir,
+ BSC_rmdir,
+ BSC_utimes,
+ BSC_futimes,
+ BSC_pread,
+ BSC_pread_nocancel,
+ BSC_pwrite,
+ BSC_pwrite_nocancel,
+ BSC_statfs,
+ BSC_fstatfs,
+ BSC_fdatasync,
+ BSC_stat,
+ BSC_fstat,
+ BSC_lstat,
+ BSC_mount,
+ BSC_unmount,
+ BSC_pathconf,
+ BSC_fpathconf,
+ BSC_getdirentries,
+ BSC_mmap,
+ BSC_lseek,
+ BSC_truncate,
+ BSC_ftruncate,
+ BSC_flock,
+ BSC_undelete,
+ BSC_open_dprotected_np,
+ BSC_getattrlist,
+ BSC_setattrlist,
+ BSC_fgetattrlist,
+ BSC_fsetattrlist,
+ BSC_getdirentriesattr,
+ BSC_exchangedata,
+ BSC_checkuseraccess,
+ BSC_searchfs,
+ BSC_delete,
+ BSC_copyfile,
+ BSC_getxattr,
+ BSC_fgetxattr,
+ BSC_setxattr,
+ BSC_fsetxattr,
+ BSC_removexattr,
+ BSC_fremovexattr,
+ BSC_listxattr,
+ BSC_flistxattr,
+ BSC_fsctl,
+ BSC_ffsctl,
+ BSC_open_extended,
+ BSC_umask_extended,
+ BSC_stat_extended,
+ BSC_lstat_extended,
+ BSC_fstat_extended,
+ BSC_chmod_extended,
+ BSC_fchmod_extended,
+ BSC_access_extended,
+ BSC_mkfifo_extended,
+ BSC_mkdir_extended,
+ BSC_aio_fsync,
+ BSC_aio_return,
+ BSC_aio_suspend,
+ BSC_aio_suspend_nocancel,
+ BSC_aio_cancel,
+ BSC_aio_error,
+ BSC_aio_read,
+ BSC_aio_write,
+ BSC_lio_listio,
+ BSC_lchown,
+ BSC_sendfile,
+ BSC_msync,
+ BSC_msync_nocancel,
+ BSC_fcntl,
+ BSC_fcntl_nocancel,
+ BSC_ioctl,
+ BSC_stat64,
+ BSC_fstat64,
+ BSC_lstat64,
+ BSC_stat64_extended,
+ BSC_lstat64_extended,
+ BSC_fstat64_extended,
+ BSC_getdirentries64,
+ BSC_statfs64,
+ BSC_fstatfs64,
+ BSC_pthread_chdir,
+ BSC_pthread_fchdir,
+ BSC_getfsstat,
+ BSC_getfsstat64,
+ BSC_guarded_open_np,
+ BSC_guarded_close_np,
+ BSC_fsgetpath,
+ 0
+};
+
+
+#define MAX_FILEMGR 512
+
+struct filemgr_call {
+ char *fm_name;
+} filemgr_calls[MAX_FILEMGR];
+
+
+int filemgr_call_types[] = {
+ FILEMGR_PBGETCATALOGINFO,
+ FILEMGR_PBGETCATALOGINFOBULK,
+ FILEMGR_PBCREATEFILEUNICODE,
+ FILEMGR_PBCREATEDIRECTORYUNICODE,
+ FILEMGR_PBCREATEFORK,
+ FILEMGR_PBDELETEFORK,
+ FILEMGR_PBITERATEFORK,
+ FILEMGR_PBOPENFORK,
+ FILEMGR_PBREADFORK,
+ FILEMGR_PBWRITEFORK,
+ FILEMGR_PBALLOCATEFORK,
+ FILEMGR_PBDELETEOBJECT,
+ FILEMGR_PBEXCHANGEOBJECT,
+ FILEMGR_PBGETFORKCBINFO,
+ FILEMGR_PBGETVOLUMEINFO,
+ FILEMGR_PBMAKEFSREF,
+ FILEMGR_PBMAKEFSREFUNICODE,
+ FILEMGR_PBMOVEOBJECT,
+ FILEMGR_PBOPENITERATOR,
+ FILEMGR_PBRENAMEUNICODE,
+ FILEMGR_PBSETCATALOGINFO,
+ FILEMGR_PBSETVOLUMEINFO,
+ FILEMGR_FSREFMAKEPATH,
+ FILEMGR_FSPATHMAKEREF,
+
+ FILEMGR_PBGETCATINFO,
+ FILEMGR_PBGETCATINFOLITE,
+ FILEMGR_PBHGETFINFO,
+ FILEMGR_PBXGETVOLINFO,
+ FILEMGR_PBHCREATE,
+ FILEMGR_PBHOPENDF,
+ FILEMGR_PBHOPENRF,
+ FILEMGR_PBHGETDIRACCESS,
+ FILEMGR_PBHSETDIRACCESS,
+ FILEMGR_PBHMAPID,
+ FILEMGR_PBHMAPNAME,
+ FILEMGR_PBCLOSE,
+ FILEMGR_PBFLUSHFILE,
+ FILEMGR_PBGETEOF,
+ FILEMGR_PBSETEOF,
+ FILEMGR_PBGETFPOS,
+ FILEMGR_PBREAD,
+ FILEMGR_PBWRITE,
+ FILEMGR_PBGETFCBINFO,
+ FILEMGR_PBSETFINFO,
+ FILEMGR_PBALLOCATE,
+ FILEMGR_PBALLOCCONTIG,
+ FILEMGR_PBSETFPOS,
+ FILEMGR_PBSETCATINFO,
+ FILEMGR_PBGETVOLPARMS,
+ FILEMGR_PBSETVINFO,
+ FILEMGR_PBMAKEFSSPEC,
+ FILEMGR_PBHGETVINFO,
+ FILEMGR_PBCREATEFILEIDREF,
+ FILEMGR_PBDELETEFILEIDREF,
+ FILEMGR_PBRESOLVEFILEIDREF,
+ FILEMGR_PBFLUSHVOL,
+ FILEMGR_PBHRENAME,
+ FILEMGR_PBCATMOVE,
+ FILEMGR_PBEXCHANGEFILES,
+ FILEMGR_PBHDELETE,
+ FILEMGR_PBDIRCREATE,
+ FILEMGR_PBCATSEARCH,
+ FILEMGR_PBHSETFLOCK,
+ FILEMGR_PBHRSTFLOCK,
+ FILEMGR_PBLOCKRANGE,
+ FILEMGR_PBUNLOCKRANGE,
+ 0
+};
+
+
+
+#define MAX_PIDS 256
+int pids[MAX_PIDS];
+
+int num_of_pids = 0;
+int exclude_pids = 0;
+int exclude_default_pids = 1;
+
+
+struct kinfo_proc *kp_buffer = 0;
+int kp_nentries = 0;
+
+#define EVENT_BASE 60000
+
+int num_events = EVENT_BASE;
+
+
+#define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
+#define DBG_FUNC_MASK 0xfffffffc
+
+double divisor = 0.0; /* Trace divisor converts to microseconds */
+
+int mib[6];
+size_t needed;
+char *my_buffer;
+
+kbufinfo_t bufinfo = {0, 0, 0, 0, 0};
+
+
+/* defines for tracking file descriptor state */
+#define FS_USAGE_FD_SETSIZE 256 /* Initial number of file descriptors per
+ thread that we will track */
+
+#define FS_USAGE_NFDBITS (sizeof (unsigned long) * 8)
+#define FS_USAGE_NFDBYTES(n) (((n) / FS_USAGE_NFDBITS) * sizeof (unsigned long))
+
+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;
+
+uint64_t sample_TOD_secs;
+uint32_t sample_TOD_usecs;
+
+double bias_now = 0.0;
+double start_time = 0.0;
+double end_time = 999999999999.9;
+
+
+void set_numbufs();
+void set_filter();
+void set_init();
+void set_enable();
+void sample_sc();
+int quit();
+
+/*
+ * signal handlers
+ */
+
+void leave() /* exit under normal conditions -- INT handler */
+{
+ int i;
+ void set_enable();
+ void set_pidcheck();
+ void set_pidexclude();
+ void set_remove();
+
+ fflush(0);
+
+ set_enable(0);
+
+ if (exclude_pids == 0) {
+ for (i = 0; i < num_of_pids; i++)
+ set_pidcheck(pids[i], 0);
+ }
+ else {
+ for (i = 0; i < num_of_pids; i++)
+ set_pidexclude(pids[i], 0);
+ }
+ set_remove();
+
+ exit(0);
+}
+
+
+int
+quit(s)
+char *s;
+{
+ if (trace_enabled)
+ set_enable(0);
+
+ /*
+ * This flag is turned off when calling
+ * quit() due to a set_remove() failure.
+ */
+ if (set_remove_flag)
+ set_remove();
+
+ fprintf(stderr, "fs_usage: ");
+ if (s)
+ fprintf(stderr, "%s", s);
+
+ exit(1);
+}
+
+
+void get_screenwidth()
+{
+ struct winsize size;
+
+ columns = MAXCOLS;
+
+ if (isatty(1)) {
+ if (ioctl(1, TIOCGWINSZ, &size) != -1) {
+ columns = size.ws_col;
+
+ if (columns > MAXWIDTH)
+ columns = MAXWIDTH;
+ }
+ }
+}
+
+
+void sigwinch()
+{
+ if (!wideflag)
+ get_screenwidth();
+}
+
+
+void getdivisor()
+{
+ struct mach_timebase_info mti;
+
+ mach_timebase_info(&mti);
+
+ divisor = ((double)mti.denom / (double)mti.numer) * 1000;
+}
+
+
+int
+exit_usage(char *myname) {
+
+ fprintf(stderr, "Usage: %s [-e] [-w] [-f mode] [-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 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");
+ fprintf(stderr, " pid selects process(s) to sample\n");
+ fprintf(stderr, " cmd selects process(s) matching command string to sample\n");
+ fprintf(stderr, "\n%s will handle a maximum list of %d pids.\n\n", myname, MAX_PIDS);
+ fprintf(stderr, "By default (no options) the following processes are excluded from the output:\n");
+ fprintf(stderr, "fs_usage, Terminal, telnetd, sshd, rlogind, tcsh, csh, sh\n\n");
+
+ exit(1);
+}
+
+
+int filemgr_index(type) {
+
+ if (type & 0x10000)
+ return (((type >> 2) & 0x3fff) + 256);
+
+ return (((type >> 2) & 0x3fff));
+}
+
+
+void init_tables(void)
+{ int i;
+ int type;
+ int code;
+
+
+ for (i = 0; i < MAX_BSD_SYSCALL; i++) {
+ bsd_syscalls[i].sc_name = NULL;
+ bsd_syscalls[i].sc_format = FMT_DEFAULT;
+ }
+
+ for (i = 0; i < MAX_FILEMGR; i++) {
+ filemgr_calls[i].fm_name = NULL;
+ }
+
+ for (i = 0; (type = bsd_syscall_types[i]); i++) {
+
+ code = BSC_INDEX(type);
+
+ if (code >= MAX_BSD_SYSCALL) {
+ printf("BSD syscall init (%x): type exceeds table size\n", type);
+ continue;
+ }
+ switch (type) {
+
+ case BSC_sendfile:
+ bsd_syscalls[code].sc_name = "sendfile";
+ bsd_syscalls[code].sc_format = FMT_FD; /* this should be changed to FMT_SENDFILE */
+ break; /* once we add an extended info trace event */
+
+ case BSC_recvmsg:
+ case BSC_recvmsg_nocancel:
+ bsd_syscalls[code].sc_name = "recvmsg";
+ bsd_syscalls[code].sc_format = FMT_FD_IO;
+ break;
+
+ case BSC_sendmsg:
+ case BSC_sendmsg_nocancel:
+ bsd_syscalls[code].sc_name = "sendmsg";
+ bsd_syscalls[code].sc_format = FMT_FD_IO;
+ break;
+
+ case BSC_recvfrom:
+ case BSC_recvfrom_nocancel:
+ bsd_syscalls[code].sc_name = "recvfrom";
+ bsd_syscalls[code].sc_format = FMT_FD_IO;
+ break;
+
+ case BSC_sendto:
+ case BSC_sendto_nocancel:
+ bsd_syscalls[code].sc_name = "sendto";
+ bsd_syscalls[code].sc_format = FMT_FD_IO;
+ break;
+
+ case BSC_select:
+ case BSC_select_nocancel:
+ bsd_syscalls[code].sc_name = "select";
+ bsd_syscalls[code].sc_format = FMT_SELECT;
+ break;
+
+ case BSC_accept:
+ case BSC_accept_nocancel:
+ bsd_syscalls[code].sc_name = "accept";
+ bsd_syscalls[code].sc_format = FMT_FD_2;
+ break;
+
+ case BSC_socket:
+ bsd_syscalls[code].sc_name = "socket";
+ bsd_syscalls[code].sc_format = FMT_SOCKET;
+ break;
+
+ case BSC_connect:
+ case BSC_connect_nocancel:
+ bsd_syscalls[code].sc_name = "connect";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_bind:
+ bsd_syscalls[code].sc_name = "bind";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_listen:
+ bsd_syscalls[code].sc_name = "listen";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_mmap:
+ bsd_syscalls[code].sc_name = "mmap";
+ bsd_syscalls[code].sc_format = FMT_MMAP;
+ break;
+
+ case BSC_socketpair:
+ bsd_syscalls[code].sc_name = "socketpair";
+ break;
+
+ case BSC_getxattr:
+ bsd_syscalls[code].sc_name = "getxattr";
+ break;
+
+ case BSC_setxattr:
+ bsd_syscalls[code].sc_name = "setxattr";
+ break;
+
+ case BSC_removexattr:
+ bsd_syscalls[code].sc_name = "removexattr";
+ break;
+
+ case BSC_listxattr:
+ bsd_syscalls[code].sc_name = "listxattr";
+ break;
+
+ case BSC_stat:
+ bsd_syscalls[code].sc_name = "stat";
+ break;
+
+ case BSC_stat64:
+ bsd_syscalls[code].sc_name = "stat64";
+ break;
+
+ case BSC_stat_extended:
+ bsd_syscalls[code].sc_name = "stat_extended";
+ break;
+
+ case BSC_stat64_extended:
+ bsd_syscalls[code].sc_name = "stat_extended64";
+ break;
+
+ case BSC_mount:
+ bsd_syscalls[code].sc_name = "mount";
+ bsd_syscalls[code].sc_format = FMT_MOUNT;
+ break;
+
+ case BSC_unmount:
+ bsd_syscalls[code].sc_name = "unmount";
+ bsd_syscalls[code].sc_format = FMT_UNMOUNT;
+ break;
+
+ case BSC_exit:
+ bsd_syscalls[code].sc_name = "exit";
+ break;
+
+ case BSC_execve:
+ bsd_syscalls[code].sc_name = "execve";
+ break;
+
+ case BSC_posix_spawn:
+ bsd_syscalls[code].sc_name = "posix_spawn";
+ break;
+
+ case BSC_open:
+ case BSC_open_nocancel:
+ bsd_syscalls[code].sc_name = "open";
+ bsd_syscalls[code].sc_format = FMT_OPEN;
+ break;
+
+ case BSC_open_extended:
+ bsd_syscalls[code].sc_name = "open_extended";
+ bsd_syscalls[code].sc_format = FMT_OPEN;
+ break;
+
+ case BSC_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;
+ break;
+
+ case BSC_dup2:
+ bsd_syscalls[code].sc_name = "dup2";
+ bsd_syscalls[code].sc_format = FMT_FD_2;
+ break;
+
+ case BSC_close:
+ case BSC_close_nocancel:
+ bsd_syscalls[code].sc_name = "close";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_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_format = FMT_FD_IO;
+ break;
+
+ case BSC_write:
+ case BSC_write_nocancel:
+ bsd_syscalls[code].sc_name = "write";
+ bsd_syscalls[code].sc_format = FMT_FD_IO;
+ break;
+
+ case BSC_fgetxattr:
+ bsd_syscalls[code].sc_name = "fgetxattr";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_fsetxattr:
+ bsd_syscalls[code].sc_name = "fsetxattr";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_fremovexattr:
+ bsd_syscalls[code].sc_name = "fremovexattr";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_flistxattr:
+ bsd_syscalls[code].sc_name = "flistxattr";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_fstat:
+ bsd_syscalls[code].sc_name = "fstat";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_fstat64:
+ bsd_syscalls[code].sc_name = "fstat64";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_fstat_extended:
+ bsd_syscalls[code].sc_name = "fstat_extended";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_fstat64_extended:
+ bsd_syscalls[code].sc_name = "fstat64_extended";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_lstat:
+ bsd_syscalls[code].sc_name = "lstat";
+ break;
+
+ case BSC_lstat64:
+ bsd_syscalls[code].sc_name = "lstat64";
+ break;
+
+ case BSC_lstat_extended:
+ bsd_syscalls[code].sc_name = "lstat_extended";
+ break;
+
+ case BSC_lstat64_extended:
+ bsd_syscalls[code].sc_name = "lstat_extended64";
+ break;
+
+ case BSC_link:
+ bsd_syscalls[code].sc_name = "link";
+ break;
+
+ case BSC_unlink:
+ bsd_syscalls[code].sc_name = "unlink";
+ break;
+
+ case BSC_mknod:
+ bsd_syscalls[code].sc_name = "mknod";
+ break;
+
+ case BSC_umask:
+ bsd_syscalls[code].sc_name = "umask";
+ bsd_syscalls[code].sc_format = FMT_UMASK;
+ break;
+
+ case BSC_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;
+ break;
+
+ case BSC_chmod_extended:
+ bsd_syscalls[code].sc_name = "chmod_extended";
+ bsd_syscalls[code].sc_format = FMT_CHMOD_EXT;
+ break;
+
+ case BSC_fchmod:
+ bsd_syscalls[code].sc_name = "fchmod";
+ bsd_syscalls[code].sc_format = FMT_FCHMOD;
+ break;
+
+ case BSC_fchmod_extended:
+ bsd_syscalls[code].sc_name = "fchmod_extended";
+ bsd_syscalls[code].sc_format = FMT_FCHMOD_EXT;
+ break;
+
+ case BSC_chown:
+ bsd_syscalls[code].sc_name = "chown";
+ break;
+
+ case BSC_lchown:
+ bsd_syscalls[code].sc_name = "lchown";
+ break;
+
+ case BSC_fchown:
+ bsd_syscalls[code].sc_name = "fchown";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_access:
+ bsd_syscalls[code].sc_name = "access";
+ bsd_syscalls[code].sc_format = FMT_ACCESS;
+ break;
+
+ case BSC_access_extended:
+ bsd_syscalls[code].sc_name = "access_extended";
+ break;
+
+ case BSC_chdir:
+ bsd_syscalls[code].sc_name = "chdir";
+ break;
+
+ case BSC_pthread_chdir:
+ bsd_syscalls[code].sc_name = "pthread_chdir";
+ break;
+
+ case BSC_chroot:
+ bsd_syscalls[code].sc_name = "chroot";
+ break;
+
+ case BSC_utimes:
+ bsd_syscalls[code].sc_name = "utimes";
+ break;
+
+ case BSC_delete:
+ bsd_syscalls[code].sc_name = "delete-Carbon";
+ break;
+
+ case BSC_undelete:
+ bsd_syscalls[code].sc_name = "undelete";
+ break;
+
+ case BSC_revoke:
+ bsd_syscalls[code].sc_name = "revoke";
+ break;
+
+ case BSC_fsctl:
+ bsd_syscalls[code].sc_name = "fsctl";
+ break;
+
+ case BSC_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;
+ break;
+
+ case BSC_fchflags:
+ bsd_syscalls[code].sc_name = "fchflags";
+ bsd_syscalls[code].sc_format = FMT_FCHFLAGS;
+ break;
+
+ case BSC_fchdir:
+ bsd_syscalls[code].sc_name = "fchdir";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_pthread_fchdir:
+ bsd_syscalls[code].sc_name = "pthread_fchdir";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_futimes:
+ bsd_syscalls[code].sc_name = "futimes";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_sync:
+ bsd_syscalls[code].sc_name = "sync";
+ break;
+
+ case BSC_symlink:
+ bsd_syscalls[code].sc_name = "symlink";
+ break;
+
+ case BSC_readlink:
+ bsd_syscalls[code].sc_name = "readlink";
+ break;
+
+ case BSC_fsync:
+ case BSC_fsync_nocancel:
+ bsd_syscalls[code].sc_name = "fsync";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_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_FD_IO;
+ break;
+
+ case BSC_writev:
+ case BSC_writev_nocancel:
+ bsd_syscalls[code].sc_name = "writev";
+ bsd_syscalls[code].sc_format = FMT_FD_IO;
+ break;
+
+ case BSC_pread:
+ case BSC_pread_nocancel:
+ bsd_syscalls[code].sc_name = "pread";
+ bsd_syscalls[code].sc_format = FMT_PREAD;
+ break;
+
+ case BSC_pwrite:
+ case BSC_pwrite_nocancel:
+ bsd_syscalls[code].sc_name = "pwrite";
+ bsd_syscalls[code].sc_format = FMT_PREAD;
+ break;
+
+ case BSC_mkdir:
+ bsd_syscalls[code].sc_name = "mkdir";
+ break;
+
+ case BSC_mkdir_extended:
+ bsd_syscalls[code].sc_name = "mkdir_extended";
+ break;
+
+ case BSC_mkfifo:
+ bsd_syscalls[code].sc_name = "mkfifo";
+ break;
+
+ case BSC_mkfifo_extended:
+ bsd_syscalls[code].sc_name = "mkfifo_extended";
+ break;
+
+ case BSC_rmdir:
+ bsd_syscalls[code].sc_name = "rmdir";
+ break;
+
+ case BSC_statfs:
+ bsd_syscalls[code].sc_name = "statfs";
+ break;
+
+ case BSC_statfs64:
+ bsd_syscalls[code].sc_name = "statfs64";
+ break;
+
+ case BSC_getfsstat:
+ bsd_syscalls[code].sc_name = "getfsstat";
+ break;
+
+ case BSC_getfsstat64:
+ bsd_syscalls[code].sc_name = "getfsstat64";
+ break;
+
+ case BSC_fstatfs:
+ bsd_syscalls[code].sc_name = "fstatfs";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_fstatfs64:
+ bsd_syscalls[code].sc_name = "fstatfs64";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_pathconf:
+ bsd_syscalls[code].sc_name = "pathconf";
+ break;
+
+ case BSC_fpathconf:
+ bsd_syscalls[code].sc_name = "fpathconf";
+ bsd_syscalls[code].sc_format = FMT_FD;
+ break;
+
+ case BSC_getdirentries:
+ bsd_syscalls[code].sc_name = "getdirentries";
+ bsd_syscalls[code].sc_format = FMT_FD_IO;
+ break;
+
+ case BSC_getdirentries64:
+ bsd_syscalls[code].sc_name = "getdirentries64";
+ bsd_syscalls[code].sc_format = FMT_FD_IO;
+ break;
+
+ case BSC_lseek:
+ bsd_syscalls[code].sc_name = "lseek";
+ bsd_syscalls[code].sc_format = FMT_LSEEK;
+ break;
+
+ case BSC_truncate:
+ bsd_syscalls[code].sc_name = "truncate";
+ bsd_syscalls[code].sc_format = FMT_TRUNC;
+ break;
+
+ case BSC_ftruncate:
+ bsd_syscalls[code].sc_name = "ftruncate";
+ bsd_syscalls[code].sc_format = FMT_FTRUNC;
+ break;
+
+ case BSC_flock:
+ bsd_syscalls[code].sc_name = "flock";
+ bsd_syscalls[code].sc_format = FMT_FLOCK;
+ break;
+
+ case BSC_getattrlist:
+ bsd_syscalls[code].sc_name = "getattrlist";
+ break;
+
+ case BSC_setattrlist:
+ 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;
+ break;
+
+ case BSC_exchangedata:
+ bsd_syscalls[code].sc_name = "exchangedata";
+ break;
+
+ case BSC_rename:
+ bsd_syscalls[code].sc_name = "rename";
+ break;
+
+ case BSC_copyfile:
+ bsd_syscalls[code].sc_name = "copyfile";
+ break;
+
+ case BSC_checkuseraccess:
+ bsd_syscalls[code].sc_name = "checkuseraccess";
+ break;
+
+ case BSC_searchfs:
+ bsd_syscalls[code].sc_name = "searchfs";
+ break;
+
+ case BSC_aio_fsync:
+ bsd_syscalls[code].sc_name = "aio_fsync";
+ bsd_syscalls[code].sc_format = FMT_AIO_FSYNC;
+ break;
+
+ case BSC_aio_return:
+ bsd_syscalls[code].sc_name = "aio_return";
+ bsd_syscalls[code].sc_format = FMT_AIO_RETURN;
+ break;
+
+ case BSC_aio_suspend:
+ case BSC_aio_suspend_nocancel:
+ bsd_syscalls[code].sc_name = "aio_suspend";
+ bsd_syscalls[code].sc_format = FMT_AIO_SUSPEND;
+ break;
+
+ case BSC_aio_cancel:
+ bsd_syscalls[code].sc_name = "aio_cancel";
+ bsd_syscalls[code].sc_format = FMT_AIO_CANCEL;
+ break;
+
+ case BSC_aio_error:
+ bsd_syscalls[code].sc_name = "aio_error";
+ bsd_syscalls[code].sc_format = FMT_AIO;
+ break;
+
+ case BSC_aio_read:
+ bsd_syscalls[code].sc_name = "aio_read";
+ bsd_syscalls[code].sc_format = FMT_AIO;
+ break;
+
+ case BSC_aio_write:
+ bsd_syscalls[code].sc_name = "aio_write";
+ bsd_syscalls[code].sc_format = FMT_AIO;
+ break;
+
+ case BSC_lio_listio:
+ bsd_syscalls[code].sc_name = "lio_listio";
+ bsd_syscalls[code].sc_format = FMT_LIO_LISTIO;
+ break;
+
+ case BSC_msync:
+ case BSC_msync_nocancel:
+ bsd_syscalls[code].sc_name = "msync";
+ bsd_syscalls[code].sc_format = FMT_MSYNC;
+ break;
+
+ case BSC_fcntl:
+ case BSC_fcntl_nocancel:
+ bsd_syscalls[code].sc_name = "fcntl";
+ bsd_syscalls[code].sc_format = FMT_FCNTL;
+ break;
+
+ case BSC_ioctl:
+ bsd_syscalls[code].sc_name = "ioctl";
+ bsd_syscalls[code].sc_format = FMT_IOCTL;
+ break;
+
+ case BSC_fsgetpath:
+ bsd_syscalls[code].sc_name = "fsgetpath";
+ break;
+ }
+ }
+
+ for (i = 0; (type = filemgr_call_types[i]); i++) {
+ char * p;
+
+ code = filemgr_index(type);
+
+ if (code >= MAX_FILEMGR) {
+ printf("FILEMGR call init (%x): type exceeds table size\n", type);
+ continue;
+ }
+ switch (type) {
+
+ case FILEMGR_PBGETCATALOGINFO:
+ p = "GetCatalogInfo";
+ break;
+
+ case FILEMGR_PBGETCATALOGINFOBULK:
+ p = "GetCatalogInfoBulk";
+ break;
+
+ case FILEMGR_PBCREATEFILEUNICODE:
+ p = "CreateFileUnicode";
+ break;
+
+ case FILEMGR_PBCREATEDIRECTORYUNICODE:
+ p = "CreateDirectoryUnicode";
+ break;
+
+ case FILEMGR_PBCREATEFORK:
+ p = "PBCreateFork";
+ break;
+
+ case FILEMGR_PBDELETEFORK:
+ p = "PBDeleteFork";
+ break;
+
+ case FILEMGR_PBITERATEFORK:
+ p = "PBIterateFork";
+ break;
+
+ case FILEMGR_PBOPENFORK:
+ p = "PBOpenFork";
+ break;
+
+ case FILEMGR_PBREADFORK:
+ p = "PBReadFork";
+ break;
+
+ case FILEMGR_PBWRITEFORK:
+ p = "PBWriteFork";
+ break;
+
+ case FILEMGR_PBALLOCATEFORK:
+ p = "PBAllocateFork";
+ break;
+
+ case FILEMGR_PBDELETEOBJECT:
+ p = "PBDeleteObject";
+ break;
+
+ case FILEMGR_PBEXCHANGEOBJECT:
+ p = "PBExchangeObject";
+ break;
+
+ case FILEMGR_PBGETFORKCBINFO:
+ p = "PBGetForkCBInfo";
+ break;
+
+ case FILEMGR_PBGETVOLUMEINFO:
+ p = "PBGetVolumeInfo";
+ break;
+
+ case FILEMGR_PBMAKEFSREF:
+ p = "PBMakeFSRef";
+ break;
+
+ case FILEMGR_PBMAKEFSREFUNICODE:
+ p = "PBMakeFSRefUnicode";
+ break;
+
+ case FILEMGR_PBMOVEOBJECT:
+ p = "PBMoveObject";
+ break;
+
+ case FILEMGR_PBOPENITERATOR:
+ p = "PBOpenIterator";
+ break;
+
+ case FILEMGR_PBRENAMEUNICODE:
+ p = "PBRenameUnicode";
+ break;
+
+ case FILEMGR_PBSETCATALOGINFO:
+ p = "SetCatalogInfo";
+ break;
+
+ case FILEMGR_PBSETVOLUMEINFO:
+ p = "SetVolumeInfo";
+ break;
+
+ case FILEMGR_FSREFMAKEPATH:
+ p = "FSRefMakePath";
+ break;
+
+ case FILEMGR_FSPATHMAKEREF:
+ p = "FSPathMakeRef";
+ break;
+
+ case FILEMGR_PBGETCATINFO:
+ p = "GetCatInfo";
+ break;
+
+ case FILEMGR_PBGETCATINFOLITE:
+ p = "GetCatInfoLite";
+ break;
+
+ case FILEMGR_PBHGETFINFO:
+ p = "PBHGetFInfo";
+ break;
+
+ case FILEMGR_PBXGETVOLINFO:
+ p = "PBXGetVolInfo";
+ break;
+
+ case FILEMGR_PBHCREATE:
+ p = "PBHCreate";
+ break;
+
+ case FILEMGR_PBHOPENDF:
+ p = "PBHOpenDF";
+ break;
+
+ case FILEMGR_PBHOPENRF:
+ p = "PBHOpenRF";
+ break;
+
+ case FILEMGR_PBHGETDIRACCESS:
+ p = "PBHGetDirAccess";
+ break;
+
+ case FILEMGR_PBHSETDIRACCESS:
+ p = "PBHSetDirAccess";
+ break;
+
+ case FILEMGR_PBHMAPID:
+ p = "PBHMapID";
+ break;
+
+ case FILEMGR_PBHMAPNAME:
+ p = "PBHMapName";
+ break;
+
+ case FILEMGR_PBCLOSE:
+ p = "PBClose";
+ break;
+
+ case FILEMGR_PBFLUSHFILE:
+ p = "PBFlushFile";
+ break;
+
+ case FILEMGR_PBGETEOF:
+ p = "PBGetEOF";
+ break;
+
+ case FILEMGR_PBSETEOF:
+ p = "PBSetEOF";
+ break;
+
+ case FILEMGR_PBGETFPOS:
+ p = "PBGetFPos";
+ break;
+
+ case FILEMGR_PBREAD:
+ p = "PBRead";
+ break;
+
+ case FILEMGR_PBWRITE:
+ p = "PBWrite";
+ break;
+
+ case FILEMGR_PBGETFCBINFO:
+ p = "PBGetFCBInfo";
+ break;
+
+ case FILEMGR_PBSETFINFO:
+ p = "PBSetFInfo";
+ break;
+
+ case FILEMGR_PBALLOCATE:
+ p = "PBAllocate";
+ break;
+
+ case FILEMGR_PBALLOCCONTIG:
+ p = "PBAllocContig";
+ break;
+
+ case FILEMGR_PBSETFPOS:
+ p = "PBSetFPos";
+ break;
+
+ case FILEMGR_PBSETCATINFO:
+ p = "PBSetCatInfo";
+ break;
+
+ case FILEMGR_PBGETVOLPARMS:
+ p = "PBGetVolParms";
+ break;
+
+ case FILEMGR_PBSETVINFO:
+ p = "PBSetVInfo";
+ break;
+
+ case FILEMGR_PBMAKEFSSPEC:
+ p = "PBMakeFSSpec";
+ break;
+
+ case FILEMGR_PBHGETVINFO:
+ p = "PBHGetVInfo";
+ break;
+
+ case FILEMGR_PBCREATEFILEIDREF:
+ p = "PBCreateFileIDRef";
+ break;
+
+ case FILEMGR_PBDELETEFILEIDREF:
+ p = "PBDeleteFileIDRef";
+ break;
+
+ case FILEMGR_PBRESOLVEFILEIDREF:
+ p = "PBResolveFileIDRef";
+ break;
+
+ case FILEMGR_PBFLUSHVOL:
+ p = "PBFlushVol";
+ break;
+
+ case FILEMGR_PBHRENAME:
+ p = "PBHRename";
+ break;
+
+ case FILEMGR_PBCATMOVE:
+ p = "PBCatMove";
+ break;
+
+ case FILEMGR_PBEXCHANGEFILES:
+ p = "PBExchangeFiles";
+ break;
+
+ case FILEMGR_PBHDELETE:
+ p = "PBHDelete";
+ break;
+
+ case FILEMGR_PBDIRCREATE:
+ p = "PBDirCreate";
+ break;
+
+ case FILEMGR_PBCATSEARCH:
+ p = "PBCatSearch";
+ break;
+
+ case FILEMGR_PBHSETFLOCK:
+ p = "PBHSetFlock";
+ break;
+
+ case FILEMGR_PBHRSTFLOCK:
+ p = "PBHRstFLock";
+ break;
+
+ case FILEMGR_PBLOCKRANGE:
+ p = "PBLockRange";
+ break;
+
+ case FILEMGR_PBUNLOCKRANGE:
+ p = "PBUnlockRange";
+ break;
+
+ default:
+ p = NULL;
+ break;
+ }
+ filemgr_calls[code].fm_name = p;
+ }
+}
+
+
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *myname = "fs_usage";
+ int i;
+ char ch;
+
+ time_t stop_at_time = 0;
+
+ if (0 != reexec_to_match_kernel()) {
+ fprintf(stderr, "Could not re-execute: %d\n", errno);
+ exit(1);
+ }
+ get_screenwidth();
+
+ /*
+ * get our name
+ */
+ if (argc > 0) {
+ if ((myname = rindex(argv[0], '/')) == 0)
+ myname = argv[0];
+ else
+ myname++;
+ }
+
+ while ((ch = getopt(argc, argv, "bewf:R:S:E:t:")) != EOF) {
+
+ switch(ch) {
+
+ case 'e':
+ exclude_pids = 1;
+ exclude_default_pids = 0;
+ break;
+
+ case 'w':
+ wideflag = 1;
+ if ((uint)columns < MAX_WIDE_MODE_COLS)
+ columns = MAX_WIDE_MODE_COLS;
+ break;
+
+ case 'f':
+ if (!strcmp(optarg, "network"))
+ filter_mode |= NETWORK_FILTER;
+ else if (!strcmp(optarg, "filesys"))
+ filter_mode |= FILESYS_FILTER;
+ else if (!strcmp(optarg, "cachehit"))
+ 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;
+ RAW_file = optarg;
+ break;
+
+ case 'S':
+ start_time = atof(optarg);
+ break;
+
+ case 'E':
+ end_time = atof(optarg);
+ break;
+
+ default:
+ exit_usage(myname);
+ }
+ }
+ if (!RAW_flag) {
+ if ( geteuid() != 0 ) {
+ fprintf(stderr, "'fs_usage' must be run as root...\n");
+ exit(1);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * when excluding, fs_usage should be the first in line for pids[]
+ *
+ * the !exclude_pids && argc == 0 catches the exclude_default_pids
+ * case below where exclude_pids is later set and the fs_usage PID
+ * needs to make it into pids[]
+ */
+ if (exclude_pids || (!exclude_pids && argc == 0)) {
+ if (num_of_pids < (MAX_PIDS - 1))
+ pids[num_of_pids++] = getpid();
+ }
+
+ /*
+ * If we process any list of pids/cmds, then turn off the defaults
+ */
+ if (argc > 0)
+ exclude_default_pids = 0;
+
+ while (argc > 0 && num_of_pids < (MAX_PIDS - 1)) {
+ select_pid_mode++;
+ argtopid(argv[0]);
+ argc--;
+ argv++;
+ }
+ /*
+ * Exclude a set of default pids
+ */
+ if (exclude_default_pids) {
+ argtopid("Terminal");
+ argtopid("telnetd");
+ argtopid("telnet");
+ argtopid("sshd");
+ argtopid("rlogind");
+ argtopid("tcsh");
+ argtopid("csh");
+ argtopid("sh");
+ exclude_pids = 1;
+ }
+#if 0
+ for (i = 0; i < num_of_pids; i++) {
+ if (exclude_pids)
+ fprintf(stderr, "exclude pid %d\n", pids[i]);
+ else
+ fprintf(stderr, "pid %d\n", pids[i]);
+ }
+#endif
+ if (!RAW_flag) {
+ struct sigaction osa;
+ int num_cpus;
+ size_t len;
+
+ /* set up signal handlers */
+ signal(SIGINT, leave);
+ signal(SIGQUIT, leave);
+
+ sigaction(SIGHUP, (struct sigaction *)NULL, &osa);
+
+ if (osa.sa_handler == SIG_DFL)
+ signal(SIGHUP, leave);
+ signal(SIGTERM, leave);
+ /*
+ * grab the number of cpus
+ */
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ mib[2] = 0;
+ len = sizeof(num_cpus);
+
+ sysctl(mib, 2, &num_cpus, &len, NULL, 0);
+ num_events = EVENT_BASE * num_cpus;
+ }
+ signal(SIGWINCH, sigwinch);
+
+ if ((my_buffer = malloc(num_events * sizeof(kd_buf))) == (char *)0)
+ quit("can't allocate memory for tracing info\n");
+
+ if (ReadSharedCacheMap("/var/db/dyld/dyld_shared_cache_i386.map", &framework32, "/var/db/dyld/dyld_shared_cache_i386")) {
+ ReadSharedCacheMap("/var/db/dyld/dyld_shared_cache_x86_64.map", &framework64, "/var/db/dyld/dyld_shared_cache_x86_64");
+ } else {
+ ReadSharedCacheMap("/var/db/dyld/dyld_shared_cache_ppc.map", &framework32, "/var/db/dyld/dyld_shared_cache_ppc");
+ ReadSharedCacheMap("/var/db/dyld/dyld_shared_cache_ppc64.map", &framework64, "/var/db/dyld/dyld_shared_cache_ppc64");
+ }
+ SortFrameworkAddresses();
+
+ cache_disk_names();
+
+ if (!RAW_flag) {
+
+ set_remove();
+ set_numbufs(num_events);
+ set_init();
+
+ if (exclude_pids == 0) {
+ for (i = 0; i < num_of_pids; i++)
+ set_pidcheck(pids[i], 1);
+ } else {
+ for (i = 0; i < num_of_pids; i++)
+ set_pidexclude(pids[i], 1);
+ }
+ if (select_pid_mode && !one_good_pid) {
+ /*
+ * An attempt to restrict output to a given
+ * pid or command has failed. Exit gracefully
+ */
+ set_remove();
+ exit_usage(myname);
+ }
+
+ set_filter();
+
+ set_enable(1);
+
+ init_arguments_buffer();
+ }
+ getdivisor();
+
+ init_tables();
+
+ /*
+ * main loop
+ */
+ while (stop_at_time == 0 || last_time < stop_at_time) {
+ if (!RAW_flag)
+ usleep(1000 * usleep_ms);
+
+ sample_sc();
+
+ last_time = time((long *)0);
+ }
+}
+
+
+void
+find_proc_names()
+{
+ size_t bufSize = 0;
+ struct kinfo_proc *kp;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_ALL;
+ mib[3] = 0;
+
+ if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0)
+ quit("trace facility failure, KERN_PROC_ALL\n");
+
+ if ((kp = (struct kinfo_proc *)malloc(bufSize)) == (struct kinfo_proc *)0)
+ quit("can't allocate memory for proc buffer\n");
+
+ if (sysctl(mib, 4, kp, &bufSize, NULL, 0) < 0)
+ quit("trace facility failure, KERN_PROC_ALL\n");
+
+ kp_nentries = bufSize/ sizeof(struct kinfo_proc);
+ kp_buffer = kp;
+}
+
+
+void
+set_enable(int val)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDENABLE; /* protocol */
+ mib[3] = val;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDENABLE\n");
+
+ if (val)
+ trace_enabled = 1;
+ else
+ trace_enabled = 0;
+}
+
+void
+set_numbufs(int nbufs)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETBUF;
+ mib[3] = nbufs;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDSETBUF\n");
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETUP;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+
+ if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDSETUP\n");
+}
+
+#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)
+{
+ kd_regtype kr;
+
+ kr.type = KDBG_TYPENONE;
+ kr.value1 = pid;
+ kr.value2 = on_off;
+ needed = sizeof(kd_regtype);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDPIDTR;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+
+ if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) {
+ if (on_off == 1)
+ fprintf(stderr, "pid %d does not exist\n", pid);
+ } else
+ one_good_pid++;
+}
+
+/*
+ * on_off == 0 turns off pid exclusion
+ * on_off == 1 turns on pid exclusion
+ */
+void
+set_pidexclude(int pid, int on_off)
+{
+ kd_regtype kr;
+
+ one_good_pid++;
+
+ kr.type = KDBG_TYPENONE;
+ kr.value1 = pid;
+ kr.value2 = on_off;
+ needed = sizeof(kd_regtype);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDPIDEX;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+
+ if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) {
+ if (on_off == 1)
+ fprintf(stderr, "pid %d does not exist\n", pid);
+ }
+}
+
+void
+get_bufinfo(kbufinfo_t *val)
+{
+ needed = sizeof (*val);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDGETBUF;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+
+ if (sysctl(mib, 3, val, &needed, 0, 0) < 0)
+ quit("trace facility failure, KERN_KDGETBUF\n");
+
+}
+
+void
+set_remove()
+{
+ errno = 0;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDREMOVE; /* protocol */
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+
+ if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0) {
+ set_remove_flag = 0;
+
+ if (errno == EBUSY)
+ quit("the trace facility is currently in use...\n fs_usage, sc_usage, and latency use this feature.\n\n");
+ else
+ quit("trace facility failure, KERN_KDREMOVE\n");
+ }
+}
+
+void
+set_init()
+{ kd_regtype kr;
+
+ kr.type = KDBG_RANGETYPE;
+ kr.value1 = 0;
+ kr.value2 = -1;
+ needed = sizeof(kd_regtype);
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETREG;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+
+ if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDSETREG\n");
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETUP;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+
+ if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDSETUP\n");
+}
+
+
+void
+sample_sc()
+{
+ kd_buf *kd;
+ int i, count;
+ size_t needed;
+ uint32_t my_buffer_size = 0;
+
+ if (!RAW_flag)
+ get_bufinfo(&bufinfo);
+ else
+ my_buffer_size = num_events * sizeof(kd_buf);
+
+ if (need_new_map) {
+ read_command_map();
+ need_new_map = 0;
+ }
+ if (!RAW_flag) {
+ needed = bufinfo.nkdbufs * sizeof(kd_buf);
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDREADTR;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+
+ if (sysctl(mib, 3, my_buffer, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDREADTR\n");
+ count = needed;
+
+ if (count > (num_events / 8)) {
+ if (usleep_ms > USLEEP_BEHIND)
+ usleep_ms = USLEEP_BEHIND;
+ else if (usleep_ms > USLEEP_MIN)
+ usleep_ms /= 2;
+
+ } else if (count < (num_events / 16)) {
+ if (usleep_ms < USLEEP_MAX)
+ usleep_ms *= 2;
+ }
+
+ if (bufinfo.flags & KDBG_WRAPPED) {
+ fprintf(stderr, "fs_usage: buffer overrun, events generated too quickly: %d\n", count);
+
+ delete_all_events();
+
+ need_new_map = 1;
+
+ set_enable(0);
+ set_enable(1);
+ }
+ } else {
+ int bytes_read;
+
+ if ((bytes_read = read(RAW_fd, my_buffer, my_buffer_size)) < sizeof(kd_buf))
+ exit(0);
+ count = bytes_read / sizeof(kd_buf);
+ }
+ kd = (kd_buf *)my_buffer;
+#if 0
+ fprintf(stderr, "READTR returned %d items\n", count);
+#endif
+ for (i = 0; i < count; i++) {
+ uint32_t debugid;
+ uintptr_t thread;
+ int type;
+ int index;
+ uintptr_t *sargptr;
+ uint64_t now;
+ long long l_usecs;
+ int secs;
+ long curr_time;
+ th_info_t ti;
+ struct diskio *dio;
+
+
+ thread = kd[i].arg5;
+ debugid = kd[i].debugid;
+ type = kd[i].debugid & DBG_FUNC_MASK;
+
+ now = kdbg_get_timestamp(&kd[i]);
+
+ if (i == 0 && !RAW_flag) {
+
+ curr_time = time((long *)0);
+ /*
+ * Compute bias seconds after each trace buffer read.
+ * This helps resync timestamps with the system clock
+ * in the event of a system sleep.
+ */
+ if (bias_secs == 0 || curr_time < last_time || curr_time > (last_time + 2)) {
+ l_usecs = (long long)(now / divisor);
+ secs = l_usecs / 1000000;
+ bias_secs = curr_time - secs;
+ }
+ }
+ if (RAW_flag && bias_now == 0.0)
+ bias_now = now;
+
+ if ((type & P_DISKIO_MASK) == P_DISKIO) {
+ insert_diskio(type, kd[i].arg1, kd[i].arg2, kd[i].arg3, kd[i].arg4, thread, (double)now);
+ continue;
+ }
+ if ((type & P_DISKIO_MASK) == P_DISKIO_DONE) {
+ if ((dio = complete_diskio(kd[i].arg1, kd[i].arg4, kd[i].arg3, thread, (double)now))) {
+ dio->vnodeid = kd[i].arg2;
+ print_diskio(dio);
+ free_diskio(dio);
+ }
+ continue;
+ }
+
+ if ((type & CLASS_MASK) == P_CS_Class) {
+
+ // the usual DBG_FUNC_START/END does not work for i/o since it will
+ // return on a different thread, this code uses the P_CS_IO_Done (0x4) bit
+ // instead. the trace command doesn't know how handle either method
+ // (unmatched start/end or 0x4) but works a little better this way.
+
+ int cs_type = type & P_CS_Type_Mask; // strip out the done bit
+ bool start = (type & P_CS_IO_Done) != P_CS_IO_Done;
+
+ switch (cs_type) {
+
+ case P_CS_ReadChunk:
+ case P_CS_WriteChunk:
+ case P_CS_MetaRead:
+ case P_CS_MetaWrite:
+ if (start) {
+ insert_diskio(cs_type, kd[i].arg2, kd[i].arg1, kd[i].arg3, kd[i].arg4, thread, (double)now);
+ } else {
+ if ((dio = complete_diskio(kd[i].arg2, kd[i].arg4, kd[i].arg3, thread, (double)now))) {
+ print_diskio(dio);
+ free_diskio(dio);
+ }
+ }
+ continue;
+
+ case P_CS_TransformRead:
+ case P_CS_TransformWrite:
+ case P_CS_MigrationRead:
+ case P_CS_MigrationWrite:
+ if (start) {
+ insert_diskio(cs_type, kd[i].arg2, CS_DEV, kd[i].arg3, kd[i].arg4, thread, (double)now);
+ } else {
+ if ((dio = complete_diskio(kd[i].arg2, kd[i].arg4, kd[i].arg3, thread, (double)now))) {
+ print_diskio(dio);
+ free_diskio(dio);
+ }
+ }
+ continue;
+
+ case P_CS_SYNC_DISK:
+ if (start) {
+ enter_event(thread, cs_type, &kd[i], NULL, (double)now);
+ } else {
+ exit_event(" SyncCacheCS", thread, cs_type, kd[i].arg1, 0, 0, 0, FMT_SYNC_DISK_CS, (double)now);
+ }
+ continue;
+ }
+
+ continue; // ignore other cs timestamps
+ }
+
+ switch (type) {
+
+ case TRACE_DATA_NEWTHREAD:
+ if (kd[i].arg1) {
+ if ((ti = add_event(thread, TRACE_DATA_NEWTHREAD)) == NULL)
+ continue;
+ ti->child_thread = kd[i].arg1;
+ ti->pid = kd[i].arg2;
+ }
+ continue;
+
+ case TRACE_STRING_NEWTHREAD:
+ if ((ti = find_event(thread, TRACE_DATA_NEWTHREAD)) == (struct th_info *)0)
+ continue;
+
+ create_map_entry(ti->child_thread, ti->pid, (char *)&kd[i].arg1);
+
+ delete_event(ti);
+ continue;
+
+ case TRACE_DATA_EXEC:
+ if ((ti = add_event(thread, TRACE_DATA_EXEC)) == NULL)
+ continue;
+
+ ti->pid = kd[i].arg1;
+ continue;
+
+ case TRACE_STRING_EXEC:
+ if ((ti = find_event(thread, BSC_execve))) {
+ if (ti->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->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)
+ continue;
+
+ create_map_entry(thread, ti->pid, (char *)&kd[i].arg1);
+
+ delete_event(ti);
+ continue;
+
+ case BSC_thread_terminate:
+ delete_map_entry(thread);
+ continue;
+
+ case BSC_exit:
+ continue;
+
+ case proc_exit:
+ kd[i].arg1 = kd[i].arg2 >> 8;
+ type = BSC_exit;
+ break;
+
+ case BSC_mmap:
+ if (kd[i].arg4 & MAP_ANON)
+ continue;
+ break;
+
+ case MACH_idle:
+ case MACH_sched:
+ case MACH_stkhandoff:
+ mark_thread_waited(thread);
+ continue;
+
+ case 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->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;
+ /*
+ * NULL terminate the 'string'
+ */
+ *sargptr = 0;
+
+ ti->pathptr = sargptr;
+ } else {
+ sargptr = ti->pathptr;
+
+ /*
+ * We don't want to overrun our pathname buffer if the
+ * kernel sends us more VFS_LOOKUP entries than we can
+ * handle and we only handle 2 pathname lookups for
+ * a given system call
+ */
+ if (sargptr == 0)
+ 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;
+ }
+ }
+ if (debugid & DBG_FUNC_END) {
+
+ 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 = 0;
+ }
+ } else
+ ti->pathptr = sargptr;
+
+ continue;
+ }
+
+ if (debugid & DBG_FUNC_START) {
+ char * p;
+
+ if ((type & CLASS_MASK) == FILEMGR_BASE) {
+
+ index = filemgr_index(type);
+
+ if (index >= MAX_FILEMGR)
+ continue;
+
+ if ((p = filemgr_calls[index].fm_name) == NULL)
+ continue;
+ } else
+ p = NULL;
+
+ enter_event(thread, type, &kd[i], p, (double)now);
+ continue;
+ }
+
+ switch (type) {
+
+ case Throttled:
+ exit_event(" THROTTLED", thread, type, 0, 0, 0, 0, FMT_DEFAULT, (double)now);
+ continue;
+
+ case 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"))
+ format_print(NULL, " TrimExtent", thread, type, kd[i].arg1, kd[i].arg2, kd[i].arg3, 0, FMT_UNMAP_INFO, now, now, 0, "", NULL);
+ continue;
+
+ case SPEC_ioctl:
+ if (kd[i].arg2 == DKIOCSYNCHRONIZECACHE)
+ exit_event("IOCTL", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, FMT_IOCTL_SYNC, (double)now);
+ else if (kd[i].arg2 == DKIOCUNMAP)
+ exit_event("IOCTL", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, FMT_IOCTL_UNMAP, (double)now);
+ else {
+ if ((ti = find_event(thread, type)))
+ delete_event(ti);
+ }
+ continue;
+
+ case MACH_pageout:
+ if (kd[i].arg2)
+ exit_event("PAGE_OUT_ANON", thread, type, 0, kd[i].arg1, 0, 0, FMT_PGOUT, (double)now);
+ else
+ exit_event("PAGE_OUT_FILE", thread, type, 0, kd[i].arg1, 0, 0, FMT_PGOUT, (double)now);
+ continue;
+
+ case MACH_vmfault:
+ if (kd[i].arg4 == DBG_PAGEIN_FAULT)
+ exit_event("PAGE_IN", thread, type, 0, kd[i].arg1, kd[i].arg2, 0, FMT_PGIN, (double)now);
+ else if (kd[i].arg4 == DBG_PAGEINV_FAULT)
+ exit_event("PAGE_IN_FILE", thread, type, 0, kd[i].arg1, kd[i].arg2, 0, FMT_PGIN, (double)now);
+ else if (kd[i].arg4 == DBG_PAGEIND_FAULT)
+ exit_event("PAGE_IN_ANON", thread, type, 0, kd[i].arg1, kd[i].arg2, 0, FMT_PGIN, (double)now);
+ else if (kd[i].arg4 == DBG_CACHE_HIT_FAULT)
+ exit_event("CACHE_HIT", thread, type, 0, kd[i].arg1, kd[i].arg2, 0, FMT_CACHEHIT, (double)now);
+ else {
+ if ((ti = find_event(thread, type)))
+ delete_event(ti);
+ }
+ continue;
+
+ case MSC_map_fd:
+ exit_event("map_fd", thread, type, kd[i].arg1, kd[i].arg2, 0, 0, FMT_FD, (double)now);
+ continue;
+
+ case BSC_mmap_extended:
+ case BSC_mmap_extended2:
+ case BSC_msync_extended:
+ case BSC_pread_extended:
+ case BSC_pwrite_extended:
+ extend_syscall(thread, type, &kd[i]);
+ continue;
+ }
+
+ if ((type & CSC_MASK) == BSC_BASE) {
+
+ if ((index = BSC_INDEX(type)) >= MAX_BSD_SYSCALL)
+ continue;
+
+ if (bsd_syscalls[index].sc_name) {
+ exit_event(bsd_syscalls[index].sc_name, thread, type, kd[i].arg1, kd[i].arg2, kd[i].arg3, kd[i].arg4,
+ bsd_syscalls[index].sc_format, (double)now);
+
+ if (type == BSC_exit)
+ delete_map_entry(thread);
+ }
+ } else if ((type & CLASS_MASK) == FILEMGR_BASE) {
+
+ if ((index = filemgr_index(type)) >= MAX_FILEMGR)
+ continue;
+
+ if (filemgr_calls[index].fm_name) {
+ exit_event(filemgr_calls[index].fm_name, thread, type, kd[i].arg1, kd[i].arg2, kd[i].arg3, kd[i].arg4,
+ FMT_DEFAULT, (double)now);
+ }
+ }
+ }
+ fflush(0);
+}
+
+
+void
+enter_event_now(uintptr_t thread, int type, kd_buf *kd, char *name, double now)
+{
+ th_info_t ti;
+ threadmap_t tme;
+ int secs;
+ int usecs;
+ long long l_usecs;
+ long curr_time;
+ int clen = 0;
+ int tsclen = 0;
+ int nmclen = 0;
+ int argsclen = 0;
+ char buf[MAXWIDTH];
+
+ if ((ti = add_event(thread, type)) == NULL)
+ return;
+
+ ti->stime = now;
+ ti->arg1 = kd->arg1;
+ ti->arg2 = kd->arg2;
+ ti->arg3 = kd->arg3;
+ ti->arg4 = kd->arg4;
+
+ 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))) {
+
+ filemgr_in_progress++;
+ ti->in_filemgr = 1;
+
+ if (RAW_flag) {
+ l_usecs = (long long)((now - bias_now) / divisor);
+ l_usecs += (sample_TOD_secs * 1000000) + sample_TOD_usecs;
+ } else
+ l_usecs = (long long)(now / divisor);
+ secs = l_usecs / 1000000;
+ curr_time = bias_secs + secs;
+
+ sprintf(buf, "%-8.8s", &(ctime(&curr_time)[11]));
+ tsclen = strlen(buf);
+
+ if (columns > MAXCOLS || wideflag) {
+ usecs = l_usecs - (long long)((long long)secs * 1000000);
+ sprintf(&buf[tsclen], ".%06ld", (long)usecs);
+ tsclen = strlen(buf);
+ }
+
+ /*
+ * Print timestamp column
+ */
+ printf("%s", buf);
+
+ tme = find_map_entry(thread);
+ if (tme) {
+ sprintf(buf, " %-25.25s ", name);
+ nmclen = strlen(buf);
+ printf("%s", buf);
+
+ sprintf(buf, "(%d, 0x%lx, 0x%lx, 0x%lx)", (short)kd->arg1, kd->arg2, kd->arg3, kd->arg4);
+ argsclen = strlen(buf);
+
+ /*
+ * Calculate white space out to command
+ */
+ if (columns > MAXCOLS || wideflag) {
+ clen = columns - (tsclen + nmclen + argsclen + 20 + 11);
+ } else
+ clen = columns - (tsclen + nmclen + argsclen + 12);
+
+ if (clen > 0) {
+ printf("%s", buf); /* print the kdargs */
+ memset(buf, ' ', clen);
+ buf[clen] = '\0';
+ printf("%s", buf);
+ }
+ else if ((argsclen + clen) > 0) {
+ /*
+ * no room so wipe out the kdargs
+ */
+ memset(buf, ' ', (argsclen + clen));
+ buf[argsclen + clen] = '\0';
+ printf("%s", buf);
+ }
+ if (columns > MAXCOLS || wideflag)
+ printf("%s.%d\n", tme->tm_command, (int)thread);
+ else
+ printf("%-12.12s\n", tme->tm_command);
+ } else
+ printf(" %-24.24s (%5d, %#lx, 0x%lx, 0x%lx)\n", name, (short)kd->arg1, kd->arg2, kd->arg3, kd->arg4);
+ }
+}
+
+
+void
+enter_event(uintptr_t thread, int type, kd_buf *kd, char *name, double now)
+{
+ int index;
+
+ 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 ((index = BSC_INDEX(type)) >= MAX_BSD_SYSCALL)
+ return;
+
+ if (bsd_syscalls[index].sc_name)
+ enter_event_now(thread, type, kd, name, now);
+ return;
+ }
+ if ((type & CLASS_MASK) == FILEMGR_BASE) {
+
+ if ((index = filemgr_index(type)) >= MAX_FILEMGR)
+ return;
+
+ if (filemgr_calls[index].fm_name)
+ enter_event_now(thread, type, kd, name, now);
+ return;
+ }
+}
+
+/*
+ * Handle system call extended trace data.
+ * pread and pwrite:
+ * Wipe out the kd args that were collected upon syscall_entry
+ * because it is the extended info that we really want, and it
+ * is all we really need.
+*/
+
+void
+extend_syscall(uintptr_t thread, int type, kd_buf *kd)
+{
+ th_info_t ti;
+
+ switch (type) {
+ case BSC_mmap_extended:
+ if ((ti = find_event(thread, BSC_mmap)) == (struct th_info *)0)
+ return;
+ ti->arg8 = ti->arg3; /* save protection */
+ ti->arg1 = kd->arg1; /* the fd */
+ ti->arg3 = kd->arg2; /* bottom half address */
+ ti->arg5 = kd->arg3; /* bottom half size */
+ break;
+ case BSC_mmap_extended2:
+ if ((ti = find_event(thread, BSC_mmap)) == (struct th_info *)0)
+ return;
+ ti->arg2 = kd->arg1; /* top half address */
+ ti->arg4 = kd->arg2; /* top half size */
+ ti->arg6 = kd->arg3; /* top half file offset */
+ ti->arg7 = kd->arg4; /* bottom half file offset */
+ break;
+ case BSC_msync_extended:
+ if ((ti = find_event(thread, BSC_msync)) == (struct th_info *)0) {
+ if ((ti = find_event(thread, BSC_msync_nocancel)) == (struct th_info *)0)
+ return;
+ }
+ ti->arg4 = kd->arg1; /* top half address */
+ ti->arg5 = kd->arg2; /* top half size */
+ break;
+ case BSC_pread_extended:
+ if ((ti = find_event(thread, BSC_pread)) == (struct th_info *)0) {
+ if ((ti = find_event(thread, BSC_pread_nocancel)) == (struct th_info *)0)
+ return;
+ }
+ ti->arg1 = kd->arg1; /* the fd */
+ ti->arg2 = kd->arg2; /* nbytes */
+ ti->arg3 = kd->arg3; /* top half offset */
+ ti->arg4 = kd->arg4; /* bottom half offset */
+ break;
+ case BSC_pwrite_extended:
+ if ((ti = find_event(thread, BSC_pwrite)) == (struct th_info *)0) {
+ if ((ti = find_event(thread, BSC_pwrite_nocancel)) == (struct th_info *)0)
+ return;
+ }
+ ti->arg1 = kd->arg1; /* the fd */
+ ti->arg2 = kd->arg2; /* nbytes */
+ ti->arg3 = kd->arg3; /* top half offset */
+ ti->arg4 = kd->arg4; /* bottom half offset */
+ break;
+ default:
+ return;
+ }
+}
+
+
+void
+exit_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->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;
+
+ if (filemgr_in_progress > 0)
+ filemgr_in_progress--;
+ }
+ delete_event(ti);
+}
+
+
+void
+get_mode_nibble(char * buf, int smode, int special, char x_on, char x_off)
+{
+ if (smode & 04)
+ buf[0] = 'r';
+ if (smode & 02)
+ buf[1] = 'w';
+ if (smode & 01) {
+ if (special)
+ buf[2] = x_on;
+ else
+ buf[2] = 'x';
+ } else {
+ if (special)
+ buf[2] = x_off;
+ }
+}
+
+
+void
+get_mode_string(int mode, char *buf)
+{
+ memset(buf, '-', 9);
+ buf[9] = '\0';
+
+ get_mode_nibble(&buf[6], mode, (mode & 01000), 't', 'T');
+ get_mode_nibble(&buf[3], (mode>>3), (mode & 02000), 's', 'S');
+ get_mode_nibble(&buf[0], (mode>>6), (mode & 04000), 's', 'S');
+}
+
+
+int clip_64bit(char *s, uint64_t value)
+{
+ int clen = 0;
+
+ if ( (value & 0xff00000000000000LL) )
+ clen = printf("%s0x%16.16qx", s, value);
+ else if ( (value & 0x00ff000000000000LL) )
+ clen = printf("%s0x%14.14qx ", s, value);
+ else if ( (value & 0x0000ff0000000000LL) )
+ clen = printf("%s0x%12.12qx ", s, value);
+ else if ( (value & 0x000000ff00000000LL) )
+ clen = printf("%s0x%10.10qx ", s, value);
+ else
+ clen = printf("%s0x%8.8qx ", s, value);
+
+ return (clen);
+}
+
+
+void
+format_print(struct th_info *ti, char *sc_name, uintptr_t thread, int type, 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;
+ int usecs;
+ int nopadding = 0;
+ long long l_usecs;
+ long curr_time;
+ char *command_name;
+ int in_filemgr = 0;
+ int len = 0;
+ int clen = 0;
+ int tlen = 0;
+ int class;
+ uint64_t user_addr;
+ uint64_t user_size;
+ char *framework_name;
+ char *framework_type;
+ char *p1;
+ char *p2;
+ char buf[MAXWIDTH];
+ char cs_diskname[32];
+
+ 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);
+
+ if ((double)l_usecs < start_time || (double)l_usecs > end_time)
+ return;
+
+ l_usecs += (sample_TOD_secs * 1000000) + sample_TOD_usecs;
+ }
+ else
+ l_usecs = (long long)(now / divisor);
+ secs = l_usecs / 1000000;
+ curr_time = bias_secs + secs;
+
+ class = type >> 24;
+
+ if (dio)
+ command_name = dio->issuing_command;
+ else {
+ threadmap_t tme;
+
+ if ((tme = find_map_entry(thread)))
+ command_name = tme->tm_command;
+ }
+ if (last_timestamp != curr_time) {
+ timestamp_len = sprintf(timestamp, "%-8.8s", &(ctime(&curr_time)[11]));
+ last_timestamp = curr_time;
+ }
+ if (columns > MAXCOLS || wideflag) {
+ int usec;
+
+ tlen = timestamp_len;
+ nopadding = 0;
+ usec = (l_usecs - (long long)((long long)secs * 1000000));
+
+ sprintf(×tamp[tlen], ".%06ld", (long)usec);
+ tlen += 7;
+
+ timestamp[tlen] = '\0';
+
+ if (filemgr_in_progress) {
+ if (class != FILEMGR_CLASS) {
+ if (find_event(thread, -1))
+ in_filemgr = 1;
+ }
+ }
+ } else
+ nopadding = 1;
+
+ if ((class == FILEMGR_CLASS) && (columns > MAXCOLS || wideflag))
+ clen = printf("%s %-20.20s", timestamp, sc_name);
+ else if (in_filemgr)
+ clen = printf("%s %-15.15s", timestamp, sc_name);
+ else
+ clen = printf("%s %-17.17s", timestamp, sc_name);
+
+
+ framework_name = NULL;
+
+ if (columns > MAXCOLS || wideflag) {
+
+ off_t offset_reassembled = 0LL;
+
+ switch (format) {
+
+ case FMT_DEFAULT:
+ /*
+ * pathname based system calls or
+ * calls with no fd or pathname (i.e. sync)
+ */
+ if (arg1)
+ clen += printf(" [%3d] ", arg1);
+ else
+ clen += printf(" ");
+ break;
+
+ case FMT_FD:
+ /*
+ * fd based system call... no I/O
+ */
+ if (arg1)
+ clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
+ else
+ clen += printf(" F=%-3d", ti->arg1);
+ break;
+
+ case FMT_FD_2:
+ /*
+ * accept, dup, dup2
+ */
+ if (arg1)
+ clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
+ else
+ clen += printf(" F=%-3d F=%-3d", ti->arg1, arg2);
+ break;
+
+ case FMT_FD_IO:
+ /*
+ * system calls with fd's that return an I/O completion count
+ */
+ if (arg1)
+ clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
+ else
+ clen += printf(" F=%-3d B=0x%-6x", ti->arg1, arg2);
+ break;
+
+ case FMT_PGIN:
+ /*
+ * pagein
+ */
+ user_addr = ((uint64_t)arg2 << 32) | (uint32_t)arg3;
+
+ lookup_name(user_addr, &framework_type, &framework_name);
+ clen += clip_64bit(" A=", user_addr);
+ break;
+
+ case FMT_CACHEHIT:
+ /*
+ * cache hit
+ */
+ user_addr = ((uint64_t)arg2 << 32) | (uint32_t)arg3;
+
+ lookup_name(user_addr, &framework_type, &framework_name);
+ clen += clip_64bit(" A=", user_addr);
+ break;
+
+ case FMT_PGOUT:
+ /*
+ * pageout
+ */
+ 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 {
+ 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:
+ /*
+ * 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%-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]));
+
+ break;
+
+ case FMT_MSYNC:
+ {
+ /*
+ * msync
+ */
+ int mlen = 0;
+
+ buf[0] = '\0';
+
+ if (ti->arg3 & MS_ASYNC)
+ mlen += sprintf(&buf[mlen], "MS_ASYNC | ");
+ else
+ mlen += sprintf(&buf[mlen], "MS_SYNC | ");
+
+ if (ti->arg3 & MS_INVALIDATE)
+ mlen += sprintf(&buf[mlen], "MS_INVALIDATE | ");
+ if (ti->arg3 & MS_KILLPAGES)
+ mlen += sprintf(&buf[mlen], "MS_KILLPAGES | ");
+ if (ti->arg3 & MS_DEACTIVATE)
+ mlen += sprintf(&buf[mlen], "MS_DEACTIVATE | ");
+
+ if (ti->arg3 & ~(MS_ASYNC | MS_SYNC | MS_INVALIDATE | MS_KILLPAGES | MS_DEACTIVATE))
+ mlen += sprintf(&buf[mlen], "UNKNOWN | ");
+
+ if (mlen)
+ buf[mlen - 3] = '\0';
+
+ if (arg1)
+ clen += printf(" [%3d]", arg1);
+
+ user_addr = (((off_t)(unsigned int)(ti->arg4)) << 32) | (unsigned int)(ti->arg1);
+ clen += clip_64bit(" A=", user_addr);
+
+ user_size = (((off_t)(unsigned int)(ti->arg5)) << 32) | (unsigned int)(ti->arg2);
+
+ clen += printf(" B=0x%-16qx <%s>", user_size, buf);
+
+ break;
+ }
+
+ case FMT_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:
+ {
+ /*
+ * fcntl
+ */
+ char *p = NULL;
+ int fd = -1;
+
+ if (arg1)
+ clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
+ else
+ clen += printf(" F=%-3d", ti->arg1);
+
+ switch(ti->arg2) {
+
+ case F_DUPFD:
+ p = "DUPFD";
+ break;
+
+ case F_GETFD:
+ p = "GETFD";
+ break;
+
+ case F_SETFD:
+ p = "SETFD";
+ break;
+
+ case F_GETFL:
+ p = "GETFL";
+ break;
+
+ case F_SETFL:
+ p = "SETFL";
+ break;
+
+ case F_GETOWN:
+ p = "GETOWN";
+ break;
+
+ case F_SETOWN:
+ p = "SETOWN";
+ break;
+
+ case F_GETLK:
+ p = "GETLK";
+ break;
+
+ case F_SETLK:
+ p = "SETLK";
+ break;
+
+ case F_SETLKW:
+ p = "SETLKW";
+ break;
+
+ case F_PREALLOCATE:
+ p = "PREALLOCATE";
+ break;
+
+ case F_SETSIZE:
+ p = "SETSIZE";
+ break;
+
+ case F_RDADVISE:
+ p = "RDADVISE";
+ break;
+
+ case F_GETPATH:
+ p = "GETPATH";
+ break;
+
+ case F_FULLFSYNC:
+ p = "FULLFSYNC";
+ break;
+
+ case F_PATHPKG_CHECK:
+ p = "PATHPKG_CHECK";
+ break;
+
+ case F_OPENFROM:
+ p = "OPENFROM";
+
+ if (arg1 == 0)
+ fd = arg2;
+ break;
+
+ case F_UNLINKFROM:
+ p = "UNLINKFROM";
+ break;
+
+ case F_CHECK_OPENEVT:
+ p = "CHECK_OPENEVT";
+ break;
+
+ case F_NOCACHE:
+ if (ti->arg3)
+ p = "CACHING OFF";
+ else
+ p = "CACHING ON";
+ break;
+
+ case F_GLOBAL_NOCACHE:
+ if (ti->arg3)
+ p = "CACHING OFF (GLOBAL)";
+ else
+ p = "CACHING ON (GLOBAL)";
+ break;
+
+ }
+ if (p) {
+ if (fd == -1)
+ clen += printf(" <%s>", p);
+ else
+ clen += printf(" <%s> F=%d", p, fd);
+ } else
+ clen += printf(" <CMD=%d>", ti->arg2);
+
+ break;
+ }
+
+ case FMT_IOCTL:
+ {
+ /*
+ * ioctl
+ */
+ if (arg1)
+ clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
+ else
+ clen += printf(" F=%-3d", ti->arg1);
+
+ clen += printf(" <CMD=0x%x>", ti->arg2);
+
+ break;
+ }
+
+ case FMT_IOCTL_SYNC:
+ {
+ /*
+ * ioctl
+ */
+ clen += printf(" <DKIOCSYNCHRONIZECACHE> /dev/%s", find_disk_name(arg1));
+
+ break;
+ }
+
+ case FMT_IOCTL_UNMAP:
+ {
+ /*
+ * ioctl
+ */
+ clen += printf(" <DKIOCUNMAP> /dev/%s", find_disk_name(arg1));
+
+ break;
+ }
+
+ case FMT_UNMAP_INFO:
+ {
+ clen += printf(" D=0x%8.8x B=0x%-6x /dev/%s", arg2, arg3, find_disk_name(arg1));
+
+ break;
+ }
+
+ case FMT_SELECT:
+ /*
+ * select
+ */
+ if (arg1)
+ clen += printf(" [%3d]", arg1);
+ else
+ clen += printf(" S=%-3d", arg2);
+
+ break;
+
+ case FMT_LSEEK:
+ case FMT_PREAD:
+ /*
+ * pread, pwrite, lseek
+ */
+ clen += printf(" F=%-3d", ti->arg1);
+
+ if (arg1)
+ clen += printf("[%3d] ", arg1);
+ else {
+ if (format == FMT_PREAD)
+ clen += printf(" B=0x%-8x ", arg2);
+ else
+ clen += printf(" ");
+ }
+ if (format == FMT_PREAD)
+ offset_reassembled = (((off_t)(unsigned int)(ti->arg3)) << 32) | (unsigned int)(ti->arg4);
+ else
+#ifdef __ppc__
+ offset_reassembled = (((off_t)(unsigned int)(arg2)) << 32) | (unsigned int)(arg3);
+#else
+ offset_reassembled = (((off_t)(unsigned int)(arg3)) << 32) | (unsigned int)(arg2);
+#endif
+ clen += clip_64bit("O=", offset_reassembled);
+
+ if (format == FMT_LSEEK) {
+ char *mode;
+
+ if (ti->arg4 == SEEK_SET)
+ mode = "SEEK_SET";
+ else if (ti->arg4 == SEEK_CUR)
+ mode = "SEEK_CUR";
+ else if (ti->arg4 == SEEK_END)
+ mode = "SEEK_END";
+ else
+ mode = "UNKNOWN";
+
+ clen += printf(" <%s>", mode);
+ }
+ break;
+
+ case FMT_MMAP:
+ /*
+ * mmap
+ */
+ clen += printf(" F=%-3d ", ti->arg1);
+
+ if (arg1)
+ clen += printf("[%3d] ", arg1);
+ else {
+
+ user_addr = (((off_t)(unsigned int)(ti->arg2)) << 32) | (unsigned int)(ti->arg3);
+
+ clen += clip_64bit("A=", user_addr);
+
+ offset_reassembled = (((off_t)(unsigned int)(ti->arg6)) << 32) | (unsigned int)(ti->arg7);
+
+ clen += clip_64bit("O=", offset_reassembled);
+
+ user_size = (((off_t)(unsigned int)(ti->arg4)) << 32) | (unsigned int)(ti->arg5);
+
+ clen += printf("B=0x%-16qx", user_size);
+
+ clen += printf(" <");
+
+ if (ti->arg8 & PROT_READ)
+ clen += printf("READ");
+
+ if (ti->arg8 & PROT_WRITE)
+ clen += printf("|WRITE");
+
+ if (ti->arg8 & PROT_EXEC)
+ clen += printf("|EXEC");
+
+ clen += printf(">");
+ }
+ break;
+
+ case FMT_TRUNC:
+ case FMT_FTRUNC:
+ /*
+ * ftruncate, truncate
+ */
+ if (format == FMT_FTRUNC)
+ clen += printf(" F=%-3d", ti->arg1);
+ else
+ clen += printf(" ");
+
+ if (arg1)
+ clen += printf("[%3d]", arg1);
+
+#ifdef __ppc__
+ offset_reassembled = (((off_t)(unsigned int)(ti->arg2)) << 32) | (unsigned int)(ti->arg3);
+#else
+ offset_reassembled = (((off_t)(unsigned int)(ti->arg3)) << 32) | (unsigned int)(ti->arg2);
+#endif
+ clen += clip_64bit(" O=", offset_reassembled);
+
+ nopadding = 1;
+ break;
+
+ case FMT_FCHFLAGS:
+ case FMT_CHFLAGS:
+ {
+ /*
+ * fchflags, chflags
+ */
+ int mlen = 0;
+
+ if (format == FMT_FCHFLAGS) {
+ if (arg1)
+ clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
+ else
+ clen += printf(" F=%-3d", ti->arg1);
+ } else {
+ if (arg1)
+ clen += printf(" [%3d] ", arg1);
+ }
+ buf[mlen++] = ' ';
+ buf[mlen++] = '<';
+
+ if (ti->arg2 & UF_NODUMP)
+ mlen += sprintf(&buf[mlen], "UF_NODUMP | ");
+ if (ti->arg2 & UF_IMMUTABLE)
+ mlen += sprintf(&buf[mlen], "UF_IMMUTABLE | ");
+ if (ti->arg2 & UF_APPEND)
+ mlen += sprintf(&buf[mlen], "UF_APPEND | ");
+ if (ti->arg2 & UF_OPAQUE)
+ mlen += sprintf(&buf[mlen], "UF_OPAQUE | ");
+ if (ti->arg2 & SF_ARCHIVED)
+ mlen += sprintf(&buf[mlen], "SF_ARCHIVED | ");
+ if (ti->arg2 & SF_IMMUTABLE)
+ mlen += sprintf(&buf[mlen], "SF_IMMUTABLE | ");
+ if (ti->arg2 & SF_APPEND)
+ mlen += sprintf(&buf[mlen], "SF_APPEND | ");
+
+ if (ti->arg2 == 0)
+ mlen += sprintf(&buf[mlen], "CLEAR_ALL_FLAGS | ");
+ else if (ti->arg2 & ~(UF_NODUMP | UF_IMMUTABLE | UF_APPEND | SF_ARCHIVED | SF_IMMUTABLE | SF_APPEND))
+ mlen += sprintf(&buf[mlen], "UNKNOWN | ");
+
+ if (mlen >= 3)
+ mlen -= 3;
+
+ buf[mlen++] = '>';
+ buf[mlen] = '\0';
+
+ if (mlen < 19) {
+ memset(&buf[mlen], ' ', 19 - mlen);
+ mlen = 19;
+ }
+ clen += printf("%s", buf);
+
+ nopadding = 1;
+ break;
+ }
+
+ case FMT_UMASK:
+ case FMT_FCHMOD:
+ case FMT_FCHMOD_EXT:
+ case FMT_CHMOD:
+ case FMT_CHMOD_EXT:
+ {
+ /*
+ * fchmod, fchmod_extended, chmod, chmod_extended
+ */
+ int mode;
+
+ if (format == FMT_FCHMOD || format == FMT_FCHMOD_EXT) {
+ if (arg1)
+ clen += printf(" F=%-3d[%3d] ", ti->arg1, arg1);
+ else
+ clen += printf(" F=%-3d ", ti->arg1);
+ } else {
+ if (arg1)
+ clen += printf(" [%3d] ", arg1);
+ else
+ clen += printf(" ");
+ }
+ if (format == FMT_UMASK)
+ mode = ti->arg1;
+ else if (format == FMT_FCHMOD || format == FMT_CHMOD)
+ mode = ti->arg2;
+ else
+ mode = ti->arg4;
+
+ get_mode_string(mode, &buf[0]);
+
+ if (arg1 == 0)
+ clen += printf("<%s> ", buf);
+ else
+ clen += printf("<%s>", buf);
+ break;
+ }
+
+ case FMT_ACCESS:
+ {
+ /*
+ * access
+ */
+ char mode[5];
+
+ memset(mode, '_', 4);
+ mode[4] = '\0';
+
+ if (ti->arg2 & R_OK)
+ mode[0] = 'R';
+ if (ti->arg2 & W_OK)
+ mode[1] = 'W';
+ if (ti->arg2 & X_OK)
+ mode[2] = 'X';
+ if (ti->arg2 == F_OK)
+ mode[3] = 'F';
+
+ if (arg1)
+ clen += printf(" [%3d] (%s) ", arg1, mode);
+ else
+ clen += printf(" (%s) ", mode);
+
+ nopadding = 1;
+ break;
+ }
+
+ case FMT_MOUNT:
+ {
+ if (arg1)
+ clen += printf(" [%3d] <FLGS=0x%x> ", arg1, ti->arg3);
+ else
+ clen += printf(" <FLGS=0x%x> ", ti->arg3);
+
+ nopadding = 1;
+ break;
+ }
+
+ case FMT_UNMOUNT:
+ {
+ char *mountflag;
+
+ if (ti->arg2 & MNT_FORCE)
+ mountflag = "<FORCE>";
+ else
+ mountflag = "";
+
+ if (arg1)
+ clen += printf(" [%3d] %s ", arg1, mountflag);
+ else
+ clen += printf(" %s ", mountflag);
+
+ nopadding = 1;
+ break;
+ }
+
+ case FMT_OPEN:
+ {
+ /*
+ * open
+ */
+ char mode[7];
+
+ memset(mode, '_', 6);
+ mode[6] = '\0';
+
+ if (ti->arg2 & O_RDWR) {
+ mode[0] = 'R';
+ mode[1] = 'W';
+ } else if (ti->arg2 & O_WRONLY)
+ mode[1] = 'W';
+ else
+ mode[0] = 'R';
+
+ if (ti->arg2 & O_CREAT)
+ mode[2] = 'C';
+
+ if (ti->arg2 & O_APPEND)
+ mode[3] = 'A';
+
+ if (ti->arg2 & O_TRUNC)
+ mode[4] = 'T';
+
+ if (ti->arg2 & O_EXCL)
+ mode[5] = 'E';
+
+ if (arg1)
+ clen += printf(" [%3d] (%s) ", arg1, mode);
+ else
+ clen += printf(" F=%-3d (%s) ", arg2, mode);
+
+ nopadding = 1;
+ break;
+ }
+
+ case FMT_SOCKET:
+ {
+ /*
+ * socket
+ *
+ */
+ char *domain;
+ char *type;
+
+ switch (ti->arg1) {
+
+ case AF_UNIX:
+ domain = "AF_UNIX";
+ break;
+
+ case AF_INET:
+ domain = "AF_INET";
+ break;
+
+ case AF_ISO:
+ domain = "AF_ISO";
+ break;
+
+ case AF_NS:
+ domain = "AF_NS";
+ break;
+
+ case AF_IMPLINK:
+ domain = "AF_IMPLINK";
+ break;
+
+ default:
+ domain = "UNKNOWN";
+ break;
+ }
+
+ switch (ti->arg2) {
+
+ case SOCK_STREAM:
+ type = "SOCK_STREAM";
+ break;
+
+ case SOCK_DGRAM:
+ type = "SOCK_DGRAM";
+ break;
+
+ case SOCK_RAW:
+ type = "SOCK_RAW";
+ break;
+
+ case SOCK_SEQPACKET:
+ type = "SOCK_SEQPACKET";
+ break;
+
+ case SOCK_RDM:
+ type = "SOCK_RDM";
+ break;
+
+ default:
+ type = "UNKNOWN";
+ break;
+ }
+
+ if (arg1)
+ clen += printf(" [%3d] <%s, %s, 0x%x>", arg1, domain, type, ti->arg3);
+ else
+ clen += printf(" F=%-3d <%s, %s, 0x%x>", arg2, domain, type, ti->arg3);
+ break;
+ }
+
+ case FMT_AIO_FSYNC:
+ {
+ /*
+ * aio_fsync [errno] AIOCBP OP
+ */
+ char *op;
+
+ if (ti->arg1 == O_SYNC || ti->arg1 == 0)
+ op = "AIO_FSYNC";
+#if O_DSYNC
+ else if (ti->arg1 == O_DSYNC)
+ op = "AIO_DSYNC";
+#endif
+ else
+ op = "UNKNOWN";
+
+ if (arg1)
+ clen += printf(" [%3d] P=0x%8.8x <%s>", arg1, ti->arg2, op);
+ else
+ clen += printf(" P=0x%8.8x <%s>", ti->arg2, op);
+ break;
+ }
+
+ case FMT_AIO_RETURN:
+ /*
+ * aio_return [errno] AIOCBP IOSIZE
+ */
+ if (arg1)
+ clen += printf(" [%3d] P=0x%8.8x", arg1, ti->arg1);
+ else
+ clen += printf(" P=0x%8.8x B=0x%-8x", ti->arg1, arg2);
+ break;
+
+ case FMT_AIO_SUSPEND:
+ /*
+ * aio_suspend [errno] NENTS
+ */
+ if (arg1)
+ clen += printf(" [%3d] N=%d", arg1, ti->arg2);
+ else
+ clen += printf(" N=%d", ti->arg2);
+ break;
+
+ case FMT_AIO_CANCEL:
+ /*
+ * aio_cancel [errno] FD or AIOCBP (if non-null)
+ */
+ if (ti->arg2) {
+ if (arg1)
+ clen += printf(" [%3d] P=0x%8.8x", arg1, ti->arg2);
+ else
+ clen += printf(" P=0x%8.8x", ti->arg2);
+ } else {
+ if (arg1)
+ clen += printf(" F=%-3d[%3d]", ti->arg1, arg1);
+ else
+ clen += printf(" F=%-3d", ti->arg1);
+ }
+ break;
+
+ case FMT_AIO:
+ /*
+ * aio_error, aio_read, aio_write [errno] AIOCBP
+ */
+ if (arg1)
+ clen += printf(" [%3d] P=0x%8.8x", arg1, ti->arg1);
+ else
+ clen += printf(" P=0x%8.8x", ti->arg1);
+ break;
+
+ case FMT_LIO_LISTIO:
+ {
+ /*
+ * lio_listio [errno] NENTS MODE
+ */
+ char *op;
+
+ if (ti->arg1 == LIO_NOWAIT)
+ op = "LIO_NOWAIT";
+ else if (ti->arg1 == LIO_WAIT)
+ op = "LIO_WAIT";
+ else
+ op = "UNKNOWN";
+
+ if (arg1)
+ clen += printf(" [%3d] N=%d <%s>", arg1, ti->arg3, op);
+ else
+ clen += printf(" N=%d <%s>", ti->arg3, op);
+ break;
+ }
+
+ }
+ }
+
+ /*
+ * Calculate space available to print pathname
+ */
+ if (columns > MAXCOLS || wideflag)
+ clen = columns - (clen + 14 + 20 + 11);
+ else
+ clen = columns - (clen + 14 + 12);
+
+ if (class != FILEMGR_CLASS && !nopadding)
+ clen -= 3;
+
+ if (framework_name)
+ len = sprintf(&buf[0], " %s %s ", framework_type, framework_name);
+ else if (*pathname != '\0') {
+ len = sprintf(&buf[0], " %s ", pathname);
+
+ if (format == FMT_MOUNT && ti->lookups[1].pathname[0]) {
+ int len2;
+
+ memset(&buf[len], ' ', 2);
+
+ len2 = sprintf(&buf[len+2], " %s ", (char *)&ti->lookups[1].pathname[0]);
+ len = len + 2 + len2;
+ }
+ } else
+ len = 0;
+
+ if (clen > len) {
+ /*
+ * Add null padding if column length
+ * is wider than the pathname length.
+ */
+ memset(&buf[len], ' ', clen - len);
+ buf[clen] = '\0';
+
+ pathname = buf;
+
+ } else if (clen == len) {
+ pathname = buf;
+
+ } else if ((clen > 0) && (clen < len)) {
+ /*
+ * This prints the tail end of the pathname
+ */
+ buf[len-clen] = ' ';
+
+ pathname = &buf[len - clen];
+
+ } else {
+ pathname = "";
+ }
+
+ /*
+ * fudge some additional system call overhead
+ * that currently isn't tracked... this also
+ * insures that we see a minimum of 1 us for
+ * an elapsed time
+ */
+ usecs = (unsigned long)(((now - stime) + (divisor-1)) / divisor);
+ secs = usecs / 1000000;
+ usecs -= secs * 1000000;
+
+ if (class != FILEMGR_CLASS && !nopadding)
+ p1 = " ";
+ else
+ p1 = "";
+
+ if (waited)
+ p2 = " W";
+ else
+ p2 = " ";
+
+ if (columns > MAXCOLS || wideflag)
+ printf("%s%s %3ld.%06ld%s %s.%d\n", p1, pathname, (unsigned long)secs, (unsigned long)usecs, p2, command_name, (int)thread);
+ else
+ printf("%s%s %3ld.%06ld%s %-12.12s\n", p1, pathname, (unsigned long)secs, (unsigned long)usecs, p2, command_name);
+}
+
+
+void
+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 ti_prev;
+ int hashid;
+
+ hashid = ti_to_delete->thread & HASH_MASK;
+
+ if ((ti = th_info_hash[hashid])) {
+ if (ti == ti_to_delete)
+ th_info_hash[hashid] = ti->next;
+ else {
+ ti_prev = ti;
+
+ for (ti = ti->next; ti; ti = ti->next) {
+ if (ti == ti_to_delete) {
+ ti_prev->next = ti->next;
+ break;
+ }
+ ti_prev = ti;
+ }
+ }
+ if (ti) {
+ ti->next = th_info_freelist;
+ th_info_freelist = ti;
+ }
+ }
+}
+
+th_info_t
+add_event(uintptr_t thread, int type) {
+ th_info_t ti;
+ int i;
+ int hashid;
+
+ if ((ti = th_info_freelist))
+ th_info_freelist = ti->next;
+ else
+ ti = (th_info_t)malloc(sizeof(struct th_info));
+
+ hashid = thread & HASH_MASK;
+
+ ti->next = th_info_hash[hashid];
+ th_info_hash[hashid] = ti;
+
+ ti->thread = thread;
+ ti->type = type;
+
+ ti->waited = 0;
+ ti->in_filemgr = 0;
+ ti->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);
+}
+
+th_info_t
+find_event(uintptr_t thread, int type) {
+ th_info_t ti;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ for (ti = th_info_hash[hashid]; ti; ti = ti->next) {
+ if (ti->thread == thread) {
+ if (type == ti->type)
+ return (ti);
+ if (ti->in_filemgr) {
+ if (type == -1)
+ return (ti);
+ continue;
+ }
+ if (type == 0)
+ return (ti);
+ }
+ }
+ return ((th_info_t) 0);
+}
+
+void
+delete_all_events() {
+ th_info_t ti = 0;
+ th_info_t ti_next = 0;
+ int i;
+
+ for (i = 0; i < HASH_SIZE; i++) {
+
+ for (ti = th_info_hash[i]; ti; ti = ti_next) {
+ ti_next = ti->next;
+ ti->next = th_info_freelist;
+ th_info_freelist = ti;
+ }
+ th_info_hash[i] = 0;
+ }
+}
+
+
+void
+mark_thread_waited(uintptr_t thread) {
+ th_info_t ti;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ for (ti = th_info_hash[hashid]; ti; ti = ti->next) {
+ if (ti->thread == thread)
+ ti->waited = 1;
+ }
+}
+
+
+void read_command_map()
+{
+ size_t size;
+ int i;
+ int total_threads = 0;
+ kd_threadmap *mapptr = 0;
+
+ delete_all_map_entries();
+
+ if (!RAW_flag) {
+
+ total_threads = bufinfo.nkdthreads;
+ size = bufinfo.nkdthreads * sizeof(kd_threadmap);
+
+ if (size) {
+ if ((mapptr = (kd_threadmap *) malloc(size))) {
+ int mib[6];
+
+ bzero (mapptr, size);
+ /*
+ * Now read the threadmap
+ */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDTHRMAP;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+
+ if (sysctl(mib, 3, mapptr, &size, NULL, 0) < 0) {
+ /*
+ * This is not fatal -- just means I cant map command strings
+ */
+ free(mapptr);
+ return;
+ }
+ }
+ }
+ } else {
+ RAW_header header;
+ off_t offset;
+
+ RAW_fd = open(RAW_file, O_RDONLY);
+
+ if (RAW_fd < 0) {
+ perror("Can't open RAW file");
+ exit(1);
+ }
+ if (read(RAW_fd, &header, sizeof(RAW_header)) != sizeof(RAW_header)) {
+ perror("read failed");
+ exit(2);
+ }
+ if (header.version_no != RAW_VERSION1) {
+ header.version_no = RAW_VERSION0;
+ header.TOD_secs = time((long *)0);
+ header.TOD_usecs = 0;
+
+ lseek(RAW_fd, (off_t)0, SEEK_SET);
+
+ if (read(RAW_fd, &header.thread_count, sizeof(int)) != sizeof(int)) {
+ perror("read failed");
+ exit(2);
+ }
+ }
+ sample_TOD_secs = header.TOD_secs;
+ sample_TOD_usecs = header.TOD_usecs;
+
+ total_threads = header.thread_count;
+ size = total_threads * sizeof(kd_threadmap);
+
+ if (size) {
+ if ((mapptr = (kd_threadmap *) malloc(size))) {
+ bzero (mapptr, size);
+
+ if (read(RAW_fd, mapptr, size) != size) {
+ free(mapptr);
+ return;
+ }
+ }
+ }
+ if (header.version_no != RAW_VERSION0) {
+ offset = lseek(RAW_fd, (off_t)0, SEEK_CUR);
+ offset = (offset + (4095)) & ~4095;
+
+ lseek(RAW_fd, offset, SEEK_SET);
+ }
+ }
+ for (i = 0; i < total_threads; i++)
+ create_map_entry(mapptr[i].thread, mapptr[i].valid, &mapptr[i].command[0]);
+
+ free(mapptr);
+}
+
+
+void delete_all_map_entries()
+{
+ threadmap_t tme = 0;
+ threadmap_t tme_next = 0;
+ int i;
+
+ for (i = 0; i < HASH_SIZE; i++) {
+
+ for (tme = threadmap_hash[i]; tme; tme = tme_next) {
+ if (tme->tm_setptr)
+ free(tme->tm_setptr);
+ tme_next = tme->tm_next;
+ tme->tm_next = threadmap_freelist;
+ threadmap_freelist = tme;
+ }
+ threadmap_hash[i] = 0;
+ }
+}
+
+
+void create_map_entry(uintptr_t thread, int pid, char *command)
+{
+ threadmap_t tme;
+ int hashid;
+
+ if ((tme = threadmap_freelist))
+ threadmap_freelist = tme->tm_next;
+ else
+ tme = (threadmap_t)malloc(sizeof(struct threadmap));
+
+ tme->tm_thread = thread;
+ tme->tm_setsize = 0;
+ tme->tm_setptr = 0;
+
+ (void)strncpy (tme->tm_command, command, MAXCOMLEN);
+ tme->tm_command[MAXCOMLEN] = '\0';
+
+ hashid = thread & HASH_MASK;
+
+ tme->tm_next = threadmap_hash[hashid];
+ threadmap_hash[hashid] = tme;
+
+ if (pid != 0 && pid != 1) {
+ if (!strncmp(command, "LaunchCFMA", 10))
+ (void)get_real_command_name(pid, tme->tm_command, MAXCOMLEN);
+ }
+}
+
+
+threadmap_t
+find_map_entry(uintptr_t thread)
+{
+ threadmap_t tme;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ for (tme = threadmap_hash[hashid]; tme; tme = tme->tm_next) {
+ if (tme->tm_thread == thread)
+ return (tme);
+ }
+ return (0);
+}
+
+
+void
+delete_map_entry(uintptr_t thread)
+{
+ threadmap_t tme = 0;
+ threadmap_t tme_prev;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ if ((tme = threadmap_hash[hashid])) {
+ if (tme->tm_thread == thread)
+ threadmap_hash[hashid] = tme->tm_next;
+ else {
+ tme_prev = tme;
+
+ for (tme = tme->tm_next; tme; tme = tme->tm_next) {
+ if (tme->tm_thread == thread) {
+ tme_prev->tm_next = tme->tm_next;
+ break;
+ }
+ tme_prev = tme;
+ }
+ }
+ if (tme) {
+ if (tme->tm_setptr)
+ free(tme->tm_setptr);
+
+ tme->tm_next = threadmap_freelist;
+ threadmap_freelist = tme;
+ }
+ }
+}
+
+
+void
+fs_usage_fd_set(uintptr_t thread, unsigned int fd)
+{
+ threadmap_t tme;
+
+ if ((tme = find_map_entry(thread)) == 0)
+ return;
+ /*
+ * If the map is not allocated, then now is the time
+ */
+ if (tme->tm_setptr == (unsigned long *)0) {
+ if ((tme->tm_setptr = (unsigned long *)malloc(FS_USAGE_NFDBYTES(FS_USAGE_FD_SETSIZE))) == 0)
+ return;
+
+ tme->tm_setsize = FS_USAGE_FD_SETSIZE;
+ bzero(tme->tm_setptr, (FS_USAGE_NFDBYTES(FS_USAGE_FD_SETSIZE)));
+ }
+ /*
+ * If the map is not big enough, then reallocate it
+ */
+ while (tme->tm_setsize <= fd) {
+ int n;
+
+ n = tme->tm_setsize * 2;
+ tme->tm_setptr = (unsigned long *)realloc(tme->tm_setptr, (FS_USAGE_NFDBYTES(n)));
+
+ bzero(&tme->tm_setptr[(tme->tm_setsize/FS_USAGE_NFDBITS)], (FS_USAGE_NFDBYTES(tme->tm_setsize)));
+ tme->tm_setsize = n;
+ }
+ /*
+ * set the bit
+ */
+ tme->tm_setptr[fd/FS_USAGE_NFDBITS] |= (1 << ((fd) % FS_USAGE_NFDBITS));
+}
+
+
+/*
+ * Return values:
+ * 0 : File Descriptor bit is not set
+ * 1 : File Descriptor bit is set
+ */
+int
+fs_usage_fd_isset(uintptr_t thread, unsigned int fd)
+{
+ threadmap_t tme;
+ int ret = 0;
+
+ if ((tme = find_map_entry(thread))) {
+ if (tme->tm_setptr && fd < tme->tm_setsize)
+ ret = tme->tm_setptr[fd/FS_USAGE_NFDBITS] & (1 << (fd % FS_USAGE_NFDBITS));
+ }
+ return (ret);
+}
+
+
+void
+fs_usage_fd_clear(uintptr_t thread, unsigned int fd)
+{
+ threadmap_t tme;
+
+ if ((tme = find_map_entry(thread))) {
+ if (tme->tm_setptr && fd < tme->tm_setsize)
+ tme->tm_setptr[fd/FS_USAGE_NFDBITS] &= ~(1 << (fd % FS_USAGE_NFDBITS));
+ }
+}
+
+
+
+void
+argtopid(char *str)
+{
+ char *cp;
+ int ret;
+ int i;
+
+ ret = (int)strtol(str, &cp, 10);
+
+ if (cp == str || *cp) {
+ /*
+ * Assume this is a command string and find matching pids
+ */
+ if (!kp_buffer)
+ find_proc_names();
+
+ for (i = 0; i < kp_nentries && num_of_pids < (MAX_PIDS - 1); i++) {
+ if (kp_buffer[i].kp_proc.p_stat == 0)
+ continue;
+ else {
+ if (!strncmp(str, kp_buffer[i].kp_proc.p_comm,
+ sizeof(kp_buffer[i].kp_proc.p_comm) -1))
+ pids[num_of_pids++] = kp_buffer[i].kp_proc.p_pid;
+ }
+ }
+ }
+ else if (num_of_pids < (MAX_PIDS - 1))
+ pids[num_of_pids++] = ret;
+}
+
+
+
+void
+lookup_name(uint64_t user_addr, char **type, char **name)
+{
+ int i;
+ int start, last;
+
+ *name = NULL;
+ *type = NULL;
+
+ if (numFrameworks) {
+
+ if ((user_addr >= framework32.b_address && user_addr < framework32.e_address) ||
+ (user_addr >= framework64.b_address && user_addr < framework64.e_address)) {
+
+ start = 0;
+ last = numFrameworks;
+
+ for (i = numFrameworks / 2; start < last; i = start + ((last - start) / 2)) {
+ if (user_addr > frameworkInfo[i].e_address)
+ start = i+1;
+ else
+ last = i;
+ }
+ if (start < numFrameworks &&
+ user_addr >= frameworkInfo[start].b_address && user_addr < frameworkInfo[start].e_address) {
+ *type = frameworkType[frameworkInfo[start].r_type];
+ *name = frameworkInfo[start].name;
+ }
+ }
+ }
+}
+
+
+/*
+ * Comparison routines for sorting
+ */
+static int compareFrameworkAddress(const void *aa, const void *bb)
+{
+ LibraryInfo *a = (LibraryInfo *)aa;
+ LibraryInfo *b = (LibraryInfo *)bb;
+
+ if (a->b_address < b->b_address) return -1;
+ if (a->b_address == b->b_address) return 0;
+ return 1;
+}
+
+
+int scanline(char *inputstring, char **argv, int maxtokens)
+{
+ int n = 0;
+ char **ap = argv, *p, *val;
+
+ for (p = inputstring; n < maxtokens && p != NULL; ) {
+
+ while ((val = strsep(&p, " \t")) != NULL && *val == '\0');
+
+ *ap++ = val;
+ n++;
+ }
+ *ap = 0;
+
+ return n;
+}
+
+
+int ReadSharedCacheMap(const char *path, LibraryRange *lr, char *linkedit_name)
+{
+ uint64_t b_address, e_address;
+ char buf[1024];
+ char *fnp;
+ FILE *fd;
+ char frameworkName[256];
+ char *tokens[64];
+ int ntokens;
+ int type;
+ int linkedit_found = 0;
+ char *substring, *ptr;
+
+ bzero(buf, sizeof(buf));
+ bzero(tokens, sizeof(tokens));
+
+ lr->b_address = 0;
+ lr->e_address = 0;
+
+ if ((fd = fopen(path, "r")) == 0)
+ return 0;
+
+ while (fgets(buf, 1023, fd)) {
+ if (strncmp(buf, "mapping", 7))
+ break;
+ }
+ buf[strlen(buf)-1] = 0;
+
+ frameworkName[0] = 0;
+
+ for (;;) {
+ /*
+ * Extract lib name from path name
+ */
+ if ((substring = strrchr(buf, '.')))
+ {
+ /*
+ * There is a ".": name is whatever is between the "/" around the "."
+ */
+ while ( *substring != '/') /* find "/" before "." */
+ substring--;
+ substring++;
+
+ strncpy(frameworkName, substring, 256); /* copy path from "/" */
+ frameworkName[255] = 0;
+ substring = frameworkName;
+
+ while ( *substring != '/' && *substring) /* find "/" after "." and stop string there */
+ substring++;
+ *substring = 0;
+ }
+ else
+ {
+ /*
+ * No ".": take segment after last "/"
+ */
+ ptr = buf;
+ substring = ptr;
+
+ while (*ptr) {
+ if (*ptr == '/')
+ substring = ptr + 1;
+ ptr++;
+ }
+ strncpy(frameworkName, substring, 256);
+ frameworkName[255] = 0;
+ }
+ fnp = (char *)malloc(strlen(frameworkName) + 1);
+ strcpy(fnp, frameworkName);
+
+ while (fgets(buf, 1023, fd) && numFrameworks < (MAXINDEX - 2)) {
+ /*
+ * Get rid of EOL
+ */
+ buf[strlen(buf)-1] = 0;
+
+ ntokens = scanline(buf, tokens, 64);
+
+ if (ntokens < 4)
+ continue;
+
+ if (strncmp(tokens[0], "__TEXT", 6) == 0)
+ type = TEXT_R;
+ else if (strncmp(tokens[0], "__DATA", 6) == 0)
+ type = DATA_R;
+ else if (strncmp(tokens[0], "__OBJC", 6) == 0)
+ type = OBJC_R;
+ else if (strncmp(tokens[0], "__IMPORT", 8) == 0)
+ type = IMPORT_R;
+ else if (strncmp(tokens[0], "__UNICODE", 9) == 0)
+ type = UNICODE_R;
+ else if (strncmp(tokens[0], "__IMAGE", 7) == 0)
+ type = IMAGE_R;
+ else if (strncmp(tokens[0], "__LINKEDIT", 10) == 0)
+ type = LINKEDIT_R;
+ else
+ type = -1;
+
+ if (type == LINKEDIT_R && linkedit_found)
+ break;
+
+ if (type != -1) {
+ b_address = strtoull(tokens[1], 0, 16);
+ e_address = strtoull(tokens[3], 0, 16);
+
+ frameworkInfo[numFrameworks].b_address = b_address;
+ frameworkInfo[numFrameworks].e_address = e_address;
+ frameworkInfo[numFrameworks].r_type = type;
+
+ if (type == LINKEDIT_R) {
+ frameworkInfo[numFrameworks].name = linkedit_name;
+ linkedit_found = 1;
+ } else
+ frameworkInfo[numFrameworks].name = fnp;
+#if 0
+ printf("%s(%d): %qx-%qx\n", frameworkInfo[numFrameworks].name, type, b_address, e_address);
+#endif
+ if (lr->b_address == 0 || b_address < lr->b_address)
+ lr->b_address = b_address;
+
+ if (lr->e_address == 0 || e_address > lr->e_address)
+ lr->e_address = e_address;
+
+ numFrameworks++;
+ }
+ if (type == LINKEDIT_R)
+ break;
+ }
+ if (fgets(buf, 1023, fd) == 0)
+ break;
+
+ buf[strlen(buf)-1] = 0;
+ }
+ fclose(fd);
+
+#if 0
+ printf("%s range, %qx-%qx\n", path, lr->b_address, lr->e_address);
+#endif
+ return 1;
+}
+
+
+void
+SortFrameworkAddresses()
+{
+
+ frameworkInfo[numFrameworks].b_address = frameworkInfo[numFrameworks - 1].b_address + 0x800000;
+ frameworkInfo[numFrameworks].e_address = frameworkInfo[numFrameworks].b_address;
+ frameworkInfo[numFrameworks].name = (char *)0;
+
+ qsort(frameworkInfo, numFrameworks, sizeof(LibraryInfo), compareFrameworkAddress);
+}
+
+
+struct diskio *insert_diskio(int type, int bp, int dev, int blkno, int io_size, uintptr_t thread, double curtime)
+{
+ struct diskio *dio;
+ threadmap_t tme;
+
+ if ((dio = free_diskios))
+ free_diskios = dio->next;
+ else {
+ if ((dio = (struct diskio *)malloc(sizeof(struct diskio))) == NULL)
+ return (NULL);
+ }
+ dio->prev = NULL;
+
+ dio->type = type;
+ dio->bp = bp;
+ dio->dev = dev;
+ dio->blkno = blkno;
+ dio->iosize = io_size;
+ dio->issued_time = curtime;
+ dio->issuing_thread = thread;
+
+ dio->bc_info = 0x0;
+
+ if ((tme = find_map_entry(thread))) {
+ strncpy(dio->issuing_command, tme->tm_command, MAXCOMLEN);
+ dio->issuing_command[MAXCOMLEN-1] = '\0';
+ } else
+ strcpy(dio->issuing_command, "");
+
+ dio->next = busy_diskios;
+ if (dio->next)
+ dio->next->prev = dio;
+ busy_diskios = dio;
+
+ return (dio);
+}
+
+struct diskio *find_diskio(int bp) {
+ struct diskio *dio;
+
+ for (dio = busy_diskios; dio; dio = dio->next) {
+ if (dio->bp == bp)
+ return (dio);
+ }
+
+ 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;
+}
+
+
+void free_diskio(struct diskio *dio)
+{
+ dio->next = free_diskios;
+ free_diskios = dio;
+}
+
+
+void print_diskio(struct diskio *dio)
+{
+ char *p = NULL;
+ int len = 0;
+ int type;
+ int format = FMT_DISKIO;
+ char buf[64];
+
+ type = dio->type;
+ dio->is_meta = 0;
+
+ if ((type & P_CS_Class) == P_CS_Class) {
+
+ switch (type) {
+
+ case P_CS_ReadChunk:
+ p = " RdChunkCS";
+ len = 13;
+ format = FMT_DISKIO_CS;
+ break;
+ case P_CS_WriteChunk:
+ p = " WrChunkCS";
+ len = 13;
+ format = FMT_DISKIO_CS;
+ break;
+ case P_CS_MetaRead:
+ p = " RdMetaCS";
+ len = 10;
+ format = FMT_DISKIO_CS;
+ break;
+ case P_CS_MetaWrite:
+ p = " WrMetaCS";
+ len = 10;
+ format = FMT_DISKIO_CS;
+ break;
+ case P_CS_TransformRead:
+ p = " RdBgTfCS";
+ len = 10;
+ break;
+ case P_CS_TransformWrite:
+ p = " WrBgTfCS";
+ len = 10;
+ break;
+ case P_CS_MigrationRead:
+ p = " RdBgMigrCS";
+ len = 12;
+ break;
+ case P_CS_MigrationWrite:
+ p = " WrBgMigrCS";
+ len = 12;
+ break;
+ }
+ strncpy(buf, p, len);
+ } else {
+
+ switch (type & P_DISKIO_TYPE) {
+
+ case P_RdMeta:
+ dio->is_meta = 1;
+ p = " RdMeta";
+ len = 8;
+ break;
+ case P_WrMeta:
+ dio->is_meta = 1;
+ p = " WrMeta";
+ len = 8;
+ break;
+ case P_RdData:
+ p = " RdData";
+ len = 8;
+ break;
+ case P_WrData:
+ p = " WrData";
+ len = 8;
+ break;
+ case P_PgIn:
+ p = " PgIn";
+ len = 6;
+ break;
+ case P_PgOut:
+ p = " PgOut";
+ len = 7;
+ break;
+ default:
+ p = " ";
+ len = 2;
+ break;
+ }
+ strncpy(buf, p, len);
+
+ buf[len++] = '[';
+
+ if (type & P_DISKIO_ASYNC)
+ buf[len++] = 'A';
+ else
+ buf[len++] = 'S';
+
+ if (type & P_DISKIO_NOCACHE)
+ buf[len++] = 'N';
+
+ int tier = (type & P_DISKIO_TIER_MASK) >> P_DISKIO_TIER_SHIFT;
+ if (tier > 0) {
+ buf[len++] = 'T';
+ if (tier > 0 && tier < 10)
+ buf[len++] = '0' + tier;
+ }
+
+ if (type & P_DISKIO_PASSIVE)
+ buf[len++] = 'P';
+
+
+ buf[len++] = ']';
+ }
+ buf[len] = 0;
+
+ if (check_filter_mode(NULL, type, 0, 0, buf))
+ format_print(NULL, buf, dio->issuing_thread, type, 0, 0, 0, 0, format, dio->completed_time, dio->issued_time, 1, "", dio);
+}
+
+
+void cache_disk_names()
+{
+ struct stat st;
+ DIR *dirp = NULL;
+ struct dirent *dir;
+ struct diskrec *dnp;
+
+
+ if ((dirp = opendir("/dev")) == NULL)
+ return;
+
+ while ((dir = readdir(dirp)) != NULL) {
+ char nbuf[MAXPATHLEN];
+
+ if (dir->d_namlen < 5 || strncmp("disk", dir->d_name, 4))
+ continue;
+
+ snprintf(nbuf, MAXPATHLEN, "%s/%s", "/dev", dir->d_name);
+
+ if (stat(nbuf, &st) < 0)
+ continue;
+
+ if ((dnp = (struct diskrec *)malloc(sizeof(struct diskrec))) == NULL)
+ continue;
+
+ if ((dnp->diskname = (char *)malloc(dir->d_namlen + 1)) == NULL) {
+ free(dnp);
+ continue;
+ }
+ strncpy(dnp->diskname, dir->d_name, dir->d_namlen);
+ dnp->diskname[dir->d_namlen] = 0;
+ dnp->dev = st.st_rdev;
+
+ dnp->next = disk_list;
+ disk_list = dnp;
+ }
+ (void) closedir(dirp);
+}
+
+
+void recache_disk_names()
+{
+ struct diskrec *dnp, *next_dnp;
+
+ for (dnp = disk_list; dnp; dnp = next_dnp) {
+ next_dnp = dnp->next;
+
+ free(dnp->diskname);
+ free(dnp);
+ }
+ disk_list = NULL;
+
+ cache_disk_names();
+}
+
+
+char *find_disk_name(int dev)
+{
+ struct diskrec *dnp;
+ int i;
+
+ if (dev == NFS_DEV)
+ return ("NFS");
+
+ if (dev == CS_DEV)
+ return ("CS");
+
+ for (i = 0; i < 2; i++) {
+ for (dnp = disk_list; dnp; dnp = dnp->next) {
+ if (dnp->dev == dev)
+ return (dnp->diskname);
+ }
+ recache_disk_names();
+ }
+ return ("NOTFOUND");
+}
+
+
+char *generate_cs_disk_name(int dev, char *s)
+{
+ if (dev == -1)
+ return ("UNKNOWN");
+
+ sprintf(s, "disk%ds%d", (dev >> 16) & 0xffff, dev & 0xffff);
+
+ return (s);
+}
+
+
+
+/*
+ * 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)
+{
+ int ret = 0;
+ int network_fd_isset = 0;
+ unsigned int fd;
+
+ /* 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 (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);
+ }
+
+ if (filter_mode & PATHNAME_FILTER) {
+ if (ti && ti->lookups[0].pathname[0])
+ return(1);
+ if (type == BSC_close || type == BSC_close_nocancel ||
+ type == BSC_guarded_close_np)
+ return(1);
+ }
+
+ if (ti == (struct th_info *)0) {
+ if (filter_mode & FILESYS_FILTER)
+ return(1);
+ return(0);
+ }
+
+ switch (type) {
+
+ case BSC_close:
+ case BSC_close_nocancel:
+ case BSC_guarded_close_np:
+ fd = ti->arg1;
+ network_fd_isset = fs_usage_fd_isset(ti->thread, fd);
+
+ if (error == 0)
+ fs_usage_fd_clear(ti->thread,fd);
+
+ if (network_fd_isset) {
+ if (filter_mode & NETWORK_FILTER)
+ ret = 1;
+ } else
+ if (filter_mode & FILESYS_FILTER)
+ ret = 1;
+ break;
+
+ case BSC_read:
+ case BSC_write:
+ case BSC_read_nocancel:
+ case BSC_write_nocancel:
+ /*
+ * we don't care about error in these cases
+ */
+ fd = ti->arg1;
+ network_fd_isset = fs_usage_fd_isset(ti->thread, fd);
+
+ if (network_fd_isset) {
+ if (filter_mode & NETWORK_FILTER)
+ ret = 1;
+ } else
+ if (filter_mode & FILESYS_FILTER)
+ ret = 1;
+ break;
+
+ case BSC_accept:
+ case BSC_accept_nocancel:
+ case BSC_socket:
+ fd = retval;
+
+ if (error == 0)
+ fs_usage_fd_set(ti->thread, fd);
+ if (filter_mode & NETWORK_FILTER)
+ ret = 1;
+ break;
+
+ case BSC_recvfrom:
+ case BSC_sendto:
+ case BSC_recvmsg:
+ case BSC_sendmsg:
+ case BSC_connect:
+ case BSC_bind:
+ case BSC_listen:
+ case BSC_sendto_nocancel:
+ case BSC_recvfrom_nocancel:
+ case BSC_recvmsg_nocancel:
+ case BSC_sendmsg_nocancel:
+ case BSC_connect_nocancel:
+ fd = ti->arg1;
+
+ if (error == 0)
+ fs_usage_fd_set(ti->thread, fd);
+ if (filter_mode & NETWORK_FILTER)
+ ret = 1;
+ break;
+
+ case BSC_select:
+ case BSC_select_nocancel:
+ case BSC_socketpair:
+ /*
+ * Cannot determine info about file descriptors
+ */
+ if (filter_mode & NETWORK_FILTER)
+ ret = 1;
+ break;
+
+ case BSC_dup:
+ case BSC_dup2:
+ /*
+ * We track these cases for fd state only
+ */
+ fd = ti->arg1;
+ network_fd_isset = fs_usage_fd_isset(ti->thread, fd);
+
+ if (error == 0 && network_fd_isset) {
+ /*
+ * then we are duping a socket descriptor
+ */
+ fd = retval; /* the new fd */
+ fs_usage_fd_set(ti->thread, fd);
+ }
+ break;
+
+ default:
+ if (filter_mode & FILESYS_FILTER)
+ ret = 1;
+ break;
+ }
+
+ return(ret);
+}
+
+/*
+ * Allocate a buffer that is large enough to hold the maximum arguments
+ * to execve(). This is used when getting the arguments to programs
+ * when we see LaunchCFMApps. If this fails, it is not fatal, we will
+ * simply not resolve the command name.
+ */
+
+void
+init_arguments_buffer()
+{
+ int mib[2];
+ size_t size;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_ARGMAX;
+ size = sizeof(argmax);
+
+ if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1)
+ return;
+#if 1
+ /* Hack to avoid kernel bug. */
+ if (argmax > 8192) {
+ argmax = 8192;
+ }
+#endif
+ arguments = (char *)malloc(argmax);
+}
+
+
+int
+get_real_command_name(int pid, char *cbuf, int csize)
+{
+ /*
+ * Get command and arguments.
+ */
+ char *cp;
+ int mib[4];
+ char *command_beg, *command, *command_end;
+
+ if (cbuf == NULL)
+ return(0);
+
+ if (arguments)
+ bzero(arguments, argmax);
+ else
+ return(0);
+
+ /*
+ * A sysctl() is made to find out the full path that the command
+ * was called with.
+ */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROCARGS2;
+ mib[2] = pid;
+ mib[3] = 0;
+
+ if (sysctl(mib, 3, arguments, (size_t *)&argmax, NULL, 0) < 0)
+ return(0);
+
+ /*
+ * Skip the saved exec_path
+ */
+ for (cp = arguments; cp < &arguments[argmax]; cp++) {
+ if (*cp == '\0') {
+ /*
+ * End of exec_path reached
+ */
+ break;
+ }
+ }
+ if (cp == &arguments[argmax])
+ return(0);
+
+ /*
+ * Skip trailing '\0' characters
+ */
+ for (; cp < &arguments[argmax]; cp++) {
+ if (*cp != '\0') {
+ /*
+ * Beginning of first argument reached
+ */
+ break;
+ }
+ }
+ if (cp == &arguments[argmax])
+ return(0);
+
+ command_beg = cp;
+ /*
+ * Make sure that the command is '\0'-terminated. This protects
+ * against malicious programs; under normal operation this never
+ * ends up being a problem..
+ */
+ for (; cp < &arguments[argmax]; cp++) {
+ if (*cp == '\0') {
+ /*
+ * End of first argument reached
+ */
+ break;
+ }
+ }
+ if (cp == &arguments[argmax])
+ return(0);
+
+ command_end = command = cp;
+
+ /*
+ * Get the basename of command
+ */
+ for (command--; command >= command_beg; command--) {
+ if (*command == '/') {
+ command++;
+ break;
+ }
+ }
+ (void) strncpy(cbuf, (char *)command, csize);
+ cbuf[csize-1] = '\0';
+
+ return(1);
+}
--- /dev/null
+%{
+/*
+ * Copyright is disclaimed as to the contents of this file.
+ *
+ * $FreeBSD: src/usr.bin/getconf/confstr.gperf,v 1.5 2003/08/22 17:32:07 markm Exp $
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <unistd.h>
+
+#include "getconf.h"
+
+/*
+ * Override gperf's built-in external scope.
+ */
+static const struct map *in_word_set(const char *str);
+
+/*
+ * The Standard seems a bit ambiguous over whether the POSIX_V6_*
+ * are specified with or without a leading underscore, so we just
+ * use both.
+ */
+%}
+struct map { const char *name; int key; int valid; };
+%%
+PATH, _CS_PATH
+POSIX_V6_ILP32_OFF32_CFLAGS, _CS_POSIX_V6_ILP32_OFF32_CFLAGS
+POSIX_V6_ILP32_OFF32_LDFLAGS, _CS_POSIX_V6_ILP32_OFF32_LDFLAGS
+POSIX_V6_ILP32_OFF32_LIBS, _CS_POSIX_V6_ILP32_OFF32_LIBS
+POSIX_V6_ILP32_OFFBIG_CFLAGS, _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS
+POSIX_V6_ILP32_OFFBIG_LDFLAGS, _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS
+POSIX_V6_ILP32_OFFBIG_LIBS, _CS_POSIX_V6_ILP32_OFFBIG_LIBS
+POSIX_V6_LP64_OFF64_CFLAGS, _CS_POSIX_V6_LP64_OFF64_CFLAGS
+POSIX_V6_LP64_OFF64_LDFLAGS, _CS_POSIX_V6_LP64_OFF64_LDFLAGS
+POSIX_V6_LP64_OFF64_LIBS, _CS_POSIX_V6_LP64_OFF64_LIBS
+POSIX_V6_LPBIG_OFFBIG_CFLAGS, _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS
+POSIX_V6_LPBIG_OFFBIG_LDFLAGS, _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS
+POSIX_V6_LPBIG_OFFBIG_LIBS, _CS_POSIX_V6_LPBIG_OFFBIG_LIBS
+POSIX_V6_WIDTH_RESTRICTED_ENVS, _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS
+_POSIX_V6_ILP32_OFF32_CFLAGS, _CS_POSIX_V6_ILP32_OFF32_CFLAGS
+_POSIX_V6_ILP32_OFF32_LDFLAGS, _CS_POSIX_V6_ILP32_OFF32_LDFLAGS
+_POSIX_V6_ILP32_OFF32_LIBS, _CS_POSIX_V6_ILP32_OFF32_LIBS
+_POSIX_V6_ILP32_OFFBIG_CFLAGS, _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS
+_POSIX_V6_ILP32_OFFBIG_LDFLAGS, _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS
+_POSIX_V6_ILP32_OFFBIG_LIBS, _CS_POSIX_V6_ILP32_OFFBIG_LIBS
+_POSIX_V6_LP64_OFF64_CFLAGS, _CS_POSIX_V6_LP64_OFF64_CFLAGS
+_POSIX_V6_LP64_OFF64_LDFLAGS, _CS_POSIX_V6_LP64_OFF64_LDFLAGS
+_POSIX_V6_LP64_OFF64_LIBS, _CS_POSIX_V6_LP64_OFF64_LIBS
+_POSIX_V6_LPBIG_OFFBIG_CFLAGS, _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS
+_POSIX_V6_LPBIG_OFFBIG_LDFLAGS, _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS
+_POSIX_V6_LPBIG_OFFBIG_LIBS, _CS_POSIX_V6_LPBIG_OFFBIG_LIBS
+_POSIX_V6_WIDTH_RESTRICTED_ENVS, _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS
+DARWIN_USER_DIR, _CS_DARWIN_USER_DIR
+DARWIN_USER_TEMP_DIR, _CS_DARWIN_USER_TEMP_DIR
+DARWIN_USER_CACHE_DIR, _CS_DARWIN_USER_CACHE_DIR
+%%
+int
+find_confstr(const char *name, int *key)
+{
+ const struct map *rv;
+
+ rv = in_word_set(name);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *key = rv->key;
+ return 1;
+ }
+ return -1;
+ }
+ return 0;
+}
--- /dev/null
+#!/usr/bin/awk -f
+# $FreeBSD: src/usr.bin/getconf/fake-gperf.awk,v 1.3 2003/08/22 17:32:07 markm Exp $
+BEGIN {
+ state = 0;
+ struct_seen = "";
+}
+/^%{$/ && state == 0 {
+ state = 1;
+ next;
+}
+/^%}$/ && state == 1 {
+ state = 0;
+ next;
+}
+state == 1 { print; next; }
+/^struct/ && state == 0 {
+ print;
+ struct_seen = $2;
+ next;
+}
+/^%%$/ && state == 0 {
+ state = 2;
+ if (struct_seen !~ /^$/) {
+ print "static const struct", struct_seen, "wordlist[] = {";
+ } else {
+ print "static const struct map {";
+ print "\tconst char *name;";
+ print "\tint key;";
+ print "\tint valid;";
+ print "} wordlist[] = {";
+ struct_seen = "map";
+ }
+ next;
+}
+/^%%$/ && state == 2 {
+ state = 3;
+ print "\t{ NULL, 0, 0 }";
+ print "};";
+ print "#define\tNWORDS\t(sizeof(wordlist)/sizeof(wordlist[0]) - 1)";
+ print "static const struct map *";
+ print "in_word_set(const char *word)";
+ print "{";
+ print "\tconst struct", struct_seen, "*mp;";
+ print "";
+ print "\tfor (mp = wordlist; mp < &wordlist[NWORDS]; mp++) {";
+ print "\t\tif (strcmp(word, mp->name) == 0)";
+ print "\t\t\treturn (mp);";
+ print "\t}";
+ print "\treturn (NULL);";
+ print "}";
+ print "";
+ next;
+}
+state == 2 && NF == 2 {
+ name = substr($1, 1, length($1) - 1);
+ printf "#ifdef %s\n", $2;
+ printf "\t{ \"%s\", %s, 1 },\n", name, $2;
+ print "#else";
+ printf "\t{ \"%s\", 0, 0 },\n", name, $2;
+ print "#endif"
+ next;
+}
+state == 3 { print; next; }
+{
+ # eat anything not matched.
+}
--- /dev/null
+.\"
+.\" Copyright 2000 Massachusetts Institute of Technology
+.\"
+.\" Permission to use, copy, modify, and distribute this software and
+.\" its documentation for any purpose and without fee is hereby
+.\" granted, provided that both the above copyright notice and this
+.\" permission notice appear in all copies, that both the above
+.\" copyright notice and this permission notice appear in all
+.\" supporting documentation, and that the name of M.I.T. not be used
+.\" in advertising or publicity pertaining to distribution of the
+.\" software without specific, written prior permission. M.I.T. makes
+.\" no representations about the suitability of this software for any
+.\" purpose. It is provided "as is" without express or implied
+.\" warranty.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+.\" SHALL M.I.T. 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.
+.\"
+.\" $FreeBSD: src/usr.bin/getconf/getconf.1,v 1.14 2005/01/18 13:43:49 ru Exp $
+.\"
+.Dd September 18, 2002
+.Dt GETCONF 1
+.Os
+.Sh NAME
+.Nm getconf
+.Nd retrieve standard configuration variables
+.Sh SYNOPSIS
+.Nm
+.Op Fl v Ar environment
+.Ar path_var
+.Ar file
+.Nm
+.Op Fl v Ar environment
+.Ar system_var
+.Sh DESCRIPTION
+The
+.Nm
+utility prints the value of a
+.Tn POSIX
+or
+.Tn X/Open
+path or system configuration variable to the standard output.
+If the specified variable is undefined, the string
+.Dq Li undefined
+is output.
+.Pp
+The first form of the command, with two mandatory
+arguments, retrieves file- and file system-specific
+configuration variables using
+.Xr pathconf 2 .
+The second form, with a single argument, retrieves system
+configuration variables using
+.Xr confstr 3
+and
+.Xr sysconf 3 ,
+depending on the type of variable.
+As an extension, the second form can also be used to query static limits from
+.In limits.h .
+.Pp
+All
+.Xr sysconf 3
+and
+.Xr pathconf 2
+variables use the same name as the manifest constants defined in
+the relevant standard C-language bindings, including any leading
+underscore or prefix.
+That is to say,
+.Ar system_var
+might be
+.Dv ARG_MAX
+or
+.Dv _POSIX_VERSION ,
+as opposed to the
+.Xr sysconf 3
+names
+.Dv _SC_ARG_MAX
+or
+.Dv _SC_POSIX_VERSION .
+Variables retrieved from
+.Xr confstr 3
+have the leading
+.Ql _CS_
+stripped off; thus,
+.Dv _CS_PATH
+is queried by a
+.Ar system_var
+of
+.Dq Li PATH .
+.Ss Programming Environments
+The
+.Fl v Ar environment
+option specifies a
+.St -p1003.1-2001
+programming environment under which the values are to be queried.
+This option currently does nothing, but may in the future be used
+to select between 32-bit and 64-bit execution environments on platforms
+which support both.
+Specifying an environment which is not supported on the current execution
+platform gives undefined results.
+.Pp
+The standard programming environments are as follows:
+.Bl -tag -width ".Li POSIX_V6_LPBIG_OFFBIG" -offset indent
+.It Li POSIX_V6_ILP32_OFF32
+Exactly 32-bit integer, long, pointer, and file offset.
+.Sy Supported platforms :
+None.
+.It Li POSIX_V6_ILP32_OFFBIG
+Exactly 32-bit integer, long, and pointer; at least 64-bit file offset.
+.Sy Supported platforms :
+.Tn IA32 ,
+.Tn PowerPC .
+.It Li POSIX_V6_LP64_OFF64
+Exactly 32-bit integer; exactly 64-bit long, pointer, and file offset.
+.Sy Supported platforms :
+.Tn Alpha ,
+.Tn SPARC64 .
+.It Li POSIX_V6_LPBIG_OFFBIG
+At least 32-bit integer; at least 64-bit long, pointer, and file offset.
+.Sy Supported platforms :
+None.
+.El
+.Pp
+The command:
+.Pp
+.Dl "getconf POSIX_V6_WIDTH_RESTRICTED_ENVS"
+.Pp
+returns a newline-separated list of environments in which the width
+of certain fundamental types is no greater than the width of the native
+C type
+.Vt long .
+At present, all programming environments supported by
+.Fx
+have this property.
+Several of the
+.Xr confstr 3
+variables provide information on the necessary compiler and linker flags
+to use the standard programming environments described above.
+.Pp
+Many of these values are also available through the
+.Xr sysctl 8
+mechanism.
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+The command:
+.Pp
+.Dl "getconf PATH"
+.Pp
+will display the system default setting for the
+.Ev PATH
+environment variable.
+.Pp
+The command:
+.Pp
+.Dl "getconf NAME_MAX /tmp"
+.Pp
+will display the maximum length of a filename in the
+.Pa /tmp
+directory.
+.Pp
+The command:
+.Pp
+.Dl "getconf -v POSIX_V6_LPBIG_OFFBIG LONG_MAX"
+.Pp
+will display the maximum value of the C type
+.Vt long
+in the
+.Li POSIX_V6_LPBIG_OFFBIG
+programming environment,
+if the system supports that environment.
+.Sh DIAGNOSTICS
+Use of a
+.Ar system_var
+or
+.Ar path_var
+which is completely unrecognized is considered an error,
+causing a diagnostic message to be written to standard error.
+One
+which is known but merely undefined does not result in an error
+indication.
+The
+.Nm
+utility recognizes all of the variables defined for
+.St -p1003.1-2001 ,
+including those which are not currently implemented.
+.Sh SEE ALSO
+.Xr pathconf 2 ,
+.Xr confstr 3 ,
+.Xr sysconf 3 ,
+.Xr sysctl 8
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be compliant with
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Garrett A. Wollman Aq wollman@lcs.mit.edu
--- /dev/null
+/*
+ * Copyright 2000 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/getconf/getconf.c,v 1.10 2006/12/06 12:00:26 maxim Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "getconf.h"
+
+static void do_confstr(const char *name, int key);
+static void do_sysconf(const char *name, int key);
+static void do_pathconf(const char *name, int key, const char *path);
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+"usage: getconf [-v prog_env] system_var\n"
+" getconf [-v prog_env] path_var pathname\n");
+ exit(EX_USAGE);
+}
+
+int
+main(int argc, char **argv)
+{
+ int c, key, valid;
+ const char *name, *vflag, *alt_path;
+ intmax_t limitval;
+
+ vflag = NULL;
+ while ((c = getopt(argc, argv, "v:")) != -1) {
+ switch (c) {
+ case 'v':
+ vflag = optarg;
+ break;
+
+ default:
+ usage();
+ }
+ }
+
+ if ((name = argv[optind]) == NULL)
+ usage();
+
+ if (vflag != NULL) {
+ if ((valid = find_progenv(vflag, &alt_path)) == 0)
+ errx(EX_USAGE, "invalid programming environment %s",
+ vflag);
+ if (valid > 0 && alt_path != NULL) {
+ if (argv[optind + 1] == NULL)
+ execl(alt_path, "getconf", argv[optind],
+ (char *)NULL);
+ else
+ execl(alt_path, "getconf", argv[optind],
+ argv[optind + 1], (char *)NULL);
+
+ err(EX_OSERR, "execl: %s", alt_path);
+ }
+ if (valid < 0)
+ errx(EX_UNAVAILABLE, "environment %s is not available",
+ vflag);
+ }
+
+ if (argv[optind + 1] == NULL) { /* confstr or sysconf */
+ if ((valid = find_limit(name, &limitval)) != 0) {
+ if (valid > 0)
+ printf("%" PRIdMAX "\n", limitval);
+ else
+ printf("undefined\n");
+
+ return 0;
+ }
+ if ((valid = find_confstr(name, &key)) != 0) {
+ if (valid > 0)
+ do_confstr(name, key);
+ else
+ printf("undefined\n");
+ } else {
+ valid = find_sysconf(name, &key);
+ if (valid > 0) {
+ do_sysconf(name, key);
+ } else if (valid < 0) {
+ printf("undefined\n");
+ } else
+ errx(EX_USAGE,
+ "no such configuration parameter `%s'",
+ name);
+ }
+ } else {
+ valid = find_pathconf(name, &key);
+ if (valid != 0) {
+ if (valid > 0)
+ do_pathconf(name, key, argv[optind + 1]);
+ else
+ printf("undefined\n");
+ } else
+ errx(EX_USAGE,
+ "no such path configuration parameter `%s'",
+ name);
+ }
+ return 0;
+}
+
+static void
+do_confstr(const char *name, int key)
+{
+ size_t len;
+ int savederr;
+
+ savederr = errno;
+ errno = 0;
+ len = confstr(key, 0, 0);
+ if (len == 0) {
+ if (errno)
+ err(EX_OSERR, "confstr: %s", name);
+ else
+ printf("undefined\n");
+ } else {
+ char buf[len + 1];
+
+ confstr(key, buf, len);
+ printf("%s\n", buf);
+ }
+ errno = savederr;
+}
+
+static void
+do_sysconf(const char *name, int key)
+{
+ long value;
+
+ errno = 0;
+ value = sysconf(key);
+ if (value == -1 && errno != 0)
+ err(EX_OSERR, "sysconf: %s", name);
+ else if (value == -1)
+ printf("undefined\n");
+ else
+ printf("%ld\n", value);
+}
+
+static void
+do_pathconf(const char *name, int key, const char *path)
+{
+ long value;
+
+ errno = 0;
+ value = pathconf(path, key);
+ if (value == -1 && errno != 0)
+ err(EX_OSERR, "pathconf: %s", name);
+ else if (value == -1)
+ printf("undefined\n");
+ else
+ printf("%ld\n", value);
+}
+
--- /dev/null
+/*
+ * Copyright 2000 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. 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.
+ *
+ * $FreeBSD: src/usr.bin/getconf/getconf.h,v 1.4 2002/10/27 04:14:08 wollman Exp $
+ */
+
+#ifdef STABLE
+typedef long long intmax_t;
+#define PRIdMAX "lld"
+#else
+#include <inttypes.h>
+#endif
+
+int find_confstr(const char *name, int *key);
+int find_limit(const char *name, intmax_t *value);
+int find_pathconf(const char *name, int *key);
+int find_progenv(const char *name, const char **alt_path);
+int find_sysconf(const char *name, int *key);
--- /dev/null
+%{
+/*
+ * Copyright is disclaimed as to the contents of this file.
+ *
+ * $FreeBSD: src/usr.bin/getconf/limits.gperf,v 1.2 2003/08/22 17:32:07 markm Exp $
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <limits.h>
+#ifdef APPLE_GETCONF_UNDERSCORE
+#include <alloca.h>
+#endif /* APPLE_GETCONF_UNDERSCORE */
+
+#include "getconf.h"
+
+/*
+ * Override gperf's built-in external scope.
+ */
+static const struct map *in_word_set(const char *str);
+
+%}
+struct map { const char *name; intmax_t value; int valid; };
+%%
+_POSIX_AIO_LISTIO_MAX, _POSIX_AIO_LISTIO_MAX
+_POSIX_AIO_MAX, _POSIX_AIO_MAX
+_POSIX_ARG_MAX, _POSIX_ARG_MAX
+_POSIX_CHILD_MAX, _POSIX_CHILD_MAX
+_POSIX_CLOCKRES_MIN, _POSIX_CLOCKRES_MIN
+_POSIX_DELAYTIMER_MAX, _POSIX_DELAYTIMER_MAX
+_POSIX_HOST_NAME_MAX, _POSIX_HOST_NAME_MAX
+_POSIX_LINK_MAX, _POSIX_LINK_MAX
+_POSIX_LOGIN_NAME_MAX, _POSIX_LOGIN_NAME_MAX
+_POSIX_MAX_CANON, _POSIX_MAX_CANON
+_POSIX_MAX_INPUT, _POSIX_MAX_INPUT
+_POSIX_MQ_OPEN_MAX, _POSIX_MQ_OPEN_MAX
+_POSIX_MQ_PRIO_MAX, _POSIX_MQ_PRIO_MAX
+_POSIX_NAME_MAX, _POSIX_NAME_MAX
+_POSIX_NGROUPS_MAX, _POSIX_NGROUPS_MAX
+_POSIX_OPEN_MAX, _POSIX_OPEN_MAX
+_POSIX_PATH_MAX, _POSIX_PATH_MAX
+_POSIX_PIPE_BUF, __POSIX_PIPE_BUF
+_POSIX_RE_DUP_MAX, _POSIX_RE_DUP_MAX
+_POSIX_RTSIG_MAX, _POSIX_RTSIG_MAX
+_POSIX_SEM_NSEMS_MAX, _POSIX_SEM_NSEMS_MAX
+_POSIX_SEM_VALUE_MAX, _POSIX_SEM_VALUE_MAX
+_POSIX_SIGQUEUE_MAX, _POSIX_SIGQUEUE_MAX
+_POSIX_SSIZE_MAX, _POSIX_SSIZE_MAX
+_POSIX_STREAM_MAX, _POSIX_STREAM_MAX
+_POSIX_SS_REPL_MAX, _POSIX_SS_REPL_MAX
+_POSIX_SYMLINK_MAX, _POSIX_SYMLINK_MAX
+_POSIX_SYMLOOP_MAX, _POSIX_SYMLOOP_MAX
+_POSIX_THREAD_DESTRUCTOR_ITERATIONS, _POSIX_THREAD_DESTRUCTOR_ITERATIONS
+_POSIX_THREAD_KEYS_MAX, _POSIX_THREAD_KEYS_MAX
+_POSIX_THREAD_THREADS_MAX, _POSIX_THREAD_THREADS_MAX
+_POSIX_TIMER_MAX, _POSIX_TIMER_MAX
+_POSIX_TRACE_EVENT_NAME_MAX, _POSIX_TRACE_EVENT_NAME_MAX
+_POSIX_TRACE_NAME_MAX, _POSIX_TRACE_NAME_MAX
+_POSIX_TRACE_SYS_MAX, _POSIX_TRACE_SYS_MAX
+_POSIX_TRACE_USER_EVENT_MAX, _POSIX_TRACE_USER_EVENT_MAX
+_POSIX_TTY_NAME_MAX, _POSIX_TTY_NAME_MAX
+_POSIX_TZNAME_MAX, _POSIX_TZNAME_MAX
+_POSIX2_BC_BASE_MAX, _POSIX2_BC_BASE_MAX
+_POSIX2_BC_DIM_MAX, _POSIX2_BC_DIM_MAX
+_POSIX2_BC_SCALE_MAX, _POSIX2_BC_SCALE_MAX
+_POSIX2_BC_STRING_MAX, _POSIX2_BC_STRING_MAX
+_POSIX2_CHARCLASS_NAME_MAX, _POSIX2_CHARCLASS_NAME_MAX
+_POSIX2_COLL_WEIGHTS_MAX, _POSIX2_COLL_WEIGHTS_MAX
+_POSIX2_EXPR_NEST_MAX, _POSIX2_EXPR_NEST_MAX
+_POSIX2_LINE_MAX, _POSIX2_LINE_MAX
+_POSIX2_RE_DUP_MAX, _POSIX2_RE_DUP_MAX
+_XOPEN_IOV_MAX, _XOPEN_IOV_MAX
+_XOPEN_NAME_MAX, _XOPEN_NAME_MAX
+_XOPEN_PATH_MAX, _XOPEN_PATH_MAX
+CHAR_BIT, CHAR_BIT
+CHAR_MAX, CHAR_MAX
+CHAR_MIN, CHAR_MIN
+INT_MAX, INT_MAX
+INT_MIN, INT_MIN
+LLONG_MIN, LLONG_MIN
+LLONG_MAX, LLONG_MAX
+LONG_BIT, LONG_BIT
+LONG_MAX, LONG_MAX
+LONG_MIN, LONG_MIN
+MB_LEN_MAX, MB_LEN_MAX
+SCHAR_MAX, SCHAR_MAX
+SCHAR_MIN, SCHAR_MIN
+SHRT_MAX, SHRT_MAX
+SHRT_MIN, SHRT_MIN
+SSIZE_MAX, SSIZE_MAX
+UCHAR_MAX, UCHAR_MAX
+UINT_MAX, UINT_MAX
+ULLONG_MAX, ULLONG_MAX
+ULONG_MAX, ULONG_MAX
+USHRT_MAX, USHRT_MAX
+WORD_BIT, WORD_BIT
+CHARCLASS_NAME_MAX, CHARCLASS_NAME_MAX
+NL_ARGMAX, NL_ARGMAX
+ML_LANGMAX, NL_LANGMAX
+NL_MSGMAX, NL_MSGMAX
+NL_NMAX, NL_NMAX
+NL_SETMAX, NL_SETMAX
+NL_TEXTMAX, NL_TEXTMAX
+NZERO, NZERO
+%%
+int
+find_limit(const char *name, intmax_t *value)
+{
+ const struct map *rv;
+#ifdef APPLE_GETCONF_UNDERSCORE
+ char *alt;
+#endif /* APPLE_GETCONF_UNDERSCORE */
+
+ rv = in_word_set(name);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *value = rv->value;
+ return 1;
+ }
+ return -1;
+ }
+#ifdef APPLE_GETCONF_UNDERSCORE
+ if(*name == '_')
+ alt = (char *)name + 1;
+ else {
+ if((alt = (char *)alloca(strlen(name) + 2)) == NULL)
+ return 0;
+ *alt = '_';
+ strcpy(alt + 1, name);
+ }
+ rv = in_word_set(alt);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *value = rv->value;
+ return 1;
+ }
+ return -1;
+ }
+#endif /* APPLE_GETCONF_UNDERSCORE */
+ return 0;
+}
--- /dev/null
+%{
+/*
+ * Copyright is disclaimed as to the contents of this file.
+ *
+ * $FreeBSD: src/usr.bin/getconf/pathconf.gperf,v 1.4 2003/08/22 17:32:07 markm Exp $
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <unistd.h>
+#ifdef APPLE_GETCONF_UNDERSCORE
+#include <alloca.h>
+#endif /* APPLE_GETCONF_UNDERSCORE */
+
+#include "getconf.h"
+
+/*
+ * Override gperf's built-in external scope.
+ */
+static const struct map *in_word_set(const char *str);
+
+%}
+struct map { const char *name; int key; int valid; };
+%%
+FILESIZEBITS, _PC_FILESIZEBITS
+LINK_MAX, _PC_LINK_MAX
+MAX_CANON, _PC_MAX_CANON
+MAX_INPUT, _PC_MAX_INPUT
+NAME_MAX, _PC_NAME_MAX
+PATH_MAX, _PC_PATH_MAX
+PIPE_BUF, _PC_PIPE_BUF
+POSIX_ALLOC_SIZE_MIN, _PC_ALLOC_SIZE_MIN
+POSIX_REC_INCR_XFER_SIZE, _PC_REC_INCR_XFER_SIZE
+POSIX_REC_MAX_XFER_SIZE, _PC_REC_MAX_XFER_SIZE
+POSIX_REC_MIN_XFER_SIZE, _PC_REC_MIN_XFER_SIZE
+POSIX_REC_XFER_ALIGN, _PC_REC_XFER_ALIGN
+POSIX2_SYMLINKS, _PC_2_SYMLINKS
+SYMLINK_MAX, _PC_SYMLINK_MAX
+TRUSTEDBSD_ACL_EXTENDED, _PC_ACL_EXTENDED
+TRUSTEDBSD_ACL_PATH_MAX, _PC_ACL_PATH_MAX
+TRUSTEDBSD_CAP_PRESENT, _PC_CAP_PRESENT
+TRUSTEDBSD_INF_PRESENT, _PC_INF_PRESENT
+TRUSTEDBSD_MAC_PRESENT, _PC_MAC_PRESENT
+_POSIX_ASYNC_IO, _PC_ASYNC_IO
+_POSIX_CHOWN_RESTRICTED, _PC_CHOWN_RESTRICTED
+_POSIX_NO_TRUNC, _PC_NO_TRUNC
+_POSIX_PATH_MAX, _PC_PATH_MAX
+_POSIX_PRIO_IO, _PC_PRIO_IO
+_POSIX_SYNC_IO, _PC_SYNC_IO
+_POSIX_VDISABLE, _PC_VDISABLE
+%%
+int
+find_pathconf(const char *name, int *key)
+{
+ const struct map *rv;
+#ifdef APPLE_GETCONF_UNDERSCORE
+ char *alt;
+#endif /* APPLE_GETCONF_UNDERSCORE */
+
+ rv = in_word_set(name);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *key = rv->key;
+ return 1;
+ }
+ return -1;
+ }
+#ifdef APPLE_GETCONF_UNDERSCORE
+ if(*name == '_')
+ alt = (char *)name + 1;
+ else {
+ if((alt = (char *)alloca(strlen(name) + 2)) == NULL)
+ return 0;
+ *alt = '_';
+ strcpy(alt + 1, name);
+ }
+ rv = in_word_set(alt);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *key = rv->key;
+ return 1;
+ }
+ return -1;
+ }
+#endif /* APPLE_GETCONF_UNDERSCORE */
+ return 0;
+}
--- /dev/null
+%{
+/*
+ * Copyright is disclaimed as to the contents of this file.
+ *
+ * $FreeBSD: src/usr.bin/getconf/progenv.gperf,v 1.2 2003/08/22 17:32:07 markm Exp $
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <unistd.h>
+
+#include "getconf.h"
+
+/*
+ * Override gperf's built-in external scope.
+ */
+static const struct map *in_word_set(const char *str);
+
+/*
+ * The Standard seems a bit ambiguous over whether the POSIX_V6_*
+ * are specified with or without a leading underscore, so we just
+ * use both.
+ */
+/*
+ * The alt_path member gives the path containing another `getconf'
+ * executable which was compiled using the specified programming
+ * environment. If it is NULL, the current executable is good enough.
+ * If we ever support multiple environments, this table will need to
+ * be updated. (We cheat here and define the supported environments
+ * statically.)
+ */
+#if defined(__alpha__) || defined(__sparc64__)
+#define have_LP64_OFF64 NULL
+#elif defined(__APPLE__)
+#define have_LP64_OFF64 NULL
+#define have_LPBIG_OFFBIG NULL
+#endif
+
+#if defined(__i386__) || defined(__powerpc__) || defined(__x86_64__)
+#define have_ILP32_OFFBIG NULL
+#endif
+
+%}
+struct map { const char *name; const char *alt_path; int valid; };
+%%
+POSIX_V6_ILP32_OFF32, notdef
+POSIX_V6_ILP32_OFFBIG, have_ILP32_OFFBIG
+POSIX_V6_LP64_OFF64, have_LP64_OFF64
+POSIX_V6_LPBIG_OFFBIG, have_LPBIG_OFFBIG
+_POSIX_V6_ILP32_OFF32, notdef
+_POSIX_V6_ILP32_OFFBIG, have_ILP32_OFFBIG
+_POSIX_V6_LP64_OFF64, have_LP64_OFF64
+_POSIX_V6_LPBIG_OFFBIG, have_LPBIG_OFFBIG
+%%
+int
+find_progenv(const char *name, const char **alt_path)
+{
+ const struct map *rv;
+
+ rv = in_word_set(name);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *alt_path = rv->alt_path;
+ return 1;
+ }
+ return -1;
+ }
+ return 0;
+}
--- /dev/null
+%{
+/*
+ * Copyright is disclaimed as to the contents of this file.
+ *
+ * $FreeBSD: src/usr.bin/getconf/sysconf.gperf,v 1.5 2003/08/22 17:32:07 markm Exp $
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <unistd.h>
+#ifdef APPLE_GETCONF_UNDERSCORE
+#include <alloca.h>
+#endif /* APPLE_GETCONF_UNDERSCORE */
+
+#include "getconf.h"
+
+/*
+ * Override gperf's built-in external scope.
+ */
+static const struct map *in_word_set(const char *str);
+
+%}
+struct map { const char *name; int key; int valid; };
+%%
+AIO_LISTIO_MAX, _SC_AIO_LISTIO_MAX
+AIO_MAX, _SC_AIO_MAX
+AIO_PRIO_DELTA_MAX, _SC_AIO_PRIO_DELTA_MAX
+ARG_MAX, _SC_ARG_MAX
+ATEXIT_MAX, _SC_ATEXIT_MAX
+BC_BASE_MAX, _SC_BC_BASE_MAX
+BC_DIM_MAX, _SC_BC_DIM_MAX
+BC_SCALE_MAX, _SC_BC_SCALE_MAX
+BC_STRING_MAX, _SC_BC_STRING_MAX
+CHILD_MAX, _SC_CHILD_MAX
+CLK_TCK, _SC_CLK_TCK
+COLL_WEIGHTS_MAX, _SC_COLL_WEIGHTS_MAX
+DELAYTIMER_MAX, _SC_DELAYTIMER_MAX
+EXPR_NEST_MAX, _SC_EXPR_NEST_MAX
+GETGR_R_SIZE_MAX, _SC_GETGR_R_SIZE_MAX
+GETPW_R_SIZE_MAX, _SC_GETPW_R_SIZE_MAX
+HOST_NAME_MAX, _SC_HOST_NAME_MAX
+IOV_MAX, _SC_IOV_MAX
+LINE_MAX, _SC_LINE_MAX
+LOGIN_NAME_MAX, _SC_LOGIN_NAME_MAX
+MQ_OPEN_MAX, _SC_MQ_OPEN_MAX
+MQ_PRIO_MAX, _SC_MQ_PRIO_MAX
+NGROUPS_MAX, _SC_NGROUPS_MAX
+NPROCESSORS_CONF, _SC_NPROCESSORS_CONF
+NPROCESSORS_ONLN, _SC_NPROCESSORS_ONLN
+OPEN_MAX, _SC_OPEN_MAX
+PAGESIZE, _SC_PAGESIZE
+PAGE_SIZE, _SC_PAGESIZE
+PASS_MAX, _SC_PASS_MAX
+PTHREAD_DESTRUCTOR_ITERATIONS, _SC_THREAD_DESTRUCTOR_ITERATIONS
+PTHREAD_KEYS_MAX, _SC_THREAD_KEYS_MAX
+PTHREAD_STACK_MIN, _SC_THREAD_STACK_MIN
+PTHREAD_THREADS_MAX, _SC_THREAD_THREADS_MAX
+RE_DUP_MAX, _SC_RE_DUP_MAX
+RTSIG_MAX, _SC_RTSIG_MAX
+SEM_NSEMS_MAX, _SC_SEM_NSEMS_MAX
+SEM_VALUE_MAX, _SC_SEM_VALUE_MAX
+SIGQUEUE_MAX, _SC_SIGQUEUE_MAX
+STREAM_MAX, _SC_STREAM_MAX
+SYMLOOP_MAX, _SC_SYMLOOP_MAX
+TIMER_MAX, _SC_TIMER_MAX
+TTY_NAME_MAX, _SC_TTY_NAME_MAX
+TZNAME_MAX, _SC_TZNAME_MAX
+_POSIX2_CHAR_TERM, _SC_2_CHAR_TERM
+_POSIX2_C_BIND, _SC_2_C_BIND
+_POSIX2_C_DEV, _SC_2_C_DEV
+_POSIX2_C_VERSION, _SC_2_C_VERSION
+_POSIX2_FORT_DEV, _SC_2_FORT_DEV
+_POSIX2_FORT_RUN, _SC_2_FORT_RUN
+_POSIX2_LOCALEDEF, _SC_2_LOCALEDEF
+_POSIX2_PBS, _SC_PBS
+_POSIX2_PBS_ACCOUNTING, _SC_PBS_ACCOUNTING
+_POSIX2_PBS_CHECKPOINT, _SC_PBS_CHECKPOINT
+_POSIX2_PBS_LOCATE, _SC_PBS_LOCATE
+_POSIX2_PBS_MESSAGE, _SC_PBS_MESSAGE
+_POSIX2_PBS_TRACK, _SC_PBS_TRACK
+_POSIX2_SW_DEV, _SC_2_SW_DEV
+_POSIX2_UPE, _SC_2_UPE
+_POSIX2_VERSION, _SC_2_VERSION
+_POSIX_ADVISORY_INFO, _SC_ADVISORY_INFO
+_POSIX_ASYNCHRONOUS_IO, _SC_ASYNCHRONOUS_IO
+_POSIX_BARRIERS, _SC_BARRIERS
+_POSIX_CLOCK_SELECTION, _SC_CLOCK_SELECTION
+_POSIX_CPUTIME, _SC_CPUTIME
+_POSIX_FILE_LOCKING, _SC_FILE_LOCKING
+_POSIX_FSYNC, _SC_FSYNC
+_POSIX_IPV6, _SC_IPV6
+_POSIX_JOB_CONTROL, _SC_JOB_CONTROL
+_POSIX_MAPPED_FILES, _SC_MAPPED_FILES
+_POSIX_MEMLOCK, _SC_MEMLOCK
+_POSIX_MEMLOCK_RANGE, _SC_MEMLOCK_RANGE
+_POSIX_MEMORY_PROTECTION, _SC_MEMORY_PROTECTION
+_POSIX_MESSAGE_PASSING, _SC_MESSAGE_PASSING
+_POSIX_MONOTONIC_CLOCK, _SC_MONOTONIC_CLOCK
+_POSIX_PRIORITIZED_IO, _SC_PRIORITIZED_IO
+_POSIX_PRIORITY_SCHEDULING, _SC_PRIORITY_SCHEDULING
+_POSIX_RAW_SOCKETS, _SC_RAW_SOCKETS
+_POSIX_READER_WRITER_LOCKS, _SC_READER_WRITER_LOCKS
+_POSIX_REALTIME_SIGNALS, _SC_REALTIME_SIGNALS
+_POSIX_REGEXP, _SC_REGEXP
+_POSIX_SAVED_IDS, _SC_SAVED_IDS
+_POSIX_SEMAPHORES, _SC_SEMAPHORES
+_POSIX_SHARED_MEMORY_OBJECTS, _SC_SHARED_MEMORY_OBJECTS
+_POSIX_SHELL, _SC_SHELL
+_POSIX_SPAWN, _SC_SPAWN
+_POSIX_SPIN_LOCKS, _SC_SPIN_LOCKS
+_POSIX_SPORADIC_SERVER, _SC_SPORADIC_SERVER
+_POSIX_SS_REPL_MAX, _SC_SS_REPL_MAX
+_POSIX_SYNCHRONIZED_IO, _SC_SYNCHRONIZED_IO
+_POSIX_THREADS, _SC_THREADS
+_POSIX_THREAD_ATTR_STACKADDR, _SC_THREAD_ATTR_STACKADDR
+_POSIX_THREAD_ATTR_STACKSIZE, _SC_THREAD_ATTR_STACKSIZE
+_POSIX_THREAD_CPUTIME, _SC_THREAD_CPUTIME
+_POSIX_THREAD_PRIORITY_SCHEDULING, _SC_THREAD_PRIORITY_SCHEDULING
+_POSIX_THREAD_PRIO_INHERIT, _SC_THREAD_PRIO_INHERIT
+_POSIX_THREAD_PRIO_PROTECT, _SC_THREAD_PRIO_PROTECT
+_POSIX_THREAD_PROCESS_SHARED, _SC_THREAD_PROCESS_SHARED
+_POSIX_THREAD_SAFE_FUNCTIONS, _SC_THREAD_SAFE_FUNCTIONS
+_POSIX_THREAD_SPORADIC_SERVER, _SC_THREAD_SPORADIC_SERVER
+_POSIX_TIMEOUTS, _SC_TIMEOUTS
+_POSIX_TIMERS, _SC_TIMERS
+_POSIX_TRACE, _SC_TRACE
+_POSIX_TRACE_EVENT_FILTER, _SC_TRACE_EVENT_FILTER
+_POSIX_TRACE_EVENT_NAME_MAX, _SC_TRACE_EVENT_NAME_MAX
+_POSIX_TRACE_INHERIT, _SC_TRACE_INHERIT
+_POSIX_TRACE_LOG, _SC_TRACE_LOG
+_POSIX_TRACE_NAME_MAX, _SC_TRACE_NAME_MAX
+_POSIX_TRACE_SYS_MAX, _SC_TRACE_SYS_MAX
+_POSIX_TRACE_USER_EVENT_MAX, _SC_TRACE_USER_EVENT_MAX
+_POSIX_TYPED_MEMORY_OBJECTS, _SC_TYPED_MEMORY_OBJECTS
+_POSIX_V6_ILP32_OFF32, _SC_V6_ILP32_OFF32
+_POSIX_V6_ILP32_OFFBIG, _SC_V6_ILP32_OFFBIG
+_POSIX_V6_LP64_OFF64, _SC_V6_LP64_OFF64
+_POSIX_V6_LPBIG_OFFBIG, _SC_V6_LPBIG_OFFBIG
+_POSIX_VERSION, _SC_VERSION
+_XOPEN_CRYPT, _SC_XOPEN_CRYPT
+_XOPEN_ENH_I18N, _SC_XOPEN_ENH_I18N
+_XOPEN_LEGACY, _SC_XOPEN_LEGACY
+_XOPEN_REALTIME, _SC_XOPEN_REALTIME
+_XOPEN_REALTIME_THREADS, _SC_XOPEN_REALTIME_THREADS
+_XOPEN_SHM, _SC_XOPEN_SHM
+_XOPEN_STREAMS, _SC_XOPEN_STREAMS
+_XOPEN_UNIX, _SC_XOPEN_UNIX
+_XOPEN_VERSION, _SC_XOPEN_VERSION
+_XOPEN_XCU_VERSION, _SC_XCU_VERSION
+%%
+int
+find_sysconf(const char *name, int *key)
+{
+ const struct map *rv;
+#ifdef APPLE_GETCONF_UNDERSCORE
+ char *alt;
+#endif /* APPLE_GETCONF_UNDERSCORE */
+
+ rv = in_word_set(name);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *key = rv->key;
+ return 1;
+ }
+ return -1;
+ }
+#ifdef APPLE_GETCONF_UNDERSCORE
+ if(*name == '_')
+ alt = (char *)name + 1;
+ else {
+ if((alt = (char *)alloca(strlen(name) + 2)) == NULL)
+ return 0;
+ *alt = '_';
+ strcpy(alt + 1, name);
+ }
+ rv = in_word_set(alt);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *key = rv->key;
+ return 1;
+ }
+ return -1;
+ }
+#endif /* APPLE_GETCONF_UNDERSCORE */
+ return 0;
+}
--- /dev/null
+/*-
+ * Copyright (c) 1997
+ * David L Nugent <davidn@blaze.net.au>.
+ * All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, is permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * 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. This work was done expressly for inclusion into FreeBSD. Other use
+ * is permitted provided this notation is included.
+ * 4. Absolutely no warranty of function or purpose is made by the authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * Modem chat module - send/expect style functions for getty
+ * For semi-intelligent modem handling.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/getty/chat.c,v 1.11 2005/04/06 17:42:24 stefanf Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/utsname.h>
+
+#include <ctype.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "gettytab.h"
+#include "extern.h"
+
+#define PAUSE_CH (unsigned char)'\xff' /* pause kludge */
+
+#define CHATDEBUG_RECEIVE 0x01
+#define CHATDEBUG_SEND 0x02
+#define CHATDEBUG_EXPECT 0x04
+#define CHATDEBUG_MISC 0x08
+
+#define CHATDEBUG_DEFAULT 0
+#define CHAT_DEFAULT_TIMEOUT 10
+
+
+static int chat_debug = CHATDEBUG_DEFAULT;
+static int chat_alarm = CHAT_DEFAULT_TIMEOUT; /* Default */
+
+static volatile int alarmed = 0;
+
+
+static void chat_alrm(int);
+static int chat_unalarm(void);
+static int getdigit(unsigned char **, int, int);
+static char **read_chat(char **);
+static char *cleanchr(char **, unsigned char);
+static char *cleanstr(const char *, int);
+static const char *result(int);
+static int chat_expect(const char *);
+static int chat_send(char const *);
+
+
+/*
+ * alarm signal handler
+ * handle timeouts in read/write
+ * change stdin to non-blocking mode to prevent
+ * possible hang in read().
+ */
+
+static void
+chat_alrm(int signo)
+{
+ int on = 1;
+
+ alarm(1);
+ alarmed = 1;
+ signal(SIGALRM, chat_alrm);
+ ioctl(STDIN_FILENO, FIONBIO, &on);
+}
+
+
+/*
+ * Turn back on blocking mode reset by chat_alrm()
+ */
+
+static int
+chat_unalarm(void)
+{
+ int off = 0;
+ return ioctl(STDIN_FILENO, FIONBIO, &off);
+}
+
+
+/*
+ * convert a string of a given base (octal/hex) to binary
+ */
+
+static int
+getdigit(unsigned char **ptr, int base, int max)
+{
+ int i, val = 0;
+ unsigned char * q;
+
+ static const char xdigits[] = "0123456789abcdef";
+
+ for (i = 0, q = *ptr; i++ < max; ++q) {
+ int sval;
+ const char * s = strchr(xdigits, tolower(*q));
+
+ if (s == NULL || (sval = s - xdigits) >= base)
+ break;
+ val = (val * base) + sval;
+ }
+ *ptr = q;
+ return val;
+}
+
+
+/*
+ * read_chat()
+ * Convert a whitespace delimtied string into an array
+ * of strings, being expect/send pairs
+ */
+
+static char **
+read_chat(char **chatstr)
+{
+ char *str = *chatstr;
+ char **res = NULL;
+
+ if (str != NULL) {
+ char *tmp = NULL;
+ int l;
+
+ if ((l=strlen(str)) > 0 && (tmp=malloc(l + 1)) != NULL &&
+ (res=malloc((l / 2 + 1) * sizeof(char *))) != NULL) {
+ static char ws[] = " \t";
+ char * p;
+
+ for (l = 0, p = strtok(strcpy(tmp, str), ws);
+ p != NULL;
+ p = strtok(NULL, ws))
+ {
+ unsigned char *q, *r;
+
+ /* Read escapes */
+ for (q = r = (unsigned char *)p; *r; ++q)
+ {
+ if (*q == '\\')
+ {
+ /* handle special escapes */
+ switch (*++q)
+ {
+ case 'a': /* bell */
+ *r++ = '\a';
+ break;
+ case 'r': /* cr */
+ *r++ = '\r';
+ break;
+ case 'n': /* nl */
+ *r++ = '\n';
+ break;
+ case 'f': /* ff */
+ *r++ = '\f';
+ break;
+ case 'b': /* bs */
+ *r++ = '\b';
+ break;
+ case 'e': /* esc */
+ *r++ = 27;
+ break;
+ case 't': /* tab */
+ *r++ = '\t';
+ break;
+ case 'p': /* pause */
+ *r++ = PAUSE_CH;
+ break;
+ case 's':
+ case 'S': /* space */
+ *r++ = ' ';
+ break;
+ case 'x': /* hexdigit */
+ ++q;
+ *r++ = getdigit(&q, 16, 2);
+ --q;
+ break;
+ case '0': /* octal */
+ ++q;
+ *r++ = getdigit(&q, 8, 3);
+ --q;
+ break;
+ default: /* literal */
+ *r++ = *q;
+ break;
+ case 0: /* not past eos */
+ --q;
+ break;
+ }
+ } else {
+ /* copy standard character */
+ *r++ = *q;
+ }
+ }
+
+ /* Remove surrounding quotes, if any
+ */
+ if (*p == '"' || *p == '\'') {
+ q = (unsigned char*)strrchr(p+1, *p);
+ if (q != NULL && *q == *p && q[1] == '\0') {
+ *q = '\0';
+ strcpy(p, p+1);
+ }
+ }
+
+ res[l++] = p;
+ }
+ res[l] = NULL;
+ *chatstr = tmp;
+ return res;
+ }
+ free(tmp);
+ }
+ return res;
+}
+
+
+/*
+ * clean a character for display (ctrl/meta character)
+ */
+
+static char *
+cleanchr(char **buf, unsigned char ch)
+{
+ int l;
+ static char tmpbuf[5];
+ char * tmp = buf ? *buf : tmpbuf;
+
+ if (ch & 0x80) {
+ strcpy(tmp, "M-");
+ l = 2;
+ ch &= 0x7f;
+ } else
+ l = 0;
+
+ if (ch < 32) {
+ tmp[l++] = '^';
+ tmp[l++] = ch + '@';
+ } else if (ch == 127) {
+ tmp[l++] = '^';
+ tmp[l++] = '?';
+ } else
+ tmp[l++] = ch;
+ tmp[l] = '\0';
+
+ if (buf)
+ *buf = tmp + l;
+ return tmp;
+}
+
+
+/*
+ * clean a string for display (ctrl/meta characters)
+ */
+
+static char *
+cleanstr(const char *s, int l)
+{
+ static char * tmp = NULL;
+ static int tmplen = 0;
+
+ if (tmplen < l * 4 + 1)
+ tmp = realloc(tmp, tmplen = l * 4 + 1);
+
+ if (tmp == NULL) {
+ tmplen = 0;
+ return (char *)"(mem alloc error)";
+ } else {
+ int i = 0;
+ char * p = tmp;
+
+ while (i < l)
+ cleanchr(&p, s[i++]);
+ *p = '\0';
+ }
+
+ return tmp;
+}
+
+
+/*
+ * return result as a pseudo-english word
+ */
+
+static const char *
+result(int r)
+{
+ static const char * results[] = {
+ "OK", "MEMERROR", "IOERROR", "TIMEOUT"
+ };
+ return results[r & 3];
+}
+
+
+/*
+ * chat_expect()
+ * scan input for an expected string
+ */
+
+static int
+chat_expect(const char *str)
+{
+ int len, r = 0;
+
+ if (chat_debug & CHATDEBUG_EXPECT)
+ syslog(LOG_DEBUG, "chat_expect '%s'", cleanstr(str, strlen(str)));
+
+ if ((len = strlen(str)) > 0) {
+ int i = 0;
+ char * got;
+
+ if ((got = malloc(len + 1)) == NULL)
+ r = 1;
+ else {
+
+ memset(got, 0, len+1);
+ alarm(chat_alarm);
+ alarmed = 0;
+
+ while (r == 0 && i < len) {
+ if (alarmed)
+ r = 3;
+ else {
+ unsigned char ch;
+
+ if (read(STDIN_FILENO, &ch, 1) == 1) {
+
+ if (chat_debug & CHATDEBUG_RECEIVE)
+ syslog(LOG_DEBUG, "chat_recv '%s' m=%d",
+ cleanchr(NULL, ch), i);
+
+ if (ch == str[i])
+ got[i++] = ch;
+ else if (i > 0) {
+ int j = 1;
+
+ /* See if we can resync on a
+ * partial match in our buffer
+ */
+ while (j < i && memcmp(got + j, str, i - j) != 0)
+ j++;
+ if (j < i)
+ memcpy(got, got + j, i - j);
+ i -= j;
+ }
+ } else
+ r = alarmed ? 3 : 2;
+ }
+ }
+ alarm(0);
+ chat_unalarm();
+ alarmed = 0;
+ free(got);
+ }
+ }
+
+ if (chat_debug & CHATDEBUG_EXPECT)
+ syslog(LOG_DEBUG, "chat_expect %s", result(r));
+
+ return r;
+}
+
+
+/*
+ * chat_send()
+ * send a chat string
+ */
+
+static int
+chat_send(char const *str)
+{
+ int r = 0;
+
+ if (chat_debug & CHATDEBUG_SEND)
+ syslog(LOG_DEBUG, "chat_send '%s'", cleanstr(str, strlen(str)));
+
+ if (*str) {
+ alarm(chat_alarm);
+ alarmed = 0;
+ while (r == 0 && *str)
+ {
+ unsigned char ch = (unsigned char)*str++;
+
+ if (alarmed)
+ r = 3;
+ else if (ch == PAUSE_CH)
+ usleep(500000); /* 1/2 second */
+ else {
+ usleep(10000); /* be kind to modem */
+ if (write(STDOUT_FILENO, &ch, 1) != 1)
+ r = alarmed ? 3 : 2;
+ }
+ }
+ alarm(0);
+ chat_unalarm();
+ alarmed = 0;
+ }
+
+ if (chat_debug & CHATDEBUG_SEND)
+ syslog(LOG_DEBUG, "chat_send %s", result(r));
+
+ return r;
+}
+
+
+/*
+ * getty_chat()
+ *
+ * Termination codes:
+ * -1 - no script supplied
+ * 0 - script terminated correctly
+ * 1 - invalid argument, expect string too large, etc.
+ * 2 - error on an I/O operation or fatal error condition
+ * 3 - timeout waiting for a simple string
+ *
+ * Parameters:
+ * char *scrstr - unparsed chat script
+ * timeout - seconds timeout
+ * debug - debug value (bitmask)
+ */
+
+int
+getty_chat(char *scrstr, int timeout, int debug)
+{
+ int r = -1;
+
+ chat_alarm = timeout ? timeout : CHAT_DEFAULT_TIMEOUT;
+ chat_debug = debug;
+
+ if (scrstr != NULL) {
+ char **script;
+
+ if (chat_debug & CHATDEBUG_MISC)
+ syslog(LOG_DEBUG, "getty_chat script='%s'", scrstr);
+
+ if ((script = read_chat(&scrstr)) != NULL) {
+ int i = r = 0;
+ int off = 0;
+ sig_t old_alarm;
+
+ /*
+ * We need to be in raw mode for all this
+ * Rely on caller...
+ */
+
+ old_alarm = signal(SIGALRM, chat_alrm);
+ chat_unalarm(); /* Force blocking mode at start */
+
+ /*
+ * This is the send/expect loop
+ */
+ while (r == 0 && script[i] != NULL)
+ if ((r = chat_expect(script[i++])) == 0 && script[i] != NULL)
+ r = chat_send(script[i++]);
+
+ signal(SIGALRM, old_alarm);
+ free(script);
+ free(scrstr);
+
+ /*
+ * Ensure stdin is in blocking mode
+ */
+ ioctl(STDIN_FILENO, FIONBIO, &off);
+ }
+
+ if (chat_debug & CHATDEBUG_MISC)
+ syslog(LOG_DEBUG, "getty_chat %s", result(r));
+
+ }
+ return r;
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <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>
--- /dev/null
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * from: @(#)extern.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/libexec/getty/extern.h,v 1.9 2005/04/06 17:42:24 stefanf Exp $
+ */
+
+struct delayval;
+struct termios;
+
+extern char hostname[];
+extern int hopcount;
+extern struct termios tmode, omode;
+extern struct gettyflags gettyflags[];
+extern struct gettynums gettynums[];
+extern struct gettystrs gettystrs[];
+
+int adelay(int, struct delayval *);
+const char *autobaud(void);
+int delaybits(void);
+void edithost(const char *);
+void gendefaults(void);
+void gettable(const char *);
+void makeenv(char *[]);
+const char *portselector(void);
+void set_ttydefaults(int);
+void setchars(void);
+void setdefaults(void);
+void set_flags(int);
+int speed(int);
+int getty_chat(char *, int, int);
--- /dev/null
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" from: @(#)getty.8 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD: src/libexec/getty/getty.8,v 1.16 2005/01/18 09:29:39 ru Exp $
+.\" "
+.Dd June 4, 1993
+.Dt GETTY 8
+.Os
+.Sh NAME
+.Nm getty
+.Nd set terminal mode
+.Sh SYNOPSIS
+.Nm
+.Oo
+.Ar type
+.Op Ar tty
+.Oc
+.Sh DESCRIPTION
+The
+.Nm
+utility is called by
+.Xr launchd 8
+to open and initialize the tty line, read a login name, and invoke
+.Xr login 1 .
+.Pp
+The argument
+.Ar tty
+is the special device file in
+.Pa /dev
+to open for the terminal (for example, ``ttyh0'').
+If there is no argument or the argument is
+.Sq Fl ,
+the tty line is assumed to be open as file descriptor 0.
+.Pp
+The
+.Ar type
+argument can be used to make
+.Nm
+treat the terminal line specially.
+This argument is used as an index into the
+.Xr gettytab 5
+database, to determine the characteristics of the line.
+If there is no argument, or there is no such table, the
+.Em default
+table is used.
+If there is no
+.Pa /etc/gettytab
+a set of system defaults is used.
+If indicated by the table located,
+.Nm
+will clear the terminal screen,
+print a banner heading,
+and prompt for a login name.
+Usually either the banner or the login prompt will include
+the system hostname.
+.Pp
+Most of the default actions of
+.Nm
+can be circumvented, or modified, by a suitable
+.Pa gettytab
+table.
+.Pp
+The
+.Nm
+utility can be set to timeout after some interval,
+which will cause dial up lines to hang up
+if the login name is not entered reasonably quickly.
+.Sh FILES
+.Bl -tag -width /etc/gettytab -compact
+.It Pa /etc/gettytab
+.It Pa /etc/ttys
+.El
+.Sh DIAGNOSTICS
+.Bl -diag
+.It "ttyxx: No such device or address."
+.It "ttyxx: No such file or address."
+.Pp
+A terminal which is turned
+on in the
+.Pa ttys
+file cannot be opened, likely because the requisite
+lines are either not configured into the system, the associated device
+was not attached during boot-time system configuration,
+or the special file in
+.Pa /dev
+does not exist.
+.El
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr ioctl 2 ,
+.Xr tty 4 ,
+.Xr gettytab 5 ,
+.Xr ttys 5 ,
+.Xr launchd 8
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v6 .
--- /dev/null
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" from: @(#)gettytab.5 8.4 (Berkeley) 4/19/94
+.\" $FreeBSD: src/libexec/getty/gettytab.5,v 1.41 2005/01/18 09:29:39 ru Exp $
+.\" "
+.Dd April 19, 1994
+.Dt GETTYTAB 5
+.Os
+.Sh NAME
+.Nm gettytab
+.Nd terminal configuration data base
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+file
+is a simplified version of the
+.Xr termcap 5
+data base
+used to describe terminal lines.
+The initial terminal login process
+.Xr getty 8
+accesses the
+.Nm
+file each time it starts, allowing simpler
+reconfiguration of terminal characteristics.
+Each entry in the data base
+is used to describe one class of terminals.
+.Pp
+There is a default terminal class,
+.Va default ,
+that is used to set global defaults for all other classes.
+(That is, the
+.Va default
+entry is read, then the entry for the class required
+is used to override particular settings.)
+.Sh CAPABILITIES
+Refer to
+.Xr termcap 5
+for a description of the file layout.
+The
+.Va default
+column below lists defaults obtained if there is
+no entry in the table obtained, nor one in the special
+.Va default
+table.
+.Bl -column Name Type /usr/bin/login
+.It Sy "Name Type Default Description
+.It "ac str unused expect-send chat script for modem answer"
+.It "al str unused user to auto-login instead of prompting"
+.It "ap bool false terminal uses any parity"
+.It "bk str 0377 alternate end of line character (input break)"
+.It "c0 num unused tty control flags to write messages"
+.It "c1 num unused tty control flags to read login name"
+.It "c2 num unused tty control flags to leave terminal as"
+.It "ce bool false use crt erase algorithm"
+.It "ck bool false use crt kill algorithm"
+.It "cl str" Ta Dv NULL Ta
+.No "screen clear sequence"
+.It "co bool false console - add"
+.Ql \en
+after login prompt
+.It "ct num 10 chat timeout for"
+.Va \&ac
+and
+.Va \&ic
+scripts
+.It "dc num 0 chat debug bitmask"
+.It "de num 0 delay secs and flush input before writing first prompt"
+.It "df str %+ the" Xr strftime 3 "format used for \&%d in the banner message"
+.It "ds str" Ta So Li ^Y Sc Ta
+.No "delayed suspend character"
+.It "dx bool false set"
+.Dv DECCTLQ
+.It "ec bool false leave echo"
+.Em OFF
+.It "ep bool false terminal uses even parity"
+.It "er str" Ta So Li ^? Sc Ta
+.No "erase character"
+.It "et str" Ta So Li ^D Sc Ta
+.No "end of text"
+.Pq Dv EOF
+character
+.It "ev str" Ta Dv NULL Ta
+.No "initial environment"
+.It "f0 num unused tty mode flags to write messages"
+.It "f1 num unused tty mode flags to read login name"
+.It "f2 num unused tty mode flags to leave terminal as"
+.It "fl str" Ta So Li ^O Sc Ta
+.No "output flush character"
+.It "hc bool false do"
+.Em NOT
+hangup line on last close
+.It "he str" Ta Dv NULL Ta
+.No "hostname editing string"
+.It "hn str hostname hostname"
+.It "ht bool false terminal has real tabs"
+.It "hw bool false do cts/rts hardware flow control"
+.It "i0 num unused tty input flags to write messages"
+.It "i1 num unused tty input flags to read login name"
+.It "i2 num unused tty input flags to leave terminal as"
+.It "ic str unused expect-send chat script for modem initialization"
+.It "if str unused display named file before prompt, like /etc/issue"
+.It "ig bool false ignore garbage characters in login name"
+.It "im str" Ta Dv NULL Ta
+.No "initial (banner) message"
+.It "in str" Ta So Li ^C Sc Ta
+.No "interrupt character"
+.It "is num unused input speed"
+.It "kl str" Ta So Li ^U Sc Ta
+.No "kill character"
+.It "l0 num unused tty local flags to write messages"
+.It "l1 num unused tty local flags to read login name"
+.It "l2 num unused tty local flags to leave terminal as"
+.It "lm str login: login prompt"
+.It "ln str" Ta So Li ^V Sc Ta
+.No "``literal next'' character"
+.It "lo str" Ta Pa /usr/bin/login Ta
+.No "program to exec when name obtained"
+.It "mb bool false do flow control based on carrier"
+.It "nc bool false terminal does not supply carrier (set clocal)"
+.It "nl bool false terminal has (or might have) a newline character"
+.It "np bool false terminal uses no parity (i.e. 8-bit characters)"
+.It "nx str default next table (for auto speed selection)"
+.It "o0 num unused tty output flags to write messages"
+.It "o1 num unused tty output flags to read login name"
+.It "o2 num unused tty output flags to leave terminal as"
+.It "op bool false terminal uses odd parity"
+.It "os num unused output speed"
+.It "pc str" Ta So Li \e0 Sc Ta
+.No "pad character"
+.It "pe bool false use printer (hard copy) erase algorithm"
+.It "pf num 0 delay"
+between first prompt and following flush (seconds)
+.It "pl bool false start PPP login program unconditionally if"
+.Va \&pp
+is specified
+.It "pp str unused PPP login program"
+.It "ps bool false line connected to a"
+.Tn MICOM
+port selector
+.It "qu str" Ta So Li \&^\e Sc Ta
+.No "quit character"
+.It "rp str" Ta So Li ^R Sc Ta
+.No "line retype character"
+.It "rt num unused ring timeout when using"
+.Va \&ac
+.It "rw bool false do"
+.Em NOT
+use raw for input, use cbreak
+.It "sp num unused line speed (input and output)"
+.It "su str" Ta So Li ^Z Sc Ta
+.No "suspend character"
+.It "tc str none table continuation"
+.It "to num 0 timeout (seconds)"
+.It "tt str" Ta Dv NULL Ta
+.No "terminal type (for environment)"
+.It "ub bool false do unbuffered output (of prompts etc)"
+.It "we str" Ta So Li ^W Sc Ta
+.No "word erase character"
+.It "xc bool false do
+.Em NOT
+echo control chars as
+.Ql ^X
+.It "xf str" Ta So Li ^S Sc Ta Dv XOFF
+(stop output) character
+.It "xn str" Ta So Li ^Q Sc Ta Dv XON
+(start output) character
+.It "Lo str C the locale name used for \&%d in the banner message"
+.El
+.Pp
+The following capabilities are no longer supported by
+.Xr getty 8 :
+.Bl -column Name Type /usr/bin/login
+.It "bd num 0 backspace delay"
+.It "cb bool false use crt backspace mode"
+.It "cd num 0 carriage-return delay"
+.It "fd num 0 form-feed (vertical motion) delay"
+.It "lc bool false terminal has lower case"
+.It "nd num 0 newline (line-feed) delay"
+.It "uc bool false terminal is known upper case only"
+.El
+.Pp
+If no line speed is specified, speed will not be altered
+from that which prevails when getty is entered.
+Specifying an input or output speed will override
+line speed for stated direction only.
+.Pp
+Terminal modes to be used for the output of the message,
+for input of the login name,
+and to leave the terminal set as upon completion,
+are derived from the boolean flags specified.
+If the derivation should prove inadequate,
+any (or all) of these three may be overridden
+with one of the
+.Va \&c0 ,
+.Va \&c1 ,
+.Va \&c2 ,
+.Va \&i0 ,
+.Va \&i1 ,
+.Va \&i2 ,
+.Va \&l0 ,
+.Va \&l1 ,
+.Va \&l2 ,
+.Va \&o0 ,
+.Va \&o1 ,
+or
+.Va \&o2
+numeric specifications, which can be used to specify
+(usually in octal, with a leading '0')
+the exact values of the flags.
+These flags correspond to the termios
+.Va c_cflag ,
+.Va c_iflag ,
+.Va c_lflag ,
+and
+.Va c_oflag
+fields, respectively.
+Each of these sets must be completely specified to be effective.
+.Pp
+The
+.Va \&f0 ,
+.Va \&f1 ,
+and
+.Va \&f2
+are excepted for backwards compatibility with a previous incarnation of
+the TTY sub-system.
+In these flags the bottom 16 bits of the (32 bits)
+value contain the sgttyb
+.Va sg_flags
+field, while the top 16 bits represent the local mode word.
+.Pp
+Should
+.Xr getty 8
+receive a null character
+(presumed to indicate a line break)
+it will restart using the table indicated by the
+.Va \&nx
+entry.
+If there is none, it will re-use its original table.
+.Pp
+Delays are specified in milliseconds, the nearest possible
+delay available in the tty driver will be used.
+Should greater certainty be desired, delays
+with values 0, 1, 2, and 3 are interpreted as
+choosing that particular delay algorithm from the driver.
+.Pp
+The
+.Va \&cl
+screen clear string may be preceded by a (decimal) number
+of milliseconds of delay required (a la termcap).
+This delay is simulated by repeated use of the pad character
+.Va \&pc .
+.Pp
+The initial message, login message, and initial file;
+.Va \&im ,
+.Va \&lm
+and
+.Va \&if
+may include any of the following character sequences, which expand to
+information about the environment in which
+.Xr getty 8
+is running.
+.Pp
+.Bl -tag -offset indent -width \&%xxxxxxxxxxxxxx
+.It \&%d
+The current date and time formatted according to the
+.Va \&Lo
+and
+.Va \&df
+strings.
+.It \&%h
+The hostname of the machine, which is normally obtained from the
+system using
+.Xr gethostname 3 ,
+but may also be overridden by the
+.Va \&hn
+table entry.
+In either case it may be edited with the
+.Va \&he
+string.
+A '@' in the
+.Va \&he
+string causes one character from the real hostname to
+be copied to the final hostname.
+A '#' in the
+.Va \&he
+string causes the next character of the real hostname
+to be skipped.
+Each character that
+is neither '@' nor '#' is copied into the final hostname.
+Surplus '@' and '#' characters are ignored.
+.It \&%t
+The tty name.
+.It "\&%m, \&%r, \&%s, \&%v"
+The type of machine, release of the operating system, name of the
+operating system, and version of the kernel, respectively, as
+returned by
+.Xr uname 3 .
+.It \&%%
+A
+.Dq %
+character.
+.El
+.Pp
+When getty execs the login process, given
+in the
+.Va \&lo
+string (usually
+.Dq Pa /usr/bin/login ) ,
+it will have set
+the environment to include the terminal type, as indicated
+by the
+.Va \&tt
+string (if it exists).
+The
+.Va \&ev
+string, can be used to enter additional data into
+the environment.
+It is a list of comma separated strings, each of which
+will presumably be of the form
+.Li name=value .
+.Pp
+If a non-zero timeout is specified, with
+.Va \&to ,
+then getty will exit within the indicated
+number of seconds, either having
+received a login name and passed control
+to
+.Xr login 1 ,
+or having received an alarm signal, and exited.
+This may be useful to hangup dial in lines.
+.Pp
+Output from
+.Xr getty 8
+is even parity unless
+.Va \&op
+or
+.Va \&np
+is specified.
+The
+.Va \&op
+string
+may be specified with
+.Va \&ap
+to allow any parity on input, but generate odd parity output.
+Note: this only applies while getty is being run,
+terminal driver limitations prevent a more complete
+implementation.
+The
+.Xr getty 8
+utility does not check parity of input characters in
+.Dv RAW
+mode.
+.Pp
+If a
+.Va \&pp
+string is specified and a PPP link bring-up sequence is recognized,
+getty will invoke the program referenced by the
+.Va \&pp
+option.
+This can be used to handle incoming PPP calls.
+If the
+.Va \&pl
+option is true as well,
+.Xr getty 8
+will skip the user name prompt and the PPP detection phase, and will
+invoke the program specified by
+.Va \&pp
+instantly.
+.Pp
+.Nm Getty
+provides some basic intelligent modem handling by providing a chat
+script feature available via two capabilities:
+.Pp
+.Bl -tag -offset indent -width \&xxxxxxxx -compact
+.It ic
+Chat script to initialize modem.
+.It ac
+Chat script to answer a call.
+.El
+.Pp
+A chat script is a set of expect/send string pairs.
+When a chat string starts,
+.Nm getty
+will wait for the first string, and if it finds it, will send the
+second, and so on.
+Strings specified are separated by one or more tabs or spaces.
+Strings may contain standard ASCII characters and special 'escapes',
+which consist of a backslash character followed by one or more
+characters which are interpreted as follows:
+.Pp
+.Bl -tag -offset indent -width \&xxxxxxxx -compact
+.It \ea
+bell character.
+.It \eb
+backspace.
+.It \en
+newline.
+.It \ee
+escape.
+.It \ef
+formfeed.
+.It \ep
+half-second pause.
+.It \er
+carriage return.
+.It \eS , \es
+space character.
+.It \et
+tab.
+.It \exNN
+hexadecimal byte value.
+.It \e0NNN
+octal byte value.
+.El
+.Pp
+Note that the
+.Ql \ep
+sequence is only valid for send strings and causes a half-second
+pause between sending the previous and next characters.
+Hexadecimal values are, at most, 2 hex digits long, and octal
+values are a maximum of 3 octal digits.
+.Pp
+The
+.Va \&ic
+chat sequence is used to initialize a modem or similar device.
+A typical example of an init chat script for a modem with a
+hayes compatible command set might look like this:
+.Pp
+.Dl :ic="" ATE0Q0V1\er OK\er ATS0=0\er OK\er:
+.Pp
+This script waits for nothing (which always succeeds), sends
+a sequence to ensure that the modem is in the correct mode
+(suppress command echo, send responses in verbose mode),
+and then disables auto-answer.
+It waits for an "OK" response before it terminates.
+The init sequence is used to check modem responses to ensure that
+the modem is functioning correctly.
+If the init script fails to complete,
+.Nm getty
+considers this to be fatal, and results in an error logged via
+.Xr syslogd 8 ,
+and exiting.
+.Pp
+Similarly, an answer chat script is used to manually answer the
+phone in response to (usually) a "RING".
+When run with an answer script,
+.Nm getty
+opens the port in non-blocking mode, clears any extraneous input
+and waits for data on the port.
+As soon as any data is available, the answer chat script is
+started and scanned for a string, and responds according to
+the answer chat script.
+With a hayes compatible modem, this would normally look something
+like:
+.Pp
+.Dl :ac=RING\er ATA\er CONNECT:
+.Pp
+This causes the modem to answer the call via the "ATA" command,
+then scans input for a "CONNECT" string.
+If this is received before a
+.Va \&ct
+timeout, then a normal login sequence commences.
+.Pp
+The
+.Va \&ct
+capability specifies a timeout for all send and expect strings.
+This timeout is set individually for each expect wait and send
+string and must be at least as long as the time it takes for
+a connection to be established between a remote and local
+modem (usually around 10 seconds).
+.Pp
+In most situations, you will want to flush any additional
+input after the connection has been detected, and the
+.Va \&de
+capability may be used to do that, as well as delay for a
+short time after the connection has been established during
+which all of the connection data has been sent by the modem.
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr gethostname 3 ,
+.Xr uname 3 ,
+.Xr termcap 5 ,
+.Xr getty 8 ,
+.Xr telnetd 8
+.Sh HISTORY
+The
+.Nm
+file format appeared in
+.Bx 4.2 .
+.Sh BUGS
+The special characters (erase, kill, etc.) are reset to system defaults
+by
+.Xr login 1 .
+In
+.Em all
+cases, '#' or '^H' typed in a login name will be treated as
+an erase character, and '@' will be treated as a kill character.
+.Pp
+The delay stuff is a real crock.
+Apart form its general lack of flexibility, some
+of the delay algorithms are not implemented.
+The terminal driver should support sane delay settings.
+.Pp
+The
+.Va \&he
+capability is stupid.
+.Pp
+The
+.Xr termcap 5
+format is horrid, something more rational should
+have been chosen.
+.Pp
+This should be converted to use
+.Xr termios 4 .
--- /dev/null
+/*
+ * Copyright (c) 1983, 1993, 1994
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * from: @(#)gettytab.h 8.2 (Berkeley) 3/30/94
+ * $FreeBSD: src/libexec/getty/gettytab.h,v 1.14 2003/06/10 18:30:41 yar Exp $
+ */
+
+/*
+ * Getty description definitions.
+ */
+struct gettystrs {
+ const char *field; /* name to lookup in gettytab */
+ char *defalt; /* value we find by looking in defaults */
+ char *value; /* value that we find there */
+};
+
+struct gettynums {
+ const char *field; /* name to lookup */
+ long defalt; /* number we find in defaults */
+ long value; /* number we find there */
+ int set; /* we actually got this one */
+};
+
+struct gettyflags {
+ const char *field; /* name to lookup */
+ char invrt; /* name existing in gettytab --> false */
+ char defalt; /* true/false in defaults */
+ char value; /* true/false flag */
+ char set; /* we found it */
+};
+
+/*
+ * String values.
+ */
+#define NX gettystrs[0].value
+#define CL gettystrs[1].value
+#define IM gettystrs[2].value
+#define LM gettystrs[3].value
+#define ER gettystrs[4].value
+#define KL gettystrs[5].value
+#define ET gettystrs[6].value
+#define PC gettystrs[7].value
+#define TT gettystrs[8].value
+#define EV gettystrs[9].value
+#define LO gettystrs[10].value
+#define HN gettystrs[11].value
+#define HE gettystrs[12].value
+#define IN gettystrs[13].value
+#define QU gettystrs[14].value
+#define XN gettystrs[15].value
+#define XF gettystrs[16].value
+#define BK gettystrs[17].value
+#define SU gettystrs[18].value
+#define DS gettystrs[19].value
+#define RP gettystrs[20].value
+#define FL gettystrs[21].value
+#define WE gettystrs[22].value
+#define LN gettystrs[23].value
+#define Lo gettystrs[24].value
+#define PP gettystrs[25].value
+#define IF gettystrs[26].value
+#define IC gettystrs[27].value
+#define AC gettystrs[28].value
+#define AL gettystrs[29].value
+#define DF gettystrs[30].value
+
+/*
+ * Numeric definitions.
+ */
+#define IS gettynums[0].value
+#define OS gettynums[1].value
+#define SP gettynums[2].value
+#define ND gettynums[3].value
+#define CD gettynums[4].value
+#define TD gettynums[5].value
+#define FD gettynums[6].value
+#define BD gettynums[7].value
+#define TO gettynums[8].value
+#define F0 gettynums[9].value
+#define F0set gettynums[9].set
+#define F1 gettynums[10].value
+#define F1set gettynums[10].set
+#define F2 gettynums[11].value
+#define F2set gettynums[11].set
+#define PF gettynums[12].value
+#define C0 gettynums[13].value
+#define C0set gettynums[13].set
+#define C1 gettynums[14].value
+#define C1set gettynums[14].set
+#define C2 gettynums[15].value
+#define C2set gettynums[15].set
+#define I0 gettynums[16].value
+#define I0set gettynums[16].set
+#define I1 gettynums[17].value
+#define I1set gettynums[17].set
+#define I2 gettynums[18].value
+#define I2set gettynums[18].set
+#define L0 gettynums[19].value
+#define L0set gettynums[19].set
+#define L1 gettynums[20].value
+#define L1set gettynums[20].set
+#define L2 gettynums[21].value
+#define L2set gettynums[21].set
+#define O0 gettynums[22].value
+#define O0set gettynums[22].set
+#define O1 gettynums[23].value
+#define O1set gettynums[23].set
+#define O2 gettynums[24].value
+#define O2set gettynums[24].set
+#define DE gettynums[25].value
+#define RTset gettynums[26].set
+#define RT gettynums[26].value
+#define CT gettynums[27].value
+#define DC gettynums[28].value
+
+/*
+ * Boolean values.
+ */
+#define HT gettyflags[0].value
+#define NL gettyflags[1].value
+#define EP gettyflags[2].value
+#define EPset gettyflags[2].set
+#define OP gettyflags[3].value
+#define OPset gettyflags[3].set
+#define AP gettyflags[4].value
+#define APset gettyflags[4].set
+#define EC gettyflags[5].value
+#define CO gettyflags[6].value
+#define CB gettyflags[7].value
+#define CK gettyflags[8].value
+#define CE gettyflags[9].value
+#define PE gettyflags[10].value
+#define RW gettyflags[11].value
+#define XC gettyflags[12].value
+#define LC gettyflags[13].value
+#define UC gettyflags[14].value
+#define IG gettyflags[15].value
+#define PS gettyflags[16].value
+#define HC gettyflags[17].value
+#define UB gettyflags[18].value
+#define AB gettyflags[19].value
+#define DX gettyflags[20].value
+#define NP gettyflags[21].value
+#define NPset gettyflags[21].set
+#define MB gettyflags[22].value
+#define HW gettyflags[23].value
+#define NC gettyflags[24].value
+#define PL gettyflags[25].value
--- /dev/null
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)from: init.c 8.1 (Berkeley) 6/4/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/getty/init.c,v 1.16 2005/04/06 17:42:24 stefanf Exp $";
+#endif /* not lint */
+
+/*
+ * Getty table initializations.
+ *
+ * Melbourne getty.
+ */
+#include <termios.h>
+#include "gettytab.h"
+#include "extern.h"
+#include "pathnames.h"
+
+static char loginmsg[] = "login: ";
+static char nullstr[] = "";
+static char loginprg[] = _PATH_LOGIN;
+static char datefmt[] = "%+";
+
+struct gettystrs gettystrs[] = {
+ { "nx" }, /* next table */
+ { "cl" }, /* screen clear characters */
+ { "im" }, /* initial message */
+ { "lm", loginmsg }, /* login message */
+ { "er", (char*)&omode.c_cc[VERASE] }, /* erase character */
+ { "kl", (char*)&omode.c_cc[VKILL] }, /* kill character */
+ { "et", (char*)&omode.c_cc[VEOF] }, /* eof chatacter (eot) */
+ { "pc", nullstr }, /* pad character */
+ { "tt" }, /* terminal type */
+ { "ev" }, /* enviroment */
+ { "lo", loginprg }, /* login program */
+ { "hn", hostname }, /* host name */
+ { "he" }, /* host name edit */
+ { "in", (char*)&omode.c_cc[VINTR] }, /* interrupt char */
+ { "qu", (char*)&omode.c_cc[VQUIT] }, /* quit char */
+ { "xn", (char*)&omode.c_cc[VSTART] }, /* XON (start) char */
+ { "xf", (char*)&omode.c_cc[VSTOP] }, /* XOFF (stop) char */
+ { "bk", (char*)&omode.c_cc[VEOL] }, /* brk char (alt \n) */
+ { "su", (char*)&omode.c_cc[VSUSP] }, /* suspend char */
+ { "ds", (char*)&omode.c_cc[VDSUSP] }, /* delayed suspend */
+ { "rp", (char*)&omode.c_cc[VREPRINT] },/* reprint char */
+ { "fl", (char*)&omode.c_cc[VDISCARD] },/* flush output */
+ { "we", (char*)&omode.c_cc[VWERASE] }, /* word erase */
+ { "ln", (char*)&omode.c_cc[VLNEXT] }, /* literal next */
+ { "Lo" }, /* locale for strftime() */
+ { "pp" }, /* ppp login program */
+ { "if" }, /* sysv-like 'issue' filename */
+ { "ic" }, /* modem init-chat */
+ { "ac" }, /* modem answer-chat */
+ { "al" }, /* user to auto-login */
+ { "df", datefmt}, /* format for strftime() */
+ { 0 }
+};
+
+struct gettynums gettynums[] = {
+ { "is" }, /* input speed */
+ { "os" }, /* output speed */
+ { "sp" }, /* both speeds */
+ { "nd" }, /* newline delay */
+ { "cd" }, /* carriage-return delay */
+ { "td" }, /* tab delay */
+ { "fd" }, /* form-feed delay */
+ { "bd" }, /* backspace delay */
+ { "to" }, /* timeout */
+ { "f0" }, /* output flags */
+ { "f1" }, /* input flags */
+ { "f2" }, /* user mode flags */
+ { "pf" }, /* delay before flush at 1st prompt */
+ { "c0" }, /* output c_flags */
+ { "c1" }, /* input c_flags */
+ { "c2" }, /* user mode c_flags */
+ { "i0" }, /* output i_flags */
+ { "i1" }, /* input i_flags */
+ { "i2" }, /* user mode i_flags */
+ { "l0" }, /* output l_flags */
+ { "l1" }, /* input l_flags */
+ { "l2" }, /* user mode l_flags */
+ { "o0" }, /* output o_flags */
+ { "o1" }, /* input o_flags */
+ { "o2" }, /* user mode o_flags */
+ { "de" }, /* delay before sending 1st prompt */
+ { "rt" }, /* reset timeout */
+ { "ct" }, /* chat script timeout */
+ { "dc" }, /* debug chat script value */
+ { 0 }
+};
+
+
+struct gettyflags gettyflags[] = {
+ { "ht", 0 }, /* has tabs */
+ { "nl", 1 }, /* has newline char */
+ { "ep", 0 }, /* even parity */
+ { "op", 0 }, /* odd parity */
+ { "ap", 0 }, /* any parity */
+ { "ec", 1 }, /* no echo */
+ { "co", 0 }, /* console special */
+ { "cb", 0 }, /* crt backspace */
+ { "ck", 0 }, /* crt kill */
+ { "ce", 0 }, /* crt erase */
+ { "pe", 0 }, /* printer erase */
+ { "rw", 1 }, /* don't use raw */
+ { "xc", 1 }, /* don't ^X ctl chars */
+ { "lc", 0 }, /* terminal las lower case */
+ { "uc", 0 }, /* terminal has no lower case */
+ { "ig", 0 }, /* ignore garbage */
+ { "ps", 0 }, /* do port selector speed select */
+ { "hc", 1 }, /* don't set hangup on close */
+ { "ub", 0 }, /* unbuffered output */
+ { "ab", 0 }, /* auto-baud detect with '\r' */
+ { "dx", 0 }, /* set decctlq */
+ { "np", 0 }, /* no parity at all (8bit chars) */
+ { "mb", 0 }, /* do MDMBUF flow control */
+ { "hw", 0 }, /* do CTSRTS flow control */
+ { "nc", 0 }, /* set clocal (no carrier) */
+ { "pl", 0 }, /* use PPP instead of login(1) */
+ { 0 }
+};
--- /dev/null
+/*-
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Portions copyright (c) 2007 Apple Inc. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)from: main.c 8.1 (Berkeley) 6/20/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/getty/main.c,v 1.47 2005/04/06 17:42:24 stefanf Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/ttydefaults.h>
+#include <sys/utsname.h>
+
+#include <ctype.h>
+#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>
+#include <string.h>
+#include <syslog.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#include "gettytab.h"
+#include "extern.h"
+#include "pathnames.h"
+
+/*
+ * Set the amount of running time that getty should accumulate
+ * before deciding that something is wrong and exit.
+ */
+#define GETTY_TIMEOUT 60 /* seconds */
+
+#undef CTRL
+#define CTRL(x) (x&037)
+
+/* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
+
+#define PPP_FRAME 0x7e /* PPP Framing character */
+#define PPP_STATION 0xff /* "All Station" character */
+#define PPP_ESCAPE 0x7d /* Escape Character */
+#define PPP_CONTROL 0x03 /* PPP Control Field */
+#define PPP_CONTROL_ESCAPED 0x23 /* PPP Control Field, escaped */
+#define PPP_LCP_HI 0xc0 /* LCP protocol - high byte */
+#define PPP_LCP_LOW 0x21 /* LCP protocol - low byte */
+
+/* original mode; flags've been reset using values from <sys/ttydefaults.h> */
+struct termios omode;
+/* current mode */
+struct termios tmode;
+
+int crmod, digit, lower, upper;
+
+char hostname[MAXHOSTNAMELEN];
+char name[MAXLOGNAME*3];
+char dev[] = _PATH_DEV;
+char ttyn[32];
+
+#define OBUFSIZ 128
+#define TABBUFSIZ 512
+
+const char *tname;
+
+char *env[128];
+
+char partab[] = {
+ 0001,0201,0201,0001,0201,0001,0001,0201,
+ 0202,0004,0003,0205,0005,0206,0201,0001,
+ 0201,0001,0001,0201,0001,0201,0201,0001,
+ 0001,0201,0201,0001,0201,0001,0001,0201,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0000,0200,0200,0000,0200,0000,0000,0200,
+ 0000,0200,0200,0000,0200,0000,0000,0200,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0000,0200,0200,0000,0200,0000,0000,0200,
+ 0000,0200,0200,0000,0200,0000,0000,0200,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0000,0200,0200,0000,0200,0000,0000,0200,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0000,0200,0200,0000,0200,0000,0000,0201
+};
+
+#define ERASE tmode.c_cc[VERASE]
+#define KILL tmode.c_cc[VKILL]
+#define EOT tmode.c_cc[VEOF]
+
+#define puts Gputs
+
+static void defttymode(void);
+static void dingdong(int);
+static void dogettytab(void);
+static int getname(void);
+static void interrupt(int);
+static void oflush(void);
+static void prompt(void);
+static void putchr(int);
+static void putf(const char *);
+static void putpad(const char *);
+static void puts(const char *);
+static void timeoverrun(int);
+static char *getty_getline(int);
+static void setttymode(int);
+static int opentty(const char *, int);
+
+jmp_buf timeout;
+
+static void
+dingdong(int signo __unused)
+{
+ alarm(0);
+ longjmp(timeout, 1);
+}
+
+jmp_buf intrupt;
+
+static void
+interrupt(int signo __unused)
+{
+ longjmp(intrupt, 1);
+}
+
+/*
+ * Action to take when getty is running too long.
+ */
+static void
+timeoverrun(int signo __unused)
+{
+
+ syslog(LOG_ERR, "getty exiting due to excessive running time");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ extern char **environ;
+ int first_sleep = 1, first_time = 1;
+ struct rlimit limit;
+ int rval;
+#ifdef __APPLE__
+ int ttyopenmode = O_RDWR;
+#endif
+
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+
+ openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
+ gethostname(hostname, sizeof(hostname) - 1);
+ hostname[sizeof(hostname) - 1] = '\0';
+ if (hostname[0] == '\0')
+ strcpy(hostname, "Amnesiac");
+
+ /*
+ * Limit running time to deal with broken or dead lines.
+ */
+ (void)signal(SIGXCPU, timeoverrun);
+ limit.rlim_max = RLIM_INFINITY;
+ limit.rlim_cur = GETTY_TIMEOUT;
+ (void)setrlimit(RLIMIT_CPU, &limit);
+
+ gettable("default");
+ gendefaults();
+ tname = "default";
+ if (argc > 1)
+ tname = argv[1];
+
+ /*
+ * The following is a work around for vhangup interactions
+ * which cause great problems getting window systems started.
+ * If the tty line is "-", we do the old style getty presuming
+ * that the file descriptors are already set up for us.
+ * J. Gettys - MIT Project Athena.
+ */
+ if (argc <= 2 || strcmp(argv[2], "-") == 0)
+#ifdef __APPLE__
+ {
+ // <rdar://problem/5178373>
+ char* n = ttyname(STDIN_FILENO);
+ if (n) {
+ strlcpy(ttyn, n, sizeof(ttyn));
+ } else {
+ syslog(LOG_ERR, "ttyname %m");
+ exit(1);
+ }
+ }
+#else
+ strcpy(ttyn, ttyname(STDIN_FILENO));
+#endif
+ else {
+ strcpy(ttyn, dev);
+ strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
+ if (strcmp(argv[0], "+") != 0) {
+ chown(ttyn, 0, 0);
+ chmod(ttyn, 0600);
+ revoke(ttyn);
+
+ /*
+ * Do the first scan through gettytab.
+ * Terminal mode parameters will be wrong until
+ * defttymode() called, but they're irrelevant for
+ * the initial setup of the terminal device.
+ */
+ dogettytab();
+
+#if defined(__APPLE__) && !TARGET_OS_EMBEDDED
+ if (strncmp(ttyn, _PATH_CONSOLE, sizeof(ttyn)) == 0)
+ ttyopenmode |= O_POPUP;
+#endif
+ /*
+ * Init or answer modem sequence has been specified.
+ */
+ if (IC || AC) {
+#ifdef __APPLE__
+ if (!opentty(ttyn, ttyopenmode))
+#else
+ if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
+#endif
+ exit(1);
+ defttymode();
+ setttymode(1);
+ }
+
+ if (IC) {
+ if (getty_chat(IC, CT, DC) > 0) {
+ syslog(LOG_ERR, "modem init problem on %s", ttyn);
+ (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
+ exit(1);
+ }
+ }
+
+ if (AC) {
+ int i, rfds;
+ struct timeval to;
+
+ rfds = 1 << 0; /* FD_SET */
+ to.tv_sec = RT;
+ to.tv_usec = 0;
+ i = select(32, (fd_set*)&rfds, (fd_set*)NULL,
+ (fd_set*)NULL, RT ? &to : NULL);
+ if (i < 0) {
+ syslog(LOG_ERR, "select %s: %m", ttyn);
+ } else if (i == 0) {
+ syslog(LOG_NOTICE, "recycle tty %s", ttyn);
+ (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
+ exit(0); /* recycle for init */
+ }
+ i = getty_chat(AC, CT, DC);
+ if (i > 0) {
+ syslog(LOG_ERR, "modem answer problem on %s", ttyn);
+ (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
+ exit(1);
+ }
+ } else { /* maybe blocking open */
+#ifdef __APPLE__
+ if (!opentty(ttyn, ttyopenmode | (NC ? O_NONBLOCK : 0 )))
+#else
+ if (!opentty(ttyn, O_RDWR | (NC ? O_NONBLOCK : 0 )))
+#endif
+ exit(1);
+ }
+ }
+ }
+
+ defttymode();
+ for (;;) {
+
+ /*
+ * if a delay was specified then sleep for that
+ * number of seconds before writing the initial prompt
+ */
+ if (first_sleep && DE) {
+ sleep(DE);
+ /* remove any noise */
+ (void)tcflush(STDIN_FILENO, TCIOFLUSH);
+ }
+ first_sleep = 0;
+
+ setttymode(0);
+ if (AB) {
+ tname = autobaud();
+ dogettytab();
+ continue;
+ }
+ if (PS) {
+ tname = portselector();
+ dogettytab();
+ continue;
+ }
+ if (CL && *CL)
+ putpad(CL);
+ edithost(HE);
+
+ /* if this is the first time through this, and an
+ issue file has been given, then send it */
+ if (first_time && IF) {
+ int fd;
+
+ if ((fd = open(IF, O_RDONLY)) != -1) {
+ char * cp;
+
+ while ((cp = getty_getline(fd)) != NULL) {
+ putf(cp);
+ }
+ close(fd);
+ }
+ }
+ first_time = 0;
+
+ if (IM && *IM && !(PL && PP))
+ putf(IM);
+ if (setjmp(timeout)) {
+ cfsetispeed(&tmode, B0);
+ cfsetospeed(&tmode, B0);
+ (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
+ exit(1);
+ }
+ if (TO) {
+ signal(SIGALRM, dingdong);
+ alarm(TO);
+ }
+
+ rval = 0;
+ if (AL) {
+ const char *p = AL;
+ char *q = name;
+
+ while (*p && q < &name[sizeof name - 1]) {
+ if (isupper(*p))
+ upper = 1;
+ else if (islower(*p))
+ lower = 1;
+ else if (isdigit(*p))
+ digit = 1;
+ *q++ = *p++;
+ }
+ } else if (!(PL && PP))
+ rval = getname();
+ if (rval == 2 || (PL && PP)) {
+ oflush();
+ alarm(0);
+ limit.rlim_max = RLIM_INFINITY;
+ limit.rlim_cur = RLIM_INFINITY;
+ (void)setrlimit(RLIMIT_CPU, &limit);
+ execle(PP, "ppplogin", ttyn, (char *) 0, env);
+ syslog(LOG_ERR, "%s: %m", PP);
+ exit(1);
+ } else if (rval || AL) {
+ int i;
+
+ oflush();
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+ if (name[0] == '\0')
+ continue;
+ if (name[0] == '-') {
+ puts("user names may not start with '-'.");
+ continue;
+ }
+ if (!(upper || lower || digit)) {
+ if (AL) {
+ syslog(LOG_ERR,
+ "invalid auto-login name: %s", AL);
+ exit(1);
+ } else
+ continue;
+ }
+ set_flags(2);
+ if (crmod) {
+ tmode.c_iflag |= ICRNL;
+ tmode.c_oflag |= ONLCR;
+ }
+#if REALLY_OLD_TTYS
+ if (upper || UC)
+ tmode.sg_flags |= LCASE;
+ if (lower || LC)
+ tmode.sg_flags &= ~LCASE;
+#endif
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
+ syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
+ exit(1);
+ }
+ signal(SIGINT, SIG_DFL);
+ for (i = 0; environ[i] != (char *)0; i++)
+ env[i] = environ[i];
+ makeenv(&env[i]);
+
+ limit.rlim_max = RLIM_INFINITY;
+ limit.rlim_cur = RLIM_INFINITY;
+ (void)setrlimit(RLIMIT_CPU, &limit);
+#ifdef __APPLE__
+ // <rdar://problem/3205179>
+ execle(LO, "login", AL ? "-fp1" : "-p1", name,
+#else
+ execle(LO, "login", AL ? "-fp" : "-p", name,
+#endif
+ (char *) 0, env);
+ syslog(LOG_ERR, "%s: %m", LO);
+ exit(1);
+ }
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+ signal(SIGINT, SIG_IGN);
+ if (NX && *NX) {
+ tname = NX;
+ dogettytab();
+ }
+ }
+}
+
+static int
+opentty(const char *tty, int flags)
+{
+ int i;
+ int failopenlogged = 0;
+
+ while ((i = open(tty, flags)) == -1)
+ {
+ if (!failopenlogged) {
+ syslog(LOG_ERR, "open %s: %m", tty);
+ failopenlogged = 1;
+ }
+ sleep(60);
+ }
+ if (login_tty(i) < 0) {
+#ifndef __APPLE__
+ if (daemon(0,0) < 0) {
+ syslog(LOG_ERR,"daemon: %m");
+ close(i);
+ return 0;
+ }
+#endif
+ if (login_tty(i) < 0) {
+ syslog(LOG_ERR, "login_tty %s: %m", tty);
+ close(i);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void
+defttymode()
+{
+
+ /* Start with default tty settings. */
+ if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
+ syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
+ exit(1);
+ }
+ omode = tmode; /* fill c_cc for dogettytab() */
+ dogettytab();
+ /*
+ * Don't rely on the driver too much, and initialize crucial
+ * things according to <sys/ttydefaults.h>. Avoid clobbering
+ * the c_cc[] settings however, the console drivers might wish
+ * to leave their idea of the preferred VERASE key value
+ * there.
+ */
+ tmode.c_iflag = TTYDEF_IFLAG;
+ tmode.c_oflag = TTYDEF_OFLAG;
+ tmode.c_lflag = TTYDEF_LFLAG;
+ tmode.c_cflag = TTYDEF_CFLAG;
+ if (NC)
+ tmode.c_cflag |= CLOCAL;
+ omode = tmode;
+}
+
+static void
+setttymode(int raw)
+{
+ int off = 0;
+
+ (void)tcflush(STDIN_FILENO, TCIOFLUSH); /* clear out the crap */
+ ioctl(STDIN_FILENO, FIONBIO, &off); /* turn off non-blocking mode */
+ ioctl(STDIN_FILENO, FIOASYNC, &off); /* ditto for async mode */
+
+ if (IS)
+ cfsetispeed(&tmode, speed(IS));
+ else if (SP)
+ cfsetispeed(&tmode, speed(SP));
+ if (OS)
+ cfsetospeed(&tmode, speed(OS));
+ else if (SP)
+ cfsetospeed(&tmode, speed(SP));
+ set_flags(0);
+ setchars();
+ if (raw)
+ cfmakeraw(&tmode);
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
+ syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
+ exit(1);
+ }
+}
+
+
+static int
+getname(void)
+{
+ int c;
+ char *np;
+ unsigned char cs;
+ int ppp_state = 0;
+ int ppp_connection = 0;
+
+ /*
+ * Interrupt may happen if we use CBREAK mode
+ */
+ if (setjmp(intrupt)) {
+ signal(SIGINT, SIG_IGN);
+ return (0);
+ }
+ signal(SIGINT, interrupt);
+ set_flags(1);
+ prompt();
+ oflush();
+ if (PF > 0) {
+ sleep(PF);
+ PF = 0;
+ }
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
+ syslog(LOG_ERR, "%s: %m", ttyn);
+ exit(1);
+ }
+ crmod = digit = lower = upper = 0;
+ np = name;
+ for (;;) {
+ oflush();
+ if (read(STDIN_FILENO, &cs, 1) <= 0)
+ exit(0);
+ if ((c = cs&0177) == 0)
+ return (0);
+
+ /* PPP detection state machine..
+ Look for sequences:
+ PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
+ PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
+ See RFC1662.
+ Derived from code from Michael Hancock, <michaelh@cet.co.jp>
+ and Erik 'PPP' Olson, <eriko@wrq.com>
+ */
+
+ if (PP && (cs == PPP_FRAME)) {
+ ppp_state = 1;
+ } else if (ppp_state == 1 && cs == PPP_STATION) {
+ ppp_state = 2;
+ } else if (ppp_state == 2 && cs == PPP_ESCAPE) {
+ ppp_state = 3;
+ } else if ((ppp_state == 2 && cs == PPP_CONTROL)
+ || (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
+ ppp_state = 4;
+ } else if (ppp_state == 4 && cs == PPP_LCP_HI) {
+ ppp_state = 5;
+ } else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
+ ppp_connection = 1;
+ break;
+ } else {
+ ppp_state = 0;
+ }
+
+ if (c == EOT || c == CTRL('d'))
+ exit(0);
+ if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) {
+ putf("\r\n");
+ break;
+ }
+ if (islower(c))
+ lower = 1;
+ else if (isupper(c))
+ upper = 1;
+ else if (c == ERASE || c == '\b' || c == 0177) {
+ if (np > name) {
+ np--;
+ if (cfgetospeed(&tmode) >= 1200)
+ puts("\b \b");
+ else
+ putchr(cs);
+ }
+ continue;
+ } else if (c == KILL || c == CTRL('u')) {
+ putchr('\r');
+ if (cfgetospeed(&tmode) < 1200)
+ putchr('\n');
+ /* this is the way they do it down under ... */
+ else if (np > name)
+ puts(" \r");
+ prompt();
+ digit = lower = upper = 0;
+ np = name;
+ continue;
+ } else if (isdigit(c))
+ digit = 1;
+ if (IG && (c <= ' ' || c > 0176))
+ continue;
+ *np++ = c;
+ putchr(cs);
+ }
+ signal(SIGINT, SIG_IGN);
+ *np = 0;
+ if (c == '\r')
+ crmod = 1;
+ if ((upper && !lower && !LC) || UC)
+ for (np = name; *np; np++)
+ if (isupper(*np))
+ *np = tolower(*np);
+ return (1 + ppp_connection);
+}
+
+static void
+putpad(const char *s)
+{
+ int pad = 0;
+ speed_t ospeed = cfgetospeed(&tmode);
+
+ if (isdigit(*s)) {
+ while (isdigit(*s)) {
+ pad *= 10;
+ pad += *s++ - '0';
+ }
+ pad *= 10;
+ if (*s == '.' && isdigit(s[1])) {
+ pad += s[1] - '0';
+ s += 2;
+ }
+ }
+
+ puts(s);
+ /*
+ * If no delay needed, or output speed is
+ * not comprehensible, then don't try to delay.
+ */
+ if (pad == 0 || ospeed <= 0)
+ return;
+
+ /*
+ * Round up by a half a character frame, and then do the delay.
+ * Too bad there are no user program accessible programmed delays.
+ * Transmitting pad characters slows many terminals down and also
+ * loads the system.
+ */
+ pad = (pad * ospeed + 50000) / 100000;
+ while (pad--)
+ putchr(*PC);
+}
+
+static void
+puts(const char *s)
+{
+ while (*s)
+ putchr(*s++);
+}
+
+char outbuf[OBUFSIZ];
+int obufcnt = 0;
+
+static void
+putchr(int cc)
+{
+ char c;
+
+ c = cc;
+ if (!NP) {
+ c |= partab[c&0177] & 0200;
+ if (OP)
+ c ^= 0200;
+ }
+ if (!UB) {
+ outbuf[obufcnt++] = c;
+ if (obufcnt >= OBUFSIZ)
+ oflush();
+ } else
+ write(STDOUT_FILENO, &c, 1);
+}
+
+static void
+oflush(void)
+{
+ if (obufcnt)
+ write(STDOUT_FILENO, outbuf, obufcnt);
+ obufcnt = 0;
+}
+
+static void
+prompt(void)
+{
+
+ putf(LM);
+ if (CO)
+ putchr('\n');
+}
+
+
+static char *
+getty_getline(int fd)
+{
+ int i = 0;
+ static char linebuf[512];
+
+ /*
+ * This is certainly slow, but it avoids having to include
+ * stdio.h unnecessarily. Issue files should be small anyway.
+ */
+ while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) {
+ if (linebuf[i] == '\n') {
+ /* Don't rely on newline mode, assume raw */
+ linebuf[i++] = '\r';
+ linebuf[i++] = '\n';
+ linebuf[i] = '\0';
+ return linebuf;
+ }
+ ++i;
+ }
+ linebuf[i] = '\0';
+ return i ? linebuf : 0;
+}
+
+static void
+putf(const char *cp)
+{
+ extern char editedhost[];
+ time_t t;
+ char *slash, db[100];
+
+ static struct utsname kerninfo;
+
+ if (!*kerninfo.sysname)
+ uname(&kerninfo);
+
+ while (*cp) {
+ if (*cp != '%') {
+ putchr(*cp++);
+ continue;
+ }
+ switch (*++cp) {
+
+ case 't':
+ slash = strrchr(ttyn, '/');
+ if (slash == (char *) 0)
+ puts(ttyn);
+ else
+ puts(&slash[1]);
+ break;
+
+ case 'h':
+ puts(editedhost);
+ break;
+
+ case 'd': {
+ t = (time_t)0;
+ (void)time(&t);
+ if (Lo)
+ (void)setlocale(LC_TIME, Lo);
+ (void)strftime(db, sizeof(db), DF, localtime(&t));
+ puts(db);
+ break;
+
+ case 's':
+ puts(kerninfo.sysname);
+ break;
+
+ case 'm':
+ puts(kerninfo.machine);
+ break;
+
+ case 'r':
+ puts(kerninfo.release);
+ break;
+
+ case 'v':
+ puts(kerninfo.version);
+ break;
+ }
+
+ case '%':
+ putchr('%');
+ break;
+ }
+ cp++;
+ }
+}
+
+/*
+ * Read a gettytab database entry and perform necessary quirks.
+ */
+static void
+dogettytab()
+{
+
+ /* Read the database entry. */
+ gettable(tname);
+
+ /*
+ * Avoid inheriting the parity values from the default entry
+ * if any of them is set in the current entry.
+ * Mixing different parity settings is unreasonable.
+ */
+ if (OPset || EPset || APset || NPset)
+ OPset = EPset = APset = NPset = 1;
+
+ /* Fill in default values for unset capabilities. */
+ setdefaults();
+}
--- /dev/null
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * from: @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/libexec/getty/pathnames.h,v 1.7 1999/08/28 00:09:36 peter Exp $
+ */
+
+#include <paths.h>
+
+#define _PATH_GETTYTAB "/etc/gettytab"
+#define _PATH_LOGIN "/usr/bin/login"
--- /dev/null
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)from: subr.c 8.1 (Berkeley) 6/4/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/getty/subr.c,v 1.19 2004/06/25 10:11:28 phk Exp $";
+#endif /* not lint */
+
+/*
+ * Melbourne getty.
+ */
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <syslog.h>
+
+#include "gettytab.h"
+#include "pathnames.h"
+#include "extern.h"
+
+
+
+/*
+ * Get a table entry.
+ */
+void
+gettable(const char *name)
+{
+ char *buf = NULL;
+ struct gettystrs *sp;
+ struct gettynums *np;
+ struct gettyflags *fp;
+ long n;
+ int l;
+ char *p;
+ char *msg = NULL;
+ const char *dba[2];
+
+ static int firsttime = 1;
+
+ dba[0] = _PATH_GETTYTAB;
+ dba[1] = 0;
+
+ if (firsttime) {
+ /*
+ * we need to strdup() anything in the strings array
+ * initially in order to simplify things later
+ */
+ for (sp = gettystrs; sp->field; sp++)
+ if (sp->value != NULL) {
+ /* handle these ones more carefully */
+ if (sp >= &gettystrs[4] && sp <= &gettystrs[6])
+ l = 2;
+ else
+ l = (int)strlen(sp->value) + 1;
+ if ((p = malloc(l)) != NULL) {
+ strncpy(p, sp->value, l);
+ p[l-1] = '\0';
+ }
+ /*
+ * replace, even if NULL, else we'll
+ * have problems with free()ing static mem
+ */
+ sp->value = p;
+ }
+ firsttime = 0;
+ }
+
+ switch (cgetent(&buf, (char **)dba, (char *)name)) {
+ case 1:
+ msg = "%s: couldn't resolve 'tc=' in gettytab '%s'";
+ case 0:
+ break;
+ case -1:
+ msg = "%s: unknown gettytab entry '%s'";
+ break;
+ case -2:
+ msg = "%s: retrieving gettytab entry '%s': %m";
+ break;
+ case -3:
+ msg = "%s: recursive 'tc=' reference gettytab entry '%s'";
+ break;
+ default:
+ msg = "%s: unexpected cgetent() error for entry '%s'";
+ break;
+ }
+
+ if (msg != NULL) {
+ syslog(LOG_ERR, msg, "getty", name);
+ return;
+ }
+
+ for (sp = gettystrs; sp->field; sp++) {
+ if ((l = cgetstr(buf, (char*)sp->field, &p)) >= 0) {
+ if (sp->value) {
+ /* prefer existing value */
+ if (strcmp(p, sp->value) != 0)
+ free(sp->value);
+ else {
+ free(p);
+ p = sp->value;
+ }
+ }
+ sp->value = p;
+ } else if (l == -1) {
+ free(sp->value);
+ sp->value = NULL;
+ }
+ }
+
+ for (np = gettynums; np->field; np++) {
+ if (cgetnum(buf, (char*)np->field, &n) == -1)
+ np->set = 0;
+ else {
+ np->set = 1;
+ np->value = n;
+ }
+ }
+
+ for (fp = gettyflags; fp->field; fp++) {
+ if (cgetcap(buf, (char *)fp->field, ':') == NULL)
+ fp->set = 0;
+ else {
+ fp->set = 1;
+ fp->value = 1 ^ fp->invrt;
+ }
+ }
+
+#ifdef DEBUG
+ printf("name=\"%s\", buf=\"%s\"\r\n", name, buf);
+ for (sp = gettystrs; sp->field; sp++)
+ printf("cgetstr: %s=%s\r\n", sp->field, sp->value);
+ for (np = gettynums; np->field; np++)
+ printf("cgetnum: %s=%d\r\n", np->field, np->value);
+ for (fp = gettyflags; fp->field; fp++)
+ printf("cgetflags: %s='%c' set='%c'\r\n", fp->field,
+ fp->value + '0', fp->set + '0');
+#endif /* DEBUG */
+
+ free(buf);
+}
+
+void
+gendefaults(void)
+{
+ struct gettystrs *sp;
+ struct gettynums *np;
+ struct gettyflags *fp;
+
+ for (sp = gettystrs; sp->field; sp++)
+ if (sp->value)
+ sp->defalt = strdup(sp->value);
+ for (np = gettynums; np->field; np++)
+ if (np->set)
+ np->defalt = np->value;
+ for (fp = gettyflags; fp->field; fp++)
+ if (fp->set)
+ fp->defalt = fp->value;
+ else
+ fp->defalt = fp->invrt;
+}
+
+void
+setdefaults(void)
+{
+ struct gettystrs *sp;
+ struct gettynums *np;
+ struct gettyflags *fp;
+
+ for (sp = gettystrs; sp->field; sp++)
+ if (!sp->value)
+ sp->value = !sp->defalt ? sp->defalt
+ : strdup(sp->defalt);
+ for (np = gettynums; np->field; np++)
+ if (!np->set)
+ np->value = np->defalt;
+ for (fp = gettyflags; fp->field; fp++)
+ if (!fp->set)
+ fp->value = fp->defalt;
+}
+
+static char **
+charnames[] = {
+ &ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK,
+ &SU, &DS, &RP, &FL, &WE, &LN, 0
+};
+
+static char *
+charvars[] = {
+ (char*)&tmode.c_cc[VERASE],
+ (char*)&tmode.c_cc[VKILL],
+ (char*)&tmode.c_cc[VINTR],
+ (char*)&tmode.c_cc[VQUIT],
+ (char*)&tmode.c_cc[VSTART],
+ (char*)&tmode.c_cc[VSTOP],
+ (char*)&tmode.c_cc[VEOF],
+ (char*)&tmode.c_cc[VEOL],
+ (char*)&tmode.c_cc[VSUSP],
+ (char*)&tmode.c_cc[VDSUSP],
+ (char*)&tmode.c_cc[VREPRINT],
+ (char*)&tmode.c_cc[VDISCARD],
+ (char*)&tmode.c_cc[VWERASE],
+ (char*)&tmode.c_cc[VLNEXT],
+ 0
+};
+
+void
+setchars(void)
+{
+ int i;
+ const char *p;
+
+ for (i = 0; charnames[i]; i++) {
+ p = *charnames[i];
+ if (p && *p)
+ *charvars[i] = *p;
+ else
+ *charvars[i] = _POSIX_VDISABLE;
+ }
+}
+
+/* Macros to clear/set/test flags. */
+#define SET(t, f) (t) |= (f)
+#define CLR(t, f) (t) &= ~(f)
+#define ISSET(t, f) ((t) & (f))
+
+void
+set_flags(int n)
+{
+ tcflag_t iflag, oflag, cflag, lflag;
+
+
+ switch (n) {
+ case 0:
+ if (C0set && I0set && L0set && O0set) {
+ tmode.c_cflag = C0;
+ tmode.c_iflag = I0;
+ tmode.c_lflag = L0;
+ tmode.c_oflag = O0;
+ return;
+ }
+ break;
+ case 1:
+ if (C1set && I1set && L1set && O1set) {
+ tmode.c_cflag = C1;
+ tmode.c_iflag = I1;
+ tmode.c_lflag = L1;
+ tmode.c_oflag = O1;
+ return;
+ }
+ break;
+ default:
+ if (C2set && I2set && L2set && O2set) {
+ tmode.c_cflag = C2;
+ tmode.c_iflag = I2;
+ tmode.c_lflag = L2;
+ tmode.c_oflag = O2;
+ return;
+ }
+ break;
+ }
+
+ iflag = omode.c_iflag;
+ oflag = omode.c_oflag;
+ cflag = omode.c_cflag;
+ lflag = omode.c_lflag;
+
+ if (NP) {
+ CLR(cflag, CSIZE|PARENB);
+ SET(cflag, CS8);
+ CLR(iflag, ISTRIP|INPCK|IGNPAR);
+ } else if (AP || EP || OP) {
+ CLR(cflag, CSIZE);
+ SET(cflag, CS7|PARENB);
+ SET(iflag, ISTRIP);
+ if (OP && !EP) {
+ SET(iflag, INPCK|IGNPAR);
+ SET(cflag, PARODD);
+ if (AP)
+ CLR(iflag, INPCK);
+ } else if (EP && !OP) {
+ SET(iflag, INPCK|IGNPAR);
+ CLR(cflag, PARODD);
+ if (AP)
+ CLR(iflag, INPCK);
+ } else if (AP || (EP && OP)) {
+ CLR(iflag, INPCK|IGNPAR);
+ CLR(cflag, PARODD);
+ }
+ } /* else, leave as is */
+
+#if 0
+ if (UC)
+ f |= LCASE;
+#endif
+
+ if (HC)
+ SET(cflag, HUPCL);
+ else
+ CLR(cflag, HUPCL);
+
+ if (MB)
+ SET(cflag, MDMBUF);
+ else
+ CLR(cflag, MDMBUF);
+
+ if (HW)
+ SET(cflag, CRTSCTS);
+ else
+ CLR(cflag, CRTSCTS);
+
+ if (NL) {
+ SET(iflag, ICRNL);
+ SET(oflag, ONLCR|OPOST);
+ } else {
+ CLR(iflag, ICRNL);
+ CLR(oflag, ONLCR);
+ }
+
+ if (!HT)
+ SET(oflag, OXTABS|OPOST);
+ else
+ CLR(oflag, OXTABS);
+
+#ifdef XXX_DELAY
+ SET(f, delaybits());
+#endif
+
+ if (n == 1) { /* read mode flags */
+ if (RW) {
+ iflag = 0;
+ CLR(oflag, OPOST);
+ CLR(cflag, CSIZE|PARENB);
+ SET(cflag, CS8);
+ lflag = 0;
+ } else {
+ CLR(lflag, ICANON);
+ }
+ goto out;
+ }
+
+ if (n == 0)
+ goto out;
+
+#if 0
+ if (CB)
+ SET(f, CRTBS);
+#endif
+
+ if (CE)
+ SET(lflag, ECHOE);
+ else
+ CLR(lflag, ECHOE);
+
+ if (CK)
+ SET(lflag, ECHOKE);
+ else
+ CLR(lflag, ECHOKE);
+
+ if (PE)
+ SET(lflag, ECHOPRT);
+ else
+ CLR(lflag, ECHOPRT);
+
+ if (EC)
+ SET(lflag, ECHO);
+ else
+ CLR(lflag, ECHO);
+
+ if (XC)
+ SET(lflag, ECHOCTL);
+ else
+ CLR(lflag, ECHOCTL);
+
+ if (DX)
+ SET(lflag, IXANY);
+ else
+ CLR(lflag, IXANY);
+
+out:
+ tmode.c_iflag = iflag;
+ tmode.c_oflag = oflag;
+ tmode.c_cflag = cflag;
+ tmode.c_lflag = lflag;
+}
+
+
+#ifdef XXX_DELAY
+struct delayval {
+ unsigned delay; /* delay in ms */
+ int bits;
+};
+
+/*
+ * below are random guesses, I can't be bothered checking
+ */
+
+struct delayval crdelay[] = {
+ { 1, CR1 },
+ { 2, CR2 },
+ { 3, CR3 },
+ { 83, CR1 },
+ { 166, CR2 },
+ { 0, CR3 },
+};
+
+struct delayval nldelay[] = {
+ { 1, NL1 }, /* special, calculated */
+ { 2, NL2 },
+ { 3, NL3 },
+ { 100, NL2 },
+ { 0, NL3 },
+};
+
+struct delayval bsdelay[] = {
+ { 1, BS1 },
+ { 0, 0 },
+};
+
+struct delayval ffdelay[] = {
+ { 1, FF1 },
+ { 1750, FF1 },
+ { 0, FF1 },
+};
+
+struct delayval tbdelay[] = {
+ { 1, TAB1 },
+ { 2, TAB2 },
+ { 3, XTABS }, /* this is expand tabs */
+ { 100, TAB1 },
+ { 0, TAB2 },
+};
+
+int
+delaybits(void)
+{
+ int f;
+
+ f = adelay(CD, crdelay);
+ f |= adelay(ND, nldelay);
+ f |= adelay(FD, ffdelay);
+ f |= adelay(TD, tbdelay);
+ f |= adelay(BD, bsdelay);
+ return (f);
+}
+
+int
+adelay(int ms, struct delayval *dp)
+{
+ if (ms == 0)
+ return (0);
+ while (dp->delay && ms > dp->delay)
+ dp++;
+ return (dp->bits);
+}
+#endif
+
+char editedhost[MAXHOSTNAMELEN];
+
+void
+edithost(const char *pat)
+{
+ const char *host = HN;
+ char *res = editedhost;
+
+ if (!pat)
+ pat = "";
+ while (*pat) {
+ switch (*pat) {
+
+ case '#':
+ if (*host)
+ host++;
+ break;
+
+ case '@':
+ if (*host)
+ *res++ = *host++;
+ break;
+
+ default:
+ *res++ = *pat;
+ break;
+
+ }
+ if (res == &editedhost[sizeof editedhost - 1]) {
+ *res = '\0';
+ return;
+ }
+ pat++;
+ }
+ if (*host)
+ strncpy(res, host, sizeof editedhost - (res - editedhost) - 1);
+ else
+ *res = '\0';
+ editedhost[sizeof editedhost - 1] = '\0';
+}
+
+static struct speedtab {
+ int speed;
+ int uxname;
+} speedtab[] = {
+ { 50, B50 },
+ { 75, B75 },
+ { 110, B110 },
+ { 134, B134 },
+ { 150, B150 },
+ { 200, B200 },
+ { 300, B300 },
+ { 600, B600 },
+ { 1200, B1200 },
+ { 1800, B1800 },
+ { 2400, B2400 },
+ { 4800, B4800 },
+ { 9600, B9600 },
+ { 19200, EXTA },
+ { 19, EXTA }, /* for people who say 19.2K */
+ { 38400, EXTB },
+ { 38, EXTB },
+ { 7200, EXTB }, /* alternative */
+ { 57600, B57600 },
+ { 115200, B115200 },
+ { 230400, B230400 },
+ { 0 }
+};
+
+int
+speed(int val)
+{
+ struct speedtab *sp;
+
+ if (val <= B230400)
+ return (val);
+
+ for (sp = speedtab; sp->speed; sp++)
+ if (sp->speed == val)
+ return (sp->uxname);
+
+ return (B300); /* default in impossible cases */
+}
+
+void
+makeenv(char *env[])
+{
+ static char termbuf[128] = "TERM=";
+ char *p, *q;
+ char **ep;
+
+ ep = env;
+ if (TT && *TT) {
+ strlcat(termbuf, TT, sizeof(termbuf));
+ *ep++ = termbuf;
+ }
+ if ((p = EV)) {
+ q = p;
+ while ((q = strchr(q, ','))) {
+ *q++ = '\0';
+ *ep++ = p;
+ p = q;
+ }
+ if (*p)
+ *ep++ = p;
+ }
+ *ep = (char *)0;
+}
+
+/*
+ * This speed select mechanism is written for the Develcon DATASWITCH.
+ * The Develcon sends a string of the form "B{speed}\n" at a predefined
+ * baud rate. This string indicates the user's actual speed.
+ * The routine below returns the terminal type mapped from derived speed.
+ */
+struct portselect {
+ const char *ps_baud;
+ const char *ps_type;
+} portspeeds[] = {
+ { "B110", "std.110" },
+ { "B134", "std.134" },
+ { "B150", "std.150" },
+ { "B300", "std.300" },
+ { "B600", "std.600" },
+ { "B1200", "std.1200" },
+ { "B2400", "std.2400" },
+ { "B4800", "std.4800" },
+ { "B9600", "std.9600" },
+ { "B19200", "std.19200" },
+ { 0 }
+};
+
+const char *
+portselector(void)
+{
+ char c, baud[20];
+ const char *type = "default";
+ struct portselect *ps;
+ int len;
+
+ alarm(5*60);
+ for (len = 0; len < sizeof (baud) - 1; len++) {
+ if (read(STDIN_FILENO, &c, 1) <= 0)
+ break;
+ c &= 0177;
+ if (c == '\n' || c == '\r')
+ break;
+ if (c == 'B')
+ len = 0; /* in case of leading garbage */
+ baud[len] = c;
+ }
+ baud[len] = '\0';
+ for (ps = portspeeds; ps->ps_baud; ps++)
+ if (strcmp(ps->ps_baud, baud) == 0) {
+ type = ps->ps_type;
+ break;
+ }
+ sleep(2); /* wait for connection to complete */
+ return (type);
+}
+
+/*
+ * This auto-baud speed select mechanism is written for the Micom 600
+ * portselector. Selection is done by looking at how the character '\r'
+ * is garbled at the different speeds.
+ */
+const char *
+autobaud(void)
+{
+ int rfds;
+ struct timeval timeout;
+ char c;
+ const char *type = "9600-baud";
+
+ (void)tcflush(0, TCIOFLUSH);
+ rfds = 1 << 0;
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+ if (select(32, (fd_set *)&rfds, (fd_set *)NULL,
+ (fd_set *)NULL, &timeout) <= 0)
+ return (type);
+ if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char))
+ return (type);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 20;
+ (void) select(32, (fd_set *)NULL, (fd_set *)NULL,
+ (fd_set *)NULL, &timeout);
+ (void)tcflush(0, TCIOFLUSH);
+ switch (c & 0377) {
+
+ case 0200: /* 300-baud */
+ type = "300-baud";
+ break;
+
+ case 0346: /* 1200-baud */
+ type = "1200-baud";
+ break;
+
+ case 015: /* 2400-baud */
+ case 0215:
+ type = "2400-baud";
+ break;
+
+ default: /* 4800-baud */
+ type = "4800-baud";
+ break;
+
+ case 0377: /* 9600-baud */
+ type = "9600-baud";
+ break;
+ }
+ return (type);
+}
--- /dev/null
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" from: @(#)ttys.5 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD: src/libexec/getty/ttys.5,v 1.18 2005/06/14 08:40:10 ru Exp $
+.\" "
+.Dd May 27, 2005
+.Dt TTYS 5
+.Os
+.Sh NAME
+.Nm ttys
+.Nd terminal initialization information
+.Sh DESCRIPTION
+The file
+.Nm
+contains information that is used by various routines to initialize
+and control the use of terminal special files.
+This information is read with the
+.Xr getttyent 3
+library routines.
+There is one line in the
+.Nm
+file per special device file.
+Fields are separated by tabs and/or spaces.
+Fields comprised of more than one word should be enclosed in double
+quotes (``"'').
+Blank lines and comments may appear anywhere in the file; comments
+are delimited by hash marks (``#'') and new lines.
+Any unspecified fields will default to null.
+.Pp
+The first field is normally the
+name of the terminal special file as it is found in
+.Pa /dev .
+However, it can be any arbitrary string
+when the associated command is not related to a tty.
+.Pp
+The second field of the file is the command to execute for the line,
+usually
+.Xr getty 8 ,
+which initializes and opens the line, setting the speed, waiting for
+a user name and executing the
+.Xr login 1
+program.
+It can be, however, any desired command, for example
+the start up for a window system terminal emulator or some other
+daemon process, and can contain multiple words if quoted.
+.Pp
+The third field is the type of terminal usually connected to that
+tty line, normally the one found in the
+.Xr termcap 5
+data base file.
+The environment variable
+.Ev TERM
+is initialized with the value by
+either
+.Xr getty 8
+or
+.Xr login 1 .
+.Pp
+The remaining fields set flags in the
+.Fa ty_status
+entry (see
+.Xr getttyent 3 ) ,
+specify a window system process that
+.Xr launchd 8
+will maintain for the terminal line.
+.Pp
+As flag values, the strings ``on'' and ``off'' specify that
+.Xr launchd 8
+should (should not) execute the command given in the second field,
+while ``secure'' (if ``on'' is also specified) allows users with a
+uid of 0 to login on
+this line.
+The flags ``local'', ``rtscts'', ``mdmbuf'', and ``softcar''
+modify the default behaviour of the terminal line, and their actions
+are driver dependent.
+The ``local'' flag causes the driver to
+treat the line as if it locally connected.
+The ``rtscts'' flag
+instructs the driver to use RTS/CTS hardware flow control, if
+possible.
+The ``mdmbuf'' flag instructs the driver to use
+DTR/DCD flow control, if possible.
+The ``softcar'' flag causes the driver to ignore
+hardware carrier on the line.
+These flag fields should not be quoted.
+.Pp
+The string ``window='' may be followed by a quoted command
+string which
+.Xr launchd 8
+will execute
+.Em before
+starting the command specified by the second field.
+.Sh FILES
+.Bl -tag -width /etc/ttys -compact
+.It Pa /etc/ttys
+.El
+.Sh NUMERIC SEQUENCES
+Numeric sequences of terminals can be represented in a more compact format.
+A matching pair of square bracket may enclose two numbers (the start and
+stop values), separated by a hyphen.
+The numbers are assumed to be decimal, unless prefixed with ``0x'', in which
+case they are interpreted as hexadecimal.
+The number of characters (not including any ``0x'') in the starting value gives
+the minimum width; sequence values are zero padded up to this width.
+Thus ``tty[00-07]'' represents the eight terminals ``tty00'' through ``tty07''.
+.Sh EXAMPLES
+.Bd -literal
+# root login on console at 1200 baud
+console "/usr/libexec/getty std.1200" vt100 on secure
+# dialup at 1200 baud, no root logins
+ttyd0 "/usr/libexec/getty d1200" dialup on # 555-1234
+# Mike's terminal: hp2621
+ttyh0 "/usr/libexec/getty std.9600" hp2621-nl on # 457 Evans
+# John's terminal: vt100
+ttyh1 "/usr/libexec/getty std.9600" vt100 on # 459 Evans
+# terminal emulate/window system
+ttyv0 "/usr/X11/bin/xterm -display :0" xterm on window="/usr/X11/bin/X :0"
+# the sequence of eight terminals tty00 through tty07
+tty[00-07] "/usr/libexec/getty std.9600" vt100 on
+# Network pseudo ttys -- don't enable getty
+ttyp0 none network
+ttyp1 none network off
+# All sixteen of a pseudo tty sequence
+ttyq[0x0-0xf] none network
+.Ed
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr getttyent 3 ,
+.Xr ttyslot 3 ,
+.Xr gettytab 5 ,
+.Xr termcap 5 ,
+.Xr getty 8 ,
+.Xr launchd 8
+.\" .Xr ttyflags 8
+.Sh HISTORY
+A
+.Nm
+file appeared in
+.At v6 .
--- /dev/null
+.\" Copyright (c) 2003-2009 Apple Inc. All rights reserved.
+.\"
+.\" 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.
+.\"
+.\" @(#)hostinfo.1
+.Dd October 30, 2003 \" DATE
+.Dt hostinfo 8 \" Program name and manual section number
+.Os "Mac OS X"
+.Sh NAME \" Section Header - required - don't modify
+.Nm hostinfo
+.\" The following lines are read in generating the apropos(man -k) database. Use only key
+.\" words here as the database is built based on the words here and in the .ND line.
+.\" Use .Nm macro to designate other names for the documented program.
+.Nd host information
+.Sh SYNOPSIS \" Section Header - required - don't modify
+.Nm
+.Sh DESCRIPTION \" Section Header - required - don't modify
+The
+.Nm
+command displays information about the host system on which the command is executing.
+The output includes
+a kernel version description,
+processor configuration data,
+available physical memory,
+and various scheduling statistics.
+.Pp
+.Sh OPTIONS
+There are no options.
+.Sh DISPLAY
+.Pp
+.Bl -ohang -width Primary_memory_available_ -offset indent
+.It Mach kernel version:
+The version string compiled into the kernel executing on the host system.
+.Pp
+.It Processor Configuration:
+The maximum possible processors for which the kernel is configured,
+followed by the number of physical and logical processors available.
+.Pp
+Note: on Intel architectures, physical processors are referred to as cores, and
+logical processors are referred to as hardware threads; there may be multiple
+logical processors per core and multiple cores per processor package.
+This command does not report the number of processor packages.
+.Pp
+.It Processor type:
+The host's processor type and subtype.
+.Pp
+.It Processor active:
+A list of active processors on the host system.
+Active processors are members of a processor set and are ready to
+dispatch threads.
+On a single processor system, the active processor, is processor 0.
+.Pp
+.It Primary memory available:
+The amount of physical memory that is configured for use on the host system.
+.Pp
+.It Default processor set:
+Displays the number of tasks currently assigned to the host processor set,
+the number of threads currently assigned to the host processor set,
+and the number of processors included in the host processor set.
+.Pp
+.It Load average:
+Measures the average number of threads in the run queue.
+.Pp
+.It Mach factor:
+A variant of the load average which measures
+the processing resources available to a new thread.
+Mach factor is based on the number of CPUs divided by (1 + the number of runnablethreads)
+or
+the number of CPUs minus the number of runnable threads when the number of runnable threads
+is less than the number of CPUs.
+The closer the Mach factor value is to zero, the higher the load.
+On an idle system with a fixed number of active processors, the mach factor will be equal to the number of CPUs.
+.El
+.Sh SEE ALSO
+.\" List links in ascending order by section, alphabetically within a section.
+.Xr sysctl 8
+.\" .Sh BUGS \" Document known, unremedied bugs
--- /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@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1990 Carnegie-Mellon University
+ * All rights reserved. The CMU software License Agreement specifies
+ * the terms and conditions for use and redistribution.
+ */
+/*
+ * File: hostinfo.c
+ * Author: Avadis Tevanian, Jr.
+ *
+ * Copyright (C) 1987, Avadis Tevanian, Jr.
+ *
+ * Display information about the host this program is
+ * execting on.
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <sys/sysctl.h>
+#include <sys/errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct host_basic_info hi;
+kernel_version_t version;
+int slots[1024];
+
+int main(int argc, char *argv[])
+{
+ kern_return_t ret;
+ unsigned int size, count;
+ char *cpu_name, *cpu_subname;
+ int i;
+ int mib[2];
+ size_t len;
+ uint64_t memsize;
+ processor_set_name_port_t default_pset;
+ host_name_port_t host;
+ struct processor_set_basic_info basic_info;
+ struct processor_set_load_info load_info;
+
+ host = mach_host_self();
+ ret = host_kernel_version(host, version);
+ if (ret != KERN_SUCCESS) {
+ mach_error(argv[0], ret);
+ exit(EXIT_FAILURE);
+ }
+ printf("Mach kernel version:\n\t %s\n", version);
+ size = sizeof(hi)/sizeof(int);
+ ret = host_info(host, HOST_BASIC_INFO, (host_info_t)&hi, &size);
+ if (ret != KERN_SUCCESS) {
+ mach_error(argv[0], ret);
+ exit(EXIT_FAILURE);
+ }
+
+ ret = processor_set_default(host, &default_pset);
+ if (ret != KERN_SUCCESS) {
+ mach_error(argv[0], ret);
+ exit(EXIT_FAILURE);
+ }
+
+ count = PROCESSOR_SET_BASIC_INFO_COUNT;
+ ret = processor_set_info(default_pset, PROCESSOR_SET_BASIC_INFO,
+ &host, (processor_set_info_t)&basic_info, &count);
+ if (ret != KERN_SUCCESS) {
+ mach_error(argv[0], ret);
+ exit(EXIT_FAILURE);
+ }
+
+ count = PROCESSOR_SET_LOAD_INFO_COUNT;
+ ret = processor_set_statistics(default_pset, PROCESSOR_SET_LOAD_INFO,
+ (processor_set_info_t)&load_info, &count);
+ if (ret != KERN_SUCCESS) {
+ mach_error(argv[0], ret);
+ exit(EXIT_FAILURE);
+ }
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_MEMSIZE;
+ len = sizeof(memsize);
+ memsize = 0L;
+ if(sysctl(mib, 2, &memsize, &len, NULL, 0 ) == -1)
+ {
+ perror("sysctl");
+ exit(EXIT_FAILURE);
+ }
+
+
+ if (hi.max_cpus > 1)
+ printf("Kernel configured for up to %d processors.\n",
+ hi.max_cpus);
+ else
+ printf("Kernel configured for a single processor only.\n");
+ printf("%d processor%s physically available.\n", hi.physical_cpu,
+ (hi.physical_cpu > 1) ? "s are" : " is");
+
+ printf("%d processor%s logically available.\n", hi.logical_cpu,
+ (hi.logical_cpu > 1) ? "s are" : " is");
+
+ printf("Processor type:");
+ slot_name(hi.cpu_type, hi.cpu_subtype, &cpu_name, &cpu_subname);
+ printf(" %s (%s)\n", cpu_name, cpu_subname);
+
+ printf("Processor%s active:", (hi.avail_cpus > 1) ? "s" : "");
+ for (i = 0; i < hi.avail_cpus; i++)
+ printf(" %d", i);
+ printf("\n");
+
+ if (((float)memsize / (1024.0 * 1024.0)) >= 1024.0)
+ printf("Primary memory available: %.2f gigabytes\n",
+ (float)memsize/(1024.0*1024.0*1024.0));
+ else
+ printf("Primary memory available: %.2f megabytes\n",
+ (float)memsize/(1024.0*1024.0));
+
+ printf("Default processor set: %d tasks, %d threads, %d processors\n",
+ load_info.task_count, load_info.thread_count, basic_info.processor_count);
+ printf("Load average: %d.%02d, Mach factor: %d.%02d\n",
+ load_info.load_average/LOAD_SCALE,
+ (load_info.load_average%LOAD_SCALE)/10,
+ load_info.mach_factor/LOAD_SCALE,
+ (load_info.mach_factor%LOAD_SCALE)/10);
+
+ exit(0);
+}
+
--- /dev/null
+.\"
+.\" Copyright (c) 1997 Kenneth D. Merry.
+.\" 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. 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD: src/usr.sbin/iostat/iostat.8,v 1.20 2001/08/07 13:59:48 ru Exp $
+.\"
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)iostat.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd September 27, 2001
+.Dt IOSTAT 8
+.Os
+.Sh NAME
+.Nm iostat
+.Nd report
+.Tn I/O
+statistics
+.Sh SYNOPSIS
+.Nm iostat
+.Op Fl CUdKIoT?\&
+.Op Fl c Ar count
+.Op Fl n Ar devs
+.Op Fl w Ar wait
+.Op Ar drives
+.Sh DESCRIPTION
+.Nm Iostat
+displays kernel
+.Tn I/O
+statistics on terminal, device and cpu operations.
+The first statistics that are printed are averaged over the system uptime.
+To get information about the current activity, a suitable wait time should
+be specified, so that the subsequent sets of printed statistics will be
+averaged over that time.
+.Pp
+The options are as follows:
+.Bl -tag -width flag
+.\" ==========
+.It Fl ?\&
+Display a usage statement and exit.
+.\" ==========
+.It Fl C
+Display CPU statistics.
+This is on by default, unless
+.Fl d
+is specified.
+.\" ==========
+.It Fl c
+Repeat the display
+.Ar count
+times.
+If no
+.Ar wait
+interval is specified, the default is 1 second.
+.\" ==========
+.It Fl d
+Display only device statistics.
+If this flag is turned on, only device statistics will be displayed, unless
+.Fl C
+or
+.Fl U
+or
+.Fl T
+is also specfied to enable the display of CPU, load average or TTY statistics.
+.\" ==========
+.It Fl I
+Display total statstics for a given time period, rather than average
+statistics for each second during that time period.
+.\" ==========
+.It Fl K
+In the blocks transferred display (-o), display block count in kilobytes rather
+then the device native block size.
+.\" ==========
+.It Fl n
+Display up to
+.Ar devs
+number of devices.
+.Nm iostat
+will display fewer devices if there aren't
+.Ar devs
+devices present.
+.\" ==========
+.It Fl o
+Display old-style
+.Nm iostat
+device statistics.
+Sectors per second, transfers per second, and miliseconds per seek are
+displayed.
+If
+.Fl I
+is specified, total blocks/sectors, total transfers, and
+miliseconds per seek are displayed.
+.\" ==========
+.It Fl T
+Display TTY statistics.
+This is on by default, unless
+.Fl d
+is specified.
+.\" ==========
+.It Fl U
+Display system load averages.
+This is on by default, unless
+.Fl d
+is specified.
+.\" ==========
+.It Fl w
+Pause
+.Ar wait
+seconds between each display.
+If no repeat
+.Ar count
+is specified, the default is infinity.
+.El
+.Pp
+.Nm Iostat
+displays its information in the following format:
+.Bl -tag -width flag
+.It tty
+.Bl -tag -width indent -compact
+.It tin
+characters read from terminals
+.It tout
+characters written to terminals
+.El
+.It devices
+Device operations.
+The header of the field is the device name and unit number.
+.Nm iostat
+will display as many devices as will fit in a standard 80 column screen, or
+the maximum number of devices in the system, whichever is smaller.
+If
+.Fl n
+is specified on the command line,
+.Nm iostat
+will display the smaller of the
+requested number of devices, and the maximum number of devices in the system.
+To force
+.Nm iostat
+to display specific drives, their names may be supplied on the command
+line.
+.Nm iostat
+will not display more devices than will fit in an 80 column screen, unless
+the
+.Fl n
+argument is given on the command line to specify a maximum number of
+devices to display, or the list of specified devices exceeds 80 columns.
+If fewer devices are specified on the command line than will fit in an 80
+column screen,
+.Nm iostat
+will show only the specified devices.
+.Pp
+The standard
+.Nm iostat
+device display shows the following statistics:
+.Pp
+.Bl -tag -width indent -compact
+.It KB/t
+kilobytes per transfer
+.It tps
+transfers per second
+.It MB/s
+megabytes per second
+.El
+.Pp
+The standard
+.Nm iostat
+device display, with the
+.Fl I
+flag specified, shows the following statistics:
+.Pp
+.Bl -tag -width indent -compact
+.It KB/t
+kilobytes per transfer
+.It xfrs
+total number of transfers
+.It MB
+total number of megabytes transferred
+.El
+.Pp
+The old-style
+.Nm iostat
+display (using
+.Fl o )
+shows the following statistics:
+.Pp
+.Bl -tag -width indent -compact
+.It sps
+sectors transferred per second
+.It tps
+transfers per second
+.It msps
+average milliseconds per transaction
+.El
+.Pp
+The old-style
+.Nm iostat
+display, with the
+.Fl I
+flag specified, shows the following statistics:
+.Pp
+.Bl -tag -width indent -compact
+.It blk
+total blocks/sectors transferred
+.It xfr
+total transfers
+.It msps
+average milliseconds per transaction
+.El
+.It cpu
+.Bl -tag -width indent -compact
+.It \&us
+% of cpu time in user mode
+.It \&sy
+% of cpu time in system mode
+.It \&id
+% of cpu time in idle mode
+.El
+.El
+.Sh EXAMPLES
+.Dl iostat -w 1 disk0 disk2
+.Pp
+Display statistics for the first and third disk devices device every
+second ad infinitum.
+.Pp
+.Dl iostat -c 2
+.Pp
+Display the statistics for the first four devices in the system twice, with
+a one second display interval.
+.Pp
+.Dl iostat -Iw 3
+.Pp
+Display total statistics every three seconds ad infinitum.
+.Pp
+.Dl iostat -odICTw 2 -c 9
+.Pp
+Display total statistics using the old-style output format 9 times, with
+a two second interval between each measurement/display.
+The
+.Fl d
+flag generally disables the TTY and CPU displays, but since the
+.Fl T
+and
+.Fl C
+flags are given, the TTY and CPU displays will be displayed.
+.Sh SEE ALSO
+.Xr fstat 1 ,
+.Xr netstat 1 ,
+.Xr nfsstat 1 ,
+.Xr ps 1 ,
+.Xr pstat 8
+.Pp
+The sections starting with ``Interpreting system activity'' in
+.%T "Installing and Operating 4.3BSD" .
+.Sh HISTORY
+This version of
+.Nm iostat
+first appeared in
+.Nm FreeBSD 3.0 .
--- /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) 1997, 1998, 2000, 2001 Kenneth D. Merry
+ * 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. 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD: src/usr.sbin/iostat/iostat.c,v 1.22 2001/09/01 07:40:19 kris Exp $
+ */
+/*
+ * Parts of this program are derived from the original FreeBSD iostat
+ * program:
+ */
+/*-
+ * Copyright (c) 1986, 1991, 1993
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+/*
+ * Ideas for the new iostat statistics output modes taken from the NetBSD
+ * version of iostat:
+ */
+/*
+ * Copyright (c) 1996 John M. Vinopal
+ * 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 for the NetBSD Project
+ * by John M. Vinopal.
+ * 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.
+ */
+
+#define IOKIT 1 /* to get io_name_t in device_types.h */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/storage/IOBlockStorageDriver.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/IOBSD.h>
+#include <mach/mach_host.h> /* host_statistics */
+#include <err.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define MAXDRIVES 16 /* most drives we will record */
+#define MAXDRIVENAME 31 /* largest drive name we allow */
+
+struct drivestats {
+ io_registry_entry_t driver;
+ char name[MAXDRIVENAME + 1];
+ u_int64_t blocksize;
+ u_int64_t total_bytes;
+ u_int64_t total_transfers;
+ u_int64_t total_time;
+};
+
+static struct drivestats drivestat[MAXDRIVES];
+
+static struct timeval cur_time, last_time;
+
+struct statinfo {
+ long tk_nin;
+ long tk_nout;
+ host_cpu_load_info_data_t load;
+};
+
+static struct statinfo cur, last;
+
+static mach_port_t host_priv_port;
+static mach_port_t masterPort;
+
+static int num_devices;
+static int maxshowdevs;
+static int dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Uflag = 0, Kflag = 0;
+static volatile sig_atomic_t phdr_flag = 0;
+static IONotificationPortRef notifyPort;
+
+/* local function declarations */
+static void usage(void);
+static void phdr(int signo);
+static void do_phdr();
+static void devstats(int perf_select, long double etime, int havelast);
+static void cpustats(void);
+static void loadstats(void);
+static int readvar(const char *name, void *ptr, size_t len);
+
+static int record_all_devices(void);
+static void record_drivelist(void* context, io_iterator_t drivelist);
+static void remove_drivelist(void* context, io_iterator_t drivelist);
+static int record_one_device(char *name);
+static int record_device(io_registry_entry_t drive);
+
+static int compare_drivestats(const void* pa, const void* pb);
+
+static long double compute_etime(struct timeval cur_time,
+ struct timeval prev_time);
+
+static void
+usage(void)
+{
+ /*
+ * We also support the following 'traditional' syntax:
+ * iostat [drives] [wait [count]]
+ * This isn't mentioned in the man page, or the usage statement,
+ * but it is supported.
+ */
+ fprintf(stderr, "usage: iostat [-CUdIKoT?] [-c count] [-n devs]\n"
+ "\t [-w wait] [drives]\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ int hflag = 0, cflag = 0, wflag = 0, nflag = 0;
+ int count = 0, waittime = 0;
+ int headercount;
+ int num_devices_specified;
+ int havelast = 0;
+
+ CFRunLoopSourceRef rls;
+
+ maxshowdevs = 3;
+
+ while ((c = getopt(argc, argv, "c:CdIKM:n:oTUw:?")) != -1) {
+ switch(c) {
+ case 'c':
+ cflag++;
+ count = atoi(optarg);
+ if (count < 1)
+ errx(1, "count %d is < 1", count);
+ break;
+ case 'C':
+ Cflag++;
+ break;
+ case 'd':
+ dflag++;
+ break;
+ case 'I':
+ Iflag++;
+ break;
+ case 'K':
+ Kflag++;
+ break;
+ case 'n':
+ nflag++;
+ maxshowdevs = atoi(optarg);
+ if (maxshowdevs < 0)
+ errx(1, "number of devices %d is < 0",
+ maxshowdevs);
+ break;
+ case 'o':
+ oflag++;
+ break;
+ case 'T':
+ Tflag++;
+ break;
+ case 'U':
+ Uflag++;
+ break;
+ case 'w':
+ wflag++;
+ waittime = atoi(optarg);
+ if (waittime < 1)
+ errx(1, "wait time is < 1");
+ break;
+ default:
+ usage();
+ exit(1);
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * Get the Mach private port.
+ */
+ host_priv_port = mach_host_self();
+
+ /*
+ * Get the I/O Kit communication handle.
+ */
+ IOMasterPort(bootstrap_port, &masterPort);
+
+ notifyPort = IONotificationPortCreate(masterPort);
+ rls = IONotificationPortGetRunLoopSource(notifyPort);
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+
+ /*
+ * Make sure Tflag, Cflag and Uflag are set if dflag == 0. If dflag is
+ * greater than 0, they may be 0 or non-zero.
+ */
+ if (dflag == 0) {
+ Cflag = 1;
+ Tflag = 1;
+ Uflag = 1;
+ }
+
+ /*
+ * TTY statistics are broken, disabling them.
+ */
+ Tflag = 0;
+
+ /*
+ * Figure out how many devices we should display if not given
+ * an explicit value.
+ */
+ if (nflag == 0) {
+ if (oflag > 0) {
+ if ((dflag > 0) && (Cflag == 0) && (Tflag == 0))
+ maxshowdevs = 5;
+ else if ((dflag > 0) && (Tflag > 0) && (Cflag == 0))
+ maxshowdevs = 5;
+ else
+ maxshowdevs = 4;
+ } else {
+ if ((dflag > 0) && (Cflag == 0))
+ maxshowdevs = 4;
+ else
+ maxshowdevs = 3;
+ }
+ }
+
+ /*
+ * If the user specified any devices on the command line, record
+ * them for monitoring.
+ */
+ for (num_devices_specified = 0; *argv; ++argv) {
+ if (isdigit(**argv))
+ break;
+ if (record_one_device(*argv))
+ errx(1, "can't record '%s' for monitoring", *argv);
+ num_devices_specified++;
+ }
+ if (nflag == 0 && maxshowdevs < num_devices_specified)
+ maxshowdevs = num_devices_specified;
+
+ /* if no devices were specified, pick them ourselves */
+ if ((num_devices_specified == 0) && record_all_devices())
+ err(1, "can't find any devices to display");
+
+ /*
+ * Look for the traditional wait time and count arguments.
+ */
+ if (*argv) {
+ waittime = atoi(*argv);
+
+ /* Let the user know he goofed, but keep going anyway */
+ if (wflag != 0)
+ warnx("discarding previous wait interval, using"
+ " %d instead", waittime);
+ wflag++;
+
+ if (*++argv) {
+ count = atoi(*argv);
+ if (cflag != 0)
+ warnx("discarding previous count, using %d"
+ " instead", count);
+ cflag++;
+ } else
+ count = -1;
+ }
+
+ /*
+ * If the user specified a count, but not an interval, we default
+ * to an interval of 1 second.
+ */
+ if ((wflag == 0) && (cflag > 0))
+ waittime = 1;
+
+ /*
+ * If the user specified a wait time, but not a count, we want to
+ * go on ad infinitum. This can be redundant if the user uses the
+ * traditional method of specifying the wait, since in that case we
+ * already set count = -1 above. Oh well.
+ */
+ if ((wflag > 0) && (cflag == 0))
+ count = -1;
+
+ cur.tk_nout = 0;
+ cur.tk_nin = 0;
+
+ /*
+ * Set the busy time to the system boot time, so the stats are
+ * calculated since system boot.
+ */
+ if (readvar("kern.boottime", &cur_time, sizeof(cur_time)) != 0)
+ exit(1);
+
+ /*
+ * If the user stops the program (control-Z) and then resumes it,
+ * print out the header again.
+ */
+ (void)signal(SIGCONT, phdr);
+
+ for (headercount = 1;;) {
+ long tmp;
+ long double etime;
+
+ if (Tflag > 0) {
+ if ((readvar("kern.tty_nin", &cur.tk_nin,
+ sizeof(cur.tk_nin)) != 0)
+ || (readvar("kern.tty_nout",
+ &cur.tk_nout, sizeof(cur.tk_nout))!= 0)) {
+ Tflag = 0;
+ warnx("disabling TTY statistics");
+ }
+ }
+
+ if (!--headercount || phdr_flag) {
+ phdr_flag = 0;
+ headercount = 20;
+ do_phdr();
+ }
+
+ last_time = cur_time;
+ gettimeofday(&cur_time, NULL);
+
+ if (Tflag > 0) {
+ tmp = cur.tk_nin;
+ cur.tk_nin -= last.tk_nin;
+ last.tk_nin = tmp;
+ tmp = cur.tk_nout;
+ cur.tk_nout -= last.tk_nout;
+ last.tk_nout = tmp;
+ }
+
+ etime = compute_etime(cur_time, last_time);
+
+ if (etime == 0.0)
+ etime = 1.0;
+
+ if (Tflag > 0)
+ printf("%4.0Lf%5.0Lf", cur.tk_nin / etime,
+ cur.tk_nout / etime);
+
+ devstats(hflag, etime, havelast);
+
+ if (Cflag > 0)
+ cpustats();
+
+ if (Uflag > 0)
+ loadstats();
+
+ printf("\n");
+ fflush(stdout);
+
+ if (count >= 0 && --count <= 0)
+ break;
+
+ /*
+ * Instead of sleep(waittime), wait in
+ * the RunLoop for IONotifications.
+ */
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, (CFTimeInterval)waittime, 1);
+
+ havelast = 1;
+ }
+
+ exit(0);
+}
+
+static void
+phdr(int signo)
+{
+
+ phdr_flag = 1;
+}
+
+static void
+do_phdr()
+{
+ register int i;
+
+ if (Tflag > 0)
+ (void)printf(" tty");
+
+ for (i = 0; i < num_devices && i < maxshowdevs; i++){
+ if (oflag > 0)
+ (void)printf("%12.6s ", drivestat[i].name);
+ else
+ printf("%15.6s ", drivestat[i].name);
+ }
+
+ if (Cflag > 0)
+ (void)printf(" cpu");
+
+ if (Uflag > 0)
+ (void)printf(" load average\n");
+ else
+ (void)printf("\n");
+
+ if (Tflag > 0)
+ (void)printf(" tin tout");
+
+ for (i=0; i < num_devices && i < maxshowdevs; i++){
+ if (oflag > 0) {
+ if (Iflag == 0)
+ (void)printf(" sps tps msps ");
+ else
+ (void)printf(" blk xfr msps ");
+ } else {
+ if (Iflag == 0)
+ printf(" KB/t tps MB/s ");
+ else
+ printf(" KB/t xfrs MB ");
+ }
+ }
+
+ if (Cflag > 0)
+ (void)printf(" us sy id");
+
+ if (Uflag > 0)
+ (void)printf(" 1m 5m 15m\n");
+ else
+ printf("\n");
+}
+
+static void
+devstats(int perf_select, long double etime, int havelast)
+{
+ CFNumberRef number;
+ CFDictionaryRef properties;
+ CFDictionaryRef statistics;
+ long double transfers_per_second;
+ long double kb_per_transfer, mb_per_second;
+ u_int64_t value;
+ u_int64_t total_bytes, total_transfers, total_blocks, total_time;
+ u_int64_t interval_bytes, interval_transfers, interval_blocks;
+ u_int64_t interval_time;
+ long double interval_mb;
+ long double blocks_per_second, ms_per_transaction;
+ kern_return_t status;
+ int i;
+
+ for (i = 0; i < num_devices && i < maxshowdevs; i++) {
+
+ /*
+ * If the drive goes away, we may not get any properties
+ * for it. So take some defaults.
+ */
+ total_bytes = 0;
+ total_transfers = 0;
+ total_time = 0;
+
+ /* get drive properties */
+ status = IORegistryEntryCreateCFProperties(drivestat[i].driver,
+ (CFMutableDictionaryRef *)&properties,
+ kCFAllocatorDefault,
+ kNilOptions);
+ if (status != KERN_SUCCESS)
+ continue;
+
+ /* get statistics from properties */
+ statistics = (CFDictionaryRef)CFDictionaryGetValue(properties,
+ CFSTR(kIOBlockStorageDriverStatisticsKey));
+ if (statistics) {
+
+ /*
+ * Get I/O volume.
+ */
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_bytes += value;
+ }
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_bytes += value;
+ }
+
+ /*
+ * Get I/O counts.
+ */
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_transfers += value;
+ }
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_transfers += value;
+ }
+
+ /*
+ * Get I/O time.
+ */
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsLatentReadTimeKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_time += value;
+ }
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsLatentWriteTimeKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_time += value;
+ }
+
+ }
+ CFRelease(properties);
+
+ /*
+ * Compute delta values and stats.
+ */
+ interval_bytes = total_bytes - drivestat[i].total_bytes;
+ interval_transfers = total_transfers
+ - drivestat[i].total_transfers;
+ interval_time = total_time - drivestat[i].total_time;
+
+ /* update running totals, only once for -I */
+ if ((Iflag == 0) || (drivestat[i].total_bytes == 0)) {
+ drivestat[i].total_bytes = total_bytes;
+ drivestat[i].total_transfers = total_transfers;
+ drivestat[i].total_time = total_time;
+ }
+
+ interval_blocks = interval_bytes / drivestat[i].blocksize;
+ total_blocks = total_bytes / drivestat[i].blocksize;
+
+ blocks_per_second = interval_blocks / etime;
+ transfers_per_second = interval_transfers / etime;
+ mb_per_second = (interval_bytes / etime) / (1024 * 1024);
+
+ kb_per_transfer = (interval_transfers > 0) ?
+ ((long double)interval_bytes / interval_transfers)
+ / 1024 : 0;
+
+ /* times are in nanoseconds, convert to milliseconds */
+ ms_per_transaction = (interval_transfers > 0) ?
+ ((long double)interval_time / interval_transfers)
+ / 1000 : 0;
+
+ if (Kflag)
+ total_blocks = total_blocks * drivestat[i].blocksize
+ / 1024;
+
+ if (oflag > 0) {
+ int msdig = (ms_per_transaction < 100.0) ? 1 : 0;
+
+ if (Iflag == 0)
+ printf("%4.0Lf%4.0Lf%5.*Lf ",
+ blocks_per_second,
+ transfers_per_second,
+ msdig,
+ ms_per_transaction);
+ else
+ printf("%4.1qu%4.1qu%5.*Lf ",
+ interval_blocks,
+ interval_transfers,
+ msdig,
+ ms_per_transaction);
+ } else {
+ if (Iflag == 0)
+ printf(" %7.2Lf %3.0Lf %5.2Lf ",
+ kb_per_transfer,
+ transfers_per_second,
+ mb_per_second);
+ else {
+ interval_mb = interval_bytes;
+ interval_mb /= 1024 * 1024;
+
+ printf(" %7.2Lf %3.1qu %5.2Lf ",
+ kb_per_transfer,
+ interval_transfers,
+ interval_mb);
+ }
+ }
+ }
+}
+
+static void
+cpustats(void)
+{
+ mach_msg_type_number_t count;
+ kern_return_t status;
+ double time;
+
+ /*
+ * Get CPU usage counters.
+ */
+ count = HOST_CPU_LOAD_INFO_COUNT;
+ status = host_statistics(host_priv_port, HOST_CPU_LOAD_INFO,
+ (host_info_t)&cur.load, &count);
+ if (status != KERN_SUCCESS)
+ errx(1, "couldn't fetch CPU stats");
+
+ /*
+ * Make 'cur' fields relative, update 'last' fields to current values,
+ * calculate total elapsed time.
+ */
+ time = 0.0;
+ cur.load.cpu_ticks[CPU_STATE_USER]
+ -= last.load.cpu_ticks[CPU_STATE_USER];
+ last.load.cpu_ticks[CPU_STATE_USER]
+ += cur.load.cpu_ticks[CPU_STATE_USER];
+ time += cur.load.cpu_ticks[CPU_STATE_USER];
+ cur.load.cpu_ticks[CPU_STATE_SYSTEM]
+ -= last.load.cpu_ticks[CPU_STATE_SYSTEM];
+ last.load.cpu_ticks[CPU_STATE_SYSTEM]
+ += cur.load.cpu_ticks[CPU_STATE_SYSTEM];
+ time += cur.load.cpu_ticks[CPU_STATE_SYSTEM];
+ cur.load.cpu_ticks[CPU_STATE_IDLE]
+ -= last.load.cpu_ticks[CPU_STATE_IDLE];
+ last.load.cpu_ticks[CPU_STATE_IDLE]
+ += cur.load.cpu_ticks[CPU_STATE_IDLE];
+ time += cur.load.cpu_ticks[CPU_STATE_IDLE];
+
+ /*
+ * Print times.
+ */
+#define PTIME(kind) { \
+ double cpu = rint(100. * cur.load.cpu_ticks[kind] / (time ? time : 1));\
+ printf("%*.0f", (100 == cpu) ? 4 : 3, cpu); \
+}
+ PTIME(CPU_STATE_USER);
+ PTIME(CPU_STATE_SYSTEM);
+ PTIME(CPU_STATE_IDLE);
+}
+
+static void
+loadstats(void)
+{
+ double loadavg[3];
+
+ if(getloadavg(loadavg,3)!=3)
+ errx(1, "couldn't fetch load average");
+
+ printf(" %4.2f %4.2f %4.2f",loadavg[0],loadavg[1],loadavg[2]);
+}
+
+static int
+readvar(const char *name, void *ptr, size_t len)
+{
+ int oid[4];
+ int oidlen;
+
+ size_t nlen = len;
+
+ if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
+ if (errno != ENOENT) {
+ warn("sysctl(%s) failed", name);
+ return (1);
+ }
+ /*
+ * XXX fallback code to deal with systems where
+ * sysctlbyname can't find "old" OIDs, should be removed.
+ */
+ if (!strcmp(name, "kern.boottime")) {
+ oid[0] = CTL_KERN;
+ oid[1] = KERN_BOOTTIME;
+ oidlen = 2;
+ } else {
+ warn("sysctl(%s) failed", name);
+ return (1);
+ }
+
+ nlen = len;
+ if (sysctl(oid, oidlen, ptr, &nlen, NULL, 0) == -1) {
+ warn("sysctl(%s) failed", name);
+ return (1);
+ }
+ }
+ if (nlen != len) {
+ warnx("sysctl(%s): expected %lu, got %lu", name,
+ (unsigned long)len, (unsigned long)nlen);
+ return (1);
+ }
+ return (0);
+}
+
+static long double
+compute_etime(struct timeval cur_time, struct timeval prev_time)
+{
+ struct timeval busy_time;
+ u_int64_t busy_usec;
+ long double etime;
+
+ timersub(&cur_time, &prev_time, &busy_time);
+
+ busy_usec = busy_time.tv_sec;
+ busy_usec *= 1000000;
+ busy_usec += busy_time.tv_usec;
+ etime = busy_usec;
+ etime /= 1000000;
+
+ return(etime);
+}
+
+/*
+ * Record all "whole" IOMedia objects as being interesting.
+ */
+static int
+record_all_devices(void)
+{
+ io_iterator_t drivelist;
+ CFMutableDictionaryRef match;
+ kern_return_t status;
+
+ /*
+ * Get an iterator for IOMedia objects.
+ */
+ match = IOServiceMatching("IOMedia");
+ CFDictionaryAddValue(match, CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
+
+ CFRetain(match);
+ status = IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, match, &record_drivelist, NULL, &drivelist);
+
+ if (status != KERN_SUCCESS)
+ errx(1, "couldn't match whole IOMedia devices");
+
+ /*
+ * Scan all of the IOMedia objects, and for each
+ * object that has a parent IOBlockStorageDriver, save
+ * the object's name and the parent (from which we can
+ * fetch statistics).
+ *
+ * XXX What about RAID devices?
+ */
+
+ record_drivelist(NULL, drivelist);
+
+
+ status = IOServiceAddMatchingNotification(notifyPort, kIOTerminatedNotification, match, &remove_drivelist, NULL, &drivelist);
+
+ if (status != KERN_SUCCESS)
+ errx(1, "couldn't match whole IOMedia device removal");
+
+ remove_drivelist(NULL, drivelist);
+
+ return(0);
+}
+
+static void record_drivelist(void* context, io_iterator_t drivelist)
+{
+ io_registry_entry_t drive;
+ while ((drive = IOIteratorNext(drivelist))) {
+ if (num_devices < MAXDRIVES) {
+ record_device(drive);
+ phdr_flag = 1;
+ }
+ IOObjectRelease(drive);
+ }
+ qsort(drivestat, num_devices, sizeof(struct drivestats), &compare_drivestats);
+}
+
+static void remove_drivelist(void* context, io_iterator_t drivelist)
+{
+ io_registry_entry_t drive;
+ while ((drive = IOIteratorNext(drivelist))) {
+ kern_return_t status;
+ char bsdname[MAXDRIVENAME];
+ CFDictionaryRef properties;
+ CFStringRef name;
+
+ /* get drive properties */
+ status = IORegistryEntryCreateCFProperties(drive,
+ (CFMutableDictionaryRef *)&properties,
+ kCFAllocatorDefault,
+ kNilOptions);
+ if (status != KERN_SUCCESS) continue;
+
+ /* get name from properties */
+ name = (CFStringRef)CFDictionaryGetValue(properties,
+ CFSTR(kIOBSDNameKey));
+
+ if (name && CFStringGetCString(name, bsdname, MAXDRIVENAME, kCFStringEncodingUTF8)) {
+ int i;
+ for (i = 0; i < num_devices; ++i) {
+ if (strcmp(bsdname,drivestat[i].name) == 0) {
+ if (i < MAXDRIVES-1) {
+ memmove(&drivestat[i], &drivestat[i+1], sizeof(struct drivestats)*(MAXDRIVES-i));
+ }
+ --num_devices;
+ phdr_flag = 1;
+ qsort(drivestat, num_devices, sizeof(struct drivestats), &compare_drivestats);
+ break;
+ }
+ }
+ }
+ CFRelease(properties);
+ IOObjectRelease(drive);
+ }
+}
+
+/*
+ * Try to record the named device as interesting. It
+ * must be an IOMedia device.
+ */
+static int
+record_one_device(char *name)
+{
+ io_iterator_t drivelist;
+ io_registry_entry_t drive;
+ kern_return_t status;
+
+ /*
+ * Find the device.
+ */
+ status = IOServiceGetMatchingServices(masterPort,
+ IOBSDNameMatching(masterPort, kNilOptions, name),
+ &drivelist);
+ if (status != KERN_SUCCESS)
+ errx(1, "couldn't match '%s'", name);
+
+ /*
+ * Get the first match (should only be one)
+ */
+ if (!(drive = IOIteratorNext(drivelist)))
+ errx(1, "'%s' not found", name);
+ if (!IOObjectConformsTo(drive, "IOMedia"))
+ errx(1, "'%s' is not a storage device", name);
+
+ /*
+ * Record the device.
+ */
+ if (record_device(drive))
+ errx(1, "could not record '%s' for monitoring", name);
+
+ IOObjectRelease(drive);
+ IOObjectRelease(drivelist);
+
+ return(0);
+}
+
+/*
+ * Determine whether an IORegistryEntry refers to a valid
+ * I/O device, and if so, record it.
+ */
+static int
+record_device(io_registry_entry_t drive)
+{
+ io_registry_entry_t parent;
+ CFDictionaryRef properties;
+ CFStringRef name;
+ CFNumberRef number;
+ kern_return_t status;
+
+ /* get drive's parent */
+ status = IORegistryEntryGetParentEntry(drive,
+ kIOServicePlane, &parent);
+ if (status != KERN_SUCCESS)
+ errx(1, "device has no parent");
+ if (IOObjectConformsTo(parent, "IOBlockStorageDriver")) {
+ drivestat[num_devices].driver = parent;
+
+ /* get drive properties */
+ status = IORegistryEntryCreateCFProperties(drive,
+ (CFMutableDictionaryRef *)&properties,
+ kCFAllocatorDefault,
+ kNilOptions);
+ if (status != KERN_SUCCESS)
+ errx(1, "device has no properties");
+
+ /* get name from properties */
+ name = (CFStringRef)CFDictionaryGetValue(properties,
+ CFSTR(kIOBSDNameKey));
+ if (name)
+ CFStringGetCString(name, drivestat[num_devices].name,
+ MAXDRIVENAME, kCFStringEncodingUTF8);
+ else {
+ errx(1, "device does not have a BSD name");
+ }
+
+ /* get blocksize from properties */
+ number = (CFNumberRef)CFDictionaryGetValue(properties,
+ CFSTR(kIOMediaPreferredBlockSizeKey));
+ if (number)
+ CFNumberGetValue(number, kCFNumberSInt64Type,
+ &drivestat[num_devices].blocksize);
+ else
+ errx(1, "device does not have a preferred block size");
+
+ /* clean up, return success */
+ CFRelease(properties);
+ num_devices++;
+ return(0);
+ }
+
+ /* failed, don't keep parent */
+ IOObjectRelease(parent);
+ return(1);
+}
+
+static int
+compare_drivestats(const void* pa, const void* pb)
+{
+ struct drivestats* a = (struct drivestats*)pa;
+ struct drivestats* b = (struct drivestats*)pb;
+ return strcmp(a->name, b->name);
+}
--- /dev/null
+.\" Copyright (c) 2000, Apple Computer, Inc. All rights reserved.
+.\"
+.Dd March 28, 2000
+.Dt LATENCY 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm latency
+.Nd monitors scheduling and interrupt latency
+.Sh SYNOPSIS
+.Nm latency
+.Op Fl p
+.Op Fl h
+.Op Fl m
+.Op Fl st Ar threshold
+.Op Fl it Ar threshold
+.Op Fl c Ar code_file
+.Op Fl l Ar log_file
+.Op Fl R Ar raw_file
+.Op Fl n Ar kernel
+.Sh DESCRIPTION
+The
+.Nm latency
+utility provides scheduling and interrupt-latency statistics.
+Due to the kernel tracing facility it uses to operate,
+the command requires root privileges.
+.Pp
+The arguments are as follows:
+.Bl -tag -width Ds
+.\" ==========
+.It Fl c Ar code_file
+When the
+.Fl c
+option is specified, it takes a path to a code file
+that contains the mappings for the system calls.
+This option overrides the default location of the system call code file,
+which is found in /usr/share/misc/trace.codes.
+.\" ==========
+.It Fl h
+Display high resolution interrupt latencies and write them to latencies.csv (truncate existing file) upon exit.
+.\" ==========
+.It Fl m
+Display per-CPU interrupt latency statistics.
+.\" ==========
+.It Fl it Ar threshold
+Set the interrupt latency threshold,
+expressed in microseconds.
+If the latency exceeds this value,
+and a log file has been specified,
+a record of what occurred during this time is recorded.
+.\" ==========
+.It Fl l Ar log_file
+Specifies a log file that is written to when
+either the interrupt or scheduling latency is exceeded.
+.\" ==========
+.It Fl n Ar kernel
+By default,
+.Nm latency
+acts on the default /mach_kernel.
+This option allows you to specify an alternate booted kernel.
+.\" ==========
+.It Fl p Ar priority
+Specifies the priority level to observe scheduler latencies for.
+.\" ==========
+.It Fl st Ar threshold
+Set the scheduler latency threshold in microseconds.
+If latency exceeds this, and a log file has been specified,
+a record of what occurred during this time is recorded.
+.\" ==========
+.It Fl R Ar raw_file
+Specifies a raw trace file to use as input.
+.El
+.Pp
+The data columns displayed are as follows:
+.Bl -tag -width LAST_PATHNAME_WAITED_FOR
+.It SCHEDULER
+The number of context switches that fall within the described delay.
+.It INTERRUPTS
+The number of interrupts that fall within the described delay.
+.El
+.Pp
+The
+.Nm latency
+utility is also SIGWINCH savvy, so adjusting your window geometry will change
+the list of delay values displayed.
+.Sh SAMPLE USAGE
+.Pp
+latency -p 97 -st 20000 -it 1000 -l /var/tmp/latency.log
+.Pp
+The
+.Nm latency
+utility will watch threads with priority 97 for scheduling latencies.
+The threshold for the scheduler is set to 20000 microseconds.
+The threshold for interrupts is set to 1000 microseconds.
+Latencies that exceed these thresholds will be logged in /var/tmp/latency.log.
+.Sh SEE ALSO
+.Xr fs_usage 1 ,
+.Xr sc_usage 1 ,
+.Xr top 1
--- /dev/null
+/*
+ * Copyright (c) 1999-2010 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@
+ */
+
+/*
+ cc -I/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders -DPRIVATE -D__APPLE_PRIVATE -arch x86_64 -arch i386 -O -o latency latency.c -lncurses -lutil
+*/
+
+#include <mach/mach.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <strings.h>
+#include <nlist.h>
+#include <fcntl.h>
+#include <string.h>
+#include <libc.h>
+#include <termios.h>
+#include <curses.h>
+#include <libutil.h>
+#include <errno.h>
+#include <err.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+
+#ifndef KERNEL_PRIVATE
+#define KERNEL_PRIVATE
+#include <sys/kdebug.h>
+#undef KERNEL_PRIVATE
+#else
+#include <sys/kdebug.h>
+#endif /*KERNEL_PRIVATE*/
+
+#include <mach/mach_error.h>
+#include <mach/mach_types.h>
+#include <mach/message.h>
+#include <mach/mach_syscalls.h>
+#include <mach/clock_types.h>
+#include <mach/mach_time.h>
+
+#include <libkern/OSTypes.h>
+
+
+int s_usec_10_bins[10];
+int s_usec_100_bins[10];
+int s_msec_1_bins[10];
+int s_msec_10_bins[5];
+int s_too_slow;
+int s_max_latency;
+int s_min_latency = 0;
+long long s_total_latency = 0;
+int s_total_samples = 0;
+long s_thresh_hold;
+int s_exceeded_threshold = 0;
+
+
+#define N_HIGH_RES_BINS 500
+int use_high_res_bins = false;
+
+struct i_latencies {
+ int i_usec_10_bins[10];
+ int i_usec_100_bins[10];
+ int i_msec_1_bins[10];
+ int i_msec_10_bins[5];
+ int i_too_slow;
+ int i_max_latency;
+ int i_min_latency;
+ int i_total_samples;
+ int i_total;
+ int i_exceeded_threshold;
+ uint64_t i_total_latency;
+};
+
+struct i_latencies *i_lat;
+boolean_t i_latency_per_cpu = FALSE;
+
+int i_high_res_bins[N_HIGH_RES_BINS];
+
+long i_thresh_hold;
+
+int watch_priority = 97;
+
+long start_time;
+long curr_time;
+long refresh_time;
+
+
+char *kernelpath = NULL;
+
+typedef struct {
+ void *k_sym_addr; /* kernel symbol address from nm */
+ u_int k_sym_len; /* length of kernel symbol string */
+ char *k_sym_name; /* kernel symbol string from nm */
+} kern_sym_t;
+
+kern_sym_t *kern_sym_tbl; /* pointer to the nm table */
+int kern_sym_count; /* number of entries in nm table */
+
+
+
+#define MAX_ENTRIES 4096
+struct ct {
+ int type;
+ char name[32];
+} codes_tab[MAX_ENTRIES];
+
+char *code_file = NULL;
+int num_of_codes = 0;
+
+
+double divisor;
+sig_atomic_t gotSIGWINCH = 0;
+int trace_enabled = 0;
+int need_new_map = 1;
+int set_remove_flag = 1; /* By default, remove trace buffer */
+
+int RAW_flag = 0;
+int RAW_fd = 0;
+
+uint64_t first_now = 0;
+uint64_t last_now = 0;
+int first_read = 1;
+
+
+#define SAMPLE_TIME_USECS 50000
+#define SAMPLE_SIZE 300000
+#define MAX_LOG_COUNT 30 /* limits the number of entries dumped in log_decrementer */
+
+kbufinfo_t bufinfo = {0, 0, 0};
+
+FILE *log_fp = NULL;
+
+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;
+char *my_buffer;
+int num_entries;
+
+kd_buf **last_decrementer_kd; /* last DECR_TRAP per cpu */
+
+
+#define NUMPARMS 23
+
+typedef struct event *event_t;
+
+struct event {
+ event_t ev_next;
+
+ uintptr_t ev_thread;
+ uint32_t ev_type;
+ uint64_t ev_timestamp;
+};
+
+
+typedef struct lookup *lookup_t;
+
+struct lookup {
+ lookup_t lk_next;
+
+ uintptr_t lk_thread;
+ uintptr_t lk_dvp;
+ long *lk_pathptr;
+ long lk_pathname[NUMPARMS + 1];
+};
+
+
+typedef struct threadmap *threadmap_t;
+
+struct threadmap {
+ threadmap_t tm_next;
+
+ uintptr_t tm_thread;
+ uintptr_t tm_pthread;
+ char tm_command[MAXCOMLEN + 1];
+ char tm_orig_command[MAXCOMLEN + 1];
+};
+
+
+typedef struct threadrun *threadrun_t;
+
+struct threadrun {
+ threadrun_t tr_next;
+
+ uintptr_t tr_thread;
+ kd_buf *tr_entry;
+ uint64_t tr_timestamp;
+};
+
+
+typedef struct thread_entry *thread_entry_t;
+
+struct thread_entry {
+ thread_entry_t te_next;
+
+ uintptr_t te_thread;
+};
+
+
+#define HASH_SIZE 1024
+#define HASH_MASK 1023
+
+event_t event_hash[HASH_SIZE];
+lookup_t lookup_hash[HASH_SIZE];
+threadmap_t threadmap_hash[HASH_SIZE];
+threadrun_t threadrun_hash[HASH_SIZE];
+
+event_t event_freelist;
+lookup_t lookup_freelist;
+threadrun_t threadrun_freelist;
+threadmap_t threadmap_freelist;
+threadmap_t threadmap_temp;
+
+thread_entry_t thread_entry_freelist;
+thread_entry_t thread_delete_list;
+thread_entry_t thread_reset_list;
+thread_entry_t thread_event_list;
+thread_entry_t thread_lookup_list;
+thread_entry_t thread_run_list;
+
+
+#ifndef RAW_VERSION1
+typedef struct {
+ int version_no;
+ int thread_count;
+ uint64_t TOD_secs;
+ uint32_t TOD_usecs;
+} RAW_header;
+
+#define RAW_VERSION0 0x55aa0000
+#define RAW_VERSION1 0x55aa0101
+#endif
+
+
+#define USER_MODE 0
+#define KERNEL_MODE 1
+
+
+#define TRACE_DATA_NEWTHREAD 0x07000004
+#define TRACE_STRING_NEWTHREAD 0x07010004
+#define TRACE_STRING_EXEC 0x07010008
+
+#define INTERRUPT 0x01050000
+#define DECR_TRAP 0x01090000
+#define DECR_SET 0x01090004
+#define MACH_vmfault 0x01300008
+#define MACH_sched 0x01400000
+#define MACH_stkhandoff 0x01400008
+#define MACH_makerunnable 0x01400018
+#define MACH_idle 0x01400024
+#define VFS_LOOKUP 0x03010090
+#define IES_action 0x050b0018
+#define IES_filter 0x050b001c
+#define TES_action 0x050c0010
+#define CQ_action 0x050d0018
+#define CPUPM_CPUSTER_RUNCOUNT 0x05310144
+
+#define BSC_exit 0x040C0004
+#define BSC_thread_terminate 0x040c05a4
+
+#define DBG_FUNC_MASK ~(DBG_FUNC_START | DBG_FUNC_END)
+
+#define CPU_NUMBER(kp) kdbg_get_cpu(kp)
+
+#define EMPTYSTRING ""
+
+
+const char *fault_name[] = {
+ "",
+ "ZeroFill",
+ "PageIn",
+ "COW",
+ "CacheHit",
+ "NoZeroFill",
+ "Guard",
+ "PageInFile",
+ "PageInAnon"
+};
+
+const char *sched_reasons[] = {
+ "N",
+ "P",
+ "Q",
+ "?",
+ "u",
+ "U",
+ "?",
+ "?",
+ "H",
+ "?",
+ "?",
+ "?",
+ "?",
+ "?",
+ "?",
+ "?",
+ "Y"
+};
+
+#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(*x)))
+#define MAX_REASON ARRAYSIZE(sched_reasons)
+
+static double handle_decrementer(kd_buf *, int);
+static kd_buf *log_decrementer(kd_buf *kd_beg, kd_buf *kd_end, kd_buf *end_of_sample, double i_latency);
+static void read_command_map(void);
+static void enter_syscall(FILE *fp, kd_buf *kd, int thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, int print_info);
+static void exit_syscall(FILE *fp, kd_buf *kd, int thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, int print_info);
+static void print_entry(FILE *fp, kd_buf *kd, int thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, kd_buf *kd_note);
+static void log_info(uint64_t now, uint64_t idelta, uint64_t start_bias, kd_buf *kd, kd_buf *kd_note);
+static char *find_code(int);
+static void pc_to_string(char *pcstring, uintptr_t pc, int max_len, int mode);
+static void getdivisor(void);
+static int sample_sc(void);
+static void init_code_file(void);
+static void do_kernel_nm(void);
+static void open_logfile(const char*);
+static int binary_search(kern_sym_t *list, int low, int high, uintptr_t addr);
+
+static void create_map_entry(uintptr_t, char *);
+static void check_for_thread_update(uintptr_t thread, int debugid_base, kd_buf *kbufp, char **command);
+static void log_scheduler(kd_buf *kd_start, kd_buf *kd_stop, kd_buf *end_of_sample, double s_latency, uintptr_t thread);
+static int check_for_scheduler_latency(int type, uintptr_t *thread, uint64_t now, kd_buf *kd, kd_buf **kd_start, double *latency);
+static void open_rawfile(const char *path);
+
+static void screen_update(FILE *);
+
+static void set_enable(int);
+static void set_remove(void);
+
+static int
+quit(char *s)
+{
+ if (!RAW_flag) {
+ if (trace_enabled) {
+ set_enable(0);
+ }
+ /*
+ * This flag is turned off when calling
+ * quit() due to a set_remove() failure.
+ */
+ if (set_remove_flag) {
+ set_remove();
+ }
+ }
+ printf("latency: ");
+ if (s) {
+ printf("%s", s);
+ }
+ exit(1);
+}
+
+void
+set_enable(int val)
+{
+ int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDENABLE, val };
+ size_t needed;
+
+ if (sysctl(mib, ARRAYSIZE(mib), NULL, &needed, NULL, 0) < 0) {
+ quit("trace facility failure, KERN_KDENABLE\n");
+ }
+}
+
+void
+set_numbufs(int nbufs)
+{
+ int mib1[] = { CTL_KERN, KERN_KDEBUG, KERN_KDSETBUF, nbufs };
+ int mib2[] = { CTL_KERN, KERN_KDEBUG, KERN_KDSETUP };
+ size_t needed;
+
+ if (sysctl(mib1, ARRAYSIZE(mib1), NULL, &needed, NULL, 0) < 0) {
+ quit("trace facility failure, KERN_KDSETBUF\n");
+ }
+ if (sysctl(mib2, ARRAYSIZE(mib2), NULL, &needed, NULL, 0) < 0) {
+ quit("trace facility failure, KERN_KDSETUP\n");
+ }
+}
+
+void
+set_pidexclude(int pid, int on_off)
+{
+ int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDPIDEX };
+ size_t needed = sizeof(kd_regtype);
+
+ kd_regtype kr = {
+ .type = KDBG_TYPENONE,
+ .value1 = pid,
+ .value2 = on_off
+ };
+
+ sysctl(mib, ARRAYSIZE(mib), &kr, &needed, NULL, 0);
+}
+
+void
+get_bufinfo(kbufinfo_t *val)
+{
+ int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDGETBUF };
+ size_t needed = sizeof (*val);
+
+ if (sysctl(mib, ARRAYSIZE(mib), val, &needed, 0, 0) < 0) {
+ quit("trace facility failure, KERN_KDGETBUF\n");
+ }
+}
+
+void
+set_remove(void)
+{
+ int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDREMOVE };
+ size_t needed;
+
+ errno = 0;
+
+ if (sysctl(mib, ARRAYSIZE(mib), NULL, &needed, NULL, 0) < 0) {
+ set_remove_flag = 0;
+ if (errno == EBUSY) {
+ quit("the trace facility is currently in use...\n fs_usage, sc_usage, and latency use this feature.\n\n");
+ } else {
+ quit("trace facility failure, KERN_KDREMOVE\n");
+ }
+ }
+}
+
+
+void
+write_high_res_latencies(void)
+{
+ int i;
+ FILE *f;
+
+ if (use_high_res_bins) {
+ if ((f = fopen("latencies.csv","w"))) {
+ for (i = 0; i < N_HIGH_RES_BINS; i++) {
+ fprintf(f, "%d,%d\n", i, i_high_res_bins[i]);
+ }
+ fclose(f);
+ }
+ }
+}
+
+void
+sigintr(int signo __attribute__((unused)))
+{
+ write_high_res_latencies();
+
+ set_enable(0);
+ set_pidexclude(getpid(), 0);
+ screen_update(log_fp);
+ endwin();
+ set_remove();
+
+ exit(1);
+}
+
+/* exit under normal conditions -- signal handler */
+void
+leave(int signo __attribute__((unused)))
+{
+ write_high_res_latencies();
+
+ set_enable(0);
+ set_pidexclude(getpid(), 0);
+ endwin();
+ set_remove();
+
+ exit(1);
+}
+
+void
+sigwinch(int signo __attribute__((unused)))
+{
+ gotSIGWINCH = 1;
+}
+
+void
+print_total(FILE *fp, char *s, int total)
+{
+ int cpu;
+ int clen;
+ int itotal;
+ struct i_latencies *il;
+ char tbuf[512];
+
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+ itotal += il->i_total;
+ }
+ clen = sprintf(tbuf, "%s %10d %9d", s, total, itotal);
+
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ if (i_latency_per_cpu == TRUE) {
+ clen += sprintf(&tbuf[clen], " %9d", il->i_total);
+ }
+
+ il->i_total = 0;
+ }
+ sprintf(&tbuf[clen], "\n");
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+}
+
+
+
+void
+screen_update(FILE *fp)
+{
+ int i;
+ int cpu;
+ int clen;
+ int itotal, stotal;
+ int elapsed_secs;
+ int elapsed_mins;
+ int elapsed_hours;
+ int min_lat, max_lat;
+ uint64_t tot_lat;
+ unsigned int average_s_latency;
+ unsigned int average_i_latency;
+ struct i_latencies *il;
+ char tbuf[1024];
+
+ if (fp == NULL) {
+ erase();
+ move(0, 0);
+ } else {
+ fprintf(fp,"\n\n===================================================================================================\n");
+ }
+ /*
+ * Display the current time.
+ * "ctime" always returns a string that looks like this:
+ *
+ * Sun Sep 16 01:03:52 1973
+ * 012345678901234567890123
+ * 1 2
+ *
+ * We want indices 11 thru 18 (length 8).
+ */
+ if (RAW_flag) {
+ curr_time = sample_TOD_secs;
+ elapsed_secs = ((last_now - first_now) / divisor) / 1000000;
+ } else {
+ elapsed_secs = curr_time - start_time;
+ }
+
+ elapsed_hours = elapsed_secs / 3600;
+ elapsed_secs -= elapsed_hours * 3600;
+ elapsed_mins = elapsed_secs / 60;
+ elapsed_secs -= elapsed_mins * 60;
+
+ sprintf(tbuf, "%-19.19s %2ld:%02ld:%02ld\n", &(ctime(&curr_time)[0]),
+ (long)elapsed_hours, (long)elapsed_mins, (long)elapsed_secs);
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+ sprintf(tbuf, " SCHEDULER INTERRUPTS\n");
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+ if (i_latency_per_cpu == TRUE) {
+ clen = sprintf(tbuf, " Total");
+
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ if (cpu <= 9) {
+ clen += sprintf(&tbuf[clen], " CPU %d", cpu);
+ } else {
+ clen += sprintf(&tbuf[clen], " CPU %d", cpu);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+ clen = sprintf(tbuf, "\n-------------------------------------------------------");
+
+ for (cpu = 1; cpu < num_i_latency_cpus; cpu++) {
+ clen += sprintf(&tbuf[clen], "----------");
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+ } else {
+ sprintf(tbuf, "---------------------------------------------");
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+ }
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+ itotal += il->i_total_samples;
+ }
+ clen = sprintf(tbuf, "\ntotal_samples %10d %9d", s_total_samples, itotal);
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_total_samples);
+ }
+ }
+ sprintf(&tbuf[clen], "\n");
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+
+ for (stotal = 0, i = 0; i < 10; i++) {
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ itotal += il->i_usec_10_bins[i];
+ il->i_total += il->i_usec_10_bins[i];
+ }
+ clen = sprintf(tbuf, "\ndelays < %3d usecs %10d %9d", (i + 1) * 10, s_usec_10_bins[i], itotal);
+
+ stotal += s_usec_10_bins[i];
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_usec_10_bins[i]);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+ }
+ print_total(fp, "\ntotal < 100 usecs", stotal);
+
+ for (stotal = 0, i = 1; i < 10; i++) {
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ itotal += il->i_usec_100_bins[i];
+ il->i_total += il->i_usec_100_bins[i];
+ }
+ if (i < 9) {
+ clen = sprintf(tbuf, "\ndelays < %3d usecs %10d %9d", (i + 1) * 100, s_usec_100_bins[i], itotal);
+ } else {
+ clen = sprintf(tbuf, "\ndelays < 1 msec %10d %9d", s_usec_100_bins[i], itotal);
+ }
+
+ stotal += s_usec_100_bins[i];
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_usec_100_bins[i]);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+ }
+ print_total(fp, "\ntotal < 1 msec ", stotal);
+
+
+ for (stotal = 0, i = 1; i < 10; i++) {
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ itotal += il->i_msec_1_bins[i];
+ il->i_total += il->i_msec_1_bins[i];
+ }
+ clen = sprintf(tbuf, "\ndelays < %3d msecs %10d %9d", (i + 1), s_msec_1_bins[i], itotal);
+
+ stotal += s_msec_1_bins[i];
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_msec_1_bins[i]);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+ }
+ print_total(fp, "\ntotal < 10 msecs", stotal);
+
+ for (stotal = 0, i = 1; i < 5; i++) {
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ itotal += il->i_msec_10_bins[i];
+ il->i_total += il->i_msec_10_bins[i];
+ }
+ clen = sprintf(tbuf, "\ndelays < %3d msecs %10d %9d", (i + 1)*10, s_msec_10_bins[i], itotal);
+
+ stotal += s_msec_10_bins[i];
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_msec_10_bins[i]);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+ }
+ print_total(fp, "\ntotal < 50 msecs", stotal);
+
+
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+ itotal += il->i_too_slow;
+ }
+ clen = sprintf(tbuf, "\ndelays > 50 msecs %10d %9d", s_too_slow, itotal);
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_too_slow);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ if (cpu == 0 || (il->i_min_latency < min_lat)) {
+ min_lat = il->i_min_latency;
+ }
+ }
+ clen = sprintf(tbuf, "\n\nminimum latency(usecs) %7d %9d", s_min_latency, min_lat);
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_min_latency);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ if (cpu == 0 || (il->i_max_latency > max_lat)) {
+ max_lat = il->i_max_latency;
+ }
+ }
+ clen = sprintf(tbuf, "\nmaximum latency(usecs) %7d %9d", s_max_latency, max_lat);
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_max_latency);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+ if (s_total_samples) {
+ average_s_latency = (unsigned int)(s_total_latency/s_total_samples);
+ } else {
+ average_s_latency = 0;
+ }
+
+ for (itotal = 0, tot_lat = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ itotal += il->i_total_samples;
+ tot_lat += il->i_total_latency;
+ }
+ if (itotal) {
+ average_i_latency = (unsigned)(tot_lat/itotal);
+ } else {
+ average_i_latency = 0;
+ }
+
+ clen = sprintf(tbuf, "\naverage latency(usecs) %7d %9d", average_s_latency, average_i_latency);
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ if (il->i_total_samples) {
+ average_i_latency = (unsigned int)(il->i_total_latency/il->i_total_samples);
+ } else {
+ average_i_latency = 0;
+ }
+
+ clen += sprintf(&tbuf[clen], " %9d", average_i_latency);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ itotal += il->i_exceeded_threshold;
+ }
+ clen = sprintf(tbuf, "\nexceeded threshold %7d %9d", s_exceeded_threshold, itotal);
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_exceeded_threshold);
+ }
+ }
+ sprintf(&tbuf[clen], "\n");
+
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+ if (fp == NULL) {
+ refresh();
+ } else {
+ fflush(fp);
+ }
+}
+
+int
+exit_usage(void)
+{
+ fprintf(stderr, "Usage: latency [-p priority] [-h] [-m] [-st threshold] [-it threshold]\n");
+ fprintf(stderr, " [-c codefile] [-l logfile] [-R rawfile] [-n kernel]\n\n");
+
+ fprintf(stderr, " -p specify scheduling priority to watch... default is realtime\n");
+ fprintf(stderr, " -h Display high resolution interrupt latencies and write them to latencies.csv (truncate existing file) upon exit.\n");
+ fprintf(stderr, " -st set scheduler latency threshold in microseconds... if latency exceeds this, then log trace\n");
+ fprintf(stderr, " -m specify per-CPU interrupt latency reporting\n");
+ fprintf(stderr, " -it set interrupt latency threshold in microseconds... if latency exceeds this, then log trace\n");
+ fprintf(stderr, " -c specify name of codes file... default is /usr/share/misc/trace.codes\n");
+ fprintf(stderr, " -l specify name of file to log trace entries to when the specified threshold is exceeded\n");
+ fprintf(stderr, " -R specify name of raw trace file to process\n");
+ fprintf(stderr, " -n specify kernel... default is /mach_kernel\n");
+
+ fprintf(stderr, "\nlatency must be run as root\n\n");
+
+ exit(1);
+}
+
+
+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);
+ }
+ while (argc > 1) {
+
+ if (strcmp(argv[1], "-R") == 0) {
+ argc--;
+ argv++;
+
+ if (argc > 1) {
+ open_rawfile(argv[1]);
+ } else {
+ exit_usage();
+ }
+
+ RAW_flag = 1;
+
+ } else if (strcmp(argv[1], "-p") == 0) {
+ argc--;
+ argv++;
+
+ if (argc > 1) {
+ watch_priority = atoi(argv[1]);
+ } else {
+ exit_usage();
+ }
+ } else if (strcmp(argv[1], "-st") == 0) {
+ argc--;
+ argv++;
+
+ if (argc > 1) {
+ s_thresh_hold = atoi(argv[1]);
+ } else {
+ exit_usage();
+ }
+ } else if (strcmp(argv[1], "-it") == 0) {
+ argc--;
+ argv++;
+
+ if (argc > 1) {
+ i_thresh_hold = atoi(argv[1]);
+ } else {
+ exit_usage();
+ }
+ } else if (strcmp(argv[1], "-c") == 0) {
+ argc--;
+ argv++;
+
+ if (argc > 1) {
+ code_file = argv[1];
+ } else {
+ exit_usage();
+ }
+ } else if (strcmp(argv[1], "-l") == 0) {
+ argc--;
+ argv++;
+
+ if (argc > 1) {
+ open_logfile(argv[1]);
+ } else {
+ exit_usage();
+ }
+ } else if (strcmp(argv[1], "-n") == 0) {
+ argc--;
+ argv++;
+
+ if (argc > 1) {
+ kernelpath = argv[1];
+ } else {
+ exit_usage();
+ }
+ } else if (strcmp(argv[1], "-h") == 0) {
+ use_high_res_bins = TRUE;
+
+ } else if (strcmp(argv[1], "-m") == 0) {
+ i_latency_per_cpu = TRUE;
+
+ } else {
+ exit_usage();
+ }
+
+ argc--;
+ argv++;
+ }
+ if (!RAW_flag) {
+ if (geteuid() != 0) {
+ printf("'latency' must be run as root...\n");
+ exit(1);
+ }
+ }
+ if (kernelpath == NULL) {
+ kernelpath = "/mach_kernel";
+ }
+
+ if (code_file == NULL) {
+ code_file = "/usr/share/misc/trace.codes";
+ }
+
+ do_kernel_nm();
+
+ getdivisor();
+
+ init_code_file();
+
+ if (!RAW_flag) {
+ if (initscr() == NULL) {
+ printf("Unrecognized TERM type, try vt100\n");
+ exit(1);
+ }
+ clear();
+ refresh();
+
+ signal(SIGWINCH, sigwinch);
+ signal(SIGINT, sigintr);
+ signal(SIGQUIT, leave);
+ signal(SIGTERM, leave);
+ signal(SIGHUP, leave);
+
+ /*
+ * grab the number of cpus and scale the buffer size
+ */
+ int mib[] = { CTL_HW, HW_NCPU };
+ size_t len = sizeof(num_cpus);
+
+ sysctl(mib, ARRAYSIZE(mib), &num_cpus, &len, NULL, 0);
+
+ set_remove();
+ set_numbufs(SAMPLE_SIZE * num_cpus);
+
+ get_bufinfo(&bufinfo);
+
+ set_enable(0);
+
+ set_pidexclude(getpid(), 1);
+ set_enable(1);
+
+ num_entries = bufinfo.nkdbufs;
+ } else {
+ num_entries = 50000;
+ 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");
+ }
+
+ if ((last_decrementer_kd = (kd_buf **)malloc(num_cpus * sizeof(kd_buf *))) == NULL) {
+ quit("can't allocate memory for decrementer tracing info\n");
+ }
+
+ if (i_latency_per_cpu == FALSE) {
+ num_i_latency_cpus = 1;
+ } else {
+ num_i_latency_cpus = num_cpus;
+ }
+
+ if ((i_lat = (struct i_latencies *)malloc(num_i_latency_cpus * sizeof(struct i_latencies))) == NULL) {
+ quit("can't allocate memory for interrupt latency info\n");
+ }
+
+ bzero((char *)i_lat, num_i_latency_cpus * sizeof(struct i_latencies));
+
+ if (RAW_flag) {
+ while (sample_sc()) {
+ continue;
+ }
+
+ if (log_fp) {
+ screen_update(log_fp);
+ }
+
+ screen_update(stdout);
+
+ } else {
+ uint64_t adelay;
+ double fdelay;
+ double nanosecs_to_sleep;
+
+ nanosecs_to_sleep = (double)(SAMPLE_TIME_USECS * 1000);
+ fdelay = nanosecs_to_sleep * (divisor /1000);
+ adelay = (uint64_t)fdelay;
+
+ trace_enabled = 1;
+
+ start_time = time(NULL);
+ refresh_time = start_time;
+
+ for (;;) {
+ curr_time = time(NULL);
+
+ if (curr_time >= refresh_time) {
+ screen_update(NULL);
+ refresh_time = curr_time + 1;
+ }
+ mach_wait_until(mach_absolute_time() + adelay);
+
+ sample_sc();
+
+ if (gotSIGWINCH) {
+ /*
+ * No need to check for initscr error return.
+ * We won't get here if it fails on the first call.
+ */
+ endwin();
+ clear();
+ refresh();
+
+ gotSIGWINCH = 0;
+ }
+ }
+ }
+}
+
+
+
+void
+read_command_map(void)
+{
+ kd_threadmap *mapptr = 0;
+ int total_threads = 0;
+ size_t size;
+ off_t offset;
+ int i;
+ RAW_header header = {0};
+
+ if (RAW_flag) {
+ if (read(RAW_fd, &header, sizeof(RAW_header)) != sizeof(RAW_header)) {
+ perror("read failed");
+ exit(2);
+ }
+ if (header.version_no != RAW_VERSION1) {
+ header.version_no = RAW_VERSION0;
+ header.TOD_secs = time(NULL);
+ header.TOD_usecs = 0;
+
+ lseek(RAW_fd, (off_t)0, SEEK_SET);
+
+ if (read(RAW_fd, &header.thread_count, sizeof(int)) != sizeof(int)) {
+ perror("read failed");
+ exit(2);
+ }
+ }
+ total_threads = header.thread_count;
+
+ sample_TOD_secs = header.TOD_secs;
+ sample_TOD_usecs = header.TOD_usecs;
+
+ if (total_threads == 0 && header.version_no != RAW_VERSION0) {
+ offset = lseek(RAW_fd, (off_t)0, SEEK_CUR);
+ offset = (offset + (4095)) & ~4095;
+
+ lseek(RAW_fd, offset, SEEK_SET);
+ }
+ } else {
+ total_threads = bufinfo.nkdthreads;
+ }
+
+ size = total_threads * sizeof(kd_threadmap);
+
+ if (size == 0 || ((mapptr = (kd_threadmap *) malloc(size)) == 0)) {
+ return;
+ }
+ bzero (mapptr, size);
+
+ /*
+ * Now read the threadmap
+ */
+ if (RAW_flag) {
+ if (read(RAW_fd, mapptr, size) != size) {
+ printf("Can't read the thread map -- this is not fatal\n");
+ }
+ if (header.version_no != RAW_VERSION0) {
+ offset = lseek(RAW_fd, (off_t)0, SEEK_CUR);
+ offset = (offset + (4095)) & ~4095;
+
+ lseek(RAW_fd, offset, SEEK_SET);
+ }
+ } else {
+ int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDTHRMAP};
+ if (sysctl(mib, ARRAYSIZE(mib), mapptr, &size, NULL, 0) < 0) {
+ /*
+ * This is not fatal -- just means I cant map command strings
+ */
+ printf("Can't read the thread map -- this is not fatal\n");
+
+ total_threads = 0;
+ }
+ }
+ for (i = 0; i < total_threads; i++) {
+ create_map_entry(mapptr[i].thread, &mapptr[i].command[0]);
+ }
+ free(mapptr);
+}
+
+void
+create_map_entry(uintptr_t thread, char *command)
+{
+ threadmap_t tme;
+
+ if ((tme = threadmap_freelist)) {
+ threadmap_freelist = tme->tm_next;
+ } else {
+ tme = (threadmap_t)malloc(sizeof(struct threadmap));
+ }
+
+ tme->tm_thread = thread;
+
+ (void)strncpy (tme->tm_command, command, MAXCOMLEN);
+ tme->tm_command[MAXCOMLEN] = '\0';
+ tme->tm_orig_command[0] = '\0';
+
+ int hashid = thread & HASH_MASK;
+
+ tme->tm_next = threadmap_hash[hashid];
+ threadmap_hash[hashid] = tme;
+}
+
+void
+delete_thread_entry(uintptr_t thread)
+{
+ threadmap_t tme;
+
+ int hashid = thread & HASH_MASK;
+
+ if ((tme = threadmap_hash[hashid])) {
+ if (tme->tm_thread == thread) {
+ threadmap_hash[hashid] = tme->tm_next;
+ } else {
+ threadmap_t tme_prev = tme;
+
+ for (tme = tme->tm_next; tme; tme = tme->tm_next) {
+ if (tme->tm_thread == thread) {
+ tme_prev->tm_next = tme->tm_next;
+ break;
+ }
+ tme_prev = tme;
+ }
+ }
+ if (tme) {
+ tme->tm_next = threadmap_freelist;
+ threadmap_freelist = tme;
+ }
+ }
+}
+
+void
+find_and_insert_tmp_map_entry(uintptr_t pthread, char *command)
+{
+ threadmap_t tme;
+
+ if ((tme = threadmap_temp)) {
+ if (tme->tm_pthread == pthread) {
+ threadmap_temp = tme->tm_next;
+ } else {
+ threadmap_t tme_prev = tme;
+
+ for (tme = tme->tm_next; tme; tme = tme->tm_next) {
+ if (tme->tm_pthread == pthread) {
+ tme_prev->tm_next = tme->tm_next;
+ break;
+ }
+ tme_prev = tme;
+ }
+ }
+ if (tme) {
+ (void)strncpy (tme->tm_command, command, MAXCOMLEN);
+ tme->tm_command[MAXCOMLEN] = '\0';
+ tme->tm_orig_command[0] = '\0';
+
+ int hashid = tme->tm_thread & HASH_MASK;
+ tme->tm_next = threadmap_hash[hashid];
+ threadmap_hash[hashid] = tme;
+ }
+ }
+}
+
+void
+create_tmp_map_entry(uintptr_t thread, uintptr_t pthread)
+{
+ threadmap_t tme;
+
+ if ((tme = threadmap_freelist)) {
+ threadmap_freelist = tme->tm_next;
+ } else {
+ tme = malloc(sizeof(struct threadmap));
+ }
+
+ tme->tm_thread = thread;
+ tme->tm_pthread = pthread;
+ tme->tm_command[0] = '\0';
+ tme->tm_orig_command[0] = '\0';
+
+ tme->tm_next = threadmap_temp;
+ threadmap_temp = tme;
+}
+
+threadmap_t
+find_thread_entry(uintptr_t thread)
+{
+ threadmap_t tme;
+
+ int hashid = thread & HASH_MASK;
+
+ for (tme = threadmap_hash[hashid]; tme; tme = tme->tm_next) {
+ if (tme->tm_thread == thread) {
+ return tme;
+ }
+ }
+ return 0;
+}
+
+void
+find_thread_name(uintptr_t thread, char **command)
+{
+ threadmap_t tme;
+
+ if ((tme = find_thread_entry(thread))) {
+ *command = tme->tm_command;
+ } else {
+ *command = EMPTYSTRING;
+ }
+}
+
+void
+add_thread_entry_to_list(thread_entry_t *list, uintptr_t thread)
+{
+ thread_entry_t te;
+
+ if ((te = thread_entry_freelist)) {
+ thread_entry_freelist = te->te_next;
+ } else {
+ te = (thread_entry_t)malloc(sizeof(struct thread_entry));
+ }
+
+ te->te_thread = thread;
+ te->te_next = *list;
+ *list = te;
+}
+
+void
+exec_thread_entry(uintptr_t thread, char *command)
+{
+ threadmap_t tme;
+
+ if ((tme = find_thread_entry(thread))) {
+ if (tme->tm_orig_command[0] == '\0') {
+ (void)strncpy (tme->tm_orig_command, tme->tm_command, MAXCOMLEN);
+ tme->tm_orig_command[MAXCOMLEN] = '\0';
+ }
+ (void)strncpy (tme->tm_command, command, MAXCOMLEN);
+ tme->tm_command[MAXCOMLEN] = '\0';
+
+ add_thread_entry_to_list(&thread_reset_list, thread);
+ } else {
+ create_map_entry(thread, command);
+ }
+}
+
+void
+record_thread_entry_for_gc(uintptr_t thread)
+{
+ add_thread_entry_to_list(&thread_delete_list, thread);
+}
+
+void
+gc_thread_entries(void)
+{
+ thread_entry_t te;
+ thread_entry_t te_next;
+ int count = 0;
+
+ for (te = thread_delete_list; te; te = te_next) {
+ delete_thread_entry(te->te_thread);
+
+ te_next = te->te_next;
+ te->te_next = thread_entry_freelist;
+ thread_entry_freelist = te;
+
+ count++;
+ }
+ thread_delete_list = 0;
+}
+
+void
+gc_reset_entries(void)
+{
+ thread_entry_t te;
+ thread_entry_t te_next;
+ int count = 0;
+
+ for (te = thread_reset_list; te; te = te_next) {
+ te_next = te->te_next;
+ te->te_next = thread_entry_freelist;
+ thread_entry_freelist = te;
+
+ count++;
+ }
+ thread_reset_list = 0;
+}
+
+void
+reset_thread_names(void)
+{
+ thread_entry_t te;
+ thread_entry_t te_next;
+ int count = 0;
+
+ for (te = thread_reset_list; te; te = te_next) {
+ threadmap_t tme;
+
+ if ((tme = find_thread_entry(te->te_thread))) {
+ if (tme->tm_orig_command[0]) {
+ (void)strncpy (tme->tm_command, tme->tm_orig_command, MAXCOMLEN);
+ tme->tm_command[MAXCOMLEN] = '\0';
+ tme->tm_orig_command[0] = '\0';
+ }
+ }
+ te_next = te->te_next;
+ te->te_next = thread_entry_freelist;
+ thread_entry_freelist = te;
+
+ count++;
+ }
+ thread_reset_list = 0;
+}
+
+void
+delete_all_thread_entries(void)
+{
+ threadmap_t tme = 0;
+ threadmap_t tme_next = 0;
+ int i;
+
+ for (i = 0; i < HASH_SIZE; i++) {
+ for (tme = threadmap_hash[i]; tme; tme = tme_next) {
+ tme_next = tme->tm_next;
+ tme->tm_next = threadmap_freelist;
+ threadmap_freelist = tme;
+ }
+ threadmap_hash[i] = 0;
+ }
+}
+
+
+
+
+static void
+insert_run_event(uintptr_t thread, kd_buf *kd, uint64_t now)
+{
+ threadrun_t trp;
+
+ int hashid = thread & HASH_MASK;
+
+ for (trp = threadrun_hash[hashid]; trp; trp = trp->tr_next) {
+ if (trp->tr_thread == thread) {
+ break;
+ }
+ }
+ if (trp == NULL) {
+ if ((trp = threadrun_freelist)) {
+ threadrun_freelist = trp->tr_next;
+ } else {
+ trp = (threadrun_t)malloc(sizeof(struct threadrun));
+ }
+
+ trp->tr_thread = thread;
+
+ trp->tr_next = threadrun_hash[hashid];
+ threadrun_hash[hashid] = trp;
+
+ add_thread_entry_to_list(&thread_run_list, thread);
+ }
+ trp->tr_entry = kd;
+ trp->tr_timestamp = now;
+}
+
+static threadrun_t
+find_run_event(uintptr_t thread)
+{
+ threadrun_t trp;
+ int hashid = thread & HASH_MASK;
+
+ for (trp = threadrun_hash[hashid]; trp; trp = trp->tr_next) {
+ if (trp->tr_thread == thread) {
+ return trp;
+ }
+ }
+ return 0;
+}
+
+static void
+delete_run_event(uintptr_t thread)
+{
+ threadrun_t trp = 0;
+ threadrun_t trp_prev;
+
+ int hashid = thread & HASH_MASK;
+
+ if ((trp = threadrun_hash[hashid])) {
+ if (trp->tr_thread == thread) {
+ threadrun_hash[hashid] = trp->tr_next;
+ } else {
+ trp_prev = trp;
+
+ for (trp = trp->tr_next; trp; trp = trp->tr_next) {
+ if (trp->tr_thread == thread) {
+ trp_prev->tr_next = trp->tr_next;
+ break;
+ }
+ trp_prev = trp;
+ }
+ }
+ if (trp) {
+ trp->tr_next = threadrun_freelist;
+ threadrun_freelist = trp;
+ }
+ }
+}
+
+static void
+gc_run_events(void) {
+ thread_entry_t te;
+ thread_entry_t te_next;
+ threadrun_t trp;
+ threadrun_t trp_next;
+ int count = 0;
+
+ for (te = thread_run_list; te; te = te_next) {
+ int hashid = te->te_thread & HASH_MASK;
+
+ for (trp = threadrun_hash[hashid]; trp; trp = trp_next) {
+ trp_next = trp->tr_next;
+ trp->tr_next = threadrun_freelist;
+ threadrun_freelist = trp;
+ count++;
+ }
+ threadrun_hash[hashid] = 0;
+
+ te_next = te->te_next;
+ te->te_next = thread_entry_freelist;
+ thread_entry_freelist = te;
+ }
+ thread_run_list = 0;
+}
+
+
+
+static void
+insert_start_event(uintptr_t thread, int type, uint64_t now)
+{
+ event_t evp;
+
+ int hashid = thread & HASH_MASK;
+
+ for (evp = event_hash[hashid]; evp; evp = evp->ev_next) {
+ if (evp->ev_thread == thread && evp->ev_type == type) {
+ break;
+ }
+ }
+ if (evp == NULL) {
+ if ((evp = event_freelist)) {
+ event_freelist = evp->ev_next;
+ } else {
+ evp = (event_t)malloc(sizeof(struct event));
+ }
+
+ evp->ev_thread = thread;
+ evp->ev_type = type;
+
+ evp->ev_next = event_hash[hashid];
+ event_hash[hashid] = evp;
+
+ add_thread_entry_to_list(&thread_event_list, thread);
+ }
+ evp->ev_timestamp = now;
+}
+
+
+static uint64_t
+consume_start_event(uintptr_t thread, int type, uint64_t now)
+{
+ event_t evp;
+ event_t evp_prev;
+ uint64_t elapsed = 0;
+
+ int hashid = thread & HASH_MASK;
+
+ if ((evp = event_hash[hashid])) {
+ if (evp->ev_thread == thread && evp->ev_type == type) {
+ event_hash[hashid] = evp->ev_next;
+ } else {
+ evp_prev = evp;
+
+ for (evp = evp->ev_next; evp; evp = evp->ev_next) {
+ if (evp->ev_thread == thread && evp->ev_type == type) {
+ evp_prev->ev_next = evp->ev_next;
+ break;
+ }
+ evp_prev = evp;
+ }
+ }
+ if (evp) {
+ elapsed = now - evp->ev_timestamp;
+
+ if (now < evp->ev_timestamp) {
+ printf("consume: now = %qd, timestamp = %qd\n", now, evp->ev_timestamp);
+ elapsed = 0;
+ }
+ evp->ev_next = event_freelist;
+ event_freelist = evp;
+ }
+ }
+ return elapsed;
+}
+
+static void
+gc_start_events(void)
+{
+ thread_entry_t te;
+ thread_entry_t te_next;
+ event_t evp;
+ event_t evp_next;
+ int count = 0;
+ int hashid;
+
+ for (te = thread_event_list; te; te = te_next) {
+
+ hashid = te->te_thread & HASH_MASK;
+
+ for (evp = event_hash[hashid]; evp; evp = evp_next) {
+ evp_next = evp->ev_next;
+ evp->ev_next = event_freelist;
+ event_freelist = evp;
+ count++;
+ }
+ event_hash[hashid] = 0;
+
+ te_next = te->te_next;
+ te->te_next = thread_entry_freelist;
+ thread_entry_freelist = te;
+ }
+ thread_event_list = 0;
+}
+
+int
+thread_in_user_mode(uintptr_t thread, char *command)
+{
+ event_t evp;
+
+ if (strcmp(command, "kernel_task") == 0) {
+ return 0;
+ }
+
+ int hashid = thread & HASH_MASK;
+
+ for (evp = event_hash[hashid]; evp; evp = evp->ev_next) {
+ if (evp->ev_thread == thread) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+
+static lookup_t
+handle_lookup_event(uintptr_t thread, int debugid, kd_buf *kdp)
+{
+ lookup_t lkp;
+ boolean_t first_record = FALSE;
+
+ int hashid = thread & HASH_MASK;
+
+ if (debugid & DBG_FUNC_START) {
+ first_record = TRUE;
+ }
+
+ for (lkp = lookup_hash[hashid]; lkp; lkp = lkp->lk_next) {
+ if (lkp->lk_thread == thread) {
+ break;
+ }
+ }
+ if (lkp == NULL) {
+ if (first_record == FALSE) {
+ return 0;
+ }
+
+ if ((lkp = lookup_freelist)) {
+ lookup_freelist = lkp->lk_next;
+ } else {
+ lkp = (lookup_t)malloc(sizeof(struct lookup));
+ }
+
+ lkp->lk_thread = thread;
+
+ lkp->lk_next = lookup_hash[hashid];
+ lookup_hash[hashid] = lkp;
+
+ add_thread_entry_to_list(&thread_lookup_list, thread);
+ }
+
+ if (first_record == TRUE) {
+ lkp->lk_pathptr = lkp->lk_pathname;
+ lkp->lk_dvp = kdp->arg1;
+ } else {
+ if (lkp->lk_pathptr > &lkp->lk_pathname[NUMPARMS-4]) {
+ return lkp;
+ }
+ *lkp->lk_pathptr++ = kdp->arg1;
+ }
+ *lkp->lk_pathptr++ = kdp->arg2;
+ *lkp->lk_pathptr++ = kdp->arg3;
+ *lkp->lk_pathptr++ = kdp->arg4;
+ *lkp->lk_pathptr = 0;
+
+ if (debugid & DBG_FUNC_END) {
+ return lkp;
+ }
+
+ return 0;
+}
+
+static void
+delete_lookup_event(uintptr_t thread, lookup_t lkp_to_delete)
+{
+ lookup_t lkp;
+ lookup_t lkp_prev;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ if ((lkp = lookup_hash[hashid])) {
+ if (lkp == lkp_to_delete) {
+ lookup_hash[hashid] = lkp->lk_next;
+ } else {
+ lkp_prev = lkp;
+
+ for (lkp = lkp->lk_next; lkp; lkp = lkp->lk_next) {
+ if (lkp == lkp_to_delete) {
+ lkp_prev->lk_next = lkp->lk_next;
+ break;
+ }
+ lkp_prev = lkp;
+ }
+ }
+ if (lkp) {
+ lkp->lk_next = lookup_freelist;
+ lookup_freelist = lkp;
+ }
+ }
+}
+
+static void
+gc_lookup_events(void) {
+ thread_entry_t te;
+ thread_entry_t te_next;
+ lookup_t lkp;
+ lookup_t lkp_next;
+ int count = 0;
+ int hashid;
+
+ for (te = thread_lookup_list; te; te = te_next) {
+ hashid = te->te_thread & HASH_MASK;
+
+ for (lkp = lookup_hash[hashid]; lkp; lkp = lkp_next) {
+ lkp_next = lkp->lk_next;
+ lkp->lk_next = lookup_freelist;
+ lookup_freelist = lkp;
+ count++;
+ }
+ lookup_hash[hashid] = 0;
+
+ te_next = te->te_next;
+ te->te_next = thread_entry_freelist;
+ thread_entry_freelist = te;
+ }
+ thread_lookup_list = 0;
+}
+
+int
+sample_sc(void)
+{
+ kd_buf *kd, *end_of_sample;
+ int keep_going = 1;
+ int count, i;
+
+ if (!RAW_flag) {
+ /*
+ * Get kernel buffer information
+ */
+ get_bufinfo(&bufinfo);
+ }
+ if (need_new_map) {
+ delete_all_thread_entries();
+ read_command_map();
+ need_new_map = 0;
+ }
+ if (RAW_flag) {
+ uint32_t bytes_read;
+
+ bytes_read = read(RAW_fd, my_buffer, num_entries * sizeof(kd_buf));
+
+ if (bytes_read == -1) {
+ perror("read failed");
+ exit(2);
+ }
+ count = bytes_read / sizeof(kd_buf);
+
+ if (count != num_entries) {
+ keep_going = 0;
+ }
+
+ if (first_read) {
+ kd = (kd_buf *)my_buffer;
+ first_now = kd->timestamp & KDBG_TIMESTAMP_MASK;
+ first_read = 0;
+ }
+
+ } else {
+ int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDREADTR };
+ size_t needed = bufinfo.nkdbufs * sizeof(kd_buf);
+
+ if (sysctl(mib, ARRAYSIZE(mib), my_buffer, &needed, NULL, 0) < 0) {
+ quit("trace facility failure, KERN_KDREADTR\n");
+ }
+
+ count = needed;
+ sample_generation++;
+
+ if (bufinfo.flags & KDBG_WRAPPED) {
+ need_new_map = 1;
+
+ if (log_fp) {
+ fprintf(log_fp, "\n\n%-19.19s sample = %d <<<<<<< trace buffer wrapped >>>>>>>\n\n",
+ &(ctime(&curr_time)[0]), sample_generation);
+ }
+ set_enable(0);
+ set_enable(1);
+ }
+ }
+ end_of_sample = &((kd_buf *)my_buffer)[count];
+
+ /*
+ * Always reinitialize the DECR_TRAP array
+ */
+ for (i = 0; i < num_cpus; i++) {
+ last_decrementer_kd[i] = (kd_buf *)my_buffer;
+ }
+
+ for (kd = (kd_buf *)my_buffer; kd < end_of_sample; kd++) {
+ kd_buf *kd_start;
+ uintptr_t thread = kd->arg5;
+ int type = kd->debugid & DBG_FUNC_MASK;
+
+ (void)check_for_thread_update(thread, type, kd, NULL);
+
+ uint64_t now = kd->timestamp & KDBG_TIMESTAMP_MASK;
+ last_now = now;
+
+ if (type == DECR_TRAP) {
+ int cpunum = CPU_NUMBER(kd);
+ double i_latency = handle_decrementer(kd, cpunum);
+
+ if (log_fp) {
+ if (i_thresh_hold && (int)i_latency > i_thresh_hold) {
+ kd_start = last_decrementer_kd[cpunum];
+
+ log_decrementer(kd_start, kd, end_of_sample, i_latency);
+ }
+ last_decrementer_kd[cpunum] = kd;
+ }
+ } else {
+ double s_latency;
+ if (check_for_scheduler_latency(type, &thread, now, kd, &kd_start, &s_latency)) {
+ log_scheduler(kd_start, kd, end_of_sample, s_latency, thread);
+ }
+ }
+ }
+ if (log_fp) {
+ fflush(log_fp);
+ }
+
+ gc_thread_entries();
+ gc_reset_entries();
+ gc_run_events();
+
+ return keep_going;
+}
+
+
+
+void
+enter_syscall(FILE *fp, kd_buf *kd, int thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, int print_info)
+{
+ char *p;
+ double timestamp;
+ double delta;
+ char pcstring[128];
+
+ int cpunum = CPU_NUMBER(kd);
+
+ if (print_info && fp) {
+ timestamp = (double)(now - start_bias) / divisor;
+ delta = (double)idelta / divisor;
+
+ if ((p = find_code(type))) {
+ if (type == INTERRUPT) {
+ int mode;
+
+ if (kd->arg3) {
+ mode = USER_MODE;
+ } else {
+ mode = KERNEL_MODE;
+ }
+
+ pc_to_string(&pcstring[0], kd->arg2, 58, mode);
+
+ 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 %2d %s\n",
+ timestamp, delta, p, thread, cpunum, command);
+ } else {
+ 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 %-16lx %-16lx %-16lx %-16lx %8x %2d %s\n",
+ timestamp, delta, type, kd->arg1, kd->arg2, kd->arg3, kd->arg4,
+ thread, cpunum, command);
+ }
+ }
+ if (type != BSC_thread_terminate && type != BSC_exit) {
+ insert_start_event(thread, type, now);
+ }
+}
+
+
+void
+exit_syscall(FILE *fp, kd_buf *kd, int thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, int print_info)
+{
+ char *p;
+ uint64_t user_addr;
+ double timestamp;
+ double delta;
+ double elapsed_timestamp;
+
+ elapsed_timestamp = (double)consume_start_event(thread, type, now) / divisor;
+
+ if (print_info && fp) {
+ int cpunum = CPU_NUMBER(kd);
+
+ timestamp = (double)(now - start_bias) / divisor;
+ delta = (double)idelta / divisor;
+
+ fprintf(fp, "%9.1f %8.1f(%.1f) \t", timestamp, delta, elapsed_timestamp);
+
+ if ((p = find_code(type))) {
+ if (type == INTERRUPT) {
+ 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 %2d %s\n",
+ p, fault_name[kd->arg4], user_addr,
+ thread, cpunum, command);
+ } else {
+ fprintf(fp, "%-28.28s %-16lx %-16lx %8x %2d %s\n",
+ p, kd->arg1, kd->arg2,
+ thread, cpunum, command);
+ }
+ } else {
+ fprintf(fp, "%-8x %-16lx %-16lx %8x %2d %s\n",
+ type, kd->arg1, kd->arg2,
+ thread, cpunum, command);
+ }
+ }
+}
+
+
+void
+print_entry(FILE *fp, kd_buf *kd, int thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, kd_buf *kd_note)
+{
+ char *p;
+
+ if (!fp) {
+ return;
+ }
+
+ int cpunum = CPU_NUMBER(kd);
+
+ double timestamp = (double)(now - start_bias) / divisor;
+ double delta = (double)idelta / divisor;
+
+ if ((p = find_code(type))) {
+ if (kd == kd_note) {
+ fprintf(fp, "%9.1f %8.1f\t**\t", timestamp, delta);
+ } else {
+ fprintf(fp, "%9.1f %8.1f\t\t", timestamp, delta);
+ }
+ 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 %-16lx %-16lx %-16lx %-16lx %8x %2d %s\n",
+ timestamp, delta, type, kd->arg1, kd->arg2, kd->arg3, kd->arg4,
+ thread, cpunum, command);
+ }
+}
+
+
+void
+check_for_thread_update(uintptr_t thread, int debugid_base, kd_buf *kbufp, char **command)
+{
+ if (debugid_base == TRACE_DATA_NEWTHREAD) {
+ /*
+ * Save the create thread data
+ */
+ create_tmp_map_entry(kbufp->arg1, thread);
+ } else if (debugid_base == TRACE_STRING_NEWTHREAD) {
+ /*
+ * process new map entry
+ */
+ find_and_insert_tmp_map_entry(thread, (char *)&kbufp->arg1);
+ } else if (debugid_base == TRACE_STRING_EXEC) {
+ exec_thread_entry(thread, (char *)&kbufp->arg1);
+ } else {
+ if (debugid_base == BSC_exit || debugid_base == BSC_thread_terminate) {
+ record_thread_entry_for_gc(thread);
+ }
+ if (command) {
+ find_thread_name(thread, command);
+ }
+ }
+}
+
+
+void
+log_info(uint64_t now, uint64_t idelta, uint64_t start_bias, kd_buf *kd, kd_buf *kd_note)
+{
+ lookup_t lkp;
+ int mode;
+ int reason;
+ char *p;
+ char *command;
+ char *command1;
+ char command_buf[32];
+ char sched_info[64];
+ char pcstring[128];
+ const char *sched_reason;
+ double i_latency;
+ double timestamp;
+ double delta;
+ char joe[32];
+
+ int thread = kd->arg5;
+ int cpunum = CPU_NUMBER(kd);
+ int debugid = kd->debugid;
+ int type = kd->debugid & DBG_FUNC_MASK;
+
+ (void)check_for_thread_update(thread, type, kd, &command);
+
+ if ((type >> 24) == DBG_TRACE) {
+ if (((type >> 16) & 0xff) != DBG_TRACE_INFO) {
+ return;
+ }
+ }
+ timestamp = (double)(now - start_bias) / divisor;
+ delta = (double)idelta / divisor;
+
+ switch (type) {
+
+ case CQ_action:
+ pc_to_string(&pcstring[0], kd->arg1, 84, KERNEL_MODE);
+
+ 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, 83, KERNEL_MODE);
+
+ 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, 83, KERNEL_MODE);
+
+ 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, 83, KERNEL_MODE);
+
+ fprintf(log_fp, "%9.1f %8.1f\t\tIES_filter @ %-83.83s %8x %2d %s\n",
+ timestamp, delta, &pcstring[0], thread, cpunum, command);
+ break;
+
+ case DECR_TRAP:
+ if ((int)kd->arg1 >= 0) {
+ i_latency = 0;
+ } else {
+ i_latency = (((double)(-1 - kd->arg1)) / divisor);
+ }
+
+ if (i_thresh_hold && (int)i_latency > i_thresh_hold) {
+ p = "*";
+ } else {
+ p = " ";
+ }
+
+ if (kd->arg3) {
+ mode = USER_MODE;
+ } else {
+ mode = KERNEL_MODE;
+ }
+
+ pc_to_string(&pcstring[0], kd->arg2, 84, mode);
+
+ 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 %2d %s\n",
+ timestamp, delta, (double)kd->arg1/divisor, "DECR_SET", thread, cpunum, command);
+ break;
+
+ case MACH_sched:
+ case MACH_stkhandoff:
+
+ find_thread_name(kd->arg2, &command1);
+
+ if (command1 == EMPTYSTRING) {
+ command1 = command_buf;
+ sprintf(command1, "%-8lx", kd->arg2);
+ }
+ if (thread_in_user_mode(kd->arg2, command1)) {
+ p = "U";
+ } else {
+ p = "K";
+ }
+
+ reason = kd->arg1;
+
+ if (reason > MAX_REASON) {
+ sched_reason = "?";
+ } else {
+ sched_reason = sched_reasons[reason];
+ }
+
+ if (sched_reason[0] == '?') {
+ sprintf(joe, "%x", reason);
+ sched_reason = joe;
+ }
+ 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 %2d\n",
+ timestamp, delta, "MACH_SCHED", sched_reason, sched_info, thread, cpunum);
+ break;
+
+ case VFS_LOOKUP:
+ if ((lkp = handle_lookup_event(thread, debugid, kd))) {
+ /*
+ * print the tail end of the pathname
+ */
+ p = (char *)lkp->lk_pathname;
+ int clen = strlen(p);
+
+ if (clen > 45) {
+ clen -= 45;
+ } else {
+ clen = 0;
+ }
+
+ 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);
+
+ delete_lookup_event(thread, lkp);
+ }
+ break;
+
+ default:
+ if (debugid & DBG_FUNC_START) {
+ enter_syscall(log_fp, kd, thread, type, command, now, idelta, start_bias, 1);
+ } else if (debugid & DBG_FUNC_END) {
+ exit_syscall(log_fp, kd, thread, type, command, now, idelta, start_bias, 1);
+ } else {
+ print_entry(log_fp, kd, thread, type, command, now, idelta, start_bias, kd_note);
+ }
+ break;
+ }
+}
+
+
+
+void
+log_range(kd_buf *kd_buffer, kd_buf *kd_start, kd_buf *kd_stop, kd_buf *kd_note, char *buf1)
+{
+ uint64_t last_timestamp = 0;
+ uint64_t delta = 0;
+ uint64_t start_bias = 0;
+ uint64_t now;
+ kd_buf *kd;
+ int clen;
+ char buf2[128];
+
+ clen = strlen(buf1);
+ memset(buf2, '-', clen);
+ buf2[clen] = 0;
+ 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");
+
+ reset_thread_names();
+
+ last_timestamp = kd_start->timestamp & KDBG_TIMESTAMP_MASK;
+ start_bias = last_timestamp;
+
+ for (kd = kd_buffer; kd <= kd_stop; kd++) {
+ now = kd->timestamp & KDBG_TIMESTAMP_MASK;
+
+ if (kd >= kd_start) {
+ delta = now - last_timestamp;
+
+ log_info(now, delta, start_bias, kd, kd_note);
+
+ last_timestamp = now;
+ } else {
+ int debugid = kd->debugid;
+ int thread = kd->arg5;
+ int type = kd->debugid & DBG_FUNC_MASK;
+
+ if ((type >> 24) == DBG_TRACE) {
+ if (((type >> 16) & 0xff) != DBG_TRACE_INFO) {
+ continue;
+ }
+ }
+ if (type == BSC_thread_terminate || type == BSC_exit) {
+ continue;
+ }
+
+ if (debugid & DBG_FUNC_START) {
+ insert_start_event(thread, type, now);
+ } else if (debugid & DBG_FUNC_END) {
+ (void)consume_start_event(thread, type, now);
+ }
+ }
+ }
+ gc_start_events();
+ gc_lookup_events();
+}
+
+
+kd_buf *
+log_decrementer(kd_buf *kd_beg, kd_buf *kd_end, kd_buf *end_of_sample, double i_latency)
+{
+ kd_buf *kd_start, *kd_stop;
+ int kd_count; /* Limit the boundary of kd_start */
+ uint64_t now;
+ double sample_timestamp;
+ char buf1[128];
+
+ int thread = kd_beg->arg5;
+ int cpunum = CPU_NUMBER(kd_end);
+
+ for (kd_count = 0, kd_start = kd_beg - 1; (kd_start >= (kd_buf *)my_buffer); kd_start--, kd_count++) {
+ if (kd_count == MAX_LOG_COUNT) {
+ break;
+ }
+
+ if (CPU_NUMBER(kd_start) != cpunum) {
+ continue;
+ }
+
+ if ((kd_start->debugid & DBG_FUNC_MASK) == DECR_TRAP) {
+ break;
+ }
+
+ if (kd_start->arg5 != thread) {
+ break;
+ }
+ }
+ if (kd_start < (kd_buf *)my_buffer) {
+ kd_start = (kd_buf *)my_buffer;
+ }
+
+ thread = kd_end->arg5;
+
+ for (kd_stop = kd_end + 1; kd_stop < end_of_sample; kd_stop++) {
+ if (CPU_NUMBER(kd_stop) != cpunum) {
+ continue;
+ }
+
+ if ((kd_stop->debugid & DBG_FUNC_MASK) == INTERRUPT) {
+ break;
+ }
+
+ if (kd_stop->arg5 != thread) {
+ break;
+ }
+ }
+ if (kd_stop >= end_of_sample) {
+ kd_stop = end_of_sample - 1;
+ }
+
+ if (RAW_flag) {
+ time_t TOD_secs;
+ uint64_t TOD_usecs;
+
+ now = kd_start->timestamp & KDBG_TIMESTAMP_MASK;
+ sample_timestamp = (double)(now - first_now) / divisor;
+
+ TOD_usecs = (uint64_t)sample_timestamp;
+ TOD_secs = sample_TOD_secs + ((sample_TOD_usecs + TOD_usecs) / 1000000);
+
+ sprintf(buf1, "%-19.19s interrupt latency = %.1fus [timestamp %.1f]", ctime(&TOD_secs), i_latency, sample_timestamp);
+ } else {
+ sprintf(buf1, "%-19.19s interrupt latency = %.1fus [sample %d]", &(ctime(&curr_time)[0]), i_latency, sample_generation);
+ }
+
+ log_range((kd_buf *)my_buffer, kd_start, kd_stop, 0, buf1);
+
+ return kd_stop;
+}
+
+
+void
+log_scheduler(kd_buf *kd_beg, kd_buf *kd_end, kd_buf *end_of_sample, double s_latency, uintptr_t thread)
+{
+ kd_buf *kd_start, *kd_stop;
+ uint64_t now;
+ int count;
+ int cpunum;
+ uint64_t cmask = 0;
+ double sample_timestamp;
+ char buf1[128];
+
+ 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) {
+ kd_start = (kd_buf *)my_buffer;
+ }
+
+ for (kd_stop = kd_end + 1; kd_stop < end_of_sample; kd_stop++) {
+ if (kd_stop->arg5 == thread) {
+ break;
+ }
+ }
+ if (kd_stop >= end_of_sample) {
+ kd_stop = end_of_sample - 1;
+ }
+
+ if (RAW_flag) {
+ time_t TOD_secs;
+ uint64_t TOD_usecs;
+
+ now = kd_start->timestamp & KDBG_TIMESTAMP_MASK;
+ sample_timestamp = (double)(now - first_now) / divisor;
+
+ TOD_usecs = (uint64_t)sample_timestamp;
+ TOD_secs = sample_TOD_secs + ((sample_TOD_usecs + TOD_usecs) / 1000000);
+
+ sprintf(buf1, "%-19.19s priority = %d, scheduling latency = %.1fus [timestamp %.1f]", ctime(&TOD_secs), watch_priority, s_latency, sample_timestamp);
+ } else {
+ sprintf(buf1, "%-19.19s priority = %d, scheduling latency = %.1fus [sample %d]", &(ctime(&curr_time)[0]), watch_priority, s_latency, sample_generation);
+ }
+
+ log_range((kd_buf *)my_buffer, kd_start, kd_stop, kd_beg, buf1);
+}
+
+
+
+int
+check_for_scheduler_latency(int type, uintptr_t *thread, uint64_t now, kd_buf *kd, kd_buf **kd_start, double *latency)
+{
+ int found_latency = 0;
+
+ if (type == MACH_makerunnable) {
+ if (watch_priority == kd->arg2) {
+ insert_run_event(kd->arg1, kd, now);
+ }
+ } else if (type == MACH_sched || type == MACH_stkhandoff) {
+ threadrun_t trp;
+
+ if (type == MACH_sched || type == MACH_stkhandoff) {
+ *thread = kd->arg2;
+ }
+
+ if ((trp = find_run_event(*thread))) {
+ double d_s_latency = (((double)(now - trp->tr_timestamp)) / divisor);
+ int s_latency = (int)d_s_latency;
+
+ if (s_latency) {
+ if (s_latency < 100) {
+ s_usec_10_bins[s_latency/10]++;
+ }
+ if (s_latency < 1000) {
+ s_usec_100_bins[s_latency/100]++;
+ } else if (s_latency < 10000) {
+ s_msec_1_bins[s_latency/1000]++;
+ } else if (s_latency < 50000) {
+ s_msec_10_bins[s_latency/10000]++;
+ } else {
+ s_too_slow++;
+ }
+
+ if (s_latency > s_max_latency) {
+ s_max_latency = s_latency;
+ }
+ if (s_latency < s_min_latency || s_total_samples == 0) {
+ s_min_latency = s_latency;
+ }
+ s_total_latency += s_latency;
+ s_total_samples++;
+
+ if (s_thresh_hold && s_latency > s_thresh_hold) {
+ s_exceeded_threshold++;
+
+ if (log_fp) {
+ *kd_start = trp->tr_entry;
+ *latency = d_s_latency;
+ found_latency = 1;
+ }
+ }
+ }
+ delete_run_event(*thread);
+ }
+ }
+ return found_latency;
+}
+
+
+double
+handle_decrementer(kd_buf *kd, int cpunum)
+{
+ struct i_latencies *il;
+ double latency;
+ long elapsed_usecs;
+
+ if (i_latency_per_cpu == FALSE) {
+ cpunum = 0;
+ }
+
+ il = &i_lat[cpunum];
+
+ if ((long)(kd->arg1) >= 0) {
+ latency = 1;
+ } else {
+ latency = (((double)(-1 - kd->arg1)) / divisor);
+ }
+ elapsed_usecs = (long)latency;
+
+ if (elapsed_usecs < 100) {
+ il->i_usec_10_bins[elapsed_usecs/10]++;
+ }
+
+ if (elapsed_usecs < 1000) {
+ il->i_usec_100_bins[elapsed_usecs/100]++;
+ } else if (elapsed_usecs < 10000) {
+ il->i_msec_1_bins[elapsed_usecs/1000]++;
+ } else if (elapsed_usecs < 50000) {
+ il->i_msec_10_bins[elapsed_usecs/10000]++;
+ } else {
+ il->i_too_slow++;
+ }
+
+ if (use_high_res_bins && elapsed_usecs < N_HIGH_RES_BINS) {
+ i_high_res_bins[elapsed_usecs]++;
+ }
+ if (i_thresh_hold && elapsed_usecs > i_thresh_hold) {
+ il->i_exceeded_threshold++;
+ }
+ if (elapsed_usecs > il->i_max_latency) {
+ il->i_max_latency = elapsed_usecs;
+ }
+ if (elapsed_usecs < il->i_min_latency || il->i_total_samples == 0) {
+ il->i_min_latency = elapsed_usecs;
+ }
+ il->i_total_latency += elapsed_usecs;
+ il->i_total_samples++;
+
+ return latency;
+}
+
+
+
+char *
+find_code(int type)
+{
+ int i;
+ for (i = 0; i < num_of_codes; i++) {
+ if (codes_tab[i].type == type) {
+ return codes_tab[i].name;
+ }
+ }
+ return NULL;
+}
+
+
+void
+init_code_file(void)
+{
+ FILE *fp;
+ int i;
+
+ if ((fp = fopen(code_file, "r")) == NULL) {
+ if (log_fp) {
+ fprintf(log_fp, "open of %s failed\n", code_file);
+ }
+ return;
+ }
+ for (i = 0; i < MAX_ENTRIES; i++) {
+ int code;
+ char name[128];
+ int n = fscanf(fp, "%x%127s\n", &code, name);
+
+ if (n == 1 && i == 0) {
+ /*
+ * old code file format, just skip
+ */
+ continue;
+ }
+ if (n != 2) {
+ break;
+ }
+
+ strncpy(codes_tab[i].name, name, 32);
+ codes_tab[i].type = code;
+ }
+ num_of_codes = i;
+
+ fclose(fp);
+}
+
+
+void
+do_kernel_nm(void)
+{
+ int i, len;
+ FILE *fp = NULL;
+ char tmp_nm_file[128];
+ char tmpstr[1024];
+ char inchr;
+
+ bzero(tmp_nm_file, 128);
+ bzero(tmpstr, 1024);
+
+ /*
+ * Build the temporary nm file path
+ */
+ strcpy(tmp_nm_file,"/tmp/knm.out.XXXXXX");
+
+ if (!mktemp(tmp_nm_file)) {
+ fprintf(stderr, "Error in mktemp call\n");
+ return;
+ }
+
+ /*
+ * Build the nm command and create a tmp file with the output
+ */
+ sprintf (tmpstr, "/usr/bin/nm -f -n -s __TEXT __text %s > %s",
+ kernelpath, tmp_nm_file);
+ system(tmpstr);
+
+ /*
+ * Parse the output from the nm command
+ */
+ if ((fp = fopen(tmp_nm_file, "r")) == NULL) {
+ /* Hmmm, let's not treat this as fatal */
+ fprintf(stderr, "Failed to open nm symbol file [%s]\n", tmp_nm_file);
+ return;
+ }
+ /*
+ * Count the number of symbols in the nm symbol table
+ */
+ kern_sym_count = 0;
+
+ while ((inchr = getc(fp)) != -1) {
+ if (inchr == '\n') {
+ kern_sym_count++;
+ }
+ }
+ rewind(fp);
+
+ /*
+ * Malloc the space for symbol table
+ */
+ if (kern_sym_count > 0) {
+ kern_sym_tbl = malloc(kern_sym_count * sizeof(kern_sym_t));
+
+ if (!kern_sym_tbl) {
+ /*
+ * Hmmm, lets not treat this as fatal
+ */
+ fprintf(stderr, "Can't allocate memory for kernel symbol table\n");
+ } else {
+ bzero(kern_sym_tbl, kern_sym_count * sizeof(kern_sym_t));
+ }
+ } else {
+ /*
+ * Hmmm, lets not treat this as fatal
+ */
+ fprintf(stderr, "No kernel symbol table \n");
+ }
+ for (i = 0; i < kern_sym_count; i++) {
+ bzero(tmpstr, 1024);
+
+ if (fscanf(fp, "%p %c %s", &kern_sym_tbl[i].k_sym_addr, &inchr, tmpstr) != 3) {
+ break;
+ } else {
+ len = strlen(tmpstr);
+ kern_sym_tbl[i].k_sym_name = malloc(len + 1);
+
+ if (kern_sym_tbl[i].k_sym_name == NULL) {
+ fprintf(stderr, "Can't allocate memory for symbol name [%s]\n", tmpstr);
+ kern_sym_tbl[i].k_sym_name = NULL;
+ len = 0;
+ } else {
+ strcpy(kern_sym_tbl[i].k_sym_name, tmpstr);
+ }
+
+ kern_sym_tbl[i].k_sym_len = len;
+ }
+ }
+ if (i != kern_sym_count) {
+ /*
+ * Hmmm, didn't build up entire table from nm
+ * scrap the entire thing
+ */
+ free(kern_sym_tbl);
+ kern_sym_tbl = NULL;
+ kern_sym_count = 0;
+ }
+ fclose(fp);
+
+ /*
+ * Remove the temporary nm file
+ */
+ unlink(tmp_nm_file);
+#if 0
+ /*
+ * Dump the kernel symbol table
+ */
+ for (i = 0; i < kern_sym_count; i++) {
+ if (kern_sym_tbl[i].k_sym_name) {
+ printf ("[%d] %-16p %s\n", i,
+ kern_sym_tbl[i].k_sym_addr, kern_sym_tbl[i].k_sym_name);
+ } else {
+ printf ("[%d] %-16p %s\n", i,
+ kern_sym_tbl[i].k_sym_addr, "No symbol name");
+ }
+ }
+#endif
+}
+
+void
+pc_to_string(char *pcstring, uintptr_t pc, int max_len, int mode)
+{
+ int ret;
+ int len;
+
+ if (mode == USER_MODE) {
+ sprintf(pcstring, "%-16lx [usermode addr]", pc);
+ return;
+ }
+ ret = binary_search(kern_sym_tbl, 0, kern_sym_count-1, pc);
+
+ if (ret == -1 || kern_sym_tbl[ret].k_sym_name == NULL) {
+ sprintf(pcstring, "%-16lx", pc);
+ return;
+ }
+ if ((len = kern_sym_tbl[ret].k_sym_len) > (max_len - 8)) {
+ len = max_len - 8;
+ }
+
+ memcpy(pcstring, kern_sym_tbl[ret].k_sym_name, len);
+
+ sprintf(&pcstring[len], "+0x%-5lx", pc - (uintptr_t)kern_sym_tbl[ret].k_sym_addr);
+}
+
+
+/*
+ * Return -1 if not found, else return index
+ */
+int
+binary_search(kern_sym_t *list, int low, int high, uintptr_t addr)
+{
+ int mid;
+
+ if (kern_sym_count == 0) {
+ return -1;
+ }
+
+ if (low > high) {
+ return -1; /* failed */
+ }
+
+ if (low + 1 == high) {
+ if ((uintptr_t)list[low].k_sym_addr <= addr && addr < (uintptr_t)list[high].k_sym_addr) {
+ /*
+ * We have a range match
+ */
+ return low;
+ }
+ if ((uintptr_t)list[high].k_sym_addr <= addr) {
+ return high;
+ }
+ /*
+ * Failed
+ */
+ return -1;
+ }
+ mid = (low + high) / 2;
+
+ if (addr < (uintptr_t)list[mid].k_sym_addr) {
+ return binary_search(list, low, mid, addr);
+ }
+
+ return binary_search(list, mid, high, addr);
+}
+
+
+void
+open_logfile(const char *path)
+{
+ log_fp = fopen(path, "a");
+
+ if (!log_fp) {
+ /*
+ * failed to open path
+ */
+ fprintf(stderr, "latency: failed to open logfile [%s]\n", path);
+ exit_usage();
+ }
+}
+
+
+void
+open_rawfile(const char *path)
+{
+ RAW_fd = open(path, O_RDONLY);
+
+ if (RAW_fd == -1) {
+ /*
+ * failed to open path
+ */
+ fprintf(stderr, "latency: failed to open RAWfile [%s]\n", path);
+ exit_usage();
+ }
+}
+
+
+void
+getdivisor(void)
+{
+ mach_timebase_info_data_t info;
+
+ (void)mach_timebase_info(&info);
+
+ divisor = ((double)info.denom / (double)info.numer) * 1000;
+}
--- /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) 1990, 1993, 1994
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#ifdef KERBEROS
+#include <sys/param.h>
+#include <sys/syslog.h>
+#include <kerberosIV/des.h>
+#include <kerberosIV/krb.h>
+
+#include <err.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define INITIAL_TICKET "krbtgt"
+#define VERIFY_SERVICE "rcmd"
+
+extern int notickets;
+extern char *krbtkfile_env;
+
+/*
+ * Attempt to log the user in using Kerberos authentication
+ *
+ * return 0 on success (will be logged in)
+ * 1 if Kerberos failed (try local password in login)
+ */
+int
+klogin(pw, instance, localhost, password)
+ struct passwd *pw;
+ char *instance, *localhost, *password;
+{
+ int kerror;
+ AUTH_DAT authdata;
+ KTEXT_ST ticket;
+ struct hostent *hp;
+ unsigned long faddr;
+ char realm[REALM_SZ], savehost[MAXHOSTNAMELEN];
+ char tkt_location[MAXPATHLEN];
+ char *krb_get_phost();
+
+ /*
+ * Root logins don't use Kerberos.
+ * If we have a realm, try getting a ticket-granting ticket
+ * and using it to authenticate. Otherwise, return
+ * failure so that we can try the normal passwd file
+ * for a password. If that's ok, log the user in
+ * without issuing any tickets.
+ */
+ if (strcmp(pw->pw_name, "root") == 0 ||
+ krb_get_lrealm(realm, 0) != KSUCCESS)
+ return (1);
+
+ /*
+ * get TGT for local realm
+ * tickets are stored in a file named TKT_ROOT plus uid
+ * except for user.root tickets.
+ */
+
+ if (strcmp(instance, "root") != 0)
+ (void)sprintf(tkt_location, "%s%d", TKT_ROOT, pw->pw_uid);
+ else {
+ (void)sprintf(tkt_location, "%s_root_%d", TKT_ROOT, pw->pw_uid);
+ krbtkfile_env = tkt_location;
+ }
+ (void)krb_set_tkt_string(tkt_location);
+
+ /*
+ * Set real as well as effective ID to 0 for the moment,
+ * to make the kerberos library do the right thing.
+ */
+ if (setuid(0) < 0) {
+ warnx("setuid");
+ return (1);
+ }
+ kerror = krb_get_pw_in_tkt(pw->pw_name, instance,
+ realm, INITIAL_TICKET, realm, DEFAULT_TKT_LIFE, password);
+ /*
+ * If we got a TGT, get a local "rcmd" ticket and check it so as to
+ * ensure that we are not talking to a bogus Kerberos server.
+ *
+ * There are 2 cases where we still allow a login:
+ * 1: the VERIFY_SERVICE doesn't exist in the KDC
+ * 2: local host has no srvtab, as (hopefully) indicated by a
+ * return value of RD_AP_UNDEC from krb_rd_req().
+ */
+ if (kerror != INTK_OK) {
+ if (kerror != INTK_BADPW && kerror != KDC_PR_UNKNOWN) {
+ syslog(LOG_ERR, "Kerberos intkt error: %s",
+ krb_err_txt[kerror]);
+ dest_tkt();
+ }
+ return (1);
+ }
+
+ if (chown(TKT_FILE, pw->pw_uid, pw->pw_gid) < 0)
+ syslog(LOG_ERR, "chown tkfile (%s): %m", TKT_FILE);
+
+ (void)strncpy(savehost, krb_get_phost(localhost), sizeof(savehost));
+ savehost[sizeof(savehost)-1] = NULL;
+
+ /*
+ * if the "VERIFY_SERVICE" doesn't exist in the KDC for this host,
+ * still allow login with tickets, but log the error condition.
+ */
+
+ kerror = krb_mk_req(&ticket, VERIFY_SERVICE, savehost, realm, 33);
+ if (kerror == KDC_PR_UNKNOWN) {
+ syslog(LOG_NOTICE,
+ "warning: TGT not verified (%s); %s.%s not registered, or srvtab is wrong?",
+ krb_err_txt[kerror], VERIFY_SERVICE, savehost);
+ notickets = 0;
+ return (0);
+ }
+
+ if (kerror != KSUCCESS) {
+ warnx("unable to use TGT: (%s)", krb_err_txt[kerror]);
+ syslog(LOG_NOTICE, "unable to use TGT: (%s)",
+ krb_err_txt[kerror]);
+ dest_tkt();
+ return (1);
+ }
+
+ if (!(hp = gethostbyname(localhost))) {
+ syslog(LOG_ERR, "couldn't get local host address");
+ dest_tkt();
+ return (1);
+ }
+
+ memmove((void *)&faddr, (void *)hp->h_addr, sizeof(faddr));
+
+ kerror = krb_rd_req(&ticket, VERIFY_SERVICE, savehost, faddr,
+ &authdata, "");
+
+ if (kerror == KSUCCESS) {
+ notickets = 0;
+ return (0);
+ }
+
+ /* undecipherable: probably didn't have a srvtab on the local host */
+ if (kerror = RD_AP_UNDEC) {
+ syslog(LOG_NOTICE, "krb_rd_req: (%s)\n", krb_err_txt[kerror]);
+ dest_tkt();
+ return (1);
+ }
+ /* failed for some other reason */
+ warnx("unable to verify %s ticket: (%s)", VERIFY_SERVICE,
+ krb_err_txt[kerror]);
+ syslog(LOG_NOTICE, "couldn't verify %s ticket: %s", VERIFY_SERVICE,
+ krb_err_txt[kerror]);
+ dest_tkt();
+ return (1);
+}
+#endif
--- /dev/null
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)login.1 8.2 (Berkeley) 5/5/94
+.\" $FreeBSD: src/usr.bin/login/login.1,v 1.33 2007/11/30 11:02:36 philip Exp $
+.\"
+.Dd September 13, 2006
+.Dt LOGIN 1
+.Os
+.Sh NAME
+.Nm login
+.Nd log into the computer
+.Sh SYNOPSIS
+.Nm
+.Op Fl pq
+.Op Fl h Ar hostname
+.Op Ar user
+.Nm
+.Fl f
+.Op Fl lpq
+.Op Fl h Ar hostname
+.Op Ar user Op Ar prog Op Ar args...
+.Sh DESCRIPTION
+The
+.Nm
+utility logs users (and pseudo-users) into the computer system.
+.Pp
+If no user is specified, or if a user is specified and authentication
+of the user fails,
+.Nm
+prompts for a user name.
+Authentication of users is configurable via
+.Xr pam 8 .
+Password authentication is the default.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl f
+When a user name is specified, this option indicates that proper
+authentication has already been done and that no password need be
+requested.
+This option may only be used by the super-user or when an already
+logged in user is logging in as themselves.
+.Pp
+With the
+.Fl f
+option, an alternate program (and any arguments) may be run instead of the
+user's default shell.
+The program and arguments follows the user name.
+.It Fl h
+Specify the host from which the connection was received.
+It is used by various daemons such as
+.Xr telnetd 8 .
+This option may only be used by the super-user.
+.It Fl l
+Tells the program executed by
+.Nm
+that this is not a login session (by convention, a login session is
+signalled to the program with a hyphen as the first character of
+.Em argv[0] ;
+this option disables that), and prevents it from chdir(2)ing to the user's home directory.
+The default is to add the hyphen (this is a login session).
+.It Fl p
+By default,
+.Nm
+discards any previous environment.
+The
+.Fl p
+option disables this behavior.
+.It Fl q
+This forces quiet logins, as if a
+.Pa .hushlogin
+is present.
+.El
+.Pp
+If the file
+.Pa /etc/nologin
+exists,
+.Nm
+dislays its contents to the user and exits.
+This is used by
+.Xr shutdown 8
+to prevent users from logging in when the system is about to go down.
+.Pp
+Immediately after logging a user in,
+.Nm
+displays the system copyright notice, the date and time the user last
+logged in, the message of the day as well as other information.
+If the file
+.Pa .hushlogin
+exists in the user's home directory, all of these messages are suppressed.
+.Fl q
+is specified, all of these messages are suppressed.
+This is to simplify logins for non-human users, such as
+.Xr uucp 1 .
+.Nm
+then records an entry in
+.Xr utmpx 5
+and the like, and executes the user's command interpreter (or the program
+specified on the command line if
+.Fl f
+is specified).
+.Pp
+The
+.Nm
+utility enters information into the environment (see
+.Xr environ 7 )
+specifying the user's home directory (HOME), command interpreter (SHELL),
+search path (PATH), terminal type (TERM) and user name (both LOGNAME and
+USER).
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Pp
+The
+.Nm
+utility will submit an audit record when login succeeds or fails.
+Failure to determine the current auditing state will
+result in an error exit from
+.Nm .
+.Sh FILES
+.Bl -tag -width /var/mail/userXXX -compact
+.It Pa /etc/motd
+message-of-the-day
+.It Pa /etc/nologin
+disallows logins
+.It Pa /var/run/utmpx
+current logins
+.It Pa /var/mail/user
+system mailboxes
+.It Pa \&.hushlogin
+makes login quieter
+.It Pa /etc/pam.d/login
+.Xr pam 8
+configuration file
+.It Pa /etc/security/audit_user
+user flags for auditing
+.It Pa /etc/security/audit_control
+global flags for auditing
+.El
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr chpass 1 ,
+.Xr newgrp 1 ,
+.Xr passwd 1 ,
+.Xr rlogin 1 ,
+.Xr getpass 3 ,
+.Xr utmpx 5 ,
+.Xr environ 7
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v6 .
--- /dev/null
+/*-
+ * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ * Portions copyright (c) 1999-2007 Apple Inc. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/login/login.c,v 1.106 2007/07/04 00:00:40 scf Exp $");
+
+/*
+ * login [ name ]
+ * login -h hostname (for telnetd, etc.)
+ * login -f name (for pre-authenticated login: datakit, xterm, etc.)
+ */
+
+#ifndef __APPLE__
+#include <sys/copyright.h>
+#endif
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#ifdef __APPLE__
+#include <util.h>
+#else
+#include <libutil.h>
+#endif
+#ifdef LOGIN_CAP
+#include <login_cap.h>
+#endif
+#include <pwd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <ttyent.h>
+#include <unistd.h>
+#ifdef __APPLE__
+#include <utmpx.h>
+#ifdef USE_PAM
+#else /* !USE_PAM */
+#ifndef _UTX_USERSIZE
+#define _UTX_USERSIZE MAXLOGNAME
+#endif
+#endif /* USE_PAM */
+#endif /* __APPLE__ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifdef USE_BSM_AUDIT
+#include <bsm/libbsm.h>
+#include <bsm/audit.h>
+#include <bsm/audit_session.h>
+#include <bsm/audit_uevents.h>
+#endif
+
+#ifdef __APPLE__
+#include <mach/mach_types.h>
+#include <mach/task.h>
+#include <mach/mach_init.h>
+#include <servers/bootstrap.h>
+
+#include <sys/file.h>
+#include <tzfile.h>
+#endif /* __APPLE__ */
+
+#ifdef USE_PAM
+#include <security/pam_appl.h>
+#include <security/openpam.h>
+#endif /* USE_PAM */
+
+#include "login.h"
+#include "pathnames.h"
+
+#ifdef USE_PAM
+static int auth_pam(int skip_auth);
+#endif /* USE_PAM */
+static void bail(int, int);
+#ifdef USE_PAM
+static int export(const char *);
+static void export_pam_environment(void);
+#endif /* USE_PAM */
+static int motd(const char *);
+static void badlogin(char *);
+static char *getloginname(void);
+#ifdef USE_PAM
+static void pam_syslog(const char *);
+static void pam_cleanup(void);
+#endif /* USE_PAM */
+static void refused(const char *, const char *, int);
+static const char *stypeof(char *);
+static void sigint(int);
+static void timedout(int);
+static void usage(void);
+
+#ifdef __APPLE__
+static void dolastlog(int);
+static void handle_sighup(int);
+
+#ifndef USE_PAM
+static void checknologin(void);
+static int rootterm(const char *);
+#endif /* !USE_PAM */
+#endif /* __APPLE__ */
+
+#define TTYGRPNAME "tty" /* group to own ttys */
+#define DEFAULT_BACKOFF 3
+#define DEFAULT_RETRIES 10
+#define DEFAULT_PROMPT "login: "
+#define DEFAULT_PASSWD_PROMPT "Password:"
+#define TERM_UNKNOWN "su"
+#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
+#define NO_SLEEP_EXIT 0
+#define SLEEP_EXIT 5
+
+/*
+ * This bounds the time given to login. Not a define so it can
+ * be patched on machines where it's too small.
+ */
+static u_int timeout = 300;
+
+/* Buffer for signal handling of timeout */
+static jmp_buf timeout_buf;
+
+struct passwd *pwd;
+static int failures;
+
+static char *envinit[1]; /* empty environment list */
+
+/*
+ * Command line flags and arguments
+ */
+static int fflag; /* -f: do not perform authentication */
+#ifdef __APPLE__
+static int lflag; /* -l: login session to the commmand that follows username */
+#endif
+static int hflag; /* -h: login from remote host */
+static char *hostname; /* hostname from command line */
+static int pflag; /* -p: preserve environment */
+
+/*
+ * User name
+ */
+static char *username; /* user name */
+static char *olduser; /* previous user name */
+
+/*
+ * Prompts
+ */
+static char default_prompt[] = DEFAULT_PROMPT;
+static const char *prompt;
+static char default_passwd_prompt[] = DEFAULT_PASSWD_PROMPT;
+static const char *passwd_prompt;
+
+static char *tty;
+
+/*
+ * PAM data
+ */
+#ifdef USE_PAM
+static pam_handle_t *pamh = NULL;
+static struct pam_conv pamc = { openpam_ttyconv, NULL };
+static int pam_err;
+static int pam_silent = PAM_SILENT;
+static int pam_cred_established;
+static int pam_session_established;
+#endif /* USE_PAM */
+
+#ifdef __APPLE__
+pid_t pid;
+
+#ifdef USE_PAM
+static struct lastlogx lastlog;
+#endif /* USE_PAM */
+
+#ifdef USE_BSM_AUDIT
+extern au_tid_addr_t tid;
+#endif /* USE_BSM_AUDIT */
+#endif /* __APPLE__ */
+
+int
+main(int argc, char *argv[])
+{
+ struct group *gr;
+ struct stat st;
+ int retries, backoff;
+ int ask, ch, cnt, quietlog = 0, rootlogin, rval;
+ uid_t uid, euid;
+ gid_t egid;
+ char *term;
+ char *p, *ttyn;
+ char tname[sizeof(_PATH_TTY) + 10];
+ char *arg0;
+ const char *tp;
+#ifdef __APPLE__
+ int prio;
+#ifdef USE_PAM
+ const char *name = "login"; /* PAM config */
+#else
+ struct utmpx utmp;
+#endif /* USE_PAM */
+ const char *shell = NULL;
+#endif /* !__APPLE__ */
+#ifdef LOGIN_CAP
+ login_cap_t *lc = NULL;
+ login_cap_t *lc_user = NULL;
+#endif /* LOGIN_CAP */
+#ifndef __APPLE__
+ pid_t pid;
+#endif
+#ifdef USE_BSM_AUDIT
+ char auditsuccess = 1;
+#endif
+
+ (void)signal(SIGQUIT, SIG_IGN);
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGHUP, SIG_IGN);
+ if (setjmp(timeout_buf)) {
+ if (failures)
+ badlogin(username);
+ (void)fprintf(stderr, "Login timed out after %d seconds\n",
+ timeout);
+ bail(NO_SLEEP_EXIT, 0);
+ }
+ (void)signal(SIGALRM, timedout);
+ (void)alarm(timeout);
+#ifdef __APPLE__
+ prio = getpriority(PRIO_PROCESS, 0);
+#endif
+ (void)setpriority(PRIO_PROCESS, 0, 0);
+
+ openlog("login", LOG_ODELAY, LOG_AUTH);
+
+ uid = getuid();
+ euid = geteuid();
+ egid = getegid();
+
+#ifdef __APPLE__
+ while ((ch = getopt(argc, argv, "1fh:lpq")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "fh:p")) != -1)
+#endif
+ switch (ch) {
+ case 'f':
+ fflag = 1;
+ break;
+ case 'h':
+ if (uid != 0)
+ errx(1, "-h option: %s", strerror(EPERM));
+ if (strlen(optarg) >= MAXHOSTNAMELEN)
+ errx(1, "-h option: %s: exceeds maximum "
+ "hostname size", optarg);
+ hflag = 1;
+ hostname = optarg;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+#ifdef __APPLE__
+ case '1':
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case 'q':
+ quietlog = 1;
+ break;
+#endif
+ case '?':
+ default:
+ if (uid == 0)
+ syslog(LOG_ERR, "invalid flag %c", ch);
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0) {
+ username = strdup(*argv);
+ if (username == NULL)
+ err(1, "strdup()");
+ ask = 0;
+#ifdef __APPLE__
+ argv++;
+#endif /* __APPLE__ */
+ } else {
+ ask = 1;
+ }
+
+#ifndef __APPLE__
+ setproctitle("-%s", getprogname());
+#endif /* !__APPLE__ */
+
+ for (cnt = getdtablesize(); cnt > 2; cnt--)
+ (void)close(cnt);
+
+ /*
+ * Get current TTY
+ */
+ ttyn = ttyname(STDIN_FILENO);
+ if (ttyn == NULL || *ttyn == '\0') {
+ (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
+ ttyn = tname;
+ }
+ if ((tty = strrchr(ttyn, '/')) != NULL)
+ ++tty;
+ else
+ tty = ttyn;
+
+#ifdef LOGIN_CAP
+ /*
+ * Get "login-retries" & "login-backoff" from default class
+ */
+ lc = login_getclass(NULL);
+ prompt = login_getcapstr(lc, "login_prompt",
+ default_prompt, default_prompt);
+ passwd_prompt = login_getcapstr(lc, "passwd_prompt",
+ default_passwd_prompt, default_passwd_prompt);
+ retries = login_getcapnum(lc, "login-retries",
+ DEFAULT_RETRIES, DEFAULT_RETRIES);
+ backoff = login_getcapnum(lc, "login-backoff",
+ DEFAULT_BACKOFF, DEFAULT_BACKOFF);
+ login_close(lc);
+ lc = NULL;
+#else /* !LOGIN_CAP */
+ prompt = default_prompt;
+ passwd_prompt = default_passwd_prompt;
+ retries = DEFAULT_RETRIES;
+ backoff = DEFAULT_BACKOFF;
+#endif /* !LOGIN_CAP */
+
+#ifdef __APPLE__
+#ifdef USE_BSM_AUDIT
+ /* Set the terminal id */
+ au_tid_t old_tid;
+ audit_set_terminal_id(&old_tid);
+ tid.at_type = AU_IPv4;
+ tid.at_addr[0] = old_tid.machine;
+ if (fstat(STDIN_FILENO, &st) < 0) {
+ fprintf(stderr, "login: Unable to stat terminal\n");
+ au_login_fail("Unable to stat terminal", 1);
+ exit(-1);
+ }
+ if (S_ISCHR(st.st_mode)) {
+ tid.at_port = st.st_rdev;
+ } else {
+ tid.at_port = 0;
+ }
+#endif /* USE_BSM_AUDIT */
+#endif /* __APPLE__ */
+
+ /*
+ * Try to authenticate the user until we succeed or time out.
+ */
+ for (cnt = 0;; ask = 1) {
+ if (ask) {
+ fflag = 0;
+ if (olduser != NULL)
+ free(olduser);
+ olduser = username;
+ username = getloginname();
+ }
+ rootlogin = 0;
+
+#ifdef __APPLE__
+ if (strlen(username) > _UTX_USERSIZE)
+ username[_UTX_USERSIZE] = '\0';
+#endif /* __APPLE__ */
+
+ /*
+ * Note if trying multiple user names; log failures for
+ * previous user name, but don't bother logging one failure
+ * for nonexistent name (mistyped username).
+ */
+ if (failures && strcmp(olduser, username) != 0) {
+ if (failures > (pwd ? 0 : 1))
+ badlogin(olduser);
+ }
+
+#ifdef __APPLE__
+#ifdef USE_PAM
+ /* get lastlog info before PAM make a new entry */
+ if (!quietlog)
+ getlastlogxbyname(username, &lastlog);
+#endif /* USE_PAM */
+#endif /* __APPLE__ */
+
+ pwd = getpwnam(username);
+
+#ifdef USE_PAM
+ /*
+ * Load the PAM policy and set some variables
+ */
+#ifdef __APPLE__
+ if (fflag && (pwd != NULL) && (pwd->pw_uid == uid)) {
+ name = "login.term";
+ }
+#endif
+ pam_err = pam_start(name, username, &pamc, &pamh);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_start()");
+#ifdef USE_BSM_AUDIT
+ au_login_fail("PAM Error", 1);
+#endif
+ bail(NO_SLEEP_EXIT, 1);
+ }
+ pam_err = pam_set_item(pamh, PAM_TTY, tty);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_set_item(PAM_TTY)");
+#ifdef USE_BSM_AUDIT
+ au_login_fail("PAM Error", 1);
+#endif
+ bail(NO_SLEEP_EXIT, 1);
+ }
+ pam_err = pam_set_item(pamh, PAM_RHOST, hostname);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_set_item(PAM_RHOST)");
+#ifdef USE_BSM_AUDIT
+ au_login_fail("PAM Error", 1);
+#endif
+ bail(NO_SLEEP_EXIT, 1);
+ }
+#endif /* USE_PAM */
+
+ if (pwd != NULL && pwd->pw_uid == 0)
+ rootlogin = 1;
+
+ /*
+ * If the -f option was specified and the caller is
+ * root or the caller isn't changing their uid, don't
+ * authenticate.
+ */
+ if (pwd != NULL && fflag &&
+ (uid == (uid_t)0 || uid == (uid_t)pwd->pw_uid)) {
+#ifdef USE_PAM
+ rval = auth_pam(fflag);
+#else
+ rval = 0;
+#endif /* USE_PAM */
+#ifdef USE_BSM_AUDIT
+ auditsuccess = 0; /* opened a terminal window only */
+#endif
+
+#ifdef __APPLE__
+#ifndef USE_PAM
+ /* If the account doesn't have a password, authenticate. */
+ } else if (pwd != NULL && pwd->pw_passwd[0] == '\0') {
+ rval = 0;
+#endif /* !USE_PAM */
+#endif /* __APPLE__ */
+ } else if( pwd ) {
+ fflag = 0;
+ (void)setpriority(PRIO_PROCESS, 0, -4);
+#ifdef USE_PAM
+ rval = auth_pam(fflag);
+#else
+ {
+ char* salt = pwd->pw_passwd;
+ char* p = getpass(passwd_prompt);
+ rval = strcmp(crypt(p, salt), salt);
+ memset(p, 0, strlen(p));
+ }
+#endif
+ (void)setpriority(PRIO_PROCESS, 0, 0);
+ } else {
+ rval = -1;
+ }
+
+#ifdef __APPLE__
+#ifndef USE_PAM
+ /*
+ * If trying to log in as root but with insecure terminal,
+ * refuse the login attempt.
+ */
+ if (pwd && rootlogin && !rootterm(tty)) {
+ refused("root login refused on this terminal", "ROOTTERM", 0);
+#ifdef USE_BSM_AUDIT
+ au_login_fail("Login refused on terminal", 0);
+#endif
+ continue;
+ }
+#endif /* !USE_PAM */
+#endif /* __APPLE__ */
+
+ if (pwd && rval == 0)
+ break;
+
+#ifdef USE_PAM
+ pam_cleanup();
+#endif /* USE_PAM */
+
+ /*
+ * We are not exiting here, but this corresponds to a failed
+ * login event, so set exitstatus to 1.
+ */
+#ifdef USE_BSM_AUDIT
+ au_login_fail("Login incorrect", 1);
+#endif
+
+ (void)printf("Login incorrect\n");
+ failures++;
+
+ pwd = NULL;
+
+ /*
+ * Allow up to 'retry' (10) attempts, but start
+ * backing off after 'backoff' (3) attempts.
+ */
+ if (++cnt > backoff) {
+ if (cnt >= retries) {
+ badlogin(username);
+ bail(SLEEP_EXIT, 1);
+ }
+ sleep((u_int)((cnt - backoff) * 5));
+ }
+ }
+
+ /* committed to login -- turn off timeout */
+ (void)alarm((u_int)0);
+ (void)signal(SIGHUP, SIG_DFL);
+
+ endpwent();
+
+#ifdef __APPLE__
+ if (!pwd) {
+ fprintf(stderr, "login: Unable to find user: %s\n", username);
+ exit(1);
+ }
+
+#ifndef USE_PAM
+ /* if user not super-user, check for disabled logins */
+ if (!rootlogin)
+ checknologin();
+#endif /* !USE_PAM */
+#endif /* APPLE */
+
+#ifdef USE_BSM_AUDIT
+ /* Audit successful login. */
+ if (auditsuccess)
+ au_login_success(fflag);
+#endif
+
+#ifdef LOGIN_CAP
+ /*
+ * Establish the login class.
+ */
+ lc = login_getpwclass(pwd);
+ lc_user = login_getuserclass(pwd);
+
+ if (!(quietlog = login_getcapbool(lc_user, "hushlogin", 0)))
+ quietlog = login_getcapbool(lc, "hushlogin", 0);
+#endif /* LOGIN_CAP */
+
+#ifndef __APPLE__
+ /*
+ * Switching needed for NFS with root access disabled.
+ *
+ * XXX: This change fails to modify the additional groups for the
+ * process, and as such, may restrict rights normally granted
+ * through those groups.
+ */
+ (void)setegid(pwd->pw_gid);
+ (void)seteuid(rootlogin ? 0 : pwd->pw_uid);
+
+ if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
+#ifdef LOGIN_CAP
+ if (login_getcapbool(lc, "requirehome", 0))
+ refused("Home directory not available", "HOMEDIR", 1);
+#endif /* LOGIN_CAP */
+ if (chdir("/") < 0)
+ refused("Cannot find root directory", "ROOTDIR", 1);
+ if (!quietlog || *pwd->pw_dir)
+ printf("No home directory.\nLogging in with home = \"/\".\n");
+ pwd->pw_dir = strdup("/");
+ if (pwd->pw_dir == NULL) {
+ syslog(LOG_NOTICE, "strdup(): %m");
+ bail(SLEEP_EXIT, 1);
+ }
+ }
+
+ (void)seteuid(euid);
+ (void)setegid(egid);
+#endif /* !__APPLE__ */
+ if (!quietlog) {
+ quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
+#ifdef USE_PAM
+ if (!quietlog)
+ pam_silent = 0;
+#endif /* USE_PAM */
+ }
+
+#ifdef __APPLE__
+ /* Nothing else left to fail -- really log in. */
+#ifndef USE_PAM
+ memset((void *)&utmp, 0, sizeof(utmp));
+ (void)gettimeofday(&utmp.ut_tv, NULL);
+ (void)strncpy(utmp.ut_user, username, sizeof(utmp.ut_user));
+ if (hostname)
+ (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
+ (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
+ utmp.ut_type = USER_PROCESS | UTMPX_AUTOFILL_MASK;
+ utmp.ut_pid = getpid();
+ pututxline(&utmp);
+#endif /* USE_PAM */
+
+ shell = "";
+#endif /* !__APPLE__ */
+#ifdef LOGIN_CAP
+ shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
+#endif /* !LOGIN_CAP */
+ if (*pwd->pw_shell == '\0')
+ pwd->pw_shell = strdup(_PATH_BSHELL);
+ if (pwd->pw_shell == NULL) {
+ syslog(LOG_NOTICE, "strdup(): %m");
+ bail(SLEEP_EXIT, 1);
+ }
+
+#if defined(__APPLE__) && TARGET_OS_EMBEDDED
+ /* on embedded, allow a shell to live in /var/debug_mount/bin/sh */
+#define _PATH_DEBUGSHELL "/var/debug_mount/bin/sh"
+ if (stat(pwd->pw_shell, &st) != 0) {
+ if (stat(_PATH_DEBUGSHELL, &st) == 0) {
+ pwd->pw_shell = strdup(_PATH_DEBUGSHELL);
+ }
+ }
+#endif
+
+ if (*shell == '\0') /* Not overridden */
+ shell = pwd->pw_shell;
+ if ((shell = strdup(shell)) == NULL) {
+ syslog(LOG_NOTICE, "strdup(): %m");
+ bail(SLEEP_EXIT, 1);
+ }
+
+#ifdef __APPLE__
+ dolastlog(quietlog);
+#endif
+
+#ifndef __APPLE__
+ /*
+ * Set device protections, depending on what terminal the
+ * user is logged in. This feature is used on Suns to give
+ * console users better privacy.
+ */
+ login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
+#endif /* !__APPLE__ */
+
+ /*
+ * Clear flags of the tty. None should be set, and when the
+ * user sets them otherwise, this can cause the chown to fail.
+ * Since it isn't clear that flags are useful on character
+ * devices, we just clear them.
+ *
+ * We don't log in the case of EOPNOTSUPP because dev might be
+ * on NFS, which doesn't support chflags.
+ *
+ * We don't log in the EROFS because that means that /dev is on
+ * a read only file system and we assume that the permissions there
+ * are sane.
+ */
+ if (ttyn != tname && chflags(ttyn, 0))
+#ifdef __APPLE__
+ if (errno != EOPNOTSUPP && errno != ENOTSUP && errno != EROFS)
+#else
+ if (errno != EOPNOTSUPP && errno != EROFS)
+#endif
+ syslog(LOG_ERR, "chflags(%s): %m", ttyn);
+ if (ttyn != tname && chown(ttyn, pwd->pw_uid,
+ (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid))
+ if (errno != EROFS)
+ syslog(LOG_ERR, "chown(%s): %m", ttyn);
+
+#ifdef __APPLE__
+ (void)chmod(ttyn, 0620);
+#endif /* __APPLE__ */
+
+#ifndef __APPLE__
+ /*
+ * Exclude cons/vt/ptys only, assume dialup otherwise
+ * TODO: Make dialup tty determination a library call
+ * for consistency (finger etc.)
+ */
+ if (hflag && isdialuptty(tty))
+ syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
+#endif /* !__APPLE__ */
+
+#ifdef LOGALL
+ /*
+ * Syslog each successful login, so we don't have to watch
+ * hundreds of wtmp or lastlogin files.
+ */
+ if (hflag)
+ syslog(LOG_INFO, "login from %s on %s as %s",
+ hostname, tty, pwd->pw_name);
+ else
+ syslog(LOG_INFO, "login on %s as %s",
+ tty, pwd->pw_name);
+#endif
+
+ /*
+ * If fflag is on, assume caller/authenticator has logged root
+ * login.
+ */
+ if (rootlogin && fflag == 0) {
+ if (hflag)
+ syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
+ username, tty, hostname);
+ else
+ syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
+ username, tty);
+ }
+
+ /*
+ * Destroy environment unless user has requested its
+ * preservation - but preserve TERM in all cases
+ */
+ term = getenv("TERM");
+ if (!pflag)
+ environ = envinit;
+ if (term != NULL)
+ setenv("TERM", term, 0);
+
+#ifndef __APPLE__
+ /*
+ * PAM modules might add supplementary groups during pam_setcred().
+ */
+ if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
+ syslog(LOG_ERR, "setusercontext() failed - exiting");
+ bail(NO_SLEEP_EXIT, 1);
+ }
+#endif /* !__APPLE__ */
+#ifdef USE_PAM
+ if (!fflag) {
+ pam_err = pam_setcred(pamh, pam_silent|PAM_ESTABLISH_CRED);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_setcred()");
+ bail(NO_SLEEP_EXIT, 1);
+ }
+ pam_cred_established = 1;
+ }
+
+ pam_err = pam_open_session(pamh, pam_silent);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_open_session()");
+ bail(NO_SLEEP_EXIT, 1);
+ }
+ pam_session_established = 1;
+#endif /* USE_PAM */
+
+#ifdef __APPLE__
+ /* <rdar://problem/5377791>
+ Install a signal handler that will forward SIGHUP to the
+ child and process group. The parent should not exit on
+ SIGHUP so that the tty ownership can be reset. */
+ (void)signal(SIGHUP, handle_sighup);
+#endif /* __APPLE__ */
+
+ /*
+ * We must fork() before setuid() because we need to call
+ * pam_close_session() as root.
+ */
+ pid = fork();
+ if (pid < 0) {
+ err(1, "fork");
+ } else if (pid != 0) {
+ /*
+ * Parent: wait for child to finish, then clean up
+ * session.
+ */
+ int status;
+#ifndef __APPLE__
+ setproctitle("-%s [pam]", getprogname());
+#endif /* !__APPLE__ */
+#ifdef __APPLE__
+ /* Our SIGHUP handler may interrupt the wait */
+ int res;
+ do {
+ res = waitpid(pid, &status, 0);
+ } while (res == -1 && errno == EINTR);
+#else
+ waitpid(pid, &status, 0);
+#endif
+#ifdef __APPLE__
+ chown(ttyn, 0, 0);
+ chmod(ttyn, 0666);
+#endif /* __APPLE__ */
+ bail(NO_SLEEP_EXIT, 0);
+ }
+
+ /*
+ * NOTICE: We are now in the child process!
+ */
+
+#ifdef __APPLE__
+ /* Restore the default SIGHUP handler for the child. */
+ (void)signal(SIGHUP, SIG_DFL);
+#endif /* __APPLE__ */
+
+#ifdef USE_PAM
+ /*
+ * Add any environment variables the PAM modules may have set.
+ */
+ export_pam_environment();
+
+ /*
+ * We're done with PAM now; our parent will deal with the rest.
+ */
+ pam_end(pamh, 0);
+ pamh = NULL;
+#endif /* USE_PAM */
+
+ /*
+ * We don't need to be root anymore, so set the login name and
+ * the UID.
+ */
+ if (setlogin(username) != 0) {
+ syslog(LOG_ERR, "setlogin(%s): %m - exiting", username);
+ bail(NO_SLEEP_EXIT, 1);
+ }
+#ifdef __APPLE__
+ /* <rdar://problem/6041650> restore process priority if not changing uids */
+ if (uid == (uid_t)pwd->pw_uid) {
+ (void)setpriority(PRIO_PROCESS, 0, prio);
+ }
+
+ (void)setgid(pwd->pw_gid);
+ if (initgroups(username, pwd->pw_gid) == -1)
+ syslog(LOG_ERR, "login: initgroups() failed");
+ (void) setuid(rootlogin ? 0 : pwd->pw_uid);
+#else /* !__APPLE__ */
+ if (setusercontext(lc, pwd, pwd->pw_uid,
+ LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) {
+ syslog(LOG_ERR, "setusercontext() failed - exiting");
+ exit(1);
+ }
+#endif /* !__APPLE__ */
+
+#ifdef __APPLE__
+ /* We test for the home directory after pam_open_session(3)
+ * as the home directory may have been mounted by a session
+ * module, and after changing uid as the home directory may
+ * be NFS with root access disabled. */
+ if (!lflag) {
+ /* First do a stat in case the homedir is automounted */
+ stat(pwd->pw_dir,&st);
+ if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
+ printf("No home directory: %s\n", pwd->pw_dir);
+ if (chdir("/") < 0) {
+ refused("Cannot find root directory", "ROOTDIR", 0);
+ exit(1);
+ }
+ pwd->pw_dir = strdup("/");
+ if (pwd->pw_dir == NULL) {
+ syslog(LOG_NOTICE, "strdup(): %m");
+ exit(1);
+ }
+ }
+ }
+#endif /* __APPLE__ */
+ if (pwd->pw_shell) {
+ (void)setenv("SHELL", pwd->pw_shell, 1);
+ } else {
+ syslog(LOG_ERR, "pwd->pw_shell not set - exiting");
+ bail(NO_SLEEP_EXIT, 1);
+ }
+ if (pwd->pw_dir) {
+ (void)setenv("HOME", pwd->pw_dir, 1);
+ } else {
+ (void)setenv("HOME", "/", 1);
+ }
+ /* Overwrite "term" from login.conf(5) for any known TERM */
+ if (term == NULL && (tp = stypeof(tty)) != NULL)
+ (void)setenv("TERM", tp, 1);
+ else
+ (void)setenv("TERM", TERM_UNKNOWN, 0);
+ (void)setenv("LOGNAME", username, 1);
+ (void)setenv("USER", username, 1);
+ (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
+
+#ifdef __APPLE__
+ /* Re-enable crash reporter */
+ do {
+ kern_return_t kr;
+ mach_port_t bp, ep, mts;
+ thread_state_flavor_t flavor = 0;
+
+#if defined(__ppc__)
+ flavor = PPC_THREAD_STATE64;
+#elif defined(__i386__) || defined(__x86_64__)
+ flavor = x86_THREAD_STATE;
+#elif defined(__arm__)
+ flavor = ARM_THREAD_STATE;
+#else
+#error unsupported architecture
+#endif
+
+ mts = mach_task_self();
+
+ kr = task_get_bootstrap_port(mts, &bp);
+ if (kr != KERN_SUCCESS) {
+ syslog(LOG_ERR, "task_get_bootstrap_port() failure: %s (%d)",
+ bootstrap_strerror(kr), kr);
+ break;
+ }
+
+ const char* bs = "com.apple.ReportCrash";
+ kr = bootstrap_look_up(bp, (char*)bs, &ep);
+ if (kr != KERN_SUCCESS) {
+ syslog(LOG_ERR, "bootstrap_look_up(%s) failure: %s (%d)",
+ bs, bootstrap_strerror(kr), kr);
+ break;
+ }
+
+ kr = task_set_exception_ports(mts, EXC_MASK_CRASH, ep, EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, flavor);
+ if (kr != KERN_SUCCESS) {
+ syslog(LOG_ERR, "task_set_exception_ports() failure: %d", kr);
+ break;
+ }
+ } while (0);
+#endif /* __APPLE__ */
+
+ if (!quietlog) {
+#ifdef LOGIN_CAP
+ const char *cw;
+
+ cw = login_getcapstr(lc, "copyright", NULL, NULL);
+ if (cw == NULL || motd(cw) == -1)
+ (void)printf("%s", copyright);
+
+ (void)printf("\n");
+
+ cw = login_getcapstr(lc, "welcome", NULL, NULL);
+ if (cw != NULL && access(cw, F_OK) == 0)
+ motd(cw);
+ else
+ motd(_PATH_MOTDFILE);
+
+ if (login_getcapbool(lc_user, "nocheckmail", 0) == 0 &&
+ login_getcapbool(lc, "nocheckmail", 0) == 0) {
+#else /* !LOGIN_CAP */
+ motd(_PATH_MOTDFILE);
+ {
+#endif /* !LOGIN_CAP */
+ char *cx;
+
+ /* $MAIL may have been set by class. */
+ cx = getenv("MAIL");
+ if (cx == NULL) {
+ asprintf(&cx, "%s/%s",
+ _PATH_MAILDIR, pwd->pw_name);
+ }
+ if (cx && stat(cx, &st) == 0 && st.st_size != 0)
+ (void)printf("You have %smail.\n",
+ (st.st_mtime > st.st_atime) ? "new " : "");
+ if (getenv("MAIL") == NULL)
+ free(cx);
+ }
+ }
+
+#ifdef LOGIN_CAP
+ login_close(lc_user);
+ login_close(lc);
+#endif /* LOGIN_CAP */
+
+ (void)signal(SIGALRM, SIG_DFL);
+ (void)signal(SIGQUIT, SIG_DFL);
+ (void)signal(SIGINT, SIG_DFL);
+ (void)signal(SIGTSTP, SIG_IGN);
+
+#ifdef __APPLE__
+ if (fflag && *argv) pwd->pw_shell = *argv;
+#endif /* __APPLE__ */
+
+ /*
+ * Login shells have a leading '-' in front of argv[0]
+ */
+ p = strrchr(pwd->pw_shell, '/');
+#ifdef __APPLE__
+ if (asprintf(&arg0, "%s%s", lflag ? "" : "-", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) {
+#else /* __APPLE__ */
+ if (asprintf(&arg0, "-%s", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) {
+#endif /* __APPLE__ */
+ syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size",
+ username);
+ errx(1, "shell exceeds maximum pathname size");
+ } else if (arg0 == NULL) {
+ err(1, "asprintf()");
+ }
+
+#ifdef __APPLE__
+ if (fflag && *argv) {
+ *argv = arg0;
+ execvp(pwd->pw_shell, argv);
+ err(1, "%s", arg0);
+ }
+#endif /* __APPLE__ */
+ execlp(shell, arg0, (char *)0);
+ err(1, "%s", shell);
+
+ /*
+ * That's it, folks!
+ */
+}
+
+#ifdef USE_PAM
+/*
+ * Attempt to authenticate the user using PAM. Returns 0 if the user is
+ * authenticated, or 1 if not authenticated. If some sort of PAM system
+ * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
+ * function returns -1. This can be used as an indication that we should
+ * fall back to a different authentication mechanism.
+ */
+static int
+auth_pam(int skip_auth)
+{
+ const char *tmpl_user;
+ const void *item;
+ int rval;
+
+ rval = 0;
+
+ if (skip_auth == 0)
+ {
+ pam_err = pam_authenticate(pamh, pam_silent);
+ switch (pam_err) {
+
+ case PAM_SUCCESS:
+ /*
+ * With PAM we support the concept of a "template"
+ * user. The user enters a login name which is
+ * authenticated by PAM, usually via a remote service
+ * such as RADIUS or TACACS+. If authentication
+ * succeeds, a different but related "template" name
+ * is used for setting the credentials, shell, and
+ * home directory. The name the user enters need only
+ * exist on the remote authentication server, but the
+ * template name must be present in the local password
+ * database.
+ *
+ * This is supported by two various mechanisms in the
+ * individual modules. However, from the application's
+ * point of view, the template user is always passed
+ * back as a changed value of the PAM_USER item.
+ */
+ pam_err = pam_get_item(pamh, PAM_USER, &item);
+ if (pam_err == PAM_SUCCESS) {
+ tmpl_user = (const char *)item;
+ if (strcmp(username, tmpl_user) != 0)
+ pwd = getpwnam(tmpl_user);
+ } else {
+ pam_syslog("pam_get_item(PAM_USER)");
+ }
+ rval = 0;
+ break;
+
+ case PAM_AUTH_ERR:
+ case PAM_USER_UNKNOWN:
+ case PAM_MAXTRIES:
+ rval = 1;
+ break;
+
+ default:
+ pam_syslog("pam_authenticate()");
+ rval = -1;
+ break;
+ }
+ }
+
+ if (rval == 0) {
+ pam_err = pam_acct_mgmt(pamh, pam_silent);
+ switch (pam_err) {
+ case PAM_SUCCESS:
+ break;
+ case PAM_NEW_AUTHTOK_REQD:
+ if (skip_auth == 0)
+ {
+ pam_err = pam_chauthtok(pamh,
+ pam_silent|PAM_CHANGE_EXPIRED_AUTHTOK);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_chauthtok()");
+ rval = 1;
+ }
+ }
+ else
+ {
+ pam_syslog("pam_acct_mgmt()");
+ }
+ break;
+ default:
+ pam_syslog("pam_acct_mgmt()");
+ rval = 1;
+ break;
+ }
+ }
+
+ if (rval != 0) {
+ pam_end(pamh, pam_err);
+ pamh = NULL;
+ }
+ return (rval);
+}
+
+/*
+ * Export any environment variables PAM modules may have set
+ */
+static void
+export_pam_environment()
+{
+ char **pam_env;
+ char **pp;
+
+ pam_env = pam_getenvlist(pamh);
+ if (pam_env != NULL) {
+ for (pp = pam_env; *pp != NULL; pp++) {
+ (void)export(*pp);
+ free(*pp);
+ }
+ }
+}
+
+/*
+ * Perform sanity checks on an environment variable:
+ * - Make sure there is an '=' in the string.
+ * - Make sure the string doesn't run on too long.
+ * - Do not export certain variables. This list was taken from the
+ * Solaris pam_putenv(3) man page.
+ * Then export it.
+ */
+static int
+export(const char *s)
+{
+ static const char *noexport[] = {
+ "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
+ "IFS", "PATH", NULL
+ };
+ char *p;
+ const char **pp;
+ size_t n;
+
+ if (strlen(s) > 1024 || (p = strchr(s, '=')) == NULL)
+ return (0);
+ if (strncmp(s, "LD_", 3) == 0)
+ return (0);
+ for (pp = noexport; *pp != NULL; pp++) {
+ n = strlen(*pp);
+ if (s[n] == '=' && strncmp(s, *pp, n) == 0)
+ return (0);
+ }
+ *p = '\0';
+ (void)setenv(s, p + 1, 1);
+ *p = '=';
+ return (1);
+}
+#endif /* USE_PAM */
+
+static void
+usage()
+{
+#ifdef __APPLE__
+ (void)fprintf(stderr, "usage: login [-pq] [-h hostname] [username]\n");
+ (void)fprintf(stderr, " login -f [-lpq] [-h hostname] [username [prog [arg ...]]]\n");
+#else
+ (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n");
+#endif
+ exit(1);
+}
+
+/*
+ * Prompt user and read login name from stdin.
+ */
+static char *
+getloginname()
+{
+ char *nbuf, *p;
+ int ch;
+
+ nbuf = malloc(MAXLOGNAME);
+ if (nbuf == NULL)
+ err(1, "malloc()");
+ do {
+ (void)printf("%s", prompt);
+ for (p = nbuf; (ch = getchar()) != '\n'; ) {
+ if (ch == EOF) {
+ badlogin(username);
+ bail(NO_SLEEP_EXIT, 0);
+ }
+ if (p < nbuf + MAXLOGNAME - 1)
+ *p++ = ch;
+ }
+ } while (p == nbuf);
+
+ *p = '\0';
+ if (nbuf[0] == '-') {
+#ifdef USE_PAM
+ pam_silent = 0;
+#endif /* USE_PAM */
+ memmove(nbuf, nbuf + 1, strlen(nbuf));
+ } else {
+#ifdef USE_PAM
+ pam_silent = PAM_SILENT;
+#endif /* USE_PAM */
+ }
+ return nbuf;
+}
+
+#ifdef __APPLE__
+#ifndef USE_PAM
+static int
+rootterm(const char* ttyn)
+{
+ struct ttyent *t;
+ return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
+}
+#endif /* !USE_PAM */
+#endif /* __APPLE__ */
+
+/*
+ * SIGINT handler for motd().
+ */
+static volatile int motdinterrupt;
+static void
+sigint(int signo __unused)
+{
+ motdinterrupt = 1;
+}
+
+/*
+ * Display the contents of a file (such as /etc/motd).
+ */
+static int
+motd(const char *motdfile)
+{
+ sig_t oldint;
+ FILE *f;
+ int ch;
+
+ if ((f = fopen(motdfile, "r")) == NULL)
+ return (-1);
+ motdinterrupt = 0;
+ oldint = signal(SIGINT, sigint);
+ while ((ch = fgetc(f)) != EOF && !motdinterrupt)
+ putchar(ch);
+ signal(SIGINT, oldint);
+ if (ch != EOF || ferror(f)) {
+ fclose(f);
+ return (-1);
+ }
+ fclose(f);
+ return (0);
+}
+
+/*
+ * SIGHUP handler
+ * Forwards the SIGHUP to the child process and current process group.
+ */
+static void
+handle_sighup(int signo)
+{
+ if (pid > 0) {
+ /* close the controlling terminal */
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ /* Ignore SIGHUP to avoid tail-recursion on signaling
+ the current process group (of which we are a member). */
+ (void)signal(SIGHUP, SIG_IGN);
+ /* Forward the signal to the current process group. */
+ (void)kill(0, signo);
+ /* Forward the signal to the child if not a member of the current
+ * process group <rdar://problem/6244808>. */
+ if (getpgid(pid) != getpgrp()) {
+ (void)kill(pid, signo);
+ }
+ }
+}
+
+/*
+ * SIGALRM handler, to enforce login prompt timeout.
+ *
+ * XXX This can potentially confuse the hell out of PAM. We should
+ * XXX instead implement a conversation function that returns
+ * XXX PAM_CONV_ERR when interrupted by a signal, and have the signal
+ * XXX handler just set a flag.
+ */
+static void
+timedout(int signo __unused)
+{
+
+ longjmp(timeout_buf, signo);
+}
+
+#ifdef __APPLE__
+#ifndef USE_PAM
+void
+checknologin()
+{
+ int fd, nchars;
+ char tbuf[8192];
+
+ if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
+ while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
+ (void)write(fileno(stdout), tbuf, nchars);
+#ifdef USE_BSM_AUDIT
+ au_login_fail("No login", 0);
+#endif
+ sleep(5);
+ exit(0);
+ }
+}
+#endif /* !USE_PAM */
+
+void
+dolastlog(quiet)
+ int quiet;
+{
+#ifdef USE_PAM
+ if (quiet)
+ return;
+ if (*lastlog.ll_line) {
+ (void)printf("Last login: %.*s ",
+ 24-5, (char *)ctime(&lastlog.ll_tv.tv_sec));
+ if (*lastlog.ll_host != '\0')
+ (void)printf("from %.*s\n",
+ (int)sizeof(lastlog.ll_host),
+ lastlog.ll_host);
+ else
+ (void)printf("on %.*s\n",
+ (int)sizeof(lastlog.ll_line),
+ lastlog.ll_line);
+ }
+#else /* !USE_PAM */
+ struct lastlogx ll;
+
+ if(!quiet && getlastlogx(pwd->pw_uid, &ll) != NULL) {
+ (void)printf("Last login: %.*s ",
+ 24-5, (char *)ctime(&ll.ll_tv.tv_sec));
+ if (*ll.ll_host != '\0')
+ (void)printf("from %.*s\n",
+ (int)sizeof(ll.ll_host),
+ ll.ll_host);
+ else
+ (void)printf("on %.*s\n",
+ (int)sizeof(ll.ll_line),
+ ll.ll_line);
+ }
+#endif /* USE_PAM */
+}
+#endif /* __APPLE__ */
+
+static void
+badlogin(char *name)
+{
+
+ if (failures == 0)
+ return;
+ if (hflag) {
+ syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
+ failures, failures > 1 ? "S" : "", hostname);
+ syslog(LOG_AUTHPRIV|LOG_NOTICE,
+ "%d LOGIN FAILURE%s FROM %s, %s",
+ failures, failures > 1 ? "S" : "", hostname, name);
+ } else {
+ syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
+ failures, failures > 1 ? "S" : "", tty);
+ syslog(LOG_AUTHPRIV|LOG_NOTICE,
+ "%d LOGIN FAILURE%s ON %s, %s",
+ failures, failures > 1 ? "S" : "", tty, name);
+ }
+ failures = 0;
+}
+
+const char *
+stypeof(char *ttyid)
+{
+ struct ttyent *t;
+
+ if (ttyid != NULL && *ttyid != '\0') {
+ t = getttynam(ttyid);
+ if (t != NULL && t->ty_type != NULL)
+ return (t->ty_type);
+ }
+ return (NULL);
+}
+
+static void
+refused(const char *msg, const char *rtype, int lout)
+{
+
+ if (msg != NULL)
+ printf("%s.\n", msg);
+ if (hflag)
+ syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
+ pwd->pw_name, rtype, hostname, tty);
+ else
+ syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s",
+ pwd->pw_name, rtype, tty);
+ if (lout)
+ bail(SLEEP_EXIT, 1);
+}
+
+#ifdef USE_PAM
+/*
+ * Log a PAM error
+ */
+static void
+pam_syslog(const char *msg)
+{
+ syslog(LOG_ERR, "%s: %s", msg, pam_strerror(pamh, pam_err));
+}
+
+/*
+ * Shut down PAM
+ */
+static void
+pam_cleanup()
+{
+
+ if (pamh != NULL) {
+ if (pam_session_established) {
+ pam_err = pam_close_session(pamh, 0);
+ if (pam_err != PAM_SUCCESS)
+ pam_syslog("pam_close_session()");
+ }
+ pam_session_established = 0;
+ if (pam_cred_established) {
+ pam_err = pam_setcred(pamh, pam_silent|PAM_DELETE_CRED);
+ if (pam_err != PAM_SUCCESS)
+ pam_syslog("pam_setcred()");
+ }
+ pam_cred_established = 0;
+ pam_end(pamh, pam_err);
+ pamh = NULL;
+ }
+}
+#endif /* USE_PAM */
+
+/*
+ * Exit, optionally after sleeping a few seconds
+ */
+void
+bail(int sec, int eval)
+{
+
+#ifdef USE_PAM
+ pam_cleanup();
+#endif /* USE_PAM */
+#ifdef USE_BSM_AUDIT
+ if (pwd != NULL)
+ audit_logout();
+#endif
+ (void)sleep(sec);
+ exit(eval);
+}
--- /dev/null
+/*-
+ * Copyright (c) 2001 FreeBSD, Inc
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD: src/usr.bin/login/login.h,v 1.7 2007/05/07 11:01:36 dwmalone Exp $
+ */
+
+void login_fbtab(char *, uid_t, gid_t);
+
+#ifdef USE_BSM_AUDIT
+void au_login_success(int fflag);
+void au_login_fail(const char *errmsg, int na);
+void audit_logout(void);
+#endif
+
+extern char **environ;
+extern struct passwd *pwd;
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc.
+ * All rights reserved.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_START@
+ *
+ * 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. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 APPLE OR ITS CONTRIBUTORS 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.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_END@
+ */
+
+#ifdef USE_BSM_AUDIT
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/login/login_audit.c,v 1.2 2007/05/07 11:01:36 dwmalone Exp $");
+
+#include <sys/types.h>
+
+#include <bsm/libbsm.h>
+#include <bsm/audit_uevents.h>
+#include <bsm/audit_session.h>
+
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "login.h"
+
+/*
+ * Audit data
+ */
+au_tid_addr_t tid;
+
+/*
+ * The following tokens are included in the audit record for a successful
+ * login: header, subject, return.
+ */
+void
+au_login_success(int fflag)
+{
+ token_t *tok;
+ int aufd;
+ auditinfo_addr_t auinfo;
+ uid_t uid = pwd->pw_uid;
+ gid_t gid = pwd->pw_gid;
+ pid_t pid = getpid();
+ long au_cond;
+
+ /* Determine whether auditing is enabled. */
+ if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
+ if (errno == ENOSYS)
+ return;
+ errx(1, "login: Could not determine audit condition");
+ }
+
+ /* Initialize with the current audit info. */
+ if (getaudit_addr(&auinfo, sizeof(auinfo)) < 0) {
+ err(1, "getaudit_addr");
+ }
+ auinfo.ai_auid = pwd->pw_uid;
+ memcpy(&auinfo.ai_termid, &tid, sizeof(auinfo.ai_termid));
+
+ /* Do the SessionCreate() equivalent. */
+ if (!fflag) {
+ auinfo.ai_asid = AU_ASSIGN_ASID;
+ auinfo.ai_flags |= AU_SESSION_FLAG_HAS_TTY;
+ auinfo.ai_flags |= AU_SESSION_FLAG_HAS_AUTHENTICATED;
+ }
+
+ if (au_cond != AUC_NOAUDIT) {
+ /* Compute and set the user's preselection mask. */
+ if (au_user_mask(pwd->pw_name, &auinfo.ai_mask) < 0) {
+ errx(1, "login: Could not set audit mask\n");
+ }
+ }
+
+ if (setaudit_addr(&auinfo, sizeof(auinfo)) < 0)
+ err(1, "login: setaudit_addr failed");
+
+ char *session = NULL;
+ asprintf(&session, "%x", auinfo.ai_asid);
+ if (NULL == session) {
+ errx(1, "asprintf failed");
+ }
+ setenv("SECURITYSESSIONID", session, 1);
+ free(session);
+
+ /* If we are not auditing, don't cut an audit record; just return. */
+ if (au_cond == AUC_NOAUDIT)
+ return;
+
+ if ((aufd = au_open()) == -1)
+ errx(1,"login: Audit Error: au_open() failed");
+
+ if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, gid, pid,
+ pid, &tid)) == NULL)
+ errx(1, "login: Audit Error: au_to_subject32() failed");
+ au_write(aufd, tok);
+
+ if ((tok = au_to_return32(0, 0)) == NULL)
+ errx(1, "login: Audit Error: au_to_return32() failed");
+ au_write(aufd, tok);
+
+ if (au_close(aufd, 1, AUE_login) == -1)
+ errx(1, "login: Audit Record was not committed.");
+}
+
+/*
+ * The following tokens are included in the audit record for failed
+ * login attempts: header, subject, text, return.
+ */
+void
+au_login_fail(const char *errmsg, int na)
+{
+ token_t *tok;
+ int aufd;
+ long au_cond;
+ uid_t uid;
+ gid_t gid;
+ pid_t pid = getpid();
+
+ /* If we are not auditing, don't cut an audit record; just return. */
+ if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
+ if (errno == ENOSYS)
+ return;
+ errx(1, "login: Could not determine audit condition");
+ }
+ if (au_cond == AUC_NOAUDIT)
+ return;
+
+ if ((aufd = au_open()) == -1)
+ errx(1, "login: Audit Error: au_open() failed");
+
+ if (na) {
+ /*
+ * Non attributable event. Assuming that login is not called
+ * within a user's session => auid,asid == -1.
+ */
+ if ((tok = au_to_subject32_ex(-1, geteuid(), getegid(), -1, -1,
+ pid, -1, &tid)) == NULL)
+ errx(1, "login: Audit Error: au_to_subject32() failed");
+ } else {
+ /* We know the subject -- so use its value instead. */
+ uid = pwd->pw_uid;
+ gid = pwd->pw_gid;
+ if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid,
+ gid, pid, pid, &tid)) == NULL)
+ errx(1, "login: Audit Error: au_to_subject32() failed");
+ }
+ au_write(aufd, tok);
+
+ /* Include the error message. */
+ if ((tok = au_to_text(errmsg)) == NULL)
+ errx(1, "login: Audit Error: au_to_text() failed");
+ au_write(aufd, tok);
+
+ if ((tok = au_to_return32(1, errno)) == NULL)
+ errx(1, "login: Audit Error: au_to_return32() failed");
+ au_write(aufd, tok);
+
+ if (au_close(aufd, 1, AUE_login) == -1)
+ errx(1, "login: Audit Error: au_close() was not committed");
+}
+
+/*
+ * The following tokens are included in the audit record for a logout:
+ * header, subject, return.
+ */
+void
+audit_logout(void)
+{
+ token_t *tok;
+ int aufd;
+ uid_t uid = pwd->pw_uid;
+ gid_t gid = pwd->pw_gid;
+ pid_t pid = getpid();
+ long au_cond;
+
+ /* If we are not auditing, don't cut an audit record; just return. */
+ if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
+ if (errno == ENOSYS)
+ return;
+ errx(1, "login: Could not determine audit condition");
+ }
+ if (au_cond == AUC_NOAUDIT)
+ return;
+
+ if ((aufd = au_open()) == -1)
+ errx(1, "login: Audit Error: au_open() failed");
+
+ /* The subject that is created (euid, egid of the current process). */
+ if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, gid, pid,
+ pid, &tid)) == NULL)
+ errx(1, "login: Audit Error: au_to_subject32() failed");
+ au_write(aufd, tok);
+
+ if ((tok = au_to_return32(0, 0)) == NULL)
+ errx(1, "login: Audit Error: au_to_return32() failed");
+ au_write(aufd, tok);
+
+ if (au_close(aufd, 1, AUE_logout) == -1)
+ errx(1, "login: Audit Record was not committed.");
+}
+
+#endif /* USE_BSM_AUDIT */
--- /dev/null
+# login: auth account password session
+auth optional pam_krb5.so use_kcminit
+auth optional pam_ntlm.so try_first_pass
+auth optional pam_mount.so try_first_pass
+auth required pam_opendirectory.so try_first_pass
+account required pam_nologin.so
+account required pam_opendirectory.so
+password required pam_opendirectory.so
+session required pam_launchd.so
+session required pam_uwtmp.so
+session optional pam_mount.so
--- /dev/null
+# login: account session
+account required pam_nologin.so
+account required pam_opendirectory.so
+session required pam_uwtmp.so
--- /dev/null
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/9/93
+ * $FreeBSD: src/usr.bin/login/pathnames.h,v 1.6 2006/03/06 12:38:42 yar Exp $
+ */
+
+#include <paths.h>
+
+#define _PATH_HUSHLOGIN ".hushlogin"
+#define _PATH_MOTDFILE "/etc/motd"
+#define _PATH_FBTAB "/etc/fbtab"
+#define _PATH_LOGINDEVPERM "/etc/logindevperm"
--- /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) 1990, 1991, 1993
+.\" The Regents of the University of California. 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)makekey.8 8.2 (Berkeley) 12/11/93
+.\"
+.Dd December 11, 1993
+.Dt MAKEKEY 8
+.Os
+.Sh NAME
+.Nm makekey
+.Nd make encrypted keys or passwords
+.Sh SYNOPSIS
+.Nm makekey
+.Sh DESCRIPTION
+.Nm Makekey
+encrypts a key and salt which it reads from the standard input,
+writing the result to the standard output.
+The key and salt values are expected to be ten and two bytes,
+respectively, in length.
+See
+.Xr crypt 3
+for more information on what characters the key and salt can contain
+and how the encrypted value is calculated.
+.Sh SEE ALSO
+.Xr crypt 1 ,
+.Xr login 1 ,
+.Xr crypt 3
+.Sh HISTORY
+A
+.Nm makekey
+command appeared in Version 7 AT&T UNIX.
--- /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) 1990, 1993
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static char copyright[] =
+"@(#) Copyright (c) 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+__unused static char sccsid[] = "@(#)makekey.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void get __P((char *, int));
+
+int
+main()
+{
+ int len;
+ char *r, key[9], salt[3];
+
+ get(key, sizeof(key) - 1);
+ get(salt, sizeof(salt) - 1);
+ len = strlen(r = crypt(key, salt));
+ if (write(STDOUT_FILENO, r, len) != len)
+ err(1, "stdout");
+ exit(0);
+}
+
+static void
+get(bp, len)
+ char *bp;
+ register int len;
+{
+ register int nr;
+
+ bp[len] = '\0';
+ if ((nr = read(STDIN_FILENO, bp, len)) == len)
+ return;
+ if (nr >= 0)
+ errno = EFTYPE;
+ err(1, "stdin");
+}
--- /dev/null
+/*
+ * mean.c
+ * mean - lower process priorities with more force than nice
+ *
+ * Created by Lucia Ballard on 9/16/09.
+ * Copyright 2009 Apple Inc. All rights reserved.
+ *
+ */
+
+#include <mach/mach.h>
+#include <mach/task.h>
+#include <mach/thread_act.h>
+#include <mach/thread_policy.h>
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void usage(void);
+
+
+void
+usage(void)
+{
+ fprintf(stderr, "Usage: mean -[r|s|u] <pid>\n");
+ fprintf(stderr, "\tLower <pid>'s priority.\n");
+ fprintf(stderr, "\t-u: return <pid> to normal priority\n");
+ fprintf(stderr, "\t-r: resume <pid>\n");
+ fprintf(stderr, "\t-s: suspend <pid>\n");
+ exit(0);
+}
+
+int
+main(int argc, char **argv)
+{
+ int pid, err, i, ch;
+ unsigned int count;
+ mach_port_t task;
+ thread_act_array_t threads;
+ thread_precedence_policy_data_t policy;
+
+ boolean_t do_high = 0, do_resume = 0, do_suspend = 0;
+ boolean_t do_low = 1;
+
+ if (argc < 2)
+ usage();
+
+ while ((ch = getopt(argc, argv, "rsu")) != -1)
+ switch (ch) {
+ case 'u':
+ do_high = 1;
+ do_low = 0;
+ continue;
+ case 'r':
+ do_resume = 1;
+ do_low = 0;
+ continue;
+ case 's':
+ do_suspend = 1;
+ do_low = 0;
+ continue;
+ default:
+ usage();
+ }
+
+ argc -= optind; argv += optind;
+
+ if (argc == 0)
+ usage();
+
+ pid = atoi(*argv);
+ if (!pid)
+ usage();
+
+ err = task_for_pid(mach_task_self(), pid, &task);
+ if (err) {
+ fprintf(stderr, "Failed to get task port (%d)\n", err);
+ exit(0);
+ }
+
+ if (do_low || do_high) {
+
+ err = task_threads(task, &threads, &count);
+ if (err) {
+ fprintf(stderr, "Failed to get thread list (%d)\n", err);
+ exit(0);
+ }
+
+ if (do_low)
+ policy.importance = -100;
+ else
+ policy.importance = 0;
+
+ for (i = 0; i < count; i++) {
+ err = thread_policy_set(threads[i],
+ THREAD_PRECEDENCE_POLICY,
+ (thread_policy_t) &policy,
+ THREAD_PRECEDENCE_POLICY_COUNT);
+ if (err) {
+ fprintf(stderr, "Failed to set thread priority (%d)\n", err);
+ exit(0);
+ }
+ }
+
+ printf("Process %d's threads set to %s priority.\n", pid,
+ (do_low ? "lowest" : "highest"));
+ }
+
+ if (do_suspend) {
+ err = task_suspend(task);
+ if (err) {
+ fprintf(stderr, "Failed to suspend task (%d)\n", err);
+ } else {
+ printf("Process %d suspended.\n", pid);
+ }
+
+ }
+
+ if (do_resume) {
+ err = task_resume(task);
+ if (err) {
+ fprintf(stderr, "Failed to resume task (%d)\n", err);
+ } else {
+ printf("Process %d resumed.\n", pid);
+ }
+ }
+
+ return 0;
+}
+
--- /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;
+}
--- /dev/null
+.\" (c) 1997 Apple Computer, Inc.
+.TH MKFILE 8 "1 September 1997"
+.SH NAME
+mkfile \- create a file
+.SH SYNOPSIS
+.B mkfile
+.RB [ " -nv " ]
+.I size\c
+[\c
+.BR b | k | m | g\c
+]
+.IR filename " .\|.\|."
+.SH DESCRIPTION
+.B mkfile
+creates one or more files that are suitable for use as
+.SM NFS-\s0mounted
+swap areas. The sticky bit is set, and
+the file is padded with zeroes by default.
+Non-root users must set the sticky bit using
+chmod(1).
+The default size unit is bytes, but the following suffixes
+may be used to multiply by the given factor:
+.B b
+(512),
+.B k
+(1024),
+.B m
+(1048576), and
+.B g
+(1073741824).
+.SH OPTIONS
+.TP
+.B \-n
+Create an empty
+.IR filename .
+The size is noted, but disk blocks aren't allocated until data is
+written to them.
+.TP
+.B \-v
+Verbose. Report the names and sizes of created files.
+.SH WARNING
+If a client's swap file is removed and recreated, it must be
+re-exported before the client will be able to access it.
+This action may only be done when the client is not running.
+.SH "SEE ALSO"
+.TP
+chmod(2), stat(2), sticky(8)
--- /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) 1997 Apple Computer, Inc. All Rights Reserved
+ *
+ * HISTORY
+ * 29-Aug-97 Daniel Wade (danielw) at Apple
+ * Created.
+ *
+ */
+
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <err.h>
+
+#define BF_SZ 512 /* Size of write chunks */
+
+extern void usage(char *, char *);
+extern void create_file(char *, quad_t, int, int);
+extern void err_rm(char *, char *);
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *b_num, *prog_name;
+ char *options = "nv";
+ char c;
+ off_t multiplier = 1;
+ off_t file_size;
+ int len;
+ int empty = 0;
+ int verbose = 0;
+ char* endptr = NULL;
+
+ prog_name = argv[0]; /* Get program name */
+ if (1 == argc)
+ usage(prog_name, options);
+
+ /* Get options */
+ opterr=1;
+
+ while ((c=getopt(argc, argv, options)) != EOF)
+ switch (c) {
+ case 'v': /* Turn on verbose setting */
+ verbose = 1;
+ break;
+ case 'n': /* Create an empty file */
+ empty = 1;
+ break;
+ default:
+ usage(prog_name, options);
+ break;
+ }
+
+ /* Stop getting options
+ */
+ argv += optind;
+ if (*argv == NULL) /* Is there a size given? */
+ usage(prog_name, options);
+
+ b_num = *argv++; /* Size of file and byte multiplier */
+ len = strlen(b_num) - 1;
+
+ if (!isdigit(b_num[len])) {
+ switch(b_num[len]) { /* Figure out multiplier */
+ case 'B':
+ case 'b':
+ multiplier = 512;
+ break;
+ case 'K':
+ case 'k':
+ multiplier = 1024;
+ break;
+ case 'M':
+ case 'm':
+ multiplier = 1024 * 1024;
+ break;
+ case 'G':
+ case 'g':
+ multiplier = 1024 * 1024 * 1024;
+ break;
+ default:
+ usage(prog_name, options);
+ }
+ }
+
+ if (*argv == NULL) /* Was a file name given? */
+ usage(prog_name, options);
+
+ if ((file_size = strtoll(b_num, &endptr, 10)) == 0 &&
+ (*endptr != 0 && endptr != &b_num[len])) {
+ err(1, "Bad file size!");
+ }
+
+ while ( *argv != NULL ) { /* Create file for each file_name */
+ create_file(*argv, file_size*multiplier, empty, verbose);
+ argv++;
+ }
+
+ return (0);
+
+}
+
+
+/* Create a file and make it empty (lseek) or zero'd */
+
+void
+create_file(file_name, size, empty, verbose)
+ char *file_name;
+ quad_t size;
+ int empty;
+ int verbose;
+{
+ char buff[BF_SZ];
+ int fd, bytes_written = BF_SZ;
+ quad_t i;
+ mode_t mode = S_IRUSR | S_IWUSR;
+
+ /* If superuser, then set sticky bit */
+ if (!geteuid()) mode |= S_ISVTX;
+
+ if ((fd = open(file_name, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1)
+ err(1, NULL);
+
+
+ if (empty) { /* Create an empty file */
+ lseek(fd, (off_t)size-1, SEEK_SET);
+ if ( 1 != write(fd, "\0", 1))
+ err_rm(file_name, "Write Error");
+ }
+ else {
+ bzero(buff, BF_SZ);
+
+ /*
+ * First loop: write BF_SZ chunks until you have
+ * less then BF_SZ bytes to write.
+ * Second loop: write the remaining bytes.
+ * ERRORS in the write process will cause the
+ * file to be removed before the error is
+ * reported.
+ */
+ for (i = size; i > BF_SZ; i -= bytes_written) {
+ bytes_written = write (fd, buff, BF_SZ);
+ if ( bytes_written == -1 )
+ err_rm (file_name, "Write Error");
+ }
+ for (; i > 0; i -= bytes_written) {
+ bytes_written = write (fd, buff, i);
+ if ( bytes_written == -1 )
+ err_rm (file_name, "Write Error");
+ }
+ }
+
+ if (fchmod(fd, mode)) /* Change permissions */
+ err_rm(file_name, NULL);
+
+ if ((close(fd)) == -1)
+ err_rm(file_name, NULL);
+
+ if (verbose)
+ (void)fprintf(stderr, "%s %qd bytes\n", file_name, size);
+
+}
+
+/* On error remove the file */
+
+void
+err_rm(filename, msg)
+ char *filename;
+ char *msg;
+{
+ unlink(filename);
+ err(1, "(%s removed) %s", filename, msg);
+}
+
+
+/* Print usage string */
+void
+usage (prog_name, options)
+ char *prog_name;
+ char *options;
+{
+ (void)fprintf(stderr,
+ "usage: %s [-%s] size[b|k|m|g] filename ...\n", prog_name, options);
+ exit(1);
+
+}
--- /dev/null
+.\" Copyright (c) 2002 Tim J. Robbins.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD: src/usr.bin/newgrp/newgrp.1,v 1.3 2005/01/17 07:44:25 ru Exp $
+.\"
+.Dd May 23, 2002
+.Dt NEWGRP 1
+.Os
+.Sh NAME
+.Nm newgrp
+.Nd change to a new group
+.Sh SYNOPSIS
+.Nm
+.Op Fl l
+.Op Ar group
+.Sh DESCRIPTION
+The
+.Nm
+utility creates a new shell execution environment with modified
+real and effective group IDs.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl l
+Simulate a full login.
+The environment and umask are set to what would be expected if the user
+actually logged in again.
+.El
+.Pp
+If the
+.Ar group
+operand is present, a new shell is started with the specified effective
+and real group IDs.
+The user will be prompted for a password if they are not a member of the
+specified group.
+.Pp
+Otherwise, the real, effective and supplementary group IDs are restored to
+those from the current user's password database entry.
+.Sh EXIT STATUS
+The
+.Nm
+utility attempts to start the shell regardless of whether group IDs
+were successfully changed.
+.Pp
+If an error occurs and the shell cannot be started,
+.Nm
+exits >0.
+Otherwise, the exit status of
+.Nm
+is the exit status of the shell.
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr groups 1 ,
+.Xr login 1 ,
+.Xr sh 1 ,
+.Xr su 1 ,
+.Xr umask 1 ,
+.Xr group 5 ,
+.Xr passwd 5 ,
+.Xr environ 7
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v6 .
+.Sh BUGS
+Group passwords are inherently insecure as there is no way to stop
+users obtaining the crypted passwords from the group database.
+Their use is discouraged.
--- /dev/null
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+/*
+ * newgrp -- change to a new group
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/newgrp/newgrp.c,v 1.5 2009/12/13 03:14:06 delphij Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <libgen.h>
+#include <limits.h>
+#ifndef __APPLE__
+#include <login_cap.h>
+#endif /* !__APPLE__ */
+#ifdef __APPLE__
+#include <membership.h>
+#endif /* __APPLE__ */
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef __APPLE__
+#include <paths.h>
+#endif /* __APPLE__ */
+static void addgroup(const char *grpname);
+static void doshell(void);
+static int inarray(gid_t, const gid_t[], int);
+static void loginshell(void);
+static void restoregrps(void);
+static void usage(void);
+
+static struct passwd *pwd;
+static uid_t euid;
+
+extern char **environ;
+
+/* Manipulate effective user ID. */
+#define PRIV_START do { \
+ if (seteuid(euid) < 0) \
+ err(1, "seteuid"); \
+ } while (0)
+#define PRIV_END do { \
+ if (seteuid(getuid()) < 0) \
+ err(1, "seteuid"); \
+ } while (0)
+
+int
+main(int argc, char *argv[])
+{
+ int ch, login;
+
+ euid = geteuid();
+ if (seteuid(getuid()) < 0)
+ err(1, "seteuid");
+
+ if ((pwd = getpwuid(getuid())) == NULL)
+ errx(1, "unknown user");
+
+ login = 0;
+ while ((ch = getopt(argc, argv, "-l")) != -1) {
+ switch (ch) {
+ case '-': /* Obsolescent */
+ case 'l':
+ login = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch (argc) {
+ case 0:
+ restoregrps();
+ break;
+ case 1:
+ addgroup(*argv);
+ break;
+ default:
+ usage();
+ }
+
+ if (seteuid(euid) < 0)
+ err(1, "seteuid");
+ if (setuid(getuid()) < 0)
+ err(1, "setuid");
+
+ if (login)
+ loginshell();
+ else
+ doshell();
+
+ /*NOTREACHED*/
+ exit(1);
+}
+
+static void
+usage(void)
+{
+
+ fprintf(stderr, "usage: newgrp [-l] [group]\n");
+ exit(1);
+}
+
+static void
+restoregrps(void)
+{
+ int initres, setres;
+
+ PRIV_START;
+ initres = initgroups(pwd->pw_name, pwd->pw_gid);
+ setres = setgid(pwd->pw_gid);
+ PRIV_END;
+
+ if (initres < 0)
+ warn("initgroups");
+ if (setres < 0)
+ warn("setgid");
+}
+
+static void
+addgroup(const char *grpname)
+{
+ gid_t *grps;
+ long lgid, ngrps_max;
+ int dbmember, i, ngrps;
+ gid_t egid;
+ struct group *grp;
+ char *ep, *pass;
+ char **p;
+ char *grp_passwd;
+#ifdef __APPLE__
+ uuid_t user_uuid;
+ uuid_t group_uuid;
+ int status;
+#endif
+
+ egid = getegid();
+
+ /* Try it as a group name, then a group id. */
+ if ((grp = getgrnam(grpname)) == NULL)
+ if ((lgid = strtol(grpname, &ep, 10)) <= 0 || *ep != '\0' ||
+ (grp = getgrgid((gid_t)lgid)) == NULL ) {
+ warnx("%s: bad group name", grpname);
+ return;
+ }
+
+#ifdef __APPLE__
+ status = mbr_uid_to_uuid(pwd->pw_uid, user_uuid);
+ if (status)
+ errc(1, status, "mbr_uid_to_uuid");
+
+ status = mbr_gid_to_uuid(grp->gr_gid, group_uuid);
+ if (status)
+ errc(1, status, "mbr_gid_to_uuid");
+
+ status = mbr_check_membership(user_uuid, group_uuid, &dbmember);
+ if (status)
+ errc(1, status, "mbr_check_membership");
+#else
+ /*
+ * If the user is not a member of the requested group and the group
+ * has a password, prompt and check it.
+ */
+ dbmember = 0;
+ if (pwd->pw_gid == grp->gr_gid)
+ dbmember = 1;
+ for (p = grp->gr_mem; *p != NULL; p++)
+ if (strcmp(*p, pwd->pw_name) == 0) {
+ dbmember = 1;
+ break;
+ }
+#endif
+
+ grp_passwd = grp->gr_passwd;
+ if ((grp_passwd == NULL) || (grp_passwd[0] == '\0'))
+ grp_passwd = "*";
+ if (!dbmember && getuid() != 0) {
+ pass = getpass("Password:");
+ if (pass == NULL ||
+ strcmp(grp_passwd, crypt(pass, grp_passwd)) != 0) {
+ fprintf(stderr, "Sorry\n");
+ return;
+ }
+ }
+
+ ngrps_max = sysconf(_SC_NGROUPS_MAX) + 1;
+ if ((grps = malloc(sizeof(gid_t) * ngrps_max)) == NULL)
+ err(1, "malloc");
+ if ((ngrps = getgroups(ngrps_max, (gid_t *)grps)) < 0) {
+ warn("getgroups");
+ goto end;
+ }
+
+ /* Remove requested gid from supp. list if it exists. */
+ if (grp->gr_gid != egid && inarray(grp->gr_gid, grps, ngrps)) {
+ for (i = 0; i < ngrps; i++)
+ if (grps[i] == grp->gr_gid)
+ break;
+ ngrps--;
+ memmove(&grps[i], &grps[i + 1], (ngrps - i) * sizeof(gid_t));
+ PRIV_START;
+ if (setgroups(ngrps, (const gid_t *)grps) < 0) {
+ PRIV_END;
+ warn("setgroups");
+ goto end;
+ }
+ PRIV_END;
+ }
+
+ PRIV_START;
+ if (setgid(grp->gr_gid)) {
+ PRIV_END;
+ warn("setgid");
+ goto end;
+ }
+ PRIV_END;
+ grps[0] = grp->gr_gid;
+
+ /* Add old effective gid to supp. list if it does not exist. */
+ if (egid != grp->gr_gid && !inarray(egid, grps, ngrps)) {
+ if (ngrps + 1 >= ngrps_max)
+ warnx("too many groups");
+ else {
+ grps[ngrps++] = egid;
+ PRIV_START;
+ if (setgroups(ngrps, (const gid_t *)grps)) {
+ PRIV_END;
+ warn("setgroups");
+ goto end;
+ }
+ PRIV_END;
+ }
+ }
+
+end:
+ free(grps);
+}
+
+static int
+inarray(gid_t gid, const gid_t grps[], int ngrps)
+{
+ int i;
+
+ for (i = 0; i < ngrps; i++)
+ if (grps[i] == gid)
+ return (1);
+ return (0);
+}
+
+/*
+ * Set the environment to what would be expected if the user logged in
+ * again; this performs the same steps as su(1)'s -l option.
+ */
+static void
+loginshell(void)
+{
+ char *args[2], **cleanenv, *term, *ticket;
+ const char *shell;
+ char *prog, progbuf[PATH_MAX];
+#ifndef __APPLE__
+ login_cap_t *lc;
+#endif /* !__APPLE__ */
+ shell = pwd->pw_shell;
+ if (*shell == '\0')
+ shell = _PATH_BSHELL;
+ if (chdir(pwd->pw_dir) < 0) {
+ warn("%s", pwd->pw_dir);
+ chdir("/");
+ }
+
+ term = getenv("TERM");
+ ticket = getenv("KRBTKFILE");
+
+ if ((cleanenv = calloc(20, sizeof(char *))) == NULL)
+ err(1, "calloc");
+ *cleanenv = NULL;
+ environ = cleanenv;
+#ifndef __APPLE__
+ lc = login_getpwclass(pwd);
+ setusercontext(lc, pwd, pwd->pw_uid,
+ LOGIN_SETPATH|LOGIN_SETUMASK|LOGIN_SETENV);
+ login_close(lc);
+#endif /* !__APPLE__ */
+ setenv("USER", pwd->pw_name, 1);
+ setenv("SHELL", shell, 1);
+ setenv("HOME", pwd->pw_dir, 1);
+ if (term != NULL)
+ setenv("TERM", term, 1);
+ if (ticket != NULL)
+ setenv("KRBTKFILE", ticket, 1);
+
+ strlcpy(progbuf, shell, sizeof(progbuf));
+ prog = basename(progbuf);
+
+ if (asprintf(args, "-%s", prog) < 0)
+ err(1, "asprintf");
+ args[1] = NULL;
+
+ execv(shell, args);
+ err(1, "%s", shell);
+}
+
+static void
+doshell(void)
+{
+ const char *shell;
+ char *prog, progbuf[PATH_MAX];
+
+ shell = pwd->pw_shell;
+ if (*shell == '\0')
+ shell = _PATH_BSHELL;
+
+ strlcpy(progbuf, shell, sizeof(progbuf));
+ prog = basename(progbuf);
+
+ execl(shell, prog, (char *)NULL);
+ err(1, "%s", shell);
+}
--- /dev/null
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)nologin.8 8.1 (Berkeley) 6/19/93
+.\" $FreeBSD: src/usr.sbin/nologin/nologin.5,v 1.15 2007/05/10 11:22:24 yar Exp $
+.\"
+.Dd May 10, 2007
+.Dt NOLOGIN 5
+.Os
+.Sh NAME
+.Nm nologin
+.Nd disallow logins
+.Sh DESCRIPTION
+Programs such as
+.Xr login 1
+disallow logins if the
+.Nm
+file exists.
+The programs display the contents of
+.Nm
+to the user if possible and interrupt the login sequence.
+This makes it simple to temporarily prevent incoming logins systemwide.
+.Pp
+To disable logins on a per-account basis,
+investigate
+.Xr nologin 8 .
+.Sh SECURITY
+The
+.Nm
+file is ignored for user root by default.
+.Sh IMPLEMENTATION NOTES
+The
+.Nm
+feature is implemented through
+.Xr login.conf 5 ,
+which allows to change the pathname of the
+file and to extend the list of users
+exempt from temporary login restriction.
+.Pp
+PAM-aware programs can be selectively configured to respect
+.Nm
+using the
+.Xr pam_nologin 8
+module via
+.Xr pam.conf 5 .
+.Pp
+The
+.Nm
+file will be removed at system boot if it resides in
+.Pa /var/run
+and
+.Va cleanvar_enable
+is set to
+.Dq Li YES
+in
+.Xr rc.conf 5 ,
+which is default.
+Therefore system reboot can effectively re-enable logins.
+.Sh FILES
+.Bl -tag -width ".Pa /var/run/nologin" -compact
+.It Pa /var/run/nologin
+default location of
+.Nm
+.El
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr login.conf 5 ,
+.Xr pam.conf 5 ,
+.Xr rc.conf 5 ,
+.Xr nologin 8 ,
+.Xr pam_nologin 8 ,
+.Xr shutdown 8
--- /dev/null
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)nologin.8 8.1 (Berkeley) 6/19/93
+.\" $FreeBSD: src/usr.sbin/nologin/nologin.8,v 1.14 2004/08/07 04:27:52 imp Exp $
+.\"
+.Dd June 19, 1993
+.Dt NOLOGIN 8
+.Os
+.Sh NAME
+.Nm nologin
+.Nd politely refuse a login
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility displays a message that an account is not available and
+exits non-zero.
+It is intended as a replacement shell field for accounts that
+have been disabled.
+.Pp
+To disable all logins,
+investigate
+.Xr nologin 5 .
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr nologin 5
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.4 .
--- /dev/null
+/*-
+ * Copyright (c) 2004 The FreeBSD Project.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/nologin/nologin.c,v 1.6 2005/01/04 20:07:12 delphij Exp $");
+
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define MESSAGE "This account is currently not available.\n"
+
+int
+main(__unused int argc, __unused char *argv[])
+{
+ const char *user, *tt;
+
+ if ((tt = ttyname(0)) == NULL)
+ tt = "UNKNOWN";
+ if ((user = getlogin()) == NULL)
+ user = "UNKNOWN";
+ openlog("nologin", LOG_CONS, LOG_AUTH);
+ syslog(LOG_CRIT, "Attempted login by %s on %s", user, tt);
+ closelog();
+
+ printf("%s", MESSAGE);
+ return 1;
+}
--- /dev/null
+.\"
+.\" Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
+.\"
+.TH nvram 8 "October 28, 2003"
+.SH NAME
+nvram \- manipulate firmware NVRAM variables
+.SH SYNOPSIS
+.B nvram
+[
+.B -p
+] [
+.B -f
+.IR filename
+] [
+.B -d
+.IR name
+] [
+.B -c
+] [
+.IR name
+[=
+.IR value
+]] ...
+.SH DESCRIPTION
+The
+.I nvram
+command allows manipulation of firmware NVRAM variables. It
+can be used to get or set a variable. It can also be used to print
+all of the variables or set a list of variables from a file.
+Changes to NVRAM variables are only saved by clean restart or shutdown.
+.LP
+In principle,
+.IR name
+can be any string. In practice, not all strings will be accepted.
+New World machines can create new variables as desired. Some variables
+require administrator privilege to get or set.
+.LP
+The given
+.IR value
+must match the data type required for
+.IR name .
+Binary data can be set using the %xx notation, where xx is the hex
+value of the byte. The type for new variables is always binary
+data.
+.SH OPTIONS
+.\" ==========
+.TP
+.BI \-d " name"
+Deletes the named firmware variable.
+.\" ==========
+.TP
+.BI \-f " filename"
+Set firmware variables from a text file. The file must be a
+list of "name value" statements. The first space on each line
+is taken to be the separator between "name" and "value". If
+the last character of a line is \\, the value extends to the next line.
+.\" ==========
+.TP
+.B \-x
+Use XML format for reading and writing variables.
+This option must be used before the
+.B \-p
+or
+.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
+.LP
+.RS
+example% nvram boot-args="-s rd=*hd:10"
+.RE
+.LP
+Set the boot-args variable to "-s rd=*hd:10". This would specify
+single user mode with the root device in hard drive partition 10.
+.LP
+.RS
+example% nvram my-variable="String One%00String Two%00%00"
+.RE
+.LP
+Create a new variable, my-variable, containing a list of two
+C-strings that is terminated by a NUL.
+.LP
+.RS
+example% nvram -d my-variable
+.RE
+.LP
+Deletes the variable named my-variable.
+.PD
--- /dev/null
+/*
+ * Copyright (c) 2000-2012 Apple Computer, 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@
+ */
+/*
+cc -o nvram nvram.c -framework CoreFoundation -framework IOKit -Wall
+*/
+
+#include <stdio.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOKitKeys.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <err.h>
+#include <mach/mach_error.h>
+
+// Prototypes
+static void UsageMessage(char *message);
+static void ParseFile(char *fileName);
+static void ParseXMLFile(char *fileName);
+static void SetOrGetOFVariable(char *str);
+static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
+ CFTypeRef *valueRef);
+static kern_return_t SetOFVariable(char *name, char *value);
+static void DeleteOFVariable(char *name);
+static void PrintOFVariables(void);
+static void PrintOFVariable(const void *key,const void *value,void *context);
+static void SetOFVariableFromFile(const void *key, const void *value, void *context);
+static void ClearOFVariables(void);
+static void ClearOFVariable(const void *key,const void *value,void *context);
+static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value);
+
+static void NVRamSyncNow(char *name);
+
+// Global Variables
+static char *gToolName;
+static io_registry_entry_t gOptionsRef;
+static bool gUseXML;
+
+
+int main(int argc, char **argv)
+{
+ long cnt;
+ char *str, errorMessage[256];
+ kern_return_t result;
+ mach_port_t masterPort;
+
+ // Get the name of the command.
+ gToolName = strrchr(argv[0], '/');
+ if (gToolName != 0) gToolName++;
+ else gToolName = argv[0];
+
+ result = IOMasterPort(bootstrap_port, &masterPort);
+ if (result != KERN_SUCCESS) {
+ errx(1, "Error getting the IOMaster port: %s",
+ mach_error_string(result));
+ }
+
+ gOptionsRef = IORegistryEntryFromPath(masterPort, "IODeviceTree:/options");
+ if (gOptionsRef == 0) {
+ errx(1, "nvram is not supported on this system");
+ }
+
+ for (cnt = 1; cnt < argc; cnt++) {
+ str = argv[cnt];
+ if (str[0] == '-' && str[1] != 0) {
+ // Parse the options.
+ for (str += 1 ; *str; str++) {
+ switch (*str) {
+ case 'p' :
+ PrintOFVariables();
+ break;
+
+ case 'x' :
+ gUseXML = true;
+ break;
+
+ case 'f':
+ cnt++;
+ if (cnt < argc && *argv[cnt] != '-') {
+ ParseFile(argv[cnt]);
+ } else {
+ UsageMessage("missing filename");
+ }
+ break;
+
+ case 'd':
+ cnt++;
+ if (cnt < argc && *argv[cnt] != '-') {
+ DeleteOFVariable(argv[cnt]);
+ } else {
+ UsageMessage("missing name");
+ }
+ break;
+
+ case 'c':
+ ClearOFVariables();
+ break;
+
+ default:
+ strcpy(errorMessage, "no such option as --");
+ errorMessage[strlen(errorMessage)-1] = *str;
+ UsageMessage(errorMessage);
+ }
+ }
+ } else {
+ // Other arguments will be firmware variable requests.
+ SetOrGetOFVariable(str);
+ }
+ }
+
+ IOObjectRelease(gOptionsRef);
+
+ return 0;
+}
+
+// UsageMessage(message)
+//
+// Print the usage information and exit.
+//
+static void UsageMessage(char *message)
+{
+ warnx("(usage: %s)", message);
+
+ 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");
+ printf("\t-f set firmware variables from a text file\n");
+ printf("\t-d delete the named variable\n");
+ printf("\t-c delete all variables\n");
+ printf("\tname=value set named variable\n");
+ printf("\tname print variable\n");
+ printf("Note that arguments and options are executed in order.\n");
+
+ exit(1);
+}
+
+
+// States for ParseFile.
+enum {
+ kFirstColumn = 0,
+ kScanComment,
+ kFindName,
+ kCollectName,
+ kFindValue,
+ kCollectValue,
+ kContinueValue,
+ kSetenv,
+
+ kMaxStringSize = 0x800,
+ kMaxNameSize = 0x100
+};
+
+
+// ParseFile(fileName)
+//
+// Open and parse the specified file.
+//
+static void ParseFile(char *fileName)
+{
+ long state, tc, ni = 0, vi = 0;
+ char name[kMaxNameSize];
+ char value[kMaxStringSize];
+ FILE *patches;
+ kern_return_t kret;
+
+ if (gUseXML) {
+ ParseXMLFile(fileName);
+ return;
+ }
+
+ patches = fopen(fileName, "r");
+ if (patches == 0) {
+ err(1, "Couldn't open patch file - '%s'", fileName);
+ }
+
+ state = kFirstColumn;
+ while ((tc = getc(patches)) != EOF) {
+ if(ni==(kMaxNameSize-1))
+ errx(1, "Name exceeded max length of %d", kMaxNameSize);
+ if(vi==(kMaxStringSize-1))
+ errx(1, "Value exceeded max length of %d", kMaxStringSize);
+ switch (state) {
+ case kFirstColumn :
+ ni = 0;
+ vi = 0;
+ if (tc == '#') {
+ state = kScanComment;
+ } else if (tc == '\n') {
+ // state stays kFirstColumn.
+ } else if (isspace(tc)) {
+ state = kFindName;
+ } else {
+ state = kCollectName;
+ name[ni++] = tc;
+ }
+ break;
+
+ case kScanComment :
+ if (tc == '\n') {
+ state = kFirstColumn;
+ } else {
+ // state stays kScanComment.
+ }
+ break;
+
+ case kFindName :
+ if (tc == '\n') {
+ state = kFirstColumn;
+ } else if (isspace(tc)) {
+ // state stays kFindName.
+ } else {
+ state = kCollectName;
+ name[ni++] = tc;
+ }
+ break;
+
+ case kCollectName :
+ if (tc == '\n') {
+ name[ni] = 0;
+ warnx("Name must be followed by white space - '%s'", name);
+ state = kFirstColumn;
+ } else if (isspace(tc)) {
+ state = kFindValue;
+ } else {
+ name[ni++] = tc;
+ // state staus kCollectName.
+ }
+ break;
+
+ case kFindValue :
+ case kContinueValue :
+ if (tc == '\n') {
+ state = kSetenv;
+ } else if (isspace(tc)) {
+ // state stays kFindValue or kContinueValue.
+ } else {
+ state = kCollectValue;
+ value[vi++] = tc;
+ }
+ break;
+
+ case kCollectValue :
+ if (tc == '\n') {
+ if (value[vi-1] == '\\') {
+ value[vi-1] = '\r';
+ state = kContinueValue;
+ } else {
+ state = kSetenv;
+ }
+ } else {
+ // state stays kCollectValue.
+ value[vi++] = tc;
+ }
+ break;
+ }
+
+ if (state == kSetenv) {
+ name[ni] = 0;
+ value[vi] = 0;
+ if ((kret = SetOFVariable(name, value)) != KERN_SUCCESS) {
+ errx(1, "Error setting variable - '%s': %s", name,
+ mach_error_string(kret));
+ }
+ state = kFirstColumn;
+ }
+ }
+
+ if (state != kFirstColumn) {
+ errx(1, "Last line ended abruptly");
+ }
+}
+
+
+// ParseXMLFile(fileName)
+//
+// Open and parse the specified file in XML format,
+// and set variables appropriately.
+//
+static void ParseXMLFile(char *fileName)
+{
+ CFPropertyListRef plist;
+ CFURLRef fileURL = NULL;
+ CFStringRef filePath = NULL;
+ CFStringRef errorString = NULL;
+ CFDataRef data = NULL;
+ SInt32 errorCode = 0;
+
+ filePath = CFStringCreateWithCString(kCFAllocatorDefault, fileName, kCFStringEncodingUTF8);
+ if (filePath == NULL) {
+ errx(1, "Could not create file path string");
+ }
+
+ // Create a URL that specifies the file we will create to
+ // hold the XML data.
+ fileURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault,
+ filePath,
+ kCFURLPOSIXPathStyle,
+ false /* not a directory */ );
+ if (fileURL == NULL) {
+ errx(1, "Could not create file path URL");
+ }
+
+ CFRelease(filePath);
+
+ if (! CFURLCreateDataAndPropertiesFromResource(
+ kCFAllocatorDefault,
+ fileURL,
+ &data,
+ NULL,
+ NULL,
+ &errorCode) || data == NULL ) {
+ errx(1, "Error reading XML file (%d)", (int)errorCode);
+ }
+
+ CFRelease(fileURL);
+
+ plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault,
+ data,
+ kCFPropertyListImmutable,
+ &errorString);
+
+ CFRelease(data);
+
+ if (plist == NULL) {
+ errx(1, "Error parsing XML file");
+ }
+
+ if (errorString != NULL) {
+ errx(1, "Error parsing XML file: %s", CFStringGetCStringPtr(errorString, kCFStringEncodingUTF8));
+ }
+
+ CFDictionaryApplyFunction(plist, &SetOFVariableFromFile, 0);
+
+ CFRelease(plist);
+}
+
+// SetOrGetOFVariable(str)
+//
+// Parse the input string, then set or get the specified
+// firmware variable.
+//
+static void SetOrGetOFVariable(char *str)
+{
+ long set = 0;
+ char *name;
+ char *value;
+ CFStringRef nameRef;
+ CFTypeRef valueRef;
+ kern_return_t result;
+
+ // OF variable name is first.
+ name = str;
+
+ // Find the equal sign for set
+ while (*str) {
+ if (*str == '=') {
+ set = 1;
+ *str++ = '\0';
+ break;
+ }
+ str++;
+ }
+
+ if (set == 1) {
+ // On sets, the OF variable's value follows the equal sign.
+ value = str;
+
+ result = SetOFVariable(name, value);
+ NVRamSyncNow(name); /* Try syncing the new data to device, best effort! */
+ if (result != KERN_SUCCESS) {
+ errx(1, "Error setting variable - '%s': %s", name,
+ mach_error_string(result));
+ }
+ } else {
+ result = GetOFVariable(name, &nameRef, &valueRef);
+ if (result != KERN_SUCCESS) {
+ errx(1, "Error getting variable - '%s': %s", name,
+ mach_error_string(result));
+ }
+
+ PrintOFVariable(nameRef, valueRef, 0);
+ CFRelease(nameRef);
+ CFRelease(valueRef);
+ }
+}
+
+
+// GetOFVariable(name, nameRef, valueRef)
+//
+// Get the named firmware variable.
+// Return it and it's symbol in valueRef and nameRef.
+//
+static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
+ CFTypeRef *valueRef)
+{
+ *nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
+ kCFStringEncodingUTF8);
+ if (*nameRef == 0) {
+ errx(1, "Error creating CFString for key %s", name);
+ }
+
+ *valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, *nameRef, 0, 0);
+ if (*valueRef == 0) return kIOReturnNotFound;
+
+ return KERN_SUCCESS;
+}
+
+
+// SetOFVariable(name, value)
+//
+// Set or create an firmware variable with name and value.
+//
+static kern_return_t SetOFVariable(char *name, char *value)
+{
+ CFStringRef nameRef;
+ CFTypeRef valueRef;
+ CFTypeID typeID;
+ kern_return_t result = KERN_SUCCESS;
+
+ nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
+ kCFStringEncodingUTF8);
+ if (nameRef == 0) {
+ errx(1, "Error creating CFString for key %s", name);
+ }
+
+ valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, nameRef, 0, 0);
+ if (valueRef) {
+ typeID = CFGetTypeID(valueRef);
+ CFRelease(valueRef);
+
+ valueRef = ConvertValueToCFTypeRef(typeID, value);
+ if (valueRef == 0) {
+ errx(1, "Error creating CFTypeRef for value %s", value);
+ } result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
+ } else {
+ while (1) {
+ // In the default case, try data, string, number, then boolean.
+
+ valueRef = ConvertValueToCFTypeRef(CFDataGetTypeID(), value);
+ if (valueRef != 0) {
+ result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
+ if (result == KERN_SUCCESS) break;
+ }
+
+ valueRef = ConvertValueToCFTypeRef(CFStringGetTypeID(), value);
+ if (valueRef != 0) {
+ result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
+ if (result == KERN_SUCCESS) break;
+ }
+
+ valueRef = ConvertValueToCFTypeRef(CFNumberGetTypeID(), value);
+ if (valueRef != 0) {
+ result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
+ if (result == KERN_SUCCESS) break;
+ }
+
+ valueRef = ConvertValueToCFTypeRef(CFBooleanGetTypeID(), value);
+ if (valueRef != 0) {
+ result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
+ if (result == KERN_SUCCESS) break;
+ }
+
+ break;
+ }
+ }
+
+ CFRelease(nameRef);
+
+ return result;
+}
+
+
+// DeleteOFVariable(name)
+//
+// Delete the named firmware variable.
+//
+//
+static void DeleteOFVariable(char *name)
+{
+ SetOFVariable(kIONVRAMDeletePropertyKey, name);
+}
+
+static void NVRamSyncNow(char *name)
+{
+ SetOFVariable(kIONVRAMSyncNowPropertyKey, name);
+}
+
+// PrintOFVariables()
+//
+// Print all of the firmware variables.
+//
+static void PrintOFVariables()
+{
+ kern_return_t result;
+ CFMutableDictionaryRef dict;
+
+ result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
+ if (result != KERN_SUCCESS) {
+ errx(1, "Error getting the firmware variables: %s", mach_error_string(result));
+ }
+
+ if (gUseXML) {
+ CFDataRef data;
+
+ data = CFPropertyListCreateXMLData( kCFAllocatorDefault, dict );
+ if (data == NULL) {
+ errx(1, "Error converting variables to xml");
+ }
+
+ fwrite(CFDataGetBytePtr(data), sizeof(UInt8), CFDataGetLength(data), stdout);
+
+ CFRelease(data);
+
+ } else {
+
+ CFDictionaryApplyFunction(dict, &PrintOFVariable, 0);
+
+ }
+
+ CFRelease(dict);
+}
+
+// PrintOFVariable(key, value, context)
+//
+// Print the given firmware variable.
+//
+static void PrintOFVariable(const void *key, const void *value, void *context)
+{
+ long cnt, cnt2;
+ CFIndex nameLen;
+ char *nameBuffer = 0;
+ const char *nameString;
+ char numberBuffer[10];
+ const uint8_t *dataPtr;
+ uint8_t dataChar;
+ char *dataBuffer = 0;
+ CFIndex valueLen;
+ char *valueBuffer = 0;
+ const char *valueString = 0;
+ uint32_t number, length;
+ CFTypeID typeID;
+
+ // Get the OF variable's name.
+ nameLen = CFStringGetLength(key) + 1;
+ nameBuffer = malloc(nameLen);
+ if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) )
+ nameString = nameBuffer;
+ else {
+ warnx("Unable to convert property name to C string");
+ nameString = "<UNPRINTABLE>";
+ }
+
+ // Get the OF variable's type.
+ typeID = CFGetTypeID(value);
+
+ if (typeID == CFBooleanGetTypeID()) {
+ if (CFBooleanGetValue(value)) valueString = "true";
+ else valueString = "false";
+ } else if (typeID == CFNumberGetTypeID()) {
+ CFNumberGetValue(value, kCFNumberSInt32Type, &number);
+ if (number == 0xFFFFFFFF) sprintf(numberBuffer, "-1");
+ else if (number < 1000) sprintf(numberBuffer, "%d", number);
+ else sprintf(numberBuffer, "0x%x", number);
+ valueString = numberBuffer;
+ } else if (typeID == CFStringGetTypeID()) {
+ valueLen = CFStringGetLength(value) + 1;
+ valueBuffer = malloc(valueLen + 1);
+ if ( valueBuffer && CFStringGetCString(value, valueBuffer, valueLen, kCFStringEncodingUTF8) )
+ valueString = valueBuffer;
+ else {
+ warnx("Unable to convert value to C string");
+ valueString = "<UNPRINTABLE>";
+ }
+ } else if (typeID == CFDataGetTypeID()) {
+ length = CFDataGetLength(value);
+ if (length == 0) valueString = "";
+ else {
+ dataBuffer = malloc(length * 3 + 1);
+ if (dataBuffer != 0) {
+ dataPtr = CFDataGetBytePtr(value);
+ for (cnt = cnt2 = 0; cnt < length; cnt++) {
+ dataChar = dataPtr[cnt];
+ if (isprint(dataChar)) dataBuffer[cnt2++] = dataChar;
+ else {
+ sprintf(dataBuffer + cnt2, "%%%02x", dataChar);
+ cnt2 += 3;
+ }
+ }
+ dataBuffer[cnt2] = '\0';
+ valueString = dataBuffer;
+ }
+ }
+ } else {
+ valueString="<INVALID>";
+ }
+
+ if ((nameString != 0) && (valueString != 0))
+ printf("%s\t%s\n", nameString, valueString);
+
+ if (dataBuffer != 0) free(dataBuffer);
+ if (nameBuffer != 0) free(nameBuffer);
+ if (valueBuffer != 0) free(valueBuffer);
+}
+
+// ClearOFVariables()
+//
+// Deletes all OF variables
+//
+static void ClearOFVariables(void)
+{
+ kern_return_t result;
+ CFMutableDictionaryRef dict;
+
+ result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
+ if (result != KERN_SUCCESS) {
+ errx(1, "Error getting the firmware variables: %s", mach_error_string(result));
+ }
+ CFDictionaryApplyFunction(dict, &ClearOFVariable, 0);
+
+ CFRelease(dict);
+}
+
+static void ClearOFVariable(const void *key, const void *value, void *context)
+{
+ kern_return_t result;
+ result = IORegistryEntrySetCFProperty(gOptionsRef,
+ CFSTR(kIONVRAMDeletePropertyKey), key);
+ if (result != KERN_SUCCESS) {
+ errx(1, "Error clearing firmware variables: %s", mach_error_string(result));
+ }
+}
+
+// ConvertValueToCFTypeRef(typeID, value)
+//
+// Convert the value into a CFType given the typeID.
+//
+static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value)
+{
+ CFTypeRef valueRef = 0;
+ long cnt, cnt2, length;
+ unsigned long number, tmp;
+
+ if (typeID == CFBooleanGetTypeID()) {
+ if (!strcmp("true", value)) valueRef = kCFBooleanTrue;
+ else if (!strcmp("false", value)) valueRef = kCFBooleanFalse;
+ } else if (typeID == CFNumberGetTypeID()) {
+ number = strtol(value, 0, 0);
+ valueRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type,
+ &number);
+ } else if (typeID == CFStringGetTypeID()) {
+ valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value,
+ kCFStringEncodingUTF8);
+ } else if (typeID == CFDataGetTypeID()) {
+ length = strlen(value);
+ for (cnt = cnt2 = 0; cnt < length; cnt++, cnt2++) {
+ if (value[cnt] == '%') {
+ if (!ishexnumber(value[cnt + 1]) ||
+ !ishexnumber(value[cnt + 2])) return 0;
+ number = toupper(value[++cnt]) - '0';
+ if (number > 9) number -= 7;
+ tmp = toupper(value[++cnt]) - '0';
+ if (tmp > 9) tmp -= 7;
+ number = (number << 4) + tmp;
+ value[cnt2] = number;
+ } else value[cnt2] = value[cnt];
+ }
+ valueRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)value,
+ cnt2, kCFAllocatorDefault);
+ } else return 0;
+
+ return valueRef;
+}
+
+static void SetOFVariableFromFile(const void *key, const void *value, void *context)
+{
+ kern_return_t result;
+
+ result = IORegistryEntrySetCFProperty(gOptionsRef, key, value);
+ if ( result != KERN_SUCCESS ) {
+ int nameLen;
+ char *nameBuffer;
+ char *nameString;
+
+ // Get the variable's name.
+ nameLen = CFStringGetLength(key) + 1;
+ nameBuffer = malloc(nameLen);
+ if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) )
+ nameString = nameBuffer;
+ else {
+ warnx("Unable to convert property name to C string");
+ nameString = "<UNPRINTABLE>";
+ }
+ errx(1, "Error setting variable - '%s': %s", nameString,
+ mach_error_string(result));
+ }
+}
--- /dev/null
+.\" Copyright (c) 1983, 1990, 1993
+.\" The Regents of the University of California. 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)pagesize.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/pagesize/pagesize.1,v 1.7 2002/04/20 12:16:17 charnier Exp $
+.\"
+.Dd June 6, 1993
+.Dt PAGESIZE 1
+.Os
+.Sh NAME
+.Nm pagesize
+.Nd print system page size
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility prints the size of a page of memory in bytes, as
+returned by
+.Xr getpagesize 3 .
+This program is useful in constructing portable
+shell scripts.
+.Sh SEE ALSO
+.Xr getpagesize 3
+.Sh HISTORY
+The
+.Nm
+command
+appeared in
+.Bx 4.2 .
--- /dev/null
+#!/bin/sh -
+#
+# Copyright (c) 1994
+# The Regents of the University of California. 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 the University of
+# California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+#
+# @(#)pagesize.sh 8.1 (Berkeley) 4/3/94
+# $FreeBSD: src/usr.bin/pagesize/pagesize.sh,v 1.5 1999/08/28 01:04:48 peter Exp $
+#
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin; export PATH
+
+exec sysctl -n hw.pagesize
--- /dev/null
+/*
+ * Copyright (c) 1999-2010 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 <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include "passwd.h"
+
+#define _PASSWD_FILE "/etc/master.passwd"
+#define _COMPAT_FILE "/etc/passwd"
+#define _PASSWD_FIELDS 10
+#define BUFSIZE 8192
+
+void getpasswd(char *, int, int, int, int, char *, char **, char**, char **);
+
+static struct passwd *
+parse_user(char *line, size_t len)
+{
+ static struct passwd pw;
+ int i,j;
+ char *tokens[_PASSWD_FIELDS];
+ char *token = NULL;
+ bool comment = true;
+
+ free(pw.pw_name);
+ free(pw.pw_passwd);
+ free(pw.pw_class);
+ free(pw.pw_gecos);
+ free(pw.pw_dir);
+ free(pw.pw_shell);
+ memset(&pw, 0, sizeof(pw));
+
+ if (line == NULL) return NULL;
+
+ memset(&tokens, 0, sizeof(char *) * _PASSWD_FIELDS);
+
+ for (i = 0, j = 0; i < len && j < _PASSWD_FIELDS; ++i) {
+ int c = line[i];
+ if (!isspace(c) && c != '#') {
+ comment = false;
+ }
+ if (!comment && token == NULL) {
+ // start a new token
+ token = &line[i];
+ } else if (token && (c == ':' || c == '\n')) {
+ // end the current token
+ // special case for empty token
+ while (token[0] == ':' && token < &line[i]) {
+ tokens[j++] = strdup("");
+ ++token;
+ }
+ tokens[j++] = strndup(token, &line[i] - token);
+ token = NULL;
+ }
+ }
+
+ if (comment || j != _PASSWD_FIELDS) return NULL;
+
+ j = 0;
+ pw.pw_name = tokens[j++];
+ pw.pw_passwd = tokens[j++];
+ pw.pw_uid = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_gid = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_class = tokens[j++];
+ pw.pw_change = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_expire = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_gecos = tokens[j++];
+ pw.pw_dir = tokens[j++];
+ pw.pw_shell = tokens[j++];
+
+ return &pw;
+}
+
+static struct passwd *
+find_user(FILE *fp, char *uname)
+{
+ size_t len;
+ char *line;
+
+ rewind(fp);
+
+ while ((line = fgetln(fp, &len)) != NULL) {
+ struct passwd *pw = parse_user(line, len);
+ if (pw && strcmp(uname, pw->pw_name) == 0) {
+ return pw;
+ }
+ }
+ return NULL;
+}
+
+static void
+rewrite_file(char *path, FILE *fp, struct passwd *newpw)
+{
+ int fd;
+ char *line;
+ size_t len;
+ FILE *tfp = NULL;
+ char *tempname = NULL; // temporary master.passwd file
+
+ asprintf(&tempname, "%s.XXXXXX", path);
+
+ fd = mkstemp(tempname);
+ if (fd == -1) {
+ err(EXIT_FAILURE, "%s", tempname);
+ }
+ tfp = fdopen(fd, "w+");
+ if (tfp == NULL || fchmod(fd, S_IRUSR | S_IWUSR) != 0) {
+ int save = errno;
+ unlink(tempname);
+ errno = save;
+ err(EXIT_FAILURE, "%s", tempname);
+ }
+
+ while ((line = fgetln(fp, &len)) != NULL) {
+ struct passwd *pw = parse_user(line, len);
+
+ // if this is not the entry we're looking for or if parsing
+ // failed (likely a comment) then print the entry as is.
+ if (pw == NULL || strcmp(newpw->pw_name, pw->pw_name) != 0) {
+ fwrite(line, sizeof(char), len, tfp);
+ } else {
+ fprintf(tfp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
+ newpw->pw_name,
+ newpw->pw_passwd,
+ newpw->pw_uid,
+ newpw->pw_gid,
+ newpw->pw_class,
+ newpw->pw_change,
+ newpw->pw_expire,
+ newpw->pw_gecos,
+ newpw->pw_dir,
+ newpw->pw_shell);
+ }
+ }
+
+ // Move the temporary file into place.
+ if (fclose(tfp) != 0 || rename(tempname, path) != 0) {
+ int save = errno;
+ unlink(tempname);
+ errno = save;
+ err(EXIT_FAILURE, "%s", tempname);
+ }
+
+ free(tempname);
+}
+
+int
+file_passwd(char *uname, char *locn)
+{
+ char *ne, *oc, *nc;
+ int fd;
+ FILE *fp;
+ uid_t uid;
+ char *fname;
+ struct passwd *pw;
+ struct passwd newpw;
+
+ fname = _PASSWD_FILE;
+ if (locn != NULL) fname = locn;
+
+ fd = open(fname, O_RDONLY | O_EXLOCK);
+ if (fd == -1) {
+ err(EXIT_FAILURE, "%s", fname);
+ }
+
+ fp = fdopen(fd, "r");
+ if (fp == NULL) {
+ err(EXIT_FAILURE, "%s", fname);
+ }
+
+ pw = find_user(fp, uname);
+ if (pw == NULL) {
+ errx(EXIT_FAILURE, "user %s not found in %s", uname, fname);
+ }
+
+ uid = getuid();
+ if (uid != 0 && uid != pw->pw_uid) {
+ errno = EACCES;
+ err(EXIT_FAILURE, "%s", uname);
+ }
+
+ // Get the password
+ getpasswd(uname, (uid == 0), 5, 0, 0, pw->pw_passwd, &ne, &oc, &nc);
+
+ newpw.pw_name = strdup(pw->pw_name);
+ newpw.pw_passwd = strdup(ne);
+ newpw.pw_uid = pw->pw_uid;
+ newpw.pw_gid = pw->pw_gid;
+ newpw.pw_class = strdup(pw->pw_class);
+ newpw.pw_change = pw->pw_change;
+ newpw.pw_expire = pw->pw_expire;
+ newpw.pw_gecos = strdup(pw->pw_gecos);
+ newpw.pw_dir = strdup(pw->pw_dir);
+ newpw.pw_shell = strdup(pw->pw_shell);
+
+ // Rewrite the file
+ rewind(fp);
+ rewrite_file(fname, fp, &newpw);
+
+ fclose(fp);
+
+ return 0;
+}
--- /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@
+ */
+/*
+ * Portions Copyright (c) 1998 by Apple Computer, Inc.
+ * Portions Copyright (c) 1988 by Sun Microsystems, Inc.
+ * Portions Copyright (c) 1988 The Regents of the University of California.
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#include "passwd.h"
+
+#ifdef INFO_NIS
+
+/* update a user's password in NIS. This was based on the Sun implementation
+ * we used in NEXTSTEP, although I've added some stuff from OpenBSD. And
+ * it uses the API to support Rhapsody's proprietry infosystem switch.
+ * lukeh
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pwd.h>
+#include <netinet/in.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yppasswd.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <errno.h>
+
+extern int getrpcport(char *, int, int, int);
+extern void getpasswd(char *, int, int, int, int, char *, char **, char**, char **);
+
+static struct passwd *ypgetpwnam(char *name, char *domain);
+static struct passwd *interpret(struct passwd *pwent, char *line);
+
+int nis_passwd(char *uname, char *domain)
+{
+ int ans, port, ok = -1;
+ char *master;
+ char *ne; /* new encrypted password */
+ char *oc; /* old cleartext password */
+ char *nc; /* new cleartext password */
+ static struct yppasswd yppasswd;
+ struct passwd *pwd;
+ int uid;
+ struct timeval tv;
+ CLIENT *cl;
+
+ if (domain == NULL)
+ {
+ if (yp_get_default_domain(&domain) != 0)
+ {
+ (void)fprintf(stderr, "can't get domain\n");
+ exit(1);
+ }
+ }
+
+ if (yp_master(domain, "passwd.byname", &master) != 0)
+ {
+ (void)fprintf(stderr, "can't get master for passwd file\n");
+ exit(1);
+ }
+
+ port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE,
+ IPPROTO_UDP);
+ if (port == 0)
+ {
+ (void)fprintf(stderr, "%s is not running yppasswd daemon\n",
+ master);
+ exit(1);
+ }
+ if (port >= IPPORT_RESERVED)
+ {
+ (void)fprintf(stderr,
+ "yppasswd daemon is not running on privileged port\n");
+ exit(1);
+ }
+
+ pwd = ypgetpwnam(uname, domain);
+ if (pwd == NULL)
+ {
+ (void)fprintf(stderr, "user %s not found\n", uname);
+ exit(1);
+ }
+
+ uid = getuid();
+ if (uid != 0 && uid != pwd->pw_uid)
+ {
+ (void)fprintf(stderr, "you may only change your own password\n");
+ exit(1);
+ }
+
+ getpasswd(uname, 0, 5, 0, 0, pwd->pw_passwd, &ne, &oc, &nc);
+
+ yppasswd.oldpass = oc;
+ yppasswd.newpw.pw_name = pwd->pw_name;
+ yppasswd.newpw.pw_passwd = ne;
+ yppasswd.newpw.pw_uid = pwd->pw_uid;
+ yppasswd.newpw.pw_gid = pwd->pw_gid;
+ yppasswd.newpw.pw_gecos = pwd->pw_gecos;
+ yppasswd.newpw.pw_dir = pwd->pw_dir;
+ yppasswd.newpw.pw_shell = pwd->pw_shell;
+
+ cl = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp");
+ if (cl == NULL)
+ {
+ (void)fprintf(stderr, "could not contact yppasswdd on %s\n", master);
+ exit(1);
+ }
+ cl->cl_auth = authunix_create_default();
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+ ans = clnt_call(cl, YPPASSWDPROC_UPDATE,
+ (xdrproc_t)xdr_yppasswd, &yppasswd, (xdrproc_t)xdr_int, &ok, tv);
+
+ if (ans != 0)
+ {
+ clnt_perrno(ans);
+ (void)fprintf(stderr, "\n");
+ (void)fprintf(stderr, "couldn't change passwd\n");
+ exit(1);
+ }
+ if (ok != 0)
+ {
+ (void)fprintf(stderr, "couldn't change passwd\n");
+ exit(1);
+ }
+ return(0);
+}
+
+static char *
+pwskip(register char *p)
+{
+ while (*p && *p != ':' && *p != '\n')
+ ++p;
+ if (*p)
+ *p++ = 0;
+ return (p);
+}
+
+static struct passwd *
+interpret(struct passwd *pwent, char *line)
+{
+ register char *p = line;
+
+ pwent->pw_passwd = "*";
+ pwent->pw_uid = 0;
+ pwent->pw_gid = 0;
+ pwent->pw_gecos = "";
+ pwent->pw_dir = "";
+ pwent->pw_shell = "";
+#ifndef __SLICK__
+ pwent->pw_change = 0;
+ pwent->pw_expire = 0;
+ pwent->pw_class = "";
+#endif
+
+ /* line without colon separators is no good, so ignore it */
+ if(!strchr(p, ':'))
+ return(NULL);
+
+ pwent->pw_name = p;
+ p = pwskip(p);
+ pwent->pw_passwd = p;
+ p = pwskip(p);
+ pwent->pw_uid = (uid_t)strtoul(p, NULL, 10);
+ p = pwskip(p);
+ pwent->pw_gid = (gid_t)strtoul(p, NULL, 10);
+ p = pwskip(p);
+ pwent->pw_gecos = p;
+ p = pwskip(p);
+ pwent->pw_dir = p;
+ p = pwskip(p);
+ pwent->pw_shell = p;
+ while (*p && *p != '\n')
+ p++;
+ *p = '\0';
+ return (pwent);
+}
+
+
+static struct passwd *
+ypgetpwnam(char *nam, char *domain)
+{
+ static struct passwd pwent;
+ char *val;
+ int reason, vallen;
+ static char *__yplin = NULL;
+
+ reason = yp_match(domain, "passwd.byname", nam, (int)strlen(nam),
+ &val, &vallen);
+ switch(reason) {
+ case 0:
+ break;
+ default:
+ return (NULL);
+ break;
+ }
+ val[vallen] = '\0';
+ if (__yplin)
+ free(__yplin);
+ __yplin = (char *)malloc(vallen + 1);
+ strcpy(__yplin, val);
+ free(val);
+
+ return(interpret(&pwent, __yplin));
+}
+
+#endif /* INFO_NIS */
--- /dev/null
+/*
+ * Copyright (c) 1999-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@
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/sysctl.h>
+
+#include "passwd.h"
+
+#ifdef INFO_OPEN_DIRECTORY
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <OpenDirectory/OpenDirectory.h>
+#include <OpenDirectory/OpenDirectoryPriv.h>
+
+extern char* progname;
+int master_mode;
+
+static int
+cfprintf(FILE* file, const char* format, ...) {
+ char* cstr;
+ int result = 0;
+ va_list args;
+ va_start(args, format);
+ CFStringRef formatStr = CFStringCreateWithCStringNoCopy(NULL, format, kCFStringEncodingUTF8, kCFAllocatorNull);
+ if (formatStr) {
+ CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, formatStr, args);
+ if (str) {
+ size_t size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1;
+ va_end(args);
+ cstr = malloc(size);
+ if (cstr && CFStringGetCString(str, cstr, size, kCFStringEncodingUTF8)) {
+ result = fprintf(file, "%s", cstr);
+ free(cstr);
+ }
+ CFRelease(str);
+ }
+ CFRelease(formatStr);
+ }
+ return result;
+}
+
+static void
+show_error(CFErrorRef error) {
+ if (error) {
+ CFStringRef desc = CFErrorCopyDescription(error);
+ if (desc) {
+ cfprintf(stderr, "%s: %@", progname, desc);
+ CFRelease(desc);
+ }
+ desc = CFErrorCopyFailureReason(error);
+ if (desc) cfprintf(stderr, " %@", desc);
+
+ desc = CFErrorCopyRecoverySuggestion(error);
+ if (desc) cfprintf(stderr, " %@", desc);
+
+ fprintf(stderr, "\n");
+ }
+}
+
+int
+od_passwd(char* uname, char* locn, char* aname)
+{
+ int change_pass_on_self;
+ CFErrorRef error = NULL;
+ CFStringRef username = NULL;
+ CFStringRef location = NULL;
+ CFStringRef authname = NULL;
+ ODNodeRef node = NULL;
+ ODRecordRef rec = NULL;
+ CFStringRef oldpass = NULL;
+ CFStringRef newpass = NULL;
+
+ if (uname == NULL)
+ return -1;
+
+ /*
+ * If no explicit authorization name was specified (via -u)
+ * then default to the target user.
+ */
+ if (!aname) {
+ aname = strdup(uname);
+ }
+
+ master_mode = (getuid() == 0);
+ change_pass_on_self = (strcmp(aname, uname) == 0);
+
+ if (locn) {
+ location = CFStringCreateWithCString(NULL, locn, kCFStringEncodingUTF8);
+ }
+
+ if (aname) {
+ authname = CFStringCreateWithCString(NULL, aname, kCFStringEncodingUTF8);
+ }
+
+ if (uname) {
+ username = CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8);
+ if (!username) return -1;
+ }
+
+ /*
+ * Copy the record from the specified node, or perform a search.
+ */
+ if (location) {
+ node = ODNodeCreateWithName(NULL, kODSessionDefault, location, &error);
+ } else {
+ node = ODNodeCreateWithNodeType(NULL, kODSessionDefault, kODNodeTypeAuthentication, &error);
+ }
+
+ if (node) {
+ rec = ODNodeCopyRecord(node, kODRecordTypeUsers, username, NULL, &error );
+ CFRelease(node);
+ }
+
+ if (!rec) {
+ if (error) {
+ show_error(error);
+ } else {
+ fprintf(stderr, "%s: Unknown user name '%s'.\n", progname, uname);
+ }
+ return -1;
+ }
+
+ /*
+ * Get the actual location.
+ */
+ CFArrayRef values = NULL;
+ values = ODRecordCopyValues(rec, kODAttributeTypeMetaNodeLocation, &error);
+ location = (values && CFArrayGetCount(values) > 0) ? CFArrayGetValueAtIndex(values, 0) : location;
+
+ printf("Changing password for %s.\n", uname);
+
+ /*
+ * Prompt for password if not super-user, or if changing a remote node.
+ */
+ int needs_auth = (!master_mode || CFStringCompareWithOptions(location, CFSTR("/Local/"), CFRangeMake(0, 7), 0) != kCFCompareEqualTo);
+
+ if (needs_auth) {
+ char prompt[BUFSIZ];
+ if (change_pass_on_self) {
+ strlcpy(prompt, "Old password:", sizeof(prompt));
+ } else {
+ snprintf(prompt, sizeof(prompt), "Password for %s:", aname);
+ }
+ char *p = getpass( prompt );
+ if (p) {
+ oldpass = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8);
+ memset(p, 0, strlen(p));
+ }
+ }
+
+ for (;;) {
+ char *p = getpass("New password:");
+ if (p && strlen(p) > 0) {
+ newpass = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8);
+ memset(p, 0, strlen(p));
+ } else {
+ printf("Password unchanged.\n");
+ exit(0);
+ }
+
+ p = getpass("Retype new password:");
+ if (p) {
+ CFStringRef verify = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8);
+ if (!verify || !CFEqual(newpass, verify)) {
+ if (verify) CFRelease(verify);
+ printf("Mismatch; try again, EOF to quit.\n");
+ } else {
+ CFRelease(verify);
+ break;
+ }
+ }
+ }
+
+ ODRecordChangePassword(rec, oldpass, newpass, &error);
+
+ if (error) {
+ show_error(error);
+ exit(1);
+ }
+
+ if (oldpass) CFRelease(oldpass);
+ if (newpass) CFRelease(newpass);
+
+#if 0
+ if ( status != eDSNoErr ) {
+ switch( status )
+ {
+ case eDSAuthPasswordTooShort:
+ errMsgStr = "The new password is too short.";
+ break;
+
+ case eDSAuthPasswordTooLong:
+ errMsgStr = "The new password is too long.";
+ break;
+
+ case eDSAuthPasswordNeedsLetter:
+ errMsgStr = "The new password must contain a letter.";
+ break;
+
+ case eDSAuthPasswordNeedsDigit:
+ errMsgStr = "The new password must contain a number.";
+ break;
+
+ default:
+ errMsgStr = "Sorry";
+ }
+ fprintf(stderr, "%s\n", errMsgStr);
+ exit(1);
+#endif
+ return 0;
+}
+
+#endif /* INFO_OPEN_DIRECTORY */
--- /dev/null
+/*
+ * Copyright (c) 1999-2008 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@
+ */
+#include <stdio.h>
+#include "passwd.h"
+
+#ifdef INFO_PAM
+
+#include <security/pam_appl.h>
+#include <security/openpam.h> /* for openpam_ttyconv() */
+
+extern char* progname;
+static pam_handle_t *pamh;
+static struct pam_conv pamc;
+
+int
+pam_passwd(char* uname)
+{
+ int retval = PAM_SUCCESS;
+
+ /* Initialize PAM. */
+ pamc.conv = &openpam_ttyconv;
+ pam_start(progname, uname, &pamc, &pamh);
+
+ /* Authenticate. */
+ if (PAM_SUCCESS != (retval = pam_authenticate(pamh, 0)))
+ goto pamerr;
+
+ /* Authorize. */
+ if (PAM_SUCCESS != (retval = pam_acct_mgmt(pamh, 0)) && PAM_NEW_AUTHTOK_REQD != retval)
+ goto pamerr;
+
+ printf("Changing password for %s.\n", uname);
+
+ /* Change the password. */
+ if (PAM_SUCCESS != (retval = pam_chauthtok(pamh, 0)))
+ goto pamerr;
+
+ /* Set the credentials. */
+ if (PAM_SUCCESS != (retval = pam_setcred(pamh, PAM_ESTABLISH_CRED)))
+ goto pamerr;
+
+ /* Open the session. */
+ if (PAM_SUCCESS != (retval = pam_open_session(pamh, 0)))
+ goto pamerr;
+
+ /* Close the session. */
+ if (PAM_SUCCESS != (retval = pam_close_session(pamh, 0)))
+ goto pamerr;
+
+pamerr:
+ /* Print an error, if needed. */
+ if (PAM_SUCCESS != retval)
+ fprintf(stderr, "%s: %s\n", progname, pam_strerror(pamh, retval));
+
+ /* Terminate PAM. */
+ pam_end(pamh, retval);
+ return retval;
+}
+
+#endif /* INFO_PAM */
--- /dev/null
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)passwd.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd August 18, 2008
+.Dt PASSWD 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm passwd
+.Nd modify a user's password
+.Sh SYNOPSIS
+.Nm passwd
+.Op Fl i Ar infosystem Op Fl l Ar location
+.Op Fl u Ar authname
+.Op Ar user
+.Sh DESCRIPTION
+The
+.Nm
+utility changes the user's password.
+If the user is not the super-user,
+.Nm
+first prompts for the current password and will not continue unless the correct
+password is entered.
+.Pp
+When entering the new password, the characters entered do not echo, in order to
+avoid the password being seen by a passer-by.
+The
+.Nm
+utility prompts for the new password twice in order to detect typing errors.
+.Pp
+The new password should be at least six characters long
+and not purely alphabetic.
+Its total length should be less than
+.Dv _PASSWORD_LEN
+(currently 128 characters),
+although some directory systems allow longer passwords.
+Numbers, upper
+case letters, and meta characters are encouraged.
+.Pp
+Once the password has been verified,
+.Nm
+communicates the new password to the directory system.
+.Bl -tag -width flag
+.It Fl i Ar infosystem
+This option specifies where the password update should be applied.
+Under Mac OS X 10.5 and later, supported directory systems are:
+.Bl -tag -width flag
+.It Ar PAM
+(default) Pluggable Authentication Modules.
+.It Ar opendirectory
+A system conforming to Open Directory APIs and supporting updates
+(including LDAP, etc).
+If no -l option is specified, the search node is used.
+.It Ar file
+The local flat-files (included for legacy configurations).
+.It Ar nis
+A remote NIS server containing the user's password.
+.El
+.It Fl l Ar location
+This option causes the password to be updated in the given location
+of the chosen directory system.
+.Bl -tag -width flag
+.It for file,
+location may be a file name (/etc/master.passwd is the default)
+.It for nis,
+location may be a NIS domainname
+.It for opendirectory,
+location may be a directory node name
+.It for PAM,
+location is not used
+.El
+.It Fl u Ar authname
+This option specifies the user name to use when authenticating to
+the directory node.
+.It Ar user
+This optional argument specifies the user account whose password will be
+changed. This account's current password may be required, even when run as the
+super-user, depending on the directory system.
+.El
+.Sh FILES
+.Bl -tag -width /etc/master.passwd -compact
+.It Pa /etc/master.passwd
+The user database
+.It Pa /etc/passwd
+A Version 7 format password file
+.It Pa /etc/passwd.XXXXXX
+Temporary copy of the password file
+.El
+.Sh SEE ALSO
+.Xr chpass 1 ,
+.Xr login 1 ,
+.Xr dscl 1 ,
+.Xr passwd 5 ,
+.Xr pwd_mkdb 8 ,
+.Xr vipw 8
+.Rs
+.%A Robert Morris
+.%A Ken Thompson
+.%T "UNIX password security"
+.Re
+.Sh HISTORY
+A
+.Nm passwd
+command appeared in
+.At v6 .
--- /dev/null
+/*
+ * Copyright (c) 1999-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@
+ */
+#include <TargetConditionals.h>
+
+#define _PASSWD_FILE "/etc/master.passwd"
+
+#include <stdio.h>
+#include <errno.h>
+#include <pwd.h>
+#include <libc.h>
+#include <ctype.h>
+#include <string.h>
+#include "passwd.h"
+
+#ifdef __SLICK__
+#define _PASSWORD_LEN 8
+#endif
+
+char* progname = "passwd";
+
+static char *saltchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
+
+void
+getpasswd(char *name, int isroot, int minlen, int mixcase, int nonalpha,
+ char *old_pw, char **new_pw, char **old_clear, char **new_clear)
+{
+ int i, tries, pw_ok, upper, lower, alpha, notalpha;
+ size_t len;
+ int isNull;
+ char *p;
+ static char obuf[_PASSWORD_LEN+1];
+ static char nbuf[_PASSWORD_LEN+1];
+ char salt[9];
+
+ printf("Changing password for %s.\n", name);
+
+ p = "";
+ isNull = 0;
+ if (old_pw == NULL) isNull = 1;
+ if ((isNull == 0) && (old_pw[0] == '\0')) isNull = 1;
+ if ((isroot == 0) && (isNull == 0))
+ {
+ p = getpass("Old password:");
+ if (strcmp(crypt(p, old_pw), old_pw))
+ {
+ errno = EACCES;
+ fprintf(stderr, "Sorry\n");
+ exit(1);
+ }
+ }
+ //strcpy(obuf, p);
+ snprintf( obuf, sizeof(obuf), "%s", p );
+
+ tries = 0;
+ nbuf[0] = '\0';
+ for (;;)
+ {
+ p = getpass("New password:");
+ if (!*p)
+ {
+ printf("Password unchanged.\n");
+ exit(0);
+ }
+
+ tries++;
+ len = strlen(p);
+ upper = 0;
+ lower = 0;
+ alpha = 0;
+ notalpha = 0;
+ for (i = 0; i < len; i++)
+ {
+ if (isupper(p[i])) upper++;
+ if (islower(p[i])) lower++;
+ if (isalpha(p[i])) alpha++;
+ else notalpha++;
+ }
+
+
+ pw_ok = 1;
+ if (len < minlen) pw_ok = 0;
+ if ((mixcase == 1) && ((upper == 0) || (lower == 0))) pw_ok = 0;
+ if ((nonalpha == 1) && (notalpha == 0)) pw_ok = 0;
+
+ /*
+ * An insistent root may override security options.
+ */
+ if ((isroot == 1) && (tries > 2)) pw_ok = 1;
+
+ /*
+ * A very insistent user may override security options.
+ */
+ if (tries > 4) pw_ok = 1;
+
+ if (pw_ok == 0)
+ {
+ if (len < minlen)
+ printf("Password must be at least %d characters long.\n", minlen);
+ if ((mixcase == 1) && ((upper == 0) || (lower == 0)))
+ printf("Password must contain both upper and lower case characters.\n");
+ if ((nonalpha == 1) && (notalpha == 0))
+ printf("Password must contain non-alphabetic characters.\n");
+ continue;
+ }
+
+ //strcpy(nbuf, p);
+ snprintf( nbuf, sizeof(nbuf), "%s", p );
+
+ if (!strcmp(nbuf, getpass("Retype new password:"))) break;
+
+ printf("Mismatch; try again, EOF to quit.\n");
+ }
+
+ /*
+ * Create a random salt
+ */
+ srandom((int)time((time_t *)NULL));
+ salt[0] = saltchars[random() % strlen(saltchars)];
+ salt[1] = saltchars[random() % strlen(saltchars)];
+ salt[2] = '\0';
+ *new_pw = crypt(nbuf, salt);
+
+ *old_clear = obuf;
+ *new_clear = nbuf;
+ return;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-i infosystem] -l location]] [-u authname] [name]\n", progname);
+ fprintf(stderr, " infosystem:\n");
+ fprintf(stderr, " file\n");
+ fprintf(stderr, " NIS\n");
+ fprintf(stderr, " OpenDirectory\n");
+ fprintf(stderr, " PAM\n");
+ fprintf(stderr, " location (for infosystem):\n");
+ fprintf(stderr, " file location is path to file (default is %s)\n", _PASSWD_FILE);
+ fprintf(stderr, " NIS location is NIS domain name\n");
+ fprintf(stderr, " OpenDirectory location is directory node name\n");
+ fprintf(stderr, " PAM location is not used\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ char* user = NULL;
+ char* locn = NULL;
+ char* auth = NULL;
+ int infosystem, ch;
+ int free_user = 0;
+
+#ifdef INFO_PAM
+ infosystem = INFO_PAM;
+#else
+#ifdef INFO_OPEN_DIRECTORY
+ infosystem = INFO_OPEN_DIRECTORY;
+#else
+ infosystem = INFO_FILE;
+#endif
+#endif
+
+#ifdef INFO_OPEN_DIRECTORY
+ /* PAM is the default infosystem, but we still want to use OpenDirectory directly when run by root */
+ if (0 == getuid())
+ infosystem = INFO_OPEN_DIRECTORY;
+#endif
+
+ while ((ch = getopt(argc, argv, "i:l:u:")) != -1)
+ switch(ch) {
+ case 'i':
+ if (!strcasecmp(optarg, "file")) {
+ infosystem = INFO_FILE;
+#ifdef INFO_NIS
+ } else if (!strcasecmp(optarg, "NIS")) {
+ infosystem = INFO_NIS;
+ } else if (!strcasecmp(optarg, "YP")) {
+ infosystem = INFO_NIS;
+#endif
+#ifdef INFO_OPEN_DIRECTORY
+ } else if (!strcasecmp(optarg, "opendirectory")) {
+ infosystem = INFO_OPEN_DIRECTORY;
+#endif
+#ifdef INFO_PAM
+ } else if (!strcasecmp(optarg, "PAM")) {
+ infosystem = INFO_PAM;
+#endif
+ } else {
+ fprintf(stderr, "%s: Unknown info system \'%s\'.\n",
+ progname, optarg);
+ usage();
+ }
+ break;
+ case 'l':
+ locn = optarg;
+ break;
+ case 'u':
+ auth = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 1) {
+ usage();
+ } else if (argc == 1) {
+ user = argv[0];
+ }
+
+#ifdef INFO_PAM
+ if (INFO_PAM == infosystem && NULL != locn)
+ usage();
+#endif
+
+ if (user == NULL)
+ {
+ /*
+ * Verify that the login name exists.
+ * lukeh 24 Dec 1997
+ */
+
+ /* getlogin() is the wrong thing to use here because it returns the wrong user after su */
+ /* sns 5 Jan 2005 */
+
+ struct passwd * userRec = getpwuid(getuid());
+ if (userRec != NULL && userRec->pw_name != NULL) {
+ /* global static mem is volatile; must strdup */
+ user = strdup(userRec->pw_name);
+ free_user = 1;
+ }
+
+ if (user == NULL)
+ {
+ fprintf(stderr, "you don't have a login name\n");
+ exit(1);
+ }
+ }
+
+ switch (infosystem)
+ {
+ case INFO_FILE:
+ file_passwd(user, locn);
+ break;
+#ifdef INFO_NIS
+ case INFO_NIS:
+ nis_passwd(user, locn);
+ break;
+#endif
+#ifdef INFO_OPEN_DIRECTORY
+ case INFO_OPEN_DIRECTORY:
+ od_passwd(user, locn, auth);
+ break;
+#endif
+#ifdef INFO_PAM
+ case INFO_PAM:
+ pam_passwd(user);
+ break;
+#endif
+ }
+
+ if (free_user == 1)
+ free(user);
+
+ exit(0);
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2011 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 <TargetConditionals.h>
+
+#define INFO_FILE 1
+#if !TARGET_OS_EMBEDDED
+#define INFO_NIS 2
+#define INFO_OPEN_DIRECTORY 3
+#define INFO_PAM 4
+#endif
+
+extern int file_passwd(char *, char *);
+extern int nis_passwd(char *, char *);
+#ifdef INFO_OPEN_DIRECTORY
+extern int od_passwd(char *, char *, char*);
+#endif
+#ifdef INFO_PAM
+extern int pam_passwd(char *);
+#endif
+
+void
+getpasswd(char *name, int isroot, int minlen, int mixcase, int nonalpha,
+ char *old_pw, char **new_pw, char **old_clear, char **new_clear);
--- /dev/null
+# passwd: auth account
+auth required pam_permit.so
+account required pam_opendirectory.so
+password required pam_opendirectory.so
+session required pam_permit.so
--- /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;
+}
--- /dev/null
+/* $OpenBSD: passwd.c,v 1.42 2003/06/26 16:34:42 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994, 1995
+ * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$OpenBSD: passwd.c,v 1.42 2003/06/26 16:34:42 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <signal.h>
+#include <limits.h>
+
+#include "util.h"
+
+int
+pw_scan(char *bp, struct passwd *pw, int *flags)
+{
+ u_long id;
+ int root;
+ char *p, *sh, *p2;
+
+ if (flags != (int *)NULL)
+ *flags = 0;
+
+#ifdef __APPLE__
+ if (bp[0] == '#') {
+ pw->pw_name = NULL;
+ return(1);
+ }
+#endif
+
+ if (!(p = strsep(&bp, ":")) || *p == '\0') /* login */
+ goto fmt;
+ pw->pw_name = p;
+ root = !strcmp(pw->pw_name, "root");
+
+ if (!(pw->pw_passwd = strsep(&bp, ":"))) /* passwd */
+ goto fmt;
+
+ if (!(p = strsep(&bp, ":"))) /* uid */
+ goto fmt;
+ id = strtoul(p, &p2, 10);
+ if (root && id) {
+ warnx("root uid should be 0");
+ return (0);
+ }
+ if (*p2 != '\0') {
+ warnx("illegal uid field");
+ return (0);
+ }
+#ifndef __APPLE__
+ /* Apple's UID_MAX is too small (sizeof signed) 3091256 */
+ if (id > UID_MAX) {
+ /* errno is set to ERANGE by strtoul(3) */
+ warnx("uid greater than %u", UID_MAX-1);
+ return (0);
+ }
+#endif
+ pw->pw_uid = (uid_t)id;
+ if ((*p == '\0') && (flags != (int *)NULL))
+ *flags |= _PASSWORD_NOUID;
+
+ if (!(p = strsep(&bp, ":"))) /* gid */
+ goto fmt;
+ id = strtoul(p, &p2, 10);
+ if (*p2 != '\0') {
+ warnx("illegal gid field");
+ return (0);
+ }
+#ifndef __APPLE__
+ /* Apple's UID_MAX is too small (sizeof signed) 3091256 */
+ if (id > UID_MAX) {
+ /* errno is set to ERANGE by strtoul(3) */
+ warnx("gid greater than %u", UID_MAX-1);
+ return (0);
+ }
+#endif
+ pw->pw_gid = (gid_t)id;
+ if ((*p == '\0') && (flags != (int *)NULL))
+ *flags |= _PASSWORD_NOGID;
+
+ pw->pw_class = strsep(&bp, ":"); /* class */
+ if (!(p = strsep(&bp, ":"))) /* change */
+ goto fmt;
+ pw->pw_change = atol(p);
+ if ((*p == '\0') && (flags != (int *)NULL))
+ *flags |= _PASSWORD_NOCHG;
+ if (!(p = strsep(&bp, ":"))) /* expire */
+ goto fmt;
+ pw->pw_expire = atol(p);
+ if ((*p == '\0') && (flags != (int *)NULL))
+ *flags |= _PASSWORD_NOEXP;
+ pw->pw_gecos = strsep(&bp, ":"); /* gecos */
+ pw->pw_dir = strsep(&bp, ":"); /* directory */
+ if (!(pw->pw_shell = strsep(&bp, ":"))) /* shell */
+ goto fmt;
+
+ p = pw->pw_shell;
+ if (root && *p) { /* empty == /bin/sh */
+ for (setusershell();;) {
+ if (!(sh = getusershell())) {
+ warnx("warning, unknown root shell");
+ break;
+ }
+ if (!strcmp(p, sh))
+ break;
+ }
+ endusershell();
+ }
+
+ if ((p = strsep(&bp, ":"))) { /* too many */
+fmt: warnx("corrupted entry");
+ return (0);
+ }
+
+ return (1);
+}
--- /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) 1994
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * @(#)pw_scan.h 8.1 (Berkeley) 4/1/94
+ */
+
+extern int pw_scan __P((char *, struct passwd *, int *));
--- /dev/null
+.\" $OpenBSD: pwd_mkdb.8,v 1.17 2003/06/12 12:59:52 jmc Exp $
+.\"
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" from: @(#)pwd_mkdb.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt PWD_MKDB 8
+.Os
+.Sh NAME
+.Nm pwd_mkdb
+.Nd generate the password databases
+.Sh SYNOPSIS
+.Nm pwd_mkdb
+.Op Fl c
+.Op Fl p | Fl s
+.Op Fl d Ar directory
+.Op Fl u Ar username
+.Ar file
+.Sh DESCRIPTION
+.Nm pwd_mkdb
+creates
+.Xr db 3
+style secure and insecure databases for the specified file.
+These databases are then installed into
+.Pa /etc/spwd.db
+and
+.Pa /etc/pwd.db ,
+respectively.
+The file is installed into
+.Pa /etc/master.passwd .
+The file must be in the correct format (see
+.Xr passwd 5 ) .
+It is important to note that the format used in this system is
+different from the historic Version 7 style format.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.\" ==========
+.It Fl c
+Check if the password file is in the correct format.
+Do not change, add, or remove any files.
+.\" ==========
+.It Fl d Ar directory
+Operate in a base directory other than the default of
+.Pa /etc .
+All absolute paths (including
+.Ar file )
+will be made relative to
+.Ar directory .
+Any directories specified as a part of
+.Ar file
+will be stripped off.
+This option is used to create password databases in directories
+other than
+.Pa etc ;
+for instance in a
+.Xr chroot 8
+jail.
+.\" ==========
+.It Fl p
+Create a Version 7 style password file and install it into
+.Pa /etc/passwd .
+.\" ==========
+.It Fl s
+Only update the secure version of the database.
+This is most commonly used in conjunction with the
+.Fl u
+flag during a password change.
+Because the insecure database doesn't contain the password there
+is no reason to update it if the only change is in the password field.
+Cannot be used in conjunction with the
+.Fl p
+flag.
+.\" ==========
+.It Fl u Ar username
+Only update the record for the specified user.
+Utilities that operate on a single user can use this option to avoid the
+overhead of rebuilding the entire database.
+This option must never be used if the line number of the user's record in
+.Pa /etc/master.passwd
+has changed.
+.\" ==========
+.It Ar file
+The absolute path to a file in
+.Ar master.passwd
+format, as described in
+.Xr passwd 5 .
+.El
+.Pp
+The two databases differ in that the secure version contains the user's
+encrypted password and the insecure version has an asterisk
+.Pq Sq \&* .
+.Pp
+The databases are used by the C library password routines (see
+.Xr getpwent 3 ) .
+.Pp
+.Nm pwd_mkdb
+exits zero on success, non-zero on failure.
+.Sh FILES
+.Bl -tag -width /etc/master.passwd -compact
+.It Pa /etc/master.passwd
+current password file
+.It Pa /etc/passwd
+a Version 7 format password file
+.It Pa /etc/pwd.db
+insecure password database file
+.It Pa /etc/pwd.db.tmp
+temporary file
+.It Pa /etc/spwd.db
+secure password database file
+.It Pa /etc/spwd.db.tmp
+temporary file
+.El
+.Sh SEE ALSO
+.Xr chpass 1 ,
+.Xr passwd 1 ,
+.Xr db 3 ,
+.Xr getpwent 3 ,
+.Xr passwd 5 ,
+.Xr vipw 8
+.Sh STANDARDS
+Previous versions of the system had a program similar to
+.Nm pwd_mkdb ,
+.Xr mkpasswd ,
+which built
+.Xr dbm 3
+style databases for the password file but depended on the calling programs
+to install them.
+The program was renamed in order that previous users of the program
+not be surprised by the changes in functionality.
+.Sh BUGS
+Because of the necessity for atomic update of the password files,
+.Nm pwd_mkdb
+uses
+.Xr rename 2
+to install them.
+This, however, requires that the file specified on the command line live
+on the same file system as the
+.Pa /etc
+directory.
+.Pp
+There are the obvious races with multiple people running
+.Nm pwd_mkdb
+on different password files at the same time.
+The front-ends to
+.Nm pwd_mkdb ,
+.Xr chpass 1 ,
+.Xr passwd 1 ,
+and
+.Xr vipw 8
+handle the locking necessary to avoid this problem.
--- /dev/null
+/* $OpenBSD: pwd_mkdb.c,v 1.36 2003/06/08 21:14:55 millert Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Portions Copyright (c) 1994, Jason Downs. All rights reserved.
+ * Portions Copyright (c) 1998, Todd C. Miller. 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. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static const char sccsid[] = "from: @(#)pwd_mkdb.c 8.5 (Berkeley) 4/20/94";
+#else
+__unused static const char rcsid[] = "$OpenBSD: pwd_mkdb.c,v 1.36 2003/06/08 21:14:55 millert Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <db.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <limits.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <util.h>
+#include <sys/param.h>
+#include "pw_scan.h"
+
+#define INSECURE 1
+#define SECURE 2
+#define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
+#define PERM_SECURE (S_IRUSR|S_IWUSR)
+
+#define FILE_SECURE 0x01
+#define FILE_INSECURE 0x02
+#define FILE_ORIG 0x04
+
+#define SHADOW_GROUP "wheel"
+
+HASHINFO openinfo = {
+ 4096, /* bsize */
+ 32, /* ffactor */
+ 256, /* nelem */
+ 2048 * 1024, /* cachesize */
+ NULL, /* hash() */
+ 0 /* lorder */
+};
+
+static char *pname; /* password file name */
+static char *basedir; /* dir holding master.passwd */
+static int clean; /* what to remove on cleanup */
+static int hasyp; /* are we running YP? */
+
+void cleanup(void);
+void error(char *);
+void errorx(char *);
+void cp(char *, char *, mode_t);
+void mv(char *, char *);
+int scan(FILE *, struct passwd *, int *);
+void usage(void);
+char *changedir(char *path, char *dir);
+void db_store(FILE *, FILE *, DB *, DB *,struct passwd *, int, char *, uid_t);
+
+int
+main(int argc, char **argv)
+{
+ DB *dp, *edp;
+ DBT data, key;
+ FILE *fp, *oldfp = NULL;
+ struct stat st;
+ struct passwd pwd;
+ struct group *grp;
+ sigset_t set;
+ uid_t olduid;
+ gid_t shadow;
+ int ch, tfd, makeold, secureonly, flags, checkonly;
+ char *username, buf[MAX(MAXPATHLEN, LINE_MAX * 2)];
+
+ flags = checkonly = makeold = secureonly = 0;
+ username = NULL;
+ while ((ch = getopt(argc, argv, "cd:psu:v")) != -1)
+ switch (ch) {
+ case 'c': /* verify only */
+ checkonly = 1;
+ break;
+ case 'd':
+ basedir = optarg;
+ if (strlen(basedir) > MAXPATHLEN - 40)
+ errx(1, "basedir too long");
+ break;
+ case 'p': /* create V7 "file.orig" */
+ makeold = 1;
+ break;
+ case 's': /* only update spwd.db */
+ secureonly = 1;
+ break;
+ case 'u': /* only update this record */
+ username = optarg;
+ if (strlen(username) > _PW_NAME_LEN)
+ errx(1, "username too long");
+ break;
+ case 'v': /* backward compatible */
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1 || (makeold && secureonly) ||
+ (username && (*username == '+' || *username == '-')))
+ usage();
+
+ if ((grp = getgrnam(SHADOW_GROUP)) == NULL)
+ errx(1, "cannot find `%s' in the group database, aborting",
+ SHADOW_GROUP);
+ shadow = grp->gr_gid;
+
+ /*
+ * This could be changed to allow the user to interrupt.
+ * Probably not worth the effort.
+ */
+ sigemptyset(&set);
+ sigaddset(&set, SIGTSTP);
+ sigaddset(&set, SIGHUP);
+ sigaddset(&set, SIGINT);
+ sigaddset(&set, SIGQUIT);
+ sigaddset(&set, SIGTERM);
+ (void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL);
+
+ /* We don't care what the user wants. */
+ (void)umask(0);
+
+ if (**argv != '/' && basedir == NULL)
+ errx(1, "%s must be specified as an absolute path", *argv);
+
+ if ((pname = strdup(changedir(*argv, basedir))) == NULL)
+ err(1, NULL);
+ /* Open the original password file */
+ if (!(fp = fopen(pname, "r")))
+ error(pname);
+
+ /* Check only if password database is valid */
+ if (checkonly) {
+ u_int cnt;
+
+ for (cnt = 1; scan(fp, &pwd, &flags); ++cnt)
+ ;
+ exit(0);
+ }
+
+ if (fstat(fileno(fp), &st) == -1)
+ error(pname);
+
+ /* Tweak openinfo values for large passwd files. */
+ if (st.st_size > (off_t)100*1024)
+ openinfo.cachesize = MIN(st.st_size * 20, (off_t)12*1024*1024);
+ if (st.st_size / 128 > openinfo.nelem)
+ openinfo.nelem = st.st_size / 128;
+
+ /* If only updating a single record, stash the old uid */
+ if (username) {
+ dp = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
+ if (dp == NULL)
+ error(_PATH_MP_DB);
+ buf[0] = _PW_KEYBYNAME;
+ strlcpy(buf + 1, username, sizeof(buf) - 1);
+ key.data = (u_char *)buf;
+ key.size = strlen(buf + 1) + 1;
+ if ((dp->get)(dp, &key, &data, 0) == 0) {
+ char *p = (char *)data.data;
+ /* Skip to uid field */
+ while (*p++ != '\0')
+ ;
+ while (*p++ != '\0')
+ ;
+ memcpy(&olduid, p, sizeof(olduid));
+ } else
+ olduid = UID_MAX;
+ (dp->close)(dp);
+ }
+
+ /* Open the temporary encrypted password database. */
+ (void)snprintf(buf, sizeof(buf), "%s.tmp",
+ changedir(_PATH_SMP_DB, basedir));
+ if (username) {
+ cp(changedir(_PATH_SMP_DB, basedir), buf, PERM_SECURE);
+ edp = dbopen(buf,
+ O_RDWR, PERM_SECURE, DB_HASH, &openinfo);
+ } else {
+ edp = dbopen(buf,
+ O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
+ }
+ if (!edp)
+ error(buf);
+ if (fchown(edp->fd(edp), (uid_t)-1, shadow) != 0)
+ warn("%s: unable to set group to %s", _PATH_SMP_DB,
+ SHADOW_GROUP);
+ else if (fchmod(edp->fd(edp), PERM_SECURE|S_IRGRP) != 0)
+ warn("%s: unable to make group readable", _PATH_SMP_DB);
+ clean |= FILE_SECURE;
+
+ /* Open the temporary insecure password database. */
+ if (!secureonly) {
+ (void)snprintf(buf, sizeof(buf), "%s.tmp",
+ changedir(_PATH_MP_DB, basedir));
+ if (username) {
+ cp(changedir(_PATH_MP_DB, basedir), buf, PERM_INSECURE);
+ dp = dbopen(buf, O_RDWR, PERM_INSECURE, DB_HASH,
+ &openinfo);
+ } else {
+ dp = dbopen(buf, O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE,
+ DB_HASH, &openinfo);
+ }
+ if (dp == NULL)
+ error(buf);
+ clean |= FILE_INSECURE;
+ } else
+ dp = NULL;
+
+ /*
+ * Open file for old password file. Minor trickiness -- don't want to
+ * chance the file already existing, since someone (stupidly) might
+ * still be using this for permission checking. So, open it first and
+ * fdopen the resulting fd. The resulting file should be readable by
+ * everyone.
+ */
+ if (makeold) {
+ (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
+ if ((tfd = open(buf,
+ O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0)
+ error(buf);
+ if ((oldfp = fdopen(tfd, "w")) == NULL)
+ error(buf);
+ clean |= FILE_ORIG;
+ }
+
+ /*
+ * The databases actually contain three copies of the original data.
+ * Each password file entry is converted into a rough approximation
+ * of a ``struct passwd'', with the strings placed inline. This
+ * object is then stored as the data for three separate keys. The
+ * first key * is the pw_name field prepended by the _PW_KEYBYNAME
+ * character. The second key is the pw_uid field prepended by the
+ * _PW_KEYBYUID character. The third key is the line number in the
+ * original file prepended by the _PW_KEYBYNUM character. (The special
+ * characters are prepended to ensure that the keys do not collide.)
+ *
+ * If we see something go by that looks like YP, we save a special
+ * pointer record, which if YP is enabled in the C lib, will speed
+ * things up.
+ */
+
+ /*
+ * Write the .db files.
+ * We do this three times, one per key type (for getpw{nam,uid,ent}).
+ * The first time through we also check for YP, issue warnings
+ * and save the V7 format passwd file if necessary.
+ */
+ db_store(fp, oldfp, edp, dp, &pwd, _PW_KEYBYNAME, username, olduid);
+ db_store(fp, oldfp, edp, dp, &pwd, _PW_KEYBYUID, username, olduid);
+ db_store(fp, oldfp, edp, dp, &pwd, _PW_KEYBYNUM, username, olduid);
+
+ /* Store YP token, if needed. */
+ if (hasyp && !username) {
+ key.data = (u_char *)_PW_YPTOKEN;
+ key.size = strlen(_PW_YPTOKEN);
+ data.data = (u_char *)NULL;
+ data.size = 0;
+
+ if ((edp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
+ error("put");
+
+ if (dp && (dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
+ error("put");
+ }
+
+ if ((edp->close)(edp))
+ error("close edp");
+ if (dp && (dp->close)(dp))
+ error("close dp");
+ if (makeold) {
+ if (fclose(oldfp) == EOF)
+ error("close old");
+ }
+
+ /* Set master.passwd permissions, in case caller forgot. */
+ (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
+ if (fclose(fp) != 0)
+ error("fclose");
+
+ /* Install as the real password files. */
+ if (!secureonly) {
+ (void)snprintf(buf, sizeof(buf), "%s.tmp",
+ changedir(_PATH_MP_DB, basedir));
+ mv(buf, changedir(_PATH_MP_DB, basedir));
+ }
+ (void)snprintf(buf, sizeof(buf), "%s.tmp",
+ changedir(_PATH_SMP_DB, basedir));
+ mv(buf, changedir(_PATH_SMP_DB, basedir));
+ if (makeold) {
+ (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
+ mv(buf, changedir(_PATH_PASSWD, basedir));
+ }
+
+ /*
+ * Move the master password LAST -- chpass(1), passwd(1) and vipw(8)
+ * all use flock(2) on it to block other incarnations of themselves.
+ * The rename means that everything is unlocked, as the original file
+ * can no longer be accessed.
+ */
+ mv(pname, changedir(_PATH_MASTERPASSWD, basedir));
+ exit(0);
+}
+
+int
+scan(FILE *fp, struct passwd *pw, int *flags)
+{
+ static int lcnt;
+ static char line[LINE_MAX];
+ char *p;
+
+ if (fgets(line, sizeof(line), fp) == NULL)
+ return (0);
+ ++lcnt;
+ /*
+ * ``... if I swallow anything evil, put your fingers down my
+ * throat...''
+ * -- The Who
+ */
+ p = line;
+ if (*p != '\0' && *(p += strlen(line) - 1) != '\n') {
+ warnx("line too long");
+ goto fmt;
+ }
+ *p = '\0';
+ *flags = 0;
+ if (!pw_scan(line, pw, flags)) {
+ warnx("at line #%d", lcnt);
+fmt: errno = EFTYPE; /* XXX */
+ error(pname);
+ }
+
+ return (1);
+}
+
+void
+cp(char *from, char *to, mode_t mode)
+{
+ static char buf[MAXBSIZE];
+ int from_fd, rcount, to_fd, wcount;
+
+ if ((from_fd = open(from, O_RDONLY, 0)) < 0)
+ error(from);
+ if ((to_fd = open(to, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0)
+ error(to);
+ while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
+ wcount = write(to_fd, buf, rcount);
+ if (rcount != wcount || wcount == -1) {
+ int sverrno = errno;
+
+ (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
+ errno = sverrno;
+ error(buf);
+ }
+ }
+ if (rcount < 0) {
+ int sverrno = errno;
+
+ (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
+ errno = sverrno;
+ error(buf);
+ }
+}
+
+void
+mv(from, to)
+ char *from, *to;
+{
+ char buf[MAXPATHLEN * 2];
+
+ if (rename(from, to)) {
+ int sverrno = errno;
+
+ (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
+ errno = sverrno;
+ error(buf);
+ }
+}
+
+void
+error(name)
+ char *name;
+{
+
+ warn("%s", name);
+ cleanup();
+ exit(1);
+}
+
+void
+errorx(name)
+ char *name;
+{
+
+ warnx("%s", name);
+ cleanup();
+ exit(1);
+}
+
+void
+cleanup()
+{
+ char buf[MAXPATHLEN];
+
+ if (clean & FILE_ORIG) {
+ (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
+ (void)unlink(buf);
+ }
+ if (clean & FILE_SECURE) {
+ (void)snprintf(buf, sizeof(buf), "%s.tmp",
+ changedir(_PATH_SMP_DB, basedir));
+ (void)unlink(buf);
+ }
+ if (clean & FILE_INSECURE) {
+ (void)snprintf(buf, sizeof(buf), "%s.tmp",
+ changedir(_PATH_MP_DB, basedir));
+ (void)unlink(buf);
+ }
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr,
+ "usage: pwd_mkdb [-c] [-p | -s] [-d basedir] [-u username] file\n");
+ exit(1);
+}
+
+char *
+changedir(char *path, char *dir)
+{
+ static char fixed[MAXPATHLEN];
+ char *p;
+
+ if (!dir)
+ return (path);
+
+ if ((p = strrchr(path, '/')) != NULL)
+ path = p + 1;
+ snprintf(fixed, sizeof(fixed), "%s/%s", dir, path);
+ return (fixed);
+}
+
+void
+db_store(FILE *fp, FILE *oldfp, DB *edp, DB *dp, struct passwd *pw,
+ int keytype, char *username, uid_t olduid)
+{
+ int flags = 0;
+ int dbmode, found = 0;
+ u_int cnt;
+ char *p, *t, buf[LINE_MAX * 2], tbuf[1024];
+ DBT data, key;
+ size_t len;
+ static int firsttime = 1;
+
+ /* If given a username just add that record to the existing db. */
+ dbmode = username ? 0 : R_NOOVERWRITE;
+
+ rewind(fp);
+ data.data = (u_char *)buf;
+ key.data = (u_char *)tbuf;
+ for (cnt = 1; scan(fp, pw, &flags); ++cnt) {
+
+#ifdef __APPLE__
+ if (pw->pw_name == NULL)
+ continue;
+#endif
+
+ if (firsttime) {
+ /* Look like YP? */
+ if ((pw->pw_name[0] == '+') || (pw->pw_name[0] == '-'))
+ hasyp++;
+
+ /* Warn about potentially unsafe uid/gid overrides. */
+ if (pw->pw_name[0] == '+') {
+ if (!(flags & _PASSWORD_NOUID) && !pw->pw_uid)
+ warnx("line %d: superuser override in "
+ "YP inclusion", cnt);
+ if (!(flags & _PASSWORD_NOGID) && !pw->pw_gid)
+ warnx("line %d: wheel override in "
+ "YP inclusion", cnt);
+ }
+
+ /* Create V7 format password file entry. */
+ if (oldfp != NULL)
+ if (fprintf(oldfp, "%s:*:%u:%u:%s:%s:%s\n",
+ pw->pw_name, pw->pw_uid, pw->pw_gid,
+ pw->pw_gecos, pw->pw_dir, pw->pw_shell)
+ == EOF)
+ error("write old");
+ }
+
+ /* Are we updating a specific record? */
+ if (username) {
+ if (strcmp(username, pw->pw_name) != 0)
+ continue;
+ found = 1;
+ /* If the uid changed, remove the old record by uid. */
+ if (olduid != UID_MAX && olduid != pw->pw_uid) {
+ tbuf[0] = _PW_KEYBYUID;
+ memcpy(tbuf + 1, &olduid, sizeof(olduid));
+ key.size = sizeof(olduid) + 1;
+ (edp->del)(edp, &key, 0);
+ if (dp)
+ (dp->del)(dp, &key, 0);
+ }
+ /* XXX - should check to see if line number changed. */
+ }
+
+ /* Build the key. */
+ tbuf[0] = keytype;
+ switch (keytype) {
+ case _PW_KEYBYNUM:
+ memmove(tbuf + 1, &cnt, sizeof(cnt));
+ key.size = sizeof(cnt) + 1;
+ break;
+
+ case _PW_KEYBYNAME:
+ len = strlen(pw->pw_name);
+ memmove(tbuf + 1, pw->pw_name, len);
+ key.size = len + 1;
+ break;
+
+ case _PW_KEYBYUID:
+ memmove(tbuf + 1, &pw->pw_uid, sizeof(pw->pw_uid));
+ key.size = sizeof(pw->pw_uid) + 1;
+ break;
+ }
+
+#define COMPACT(e) t = e; while ((*p++ = *t++));
+ /* Create the secure record. */
+ p = buf;
+ COMPACT(pw->pw_name);
+ COMPACT(pw->pw_passwd);
+ memmove(p, &pw->pw_uid, sizeof(uid_t));
+ p += sizeof(uid_t);
+ memmove(p, &pw->pw_gid, sizeof(gid_t));
+ p += sizeof(gid_t);
+ memmove(p, &pw->pw_change, sizeof(time_t));
+ p += sizeof(time_t);
+ COMPACT(pw->pw_class);
+ COMPACT(pw->pw_gecos);
+ COMPACT(pw->pw_dir);
+ COMPACT(pw->pw_shell);
+ memmove(p, &pw->pw_expire, sizeof(time_t));
+ p += sizeof(time_t);
+ memmove(p, &flags, sizeof(int));
+ p += sizeof(int);
+ data.size = p - buf;
+
+ /* Write the secure record. */
+ if ((edp->put)(edp, &key, &data, dbmode) == -1)
+ error("put");
+
+ if (dp == NULL)
+ continue;
+
+ /* Star out password to make insecure record. */
+ p = buf + strlen(pw->pw_name) + 1; /* skip pw_name */
+ len = strlen(pw->pw_passwd);
+ memset(p, 0, len); /* zero pw_passwd */
+ t = p + len + 1; /* skip pw_passwd */
+ if (len != 0)
+ *p++ = '*';
+ *p++ = '\0';
+ memmove(p, t, data.size - (t - buf));
+ data.size -= len - 1;
+
+ /* Write the insecure record. */
+ if ((dp->put)(dp, &key, &data, dbmode) == -1)
+ error("put");
+ }
+ if (firsttime) {
+ firsttime = 0;
+ if (username && !found && olduid != UID_MAX)
+ errorx("can't find user in master.passwd");
+ }
+}
--- /dev/null
+#include <TargetConditionals.h>
+#if TARGET_OS_EMBEDDED
+subsystem dummy 0;
+#else
+#include <IOKit/kext/kextmanager_mig.defs>
+#endif
--- /dev/null
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)reboot.8 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD: src/sbin/reboot/reboot.8,v 1.21 2002/12/27 12:15:33 schweikh Exp $
+.\"
+.Dd June 9, 1993
+.Dt REBOOT 8
+.Os
+.Sh NAME
+.Nm halt ,
+.Nm reboot
+.Nd stopping and restarting the system
+.Sh SYNOPSIS
+.Nm halt
+.Op Fl lnqu
+.Nm reboot
+.Op Fl lnq
+.Sh DESCRIPTION
+The
+.Nm halt
+and
+.Nm reboot
+utilities flush the file system cache to disk,
+send all running processes a
+.Dv SIGTERM
+(and subsequently a
+.Dv SIGKILL )
+and, respectively, halt or restart the system.
+The action is logged, including entering a shutdown record into the
+.Xr wtmp 5
+file.
+.Pp
+When the system is halted with the halt command, the system is powered off.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl l
+The halt or reboot is
+.Em not
+recorded in the system log.
+This option is intended for applications such as
+.Xr shutdown 8 ,
+that call
+.Nm reboot
+or
+.Nm halt
+and log this themselves.
+.It Fl n
+The file system cache is not flushed.
+This option should probably not be used.
+.It Fl q
+The system is halted or restarted quickly and ungracefully, and only
+the flushing of the file system cache is performed (if the
+.Fl n
+option is not specified).
+This option should probably not be used.
+.It Fl u
+The system is halted up until the point of removing system power, but waits
+before removing power for 5 minutes so that an external UPS
+(uninterruptible power supply) can forcibly remove power.
+This simulates a dirty shutdown to permit a later automatic power on. OS X uses
+this mode automatically with supported UPSs in emergency shutdowns.
+.El
+.Pp
+Normally, the
+.Xr shutdown 8
+utility is used when the system needs to be halted or restarted, giving
+users advance warning of their impending doom and cleanly terminating
+specific programs.
+.Sh SIGTERM TO SIGKILL INTERVAL
+The
+.Dv SIGKILL
+will follow the
+.Dv SIGTERM
+by an intentionally indeterminate period of time.
+Programs are expected to take only enough time to flush all dirty data and exit.
+Developers are encouraged to file a bug with the OS vendor, should they encounter an issue with this functionality.
+.Sh SEE ALSO
+.Xr wtmp 5 ,
+.Xr shutdown 8 ,
+.Xr sync 8
+.Sh HISTORY
+A
+.Nm reboot
+utility appeared in
+.At v6 .
--- /dev/null
+/*
+ * Copyright (c) 1980, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Portions copyright (c) 2007 Apple Inc. 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. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1986, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)reboot.c 8.1 (Berkeley) 6/5/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/sbin/reboot/reboot.c,v 1.17 2002/10/06 16:24:36 thomas Exp $";
+#endif /* not lint */
+
+#include <sys/reboot.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <signal.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <util.h>
+#include <pwd.h>
+#include <syslog.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#if !TARGET_OS_EMBEDDED
+#include "kextmanager.h"
+#include <IOKit/kext/kextmanager_types.h>
+#endif
+#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>
+#endif
+
+void usage(void);
+u_int get_pageins(void);
+#if defined(__APPLE__) && !TARGET_OS_EMBEDDED
+int reserve_reboot(void);
+#endif
+
+int dohalt;
+
+int
+main(int argc, char *argv[])
+{
+ struct passwd *pw;
+ int ch, howto, kflag, lflag, nflag, qflag, uflag;
+ char *p;
+ const char *user;
+#ifndef __APPLE__
+ int i, fd, pflag, sverrno;
+ u_int pageins;
+ char *kernel;
+#endif
+
+ if (strstr((p = rindex(*argv, '/')) ? p + 1 : *argv, "halt")) {
+ dohalt = 1;
+ howto = RB_HALT;
+ } else
+ howto = 0;
+ kflag = lflag = nflag = qflag = 0;
+#ifndef __APPLE__
+ while ((ch = getopt(argc, argv, "dk:lnpq")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "lnqu")) != -1)
+#endif
+ switch(ch) {
+#ifndef __APPLE__
+ case 'd':
+ howto |= RB_DUMP;
+ break;
+ case 'k':
+ kflag = 1;
+ kernel = optarg;
+ break;
+#endif
+ case 'l':
+ lflag = 1;
+ break;
+ case 'n':
+ nflag = 1;
+ howto |= RB_NOSYNC;
+ break;
+/* -p is irrelevant on OS X. It does that anyway. */
+#ifndef __APPLE__
+ case 'p':
+ pflag = 1;
+ howto |= RB_POWEROFF;
+ break;
+#endif
+ case 'u':
+ uflag = 1;
+ howto |= RB_UPSDELAY;
+ break;
+ case 'q':
+ qflag = 1;
+ howto |= RB_QUICK;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifndef __APPLE__
+ if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT))
+ errx(1, "cannot dump (-d) when halting; must reboot instead");
+#endif
+ if (geteuid()) {
+ errno = EPERM;
+ err(1, NULL);
+ }
+
+#if defined(__APPLE__) && !TARGET_OS_EMBEDDED
+ if (!qflag && !lflag) { // shutdown(8) has already checked w/kextd
+ if ((errno = reserve_reboot()))
+ err(1, "couldn't lock for reboot");
+ }
+#endif
+
+ if (qflag) {
+ reboot(howto);
+ err(1, NULL);
+ }
+
+#ifndef __APPLE__
+ if (kflag) {
+ fd = open("/boot/nextboot.conf", O_WRONLY | O_CREAT, 0444);
+ if (fd > -1) {
+ (void)write(fd, "nextboot_enable=\"YES\"\n", 22);
+ (void)write(fd, "kernel=\"", 8L);
+ (void)write(fd, kernel, strlen(kernel));
+ (void)write(fd, "\"\n", 2);
+ close(fd);
+ }
+ }
+#endif
+
+ /* Log the reboot. */
+ if (!lflag) {
+ if ((user = getlogin()) == NULL)
+ user = (pw = getpwuid(getuid())) ?
+ pw->pw_name : "???";
+ if (dohalt) {
+ openlog("halt", 0, LOG_AUTH | LOG_CONS);
+ syslog(LOG_CRIT, "halted by %s%s", user,
+ (howto & RB_UPSDELAY) ? " with UPS delay":"");
+ } else {
+ openlog("reboot", 0, LOG_AUTH | LOG_CONS);
+ syslog(LOG_CRIT, "rebooted by %s", user);
+ }
+ }
+#if defined(__APPLE__)
+ {
+ struct utmpx utx;
+ bzero(&utx, sizeof(utx));
+ utx.ut_type = SHUTDOWN_TIME;
+ gettimeofday(&utx.ut_tv, NULL);
+ pututxline(&utx);
+
+ int newvalue = 1;
+ sysctlbyname("kern.willshutdown", NULL, NULL, &newvalue, sizeof(newvalue));
+ }
+#else
+ logwtmp("~", "shutdown", "");
+#endif
+
+ /*
+ * Do a sync early on, so disks start transfers while we're off
+ * killing processes. Don't worry about writes done before the
+ * processes die, the reboot system call syncs the disks.
+ */
+ if (!nflag)
+ sync();
+
+#ifndef __APPLE__
+ /* Just stop init -- if we fail, we'll restart it. */
+ if (kill(1, SIGTSTP) == -1)
+ err(1, "SIGTSTP init");
+#endif
+
+ /* Ignore the SIGHUP we get when our parent shell dies. */
+ (void)signal(SIGHUP, SIG_IGN);
+
+#ifndef __APPLE__
+ /* Send a SIGTERM first, a chance to save the buffers. */
+ if (kill(-1, SIGTERM) == -1)
+ err(1, "SIGTERM processes");
+
+ /*
+ * After the processes receive the signal, start the rest of the
+ * buffers on their way. Wait 5 seconds between the SIGTERM and
+ * the SIGKILL to give everybody a chance. If there is a lot of
+ * paging activity then wait longer, up to a maximum of approx
+ * 60 seconds.
+ */
+ sleep(2);
+ for (i = 0; i < 20; i++) {
+ pageins = get_pageins();
+ if (!nflag)
+ sync();
+ sleep(3);
+ if (get_pageins() == pageins)
+ break;
+ }
+
+ for (i = 1;; ++i) {
+ if (kill(-1, SIGKILL) == -1) {
+ if (errno == ESRCH)
+ break;
+ goto restart;
+ }
+ if (i > 5) {
+ (void)fprintf(stderr,
+ "WARNING: some process(es) wouldn't die\n");
+ break;
+ }
+ (void)sleep(2 * i);
+ }
+#endif
+
+#ifdef __APPLE__
+ // launchd(8) handles reboot. This call returns NULL on success.
+ exit(reboot2(howto) == NULL ? EXIT_SUCCESS : EXIT_FAILURE);
+#else /* __APPLE__ */
+ reboot(howto);
+ /* FALLTHROUGH */
+
+restart:
+ sverrno = errno;
+ errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "",
+ strerror(sverrno));
+ /* NOTREACHED */
+#endif /* __APPLE__ */
+}
+
+void
+usage()
+{
+#ifndef __APPLE__
+ (void)fprintf(stderr, "usage: %s [-dnpq] [-k kernel]\n",
+#else
+ (void)fprintf(stderr, "usage: %s [-lnq]\n",
+#endif
+ dohalt ? "halt" : "reboot");
+ exit(1);
+}
+
+u_int
+get_pageins()
+{
+ u_int pageins;
+ size_t len;
+
+ len = sizeof(pageins);
+ if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0)
+ != 0) {
+ warnx("v_swappgsin");
+ return (0);
+ }
+ return pageins;
+}
+
+#if defined(__APPLE__) && !TARGET_OS_EMBEDDED
+// XX this routine is also in shutdown.tproj; it would be nice to share
+
+#define WAITFORLOCK 1
+/*
+ * contact kextd to lock for reboot
+ */
+int
+reserve_reboot()
+{
+ int rval = ELAST + 1;
+ kern_return_t macherr = KERN_FAILURE;
+ mach_port_t kxport, tport = MACH_PORT_NULL, myport = MACH_PORT_NULL;
+ int busyStatus = ELAST + 1;
+ mountpoint_t busyVol;
+
+ 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)
+ tport = mach_task_self();
+ if (tport == MACH_PORT_NULL) goto finish;
+ macherr = mach_port_allocate(tport, MACH_PORT_RIGHT_RECEIVE, &myport);
+ if (macherr) goto finish;
+
+ // try to lock for reboot
+ macherr = kextmanager_lock_reboot(kxport, myport, !WAITFORLOCK, busyVol,
+ &busyStatus);
+ if (macherr) goto finish;
+
+ if (busyStatus == EBUSY) {
+ warnx("%s is busy updating; waiting for lock", busyVol);
+ macherr = kextmanager_lock_reboot(kxport, myport, WAITFORLOCK,
+ busyVol, &busyStatus);
+ if (macherr) goto finish;
+ }
+
+ if (busyStatus == EALREADY) {
+ // reboot already in progress
+ rval = 0;
+ } else {
+ rval = busyStatus;
+ }
+
+finish:
+ // in general, we want to err on the side of allowing the reboot
+ if (macherr) {
+ if (macherr != BOOTSTRAP_UNKNOWN_SERVICE)
+ warnx("WARNING: couldn't lock kext manager for reboot: %s",
+ mach_error_string(macherr));
+ rval = 0;
+ }
+ // unless we got the lock, clean up our port
+ if (busyStatus != 0 && myport != MACH_PORT_NULL)
+ mach_port_mod_refs(tport, myport, MACH_PORT_RIGHT_RECEIVE, -1);
+
+ return rval;
+}
+#endif
--- /dev/null
+/*-
+ * Copyright (c) 2007 Diomidis Spinellis
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/sa/db.c,v 1.3 2008/02/21 07:12:56 grog Exp $");
+
+#include <sys/types.h>
+#include <sys/acct.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <db.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "extern.h"
+
+/* Key used to store the version of the database data elements. */
+#define VERSION_KEY "\0VERSION"
+
+/*
+ * Create the in-memory database, *mdb.
+ * If iflag is not set, fill-in mdb with the records of the disk-based
+ * database dbname.
+ * Upgrade old-version records by calling v1_to_v2.
+ * Return 0 if OK, -1 on error.
+ */
+int
+db_copy_in(DB **mdb, const char *dbname, const char *uname, BTREEINFO *bti,
+ int (*v1_to_v2)(DBT *key, DBT *data))
+{
+ DBT key, data;
+ DB *ddb;
+ int error, rv, version;
+
+ if ((*mdb = dbopen(NULL, O_RDWR, 0, DB_BTREE, bti)) == NULL)
+ return (-1);
+
+ if (iflag)
+ return (0);
+
+ if ((ddb = dbopen(dbname, O_RDONLY, 0, DB_BTREE, bti)) == NULL) {
+ if (errno == ENOENT)
+ return (0);
+ warn("retrieving %s summary", uname);
+ db_destroy(*mdb, uname);
+ return (-1);
+ }
+
+ error = 0;
+
+ /* Obtain/set version. */
+ version = 1;
+ key.data = &VERSION_KEY;
+ key.size = sizeof(VERSION_KEY);
+
+ rv = DB_GET(ddb, &key, &data, 0);
+ if (rv < 0) {
+ warn("get version key from %s stats", uname);
+ error = -1;
+ goto closeout;
+ } else if (rv == 0) { /* It's there; verify version. */
+ if (data.size != sizeof(version)) {
+ warnx("invalid version size %zd in %s",
+ data.size, uname);
+ error = -1;
+ goto closeout;
+ }
+ memcpy(&version, data.data, data.size);
+ if (version != 2) {
+ warnx("unsupported version %d in %s",
+ version, uname);
+ error = -1;
+ goto closeout;
+ }
+ }
+
+ for (rv = DB_SEQ(ddb, &key, &data, R_FIRST); rv == 0;
+ rv = DB_SEQ(ddb, &key, &data, R_NEXT)) {
+
+ /* See if this is a version record. */
+ if (key.size == sizeof(VERSION_KEY) &&
+ memcmp(key.data, VERSION_KEY, sizeof(VERSION_KEY)) == 0)
+ continue;
+
+ /* Convert record from v1, if needed. */
+ if (version == 1 && v1_to_v2(&key, &data) < 0) {
+ warn("converting %s stats", uname);
+ error = -1;
+ goto closeout;
+ }
+
+ /* Copy record to the in-memory database. */
+ if ((rv = DB_PUT(*mdb, &key, &data, 0)) < 0) {
+ warn("initializing %s stats", uname);
+ error = -1;
+ goto closeout;
+ }
+ }
+ if (rv < 0) {
+ warn("retrieving %s summary", uname);
+ error = -1;
+ }
+
+closeout:
+ if (DB_CLOSE(ddb) < 0) {
+ warn("closing %s summary", uname);
+ error = -1;
+ }
+
+ if (error)
+ db_destroy(*mdb, uname);
+ return (error);
+}
+
+/*
+ * Save the in-memory database mdb to the disk database dbname.
+ * Return 0 if OK, -1 on error.
+ */
+int
+db_copy_out(DB *mdb, const char *dbname, const char *uname, BTREEINFO *bti)
+{
+ DB *ddb;
+ DBT key, data;
+ int error, rv, version;
+
+ if ((ddb = dbopen(dbname, O_RDWR|O_CREAT|O_TRUNC, 0644,
+ DB_BTREE, bti)) == NULL) {
+ warn("creating %s summary", uname);
+ return (-1);
+ }
+
+ error = 0;
+
+ for (rv = DB_SEQ(mdb, &key, &data, R_FIRST);
+ rv == 0; rv = DB_SEQ(mdb, &key, &data, R_NEXT)) {
+ if ((rv = DB_PUT(ddb, &key, &data, 0)) < 0) {
+ warn("saving %s summary", uname);
+ error = -1;
+ goto out;
+ }
+ }
+ if (rv < 0) {
+ warn("retrieving %s stats", uname);
+ error = -1;
+ }
+
+out:
+#ifndef __APPLE__
+ /* Add a version record. */
+ key.data = &VERSION_KEY;
+ key.size = sizeof(VERSION_KEY);
+ version = 2;
+ data.data = &version;
+ data.size = sizeof(version);
+ if ((rv = DB_PUT(ddb, &key, &data, 0)) < 0) {
+ warn("add version record to %s stats", uname);
+ error = -1;
+ } else if (rv == 1) {
+ warnx("duplicate version record in %s stats", uname);
+ error = -1;
+ }
+#else
+ version = 1; // avoid unused warning
+#endif
+
+ if (DB_SYNC(ddb, 0) < 0) {
+ warn("syncing %s summary", uname);
+ error = -1;
+ }
+ if (DB_CLOSE(ddb) < 0) {
+ warn("closing %s summary", uname);
+ error = -1;
+ }
+ return error;
+}
+
+void
+db_destroy(DB *db, const char *uname)
+{
+ if (DB_CLOSE(db) < 0)
+ warn("destroying %s stats", uname);
+}
--- /dev/null
+/*
+ * Copyright (c) 1994 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.
+ *
+ * $FreeBSD: src/usr.sbin/sa/extern.h,v 1.7 2007/05/22 06:51:38 dds Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <db.h>
+
+/* structures */
+
+/* All times are stored in 1e-6s units. */
+
+struct cmdinfo {
+ char ci_comm[MAXCOMLEN+2]; /* command name (+ '*') */
+ uid_t ci_uid; /* user id */
+#ifdef __APPLE__
+ u_quad_t ci_calls; /* number of calls */
+ u_quad_t ci_etime; /* elapsed time */
+ u_quad_t ci_utime; /* user time */
+ u_quad_t ci_stime; /* system time */
+ u_quad_t ci_mem; /* memory use */
+ u_quad_t ci_io; /* number of disk i/o ops */
+#else
+ double ci_etime; /* elapsed time */
+ double ci_utime; /* user time */
+ double ci_stime; /* system time */
+ double ci_mem; /* memory use */
+ double ci_io; /* number of disk i/o ops */
+#endif
+ u_int ci_flags; /* flags; see below */
+};
+#define CI_UNPRINTABLE 0x0001 /* unprintable chars in name */
+
+struct userinfo {
+ uid_t ui_uid; /* user id; for consistency */
+ u_quad_t ui_calls; /* number of invocations */
+#ifdef __APPLE__
+ u_quad_t ui_utime; /* user time */
+ u_quad_t ui_stime; /* system time */
+ u_quad_t ui_mem; /* memory use */
+ u_quad_t ui_io; /* number of disk i/o ops */
+#else
+ double ui_utime; /* user time */
+ double ui_stime; /* system time */
+ double ui_mem; /* memory use */
+ double ui_io; /* number of disk i/o ops */
+#endif
+};
+
+/* typedefs */
+
+typedef int (*cmpf_t)(const DBT *, const DBT *);
+
+/* external functions in db.c */
+int db_copy_in(DB **mdb, const char *dbname, const char *name,
+ BTREEINFO *bti, int (*v1_to_v2)(DBT *key, DBT *data));
+int db_copy_out(DB *mdb, const char *dbname, const char *name,
+ BTREEINFO *bti);
+void db_destroy(DB *db, const char *uname);
+
+/* external functions in pdb.c */
+int pacct_init(void);
+void pacct_destroy(void);
+int pacct_add(const struct cmdinfo *);
+int pacct_update(void);
+void pacct_print(void);
+
+#ifndef __APPLE__
+/* external functions in readrec.c */
+int readrec_forward(FILE *f, struct acctv2 *av2);
+#endif
+
+/* external functions in usrdb.c */
+int usracct_init(void);
+void usracct_destroy(void);
+int usracct_add(const struct cmdinfo *);
+int usracct_update(void);
+void usracct_print(void);
+
+/* variables */
+
+extern int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
+extern int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
+extern u_quad_t cutoff;
+extern cmpf_t sa_cmp;
+extern const char *pdb_file, *usrdb_file;
+
+/* some #defines to help with db's stupidity */
+
+#define DB_CLOSE(db) \
+ ((*(db)->close)(db))
+#define DB_GET(db, key, data, flags) \
+ ((*(db)->get)((db), (key), (data), (flags)))
+#define DB_PUT(db, key, data, flags) \
+ ((*(db)->put)((db), (key), (data), (flags)))
+#define DB_SYNC(db, flags) \
+ ((*(db)->sync)((db), (flags)))
+#define DB_SEQ(db, key, data, flags) \
+ ((*(db)->seq)((db), (key), (data), (flags)))
--- /dev/null
+/*
+ * Copyright (c) 1994 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.
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1994 Christopher G. Demetriou\n\
+ All rights reserved.\n";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/sa/main.c,v 1.18 2007/05/22 06:51:38 dds Exp $");
+
+/*
+ * sa: system accounting
+ */
+
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "extern.h"
+#include "pathnames.h"
+
+static FILE *acct_load(const char *, int);
+#ifdef __APPLE__
+static u_quad_t decode_comp_t(comp_t);
+#endif
+static int cmp_comm(const char *, const char *);
+static int cmp_usrsys(const DBT *, const DBT *);
+static int cmp_avgusrsys(const DBT *, const DBT *);
+static int cmp_dkio(const DBT *, const DBT *);
+static int cmp_avgdkio(const DBT *, const DBT *);
+static int cmp_cpumem(const DBT *, const DBT *);
+static int cmp_avgcpumem(const DBT *, const DBT *);
+static int cmp_calls(const DBT *, const DBT *);
+static void usage(void);
+
+int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
+int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
+u_quad_t cutoff = 1;
+const char *pdb_file = _PATH_SAVACCT;
+const char *usrdb_file = _PATH_USRACCT;
+
+static char *dfltargv[] = { NULL };
+static int dfltargc = (sizeof dfltargv/sizeof(char *));
+
+/* default to comparing by sum of user + system time */
+cmpf_t sa_cmp = cmp_usrsys;
+
+int
+main(int argc, char **argv)
+{
+ FILE *f;
+ char pathacct[] = _PATH_ACCT;
+ int ch, error = 0;
+
+ dfltargv[0] = pathacct;
+
+ while ((ch = getopt(argc, argv, "abcdDfijkKlmnP:qrstuU:v:")) != -1)
+ switch (ch) {
+ case 'a':
+ /* print all commands */
+ aflag = 1;
+ break;
+ case 'b':
+ /* sort by per-call user/system time average */
+ bflag = 1;
+ sa_cmp = cmp_avgusrsys;
+ break;
+ case 'c':
+ /* print percentage total time */
+ cflag = 1;
+ break;
+ case 'd':
+ /* sort by averge number of disk I/O ops */
+ dflag = 1;
+ sa_cmp = cmp_avgdkio;
+ break;
+ case 'D':
+ /* print and sort by total disk I/O ops */
+ Dflag = 1;
+ sa_cmp = cmp_dkio;
+ break;
+ case 'f':
+ /* force no interactive threshold comprison */
+ fflag = 1;
+ break;
+ case 'i':
+ /* do not read in summary file */
+ iflag = 1;
+ break;
+ case 'j':
+ /* instead of total minutes, give sec/call */
+ jflag = 1;
+ break;
+ case 'k':
+ /* sort by cpu-time average memory usage */
+ kflag = 1;
+ sa_cmp = cmp_avgcpumem;
+ break;
+ case 'K':
+ /* print and sort by cpu-storage integral */
+ sa_cmp = cmp_cpumem;
+ Kflag = 1;
+ break;
+ case 'l':
+ /* separate system and user time */
+ lflag = 1;
+ break;
+ case 'm':
+ /* print procs and time per-user */
+ mflag = 1;
+ break;
+ case 'n':
+ /* sort by number of calls */
+ sa_cmp = cmp_calls;
+ break;
+ case 'P':
+ /* specify program database summary file */
+ pdb_file = optarg;
+ break;
+ case 'q':
+ /* quiet; error messages only */
+ qflag = 1;
+ break;
+ case 'r':
+ /* reverse order of sort */
+ rflag = 1;
+ break;
+ case 's':
+ /* merge accounting file into summaries */
+ sflag = 1;
+ break;
+ case 't':
+ /* report ratio of user and system times */
+ tflag = 1;
+ break;
+ case 'u':
+ /* first, print uid and command name */
+ uflag = 1;
+ break;
+ case 'U':
+ /* specify user database summary file */
+ usrdb_file = optarg;
+ break;
+ case 'v':
+ /* cull junk */
+ vflag = 1;
+ cutoff = atoi(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* various argument checking */
+ if (fflag && !vflag)
+ errx(1, "only one of -f requires -v");
+ if (fflag && aflag)
+ errx(1, "only one of -a and -v may be specified");
+ /* XXX need more argument checking */
+
+ if (!uflag) {
+ /* initialize tables */
+ if ((sflag || (!mflag && !qflag)) && pacct_init() != 0)
+ errx(1, "process accounting initialization failed");
+ if ((sflag || (mflag && !qflag)) && usracct_init() != 0)
+ errx(1, "user accounting initialization failed");
+ }
+
+ if (argc == 0) {
+ argc = dfltargc;
+ argv = dfltargv;
+ }
+
+ /* for each file specified */
+ for (; argc > 0; argc--, argv++) {
+ /*
+ * load the accounting data from the file.
+ * if it fails, go on to the next file.
+ */
+ f = acct_load(argv[0], sflag);
+ if (f == NULL)
+ continue;
+
+ if (!uflag && sflag) {
+#ifndef DEBUG
+ sigset_t nmask, omask;
+ int unmask = 1;
+
+ /*
+ * block most signals so we aren't interrupted during
+ * the update.
+ */
+ if (sigfillset(&nmask) == -1) {
+ warn("sigfillset");
+ unmask = 0;
+ error = 1;
+ }
+ if (unmask &&
+ (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1)) {
+ warn("couldn't set signal mask");
+ unmask = 0;
+ error = 1;
+ }
+#endif /* DEBUG */
+
+ /*
+ * truncate the accounting data file ASAP, to avoid
+ * losing data. don't worry about errors in updating
+ * the saved stats; better to underbill than overbill,
+ * but we want every accounting record intact.
+ */
+ if (ftruncate(fileno(f), 0) == -1) {
+ warn("couldn't truncate %s", *argv);
+ error = 1;
+ }
+
+ /*
+ * update saved user and process accounting data.
+ * note errors for later.
+ */
+ if (pacct_update() != 0 || usracct_update() != 0)
+ error = 1;
+
+#ifndef DEBUG
+ /*
+ * restore signals
+ */
+ if (unmask &&
+ (sigprocmask(SIG_SETMASK, &omask, NULL) == -1)) {
+ warn("couldn't restore signal mask");
+ error = 1;
+ }
+#endif /* DEBUG */
+ }
+
+ /*
+ * close the opened accounting file
+ */
+ if (fclose(f) == EOF) {
+ warn("fclose %s", *argv);
+ error = 1;
+ }
+ }
+
+ if (!uflag && !qflag) {
+ /* print any results we may have obtained. */
+ if (!mflag)
+ pacct_print();
+ else
+ usracct_print();
+ }
+
+ if (!uflag) {
+ /* finally, deallocate databases */
+ if (sflag || (!mflag && !qflag))
+ pacct_destroy();
+ if (sflag || (mflag && !qflag))
+ usracct_destroy();
+ }
+
+ exit(error);
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: sa [-abcdDfijkKlmnqrstu] [-P file] [-U file] [-v cutoff] [file ...]\n");
+ exit(1);
+}
+
+static FILE *
+acct_load(const char *pn, int wr)
+{
+#ifdef __APPLE__
+ struct acct ac;
+#else
+ struct acctv2 ac;
+#endif
+ struct cmdinfo ci;
+ ssize_t rv;
+ FILE *f;
+ int i;
+
+ /*
+ * open the file
+ */
+ f = fopen(pn, wr ? "r+" : "r");
+ if (f == NULL) {
+ warn("open %s %s", pn, wr ? "for read/write" : "read-only");
+ return (NULL);
+ }
+
+ /*
+ * read all we can; don't stat and open because more processes
+ * could exit, and we'd miss them
+ */
+ while (1) {
+ /* get one accounting entry and punt if there's an error */
+#ifdef __APPLE__
+ rv = read(fileno(f), &ac, sizeof(struct acct));
+ if (rv == -1)
+ warn("error reading %s", pn);
+ else if (rv > 0 && rv < (int)sizeof(struct acct))
+ warnx("short read of accounting data in %s", pn);
+ if (rv != sizeof(struct acct))
+ break;
+#else
+ rv = readrec_forward(f, &ac);
+ if (rv != 1) {
+ if (rv == EOF)
+ warn("error reading %s", pn);
+ break;
+ }
+#endif
+
+ /* decode it */
+ ci.ci_calls = 1;
+ for (i = 0; i < (int)sizeof ac.ac_comm && ac.ac_comm[i] != '\0';
+ i++) {
+ char c = ac.ac_comm[i];
+
+ if (!isascii(c) || iscntrl(c)) {
+ ci.ci_comm[i] = '?';
+ ci.ci_flags |= CI_UNPRINTABLE;
+ } else
+ ci.ci_comm[i] = c;
+ }
+#ifdef __APPLE__
+ if (ac.ac_flag & AFORK)
+ ci.ci_comm[i++] = '*';
+ ci.ci_comm[i++] = '\0';
+ ci.ci_etime = decode_comp_t(ac.ac_etime);
+ ci.ci_utime = decode_comp_t(ac.ac_utime);
+ ci.ci_stime = decode_comp_t(ac.ac_stime);
+ ci.ci_uid = ac.ac_uid;
+ ci.ci_mem = ac.ac_mem;
+ ci.ci_io = decode_comp_t(ac.ac_io) / AHZ;
+#else
+ if (ac.ac_flagx & AFORK)
+ ci.ci_comm[i++] = '*';
+ ci.ci_comm[i++] = '\0';
+ ci.ci_etime = ac.ac_etime;
+ ci.ci_utime = ac.ac_utime;
+ ci.ci_stime = ac.ac_stime;
+ ci.ci_uid = ac.ac_uid;
+ ci.ci_mem = ac.ac_mem;
+ ci.ci_io = ac.ac_io;
+#endif
+
+ if (!uflag) {
+ /* and enter it into the usracct and pacct databases */
+ if (sflag || (!mflag && !qflag))
+ pacct_add(&ci);
+ if (sflag || (mflag && !qflag))
+ usracct_add(&ci);
+ } else if (!qflag)
+#ifdef __APPLE__
+ printf("%6u %12.2f cpu %12juk mem %12ju io %s\n",
+ ci.ci_uid,
+ (ci.ci_utime + ci.ci_stime) / (double) AHZ,
+ (uintmax_t)ci.ci_mem, (uintmax_t)ci.ci_io,
+ ci.ci_comm);
+#else
+ printf("%6u %12.3lf cpu %12.0lfk mem %12.0lf io %s\n",
+ ci.ci_uid,
+ (ci.ci_utime + ci.ci_stime) / 1000000,
+ ci.ci_mem, ci.ci_io,
+ ci.ci_comm);
+#endif
+ }
+
+ /* Finally, return the file stream for possible truncation. */
+ return (f);
+}
+
+#ifdef __APPLE__
+static u_quad_t decode_comp_t(comp_t comp)
+{
+ u_quad_t rv;
+
+ /*
+ * for more info on the comp_t format, see:
+ * /usr/src/sys/kern/kern_acct.c
+ * /usr/src/sys/sys/acct.h
+ * /usr/src/usr.bin/lastcomm/lastcomm.c
+ */
+ rv = comp & 0x1fff; /* 13 bit fraction */
+ comp >>= 13; /* 3 bit base-8 exponent */
+ while (comp--)
+ rv <<= 3;
+
+ return (rv);
+}
+#endif
+
+/* sort commands, doing the right thing in terms of reversals */
+static int
+cmp_comm(const char *s1, const char *s2)
+{
+ int rv;
+
+ rv = strcmp(s1, s2);
+ if (rv == 0)
+ rv = -1;
+ return (rflag ? rv : -rv);
+}
+
+/* sort by total user and system time */
+static int
+cmp_usrsys(const DBT *d1, const DBT *d2)
+{
+ struct cmdinfo c1, c2;
+#ifdef __APPLE__
+ u_quad_t t1, t2;
+#else
+ double t1, t2;
+#endif
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ t1 = c1.ci_utime + c1.ci_stime;
+ t2 = c2.ci_utime + c2.ci_stime;
+
+ if (t1 < t2)
+ return -1;
+ else if (t1 == t2)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by average user and system time */
+static int
+cmp_avgusrsys(const DBT *d1, const DBT *d2)
+{
+ struct cmdinfo c1, c2;
+ double t1, t2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ t1 = c1.ci_utime + c1.ci_stime;
+ t1 /= (double) (c1.ci_calls ? c1.ci_calls : 1);
+
+ t2 = c2.ci_utime + c2.ci_stime;
+ t2 /= (double) (c2.ci_calls ? c2.ci_calls : 1);
+
+ if (t1 < t2)
+ return -1;
+ else if (t1 == t2)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by total number of disk I/O operations */
+static int
+cmp_dkio(const DBT *d1, const DBT *d2)
+{
+ struct cmdinfo c1, c2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ if (c1.ci_io < c2.ci_io)
+ return -1;
+ else if (c1.ci_io == c2.ci_io)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by average number of disk I/O operations */
+static int
+cmp_avgdkio(const DBT *d1, const DBT *d2)
+{
+ struct cmdinfo c1, c2;
+ double n1, n2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+#ifdef __APPLE__
+ n1 = (double) c1.ci_io / (double) (c1.ci_calls ? c1.ci_calls : 1);
+ n2 = (double) c2.ci_io / (double) (c2.ci_calls ? c2.ci_calls : 1);
+#else
+ n1 = c1.ci_io / (double) (c1.ci_calls ? c1.ci_calls : 1);
+ n2 = c2.ci_io / (double) (c2.ci_calls ? c2.ci_calls : 1);
+#endif
+
+ if (n1 < n2)
+ return -1;
+ else if (n1 == n2)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by the cpu-storage integral */
+static int
+cmp_cpumem(const DBT *d1, const DBT *d2)
+{
+ struct cmdinfo c1, c2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ if (c1.ci_mem < c2.ci_mem)
+ return -1;
+ else if (c1.ci_mem == c2.ci_mem)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by the cpu-time average memory usage */
+static int
+cmp_avgcpumem(const DBT *d1, const DBT *d2)
+{
+ struct cmdinfo c1, c2;
+#ifdef __APPLE__
+ u_quad_t t1, t2;
+#else
+ double t1, t2;
+#endif
+ double n1, n2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ t1 = c1.ci_utime + c1.ci_stime;
+ t2 = c2.ci_utime + c2.ci_stime;
+
+#ifdef __APPLE__
+ n1 = (double) c1.ci_mem / (double) (t1 ? t1 : 1);
+ n2 = (double) c2.ci_mem / (double) (t2 ? t2 : 1);
+#else
+ n1 = c1.ci_mem / (t1 ? t1 : 1);
+ n2 = c2.ci_mem / (t2 ? t2 : 1);
+#endif
+
+ if (n1 < n2)
+ return -1;
+ else if (n1 == n2)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by the number of invocations */
+static int
+cmp_calls(const DBT *d1, const DBT *d2)
+{
+ struct cmdinfo c1, c2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ if (c1.ci_calls < c2.ci_calls)
+ return -1;
+ else if (c1.ci_calls == c2.ci_calls)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
--- /dev/null
+/*
+ * Copyright (c) 1994 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.
+ *
+ * $FreeBSD: src/usr.sbin/sa/pathnames.h,v 1.4 1999/08/28 01:19:52 peter Exp $
+ */
+
+#define _PATH_ACCT "/var/account/acct"
+#define _PATH_SAVACCT "/var/account/savacct"
+#define _PATH_USRACCT "/var/account/usracct"
--- /dev/null
+/*
+ * Copyright (c) 1994 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/sa/pdb.c,v 1.14 2007/05/22 06:51:38 dds Exp $");
+
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include "extern.h"
+#include "pathnames.h"
+
+static int check_junk(const struct cmdinfo *);
+static void add_ci(const struct cmdinfo *, struct cmdinfo *);
+static void print_ci(const struct cmdinfo *, const struct cmdinfo *);
+
+static DB *pacct_db;
+
+/* Legacy format in AHZV1 units. */
+struct cmdinfov1 {
+ char ci_comm[MAXCOMLEN+2]; /* command name (+ '*') */
+ uid_t ci_uid; /* user id */
+ u_quad_t ci_calls; /* number of calls */
+ u_quad_t ci_etime; /* elapsed time */
+ u_quad_t ci_utime; /* user time */
+ u_quad_t ci_stime; /* system time */
+ u_quad_t ci_mem; /* memory use */
+ u_quad_t ci_io; /* number of disk i/o ops */
+ u_int ci_flags; /* flags; see below */
+};
+
+/*
+ * Convert a v1 data record into the current version.
+ * Return 0 if OK, -1 on error, setting errno.
+ */
+static int
+v1_to_v2(DBT *key __unused, DBT *data)
+{
+ struct cmdinfov1 civ1;
+ static struct cmdinfo civ2;
+
+ if (data->size != sizeof(civ1)) {
+ errno = EFTYPE;
+ return (-1);
+ }
+ memcpy(&civ1, data->data, data->size);
+ memset(&civ2, 0, sizeof(civ2));
+ memcpy(civ2.ci_comm, civ1.ci_comm, sizeof(civ2.ci_comm));
+ civ2.ci_uid = civ1.ci_uid;
+ civ2.ci_calls = civ1.ci_calls;
+ civ2.ci_etime = ((double)civ1.ci_etime / AHZV1) * 1000000;
+ civ2.ci_utime = ((double)civ1.ci_utime / AHZV1) * 1000000;
+ civ2.ci_stime = ((double)civ1.ci_stime / AHZV1) * 1000000;
+ civ2.ci_mem = civ1.ci_mem;
+ civ2.ci_io = civ1.ci_io;
+ civ2.ci_flags = civ1.ci_flags;
+ data->size = sizeof(civ2);
+ data->data = &civ2;
+ return (0);
+}
+
+/* Copy pdb_file to in-memory pacct_db. */
+int
+pacct_init()
+{
+ return (db_copy_in(&pacct_db, pdb_file, "process accounting",
+ NULL, v1_to_v2));
+}
+
+void
+pacct_destroy()
+{
+ db_destroy(pacct_db, "process accounting");
+}
+
+int
+pacct_add(const struct cmdinfo *ci)
+{
+ DBT key, data;
+ struct cmdinfo newci;
+ char keydata[sizeof ci->ci_comm];
+ int rv;
+
+ bcopy(ci->ci_comm, &keydata, sizeof keydata);
+ key.data = &keydata;
+ key.size = strlen(keydata);
+
+ rv = DB_GET(pacct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("get key %s from process accounting stats", ci->ci_comm);
+ return (-1);
+ } else if (rv == 0) { /* it's there; copy whole thing */
+ /* XXX compare size if paranoid */
+ /* add the old data to the new data */
+ bcopy(data.data, &newci, data.size);
+ } else { /* it's not there; zero it and copy the key */
+ bzero(&newci, sizeof newci);
+ bcopy(key.data, newci.ci_comm, key.size);
+ }
+
+ add_ci(ci, &newci);
+
+ data.data = &newci;
+ data.size = sizeof newci;
+ rv = DB_PUT(pacct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("add key %s to process accounting stats", ci->ci_comm);
+ return (-1);
+ } else if (rv == 1) {
+ warnx("duplicate key %s in process accounting stats",
+ ci->ci_comm);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* Copy in-memory pacct_db to pdb_file. */
+int
+pacct_update()
+{
+ return (db_copy_out(pacct_db, pdb_file, "process accounting",
+ NULL));
+}
+
+void
+pacct_print()
+{
+ BTREEINFO bti;
+ DBT key, data, ndata;
+ DB *output_pacct_db;
+ struct cmdinfo *cip, ci, ci_total, ci_other, ci_junk;
+ int rv;
+
+ bzero(&ci_total, sizeof ci_total);
+ strcpy(ci_total.ci_comm, "");
+ bzero(&ci_other, sizeof ci_other);
+ strcpy(ci_other.ci_comm, "***other");
+ bzero(&ci_junk, sizeof ci_junk);
+ strcpy(ci_junk.ci_comm, "**junk**");
+
+ /*
+ * Retrieve them into new DB, sorted by appropriate key.
+ * At the same time, cull 'other' and 'junk'
+ */
+ bzero(&bti, sizeof bti);
+ bti.compare = sa_cmp;
+ output_pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
+ if (output_pacct_db == NULL) {
+ warn("couldn't sort process accounting stats");
+ return;
+ }
+
+ ndata.data = NULL;
+ ndata.size = 0;
+ rv = DB_SEQ(pacct_db, &key, &data, R_FIRST);
+ if (rv < 0)
+ warn("retrieving process accounting stats");
+ while (rv == 0) {
+ cip = (struct cmdinfo *) data.data;
+ bcopy(cip, &ci, sizeof ci);
+
+ /* add to total */
+ add_ci(&ci, &ci_total);
+
+ if (vflag && ci.ci_calls <= cutoff &&
+ (fflag || check_junk(&ci))) {
+ /* put it into **junk** */
+ add_ci(&ci, &ci_junk);
+ goto next;
+ }
+ if (!aflag &&
+ ((ci.ci_flags & CI_UNPRINTABLE) != 0 || ci.ci_calls <= 1)) {
+ /* put into ***other */
+ add_ci(&ci, &ci_other);
+ goto next;
+ }
+ rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
+ if (rv < 0)
+ warn("sorting process accounting stats");
+
+next: rv = DB_SEQ(pacct_db, &key, &data, R_NEXT);
+ if (rv < 0)
+ warn("retrieving process accounting stats");
+ }
+
+ /* insert **junk** and ***other */
+ if (ci_junk.ci_calls != 0) {
+ data.data = &ci_junk;
+ data.size = sizeof ci_junk;
+ rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
+ if (rv < 0)
+ warn("sorting process accounting stats");
+ }
+ if (ci_other.ci_calls != 0) {
+ data.data = &ci_other;
+ data.size = sizeof ci_other;
+ rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
+ if (rv < 0)
+ warn("sorting process accounting stats");
+ }
+
+ /* print out the total */
+ print_ci(&ci_total, &ci_total);
+
+ /* print out; if reversed, print first (smallest) first */
+ rv = DB_SEQ(output_pacct_db, &data, &ndata, rflag ? R_FIRST : R_LAST);
+ if (rv < 0)
+ warn("retrieving process accounting report");
+ while (rv == 0) {
+ cip = (struct cmdinfo *) data.data;
+ bcopy(cip, &ci, sizeof ci);
+
+ print_ci(&ci, &ci_total);
+
+ rv = DB_SEQ(output_pacct_db, &data, &ndata,
+ rflag ? R_NEXT : R_PREV);
+ if (rv < 0)
+ warn("retrieving process accounting report");
+ }
+ DB_CLOSE(output_pacct_db);
+}
+
+static int
+check_junk(const struct cmdinfo *cip)
+{
+ char *cp;
+ size_t len;
+
+ fprintf(stderr, "%s (%ju) -- ", cip->ci_comm, (uintmax_t)cip->ci_calls);
+ cp = fgetln(stdin, &len);
+
+ return (cp && (cp[0] == 'y' || cp[0] == 'Y')) ? 1 : 0;
+}
+
+static void
+add_ci(const struct cmdinfo *fromcip, struct cmdinfo *tocip)
+{
+ tocip->ci_calls += fromcip->ci_calls;
+ tocip->ci_etime += fromcip->ci_etime;
+ tocip->ci_utime += fromcip->ci_utime;
+ tocip->ci_stime += fromcip->ci_stime;
+ tocip->ci_mem += fromcip->ci_mem;
+ tocip->ci_io += fromcip->ci_io;
+}
+
+#ifdef __APPLE__
+static void
+print_ci(const struct cmdinfo *cip, const struct cmdinfo *totalcip)
+{
+ double t, c;
+ int uflow;
+
+ c = cip->ci_calls ? cip->ci_calls : 1;
+ t = (cip->ci_utime + cip->ci_stime) / (double) AHZ;
+ if (t < 0.01) {
+ t = 0.01;
+ uflow = 1;
+ } else
+ uflow = 0;
+
+ printf("%8ju ", (uintmax_t)cip->ci_calls);
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ",
+ cip->ci_calls / (double) totalcip->ci_calls);
+ else
+ printf(" %4s ", "");
+ }
+
+ if (jflag)
+ printf("%11.2fre ", cip->ci_etime / (double) (AHZ * c));
+ else
+ printf("%11.2fre ", cip->ci_etime / (60.0 * AHZ));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ",
+ cip->ci_etime / (double) totalcip->ci_etime);
+ else
+ printf(" %4s ", "");
+ }
+
+ if (!lflag) {
+ if (jflag)
+ printf("%11.2fcp ", t / (double) cip->ci_calls);
+ else
+ printf("%11.2fcp ", t / 60.0);
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ",
+ (cip->ci_utime + cip->ci_stime) / (double)
+ (totalcip->ci_utime + totalcip->ci_stime));
+ else
+ printf(" %4s ", "");
+ }
+ } else {
+ if (jflag)
+ printf("%11.2fu ", cip->ci_utime / (double) (AHZ * c));
+ else
+ printf("%11.2fu ", cip->ci_utime / (60.0 * AHZ));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ", cip->ci_utime / (double) totalcip->ci_utime);
+ else
+ printf(" %4s ", "");
+ }
+ if (jflag)
+ printf("%11.2fs ", cip->ci_stime / (double) (AHZ * c));
+ else
+ printf("%11.2fs ", cip->ci_stime / (60.0 * AHZ));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ", cip->ci_stime / (double) totalcip->ci_stime);
+ else
+ printf(" %4s ", "");
+ }
+ }
+
+ if (tflag) {
+ if (!uflow)
+ printf("%8.2fre/cp ",
+ cip->ci_etime /
+ (double) (cip->ci_utime + cip->ci_stime));
+ else
+ printf("*ignore* ");
+ }
+
+ if (Dflag)
+ printf("%10jutio ", (uintmax_t)cip->ci_io);
+ else
+ printf("%8.0favio ", cip->ci_io / c);
+
+ if (Kflag)
+ printf("%10juk*sec ", (uintmax_t)cip->ci_mem);
+ else
+ printf("%8.0fk ", cip->ci_mem / t);
+
+ printf(" %s\n", cip->ci_comm);
+}
+#else
+static void
+print_ci(const struct cmdinfo *cip, const struct cmdinfo *totalcip)
+{
+ double t, c;
+ int uflow;
+
+ c = cip->ci_calls ? cip->ci_calls : 1;
+ t = (cip->ci_utime + cip->ci_stime) / 1000000;
+ if (t < 0.01) {
+ t = 0.01;
+ uflow = 1;
+ } else
+ uflow = 0;
+
+ printf("%8ju ", (uintmax_t)cip->ci_calls);
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.1f%% ", cip->ci_calls /
+ (double)totalcip->ci_calls * 100);
+ else
+ printf(" %4s ", "");
+ }
+
+ if (jflag)
+ printf("%11.3fre ", cip->ci_etime / (1000000 * c));
+ else
+ printf("%11.3fre ", cip->ci_etime / (60.0 * 1000000));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.1f%% ", cip->ci_etime /
+ totalcip->ci_etime * 100);
+ else
+ printf(" %4s ", "");
+ }
+
+ if (!lflag) {
+ if (jflag)
+ printf("%11.3fcp ", t / (double) cip->ci_calls);
+ else
+ printf("%11.2fcp ", t / 60.0);
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.1f%% ",
+ (cip->ci_utime + cip->ci_stime) /
+ (totalcip->ci_utime + totalcip->ci_stime) *
+ 100);
+ else
+ printf(" %4s ", "");
+ }
+ } else {
+ if (jflag)
+ printf("%11.3fu ", cip->ci_utime / (1000000 * c));
+ else
+ printf("%11.2fu ", cip->ci_utime / (60.0 * 1000000));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.1f%% ", cip->ci_utime /
+ (double)totalcip->ci_utime * 100);
+ else
+ printf(" %4s ", "");
+ }
+ if (jflag)
+ printf("%11.3fs ", cip->ci_stime / (1000000 * c));
+ else
+ printf("%11.2fs ", cip->ci_stime / (60.0 * 1000000));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.1f%% ", cip->ci_stime /
+ (double)totalcip->ci_stime * 100);
+ else
+ printf(" %4s ", "");
+ }
+ }
+
+ if (tflag) {
+ if (!uflow)
+ printf("%8.2fre/cp ",
+ cip->ci_etime /
+ (cip->ci_utime + cip->ci_stime));
+ else
+ printf("*ignore* ");
+ }
+
+ if (Dflag)
+ printf("%10.0fio ", cip->ci_io);
+ else
+ printf("%8.0favio ", cip->ci_io / c);
+
+ if (Kflag)
+ printf("%10.0fk*sec ", cip->ci_mem);
+ else
+ printf("%8.0fk ", cip->ci_mem / t);
+
+ printf(" %s\n", cip->ci_comm);
+}
+#endif
\ No newline at end of file
--- /dev/null
+.\"
+.\" Copyright (c) 1994 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.
+.\" 3. 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.
+.\"
+.\" $FreeBSD: src/usr.sbin/sa/sa.8,v 1.20 2007/05/18 12:36:10 dds Exp $
+.\"
+.Dd May 18, 2007
+.Dt SA 8
+.Os
+.Sh NAME
+.Nm sa
+.Nd print system accounting statistics
+.Sh SYNOPSIS
+.Nm
+.Op Fl abcdDfijkKlmnqrstu
+.Op Fl P Ar file
+.Op Fl U Ar file
+.Op Fl v Ar cutoff
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility reports on, cleans up,
+and generally maintains system
+accounting files.
+.Pp
+The
+.Nm
+utility is able to condense the information in
+.Pa /var/account/acct
+into the summary files
+.Pa /var/account/savacct
+and
+.Pa /var/account/usracct ,
+which contain system statistics according
+to command name and login id, respectively.
+This condensation is desirable because on a
+large system,
+.Pa /var/account/acct
+can grow by hundreds of blocks per day.
+The summary files are normally read before
+the accounting file, so that reports include
+all available information.
+.Pp
+If file names are supplied, they are read instead of
+.Pa /var/account/acct .
+After each file is read, if the summary
+files are being updated, an updated summary will
+be saved to disk.
+Only one report is printed,
+after the last file is processed.
+.Pp
+The labels used in the output indicate the following, except
+where otherwise specified by individual options:
+.Bl -tag -width k*sec
+.It Dv avio
+Average number of I/O operations per execution
+.It Dv cp
+Sum of user and system time, in minutes
+.It Dv cpu
+Same as
+.Dv cp
+.It Dv k
+CPU-time averaged core usage, in 1k units
+.It Dv k*sec
+CPU storage integral, in 1k-core seconds
+.It Dv re
+Real time, in minutes
+.It Dv s
+System time, in minutes
+.It Dv tio
+Total number of I/O operations
+.It Dv u
+User time, in minutes
+.El
+.Pp
+The options to
+.Nm
+are:
+.Bl -tag -width Ds
+.It Fl a
+List all command names, including those containing unprintable
+characters and those used only once.
+By default,
+.Nm
+places all names containing unprintable characters and
+those used only once under the name ``***other''.
+.It Fl b
+If printing command statistics, sort output by the sum of user and system
+time divided by number of calls.
+.It Fl c
+In addition to the number of calls and the user, system and real times
+for each command, print their percentage of the total over all commands.
+.It Fl d
+If printing command statistics, sort by the average number of disk
+I/O operations.
+If printing user statistics, print the average number of
+disk I/O operations per user.
+.It Fl D
+If printing command statistics, sort and print by the total number
+of disk I/O operations.
+.It Fl f
+Force no interactive threshold comparison with the
+.Fl v
+option.
+.It Fl i
+Do not read in the summary files.
+.It Fl j
+Instead of the total minutes per category, give seconds per call.
+.It Fl k
+If printing command statistics, sort by the cpu-time average memory
+usage.
+If printing user statistics, print the cpu-time average
+memory usage.
+.It Fl K
+If printing command statistics, print and sort by the cpu-storage integral.
+.It Fl l
+Separate system and user time; normally they are combined.
+.It Fl m
+Print per-user statistics rather than per-command statistics.
+.It Fl n
+Sort by number of calls.
+.It Fl P Ar file
+Use the specified
+.Ar file
+for accessing the per-command accounting summary database,
+instead of the default
+.Pa /var/account/savacct .
+.It Fl q
+Create no output other than error messages.
+.It Fl r
+Reverse order of sort.
+.It Fl s
+Truncate the accounting files when done and merge their data
+into the summary files.
+.It Fl t
+For each command, report the ratio of real time to the sum
+of user and system cpu times.
+If the cpu time is too small to report, ``*ignore*'' appears in
+this field.
+.It Fl U Ar file
+Use the specified
+.Ar file
+for accessing the per-user accounting summary database,
+instead of the default
+.Pa /var/account/usracct .
+.It Fl u
+Superseding all other flags, for each entry
+in the accounting file, print the user ID, total seconds of cpu usage,
+total memory usage, number of I/O operations performed, and
+command name.
+.It Fl v Ar cutoff
+For each command used
+.Ar cutoff
+times or fewer, print the command name and await a reply
+from the terminal.
+If the reply begins with ``y'', add
+the command to the category ``**junk**''.
+This flag is
+used to strip garbage from the report.
+.El
+.Pp
+By default, per-command statistics will be printed.
+The number of
+calls, the total elapsed time in minutes, total cpu and user time
+in minutes, average number of I/O operations, and CPU-time
+averaged core usage will be printed.
+If the
+.Fl m
+option is specified, per-user statistics will be printed, including
+the user name, the number of commands invoked, total cpu time used
+(in minutes), total number of I/O operations, and CPU storage integral
+for each user.
+If the
+.Fl u
+option is specified, the uid, user and system time (in seconds),
+CPU storage integral, I/O usage, and command name will be printed
+for each entry in the accounting data file.
+.Pp
+If the
+.Fl u
+flag is specified, all flags other than
+.Fl q
+are ignored.
+If the
+.Fl m
+flag is specified, only the
+.Fl b ,
+.Fl d ,
+.Fl i ,
+.Fl k ,
+.Fl q ,
+and
+.Fl s
+flags are honored.
+.Sh FILES
+.Bl -tag -width /var/account/usracct -compact
+.It Pa /var/account/acct
+raw accounting data file
+.It Pa /var/account/savacct
+per-command accounting summary database
+.It Pa /var/account/usracct
+per-user accounting summary database
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr lastcomm 1 ,
+.Xr acct 5 ,
+.Xr ac 8 ,
+.Xr accton 8
+.Sh CAVEATS
+While the behavior of the options in this version of
+.Nm
+was modeled after the original version, there are some intentional
+differences and undoubtedly some unintentional ones as well.
+In
+particular, the
+.Fl q
+option has been added, and the
+.Fl m
+option now understands more options than it used to.
+.Pp
+The formats of the summary files created by this version of
+.Nm
+are very different from the those used by the original version.
+This is not considered a problem, however, because the accounting record
+format has changed as well (since user ids are now 32 bits).
+.Sh AUTHORS
+.An Chris G. Demetriou Aq cgd@postgres.berkeley.edu
+.Sh BUGS
+The number of options to this program is absurd, especially considering
+that there is not much logic behind their lettering.
+.Pp
+The field labels should be more consistent.
+.Pp
+The VM system does not record the CPU storage integral.
--- /dev/null
+/*
+ * Copyright (c) 1994 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/sa/usrdb.c,v 1.16 2007/05/22 06:51:38 dds Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "extern.h"
+#include "pathnames.h"
+
+static int uid_compare(const DBT *, const DBT *);
+
+static DB *usracct_db;
+
+/* Legacy format in AHZV1 units. */
+struct userinfov1 {
+ uid_t ui_uid; /* user id; for consistency */
+ u_quad_t ui_calls; /* number of invocations */
+ u_quad_t ui_utime; /* user time */
+ u_quad_t ui_stime; /* system time */
+ u_quad_t ui_mem; /* memory use */
+ u_quad_t ui_io; /* number of disk i/o ops */
+};
+
+/*
+ * Convert a v1 data record into the current version.
+ * Return 0 if OK, -1 on error, setting errno.
+ */
+static int
+v1_to_v2(DBT *key, DBT *data)
+{
+ struct userinfov1 uiv1;
+ static struct userinfo uiv2;
+ static uid_t uid;
+
+ if (key->size != sizeof(u_long) || data->size != sizeof(uiv1)) {
+ errno = EFTYPE;
+ return (-1);
+ }
+
+ /* Convert key. */
+ key->size = sizeof(uid_t);
+ uid = (uid_t)*(u_long *)(key->data);
+ key->data = &uid;
+
+ /* Convert data. */
+ memcpy(&uiv1, data->data, data->size);
+ memset(&uiv2, 0, sizeof(uiv2));
+ uiv2.ui_uid = uiv1.ui_uid;
+ uiv2.ui_calls = uiv1.ui_calls;
+ uiv2.ui_utime = ((double)uiv1.ui_utime / AHZV1) * 1000000;
+ uiv2.ui_stime = ((double)uiv1.ui_stime / AHZV1) * 1000000;
+ uiv2.ui_mem = uiv1.ui_mem;
+ uiv2.ui_io = uiv1.ui_io;
+ data->size = sizeof(uiv2);
+ data->data = &uiv2;
+
+ return (0);
+}
+
+/* Copy usrdb_file to in-memory usracct_db. */
+int
+usracct_init()
+{
+ BTREEINFO bti;
+
+ bzero(&bti, sizeof bti);
+ bti.compare = uid_compare;
+
+ return (db_copy_in(&usracct_db, usrdb_file, "user accounting",
+ &bti, v1_to_v2));
+}
+
+void
+usracct_destroy()
+{
+ db_destroy(usracct_db, "user accounting");
+}
+
+int
+usracct_add(const struct cmdinfo *ci)
+{
+ DBT key, data;
+ struct userinfo newui;
+ uid_t uid;
+ int rv;
+
+ uid = ci->ci_uid;
+ key.data = &uid;
+ key.size = sizeof uid;
+
+ rv = DB_GET(usracct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("get key %u from user accounting stats", uid);
+ return (-1);
+ } else if (rv == 0) { /* it's there; copy whole thing */
+ /* add the old data to the new data */
+ bcopy(data.data, &newui, data.size);
+ if (newui.ui_uid != uid) {
+ warnx("key %u != expected record number %u",
+ newui.ui_uid, uid);
+ warnx("inconsistent user accounting stats");
+ return (-1);
+ }
+ } else { /* it's not there; zero it and copy the key */
+ bzero(&newui, sizeof newui);
+ newui.ui_uid = ci->ci_uid;
+ }
+
+ newui.ui_calls += ci->ci_calls;
+ newui.ui_utime += ci->ci_utime;
+ newui.ui_stime += ci->ci_stime;
+ newui.ui_mem += ci->ci_mem;
+ newui.ui_io += ci->ci_io;
+
+ data.data = &newui;
+ data.size = sizeof newui;
+ rv = DB_PUT(usracct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("add key %u to user accounting stats", uid);
+ return (-1);
+ } else if (rv != 0) {
+ warnx("DB_PUT returned 1");
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* Copy in-memory usracct_db to usrdb_file. */
+int
+usracct_update()
+{
+ BTREEINFO bti;
+
+ bzero(&bti, sizeof bti);
+ bti.compare = uid_compare;
+
+ return (db_copy_out(usracct_db, usrdb_file, "user accounting",
+ &bti));
+}
+
+void
+usracct_print()
+{
+ DBT key, data;
+ struct userinfo uistore, *ui = &uistore;
+ double t;
+ int rv;
+
+ rv = DB_SEQ(usracct_db, &key, &data, R_FIRST);
+ if (rv < 0)
+ warn("retrieving user accounting stats");
+
+ while (rv == 0) {
+ memcpy(ui, data.data, sizeof(struct userinfo));
+
+ printf("%-*s %9ju ", MAXLOGNAME - 1,
+ user_from_uid(ui->ui_uid, 0), (uintmax_t)ui->ui_calls);
+
+#ifdef __APPLE__
+ t = (double) (ui->ui_utime + ui->ui_stime) /
+ (double) AHZ;
+ if (t < 0.0001) /* kill divide by zero */
+ t = 0.0001;
+
+ printf("%12.2f%s ", t / 60.0, "cpu");
+
+ /* ui->ui_calls is always != 0 */
+ if (dflag)
+ printf("%12ju%s",
+ (uintmax_t)(ui->ui_io / ui->ui_calls), "avio");
+ else
+ printf("%12ju%s", (uintmax_t)ui->ui_io, "tio");
+
+ /* t is always >= 0.0001; see above */
+ if (kflag)
+ printf("%12.0f%s", ui->ui_mem / t, "k");
+ else
+ printf("%12ju%s", (uintmax_t)ui->ui_mem, "k*sec");
+#else
+ t = (ui->ui_utime + ui->ui_stime) / 1000000;
+ if (t < 0.000001) /* kill divide by zero */
+ t = 0.000001;
+
+ printf("%12.2f%s ", t / 60.0, "cpu");
+
+ /* ui->ui_calls is always != 0 */
+ if (dflag)
+ printf("%12.0f%s",
+ ui->ui_io / ui->ui_calls, "avio");
+ else
+ printf("%12.0f%s", ui->ui_io, "tio");
+
+ /* t is always >= 0.000001; see above. */
+ if (kflag)
+ printf("%12.0f%s", ui->ui_mem / t, "k");
+ else
+ printf("%12.0f%s", ui->ui_mem, "k*sec");
+#endif
+
+ printf("\n");
+
+ rv = DB_SEQ(usracct_db, &key, &data, R_NEXT);
+ if (rv < 0)
+ warn("retrieving user accounting stats");
+ }
+}
+
+static int
+uid_compare(const DBT *k1, const DBT *k2)
+{
+ uid_t d1, d2;
+
+ bcopy(k1->data, &d1, sizeof d1);
+ bcopy(k2->data, &d2, sizeof d2);
+
+ if (d1 < d2)
+ return -1;
+ else if (d1 == d2)
+ return 0;
+ else
+ return 1;
+}
--- /dev/null
+.\"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
+.\"Reserved.
+.\"
+.\"This file contains Original Code and/or Modifications of Original Code
+.\"as defined in and that are subject to the Apple Public Source License
+.\"Version 2.0 (the 'License'). You may not use this file except in
+.\"compliance with the License. Please obtain a copy of the License at
+.\"http://www.opensource.apple.com/apsl/ and read it before using this
+.\"file.
+.\"
+.\"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.
+.\"
+.\" @(#)sa1.8
+.Dd Jul 25 2003 \" DATE
+.Dt sa1 8 \" Program name and manual section number
+.Os "Mac OS X"
+.Sh NAME \" Section Header - required - don't modify
+.Nm sa1
+.Nd Generate a system activity daily data file.
+.Sh SYNOPSIS \" Section Header - required - don't modify
+.Nm /usr/lib/sa/sa1
+.Op Ar t n \" [t n]
+.Sh DESCRIPTION \" Section Header - required - don't modify
+The
+.Nm sa1
+command is a shell script used to invoke the system
+activity data collector,
+.Nm sadc .
+The binary sample data is collected at intervals
+.Ar t
+seconds apart, in a loop
+.Ar n
+times.
+The binary sample data is written to the standard
+daily data file,
+.Ar /var/log/sa/sadd
+where the
+.Ar dd
+represents the current day of the month.
+.Pp \" Inserts a space
+.Nm sa1
+is intended to be started by cron.
+.Sh EXAMPLE CRON ENTRY
+.Bd -literal
+# Starting at 8am collect system activity records
+# every 20 minutes for 12 hours
+# 20 minutes = 1200 seconds
+# 12 hours with 3 samples each hour = 36 loops
+
+0 8 * * 1-5 /usr/lib/sa/sa1 1200 36
+
+
+# After the 12 hour period,
+# collect a system activity report
+
+30 20 * * 1-5 /usr/lib/sa/sa2 -A
+
+.Ed
+.Pp
+.Sh FILES \" File used or created by the topic of the man page
+.Bl -tag -width "/var/log/sa/sadd" -compact
+.It Pa /var/log/sa/sadd
+Default daily activity file that holds the binary sampling data.
+.Ar dd
+are digits that represent the day of the month.
+.El
+.Sh SEE ALSO
+.\" List links in ascending order by section, alphabetically within a section.
+.Xr crontab 1 ,
+.Xr fs_usage 1 ,
+.Xr netstat 1 ,
+.Xr sar 1 ,
+.Xr sc_usage 1 ,
+.Xr top 1 ,
+.Xr vm_stat 1 ,
+.Xr crontab 5 ,
+.Xr iostat 8 ,
+.Xr sa2 8 ,
+.Xr sadc 8
--- /dev/null
+#!/bin/sh
+# /usr/lib/sa/sa1.sh
+# Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
+# Reserved.
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# 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.
+#
+umask 0022
+DATE=`/bin/date +%d`
+ENDIR=/usr/lib/sa
+DFILE=/var/log/sa/sa${DATE}
+cd ${ENDIR}
+if [ $# = 0 ]
+then
+ exec ${ENDIR}/sadc 1 1 ${DFILE}
+else
+ exec ${ENDIR}/sadc $* ${DFILE}
+fi
--- /dev/null
+.\"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
+.\"Reserved.
+.\"
+.\"This file contains Original Code and/or Modifications of Original Code
+.\"as defined in and that are subject to the Apple Public Source License
+.\"Version 2.0 (the 'License'). You may not use this file except in
+.\"compliance with the License. Please obtain a copy of the License at
+.\"http://www.opensource.apple.com/apsl/ and read it before using this
+.\"file.
+.\"
+.\"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.
+.\"
+.\" @(#)sa2.8
+.Dd Jul 25 2003 \" DATE
+.Dt sa2 8 \" Program name and manual section number
+.Os "Mac OS X"
+.Sh NAME \" Section Header - required - don't modify
+.Nm sa2
+.Nd Generate a system activity daily report file.
+.Sh SYNOPSIS \" Section Header - required - don't modify
+.Nm /usr/lib/sa/sa2
+.Op Fl dgpu \" [-dgpu]
+.Op Fl n Ar mode \" [-n mode ]
+.Op Fl e Ar time \" [-e time]
+.Op Fl f Ar filename \" [-f filename]
+.Op Fl i Ar seconds \" [-i seconds]
+.Op Fl s Ar time \" [-s time]
+.Sh DESCRIPTION \" Section Header - required - don't modify
+The
+.Nm sa2
+command is a shell script used to invoke the system
+activity reporter
+.Nm sar
+for purposes of generating the standard default
+daily report file.
+The report file generated is,
+.Ar /var/log/sa/sardd
+where the
+.Ar dd
+represents the current day of the month.
+The
+.Nm sa2
+options are the same as those documented in
+.Nm sar(1) .
+.Pp \" Inserts a space
+When
+.Nm sa2
+runs, it will also remove data and report files,
+found in /var/log/sa, that are more than one week old.
+.Pp
+The
+.Nm sa2
+command is intended to be started by cron.
+.Pp
+.Sh EXAMPLE CRON ENTRY
+.Pp
+.Bd -literal
+# Starting at 8am collect system activity records
+# every 20 minutes for 12 hours
+# 20 minutes = 1200 seconds
+# 12 hours with 3 samples each hour = 36 loops
+
+0 8 * * 1-5 /usr/lib/sa/sa1 1200 36
+
+# After the 12 hour period,
+# collect a system activity report
+
+30 20 * * 1-5 /usr/lib/sa/sa2 -A
+
+.Ed
+.Pp
+.Sh FILES \" File used or created by the topic of the man page
+.Bl -tag -width "/var/log/sa/sardd" -compact
+.It Pa /var/log/sa/sardd
+Default daily report file.
+.It Pa /var/log/sa/sadd
+Default daily data file.
+.Pp
+.Ar dd
+are digits that represent the day of the month.
+.El
+.Sh SEE ALSO
+.\" List links in ascending order by section, alphabetically within a section.
+.Xr crontab 1 ,
+.Xr fs_usage 1 ,
+.Xr netstat 1 ,
+.Xr sar 1 ,
+.Xr sc_usage 1 ,
+.Xr top 1 ,
+.Xr vm_stat 1 ,
+.Xr crontab 5 ,
+.Xr iostat 8 ,
+.Xr sa1 8 ,
+.Xr sadc 8
--- /dev/null
+#!/bin/sh
+# /usr/lib/sa/sa2.sh
+# Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
+# Reserved.
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# 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.
+#
+umask 0022
+DATE=`/bin/date +%d`
+RPT=/var/log/sa/sar${DATE}
+ENDIR=/usr/bin
+DFILE=/var/log/sa/sa${DATE}
+[ -f "$DFILE" ] || exit 0
+cd ${ENDIR}
+${ENDIR}/sar $* -f ${DFILE} > ${RPT}
+/usr/bin/find /var/log/sa \( -name 'sar??' -o -name 'sa??' \) -mtime +7 -exec /bin/rm -f {} \;
--- /dev/null
+.\"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
+.\"Reserved.
+.\"
+.\"This file contains Original Code and/or Modifications of Original Code
+.\"as defined in and that are subject to the Apple Public Source License
+.\"Version 2.0 (the 'License'). You may not use this file except in
+.\"compliance with the License. Please obtain a copy of the License at
+.\"http://www.opensource.apple.com/apsl/ and read it before using this
+.\"file.
+.\"
+.\"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.
+.\"
+.\" @(#)sadc.8
+.Dd Jul 25 2003 \" DATE
+.Dt sadc 8 \" Program name and manual section number
+.Os "Mac OS X"
+.Sh NAME \" Section Header - required - don't modify
+.Nm sadc
+.Nd system activity data collector
+.Sh SYNOPSIS \" Section Header - required - don't modify
+.Nm /usr/lib/sa/sadc
+.Op Fl m Ar mode \" [-m mode]
+.Op Ar t n \" [t n]
+.Op Ar ofile \" [ofile]
+.Sh DESCRIPTION \" Section Header - required - don't modify
+The
+.Nm sadc
+tool is used to collect cumulative system activity data.
+The sample system data is collected at intervals
+.Ar t
+seconds apart, in a loop
+.Ar n
+times.
+The binary sample data is written to
+.Ar ofile
+if specified.
+Otherwise, the binary data is written to stdout.
+If the
+.Ar ofile
+file does not exist, it is created, otherwise it is truncated.
+.Pp \" Inserts a space
+.Nm sadc
+is intended to be used as the engine behind the
+.Nm sar(1)
+command, and is not typically invoked on the command line.
+Two shell scripts,
+.Nm sa1
+and
+.Nm sa2 ,
+are provided to drive the typical sampling, saving, and
+reporting process.
+.Pp
+.Sh OPTIONS
+The following options modify the way data is collected by
+.Nm sadc .
+.Bl -tag -width -indent \" Begins a tagged list
+.It Fl m Ar mode
+Modify the collection of system statistics as specified by
+.Ar mode .
+Currently only one mode is supported.
+.Bl -tag -width -indent \" Begins a tagged list
+.It PPP
+By default, the collection of ppp network interface statistics
+is turned off.
+This is because the number of ppp connections can be very high,
+causing the raw data file to grow unexpectedly large,
+especially when samples are collected at short intervals.
+Use the
+.Ar PPP
+mode to turn the collection back on.
+.El
+.El
+.Pp
+.Sh EXAMPLES
+/usr/lib/sa/sadc 15 20 /tmp/sample.out
+.Pp
+This call collects 20 samples at 15 second intervals.
+The binary data is written to the /tmp/sample.out file
+.Sh FILES \" File used or created by the topic of the man page
+.Bl -tag -width "/var/log/sa/sadd" -compact
+.It Pa /var/log/sa/sadd
+Default daily activity file that holds the binary sampling data.
+.Ar dd
+are digits that represent the day of the month.
+.It Pa /usr/lib/sa/sa1
+Shell script used to drive the
+.Nm sar
+data collection.
+.It Pa /usr/lib/sa/sa2
+Shell script used to drive the
+.Nm sar
+data reporting.
+.El
+.Sh SEE ALSO
+.\" List links in ascending order by section, alphabetically within a section.
+.Xr fs_usage 1 ,
+.Xr netstat 1 ,
+.Xr sar 1 ,
+.Xr sc_usage 1 ,
+.Xr top 1 ,
+.Xr vm_stat 1 ,
+.Xr iostat 8 ,
+.Xr sa1 8 ,
+.Xr sa2 8
--- /dev/null
+/*
+ * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
+ * Reserved.
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * 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.
+*/
+
+#define IOKIT 1 /* to get io_name_t in device_types.h */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+#include <err.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <sys/param.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/storage/IOBlockStorageDriver.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/IOBSD.h>
+
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <ifaddrs.h>
+
+#include <sadc.h>
+
+extern int errno;
+
+FILE *data_fp = (FILE *)0; /* raw data output file pointer */
+
+
+#define REVISION_HISTORY_DATE 20030718
+
+struct record_hdr restart_record = { SAR_RESTART, REVISION_HISTORY_DATE, 0, 0 };
+struct record_hdr timestamp_record = { SAR_TIMESTAMP, 1, 0, 0 };
+struct record_hdr vmstat_record = {SAR_VMSTAT, 1, 1, 0 };
+struct record_hdr cpu_record = {SAR_CPU, 1, 1, 0 };
+struct record_hdr drivestats_record = {SAR_DRIVESTATS, 1, 0, 0 };
+struct record_hdr drivepath_record = {SAR_DRIVEPATH, 1, 1, 0 };
+struct record_hdr netstats_record = {SAR_NETSTATS, 1, 0, 0};
+
+/* Compile for verbose output */
+
+int t_interval = 0; /* in seconds */
+int n_samples = 1; /* number of sample loops */
+char *ofile = NULL; /* output file */
+int ofd; /* output file descriptor */
+static mach_port_t myHost;
+static mach_port_t masterPort;
+
+/* internal table of drive path mappings */
+struct drivepath *dp_table = NULL;
+
+/* number of entries in the dp_table */
+int dp_count = 0;
+
+/* internal table of network interface statistics */
+struct netstats *ns_table = NULL;
+int ns_count = 0;
+
+static uid_t realuid;
+
+int network_mode = 0;
+
+/* Forward fuction declarations */
+static void exit_usage();
+static void open_datafile(char *);
+static void write_record_hdr(struct record_hdr *);
+static void write_record_data(char *, int);
+static void get_all_stats();
+static void get_vmstat_sample();
+static void get_drivestat_sample();
+static int get_ndrives();
+static int record_device(io_registry_entry_t, struct drivestats *, int ndrives);
+static int check_device_path (char *name, char *path, int ndrives);
+static void get_netstat_sample(int pppflag);
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ char *p;
+ char ch;
+
+ /*
+ * Stop being root ASAP.
+ */
+ if (geteuid() != 0)
+ {
+ fprintf(stderr, "sadc: must be setuid root or root");
+ exit(1);
+ }
+
+ realuid = getuid();
+ seteuid(realuid);
+
+ setvbuf(stdout, (char *)NULL, _IONBF, 0);
+
+ while ((ch=getopt(argc, argv, "m:")) != EOF) {
+ switch(ch) {
+ case 'm':
+ /* Only the PPP mode matters on this collector side */
+ /* The reporter side deals with the DEV or EDEV modes */
+ if (!strncmp(optarg, "PPP", 3))
+ network_mode |= NET_PPP_MODE;
+ break;
+ default:
+ exit_usage();
+ break;
+ }
+ }
+
+ argc -= optind;
+ if (argc > 0)
+ {
+ if (isdigit(*argv[optind]))
+ {
+ /* we expect to have both an interval and a sample count */
+ errno=0;
+ t_interval = strtol(argv[optind], &p, 0);
+ if (errno || (*p !='\0') || t_interval <= 0)
+ {
+ exit_usage();
+ }
+
+ optind++;
+ if ((argc < 2) || (!isdigit(*argv[optind]))) {
+ exit_usage();
+ }
+
+ errno=0;
+ n_samples = strtol(argv[optind], &p, 0);
+ if (errno || (*p != '\0') || n_samples <= 0)
+ {
+ exit_usage();
+ }
+
+ optind++;
+ if (argc == 3)
+ {
+ /* we have an output file */
+ ofile = argv[optind];
+ }
+ }
+ else
+ {
+ /* all we have is an output file */
+ ofile = argv[optind];
+ }
+ }
+
+
+ /* open the output file */
+ (void)open_datafile(ofile);
+
+ /*
+ * Get the Mach private port.
+ */
+ myHost = mach_host_self();
+
+ /*
+ * Get the I/O Kit communication handle.
+ */
+ IOMasterPort(bootstrap_port, &masterPort);
+
+
+ restart_record.rec_timestamp = time((time_t *)0);
+ write_record_hdr(&restart_record);
+ get_all_stats(); /* this is the initial stat collection */
+ sleep(t_interval);
+
+ if (n_samples > 0)
+ {
+ /* this init sample is not counted */
+ timestamp_record.rec_data = time((time_t *)0); /* returns time in
+ * seconds */
+#if 0
+ struct tm *tm;
+ tm = gmtime(&(timestamp_record.rec_data));
+ fprintf(stderr, "timestamp=%ld\n", timestamp_record.rec_data);
+ fprintf(stderr, "GMTIME offset from UTC in seconds = %ld\n", tm->tm_gmtoff);
+ fprintf(stderr, "GMTIME secnds=%d, min=%d, hour=%d\n", tm->tm_sec, tm->tm_min, tm->tm_hour);
+ fprintf(stderr, "asctime = %s\n", asctime(tm));
+
+ tm=localtime(&(timestamp_record.rec_data));
+ fprintf(stderr, "LOCTIME offset from UTC in seconds = %ld\n",tm->tm_gmtoff);
+ fprintf(stderr, "LOCTIME secnds=%d, min=%d, hour=%d\n", tm->tm_sec, tm->tm_min, tm->tm_hour);
+ fprintf(stderr, "asctime = %s\n", asctime(tm));
+#endif
+
+ write_record_hdr(×tamp_record);
+ get_all_stats();
+ }
+
+ while (n_samples)
+ {
+ sleep(t_interval);
+ timestamp_record.rec_timestamp = time((time_t *)0); /* returns time in
+ * seconds */
+ write_record_hdr(×tamp_record);
+ get_all_stats();
+ n_samples--;
+ }
+ exit(EXIT_SUCCESS);
+}
+
+static void
+exit_usage()
+{
+ fprintf(stderr, "/usr/lib/sa/sadc [-m {PPP}] [t n] [ofile]\n");
+ exit(EXIT_FAILURE);
+}
+
+static void
+open_datafile(char *path)
+{
+ if (path == NULL)
+ {
+ data_fp = stdout;
+ return;
+ }
+ else
+ data_fp = fopen(path, "w+");
+
+ if (!data_fp)
+ {
+ /* failed to open path */
+ fprintf(stderr, "sadc: failed to open data file [%s]\n", path?path:"stdout");
+ exit_usage();
+ }
+}
+
+static void
+write_record_hdr(hdr)
+ struct record_hdr *hdr;
+{
+ errno = 0;
+
+ if (fwrite(hdr, sizeof(struct record_hdr), 1, data_fp) != 1)
+ {
+ fprintf(stderr, "sadc: write_record_hdr failed, errno=%d\n", errno);
+ exit(EXIT_FAILURE);
+ }
+
+ fflush(data_fp);
+ return;
+}
+
+static void
+write_record_data(data, size)
+ char *data;
+ int size;
+{
+ errno = 0;
+
+ if (fwrite(data, size, 1, data_fp) != 1)
+ {
+ fprintf(stderr, "sadc: write_record_data failed, errno=%d\n", errno);
+ exit(EXIT_FAILURE);
+ }
+
+ fflush(data_fp);
+ return;
+}
+
+
+static void
+get_vmstat_sample()
+{
+ struct vm_statistics stat;
+ kern_return_t error;
+ mach_msg_type_number_t count;
+
+ count = HOST_VM_INFO_COUNT;
+ error = host_statistics(myHost, HOST_VM_INFO, (host_info_t)&stat, &count);
+ if (error != KERN_SUCCESS) {
+ fprintf(stderr, "sadc: Error in vm host_statistics(): %s\n",
+ mach_error_string(error));
+ exit(2);
+ }
+
+ vmstat_record.rec_count = 1;
+ vmstat_record.rec_size = sizeof(vm_statistics_data_t);
+ write_record_hdr(&vmstat_record);
+ write_record_data((char *)&stat, sizeof(vm_statistics_data_t));
+}
+
+static void
+get_cpu_sample()
+{
+ host_cpu_load_info_data_t cpuload;
+ kern_return_t error;
+ mach_msg_type_number_t count;
+
+ count = HOST_CPU_LOAD_INFO_COUNT;
+ error = host_statistics(myHost, HOST_CPU_LOAD_INFO,(host_info_t)&cpuload, &count);
+ if (error != KERN_SUCCESS) {
+ fprintf(stderr, "sadc: Error in cpu host_statistics(): %s",
+ mach_error_string(error));
+ exit(2);
+ }
+
+ cpu_record.rec_count = 1;
+ cpu_record.rec_size = sizeof(host_cpu_load_info_data_t);
+ write_record_hdr(&cpu_record);
+ write_record_data((char *)&cpuload, sizeof(host_cpu_load_info_data_t));
+}
+
+static void
+get_drivestat_sample()
+{
+ io_registry_entry_t drive;
+ io_iterator_t drivelist;
+ CFMutableDictionaryRef match;
+ int ndrives;
+ int i = 0;
+ long bufsize = 0;
+ char *buf;
+ struct drivestats *dbuf;
+ kern_return_t status;
+ int error;
+
+ if ((ndrives = get_ndrives()) <= 0)
+ return;
+
+ /* allocate space to collect stats for all the drives */
+ bufsize = ndrives * sizeof(struct drivestats);
+ buf = (char *) malloc (bufsize);
+ dbuf = (struct drivestats *)buf;
+ if (buf)
+ bzero((char *)buf, bufsize);
+ else
+ return;
+
+ /*
+ * Get an iterator for IOMedia objects.
+ */
+ match = IOServiceMatching("IOMedia");
+
+ /* Get whole disk info */
+ CFDictionaryAddValue(match, CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
+
+ status = IOServiceGetMatchingServices(masterPort, match, &drivelist);
+ if (status != KERN_SUCCESS)
+ goto RETURN;
+
+ /*
+ * Scan all of the IOMedia objects, and for each
+ * object that has a parent IOBlockStorageDriver,
+ * record the statistics
+ *
+ * XXX What about RAID devices?
+ */
+ error = 1;
+ i = 0;
+ while ((drive = IOIteratorNext(drivelist)))
+ {
+ if (i < ndrives)
+ {
+ if (record_device(drive, &dbuf[i], ndrives))
+ {
+ error = 0;
+ i++;
+ }
+ }
+ else
+ {
+ IOObjectRelease(drive);
+ break;
+ }
+ IOObjectRelease(drive);
+ }
+ IOObjectRelease(drivelist);
+
+ if (! error)
+ {
+ drivestats_record.rec_count = i;
+ drivestats_record.rec_size = sizeof (struct drivestats);
+ write_record_hdr(&drivestats_record);
+ write_record_data((char *)buf, (i * sizeof(struct drivestats)));
+ }
+
+ RETURN:
+ if (buf)
+ free(buf);
+ return;
+}
+
+/*
+ * Determine whether an IORegistryEntry refers to a valid
+ * I/O device, and if so, record it.
+ * Return zero: no device recorded
+ * Return non-zero: device stats recorded
+ */
+static int
+record_device(io_registry_entry_t drive, struct drivestats* drivestat, int ndrives)
+{
+ io_registry_entry_t parent;
+ CFDictionaryRef properties, statistics;
+ CFStringRef name;
+ CFNumberRef number;
+ UInt64 value;
+ kern_return_t status;
+ int retval = 0;
+ int drive_id;
+ io_string_t path;
+ char BSDName[MAXDRIVENAME + 1];
+
+ status = IORegistryEntryGetParentEntry(drive, kIOServicePlane, &parent);
+ if (status != KERN_SUCCESS)
+ {
+ /* device has no parent */
+ return(retval);
+ }
+
+ if (IOObjectConformsTo(parent, "IOBlockStorageDriver"))
+ {
+ /*
+ * Get a unique device path identifier.
+ * Devices available at boot have an Open Firmware Device Tree path.
+ * The OF path is short and concise and should be first choice.
+ * Devices that show up after boot, are guaranteed to have
+ * a Service Plane, hardware unique path.
+ */
+
+ bzero(path, sizeof(io_string_t));
+ if (IORegistryEntryGetPath(drive, kIODeviceTreePlane, path) != KERN_SUCCESS)
+ {
+ if(IORegistryEntryGetPath(drive, kIOServicePlane, path) != KERN_SUCCESS)
+ /* device has no unique path identifier */
+ goto RETURN;
+ }
+ retval++;
+
+ /* get drive properties */
+ status = IORegistryEntryCreateCFProperties(drive,
+ (CFMutableDictionaryRef *)&properties,
+ kCFAllocatorDefault,
+ kNilOptions);
+ if (status != KERN_SUCCESS)
+ {
+ /* device has no properties */
+ goto RETURN;
+ }
+
+ bzero(BSDName, MAXDRIVENAME+1);
+ /* get name from properties */
+ name = (CFStringRef)CFDictionaryGetValue(properties,
+ CFSTR(kIOBSDNameKey));
+ if (name) {
+ CFStringGetCString(name, BSDName,
+ MAXDRIVENAME, kCFStringEncodingUTF8);
+ retval++;
+ }
+
+ /* get blocksize from properties */
+ number = (CFNumberRef)CFDictionaryGetValue(properties,
+ CFSTR(kIOMediaPreferredBlockSizeKey));
+ if (number != 0) {
+ CFNumberGetValue(number,
+ kCFNumberSInt64Type, &value);
+ drivestat->blocksize = value;
+ retval++;
+ }
+ CFRelease(properties);
+ }
+ else
+ goto RETURN;
+
+ /* we should have a name and blocksize at a minimum */
+ if (retval != 3)
+ {
+ retval = FALSE;
+ goto RETURN;
+ }
+
+ drive_id = check_device_path (BSDName, path, ndrives);
+ if (drive_id == -1)
+ {
+ retval = FALSE;
+ goto RETURN;
+ }
+ else
+ drivestat->drivepath_id = drive_id;
+
+
+ /* get parent drive properties */
+ status = IORegistryEntryCreateCFProperties(parent,
+ (CFMutableDictionaryRef *)&properties,
+ kCFAllocatorDefault,
+ kNilOptions);
+ if (status != KERN_SUCCESS)
+ {
+ /* device has no properties */
+ goto RETURN;
+ }
+
+ /* Obtain the statistics from the parent drive properties. */
+
+ statistics
+ = (CFDictionaryRef)CFDictionaryGetValue(properties,
+ CFSTR(kIOBlockStorageDriverStatisticsKey));
+
+ if (statistics != 0)
+ {
+ /* Get number of reads. */
+ number =
+ (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsReadsKey));
+ if (number != 0) {
+ CFNumberGetValue(number,
+ kCFNumberSInt64Type, &value);
+ drivestat->Reads = value;
+ }
+
+ /* Get bytes read. */
+ number =
+ (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey));
+ if (number != 0) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ drivestat->BytesRead = value;
+ }
+
+ /* Get number of writes. */
+ number =
+ (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsWritesKey));
+ if (number != 0) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ drivestat->Writes = value;
+ }
+
+ /* Get bytes written. */
+ number =
+ (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey));
+ if (number != 0) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ drivestat->BytesWritten = value;
+ }
+
+ /* Get LatentReadTime. */
+ number =
+ (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsLatentReadTimeKey));
+ if (number != 0) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ drivestat->LatentReadTime = value;
+ }
+
+ /* Get LatentWriteTime. */
+ number =
+ (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsLatentWriteTimeKey));
+ if (number != 0) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ drivestat->LatentWriteTime = value;
+ }
+
+ /* Get ReadErrors. */
+ number =
+ (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsReadErrorsKey));
+ if (number != 0) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ drivestat->ReadErrors = value;
+ }
+
+ /* Get WriteErrors. */
+ number =
+ (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsWriteErrorsKey));
+ if (number != 0) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ drivestat->WriteErrors = value;
+ }
+
+ /* Get ReadRetries. */
+ number =
+ (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsReadRetriesKey));
+ if (number != 0) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ drivestat->ReadRetries = value;
+ }
+
+ /* Get WriteRetries. */
+ number =
+ (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsWriteRetriesKey));
+ if (number != 0) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ drivestat->WriteRetries = value;
+ }
+
+ /* Get TotalReadTime. */
+ number =
+ (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey));
+ if (number != 0) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ drivestat->TotalReadTime = value;
+ }
+
+ /* Get WriteRetries. */
+ number =
+ (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey));
+ if (number != 0) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ drivestat->TotalWriteTime = value;
+ }
+
+ CFRelease(properties);
+ } /* end if statistics != 0 */
+
+ RETURN:
+ IOObjectRelease(parent);
+ return(retval);
+}
+
+
+/*
+ * find IOMedia objects
+ * This routine always gives me a lower count on the number
+ * of disks. I don't know which one to use.
+ */
+static int
+get_ndrives(void)
+{
+ io_iterator_t drivelist;
+ io_registry_entry_t drive;
+ io_registry_entry_t parent;
+ CFMutableDictionaryRef match;
+ int error, ndrives;
+ kern_return_t status;
+
+ /*
+ * Get an iterator for IOMedia objects.
+ */
+ match = IOServiceMatching("IOMedia");
+ CFDictionaryAddValue(match, CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
+ status = IOServiceGetMatchingServices(masterPort, match, &drivelist);
+ if (status != KERN_SUCCESS)
+ return(0);
+
+ /*
+ * Scan all of the IOMedia objects, and count each
+ * object that has a parent IOBlockStorageDriver
+ *
+ * XXX What about RAID devices?
+ */
+ error = 1;
+ ndrives = 0;
+ while ((drive = IOIteratorNext(drivelist)))
+ {
+ /* get drive's parent */
+ status = IORegistryEntryGetParentEntry(drive,
+ kIOServicePlane, &parent);
+ if (status != KERN_SUCCESS)
+ {
+ IOObjectRelease(drive);
+ continue;
+ }
+
+ if (IOObjectConformsTo(parent, "IOBlockStorageDriver"))
+ {
+ error = 0;
+ ndrives++;
+ }
+ IOObjectRelease(parent);
+ IOObjectRelease(drive);
+ }
+
+ IOObjectRelease(drivelist);
+
+ return(ndrives);
+}
+
+
+/*
+ * When getting the stats, do it in the order
+ * of their type. The types that have the most
+ * data come first in the list if possible.
+ * This makes the sar reporter tool more efficient,
+ * because in some cases, it will allocate a buffer
+ * and keep reusing it as long as the sample data fits.
+ * When a sample data doesn't fit, it reallocates the buffer
+ * to a bigger size etc.
+ */
+void
+get_all_stats()
+{
+
+ get_drivestat_sample();
+ get_netstat_sample(network_mode);
+ get_vmstat_sample();
+ get_cpu_sample();
+}
+
+
+/*
+ * An internal table maps the BSDName to a unique ioregistry path.
+ * The table's index is then used as a unique compressed path, and
+ * helps track disks that come and go during the sampling intervals.
+ * This routine finds an entry that maps both the BSDName and the
+ * IOKit registry path. If no mapping is discovered, a new entry
+ * is created. An entry is never removed, this maintaining the
+ * unique index throughout the data collection.
+ * Success returns the map index. Failure returns -1.
+ */
+static int
+check_device_path (char *name, char *path, int ndrives)
+{
+ int i;
+ int index;
+ int n;
+
+ if (dp_table == NULL)
+ {
+ /* First setup of internal drivepath table */
+ dp_table = (struct drivepath *)malloc (ndrives * sizeof(struct drivepath));
+ if (dp_table == NULL)
+ return(-1);
+ else
+ {
+ bzero(dp_table, (ndrives * sizeof(struct drivepath)));
+ dp_count = ndrives;
+ drivepath_record.rec_size = sizeof(struct drivepath);
+ }
+ }
+
+ for (i=0; i < dp_count; i++)
+ {
+ if (dp_table[i].state == DPSTATE_UNINITIALIZED)
+ {
+ /* This is a new drive entry that should be recorded */
+ index = i;
+ goto NEW_ENTRY;
+ }
+ else if (!strcmp (dp_table[i].ioreg_path, path))
+ {
+ /* Found a matching hardware path */
+ if (!strcmp(dp_table[i].BSDName, name))
+ {
+ /* The BSDName matches the entry in the table
+ * so there is no need to record this data.
+ */
+ return(i);
+ }
+ else
+ {
+ /* The BSDName is different ... implies a change,
+ * like the drive was removed and now is back
+ */
+ bzero((char *)dp_table[i].BSDName, MAXDRIVENAME+1);
+ dp_table[i].drivepath_id = i;
+ dp_table[i].state = DPSTATE_CHANGED;
+ strcpy(dp_table[i].BSDName, name);
+ write_record_hdr(&drivepath_record);
+ write_record_data((char *)&dp_table[i], sizeof(struct drivepath));
+ return(i);
+ }
+ }
+ } /* end for loop */
+
+ /*
+ * If we reach this point, then we've run out of
+ * table entries. Double the size of the table.
+ */
+ n = dp_count * 2;
+ dp_table = (struct drivepath *)realloc(dp_table, n * sizeof(struct drivepath));
+ bzero(&dp_table[dp_count], dp_count * sizeof(struct drivepath));
+ index = dp_count;
+ dp_count = n;
+
+ /* This is a new drive entry that should be recorded */
+ NEW_ENTRY:
+ dp_table[index].drivepath_id = index;
+ dp_table[index].state = DPSTATE_NEW;
+ strcpy(dp_table[index].BSDName, name);
+ strcpy(dp_table[index].ioreg_path, path);
+ write_record_hdr(&drivepath_record);
+ write_record_data((char *)&dp_table[index], sizeof(struct drivepath));
+ return(index);
+}
+
+
+
+/*
+ * Thus far, only the networking stats take an optional flag
+ * to modify the collection of data. The number of ppp
+ * interfaces can be very high, causing the raw data file to
+ * grow very large. We want this option to include ppp
+ * statistics to be off by default. When we see the -m PPP
+ * mode passed in, ppp collection will be turned on.
+ */
+static void
+get_netstat_sample(int mode)
+{
+
+ int n;
+ int ns_index = 0;
+ char tname[MAX_TNAME_SIZE + 1];
+ char name[MAX_TNAME_UNIT_SIZE + 1];
+ struct ifaddrs *ifa_list, *ifa;
+
+
+ /*
+ * Set the starting table size to 100 entries
+ * That should be big enough for most cases,
+ * even with a lot of ppp connections.
+ */
+ ns_count = 100;
+ ns_table = (struct netstats *) malloc(ns_count * sizeof (struct netstats));
+ if (ns_table == NULL)
+ {
+ fprintf(stderr, "sadc: malloc netstat table failed\n");
+ return;
+ }
+
+ bzero(ns_table, ns_count * sizeof(struct netstats));
+ if (getifaddrs(&ifa_list) == -1)
+ return;
+
+ for (ifa = ifa_list; ifa; ifa = ifa->ifa_next)
+ {
+ struct if_data *if_data = (struct if_data *)ifa->ifa_data;
+
+ if (AF_LINK != ifa->ifa_addr->sa_family)
+ continue;
+ if (ifa->ifa_data == 0)
+ continue;
+ tname[MAX_TNAME_SIZE] = '\0';
+ if (!(network_mode & NET_PPP_MODE))
+ {
+ /*
+ * If the flag is set, include PPP connections.
+ * By default this collection is turned off
+ */
+ if(!strncmp(ifa->ifa_name, "ppp", 3))
+ continue;
+ }
+ snprintf(name, MAX_TNAME_UNIT_SIZE, "%s", ifa->ifa_name);
+ name[MAX_TNAME_UNIT_SIZE] = '\0';
+
+ if (ns_index == ns_count)
+ {
+ /* the stat table needs to grow */
+ n = ns_count * 2;
+ ns_table = (struct netstats *)realloc(ns_table, n * sizeof(struct netstats));
+ bzero(&ns_table[ns_count], ns_count * sizeof(struct netstats));
+ ns_count = n;
+ }
+
+ /*
+ * As a means of helping to identify when interface unit numbers
+ * are reused, a generation counter may eventually be implemented.
+ * This will be especially helpful with ppp-x connections.
+ * In anticipation, we will reserve a space for it, but always
+ * set it to zero for now.
+ */
+ ns_table[ns_index].gen_counter = 0;
+
+ strncpy(ns_table[ns_index].tname_unit, name, MAX_TNAME_UNIT_SIZE);
+ ns_table[ns_index].tname_unit[MAX_TNAME_UNIT_SIZE] = '\0';
+ ns_table[ns_index].net_ipackets = if_data->ifi_ipackets;
+ ns_table[ns_index].net_ierrors = if_data->ifi_ierrors;
+ ns_table[ns_index].net_opackets = if_data->ifi_opackets;
+ ns_table[ns_index].net_oerrors = if_data->ifi_oerrors;
+ ns_table[ns_index].net_collisions = if_data->ifi_collisions;
+ ns_table[ns_index].net_ibytes = if_data->ifi_ibytes;
+ ns_table[ns_index].net_obytes = if_data->ifi_obytes;
+ ns_table[ns_index].net_imcasts = if_data->ifi_imcasts;
+ ns_table[ns_index].net_omcasts = if_data->ifi_omcasts;
+ ns_table[ns_index].net_drops = if_data->ifi_iqdrops;
+ ns_index++;
+ } /* end for */
+
+ netstats_record.rec_count = ns_index;
+ netstats_record.rec_size = sizeof(struct netstats);
+ write_record_hdr(&netstats_record);
+ write_record_data((char *)ns_table, (ns_index * sizeof(struct netstats)));
+ return;
+}
--- /dev/null
+/*
+ * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
+ * Reserved.
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * 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.
+*/
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/storage/IOBlockStorageDriver.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/IOBSD.h>
+
+/* record types in sadc raw data output */
+
+#define SAR_NOTSET 0
+#define SAR_RESTART 1
+#define SAR_TIMESTAMP 2
+#define SAR_NETSTATS 3
+#define SAR_DRIVEPATH 4
+#define SAR_DRIVESTATS 5
+#define SAR_VMSTAT 6
+#define SAR_CPU 7
+
+struct record_hdr
+{
+ int32_t rec_type;
+ int32_t rec_version;
+ int32_t rec_count;
+ int32_t rec_size;
+};
+
+#define rec_data rec_size
+#define rec_timestamp rec_size
+
+#define MAXDRIVENAME 31 /* largest drive name we allow */
+
+#define DPSTATE_UNINITIALIZED 0
+#define DPSTATE_NEW 1
+#define DPSTATE_CHANGED 2
+#define DPSTATE_ACTIVE 3
+
+struct drivepath
+{
+ int32_t drivepath_id; /* compressed table id */
+ int32_t state;
+ char BSDName[MAXDRIVENAME + 1];
+ io_string_t ioreg_path; /* unique id, hardware path */
+};
+
+
+struct drivestats
+{
+ io_registry_entry_t driver;
+
+ int32_t drivepath_id;
+ uint64_t blocksize;
+
+ uint64_t Reads;
+ uint64_t BytesRead;
+
+ uint64_t Writes;
+ uint64_t BytesWritten;
+
+ uint64_t LatentReadTime;
+ uint64_t LatentWriteTime;
+
+ uint64_t ReadErrors;
+ uint64_t WriteErrors;
+
+ uint64_t ReadRetries;
+ uint64_t WriteRetries;
+
+ uint64_t TotalReadTime;
+ uint64_t TotalWriteTime;
+};
+
+
+/*
+ * netstat mode drives the
+ * collection of ppp interface data
+ */
+
+#define NET_DEV_MODE 0x1 /* Turn on network interface counters */
+#define NET_EDEV_MODE 0x2 /* Turn on network interface error counters */
+#define NET_PPP_MODE 0x4 /* Include ppp interface counters - further
+ * modifies NET_DEV_MODE and NET_EDEV_MODE */
+
+#define MAX_TNAME_SIZE 15
+#define MAX_TNAME_UNIT_SIZE 23
+
+struct netstats
+{
+ char tname_unit[MAX_TNAME_UNIT_SIZE + 1];
+ uint32_t gen_counter; /* unit generation counter */
+
+ uint64_t net_ipackets;
+ uint64_t net_ierrors;
+ uint64_t net_opackets;
+ uint64_t net_oerrors;
+ uint64_t net_collisions;
+ uint64_t net_ibytes;
+ uint64_t net_obytes;
+ uint64_t net_imcasts;
+ uint64_t net_omcasts;
+ uint64_t net_drops;
+};
--- /dev/null
+.\"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
+.\"Reserved.
+.\"
+.\"This file contains Original Code and/or Modifications of Original Code
+.\"as defined in and that are subject to the Apple Public Source License
+.\"Version 2.0 (the 'License'). You may not use this file except in
+.\"compliance with the License. Please obtain a copy of the License at
+.\"http://www.opensource.apple.com/apsl/ and read it before using this
+.\"file.
+.\"
+.\"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.
+.\"
+.\" @(#)sadc.8
+
+.Dd Jul 25, 2003 \" DATE
+.Dt sar 1 \" Program name and manual section number
+.Os "Mac OS X"
+.Sh NAME \" Section Header - required - don't modify
+.Nm sar
+.Nd system activity reporter
+.Sh SYNOPSIS \" Section Header - required - don't modify
+.Nm sar
+.Op Fl dgpu \" [-dgpu]
+.Op Fl n Ar mode \" [-n mode]
+.Op Fl o Ar filename \" [-o filename]
+t \" t
+.Op Ar n \" [ n ]
+.Nm sar
+.Op Fl dgpu \" [-dgpu]
+.Op Fl n Ar mode \" [-n mode]
+.Op Fl e Ar time \" [-e time]
+.Op Fl f Ar filename \" [-f filename]
+.Op Fl i Ar seconds \" [-i seconds]
+.Op Fl s Ar time \" [-s time]
+.Sh DESCRIPTION \" Section Header - required - don't modify
+The
+.Nm sar
+command is used to sample and report various cumulative statistic counters
+maintained by the operating system.
+It can be invoked in two different ways.
+.Pp
+In the first usage instance,
+.Ar n
+samples are reported at
+.Ar t
+second intervals.
+If
+.Ar n
+is not specified, only one sample will be captured.
+When the -o option is specified,
+.Nm sar
+will write the binary sampling data to the output file specified by
+.Ar filename .
+.Pp
+In the second usage instance,
+there is no on-going sample interval to specify.
+This is because the sampling input comes
+from a previously recorded, binary activity file.
+The binary activity file can be specified using the
+.Fl f Ar filename
+option.
+When the
+.Fl f
+option isn't used,
+.Nm sar
+attempts to open a default binary activity file,
+/var/log/sa/sadd, where
+.Ar dd
+represents the current day of the month.
+.Pp
+The starting and ending time of the report can be restricted using the
+.Fl e
+and
+.Fl s
+options. Here, the
+.Ar time
+field is specified in the form hh[:mm[:ss]].
+.Pp
+Finally, the
+.Fl i
+option can be used to select the sampling interval.
+Only records at least
+.Ar seconds
+apart will be reported.
+When the
+.Fl i
+option is not used,
+all of the previously recorded interval samples are reported.
+.Pp
+Due to the nature of on-going sample collection,
+the data is reported in a verbose mode
+when more than one sampling option is specified.
+Column headers are printed at the beginning of the report;
+averages are printed when the
+.Nm sar
+command terminates.
+.Sh OPTIONS
+The following options restrict the sample set that
+.Nm sar
+reports.
+.Pp \" Inserts a space
+.Bl -tag -width -indent \" Differs from above in tag removed
+.It Fl d
+Report disk activity.
+.Pp
+.Bl -tag -width -indent \" Begins a tagged list
+.It device
+The BSD name of the device.
+.It r+w/s
+The number of reads and writes per second.
+.It blks/s
+Number of blocks (in device's default blocksize) transferred to a device per second.
+.El
+.It Fl g
+Report page-out activity.
+.Pp
+.Bl -tag -width -indent \" Begins a tagged list
+.It pgout/s
+The number of pages paged out per second.
+.El
+.It Fl p
+Report page-in and page fault activity
+.Pp
+.Bl -tag -width -indent \" Begins a tagged list
+.It pgin/s
+The number of pages paged in per second.
+.It pflts/s
+The number of faults that caused a page to be copied in per second.
+.It vflts/s
+The number of times vm_fault routine has been called.
+.El
+.It Fl n Ar mode
+Report network activity with modes
+.Ar DEV ,
+.Ar EDEV ,
+or
+.Ar PPP .
+Multiple network modes can be specified.
+.Pp
+.Bl -tag -width -indent \" Begins a tagged list
+.It DEV
+The
+.Ar DEV
+mode reports network device statistics. The following
+information is displayed for each interface.
+.Pp
+.Bl -tag -width "Obytes/s" \" Begins a tagged list
+.It IFACE
+The network interface name.
+.It Ipkts/s
+The number of packets received per second.
+.It Ibytes/s
+The number of bytes received per second.
+.It Opkts/s
+The number of packets sent per second.
+.It Obytes/s
+The number of bytes sent per second.
+.El
+.It EDEV
+The
+.Ar EDEV
+mode reports network device error statistics. The
+following information is displayed for each interface.
+.Pp
+.Bl -tag -width "Drops/s" \" Begins a tagged list
+.It IFACE
+The interface name.
+.It Ierrs/s
+The input errors per second.
+.It Oerrs/s
+The output errors per second.
+.It Coll/s
+The collisions that occurred per second.
+.It Drops/s
+The number of dropped packets per second.
+.El
+.It PPP
+The
+.Ar PPP
+mode must be specified in order to display ppp connections
+in the network statistics. This will also turn on the PPP modify
+mode in
+.Ar sadc
+(8) when sampling data is not being read from a file.
+By default, both the collection and reporting of ppp
+statistics is turned off. See
+.Ar sadc
+(8).
+.El
+.Pp
+.It Fl u
+Report CPU activity (default)
+.Pp
+%usr, %sys, and %idle
+.Pp
+These report the percentage of time running in user mode,
+system mode and idle.
+.El
+.Sh FILES \" File used or created by the topic of the man page
+.Bl -tag -width "/var/log/sa/sadd" -compact
+.It Pa /var/log/sa/sadd
+Default daily activity file that holds the binary sampling data.
+.Ar dd
+are digits that represent the day of the month.
+.El
+.Sh SEE ALSO
+.\" List links in ascending order by section, alphabetically within a section.
+.Xr fs_usage 1 ,
+.Xr netstat 1 ,
+.Xr sc_usage 1 ,
+.Xr top 1 ,
+.Xr vm_stat 1 ,
+.Xr iostat 8 ,
+.Xr sa1 8 ,
+.Xr sa2 8 ,
+.Xr sadc 8
+.\" .Sh BUGS \" Document known, unremedied bugs
--- /dev/null
+/*
+ * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
+ * Reserved.
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * 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.
+*/
+
+/*
+ cc -Wall -I. -I ../sadc.tproj -O -o sar sar.c
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <mach/mach.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <sadc.h>
+#include <sar.h>
+
+
+#define IFNET_32_BIT_COUNTERS 1
+
+/* Options used only for launching sadc */
+int t_interval = 5; /* in seconds */
+char * t_intervalp = "5";
+int n_samples = 1; /* number of sample loops */
+char * n_samplesp = "1";
+
+/* Used only for storing the binary output after launching sadc */
+char *outfile = NULL; /* output file */
+int ofd = 0; /* output file descriptor */
+
+/*
+ * When launching sadc, this file descriptor reads sadc's stdout
+ * via pipe.
+ * When not launching sadc, this file descriptor will be either
+ * the input file passed in with the -f flag
+ * or the standard input file /var/log/sa/saXX
+ */
+int ifd = 0; /* input file descriptor */
+char *infile = NULL; /* input file */
+
+
+
+/* Used when we have to luanch sadc */
+pid_t pid;
+int fd[2]; /* read from fd[0], write to fd[1] */
+
+char *optionstring1 = "Adgn:puo:";
+char *optionstring1_usage = "/usr/bin/sar [-Adgpu] [-n { DEV | EDEV | PPP } ] [-o filename] t [n]";
+char *optionstring2 = "Adgn:pue:f:i:s:";
+char *optionstring2_usage = "/usr/bin/sar [-Adgpu] [-n { DEV | EDEV | PPP }] [-e time] [-f filename] [-i sec] [-s time]";
+
+
+/* option flags */
+int aflag = 0;
+int Aflag = 0;
+int bflag = 0;
+int cflag = 0;
+int dflag = 0; /* drive statistics */
+int gflag = 0; /* page-out activity */
+int kflag = 0;
+int mflag = 0;
+
+int nflag = 0; /* network statistics */
+int network_mode = 0;
+char *sadc_mflagp = "-m";
+char *sadc_ppp_modep = "PPP";
+
+int pflag = 0; /* page-in activity */
+int qflag = 0;
+int rflag = 0;
+int uflag = 0; /* cpu utilization - this is the only default */
+int vflag = 0;
+int wflag = 0;
+int yflag = 0;
+int set_default_flag = 1;
+int flag_count = 0;
+
+/*
+ * To get the current time of day in seconds
+ * based on a 24 hour clock, pass in the time_t from time()
+ * the remainder is the current time in seconds
+*/
+#define HOURS_PER_DAY 24
+#define MINS_PER_HOUR 60
+#define SECS_PER_MIN 60
+#define SECS_PER_DAY (SECS_PER_MIN * MINS_PER_HOUR * HOURS_PER_DAY)
+
+/* end time delimiter -- converted from hh:mm:ss to seconds */
+time_t end_time = 0;
+
+int iflag = 0;
+int iseconds = 0; /* interval seconds, default = 0 implies all samples are
+ * printed */
+
+/* start time delimiter -- converted from hh:mm:ss to seconds */
+time_t start_time = 0;
+
+int oflag = 0;
+int fflag = 0;
+
+/* stat records average and previous */
+struct vm_statistics prev_vmstat, avg_vmstat, cur_vmstat;
+host_cpu_load_info_data_t prev_cpuload, avg_cpuload, cur_cpuload;
+struct drivestats_report *dr_head = NULL;
+
+/* internal table of drive path mappings */
+struct drivepath *dp_table = NULL;
+int dp_count = 0;
+
+/* internal table of network interface statistics */
+struct netstats_report *nr_table = NULL;
+int nr_count;
+struct netstats *netstat_readbuf = NULL;
+size_t netstat_readbuf_size = 0;
+
+int avg_counter = 0;
+int avg_interval = 0;
+
+extern int errno;
+
+/* Forward function declarations */
+static void exit_usage();
+static void open_output_file(char *path);
+static void open_input_file(char *path);
+static void read_record_hdr(struct record_hdr *hdr, int writeflag);
+static void read_record_data(char *buf, size_t size, int writeflag);
+static void write_record_hdr(struct record_hdr *hdr);
+static void write_record_data(char *buf, size_t size);
+static time_t convert_hms(char *string);
+static char *get_hms_string(time_t, char *);
+static int find_restart_header(struct record_hdr *);
+static void print_all_column_headings (time_t timestamp);
+static void print_column_heading (int type, char *timebufptr, int mode);
+static void read_sample_set(int, time_t, struct record_hdr *);
+static void do_main_workloop();
+static int bypass_sample_set(struct record_hdr *, time_t);
+static void skip_data(int);
+static int get_cpu_sample(int flag, struct record_hdr *hdr);
+static void print_cpu_sample(char *timebufptr);
+static int get_vmstat_sample(int flag, struct record_hdr *hdr);
+static void print_vmstat_sample(char *timebufptr);
+
+static int get_drivestats_sample(int flag, struct record_hdr *hdr);
+static void init_drivestats(struct drivestats_report *dr);
+static void print_drivestats_sample(char *timebufptr);
+static int get_drivepath_sample(int flag, struct record_hdr *hdr);
+
+static void set_cur_netstats(struct netstats_report *nr, struct netstats *ns);
+static void init_prev_netstats(struct netstats_report *nr);
+static int get_netstats_sample(int flag, struct record_hdr *hdr);
+static void print_netstats_sample(char *timebufptr);
+
+static void exit_average();
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ char ch;
+
+ time_t curr_time; /* current time in seconds */
+ char timebuf[26];
+ char filenamebuf[20];
+ char *optstring = NULL;
+ int optstringval;
+ int i;
+
+ /*
+ * Detirmine which option string to use
+ */
+
+ optreset=0;
+ optstringval=0;
+
+ while((ch=getopt(argc, argv, "aAbcdgkmn:pqruvwyo:e:f:i:s:")) != EOF) {
+ switch(ch) {
+ case 'o':
+ if (optstringval == 2)
+ exit_usage();
+ optstring=optionstring1;
+ optstringval=1;
+ break;
+ case 'e':
+ case 'f':
+ case 'i':
+ case 's':
+ if (optstringval == 1)
+ exit_usage();
+ optstring=optionstring2;
+ optstringval=2;
+ break;
+ default:
+ /* ignore for now */
+ break;
+ }
+ }
+
+ if (!optstring)
+ {
+ /* still trying to determine which option string to use */
+ if (argc - optind > 0)
+ {
+ optstring=optionstring1; /* we should have a t_second value */
+ optstringval=1;
+ }
+ else
+ {
+ optstring=optionstring2;
+ optstringval=2;
+ }
+ }
+
+ optreset = optind = 1;
+ while ((ch=getopt(argc, argv, optstring)) != EOF) {
+ switch (ch) {
+ case 'a':
+ aflag = 1;
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'A':
+ Aflag = 1;
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'b':
+ bflag = 1;
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'c':
+ cflag = 1;
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'd':
+ dflag = 1;
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'g':
+ gflag = 1;
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'k':
+ kflag = 1;
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'm':
+ mflag = 1;
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'n':
+ nflag= 1;
+ if (!strncmp(optarg, "PPP", 3))
+ network_mode |= NET_PPP_MODE;
+ else if (!strncmp(optarg, "DEV", 3))
+ network_mode |= NET_DEV_MODE;
+ else if (!strncmp(optarg, "EDEV", 4))
+ network_mode |= NET_EDEV_MODE;
+ else
+ exit_usage();
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'p':
+ pflag = 1;
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'q':
+ qflag = 1;
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'r':
+ rflag = 1;
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'u':
+ uflag= 1;
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'v':
+ vflag = 1;
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'w':
+ wflag = 1;
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'y':
+ yflag = 1;
+ set_default_flag = 0;
+ flag_count++;
+ break;
+ case 'o':
+ /* open the output file */
+ oflag = 1;
+ outfile=optarg;
+ (void)open_output_file(outfile);
+ break;
+ case 'e': /* eflag */
+ end_time = convert_hms(optarg);
+ break;
+ case 'f':
+ fflag = 1;
+ infile=optarg;
+ break;
+ case 'i':
+ iflag = 1;
+ iseconds=atoi(optarg);
+ break;
+ case 's':
+ start_time = convert_hms(optarg);
+ break;
+ default:
+ exit_usage();
+ break;
+ }
+ }
+
+ /* setup default uflag option */
+ if (Aflag)
+ {
+ dflag = gflag = pflag = uflag = 1;
+ if (!nflag)
+ {
+ /*
+ * Add network stats to the load
+ * but avoid PPP data by default.
+ */
+ nflag = 1;
+ network_mode = NET_DEV_MODE | NET_EDEV_MODE;;
+ }
+ flag_count = 2; /* triggers column headings */
+ }
+ else if (set_default_flag)
+ {
+ uflag=1;
+ flag_count++;
+ }
+
+ if (nflag)
+ {
+ if (network_mode & NET_PPP_MODE)
+ {
+ if (!(network_mode & NET_DEV_MODE) &&
+ !(network_mode & NET_EDEV_MODE))
+ {
+ /* set defaults */
+ network_mode |= NET_DEV_MODE;
+ network_mode |= NET_EDEV_MODE;
+ flag_count++;
+ }
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* set up signal handlers */
+ signal(SIGINT, exit_average);
+ signal(SIGQUIT, exit_average);
+ signal(SIGHUP, exit_average);
+ signal(SIGTERM, exit_average);
+
+ if (optstringval == 1)
+ {
+ /* expecting a time interval */
+
+ char *p;
+
+ if (argc >= 1)
+ {
+ errno = 0;
+ t_interval = strtol(argv[0], &p, 0);
+ t_intervalp = argv[0];
+ if (errno || (*p != '\0') || t_interval <= 0 )
+ exit_usage();
+ if (argc >= 2)
+ {
+ errno=0;
+ n_samples = strtol(argv[1], &p, 0);
+ n_samplesp = argv[1];
+ if (errno || (*p != '\0') || n_samples <= 0)
+ exit_usage();
+ }
+ }
+ }
+
+ /* where does the input come from */
+ if (fflag)
+ {
+ (void)open_input_file(infile);
+ }
+ else if (optstringval == 2)
+ {
+ /*
+ * Create a filename of the form /var/log/sa/sadd
+ * where "dd" is the date of the month
+ */
+ curr_time = time((time_t *)0); /* returns time in seconds */
+
+ /*
+ timebuf will be a 26-character string of the form:
+ Thu Nov 24 18:22:48 1986\n\0
+ */
+
+ ctime_r(&curr_time, timebuf);
+ strncpy(filenamebuf, "/var/log/sa/sa", 14);
+ strncpy(&filenamebuf[14], &timebuf[8], 2);
+ if (filenamebuf[14] == ' ')
+ filenamebuf[14] = '0';
+ filenamebuf[16]='\0';
+ infile = filenamebuf;
+ (void)open_input_file(infile);
+ }
+ else if (optstringval == 1)
+ {
+ /* launch sadc */
+ if (pipe(fd) == -1)
+ {
+ fprintf(stderr, "sar: pipe(2) failed, errno = (%d)\n",errno);
+ exit(1);
+ }
+
+ if ((pid=fork()) == 0)
+ {
+#if 0
+ int efd;
+#endif
+ int fdlimit = getdtablesize();
+
+ /* This is the child */
+ /* Close all file descriptors except the one we need */
+
+ for (i=0; i < fdlimit; i++) {
+ if ((i != fd[0]) && (i != fd[1]))
+ (void)close(i);
+ }
+#if 0
+ efd = open("/tmp/errlog", O_CREAT|O_APPEND|O_RDWR, 0666);
+ if (dup2(efd,2) == -1) {
+ exit(1);
+ }
+#endif
+ /* Dup the two file descriptors to stdin and stdout */
+ if (dup2(fd[0],0) == -1) {
+ exit(1);
+ }
+ if (dup2(fd[1],1) == -1) {
+ exit(1);
+ }
+ /* Exec the child process */
+ if (network_mode & NET_PPP_MODE)
+ execl("/usr/lib/sa/sadc", "sadc", sadc_mflagp, sadc_ppp_modep, t_intervalp, n_samplesp, NULL);
+ else
+ execl("/usr/lib/sa/sadc", "sadc", t_intervalp, n_samplesp, NULL);
+
+ perror("execlp sadc");
+ exit(2); /* This call of exit(2) should never be reached... */
+ }
+ else
+ { /* This is the parent */
+ if (pid == -1) {
+ fprintf(stderr, "sar: fork(2) failed, errno = (%d)\n",errno);
+ exit(1);
+ }
+ close (fd[1]); /* parent does not write to the pipe */
+ ifd = fd[0]; /* parent will read from the pipe */
+ }
+ }
+ else
+ {
+ /* we're confused about source of input data - bail out */
+ fprintf(stderr, "sar: no input file recognized\n");
+ exit_usage();
+ }
+
+ /* start reading input data and format the output */
+ (void)do_main_workloop();
+ (void)exit_average();
+ exit(0);
+}
+
+static void
+exit_usage()
+{
+ fprintf(stderr, "\n%s\n\n", optionstring1_usage);
+ fprintf(stderr, "%s\n", optionstring2_usage);
+ exit(EXIT_FAILURE);
+}
+
+static void
+open_output_file(char *path)
+{
+ if ((ofd = open(path, O_CREAT|O_APPEND|O_TRUNC|O_WRONLY, 0664)) == -1 )
+ {
+ /* failed to open path */
+ fprintf(stderr, "sar: failed to open output file [%s]\n", path);
+ exit_usage();
+ }
+}
+
+
+static void
+open_input_file(char *path)
+{
+ if ((ifd = open(path, O_RDONLY, 0)) == -1)
+ {
+ /* failed to open path */
+ fprintf(stderr, "sar: failed to open input file [%d][%s]\n", ifd, path);
+ exit_usage();
+ }
+}
+
+static void
+read_record_hdr(hdr, writeflag)
+ struct record_hdr *hdr;
+ int writeflag;
+{
+ errno = 0;
+ int num = 0;
+ int n = 0;
+ size_t size = 0;
+
+ size = sizeof(struct record_hdr);
+
+ while (size)
+ {
+ num = read(ifd, &hdr[n], size);
+ if (num > 0)
+ {
+ n += num;
+ size -= num;
+ }
+ else if (num == 0)
+ exit_average();
+ else
+ {
+ fprintf(stderr, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno, (int)num, (int)size);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (oflag && writeflag)
+ write_record_hdr(hdr);
+
+ return;
+}
+
+static void
+read_record_data(buf, size, writeflag)
+ char * buf;
+ size_t size;
+ int writeflag;
+{
+ errno = 0;
+ size_t num = 0;
+ size_t n = 0;
+
+ while (size)
+ {
+ num = read(ifd, &buf[n], size);
+ if (num > 0)
+ {
+ n += num;
+ size -= num;
+ }
+ else if (num == 0) /* EOF */
+ exit_average();
+ else
+ {
+ fprintf(stderr, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno, (int)num, (int)size);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (oflag && writeflag)
+ write_record_data(buf, n);
+
+ return;
+}
+
+static void
+write_record_hdr(hdr)
+ struct record_hdr *hdr;
+{
+ errno = 0;
+ int num;
+
+ if ((num = write(ofd, hdr, sizeof(struct record_hdr))) == -1)
+ {
+ fprintf(stderr, "sar: write_record_hdr failed, errno=%d\n", errno);
+ exit(EXIT_FAILURE);
+ }
+ return;
+}
+
+static void
+write_record_data(char *buf, size_t nbytes)
+{
+ errno = 0;
+ int num;
+ if ((num = write(ofd, buf, nbytes)) == -1)
+ {
+ fprintf(stderr, "sar: write_record_data failed, errno=%d\n", errno);
+ exit(EXIT_FAILURE);
+ }
+ return;
+}
+
+/*
+ * Convert a string of one of the forms
+ * hh hh:mm hh:mm:ss
+ * into the number of seconds.
+ * exit on error
+*/
+
+static time_t
+convert_hms(string)
+ char *string;
+{
+ int hh = 0; /* hours */
+ int mm = 0; /* minutes */
+ int ss = 0; /* seconds */
+ time_t seconds;
+ time_t timestamp;
+ struct tm *tm;
+ int i;
+
+ if (string == NULL || *string == '\0')
+ goto convert_err;
+
+ for (i=0; string[i] != '\0'; i++)
+ {
+ if ((!isdigit(string[i])) && (string[i] != ':'))
+ {
+ goto convert_err;
+ }
+ }
+
+ if (sscanf(string, "%d:%d:%d", &hh, &mm, &ss) != 3)
+ {
+ if (sscanf(string, "%d:%d", &hh, &mm) != 2)
+ {
+ if (sscanf(string, "%d", &hh) != 1)
+ {
+ goto convert_err;
+ }
+ }
+ }
+
+ if (hh < 0 || hh >= HOURS_PER_DAY ||
+ mm < 0 || mm >= MINS_PER_HOUR ||
+ ss < 0 || ss > SECS_PER_MIN)
+ {
+ goto convert_err;
+ }
+
+ seconds = ((((hh * MINS_PER_HOUR) + mm) * SECS_PER_MIN) + ss);
+ timestamp = time((time_t *)0);
+ tm=localtime(×tamp);
+ seconds -= tm->tm_gmtoff;
+
+ return(seconds);
+
+ convert_err:
+ fprintf(stderr, "sar: time format usage is hh[:mm[:ss]]\n");
+ exit_usage();
+ return(0);
+}
+
+
+/*
+ * Use ctime_r to convert a time value into
+ * a 26-character string of the form:
+ *
+ * Thu Nov 24 18:22:48 1986\n\0
+ */
+
+static char *
+get_hms_string(tdata, tbuf)
+ time_t tdata;
+ char *tbuf;
+{
+ time_t t;
+ char *p;
+
+ t = tdata;
+ ctime_r(&t, tbuf);
+ p=&tbuf[11];
+ tbuf[19] = 0;
+
+ return(p);
+}
+
+
+/* sample set flags */
+#define INIT_SET 0
+#define PRINT_SET 1
+#define PRINT_AVG 2
+
+static void
+do_main_workloop()
+{
+ struct record_hdr hdr;
+ time_t cur_timestamp = 0; /* seconds - Coordinated Universal Time */
+ time_t next_timestamp = 0; /* seconds - Coordinated Universal Time */
+
+ if (!find_restart_header(&hdr))
+ exit(1);
+
+ cur_timestamp = hdr.rec_timestamp;
+
+ /* convert sflag's start_time from 24 hour clock time to UTC seconds */
+ if (start_time < (cur_timestamp % SECS_PER_DAY))
+ start_time = cur_timestamp;
+ else
+ start_time += cur_timestamp - (cur_timestamp % SECS_PER_DAY);
+
+ /* convert end_time, from 24 hour clock time to UTC seconds */
+ if (end_time != 0)
+ end_time += cur_timestamp - (cur_timestamp % SECS_PER_DAY);
+
+#if 0
+ fprintf(stderr, "start = %ld, end = %ld, cur=%ld, [24hour - %ld]\n",
+ start_time, end_time, cur_timestamp,(cur_timestamp % SECS_PER_DAY));
+#endif
+
+ while (cur_timestamp < start_time)
+ {
+ bypass_sample_set(&hdr, cur_timestamp);
+ cur_timestamp = hdr.rec_timestamp;
+ }
+
+ next_timestamp = cur_timestamp + iseconds;
+ print_all_column_headings(cur_timestamp);
+ read_sample_set(INIT_SET, cur_timestamp, &hdr);
+ cur_timestamp = hdr.rec_timestamp;
+
+ while ((end_time == 0) || (next_timestamp < end_time))
+ {
+ if (cur_timestamp < next_timestamp)
+ {
+ bypass_sample_set (&hdr, cur_timestamp);
+ cur_timestamp = hdr.rec_timestamp;
+ }
+ else
+ {
+ /* need to know the seconds interval when printing averages */
+ if (avg_interval == 0)
+ {
+ if (iseconds)
+ avg_interval = iseconds;
+ else
+ avg_interval = cur_timestamp - next_timestamp;
+ }
+ next_timestamp = cur_timestamp + iseconds;
+ read_sample_set(PRINT_SET, cur_timestamp, &hdr);
+ cur_timestamp = hdr.rec_timestamp;
+ }
+ }
+ exit_average();
+}
+
+
+/*
+ * Find and fill in a restart header. We don't write
+ * the binary data when looking for SAR_RESTART.
+ * Return: 1 on success
+ * 0 on failure
+ */
+static int
+find_restart_header (ret_hdr)
+ struct record_hdr *ret_hdr;
+{
+ struct record_hdr hdr;
+ int bufsize = 0;
+ char *buf = NULL;
+
+ errno = 0;
+
+ restart_loop:
+ read_record_hdr(&hdr, FALSE); /* exits on error */
+
+ if (hdr.rec_type == SAR_RESTART)
+ {
+ *ret_hdr = hdr;
+ if (oflag)
+ write_record_hdr(&hdr); /* writes the RESTART record */
+ if (buf)
+ free(buf);
+ return(1);
+ }
+
+ /*
+ * not the record we want...
+ * read past data and try again
+ */
+ if (hdr.rec_count)
+ {
+ if (fflag)
+ { /* seek past data in the file */
+ if ((lseek(ifd, (hdr.rec_count * hdr.rec_size), SEEK_CUR)) == -1)
+ {
+ /*exit on error */
+ fprintf(stderr, "sar: lseek failed, errno=%d\n", errno);
+ exit(EXIT_FAILURE);
+ }
+
+ }
+ /* compute data size - malloc a new buf if it's not big enough */
+ else
+ {
+ /* have to read from the pipe */
+ if (bufsize < (hdr.rec_count * hdr.rec_size))
+ {
+ if (buf)
+ free(buf);
+ bufsize = hdr.rec_count * hdr.rec_size;
+ if((buf = (char *)malloc(bufsize)) == NULL)
+ {
+ fprintf(stderr, "sar: malloc failed\n");
+ return(0);
+ }
+ }
+ /* exits on error */
+ read_record_data(buf, (hdr.rec_count * hdr.rec_size), FALSE);
+ }
+ }
+ goto restart_loop;
+}
+
+static void
+print_all_column_headings(timestamp)
+ time_t timestamp;
+{
+ char timebuf[26];
+ char *timebufp;
+
+ timebufp = get_hms_string (timestamp, timebuf);
+
+ if (uflag) /* print cpu headers */
+ print_column_heading(SAR_CPU, timebufp, 0);
+
+ if (gflag) /* print page-out activity */
+ print_column_heading(SAR_VMSTAT, timebufp, 0);
+
+ if (pflag ) /* print page-in activity */
+ print_column_heading(SAR_VMSTAT, timebufp, 1);
+
+ if (dflag) /* print drive stats */
+ print_column_heading(SAR_DRIVESTATS, timebufp, 0);
+
+ if (nflag) /* print network stats */
+ {
+ if (network_mode & NET_DEV_MODE)
+ print_column_heading(SAR_NETSTATS, timebufp, NET_DEV_MODE);
+
+ if (network_mode & NET_EDEV_MODE)
+ print_column_heading(SAR_NETSTATS, timebufp, NET_EDEV_MODE);
+ }
+}
+
+
+/*
+ * Find and fill in a timestamp header.
+ * Write the binary data when looking for SAR_TIMESTAMP
+ * Don't do anything with the data, just read past it.
+ * Return: 1 on success
+ * 0 on failure
+ */
+static int
+bypass_sample_set (ret_hdr, timestamp)
+ struct record_hdr *ret_hdr;
+ time_t timestamp;
+{
+ struct record_hdr hdr;
+ int bufsize = 0;
+ char *buf = NULL;
+
+ bypass_loop:
+ read_record_hdr(&hdr, TRUE); /* exits on error */
+
+ if (hdr.rec_type == SAR_TIMESTAMP)
+ {
+ *ret_hdr = hdr;
+ if (buf)
+ free(buf);
+ return(1);
+ }
+
+ /*
+ * not the record we want...
+ * read past data and try again
+ */
+ if (hdr.rec_count)
+ {
+ if (fflag && !oflag)
+ {
+ /*
+ * we're reading from a file and we don't have to write the
+ * binary data so seek past data in the file
+ */
+ errno = 0;
+ if ((lseek(ifd, (hdr.rec_count * hdr.rec_size), SEEK_CUR)) == -1)
+ {
+ /*exit on error */
+ fprintf(stderr, "sar: lseek failed, errno=%d\n", errno);
+ exit(EXIT_FAILURE);
+ }
+ }
+ else
+ {
+ /*
+ * We end up here when reading from pipe.
+ * malloc a new buffer if current is not big enough
+ */
+ if (bufsize < (hdr.rec_count * hdr.rec_size))
+ {
+ if (buf)
+ free(buf);
+ bufsize = hdr.rec_count * hdr.rec_size;
+ if((buf = (char *)malloc(bufsize)) == NULL)
+ {
+ fprintf(stderr, "sar: malloc failed\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* exits on error */
+ read_record_data(buf, (hdr.rec_count * hdr.rec_size), TRUE);
+ }
+ } /* end if hdr.rec_count */
+ goto bypass_loop;
+}
+
+
+/*
+ * INIT_SET: This initializes the first sample for each type.
+ * PRINT_SET: This read, compute and print out sample data.
+ */
+static void
+read_sample_set(flag, timestamp, ret_hdr)
+ int flag;
+ time_t timestamp;
+ struct record_hdr *ret_hdr;
+{
+ struct record_hdr hdr;
+ char timebuf[26];
+ char *timebufp;
+ char *indent_string;
+ char *indent_string_wide;
+ char *indent_string_narrow;
+ int sar_cpu = 0;
+ int sar_vmstat=0;
+ int sar_drivestats=0;
+ int sar_drivepath=0;
+ int sar_netstats = 0;
+
+ indent_string_wide = " ";
+ indent_string_narrow = " ";
+ indent_string = indent_string_narrow;
+
+ read_record_hdr(&hdr, TRUE);
+
+ while (hdr.rec_type != SAR_TIMESTAMP)
+ {
+ switch (hdr.rec_type)
+ {
+ case SAR_CPU:
+ sar_cpu = get_cpu_sample(flag, &hdr);
+ break;
+ case SAR_VMSTAT:
+ sar_vmstat=get_vmstat_sample(flag, &hdr);
+ break;
+ case SAR_DRIVEPATH:
+ sar_drivepath = get_drivepath_sample(flag, &hdr);
+ if (sar_drivepath < 0)
+ fprintf(stderr, "sar: drivepath sync code error %d\n", sar_drivepath);
+ break;
+ case SAR_DRIVESTATS:
+ sar_drivestats = get_drivestats_sample(flag, &hdr);
+ break;
+ case SAR_NETSTATS:
+ sar_netstats = get_netstats_sample(flag, &hdr);
+ break;
+ default:
+ break;
+ }
+
+ read_record_hdr(&hdr, TRUE);
+ }
+
+ /* return the timestamp header */
+ *ret_hdr = hdr;
+
+ if (flag == PRINT_SET)
+ {
+ avg_counter++;
+ timebufp = get_hms_string(timestamp, timebuf);
+
+ if (uflag && sar_cpu)
+ print_cpu_sample(timebufp);
+
+ if((gflag || pflag) && sar_vmstat)
+ print_vmstat_sample(timebufp);
+
+ if (dflag && sar_drivestats)
+ print_drivestats_sample(timebufp);
+
+ if (nflag && sar_netstats)
+ print_netstats_sample(timebufp);
+ }
+}
+
+static void
+skip_data(bufsize)
+ int bufsize;
+{
+ char *buf = NULL;
+
+ if (fflag)
+ {
+ /* seek past data in the file */
+ if ((lseek(ifd, bufsize, SEEK_CUR) == -1))
+ {
+ /*exit on error */
+ fprintf(stderr, "sar: lseek failed, errno=%d\n", errno);
+ exit(EXIT_FAILURE);
+ }
+ }
+ else
+ {
+ /* have to read from the pipe */
+ if((buf = (char *)malloc(bufsize)) == NULL)
+ {
+ fprintf(stderr, "sar: malloc failed\n");
+ exit(EXIT_FAILURE);
+ }
+ /* even though we skip this data, we still write it if necessary */
+ read_record_data(buf, bufsize, TRUE);
+ }
+ if (buf)
+ free(buf);
+
+ return;
+}
+
+static int
+get_cpu_sample(flag, hdr)
+ int flag;
+ struct record_hdr *hdr;
+{
+ int datasize;
+
+ datasize = hdr->rec_count * hdr->rec_size;
+
+ if (datasize != sizeof(host_cpu_load_info_data_t))
+ {
+ /* read past the data but don't do anything with it */
+ skip_data(datasize);
+ return(0);
+ }
+
+ read_record_data ((char *)&cur_cpuload, (int)sizeof(host_cpu_load_info_data_t), TRUE );
+
+ if (flag == INIT_SET)
+ {
+ prev_cpuload = cur_cpuload;
+ bzero(&avg_cpuload, sizeof(avg_cpuload));
+ }
+ return(1);
+}
+
+static void
+print_cpu_sample(timebufptr)
+ char * timebufptr;
+{
+
+ double time;
+
+ time = 0.0;
+ cur_cpuload.cpu_ticks[CPU_STATE_USER]
+ -= prev_cpuload.cpu_ticks[CPU_STATE_USER];
+
+ prev_cpuload.cpu_ticks[CPU_STATE_USER]
+ += cur_cpuload.cpu_ticks[CPU_STATE_USER];
+
+ time += cur_cpuload.cpu_ticks[CPU_STATE_USER];
+
+ cur_cpuload.cpu_ticks[CPU_STATE_NICE]
+ -= prev_cpuload.cpu_ticks[CPU_STATE_NICE];
+
+ prev_cpuload.cpu_ticks[CPU_STATE_NICE]
+ += cur_cpuload.cpu_ticks[CPU_STATE_NICE];
+
+ time += cur_cpuload.cpu_ticks[CPU_STATE_NICE];
+
+ cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
+ -= prev_cpuload.cpu_ticks[CPU_STATE_SYSTEM];
+
+ prev_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
+ += cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM];
+
+ time += cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM];
+
+ cur_cpuload.cpu_ticks[CPU_STATE_IDLE]
+ -= prev_cpuload.cpu_ticks[CPU_STATE_IDLE];
+
+ prev_cpuload.cpu_ticks[CPU_STATE_IDLE]
+ += cur_cpuload.cpu_ticks[CPU_STATE_IDLE];
+
+ time += cur_cpuload.cpu_ticks[CPU_STATE_IDLE];
+
+ avg_cpuload.cpu_ticks[CPU_STATE_USER] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_USER]
+ / (time ? time : 1));
+
+ avg_cpuload.cpu_ticks[CPU_STATE_NICE] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_NICE]
+ / (time ? time : 1));
+
+ avg_cpuload.cpu_ticks[CPU_STATE_SYSTEM] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
+ / (time ? time : 1));
+
+ avg_cpuload.cpu_ticks[CPU_STATE_IDLE] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_IDLE]
+ / (time ? time : 1));
+
+ if(flag_count > 1)
+ print_column_heading(SAR_CPU, timebufptr, 0);
+
+ fprintf(stdout, "%s%5.0f ", timebufptr,
+ rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_USER]
+ / (time ? time : 1)));
+
+ fprintf(stdout, "%4.0f ",
+ rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_NICE]
+ / (time ? time : 1)));
+
+ fprintf(stdout, "%4.0f ",
+ rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
+ / (time ? time : 1)));
+
+ fprintf(stdout, "%4.0f\n",
+ rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_IDLE]
+ / (time ? time : 1)));
+}
+
+static int
+get_vmstat_sample(flag, hdr)
+ int flag;
+ struct record_hdr *hdr;
+{
+ int datasize;
+
+ datasize = hdr->rec_count * hdr->rec_size;
+
+ if (datasize != sizeof(struct vm_statistics))
+ {
+ /* read past the data but don't do anything with it */
+ skip_data(datasize);
+ return(0);
+ }
+
+ read_record_data ((char *)&cur_vmstat, (int)sizeof(struct vm_statistics), TRUE );
+
+ if (flag == INIT_SET)
+ {
+ prev_vmstat = cur_vmstat;
+ bzero(&avg_vmstat, sizeof(avg_vmstat));
+ }
+ return(1);
+}
+
+
+static void
+print_vmstat_sample(char *timebufptr)
+{
+
+ cur_vmstat.faults -= prev_vmstat.faults;
+ prev_vmstat.faults += cur_vmstat.faults;
+ avg_vmstat.faults += cur_vmstat.faults;
+
+ cur_vmstat.cow_faults -= prev_vmstat.cow_faults;
+ prev_vmstat.cow_faults += cur_vmstat.cow_faults;
+ avg_vmstat.cow_faults += cur_vmstat.cow_faults;
+
+ cur_vmstat.zero_fill_count -= prev_vmstat.zero_fill_count;
+ prev_vmstat.zero_fill_count += cur_vmstat.zero_fill_count;
+ avg_vmstat.zero_fill_count += cur_vmstat.zero_fill_count;
+
+ cur_vmstat.reactivations -= prev_vmstat.reactivations;
+ prev_vmstat.reactivations += cur_vmstat.reactivations;
+ avg_vmstat.reactivations += cur_vmstat.reactivations;
+
+ cur_vmstat.pageins -= prev_vmstat.pageins;
+ prev_vmstat.pageins += cur_vmstat.pageins;
+ avg_vmstat.pageins += cur_vmstat.pageins;
+
+ cur_vmstat.pageouts -= prev_vmstat.pageouts;
+ prev_vmstat.pageouts += cur_vmstat.pageouts;
+ avg_vmstat.pageouts += cur_vmstat.pageouts;
+
+
+ if (gflag)
+ {
+ if (flag_count > 1)
+ print_column_heading(SAR_VMSTAT, timebufptr, 0);
+ fprintf(stdout, "%s %8.1f \n", timebufptr, (float)((float)cur_vmstat.pageouts/avg_interval));
+ }
+
+ if (pflag)
+ {
+ if (flag_count > 1)
+ print_column_heading(SAR_VMSTAT, timebufptr, 1);
+ fprintf(stdout, "%s %8.1f %8.1f %8.1f\n", timebufptr,
+ (float)((float)cur_vmstat.pageins / avg_interval),
+ (float)((float)cur_vmstat.cow_faults/avg_interval),
+ (float)((float)cur_vmstat.faults/avg_interval));
+ }
+ fflush(stdout);
+}
+
+static int
+get_drivestats_sample(flag, hdr)
+ int flag;
+ struct record_hdr *hdr;
+{
+ struct drivestats *databuf;
+ struct drivestats_report *dr;
+ size_t datasize;
+ int datacount;
+ int index;
+ int i;
+
+ datasize = hdr->rec_count * hdr->rec_size;
+ datacount = hdr->rec_count;
+
+ if (hdr->rec_size != sizeof(struct drivestats))
+ {
+ /* something isn't right... read past the data but don't analyze it */
+ skip_data(datasize);
+ return(0);
+ }
+
+ /* malloc read buffer */
+ if ((databuf = (struct drivestats *)malloc(datasize)) == NULL)
+ {
+ fprintf(stderr, "sar: malloc failed\n");
+ exit (EXIT_FAILURE);
+ }
+
+ bzero(databuf, datasize);
+
+ read_record_data ((char *)databuf, datasize, TRUE );
+
+ /* clear all global current fields */
+ for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
+ {
+ dr->present = 0;
+ dr->cur_Reads = 0;
+ dr->cur_BytesRead = 0;
+ dr->cur_Writes = 0;
+ dr->cur_BytesWritten = 0;
+ dr->cur_LatentReadTime = 0;
+ dr->cur_LatentWriteTime = 0;
+ dr->cur_ReadErrors = 0;
+ dr->cur_WriteErrors = 0;
+ dr->cur_ReadRetries = 0;
+ dr->cur_WriteRetries = 0;
+ dr->cur_TotalReadTime = 0;
+ dr->cur_TotalWriteTime=0;
+ }
+
+ /* By this point, we have read in a complete set of diskstats from the sadc
+ * data collector.
+ * The order of the drives in not guaranteed.
+ * The global report structure is a linked list, but may need initialization
+ * We need to traverse this list and transfer the current
+ * read data. If a disk entry isn't found, then we need to allocate one
+ * initilize it.
+ */
+ for (i=0; i< datacount; i++)
+ {
+ struct drivestats_report *dr_last = NULL;
+
+ index = databuf[i].drivepath_id; /* use this as index into dp_table */
+
+ /* find disk entry or allocate new one*/
+ for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
+ {
+ dr_last = dr;
+ if(index == dr->drivepath_id)
+ break;
+ }
+
+ if (dr == NULL)
+ {
+ /* allocate new entry */
+ if((dr = (struct drivestats_report *)malloc(sizeof(struct drivestats_report))) == NULL)
+ {
+ fprintf(stderr, "sar: malloc error\n");
+ exit(EXIT_FAILURE);
+ }
+ bzero((char *)dr, sizeof(struct drivestats_report));
+ dr->blocksize = databuf[i].blocksize;
+ dr->drivepath_id = index;
+ dr->next = NULL;
+ dr->avg_count = 0;
+
+ /* get the BSDName which should be in the table by now */
+ if ((index < dp_count) && (dp_table[index].state != DPSTATE_UNINITIALIZED))
+ strncpy(dr->name, dp_table[index].BSDName, MAXDRIVENAME+1);
+ else
+ strcpy(dr->name, "disk??");
+
+ if (dr_head == NULL)
+ {
+ dr_head = dr;
+ dr_head->next = NULL;
+ }
+ else
+ {
+ dr_last->next = (char *)dr;
+ }
+ } /* end if dr == NULL */
+
+ dr->present = TRUE;
+ dr->cur_Reads = databuf[i].Reads;
+ dr->cur_BytesRead = databuf[i].BytesRead;
+ dr->cur_Writes = databuf[i].Writes;
+ dr->cur_BytesWritten = databuf[i].BytesWritten;
+ dr->cur_LatentReadTime = databuf[i].LatentReadTime;
+ dr->cur_LatentWriteTime = databuf[i].LatentWriteTime;
+ dr->cur_ReadErrors = databuf[i].ReadErrors;
+ dr->cur_WriteErrors = databuf[i].WriteErrors;
+ dr->cur_ReadRetries = databuf[i].ReadRetries;
+ dr->cur_WriteRetries = databuf[i].WriteRetries;
+ dr->cur_TotalReadTime = databuf[i].TotalReadTime;
+ dr->cur_TotalWriteTime=databuf[i].TotalWriteTime;
+ } /* end for loop */
+
+ /* Reinitialize the prev and avg fields when
+ * This is a new disk
+ * This is a changed disk - name change implies disk swapping
+ * This disk is not present in this sample
+ */
+ for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
+ {
+ if (dr->drivepath_id >= dp_count)
+ {
+ /* something is amiss */
+ continue;
+ }
+ else
+ {
+ index = dr->drivepath_id; /* use this as index into dp_table */
+ }
+
+ if ((flag == INIT_SET) ||
+ (dp_table[index].state == DPSTATE_NEW) ||
+ (dp_table[index].state == DPSTATE_CHANGED) ||
+ (!dr->present))
+ {
+ /*
+ * prev will be set to cur
+ * activate the state in dp_table
+ */
+ if (dr->present)
+ dp_table[index].state = DPSTATE_ACTIVE;
+
+ init_drivestats(dr);
+ }
+ }
+ return(1);
+}
+
+static void
+init_drivestats(struct drivestats_report *dr)
+{
+ dr->avg_count = 0;
+ dr->prev_Reads = dr->cur_Reads;
+ dr->avg_Reads = 0;
+ dr->prev_BytesRead = dr->cur_BytesRead;
+ dr->avg_BytesRead = 0;
+ dr->prev_Writes = dr->cur_Writes;
+ dr->avg_Writes = 0;
+ dr->prev_BytesWritten = dr->cur_BytesWritten;
+ dr->avg_BytesWritten = 0;
+ dr->prev_LatentReadTime = dr->cur_LatentReadTime;
+ dr->avg_LatentReadTime = 0;
+ dr->prev_LatentWriteTime = dr->cur_LatentWriteTime ;
+ dr->avg_LatentWriteTime = 0;
+ dr->prev_ReadErrors = dr->cur_ReadErrors ;
+ dr->avg_ReadErrors = 0;
+ dr->prev_WriteErrors = dr->cur_WriteErrors ;
+ dr->avg_WriteErrors = 0;
+ dr->prev_ReadRetries = dr->cur_ReadRetries ;
+ dr->avg_ReadRetries = 0;
+ dr->prev_WriteRetries = dr->cur_WriteRetries ;
+ dr->avg_WriteRetries = 0;
+ dr->prev_TotalReadTime = dr->cur_TotalReadTime ;
+ dr->avg_TotalReadTime = 0;
+ dr->prev_TotalWriteTime = dr->cur_TotalWriteTime ;
+ dr->avg_TotalWriteTime = 0;
+}
+
+
+static void
+print_drivestats_sample(char *timebufptr)
+{
+ struct drivestats_report *dr;
+ long double transfers_per_second;
+ long double kb_per_transfer, mb_per_second;
+ u_int64_t interval_bytes, interval_transfers, interval_blocks;
+ u_int64_t interval_time;
+ long double blocks_per_second, ms_per_transaction;
+
+ if (flag_count > 1)
+ print_column_heading(SAR_DRIVESTATS, timebufptr, 0);
+
+ for (dr=dr_head; dr; dr=(struct drivestats_report *)dr->next)
+ {
+ if(!dr->present)
+ continue;
+
+ /*
+ * This sanity check is for drives that get removed and then
+ * returned during the sampling sleep interval. If anything
+ * looks out of sync, reinit and skip this entry. There is
+ * no way to guard against this entirely.
+ */
+ if ((dr->cur_Reads < dr->prev_Reads) ||
+ (dr->cur_BytesRead < dr->prev_BytesRead) ||
+ (dr->cur_Writes < dr->prev_Writes) ||
+ (dr->cur_BytesWritten < dr->prev_BytesWritten))
+ {
+ init_drivestats(dr);
+ continue;
+ }
+
+ dr->avg_count++;
+
+ dr->cur_Reads -= dr->prev_Reads;
+ dr->prev_Reads += dr->cur_Reads;
+ dr->avg_Reads += dr->cur_Reads;
+
+ dr->cur_BytesRead -= dr->prev_BytesRead;
+ dr->prev_BytesRead += dr->cur_BytesRead;
+ dr->avg_BytesRead += dr->cur_BytesRead;
+
+ dr->cur_Writes -= dr->prev_Writes ;
+ dr->prev_Writes += dr->cur_Writes ;
+ dr->avg_Writes += dr->cur_Writes ;
+
+ dr->cur_BytesWritten -= dr->prev_BytesWritten ;
+ dr->prev_BytesWritten += dr->cur_BytesWritten ;
+ dr->avg_BytesWritten += dr->cur_BytesWritten ;
+
+ dr->cur_LatentReadTime -= dr->prev_LatentReadTime ;
+ dr->prev_LatentReadTime += dr->cur_LatentReadTime ;
+ dr->avg_LatentReadTime += dr->cur_LatentReadTime ;
+
+ dr->cur_LatentWriteTime -= dr->prev_LatentWriteTime ;
+ dr->prev_LatentWriteTime += dr->cur_LatentWriteTime ;
+ dr->avg_LatentWriteTime += dr->cur_LatentWriteTime ;
+
+ dr->cur_ReadErrors -= dr->prev_ReadErrors ;
+ dr->prev_ReadErrors += dr->cur_ReadErrors ;
+ dr->avg_ReadErrors += dr->cur_ReadErrors ;
+
+ dr->cur_WriteErrors -= dr->prev_WriteErrors ;
+ dr->prev_WriteErrors += dr->cur_WriteErrors ;
+ dr->avg_WriteErrors += dr->cur_WriteErrors ;
+
+ dr->cur_ReadRetries -= dr->prev_ReadRetries ;
+ dr->prev_ReadRetries += dr->cur_ReadRetries ;
+ dr->avg_ReadRetries += dr->cur_ReadRetries ;
+
+ dr->cur_WriteRetries -= dr->prev_WriteRetries ;
+ dr->prev_WriteRetries += dr->cur_WriteRetries;
+ dr->avg_WriteRetries += dr->cur_WriteRetries;
+
+ dr->cur_TotalReadTime -= dr->prev_TotalReadTime ;
+ dr->prev_TotalReadTime += dr->cur_TotalReadTime ;
+ dr->avg_TotalReadTime += dr->cur_TotalReadTime ;
+
+ dr->cur_TotalWriteTime -= dr->prev_TotalWriteTime ;
+ dr->prev_TotalWriteTime += dr->cur_TotalWriteTime ;
+ dr->avg_TotalWriteTime += dr->cur_TotalWriteTime ;
+
+ /* I/O volume */
+ interval_bytes = dr->cur_BytesRead + dr->cur_BytesWritten;
+
+ /* I/O counts */
+ interval_transfers = dr->cur_Reads + dr->cur_Writes;
+
+ /* I/O time */
+ interval_time = dr->cur_LatentReadTime + dr->cur_LatentWriteTime;
+
+ interval_blocks = interval_bytes / dr->blocksize;
+ blocks_per_second = interval_blocks / avg_interval;
+ transfers_per_second = interval_transfers / avg_interval;
+ mb_per_second = (interval_bytes / avg_interval) / (1024 *1024);
+
+ kb_per_transfer = (interval_transfers > 0) ?
+ ((long double)interval_bytes / interval_transfers)
+ / 1024 : 0;
+
+ /* times are in nanoseconds, convert to milliseconds */
+ ms_per_transaction = (interval_transfers > 0) ?
+ ((long double)interval_time / interval_transfers)
+ / 1000 : 0;
+
+ /* print device name */
+ fprintf(stdout, "%s %-10s", timebufptr, dr->name);
+
+ /* print transfers per second */
+ fprintf(stdout, "%4.0Lf ", transfers_per_second);
+
+ /* print blocks per second - in device blocksize */
+ fprintf(stdout, "%4.0Lf\n", blocks_per_second);
+ }
+}
+
+/*
+ * Print averages before exiting.
+ */
+static void
+exit_average()
+{
+ int i;
+
+ if (avg_counter <= 0 )
+ exit(0);
+
+ if (oflag)
+ {
+ if (ofd)
+ close (ofd);
+ ofd = 0;
+ }
+
+ if (uflag) /* print cpu averages */
+ {
+ if(flag_count > 1)
+ print_column_heading(SAR_CPU, 0, 0);
+
+ fprintf(stdout, "Average: %5d ",
+ (int)avg_cpuload.cpu_ticks[CPU_STATE_USER]
+ / (avg_counter ? avg_counter : 1));
+
+ fprintf(stdout, "%4d ",
+ (int)avg_cpuload.cpu_ticks[CPU_STATE_NICE]
+ / (avg_counter ? avg_counter : 1));
+
+ fprintf(stdout, "%4d ",
+ (int)avg_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
+ / (avg_counter ? avg_counter : 1));
+
+ fprintf(stdout, "%4d \n",
+ (int)avg_cpuload.cpu_ticks[CPU_STATE_IDLE]
+ / (avg_counter ? avg_counter : 1));
+
+ fflush(stdout);
+ }
+
+
+ if (gflag) /* print page-out averages */
+ {
+ if (flag_count > 1)
+ print_column_heading(SAR_VMSTAT, 0, 0);
+
+ fprintf(stdout, "Average: %8.1f\n",
+ (float)((avg_vmstat.pageouts / (avg_counter ? avg_counter : 1)) / avg_interval));
+ fflush(stdout);
+ }
+
+ if (pflag) /* print page-in averages */
+ {
+ if (flag_count > 1)
+ print_column_heading(SAR_VMSTAT, 0, 1);
+
+ fprintf(stdout, "Average: %8.1f %8.1f %8.1f\n",
+ (float)(((float)avg_vmstat.pageins / (avg_counter ? avg_counter : 1)) / avg_interval),
+ (float)(((float)avg_vmstat.cow_faults / (avg_counter ? avg_counter : 1)) / avg_interval),
+ (float)(((float)avg_vmstat.faults / (avg_counter ? avg_counter : 1)) / avg_interval));
+ fflush(stdout);
+ }
+
+ if (dflag) /* print drivestats averages */
+ {
+ struct drivestats_report *dr;
+ long double transfers_per_second;
+ long double kb_per_transfer, mb_per_second;
+ u_int64_t total_bytes, total_transfers, total_blocks;
+ u_int64_t total_time;
+ long double blocks_per_second, ms_per_transaction;
+ int msdig;
+
+ if (flag_count > 1)
+ print_column_heading(SAR_DRIVESTATS, 0, 0);
+
+ for (dr=dr_head; dr; dr=(struct drivestats_report *)dr->next)
+ {
+ /* don't bother to print out averages for disks that were removed */
+ if (!dr->present)
+ continue;
+
+ fprintf(stdout, " %s %s\n",
+ dp_table[dr->drivepath_id].BSDName, dp_table[dr->drivepath_id].ioreg_path);
+
+ /* I/O volume */
+ total_bytes = dr->avg_BytesRead + dr->avg_BytesWritten;
+
+ /* I/O counts */
+ total_transfers = dr->avg_Reads + dr->avg_Writes;
+
+ /* I/O time */
+ total_time = dr->avg_LatentReadTime + dr->avg_LatentWriteTime;
+
+ total_blocks = total_bytes / dr->blocksize;
+ blocks_per_second = total_blocks / avg_interval;
+ transfers_per_second = total_transfers / avg_interval;
+ mb_per_second = (total_bytes / avg_interval) / (1024 *1024);
+
+ kb_per_transfer = (total_transfers > 0) ?
+ ((long double)total_bytes / total_transfers)
+ / 1024 : 0;
+
+ /* times are in nanoseconds, convert to milliseconds */
+ ms_per_transaction = (total_transfers > 0) ?
+ ((long double)total_time / total_transfers)
+ / 1000 : 0;
+ msdig = (ms_per_transaction < 100.0) ? 1 : 0;
+ fprintf(stdout, "Average: %-10s %4.0Lf %4.0Lf\n",
+ dr->name,
+ (transfers_per_second / dr->avg_count),
+ (blocks_per_second / dr->avg_count));
+
+ fflush(stdout);
+ }
+ } /* end if dflag */
+
+ if (nflag)
+ {
+ int avg_count;
+
+ if (network_mode & NET_DEV_MODE)
+ {
+ if (flag_count > 1)
+ print_column_heading(SAR_NETSTATS, 0, NET_DEV_MODE);
+ for (i = 0; i < nr_count; i++)
+ {
+ if (!nr_table[i].valid)
+ continue;
+
+ if(nr_table[i].avg_count == 0)
+ avg_count = 1;
+ else
+ avg_count = nr_table[i].avg_count;
+
+ fprintf(stdout, "Average: %-8.8s", nr_table[i].tname_unit);
+
+ fprintf (stdout, "%8llu ",
+ ((nr_table[i].avg_ipackets / avg_count) / avg_interval));
+
+ fprintf (stdout, "%10llu ",
+ ((nr_table[i].avg_ibytes / avg_count) / avg_interval));
+
+ fprintf (stdout, "%8llu ",
+ ((nr_table[i].avg_opackets / avg_count) / avg_interval));
+
+ fprintf (stdout, "%10llu\n",
+ ((nr_table[i].avg_obytes / avg_count) / avg_interval));
+
+ fflush(stdout);
+ }
+ }
+
+ if (network_mode & NET_EDEV_MODE)
+ {
+
+ if(flag_count > 1)
+ print_column_heading(SAR_NETSTATS, 0, NET_EDEV_MODE);
+
+ for (i = 0; i < nr_count; i++)
+ {
+ if (!nr_table[i].valid)
+ continue;
+
+ if(nr_table[i].avg_count == 0)
+ avg_count = 1;
+ else
+ avg_count = nr_table[i].avg_count;
+
+ fprintf(stdout, "Average: %-8.8s ", nr_table[i].tname_unit);
+
+ fprintf (stdout, "%7llu ",
+ ((nr_table[i].avg_ierrors / avg_count) / avg_interval));
+
+ fprintf (stdout, "%7llu ",
+ ((nr_table[i].avg_oerrors / avg_count) / avg_interval));
+
+ fprintf (stdout, "%5llu ",
+ ((nr_table[i].avg_collisions / avg_count) / avg_interval));
+
+ fprintf (stdout, " %5llu\n",
+ ((nr_table[i].avg_drops / avg_count) / avg_interval));
+
+ fflush(stdout);
+ }
+ }
+
+ } /* end if nflag */
+ exit(0);
+}
+
+
+/*
+ * Return < 0 failure, debugging purposes only
+ * Return = 0 data skipped
+ * Return > 0 success
+ */
+
+static int
+get_drivepath_sample(flag, hdr)
+ int flag;
+ struct record_hdr *hdr;
+{
+ size_t datasize;
+ struct drivepath dp;
+ struct drivestats_report *dr;
+ int i, n;
+
+ datasize = hdr->rec_count * hdr->rec_size;
+
+ if (datasize != sizeof(struct drivepath))
+ {
+ /* read past the data but don't do anything with it */
+ skip_data(datasize);
+ return(0);
+ }
+
+ read_record_data ((char *)&dp, (int)sizeof(struct drivepath), TRUE );
+
+ /*
+ * If state is new -- put a new entry in the dp_table.
+ * If state is changed -- traverse the drivestats_report table
+ * and copy new name.
+ */
+ if (dp.state == DPSTATE_NEW)
+ {
+
+ if (dp_table == NULL)
+ {
+ if (dp.drivepath_id != 0)
+ return(-1);
+ /* First setup of internal drivepath table */
+ dp_table = (struct drivepath *)malloc(sizeof(struct drivepath));
+ if (dp_table == NULL)
+ return(-2);
+ dp_count = 1;
+ }
+
+ if (dflag)
+ fprintf(stdout, "New Disk: [%s] %s\n", dp.BSDName, dp.ioreg_path);
+
+ /* traverse table and find next uninitialized entry */
+ for (i = 0; i< dp_count; i++)
+ {
+ if (dp_table[i].state == DPSTATE_UNINITIALIZED)
+ {
+ if (dp.drivepath_id != i)
+ {
+ /* the table is out of sync - this should not happen */
+ return (-3);
+ }
+ dp_table[i] = dp;
+ return(1);
+ }
+ }
+ /*
+ * If we get here, we've run out of table entries.
+ * Double the size of the table, then assign the next entry.
+ */
+ if (dp.drivepath_id != i)
+ {
+ /* the table is out of sync - this should not happen */
+ return (-4);
+ }
+ n = dp_count * 2;
+ dp_table = (struct drivepath *)realloc(dp_table, n * sizeof(struct drivepath));
+ bzero(&dp_table[dp_count], dp_count * sizeof(struct drivepath));
+ dp_table[dp_count] = dp;
+ dp_count = n;
+ return(1);
+
+ }
+ else if (dp.state == DPSTATE_CHANGED)
+ {
+
+ /* Update the name in the table */
+ if ((dp.drivepath_id < dp_count) && (dp_table[dp.drivepath_id].state != DPSTATE_UNINITIALIZED))
+ {
+ if (strcmp(dp_table[dp.drivepath_id].ioreg_path, dp.ioreg_path) != 0)
+ {
+ /* something is amiss */
+ return (-5);
+ }
+ else
+ {
+ if (dflag)
+ {
+ fprintf(stdout, "Change: [%s] %s\n", dp.BSDName,
+ dp_table[dp.drivepath_id].ioreg_path);
+ }
+ strcpy(dp_table[dp.drivepath_id].BSDName, dp.BSDName);
+
+ for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
+ {
+ if (dr->drivepath_id == dp.drivepath_id)
+ strcpy(dr->name, dp.BSDName);
+ }
+ return(1);
+ }
+ }
+ else
+ return(-6);
+ }
+ return(-7);
+}
+
+/*
+ * Bytes and packet counts are used to track
+ * counter wraps. So, don't enforce the
+ * NET_DEV_MODE or NET_EDEV_MODE in here.
+ * Maintain all the stats.
+ */
+static void
+set_cur_netstats(struct netstats_report *nr, struct netstats *ns)
+{
+
+ nr->cur_ipackets = ns->net_ipackets;
+ nr->cur_ibytes = ns->net_ibytes;
+ nr->cur_opackets = ns->net_opackets;
+ nr->cur_obytes = ns->net_obytes;
+
+ nr->cur_ierrors = ns->net_ierrors;
+ nr->cur_oerrors = ns->net_oerrors;
+ nr->cur_collisions = ns->net_collisions;
+ nr->cur_drops = ns->net_drops;
+
+ nr->cur_imcasts = ns->net_imcasts;
+ nr->cur_omcasts = ns->net_omcasts;
+
+}
+
+static void
+init_prev_netstats(struct netstats_report *nr)
+{
+ nr->avg_count = 0;
+ nr->valid = 1;
+ nr->present = 1;
+
+ nr->prev_ipackets = nr->cur_ipackets;
+ nr->avg_ipackets = 0;
+ nr->prev_ibytes = nr->cur_ibytes;
+ nr->avg_ibytes = 0;
+ nr->prev_opackets = nr->cur_opackets;
+ nr->avg_opackets = 0;
+ nr->prev_obytes = nr->cur_obytes;
+ nr->avg_obytes = 0;
+
+ nr->prev_ierrors = nr->cur_ierrors;
+ nr->avg_ierrors = 0;
+ nr->prev_oerrors = nr->cur_oerrors ;
+ nr->avg_oerrors = 0;
+ nr->prev_collisions = nr->cur_collisions ;
+ nr->avg_collisions = 0;
+ nr->prev_drops = nr->cur_drops ;
+ nr->avg_drops = 0;
+
+ /* track these, but never displayed */
+ nr->prev_imcasts = nr->cur_imcasts;
+ nr->avg_imcasts = 0;
+ nr->prev_omcasts = nr->cur_omcasts;
+ nr->avg_omcasts = 0;
+}
+
+/*
+ * Success : 1
+ * Failure : 0
+ */
+static int
+get_netstats_sample(flag, hdr)
+ int flag;
+ struct record_hdr *hdr;
+{
+ struct netstats *databuf = NULL;
+ size_t datasize;
+ int datacount;
+ int i, j;
+
+ datasize = hdr->rec_count * hdr->rec_size;
+ datacount = hdr->rec_count;
+
+ if (hdr->rec_size != sizeof(struct netstats))
+ {
+ /* something isn't right... read past the data but don't analyze it */
+ skip_data(datasize);
+ return(0);
+ }
+
+ /* malloc new or bigger read buffer */
+ if((netstat_readbuf == NULL) || (netstat_readbuf_size < datasize))
+ {
+ if (netstat_readbuf)
+ free (netstat_readbuf);
+
+ if ((netstat_readbuf = (struct netstats *)malloc(datasize)) == NULL)
+ {
+ fprintf(stderr, "sar: malloc failed\n");
+ exit (EXIT_FAILURE);
+ }
+ netstat_readbuf_size = datasize;
+ }
+
+ bzero(netstat_readbuf, netstat_readbuf_size);
+ databuf = netstat_readbuf;
+
+ read_record_data ((char *)databuf, datasize, TRUE );
+
+ if (nr_table == NULL)
+ {
+ /* initial internal table setup */
+ nr_table = (struct netstats_report *)malloc(datacount * sizeof(struct netstats_report));
+ nr_count = datacount;
+ bzero(nr_table, (datacount * sizeof(struct netstats_report)));
+
+ /* on first init, this is faster than finding our way to NEW_ENTRY */
+ for (i = 0; i < datacount; i++)
+ {
+ if (!(network_mode & NET_PPP_MODE))
+ {
+ if (!strncmp(databuf[i].tname_unit, "ppp", 3))
+ continue; /*
+ * Skip ppp interfaces.
+ * ie don't even put them in this internal table.
+ */
+ }
+ strncpy(nr_table[i].tname_unit, databuf[i].tname_unit, MAX_TNAME_UNIT_SIZE);
+ nr_table[i].tname_unit[MAX_TNAME_UNIT_SIZE] = '\0';
+ set_cur_netstats(&nr_table[i], &databuf[i]);
+ init_prev_netstats(&nr_table[i]);
+ }
+ return(1);
+ }
+
+ /*
+ * clear all the present flags.
+ * As we traverse the current sample set
+ * and update the internal table, the flag
+ * is reset.
+ */
+ for (i = 0; i < nr_count; i++)
+ {
+ nr_table[i].present = 0;
+ }
+
+ /*
+ * Find and update table entries.
+ * Init new entries.
+ */
+ for (i=0; i<datacount; i++)
+ {
+ int found;
+ char *name;
+ int nr_index;
+ int n;
+
+ name = databuf[i].tname_unit;
+ found = 0;
+
+ if (!(network_mode & NET_PPP_MODE))
+ {
+ if (!strncmp(name, "ppp", 3))
+ continue; /* skip ppp interfaces */
+ }
+
+ /* Find the matching entry using the interface name */
+ for (j=0; j < nr_count && !found; j++)
+ {
+ if (nr_table[j].valid)
+ {
+ if(!strcmp(nr_table[j].tname_unit, name))
+ {
+ found = 1;
+ nr_table[j].present = 1;
+ set_cur_netstats(&nr_table[j], &databuf[i]);
+ }
+ }
+ } /* end for */
+
+ if (!found) /* this is a new entry */
+ {
+ /* Find an invalid entry in the table and init it */
+ for (j=0; j < nr_count; j++)
+ {
+ if (!nr_table[j].valid)
+ {
+ nr_index = j;
+ goto NEW_ENTRY;
+ }
+ }
+
+ /* we ran out of entries... grow the table */
+ n = nr_count * 2;
+ nr_table = (struct netstats_report *)realloc(nr_table, n * sizeof(struct netstats_report));
+ bzero(&nr_table[nr_count], nr_count * sizeof (struct netstats_report));
+ nr_index = nr_count;
+ nr_count = n;
+
+ NEW_ENTRY:
+ strncpy(nr_table[nr_index].tname_unit, databuf[i].tname_unit, MAX_TNAME_UNIT_SIZE);
+ nr_table[nr_index].tname_unit[MAX_TNAME_UNIT_SIZE] = '\0';
+ set_cur_netstats(&nr_table[nr_index], &databuf[i]);
+ init_prev_netstats(&nr_table[nr_index]);
+ }
+
+ } /* end for */
+
+ /*
+ * Traverse the internal table. Any valid entry that wasn't
+ * present in this sample is cleared for reuse.
+ */
+ for (i = 0; i < nr_count; i++)
+ {
+ if (nr_table[i].valid)
+ {
+ if (nr_table[i].present == 0)
+ bzero(&nr_table[i], sizeof(struct netstats_report));
+ }
+ }
+ return (1);
+}
+
+static void
+print_netstats_sample(char *timebufptr)
+{
+ int i;
+
+ for (i=0; i < nr_count; i++)
+ {
+ if (!nr_table[i].valid)
+ continue;
+
+ /*
+ * This is where we attempt to handle counters that
+ * might wrap ... the kernel netstats are only 32 bits.
+ *
+ * Interfaces may go away and then return within the
+ * sampling period. This can't be detected and it
+ * may look like a counter wrap. An interface generation
+ * counter will help... but isn't implemented at this time.
+ */
+
+ /*
+ * The ppp interfaces are very likely to come and go during
+ * a sampling period. During the normal life of a ppp interface,
+ * it's less likely that the packet counter will wrap, so if
+ * it appears to have done so, is probably because the
+ * interface unit number has been reused.
+ * We reinitialize that interface in that case.
+ */
+ if (network_mode & NET_PPP_MODE)
+ {
+ /*
+ * ppp interfaces won't even make it into this table
+ * when NET_PPP_MODE isn't set
+ */
+ if (!strncmp(nr_table[i].tname_unit, "ppp", 3))
+ {
+ /*
+ * Both ipackets and opackets have to be less
+ * than the previous counter to cause us to reinit.
+ */
+
+ if ((nr_table[i].cur_ipackets < nr_table[i].prev_ipackets)
+ && (nr_table[i].cur_opackets < nr_table[i].prev_opackets))
+ {
+ init_prev_netstats(&nr_table[i]);
+ continue;
+ }
+ }
+ }
+
+ nr_table[i].avg_count ++;
+
+#ifdef IFNET_32_BIT_COUNTERS
+ while (nr_table[i].cur_ipackets < nr_table[i].prev_ipackets)
+ nr_table[i].cur_ipackets += 0x100000000LL;
+#endif /* IFNET_32_BIT_COUNTERS */
+ nr_table[i].cur_ipackets -= nr_table[i].prev_ipackets;
+ nr_table[i].prev_ipackets += nr_table[i].cur_ipackets;
+ nr_table[i].avg_ipackets += nr_table[i].cur_ipackets;
+
+
+#ifdef IFNET_32_BIT_COUNTERS
+ while (nr_table[i].cur_ibytes < nr_table[i].prev_ibytes)
+ nr_table[i].cur_ibytes += 0x100000000LL;
+#endif /* IFNET_32_BIT_COUNTERS */
+ nr_table[i].cur_ibytes -= nr_table[i].prev_ibytes;
+ nr_table[i].prev_ibytes += nr_table[i].cur_ibytes;
+ nr_table[i].avg_ibytes += nr_table[i].cur_ibytes;
+
+
+#ifdef IFNET_32_BIT_COUNTERS
+ while (nr_table[i].cur_opackets < nr_table[i].prev_opackets)
+ nr_table[i].cur_opackets += 0x100000000LL;
+#endif /* IFNET_32_BIT_COUNTERS */
+ nr_table[i].cur_opackets -= nr_table[i].prev_opackets;
+ nr_table[i].prev_opackets += nr_table[i].cur_opackets;
+ nr_table[i].avg_opackets += nr_table[i].cur_opackets;
+
+#ifdef IFNET_32_BIT_COUNTERS
+ while (nr_table[i].cur_obytes < nr_table[i].prev_obytes)
+ nr_table[i].cur_obytes += 0x100000000LL;
+#endif /* IFNET_32_BIT_COUNTERS */
+ nr_table[i].cur_obytes -= nr_table[i].prev_obytes;
+ nr_table[i].prev_obytes += nr_table[i].cur_obytes;
+ nr_table[i].avg_obytes += nr_table[i].cur_obytes;
+
+
+#ifdef IFNET_32_BIT_COUNTERS
+ while (nr_table[i].cur_ierrors < nr_table[i].prev_ierrors)
+ nr_table[i].cur_ierrors += 0x100000000LL;
+#endif /* IFNET_32_BIT_COUNTERS */
+ nr_table[i].cur_ierrors -= nr_table[i].prev_ierrors;
+ nr_table[i].prev_ierrors += nr_table[i].cur_ierrors;
+ nr_table[i].avg_ierrors += nr_table[i].cur_ierrors;
+
+#ifdef IFNET_32_BIT_COUNTERS
+ while (nr_table[i].cur_oerrors < nr_table[i].prev_oerrors)
+ nr_table[i].cur_oerrors += 0x100000000LL;
+#endif /* IFNET_32_BIT_COUNTERS */
+ nr_table[i].cur_oerrors -= nr_table[i].prev_oerrors;
+ nr_table[i].prev_oerrors += nr_table[i].cur_oerrors;
+ nr_table[i].avg_oerrors += nr_table[i].cur_oerrors;
+
+#ifdef IFNET_32_BIT_COUNTERS
+ while (nr_table[i].cur_collisions < nr_table[i].prev_collisions)
+ nr_table[i].cur_collisions += 0x100000000LL;
+#endif /* IFNET_32_BIT_COUNTERS */
+ nr_table[i].cur_collisions -= nr_table[i].prev_collisions;
+ nr_table[i].prev_collisions += nr_table[i].cur_collisions;
+ nr_table[i].avg_collisions += nr_table[i].cur_collisions;
+
+#ifdef IFNET_32_BIT_COUNTERS
+ while (nr_table[i].cur_drops < nr_table[i].prev_drops)
+ nr_table[i].cur_drops += 0x100000000LL;
+#endif /* IFNET_32_BIT_COUNTERS */
+ nr_table[i].cur_drops -= nr_table[i].prev_drops;
+ nr_table[i].prev_drops += nr_table[i].cur_drops;
+ nr_table[i].avg_drops += nr_table[i].cur_drops;
+
+
+#ifdef IFNET_32_BIT_COUNTERS
+ while (nr_table[i].cur_imcasts < nr_table[i].prev_imcasts)
+ nr_table[i].cur_imcasts += 0x100000000LL;
+#endif /* IFNET_32_BIT_COUNTERS */
+ nr_table[i].cur_imcasts -= nr_table[i].prev_imcasts;
+ nr_table[i].prev_imcasts += nr_table[i].cur_imcasts;
+ nr_table[i].avg_imcasts += nr_table[i].cur_imcasts;
+
+#ifdef IFNET_32_BIT_COUNTERS
+ while (nr_table[i].cur_omcasts < nr_table[i].prev_omcasts)
+ nr_table[i].cur_omcasts += 0x100000000LL;
+#endif /* IFNET_32_BIT_COUNTERS */
+ nr_table[i].cur_omcasts -= nr_table[i].prev_omcasts;
+ nr_table[i].prev_omcasts += nr_table[i].cur_omcasts;
+ nr_table[i].avg_omcasts += nr_table[i].cur_omcasts;
+ }
+
+
+ if (!(flag_count > 1))
+ fprintf(stdout, "\n");
+
+ if (network_mode & NET_DEV_MODE)
+ {
+ if (flag_count > 1)
+ print_column_heading(SAR_NETSTATS, timebufptr, NET_DEV_MODE);
+
+ for (i=0; i < nr_count; i++)
+ {
+ if (!nr_table[i].valid)
+ continue;
+
+ if (!(network_mode & NET_PPP_MODE))
+ {
+ if (!strncmp(nr_table[i].tname_unit, "ppp", 3))
+ {
+ continue; /* skip any ppp interfaces */
+ }
+ }
+
+ /* print the interface name */
+ fprintf(stdout, "%s %-8.8s", timebufptr, nr_table[i].tname_unit);
+
+ fprintf (stdout, "%8llu ",
+ (nr_table[i].cur_ipackets / avg_interval));
+
+ fprintf (stdout, "%10llu ",
+ (nr_table[i].cur_ibytes / avg_interval));
+
+ fprintf (stdout, "%8llu ",
+ (nr_table[i].cur_opackets / avg_interval));
+
+ fprintf (stdout, "%10llu\n",
+ (nr_table[i].cur_obytes / avg_interval));
+ }
+ }
+
+
+ if (network_mode & NET_EDEV_MODE)
+ {
+ if(flag_count > 1)
+ {
+ print_column_heading(SAR_NETSTATS, timebufptr, NET_EDEV_MODE);
+ }
+
+ for (i=0; i < nr_count; i++)
+ {
+ if (!nr_table[i].valid)
+ continue;
+
+ if (!(network_mode & NET_PPP_MODE))
+ {
+ if (!strncmp(nr_table[i].tname_unit, "ppp", 3))
+ {
+ continue; /* skip any ppp interfaces */
+ }
+ }
+
+ /* print the interface name */
+ fprintf(stdout, "%s %-8.8s ", timebufptr, nr_table[i].tname_unit);
+
+ fprintf (stdout, "%7llu ",
+ (nr_table[i].cur_ierrors / avg_interval));
+
+ fprintf (stdout, "%7llu ",
+ (nr_table[i].cur_oerrors / avg_interval));
+
+ fprintf (stdout, "%5llu ",
+ (nr_table[i].cur_collisions / avg_interval));
+
+ fprintf (stdout, " %5llu\n",
+ (nr_table[i].cur_drops / avg_interval));
+ }
+ fflush(stdout);
+ }
+}
+
+static void
+print_column_heading(int type, char *timebufptr, int mode)
+{
+ char *p;
+
+ p = timebufptr;
+
+ if (p == NULL)
+ p = "Average:";
+
+ if (!(flag_count > 1))
+ fprintf(stdout, "\n");
+
+ switch (type)
+ {
+ case SAR_CPU:
+ fprintf (stdout, "\n%s %%usr %%nice %%sys %%idle\n", p);
+ break;
+
+ case SAR_VMSTAT:
+ if (mode == 0) /* gflag */
+ fprintf(stdout, "\n%s pgout/s\n", p);
+ else if (mode == 1) /* pflag */
+ fprintf(stdout, "\n%s pgin/s pflt/s vflt/s\n", p);
+ break;
+ case SAR_DRIVESTATS:
+ fprintf(stdout, "\n%s device r+w/s blks/s\n", p);
+ break;
+ case SAR_NETSTATS:
+ if (mode == NET_DEV_MODE)
+ {
+ fprintf(stdout, "\n%s %-8.8s %8.8s %10.10s %8.8s %10.10s\n", p,
+ " IFACE", "Ipkts/s", "Ibytes/s", "Opkts/s", "Obytes/s");
+ }
+ else if (mode == NET_EDEV_MODE)
+ {
+ fprintf(stdout, "\n%s %-8.8s %7.7s %7.7s %5s %s\n", p,
+ " IFACE", "Ierrs/s", "Oerrs/s", "Coll/s", "Drop/s");
+ }
+ break;
+ default:
+ break;
+ }
+}
+
--- /dev/null
+/*
+ * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
+ * Reserved.
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * 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.
+*/
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/storage/IOBlockStorageDriver.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/IOBSD.h>
+
+#define MAXDRIVENAME 31 /* largest drive name we allow */
+
+
+struct drivestats_report
+{
+ char *next;
+ int32_t present;
+ int32_t avg_count;
+ int32_t drivepath_id;
+ char name[MAXDRIVENAME+1];
+ uint64_t blocksize;
+
+ uint64_t cur_Reads;
+ uint64_t prev_Reads;
+ uint64_t avg_Reads;
+
+ uint64_t cur_BytesRead;
+ uint64_t prev_BytesRead;
+ uint64_t avg_BytesRead;
+
+ uint64_t cur_Writes;
+ uint64_t prev_Writes;
+ uint64_t avg_Writes;
+
+ uint64_t cur_BytesWritten;
+ uint64_t prev_BytesWritten;
+ uint64_t avg_BytesWritten;
+
+ uint64_t cur_LatentReadTime;
+ uint64_t prev_LatentReadTime;
+ uint64_t avg_LatentReadTime;
+
+ uint64_t cur_LatentWriteTime;
+ uint64_t prev_LatentWriteTime;
+ uint64_t avg_LatentWriteTime;
+
+ uint64_t cur_ReadErrors;
+ uint64_t prev_ReadErrors;
+ uint64_t avg_ReadErrors;
+
+ uint64_t cur_WriteErrors;
+ uint64_t prev_WriteErrors;
+ uint64_t avg_WriteErrors;
+
+ uint64_t cur_ReadRetries;
+ uint64_t prev_ReadRetries;
+ uint64_t avg_ReadRetries;
+
+ uint64_t cur_WriteRetries;
+ uint64_t prev_WriteRetries;
+ uint64_t avg_WriteRetries;
+
+ uint64_t cur_TotalReadTime;
+ uint64_t prev_TotalReadTime;
+ uint64_t avg_TotalReadTime;
+
+ uint64_t cur_TotalWriteTime;
+ uint64_t prev_TotalWriteTime;
+ uint64_t avg_TotalWriteTime;
+};
+
+struct netstats_report
+{
+ int32_t valid;
+ int32_t present;
+ int32_t avg_count;
+ uint32_t gen_counter;
+ char tname_unit[MAX_TNAME_UNIT_SIZE +1 ];
+
+ uint64_t cur_ipackets;
+ uint64_t prev_ipackets;
+ uint64_t avg_ipackets;
+
+ uint64_t cur_ierrors;
+ uint64_t prev_ierrors;
+ uint64_t avg_ierrors;
+
+ uint64_t cur_opackets;
+ uint64_t prev_opackets;
+ uint64_t avg_opackets;
+
+ uint64_t cur_oerrors;
+ uint64_t prev_oerrors;
+ uint64_t avg_oerrors;
+
+ uint64_t cur_collisions;
+ uint64_t prev_collisions;
+ uint64_t avg_collisions;
+
+ uint64_t cur_ibytes;
+ uint64_t prev_ibytes;
+ uint64_t avg_ibytes;
+
+ uint64_t cur_obytes;
+ uint64_t prev_obytes;
+ uint64_t avg_obytes;
+
+ uint64_t cur_imcasts;
+ uint64_t prev_imcasts;
+ uint64_t avg_imcasts;
+
+ uint64_t cur_omcasts;
+ uint64_t prev_omcasts;
+ uint64_t avg_omcasts;
+
+ uint64_t cur_drops;
+ uint64_t prev_drops;
+ uint64_t avg_drops;
+};
--- /dev/null
+.\" Copyright (c) 2000, Apple Computer, Inc. All rights reserved.
+.\"
+.Dd October 28, 2002
+.Dt SC_USAGE 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm sc_usage
+.Nd show system call usage statistics
+.Sh SYNOPSIS
+.Nm sc_usage
+.Op Fl c Ar codefile
+.Op Fl e
+.Op Fl l
+.Op Fl s Ar interval
+pid | cmd |
+.Fl E
+execute
+.Sh DESCRIPTION
+.Nm sc_usage
+displays an ongoing sample of system call and page fault usage statistics for
+a given process in a
+.Dq Li top-like
+fashion.
+It requires root privileges due to the kernel tracing facility it uses to
+operate.
+.Pp
+Page faults can be of the following types:
+.Bl -tag -width CACHEHITTT -compact
+.It PAGE_IN
+page had to read from disk
+.It ZERO_FILL
+page was created and zero filled
+.It COW
+page was copied from another page
+.It CACHE_HIT
+page was found in the cache
+.El
+.Pp
+The arguments are as follows:
+.Bl -tag -width Ds
+.It Fl c
+When the
+.Fl c
+option is specified, it expects a path to a
+.Ar codefile
+that
+contains the mappings for the system calls.
+This option overrides the default location of the system call codefile which
+is found in /usr/share/misc/trace.codes.
+.It Fl e
+Specifying the
+.Fl e
+option generates output that is sorted by call count.
+This overrides the default sort by time.
+.It Fl l
+The
+.Fl l
+option causes
+.Nm sc_usage
+to turn off its continuous window updating style of output and instead output
+as a continuous scrolling of data.
+.It Fl s
+By default,
+.Nm sc_usage
+updates its output at one second intervals.
+This sampling interval may be changed by specifying the
+.Fl s
+option.
+Enter the
+.Ar interval
+in seconds.
+.It pid | cmd | -E execute
+The last argument must be a process id, a running command name, or using the
+.Fl E
+option, an execution path followed by optional arguments.
+The system call usage data for the process or command is displayed.
+If the
+.Fl E
+flag is used, sc_usage will launch the executable, pass along any optional
+arguments and display system call usage date for that executable.
+.El
+.Pp
+The data columns displayed are as follows:
+.Bl -tag -width LAST_PATHNAME_WAITED_FOR -compact
+.Pp
+.It TYPE
+the system call type
+.It NUMBER
+the system call count
+.It CPU_TIME
+the amount of cpu time consumed
+.It WAIT_TIME
+the absolute time the process is waiting
+.It CURRENT_TYPE
+the current system call type
+.It LAST_PATHNAME_WAITED_FOR
+for each active thread, the last pathname
+that was referenced by a system call that blocked
+.It CUR_WAIT_TIME
+the cumulative time that a thread has been blocked
+.It THRD#
+the thread number
+.It PRI
+current scheduling priority
+.El
+.Pp
+The
+.Nm sc_usage
+command also displays some global state in the first few lines of output,
+including the number of preemptions, context switches, threads, faults and
+system calls, found during the sampling period.
+The current time and the elapsed time that the command has been running is also
+displayed here.
+The
+.Nm sc_usage
+command is also SIGWINCH savvy, so adjusting your window geometry may change
+the list of system calls being displayed.
+Typing a
+.Sq Li q
+will cause sc_usage to exit immediately.
+Typing any other character will cause sc_usage to reset its counters and the
+display.
+.Sh SAMPLE USAGE
+.Pp
+sc_usage Finder -e -s2
+.Pp
+.Nm sc_usage
+will sort the Finder process usage data according to system call count and
+update the output at 2 second intervals.
+.Sh SEE ALSO
+.Xr fs_usage 1 ,
+.Xr latency 1 ,
+.Xr top 1
--- /dev/null
+/*
+ * Copyright (c) 1999-2007 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@
+ */
+
+/*
+cc -I. -DPRIVATE -D__APPLE_PRIVATE -O -o sc_usage sc_usage.c -lncurses
+*/
+
+#define Default_DELAY 1 /* default delay interval */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <strings.h>
+#include <nlist.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/ptrace.h>
+
+#include <libc.h>
+#include <termios.h>
+#include <curses.h>
+
+#include <sys/ioctl.h>
+
+#ifndef KERNEL_PRIVATE
+#define KERNEL_PRIVATE
+#include <sys/kdebug.h>
+#undef KERNEL_PRIVATE
+#else
+#include <sys/kdebug.h>
+#endif /*KERNEL_PRIVATE*/
+
+#include <sys/sysctl.h>
+#include <errno.h>
+#include <mach/mach_time.h>
+#include <err.h>
+#include <libutil.h>
+
+/* Number of lines of header information on the standard screen */
+#define HEADER_LINES 5
+
+int newLINES = 0;
+int Header_lines = HEADER_LINES;
+
+int how_to_sort = 0;
+int no_screen_refresh = 0;
+int execute_flag = 0;
+int topn = 0;
+int pid;
+int called = 0;
+int sort_now = 0;
+int waiting_index = 0;
+FILE *dfp = 0; /*Debug output file */
+long start_time = 0;
+
+#define SAMPLE_SIZE 20000
+
+#define DBG_ZERO_FILL_FAULT 1
+#define DBG_PAGEIN_FAULT 2
+#define DBG_COW_FAULT 3
+#define DBG_CACHE_HIT_FAULT 4
+
+#define MAX_SC 1024
+#define MAX_THREADS 16
+#define MAX_NESTED 8
+#define MAX_FAULTS 5
+
+
+#define NUMPARMS 23
+
+
+char *state_name[] = {
+ "Dont Know",
+ "Running S",
+ "Running U",
+ "Waiting",
+ "Pre-empted",
+};
+
+#define DONT_KNOW 0
+#define KERNEL_MODE 1
+#define USER_MODE 2
+#define WAITING 3
+#define PREEMPTED 4
+
+struct entry {
+ int sc_state;
+ int type;
+ int code;
+ double otime;
+ double stime;
+ double ctime;
+ double wtime;
+};
+
+struct th_info {
+ int thread;
+ int depth;
+ int vfslookup;
+ int curpri;
+ long *pathptr;
+ long pathname[NUMPARMS + 1];
+ struct entry th_entry[MAX_NESTED];
+};
+
+struct sc_entry {
+ char name[32];
+ int delta_count;
+ int total_count;
+ int waiting;
+ unsigned int stime_secs;
+ double stime_usecs;
+ unsigned int wtime_secs;
+ double wtime_usecs;
+ unsigned int delta_wtime_secs;
+ double delta_wtime_usecs;
+};
+
+struct th_info th_state[MAX_THREADS];
+struct sc_entry faults[MAX_FAULTS];
+
+struct sc_entry *sc_tab;
+int *msgcode_tab;
+int msgcode_cnt; /* number of MSG_ codes */
+
+int num_of_threads = 0;
+int now_collect_cpu_time = 0;
+
+unsigned int utime_secs;
+double utime_usecs;
+
+int in_idle = 0;
+unsigned int itime_secs;
+double itime_usecs;
+unsigned int delta_itime_secs;
+double delta_itime_usecs;
+double idle_start;
+
+int in_other = 0;
+unsigned int otime_secs;
+double otime_usecs;
+unsigned int delta_otime_secs;
+double delta_otime_usecs;
+double other_start;
+
+int max_sc = 0;
+int bsc_base = 0;
+int msc_base = 0;
+int mach_idle = 0;
+int mach_sched = 0;
+int mach_stkhandoff = 0;
+int vfs_lookup = 0;
+int mach_vmfault = 0;
+int bsc_exit = 0;
+int *sort_by_count;
+int *sort_by_wtime;
+
+char proc_name[32];
+
+#define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
+#define DBG_FUNC_MASK 0xfffffffc
+
+int preempted;
+int csw;
+int total_faults;
+int scalls;
+
+/* Default divisor */
+#define DIVISOR 16.6666 /* Trace divisor converts to microseconds */
+double divisor = DIVISOR;
+
+
+int mib[6];
+size_t needed;
+char *my_buffer;
+
+kbufinfo_t bufinfo = {0, 0, 0, 0};
+
+int trace_enabled = 0;
+int set_remove_flag = 1;
+
+struct kinfo_proc *kp_buffer = 0;
+int kp_nentries = 0;
+
+extern char **environ;
+
+void set_enable();
+void set_pidcheck();
+void set_remove();
+void set_numbufs();
+void set_init();
+void quit(char *);
+int argtopid(char *);
+int argtoi(int, char*, char*, int);
+
+void get_bufinfo(kbufinfo_t *);
+
+
+/*
+ * signal handlers
+ */
+
+void leave() /* exit under normal conditions -- INT handler */
+{
+
+ if (no_screen_refresh == 0) {
+ move(LINES - 1, 0);
+ refresh();
+ endwin();
+ }
+ set_enable(0);
+ set_pidcheck(pid, 0);
+ set_remove();
+ exit(0);
+}
+
+void err_leave(s) /* exit under error conditions */
+char *s;
+{
+
+ if (no_screen_refresh == 0) {
+ move(LINES - 1, 0);
+ refresh();
+ endwin();
+ }
+
+ printf("sc_usage: ");
+ if (s)
+ printf("%s ", s);
+
+ set_enable(0);
+ set_pidcheck(pid, 0);
+ set_remove();
+
+ exit(1);
+}
+
+void sigwinch()
+{
+ if (no_screen_refresh == 0)
+ newLINES = 1;
+}
+
+int
+exit_usage(char *myname) {
+
+ fprintf(stderr, "Usage: %s [-c codefile] [-e] [-l] [-sn] pid | cmd | -E execute path\n", myname);
+ fprintf(stderr, " -c name of codefile containing mappings for syscalls\n");
+ fprintf(stderr, " Default is /usr/share/misc/trace.codes\n");
+ fprintf(stderr, " -e enable sort by call count\n");
+ fprintf(stderr, " -l turn off top style output\n");
+ fprintf(stderr, " -sn change sample rate to every n seconds\n");
+ fprintf(stderr, " pid selects process to sample\n");
+ fprintf(stderr, " cmd selects command to sample\n");
+ fprintf(stderr, " -E Execute the given path and optional arguments\n");
+
+ exit(1);
+}
+
+
+#define usec_to_1000ths(t) ((t) / 1000)
+
+void print_time(char *p, unsigned int useconds, unsigned int seconds)
+{
+ long minutes, hours;
+
+ minutes = seconds / 60;
+ hours = minutes / 60;
+
+ if (minutes < 100) { // up to 100 minutes
+ sprintf(p, "%02ld:%02ld.%03ld", minutes, (unsigned long)(seconds % 60),
+ (unsigned long)usec_to_1000ths(useconds));
+ }
+ else if (hours < 100) { // up to 100 hours
+ sprintf(p, "%02ld:%02ld:%02ld ", hours, (minutes % 60),
+ (unsigned long)(seconds % 60));
+ }
+ else {
+ sprintf(p, "%4ld hrs ", hours);
+ }
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *myname = "sc_usage";
+ char *codefile = "/usr/share/misc/trace.codes";
+ char ch;
+ char *ptr;
+ int delay = Default_DELAY;
+ void screen_update();
+ void sort_scalls();
+ void sc_tab_init();
+ void getdivisor();
+ void reset_counters();
+
+ if ( geteuid() != 0 ) {
+ printf("'sc_usage' must be run as root...\n");
+ exit(1);
+ }
+
+ if (0 != reexec_to_match_kernel()) {
+ fprintf(stderr, "Could not re-execute: %d\n", errno);
+ exit(1);
+ }
+
+ /* get our name */
+ if (argc > 0) {
+ if ((myname = rindex(argv[0], '/')) == 0) {
+ myname = argv[0];
+ }
+ else {
+ myname++;
+ }
+ }
+
+ while ((ch = getopt(argc, argv, "c:els:d:E")) != EOF) {
+ switch(ch) {
+ case 's':
+ delay = argtoi('s', "decimal number", optarg, 10);
+ break;
+ case 'e':
+ how_to_sort = 1;
+ break;
+ case 'l':
+ no_screen_refresh = 1;
+ break;
+ case 'c':
+ codefile = optarg;
+ break;
+ case 'E':
+ execute_flag = 1;
+ break;
+ default:
+ /* exit_usage(myname);*/
+ exit_usage("default");
+ }
+ }
+ argc -= optind;
+ //argv += optind;
+
+ sc_tab_init(codefile);
+
+ if (argc)
+ {
+ if (!execute_flag)
+ {
+ /* parse a pid or a command */
+ if((pid = argtopid(argv[optind])) < 0 )
+ exit_usage(myname);
+ }
+ else
+ { /* execute this command */
+
+ uid_t uid, euid;
+ gid_t gid, egid;
+
+ ptr = strrchr(argv[optind], '/');
+ if (ptr)
+ ptr++;
+ else
+ ptr = argv[optind];
+
+ strncpy(proc_name, ptr, sizeof(proc_name)-1);
+ proc_name[sizeof(proc_name)-1] = '\0';
+
+ uid= getuid();
+ gid= getgid();
+ euid= geteuid();
+ egid= getegid();
+
+ seteuid(uid);
+ setegid(gid);
+
+ fprintf(stderr, "Starting program: %s\n", argv[optind]);
+ fflush(stdout);
+ fflush(stderr);
+ switch ((pid = vfork()))
+ {
+ case -1:
+ perror("vfork: ");
+ exit(1);
+ case 0: /* child */
+ setsid();
+ ptrace(0,(pid_t)0,(caddr_t)0,0); /* PT_TRACE_ME */
+ execve(argv[optind], &argv[optind], environ);
+ perror("execve:");
+ exit(1);
+ }
+
+ seteuid(euid);
+ setegid(egid);
+ }
+ }
+ else
+ {
+ exit_usage(myname);
+ }
+
+
+ if (no_screen_refresh == 0) {
+
+ /* initializes curses and screen (last) */
+ if (initscr() == (WINDOW *) 0)
+ {
+ printf("Unrecognized TERM type, try vt100\n");
+ exit(1);
+ }
+ cbreak();
+ timeout(100);
+ noecho();
+
+ clear();
+ refresh();
+ }
+
+
+ /* set up signal handlers */
+ signal(SIGINT, leave);
+ signal(SIGQUIT, leave);
+ signal(SIGHUP, leave);
+ signal(SIGTERM, leave);
+ signal(SIGWINCH, sigwinch);
+
+ if (no_screen_refresh == 0)
+ topn = LINES - Header_lines;
+ else {
+ topn = 1024;
+ COLS = 80;
+ }
+
+ set_remove();
+ set_numbufs(SAMPLE_SIZE);
+ set_init();
+ set_pidcheck(pid, 1);
+ set_enable(1);
+ if (execute_flag)
+ ptrace(7, pid, (caddr_t)1, 0); /* PT_CONTINUE */
+ getdivisor();
+
+ if (delay == 0)
+ delay = 1;
+ if ((sort_now = 10 / delay) < 2)
+ sort_now = 2;
+
+ get_bufinfo(&bufinfo);
+
+ my_buffer = malloc(bufinfo.nkdbufs * sizeof(kd_buf));
+ if(my_buffer == (char *) 0)
+ quit("can't allocate memory for tracing info\n");
+
+ (void)sort_scalls();
+ (void)screen_update();
+
+ /* main loop */
+
+ while (1) {
+ int i;
+ char c;
+ void sample_sc();
+
+ for (i = 0; i < (10 * delay) && newLINES == 0; i++) {
+
+ if (no_screen_refresh == 0) {
+ if ((c = getch()) != ERR && (char)c == 'q')
+ leave();
+ if (c != ERR)
+ reset_counters();
+ } else
+ usleep(100000);
+ sample_sc();
+ }
+ (void)sort_scalls();
+
+ if (newLINES) {
+ /*
+ No need to check for initscr error return.
+ We won't get here if it fails on the first call.
+ */
+ endwin();
+ clear();
+ refresh();
+
+ topn = LINES - Header_lines;
+ newLINES = 0;
+ }
+ (void)screen_update();
+ }
+}
+
+void
+print_row(struct sc_entry *se, int no_wtime) {
+ char tbuf[256];
+ int clen;
+
+ if (se->delta_count)
+ sprintf(tbuf, "%-23.23s %8d(%d)", se->name, se->total_count, se->delta_count);
+ else
+ sprintf(tbuf, "%-23.23s %8d", se->name, se->total_count);
+ clen = strlen(tbuf);
+
+ memset(&tbuf[clen], ' ', 45 - clen);
+
+ print_time(&tbuf[45], (unsigned long)(se->stime_usecs), se->stime_secs);
+ clen = strlen(tbuf);
+
+ if (no_wtime == 0 && (se->wtime_usecs || se->wtime_secs)) {
+ sprintf(&tbuf[clen], " ");
+ clen += strlen(&tbuf[clen]);
+
+ print_time(&tbuf[clen], (unsigned long)(se->wtime_usecs), se->wtime_secs);
+ clen += strlen(&tbuf[clen]);
+
+ if (se->waiting || se->delta_wtime_usecs || se->delta_wtime_secs) {
+
+ sprintf(&tbuf[clen], "(");
+ clen += strlen(&tbuf[clen]);
+
+ print_time(&tbuf[clen], (unsigned long)(se->delta_wtime_usecs),
+ se->delta_wtime_secs);
+ clen += strlen(&tbuf[clen]);
+
+ sprintf(&tbuf[clen], ")");
+ clen += strlen(&tbuf[clen]);
+
+ if (se->waiting) {
+ if (se->waiting == 1)
+ sprintf(&tbuf[clen], " W");
+ else
+ sprintf(&tbuf[clen], " %d", se->waiting);
+ clen += strlen(&tbuf[clen]);
+ }
+ }
+ }
+ sprintf(&tbuf[clen], "\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+}
+
+
+void screen_update()
+{
+ char *p1, *p2, *p3;
+ char tbuf[256];
+ int clen;
+ int plen;
+ int n, i, rows;
+ long curr_time;
+ long elapsed_secs;
+ int hours;
+ int minutes;
+ struct sc_entry *se;
+ int output_lf;
+ int max_rows;
+ struct th_info *ti;
+
+ if (no_screen_refresh == 0) {
+ /* clear for new display */
+ erase();
+ move(0, 0);
+ }
+ rows = 0;
+
+ sprintf(tbuf, "%-14.14s", proc_name);
+ clen = strlen(tbuf);
+
+ if (preempted == 1)
+ p1 = "preemption ";
+ else
+ p1 = "preemptions";
+ if (csw == 1)
+ p2 = "context switch ";
+ else
+ p2 = "context switches";
+ if (num_of_threads == 1)
+ p3 = "thread ";
+ else
+ p3 = "threads";
+
+ sprintf(&tbuf[clen], " %4d %s %4d %s %4d %s",
+ preempted, p1, csw, p2, num_of_threads, p3);
+ clen += strlen(&tbuf[clen]);
+
+ /*
+ * Display the current time.
+ * "ctime" always returns a string that looks like this:
+ *
+ * Sun Sep 16 01:03:52 1973
+ * 012345678901234567890123
+ * 1 2
+ *
+ * We want indices 11 thru 18 (length 8).
+ */
+ curr_time = time((long *)0);
+
+ if (start_time == 0)
+ start_time = curr_time;
+
+ elapsed_secs = curr_time - start_time;
+ minutes = elapsed_secs / 60;
+ hours = minutes / 60;
+
+ memset(&tbuf[clen], ' ', 78 - clen);
+
+ clen = 78 - 8;
+
+ sprintf(&tbuf[clen], "%-8.8s\n", &(ctime(&curr_time)[11]));
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+
+ if (total_faults == 1)
+ p1 = "fault ";
+ else
+ p1 = "faults";
+ if (scalls == 1)
+ p2 = "system call ";
+ else
+ p2 = "system calls";
+ sprintf(tbuf, " %4d %s %4d %s",
+ total_faults, p1, scalls, p2);
+
+ clen = strlen(tbuf);
+ sprintf(&tbuf[clen], " %3ld:%02ld:%02ld\n",
+ (long)hours, (long)(minutes % 60), (long)(elapsed_secs % 60));
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+
+
+
+ sprintf(tbuf, "\nTYPE NUMBER CPU_TIME WAIT_TIME\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+
+ sprintf(tbuf, "------------------------------------------------------------------------------\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ rows = 0;
+
+
+
+ sprintf(tbuf, "System Idle ");
+ clen = strlen(tbuf);
+
+ print_time(&tbuf[clen], (unsigned long)(itime_usecs), itime_secs);
+ clen += strlen(&tbuf[clen]);
+
+ if (delta_itime_usecs || delta_itime_secs) {
+
+ sprintf(&tbuf[clen], "(");
+ clen += strlen(&tbuf[clen]);
+
+ print_time(&tbuf[clen], (unsigned long)(delta_itime_usecs), delta_itime_secs);
+ clen += strlen(&tbuf[clen]);
+
+ sprintf(&tbuf[clen], ")");
+ clen += strlen(&tbuf[clen]);
+ }
+ sprintf(&tbuf[clen], "\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ rows++;
+
+
+
+ sprintf(tbuf, "System Busy ");
+ clen = strlen(tbuf);
+
+ print_time(&tbuf[clen], (unsigned long)(otime_usecs), otime_secs);
+ clen += strlen(&tbuf[clen]);
+
+ if (delta_otime_usecs || delta_otime_secs) {
+
+ sprintf(&tbuf[clen], "(");
+ clen += strlen(&tbuf[clen]);
+
+ print_time(&tbuf[clen], (unsigned long)(delta_otime_usecs), delta_otime_secs);
+ clen += strlen(&tbuf[clen]);
+
+ sprintf(&tbuf[clen], ")");
+ clen += strlen(&tbuf[clen]);
+ }
+ sprintf(&tbuf[clen], "\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ rows++;
+
+
+ sprintf(tbuf, "%-14.14s Usermode ", proc_name);
+ clen = strlen(tbuf);
+
+ print_time(&tbuf[clen], (unsigned long)(utime_usecs), utime_secs);
+ clen += strlen(&tbuf[clen]);
+
+ sprintf(&tbuf[clen], "\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ rows++;
+
+ if (num_of_threads)
+ max_rows = topn - (num_of_threads + 3);
+ else
+ max_rows = topn;
+
+ for (output_lf = 1, n = 1; rows < max_rows && n < MAX_FAULTS; n++) {
+ se = &faults[n];
+
+ if (se->total_count == 0)
+ continue;
+ if (output_lf == 1) {
+ sprintf(tbuf, "\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ rows++;
+
+ if (rows >= max_rows)
+ break;
+ output_lf = 0;
+ }
+ print_row(se, 0);
+ rows++;
+ }
+ sprintf(tbuf, "\n");
+
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ rows++;
+
+ for (i = 0; rows < max_rows; i++) {
+ if (how_to_sort)
+ n = sort_by_count[i];
+ else
+ n = sort_by_wtime[i];
+ if (n == -1)
+ break;
+ print_row(&sc_tab[n], 0);
+ rows++;
+ }
+
+
+ sprintf(tbuf, "\n");
+ if (no_screen_refresh == 0) {
+ while (rows++ < max_rows)
+ printw(tbuf);
+ } else
+ printf("%s", tbuf);
+
+ if (num_of_threads) {
+ sprintf(tbuf, "\nCURRENT_TYPE LAST_PATHNAME_WAITED_FOR CUR_WAIT_TIME THRD# PRI\n");
+
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+
+ sprintf(tbuf, "------------------------------------------------------------------------------\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ }
+ ti = &th_state[0];
+
+ for (i = 0; i < num_of_threads; i++, ti++) {
+ struct entry *te;
+ char *p;
+ uint64_t now;
+ int secs, time_secs, time_usecs;
+
+ now = mach_absolute_time();
+
+ while (ti->thread == 0 && ti < &th_state[MAX_THREADS])
+ ti++;
+ if (ti == &th_state[MAX_THREADS])
+ break;
+
+ if (ti->depth) {
+ te = &ti->th_entry[ti->depth - 1];
+
+ if (te->sc_state == WAITING) {
+ if (te->code)
+ sprintf(tbuf, "%-23.23s", sc_tab[te->code].name);
+ else
+ sprintf(tbuf, "%-23.23s", "vm_fault");
+ } else
+ sprintf(tbuf, "%-23.23s", state_name[te->sc_state]);
+ } else {
+ te = &ti->th_entry[0];
+ sprintf(tbuf, "%-23.23s", state_name[te->sc_state]);
+ }
+ clen = strlen(tbuf);
+
+ /* print the tail end of the pathname */
+ p = (char *)ti->pathname;
+
+ plen = strlen(p);
+ if (plen > 26)
+ plen -= 26;
+ else
+ plen = 0;
+ sprintf(&tbuf[clen], " %-26.26s ", &p[plen]);
+
+ clen += strlen(&tbuf[clen]);
+
+ time_usecs = (unsigned long)(((double)now - te->otime) / divisor);
+ secs = time_usecs / 1000000;
+ time_usecs -= secs * 1000000;
+ time_secs = secs;
+
+ print_time(&tbuf[clen], time_usecs, time_secs);
+ clen += strlen(&tbuf[clen]);
+ sprintf(&tbuf[clen], " %2d %3d\n", i, ti->curpri);
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ }
+ if (no_screen_refresh == 0) {
+ move(0, 0);
+ refresh();
+ } else
+ printf("\n=================\n");
+
+
+
+ for (i = 0; i < (MAX_SC + msgcode_cnt); i++) {
+ if ((n = sort_by_count[i]) == -1)
+ break;
+ sc_tab[n].delta_count = 0;
+ sc_tab[n].waiting = 0;
+ sc_tab[n].delta_wtime_usecs = 0;
+ sc_tab[n].delta_wtime_secs = 0;
+ }
+ for (i = 1; i < MAX_FAULTS; i++) {
+ faults[i].delta_count = 0;
+ faults[i].waiting = 0;
+ faults[i].delta_wtime_usecs = 0;
+ faults[i].delta_wtime_secs = 0;
+ }
+ preempted = 0;
+ csw = 0;
+ total_faults = 0;
+ scalls = 0;
+ delta_itime_secs = 0;
+ delta_itime_usecs = 0;
+ delta_otime_secs = 0;
+ delta_otime_usecs = 0;
+}
+
+void
+reset_counters() {
+ int i;
+
+ for (i = 0; i < (MAX_SC + msgcode_cnt) ; i++) {
+ sc_tab[i].delta_count = 0;
+ sc_tab[i].total_count = 0;
+ sc_tab[i].waiting = 0;
+ sc_tab[i].delta_wtime_usecs = 0;
+ sc_tab[i].delta_wtime_secs = 0;
+ sc_tab[i].wtime_usecs = 0;
+ sc_tab[i].wtime_secs = 0;
+ sc_tab[i].stime_usecs = 0;
+ sc_tab[i].stime_secs = 0;
+ }
+ for (i = 1; i < MAX_FAULTS; i++) {
+ faults[i].delta_count = 0;
+ faults[i].total_count = 0;
+ faults[i].waiting = 0;
+ faults[i].delta_wtime_usecs = 0;
+ faults[i].delta_wtime_secs = 0;
+ faults[i].wtime_usecs = 0;
+ faults[i].wtime_secs = 0;
+ faults[i].stime_usecs = 0;
+ faults[i].stime_secs = 0;
+ }
+ preempted = 0;
+ csw = 0;
+ total_faults = 0;
+ scalls = 0;
+ called = 0;
+
+ utime_secs = 0;
+ utime_usecs = 0;
+ itime_secs = 0;
+ itime_usecs = 0;
+ delta_itime_secs = 0;
+ delta_itime_usecs = 0;
+ otime_secs = 0;
+ otime_usecs = 0;
+ delta_otime_secs = 0;
+ delta_otime_usecs = 0;
+}
+
+void
+sc_tab_init(char *codefile) {
+ int code;
+ int n, cnt;
+ int msgcode_indx=0;
+ char name[56];
+ FILE *fp;
+
+ if ((fp = fopen(codefile,"r")) == (FILE *)0) {
+ printf("Failed to open code description file %s\n", codefile);
+ exit(1);
+ }
+
+ /* Count Mach message MSG_ codes */
+ for (msgcode_cnt=0;;) {
+ n = fscanf(fp, "%x%55s\n", &code, &name[0]);
+ if (n != 2)
+ break;
+ if (strncmp ("MSG_", &name[0], 4) == 0)
+ msgcode_cnt++;
+ if (strcmp("TRACE_LAST_WRAPPER", &name[0]) == 0)
+ break;
+ }
+
+ sc_tab = (struct sc_entry *)malloc((MAX_SC+msgcode_cnt) * sizeof (struct sc_entry));
+ if(!sc_tab)
+ quit("can't allocate memory for system call table\n");
+ bzero(sc_tab,(MAX_SC+msgcode_cnt) * sizeof (struct sc_entry));
+
+ msgcode_tab = (int *)malloc(msgcode_cnt * sizeof(int));
+ if (!msgcode_tab)
+ quit("can't allocate memory for msgcode table\n");
+ bzero(msgcode_tab,(msgcode_cnt * sizeof(int)));
+
+ sort_by_count = (int *)malloc((MAX_SC + msgcode_cnt + 1) * sizeof(int));
+ if (!sort_by_count)
+ quit("can't allocate memory for sort_by_count table\n");
+ bzero(sort_by_count,(MAX_SC + msgcode_cnt + 1) * sizeof(int));
+
+ sort_by_wtime = (int *)malloc((MAX_SC + msgcode_cnt + 1) * sizeof(int));
+ if (!sort_by_wtime)
+ quit("can't allocate memory for sort_by_wtime table\n");
+ bzero(sort_by_wtime, (MAX_SC + msgcode_cnt + 1) * sizeof(int));
+
+
+ rewind(fp);
+
+ for (;;) {
+ n = fscanf(fp, "%x%55s\n", &code, &name[0]);
+
+ if (n != 2)
+ break;
+
+ if (strcmp("MACH_vmfault", &name[0]) == 0) {
+ mach_vmfault = code;
+ continue;
+ }
+ if (strcmp("MACH_SCHED", &name[0]) == 0) {
+ mach_sched = code;
+ continue;
+ }
+ if (strcmp("MACH_STKHANDOFF", &name[0]) == 0) {
+ mach_stkhandoff = code;
+ continue;
+ }
+ if (strcmp("MACH_IDLE", &name[0]) == 0) {
+ mach_idle = code;
+ continue;
+ }
+ if (strcmp("VFS_LOOKUP", &name[0]) == 0) {
+ vfs_lookup = code;
+ continue;
+ }
+ if (strcmp("BSC_SysCall", &name[0]) == 0) {
+ bsc_base = code;
+ continue;
+ }
+ if (strcmp("MACH_SysCall", &name[0]) == 0) {
+ msc_base = code;
+ continue;
+ }
+ if (strcmp("BSC_exit", &name[0]) == 0) {
+ bsc_exit = code;
+ continue;
+ }
+ if (strncmp("MSG_", &name[0], 4) == 0) {
+ msgcode_tab[msgcode_indx] = ((code & 0x00ffffff) >>2);
+ n = MAX_SC + msgcode_indx;
+ strncpy(&sc_tab[n].name[0], &name[4], 31 );
+ msgcode_indx++;
+ continue;
+ }
+ if (strncmp("MSC_", &name[0], 4) == 0) {
+ n = 512 + ((code>>2) & 0x1ff);
+ strcpy(&sc_tab[n].name[0], &name[4]);
+ continue;
+ }
+ if (strncmp("BSC_", &name[0], 4) == 0) {
+ n = (code>>2) & 0x1ff;
+ strcpy(&sc_tab[n].name[0], &name[4]);
+ continue;
+ }
+ if (strcmp("TRACE_LAST_WRAPPER", &name[0]) == 0)
+ break;
+ }
+ strcpy(&faults[1].name[0], "zero_fill");
+ strcpy(&faults[2].name[0], "pagein");
+ strcpy(&faults[3].name[0], "copy_on_write");
+ strcpy(&faults[4].name[0], "cache_hit");
+}
+
+void
+find_proc_names()
+{
+ size_t bufSize = 0;
+ struct kinfo_proc *kp;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_ALL;
+ mib[3] = 0;
+
+ if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0)
+ quit("trace facility failure, KERN_PROC_ALL\n");
+
+ if((kp = (struct kinfo_proc *)malloc(bufSize)) == (struct kinfo_proc *)0)
+ quit("can't allocate memory for proc buffer\n");
+
+ if (sysctl(mib, 4, kp, &bufSize, NULL, 0) < 0)
+ quit("trace facility failure, KERN_PROC_ALL\n");
+
+ kp_nentries = bufSize/ sizeof(struct kinfo_proc);
+ kp_buffer = kp;
+}
+
+struct th_info *find_thread(int thread) {
+ struct th_info *ti;
+
+ for (ti = th_state; ti < &th_state[MAX_THREADS]; ti++) {
+ if (ti->thread == thread)
+ return(ti);
+ }
+ return ((struct th_info *)0);
+}
+
+
+int
+cmp_wtime(struct sc_entry *s1, struct sc_entry *s2) {
+
+ if (s1->wtime_secs < s2->wtime_secs)
+ return 0;
+ if (s1->wtime_secs > s2->wtime_secs)
+ return 1;
+ if (s1->wtime_usecs <= s2->wtime_usecs)
+ return 0;
+ return 1;
+}
+
+
+void
+sort_scalls() {
+ int i, n, k, cnt, secs;
+ struct th_info *ti;
+ struct sc_entry *se;
+ struct entry *te;
+ uint64_t now;
+
+ now = mach_absolute_time();
+
+ for (ti = th_state; ti < &th_state[MAX_THREADS]; ti++) {
+ if (ti->thread == 0)
+ continue;
+
+ if (ti->depth) {
+ te = &ti->th_entry[ti->depth-1];
+
+ if (te->sc_state == WAITING) {
+ if (te->code)
+ se = &sc_tab[te->code];
+ else
+ se = &faults[DBG_PAGEIN_FAULT];
+ se->waiting++;
+ se->wtime_usecs += ((double)now - te->stime) / divisor;
+ se->delta_wtime_usecs += ((double)now - te->stime) / divisor;
+ te->stime = (double)now;
+
+ secs = se->wtime_usecs / 1000000;
+ se->wtime_usecs -= secs * 1000000;
+ se->wtime_secs += secs;
+
+ secs = se->delta_wtime_usecs / 1000000;
+ se->delta_wtime_usecs -= secs * 1000000;
+ se->delta_wtime_secs += secs;
+ }
+ } else {
+ te = &ti->th_entry[0];
+
+ if (te->sc_state == PREEMPTED) {
+ if ((unsigned long)(((double)now - te->otime) / divisor) > 5000000) {
+ ti->thread = 0;
+ ti->vfslookup = 0;
+ ti->pathptr = (long *)NULL;
+ ti->pathname[0] = 0;
+ num_of_threads--;
+ }
+ }
+ }
+ }
+ if ((called % sort_now) == 0) {
+ sort_by_count[0] = -1;
+ sort_by_wtime[0] = -1;
+ for (cnt = 1, n = 1; n < (MAX_SC + msgcode_cnt); n++) {
+ if (sc_tab[n].total_count) {
+ for (i = 0; i < cnt; i++) {
+ if ((k = sort_by_count[i]) == -1 ||
+ sc_tab[n].total_count > sc_tab[k].total_count) {
+
+ for (k = cnt - 1; k >= i; k--)
+ sort_by_count[k+1] = sort_by_count[k];
+ sort_by_count[i] = n;
+ break;
+ }
+ }
+ if (how_to_sort == 0) {
+ for (i = 0; i < cnt; i++) {
+ if ((k = sort_by_wtime[i]) == -1 ||
+ cmp_wtime(&sc_tab[n], &sc_tab[k])) {
+
+ for (k = cnt - 1; k >= i; k--)
+ sort_by_wtime[k+1] = sort_by_wtime[k];
+ sort_by_wtime[i] = n;
+ break;
+ }
+ }
+ }
+ cnt++;
+ }
+ }
+ }
+ called++;
+}
+
+void
+set_enable(int val)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDENABLE; /* protocol */
+ mib[3] = val;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDENABLE\n");
+
+ if (val)
+ trace_enabled = 1;
+ else
+ trace_enabled = 0;
+}
+
+void
+set_numbufs(int nbufs)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETBUF;
+ mib[3] = nbufs;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDSETBUF\n");
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETUP;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDSETUP\n");
+
+}
+
+void
+set_pidcheck(int pid, int on_off)
+{
+ kd_regtype kr;
+
+ kr.type = KDBG_TYPENONE;
+ kr.value1 = pid;
+ kr.value2 = on_off;
+ needed = sizeof(kd_regtype);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDPIDTR;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) {
+ if (on_off == 1) {
+ printf("pid %d does not exist\n", pid);
+ set_remove();
+ exit(2);
+ }
+ }
+}
+
+void
+get_bufinfo(kbufinfo_t *val)
+{
+ needed = sizeof (*val);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDGETBUF;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 3, val, &needed, 0, 0) < 0)
+ quit("trace facility failure, KERN_KDGETBUF\n");
+
+}
+
+void
+set_remove()
+{
+ extern int errno;
+
+ errno = 0;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDREMOVE; /* protocol */
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+
+ if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
+ {
+ set_remove_flag = 0;
+
+ if (errno == EBUSY)
+ quit("The trace facility is currently in use...\n Note: fs_usage, sc_usage, and latency use this feature.\n\n");
+ else
+ quit("trace facility failure, KERN_KDREMOVE\n");
+ }
+}
+
+void
+set_init()
+{ kd_regtype kr;
+
+ kr.type = KDBG_RANGETYPE;
+ kr.value1 = 0;
+ kr.value2 = -1;
+ needed = sizeof(kd_regtype);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETREG;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDSETREG\n");
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETUP;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDSETUP\n");
+
+}
+
+void
+sample_sc()
+{
+ kd_buf *kd;
+ int i, count;
+ int secs;
+ int find_msgcode();
+
+ int reenable;
+
+#ifdef OLD_KDEBUG
+ set_enable(0);
+#endif
+ get_bufinfo(&bufinfo);
+
+ needed = bufinfo.nkdbufs * sizeof(kd_buf);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDREADTR;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+
+ if (sysctl(mib, 3, my_buffer, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDREADTR\n");
+
+ count = needed;
+
+ if (bufinfo.flags & KDBG_WRAPPED) {
+ for (i = 0; i < MAX_THREADS; i++) {
+ th_state[i].depth = 0;
+ th_state[i].thread = 0;
+ th_state[i].vfslookup = 0;
+ th_state[i].pathptr = (long *)NULL;
+ th_state[i].pathname[0] = 0;
+ }
+ num_of_threads = 0;
+ }
+
+#ifdef OLD_KDEBUG
+ set_remove();
+ set_init();
+ set_pidcheck(pid, 1);
+ set_enable(1); /* re-enable kernel logging */
+#endif
+ kd = (kd_buf *)my_buffer;
+
+ for (i = 0; i < count; i++) {
+ int debugid, baseid, thread;
+ int type, code;
+ uint64_t now;
+ struct th_info *ti, *switched_out, *switched_in;
+ struct sc_entry *se;
+ struct entry *te;
+
+ thread = kd[i].arg5;
+ debugid = kd[i].debugid;
+ type = kd[i].debugid & DBG_FUNC_MASK;
+
+ code = 0;
+ switched_out = (struct th_info *)0;
+ switched_in = (struct th_info *)0;
+
+ now = kd[i].timestamp & KDBG_TIMESTAMP_MASK;
+
+ baseid = debugid & 0xffff0000;
+
+ if (type == vfs_lookup) {
+ long *sargptr;
+
+ if ((ti = find_thread(thread)) == (struct th_info *)0)
+ continue;
+
+ if (ti->vfslookup == 1) {
+ ti->vfslookup++;
+ sargptr = ti->pathname;
+
+ *sargptr++ = kd[i].arg2;
+ *sargptr++ = kd[i].arg3;
+ *sargptr++ = kd[i].arg4;
+ /*
+ * NULL terminate the 'string'
+ */
+ *sargptr = 0;
+
+ ti->pathptr = sargptr;
+
+ } else if (ti->vfslookup > 1) {
+ ti->vfslookup++;
+ sargptr = ti->pathptr;
+
+ /*
+ We don't want to overrun our pathname buffer if the
+ kernel sends us more VFS_LOOKUP entries than we can
+ handle.
+ */
+
+ if (sargptr >= &ti->pathname[NUMPARMS])
+ continue;
+
+ /*
+ We need to detect consecutive vfslookup entries.
+ So, if we get here and find a START entry,
+ fake the pathptr so we can bypass all further
+ vfslookup entries.
+ */
+
+ if (debugid & DBG_FUNC_START)
+ {
+ ti->pathptr = &ti->pathname[NUMPARMS];
+ continue;
+ }
+
+ *sargptr++ = kd[i].arg1;
+ *sargptr++ = kd[i].arg2;
+ *sargptr++ = kd[i].arg3;
+ *sargptr++ = kd[i].arg4;
+ /*
+ * NULL terminate the 'string'
+ */
+ *sargptr = 0;
+
+ ti->pathptr = sargptr;
+ }
+ continue;
+
+ } else if (baseid == bsc_base)
+ code = (debugid >> 2) & 0x1ff;
+ else if (baseid == msc_base)
+ code = 512 + ((debugid >> 2) & 0x1ff);
+ else if (type == mach_idle) {
+ if (debugid & DBG_FUNC_START) {
+ switched_out = find_thread(kd[i].arg5);
+ switched_in = 0;
+ }
+ else
+ if (debugid & DBG_FUNC_END) {
+ switched_in = find_thread(kd[i].arg5);
+ switched_out = 0;
+ }
+
+ if (in_idle) {
+ itime_usecs += ((double)now - idle_start) / divisor;
+ delta_itime_usecs += ((double)now - idle_start) / divisor;
+ in_idle = 0;
+ } else if (in_other) {
+ otime_usecs += ((double)now - other_start) / divisor;
+ delta_otime_usecs += ((double)now - other_start) / divisor;
+ in_other = 0;
+ }
+ if ( !switched_in) {
+ /*
+ * not one of the target proc's threads
+ */
+ if (now_collect_cpu_time) {
+ in_idle = 1;
+ idle_start = (double)now;
+ }
+ }
+ else {
+ if (now_collect_cpu_time) {
+ in_idle = 0;
+ in_other = 1;
+ other_start = (double)now;
+ }
+ }
+ if ( !switched_in && !switched_out)
+ continue;
+
+ }
+ else if (type == mach_sched || type == mach_stkhandoff) {
+ switched_out = find_thread(kd[i].arg5);
+ switched_in = find_thread(kd[i].arg2);
+
+ if (in_idle) {
+ itime_usecs += ((double)now - idle_start) / divisor;
+ delta_itime_usecs += ((double)now - idle_start) / divisor;
+ in_idle = 0;
+ } else if (in_other) {
+ otime_usecs += ((double)now - other_start) / divisor;
+ delta_otime_usecs += ((double)now - other_start) / divisor;
+ in_other = 0;
+ }
+ if ( !switched_in) {
+ /*
+ * not one of the target proc's threads
+ */
+ if (now_collect_cpu_time) {
+ in_other = 1;
+ other_start = (double)now;
+ }
+ }
+ if ( !switched_in && !switched_out)
+ continue;
+
+ }
+ else if ((baseid & 0xff000000) == 0xff000000) {
+ code = find_msgcode (debugid);
+ if (!code)
+ continue;
+ } else if (baseid != mach_vmfault)
+ continue;
+
+ if (switched_out || switched_in) {
+ if (switched_out) {
+ ti = switched_out;
+ ti->curpri = kd[i].arg3;
+
+ if (ti->depth) {
+ te = &ti->th_entry[ti->depth-1];
+
+ if (te->sc_state == KERNEL_MODE)
+ te->ctime += (double)now - te->stime;
+ te->sc_state = WAITING;
+
+ ti->vfslookup = 1;
+
+ } else {
+ te = &ti->th_entry[0];
+
+ if (te->sc_state == USER_MODE)
+ utime_usecs += ((double)now - te->stime) / divisor;
+ te->sc_state = PREEMPTED;
+ preempted++;
+ }
+ te->stime = (double)now;
+ te->otime = (double)now;
+ now_collect_cpu_time = 1;
+ csw++;
+ }
+ if (switched_in) {
+ ti = switched_in;
+ ti->curpri = kd[i].arg4;
+
+ if (ti->depth) {
+ te = &ti->th_entry[ti->depth-1];
+
+ if (te->sc_state == WAITING)
+ te->wtime += (double)now - te->stime;
+ te->sc_state = KERNEL_MODE;
+ } else {
+ te = &ti->th_entry[0];
+
+ te->sc_state = USER_MODE;
+ }
+ te->stime = (double)now;
+ te->otime = (double)now;
+ }
+ continue;
+ }
+ if ((ti = find_thread(thread)) == (struct th_info *)0) {
+ for (ti = &th_state[0]; ti < &th_state[MAX_THREADS]; ti++) {
+ if (ti->thread == 0) {
+ ti->thread = thread;
+ num_of_threads++;
+ break;
+ }
+ }
+ if (ti == &th_state[MAX_THREADS])
+ continue;
+ }
+ if (debugid & DBG_FUNC_START) {
+ ti->vfslookup = 0;
+
+ if (ti->depth) {
+ te = &ti->th_entry[ti->depth-1];
+
+ if (te->sc_state == KERNEL_MODE)
+ te->ctime += (double)now - te->stime;
+ } else {
+ te = &ti->th_entry[0];
+
+ if (te->sc_state == USER_MODE)
+ utime_usecs += ((double)now - te->stime) / divisor;
+ }
+ te->stime = (double)now;
+ te->otime = (double)now;
+
+ if (ti->depth < MAX_NESTED) {
+ te = &ti->th_entry[ti->depth];
+
+ te->sc_state = KERNEL_MODE;
+ te->type = type;
+ te->code = code;
+ te->stime = (double)now;
+ te->otime = (double)now;
+ te->ctime = (double)0;
+ te->wtime = (double)0;
+ ti->depth++;
+ }
+
+ } else if (debugid & DBG_FUNC_END) {
+ if (code) {
+ se = &sc_tab[code];
+ scalls++;
+ } else {
+ se = &faults[kd[i].arg4];
+ total_faults++;
+ }
+ if (se->total_count == 0)
+ called = 0;
+ se->delta_count++;
+ se->total_count++;
+
+ while (ti->depth) {
+ te = &ti->th_entry[ti->depth-1];
+
+ if (te->type == type) {
+ se->stime_usecs += te->ctime / divisor;
+ se->stime_usecs += ((double)now - te->stime) / divisor;
+
+ se->wtime_usecs += te->wtime / divisor;
+ se->delta_wtime_usecs += te->wtime / divisor;
+
+ secs = se->stime_usecs / 1000000;
+ se->stime_usecs -= secs * 1000000;
+ se->stime_secs += secs;
+
+ secs = se->wtime_usecs / 1000000;
+ se->wtime_usecs -= secs * 1000000;
+ se->wtime_secs += secs;
+
+ secs = se->delta_wtime_usecs / 1000000;
+ se->delta_wtime_usecs -= secs * 1000000;
+ se->delta_wtime_secs += secs;
+
+ ti->depth--;
+
+ if (ti->depth == 0) {
+ /*
+ * headed back to user mode
+ * start the time accumulation
+ */
+ te = &ti->th_entry[0];
+ te->sc_state = USER_MODE;
+ } else
+ te = &ti->th_entry[ti->depth-1];
+
+ te->stime = (double)now;
+ te->otime = (double)now;
+
+ break;
+ }
+ ti->depth--;
+
+ if (ti->depth == 0) {
+ /*
+ * headed back to user mode
+ * start the time accumulation
+ */
+ te = &ti->th_entry[0];
+ te->sc_state = USER_MODE;
+ te->stime = (double)now;
+ te->otime = (double)now;
+ }
+ }
+ }
+ }
+ secs = utime_usecs / 1000000;
+ utime_usecs -= secs * 1000000;
+ utime_secs += secs;
+
+ secs = itime_usecs / 1000000;
+ itime_usecs -= secs * 1000000;
+ itime_secs += secs;
+
+ secs = delta_itime_usecs / 1000000;
+ delta_itime_usecs -= secs * 1000000;
+ delta_itime_secs += secs;
+
+ secs = otime_usecs / 1000000;
+ otime_usecs -= secs * 1000000;
+ otime_secs += secs;
+
+ secs = delta_otime_usecs / 1000000;
+ delta_otime_usecs -= secs * 1000000;
+ delta_otime_secs += secs;
+}
+
+void
+quit(char *s)
+{
+ if (trace_enabled)
+ set_enable(0);
+
+ /*
+ This flag is turned off when calling
+ quit() due to a set_remove() failure.
+ */
+ if (set_remove_flag)
+ set_remove();
+
+ if (no_screen_refresh == 0) {
+ /* clear for new display */
+ erase();
+ move(0, 0);
+ refresh();
+ endwin();
+ }
+
+ printf("sc_usage: ");
+ if (s)
+ printf("%s", s);
+
+ exit(1);
+}
+
+void getdivisor()
+{
+ mach_timebase_info_data_t info;
+
+ (void) mach_timebase_info (&info);
+
+ divisor = ( (double)info.denom / (double)info.numer) * 1000;
+
+}
+
+
+int
+argtopid(str)
+ char *str;
+{
+ char *cp;
+ int ret;
+ int i;
+
+ if (!kp_buffer)
+ find_proc_names();
+
+ ret = (int)strtol(str, &cp, 10);
+ if (cp == str || *cp) {
+ /* Assume this is a command string and find first matching pid */
+ for (i=0; i < kp_nentries; i++) {
+ if(kp_buffer[i].kp_proc.p_stat == 0)
+ continue;
+ else {
+ if(!strcmp(str, kp_buffer[i].kp_proc.p_comm))
+ {
+ strncpy(proc_name, kp_buffer[i].kp_proc.p_comm, sizeof(proc_name)-1);
+ proc_name[sizeof(proc_name)-1] = '\0';
+ return(kp_buffer[i].kp_proc.p_pid);
+ }
+ }
+ }
+ }
+ else
+ {
+ for (i=0; i < kp_nentries; i++)
+ {
+ if(kp_buffer[i].kp_proc.p_stat == 0)
+ continue;
+ else if (kp_buffer[i].kp_proc.p_pid == ret) {
+ strncpy(proc_name, kp_buffer[i].kp_proc.p_comm, sizeof(proc_name)-1);
+ proc_name[sizeof(proc_name)-1] = '\0';
+ return(kp_buffer[i].kp_proc.p_pid);
+ }
+ }
+ }
+ return(-1);
+}
+
+
+/* Returns index into sc_tab for a mach msg entry */
+int
+find_msgcode(int debugid)
+{
+
+ int indx;
+
+ for (indx=0; indx< msgcode_cnt; indx++)
+ {
+ if (msgcode_tab[indx] == ((debugid & 0x00ffffff) >>2))
+ return (MAX_SC+indx);
+ }
+ return (0);
+}
+
+int
+argtoi(flag, req, str, base)
+ int flag;
+ char *req, *str;
+ int base;
+{
+ char *cp;
+ int ret;
+
+ ret = (int)strtol(str, &cp, base);
+ if (cp == str || *cp)
+ errx(EINVAL, "-%c flag requires a %s", flag, req);
+ return (ret);
+}
+
--- /dev/null
+#include <TargetConditionals.h>
+#if TARGET_OS_EMBEDDED
+subsystem dummy 0;
+#else
+#include <IOKit/kext/kextmanager_mig.defs>
+#endif
--- /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@
+ */
+#include <paths.h>
+
+#define _PATH_FASTBOOT "/fastboot"
+#define _PATH_HALT "/sbin/halt"
+#define _PATH_REBOOT "/sbin/reboot"
+#define _PATH_WALL "/usr/bin/wall"
--- /dev/null
+.\" Copyright (c) 1988, 1991, 1993
+.\" The Regents of the University of California. 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)shutdown.8 8.2 (Berkeley) 4/27/95
+.\" $FreeBSD: src/sbin/shutdown/shutdown.8,v 1.21 2002/12/23 16:04:50 ru Exp $
+.\"
+.Dd December 11, 1998
+.Dt SHUTDOWN 8
+.Os
+.Sh NAME
+.Nm shutdown
+.Nd "close down the system at a given time"
+.Sh SYNOPSIS
+.Nm shutdown
+.Op Fl
+.Oo
+.Fl h
+.Op Fl u
+|
+.Fl r | Fl s | Fl k
+.Oc
+.Oo
+.Fl o
+.Op Fl n
+.Oc
+.Ar time
+.Op Ar warning-message ...
+.Sh DESCRIPTION
+The
+.Nm shutdown
+utility provides an automated shutdown procedure for super-users
+to nicely notify users when the system is shutting down,
+saving them from system administrators, hackers, and gurus, who
+would otherwise not bother with such niceties.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl h
+The system is halted at the specified
+.Ar time .
+.It Fl k
+Kick everybody off.
+The
+.Fl k
+option
+does not actually halt the system, but leaves the
+system multi-user with logins disabled (for all but super-user).
+.It Fl n
+If the
+.Fl o
+is specified, prevent the file system cache from being flushed by passing
+.Fl n
+option to
+.Xr halt 8
+or
+.Xr reboot 8 .
+This option should probably not be used.
+.It Fl o
+If
+.Fl h
+or
+.Fl r
+is specified,
+.Nm shutdown
+will execute
+.Xr halt 8
+or
+.Xr reboot 8
+instead of sending a signal to
+.Xr launchd 8 .
+.It Fl r
+The system is rebooted at the specified
+.Ar time .
+.It Fl s
+The system is put to sleep at the specified
+.Ar time .
+.It Fl u
+The system is halted up until the point of removing system power, but waits
+before removing power for 5 minutes so that an external UPS
+(uninterruptible power supply) can forcibly remove power.
+This simulates a dirty shutdown to permit a later automatic power on. OS X uses
+this mode automatically with supported UPSs in emergency shutdowns.
+.It Ar time
+.Ar Time
+is the time at which
+.Nm shutdown
+will bring the system down and
+may be the word
+.Ar now
+(indicating an immediate shutdown) or
+specify a future time in one of two formats:
+.Ar +number ,
+or
+.Ar yymmddhhmm ,
+where the year, month, and day may be defaulted
+to the current system values. The first form brings the system down in
+.Ar number
+minutes and the second at the absolute time specified.
+.It Ar warning-message
+Any other arguments comprise the warning message that is broadcast
+to users currently logged into the system.
+.It Fl
+If
+.Sq Fl
+is supplied as an option, the warning message is read from the standard
+input.
+.El
+.Pp
+At intervals, becoming more frequent as apocalypse approaches
+and starting at ten hours before shutdown, warning messages are displayed
+on the terminals of all users logged in.
+.Pp
+At shutdown time a message is written to the system log, containing the
+time of shutdown, the person who initiated the shutdown and the reason.
+Corresponding signal is then sent to
+.Xr launchd 8
+to respectively halt, reboot or bring the system down to single-user state
+(depending on the above options).
+.Pp
+A scheduled shutdown can be canceled by killing the
+.Nm shutdown
+process (a
+.Dv SIGTERM
+should suffice).
+.Sh SIGTERM TO SIGKILL INTERVAL
+Upon shutdown, all running processes are sent a SIGTERM followed by a SIGKILL.
+The
+.Dv SIGKILL
+will follow the
+.Dv SIGTERM
+by an intentionally indeterminate period of time.
+Programs are expected to take only enough time to flush all dirty data and exit.
+Developers are encouraged to file a bug with the OS vendor, should they encounter an issue with this functionality.
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr login 1 ,
+.Xr wall 1 ,
+.Xr halt 8 ,
+.Xr launchd 8 ,
+.Xr reboot 8
+.Sh BACKWARD COMPATIBILITY
+The hours and minutes in the second time format may be separated by
+a colon (``:'') for backward compatibility.
+.Sh HISTORY
+The
+.Nm shutdown
+utility appeared in
+.Bx 4.0 .
--- /dev/null
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Portions copyright (c) 2007 Apple Inc. 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. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)shutdown.c 8.4 (Berkeley) 4/28/95";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/sbin/shutdown/shutdown.c,v 1.28 2005/01/25 08:40:51 delphij Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/syslog.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <errno.h>
+#include <util.h>
+#include <bsm/libbsm.h>
+#include <bsm/audit_uevents.h>
+#include <vproc.h>
+#include <vproc_priv.h>
+
+#include "kextmanager.h"
+#include <IOKit/kext/kextmanager_types.h>
+#include <IOKit/pwr_mgt/IOPMLib.h>
+#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>
+
+#include "pathnames.h"
+#endif /* __APPLE__ */
+
+#ifdef DEBUG
+#undef _PATH_NOLOGIN
+#define _PATH_NOLOGIN "./nologin"
+#endif
+
+#define H *60*60
+#define M *60
+#define S *1
+#define NOLOG_TIME 5*60
+struct interval {
+ int timeleft, timetowait;
+} tlist[] = {
+ { 10 H, 5 H },
+ { 5 H, 3 H },
+ { 2 H, 1 H },
+ { 1 H, 30 M },
+ { 30 M, 10 M },
+ { 20 M, 10 M },
+ { 10 M, 5 M },
+ { 5 M, 3 M },
+ { 2 M, 1 M },
+ { 1 M, 30 S },
+ { 30 S, 30 S },
+ { 0 , 0 }
+};
+#undef H
+#undef M
+#undef S
+
+static time_t offset, shuttime;
+#ifdef __APPLE__
+static int dohalt, doreboot, doups, killflg, mbuflen, oflag;
+#else
+static int dohalt, dopower, doreboot, killflg, mbuflen, oflag;
+#endif
+static char mbuf[BUFSIZ];
+static const char *nosync, *whom;
+#ifdef __APPLE__
+static int dosleep;
+#endif
+
+void badtime(void);
+#ifdef __APPLE__
+void log_and_exec_reboot_or_halt(void);
+#else
+void die_you_gravy_sucking_pig_dog(void);
+#endif
+void finish(int);
+void getoffset(char *);
+void loop(void);
+void nolog(void);
+void timeout(int);
+void timewarn(int);
+void usage(const char *);
+#ifdef __APPLE__
+int audit_shutdown(int);
+int reserve_reboot(void);
+#endif
+
+extern const char **environ;
+
+int
+main(int argc, char **argv)
+{
+ char *p, *endp;
+ struct passwd *pw;
+ int arglen, ch, len, readstdin;
+
+#ifndef DEBUG
+ if (geteuid())
+ errx(1, "NOT super-user");
+#endif
+ nosync = NULL;
+ readstdin = 0;
+#ifndef __APPLE__
+ while ((ch = getopt(argc, argv, "-hknopr")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "-hknorsu")) != -1)
+#endif
+ switch (ch) {
+ case '-':
+ readstdin = 1;
+ break;
+ case 'h':
+ dohalt = 1;
+ break;
+ case 'k':
+ killflg = 1;
+ break;
+ case 'n':
+ nosync = "-n";
+ break;
+ case 'o':
+ oflag = 1;
+ break;
+#ifndef __APPLE__
+ case 'p':
+ dopower = 1;
+ break;
+#endif
+ case 'u':
+ doups = 1;
+ break;
+ case 'r':
+ doreboot = 1;
+ break;
+#ifdef __APPLE__
+ case 's':
+ dosleep = 1;
+ break;
+#endif
+ case '?':
+ default:
+ usage((char *)NULL);
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1)
+ usage((char *)NULL);
+
+#ifndef __APPLE__
+ if (killflg + doreboot + dohalt + dopower > 1)
+ usage("incompatible switches -h, -k, -p and -r");
+
+ if (oflag && !(dohalt || dopower || doreboot))
+ usage("-o requires -h, -p or -r");
+
+ if (nosync != NULL && !oflag)
+ usage("-n requires -o");
+#else /* !__APPLE__ */
+ if (killflg + doreboot + dohalt + dosleep > 1)
+ usage("incompatible switches -h, -k, -r, and -s");
+
+ if (!(dohalt || doreboot || dosleep || killflg))
+ usage("-h, -r, -s, or -k is required");
+
+ if (doups && !dohalt)
+ usage("-u requires -h");
+#endif /* !__APPLE__ */
+
+ getoffset(*argv++);
+
+ if (*argv) {
+ for (p = mbuf, len = sizeof(mbuf); *argv; ++argv) {
+ arglen = strlen(*argv);
+ if ((len -= arglen) <= 2)
+ break;
+ if (p != mbuf)
+ *p++ = ' ';
+ memmove(p, *argv, arglen);
+ p += arglen;
+ }
+ *p = '\n';
+ *++p = '\0';
+ }
+
+ if (readstdin) {
+ p = mbuf;
+ endp = mbuf + sizeof(mbuf) - 2;
+ for (;;) {
+ if (!fgets(p, endp - p + 1, stdin))
+ break;
+ for (; *p && p < endp; ++p);
+ if (p == endp) {
+ *p = '\n';
+ *++p = '\0';
+ break;
+ }
+ }
+ }
+ mbuflen = strlen(mbuf);
+
+ if (offset)
+ (void)printf("Shutdown at %.24s.\n", ctime(&shuttime));
+ else
+ (void)printf("Shutdown NOW!\n");
+
+ if (!(whom = getlogin()))
+ whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
+
+#ifdef DEBUG
+ audit_shutdown(0);
+ (void)putc('\n', stdout);
+#else
+ (void)setpriority(PRIO_PROCESS, 0, PRIO_MIN);
+#ifdef __APPLE__
+ if (offset) {
+#else
+ {
+#endif
+ int forkpid;
+
+ forkpid = fork();
+ if (forkpid == -1) {
+ audit_shutdown(1);
+ err(1, "fork");
+ }
+ if (forkpid)
+ errx(0, "[pid %d]", forkpid);
+#ifdef __APPLE__
+ /* 5863185: reboot2() needs to talk to launchd. */
+ if (_vprocmgr_detach_from_console(0) != NULL)
+ warnx("can't detach from console");
+#endif /* __APPLE__ */
+ }
+ audit_shutdown(0);
+ setsid();
+#endif
+ openlog("shutdown", LOG_CONS, LOG_AUTH);
+ loop();
+ return(0);
+}
+
+void
+loop()
+{
+ struct interval *tp;
+ u_int sltime;
+ int logged;
+
+ if (offset <= NOLOG_TIME) {
+ logged = 1;
+ nolog();
+ }
+ else
+ logged = 0;
+ tp = tlist;
+ if (tp->timeleft < offset)
+ (void)sleep((u_int)(offset - tp->timeleft));
+ else {
+ while (tp->timeleft && offset < tp->timeleft)
+ ++tp;
+ /*
+ * Warn now, if going to sleep more than a fifth of
+ * the next wait time.
+ */
+ if ((sltime = offset - tp->timeleft)) {
+ if (sltime > (u_int)(tp->timetowait / 5))
+ timewarn(offset);
+ (void)sleep(sltime);
+ }
+ }
+ for (;; ++tp) {
+ timewarn(tp->timeleft);
+ if (!logged && tp->timeleft <= NOLOG_TIME) {
+ logged = 1;
+ nolog();
+ }
+ (void)sleep((u_int)tp->timetowait);
+ if (!tp->timeleft)
+ break;
+ }
+#ifdef __APPLE__
+ log_and_exec_reboot_or_halt();
+#else
+ die_you_gravy_sucking_pig_dog();
+#endif
+}
+
+static jmp_buf alarmbuf;
+
+static const char *restricted_environ[] = {
+ "PATH=" _PATH_STDPATH,
+ NULL
+};
+
+void
+timewarn(int timeleft)
+{
+ static int first;
+ static char hostname[MAXHOSTNAMELEN + 1];
+ FILE *pf;
+ char wcmd[MAXPATHLEN + 4];
+
+ /* wall is sometimes missing, e.g. on install media */
+ if (access(_PATH_WALL, X_OK) == -1) return;
+
+ if (!first++)
+ (void)gethostname(hostname, sizeof(hostname));
+
+ /* undoc -n option to wall suppresses normal wall banner */
+ (void)snprintf(wcmd, sizeof(wcmd), "%s -n", _PATH_WALL);
+ environ = restricted_environ;
+ if (!(pf = popen(wcmd, "w"))) {
+ syslog(LOG_ERR, "shutdown: can't find %s: %m", _PATH_WALL);
+ return;
+ }
+
+ (void)fprintf(pf,
+ "\007*** %sSystem shutdown message from %s@%s ***\007\n",
+ timeleft ? "": "FINAL ", whom, hostname);
+
+ if (timeleft > 10*60)
+ (void)fprintf(pf, "System going down at %5.5s\n\n",
+ ctime(&shuttime) + 11);
+ else if (timeleft > 59)
+ (void)fprintf(pf, "System going down in %d minute%s\n\n",
+ timeleft / 60, (timeleft > 60) ? "s" : "");
+ else if (timeleft)
+ (void)fprintf(pf, "System going down in 30 seconds\n\n");
+ else
+ (void)fprintf(pf, "System going down IMMEDIATELY\n\n");
+
+ if (mbuflen)
+ (void)fwrite(mbuf, sizeof(*mbuf), mbuflen, pf);
+
+ /*
+ * play some games, just in case wall doesn't come back
+ * probably unnecessary, given that wall is careful.
+ */
+ if (!setjmp(alarmbuf)) {
+ (void)signal(SIGALRM, timeout);
+ (void)alarm((u_int)30);
+ (void)pclose(pf);
+ (void)alarm((u_int)0);
+ (void)signal(SIGALRM, SIG_DFL);
+ }
+}
+
+void
+timeout(int signo __unused)
+{
+ longjmp(alarmbuf, 1);
+}
+
+void
+#ifdef __APPLE__
+log_and_exec_reboot_or_halt()
+#else
+die_you_gravy_sucking_pig_dog()
+#endif
+{
+#ifndef __APPLE__
+ char *empty_environ[] = { NULL };
+#else
+ if ((errno = reserve_reboot())) {
+ warn("couldn't lock for reboot");
+ finish(0);
+ }
+#endif
+
+ syslog(LOG_NOTICE, "%s%s by %s: %s",
+#ifndef __APPLE__
+ doreboot ? "reboot" : dohalt ? "halt" : dopower ? "power-down" :
+#else
+ doreboot ? "reboot" : dohalt ? "halt" : dosleep ? "sleep" :
+#endif
+ "shutdown", doups?" with UPS delay":"", whom, mbuf);
+#ifndef __APPLE__
+ (void)sleep(2);
+#endif
+
+ (void)printf("\r\nSystem shutdown time has arrived\007\007\r\n");
+ if (killflg) {
+ (void)printf("\rbut you'll have to do it yourself\r\n");
+ exit(0);
+ }
+#ifdef DEBUG
+ if (doreboot)
+ (void)printf("reboot");
+ else if (dohalt)
+ (void)printf("halt");
+#ifndef __APPLE__
+ else if (dopower)
+ (void)printf("power-down");
+ if (nosync != NULL)
+ (void)printf(" no sync");
+#else
+ else if (dosleep)
+ (void)printf("sleep");
+#endif
+ (void)printf("\nkill -HUP 1\n");
+#else
+#ifdef __APPLE__
+ if (dosleep) {
+ mach_port_t mp;
+ io_connect_t fb;
+ kern_return_t kr = IOMasterPort(bootstrap_port, &mp);
+ if (kr == kIOReturnSuccess) {
+ fb = IOPMFindPowerManagement(mp);
+ if (fb != IO_OBJECT_NULL) {
+ IOReturn err = IOPMSleepSystem(fb);
+ if (err != kIOReturnSuccess) {
+ fprintf(stderr, "shutdown: sleep failed (0x%08x)\n", err);
+ kr = -1;
+ }
+ }
+ }
+ } else {
+ int howto = 0;
+
+#if defined(__APPLE__)
+ {
+ struct utmpx utx;
+ bzero(&utx, sizeof(utx));
+ utx.ut_type = SHUTDOWN_TIME;
+ gettimeofday(&utx.ut_tv, NULL);
+ pututxline(&utx);
+
+ int newvalue = 1;
+ sysctlbyname("kern.willshutdown", NULL, NULL, &newvalue, sizeof(newvalue));
+ }
+#else
+ logwtmp("~", "shutdown", "");
+#endif
+
+ if (dohalt) howto |= RB_HALT;
+ if (doups) howto |= RB_UPSDELAY;
+ if (nosync) howto |= RB_NOSYNC;
+
+ // launchd(8) handles reboot. This call returns NULL on success.
+ if (reboot2(howto)) {
+ syslog(LOG_ERR, "shutdown: launchd reboot failed.");
+ }
+ }
+#else /* __APPLE__ */
+ if (!oflag) {
+ (void)kill(1, doreboot ? SIGINT : /* reboot */
+ dohalt ? SIGUSR1 : /* halt */
+ dopower ? SIGUSR2 : /* power-down */
+ SIGTERM); /* single-user */
+ } else {
+ if (doreboot) {
+ execle(_PATH_REBOOT, "reboot", "-l", nosync,
+ (char *)NULL, empty_environ);
+ syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
+ _PATH_REBOOT);
+ warn(_PATH_REBOOT);
+ }
+ else if (dohalt) {
+ execle(_PATH_HALT, "halt", "-l", nosync,
+ (char *)NULL, empty_environ);
+ syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
+ _PATH_HALT);
+ warn(_PATH_HALT);
+ }
+ else if (dopower) {
+ execle(_PATH_HALT, "halt", "-l", "-p", nosync,
+ (char *)NULL, empty_environ);
+ syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
+ _PATH_HALT);
+ warn(_PATH_HALT);
+ }
+ (void)kill(1, SIGTERM); /* to single-user */
+ }
+#endif /* __APPLE__ */
+#endif
+ finish(0);
+}
+
+#define ATOI2(p) (p[0] - '0') * 10 + (p[1] - '0'); p += 2;
+
+void
+getoffset(char *timearg)
+{
+ struct tm *lt;
+ char *p;
+ time_t now;
+ int this_year;
+
+ (void)time(&now);
+
+ if (!strcasecmp(timearg, "now")) { /* now */
+ offset = 0;
+ shuttime = now;
+ return;
+ }
+
+ if (*timearg == '+') { /* +minutes */
+ if (!isdigit(*++timearg))
+ badtime();
+ if ((offset = atoi(timearg) * 60) < 0)
+ badtime();
+ shuttime = now + offset;
+ return;
+ }
+
+ /* handle hh:mm by getting rid of the colon */
+ for (p = timearg; *p; ++p)
+ if (!isascii(*p) || !isdigit(*p)) {
+ if (*p == ':' && strlen(p) == 3) {
+ p[0] = p[1];
+ p[1] = p[2];
+ p[2] = '\0';
+ }
+ else
+ badtime();
+ }
+
+ unsetenv("TZ"); /* OUR timezone */
+ lt = localtime(&now); /* current time val */
+
+ switch(strlen(timearg)) {
+ case 10:
+ this_year = lt->tm_year;
+ lt->tm_year = ATOI2(timearg);
+ /*
+ * check if the specified year is in the next century.
+ * allow for one year of user error as many people will
+ * enter n - 1 at the start of year n.
+ */
+ if (lt->tm_year < (this_year % 100) - 1)
+ lt->tm_year += 100;
+ /* adjust for the year 2000 and beyond */
+ lt->tm_year += (this_year - (this_year % 100));
+ /* FALLTHROUGH */
+ case 8:
+ lt->tm_mon = ATOI2(timearg);
+ if (--lt->tm_mon < 0 || lt->tm_mon > 11)
+ badtime();
+ /* FALLTHROUGH */
+ case 6:
+ lt->tm_mday = ATOI2(timearg);
+ if (lt->tm_mday < 1 || lt->tm_mday > 31)
+ badtime();
+ /* FALLTHROUGH */
+ case 4:
+ lt->tm_hour = ATOI2(timearg);
+ if (lt->tm_hour < 0 || lt->tm_hour > 23)
+ badtime();
+ lt->tm_min = ATOI2(timearg);
+ if (lt->tm_min < 0 || lt->tm_min > 59)
+ badtime();
+ lt->tm_sec = 0;
+ if ((shuttime = mktime(lt)) == -1)
+ badtime();
+ if ((offset = shuttime - now) < 0)
+ errx(1, "that time is already past.");
+ break;
+ default:
+ badtime();
+ }
+}
+
+#define NOMSG "\n\nNO LOGINS: System going down at "
+void
+nolog()
+{
+ int logfd;
+ char *ct;
+
+ (void)unlink(_PATH_NOLOGIN); /* in case linked to another file */
+ (void)signal(SIGINT, finish);
+ (void)signal(SIGHUP, finish);
+ (void)signal(SIGQUIT, finish);
+ (void)signal(SIGTERM, finish);
+ if ((logfd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT|O_TRUNC,
+ 0664)) >= 0) {
+ (void)write(logfd, NOMSG, sizeof(NOMSG) - 1);
+ ct = ctime(&shuttime);
+ (void)write(logfd, ct + 11, 5);
+ (void)write(logfd, "\n\n", 2);
+ (void)write(logfd, mbuf, strlen(mbuf));
+ (void)close(logfd);
+ }
+}
+
+void
+finish(int signo __unused)
+{
+ if (!killflg)
+ (void)unlink(_PATH_NOLOGIN);
+ exit(0);
+}
+
+void
+badtime()
+{
+ errx(1, "bad time format");
+}
+
+void
+usage(const char *cp)
+{
+ if (cp != NULL)
+ warnx("%s", cp);
+ (void)fprintf(stderr,
+#ifdef __APPLE__
+ "usage: shutdown [-] [-h [-u] [-n] | -r [-n] | -s | -k]"
+#else
+ "usage: shutdown [-] [-h | -p | -r | -k] [-o [-n]]"
+#endif
+ " time [warning-message ...]\n");
+ exit(1);
+}
+
+#ifdef __APPLE__
+/*
+ * The following tokens are included in the audit record for shutdown
+ * header
+ * subject
+ * return
+ */
+int audit_shutdown(int exitstatus)
+{
+ int aufd;
+ token_t *tok;
+ long au_cond;
+
+ /* If we are not auditing, don't cut an audit record; just return */
+ if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
+ fprintf(stderr, "shutdown: Could not determine audit condition\n");
+ return 0;
+ }
+ if (au_cond == AUC_NOAUDIT)
+ return 0;
+
+ if((aufd = au_open()) == -1) {
+ fprintf(stderr, "shutdown: Audit Error: au_open() failed\n");
+ exit(1);
+ }
+
+ /* The subject that performed the operation */
+ if((tok = au_to_me()) == NULL) {
+ fprintf(stderr, "shutdown: Audit Error: au_to_me() failed\n");
+ exit(1);
+ }
+ au_write(aufd, tok);
+
+ /* success and failure status */
+ if((tok = au_to_return32(exitstatus, errno)) == NULL) {
+ fprintf(stderr, "shutdown: Audit Error: au_to_return32() failed\n");
+ exit(1);
+ }
+ au_write(aufd, tok);
+
+ if(au_close(aufd, 1, AUE_shutdown) == -1) {
+ fprintf(stderr, "shutdown: Audit Error: au_close() failed\n");
+ exit(1);
+ }
+ return 1;
+}
+
+
+// XX copied from reboot.tproj/reboot.c; it would be nice to share the code
+
+#define WAITFORLOCK 1
+/*
+ * contact kextd to lock for reboot
+ */
+int
+reserve_reboot()
+{
+ int rval = ELAST + 1;
+ kern_return_t macherr = KERN_FAILURE;
+ mach_port_t kxport, tport = MACH_PORT_NULL, myport = MACH_PORT_NULL;
+ int busyStatus = ELAST + 1;
+ mountpoint_t busyVol;
+
+ 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)
+ tport = mach_task_self();
+ if (tport == MACH_PORT_NULL) goto finish;
+ macherr = mach_port_allocate(tport, MACH_PORT_RIGHT_RECEIVE, &myport);
+ if (macherr) goto finish;
+
+ // try to lock for reboot
+ macherr = kextmanager_lock_reboot(kxport, myport, !WAITFORLOCK, busyVol,
+ &busyStatus);
+ if (macherr) goto finish;
+
+ if (busyStatus == EBUSY) {
+ warnx("%s is busy updating; waiting for lock", busyVol);
+ macherr = kextmanager_lock_reboot(kxport, myport, WAITFORLOCK,
+ busyVol, &busyStatus);
+ if (macherr) goto finish;
+ }
+
+ if (busyStatus == EALREADY) {
+ // reboot already in progress
+ rval = 0;
+ } else {
+ rval = busyStatus;
+ }
+
+finish:
+ // in general, we want to err on the side of allowing the reboot
+ if (macherr) {
+ if (macherr != BOOTSTRAP_UNKNOWN_SERVICE)
+ warnx("WARNING: couldn't lock kext manager for reboot: %s",
+ mach_error_string(macherr));
+ rval = 0;
+ }
+ // unless we got the lock, clean up our port
+ if (busyStatus != 0 && myport != MACH_PORT_NULL)
+ mach_port_mod_refs(tport, myport, MACH_PORT_RIGHT_RECEIVE, -1);
+
+ return rval;
+}
+#endif /* __APPLE__ */
+
--- /dev/null
+.\"-
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)sync.8 8.1 (Berkeley) 5/31/93
+.\" $FreeBSD: src/bin/sync/sync.8,v 1.16 2005/01/10 08:39:26 imp Exp $
+.\"
+.Dd May 31, 1993
+.Dt SYNC 8
+.Os
+.Sh NAME
+.Nm sync
+.Nd force completion of pending disk writes (flush cache)
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility
+can be called to ensure that all disk writes have been completed before the
+processor is halted in a way not suitably done by
+.Xr shutdown 8 .
+Generally, it is preferable to use
+.Xr shutdown 8
+to shut down the system,
+as they may perform additional actions
+such as resynchronizing the hardware clock
+and flushing internal caches before performing a final
+.Nm .
+.Pp
+The
+.Nm
+utility utilizes the
+.Xr sync 2
+function call.
+.Sh SEE ALSO
+.Xr fsync 2 ,
+.Xr sync 2 ,
+.Xr shutdown 8
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v4 .
--- /dev/null
+/*-
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1987, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)sync.c 8.1 (Berkeley) 5/31/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sync/sync.c,v 1.16 2005/01/10 08:39:26 imp Exp $");
+
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(int argc __unused, char *argv[] __unused)
+{
+ sync();
+ exit(0);
+}
--- /dev/null
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)sysctl.8 8.2 (Berkeley) 5/9/95
+.\"
+.Dd "May 9, 1995"
+.Dt SYSCTL 8
+.Os
+.Sh NAME
+.Nm sysctl
+.Nd get or set kernel state
+.Sh SYNOPSIS
+.Nm sysctl
+.Op Fl bn
+.Ar name ...
+.Nm sysctl
+.Op Fl bn
+.Fl w
+.Ar name=value ...
+.Nm sysctl
+.Op Fl bn
+.Fl a
+.Nm sysctl
+.Op Fl bn
+.Fl A
+.Nm sysctl
+.Op Fl bn
+.Fl X
+.Sh DESCRIPTION
+The
+.Nm sysctl
+utility retrieves kernel state and allows processes with
+appropriate privilege to set kernel state.
+The state to be retrieved or set is described using a
+``Management Information Base'' (``MIB'') style name,
+described as a dotted set of components.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.\" ==========
+.It Fl A
+List all MIB variables including opaque variables (which are normally suppressed).
+The format and length are printed, as well as a hex dump of the first sixteen bytes of the value.
+.\" ==========
+.It Fl a
+List all the currently available non-opaque values.
+This option is ignored if one or more variable names are specified on
+the command line.
+.\" ==========
+.It Fl b
+Force the value of the variable(s) to be output in raw, binary format.
+No names are printed and no terminating newlines are output.
+This is mostly useful with a single variable.
+.\" ==========
+.It Fl n
+Show only variable values, not their names.
+This option is useful for setting shell variables.
+For instance, to save the pagesize in variable
+.Va psize ,
+use:
+.Pp
+.Dl "set psize=`sysctl -n hw.pagesize`"
+.\" ==========
+.It Fl w Ar name=value
+Used to set values. The MIB name (
+.Ar name
+) followed by an equal sign and the new value (
+.Ar value
+) to be used.
+.\" ==========
+.It Fl X
+Same as
+.Fl A ,
+but prints a hex dump of the entire value
+instead of just the first few bytes.
+.El
+.Pp
+If just a MIB style name is given,
+the corresponding value is retrieved.
+.Pp
+The information available from
+.Nm sysctl
+consists of integers, strings, and tables.
+The tabular information can only be retrieved by special
+purpose programs such as
+.Nm ps ,
+.Nm systat ,
+and
+.Nm netstat .
+The string and integer information is summarized below.
+For a detailed description of these variable see
+.Xr sysctl 3 .
+The changeable column indicates whether a process with appropriate
+privilege can change the value.
+.Bl -column net.inet.ip.forwardingxxxxxx integerxxx
+.It Sy Name Type Changeable
+.It kern.ostype string no
+.It kern.osrelease string no
+.It kern.osrevision integer no
+.It kern.version string no
+.It kern.maxvnodes integer yes
+.It kern.maxproc integer yes
+.It kern.maxfiles integer yes
+.It kern.argmax integer no
+.It kern.securelevel integer raise only
+.It kern.hostname string yes
+.It kern.hostid integer yes
+.It kern.clockrate struct no
+.It kern.posix1version integer no
+.It kern.ngroups integer no
+.It kern.job_control integer no
+.It kern.saved_ids integer no
+.It kern.link_max integer no
+.It kern.max_canon integer no
+.It kern.max_input integer no
+.It kern.name_max integer no
+.It kern.path_max integer no
+.It kern.pipe_buf integer no
+.It kern.chown_restricted integer no
+.It kern.no_trunc integer no
+.It kern.vdisable integer no
+.It kern.boottime struct no
+.It vm.loadavg struct no
+.It vm.swapusage struct no
+.It machdep.console_device dev_t no
+.It net.inet.ip.forwarding integer yes
+.It net.inet.ip.redirect integer yes
+.It net.inet.ip.ttl integer yes
+.It net.inet.icmp.maskrepl integer yes
+.It net.inet.udp.checksum integer yes
+.It hw.machine string no
+.It hw.model string no
+.It hw.ncpu integer no
+.It hw.byteorder integer no
+.It hw.physmem integer no
+.It hw.usermem integer no
+.It hw.memsize integer no
+.It hw.pagesize integer no
+.It user.cs_path string no
+.It user.bc_base_max integer no
+.It user.bc_dim_max integer no
+.It user.bc_scale_max integer no
+.It user.bc_string_max integer no
+.It user.coll_weights_max integer no
+.It user.expr_nest_max integer no
+.It user.line_max integer no
+.It user.re_dup_max integer no
+.It user.posix2_version integer no
+.It user.posix2_c_bind integer no
+.It user.posix2_c_dev integer no
+.It user.posix2_char_term integer no
+.It user.posix2_fort_dev integer no
+.It user.posix2_fort_run integer no
+.It user.posix2_localedef integer no
+.It user.posix2_sw_dev integer no
+.It user.posix2_upe integer no
+.El
+.Pp
+The
+.Nm sysctl
+program can get or set debugging variables
+that have been identified for its display.
+This information can be obtained by using the command:
+.Bd -literal -offset indent
+sysctl debug
+.Ed
+.Pp
+In addition,
+.Nm sysctl
+can extract information about the filesystems that have been compiled
+into the running system.
+This information can be obtained by using the command:
+.Bd -literal -offset indent
+sysctl vfs
+.Ed
+.Pp
+By default, only filesystems that are actively being used are listed.
+Use of the
+.Fl A
+flag lists all the filesystems compiled into the running kernel.
+.Sh EXAMPLES
+.Pp
+For example, to retrieve the maximum number of processes allowed
+in the system, one would use the request:
+.Bd -literal -offset indent
+sysctl kern.maxproc
+.Ed
+.Pp
+To set the maximum number of processes allowed
+in the system to 1000, one would use the request:
+.Bd -literal -offset inden
+sysctl -w kern.maxproc=1000
+.Ed
+.Pp
+Information about the system clock rate may be obtained with:
+.Bd -literal -offset indent
+sysctl kern.clockrate
+.Ed
+.Pp
+Information about the load average history may be obtained with:
+.Bd -literal -offset indent
+sysctl vm.loadavg
+.Ed
+.Pp
+Information about the system's swap space usage may be obtained with:
+.Bd -literal -offset indent
+sysctl vm.swapusage
+.Ed
+.Sh FILES
+.Bl -tag -width <netinet/icmpXvar.h> -compact
+.It Pa <sys/sysctl.h>
+definitions for top level identifiers, second level kernel and hardware
+identifiers, and user level identifiers
+.It Pa <sys/socket.h>
+definitions for second level network identifiers
+.It Pa <sys/gmon.h>
+definitions for third level profiling identifiers
+.It Pa <vm/vm_param.h>
+definitions for second level virtual memory identifiers
+.It Pa <netinet/in.h>
+definitions for third level Internet identifiers and
+fourth level IP identifiers
+.It Pa <netinet/icmp_var.h>
+definitions for fourth level ICMP identifiers
+.It Pa <netinet/udp_var.h>
+definitions for fourth level UDP identifiers
+.El
+.Sh SEE ALSO
+.Xr sysctl 3
+.Sh HISTORY
+.Nm sysctl
+first appeared in 4.4BSD.
--- /dev/null
+ /*
+ * Copyright (c) 1999-2010 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@
+ */
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+ /*
+ Modified November 1, 2000, by Ryan Rempel, ryan.rempel@utoronto.ca
+
+ The Darwin sysctl mechanism is in a state of flux. Parts of the kernel use the old
+ style of BSD sysctl definition, and other parts use the new style. The sysctl (8)
+ command that shipped with Darwin 1.2 (OS X PB) did not allow you to access
+ all possible sysctl values. In particular, it did not permit access to sysctl values
+ created by kernel extensions--hence my particular interest. The freeBSD sysctl (8)
+ command compiled and ran under Darwin 1.2, and it did permit access to
+ sysctl values created by kernel extensions, as well as several others. However, it
+ did not permit access to many other values which the Darwin 1.2 sysctl could access.
+
+ What I have done is merge the Darwin 1.2 sysctl and the freeBSD sysctl. Essentially,
+ there are two points of merger. When showing all values (i.e. -a, -A, or -X), sysctl now
+ runs the Darwin 1.2 routine to show all values, and then the freeBSD routine. This does
+ result in some duplication. When getting or setting a particular value, sysctl now tries
+ the freeBSD way first. If it cannot find the value, then it tries the Darwin 1.2 way.
+
+ There are a few oddities which this creates (aside from some duplication with -a, -A,
+ and -X). The freeBSD version of sysctl now supports two extra options, -b and -X.
+ In this syctl, those options are supported where the value is retrieved by the freeBSD
+ routine, and have no effect where the value is retrieved by the Darwin 1.2 routine.
+ The freeBSD sysctl uses a ':' to separate the name and the value, whereas Darwin 1.2's
+ sysctl uses a '='. I have left this way, as it lets you know which routine was used,
+ should it matter.
+
+ I have also fixed several lines which gave warnings previously, one of which appears
+ to have been an actual bug (bufp was dereferenced when it shouldn't have been).
+ I have also incoporated my previous patch to permit setting kern.hostid as an unsigned
+ integer. In the freeBSD side of the code, I have incorporated a general fix for
+ setting values where the format is specified as unsigned integer.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static char copyright[] =
+"@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+__unused static char sccsid[] = "@(#)sysctl.c 8.5 (Berkeley) 5/9/95";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/gmon.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#ifdef __APPLE__
+#include <mach/machine/vm_param.h>
+#include <mach/machine/vm_types.h>
+#include <mach/mach_types.h>
+#else
+#include <vm/vm_param.h>
+#endif /* __APPLE__ */
+
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <err.h>
+
+struct ctlname topname[] = CTL_NAMES;
+struct ctlname kernname[] = CTL_KERN_NAMES;
+struct ctlname vmname[] = CTL_VM_NAMES;
+struct ctlname hwname[] = CTL_HW_NAMES;
+struct ctlname username[] = CTL_USER_NAMES;
+struct ctlname debugname[CTL_DEBUG_MAXID];
+struct ctlname *vfsname;
+#ifdef CTL_MACHDEP_NAMES
+struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
+#endif
+char names[BUFSIZ];
+int lastused;
+
+struct list {
+ struct ctlname *list;
+ int size;
+};
+struct list toplist = { topname, CTL_MAXID };
+struct list secondlevel[] = {
+ { 0, 0 }, /* CTL_UNSPEC */
+ { kernname, KERN_MAXID }, /* CTL_KERN */
+ { vmname, VM_MAXID }, /* CTL_VM */
+ { 0, 0 }, /* CTL_VFS */
+ { 0, 0 }, /* CTL_NET */
+ { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */
+ { hwname, HW_MAXID }, /* CTL_HW */
+#ifdef CTL_MACHDEP_NAMES
+ { machdepname, CPU_MAXID }, /* CTL_MACHDEP */
+#else
+ { 0, 0 }, /* CTL_MACHDEP */
+#endif
+ { username, USER_MAXID }, /* CTL_USER_NAMES */
+};
+
+static int Aflag, aflag, bflag, hflag, nflag, wflag, Xflag;
+static int foundSome = 0;
+static int invalid_name_used = 0;
+
+void listall(char *prefix, struct list *lp);
+void old_parse(char *string, int flags);
+void debuginit();
+void vfsinit();
+int findname(char *string, char *level, char **bufp, struct list *namelist);
+void usage();
+
+static void parse(char *string, int flags);
+static int oidfmt(int *, int, char *, u_int *);
+static int show_var(int *, int, int);
+static int sysctl_all (int *oid, int len);
+static int name2oid(char *, int *);
+
+/*
+ * Variables requiring special processing.
+ */
+#define CLOCK 0x00000001
+#define BOOTTIME 0x00000002
+#define CONSDEV 0x00000004
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+// extern char *optarg; // unused
+ extern int optind;
+ int ch, lvl1;
+
+ while ((ch = getopt(argc, argv, "AabnwX")) != EOF) {
+ switch (ch) {
+ case 'A': Aflag = 1; break;
+ case 'a': aflag = 1; break;
+ case 'b': bflag = 1; break;
+ case 'h': hflag = 1; break;
+ case 'n': nflag = 1; break;
+ case 'w': wflag = 1; break;
+ case 'X': Xflag = Aflag = 1; break;
+ default: usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0 && (Aflag || aflag)) {
+ debuginit();
+ vfsinit();
+ for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
+ listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
+ exit (sysctl_all(0, 0));
+ }
+ if (argc == 0)
+ usage();
+ for (; *argv != NULL; ++argv)
+ parse(*argv, 1);
+ exit(invalid_name_used ? 1 : 0);
+}
+
+/*
+ * List all variables known to the system.
+ */
+void
+listall(prefix, lp)
+ char *prefix;
+ struct list *lp;
+{
+ int lvl2;
+ char *cp, name[BUFSIZ];
+
+ if (lp->list == 0)
+ return;
+ strcpy(name, prefix);
+ cp = &name[strlen(name)];
+ *cp++ = '.';
+ for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
+ if (lp->list[lvl2].ctl_name == 0)
+ continue;
+ strcpy(cp, lp->list[lvl2].ctl_name);
+ old_parse(name, Aflag);
+ }
+}
+
+/*
+ * Parse a name into a MIB entry.
+ * Lookup and print out the MIB entry if it exists.
+ * Set a new value if requested.
+ */
+void
+old_parse(string, flags)
+ char *string;
+ int flags;
+{
+ int indx, type, state, len;
+ size_t size;
+ int special = 0;
+ void *newval = 0;
+ int intval, newsize = 0;
+ unsigned int uintval;
+ int useUnsignedInt = 0;
+ quad_t quadval;
+ struct list *lp;
+ struct vfsconf vfc;
+ int mib[CTL_MAXNAME];
+ char *cp, *bufp, buf[BUFSIZ] /*, strval[BUFSIZ] */ ;
+
+ bufp = buf;
+ snprintf(buf, BUFSIZ, "%s", string);
+ if ((cp = strchr(string, '=')) != NULL) {
+ if (!wflag) {
+ fprintf(stderr, "Must specify -w to set variables\n");
+ exit(2);
+ }
+ *strchr(buf, '=') = '\0';
+ *cp++ = '\0';
+ while (isspace(*cp))
+ cp++;
+ newval = cp;
+ newsize = strlen(cp);
+ }
+ if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
+ return;
+ mib[0] = indx;
+ if (indx == CTL_VFS)
+ vfsinit();
+ if (indx == CTL_DEBUG)
+ debuginit();
+ lp = &secondlevel[indx];
+ if (lp->list == 0) {
+ if (!foundSome) fprintf(stderr, "%s: class is not implemented\n",
+ topname[indx].ctl_name);
+ return;
+ }
+ if (bufp == NULL) {
+ listall(topname[indx].ctl_name, lp);
+ return;
+ }
+ if ((indx = findname(string, "second", &bufp, lp)) == -1)
+ return;
+ mib[1] = indx;
+ type = lp->list[indx].ctl_type;
+ len = 2;
+ switch (mib[0]) {
+
+ case CTL_KERN:
+ switch (mib[1]) {
+ case KERN_PROF:
+ mib[2] = GPROF_STATE;
+ size = sizeof state;
+ if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) {
+ if (flags == 0)
+ return;
+ if (!nflag)
+ fprintf(stdout, "%s: ", string);
+ fprintf(stderr,
+ "kernel is not compiled for profiling\n");
+ return;
+ }
+ if (!nflag)
+ fprintf(stdout, "%s: %s\n", string,
+ state == GMON_PROF_OFF ? "off" : "running");
+ return;
+ case KERN_VNODE:
+ case KERN_FILE:
+ if (flags == 0)
+ return;
+ fprintf(stderr,
+ "Use pstat to view %s information\n", string);
+ return;
+ case KERN_PROC:
+ if (flags == 0)
+ return;
+ fprintf(stderr,
+ "Use ps to view %s information\n", string);
+ return;
+ case KERN_CLOCKRATE:
+ special |= CLOCK;
+ break;
+ case KERN_BOOTTIME:
+ special |= BOOTTIME;
+ break;
+ case KERN_HOSTID:
+ useUnsignedInt = 1;
+ break;
+ }
+ break;
+
+ case CTL_HW:
+ useUnsignedInt = 1;
+ break;
+
+ case CTL_VM: break;
+#if 0 /* XXX Handled by the new sysctl mechanism */
+ switch (mib[1]) {
+ case VM_LOADAVG: { /* XXX this is bogus */
+ double loads[3];
+
+ getloadavg(loads, 3);
+ if (!nflag)
+ fprintf(stdout, "%s: ", string);
+ fprintf(stdout, "%.2f %.2f %.2f\n",
+ loads[0], loads[1], loads[2]);
+ return;
+ }
+ case VM_SWAPUSAGE: {
+ struct xsw_usage xsu;
+ int saved_errno;
+
+ size = sizeof (xsu);
+ if (sysctl(mib, 2, &xsu, &size, NULL, 0) != 0) {
+ if (flags == 0)
+ return;
+ saved_errno = errno;
+ if (!nflag)
+ fprintf(stderr, "%s: ", string);
+ fprintf(stderr, "sysctl(VM_SWAPUSAGE): %s\n",
+ strerror(saved_errno));
+ return;
+ }
+
+ if (!nflag)
+ fprintf(stdout, "%s: ", string);
+ fprintf(stdout,
+ "total = %.2fM used = %.2fM free = %.2fM %s\n",
+ ((double) xsu.xsu_total) / (1024.0 * 1024.0),
+ ((double) xsu.xsu_used) / (1024.0 * 1024.0),
+ ((double) xsu.xsu_avail) / (1024.0 * 1024.0),
+ xsu.xsu_encrypted ? "(encrypted)" : "");
+ return;
+ }
+ }
+ if (flags == 0)
+ return;
+ fprintf(stderr,
+ "Use vmstat or systat to view %s information\n", string);
+ return;
+#endif
+
+ case CTL_DEBUG:
+ mib[2] = CTL_DEBUG_VALUE;
+ len = 3;
+ break;
+
+ case CTL_MACHDEP:
+#ifdef CPU_CONSDEV
+ if (mib[1] == CPU_CONSDEV)
+ special |= CONSDEV;
+#endif
+ break;
+
+ case CTL_VFS:
+ mib[3] = mib[1];
+ mib[1] = VFS_GENERIC;
+ mib[2] = VFS_CONF;
+ len = 4;
+ size = sizeof vfc;
+ if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) {
+ perror("vfs print");
+ return;
+ }
+ if (flags == 0 && vfc.vfc_refcount == 0)
+ return;
+ if (!nflag)
+ fprintf(stdout, "%s has %d mounted instance%s\n",
+ string, vfc.vfc_refcount,
+ vfc.vfc_refcount != 1 ? "s" : "");
+ else
+ fprintf(stdout, "%d\n", vfc.vfc_refcount);
+ return;
+
+ case CTL_USER:
+ break;
+
+ default:
+ fprintf(stderr, "Illegal top level value: %d\n", mib[0]);
+ return;
+
+ }
+ if (bufp) {
+ fprintf(stderr, "name %s in %s is unknown\n", bufp, string);
+ return;
+ }
+ if (newsize > 0) {
+ switch (type) {
+ case CTLTYPE_INT:
+ if (useUnsignedInt) {
+ uintval = strtoul(newval, NULL, 0);
+ if ((uintval == 0) && (errno == EINVAL)) {
+ fprintf(stderr, "invalid argument: %s\n",
+ (char *)newval);
+ return;
+ }
+ newval = &uintval;
+ newsize = sizeof uintval;
+ } else {
+ intval = strtol(newval, NULL, 0);
+ if ((intval == 0) && (errno == EINVAL)) {
+ fprintf(stderr, "invalid argument: %s\n",
+ (char *)newval);
+ return;
+ }
+ newval = &intval;
+ newsize = sizeof intval;
+ }
+ break;
+
+ case CTLTYPE_QUAD:
+ quadval = strtoq(newval, NULL, 0);
+ if ((quadval == 0) && (errno == EINVAL)) {
+ fprintf(stderr, "invalid argument: %s\n",
+ (char *)newval);
+ return;
+ }
+ newval = &quadval;
+ newsize = sizeof quadval;
+ break;
+ }
+ }
+ size = BUFSIZ;
+ if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
+ if (flags == 0)
+ return;
+ switch (errno) {
+ case ENOTSUP:
+ fprintf(stderr, "%s: value is not available\n", string);
+ return;
+ case ENOTDIR:
+ fprintf(stderr, "%s: specification is incomplete\n",
+ string);
+ return;
+ case ENOMEM:
+ fprintf(stderr, "%s: type is unknown to this program\n",
+ string);
+ return;
+ case ENOENT:
+ fprintf(stderr, "%s: no such MIB\n",
+ string);
+ return;
+ default:
+ perror(string);
+ return;
+ }
+ }
+ if (special & CLOCK) {
+ struct clockinfo *clkp = (struct clockinfo *)buf;
+
+ if (!nflag)
+ fprintf(stdout, "%s: ", string);
+ fprintf(stdout,
+ "hz = %d, tick = %d, profhz = %d, stathz = %d\n",
+ clkp->hz, clkp->tick, clkp->profhz, clkp->stathz);
+ return;
+ }
+ if (special & BOOTTIME) {
+ struct timeval *btp = (struct timeval *)buf;
+
+ if (!nflag)
+ fprintf(stdout, "%s = %s\n", string,
+ ctime((time_t *) &btp->tv_sec));
+ else
+ fprintf(stdout, "%ld\n", btp->tv_sec);
+ return;
+ }
+ if (special & CONSDEV) {
+ dev_t dev = *(dev_t *)buf;
+
+ if (!nflag)
+ fprintf(stdout, "%s = %s\n", string,
+ devname(dev, S_IFCHR));
+ else
+ fprintf(stdout, "0x%x\n", dev);
+ return;
+ }
+ switch (type) {
+ case CTLTYPE_INT:
+ if (newsize == 0) {
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ fprintf(stdout, useUnsignedInt ? "%u\n" : "%d\n", *(int *)buf);
+ } else {
+ if (!nflag)
+ fprintf(stdout, useUnsignedInt ? "%s: %u -> " : "%s: %d -> ",
+ string, *(int *)buf);
+ fprintf(stdout, useUnsignedInt ? "%u\n" : "%d\n", *(int *)newval);
+ }
+ return;
+
+ case CTLTYPE_STRING:
+ if (newsize == 0) {
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ fprintf(stdout, "%s\n", buf);
+ } else {
+ if (!nflag)
+ fprintf(stdout, "%s: %s -> ", string, buf);
+ fprintf(stdout, "%s\n", (char *) newval);
+ }
+ return;
+
+ case CTLTYPE_QUAD:
+ if (newsize == 0) {
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ fprintf(stdout, "%qd\n", *(quad_t *)buf);
+ } else {
+ if (!nflag)
+ fprintf(stdout, "%s: %qd -> ", string,
+ *(quad_t *)buf);
+ fprintf(stdout, "%qd\n", *(quad_t *)newval);
+ }
+ return;
+
+ case CTLTYPE_NODE:
+ case CTLTYPE_STRUCT:
+ return;
+
+ default:
+ fprintf(stderr, "%s: unknown type returned\n",
+ string);
+ return;
+ }
+}
+
+/*
+ * Initialize the set of debugging names
+ */
+void debuginit()
+{
+ int mib[3], loc, i;
+ size_t size;
+
+ if (secondlevel[CTL_DEBUG].list != 0)
+ return;
+ secondlevel[CTL_DEBUG].list = debugname;
+ mib[0] = CTL_DEBUG;
+ mib[2] = CTL_DEBUG_NAME;
+ for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
+ mib[1] = i;
+ size = BUFSIZ - loc;
+ if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
+ continue;
+ debugname[i].ctl_name = &names[loc];
+ debugname[i].ctl_type = CTLTYPE_INT;
+ loc += size;
+ }
+ lastused = loc;
+}
+
+/*
+ * Initialize the set of filesystem names
+ */
+void vfsinit()
+{
+ int mib[4], maxtypenum, cnt, loc, size;
+ struct vfsconf vfc;
+ size_t buflen;
+
+ if (secondlevel[CTL_VFS].list != 0)
+ return;
+ mib[0] = CTL_VFS;
+ mib[1] = VFS_GENERIC;
+ mib[2] = VFS_MAXTYPENUM;
+ buflen = 4;
+ if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
+ return;
+ if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == 0)
+ return;
+ memset(vfsname, 0, maxtypenum * sizeof(*vfsname));
+ mib[2] = VFS_CONF;
+ buflen = sizeof vfc;
+ for (loc = lastused, cnt = 0; cnt < maxtypenum; cnt++) {
+ mib[3] = cnt;
+ if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
+ if (errno == ENOTSUP)
+ continue;
+ perror("vfsinit");
+ free(vfsname);
+ return;
+ }
+ strcat(&names[loc], vfc.vfc_name);
+ vfsname[cnt].ctl_name = &names[loc];
+ vfsname[cnt].ctl_type = CTLTYPE_INT;
+ size = strlen(vfc.vfc_name) + 1;
+ loc += size;
+ }
+ lastused = loc;
+ secondlevel[CTL_VFS].list = vfsname;
+ secondlevel[CTL_VFS].size = maxtypenum;
+ return;
+}
+
+/*
+ * Scan a list of names searching for a particular name.
+ */
+int
+findname(string, level, bufp, namelist)
+ char *string;
+ char *level;
+ char **bufp;
+ struct list *namelist;
+{
+ char *name;
+ int i;
+
+ /* Make 'sysctl kern.' style behave the same as 'sysctl kern' 3360872*/
+ if (bufp[0][strlen(*bufp)-1] == '.')
+ bufp[0][strlen(*bufp)-1]='\0';
+ if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
+ if (!foundSome) {
+ fprintf(stderr, "%s: incomplete specification\n", string);
+ invalid_name_used = 1;
+ }
+ return (-1);
+ }
+ for (i = 0; i < namelist->size; i++)
+ if (namelist->list[i].ctl_name != NULL &&
+ strcmp(name, namelist->list[i].ctl_name) == 0)
+ break;
+ if (i == namelist->size) {
+ if (!foundSome) {
+ fprintf(stderr, "%s level name %s in %s is invalid\n",
+ level, name, string);
+ invalid_name_used = 1;
+ }
+ return (-1);
+ }
+ return (i);
+}
+
+void usage()
+{
+
+ (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
+ "usage: sysctl [-bn] variable ...",
+ " sysctl [-bn] -w variable=value ...",
+ " sysctl [-bn] -a",
+ " sysctl [-bn] -A",
+ " sysctl [-bn] -X");
+ exit(1);
+}
+
+/*
+ * Parse a name into a MIB entry.
+ * Lookup and print out the MIB entry if it exists.
+ * Set a new value if requested.
+ */
+static void
+parse(char *string, int flags)
+{
+ int len, i, j;
+ void *newval = 0;
+ int intval, newsize = 0;
+ unsigned int uintval;
+ quad_t quadval;
+ int mib[CTL_MAXNAME];
+ char *cp, *bufp, buf[BUFSIZ], fmt[BUFSIZ];
+ u_int kind;
+
+ bufp = buf;
+ if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ)
+ errx(1, "MIB too long");
+ snprintf(buf, BUFSIZ, "%s", string);
+ if ((cp = strchr(string, '=')) != NULL) {
+ if (!wflag)
+ errx(2, "must specify -w to set variables");
+ *strchr(buf, '=') = '\0';
+ *cp++ = '\0';
+ while (isspace(*cp))
+ cp++;
+ newval = cp;
+ newsize = strlen(cp);
+ } else {
+ if (wflag)
+ usage();
+ }
+ len = name2oid(bufp, mib);
+
+ if (len < 0) {
+ if (cp != NULL) {
+ while (*cp != '\0') cp--;
+ *cp = '=';
+ }
+ old_parse (string, flags);
+ return;
+ }
+
+ /*
+ * An non-zero return here is an OID space containing parameters which
+ * needs to be ignored in the interests of backward compatibility with
+ * pre-newsysctl sysctls.
+ */
+ if (oidfmt(mib, len, fmt, &kind))
+ return;
+
+ if (!wflag) {
+ if ((kind & CTLTYPE) == CTLTYPE_NODE) {
+ sysctl_all(mib, len);
+ foundSome = 1;
+ old_parse (string, flags);
+ } else {
+ i = show_var(mib, len, 1);
+ if (!i && !bflag)
+ putchar('\n');
+ }
+ } else {
+ if ((kind & CTLTYPE) == CTLTYPE_NODE)
+ errx(1, "oid '%s' isn't a leaf node", bufp);
+
+ if (!(kind&CTLFLAG_WR))
+ errx(1, "oid '%s' is read only", bufp);
+
+ switch (kind & CTLTYPE) {
+ case CTLTYPE_INT:
+ if ((*fmt == 'I') && (*(fmt + 1) == 'U')) {
+ uintval = (unsigned int) strtoul (newval, NULL, 0);
+ if ((uintval == 0) &&
+ (errno == EINVAL)) {
+ errx(1, "invalid argument: %s",
+ (char *)newval);
+ return;
+ }
+ newval = &uintval;
+ newsize = sizeof uintval;
+ } else {
+ intval = (int) strtol(newval, NULL, 0);
+ if ((intval == 0) &&
+ (errno == EINVAL)) {
+ errx(1, "invalid argument: %s",
+ (char *)newval);
+ return;
+ }
+ newval = &intval;
+ newsize = sizeof intval;
+ }
+ break;
+ case CTLTYPE_STRING:
+ break;
+ case CTLTYPE_QUAD:
+ quadval = strtoq(newval, NULL, 0);
+ if ((quadval == 0) && (errno == EINVAL)) {
+ errx(1, "invalid argument %s", (char *)newval);
+ return;
+ }
+ newval = &quadval;
+ newsize = sizeof(quadval);
+ break;
+ default:
+ errx(1, "oid '%s' is type %d,"
+ " cannot set that", bufp,
+ kind & CTLTYPE);
+ }
+
+ i = show_var(mib, len, 1);
+ if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
+ if (!i && !bflag)
+ putchar('\n');
+ switch (errno) {
+ case ENOTSUP:
+ errx(1, "%s: value is not available",
+ string);
+ case ENOTDIR:
+ errx(1, "%s: specification is incomplete",
+ string);
+ case ENOMEM:
+ errx(1, "%s: type is unknown to this program",
+ string);
+ default:
+ warn("%s", string);
+ return;
+ }
+ }
+ if (!bflag)
+ printf(" -> ");
+ i = nflag;
+ nflag = 1;
+ j = show_var(mib, len, 1);
+ if (!j && !bflag)
+ putchar('\n');
+ nflag = i;
+ }
+}
+
+/* These functions will dump out various interesting structures. */
+
+static int
+S_clockinfo(int l2, void *p)
+{
+ struct clockinfo *ci = (struct clockinfo*)p;
+
+ if (l2 != sizeof(*ci)) {
+ warnx("S_clockinfo %d != %ld", l2, sizeof(*ci));
+ return (1);
+ }
+ printf(hflag ? "{ hz = %'d, tick = %'d, tickadj = %'d, profhz = %'d, stathz = %'d }" :
+ "{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }",
+ ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz);
+ return (0);
+}
+
+static int
+S_loadavg(int l2, void *p)
+{
+ struct loadavg *tv = (struct loadavg*)p;
+
+ if (l2 != sizeof(*tv)) {
+ warnx("S_loadavg %d != %ld", l2, sizeof(*tv));
+ return (1);
+ }
+ printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
+ (double)tv->ldavg[0]/(double)tv->fscale,
+ (double)tv->ldavg[1]/(double)tv->fscale,
+ (double)tv->ldavg[2]/(double)tv->fscale);
+ return (0);
+}
+
+static int
+S_timeval(int l2, void *p)
+{
+ struct timeval *tv = (struct timeval*)p;
+ time_t tv_sec;
+ char *p1, *p2;
+
+ if (l2 != sizeof(*tv)) {
+ warnx("S_timeval %d != %ld", l2, sizeof(*tv));
+ return (1);
+ }
+ printf(hflag ? "{ sec = %'jd, usec = %'ld } " :
+ "{ sec = %jd, usec = %ld } ",
+ (intmax_t)tv->tv_sec, (long)tv->tv_usec);
+ tv_sec = tv->tv_sec;
+ p1 = strdup(ctime(&tv_sec));
+ for (p2=p1; *p2 ; p2++)
+ if (*p2 == '\n')
+ *p2 = '\0';
+ fputs(p1, stdout);
+ free(p1);
+ return (0);
+}
+
+static int
+S_xswusage(int l2, void *p)
+{
+ struct xsw_usage *xsu = (struct xsw_usage *)p;
+
+ if (l2 != sizeof(*xsu)) {
+ warnx("S_xswusage %d != %ld", l2, sizeof(*xsu));
+ return (1);
+ }
+ fprintf(stdout,
+ "total = %.2fM used = %.2fM free = %.2fM %s",
+ ((double)xsu->xsu_total) / (1024.0 * 1024.0),
+ ((double)xsu->xsu_used) / (1024.0 * 1024.0),
+ ((double)xsu->xsu_avail) / (1024.0 * 1024.0),
+ xsu->xsu_encrypted ? "(encrypted)" : "");
+ return (0);
+}
+
+static int
+T_dev_t(int l2, void *p)
+{
+ dev_t *d = (dev_t *)p;
+
+ if (l2 != sizeof(*d)) {
+ warnx("T_dev_T %d != %ld", l2, sizeof(*d));
+ return (1);
+ }
+ if ((int)(*d) != -1) {
+ if (minor(*d) > 255 || minor(*d) < 0)
+ printf("{ major = %d, minor = 0x%x }",
+ major(*d), minor(*d));
+ else
+ printf("{ major = %d, minor = %d }",
+ major(*d), minor(*d));
+ }
+ return (0);
+}
+
+/*
+ * These functions uses a presently undocumented interface to the kernel
+ * to walk the tree and get the type so it can print the value.
+ * This interface is under work and consideration, and should probably
+ * be killed with a big axe by the first person who can find the time.
+ * (be aware though, that the proper interface isn't as obvious as it
+ * may seem, there are various conflicting requirements.
+ */
+
+static int
+name2oid(char *name, int *oidp)
+{
+ int oid[2];
+ int i;
+ size_t j;
+
+ oid[0] = 0;
+ oid[1] = 3;
+
+ j = CTL_MAXNAME * sizeof (int);
+ i = sysctl(oid, 2, oidp, &j, name, strlen(name));
+ if (i < 0)
+ return i;
+ j /= sizeof (int);
+ return (j);
+}
+
+static int
+oidfmt(int *oid, int len, char *fmt, u_int *kind)
+{
+ int qoid[CTL_MAXNAME+2];
+ u_char buf[BUFSIZ];
+ int i;
+ size_t j;
+
+ qoid[0] = 0;
+ qoid[1] = 4;
+ memcpy(qoid + 2, oid, len * sizeof(int));
+
+ j = sizeof(buf);
+ i = sysctl(qoid, len + 2, buf, &j, 0, 0);
+ if (i) {
+ /*
+ * An ENOENT error return indicates that the OID in question
+ * is a node OID followed not by additional OID elements, but
+ * by integer parameters. We really do not want to support
+ * this type of thing going forward, but we alow it here for
+ * historical compatibility. Eventually, this will go away.
+ */
+ if (errno == ENOENT)
+ return ENOENT;
+ err(1, "sysctl fmt %d %ld %d", i, j, errno);
+ }
+
+ if (kind)
+ *kind = *(u_int *)buf;
+
+ if (fmt)
+ strcpy(fmt, (char *)(buf + sizeof(u_int)));
+ return (0);
+}
+
+/*
+ * This formats and outputs the value of one variable
+ *
+ * Returns zero if anything was actually output.
+ * Returns one if didn't know what to do with this.
+ * Return minus one if we had errors.
+ */
+
+static int
+show_var(int *oid, int nlen, int show_masked)
+{
+ u_char buf[BUFSIZ], *val, *mval, *p;
+ char name[BUFSIZ], /* descr[BUFSIZ], */ *fmt;
+ int qoid[CTL_MAXNAME+2];
+ int i;
+ int retval;
+ size_t j, len;
+ u_int kind;
+ int (*func)(int, void *) = 0;
+
+ qoid[0] = 0;
+ memcpy(qoid + 2, oid, nlen * sizeof(int));
+
+ qoid[1] = 1;
+ j = sizeof name;
+ i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
+ if (i || !j)
+ err(1, "sysctl name %d %ld %d", i, j, errno);
+
+ /* find an estimate of how much we need for this var */
+ j = 0;
+ i = sysctl(oid, nlen, 0, &j, 0, 0);
+ j += j; /* we want to be sure :-) */
+
+ val = mval = malloc(j);
+ len = j;
+ i = sysctl(oid, nlen, val, &len, 0, 0);
+ if (i || !len) {
+ retval = 1;
+ goto RETURN;
+ }
+
+ if (bflag) {
+ fwrite(val, 1, len, stdout);
+ retval = 0;
+ goto RETURN;
+ }
+
+ qoid[1] = 4;
+ j = sizeof buf;
+ i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
+ /*
+ * An ENOENT error return indicates that the OID in question
+ * is a node OID followed not by additional OID elements, but
+ * by integer parameters. We really do not want to support
+ * this type of thing going forward, but we alow it here for
+ * historical compatibility. Eventially, this will go away.
+ */
+ if (i && errno == ENOENT) {
+ retval = 1;
+ goto RETURN;
+ }
+
+ if (i || !j)
+ err(1, "sysctl fmt %d %ld %d", i, j, errno);
+
+ kind = *(u_int *)buf;
+ if (!show_masked && (kind & CTLFLAG_MASKED)) {
+ retval = 1;
+ goto RETURN;
+ }
+
+ fmt = (char *)(buf + sizeof(u_int));
+
+ p = val;
+ switch (*fmt) {
+ case '-':
+ /* deprecated, do not print */
+ retval = 0;
+ goto RETURN;
+
+
+ case 'A':
+ if (!nflag)
+ printf("%s: ", name);
+ printf("%s", p);
+ retval = 0;
+ goto RETURN;
+
+ case 'I':
+ if (!nflag)
+ printf("%s: ", name);
+ fmt++;
+ val = (unsigned char *)"";
+ while (len >= sizeof(int)) {
+ if(*fmt == 'U')
+ printf("%s%u", val, *(unsigned int *)p);
+ else
+ printf("%s%d", val, *(int *)p);
+ val = (unsigned char *)" ";
+ len -= sizeof (int);
+ p += sizeof (int);
+ }
+ retval = 0;
+ goto RETURN;
+
+ case 'L':
+ if (!nflag)
+ printf("%s: ", name);
+ fmt++;
+ val = (unsigned char *)"";
+ while (len >= sizeof(long)) {
+ if(*fmt == 'U')
+ printf("%s%lu", val, *(unsigned long *)p);
+ else
+ printf("%s%ld", val, *(long *)p);
+ val = (unsigned char *)" ";
+ len -= sizeof (long);
+ p += sizeof (long);
+ }
+ retval = 0;
+ goto RETURN;
+
+ case 'P':
+ if (!nflag)
+ printf("%s: ", name);
+ printf("%p", *(void **)p);
+ retval = 0;
+ goto RETURN;
+
+ case 'Q':
+ if (!nflag)
+ printf("%s: ", name);
+ fmt++;
+ val = (unsigned char *)"";
+ while (len >= sizeof(long long)) {
+ if(*fmt == 'U')
+ printf("%s%llu", val, *(unsigned long long *)p);
+ else
+ printf("%s%lld", val, *(long long *)p);
+ val = (unsigned char *)" ";
+ len -= sizeof (long long);
+ p += sizeof (long long);
+ }
+ retval = 0;
+ goto RETURN;
+
+
+ case 'T':
+ case 'S':
+ i = 0;
+ if (!strcmp(fmt, "S,clockinfo")) func = S_clockinfo;
+ else if (!strcmp(fmt, "S,timeval")) func = S_timeval;
+ else if (!strcmp(fmt, "S,loadavg")) func = S_loadavg;
+ else if (!strcmp(fmt, "S,xsw_usage")) func = S_xswusage;
+ else if (!strcmp(fmt, "T,dev_t")) func = T_dev_t;
+ if (func) {
+ if (!nflag)
+ printf("%s: ", name);
+ retval = (*func)(len, p);
+ goto RETURN;
+ }
+ /* FALL THROUGH */
+ default:
+ if (!Aflag) {
+ retval = 1;
+ goto RETURN;
+ }
+ if (!nflag)
+ printf("%s: ", name);
+ printf("Format:%s Length:%ld Dump:0x", fmt, len);
+ while (len--) {
+ printf("%02x", *p++);
+ if (Xflag || p < val+16)
+ continue;
+ printf("...");
+ break;
+ }
+ retval = 0;
+ goto RETURN;
+ }
+
+ retval = 1;
+ RETURN:
+ free(mval);
+ return (retval);
+}
+
+static int
+sysctl_all (int *oid, int len)
+{
+ int name1[22], name2[22];
+ int i, j;
+ size_t l1, l2;
+
+ name1[0] = 0;
+ name1[1] = 2;
+ l1 = 2;
+ if (len) {
+ memcpy(name1+2, oid, len*sizeof (int));
+ l1 += len;
+ } else {
+ name1[2] = 1;
+ l1++;
+ }
+ while (1) {
+ l2 = sizeof name2;
+ j = sysctl(name1, l1, name2, &l2, 0, 0);
+ if (j < 0) {
+ if (errno == ENOENT)
+ return 0;
+ else
+ err(1, "sysctl(getnext) %d %ld", j, l2);
+ }
+
+ l2 /= sizeof (int);
+
+ if (l2 < len)
+ return 0;
+
+ for (i = 0; i < len; i++)
+ if (name2[i] != oid[i])
+ return 0;
+
+ i = show_var(name2, l2, 0);
+ if (!i && !bflag)
+ putchar('\n');
+
+ memcpy(name1+2, name2, l2*sizeof (int));
+ l1 = 2 + l2;
+ }
+}
--- /dev/null
+.\" Modified August 3, 2007
+.\" Portions Copyright (c) 2007 Apple Inc.
+.\" Copyright (c) 1999 Chris Costello <chris@FreeBSD.org>
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD: src/share/man/man5/sysctl.conf.5,v 1.16 2004/07/03 18:29:23 ru Exp $
+.\"
+.Dd August 3, 2007
+.Dt SYSCTL.CONF 5
+.Os
+.Sh NAME
+.Nm sysctl.conf
+.Nd kernel state defaults
+.Sh DESCRIPTION
+The
+.Pa /etc/sysctl.conf
+file is read in when the system goes into multi-user mode to set default
+settings for the kernel.
+The
+.Pa /etc/sysctl.conf
+is in the format of the
+.Xr sysctl 8
+command, i.e.\&
+.Bd -literal -offset indent
+sysctl_mib=value
+.Ed
+.Pp
+Comments are denoted by a
+.Dq #
+at the beginning of a line.
+.Sh FILES
+.Bl -tag -width /etc/sysctl.conf -compact
+.It Pa /etc/sysctl.conf
+Initial settings for
+.Xr sysctl 8 .
+.El
+.Sh EXAMPLES
+To disable coredumps, you may use a configuration like:
+.Bd -literal -offset indent
+# Disable coredumps.
+kern.coredump=0
+.Ed
+.Sh SEE ALSO
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+file appeared in
+.Fx 4.0 .
+.Sh BUGS
+If loadable kernel modules are used to introduce additional kernel
+functionality and sysctls to manage that functionality,
+.Nm
+may be processed too early in the boot process to set those sysctls.
--- /dev/null
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ BA4FD2FE1372FE4E0025925C /* All_MacOSX */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BA4FD2FF1372FE4E0025925C /* Build configuration list for PBXAggregateTarget "All_MacOSX" */;
+ buildPhases = (
+ );
+ dependencies = (
+ ADA9007E1767A31300161ADF /* PBXTargetDependency */,
+ C625B29116D6F38700168EF7 /* PBXTargetDependency */,
+ B3F0E6DF16E97142008FAD09 /* PBXTargetDependency */,
+ 55CCB17816B851E900B56979 /* PBXTargetDependency */,
+ C96F50BA15BDFDA7008682F7 /* PBXTargetDependency */,
+ 1523FE6F1595069900661E82 /* PBXTargetDependency */,
+ BA0A861A1396B41F00D2272C /* PBXTargetDependency */,
+ BA0A861613968ECA00D2272C /* PBXTargetDependency */,
+ BA959E8813968D8A00CA9C60 /* PBXTargetDependency */,
+ BA959E8A13968D8A00CA9C60 /* PBXTargetDependency */,
+ BA959E8C13968D8A00CA9C60 /* PBXTargetDependency */,
+ BA959E8E13968D8A00CA9C60 /* PBXTargetDependency */,
+ BA959E9013968D8A00CA9C60 /* PBXTargetDependency */,
+ BA9BF4B3139682710018C7BB /* PBXTargetDependency */,
+ BA9BF4B5139682710018C7BB /* PBXTargetDependency */,
+ BA9BF4B7139682710018C7BB /* PBXTargetDependency */,
+ BA91CE6A137F43A500AE5160 /* PBXTargetDependency */,
+ BAE58A54137D69FB0049DD3B /* PBXTargetDependency */,
+ BAE58A42137A59300049DD3B /* PBXTargetDependency */,
+ BAE58A2E1379A1260049DD3B /* PBXTargetDependency */,
+ BAE58A301379A1260049DD3B /* PBXTargetDependency */,
+ BAE589FE137905740049DD3B /* PBXTargetDependency */,
+ BAE58A00137905740049DD3B /* PBXTargetDependency */,
+ BAE58A02137905740049DD3B /* PBXTargetDependency */,
+ BAE589D41378FDF40049DD3B /* PBXTargetDependency */,
+ BAE589B1137837AA0049DD3B /* PBXTargetDependency */,
+ BAE589B3137837AA0049DD3B /* PBXTargetDependency */,
+ BACC1D681377B8DC007728F4 /* PBXTargetDependency */,
+ BACC1D6A1377B8DC007728F4 /* PBXTargetDependency */,
+ BACC1D6C1377B8DC007728F4 /* PBXTargetDependency */,
+ BACC1D3C1377B5D9007728F4 /* PBXTargetDependency */,
+ BACC1D001377B3A4007728F4 /* PBXTargetDependency */,
+ BA4B7A981376600200003422 /* PBXTargetDependency */,
+ BA4B7A7C13765DC600003422 /* PBXTargetDependency */,
+ BA4B7A7A13765DC100003422 /* PBXTargetDependency */,
+ BA4B7A5A137649FA00003422 /* PBXTargetDependency */,
+ BA4B7A211373BF5000003422 /* PBXTargetDependency */,
+ BA4B7A0C1373BA8D00003422 /* PBXTargetDependency */,
+ BA4B79F81373B06B00003422 /* PBXTargetDependency */,
+ BA4B79DB1373A9CE00003422 /* PBXTargetDependency */,
+ BA4B79DD1373A9CE00003422 /* PBXTargetDependency */,
+ BA4B79C41373A58B00003422 /* PBXTargetDependency */,
+ BA9B76A81373A2CF001BB39F /* PBXTargetDependency */,
+ BA9B76AA1373A2CF001BB39F /* PBXTargetDependency */,
+ BA9B76AC1373A2CF001BB39F /* PBXTargetDependency */,
+ BA9B767513739E07001BB39F /* PBXTargetDependency */,
+ BA9B765413739B89001BB39F /* PBXTargetDependency */,
+ BAAEB3B413730E43003EA7A9 /* PBXTargetDependency */,
+ BAAEB3B613730E43003EA7A9 /* PBXTargetDependency */,
+ BAAEB3B813730E43003EA7A9 /* PBXTargetDependency */,
+ BA4FD350137307BC0025925C /* PBXTargetDependency */,
+ BA4FD3031372FE730025925C /* PBXTargetDependency */,
+ BA4FD3121373001C0025925C /* PBXTargetDependency */,
+ BA4FD329137301370025925C /* PBXTargetDependency */,
+ BA4FD337137306260025925C /* PBXTargetDependency */,
+ );
+ name = All_MacOSX;
+ productName = All_MacOSX;
+ };
+ BA4FD32F137305DD0025925C /* machine */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BA4FD330137305DD0025925C /* Build configuration list for PBXAggregateTarget "machine" */;
+ buildPhases = (
+ BA4FD335137306050025925C /* ShellScript */,
+ );
+ dependencies = (
+ BA4FD334137305E80025925C /* PBXTargetDependency */,
+ );
+ name = machine;
+ productName = machine;
+ };
+ BA959E7E13968C8E00CA9C60 /* zoneinfo */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BA959E8213968C8E00CA9C60 /* Build configuration list for PBXAggregateTarget "zoneinfo" */;
+ buildPhases = (
+ BA7248051397C1350008497A /* ShellScript */,
+ BA959E8113968C8E00CA9C60 /* ShellScript */,
+ BA28FB881396DA67004986CB /* CopyFiles */,
+ FD0AA4911630C39500606589 /* ShellScript */,
+ );
+ dependencies = (
+ );
+ name = zoneinfo;
+ productName = machine;
+ };
+ BA9B76991373A246001BB39F /* chfn */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BA9B769D1373A246001BB39F /* Build configuration list for PBXAggregateTarget "chfn" */;
+ buildPhases = (
+ BA9B769C1373A246001BB39F /* ShellScript */,
+ );
+ dependencies = (
+ BA9B76A01373A257001BB39F /* PBXTargetDependency */,
+ );
+ name = chfn;
+ productName = machine;
+ };
+ BA9B76A11373A2A2001BB39F /* chsh */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BA9B76A51373A2A2001BB39F /* Build configuration list for PBXAggregateTarget "chsh" */;
+ buildPhases = (
+ BA9B76A41373A2A2001BB39F /* ShellScript */,
+ );
+ dependencies = (
+ BA9B76A21373A2A2001BB39F /* PBXTargetDependency */,
+ );
+ name = chsh;
+ productName = machine;
+ };
+ BAAEB39C13730D5C003EA7A9 /* atq */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BAAEB3A013730D5C003EA7A9 /* Build configuration list for PBXAggregateTarget "atq" */;
+ buildPhases = (
+ BAAEB39F13730D5C003EA7A9 /* ShellScript */,
+ );
+ dependencies = (
+ BAAEB3A413730D6B003EA7A9 /* PBXTargetDependency */,
+ );
+ name = atq;
+ productName = machine;
+ };
+ BAAEB3A513730DFA003EA7A9 /* atrm */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BAAEB3A913730DFA003EA7A9 /* Build configuration list for PBXAggregateTarget "atrm" */;
+ buildPhases = (
+ BAAEB3A813730DFA003EA7A9 /* ShellScript */,
+ );
+ dependencies = (
+ BAAEB3A613730DFA003EA7A9 /* PBXTargetDependency */,
+ );
+ name = atrm;
+ productName = machine;
+ };
+ BAAEB3AC13730E1C003EA7A9 /* batch */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BAAEB3B013730E1C003EA7A9 /* Build configuration list for PBXAggregateTarget "batch" */;
+ buildPhases = (
+ BAAEB3AF13730E1C003EA7A9 /* ShellScript */,
+ );
+ dependencies = (
+ BAAEB3AD13730E1C003EA7A9 /* PBXTargetDependency */,
+ );
+ name = batch;
+ productName = machine;
+ };
+ BACC1D181377B4C9007728F4 /* All_iOS */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BACC1D191377B4C9007728F4 /* Build configuration list for PBXAggregateTarget "All_iOS" */;
+ buildPhases = (
+ );
+ dependencies = (
+ ADA900801767A31900161ADF /* PBXTargetDependency */,
+ C625B29316D6F39000168EF7 /* PBXTargetDependency */,
+ 55CCB17A16B851F300B56979 /* PBXTargetDependency */,
+ C96F50BC15BDFDB1008682F7 /* PBXTargetDependency */,
+ 1523FE711595069F00661E82 /* PBXTargetDependency */,
+ BA0A861C1396B42600D2272C /* PBXTargetDependency */,
+ BA0A861813968ED500D2272C /* PBXTargetDependency */,
+ BA959E9213968DA900CA9C60 /* PBXTargetDependency */,
+ BA959E9413968DA900CA9C60 /* PBXTargetDependency */,
+ BA959E9613968DA900CA9C60 /* PBXTargetDependency */,
+ BA959E9813968DA900CA9C60 /* PBXTargetDependency */,
+ BA959E9A13968DA900CA9C60 /* PBXTargetDependency */,
+ BA9BF4B9139682880018C7BB /* PBXTargetDependency */,
+ BA9BF4BB139682880018C7BB /* PBXTargetDependency */,
+ BA9BF4BD139682880018C7BB /* PBXTargetDependency */,
+ BAE58A56137D6A050049DD3B /* PBXTargetDependency */,
+ BAE58A44137A59390049DD3B /* PBXTargetDependency */,
+ BAE58A321379A1300049DD3B /* PBXTargetDependency */,
+ BAE58A341379A1300049DD3B /* PBXTargetDependency */,
+ BAE58A041379057F0049DD3B /* PBXTargetDependency */,
+ BAE58A061379057F0049DD3B /* PBXTargetDependency */,
+ BAE58A081379057F0049DD3B /* PBXTargetDependency */,
+ BAE589D61378FDFB0049DD3B /* PBXTargetDependency */,
+ BAE589B5137837B30049DD3B /* PBXTargetDependency */,
+ BAE589B7137837B30049DD3B /* PBXTargetDependency */,
+ BACC1D6E1377B8ED007728F4 /* PBXTargetDependency */,
+ BACC1D701377B8ED007728F4 /* PBXTargetDependency */,
+ BACC1D721377B8ED007728F4 /* PBXTargetDependency */,
+ BACC1D1C1377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D1E1377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D201377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D221377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D241377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D261377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D281377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D2A1377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D2C1377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D2E1377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D301377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D321377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D341377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D361377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D381377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D3A1377B58A007728F4 /* PBXTargetDependency */,
+ );
+ name = All_iOS;
+ productName = All_iOS;
+ };
+ BAE589AA137837130049DD3B /* pagesize */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BAE589AE137837130049DD3B /* Build configuration list for PBXAggregateTarget "pagesize" */;
+ buildPhases = (
+ BAE589AD137837130049DD3B /* ShellScript */,
+ BAE589B8137838C10049DD3B /* CopyFiles */,
+ );
+ dependencies = (
+ );
+ name = pagesize;
+ productName = machine;
+ };
+ BAE589F5137904DF0049DD3B /* halt */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BAE589F9137904DF0049DD3B /* Build configuration list for PBXAggregateTarget "halt" */;
+ buildPhases = (
+ BAE589F8137904DF0049DD3B /* ShellScript */,
+ );
+ dependencies = (
+ BAE589FC137905080049DD3B /* PBXTargetDependency */,
+ );
+ name = halt;
+ productName = machine;
+ };
+/* 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 */; };
+ 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 */; };
+ BA4B79C21373A55600003422 /* com.apple.bsd.dirhelper.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD21B1372FAFA0025925C /* com.apple.bsd.dirhelper.plist */; };
+ BA4B79CF1373A74B00003422 /* dmesg.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2201372FAFA0025925C /* dmesg.8 */; };
+ BA4B79D01373A74F00003422 /* dmesg.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2211372FAFA0025925C /* dmesg.c */; };
+ BA4B79D81373A99200003422 /* backing_store_alerts.defs in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2281372FAFA0025925C /* backing_store_alerts.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ BA4B79D91373A99600003422 /* backing_store_triggers.defs in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2291372FAFA0025925C /* backing_store_triggers.defs */; };
+ BA4B79EE1373AFFA00003422 /* dynamic_pager.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD22D1372FAFA0025925C /* dynamic_pager.c */; };
+ BA4B79EF1373B00300003422 /* backing_store_alerts.defs in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2281372FAFA0025925C /* backing_store_alerts.defs */; };
+ BA4B79F01373B00300003422 /* backing_store_triggers.defs in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2291372FAFA0025925C /* backing_store_triggers.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ BA4B79F11373B00300003422 /* default_pager_alerts.defs in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD22B1372FAFA0025925C /* default_pager_alerts.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ BA4B79F21373B01100003422 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766D13739D27001BB39F /* CoreFoundation.framework */; };
+ BA4B79F41373B01C00003422 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B79F31373B01B00003422 /* SystemConfiguration.framework */; };
+ BA4B79F51373B03300003422 /* dynamic_pager.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD22C1372FAFA0025925C /* dynamic_pager.8 */; };
+ BA4B79FC1373B82C00003422 /* com.apple.dynamic_pager.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4B79FA1373B7C300003422 /* com.apple.dynamic_pager.plist */; };
+ BA4B7A071373BA1F00003422 /* fs_usage.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2301372FAFA0025925C /* fs_usage.1 */; };
+ BA4B7A081373BA2400003422 /* fs_usage.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2311372FAFA0025925C /* fs_usage.c */; };
+ BA4B7A0A1373BA4600003422 /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ BA4B7A191373BEDD00003422 /* getconf.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2381372FAFA0025925C /* getconf.c */; };
+ BA4B7A1E1373BEEB00003422 /* getconf.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2371372FAFA0025925C /* getconf.1 */; };
+ BA4B7A291373C30100003422 /* confstr.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4B7A241373C30100003422 /* confstr.c */; };
+ BA4B7A2A1373C30100003422 /* limits.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4B7A251373C30100003422 /* limits.c */; };
+ BA4B7A2B1373C30100003422 /* pathconf.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4B7A261373C30100003422 /* pathconf.c */; };
+ BA4B7A2C1373C30100003422 /* progenv.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4B7A271373C30100003422 /* progenv.c */; };
+ BA4B7A2D1373C30100003422 /* sysconf.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4B7A281373C30100003422 /* sysconf.c */; };
+ BA4B7A511376492600003422 /* chat.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2401372FAFA0025925C /* chat.c */; };
+ BA4B7A521376492B00003422 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2461372FAFA0025925C /* init.c */; };
+ BA4B7A531376493000003422 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2471372FAFA0025925C /* main.c */; };
+ BA4B7A541376493500003422 /* subr.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2491372FAFA0025925C /* subr.c */; };
+ BA4B7A551376495900003422 /* getty.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2431372FAFA0025925C /* getty.8 */; };
+ BA4B7A571376498C00003422 /* gettytab.5 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2441372FAFA0025925C /* gettytab.5 */; };
+ BA4B7A581376499000003422 /* ttys.5 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD24A1372FAFA0025925C /* ttys.5 */; };
+ BA4B7A5C13764F2E00003422 /* com.apple.getty.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4B7A5B13764F1400003422 /* com.apple.getty.plist */; };
+ BA4B7A6713765CF500003422 /* hostinfo.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD24E1372FAFA0025925C /* hostinfo.c */; };
+ BA4B7A6813765D0000003422 /* hostinfo.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD24D1372FAFA0025925C /* hostinfo.8 */; };
+ BA4B7A7313765D5D00003422 /* iostat.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2531372FAFA0025925C /* iostat.c */; };
+ BA4B7A7513765D6B00003422 /* iostat.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2521372FAFA0025925C /* iostat.8 */; };
+ BA4B7A7713765D7700003422 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A7613765D7700003422 /* IOKit.framework */; };
+ BA4B7A7813765DB100003422 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766D13739D27001BB39F /* CoreFoundation.framework */; };
+ BA4B7A9213765F7C00003422 /* latency.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2581372FAFA0025925C /* latency.c */; };
+ BA4B7A9413765F8C00003422 /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A9313765F8B00003422 /* libncurses.dylib */; };
+ BA4B7A9513765FA100003422 /* latency.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2571372FAFA0025925C /* latency.1 */; };
+ BA4B7A9613765FE700003422 /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ BA4FD2FC1372FD670025925C /* ac.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1DC1372FAFA0025925C /* ac.c */; };
+ BA4FD2FD1372FD710025925C /* ac.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD1DB1372FAFA0025925C /* ac.8 */; };
+ BA4FD30F137300040025925C /* accton.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD1DF1372FAFA0025925C /* accton.8 */; };
+ BA4FD310137300080025925C /* accton.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1E01372FAFA0025925C /* accton.c */; };
+ 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 */; };
+ 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 */; };
+ BA4FD346137307750025925C /* parsetime.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1F01372FAFA0025925C /* parsetime.c */; };
+ BA4FD347137307750025925C /* perm.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1F31372FAFA0025925C /* perm.c */; };
+ BA4FD3491373079B0025925C /* at.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1ED1372FAFA0025925C /* at.h */; };
+ BA4FD34A1373079B0025925C /* panic.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1EF1372FAFA0025925C /* panic.h */; };
+ BA4FD34B1373079B0025925C /* parsetime.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1F11372FAFA0025925C /* parsetime.h */; };
+ BA4FD34C1373079B0025925C /* pathnames.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1F21372FAFA0025925C /* pathnames.h */; };
+ BA4FD34D1373079B0025925C /* perm.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1F41372FAFA0025925C /* perm.h */; };
+ BA4FD34E1373079B0025925C /* privs.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1F51372FAFA0025925C /* privs.h */; };
+ BA91CE58137D6CB800AE5160 /* login in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2611372FAFA0025925C /* login */; };
+ BA91CE64137F430E00AE5160 /* kextmanager.defs in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2B21372FAFA0025925C /* kextmanager.defs */; };
+ BA91CE65137F431100AE5160 /* shutdown.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2B51372FAFA0025925C /* shutdown.c */; };
+ BA91CE66137F433200AE5160 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A7613765D7700003422 /* IOKit.framework */; };
+ BA91CE67137F434200AE5160 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B79BF1373A53700003422 /* libbsm.dylib */; };
+ BA91CE68137F438700AE5160 /* shutdown.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2B41372FAFA0025925C /* shutdown.8 */; };
+ BA9B764313739ABE001BB39F /* pathnames.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1F21372FAFA0025925C /* pathnames.h */; };
+ BA9B764513739ABE001BB39F /* privs.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1F51372FAFA0025925C /* privs.h */; };
+ BA9B764E13739B1C001BB39F /* atrun.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1F91372FAFA0025925C /* atrun.c */; };
+ BA9B764F13739B45001BB39F /* atrun.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1FA1372FAFA0025925C /* atrun.h */; };
+ BA9B765013739B52001BB39F /* atrun.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD1F81372FAFA0025925C /* atrun.8 */; };
+ BA9B765213739B7D001BB39F /* com.apple.atrun.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD1FC1372FAFA0025925C /* com.apple.atrun.plist */; };
+ BA9B766513739C66001BB39F /* file_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2031372FAFA0025925C /* file_passwd.c */; };
+ BA9B766613739C66001BB39F /* nis_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2041372FAFA0025925C /* nis_passwd.c */; };
+ BA9B766713739C66001BB39F /* od_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2051372FAFA0025925C /* od_passwd.c */; };
+ BA9B766813739C66001BB39F /* pam_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2061372FAFA0025925C /* pam_passwd.c */; };
+ BA9B766913739C66001BB39F /* passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2071372FAFA0025925C /* passwd.c */; };
+ BA9B766A13739C66001BB39F /* stringops.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2081372FAFA0025925C /* stringops.c */; };
+ BA9B766B13739C7A001BB39F /* stringops.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD2091372FAFA0025925C /* stringops.h */; };
+ BA9B766C13739C84001BB39F /* chkpasswd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2011372FAFA0025925C /* chkpasswd.8 */; };
+ BA9B766F13739D27001BB39F /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766D13739D27001BB39F /* CoreFoundation.framework */; };
+ BA9B767013739D27001BB39F /* OpenDirectory.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766E13739D27001BB39F /* OpenDirectory.framework */; };
+ BA9B767213739D36001BB39F /* libpam.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B767113739D36001BB39F /* libpam.dylib */; };
+ BA9B767713739E9E001BB39F /* chkpasswd.h in Headers */ = {isa = PBXBuildFile; fileRef = BA9B767613739E9E001BB39F /* chkpasswd.h */; };
+ BA9B76851373A0D8001BB39F /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766D13739D27001BB39F /* CoreFoundation.framework */; };
+ BA9B76861373A0D8001BB39F /* OpenDirectory.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766E13739D27001BB39F /* OpenDirectory.framework */; };
+ BA9B768E1373A14B001BB39F /* chpass.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD20E1372FAFA0025925C /* chpass.c */; };
+ BA9B768F1373A159001BB39F /* edit.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2101372FAFA0025925C /* edit.c */; };
+ BA9B76901373A159001BB39F /* field.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2111372FAFA0025925C /* field.c */; };
+ BA9B76911373A159001BB39F /* open_directory.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2121372FAFA0025925C /* open_directory.c */; };
+ BA9B76921373A159001BB39F /* pw_copy.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2141372FAFA0025925C /* pw_copy.c */; };
+ BA9B76931373A159001BB39F /* table.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2161372FAFA0025925C /* table.c */; };
+ BA9B76941373A159001BB39F /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2171372FAFA0025925C /* util.c */; };
+ BA9B76951373A16A001BB39F /* chpass.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD20F1372FAFA0025925C /* chpass.h */; };
+ BA9B76961373A16A001BB39F /* open_directory.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD2131372FAFA0025925C /* open_directory.h */; };
+ BA9B76971373A16A001BB39F /* pw_copy.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD2151372FAFA0025925C /* pw_copy.h */; };
+ BA9B76981373A1A7001BB39F /* chpass.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD20D1372FAFA0025925C /* chpass.1 */; };
+ BA9BF495139681050018C7BB /* sync.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2B81372FAFA0025925C /* sync.8 */; };
+ BA9BF496139681090018C7BB /* sync.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2B91372FAFA0025925C /* sync.c */; };
+ BA9BF4A1139681500018C7BB /* sysctl.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2BD1372FAFA0025925C /* sysctl.c */; };
+ BA9BF4A31396816D0018C7BB /* sysctl.conf.5 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2BE1372FAFA0025925C /* sysctl.conf.5 */; };
+ BA9BF4A4139681710018C7BB /* sysctl.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2BC1372FAFA0025925C /* sysctl.8 */; };
+ BA9BF4A9139681910018C7BB /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ BA9BF4B0139682430018C7BB /* trace.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2C11372FAFA0025925C /* trace.1 */; };
+ BA9BF4B1139682480018C7BB /* trace.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2C21372FAFA0025925C /* trace.c */; };
+ BA9BF4C8139682DE0018C7BB /* vifs.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2C61372FAFA0025925C /* vifs.c */; };
+ BA9BF4C9139682E70018C7BB /* vifs.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2C51372FAFA0025925C /* vifs.8 */; };
+ BA9BF4D4139683140018C7BB /* vipw.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2CB1372FAFA0025925C /* vipw.8 */; };
+ BA9BF4D5139683180018C7BB /* vipw.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2CC1372FAFA0025925C /* vipw.c */; };
+ BA9BF4D61396831C0018C7BB /* pw_util.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2C91372FAFA0025925C /* pw_util.c */; };
+ BA9BF4E1139683890018C7BB /* vm_stat.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2CF1372FAFA0025925C /* vm_stat.1 */; };
+ BA9BF4E21396838C0018C7BB /* vm_stat.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2D01372FAFA0025925C /* vm_stat.c */; };
+ BA9BF4ED1396840C0018C7BB /* zdump.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2D31372FAFA0025925C /* zdump.8 */; };
+ BA9BF4EE139684100018C7BB /* zdump.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2D41372FAFA0025925C /* zdump.c */; };
+ BA9BF4F9139684CF0018C7BB /* zic.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2E11372FAFA0025925C /* zic.8 */; };
+ BA9BF4FA139684D30018C7BB /* zic.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2E21372FAFA0025925C /* zic.c */; };
+ BA9BF4FB139684D70018C7BB /* scheck.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2DE1372FAFA0025925C /* scheck.c */; };
+ BA9BF4FC139684DB0018C7BB /* ialloc.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2DC1372FAFA0025925C /* ialloc.c */; };
+ BACC1CF91377B288007728F4 /* login.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD25D1372FAFA0025925C /* login.c */; };
+ BACC1CFA1377B28C007728F4 /* login_audit.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD25F1372FAFA0025925C /* login_audit.c */; };
+ BACC1CFB1377B2A8007728F4 /* login.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD25C1372FAFA0025925C /* login.1 */; };
+ BACC1CFE1377B2D8007728F4 /* login.term in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2621372FAFA0025925C /* login.term */; };
+ BACC1D0B1377B413007728F4 /* makekey.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2681372FAFA0025925C /* makekey.c */; };
+ BACC1D0C1377B41B007728F4 /* makekey.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2671372FAFA0025925C /* makekey.8 */; };
+ BACC1D171377B4A9007728F4 /* mean.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD26B1372FAFA0025925C /* mean.c */; };
+ BACC1D471377B71D007728F4 /* mkfile.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD26F1372FAFA0025925C /* mkfile.c */; };
+ BACC1D481377B723007728F4 /* mkfile.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD26E1372FAFA0025925C /* mkfile.8 */; };
+ BACC1D571377B821007728F4 /* newgrp.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2731372FAFA0025925C /* newgrp.c */; };
+ BACC1D581377B82A007728F4 /* newgrp.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2721372FAFA0025925C /* newgrp.1 */; };
+ BACC1D631377B88B007728F4 /* nologin.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2781372FAFA0025925C /* nologin.c */; };
+ BACC1D641377B894007728F4 /* nologin.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2771372FAFA0025925C /* nologin.8 */; };
+ BACC1D661377B8B2007728F4 /* nologin.5 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2761372FAFA0025925C /* nologin.5 */; };
+ BAE5899F137836A00049DD3B /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A7613765D7700003422 /* IOKit.framework */; };
+ BAE589A0137836A00049DD3B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766D13739D27001BB39F /* CoreFoundation.framework */; };
+ BAE589A8137836CA0049DD3B /* nvram.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD27C1372FAFA0025925C /* nvram.c */; };
+ BAE589A9137836D60049DD3B /* nvram.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD27B1372FAFA0025925C /* nvram.8 */; };
+ BAE589B9137838D10049DD3B /* pagesize.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD27F1372FAFA0025925C /* pagesize.1 */; };
+ BAE589D01378FD300049DD3B /* file_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2831372FAFA0025925C /* file_passwd.c */; };
+ BAE589D11378FD340049DD3B /* passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2881372FAFA0025925C /* passwd.c */; };
+ BAE589D21378FD4D0049DD3B /* passwd.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2871372FAFA0025925C /* passwd.1 */; };
+ BAE589D8137900730049DD3B /* nis_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2841372FAFA0025925C /* nis_passwd.c */; };
+ BAE589D9137900770049DD3B /* od_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2851372FAFA0025925C /* od_passwd.c */; };
+ BAE589DA1379007C0049DD3B /* pam_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2861372FAFA0025925C /* pam_passwd.c */; };
+ BAE589E5137903680049DD3B /* pw_scan.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD28C1372FAFA0025925C /* pw_scan.c */; };
+ BAE589E6137903680049DD3B /* pwd_mkdb.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD28F1372FAFA0025925C /* pwd_mkdb.c */; };
+ BAE589E71379037A0049DD3B /* pwd_mkdb.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD28E1372FAFA0025925C /* pwd_mkdb.8 */; };
+ BAE589F2137904B50049DD3B /* kextmanager.defs in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2921372FAFA0025925C /* kextmanager.defs */; };
+ BAE589F3137904B90049DD3B /* reboot.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2941372FAFA0025925C /* reboot.c */; };
+ BAE589F4137904C50049DD3B /* reboot.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2931372FAFA0025925C /* reboot.8 */; };
+ BAE58A1313799F950049DD3B /* db.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2971372FAFA0025925C /* db.c */; };
+ BAE58A1413799F980049DD3B /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2991372FAFA0025925C /* main.c */; };
+ BAE58A1513799F9B0049DD3B /* pdb.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD29B1372FAFA0025925C /* pdb.c */; };
+ BAE58A1613799F9F0049DD3B /* usrdb.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD29D1372FAFA0025925C /* usrdb.c */; };
+ BAE58A1713799FA80049DD3B /* sa.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD29C1372FAFA0025925C /* sa.8 */; };
+ BAE58A271379A0590049DD3B /* sadc.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2A51372FAFA0025925C /* sadc.c */; };
+ BAE58A281379A0670049DD3B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766D13739D27001BB39F /* CoreFoundation.framework */; };
+ BAE58A291379A06B0049DD3B /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A7613765D7700003422 /* IOKit.framework */; };
+ BAE58A2A1379A07E0049DD3B /* sa1.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2A01372FAFA0025925C /* sa1.8 */; };
+ BAE58A2B1379A0820049DD3B /* sa2.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2A21372FAFA0025925C /* sa2.8 */; };
+ BAE58A2C1379A0860049DD3B /* sadc.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2A41372FAFA0025925C /* sadc.8 */; };
+ BAE58A3F137A59140049DD3B /* sar.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2AA1372FAFA0025925C /* sar.c */; };
+ BAE58A40137A59200049DD3B /* sar.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2A91372FAFA0025925C /* sar.1 */; };
+ BAE58A49137D69A60049DD3B /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ 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 */;
+ proxyType = 1;
+ remoteGlobalIDString = BA0A860713968E8500D2272C;
+ remoteInfo = zprint;
+ };
+ BA0A861713968ED500D2272C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA0A860713968E8500D2272C;
+ remoteInfo = zprint;
+ };
+ BA0A86191396B41F00D2272C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA959E7E13968C8E00CA9C60;
+ remoteInfo = zoneinfo;
+ };
+ BA0A861B1396B42600D2272C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA959E7E13968C8E00CA9C60;
+ remoteInfo = zoneinfo;
+ };
+ BA4B79C31373A58B00003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79AC1373A4E500003422;
+ remoteInfo = dirhelper;
+ };
+ BA4B79DA1373A9CE00003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79C51373A72800003422;
+ remoteInfo = dmesg;
+ };
+ BA4B79DC1373A9CE00003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79D41373A97000003422;
+ remoteInfo = dp_notify_lib;
+ };
+ BA4B79F71373B06B00003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79E01373AF7A00003422;
+ remoteInfo = dynamic_pager;
+ };
+ BA4B7A0B1373BA8D00003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79FD1373B9E900003422;
+ remoteInfo = fs_usage;
+ };
+ BA4B7A201373BF5000003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A0E1373BE9D00003422;
+ remoteInfo = getconf;
+ };
+ BA4B7A59137649FA00003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A3F137648E100003422;
+ remoteInfo = getty;
+ };
+ BA4B7A7913765DC100003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A5D13765CC700003422;
+ remoteInfo = hostinfo;
+ };
+ BA4B7A7B13765DC600003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A6913765D3E00003422;
+ remoteInfo = iostat;
+ };
+ BA4B7A971376600200003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A7D13765F3C00003422;
+ remoteInfo = latency;
+ };
+ BA4FD3021372FE730025925C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD2EE1372FB3D0025925C;
+ remoteInfo = ac;
+ };
+ BA4FD3111373001C0025925C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD3041372FFD80025925C;
+ remoteInfo = accton;
+ };
+ BA4FD328137301370025925C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD31A137300ED0025925C;
+ remoteInfo = arch;
+ };
+ BA4FD333137305E80025925C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD31A137300ED0025925C;
+ remoteInfo = arch;
+ };
+ BA4FD336137306260025925C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD32F137305DD0025925C;
+ remoteInfo = machine;
+ };
+ BA4FD34F137307BC0025925C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD3381373073E0025925C;
+ remoteInfo = at;
+ };
+ BA91CE69137F43A500AE5160 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA91CE59137F42ED00AE5160;
+ remoteInfo = shutdown;
+ };
+ BA959E8713968D8A00CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4BE139682BA0018C7BB;
+ remoteInfo = vifs;
+ };
+ BA959E8913968D8A00CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4CA139682F80018C7BB;
+ remoteInfo = vipw;
+ };
+ BA959E8B13968D8A00CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4D7139683580018C7BB;
+ remoteInfo = vm_stat;
+ };
+ BA959E8D13968D8A00CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4E3139683EB0018C7BB;
+ remoteInfo = zdump;
+ };
+ BA959E8F13968D8A00CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4EF139684B40018C7BB;
+ remoteInfo = zic;
+ };
+ BA959E9113968DA900CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4BE139682BA0018C7BB;
+ remoteInfo = vifs;
+ };
+ BA959E9313968DA900CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4CA139682F80018C7BB;
+ remoteInfo = vipw;
+ };
+ BA959E9513968DA900CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4D7139683580018C7BB;
+ remoteInfo = vm_stat;
+ };
+ BA959E9713968DA900CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4E3139683EB0018C7BB;
+ remoteInfo = zdump;
+ };
+ BA959E9913968DA900CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4EF139684B40018C7BB;
+ remoteInfo = zic;
+ };
+ BA9B765313739B89001BB39F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9B763913739ABE001BB39F;
+ remoteInfo = atrun;
+ };
+ BA9B767413739E07001BB39F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9B765513739C20001BB39F;
+ remoteInfo = chkpasswd;
+ };
+ BA9B769F1373A257001BB39F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9B76781373A0D8001BB39F;
+ remoteInfo = chpass;
+ };
+ BA9B76A31373A2A2001BB39F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9B76781373A0D8001BB39F;
+ remoteInfo = chpass;
+ };
+ BA9B76A71373A2CF001BB39F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9B76781373A0D8001BB39F;
+ remoteInfo = chpass;
+ };
+ BA9B76A91373A2CF001BB39F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9B76991373A246001BB39F;
+ remoteInfo = chfn;
+ };
+ BA9B76AB1373A2CF001BB39F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9B76A11373A2A2001BB39F;
+ remoteInfo = chsh;
+ };
+ BA9BF4B2139682710018C7BB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF48A139680CF0018C7BB;
+ remoteInfo = sync;
+ };
+ BA9BF4B4139682710018C7BB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4971396812D0018C7BB;
+ remoteInfo = sysctl;
+ };
+ BA9BF4B6139682710018C7BB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4A5139681910018C7BB;
+ remoteInfo = trace;
+ };
+ BA9BF4B8139682880018C7BB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF48A139680CF0018C7BB;
+ remoteInfo = sync;
+ };
+ BA9BF4BA139682880018C7BB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4971396812D0018C7BB;
+ remoteInfo = sysctl;
+ };
+ BA9BF4BC139682880018C7BB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4A5139681910018C7BB;
+ remoteInfo = trace;
+ };
+ BAAEB3A313730D6B003EA7A9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD3381373073E0025925C;
+ remoteInfo = at;
+ };
+ BAAEB3A713730DFA003EA7A9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD3381373073E0025925C;
+ remoteInfo = at;
+ };
+ BAAEB3AE13730E1C003EA7A9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD3381373073E0025925C;
+ remoteInfo = at;
+ };
+ BAAEB3B313730E43003EA7A9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAAEB39C13730D5C003EA7A9;
+ remoteInfo = atq;
+ };
+ BAAEB3B513730E43003EA7A9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAAEB3A513730DFA003EA7A9;
+ remoteInfo = atrm;
+ };
+ BAAEB3B713730E43003EA7A9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAAEB3AC13730E1C003EA7A9;
+ remoteInfo = batch;
+ };
+ BACC1CFF1377B3A4007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA473DA01377B2230005CC19;
+ remoteInfo = login;
+ };
+ BACC1D1B1377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD2EE1372FB3D0025925C;
+ remoteInfo = ac;
+ };
+ BACC1D1D1377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD3041372FFD80025925C;
+ remoteInfo = accton;
+ };
+ BACC1D1F1377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD31A137300ED0025925C;
+ remoteInfo = arch;
+ };
+ BACC1D211377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD32F137305DD0025925C;
+ remoteInfo = machine;
+ };
+ BACC1D231377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79C51373A72800003422;
+ remoteInfo = dmesg;
+ };
+ BACC1D251377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79D41373A97000003422;
+ remoteInfo = dp_notify_lib;
+ };
+ BACC1D271377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79E01373AF7A00003422;
+ remoteInfo = dynamic_pager;
+ };
+ BACC1D291377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79FD1373B9E900003422;
+ remoteInfo = fs_usage;
+ };
+ BACC1D2B1377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A0E1373BE9D00003422;
+ remoteInfo = getconf;
+ };
+ BACC1D2D1377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A3F137648E100003422;
+ remoteInfo = getty;
+ };
+ BACC1D2F1377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A5D13765CC700003422;
+ remoteInfo = hostinfo;
+ };
+ BACC1D311377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A6913765D3E00003422;
+ remoteInfo = iostat;
+ };
+ BACC1D331377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A7D13765F3C00003422;
+ remoteInfo = latency;
+ };
+ BACC1D351377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA473DA01377B2230005CC19;
+ remoteInfo = login;
+ };
+ BACC1D371377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D011377B3E6007728F4;
+ remoteInfo = makekey;
+ };
+ BACC1D391377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D0D1377B481007728F4;
+ remoteInfo = mean;
+ };
+ BACC1D3B1377B5D9007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D011377B3E6007728F4;
+ remoteInfo = makekey;
+ };
+ BACC1D671377B8DC007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D3D1377B6E2007728F4;
+ remoteInfo = mkfile;
+ };
+ BACC1D691377B8DC007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D491377B7A7007728F4;
+ remoteInfo = newgrp;
+ };
+ BACC1D6B1377B8DC007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D591377B85C007728F4;
+ remoteInfo = nologin;
+ };
+ BACC1D6D1377B8ED007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D3D1377B6E2007728F4;
+ remoteInfo = mkfile;
+ };
+ BACC1D6F1377B8ED007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D491377B7A7007728F4;
+ remoteInfo = newgrp;
+ };
+ BACC1D711377B8ED007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D591377B85C007728F4;
+ remoteInfo = nologin;
+ };
+ BAE589B0137837AA0049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE5899B137836A00049DD3B;
+ remoteInfo = nvram;
+ };
+ BAE589B2137837AA0049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589AA137837130049DD3B;
+ remoteInfo = pagesize;
+ };
+ BAE589B4137837B30049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE5899B137836A00049DD3B;
+ remoteInfo = nvram;
+ };
+ BAE589B6137837B30049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589AA137837130049DD3B;
+ remoteInfo = pagesize;
+ };
+ BAE589D31378FDF40049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589BA1378FCAA0049DD3B;
+ remoteInfo = passwd;
+ };
+ BAE589D51378FDFB0049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589BA1378FCAA0049DD3B;
+ remoteInfo = passwd;
+ };
+ BAE589FB137905080049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589E81379044E0049DD3B;
+ remoteInfo = reboot;
+ };
+ BAE589FD137905740049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589DB137902F50049DD3B;
+ remoteInfo = pwd_mkdb;
+ };
+ BAE589FF137905740049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589E81379044E0049DD3B;
+ remoteInfo = reboot;
+ };
+ BAE58A01137905740049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589F5137904DF0049DD3B;
+ remoteInfo = halt;
+ };
+ BAE58A031379057F0049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589DB137902F50049DD3B;
+ remoteInfo = pwd_mkdb;
+ };
+ BAE58A051379057F0049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589E81379044E0049DD3B;
+ remoteInfo = reboot;
+ };
+ BAE58A071379057F0049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589F5137904DF0049DD3B;
+ remoteInfo = halt;
+ };
+ BAE58A2D1379A1260049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE58A0913799F610049DD3B;
+ remoteInfo = sa;
+ };
+ BAE58A2F1379A1260049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE58A1813799FFA0049DD3B;
+ remoteInfo = sadc;
+ };
+ BAE58A311379A1300049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE58A0913799F610049DD3B;
+ remoteInfo = sa;
+ };
+ BAE58A331379A1300049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE58A1813799FFA0049DD3B;
+ remoteInfo = sadc;
+ };
+ BAE58A41137A59300049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE58A351379A3F60049DD3B;
+ remoteInfo = sar;
+ };
+ BAE58A43137A59390049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE58A351379A3F60049DD3B;
+ remoteInfo = sar;
+ };
+ BAE58A53137D69FB0049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE58A45137D69A60049DD3B;
+ remoteInfo = sc_usage;
+ };
+ BAE58A55137D6A050049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ 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 */
+ 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 = (
+ B3C10B9416E9876F006896A0 /* memory_pressure.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA0A860C13968E8500D2272C /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA0A861413968EB100D2272C /* zprint.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA28FB881396DA67004986CB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /;
+ dstSubfolderSpec = 0;
+ files = (
+ BA28FB891396DA8A004986CB /* private in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA473DAE1377B2230005CC19 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BACC1CFB1377B2A8007728F4 /* login.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B79B41373A4E500003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B79C11373A55000003422 /* dirhelper.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B79B61373A4E500003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /System/Library/LaunchDaemons;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B79C21373A55600003422 /* com.apple.bsd.dirhelper.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B79C91373A72800003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B79CF1373A74B00003422 /* dmesg.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B79E61373AF7A00003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B79F51373B03300003422 /* dynamic_pager.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B79E81373AF7A00003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /System/Library/LaunchDaemons;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B79FC1373B82C00003422 /* com.apple.dynamic_pager.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A011373B9E900003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A071373BA1F00003422 /* fs_usage.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A121373BE9D00003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A1E1373BEEB00003422 /* getconf.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A48137648E100003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A551376495900003422 /* getty.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A4B137648E100003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /System/Library/LaunchDaemons;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A5C13764F2E00003422 /* com.apple.getty.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A561376496100003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man5;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A571376498C00003422 /* gettytab.5 in CopyFiles */,
+ BA4B7A581376499000003422 /* ttys.5 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A6113765CC700003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A6813765D0000003422 /* hostinfo.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A6D13765D3E00003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A7513765D6B00003422 /* iostat.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A8B13765F3C00003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A9513765FA100003422 /* latency.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4FD2ED1372FB3D0025925C /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4FD2FD1372FD710025925C /* ac.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4FD3081372FFD80025925C /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4FD30F137300040025925C /* accton.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4FD31E137300ED0025925C /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4FD3261373012C0025925C /* arch.1 in CopyFiles */,
+ BA4FD3271373012F0025925C /* machine.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4FD33C1373073E0025925C /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4FD343137307580025925C /* at.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA91CE5E137F42ED00AE5160 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA91CE68137F438700AE5160 /* shutdown.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9B764713739ABE001BB39F /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9B765013739B52001BB39F /* atrun.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9B765113739B6A001BB39F /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /System/Library/LaunchDaemons;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9B765213739B7D001BB39F /* com.apple.atrun.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9B765D13739C20001BB39F /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9B766C13739C84001BB39F /* chkpasswd.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9B76871373A0D8001BB39F /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9B76981373A1A7001BB39F /* chpass.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF48E139680CF0018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF495139681050018C7BB /* sync.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF49B1396812D0018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4A4139681710018C7BB /* sysctl.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF4A21396815B0018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man5;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4A31396816D0018C7BB /* sysctl.conf.5 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF4AA139681910018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4B0139682430018C7BB /* trace.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF4C2139682BA0018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4C9139682E70018C7BB /* vifs.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF4CE139682F80018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4D4139683140018C7BB /* vipw.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF4DB139683580018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4E1139683890018C7BB /* vm_stat.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF4E7139683EB0018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4ED1396840C0018C7BB /* zdump.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF4F3139684B40018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4F9139684CF0018C7BB /* zic.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BACC1CFC1377B2BD007728F4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /private/etc/pam.d;
+ dstSubfolderSpec = 0;
+ files = (
+ BACC1CFE1377B2D8007728F4 /* login.term in CopyFiles */,
+ BA91CE58137D6CB800AE5160 /* login in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BACC1D051377B3E6007728F4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BACC1D0C1377B41B007728F4 /* makekey.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BACC1D411377B6E2007728F4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BACC1D481377B723007728F4 /* mkfile.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BACC1D4E1377B7A7007728F4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BACC1D581377B82A007728F4 /* newgrp.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BACC1D5D1377B85C007728F4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BACC1D641377B894007728F4 /* nologin.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BACC1D651377B89A007728F4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man5;
+ dstSubfolderSpec = 0;
+ files = (
+ BACC1D661377B8B2007728F4 /* nologin.5 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE589A1137836A00049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE589A9137836D60049DD3B /* nvram.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE589B8137838C10049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE589B9137838D10049DD3B /* pagesize.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE589C91378FCAA0049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE589D21378FD4D0049DD3B /* passwd.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE589DF137902F50049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE589E71379037A0049DD3B /* pwd_mkdb.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE589EC1379044E0049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE589F4137904C50049DD3B /* reboot.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE58A0D13799F610049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE58A1713799FA80049DD3B /* sa.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE58A2013799FFA0049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE58A2A1379A07E0049DD3B /* sa1.8 in CopyFiles */,
+ BAE58A2B1379A0820049DD3B /* sa2.8 in CopyFiles */,
+ BAE58A2C1379A0860049DD3B /* sadc.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE58A391379A3F60049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE58A40137A59200049DD3B /* sar.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE58A4A137D69A60049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE58A52137D69ED0049DD3B /* sc_usage.1 in CopyFiles */,
+ );
+ 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; 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; };
+ BA4B79D51373A97000003422 /* libdp_notify_lib.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdp_notify_lib.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B79EC1373AF7A00003422 /* dynamic_pager */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dynamic_pager; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B79F31373B01B00003422 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = "<absolute>"; };
+ BA4B79FA1373B7C300003422 /* com.apple.dynamic_pager.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = com.apple.dynamic_pager.plist; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A051373B9E900003422 /* fs_usage */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fs_usage; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A091373BA4600003422 /* libutil.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libutil.dylib; path = /usr/lib/libutil.dylib; sourceTree = "<absolute>"; };
+ BA4B7A161373BE9D00003422 /* getconf */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = getconf; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A241373C30100003422 /* confstr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = confstr.c; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A251373C30100003422 /* limits.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = limits.c; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A261373C30100003422 /* pathconf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pathconf.c; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A271373C30100003422 /* progenv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = progenv.c; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A281373C30100003422 /* sysconf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sysconf.c; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A4F137648E100003422 /* getty */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = getty; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A5B13764F1400003422 /* com.apple.getty.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = com.apple.getty.plist; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A6513765CC700003422 /* hostinfo */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = hostinfo; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A7113765D3E00003422 /* iostat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = iostat; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A7613765D7700003422 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
+ BA4B7A9013765F3C00003422 /* latency */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = latency; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A9313765F8B00003422 /* libncurses.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libncurses.dylib; path = /usr/lib/libncurses.dylib; sourceTree = "<absolute>"; };
+ BA4FD1DB1372FAFA0025925C /* ac.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = ac.8; sourceTree = "<group>"; };
+ BA4FD1DC1372FAFA0025925C /* ac.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ac.c; sourceTree = "<group>"; };
+ BA4FD1DF1372FAFA0025925C /* accton.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = accton.8; sourceTree = "<group>"; };
+ BA4FD1E01372FAFA0025925C /* accton.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = accton.c; sourceTree = "<group>"; };
+ 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>"; };
+ 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>"; };
+ BA4FD1EC1372FAFA0025925C /* at.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = at.c; sourceTree = "<group>"; };
+ BA4FD1ED1372FAFA0025925C /* at.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = at.h; sourceTree = "<group>"; };
+ BA4FD1EE1372FAFA0025925C /* panic.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = panic.c; sourceTree = "<group>"; };
+ BA4FD1EF1372FAFA0025925C /* panic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = panic.h; sourceTree = "<group>"; };
+ BA4FD1F01372FAFA0025925C /* parsetime.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = parsetime.c; sourceTree = "<group>"; };
+ BA4FD1F11372FAFA0025925C /* parsetime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = parsetime.h; sourceTree = "<group>"; };
+ BA4FD1F21372FAFA0025925C /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ BA4FD1F31372FAFA0025925C /* perm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = perm.c; sourceTree = "<group>"; };
+ BA4FD1F41372FAFA0025925C /* perm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = perm.h; sourceTree = "<group>"; };
+ BA4FD1F51372FAFA0025925C /* privs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = privs.h; sourceTree = "<group>"; };
+ BA4FD1F81372FAFA0025925C /* atrun.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = atrun.8; sourceTree = "<group>"; };
+ BA4FD1F91372FAFA0025925C /* atrun.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = atrun.c; sourceTree = "<group>"; };
+ BA4FD1FA1372FAFA0025925C /* atrun.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = atrun.h; sourceTree = "<group>"; };
+ BA4FD1FC1372FAFA0025925C /* com.apple.atrun.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.atrun.plist; sourceTree = "<group>"; };
+ BA4FD1FD1372FAFA0025925C /* gloadavg.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = gloadavg.c; sourceTree = "<group>"; };
+ BA4FD1FE1372FAFA0025925C /* gloadavg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = gloadavg.h; sourceTree = "<group>"; };
+ BA4FD2011372FAFA0025925C /* chkpasswd.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = chkpasswd.8; sourceTree = "<group>"; };
+ BA4FD2021372FAFA0025925C /* chkpasswd.pam */ = {isa = PBXFileReference; lastKnownFileType = text; path = chkpasswd.pam; sourceTree = "<group>"; };
+ BA4FD2031372FAFA0025925C /* file_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = file_passwd.c; sourceTree = "<group>"; };
+ BA4FD2041372FAFA0025925C /* nis_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nis_passwd.c; sourceTree = "<group>"; };
+ BA4FD2051372FAFA0025925C /* od_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = od_passwd.c; sourceTree = "<group>"; };
+ BA4FD2061372FAFA0025925C /* pam_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pam_passwd.c; sourceTree = "<group>"; };
+ BA4FD2071372FAFA0025925C /* passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = passwd.c; sourceTree = "<group>"; };
+ BA4FD2081372FAFA0025925C /* stringops.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = stringops.c; sourceTree = "<group>"; };
+ BA4FD2091372FAFA0025925C /* stringops.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = stringops.h; sourceTree = "<group>"; };
+ BA4FD20B1372FAFA0025925C /* IMPORT_NOTES */ = {isa = PBXFileReference; lastKnownFileType = text; path = IMPORT_NOTES; sourceTree = "<group>"; };
+ BA4FD20D1372FAFA0025925C /* chpass.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = chpass.1; sourceTree = "<group>"; };
+ BA4FD20E1372FAFA0025925C /* chpass.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = chpass.c; sourceTree = "<group>"; };
+ BA4FD20F1372FAFA0025925C /* chpass.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = chpass.h; sourceTree = "<group>"; };
+ BA4FD2101372FAFA0025925C /* edit.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = edit.c; sourceTree = "<group>"; };
+ BA4FD2111372FAFA0025925C /* field.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = field.c; sourceTree = "<group>"; };
+ BA4FD2121372FAFA0025925C /* open_directory.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = open_directory.c; sourceTree = "<group>"; };
+ BA4FD2131372FAFA0025925C /* open_directory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = open_directory.h; sourceTree = "<group>"; };
+ BA4FD2141372FAFA0025925C /* pw_copy.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pw_copy.c; sourceTree = "<group>"; };
+ BA4FD2151372FAFA0025925C /* pw_copy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pw_copy.h; sourceTree = "<group>"; };
+ BA4FD2161372FAFA0025925C /* table.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = table.c; sourceTree = "<group>"; };
+ BA4FD2171372FAFA0025925C /* util.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = "<group>"; };
+ BA4FD21A1372FAFA0025925C /* client.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = client.c; sourceTree = "<group>"; };
+ BA4FD21B1372FAFA0025925C /* com.apple.bsd.dirhelper.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.bsd.dirhelper.plist; sourceTree = "<group>"; };
+ BA4FD21C1372FAFA0025925C /* dirhelper.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = dirhelper.8; sourceTree = "<group>"; };
+ BA4FD21D1372FAFA0025925C /* dirhelper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dirhelper.c; sourceTree = "<group>"; };
+ BA4FD2201372FAFA0025925C /* dmesg.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = dmesg.8; sourceTree = "<group>"; };
+ BA4FD2211372FAFA0025925C /* dmesg.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dmesg.c; sourceTree = "<group>"; };
+ BA4FD2281372FAFA0025925C /* backing_store_alerts.defs */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.mig; path = backing_store_alerts.defs; sourceTree = "<group>"; };
+ BA4FD2291372FAFA0025925C /* backing_store_triggers.defs */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.mig; path = backing_store_triggers.defs; sourceTree = "<group>"; };
+ BA4FD22A1372FAFA0025925C /* com.apple.dynamic_pager.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.dynamic_pager.plist; sourceTree = "<group>"; };
+ BA4FD22B1372FAFA0025925C /* default_pager_alerts.defs */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.mig; path = default_pager_alerts.defs; sourceTree = "<group>"; };
+ BA4FD22C1372FAFA0025925C /* dynamic_pager.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = dynamic_pager.8; sourceTree = "<group>"; };
+ BA4FD22D1372FAFA0025925C /* dynamic_pager.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dynamic_pager.c; sourceTree = "<group>"; };
+ BA4FD2301372FAFA0025925C /* fs_usage.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = fs_usage.1; sourceTree = "<group>"; };
+ BA4FD2311372FAFA0025925C /* fs_usage.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = fs_usage.c; sourceTree = "<group>"; };
+ BA4FD2351372FAFA0025925C /* confstr.gperf */ = {isa = PBXFileReference; lastKnownFileType = text; path = confstr.gperf; sourceTree = "<group>"; };
+ BA4FD2361372FAFA0025925C /* fake-gperf.awk */ = {isa = PBXFileReference; lastKnownFileType = text; path = "fake-gperf.awk"; sourceTree = "<group>"; };
+ BA4FD2371372FAFA0025925C /* getconf.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = getconf.1; sourceTree = "<group>"; };
+ BA4FD2381372FAFA0025925C /* getconf.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = getconf.c; sourceTree = "<group>"; };
+ BA4FD2391372FAFA0025925C /* getconf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = getconf.h; sourceTree = "<group>"; };
+ BA4FD23A1372FAFA0025925C /* limits.gperf */ = {isa = PBXFileReference; lastKnownFileType = text; path = limits.gperf; sourceTree = "<group>"; };
+ BA4FD23B1372FAFA0025925C /* pathconf.gperf */ = {isa = PBXFileReference; lastKnownFileType = text; path = pathconf.gperf; sourceTree = "<group>"; };
+ BA4FD23C1372FAFA0025925C /* progenv.gperf */ = {isa = PBXFileReference; lastKnownFileType = text; path = progenv.gperf; sourceTree = "<group>"; };
+ BA4FD23D1372FAFA0025925C /* sysconf.gperf */ = {isa = PBXFileReference; lastKnownFileType = text; path = sysconf.gperf; sourceTree = "<group>"; };
+ BA4FD2401372FAFA0025925C /* chat.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = chat.c; sourceTree = "<group>"; };
+ BA4FD2411372FAFA0025925C /* com.apple.getty.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.getty.plist; sourceTree = "<group>"; };
+ BA4FD2421372FAFA0025925C /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ BA4FD2431372FAFA0025925C /* getty.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = getty.8; sourceTree = "<group>"; };
+ BA4FD2441372FAFA0025925C /* gettytab.5 */ = {isa = PBXFileReference; lastKnownFileType = text; path = gettytab.5; sourceTree = "<group>"; };
+ BA4FD2451372FAFA0025925C /* gettytab.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = gettytab.h; sourceTree = "<group>"; };
+ BA4FD2461372FAFA0025925C /* init.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = init.c; sourceTree = "<group>"; };
+ BA4FD2471372FAFA0025925C /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+ BA4FD2481372FAFA0025925C /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ BA4FD2491372FAFA0025925C /* subr.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = subr.c; sourceTree = "<group>"; };
+ BA4FD24A1372FAFA0025925C /* ttys.5 */ = {isa = PBXFileReference; lastKnownFileType = text; path = ttys.5; sourceTree = "<group>"; };
+ BA4FD24D1372FAFA0025925C /* hostinfo.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = hostinfo.8; sourceTree = "<group>"; };
+ BA4FD24E1372FAFA0025925C /* hostinfo.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hostinfo.c; sourceTree = "<group>"; };
+ BA4FD2521372FAFA0025925C /* iostat.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = iostat.8; sourceTree = "<group>"; };
+ BA4FD2531372FAFA0025925C /* iostat.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = iostat.c; sourceTree = "<group>"; };
+ BA4FD2571372FAFA0025925C /* latency.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = latency.1; sourceTree = "<group>"; };
+ BA4FD2581372FAFA0025925C /* latency.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = latency.c; sourceTree = "<group>"; };
+ BA4FD25B1372FAFA0025925C /* klogin.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = klogin.c; sourceTree = "<group>"; };
+ BA4FD25C1372FAFA0025925C /* login.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = login.1; sourceTree = "<group>"; };
+ BA4FD25D1372FAFA0025925C /* login.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = login.c; sourceTree = "<group>"; };
+ BA4FD25E1372FAFA0025925C /* login.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = login.h; sourceTree = "<group>"; };
+ BA4FD25F1372FAFA0025925C /* login_audit.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = login_audit.c; sourceTree = "<group>"; };
+ BA4FD2611372FAFA0025925C /* login */ = {isa = PBXFileReference; lastKnownFileType = text; path = login; sourceTree = "<group>"; };
+ BA4FD2621372FAFA0025925C /* login.term */ = {isa = PBXFileReference; lastKnownFileType = text; path = login.term; sourceTree = "<group>"; };
+ BA4FD2631372FAFA0025925C /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ BA4FD2671372FAFA0025925C /* makekey.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = makekey.8; sourceTree = "<group>"; };
+ BA4FD2681372FAFA0025925C /* makekey.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = makekey.c; sourceTree = "<group>"; };
+ BA4FD26B1372FAFA0025925C /* mean.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mean.c; sourceTree = "<group>"; };
+ BA4FD26E1372FAFA0025925C /* mkfile.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = mkfile.8; sourceTree = "<group>"; };
+ BA4FD26F1372FAFA0025925C /* mkfile.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mkfile.c; sourceTree = "<group>"; };
+ BA4FD2721372FAFA0025925C /* newgrp.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = newgrp.1; sourceTree = "<group>"; };
+ BA4FD2731372FAFA0025925C /* newgrp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = newgrp.c; sourceTree = "<group>"; };
+ BA4FD2761372FAFA0025925C /* nologin.5 */ = {isa = PBXFileReference; lastKnownFileType = text; path = nologin.5; sourceTree = "<group>"; };
+ BA4FD2771372FAFA0025925C /* nologin.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = nologin.8; sourceTree = "<group>"; };
+ BA4FD2781372FAFA0025925C /* nologin.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nologin.c; sourceTree = "<group>"; };
+ BA4FD27B1372FAFA0025925C /* nvram.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = nvram.8; sourceTree = "<group>"; };
+ BA4FD27C1372FAFA0025925C /* nvram.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nvram.c; sourceTree = "<group>"; };
+ BA4FD27F1372FAFA0025925C /* pagesize.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = pagesize.1; sourceTree = "<group>"; };
+ BA4FD2801372FAFA0025925C /* pagesize.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = pagesize.sh; sourceTree = "<group>"; };
+ BA4FD2831372FAFA0025925C /* file_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = file_passwd.c; sourceTree = "<group>"; };
+ BA4FD2841372FAFA0025925C /* nis_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nis_passwd.c; sourceTree = "<group>"; };
+ BA4FD2851372FAFA0025925C /* od_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = od_passwd.c; sourceTree = "<group>"; };
+ BA4FD2861372FAFA0025925C /* pam_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pam_passwd.c; sourceTree = "<group>"; };
+ BA4FD2871372FAFA0025925C /* passwd.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = passwd.1; sourceTree = "<group>"; };
+ BA4FD2881372FAFA0025925C /* passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = passwd.c; sourceTree = "<group>"; };
+ BA4FD2891372FAFA0025925C /* passwd.pam */ = {isa = PBXFileReference; lastKnownFileType = text; path = passwd.pam; sourceTree = "<group>"; };
+ BA4FD28C1372FAFA0025925C /* pw_scan.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pw_scan.c; sourceTree = "<group>"; };
+ BA4FD28D1372FAFA0025925C /* pw_scan.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pw_scan.h; sourceTree = "<group>"; };
+ BA4FD28E1372FAFA0025925C /* pwd_mkdb.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = pwd_mkdb.8; sourceTree = "<group>"; };
+ BA4FD28F1372FAFA0025925C /* pwd_mkdb.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pwd_mkdb.c; sourceTree = "<group>"; };
+ BA4FD2921372FAFA0025925C /* kextmanager.defs */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.mig; path = kextmanager.defs; sourceTree = "<group>"; };
+ BA4FD2931372FAFA0025925C /* reboot.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = reboot.8; sourceTree = "<group>"; };
+ BA4FD2941372FAFA0025925C /* reboot.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = reboot.c; sourceTree = "<group>"; };
+ BA4FD2971372FAFA0025925C /* db.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = db.c; sourceTree = "<group>"; };
+ BA4FD2981372FAFA0025925C /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ BA4FD2991372FAFA0025925C /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+ BA4FD29A1372FAFA0025925C /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ BA4FD29B1372FAFA0025925C /* pdb.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pdb.c; sourceTree = "<group>"; };
+ BA4FD29C1372FAFA0025925C /* sa.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = sa.8; sourceTree = "<group>"; };
+ BA4FD29D1372FAFA0025925C /* usrdb.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = usrdb.c; sourceTree = "<group>"; };
+ BA4FD2A01372FAFA0025925C /* sa1.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = sa1.8; sourceTree = "<group>"; };
+ BA4FD2A11372FAFA0025925C /* sa1.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = sa1.sh; sourceTree = "<group>"; };
+ BA4FD2A21372FAFA0025925C /* sa2.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = sa2.8; sourceTree = "<group>"; };
+ BA4FD2A31372FAFA0025925C /* sa2.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = sa2.sh; sourceTree = "<group>"; };
+ BA4FD2A41372FAFA0025925C /* sadc.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = sadc.8; sourceTree = "<group>"; };
+ BA4FD2A51372FAFA0025925C /* sadc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sadc.c; sourceTree = "<group>"; };
+ BA4FD2A61372FAFA0025925C /* sadc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sadc.h; sourceTree = "<group>"; };
+ BA4FD2A91372FAFA0025925C /* sar.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = sar.1; sourceTree = "<group>"; };
+ BA4FD2AA1372FAFA0025925C /* sar.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sar.c; sourceTree = "<group>"; };
+ BA4FD2AB1372FAFA0025925C /* sar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sar.h; sourceTree = "<group>"; };
+ BA4FD2AE1372FAFA0025925C /* sc_usage.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = sc_usage.1; sourceTree = "<group>"; };
+ BA4FD2AF1372FAFA0025925C /* sc_usage.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sc_usage.c; sourceTree = "<group>"; };
+ BA4FD2B21372FAFA0025925C /* kextmanager.defs */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.mig; path = kextmanager.defs; sourceTree = "<group>"; };
+ BA4FD2B31372FAFA0025925C /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ BA4FD2B41372FAFA0025925C /* shutdown.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = shutdown.8; sourceTree = "<group>"; };
+ BA4FD2B51372FAFA0025925C /* shutdown.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = shutdown.c; sourceTree = "<group>"; };
+ BA4FD2B81372FAFA0025925C /* sync.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = sync.8; sourceTree = "<group>"; };
+ BA4FD2B91372FAFA0025925C /* sync.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sync.c; sourceTree = "<group>"; };
+ BA4FD2BC1372FAFA0025925C /* sysctl.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = sysctl.8; sourceTree = "<group>"; };
+ BA4FD2BD1372FAFA0025925C /* sysctl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sysctl.c; sourceTree = "<group>"; };
+ BA4FD2BE1372FAFA0025925C /* sysctl.conf.5 */ = {isa = PBXFileReference; lastKnownFileType = text; path = sysctl.conf.5; sourceTree = "<group>"; };
+ BA4FD2C11372FAFA0025925C /* trace.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = trace.1; sourceTree = "<group>"; };
+ BA4FD2C21372FAFA0025925C /* trace.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = trace.c; sourceTree = "<group>"; };
+ BA4FD2C51372FAFA0025925C /* vifs.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = vifs.8; sourceTree = "<group>"; };
+ BA4FD2C61372FAFA0025925C /* vifs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vifs.c; sourceTree = "<group>"; };
+ BA4FD2C91372FAFA0025925C /* pw_util.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pw_util.c; sourceTree = "<group>"; };
+ BA4FD2CA1372FAFA0025925C /* pw_util.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pw_util.h; sourceTree = "<group>"; };
+ BA4FD2CB1372FAFA0025925C /* vipw.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = vipw.8; sourceTree = "<group>"; };
+ BA4FD2CC1372FAFA0025925C /* vipw.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vipw.c; sourceTree = "<group>"; };
+ BA4FD2CF1372FAFA0025925C /* vm_stat.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = vm_stat.1; sourceTree = "<group>"; };
+ BA4FD2D01372FAFA0025925C /* vm_stat.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vm_stat.c; sourceTree = "<group>"; };
+ BA4FD2D31372FAFA0025925C /* zdump.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = zdump.8; sourceTree = "<group>"; };
+ BA4FD2D41372FAFA0025925C /* zdump.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zdump.c; sourceTree = "<group>"; };
+ BA4FD2D61372FAFA0025925C /* Arts.htm */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = Arts.htm; sourceTree = "<group>"; };
+ BA4FD2D81372FAFA0025925C /* Makefile.zoneinfo.dist */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.zoneinfo.dist; sourceTree = "<group>"; };
+ BA4FD2D91372FAFA0025925C /* README */ = {isa = PBXFileReference; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+ BA4FD2DA1372FAFA0025925C /* Theory */ = {isa = PBXFileReference; lastKnownFileType = text; path = Theory; sourceTree = "<group>"; };
+ BA4FD2DB1372FAFA0025925C /* ZIC_HACK */ = {isa = PBXFileReference; lastKnownFileType = text; path = ZIC_HACK; sourceTree = "<group>"; };
+ BA4FD2DC1372FAFA0025925C /* ialloc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ialloc.c; sourceTree = "<group>"; };
+ BA4FD2DD1372FAFA0025925C /* private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = private.h; sourceTree = "<group>"; };
+ BA4FD2DE1372FAFA0025925C /* scheck.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = scheck.c; sourceTree = "<group>"; };
+ BA4FD2DF1372FAFA0025925C /* tz-art.htm */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "tz-art.htm"; sourceTree = "<group>"; };
+ BA4FD2E01372FAFA0025925C /* tz-link.htm */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "tz-link.htm"; sourceTree = "<group>"; };
+ BA4FD2E11372FAFA0025925C /* zic.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = zic.8; sourceTree = "<group>"; };
+ BA4FD2E21372FAFA0025925C /* zic.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zic.c; sourceTree = "<group>"; };
+ BA4FD2E51372FAFA0025925C /* zprint.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = zprint.1; sourceTree = "<group>"; };
+ BA4FD2E61372FAFA0025925C /* zprint.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zprint.c; sourceTree = "<group>"; };
+ BA4FD2EF1372FB3D0025925C /* ac */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ac; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4FD2FB1372FB710025925C /* BSD.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = BSD.xcconfig; path = Makefiles/CoreOS/Xcode/BSD.xcconfig; sourceTree = DEVELOPER_DIR; };
+ BA4FD30D1372FFD80025925C /* accton */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = accton; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4FD323137300EE0025925C /* arch */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = arch; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4FD3411373073E0025925C /* at */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = at; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA91CE62137F42ED00AE5160 /* shutdown */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = shutdown; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA959E8413968CF900CA9C60 /* generate_zoneinfo.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = generate_zoneinfo.sh; sourceTree = "<group>"; };
+ BA9B764C13739ABE001BB39F /* atrun */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = atrun; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9B766313739C20001BB39F /* chkpasswd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = chkpasswd; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9B766D13739D27001BB39F /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
+ BA9B766E13739D27001BB39F /* OpenDirectory.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenDirectory.framework; path = /System/Library/Frameworks/OpenDirectory.framework; sourceTree = "<absolute>"; };
+ BA9B767113739D36001BB39F /* libpam.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpam.dylib; path = /usr/lib/libpam.dylib; sourceTree = "<absolute>"; };
+ BA9B767613739E9E001BB39F /* chkpasswd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chkpasswd.h; sourceTree = "<group>"; };
+ BA9B768C1373A0D8001BB39F /* chpass */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = chpass; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF492139680CF0018C7BB /* sync */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sync; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF49F1396812D0018C7BB /* sysctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sysctl; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF4AE139681910018C7BB /* trace */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = trace; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF4C6139682BA0018C7BB /* vifs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = vifs; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF4D2139682F80018C7BB /* vipw */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = vipw; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF4DF139683580018C7BB /* vm_stat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = vm_stat; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF4EB139683EB0018C7BB /* zdump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = zdump; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF4F7139684B40018C7BB /* zic */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = zic; sourceTree = BUILT_PRODUCTS_DIR; };
+ BACC1D091377B3E6007728F4 /* makekey */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = makekey; sourceTree = BUILT_PRODUCTS_DIR; };
+ BACC1D151377B481007728F4 /* mean */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mean; sourceTree = BUILT_PRODUCTS_DIR; };
+ BACC1D451377B6E2007728F4 /* mkfile */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mkfile; sourceTree = BUILT_PRODUCTS_DIR; };
+ BACC1D551377B7A7007728F4 /* newgrp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = newgrp; sourceTree = BUILT_PRODUCTS_DIR; };
+ BACC1D611377B85C007728F4 /* nologin */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = nologin; sourceTree = BUILT_PRODUCTS_DIR; };
+ BAE589A5137836A00049DD3B /* nvram */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = nvram; sourceTree = BUILT_PRODUCTS_DIR; };
+ BAE589CE1378FCAA0049DD3B /* passwd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = passwd; sourceTree = BUILT_PRODUCTS_DIR; };
+ BAE589D71378FE8D0049DD3B /* passwd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = passwd.h; sourceTree = "<group>"; };
+ BAE589E3137902F50049DD3B /* pwd_mkdb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pwd_mkdb; sourceTree = BUILT_PRODUCTS_DIR; };
+ BAE589F01379044E0049DD3B /* reboot */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = reboot; sourceTree = BUILT_PRODUCTS_DIR; };
+ BAE58A1113799F610049DD3B /* sa */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sa; sourceTree = BUILT_PRODUCTS_DIR; };
+ 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;
+ files = (
+ BA0A860B13968E8500D2272C /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA473DAD1377B2230005CC19 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B79B31373A4E500003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B79C01373A53700003422 /* libbsm.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B79C81373A72800003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B79D21373A97000003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B79E41373AF7A00003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B79F41373B01C00003422 /* SystemConfiguration.framework in Frameworks */,
+ BA4B79F21373B01100003422 /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A001373B9E900003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A0A1373BA4600003422 /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A111373BE9D00003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A45137648E100003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A6013765CC700003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A6C13765D3E00003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A7713765D7700003422 /* IOKit.framework in Frameworks */,
+ BA4B7A7813765DB100003422 /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A8A13765F3C00003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A9413765F8C00003422 /* libncurses.dylib in Frameworks */,
+ BA4B7A9613765FE700003422 /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD2EC1372FB3D0025925C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD3071372FFD80025925C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD31D137300ED0025925C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C65BF57A144BD7C5009028A3 /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD33B1373073E0025925C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA91CE5D137F42ED00AE5160 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA91CE67137F434200AE5160 /* libbsm.dylib in Frameworks */,
+ BA91CE66137F433200AE5160 /* IOKit.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B764613739ABE001BB39F /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B765C13739C20001BB39F /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B767213739D36001BB39F /* libpam.dylib in Frameworks */,
+ BA9B766F13739D27001BB39F /* CoreFoundation.framework in Frameworks */,
+ BA9B767013739D27001BB39F /* OpenDirectory.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B76831373A0D8001BB39F /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B76851373A0D8001BB39F /* CoreFoundation.framework in Frameworks */,
+ BA9B76861373A0D8001BB39F /* OpenDirectory.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF48D139680CF0018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF49A1396812D0018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4A8139681910018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4A9139681910018C7BB /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4C1139682BA0018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4CD139682F80018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4DA139683580018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4E6139683EB0018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4F2139684B40018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D041377B3E6007728F4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D101377B481007728F4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D401377B6E2007728F4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D4D1377B7A7007728F4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D5C1377B85C007728F4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE5899E137836A00049DD3B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE5899F137836A00049DD3B /* IOKit.framework in Frameworks */,
+ BAE589A0137836A00049DD3B /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE589C51378FCAA0049DD3B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE589DE137902F50049DD3B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE589EB1379044E0049DD3B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE58A0C13799F610049DD3B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE58A1F13799FFA0049DD3B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE58A281379A0670049DD3B /* CoreFoundation.framework in Frameworks */,
+ BAE58A291379A06B0049DD3B /* IOKit.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE58A381379A3F60049DD3B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE58A48137D69A60049DD3B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE58A49137D69A60049DD3B /* libutil.dylib in Frameworks */,
+ BAE58A51137D69E30049DD3B /* libncurses.dylib in Frameworks */,
+ );
+ 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 = (
+ BA28FB851396DA01004986CB /* private */,
+ BA28FB861396DA01004986CB /* zoneinfo */,
+ );
+ name = "Generated zoneinfo Files";
+ sourceTree = "<group>";
+ };
+ 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 */,
+ BA4FD1DD1372FAFA0025925C /* accton.tproj */,
+ BA4FD1E21372FAFA0025925C /* arch.tproj */,
+ BA4FD1E81372FAFA0025925C /* at.tproj */,
+ BA4FD1F61372FAFA0025925C /* atrun.tproj */,
+ BA4FD1FF1372FAFA0025925C /* chkpasswd.tproj */,
+ BA4FD20A1372FAFA0025925C /* chpass.tproj */,
+ BA4FD2181372FAFA0025925C /* dirhelper.tproj */,
+ BA4FD21E1372FAFA0025925C /* dmesg.tproj */,
+ BA4FD2261372FAFA0025925C /* dynamic_pager.tproj */,
+ BA4FD22E1372FAFA0025925C /* fs_usage.tproj */,
+ BA4FD2321372FAFA0025925C /* getconf.tproj */,
+ BA4FD23E1372FAFA0025925C /* getty.tproj */,
+ BA4FD24B1372FAFA0025925C /* hostinfo.tproj */,
+ BA4FD24F1372FAFA0025925C /* iostat.tproj */,
+ BA4FD2551372FAFA0025925C /* latency.tproj */,
+ BA4FD2591372FAFA0025925C /* login.tproj */,
+ 1523FE691595056C00661E82 /* ltop.tproj */,
+ BA4FD2651372FAFA0025925C /* makekey.tproj */,
+ BA4FD2691372FAFA0025925C /* mean.tproj */,
+ BA4FD26C1372FAFA0025925C /* mkfile.tproj */,
+ BA4FD2701372FAFA0025925C /* newgrp.tproj */,
+ BA4FD2741372FAFA0025925C /* nologin.tproj */,
+ BA4FD2791372FAFA0025925C /* nvram.tproj */,
+ BA4FD27D1372FAFA0025925C /* pagesize.tproj */,
+ BA4FD2811372FAFA0025925C /* passwd.tproj */,
+ BA4FD28A1372FAFA0025925C /* pwd_mkdb.tproj */,
+ BA4FD2901372FAFA0025925C /* reboot.tproj */,
+ BA4FD2951372FAFA0025925C /* sa.tproj */,
+ BA4FD29E1372FAFA0025925C /* sadc.tproj */,
+ BA4FD2A71372FAFA0025925C /* sar.tproj */,
+ BA4FD2AC1372FAFA0025925C /* sc_usage.tproj */,
+ BA4FD2B01372FAFA0025925C /* shutdown.tproj */,
+ BA4FD2B61372FAFA0025925C /* sync.tproj */,
+ BA4FD2BA1372FAFA0025925C /* sysctl.tproj */,
+ BA4FD2BF1372FAFA0025925C /* trace.tproj */,
+ BA4FD2C31372FAFA0025925C /* vifs.tproj */,
+ BA4FD2C71372FAFA0025925C /* vipw.tproj */,
+ BA4FD2CD1372FAFA0025925C /* vm_stat.tproj */,
+ BA4FD2D11372FAFA0025925C /* zdump.tproj */,
+ BA4FD2D51372FAFA0025925C /* zic.tproj */,
+ BA4FD2E31372FAFA0025925C /* zprint.tproj */,
+ BA4B7A0D1373BBB600003422 /* Libraries */,
+ C625B28916D6F27E00168EF7 /* taskpolicy.tproj */,
+ BA4FD2F01372FB3D0025925C /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ BA4B79FB1373B7ED00003422 /* Processed LaunchDaemon plist */ = {
+ isa = PBXGroup;
+ children = (
+ BA4B79FA1373B7C300003422 /* com.apple.dynamic_pager.plist */,
+ );
+ name = "Processed LaunchDaemon plist";
+ sourceTree = "<group>";
+ };
+ BA4B7A0D1373BBB600003422 /* Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ BA4B79BF1373A53700003422 /* libbsm.dylib */,
+ BA4B7A9313765F8B00003422 /* libncurses.dylib */,
+ BA4B7A091373BA4600003422 /* libutil.dylib */,
+ BA9B767113739D36001BB39F /* libpam.dylib */,
+ BA9B766D13739D27001BB39F /* CoreFoundation.framework */,
+ BA4B79F31373B01B00003422 /* SystemConfiguration.framework */,
+ BA9B766E13739D27001BB39F /* OpenDirectory.framework */,
+ BA4B7A7613765D7700003422 /* IOKit.framework */,
+ );
+ name = Libraries;
+ sourceTree = "<group>";
+ };
+ BA4B7A231373C2DC00003422 /* Generated Source */ = {
+ isa = PBXGroup;
+ children = (
+ BA4B7A241373C30100003422 /* confstr.c */,
+ BA4B7A251373C30100003422 /* limits.c */,
+ BA4B7A261373C30100003422 /* pathconf.c */,
+ BA4B7A271373C30100003422 /* progenv.c */,
+ BA4B7A281373C30100003422 /* sysconf.c */,
+ );
+ name = "Generated Source";
+ sourceTree = "<group>";
+ };
+ BA4B7A3D1375189E00003422 /* Processed LaunchDaemon plist */ = {
+ isa = PBXGroup;
+ children = (
+ BA4B7A5B13764F1400003422 /* com.apple.getty.plist */,
+ );
+ name = "Processed LaunchDaemon plist";
+ sourceTree = "<group>";
+ };
+ BA4FD1D91372FAFA0025925C /* ac.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD1DB1372FAFA0025925C /* ac.8 */,
+ BA4FD1DC1372FAFA0025925C /* ac.c */,
+ );
+ path = ac.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD1DD1372FAFA0025925C /* accton.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD1DF1372FAFA0025925C /* accton.8 */,
+ BA4FD1E01372FAFA0025925C /* accton.c */,
+ );
+ path = accton.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD1E21372FAFA0025925C /* arch.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD1E41372FAFA0025925C /* arch.1 */,
+ BA4FD1E51372FAFA0025925C /* arch.c */,
+ BA4FD1E71372FAFA0025925C /* machine.1 */,
+ );
+ path = arch.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD1E81372FAFA0025925C /* at.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD1E91372FAFA0025925C /* LEGAL */,
+ BA4FD1EB1372FAFA0025925C /* at.1 */,
+ BA4FD1EC1372FAFA0025925C /* at.c */,
+ BA4FD1ED1372FAFA0025925C /* at.h */,
+ BA4FD1EE1372FAFA0025925C /* panic.c */,
+ BA4FD1EF1372FAFA0025925C /* panic.h */,
+ BA4FD1F01372FAFA0025925C /* parsetime.c */,
+ BA4FD1F11372FAFA0025925C /* parsetime.h */,
+ BA4FD1F21372FAFA0025925C /* pathnames.h */,
+ BA4FD1F31372FAFA0025925C /* perm.c */,
+ BA4FD1F41372FAFA0025925C /* perm.h */,
+ BA4FD1F51372FAFA0025925C /* privs.h */,
+ );
+ path = at.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD1F61372FAFA0025925C /* atrun.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD1F81372FAFA0025925C /* atrun.8 */,
+ BA4FD1F91372FAFA0025925C /* atrun.c */,
+ BA4FD1FA1372FAFA0025925C /* atrun.h */,
+ BA4FD1FC1372FAFA0025925C /* com.apple.atrun.plist */,
+ BA4FD1FD1372FAFA0025925C /* gloadavg.c */,
+ BA4FD1FE1372FAFA0025925C /* gloadavg.h */,
+ );
+ path = atrun.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD1FF1372FAFA0025925C /* chkpasswd.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2011372FAFA0025925C /* chkpasswd.8 */,
+ BA4FD2021372FAFA0025925C /* chkpasswd.pam */,
+ BA4FD2031372FAFA0025925C /* file_passwd.c */,
+ BA4FD2041372FAFA0025925C /* nis_passwd.c */,
+ BA4FD2051372FAFA0025925C /* od_passwd.c */,
+ BA4FD2061372FAFA0025925C /* pam_passwd.c */,
+ BA4FD2071372FAFA0025925C /* passwd.c */,
+ BA4FD2081372FAFA0025925C /* stringops.c */,
+ BA4FD2091372FAFA0025925C /* stringops.h */,
+ BA9B767613739E9E001BB39F /* chkpasswd.h */,
+ );
+ path = chkpasswd.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD20A1372FAFA0025925C /* chpass.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD20B1372FAFA0025925C /* IMPORT_NOTES */,
+ BA4FD20D1372FAFA0025925C /* chpass.1 */,
+ BA4FD20E1372FAFA0025925C /* chpass.c */,
+ BA4FD20F1372FAFA0025925C /* chpass.h */,
+ BA4FD2101372FAFA0025925C /* edit.c */,
+ BA4FD2111372FAFA0025925C /* field.c */,
+ BA4FD2121372FAFA0025925C /* open_directory.c */,
+ BA4FD2131372FAFA0025925C /* open_directory.h */,
+ BA4FD2141372FAFA0025925C /* pw_copy.c */,
+ BA4FD2151372FAFA0025925C /* pw_copy.h */,
+ BA4FD2161372FAFA0025925C /* table.c */,
+ BA4FD2171372FAFA0025925C /* util.c */,
+ );
+ path = chpass.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2181372FAFA0025925C /* dirhelper.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4B79AA1373A49400003422 /* dirhelper.defs */,
+ BA4FD21A1372FAFA0025925C /* client.c */,
+ BA4FD21B1372FAFA0025925C /* com.apple.bsd.dirhelper.plist */,
+ BA4FD21C1372FAFA0025925C /* dirhelper.8 */,
+ BA4FD21D1372FAFA0025925C /* dirhelper.c */,
+ );
+ path = dirhelper.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD21E1372FAFA0025925C /* dmesg.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2201372FAFA0025925C /* dmesg.8 */,
+ BA4FD2211372FAFA0025925C /* dmesg.c */,
+ );
+ path = dmesg.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2261372FAFA0025925C /* dynamic_pager.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2281372FAFA0025925C /* backing_store_alerts.defs */,
+ BA4FD2291372FAFA0025925C /* backing_store_triggers.defs */,
+ BA4FD22A1372FAFA0025925C /* com.apple.dynamic_pager.plist */,
+ BA4FD22B1372FAFA0025925C /* default_pager_alerts.defs */,
+ BA4FD22C1372FAFA0025925C /* dynamic_pager.8 */,
+ BA4FD22D1372FAFA0025925C /* dynamic_pager.c */,
+ BA4B79FB1373B7ED00003422 /* Processed LaunchDaemon plist */,
+ );
+ path = dynamic_pager.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD22E1372FAFA0025925C /* fs_usage.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2301372FAFA0025925C /* fs_usage.1 */,
+ BA4FD2311372FAFA0025925C /* fs_usage.c */,
+ );
+ path = fs_usage.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2321372FAFA0025925C /* getconf.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2351372FAFA0025925C /* confstr.gperf */,
+ BA4FD2361372FAFA0025925C /* fake-gperf.awk */,
+ BA4FD2371372FAFA0025925C /* getconf.1 */,
+ BA4FD2381372FAFA0025925C /* getconf.c */,
+ BA4FD2391372FAFA0025925C /* getconf.h */,
+ BA4FD23A1372FAFA0025925C /* limits.gperf */,
+ BA4FD23B1372FAFA0025925C /* pathconf.gperf */,
+ BA4FD23C1372FAFA0025925C /* progenv.gperf */,
+ BA4FD23D1372FAFA0025925C /* sysconf.gperf */,
+ BA4B7A231373C2DC00003422 /* Generated Source */,
+ );
+ path = getconf.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD23E1372FAFA0025925C /* getty.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2401372FAFA0025925C /* chat.c */,
+ BA4FD2411372FAFA0025925C /* com.apple.getty.plist */,
+ BA4FD2421372FAFA0025925C /* extern.h */,
+ BA4FD2431372FAFA0025925C /* getty.8 */,
+ BA4FD2441372FAFA0025925C /* gettytab.5 */,
+ BA4FD2451372FAFA0025925C /* gettytab.h */,
+ BA4FD2461372FAFA0025925C /* init.c */,
+ BA4FD2471372FAFA0025925C /* main.c */,
+ BA4FD2481372FAFA0025925C /* pathnames.h */,
+ BA4FD2491372FAFA0025925C /* subr.c */,
+ BA4FD24A1372FAFA0025925C /* ttys.5 */,
+ BA4B7A3D1375189E00003422 /* Processed LaunchDaemon plist */,
+ );
+ path = getty.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD24B1372FAFA0025925C /* hostinfo.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD24D1372FAFA0025925C /* hostinfo.8 */,
+ BA4FD24E1372FAFA0025925C /* hostinfo.c */,
+ );
+ path = hostinfo.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD24F1372FAFA0025925C /* iostat.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2521372FAFA0025925C /* iostat.8 */,
+ BA4FD2531372FAFA0025925C /* iostat.c */,
+ );
+ path = iostat.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2551372FAFA0025925C /* latency.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2571372FAFA0025925C /* latency.1 */,
+ BA4FD2581372FAFA0025925C /* latency.c */,
+ );
+ path = latency.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2591372FAFA0025925C /* login.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD25B1372FAFA0025925C /* klogin.c */,
+ BA4FD25C1372FAFA0025925C /* login.1 */,
+ BA4FD25D1372FAFA0025925C /* login.c */,
+ BA4FD25E1372FAFA0025925C /* login.h */,
+ BA4FD25F1372FAFA0025925C /* login_audit.c */,
+ BA4FD2601372FAFA0025925C /* pam.d */,
+ BA4FD2631372FAFA0025925C /* pathnames.h */,
+ );
+ path = login.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2601372FAFA0025925C /* pam.d */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2611372FAFA0025925C /* login */,
+ BA4FD2621372FAFA0025925C /* login.term */,
+ );
+ path = pam.d;
+ sourceTree = "<group>";
+ };
+ BA4FD2651372FAFA0025925C /* makekey.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2671372FAFA0025925C /* makekey.8 */,
+ BA4FD2681372FAFA0025925C /* makekey.c */,
+ );
+ path = makekey.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2691372FAFA0025925C /* mean.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD26B1372FAFA0025925C /* mean.c */,
+ );
+ path = mean.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD26C1372FAFA0025925C /* mkfile.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD26E1372FAFA0025925C /* mkfile.8 */,
+ BA4FD26F1372FAFA0025925C /* mkfile.c */,
+ );
+ path = mkfile.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2701372FAFA0025925C /* newgrp.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2721372FAFA0025925C /* newgrp.1 */,
+ BA4FD2731372FAFA0025925C /* newgrp.c */,
+ );
+ path = newgrp.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2741372FAFA0025925C /* nologin.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2761372FAFA0025925C /* nologin.5 */,
+ BA4FD2771372FAFA0025925C /* nologin.8 */,
+ BA4FD2781372FAFA0025925C /* nologin.c */,
+ );
+ path = nologin.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2791372FAFA0025925C /* nvram.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD27B1372FAFA0025925C /* nvram.8 */,
+ BA4FD27C1372FAFA0025925C /* nvram.c */,
+ );
+ path = nvram.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD27D1372FAFA0025925C /* pagesize.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD27F1372FAFA0025925C /* pagesize.1 */,
+ BA4FD2801372FAFA0025925C /* pagesize.sh */,
+ );
+ path = pagesize.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2811372FAFA0025925C /* passwd.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2831372FAFA0025925C /* file_passwd.c */,
+ BA4FD2841372FAFA0025925C /* nis_passwd.c */,
+ BA4FD2851372FAFA0025925C /* od_passwd.c */,
+ BA4FD2861372FAFA0025925C /* pam_passwd.c */,
+ BA4FD2871372FAFA0025925C /* passwd.1 */,
+ BA4FD2881372FAFA0025925C /* passwd.c */,
+ BAE589D71378FE8D0049DD3B /* passwd.h */,
+ BA4FD2891372FAFA0025925C /* passwd.pam */,
+ );
+ path = passwd.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD28A1372FAFA0025925C /* pwd_mkdb.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD28C1372FAFA0025925C /* pw_scan.c */,
+ BA4FD28D1372FAFA0025925C /* pw_scan.h */,
+ BA4FD28E1372FAFA0025925C /* pwd_mkdb.8 */,
+ BA4FD28F1372FAFA0025925C /* pwd_mkdb.c */,
+ );
+ path = pwd_mkdb.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2901372FAFA0025925C /* reboot.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2921372FAFA0025925C /* kextmanager.defs */,
+ BA4FD2931372FAFA0025925C /* reboot.8 */,
+ BA4FD2941372FAFA0025925C /* reboot.c */,
+ );
+ path = reboot.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2951372FAFA0025925C /* sa.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2971372FAFA0025925C /* db.c */,
+ BA4FD2981372FAFA0025925C /* extern.h */,
+ BA4FD2991372FAFA0025925C /* main.c */,
+ BA4FD29A1372FAFA0025925C /* pathnames.h */,
+ BA4FD29B1372FAFA0025925C /* pdb.c */,
+ BA4FD29C1372FAFA0025925C /* sa.8 */,
+ BA4FD29D1372FAFA0025925C /* usrdb.c */,
+ );
+ path = sa.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD29E1372FAFA0025925C /* sadc.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2A01372FAFA0025925C /* sa1.8 */,
+ BA4FD2A11372FAFA0025925C /* sa1.sh */,
+ BA4FD2A21372FAFA0025925C /* sa2.8 */,
+ BA4FD2A31372FAFA0025925C /* sa2.sh */,
+ BA4FD2A41372FAFA0025925C /* sadc.8 */,
+ BA4FD2A51372FAFA0025925C /* sadc.c */,
+ BA4FD2A61372FAFA0025925C /* sadc.h */,
+ );
+ path = sadc.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2A71372FAFA0025925C /* sar.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2A91372FAFA0025925C /* sar.1 */,
+ BA4FD2AA1372FAFA0025925C /* sar.c */,
+ BA4FD2AB1372FAFA0025925C /* sar.h */,
+ );
+ path = sar.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2AC1372FAFA0025925C /* sc_usage.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2AE1372FAFA0025925C /* sc_usage.1 */,
+ BA4FD2AF1372FAFA0025925C /* sc_usage.c */,
+ );
+ path = sc_usage.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2B01372FAFA0025925C /* shutdown.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2B21372FAFA0025925C /* kextmanager.defs */,
+ BA4FD2B31372FAFA0025925C /* pathnames.h */,
+ BA4FD2B41372FAFA0025925C /* shutdown.8 */,
+ BA4FD2B51372FAFA0025925C /* shutdown.c */,
+ );
+ path = shutdown.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2B61372FAFA0025925C /* sync.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2B81372FAFA0025925C /* sync.8 */,
+ BA4FD2B91372FAFA0025925C /* sync.c */,
+ );
+ path = sync.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2BA1372FAFA0025925C /* sysctl.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2BC1372FAFA0025925C /* sysctl.8 */,
+ BA4FD2BD1372FAFA0025925C /* sysctl.c */,
+ BA4FD2BE1372FAFA0025925C /* sysctl.conf.5 */,
+ );
+ path = sysctl.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2BF1372FAFA0025925C /* trace.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2C11372FAFA0025925C /* trace.1 */,
+ BA4FD2C21372FAFA0025925C /* trace.c */,
+ );
+ path = trace.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2C31372FAFA0025925C /* vifs.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2C51372FAFA0025925C /* vifs.8 */,
+ BA4FD2C61372FAFA0025925C /* vifs.c */,
+ );
+ path = vifs.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2C71372FAFA0025925C /* vipw.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2C91372FAFA0025925C /* pw_util.c */,
+ BA4FD2CA1372FAFA0025925C /* pw_util.h */,
+ BA4FD2CB1372FAFA0025925C /* vipw.8 */,
+ BA4FD2CC1372FAFA0025925C /* vipw.c */,
+ );
+ path = vipw.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2CD1372FAFA0025925C /* vm_stat.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2CF1372FAFA0025925C /* vm_stat.1 */,
+ BA4FD2D01372FAFA0025925C /* vm_stat.c */,
+ );
+ path = vm_stat.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2D11372FAFA0025925C /* zdump.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2D31372FAFA0025925C /* zdump.8 */,
+ BA4FD2D41372FAFA0025925C /* zdump.c */,
+ );
+ path = zdump.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2D51372FAFA0025925C /* zic.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA959E8413968CF900CA9C60 /* generate_zoneinfo.sh */,
+ BA4FD2D61372FAFA0025925C /* Arts.htm */,
+ BA4FD2D81372FAFA0025925C /* Makefile.zoneinfo.dist */,
+ BA4FD2D91372FAFA0025925C /* README */,
+ BA4FD2DA1372FAFA0025925C /* Theory */,
+ BA4FD2DB1372FAFA0025925C /* ZIC_HACK */,
+ BA4FD2DC1372FAFA0025925C /* ialloc.c */,
+ BA4FD2DD1372FAFA0025925C /* private.h */,
+ BA4FD2DE1372FAFA0025925C /* scheck.c */,
+ BA4FD2DF1372FAFA0025925C /* tz-art.htm */,
+ BA4FD2E01372FAFA0025925C /* tz-link.htm */,
+ BA4FD2E11372FAFA0025925C /* zic.8 */,
+ BA4FD2E21372FAFA0025925C /* zic.c */,
+ BA0A86491396D3CE00D2272C /* Generated zoneinfo Files */,
+ );
+ path = zic.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2E31372FAFA0025925C /* zprint.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2E51372FAFA0025925C /* zprint.1 */,
+ BA4FD2E61372FAFA0025925C /* zprint.c */,
+ );
+ path = zprint.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2F01372FB3D0025925C /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2EF1372FB3D0025925C /* ac */,
+ BA4FD30D1372FFD80025925C /* accton */,
+ BA4FD323137300EE0025925C /* arch */,
+ BA4FD3411373073E0025925C /* at */,
+ BA9B764C13739ABE001BB39F /* atrun */,
+ BA9B766313739C20001BB39F /* chkpasswd */,
+ BA9B768C1373A0D8001BB39F /* chpass */,
+ BA4B79BA1373A4E500003422 /* dirhelper */,
+ BA4B79CD1373A72800003422 /* dmesg */,
+ BA4B79D51373A97000003422 /* libdp_notify_lib.a */,
+ BA4B79EC1373AF7A00003422 /* dynamic_pager */,
+ BA4B7A051373B9E900003422 /* fs_usage */,
+ BA4B7A161373BE9D00003422 /* getconf */,
+ BA4B7A4F137648E100003422 /* getty */,
+ BA4B7A6513765CC700003422 /* hostinfo */,
+ BA4B7A7113765D3E00003422 /* iostat */,
+ BA4B7A9013765F3C00003422 /* latency */,
+ BA473DB31377B2230005CC19 /* login */,
+ BACC1D091377B3E6007728F4 /* makekey */,
+ BACC1D151377B481007728F4 /* mean */,
+ BACC1D451377B6E2007728F4 /* mkfile */,
+ BACC1D551377B7A7007728F4 /* newgrp */,
+ BACC1D611377B85C007728F4 /* nologin */,
+ BAE589A5137836A00049DD3B /* nvram */,
+ BAE589CE1378FCAA0049DD3B /* passwd */,
+ BAE589E3137902F50049DD3B /* pwd_mkdb */,
+ BAE589F01379044E0049DD3B /* reboot */,
+ BAE58A1113799F610049DD3B /* sa */,
+ BAE58A2513799FFA0049DD3B /* sadc */,
+ BAE58A3D1379A3F60049DD3B /* sar */,
+ BAE58A4E137D69A60049DD3B /* sc_usage */,
+ BA91CE62137F42ED00AE5160 /* shutdown */,
+ BA9BF492139680CF0018C7BB /* sync */,
+ BA9BF49F1396812D0018C7BB /* sysctl */,
+ BA9BF4AE139681910018C7BB /* trace */,
+ BA9BF4C6139682BA0018C7BB /* vifs */,
+ BA9BF4D2139682F80018C7BB /* vipw */,
+ BA9BF4DF139683580018C7BB /* vm_stat */,
+ 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 */
+ BA4FD3481373077C0025925C /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4FD3491373079B0025925C /* at.h in Headers */,
+ BA4FD34A1373079B0025925C /* panic.h in Headers */,
+ BA4FD34B1373079B0025925C /* parsetime.h in Headers */,
+ BA4FD34C1373079B0025925C /* pathnames.h in Headers */,
+ BA4FD34D1373079B0025925C /* perm.h in Headers */,
+ BA4FD34E1373079B0025925C /* privs.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B763F13739ABE001BB39F /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B764313739ABE001BB39F /* pathnames.h in Headers */,
+ BA9B764513739ABE001BB39F /* privs.h in Headers */,
+ BA9B764F13739B45001BB39F /* atrun.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B765813739C20001BB39F /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B766B13739C7A001BB39F /* stringops.h in Headers */,
+ BA9B767713739E9E001BB39F /* chkpasswd.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B76801373A0D8001BB39F /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B76951373A16A001BB39F /* chpass.h in Headers */,
+ BA9B76961373A16A001BB39F /* open_directory.h in Headers */,
+ BA9B76971373A16A001BB39F /* pw_copy.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* 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" */;
+ buildPhases = (
+ BA0A860813968E8500D2272C /* Sources */,
+ BA0A860A13968E8500D2272C /* Frameworks */,
+ BA0A860C13968E8500D2272C /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = zprint;
+ productName = ac;
+ productReference = BA0A861013968E8500D2272C /* zprint */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA473DA01377B2230005CC19 /* login */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA473DB11377B2230005CC19 /* Build configuration list for PBXNativeTarget "login" */;
+ buildPhases = (
+ BA473DA11377B2230005CC19 /* Sources */,
+ BA473DAD1377B2230005CC19 /* Frameworks */,
+ BA473DAE1377B2230005CC19 /* CopyFiles */,
+ BACC1CFC1377B2BD007728F4 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = login;
+ productName = ac;
+ productReference = BA473DB31377B2230005CC19 /* login */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B79AC1373A4E500003422 /* dirhelper */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B79B81373A4E500003422 /* Build configuration list for PBXNativeTarget "dirhelper" */;
+ buildPhases = (
+ BA4B79AD1373A4E500003422 /* Sources */,
+ BA4B79B31373A4E500003422 /* Frameworks */,
+ BA4B79B41373A4E500003422 /* CopyFiles */,
+ BA4B79B61373A4E500003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dirhelper;
+ productName = ac;
+ productReference = BA4B79BA1373A4E500003422 /* dirhelper */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B79C51373A72800003422 /* dmesg */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B79CB1373A72800003422 /* Build configuration list for PBXNativeTarget "dmesg" */;
+ buildPhases = (
+ BA4B79C61373A72800003422 /* Sources */,
+ BA4B79C81373A72800003422 /* Frameworks */,
+ BA4B79C91373A72800003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dmesg;
+ productName = ac;
+ productReference = BA4B79CD1373A72800003422 /* dmesg */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B79D41373A97000003422 /* dp_notify_lib */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B79D61373A97000003422 /* Build configuration list for PBXNativeTarget "dp_notify_lib" */;
+ buildPhases = (
+ BA4B79D11373A97000003422 /* Sources */,
+ BA4B79D21373A97000003422 /* Frameworks */,
+ BA4B79DF1373AB0900003422 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dp_notify_lib;
+ productName = dp_notify_lib;
+ productReference = BA4B79D51373A97000003422 /* libdp_notify_lib.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ BA4B79E01373AF7A00003422 /* dynamic_pager */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B79EA1373AF7A00003422 /* Build configuration list for PBXNativeTarget "dynamic_pager" */;
+ buildPhases = (
+ BA4B79E11373AF7A00003422 /* Sources */,
+ BA4B79E41373AF7A00003422 /* Frameworks */,
+ BA4B79E61373AF7A00003422 /* CopyFiles */,
+ BA4B79F91373B6A400003422 /* ShellScript */,
+ BA4B79E81373AF7A00003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dynamic_pager;
+ productName = ac;
+ productReference = BA4B79EC1373AF7A00003422 /* dynamic_pager */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B79FD1373B9E900003422 /* fs_usage */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B7A031373B9E900003422 /* Build configuration list for PBXNativeTarget "fs_usage" */;
+ buildPhases = (
+ BA4B79FE1373B9E900003422 /* Sources */,
+ BA4B7A001373B9E900003422 /* Frameworks */,
+ BA4B7A011373B9E900003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = fs_usage;
+ productName = ac;
+ productReference = BA4B7A051373B9E900003422 /* fs_usage */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B7A0E1373BE9D00003422 /* getconf */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B7A141373BE9D00003422 /* Build configuration list for PBXNativeTarget "getconf" */;
+ buildPhases = (
+ BA4B7A221373C01600003422 /* ShellScript */,
+ BA4B7A0F1373BE9D00003422 /* Sources */,
+ BA4B7A111373BE9D00003422 /* Frameworks */,
+ BA4B7A121373BE9D00003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = getconf;
+ productName = ac;
+ productReference = BA4B7A161373BE9D00003422 /* getconf */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B7A3F137648E100003422 /* getty */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B7A4D137648E100003422 /* Build configuration list for PBXNativeTarget "getty" */;
+ buildPhases = (
+ BA4B7A40137648E100003422 /* Sources */,
+ BA4B7A45137648E100003422 /* Frameworks */,
+ BA4B7A48137648E100003422 /* CopyFiles */,
+ BA4B7A561376496100003422 /* CopyFiles */,
+ BA4B7A4A137648E100003422 /* ShellScript */,
+ BA4B7A4B137648E100003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = getty;
+ productName = ac;
+ productReference = BA4B7A4F137648E100003422 /* getty */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B7A5D13765CC700003422 /* hostinfo */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B7A6313765CC700003422 /* Build configuration list for PBXNativeTarget "hostinfo" */;
+ buildPhases = (
+ BA4B7A5E13765CC700003422 /* Sources */,
+ BA4B7A6013765CC700003422 /* Frameworks */,
+ BA4B7A6113765CC700003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = hostinfo;
+ productName = ac;
+ productReference = BA4B7A6513765CC700003422 /* hostinfo */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B7A6913765D3E00003422 /* iostat */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B7A6F13765D3E00003422 /* Build configuration list for PBXNativeTarget "iostat" */;
+ buildPhases = (
+ BA4B7A6A13765D3E00003422 /* Sources */,
+ BA4B7A6C13765D3E00003422 /* Frameworks */,
+ BA4B7A6D13765D3E00003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = iostat;
+ productName = ac;
+ productReference = BA4B7A7113765D3E00003422 /* iostat */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B7A7D13765F3C00003422 /* latency */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B7A8E13765F3C00003422 /* Build configuration list for PBXNativeTarget "latency" */;
+ buildPhases = (
+ BA4B7A7E13765F3C00003422 /* Sources */,
+ BA4B7A8A13765F3C00003422 /* Frameworks */,
+ BA4B7A8B13765F3C00003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = latency;
+ productName = ac;
+ productReference = BA4B7A9013765F3C00003422 /* latency */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4FD2EE1372FB3D0025925C /* ac */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4FD2F91372FB3D0025925C /* Build configuration list for PBXNativeTarget "ac" */;
+ buildPhases = (
+ BA4FD2EB1372FB3D0025925C /* Sources */,
+ BA4FD2EC1372FB3D0025925C /* Frameworks */,
+ BA4FD2ED1372FB3D0025925C /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ac;
+ productName = ac;
+ productReference = BA4FD2EF1372FB3D0025925C /* ac */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4FD3041372FFD80025925C /* accton */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4FD30A1372FFD80025925C /* Build configuration list for PBXNativeTarget "accton" */;
+ buildPhases = (
+ BA4FD3051372FFD80025925C /* Sources */,
+ BA4FD3071372FFD80025925C /* Frameworks */,
+ BA4FD3081372FFD80025925C /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = accton;
+ productName = ac;
+ productReference = BA4FD30D1372FFD80025925C /* accton */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4FD31A137300ED0025925C /* arch */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4FD320137300ED0025925C /* Build configuration list for PBXNativeTarget "arch" */;
+ buildPhases = (
+ BA4FD31B137300ED0025925C /* Sources */,
+ BA4FD31D137300ED0025925C /* Frameworks */,
+ BA4FD31E137300ED0025925C /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = arch;
+ productName = ac;
+ productReference = BA4FD323137300EE0025925C /* arch */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4FD3381373073E0025925C /* at */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4FD33E1373073E0025925C /* Build configuration list for PBXNativeTarget "at" */;
+ buildPhases = (
+ BA4FD3391373073E0025925C /* Sources */,
+ BA4FD3481373077C0025925C /* Headers */,
+ BA4FD33B1373073E0025925C /* Frameworks */,
+ BA4FD33C1373073E0025925C /* CopyFiles */,
+ BAAEB39A13730C41003EA7A9 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = at;
+ productName = ac;
+ productReference = BA4FD3411373073E0025925C /* at */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA91CE59137F42ED00AE5160 /* shutdown */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA91CE60137F42ED00AE5160 /* Build configuration list for PBXNativeTarget "shutdown" */;
+ buildPhases = (
+ BA91CE5A137F42ED00AE5160 /* Sources */,
+ BA91CE5D137F42ED00AE5160 /* Frameworks */,
+ BA91CE5E137F42ED00AE5160 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = shutdown;
+ productName = ac;
+ productReference = BA91CE62137F42ED00AE5160 /* shutdown */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9B763913739ABE001BB39F /* atrun */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9B764A13739ABE001BB39F /* Build configuration list for PBXNativeTarget "atrun" */;
+ buildPhases = (
+ BA9B763A13739ABE001BB39F /* Sources */,
+ BA9B763F13739ABE001BB39F /* Headers */,
+ BA9B764613739ABE001BB39F /* Frameworks */,
+ BA9B764713739ABE001BB39F /* CopyFiles */,
+ BA9B765113739B6A001BB39F /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = atrun;
+ productName = ac;
+ productReference = BA9B764C13739ABE001BB39F /* atrun */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9B765513739C20001BB39F /* chkpasswd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9B766113739C20001BB39F /* Build configuration list for PBXNativeTarget "chkpasswd" */;
+ buildPhases = (
+ BA9B765613739C20001BB39F /* Sources */,
+ BA9B765813739C20001BB39F /* Headers */,
+ BA9B765C13739C20001BB39F /* Frameworks */,
+ BA9B765D13739C20001BB39F /* CopyFiles */,
+ BA9B767313739D86001BB39F /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = chkpasswd;
+ productName = ac;
+ productReference = BA9B766313739C20001BB39F /* chkpasswd */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9B76781373A0D8001BB39F /* chpass */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9B768A1373A0D8001BB39F /* Build configuration list for PBXNativeTarget "chpass" */;
+ buildPhases = (
+ BA9B76791373A0D8001BB39F /* Sources */,
+ BA9B76801373A0D8001BB39F /* Headers */,
+ BA9B76831373A0D8001BB39F /* Frameworks */,
+ BA9B76871373A0D8001BB39F /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = chpass;
+ productName = ac;
+ productReference = BA9B768C1373A0D8001BB39F /* chpass */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF48A139680CF0018C7BB /* sync */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF490139680CF0018C7BB /* Build configuration list for PBXNativeTarget "sync" */;
+ buildPhases = (
+ BA9BF48B139680CF0018C7BB /* Sources */,
+ BA9BF48D139680CF0018C7BB /* Frameworks */,
+ BA9BF48E139680CF0018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sync;
+ productName = ac;
+ productReference = BA9BF492139680CF0018C7BB /* sync */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF4971396812D0018C7BB /* sysctl */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF49D1396812D0018C7BB /* Build configuration list for PBXNativeTarget "sysctl" */;
+ buildPhases = (
+ BA9BF4981396812D0018C7BB /* Sources */,
+ BA9BF49A1396812D0018C7BB /* Frameworks */,
+ BA9BF49B1396812D0018C7BB /* CopyFiles */,
+ BA9BF4A21396815B0018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sysctl;
+ productName = ac;
+ productReference = BA9BF49F1396812D0018C7BB /* sysctl */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF4A5139681910018C7BB /* trace */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF4AC139681910018C7BB /* Build configuration list for PBXNativeTarget "trace" */;
+ buildPhases = (
+ BA9BF4A6139681910018C7BB /* Sources */,
+ BA9BF4A8139681910018C7BB /* Frameworks */,
+ BA9BF4AA139681910018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = trace;
+ productName = ac;
+ productReference = BA9BF4AE139681910018C7BB /* trace */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF4BE139682BA0018C7BB /* vifs */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF4C4139682BA0018C7BB /* Build configuration list for PBXNativeTarget "vifs" */;
+ buildPhases = (
+ BA9BF4BF139682BA0018C7BB /* Sources */,
+ BA9BF4C1139682BA0018C7BB /* Frameworks */,
+ BA9BF4C2139682BA0018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = vifs;
+ productName = ac;
+ productReference = BA9BF4C6139682BA0018C7BB /* vifs */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF4CA139682F80018C7BB /* vipw */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF4D0139682F80018C7BB /* Build configuration list for PBXNativeTarget "vipw" */;
+ buildPhases = (
+ BA9BF4CB139682F80018C7BB /* Sources */,
+ BA9BF4CD139682F80018C7BB /* Frameworks */,
+ BA9BF4CE139682F80018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = vipw;
+ productName = ac;
+ productReference = BA9BF4D2139682F80018C7BB /* vipw */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF4D7139683580018C7BB /* vm_stat */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF4DD139683580018C7BB /* Build configuration list for PBXNativeTarget "vm_stat" */;
+ buildPhases = (
+ BA9BF4D8139683580018C7BB /* Sources */,
+ BA9BF4DA139683580018C7BB /* Frameworks */,
+ BA9BF4DB139683580018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = vm_stat;
+ productName = ac;
+ productReference = BA9BF4DF139683580018C7BB /* vm_stat */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF4E3139683EB0018C7BB /* zdump */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF4E9139683EB0018C7BB /* Build configuration list for PBXNativeTarget "zdump" */;
+ buildPhases = (
+ BA9BF4E4139683EB0018C7BB /* Sources */,
+ BA9BF4E6139683EB0018C7BB /* Frameworks */,
+ BA9BF4E7139683EB0018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = zdump;
+ productName = ac;
+ productReference = BA9BF4EB139683EB0018C7BB /* zdump */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF4EF139684B40018C7BB /* zic */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF4F5139684B40018C7BB /* Build configuration list for PBXNativeTarget "zic" */;
+ buildPhases = (
+ BA9BF4F0139684B40018C7BB /* Sources */,
+ BA9BF4F2139684B40018C7BB /* Frameworks */,
+ BA9BF4F3139684B40018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = zic;
+ productName = ac;
+ productReference = BA9BF4F7139684B40018C7BB /* zic */;
+ productType = "com.apple.product-type.tool";
+ };
+ BACC1D011377B3E6007728F4 /* makekey */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BACC1D071377B3E6007728F4 /* Build configuration list for PBXNativeTarget "makekey" */;
+ buildPhases = (
+ BACC1D021377B3E6007728F4 /* Sources */,
+ BACC1D041377B3E6007728F4 /* Frameworks */,
+ BACC1D051377B3E6007728F4 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = makekey;
+ productName = ac;
+ productReference = BACC1D091377B3E6007728F4 /* makekey */;
+ productType = "com.apple.product-type.tool";
+ };
+ BACC1D0D1377B481007728F4 /* mean */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BACC1D131377B481007728F4 /* Build configuration list for PBXNativeTarget "mean" */;
+ buildPhases = (
+ BACC1D0E1377B481007728F4 /* Sources */,
+ BACC1D101377B481007728F4 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mean;
+ productName = ac;
+ productReference = BACC1D151377B481007728F4 /* mean */;
+ productType = "com.apple.product-type.tool";
+ };
+ BACC1D3D1377B6E2007728F4 /* mkfile */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BACC1D431377B6E2007728F4 /* Build configuration list for PBXNativeTarget "mkfile" */;
+ buildPhases = (
+ BACC1D3E1377B6E2007728F4 /* Sources */,
+ BACC1D401377B6E2007728F4 /* Frameworks */,
+ BACC1D411377B6E2007728F4 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mkfile;
+ productName = ac;
+ productReference = BACC1D451377B6E2007728F4 /* mkfile */;
+ productType = "com.apple.product-type.tool";
+ };
+ BACC1D491377B7A7007728F4 /* newgrp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BACC1D531377B7A7007728F4 /* Build configuration list for PBXNativeTarget "newgrp" */;
+ buildPhases = (
+ BACC1D4A1377B7A7007728F4 /* Sources */,
+ BACC1D4D1377B7A7007728F4 /* Frameworks */,
+ BACC1D4E1377B7A7007728F4 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = newgrp;
+ productName = ac;
+ productReference = BACC1D551377B7A7007728F4 /* newgrp */;
+ productType = "com.apple.product-type.tool";
+ };
+ BACC1D591377B85C007728F4 /* nologin */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BACC1D5F1377B85C007728F4 /* Build configuration list for PBXNativeTarget "nologin" */;
+ buildPhases = (
+ BACC1D5A1377B85C007728F4 /* Sources */,
+ BACC1D5C1377B85C007728F4 /* Frameworks */,
+ BACC1D651377B89A007728F4 /* CopyFiles */,
+ BACC1D5D1377B85C007728F4 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = nologin;
+ productName = ac;
+ productReference = BACC1D611377B85C007728F4 /* nologin */;
+ productType = "com.apple.product-type.tool";
+ };
+ BAE5899B137836A00049DD3B /* nvram */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BAE589A3137836A00049DD3B /* Build configuration list for PBXNativeTarget "nvram" */;
+ buildPhases = (
+ BAE5899C137836A00049DD3B /* Sources */,
+ BAE5899E137836A00049DD3B /* Frameworks */,
+ BAE589A1137836A00049DD3B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = nvram;
+ productName = ac;
+ productReference = BAE589A5137836A00049DD3B /* nvram */;
+ productType = "com.apple.product-type.tool";
+ };
+ BAE589BA1378FCAA0049DD3B /* passwd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BAE589CC1378FCAA0049DD3B /* Build configuration list for PBXNativeTarget "passwd" */;
+ buildPhases = (
+ BAE589BB1378FCAA0049DD3B /* Sources */,
+ BAE589C51378FCAA0049DD3B /* Frameworks */,
+ BAE589C91378FCAA0049DD3B /* CopyFiles */,
+ BAE589CB1378FCAA0049DD3B /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = passwd;
+ productName = ac;
+ productReference = BAE589CE1378FCAA0049DD3B /* passwd */;
+ productType = "com.apple.product-type.tool";
+ };
+ BAE589DB137902F50049DD3B /* pwd_mkdb */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BAE589E1137902F50049DD3B /* Build configuration list for PBXNativeTarget "pwd_mkdb" */;
+ buildPhases = (
+ BAE589DC137902F50049DD3B /* Sources */,
+ BAE589DE137902F50049DD3B /* Frameworks */,
+ BAE589DF137902F50049DD3B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = pwd_mkdb;
+ productName = ac;
+ productReference = BAE589E3137902F50049DD3B /* pwd_mkdb */;
+ productType = "com.apple.product-type.tool";
+ };
+ BAE589E81379044E0049DD3B /* reboot */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BAE589EE1379044E0049DD3B /* Build configuration list for PBXNativeTarget "reboot" */;
+ buildPhases = (
+ BAE589E91379044E0049DD3B /* Sources */,
+ BAE589EB1379044E0049DD3B /* Frameworks */,
+ BAE589EC1379044E0049DD3B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = reboot;
+ productName = ac;
+ productReference = BAE589F01379044E0049DD3B /* reboot */;
+ productType = "com.apple.product-type.tool";
+ };
+ BAE58A0913799F610049DD3B /* sa */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BAE58A0F13799F610049DD3B /* Build configuration list for PBXNativeTarget "sa" */;
+ buildPhases = (
+ BAE58A0A13799F610049DD3B /* Sources */,
+ BAE58A0C13799F610049DD3B /* Frameworks */,
+ BAE58A0D13799F610049DD3B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sa;
+ productName = ac;
+ productReference = BAE58A1113799F610049DD3B /* sa */;
+ productType = "com.apple.product-type.tool";
+ };
+ BAE58A1813799FFA0049DD3B /* sadc */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BAE58A2313799FFA0049DD3B /* Build configuration list for PBXNativeTarget "sadc" */;
+ buildPhases = (
+ BAE58A1913799FFA0049DD3B /* Sources */,
+ BAE58A1F13799FFA0049DD3B /* Frameworks */,
+ BAE58A2013799FFA0049DD3B /* CopyFiles */,
+ BAE58A2213799FFA0049DD3B /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sadc;
+ productName = ac;
+ productReference = BAE58A2513799FFA0049DD3B /* sadc */;
+ productType = "com.apple.product-type.tool";
+ };
+ BAE58A351379A3F60049DD3B /* sar */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BAE58A3B1379A3F60049DD3B /* Build configuration list for PBXNativeTarget "sar" */;
+ buildPhases = (
+ BAE58A361379A3F60049DD3B /* Sources */,
+ BAE58A381379A3F60049DD3B /* Frameworks */,
+ BAE58A391379A3F60049DD3B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sar;
+ productName = ac;
+ productReference = BAE58A3D1379A3F60049DD3B /* sar */;
+ productType = "com.apple.product-type.tool";
+ };
+ BAE58A45137D69A60049DD3B /* sc_usage */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BAE58A4C137D69A60049DD3B /* Build configuration list for PBXNativeTarget "sc_usage" */;
+ buildPhases = (
+ BAE58A46137D69A60049DD3B /* Sources */,
+ BAE58A48137D69A60049DD3B /* Frameworks */,
+ BAE58A4A137D69A60049DD3B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sc_usage;
+ productName = ac;
+ 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 */
+ BA2DE9181372FA9100D1913C /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0420;
+ };
+ buildConfigurationList = BA2DE91B1372FA9100D1913C /* Build configuration list for PBXProject "system_cmds" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = BA2DE9161372FA9100D1913C;
+ productRefGroup = BA4FD2F01372FB3D0025925C /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ BA4FD2FE1372FE4E0025925C /* All_MacOSX */,
+ BACC1D181377B4C9007728F4 /* All_iOS */,
+ BA4FD2EE1372FB3D0025925C /* ac */,
+ BA4FD3041372FFD80025925C /* accton */,
+ BA4FD31A137300ED0025925C /* arch */,
+ BA4FD32F137305DD0025925C /* machine */,
+ BA4FD3381373073E0025925C /* at */,
+ BAAEB39C13730D5C003EA7A9 /* atq */,
+ BAAEB3A513730DFA003EA7A9 /* atrm */,
+ BAAEB3AC13730E1C003EA7A9 /* batch */,
+ BA9B763913739ABE001BB39F /* atrun */,
+ BA9B765513739C20001BB39F /* chkpasswd */,
+ BA9B76781373A0D8001BB39F /* chpass */,
+ BA9B76991373A246001BB39F /* chfn */,
+ BA9B76A11373A2A2001BB39F /* chsh */,
+ BA4B79AC1373A4E500003422 /* dirhelper */,
+ BA4B79C51373A72800003422 /* dmesg */,
+ BA4B79D41373A97000003422 /* dp_notify_lib */,
+ BA4B79E01373AF7A00003422 /* dynamic_pager */,
+ BA4B79FD1373B9E900003422 /* fs_usage */,
+ BA4B7A0E1373BE9D00003422 /* getconf */,
+ BA4B7A3F137648E100003422 /* getty */,
+ BA4B7A5D13765CC700003422 /* hostinfo */,
+ BA4B7A6913765D3E00003422 /* iostat */,
+ BA4B7A7D13765F3C00003422 /* latency */,
+ BA473DA01377B2230005CC19 /* login */,
+ 1523FE5A1595048900661E82 /* ltop */,
+ BACC1D011377B3E6007728F4 /* makekey */,
+ BACC1D0D1377B481007728F4 /* mean */,
+ BACC1D3D1377B6E2007728F4 /* mkfile */,
+ BACC1D491377B7A7007728F4 /* newgrp */,
+ BACC1D591377B85C007728F4 /* nologin */,
+ BAE5899B137836A00049DD3B /* nvram */,
+ BAE589AA137837130049DD3B /* pagesize */,
+ BAE589BA1378FCAA0049DD3B /* passwd */,
+ BAE589DB137902F50049DD3B /* pwd_mkdb */,
+ BAE589E81379044E0049DD3B /* reboot */,
+ BAE589F5137904DF0049DD3B /* halt */,
+ BAE58A0913799F610049DD3B /* sa */,
+ BAE58A1813799FFA0049DD3B /* sadc */,
+ BAE58A351379A3F60049DD3B /* sar */,
+ BAE58A45137D69A60049DD3B /* sc_usage */,
+ BA91CE59137F42ED00AE5160 /* shutdown */,
+ BA9BF48A139680CF0018C7BB /* sync */,
+ BA9BF4971396812D0018C7BB /* sysctl */,
+ BA9BF4A5139681910018C7BB /* trace */,
+ BA9BF4BE139682BA0018C7BB /* vifs */,
+ BA9BF4CA139682F80018C7BB /* vipw */,
+ BA9BF4D7139683580018C7BB /* vm_stat */,
+ BA9BF4E3139683EB0018C7BB /* zdump */,
+ BA9BF4EF139684B40018C7BB /* zic */,
+ BA959E7E13968C8E00CA9C60 /* zoneinfo */,
+ BA0A860713968E8500D2272C /* zprint */,
+ C96F50AE15BDCEC3008682F7 /* lsmp */,
+ 55CCB16A16B84EDA00B56979 /* vm_purgeable_stat */,
+ C625B28716D6F27E00168EF7 /* taskpolicy */,
+ B3F0E6CC16E96FC2008FAD09 /* memory_pressure */,
+ ADA9006F17679A8C00161ADF /* purge */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ BA4B79DF1373AB0900003422 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ 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 */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/dynamic_pager.tproj/com.apple.dynamic_pager.plist",
+ );
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/com.apple.dynamic_pager.plist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\ncp \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\nif [ \"${PLATFORM_NAME}\" = \"iphoneos\" ]; then\n /usr/libexec/PlistBuddy -c \"Add :LaunchOnlyOnce bool true\" \"${SCRIPT_OUTPUT_FILE_0}\"\nfi\n";
+ };
+ BA4B7A221373C01600003422 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/getconf.tproj/confstr.gperf",
+ "$(SRCROOT)/getconf.tproj/limits.gperf",
+ "$(SRCROOT)/getconf.tproj/pathconf.gperf",
+ "$(SRCROOT)/getconf.tproj/progenv.gperf",
+ "$(SRCROOT)/getconf.tproj/sysconf.gperf",
+ );
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/confstr.c",
+ "$(BUILT_PRODUCTS_DIR)/limits.c",
+ "$(BUILT_PRODUCTS_DIR)/pathconf.c",
+ "$(BUILT_PRODUCTS_DIR)/progenv.c",
+ "$(BUILT_PRODUCTS_DIR)/sysconf.c",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\ni=0\n\nwhile [ $i -lt ${SCRIPT_INPUT_FILE_COUNT} ]; do\n INPUT=\"SCRIPT_INPUT_FILE_${i}\"\n OUTPUT=\"SCRIPT_OUTPUT_FILE_${i}\"\n LC_ALL=C awk -f \"${SRCROOT}/getconf.tproj/fake-gperf.awk\" ${!INPUT} > ${!OUTPUT}\n i=$(($i + 1))\ndone\n";
+ showEnvVarsInLog = 0;
+ };
+ BA4B7A4A137648E100003422 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/getty.tproj/com.apple.getty.plist",
+ );
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/com.apple.getty.plist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\ncp \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\nif [ \"${PLATFORM_NAME}\" != \"iphoneos\" ]; then\n /usr/libexec/PlistBuddy -c \"Add :Disabled bool true\" \"${SCRIPT_OUTPUT_FILE_0}\"\nfi\n";
+ };
+ BA4FD335137306050025925C /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/usr/bin/arch",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/bin/machine",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nln -fhv \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BA7248051397C1350008497A /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/zic.tproj/build_zichost.sh",
+ );
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/zic_host-dst/zic_host",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\n\"${SCRIPT_INPUT_FILE_0}\" \"${BUILT_PRODUCTS_DIR}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BA959E8113968C8E00CA9C60 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 12;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/zic.tproj/generate_zoneinfo.sh",
+ "$(BUILT_PRODUCTS_DIR)/zic_host-dst/zic_host",
+ );
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/zoneinfo",
+ "$(BUILT_PRODUCTS_DIR)/private",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\n\"${SCRIPT_INPUT_FILE_0}\" \"${SRCROOT}\" \"${OBJROOT}\" \"${BUILT_PRODUCTS_DIR}\" \"${SDKROOT}\" \"${PLATFORM_NAME}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BA9B767313739D86001BB39F /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/chkpasswd.tproj/chkpasswd.pam",
+ );
+ outputPaths = (
+ "$(DSTROOT)/private/etc/pam.d/chkpasswd",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nmkdir -p \"${DSTROOT}/private/etc/pam.d\"\ncp \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BA9B769C1373A246001BB39F /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/usr/bin/chpass",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/bin/chfn",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nln -fhv \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\nmkdir -p \"${DSTROOT}/usr/share/man/man1\"\necho \".so man1/chpass.1\" > \"${DSTROOT}/usr/share/man/man1/chfn.1\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BA9B76A41373A2A2001BB39F /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/usr/bin/chpass",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/bin/chsh",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nln -fhv \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\nmkdir -p \"${DSTROOT}/usr/share/man/man1\"\necho \".so man1/chpass.1\" > \"${DSTROOT}/usr/share/man/man1/chsh.1\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BAAEB39A13730C41003EA7A9 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ "$(DSTROOT)/private/var/at/at.deny",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nmkdir -p \"${DSTROOT}/private/var/at\"\ninstall -o daemon -d \"${DSTROOT}/private/var/at/spool\"\ntouch \"${DSTROOT}/private/var/at/at.deny\"\nmkdir -p \"${DSTROOT}/usr/lib\"\nln -sf ../../var/at \"${DSTROOT}/usr/lib/cron\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BAAEB39F13730D5C003EA7A9 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/usr/bin/at",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/bin/atq",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nln -fhv \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\nmkdir -p \"${DSTROOT}/usr/share/man/man1\"\necho \".so man1/at.1\" > \"${DSTROOT}/usr/share/man/man1/atq.1\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BAAEB3A813730DFA003EA7A9 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/usr/bin/at",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/bin/atrm",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nln -fhv \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\nmkdir -p \"${DSTROOT}/usr/share/man/man1\"\necho \".so man1/at.1\" > \"${DSTROOT}/usr/share/man/man1/atrm.1\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BAAEB3AF13730E1C003EA7A9 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/usr/bin/at",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/bin/batch",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nln -fhv \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\nmkdir -p \"${DSTROOT}/usr/share/man/man1\"\necho \".so man1/at.1\" > \"${DSTROOT}/usr/share/man/man1/batch.1\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BAE589AD137837130049DD3B /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/pagesize.tproj/pagesize.sh",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/bin/pagesize",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nmkdir -p \"${DSTROOT}/usr/bin\"\ninstall \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BAE589CB1378FCAA0049DD3B /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/passwd.tproj/passwd.pam",
+ );
+ outputPaths = (
+ "$(DSTROOT)/private/etc/pam.d/passwd",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nmkdir -p \"${DSTROOT}/private/etc/pam.d\"\ncp \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BAE589F8137904DF0049DD3B /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/sbin/reboot",
+ );
+ outputPaths = (
+ "$(DSTROOT)/sbin/halt",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nln -fhv \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\nmkdir -p \"${DSTROOT}/usr/share/man/man8\"\necho \".so man8/reboot.8\" > \"${DSTROOT}/usr/share/man/man8/halt.8\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BAE58A2213799FFA0049DD3B /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/sadc.tproj/sa1.sh",
+ "$(SRCROOT)/sadc.tproj/sa2.sh",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/lib/sa/sa1",
+ "$(DSTROOT)/usr/lib/sa/sa2",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ 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;
+ files = (
+ BA0A861313968EAD00D2272C /* zprint.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA473DA11377B2230005CC19 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BACC1CF91377B288007728F4 /* login.c in Sources */,
+ BACC1CFA1377B28C007728F4 /* login_audit.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B79AD1373A4E500003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B79BC1373A51300003422 /* dirhelper.defs in Sources */,
+ BA4B79BD1373A51E00003422 /* dirhelper.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B79C61373A72800003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B79D01373A74F00003422 /* dmesg.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B79D11373A97000003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B79D81373A99200003422 /* backing_store_alerts.defs in Sources */,
+ BA4B79D91373A99600003422 /* backing_store_triggers.defs in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B79E11373AF7A00003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B79EE1373AFFA00003422 /* dynamic_pager.c in Sources */,
+ BA4B79EF1373B00300003422 /* backing_store_alerts.defs in Sources */,
+ BA4B79F01373B00300003422 /* backing_store_triggers.defs in Sources */,
+ BA4B79F11373B00300003422 /* default_pager_alerts.defs in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B79FE1373B9E900003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A081373BA2400003422 /* fs_usage.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A0F1373BE9D00003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A191373BEDD00003422 /* getconf.c in Sources */,
+ BA4B7A291373C30100003422 /* confstr.c in Sources */,
+ BA4B7A2A1373C30100003422 /* limits.c in Sources */,
+ BA4B7A2B1373C30100003422 /* pathconf.c in Sources */,
+ BA4B7A2C1373C30100003422 /* progenv.c in Sources */,
+ BA4B7A2D1373C30100003422 /* sysconf.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A40137648E100003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A511376492600003422 /* chat.c in Sources */,
+ BA4B7A521376492B00003422 /* init.c in Sources */,
+ BA4B7A531376493000003422 /* main.c in Sources */,
+ BA4B7A541376493500003422 /* subr.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A5E13765CC700003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A6713765CF500003422 /* hostinfo.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A6A13765D3E00003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A7313765D5D00003422 /* iostat.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A7E13765F3C00003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A9213765F7C00003422 /* latency.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD2EB1372FB3D0025925C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4FD2FC1372FD670025925C /* ac.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD3051372FFD80025925C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4FD310137300080025925C /* accton.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD31B137300ED0025925C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4FD325137301200025925C /* arch.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD3391373073E0025925C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4FD344137307750025925C /* at.c in Sources */,
+ BA4FD345137307750025925C /* panic.c in Sources */,
+ BA4FD346137307750025925C /* parsetime.c in Sources */,
+ BA4FD347137307750025925C /* perm.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA91CE5A137F42ED00AE5160 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA91CE64137F430E00AE5160 /* kextmanager.defs in Sources */,
+ BA91CE65137F431100AE5160 /* shutdown.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B763A13739ABE001BB39F /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B764E13739B1C001BB39F /* atrun.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B765613739C20001BB39F /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B766513739C66001BB39F /* file_passwd.c in Sources */,
+ BA9B766613739C66001BB39F /* nis_passwd.c in Sources */,
+ BA9B766713739C66001BB39F /* od_passwd.c in Sources */,
+ BA9B766813739C66001BB39F /* pam_passwd.c in Sources */,
+ BA9B766913739C66001BB39F /* passwd.c in Sources */,
+ BA9B766A13739C66001BB39F /* stringops.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B76791373A0D8001BB39F /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B768E1373A14B001BB39F /* chpass.c in Sources */,
+ BA9B768F1373A159001BB39F /* edit.c in Sources */,
+ BA9B76901373A159001BB39F /* field.c in Sources */,
+ BA9B76911373A159001BB39F /* open_directory.c in Sources */,
+ BA9B76921373A159001BB39F /* pw_copy.c in Sources */,
+ BA9B76931373A159001BB39F /* table.c in Sources */,
+ BA9B76941373A159001BB39F /* util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF48B139680CF0018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF496139681090018C7BB /* sync.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4981396812D0018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4A1139681500018C7BB /* sysctl.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4A6139681910018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4B1139682480018C7BB /* trace.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4BF139682BA0018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4C8139682DE0018C7BB /* vifs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4CB139682F80018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4D5139683180018C7BB /* vipw.c in Sources */,
+ BA9BF4D61396831C0018C7BB /* pw_util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4D8139683580018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4E21396838C0018C7BB /* vm_stat.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4E4139683EB0018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4EE139684100018C7BB /* zdump.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4F0139684B40018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4FA139684D30018C7BB /* zic.c in Sources */,
+ BA9BF4FB139684D70018C7BB /* scheck.c in Sources */,
+ BA9BF4FC139684DB0018C7BB /* ialloc.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D021377B3E6007728F4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BACC1D0B1377B413007728F4 /* makekey.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D0E1377B481007728F4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BACC1D171377B4A9007728F4 /* mean.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D3E1377B6E2007728F4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BACC1D471377B71D007728F4 /* mkfile.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D4A1377B7A7007728F4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BACC1D571377B821007728F4 /* newgrp.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D5A1377B85C007728F4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BACC1D631377B88B007728F4 /* nologin.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE5899C137836A00049DD3B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE589A8137836CA0049DD3B /* nvram.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE589BB1378FCAA0049DD3B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE589D11378FD340049DD3B /* passwd.c in Sources */,
+ BAE589D01378FD300049DD3B /* file_passwd.c in Sources */,
+ BAE589D8137900730049DD3B /* nis_passwd.c in Sources */,
+ BAE589D9137900770049DD3B /* od_passwd.c in Sources */,
+ BAE589DA1379007C0049DD3B /* pam_passwd.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE589DC137902F50049DD3B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE589E5137903680049DD3B /* pw_scan.c in Sources */,
+ BAE589E6137903680049DD3B /* pwd_mkdb.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE589E91379044E0049DD3B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE589F3137904B90049DD3B /* reboot.c in Sources */,
+ BAE589F2137904B50049DD3B /* kextmanager.defs in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE58A0A13799F610049DD3B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE58A1313799F950049DD3B /* db.c in Sources */,
+ BAE58A1413799F980049DD3B /* main.c in Sources */,
+ BAE58A1513799F9B0049DD3B /* pdb.c in Sources */,
+ BAE58A1613799F9F0049DD3B /* usrdb.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE58A1913799FFA0049DD3B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE58A271379A0590049DD3B /* sadc.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE58A361379A3F60049DD3B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE58A3F137A59140049DD3B /* sar.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE58A46137D69A60049DD3B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE58A50137D69DA0049DD3B /* sc_usage.c in Sources */,
+ );
+ 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 */;
+ targetProxy = BA0A861513968ECA00D2272C /* PBXContainerItemProxy */;
+ };
+ BA0A861813968ED500D2272C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA0A860713968E8500D2272C /* zprint */;
+ targetProxy = BA0A861713968ED500D2272C /* PBXContainerItemProxy */;
+ };
+ BA0A861A1396B41F00D2272C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA959E7E13968C8E00CA9C60 /* zoneinfo */;
+ targetProxy = BA0A86191396B41F00D2272C /* PBXContainerItemProxy */;
+ };
+ BA0A861C1396B42600D2272C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA959E7E13968C8E00CA9C60 /* zoneinfo */;
+ targetProxy = BA0A861B1396B42600D2272C /* PBXContainerItemProxy */;
+ };
+ BA4B79C41373A58B00003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79AC1373A4E500003422 /* dirhelper */;
+ targetProxy = BA4B79C31373A58B00003422 /* PBXContainerItemProxy */;
+ };
+ BA4B79DB1373A9CE00003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79C51373A72800003422 /* dmesg */;
+ targetProxy = BA4B79DA1373A9CE00003422 /* PBXContainerItemProxy */;
+ };
+ BA4B79DD1373A9CE00003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79D41373A97000003422 /* dp_notify_lib */;
+ targetProxy = BA4B79DC1373A9CE00003422 /* PBXContainerItemProxy */;
+ };
+ BA4B79F81373B06B00003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79E01373AF7A00003422 /* dynamic_pager */;
+ targetProxy = BA4B79F71373B06B00003422 /* PBXContainerItemProxy */;
+ };
+ BA4B7A0C1373BA8D00003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79FD1373B9E900003422 /* fs_usage */;
+ targetProxy = BA4B7A0B1373BA8D00003422 /* PBXContainerItemProxy */;
+ };
+ BA4B7A211373BF5000003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A0E1373BE9D00003422 /* getconf */;
+ targetProxy = BA4B7A201373BF5000003422 /* PBXContainerItemProxy */;
+ };
+ BA4B7A5A137649FA00003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A3F137648E100003422 /* getty */;
+ targetProxy = BA4B7A59137649FA00003422 /* PBXContainerItemProxy */;
+ };
+ BA4B7A7A13765DC100003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A5D13765CC700003422 /* hostinfo */;
+ targetProxy = BA4B7A7913765DC100003422 /* PBXContainerItemProxy */;
+ };
+ BA4B7A7C13765DC600003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A6913765D3E00003422 /* iostat */;
+ targetProxy = BA4B7A7B13765DC600003422 /* PBXContainerItemProxy */;
+ };
+ BA4B7A981376600200003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A7D13765F3C00003422 /* latency */;
+ targetProxy = BA4B7A971376600200003422 /* PBXContainerItemProxy */;
+ };
+ BA4FD3031372FE730025925C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD2EE1372FB3D0025925C /* ac */;
+ targetProxy = BA4FD3021372FE730025925C /* PBXContainerItemProxy */;
+ };
+ BA4FD3121373001C0025925C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD3041372FFD80025925C /* accton */;
+ targetProxy = BA4FD3111373001C0025925C /* PBXContainerItemProxy */;
+ };
+ BA4FD329137301370025925C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD31A137300ED0025925C /* arch */;
+ targetProxy = BA4FD328137301370025925C /* PBXContainerItemProxy */;
+ };
+ BA4FD334137305E80025925C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD31A137300ED0025925C /* arch */;
+ targetProxy = BA4FD333137305E80025925C /* PBXContainerItemProxy */;
+ };
+ BA4FD337137306260025925C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD32F137305DD0025925C /* machine */;
+ targetProxy = BA4FD336137306260025925C /* PBXContainerItemProxy */;
+ };
+ BA4FD350137307BC0025925C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD3381373073E0025925C /* at */;
+ targetProxy = BA4FD34F137307BC0025925C /* PBXContainerItemProxy */;
+ };
+ BA91CE6A137F43A500AE5160 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA91CE59137F42ED00AE5160 /* shutdown */;
+ targetProxy = BA91CE69137F43A500AE5160 /* PBXContainerItemProxy */;
+ };
+ BA959E8813968D8A00CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4BE139682BA0018C7BB /* vifs */;
+ targetProxy = BA959E8713968D8A00CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E8A13968D8A00CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4CA139682F80018C7BB /* vipw */;
+ targetProxy = BA959E8913968D8A00CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E8C13968D8A00CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4D7139683580018C7BB /* vm_stat */;
+ targetProxy = BA959E8B13968D8A00CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E8E13968D8A00CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4E3139683EB0018C7BB /* zdump */;
+ targetProxy = BA959E8D13968D8A00CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E9013968D8A00CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4EF139684B40018C7BB /* zic */;
+ targetProxy = BA959E8F13968D8A00CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E9213968DA900CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4BE139682BA0018C7BB /* vifs */;
+ targetProxy = BA959E9113968DA900CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E9413968DA900CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4CA139682F80018C7BB /* vipw */;
+ targetProxy = BA959E9313968DA900CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E9613968DA900CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4D7139683580018C7BB /* vm_stat */;
+ targetProxy = BA959E9513968DA900CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E9813968DA900CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4E3139683EB0018C7BB /* zdump */;
+ targetProxy = BA959E9713968DA900CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E9A13968DA900CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4EF139684B40018C7BB /* zic */;
+ targetProxy = BA959E9913968DA900CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA9B765413739B89001BB39F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9B763913739ABE001BB39F /* atrun */;
+ targetProxy = BA9B765313739B89001BB39F /* PBXContainerItemProxy */;
+ };
+ BA9B767513739E07001BB39F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9B765513739C20001BB39F /* chkpasswd */;
+ targetProxy = BA9B767413739E07001BB39F /* PBXContainerItemProxy */;
+ };
+ BA9B76A01373A257001BB39F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9B76781373A0D8001BB39F /* chpass */;
+ targetProxy = BA9B769F1373A257001BB39F /* PBXContainerItemProxy */;
+ };
+ BA9B76A21373A2A2001BB39F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9B76781373A0D8001BB39F /* chpass */;
+ targetProxy = BA9B76A31373A2A2001BB39F /* PBXContainerItemProxy */;
+ };
+ BA9B76A81373A2CF001BB39F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9B76781373A0D8001BB39F /* chpass */;
+ targetProxy = BA9B76A71373A2CF001BB39F /* PBXContainerItemProxy */;
+ };
+ BA9B76AA1373A2CF001BB39F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9B76991373A246001BB39F /* chfn */;
+ targetProxy = BA9B76A91373A2CF001BB39F /* PBXContainerItemProxy */;
+ };
+ BA9B76AC1373A2CF001BB39F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9B76A11373A2A2001BB39F /* chsh */;
+ targetProxy = BA9B76AB1373A2CF001BB39F /* PBXContainerItemProxy */;
+ };
+ BA9BF4B3139682710018C7BB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF48A139680CF0018C7BB /* sync */;
+ targetProxy = BA9BF4B2139682710018C7BB /* PBXContainerItemProxy */;
+ };
+ BA9BF4B5139682710018C7BB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4971396812D0018C7BB /* sysctl */;
+ targetProxy = BA9BF4B4139682710018C7BB /* PBXContainerItemProxy */;
+ };
+ BA9BF4B7139682710018C7BB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4A5139681910018C7BB /* trace */;
+ targetProxy = BA9BF4B6139682710018C7BB /* PBXContainerItemProxy */;
+ };
+ BA9BF4B9139682880018C7BB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF48A139680CF0018C7BB /* sync */;
+ targetProxy = BA9BF4B8139682880018C7BB /* PBXContainerItemProxy */;
+ };
+ BA9BF4BB139682880018C7BB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4971396812D0018C7BB /* sysctl */;
+ targetProxy = BA9BF4BA139682880018C7BB /* PBXContainerItemProxy */;
+ };
+ BA9BF4BD139682880018C7BB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4A5139681910018C7BB /* trace */;
+ targetProxy = BA9BF4BC139682880018C7BB /* PBXContainerItemProxy */;
+ };
+ BAAEB3A413730D6B003EA7A9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD3381373073E0025925C /* at */;
+ targetProxy = BAAEB3A313730D6B003EA7A9 /* PBXContainerItemProxy */;
+ };
+ BAAEB3A613730DFA003EA7A9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD3381373073E0025925C /* at */;
+ targetProxy = BAAEB3A713730DFA003EA7A9 /* PBXContainerItemProxy */;
+ };
+ BAAEB3AD13730E1C003EA7A9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD3381373073E0025925C /* at */;
+ targetProxy = BAAEB3AE13730E1C003EA7A9 /* PBXContainerItemProxy */;
+ };
+ BAAEB3B413730E43003EA7A9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAAEB39C13730D5C003EA7A9 /* atq */;
+ targetProxy = BAAEB3B313730E43003EA7A9 /* PBXContainerItemProxy */;
+ };
+ BAAEB3B613730E43003EA7A9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAAEB3A513730DFA003EA7A9 /* atrm */;
+ targetProxy = BAAEB3B513730E43003EA7A9 /* PBXContainerItemProxy */;
+ };
+ BAAEB3B813730E43003EA7A9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAAEB3AC13730E1C003EA7A9 /* batch */;
+ targetProxy = BAAEB3B713730E43003EA7A9 /* PBXContainerItemProxy */;
+ };
+ BACC1D001377B3A4007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA473DA01377B2230005CC19 /* login */;
+ targetProxy = BACC1CFF1377B3A4007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D1C1377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD2EE1372FB3D0025925C /* ac */;
+ targetProxy = BACC1D1B1377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D1E1377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD3041372FFD80025925C /* accton */;
+ targetProxy = BACC1D1D1377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D201377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD31A137300ED0025925C /* arch */;
+ targetProxy = BACC1D1F1377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D221377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD32F137305DD0025925C /* machine */;
+ targetProxy = BACC1D211377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D241377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79C51373A72800003422 /* dmesg */;
+ targetProxy = BACC1D231377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D261377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79D41373A97000003422 /* dp_notify_lib */;
+ targetProxy = BACC1D251377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D281377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79E01373AF7A00003422 /* dynamic_pager */;
+ targetProxy = BACC1D271377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D2A1377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79FD1373B9E900003422 /* fs_usage */;
+ targetProxy = BACC1D291377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D2C1377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A0E1373BE9D00003422 /* getconf */;
+ targetProxy = BACC1D2B1377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D2E1377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A3F137648E100003422 /* getty */;
+ targetProxy = BACC1D2D1377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D301377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A5D13765CC700003422 /* hostinfo */;
+ targetProxy = BACC1D2F1377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D321377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A6913765D3E00003422 /* iostat */;
+ targetProxy = BACC1D311377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D341377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A7D13765F3C00003422 /* latency */;
+ targetProxy = BACC1D331377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D361377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA473DA01377B2230005CC19 /* login */;
+ targetProxy = BACC1D351377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D381377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D011377B3E6007728F4 /* makekey */;
+ targetProxy = BACC1D371377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D3A1377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D0D1377B481007728F4 /* mean */;
+ targetProxy = BACC1D391377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D3C1377B5D9007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D011377B3E6007728F4 /* makekey */;
+ targetProxy = BACC1D3B1377B5D9007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D681377B8DC007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D3D1377B6E2007728F4 /* mkfile */;
+ targetProxy = BACC1D671377B8DC007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D6A1377B8DC007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D491377B7A7007728F4 /* newgrp */;
+ targetProxy = BACC1D691377B8DC007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D6C1377B8DC007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D591377B85C007728F4 /* nologin */;
+ targetProxy = BACC1D6B1377B8DC007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D6E1377B8ED007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D3D1377B6E2007728F4 /* mkfile */;
+ targetProxy = BACC1D6D1377B8ED007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D701377B8ED007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D491377B7A7007728F4 /* newgrp */;
+ targetProxy = BACC1D6F1377B8ED007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D721377B8ED007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D591377B85C007728F4 /* nologin */;
+ targetProxy = BACC1D711377B8ED007728F4 /* PBXContainerItemProxy */;
+ };
+ BAE589B1137837AA0049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE5899B137836A00049DD3B /* nvram */;
+ targetProxy = BAE589B0137837AA0049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE589B3137837AA0049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589AA137837130049DD3B /* pagesize */;
+ targetProxy = BAE589B2137837AA0049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE589B5137837B30049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE5899B137836A00049DD3B /* nvram */;
+ targetProxy = BAE589B4137837B30049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE589B7137837B30049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589AA137837130049DD3B /* pagesize */;
+ targetProxy = BAE589B6137837B30049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE589D41378FDF40049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589BA1378FCAA0049DD3B /* passwd */;
+ targetProxy = BAE589D31378FDF40049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE589D61378FDFB0049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589BA1378FCAA0049DD3B /* passwd */;
+ targetProxy = BAE589D51378FDFB0049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE589FC137905080049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589E81379044E0049DD3B /* reboot */;
+ targetProxy = BAE589FB137905080049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE589FE137905740049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589DB137902F50049DD3B /* pwd_mkdb */;
+ targetProxy = BAE589FD137905740049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A00137905740049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589E81379044E0049DD3B /* reboot */;
+ targetProxy = BAE589FF137905740049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A02137905740049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589F5137904DF0049DD3B /* halt */;
+ targetProxy = BAE58A01137905740049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A041379057F0049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589DB137902F50049DD3B /* pwd_mkdb */;
+ targetProxy = BAE58A031379057F0049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A061379057F0049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589E81379044E0049DD3B /* reboot */;
+ targetProxy = BAE58A051379057F0049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A081379057F0049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589F5137904DF0049DD3B /* halt */;
+ targetProxy = BAE58A071379057F0049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A2E1379A1260049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE58A0913799F610049DD3B /* sa */;
+ targetProxy = BAE58A2D1379A1260049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A301379A1260049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE58A1813799FFA0049DD3B /* sadc */;
+ targetProxy = BAE58A2F1379A1260049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A321379A1300049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE58A0913799F610049DD3B /* sa */;
+ targetProxy = BAE58A311379A1300049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A341379A1300049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE58A1813799FFA0049DD3B /* sadc */;
+ targetProxy = BAE58A331379A1300049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A42137A59300049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE58A351379A3F60049DD3B /* sar */;
+ targetProxy = BAE58A41137A59300049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A44137A59390049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE58A351379A3F60049DD3B /* sar */;
+ targetProxy = BAE58A43137A59390049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A54137D69FB0049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE58A45137D69A60049DD3B /* sc_usage */;
+ targetProxy = BAE58A53137D69FB0049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A56137D6A050049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ 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 = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = zprint;
+ };
+ name = Release;
+ };
+ BA2DE91E1372FA9100D1913C /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BA4FD2FB1372FB710025925C /* BSD.xcconfig */;
+ buildSettings = {
+ APPLY_RULES_IN_COPY_FILES = YES;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ SUPPORTED_PLATFORMS = "macosx iphoneos";
+ WARNING_CFLAGS = (
+ "-Wall",
+ "-Wcast-align",
+ );
+ };
+ name = Release;
+ };
+ BA473DB21377B2230005CC19 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ "GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*][arch=*]" = (
+ "$(inherited)",
+ USE_PAM,
+ USE_BSM_AUDIT,
+ );
+ INSTALL_MODE_FLAG = "u+s,a+rx,a-w";
+ INSTALL_PATH = /usr/bin;
+ "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
+ "-lbsm",
+ "-lpam",
+ );
+ PRODUCT_NAME = login;
+ };
+ name = Release;
+ };
+ BA4B79B91373A4E500003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = dirhelper;
+ };
+ name = Release;
+ };
+ BA4B79CC1373A72800003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = dmesg;
+ };
+ name = Release;
+ };
+ BA4B79D71373A97000003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = lib;
+ OTHER_MIGFLAGS = "-R -untyped -DNO_DIRECT_RPC";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ BA4B79EB1373AF7A00003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ NO_DIRECT_RPC,
+ );
+ INSTALL_PATH = /sbin;
+ OTHER_MIGFLAGS = "-R -untyped -DNO_DIRECT_RPC";
+ PRODUCT_NAME = dynamic_pager;
+ };
+ name = Release;
+ };
+ BA4B7A041373B9E900003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = fs_usage;
+ };
+ name = Release;
+ };
+ BA4B7A151373BE9D00003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ APPLE_GETCONF_UNDERSCORE,
+ APPLE_GETCONF_SPEC,
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = getconf;
+ };
+ name = Release;
+ };
+ BA4B7A4E137648E100003422 /* Release */ = {
+ 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;
+ };
+ BA4B7A6413765CC700003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = hostinfo;
+ };
+ name = Release;
+ };
+ BA4B7A7013765D3E00003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = iostat;
+ };
+ name = Release;
+ };
+ BA4B7A8F13765F3C00003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = latency;
+ };
+ name = Release;
+ };
+ BA4FD2F81372FB3D0025925C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ BA4FD3011372FE4E0025925C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ BA4FD30C1372FFD80025925C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = accton;
+ };
+ name = Release;
+ };
+ BA4FD322137300ED0025925C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = arch;
+ };
+ name = Release;
+ };
+ BA4FD332137305DD0025925C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ BA4FD3401373073E0025925C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "DAEMON_UID=1",
+ "DAEMON_GID=1",
+ "DEFAULT_AT_QUEUE=\\'a\\'",
+ "DEFAULT_BATCH_QUEUE=\\'b\\'",
+ "PERM_PATH=\\\"/usr/lib/cron/\\\"",
+ );
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders";
+ INSTALL_MODE_FLAG = "u+s,a+rx,a-w";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = at;
+ };
+ name = Release;
+ };
+ BA91CE61137F42ED00AE5160 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = shutdown;
+ };
+ name = Release;
+ };
+ BA959E8313968C8E00CA9C60 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = zoneinfo;
+ };
+ name = Release;
+ };
+ BA9B764B13739ABE001BB39F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "DAEMON_UID=1",
+ "DAEMON_GID=1",
+ );
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = atrun;
+ };
+ name = Release;
+ };
+ BA9B766213739C20001BB39F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = chkpasswd;
+ };
+ name = Release;
+ };
+ BA9B768B1373A0D8001BB39F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ OPEN_DIRECTORY,
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = chpass;
+ };
+ name = Release;
+ };
+ BA9B769E1373A246001BB39F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = chfn;
+ };
+ name = Release;
+ };
+ BA9B76A61373A2A2001BB39F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = chsh;
+ };
+ name = Release;
+ };
+ BA9BF491139680CF0018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = sync;
+ };
+ name = Release;
+ };
+ BA9BF49E1396812D0018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = sysctl;
+ };
+ name = Release;
+ };
+ BA9BF4AD139681910018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = trace;
+ };
+ name = Release;
+ };
+ BA9BF4C5139682BA0018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = vifs;
+ };
+ name = Release;
+ };
+ BA9BF4D1139682F80018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = vipw;
+ };
+ name = Release;
+ };
+ BA9BF4DE139683580018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = vm_stat;
+ };
+ name = Release;
+ };
+ BA9BF4EA139683EB0018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = zdump;
+ };
+ name = Release;
+ };
+ BA9BF4F6139684B40018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = zic;
+ };
+ name = Release;
+ };
+ BAAEB3A213730D5C003EA7A9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = atq;
+ };
+ name = Release;
+ };
+ BAAEB3AB13730DFA003EA7A9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = atrm;
+ };
+ name = Release;
+ };
+ BAAEB3B213730E1C003EA7A9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = batch;
+ };
+ name = Release;
+ };
+ BACC1D081377B3E6007728F4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = makekey;
+ };
+ name = Release;
+ };
+ BACC1D141377B481007728F4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = mean;
+ };
+ name = Release;
+ };
+ BACC1D1A1377B4C9007728F4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ BACC1D441377B6E2007728F4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = mkfile;
+ };
+ name = Release;
+ };
+ BACC1D541377B7A7007728F4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_MODE_FLAG = "u+s,a+rx,a-w";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = newgrp;
+ };
+ name = Release;
+ };
+ BACC1D601377B85C007728F4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = nologin;
+ };
+ name = Release;
+ };
+ BAE589A4137836A00049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = nvram;
+ };
+ name = Release;
+ };
+ BAE589AF137837130049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = pagesize;
+ };
+ name = Release;
+ };
+ BAE589CD1378FCAA0049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/bin;
+ "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
+ "-framework",
+ CoreFoundation,
+ "-framework",
+ OpenDirectory,
+ "-lpam",
+ );
+ PRODUCT_NAME = passwd;
+ };
+ name = Release;
+ };
+ BAE589E2137902F50049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "_PW_NAME_LEN=MAXLOGNAME",
+ "_PW_YPTOKEN=\\\"__YP!\\\"",
+ );
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = pwd_mkdb;
+ };
+ name = Release;
+ };
+ BAE589EF1379044E0049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = reboot;
+ };
+ name = Release;
+ };
+ BAE589FA137904DF0049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = halt;
+ };
+ name = Release;
+ };
+ BAE58A1013799F610049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "AHZV1=64",
+ );
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = sa;
+ };
+ name = Release;
+ };
+ BAE58A2413799FFA0049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_MODE_FLAG = "u+s,a+rx,a-w";
+ INSTALL_PATH = /usr/lib/sa;
+ PRODUCT_NAME = sadc;
+ WARNING_CFLAGS = (
+ "$(inherited)",
+ "-Wno-error=deprecated-declarations",
+ );
+ };
+ name = Release;
+ };
+ BAE58A3C1379A3F60049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = sar;
+ };
+ name = Release;
+ };
+ BAE58A4D137D69A60049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = sc_usage;
+ };
+ 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 = (
+ BA0A860F13968E8500D2272C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA2DE91B1372FA9100D1913C /* Build configuration list for PBXProject "system_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA2DE91E1372FA9100D1913C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA473DB11377B2230005CC19 /* Build configuration list for PBXNativeTarget "login" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA473DB21377B2230005CC19 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B79B81373A4E500003422 /* Build configuration list for PBXNativeTarget "dirhelper" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B79B91373A4E500003422 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B79CB1373A72800003422 /* Build configuration list for PBXNativeTarget "dmesg" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B79CC1373A72800003422 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B79D61373A97000003422 /* Build configuration list for PBXNativeTarget "dp_notify_lib" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B79D71373A97000003422 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B79EA1373AF7A00003422 /* Build configuration list for PBXNativeTarget "dynamic_pager" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B79EB1373AF7A00003422 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B7A031373B9E900003422 /* Build configuration list for PBXNativeTarget "fs_usage" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B7A041373B9E900003422 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B7A141373BE9D00003422 /* Build configuration list for PBXNativeTarget "getconf" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B7A151373BE9D00003422 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B7A4D137648E100003422 /* Build configuration list for PBXNativeTarget "getty" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B7A4E137648E100003422 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B7A6313765CC700003422 /* Build configuration list for PBXNativeTarget "hostinfo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B7A6413765CC700003422 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B7A6F13765D3E00003422 /* Build configuration list for PBXNativeTarget "iostat" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B7A7013765D3E00003422 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B7A8E13765F3C00003422 /* Build configuration list for PBXNativeTarget "latency" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B7A8F13765F3C00003422 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4FD2F91372FB3D0025925C /* Build configuration list for PBXNativeTarget "ac" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4FD2F81372FB3D0025925C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4FD2FF1372FE4E0025925C /* Build configuration list for PBXAggregateTarget "All_MacOSX" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4FD3011372FE4E0025925C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4FD30A1372FFD80025925C /* Build configuration list for PBXNativeTarget "accton" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4FD30C1372FFD80025925C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4FD320137300ED0025925C /* Build configuration list for PBXNativeTarget "arch" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4FD322137300ED0025925C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4FD330137305DD0025925C /* Build configuration list for PBXAggregateTarget "machine" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4FD332137305DD0025925C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4FD33E1373073E0025925C /* Build configuration list for PBXNativeTarget "at" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4FD3401373073E0025925C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA91CE60137F42ED00AE5160 /* Build configuration list for PBXNativeTarget "shutdown" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA91CE61137F42ED00AE5160 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA959E8213968C8E00CA9C60 /* Build configuration list for PBXAggregateTarget "zoneinfo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA959E8313968C8E00CA9C60 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9B764A13739ABE001BB39F /* Build configuration list for PBXNativeTarget "atrun" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9B764B13739ABE001BB39F /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9B766113739C20001BB39F /* Build configuration list for PBXNativeTarget "chkpasswd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9B766213739C20001BB39F /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9B768A1373A0D8001BB39F /* Build configuration list for PBXNativeTarget "chpass" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9B768B1373A0D8001BB39F /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9B769D1373A246001BB39F /* Build configuration list for PBXAggregateTarget "chfn" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9B769E1373A246001BB39F /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9B76A51373A2A2001BB39F /* Build configuration list for PBXAggregateTarget "chsh" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9B76A61373A2A2001BB39F /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF490139680CF0018C7BB /* Build configuration list for PBXNativeTarget "sync" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF491139680CF0018C7BB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF49D1396812D0018C7BB /* Build configuration list for PBXNativeTarget "sysctl" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF49E1396812D0018C7BB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF4AC139681910018C7BB /* Build configuration list for PBXNativeTarget "trace" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF4AD139681910018C7BB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF4C4139682BA0018C7BB /* Build configuration list for PBXNativeTarget "vifs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF4C5139682BA0018C7BB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF4D0139682F80018C7BB /* Build configuration list for PBXNativeTarget "vipw" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF4D1139682F80018C7BB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF4DD139683580018C7BB /* Build configuration list for PBXNativeTarget "vm_stat" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF4DE139683580018C7BB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF4E9139683EB0018C7BB /* Build configuration list for PBXNativeTarget "zdump" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF4EA139683EB0018C7BB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF4F5139684B40018C7BB /* Build configuration list for PBXNativeTarget "zic" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF4F6139684B40018C7BB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAAEB3A013730D5C003EA7A9 /* Build configuration list for PBXAggregateTarget "atq" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAAEB3A213730D5C003EA7A9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAAEB3A913730DFA003EA7A9 /* Build configuration list for PBXAggregateTarget "atrm" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAAEB3AB13730DFA003EA7A9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAAEB3B013730E1C003EA7A9 /* Build configuration list for PBXAggregateTarget "batch" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAAEB3B213730E1C003EA7A9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BACC1D071377B3E6007728F4 /* Build configuration list for PBXNativeTarget "makekey" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BACC1D081377B3E6007728F4 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BACC1D131377B481007728F4 /* Build configuration list for PBXNativeTarget "mean" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BACC1D141377B481007728F4 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BACC1D191377B4C9007728F4 /* Build configuration list for PBXAggregateTarget "All_iOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BACC1D1A1377B4C9007728F4 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BACC1D431377B6E2007728F4 /* Build configuration list for PBXNativeTarget "mkfile" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BACC1D441377B6E2007728F4 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BACC1D531377B7A7007728F4 /* Build configuration list for PBXNativeTarget "newgrp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BACC1D541377B7A7007728F4 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BACC1D5F1377B85C007728F4 /* Build configuration list for PBXNativeTarget "nologin" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BACC1D601377B85C007728F4 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE589A3137836A00049DD3B /* Build configuration list for PBXNativeTarget "nvram" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE589A4137836A00049DD3B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE589AE137837130049DD3B /* Build configuration list for PBXAggregateTarget "pagesize" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE589AF137837130049DD3B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE589CC1378FCAA0049DD3B /* Build configuration list for PBXNativeTarget "passwd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE589CD1378FCAA0049DD3B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE589E1137902F50049DD3B /* Build configuration list for PBXNativeTarget "pwd_mkdb" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE589E2137902F50049DD3B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE589EE1379044E0049DD3B /* Build configuration list for PBXNativeTarget "reboot" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE589EF1379044E0049DD3B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE589F9137904DF0049DD3B /* Build configuration list for PBXAggregateTarget "halt" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE589FA137904DF0049DD3B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE58A0F13799F610049DD3B /* Build configuration list for PBXNativeTarget "sa" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE58A1013799F610049DD3B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE58A2313799FFA0049DD3B /* Build configuration list for PBXNativeTarget "sadc" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE58A2413799FFA0049DD3B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE58A3B1379A3F60049DD3B /* Build configuration list for PBXNativeTarget "sar" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE58A3C1379A3F60049DD3B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE58A4C137D69A60049DD3B /* Build configuration list for PBXNativeTarget "sc_usage" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE58A4D137D69A60049DD3B /* Release */,
+ );
+ 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
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:system_cmds.xcodeproj">
+ </FileRef>
+</Workspace>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
+ <false/>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "NO">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "BA4FD2FE1372FE4E0025925C"
+ BuildableName = "All_MacOSX"
+ BlueprintName = "All_MacOSX"
+ ReferencedContainer = "container:system_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release">
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release">
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "NO">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "BACC1D181377B4C9007728F4"
+ BuildableName = "All_iOS"
+ BlueprintName = "All_iOS"
+ ReferencedContainer = "container:system_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release">
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release">
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
--- /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;
+}
--- /dev/null
+.\" Copyright (c) 2010, Apple Inc. All rights reserved.
+.\"
+.Dd October 28, 2010
+.Dt TRACE 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm trace
+.Nd configure and record kernel trace events
+.Sh SYNOPSIS
+.Nm trace
+.Fl h
+.Pp
+.Nm trace
+.Fl i
+.Op Fl b Ar numbufs
+.Pp
+.Nm trace
+.Fl g
+.Pp
+.Nm trace
+.Fl d
+.Op Fl a Ar pid | Fl x Ar pid
+.Pp
+.Nm trace
+.Fl r
+.Pp
+.Nm trace
+.Fl n
+.Pp
+.Nm trace
+.Fl e
+.Op Fl c Ar class Oo Fl p Ar class Oc Oo Fl s Ar subclass Oc
+.Op Fl a Ar pid | Fl x Ar pid
+.Op Fl k Ar code | Fl k Ar code | Fl k Ar code | Fl k Ar code
+.Pp
+.Nm trace
+.Fl E
+.Op Fl c Ar class Oo Fl p Ar class Oc Oo Fl s Ar subclass Oc
+.Op Fl a Ar pid | Fl x Ar pid
+.Op Fl k Ar code | Fl k Ar code | Fl k Ar code | Fl k Ar code
+.Ar executable_path
+.Op Ar optional args to executable
+.Pp
+.Nm trace
+.Fl t
+.Op Fl R Ar rawfile
+.Op Fl o Ar OutputFilename
+.Op Fl N
+.Op Ar ExtraCodeFilename1 ExtraCodeFilename2 ...
+.Sh DESCRIPTION
+The
+.Nm trace
+command allows developers to initialize and configure
+the kernel trace subsystem. Trace events can be recorded
+to an in-memory buffer, or logged directly to a file. Raw
+data files can later be decoded to a plaintext format.
+.Sh SEE ALSO
+.Xr fs_usage 1 ,
+.Xr sc_usage 1 ,
+.Xr latency 1 ,
+.Xr top 1
--- /dev/null
+/*
+ cc -I/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders -arch x86_64 -arch i386 -O -o trace trace.c
+*/
+
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mbuf.h>
+#include <sys/mman.h>
+#include <sys/ucred.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#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 nbufs = 0;
+int enable_flag=0;
+int execute_flag=0;
+int logRAW_flag=0;
+int LogRAW_flag=0;
+int readRAW_flag = 0;
+int disable_flag=0;
+int init_flag=0;
+int kval_flag=0;
+int remove_flag=0;
+int bufset_flag=0;
+int bufget_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;
+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;
+
+int force_32bit_exec = 0;
+int frequency = 0;
+
+int mib[6];
+size_t needed;
+
+char *logfile = (char *)0; /* This file is trace format */
+char *RAW_file = (char *)0;
+FILE *output_file;
+int output_fd;
+
+extern char **environ;
+
+uint8_t* type_filter_bitmap;
+
+
+#define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
+#define DBG_FUNC_MASK 0xfffffffc
+#define SHORT_HELP 1
+#define LONG_HELP 0
+
+#define CSC_MASK 0xffff0000
+
+#define VFS_LOOKUP 0x03010090
+#define BSC_exit 0x040c0004
+#define BSC_thread_terminate 0x040c05a4
+#define TRACE_DATA_NEWTHREAD 0x07000004
+#define TRACE_STRING_NEWTHREAD 0x07010004
+#define TRACE_STRING_EXEC 0x07010008
+#define TRACE_LOST_EVENTS 0x07020008
+#define MACH_SCHEDULED 0x01400000
+#define MACH_MAKERUNNABLE 0x01400018
+#define MACH_STKHANDOFF 0x01400008
+
+#define EMPTYSTRING ""
+#define UNKNOWN "unknown"
+
+char tmpcommand[MAXCOMLEN];
+
+int total_threads = 0;
+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
+ This is for the vfslookup entries that
+ return pathnames
+*/
+#define NUMPARMS 23
+#define PATHLENGTH (NUMPARMS*sizeof(long))
+
+
+#define US_TO_SLEEP 50000
+#define BASE_EVENTS 500000
+
+
+double divisor;
+
+typedef struct {
+ uint32_t debugid;
+ char *debug_string;
+} code_type_t;
+
+code_type_t* codesc = 0;
+size_t codesc_idx = 0; // Index into first empty codesc entry
+
+
+
+typedef struct event *event_t;
+
+struct event {
+ event_t ev_next;
+
+ uintptr_t ev_thread;
+ uint32_t ev_debugid;
+ uint64_t ev_timestamp;
+};
+
+typedef struct lookup *lookup_t;
+
+struct lookup {
+ lookup_t lk_next;
+
+ uintptr_t lk_thread;
+ uintptr_t lk_dvp;
+ long *lk_pathptr;
+ long lk_pathname[NUMPARMS + 1];
+};
+
+typedef struct threadmap *threadmap_t;
+
+struct threadmap {
+ threadmap_t tm_next;
+
+ uintptr_t tm_thread;
+ uintptr_t tm_pthread;
+ boolean_t tm_deleteme;
+ char tm_command[MAXCOMLEN + 1];
+};
+
+
+#define HASH_SIZE 1024
+#define HASH_MASK 1023
+
+event_t event_hash[HASH_SIZE];
+lookup_t lookup_hash[HASH_SIZE];
+threadmap_t threadmap_hash[HASH_SIZE];
+
+event_t event_freelist;
+lookup_t lookup_freelist;
+threadmap_t threadmap_freelist;
+threadmap_t threadmap_temp;
+
+
+#define SBUFFER_SIZE (128 * 4096)
+char sbuffer[SBUFFER_SIZE];
+
+int secs_to_run = 0;
+int use_current_buf = 0;
+
+
+kbufinfo_t bufinfo = {0, 0, 0, 0};
+
+int codenum = 0;
+int codeindx_cache = 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(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 unsigned long argtoul();
+
+static void set_enable(int);
+static void set_remove();
+static void set_nowrap();
+static void set_pidcheck(int, int);
+static void set_pidexclude(int, int);
+static void set_numbufs(int);
+static void set_freerun();
+static void get_bufinfo(kbufinfo_t *);
+static void set_init();
+static void set_kval_list();
+static void readtrace(char *);
+static void log_trace();
+static void Log_trace();
+static void read_trace();
+static void signal_handler(int);
+static void signal_handler_RAW(int);
+static void delete_thread_entry(uintptr_t);
+static void find_and_insert_tmp_map_entry(uintptr_t, char *);
+static void create_tmp_map_entry(uintptr_t, uintptr_t);
+static void find_thread_name(uintptr_t, char **, boolean_t);
+
+static int writetrace(int);
+static int write_command_map(int);
+static int debugid_compar(code_type_t *, code_type_t *);
+
+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
+#endif
+
+#ifndef KERN_KDWRITEMAP
+#define KERN_KDWRITEMAP 18
+#endif
+
+#ifndef F_FLUSH_DATA
+#define F_FLUSH_DATA 40
+#endif
+
+#ifndef RAW_VERSION1
+typedef struct {
+ int version_no;
+ int thread_count;
+ uint64_t TOD_secs;
+ uint32_t TOD_usecs;
+} RAW_header;
+
+#define RAW_VERSION0 0x55aa0000
+#define RAW_VERSION1 0x55aa0101
+#endif
+
+#define 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;
+
+
+
+void set_enable(int val)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDENABLE;
+#ifdef KDEBUG_ENABLE_PPT
+ if (ppt_flag && val) {
+ mib[3] = KDEBUG_ENABLE_PPT;
+ } else {
+ mib[3] = val;
+ }
+#else
+ mib[3] = val;
+#endif
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KERN_KDENABLE: %s\n", strerror(errno));
+}
+
+void set_remove()
+{
+ extern int errno;
+
+ errno = 0;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDREMOVE;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
+ {
+ 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_args("trace facility failure, KERN_KDREMOVE: %s\n", strerror(errno));
+ }
+}
+
+void set_numbufs(int nbufs)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETBUF;
+ mib[3] = nbufs;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KERN_KDSETBUF: %s\n", strerror(errno));
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETUP;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno));
+}
+
+void set_nowrap()
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDEFLAGS;
+ mib[3] = KDBG_NOWRAP;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KDBG_NOWRAP: %s\n", strerror(errno));
+
+}
+
+void set_pidcheck(int pid, int on_off_flag)
+{
+ kd_regtype kr;
+
+ kr.type = KDBG_TYPENONE;
+ kr.value1 = pid;
+ kr.value2 = on_off_flag;
+ needed = sizeof(kd_regtype);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDPIDTR;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
+ {
+ if (on_off_flag == 1)
+ {
+ printf("trace facility failure, KERN_KDPIDTR,\n\tpid %d does not exist\n", pid);
+ set_remove();
+ exit(2);
+ }
+ }
+}
+
+void set_pidexclude(int pid, int on_off_flag)
+{
+ kd_regtype kr;
+
+ kr.type = KDBG_TYPENONE;
+ kr.value1 = pid;
+ kr.value2 = on_off_flag;
+ needed = sizeof(kd_regtype);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDPIDEX;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
+ {
+ if (on_off_flag == 1)
+ {
+ printf ("pid %d does not exist\n", pid);
+ set_remove();
+ exit(2);
+ }
+ }
+}
+
+void set_freerun()
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDEFLAGS;
+ mib[3] = KDBG_FREERUN;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KDBG_FREERUN: %s\n", strerror(errno));
+}
+
+void get_bufinfo(kbufinfo_t *val)
+{
+ needed = sizeof (*val);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDGETBUF;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, val, &needed, 0, 0) < 0)
+ quit_args("trace facility failure, KERN_KDGETBUF: %s\n", strerror(errno));
+}
+
+void set_init()
+{
+ kd_regtype kr;
+
+ kr.type = KDBG_RANGETYPE;
+ kr.value1 = 0;
+ kr.value2 = -1;
+ needed = sizeof(kd_regtype);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETREG;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KERN_KDSETREG (rangetype): %s\n", strerror(errno));
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETUP;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno));
+}
+
+
+static void
+set_filter(void)
+{
+ 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()
+{
+ kd_regtype kr;
+
+ kr.type = KDBG_VALCHECK;
+ kr.value1 = value1;
+ kr.value2 = value2;
+ kr.value3 = value3;
+ kr.value4 = value4;
+ 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_args("trace facility failure, KERN_KDSETREG (valcheck): %s\n", strerror(errno));
+}
+
+
+void readtrace(char *buffer)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDREADTR;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+
+ if (sysctl(mib, 3, buffer, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno));
+}
+
+
+int writetrace(int fd)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDWRITETR;
+ mib[3] = fd;
+ mib[4] = 0;
+ mib[5] = 0;
+
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ return 1;
+
+ return 0;
+}
+
+
+int write_command_map(int fd)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDWRITEMAP;
+ mib[3] = fd;
+ mib[4] = 0;
+ mib[5] = 0;
+
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ return 1;
+
+ return 0;
+}
+
+
+static
+lookup_t handle_lookup_event(uintptr_t thread, int debugid, kd_buf *kdp)
+{
+ lookup_t lkp;
+ int hashid;
+ boolean_t first_record = FALSE;
+
+ hashid = thread & HASH_MASK;
+
+ if (debugid & DBG_FUNC_START)
+ first_record = TRUE;
+
+ for (lkp = lookup_hash[hashid]; lkp; lkp = lkp->lk_next) {
+ if (lkp->lk_thread == thread)
+ break;
+ }
+ if (lkp == NULL) {
+ if (first_record == FALSE)
+ return (0);
+
+ if ((lkp = lookup_freelist))
+ lookup_freelist = lkp->lk_next;
+ else
+ lkp = (lookup_t)malloc(sizeof(struct lookup));
+
+ lkp->lk_thread = thread;
+
+ lkp->lk_next = lookup_hash[hashid];
+ lookup_hash[hashid] = lkp;
+ }
+
+ if (first_record == TRUE) {
+ lkp->lk_pathptr = lkp->lk_pathname;
+ lkp->lk_dvp = kdp->arg1;
+ } else {
+ if (lkp->lk_pathptr > &lkp->lk_pathname[NUMPARMS-4])
+ return (lkp);
+
+ *lkp->lk_pathptr++ = kdp->arg1;
+ }
+ *lkp->lk_pathptr++ = kdp->arg2;
+ *lkp->lk_pathptr++ = kdp->arg3;
+ *lkp->lk_pathptr++ = kdp->arg4;
+ *lkp->lk_pathptr = 0;
+
+ return (lkp);
+}
+
+
+static
+void delete_lookup_event(uintptr_t thread, lookup_t lkp_to_delete)
+{
+ lookup_t lkp;
+ lookup_t lkp_prev;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ if ((lkp = lookup_hash[hashid])) {
+ if (lkp == lkp_to_delete)
+ lookup_hash[hashid] = lkp->lk_next;
+ else {
+ lkp_prev = lkp;
+
+ for (lkp = lkp->lk_next; lkp; lkp = lkp->lk_next) {
+ if (lkp == lkp_to_delete) {
+ lkp_prev->lk_next = lkp->lk_next;
+ break;
+ }
+ lkp_prev = lkp;
+ }
+ }
+ if (lkp) {
+ lkp->lk_next = lookup_freelist;
+ lookup_freelist = lkp;
+ }
+ }
+}
+
+
+static
+void insert_start_event(uintptr_t thread, int debugid, uint64_t now)
+{
+ event_t evp;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ for (evp = event_hash[hashid]; evp; evp = evp->ev_next) {
+ if (evp->ev_thread == thread && evp->ev_debugid == debugid)
+ break;
+ }
+ if (evp == NULL) {
+ if ((evp = event_freelist))
+ event_freelist = evp->ev_next;
+ else
+ evp = (event_t)malloc(sizeof(struct event));
+
+ evp->ev_thread = thread;
+ evp->ev_debugid = debugid;
+
+ evp->ev_next = event_hash[hashid];
+ event_hash[hashid] = evp;
+ }
+ evp->ev_timestamp = now;
+}
+
+
+static
+uint64_t consume_start_event(uintptr_t thread, int debugid, uint64_t now)
+{
+ event_t evp;
+ event_t evp_prev;
+ int hashid;
+ uint64_t elapsed = 0;
+
+ hashid = thread & HASH_MASK;
+
+ if ((evp = event_hash[hashid])) {
+ if (evp->ev_thread == thread && evp->ev_debugid == debugid)
+ event_hash[hashid] = evp->ev_next;
+ else {
+ evp_prev = evp;
+
+ for (evp = evp->ev_next; evp; evp = evp->ev_next) {
+
+ if (evp->ev_thread == thread && evp->ev_debugid == debugid) {
+ evp_prev->ev_next = evp->ev_next;
+ break;
+ }
+ evp_prev = evp;
+ }
+ }
+ if (evp) {
+ elapsed = now - evp->ev_timestamp;
+
+ evp->ev_next = event_freelist;
+ event_freelist = evp;
+ }
+ }
+ return (elapsed);
+}
+
+
+void
+log_trace()
+{
+ char *buffer;
+ uint32_t buffer_size;
+ int fd;
+ int size;
+ int pad_size;
+ char pad_buf[4096];
+
+
+ if ((fd = open(logfile, O_TRUNC|O_WRONLY|O_CREAT, 0777)) == -1) {
+ perror("Can't open logfile");
+ exit(1);
+ }
+ get_bufinfo(&bufinfo);
+
+ if (bufinfo.nolog != 1) {
+ reenable = 1;
+ set_enable(0); /* disable logging*/
+ }
+ get_bufinfo(&bufinfo);
+
+ if (verbose_flag) {
+ if (bufinfo.flags & KDBG_WRAPPED)
+ printf("Buffer has wrapped\n");
+ else
+ printf("Buffer has not wrapped\n");
+ }
+ buffer_size = 1000000 * sizeof(kd_buf);
+ buffer = malloc(buffer_size);
+
+ if (buffer == (char *) 0)
+ 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;
+ raw_header.TOD_secs = time((long *)0);
+ raw_header.TOD_usecs = 0;
+
+ write(fd, &raw_header, sizeof(RAW_header));
+
+ size = total_threads * sizeof(kd_threadmap);
+ 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 (;;) {
+ needed = buffer_size;
+
+ readtrace(buffer);
+
+ if (needed == 0)
+ break;
+ write(fd, buffer, needed * sizeof(kd_buf));
+ }
+ close(fd);
+}
+
+
+void
+Log_trace()
+{
+ int size;
+ kd_buf kd_tmp;
+ size_t len;
+ int num_cpus;
+ int try_writetrace = 1;
+ int fd;
+ char *buffer;
+ kd_buf *kd;
+ uint64_t sample_window_abs;
+ uint64_t next_window_begins;
+ uint64_t current_abs;
+ uint64_t ending_abstime;
+ uint64_t last_time_written;
+ uint32_t us_to_sleep;
+ uint32_t us_to_adjust;
+ uint32_t ms_to_run;
+
+ memset(&kd_tmp, 0, sizeof(kd_tmp));
+
+ if ((fd = open(logfile, O_TRUNC|O_WRONLY|O_CREAT, 0777)) == -1) {
+ perror("Can't open logfile");
+ exit(1);
+ }
+ if (use_current_buf == 0) {
+ /*
+ * grab the number of cpus and scale the buffer size
+ */
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ mib[2] = 0;
+ len = sizeof(num_cpus);
+
+ sysctl(mib, 2, &num_cpus, &len, NULL, 0);
+
+ if (!bufset_flag)
+ nbufs = BASE_EVENTS * num_cpus;
+
+ set_remove();
+ set_numbufs(nbufs);
+ set_init();
+
+ if (filter_flag)
+ set_filter();
+
+ if (kval_flag)
+ set_kval_list();
+ }
+ /* Get kernel buffer information */
+ get_bufinfo(&bufinfo);
+
+ buffer = malloc(bufinfo.nkdbufs * sizeof(kd_buf));
+ if (buffer == (char *) 0)
+ quit("can't allocate memory for tracing info\n");
+ memset(buffer, 0, bufinfo.nkdbufs * sizeof(kd_buf));
+
+ if (use_current_buf == 0)
+ set_enable(1);
+
+ if (write_command_map(fd)) {
+ int pad_size;
+ 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;
+ raw_header.TOD_secs = time((long *)0);
+ raw_header.TOD_usecs = 0;
+
+ write(fd, &raw_header, sizeof(RAW_header));
+
+ size = total_threads * sizeof(kd_threadmap);
+ 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);
+ }
+ sample_window_abs = (uint64_t)((double)US_TO_SLEEP * divisor);
+
+ next_window_begins = mach_absolute_time() + sample_window_abs;
+
+ if (secs_to_run) {
+ ending_abstime = mach_absolute_time() + (uint64_t)((double)secs_to_run * (double)1000000 * divisor);
+ ms_to_run = secs_to_run * 1000;
+ } else
+ ms_to_run = 0;
+ last_time_written = mach_absolute_time();
+
+ while (LogRAW_flag) {
+ current_abs = mach_absolute_time();
+
+ if (try_writetrace) {
+ needed = ms_to_run;
+
+ if (writetrace(fd))
+ try_writetrace = 0;
+ else {
+ if (needed) {
+ current_abs = mach_absolute_time();
+
+ printf("wrote %d events - elapsed time = %.1f secs\n",
+ (int)needed, ((double)(current_abs - last_time_written) / divisor) / 1000000);
+
+ last_time_written = current_abs;
+ }
+ }
+ }
+ if (try_writetrace == 0) {
+
+ if (next_window_begins > current_abs)
+ us_to_adjust = US_TO_SLEEP - (uint32_t)((double)(next_window_begins - current_abs) / divisor);
+ else
+ us_to_adjust = US_TO_SLEEP;
+
+ next_window_begins = current_abs + sample_window_abs;
+
+ us_to_sleep = US_TO_SLEEP - us_to_adjust;
+
+ next_window_begins = current_abs + (uint64_t)((double)(us_to_sleep + US_TO_SLEEP) * divisor);
+
+ if (us_to_sleep)
+ usleep(us_to_sleep);
+
+ get_bufinfo(&bufinfo);
+
+ if (bufinfo.flags & KDBG_WRAPPED)
+ printf("lost events\n");
+
+ needed = bufinfo.nkdbufs * sizeof(kd_buf);
+
+ readtrace(buffer);
+
+ if (bufinfo.flags & KDBG_WRAPPED) {
+
+ kd = (kd_buf *) buffer;
+
+ kd_tmp.timestamp = kd[0].timestamp;
+ kd_tmp.debugid = TRACE_LOST_EVENTS;
+
+ write(fd, &kd_tmp, sizeof(kd_tmp));
+ }
+ write(fd, buffer, needed * sizeof(kd_buf));
+
+ if (verbose_flag && needed > nbufs)
+ printf("needed = %ld\n", needed);
+ }
+ if (secs_to_run) {
+ current_abs = mach_absolute_time();
+
+ if (current_abs > ending_abstime)
+ break;
+ ms_to_run = (ending_abstime - current_abs) / (1000 * 1000);
+
+ if (ms_to_run == 0)
+ break;
+ }
+ }
+ set_enable(0);
+ set_numbufs(0);
+ set_remove();
+
+ close(fd);
+}
+
+
+void read_trace()
+{
+ char *buffer;
+ uint32_t buffer_size;
+ kd_buf *kd;
+ int fd;
+ int firsttime = 1;
+ int lines = 0;
+ int io_lines = 0;
+ uint64_t bias = 0;
+ uint32_t count_of_names;
+ double last_event_time = 0.0;
+ time_t trace_time;
+
+ if (!readRAW_flag) {
+ get_bufinfo(&bufinfo);
+
+ if (bufinfo.nolog != 1) {
+ reenable = 1;
+ set_enable(0); /* disable logging*/
+ }
+ if (verbose_flag) {
+ if (bufinfo.flags & KDBG_WRAPPED)
+ printf("Buffer has wrapped\n");
+ else
+ printf("Buffer has not wrapped\n");
+ }
+ fd = 0;
+ count_of_names = 0;
+
+ } else {
+ fd = open(RAW_file, O_RDONLY);
+
+ if (fd < 0) {
+ perror("Can't open file");
+ exit(1);
+ }
+ if (read(fd, &raw_header, sizeof(RAW_header)) != sizeof(RAW_header)) {
+ perror("read failed");
+ exit(2);
+ }
+ if (raw_header.version_no != RAW_VERSION1) {
+ raw_header.version_no = RAW_VERSION0;
+ raw_header.TOD_secs = time((long *)0);
+ raw_header.TOD_usecs = 0;
+
+ lseek(fd, (off_t)0, SEEK_SET);
+
+ if (read(fd, &raw_header.thread_count, sizeof(int)) != sizeof(int)) {
+ perror("read failed");
+ exit(2);
+ }
+ }
+ count_of_names = raw_header.thread_count;
+ trace_time = (time_t) (raw_header.TOD_secs);
+
+ printf("%s\n", ctime(&trace_time));
+ }
+ buffer_size = 1000000 * sizeof(kd_buf);
+ buffer = malloc(buffer_size);
+
+ if (buffer == (char *) 0)
+ quit("can't allocate memory for tracing info\n");
+
+ kd = (kd_buf *)buffer;
+
+ read_command_map(fd, count_of_names);
+ read_cpu_map(fd);
+
+ for (;;) {
+ uint32_t count;
+ uint64_t now = 0;
+ uint64_t prev;
+ uint64_t prevdelta;
+ uint32_t cpunum;
+ uintptr_t thread;
+ double x = 0.0;
+ double y = 0.0;
+ double event_elapsed_time;
+ kd_buf *kdp;
+ lookup_t lkp;
+ boolean_t ending_event;
+ int i;
+ int debugid;
+ int debugid_base;
+ int dmsgindex;
+ char dbgmessge[80];
+ char outbuf[32];
+ char *command;
+
+ if (!readRAW_flag) {
+ needed = buffer_size;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDREADTR;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, buffer, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno));
+
+ if (needed == 0)
+ break;
+ count = needed;
+
+ } else {
+ uint32_t bytes_read;
+
+ bytes_read = read(fd, buffer, buffer_size);
+
+ if (bytes_read == -1) {
+ perror("read failed");
+ exit(2);
+ }
+ count = bytes_read / sizeof(kd_buf);
+
+ if (count == 0)
+ break;
+ }
+ for (kdp = &kd[0], i = 0; i < count; i++, kdp++) {
+
+ prev = now;
+ debugid = kdp->debugid;
+ debugid_base = debugid & DBG_FUNC_MASK;
+ now = kdp->timestamp & KDBG_TIMESTAMP_MASK;
+
+ if (firsttime)
+ bias = now;
+ now -= bias;
+
+ cpunum = kdbg_get_cpu(kdp);
+ thread = kdp->arg5;
+
+ if (lines == 64 || firsttime)
+ {
+ prevdelta = now - prevdelta;
+
+ if (firsttime)
+ firsttime = 0;
+ else {
+ x = (double)prevdelta;
+ x /= divisor;
+
+ fprintf(output_file, "\n\nNumber of microsecs since in last page %8.1f\n", x);
+ }
+ prevdelta = now;
+
+ /*
+ * Output description row to output file (make sure to format correctly for 32-bit and 64-bit)
+ */
+ fprintf(output_file,
+#ifdef __LP64__
+ " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
+#else
+ " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
+#endif
+ );
+
+ lines = 0;
+
+ if (io_lines > 15000) {
+ fcntl(output_fd, F_FLUSH_DATA, 0);
+
+ io_lines = 0;
+ }
+ }
+ lkp = 0;
+
+ if (debugid_base == VFS_LOOKUP) {
+ lkp = handle_lookup_event(thread, debugid, kdp);
+
+ if ( !lkp || !(debugid & DBG_FUNC_END))
+ continue;
+ }
+ x = (double)now;
+ x /= divisor;
+
+ if (last_event_time)
+ y = x - last_event_time;
+ else
+ y = x;
+ last_event_time = x;
+ ending_event = FALSE;
+
+ /*
+ * 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.
+ * Print them only if in verbose mode.
+ */
+ if (!verbose_flag)
+ {
+ /* Is this entry of Class DBG_TRACE */
+ if ((debugid >> 24) == DBG_TRACE) {
+ if (((debugid >> 16) & 0xff) != DBG_TRACE_INFO)
+ continue;
+ }
+ }
+ if ( !lkp) {
+ int t_debugid;
+ int t_thread;
+
+ if ((debugid & DBG_FUNC_START) || debugid == MACH_MAKERUNNABLE) {
+
+ if (debugid_base != BSC_thread_terminate && debugid_base != BSC_exit) {
+
+ if (debugid == MACH_MAKERUNNABLE)
+ t_thread = kdp->arg1;
+ else
+ t_thread = thread;
+
+ insert_start_event(t_thread, debugid_base, now);
+ }
+
+ } else if ((debugid & DBG_FUNC_END) || debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED) {
+
+ if (debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED) {
+ t_debugid = MACH_MAKERUNNABLE;
+ t_thread = kdp->arg2;
+ } else {
+ t_debugid = debugid_base;
+ t_thread = thread;
+ }
+ event_elapsed_time = (double)consume_start_event(t_thread, t_debugid, now);
+ event_elapsed_time /= divisor;
+ ending_event = TRUE;
+
+ if (event_elapsed_time == 0 && (debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED))
+ ending_event = FALSE;
+ }
+ }
+ if (ending_event) {
+ char *ch;
+
+ sprintf(&outbuf[0], "(%-10.1f)", event_elapsed_time);
+ /*
+ * fix that right paren
+ */
+ ch = &outbuf[11];
+
+ if (*ch != ')') {
+ ch = strchr (&outbuf[0], ')');
+ }
+ if (ch)
+ {
+ *ch = ' ';
+ --ch;
+
+ while (ch != &outbuf[0])
+ {
+ if (*ch == ' ')
+ --ch;
+ else
+ {
+ *(++ch) = ')';
+ break;
+ }
+ }
+ }
+ }
+ if (match_debugid(debugid_base, dbgmessge, &dmsgindex)) {
+ if (ending_event)
+ fprintf(output_file, "%13.1f %10.1f%s %-28x ", x, y, outbuf, debugid_base);
+ else
+ fprintf(output_file, "%13.1f %10.1f %-28x ", x, y, debugid_base);
+ } else {
+ if (ending_event)
+ fprintf(output_file, "%13.1f %10.1f%s %-28.28s ", x, y, outbuf, dbgmessge);
+ else
+ fprintf(output_file, "%13.1f %10.1f %-28.28s ", x, y, dbgmessge);
+ }
+ if (lkp) {
+ char *strptr;
+ int len;
+
+ strptr = (char *)lkp->lk_pathname;
+
+ /*
+ * print the tail end of the pathname
+ */
+ len = strlen(strptr);
+ if (len > 51)
+ len -= 51;
+ else
+ len = 0;
+#ifdef __LP64__
+
+ fprintf(output_file, "%-16lx %-51s %-16lx %-2d %s\n", lkp->lk_dvp, &strptr[len], thread, cpunum, command);
+#else
+ fprintf(output_file, "%-8x %-51s %-8lx %-2d %s\n", (unsigned int)lkp->lk_dvp, &strptr[len], thread, cpunum, command);
+#endif
+ delete_lookup_event(thread, lkp);
+ } else {
+#ifdef __LP64__
+ fprintf(output_file, "%-16lx %-16lx %-16lx %-16lx %-16lx %-2d %s\n", kdp->arg1, kdp->arg2, kdp->arg3, kdp->arg4, thread, cpunum, command);
+#else
+ fprintf(output_file, "%-8lx %-8lx %-8lx %-8lx %-8lx %-2d %s\n", kdp->arg1, kdp->arg2, kdp->arg3, kdp->arg4, thread, cpunum, command);
+#endif
+ }
+ lines++;
+ io_lines++;
+ }
+ }
+ if (reenable == 1)
+ set_enable(1); /* re-enable kernel logging */
+}
+
+
+
+void signal_handler(int sig)
+{
+ ptrace(PT_KILL, pid, (caddr_t)0, 0);
+ /*
+ * child is gone; no need to disable the pid
+ */
+ exit(2);
+}
+
+
+void signal_handler_RAW(int sig)
+{
+ LogRAW_flag = 0;
+}
+
+
+
+int main(argc, argv, env)
+int argc;
+char **argv;
+char **env;
+{
+ extern char *optarg;
+ extern int optind;
+ int status;
+ 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) {
+ force_32bit_exec = 1;
+ break;
+ }
+ }
+ if (force_32bit_exec) {
+ if (0 != reexec_to_match_lp64ness(FALSE)) {
+ fprintf(stderr, "Could not re-execute: %d\n", errno);
+ exit(1);
+ }
+ } else {
+ if (0 != reexec_to_match_kernel()) {
+ fprintf(stderr, "Could not re-execute: %d\n", errno);
+ exit(1);
+ }
+ }
+ if (setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_PASSIVE) < 0) {
+ printf("setiopolicy failed\n");
+ exit(1);
+ }
+ output_file = stdout;
+ output_fd = 1;
+
+ 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_flag=1;
+ break;
+ case 'S':
+ secs_to_run = argtoi('S', "decimal number", optarg, 10);
+ break;
+ case 'a': /* set tracing on a pid */
+ pid_flag=1;
+ pid = argtoi('a', "decimal number", optarg, 10);
+ break;
+ case 'x': /* exclude a pid from tracing */
+ pid_exflag=1;
+ pid = argtoi('x', "decimal number", optarg, 10);
+ break;
+ case 'v':
+ verbose_flag=1;
+ break;
+ case 'l':
+ logRAW_flag = 1;
+ logfile = optarg;
+ break;
+ case 'L':
+ LogRAW_flag = 1;
+ logfile = optarg;
+ signal(SIGINT, signal_handler_RAW);
+ break;
+ case 'e':
+ enable_flag = 1;
+ break;
+ case 'i':
+ init_flag = 1;
+ break;
+ case 'E':
+ execute_flag = 1;
+ break;
+ case 'd':
+ disable_flag = 1;
+ break;
+ case 'k':
+ if (kval_flag == 0)
+ value1 = (unsigned int) argtoul('k', "hex number", optarg, 16);
+ else if (kval_flag == 1)
+ value2 = (unsigned int) argtoul('k', "hex number", optarg, 16);
+ else if (kval_flag == 2)
+ value3 = (unsigned int) argtoul('k', "hex number", optarg, 16);
+ else if (kval_flag == 3)
+ value4 = (unsigned int) argtoul('k', "hex number", optarg, 16);
+ else
+ {
+ fprintf(stderr, "A maximum of four values can be specified with -k\n");
+ usage(SHORT_HELP);
+ }
+ kval_flag++;
+ break;
+ case 'r':
+ remove_flag = 1;
+ break;
+ case 'g':
+ bufget_flag = 1;
+ break;
+ case 't':
+ trace_flag = 1;
+ break;
+ case 'R':
+ readRAW_flag = 1;
+ RAW_file = optarg;
+ break;
+ case 'n':
+ nowrap_flag = 1;
+ break;
+ case 'f':
+ freerun_flag = 1;
+ break;
+ case 'b':
+ bufset_flag = 1;
+ nbufs = argtoi('b', "decimal number", optarg, 10);
+ break;
+ case 'c':
+ 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':
+ 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':
+ 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 'o':
+ output_filename = optarg;
+ break;
+ case 'F':
+ frequency = argtoi('F', "decimal number", optarg, 10);
+ 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)
+ {
+ while (argc--)
+ {
+ const char *cfile = argv[optind++];
+ if (verbose_flag) printf("Adding code file %s \n", cfile);
+ parse_codefile(cfile);
+ }
+ }
+ }
+ else
+ {
+ if (execute_flag)
+ quit_args("-E flag needs an executable to launch\n");
+ }
+
+ if (usage_flag)
+ usage(LONG_HELP);
+
+ getdivisor();
+
+ if (pid_flag && pid_exflag)
+ quit_args("Can't use both -a and -x flag together\n");
+
+ if (kval_flag && filter_flag)
+ quit_args("Cannot use -k flag with -c, -s, or -p\n");
+
+ if (output_filename && !trace_flag && !readRAW_flag)
+ 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.nolog == 0)
+ use_current_buf = 1;
+ }
+
+ if (disable_flag)
+ {
+ if (pid_flag)
+ {
+ set_pidcheck(pid, 0); /* disable pid check for given pid */
+ exit(1);
+ }
+ else if (pid_exflag)
+ {
+ set_pidexclude(pid, 0); /* disable pid exclusion for given pid */
+ exit(1);
+ }
+ set_enable(0);
+ exit(1);
+ }
+
+ if (remove_flag)
+ {
+ set_remove();
+ exit(1);
+ }
+
+ if (bufset_flag )
+ {
+ if (!init_flag && !LogRAW_flag)
+ {
+ fprintf(stderr,"The -b flag must be used with the -i flag\n");
+ exit(1);
+ }
+ set_numbufs(nbufs);
+ }
+
+ if (nowrap_flag)
+ set_nowrap();
+
+ if (freerun_flag)
+ set_freerun();
+
+ if (bufget_flag)
+ {
+ get_bufinfo(&bufinfo);
+
+ printf("The kernel buffer settings are:\n");
+
+ if (bufinfo.flags & KDBG_BUFINIT)
+ printf("\tKernel buffer is initialized\n");
+ else
+ printf("\tKernel buffer is not initialized\n");
+
+ printf("\t number of buf entries = %d\n", bufinfo.nkdbufs);
+
+ if (verbose_flag)
+ {
+ if (bufinfo.flags & KDBG_MAPINIT)
+ printf("\tKernel thread map is initialized\n");
+ else
+ printf("\tKernel thread map is not initialized\n");
+ printf("\t number of thread entries = %d\n", bufinfo.nkdthreads);
+ }
+
+ if (bufinfo.nolog)
+ printf("\tBuffer logging is disabled\n");
+ else
+ printf("\tBuffer logging is enabled\n");
+
+ if (verbose_flag)
+ printf("\tkernel flags = 0x%x\n", bufinfo.flags);
+
+ if (bufinfo.flags & KDBG_NOWRAP)
+ printf("\tKernel buffer wrap is disabled\n");
+ else
+ printf("\tKernel buffer wrap is enabled\n");
+
+ if (bufinfo.flags & KDBG_RANGECHECK)
+ printf("\tCollection within a range is enabled\n");
+ else
+ printf("\tCollection within a range is disabled\n");
+
+ if (bufinfo.flags & KDBG_VALCHECK)
+ printf("\tCollecting specific code values is enabled\n");
+ 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
+ printf("\tCollection based on pid is disabled\n");
+
+ if (bufinfo.flags & KDBG_PIDEXCLUDE)
+ printf("\tCollection based on pid exclusion is enabled\n");
+ else
+ printf("\tCollection based on pid exclusion is disabled\n");
+
+ if (bufinfo.bufid == -1)
+ printf("\tKernel buffer is not controlled by any process.\n");
+ else
+ printf("\tKernel buffer is controlled by proc id [%d]\n", bufinfo.bufid);
+ }
+
+ if (init_flag)
+ set_init();
+
+ if (filter_flag)
+ set_filter();
+
+ if (kval_flag)
+ set_kval_list();
+
+ if (execute_flag)
+ {
+ fprintf(stderr, "Starting program: %s\n", argv[optind]);
+ fflush(stdout);
+ fflush(stderr);
+
+ switch ((pid = vfork()))
+ {
+ case -1:
+ perror("vfork: ");
+ exit(1);
+ case 0: /* child */
+ setsid();
+ ptrace(PT_TRACE_ME, 0, (caddr_t)0, 0);
+ execve(argv[optind], &argv[optind], environ);
+ perror("execve:");
+ exit(1);
+ }
+ sleep(1);
+
+ signal(SIGINT, signal_handler);
+ set_pidcheck(pid, 1);
+ set_enable(1);
+ ptrace(PT_CONTINUE, pid, (caddr_t)1, 0);
+ waitpid(pid, &status, 0);
+ /* child is gone; no need to disable the pid */
+ exit(0);
+ }
+ else if (enable_flag)
+ {
+ if (pid_flag)
+ set_pidcheck(pid, 1);
+ else if (pid_exflag)
+ set_pidexclude(pid, 1);
+ set_enable(1);
+ }
+
+ if (output_filename)
+ {
+ if (((output_fd = open(output_filename, O_CREAT | O_TRUNC | O_WRONLY | O_APPEND, 0644)) < 0 ) ||
+ !(output_file = fdopen(output_fd, "w")))
+ {
+ fprintf(stderr, "Cannot open file \"%s\" for writing.\n", output_filename);
+ usage(SHORT_HELP);
+ }
+ setbuffer(output_file, &sbuffer[0], SBUFFER_SIZE);
+
+ if (fcntl(output_fd, F_NOCACHE, 1) < 0)
+ {
+ /* Not fatal */
+ fprintf(stderr, "Warning: setting F_NOCACHE on %s, failed\n", output_filename);
+ }
+ }
+ if (!LogRAW_flag && !logRAW_flag)
+ setbuffer(output_file, &sbuffer[0], SBUFFER_SIZE);
+
+ if (trace_flag || readRAW_flag)
+ read_trace();
+ else if (LogRAW_flag)
+ Log_trace();
+ else if (logRAW_flag)
+ log_trace();
+
+ exit(0);
+
+} /* 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 (reenable == 1)
+ {
+ reenable = 0;
+ set_enable(1); /* re-enable kernel logging */
+ }
+
+ printf("trace: ");
+ if (s)
+ printf("%s ", s);
+ exit(1);
+}
+
+static void
+usage(int short_help)
+{
+
+ if (short_help)
+ {
+ (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 -r\n");
+ (void)fprintf(stderr, " usage: trace -n\n");
+
+ (void)fprintf(stderr,
+ " usage: trace -e [ -c class [[-s subclass]... | -p class ]]... | \n");
+ (void)fprintf(stderr,
+ " [-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 [[-s subclass]... | -p class ]]... | \n");
+ (void)fprintf(stderr,
+ " [-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 [-S SecsToRun]\n");
+ (void)fprintf(stderr,
+ " usage: trace -l RawFilename\n");
+ (void)fprintf(stderr,
+ " 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,
+ " 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 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, "\t-b numbufs The number of trace elements the kernel buffer\n");
+ (void)fprintf(stderr, "\t can hold is set to numbufs. Use with the -i flag.\n");
+ (void)fprintf(stderr, "\t Enter a decimal value.\n\n");
+
+ (void)fprintf(stderr, "usage: trace -g\n");
+ (void)fprintf(stderr, "\tGet the kernel buffer settings.\n\n");
+
+ (void)fprintf(stderr, "usage: trace -d [-a pid | -x pid]\n");
+ (void)fprintf(stderr, "\tDisable/stop collection of kernel trace elements.\n\n");
+ (void)fprintf(stderr, "\t -a pid Disable/stop collection for this process only.\n\n");
+ (void)fprintf(stderr, "\t -x pid Disable/stop exclusion of this process only.\n\n");
+
+ (void)fprintf(stderr, "usage: trace -r\n");
+ (void)fprintf(stderr, "\tRemove the kernel trace buffer. Set controls to default.\n\n");
+
+ (void)fprintf(stderr, "usage: trace -n\n");
+ (void)fprintf(stderr, "\tDisables kernel buffer wrap around.\n\n");
+
+ (void)fprintf(stderr,
+ "usage: trace -e [ -c class [[-s subclass]... | -p class ]]... |\n");
+ (void)fprintf(stderr,
+ " [-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 (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 [[-s subclass]... | -p class ]]... |\n");
+ (void)fprintf(stderr,
+ " [-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] [-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] [-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. \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 \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);
+}
+
+
+static int
+argtoi(flag, req, str, base)
+int flag;
+char *req, *str;
+int base;
+{
+ char *cp;
+ int ret;
+
+ ret = (int)strtol(str, &cp, base);
+ if (cp == str || *cp)
+ errx(EINVAL, "-%c flag requires a %s", flag, req);
+ return (ret);
+}
+
+
+static unsigned long
+argtoul(flag, req, str, base)
+int flag;
+char *req, *str;
+int base;
+{
+ char *cp;
+ unsigned long ret;
+
+ ret = (int)strtoul(str, &cp, base);
+ if (cp == str || *cp)
+ errx(EINVAL, "-%c flag requires a %s", flag, req);
+ return (ret);
+}
+
+
+/*
+ * comparison function for qsort
+ * sort by debugid
+ */
+int debugid_compar(p1, p2)
+ code_type_t *p1;
+ code_type_t *p2;
+{
+ if (p1->debugid > p2->debugid)
+ return(1);
+ else if (p1->debugid == p2->debugid)
+ return(0);
+ else
+ return(-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 binary_search(list, lowbound, highbound, code)
+ code_type_t *list;
+ int lowbound, highbound;
+ unsigned int code;
+{
+ int low, high, mid;
+ int tries = 0;
+
+ low = lowbound;
+ high = highbound;
+
+ while (1)
+ {
+ mid = (low + high) / 2;
+
+ tries++;
+
+ if (low > high)
+ return (-1); /* failed */
+ else if ( low + 1 >= high)
+ {
+ /* We have a match */
+ if (list[high].debugid == code)
+ return(high);
+ else if (list[low].debugid == code)
+ return(low);
+ else
+ return(-1); /* search failed */
+ }
+ else if (code < list[mid].debugid)
+ high = mid;
+ else
+ low = mid;
+ }
+}
+
+
+static int
+parse_codefile(const char *filename)
+{
+ int fd;
+ int i, j, line;
+ size_t count;
+ struct stat stat_buf;
+ unsigned long file_size;
+ char *file_addr, *endp;
+
+ if ((fd = open(filename, O_RDONLY, 0)) == -1)
+ {
+ printf("Failed to open code description file %s\n",filename);
+ return(-1);
+ }
+
+ if (fstat(fd, &stat_buf) == -1)
+ {
+ printf("Error: Can't fstat file: %s\n", filename);
+ return(-1);
+ }
+
+ /*
+ * For some reason mapping files with zero size fails
+ * 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,
+ MAP_PRIVATE|MAP_FILE, fd, 0)) == (char*) -1)
+ {
+ printf("Error: Can't map file: %s\n", filename);
+ close(fd);
+ return(-1);
+ }
+ }
+ else
+ {
+ // Skip empty files
+ close(fd);
+ return(0);
+ }
+ close(fd);
+
+
+ /*
+ * If we get here, we have mapped the file
+ * and we are ready to parse it. Count
+ * the newlines to get total number of codes.
+ */
+
+ for (count = 0, j=1; j < file_size; j++)
+ {
+ if (file_addr[j] == '\n')
+ count++;
+ }
+
+ if (count == 0)
+ {
+ printf("Error: No codes in %s\n", filename);
+ return(-1);
+ }
+
+ /*
+ * Fudge the count to accomodate the last line in the file -
+ * in case it doesn't end in a newline.
+ */
+ count++;
+
+ // 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));
+
+ 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, j = 0; j < file_size && codesc_idx < total_count; codesc_idx++)
+ {
+ /* Skip blank lines */
+ while (file_addr[j] == '\n')
+ {
+ j++;
+ line++;
+ }
+
+ /* Skip leading whitespace */
+ while (file_addr[j] == ' ' || file_addr[j] == '\t')
+ j++;
+
+ /* Get the debugid code */
+ codesc[codesc_idx].debugid = strtoul(file_addr + j, &endp, 16);
+ j = endp - file_addr;
+
+ 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++;
+ codesc_idx--;
+ line++;
+ continue;
+ }
+
+ /* Skip whitespace */
+ while (file_addr[j] == ' ' || file_addr[j] == '\t')
+ j++;
+
+ /* Get around old file that had count at the beginning */
+ if (file_addr[j] == '\n')
+ {
+ /* missing debugid string - skip */
+ if (verbose_flag)
+ printf("Error: while parsing line %d, (0x%x) skip\n", line, codesc[codesc_idx].debugid);
+
+ j++;
+ codesc_idx--;
+ line++;
+ continue;
+ }
+
+ /* Next is the debugid string terminated by a newline */
+ codesc[codesc_idx].debug_string = &file_addr[j];
+
+ /* Null out the newline terminator */
+ while ((j < file_size) && (file_addr[j] != '\n'))
+ j++;
+ file_addr[j] = '\0'; /* File must be read-write */
+ j++;
+ line++;
+ codenum++; /*Index into codesc is 0 to codenum-1 */
+ }
+
+ if (verbose_flag)
+ {
+ printf("Parsed %d codes in %s\n", codenum, filename);
+ printf("[%6d] 0x%8x %s\n", 0, codesc[0].debugid, codesc[0].debug_string);
+ printf("[%6d] 0x%8x %s\n\n", codenum-1, codesc[codenum-1].debugid, codesc[codenum-1].debug_string);
+ }
+
+ /* sort */
+ qsort((void *)codesc, codesc_idx, sizeof(code_type_t), debugid_compar);
+
+ if (verbose_flag)
+ {
+ 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 [%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 < 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)
+{
+ int indx;
+
+ if (codenum == 0)
+ return(-1);
+
+ if (codesc[codeindx_cache].debugid != xx)
+ indx = binary_search(codesc, 0, (codenum-1), xx);
+ else
+ indx = codeindx_cache;
+
+ if (indx == -1)
+ return(indx); /* match failed */
+ else {
+ bcopy(&codesc[indx].debug_string[0], debugstr,80);
+ *yy = indx;
+ codeindx_cache = indx;
+ return(0); /* match success */
+ }
+}
+
+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, uint32_t count)
+{
+ int i;
+ size_t size;
+ int mib[6];
+
+ if (readRAW_flag) {
+ total_threads = count;
+ size = count * sizeof(kd_threadmap);
+ } else {
+ get_bufinfo(&bufinfo);
+
+ total_threads = bufinfo.nkdthreads;
+ size = bufinfo.nkdthreads * sizeof(kd_threadmap);
+ }
+ mapptr = 0;
+ nthreads = total_threads * 2;
+
+ if (verbose_flag)
+ printf("Size of map table is %d, thus %d entries\n", (int)size, total_threads);
+
+ if (size) {
+ if ((mapptr = (kd_threadmap *) malloc(size)))
+ bzero (mapptr, size);
+ else
+ {
+ if (verbose_flag)
+ printf("Thread map is not initialized -- this is not fatal\n");
+ return(0);
+ }
+ }
+ if (readRAW_flag) {
+ 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 (int)size;
+ }
+ } else {
+ /* Now read the threadmap */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDTHRMAP;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 3, mapptr, &size, NULL, 0) < 0)
+ {
+ /* This is not fatal -- just means I cant map command strings */
+ if (verbose_flag)
+ printf("Can't read the thread map -- this is not fatal\n");
+ free(mapptr);
+ mapptr = 0;
+ return(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++) {
+ printf ("0x%lx %s\n",
+ mapptr[i].thread,
+ mapptr[i].command);
+ }
+ }
+ return (int)size;
+}
+
+
+void create_map_entry(uintptr_t thread, char *command)
+{
+ threadmap_t tme;
+ int hashid;
+
+ if ((tme = threadmap_freelist))
+ threadmap_freelist = tme->tm_next;
+ else
+ tme = (threadmap_t)malloc(sizeof(struct threadmap));
+
+ tme->tm_thread = thread;
+ tme->tm_deleteme = FALSE;
+
+ (void)strncpy (tme->tm_command, command, MAXCOMLEN);
+ tme->tm_command[MAXCOMLEN] = '\0';
+
+ hashid = thread & HASH_MASK;
+
+ tme->tm_next = threadmap_hash[hashid];
+ threadmap_hash[hashid] = tme;
+}
+
+
+void delete_thread_entry(uintptr_t thread)
+{
+ threadmap_t tme = 0;
+ threadmap_t tme_prev;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ if ((tme = threadmap_hash[hashid])) {
+ if (tme->tm_thread == thread)
+ threadmap_hash[hashid] = tme->tm_next;
+ else {
+ tme_prev = tme;
+
+ for (tme = tme->tm_next; tme; tme = tme->tm_next) {
+ if (tme->tm_thread == thread) {
+ tme_prev->tm_next = tme->tm_next;
+ break;
+ }
+ tme_prev = tme;
+ }
+ }
+ if (tme) {
+ tme->tm_next = threadmap_freelist;
+ threadmap_freelist = tme;
+ }
+ }
+}
+
+
+void find_and_insert_tmp_map_entry(uintptr_t pthread, char *command)
+{
+ threadmap_t tme = 0;
+ threadmap_t tme_prev;
+ int hashid;
+
+ if ((tme = threadmap_temp)) {
+ if (tme->tm_pthread == pthread)
+ threadmap_temp = tme->tm_next;
+ else {
+ tme_prev = tme;
+
+ for (tme = tme->tm_next; tme; tme = tme->tm_next) {
+ if (tme->tm_pthread == pthread) {
+ tme_prev->tm_next = tme->tm_next;
+ break;
+ }
+ tme_prev = tme;
+ }
+ }
+ if (tme) {
+ (void)strncpy (tme->tm_command, command, MAXCOMLEN);
+ tme->tm_command[MAXCOMLEN] = '\0';
+
+ delete_thread_entry(tme->tm_thread);
+
+ hashid = tme->tm_thread & HASH_MASK;
+
+ tme->tm_next = threadmap_hash[hashid];
+ threadmap_hash[hashid] = tme;
+ }
+ }
+}
+
+
+void create_tmp_map_entry(uintptr_t thread, uintptr_t pthread)
+{
+ threadmap_t tme;
+
+ if ((tme = threadmap_freelist))
+ threadmap_freelist = tme->tm_next;
+ else
+ tme = (threadmap_t)malloc(sizeof(struct threadmap));
+
+ tme->tm_thread = thread;
+ tme->tm_pthread = pthread;
+ tme->tm_deleteme = FALSE;
+ tme->tm_command[0] = '\0';
+
+ tme->tm_next = threadmap_temp;
+ threadmap_temp = tme;
+}
+
+
+threadmap_t
+find_thread_entry(uintptr_t thread)
+{
+ threadmap_t tme;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ for (tme = threadmap_hash[hashid]; tme; tme = tme->tm_next) {
+ if (tme->tm_thread == thread)
+ return (tme);
+ }
+ return (0);
+}
+
+
+void find_thread_name(uintptr_t thread, char **command, boolean_t deleteme)
+{
+ threadmap_t tme;
+
+ if ((tme = find_thread_entry(thread))) {
+ *command = tme->tm_command;
+
+ if (deleteme == TRUE)
+ tme->tm_deleteme = deleteme;
+ } else
+ *command = EMPTYSTRING;
+}
+
+
+void find_thread_command(kd_buf *kbufp, char **command)
+{
+ uintptr_t thread;
+ threadmap_t tme;
+ int debugid_base;
+
+ thread = kbufp->arg5;
+ debugid_base = kbufp->debugid & DBG_FUNC_MASK;
+
+ if (debugid_base == BSC_exit || debugid_base == MACH_STKHANDOFF) {
+ /*
+ * Mark entry as invalid and return temp command pointer
+ */
+ if ((tme = find_thread_entry(thread))) {
+
+ strncpy(tmpcommand, tme->tm_command, MAXCOMLEN);
+ *command = tmpcommand;
+
+ if (debugid_base == BSC_exit || tme->tm_deleteme == TRUE)
+ delete_thread_entry(thread);
+ } else
+ *command = EMPTYSTRING;
+ }
+ else if (debugid_base == TRACE_DATA_NEWTHREAD) {
+ /*
+ * Save the create thread data
+ */
+ create_tmp_map_entry(kbufp->arg1, kbufp->arg5);
+ }
+ else if (debugid_base == TRACE_STRING_NEWTHREAD) {
+ /*
+ * process new map entry
+ */
+ find_and_insert_tmp_map_entry(kbufp->arg5, (char *)&kbufp->arg1);
+ }
+ else if (debugid_base == TRACE_STRING_EXEC) {
+
+ delete_thread_entry(kbufp->arg5);
+
+ create_map_entry(kbufp->arg5, (char *)&kbufp->arg1);
+ }
+ else
+ find_thread_name(thread, command, (debugid_base == BSC_thread_terminate));
+}
+
+
+static
+void getdivisor()
+{
+ mach_timebase_info_data_t info;
+
+ if (frequency == 0) {
+ (void) mach_timebase_info (&info);
+
+ divisor = ( (double)info.denom / (double)info.numer) * 1000;
+ } else
+ divisor = (double)frequency / 1000000;
+
+ if (verbose_flag)
+ printf("divisor = %g\n", divisor);
+}
--- /dev/null
+.\"
+.\" (c) 2005 Apple Computer, 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@
+.\"
+.Dd November 18, 2005
+.Dt VIFS 8
+.Os
+.Sh NAME
+.Nm vifs
+.Nd safely edit fstab
+.Sh SYNOPSIS
+.Nm vifs
+.Sh DESCRIPTION
+The
+.Nm vifs
+utility simply locks the fstab file before invoking an editor on it.
+This is important to facilitate the modification of fstab by automated tools
+and system management software.
+.Pp
+Always use
+.Nm vifs
+to edit fstab, instead of invoking an editor directly.
+.Sh SEE ALSO
+.Xr vi 1 ,
+.Xr fstab 5
+.Sh HISTORY
+The
+.Nm vifs
+utility originates from Mac OSX 10.5.
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, 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 <sys/errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <fstab.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+#include <unistd.h>
+#include <signal.h>
+
+char *warning = "\
+#\n\
+# Warning - this file should only be modified with vifs(8)\n\
+#\n\
+# Failure to do so is unsupported and may be destructive.\n\
+#\n";
+
+int
+main(int argc, char *argv[])
+{
+ struct stat sb;
+ int fd, x;
+ uid_t euid;
+ pid_t editpid;
+ char *p, *editor;
+
+ if (argc != 1) {
+ printf("usage: vifs\n");
+ exit(1);
+ }
+
+ euid = geteuid();
+ if (euid != 0)
+ errx(1, "need to run as root");
+
+ /* examine the existing fstab, try to create it if needed */
+ if (stat(_PATH_FSTAB, &sb) < 0) {
+ if (errno == ENOENT) {
+ fd = open(_PATH_FSTAB, O_CREAT | O_WRONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0)
+ errx(1, "error creating %s", _PATH_FSTAB);
+ write(fd, warning, strlen(warning));
+ close(fd);
+ } else {
+ errx(1, "could not stat %s", _PATH_FSTAB);
+ }
+ }
+
+ /* prepare the file for the editor */
+ fd = open(_PATH_FSTAB, O_RDONLY, 0);
+ if (fd < 0)
+ errx(1, "error opening %s", _PATH_FSTAB);
+
+ x = fcntl(fd, F_SETFD, 1);
+ if (x < 0)
+ errx(1, "error setting close on exit");
+
+ x = flock(fd, LOCK_EX | LOCK_NB);
+ if (x != 0)
+ errx(1, "file is busy");
+
+ /* obtain and invoke the editor */
+ editor = getenv("EDITOR");
+ if (editor == NULL)
+ editor = _PATH_VI;
+ p = strrchr(editor, '/');
+ if (p != NULL)
+ ++p;
+ else
+ p = editor;
+
+ editpid = vfork();
+ if (editpid == 0) {
+ execlp(editor, p, _PATH_FSTAB, NULL);
+ _exit(1);
+ }
+
+ for ( ; ; ) {
+ editpid = waitpid(editpid, (int *)&x, WUNTRACED);
+ if (editpid == -1)
+ errx(1, "editing error");
+ else if (WIFSTOPPED(x))
+ raise(WSTOPSIG(x));
+ else if (WIFEXITED(x) && WEXITSTATUS(x) == 0)
+ break;
+ else
+ errx(1, "editing error");
+ }
+
+ /* let process death clean up locks and file descriptors */
+ return 0;
+}
--- /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) 1990, 1993, 1994
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#ifndef lint
+#include <sys/cdefs.h>
+__unused static char sccsid[] = "@(#)pw_util.c 8.4 (Berkeley) 4/28/95";
+#endif /* not lint */
+
+/*
+ * This file is used by all the "password" programs; vipw(8), chpass(1),
+ * and passwd(1).
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pw_util.h"
+
+extern char *tempname;
+static pid_t editpid = -1;
+static int lockfd;
+
+void
+pw_cont(sig)
+ int sig;
+{
+
+ if (editpid != -1)
+ kill(editpid, sig);
+}
+
+void
+pw_init()
+{
+ struct rlimit rlim;
+
+ /* Unlimited resource limits. */
+ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+ (void)setrlimit(RLIMIT_CPU, &rlim);
+ (void)setrlimit(RLIMIT_FSIZE, &rlim);
+ (void)setrlimit(RLIMIT_STACK, &rlim);
+ (void)setrlimit(RLIMIT_DATA, &rlim);
+ (void)setrlimit(RLIMIT_RSS, &rlim);
+
+ /* Don't drop core (not really necessary, but GP's). */
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ (void)setrlimit(RLIMIT_CORE, &rlim);
+
+ /* Turn off signals. */
+ (void)signal(SIGALRM, SIG_IGN);
+ (void)signal(SIGHUP, SIG_IGN);
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGPIPE, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
+ (void)signal(SIGTERM, SIG_IGN);
+ (void)signal(SIGCONT, pw_cont);
+
+ /* Create with exact permissions. */
+ (void)umask(0);
+}
+
+int
+pw_lock()
+{
+ /*
+ * If the master password file doesn't exist, the system is hosed.
+ * Might as well try to build one. Set the close-on-exec bit so
+ * that users can't get at the encrypted passwords while editing.
+ * Open should allow flock'ing the file; see 4.4BSD. XXX
+ */
+ lockfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0);
+ if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1)
+ err(1, "%s", _PATH_MASTERPASSWD);
+ if (flock(lockfd, LOCK_EX|LOCK_NB))
+ errx(1, "the password db file is busy");
+ return (lockfd);
+}
+
+int
+pw_tmp()
+{
+ static char path[MAXPATHLEN] = _PATH_MASTERPASSWD;
+ int fd;
+ char *p;
+
+ if (p = strrchr(path, '/'))
+ ++p;
+ else
+ p = path;
+ strcpy(p, "pw.XXXXXX");
+ if ((fd = mkstemp(path)) == -1)
+ err(1, "%s", path);
+ tempname = path;
+ return (fd);
+}
+
+int
+pw_mkdb()
+{
+ int pstat;
+ pid_t pid;
+
+ warnx("rebuilding the database...");
+ (void)fflush(stderr);
+ if (!(pid = vfork())) {
+ execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", tempname, NULL);
+ pw_error(_PATH_PWD_MKDB, 1, 1);
+ }
+ pid = waitpid(pid, &pstat, 0);
+ if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0)
+ return (1);
+ warnx("done");
+ return (0);
+}
+
+void
+pw_edit(notsetuid)
+ int notsetuid;
+{
+ int pstat;
+ char *p, *editor;
+
+ if (!(editor = getenv("EDITOR")))
+ editor = _PATH_VI;
+ if (p = strrchr(editor, '/'))
+ ++p;
+ else
+ p = editor;
+
+ if (!(editpid = vfork())) {
+ if (notsetuid) {
+ (void)setgid(getgid());
+ (void)setuid(getuid());
+ }
+ execlp(editor, p, tempname, NULL);
+ _exit(1);
+ }
+ for (;;) {
+ editpid = waitpid(editpid, (int *)&pstat, WUNTRACED);
+ if (editpid == -1)
+ pw_error(editor, 1, 1);
+ else if (WIFSTOPPED(pstat))
+ raise(WSTOPSIG(pstat));
+ else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0)
+ break;
+ else
+ pw_error(editor, 1, 1);
+ }
+ editpid = -1;
+}
+
+void
+pw_prompt()
+{
+ int c;
+
+ (void)printf("re-edit the password file? [y]: ");
+ (void)fflush(stdout);
+ c = getchar();
+ if (c != EOF && c != '\n')
+ while (getchar() != '\n');
+ if (c == 'n')
+ pw_error(NULL, 0, 0);
+}
+
+void
+pw_error(name, err, eval)
+ char *name;
+ int err, eval;
+{
+ if (err)
+ warn("%s", name);
+
+ warnx("%s: unchanged", _PATH_MASTERPASSWD);
+ (void)unlink(tempname);
+ exit(eval);
+}
--- /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) 1994
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * @(#)pw_util.h 8.2 (Berkeley) 4/1/94
+ */
+
+void pw_edit __P((int));
+void pw_error __P((char *, int, int));
+void pw_init __P((void));
+int pw_lock __P((void));
+int pw_mkdb __P((void));
+void pw_prompt __P((void));
+int pw_tmp __P((void));
--- /dev/null
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)vipw.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt VIPW 8
+.Os BSD 4
+.Sh NAME
+.Nm vipw
+.Nd edit the password file
+.Sh SYNOPSIS
+.Nm vipw
+.Sh DESCRIPTION
+.Nm Vipw
+edits the password file after setting the appropriate locks,
+and does any necessary processing after the password file is unlocked.
+If the password file is already locked for editing by another user,
+.Nm vipw
+will ask you
+to try again later. The default editor for
+.Nm vipw
+is
+.Xr vi 1 .
+.Pp
+.Nm Vipw
+performs a number of consistency checks on the password entries,
+and will not allow a password file with a
+.Dq mangled
+entry to be
+installed.
+If
+.Nm vipw
+rejects the new password file, the user is prompted to re-enter
+the edit session.
+.Pp
+Once the information has been verified,
+.Nm vipw
+uses
+.Xr pwd_mkdb 8
+to update the user database. This is run in the background, and,
+at very large sites could take several minutes. Until this update
+is completed, the password file is unavailable for other updates
+and the new information is not available to programs.
+.Sh ENVIRONMENT
+If the following environment variable exists it will be utilized by
+.Nm vipw :
+.Bl -tag -width EDITOR
+.It Ev EDITOR
+The editor specified by the string
+.Ev EDITOR
+will be invoked instead of the default editor
+.Xr vi 1 .
+.El
+.Sh SEE ALSO
+.Xr chpass 1 ,
+.Xr passwd 1 ,
+.Xr passwd 5 ,
+.Xr pwd_mkdb 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
--- /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) 1987, 1993, 1994
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static char copyright[] =
+"@(#) Copyright (c) 1987, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+__unused static char sccsid[] = "@(#)vipw.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pw_util.h"
+
+char *tempname;
+
+void copyfile __P((int, int));
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int pfd, tfd;
+ struct stat begin, end;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != EOF)
+ switch (ch) {
+ case '?':
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 0)
+ usage();
+
+ pw_init();
+ pfd = pw_lock();
+ tfd = pw_tmp();
+ copyfile(pfd, tfd);
+ (void)close(tfd);
+
+ for (;;) {
+ if (stat(tempname, &begin))
+ pw_error(tempname, 1, 1);
+ pw_edit(0);
+ if (stat(tempname, &end))
+ pw_error(tempname, 1, 1);
+ if (begin.st_mtime == end.st_mtime) {
+ warnx("no changes made");
+ pw_error((char *)NULL, 0, 0);
+ }
+ if (pw_mkdb())
+ break;
+ pw_prompt();
+ }
+ exit(0);
+}
+
+void
+copyfile(from, to)
+ int from, to;
+{
+ int nr, nw, off;
+ char buf[8*1024];
+
+ while ((nr = read(from, buf, sizeof(buf))) > 0)
+ for (off = 0; off < nr; nr -= nw, off += nw)
+ if ((nw = write(to, buf + off, nr)) < 0)
+ pw_error(tempname, 1, 1);
+ if (nr < 0)
+ pw_error(_PATH_MASTERPASSWD, 1, 1);
+}
+
+void
+usage()
+{
+
+ (void)fprintf(stderr, "usage: vipw\n");
+ exit(1);
+}
--- /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;
+}
+
+
--- /dev/null
+.\" Copyright (c) 1997, Apple Computer, Inc. All rights reserved.
+.\"
+.Dd August 13, 1997
+.Dt VM_STAT 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm vm_stat
+.Nd show Mach virtual memory statistics
+.Sh SYNOPSIS
+.Nm vm_stat
+.Oo
+.Op Fl c Ar count
+.Ar interval
+.Oc
+.Sh DESCRIPTION
+.Nm vm_stat
+displays Mach virtual memory statistics. If the optional
+.Ar interval
+is specified, then
+.Nm vm_stat
+will display the statistics every
+.Ar interval
+seconds. In this case, each line of output displays the change in
+each statistic (an
+.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.
+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.
+.It Pages active
+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
+the number of faults that caused a page to be
+copied (generally caused by copy-on-write faults).
+.It Pages zero filled
+the total number of pages that have been zero-filled on demand.
+.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 total number of requests for pages from a pager (such as the inode pager).
+.It Pageouts
+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.
--- /dev/null
+/*
+ * Copyright (c) 1999-2009 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@
+ */
+/*
+ * File: vm_stat.c
+ * Author: Avadis Tevanian, Jr.
+ *
+ * Copyright (C) 1986, Avadis Tevanian, Jr.
+ *
+ *
+ * Display Mach VM statistics.
+ *
+ ************************************************************************
+ * HISTORY
+ * 6-Jun-86 Avadis Tevanian, Jr. (avie) at Carnegie-Mellon University
+ * Use official Mach interface.
+ *
+ * 25-mar-99 A.Ramesh at Apple
+ * Ported to MacOS X
+ *
+ * 22-Jan-09 R.Branche at Apple
+ * Changed some fields to 64-bit to alleviate overflows
+ ************************************************************************
+ */
+
+#include <err.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <mach/mach.h>
+
+vm_statistics64_data_t vm_stat, last;
+char *pgmname;
+mach_port_t myHost;
+vm_size_t pageSize = 4096; /* set to 4k default */
+
+void usage(void);
+void snapshot(void);
+void sspstat(char *str, uint64_t n);
+void banner(void);
+void print_stats(void);
+void get_stats(vm_statistics64_t stat);
+
+void pstat(uint64_t n, int width);
+
+int
+main(int argc, char *argv[])
+{
+
+ double delay = 0.0;
+ int count = 0;
+
+ pgmname = argv[0];
+
+ setlinebuf (stdout);
+
+ 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();
+
+ if(host_page_size(mach_host_self(), &pageSize) != KERN_SUCCESS) {
+ fprintf(stderr, "%s: failed to get pagesize; defaulting to 4K.\n", pgmname);
+ pageSize = 4096;
+ }
+
+ if (delay == 0.0) {
+ snapshot();
+ } else {
+ print_stats();
+ for (int i = 1; i < count || count == 0; i++ ){
+ usleep((int)(delay * USEC_PER_SEC));
+ print_stats();
+ }
+ }
+ exit(EXIT_SUCCESS);
+}
+
+void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [[-c count] interval]\n", pgmname);
+ exit(EXIT_FAILURE);
+}
+
+void
+snapshot(void)
+{
+
+ get_stats(&vm_stat);
+ printf("Mach Virtual Memory Statistics: (page size of %d bytes)\n",
+ (int) (pageSize));
+
+ sspstat("Pages free:", (uint64_t) (vm_stat.free_count - vm_stat.speculative_count));
+ 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));
+ sspstat("Swapins:", (uint64_t) (vm_stat.swapins));
+ sspstat("Swapouts:", (uint64_t) (vm_stat.swapouts));
+}
+
+void
+sspstat(char *str, uint64_t n)
+{
+ printf("%-30s %16llu.\n", str, n);
+}
+
+void
+banner(void)
+{
+ get_stats(&vm_stat);
+ printf("Mach Virtual Memory Statistics: ");
+ 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));
+}
+
+void
+print_stats(void)
+{
+ static int count = 0;
+
+ if (count++ == 0)
+ banner();
+
+ if (count > 20)
+ count = 0;
+
+ get_stats(&vm_stat);
+ 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.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;
+}
+
+void
+pstat(uint64_t n, int width)
+{
+ char buf[80];
+ if (width >= sizeof(buf)) {
+ width = sizeof(buf) -1;
+ }
+
+ /* 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
+ digets and slap on the appropriate suffix
+ */
+ int w = snprintf(buf, sizeof(buf), "%*llu", width, n);
+ if (w > width) {
+ w = snprintf(buf, sizeof(buf), "%*lluK", width -1, n / 1000);
+ if (w > width) {
+ w = snprintf(buf, sizeof(buf), "%*lluM", width -1, n / 1000000);
+ if (w > width) {
+ w = snprintf(buf, sizeof(buf), "%*lluG", width -1, n / 1000000000);
+ }
+ }
+ }
+ fputs(buf, stdout);
+ putchar(' ');
+}
+
+void
+get_stats(vm_statistics64_t stat)
+{
+ unsigned int count = HOST_VM_INFO64_COUNT;
+ kern_return_t ret;
+ if ((ret = host_statistics64(myHost, HOST_VM_INFO64, (host_info64_t)stat, &count) != KERN_SUCCESS)) {
+ fprintf(stderr, "%s: failed to get statistics. error %d\n", pgmname, ret);
+ exit(EXIT_FAILURE);
+ }
+}
--- /dev/null
+.\"
+.\" @(#)zdump.8 7.3
+.\" $FreeBSD: src/usr.sbin/zic/zdump.8,v 1.10 2004/06/20 21:41:11 stefanf Exp $
+.\"
+.Dd June 20, 2004
+.Dt ZDUMP 8
+.Os
+.Sh NAME
+.Nm zdump
+.Nd timezone dumper
+.Sh SYNOPSIS
+.Nm
+.Op Fl -version
+.Op Fl v
+.Op Fl c Ar cutoffyear
+.Op Ar zonename ...
+.Sh DESCRIPTION
+The
+.Nm
+utility prints the current time in each
+.Ar zonename
+named on the command line.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl -version
+Output version information and exit.
+.It Fl v
+For each
+.Ar zonename
+on the command line,
+print the time at the lowest possible time value,
+the time one day after the lowest possible time value,
+the times both one second before and exactly at
+each detected time discontinuity,
+the time at one day less than the highest possible time value,
+and the time at the highest possible time value,
+Each line ends with
+.Em isdst=1
+if the given time is Daylight Saving Time or
+.Em isdst=0
+otherwise.
+.It Fl c Ar cutoffyear
+Cut off the verbose output near the start of the given year.
+.El
+.Sh "SEE ALSO"
+.Xr ctime 3 ,
+.Xr tzfile 5 ,
+.Xr zic 8
--- /dev/null
+static const char elsieid[] = "@(#)zdump.c 7.31";
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: src/usr.sbin/zic/zdump.c,v 1.10 2008/02/19 07:09:19 ru Exp $";
+#endif /* not lint */
+
+/*
+** This code has been made independent of the rest of the time
+** conversion package to increase confidence in the verification it provides.
+** You can use this code to help in verifying other implementations.
+*/
+
+#include <err.h>
+#include <stdio.h> /* for stdout, stderr */
+#include <stdlib.h> /* for exit, malloc, atoi */
+#include <string.h> /* for strcpy */
+#include <sys/types.h> /* for time_t */
+#include <time.h> /* for struct tm */
+#include <unistd.h>
+#include <limits.h>
+
+#ifndef MAX_STRING_LENGTH
+#define MAX_STRING_LENGTH 1024
+#endif /* !defined MAX_STRING_LENGTH */
+
+#ifndef TRUE
+#define TRUE 1
+#endif /* !defined TRUE */
+
+#ifndef FALSE
+#define FALSE 0
+#endif /* !defined FALSE */
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif /* !defined EXIT_SUCCESS */
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif /* !defined EXIT_FAILURE */
+
+#ifndef SECSPERMIN
+#define SECSPERMIN 60
+#endif /* !defined SECSPERMIN */
+
+#ifndef MINSPERHOUR
+#define MINSPERHOUR 60
+#endif /* !defined MINSPERHOUR */
+
+#ifndef SECSPERHOUR
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#endif /* !defined SECSPERHOUR */
+
+#ifndef HOURSPERDAY
+#define HOURSPERDAY 24
+#endif /* !defined HOURSPERDAY */
+
+#ifndef EPOCH_YEAR
+#define EPOCH_YEAR 1970
+#endif /* !defined EPOCH_YEAR */
+
+#ifndef TM_YEAR_BASE
+#define TM_YEAR_BASE 1900
+#endif /* !defined TM_YEAR_BASE */
+
+#ifndef DAYSPERNYEAR
+#define DAYSPERNYEAR 365
+#endif /* !defined DAYSPERNYEAR */
+
+#ifndef isleap
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+#endif /* !defined isleap */
+
+#if HAVE_GETTEXT - 0
+#include "locale.h" /* for setlocale */
+#include "libintl.h"
+#endif /* HAVE_GETTEXT - 0 */
+
+#ifndef GNUC_or_lint
+#ifdef lint
+#define GNUC_or_lint
+#endif /* defined lint */
+#ifndef lint
+#ifdef __GNUC__
+#define GNUC_or_lint
+#endif /* defined __GNUC__ */
+#endif /* !defined lint */
+#endif /* !defined GNUC_or_lint */
+
+#ifndef INITIALIZE
+#ifdef GNUC_or_lint
+#define INITIALIZE(x) ((x) = 0)
+#endif /* defined GNUC_or_lint */
+#ifndef GNUC_or_lint
+#define INITIALIZE(x)
+#endif /* !defined GNUC_or_lint */
+#endif /* !defined INITIALIZE */
+
+/*
+** For the benefit of GNU folk...
+** `_(MSGID)' uses the current locale's message library string for MSGID.
+** The default is to use gettext if available, and use MSGID otherwise.
+*/
+
+#ifndef _
+#if HAVE_GETTEXT - 0
+#define _(msgid) gettext(msgid)
+#else /* !(HAVE_GETTEXT - 0) */
+#define _(msgid) msgid
+#endif /* !(HAVE_GETTEXT - 0) */
+#endif /* !defined _ */
+
+#ifndef TZ_DOMAIN
+#define TZ_DOMAIN "tz"
+#endif /* !defined TZ_DOMAIN */
+
+#ifndef P
+#ifdef __STDC__
+#define P(x) x
+#endif /* defined __STDC__ */
+#ifndef __STDC__
+#define P(x) ()
+#endif /* !defined __STDC__ */
+#endif /* !defined P */
+
+extern char ** environ;
+extern char * tzname[2];
+
+static char * abbr P((struct tm * tmp));
+static long delta P((struct tm * newp, struct tm * oldp));
+static time_t hunt P((char * name, time_t lot, time_t hit));
+static size_t longest;
+static void show P((char * zone, time_t t, int v));
+static void usage(void);
+
+int
+main(argc, argv)
+int argc;
+char * argv[];
+{
+ register int i;
+ register int c;
+ register int vflag;
+ register char * cutoff;
+ register int cutyear;
+ register long cuttime;
+ char ** fakeenv;
+ time_t now;
+ time_t t;
+ time_t newt;
+#ifndef __APPLE__
+// <rdar://problem/6013740>
+// The approach of walking through every day from the minimum
+// possible time_t value to the maximum possible time_t value
+// falls apart with 64-bit time_t (takes too long to iterate,
+// and causes gmtime(3) and localtime(3) to return EOVERFLOW
+// which this code does not anticipate). Limiting the time_t
+// range to [INT_MIN:INT_MAX] even on LP64.
+ time_t hibit;
+#endif
+ struct tm tm;
+ struct tm newtm;
+
+ INITIALIZE(cuttime);
+#if HAVE_GETTEXT - 0
+ (void) setlocale(LC_MESSAGES, "");
+#ifdef TZ_DOMAINDIR
+ (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
+#endif /* defined(TEXTDOMAINDIR) */
+ (void) textdomain(TZ_DOMAIN);
+#endif /* HAVE_GETTEXT - 0 */
+ for (i = 1; i < argc; ++i)
+ if (strcmp(argv[i], "--version") == 0) {
+ errx(EXIT_SUCCESS, "%s", elsieid);
+ }
+ vflag = 0;
+ cutoff = NULL;
+ while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
+ if (c == 'v')
+ vflag = 1;
+ else cutoff = optarg;
+ if ((c != -1) ||
+ (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
+ usage();
+ }
+ if (cutoff != NULL) {
+ int y;
+
+ cutyear = atoi(cutoff);
+ cuttime = 0;
+ for (y = EPOCH_YEAR; y < cutyear; ++y)
+ cuttime += DAYSPERNYEAR + isleap(y);
+ cuttime *= SECSPERHOUR * HOURSPERDAY;
+ }
+ (void) time(&now);
+ longest = 0;
+ for (i = optind; i < argc; ++i)
+ if (strlen(argv[i]) > longest)
+ longest = strlen(argv[i]);
+#ifndef __APPLE__
+ for (hibit = 1; (hibit << 1) != 0; hibit <<= 1)
+ continue;
+#endif
+ {
+ register int from;
+ register int to;
+
+ for (i = 0; environ[i] != NULL; ++i)
+ continue;
+ fakeenv = (char **) malloc((size_t) ((i + 2) *
+ sizeof *fakeenv));
+ if (fakeenv == NULL ||
+ (fakeenv[0] = (char *) malloc((size_t) (longest +
+ 4))) == NULL)
+ errx(EXIT_FAILURE,
+ _("malloc() failed"));
+ to = 0;
+ (void) strcpy(fakeenv[to++], "TZ=");
+ for (from = 0; environ[from] != NULL; ++from)
+ if (strncmp(environ[from], "TZ=", 3) != 0)
+ fakeenv[to++] = environ[from];
+ fakeenv[to] = NULL;
+ environ = fakeenv;
+ }
+ for (i = optind; i < argc; ++i) {
+ static char buf[MAX_STRING_LENGTH];
+
+ (void) strcpy(&fakeenv[0][3], argv[i]);
+ if (!vflag) {
+ show(argv[i], now, FALSE);
+ continue;
+ }
+ /*
+ ** Get lowest value of t.
+ */
+#ifdef __APPLE__
+ t = INT_MIN;
+#else
+ t = hibit;
+ if (t > 0) /* time_t is unsigned */
+ t = 0;
+#endif
+ show(argv[i], t, TRUE);
+ t += SECSPERHOUR * HOURSPERDAY;
+ show(argv[i], t, TRUE);
+ tm = *localtime(&t);
+ (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1);
+ for ( ; ; ) {
+ if (cutoff != NULL && t >= cuttime)
+ break;
+ newt = t + SECSPERHOUR * 12;
+ if (cutoff != NULL && newt >= cuttime)
+ break;
+#ifdef __APPLE__
+ if (newt > INT_MAX)
+ break;
+#else
+ if (newt <= t)
+ break;
+#endif
+ newtm = *localtime(&newt);
+ if (delta(&newtm, &tm) != (newt - t) ||
+ newtm.tm_isdst != tm.tm_isdst ||
+ strcmp(abbr(&newtm), buf) != 0) {
+ newt = hunt(argv[i], t, newt);
+ newtm = *localtime(&newt);
+ (void) strncpy(buf, abbr(&newtm),
+ (sizeof buf) - 1);
+ }
+ t = newt;
+ tm = newtm;
+ }
+ /*
+ ** Get highest value of t.
+ */
+#ifdef __APPLE__
+ t = INT_MAX;
+#else
+ t = ~((time_t) 0);
+ if (t < 0) /* time_t is signed */
+ t &= ~hibit;
+#endif
+ t -= SECSPERHOUR * HOURSPERDAY;
+ show(argv[i], t, TRUE);
+ t += SECSPERHOUR * HOURSPERDAY;
+ show(argv[i], t, TRUE);
+ }
+ if (fflush(stdout) || ferror(stdout))
+ errx(EXIT_FAILURE, _("error writing standard output"));
+ exit(EXIT_SUCCESS);
+
+ /* gcc -Wall pacifier */
+ for ( ; ; )
+ continue;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+_("usage: zdump [--version] [-v] [-c cutoff] zonename ...\n"));
+ exit(EXIT_FAILURE);
+}
+
+static time_t
+hunt(name, lot, hit)
+char * name;
+time_t lot;
+time_t hit;
+{
+ time_t t;
+ struct tm lotm;
+ struct tm tm;
+ static char loab[MAX_STRING_LENGTH];
+
+ lotm = *localtime(&lot);
+ (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1);
+ while ((hit - lot) >= 2) {
+ t = lot / 2 + hit / 2;
+ if (t <= lot)
+ ++t;
+ else if (t >= hit)
+ --t;
+ tm = *localtime(&t);
+ if (delta(&tm, &lotm) == (t - lot) &&
+ tm.tm_isdst == lotm.tm_isdst &&
+ strcmp(abbr(&tm), loab) == 0) {
+ lot = t;
+ lotm = tm;
+ } else hit = t;
+ }
+ show(name, lot, TRUE);
+ show(name, hit, TRUE);
+ return hit;
+}
+
+/*
+** Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta.
+*/
+
+static long
+delta(newp, oldp)
+struct tm * newp;
+struct tm * oldp;
+{
+ long result;
+ int tmy;
+
+ if (newp->tm_year < oldp->tm_year)
+ return -delta(oldp, newp);
+ result = 0;
+ for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
+ result += DAYSPERNYEAR + isleap(tmy + TM_YEAR_BASE);
+ result += newp->tm_yday - oldp->tm_yday;
+ result *= HOURSPERDAY;
+ result += newp->tm_hour - oldp->tm_hour;
+ result *= MINSPERHOUR;
+ result += newp->tm_min - oldp->tm_min;
+ result *= SECSPERMIN;
+ result += newp->tm_sec - oldp->tm_sec;
+ return result;
+}
+
+static void
+show(zone, t, v)
+char * zone;
+time_t t;
+int v;
+{
+ struct tm * tmp;
+
+ (void) printf("%-*s ", (int) longest, zone);
+ if (v)
+ (void) printf("%.24s UTC = ", asctime(gmtime(&t)));
+ tmp = localtime(&t);
+ (void) printf("%.24s", asctime(tmp));
+ if (*abbr(tmp) != '\0')
+ (void) printf(" %s", abbr(tmp));
+ if (v) {
+ (void) printf(" isdst=%d", tmp->tm_isdst);
+#ifdef TM_GMTOFF
+ (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
+#endif /* defined TM_GMTOFF */
+ }
+ (void) printf("\n");
+}
+
+static char *
+abbr(tmp)
+struct tm * tmp;
+{
+ register char * result;
+ static char nada;
+
+ if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
+ return &nada;
+ result = tzname[tmp->tm_isdst];
+ return (result == NULL) ? &nada : result;
+}
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<!-- $FreeBSD: src/usr.sbin/zic/Arts.htm,v 1.2 2000/05/29 20:23:04 charnier Exp $ -->
+<HTML>
+<HEAD>
+<TITLE>Time and the Arts</TITLE>
+</HEAD>
+<BODY>
+<H1>Time and the Arts</H1>
+<P>
+<H6>
+@(#)Arts.htm 7.18
+</H6>
+</P>
+<PRE>
+Data on recordings of "Save That Time," Russ Long, Serrob Publishing, BMI:
+--------------------------------------------------------------------------
+Artist: Karrin Allyson
+CD: I Didn't Know About You
+Copyright Date: 1993
+Label: Concord Jazz, Inc.
+ID: CCD-4543
+Track Time: 3:44
+Personnel: Karrin Allyson, vocal
+ Russ Long, piano
+ Gerald Spaits, bass
+ Todd Strait, drums
+Notes: CD notes "additional lyric by Karrin Allyson;
+ arranged by Russ Long and Karrin Allyson"
+ADO Rating: 1 star
+<A HREF="http://205.186.189.2/cgi-win/amg.exe?sql=1A_IDR|||175928">AMG Rating: 3.5 stars</A>
+Penguin Rating: 3.5 stars
+--------------------------------------------------------------------------
+Artist: Kevin Mahogany
+CD: Double Rainbow
+Copyright Date: 1993
+Label: Enja Records
+ID: ENJ-7097 2
+Track Time: 6:27
+Personnel: Kevin Mahogany, vocal
+ Kenny Barron, piano
+ Ray Drummond, bss
+ Ralph Moore, tenor saxophone
+ Lewis Nash, drums
+ADO Rating: 1.5 stars
+<A HREF="http://205.186.189.2/cgi-win/amg.exe?sql=1A_IDR|||262654">AMG Rating: unrated</A>
+Penguin Rating: 3 stars
+--------------------------------------------------------------------------
+Artist: Joe Williams
+CD: Here's to Life
+Copyright Date: 1994
+Label: Telarc International Corporation
+ID: CD-83357
+Track Time: 3:58
+Personnel: Joe Williams, vocal
+ The Robert Farnon [39 piece] Orchestra
+Notes: On-line information and samples available at
+ <A HREF="http://www.telarc.com/telarc/releases/release.req?ID=83357">http://telarc.dmn.com/telarc/releases/release.req?ID=83357</A>
+ADO Rating: black dot
+<A HREF="http://205.186.189.2/cgi-win/amg.exe?sql=1A_IDR|||194434">AMG Rating: 2 stars</A>
+Penguin Rating: 3 stars
+--------------------------------------------------------------------------
+Artist: Charles Fambrough
+CD: Keeper of the Spirit
+Copyright Date: 1995
+Label: AudioQuest Music
+ID: AQ-CD1033
+Track Time: 7:07
+Personnel: Charles Fambrough, bass
+ Joel Levine, tenor recorder
+ Edward Simon, piano
+ Lenny White, drums
+ Marion Simon, percussion
+Notes: On-line information and samples available at
+ <A HREF="http://wwmusic.com/~music/audioq/rel/1033.html">http://wwmusic.com/~music/audioq/rel/1033.html</A>
+ADO Rating: 2 stars
+<A HREF="http://205.186.189.2/cgi-win/AMG.exe?sql=1A_IDR|||224430">AMG Rating: unrated</A>
+Penguin Rating: 3 stars
+==========================================================================
+Also of note:
+--------------------------------------------------------------------------
+Artist: Holly Cole Trio
+CD: Blame It On My Youth
+Copyright Date: 1992
+Label: Manhattan
+ID: CDP 7 97349 2
+Total Time: 37:45
+Personnel: Holly Cole, voice
+ Aaron Davis, piano
+ David Piltch, string bass
+Notes: Lyrical reference to "Eastern Standard Time" in
+ Tom Waits' "Purple Avenue"
+ADO Rating: 2.5 stars
+<A HREF="http://205.186.189.2/cgi-win/AMG.exe?sql=1A_IDR|||157959">AMG Rating: 2 stars</A>
+Penguin Rating: unrated
+--------------------------------------------------------------------------
+Artist: Milt Hinton
+CD: Old Man Time
+Copyright Date: 1990
+Label: Chiaroscuro
+ID: CR(D) 310
+Total Time: 149:38 (two CDs)
+Personnel: Milt Hinton, bass
+ Doc Cheatham, Dizzy Gillespie, Clark Terry, trumpet
+ Al Grey, trombone
+ Eddie Barefield, Joe Camel (Flip Phillips), Buddy Tate,
+ clarinet and saxophone
+ John Bunch, Red Richards, Norman Simmons, Derek Smith,
+ Ralph Sutton, piano
+ Danny Barker, Al Casey, guitar
+ Gus Johnson, Gerryck King, Bob Rosengarden, Jackie Williams,
+ drums
+ Lionel Hampton, vibraphone
+ Cab Calloway, Joe Williams, vocal
+ Buck Clayton, arrangements
+Notes: tunes include Old Man Time, Time After Time,
+ Sometimes I'm Happy,
+ A Hot Time in the Old Town Tonight,
+ Four or Five Times, Now's the Time,
+ Time on My Hands, This Time It's Us,
+ and Good Time Charlie
+ On-line samples available at
+ <A HREF="http://www.globalmusic.com/labels/chiaroscuro/chiaro_cd_gallery.html">http://www.globalmusic.com/labels/chiaroscuro/chiaro_cd_gallery.html</A>
+ADO Rating: 3 stars
+<A HREF="http://205.186.189.2/cgi-win/AMG.exe?sql=1A_IDR|||162344">AMG Rating: 4.5 stars</A>
+Penguin Rating: 3 stars
+--------------------------------------------------------------------------
+Artist: Paul Broadbent
+CD: Pacific Standard Time
+Copyright Date: 1995
+Label: Concord Jazz, Inc.
+ID: CCD-4664
+Total Time: 62:42
+Personnel: Paul Broadbent, piano
+ Putter Smith, Bass
+ Frank Gibson, Jr., drums
+Notes: The CD cover features an analemma for equation of time fans
+ADO Rating: 1 star
+<A HREF="http://205.186.189.2/cgi-win/AMG.exe?sql=1A_IDR|||223722">AMG Rating: 3 stars</A>
+Penguin Rating: 3.5 stars
+--------------------------------------------------------------------------
+Artist: Anthony Braxton/Richard Teitelbaum
+CD: Silence/Time Zones
+Copyright Date: 1996
+Label: Black Lion
+ID: BLCD 760221
+Total Time: 72:58
+Personnel: Anthony Braxton, sopranino and alto saxophones,
+ contrebasse clarinet, miscellaneous instruments
+ Leo Smith, trumpet and miscellaneous instruments
+ Leroy Jenkins, violin and miscellaneous instruments
+ Richard Teitelbaum, modular moog and micromoog synthesizer
+ADO Rating: black dot
+<A HREF="http://205.186.189.2/cg/AMG_.exe?sql=A310757">AMG Rating: unrated</A>
+--------------------------------------------------------------------------
+Artist: Jules Verne
+Book: Le Tour du Monde en Quatre-Vingts Jours
+ (Around the World in Eighty Days)
+Notes: Wall-clock time plays a central role in the plot.
+ European readers of the 1870s clearly held the U.S. press in
+ deep contempt; the protagonists cross the U.S. without once
+ reading a paper.
+ An on-line French-language version of the book
+ "with illustrations from the original 1873 French-language edition"
+ is available at
+ <A HREF="http://fourmilab.ch/etexts/www/tdm80j">http://fourmilab.ch/etexts/www/tdm80j</A>
+ An on-line English-language translation of the book is available at
+ <A HREF="http://www.literature.org/Works/Jules-Verne/eighty">http://www.literature.org/Works/Jules-Verne/eighty</A>
+--------------------------------------------------------------------------
+Film: Bell Science - About Time
+Notes: The Frank Baxter/Richard Deacon extravaganza
+ Information on ordering is available at
+ <A HREF="http://www.videoflicks.com/VF/38/038332.htm">http://www.videoflicks.com/VF/38/038332.htm</A>
+--------------------------------------------------------------------------
+The syndicated comic strip "Dilbert" featured an all-too-rare example of
+time zone humor on 1998-03-14.
+</PRE>
+</BODY>
+</HTML>
--- /dev/null
+# $NetBSD: Makefile,v 1.14 1995/04/22 12:10:17 cgd Exp $
+
+# Change the line below for your time zone (after finding the zone you want in
+# the time zone files, or adding it to a time zone file).
+# Alternately, if you discover you've got the wrong time zone, you can just
+# zic -l rightzone
+
+# This line has been moved to /usr/src/etc/Makefile
+LOCALTIME= US/Pacific
+
+# If you want something other than Eastern United States time as a template
+# for handling POSIX-style time zone environment variables,
+# change the line below (after finding the zone you want in the
+# time zone files, or adding it to a time zone file).
+# Alternately, if you discover you've got the wrong time zone, you can just
+# zic -p rightzone
+
+POSIXRULES= US/Pacific
+
+# Use an absolute path name for TZDIR unless you're just testing the software.
+
+TZDIR= ${DESTDIR}/usr/share/zoneinfo
+
+# If you always want time values interpreted as "seconds since the epoch
+# (not counting leap seconds)", use
+# REDO= posix_only
+# below. If you always want right time values interpreted as "seconds since
+# the epoch" (counting leap seconds)", use
+# REDO= right_only
+# below. If you want both sets of data available, with leap seconds not
+# counted normally, use
+# REDO= posix_right
+# below. If you want both sets of data available, with leap seconds counted
+# normally, use
+# REDO= right_posix
+# below.
+
+REDO= posix_only
+
+# Since "." may not be in PATH...
+YEARISTYPE= ${.CURDIR}/datfiles/yearistype.sh
+YEARISTYPECOPY= ${.OBJDIR}/yearistypecopy
+
+YDATA= africa antarctica asia australasia \
+ europe northamerica southamerica pacificnew etcetera factory \
+ backward
+NDATA= systemv
+SDATA= solar87 solar88 solar89
+TDATA= $(YDATA) $(NDATA) $(SDATA)
+DATA= $(YDATA) $(NDATA) $(SDATA) leapseconds # yearistype.sh
+USNO= usno1988 usno1989
+
+ZIC=zic
+
+${YEARISTYPECOPY}:
+ cp ${YEARISTYPE} yearistypecopy
+ chmod u+x yearistypecopy
+
+posix_only: ${TDATA} ${YEARISTYPECOPY}
+ (cd ${.CURDIR}/datfiles; \
+ ${ZIC} -y ${YEARISTYPECOPY} -d ${TZDIR} -L /dev/null ${TDATA})
+
+right_only: leapseconds ${TDATA} ${YEARISTYPECOPY}
+ (cd ${.CURDIR}/datfiles; \
+ ${ZIC} -y ${YEARISTYPECOPY} -d ${TZDIR} -L leapseconds ${TDATA})
+
+other_two: leapseconds ${TDATA} ${YEARISTYPECOPY}
+ (cd ${.CURDIR}/datfiles; \
+ ${ZIC} -y ${YEARISTYPECOPY} -d ${TZDIR}/posix -L /dev/null ${TDATA})
+ (cd ${.CURDIR}/datfiles; \
+ ${ZIC} -y ${YEARISTYPECOPY} -d ${TZDIR}/right -L leapseconds ${TDATA})
+
+posix_right: posix_only other_two
+
+right_posix: right_only other_two
+
+realinstall: ${DATA} ${REDO} ${YEARISTYPECOPY}
+ (cd ${.CURDIR}/datfiles; \
+ ${ZIC} -y ${YEARISTYPECOPY} -d ${TZDIR} -p ${POSIXRULES})
+ chown -R ${BINOWN}:${BINGRP} ${TZDIR}
+ find ${TZDIR} -type f | xargs chmod a=r
+
+CLEANFILES+= yearistypecopy
+
+.PATH: ${.CURDIR}/datfiles
+.include <bsd.prog.mk>
--- /dev/null
+@(#)README 7.11
+
+"What time is it?" -- Richard Deacon as The King
+"Any time you want it to be." -- Frank Baxter as The Scientist
+ (from the Bell System film "About Time")
+
+The 1989 update of the time zone package featured
+
+* POSIXization (including interpretation of POSIX-style TZ environment
+ variables, provided by Guy Harris),
+* ANSIfication (including versions of "mktime" and "difftime"),
+* SVIDulation (an "altzone" variable)
+* MACHination (the "gtime" function)
+* corrections to some time zone data (including corrections to the rules
+ for Great Britain and New Zealand)
+* reference data from the United States Naval Observatory for folks who
+ want to do additional time zones
+* and the 1989 data for Saudi Arabia.
+
+(Since this code will be treated as "part of the implementation" in some places
+and as "part of the application" in others, there's no good way to name
+functions, such as timegm, that are not part of the proposed ANSI C standard;
+such functions have kept their old, underscore-free names in this update.)
+
+And the "dysize" function has disappeared; it was present to allow compilation
+of the "date" command on old BSD systems, and a version of "date" is now
+provided in the package. The "date" command is not created when you "make all"
+since it may lack options provided by the version distributed with your
+operating system, or may not interact with the system in the same way the
+native version does.
+
+Since POSIX frowns on correct leap second handling, the default behavior of
+the "zic" command (in the absence of a "-L" option) has been changed to omit
+leap second information from its output files.
+
+Here is a recipe for acquiring, building, installing, and testing the
+tz distribution on a GNU/Linux or similar host.
+
+ mkdir tz
+ cd tz
+ wget 'ftp://elsie.nci.nih.gov/pub/tz*.tar.gz'
+ gzip -dc tzcode*.tar.gz | tar -xf -
+ gzip -dc tzdata*.tar.gz | tar -xf -
+
+Be sure to read the comments in "Makefile" and make any changes needed
+to make things right for your system, especially if you are using some
+platform other than GNU/Linux. Then run the following commands,
+substituting your desired installation directory for "$HOME/tzdir":
+
+ make TOPDIR=$HOME/tzdir install
+ $HOME/tzdir/etc/zdump -v America/Los_Angeles
+
+To use the new functions, use a "-ltz" option when compiling or linking.
+
+Historical local time information has been included here not because it
+is particularly useful, but rather to:
+
+* give an idea of the variety of local time rules that have
+ existed in the past and thus an idea of the variety that may be
+ expected in the future;
+
+* provide a test of the generality of the local time rule description
+ system.
+
+The information in the time zone data files is by no means authoritative;
+if you know that the rules are different from those in a file, by all means
+feel free to change file (and please send the changed version to
+tz@elsie.nci.nih.gov for use in the future). Europeans take note!
+
+Thanks to these Timezone Caballeros who've made major contributions to the
+time conversion package: Keith Bostic; Bob Devine; Paul Eggert; Robert Elz;
+Guy Harris; Mark Horton; John Mackin; and Bradley White. Thanks also to
+Michael Bloom, Art Neilson, Stephen Prince, John Sovereign, and Frank Wales
+for testing work, and to Gwillim Law for checking local mean time data.
+None of them are responsible for remaining errors.
+
+Look in the ~ftp/pub directory of elsie.nci.nih.gov
+for updated versions of these files.
+
+Please send comments or information to tz@elsie.nci.nih.gov.
--- /dev/null
+@(#)Theory 7.15
+
+
+----- Outline -----
+
+ Time and date functions
+ Names of time zone regions
+ Time zone abbreviations
+ Calendrical issues
+ Time and time zones on Mars
+
+
+----- Time and date functions -----
+
+These time and date functions are upwards compatible with POSIX.1,
+an international standard for UNIX-like systems.
+As of this writing, the current edition of POSIX.1 is:
+
+ Information technology --Portable Operating System Interface (POSIX (R))
+ -- Part 1: System Application Program Interface (API) [C Language]
+ ISO/IEC 9945-1:1996
+ ANSI/IEEE Std 1003.1, 1996 Edition
+ 1996-07-12
+
+POSIX.1 has the following properties and limitations.
+
+* In POSIX.1, time display in a process is controlled by the
+ environment variable TZ. Unfortunately, the POSIX.1 TZ string takes
+ a form that is hard to describe and is error-prone in practice.
+ Also, POSIX.1 TZ strings can't deal with other (for example, Israeli)
+ daylight saving time rules, or situations where more than two
+ time zone abbreviations are used in an area.
+
+ The POSIX.1 TZ string takes the following form:
+
+ stdoffset[dst[offset],date[/time],date[/time]]
+
+ where:
+
+ std and dst
+ are 3 or more characters specifying the standard
+ and daylight saving time (DST) zone names.
+ offset
+ is of the form `[-]hh:[mm[:ss]]' and specifies the
+ offset west of UTC. The default DST offset is one hour
+ ahead of standard time.
+ date[/time],date[/time]
+ specifies the beginning and end of DST. If this is absent,
+ the system supplies its own rules for DST, and these can
+ differ from year to year; typically US DST rules are used.
+ time
+ takes the form `hh:[mm[:ss]]' and defaults to 02:00.
+ date
+ takes one of the following forms:
+ Jn (1<=n<=365)
+ origin-1 day number not counting February 29
+ n (0<=n<=365)
+ origin-0 day number counting February 29 if present
+ Mm.n.d (0[Sunday]<=d<=6[Saturday], 1<=n<=5, 1<=m<=12)
+ for the dth day of week n of month m of the year,
+ where week 1 is the first week in which day d appears,
+ and `5' stands for the last week in which day d appears
+ (which may be either the 4th or 5th week).
+
+* In POSIX.1, when a TZ value like "EST5EDT" is parsed,
+ typically the current US DST rules are used,
+ but this means that the US DST rules are compiled into each program
+ that does time conversion. This means that when US time conversion
+ rules change (as in the United States in 1987), all programs that
+ do time conversion must be recompiled to ensure proper results.
+
+* In POSIX.1, there's no tamper-proof way for a process to learn the
+ system's best idea of local wall clock. (This is important for
+ applications that an administrator wants used only at certain times--
+ without regard to whether the user has fiddled the "TZ" environment
+ variable. While an administrator can "do everything in UTC" to get
+ around the problem, doing so is inconvenient and precludes handling
+ daylight saving time shifts--as might be required to limit phone
+ calls to off-peak hours.)
+
+* POSIX.1 requires that systems ignore leap seconds.
+
+These are the extensions that have been made to the POSIX.1 functions:
+
+* The "TZ" environment variable is used in generating the name of a file
+ from which time zone information is read (or is interpreted a la
+ POSIX); "TZ" is no longer constrained to be a three-letter time zone
+ name followed by a number of hours and an optional three-letter
+ daylight time zone name. The daylight saving time rules to be used
+ for a particular time zone are encoded in the time zone file;
+ the format of the file allows U.S., Australian, and other rules to be
+ encoded, and allows for situations where more than two time zone
+ abbreviations are used.
+
+ It was recognized that allowing the "TZ" environment variable to
+ take on values such as "America/New_York" might cause "old" programs
+ (that expect "TZ" to have a certain form) to operate incorrectly;
+ consideration was given to using some other environment variable
+ (for example, "TIMEZONE") to hold the string used to generate the
+ time zone information file name. In the end, however, it was decided
+ to continue using "TZ": it is widely used for time zone purposes;
+ separately maintaining both "TZ" and "TIMEZONE" seemed a nuisance;
+ and systems where "new" forms of "TZ" might cause problems can simply
+ use TZ values such as "EST5EDT" which can be used both by
+ "new" programs (a la POSIX) and "old" programs (as zone names and
+ offsets).
+
+* To handle places where more than two time zone abbreviations are used,
+ the functions "localtime" and "gmtime" set tzname[tmp->tm_isdst]
+ (where "tmp" is the value the function returns) to the time zone
+ abbreviation to be used. This differs from POSIX.1, where the elements
+ of tzname are only changed as a result of calls to tzset.
+
+* Since the "TZ" environment variable can now be used to control time
+ conversion, the "daylight" and "timezone" variables are no longer
+ needed. (These variables are defined and set by "tzset"; however, their
+ values will not be used by "localtime.")
+
+* The "localtime" function has been set up to deliver correct results
+ for near-minimum or near-maximum time_t values. (A comment in the
+ source code tells how to get compatibly wrong results).
+
+* A function "tzsetwall" has been added to arrange for the system's
+ best approximation to local wall clock time to be delivered by
+ subsequent calls to "localtime." Source code for portable
+ applications that "must" run on local wall clock time should call
+ "tzsetwall();" if such code is moved to "old" systems that don't
+ provide tzsetwall, you won't be able to generate an executable program.
+ (These time zone functions also arrange for local wall clock time to be
+ used if tzset is called--directly or indirectly--and there's no "TZ"
+ environment variable; portable applications should not, however, rely
+ on this behavior since it's not the way SVR2 systems behave.)
+
+* These functions can account for leap seconds, thanks to Bradley White
+ (bww@k.cs.cmu.edu).
+
+Points of interest to folks with other systems:
+
+* This package is already part of many POSIX-compliant hosts,
+ including BSD, HP, Linux, Network Appliance, SCO, SGI, and Sun.
+ On such hosts, the primary use of this package
+ is to update obsolete time zone rule tables.
+ To do this, you may need to compile the time zone compiler
+ `zic' supplied with this package instead of using the system `zic',
+ since the format of zic's input changed slightly in late 1994,
+ and many vendors still do not support the new input format.
+
+* The UNIX Version 7 "timezone" function is not present in this package;
+ it's impossible to reliably map timezone's arguments (a "minutes west
+ of GMT" value and a "daylight saving time in effect" flag) to a
+ time zone abbreviation, and we refuse to guess.
+ Programs that in the past used the timezone function may now examine
+ tzname[localtime(&clock)->tm_isdst] to learn the correct time
+ zone abbreviation to use. Alternatively, use
+ localtime(&clock)->tm_zone if this has been enabled.
+
+* The 4.2BSD gettimeofday function is not used in this package.
+ This formerly let users obtain the current UTC offset and DST flag,
+ but this functionality was removed in later versions of BSD.
+
+* In SVR2, time conversion fails for near-minimum or near-maximum
+ time_t values when doing conversions for places that don't use UTC.
+ This package takes care to do these conversions correctly.
+
+The functions that are conditionally compiled if STD_INSPIRED is defined
+should, at this point, be looked on primarily as food for thought. They are
+not in any sense "standard compatible"--some are not, in fact, specified in
+*any* standard. They do, however, represent responses of various authors to
+standardization proposals.
+
+Other time conversion proposals, in particular the one developed by folks at
+Hewlett Packard, offer a wider selection of functions that provide capabilities
+beyond those provided here. The absence of such functions from this package
+is not meant to discourage the development, standardization, or use of such
+functions. Rather, their absence reflects the decision to make this package
+contain valid extensions to POSIX.1, to ensure its broad
+acceptability. If more powerful time conversion functions can be standardized,
+so much the better.
+
+
+----- Names of time zone rule files -----
+
+The time zone rule file naming conventions attempt to strike a balance
+among the following goals:
+
+ * Uniquely identify every national region where clocks have all
+ agreed since 1970. This is essential for the intended use: static
+ clocks keeping local civil time.
+
+ * Indicate to humans as to where that region is. This simplifes use.
+
+ * Be robust in the presence of political changes. This reduces the
+ number of updates and backward-compatibility hacks. For example,
+ names of countries are ordinarily not used, to avoid
+ incompatibilities when countries change their name
+ (e.g. Zaire->Congo) or when locations change countries
+ (e.g. Hong Kong from UK colony to China).
+
+ * Be portable to a wide variety of implementations.
+ This promotes use of the technology.
+
+ * Use a consistent naming convention over the entire world.
+ This simplifies both use and maintenance.
+
+This naming convention is not intended for use by inexperienced users
+to select TZ values by themselves (though they can of course examine
+and reuse existing settings). Distributors should provide
+documentation and/or a simple selection interface that explains the
+names; see the 'tzselect' program supplied with this distribution for
+one example.
+
+Names normally have the form AREA/LOCATION, where AREA is the name
+of a continent or ocean, and LOCATION is the name of a specific
+location within that region. North and South America share the same
+area, `America'. Typical names are `Africa/Cairo', `America/New_York',
+and `Pacific/Honolulu'.
+
+Here are the general rules used for choosing location names,
+in decreasing order of importance:
+
+ Use only valid POSIX file name components (i.e., the parts of
+ names other than `/'). Within a file name component,
+ use only ASCII letters, `.', `-' and `_'. Do not use
+ digits, as that might create an ambiguity with POSIX
+ TZ strings. A file name component must not exceed 14
+ characters or start with `-'. E.g., prefer `Brunei'
+ to `Bandar_Seri_Begawan'.
+ Include at least one location per time zone rule set per country.
+ One such location is enough. Use ISO 3166 (see the file
+ iso3166.tab) to help decide whether something is a country.
+ If all the clocks in a country's region have agreed since 1970,
+ don't bother to include more than one location
+ even if subregions' clocks disagreed before 1970.
+ Otherwise these tables would become annoyingly large.
+ If a name is ambiguous, use a less ambiguous alternative;
+ e.g. many cities are named San Jose and Georgetown, so
+ prefer `Costa_Rica' to `San_Jose' and `Guyana' to `Georgetown'.
+ Keep locations compact. Use cities or small islands, not countries
+ or regions, so that any future time zone changes do not split
+ locations into different time zones. E.g. prefer `Paris'
+ to `France', since France has had multiple time zones.
+ Use mainstream English spelling, e.g. prefer `Rome' to `Roma', and
+ prefer `Athens' to the true name (which uses Greek letters).
+ The POSIX file name restrictions encourage this rule.
+ Use the most populous among locations in a country's time zone,
+ e.g. prefer `Shanghai' to `Beijing'. Among locations with
+ similar populations, pick the best-known location,
+ e.g. prefer `Rome' to `Milan'.
+ Use the singular form, e.g. prefer `Canary' to `Canaries'.
+ Omit common suffixes like `_Islands' and `_City', unless that
+ would lead to ambiguity. E.g. prefer `Cayman' to
+ `Cayman_Islands' and `Guatemala' to `Guatemala_City',
+ but prefer `Mexico_City' to `Mexico' because the country
+ of Mexico has several time zones.
+ Use `_' to represent a space.
+ Omit `.' from abbreviations in names, e.g. prefer `St_Helena'
+ to `St._Helena'.
+ Do not change established names if they only marginally
+ violate the above rules. For example, don't change
+ the existing name `Rome' to `Milan' merely because
+ Milan's population has grown to be somewhat greater
+ than Rome's.
+ If a name is changed, put its old spelling in the `backward' file.
+
+The file `zone.tab' lists the geographical locations used to name
+time zone rule files.
+
+Older versions of this package used a different naming scheme,
+and these older names are still supported.
+See the file `backward' for most of these older names
+(e.g. `US/Eastern' instead of `America/New_York').
+The other old-fashioned names still supported are
+`WET', `CET', `MET', `EET' (see the file `europe'),
+and `Factory' (see the file `factory').
+
+
+----- Time zone abbreviations -----
+
+When this package is installed, it generates time zone abbreviations
+like `EST' to be compatible with human tradition and POSIX.1.
+Here are the general rules used for choosing time zone abbreviations,
+in decreasing order of importance:
+
+ Use abbreviations that consist of three or more ASCII letters.
+ Previous editions of this database also used characters like
+ ' ' and '?', but these characters have a special meaning to
+ the shell and cause commands like
+ set `date`
+ to have unexpected effects.
+ Previous editions of this rule required upper-case letters,
+ but the Congressman who introduced Chamorro Standard Time
+ preferred "ChST", so the rule has been relaxed.
+
+ This rule guarantees that all abbreviations could have
+ been specified by a POSIX.1 TZ string. POSIX.1
+ requires at least three characters for an
+ abbreviation. POSIX.1-1996 says that an abbreviation
+ cannot start with ':', and cannot contain ',', '-',
+ '+', NUL, or a digit. Draft 7 of POSIX 1003.1-200x
+ changes this rule to say that an abbreviation can
+ contain only '-', '+', and alphanumeric characters in
+ the current locale. To be portable to both sets of
+ rules, an abbreviation must therefore use only ASCII
+ letters, as these are the only letters that are
+ alphabetic in all locales.
+
+ Use abbreviations that are in common use among English-speakers,
+ e.g. `EST' for Eastern Standard Time in North America.
+ We assume that applications translate them to other languages
+ as part of the normal localization process; for example,
+ a French application might translate `EST' to `HNE'.
+
+ For zones whose times are taken from a city's longitude, use the
+ traditional xMT notation, e.g. `PMT' for Paris Mean Time.
+ The only name like this in current use is `GMT'.
+
+ If there is no common English abbreviation, abbreviate the English
+ translation of the usual phrase used by native speakers.
+ If this is not available or is a phrase mentioning the country
+ (e.g. ``Cape Verde Time''), then:
+
+ When a country has a single or principal time zone region,
+ append `T' to the country's ISO code, e.g. `CVT' for
+ Cape Verde Time. For summer time append `ST';
+ for double summer time append `DST'; etc.
+ When a country has multiple time zones, take the first three
+ letters of an English place name identifying each zone
+ and then append `T', `ST', etc. as before;
+ e.g. `VLAST' for VLAdivostok Summer Time.
+
+ Use "zzz" for locations while uninhabited. The mnemonic is that
+ these locations are, in some sense, asleep.
+
+Application writers should note that these abbreviations are ambiguous
+in practice: e.g. `EST' has a different meaning in Australia than
+it does in the United States. In new applications, it's often better
+to use numeric UTC offsets like `-0500' instead of time zone
+abbreviations like `EST'; this avoids the ambiguity.
+
+
+----- Calendrical issues -----
+
+Calendrical issues are a bit out of scope for a time zone database,
+but they indicate the sort of problems that we would run into if we
+extended the time zone database further into the past. An excellent
+resource in this area is Nachum Dershowitz and Edward M. Reingold,
+<a href="http://emr.cs.uiuc.edu/home/reingold/calendar-book/index.shtml">
+Calendrical Calculations
+</a>, Cambridge University Press (1997). Other information and
+sources are given below. They sometimes disagree.
+
+
+France
+
+Gregorian calendar adopted 1582-12-20.
+French Revolutionary calendar used 1793-11-24 through 1805-12-31,
+and (in Paris only) 1871-05-06 through 1871-05-23.
+
+
+Russia
+
+From Chris Carrier <72157.3334@CompuServe.COM> (1996-12-02):
+On 1929-10-01 the Soviet Union instituted an ``Eternal Calendar''
+with 30-day months plus 5 holidays, with a 5-day week.
+On 1931-12-01 it changed to a 6-day week; in 1934 it reverted to the
+Gregorian calendar while retaining the 6-day week; on 1940-06-27 it
+reverted to the 7-day week. With the 6-day week the usual days
+off were the 6th, 12th, 18th, 24th and 30th of the month.
+(Source: Evitiar Zerubavel, _The Seven Day Circle_)
+
+
+Mark Brader reported a similar story in "The Book of Calendars", edited
+by Frank Parise (1982, Facts on File, ISBN 0-8719-6467-8), page 377. But:
+
+From: Petteri Sulonen (via Usenet)
+Date: 14 Jan 1999 00:00:00 GMT
+Message-ID: <Petteri.Sulonen-1401991626030001@lapin-kulta.in.helsinki.fi>
+
+If your source is correct, how come documents between 1929 -- 1940 were
+still dated using the conventional, Gregorian calendar?
+
+I can post a scan of a document dated December 1, 1934, signed by
+Yenukidze, the secretary, on behalf of Kalinin, the President of the
+Executive Committee of the Supreme Soviet, if you like.
+
+
+
+Sweden (and Finland)
+
+From: msb@sq.com (Mark Brader)
+<a href="news:1996Jul6.012937.29190@sq.com">
+Subject: Re: Gregorian reform -- a part of locale?
+</a>
+Date: 1996-07-06
+
+In 1700, Denmark made the transition from Julian to Gregorian. Sweden
+decided to *start* a transition in 1700 as well, but rather than have one of
+those unsightly calendar gaps :-), they simply decreed that the next leap
+year after 1696 would be in 1744 -- putting the whole country on a calendar
+different from both Julian and Gregorian for a period of 40 years.
+
+However, in 1704 something went wrong and the plan was not carried through;
+they did, after all, have a leap year that year. And one in 1708. In 1712
+they gave it up and went back to Julian, putting 30 days in February that
+year!...
+
+Then in 1753, Sweden made the transition to Gregorian in the usual manner,
+getting there only 13 years behind the original schedule.
+
+(A previous posting of this story was challenged, and Swedish readers
+produced the following references to support it: "Tiderakning och historia"
+by Natanael Beckman (1924) and "Tid, en bok om tiderakning och
+kalendervasen" by Lars-Olof Lode'n (no date was given).)
+
+
+Grotefend's data
+
+From: "Michael Palmer" <mpalmer@netcom.com> [with one obvious typo fixed]
+Subject: Re: Gregorian Calendar (was Re: Another FHC related question
+Newsgroups: soc.genealogy.german
+Date: Tue, 9 Feb 1999 02:32:48 -800
+Message-ID: <199902091032.CAA09644@netcom10.netcom.com>
+
+The following is a(n incomplete) listing, arranged chronologically, of
+European states, with the date they converted from the Julian to the
+Gregorian calendar:
+
+04/15 Oct 1582 - Italy (with exceptions), Spain, Portugal, Poland (Roman
+ Catholics and Danzig only)
+09/20 Dec 1582 - France, Lorraine
+
+21 Dec 1582/
+ 01 Jan 1583 - Holland, Brabant, Flanders, Hennegau
+10/21 Feb 1583 - bishopric of Liege (L"uttich)
+13/24 Feb 1583 - bishopric of Augsburg
+04/15 Oct 1583 - electorate of Trier
+05/16 Oct 1583 - Bavaria, bishoprics of Freising, Eichstedt, Regensburg,
+ Salzburg, Brixen
+13/24 Oct 1583 - Austrian Oberelsass and Breisgau
+20/31 Oct 1583 - bishopric of Basel
+02/13 Nov 1583 - duchy of J"ulich-Berg
+02/13 Nov 1583 - electorate and city of K"oln
+04/15 Nov 1583 - bishopric of W"urzburg
+11/22 Nov 1583 - electorate of Mainz
+16/27 Nov 1583 - bishopric of Strassburg and the margraviate of Baden
+17/28 Nov 1583 - bishopric of M"unster and duchy of Cleve
+14/25 Dec 1583 - Steiermark
+
+06/17 Jan 1584 - Austria and Bohemia
+11/22 Jan 1584 - Luzern, Uri, Schwyz, Zug, Freiburg, Solothurn
+12/23 Jan 1584 - Silesia and the Lausitz
+22 Jan/
+ 02 Feb 1584 - Hungary (legally on 21 Oct 1587)
+ Jun 1584 - Unterwalden
+01/12 Jul 1584 - duchy of Westfalen
+
+16/27 Jun 1585 - bishopric of Paderborn
+
+14/25 Dec 1590 - Transylvania
+
+22 Aug/
+ 02 Sep 1612 - duchy of Prussia
+
+13/24 Dec 1614 - Pfalz-Neuburg
+
+ 1617 - duchy of Kurland (reverted to the Julian calendar in
+ 1796)
+
+ 1624 - bishopric of Osnabr"uck
+
+ 1630 - bishopric of Minden
+
+15/26 Mar 1631 - bishopric of Hildesheim
+
+ 1655 - Kanton Wallis
+
+05/16 Feb 1682 - city of Strassburg
+
+18 Feb/
+ 01 Mar 1700 - Protestant Germany (including Swedish possessions in
+ Germany), Denmark, Norway
+30 Jun/
+ 12 Jul 1700 - Gelderland, Zutphen
+10 Nov/
+ 12 Dec 1700 - Utrecht, Overijssel
+
+31 Dec 1700/
+ 12 Jan 1701 - Friesland, Groningen, Z"urich, Bern, Basel, Geneva,
+ Turgau, and Schaffhausen
+
+ 1724 - Glarus, Appenzell, and the city of St. Gallen
+
+01 Jan 1750 - Pisa and Florence
+
+02/14 Sep 1752 - Great Britain
+
+17 Feb/
+ 01 Mar 1753 - Sweden
+
+1760-1812 - Graub"unden
+
+The Russian empire (including Finland and the Baltic states) did not
+convert to the Gregorian calendar until the Soviet revolution of 1917.
+
+Source: H. Grotefend, _Taschenbuch der Zeitrechnung des deutschen
+Mittelalters und der Neuzeit_, herausgegeben von Dr. O. Grotefend
+(Hannover: Hahnsche Buchhandlung, 1941), pp. 26-28.
+
+
+----- Time and time zones on Mars -----
+
+Some people have adjusted their work schedules to fit Mars time.
+Dozens of special Mars watches were built for Jet Propulsion
+Laboratory workers who kept Mars time during the Mars Exploration
+Rovers mission (2004). These timepieces look like normal Seikos and
+Citizens but use Mars seconds rather than terrestrial seconds.
+
+A Mars solar day is called a "sol" and has a mean period equal to
+about 24 hours 39 minutes 35.244 seconds in terrestrial time. It is
+divided into a conventional 24-hour clock, so each Mars second equals
+about 1.02749125 terrestrial seconds.
+
+The prime meridian of Mars goes through the center of the crater
+Airy-0, named in honor of the British astronomer who built the
+Greenwich telescope that defines Earth's prime meridian. Mean solar
+time on the Mars prime meridian is called Mars Coordinated Time (MTC).
+
+Each landed mission on Mars has adopted a different reference for
+solar time keeping, so there is no real standard for Mars time zones.
+For example, the Mars Exploration Rover project (2004) defined two
+time zones "Local Solar Time A" and "Local Solar Time B" for its two
+missions, each zone designed so that its time equals local true solar
+time at approximately the middle of the nominal mission. Such a "time
+zone" is not particularly suited for any application other than the
+mission itself.
+
+Many calendars have been proposed for Mars, but none have achieved
+wide acceptance. Astronomers often use Mars Sol Date (MSD) which is a
+sequential count of Mars solar days elapsed since about 1873-12-29
+12:00 GMT.
+
+The tz database does not currently support Mars time, but it is
+documented here in the hopes that support will be added eventually.
+
+Sources:
+
+Michael Allison and Robert Schmunk,
+"Technical Notes on Mars Solar Time as Adopted by the Mars24 Sunclock"
+<http://www.giss.nasa.gov/tools/mars24/help/notes.html> (2004-03-15).
+
+Jia-Rui Chong, "Workdays Fit for a Martian", Los Angeles Times
+(2004-01-14), pp A1, A20-A21.
--- /dev/null
+#this must be run on a native system
+
+zic -y datfiles/yearistype.sh -d /tmp/zoneinfo -L /dev/null datfiles/africa datfiles/antarctica datfiles/asia datfiles/australasia datfiles/europe datfiles/northamerica datfiles/southamerica datfiles/pacificnew datfiles/etcetera datfiles/factory datfiles/backward datfiles/systemv datfiles/solar87 datfiles/solar88 datfiles/solar89
+
--- /dev/null
+#!/bin/sh
+set -e
+set -x
+
+if [ $# -ne 1 ]; then
+ echo "Usage: $0 BUILT_PRODUCTS_DIR" 1>&2
+ exit 1
+fi
+
+BUILT_PRODUCTS_DIR="$1"
+
+# We may not be building for a platform we can natively
+# run on the build machine. Build a dedicate copy of zic
+# for processing zoneinfo files
+
+ZICHOST_SYMROOT="${BUILT_PRODUCTS_DIR}/zic_host-sym"
+ZICHOST_DSTROOT="${BUILT_PRODUCTS_DIR}/zic_host-dst"
+ZICHOST="${ZICHOST_DSTROOT}/zic_host"
+
+# A full environment causes build settings from a cross
+# build (like PLATFORM_NAME) to leak into a native
+# host tool build
+
+EXTRA_ARGS=""
+if [ -n "${XCODE_DEVELOPER_USR_PATH}" ]; then
+ EXTRA_ARGS="XCODE_DEVELOPER_USR_PATH=${XCODE_DEVELOPER_USR_PATH}"
+fi
+
+env -i \
+ TMPDIR="${TMPDIR}" \
+ PATH="${PATH}" \
+ SCDontUseServer="${SCDontUseServer}" \
+ __CFPREFERENCES_AVOID_DAEMON="${__CFPREFERENCES_AVOID_DAEMON}" \
+ __CF_USER_TEXT_ENCODING="${__CF_USER_TEXT_ENCODING}" \
+ LANG="${LANG}" \
+ HOME="${HOME}" \
+ $EXTRA_ARGS \
+ xcrun -sdk "${SDKROOT}" xcodebuild install \
+ -target zic \
+ -sdk "macosx" \
+ SRCROOT="${SRCROOT}" \
+ OBJROOT="${OBJROOT}" \
+ SYMROOT="${ZICHOST_SYMROOT}" \
+ DSTROOT="${ZICHOST_DSTROOT}" \
+ ARCHS='$(NATIVE_ARCH_ACTUAL)' \
+ PRODUCT_NAME=zic_host \
+ INSTALL_PATH="/"
--- /dev/null
+#!/bin/sh
+set -e
+set -x
+
+printenv | sort
+
+if [ $# -ne 5 ]; then
+ echo "Usage: $0 SRCROOT OBJROOT BUILT_PRODUCTS_DIR SDKROOT PLATFORM_NAME" 1>&2
+ exit 1
+fi
+
+SRCROOT="$1"
+OBJROOT="$2"
+BUILT_PRODUCTS_DIR="$3"
+SDKROOT="$4"
+PLATFORM_NAME="$5"
+
+ZICHOST_SYMROOT="${BUILT_PRODUCTS_DIR}/zic_host-sym"
+ZICHOST_DSTROOT="${BUILT_PRODUCTS_DIR}/zic_host-dst"
+ZICHOST="${ZICHOST_DSTROOT}/zic_host"
+
+LOCALTIME="US/Pacific"
+POSIXRULES="US/Pacific"
+
+# pacificnew is obsolete and was removed from ZONE_FILES
+ZONE_FILES="africa antarctica asia australasia europe northamerica southamerica etcetera factory backward systemv solar87 solar88 solar89"
+ZONEINFO="${BUILT_PRODUCTS_DIR}/zoneinfo"
+DATFILES="${BUILT_PRODUCTS_DIR}/datfiles"
+PRIVATEDIR="${BUILT_PRODUCTS_DIR}/private"
+
+# ftp://elsie.nci.nih.gov/pub/tzdata*.tar.gz
+# the tzdata*.tar.gz file is automatically unpacked and a version file created
+# /usr/local/share/tz/tzdata*.tar.gz is installed by the TimeZoneData project
+TARBALL=`ls ${SDKROOT}/usr/local/share/tz/tzdata* | sort | tail -n 1`
+if [ -z "$TARBALL" ]; then
+ echo "No tzdata file found in ${SDKROOT}/usr/local/share/tz" 1>&2
+ exit 1
+fi
+DATVERS=`basename ${TARBALL} | sed -e 's,\..*,,' -e 's/^tzdata//'`
+VERSIONFILE="${ZONEINFO}/+VERSION"
+
+mkdir -p "${DATFILES}"
+mkdir -p "${ZONEINFO}"
+tar zxf "${TARBALL}" -C "${DATFILES}"
+for tz in ${ZONE_FILES}; do
+ if [ ${tz} = "northamerica" ]; then
+ ARG="-p America/New_York"
+ else
+ ARG=""
+ fi
+ ${ZICHOST} ${ARG} -L /dev/null -d "${ZONEINFO}" \
+ -y "${DATFILES}/yearistype.sh" "${DATFILES}/${tz}" || exit 1
+done
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+chmod -R og-w "${ZONEINFO}"
+for f in "zone.tab" "iso3166.tab"; do
+ install -m 0444 "${DATFILES}/$f" "${ZONEINFO}/$f" || exit 1
+done
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+if [ "${PLATFORM_NAME}" = "iphoneos" ]; then
+ mkdir -p "${PRIVATEDIR}/var/db"
+ mkdir -p -m a+rwx "${PRIVATEDIR}/var/db/timezone"
+
+ # 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"
+fi
+
+rm -f "${VERSIONFILE}"
+echo ${DATVERS} > "${VERSIONFILE}"
+chmod 444 "${VERSIONFILE}"
+touch "${ZONEINFO}"
+touch "${PRIVATEDIR}"
+
--- /dev/null
+#ifndef lint
+#ifndef NOID
+static const char elsieid[] = "@(#)ialloc.c 8.29";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: src/usr.sbin/zic/ialloc.c,v 1.6 2000/11/28 18:18:56 charnier Exp $";
+#endif /* not lint */
+
+/*LINTLIBRARY*/
+
+#include "private.h"
+
+#define nonzero(n) (((n) == 0) ? 1 : (n))
+
+char *
+imalloc(n)
+const int n;
+{
+ return malloc((size_t) nonzero(n));
+}
+
+char *
+icalloc(nelem, elsize)
+int nelem;
+int elsize;
+{
+ if (nelem == 0 || elsize == 0)
+ nelem = elsize = 1;
+ return calloc((size_t) nelem, (size_t) elsize);
+}
+
+void *
+irealloc(pointer, size)
+void * const pointer;
+const int size;
+{
+ if (pointer == NULL)
+ return imalloc(size);
+ return realloc((void *) pointer, (size_t) nonzero(size));
+}
+
+char *
+icatalloc(old, new)
+char * const old;
+const char * const new;
+{
+ register char * result;
+ register int oldsize, newsize;
+
+ newsize = (new == NULL) ? 0 : strlen(new);
+ if (old == NULL)
+ oldsize = 0;
+ else if (newsize == 0)
+ return old;
+ else oldsize = strlen(old);
+ if ((result = irealloc(old, oldsize + newsize + 1)) != NULL)
+ if (new != NULL)
+ (void) strcpy(result + oldsize, new);
+ return result;
+}
+
+char *
+icpyalloc(string)
+const char * const string;
+{
+ return icatalloc((char *) NULL, string);
+}
+
+void
+ifree(p)
+char * const p;
+{
+ if (p != NULL)
+ (void) free(p);
+}
+
+void
+icfree(p)
+char * const p;
+{
+ if (p != NULL)
+ (void) free(p);
+}
--- /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
--- /dev/null
+#ifndef PRIVATE_H
+
+#define PRIVATE_H
+
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+*/
+
+/*
+ * FreeBSD modifications: separate libc's privates from zic's.
+ * This makes it easier when we need to update one but not the other.
+ * I have removed all of the ifdef spaghetti which is not relevant to
+ * zic from this file.
+ *
+ * $FreeBSD: src/usr.sbin/zic/private.h,v 1.7 2004/06/20 21:41:11 stefanf Exp $
+ */
+
+/*
+** This header is for use ONLY with the time conversion code.
+** There is no guarantee that it will remain unchanged,
+** or that it will remain at all.
+** Do NOT copy it to any system include directory.
+** Thank you!
+*/
+
+/*
+** ID
+*/
+
+#ifndef lint
+#ifndef NOID
+static const char privatehid[] = "@(#)private.h 7.53";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*
+** Defaults for preprocessor symbols.
+** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
+*/
+
+#ifndef HAVE_GETTEXT
+#define HAVE_GETTEXT 0
+#endif /* !defined HAVE_GETTEXT */
+
+#ifndef HAVE_STRERROR
+#define HAVE_STRERROR 1
+#endif /* !defined HAVE_STRERROR */
+
+#ifndef HAVE_SYMLINK
+#define HAVE_SYMLINK 1
+#endif /* !defined HAVE_SYMLINK */
+
+#ifndef HAVE_SYS_STAT_H
+#define HAVE_SYS_STAT_H 1
+#endif /* !defined HAVE_SYS_STAT_H */
+
+#ifndef HAVE_SYS_WAIT_H
+#define HAVE_SYS_WAIT_H 1
+#endif /* !defined HAVE_SYS_WAIT_H */
+
+#ifndef HAVE_UNISTD_H
+#define HAVE_UNISTD_H 1
+#endif /* !defined HAVE_UNISTD_H */
+
+/*
+** Nested includes
+*/
+
+#include "sys/types.h" /* for time_t */
+#include "stdio.h"
+#include "errno.h"
+#include "string.h"
+#include "limits.h" /* for CHAR_BIT */
+#include "time.h"
+#include "stdlib.h"
+
+#if HAVE_GETTEXT - 0
+#include "libintl.h"
+#endif /* HAVE_GETTEXT - 0 */
+
+#if HAVE_SYS_WAIT_H - 0
+#include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */
+#endif /* HAVE_SYS_WAIT_H - 0 */
+
+#if HAVE_UNISTD_H - 0
+#include "unistd.h" /* for F_OK and R_OK */
+#endif /* HAVE_UNISTD_H - 0 */
+
+#if !(HAVE_UNISTD_H - 0)
+#ifndef F_OK
+#define F_OK 0
+#endif /* !defined F_OK */
+#ifndef R_OK
+#define R_OK 4
+#endif /* !defined R_OK */
+#endif /* !(HAVE_UNISTD_H - 0) */
+
+/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
+#define is_digit(c) ((unsigned)(c) - '0' <= 9)
+
+#define P(x) x
+
+/*
+** Private function declarations.
+*/
+char * icalloc P((int nelem, int elsize));
+char * icatalloc P((char * old, const char * new));
+char * icpyalloc P((const char * string));
+char * imalloc P((int n));
+void * irealloc P((void * pointer, int size));
+void icfree P((char * pointer));
+void ifree P((char * pointer));
+char * scheck P((const char *string, const char *format));
+
+/*
+** Finally, some convenience items.
+*/
+
+#ifndef TRUE
+#define TRUE 1
+#endif /* !defined TRUE */
+
+#ifndef FALSE
+#define FALSE 0
+#endif /* !defined FALSE */
+
+#ifndef TYPE_BIT
+#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
+#endif /* !defined TYPE_BIT */
+
+#ifndef TYPE_SIGNED
+#define TYPE_SIGNED(type) (((type) -1) < 0)
+#endif /* !defined TYPE_SIGNED */
+
+#ifndef INT_STRLEN_MAXIMUM
+/*
+** 302 / 1000 is log10(2.0) rounded up.
+** Subtract one for the sign bit if the type is signed;
+** add one for integer division truncation;
+** add one more for a minus sign if the type is signed.
+*/
+#define INT_STRLEN_MAXIMUM(type) \
+ ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type))
+#endif /* !defined INT_STRLEN_MAXIMUM */
+
+/*
+** INITIALIZE(x)
+*/
+
+#ifndef GNUC_or_lint
+#ifdef lint
+#define GNUC_or_lint
+#endif /* defined lint */
+#ifndef lint
+#ifdef __GNUC__
+#define GNUC_or_lint
+#endif /* defined __GNUC__ */
+#endif /* !defined lint */
+#endif /* !defined GNUC_or_lint */
+
+#ifndef INITIALIZE
+#ifdef GNUC_or_lint
+#define INITIALIZE(x) ((x) = 0)
+#endif /* defined GNUC_or_lint */
+#ifndef GNUC_or_lint
+#define INITIALIZE(x)
+#endif /* !defined GNUC_or_lint */
+#endif /* !defined INITIALIZE */
+
+/*
+** For the benefit of GNU folk...
+** `_(MSGID)' uses the current locale's message library string for MSGID.
+** The default is to use gettext if available, and use MSGID otherwise.
+*/
+
+#ifndef _
+#if HAVE_GETTEXT - 0
+#define _(msgid) gettext(msgid)
+#else /* !(HAVE_GETTEXT - 0) */
+#define _(msgid) msgid
+#endif /* !(HAVE_GETTEXT - 0) */
+#endif /* !defined _ */
+
+#ifndef TZ_DOMAIN
+#define TZ_DOMAIN "tz"
+#endif /* !defined TZ_DOMAIN */
+
+/*
+** UNIX was a registered trademark of The Open Group in 2003.
+*/
+
+#endif /* !defined PRIVATE_H */
--- /dev/null
+#ifndef lint
+#ifndef NOID
+static const char elsieid[] = "@(#)scheck.c 8.15";
+#endif /* !defined lint */
+#endif /* !defined NOID */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: src/usr.sbin/zic/scheck.c,v 1.7 2001/07/18 11:27:04 dd Exp $";
+#endif /* not lint */
+
+/*LINTLIBRARY*/
+
+#include "private.h"
+
+char *
+scheck(string, format)
+const char * const string;
+const char * const format;
+{
+ register char * fbuf;
+ register const char * fp;
+ register char * tp;
+ register int c;
+ register char * result;
+ char dummy;
+ static char nada;
+
+ result = &nada;
+ if (string == NULL || format == NULL)
+ return result;
+ fbuf = imalloc((int) (2 * strlen(format) + 4));
+ if (fbuf == NULL)
+ return result;
+ fp = format;
+ tp = fbuf;
+ while ((*tp++ = c = *fp++) != '\0') {
+ if (c != '%')
+ continue;
+ if (*fp == '%') {
+ *tp++ = *fp++;
+ continue;
+ }
+ *tp++ = '*';
+ if (*fp == '*')
+ ++fp;
+ while (is_digit(*fp))
+ *tp++ = *fp++;
+ if (*fp == 'l' || *fp == 'h')
+ *tp++ = *fp++;
+ else if (*fp == '[')
+ do *tp++ = *fp++;
+ while (*fp != '\0' && *fp != ']');
+ if ((*tp++ = *fp++) == '\0')
+ break;
+ }
+ *(tp - 1) = '%';
+ *tp++ = 'c';
+ *tp = '\0';
+ if (sscanf(string, fbuf, &dummy) != 1)
+ result = (char *) format;
+ ifree(fbuf);
+ return result;
+}
--- /dev/null
+<?xml version="1.0" encoding="US-ASCII"?>
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-type" content='text/html; charset="US-ASCII"' />
+<title>Time and the Arts</title>
+</head>
+<body>
+<h1>Time and the Arts</h1>
+<address>
+@(#)tz-art.htm 7.53
+</address>
+<p>
+Please send corrections to this web page to the
+<a href="mailto:tz@elsie.nci.nih.gov">time zone mailing list</a>.</p>
+<p>
+See also <a href="tz-link.htm">Sources for Time Zone and Daylight Saving Time Data</a>.</p>
+<hr />
+<p>
+Data on recordings of "Save That Time," Russ Long, Serrob Publishing, BMI:</p>
+<table>
+<tr><td>Artist</td><td>Karrin Allyson</td></tr>
+<tr><td>CD</td><td>I Didn't Know About You</td></tr>
+<tr><td>Copyright Date</td><td>1993</td></tr>
+<tr><td>Label</td><td>Concord Jazz, Inc.</td></tr>
+<tr><td>ID</td><td>CCD-4543</td></tr>
+<tr><td>Track Time</td><td>3:44</td></tr>
+<tr><td>Personnel</td><td>Karrin Allyson, vocal;
+Russ Long, piano;
+Gerald Spaits, bass;
+Todd Strait, drums</td></tr>
+<tr><td>Notes</td><td>CD notes "additional lyric by Karrin Allyson;
+arranged by Russ Long and Karrin Allyson"</td></tr>
+<tr><td>ADO Rating</td><td>1 star</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&sql=A1fdovw9ta92k">AMG Rating</a></td><td>4 stars</td></tr>
+<tr><td>Penguin Rating</td><td>3.5 stars</td></tr>
+<tr><td> </td></tr>
+<tr><td>Artist</td><td>Kevin Mahogany</td></tr>
+<tr><td>CD</td><td>Double Rainbow</td></tr>
+<tr><td>Copyright Date</td><td>1993</td></tr>
+<tr><td>Label</td><td>Enja Records</td></tr>
+<tr><td>ID</td><td>ENJ-7097 2</td></tr>
+<tr><td>Track Time</td><td>6:27</td></tr>
+<tr><td>Personnel</td><td>Kevin Mahogany, vocal;
+Kenny Barron, piano;
+Ray Drummond, bass;
+Ralph Moore, tenor saxophone;
+Lewis Nash, drums</td></tr>
+<tr><td>ADO Rating</td><td>1.5 stars</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&sql=Akikbikzjbb19">AMG Rating</a></td><td>3 stars</td></tr>
+<tr><td>Penguin Rating</td><td>3 stars</td></tr>
+<tr><td> </td></tr>
+<tr><td>Artist</td><td>Joe Williams</td></tr>
+<tr><td>CD</td><td>Here's to Life</td></tr>
+<tr><td>Copyright Date</td><td>1994</td></tr>
+<tr><td>Label</td><td>Telarc International Corporation</td></tr>
+<tr><td>ID</td><td>CD-83357</td></tr>
+<tr><td>Track Time</td><td>3:58</td></tr>
+<tr><td>Personnel</td><td>Joe Williams, vocal
+The Robert Farnon [39 piece] Orchestra</td></tr>
+<tr><td>Notes</td><td>This CD is also available as part of a 3-CD package from
+Telarc, "Triple Play" (CD-83461)</td></tr>
+<tr><td>ADO Rating</td><td>black dot</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&sql=Amyyvad6kt8w1">AMG Rating</a></td><td>2 stars</td></tr>
+<tr><td>Penguin Rating</td><td>3 stars</td></tr>
+<tr><td> </td></tr>
+<tr><td>Artist</td><td>Charles Fambrough</td></tr>
+<tr><td>CD</td><td>Keeper of the Spirit</td></tr>
+<tr><td>Copyright Date</td><td>1995</td></tr>
+<tr><td>Label</td><td>AudioQuest Music</td></tr>
+<tr><td>ID</td><td>AQ-CD1033</td></tr>
+<tr><td>Track Time</td><td>7:07</td></tr>
+<tr><td>Personnel</td><td>Charles Fambrough, bass;
+Joel Levine, tenor recorder;
+Edward Simon, piano;
+Lenny White, drums;
+Marion Simon, percussion</td></tr>
+<tr><td>Notes</td><td>On-line information and samples available at
+<a href="http://wwmusic.com/~music/audioq/rel/1033.html">http://wwmusic.com/~music/audioq/rel/1033.html</a></td></tr>
+<tr><td>ADO Rating</td><td>2 stars</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&sql=A5rkcikcjbb89">AMG Rating</a></td><td>unrated</td></tr>
+<tr><td>Penguin Rating</td><td>3 stars</td></tr>
+</table>
+<hr />
+<p>Also of note:</p>
+<table>
+<tr><td>Artist</td><td>Holly Cole Trio</td></tr>
+<tr><td>CD</td><td>Blame It On My Youth</td></tr>
+<tr><td>Copyright Date</td><td>1992</td></tr>
+<tr><td>Label</td><td>Manhattan</td></tr>
+<tr><td>ID</td><td>CDP 7 97349 2</td></tr>
+<tr><td>Total Time</td><td>37:45</td></tr>
+<tr><td>Personnel</td><td>Holly Cole, voice;
+Aaron Davis, piano;
+David Piltch, string bass</td></tr>
+<tr><td>Notes</td><td>Lyrical reference to "Eastern Standard Time" in
+Tom Waits' "Purple Avenue"</td></tr>
+<tr><td>ADO Rating</td><td>2.5 stars</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&sql=A3a9ds37ya3dg">AMG Rating</a></td><td>3 stars</td></tr>
+<tr><td>Penguin Rating</td><td>unrated</td></tr>
+<tr><td> </td></tr>
+<tr><td>Artist</td><td>Milt Hinton</td></tr>
+<tr><td>CD</td><td>Old Man Time</td></tr>
+<tr><td>Copyright Date</td><td>1990</td></tr>
+<tr><td>Label</td><td>Chiaroscuro</td></tr>
+<tr><td>ID</td><td>CR(D) 310</td></tr>
+<tr><td>Total Time</td><td>149:38 (two CDs)</td></tr>
+<tr><td>Personnel</td><td>Milt Hinton, bass;
+Doc Cheatham, Dizzy Gillespie, Clark Terry, trumpet;
+Al Grey, trombone;
+Eddie Barefield, Joe Camel (Flip Phillips), Buddy Tate,
+clarinet and saxophone;
+John Bunch, Red Richards, Norman Simmons, Derek Smith,
+Ralph Sutton, piano;
+Danny Barker, Al Casey, guitar;
+Gus Johnson, Gerryck King, Bob Rosengarden, Jackie Williams,
+drums;
+Lionel Hampton, vibraphone;
+Cab Calloway, Joe Williams, vocal;
+Buck Clayton, arrangements</td></tr>
+<tr><td>Notes</td><td>tunes include Old Man Time, Time After Time,
+Sometimes I'm Happy,
+A Hot Time in the Old Town Tonight,
+Four or Five Times, Now's the Time,
+Time on My Hands, This Time It's Us,
+and Good Time Charlie
+On-line samples available at
+<a href="http://www.chiaroscurojazz.com/albuminfo.php4?albumid=49">http://www.chiaroscurojazz.com/albuminfo.php3?albumid=49</a></td></tr>
+<tr><td>ADO Rating</td><td>3 stars</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&sql=A1cbyxdab8ola">AMG Rating</a></td><td>4.5 stars</td></tr>
+<tr><td>Penguin Rating</td><td>3 stars</td></tr>
+<tr><td> </td></tr>
+<tr><td>Artist</td><td>Alan Broadbent</td></tr>
+<tr><td>CD</td><td>Pacific Standard Time</td></tr>
+<tr><td>Copyright Date</td><td>1995</td></tr>
+<tr><td>Label</td><td>Concord Jazz, Inc.</td></tr>
+<tr><td>ID</td><td>CCD-4664</td></tr>
+<tr><td>Total Time</td><td>62:42</td></tr>
+<tr><td>Personnel</td><td>Alan Broadbent, piano;
+Putter Smith, Bass;
+Frank Gibson, Jr., drums</td></tr>
+<tr><td>Notes</td><td>The CD cover features an analemma for equation-of-time fans</td></tr>
+<tr><td>ADO Rating</td><td>1 star</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&sql=Asl8zefuk8gfo">AMG Rating</a></td><td>4 stars</td></tr>
+<tr><td>Penguin Rating</td><td>3.5 stars</td></tr>
+<tr><td> </td></tr>
+<tr><td>Artist</td><td>Anthony Braxton/Richard Teitelbaum</td></tr>
+<tr><td>CD</td><td>Silence/Time Zones</td></tr>
+<tr><td>Copyright Date</td><td>1996</td></tr>
+<tr><td>Label</td><td>Black Lion</td></tr>
+<tr><td>ID</td><td>BLCD 760221</td></tr>
+<tr><td>Total Time</td><td>72:58</td></tr>
+<tr><td>Personnel</td><td>Anthony Braxton, sopranino and alto saxophones,
+contrebasse clarinet, miscellaneous instruments;
+Leo Smith, trumpet and miscellaneous instruments;
+Leroy Jenkins, violin and miscellaneous instruments;
+Richard Teitelbaum, modular moog and micromoog synthesizer</td></tr>
+<tr><td>ADO Rating</td><td>black dot</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&sql=A5bkvu3xjan1k">AMG Rating</a></td><td>unrated</td></tr>
+<tr><td> </td></tr>
+<tr><td>Artist</td><td>Jules Verne</td></tr>
+<tr><td>Book</td><td>Le Tour du Monde en Quatre-Vingts Jours
+(Around the World in Eighty Days)</td></tr>
+<tr><td>Notes</td><td>Wall-clock time plays a central role in the plot.
+European readers of the 1870s clearly held the U.S. press in
+deep contempt; the protagonists cross the U.S. without once
+reading a paper.
+An on-line French-language version of the book
+"with illustrations from the original 1873 French-language edition"
+is available at
+<a href="http://fourmilab.ch/etexts/www/tdm80j">http://fourmilab.ch/etexts/www/tdm80j</a>
+An on-line English-language translation of the book is available at
+<a href="http://www.literature.org/Works/Jules-Verne/eighty">http://www.literature.org/Works/Jules-Verne/eighty</a></td></tr>
+<tr><td> </td></tr>
+<tr><td>Film</td><td>Bell Science - About Time</td></tr>
+<tr><td>Notes</td><td>The Frank Baxter/Richard Deacon extravaganza
+Information on ordering is available at
+<a href="http://www.videoflicks.com/VF2/1035/1035893.ihtml">http://www.videoflicks.com/VF2/1035/1035893.ihtml</a></td></tr>
+</table>
+<hr />
+<ul>
+<li>
+An episode of "The Adventures of Superman" entitled "The Mysterious
+Cube," first aired 1958-02-24, had Superman convincing the controllers
+of WWV to broadcast time signals five minutes ahead of actual time;
+doing so got a crook trying to beat the statute of limitations to
+emerge a bit too early from the titular enclosure.
+</li>
+<li>
+The 1960s ITC television series "The Prisoner" included an episode
+entitled "The Chimes of Big Ben" in which our protagonist tumbled to
+the fraudulent nature of a Poland-to-England escape upon hearing "Big
+Ben" chiming on Polish local time.
+</li>
+<li>
+The series "Seinfeld" included an episode entitled "The Susie," first
+broadcast 1997-02-13, in which Kramer decides that daylight saving time
+isn't coming fast enough, so he sets his watch ahead an hour.
+</li>
+<li>
+The syndicated comic strip "Dilbert" featured an all-too-rare example of
+time zone humor on 1998-03-14.
+</li>
+<li>
+Surrealist artist Guy Billout's work "Date Line" appeared on page 103
+of the 1999-11 Atlantic Monthly.
+</li>
+<li>
+"Gloom, Gloom, Go Away" by Walter Kirn appeared on page 106 of Time
+Magazine's 2002-11-11 issue; among other things, it proposed
+year-round DST as a way of lessening wintertime despair.
+</li>
+<li>
+The "20 Hours in America" episode of "The West Wing," first aired 2002-09-25,
+saw White House staffers stranded in Indiana; they thought they had time to
+catch Air Force One but were done in by intra-Indiana local time changes.
+</li>
+<li>
+"In what time zone would you find New York City?" was a $200 question on
+the 1999-11-13 United States airing of "Who Wants to Be a Millionaire?"
+"In 1883, what industry led the movement to divide the U.S. into four time
+zones?" was a $32,000 question on the 2001-05-23 United States airing of
+"Who Wants to Be a Millionaire?" At this rate, the million-dollar time-zone
+question should have been asked 2002-06-04.
+</li>
+</ul>
+<hr />
+<ul>
+<li>
+"We're been using the five-cent nickle in this country since 1492.
+Now that's pretty near 100 years, daylight savings [sic]."
+(Groucho Marx as Captain Spaulding in "Animal Crackers", 1930,
+as noted by Will Fitzerald, wfitzgerald@ameritech.net)
+</li>
+<li>
+"Good news."
+"What did they do? Extend Daylight Saving Time year round?"
+(Professional tanner George Hamilton, in dialog from a
+May, 1999 episode of the syndicated television series "Baywatch")
+</li>
+<li>
+"A fundamental belief held by Americans is that if you are on land, you
+cannot be killed by a fish...So most Americans remain on land, believing
+they're safe. Unfortunately, this belief—like so many myths, such as that
+there's a reason for 'Daylight Saving Time'—is false."
+(Dave Barry column, 2000-07-02)
+</li>
+<li>
+"I once had sex for an hour and five minutes, but that was on the day
+when you turn the clocks ahead."
+(Garry Shandling, 52nd Annual Emmys, 2000-09-10)
+</li>
+<li>
+"Would it impress you if I told you I invented Daylight Savings Time?"
+("Sahjhan" to "Lilah" in dialog from the "Loyalty" episode of "Angel,"
+originally aired 2002-02-25)
+</li>
+<li>
+"I thought you said Tulsa was a three hour flight."
+"Well, you're forgetting about the time difference."
+("Chandler" and "Joey" in dialog from the episode of "Friends" first
+aired 2002-12-05)
+</li>
+<li>
+"Is that a pertinent fact,
+or are you trying to dazzle me with your command of time zones?"
+(Kelsey Grammer as "Frasier Crane")
+</li>
+<li>
+"Don't worry about the world coming to an end today.
+It is already tomorrow in Australia."
+(Charles M. Schulz, provided by Steve Summit)
+</li>
+</ul>
+</body>
+</html>
--- /dev/null
+<?xml version="1.0" encoding="US-ASCII"?>
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>Sources for Time Zone and Daylight Saving Time Data</title>
+<link rel="schema.DC" href="http://purl.org/DC/elements/1.1/" />
+<meta http-equiv="Content-type" content='text/html; charset="US-ASCII"' />
+<meta name="DC.Creator" content="Eggert, Paul" />
+<meta name="DC.Contributor" content="Olson, Arthur David" />
+<meta name="DC.Date" content="2004-05-24" />
+<meta name="DC.Description"
+ content="Sources of information about time zones and daylight saving time" />
+<meta name="DC.Identifier" content="http://www.twinsun.com/tz/tz-link.htm" />
+<meta name="Keywords"
+ content="database,daylight saving,DST,time zone,timezone,tz,zoneinfo" />
+</head>
+<body>
+<h1>Sources for Time Zone and Daylight Saving Time Data</h1>
+<address>
+@(#)tz-link.htm 7.42
+</address>
+<p>
+Please send corrections to this web page to the
+<a href="mailto:tz@elsie.nci.nih.gov">time zone mailing list</a>.
+</p>
+<h2>The <code>tz</code> database</h2>
+<p>
+The public-domain time zone database contains code and data
+that represent the history of local time
+for many representative locations around the globe.
+It is updated periodically to reflect changes made by political bodies
+to UTC offsets and daylight-saving rules.
+This database (often called <code>tz</code> or <code>zoneinfo</code>)
+is used by several implementations,
+including
+<a href="http://www.gnu.org/software/libc/">the GNU C Library</a> used in
+<a href="http://www.linux.org/">GNU/Linux</a>,
+<a href="http://www.freebsd.org/">FreeBSD</a>,
+<a href="http://www.netbsd.org/">NetBSD</a>,
+<a href="http://www.openbsd.org/">OpenBSD</a>,
+<a href="http://www.cygwin.com/">Cygwin</a>,
+<a href="http://www.delorie.com/djgpp/">DJGPP</a>,
+<a href="http://www.hp.com/products1/unix/operating/">HP-UX</a>,
+<a href="http://www.sgi.com/developers/technology/irix/">IRIX</a>,
+<a href="http://www.apple.com/macosx/">Mac OS X</a>,
+<a href="http://h71000.www7.hp.com/">OpenVMS</a>,
+<a href="http://wwws.sun.com/software/solaris/">Solaris</a>,
+<a href="http://www.tru64unix.compaq.com/">Tru64</a>, and
+<a href="http://www.sco.com/products/unixware/">UnixWare</a>.</p>
+<p>
+Each location in the database represents a national region where all
+clocks keeping local time have agreed since 1970.
+Locations are identified by continent or ocean and then by the name of
+the location, which is typically the largest city within the region.
+For example, <code>America/New_York</code>
+represents most of the US eastern time zone;
+<code>America/Indianapolis</code> represents most of Indiana, which
+uses eastern time without daylight saving time (DST);
+<code>America/Detroit</code> represents most of Michigan, which uses
+eastern time but with different DST rules in 1975;
+and other entries represent smaller regions like Starke County,
+Kentucky, which switched from central to eastern time in 1991.
+To use the database, set the <code>TZ</code> environment variable to
+the location's full name, e.g., <code>TZ="America/New_York"</code>.</p>
+<p>
+In the <code>tz</code> database's
+<a href="ftp://elsie.nci.nih.gov/pub/">FTP distribution</a>,
+the code is in the file <code>tzcode<var>C</var>.tar.gz</code>,
+where <code><var>C</var></code> is the code's version;
+similarly, the data are in <code>tzdata<var>D</var>.tar.gz</code>,
+where <code><var>D</var></code> is the data's version.
+The following shell commands download
+these files to a GNU/Linux or similar host; see the downloaded
+<code>README</code> file for what to do next.</p>
+<pre style="margin-left: 2em"><code><a href="http://www.gnu.org/software/wget/">wget</a> 'ftp://elsie.nci.nih.gov/pub/tz*.tar.gz'
+<a href="http://www.gnu.org/software/gzip/">gzip</a> -dc tzcode*.tar.gz | <a href="http://www.gnu.org/software/tar/">tar</a> -xf -
+gzip -dc tzdata*.tar.gz | tar -xf -
+</code></pre>
+<p>
+The code lets you compile the <code>tz</code> source files into
+machine-readable binary files, one for each location. It also lets
+you read a <code>tz</code> binary file and interpret time stamps for that
+location.</p>
+<p>
+The data are by no means authoritative. If you find errors, please
+send changes to the <a href="mailto:tz@elsie.nci.nih.gov">time zone
+mailing list</a>. You can also <a
+href="mailto:tz-request@elsie.nci.nih.gov">subscribe</a> to the
+mailing list, retrieve the <a
+href="ftp://elsie.nci.nih.gov/pub/tzarchive.gz">archive of old
+messages</a> (in gzip compressed format), or retrieve <a
+href="ftp://munnari.oz.au/pub/oldtz/">archived older versions of code
+and data</a>.</p>
+<p>
+The Web has several other sources for time zone and daylight saving time data.
+Here are some recent links that may be of interest.
+</p>
+<h2>Web pages using recent versions of the <code>tz</code> database</h2>
+<ul>
+<li><a href="http://twiki.org/cgi-bin/xtra/tzdate">Date and Time Gateway</a>
+is a text-based point-and-click interface to tables of current time
+throughout the world.</li>
+<li>Fancier web interfaces, roughly in ascending order of complexity, include:
+<ul>
+<li><a href="http://www.hilink.com.au/times/">Local Times Around the
+World</a></li>
+<li><a href="http://www.convertit.com/Go/ConvertIt/World_Time/Current_Time.ASP">Current Time in 1000 Places</a></li>
+<li><a href="http://timezoneconverter.com/">Time Zone Converter</a></li>
+</ul></li>
+<li><a href="http://www.holidayfestival.com/">The Worldwide Holiday
+& Festival Site</a> lists DST-related clock changes along with
+holidays.</li>
+<li><a href="http://www.timeanddate.com/worldclock/">The World Clock -
+Time Zones</a>
+is a web interface to a time zone database derived from
+<code>tz</code>'s.</li>
+</ul>
+<h2>Other time zone database formats</h2>
+<ul>
+<li>The <a href="ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt">
+Internet Calendaring and Scheduling Core Object Specification
+(iCalendar)</a> specification published by the <a
+href="http://www.ietf.org/html.charters/calsch-charter.html">IETF
+Calendaring and Scheduling Working Group (calsch)</a> covers time zone
+data; see its VTIMEZONE calendar component.</li>
+<li>The <a
+href="http://lists.w3.org/Archives/Public/www-rdf-calendar/">www-rdf-calendar</a>
+list discusses <a href="http://www.w3.org/RDF/">RDF</a>-based calendar
+and group scheduling systems, and has a <a
+href="http://www.w3.org/2002/12/cal/#tzd">workspace on time zone
+data</a> converted from <code>tz</code>. An earlier <a
+href="http://www.w3.org/2000/01/foo">schema</a> was sketched out by <a
+href="http://www.w3.org/People/Berners-Lee/">Tim Berners-Lee</a>.</li>
+<li><a
+href="http://www.calsch.org/ietf/archives/draft-ietf-calsch-many-xcal-02.txt">XCal</a>
+was a draft <a href="http://www.w3.org/XML/">XML</a> document type
+definition that corresponded to iCalendar.</li>
+</ul>
+<h2>Other <code>tz</code> compilers</h2>
+<ul>
+<li><a href="http://www.dachaplin.dsl.pipex.com/vzic">Vzic iCalendar
+Timezone Converter</a> describes a program Vzic that compiles
+<code>tz</code> source into iCalendar-compatible VTIMEZONE files.
+Vzic is freely
+available under the <a href="http://www.gnu.org/copyleft/gpl.html">GNU
+General Public License (GPL)</a>.</li>
+<li><a
+href="http://search.cpan.org/dist/DateTime-TimeZone/">DateTime::TimeZone</a>
+contains a script <code>parse_olson</code> that compiles
+<code>tz</code> source into <a href="http://www.perl.org/">Perl</a>
+modules. It is part of the Perl <a
+href="http://datetime.perl.org/">DateTime Project</a>, which is freely
+available under both the GPL and the Perl <a
+href="http://www.perl.com/language/misc/Artistic.html">Artistic
+License</a>. DateTime::TimeZone also contains a script
+<code>tests_from_zdump</code> that generates test cases for each clock
+transition in the <code>tz</code> database.</li>
+<li><a href="http://oss.software.ibm.com/icu/">International Components for
+Unicode (ICU)</a> contains a C/C++ library for internationalization that
+has a compiler from <samp>tz</samp> source into an ICU-specific format.
+ICU is freely available under a BSD-style license.</li>
+<li><a href="http://joda-time.sourceforge.net/">Joda Time - Java date
+and time API</a> contains a class
+<code>org.joda.time.tz.ZoneInfoCompiler</code> that compiles
+<code>tz</code> source into a Joda-specific binary format. Joda Time
+is freely available under a BSD-style license.</li>
+</ul>
+<h2>Other <code>tz</code> binary file readers</h2>
+<ul>
+<li>The <a href="http://www.gnu.org/software/libc/">GNU C Library</a>
+has an independent, thread-safe implementation of
+a <code>tz</code> binary file reader.
+This library is freely available under the
+<a href="http://www.gnu.org/copyleft/lesser.html">
+GNU Lesser General Public License (LGPL)</a>,
+and is widely used in GNU/Linux systems.</li>
+<li><a href="http://www.bmsi.com/java/#TZ">ZoneInfo.java</a>
+is a <code>tz</code> binary file reader written in Java.
+It is freely available under the GNU LGPL.</li>
+<li><a href="http://s.keim.free.fr/tz/doc.html">Python time zones</a>
+is a <code>tz</code> binary file reader written in <a
+href="http://www.python.org/">Python</a>. It is freely available
+under a BSD-style license.</li>
+</ul>
+<h2>Other <code>tz</code>-based time zone conversion software</h2>
+<ul>
+<li><a href="http://java.sun.com/">Sun Java</a> releases since 1.4
+contain a copy of a recent <samp>tz</samp> database in a Java-specific
+format.</li>
+<li><a
+href="http://www1.tip.nl/~t876506/AboutTimeZonesHC.html">HyperCard
+time zones calculator</a> is a HyperCard stack.</li>
+<li><a
+href="http://www.cimmyt.org/timezone/">World Time Explorer</a> is a
+Microsoft Windows program.</li>
+</ul>
+<h2>Other time zone databases</h2>
+<ul>
+<li><a href="http://www.astro.com/cgi-bin/atlw3/aq.cgi?lang=e">Atlas Query
+- Astrodienst</a> is Astrodienst's Web version of Shanks's
+excellent time zone history atlases published in both <a
+href="http://astrocom.com/software/pcatlas.php">computer</a> and <a
+href="http://astrocom.com/books/xrefa.php#SHANKS">book</a> form by <a
+href="http://astrocom.com/">Astro Communications Services</a>.</li>
+<li><a href="http://worldtime.com/">WORLDTIME: interactive atlas,
+time info, public holidays</a>
+contains information on local time, sunrise and sunset,
+and public holidays in several hundred cities around the world.</li>
+<li><a href="http://www.worldtimeserver.com/">World Time Server</a>
+is another time zone database.</li>
+<li><a href="http://tycho.usno.navy.mil/tzones.html">World Time Zones</a>
+contains data from the Time Service Department of the US Naval Observatory
+(USNO), used as the source
+for the <code>usno*</code> files in the <code>tz</code> distribution.</li>
+<li><a href="http://www.airportcitycodes.com/aaa/">Airlines, Airplanes
+and Airports</a> lists current standard times for thousands of
+airports around the world. This seems to be derived from
+the <a href="http://www.iata.org/sked/publications/">Standard
+Schedules Information Manual (SSIM)</a> of the
+the <a href="http://www.iata.org/">International Air Transport
+Association</a>,
+which gives current time zone rules for
+all the airports served by commercial aviation.</li>
+</ul>
+<h2>Maps</h2>
+<ul>
+<li>The <a href="http://www.odci.gov/">United States Central
+Intelligence Agency (CIA)</a> publishes a <a
+href="http://www.odci.gov/cia/publications/factbook/reference_maps/pdf/time_zones.pdf">time
+zone map</a>; the
+<a
+href="http://www.lib.utexas.edu/maps/world.html">Perry-Castañeda
+Library Map Collection</a>
+of the University of Texas at Austin has copies of
+recent editions.
+The pictorial quality is good,
+but the maps do not indicate summer time,
+and parts of the data are a few years out of date.</li>
+<li><a href="http://worldtimezone.com/">World timezones map with
+current time</a>
+has several fancy time zone maps; it covers Russia particularly well.
+The maps' pictorial quality is not quite as good as the CIA's
+but the maps are more up to date.</li>
+</ul>
+<h2>Time zone boundaries</h2>
+<ul>
+<li><a href="http://home-4.tiscali.nl/~t876506/Multizones.html">Time
+zone boundaries for multizone countries</a> summarizes legal
+boundaries between time zones within countries.</li>
+<li>Manifold.net's <a
+href="http://www.manifold.net/download/freemaps.html">Free Maps and
+GIS Data</a> includes a Manifold-format map of world time zone
+boundaries distributed under the GPL. The GeoCommunity's <a
+href="http://software.geocomm.com/data/intl_timezones.html">International
+Time Zones</a> publishes the same data in other formats.</li>
+<li>The US Geological Survey's National Atlas of the United States
+publishes the <a href="http://www.nationalatlas.gov/timeznm.html">Time
+Zones of the United States</a> in the public domain.</li>
+<li>The GeoCommunity lists several commercial sources for <a
+href="http://spatialnews.geocomm.com/features/timezones/">International
+Time Zones and Time Zone Data</a>.</li>
+</ul>
+<h2>Civil time concepts and history</h2>
+<ul>
+<li><a href="http://physics.nist.gov/time">A Walk through Time</a>
+surveys the evolution of timekeeping.</li>
+<li><a href="http://webexhibits.org/daylightsaving/">About Daylight
+Saving Time - History, rationale, laws and dates</a>
+is an overall history of DST.</li>
+<li><a href="http://toi.iriti.cnr.it/">The
+Time of Internet</a>
+describes time zones and daylight saving time,
+with diagrams.
+The time zone map is out of date, however.</li>
+<li><a href="http://www.phys.uu.nl/~vgent/idl/idl.htm">A History of
+the International Date Line</a> tells the story of the most important
+time zone boundary.</li>
+<li><a href="http://www.statoids.com/tconcept.html">Basic Time
+Zone Concepts</a> discusses terminological issues behind time zones.</li>
+</ul>
+<h2>National histories of legal time</h2>
+<dl>
+<dt>Australia</dt>
+<dd>The Community Relations Division of the New South Wales (NSW)
+Attorney General's Department maintains a <a
+href="http://www.lawlink.nsw.gov.au/crd.nsf/pages/time2">history of
+daylight saving in NSW</a>.</dd>
+<dt>Austria</dt>
+<dd>The Federal Office of Metrology and Surveying publishes a
+table of <a href="http://www.metrologie.at/pdf/sommerzeit.pdf"
+hreflang="de">daylight saving time in Austria (in German)</a>.</dd>
+<dt>Belgium</dt>
+<dd>The Royal Observatory of Belgium maintains a table of <a
+href="http://www.astro.oma.be/GENERAL/INFO/nli001a.html"
+hreflang="nl">time in Belgium (in Dutch)</a>.</dd>
+<dt>Brazil</dt>
+<dd>The Time Service Department of the National Observatory
+records <a href="http://pcdsh01.on.br/DecHV.html"
+hreflang="pt-BR">Brazil's daylight saving time decrees (in
+Portuguese)</a>.</dd>
+<dt>Canada</dt>
+<dd>The Institute for National Measurement Standards publishes current
+and some older information about <a
+href="http://inms-ienm.nrc-cnrc.gc.ca/time_services/daylight_savings_e.html">Time
+Zones and Daylight Saving Time</a>.</dd>
+<dt>Chile</dt>
+<dd>WebExhibits publishes a <a
+href="http://webexhibits.org/daylightsaving/chile.html"
+hreflang="es">history of official time (in Spanish)</a> originally
+written by the Chilean Hydrographic and Oceanographic Service.</dd>
+<dt>Germany</dt>
+<dd>The National Institute for Science and Technology maintains the <a
+href="http://www.ptb.de/en/org/4/44/441/dars_e.htm">Realisation of
+Legal Time in Germany</a>.</dd>
+<dt>Israel</dt>
+<dd>The Interior Ministry periodically issues <a
+href="ftp://ftp.cs.huji.ac.il/pub/tz/announcements/"
+hreflang="he">announcements (in Hebrew)</a>.</dd>
+<dt>Mexico</dt>
+<dd>The Investigation and Analysis Service of the Mexican Library of
+Congress has published a <a
+href="http://www.cddhcu.gob.mx/bibliot/publica/inveyana/polisoc/horver/"
+hreflang="es">history of Mexican local time (in Spanish)</a>.</dd>
+<dt>Malaysia</dt>
+<dd>See Singapore below.</dd>
+<dt>Netherlands</dt>
+<dd><a href="http://www.phys.uu.nl/~vgent/wettijd/wettijd.htm"
+hreflang="nl">Legal time in the Netherlands (in Dutch)</a>
+covers the history of local time in the Netherlands from ancient times.</dd>
+<dt>New Zealand</dt>
+<dd>The Department of Internal Affairs maintains a brief history <a
+href="http://www.dia.govt.nz/diawebsite.nsf/wpg_URL/Resource-material-Information-We-Provide-About-Daylight-Saving">about
+daylight saving</a>. The privately-maintained <a
+href="http://www.astrologyhouse.co.nz/timechanges.htm">Time Changes in
+New Zealand</a> has more details.</dd>
+<dt>Singapore</dt>
+<dd><a
+href="http://www.math.nus.edu.sg/aslaksen/teaching/timezone.html">Why
+is Singapore in the "Wrong" Time Zone?</a> details the
+history of legal time in Singapore and Malaysia.</dd>
+<dt>United Kingdom</dt>
+<dd><a
+href="http://www.srcf.ucam.org/~jsm28/british-time/">History of
+legal time in Britain</a> discusses in detail the country
+with perhaps the best-documented history of clock adjustments.
+The National Physical Laboratory also maintains an <a
+href="http://www.npl.co.uk/time/summer_time_archive.html">archive
+of summer time dates</a>.</dd>
+</dl>
+<h2>Precision timekeeping</h2>
+<ul>
+<li><a
+href="http://literature.agilent.com/litwebbin/purl.cgi?org_id=tmo&pub_id=5965-7984E">The
+Science of Timekeeping</a> is a thorough introduction
+to the theory and practice of precision timekeeping.</li>
+<li><a href="http://www.ntp.org/">NTP: The Network Time Protocol</a>
+discusses how to synchronize clocks of
+Internet hosts.</li>
+<li><a href="http://gauss.gge.unb.ca/GMT.UT.and.the.RGO.txt"
+charset="macintosh">A
+Few Facts Concerning GMT, UT, and the RGO</a>
+answers questions like "What is the difference between GMT and UTC?"</li>
+<li><a
+href="http://www.gb.nrao.edu/~rfisher/Ephemerides/times.html">Astronomical
+Times</a> explains more abstruse astronomical time scales like TT, TCG,
+and TDB.</li>
+<li>The <a href="http://www.iau.org/">IAU</a>'s <a
+href="http://www.iau-sofa.rl.ac.uk/">Standards Of Fundamental
+Astronomy</a> (SOFA) initiative publishes Fortran code for converting
+among time scales like TAI, TDB, TT and UTC.</li>
+<li><a href="http://www.jpl.nasa.gov/basics/bsf2-3.htm">Basics of
+Space Flight - Reference Systems - Time Conventions</a>
+briefly explains interplanetary space flight timekeeping.</li>
+<li><a
+href="http://www.giss.nasa.gov/tools/mars24/help/notes.html">Technical
+Notes on Mars Solar Time as Adopted by the Mars24 Sunclock</a> briefly
+describes Mars Coordinated Time (MTC) and the diverse local time
+scales used by each landed mission on Mars.</li>
+<li><a
+href="http://hpiers.obspm.fr/eop-pc/products/bulletins/bulletins.html">Bulletins
+maintained by the IERS EOP (PC)</a> contains official publications of
+the Earth Orientation Parameters Product Center of the
+International Earth Rotation Service, the committee that decides
+when leap seconds occur.</li>
+<li>The <a
+href="http://www.mail-archive.com/leapsecs@rom.usno.navy.mil/">Leap
+Second Discussion List</a> covers McCarthy and Klepczynski's proposal
+to discontinue leap seconds, published in <a
+href="http://www.gpsworld.com/">GPS World</a> <strong>10</strong>, 11
+(1999-11), 50–57 and discussed further in R. A. Nelson et al.,
+<a href="http://www.cl.cam.ac.uk/~mgk25/time/metrologia-leapsecond.pdf">The
+leap second: its history and possible future</a>,
+<a href="http://www.bipm.fr/metrologia/metrologia.html">Metrologia</a>
+<strong>38</strong> (2001), 509–529.
+<a href="http://www.ucolick.org/~sla/leapsecs/onlinebib.html">The
+Future of Leap Seconds</a> catalogs information about this
+contentious issue.</li>
+</ul>
+<h2>Time notation</h2>
+<ul>
+<li>
+<a href="http://www.cl.cam.ac.uk/~mgk25/iso-time.html">A Summary of
+the International Standard Date and Time Notation</a> is a good
+summary of ISO
+8601:1988 - Data elements and interchange formats - Information interchange
+- Representation of dates and times (which has been superseded by
+<a href="http://www.iso.org/iso/en/CatalogueDetailPage.CatalogueDetail?CSNUMBER=26780">ISO 8601:2000</a>).</li>
+<li>
+Section 3.3 of <a
+href="ftp://ftp.rfc-editor.org/in-notes/rfc2822.txt">Internet RFC 2822</a>
+specifies the time notation used in email and <a
+href="ftp://ftp.rfc-editor.org/in-notes/rfc2616.txt">HTTP</a> headers.</li>
+<li>
+<a href="ftp://ftp.rfc-editor.org/in-notes/rfc3339.txt">Internet RFC
+3339</a> specifies an ISO 8601 profile for use in new Internet
+protocols.</li>
+<li>
+<a href="http://www.exit109.com/~ghealton/y2k/yrexamples.html">The
+Best of Dates, the Worst of Dates</a> covers many problems encountered
+by software developers when handling dates and time stamps.</li>
+<li>
+Alphabetic time zone abbreviations should not be used as unique
+identifiers for UTC offsets as they are ambiguous in practice. For
+example, "EST" denotes 5 hours behind UTC in English-speaking North
+America, but it denotes 10 or 11 hours ahead of UTC in Australia;
+and French-speaking North Americans prefer "HNE" to "EST". For
+compatibility with <a href="http://www.pasc.org/#POSIX">POSIX</a> the
+<code>tz</code> database contains English abbreviations for all time
+stamps but in many cases these are merely inventions of the database
+maintainers.</li>
+</ul>
+<h2>Related indexes</h2>
+<ul>
+<li><a href="tz-art.htm">Time and the Arts</a></li>
+<li><a href="http://dmoz.org/Reference/Time/">Open Directory -
+Reference: Time</a></li>
+<li><a href="http://directory.google.com/Top/Reference/Time/">Google Directory - Reference > Time</a></li>
+<li><a href="http://dir.yahoo.com/Science/Measurements_and_Units/Time/">Yahoo! Science > Measurements and Units > Time</a></li>
+</ul>
+</body>
+</html>
--- /dev/null
+.\" $FreeBSD: src/usr.sbin/zic/zic.8,v 1.19 2005/02/13 23:45:54 ru Exp $
+.Dd June 20, 2004
+.Dt ZIC 8
+.Os
+.Sh NAME
+.Nm zic
+.Nd timezone compiler
+.Sh SYNOPSIS
+.Nm
+.Op Fl -version
+.Op Fl Dsv
+.Op Fl d Ar directory
+.Op Fl g Ar group
+.Op Fl L Ar leapsecondfilename
+.Op Fl l Ar localtime
+.Op Fl m Ar mode
+.Op Fl p Ar posixrules
+.Op Fl u Ar user
+.Op Fl y Ar command
+.Op Ar filename ...
+.Sh DESCRIPTION
+The
+.Nm
+utility reads text from the file(s) named on the command line
+and creates the time conversion information files specified in this input.
+If a
+.Ar filename
+is
+.Em - ,
+the standard input is read.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl -version
+Output version information and exit.
+.It Fl D
+Do not automatically create directories.
+If the input file(s) specify
+an output file in a directory which does not already exist, the
+default behavior is to attempt to create the directory.
+If
+.Fl D
+is specified,
+.Nm
+will instead error out immediately.
+.It Fl d Ar directory
+Create time conversion information files in the named directory rather than
+in the standard directory named below.
+.It Fl g Ar group
+After creating each output file, change its group ownership to the
+specified
+.Ar group
+(which can be either a name or a numeric group ID).
+.It Fl L Ar leapsecondfilename
+Read leap second information from the file with the given name.
+If this option is not used,
+no leap second information appears in output files.
+.It Fl l Ar timezone
+Use the given
+.Ar time zone
+as local time.
+The
+.Nm
+utility will act as if the input contained a link line of the form
+.Pp
+.D1 No "Link timezone localtime"
+.Pp
+(Note that this action has no effect on
+.Fx ,
+since the local time zone is specified in
+.Pa /etc/localtime
+and not
+.Pa /usr/share/zoneinfo/localtime . )
+.It Fl m Ar mode
+After creating each output file, change its access mode to
+.Ar mode .
+Both numeric and alphabetic modes are accepted
+(see
+.Xr chmod 1 ) .
+.It Fl p Ar timezone
+Use the given
+.Ar "time zone" Ns 's
+rules when handling POSIX-format
+time zone environment variables.
+The
+.Nm
+utility will act as if the input contained a link line of the form
+.Pp
+.D1 No "Link timezone posixrules"
+.It Fl u Ar user
+After creating each output file, change its owner to
+.Ar user
+(which can be either a name or a numeric user ID).
+.It Fl v
+Complain if a year that appears in a data file is outside the range
+of years representable by
+.Xr time 3
+values.
+.It Fl s
+Limit time values stored in output files to values that are the same
+whether they are taken to be signed or unsigned.
+You can use this option to generate SVVS-compatible files.
+.It Fl y Ar command
+Use the given
+.Ar command
+rather than
+.Em yearistype
+when checking year types (see below).
+.El
+.Pp
+Input lines are made up of fields.
+Fields are separated from one another by any number of white space characters.
+Leading and trailing white space on input lines is ignored.
+An unquoted sharp character (#) in the input introduces a comment which extends
+to the end of the line the sharp character appears on.
+White space characters and sharp characters may be enclosed in double quotes
+(") if they are to be used as part of a field.
+Any line that is blank (after comment stripping) is ignored.
+Non-blank lines are expected to be of one of three types:
+rule lines, zone lines, and link lines.
+.Pp
+A rule line has the form:
+.Dl "Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
+For example:
+.Dl "Rule US 1967 1973 \- Apr lastSun 2:00 1:00 D
+.Pp
+The fields that make up a rule line are:
+.Bl -tag -width "LETTER/S" -offset indent
+.It NAME
+Give the (arbitrary) name of the set of rules this rule is part of.
+.It FROM
+Give the first year in which the rule applies.
+Any integer year can be supplied; the Gregorian calendar is assumed.
+The word
+.Em minimum
+(or an abbreviation) means the minimum year representable as an integer.
+The word
+.Em maximum
+(or an abbreviation) means the maximum year representable as an integer.
+Rules can describe times that are not representable as time values,
+with the unrepresentable times ignored; this allows rules to be portable
+among hosts with differing time value types.
+.It TO
+Give the final year in which the rule applies.
+In addition to
+.Em minimum
+and
+.Em maximum
+(as above),
+the word
+.Em only
+(or an abbreviation)
+may be used to repeat the value of the
+.Em FROM
+field.
+.It TYPE
+Give the type of year in which the rule applies.
+If
+.Em TYPE
+is
+.Em \-
+then the rule applies in all years between
+.Em FROM
+and
+.Em TO
+inclusive.
+If
+.Em TYPE
+is something else, then
+.Nm
+executes the command
+.Li yearistype Ar year Ar type
+to check the type of a year:
+an exit status of zero is taken to mean that the year is of the given type;
+an exit status of one is taken to mean that the year is not of the given type.
+.It IN
+Name the month in which the rule takes effect.
+Month names may be abbreviated.
+.It ON
+Give the day on which the rule takes effect.
+Recognized forms include:
+.Pp
+.Bl -tag -width lastSun -compact -offset indent
+.It \&5
+the fifth of the month
+.It lastSun
+the last Sunday in the month
+.It lastMon
+the last Monday in the month
+.It Sun>=8
+first Sunday on or after the eighth
+.It Sun<=25
+last Sunday on or before the 25th
+.El
+.Pp
+Names of days of the week may be abbreviated or spelled out in full.
+Note that there must be no spaces within the
+.Em ON
+field.
+.It AT
+Give the time of day at which the rule takes effect.
+Recognized forms include:
+.Pp
+.Bl -tag -width "\&1:28:14" -offset indent -compact
+.It 2
+time in hours
+.It 2:00
+time in hours and minutes
+.It 15:00
+24-hour format time (for times after noon)
+.It 1:28:14
+time in hours, minutes, and seconds
+.El
+.Pp
+where hour 0 is midnight at the start of the day,
+and hour 24 is midnight at the end of the day.
+Any of these forms may be followed by the letter
+.Sq Li w
+if the given time is local
+.Dq "wall clock"
+time,
+.Sq Li s
+if the given time is local
+.Dq standard
+time, or
+.Sq Li u
+(or
+.Sq Li g
+or
+.Sq Li z )
+if the given time is universal time;
+in the absence of an indicator,
+wall clock time is assumed.
+.It SAVE
+Give the amount of time to be added to local standard time when the rule is in
+effect.
+This field has the same format as the
+.Em AT
+field
+(although, of course, the
+.Sq Li w
+and
+.Sq Li s
+suffixes are not used).
+.It LETTER/S
+Give the
+.Dq "variable part"
+(for example, the
+.Dq S
+or
+.Dq D
+in
+.Dq EST
+or
+.Dq EDT )
+of time zone abbreviations to be used when this rule is in effect.
+If this field is
+.Em \- ,
+the variable part is null.
+.El
+.Pp
+A zone line has the form:
+.Dl "Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL]
+For example:
+.Dl "Zone Australia/Adelaide 9:30 Aus CST 1971 Oct 31 2:00
+The fields that make up a zone line are:
+.Bl -tag -width indent
+.It NAME
+The name of the time zone.
+This is the name used in creating the time conversion information file for the
+zone.
+.It GMTOFF
+The amount of time to add to UTC to get standard time in this zone.
+This field has the same format as the
+.Em AT
+and
+.Em SAVE
+fields of rule lines;
+begin the field with a minus sign if time must be subtracted from UTC.
+.It RULES/SAVE
+The name of the rule(s) that apply in the time zone or,
+alternately, an amount of time to add to local standard time.
+If this field is
+.Em \-
+then standard time always applies in the time zone.
+.It FORMAT
+The format for time zone abbreviations in this time zone.
+The pair of characters
+.Em %s
+is used to show where the
+.Dq "variable part"
+of the time zone abbreviation goes.
+Alternately,
+a slash (/)
+separates standard and daylight abbreviations.
+.It UNTIL
+The time at which the UTC offset or the rule(s) change for a location.
+It is specified as a year, a month, a day, and a time of day.
+If this is specified,
+the time zone information is generated from the given UTC offset
+and rule change until the time specified.
+The month, day, and time of day have the same format as the IN, ON, and AT
+columns of a rule; trailing columns can be omitted, and default to the
+earliest possible value for the missing columns.
+.Pp
+The next line must be a
+.Dq continuation
+line; this has the same form as a zone line except that the
+string
+.Dq Zone
+and the name are omitted, as the continuation line will
+place information starting at the time specified as the
+.Em UNTIL
+field in the previous line in the file used by the previous line.
+Continuation lines may contain an
+.Em UNTIL
+field, just as zone lines do, indicating that the next line is a further
+continuation.
+.El
+.Pp
+A link line has the form
+.Dl "Link LINK-FROM LINK-TO
+For example:
+.Dl "Link Europe/Istanbul Asia/Istanbul
+The
+.Em LINK-FROM
+field should appear as the
+.Em NAME
+field in some zone line;
+the
+.Em LINK-TO
+field is used as an alternate name for that zone.
+.Pp
+Except for continuation lines,
+lines may appear in any order in the input.
+.Pp
+Lines in the file that describes leap seconds have the following form:
+.Dl "Leap YEAR MONTH DAY HH:MM:SS CORR R/S
+For example:
+.Dl "Leap 1974 Dec 31 23:59:60 + S
+The
+.Em YEAR ,
+.Em MONTH ,
+.Em DAY ,
+and
+.Em HH:MM:SS
+fields tell when the leap second happened.
+The
+.Em CORR
+field
+should be
+.Dq +
+if a second was added
+or
+.Dq -
+if a second was skipped.
+.\" There's no need to document the following, since it's impossible for more
+.\" than one leap second to be inserted or deleted at a time.
+.\" The C Standard is in error in suggesting the possibility.
+.\" See Terry J Quinn, The BIPM and the accurate measure of time,
+.\" Proc IEEE 79, 7 (July 1991), 894-905.
+.\" or
+.\" .q ++
+.\" if two seconds were added
+.\" or
+.\" .q --
+.\" if two seconds were skipped.
+The
+.Em R/S
+field
+should be (an abbreviation of)
+.Dq Stationary
+if the leap second time given by the other fields should be interpreted as UTC
+or
+(an abbreviation of)
+.Dq Rolling
+if the leap second time given by the other fields should be interpreted as
+local wall clock time.
+.Sh NOTE
+For areas with more than two types of local time,
+you may need to use local standard time in the
+.Em AT
+field of the earliest transition time's rule to ensure that
+the earliest transition time recorded in the compiled file is correct.
+.Sh FILES
+.Bl -tag -width /usr/share/zoneinfo -compact
+.It /usr/share/zoneinfo
+standard directory used for created files
+.El
+.Sh "SEE ALSO"
+.Xr ctime 3 ,
+.Xr tzfile 5 ,
+.Xr zdump 8
+.\" @(#)zic.8 7.18
--- /dev/null
+static const char elsieid[] = "@(#)zic.c 7.116";
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: src/usr.sbin/zic/zic.c,v 1.18 2007/12/03 10:45:44 kevlo Exp $";
+#endif /* not lint */
+
+#include "private.h"
+#include "tzfile.h"
+#include <err.h>
+#include <locale.h>
+#include <sys/stat.h> /* for umask manifest constants */
+#include <sys/types.h>
+#include <unistd.h>
+
+#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
+
+/*
+** On some ancient hosts, predicates like `isspace(C)' are defined
+** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
+** which says they are defined only if C == ((unsigned char) C) || C == EOF.
+** Neither the C Standard nor POSIX require that `isascii' exist.
+** For portability, we check both ancient and modern requirements.
+** If isascii is not defined, the isascii check succeeds trivially.
+*/
+#include "ctype.h"
+#ifndef isascii
+#define isascii(x) 1
+#endif
+
+struct rule {
+ const char * r_filename;
+ int r_linenum;
+ const char * r_name;
+
+ int r_loyear; /* for example, 1986 */
+ int r_hiyear; /* for example, 1986 */
+ const char * r_yrtype;
+
+ int r_month; /* 0..11 */
+
+ int r_dycode; /* see below */
+ int r_dayofmonth;
+ int r_wday;
+
+ long r_tod; /* time from midnight */
+ int r_todisstd; /* above is standard time if TRUE */
+ /* or wall clock time if FALSE */
+ int r_todisgmt; /* above is GMT if TRUE */
+ /* or local time if FALSE */
+ long r_stdoff; /* offset from standard time */
+ const char * r_abbrvar; /* variable part of abbreviation */
+
+ int r_todo; /* a rule to do (used in outzone) */
+ time_t r_temp; /* used in outzone */
+};
+
+/*
+** r_dycode r_dayofmonth r_wday
+*/
+
+#define DC_DOM 0 /* 1..31 */ /* unused */
+#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
+#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
+
+struct zone {
+ const char * z_filename;
+ int z_linenum;
+
+ const char * z_name;
+ long z_gmtoff;
+ const char * z_rule;
+ const char * z_format;
+
+ long z_stdoff;
+
+ struct rule * z_rules;
+ int z_nrules;
+
+ struct rule z_untilrule;
+ time_t z_untiltime;
+};
+
+static void addtt P((time_t starttime, int type));
+static int addtype P((long gmtoff, const char * abbr, int isdst,
+ int ttisstd, int ttisgmt));
+static void leapadd P((time_t t, int positive, int rolling, int count));
+static void adjleap P((void));
+static void associate P((void));
+static int ciequal P((const char * ap, const char * bp));
+static void convert P((long val, char * buf));
+static void dolink P((const char * fromfile, const char * tofile));
+static void doabbr P((char * abbr, const char * format,
+ const char * letters, int isdst));
+static void eat P((const char * name, int num));
+static void eats P((const char * name, int num,
+ const char * rname, int rnum));
+static long eitol P((int i));
+static void error P((const char * message));
+static char ** getfields P((char * buf));
+static long gethms P((const char * string, const char * errstrng,
+ int signable));
+static void infile P((const char * filename));
+static void inleap P((char ** fields, int nfields));
+static void inlink P((char ** fields, int nfields));
+static void inrule P((char ** fields, int nfields));
+static int inzcont P((char ** fields, int nfields));
+static int inzone P((char ** fields, int nfields));
+static int inzsub P((char ** fields, int nfields, int iscont));
+static int itsabbr P((const char * abbr, const char * word));
+static int itsdir P((const char * name));
+static int lowerit P((int c));
+static char * memcheck P((char * tocheck));
+static int mkdirs P((char * filename));
+static void newabbr P((const char * abbr));
+static long oadd P((long t1, long t2));
+static void outzone P((const struct zone * zp, int ntzones));
+static void puttzcode P((long code, FILE * fp));
+static int rcomp P((const void * leftp, const void * rightp));
+static time_t rpytime P((const struct rule * rp, int wantedy));
+static void rulesub P((struct rule * rp,
+ const char * loyearp, const char * hiyearp,
+ const char * typep, const char * monthp,
+ const char * dayp, const char * timep));
+static void setboundaries P((void));
+static void setgroup P((gid_t *flag, const char *name));
+static void setuser P((uid_t *flag, const char *name));
+static time_t tadd P((time_t t1, long t2));
+static void usage P((void));
+static void writezone P((const char * name));
+static int yearistype P((int year, const char * type));
+
+#if !(HAVE_STRERROR - 0)
+static char * strerror P((int));
+#endif /* !(HAVE_STRERROR - 0) */
+
+static int charcnt;
+static int errors;
+static const char * filename;
+static int leapcnt;
+static int linenum;
+static time_t max_time;
+static int max_year;
+static int max_year_representable;
+static time_t min_time;
+static int min_year;
+static int min_year_representable;
+static int noise;
+static const char * rfilename;
+static int rlinenum;
+static int timecnt;
+static int typecnt;
+
+/*
+** Line codes.
+*/
+
+#define LC_RULE 0
+#define LC_ZONE 1
+#define LC_LINK 2
+#define LC_LEAP 3
+
+/*
+** Which fields are which on a Zone line.
+*/
+
+#define ZF_NAME 1
+#define ZF_GMTOFF 2
+#define ZF_RULE 3
+#define ZF_FORMAT 4
+#define ZF_TILYEAR 5
+#define ZF_TILMONTH 6
+#define ZF_TILDAY 7
+#define ZF_TILTIME 8
+#define ZONE_MINFIELDS 5
+#define ZONE_MAXFIELDS 9
+
+/*
+** Which fields are which on a Zone continuation line.
+*/
+
+#define ZFC_GMTOFF 0
+#define ZFC_RULE 1
+#define ZFC_FORMAT 2
+#define ZFC_TILYEAR 3
+#define ZFC_TILMONTH 4
+#define ZFC_TILDAY 5
+#define ZFC_TILTIME 6
+#define ZONEC_MINFIELDS 3
+#define ZONEC_MAXFIELDS 7
+
+/*
+** Which files are which on a Rule line.
+*/
+
+#define RF_NAME 1
+#define RF_LOYEAR 2
+#define RF_HIYEAR 3
+#define RF_COMMAND 4
+#define RF_MONTH 5
+#define RF_DAY 6
+#define RF_TOD 7
+#define RF_STDOFF 8
+#define RF_ABBRVAR 9
+#define RULE_FIELDS 10
+
+/*
+** Which fields are which on a Link line.
+*/
+
+#define LF_FROM 1
+#define LF_TO 2
+#define LINK_FIELDS 3
+
+/*
+** Which fields are which on a Leap line.
+*/
+
+#define LP_YEAR 1
+#define LP_MONTH 2
+#define LP_DAY 3
+#define LP_TIME 4
+#define LP_CORR 5
+#define LP_ROLL 6
+#define LEAP_FIELDS 7
+
+/*
+** Year synonyms.
+*/
+
+#define YR_MINIMUM 0
+#define YR_MAXIMUM 1
+#define YR_ONLY 2
+
+static struct rule * rules;
+static int nrules; /* number of rules */
+
+static struct zone * zones;
+static int nzones; /* number of zones */
+
+struct link {
+ const char * l_filename;
+ int l_linenum;
+ const char * l_from;
+ const char * l_to;
+};
+
+static struct link * links;
+static int nlinks;
+
+struct lookup {
+ const char * l_word;
+ const int l_value;
+};
+
+static struct lookup const * byword P((const char * string,
+ const struct lookup * lp));
+
+static struct lookup const line_codes[] = {
+ { "Rule", LC_RULE },
+ { "Zone", LC_ZONE },
+ { "Link", LC_LINK },
+ { "Leap", LC_LEAP },
+ { NULL, 0}
+};
+
+static struct lookup const mon_names[] = {
+ { "January", TM_JANUARY },
+ { "February", TM_FEBRUARY },
+ { "March", TM_MARCH },
+ { "April", TM_APRIL },
+ { "May", TM_MAY },
+ { "June", TM_JUNE },
+ { "July", TM_JULY },
+ { "August", TM_AUGUST },
+ { "September", TM_SEPTEMBER },
+ { "October", TM_OCTOBER },
+ { "November", TM_NOVEMBER },
+ { "December", TM_DECEMBER },
+ { NULL, 0 }
+};
+
+static struct lookup const wday_names[] = {
+ { "Sunday", TM_SUNDAY },
+ { "Monday", TM_MONDAY },
+ { "Tuesday", TM_TUESDAY },
+ { "Wednesday", TM_WEDNESDAY },
+ { "Thursday", TM_THURSDAY },
+ { "Friday", TM_FRIDAY },
+ { "Saturday", TM_SATURDAY },
+ { NULL, 0 }
+};
+
+static struct lookup const lasts[] = {
+ { "last-Sunday", TM_SUNDAY },
+ { "last-Monday", TM_MONDAY },
+ { "last-Tuesday", TM_TUESDAY },
+ { "last-Wednesday", TM_WEDNESDAY },
+ { "last-Thursday", TM_THURSDAY },
+ { "last-Friday", TM_FRIDAY },
+ { "last-Saturday", TM_SATURDAY },
+ { NULL, 0 }
+};
+
+static struct lookup const begin_years[] = {
+ { "minimum", YR_MINIMUM },
+ { "maximum", YR_MAXIMUM },
+ { NULL, 0 }
+};
+
+static struct lookup const end_years[] = {
+ { "minimum", YR_MINIMUM },
+ { "maximum", YR_MAXIMUM },
+ { "only", YR_ONLY },
+ { NULL, 0 }
+};
+
+static struct lookup const leap_types[] = {
+ { "Rolling", TRUE },
+ { "Stationary", FALSE },
+ { NULL, 0 }
+};
+
+static const int len_months[2][MONSPERYEAR] = {
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+static const int len_years[2] = {
+ DAYSPERNYEAR, DAYSPERLYEAR
+};
+
+static struct attype {
+ time_t at;
+ unsigned char type;
+} attypes[TZ_MAX_TIMES];
+static long gmtoffs[TZ_MAX_TYPES];
+static char isdsts[TZ_MAX_TYPES];
+static unsigned char abbrinds[TZ_MAX_TYPES];
+static char ttisstds[TZ_MAX_TYPES];
+static char ttisgmts[TZ_MAX_TYPES];
+static char chars[TZ_MAX_CHARS];
+static time_t trans[TZ_MAX_LEAPS];
+static long corr[TZ_MAX_LEAPS];
+static char roll[TZ_MAX_LEAPS];
+
+/*
+** Memory allocation.
+*/
+
+static char *
+memcheck(ptr)
+char * const ptr;
+{
+ if (ptr == NULL)
+ errx(EXIT_FAILURE, _("memory exhausted"));
+ return ptr;
+}
+
+#define emalloc(size) memcheck(imalloc(size))
+#define erealloc(ptr, size) memcheck(irealloc((ptr), (size)))
+#define ecpyalloc(ptr) memcheck(icpyalloc(ptr))
+#define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp)))
+
+/*
+** Error handling.
+*/
+
+#if !(HAVE_STRERROR - 0)
+static char *
+strerror(errnum)
+int errnum;
+{
+ extern char * sys_errlist[];
+ extern int sys_nerr;
+
+ return (errnum > 0 && errnum <= sys_nerr) ?
+ sys_errlist[errnum] : _("Unknown system error");
+}
+#endif /* !(HAVE_STRERROR - 0) */
+
+static void
+eats(name, num, rname, rnum)
+const char * const name;
+const int num;
+const char * const rname;
+const int rnum;
+{
+ filename = name;
+ linenum = num;
+ rfilename = rname;
+ rlinenum = rnum;
+}
+
+static void
+eat(name, num)
+const char * const name;
+const int num;
+{
+ eats(name, num, (char *) NULL, -1);
+}
+
+static void
+error(string)
+const char * const string;
+{
+ /*
+ ** Match the format of "cc" to allow sh users to
+ ** zic ... 2>&1 | error -t "*" -v
+ ** on BSD systems.
+ */
+ (void) fprintf(stderr, _("\"%s\", line %d: %s"),
+ filename, linenum, string);
+ if (rfilename != NULL)
+ (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),
+ rfilename, rlinenum);
+ (void) fprintf(stderr, "\n");
+ ++errors;
+}
+
+static void
+warning(string)
+const char * const string;
+{
+ char * cp;
+
+ cp = ecpyalloc(_("warning: "));
+ cp = ecatalloc(cp, string);
+ error(cp);
+ ifree(cp);
+ --errors;
+}
+
+static void
+usage P((void))
+{
+ (void) fprintf(stderr, "%s\n%s\n",
+_("usage: zic [--version] [-s] [-v] [-l localtime] [-p posixrules] [-d directory]"),
+_(" [-L leapseconds] [-y yearistype] [filename ... ]"));
+ (void) exit(EXIT_FAILURE);
+}
+
+static const char * psxrules;
+static const char * lcltime;
+static const char * directory;
+static const char * leapsec;
+static const char * yitcommand;
+static int sflag = FALSE;
+static int Dflag;
+static uid_t uflag = (uid_t)-1;
+static gid_t gflag = (gid_t)-1;
+static mode_t mflag = (S_IRUSR | S_IRGRP | S_IROTH
+ | S_IWUSR);
+
+int
+main(argc, argv)
+int argc;
+char * argv[];
+{
+ register int i;
+ register int j;
+ register int c;
+
+#ifdef unix
+ (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
+#endif /* defined unix */
+#if HAVE_GETTEXT - 0
+ (void) setlocale(LC_MESSAGES, "");
+#ifdef TZ_DOMAINDIR
+ (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
+#endif /* defined TEXTDOMAINDIR */
+ (void) textdomain(TZ_DOMAIN);
+#endif /* HAVE_GETTEXT - 0 */
+ for (i = 1; i < argc; ++i)
+ if (strcmp(argv[i], "--version") == 0) {
+ errx(EXIT_SUCCESS, "%s", elsieid);
+ }
+ while ((c = getopt(argc, argv, "Dd:g:l:m:p:L:u:vsy:")) != -1)
+ switch (c) {
+ default:
+ usage();
+ case 'D':
+ Dflag = 1;
+ break;
+ case 'd':
+ if (directory == NULL)
+ directory = optarg;
+ else
+ errx(EXIT_FAILURE,
+_("more than one -d option specified"));
+ break;
+ case 'g':
+ setgroup(&gflag, optarg);
+ break;
+ case 'l':
+ if (lcltime == NULL)
+ lcltime = optarg;
+ else
+ errx(EXIT_FAILURE,
+_("more than one -l option specified"));
+ break;
+ case 'm':
+ {
+ void *set = setmode(optarg);
+ if (set == NULL)
+ errx(EXIT_FAILURE,
+_("invalid file mode"));
+ mflag = getmode(set, mflag);
+ free(set);
+ break;
+ }
+ case 'p':
+ if (psxrules == NULL)
+ psxrules = optarg;
+ else
+ errx(EXIT_FAILURE,
+_("more than one -p option specified"));
+ break;
+ case 'u':
+ setuser(&uflag, optarg);
+ break;
+ case 'y':
+ if (yitcommand == NULL)
+ yitcommand = optarg;
+ else
+ errx(EXIT_FAILURE,
+_("more than one -y option specified"));
+ break;
+ case 'L':
+ if (leapsec == NULL)
+ leapsec = optarg;
+ else
+ errx(EXIT_FAILURE,
+_("more than one -L option specified"));
+ break;
+ case 'v':
+ noise = TRUE;
+ break;
+ case 's':
+ sflag = TRUE;
+ break;
+ }
+ if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
+ usage(); /* usage message by request */
+ if (directory == NULL)
+ directory = TZDIR;
+ if (yitcommand == NULL)
+ yitcommand = "yearistype";
+
+ setboundaries();
+
+ if (optind < argc && leapsec != NULL) {
+ infile(leapsec);
+ adjleap();
+ }
+
+ for (i = optind; i < argc; ++i)
+ infile(argv[i]);
+ if (errors)
+ (void) exit(EXIT_FAILURE);
+ associate();
+ for (i = 0; i < nzones; i = j) {
+ /*
+ ** Find the next non-continuation zone entry.
+ */
+ for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
+ continue;
+ outzone(&zones[i], j - i);
+ }
+ /*
+ ** Make links.
+ */
+ for (i = 0; i < nlinks; ++i) {
+ eat(links[i].l_filename, links[i].l_linenum);
+ dolink(links[i].l_from, links[i].l_to);
+ }
+ if (lcltime != NULL) {
+ eat("command line", 1);
+ dolink(lcltime, TZDEFAULT);
+ }
+ if (psxrules != NULL) {
+ eat("command line", 1);
+ dolink(psxrules, TZDEFRULES);
+ }
+ return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static void
+dolink(fromfile, tofile)
+const char * const fromfile;
+const char * const tofile;
+{
+ register char * fromname;
+ register char * toname;
+
+ if (fromfile[0] == '/')
+ fromname = ecpyalloc(fromfile);
+ else {
+ fromname = ecpyalloc(directory);
+ fromname = ecatalloc(fromname, "/");
+ fromname = ecatalloc(fromname, fromfile);
+ }
+ if (tofile[0] == '/')
+ toname = ecpyalloc(tofile);
+ else {
+ toname = ecpyalloc(directory);
+ toname = ecatalloc(toname, "/");
+ toname = ecatalloc(toname, tofile);
+ }
+ /*
+ ** We get to be careful here since
+ ** there's a fair chance of root running us.
+ */
+ if (!itsdir(toname))
+ (void) remove(toname);
+ if (link(fromname, toname) != 0) {
+ int result;
+
+ if (mkdirs(toname) != 0)
+ (void) exit(EXIT_FAILURE);
+
+ result = link(fromname, toname);
+#if (HAVE_SYMLINK - 0)
+ if (result != 0 &&
+ access(fromname, F_OK) == 0 &&
+ !itsdir(fromname)) {
+ const char *s = tofile;
+ register char * symlinkcontents = NULL;
+ while ((s = strchr(s+1, '/')) != NULL)
+ symlinkcontents = ecatalloc(symlinkcontents, "../");
+ symlinkcontents = ecatalloc(symlinkcontents, fromfile);
+
+ result = symlink(symlinkcontents, toname);
+ if (result == 0)
+warning(_("hard link failed, symbolic link used"));
+ ifree(symlinkcontents);
+ }
+#endif
+ if (result != 0) {
+ err(EXIT_FAILURE, _("can't link from %s to %s"),
+ fromname, toname);
+ }
+ }
+ ifree(fromname);
+ ifree(toname);
+}
+
+#ifndef INT_MAX
+#define INT_MAX ((int) (((unsigned)~0)>>1))
+#endif /* !defined INT_MAX */
+
+#ifndef INT_MIN
+#define INT_MIN ((int) ~(((unsigned)~0)>>1))
+#endif /* !defined INT_MIN */
+
+/*
+** The tz file format currently allows at most 32-bit quantities.
+** This restriction should be removed before signed 32-bit values
+** wrap around in 2038, but unfortunately this will require a
+** change to the tz file format.
+*/
+
+#define MAX_BITS_IN_FILE 32
+#define TIME_T_BITS_IN_FILE ((TYPE_BIT(time_t) < MAX_BITS_IN_FILE) ? TYPE_BIT(time_t) : MAX_BITS_IN_FILE)
+
+static void
+setboundaries P((void))
+{
+ if (TYPE_SIGNED(time_t)) {
+ min_time = ~ (time_t) 0;
+ min_time <<= TIME_T_BITS_IN_FILE - 1;
+ max_time = ~ (time_t) 0 - min_time;
+ if (sflag)
+ min_time = 0;
+ } else {
+ min_time = 0;
+ max_time = 2 - sflag;
+ max_time <<= TIME_T_BITS_IN_FILE - 1;
+ --max_time;
+ }
+ min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
+ max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
+ min_year_representable = min_year;
+ max_year_representable = max_year;
+}
+
+static int
+itsdir(name)
+const char * const name;
+{
+ register char * myname;
+ register int accres;
+
+ myname = ecpyalloc(name);
+ myname = ecatalloc(myname, "/.");
+ accres = access(myname, F_OK);
+ ifree(myname);
+ return accres == 0;
+}
+
+/*
+** Associate sets of rules with zones.
+*/
+
+/*
+** Sort by rule name.
+*/
+
+static int
+rcomp(cp1, cp2)
+const void * cp1;
+const void * cp2;
+{
+ return strcmp(((const struct rule *) cp1)->r_name,
+ ((const struct rule *) cp2)->r_name);
+}
+
+static void
+associate P((void))
+{
+ register struct zone * zp;
+ register struct rule * rp;
+ register int base, out;
+ register int i, j;
+
+ if (nrules != 0) {
+ (void) qsort((void *) rules, (size_t) nrules,
+ (size_t) sizeof *rules, rcomp);
+ for (i = 0; i < nrules - 1; ++i) {
+ if (strcmp(rules[i].r_name,
+ rules[i + 1].r_name) != 0)
+ continue;
+ if (strcmp(rules[i].r_filename,
+ rules[i + 1].r_filename) == 0)
+ continue;
+ eat(rules[i].r_filename, rules[i].r_linenum);
+ warning(_("same rule name in multiple files"));
+ eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
+ warning(_("same rule name in multiple files"));
+ for (j = i + 2; j < nrules; ++j) {
+ if (strcmp(rules[i].r_name,
+ rules[j].r_name) != 0)
+ break;
+ if (strcmp(rules[i].r_filename,
+ rules[j].r_filename) == 0)
+ continue;
+ if (strcmp(rules[i + 1].r_filename,
+ rules[j].r_filename) == 0)
+ continue;
+ break;
+ }
+ i = j - 1;
+ }
+ }
+ for (i = 0; i < nzones; ++i) {
+ zp = &zones[i];
+ zp->z_rules = NULL;
+ zp->z_nrules = 0;
+ }
+ for (base = 0; base < nrules; base = out) {
+ rp = &rules[base];
+ for (out = base + 1; out < nrules; ++out)
+ if (strcmp(rp->r_name, rules[out].r_name) != 0)
+ break;
+ for (i = 0; i < nzones; ++i) {
+ zp = &zones[i];
+ if (strcmp(zp->z_rule, rp->r_name) != 0)
+ continue;
+ zp->z_rules = rp;
+ zp->z_nrules = out - base;
+ }
+ }
+ for (i = 0; i < nzones; ++i) {
+ zp = &zones[i];
+ if (zp->z_nrules == 0) {
+ /*
+ ** Maybe we have a local standard time offset.
+ */
+ eat(zp->z_filename, zp->z_linenum);
+ zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
+ TRUE);
+ /*
+ ** Note, though, that if there's no rule,
+ ** a '%s' in the format is a bad thing.
+ */
+ if (strchr(zp->z_format, '%') != 0)
+ error(_("%s in ruleless zone"));
+ }
+ }
+ if (errors)
+ (void) exit(EXIT_FAILURE);
+}
+
+static void
+infile(name)
+const char * name;
+{
+ register FILE * fp;
+ register char ** fields;
+ register char * cp;
+ register const struct lookup * lp;
+ register int nfields;
+ register int wantcont;
+ register int num;
+ char buf[BUFSIZ];
+
+ if (strcmp(name, "-") == 0) {
+ name = _("standard input");
+ fp = stdin;
+ } else if ((fp = fopen(name, "r")) == NULL)
+ err(EXIT_FAILURE, _("can't open %s"), name);
+ wantcont = FALSE;
+ for (num = 1; ; ++num) {
+ eat(name, num);
+ if (fgets(buf, (int) sizeof buf, fp) != buf)
+ break;
+ cp = strchr(buf, '\n');
+ if (cp == NULL) {
+ error(_("line too long"));
+ (void) exit(EXIT_FAILURE);
+ }
+ *cp = '\0';
+ fields = getfields(buf);
+ nfields = 0;
+ while (fields[nfields] != NULL) {
+ static char nada;
+
+ if (strcmp(fields[nfields], "-") == 0)
+ fields[nfields] = &nada;
+ ++nfields;
+ }
+ if (nfields == 0) {
+ /* nothing to do */
+ } else if (wantcont) {
+ wantcont = inzcont(fields, nfields);
+ } else {
+ lp = byword(fields[0], line_codes);
+ if (lp == NULL)
+ error(_("input line of unknown type"));
+ else switch ((int) (lp->l_value)) {
+ case LC_RULE:
+ inrule(fields, nfields);
+ wantcont = FALSE;
+ break;
+ case LC_ZONE:
+ wantcont = inzone(fields, nfields);
+ break;
+ case LC_LINK:
+ inlink(fields, nfields);
+ wantcont = FALSE;
+ break;
+ case LC_LEAP:
+ if (name != leapsec)
+ warnx(
+_("leap line in non leap seconds file %s"), name);
+ else inleap(fields, nfields);
+ wantcont = FALSE;
+ break;
+ default: /* "cannot happen" */
+ errx(EXIT_FAILURE,
+_("panic: invalid l_value %d"), lp->l_value);
+ }
+ }
+ ifree((char *) fields);
+ }
+ if (ferror(fp))
+ errx(EXIT_FAILURE, _("error reading %s"), filename);
+ if (fp != stdin && fclose(fp))
+ err(EXIT_FAILURE, _("error closing %s"), filename);
+ if (wantcont)
+ error(_("expected continuation line not found"));
+}
+
+/*
+** Convert a string of one of the forms
+** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
+** into a number of seconds.
+** A null string maps to zero.
+** Call error with errstring and return zero on errors.
+*/
+
+static long
+gethms(string, errstring, signable)
+const char * string;
+const char * const errstring;
+const int signable;
+{
+ int hh, mm, ss, sign;
+
+ if (string == NULL || *string == '\0')
+ return 0;
+ if (!signable)
+ sign = 1;
+ else if (*string == '-') {
+ sign = -1;
+ ++string;
+ } else sign = 1;
+ if (sscanf(string, scheck(string, "%d"), &hh) == 1)
+ mm = ss = 0;
+ else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)
+ ss = 0;
+ else if (sscanf(string, scheck(string, "%d:%d:%d"),
+ &hh, &mm, &ss) != 3) {
+ error(errstring);
+ return 0;
+ }
+ if ((hh < 0 || hh >= HOURSPERDAY ||
+ mm < 0 || mm >= MINSPERHOUR ||
+ ss < 0 || ss > SECSPERMIN) &&
+ !(hh == HOURSPERDAY && mm == 0 && ss == 0)) {
+ error(errstring);
+ return 0;
+ }
+ if (noise && hh == HOURSPERDAY)
+ warning(_("24:00 not handled by pre-1998 versions of zic"));
+ return eitol(sign) *
+ (eitol(hh * MINSPERHOUR + mm) *
+ eitol(SECSPERMIN) + eitol(ss));
+}
+
+static void
+inrule(fields, nfields)
+register char ** const fields;
+const int nfields;
+{
+ static struct rule r;
+
+ if (nfields != RULE_FIELDS) {
+ error(_("wrong number of fields on Rule line"));
+ return;
+ }
+ if (*fields[RF_NAME] == '\0') {
+ error(_("nameless rule"));
+ return;
+ }
+ r.r_filename = filename;
+ r.r_linenum = linenum;
+ r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE);
+ rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
+ fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
+ r.r_name = ecpyalloc(fields[RF_NAME]);
+ r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
+ rules = (struct rule *) (void *) erealloc((char *) rules,
+ (int) ((nrules + 1) * sizeof *rules));
+ rules[nrules++] = r;
+}
+
+static int
+inzone(fields, nfields)
+register char ** const fields;
+const int nfields;
+{
+ register int i;
+ static char * buf;
+
+ if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
+ error(_("wrong number of fields on Zone line"));
+ return FALSE;
+ }
+ if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
+ buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT)));
+ (void) sprintf(buf,
+_("\"Zone %s\" line and -l option are mutually exclusive"),
+ TZDEFAULT);
+ error(buf);
+ return FALSE;
+ }
+ if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
+ buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES)));
+ (void) sprintf(buf,
+_("\"Zone %s\" line and -p option are mutually exclusive"),
+ TZDEFRULES);
+ error(buf);
+ return FALSE;
+ }
+ for (i = 0; i < nzones; ++i)
+ if (zones[i].z_name != NULL &&
+ strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
+ buf = erealloc(buf, (int) (132 +
+ strlen(fields[ZF_NAME]) +
+ strlen(zones[i].z_filename)));
+ (void) sprintf(buf,
+_("duplicate zone name %s (file \"%s\", line %d)"),
+ fields[ZF_NAME],
+ zones[i].z_filename,
+ zones[i].z_linenum);
+ error(buf);
+ return FALSE;
+ }
+ return inzsub(fields, nfields, FALSE);
+}
+
+static int
+inzcont(fields, nfields)
+register char ** const fields;
+const int nfields;
+{
+ if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
+ error(_("wrong number of fields on Zone continuation line"));
+ return FALSE;
+ }
+ return inzsub(fields, nfields, TRUE);
+}
+
+static int
+inzsub(fields, nfields, iscont)
+register char ** const fields;
+const int nfields;
+const int iscont;
+{
+ register char * cp;
+ static struct zone z;
+ register int i_gmtoff, i_rule, i_format;
+ register int i_untilyear, i_untilmonth;
+ register int i_untilday, i_untiltime;
+ register int hasuntil;
+
+ if (iscont) {
+ i_gmtoff = ZFC_GMTOFF;
+ i_rule = ZFC_RULE;
+ i_format = ZFC_FORMAT;
+ i_untilyear = ZFC_TILYEAR;
+ i_untilmonth = ZFC_TILMONTH;
+ i_untilday = ZFC_TILDAY;
+ i_untiltime = ZFC_TILTIME;
+ z.z_name = NULL;
+ } else {
+ i_gmtoff = ZF_GMTOFF;
+ i_rule = ZF_RULE;
+ i_format = ZF_FORMAT;
+ i_untilyear = ZF_TILYEAR;
+ i_untilmonth = ZF_TILMONTH;
+ i_untilday = ZF_TILDAY;
+ i_untiltime = ZF_TILTIME;
+ z.z_name = ecpyalloc(fields[ZF_NAME]);
+ }
+ z.z_filename = filename;
+ z.z_linenum = linenum;
+ z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);
+ if ((cp = strchr(fields[i_format], '%')) != 0) {
+ if (*++cp != 's' || strchr(cp, '%') != 0) {
+ error(_("invalid abbreviation format"));
+ return FALSE;
+ }
+ }
+ z.z_rule = ecpyalloc(fields[i_rule]);
+ z.z_format = ecpyalloc(fields[i_format]);
+ hasuntil = nfields > i_untilyear;
+ if (hasuntil) {
+ z.z_untilrule.r_filename = filename;
+ z.z_untilrule.r_linenum = linenum;
+ rulesub(&z.z_untilrule,
+ fields[i_untilyear],
+ "only",
+ "",
+ (nfields > i_untilmonth) ?
+ fields[i_untilmonth] : "Jan",
+ (nfields > i_untilday) ? fields[i_untilday] : "1",
+ (nfields > i_untiltime) ? fields[i_untiltime] : "0");
+ z.z_untiltime = rpytime(&z.z_untilrule,
+ z.z_untilrule.r_loyear);
+ if (iscont && nzones > 0 &&
+ z.z_untiltime > min_time &&
+ z.z_untiltime < max_time &&
+ zones[nzones - 1].z_untiltime > min_time &&
+ zones[nzones - 1].z_untiltime < max_time &&
+ zones[nzones - 1].z_untiltime >= z.z_untiltime) {
+ error(_("Zone continuation line end time is not after end time of previous line"));
+ return FALSE;
+ }
+ }
+ zones = (struct zone *) (void *) erealloc((char *) zones,
+ (int) ((nzones + 1) * sizeof *zones));
+ zones[nzones++] = z;
+ /*
+ ** If there was an UNTIL field on this line,
+ ** there's more information about the zone on the next line.
+ */
+ return hasuntil;
+}
+
+static void
+inleap(fields, nfields)
+register char ** const fields;
+const int nfields;
+{
+ register const char * cp;
+ register const struct lookup * lp;
+ register int i, j;
+ int year, month, day;
+ long dayoff, tod;
+ time_t t;
+
+ if (nfields != LEAP_FIELDS) {
+ error(_("wrong number of fields on Leap line"));
+ return;
+ }
+ dayoff = 0;
+ cp = fields[LP_YEAR];
+ if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
+ /*
+ * Leapin' Lizards!
+ */
+ error(_("invalid leaping year"));
+ return;
+ }
+ j = EPOCH_YEAR;
+ while (j != year) {
+ if (year > j) {
+ i = len_years[isleap(j)];
+ ++j;
+ } else {
+ --j;
+ i = -len_years[isleap(j)];
+ }
+ dayoff = oadd(dayoff, eitol(i));
+ }
+ if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
+ error(_("invalid month name"));
+ return;
+ }
+ month = lp->l_value;
+ j = TM_JANUARY;
+ while (j != month) {
+ i = len_months[isleap(year)][j];
+ dayoff = oadd(dayoff, eitol(i));
+ ++j;
+ }
+ cp = fields[LP_DAY];
+ if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
+ day <= 0 || day > len_months[isleap(year)][month]) {
+ error(_("invalid day of month"));
+ return;
+ }
+ dayoff = oadd(dayoff, eitol(day - 1));
+ if (dayoff < 0 && !TYPE_SIGNED(time_t)) {
+ error(_("time before zero"));
+ return;
+ }
+ if (dayoff < min_time / SECSPERDAY) {
+ error(_("time too small"));
+ return;
+ }
+ if (dayoff > max_time / SECSPERDAY) {
+ error(_("time too large"));
+ return;
+ }
+ t = (time_t) dayoff * SECSPERDAY;
+ tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
+ cp = fields[LP_CORR];
+ {
+ register int positive;
+ int count;
+
+ if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
+ positive = FALSE;
+ count = 1;
+ } else if (strcmp(cp, "--") == 0) {
+ positive = FALSE;
+ count = 2;
+ } else if (strcmp(cp, "+") == 0) {
+ positive = TRUE;
+ count = 1;
+ } else if (strcmp(cp, "++") == 0) {
+ positive = TRUE;
+ count = 2;
+ } else {
+ error(_("illegal CORRECTION field on Leap line"));
+ return;
+ }
+ if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
+ error(_("illegal Rolling/Stationary field on Leap line"));
+ return;
+ }
+ leapadd(tadd(t, tod), positive, lp->l_value, count);
+ }
+}
+
+static void
+inlink(fields, nfields)
+register char ** const fields;
+const int nfields;
+{
+ struct link l;
+
+ if (nfields != LINK_FIELDS) {
+ error(_("wrong number of fields on Link line"));
+ return;
+ }
+ if (*fields[LF_FROM] == '\0') {
+ error(_("blank FROM field on Link line"));
+ return;
+ }
+ if (*fields[LF_TO] == '\0') {
+ error(_("blank TO field on Link line"));
+ return;
+ }
+ l.l_filename = filename;
+ l.l_linenum = linenum;
+ l.l_from = ecpyalloc(fields[LF_FROM]);
+ l.l_to = ecpyalloc(fields[LF_TO]);
+ links = (struct link *) (void *) erealloc((char *) links,
+ (int) ((nlinks + 1) * sizeof *links));
+ links[nlinks++] = l;
+}
+
+static void
+rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
+register struct rule * const rp;
+const char * const loyearp;
+const char * const hiyearp;
+const char * const typep;
+const char * const monthp;
+const char * const dayp;
+const char * const timep;
+{
+ register const struct lookup * lp;
+ register const char * cp;
+ register char * dp;
+ register char * ep;
+
+ if ((lp = byword(monthp, mon_names)) == NULL) {
+ error(_("invalid month name"));
+ return;
+ }
+ rp->r_month = lp->l_value;
+ rp->r_todisstd = FALSE;
+ rp->r_todisgmt = FALSE;
+ dp = ecpyalloc(timep);
+ if (*dp != '\0') {
+ ep = dp + strlen(dp) - 1;
+ switch (lowerit(*ep)) {
+ case 's': /* Standard */
+ rp->r_todisstd = TRUE;
+ rp->r_todisgmt = FALSE;
+ *ep = '\0';
+ break;
+ case 'w': /* Wall */
+ rp->r_todisstd = FALSE;
+ rp->r_todisgmt = FALSE;
+ *ep = '\0';
+ break;
+ case 'g': /* Greenwich */
+ case 'u': /* Universal */
+ case 'z': /* Zulu */
+ rp->r_todisstd = TRUE;
+ rp->r_todisgmt = TRUE;
+ *ep = '\0';
+ break;
+ }
+ }
+ rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);
+ ifree(dp);
+ /*
+ ** Year work.
+ */
+ cp = loyearp;
+ lp = byword(cp, begin_years);
+ if (lp != NULL) switch ((int) lp->l_value) {
+ case YR_MINIMUM:
+ rp->r_loyear = INT_MIN;
+ break;
+ case YR_MAXIMUM:
+ rp->r_loyear = INT_MAX;
+ break;
+ default: /* "cannot happen" */
+ errx(EXIT_FAILURE,
+ _("panic: invalid l_value %d"), lp->l_value);
+ } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
+ error(_("invalid starting year"));
+ return;
+ } else if (noise) {
+ if (rp->r_loyear < min_year_representable)
+ warning(_("starting year too low to be represented"));
+ else if (rp->r_loyear > max_year_representable)
+ warning(_("starting year too high to be represented"));
+ }
+ cp = hiyearp;
+ if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
+ case YR_MINIMUM:
+ rp->r_hiyear = INT_MIN;
+ break;
+ case YR_MAXIMUM:
+ rp->r_hiyear = INT_MAX;
+ break;
+ case YR_ONLY:
+ rp->r_hiyear = rp->r_loyear;
+ break;
+ default: /* "cannot happen" */
+ errx(EXIT_FAILURE,
+ _("panic: invalid l_value %d"), lp->l_value);
+ } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
+ error(_("invalid ending year"));
+ return;
+ } else if (noise) {
+ if (rp->r_loyear < min_year_representable)
+ warning(_("ending year too low to be represented"));
+ else if (rp->r_loyear > max_year_representable)
+ warning(_("ending year too high to be represented"));
+ }
+ if (rp->r_loyear > rp->r_hiyear) {
+ error(_("starting year greater than ending year"));
+ return;
+ }
+ if (*typep == '\0')
+ rp->r_yrtype = NULL;
+ else {
+ if (rp->r_loyear == rp->r_hiyear) {
+ error(_("typed single year"));
+ return;
+ }
+ rp->r_yrtype = ecpyalloc(typep);
+ }
+ if (rp->r_loyear < min_year && rp->r_loyear > 0)
+ min_year = rp->r_loyear;
+ /*
+ ** Day work.
+ ** Accept things such as:
+ ** 1
+ ** last-Sunday
+ ** Sun<=20
+ ** Sun>=7
+ */
+ dp = ecpyalloc(dayp);
+ if ((lp = byword(dp, lasts)) != NULL) {
+ rp->r_dycode = DC_DOWLEQ;
+ rp->r_wday = lp->l_value;
+ rp->r_dayofmonth = len_months[1][rp->r_month];
+ } else {
+ if ((ep = strchr(dp, '<')) != 0)
+ rp->r_dycode = DC_DOWLEQ;
+ else if ((ep = strchr(dp, '>')) != 0)
+ rp->r_dycode = DC_DOWGEQ;
+ else {
+ ep = dp;
+ rp->r_dycode = DC_DOM;
+ }
+ if (rp->r_dycode != DC_DOM) {
+ *ep++ = 0;
+ if (*ep++ != '=') {
+ error(_("invalid day of month"));
+ ifree(dp);
+ return;
+ }
+ if ((lp = byword(dp, wday_names)) == NULL) {
+ error(_("invalid weekday name"));
+ ifree(dp);
+ return;
+ }
+ rp->r_wday = lp->l_value;
+ }
+ if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
+ rp->r_dayofmonth <= 0 ||
+ (rp->r_dayofmonth > len_months[1][rp->r_month])) {
+ error(_("invalid day of month"));
+ ifree(dp);
+ return;
+ }
+ }
+ ifree(dp);
+}
+
+static void
+convert(val, buf)
+const long val;
+char * const buf;
+{
+ register int i;
+ register long shift;
+
+ for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
+ buf[i] = val >> shift;
+}
+
+static void
+puttzcode(val, fp)
+const long val;
+FILE * const fp;
+{
+ char buf[4];
+
+ convert(val, buf);
+ (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
+}
+
+static int
+atcomp(avp, bvp)
+void * avp;
+void * bvp;
+{
+ if (((struct attype *) avp)->at < ((struct attype *) bvp)->at)
+ return -1;
+ else if (((struct attype *) avp)->at > ((struct attype *) bvp)->at)
+ return 1;
+ else return 0;
+}
+
+static void
+writezone(name)
+const char * const name;
+{
+ register FILE * fp;
+ register int i, j;
+ static char * fullname;
+ static struct tzhead tzh;
+ time_t ats[TZ_MAX_TIMES];
+ unsigned char types[TZ_MAX_TIMES];
+
+ /*
+ ** Sort.
+ */
+ if (timecnt > 1)
+ (void) qsort((void *) attypes, (size_t) timecnt,
+ (size_t) sizeof *attypes, atcomp);
+ /*
+ ** Optimize.
+ */
+ {
+ int fromi;
+ int toi;
+
+ toi = 0;
+ fromi = 0;
+ while (fromi < timecnt && attypes[fromi].at < min_time)
+ ++fromi;
+ if (isdsts[0] == 0)
+ while (fromi < timecnt && attypes[fromi].type == 0)
+ ++fromi; /* handled by default rule */
+ for ( ; fromi < timecnt; ++fromi) {
+ if (toi != 0
+ && ((attypes[fromi].at
+ + gmtoffs[attypes[toi - 1].type])
+ <= (attypes[toi - 1].at
+ + gmtoffs[toi == 1 ? 0
+ : attypes[toi - 2].type]))) {
+ attypes[toi - 1].type = attypes[fromi].type;
+ continue;
+ }
+ if (toi == 0 ||
+ attypes[toi - 1].type != attypes[fromi].type)
+ attypes[toi++] = attypes[fromi];
+ }
+ timecnt = toi;
+ }
+ /*
+ ** Transfer.
+ */
+ for (i = 0; i < timecnt; ++i) {
+ ats[i] = attypes[i].at;
+ types[i] = attypes[i].type;
+ }
+ fullname = erealloc(fullname,
+ (int) (strlen(directory) + 1 + strlen(name) + 1));
+ (void) sprintf(fullname, "%s/%s", directory, name);
+
+ /*
+ * Remove old file, if any, to snap links.
+ */
+ if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT)
+ err(EXIT_FAILURE, _("can't remove %s"), fullname);
+
+ if ((fp = fopen(fullname, "wb")) == NULL) {
+ if (mkdirs(fullname) != 0)
+ (void) exit(EXIT_FAILURE);
+ if ((fp = fopen(fullname, "wb")) == NULL)
+ err(EXIT_FAILURE, _("can't create %s"), fullname);
+ }
+ convert(eitol(typecnt), tzh.tzh_ttisgmtcnt);
+ convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
+ convert(eitol(leapcnt), tzh.tzh_leapcnt);
+ convert(eitol(timecnt), tzh.tzh_timecnt);
+ convert(eitol(typecnt), tzh.tzh_typecnt);
+ convert(eitol(charcnt), tzh.tzh_charcnt);
+ (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
+#define DO(field) (void) fwrite((void *) tzh.field, (size_t) sizeof tzh.field, (size_t) 1, fp)
+ DO(tzh_magic);
+ DO(tzh_reserved);
+ DO(tzh_ttisgmtcnt);
+ DO(tzh_ttisstdcnt);
+ DO(tzh_leapcnt);
+ DO(tzh_timecnt);
+ DO(tzh_typecnt);
+ DO(tzh_charcnt);
+#undef DO
+ for (i = 0; i < timecnt; ++i) {
+ j = leapcnt;
+ while (--j >= 0)
+ if (ats[i] >= trans[j]) {
+ ats[i] = tadd(ats[i], corr[j]);
+ break;
+ }
+ puttzcode((long) ats[i], fp);
+ }
+ if (timecnt > 0)
+ (void) fwrite((void *) types, (size_t) sizeof types[0],
+ (size_t) timecnt, fp);
+ for (i = 0; i < typecnt; ++i) {
+ puttzcode((long) gmtoffs[i], fp);
+ (void) putc(isdsts[i], fp);
+ (void) putc(abbrinds[i], fp);
+ }
+ if (charcnt != 0)
+ (void) fwrite((void *) chars, (size_t) sizeof chars[0],
+ (size_t) charcnt, fp);
+ for (i = 0; i < leapcnt; ++i) {
+ if (roll[i]) {
+ if (timecnt == 0 || trans[i] < ats[0]) {
+ j = 0;
+ while (isdsts[j])
+ if (++j >= typecnt) {
+ j = 0;
+ break;
+ }
+ } else {
+ j = 1;
+ while (j < timecnt && trans[i] >= ats[j])
+ ++j;
+ j = types[j - 1];
+ }
+ puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);
+ } else puttzcode((long) trans[i], fp);
+ puttzcode((long) corr[i], fp);
+ }
+ for (i = 0; i < typecnt; ++i)
+ (void) putc(ttisstds[i], fp);
+ for (i = 0; i < typecnt; ++i)
+ (void) putc(ttisgmts[i], fp);
+ if (ferror(fp) || fclose(fp))
+ errx(EXIT_FAILURE, _("error writing %s"), fullname);
+ if (chmod(fullname, mflag) < 0)
+ err(EXIT_FAILURE, _("cannot change mode of %s to %03o"),
+ fullname, (unsigned)mflag);
+ if ((uflag != (uid_t)-1 || gflag != (gid_t)-1)
+ && chown(fullname, uflag, gflag) < 0)
+ err(EXIT_FAILURE, _("cannot change ownership of %s"),
+ fullname);
+}
+
+static void
+doabbr(abbr, format, letters, isdst)
+char * const abbr;
+const char * const format;
+const char * const letters;
+const int isdst;
+{
+ if (strchr(format, '/') == NULL) {
+ if (letters == NULL)
+ (void) strcpy(abbr, format);
+ else (void) sprintf(abbr, format, letters);
+ } else if (isdst)
+ (void) strcpy(abbr, strchr(format, '/') + 1);
+ else {
+ (void) strcpy(abbr, format);
+ *strchr(abbr, '/') = '\0';
+ }
+}
+
+static void
+outzone(zpfirst, zonecount)
+const struct zone * const zpfirst;
+const int zonecount;
+{
+ register const struct zone * zp;
+ register struct rule * rp;
+ register int i, j;
+ register int usestart, useuntil;
+ register time_t starttime, untiltime;
+ register long gmtoff;
+ register long stdoff;
+ register int year;
+ register long startoff;
+ register int startttisstd;
+ register int startttisgmt;
+ register int type;
+ char startbuf[BUFSIZ];
+
+ INITIALIZE(untiltime);
+ INITIALIZE(starttime);
+ /*
+ ** Now. . .finally. . .generate some useful data!
+ */
+ timecnt = 0;
+ typecnt = 0;
+ charcnt = 0;
+ /*
+ ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au)
+ ** for noting the need to unconditionally initialize startttisstd.
+ */
+ startttisstd = FALSE;
+ startttisgmt = FALSE;
+ for (i = 0; i < zonecount; ++i) {
+ /*
+ ** A guess that may well be corrected later.
+ */
+ stdoff = 0;
+ zp = &zpfirst[i];
+ usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
+ useuntil = i < (zonecount - 1);
+ if (useuntil && zp->z_untiltime <= min_time)
+ continue;
+ gmtoff = zp->z_gmtoff;
+ eat(zp->z_filename, zp->z_linenum);
+ *startbuf = '\0';
+ startoff = zp->z_gmtoff;
+ if (zp->z_nrules == 0) {
+ stdoff = zp->z_stdoff;
+ doabbr(startbuf, zp->z_format,
+ (char *) NULL, stdoff != 0);
+ type = addtype(oadd(zp->z_gmtoff, stdoff),
+ startbuf, stdoff != 0, startttisstd,
+ startttisgmt);
+ if (usestart) {
+ addtt(starttime, type);
+ usestart = FALSE;
+ } else if (stdoff != 0)
+ addtt(min_time, type);
+ } else for (year = min_year; year <= max_year; ++year) {
+ if (useuntil && year > zp->z_untilrule.r_hiyear)
+ break;
+ /*
+ ** Mark which rules to do in the current year.
+ ** For those to do, calculate rpytime(rp, year);
+ */
+ for (j = 0; j < zp->z_nrules; ++j) {
+ rp = &zp->z_rules[j];
+ eats(zp->z_filename, zp->z_linenum,
+ rp->r_filename, rp->r_linenum);
+ rp->r_todo = year >= rp->r_loyear &&
+ year <= rp->r_hiyear &&
+ yearistype(year, rp->r_yrtype);
+ if (rp->r_todo)
+ rp->r_temp = rpytime(rp, year);
+ }
+ for ( ; ; ) {
+ register int k;
+ register time_t jtime, ktime;
+ register long offset;
+ char buf[BUFSIZ];
+
+ INITIALIZE(ktime);
+ if (useuntil) {
+ /*
+ ** Turn untiltime into UTC
+ ** assuming the current gmtoff and
+ ** stdoff values.
+ */
+ untiltime = zp->z_untiltime;
+ if (!zp->z_untilrule.r_todisgmt)
+ untiltime = tadd(untiltime,
+ -gmtoff);
+ if (!zp->z_untilrule.r_todisstd)
+ untiltime = tadd(untiltime,
+ -stdoff);
+ }
+ /*
+ ** Find the rule (of those to do, if any)
+ ** that takes effect earliest in the year.
+ */
+ k = -1;
+ for (j = 0; j < zp->z_nrules; ++j) {
+ rp = &zp->z_rules[j];
+ if (!rp->r_todo)
+ continue;
+ eats(zp->z_filename, zp->z_linenum,
+ rp->r_filename, rp->r_linenum);
+ offset = rp->r_todisgmt ? 0 : gmtoff;
+ if (!rp->r_todisstd)
+ offset = oadd(offset, stdoff);
+ jtime = rp->r_temp;
+ if (jtime == min_time ||
+ jtime == max_time)
+ continue;
+ jtime = tadd(jtime, -offset);
+ if (k < 0 || jtime < ktime) {
+ k = j;
+ ktime = jtime;
+ }
+ }
+ if (k < 0)
+ break; /* go on to next year */
+ rp = &zp->z_rules[k];
+ rp->r_todo = FALSE;
+ if (useuntil && ktime >= untiltime)
+ break;
+ stdoff = rp->r_stdoff;
+ if (usestart && ktime == starttime)
+ usestart = FALSE;
+ if (usestart) {
+ if (ktime < starttime) {
+ startoff = oadd(zp->z_gmtoff,
+ stdoff);
+ doabbr(startbuf, zp->z_format,
+ rp->r_abbrvar,
+ rp->r_stdoff != 0);
+ continue;
+ }
+ if (*startbuf == '\0' &&
+ startoff == oadd(zp->z_gmtoff,
+ stdoff)) {
+ doabbr(startbuf, zp->z_format,
+ rp->r_abbrvar,
+ rp->r_stdoff != 0);
+ }
+ }
+ eats(zp->z_filename, zp->z_linenum,
+ rp->r_filename, rp->r_linenum);
+ doabbr(buf, zp->z_format, rp->r_abbrvar,
+ rp->r_stdoff != 0);
+ offset = oadd(zp->z_gmtoff, rp->r_stdoff);
+ type = addtype(offset, buf, rp->r_stdoff != 0,
+ rp->r_todisstd, rp->r_todisgmt);
+ addtt(ktime, type);
+ }
+ }
+ if (usestart) {
+ if (*startbuf == '\0' &&
+ zp->z_format != NULL &&
+ strchr(zp->z_format, '%') == NULL &&
+ strchr(zp->z_format, '/') == NULL)
+ (void) strcpy(startbuf, zp->z_format);
+ eat(zp->z_filename, zp->z_linenum);
+ if (*startbuf == '\0')
+error(_("can't determine time zone abbreviation to use just after until time"));
+ else addtt(starttime,
+ addtype(startoff, startbuf,
+ startoff != zp->z_gmtoff,
+ startttisstd,
+ startttisgmt));
+ }
+ /*
+ ** Now we may get to set starttime for the next zone line.
+ */
+ if (useuntil) {
+ startttisstd = zp->z_untilrule.r_todisstd;
+ startttisgmt = zp->z_untilrule.r_todisgmt;
+ starttime = zp->z_untiltime;
+ if (!startttisstd)
+ starttime = tadd(starttime, -stdoff);
+ if (!startttisgmt)
+ starttime = tadd(starttime, -gmtoff);
+ }
+ }
+ writezone(zpfirst->z_name);
+}
+
+static void
+addtt(starttime, type)
+const time_t starttime;
+int type;
+{
+ if (starttime <= min_time ||
+ (timecnt == 1 && attypes[0].at < min_time)) {
+ gmtoffs[0] = gmtoffs[type];
+ isdsts[0] = isdsts[type];
+ ttisstds[0] = ttisstds[type];
+ ttisgmts[0] = ttisgmts[type];
+ if (abbrinds[type] != 0)
+ (void) strcpy(chars, &chars[abbrinds[type]]);
+ abbrinds[0] = 0;
+ charcnt = strlen(chars) + 1;
+ typecnt = 1;
+ timecnt = 0;
+ type = 0;
+ }
+ if (timecnt >= TZ_MAX_TIMES) {
+ error(_("too many transitions?!"));
+ (void) exit(EXIT_FAILURE);
+ }
+ attypes[timecnt].at = starttime;
+ attypes[timecnt].type = type;
+ ++timecnt;
+}
+
+static int
+addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
+const long gmtoff;
+const char * const abbr;
+const int isdst;
+const int ttisstd;
+const int ttisgmt;
+{
+ register int i, j;
+
+ if (isdst != TRUE && isdst != FALSE) {
+ error(_("internal error - addtype called with bad isdst"));
+ (void) exit(EXIT_FAILURE);
+ }
+ if (ttisstd != TRUE && ttisstd != FALSE) {
+ error(_("internal error - addtype called with bad ttisstd"));
+ (void) exit(EXIT_FAILURE);
+ }
+ if (ttisgmt != TRUE && ttisgmt != FALSE) {
+ error(_("internal error - addtype called with bad ttisgmt"));
+ (void) exit(EXIT_FAILURE);
+ }
+ /*
+ ** See if there's already an entry for this zone type.
+ ** If so, just return its index.
+ */
+ for (i = 0; i < typecnt; ++i) {
+ if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
+ strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
+ ttisstd == ttisstds[i] &&
+ ttisgmt == ttisgmts[i])
+ return i;
+ }
+ /*
+ ** There isn't one; add a new one, unless there are already too
+ ** many.
+ */
+ if (typecnt >= TZ_MAX_TYPES) {
+ error(_("too many local time types"));
+ (void) exit(EXIT_FAILURE);
+ }
+ gmtoffs[i] = gmtoff;
+ isdsts[i] = isdst;
+ ttisstds[i] = ttisstd;
+ ttisgmts[i] = ttisgmt;
+
+ for (j = 0; j < charcnt; ++j)
+ if (strcmp(&chars[j], abbr) == 0)
+ break;
+ if (j == charcnt)
+ newabbr(abbr);
+ abbrinds[i] = j;
+ ++typecnt;
+ return i;
+}
+
+static void
+leapadd(t, positive, rolling, count)
+const time_t t;
+const int positive;
+const int rolling;
+int count;
+{
+ register int i, j;
+
+ if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
+ error(_("too many leap seconds"));
+ (void) exit(EXIT_FAILURE);
+ }
+ for (i = 0; i < leapcnt; ++i)
+ if (t <= trans[i]) {
+ if (t == trans[i]) {
+ error(_("repeated leap second moment"));
+ (void) exit(EXIT_FAILURE);
+ }
+ break;
+ }
+ do {
+ for (j = leapcnt; j > i; --j) {
+ trans[j] = trans[j - 1];
+ corr[j] = corr[j - 1];
+ roll[j] = roll[j - 1];
+ }
+ trans[i] = t;
+ corr[i] = positive ? 1L : eitol(-count);
+ roll[i] = rolling;
+ ++leapcnt;
+ } while (positive && --count != 0);
+}
+
+static void
+adjleap P((void))
+{
+ register int i;
+ register long last = 0;
+
+ /*
+ ** propagate leap seconds forward
+ */
+ for (i = 0; i < leapcnt; ++i) {
+ trans[i] = tadd(trans[i], last);
+ last = corr[i] += last;
+ }
+}
+
+static int
+yearistype(year, type)
+const int year;
+const char * const type;
+{
+ static char * buf;
+ int result;
+
+ if (type == NULL || *type == '\0')
+ return TRUE;
+ buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type)));
+ (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
+ result = system(buf);
+ if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
+ case 0:
+ return TRUE;
+ case 1:
+ return FALSE;
+ }
+ error(_("wild result from command execution"));
+ warnx(_("command was '%s', result was %d"), buf, result);
+ for ( ; ; )
+ (void) exit(EXIT_FAILURE);
+}
+
+static int
+lowerit(a)
+int a;
+{
+ a = (unsigned char) a;
+ return (isascii(a) && isupper(a)) ? tolower(a) : a;
+}
+
+static int
+ciequal(ap, bp) /* case-insensitive equality */
+register const char * ap;
+register const char * bp;
+{
+ while (lowerit(*ap) == lowerit(*bp++))
+ if (*ap++ == '\0')
+ return TRUE;
+ return FALSE;
+}
+
+static int
+itsabbr(abbr, word)
+register const char * abbr;
+register const char * word;
+{
+ if (lowerit(*abbr) != lowerit(*word))
+ return FALSE;
+ ++word;
+ while (*++abbr != '\0')
+ do {
+ if (*word == '\0')
+ return FALSE;
+ } while (lowerit(*word++) != lowerit(*abbr));
+ return TRUE;
+}
+
+static const struct lookup *
+byword(word, table)
+register const char * const word;
+register const struct lookup * const table;
+{
+ register const struct lookup * foundlp;
+ register const struct lookup * lp;
+
+ if (word == NULL || table == NULL)
+ return NULL;
+ /*
+ ** Look for exact match.
+ */
+ for (lp = table; lp->l_word != NULL; ++lp)
+ if (ciequal(word, lp->l_word))
+ return lp;
+ /*
+ ** Look for inexact match.
+ */
+ foundlp = NULL;
+ for (lp = table; lp->l_word != NULL; ++lp)
+ if (itsabbr(word, lp->l_word)) {
+ if (foundlp == NULL)
+ foundlp = lp;
+ else return NULL; /* multiple inexact matches */
+ }
+ return foundlp;
+}
+
+static char **
+getfields(cp)
+register char * cp;
+{
+ register char * dp;
+ register char ** array;
+ register int nsubs;
+
+ if (cp == NULL)
+ return NULL;
+ array = (char **) (void *)
+ emalloc((int) ((strlen(cp) + 1) * sizeof *array));
+ nsubs = 0;
+ for ( ; ; ) {
+ while (isascii(*cp) && isspace((unsigned char) *cp))
+ ++cp;
+ if (*cp == '\0' || *cp == '#')
+ break;
+ array[nsubs++] = dp = cp;
+ do {
+ if ((*dp = *cp++) != '"')
+ ++dp;
+ else while ((*dp = *cp++) != '"')
+ if (*dp != '\0')
+ ++dp;
+ else {
+ error(_("odd number of quotation marks"));
+ exit(EXIT_FAILURE);
+ }
+ } while (*cp != '\0' && *cp != '#' &&
+ (!isascii(*cp) || !isspace((unsigned char) *cp)));
+ if (isascii(*cp) && isspace((unsigned char) *cp))
+ ++cp;
+ *dp = '\0';
+ }
+ array[nsubs] = NULL;
+ return array;
+}
+
+static long
+oadd(t1, t2)
+const long t1;
+const long t2;
+{
+ register long t;
+
+ t = t1 + t2;
+ if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
+ error(_("time overflow"));
+ (void) exit(EXIT_FAILURE);
+ }
+ return t;
+}
+
+static time_t
+tadd(t1, t2)
+const time_t t1;
+const long t2;
+{
+ register time_t t;
+
+ if (t1 == max_time && t2 > 0)
+ return max_time;
+ if (t1 == min_time && t2 < 0)
+ return min_time;
+ t = t1 + t2;
+ if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
+ error(_("time overflow"));
+ (void) exit(EXIT_FAILURE);
+ }
+ return t;
+}
+
+/*
+** Given a rule, and a year, compute the date - in seconds since January 1,
+** 1970, 00:00 LOCAL time - in that year that the rule refers to.
+*/
+
+static time_t
+rpytime(rp, wantedy)
+register const struct rule * const rp;
+register const int wantedy;
+{
+ register int y, m, i;
+ register long dayoff; /* with a nod to Margaret O. */
+ register time_t t;
+
+ if (wantedy == INT_MIN)
+ return min_time;
+ if (wantedy == INT_MAX)
+ return max_time;
+ dayoff = 0;
+ m = TM_JANUARY;
+ y = EPOCH_YEAR;
+ while (wantedy != y) {
+ if (wantedy > y) {
+ i = len_years[isleap(y)];
+ ++y;
+ } else {
+ --y;
+ i = -len_years[isleap(y)];
+ }
+ dayoff = oadd(dayoff, eitol(i));
+ }
+ while (m != rp->r_month) {
+ i = len_months[isleap(y)][m];
+ dayoff = oadd(dayoff, eitol(i));
+ ++m;
+ }
+ i = rp->r_dayofmonth;
+ if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
+ if (rp->r_dycode == DC_DOWLEQ)
+ --i;
+ else {
+ error(_("use of 2/29 in non leap-year"));
+ (void) exit(EXIT_FAILURE);
+ }
+ }
+ --i;
+ dayoff = oadd(dayoff, eitol(i));
+ if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
+ register long wday;
+
+#define LDAYSPERWEEK ((long) DAYSPERWEEK)
+ wday = eitol(EPOCH_WDAY);
+ /*
+ ** Don't trust mod of negative numbers.
+ */
+ if (dayoff >= 0)
+ wday = (wday + dayoff) % LDAYSPERWEEK;
+ else {
+ wday -= ((-dayoff) % LDAYSPERWEEK);
+ if (wday < 0)
+ wday += LDAYSPERWEEK;
+ }
+ while (wday != eitol(rp->r_wday))
+ if (rp->r_dycode == DC_DOWGEQ) {
+ dayoff = oadd(dayoff, (long) 1);
+ if (++wday >= LDAYSPERWEEK)
+ wday = 0;
+ ++i;
+ } else {
+ dayoff = oadd(dayoff, (long) -1);
+ if (--wday < 0)
+ wday = LDAYSPERWEEK - 1;
+ --i;
+ }
+ if (i < 0 || i >= len_months[isleap(y)][m]) {
+ if (noise)
+ warning(_("rule goes past start/end of month--will not work with pre-2004 versions of zic"));
+ }
+ }
+ if (dayoff < 0 && !TYPE_SIGNED(time_t))
+ return min_time;
+ if (dayoff < min_time / SECSPERDAY)
+ return min_time;
+ if (dayoff > max_time / SECSPERDAY)
+ return max_time;
+ t = (time_t) dayoff * SECSPERDAY;
+ return tadd(t, rp->r_tod);
+}
+
+static void
+newabbr(string)
+const char * const string;
+{
+ register int i;
+
+ i = strlen(string) + 1;
+ if (charcnt + i > TZ_MAX_CHARS) {
+ error(_("too many, or too long, time zone abbreviations"));
+ (void) exit(EXIT_FAILURE);
+ }
+ (void) strcpy(&chars[charcnt], string);
+ charcnt += eitol(i);
+}
+
+static int
+mkdirs(argname)
+char * const argname;
+{
+ register char * name;
+ register char * cp;
+
+ if (argname == NULL || *argname == '\0' || Dflag)
+ return 0;
+ cp = name = ecpyalloc(argname);
+ while ((cp = strchr(cp + 1, '/')) != 0) {
+ *cp = '\0';
+#ifndef unix
+ /*
+ ** DOS drive specifier?
+ */
+ if (isalpha((unsigned char) name[0]) &&
+ name[1] == ':' && name[2] == '\0') {
+ *cp = '/';
+ continue;
+ }
+#endif /* !defined unix */
+ if (!itsdir(name)) {
+ /*
+ ** It doesn't seem to exist, so we try to create it.
+ ** Creation may fail because of the directory being
+ ** created by some other multiprocessor, so we get
+ ** to do extra checking.
+ */
+ if (mkdir(name, MKDIR_UMASK) != 0
+ && (errno != EEXIST || !itsdir(name))) {
+ warn(_("can't create directory %s"), name);
+ ifree(name);
+ return -1;
+ }
+ }
+ *cp = '/';
+ }
+ ifree(name);
+ return 0;
+}
+
+static long
+eitol(i)
+const int i;
+{
+ long l;
+
+ l = i;
+ if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0))
+ errx(EXIT_FAILURE, _("%d did not sign extend correctly"), i);
+ return l;
+}
+
+#include <grp.h>
+#include <pwd.h>
+
+static void
+setgroup(flag, name)
+ gid_t *flag;
+ const char *name;
+{
+ struct group *gr;
+
+ if (*flag != (gid_t)-1)
+ errx(EXIT_FAILURE, _("multiple -g flags specified"));
+
+ gr = getgrnam(name);
+ if (gr == 0) {
+ char *ep;
+ unsigned long ul;
+
+ ul = strtoul(name, &ep, 10);
+ if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
+ *flag = ul;
+ return;
+ }
+ errx(EXIT_FAILURE, _("group `%s' not found"), name);
+ }
+ *flag = gr->gr_gid;
+}
+
+static void
+setuser(flag, name)
+ uid_t *flag;
+ const char *name;
+{
+ struct passwd *pw;
+
+ if (*flag != (gid_t)-1)
+ errx(EXIT_FAILURE, _("multiple -u flags specified"));
+
+ pw = getpwnam(name);
+ if (pw == 0) {
+ char *ep;
+ unsigned long ul;
+
+ ul = strtoul(name, &ep, 10);
+ if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
+ *flag = ul;
+ return;
+ }
+ errx(EXIT_FAILURE, _("user `%s' not found"), name);
+ }
+ *flag = pw->pw_uid;
+}
+
+/*
+** UNIX was a registered trademark of The Open Group in 2003.
+*/
--- /dev/null
+.TH ZPRINT 1 02/12/09
+.CM 4
+.SH NAME
+zprint \- show information about kernel zones
+.SH SYNOPSIS
+\fBzprint\fP [\fB-w\fP] [\fB-s\fP] [\fB-c\fP] [\fB-h\fP] [\fB-t\fP] [\fB-d\fP] [\fB-p <pid>\fP][name]
+.SH DESCRIPTION
+\fIzprint(1)\fR displays data about Mach zones. By default,
+\fIzprint\fR will print out information about all Mach zones. If the
+optional \fIname\fR is specified, \fIzprint\fR will print information
+about each zone for which \fIname\fR is a substring of the zone's
+name.
+.PP
+\fIzprint\fR interprets the following options:
+.\" ==========
+.TP 8
+.B \-c
+(Default)
+\fIzprint\fR prints zone info in columns. Long zone names are truncated
+with '$', and spaces are replaced with '.', to allow for sorting by column.
+Pageable and collectible zones are shown with 'P' and 'C'
+on the far right. Zones with preposterously large maximum
+sizes are shown with '----' in the max size and max num elts fields.
+.\" ==========
+.TP 8
+.B \-h
+(Default)
+Shows headings for the columns printed with the -c option.
+It may be useful to override this option when sorting by column.
+.\" ==========
+.TP 8
+.B \-s
+\fIzprint\fR sorts the zones, showing the zone wasting the most memory first.
+.\" ==========
+.TP 8
+.B \-w
+For each zone, \fIzprint\fR calculates how much space is allocated but
+not currently in use, the space wasted by the zone.
+.TP 8
+.B \-t
+For each zone, \fIzprint\fR calculates the total size of allocations from
+the zone over the life of the zone.
+.TP 8
+.B \-d
+Display deltas over time, showing any zones that have achieved a new maximum
+current allocation size during the interval. If the total allocation sizes are
+being displayed for the zones in question, it will also display the deltas if the
+total allocations have doubled.
+.B \-p <pid>
+Display zone usage related to the specified process id. Each zone will display
+standard columns and the amount of memory from that zone associated with a given
+process. The letter "A" in the flags column indicates that this total is being
+accounted to the process. Otherwise, the total is an indication of the influence
+the process has on the kernel, but the memory is being accounted to the kernel proper.
+.PP
+Any option (including default options) can be overridden
+by specifying the option in upper-case; for example, -C overrides
+the (default) option -c.
--- /dev/null
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_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. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * 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_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * @OSF_COPYRIGHT@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * zprint.c
+ *
+ * utility for printing out zone structures
+ *
+ * With no arguments, prints information on all zone structures.
+ * With an argument, prints information only on those zones for
+ * which the given name is a substring of the zone's name.
+ * With a "-w" flag, calculates how much much space is allocated
+ * to zones but not currently in use.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mach/mach.h>
+#include <mach_debug/mach_debug.h>
+#include <mach/mach_error.h>
+#include <libutil.h>
+#include <errno.h>
+
+#define streql(a, b) (strcmp((a), (b)) == 0)
+#define strneql(a, b, n) (strncmp((a), (b), (n)) == 0)
+
+static void usage(void);
+static void printzone(mach_zone_name_t *, task_zone_info_t *);
+static void colprintzone(mach_zone_name_t *, task_zone_info_t *);
+static int find_deltas(mach_zone_name_t *, task_zone_info_t *, task_zone_info_t *, char *, int, int);
+static void colprintzoneheader(void);
+static boolean_t substr(const char *a, int alen, const char *b, int blen);
+
+static char *program;
+
+static pid_t pid = 0;
+static task_t task = TASK_NULL;
+static boolean_t ShowPid = FALSE;
+
+static boolean_t ShowDeltas = FALSE;
+static boolean_t ShowWasted = FALSE;
+static boolean_t ShowTotal = FALSE;
+static boolean_t SortZones = FALSE;
+static boolean_t ColFormat = TRUE;
+static boolean_t PrintHeader = TRUE;
+
+static unsigned long long totalsize = 0;
+static unsigned long long totalused = 0;
+static unsigned long long totalsum = 0;
+static unsigned long long pidsum = 0;
+
+static int last_time = 0;
+
+static char *zname = NULL;
+static int znamelen = 0;
+
+static void
+sigintr(__unused int signum)
+{
+ last_time = 1;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-w] [-s] [-c] [-h] [-t] [-d] [-p <pid>] [name]\n", program);
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ mach_zone_name_t *name = NULL;
+ unsigned int nameCnt = 0;
+ task_zone_info_t *info = NULL;
+ unsigned int infoCnt = 0;
+
+ task_zone_info_t *max_info = NULL;
+ char *deltas = NULL;
+
+ kern_return_t kr;
+ int i, j;
+ int first_time = 1;
+ int must_print = 1;
+ int interval = 1;
+
+ signal(SIGINT, sigintr);
+
+ program = strrchr(argv[0], '/');
+ if (program == NULL)
+ program = argv[0];
+ else
+ program++;
+
+ for (i = 1; i < argc; i++) {
+ if (streql(argv[i], "-d"))
+ ShowDeltas = TRUE;
+ else if (streql(argv[i], "-t"))
+ ShowTotal = TRUE;
+ else if (streql(argv[i], "-T"))
+ ShowTotal = FALSE;
+ else if (streql(argv[i], "-w"))
+ ShowWasted = TRUE;
+ else if (streql(argv[i], "-W"))
+ ShowWasted = FALSE;
+ else if (streql(argv[i], "-s"))
+ SortZones = TRUE;
+ else if (streql(argv[i], "-S"))
+ SortZones = FALSE;
+ else if (streql(argv[i], "-c"))
+ ColFormat = TRUE;
+ else if (streql(argv[i], "-C"))
+ ColFormat = FALSE;
+ else if (streql(argv[i], "-H"))
+ PrintHeader = FALSE;
+ else if (streql(argv[i], "-p")) {
+ ShowPid = TRUE;
+ if (i < argc - 1) {
+ pid = atoi(argv[i+1]);
+ i++;
+ } else
+ usage();
+ } else if (streql(argv[i], "--")) {
+ i++;
+ break;
+ } else if (argv[i][0] == '-')
+ usage();
+ else
+ break;
+ }
+
+ switch (argc - i) {
+ case 0:
+ zname = "";
+ znamelen = 0;
+ break;
+
+ case 1:
+ zname = argv[i];
+ znamelen = strlen(zname);
+ break;
+
+ default:
+ usage();
+ }
+
+ if (ShowDeltas) {
+ SortZones = FALSE;
+ ColFormat = TRUE;
+ PrintHeader = TRUE;
+ }
+
+ if (ShowPid) {
+ kr = task_for_pid(mach_task_self(), pid, &task);
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "%s: task_for_pid(%d) failed: %s (try running as root)\n",
+ program, pid, mach_error_string(kr));
+ exit(1);
+ }
+ }
+
+ for (;;) {
+ if (ShowPid) {
+ kr = task_zone_info(task, &name, &nameCnt, &info, &infoCnt);
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "%s: task_zone_info: %s\n",
+ program, mach_error_string(kr));
+ exit(1);
+ }
+ } else {
+ mach_zone_info_t *zinfo = NULL;
+
+ kr = mach_zone_info(mach_host_self(),
+ &name, &nameCnt, &zinfo, &infoCnt);
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "%s: mach_zone_info: %s\n",
+ program, mach_error_string(kr));
+ exit(1);
+ }
+ kr = vm_allocate(mach_task_self(), (vm_address_t *)&info,
+ infoCnt * sizeof *info, VM_FLAGS_ANYWHERE);
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "%s vm_allocate: %s\n",
+ program, mach_error_string(kr));
+ exit(1);
+ }
+ for (i = 0; i < infoCnt; i++) {
+ *(mach_zone_info_t *)(info + i) = zinfo[i];
+ info[i].tzi_caller_acct = 0;
+ info[i].tzi_task_alloc = 0;
+ info[i].tzi_task_free = 0;
+ }
+ kr = vm_deallocate(mach_task_self(), (vm_address_t) zinfo,
+ (vm_size_t) (infoCnt * sizeof *zinfo));
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "%s: vm_deallocate: %s\n",
+ program, mach_error_string(kr));
+ exit(1);
+ }
+ }
+
+ if (nameCnt != infoCnt) {
+ fprintf(stderr, "%s: mach/task_zone_info: counts not equal?\n",
+ program);
+ exit(1);
+ }
+
+ if (first_time) {
+ deltas = (char *)malloc(infoCnt);
+ max_info = (task_zone_info_t *)malloc((infoCnt * sizeof *info));
+ }
+
+ if (SortZones) {
+ for (i = 0; i < nameCnt-1; i++)
+ for (j = i+1; j < nameCnt; j++) {
+ int wastei, wastej;
+
+ wastei = (info[i].tzi_cur_size -
+ (info[i].tzi_elem_size *
+ info[i].tzi_count));
+ wastej = (info[j].tzi_cur_size -
+ (info[j].tzi_elem_size *
+ info[j].tzi_count));
+
+ if (wastej > wastei) {
+ task_zone_info_t tinfo;
+ mach_zone_name_t tname;
+
+ tinfo = info[i];
+ info[i] = info[j];
+ info[j] = tinfo;
+
+ tname = name[i];
+ name[i] = name[j];
+ name[j] = tname;
+ }
+ }
+ }
+
+ must_print = find_deltas(name, info, max_info, deltas, infoCnt, first_time);
+ if (must_print) {
+ if (ColFormat) {
+ if (!first_time)
+ printf("\n");
+ colprintzoneheader();
+ }
+ for (i = 0; i < nameCnt; i++) {
+ if (deltas[i]) {
+ if (ColFormat)
+ colprintzone(&name[i], &info[i]);
+ else
+ printzone(&name[i], &info[i]);
+ }
+ }
+ }
+
+ first_time = 0;
+
+ if ((name != NULL) && (nameCnt != 0)) {
+ kr = vm_deallocate(mach_task_self(), (vm_address_t) name,
+ (vm_size_t) (nameCnt * sizeof *name));
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "%s: vm_deallocate: %s\n",
+ program, mach_error_string(kr));
+ exit(1);
+ }
+ }
+
+ if ((info != NULL) && (infoCnt != 0)) {
+ kr = vm_deallocate(mach_task_self(), (vm_address_t) info,
+ (vm_size_t) (infoCnt * sizeof *info));
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "%s: vm_deallocate: %s\n",
+ program, mach_error_string(kr));
+ exit(1);
+ }
+ }
+
+ if ((ShowWasted||ShowTotal) && PrintHeader && !ShowDeltas) {
+ printf("TOTAL SIZE = %llu\n", totalsize);
+ printf("TOTAL USED = %llu\n", totalused);
+ if (ShowWasted)
+ printf("TOTAL WASTED = %llu\n", totalsize - totalused);
+ if (ShowTotal)
+ printf("TOTAL ALLOCS = %llu\n", totalsum);
+ }
+
+ if (ShowDeltas == FALSE || last_time)
+ break;
+
+ sleep(interval);
+ }
+ exit(0);
+}
+
+static boolean_t
+substr(const char *a, int alen, const char *b, int blen)
+{
+ int i;
+
+ for (i = 0; i <= blen - alen; i++)
+ if (strneql(a, b+i, alen))
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+printzone(mach_zone_name_t *name, task_zone_info_t *info)
+{
+ unsigned long long used, size;
+
+ printf("%.*s zone:\n", (int)sizeof name->mzn_name, name->mzn_name);
+ printf("\tcur_size: %lluK bytes (%llu elements)\n",
+ info->tzi_cur_size/1024,
+ (info->tzi_elem_size == 0) ? 0 :
+ info->tzi_cur_size/info->tzi_elem_size);
+ printf("\tmax_size: %lluK bytes (%llu elements)\n",
+ info->tzi_max_size/1024,
+ (info->tzi_elem_size == 0) ? 0 :
+ info->tzi_max_size/info->tzi_elem_size);
+ printf("\telem_size: %llu bytes\n",
+ info->tzi_elem_size);
+ printf("\t# of elems: %llu\n",
+ info->tzi_count);
+ printf("\talloc_size: %lluK bytes (%llu elements)\n",
+ info->tzi_alloc_size/1024,
+ (info->tzi_elem_size == 0) ? 0 :
+ info->tzi_alloc_size/info->tzi_elem_size);
+ if (info->tzi_exhaustible)
+ printf("\tEXHAUSTIBLE\n");
+ if (info->tzi_collectable)
+ printf("\tCOLLECTABLE\n");
+ if (ShowPid && info->tzi_caller_acct)
+ printf("\tCALLER ACCOUNTED\n");
+ if (ShowPid) {
+ pidsum += info->tzi_task_alloc - info->tzi_task_free;
+ printf("\tproc_alloc_size: %8dK bytes (%llu elements)\n",
+ (int)((info->tzi_task_alloc - info->tzi_task_free)/1024),
+ (info->tzi_elem_size == 0) ? 0 :
+ (info->tzi_task_alloc - info->tzi_task_free)/info->tzi_elem_size);
+ }
+ if (ShowWasted) {
+ totalused += used = info->tzi_elem_size * info->tzi_count;
+ totalsize += size = info->tzi_cur_size;
+ printf("\t\t\t\t\tWASTED: %llu\n", size - used);
+ }
+ if (ShowTotal) {
+ totalsum += info->tzi_sum_size;
+ printf("\t\t\t\t\tTOTAL: %llu\n", totalsum);
+ if (ShowPid)
+ printf("\t\t\t\t\tPID TOTAL: %llu\n", pidsum);
+ }
+}
+
+#define PRINTK(fmt, value) \
+ printf(fmt "K", (value) / 1024 ) /* ick */
+
+static void
+colprintzone(mach_zone_name_t *zone_name, task_zone_info_t *info)
+{
+ char *name = zone_name->mzn_name;
+ int j, namewidth;
+ unsigned long long used, size;
+
+ namewidth = 25;
+ if (ShowWasted || ShowTotal) {
+ namewidth -= 7;
+ }
+ for (j = 0; j < namewidth - 1 && name[j]; j++) {
+ if (name[j] == ' ') {
+ putchar('.');
+ } else {
+ putchar(name[j]);
+ }
+ }
+ if (j == namewidth - 1) {
+ if (name[j]) {
+ putchar('$');
+ } else {
+ putchar(' ');
+ }
+ } else {
+ for (; j < namewidth; j++) {
+ putchar(' ');
+ }
+ }
+ printf(" %6llu", info->tzi_elem_size);
+ PRINTK(" %10llu", info->tzi_cur_size);
+ if (info->tzi_max_size / 1024 > 9999999) {
+ printf(" --------");
+ } else {
+ PRINTK(" %10llu", info->tzi_max_size);
+ }
+ printf(" %10llu", info->tzi_cur_size / info->tzi_elem_size);
+ if (info->tzi_max_size / 1024 >= 999999999) {
+ printf(" ----------");
+ } else {
+ printf(" %11llu", info->tzi_max_size / info->tzi_elem_size);
+ }
+ printf(" %11llu", info->tzi_count);
+ PRINTK(" %5llu", info->tzi_alloc_size);
+ printf(" %6llu", info->tzi_alloc_size / info->tzi_elem_size);
+
+ totalused += used = info->tzi_elem_size * info->tzi_count;
+ totalsize += size = info->tzi_cur_size;
+ totalsum += info->tzi_sum_size;
+
+ printf(" %c%c%c",
+ (info->tzi_exhaustible ? 'X' : ' '),
+ (info->tzi_caller_acct ? 'A' : ' '),
+ (info->tzi_collectable ? 'C' : ' '));
+ if (ShowWasted) {
+ PRINTK(" %8llu", size - used);
+ }
+ if (ShowPid) {
+ printf("%8dK", (int)((info->tzi_task_alloc - info->tzi_task_free)/1024));
+ }
+ if (ShowTotal) {
+ if (info->tzi_sum_size < 1024)
+ printf(" %16lluB", info->tzi_sum_size);
+ else
+ PRINTK(" %16llu", info->tzi_sum_size);
+ }
+ printf("\n");
+}
+
+static void
+colprintzoneheader(void)
+{
+ if (! PrintHeader) {
+ return;
+ }
+ printf("%s elem cur max cur max"
+ " cur alloc alloc %s%s\n",
+ (ShowWasted||ShowTotal)? "" : " ",
+ (ShowWasted)? " ":"",
+ (ShowPid) ? " PID" : "" );
+ printf("zone name%s size size size #elts #elts"
+ " inuse size count ", (ShowWasted||ShowTotal)? " " : " " );
+ if (ShowWasted)
+ printf(" wasted");
+ if (ShowPid)
+ printf(" Allocs");
+ if (ShowTotal)
+ printf(" Total Allocs");
+ printf("\n%s-------------------------------------------------------"
+ "-----------------------------------------------",
+ (ShowWasted||ShowTotal)? "" : "-------");
+ if (ShowWasted)
+ printf("----------");
+ if (ShowPid)
+ printf("---------");
+ if (ShowTotal)
+ printf("------------------");
+ printf("\n");
+}
+
+int
+find_deltas(mach_zone_name_t *name, task_zone_info_t *info, task_zone_info_t *max_info,
+ char *deltas, int cnt, int first_time)
+{
+ int i;
+ int found_one = 0;
+
+ for (i = 0; i < cnt; i++) {
+ deltas[i] = 0;
+ if (substr(zname, znamelen, name[i].mzn_name,
+ strnlen(name[i].mzn_name, sizeof name[i].mzn_name))) {
+ if (first_time || info->tzi_cur_size > max_info->tzi_cur_size ||
+ (ShowTotal && ((info->tzi_sum_size >> 1) > max_info->tzi_sum_size))) {
+ max_info->tzi_cur_size = info->tzi_cur_size;
+ max_info->tzi_sum_size = info->tzi_sum_size;
+ deltas[i] = 1;
+ found_one = 1;
+ }
+ }
+ info++;
+ max_info++;
+ }
+ return(found_one);
+}
europe northamerica southamerica pacificnew etcetera factory \
backward
NDATA= systemv
-SDATA= solar87 solar88 solar89
-TDATA= $(YDATA) $(NDATA) $(SDATA)
-DATA= $(YDATA) $(NDATA) $(SDATA) leapseconds # yearistype.sh
+TDATA= $(YDATA) $(NDATA)
+DATA= $(YDATA) $(NDATA) leapseconds # yearistype.sh
USNO= usno1988 usno1989
ZIC=zic
#this must be run on a native system
-zic -y datfiles/yearistype.sh -d /tmp/zoneinfo -L /dev/null datfiles/africa datfiles/antarctica datfiles/asia datfiles/australasia datfiles/europe datfiles/northamerica datfiles/southamerica datfiles/pacificnew datfiles/etcetera datfiles/factory datfiles/backward datfiles/systemv datfiles/solar87 datfiles/solar88 datfiles/solar89
+zic -y datfiles/yearistype.sh -d /tmp/zoneinfo -L /dev/null datfiles/africa datfiles/antarctica datfiles/asia datfiles/australasia datfiles/europe datfiles/northamerica datfiles/southamerica datfiles/pacificnew datfiles/etcetera datfiles/factory datfiles/backward datfiles/systemv
POSIXRULES="US/Pacific"
# pacificnew is obsolete and was removed from ZONE_FILES
-ZONE_FILES="africa antarctica asia australasia europe northamerica southamerica etcetera factory backward systemv solar87 solar88 solar89"
+ZONE_FILES="africa antarctica asia australasia europe northamerica southamerica etcetera factory backward systemv"
ZONEINFO="${BUILT_PRODUCTS_DIR}/zoneinfo"
DATFILES="${BUILT_PRODUCTS_DIR}/datfiles"
PRIVATEDIR="${BUILT_PRODUCTS_DIR}/private"