[Midnightbsd-cvs] src [7700] trunk/lib: add libnotify/libosxsupport

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Thu Aug 11 21:15:53 EDT 2016


Revision: 7700
          http://svnweb.midnightbsd.org/src/?rev=7700
Author:   laffer1
Date:     2016-08-11 21:15:53 -0400 (Thu, 11 Aug 2016)
Log Message:
-----------
add libnotify/libosxsupport

Added Paths:
-----------
    trunk/lib/libnotify/
    trunk/lib/libnotify/APPLE_LICENSE
    trunk/lib/libnotify/Makefile
    trunk/lib/libnotify/libnotify.c
    trunk/lib/libnotify/libnotify.h
    trunk/lib/libnotify/notify.3
    trunk/lib/libnotify/notify.h
    trunk/lib/libnotify/notify_cancel.3
    trunk/lib/libnotify/notify_check.3
    trunk/lib/libnotify/notify_client.c
    trunk/lib/libnotify/notify_get_state.3
    trunk/lib/libnotify/notify_internal.h
    trunk/lib/libnotify/notify_ipc.defs
    trunk/lib/libnotify/notify_ipc_types.h
    trunk/lib/libnotify/notify_is_valid_token.3
    trunk/lib/libnotify/notify_keys.h
    trunk/lib/libnotify/notify_post.3
    trunk/lib/libnotify/notify_private.h
    trunk/lib/libnotify/notify_register_check.3
    trunk/lib/libnotify/notify_register_dispatch.3
    trunk/lib/libnotify/notify_register_file_descriptor.3
    trunk/lib/libnotify/notify_register_mach_port.3
    trunk/lib/libnotify/notify_register_signal.3
    trunk/lib/libnotify/notify_set_state.3
    trunk/lib/libnotify/table.c
    trunk/lib/libnotify/table.h
    trunk/lib/libosxsupport/
    trunk/lib/libosxsupport/Makefile
    trunk/lib/libosxsupport/assumes.c
    trunk/lib/libosxsupport/atomic_compat.h
    trunk/lib/libosxsupport/cache_module.c
    trunk/lib/libosxsupport/config.h
    trunk/lib/libosxsupport/file_module.c
    trunk/lib/libosxsupport/fileport.c
    trunk/lib/libosxsupport/getiopolicy_np.c
    trunk/lib/libosxsupport/libproc.c
    trunk/lib/libosxsupport/mdns_module.c
    trunk/lib/libosxsupport/search_module.c
    trunk/lib/libosxsupport/si_data.c
    trunk/lib/libosxsupport/si_getaddrinfo.c
    trunk/lib/libosxsupport/si_module.c
    trunk/lib/libosxsupport/uuid/
    trunk/lib/libosxsupport/uuid/clear.c
    trunk/lib/libosxsupport/uuid/copy.c
    trunk/lib/libosxsupport/uuid/gen_uuid.c
    trunk/lib/libosxsupport/uuid/isnull.c
    trunk/lib/libosxsupport/uuid/pack.c
    trunk/lib/libosxsupport/uuid/unpack.c
    trunk/lib/libosxsupport/uuid/unparse.c
    trunk/lib/libosxsupport/uuid/uuidP.h
    trunk/lib/libosxsupport/uuid/uuidd.h

Added: trunk/lib/libnotify/APPLE_LICENSE
===================================================================
--- trunk/lib/libnotify/APPLE_LICENSE	                        (rev 0)
+++ trunk/lib/libnotify/APPLE_LICENSE	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,372 @@
+APPLE PUBLIC SOURCE LICENSE
+Version 1.1 - April 19,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.1 (or subsequent version thereof), as it may
+be revised from time to time by Apple ("License").  As used in this
+License:
+
+1.1 "Affected Original Code" means only those specific portions of
+Original Code that allegedly infringe upon any party's intellectual
+property rights or are otherwise the subject of a claim of
+infringement.
+
+1.2 "Applicable Patent Rights" mean: (a) in the case where Apple is
+the grantor of rights, (i) claims of patents that are now or hereafter
+acquired, owned by or assigned to Apple and (ii) that 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) claims of patents that are now or hereafter acquired,
+owned by or assigned to You and (ii) that cover subject matter in Your
+Modifications, taken alone or in combination with Original Code.
+
+1.3 "Covered Code" means the Original Code, Modifications, the
+combination of Original Code and any Modifications, and/or any
+respective portions thereof.
+
+1.4 "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.5 "Larger Work" means a work which combines Covered Code or portions
+thereof with code not governed by the terms of this License.
+
+1.6 "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.7 "Original Code" means (a) 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; and (b) the object code compiled from such Source Code and
+originally made available by Apple under this License.
+
+1.8 "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.9 "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 Patent Rights 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) if You Deploy Covered Code containing Modifications made by You,
+inform others of how to obtain those Modifications by filling out and
+submitting the information found at
+http://www.apple.com/publicsource/modifications.html, if available;
+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 Patent Rights 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 Patent Rights 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 portion of, or functionality implemented by,
+the Original Code becomes the subject of a claim of infringement,
+Apple may, at its option: (a) attempt to procure the rights necessary
+for Apple and You to continue using the Affected Original Code; (b)
+modify the Affected Original Code so that it is no longer infringing;
+or (c) suspend Your rights to use, reproduce, modify, sublicense and
+distribute the Affected Original Code until a final determination of
+the claim is made by a court or governmental administrative agency of
+competent jurisdiction and Apple lifts the suspension as set forth
+below.  Such suspension of rights will be 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.  Upon such final
+determination being made, if Apple is legally able, without the
+payment of a fee or royalty, to resume use, reproduction,
+modification, sublicensing and distribution of the Affected Original
+Code, Apple will lift the suspension of rights to the Affected
+Original Code by posting a notice to such effect on the Apple web site
+that is used for implementation of this License.  If Apple suspends
+Your rights to Affected Original Code, nothing in this License shall
+be construed to restrict You, at Your option and subject to applicable
+law, from replacing the Affected Original Code with non-infringing
+code or independently negotiating for necessary rights from such third
+party.
+
+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 Section 13.5(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,
+sublicensing and distribution of the Covered Code and to destroy all
+copies of the Covered Code 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 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.2 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.3 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.4 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.5 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.6 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.7 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.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.
+
+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."

Added: trunk/lib/libnotify/Makefile
===================================================================
--- trunk/lib/libnotify/Makefile	                        (rev 0)
+++ trunk/lib/libnotify/Makefile	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,29 @@
+.include <bsd.init.mk>
+
+LIB=	notify
+WARNS=	6
+
+.PATH: .
+.PATH: ../../sbin/launchd
+
+BASE_INCLUDE= -I${.CURDIR}/../../include/apple -I${MACHINE_INCLUDES}
+BASE_INCLUDE+= -I${.CURDIR} -I. -I${.CURDIR}/../liblaunch -I${.CURDIR}/../libosxsupport
+BASE_INCLUDE+= -I${.CURDIR}/../../include -I${.CURDIR}/../../sys
+DEFINES= -D__APPLE__ -fblocks -DLIBC_NO_LIBCRASHREPORTERCLIENT -DPRIVATE
+MIG_FLAGS= ${BASE_INCLUDE} 	${DEFINES}
+CFLAGS+= ${MIG_FLAGS} -D__MigTypeCheck 
+
+notify_ipc.h notify_ipcUser.c: notify_ipc.defs
+	mig ${MIG_FLAGS} ${.CURDIR}/notify_ipc.defs
+
+notify_client.c: notify_ipc.h notify_ipcUser.c
+
+SRCS=	libnotify.c \
+	notify_client.c \
+	table.c \
+	notify_ipcUser.c
+INCS=	notify.h
+
+CLEANFILES+= *User.c *Server.c notify_ipc.h
+
+.include <bsd.lib.mk>


Property changes on: trunk/lib/libnotify/Makefile
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/libnotify.c
===================================================================
--- trunk/lib/libnotify/libnotify.c	                        (rev 0)
+++ trunk/lib/libnotify/libnotify.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,1551 @@
+/*
+ * Copyright (c) 2003-2012 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/types.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <sys/ipc.h>
+#include <signal.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include "libnotify.h"
+#include "notify.h"
+#include "notify_internal.h"
+
+#define USER_PROTECTED_UID_PREFIX "user.uid."
+#define USER_PROTECTED_UID_PREFIX_LEN 9
+
+uint64_t
+make_client_id(pid_t pid, int token)
+{
+	uint64_t cid;
+
+	cid = pid;
+	cid <<= 32;
+	cid |= token;
+
+	return cid;
+}
+
+notify_state_t *
+_notify_lib_notify_state_new(uint32_t flags, uint32_t table_size)
+{
+	notify_state_t *ns;
+
+	ns = (notify_state_t *)calloc(1, sizeof(notify_state_t));
+	if (ns == NULL) return NULL;
+
+	ns->flags = flags;
+	ns->sock = -1;
+
+	if (ns->flags & NOTIFY_STATE_USE_LOCKS) 
+	{
+		ns->lock = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
+		if (ns->lock == NULL)
+		{
+			free(ns);
+			return NULL;
+		}
+
+		pthread_mutex_init(ns->lock, NULL);
+	}
+
+	ns->name_table = _nc_table_new(table_size);
+	ns->name_id_table = _nc_table_new(table_size);
+	ns->client_table = _nc_table_new(table_size);
+	ns->port_table = _nc_table_new(table_size);
+	ns->proc_table = _nc_table_new(table_size);
+
+	if ((ns->name_table == NULL) || (ns->name_id_table == NULL) || (ns->client_table == NULL) || (ns->port_table == NULL) || (ns->proc_table == NULL))
+	{
+		free(ns->lock);
+		_nc_table_free(ns->name_table);
+		_nc_table_free(ns->name_id_table);
+		_nc_table_free(ns->client_table);
+		_nc_table_free(ns->port_table);
+		_nc_table_free(ns->proc_table);
+		free(ns);
+		return NULL;
+	}
+
+	return ns;
+}
+
+void
+_notify_lib_notify_state_free(notify_state_t *ns)
+{
+	if (ns == NULL) return;
+
+	_nc_table_free(ns->name_table);
+	_nc_table_free(ns->name_id_table);
+	_nc_table_free(ns->client_table);
+	_nc_table_free(ns->port_table);
+	_nc_table_free(ns->proc_table);
+
+	if (ns->lock != NULL)
+	{
+		pthread_mutex_destroy(ns->lock);
+		free(ns->lock);
+	}
+
+	if (ns->sock != -1)
+	{
+		shutdown(ns->sock, 2);
+		close(ns->sock);
+	}
+
+	if (ns->controlled_name != NULL) free(ns->controlled_name);
+}
+
+static client_t *
+_internal_client_new(notify_state_t *ns, pid_t pid, int token)
+{
+	client_t *c;
+	uint64_t cid = make_client_id(pid, token);
+
+	if (ns == NULL) return NULL;
+
+	/* detect duplicates - should never happen, but it would be bad */
+	c = _nc_table_find_64(ns->client_table, cid);
+	if (c != NULL) return NULL;
+
+	c = calloc(1, sizeof(client_t));
+	if (c == NULL) return NULL;
+
+	ns->stat_client_alloc++;
+
+	c->client_id = cid;
+	c->pid = pid;
+	c->send_val = token;
+
+	_nc_table_insert_64(ns->client_table, cid, c);
+
+	return c;
+}
+
+static void
+_internal_client_release(notify_state_t *ns, client_t *c)
+{
+	uint64_t cid;
+
+	if (ns == NULL) return;
+	if (c == NULL) return;
+
+	cid = c->client_id;
+	_nc_table_delete_64(ns->client_table, cid);
+
+	switch (c->notify_type)
+	{
+		case NOTIFY_TYPE_SIGNAL:
+		{
+			break;
+		}
+		case NOTIFY_TYPE_FILE:
+		{
+			if (c->fd > 0) close(c->fd);
+			c->fd = -1;
+			break;
+		}
+		case NOTIFY_TYPE_PORT:
+		{
+			if (c->port != MACH_PORT_NULL)
+			{
+				/* release my send right to the port */
+				mach_port_deallocate(mach_task_self(), c->port);
+			}
+			break;
+		}
+		default:
+		{
+			break;
+		}
+	}
+
+	free(c);
+	ns->stat_client_free++;
+}
+
+static name_info_t *
+_internal_new_name(notify_state_t *ns, const char *name)
+{
+	name_info_t *n;
+	size_t namelen;
+
+	if (ns == NULL) return NULL;
+	if (name == NULL) return NULL;
+
+	namelen = strlen(name) + 1;
+
+	n = (name_info_t *)calloc(1, sizeof(name_info_t) + namelen);
+	if (n == NULL) return NULL;
+
+	ns->stat_name_alloc++;
+
+	n->name = (char *)n + sizeof(name_info_t);
+	memcpy(n->name, name, namelen);
+
+	notify_globals_t globals = _notify_globals();
+	n->name_id = globals->name_id++;
+
+	n->access = NOTIFY_ACCESS_DEFAULT;
+	n->slot = (uint32_t)-1;
+	n->val = 1;
+
+	_nc_table_insert_no_copy(ns->name_table, n->name, n);
+	_nc_table_insert_64(ns->name_id_table, n->name_id, n);
+
+	return n;
+}
+
+static void
+_internal_insert_controlled_name(notify_state_t *ns, name_info_t *n)
+{
+	unsigned int i, j;
+
+	if (ns == NULL) return;
+	if (n == NULL) return;
+
+	if (ns->controlled_name == NULL) ns->controlled_name_count = 0;
+
+	for (i = 0; i < ns->controlled_name_count; i++)
+	{
+		if (ns->controlled_name[i] == n) return;
+	}
+
+	ns->controlled_name = (name_info_t **)reallocf(ns->controlled_name, (ns->controlled_name_count + 1) * sizeof(name_info_t *));
+
+	/*
+	 * Insert name in reverse sorted order (longer names preceed shorter names).
+	 * this means that in _internal_check_access, we check subspaces from the bottom up
+	 * i.e. we check access for the "deepest" controlled subspace.
+	 */
+
+	for (i = 0; i < ns->controlled_name_count; i++)
+	{
+		if (strcmp(n->name, ns->controlled_name[i]->name) > 0) break;
+	}
+
+	for (j = ns->controlled_name_count; j > i; j--)
+	{
+		ns->controlled_name[j] = ns->controlled_name[j-1];
+	}
+
+	ns->controlled_name[i] = n;
+	ns->controlled_name_count++;
+}
+
+static void
+_internal_remove_controlled_name(notify_state_t *ns, name_info_t *n)
+{
+	uint32_t i, j;
+
+	for (i = 0; i < ns->controlled_name_count; i++)
+	{
+		if (ns->controlled_name[i] == n)
+		{
+			for (j = i + 1; j < ns->controlled_name_count; j++)
+			{
+				ns->controlled_name[j-1] = ns->controlled_name[j];
+			}
+
+			ns->controlled_name_count--;
+			if (ns->controlled_name_count == 0)
+			{
+				free(ns->controlled_name);
+				ns->controlled_name = NULL;
+			}
+			else
+			{
+				ns->controlled_name = (name_info_t **)reallocf(ns->controlled_name, ns->controlled_name_count * sizeof(name_info_t *));
+			}
+
+			return;
+		}
+	}
+}
+
+static uint32_t
+_internal_check_access(notify_state_t *ns, const char *name, uid_t uid, gid_t gid, int req)
+{
+	uint32_t i, len, plen;
+	name_info_t *p;
+	char str[64];
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	/* root may do anything */
+	if (uid == 0) return NOTIFY_STATUS_OK;
+
+	/* if name has "user.uid." as a prefix, it is a user-protected namespace */
+	if (!strncmp(name, USER_PROTECTED_UID_PREFIX, USER_PROTECTED_UID_PREFIX_LEN))
+    {
+        snprintf(str, sizeof(str) - 1, "%s%d", USER_PROTECTED_UID_PREFIX, uid);
+        len = strlen(str);
+
+        /* user <uid> may access user.uid.<uid> or a subtree name */
+        if ((!strncmp(name, str, len)) && ((name[len] == '\0') || (name[len] == '.'))) return NOTIFY_STATUS_OK;
+        return NOTIFY_STATUS_NOT_AUTHORIZED;
+    }
+
+    len = strlen(name);
+
+	if (ns->controlled_name == NULL) ns->controlled_name_count = 0;
+	for (i = 0; i < ns->controlled_name_count; i++)
+	{
+		p = ns->controlled_name[i];
+		if (p == NULL) break;
+		if (p->name == NULL) continue;
+
+		plen = strlen(p->name);
+		if (plen > len) continue;
+		if (strncmp(p->name, name, plen)) continue;
+
+		/* Found a match or a prefix, check if restrictions apply to this uid/gid */
+		if ((p->uid == uid) && (p->access & (req << NOTIFY_ACCESS_USER_SHIFT))) break;
+		if ((p->gid == gid) && (p->access & (req << NOTIFY_ACCESS_GROUP_SHIFT))) break;
+		if (p->access & (req << NOTIFY_ACCESS_OTHER_SHIFT)) break;
+
+		return NOTIFY_STATUS_NOT_AUTHORIZED;
+	}
+
+	return NOTIFY_STATUS_OK;
+}
+
+uint32_t
+_notify_lib_check_controlled_access(notify_state_t *ns, char *name, uid_t uid, gid_t gid, int req)
+{
+	uint32_t status;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+	status = _internal_check_access(ns, name, uid, gid, req);
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+
+	return status;
+}
+
+uint32_t
+_notify_lib_port_proc_new(notify_state_t *ns, mach_port_t port, pid_t proc, uint32_t state, dispatch_source_t src)
+{
+	portproc_data_t *pdata;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if ((proc == 0) && (port == MACH_PORT_NULL)) return NOTIFY_STATUS_FAILED;
+
+	pdata = (portproc_data_t *)calloc(1, sizeof(portproc_data_t));
+	if (pdata == NULL) return NOTIFY_STATUS_FAILED;
+
+	ns->stat_portproc_alloc++;
+
+	pdata->refcount = 1;
+	pdata->flags = state;
+	pdata->src = src;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+	if (proc == 0) _nc_table_insert_n(ns->port_table, port, pdata);
+	else _nc_table_insert_n(ns->proc_table, proc, pdata);
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+
+	return NOTIFY_STATUS_OK;
+}
+
+portproc_data_t *
+_notify_lib_port_proc_find(notify_state_t *ns, mach_port_t port, pid_t proc)
+{
+	portproc_data_t *pdata = NULL;
+
+	if (ns == NULL) return NULL;
+	if ((proc == 0) && (port == MACH_PORT_NULL)) return NULL;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	if (proc == 0) pdata = _nc_table_find_n(ns->port_table, port);
+	else pdata = _nc_table_find_n(ns->proc_table, proc);
+
+	if (pdata != NULL) pdata->refcount++;
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+
+	return pdata;
+}
+
+void
+_notify_lib_port_proc_release(notify_state_t *ns, mach_port_t port, pid_t proc)
+{
+	portproc_data_t *pdata = NULL;
+
+	if (ns == NULL) return;
+	if ((proc == 0) && (port == MACH_PORT_NULL)) return;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	if (proc == 0) pdata = _nc_table_find_n(ns->port_table, port);
+	else pdata = _nc_table_find_n(ns->proc_table, proc);
+
+	if (pdata != NULL)
+	{
+		if (pdata->refcount > 0) pdata->refcount--;
+		if (pdata->refcount == 0)
+		{
+			if (proc == 0) _nc_table_delete_n(ns->port_table, port);
+			else _nc_table_delete_n(ns->proc_table, proc);
+
+			dispatch_source_cancel(pdata->src);
+			dispatch_release(pdata->src);
+
+			free(pdata);
+			ns->stat_portproc_free++;
+		}
+	}
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+}
+
+/*
+ * Send notification to a subscriber
+ */
+static uint32_t
+_internal_send(notify_state_t *ns, client_t *c)
+{
+	uint32_t send;
+	portproc_data_t *pdata;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (c == NULL) return NOTIFY_STATUS_FAILED;
+
+	if (c->state & NOTIFY_CLIENT_STATE_SUSPENDED)
+	{
+		c->state |= NOTIFY_CLIENT_STATE_PENDING;
+		return NOTIFY_STATUS_OK;
+	}
+
+	pdata = _nc_table_find_n(ns->proc_table, c->pid);
+	if ((pdata != NULL) && (pdata->flags & NOTIFY_PORT_PROC_STATE_SUSPENDED))
+	{
+		c->suspend_count++;
+		c->state |= NOTIFY_CLIENT_STATE_SUSPENDED;
+		c->state |= NOTIFY_CLIENT_STATE_PENDING;
+		return NOTIFY_STATUS_OK;
+	}
+
+	send = c->send_val;
+
+	switch (c->notify_type)
+	{
+		case NOTIFY_TYPE_SIGNAL:
+		{
+			int rc = 0;
+
+			if (c->pid == NOTIFY_CLIENT_SELF) rc = kill(getpid(), c->sig);
+			else rc = kill(c->pid, c->sig);
+
+			if (rc != 0) return NOTIFY_STATUS_FAILED;
+
+			c->state &= ~NOTIFY_CLIENT_STATE_PENDING;
+			c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT;
+
+			return NOTIFY_STATUS_OK;
+		}
+
+		case NOTIFY_TYPE_FILE:
+		{
+			ssize_t len;
+
+			if (c->fd >= 0)
+			{
+				send = htonl(send);
+				len = write(c->fd, &send, sizeof(uint32_t));
+				if (len != sizeof(uint32_t))
+				{
+					close(c->fd);
+					c->fd = -1;
+					return NOTIFY_STATUS_FAILED;
+				}
+			}
+
+			c->state &= ~NOTIFY_CLIENT_STATE_PENDING;
+			c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT;
+
+			return NOTIFY_STATUS_OK;
+		}
+
+		case NOTIFY_TYPE_PORT:
+		{
+			kern_return_t kstatus;
+			mach_msg_empty_send_t msg;
+			mach_msg_option_t opts = MACH_SEND_MSG | MACH_SEND_TIMEOUT;
+
+			pdata = _nc_table_find_n(ns->port_table, c->port);
+			if ((pdata != NULL) && (pdata->flags & NOTIFY_PORT_PROC_STATE_SUSPENDED))
+			{
+				c->suspend_count++;
+				c->state |= NOTIFY_CLIENT_STATE_SUSPENDED;
+				c->state |= NOTIFY_CLIENT_STATE_PENDING;
+				return NOTIFY_STATUS_OK;
+			}
+
+			if (ns->flags & NOTIFY_STATE_ENABLE_RESEND) opts |= MACH_SEND_NOTIFY;
+
+			memset(&msg, 0, sizeof(mach_msg_empty_send_t));
+			msg.header.msgh_size = sizeof(mach_msg_empty_send_t);
+			msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSGH_BITS_ZERO);
+			msg.header.msgh_local_port = MACH_PORT_NULL;
+			msg.header.msgh_remote_port = c->port;
+			msg.header.msgh_id = (mach_msg_id_t)send;
+
+			kstatus = mach_msg(&msg.header, opts, msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+
+			if (kstatus == MACH_SEND_TIMED_OUT)
+			{
+				/* deallocate port rights obtained via pseudo-receive after failed mach_msg() send */
+				mach_msg_destroy(&msg.header);
+				if (ns->flags & NOTIFY_STATE_ENABLE_RESEND)
+				{
+					/*
+					 * Suspend on timeout.
+					 * notifyd will get a MACH_NOTIFY_SEND_POSSIBLE and trigger a retry.
+					 * c->suspend_count must be zero, or we would not be trying to send.
+					 */
+					c->suspend_count++;
+					c->state |= NOTIFY_CLIENT_STATE_SUSPENDED;
+					c->state |= NOTIFY_CLIENT_STATE_PENDING;
+					c->state |= NOTIFY_CLIENT_STATE_TIMEOUT;
+
+					return NOTIFY_STATUS_OK;
+				}
+
+				return NOTIFY_STATUS_FAILED;
+			}
+			else if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+
+			c->state &= ~NOTIFY_CLIENT_STATE_PENDING;
+			c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT;
+
+			return NOTIFY_STATUS_OK;
+		}
+
+		default:
+		{
+			break;
+		}
+	}
+
+	c->state &= ~NOTIFY_CLIENT_STATE_PENDING;
+	c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT;
+
+	return NOTIFY_STATUS_OK;
+}
+
+uint32_t
+_notify_lib_post_client(notify_state_t *ns, client_t *c)
+{
+	uint32_t status;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (c == NULL) return NOTIFY_STATUS_FAILED;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+	status = _internal_send(ns, c);
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+
+	return status;
+}
+
+static uint32_t
+_internal_post_name(notify_state_t *ns, name_info_t *n, uid_t uid, gid_t gid)
+{
+	int auth;
+	list_t *l;
+	client_t *c;
+
+	if (n == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	auth = _internal_check_access(ns, n->name, uid, gid, NOTIFY_ACCESS_WRITE);
+	if (auth != 0) return NOTIFY_STATUS_NOT_AUTHORIZED;
+
+	n->val++;
+
+	for (l = n->subscriptions; l != NULL; l = _nc_list_next(l))
+	{
+		c = _nc_list_data(l);
+		if (c != NULL) _internal_send(ns, c);
+	}
+
+	return NOTIFY_STATUS_OK;
+}
+
+/*
+ * Notify subscribers of this name.
+ */
+uint32_t
+_notify_lib_post(notify_state_t *ns, const char *name, uid_t uid, gid_t gid)
+{
+	name_info_t *n;
+	uint32_t status;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	n = (name_info_t *)_nc_table_find(ns->name_table, name);
+	if (n == NULL)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_INVALID_NAME;
+	}
+
+	status = _internal_post_name(ns, n, uid, gid);
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return status;
+}
+
+uint32_t
+_notify_lib_post_nid(notify_state_t *ns, uint64_t nid, uid_t uid, gid_t gid)
+{
+	name_info_t *n;
+	uint32_t status;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	n = (name_info_t *)_nc_table_find_64(ns->name_id_table, nid);
+	if (n == NULL)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_INVALID_NAME;
+	}
+
+	status = _internal_post_name(ns, n, uid, gid);
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return status;
+}
+
+static void
+_internal_release_name_info(notify_state_t *ns, name_info_t *n)
+{
+	if (ns == NULL) return;
+	if (n == NULL) return;
+
+	if (n->refcount > 0) n->refcount--;
+	if (n->refcount == 0)
+	{
+		_internal_remove_controlled_name(ns, n);
+		_nc_table_delete(ns->name_table, n->name);
+		_nc_table_delete_64(ns->name_id_table, n->name_id);
+		_nc_list_release_list(n->subscriptions);
+		free(n);
+		ns->stat_name_free++;
+	}
+}
+
+/*
+ * Cancel (delete) a client
+ */
+static void
+_internal_cancel(notify_state_t *ns, uint64_t cid)
+{
+	client_t *c;
+	name_info_t *n;
+
+	if (ns == NULL) return;
+
+	c = NULL;
+	n = NULL;
+
+	c = _nc_table_find_64(ns->client_table, cid);
+	if (c == NULL) return;
+
+	n = c->name_info;
+	if (n == NULL) return;
+
+	n->subscriptions =_nc_list_find_release(n->subscriptions, c);
+	_internal_client_release(ns, c);
+	_internal_release_name_info(ns, n);
+}
+
+void
+_notify_lib_cancel(notify_state_t *ns, pid_t pid, int token)
+{
+	uint64_t cid;
+
+	if (ns == NULL) return;
+
+	cid = make_client_id(pid, token);
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+	_internal_cancel(ns, cid);
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+}
+
+void
+_notify_lib_suspend(notify_state_t *ns, pid_t pid, int token)
+{
+	client_t *c;
+	uint64_t cid;
+
+	if (ns == NULL) return;
+
+	cid = make_client_id(pid, token);
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	c = _nc_table_find_64(ns->client_table, cid);
+	if (c != NULL)
+	{
+		c->state |= NOTIFY_CLIENT_STATE_SUSPENDED;
+		if (c->suspend_count < UINT32_MAX) c->suspend_count++;
+	}
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+}
+
+uint32_t
+_notify_lib_resume(notify_state_t *ns, pid_t pid, int token)
+{
+	client_t *c;
+	uint64_t cid;
+	uint32_t status = NOTIFY_STATUS_OK;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+
+	cid = make_client_id(pid, token);
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	c = _nc_table_find_64(ns->client_table, cid);
+	if (c != NULL)
+	{
+		if (c->suspend_count > 0) c->suspend_count--;
+		if (c->suspend_count == 0)
+		{
+			c->state &= ~NOTIFY_CLIENT_STATE_SUSPENDED;
+			c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT;
+
+			if (c->state & NOTIFY_CLIENT_STATE_PENDING)
+			{
+				status = _internal_send(ns, c);
+			}
+		}
+	}
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+
+	return status;
+}
+
+void
+_notify_lib_suspend_proc(notify_state_t *ns, pid_t pid)
+{
+	portproc_data_t *pdata;
+
+	if (ns == NULL) return;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	pdata = _nc_table_find_n(ns->proc_table, pid);
+	if (pdata != NULL) pdata->flags |= NOTIFY_PORT_PROC_STATE_SUSPENDED;
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+}
+
+void
+_notify_lib_resume_proc(notify_state_t *ns, pid_t pid)
+{
+	client_t *c;
+	void *tt;
+	portproc_data_t *pdata;
+
+	if (ns == NULL) return;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	/* Resume all subscriptions for this process */
+	pdata = _nc_table_find_n(ns->proc_table, pid);
+	if (pdata != NULL) pdata->flags &= ~NOTIFY_PORT_PROC_STATE_SUSPENDED;
+
+	tt = _nc_table_traverse_start(ns->client_table);
+	while (tt != NULL)
+	{
+		c = _nc_table_traverse(ns->client_table, tt);
+		if (c == NULL) break;
+
+		if (c->pid == pid)
+		{
+			if (c->suspend_count > 0) c->suspend_count--;
+			if (c->suspend_count == 0)
+			{
+				c->state &= ~NOTIFY_CLIENT_STATE_SUSPENDED;
+				c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT;
+
+				if (c->state & NOTIFY_CLIENT_STATE_PENDING)
+				{
+					_internal_send(ns, c);
+				}
+			}
+		}
+	}
+	_nc_table_traverse_end(ns->client_table, tt);
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+}
+
+void
+_notify_lib_suspend_port(notify_state_t *ns, mach_port_t port)
+{
+	portproc_data_t *pdata;
+
+	if (ns == NULL) return;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	pdata = _nc_table_find_n(ns->port_table, port);
+	if (pdata != NULL) pdata->flags |= NOTIFY_PORT_PROC_STATE_SUSPENDED;
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+}
+
+void
+_notify_lib_resume_port(notify_state_t *ns, mach_port_t port)
+{
+	client_t *c;
+	void *tt;
+	portproc_data_t *pdata;
+
+	if (ns == NULL) return;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	/* Resume all subscriptions with this port */
+	pdata = _nc_table_find_n(ns->port_table, port);
+	if (pdata != NULL) pdata->flags &= ~NOTIFY_PORT_PROC_STATE_SUSPENDED;
+
+	tt = _nc_table_traverse_start(ns->client_table);
+	while (tt != NULL)
+	{
+		c = _nc_table_traverse(ns->client_table, tt);
+		if (c == NULL) break;
+
+		if (c->port == port)
+		{
+			if (c->suspend_count > 0) c->suspend_count--;
+			if (c->suspend_count == 0)
+			{
+				c->state &= ~NOTIFY_CLIENT_STATE_SUSPENDED;
+				c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT;
+
+				if (c->state & NOTIFY_CLIENT_STATE_PENDING)
+				{
+					_internal_send(ns, c);
+				}
+			}
+		}
+	}
+	_nc_table_traverse_end(ns->client_table, tt);
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+}
+
+/*
+ * Delete all clients for a process
+ * N.B. notifyd does not use this routine.
+ */
+void
+_notify_lib_cancel_proc(notify_state_t *ns, pid_t pid)
+{
+	client_t *c;
+	void *tt;
+	list_t *l, *x;
+
+	if (ns == NULL) return;
+
+	x = NULL;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	tt = _nc_table_traverse_start(ns->client_table);
+	while (tt != NULL)
+	{
+		c = _nc_table_traverse(ns->client_table, tt);
+		if (c == NULL) break;
+
+		if (c->pid == pid) x = _nc_list_prepend(x, _nc_list_new(c));
+	}
+	_nc_table_traverse_end(ns->client_table, tt);
+
+	for (l = x; l != NULL; l = _nc_list_next(l))
+	{
+		c = _nc_list_data(l);
+		_internal_cancel(ns, c->client_id);
+	}
+
+	_nc_list_release_list(x);
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+}
+
+/*
+ * Delete all clients for a port
+ * N.B. notifyd does not use this routine.
+ */
+void
+_notify_lib_cancel_port(notify_state_t *ns, mach_port_t port)
+{
+	client_t *c;
+	void *tt;
+	list_t *l, *x;
+
+	if (ns == NULL) return;
+
+	x = NULL;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	tt = _nc_table_traverse_start(ns->client_table);
+	while (tt != NULL)
+	{
+		c = _nc_table_traverse(ns->client_table, tt);
+		if (c == NULL) break;
+
+		if (c->port == port) x = _nc_list_prepend(x, _nc_list_new(c));
+	}
+	_nc_table_traverse_end(ns->client_table, tt);
+
+	for (l = x; l != NULL; l = _nc_list_next(l))
+	{
+		c = _nc_list_data(l);
+		_internal_cancel(ns, c->client_id);
+	}
+
+	_nc_list_release_list(x);
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+}
+
+/*
+ * Check if a name has changed since the last time this client checked.
+ * Returns true, false, or error.
+ */
+uint32_t
+_notify_lib_check(notify_state_t *ns, pid_t pid, int token, int *check)
+{
+	client_t *c;
+	uint64_t cid;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (check == NULL) return NOTIFY_STATUS_FAILED;
+
+	cid = make_client_id(pid, token);
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	c = _nc_table_find_64(ns->client_table, cid);
+
+	if (c == NULL)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_INVALID_TOKEN;
+	}
+
+	if (c->name_info == NULL)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_INVALID_TOKEN;
+	}
+
+	if (c->name_info->val == c->lastval)
+	{
+		*check = 0;
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_OK;
+	}
+
+	c->lastval = c->name_info->val;
+	*check = 1;
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return NOTIFY_STATUS_OK;
+}
+
+/*
+ * SPI: get value for a name.
+ */
+uint32_t
+_notify_lib_peek(notify_state_t *ns, pid_t pid, int token, int *val)
+{
+	client_t *c;
+	uint64_t cid;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (val == NULL) return NOTIFY_STATUS_FAILED;
+
+	cid = make_client_id(pid, token);
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	c = _nc_table_find_64(ns->client_table, cid);
+
+	if (c == NULL)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_INVALID_TOKEN;
+	}
+
+	if (c->name_info == NULL)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_INVALID_TOKEN;
+	}
+
+	*val = c->name_info->val;
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return NOTIFY_STATUS_OK;
+}
+
+int *
+_notify_lib_check_addr(notify_state_t *ns, pid_t pid, int token)
+{
+	client_t *c;
+	int *addr;
+	uint64_t cid;
+
+	if (ns == NULL) return NULL;
+
+	cid = make_client_id(pid, token);
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	c = _nc_table_find_64(ns->client_table, cid);
+
+	if (c == NULL)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NULL;
+	}
+
+	if (c->name_info == NULL)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NULL;
+	}
+
+	addr = (int *)&(c->name_info->val);
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return addr;
+}
+
+/*
+ * Get state value for a name.
+ */
+uint32_t
+_notify_lib_get_state(notify_state_t *ns, uint64_t nid, uint64_t *state, uid_t uid, gid_t gid)
+{
+	name_info_t *n;
+
+	(void)uid;
+	(void)gid;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (state == NULL) return NOTIFY_STATUS_FAILED;
+
+	*state = 0;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	n = (name_info_t *)_nc_table_find_64(ns->name_id_table, nid);
+
+	if (n == NULL)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_INVALID_NAME;
+	}
+
+#ifdef GET_STATE_AUTH_CHECK
+	int auth = _internal_check_access(ns, n->name, uid, gid, NOTIFY_ACCESS_READ);
+	if (auth != 0)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_NOT_AUTHORIZED;
+	}
+#endif
+
+	*state = n->state;
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return NOTIFY_STATUS_OK;
+}
+
+/*
+ * Set state value for a name.
+ */
+uint32_t
+_notify_lib_set_state(notify_state_t *ns, uint64_t nid, uint64_t state, uid_t uid, gid_t gid)
+{
+	name_info_t *n;
+	int auth;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	n = (name_info_t *)_nc_table_find_64(ns->name_id_table, nid);
+
+	if (n == NULL)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_INVALID_NAME;
+	}
+
+	auth = _internal_check_access(ns, n->name, uid, gid, NOTIFY_ACCESS_WRITE);
+	if (auth != 0)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_NOT_AUTHORIZED;
+	}
+
+	n->state = state;
+	n->state_time = mach_absolute_time();
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return NOTIFY_STATUS_OK;
+}
+
+static uint32_t
+_internal_register_common(notify_state_t *ns, const char *name, pid_t pid, int token, uid_t uid, gid_t gid, client_t **outc)
+{
+	client_t *c;
+	name_info_t *n;
+	int is_new_name;
+	uint32_t status;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+	if (outc == NULL) return NOTIFY_STATUS_OK;
+
+	status = _internal_check_access(ns, name, uid, gid, NOTIFY_ACCESS_READ);
+	if (status != NOTIFY_STATUS_OK) return NOTIFY_STATUS_NOT_AUTHORIZED;
+
+	*outc = NULL;
+	is_new_name = 0;
+
+	n = (name_info_t *)_nc_table_find(ns->name_table, name);
+	if (n == NULL)
+	{
+		is_new_name = 1;
+
+		n = _internal_new_name(ns, name);
+		if (n == NULL) return NOTIFY_STATUS_FAILED;
+	}
+
+	c = _internal_client_new(ns, pid, token);
+	if (c == NULL)
+	{
+		if (is_new_name == 1)
+		{
+			_nc_table_delete(ns->name_table, n->name);
+			_nc_list_release_list(n->subscriptions);
+			free(n);
+			ns->stat_name_free++;
+		}
+
+		return NOTIFY_STATUS_FAILED;
+	}
+
+	n->refcount++;
+
+	c->name_info = n;
+	n->subscriptions = _nc_list_prepend(n->subscriptions, _nc_list_new(c));
+
+	*outc = c;
+
+	return NOTIFY_STATUS_OK;
+}
+
+/*
+ * Register for signal.
+ * Returns the client_id;
+ */
+uint32_t
+_notify_lib_register_signal(notify_state_t *ns, const char *name, pid_t pid, int token, uint32_t sig, uid_t uid, gid_t gid, uint64_t *out_nid)
+{
+	client_t *c;
+	uint32_t status;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	c = NULL;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	status = _internal_register_common(ns, name, pid, token, uid, gid, &c);
+	if (status != NOTIFY_STATUS_OK)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return status;
+	}
+
+	c->notify_type = NOTIFY_TYPE_SIGNAL;
+	c->pid = pid;
+	c->sig = sig;
+	*out_nid = c->name_info->name_id;
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return NOTIFY_STATUS_OK;
+}
+
+/*
+ * Register for notification on a file descriptor.
+ * Returns the client_id;
+ */
+uint32_t
+_notify_lib_register_file_descriptor(notify_state_t *ns, const char *name, pid_t pid, int token, int fd, uid_t uid, gid_t gid, uint64_t *out_nid)
+{
+	client_t *c;
+	uint32_t status;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	c = NULL;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	status = _internal_register_common(ns, name, pid, token, uid, gid, &c);
+	if (status != NOTIFY_STATUS_OK)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return status;
+	}
+
+	c->notify_type = NOTIFY_TYPE_FILE;
+	c->fd = fd;
+	*out_nid = c->name_info->name_id;
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return NOTIFY_STATUS_OK;
+}
+
+/*
+ * Register for notification on a mach port.
+ * Returns the client_id;
+ */
+uint32_t
+_notify_lib_register_mach_port(notify_state_t *ns, const char *name, pid_t pid, int token, mach_port_t port, uid_t uid, gid_t gid, uint64_t *out_nid)
+{
+	client_t *c;
+	uint32_t status;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	c = NULL;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	status = _internal_register_common(ns, name, pid, token, uid, gid, &c);
+	if (status != NOTIFY_STATUS_OK)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return status;
+	}
+
+	c->notify_type = NOTIFY_TYPE_PORT;
+	c->port = port;
+	*out_nid = c->name_info->name_id;
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return NOTIFY_STATUS_OK;
+}
+
+/*
+ * Plain registration - only for notify_check()
+ * Returns the client_id.
+ */
+uint32_t
+_notify_lib_register_plain(notify_state_t *ns, const char *name, pid_t pid, int token, uint32_t slot, uint32_t uid, uint32_t gid, uint64_t *out_nid)
+{
+	client_t *c;
+	uint32_t status;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	c = NULL;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	status = _internal_register_common(ns, name, pid, token, uid, gid, &c);
+	if (status != NOTIFY_STATUS_OK)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return status;
+	}
+
+	if (slot == (uint32_t)SLOT_NONE)
+	{
+		c->notify_type = NOTIFY_TYPE_PLAIN;
+	}
+	else
+	{
+		c->notify_type = NOTIFY_TYPE_MEMORY;
+		c->name_info->slot = slot;
+	}
+
+	*out_nid = c->name_info->name_id;
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return NOTIFY_STATUS_OK;
+}
+
+uint32_t
+_notify_lib_set_owner(notify_state_t *ns, const char *name, uid_t uid, gid_t gid)
+{
+	name_info_t *n;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	n = (name_info_t *)_nc_table_find(ns->name_table, name);
+	if (n == NULL)
+	{
+		/* create new name */
+		n = _internal_new_name(ns, name);
+		if (n == NULL)
+		{
+			if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+			return NOTIFY_STATUS_FAILED;
+		}
+
+		/* 
+		 * Setting the refcount here allows the namespace to be "pre-populated"
+		 * with controlled names.  notifyd does this for reserved names in 
+		 * its configuration file.
+		 */
+		n->refcount++;
+	}
+
+	n->uid = uid;
+	n->gid = gid;
+
+	_internal_insert_controlled_name(ns, n);
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return NOTIFY_STATUS_OK;
+}
+
+uint32_t
+_notify_lib_get_owner(notify_state_t *ns, const char *name, uint32_t *uid, uint32_t *gid)
+{
+	name_info_t *n;
+	unsigned int i;
+	int nlen, len;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	n = (name_info_t *)_nc_table_find(ns->name_table, name);
+	if (n != NULL)
+	{
+		*uid = n->uid;
+		*gid = n->gid;
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_OK;
+	}
+
+	len = strlen(name);
+
+	for (i = 0; i < ns->controlled_name_count; i++)
+	{
+		n = ns->controlled_name[i];
+		if (n == NULL) break;
+
+		nlen = strlen(n->name);
+
+		if (!strcmp(n->name, name))
+		{
+			*uid = n->uid;
+			*gid = n->gid;
+			if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+			return NOTIFY_STATUS_OK;
+		}
+
+		/* check if this key is a prefix */
+		if (nlen >= len) continue;
+		if (strncmp(n->name, name, nlen)) continue;
+
+		*uid = n->uid;
+		*gid = n->gid;
+
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_OK;
+	}
+
+	*uid = 0;
+	*gid = 0;
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return NOTIFY_STATUS_OK;
+}
+
+uint32_t
+_notify_lib_set_access(notify_state_t *ns, const char *name, uint32_t mode)
+{
+	name_info_t *n;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	n = (name_info_t *)_nc_table_find(ns->name_table, name);
+	if (n == NULL)
+	{
+		/* create new name */
+		n = _internal_new_name(ns, name);
+		if (n == NULL)
+		{
+			if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+			return NOTIFY_STATUS_FAILED;
+		}
+
+		/* 
+		 * Setting the refcount here allows the namespace to be "pre-populated"
+		 * with controlled names.  notifyd does this for reserved names in 
+		 * its configuration file.
+		 */
+		n->refcount++;
+	}
+
+	n->access = mode;
+
+	_internal_insert_controlled_name(ns, n);
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return NOTIFY_STATUS_OK;
+}
+
+uint32_t
+_notify_lib_get_access(notify_state_t *ns, const char *name, uint32_t *mode)
+{
+	name_info_t *n;
+	unsigned int i;
+	int nlen, len;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	n = (name_info_t *)_nc_table_find(ns->name_table, name);
+	if (n != NULL)
+	{
+		*mode = n->access;
+
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_OK;
+	}
+
+	len = strlen(name);
+
+	for (i = 0; i < ns->controlled_name_count; i++)
+	{
+		n = ns->controlled_name[i];
+		if (n == NULL) break;
+		if (n->name == NULL) continue;
+
+		nlen = strlen(n->name);
+
+		if (!strcmp(n->name, name))
+		{
+			*mode = n->access;
+
+			if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+			return NOTIFY_STATUS_OK;
+		}
+
+		/* check if this key is a prefix */
+		if (nlen >= len) continue;
+		if (strncmp(n->name, name, nlen)) continue;
+
+		*mode = n->access;
+
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_OK;
+	}
+
+	*mode = NOTIFY_ACCESS_DEFAULT;
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return NOTIFY_STATUS_OK;
+}
+
+uint32_t
+_notify_lib_release_name(notify_state_t *ns, const char *name, uid_t uid, gid_t gid)
+{
+	name_info_t *n;
+
+	(void)gid;
+
+	if (ns == NULL) return NOTIFY_STATUS_FAILED;
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	if (ns->lock != NULL) pthread_mutex_lock(ns->lock);
+
+	n = (name_info_t *)_nc_table_find(ns->name_table, name);
+	if (n == NULL)
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_INVALID_NAME;
+	}
+
+	/* Owner and root may release */
+	if ((n->uid != uid) && (uid != 0))
+	{
+		if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+		return NOTIFY_STATUS_NOT_AUTHORIZED;
+	}
+
+	_internal_release_name_info(ns, n);
+
+	if (ns->lock != NULL) pthread_mutex_unlock(ns->lock);
+	return NOTIFY_STATUS_OK;
+}


Property changes on: trunk/lib/libnotify/libnotify.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/libnotify.h
===================================================================
--- trunk/lib/libnotify/libnotify.h	                        (rev 0)
+++ trunk/lib/libnotify/libnotify.h	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2003-2012 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@
+ */
+
+#ifndef _LIBNOTIFY_H_
+#define _LIBNOTIFY_H_
+
+#include <pthread.h>
+#include <mach/mach.h>
+#include <dispatch/dispatch.h>
+#include "table.h"
+
+#include <TargetConditionals.h>
+
+#if TARGET_IPHONE_SIMULATOR
+extern const char *_notify_shm_id();
+#define SHM_ID _notify_shm_id()
+#else
+#ifdef __FreeBSD__
+#define SHM_ID "/apple.shm.notification_center"
+#else
+#define SHM_ID "apple.shm.notification_center"
+#endif
+#endif
+
+#define NOTIFY_IPC_VERSION_NAME "com.apple.system.notify.ipc_version"
+#define NOTIFY_IPC_VERSION_NAME_LEN 35
+#define NOTIFY_SERVICE_NAME "com.apple.system.notification_center"
+#define NOTIFY_SERVICE_NAME_LEN 36
+
+#define COMMON_PORT_KEY "com.apple.system.notify.common"
+
+/* Notification types */
+#define NOTIFY_TYPE_NONE   0x00000000
+#define NOTIFY_TYPE_MEMORY 0x00000001
+#define NOTIFY_TYPE_PLAIN  0x00000002
+#define NOTIFY_TYPE_PORT   0x00000004
+#define NOTIFY_TYPE_FILE   0x00000008
+#define NOTIFY_TYPE_SIGNAL 0x00000010
+#define NOTIFY_TYPE_MASK   0x000000ff
+#define NOTIFY_FLAG_SELF   0x80000000
+#define NOTIFY_FLAG_REGEN  0x40000000
+#define NOTIFY_FLAG_RELEASE_SEND 0x20000000
+
+/* Return values for notify_check() */
+#define NOTIFY_CHECK_FALSE 0
+#define NOTIFY_CHECK_TRUE 1
+#define NOTIFY_CHECK_ERROR 2
+
+/* Access control */
+#define NOTIFY_ACCESS_READ   1
+#define NOTIFY_ACCESS_WRITE  2
+
+#define NOTIFY_ACCESS_OTHER_SHIFT 8
+#define NOTIFY_ACCESS_GROUP_SHIFT 4
+#define NOTIFY_ACCESS_USER_SHIFT  0
+
+#define NOTIFY_ACCESS_DEFAULT 0x00000333
+#define NOTIFY_ACCESS_USER_RW 0x00000003
+
+/* Filesystem Services */
+#define NOTIFY_SERVICE_FILE_STATUS_QUO 0x00
+#define NOTIFY_SERVICE_FILE_ADD        0x01
+#define NOTIFY_SERVICE_FILE_DELETE     0x02
+#define NOTIFY_SERVICE_FILE_MODIFY     0x04
+#define NOTIFY_SERVICE_FILE_ATTR       0x08
+
+#define NOTIFY_SERVICE_DIR_FILE_ADD    0x10
+#define NOTIFY_SERVICE_DIR_FILE_DELETE 0x20
+
+#define NOTIFY_CLIENT_STATE_SUSPENDED 0x00000001
+#define NOTIFY_CLIENT_STATE_PENDING   0x00000002
+#define NOTIFY_CLIENT_STATE_TIMEOUT   0x00000004
+
+#define NOTIFY_PORT_PROC_TYPE_PORT			0x00000010
+#define NOTIFY_PORT_PROC_TYPE_PROC			0x00000020
+#define NOTIFY_PORT_PROC_TYPE_MASK			0x000000f0
+#define NOTIFY_PORT_PROC_STATE_INVALID		0x00000001
+#define NOTIFY_PORT_PROC_STATE_SUSPENDED	0x00000002
+#define NOTIFY_PORT_PROC_STATE_MASK			0x0000000f
+
+/* notify state flags */
+#define NOTIFY_STATE_USE_LOCKS 0x00000001
+#define NOTIFY_STATE_ENABLE_RESEND 0x00000002
+
+#define NOTIFY_CLIENT_SELF 0
+#define SIGNAL_NONE -1
+#define FD_NONE -1
+#define SLOT_NONE -1
+
+#define _notify_lib_port_new(A,B,C,D) _notify_lib_port_proc_new(A,B,0,C,D)
+#define _notify_lib_proc_new(A,B,C,D) _notify_lib_port_proc_new(A,MACH_PORT_NULL,B,C,D)
+#define _notify_lib_port_find(A,B) _notify_lib_port_proc_find(A,B,0)
+#define _notify_lib_proc_find(A,B) _notify_lib_port_proc_find(A,MACH_PORT_NULL,B)
+#define _notify_lib_port_release(A,B) _notify_lib_port_proc_release(A,B,0)
+#define _notify_lib_proc_release(A,B) _notify_lib_port_proc_release(A,MACH_PORT_NULL,B)
+
+typedef struct
+{
+	char *name;
+	uint64_t name_id;
+	uint32_t uid;
+	uint32_t gid;
+	uint32_t access;
+	uint32_t slot;
+	uint32_t refcount;
+	uint32_t val;
+	uint64_t state;
+	uint64_t state_time;
+	void *private;
+	list_t *subscriptions;
+} name_info_t;
+
+typedef struct
+{
+	uint64_t client_id;
+	uint32_t state;
+	name_info_t *name_info;
+	uint32_t suspend_count;
+	uint32_t notify_type;
+	uint32_t lastval;
+	mach_port_t port;
+	int fd;
+	uint32_t send_val;
+	pid_t pid;
+	uint32_t sig;
+	void *private;
+} client_t;
+
+typedef struct
+{
+	uint32_t refcount;
+	uint32_t flags;
+	dispatch_source_t src;
+} portproc_data_t;
+
+typedef struct
+{
+	uint32_t flags;
+	table_t *name_table;
+	table_t *name_id_table;
+	table_t *client_table;
+	table_t *port_table;
+	table_t *proc_table;
+	name_info_t **controlled_name;
+	uint32_t controlled_name_count;
+	pthread_mutex_t *lock;
+	int sock;
+	uint32_t stat_name_alloc;
+	uint32_t stat_name_free;
+	uint32_t stat_client_alloc;
+	uint32_t stat_client_free;
+	uint32_t stat_portproc_alloc;
+	uint32_t stat_portproc_free;
+} notify_state_t;
+
+notify_state_t *_notify_lib_notify_state_new(uint32_t flags, uint32_t table_size);
+void _notify_lib_notify_state_free(notify_state_t *ns);
+
+uint32_t _notify_lib_post(notify_state_t *ns, const char *name, uint32_t uid, uint32_t gid);
+uint32_t _notify_lib_post_nid(notify_state_t *ns, uint64_t nid, uid_t uid, gid_t gid);
+uint32_t _notify_lib_post_client(notify_state_t *ns, client_t *c);
+
+uint32_t _notify_lib_check(notify_state_t *ns, pid_t pid, int token, int *check);
+uint32_t _notify_lib_get_state(notify_state_t *ns, uint64_t nid, uint64_t *state, uint32_t uid, uint32_t gid);
+uint32_t _notify_lib_set_state(notify_state_t *ns, uint64_t nid, uint64_t state, uint32_t uid, uint32_t gid);
+
+uint32_t _notify_lib_register_plain(notify_state_t *ns, const char *name, pid_t pid, int token, uint32_t slot, uint32_t uid, uint32_t gid, uint64_t *out_nid);
+uint32_t _notify_lib_register_signal(notify_state_t *ns, const char *name, pid_t pid, int token, uint32_t sig, uint32_t uid, uint32_t gid, uint64_t *out_nid);
+uint32_t _notify_lib_register_mach_port(notify_state_t *ns, const char *name, pid_t pid, int token, mach_port_t port, uint32_t uid, uint32_t gid, uint64_t *out_nid);
+uint32_t _notify_lib_register_file_descriptor(notify_state_t *ns, const char *name, pid_t pid, int token, int fd, uint32_t uid, uint32_t gid, uint64_t *out_nid);
+
+uint32_t _notify_lib_get_owner(notify_state_t *ns, const char *name, uint32_t *uid, uint32_t *gid);
+uint32_t _notify_lib_get_access(notify_state_t *ns, const char *name, uint32_t *access);
+
+uint32_t _notify_lib_set_owner(notify_state_t *ns, const char *name, uint32_t uid, uint32_t gid);
+uint32_t _notify_lib_set_access(notify_state_t *ns, const char *name, uint32_t access);
+
+uint32_t _notify_lib_release_name(notify_state_t *ns, const char *name, uint32_t uid, uint32_t gid);
+
+void _notify_lib_cancel(notify_state_t *ns, pid_t pid, int token);
+void _notify_lib_suspend(notify_state_t *ns, pid_t pid, int token);
+uint32_t _notify_lib_resume(notify_state_t *ns, pid_t pid, int token);
+
+void _notify_lib_cancel_proc(notify_state_t *ns, pid_t pid);
+void _notify_lib_suspend_proc(notify_state_t *ns, pid_t pid);
+void _notify_lib_resume_proc(notify_state_t *ns, pid_t pid);
+
+void _notify_lib_suspend_port(notify_state_t *ns, mach_port_t port);
+void _notify_lib_resume_port(notify_state_t *ns, mach_port_t port);
+
+uint32_t _notify_lib_check_controlled_access(notify_state_t *ns, char *name, uid_t uid, gid_t gid, int req);
+
+uint64_t make_client_id(pid_t pid, int token);
+
+uint32_t _notify_lib_port_proc_new(notify_state_t *ns, mach_port_t port, pid_t proc, uint32_t state, dispatch_source_t src);
+portproc_data_t *_notify_lib_port_proc_find(notify_state_t *ns, mach_port_t port, pid_t proc);
+void _notify_lib_port_proc_release(notify_state_t *ns, mach_port_t port, pid_t proc);
+
+
+#endif /* _LIBNOTIFY_H_ */


Property changes on: trunk/lib/libnotify/libnotify.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify.3
===================================================================
--- trunk/lib/libnotify/notify.3	                        (rev 0)
+++ trunk/lib/libnotify/notify.3	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,419 @@
+.\" Copyright (c) 2003-2014 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_LICENSE_HEADER_START@
+.\"
+.\" Portions Copyright (c) 2003-2010 Apple 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.
+.\"
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.\"
+.Dd September 3, 2008
+.Dt notify 3
+.Os "Mac OS X"
+.Sh NAME
+.Nm notify_post ,
+.Nm notify_register_check ,
+.Nm notify_register_dispatch ,
+.Nm notify_register_signal ,
+.Nm notify_register_mach_port ,
+.Nm notify_register_file_descriptor ,
+.Nm notify_check ,
+.Nm notify_get_state ,
+.Nm notify_set_state ,
+.Nm notify_suspend ,
+.Nm notify_resume ,
+.Nm notify_cancel ,
+.Nm notify_is_valid_token
+.Nd event distribution functions
+.Sh SYNOPSIS
+.Fd #include <notify.h>
+.Ft uint32_t
+.Fn notify_post "const char *name"
+.Ft uint32_t
+.Fn notify_register_check "const char *name, int *out_token"
+.Ft uint32_t
+.Fn notify_register_dispatch "const char *name, int *out_token" "dispatch_queue_t queue" "notify_handler_t handler"
+.Ft uint32_t
+.Fn notify_register_signal "const char *name, int sig, int *out_token"
+.Ft uint32_t
+.Fn notify_register_mach_port "const char *name, mach_port_t *notify_port, int flags, int *out_token"
+.Ft uint32_t
+.Fn notify_register_file_descriptor "const char *name, int *notify_fd, int flags, int *out_token"
+.Ft uint32_t
+.Fn notify_check "int token, int *check"
+.Ft uint32_t
+.Fn notify_set_state "int token, uint64_t state"
+.Ft uint32_t
+.Fn notify_get_state "int token, uint64_t *state"
+.Ft uint32_t
+.Fn notify_suspend "int token"
+.Ft uint32_t
+.Fn notify_resume "int token"
+.Ft uint32_t
+.Fn notify_cancel "int token"
+.Ft bool
+.Fn notify_is_valid_token "int val"
+.Sh DESCRIPTION
+These routines allow processes to exchange stateless notification events.
+Processes post notifications to a single system-wide notification server,
+which then distributes notifications to client processes that have
+registered to receive those notifications, including processes run by
+other users.
+.Pp
+Notifications are associated with names in a namespace shared by all 
+clients of the system.
+Clients may post notifications for names, and
+may monitor names for posted notifications.
+Clients may request
+notification delivery by a number of different methods.
+.Pp
+Clients desiring to monitor names in the notification system must
+register with the system, providing a name and other information
+required for the desired notification delivery method.
+Clients are
+given an integer token representing the registration.
+Token values are zero or positive integers.
+.Pp
+The kernel provides limited queues for mach message and file descriptor messages.
+It is important to make sure that clients read mach ports and file descriptors frequently
+to prevent messages from being lost due to resource limitations.
+Clients that use signal-based notification should be aware that signals
+are not delivered to a process while it is running in a signal handler.
+This may affect the delivery of signals in close succession.
+.Pp
+Notifications may be coalesced in some cases.
+Multiple events posted
+for a name in rapid succession may result in a single notification sent
+to clients registered for notification for that name.
+Clients checking
+for changes using the notify_check() routine cannot determine if
+more than one event has been posted since a previous call to 
+notify_check() for that name.
+.Pp
+"False positives" may occur in notify_check() when used with a token
+generated by notify_register_check() due to implementation constraints.
+This behavior may vary in future releases.
+.Ss notify_post
+This routine causes the system to send a notification for the given 
+name to all clients that have registered for notifications of this name.
+This is the only API required for an application that only produces
+notifications. 
+.Ss notify_register_check
+Registers for passive notification for the given name.
+The routine generates
+a token that may be used with the
+.Fn notify_check
+routine to check if any notifications have been posted for the name.
+The check is implemented using a shared memory scheme, making the check 
+very fast and efficient.
+The implementation has a limited amount
+of shared memory, so developers are encouraged to use this mechanism
+sparingly.
+It is also important to release the resources consumed
+by a registration with 
+.Fn notify_cancel
+when they are no longer required by the application.
+.Ss notify_register_dispatch
+registers a callback handler in the form of a block which will be
+dispatched to the queue when a notification for the given name is
+received.  This is a convenient way to register callbacks without any
+management of file descriptors, mach ports, or signals on the part of
+the application.  The given queue is retained by the system for the
+lifetime of the notification.  Use
+.Fn notify_cancel
+to release the notification and its reference to the queue.
+.Ss notify_register_signal
+registers a client for notification delivery via a signal.
+This fits
+well with the design of many UNIX daemons that use a signal such as SIGHUP
+to reinitialize of reset internal state information.
+Clients may use the
+registration token generated by this routine to check for notifications using
+.Fn notify_check .
+This allows the application to determine if a signal was received as the
+result of a notification, or if the signal was generated by some other source.
+It also permits the application that registers for signal notification for
+multiple names to determine which name was associated with the notification.
+.Ss notify_register_mach_port
+registers a client for notification delivery via mach messaging.
+Notifications are delivered by an empty message sent to a mach port.
+By default, a new port is created by a call to this routine.
+A mach port
+previously created by a call to this routine may be used for notifications
+if a pointer to that port is passed in to the routine and NOTIFY_REUSE is
+set in the flags parameter.
+The notification service must be able to extract
+send rights to the port.
+.Pp
+Note that the kernel limits the size of the message queue for any port.
+If it is important that notifications should not be lost due to queue
+overflow, clients should service messages quickly, and be cautious in
+using the same port for notifications for more than one name.
+.Pp
+A notification message has an empty message body.
+The msgh_id field
+in the mach message header will have the value of the notification
+token.
+If a port is reused for multiple notification registrations,
+the msgh_id value may be used to determine which name generated
+the notification.
+.Ss notify_register_file_descriptor
+Register for notification by a write to a file descriptor. 
+.Pp
+By default, a new file descriptor is created and a pointer to it
+is returned as the value of the "notify_fd" parameter.
+A file descriptor
+created by a previous call to this routine may be used for notifications
+if a pointer to that file descriptor is passed in to the routine and
+NOTIFY_REUSE is set in the flags parameter. 
+.Pp
+Note that the kernel limits the buffer space for queued writes on a
+file descriptor.
+If it is important that notifications should not be
+lost due to queue overflow, clients should service messages quickly,
+and be cautious in using the same file descriptor for notifications
+for more than one name.
+.Pp
+Notifications are delivered by an integer value written to the
+file descriptor.
+The value is sent in network byte order.
+When converted to host byte order, for example by using
+.Fn ntohl ,
+it will match the notification token
+for which the notification was generated.
+.Ss notify_check
+Checks if any notifications have been posted for a name.
+The output
+parameter "check" is set to 0 for false, 1 for true.
+A true indication is
+returned the first time notify_check is called for a token.
+Subsequent calls
+give a true indication when notifications have been posted for the name
+associated with the notification token.
+.Pp
+.Fn notify_check
+may be used with any notification token produced by any of the notification
+registration routines.
+A fast check based on a shared memory implementation
+is used when the token was generated by
+.Fn notify_register_check .
+Other tokens are checked by a call to the notification server.
+.Ss notify_set_state
+Set a 64-bit unsigned integer variable associated with a token.
+.Pp
+Each registered notification key has an associated 64-bit integer variable,
+which may be set using this routine and examined using the
+.Fn notify_get_state
+routine.
+The state variable is free to be used by clients of the notification API.
+It may be used to synchronize state information between cooperating processes or threads.
+(Available in Mac OS X 10.5 or later.)
+.Ss notify_get_state
+Get the 64-bit unsigned integer value associated with a token.
+The default value of a state variable is zero.
+(Available in Mac OS X 10.5 or later.)
+.Ss notify_suspend
+Suspends delivery of notifications for a notification token.
+Any notifications corresponding to a token that are posted while it is suspended
+will be coalesced, and pended until notifications are resumed using
+.Fn notify_resume .
+.Pp
+Calls to
+.Fn notify_suspend
+may be nested.
+Notifications will resume only when a matching number of calls are made to
+.Fn notify_resume .
+.Ss notify_resume
+Removes one level of suspension for a token previously suspended by a call to
+.Fn notify_suspend .
+When resumed, notifications will be delivered normally.
+A single notification will be generated if any notifications were pended while the token was suspended.
+.Ss notify_cancel
+Cancel notification and free resources associated with a notification
+token.
+Mach ports and file descriptor associated with a token are released
+(deallocated or closed) when all registration tokens associated with 
+the port or file descriptor have been cancelled.
+.Pp
+.Ss notify_is_valid_token
+Determines if an integer value is valid for a current registration.
+Negative integers are never valid.
+A positive or zero value is valid if the current process has a registration associated with the given value.
+.Sh NAMESPACE CONVENTIONS
+Names in the namespace must be NULL-terminated.
+Names should be encoded as UTF-8 strings.
+.Pp
+The namespace supported by the system is unstructured, but users of
+this API are highly encouraged to follow the reverse-ICANN domain
+name convention used for Java package names and for System Preferences
+on Mac OS X.
+For example, "com.mydomain.example.event".
+.Pp
+Apple reserves the portion
+of the namespace prefixed by "com.apple.".
+This policy is not 
+enforced in the current implementation, but may be in the future.
+.Pp
+Names in the space "user.uid.UID", where UID is a numeric user ID number
+are reserved for processes with that UID.
+Names in this protected space may only be accessed or modified by processes
+with the effective UID specified as the UID in the name.
+The name "user.uid.UID" is protected for the given UID, as are any
+names of the form "user.uid.UID.<sub-path>". 
+In the latter case, the name must have a dot character following the UID.
+.Pp
+Third party developers are encouraged to choose a prefix for names
+that will avoid conflicts in the shared namespace.
+.Pp
+The portion of the namespace prefixed by the string "self." is set aside
+for private use by applications.
+That is, each client may use that part
+of the namespace for intra-process notifications.
+These notifications 
+are private to each individual process and are not propagated between
+processes.
+.Sh USAGE EXAMPLES
+A notification producer.
+.Pp
+    #include <notify.h>
+    ...
+.Pp
+    notify_post("com.eg.random.event");
+.Pp
+A client using notify_check() to determine when to invalidate a cache.
+.Pp
+    #include <stdio.h>
+    #include <stdlib.h>
+    #include <notify.h>
+.Pp
+    int
+    main(int argc, char *argv[])
+    {
+        uint32_t status;
+        int token, check;
+.Pp
+        status = notify_register_check("com.eg.update", &token);
+        if (status != NOTIFY_STATUS_OK)
+        {
+           fprintf(stderr, "registration failed (%u)\\n", status);
+           exit(status);
+        }
+.Pp
+        build_my_cache();
+.Pp
+        ...
+.Pp
+        status = notify_check(token, &check);
+        if ((status == NOTIFY_STATUS_OK) && (check != 0))
+        {
+           /* An update has occurred - invalidate the cache */
+           reset_my_cache();
+        }
+.Pp
+        ...
+.Pp
+A client using file descriptor notifications.
+.Pp
+    #include <stdio.h>
+    #include <stdlib.h>
+    #include <string.h>
+    #include <errno.h>
+    #include <sys/types.h>
+    #include <sys/time.h>
+    #include <unistd.h>
+    #include <notify.h>
+.Pp
+    int
+    main(int argc, char *argv[])
+    {
+        uint32_t status;
+        int nf, rtoken, qtoken, t, ret;
+        fd_set readfds;
+.Pp
+        status = notify_register_file_descriptor("com.eg.random.event",
+           &nf, 0, &rtoken);
+        if (status != NOTIFY_STATUS_OK)
+        {
+           fprintf(stderr, "registration failed (%u)\\n", status);
+           exit(status);
+        }
+.Pp
+        status = notify_register_file_descriptor("com.eg.random.quit",
+            &nf, NOTIFY_REUSE, &qtoken);
+        if (status != NOTIFY_STATUS_OK)
+        {
+           fprintf(stderr, "registration failed (%u)\\n", status);
+           exit(status);
+        }
+.Pp
+        FD_ZERO(&readfds);
+        FD_SET(nf, &readfds);
+.Pp
+        for (;;)
+        {
+           ret = select(nf+1, &readfds, NULL, NULL, NULL);
+           if (ret <= 0) continue;
+           if (!FD_ISSET(nf, &readfds)) continue;
+.Pp
+           status = read(nf, &t, sizeof(int));
+           if (status < 0)
+           {
+               perror("read");
+               break;
+           }
+.Pp
+           t = ntohl(t);
+.Pp
+           if (t == rtoken) printf("random event\\n");
+           else if (t == qtoken) break;
+        }
+.Pp
+        printf("shutting down\\n");
+        notify_cancel(rtoken);
+        notify_cancel(qtoken);
+        exit(0);
+    }
+.Pp
+A client using dispatch notifications.
+.Pp
+    #include <stdio.h>
+    #include <stdlib.h>
+    #include <notify.h>
+    #include <dispatch/dispatch.h>
+.Pp
+    int
+    main(void)
+    {
+        uint32_t status;
+        int token;
+.Pp
+        status = notify_register_dispatch("com.eg.random.event", &token,
+            dispatch_get_main_queue(), ^(int t) { 
+                printf("com.eg.random.event received!\\n"); });
+.Pp
+        dispatch_main();
+        exit(0);
+    }
+.Sh HISTORY
+These functions first appeared in
+Mac OS X 10.3.
+.Sh SEE ALSO
+.Xr ntohl 3 ,
+.Xr read 2 ,
+.Xr select 2 ,
+.Xr signal 3


Property changes on: trunk/lib/libnotify/notify.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify.h
===================================================================
--- trunk/lib/libnotify/notify.h	                        (rev 0)
+++ trunk/lib/libnotify/notify.h	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2003-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Portions Copyright (c) 2003-2010 Apple 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.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __NOTIFICATION_H__
+#define __NOTIFICATION_H__
+
+#include <stdbool.h>
+#include <sys/cdefs.h>
+#include <stdint.h>
+#include <mach/message.h>
+#include <Availability.h>
+#ifdef __BLOCKS__
+#include <dispatch/dispatch.h>
+#endif /* __BLOCKS__ */
+
+/*! @header
+ * These routines allow processes to exchange stateless notification events.
+ * Processes post notifications to a single system-wide notification server,
+ * which then distributes notifications to client processes that have
+ * registered to receive those notifications, including processes run by
+ * other users.
+ *
+ * Notifications are associated with names in a namespace shared by all
+ * clients of the system.  Clients may post notifications for names, and
+ * may monitor names for posted notifications.  Clients may request
+ * notification delivery by a number of different methods.
+ *
+ * Clients desiring to monitor names in the notification system must
+ * register with the system, providing a name and other information
+ * required for the desired notification delivery method.  Clients are
+ * given an integer token representing the registration.
+ *
+ * Note that the kernel provides limited queues for mach message and file
+ * descriptor messages.  It is important to make sure that clients read
+ * mach ports and file descriptors frequently to prevent messages from
+ * being lost due to resource limitations.  Clients that use signal-based
+ * notification should be aware that signals are not delivered to
+ * a process while it is running in a signal handler.  This may affect
+ * the delivery of signals in close succession.
+ *
+ * Notifications may be coalesced in some cases.  Multiple events posted
+ * for a name in rapid succession may result in a single notification sent
+ * to clients registered for notification for that name.  Clients checking
+ * for changes using the notify_check() routine cannot determine if
+ * more than one event pas been posted since a previous call to 
+ * notify_check() for that name.
+ *
+ * "False positives" may occur in notify_check() when used with a token
+ * generated by notify_register_check() due to implementation constraints.
+ * This behavior may vary in future releases.  
+ *
+ * Synchronization between two processes may be achieved using the
+ * notify_set_state() and notify_get_state() routines.
+ */
+
+/*! @defineblock Status Codes
+ * Status codes returned by the API.
+ */
+#define NOTIFY_STATUS_OK 0
+#define NOTIFY_STATUS_INVALID_NAME 1
+#define NOTIFY_STATUS_INVALID_TOKEN 2
+#define NOTIFY_STATUS_INVALID_PORT 3
+#define NOTIFY_STATUS_INVALID_FILE 4
+#define NOTIFY_STATUS_INVALID_SIGNAL 5
+#define NOTIFY_STATUS_INVALID_REQUEST 6
+#define NOTIFY_STATUS_NOT_AUTHORIZED 7
+#define NOTIFY_STATUS_FAILED 1000000
+/*! @/defineblock */
+
+/*!
+ * Flag bits used for registration.
+ */
+#define NOTIFY_REUSE 0x00000001
+
+
+/*!
+ * Token values are zero or positive integers.
+ * NOTIFY_TOKEN_INVALID is useful as an initial value for
+ * a token value passed as an in/out parameter to one of
+ * the registration routines below.
+ */
+#define NOTIFY_TOKEN_INVALID -1
+
+__BEGIN_DECLS
+
+/*!
+ * Post a notification for a name.
+ *
+ * This is the only call that is required for a notification producer.
+ * Returns status.
+ */
+uint32_t notify_post(const char *name);
+
+
+#ifdef __BLOCKS__
+typedef void (^notify_handler_t)(int token);
+
+/*!
+ * @function   notify_register
+ * @abstract   Request notification delivery to a dispatch queue.
+ * @discussion When notifications are received by the process, the notify
+ *             subsystem will deliver the registered Block to the target
+ *             dispatch queue.  Notification blocks are not re-entrant,
+ *             and subsequent notification Blocks will not be delivered
+ *             for the same registration until the previous Block has
+ *             returned.
+ * @param name (input) The notification name.
+ * @param out_token (output) The registration token.
+ * @param queue (input) The dispatch queue to which the Block is submitted.
+ *              The dispatch queue is retained by the notify subsystem while
+ *              the notification is registered, and will be released when
+ *              notification is canceled.
+ * @param block (input) The Block to invoke on the dispatch queue in response
+ *              to a notification.  The notification token is passed to the
+ *              Block as an argument so that the callee can modify the state
+ *              of the notification or cancel the registration.
+ * @result Returns status.
+ */
+uint32_t notify_register_dispatch(const char *name, int *out_token, dispatch_queue_t queue, notify_handler_t handler)
+__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_3_2);
+#endif /* __BLOCKS__ */
+
+/*!
+ * Creates a registration token be used with notify_check(),
+ * but no active notifications will be delivered.
+ *
+ * @param name
+ *    (input) notification name
+ * @param out_token
+ *    (output) registration token
+ * @result Returns status.
+ */
+uint32_t notify_register_check(const char *name, int *out_token);
+
+/*!
+ * Request notification delivery by UNIX signal.
+ *
+ * A client may request signal notification for multiple names.  After a signal
+ * is delivered, the notify_check() routine may be called with each notification 
+ * token to determine which name (if any) generated the signal notification.
+ *
+ * @param name (input) notification name
+ * @param sig (input) signal number (see signal(3))
+ * @param out_token (output) notification token
+ * @result Returns status.
+ */
+uint32_t notify_register_signal(const char *name, int sig, int *out_token);
+
+/*!
+ * Request notification by mach message.  
+ *
+ * Notifications are delivered by an empty message sent to a mach port.
+ * By default, a new port is allocated and a pointer to it is returned
+ * as the value of "notify_port".  A mach port previously returned by a 
+ * call to this routine may be used for notifications if a pointer to that
+ * port is passed in to the routine and NOTIFY_REUSE is set in the flags
+ * parameter.  The notification service must be able to extract send
+ * rights to the port.
+ *
+ * Note that the kernel limits the size of the message queue for any port.
+ * If it is important that notifications should not be lost due to queue
+ * overflow, clients should service messages quickly, and be careful about
+ * using the same port for notifications for more than one name.
+ *
+ * A notification message has an empty message body.  The msgh_id field
+ * in the mach message header will have the value of the notification
+ * token.  If a port is reused for multiple notification registrations,
+ * the msgh_id value may be used to determine which name generated
+ * the notification.
+ *
+ * @param name
+ *     (input) notification name
+ * @param  out_token
+ *     (output) notification token
+ * @param  notify_port
+ *     (input/output) pointer to a mach port
+ * @result Returns status.
+ */
+uint32_t notify_register_mach_port(const char *name, mach_port_t *notify_port, int flags, int *out_token);
+
+/*
+ * Request notification by a write to a file descriptor. 
+ *
+ * Notifications are delivered by a write to a file descriptor.
+ * By default, a new file descriptor is created and a pointer to it
+ * is returned as the value of "notify_fd".  A file descriptor created
+ * by a previous call to this routine may be used for notifications if
+ * a pointer to that file descriptor is passed in to the routine and
+ * NOTIFY_REUSE is set in the flags parameter. 
+ *
+ * Note that the kernel limits the buffer space for queued writes on a
+ * file descriptor.  If it is important that notifications should not be
+ * lost due to queue overflow, clients should service messages quickly,
+ * and be careful about using the same file descriptor for notifications
+ * for more than one name.
+ *
+ * Notifications are delivered by an integer value written to the
+ * file descriptor.  The value will match the notification token
+ * for which the notification was generated.
+ *
+ * @param name
+ *     (input) notification name
+ * @param out_token
+ *     (output) notification token
+ * @param notify_fd
+ *     (input/output) pointer to a file descriptor
+ * @result Returns status.
+ */
+uint32_t notify_register_file_descriptor(const char *name, int *notify_fd, int flags, int *out_token);
+
+/*!
+ * Check if any notifications have been posted.
+ *
+ * Output parameter check is set to 0 for false, 1 for true.  Returns status.
+ * check is set to true the first time notify_check is called for a token.
+ * Subsequent calls set check to true when notifications have been posted for
+ * the name associated with the notification token.  This routine is independent
+ * of notify_post().  That is, check will be true if an application calls
+ * notify_post() for a name and then calls notify_check() for a token associated
+ * with that name.
+ *
+ * @param token
+ *     (input)notification token
+ * @param check
+ *     (output) true/false indication
+ * @result Returns status.
+ */
+uint32_t notify_check(int token, int *check);
+
+/*!
+ * Cancel notification and free resources associated with a notification
+ * token.  Mach ports and file descriptor associated with a token are released 
+ * (deallocated or closed) when all registration tokens associated with 
+ * the port or file descriptor have been cancelled.
+ *
+ * @param token
+ *     (input) notification token
+ * @result Returns status.
+ */
+uint32_t notify_cancel(int token);
+
+/*!
+ * Suspend delivery of notifications for a token. Notifications for this token will be
+ * pended and coalesced, then delivered following a matching call to notify_resume.
+ * Calls to notify_suspend may be nested.  Notifications remain suspended until
+ * an equal number of calls have been made to notify_resume.
+ *
+ * @param token
+ *     (input) notification token
+ * @result Returns status.
+ */
+uint32_t notify_suspend(int token)
+__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0);
+
+/*!
+ * Removes one level of suspension for a token previously suspended
+ * by a call to notify_suspend.  Notifications will resume when a matching
+ * call to notify_resume is made for each previous call to notify_suspend.
+ * Notifications posted while a token is suspended are coalesced into
+ * a single notification sent following a resumption.
+ *
+ * @param token
+ *     (input) notification token
+ * @result Returns status.
+ */
+uint32_t notify_resume(int token)
+__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0);
+
+/*!
+ * Set or get a state value associated with a notification token.
+ * Each key in the notification namespace has an associated integer value available
+ * for use by clients as for application-specific purposes.  A common usage is to 
+ * allow two processes or threads to synchronize their activities.  For example, a
+ * server process may need send a notification when a resource becomes available.
+ * A client process can register for the notification, but when it starts up it will
+ * not know whether the resource is available.  The server can set the state value,
+ * and the client can check the value at startup time to synchronize with the server.
+ *
+ * Set the 64-bit integer state value.
+ *
+ * @param token
+ *     (input) notification token
+ * @param state64
+ *     (input) 64-bit unsigned integer value
+ * @result Returns status.
+ */
+uint32_t notify_set_state(int token, uint64_t state64)
+__OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
+
+/*!
+ * Get the 64-bit integer state value.
+ *
+ * @param token
+ *     (input) notification token
+ * @param state64
+ *     (output) 64-bit unsigned integer value
+ * @result Returns status.
+ */
+uint32_t notify_get_state(int token, uint64_t *state64)
+__OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
+
+/*!
+ * Determine if a token is valid (currently registered).
+ * Negative integer values are always invalid.  Positive or
+ * zero values are valid only if they are associated with an
+ * existing registratiom.
+ *
+ * @param val
+ *     (input) integer value
+ * @result Returns true if the value is a valid token, false otherwise.
+ */
+bool notify_is_valid_token(int val)
+__OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0);
+
+__END_DECLS
+
+#endif /* __NOTIFICATION_H__ */


Property changes on: trunk/lib/libnotify/notify.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_cancel.3
===================================================================
--- trunk/lib/libnotify/notify_cancel.3	                        (rev 0)
+++ trunk/lib/libnotify/notify_cancel.3	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1 @@
+.so man3/notify.3


Property changes on: trunk/lib/libnotify/notify_cancel.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_check.3
===================================================================
--- trunk/lib/libnotify/notify_check.3	                        (rev 0)
+++ trunk/lib/libnotify/notify_check.3	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1 @@
+.so man3/notify.3


Property changes on: trunk/lib/libnotify/notify_check.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_client.c
===================================================================
--- trunk/lib/libnotify/notify_client.c	                        (rev 0)
+++ trunk/lib/libnotify/notify_client.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,2493 @@
+/*
+ * Copyright (c) 2003-2012 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 <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <sys/ipc.h>
+#include <sys/signal.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+#include <sys/time.h>
+#include <bootstrap_priv.h>
+#include <errno.h>
+#include <pthread.h>
+#include <TargetConditionals.h>
+#include <AvailabilityMacros.h>
+#ifdef __FreeBSD__
+#include <atomic_compat.h>
+#else
+#include <libkern/OSAtomic.h>
+#endif
+#include <Block.h>
+#include <dispatch/dispatch.h>
+#include <dispatch/private.h>
+#include <_simple.h>
+
+#include "libnotify.h"
+
+#include "notify.h"
+#include "notify_internal.h"
+#include "notify_ipc.h"
+#include "notify_private.h"
+
+#define INITIAL_TOKEN_ID 0
+
+// <rdar://problem/10385540>
+WEAK_IMPORT_ATTRIBUTE bool _dispatch_is_multithreaded(void);
+
+#define EVENT_INIT       0
+#define EVENT_REGEN      1
+
+#define SELF_PREFIX "self."
+#define SELF_PREFIX_LEN 5
+
+#define COMMON_SELF_PORT_KEY "self.com.apple.system.notify.common"
+
+#define MULTIPLE_REGISTRATION_WARNING_TRIGGER 20
+
+extern uint32_t _notify_lib_peek(notify_state_t *ns, pid_t pid, int token, int *val);
+extern int *_notify_lib_check_addr(notify_state_t *ns, pid_t pid, int token);
+
+#define CLIENT_TOKEN_TABLE_SIZE 256
+
+#define NID_UNSET 0xffffffffffffffffL
+#define NID_CALLED_ONCE 0xfffffffffffffffeL
+
+#define NO_LOCK 1
+
+typedef struct
+{
+	uint32_t refcount;
+	uint64_t name_id;
+} name_table_node_t;
+
+typedef struct
+{
+	uint32_t refcount;
+	const char *name;
+	size_t namelen;
+	name_table_node_t *name_node;
+	uint32_t token;
+	uint32_t slot;
+	uint32_t val;
+	uint32_t flags;
+	int fd;
+	int signal;
+	mach_port_t mp;
+	uint32_t client_id;
+	uint64_t set_state_time;
+	uint64_t set_state_val;
+	char * path;
+	int path_flags;
+	dispatch_queue_t queue;
+	notify_handler_t block;
+} token_table_node_t;
+
+/* FORWARD */
+static void _notify_lib_regenerate(int src);
+static void notify_retain_mach_port(mach_port_t mp, int mine);
+static void _notify_dispatch_handle(mach_port_t port);
+static notify_state_t *_notify_lib_self_state();
+
+#if TARGET_IPHONE_SIMULATOR
+const char *
+_notify_shm_id()
+{
+	static dispatch_once_t once;
+	static char *shm_id;
+
+	dispatch_once(&once, ^{
+		// According to documentation, our shm_id must be no more than 31 characters long
+		// but in practice, even 31 characters is too long (<rdar://problem/16860882>),
+		// so we jump through some hoops to make a smaller string based on our UDID.
+		const char *udid = getenv("SIMULATOR_UDID");
+		if (udid && strlen(udid) == 36) {
+			char scratch[34]; // 32 characters, 2 NUL
+
+			// 01234567890123456789012345678901234567890
+			// UUUUUUUU-UUUU-UUUU-LLLL-LLLLLLLLLLLL
+			memcpy(scratch, udid, 8);
+			memcpy(scratch+8, udid+9, 4);
+			memcpy(scratch+12, udid+14, 4);
+			scratch[16] = '\0';
+
+			memcpy(scratch+17, udid+19, 4);
+			memcpy(scratch+21, udid+24, 12);
+			scratch[33] = '\0';
+
+			// If the input is invalid, these will end up being undefined
+			// values, but they'll still be values we can use.
+			uint64_t upper = strtoull(scratch, NULL, 16);
+			uint64_t lower = strtoull(scratch + 17, NULL, 16);
+
+			const char *c64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+			scratch[0]  = c64[(upper >> 57) & 0xf];
+			scratch[1]  = c64[(upper >> 50) & 0xf];
+			scratch[2]  = c64[(upper >> 43) & 0xf];
+			scratch[3]  = c64[(upper >> 36) & 0xf];
+			scratch[4]  = c64[(upper >> 29) & 0xf];
+			scratch[5]  = c64[(upper >> 22) & 0xf];
+			scratch[6]  = c64[(upper >> 15) & 0xf];
+			scratch[7]  = c64[(upper >>  8) & 0xf];
+			scratch[8]  = c64[(upper >>  1) & 0xf];
+			// Drop a bit on the floor, but that probably doesn't matter.  It does not need to be reversible
+
+			scratch[10] = c64[(lower >> 57) & 0xf];
+			scratch[11] = c64[(lower >> 50) & 0xf];
+			scratch[12] = c64[(lower >> 43) & 0xf];
+			scratch[13] = c64[(lower >> 36) & 0xf];
+			scratch[14] = c64[(lower >> 29) & 0xf];
+			scratch[15] = c64[(lower >> 22) & 0xf];
+			scratch[16] = c64[(lower >> 15) & 0xf];
+			scratch[17] = c64[(lower >>  8) & 0xf];
+			scratch[18] = c64[(lower >>  1) & 0xf];
+			// Drop a bit on the floor, but that probably doesn't matter.  It does not need to be reversible
+
+			scratch[19] = '\0';
+
+			asprintf(&shm_id, "sim.not.%s", scratch);
+			assert(shm_id);
+		}
+
+		if (!shm_id) {
+			shm_id = "apple.shm.notification_center";
+		}
+	});
+
+	return shm_id;
+}
+#endif
+
+static int
+shm_attach(uint32_t size)
+{
+	int32_t shmfd;
+	notify_globals_t globals = _notify_globals();
+
+	shmfd = shm_open(SHM_ID, O_RDONLY, 0);
+	if (shmfd == -1) return -1;
+
+	globals->shm_base = mmap(NULL, size, PROT_READ, MAP_SHARED, shmfd, 0);
+	close(shmfd);
+
+	if (globals->shm_base == (uint32_t *)-1) globals->shm_base = NULL;
+	if (globals->shm_base == NULL) return -1;
+
+	return 0;
+}
+
+#ifdef NOTDEF
+static void
+shm_detach(void)
+{
+	if (shm_base != NULL)
+	{
+		shmdt(shm_base);
+		shm_base = NULL;
+	}
+}
+#endif
+
+/*
+ * Initialization of global variables. Called once per process.
+ */
+void
+_notify_init_globals(void * /* notify_globals_t */ _globals)
+{
+	notify_globals_t globals = _globals;
+
+	pthread_mutex_init(&globals->notify_lock, NULL);
+	globals->token_id = INITIAL_TOKEN_ID;
+	globals->notify_common_token = -1;
+}
+
+#if !_NOTIFY_HAS_ALLOC_ONCE
+notify_globals_t
+_notify_globals_impl(void)
+{
+	static dispatch_once_t once;
+	static notify_globals_t globals;
+	dispatch_once(&once, ^{
+		globals = calloc(1, sizeof(struct notify_globals_s));
+		_notify_init_globals(globals);
+	});
+	return globals;
+}
+#endif
+
+/*
+ * _notify_lib_init is called for each new registration (event = EVENT_INIT).
+ * It is also called to re-initialize when the library has detected that
+ * notifyd has restarted (event = EVENT_REGEN).
+ */
+static uint32_t
+_notify_lib_init(uint32_t event)
+{
+	__block kern_return_t kstatus;
+	__block bool first = false;
+	int status, cid;
+	uint64_t state;
+
+	notify_globals_t globals = _notify_globals();
+
+	/* notifyd sets NOTIFY_OPT_DISABLE to avoid re-entrancy issues */
+	if (globals->client_opts & NOTIFY_OPT_DISABLE) return NOTIFY_STATUS_FAILED;
+
+	/* Look up the notifyd server port just once. */
+	kstatus = KERN_SUCCESS;
+	dispatch_once(&globals->notify_server_port_once, ^{
+		first = true;
+		kstatus = bootstrap_look_up2(bootstrap_port, NOTIFY_SERVICE_NAME, &globals->notify_server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
+	});
+
+	if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+
+	pthread_mutex_lock(&globals->notify_lock);
+
+	/*
+	 * _dispatch_is_multithreaded() tells us if it is safe to use dispatch queues for
+	 * a shared port for all registratios, and to watch for notifyd exiting / restarting.
+	 *
+	 * Note that _dispatch_is_multithreaded is weak imported, <rdar://problem/10385540>
+	 */
+	if (_dispatch_is_multithreaded)
+	{
+		if (_dispatch_is_multithreaded()) globals->client_opts |= (NOTIFY_OPT_DEMUX | NOTIFY_OPT_REGEN);
+	}
+
+	/*
+	 * Look up the server's PID and supported IPC version on the first call,
+	 * and on a regeneration event (when the server has restarted).
+	 */
+	if (first || (event == EVENT_REGEN))
+	{
+		pid_t last_pid = globals->notify_server_pid;
+
+		globals->notify_ipc_version = 0;
+		globals->notify_server_pid = 0;
+
+		kstatus = _notify_server_register_plain(globals->notify_server_port, (char*)NOTIFY_IPC_VERSION_NAME, NOTIFY_IPC_VERSION_NAME_LEN, &cid, &status);
+		if ((kstatus == KERN_SUCCESS) && (status == NOTIFY_STATUS_OK))
+		{
+			kstatus = _notify_server_get_state(globals->notify_server_port, cid, &state, &status);
+			if ((kstatus == KERN_SUCCESS) && (status == NOTIFY_STATUS_OK))
+			{
+				globals->notify_ipc_version = state;
+				state >>= 32;
+				globals->notify_server_pid = state;
+			}
+
+			_notify_server_cancel(globals->notify_server_port, cid, &status);
+
+			if ((last_pid == globals->notify_server_pid) && (event == EVENT_REGEN))
+			{
+				pthread_mutex_unlock(&globals->notify_lock);
+				return NOTIFY_STATUS_INVALID_REQUEST;
+			}
+		}
+
+		if (globals->server_proc_source != NULL)
+		{
+			dispatch_source_cancel(globals->server_proc_source);
+			dispatch_release(globals->server_proc_source);
+			globals->server_proc_source = NULL;
+		}
+	}
+
+	if (globals->notify_ipc_version < 2)
+	{
+		/* regen is not supported below version 2 */
+		globals->client_opts &= ~NOTIFY_OPT_REGEN;
+	}
+
+	/*
+	 * Create a source (DISPATCH_SOURCE_TYPE_PROC) to invoke _notify_lib_regenerate if notifyd restarts.
+	 * Available in IPC version 2.
+	 */
+	if ((globals->server_proc_source == NULL) && (globals->client_opts & NOTIFY_OPT_REGEN) && (globals->notify_server_pid != 0))
+	{
+		globals->server_proc_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, (uintptr_t)globals->notify_server_pid, DISPATCH_PROC_EXIT, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
+		dispatch_source_set_event_handler(globals->server_proc_source, ^{ _notify_lib_regenerate(1); });
+		dispatch_resume(globals->server_proc_source);
+	}
+
+	/*
+	 * Create the shared multiplex ports if NOTIFY_OPT_DEMUX is set.
+	 */
+	if ((globals->client_opts & NOTIFY_OPT_DEMUX) && (globals->notify_common_port == MACH_PORT_NULL))
+	{
+		kern_return_t kr;
+		task_t task = mach_task_self();
+
+		kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &globals->notify_common_port);
+		if (kr == KERN_SUCCESS)
+		{
+			globals->notify_dispatch_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, globals->notify_common_port, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
+			dispatch_source_set_event_handler(globals->notify_dispatch_source, ^{
+				notify_globals_t _globals = _notify_globals();
+				_notify_dispatch_handle(_globals->notify_common_port);
+			});
+			dispatch_source_set_cancel_handler(globals->notify_dispatch_source, ^{
+				task_t _task = mach_task_self();
+				notify_globals_t _globals = _notify_globals();
+				mach_port_mod_refs(_task, _globals->notify_common_port, MACH_PORT_RIGHT_RECEIVE, -1);
+			});
+			dispatch_resume(globals->notify_dispatch_source);
+		}
+	}
+
+	pthread_mutex_unlock(&globals->notify_lock);
+
+	if (globals->notify_common_port != MACH_PORT_NULL && (first || event == EVENT_REGEN))
+	{
+		/* register the common port with notifyd */
+		status = notify_register_mach_port(COMMON_PORT_KEY, &globals->notify_common_port, NOTIFY_REUSE, &globals->notify_common_token);
+	}
+
+	return NOTIFY_STATUS_OK;
+}
+
+/* Reset all internal state at fork */
+void
+_notify_fork_child(void)
+{
+	notify_globals_t globals = _notify_globals();
+
+	_notify_init_globals(globals);
+
+	/*
+	 * Expressly disable notify in the child side of a fork if it had
+	 * been initialized in the parent. Using notify in the child process
+	 * can lead to deadlock (see <rdar://problem/11498014>).
+	 *
+	 * Also disable notify in the forked child of a multi-threaded parent that
+	 * used dispatch, since notify will use dispatch, and that will blow up.
+	 * It's OK to make that check here by calling _dispatch_is_multithreaded(),
+	 * since we will actually be looking at the parent's state.
+	 */
+	if (globals->notify_server_port != MACH_PORT_NULL) globals->client_opts = NOTIFY_OPT_DISABLE;
+	if (_dispatch_is_multithreaded) // weak imported symbol
+	{
+		if (_dispatch_is_multithreaded()) globals->client_opts = NOTIFY_OPT_DISABLE;
+	}
+
+	globals->self_state = NULL;
+	globals->notify_server_port = MACH_PORT_NULL;
+	globals->notify_ipc_version = 0;
+	globals->notify_server_pid = 0;
+
+	globals->token_table = NULL;
+	globals->token_name_table = NULL;
+
+	globals->fd_count = 0;
+	globals->fd_clnt = NULL;
+	globals->fd_srv = NULL;
+	globals->fd_refcount = NULL;
+
+	globals->mp_count = 0;
+	globals->mp_list = NULL;
+	globals->mp_refcount = NULL;
+	globals->mp_mine = NULL;
+
+	globals->shm_base = NULL;
+}
+
+static uint32_t
+token_table_add(const char *name, size_t namelen, uint64_t nid, uint32_t token, uint32_t cid, uint32_t slot, uint32_t flags, int sig, int fd, mach_port_t mp, int lock)
+{
+	token_table_node_t *t;
+	name_table_node_t *n;
+	uint32_t warn_count = 0;
+	notify_globals_t globals = _notify_globals();
+
+	(void)sig;
+
+	dispatch_once(&globals->token_table_once, ^{
+		globals->token_table = _nc_table_new(CLIENT_TOKEN_TABLE_SIZE);
+		globals->token_name_table = _nc_table_new(CLIENT_TOKEN_TABLE_SIZE);
+	});
+
+	if (globals->token_table == NULL) return -1;
+	if (globals->token_name_table == NULL) return -1;
+	if (name == NULL) return -1;
+
+	t = (token_table_node_t *)calloc(1, sizeof(token_table_node_t));
+	if (t == NULL) return -1;
+
+	t->refcount = 1;
+
+	/* we will get t->name from the token_name_table */
+	t->name = NULL;
+
+	t->namelen = namelen;
+	t->token = token;
+	t->slot = slot;
+	t->val = 0;
+	t->flags = flags;
+	t->fd = fd;
+	t->mp = mp;
+	t->client_id = cid;
+
+	if (lock != NO_LOCK) pthread_mutex_lock(&globals->notify_lock);
+	_nc_table_insert_n(globals->token_table, t->token, t);
+
+	/* check if we have this name in the name table */
+	n = _nc_table_find_get_key(globals->token_name_table, name, &(t->name));
+	if (n == NULL)
+	{
+		char *copy_name = strdup(name);
+		if (copy_name == NULL)
+		{
+			free(t);
+			if (lock != NO_LOCK) pthread_mutex_unlock(&globals->notify_lock);
+			return -1;
+		}
+
+		t->name = (const char *)copy_name;
+
+		/* create a new name table node */
+		n = (name_table_node_t *)calloc(1, sizeof(name_table_node_t));
+		if (n != NULL)
+		{
+			n->refcount = 1;
+			n->name_id = nid;
+
+			/* the name table node "owns" the name */
+			_nc_table_insert_pass(globals->token_name_table, copy_name, n);
+			t->name_node = n;
+		}
+	}
+	else
+	{
+		/* this token retains the name table node */
+		t->name_node = n;
+		n->refcount++;
+
+		if ((n->refcount % MULTIPLE_REGISTRATION_WARNING_TRIGGER) == 0)
+		{
+			warn_count = n->refcount;
+		}
+	}
+
+	if (lock != NO_LOCK) pthread_mutex_unlock(&globals->notify_lock);
+
+	if (warn_count > 0)
+	{
+		char *msg;
+		asprintf(&msg, "notify name \"%s\" has been registered %d times - this may be a leak", name, warn_count);
+		// if (msg)
+		/// XXX	_simple_asl_log(ASL_LEVEL_WARNING, "com.apple.notify", msg);
+		free(msg);
+	}
+
+	return 0;
+}
+
+static token_table_node_t *
+token_table_find_retain(uint32_t token)
+{
+	token_table_node_t *t;
+	notify_globals_t globals = _notify_globals();
+
+	pthread_mutex_lock(&globals->notify_lock);
+
+	t = (token_table_node_t *)_nc_table_find_n(globals->token_table, token);
+	if (t != NULL) t->refcount++;
+
+	pthread_mutex_unlock(&globals->notify_lock);
+
+	return t;
+}
+
+static token_table_node_t *
+token_table_find_no_lock(uint32_t token)
+{
+	notify_globals_t globals = _notify_globals();
+	return (token_table_node_t *)_nc_table_find_n(globals->token_table, token);
+}
+
+static name_table_node_t *
+name_table_find_retain_no_lock(const char *name)
+{
+	name_table_node_t *n;
+	notify_globals_t globals = _notify_globals();
+
+	n = (name_table_node_t *)_nc_table_find(globals->token_name_table, name);
+	if (n != NULL) n->refcount++;
+
+	return n;
+}
+
+static void
+name_table_release_no_lock(const char *name)
+{
+	name_table_node_t *n;
+	notify_globals_t globals = _notify_globals();
+
+	n = (name_table_node_t *)_nc_table_find(globals->token_name_table, name);
+	if (n != NULL)
+	{
+		if (n->refcount > 0) n->refcount--;
+		if (n->refcount == 0)
+		{
+			_nc_table_delete(globals->token_name_table, name);
+			free(n);
+		}
+	}
+}
+
+static void
+name_table_set_nid(const char *name, uint64_t nid)
+{
+	name_table_node_t *n;
+	notify_globals_t globals = _notify_globals();
+
+	pthread_mutex_lock(&globals->notify_lock);
+
+	n = (name_table_node_t *)_nc_table_find(globals->token_name_table, name);
+	if (n != NULL) n->name_id = nid;
+
+	pthread_mutex_unlock(&globals->notify_lock);
+}
+
+static void
+_notify_lib_regenerate_token(token_table_node_t *t)
+{
+	uint32_t type;
+	int status, new_slot;
+	kern_return_t kstatus;
+	mach_port_t port;
+	uint64_t new_nid;
+	size_t pathlen;
+
+	if (t == NULL) return;
+	if (t->name == NULL) return;
+	if (t->flags & NOTIFY_FLAG_SELF) return;
+	if ((t->flags & NOTIFY_FLAG_REGEN) == 0) return;
+	if (!strcmp(t->name, COMMON_PORT_KEY)) return;
+
+	notify_globals_t globals = _notify_globals();
+
+	port = MACH_PORT_NULL;
+	if (t->flags & NOTIFY_TYPE_PORT)
+	{
+		port = globals->notify_common_port;
+	}
+
+	pathlen = 0;
+	if (t->path != NULL) pathlen = strlen(t->path);
+	type = t->flags & 0x000000ff;
+
+	kstatus = _notify_server_regenerate(globals->notify_server_port, (caddr_t)t->name, t->namelen, t->token, type, port, t->signal, t->slot, t->set_state_val, t->set_state_time, t->path, pathlen, t->path_flags, &new_slot, &new_nid, &status);
+
+	if (kstatus != KERN_SUCCESS) status = NOTIFY_STATUS_FAILED;
+	if (status != NOTIFY_STATUS_OK) return;
+
+	t->slot = new_slot;
+
+	/* reset the name_id in the name table node */
+	if (t->name_node != NULL) t->name_node->name_id = new_nid;
+}
+
+/*
+ * Invoked when server has died.
+ * Regenerates all registrations and state.
+ */
+static void
+_notify_lib_regenerate(int src)
+{
+	void *tt;
+	token_table_node_t *t;
+	notify_globals_t globals = _notify_globals();
+
+	(void)src;
+
+	if ((globals->client_opts & NOTIFY_OPT_REGEN) == 0) return;
+
+	/* _notify_lib_init returns an error if regeneration is unnecessary */
+	if (_notify_lib_init(EVENT_REGEN) == NOTIFY_STATUS_OK)
+	{
+		pthread_mutex_lock(&globals->notify_lock);
+
+		tt = _nc_table_traverse_start(globals->token_table);
+		while (tt != NULL)
+		{
+			t = _nc_table_traverse(globals->token_table, tt);
+			if (t == NULL) break;
+			_notify_lib_regenerate_token(t);
+		}
+
+		_nc_table_traverse_end(globals->token_table, tt);
+
+		pthread_mutex_unlock(&globals->notify_lock);
+	}
+}
+
+/*
+ * Regenerate if the server PID (shared memory slot 0) has changed.
+ */
+static inline void
+regenerate_check()
+{
+	notify_globals_t globals = _notify_globals();
+
+	if ((globals->client_opts & NOTIFY_OPT_REGEN) == 0) return;
+
+	if ((globals->shm_base != NULL) && (globals->shm_base[0] != (uint32_t)globals->notify_server_pid)) _notify_lib_regenerate(0);
+}
+
+/* notify_lock is required in notify_retain_file_descriptor */
+static void
+notify_retain_file_descriptor(int clnt, int srv)
+{
+	unsigned int i;
+	int x;
+	notify_globals_t globals = _notify_globals();
+
+	if (clnt < 0) return;
+	if (srv < 0) return;
+
+	pthread_mutex_lock(&globals->notify_lock);
+
+	x = -1;
+	for (i = 0; (i < globals->fd_count) && (x < 0); i++)
+	{
+		if (globals->fd_clnt[i] == clnt) x = i;
+	}
+
+	if (x >= 0)
+	{
+		globals->fd_refcount[x]++;
+		pthread_mutex_unlock(&globals->notify_lock);
+		return;
+	}
+
+	x = globals->fd_count;
+	globals->fd_count++;
+
+	if (x == 0)
+	{
+		globals->fd_clnt = (int *)calloc(1, sizeof(int));
+		globals->fd_srv = (int *)calloc(1, sizeof(int));
+		globals->fd_refcount = (int *)calloc(1, sizeof(int));
+	}
+	else
+	{
+		globals->fd_clnt = (int *)reallocf(globals->fd_clnt, globals->fd_count * sizeof(int));
+		globals->fd_srv = (int *)reallocf(globals->fd_srv, globals->fd_count * sizeof(int));
+		globals->fd_refcount = (int *)reallocf(globals->fd_refcount, globals->fd_count * sizeof(int));
+	}
+
+	if ((globals->fd_clnt == NULL) || (globals->fd_srv == NULL) || (globals->fd_refcount == NULL))
+	{
+		free(globals->fd_clnt);
+		free(globals->fd_srv);
+		free(globals->fd_refcount);
+		globals->fd_count = 0;
+	}
+	else
+	{
+		globals->fd_clnt[x] = clnt;
+		globals->fd_srv[x] = srv;
+		globals->fd_refcount[x] = 1;
+	}
+
+	pthread_mutex_unlock(&globals->notify_lock);
+}
+
+/* notify_lock is NOT required in notify_release_file_descriptor */
+static void
+notify_release_file_descriptor(int fd)
+{
+	unsigned int i;
+	int x, j;
+	notify_globals_t globals = _notify_globals();
+
+	if (fd < 0) return;
+
+	x = -1;
+	for (i = 0; (i < globals->fd_count) && (x < 0); i++)
+	{
+		if (globals->fd_clnt[i] == fd) x = i;
+	}
+
+	if (x < 0) return;
+
+	if (globals->fd_refcount[x] > 0) globals->fd_refcount[x]--;
+	if (globals->fd_refcount[x] > 0) return;
+
+	close(globals->fd_clnt[x]);
+	close(globals->fd_srv[x]);
+
+	if (globals->fd_count == 1)
+	{
+		free(globals->fd_clnt);
+		free(globals->fd_srv);
+		free(globals->fd_refcount);
+		globals->fd_count = 0;
+		return;
+	}
+
+	for (i = x + 1, j = x; i < globals->fd_count; i++, j++)
+	{
+		globals->fd_clnt[j] = globals->fd_clnt[i];
+		globals->fd_srv[j] = globals->fd_srv[i];
+		globals->fd_refcount[j] = globals->fd_refcount[i];
+	}
+
+	globals->fd_count--;
+
+	globals->fd_clnt = (int *)reallocf(globals->fd_clnt, globals->fd_count * sizeof(int));
+	globals->fd_srv = (int *)reallocf(globals->fd_srv, globals->fd_count * sizeof(int));
+	globals->fd_refcount = (int *)reallocf(globals->fd_refcount, globals->fd_count * sizeof(int));
+
+	if ((globals->fd_clnt == NULL) || (globals->fd_srv == NULL) || (globals->fd_refcount == NULL))
+	{
+		free(globals->fd_clnt);
+		free(globals->fd_srv);
+		free(globals->fd_refcount);
+		globals->fd_count = 0;
+	}
+}
+
+/* notify_lock is required in notify_retain_mach_port */
+static void
+notify_retain_mach_port(mach_port_t mp, int mine)
+{
+	unsigned int i;
+	int x;
+	notify_globals_t globals = _notify_globals();
+
+	if (mp == MACH_PORT_NULL) return;
+
+	pthread_mutex_lock(&globals->notify_lock);
+
+	x = -1;
+	for (i = 0; (i < globals->mp_count) && (x < 0); i++)
+	{
+		if (globals->mp_list[i] == mp) x = i;
+	}
+
+	if (x >= 0)
+	{
+		globals->mp_refcount[x]++;
+		pthread_mutex_unlock(&globals->notify_lock);
+		return;
+	}
+
+	x = globals->mp_count;
+	globals->mp_count++;
+
+	if (x == 0)
+	{
+		globals->mp_list = (mach_port_t *)calloc(1, sizeof(mach_port_t));
+		globals->mp_refcount = (int *)calloc(1, sizeof(int));
+		globals->mp_mine = (int *)calloc(1, sizeof(int));
+	}
+	else
+	{
+		globals->mp_list = (mach_port_t *)reallocf(globals->mp_list, globals->mp_count * sizeof(mach_port_t));
+		globals->mp_refcount = (int *)reallocf(globals->mp_refcount, globals->mp_count * sizeof(int));
+		globals->mp_mine = (int *)reallocf(globals->mp_mine, globals->mp_count * sizeof(int));
+	}
+
+	if ((globals->mp_list == NULL) || (globals->mp_refcount == NULL) || (globals->mp_mine == NULL))
+	{
+		if (globals->mp_list != NULL) free(globals->mp_list);
+		if (globals->mp_refcount != NULL) free(globals->mp_refcount);
+		if (globals->mp_mine != NULL) free(globals->mp_mine);
+		globals->mp_count = 0;
+	}
+	else
+	{
+		globals->mp_list[x] = mp;
+		globals->mp_refcount[x] = 1;
+		globals->mp_mine[x] = mine;
+	}
+
+	pthread_mutex_unlock(&globals->notify_lock);
+}
+
+/* notify_lock is NOT required in notify_release_mach_port */
+static void
+notify_release_mach_port(mach_port_t mp, uint32_t flags)
+{
+	unsigned int i;
+	int x;
+	notify_globals_t globals = _notify_globals();
+
+	if (mp == MACH_PORT_NULL) return;
+
+	x = -1;
+	for (i = 0; (i < globals->mp_count) && (x < 0); i++)
+	{
+		if (globals->mp_list[i] == mp) x = i;
+	}
+
+	if (x < 0) return;
+
+	if (globals->mp_refcount[x] > 0) globals->mp_refcount[x]--;
+	if (globals->mp_refcount[x] > 0) return;
+
+	if (globals->mp_mine[x] == 1)
+	{
+		mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_RECEIVE, -1);
+
+		/* release send right if this is a self notification */
+		if (flags & NOTIFY_FLAG_SELF) mach_port_deallocate(mach_task_self(), mp);
+	}
+
+	if (flags & NOTIFY_FLAG_RELEASE_SEND)
+	{
+		/* multiplexed registration holds a send right in Libnotify */
+		mach_port_deallocate(mach_task_self(), mp);
+	}
+
+	if (globals->mp_count == 1)
+	{
+		if (globals->mp_list != NULL) free(globals->mp_list);
+		if (globals->mp_refcount != NULL) free(globals->mp_refcount);
+		if (globals->mp_mine != NULL) free(globals->mp_mine);
+		globals->mp_count = 0;
+		return;
+	}
+
+	for (i = x + 1; i < globals->mp_count; i++)
+	{
+		globals->mp_list[i - 1] = globals->mp_list[i];
+		globals->mp_refcount[i - 1] = globals->mp_refcount[i];
+		globals->mp_mine[i - 1] = globals->mp_mine[i];
+	}
+
+	globals->mp_count--;
+
+	globals->mp_list = (mach_port_t *)reallocf(globals->mp_list, globals->mp_count * sizeof(mach_port_t));
+	globals->mp_refcount = (int *)reallocf(globals->mp_refcount, globals->mp_count * sizeof(int));
+	globals->mp_mine = (int *)reallocf(globals->mp_mine, globals->mp_count * sizeof(int));
+
+	if ((globals->mp_list == NULL) || (globals->mp_refcount == NULL) || (globals->mp_mine == NULL))
+	{
+		if (globals->mp_list != NULL) free(globals->mp_list);
+		if (globals->mp_refcount != NULL) free(globals->mp_refcount);
+		if (globals->mp_mine != NULL) free(globals->mp_mine);
+		globals->mp_count = 0;
+	}
+}
+
+static void
+token_table_release_no_lock(token_table_node_t *t)
+{
+	notify_globals_t globals = _notify_globals();
+
+	if (t == NULL) return;
+
+	if (t->refcount > 0) t->refcount--;
+	if (t->refcount > 0) return;
+
+	notify_release_file_descriptor(t->fd);
+	notify_release_mach_port(t->mp, t->flags);
+
+	if (t->block != NULL)
+	{
+		dispatch_async_f(t->queue, t->block, (dispatch_function_t)_Block_release);
+	}
+
+	t->block = NULL;
+
+	if (t->queue != NULL) dispatch_release(t->queue);
+	t->queue = NULL;
+
+	_nc_table_delete_n(globals->token_table, t->token);
+	name_table_release_no_lock(t->name);
+
+	free(t->path);
+	free(t);
+}
+
+static void
+token_table_release(token_table_node_t *t)
+{
+	notify_globals_t globals = _notify_globals();
+
+	pthread_mutex_lock(&globals->notify_lock);
+	token_table_release_no_lock(t);
+	pthread_mutex_unlock(&globals->notify_lock);
+}
+
+static notify_state_t *
+_notify_lib_self_state()
+{
+	notify_globals_t globals = _notify_globals();
+
+	dispatch_once(&globals->self_state_once, ^{
+		globals->self_state = _notify_lib_notify_state_new(NOTIFY_STATE_USE_LOCKS, 0);
+	});
+
+	return globals->self_state;
+}
+
+/* SPI */
+void
+notify_set_options(uint32_t opts)
+{
+	notify_globals_t globals = _notify_globals();
+
+	/* NOTIFY_OPT_DISABLE can be unset with NOTIFY_OPT_ENABLE */
+	if (globals->client_opts & NOTIFY_OPT_DISABLE)
+	{
+		if ((opts & NOTIFY_OPT_ENABLE) == 0) return;
+
+		/* re-enable by swapping in the saved server port and saved opts*/
+		pthread_mutex_lock(&globals->notify_lock);
+
+		globals->client_opts = globals->saved_opts;
+		globals->notify_server_port = globals->saved_server_port;
+
+		pthread_mutex_unlock(&globals->notify_lock);
+		return;
+	}
+
+	/*
+	 * A client can disable the library even if the server port has already been fetched.
+	 * Note that this could race with another thread making a Libnotify call.
+	 */
+	if (opts & NOTIFY_OPT_DISABLE)
+	{
+		pthread_mutex_lock(&globals->notify_lock);
+
+		globals->saved_opts = globals->client_opts;
+		globals->client_opts = NOTIFY_OPT_DISABLE;
+
+		globals->saved_server_port = globals->notify_server_port;
+		globals->notify_server_port = MACH_PORT_NULL;
+
+		pthread_mutex_unlock(&globals->notify_lock);
+		return;
+	}
+
+	globals->client_opts = opts;
+
+	/* call _notify_lib_init to create ports / dispatch sources as required */
+	_notify_lib_init(EVENT_INIT);
+}
+
+/*
+ * PUBLIC API
+ */
+
+/*
+ * notify_post is a very simple API, but the implementation is
+ * more complex to try to optimize the time it takes.
+ *
+ * The server - notifyd - keeps a unique ID number for each key
+ * in the namespace.  Although it's reasonably fast to call
+ * _notify_server_post_4 (a MIG simpleroutine), the MIG call
+ * allocates VM and copies the name string.  It's much faster to
+ * call using the ID number.  The problem is mapping from name to
+ * ID number.  The token table keeps track of all registered names
+ * (in the client), but the registration calls are simpleroutines,
+ * except for notify_register_check.  notify_register_check saves
+ * the name ID in the token table, but the other routines set it
+ * to NID_UNSET.
+ *
+ * In notify_post, we check if the name is known.  If it is not,
+ * then the client is doing a "cold call".  There may be no
+ * clients for this name anywhere on the system.  In this case
+ * we simply send the name.  We take the allocate/copy cost, but
+ * the latency is still not too bad since we use a simpleroutine.
+ *
+ * If the name in registered and the ID number is known, we send
+ * the ID using a simpleroutine.  This is very fast.
+ *
+ * If the name is registered but the ID number is NID_UNSET, we
+ * send the name (as in a "cold call".  It *might* just be that
+ * this client process just posts once, and we don't want to incur
+ * any addition cost.  The ID number is reset to NID_CALLED_ONCE.
+ *
+ * If the client posts the same name again (the ID number is
+ * NID_CALLED_ONCE, we do a synchronous call to notifyd, sending
+ * the name string and getting back the name ID, whcih we save
+ * in the token table.  This is simply a zero/one/many heuristic:
+ * If the client posts the same name more than once, we make the
+ * guess that it's going to do it more frequently, and it's worth
+ * the time it takes to fetch the ID from notifyd.
+ */
+uint32_t
+notify_post(const char *name)
+{
+	notify_state_t *ns_self;
+	kern_return_t kstatus;
+	uint32_t status;
+	size_t namelen = 0;
+	name_table_node_t *n;
+	uint64_t nid = UINT64_MAX;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
+	{
+		ns_self = _notify_lib_self_state();
+		if (ns_self == NULL) return NOTIFY_STATUS_FAILED;
+		_notify_lib_post(ns_self, name, 0, 0);
+		return NOTIFY_STATUS_OK;
+	}
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0) return NOTIFY_STATUS_FAILED;
+	}
+
+	if (globals->notify_ipc_version == 0)
+	{
+		namelen = strlen(name);
+		kstatus = _notify_server_post(globals->notify_server_port, (caddr_t)name, namelen, (int32_t *)&status);
+		if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+		return status;
+	}
+
+	namelen = strlen(name);
+
+	/* Lock to prevent a race with notify cancel over the use of name IDs */
+	pthread_mutex_lock(&globals->notify_lock);
+
+	/* See if we have a name ID for this name. */
+	n = name_table_find_retain_no_lock(name);
+	if (n != NULL)
+	{
+		if (n->name_id == NID_UNSET)
+		{
+			/* First post goes using the name string. */
+			kstatus = _notify_server_post_4(globals->notify_server_port, (caddr_t)name, namelen);
+			if (kstatus != KERN_SUCCESS)
+			{
+				name_table_release_no_lock(name);
+				pthread_mutex_unlock(&globals->notify_lock);
+				return NOTIFY_STATUS_FAILED;
+			}
+
+			n->name_id = NID_CALLED_ONCE;
+			name_table_release_no_lock(name);
+			pthread_mutex_unlock(&globals->notify_lock);
+			return NOTIFY_STATUS_OK;
+		}
+		else if (n->name_id == NID_CALLED_ONCE)
+		{
+			/* Post and fetch the name ID.  Slow, but subsequent posts will be very fast. */
+			kstatus = _notify_server_post_2(globals->notify_server_port, (caddr_t)name, namelen, &nid, (int32_t *)&status);
+			if (kstatus != KERN_SUCCESS)
+			{
+				name_table_release_no_lock(name);
+				pthread_mutex_unlock(&globals->notify_lock);
+				return NOTIFY_STATUS_FAILED;
+			}
+
+			if (status == NOTIFY_STATUS_OK) n->name_id = nid;
+			name_table_release_no_lock(name);
+			pthread_mutex_unlock(&globals->notify_lock);
+			return status;
+		}
+		else
+		{
+			/* We have the name ID.  Do an async post using the name ID.  Very fast. */
+			kstatus = _notify_server_post_3(globals->notify_server_port, n->name_id);
+			name_table_release_no_lock(name);
+			pthread_mutex_unlock(&globals->notify_lock);
+			if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+			return NOTIFY_STATUS_OK;
+		}
+	}
+
+	pthread_mutex_unlock(&globals->notify_lock);
+
+	/* Do an async post using the name string. Fast (but not as fast as using name ID). */
+	kstatus = _notify_server_post_4(globals->notify_server_port, (caddr_t)name, namelen);
+	if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+	return NOTIFY_STATUS_OK;
+}
+
+uint32_t
+notify_set_owner(const char *name, uint32_t uid, uint32_t gid)
+{
+	notify_state_t *ns_self;
+	kern_return_t kstatus;
+	uint32_t status;
+	notify_globals_t globals = _notify_globals();
+
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
+	{
+		ns_self = _notify_lib_self_state();
+		if (ns_self == NULL) return NOTIFY_STATUS_FAILED;
+		status = _notify_lib_set_owner(ns_self, name, uid, gid);
+		return status;
+	}
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0) return NOTIFY_STATUS_FAILED;
+	}
+
+	kstatus = _notify_server_set_owner(globals->notify_server_port, (caddr_t)name, strlen(name), uid, gid, (int32_t *)&status);
+	if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+	return status;
+}
+
+uint32_t
+notify_get_owner(const char *name, uint32_t *uid, uint32_t *gid)
+{
+	notify_state_t *ns_self;
+	kern_return_t kstatus;
+	uint32_t status;
+	notify_globals_t globals = _notify_globals();
+
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
+	{
+		ns_self = _notify_lib_self_state();
+		if (ns_self == NULL) return NOTIFY_STATUS_FAILED;
+		status = _notify_lib_get_owner(ns_self, name, uid, gid);
+		return status;
+	}
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0) return NOTIFY_STATUS_FAILED;
+	}
+
+	kstatus = _notify_server_get_owner(globals->notify_server_port, (caddr_t)name, strlen(name), (int32_t *)uid, (int32_t *)gid, (int32_t *)&status);
+	if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+	return status;
+}
+
+uint32_t
+notify_set_access(const char *name, uint32_t access)
+{
+	notify_state_t *ns_self;
+	kern_return_t kstatus;
+	uint32_t status;
+	notify_globals_t globals = _notify_globals();
+
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
+	{
+		ns_self = _notify_lib_self_state();
+		if (ns_self == NULL) return NOTIFY_STATUS_FAILED;
+		status = _notify_lib_set_access(ns_self, name, access);
+		return status;
+	}
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0) return NOTIFY_STATUS_FAILED;
+	}
+
+	kstatus = _notify_server_set_access(globals->notify_server_port, (caddr_t)name, strlen(name), access, (int32_t *)&status);
+	if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+	return status;
+}
+
+uint32_t
+notify_get_access(const char *name, uint32_t *access)
+{
+	notify_state_t *ns_self;
+	kern_return_t kstatus;
+	uint32_t status;
+	notify_globals_t globals = _notify_globals();
+
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
+	{
+		ns_self = _notify_lib_self_state();
+		if (ns_self == NULL) return NOTIFY_STATUS_FAILED;
+		status = _notify_lib_get_access(ns_self, name, access);
+		return status;
+	}
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0) return NOTIFY_STATUS_FAILED;
+	}
+
+	kstatus = _notify_server_get_access(globals->notify_server_port, (caddr_t)name, strlen(name), (int32_t *)access, (int32_t *)&status);
+	if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+	return status;
+}
+
+/* notifyd retains and releases a name when clients register and cancel. */
+uint32_t
+notify_release_name(const char *name)
+{
+	(void)name;
+
+	return NOTIFY_STATUS_OK;
+}
+
+static void
+_notify_dispatch_handle(mach_port_t port)
+{
+	token_table_node_t *t;
+	int token;
+	mach_msg_empty_rcv_t msg;
+	kern_return_t status;
+
+	if (port == MACH_PORT_NULL) return;
+
+	memset(&msg, 0, sizeof(msg));
+
+	status = mach_msg(&msg.header, MACH_RCV_MSG, 0, sizeof(msg), port, 0, MACH_PORT_NULL);
+	if (status != KERN_SUCCESS) return;
+
+	token = msg.header.msgh_id;
+
+	t = token_table_find_retain(token);
+
+	if (t != NULL)
+	{
+		if ((t->queue != NULL) && (t->block != NULL))
+		{
+			/*
+			 * Don't reference into the token table node after token_table_release().
+			 * If the block calls notify_cancel, the node can get trashed, so
+			 * we keep anything we need from the block (properly retained and released)
+			 * in local variables.  Concurrent notify_cancel() calls in the block are safe.
+			 */
+			notify_handler_t theblock = Block_copy(t->block);
+			dispatch_queue_t thequeue = t->queue;
+			dispatch_retain(thequeue);
+
+			dispatch_async(thequeue, ^{
+				token_table_node_t *_t = token_table_find_no_lock(token);
+				if (_t != NULL) theblock(token);
+			});
+
+			_Block_release(theblock);
+			dispatch_release(thequeue);
+		}
+
+		token_table_release(t);
+	}
+}
+
+uint32_t
+notify_register_dispatch(const char *name, int *out_token, dispatch_queue_t queue, notify_handler_t handler)
+{
+	__block uint32_t status;
+	token_table_node_t *t;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	if (queue == NULL) return NOTIFY_STATUS_FAILED;
+	if (handler == NULL) return NOTIFY_STATUS_FAILED;
+
+	/* client is using dispatch: enable local demux and regeneration */
+	notify_set_options(NOTIFY_OPT_DEMUX | NOTIFY_OPT_REGEN);
+
+	status = notify_register_mach_port(name, &globals->notify_common_port, NOTIFY_REUSE, out_token);
+	if (status != NOTIFY_STATUS_OK) return status;
+
+	t = token_table_find_retain(*out_token);
+	if (t == NULL) return NOTIFY_STATUS_FAILED;
+
+	t->queue = queue;
+	dispatch_retain(t->queue);
+	t->block = Block_copy(handler);
+	token_table_release(t);
+
+	return NOTIFY_STATUS_OK;
+}
+
+/* note this does not get self names */
+static uint32_t
+notify_register_mux_fd(const char *name, int *out_token, int rfd, int wfd)
+{
+	__block uint32_t status;
+	token_table_node_t *t;
+	int val;
+	notify_globals_t globals = _notify_globals();
+
+	status = NOTIFY_STATUS_OK;
+
+	if (globals->notify_common_port == MACH_PORT_NULL) return NOTIFY_STATUS_FAILED;
+
+	status = notify_register_mach_port(name, &globals->notify_common_port, NOTIFY_REUSE, out_token);
+
+	t = token_table_find_retain(*out_token);
+	if (t == NULL) return NOTIFY_STATUS_FAILED;
+
+	t->token = *out_token;
+	t->fd = rfd;
+	t->queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
+	dispatch_retain(t->queue);
+	val = htonl(t->token);
+	t->block = (notify_handler_t)Block_copy(^(int unused __unused){ write(wfd, &val, sizeof(val)); });
+
+	token_table_release(t);
+
+	return NOTIFY_STATUS_OK;
+}
+
+uint32_t
+notify_register_check(const char *name, int *out_token)
+{
+	notify_state_t *ns_self;
+	kern_return_t kstatus;
+	uint32_t status, token;
+	uint64_t nid;
+	int32_t slot, shmsize;
+	size_t namelen;
+	uint32_t cid;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+	if (out_token == NULL) return NOTIFY_STATUS_FAILED;
+
+	*out_token = -1;
+	namelen = strlen(name);
+
+	if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
+	{
+		ns_self = _notify_lib_self_state();
+		if (ns_self == NULL) return NOTIFY_STATUS_FAILED;
+
+		token = OSAtomicIncrement32((int32_t *)&globals->token_id);
+		status = _notify_lib_register_plain(ns_self, name, NOTIFY_CLIENT_SELF, token, SLOT_NONE, 0, 0, &nid);
+		if (status != NOTIFY_STATUS_OK) return status;
+
+		cid = token;
+		token_table_add(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_FLAG_SELF | NOTIFY_TYPE_PLAIN, SIGNAL_NONE, FD_NONE, MACH_PORT_NULL, 0);
+
+		*out_token = token;
+		return NOTIFY_STATUS_OK;
+	}
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0) return NOTIFY_STATUS_FAILED;
+	}
+
+	token = OSAtomicIncrement32((int32_t *)&globals->token_id);
+	kstatus = KERN_SUCCESS;
+
+	if (globals->notify_ipc_version == 0)
+	{
+		nid = NID_UNSET;
+		kstatus = _notify_server_register_check(globals->notify_server_port, (caddr_t)name, namelen, &shmsize, &slot, (int32_t *)&cid, (int32_t *)&status);
+	}
+	else
+	{
+		cid = token;
+		kstatus = _notify_server_register_check_2(globals->notify_server_port, (caddr_t)name, namelen, token, &shmsize, &slot, &nid, (int32_t *)&status);
+	}
+
+	if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+	if (status != NOTIFY_STATUS_OK) return status;
+
+	if (shmsize != -1)
+	{
+		if (globals->shm_base == NULL)
+		{
+			if (shm_attach(shmsize) != 0) return NOTIFY_STATUS_FAILED;
+			if (globals->shm_base == NULL) return NOTIFY_STATUS_FAILED;
+		}
+
+		token_table_add(name, namelen, nid, token, cid, slot, NOTIFY_TYPE_MEMORY | NOTIFY_FLAG_REGEN, SIGNAL_NONE, FD_NONE, MACH_PORT_NULL, 0);
+	}
+	else
+	{
+		token_table_add(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_TYPE_PLAIN | NOTIFY_FLAG_REGEN, SIGNAL_NONE, FD_NONE, MACH_PORT_NULL, 0);
+	}
+
+	*out_token = token;
+	return status;
+}
+
+uint32_t
+notify_register_plain(const char *name, int *out_token)
+{
+	notify_state_t *ns_self;
+	kern_return_t kstatus;
+	uint32_t status;
+	uint64_t nid;
+	size_t namelen;
+	int token;
+	uint32_t cid;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	namelen = strlen(name);
+
+	if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
+	{
+		ns_self = _notify_lib_self_state();
+		if (ns_self == NULL) return NOTIFY_STATUS_FAILED;
+
+		token = OSAtomicIncrement32((int32_t *)&globals->token_id);
+		status = _notify_lib_register_plain(ns_self, name, NOTIFY_CLIENT_SELF, token, SLOT_NONE, 0, 0, &nid);
+		if (status != NOTIFY_STATUS_OK) return status;
+
+		cid = token;
+		token_table_add(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_FLAG_SELF | NOTIFY_TYPE_PLAIN, SIGNAL_NONE, FD_NONE, MACH_PORT_NULL, 0);
+
+		*out_token = token;
+		return NOTIFY_STATUS_OK;
+	}
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0) return NOTIFY_STATUS_FAILED;
+	}
+
+	token = OSAtomicIncrement32((int32_t *)&globals->token_id);
+
+	if (globals->notify_ipc_version == 0)
+	{
+		kstatus = _notify_server_register_plain(globals->notify_server_port, (caddr_t)name, namelen, (int32_t *)&cid, (int32_t *)&status);
+		if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+		if (status != NOTIFY_STATUS_OK) return status;
+	}
+	else
+	{
+		cid = token;
+		kstatus = _notify_server_register_plain_2(globals->notify_server_port, (caddr_t)name, namelen, token);
+		if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+	}
+
+	token_table_add(name, namelen, NID_UNSET, token, cid, SLOT_NONE, NOTIFY_TYPE_PLAIN | NOTIFY_FLAG_REGEN, SIGNAL_NONE, FD_NONE, MACH_PORT_NULL, 0);
+
+	*out_token = token;
+	return NOTIFY_STATUS_OK;
+}
+
+uint32_t
+notify_register_signal(const char *name, int sig, int *out_token)
+{
+	notify_state_t *ns_self;
+	kern_return_t kstatus;
+	uint32_t status;
+	uint64_t nid;
+	size_t namelen;
+	int token;
+	uint32_t cid;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+
+	namelen = strlen(name);
+
+	if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
+	{
+		ns_self = _notify_lib_self_state();
+		if (ns_self == NULL) return NOTIFY_STATUS_FAILED;
+
+		token = OSAtomicIncrement32((int32_t *)&globals->token_id);
+		status = _notify_lib_register_signal(ns_self, name, NOTIFY_CLIENT_SELF, token, sig, 0, 0, &nid);
+		if (status != NOTIFY_STATUS_OK) return status;
+
+		cid = token;
+		token_table_add(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_FLAG_SELF | NOTIFY_TYPE_SIGNAL, sig, FD_NONE, MACH_PORT_NULL, 0);
+
+		*out_token = token;
+		return NOTIFY_STATUS_OK;
+	}
+
+	if (globals->client_opts & NOTIFY_OPT_DEMUX)
+	{
+		return notify_register_dispatch(name, out_token, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(int unused __unused){ kill(getpid(), sig); });
+	}
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0) return NOTIFY_STATUS_FAILED;
+	}
+
+	token = OSAtomicIncrement32((int32_t *)&globals->token_id);
+
+	if (globals->notify_ipc_version == 0)
+	{
+		kstatus = _notify_server_register_signal(globals->notify_server_port, (caddr_t)name, namelen, sig, (int32_t *)&cid, (int32_t *)&status);
+		if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+		if (status != NOTIFY_STATUS_OK) return status;
+	}
+	else
+	{
+		cid = token;
+		kstatus = _notify_server_register_signal_2(globals->notify_server_port, (caddr_t)name, namelen, token, sig);
+		if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+	}
+
+	token_table_add(name, namelen, NID_UNSET, token, cid, SLOT_NONE, NOTIFY_TYPE_SIGNAL | NOTIFY_FLAG_REGEN, sig, FD_NONE, MACH_PORT_NULL, 0);
+
+	*out_token = token;
+	return NOTIFY_STATUS_OK;
+}
+
+uint32_t
+notify_register_mach_port(const char *name, mach_port_name_t *notify_port, int flags, int *out_token)
+{
+	notify_state_t *ns_self;
+	kern_return_t kstatus;
+	uint32_t status;
+	uint64_t nid;
+	task_t task;
+	int token, mine;
+	size_t namelen;
+	uint32_t cid, tflags;
+	token_table_node_t *t;
+	mach_port_name_t port;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+	if (notify_port == NULL) return NOTIFY_STATUS_INVALID_PORT;
+
+	mine = 0;
+	namelen = strlen(name);
+
+	task = mach_task_self();
+
+	if ((flags & NOTIFY_REUSE) == 0)
+	{
+		mine = 1;
+		kstatus = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, notify_port);
+		if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+	}
+
+	kstatus = mach_port_insert_right(task, *notify_port, *notify_port, MACH_MSG_TYPE_MAKE_SEND);
+	if (kstatus != KERN_SUCCESS)
+	{
+		if (mine == 1) mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1);
+		return NOTIFY_STATUS_FAILED;
+	}
+
+	if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
+	{
+		ns_self = _notify_lib_self_state();
+		if (ns_self == NULL)
+		{
+			if (mine == 1)
+			{
+				mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1);
+			}
+
+			mach_port_deallocate(task, *notify_port);
+			return NOTIFY_STATUS_FAILED;
+		}
+
+		token = OSAtomicIncrement32((int32_t *)&globals->token_id);
+		status = _notify_lib_register_mach_port(ns_self, name, NOTIFY_CLIENT_SELF, token, *notify_port, 0, 0, &nid);
+		if (status != NOTIFY_STATUS_OK)
+		{
+			if (mine == 1)
+			{
+				mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1);
+			}
+
+			mach_port_deallocate(task, *notify_port);
+			return status;
+		}
+
+		cid = token;
+		token_table_add(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_FLAG_SELF | NOTIFY_TYPE_PORT, SIGNAL_NONE, FD_NONE, *notify_port, 0);
+
+		*out_token = token;
+		notify_retain_mach_port(*notify_port, mine);
+
+		return NOTIFY_STATUS_OK;
+	}
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0)
+		{
+			if (mine == 1)
+			{
+				mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1);
+			}
+
+			mach_port_deallocate(task, *notify_port);
+			return NOTIFY_STATUS_FAILED;
+		}
+	}
+
+	if ((globals->client_opts & NOTIFY_OPT_DEMUX) && (*notify_port != globals->notify_common_port))
+	{
+		port = globals->notify_common_port;
+		kstatus = mach_port_insert_right(task, globals->notify_common_port, globals->notify_common_port, MACH_MSG_TYPE_MAKE_SEND);
+	}
+	else
+	{
+		port = *notify_port;
+		kstatus = KERN_SUCCESS;
+	}
+
+	if (kstatus == KERN_SUCCESS)
+	{
+		token = OSAtomicIncrement32((int32_t *)&globals->token_id);
+
+		if (globals->notify_ipc_version == 0)
+		{
+			kstatus = _notify_server_register_mach_port(globals->notify_server_port, (caddr_t)name, namelen, port, token, (int32_t *)&cid, (int32_t *)&status);
+			if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE;
+		}
+		else
+		{
+			cid = token;
+			kstatus = _notify_server_register_mach_port_2(globals->notify_server_port, (caddr_t)name, namelen, token, port);
+		}
+	}
+
+	if (kstatus != KERN_SUCCESS)
+	{
+		if (mine == 1)
+		{
+			mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1);
+		}
+
+		mach_port_deallocate(task, *notify_port);
+		return NOTIFY_STATUS_FAILED;
+	}
+
+	tflags = NOTIFY_TYPE_PORT;
+	if (port == globals->notify_common_port) tflags |= NOTIFY_FLAG_REGEN;
+	token_table_add(name, namelen, NID_UNSET, token, cid, SLOT_NONE, tflags, SIGNAL_NONE, FD_NONE, *notify_port, 0);
+
+	if ((globals->client_opts & NOTIFY_OPT_DEMUX) && (*notify_port != globals->notify_common_port))
+	{
+		t = token_table_find_retain(token);
+		if (t == NULL) return NOTIFY_STATUS_FAILED;
+
+		/* remember to release the send right when this gets cancelled */
+		t->flags |= NOTIFY_FLAG_RELEASE_SEND;
+
+		port = *notify_port;
+		t->queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
+		dispatch_retain(t->queue);
+		t->block = (notify_handler_t)Block_copy(^(int unused __unused){
+			mach_msg_empty_send_t msg;
+			kern_return_t _kstatus;
+
+			/* send empty message to the port with msgh_id = token; */
+			memset(&msg, 0, sizeof(msg));
+			msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSGH_BITS_ZERO);
+			msg.header.msgh_remote_port = port;
+			msg.header.msgh_local_port = MACH_PORT_NULL;
+			msg.header.msgh_size = sizeof(mach_msg_empty_send_t);
+			msg.header.msgh_id = token;
+
+			_kstatus = mach_msg(&(msg.header), MACH_SEND_MSG | MACH_SEND_TIMEOUT, msg.header.msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
+		});
+
+		token_table_release(t);
+	}
+
+	*out_token = token;
+	notify_retain_mach_port(*notify_port, mine);
+
+	return NOTIFY_STATUS_OK;
+}
+
+#if 0
+static char *
+_notify_mk_tmp_path(int tid)
+{
+#if TARGET_OS_EMBEDDED
+	int freetmp = 0;
+	char *path, *tmp = getenv("TMPDIR");
+
+	if (tmp == NULL)
+	{
+		asprintf(&tmp, "/tmp/com.apple.notify.%d", geteuid());
+		mkdir(tmp, 0755);
+		freetmp = 1;
+	}
+
+	if (tmp == NULL) return NULL;
+
+	asprintf(&path, "%s/com.apple.notify.%d.%d", tmp, getpid(), tid);
+	if (freetmp) free(tmp);
+	return path;
+#else
+	char tmp[PATH_MAX], *path;
+
+#if 0
+	// XXX
+	if (confstr(_CS_DARWIN_USER_TEMP_DIR, tmp, sizeof(tmp)) <= 0) return NULL;
+#endif
+#endif
+
+	path = NULL;
+	asprintf(&path, "%s/com.apple.notify.%d.%d", tmp, getpid(), tid);
+	return path;
+}
+#endif
+
+uint32_t
+notify_register_file_descriptor(const char *name, int *notify_fd, int flags, int *out_token)
+{
+	notify_state_t *ns_self;
+	uint32_t i, status;
+	uint64_t nid;
+	int token, mine, fdpair[2];
+	size_t namelen;
+#ifndef __FreeBSD__
+	fileport_t fileport;
+#endif
+	kern_return_t kstatus = 0;
+	uint32_t cid = 0;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	mine = 0;
+
+	if (name == NULL) return NOTIFY_STATUS_INVALID_NAME;
+	if (notify_fd == NULL) return NOTIFY_STATUS_INVALID_FILE;
+
+	namelen = strlen(name);
+
+	if ((flags & NOTIFY_REUSE) == 0)
+	{
+		if (pipe(fdpair) < 0) return NOTIFY_STATUS_FAILED;
+
+		mine = 1;
+		*notify_fd = fdpair[0];
+	}
+	else
+	{
+		/* check the file descriptor - it must be one of "ours" */
+		for (i = 0; i < globals->fd_count; i++)
+		{
+			if (globals->fd_clnt[i] == *notify_fd) break;
+		}
+
+		if (i >= globals->fd_count) return NOTIFY_STATUS_INVALID_FILE;
+
+		fdpair[0] = globals->fd_clnt[i];
+		fdpair[1] = globals->fd_srv[i];
+	}
+
+	if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
+	{
+		ns_self = _notify_lib_self_state();
+		if (ns_self == NULL)
+		{
+			if (mine == 1)
+			{
+				close(fdpair[0]);
+				close(fdpair[1]);
+			}
+
+			return NOTIFY_STATUS_FAILED;
+		}
+
+		token = OSAtomicIncrement32((int32_t *)&globals->token_id);
+		status = _notify_lib_register_file_descriptor(ns_self, name, NOTIFY_CLIENT_SELF, token, fdpair[1], 0, 0, &nid);
+		if (status != NOTIFY_STATUS_OK)
+		{
+			if (mine == 1)
+			{
+				close(fdpair[0]);
+				close(fdpair[1]);
+			}
+
+			return status;
+		}
+
+		cid = token;
+		token_table_add(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_FLAG_SELF | NOTIFY_TYPE_FILE, SIGNAL_NONE, *notify_fd, MACH_PORT_NULL, 0);
+
+		*out_token = token;
+		notify_retain_file_descriptor(fdpair[0], fdpair[1]);
+
+		return NOTIFY_STATUS_OK;
+	}
+
+	if (globals->client_opts & NOTIFY_OPT_DEMUX)
+	{
+		/*
+		 * Use dispatch to do a write() on fdpair[1] when notified.
+		 */
+		status = notify_register_mux_fd(name, out_token, fdpair[0], fdpair[1]);
+		if (status != NOTIFY_STATUS_OK)
+		{
+			if (mine == 1)
+			{
+				close(fdpair[0]);
+				close(fdpair[1]);
+			}
+
+			return status;
+		}
+
+		notify_retain_file_descriptor(fdpair[0], fdpair[1]);
+		return NOTIFY_STATUS_OK;
+	}
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0)
+		{
+			if (mine == 1)
+			{
+				close(fdpair[0]);
+				close(fdpair[1]);
+			}
+
+			return NOTIFY_STATUS_FAILED;
+		}
+	}
+
+#ifndef __FreeBSD__
+	/* send fdpair[1] (the sender's fd) to notifyd using a fileport */
+	fileport = MACH_PORT_NULL;
+	if (fileport_makeport(fdpair[1], (fileport_t *)&fileport) < 0)
+	{
+		if (mine == 1)
+		{
+			close(fdpair[0]);
+			close(fdpair[1]);
+		}
+
+		return NOTIFY_STATUS_FAILED;
+	}
+#endif
+
+	token = OSAtomicIncrement32((int32_t *)&globals->token_id);
+
+#ifndef __FreeBSD__
+	if (globals->notify_ipc_version == 0)
+	{
+		kstatus = _notify_server_register_file_descriptor(globals->notify_server_port, (caddr_t)name, namelen, (mach_port_t)fileport, token, (int32_t *)&cid, (int32_t *)&status);
+		if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE;
+	}
+	else
+	{
+		kstatus = _notify_server_register_file_descriptor_2(globals->notify_server_port, (caddr_t)name, namelen, token, (mach_port_t)fileport);
+	}
+#endif
+
+	if (kstatus != KERN_SUCCESS)
+	{
+		if (mine == 1)
+		{
+			close(fdpair[0]);
+			close(fdpair[1]);
+		}
+
+		return NOTIFY_STATUS_FAILED;
+	}
+
+	token_table_add(name, namelen, NID_UNSET, token, cid, SLOT_NONE, NOTIFY_TYPE_FILE, SIGNAL_NONE, *notify_fd, MACH_PORT_NULL, 0);
+
+	*out_token = token;
+	notify_retain_file_descriptor(fdpair[0], fdpair[1]);
+
+	return NOTIFY_STATUS_OK;
+}
+
+uint32_t
+notify_check(int token, int *check)
+{
+	kern_return_t kstatus;
+	uint32_t status, val;
+	token_table_node_t *t;
+	uint32_t tid;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	pthread_mutex_lock(&globals->notify_lock);
+
+	t = token_table_find_no_lock(token);
+	if (t == NULL)
+	{
+		pthread_mutex_unlock(&globals->notify_lock);
+		return NOTIFY_STATUS_INVALID_TOKEN;
+	}
+
+	if (t->flags & NOTIFY_FLAG_SELF)
+	{
+		/* _notify_lib_check returns NOTIFY_STATUS_FAILED if self_state is NULL */
+		status = _notify_lib_check(globals->self_state, NOTIFY_CLIENT_SELF, token, check);
+		pthread_mutex_unlock(&globals->notify_lock);
+		return status;
+	}
+
+	if (t->flags & NOTIFY_TYPE_MEMORY)
+	{
+		if (globals->shm_base == NULL)
+		{
+			pthread_mutex_unlock(&globals->notify_lock);
+			return NOTIFY_STATUS_FAILED;
+		}
+
+		*check = 0;
+		val = globals->shm_base[t->slot];
+		if (t->val != val)
+		{
+			*check = 1;
+			t->val = val;
+		}
+
+		pthread_mutex_unlock(&globals->notify_lock);
+		return NOTIFY_STATUS_OK;
+	}
+
+	tid = token;
+	if (globals->notify_ipc_version == 0) tid = t->client_id;
+
+	pthread_mutex_unlock(&globals->notify_lock);
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0) return NOTIFY_STATUS_FAILED;
+	}
+
+	kstatus = _notify_server_check(globals->notify_server_port, tid, check, (int32_t *)&status);
+
+	if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+	return status;
+}
+
+uint32_t
+notify_peek(int token, uint32_t *val)
+{
+	token_table_node_t *t;
+	uint32_t status;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	t = token_table_find_retain(token);
+	if (t == NULL) return NOTIFY_STATUS_INVALID_TOKEN;
+
+	if (t->flags & NOTIFY_FLAG_SELF)
+	{
+		/* _notify_lib_peek returns NOTIFY_STATUS_FAILED if self_state is NULL */
+		status = _notify_lib_peek(globals->self_state, NOTIFY_CLIENT_SELF, token, (int *)val);
+		token_table_release(t);
+		return status;
+	}
+
+	if (t->flags & NOTIFY_TYPE_MEMORY)
+	{
+		if (globals->shm_base == NULL)
+		{
+			token_table_release(t);
+			return NOTIFY_STATUS_FAILED;
+		}
+
+		*val = globals->shm_base[t->slot];
+		token_table_release(t);
+		return NOTIFY_STATUS_OK;
+	}
+
+	token_table_release(t);
+	return NOTIFY_STATUS_INVALID_REQUEST;
+}
+
+int *
+notify_check_addr(int token)
+{
+	token_table_node_t *t;
+	uint32_t slot;
+	int *val;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	t = token_table_find_retain(token);
+	if (t == NULL) return NULL;
+
+	if (t->flags & NOTIFY_FLAG_SELF)
+	{
+		/* _notify_lib_check_addr returns NOTIFY_STATUS_FAILED if self_state is NULL */
+		val = _notify_lib_check_addr(globals->self_state, NOTIFY_CLIENT_SELF, token);
+		token_table_release(t);
+		return val;
+	}
+
+	if (t->flags & NOTIFY_TYPE_MEMORY)
+	{
+		slot = t->slot;
+		token_table_release(t);
+
+		if (globals->shm_base == NULL) return NULL;
+		return (int *)&(globals->shm_base[slot]);
+	}
+
+	token_table_release(t);
+	return NULL;
+}
+
+uint32_t
+notify_monitor_file(int token, char *path, int flags)
+{
+	kern_return_t kstatus;
+	uint32_t status, len;
+	token_table_node_t *t;
+	char *dup;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	if (path == NULL) return NOTIFY_STATUS_INVALID_REQUEST;
+
+	t = token_table_find_retain(token);
+	if (t == NULL) return NOTIFY_STATUS_INVALID_TOKEN;
+
+	if (t->flags & NOTIFY_FLAG_SELF)
+	{
+		token_table_release(t);
+		return NOTIFY_STATUS_INVALID_REQUEST;
+	}
+
+	/* can only monitor one path with a token */
+	if (t->path != NULL)
+	{
+		token_table_release(t);
+		return NOTIFY_STATUS_INVALID_REQUEST;
+	}
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0)
+		{
+			token_table_release(t);
+			return NOTIFY_STATUS_FAILED;
+		}
+	}
+
+	len = strlen(path);
+	dup = strdup(path);
+	if (dup == NULL) return NOTIFY_STATUS_FAILED;
+
+	if (globals->notify_ipc_version == 0)
+	{
+		kstatus = _notify_server_monitor_file(globals->notify_server_port, t->client_id, path, len, flags, (int32_t *)&status);
+		if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE;
+	}
+	else
+	{
+		kstatus = _notify_server_monitor_file_2(globals->notify_server_port, token, path, len, flags);
+	}
+
+	t->path = dup;
+	t->path_flags = flags;
+
+	token_table_release(t);
+	if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+	return NOTIFY_STATUS_OK;
+}
+
+uint32_t
+notify_get_event(int token, int *ev, char *buf, int *len)
+{
+
+	(void)token;
+	(void)buf;
+
+	if (ev != NULL) *ev = 0;
+	if (len != NULL) *len = 0;
+
+	return NOTIFY_STATUS_OK;
+}
+
+uint32_t
+notify_get_state(int token, uint64_t *state)
+{
+	kern_return_t kstatus;
+	uint32_t status;
+	token_table_node_t *t;
+	uint64_t nid;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	t = token_table_find_retain(token);
+	if (t == NULL) return NOTIFY_STATUS_INVALID_TOKEN;
+	if (t->name_node == NULL)
+	{
+		token_table_release(t);
+		return NOTIFY_STATUS_INVALID_TOKEN;
+	}
+
+	if (t->flags & NOTIFY_FLAG_SELF)
+	{
+		/* _notify_lib_get_state returns NOTIFY_STATUS_FAILED if self_state is NULL */
+		status = _notify_lib_get_state(globals->self_state, t->name_node->name_id, state, 0, 0);
+		token_table_release(t);
+		return status;
+	}
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0)
+		{
+			token_table_release(t);
+			return NOTIFY_STATUS_FAILED;
+		}
+	}
+
+	if (globals->notify_ipc_version == 0)
+	{
+		kstatus = _notify_server_get_state(globals->notify_server_port, t->client_id, state, (int32_t *)&status);
+		if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE;
+	}
+	else
+	{
+		if (t->name_node->name_id >= NID_CALLED_ONCE)
+		{
+			kstatus = _notify_server_get_state_3(globals->notify_server_port, t->token, state, (uint64_t *)&nid, (int32_t *)&status);
+			if ((kstatus == KERN_SUCCESS) && (status == NOTIFY_STATUS_OK)) name_table_set_nid(t->name, nid);
+		}
+		else
+		{
+			kstatus = _notify_server_get_state_2(globals->notify_server_port, t->name_node->name_id, state, (int32_t *)&status);
+		}
+	}
+
+	token_table_release(t);
+	if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+	return status;
+}
+
+uint32_t
+notify_set_state(int token, uint64_t state)
+{
+	kern_return_t kstatus;
+	uint32_t status;
+	token_table_node_t *t;
+	uint64_t nid;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	t = token_table_find_retain(token);
+	if (t == NULL) return NOTIFY_STATUS_INVALID_TOKEN;
+	if (t->name_node == NULL)
+	{
+		token_table_release(t);
+		return NOTIFY_STATUS_INVALID_TOKEN;
+	}
+
+	if (t->flags & NOTIFY_FLAG_SELF)
+	{
+		/* _notify_lib_set_state returns NOTIFY_STATUS_FAILED if self_state is NULL */
+		status = _notify_lib_set_state(globals->self_state, t->name_node->name_id, state, 0, 0);
+		token_table_release(t);
+		return status;
+	}
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0)
+		{
+			token_table_release(t);
+			return NOTIFY_STATUS_FAILED;
+		}
+	}
+
+	status = NOTIFY_STATUS_OK;
+
+	if (globals->notify_ipc_version == 0)
+	{
+		kstatus = _notify_server_set_state(globals->notify_server_port, t->client_id, state, (int32_t *)&status);
+		if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE;
+	}
+	else
+	{
+		if (t->name_node->name_id >= NID_CALLED_ONCE)
+		{
+			kstatus = _notify_server_set_state_3(globals->notify_server_port, t->token, state, (uint64_t *)&nid, (int32_t *)&status);
+			if ((kstatus == KERN_SUCCESS) && (status == NOTIFY_STATUS_OK)) name_table_set_nid(t->name, nid);
+		}
+		else
+		{
+			status = NOTIFY_STATUS_OK;
+			kstatus = _notify_server_set_state_2(globals->notify_server_port, t->name_node->name_id, state);
+		}
+	}
+
+	if ((kstatus == KERN_SUCCESS) && (status == NOTIFY_STATUS_OK))
+	{
+		t->set_state_time = mach_absolute_time();
+		t->set_state_val = state;
+	}
+
+	token_table_release(t);
+	if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+	return NOTIFY_STATUS_OK;
+}
+
+uint32_t
+notify_cancel(int token)
+{
+	token_table_node_t *t;
+	uint32_t status;
+	kern_return_t kstatus;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	/*
+	 * Lock to prevent a race with notify_post, which uses the name ID.
+	 * If we are cancelling the last registration for this name, then we need
+	 * to block those routines from getting the name ID from the name table.
+	 * Once notifyd gets the cancellation, the name may vanish, and the name ID
+	 * held in the name table would go stale.
+	 *
+	 * Uses token_table_find_no_lock() which does not retain, and
+	 * token_table_release_no_lock() which releases the token.
+	 */
+	pthread_mutex_lock(&globals->notify_lock);
+
+	t = token_table_find_no_lock(token);
+	if (t == NULL)
+	{
+		pthread_mutex_unlock(&globals->notify_lock);
+		return NOTIFY_STATUS_INVALID_TOKEN;
+	}
+
+	if (t->flags & NOTIFY_FLAG_SELF)
+	{
+		/*
+		 * _notify_lib_cancel returns NOTIFY_STATUS_FAILED if self_state is NULL
+		 * We let it fail quietly.
+		 */
+		_notify_lib_cancel(globals->self_state, NOTIFY_CLIENT_SELF, t->token);
+
+		token_table_release_no_lock(t);
+		pthread_mutex_unlock(&globals->notify_lock);
+		return NOTIFY_STATUS_OK;
+	}
+
+	if (globals->notify_ipc_version == 0)
+	{
+		kstatus = _notify_server_cancel(globals->notify_server_port, t->client_id, (int32_t *)&status);
+		if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE;
+	}
+	else
+	{
+		kstatus = _notify_server_cancel_2(globals->notify_server_port, token);
+	}
+
+	token_table_release_no_lock(t);
+	pthread_mutex_unlock(&globals->notify_lock);
+
+	if ((kstatus == MIG_SERVER_DIED) || (kstatus == MACH_SEND_INVALID_DEST)) return NOTIFY_STATUS_OK;
+	else if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
+
+	return NOTIFY_STATUS_OK;
+}
+
+bool
+notify_is_valid_token(int val)
+{
+	token_table_node_t *t;
+	bool valid = false;
+
+	if (val < 0) return false;
+
+	notify_globals_t globals = _notify_globals();
+
+	pthread_mutex_lock(&globals->notify_lock);
+
+	t = (token_table_node_t *)_nc_table_find_n(globals->token_table, val);
+	if (t != NULL) valid = true;
+
+	pthread_mutex_unlock(&globals->notify_lock);
+
+	return valid;
+}
+
+uint32_t
+notify_suspend(int token)
+{
+	token_table_node_t *t;
+	uint32_t status, tid;
+	kern_return_t kstatus;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	t = token_table_find_retain(token);
+	if (t == NULL) return NOTIFY_STATUS_INVALID_TOKEN;
+
+	if (t->flags & NOTIFY_FLAG_SELF)
+	{
+		_notify_lib_suspend(globals->self_state, NOTIFY_CLIENT_SELF, t->token);
+		token_table_release(t);
+		return NOTIFY_STATUS_OK;
+	}
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0)
+		{
+			token_table_release(t);
+			return NOTIFY_STATUS_FAILED;
+		}
+	}
+
+	tid = token;
+	if (globals->notify_ipc_version == 0) tid = t->client_id;
+
+	kstatus = _notify_server_suspend(globals->notify_server_port, tid, (int32_t *)&status);
+
+	token_table_release(t);
+	if (kstatus != KERN_SUCCESS) status = NOTIFY_STATUS_FAILED;
+	return status;
+}
+
+uint32_t
+notify_resume(int token)
+{
+	token_table_node_t *t;
+	uint32_t status, tid;
+	kern_return_t kstatus;
+	notify_globals_t globals = _notify_globals();
+
+	regenerate_check();
+
+	t = token_table_find_retain(token);
+	if (t == NULL) return NOTIFY_STATUS_INVALID_TOKEN;
+
+	if (t->flags & NOTIFY_FLAG_SELF)
+	{
+		_notify_lib_resume(globals->self_state, NOTIFY_CLIENT_SELF, t->token);
+		token_table_release(t);
+		return NOTIFY_STATUS_OK;
+	}
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0)
+		{
+			token_table_release(t);
+			return NOTIFY_STATUS_FAILED;
+		}
+	}
+
+	tid = token;
+	if (globals->notify_ipc_version == 0) tid = t->client_id;
+
+	kstatus = _notify_server_resume(globals->notify_server_port, tid, (int32_t *)&status);
+
+	token_table_release(t);
+	if (kstatus != KERN_SUCCESS) status = NOTIFY_STATUS_FAILED;
+	return status;
+}
+
+uint32_t
+notify_suspend_pid(pid_t pid)
+{
+	uint32_t status;
+	kern_return_t kstatus;
+	notify_globals_t globals = _notify_globals();
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0)
+		{
+			return NOTIFY_STATUS_FAILED;
+		}
+	}
+
+	kstatus = _notify_server_suspend_pid(globals->notify_server_port, pid, (int32_t *)&status);
+
+	if (kstatus != KERN_SUCCESS) status = NOTIFY_STATUS_FAILED;
+	return status;
+}
+
+uint32_t
+notify_resume_pid(pid_t pid)
+{
+	uint32_t status;
+	kern_return_t kstatus;
+	notify_globals_t globals = _notify_globals();
+
+	if (globals->notify_server_port == MACH_PORT_NULL)
+	{
+		status = _notify_lib_init(EVENT_INIT);
+		if (status != 0)
+		{
+			return NOTIFY_STATUS_FAILED;
+		}
+	}
+
+	kstatus = _notify_server_resume_pid(globals->notify_server_port, pid, (int32_t *)&status);
+
+	if (kstatus != KERN_SUCCESS) status = NOTIFY_STATUS_FAILED;
+	return status;
+}
+
+/* Deprecated SPI */
+uint32_t
+notify_simple_post(const char *name)
+{
+	return notify_post(name);
+}


Property changes on: trunk/lib/libnotify/notify_client.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_get_state.3
===================================================================
--- trunk/lib/libnotify/notify_get_state.3	                        (rev 0)
+++ trunk/lib/libnotify/notify_get_state.3	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1 @@
+.so man3/notify.3


Property changes on: trunk/lib/libnotify/notify_get_state.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_internal.h
===================================================================
--- trunk/lib/libnotify/notify_internal.h	                        (rev 0)
+++ trunk/lib/libnotify/notify_internal.h	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2012 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 <dispatch/dispatch.h>
+#include <mach/mach.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <TargetConditionals.h>
+
+struct notify_globals_s {
+	// Global lock.
+	pthread_mutex_t notify_lock;
+
+	int32_t notify_ipc_version;
+	pid_t notify_server_pid;
+
+	uint32_t client_opts;
+	uint32_t saved_opts;
+
+	// Last allocated name id.
+	uint64_t name_id;
+
+	dispatch_once_t self_state_once;
+	notify_state_t *self_state;
+
+	dispatch_once_t notify_server_port_once;
+	mach_port_t notify_server_port;
+	mach_port_t saved_server_port;
+	
+	mach_port_t notify_common_port;
+	int notify_common_token;
+	dispatch_source_t notify_dispatch_source;
+	dispatch_source_t server_proc_source;
+	
+	dispatch_once_t token_table_once;
+	table_t *token_table;
+	table_t *token_name_table;
+	uint32_t token_id;
+	
+	// File descriptor list.
+	uint32_t fd_count;
+	int *fd_clnt;
+	int *fd_srv;
+	int *fd_refcount;
+	
+	// Mach port list.
+	uint32_t mp_count;
+	mach_port_t *mp_list;
+	int *mp_refcount;
+	int *mp_mine;
+	
+	// Shared memory base address.
+	uint32_t *shm_base;
+};
+typedef struct notify_globals_s *notify_globals_t;
+
+#if __has_include(<os/alloc_once_private.h>)
+#include <os/alloc_once_private.h>
+#if defined(OS_ALLOC_ONCE_KEY_LIBSYSTEM_NOTIFY)
+#define _NOTIFY_HAS_ALLOC_ONCE 1
+#endif
+#endif
+
+__attribute__((visibility("hidden")))
+void _notify_init_globals(void * /* notify_globals_t */ globals);
+
+__attribute__((visibility("hidden")))
+notify_globals_t _notify_globals_impl(void);
+
+uint32_t notify_set_owner(const char *name, uint32_t uid, uint32_t gid);
+uint32_t notify_get_owner(const char *name, uint32_t *uid, uint32_t *gid);
+uint32_t notify_set_access(const char *name, uint32_t access);
+uint32_t notify_get_access(const char *name, uint32_t *access);
+uint32_t notify_release_name(const char *name);
+uint32_t notify_register_plain(const char *name, int *out_token);
+uint32_t notify_peek(int token, uint32_t *val);
+int *notify_check_addr(int token);
+uint32_t notify_monitor_file(int token, char *path, int flags);
+uint32_t notify_get_event(int token, int *ev, char *buf, int *len);
+void _notify_lib_cancel_port(notify_state_t *ns, mach_port_t port);
+uint32_t _notify_lib_check(notify_state_t *ns, pid_t pid, int token, int *check);
+int *_notify_lib_check_addr(notify_state_t *ns, pid_t pid, int token);
+uint32_t _notify_lib_peek(notify_state_t *ns, pid_t pid, int token, int *val);
+void _notify_fork_child(void);
+
+__attribute__((__pure__))
+static inline notify_globals_t
+_notify_globals(void) {
+#if _NOTIFY_HAS_ALLOC_ONCE
+	return (notify_globals_t)os_alloc_once(OS_ALLOC_ONCE_KEY_LIBSYSTEM_NOTIFY,
+		sizeof(struct notify_globals_s), &_notify_init_globals);
+#else
+	return _notify_globals_impl();
+#endif
+}


Property changes on: trunk/lib/libnotify/notify_internal.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_ipc.defs
===================================================================
--- trunk/lib/libnotify/notify_ipc.defs	                        (rev 0)
+++ trunk/lib/libnotify/notify_ipc.defs	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2003-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 <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+subsystem notify_ipc 78945668;
+serverprefix _;
+
+import <sys/types.h>;
+
+import "notify_ipc_types.h";
+
+type notify_name    = ^ array [] of MACH_MSG_TYPE_BYTE
+	ctype : caddr_t;
+
+routine _notify_server_post
+(
+	server : mach_port_t;
+	name : notify_name;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_register_plain
+(
+	server : mach_port_t;
+	name : notify_name;
+	out token : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_register_check
+(
+	server : mach_port_t;
+	name : notify_name;
+	out size : int;
+	out slot : int;
+	out token : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_register_signal
+(
+	server : mach_port_t;
+	name : notify_name;
+	sig: int;
+	out token : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_register_file_descriptor
+(
+	server : mach_port_t;
+	name : notify_name;
+	fileport : mach_port_move_send_t;
+	ntoken : int;
+	out token : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_register_mach_port
+(
+	server : mach_port_t;
+	name : notify_name;
+	port : mach_port_move_send_t;
+	ntoken : int;
+	out token : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_set_owner
+(
+	server : mach_port_t;
+	name : notify_name;
+	user : int;
+	group : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_get_owner
+(
+	server : mach_port_t;
+	name : notify_name;
+	out user : int;
+	out group : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_set_access
+(
+	server : mach_port_t;
+	name : notify_name;
+	mode : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_get_access
+(
+	server : mach_port_t;
+	name : notify_name;
+	out mode : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_release_name
+(
+	server : mach_port_t;
+	name : notify_name;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_cancel
+(
+	server : mach_port_t;
+	token : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_check
+(
+	server : mach_port_t;
+	token : int;
+	out check : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_get_state
+(
+	server : mach_port_t;
+	token : int;
+	out state : uint64_t;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_set_state
+(
+	server : mach_port_t;
+	token : int;
+	state : uint64_t;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+skip; /* formerly _notify_server_get_val */
+
+skip; /* formerly _notify_server_set_val */
+
+routine _notify_server_monitor_file
+(
+	server : mach_port_t;
+	token : int;
+	path : notify_name;
+	flags : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_suspend
+(
+	server : mach_port_t;
+	token : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_resume
+(
+	server : mach_port_t;
+	token : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_suspend_pid
+(
+	server : mach_port_t;
+	pid : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_resume_pid
+(
+	server : mach_port_t;
+	pid : int;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+simpleroutine _notify_server_simple_post
+(
+	server : mach_port_t;
+	name : notify_name;
+	ServerAuditToken audit : audit_token_t
+);
+
+/* Additions for version 2 - more async support */
+
+routine _notify_server_post_2
+(
+	server : mach_port_t;
+	name : notify_name;
+	out name_id : uint64_t;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+simpleroutine _notify_server_post_3
+(
+	server : mach_port_t;
+	name_id : uint64_t;
+	ServerAuditToken audit : audit_token_t
+);
+
+simpleroutine _notify_server_post_4
+(
+	server : mach_port_t;
+	name : notify_name;
+	ServerAuditToken audit : audit_token_t
+);
+
+simpleroutine _notify_server_register_plain_2
+(
+	server : mach_port_t;
+	name : notify_name;
+	token : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_register_check_2
+(
+	server : mach_port_t;
+	name : notify_name;
+	token: int;
+	out size : int;
+	out slot : int;
+	out name_id : uint64_t;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+simpleroutine _notify_server_register_signal_2
+(
+	server : mach_port_t;
+	name : notify_name;
+	token : int;
+	sig: int;
+	ServerAuditToken audit : audit_token_t
+);
+
+simpleroutine _notify_server_register_file_descriptor_2
+(
+	server : mach_port_t;
+	name : notify_name;
+	token: int;
+	fileport : mach_port_move_send_t;
+	ServerAuditToken audit : audit_token_t
+);
+
+simpleroutine _notify_server_register_mach_port_2
+(
+	server : mach_port_t;
+	name : notify_name;
+	token: int;
+	port : mach_port_move_send_t;
+	ServerAuditToken audit : audit_token_t
+);
+
+simpleroutine _notify_server_cancel_2
+(
+	server : mach_port_t;
+	token : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_get_state_2
+(
+	server : mach_port_t;
+	name_id : uint64_t;
+	out state : uint64_t;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_get_state_3
+(
+	server : mach_port_t;
+	token : int;
+	out state : uint64_t;
+	out nid : uint64_t;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+simpleroutine _notify_server_set_state_2
+(
+	server : mach_port_t;
+	name_id : uint64_t;
+	state : uint64_t;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_set_state_3
+(
+	server : mach_port_t;
+	token : int;
+	state : uint64_t;
+	out nid : uint64_t;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+simpleroutine _notify_server_monitor_file_2
+(
+	server : mach_port_t;
+	token : int;
+	path : notify_name;
+	flags : int;
+	ServerAuditToken audit : audit_token_t
+);
+
+routine _notify_server_regenerate
+(
+	server : mach_port_t;
+	name : notify_name;
+	token : int;
+	reg_type : uint32_t;
+	port : mach_port_make_send_t;
+	sig: int;
+	prev_slot: int;
+	prev_state : uint64_t;
+	prev_time : uint64_t;
+	path : notify_name;
+	path_flags: int;
+	out new_slot : int;
+	out new_name_id : uint64_t;
+	out status : int;
+	ServerAuditToken audit : audit_token_t
+);

Added: trunk/lib/libnotify/notify_ipc_types.h
===================================================================
--- trunk/lib/libnotify/notify_ipc_types.h	                        (rev 0)
+++ trunk/lib/libnotify/notify_ipc_types.h	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2003-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Portions Copyright (c) 2003-2009 Apple 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.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _NOTIFY_IPC_TYPES_H_
+#define _NOTIFY_IPC_TYPES_H_
+
+#include <sys/types.h>
+typedef char inline_data_t[2048];
+
+#endif


Property changes on: trunk/lib/libnotify/notify_ipc_types.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_is_valid_token.3
===================================================================
--- trunk/lib/libnotify/notify_is_valid_token.3	                        (rev 0)
+++ trunk/lib/libnotify/notify_is_valid_token.3	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1 @@
+.so man3/notify.3


Property changes on: trunk/lib/libnotify/notify_is_valid_token.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_keys.h
===================================================================
--- trunk/lib/libnotify/notify_keys.h	                        (rev 0)
+++ trunk/lib/libnotify/notify_keys.h	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2007-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Portions Copyright (c) 2007-2009 Apple 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.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * This file lists notification keys that are posted using the 
+ * notify_post() API by various Mac OS X system services.
+ * The exact circumstances under which services post these
+ * notifications is controlled by those services, and may change
+ * in future software releases.
+ */
+
+/*
+ * Directory Service notifications
+ * These are posted by the DirectoryService daemon to advise clients that
+ * cached data should be invalidated.
+ */
+#define kNotifyDSCacheInvalidation "com.apple.system.DirectoryService.InvalidateCache"
+#define kNotifyDSCacheInvalidationGroup "com.apple.system.DirectoryService.InvalidateCache.group"
+#define kNotifyDSCacheInvalidationHost "com.apple.system.DirectoryService.InvalidateCache.host"
+#define kNotifyDSCacheInvalidationService "com.apple.system.DirectoryService.InvalidateCache.service"
+#define kNotifyDSCacheInvalidationUser "com.apple.system.DirectoryService.InvalidateCache.user"
+
+/*
+ * File System notifications
+ * These advise clients of various filesystem events.
+ */
+#define kNotifyVFSMount "com.apple.system.kernel.mount"
+#define kNotifyVFSUnmount "com.apple.system.kernel.unmount"
+#define kNotifyVFSUpdate "com.apple.system.kernel.mountupdate"
+#define kNotifyVFSLowDiskSpace "com.apple.system.lowdiskspace"
+#define kNotifyVFSLowDiskSpaceRootFS "com.apple.system.lowdiskspace.system"
+#define kNotifyVFSLowDiskSpaceOtherFS "com.apple.system.lowdiskspace.user"
+
+/*
+ * System Configuration notifications
+ * These advise clients of changes in the system configuration
+ * managed by the system configuration server (configd).
+ * Note that a much richer set of notifications are available to
+ * clients using the SCDynamicStore API.
+ */
+#define kNotifySCHostNameChange "com.apple.system.hostname"
+#define kNotifySCNetworkChange "com.apple.system.config.network_change"
+
+/*
+ * ASL notifications
+ * Sent by syslogd to advise clients that new log messages have been
+ * added to the ASL database.
+ */
+#define kNotifyASLDBUpdate "com.apple.system.logger.message"
+
+/*
+ * Time Zone change notification
+ * Sent by notifyd when the system's timezone changes.
+ */
+#define kNotifyTimeZoneChange "com.apple.system.timezone"
+
+/*
+ * System clock change notification
+ * Sent when a process modifies the system clock using the settimeofday system call.
+ */
+#define kNotifyClockSet "com.apple.system.clock_set"


Property changes on: trunk/lib/libnotify/notify_keys.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_post.3
===================================================================
--- trunk/lib/libnotify/notify_post.3	                        (rev 0)
+++ trunk/lib/libnotify/notify_post.3	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1 @@
+.so man3/notify.3


Property changes on: trunk/lib/libnotify/notify_post.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_private.h
===================================================================
--- trunk/lib/libnotify/notify_private.h	                        (rev 0)
+++ trunk/lib/libnotify/notify_private.h	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2009-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@
+ */
+
+#ifndef __NOTIFY_PRIVATE_H__
+#define __NOTIFY_PRIVATE_H__
+
+#include <stdint.h>
+#include <Availability.h>
+
+#define NOTIFY_OPT_DEMUX   0x00000001
+#define NOTIFY_OPT_REGEN   0x00000002
+#define NOTIFY_OPT_ENABLE  0x04000000
+#define NOTIFY_OPT_DISABLE 0x08000000
+
+uint32_t notify_suspend_pid(pid_t pid)
+__OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0);
+
+uint32_t notify_resume_pid(pid_t pid)
+__OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0);
+
+uint32_t notify_simple_post(const char *name)
+__OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_3);
+
+void notify_set_options(uint32_t opts)
+__OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_6_0);
+
+#endif /* __NOTIFY_PRIVATE_H__ */


Property changes on: trunk/lib/libnotify/notify_private.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_register_check.3
===================================================================
--- trunk/lib/libnotify/notify_register_check.3	                        (rev 0)
+++ trunk/lib/libnotify/notify_register_check.3	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1 @@
+.so man3/notify.3


Property changes on: trunk/lib/libnotify/notify_register_check.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_register_dispatch.3
===================================================================
--- trunk/lib/libnotify/notify_register_dispatch.3	                        (rev 0)
+++ trunk/lib/libnotify/notify_register_dispatch.3	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1 @@
+.so man3/notify.3


Property changes on: trunk/lib/libnotify/notify_register_dispatch.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_register_file_descriptor.3
===================================================================
--- trunk/lib/libnotify/notify_register_file_descriptor.3	                        (rev 0)
+++ trunk/lib/libnotify/notify_register_file_descriptor.3	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1 @@
+.so man3/notify.3


Property changes on: trunk/lib/libnotify/notify_register_file_descriptor.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_register_mach_port.3
===================================================================
--- trunk/lib/libnotify/notify_register_mach_port.3	                        (rev 0)
+++ trunk/lib/libnotify/notify_register_mach_port.3	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1 @@
+.so man3/notify.3


Property changes on: trunk/lib/libnotify/notify_register_mach_port.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_register_signal.3
===================================================================
--- trunk/lib/libnotify/notify_register_signal.3	                        (rev 0)
+++ trunk/lib/libnotify/notify_register_signal.3	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1 @@
+.so man3/notify.3


Property changes on: trunk/lib/libnotify/notify_register_signal.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/notify_set_state.3
===================================================================
--- trunk/lib/libnotify/notify_set_state.3	                        (rev 0)
+++ trunk/lib/libnotify/notify_set_state.3	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1 @@
+.so man3/notify.3


Property changes on: trunk/lib/libnotify/notify_set_state.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/table.c
===================================================================
--- trunk/lib/libnotify/table.c	                        (rev 0)
+++ trunk/lib/libnotify/table.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,768 @@
+/*
+ * Copyright (c) 2003-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 <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <vm/vm.h>
+#include <os/base.h>
+#include <os/assumes.h>
+#include "table.h"
+
+#define KEY_UNKNOWN    0
+#define KEY_INT        1
+#define KEY_STR_MINE   2
+#define KEY_STR_SHARED 3
+
+#define DEFAULT_SIZE 256
+
+typedef struct table_node_s
+{
+	union
+	{
+		char *string;
+		const char *const_string;
+		uint64_t uint64;
+	} key;
+	void *datum;
+	struct table_node_s *next;
+} table_node_t;
+
+typedef struct __table_private
+{
+	uint32_t type;
+	uint32_t bucket_count;
+	table_node_t **bucket;
+} table_private_t;
+
+typedef struct
+{
+	uint32_t bucket_index;
+	table_node_t *node;
+} table_traverse_t;
+
+typedef struct __list_private
+{
+	struct __list_private *prev;
+	struct __list_private *next;
+	uint32_t refcount;
+	void *data;
+} list_private_t;
+
+table_t *
+_nc_table_new(uint32_t n)
+{
+	table_private_t *t;
+
+	t = (table_t *)malloc(sizeof(table_t));
+	if (t == NULL) return NULL;
+
+	if (n == 0) n = DEFAULT_SIZE;
+
+	t->type = KEY_UNKNOWN;
+	t->bucket_count = n;
+	t->bucket = (table_node_t **)calloc(t->bucket_count, sizeof(table_node_t *));
+	if (t->bucket == NULL)
+	{
+		free(t);
+		return NULL;
+	}
+
+	return (table_t *)t;
+}
+
+static uint32_t
+hash_key(int size, const char *key)
+{
+	uint32_t v;
+	char *p;
+
+	if (key == NULL) return 0;
+
+	v = 0;
+	for (p = (char *)key; *p != '\0'; p++)
+	{
+		v = (v << 1) ^ (v ^ *p);
+	}
+
+	v %= size;
+	return v;
+}
+
+static uint32_t
+hash_nkey(uint32_t size, uint64_t key)
+{
+	uint32_t x = key;
+	uint32_t y = key >> 32;
+	return ((x ^ y) % size);
+}
+
+void *
+_nc_table_find_get_key(table_t *tin, const char *key, const char **shared_key)
+{
+	table_private_t *t;
+	table_node_t *n;
+	uint32_t b;
+
+	if (tin == NULL) return NULL;
+	if (key == NULL) return NULL;
+
+	if (shared_key != NULL) *shared_key = NULL;
+
+	t = (table_private_t *)tin;
+	b = hash_key(t->bucket_count, key);
+
+	for (n = t->bucket[b]; n != NULL; n = n->next)
+	{
+		if ((n->key.string != NULL) && (!strcmp(key, n->key.string)))
+		{
+			if (shared_key != NULL) *shared_key = n->key.const_string;
+			return n->datum;
+		}
+	}
+
+	return NULL;
+}
+
+void *
+_nc_table_find(table_t *tin, const char *key)
+{
+	return _nc_table_find_get_key(tin, key, NULL);
+}
+
+void *
+_nc_table_find_64(table_t *tin, uint64_t key)
+{
+	table_private_t *t;
+	table_node_t *n;
+	uint32_t b;
+
+	if (tin == NULL) return NULL;
+
+	t = (table_private_t *)tin;
+	b = hash_nkey(t->bucket_count, key);
+
+	for (n = t->bucket[b]; n != NULL; n = n->next)
+	{
+		if ((n->key.uint64 != (uint64_t)-1) && (key == n->key.uint64)) return n->datum;
+	}
+
+	return NULL;
+}
+
+void *
+_nc_table_find_n(table_t *tin, uint32_t key)
+{
+	uint64_t n64 = key;
+	return _nc_table_find_64(tin, n64);
+}
+
+static void
+_nc_table_insert_type(table_t *tin, int type, char *key, const char *ckey, void *datum)
+{
+	table_private_t *t;
+	table_node_t *n;
+	uint32_t b;
+
+	if (tin == NULL) return;
+	if ((key == NULL) && (ckey == NULL)) return;
+	if (datum == NULL) return;
+
+	t = (table_private_t *)tin;
+	if (t->type == KEY_UNKNOWN) t->type = type;
+	else os_assumes(t->type == (uint32_t)type);
+
+	n = (table_node_t *)malloc(sizeof(table_node_t));
+
+	if (key != NULL)
+	{
+		b = hash_key(t->bucket_count, key);
+		n->key.string = key;
+	}
+	else
+	{
+		b = hash_key(t->bucket_count, ckey);
+		n->key.const_string = ckey;
+	}
+
+	n->datum = datum;
+	n->next = t->bucket[b];
+	t->bucket[b] = n;
+}
+
+void
+_nc_table_insert(table_t *tin, const char *key, void *datum)
+{
+	char *dup;
+
+	if (tin == NULL) return;
+	if (key == NULL) return;
+	if (datum == NULL) return;
+
+	dup = strdup(key);
+	if (dup == NULL) return;
+
+	_nc_table_insert_type(tin, KEY_STR_MINE, dup, NULL, datum);
+}
+
+void
+_nc_table_insert_no_copy(table_t *tin, const char *key, void *datum)
+{
+	if (tin == NULL) return;
+	if (key == NULL) return;
+	if (datum == NULL) return;
+
+	_nc_table_insert_type(tin, KEY_STR_SHARED, NULL, key, datum);
+}
+
+void
+_nc_table_insert_pass(table_t *tin, char *key, void *datum)
+{
+	if (tin == NULL) return;
+	if (key == NULL) return;
+	if (datum == NULL) return;
+
+	_nc_table_insert_type(tin, KEY_STR_MINE, key, NULL, datum);
+}
+
+void
+_nc_table_insert_64(table_t *tin, uint64_t key, void *datum)
+{
+	table_private_t *t;
+	table_node_t *n;
+	uint32_t b;
+
+	if (tin == NULL) return;
+	if (datum == NULL) return;
+
+	t = (table_private_t *)tin;
+	if (t->type == KEY_UNKNOWN) t->type = KEY_INT;
+	else os_assumes(t->type == KEY_INT);
+
+	b = hash_nkey(t->bucket_count, key);
+	n = (table_node_t *)malloc(sizeof(table_node_t));
+	n->key.uint64 = key;
+	n->datum = datum;
+	n->next = t->bucket[b];
+	t->bucket[b] = n;
+}
+
+void
+_nc_table_insert_n(table_t *tin, uint32_t key, void *datum)
+{
+	uint64_t n64 = key;
+	_nc_table_insert_64(tin, n64, datum);
+}
+
+void
+_nc_table_delete(table_t *tin, const char *key)
+{
+	table_private_t *t;
+	table_node_t *n, *p;
+	uint32_t b;
+
+	if (tin == NULL) return;
+	if (key == NULL) return;
+
+	t = (table_private_t *)tin;
+	os_assumes((t->type == KEY_STR_MINE) || (t->type == KEY_STR_SHARED));
+
+	b = hash_key(t->bucket_count, key);
+
+	p = NULL;
+	for (n = t->bucket[b]; n != NULL; n = n->next)
+	{
+		if ((n->key.string != NULL) && (!strcmp(key, n->key.string)))
+		{
+			if (p == NULL) t->bucket[b] = n->next;
+			else p->next = n->next;
+			if (t->type == KEY_STR_MINE) free(n->key.string);
+			free(n);
+			return;
+		}
+		p = n;
+	}
+}
+
+void
+_nc_table_delete_64(table_t *tin, uint64_t key)
+{
+	table_private_t *t;
+	table_node_t *n, *p;
+	uint32_t b;
+
+	if (tin == NULL) return;
+
+	t = (table_private_t *)tin;
+	os_assumes(t->type == KEY_INT);
+
+	b = hash_nkey(t->bucket_count, key);
+
+	p = NULL;
+	for (n = t->bucket[b]; n != NULL; n = n->next)
+	{
+		if ((n->key.uint64 != (uint64_t)-1) && (key == n->key.uint64))
+		{
+			if (p == NULL) t->bucket[b] = n->next;
+			else p->next = n->next;
+			free(n);
+			return;
+		}
+		p = n;
+	}
+}
+
+void
+_nc_table_delete_n(table_t *tin, uint32_t key)
+{
+	uint64_t n64 = key;
+	_nc_table_delete_64(tin, n64);
+}
+
+void *
+_nc_table_traverse_start(table_t *tin)
+{
+	table_traverse_t *tt;
+	table_private_t *t;
+	uint32_t b;
+
+	if (tin == NULL) return NULL;
+
+	t = (table_private_t *)tin;
+	if (t->bucket_count == 0) return NULL;
+
+	for (b = 0; b < t->bucket_count; b++)
+	{
+		if (t->bucket[b] != NULL)
+		{
+			tt = (table_traverse_t *)malloc(sizeof(table_traverse_t));
+			if (tt == NULL) return NULL;
+			tt->bucket_index = b;
+			tt->node = t->bucket[b];
+			return (void *)tt;
+		}
+	}
+
+	return NULL;
+}
+
+void *
+_nc_table_traverse(table_t *tin, void *ttin)
+{
+	table_private_t *t;
+	table_traverse_t *tt;
+	void *datum;
+	uint32_t b;
+
+	if (tin == NULL) return NULL;
+	if (ttin == NULL) return NULL;
+
+	t = (table_private_t *)tin;
+	tt = (table_traverse_t *)ttin;
+
+	if (tt->node == NULL) return NULL;
+
+	datum = tt->node->datum;
+	tt->node = tt->node->next;
+	if (tt->node != NULL) return datum;
+
+	for (b = tt->bucket_index + 1; b < t->bucket_count; b++)
+	{
+		if (t->bucket[b] != NULL)
+		{
+			tt->bucket_index = b;
+			tt->node = t->bucket[b];
+			return datum;
+		}
+	}
+
+	tt->bucket_index = b;
+	tt->node = NULL;
+
+	return datum;
+}
+
+void
+_nc_table_traverse_end(table_t *tin, void *ttin)
+{
+
+	(void)tin;
+
+	if (ttin == NULL) return;
+	free(ttin);
+}
+
+void
+_nc_table_free(table_t *tin)
+{
+	table_private_t *t;
+	table_node_t *n, *x;
+	uint32_t b;
+
+	if (tin == NULL) return;
+
+	t = (table_private_t *)tin;
+
+	for (b = 0; b < t->bucket_count; b++)
+	{
+		x = NULL;
+		for (n = t->bucket[b]; n != NULL; n = x)
+		{
+			x = n->next;
+			if (t->type == KEY_STR_MINE) free(n->key.string);
+			free(n);
+		}
+	}
+
+	free(t->bucket);
+	free(t);
+}
+
+/* Linked List */
+
+/*
+ * Make a new node
+ */
+list_t *
+_nc_list_new(void *d)
+{
+	list_t *n;
+
+	n = (list_t *)calloc(1, sizeof(list_t));
+	if (n == NULL) return NULL;
+
+	n->refcount = 1;
+	n->data = d;
+	return n;
+}
+
+/*
+ * Release a node
+ */
+void
+_nc_list_release(list_t *l)
+{
+	if (l == NULL) return;
+	l->refcount--;
+	if (l->refcount > 0) return;
+
+	free(l);
+}
+
+/*
+ * Retain a node
+ */
+list_t *
+_nc_list_retain(list_t *l)
+{
+	if (l == NULL) return NULL;
+	l->refcount++;
+	return l;
+}
+
+/*
+ * Retain a list
+ */
+list_t *
+_nc_list_retain_list(list_t *l)
+{
+	list_t *n;
+
+	for (n = l; n != NULL; n = n->next) n->refcount++;
+	return l;
+}
+
+/*
+ * Get previous node
+ */
+list_t *
+_nc_list_prev(list_t *l)
+{
+	if (l == NULL) return NULL;
+	return l->prev;
+}
+
+/*
+ * Get next node
+ */
+list_t *
+_nc_list_next(list_t *l)
+{
+	if (l == NULL) return NULL;
+	return l->next;
+}
+
+/*
+ * Get head (first node) of list
+ */
+list_t *
+_nc_list_head(list_t *l)
+{
+	list_t *p;
+
+	if (l == NULL) return NULL;
+
+	for (p = l; p->prev != NULL; p = p->prev);
+
+	return p;
+}
+
+/*
+ * Get tail (last node) of list
+ */
+list_t *
+_nc_list_tail(list_t *l)
+{
+	list_t *p;
+
+	if (l == NULL) return NULL;
+
+	for (p = l; p->next != NULL; p = p->next);
+
+	return p;
+}
+
+/*
+ * Insert a node in front of another node.
+ * Cuts list if n is NULL.
+ */
+list_t *
+_nc_list_prepend(list_t *l, list_t *n)
+{
+	if (l == NULL) return n;
+
+	if (n != NULL)
+	{
+		n->next = l;
+		n->prev = l->prev;
+	}
+
+	if (l->prev != NULL) l->prev->next = n;
+	l->prev = n;
+
+	return n;
+}
+
+/*
+ * Append a node after another node.
+ * Cuts list if n is NULL.
+ */
+list_t *
+_nc_list_append(list_t *l, list_t *n)
+{
+	if (l == NULL) return n;
+
+	if (n != NULL)
+	{
+		n->prev = l;
+		n->next = l->next;
+	}
+
+	if (l->next != NULL) n->next->prev = n;
+	l->next = n;
+
+	return n;
+}
+
+/*
+ * Set next pointer - use with care.
+ */
+void
+_nc_list_set_next(list_t *l, list_t *n)
+{
+	if (l == NULL) return;
+	l->next = n;
+}
+
+/*
+ * Set prev pointer - use with care.
+ */
+void
+_nc_list_set_prev(list_t *l, list_t *p)
+{
+	if (l == NULL) return;
+	l->prev = p;
+}
+
+/*
+ * Concatenate two lists.
+ * Returns new head.
+ */
+list_t *
+_nc_list_concat(list_t *a, list_t *b)
+{
+	list_t *p;
+
+	if (a == NULL) return b;
+	if (b == NULL) return a;
+
+	for (p = a; p->next != NULL; p = p->next);
+
+	p->next = b;
+	b->prev = p;
+
+	for (p = a; p->prev != NULL; p = p->prev);
+
+	return p;
+}
+
+uint32_t
+_nc_list_count(list_t *l)
+{
+	uint32_t n;
+	list_t *p;
+
+	n = 0;
+	for (p = l; p != NULL; p = p->next) n++;
+	return n;
+}
+
+void *
+_nc_list_data(list_t *l)
+{
+	if (l == NULL) return NULL;
+	return l->data;
+}
+
+void
+_nc_list_set_data(list_t *l, void *d)
+{
+	if (l != NULL) l->data = d;
+}
+
+list_t *
+_nc_list_find(list_t *l, void *d)
+{
+	list_t *p;
+
+	if (l == NULL) return NULL;
+
+	for (p = l; p != NULL; p = p->next)
+	{
+		if (p->data == d) return p;
+	}
+
+	return NULL;
+}
+
+list_t *
+_nc_list_find_release(list_t *l, void *d)
+{
+	list_t *p;
+
+	if (l == NULL) return NULL;
+
+	if (l->data == d)
+	{
+		p = l->next;
+		if (p != NULL) p->prev = NULL;
+		_nc_list_release(l);
+		return p;
+	}
+
+	for (p = l->next; p != NULL; p = p->next)
+	{
+		if (p->data == d)
+		{
+			p->prev->next = p->next;
+			if (p->next != NULL) p->next->prev = p->prev;
+			_nc_list_release(p);
+			return l;
+		}
+	}
+
+	return l;
+}
+
+list_t *
+_nc_list_reverse(list_t *l)
+{
+	list_t *x, *s, *r;
+
+	if (l == NULL) return NULL;
+
+	x = l->prev;
+	r = l;
+	s = l->next;
+
+	while (s != NULL)
+	{
+		s = r->next;
+		r->next = r->prev;
+		r->prev = s;
+		if (s != NULL) r = s;
+	}
+
+	if (x != NULL)
+	{
+		x->next = r;
+		r->prev = x;
+	}
+
+	return r;
+}
+
+list_t *
+_nc_list_extract(list_t *n)
+{
+	if (n == NULL) return NULL;
+
+	if (n->prev != NULL) n->prev->next = n->next;
+	if (n->next != NULL) n->next->prev = n->prev;
+
+	n->prev = NULL;
+	n->next = NULL;
+
+	return n;
+}
+
+list_t *
+_nc_list_chop(list_t *l)
+{
+	list_t *p;
+
+	if (l == NULL) return NULL;
+	p = l->next;
+	if (p != NULL) p->prev = NULL;
+
+	_nc_list_release(l);
+	return p;
+}
+
+void
+_nc_list_release_list(list_t *l)
+{
+	list_t *p, *n;
+
+	if (l == NULL) return;
+	if (l->prev != NULL) l->prev->next = NULL;
+
+	p = l;
+	while (p != NULL)
+	{
+		n = p->next;
+		_nc_list_release(p);
+		p = n;
+	}
+}


Property changes on: trunk/lib/libnotify/table.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libnotify/table.h
===================================================================
--- trunk/lib/libnotify/table.h	                        (rev 0)
+++ trunk/lib/libnotify/table.h	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2003-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@
+ */
+
+#ifndef _NOTIFY_TABLE_H_
+#define _NOTIFY_TABLE_H_
+
+#include <stdint.h>
+
+typedef struct __table_private table_t;
+typedef struct __list_private list_t;
+
+extern table_t *_nc_table_new(uint32_t n);
+
+extern void _nc_table_insert(table_t *t, const char *key, void *datum);
+extern void _nc_table_insert_no_copy(table_t *t, const char *key, void *datum);
+extern void _nc_table_insert_pass(table_t *t, char *key, void *datum);
+extern void _nc_table_insert_n(table_t *t, uint32_t key, void *datum);
+extern void _nc_table_insert_64(table_t *t, uint64_t key, void *datum);
+
+extern void *_nc_table_find(table_t *t, const char *key);
+extern void *_nc_table_find_get_key(table_t *tin, const char *key, const char **shared_key);
+extern void *_nc_table_find_n(table_t *t, uint32_t key);
+extern void *_nc_table_find_64(table_t *t, uint64_t key);
+
+extern void _nc_table_delete(table_t *t, const char *key);
+extern void _nc_table_delete_n(table_t *t, uint32_t key);
+extern void _nc_table_delete_64(table_t *t, uint64_t key);
+
+extern void *_nc_table_traverse_start(table_t *tin);
+extern void *_nc_table_traverse(table_t *tin, void *ttin);
+extern void _nc_table_traverse_end(table_t *tin, void *ttin);
+
+extern void _nc_table_free(table_t *tin);
+
+extern list_t *_nc_list_new(void *d);
+
+extern list_t *_nc_list_retain(list_t *l);
+extern list_t *_nc_list_retain_list(list_t *l);
+
+extern void _nc_list_release(list_t *l);
+extern void _nc_list_release_list(list_t *l);
+
+extern list_t *_nc_list_prev(list_t *l);
+extern list_t *_nc_list_next(list_t *l);
+
+extern void _nc_list_set_next(list_t *l, list_t *n);
+extern void _nc_list_set_prev(list_t *l, list_t *p);
+
+extern list_t *_nc_list_head(list_t *l);
+extern list_t *_nc_list_tail(list_t *l);
+
+extern list_t *_nc_list_prepend(list_t *l, list_t *n);
+extern list_t *_nc_list_append(list_t *l, list_t *n);
+
+extern list_t *_nc_list_concat(list_t *a, list_t *b);
+
+extern void *_nc_list_data(list_t *l);
+extern void _nc_list_set_data(list_t *l, void *d);
+
+extern list_t *_nc_list_find(list_t *l, void *d);
+extern list_t *_nc_list_find_release(list_t *l, void *d);
+
+extern list_t * _nc_list_reverse(list_t *l);
+extern uint32_t _nc_list_count(list_t *l);
+extern list_t *_nc_list_extract(list_t *n);
+extern list_t *_nc_list_chop(list_t *l);
+
+#endif /* _NOTIFY_TABLE_H_ */


Property changes on: trunk/lib/libnotify/table.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/Makefile
===================================================================
--- trunk/lib/libosxsupport/Makefile	                        (rev 0)
+++ trunk/lib/libosxsupport/Makefile	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,24 @@
+.include <bsd.init.mk>
+LIB=	osxsupport
+
+.PATH: .
+.PATH: ${.CURDIR}/uuid
+.PATH: ../../sbin/launchd
+
+BASE_INCLUDE= -I${.CURDIR}/../../include/apple
+BASE_INCLUDE+= -I${.CURDIR}/../../include -I${.CURDIR}/../../sys -I${.CURDIR}
+DEFINES= -D__APPLE__ -DLIBC_NO_LIBCRASHREPORTERCLIENT -DPRIVATE
+MIG_FLAGS= ${BASE_INCLUDE} 	${DEFINES}
+CFLAGS+= ${MIG_FLAGS}  -DHAVE_INTTYPES_H -fblocks
+
+#support
+SRCS+= assumes.c libproc.c getiopolicy_np.c fileport.c
+SRCS+= si_module.c search_module.c si_data.c cache_module.c file_module.c
+
+#uuid
+SRCS+= clear.c copy.c gen_uuid.c isnull.c unparse.c pack.c unpack.c
+
+
+CLEANFILES+= *~ cscope.*
+
+.include <bsd.lib.mk>


Property changes on: trunk/lib/libosxsupport/Makefile
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/assumes.c
===================================================================
--- trunk/lib/libosxsupport/assumes.c	                        (rev 0)
+++ trunk/lib/libosxsupport/assumes.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2011, 2012 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 <uuid/uuid.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <mach/boolean.h>
+
+#if 0
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+#include <mach-o/arch.h>
+#include <mach-o/getsect.h>
+#endif
+#include <pthread.h>
+#include <sys/types.h>
+#include <execinfo.h>
+#include <stdio.h>
+#include <dlfcn.h>
+#include <_simple.h>
+#include <errno.h>
+#include <pthread.h>
+#include <string.h>
+#include "os/assumes.h"
+#include "gen/assumes.h"
+
+
+#define OSX_ASSUMES_LOG_REDIRECT_SECT_NAME "__osx_log_func"
+#define os_atomic_cmpxchg(p, o, n) __sync_bool_compare_and_swap((p), (o), (n))
+#if 0
+static bool _os_should_abort_on_assumes = false;
+#endif
+void
+_os_avoid_tail_call(void)
+{
+	// no-op
+}
+
+#pragma mark Public Interfaces
+void
+_os_assumes_log(uint64_t code __unused)
+{
+#ifdef notyet
+	_os_assumes_log_impl(code);
+#endif	
+}
+
+void
+_os_assumes_log_ctx(os_log_callout_t callout __unused, void *ctx __unused, uint64_t code __unused)
+{
+#ifdef notyet
+	_os_assumes_log_ctx_impl(callout, ctx, code);
+#endif	
+}
+
+char *
+_os_assert_log(uint64_t code __unused)
+{
+#ifdef notyet
+	return _os_assert_log_impl(code);
+#endif	
+	return strdup("implement _os_assert_log");
+}
+
+#if 0
+
+static const char *
+_os_basename(const char *p)
+{
+	return ((strrchr(p, '/') ? : p - 1) + 1);
+}
+#if 0
+static void
+_os_get_build(char *build, size_t sz)
+{
+	/* Get the build every time. We used to cache it, but if PID 1 experiences
+	 * an assumes() failure before the build has been set, that would mean that
+	 * all future failures would get bad build info. So we fetch it every time.
+	 * Since assumes() failures are on the slow path anyway, not a huge deal.
+	 */
+	int mib[] = { CTL_KERN, KERN_OSVERSION };
+
+	size_t oldsz = sz;
+	int r = sysctl(mib, 2, build, &sz, NULL, 0);
+	if (r == 0 && sz == 1) {
+		(void)strlcpy(build, "99Z999", oldsz);
+	}
+}
+
+static void
+_os_get_image_uuid(void *hdr, uuid_t uuid)
+{
+#if __LP64__
+	struct mach_header_64 *hdr32or64 = (struct mach_header_64 *)hdr;
+#else
+	struct mach_header *hdr32or64 = (struct mach_header *)hdr;
+#endif /* __LP64__ */
+
+	size_t i = 0;
+	size_t next = sizeof(*hdr32or64);
+	struct load_command *cur = NULL;
+	for (i = 0; i < hdr32or64->ncmds; i++) {
+		cur = (struct load_command *)((uintptr_t)hdr32or64 + next);
+		if (cur->cmd == LC_UUID) {
+			struct uuid_command *cmd = (struct uuid_command *)cur;
+			uuid_copy(uuid, cmd->uuid);
+			break;
+		}
+
+		next += cur->cmdsize;
+	}
+
+	if (i == hdr32or64->ncmds) {
+		uuid_clear(uuid);
+	}
+}
+
+static void
+_os_abort_on_assumes_once(void)
+{
+	/* Embedded boot-args can get pretty long. Let's just hope this is big
+	 * enough.
+	 */
+	char bootargs[2048];
+	size_t len = sizeof(bootargs) - 1;
+
+	if (sysctlbyname("kern.bootargs", bootargs, &len, NULL, 0) == 0) {
+		if (strnstr(bootargs, "-os_assumes_fatal", len)) {
+			_os_should_abort_on_assumes = true;
+		}
+	}
+}
+#endif
+static bool
+_os_abort_on_assumes(void)
+{
+#if 0
+	static pthread_once_t once = PTHREAD_ONCE_INIT;
+#endif	
+	bool result = false;
+
+	if (getpid() != 1) {
+		if (getenv("OS_ASSUMES_FATAL")) {
+			result = true;
+		} else {
+			_os_should_abort_on_assumes = true;
+				/* pthread_once(&once, _os_abort_on_assumes_once); */
+			result = _os_should_abort_on_assumes;
+		}
+	} else {
+		if (getenv("OS_ASSUMES_FATAL_PID1")) {
+			result = true;
+		}
+	}
+
+	return result;
+}
+
+#if 0
+#if __LP64__
+typedef struct mach_header_64 os_mach_header;
+#else
+typedef struct mach_header os_mach_header;
+#endif
+
+static os_redirect_t
+_os_find_log_redirect_func(os_mach_header *hdr)
+{
+	os_redirect_t result = NULL;
+
+	char name[128];
+	unsigned long size = 0;
+	uint8_t *data = getsectiondata(hdr, OS_ASSUMES_REDIRECT_SEG, OS_ASSUMES_REDIRECT_SECT, &size);
+	if (!data) {
+		data = getsectiondata(hdr, "__TEXT", OSX_ASSUMES_LOG_REDIRECT_SECT_NAME, &size);
+
+		if (data && size < sizeof(name) - 2) {
+			(void)strlcpy(name, (const char *)data, size + 1);
+			result = dlsym(RTLD_DEFAULT, name);
+		}
+	} else if (size == sizeof(struct _os_redirect_assumes_s)) {
+		struct _os_redirect_assumes_s *redirect = (struct _os_redirect_assumes_s *)data;
+		result = redirect->redirect;
+	}
+
+	return result;
+}
+}
+
+static bool
+_os_log_redirect(void *hdr, const char *msg)
+{
+	bool result = false;
+
+	os_redirect_t redirect_func = _os_find_log_redirect_func(hdr);
+	if (redirect_func) {
+		result = redirect_func(msg);
+	}
+
+	return result;
+}
+
+__attribute__((always_inline))
+static void
+_os_construct_message(uint64_t code, _SIMPLE_STRING asl_message, Dl_info *info, char *buff, size_t sz)
+{
+	const char *image_name = NULL;
+	uintptr_t offset = 0;
+	uuid_string_t uuid_str;
+
+	void *ret = __builtin_return_address(0);
+	if (dladdr(ret, info)) {
+		uuid_t uuid;
+		_os_get_image_uuid(info->dli_fbase, uuid);
+		
+		uuid_unparse(uuid, uuid_str);
+		image_name = _os_basename(info->dli_fname);
+		
+		offset = ret - info->dli_fbase;
+	}
+
+	char sig[64];
+	(void)snprintf(sig, sizeof(sig), "%s:%lu", uuid_str, offset);
+
+	char result[24];
+	(void)snprintf(result, sizeof(result), "0x%llx", code);
+
+	char build[16];
+	size_t bsz = sizeof(build);
+	_os_get_build(build, bsz);
+
+	(void)snprintf(buff, sz, "assertion failed: %s: %s + %lu [%s]: %s", build, image_name, offset, uuid_str, result);
+
+	_simple_asl_msg_set(asl_message, "com.apple.message.domain", "com.apple.assumes.failure");
+	_simple_asl_msg_set(asl_message, "com.apple.message.signature", sig);
+	_simple_asl_msg_set(asl_message, "com.apple.message.signature2", result);
+	_simple_asl_msg_set(asl_message, "com.apple.message.signature3", image_name);
+	_simple_asl_msg_set(asl_message, "com.apple.message.summarize", "YES");
+}
+#endif
+#pragma mark Internal Implementations
+__attribute__((always_inline))
+static inline void
+_os_assumes_log_impl(uint64_t code)
+{
+	_SIMPLE_STRING asl_message = _simple_asl_msg_new();
+	if (asl_message) {
+		Dl_info info;
+		char message[256];
+		_os_construct_message(code, asl_message, &info, message, sizeof(message));
+		if (!_os_log_redirect(info.dli_fbase, message)) {
+			_os_trace_error_str(message);
+			_simple_asl_msg_set(asl_message, "Level", "Error");
+			_simple_asl_msg_set(asl_message, "Message", "");
+			_simple_asl_send(asl_message);
+		}
+
+		_simple_sfree(asl_message);
+	}
+
+	if (_os_abort_on_assumes()) {
+		__builtin_trap();
+	}
+}
+
+__attribute__((always_inline))
+static inline char *
+_os_assert_log_impl(uint64_t code)
+{
+	char *result = NULL;
+
+	_SIMPLE_STRING asl_message = _simple_asl_msg_new();
+	if (asl_message) {
+		Dl_info info;
+		char message[256];
+		_os_construct_message(code, asl_message, &info, message, sizeof(message));
+		if (!_os_log_redirect(info.dli_fbase, message)) {
+			_os_trace_error_str(message);
+			_simple_asl_msg_set(asl_message, "Level", "Error");
+			_simple_asl_msg_set(asl_message, "Message", "");
+			_simple_asl_send(asl_message);
+		}
+
+		_simple_sfree(asl_message);
+		result = strdup(message);
+	}
+
+#if LIBC_NO_LIBCRASHREPORTERCLIENT
+	/* There is no crash report information facility on embedded, which is
+	 * really regrettable. Fortunately, all we need to capture is the value
+	 * which tripped up the assertion. We can just stuff that into the thread's 
+	 * name.
+	 */
+	char name[64];
+	(void)pthread_getname_np(pthread_self(), name, sizeof(name));
+
+	char newname[64];
+	if (strlen(name) == 0) {
+		(void)snprintf(newname, sizeof(newname), "[Fatal bug: 0x%llx]", code);
+	} else {
+		(void)snprintf(newname, sizeof(newname), "%s [Fatal bug: 0x%llx]", name, code);
+	}
+
+	(void)pthread_setname_np(newname);
+#endif
+
+	return result;
+}
+
+__attribute__((always_inline))
+static inline void
+_os_assumes_log_ctx_impl(os_log_callout_t callout, void *ctx, uint64_t code)
+{
+	_SIMPLE_STRING asl_message = _simple_asl_msg_new();
+	if (asl_message) {
+		Dl_info info;
+		char message[256];
+		_os_construct_message(code, asl_message, &info, message, sizeof(message));
+
+		(void)callout(asl_message, ctx, message);
+		_simple_sfree(asl_message);
+	}
+
+	if (_os_abort_on_assumes()) {
+		__builtin_trap();
+	}
+}
+
+__attribute__((always_inline))
+static inline char *
+_os_assert_log_ctx_impl(os_log_callout_t callout, void *ctx, uint64_t code)
+{
+	char *result = NULL;
+
+	_SIMPLE_STRING asl_message = _simple_asl_msg_new();
+	if (asl_message) {
+		Dl_info info;
+		char message[256];
+		_os_construct_message(code, asl_message, &info, message, sizeof(message));
+
+		(void)callout(asl_message, ctx, message);
+		_simple_sfree(asl_message);
+		result = strdup(message);
+	}
+	return result;
+}
+
+#pragma mark Public Interfaces
+void
+_os_assumes_log(uint64_t code)
+{
+	_os_assumes_log_impl(code);
+}
+
+char *
+_os_assert_log(uint64_t code)
+{
+	return _os_assert_log_impl(code);
+}
+
+void
+_os_assumes_log_ctx(os_log_callout_t callout, void *ctx, uint64_t code)
+{
+	_os_assumes_log_ctx_impl(callout, ctx, code);
+}
+
+char *
+_os_assert_log_ctx(os_log_callout_t callout, void *ctx, uint64_t code)
+{
+	return _os_assert_log_ctx_impl(callout, ctx, code);
+}
+
+#pragma mark Legacy
+void
+_osx_assumes_log(uint64_t code)
+{
+	_os_assumes_log(code);
+}
+
+char *
+_osx_assert_log(uint64_t code)
+{
+	return _os_assert_log_impl(code);
+}
+
+void
+_osx_assumes_log_ctx(osx_log_callout_t callout, void *ctx, uint64_t code)
+{
+	_os_assumes_log_ctx_impl(callout, ctx, code);
+}
+
+char *
+_osx_assert_log_ctx(osx_log_callout_t callout, void *ctx, uint64_t code)
+{
+	return _os_assert_log_ctx_impl(callout, ctx, code);
+}
+
+void
+_osx_avoid_tail_call(void)
+{
+	_os_avoid_tail_call();
+}
+
+#endif


Property changes on: trunk/lib/libosxsupport/assumes.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/atomic_compat.h
===================================================================
--- trunk/lib/libosxsupport/atomic_compat.h	                        (rev 0)
+++ trunk/lib/libosxsupport/atomic_compat.h	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2014-2015 iXsystems, Inc.
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted providing 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 ``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/types.h>
+#include <machine/atomic.h>
+ 
+typedef int OSSpinLock;
+
+#define OSAtomicIncrement32Barrier(v) atomic_fetchadd_int((volatile int *)v, 1)
+#define OSAtomicDecrement32Barrier(v) atomic_fetchadd_int((volatile int *)v, -1)
+#define OSAtomicTestAndSetBarrier(i, v) atomic_testandset_int((volatile int *)v, i)
+#define OSAtomicAdd64(i, v) atomic_add_64((volatile int *)v, i)
+#define OSAtomicIncrement32(v) atomic_fetchadd_32((volatile int *)v, 1)
+#define OSAtomicDecrement32(v) atomic_fetchadd_32((volatile int *)v, -1)
+#define OSAtomicCompareAndSwapLongBarrier(o, i, v) atomic_cmpset_long(v, o, i)
+#define OSAtomicCompareAndSwap32Barrier(o, i, v) atomic_cmpset_32(v, o, i)
+#define OSSpinLockLock(l) while (atomic_testandset_int((volatile int *)l, 1) == 1)
+#define OSSpinLockUnlock(l) atomic_clear_int((volatile int *)l, 1)


Property changes on: trunk/lib/libosxsupport/atomic_compat.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/cache_module.c
===================================================================
--- trunk/lib/libosxsupport/cache_module.c	                        (rev 0)
+++ trunk/lib/libosxsupport/cache_module.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,569 @@
+/*
+ * Copyright (c) 2008-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 <si_module.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <sys/stat.h>
+#include <ils.h>
+#include <pthread.h>
+#include <libkern/OSAtomic.h>
+#include <dispatch/dispatch.h>
+
+/* GLOBAL */
+#ifdef __FreeBSD__
+extern uint32_t gL1CacheEnabled;
+si_mod_t * si_module_static_cache(void);
+void si_cache_add_item(si_mod_t *si, si_mod_t *src, si_item_t *item);
+void si_cache_add_list(si_mod_t *si, si_mod_t *src, si_list_t *list);
+#endif
+uint32_t gL1CacheEnabled = 1;
+
+#define CACHE_COUNT CATEGORY_COUNT
+#define CACHE_MAX 20
+
+typedef struct
+{
+	pthread_mutex_t mutex;
+	int head;
+	si_item_t *item[CACHE_MAX];
+	si_list_t *list;
+} cache_store_t;
+
+typedef struct
+{
+	cache_store_t cache_store[CACHE_COUNT];
+} cache_si_private_t;
+
+static void *
+cache_validate_item(cache_si_private_t *pp, int cat, int where)
+{
+	si_item_t *item;
+
+	item = pp->cache_store[cat].item[where];
+	if (item == NULL) return NULL;
+
+	if (si_item_is_valid(item)) return si_item_retain(item);
+
+	si_item_release(item);
+	pp->cache_store[cat].item[where] = NULL;
+
+	return NULL;
+}
+
+static void *
+cache_validate_list(cache_si_private_t *pp, int cat)
+{
+	uint32_t i, valid;
+	si_item_t *item, *last;
+	si_list_t *list;
+
+	list = pp->cache_store[cat].list;
+
+	if (list == NULL) return NULL;
+	if (list->count == 0) return NULL;
+
+	last = list->entry[0];
+	valid = si_item_is_valid(last);
+
+	for (i = 1; (i < list->count) && (valid == 1); i++)
+	{
+		item = list->entry[i];
+		if ((item->src == last->src) && (item->type == last->type) && (item->validation_a == last->validation_a) && (item->validation_b == last->validation_b)) continue;
+
+		last = item;
+		valid = si_item_is_valid(last);
+	}
+
+	if (valid) return si_list_retain(list);
+
+	si_list_release(list);
+	pp->cache_store[cat].list = NULL;
+
+	return NULL;
+}
+
+static si_item_t *
+cache_fetch_item(si_mod_t *si, int cat, const char *name, uint32_t num, int which)
+{
+	int i;
+	cache_si_private_t *pp;
+	si_item_t *item;
+
+	if (si == NULL) return NULL;
+	if (gL1CacheEnabled == 0) return NULL;
+
+	pp = (cache_si_private_t *)si->private;
+	if (pp == NULL) return NULL;
+
+	pthread_mutex_lock(&pp->cache_store[cat].mutex);
+
+	for (i = 0; i < CACHE_MAX; i++)
+	{
+		item = cache_validate_item(pp, cat, i);
+		if (item && si_item_match(item, cat, name, num, which))
+		{
+			break;
+		}
+		else
+		{
+			si_item_release(item);
+			item = NULL;
+		}
+	}
+
+	pthread_mutex_unlock(&(pp->cache_store[cat].mutex));
+
+	return item;
+}
+
+static si_list_t *
+cache_fetch_list(si_mod_t *si, int cat)
+{
+	cache_si_private_t *pp;
+	si_list_t *list;
+
+	if (si == NULL) return NULL;
+	if (gL1CacheEnabled == 0) return NULL;
+
+	pp = (cache_si_private_t *)si->private;
+	if (pp == NULL) return NULL;
+
+	pthread_mutex_lock(&(pp->cache_store[cat].mutex));
+	list = cache_validate_list(pp, cat);
+	pthread_mutex_unlock(&(pp->cache_store[cat].mutex));
+
+	return list;
+}
+
+static si_item_t *
+cache_user_byname(si_mod_t *si, const char *name)
+{
+	return cache_fetch_item(si, CATEGORY_USER, name, 0, SEL_NAME);
+}
+
+static si_item_t *
+cache_user_byuid(si_mod_t *si, uid_t uid)
+{
+	return cache_fetch_item(si, CATEGORY_USER, NULL, uid, SEL_NUMBER);
+}
+
+static si_list_t *
+cache_user_all(si_mod_t *si)
+{
+	return cache_fetch_list(si, CATEGORY_USER);
+}
+
+static si_item_t *
+cache_group_byname(si_mod_t *si, const char *name)
+{
+	return cache_fetch_item(si, CATEGORY_GROUP, name, 0, SEL_NAME);
+}
+
+static si_item_t *
+cache_group_bygid(si_mod_t *si, gid_t gid)
+{
+	return cache_fetch_item(si, CATEGORY_GROUP, NULL, gid, SEL_NUMBER);
+}
+
+static si_list_t *
+cache_group_all(si_mod_t *si)
+{
+	return cache_fetch_list(si, CATEGORY_GROUP);
+}
+
+static si_item_t *
+cache_grouplist(si_mod_t *si, const char *name, uint32_t count __unused)
+{
+	return cache_fetch_item(si, CATEGORY_GROUPLIST, name, 0, SEL_NAME);
+}
+
+static si_item_t *
+cache_alias_byname(si_mod_t *si, const char *name)
+{
+	return cache_fetch_item(si, CATEGORY_ALIAS, name, 0, SEL_NAME);
+}
+
+static si_list_t *
+cache_alias_all(si_mod_t *si)
+{
+	return cache_fetch_list(si, CATEGORY_ALIAS);
+}
+
+static si_item_t *
+cache_host_byname(si_mod_t *si, const char *name, int af, const char *ignored __unused, uint32_t *err)
+{
+	si_item_t *item;
+
+	if (err != NULL) *err = SI_STATUS_NO_ERROR;
+	item = NULL;
+
+	if (af == AF_INET) item = cache_fetch_item(si, CATEGORY_HOST_IPV4, name, af, SEL_NAME);
+	else item = cache_fetch_item(si, CATEGORY_HOST_IPV6, name, af, SEL_NAME);
+
+	if ((item == NULL) && (err != NULL) && (*err == 0)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
+
+	return item;
+}
+
+static si_item_t *
+cache_host_byaddr(si_mod_t *si __unused, const void *addr, int af, const char *ignored __unused, uint32_t *err)
+{
+	si_item_t *item;
+
+	if (err != NULL) *err = SI_STATUS_NO_ERROR;
+	item = NULL;
+
+	if (af == AF_INET) item = cache_fetch_item(si, CATEGORY_HOST_IPV4, addr, af, SEL_NUMBER);
+	else item = cache_fetch_item(si, CATEGORY_HOST_IPV6, addr, af, SEL_NUMBER);
+
+	if ((item == NULL) && (err != NULL) && (*err == 0)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
+
+	return item;
+}
+
+static si_list_t *
+cache_host_all(si_mod_t *si)
+{
+	return cache_fetch_list(si, CATEGORY_HOST);
+}
+
+static si_item_t *
+cache_network_byname(si_mod_t *si, const char *name)
+{
+	return cache_fetch_item(si, CATEGORY_NETWORK, name, 0, SEL_NAME);
+}
+
+static si_item_t *
+cache_network_byaddr(si_mod_t *si, uint32_t addr)
+{
+	return cache_fetch_item(si, CATEGORY_NETWORK, NULL, addr, SEL_NUMBER);
+}
+
+static si_list_t *
+cache_network_all(si_mod_t *si)
+{
+	return cache_fetch_list(si, CATEGORY_NETWORK);
+}
+
+static si_item_t *
+cache_service_byname(si_mod_t *si, const char *name, const char *proto)
+{
+	uint32_t pn;
+
+	if (name == NULL) return NULL;
+	if (proto == NULL) return cache_fetch_item(si, CATEGORY_SERVICE, name, 0, SEL_NAME);
+
+	pn = 1;
+	if (string_equal(proto, "tcp")) pn = 2;
+
+	return cache_fetch_item(si, CATEGORY_SERVICE, name, pn, SEL_NAME);
+}
+
+static si_item_t *
+cache_service_byport(si_mod_t *si, int port, const char *proto)
+{
+	return cache_fetch_item(si, CATEGORY_SERVICE, proto, port, SEL_NUMBER);
+}
+
+static si_list_t *
+cache_service_all(si_mod_t *si)
+{
+	return cache_fetch_list(si, CATEGORY_SERVICE);
+}
+
+static si_item_t *
+cache_protocol_byname(si_mod_t *si, const char *name)
+{
+	return cache_fetch_item(si, CATEGORY_PROTOCOL, name, 0, SEL_NAME);
+}
+
+static si_item_t *
+cache_protocol_bynumber(si_mod_t *si, int number)
+{
+	return cache_fetch_item(si, CATEGORY_PROTOCOL, NULL, number, SEL_NUMBER);
+}
+
+static si_list_t *
+cache_protocol_all(si_mod_t *si)
+{
+	return cache_fetch_list(si, CATEGORY_PROTOCOL);
+}
+
+static si_item_t *
+cache_rpc_byname(si_mod_t *si, const char *name)
+{
+	return cache_fetch_item(si, CATEGORY_RPC, name, 0, SEL_NAME);
+}
+
+static si_item_t *
+cache_rpc_bynumber(si_mod_t *si, int number)
+{
+	return cache_fetch_item(si, CATEGORY_RPC, NULL, number, SEL_NUMBER);
+}
+
+static si_list_t *
+cache_rpc_all(si_mod_t *si)
+{
+	return cache_fetch_list(si, CATEGORY_RPC);
+}
+
+static si_item_t *
+cache_fs_byspec(si_mod_t *si, const char *name)
+{
+	return cache_fetch_item(si, CATEGORY_FS, name, 0, SEL_NAME);
+}
+
+static si_item_t *
+cache_fs_byfile(si_mod_t *si, const char *name)
+{
+	return cache_fetch_item(si, CATEGORY_FS, name, 0, SEL_NUMBER);
+}
+
+static si_list_t *
+cache_fs_all(si_mod_t *si)
+{
+	return cache_fetch_list(si, CATEGORY_FS);
+}
+
+static si_item_t *
+cache_mac_byname(si_mod_t *si, const char *name)
+{
+	return cache_fetch_item(si, CATEGORY_MAC, name, 0, SEL_NAME);
+}
+
+static si_item_t *
+cache_mac_bymac(si_mod_t *si, const char *mac)
+{
+	return cache_fetch_item(si, CATEGORY_MAC, mac, 0, SEL_NUMBER);
+}
+
+static si_list_t *
+cache_mac_all(si_mod_t *si)
+{
+	return cache_fetch_list(si, CATEGORY_MAC);
+}
+
+static si_item_t *
+cache_nameinfo(si_mod_t *si __unused, const struct sockaddr *sa __unused, int flags __unused, const char *ignored __unused, uint32_t *err)
+{
+	/*
+	 * Caching of getnameinfo(3) is not supported.
+	 * Only the individual host_byaddr and serv_byaddr responses will be cached.
+	 * This is because getnameinfo(3) returns numeric responses instead of
+	 * failing, which would poison the cache.
+	 */
+	if (err) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
+	return NULL;
+}
+
+static void
+cache_close(si_mod_t *si)
+{
+	cache_si_private_t *pp;
+	int i, j;
+
+	if (si == NULL) return;
+
+	pp = (cache_si_private_t *)si->private;
+	if (pp == NULL) return;
+
+	for (i = 0; i < CACHE_COUNT; i++)
+	{
+		si_list_release(pp->cache_store[i].list);
+
+		for (j = 0; j < CACHE_MAX; j++)
+		{
+			si_item_release(pp->cache_store[i].item[j]);
+			pp->cache_store[i].item[j] = NULL;
+		}
+		
+		pthread_mutex_destroy(&(pp->cache_store[i].mutex));
+	}
+
+	free(pp);
+}
+
+si_mod_t *
+si_module_static_cache(void)
+{
+	static const struct si_mod_vtable_s cache_vtable =
+	{
+		.sim_close = &cache_close,
+
+		.sim_user_byname = &cache_user_byname,
+		.sim_user_byuid = &cache_user_byuid,
+		.sim_user_byuuid = NULL,
+		.sim_user_all = &cache_user_all,
+
+		.sim_group_byname = &cache_group_byname,
+		.sim_group_bygid = &cache_group_bygid,
+		.sim_group_byuuid = NULL,
+		.sim_group_all = &cache_group_all,
+
+		.sim_grouplist = &cache_grouplist,
+
+		/* no netgroup support */
+		.sim_netgroup_byname = NULL,
+		.sim_in_netgroup = NULL,
+
+		.sim_alias_byname = &cache_alias_byname,
+		.sim_alias_all = &cache_alias_all,
+
+		.sim_host_byname = &cache_host_byname,
+		.sim_host_byaddr = &cache_host_byaddr,
+		.sim_host_all = &cache_host_all,
+
+		.sim_network_byname = &cache_network_byname,
+		.sim_network_byaddr = &cache_network_byaddr,
+		.sim_network_all = &cache_network_all,
+
+		.sim_service_byname = &cache_service_byname,
+		.sim_service_byport = &cache_service_byport,
+		.sim_service_all = &cache_service_all,
+
+		.sim_protocol_byname = &cache_protocol_byname,
+		.sim_protocol_bynumber = &cache_protocol_bynumber,
+		.sim_protocol_all = &cache_protocol_all,
+
+		.sim_rpc_byname = &cache_rpc_byname,
+		.sim_rpc_bynumber = &cache_rpc_bynumber,
+		.sim_rpc_all = &cache_rpc_all,
+
+		.sim_fs_byspec = &cache_fs_byspec,
+		.sim_fs_byfile = &cache_fs_byfile,
+		.sim_fs_all = &cache_fs_all,
+
+		.sim_mac_byname = &cache_mac_byname,
+		.sim_mac_bymac = &cache_mac_bymac,
+		.sim_mac_all = &cache_mac_all,
+
+		/* no addrinfo support */
+		.sim_wants_addrinfo = NULL,
+		.sim_addrinfo = NULL,
+
+		.sim_nameinfo = &cache_nameinfo,
+	};
+
+	static si_mod_t si =
+	{
+		.vers = 1,
+		.refcount = 1,
+		.flags = SI_MOD_FLAG_STATIC,
+
+		.private = NULL,
+		.vtable = &cache_vtable,
+	};
+
+	static dispatch_once_t once;
+
+	dispatch_once(&once, ^{
+		cache_si_private_t *cache;
+		int i, j;
+		
+		cache = calloc(1, sizeof(cache_si_private_t));
+		si.name = strdup("cache");
+		si.private = cache;
+
+		for (i = 0; i < CACHE_COUNT; i++) {
+			for (j = 0; j < CACHE_MAX; j++) {
+				pthread_mutex_init(&(cache->cache_store[i].mutex), NULL);
+			}
+		}
+	});
+
+	return &si;
+}
+
+void
+si_cache_add_item(si_mod_t *si, si_mod_t *src, si_item_t *item)
+{
+	cache_si_private_t *pp;
+	int head, cat;
+
+	if (si == NULL) return;
+	if (src == NULL) return;
+	if (item == NULL) return;
+
+	if (si == src) return;
+
+	if (src->name == NULL) return;
+	if (string_equal(src->name, "cache")) return;
+
+	cat = item->type;
+	if ((cat < 0) || (cat >= CACHE_COUNT)) return;
+
+	pp = (cache_si_private_t *)si->private;
+	if (pp == NULL) return;
+
+	pthread_mutex_lock(&(pp->cache_store[cat].mutex));
+
+	head = pp->cache_store[item->type].head;
+
+	si_item_release(pp->cache_store[item->type].item[head]);
+	pp->cache_store[item->type].item[head] = si_item_retain(item);
+
+	head++;
+	if (head >= CACHE_MAX) head = 0;
+	pp->cache_store[item->type].head = head;
+
+	pthread_mutex_unlock(&(pp->cache_store[cat].mutex));
+}
+
+void
+si_cache_add_list(si_mod_t *si, si_mod_t *src, si_list_t *list)
+{
+	cache_si_private_t *pp;
+	si_item_t *item;
+	int cat;
+
+	if (si == NULL) return;
+	if (src == NULL) return;
+	if (list == NULL) return;
+	if (list->count == 0) return;
+
+	if (si == src) return;
+
+	if (src->name == NULL) return;
+	if (string_equal(src->name, "cache")) return;
+
+	item = list->entry[0];
+	if (item == NULL) return;
+
+	cat = item->type;
+	if ((cat < 0) || (cat >= CACHE_COUNT)) return;
+
+	pp = (cache_si_private_t *)si->private;
+	if (pp == NULL) return;
+
+	pthread_mutex_lock(&(pp->cache_store[cat].mutex));
+
+	si_list_release(pp->cache_store[item->type].list);
+	pp->cache_store[item->type].list = si_list_retain(list);
+
+	pthread_mutex_unlock(&(pp->cache_store[cat].mutex));
+}


Property changes on: trunk/lib/libosxsupport/cache_module.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/config.h
===================================================================
--- trunk/lib/libosxsupport/config.h	                        (rev 0)
+++ trunk/lib/libosxsupport/config.h	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,32 @@
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+
+#include <TargetConditionals.h>
+
+#if __has_include(<quarantine.h>)
+#define HAVE_QUARANTINE 1
+#else
+#define HAVE_QUARANTINE 0
+#endif
+
+#if __has_include(<responsibility.h>)
+#define HAVE_RESPONSIBILITY 1
+#else
+#define HAVE_RESPONSIBILITY 0
+#endif
+
+#if __has_include(<sandbox.h>)
+#define HAVE_SANDBOX 1
+#else
+#define HAVE_SANDBOX 0
+#endif
+
+#define HAVE_LIBAUDITD !TARGET_OS_EMBEDDED
+
+#if !TARGET_OS_EMBEDDED && __has_include(<systemstats/systemstats.h>)
+#define HAVE_SYSTEMSTATS 1
+#else
+#define HAVE_SYSTEMSTATS 0
+#endif
+
+#endif /* __CONFIG_H__ */


Property changes on: trunk/lib/libosxsupport/config.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/file_module.c
===================================================================
--- trunk/lib/libosxsupport/file_module.c	                        (rev 0)
+++ trunk/lib/libosxsupport/file_module.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,2386 @@
+/*
+ * Copyright (c) 2008-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 <si_module.h>
+#include <paths.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <dirent.h>
+#include <errno.h>
+#include <notify.h>
+#include <pthread.h>
+#include <arpa/inet.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <ils.h>
+#include <dispatch/dispatch.h>
+#include <TargetConditionals.h>
+
+#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
+
+/* notify SPI */
+uint32_t notify_peek(int token, uint32_t *val);
+
+extern uint32_t gL1CacheEnabled;
+
+/* These really should be in netdb.h & etc. */
+#define _PATH_RPCS "/etc/rpc"
+#define _PATH_ALIASES "/etc/aliases"
+#define _PATH_ETHERS "/etc/ethers"
+#define _PATH_NETGROUP "/etc/netgroup"
+
+#ifndef __FreeBSD__
+static dispatch_once_t rootfs_once;
+static si_item_t *rootfs = NULL;
+#endif
+
+#define CHUNK 256
+#define FNG_MEM 0x00000010
+#define FNG_GRP 0x00000020
+
+#define forever for(;;)
+
+#define VALIDATION_PASSWD 0
+#define VALIDATION_MASTER_PASSWD 1
+#define VALIDATION_GROUP 2
+#define VALIDATION_NETGROUP 3
+#define VALIDATION_ALIASES 4
+#define VALIDATION_HOSTS 5
+#define VALIDATION_NETWORKS 6
+#define VALIDATION_SERVICES 7
+#define VALIDATION_PROTOCOLS 8
+#define VALIDATION_RPC 9
+#define VALIDATION_FSTAB 10
+#define VALIDATION_ETHERS 11
+#define VALIDATION_COUNT 12
+
+#define VALIDATION_MASK_PASSWD			0x00000001
+#define VALIDATION_MASK_MASTER_PASSWD	0x00000002
+#define VALIDATION_MASK_MASK_GROUP		0x00000004
+#define VALIDATION_MASK_NETGROUP				0x00000008
+#define VALIDATION_MASK_ALIASES			0x00000010
+#define VALIDATION_MASK_HOSTS			0x00000020
+#define VALIDATION_MASK_NETWORKS		0x00000040
+#define VALIDATION_MASK_SERVICES		0x00000080
+#define VALIDATION_MASK_PROTOCOLS		0x00000100
+#define VALIDATION_MASK_RPC				0x00000200
+#define VALIDATION_MASK_FSTAB			0x00000400
+#define VALIDATION_MASK_ETHERS			0x00000800
+
+#ifdef __FreeBSD__
+char **
+_fsi_tokenize(char *data, const char *sep, int trailing_empty, int *ntokens);
+char * _fsi_get_line(FILE *fp);
+#endif
+
+typedef struct file_netgroup_member_s
+{
+	uint32_t flags;
+	char *host;
+	char *user;
+	char *domain;
+	struct file_netgroup_member_s *next;
+} file_netgroup_member_t;
+
+typedef struct file_netgroup_s
+{
+	char *name;
+	uint32_t flags;
+	file_netgroup_member_t *members;
+	struct file_netgroup_s *next;
+} file_netgroup_t;
+
+typedef struct
+{
+	uint32_t validation_notify_mask;
+	int notify_token[VALIDATION_COUNT];
+	file_netgroup_t *file_netgroup_cache;
+	uint64_t netgroup_validation_a;
+	uint64_t netgroup_validation_b;
+} file_si_private_t;
+
+#ifndef __FreeBSD__
+static pthread_mutex_t file_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+static char *
+_fsi_copy_string(char *s)
+{
+	int len;
+	char *t;
+
+	if (s == NULL) return NULL;
+
+	len = strlen(s) + 1;
+	t = malloc(len);
+	if (t == NULL) return NULL;
+
+	bcopy(s, t, len);
+	return t;
+}
+
+static char **
+_fsi_append_string(char *s, char **l)
+{
+	int i, len;
+
+	if (s == NULL) return l;
+	if (l != NULL) {
+		for (i = 0; l[i] != NULL; i++);
+		len = i;
+	} else {
+		len = 0;
+	}
+
+	l = (char **) reallocf(l, (len + 2) * sizeof(char *));
+	if (l == NULL) return NULL;
+
+	l[len] = s;
+	l[len + 1] = NULL;
+	return l;
+}
+
+char **
+_fsi_tokenize(char *data, const char *sep, int trailing_empty, int *ntokens)
+{
+	char **tokens;
+	int p, i, start, end, more, len, end_on_sep;
+	int scanning;
+
+	tokens = NULL;
+	end_on_sep = 0;
+
+	if (data == NULL) return NULL;
+
+	if (ntokens != NULL) *ntokens = 0;
+	if (sep == NULL)
+	{
+		tokens = _fsi_append_string(data, tokens);
+		if (ntokens != NULL) *ntokens = *ntokens + 1;
+		return tokens;
+	}
+
+	len = strlen(sep);
+	p = 0;
+
+	while (data[p] != '\0')
+	{
+		end_on_sep = 1;
+		/* skip leading white space */
+		while ((data[p] == ' ') || (data[p] == '\t') || (data[p] == '\n')) p++;
+
+		/* check for end of line */
+		if (data[p] == '\0') break;
+
+		/* scan for separator */
+		start = p;
+		end = p;
+		scanning = 1;
+		end_on_sep = 0;
+
+		while (scanning == 1)
+		{
+			if (data[p] == '\0') break;
+
+			for (i = 0; i < len; i++)
+			{
+				if (data[p] == sep[i])
+				{
+					scanning = 0;
+					end_on_sep = 1;
+					break;
+				}
+			}
+
+			/* end is last non-whitespace character */
+			if ((scanning == 1) && (data[p] != ' ') && (data[p] != '\t') && (data[p] != '\n')) end = p;
+
+			p += scanning;
+		}
+
+		/* see if there's data left after p */
+		more = 0;
+		if (data[p] != '\0') more = 1;
+
+		/* set the character following the token to nul */
+		if (start == p) data[p] = '\0';
+		else data[end + 1] = '\0';
+
+		tokens = _fsi_append_string(data + start, tokens);
+		if (ntokens != NULL) *ntokens = *ntokens + 1;
+		p += more;
+	}
+
+	if ((end_on_sep == 1) && (trailing_empty != 0))
+	{
+		/* if the scan ended on an empty token, add a null string */
+		tokens = _fsi_append_string(data + p, tokens);
+		if (ntokens != NULL) *ntokens = *ntokens + 1;
+	}
+
+	return tokens;
+}
+
+char *
+_fsi_get_line(FILE *fp)
+{
+	char s[4096];
+	char *out;
+
+	s[0] = '\0';
+
+	fgets(s, sizeof(s), fp);
+	if ((s == NULL) || (s[0] == '\0')) return NULL;
+
+	if (s[0] != '#') s[strlen(s) - 1] = '\0';
+
+	out = _fsi_copy_string(s);
+	return out;
+}
+
+#ifndef __FreeBSD__
+static const char *
+_fsi_validation_path(int vtype)
+{
+	if (vtype == VALIDATION_PASSWD) return _PATH_PASSWD;
+	else if (vtype == VALIDATION_MASTER_PASSWD) return _PATH_MASTERPASSWD;
+	else if (vtype == VALIDATION_GROUP) return _PATH_GROUP;
+	else if (vtype == VALIDATION_NETGROUP) return _PATH_NETGROUP;
+	else if (vtype == VALIDATION_ALIASES) return _PATH_ALIASES;
+	else if (vtype == VALIDATION_HOSTS) return _PATH_HOSTS;
+	else if (vtype == VALIDATION_NETWORKS) return _PATH_NETWORKS;
+	else if (vtype == VALIDATION_SERVICES) return _PATH_SERVICES;
+	else if (vtype == VALIDATION_PROTOCOLS) return _PATH_PROTOCOLS;
+	else if (vtype == VALIDATION_RPC) return _PATH_RPCS;
+	else if (vtype == VALIDATION_FSTAB) return _PATH_FSTAB;
+	else if (vtype == VALIDATION_ETHERS) return _PATH_ETHERS;
+
+	return NULL;
+}
+
+static void
+_fsi_get_validation(si_mod_t *si, int vtype, const char *path, FILE *f, uint64_t *a, uint64_t *b)
+{
+	struct stat sb;
+	file_si_private_t *pp;
+	uint32_t peek, bit;
+	int status;
+
+	if (a != NULL) *a = 0;
+	if (b != NULL) *b = 0;
+
+	if (si == NULL) return;
+	if (path == NULL) return;
+	if (gL1CacheEnabled == 0) return;
+
+	pp = (file_si_private_t *)si->private;
+	if (pp == NULL) return;
+
+	if (vtype >= VALIDATION_COUNT) return;
+
+	bit = 1 << vtype;
+	if (bit & pp->validation_notify_mask)
+	{
+		/* use notify validation for this type */
+		if (pp->notify_token[vtype] < 0)
+		{
+			char *str = NULL;
+			asprintf(&str, "com.apple.system.info:%s", path);
+			if (str == NULL) return;
+
+			status = notify_register_check(str, &(pp->notify_token[vtype]));
+			free(str);
+		}
+
+		if (a != NULL)
+		{
+			status = notify_peek(pp->notify_token[vtype], &peek);
+			if (status == NOTIFY_STATUS_OK) *a = ntohl(peek);
+		}
+
+		if (b != NULL) *b = vtype;
+	}
+	else
+	{
+		/* use stat() and last mod time for this type */
+		memset(&sb, 0, sizeof(struct stat));
+		if (f != NULL)
+		{
+			if (fstat(fileno(f), &sb) == 0)
+			{
+				if (a != NULL) *a = sb.st_mtimespec.tv_sec;
+				if (b != NULL) *b = sb.st_mtimespec.tv_nsec;
+			}
+		}
+		else
+		{
+			path = _fsi_validation_path(vtype);
+			if (path != NULL)
+			{
+				memset(&sb, 0, sizeof(struct stat));
+				if (stat(path, &sb) == 0)
+				{
+					if (a != NULL) *a = sb.st_mtimespec.tv_sec;
+					if (b != NULL) *b = sb.st_mtimespec.tv_nsec;
+				}
+			}
+		}
+	}
+}
+
+static int
+_fsi_validate(si_mod_t *si, int cat, uint64_t va, uint64_t vb)
+{
+	struct stat sb;
+	const char *path;
+	uint32_t item_val, curr_val, vtype;
+	file_si_private_t *pp;
+	int status;
+
+	if (si == NULL) return 0;
+
+#if TARGET_OS_EMBEDDED
+	/* /etc is on a read-only filesystem, so no validation is required */
+	return 1;
+#endif
+
+	pp = (file_si_private_t *)si->private;
+	if (pp == NULL) return 0;
+
+	vtype = UINT32_MAX;
+	switch (cat)
+	{
+		case CATEGORY_USER:
+		{
+			if (geteuid() == 0) vtype = VALIDATION_MASTER_PASSWD;
+			else vtype = VALIDATION_PASSWD;
+			break;
+		}
+		case CATEGORY_GROUP:
+		{
+			vtype = VALIDATION_GROUP;
+			break;
+		}
+		case CATEGORY_GROUPLIST:
+		{
+			vtype = VALIDATION_GROUP;
+			break;
+		}
+		case CATEGORY_NETGROUP:
+		{
+			vtype = VALIDATION_NETGROUP;
+			break;
+		}
+		case CATEGORY_ALIAS:
+		{
+			vtype = VALIDATION_ALIASES;
+			break;
+		}
+		case CATEGORY_HOST_IPV4:
+		{
+			vtype = VALIDATION_HOSTS;
+			break;
+		}
+		case CATEGORY_HOST_IPV6:
+		{
+			vtype = VALIDATION_HOSTS;
+			break;
+		}
+		case CATEGORY_NETWORK:
+		{
+			vtype = VALIDATION_NETWORKS;
+			break;
+		}
+		case CATEGORY_SERVICE:
+		{
+			vtype = VALIDATION_SERVICES;
+			break;
+		}
+		case CATEGORY_PROTOCOL:
+		{
+			vtype = VALIDATION_PROTOCOLS;
+			break;
+		}
+		case CATEGORY_RPC:
+		{
+			vtype = VALIDATION_RPC;
+			break;
+		}
+		case CATEGORY_FS:
+		{
+			vtype = VALIDATION_FSTAB;
+			break;
+		}
+		case CATEGORY_MAC:
+		{
+			vtype = VALIDATION_ETHERS;
+			break;
+		}
+		default: return 0;
+	}
+
+	if (pp->notify_token[vtype] < 0)
+	{
+		path = _fsi_validation_path(vtype);
+		if (path == NULL) return 0;
+
+		memset(&sb, 0, sizeof(struct stat));
+		if (stat(path, &sb) != 0) return 0;
+		if (va != sb.st_mtimespec.tv_sec) return 0;
+		if (vb != sb.st_mtimespec.tv_nsec) return 0;
+	}
+	else
+	{
+		item_val = va;
+		curr_val = -1;
+		status = notify_peek(pp->notify_token[vtype], &curr_val);
+		if (status != NOTIFY_STATUS_OK) return 0;
+
+		curr_val = ntohl(curr_val);
+		if (item_val != curr_val) return 0;
+	}
+
+	return 1;
+}
+
+/* netgroup support */
+static char *
+_fsi_append_char_to_line(char c, char *buf, size_t *x)
+{
+	if (x == NULL) return NULL;
+
+	if (buf == NULL) *x = 0;
+
+	if ((*x % CHUNK) == 0)
+	{
+		buf = reallocf(buf, *x + CHUNK);
+		memset(buf + *x, 0, CHUNK);
+	}
+
+	buf[*x] = c;
+	*x = *x + 1;
+
+	return buf;
+}
+
+static char *
+_fsi_read_netgroup_line(FILE *f)
+{
+	char *out = NULL;
+	size_t x = 0;
+	int white = 0;
+	int paren = 0;
+
+	if (f == NULL) return NULL;
+	forever
+	{
+		int c = getc(f);
+
+		if (c == EOF)
+		{
+			if (out == NULL) return NULL;
+			return _fsi_append_char_to_line('\0', out, &x);
+		}
+
+		if (c == '\n') return _fsi_append_char_to_line('\0', out, &x);
+		if (c == '(') paren = 1;
+		else if (c == ')') paren = 0;
+
+		if ((c == ' ') || (c == '\t'))
+		{
+			if ((white == 0) && (paren == 0)) out = _fsi_append_char_to_line(' ', out, &x);
+			white = 1;
+		}
+		else if (c == '\\')
+		{
+			forever
+			{
+				c = getc(f);
+				if (c == EOF) return _fsi_append_char_to_line('\0', out, &x);
+				if (c == '\n') break;
+			}
+		}
+		else
+		{
+			out = _fsi_append_char_to_line(c, out, &x);
+			white = 0;
+		}
+	}
+}
+
+static file_netgroup_t *
+_fsi_find_netgroup(file_netgroup_t **list, const char *name, int create)
+{
+	file_netgroup_t *n;
+
+	if (list == NULL) return NULL;
+
+	for (n = *list; n != NULL; n = n->next)
+	{
+		if (!strcmp(name, n->name)) return n;
+	}
+
+	if (create == 0) return NULL;
+
+	n = (file_netgroup_t *)calloc(1, sizeof(file_netgroup_t));
+	if (n == NULL) return NULL;
+
+	n->name = strdup(name);
+
+	n->next = *list;
+	*list = n;
+	return n;
+}
+
+void
+_fsi_free_file_netgroup(file_netgroup_t *n)
+{
+	file_netgroup_member_t *m;
+
+	if (n == NULL) return;
+	free(n->name);
+
+	m = n->members;
+	while (m != NULL)
+	{
+		file_netgroup_member_t *x = m;
+		m = m->next;
+		free(x->host);
+		free(x->user);
+		free(x->domain);
+		free(x);
+	}
+
+	free(n);
+}
+
+static void
+_fsi_add_netgroup_group(file_netgroup_t *n, char *grp)
+{
+	file_netgroup_member_t *g;
+
+	if (n == NULL) return;
+
+	g = (file_netgroup_member_t *)calloc(1, sizeof(file_netgroup_member_t));
+	if (g == NULL) return;
+
+	g->flags = FNG_GRP;
+	g->host = strdup(grp);
+
+	g->next = n->members;
+	n->members = g;
+
+	return;
+}
+
+static void
+_fsi_add_netgroup_member(file_netgroup_t *n, char *mem)
+{
+	char **tokens;
+	file_netgroup_member_t *m;
+	int ntokens;
+
+	if (n == NULL) return;
+
+	m = (file_netgroup_member_t *)calloc(1, sizeof(file_netgroup_member_t));
+	if (m == NULL) return;
+
+	tokens = _fsi_tokenize(mem + 1, ",)", 0, &ntokens);
+
+	if (tokens == NULL)
+	{
+		free(m);
+		return;
+	}
+
+	if ((ntokens > 0) && (tokens[0][0] != '\0')) m->host = strdup(tokens[0]);
+	if ((ntokens > 1) && (tokens[1][0] != '\0')) m->user = strdup(tokens[1]);
+	if ((ntokens > 2) && (tokens[2][0] != '\0')) m->domain = strdup(tokens[2]);
+
+	free(tokens);
+
+	m->flags = FNG_MEM;
+	m->next = n->members;
+	n->members = m;
+}
+
+static file_netgroup_t *
+_fsi_process_netgroup_line(file_netgroup_t **pass1, char *line)
+{
+	file_netgroup_t *n;
+	char **tokens;
+	int i, ntokens = 0;
+
+	tokens = _fsi_tokenize(line, " ", 0, &ntokens);
+	if (tokens == NULL) return NULL;
+	if (tokens[0] == NULL)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	n = _fsi_find_netgroup(pass1, tokens[0], 1);
+
+	for (i = 1; tokens[i] != NULL; i++)
+	{
+		if (tokens[i][0] == '(') _fsi_add_netgroup_member(n, tokens[i]);
+		else if (tokens[i][0] != '\0') _fsi_add_netgroup_group(n, tokens[i]);
+	}
+
+	free(tokens);
+	return n;
+}
+
+static void
+_fsi_flatten_netgroup(file_netgroup_t *pass1, file_netgroup_t **top, file_netgroup_t *n, file_netgroup_member_t *m)
+{
+	if (n == NULL) return;
+
+	if (n->flags == 1) return;
+	n->flags = 1;
+
+	if (*top == NULL)
+	{
+		*top = (file_netgroup_t *)calloc(1, sizeof(file_netgroup_t));
+		if (*top == NULL) return;
+		(*top)->name = strdup(n->name);
+		if ((*top)->name == NULL)
+		{
+			free(*top);
+			*top = NULL;
+			return;
+		}
+	}
+
+	while (m!= NULL)
+	{
+		if (m->flags & FNG_MEM)
+		{
+			file_netgroup_member_t *x = (file_netgroup_member_t *)calloc(1, sizeof(file_netgroup_member_t));
+			if (x == NULL) return;
+
+			x->flags = FNG_MEM;
+			if (m->host != NULL) x->host = strdup(m->host);
+			if (m->user != NULL) x->user = strdup(m->user);
+			if (m->domain != NULL) x->domain = strdup(m->domain);
+
+			x->next = (*top)->members;
+			(*top)->members = x;
+		}
+		else
+		{
+			file_netgroup_t *g = _fsi_find_netgroup(&pass1, m->host, 0);
+			if (g == NULL) continue;
+
+			_fsi_flatten_netgroup(pass1, top, g, g->members);
+		}
+
+		m = m->next;
+	}
+}
+
+static void
+_fsi_check_netgroup_cache(si_mod_t *si)
+{
+	file_netgroup_t *p1, *n, *x, *a;
+	char *line;
+	FILE *f;
+	file_si_private_t *pp;
+
+	if (si == NULL) return;
+
+	pp = (file_si_private_t *)si->private;
+	if (pp == NULL) return;
+
+	pthread_mutex_lock(&file_mutex);
+
+	if (_fsi_validate(si, CATEGORY_NETGROUP, pp->netgroup_validation_a, pp->netgroup_validation_b))
+	{
+		pthread_mutex_unlock(&file_mutex);
+		return;
+	}
+
+	n = pp->file_netgroup_cache;
+	while (n != NULL)
+	{
+		x = n;
+		n = n->next;
+		_fsi_free_file_netgroup(x);
+	}
+
+	pp->file_netgroup_cache = NULL;
+
+	f = fopen(_PATH_NETGROUP, "r");
+	if (f == NULL)
+	{
+		pthread_mutex_unlock(&file_mutex);
+		return;
+	}
+
+	_fsi_get_validation(si, VALIDATION_NETGROUP, _PATH_NETGROUP, f, &(pp->netgroup_validation_a), &(pp->netgroup_validation_b));
+
+	p1 = NULL;
+
+	line = _fsi_read_netgroup_line(f);
+	while (line != NULL)
+	{
+		n = _fsi_process_netgroup_line(&p1, line);
+
+		free(line);
+		line = _fsi_read_netgroup_line(f);
+	}
+
+	fclose(f);
+
+	for (n = p1; n != NULL; n = n->next)
+	{
+		a = NULL;
+		_fsi_flatten_netgroup(p1, &a, n, n->members);
+		for (x = p1; x != NULL; x = x->next) x->flags = 0;
+
+		if (a != NULL)
+		{
+			a->next = pp->file_netgroup_cache;
+			pp->file_netgroup_cache = a;
+		}
+	}
+
+	n = p1;
+	while (n != NULL)
+	{
+		x = n;
+		n = n->next;
+		_fsi_free_file_netgroup(x);
+	}
+
+	pthread_mutex_unlock(&file_mutex);
+}
+
+/* USERS */
+#ifndef __FreeBSD__
+static si_item_t *
+_fsi_parse_user(si_mod_t *si, const char *name, uid_t uid, int which, char *data, int format, uint64_t va, uint64_t vb)
+{
+	char **tokens;
+	int ntokens, match;
+	time_t change, expire;
+	si_item_t *item;
+	uid_t xuid;
+
+	if (data == NULL) return NULL;
+
+	ntokens = 0;
+	tokens = _fsi_tokenize(data, ":", 1, &ntokens);
+	if (((format == 0) && (ntokens != 10)) || ((format == 1) && (ntokens !=  7)))
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	xuid = atoi(tokens[2]);
+	match = 0;
+
+	/* XXX MATCH GECOS? XXX*/
+	if (which == SEL_ALL) match = 1;
+	else if ((which == SEL_NAME) && (string_equal(name, tokens[0]))) match = 1;
+	else if ((which == SEL_NUMBER) && (uid == xuid)) match = 1;
+
+	if (match == 0)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	if (format == 0)
+	{
+		/* master.passwd: name[0] passwd[1] uid[2] gid[3] class[4] change[5] expire[6] gecos[7] dir[8] shell[9] */
+		/* struct pwd: name[0] passwd[1] uid[2] gid[3] change[5] class[4] gecos[7] dir[8] shell[9] expire[6] */
+		change = atoi(tokens[5]);
+		expire = atoi(tokens[6]);
+		item = (si_item_t *)LI_ils_create("L4488ss44LssssL", (unsigned long)si, CATEGORY_USER, 1, va, vb, tokens[0], tokens[1], xuid, atoi(tokens[3]), change, tokens[4], tokens[7], tokens[8], tokens[9], expire);
+	}
+	else
+	{
+		/* passwd: name[0] passwd[1] uid[2] gid[3] gecos[4] dir[5] shell[6] */
+		/* struct pwd: name[0] passwd[1] uid[2] gid[3] change[-] class[-] gecos[4] dir[5] shell[6] expire[-] */
+		item = (si_item_t *)LI_ils_create("L4488ss44LssssL", (unsigned long)si, CATEGORY_USER, 1, va, vb, tokens[0], tokens[1], xuid, atoi(tokens[3]), 0, "", tokens[4], tokens[5], tokens[6], 0);
+	}
+
+	free(tokens); 
+	return item;
+}
+#endif
+
+static void *
+_fsi_get_user(si_mod_t *si, const char *name, uid_t uid, int which)
+{
+	char *line;
+	si_item_t *item;
+	int fmt;
+	FILE *f;
+	si_list_t *all;
+	uint64_t va, vb;
+
+	if ((which == SEL_NAME) && (name == NULL)) return NULL;
+
+	all = NULL;
+	f = NULL;
+	fmt = 0;
+	va = 0;
+	vb = 0;
+
+	if (geteuid() == 0)
+	{
+		f = fopen(_PATH_MASTERPASSWD, "r");
+		_fsi_get_validation(si, VALIDATION_MASTER_PASSWD, _PATH_MASTERPASSWD, f, &va, &vb);
+	}
+	else
+	{
+		f = fopen(_PATH_PASSWD, "r");
+		_fsi_get_validation(si, VALIDATION_PASSWD, _PATH_PASSWD, f, &va, &vb);
+		fmt = 1;
+	}
+
+	if (f == NULL) return NULL;
+
+
+	forever
+	{
+		line = _fsi_get_line(f);
+		if (line == NULL) break;
+
+		if (line[0] == '#') 
+		{
+			free(line);
+			line = NULL;
+			continue;
+		}
+
+		item = _fsi_parse_user(si, name, uid, which, line, fmt, va, vb);
+		free(line);
+		line = NULL;
+
+		if (item == NULL) continue;
+
+		if (which == SEL_ALL)
+		{
+			all = si_list_add(all, item);
+			si_item_release(item);
+			continue;
+		}
+
+		fclose(f);
+		return item;
+	}
+	fclose(f);
+	return all;
+}
+
+/* GROUPS */
+#ifndef __FreeBSD__
+
+static si_item_t *
+_fsi_parse_group(si_mod_t *si, const char *name, gid_t gid, int which, char *data, uint64_t va, uint64_t vb)
+{
+	char **tokens, **members;
+	int ntokens, match;
+	si_item_t *item;
+	gid_t xgid;
+
+	if (data == NULL) return NULL;
+
+	ntokens = 0;
+	tokens = _fsi_tokenize(data, ":", 1, &ntokens);
+	if (ntokens != 4)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	xgid = atoi(tokens[2]);
+	match = 0;
+
+	if (which == SEL_ALL) match = 1;
+	else if ((which == SEL_NAME) && (string_equal(name, tokens[0]))) match = 1;
+	else if ((which == SEL_NUMBER) && (gid == xgid)) match = 1;
+
+	if (match == 0)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	ntokens = 0;
+	members = _fsi_tokenize(tokens[3], ",", 1, &ntokens);
+
+	item = (si_item_t *)LI_ils_create("L4488ss4*", (unsigned long)si, CATEGORY_GROUP, 1, va, vb, tokens[0], tokens[1], xgid, members);
+
+	free(tokens); 
+	free(members);
+
+	return item;
+}
+#endif
+static void *
+_fsi_get_group(si_mod_t *si, const char *name, gid_t gid, int which)
+{
+	char *line;
+	si_item_t *item;
+	FILE *f;
+	si_list_t *all;
+	uint64_t va, vb;
+
+	if ((which == SEL_NAME) && (name == NULL)) return NULL;
+
+	all = NULL;
+	f = NULL;
+
+	f = fopen(_PATH_GROUP, "r");
+	if (f == NULL) return NULL;
+
+	_fsi_get_validation(si, VALIDATION_GROUP, _PATH_GROUP, f, &va, &vb);
+
+	forever
+	{
+		line = _fsi_get_line(f);
+		if (line == NULL) break;
+
+		if (line[0] == '#') 
+		{
+			free(line);
+			line = NULL;
+			continue;
+		}
+
+		item = _fsi_parse_group(si, name, gid, which, line, va, vb);
+		free(line);
+		line = NULL;
+
+		if (item == NULL) continue;
+
+		if (which == SEL_ALL)
+		{
+			all = si_list_add(all, item);
+			si_item_release(item);
+			continue;
+		}
+
+		fclose(f);
+		return item;
+	}
+
+	fclose(f);
+	return all;
+}
+
+static void *
+_fsi_get_grouplist(si_mod_t *si, const char *user)
+{
+	char **tokens, **members;
+	int ntokens, i, match, gidcount;
+	char *line;
+	si_item_t *item;
+	FILE *f;
+	uint64_t va, vb;
+	gid_t gid, basegid;
+	gid_t *gidlist;
+	struct passwd *pw;
+
+	if (user == NULL) return NULL;
+
+	gidlist = NULL;
+	gidcount = 0;
+	f = NULL;
+	basegid = -1;
+
+	item = si->vtable->sim_user_byname(si, user);
+	if (item != NULL)
+	{
+		pw = (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
+		basegid = pw->pw_gid;
+		si_item_release(item);
+		item = NULL;
+	}
+
+	f = fopen(_PATH_GROUP, "r");
+	if (f == NULL) return NULL;
+
+	_fsi_get_validation(si, VALIDATION_GROUP, _PATH_GROUP, f, &va, &vb);
+
+	forever
+	{
+		line = _fsi_get_line(f);
+		if (line == NULL) break;
+
+		if (line[0] == '#') 
+		{
+			free(line);
+			line = NULL;
+			continue;
+		}
+
+		ntokens = 0;
+		tokens = _fsi_tokenize(line, ":", 1, &ntokens);
+		if (ntokens != 4)
+		{
+			free(tokens);
+			continue;
+		}
+
+		ntokens = 0;
+		members = _fsi_tokenize(tokens[3], ",", 1, &ntokens);
+
+		match = 0;
+		gid = -2;
+
+		for (i = 0; i < ntokens; i++)
+		{
+			if (string_equal(user, members[i]))
+			{
+				gid = atoi(tokens[2]);
+				match = 1;
+				break;
+			}
+		}
+
+		free(tokens); 
+		free(members);
+		free(line);
+		line = NULL;
+
+		if (match == 1)
+		{
+			gidlist = (gid_t *) reallocf(gidlist, (gidcount + 1) * sizeof(gid_t));
+			if (gidlist == NULL)
+			{
+				gidcount = 0;
+				break;
+			}
+
+			gidlist[gidcount++] = gid;
+		}
+	}
+
+	fclose(f);
+
+	if (gidcount != 0) {
+		item = (si_item_t *)LI_ils_create("L4488s4@", (unsigned long)si, CATEGORY_GROUPLIST, 1, va, vb, user, gidcount, 
+										  gidcount * sizeof(gid_t), gidlist);
+	}
+
+	free(gidlist);
+
+	return item;
+}
+
+/* ALIASES */
+
+static si_item_t *
+_fsi_parse_alias(si_mod_t *si, const char *name, int which, char *data, uint64_t va, uint64_t vb)
+{
+	char **tokens, **members;
+	int ntokens, match;
+	si_item_t *item;
+
+	if (data == NULL) return NULL;
+
+	ntokens = 0;
+	tokens = _fsi_tokenize(data, ":", 1, &ntokens);
+	if (ntokens < 2)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	match = 0;
+
+	if (which == SEL_ALL) match = 1;
+	else if (string_equal(name, tokens[0])) match = 1;
+
+	if (match == 0)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	ntokens = 0;
+	members = _fsi_tokenize(tokens[1], ",", 1, &ntokens);
+
+	item = (si_item_t *)LI_ils_create("L4488s4*4", (unsigned long)si, CATEGORY_ALIAS, 1, va, vb, tokens[0], ntokens, members, 1);
+
+	free(tokens); 
+	free(members);
+
+	return item;
+}
+
+static void *
+_fsi_get_alias(si_mod_t *si, const char *name, int which)
+{
+	char *line;
+	si_item_t *item;
+	FILE *f;
+	si_list_t *all;
+	uint64_t va, vb;
+
+	if ((which == SEL_NAME) && (name == NULL)) return NULL;
+
+	all = NULL;
+	f = NULL;
+
+	f = fopen(_PATH_ALIASES, "r");
+	if (f == NULL) return NULL;
+
+	_fsi_get_validation(si, VALIDATION_ALIASES, _PATH_ALIASES, f, &va, &vb);
+
+	forever
+	{
+		line = _fsi_get_line(f);
+		if (line == NULL) break;
+
+		if (line[0] == '#') 
+		{
+			free(line);
+			line = NULL;
+			continue;
+		}
+
+		item = _fsi_parse_alias(si, name, which, line, va, vb);
+		free(line);
+		line = NULL;
+
+		if (item == NULL) continue;
+
+		if (which == SEL_ALL)
+		{
+			all = si_list_add(all, item);
+			si_item_release(item);
+			continue;
+		}
+
+		fclose(f);
+		return item;
+	}
+
+	fclose(f);
+	return all;
+}
+
+/* ETHERS */
+
+static si_item_t *
+_fsi_parse_ether(si_mod_t *si, const char *name, int which, char *data, uint64_t va, uint64_t vb)
+{
+	char **tokens;
+	char *cmac;
+	int ntokens, match;
+	si_item_t *item;
+
+	if (data == NULL) return NULL;
+
+	ntokens = 0;
+	tokens = _fsi_tokenize(data, " \t", 1, &ntokens);
+	if (ntokens != 2)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	cmac = si_standardize_mac_address(tokens[0]);
+	if (cmac == NULL)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	match = 0;
+	if (which == SEL_ALL) match = 1;
+	else if ((which == SEL_NAME) && (string_equal(name, tokens[1]))) match = 1;
+	else if ((which == SEL_NUMBER) && (string_equal(name, cmac))) match = 1;
+
+	if (match == 0)
+	{
+		free(tokens);
+		free(cmac);
+		return NULL;
+	}
+
+	item = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_MAC, 1, va, vb, tokens[1], cmac);
+
+	free(tokens); 
+	free(cmac);
+
+	return item;
+}
+
+static void *
+_fsi_get_ether(si_mod_t *si, const char *name, int which)
+{
+	char *line, *cmac;
+	si_item_t *item;
+	FILE *f;
+	si_list_t *all;
+	uint64_t va, vb;
+
+	if ((which != SEL_ALL) && (name == NULL)) return NULL;
+
+	cmac = NULL;
+	if (which == SEL_NUMBER)
+	{
+		cmac = si_standardize_mac_address(name);
+		if (cmac == NULL) return NULL;
+	}
+
+	all = NULL;
+	f = NULL;
+
+	f = fopen(_PATH_ETHERS, "r");
+	if (f == NULL) return NULL;
+
+	_fsi_get_validation(si, VALIDATION_ETHERS, _PATH_ETHERS, f, &va, &vb);
+
+	forever
+	{
+		line = _fsi_get_line(f);
+		if (line == NULL) break;
+
+		if (line[0] == '#') 
+		{
+			free(line);
+			line = NULL;
+			continue;
+		}
+
+		item = NULL;
+		if (which == SEL_NUMBER) item = _fsi_parse_ether(si, cmac, which, line, va, vb);
+		else item = _fsi_parse_ether(si, name, which, line, va, vb);
+
+		free(line);
+		line = NULL;
+
+		if (item == NULL) continue;
+
+		if (which == SEL_ALL)
+		{
+			all = si_list_add(all, item);
+			si_item_release(item);
+			continue;
+		}
+
+		fclose(f);
+		return item;
+	}
+
+	fclose(f);
+	return all;
+}
+
+/* HOSTS */
+
+static si_item_t *
+_fsi_parse_host(si_mod_t *si, const char *name, const void *addr, int af, int which, char *data, uint64_t va, uint64_t vb)
+{
+	char **tokens, **h_aliases, *null_alias;
+	int i, ntokens, match, h_addrtype, h_length;
+	struct in_addr a4;
+	struct in6_addr a6;
+	si_item_t *item;
+	char *h_addr_list[2];
+	char h_addr_4[4], h_addr_6[16];
+
+	if (data == NULL) return NULL;
+
+	null_alias = NULL;
+
+	ntokens = 0;
+	tokens = _fsi_tokenize(data, " 	", 0, &ntokens);
+	if (ntokens < 2)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	h_addr_list[1] = NULL;
+
+	h_addrtype = AF_UNSPEC;
+	if (inet_pton(AF_INET, tokens[0], &a4) == 1)
+	{
+		h_addrtype = AF_INET;
+		h_length = sizeof(struct in_addr);
+		memcpy(h_addr_4, &a4, 4);
+		h_addr_list[0] = h_addr_4;
+	}
+	else if (inet_pton(AF_INET6, tokens[0], &a6) == 1)
+	{
+		h_addrtype = AF_INET6;
+		h_length = sizeof(struct in6_addr);
+		memcpy(h_addr_6, &a6, 16);
+		h_addr_list[0] = h_addr_6;
+	}
+
+	if (h_addrtype == AF_UNSPEC)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	h_aliases = NULL;
+	if (ntokens > 2) h_aliases = &(tokens[2]);
+
+	match = 0;
+
+	if (which == SEL_ALL) match = 1;
+	else
+	{
+		if (h_addrtype == af)
+		{
+			if (which == SEL_NAME)
+			{
+				if (string_equal(name, tokens[1])) match = 1;
+				else if (h_aliases != NULL)
+				{
+					for (i = 0; (h_aliases[i] != NULL) && (match == 0); i++)
+						if (string_equal(name, h_aliases[i])) match = 1;
+				}
+			}
+			else if (which == SEL_NUMBER)
+			{
+				if (memcmp(addr, h_addr_list[0], h_length) == 0) match = 1;
+			}
+		}
+	}
+
+	if (match == 0)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	item = NULL;
+
+	if (h_aliases == NULL) h_aliases = &null_alias;
+
+	if (h_addrtype == AF_INET)
+	{
+		item = (si_item_t *)LI_ils_create("L4488s*44a", (unsigned long)si, CATEGORY_HOST_IPV4, 1, va, vb, tokens[1], h_aliases, h_addrtype, h_length, h_addr_list);
+	}
+	else
+	{
+		item = (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, va, vb, tokens[1], h_aliases, h_addrtype, h_length, h_addr_list);
+	}
+
+	free(tokens);
+
+	return item;
+}
+
+static void *
+_fsi_get_host(si_mod_t *si, const char *name, const void *addr, int af, int which, uint32_t *err)
+{
+	char *line;
+	si_item_t *item;
+	FILE *f;
+	si_list_t *all;
+	uint64_t va, vb;
+
+	if ((which == SEL_NAME) && (name == NULL))
+	{
+		if (err != NULL) *err = NO_RECOVERY;
+		return NULL;
+	}
+
+	if ((which == SEL_NUMBER) && (addr == NULL))
+	{
+		if (err != NULL) *err = NO_RECOVERY;
+		return NULL;
+	}
+
+	f = fopen(_PATH_HOSTS, "r");
+	if (f == NULL)
+	{
+		if (err != NULL) *err = NO_RECOVERY;
+		return NULL;
+	}
+
+	_fsi_get_validation(si, VALIDATION_HOSTS, _PATH_HOSTS, f, &va, &vb);
+
+	all = NULL;
+
+	forever
+	{
+		line = _fsi_get_line(f);
+		if (line == NULL) break;
+
+		if (line[0] == '#') 
+		{
+			free(line);
+			line = NULL;
+			continue;
+		}
+
+		item = _fsi_parse_host(si, name, addr, af, which, line, va, vb);
+		free(line);
+		line = NULL;
+
+		if (item == NULL) continue;
+
+		if (which == SEL_ALL)
+		{
+			all = si_list_add(all, item);
+			si_item_release(item);
+			continue;
+		}
+
+		fclose(f);
+		return item;
+	}
+
+	fclose(f);
+	return all;
+}
+
+/* SERVICE */
+
+static si_item_t *
+_fsi_parse_service(si_mod_t *si, const char *name, const char *proto, int port, int which, char *data, uint64_t va, uint64_t vb)
+{
+	char **tokens, **s_aliases, *xproto;
+	int i, ntokens, match;
+	si_item_t *item;
+	int xport;
+
+	if (data == NULL) return NULL;
+
+	port = ntohs(port);
+
+	ntokens = 0;
+	tokens = _fsi_tokenize(data, " 	", 0, &ntokens);
+	if (ntokens < 2)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	s_aliases = NULL;
+	if (ntokens > 2) s_aliases = &(tokens[2]);
+
+	xport = atoi(tokens[1]);
+
+	xproto = strchr(tokens[1], '/');
+
+	if (xproto == NULL)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	*xproto++ = '\0';
+	if ((proto != NULL) && (string_not_equal(proto, xproto)))
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	match = 0;
+	if (which == SEL_ALL) match = 1;
+	else if (which == SEL_NAME)
+	{
+		if (string_equal(name, tokens[0])) match = 1;
+		else if (s_aliases != NULL)
+		{
+			for (i = 0; (s_aliases[i] != NULL) && (match == 0); i++)
+				if (string_equal(name, s_aliases[i])) match = 1;
+		}
+	}
+	else if ((which == SEL_NUMBER) && (port == xport)) match = 1;
+
+	if (match == 0)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	/* strange but correct */
+	xport = htons(xport);
+
+	item = (si_item_t *)LI_ils_create("L4488s*4s", (unsigned long)si, CATEGORY_SERVICE, 1, va, vb, tokens[0], s_aliases, xport, xproto);
+
+	free(tokens);
+
+	return item;
+}
+
+static void *
+_fsi_get_service(si_mod_t *si, const char *name, const char *proto, int port, int which)
+{
+	char *p, *line;
+	si_item_t *item;
+	FILE *f;
+	si_list_t *all;
+	uint64_t va, vb;
+
+	if ((which == SEL_NAME) && (name == NULL)) return NULL;
+	if ((which == SEL_NUMBER) && (port == 0)) return NULL;
+
+	f = fopen(_PATH_SERVICES, "r");
+	if (f == NULL) return NULL;
+
+	_fsi_get_validation(si, VALIDATION_SERVICES, _PATH_SERVICES, f, &va, &vb);
+
+	all = NULL;
+
+	forever
+	{
+		line = _fsi_get_line(f);
+		if (line == NULL) break;
+
+		if (line[0] == '#') 
+		{
+			free(line);
+			line = NULL;
+			continue;
+		}
+
+		p = strchr(line, '#');
+		if (p != NULL) *p = '\0';
+
+		item = _fsi_parse_service(si, name, proto, port, which, line, va, vb);
+		free(line);
+		line = NULL;
+
+		if (item == NULL) continue;
+
+		if (which == SEL_ALL)
+		{
+			all = si_list_add(all, item);
+			si_item_release(item);
+			continue;
+		}
+
+		fclose(f);
+		return item;
+	}
+
+	fclose(f);
+	return all;
+}
+
+/*
+ * Generic name/number/aliases lookup
+ * Works for protocols, networks, and rpcs
+ */
+
+static si_item_t *
+_fsi_parse_name_num_aliases(si_mod_t *si, const char *name, int num, int which, char *data, uint64_t va, uint64_t vb, int cat)
+{
+	char **tokens, **aliases;
+	int i, ntokens, match, xnum;
+	si_item_t *item;
+
+	if (data == NULL) return NULL;
+
+	ntokens = 0;
+	tokens = _fsi_tokenize(data, " 	", 0, &ntokens);
+	if (ntokens < 2)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	xnum = atoi(tokens[1]);
+
+	aliases = NULL;
+	if (ntokens > 2) aliases = &(tokens[2]);
+
+	match = 0;
+
+	if (which == SEL_ALL) match = 1;
+	else if (which == SEL_NAME)
+	{
+		if (string_equal(name, tokens[0])) match = 1;
+		else if (aliases != NULL)
+		{
+			for (i = 0; (aliases[i] != NULL) && (match == 0); i++)
+				if (string_equal(name, aliases[i])) match = 1;
+		}
+	}
+	else if ((which == SEL_NUMBER) && (num == xnum)) match = 1;
+
+	if (match == 0)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	switch (cat) {
+		case CATEGORY_NETWORK:
+			// struct netent
+			item = (si_item_t *)LI_ils_create("L4488s*44", (unsigned long)si, cat, 1, va, vb, tokens[0], aliases, AF_INET, xnum);
+			break;
+		case CATEGORY_PROTOCOL:
+		case CATEGORY_RPC:
+			// struct protoent
+			// struct rpcent
+			item = (si_item_t *)LI_ils_create("L4488s*4", (unsigned long)si, cat, 1, va, vb, tokens[0], aliases, xnum);
+			break;
+		default:
+			abort();
+	}
+
+	free(tokens);
+
+	return item;
+}
+
+static void *
+_fsi_get_name_number_aliases(si_mod_t *si, const char *name, int num, int which, int cat)
+{
+	char *p, *line;
+	si_item_t *item;
+	FILE *f;
+	si_list_t *all;
+	uint64_t va, vb;
+	const char *path;
+	int vtype;
+
+	switch (cat) {
+		case CATEGORY_NETWORK:
+			vtype = VALIDATION_NETWORKS;
+			path = _PATH_NETWORKS;
+			break;
+		case CATEGORY_PROTOCOL:
+			vtype = VALIDATION_PROTOCOLS;
+			path = _PATH_PROTOCOLS;
+			break;
+		case CATEGORY_RPC:
+			vtype = VALIDATION_RPC;
+			path = _PATH_RPCS;
+			break;
+		default:
+			abort();
+	}
+
+	f = fopen(path, "r");
+	if (f == NULL) return NULL;
+
+	_fsi_get_validation(si, vtype, path, f, &va, &vb);
+
+	all = NULL;
+
+	forever
+	{
+		line = _fsi_get_line(f);
+		if (line == NULL) break;
+
+		if (line[0] == '#') 
+		{
+			free(line);
+			line = NULL;
+			continue;
+		}
+
+		p = strchr(line, '#');
+		if (p != NULL) *p = '\0';
+
+		item = _fsi_parse_name_num_aliases(si, name, num, which, line, va, vb, cat);
+		free(line);
+		line = NULL;
+
+		if (item == NULL) continue;
+
+		if (which == SEL_ALL)
+		{
+			all = si_list_add(all, item);
+			si_item_release(item);
+			continue;
+		}
+
+		fclose(f);
+		return item;
+	}
+
+	fclose(f);
+	return all;
+}
+
+/* MOUNT */
+
+static si_item_t *
+_fsi_parse_fs(si_mod_t *si, const char *name, int which, char *data, uint64_t va, uint64_t vb)
+{
+	char **tokens, *tmp, **opts, *fstype;
+	int ntokens, match, i, freq, passno;
+	si_item_t *item;
+
+	if (data == NULL) return NULL;
+
+	freq = 0;
+	passno = 0;
+	fstype = NULL;
+
+	ntokens = 0;
+	tokens = _fsi_tokenize(data, " 	", 0, &ntokens);
+	if ((ntokens < 4) || (ntokens > 6))
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	if (ntokens >= 5) freq = atoi(tokens[4]);
+	if (ntokens == 6) passno = atoi(tokens[5]);
+
+	tmp = strdup(tokens[3]);
+	if (tmp == NULL)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	ntokens = 0;
+	opts = _fsi_tokenize(tmp, ",", 0, &ntokens);
+
+	if (opts == NULL)
+	{
+		free(tokens); 
+		free(tmp);
+		return NULL;
+	}
+
+	for (i = 0; i < ntokens; i++)
+	{
+		if ((string_equal(opts[i], "rw")) || (string_equal(opts[i], "ro")) || (string_equal(opts[i], "sw")) || (string_equal(opts[i], "xx")))
+		{
+			fstype = opts[i];
+			break;
+		}
+	}
+
+	match = 0;
+
+	if (which == SEL_ALL) match = 1;
+	else if ((which == SEL_NAME) && (string_equal(name, tokens[0]))) match = 1;
+	else if ((which == SEL_NUMBER) && (string_equal(name, tokens[1]))) match = 1;
+
+	if (match == 0)
+	{
+		free(tokens);
+		return NULL;
+	}
+
+	item = (si_item_t *)LI_ils_create("L4488sssss44", (unsigned long)si, CATEGORY_FS, 1, va, vb, tokens[0], tokens[1], tokens[2], tokens[3], (fstype == NULL) ? "rw" : fstype, freq, passno);
+
+	free(tokens); 
+	free(opts); 
+	free(tmp);
+
+	return item;
+}
+
+static char *
+_fsi_get_device_path(dev_t target_dev)
+{
+	char *result;
+    char dev[PATH_MAX];
+    char *name;
+	char namebuf[PATH_MAX];
+
+	result = NULL;
+
+    strlcpy(dev, _PATH_DEV, sizeof(dev));
+
+    /* The root device in fstab should always be a block special device */
+    name = devname_r(target_dev, S_IFBLK, namebuf, sizeof(namebuf));
+    if (name == NULL)
+	{
+		DIR *dirp;
+		struct stat devst;
+		struct dirent *ent, entbuf;
+
+       /* No _PATH_DEVDB. We have to search for it the slow way */
+        dirp = opendir(_PATH_DEV);
+        if (dirp == NULL) return NULL;
+
+        while (readdir_r(dirp, &entbuf, &ent) == 0 && ent != NULL)
+		{
+            /* Look for a block special device */
+            if (ent->d_type == DT_BLK)
+			{
+                strlcat(dev, ent->d_name, sizeof(dev));
+                if (stat(dev, &devst) == 0)
+				{
+                    if (devst.st_rdev == target_dev) {
+						result = strdup(dev);
+						break;
+					}
+                }
+            }
+
+            /* reset dev to _PATH_DEV and try again */
+            dev[sizeof(_PATH_DEV) - 1] = '\0';
+        }
+
+		if (dirp) closedir(dirp);
+    }
+	else
+	{
+        /* We found the _PATH_DEVDB entry */
+		strlcat(dev, name, sizeof(dev));
+		result = strdup(dev);
+	}
+
+    return result;
+}
+
+static si_item_t *
+_fsi_fs_root(si_mod_t *si)
+{
+	dispatch_once(&rootfs_once, ^{
+		struct stat rootstat;
+		struct statfs rootfsinfo;
+		char *root_spec;
+		const char *root_path = "/";
+
+		if (stat(root_path, &rootstat) < 0) return;
+ 		if (statfs(root_path, &rootfsinfo) < 0) return;
+
+		// Check to make sure we're not looking at a synthetic root:
+		if (string_equal(rootfsinfo.f_fstypename, "synthfs")) {
+			root_path = "/root";
+        		if (stat(root_path, &rootstat) < 0) return;
+			if (statfs(root_path, &rootfsinfo) < 0) return;
+		}
+
+		root_spec = _fsi_get_device_path(rootstat.st_dev);
+
+		rootfs = (si_item_t *)LI_ils_create("L4488sssss44", (unsigned long)si, CATEGORY_FS, 1, 0LL, 0LL, root_spec, root_path, rootfsinfo.f_fstypename, FSTAB_RW, FSTAB_RW, 0, 1);
+	});
+
+	return si_item_retain(rootfs);
+}
+
+static void *
+_fsi_get_fs(si_mod_t *si, const char *name, int which)
+{
+	char *line;
+	si_item_t *item;
+	FILE *f;
+	si_list_t *all;
+	uint64_t va, vb;
+	int synthesize_root;
+	struct fstab *rfs;
+
+	if ((which != SEL_ALL) && (name == NULL)) return NULL;
+
+	all = NULL;
+	f = NULL;
+#ifdef SYNTH_ROOTFS
+	synthesize_root = 1;
+#else
+	synthesize_root = 0;
+#endif
+
+	f = fopen(_PATH_FSTAB, "r");
+	if ((f == NULL) || (synthesize_root == 1))
+	{
+		item = _fsi_fs_root(si);
+
+		rfs = NULL;
+		if (item != NULL) rfs = (struct fstab *)((uintptr_t)item + sizeof(si_item_t));
+
+		switch (which)
+		{
+			case SEL_NAME:
+			{
+				if ((rfs != NULL) && (string_equal(name, rfs->fs_spec)))
+				{
+					if (f != NULL) fclose(f);
+					return item;
+				}
+
+				break;
+			}
+
+			case SEL_NUMBER:
+			{
+				if ((rfs != NULL) && (string_equal(name, rfs->fs_file)))
+				{
+					if (f != NULL) fclose(f);
+					return item;
+				}
+
+				break;
+			}
+
+			case SEL_ALL:
+			{
+				all = si_list_add(all, item);
+				si_item_release(item);
+				break;
+			}
+		}
+	}
+
+	if (f == NULL) return all;
+
+	_fsi_get_validation(si, VALIDATION_FSTAB, _PATH_FSTAB, f, &va, &vb);
+
+	forever
+	{
+		line = _fsi_get_line(f);
+		if (line == NULL) break;
+
+		if (line[0] == '#') 
+		{
+			free(line);
+			line = NULL;
+			continue;
+		}
+
+		item = _fsi_parse_fs(si, name, which, line, va, vb);
+		free(line);
+		line = NULL;
+
+		if (item == NULL) continue;
+
+		if (which == SEL_ALL)
+		{
+			all = si_list_add(all, item);
+			si_item_release(item);
+			continue;
+		}
+
+		fclose(f);
+		return item;
+	}
+
+	fclose(f);
+	return all;
+}
+
+static int
+file_is_valid(si_mod_t *si, si_item_t *item)
+{
+	si_mod_t *src;
+
+	if (si == NULL) return 0;
+	if (item == NULL) return 0;
+	if (si->name == NULL) return 0;
+	if (item->src == NULL) return 0;
+
+	src = (si_mod_t *)item->src;
+
+	if (src->name == NULL) return 0;
+	if (string_not_equal(si->name, src->name)) return 0;
+
+	if (item == rootfs) return 1;
+
+	return _fsi_validate(si, item->type, item->validation_a, item->validation_b);
+}
+
+static si_item_t *
+file_user_byname(si_mod_t *si, const char *name)
+{
+	return _fsi_get_user(si, name, 0, SEL_NAME);
+}
+
+static si_item_t *
+file_user_byuid(si_mod_t *si, uid_t uid)
+{
+	return _fsi_get_user(si, NULL, uid, SEL_NUMBER);
+}
+
+static si_list_t *
+file_user_all(si_mod_t *si)
+{
+	return _fsi_get_user(si, NULL, 0, SEL_ALL);
+}
+
+static si_item_t *
+file_group_byname(si_mod_t *si, const char *name)
+{
+	return _fsi_get_group(si, name, 0, SEL_NAME);
+}
+
+static si_item_t *
+file_group_bygid(si_mod_t *si, gid_t gid)
+{
+	return _fsi_get_group(si, NULL, gid, SEL_NUMBER);
+}
+
+static si_list_t *
+file_group_all(si_mod_t *si)
+{
+	return _fsi_get_group(si, NULL, 0, SEL_ALL);
+}
+
+static si_item_t *
+file_grouplist(si_mod_t *si, const char *name, __unused uint32_t ignored)
+{
+	return _fsi_get_grouplist(si, name);
+}
+
+static si_list_t *
+file_netgroup_byname(si_mod_t *si, const char *name)
+{
+	si_list_t *list = NULL;
+	si_item_t *item;
+	uint64_t va=0, vb=0;
+	file_netgroup_t *n;
+	file_si_private_t *pp;
+
+	if (name == NULL) return NULL;
+
+	pp = (file_si_private_t *)si->private;
+	if (pp == NULL) return NULL;
+
+	_fsi_check_netgroup_cache(si);
+
+	pthread_mutex_lock(&file_mutex);
+
+	n = _fsi_find_netgroup(&(pp->file_netgroup_cache), name, 0);
+	if (n != NULL)
+	{
+		file_netgroup_member_t *m = n->members;
+		while (m != NULL)
+		{
+			item = (si_item_t *)LI_ils_create("L4488sss", (unsigned long)si, CATEGORY_NETGROUP, 1, va, vb, m->host, m->user, m->domain);
+			list = si_list_add(list, item);
+			m = m->next;
+		}
+	}
+
+	pthread_mutex_unlock(&file_mutex);
+
+	return list;
+}
+
+static int
+file_in_netgroup(si_mod_t *si, const char *group, const char *host, const char *user, const char *domain)
+{
+	file_netgroup_t *n;
+	file_netgroup_member_t *m;
+	file_si_private_t *pp;
+
+	if (group == NULL) return 0;
+
+	pp = (file_si_private_t *)si->private;
+	if (pp == NULL) return 0;
+
+	_fsi_check_netgroup_cache(si);
+
+	pthread_mutex_lock(&file_mutex);
+
+	n = _fsi_find_netgroup(&(pp->file_netgroup_cache), group, 0);
+	if (n == NULL)
+	{
+		pthread_mutex_unlock(&file_mutex);
+		return 0;
+	}
+
+	m = n->members;
+	while (m != NULL)
+	{
+		file_netgroup_member_t *x = m;
+		m = m->next;
+
+		if (host != NULL)
+		{
+			if (x->host == NULL) continue;
+			if (strcmp(host, x->host)) continue;
+		}
+
+		if (user != NULL)
+		{
+			if (x->user == NULL) continue;
+			if (strcmp(user, x->user)) continue;
+		}
+
+		if (domain != NULL)
+		{
+			if (x->domain == NULL) continue;
+			if (strcmp(domain, x->domain)) continue;
+		}
+
+		pthread_mutex_unlock(&file_mutex);
+		return 1;
+	}
+
+	pthread_mutex_unlock(&file_mutex);
+	return 0;
+}
+
+static si_item_t *
+file_host_byname(si_mod_t *si, const char *name, int af, const char *ignored, uint32_t *err)
+{
+	si_item_t *item;
+
+	if (err != NULL) *err = SI_STATUS_NO_ERROR;
+
+	item = _fsi_get_host(si, name, NULL, af, SEL_NAME, err);
+	if ((item == NULL) && (err != NULL) && (*err == 0)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
+
+	return item;
+}
+
+static si_item_t *
+file_host_byaddr(si_mod_t *si, const void *addr, int af, const char *ignored, uint32_t *err)
+{
+	si_item_t *item;
+
+	if (err != NULL) *err = SI_STATUS_NO_ERROR;
+
+	item = _fsi_get_host(si, NULL, addr, af, SEL_NUMBER, err);
+	if ((item == NULL) && (err != NULL) && (*err == 0)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
+
+	return item;
+}
+
+static si_list_t *
+file_host_all(si_mod_t *si)
+{
+	return _fsi_get_host(si, NULL, NULL, 0, SEL_ALL, NULL);
+}
+
+static si_item_t *
+file_network_byname(si_mod_t *si, const char *name)
+{
+	if (name == NULL) return NULL;
+	return _fsi_get_name_number_aliases(si, name, 0, SEL_NAME, CATEGORY_NETWORK);
+}
+
+static si_item_t *
+file_network_byaddr(si_mod_t *si, uint32_t addr)
+{
+	return _fsi_get_name_number_aliases(si, NULL, (int)addr, SEL_NUMBER, CATEGORY_NETWORK);
+}
+
+static si_list_t *
+file_network_all(si_mod_t *si)
+{
+	return _fsi_get_name_number_aliases(si, NULL, 0, SEL_ALL, CATEGORY_NETWORK);
+}
+
+static si_item_t *
+file_service_byname(si_mod_t *si, const char *name, const char *proto)
+{
+	return _fsi_get_service(si, name, proto, 0, SEL_NAME);
+}
+
+static si_item_t *
+file_service_byport(si_mod_t *si, int port, const char *proto)
+{
+	return _fsi_get_service(si, NULL, proto, port, SEL_NUMBER);
+}
+
+static si_list_t *
+file_service_all(si_mod_t *si)
+{
+	return _fsi_get_service(si, NULL, NULL, 0, SEL_ALL);
+}
+
+static si_item_t *
+file_protocol_byname(si_mod_t *si, const char *name)
+{
+	if (name == NULL) return NULL;
+	return _fsi_get_name_number_aliases(si, name, 0, SEL_NAME, CATEGORY_PROTOCOL);
+}
+
+static si_item_t *
+file_protocol_bynumber(si_mod_t *si, int number)
+{
+	return _fsi_get_name_number_aliases(si, NULL, number, SEL_NUMBER, CATEGORY_PROTOCOL);
+}
+
+static si_list_t *
+file_protocol_all(si_mod_t *si)
+{
+	return _fsi_get_name_number_aliases(si, NULL, 0, SEL_ALL, CATEGORY_PROTOCOL);
+}
+
+static si_item_t *
+file_rpc_byname(si_mod_t *si, const char *name)
+{
+	if (name == NULL) return NULL;
+	return _fsi_get_name_number_aliases(si, name, 0, SEL_NAME, CATEGORY_RPC);
+}
+
+static si_item_t *
+file_rpc_bynumber(si_mod_t *si, int number)
+{
+	return _fsi_get_name_number_aliases(si, NULL, number, SEL_NUMBER, CATEGORY_RPC);
+}
+
+static si_list_t *
+file_rpc_all(si_mod_t *si)
+{
+	return _fsi_get_name_number_aliases(si, NULL, 0, SEL_ALL, CATEGORY_RPC);
+}
+
+static si_item_t *
+file_fs_byspec(si_mod_t *si, const char *spec)
+{
+	return _fsi_get_fs(si, spec, SEL_NAME);
+}
+
+static si_item_t *
+file_fs_byfile(si_mod_t *si, const char *file)
+{
+	return _fsi_get_fs(si, file, SEL_NUMBER);
+}
+
+static si_list_t *
+file_fs_all(si_mod_t *si)
+{
+	return _fsi_get_fs(si, NULL, SEL_ALL);
+}
+
+static si_item_t *
+file_alias_byname(si_mod_t *si, const char *name)
+{
+	return _fsi_get_alias(si, name, SEL_NAME);
+}
+
+static si_list_t *
+file_alias_all(si_mod_t *si)
+{
+	return _fsi_get_alias(si, NULL, SEL_ALL);
+}
+
+static si_item_t *
+file_mac_byname(si_mod_t *si, const char *name)
+{
+	return _fsi_get_ether(si, name, SEL_NAME);
+}
+
+static si_item_t *
+file_mac_bymac(si_mod_t *si, const char *mac)
+{
+	return _fsi_get_ether(si, mac, SEL_NUMBER);
+}
+
+static si_list_t *
+file_mac_all(si_mod_t *si)
+{
+	return _fsi_get_ether(si, NULL, SEL_ALL);
+}
+
+static si_list_t *
+file_addrinfo(si_mod_t *si, const void *node, const void *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err)
+{
+	if (err != NULL) *err = SI_STATUS_NO_ERROR;
+	return _gai_simple(si, node, serv, family, socktype, proto, flags, interface, err);
+}
+
+si_mod_t *
+si_module_static_file(void)
+{
+	static const struct si_mod_vtable_s file_vtable =
+	{
+		.sim_is_valid = &file_is_valid,
+
+		.sim_user_byname = &file_user_byname,
+		.sim_user_byuid = &file_user_byuid,
+		.sim_user_byuuid = NULL,
+		.sim_user_all = &file_user_all,
+
+		.sim_group_byname = &file_group_byname,
+		.sim_group_bygid = &file_group_bygid,
+		.sim_group_byuuid = NULL,
+		.sim_group_all = &file_group_all,
+
+		.sim_grouplist = &file_grouplist,
+
+		.sim_netgroup_byname = &file_netgroup_byname,
+		.sim_in_netgroup = &file_in_netgroup,
+
+		.sim_alias_byname = &file_alias_byname,
+		.sim_alias_all = &file_alias_all,
+
+		.sim_host_byname = &file_host_byname,
+		.sim_host_byaddr = &file_host_byaddr,
+		.sim_host_all = &file_host_all,
+
+		.sim_network_byname = &file_network_byname,
+		.sim_network_byaddr = &file_network_byaddr,
+		.sim_network_all = &file_network_all,
+
+		.sim_service_byname = &file_service_byname,
+		.sim_service_byport = &file_service_byport,
+		.sim_service_all = &file_service_all,
+
+		.sim_protocol_byname = &file_protocol_byname,
+		.sim_protocol_bynumber = &file_protocol_bynumber,
+		.sim_protocol_all = &file_protocol_all,
+
+		.sim_rpc_byname = &file_rpc_byname,
+		.sim_rpc_bynumber = &file_rpc_bynumber,
+		.sim_rpc_all = &file_rpc_all,
+
+		.sim_fs_byspec = &file_fs_byspec,
+		.sim_fs_byfile = &file_fs_byfile,
+		.sim_fs_all = &file_fs_all,
+
+		.sim_mac_byname = &file_mac_byname,
+		.sim_mac_bymac = &file_mac_bymac,
+		.sim_mac_all = &file_mac_all,
+
+		.sim_wants_addrinfo = NULL,
+		.sim_addrinfo = &file_addrinfo,
+
+		/* no nameinfo support */
+		.sim_nameinfo = NULL,
+	};
+
+	static si_mod_t si =
+	{
+		.vers = 1,
+		.refcount = 1,
+		.flags = SI_MOD_FLAG_STATIC,
+
+		.private = NULL,
+		.vtable = &file_vtable,
+	};
+
+	static dispatch_once_t once;
+
+	dispatch_once(&once, ^{
+		si.name = strdup("file");
+		file_si_private_t *pp = calloc(1, sizeof(file_si_private_t));
+		if (pp != NULL)
+		{
+			int i;
+			for (i = 0; i < VALIDATION_COUNT; i++) pp->notify_token[i] = -1;
+
+			/* hardwired for now, but we may want to make this configurable someday */
+			pp->validation_notify_mask = VALIDATION_MASK_HOSTS | VALIDATION_MASK_SERVICES | VALIDATION_MASK_PROTOCOLS;
+		}
+
+		si.private = pp;
+	});
+
+	return (si_mod_t *)&si;
+}
+#endif


Property changes on: trunk/lib/libosxsupport/file_module.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/fileport.c
===================================================================
--- trunk/lib/libosxsupport/fileport.c	                        (rev 0)
+++ trunk/lib/libosxsupport/fileport.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,42 @@
+/*+
+ * Copyright 2015 iXsystems, Inc.
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted providing 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 ``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/fileport.h>
+
+int fileport_makeport(int fd, fileport_t *fileport)
+{
+	if (fd < 0)
+		return (-1);
+
+	*fileport = (fileport_t)fd;
+	return (0);
+}
+
+int fileport_makefd(fileport_t fileport)
+{
+	return (int)fileport;
+}


Property changes on: trunk/lib/libosxsupport/fileport.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/getiopolicy_np.c
===================================================================
--- trunk/lib/libosxsupport/getiopolicy_np.c	                        (rev 0)
+++ trunk/lib/libosxsupport/getiopolicy_np.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <sys/types.h>
+#include <Availability.h>
+#include <errno.h>
+#include <sys/resource.h>
+
+extern int __iopolicysys(int, struct _iopol_param_t *);
+
+int
+getiopolicy_np(int iotype, int scope)
+{
+	int policy, error;
+	struct _iopol_param_t iop_param;
+
+	if (iotype != IOPOL_TYPE_DISK ||
+		(scope != IOPOL_SCOPE_PROCESS && scope != IOPOL_SCOPE_THREAD)) {
+		errno = EINVAL;
+		policy = -1;
+		goto exit;
+	}
+
+	iop_param.iop_scope = scope;
+	iop_param.iop_iotype = iotype;
+	error = __iopolicysys(IOPOL_CMD_GET, &iop_param);
+	if (error != 0) {
+		errno = error;
+		policy = -1;
+		goto exit;
+	}
+
+	policy = iop_param.iop_policy;
+
+  exit:
+	return policy;
+}
+
+int
+setiopolicy_np(int iotype, int scope, int policy)
+{
+	/* kernel validates the indiv values, no need to repeat it */
+	struct _iopol_param_t iop_param;
+	
+	iop_param.iop_scope = scope;
+	iop_param.iop_iotype = iotype;
+	iop_param.iop_policy = policy;
+
+	return( __iopolicysys(IOPOL_CMD_SET, &iop_param));
+}


Property changes on: trunk/lib/libosxsupport/getiopolicy_np.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/libproc.c
===================================================================
--- trunk/lib/libosxsupport/libproc.c	                        (rev 0)
+++ trunk/lib/libosxsupport/libproc.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,112 @@
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <mach/boolean.h>
+#include <libproc.h>
+
+
+int __proc_info(int callnum, int pid, int flavor, uint64_t arg, void * buffer, int buffersize);
+
+int 
+proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize)
+{
+	int rv;
+	
+	if ((type >= PROC_ALL_PIDS) || (type <= PROC_PPID_ONLY)) {
+		if ((rv = __proc_info(PROC_INFO_CALL_LISTPIDS, type, typeinfo, 0, buffer, buffersize)) == -1)
+			return (0);
+	} else {
+		errno = EINVAL;
+		rv = 0;
+	}
+	return (rv);
+}
+
+int
+proc_listallpids(void * buffer, int buffersize)
+{
+	int numpids;
+
+	numpids = proc_listpids(PROC_ALL_PIDS, 0, buffer, buffersize);
+	if (numpids == -1)
+		return (-1);
+	else
+		return (numpids/sizeof(int));
+}
+
+int 
+proc_listpgrppids(pid_t pgrpid, void * buffer, int buffersize)
+{
+	int numpids;
+
+	numpids = proc_listpids(PROC_PGRP_ONLY, (uint32_t)pgrpid, buffer, buffersize);
+	if (numpids == -1)
+		return (-1);
+	else
+		return (numpids/sizeof(int));
+}
+
+int 
+proc_listchildpids(pid_t ppid, void * buffer, int buffersize)
+{
+	int numpids;
+
+	numpids = proc_listpids(PROC_PPID_ONLY, (uint32_t)ppid, buffer, buffersize);
+	if (numpids == -1)
+		return (-1);
+	else
+		return (numpids/sizeof(int));
+}
+
+int 
+proc_pidinfo(int pid, int flavor, uint64_t arg,  void *buffer, int buffersize)
+{
+	int rv;
+
+	if ((rv = __proc_info(PROC_INFO_CALL_PIDINFO, pid, flavor,  arg,  buffer, buffersize)) == -1)
+		return (0);
+
+	return (rv);
+}
+
+int
+proc_setpcontrol(const int control __unused)
+{
+
+	return (ENOTSUP);
+}
+
+int
+proc_track_dirty(pid_t pid __unused, uint32_t flags __unused)
+{
+
+	return (ENOTSUP);
+}
+
+int
+proc_set_dirty(pid_t pid __unused, bool dirty __unused)
+{
+
+	return (ENOTSUP);
+}
+
+int
+proc_get_dirty(pid_t pid __unused, uint32_t *flags __unused)
+{
+
+	return (ENOTSUP);
+}
+
+int
+proc_terminate(pid_t pid, int *sig)
+{
+	int rv;
+
+	if (sig == NULL)
+		return (EINVAL);
+
+	if ((rv = __proc_info(PROC_INFO_CALL_TERMINATE, pid, 0, 0, NULL, 0)) == -1)
+		return (errno);
+
+	*sig = rv;
+	return (0);
+}


Property changes on: trunk/lib/libosxsupport/libproc.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/mdns_module.c
===================================================================
--- trunk/lib/libosxsupport/mdns_module.c	                        (rev 0)
+++ trunk/lib/libosxsupport/mdns_module.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,1639 @@
+/*
+ * Copyright (c) 2008-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@
+ */
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/*
+ * 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.
+ */
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ * 
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include "ils.h"
+#include "netdb.h"
+#include "si_module.h"
+
+#include <assert.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <arpa/nameser_compat.h>
+#include <libkern/OSAtomic.h>
+#include <netinet/in.h>
+#include <ctype.h>
+#include <dns_sd.h>
+#include <dnsinfo.h>
+#include <errno.h>
+#include <nameser.h>
+#include <notify.h>
+#include <pthread.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/event.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <time.h>
+#include <unistd.h>
+#include <asl.h>
+#include <dns.h>
+#include <dns_util.h>
+#include <TargetConditionals.h>
+#include <dispatch/dispatch.h>
+
+/* from dns_util.c */
+#define DNS_MAX_RECEIVE_SIZE 65536
+
+#define INET_NTOP_AF_INET_OFFSET 4
+#define INET_NTOP_AF_INET6_OFFSET 8
+
+#define IPPROTO_UNSPEC 0
+
+#define GOT_DATA 1
+#define GOT_ERROR 2
+#define SHORT_AAAA_EXTRA 2
+#define MEDIUM_AAAA_EXTRA 5
+#define LONG_AAAA_EXTRA 10
+
+#define MDNS_DEBUG_FILE "/etc/.mdns_debug"
+#define MDNS_DEBUG_STDOUT 0x00000001
+#define MDNS_DEBUG_STDERR 0x00000002
+#define MDNS_DEBUG_ASL    0x00000004
+#define MDNS_DEBUG_OUT    0x00000007
+#define MDNS_DEBUG_MORE   0x00000010
+
+static int _mdns_debug = 0;
+
+// mutex protects DNSServiceProcessResult and DNSServiceRefDeallocate
+static pthread_mutex_t _mdns_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+typedef struct {
+	uint16_t priority;
+	uint16_t weight;
+	uint16_t port;
+	uint8_t target[0];
+} mdns_rr_srv_t;
+
+typedef struct mdns_srv_t mdns_srv_t;
+struct mdns_srv_t {
+	si_srv_t srv;
+	mdns_srv_t *next;
+};
+
+typedef struct {
+	struct hostent host;
+	int alias_count;
+	int addr_count;
+} mdns_hostent_t;
+
+typedef struct {
+	mdns_hostent_t *h4;
+	mdns_hostent_t *h6;
+	mdns_srv_t *srv;
+	uint64_t ttl;
+	uint32_t ifnum;
+} mdns_reply_t;
+
+static uint32_t _mdns_generation = 0;
+static DNSServiceRef _mdns_sdref;
+static DNSServiceRef _mdns_old_sdref;
+
+static void _mdns_hostent_clear(mdns_hostent_t *h);
+static void _mdns_reply_clear(mdns_reply_t *r);
+static int _mdns_search(const char *name, int class, int type, const char *interface, DNSServiceFlags flags, uint8_t *answer, uint32_t *anslen, mdns_reply_t *reply);
+
+static const char hexchar[] = "0123456789abcdef";
+
+#define BILLION 1000000000
+
+/* length of a reverse DNS IPv6 address query name, e.g. "9.4.a.f.c.e.e.f.e.e.1.5.4.1.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa" */
+#define IPv6_REVERSE_LEN 72
+
+/* index of the trailing char that must be "8", "9", "A", "a", "b", or "B" */
+#define IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR 58
+
+/* index of low-order nibble of embedded scope id */
+#define IPv6_REVERSE_LINK_LOCAL_SCOPE_ID_LOW 48
+
+const static uint8_t hexval[128] = {
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,		/*  0 - 15 */
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,		/* 16 - 31 */
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,		/* 32 - 47 */
+	0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  0,  0,  0,  0,  0,  0,		/* 48 - 63 */
+	0, 10, 11, 12, 13, 14, 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,		/* 64 - 79 */
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,		/* 80 - 95 */
+	0, 10, 11, 12, 13, 14, 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,		/* 96 - 111 */
+	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0		/* 112 - 127 */
+};
+
+static void
+_mdns_debug_message(const char *str, ...)
+{
+	va_list v;
+	char *out = NULL;
+	if ((_mdns_debug & MDNS_DEBUG_OUT) == 0) return;
+
+	va_start(v, str);
+	vasprintf(&out, str, v);
+	if (out == NULL) return;
+
+	if (_mdns_debug & MDNS_DEBUG_STDOUT) fprintf(stdout, "%s", out);
+	if (_mdns_debug & MDNS_DEBUG_STDERR) fprintf(stderr, "%s", out);
+	if (_mdns_debug & MDNS_DEBUG_ASL) asl_log_message(ASL_LEVEL_NOTICE, "%s", out);
+	free(out);
+
+	va_end(v);
+}
+
+static char *
+_mdns_reverse_ipv4(const char *addr)
+{
+	union
+	{
+		uint32_t a;
+		unsigned char b[4];
+	} ab;
+	char *p;
+
+	if (addr == NULL) return NULL;
+
+	memcpy(&(ab.a), addr, 4);
+
+	asprintf(&p, "%u.%u.%u.%u.in-addr.arpa.", ab.b[3], ab.b[2], ab.b[1], ab.b[0]);
+	return p;
+}
+
+static char *
+_mdns_reverse_ipv6(const char *addr)
+{
+	char x[65], *p;
+	int i, j;
+	u_int8_t d, hi, lo;
+
+	if (addr == NULL) return NULL;
+
+	x[64] = '\0';
+	j = 63;
+	for (i = 0; i < 16; i++)
+	{
+		d = addr[i];
+		lo = d & 0x0f;
+		hi = d >> 4;
+		x[j--] = '.';
+		x[j--] = hexchar[hi];
+		x[j--] = '.';
+		x[j--] = hexchar[lo];
+	}
+
+	asprintf(&p, "%sip6.arpa.", x);
+
+	return p;
+}
+
+/* _mdns_canonicalize
+ * Canonicalize the domain name by converting to lower case and removing the
+ * trailing '.' if present.
+ */
+static char *
+_mdns_canonicalize(const char *s)
+{
+	int i;
+	char *t;
+	if (s == NULL) return NULL;
+	t = strdup(s);
+	if (t == NULL) return NULL;
+	if (t[0] == '\0') return t;
+	for (i = 0; t[i] != '\0'; i++) {
+		if (t[i] >= 'A' && t[i] <= 'Z') t[i] += 32;
+	}
+	if (t[i-1] == '.') t[i-1] = '\0';
+	return t;
+}
+
+/* _mdns_hostent_append_alias
+ * Appends an alias to the mdns_hostent_t structure.
+ */
+static int
+_mdns_hostent_append_alias(mdns_hostent_t *h, const char *alias)
+{
+	int i;
+	char *name;
+	if (h == NULL || alias == NULL) return 0;
+	name = _mdns_canonicalize(alias);
+	if (name == NULL) return -1;
+
+	// don't add the name if it matches an existing name
+	if (h->host.h_name && string_equal(h->host.h_name, name)) {
+		free(name);
+		return 0;
+	}
+	for (i = 0; i < h->alias_count; ++i) {
+		if (string_equal(h->host.h_aliases[i], name)) {
+			free(name);
+			return 0;
+		}
+	}
+
+	// add the alias and NULL terminate the list
+	h->host.h_aliases = (char **)reallocf(h->host.h_aliases, (h->alias_count+2) * sizeof(char *));
+	if (h->host.h_aliases == NULL) {
+		h->alias_count = 0;
+		free(name);
+		return -1;
+	}
+	h->host.h_aliases[h->alias_count] = name;
+	++h->alias_count;
+	h->host.h_aliases[h->alias_count] = NULL;
+	return 0;
+}
+
+/* _mdns_hostent_append_addr
+ * Appends an alias to the mdns_hostent_t structure.
+ */
+static int
+_mdns_hostent_append_addr(mdns_hostent_t *h, const uint8_t *addr, uint32_t len)
+{
+	if (h == NULL || addr == NULL || len == 0) return 0;
+
+	// copy the address buffer
+	uint8_t *buf = malloc(len);
+	if (buf == NULL) return -1;
+	memcpy(buf, addr, len);
+
+	// add the address and NULL terminate the list
+	h->host.h_addr_list = (char **)reallocf(h->host.h_addr_list, (h->addr_count+2) * sizeof(char *));
+	if (h->host.h_addr_list == NULL) {
+		h->addr_count = 0;
+		return -1;
+	}
+	h->host.h_addr_list[h->addr_count] = (char*)buf;
+	h->addr_count++;
+	h->host.h_addr_list[h->addr_count] = NULL;
+	return 0;
+}
+
+static void
+_mdns_hostent_clear(mdns_hostent_t *h)
+{
+	if (h == NULL) return;
+	free(h->host.h_name);
+	h->host.h_name = NULL;
+
+	char **aliases = h->host.h_aliases;
+	while (aliases && *aliases) {
+		free(*aliases++);
+	}
+	free(h->host.h_aliases);
+	h->host.h_aliases = NULL;
+	h->alias_count = 0;
+
+	char **addrs = h->host.h_addr_list;
+	while (addrs && *addrs) {
+		free(*addrs++);
+	}
+	free(h->host.h_addr_list);
+	h->host.h_addr_list = NULL;
+	h->addr_count = 0;
+
+}
+
+static void
+_mdns_reply_clear(mdns_reply_t *r)
+{
+	if (r == NULL) return;
+	r->ifnum = 0;
+	_mdns_hostent_clear(r->h4);
+	_mdns_hostent_clear(r->h6);
+	mdns_srv_t *srv = r->srv;
+	r->srv = NULL;
+	while (srv) {
+		mdns_srv_t *next = srv->next;
+		free(srv->srv.target);
+		free(srv);
+		srv = next;
+	}
+}
+
+static si_item_t *
+mdns_hostbyname(si_mod_t *si, const char *name, int af, const char *interface, uint32_t *err)
+{
+	uint32_t type;
+	mdns_hostent_t h;
+	mdns_reply_t reply;
+	si_item_t *out = NULL;
+	uint64_t bb;
+	int status;
+	DNSServiceFlags flags = 0;
+
+	if (err != NULL) *err = SI_STATUS_NO_ERROR;
+
+	if (name == NULL) {
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+		return NULL;
+	}
+
+	memset(&h, 0, sizeof(h));
+	memset(&reply, 0, sizeof(reply));
+
+	switch (af) {
+		case AF_INET:
+			type = ns_t_a;
+			h.host.h_length = 4;
+			reply.h4 = &h;
+			break;
+		case AF_INET6:
+			type = ns_t_aaaa;
+			h.host.h_length = 16;
+			reply.h6 = &h;
+			break;
+		default:
+			if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+			return NULL;
+	}
+	h.host.h_addrtype = af;
+
+	status = _mdns_search(name, ns_c_in, type, interface, flags, NULL, NULL, &reply);
+	if (status != 0 || h.addr_count == 0) {
+		_mdns_reply_clear(&reply);
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
+		return NULL;
+	}
+
+	bb = reply.ttl + time(NULL);
+
+	switch (af) {
+		case AF_INET:
+			out = (si_item_t *)LI_ils_create("L4488s*44a", (unsigned long)si, CATEGORY_HOST_IPV4, 1, bb, 0LL, h.host.h_name, h.host.h_aliases, h.host.h_addrtype, h.host.h_length, h.host.h_addr_list);
+			break;
+		case AF_INET6:
+			out = (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, bb, 0LL, h.host.h_name, h.host.h_aliases, h.host.h_addrtype, h.host.h_length, h.host.h_addr_list);
+			break;
+	}
+
+	_mdns_reply_clear(&reply);
+
+	if (out == NULL && err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+
+	return out;
+}
+
+static si_item_t *
+mdns_hostbyaddr(si_mod_t *si, const void *addr, int af, const char *interface, uint32_t *err)
+{
+	mdns_hostent_t h;
+	mdns_reply_t reply;
+	char *name;
+	si_item_t *out;
+	uint64_t bb;
+	int cat;
+	int status;
+	DNSServiceFlags flags = 0;
+
+	if (err != NULL) *err = SI_STATUS_NO_ERROR;
+
+	if (addr == NULL || si == NULL) {
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+		return NULL;
+	}
+
+	memset(&h, 0, sizeof(h));
+	memset(&reply, 0, sizeof(reply));
+
+	switch (af) {
+		case AF_INET:
+			h.host.h_length = 4;
+			reply.h4 = &h;
+			name = _mdns_reverse_ipv4(addr);
+			cat = CATEGORY_HOST_IPV4;
+			break;
+		case AF_INET6:
+			h.host.h_length = 16;
+			reply.h6 = &h;
+			name = _mdns_reverse_ipv6(addr);
+			cat = CATEGORY_HOST_IPV6;
+			break;
+		default:
+			if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+			return NULL;
+	}
+	h.host.h_addrtype = af;
+
+	status = _mdns_search(name, ns_c_in, ns_t_ptr, interface, flags, NULL, NULL, &reply);
+	free(name);
+	if (status != 0) {
+		_mdns_reply_clear(&reply);
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
+		return NULL;
+	}
+
+	status = _mdns_hostent_append_addr(&h, addr, h.host.h_length);
+	if (status != 0) {
+		_mdns_hostent_clear(&h);
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+		return NULL;
+	}
+
+	bb = reply.ttl + time(NULL);
+	out = (si_item_t *)LI_ils_create("L4488s*44a", (unsigned long)si, cat, 1, bb, 0LL, h.host.h_name, h.host.h_aliases, h.host.h_addrtype, h.host.h_length, h.host.h_addr_list);
+
+	_mdns_hostent_clear(&h);
+
+	if (out == NULL && err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+	return out;
+}
+
+static si_list_t *
+mdns_addrinfo(si_mod_t *si, const void *node, const void *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err)
+{
+	int wantv4 = 1;
+	int wantv6 = 1;
+	struct in_addr a4;
+	struct in6_addr a6;
+	mdns_hostent_t h4;
+	mdns_hostent_t h6;
+	mdns_reply_t reply;
+	uint32_t type;
+	uint16_t port;
+
+	if (family == AF_INET6)
+	{
+		if ((flags & AI_V4MAPPED) == 0) wantv4 = 0;
+	}
+	else if (family == AF_INET)
+	{
+		wantv6 = 0;
+	}
+	else if (family != AF_UNSPEC)
+	{
+		return NULL;
+	}
+
+	if (err != NULL) *err = SI_STATUS_NO_ERROR;
+
+	si_list_t *out = NULL;
+
+	memset(&h4, 0, sizeof(h4));
+	memset(&h6, 0, sizeof(h6));
+	memset(&reply, 0, sizeof(reply));
+
+	h4.host.h_addrtype = AF_INET;
+	h4.host.h_length = 4;
+	h6.host.h_addrtype = AF_INET6;
+	h6.host.h_length = 16;
+
+	if (wantv4 && wantv6) {
+		type = 0;
+		reply.h4 = &h4;
+		reply.h6 = &h6;
+	} else if (wantv4) {
+		reply.h4 = &h4;
+		type = ns_t_a;
+	} else if (wantv6) {
+		type = ns_t_aaaa;
+		reply.h6 = &h6;
+	} else {
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+		return NULL;
+	}
+
+	// service lookup
+	if ((flags & AI_NUMERICSERV) != 0) {
+		port = *(uint16_t *)serv;
+	} else {
+		if (_gai_serv_to_port(serv, proto, &port) != 0) {
+			if (err) *err = SI_STATUS_EAI_NONAME;
+			return NULL;
+		}
+	}
+
+	// host lookup
+	if ((flags & AI_NUMERICHOST) != 0) {
+		char *cname = NULL;
+		struct in_addr *p4 = NULL;
+		struct in6_addr *p6 = NULL;
+		if (family == AF_INET) {
+			p4 = &a4;
+			memcpy(p4, node, sizeof(a4));
+		} else if (family == AF_INET6) {
+			p6 = &a6;
+			memcpy(p6, node, sizeof(a6));
+		}
+		out = si_addrinfo_list(si, flags, socktype, proto, p4, p6, port, 0, cname, cname);
+	} else {
+		DNSServiceFlags dns_flags = 0;
+		if (flags & AI_ADDRCONFIG) {
+			dns_flags |= kDNSServiceFlagsSuppressUnusable;
+		}
+		int res;
+		res = _mdns_search(node, ns_c_in, type, interface, dns_flags, NULL, NULL, &reply);
+		if (res == 0 && (h4.addr_count > 0 || h6.addr_count > 0)) {
+			out = si_addrinfo_list_from_hostent(si, flags, socktype, proto,
+												port, 0,
+												(wantv4 ? &h4.host : NULL),
+												(wantv6 ? &h6.host : NULL));
+		} else if (err != NULL) {
+			*err = SI_STATUS_EAI_NONAME;
+		}
+		_mdns_reply_clear(&reply);
+	}
+	return out;
+}
+
+static si_list_t *
+mdns_srv_byname(si_mod_t* si, const char *qname, const char *interface, uint32_t *err)
+{
+	si_list_t *out = NULL;
+	mdns_reply_t reply;
+	mdns_srv_t *srv;
+	int res;
+	const uint64_t unused = 0;
+	DNSServiceFlags flags = 0;
+
+	if (err != NULL) *err = SI_STATUS_NO_ERROR;
+
+	memset(&reply, 0, sizeof(reply));
+	res = _mdns_search(qname, ns_c_in, ns_t_srv, interface, flags, NULL, NULL, &reply);
+	if (res == 0) {
+		srv = reply.srv;
+		while (srv) {
+			si_item_t *item;
+			item = (si_item_t *)LI_ils_create("L4488222s", (unsigned long)si, CATEGORY_SRV, 1, unused, unused, srv->srv.priority, srv->srv.weight, srv->srv.port, srv->srv.target);
+			out = si_list_add(out, item);
+			si_item_release(item);
+			srv = srv->next;
+		}
+	}
+	_mdns_reply_clear(&reply);
+	return out;
+}
+
+/*
+ * We support dns_async_start / cancel / handle_reply using dns_item_call
+ */
+static si_item_t *
+mdns_item_call(si_mod_t *si, int call, const char *name, const char *ignored, const char *interface, uint32_t class, uint32_t type, uint32_t *err)
+{
+	int res;
+	uint8_t buf[DNS_MAX_RECEIVE_SIZE];
+	uint32_t len = sizeof(buf);
+	mdns_reply_t reply;
+	mdns_hostent_t h4;
+	mdns_hostent_t h6;
+	si_item_t *out;
+	DNSServiceFlags flags = 0;
+
+	if (err != NULL) *err = SI_STATUS_NO_ERROR;
+
+	if (name == NULL) {
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+		return NULL;
+	}
+
+	memset(&h4, 0, sizeof(h4));
+	memset(&h6, 0, sizeof(h6));
+	memset(&reply, 0, sizeof(reply));
+
+	h4.host.h_addrtype = AF_INET;
+	h4.host.h_length = 4;
+	h6.host.h_addrtype = AF_INET6;
+	h6.host.h_length = 16;
+	reply.h4 = &h4;
+	reply.h6 = &h6;
+
+	res = _mdns_search(name, class, type, interface, flags, buf, &len, &reply);
+	if (res != 0 || len <= 0 || len > DNS_MAX_RECEIVE_SIZE) {
+		_mdns_reply_clear(&reply);
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
+		return NULL;
+	}
+
+	struct sockaddr_in6 from;
+	uint32_t fromlen = sizeof(from);
+	memset(&from, 0, fromlen);
+	from.sin6_len = fromlen;
+	from.sin6_family = AF_INET6;
+	from.sin6_addr.__u6_addr.__u6_addr8[15] = 1;
+	if (reply.ifnum != 0) {
+		from.sin6_addr.__u6_addr.__u6_addr16[0] = htons(0xfe80);
+		from.sin6_scope_id = reply.ifnum;
+	}
+
+	out = (si_item_t *)LI_ils_create("L4488@@", (unsigned long)si, CATEGORY_DNSPACKET, 1, 0LL, 0LL, len, buf, fromlen, &from);
+	if (out == NULL && err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+
+	_mdns_reply_clear(&reply);
+
+	return out;
+}
+
+static int
+mdns_is_valid(si_mod_t *si, si_item_t *item)
+{
+	return 0;
+}
+
+static void
+mdns_close(si_mod_t *si)
+{
+}
+
+static void
+_mdns_atfork_prepare(void)
+{
+	// acquire our lock so that we know all other threads have "drained"
+	pthread_mutex_lock(&_mdns_mutex);
+}
+
+static void
+_mdns_atfork_parent(void)
+{
+	// parent can simply resume
+	pthread_mutex_unlock(&_mdns_mutex);
+}
+
+static void
+_mdns_atfork_child(void)
+{
+	// child needs to force re-initialization
+	_mdns_old_sdref = _mdns_sdref; // for later deallocation
+	_mdns_sdref = NULL;
+	pthread_mutex_unlock(&_mdns_mutex);
+}
+
+static void
+_mdns_init(void)
+{
+	pthread_atfork(_mdns_atfork_prepare, _mdns_atfork_parent, _mdns_atfork_child);
+
+	if (getenv("RES_DEBUG") != NULL) _mdns_debug |= MDNS_DEBUG_STDOUT;
+	int fd = open(MDNS_DEBUG_FILE, O_RDONLY, 0);
+	errno = 0;
+	if (fd >= 0)
+	{
+		int i, n;
+		char c[5];
+		memset(c, 0, sizeof(c));
+		n = read(fd, c, 4);
+
+		for (i = 0; i < n; i++)
+		{
+			if ((c[i] == 'o') || (c[i] == 'O')) _mdns_debug |= MDNS_DEBUG_STDOUT;
+			if ((c[i] == 'e') || (c[i] == 'E')) _mdns_debug |= MDNS_DEBUG_STDERR;
+			if ((c[i] == 'a') || (c[i] == 'A')) _mdns_debug |= MDNS_DEBUG_ASL;
+			if ((c[i] == 'm') || (c[i] == 'M')) _mdns_debug |= MDNS_DEBUG_MORE;
+		}
+	}
+}
+
+si_mod_t *
+si_module_static_mdns(void)
+{
+	static const struct si_mod_vtable_s mdns_vtable =
+	{
+		.sim_close = &mdns_close,
+		.sim_is_valid = &mdns_is_valid,
+		.sim_host_byname = &mdns_hostbyname,
+		.sim_host_byaddr = &mdns_hostbyaddr,
+		.sim_item_call = &mdns_item_call,
+		.sim_addrinfo = &mdns_addrinfo,
+		.sim_srv_byname = &mdns_srv_byname,
+	};
+
+	static si_mod_t si =
+	{
+		.vers = 1,
+		.refcount = 1,
+		.flags = SI_MOD_FLAG_STATIC,
+
+		.private = NULL,
+		.vtable = &mdns_vtable,
+	};
+
+	static dispatch_once_t once;
+
+	dispatch_once(&once, ^{
+		si.name = strdup("mdns");
+		_mdns_init();
+	});
+
+	return (si_mod_t*)&si;
+}
+
+/*
+ * _mdns_parse_domain_name
+ * Combine DNS labels to form a string.
+ * DNSService API does not return compressed names.
+ */
+static char *
+_mdns_parse_domain_name(const uint8_t *data, uint32_t datalen)
+{
+	int i = 0, j = 0;
+	uint32_t len;
+	uint32_t domainlen = 0;
+	char *domain = NULL;
+
+	if ((data == NULL) || (datalen == 0)) return NULL;
+
+	// i: index into input data
+	// j: index into output string
+	while (datalen-- > 0) {
+		len = data[i++];
+		domainlen += (len + 1);
+		domain = reallocf(domain, domainlen);
+		if (domain == NULL) return NULL;
+		if (len == 0) break;	// DNS root (NUL)
+		if (j > 0) {
+			domain[j++] = datalen ? '.' : '\0'; 
+		}
+
+		while ((len-- > 0) && (datalen--)) {
+			if (data[i] == '.') {
+				// special case: escape the '.' with a '\'
+				domain = reallocf(domain, ++domainlen);
+				if (domain == NULL) return NULL;
+				domain[j++] = '\\';
+			}
+			domain[j++] = data[i++];
+		}
+	}
+	domain[j] = '\0';
+
+	return domain;
+}
+
+/*
+ * _mdns_pack_domain_name
+ * Format the string as packed DNS labels.
+ * Only used for one string at a time, therefore no need for compression.
+ */
+static int
+_mdns_pack_domain_name(const char* str, uint8_t *buf, size_t buflen) {
+	int i = 0;
+	uintptr_t len = 0;
+
+	while (i < buflen) {
+		// calculate length to next '.' or '\0'
+		char *dot = strchr(str, '.');
+		if (dot == NULL) dot = strchr(str, '\0');
+		len = (dot - str);
+		if (len > NS_MAXLABEL) return -1;
+		// copy data for label
+		buf[i++] = len;
+		while (str < dot && i < buflen) {
+			buf[i++] = *str++;
+		}
+		// skip past '.', break if '\0'
+		if (*str++ == '\0') break;
+	}
+
+	if (i >= buflen) return -1;
+
+	if (len > 0) {
+		// no trailing dot - add a null label
+		buf[i++] = 0;
+		if (i >= buflen) return -1;
+	}
+
+	buf[i] = '\0';
+	return i;
+}
+
+static int
+_is_rev_link_local(const char *name)
+{
+	int len, i;
+
+	if (name == NULL) return 0;
+
+	len = strlen(name);
+	if (len == 0) return 0;
+
+	/* check for trailing '.' */
+	if (name[len - 1] == '.') len--;
+
+	if (len != IPv6_REVERSE_LEN) return 0;
+
+	i = IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR;
+	if ((name[i] != '8') && (name[i] != '9') && (name[i] != 'A') && (name[i] != 'a') && (name[i] != 'B') && (name[i] != 'b')) return 0;
+
+	i = IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR + 1;
+	if (strncasecmp(name + i, ".e.f.ip6.arpa", 13)) return 0;
+
+	for (i = 0; i < IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR; i += 2)
+	{
+		if (name[i] < '0') return 0;
+		if ((name[i] > '9') && (name[i] < 'A')) return 0;
+		if ((name[i] > 'F') && (name[i] < 'a')) return 0;
+		if (name[i] > 'f') return 0;
+		if (name[i + 1] != '.') return 0;
+	}
+
+	return 1;
+}
+
+/* _mdns_ipv6_extract_scope_id
+ * If the input string is a link local IPv6 address with an encoded scope id,
+ * the scope id is extracted and a new string is constructed with the scope id removed.
+ */
+static char *
+_mdns_ipv6_extract_scope_id(const char *name, uint32_t *out_ifnum)
+{
+	char *qname = NULL;
+	uint16_t nibble;
+	uint32_t iface;
+	int i;
+
+	if (out_ifnum != NULL) *out_ifnum = 0;
+
+	/* examine the address, extract the scope id if present */
+	if ((name != NULL) && (_is_rev_link_local(name)))
+	{
+		/* _is_rev_link_local rejects chars > 127 so it's safe to index into hexval */
+		i = IPv6_REVERSE_LINK_LOCAL_SCOPE_ID_LOW;
+		nibble = hexval[(uint32_t)name[i]];
+		iface = nibble;
+
+		i += 2;
+		nibble = hexval[(uint32_t)name[i]];
+		iface += (nibble << 4);
+
+		i += 2;
+		nibble = hexval[(uint32_t)name[i]];
+		iface += (nibble << 8);
+
+		i += 2;
+		nibble = hexval[(uint32_t)name[i]];
+		iface += (nibble << 12);
+
+		if (iface != 0)
+		{
+			qname = strdup(name);
+			if (qname == NULL) return NULL;
+
+			i = IPv6_REVERSE_LINK_LOCAL_SCOPE_ID_LOW;
+			qname[i] = '0';
+			qname[i + 2] = '0';
+			qname[i + 4] = '0';
+			qname[i + 6] = '0';
+
+			if (out_ifnum) *out_ifnum = iface;
+		}
+	}
+
+	return qname;
+}
+
+static int
+_mdns_make_query(const char* name, int class, int type, uint8_t *buf, uint32_t buflen)
+{
+	uint32_t len = 0;
+
+	if (buf == NULL || buflen < (NS_HFIXEDSZ + NS_QFIXEDSZ)) return -1;
+	memset(buf, 0, NS_HFIXEDSZ);
+	HEADER *hp = (HEADER *)buf;
+
+	len += NS_HFIXEDSZ;
+	hp->id = arc4random();
+	hp->qr = 1;
+	hp->opcode = ns_o_query;
+	hp->rd = 1;
+	hp->rcode = ns_r_noerror;
+	hp->qdcount = htons(1);
+
+	int n = _mdns_pack_domain_name(name, &buf[len], buflen - len);
+	if (n < 0) return -1;
+
+	len += n;
+	uint16_t word;
+	word = htons(type);
+	memcpy(&buf[len], &word, sizeof(word));
+	len += sizeof(word);
+	word = htons(class);
+	memcpy(&buf[len], &word, sizeof(word));
+	len += sizeof(word);
+	return len;
+}
+
+typedef struct {
+	mdns_reply_t *reply;
+	mdns_hostent_t *host;
+	uint8_t *answer; // DNS packet buffer
+	size_t anslen; // DNS packet buffer current length
+	size_t ansmaxlen; // DNS packet buffer maximum length
+	int type; // type of query: A, AAAA, PTR, SRV...
+	uint16_t last_type; // last type received
+	uint32_t sd_gen;
+	DNSServiceRef sd;
+	DNSServiceFlags flags;
+	DNSServiceErrorType error;
+	int kq; // kqueue to notify when callback received
+} mdns_query_context_t;
+
+static void
+_mdns_query_callback(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, uint16_t, uint16_t, uint16_t, const void *, uint32_t, void *);
+
+/* _mdns_query_start
+ * initializes the context and starts a DNS-SD query.
+ */
+static DNSServiceErrorType
+_mdns_query_start(mdns_query_context_t *ctx, mdns_reply_t *reply, uint8_t *answer, uint32_t *anslen, const char* name, int class, int type, const char *interface, DNSServiceFlags flags, int kq)
+{
+	DNSServiceErrorType status;
+
+	flags |= kDNSServiceFlagsShareConnection;
+	flags |= kDNSServiceFlagsReturnIntermediates;
+
+	/* <rdar://problem/7428439> mDNSResponder is now responsible for timeouts */
+	flags |= kDNSServiceFlagsTimeout;
+
+	memset(ctx, 0, sizeof(mdns_query_context_t));
+
+	if (answer && anslen) {
+		// build a dummy DNS header to return to the caller
+		ctx->answer = answer;
+		ctx->ansmaxlen = *anslen;
+		ctx->anslen = _mdns_make_query(name, class, type, answer, ctx->ansmaxlen);
+		if (ctx->anslen <= 0) return -1;
+	}
+
+	ctx->type = type;
+	ctx->sd = _mdns_sdref;
+	ctx->sd_gen = _mdns_generation;
+	ctx->kq = kq;
+	if (reply) {
+		ctx->reply = reply;
+		if (type == ns_t_a) ctx->host = reply->h4;
+		else if (type == ns_t_aaaa) ctx->host = reply->h6;
+		else if (type == ns_t_ptr && reply->h4) ctx->host = reply->h4;
+		else if (type == ns_t_ptr && reply->h6) ctx->host = reply->h6;
+		else if (type != ns_t_srv && type != ns_t_cname) return -1;
+	}
+
+	uint32_t iface = 0;
+	char *qname = _mdns_ipv6_extract_scope_id(name, &iface);
+	if (qname == NULL) qname = (char *)name;
+
+	if (interface != NULL)
+	{
+		/* get interface number from name */
+		int iface2 = if_nametoindex(interface);
+
+		/* balk if interface name lookup failed */
+		if (iface2 == 0) return -1;
+
+		/* balk if scope id is set AND interface is given AND they don't match */
+		if ((iface != 0) && (iface2 != 0) && (iface != iface2)) return -1;
+		if (iface2 != 0) iface = iface2;
+	}
+
+	_mdns_debug_message(";; mdns query %s %d %d [ctx %p]\n", qname, type, class, ctx);
+
+	status = DNSServiceQueryRecord(&ctx->sd, flags, iface, qname, type, class, _mdns_query_callback, ctx);
+	if (qname != name) free(qname);
+	return status;
+}
+
+/* _mdns_query_is_complete
+ * Determines whether the specified query has sufficient information to be
+ * considered complete.
+ */
+static int
+_mdns_query_is_complete(mdns_query_context_t *ctx)
+{
+	int complete = 0;
+
+	/* NULL context is an error, but we call it complete */
+	if (ctx == NULL) return 1;
+
+	/*
+	 * The default is to ignore kDNSServiceFlagsMoreComing, since it has either
+	 * never been supported or worked correctly.  MDNS_DEBUG_MORE makes us honor it.
+	 */
+	if (ctx->flags & kDNSServiceFlagsMoreComing) {
+		if (_mdns_debug & MDNS_DEBUG_MORE) {
+			_mdns_debug_message(";; mdns is_complete type %d ctx %p more coming - incomplete\n", ctx->type, ctx);
+			return 0;
+		}
+	}
+
+	if (ctx->last_type != ctx->type) {
+		_mdns_debug_message(";; mdns is_complete ctx %p type mismatch (%d != %d) - incomplete\n", ctx, ctx->last_type, ctx->type);
+		return 0;
+	}
+
+	switch (ctx->type) {
+		case ns_t_a:
+		case ns_t_aaaa:
+			if (ctx->host != NULL && ctx->host->addr_count > 0) complete = 1;
+			break;
+		case ns_t_ptr:
+			if (ctx->host != NULL && ctx->host->host.h_name != NULL) complete = 1;
+			break;
+		case ns_t_srv:
+			if (ctx->reply != NULL && ctx->reply->srv != NULL) complete = 1;
+			break;
+		default:
+			_mdns_debug_message(";; mdns is_complete unexpected type %d ctx %p\n", ctx->type, ctx);
+	}
+
+	_mdns_debug_message(";; mdns is_complete type %d ctx %p %s%scomplete\n", ctx->type, ctx, (ctx->flags & kDNSServiceFlagsMoreComing) ? "(more coming flag ignored)" : "", (complete == 0) ? " - in" : " - ");
+
+	return complete;
+}
+
+/* _mdns_query_clear
+ * Clear out the temporary fields of the context, and clear any result
+ * structures that are incomplete.  Retrns 1 if the query was complete.
+ */
+static int
+_mdns_query_clear(mdns_query_context_t *ctx)
+{
+	int complete = _mdns_query_is_complete(ctx);
+	if (ctx == NULL) return complete;
+
+	if (ctx->sd != NULL) {
+		/* only dealloc this DNSServiceRef if the "main" _mdns_sdref has not been deallocated */
+		if (ctx->sd != NULL && ctx->sd_gen == _mdns_generation) {
+			DNSServiceRefDeallocate(ctx->sd);
+		}
+	}
+
+	ctx->sd = NULL;
+	ctx->sd_gen = 0;
+	ctx->flags = 0;
+	ctx->kq = -1;
+
+	if (complete == 0) {
+		_mdns_hostent_clear(ctx->host);
+		ctx->anslen = -1;
+	}
+
+	return complete;
+}
+
+static void
+_mdns_query_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *ctx)
+{
+	mdns_query_context_t *context;
+	struct in6_addr a6;
+
+	context = (mdns_query_context_t *)ctx;
+
+	context->flags = flags;
+	context->error = errorCode;
+	context->last_type = rrtype;
+
+	if (errorCode != kDNSServiceErr_NoError) {
+		_mdns_debug_message(";; [%s %hu %hu]: error %d [ctx %p]\n", fullname, rrtype, rrclass, errorCode, context);
+		goto wakeup_kevent;
+	}
+
+	// embed the scope ID into link-local IPv6 addresses
+	if (rrtype == ns_t_aaaa && rdlen == sizeof(struct in6_addr) &&
+	    IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)rdata)) {
+		memcpy(&a6, rdata, rdlen);
+		a6.__u6_addr.__u6_addr16[1] = htons(ifIndex);
+		rdata = &a6;
+	}
+
+	if (context->reply) {
+		char *name;
+		int malformed = 0;
+		mdns_reply_t *reply = context->reply;
+
+		if (reply->ifnum == 0) {
+			reply->ifnum = ifIndex;
+		}
+
+		_mdns_hostent_append_alias(context->host, fullname);
+		if (reply->ttl == 0 || ttl < reply->ttl) reply->ttl = ttl;
+
+		switch (rrtype) {
+			case ns_t_a:
+			case ns_t_aaaa:
+				if (((rrtype == ns_t_a && context->host->host.h_addrtype == AF_INET) ||
+					 (rrtype == ns_t_aaaa && context->host->host.h_addrtype == AF_INET6)) &&
+					rdlen >= context->host->host.h_length) {
+					if (context->host->host.h_name == NULL) {
+						int i;
+						mdns_hostent_t *h = context->host;
+						char *h_name = _mdns_canonicalize(fullname);
+						context->host->host.h_name = h_name;
+
+						// 6863416 remove h_name from h_aliases
+						for (i = 0; i < h->alias_count; ++i) {
+							if (h_name == NULL) break;
+							if (string_equal(h->host.h_aliases[i], h_name)) {
+								// includes trailing NULL pointer
+								int sz = sizeof(char *) * (h->alias_count - i);
+								free(h->host.h_aliases[i]);
+								memmove(&h->host.h_aliases[i], &h->host.h_aliases[i+1], sz);
+								h->alias_count -= 1;
+								break;
+							}
+						}
+					}
+					_mdns_hostent_append_addr(context->host, rdata, context->host->host.h_length);
+				} else {
+					malformed = 1;
+				}
+				break;
+			case ns_t_cname:
+				name = _mdns_parse_domain_name(rdata, rdlen);
+				if (!name) malformed = 1;
+				_mdns_hostent_append_alias(context->host, name);
+				_mdns_debug_message(";; [%s %hu %hu] cname %s [ctx %p]\n", fullname, rrtype, rrclass, name, context);
+				free(name);
+				break;
+			case ns_t_ptr:
+				name = _mdns_parse_domain_name(rdata, rdlen);
+				if (!name) malformed = 1;
+				if (context->host && context->host->host.h_name == NULL) {
+					context->host->host.h_name = _mdns_canonicalize(name);
+				}
+				_mdns_hostent_append_alias(context->host, name);
+				free(name);
+				break;
+			case ns_t_srv: {
+				mdns_rr_srv_t *p = (mdns_rr_srv_t*)rdata;
+				mdns_srv_t *srv = calloc(1, sizeof(mdns_srv_t));
+				if (srv == NULL) break;
+				if (rdlen < sizeof(mdns_rr_srv_t)) {
+					malformed = 1;
+					break;
+				}
+				srv->srv.priority = ntohs(p->priority);
+				srv->srv.weight = ntohs(p->weight);
+				srv->srv.port = ntohs(p->port);
+				srv->srv.target = _mdns_parse_domain_name(&p->target[0], rdlen - 3*sizeof(uint16_t));
+				if (srv->srv.target == NULL) {
+					malformed = 1;
+					break;
+				}
+				// append to the end of the list
+				if (reply->srv == NULL) {
+					reply->srv = srv;
+				} else {
+					mdns_srv_t *iter = reply->srv;
+					while (iter->next) iter = iter->next;
+					iter->next = srv;
+				}
+				break;
+			}
+			default:
+				malformed = _mdns_debug;
+				break;
+		}
+		if (malformed != 0) {
+			_mdns_debug_message(";; [%s %hu %hu]: malformed reply [ctx %p]\n", fullname, rrtype, rrclass, context);
+			goto wakeup_kevent;
+		}
+	}
+
+	if (context->answer) {
+		int n;
+		uint8_t *cp;
+		HEADER *ans;
+		size_t buflen = context->ansmaxlen - context->anslen;
+		if (buflen < NS_HFIXEDSZ) {
+			_mdns_debug_message(";; [%s %hu %hu]: malformed reply (too small) [ctx %p]\n", fullname, rrtype, rrclass, context);
+			goto wakeup_kevent;
+		}
+
+		cp = context->answer + context->anslen;
+
+		n = _mdns_pack_domain_name(fullname, cp, buflen);
+		if (n < 0) {
+			_mdns_debug_message(";; [%s %hu %hu]: name mismatch [ctx %p]\n", fullname, rrtype, rrclass, context);
+			goto wakeup_kevent;
+		}
+
+		// check that there is enough space in the buffer for the
+		// resource name (n), the resource record data (rdlen) and
+		// the resource record header (10).
+		if (buflen < n + rdlen + 10) {
+			_mdns_debug_message(";; [%s %hu %hu]: insufficient buffer space for reply [ctx %p]\n", fullname, rrtype, rrclass, context);
+			goto wakeup_kevent;
+		}
+
+		cp += n;
+		buflen -= n;
+
+		uint16_t word;
+		uint32_t longword;
+
+		word = htons(rrtype);
+		memcpy(cp, &word, sizeof(word));
+		cp += sizeof(word);
+
+		word = htons(rrclass);
+		memcpy(cp, &word, sizeof(word));
+		cp += sizeof(word);
+
+		longword = htonl(ttl);
+		memcpy(cp, &longword, sizeof(longword));
+		cp += sizeof(longword);
+
+		word = htons(rdlen);
+		memcpy(cp, &word, sizeof(word));
+		cp += sizeof(word);
+
+		memcpy(cp, rdata, rdlen);
+		cp += rdlen;
+
+		ans = (HEADER *)context->answer;
+		ans->ancount = htons(ntohs(ans->ancount) + 1);
+
+		context->anslen = (size_t)(cp - context->answer);
+	}
+
+	_mdns_debug_message(";; [%s %hu %hu] reply [ctx %p]\n", fullname, rrtype, rrclass, context);
+
+wakeup_kevent:
+	// Ping the waiting thread in case this callback was invoked on another
+	if (context->kq != -1) {
+		struct kevent ev;
+		EV_SET(&ev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, 0);
+		int res = kevent(context->kq, &ev, 1, NULL, 0, NULL);
+		if (res != 0) _mdns_debug_message(";; kevent EV_TRIGGER: %s [ctx %p]\n", strerror(errno), context);
+	}
+}
+
+static void
+_mdns_now(struct timespec *now) {
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	now->tv_sec = tv.tv_sec;
+	now->tv_nsec = tv.tv_usec * 1000;
+}
+
+static void
+_mdns_add_time(struct timespec *sum, const struct timespec *a, const struct timespec *b)
+{
+	sum->tv_sec = a->tv_sec + b->tv_sec;
+	sum->tv_nsec = a->tv_nsec + b->tv_nsec;
+	if (sum->tv_nsec > 1000000000) {
+		sum->tv_sec += (sum->tv_nsec / 1000000000);
+		sum->tv_nsec %= 1000000000;
+	}
+}
+
+// calculate a deadline from the current time based on the desired timeout
+static void
+_mdns_deadline(struct timespec *deadline, const struct timespec *delta)
+{
+	struct timespec now;
+	_mdns_now(&now);
+	_mdns_add_time(deadline, &now, delta);
+}
+
+static void
+_mdns_sub_time(struct timespec *delta, const struct timespec *a, const struct timespec *b)
+{
+	delta->tv_sec = a->tv_sec - b->tv_sec;
+	delta->tv_nsec = a->tv_nsec - b->tv_nsec;
+	if (delta->tv_nsec < 0) {
+		delta->tv_nsec += 1000000000;
+		delta->tv_sec -= 1;
+	}
+}
+
+// calculate a timeout remaining before the given deadline
+static void
+_mdns_timeout(struct timespec *timeout, const struct timespec *deadline)
+{
+	struct timespec now;
+	_mdns_now(&now);
+	_mdns_sub_time(timeout, deadline, &now);
+}
+
+int
+_mdns_search(const char *name, int class, int type, const char *interface, DNSServiceFlags flags, uint8_t *answer, uint32_t *anslen, mdns_reply_t *reply)
+{
+	DNSServiceErrorType err = 0;
+	int kq, n, wait = 1;
+	struct kevent ev;
+	struct timespec start, finish, delta, timeout;
+	int res = 0;
+	int i, complete, got_a_response = 0;
+	int initialize = 1;
+	uint32_t n_iface_4 = 0;
+
+	// determine number of IPv4 interfaces (ignore loopback)
+	si_inet_config(&n_iface_4, NULL);
+	if (n_iface_4 > 0) n_iface_4--;
+
+	// <rdar://problem/7732497> limit the number of initialization retries
+	int initialize_retries = 3;
+
+	// 2 for A and AAAA parallel queries
+	int n_ctx = 0;
+	mdns_query_context_t ctx[2];
+
+	if (name == NULL) return -1;
+
+#if TARGET_OS_EMBEDDED
+	// log a warning for queries from the main thread 
+	if (pthread_is_threaded_np() && pthread_main_np()) asl_log(NULL, NULL, ASL_LEVEL_WARNING, "Warning: Libinfo call to mDNSResponder on main thread");
+#endif // TARGET_OS_EMBEDDED
+
+	// Timeout Logic
+	// The kevent(2) API timeout parameter is used to enforce the total
+	// timeout of the DNS query.  Each iteraion recalculates the relative
+	// timeout based on the desired end time (total timeout from origin).
+	//
+	// In order to workaround some DNS configurations that do not return
+	// responses for AAAA queries, parallel queries modify the total
+	// timeout upon receipt of the first response.  The new total timeout is
+	// set to an effective value of 2N where N is the time taken to receive
+	// the A response (the original total timeout is preserved if 2N would
+	// have exceeded it).  However, since mDNSResponder caches values, a
+	// minimum value of 50ms for N is enforced in order to give some time
+	// for the receipt of a AAAA response.
+
+	// determine the maximum time to wait for a result
+	delta.tv_sec = RES_MAXRETRANS + 5;
+	delta.tv_nsec = 0;
+	_mdns_deadline(&finish, &delta);
+	timeout = delta;
+	_mdns_now(&start);
+
+	for (i = 0; i < 2; ++i) {
+		memset(&ctx[i], 0 , sizeof(mdns_query_context_t));
+	}
+
+	// set up the kqueue
+	kq = kqueue();
+	EV_SET(&ev, 1, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, 0);
+	n = kevent(kq, &ev, 1, NULL, 0, NULL);
+	if (n != 0) wait = 0;
+
+	while (wait == 1) {
+		if (initialize) {
+			initialize = 0;
+			pthread_mutex_lock(&_mdns_mutex);
+			// clear any stale contexts
+			for (i = 0; i < n_ctx; ++i) {
+				_mdns_query_clear(&ctx[i]);
+			}
+			n_ctx = 0;
+
+			if (_mdns_sdref == NULL) {
+				if (_mdns_old_sdref != NULL) {
+					_mdns_generation++;
+					DNSServiceRefDeallocate(_mdns_old_sdref);
+					_mdns_old_sdref = NULL;
+				}
+				// (re)initialize the shared connection
+				err = DNSServiceCreateConnection(&_mdns_sdref);
+
+				// limit the number of retries
+				if (initialize_retries-- <= 0 && err == 0) {
+					err = kDNSServiceErr_Unknown;
+				}
+				if (err != 0) {
+					wait = 0;
+					pthread_mutex_unlock(&_mdns_mutex);
+					break;
+				}
+			}
+
+			// issue (or reissue) the queries
+			// unspecified type: do parallel A and AAAA
+			if (err == 0) {
+				err = _mdns_query_start(&ctx[n_ctx++], reply,
+										answer, anslen,
+										name, class,
+										(type == 0) ? ns_t_a : type, interface, flags, kq);
+			}
+
+			if (err == 0 && type == 0) {
+				err = _mdns_query_start(&ctx[n_ctx++], reply,
+										answer, anslen,
+										name, class, ns_t_aaaa, interface, flags, kq);
+			}
+
+			if (err != 0) {
+				_mdns_debug_message(";; initialization error %d\n", err);
+			}
+
+			// try to reinitialize
+			if (err == kDNSServiceErr_Unknown ||
+				err == kDNSServiceErr_ServiceNotRunning ||
+				err == kDNSServiceErr_BadReference) {
+				if (_mdns_sdref) {
+					_mdns_generation++;
+					DNSServiceRefDeallocate(_mdns_sdref);
+					_mdns_sdref = NULL;
+				}
+				err = 0;
+				initialize = 1;
+				pthread_mutex_unlock(&_mdns_mutex);
+				continue;
+			} else if (err != 0) {
+				pthread_mutex_unlock(&_mdns_mutex);
+				break;
+			}
+
+			// (re)register the fd with kqueue
+			int fd = DNSServiceRefSockFD(_mdns_sdref);
+			EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
+			n = kevent(kq, &ev, 1, NULL, 0, NULL);
+			pthread_mutex_unlock(&_mdns_mutex);
+			if (err != 0 || n != 0) break;
+		}
+
+		_mdns_debug_message(";; set kevent timeout %ld.%ld [ctx %p %p]\n", timeout.tv_sec, timeout.tv_nsec, (n_ctx > 0) ? &(ctx[0]) : NULL, (n_ctx > 1) ? &(ctx[1]) : NULL);
+
+		n = kevent(kq, NULL, 0, &ev, 1, &timeout);
+		if (n < 0 && errno != EINTR) {
+			res = -1;
+			break;
+		}
+
+		pthread_mutex_lock(&_mdns_mutex);
+		// DNSServiceProcessResult() is a blocking API
+		// confirm that there is still data on the socket
+		const struct timespec notimeout = { 0, 0 };
+		int m = kevent(kq, NULL, 0, &ev, 1, &notimeout);
+		if (_mdns_sdref == NULL) {
+			initialize = 1;
+		} else if (m > 0 && ev.filter == EVFILT_READ) {
+			err = DNSServiceProcessResult(_mdns_sdref);
+			if (err == kDNSServiceErr_ServiceNotRunning ||
+			    err == kDNSServiceErr_BadReference) {
+				_mdns_debug_message(";; DNSServiceProcessResult status %d [ctx %p %p]\n", err, (n_ctx > 0) ? &(ctx[0]) : NULL, (n_ctx > 1) ? &(ctx[1]) : NULL);
+				err = 0;
+				// re-initialize the shared connection
+				_mdns_generation++;
+				DNSServiceRefDeallocate(_mdns_sdref);
+				_mdns_sdref = NULL;
+				initialize = 1;
+			}
+		}
+
+		// Check if all queries are complete (including errors)
+		complete = 1;
+		for (i = 0; i < n_ctx; ++i) {
+			if ((ctx[i].error != 0) || _mdns_query_is_complete(&ctx[i])) {
+				if (ctx[i].type == ns_t_a) {
+					got_a_response = GOT_DATA;
+					if (ctx[i].error != 0) got_a_response = GOT_ERROR;
+				}
+				_mdns_debug_message(";; [%s %d %d] finished processing ctx %p\n", name, class, type, &(ctx[i]));
+
+			} else {
+				_mdns_debug_message(";; [%s %d %d] continuing ctx %p\n", name, class, type, &(ctx[i]));
+				complete = 0;
+			}
+		}
+		pthread_mutex_unlock(&_mdns_mutex);
+
+		if (err != 0) {
+			_mdns_debug_message(";; DNSServiceProcessResult error status %d [ctx %p %p]\n", err, (n_ctx > 0) ? &(ctx[0]) : NULL, (n_ctx > 1) ? &(ctx[1]) : NULL);
+			break;
+		} else if (complete == 1) {
+			_mdns_debug_message(";; [%s %d %d] done [ctx %p %p]\n", name, class, type, (n_ctx > 0) ? &(ctx[0]) : NULL, (n_ctx > 1) ? &(ctx[1]) : NULL);
+			break;
+		} else if (got_a_response != 0) {
+			// got A, adjust deadline for AAAA
+			struct timespec now, tn, extra;
+
+			// delta = now - start
+			_mdns_now(&now);
+			_mdns_sub_time(&delta, &now, &start);
+
+			extra.tv_sec = SHORT_AAAA_EXTRA;
+			extra.tv_nsec = 0;
+
+			// if delta is small (<= 20 milliseconds), we probably got a result from mDNSResponder's cache
+			if ((delta.tv_sec == 0) && (delta.tv_nsec <= 20000000)) {
+				extra.tv_sec = MEDIUM_AAAA_EXTRA;
+			}
+			else if (n_iface_4 == 0) {
+				extra.tv_sec = LONG_AAAA_EXTRA;
+			} else if (got_a_response == GOT_ERROR) {
+				extra.tv_sec = MEDIUM_AAAA_EXTRA;
+			}
+
+			// tn = 2 * delta
+			_mdns_add_time(&tn, &delta, &delta);
+
+			// delta = tn + extra
+			_mdns_add_time(&delta, &tn, &extra);
+
+			// check that delta doesn't exceed our total timeout
+			_mdns_sub_time(&tn, &timeout, &delta);
+			if (tn.tv_sec >= 0) {
+				_mdns_debug_message(";; new timeout [%s %d %d] (waiting for AAAA) %ld.%ld [ctx %p %p]\n", name, class, type, delta.tv_sec, delta.tv_nsec, (n_ctx > 0) ? &(ctx[0]) : NULL, (n_ctx > 1) ? &(ctx[1]) : NULL);
+				_mdns_deadline(&finish, &delta);
+			}
+		}
+
+		// calculate remaining timeout
+		_mdns_timeout(&timeout, &finish);
+
+		// check for time remaining
+		if (timeout.tv_sec < 0) {
+			_mdns_debug_message(";; [%s %d %d] timeout [ctx %p %p]\n", name, class, type, (n_ctx > 0) ? &(ctx[0]) : NULL, (n_ctx > 1) ? &(ctx[1]) : NULL);
+			break;
+		}
+	}
+
+	complete = 0;
+	pthread_mutex_lock(&_mdns_mutex);
+	for (i = 0; i < n_ctx; ++i) {
+		if (err == 0) err = ctx[i].error;
+		// Only clears hostents if result is incomplete.
+		complete = _mdns_query_clear(&ctx[i]) || complete;
+	}
+	pthread_mutex_unlock(&_mdns_mutex);
+	// Everything should be done with the kq by now.
+	close(kq);
+
+	// Return error if everything is incomplete
+	if (complete == 0) {
+		res = -1;
+	}
+
+	if (anslen) *anslen = ctx[0].anslen;
+	return res;
+}


Property changes on: trunk/lib/libosxsupport/mdns_module.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/search_module.c
===================================================================
--- trunk/lib/libosxsupport/search_module.c	                        (rev 0)
+++ trunk/lib/libosxsupport/search_module.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,1085 @@
+/*
+ * Copyright (c) 2008-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 <stdlib.h>
+#include <paths.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <pthread.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <dispatch/dispatch.h>
+#include "si_module.h"
+
+#define _PATH_SI_CONF "/etc/sysinfo.conf"
+
+#define SEARCH_FLAG_CACHE_ENABLED 0x00000001
+#define SEARCH_MODULE_FLAG_DISABLED 0x00000001
+
+
+#ifdef __FreeBSD__
+void si_search_module_set_flags(const char *name, uint32_t flag);
+__private_extern__ void search_set_flags(si_mod_t *si, const char *name, uint32_t flag);
+si_mod_t *si_module_static_search(void);
+#endif
+
+si_mod_t *
+si_search(void)
+{
+	static si_mod_t *search = NULL;
+
+	if (search == NULL) search = si_module_with_name("search");
+
+	return search;
+}
+
+void
+si_search_module_set_flags(const char *name, uint32_t flag)
+{
+	search_set_flags(si_search(), name, flag);
+}
+
+typedef struct
+{
+	si_mod_t **module;
+	uint32_t *module_flags;
+	uint32_t count;
+	uint32_t flags;
+} search_list_t;
+
+typedef struct
+{
+	search_list_t search_list[CATEGORY_COUNT];
+	si_mod_t *cache;
+} search_si_private_t;
+
+extern void si_cache_add_item(si_mod_t *si, si_mod_t *src, si_item_t *item);
+extern void si_cache_add_list(si_mod_t *si, si_mod_t *src, si_list_t *list);
+
+extern char **_fsi_tokenize(char *data, const char *sep, int trailing_empty, int *ntokens);
+extern char *_fsi_get_line(FILE *fp);
+
+static void si_module_config_parse_line(search_si_private_t *pp, char *line);
+static void si_module_config_modules_for_category(search_si_private_t *pp, int cat, int ntokens, const char * const *tokens);
+
+
+static si_mod_t *
+search_get_module(search_si_private_t *pp, int cat, uint32_t *n)
+{
+	uint32_t x;
+
+	if ((pp == NULL) || (n == NULL)) return NULL;
+
+	x = *n;
+	*n = x + 1;
+
+	/* Use custom search list if available */
+	if (pp->search_list[cat].count > 0 && x < pp->search_list[cat].count)
+	{
+		return pp->search_list[cat].module[x];
+	}
+
+	/* Otherwise use the default search list */
+	while (x < pp->search_list[CATEGORY_DEFAULT].count)
+	{
+		if (pp->search_list[CATEGORY_DEFAULT].module_flags[x] & SEARCH_MODULE_FLAG_DISABLED)
+		{
+			x++;
+			*n = x + 1;
+		}
+		else
+		{
+			return pp->search_list[CATEGORY_DEFAULT].module[x];
+		}
+	}
+
+	return NULL;
+}
+
+__private_extern__ void
+search_set_flags(si_mod_t *si, const char *name, uint32_t flag)
+{
+	search_si_private_t *pp;
+	uint32_t i;
+
+	if (si == NULL) return;
+	if (si->private == NULL) return;
+
+	pp = (search_si_private_t *)si->private;
+
+	for (i = 0; i < pp->search_list[CATEGORY_DEFAULT].count; i++)
+	{
+		si_mod_t *mod = pp->search_list[CATEGORY_DEFAULT].module[i];
+		if ((mod == NULL) || (mod->name == NULL)) continue;
+
+		if (string_equal(name, mod->name))
+		{
+			pp->search_list[CATEGORY_DEFAULT].module_flags[i] = flag;
+			break;
+		}
+	}
+}
+
+static si_mod_t *
+search_cat_cache(search_si_private_t *pp, int cat)
+{
+	if (pp == NULL) return NULL;
+	if (cat < 0 || cat > CATEGORY_COUNT) return NULL;
+
+	if (pp->search_list[cat].count == 0)
+	{
+		cat = CATEGORY_DEFAULT;
+	}
+
+	if ((pp->search_list[cat].flags & SEARCH_FLAG_CACHE_ENABLED) != 0)
+	{
+		return pp->cache;
+	}
+
+	return NULL;
+}
+
+static void
+search_close(si_mod_t *si)
+{
+	int i;
+	search_si_private_t *pp;
+
+	if (si == NULL) return;
+	if (si->private == NULL) return;
+
+	pp = (search_si_private_t *)si->private;
+
+	for (i = 0; i < CATEGORY_COUNT; i++)
+	{
+		if (pp->search_list[i].module != NULL)
+		{
+			free(pp->search_list[i].module);
+			pp->search_list[i].module = NULL;
+			pp->search_list[i].count = 0;
+			pp->search_list[i].flags = 0;
+		}
+	}
+
+	free(pp);
+}
+
+static si_item_t *
+search_item_byname(si_mod_t *si, const char *name, int cat, si_item_t *(*call)(si_mod_t *, const char *))
+{
+	int i;
+	search_si_private_t *pp;
+	si_item_t *item;
+	si_mod_t *src;
+
+	if (si == NULL) return NULL;
+	if (call == NULL) return NULL;
+
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL) return NULL;
+
+	i = 0;
+
+	while (NULL != (src = search_get_module(pp, cat, &i)))
+	{
+		item = call(src, name);
+		if (item != NULL)
+		{
+			si_cache_add_item(search_cat_cache(pp, cat), src, item);
+			return item;
+		}
+	}
+
+	return NULL;
+}
+
+static si_item_t *
+search_item_bynumber(si_mod_t *si, uint32_t number, int cat, si_item_t *(*call)(si_mod_t *, uint32_t))
+{
+	int i;
+	search_si_private_t *pp;
+	si_item_t *item;
+	si_mod_t *src;
+
+	if (si == NULL) return NULL;
+	if (call == NULL) return NULL;
+
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL) return NULL;
+
+	i = 0;
+
+	while (NULL != (src = search_get_module(pp, cat, &i)))
+	{
+		item = call(src, number);
+		if (item != NULL)
+		{
+			si_cache_add_item(search_cat_cache(pp, cat), src, item);
+			return item;
+		}
+	}
+
+	return NULL;
+}
+
+static si_item_t *
+search_item_byuuid(si_mod_t *si, uuid_t uuid, int cat, si_item_t *(*call)(si_mod_t *, uuid_t))
+{
+	int i;
+	search_si_private_t *pp;
+	si_item_t *item;
+	si_mod_t *src;
+
+	if (si == NULL) return NULL;
+	if (call == NULL) return NULL;
+
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL) return NULL;
+
+	i = 0;
+
+	while (NULL != (src = search_get_module(pp, cat, &i)))
+	{
+		item = call(src, uuid);
+		if (item != NULL)
+		{
+			/*
+			 * N.B. item not added to cache, since the data does not
+			 * contain the uuid that was used to find it.
+			 */
+			return item;
+		}
+	}
+
+	return NULL;
+}
+static si_list_t *
+search_list(si_mod_t *si, int cat, si_list_t *(*call)(si_mod_t *))
+{
+	int i, null_res;
+	search_si_private_t *pp;
+	si_list_t *list, *all;
+	si_mod_t *cache, *src;
+
+	if (si == NULL) return NULL;
+	if (call == NULL) return NULL;
+
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL) return NULL;
+
+	cache = search_cat_cache(pp, cat);
+	if (cache != NULL)
+	{
+		list = call(cache);
+		if (list != NULL) return list;
+	}
+
+	i = 0;
+
+	all = NULL;
+	null_res = 0;
+
+	while (NULL != (src = search_get_module(pp, cat, &i)))
+	{
+		if (src == pp->cache) continue;
+
+		list = call(src);
+		if (list == NULL)
+		{
+			null_res = 1;
+			continue;
+		}
+
+		all = si_list_concat(all, list);
+		si_list_release(list);
+	}
+
+	if ((all != NULL) && (null_res == 0)) si_cache_add_list(cache, si, all);
+	return all;
+}
+
+static si_item_t *
+search_user_byname(si_mod_t *si, const char *name)
+{
+	return search_item_byname(si, name, CATEGORY_USER, si_user_byname);
+}
+
+static si_item_t *
+search_user_byuid(si_mod_t *si, uid_t uid)
+{
+	return search_item_bynumber(si, (uint32_t)uid, CATEGORY_USER, si_user_byuid);
+}
+
+static si_item_t *
+search_user_byuuid(si_mod_t *si, uuid_t uuid)
+{
+	return search_item_byuuid(si, uuid, CATEGORY_USER, si_user_byuuid);
+}
+
+static si_list_t *
+search_user_all(si_mod_t *si)
+{
+	return search_list(si, CATEGORY_USER, si_user_all);
+}
+
+static si_item_t *
+search_group_byname(si_mod_t *si, const char *name)
+{
+	return search_item_byname(si, name, CATEGORY_GROUP, si_group_byname);
+}
+
+static si_item_t *
+search_group_bygid(si_mod_t *si, gid_t gid)
+{
+	return search_item_bynumber(si, (uint32_t)gid, CATEGORY_GROUP, si_group_bygid);
+}
+
+static si_item_t *
+search_group_byuuid(si_mod_t *si, uuid_t uuid)
+{
+	return search_item_byuuid(si, uuid, CATEGORY_GROUP, si_group_byuuid);
+}
+
+static si_list_t *
+search_group_all(si_mod_t *si)
+{
+	return search_list(si, CATEGORY_GROUP, si_group_all);
+}
+
+static si_item_t *
+search_groupist(si_mod_t *si, const char *name, uint32_t count)
+{
+	int i;
+	search_si_private_t *pp;
+	si_item_t *item = NULL;
+	si_mod_t *src;
+	
+	if (si == NULL) return NULL;
+	
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL) return NULL;
+	
+	i = 0;
+	
+	while (NULL != (src = search_get_module(pp, CATEGORY_GROUPLIST, &i))) {
+		if (src == pp->cache) continue;
+		
+		if (src->vtable->sim_grouplist != NULL) {
+			item = src->vtable->sim_grouplist(si, name, count);
+			if (item != NULL) break;
+		}
+	}
+	
+	return item;
+}
+
+static si_list_t *
+search_netgroup_byname(si_mod_t *si, const char *name)
+{
+	int i, cat, null_res;
+	search_si_private_t *pp;
+	si_list_t *list, *all;
+	si_mod_t *cache, *src;
+
+	if (si == NULL) return NULL;
+
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL) return NULL;
+
+	cat = CATEGORY_NETGROUP;
+
+	cache = search_cat_cache(pp, cat);
+	if (cache != NULL)
+	{
+		list = si_netgroup_byname(cache, name);
+		if (list != NULL) return list;
+	}
+
+	i = 0;
+	null_res = 0;
+
+	all = NULL;
+	while (NULL != (src = search_get_module(pp, cat, &i)))
+	{
+		if (src == pp->cache) continue;
+
+		list = si_netgroup_byname(src, name);
+		if (list == NULL)
+		{
+			null_res = 1;
+			continue;
+		}
+
+		all = si_list_concat(all, list);
+		si_list_release(list);
+	}
+
+	if ((all != NULL) && (null_res == 0)) si_cache_add_list(cache, si, all);
+	return all;
+}
+
+static int
+search_in_netgroup(si_mod_t *si, const char *group, const char *host, const char *user, const char *domain)
+{
+	int i, cat, innetgr;
+	search_si_private_t *pp;
+	si_mod_t *src;
+
+	if (si == NULL) return 0;
+
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL) return 0;
+
+	cat = CATEGORY_NETGROUP;
+	i = 0;
+
+	while (NULL != (src = search_get_module(pp, cat, &i)))
+	{
+		innetgr = si_in_netgroup(src, group, host, user, domain);
+		if (innetgr != 0) return 1;
+	}
+
+	return 0;
+}
+
+static si_item_t *
+search_alias_byname(si_mod_t *si, const char *name)
+{
+	return search_item_byname(si, name, CATEGORY_ALIAS, si_alias_byname);
+}
+
+static si_list_t *
+search_alias_all(si_mod_t *si)
+{
+	return search_list(si, CATEGORY_ALIAS, si_alias_all);
+}
+
+static si_item_t *
+search_host_byname(si_mod_t *si, const char *name, int af, const char *interface, uint32_t *err)
+{
+	int i, cat;
+	search_si_private_t *pp;
+	si_item_t *item;
+	si_mod_t *src;
+
+	if (err != NULL) *err = SI_STATUS_NO_ERROR;
+
+	if ((si == NULL) || (name == NULL))
+	{
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+		return NULL;
+	}
+
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL)
+	{
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+		return NULL;
+	}
+
+	cat = CATEGORY_HOST_IPV4;
+	if (af == AF_INET6) cat = CATEGORY_HOST_IPV6;
+
+	i = 0;
+
+	while (NULL != (src = search_get_module(pp, cat, &i)))
+	{
+		item = si_host_byname(src, name, af, interface, err);
+		if (item != NULL)
+		{
+			si_cache_add_item(search_cat_cache(pp, cat), src, item);
+			return item;
+		}
+	}
+
+	if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
+	return NULL;
+}
+
+static si_item_t *
+search_host_byaddr(si_mod_t *si, const void *addr, int af, const char *interface, uint32_t *err)
+{
+	int i, cat;
+	search_si_private_t *pp;
+	si_item_t *item;
+	si_mod_t *src;
+
+	if (err != NULL) *err = SI_STATUS_NO_ERROR;
+
+	if ((si == NULL) || (addr == NULL))
+	{
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+		return NULL;
+	}
+
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL)
+	{
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+		return NULL;
+	}
+
+	cat = CATEGORY_HOST_IPV4;
+	if (af == AF_INET6) cat = CATEGORY_HOST_IPV6;
+
+	i = 0;
+
+	while (NULL != (src = search_get_module(pp, cat, &i)))
+	{
+		item = si_host_byaddr(src, addr, af, interface, err);
+		if (item != NULL)
+		{
+			si_cache_add_item(search_cat_cache(pp, cat), src, item);
+			return item;
+		}
+	}
+
+	if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
+	return NULL;
+}
+
+static si_list_t *
+search_host_all(si_mod_t *si)
+{
+	return search_list(si, CATEGORY_HOST, si_host_all);
+}
+
+static si_item_t *
+search_network_byname(si_mod_t *si, const char *name)
+{
+	return search_item_byname(si, name, CATEGORY_NETWORK, si_network_byname);
+}
+
+static si_item_t *
+search_network_byaddr(si_mod_t *si, uint32_t addr)
+{
+	return search_item_bynumber(si, addr, CATEGORY_NETWORK, si_network_byaddr);
+}
+
+static si_list_t *
+search_network_all(si_mod_t *si)
+{
+	return search_list(si, CATEGORY_NETWORK, si_network_all);
+}
+
+static si_item_t *
+search_service_byname(si_mod_t *si, const char *name, const char *proto)
+{
+	int i, cat;
+	si_item_t *item;
+	search_si_private_t *pp;
+	si_mod_t *src;
+
+	if (si == NULL) return NULL;
+	if (name == NULL) return NULL;
+
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL) return NULL;
+
+	cat = CATEGORY_SERVICE;
+	i = 0;
+
+	while (NULL != (src = search_get_module(pp, cat, &i)))
+	{
+		item = si_service_byname(src, name, proto);
+		if (item != NULL)
+		{
+			si_cache_add_item(search_cat_cache(pp, cat), src, item);
+			return item;
+		}
+	}
+
+	return NULL;
+}
+
+static si_item_t *
+search_service_byport(si_mod_t *si, int port, const char *proto)
+{
+	int i, cat;
+	search_si_private_t *pp;
+	si_item_t *item;
+	si_mod_t *src;
+
+	if (si == NULL) return NULL;
+
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL) return NULL;
+
+	cat = CATEGORY_SERVICE;
+	i = 0;
+
+	while (NULL != (src = search_get_module(pp, cat, &i)))
+	{
+		item = si_service_byport(src, port, proto);
+		if (item != NULL)
+		{
+			si_cache_add_item(search_cat_cache(pp, cat), src, item);
+			return item;
+		}
+	}
+
+	return NULL;
+}
+
+static si_list_t *
+search_service_all(si_mod_t *si)
+{
+	return search_list(si, CATEGORY_SERVICE, si_service_all);
+}
+
+static si_item_t *
+search_protocol_byname(si_mod_t *si, const char *name)
+{
+	return search_item_byname(si, name, CATEGORY_PROTOCOL, si_protocol_byname);
+}
+
+static si_item_t *
+search_protocol_bynumber(si_mod_t *si, int number)
+{
+	return search_item_bynumber(si, (uint32_t)number, CATEGORY_PROTOCOL, si_protocol_bynumber);
+}
+
+static si_list_t *
+search_protocol_all(si_mod_t *si)
+{
+	return search_list(si, CATEGORY_PROTOCOL, si_protocol_all);
+}
+
+static si_item_t *
+search_rpc_byname(si_mod_t *si, const char *name)
+{
+	return search_item_byname(si, name, CATEGORY_RPC, si_rpc_byname);
+}
+
+static si_item_t *
+search_rpc_bynumber(si_mod_t *si, int number)
+{
+	int i, cat;
+	search_si_private_t *pp;
+	si_item_t *item;
+	si_mod_t *src;
+
+	if (si == NULL) return NULL;
+
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL) return NULL;
+
+	cat = CATEGORY_RPC;
+	i = 0;
+
+	while (NULL != (src = search_get_module(pp, cat, &i)))
+	{
+		item = si_rpc_bynumber(src, number);
+		if (item != NULL)
+		{
+			si_cache_add_item(search_cat_cache(pp, cat), src, item);
+			return item;
+		}
+	}
+
+	return NULL;
+}
+
+static si_list_t *
+search_rpc_all(si_mod_t *si)
+{
+	return search_list(si, CATEGORY_RPC, si_rpc_all);
+}
+
+static si_item_t *
+search_fs_byspec(si_mod_t *si, const char *name)
+{
+	return search_item_byname(si, name, CATEGORY_FS, si_fs_byspec);
+}
+
+static si_item_t *
+search_fs_byfile(si_mod_t *si, const char *name)
+{
+	return search_item_byname(si, name, CATEGORY_FS, si_fs_byfile);
+}
+
+static si_list_t *
+search_fs_all(si_mod_t *si)
+{
+	return search_list(si, CATEGORY_FS, si_fs_all);
+}
+
+static si_item_t *
+search_mac_byname(si_mod_t *si, const char *name)
+{
+	return search_item_byname(si, name, CATEGORY_MAC, si_mac_byname);
+}
+
+static si_item_t *
+search_mac_bymac(si_mod_t *si, const char *mac)
+{
+	return search_item_byname(si, mac, CATEGORY_MAC, si_mac_bymac);
+}
+
+static si_list_t *
+search_mac_all(si_mod_t *si)
+{
+	return search_list(si, CATEGORY_MAC, si_mac_all);
+}
+
+static si_list_t *
+search_srv_byname(si_mod_t *si, const char* qname, const char *interface, uint32_t *err)
+{
+	int i, cat;
+	si_list_t *list = NULL;
+	si_mod_t *src;
+	search_si_private_t *pp;
+
+	if (si == NULL) return NULL;
+
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL) return NULL;
+
+	cat = CATEGORY_SRV;
+	i = 0;
+
+	while (NULL != (src = search_get_module(pp, cat, &i)))
+	{
+		if (src == pp->cache) continue;
+
+		if (src->vtable->sim_srv_byname != NULL)
+		{
+			list = src->vtable->sim_srv_byname(src, qname, interface, err);
+			if (list != NULL) return list;
+		}
+	}
+
+	if ((i > 0) && (err != NULL)) *err = SI_STATUS_EAI_NONAME;
+	return NULL;
+}
+#ifndef __FreeBSD__
+static int
+search_wants_addrinfo(si_mod_t *si)
+{
+	int i, cat;
+	si_mod_t *src;
+	search_si_private_t *pp;
+
+	if (si == NULL) return 0;
+
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL) return 0;
+
+	cat = CATEGORY_ADDRINFO;
+	i = 0;
+
+	while (NULL != (src = search_get_module(pp, cat, &i)))
+	{
+		if (src == pp->cache) continue;
+		if (src->vtable->sim_addrinfo != NULL) return 1;
+	}
+
+	return 0;
+}
+
+static si_list_t *
+search_addrinfo(si_mod_t *si, const void *node, const void *serv, uint32_t family, uint32_t socktype, uint32_t protocol, uint32_t flags, const char *interface, uint32_t *err)
+{
+	int i, cat;
+	search_si_private_t *pp;
+	si_list_t *list = NULL;
+	si_mod_t *src;
+
+	if (err != NULL) *err = SI_STATUS_EAI_FAIL;
+
+	if (si == NULL) return NULL;
+
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL) return NULL;
+
+	cat = CATEGORY_ADDRINFO;
+	i = 0;
+
+	while (NULL != (src = search_get_module(pp, cat, &i)))
+	{
+		if (src == pp->cache) continue;
+
+		if (src->vtable->sim_addrinfo != NULL)
+		{
+			list = src->vtable->sim_addrinfo(src, node, serv, family, socktype, protocol, flags, interface, err);
+			if (list != NULL) return list;
+		}
+	}
+
+	if ((i > 0) && (err != NULL)) *err = SI_STATUS_EAI_NONAME;
+	return NULL;
+}
+
+static si_item_t *
+search_nameinfo(si_mod_t *si, const struct sockaddr *sa, int flags, const char *interface, uint32_t *err)
+{
+	int i, cat;
+	search_si_private_t *pp;
+	si_item_t *item;
+	si_mod_t *src;
+
+	if (err != NULL) *err = SI_STATUS_EAI_FAIL;
+
+	if (si == NULL) return NULL;
+
+	pp = (search_si_private_t *)si->private;
+	if (pp == NULL) return NULL;
+
+	cat = CATEGORY_NAMEINFO;
+	i = 0;
+
+	while (NULL != (src = search_get_module(pp, cat, &i)))
+	{
+		item = si_nameinfo(src, sa, flags, interface, err);
+		if (item != NULL)
+		{
+			si_cache_add_item(search_cat_cache(pp, cat), src, item);
+			if (err != NULL) *err = SI_STATUS_NO_ERROR;
+			return item;
+		}
+	}
+
+	if ((i > 0) && (err != NULL)) *err = SI_STATUS_EAI_NONAME;
+	return NULL;
+}
+#endif
+
+static int
+search_is_valid(si_mod_t *si, si_item_t *item)
+{
+	si_mod_t *src;
+
+	if (si == NULL) return 0;
+	if (item == NULL) return 0;
+	if (si->name == NULL) return 0;
+	if (item->src == NULL) return 0;
+
+	src = (si_mod_t *)item->src;
+
+	if (src->name == NULL) return 0;
+	if (string_not_equal(si->name, src->name)) return 0;
+	return 0;
+}
+
+si_mod_t *
+si_module_static_search(void)
+{
+	static const struct si_mod_vtable_s search_vtable =
+	{
+		.sim_close = &search_close,
+
+		.sim_is_valid = &search_is_valid,
+
+		.sim_user_byname = &search_user_byname,
+		.sim_user_byuid = &search_user_byuid,
+		.sim_user_byuuid = &search_user_byuuid,
+		.sim_user_all = &search_user_all,
+
+		.sim_group_byname = &search_group_byname,
+		.sim_group_bygid = &search_group_bygid,
+		.sim_group_byuuid = &search_group_byuuid,
+		.sim_group_all = &search_group_all,
+
+		.sim_grouplist = &search_groupist,
+
+		.sim_netgroup_byname = &search_netgroup_byname,
+		.sim_in_netgroup = &search_in_netgroup,
+
+		.sim_alias_byname = &search_alias_byname,
+		.sim_alias_all = &search_alias_all,
+
+		.sim_host_byname = &search_host_byname,
+		.sim_host_byaddr = &search_host_byaddr,
+		.sim_host_all = &search_host_all,
+
+		.sim_network_byname = &search_network_byname,
+		.sim_network_byaddr = &search_network_byaddr,
+		.sim_network_all = &search_network_all,
+
+		.sim_service_byname = &search_service_byname,
+		.sim_service_byport = &search_service_byport,
+		.sim_service_all = &search_service_all,
+
+		.sim_protocol_byname = &search_protocol_byname,
+		.sim_protocol_bynumber = &search_protocol_bynumber,
+		.sim_protocol_all = &search_protocol_all,
+
+		.sim_rpc_byname = &search_rpc_byname,
+		.sim_rpc_bynumber = &search_rpc_bynumber,
+		.sim_rpc_all = &search_rpc_all,
+
+		.sim_fs_byspec = &search_fs_byspec,
+		.sim_fs_byfile = &search_fs_byfile,
+		.sim_fs_all = &search_fs_all,
+
+		.sim_mac_byname = &search_mac_byname,
+		.sim_mac_bymac = &search_mac_bymac,
+		.sim_mac_all = &search_mac_all,
+#ifndef __FreeBSD__
+		.sim_addrinfo = &search_addrinfo,
+		.sim_wants_addrinfo = &search_wants_addrinfo,
+		.sim_nameinfo = &search_nameinfo,
+#endif
+		.sim_srv_byname = &search_srv_byname,
+	};
+
+	static si_mod_t si =
+	{
+		.vers = 1,
+		.refcount = 1,
+		.flags = SI_MOD_FLAG_STATIC,
+
+		.private = NULL,
+		.vtable = &search_vtable,
+	};
+
+	static dispatch_once_t once;
+
+	dispatch_once(&once, ^{
+		si.name = strdup("search");
+		search_si_private_t *pp = calloc(1, sizeof(search_si_private_t));
+		si.private = pp;
+
+		/*
+		 * Default search order:
+		 * 1) cache
+		 * 2) DirectoryService/OpenDirectory (where available)
+		 * 3) flat file
+		 * 4) mDNSResponder
+		 */
+
+		const char * const modules[] =
+		{
+			"default", // CATEGORY_DEFAULT
+			"cache",
+#ifdef DS_AVAILABLE
+			"ds",
+#endif
+			"mdns",
+			"file",
+		};
+
+		int count = sizeof(modules) / sizeof(char *);
+		si_module_config_modules_for_category(pp, CATEGORY_DEFAULT, count, modules);
+		pp->cache = pp->search_list[CATEGORY_DEFAULT].module[0];
+
+		char *check = getenv("SYSINFO_CONF_ENABLE");
+		if ((check != NULL) && (!strcmp(check, "1")))
+		{
+			FILE *conf = fopen(_PATH_SI_CONF, "r");
+			errno = 0;
+			if (conf != NULL)
+			{
+				forever
+				{
+					char *line = _fsi_get_line(conf);
+					if (line == NULL) break;
+
+					si_module_config_parse_line(pp, line);
+					free(line);
+				}
+
+				fclose(conf);
+			}
+		}
+	});
+
+	return &si;
+}
+
+static void
+si_module_config_parse_line(search_si_private_t *pp, char *line)
+{
+	if (line == NULL || line[0] == '#') {
+		return;
+	}
+
+	int ntokens = 0;
+	char **tokens = _fsi_tokenize(line, "	: ", 0, &ntokens);
+
+	int cat = CATEGORY_INVALID;
+
+	if (string_equal(tokens[0], "default")) cat = CATEGORY_DEFAULT;
+	else if (string_equal(tokens[0], "user")) cat = CATEGORY_USER;
+	else if (string_equal(tokens[0], "group")) cat = CATEGORY_GROUP;
+	else if (string_equal(tokens[0], "grouplist")) cat = CATEGORY_GROUPLIST;
+	else if (string_equal(tokens[0], "netgroup")) cat = CATEGORY_NETGROUP;
+	else if (string_equal(tokens[0], "alias")) cat = CATEGORY_ALIAS;
+	else if (string_equal(tokens[0], "host")) cat = CATEGORY_HOST_IPV4;
+	else if (string_equal(tokens[0], "network")) cat = CATEGORY_NETWORK;
+	else if (string_equal(tokens[0], "service")) cat = CATEGORY_SERVICE;
+	else if (string_equal(tokens[0], "protocol")) cat = CATEGORY_PROTOCOL;
+	else if (string_equal(tokens[0], "rpc")) cat = CATEGORY_RPC;
+	else if (string_equal(tokens[0], "fs")) cat = CATEGORY_FS;
+	else if (string_equal(tokens[0], "mac")) cat = CATEGORY_MAC;
+	else if (string_equal(tokens[0], "addrinfo")) cat = CATEGORY_ADDRINFO;
+	else if (string_equal(tokens[0], "nameinfo")) cat = CATEGORY_NAMEINFO;
+
+	if (cat != CATEGORY_INVALID)
+	{
+		si_module_config_modules_for_category(pp, cat, ntokens, (const char * const *)tokens);
+	}
+
+	free(tokens);
+}
+
+static void
+si_module_config_modules_for_category(search_si_private_t *pp, int cat, int ntokens, const char * const *tokens)
+{
+	int count = ntokens - 1;
+	pp->search_list[cat].count = count;
+	if (count == 0)
+	{
+		return;
+	}
+
+	pp->search_list[cat].module = (si_mod_t **)calloc(pp->search_list[cat].count, sizeof(si_mod_t *));
+	pp->search_list[cat].module_flags = (uint32_t *)calloc(pp->search_list[cat].count, sizeof(uint32_t));
+	if ((pp->search_list[cat].module == NULL) || (pp->search_list[cat].module_flags == NULL))
+	{
+		free(pp->search_list[cat].module);
+		free(pp->search_list[cat].module_flags);
+		return;
+	}
+
+	int i, j;
+	for (i = 1, j = 0; i < ntokens; i++)
+	{
+		si_mod_t *mod = si_module_with_name(tokens[i]);
+		if (mod != NULL)
+		{
+			pp->search_list[cat].module[j] = mod;
+			j++;
+
+			if (string_equal(tokens[i], "cache"))
+			{
+				pp->search_list[cat].flags |= SEARCH_FLAG_CACHE_ENABLED;
+			}
+		}
+	}
+}


Property changes on: trunk/lib/libosxsupport/search_module.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/si_data.c
===================================================================
--- trunk/lib/libosxsupport/si_data.c	                        (rev 0)
+++ trunk/lib/libosxsupport/si_data.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2008-2009 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 <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#ifdef __FreeBSD__
+#include "atomic_compat.h"
+#else
+#include <libkern/OSAtomic.h>
+#endif
+
+#include "si_data.h"
+#include "si_module.h"
+
+
+
+si_list_t *
+si_list_add(si_list_t *l, si_item_t *e)
+{
+	size_t size;
+
+	if (e == NULL) return l;
+
+	if (l == NULL)
+	{
+		l = (si_list_t *)calloc(1, sizeof(si_list_t));
+		l->refcount = 1;
+	}
+
+	if (l != NULL)
+	{
+		size = (l->count + 1) * sizeof(si_item_t *);
+
+		l->entry = (si_item_t **)reallocf(l->entry, size);
+		if (l->entry != NULL)
+		{
+			l->entry[l->count++] = si_item_retain(e);
+		}
+	}
+
+	if ((l == NULL) || (l->entry == NULL))
+	{
+		free(l);
+		l = NULL;
+		errno = ENOMEM;
+	}
+
+	return l;
+}
+
+si_list_t *
+si_list_concat(si_list_t *l, si_list_t *x)
+{
+	si_item_t *item;
+	uint32_t newcount;
+	size_t size;
+	uint32_t i;
+
+	if ((x == NULL) || (x->count == 0)) return l;
+
+	if (l == NULL)
+	{
+		l = (si_list_t *)calloc(1, sizeof(si_list_t));
+		l->refcount = 1;
+	}
+
+	if (l != NULL)
+	{
+		newcount = l->count + x->count;
+		size = newcount * sizeof(si_item_t *);
+
+		l->entry = (si_item_t **)reallocf(l->entry, size);
+		if (l->entry)
+		{
+			for (i = 0; i < x->count; ++i)
+			{
+				item = x->entry[i];
+				si_item_retain(item);
+				l->entry[l->count + i] = item;
+			}
+
+			l->count += x->count;
+		}
+		else
+		{
+			l->count = 0;
+			l = NULL;
+		}
+	}
+
+	if (l == NULL) errno = ENOMEM;
+
+	return l;
+}
+
+si_item_t *
+si_list_next(si_list_t *list)
+{
+	if (list == NULL) return NULL;
+	if (list->curr >= list->count) return NULL;
+
+	return list->entry[list->curr++];
+}
+
+void
+si_list_reset(si_list_t *list)
+{
+	if (list != NULL) list->curr = 0;
+}
+
+si_list_t *
+si_list_retain(si_list_t *list)
+{
+	int32_t rc;
+
+	if (list == NULL) return NULL;
+
+	rc = OSAtomicIncrement32Barrier(&list->refcount);
+	assert(rc >= 1);
+
+	return list;
+}
+
+void
+si_list_release(si_list_t *list)
+{
+	int32_t rc;
+	uint32_t i;
+
+	if (list == NULL) return;
+
+	rc = OSAtomicDecrement32Barrier(&list->refcount);
+	assert(rc >= 0);
+
+	if (rc == 0)
+	{
+		for (i = 0; i < list->count; i++)
+		{
+			si_item_release(list->entry[i]);
+		}
+
+		free(list->entry);
+		free(list);
+	}
+}
+
+si_item_t *
+si_item_retain(si_item_t *item)
+{
+	int32_t rc;
+
+	if (item == NULL) return NULL;
+
+	rc = OSAtomicIncrement32Barrier(&item->refcount);
+	assert(rc >= 1);
+
+	return item;
+}
+
+void
+si_item_release(si_item_t *item)
+{
+	int32_t rc;
+
+	if (item == NULL) return;
+
+	rc = OSAtomicDecrement32Barrier(&item->refcount);
+	assert(rc >= 0);
+
+	if (rc == 0) free(item);
+}


Property changes on: trunk/lib/libosxsupport/si_data.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/si_getaddrinfo.c
===================================================================
--- trunk/lib/libosxsupport/si_getaddrinfo.c	                        (rev 0)
+++ trunk/lib/libosxsupport/si_getaddrinfo.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,1664 @@
+/*
+ * Copyright (c) 2008-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 <netdb.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <network/sa_compare.h>
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <string.h>
+#include <sys/param.h>
+#include <notify.h>
+#include <notify_keys.h>
+#include <pthread.h>
+#include <TargetConditionals.h>
+#include "netdb_async.h"
+#include "si_module.h"
+
+#define SOCK_UNSPEC 0
+#define IPPROTO_UNSPEC 0
+
+#define IPV6_ADDR_LEN 16
+#define IPV4_ADDR_LEN 4
+
+#define WANT_NOTHING 0
+#define WANT_A4_ONLY 1
+#define WANT_A6_ONLY 2
+#define WANT_A6_PLUS_MAPPED_A4 3
+#define WANT_A6_OR_MAPPED_A4_IF_NO_A6 4
+
+#define V6TO4_PREFIX_16 0x2002
+
+static int net_config_token = -1;
+static uint32_t net_v4_count = 0;
+static uint32_t net_v6_count = 0;	// includes 6to4 addresses
+static pthread_mutex_t net_config_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+// Libc SPI
+int _inet_aton_check(const char *cp, struct in_addr *addr, int strict);
+
+typedef struct {
+	struct hostent host;
+	int alias_count;
+	int addr_count;
+	uint64_t ttl;
+} build_hostent_t;
+
+__private_extern__ int
+si_inet_config(uint32_t *inet4, uint32_t *inet6)
+{
+	int status, checkit;
+	struct ifaddrs *ifa, *ifap;
+
+	pthread_mutex_lock(&net_config_mutex);
+
+	checkit = 1;
+
+	if (net_config_token < 0)
+	{
+		status = notify_register_check(kNotifySCNetworkChange, &net_config_token);
+		if (status != 0) net_config_token = -1;
+	}
+
+	if (net_config_token >= 0)
+	{
+		status = notify_check(net_config_token, &checkit);
+		if (status != 0) checkit = 1;
+	}
+
+	status = 0;
+
+	if (checkit != 0)
+	{
+		if (getifaddrs(&ifa) < 0)
+		{
+			status = -1;
+		}
+		else
+		{
+			net_v4_count = 0;
+			net_v6_count = 0;
+
+			for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next)
+			{
+				if (ifap->ifa_addr == NULL) continue;
+				if ((ifap->ifa_flags & IFF_UP) == 0) continue;
+
+				if (ifap->ifa_addr->sa_family == AF_INET)
+				{
+					net_v4_count++;
+				}
+				else if (ifap->ifa_addr->sa_family == AF_INET6)
+				{
+					net_v6_count++;
+				}
+			}
+            freeifaddrs(ifa);
+		}
+
+	}
+
+	if (inet4 != NULL) *inet4 = net_v4_count;
+	if (inet6 != NULL) *inet6 = net_v6_count;
+
+	pthread_mutex_unlock(&net_config_mutex);
+
+	return status;
+}
+
+void
+freeaddrinfo(struct addrinfo *a)
+{
+	struct addrinfo *next;
+
+	while (a != NULL)
+	{
+		next = a->ai_next;
+		if (a->ai_addr != NULL) free(a->ai_addr);
+		if (a->ai_canonname != NULL) free(a->ai_canonname);
+		free(a);
+		a = next;
+	}
+}
+
+const char *
+gai_strerror(int32_t err)
+{
+	switch (err)
+	{
+		case EAI_ADDRFAMILY: return "Address family for nodename not supported";
+		case EAI_AGAIN: return "Temporary failure in name resolution";
+		case EAI_BADFLAGS:	return "Invalid value for ai_flags";
+		case EAI_FAIL: return "Non-recoverable failure in name resolution";
+		case EAI_FAMILY: return "ai_family not supported";
+		case EAI_MEMORY: return "Memory allocation failure";
+		case EAI_NODATA: return "No address associated with nodename";
+		case EAI_NONAME: return "nodename nor servname provided, or not known";
+		case EAI_SERVICE: return "servname not supported for ai_socktype";
+		case EAI_SOCKTYPE: return "ai_socktype not supported";
+		case EAI_SYSTEM: return "System error";
+		case EAI_BADHINTS: return "Bad hints";
+		case EAI_PROTOCOL: return "ai_protocol not supported";
+		case EAI_OVERFLOW: return "argument buffer overflow";
+	}
+
+	return "Unknown error";
+}
+
+/*
+ * getnameinfo
+ *
+ * We handle some "trival" cases locally.  If the caller passes
+ * NI_NUMERICHOST (only), then this call turns into a getservbyport
+ * to get the service name + inet_pton() to create a host string.
+ * If the caller passes NI_NUMERICSERV (only), then we zero out the port
+ * number, complete the getnameinfo, and use printf() to create a service
+ * string.  If the caller specifies both NI_NUMERICHOST and NI_NUMERICSERV,
+ * we inet_ntop() and printf() and return the results.
+ */
+si_item_t *
+si_nameinfo(si_mod_t *si, const struct sockaddr *sa, int flags, const char *interface, uint32_t *err)
+{
+	si_item_t *out = NULL;
+	const struct sockaddr *lookup_sa;
+	struct sockaddr_in s4;
+	struct in_addr a4;
+	struct in6_addr a6;
+	const uint64_t unused = 0;
+	void *addr = NULL;
+	char *host = NULL;
+	char *serv = NULL;
+	uint32_t ifnum = 0;
+	uint16_t port = 0;
+
+	int do_host_lookup = ((flags & NI_NUMERICHOST) == 0);
+	int do_serv_lookup = ((flags & NI_NUMERICSERV) == 0);
+
+	/* check input */
+	if ((si == NULL) || (sa == NULL))
+	{
+		if (err != NULL) *err = SI_STATUS_EAI_FAIL;
+		return NULL;
+	}
+
+	if (err != NULL) *err = SI_STATUS_NO_ERROR;
+
+	lookup_sa = sa;
+
+	if (sa->sa_family == AF_INET)
+	{
+		struct sockaddr_in *s4 = (struct sockaddr_in *)sa;
+		memcpy(&a4, &s4->sin_addr, sizeof(a4));
+		port = s4->sin_port;
+		addr = &a4;
+	}
+	else if (sa->sa_family == AF_INET6)
+	{
+		struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)sa;
+		memcpy(&a6, &s6->sin6_addr, sizeof(a6));
+		port = s6->sin6_port;
+
+		/* Look for scope id in IPv6 Link Local, Multicast Node Local, and Multicast Link Local */
+		if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr) || IN6_IS_ADDR_MC_NODELOCAL(&s6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&s6->sin6_addr))
+		{
+			ifnum = ntohs(a6.__u6_addr.__u6_addr16[1]);
+			if (ifnum == 0)
+			{
+				ifnum = s6->sin6_scope_id;
+				a6.__u6_addr.__u6_addr16[1] = htons(ifnum);
+			}
+
+			if ((ifnum != s6->sin6_scope_id) && (s6->sin6_scope_id != 0))
+			{
+				if (err != NULL) *err = SI_STATUS_EAI_FAIL;
+				return NULL;
+			}
+		}
+
+		/* v4 mapped and compat addresses are converted to plain v4 */
+		if (IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr) || IN6_IS_ADDR_V4COMPAT(&s6->sin6_addr))
+		{
+			memcpy(&a4, &s6->sin6_addr.s6_addr[12], sizeof(a4));
+			addr = &a4;
+			memset(&s4, 0, sizeof(s4));
+			s4.sin_len = sizeof(s4);
+			s4.sin_family = AF_INET;
+			s4.sin_port = port;
+			memcpy(&s4.sin_addr, &a4, sizeof(s4.sin_addr));
+			lookup_sa = (const struct sockaddr *)&s4;
+		}
+		else
+		{
+			addr = &a6;
+		}
+	}
+	else
+	{
+		if (err != NULL) *err = SI_STATUS_EAI_FAMILY;
+		return NULL;
+	}
+
+	if (do_host_lookup == 1)
+	{
+		si_item_t *item = si_host_byaddr(si, addr, lookup_sa->sa_family, interface, NULL);
+		if (item != NULL)
+		{
+			struct hostent *h;
+			h = (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
+			host = strdup(h->h_name);
+			si_item_release(item);
+			if (host == NULL)
+			{
+				if (err != NULL) *err = SI_STATUS_EAI_MEMORY;
+				return NULL;
+			}
+		}
+	}
+
+	if ((do_serv_lookup == 1) && (port != 0))
+	{
+		si_item_t *item = si_service_byport(si, port, NULL);
+		if (item != NULL)
+		{
+			struct servent *s;
+			s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
+			serv = strdup(s->s_name);
+			si_item_release(item);
+			if (serv == NULL)
+			{
+				free(host);
+				if (err != NULL) *err = SI_STATUS_EAI_MEMORY;
+				return NULL;
+			}
+		}
+	}
+
+	/*
+	 * Return numeric host name for NI_NUMERICHOST or if lookup failed, but not
+	 * if NI_NAMEREQD is specified (so that we later fail with EAI_NONAME).
+	 */
+	if ((host == NULL) && ((flags & NI_NAMEREQD) == 0))
+	{
+		char tmp[INET6_ADDRSTRLEN + 1 + IF_NAMESIZE + 1];
+		tmp[0] = '\0';
+		if (sa->sa_family == AF_INET)
+		{
+			char buf[INET_ADDRSTRLEN];
+			if (inet_ntop(AF_INET, &a4, buf, sizeof(buf)) != 0)
+			{
+				host = strdup(buf);
+			}
+		}
+		else if (sa->sa_family == AF_INET6)
+		{
+			char buf[INET6_ADDRSTRLEN];
+
+			/* zero the embedded scope ID */
+			if (ifnum != 0)
+			{
+				a6.__u6_addr.__u6_addr16[1] = 0;
+			}
+
+			if (inet_ntop(AF_INET6, &a6, buf, sizeof(buf)) != 0)
+			{
+				if (ifnum != 0)
+				{
+					char ifname[IF_NAMESIZE];
+					if (if_indextoname(ifnum, ifname) != NULL)
+					{
+						asprintf(&host, "%s%%%s", buf, ifname);
+					}
+					else
+					{
+						/* ENXIO */
+						if (err != NULL) *err = SI_STATUS_EAI_FAIL;
+						return NULL;
+					}
+				}
+				else
+				{
+					host = strdup(buf);
+				}
+			}
+		}
+	}
+
+	/* Return numeric service name for NI_NUMERICSERV or if lookup failed. */
+	if (serv == NULL)
+	{
+		asprintf(&serv, "%hu", ntohs(port));
+	}
+
+	if ((host == NULL) || (serv == NULL))
+	{
+		if (err != NULL)
+		{
+			if ((flags & NI_NAMEREQD) != 0)
+			{
+				*err = SI_STATUS_EAI_NONAME;
+			}
+			else
+			{
+				*err = SI_STATUS_EAI_MEMORY;
+			}
+		}
+	}
+	else
+	{
+		out = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_NAMEINFO, 1, unused, unused, host, serv);
+	}
+
+	free(host);
+	free(serv);
+	return out;
+}
+
+static int
+_gai_numericserv(const char *serv, uint16_t *port)
+{
+	int numeric;
+	char *endptr;
+	long num;
+
+	numeric = 0;
+
+	if (serv == NULL)
+	{
+		if (port) *port = 0;
+		numeric = 1;
+	}
+	else
+	{
+		num = strtol(serv, &endptr, 10);
+		if ((serv[0] != '\0') && (*endptr == '\0') && (num >= 0) && (num <= UINT16_MAX))
+		{
+			numeric = 1;
+			if (port != NULL) *port = (uint16_t)num;
+		}
+	}
+
+	return numeric;
+}
+
+int
+_gai_serv_to_port(const char *serv, uint32_t proto, uint16_t *port)
+{
+	si_item_t *item;
+	struct servent *s;
+	const char *protoname = NULL;
+
+	if (_gai_numericserv(serv, port)) return 0;
+
+	if (proto == IPPROTO_UDP) protoname = "udp";
+	if (proto == IPPROTO_TCP) protoname = "tcp";
+
+	item = si_service_byname(si_search(), serv, protoname);
+	if (item == NULL) return -1;
+
+	s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
+	if (port) *port = ntohs(s->s_port);
+	si_item_release(item);
+
+	return 0;
+}
+
+si_item_t *
+si_addrinfo_v4(si_mod_t *si, int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in_addr *addr, uint16_t iface, const char *cname)
+{
+	socket_data_t sockdata;
+	struct sockaddr_in *sa;
+	int32_t len, v32;
+	uint64_t unused;
+
+	unused = 0;
+	len = sizeof(struct sockaddr_in);
+	memset(&sockdata, 0, sizeof(socket_data_t));
+	sa = (struct sockaddr_in *)&sockdata;
+
+	sa->sin_len = len;
+	sa->sin_family = AF_INET;
+	sa->sin_port = htons(port);
+	memcpy(&sa->sin_addr, addr, sizeof(sa->sin_addr));
+
+	/* Kludge: Jam the interface number into sin_zero (4 bytes). */
+	v32 = iface;
+	memmove(sa->sin_zero, &v32, sizeof(uint32_t));
+
+	return (si_item_t *)LI_ils_create("L448844444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET, sock, proto, len, sockdata, cname);
+}
+
+si_item_t *
+si_addrinfo_v4_mapped(si_mod_t *si, int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in_addr *addr, uint16_t iface, const char *cname)
+{
+	socket_data_t sockdata;
+	struct sockaddr_in6 *sa;
+	int32_t len;
+	uint64_t unused;
+
+	unused = 0;
+	len = sizeof(struct sockaddr_in6);
+	memset(&sockdata, 0, sizeof(socket_data_t));
+	sa = (struct sockaddr_in6 *)&sockdata;
+
+	sa->sin6_len = len;
+	sa->sin6_family = AF_INET6;
+	sa->sin6_port = htons(port);
+	memset(&(sa->sin6_addr.__u6_addr.__u6_addr8[10]), 0xff, 2);
+	memcpy(&(sa->sin6_addr.__u6_addr.__u6_addr8[12]), addr, sizeof(struct in_addr));
+
+	/* sin6_scope_id is in host byte order */
+	sa->sin6_scope_id = iface;
+
+	return (si_item_t *)LI_ils_create("L448844444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET6, sock, proto, len, sockdata, cname);
+}
+
+
+si_item_t *
+si_addrinfo_v6(si_mod_t *si, int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in6_addr *addr, uint16_t iface, const char *cname)
+{
+	socket_data_t sockdata;
+	struct sockaddr_in6 *sa;
+	int32_t len;
+	uint64_t unused;
+
+	unused = 0;
+	len = sizeof(struct sockaddr_in6);
+	memset(&sockdata, 0, sizeof(socket_data_t));
+	sa = (struct sockaddr_in6 *)&sockdata;
+
+	sa->sin6_len = len;
+	sa->sin6_family = AF_INET6;
+	sa->sin6_port = htons(port);
+	memcpy(&sa->sin6_addr, addr, sizeof(sa->sin6_addr));
+
+	/* sin6_scope_id is in host byte order */
+	sa->sin6_scope_id = iface;
+
+	if (IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr))
+	{
+		/* check for embedded scopeid */
+		uint16_t esid = ntohs(sa->sin6_addr.__u6_addr.__u6_addr16[1]);
+		if (esid != 0)
+		{
+			sa->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
+			if (iface == 0) sa->sin6_scope_id = esid;
+		}
+	}
+
+	return (si_item_t *)LI_ils_create("L448844444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET6, sock, proto, len, sockdata, cname);
+}
+
+si_list_t *
+si_addrinfo_list(si_mod_t *si, uint32_t flags, int socktype, int proto, struct in_addr *a4, struct in6_addr *a6, int port, int scopeid, const char *cname4, const char *cname6)
+{
+	int do_map = 0;
+	si_item_t *item = NULL;
+	si_list_t *out4 = NULL, *out6 = NULL;
+
+	if ((flags & AI_V4MAPPED) && ((flags & AI_ALL) || (a6 == NULL))) do_map = 1;
+
+	if (a6 != NULL)
+	{
+		if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
+		{
+			item = si_addrinfo_v6(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a6, scopeid, cname6);
+			out6 = si_list_add(out6, item);
+			si_item_release(item);
+		}
+
+		if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
+		{
+			item = si_addrinfo_v6(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a6, scopeid, cname6);
+			out6 = si_list_add(out6, item);
+			si_item_release(item);
+		}
+
+		if (proto == IPPROTO_ICMPV6)
+		{
+			item = si_addrinfo_v6(si, 0, SOCK_RAW, IPPROTO_ICMPV6, port, a6, scopeid, cname6);
+			out6 = si_list_add(out6, item);
+			si_item_release(item);
+		}
+	}
+
+	if (a4 != NULL)
+	{
+		if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
+		{
+			if (do_map == 0)
+			{
+				item = si_addrinfo_v4(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, cname4);
+				out4 = si_list_add(out4, item);
+			}
+			else
+			{
+				item = si_addrinfo_v4_mapped(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, cname4);
+				out6 = si_list_add(out6, item);
+			}
+
+			si_item_release(item);
+		}
+
+		if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
+		{
+			if (do_map == 0)
+			{
+				item = si_addrinfo_v4(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, cname4);
+				out4 = si_list_add(out4, item);
+			}
+			else
+			{
+				item = si_addrinfo_v4_mapped(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, cname4);
+				out6 = si_list_add(out6, item);
+			}
+
+			si_item_release(item);
+		}
+
+		if (proto == IPPROTO_ICMP)
+		{
+			if (do_map == 0)
+			{
+				item = si_addrinfo_v4(si, 0, SOCK_RAW, IPPROTO_ICMP, port, a4, 0, cname4);
+				out4 = si_list_add(out4, item);
+			}
+			else
+			{
+				item = si_addrinfo_v4_mapped(si, 0, SOCK_RAW, IPPROTO_ICMP, port, a4, 0, cname4);
+				out6 = si_list_add(out6, item);
+			}
+
+			si_item_release(item);
+		}
+	}
+
+	out6 = si_list_concat(out6, out4);
+	si_list_release(out4);
+
+	return out6;
+}
+
+/*
+ * _gai_numerichost
+ * Determines whether the given host name is a numeric IPv4 or IPv6 address,
+ * based on the address family input value.  If the input addres family is
+ * unspecified, a more specific value will be provided on output if possible.
+ * Returns 1 if host name is numeric or 0 if not, or -1 on error.
+ */
+static int
+_gai_numerichost(const char* nodename, uint32_t *family, int flags, struct in_addr *a4, struct in6_addr *a6, int *scope)
+{
+	int numerichost, passive;
+
+	numerichost = 0;
+
+	if (nodename == NULL)
+	{
+		/* return loopback or passive addresses */
+		passive = (flags & AI_PASSIVE);
+
+		if (((*family == AF_UNSPEC) || (*family == AF_INET)) || ((*family == AF_INET6) && (flags & AI_V4MAPPED) && (flags & AI_ALL)))
+		{
+			if (passive) a4->s_addr = 0;
+			else a4->s_addr = htonl(INADDR_LOOPBACK);
+		}
+
+		if ((*family == AF_UNSPEC) || (*family == AF_INET6))
+		{
+			memset(a6, 0, sizeof(*a6));
+			if (!passive) a6->__u6_addr.__u6_addr32[3] = htonl(1);
+		}
+
+		numerichost = 1;
+	}
+	else
+	{
+		/*
+		 * numeric IPv4 host valid for AF_UNSPEC and AF_INET
+		 * also valid for AF_INET6 with AI_V4MAPPED
+		 */
+		numerichost = inet_pton(AF_INET, nodename, a4);
+		if (numerichost == 0)
+		{
+			/* inet_pton doesn't allow "a", "a.b", or "a.b.c" forms, so we re-check */
+			numerichost = _inet_aton_check(nodename, a4, 1);
+		}
+
+		if (numerichost == 1)
+		{
+			if (*family == AF_UNSPEC)
+			{
+				*family = AF_INET;
+			}
+			else if (*family == AF_INET6)
+			{
+				if (flags & AI_V4MAPPED)
+				{
+					memset(a6, 0, sizeof(struct in6_addr));
+					memset(&(a6->__u6_addr.__u6_addr8[10]), 0xff, 2);
+					memcpy(&(a6->__u6_addr.__u6_addr8[12]), a4, sizeof(struct in_addr));
+				}
+				else
+				{
+					numerichost = -1;
+				}
+			}
+
+			return numerichost;
+		}
+
+		/* numeric IPv6 host valid for AF_UNSPEC and AF_INET6 */
+		numerichost = inet_pton(AF_INET6, nodename, a6);
+		if (numerichost == 1)
+		{
+			/* check for scope/zone id */
+			char *p = strrchr(nodename, SCOPE_DELIMITER);
+			if (p != NULL)
+			{
+				int i, d;
+				char *x;
+				
+				p++;
+				d = 1;
+				for (x = p; (*x != '\0') && (d == 1); x++)
+				{
+					i = *x;
+					d = isdigit(i);
+				}
+				
+				if (d == 1) *scope = atoi(p);
+				else *scope = if_nametoindex(p);
+			}
+
+			if (*family == AF_UNSPEC) *family = AF_INET6;
+			else if (*family == AF_INET) numerichost = -1;
+
+			return numerichost;
+		}
+	}
+
+	return numerichost;
+}
+
+/* si_addrinfo_list_from_hostent
+ * Returns an addrinfo list from IPv4 and IPv6 hostent entries
+ */
+si_list_t *
+si_addrinfo_list_from_hostent(si_mod_t *si, uint32_t flags, uint32_t socktype, uint32_t proto, uint16_t port, uint16_t scope, const struct hostent *h4, const struct hostent *h6)
+{
+	int i;
+	si_list_t *out = NULL;
+	si_list_t *list;
+
+	if ((h6 != NULL) && (h6->h_addr_list != NULL))
+	{
+		for (i = 0; h6->h_addr_list[i] != NULL; i++)
+		{
+			struct in6_addr a6;
+			memcpy(&a6, h6->h_addr_list[i], h6->h_length);
+			list = si_addrinfo_list(si, flags, socktype, proto, NULL, &a6, port, scope, NULL, h6->h_name);
+			out = si_list_concat(out, list);
+			si_list_release(list);
+		}
+	}
+
+	if ((h4 != NULL) && (h4->h_addr_list != NULL))
+	{
+		for (i = 0; h4->h_addr_list[i] != NULL; i++)
+		{
+			struct in_addr a4;
+			memcpy(&a4, h4->h_addr_list[i], h4->h_length);
+			list = si_addrinfo_list(si, flags, socktype, proto, &a4, NULL, port, 0, h4->h_name, NULL);
+			out = si_list_concat(out, list);
+			si_list_release(list);
+		}
+	}
+
+	return out;
+}
+
+int
+_gai_addr_sort(const void *a, const void *b)
+{
+	si_item_t **item_a, **item_b;
+	si_addrinfo_t *p, *q;
+	struct sockaddr *sp, *sq;
+	
+	item_a = (si_item_t **)a;
+	item_b = (si_item_t **)b;
+
+	p = (si_addrinfo_t *)((uintptr_t)*item_a + sizeof(si_item_t));
+	q = (si_addrinfo_t *)((uintptr_t)*item_b + sizeof(si_item_t));
+
+	sp = (struct sockaddr *)p->ai_addr.x;
+	sq = (struct sockaddr *)q->ai_addr.x;
+
+	/*
+	 * sa_dst_compare(A,B) returns -1 if A is less desirable than B,
+	 * 0 if they are equally desirable, and 1 if A is more desirable.
+	 * qsort() expects the inverse, so we swap sp and sq.
+	 */
+	return sa_dst_compare(sq, sp, 0);
+}
+
+static si_list_t *
+_gai_sort_list(si_list_t *in, uint32_t flags)
+{
+	si_list_t *out;
+	int filter_mapped;
+	uint32_t i;
+	uint32_t v4mapped_count = 0;
+	uint32_t v6_count = 0;
+	si_addrinfo_t *a;
+
+	if (in == NULL) return NULL;
+
+	for (i = 0; i < in->count; i++)
+	{
+		a = (si_addrinfo_t *)((uintptr_t)in->entry[i] + sizeof(si_item_t));
+		if (a->ai_family == AF_INET6)
+		{
+			struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)a->ai_addr.x;
+			if (IN6_IS_ADDR_V4MAPPED(&(s6->sin6_addr))) v4mapped_count++;
+			else v6_count++;
+		}
+	}
+
+	filter_mapped = 1;
+	if ((flags & AI_V4MAPPED) && ((v6_count == 0) || (flags & AI_ALL))) filter_mapped = 0;
+
+	out = in;
+
+	if ((filter_mapped == 1) && (v4mapped_count > 0))
+	{
+		i = in->count - v4mapped_count;
+		if (i == 0) return NULL;
+
+		out = (si_list_t *)calloc(1, sizeof(si_list_t));
+		if (out == NULL) return in;
+
+		out->count = i;
+		out->refcount = in->refcount;
+
+		out->entry = (si_item_t **)calloc(out->count, sizeof(si_item_t *));
+		if (out->entry == NULL)
+		{
+			free(out);
+			return in;
+		}
+
+		out->curr = 0;
+
+		for (i = 0; i < in->count; i++)
+		{
+			a = (si_addrinfo_t *)((uintptr_t)in->entry[i] + sizeof(si_item_t));
+			if (a->ai_family == AF_INET6)
+			{
+				struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)a->ai_addr.x;
+				if (IN6_IS_ADDR_V4MAPPED(&(s6->sin6_addr)))
+				{
+					si_item_release(in->entry[i]);
+					continue;
+				}
+			}
+
+			out->entry[out->curr++] = in->entry[i];
+		}
+
+		out->curr = 0;
+
+		free(in->entry);
+		free(in);
+	}
+
+	qsort(&out->entry[0], out->count, sizeof(si_item_t *), _gai_addr_sort);
+	return out;
+}
+
+/* _gai_simple
+ * Simple lookup via gethostbyname2(3) mechanism.
+ */
+si_list_t *
+_gai_simple(si_mod_t *si, const void *nodeptr, const void *servptr, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err)
+{
+	si_item_t *h4_item = NULL, *h6_item = NULL;
+	struct hostent *h4 = NULL, *h6 = NULL;
+	si_list_t *out = NULL;
+	uint16_t port;
+
+	if ((flags & AI_NUMERICSERV) != 0)
+	{
+		port = *(uint16_t*)servptr;
+	}
+	else
+	{
+		if (_gai_serv_to_port(servptr, proto, &port) != 0)
+		{
+			if (err) *err = SI_STATUS_EAI_NONAME;
+			return NULL;
+		}
+	}
+
+	if ((flags & AI_NUMERICHOST) != 0)
+	{
+		if (family == AF_INET)
+		{
+			h4_item = si_host_byaddr(si, nodeptr, AF_INET, interface, NULL);
+		}
+		else if (family == AF_INET6)
+		{
+			h6_item = si_host_byaddr(si, nodeptr, AF_INET6, interface, NULL);
+		}
+	}
+	else
+	{
+		if ((family == AF_INET) || (family == AF_UNSPEC))
+		{
+			h4_item = si_host_byname(si, nodeptr, AF_INET, interface, NULL);
+		}
+
+		if ((family == AF_INET6) || (family == AF_UNSPEC))
+		{
+			h6_item = si_host_byname(si, nodeptr, AF_INET6, interface, NULL);
+		}
+	}
+
+	if (h4_item != NULL)
+	{
+		h4 = (struct hostent *)((uintptr_t)h4_item + sizeof(si_item_t));
+	}
+
+	if (h6_item != NULL)
+	{
+		h6 = (struct hostent *)((uintptr_t)h6_item + sizeof(si_item_t));
+	}
+
+	out = si_addrinfo_list_from_hostent(si, flags, socktype, proto, port, 0, h4, h6);
+	si_item_release(h4_item);
+	si_item_release(h6_item);
+
+	return _gai_sort_list(out, flags);
+}
+
+si_list_t *
+si_srv_byname(si_mod_t *si, const char *qname, const char *interface, uint32_t *err)
+{
+	if (si == NULL) return 0;
+	if (si->vtable->sim_srv_byname == NULL) return 0;
+
+	return si->vtable->sim_srv_byname(si, qname, interface, err);
+}
+
+int
+si_wants_addrinfo(si_mod_t *si)
+{
+	if (si == NULL) return 0;
+	if (si->vtable->sim_addrinfo == NULL) return 0;
+	if (si->vtable->sim_wants_addrinfo == NULL) return 0;
+
+	return si->vtable->sim_wants_addrinfo(si);
+}
+
+static si_list_t *
+_gai_srv(si_mod_t *si, const char *node, const char *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err)
+{
+	int i;
+	char *qname;
+	si_srv_t *srv;
+	si_item_t *item;
+
+	si_list_t *list = NULL;
+	si_list_t *result = NULL;
+
+	/* Minimum SRV priority is zero. Start below that. */
+	int lastprio = -1;
+	int currprio;
+
+	if (node == NULL || serv == NULL) return NULL;
+
+	asprintf(&qname, "%s.%s", serv, node);
+	list = si_srv_byname(si, qname, interface, err);
+	free(qname);
+
+	/* Iterate the SRV records starting at lowest priority and attempt to
+	 * lookup the target host name. Returns the first successful lookup.
+	 * It's an O(n^2) algorithm but data sets are small (less than 100) and
+	 * sorting overhead is dwarfed by network I/O for each element.
+	 */
+	while (list != NULL && result == NULL)
+	{
+		/* Find the next lowest priority level. */
+		/* Maximum SRV priority is UINT16_MAX. Start above that. */
+		currprio = INT_MAX;
+
+		for (i = 0; i < list->count; ++i)
+		{
+			item = list->entry[i];
+			srv = (si_srv_t *)((uintptr_t)item + sizeof(si_item_t));
+
+			if (srv->priority > lastprio && srv->priority < currprio)
+			{
+				currprio = srv->priority;
+			}
+		}
+
+		if (currprio == INT_MAX)
+		{
+			/* All priorities have been evaluated. Done. */
+			break;
+		}
+		else
+		{
+			lastprio = currprio;
+		}
+
+		/* Lookup hosts at the current priority level. Return first match. */
+		for (i = 0; i < list->count; ++i)
+		{
+			item = list->entry[i];
+			srv = (si_srv_t *)((uintptr_t)item + sizeof(si_item_t));
+
+			if (srv->priority == currprio)
+			{
+				/* So that _gai_simple expects an integer service. */
+				flags |= AI_NUMERICSERV;
+
+				result = _gai_simple(si, srv->target, &srv->port, family, socktype, proto, flags, interface, err);
+				if (result)
+				{
+					break;
+				}
+			}
+		}
+	}
+
+	if (list != NULL)
+	{
+		si_list_release(list);
+	}
+
+	return result;
+}
+
+si_list_t *
+si_addrinfo(si_mod_t *si, const char *node, const char *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err)
+{
+	int numerichost, numericserv = 0;
+	int scope = 0;
+	const void *nodeptr = NULL, *servptr = NULL;
+	uint16_t port;
+	struct in_addr a4, *p4;
+	struct in6_addr a6, *p6;
+	const char *cname;
+	si_list_t *out;
+
+	if (err != NULL) *err = SI_STATUS_NO_ERROR;
+
+	if (si == NULL)
+	{
+		if (err != NULL) *err = SI_STATUS_EAI_FAIL;
+		return NULL;
+	}
+
+	/* treat empty strings as NULL */
+	if ((node != NULL) && (node[0] == '\0')) node = NULL;
+	if ((serv != NULL) && (serv[0] == '\0')) serv = NULL;
+
+	/* make sure we have a query */
+	if ((node == NULL) && (serv == NULL))
+	{
+		if (err != NULL) *err = SI_STATUS_EAI_NONAME;
+		return NULL;
+	}
+
+	/* verify family is supported */
+	switch (family)
+	{
+		case AF_UNSPEC:
+		case AF_INET:
+		case AF_INET6:
+			break;
+		default:
+			if (err != NULL) *err = SI_STATUS_EAI_FAMILY;
+			return NULL;
+	}
+
+	/* verify socket type is supported */
+	switch (socktype)
+	{
+		case SOCK_UNSPEC:
+		case SOCK_RAW:
+		case SOCK_DGRAM:
+		case SOCK_STREAM:
+			break;
+		default:
+			if (err != NULL) *err = SI_STATUS_EAI_BADHINTS;
+			return NULL;
+	}
+
+	/* verify protocol is supported */
+	switch (proto)
+	{
+		case IPPROTO_UNSPEC:
+		case IPPROTO_UDP:
+		case IPPROTO_TCP:
+		case IPPROTO_ICMP:
+		case IPPROTO_ICMPV6:
+			break;
+		default:
+			if (err != NULL) *err = SI_STATUS_EAI_BADHINTS;
+			return NULL;
+	}
+
+	/* verify socket type compatible with protocol */
+	if (((socktype == SOCK_DGRAM) && (proto != IPPROTO_UNSPEC) && (proto != IPPROTO_UDP)) || ((socktype == SOCK_STREAM) && (proto != IPPROTO_UNSPEC) && (proto != IPPROTO_TCP)))
+	{
+		if (err != NULL) *err = SI_STATUS_EAI_BADHINTS;
+		return NULL;
+	}
+
+	/* check AI_V4MAPPED and AI_ALL */
+	if (family != AF_INET6)
+	{
+		/* unset AI_V4MAPPED and AI_ALL unless family is AF_INET6 */
+		flags &= ~(AI_V4MAPPED | AI_ALL);
+	}
+	else if ((flags & AI_V4MAPPED) == 0)
+	{
+		/* unset AI_ALL unless family is AF_INET6 and AI_V4MAPPED is set */
+		flags &= ~AI_ALL;
+	}
+
+	memset(&a4, 0, sizeof(struct in_addr));
+	memset(&a6, 0, sizeof(struct in6_addr));
+
+	/* determine the protocol if possible */
+	if ((proto == IPPROTO_UNSPEC) && (socktype == SOCK_DGRAM)) proto = IPPROTO_UDP;
+	if ((proto == IPPROTO_UNSPEC) && (socktype == SOCK_STREAM)) proto = IPPROTO_TCP;
+
+	port = 0;
+
+	if ((flags & AI_SRV) != 0)
+	{
+		/* AI_SRV SPI */
+		out = _gai_srv(si, node, serv, family, socktype, proto, flags, interface, err);
+		return _gai_sort_list(out, flags);
+	}
+	else
+	{
+		/* Usual service lookup */
+		numericserv = _gai_numericserv(serv, &port);
+	}
+
+	if ((flags & AI_NUMERICSERV) && (numericserv == 0))
+	{
+		/* FreeBSD returns SI_STATUS_EAI_SERVICE */
+		if (err != NULL) *err = SI_STATUS_EAI_NONAME;
+		return NULL;
+	}
+
+	if ((serv != NULL) && (strcmp(serv, "0") != 0))
+	{
+		if (numericserv == 1)
+		{
+			flags |= AI_NUMERICSERV;
+			servptr = &port;
+		}
+		else
+		{
+			servptr = serv;
+		}
+	}
+
+	numerichost = _gai_numerichost(node, &family, flags, &a4, &a6, &scope);
+	if ((numerichost == -1) || ((flags & AI_NUMERICHOST) && (numerichost == 0)))
+	{
+		if (err != NULL) *err = SI_STATUS_EAI_NONAME;
+		return NULL;
+	}
+
+	if (numerichost == 1)
+	{
+		flags |= AI_NUMERICHOST;
+		if (family == AF_INET)
+		{
+			nodeptr = &a4;
+		}
+		else if (family == AF_INET6)
+		{
+			nodeptr = &a6;
+		}
+	}
+	else
+	{
+		nodeptr = node;
+	}
+
+	if ((numerichost == 1) && (numericserv == 0))
+	{
+		/* only service lookup needed.  convert to port and perform a trivial getaddrinfo */
+		if (_gai_serv_to_port(serv, proto, &port) != 0)
+		{
+			if (err != NULL) *err = SI_STATUS_EAI_NONAME;
+			return NULL;
+		}
+		else
+		{
+			flags |= AI_NUMERICSERV;
+			servptr = &port;
+			numericserv = 1;
+		}
+	}
+
+	if ((numerichost == 1) && (numericserv == 1))
+	{
+		p4 = &a4;
+		p6 = &a6;
+		cname = NULL;
+
+		if (family == AF_INET) p6 = NULL;
+		if (family == AF_INET6) p4 = NULL;
+		if (node == NULL) cname = "localhost";
+
+		/* allow nodename to be a mapped IPv4 address, e.g. "::ffff:10.0.0.1" */
+		if (p6 != NULL) flags |= AI_V4MAPPED;
+
+		/* handle trivial questions */
+		out = si_addrinfo_list(si, flags, socktype, proto, p4, p6, port, scope, cname, cname);
+		return _gai_sort_list(out, flags);
+	}
+	else if (si_wants_addrinfo(si))
+	{
+		/* or let the current module handle the host lookups intelligently */
+		out = si->vtable->sim_addrinfo(si, nodeptr, servptr, family, socktype, proto, flags, interface, err);
+		return _gai_sort_list(out, flags);
+	}
+
+	/* fall back to a default path */
+	out = _gai_simple(si, nodeptr, servptr, family, socktype, proto, flags, interface, err);
+	return _gai_sort_list(out, flags);
+}
+
+static struct addrinfo *
+si_item_to_addrinfo(si_item_t *item)
+{
+	si_addrinfo_t *a;
+	struct addrinfo *out;
+
+	if (item == NULL) return NULL;
+
+	a = (si_addrinfo_t *)((uintptr_t)item + sizeof(si_item_t));
+
+	out = (struct addrinfo *)calloc(1, sizeof(struct addrinfo));
+	if (out == NULL) return NULL;
+
+	out->ai_flags = a->ai_flags;
+	out->ai_family = a->ai_family;
+	out->ai_socktype = a->ai_socktype;
+	out->ai_protocol = a->ai_protocol;
+	out->ai_addrlen = a->ai_addrlen;
+
+	out->ai_addr = (struct sockaddr *)calloc(1, out->ai_addrlen);
+	if (out->ai_addr == NULL)
+	{
+		free(out);
+		return NULL;
+	}
+
+	memcpy(out->ai_addr, a->ai_addr.x, out->ai_addrlen);
+
+	if (a->ai_canonname != NULL)
+	{
+		out->ai_canonname = strdup(a->ai_canonname);
+		if (out->ai_canonname == NULL)
+		{
+			free(out);
+			return NULL;
+		}
+	}
+
+	return out;
+}
+
+struct addrinfo *
+si_list_to_addrinfo(si_list_t *list)
+{
+	struct addrinfo *tail, *out;
+	int i;
+
+	if (list == NULL) return NULL;
+	if (list->count == 0) return NULL;
+
+	i = list->count - 1;
+
+	out = si_item_to_addrinfo(list->entry[i]);
+	tail = out;
+
+	for (i--; i >= 0; i--)
+	{
+		out = si_item_to_addrinfo(list->entry[i]);
+		if (out == NULL)
+		{
+			freeaddrinfo(tail);
+			return NULL;
+		}
+
+		out->ai_next = tail;
+		tail = out;
+	}
+
+	return out;
+}
+
+/* getipnodebyname */
+
+static si_item_t *
+make_hostent(si_mod_t *si, const char *name, struct in_addr addr)
+{
+	char *addrs[2];
+	char *aliases[1];
+	uint64_t unused;
+
+	if (name == NULL) return NULL;
+
+	unused = 0;
+
+	addrs[0] = (char *)&(addr.s_addr);
+	addrs[1] = NULL;
+	aliases[0] = NULL;
+
+	return (si_item_t *)LI_ils_create("L4488s*44a", (unsigned long)si, CATEGORY_HOST_IPV4, 1, unused, unused, name, aliases, AF_INET, IPV4_ADDR_LEN, addrs);
+}
+
+static si_item_t *
+make_hostent6(si_mod_t *si, const char *name, struct in6_addr addr)
+{
+	char *addrs[2];
+	char *aliases[1];
+	uint64_t unused;
+
+	if (name == NULL) return NULL;
+
+	unused = 0;
+
+	addrs[0] = (char *)&(addr.__u6_addr.__u6_addr32[0]);
+	addrs[1] = NULL;
+	aliases[0] = NULL;
+
+	return (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, unused, unused, name, aliases, AF_INET6, IPV6_ADDR_LEN, addrs);
+}
+
+static char *
+lower_case(const 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;
+}
+
+static int
+merge_alias(const char *name, build_hostent_t *h)
+{
+	int i;
+
+	if (name == NULL) return 0;
+	if (h == NULL) return 0;
+
+	if ((h->host.h_name != NULL) && (string_equal(name, h->host.h_name))) return 0;
+
+	for (i = 0; i < h->alias_count; i++)
+	{
+		if (string_equal(name, h->host.h_aliases[i])) return 0;
+	}
+
+	if (h->alias_count == 0) h->host.h_aliases = (char **)calloc(2, sizeof(char *));
+	else h->host.h_aliases = (char **)reallocf(h->host.h_aliases, (h->alias_count + 2) * sizeof(char *));
+
+	if (h->host.h_aliases == NULL)
+	{
+		h->alias_count = 0;
+		return -1;
+	}
+
+	h->host.h_aliases[h->alias_count] = lower_case(name);
+	h->alias_count++;
+	h->host.h_aliases[h->alias_count] = NULL;
+
+	return 0;
+}
+
+static int
+append_addr(const char *addr, uint32_t len, build_hostent_t *h)
+{
+	if (addr == NULL) return 0;
+	if (h == NULL) return 0;
+
+	if (h->addr_count == 0) h->host.h_addr_list = (char **)calloc(2, sizeof(char *));
+	else h->host.h_addr_list = (char **)reallocf(h->host.h_addr_list, (h->addr_count + 2) * sizeof(char *));
+
+	if (h->host.h_addr_list == NULL)
+	{
+		h->addr_count = 0;
+		return -1;
+	}
+
+	h->host.h_addr_list[h->addr_count] = malloc(len);
+	if (h->host.h_addr_list[h->addr_count] == NULL) return -1;
+
+	memcpy(h->host.h_addr_list[h->addr_count], addr, len);
+	h->addr_count++;
+	h->host.h_addr_list[h->addr_count] = NULL;
+
+	return 0;
+}
+
+static void
+free_build_hostent(build_hostent_t *h)
+{
+	uint32_t i;
+	char **aliases;
+
+	if (h == NULL) return;
+
+	if (h->host.h_name != NULL) free(h->host.h_name);
+	h->host.h_name = NULL;
+
+	aliases = h->host.h_aliases;
+	if (aliases != NULL)
+	{
+		while (*aliases != NULL) free(*aliases++);
+		free(h->host.h_aliases);
+	}
+
+	h->host.h_aliases = NULL;
+
+	if (h->host.h_addr_list != NULL)
+	{
+		for (i = 0; h->host.h_addr_list[i] != NULL; i++) free(h->host.h_addr_list[i]);
+		free(h->host.h_addr_list);
+	}
+
+	h->host.h_addr_list = NULL;
+	free(h);
+}
+
+si_item_t *
+si_ipnode_byname(si_mod_t *si, const char *name, int family, int flags, const char *interface, uint32_t *err)
+{
+	int i, status, want;
+	uint32_t if4, if6;
+	struct in_addr addr4;
+	struct in6_addr addr6;
+	si_item_t *item4, *item6;
+	build_hostent_t *out;
+	struct hostent *h;
+	uint64_t unused;
+
+	memset(&addr4, 0, sizeof(struct in_addr));
+	memset(&addr6, 0, sizeof(struct in6_addr));
+
+	if (err != NULL) *err = 0;
+
+	if (family == AF_INET)
+	{
+		status = inet_aton(name, &addr4);
+		if (status == 1)
+		{
+			/* create a host entry */
+			item4 = make_hostent(si, name, addr4);
+			if (item4 == NULL)
+			{
+				if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+				return NULL;
+			}
+
+			return item4;
+		}
+	}
+	else if (family == AF_INET6)
+	{
+		status = inet_pton(family, name, &addr6);
+		if (status == 1)
+		{
+			/* create a host entry */
+			item6 = make_hostent6(si, name, addr6);
+			if (item6 == NULL)
+			{
+				if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+				return NULL;
+			}
+
+			return item6;
+		}
+
+		status = inet_aton(name, &addr4);
+		if (status == 1)
+		{
+			if (!(flags & (AI_V4MAPPED | AI_V4MAPPED_CFG)))
+			{
+				if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
+				return NULL;
+			}
+
+			addr6.__u6_addr.__u6_addr32[0] = 0x00000000;
+			addr6.__u6_addr.__u6_addr32[1] = 0x00000000;
+			addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
+			memmove(&(addr6.__u6_addr.__u6_addr32[3]), &(addr4.s_addr), IPV4_ADDR_LEN);
+
+			/* create a host entry */
+			item6 = make_hostent6(si, name, addr6);
+			if (item6 == NULL)
+			{
+				if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+				return NULL;
+			}
+
+			return item6;
+		}
+	}
+	else
+	{
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+		return NULL;
+	}
+
+	/*
+	 * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
+	 */
+
+	if4 = 0;
+	if6 = 0;
+
+	if (flags & AI_ADDRCONFIG)
+	{
+		if (si_inet_config(&if4, &if6) < 0)
+		{
+			if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+			return NULL;
+		}
+
+		/* Bail out if there are no interfaces */
+		if ((if4 == 0) && (if6 == 0))
+		{
+			if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+			return NULL;
+		}
+	}
+
+	/*
+	 * Figure out what we want.
+	 * If user asked for AF_INET, we only want V4 addresses.
+	 */
+	want = WANT_A4_ONLY;
+
+	if (family == AF_INET)
+	{
+		if ((flags & AI_ADDRCONFIG) && (if4 == 0))
+		{
+			if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+			return NULL;
+		}
+	}
+	else if (family == AF_INET6)
+	{
+		/* family == AF_INET6 */
+		want = WANT_A6_ONLY;
+
+		if (flags & (AI_V4MAPPED | AI_V4MAPPED_CFG))
+		{
+			if (flags & AI_ALL)
+			{
+				want = WANT_A6_PLUS_MAPPED_A4;
+			}
+			else
+			{
+				want = WANT_A6_OR_MAPPED_A4_IF_NO_A6;
+			}
+		}
+		else
+		{
+			if ((flags & AI_ADDRCONFIG) && (if6 == 0)) 
+			{
+				if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+				return NULL;
+			}
+		}
+	}
+	else
+	{
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+		return NULL;
+	}
+
+	item6 = NULL;
+	item4 = NULL;
+
+	/* fetch IPv6 data if required */
+	if ((want == WANT_A6_ONLY) || (want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) || (want == WANT_A6_PLUS_MAPPED_A4))
+	{
+		item6 = si_host_byname(si, name, AF_INET6, interface, (uint32_t *)err);
+	}
+
+	/* fetch IPv4 data if required */
+	if ((want == WANT_A4_ONLY) || (want == WANT_A6_PLUS_MAPPED_A4) || ((want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) && (item6 == NULL)))
+	{
+		item4 = si_host_byname(si, name, AF_INET, interface, (uint32_t *)err);
+	}
+
+	if (want == WANT_A4_ONLY)
+	{
+		si_item_release(item6);
+		if ((item4 == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
+		return item4;
+	}
+
+	if (want == WANT_A6_ONLY)
+	{
+		si_item_release(item4);
+		if ((item6 == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
+		return item6;
+	}
+
+	if ((item6 == NULL) && (item4 == NULL))
+	{
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
+		return NULL;
+	}
+
+	/* output item will have IPv6 + mapped IPv4 addresses */
+
+	out = (build_hostent_t *)calloc(1, sizeof(build_hostent_t));
+	if (out == NULL)
+	{
+		si_item_release(item4);
+		si_item_release(item6);
+		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
+		return NULL;
+	}
+
+	if (item4 != NULL)
+	{
+		h = (struct hostent *)((uintptr_t)item4 + sizeof(si_item_t));
+
+		out->host.h_name = lower_case(h->h_name);
+
+		if (h->h_aliases != NULL)
+		{
+			for (i = 0; h->h_aliases[i] != NULL; i++) merge_alias(h->h_aliases[i], out);
+		}
+
+		for (i = 0; h->h_addr_list[i] != 0; i++)
+		{
+			addr6.__u6_addr.__u6_addr32[0] = 0x00000000;
+			addr6.__u6_addr.__u6_addr32[1] = 0x00000000;
+			addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
+			memmove(&(addr6.__u6_addr.__u6_addr32[3]), h->h_addr_list[i], IPV4_ADDR_LEN);
+			append_addr((const char *)&addr6, IPV6_ADDR_LEN, out);
+		}
+	}
+
+	if (item6 != NULL)
+	{
+		h = (struct hostent *)((uintptr_t)item6 + sizeof(si_item_t));
+
+		if (out->host.h_name == NULL) out->host.h_name = lower_case(h->h_name);
+
+		if (h->h_aliases != NULL)
+		{
+			for (i = 0; h->h_aliases[i] != NULL; i++) merge_alias(h->h_aliases[i], out);
+		}
+
+		for (i = 0; h->h_addr_list[i] != 0; i++) append_addr(h->h_addr_list[i], IPV6_ADDR_LEN, out);
+	}
+
+	si_item_release(item4);
+	si_item_release(item6);
+
+	unused = 0;
+
+	item6 = (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, unused, unused, out->host.h_name, out->host.h_aliases, AF_INET6, IPV6_ADDR_LEN, out->host.h_addr_list);
+
+	free_build_hostent(out);
+
+	return item6;
+}


Property changes on: trunk/lib/libosxsupport/si_getaddrinfo.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/si_module.c
===================================================================
--- trunk/lib/libosxsupport/si_module.c	                        (rev 0)
+++ trunk/lib/libosxsupport/si_module.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,1252 @@
+/*
+ * Copyright (c) 2008-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/types.h>
+#include <sys/socket.h>
+#include <net/ethernet.h>
+#ifdef __FreeBSD__
+#include "atomic_compat.h"
+#else
+#include <libkern/OSAtomic.h>
+#endif
+#include <dlfcn.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <pthread.h>
+#include <mach/mach.h>
+#include <dispatch/dispatch.h>
+#include <dispatch/private.h>
+#include <rpc/rpcent.h>
+#include "si_module.h"
+
+
+
+
+
+si_mod_t * si_module_with_path(const char *path, const char *name);
+
+#define PLUGIN_DIR_PATH "/usr/lib/info"
+#define PLUGIN_BUNDLE_SUFFIX "so"
+
+#define WORKUNIT_CANCELLED     0x00000001
+#define WORKUNIT_RETURNS_LIST  0x00000002
+
+#ifdef __BIG_ENDIAN__
+#define WORKUNIT_CANCELLED_BIT_ADDRESS 31
+#else
+#define WORKUNIT_CANCELLED_BIT_ADDRESS 7
+#endif
+
+#define ether_addr_octet octet
+
+typedef struct si_async_workunit_s
+{
+	si_mod_t *si;
+	uint32_t call;
+	char *str1;
+	char *str2;
+	char *str3;
+	uint32_t num1;
+	uint32_t num2;
+	uint32_t num3;
+	uint32_t num4;
+	uint32_t err;
+	/* async support below */
+	uint32_t flags;
+	int32_t refcount;
+	void *callback;
+	void *context;
+	mach_port_t port;
+	mach_port_t send;
+	si_item_t *resitem;
+	si_list_t *reslist;
+	struct si_async_workunit_s *next;
+} si_async_workunit_t;
+
+static si_mod_t **module_list = NULL;
+static uint32_t module_count = 0;
+static pthread_mutex_t module_mutex = PTHREAD_MUTEX_INITIALIZER;
+static si_async_workunit_t *si_async_worklist = NULL;
+
+si_mod_t *si_module_static_search(void);
+si_mod_t *si_module_static_cache(void);
+#ifndef __FreeBSD__
+si_mod_t *si_module_static_file(void);
+#ifdef DS_AVAILABLE
+si_mod_t *si_module_static_ds(void);
+#endif
+si_mod_t *si_module_static_mdns(void);
+#endif
+
+static void *
+si_mod_dlsym(void *so, const char *name, const char *sym)
+{
+	char *str;
+	void *out;
+
+	if ((so == NULL) || (name == NULL) || (sym == NULL)) return NULL;
+
+	str = NULL;
+	asprintf(&str, "%s_%s", name, sym);
+	if (str == NULL) return NULL;
+
+	out = dlsym(so, str);
+	free(str);
+	return out;
+}
+
+si_mod_t *
+si_module_with_path(const char *path, const char *name)
+{
+	void *so;
+	int (*si_sym_init)(si_mod_t *);
+	void (*si_sym_close)(si_mod_t *);
+	int status;
+	si_mod_t *out;
+	char *outname;
+
+	if ((path == NULL) || (name == NULL))
+	{
+		errno = EINVAL;
+		return NULL;
+	}
+
+	so = dlopen(path, RTLD_LOCAL);
+	if (so == NULL) return NULL;
+
+	si_sym_init = si_mod_dlsym(so, name, "init");
+	if (si_sym_init == NULL)
+	{
+		dlclose(so);
+		errno = ECONNREFUSED;
+		return NULL;
+	}
+
+	si_sym_close = si_mod_dlsym(so, name, "close");
+	if (si_sym_close == NULL)
+	{
+		dlclose(so);
+		errno = ECONNREFUSED;
+		return NULL;
+	}
+
+	out = (si_mod_t *)calloc(1, sizeof(si_mod_t));
+	outname = strdup(name);
+
+	if ((out == NULL) || (outname == NULL))
+	{
+		free(out);
+		free(outname);
+		dlclose(so);
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	out->name = outname;
+	out->refcount = 1;
+	out->flags = 0;
+	out->bundle = so;
+
+	status = si_sym_init(out);
+	if (status != 0)
+	{
+		dlclose(so);
+		free(out);
+		free(outname);
+		errno = ECONNREFUSED;
+		return NULL;
+	}
+
+	return out;
+}
+
+si_mod_t *
+si_module_with_name(const char *name)
+{
+	static struct
+	{
+		const char *name;
+		si_mod_t *(*init)(void);
+		si_mod_t *module;
+	} modules[] =
+	{
+		{ "search", si_module_static_search, NULL },
+		{ "cache", si_module_static_cache, NULL },
+#ifndef __FreeBSD__		
+		{ "file", si_module_static_file, NULL },
+#ifdef DS_AVAILABLE
+		{ "ds", si_module_static_ds, NULL },
+#endif
+		{ "mdns", si_module_static_mdns, NULL },
+#endif		
+		{ NULL, NULL , NULL },
+	};
+
+	si_mod_t *si = NULL;
+	int i;
+
+	/*
+	 * We don't need to worry about locking during initialization
+	 * because all modules init routine returns static storage.
+	 */
+
+	/* Find the module by name */
+	for (i = 0; modules[i].name != NULL; ++i)
+	{
+		if (string_equal(name, modules[i].name))
+		{
+			si = modules[i].module;
+			if (si == NULL)
+			{
+				si = modules[i].init();
+				modules[i].module = si;
+			}
+
+			break;
+		}
+	}
+
+	if (si != NULL) return si;
+
+	pthread_mutex_lock(&module_mutex);
+	char *path = NULL;
+
+	asprintf(&path, "%s/%s.%s", PLUGIN_DIR_PATH, name, PLUGIN_BUNDLE_SUFFIX);
+
+	if (path == NULL)
+	{
+		errno = ENOMEM;
+		pthread_mutex_unlock(&module_mutex);
+		return NULL;
+	}
+
+	si = si_module_with_path(path, name);
+	free(path);
+
+	if (si == NULL)
+	{
+		pthread_mutex_unlock(&module_mutex);
+		return NULL;
+	}
+
+	/* add out to module_list */
+	module_list = (si_mod_t **)reallocf(module_list, (module_count + 1) * sizeof(si_mod_t *));
+	if (module_list == NULL)
+	{
+		pthread_mutex_unlock(&module_mutex);
+		return si;
+	}
+
+	module_list[module_count] = si;
+	module_count++;
+
+	pthread_mutex_unlock(&module_mutex);
+
+	return si;
+}
+
+si_mod_t *
+si_module_retain(si_mod_t *si)
+{
+	if (si == NULL) return NULL;
+	if (si->flags & SI_MOD_FLAG_STATIC) return si;
+
+	OSAtomicIncrement32Barrier(&si->refcount);
+
+	return si;
+}
+
+void
+si_module_release(si_mod_t *si)
+{
+	uint32_t i;
+
+	if (si == NULL) return;
+	if (si->flags & SI_MOD_FLAG_STATIC) return;
+
+	i = OSAtomicDecrement32Barrier(&si->refcount);
+	if (i > 0) return;
+
+	pthread_mutex_lock(&module_mutex);
+
+	for (i = 0; (i < module_count) && (module_list[i] != si); i++);
+	if (i >= module_count)
+	{
+		pthread_mutex_unlock(&module_mutex);
+		return;
+	}
+
+	if (module_count == 1)
+	{
+		free(module_list);
+		module_list = NULL;
+		module_count = 0;
+		pthread_mutex_unlock(&module_mutex);
+		return;
+	}
+
+	for (i++; i < module_count; i++) module_list[i - 1] = module_list[i];
+	module_count--;
+	module_list = (si_mod_t **)reallocf(module_list, module_count * sizeof(si_mod_t *));
+	if (module_list == NULL) module_count = 0;
+
+	pthread_mutex_unlock(&module_mutex);
+
+	if (si->vtable->sim_close != NULL) si->vtable->sim_close(si);
+	if (si->bundle != NULL) dlclose(si->bundle);
+	free(si->name);
+	free(si);
+}
+
+const char *
+si_module_name(si_mod_t *si)
+{
+	if (si == NULL) return NULL;
+
+	return (const char *)si->name;
+}
+
+int
+si_module_vers(si_mod_t *si)
+{
+	if (si == NULL) return 0;
+
+	return si->vers;
+}
+
+int
+si_item_match(si_item_t *item, int cat, const void *name, uint32_t num, int which)
+{
+	int i;
+	union
+	{
+		char *x;
+		struct passwd *u;
+		struct group *g;
+		struct grouplist_s *l;
+		struct aliasent *a;
+		struct hostent *h;
+		struct netent *n;
+		struct servent *s;
+		struct protoent *p;
+		struct rpcent *r;
+		struct fstab *f;
+		struct mac_s *m;
+	} ent;
+
+	if (item == NULL) return 0;
+	if (which == SEL_ALL) return 1;
+	if ((which == SEL_NAME) && (name == NULL)) return 0;
+
+	ent.x = (char *)((uintptr_t)item + sizeof(si_item_t));
+
+	switch (cat)
+	{
+		case CATEGORY_USER:
+		{
+			if ((which == SEL_NAME) && (string_equal(name, ent.u->pw_name))) return 1;
+			else if ((which == SEL_NUMBER) && (num == (uint32_t)ent.u->pw_uid)) return 1;
+			return 0;
+		}
+		case CATEGORY_GROUP:
+		{
+			if ((which == SEL_NAME) && (string_equal(name, ent.g->gr_name))) return 1;
+			else if ((which == SEL_NUMBER) && (num == (uint32_t)ent.g->gr_gid)) return 1;
+			return 0;
+		}
+		case CATEGORY_GROUPLIST:
+		{
+			if ((which == SEL_NAME) && (string_equal(name, ent.l->gl_user))) return 1;
+			return 0;
+		}
+		case CATEGORY_ALIAS:
+		{
+			if ((which == SEL_NAME) && (string_equal(name, ent.a->alias_name))) return 1;
+			return 0;
+		}
+		case CATEGORY_HOST_IPV4:
+		case CATEGORY_HOST_IPV6:
+		{
+			/* N.B. address family is passed in num variable */
+			if (ent.h->h_addrtype != (int32_t)num) return 0;
+			if (which == SEL_NAME)
+			{
+				if (string_equal(name, ent.h->h_name)) return 1;
+				if (ent.h->h_aliases != NULL)
+				{
+					for (i = 0; ent.h->h_aliases[i] != NULL; i++)
+					{
+						if (string_equal(name, ent.h->h_aliases[i])) return 1;
+					}
+				}
+			}
+			else if (which == SEL_NUMBER)
+			{
+				if (memcmp(name, ent.h->h_addr_list[0], ent.h->h_length) == 0) return 1;
+			}
+			return 0;
+		}
+		case CATEGORY_NETWORK:
+		{
+			if (which == SEL_NAME)
+			{
+				if (string_equal(name, ent.n->n_name)) return 1;
+				if (ent.n->n_aliases != NULL)
+				{
+					for (i = 0; ent.n->n_aliases[i] != NULL; i++)
+					{
+						if (string_equal(name, ent.n->n_aliases[i])) return 1;
+					}
+				}
+			}
+			else if (which == SEL_NUMBER)
+			{
+				if (num == ent.n->n_net) return 1;
+			}
+			return 0;
+		}
+		case CATEGORY_SERVICE:
+		{
+			if (which == SEL_NAME)
+			{
+				/* N.B. for SEL_NAME, num is 0 (don't care), 1 (udp) or 2 (tcp) */
+				if ((num == 1) && (string_not_equal("udp", ent.s->s_proto))) return 0;
+				if ((num == 2) && (string_not_equal("tcp", ent.s->s_proto))) return 0;
+
+				if (string_equal(name, ent.s->s_name)) return 1;
+				if (ent.s->s_aliases != NULL)
+				{
+					for (i = 0; ent.s->s_aliases[i] != NULL; i++)
+					{
+						if (string_equal(name, ent.s->s_aliases[i])) return 1;
+					}
+				}
+			}
+			else if (which == SEL_NUMBER)
+			{
+				/* N.B. for SEL_NUMBER, protocol is sent in name variable */
+				if ((name != NULL) && (string_not_equal(name, ent.s->s_proto))) return 0;
+				if (num == (uint32_t)ent.s->s_port) return 1;
+			}
+			return 0;
+		}
+		case CATEGORY_PROTOCOL:
+		{
+			if (which == SEL_NAME)
+			{
+				if (string_equal(name, ent.p->p_name)) return 1;
+				if (ent.p->p_aliases != NULL)
+				{
+					for (i = 0; ent.p->p_aliases[i] != NULL; i++)
+					{
+						if (string_equal(name, ent.p->p_aliases[i])) return 1;
+					}
+				}
+			}
+			else if (which == SEL_NUMBER)
+			{
+				if (num == (uint32_t)ent.p->p_proto) return 1;
+			}
+			return 0;
+		}
+		case CATEGORY_RPC:
+		{
+			if (which == SEL_NAME)
+			{
+				if (string_equal(name, ent.r->r_name)) return 1;
+				if (ent.r->r_aliases != NULL)
+				{
+					for (i = 0; ent.r->r_aliases[i] != NULL; i++)
+					{
+						if (string_equal(name, ent.r->r_aliases[i])) return 1;
+					}
+				}
+			}
+			else if (which == SEL_NUMBER)
+			{
+				if (num == (uint32_t)ent.r->r_number) return 1;
+			}
+			return 0;
+		}
+		case CATEGORY_FS:
+		{
+			if ((which == SEL_NAME) && (string_equal(name, ent.f->fs_spec))) return 1;
+			if ((which == SEL_NUMBER) && (string_equal(name, ent.f->fs_file))) return 1;
+			return 0;
+		}
+		case CATEGORY_MAC:
+		{
+			if ((which == SEL_NAME) && (string_equal(name, ent.m->host))) return 1;
+			if ((which == SEL_NUMBER) && (string_equal(name, ent.m->mac))) return 1;
+			return 0;
+		}
+		default: return 0;
+	}
+
+	return 0;
+}
+
+int
+si_item_is_valid(si_item_t *item)
+{
+	si_mod_t *si;
+
+	if (item == NULL) return 0;
+
+	si = item->src;
+
+	if (si == NULL) return 0;
+	if (si->vtable->sim_is_valid == NULL) return 0;
+
+	return si->vtable->sim_is_valid(si, item);
+}
+
+si_item_t *
+si_user_byname(si_mod_t *si, const char *name)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_user_byname == NULL) return NULL;
+	return si->vtable->sim_user_byname(si, name);
+}
+
+si_item_t *
+si_user_byuid(si_mod_t *si, uid_t uid)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_user_byuid == NULL) return NULL;
+	return si->vtable->sim_user_byuid(si, uid);
+}
+
+si_item_t *
+si_user_byuuid(si_mod_t *si, uuid_t uuid)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_user_byuuid == NULL) return NULL;
+	return si->vtable->sim_user_byuuid(si, uuid);
+}
+
+si_list_t *
+si_user_all(si_mod_t *si)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_user_all == NULL) return NULL;
+	return si->vtable->sim_user_all(si);
+}
+
+si_item_t *
+si_group_byname(si_mod_t *si, const char *name)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_group_byname == NULL) return NULL;
+	return si->vtable->sim_group_byname(si, name);
+}
+
+si_item_t *
+si_group_bygid(si_mod_t *si, gid_t gid)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_group_bygid == NULL) return NULL;
+	return si->vtable->sim_group_bygid(si, gid);
+}
+
+si_item_t *
+si_group_byuuid(si_mod_t *si, uuid_t uuid)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_group_byuuid == NULL) return NULL;
+	return si->vtable->sim_group_byuuid(si, uuid);
+}
+
+si_list_t *
+si_group_all(si_mod_t *si)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_group_all == NULL) return NULL;
+	return si->vtable->sim_group_all(si);
+}
+
+si_item_t *
+si_grouplist(si_mod_t *si, const char *name, uint32_t count)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_grouplist == NULL) return NULL;
+	return si->vtable->sim_grouplist(si, name, count);
+}
+
+si_list_t *
+si_netgroup_byname(struct si_mod_s *si, const char *name)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_netgroup_byname == NULL) return NULL;
+	return si->vtable->sim_netgroup_byname(si, name);
+}
+
+int
+si_in_netgroup(struct si_mod_s *si, const char *name, const char *host, const char *user, const char *domain)
+{
+	if (si == NULL) return 0;
+	if (si->vtable->sim_in_netgroup == NULL) return 0;
+	return si->vtable->sim_in_netgroup(si, name, host, user, domain);
+}
+
+si_item_t *
+si_alias_byname(si_mod_t *si, const char *name)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_alias_byname == NULL) return NULL;
+	return si->vtable->sim_alias_byname(si, name);
+}
+
+si_list_t *
+si_alias_all(si_mod_t *si)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_alias_all == NULL) return NULL;
+	return si->vtable->sim_alias_all(si);
+}
+
+si_item_t *
+si_host_byname(si_mod_t *si, const char *name, int af, const char *interface, uint32_t *err)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_host_byname == NULL) return NULL;
+	return si->vtable->sim_host_byname(si, name, af, interface, err);
+}
+
+si_item_t *
+si_host_byaddr(si_mod_t *si, const void *addr, int af, const char *interface, uint32_t *err)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_host_byaddr == NULL) return NULL;
+	return si->vtable->sim_host_byaddr(si, addr, af, interface, err);
+}
+
+si_list_t *
+si_host_all(si_mod_t *si)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_host_all == NULL) return NULL;
+	return si->vtable->sim_host_all(si);
+}
+
+si_item_t *
+si_mac_byname(struct si_mod_s *si, const char *name)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_mac_byname == NULL) return NULL;
+	return si->vtable->sim_mac_byname(si, name);
+}
+
+si_item_t *
+si_mac_bymac(struct si_mod_s *si, const char *mac)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_mac_bymac == NULL) return NULL;
+	return si->vtable->sim_mac_bymac(si, mac);
+}
+
+si_list_t *
+si_mac_all(si_mod_t *si)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_mac_all == NULL) return NULL;
+	return si->vtable->sim_mac_all(si);
+}
+
+si_item_t *
+si_network_byname(si_mod_t *si, const char *name)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_network_byname == NULL) return NULL;
+	return si->vtable->sim_network_byname(si, name);
+}
+
+si_item_t *
+si_network_byaddr(si_mod_t *si, uint32_t addr)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_network_byaddr == NULL) return NULL;
+	return si->vtable->sim_network_byaddr(si, addr);
+}
+
+si_list_t *
+si_network_all(si_mod_t *si)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_network_all == NULL) return NULL;
+	return si->vtable->sim_network_all(si);
+}
+
+si_item_t *
+si_service_byname(si_mod_t *si, const char *name, const char *proto)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_service_byname == NULL) return NULL;
+	return si->vtable->sim_service_byname(si, name, proto);
+}
+
+si_item_t *
+si_service_byport(si_mod_t *si, int port, const char *proto)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_service_byport == NULL) return NULL;
+	return si->vtable->sim_service_byport(si, port, proto);
+}
+
+si_list_t *
+si_service_all(si_mod_t *si)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_service_all == NULL) return NULL;
+	return si->vtable->sim_service_all(si);
+}
+
+si_item_t *
+si_protocol_byname(si_mod_t *si, const char *name)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_protocol_byname == NULL) return NULL;
+	return si->vtable->sim_protocol_byname(si, name);
+}
+
+si_item_t *
+si_protocol_bynumber(si_mod_t *si, uint32_t number)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_protocol_bynumber == NULL) return NULL;
+	return si->vtable->sim_protocol_bynumber(si, number);
+}
+
+si_list_t *
+si_protocol_all(si_mod_t *si)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_protocol_all == NULL) return NULL;
+	return si->vtable->sim_protocol_all(si);
+}
+
+si_item_t *
+si_rpc_byname(si_mod_t *si, const char *name)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_rpc_byname == NULL) return NULL;
+	return si->vtable->sim_rpc_byname(si, name);
+}
+
+si_item_t *
+si_rpc_bynumber(si_mod_t *si, int number)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_rpc_bynumber == NULL) return NULL;
+	return si->vtable->sim_rpc_bynumber(si, number);
+}
+
+si_list_t *
+si_rpc_all(si_mod_t *si)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_rpc_all == NULL) return NULL;
+	return si->vtable->sim_rpc_all(si);
+}
+
+si_item_t *
+si_fs_byspec(si_mod_t *si, const char *spec)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_fs_byspec == NULL) return NULL;
+	return si->vtable->sim_fs_byspec(si, spec);
+}
+
+si_item_t *
+si_fs_byfile(si_mod_t *si, const char *file)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_fs_byfile == NULL) return NULL;
+	return si->vtable->sim_fs_byfile(si, file);
+}
+
+si_list_t *
+si_fs_all(si_mod_t *si)
+{
+	if (si == NULL) return NULL;
+	if (si->vtable->sim_fs_all == NULL) return NULL;
+	return si->vtable->sim_fs_all(si);
+}
+
+si_item_t *
+si_item_call(struct si_mod_s *si, int call, const char *str1, const char *str2, const char *str3, uint32_t num1, uint32_t num2, uint32_t *err)
+{
+	if (si == NULL) return NULL;
+
+	switch (call)
+	{
+		case SI_CALL_USER_BYNAME: return si_user_byname(si, str1);
+		case SI_CALL_USER_BYUID: return si_user_byuid(si, (uid_t)num1);
+		case SI_CALL_GROUP_BYNAME: return si_group_byname(si, str1);
+		case SI_CALL_GROUP_BYGID: return si_group_bygid(si, (gid_t)num1);
+		case SI_CALL_GROUPLIST: return si_grouplist(si, str1, (int) num1);
+		case SI_CALL_ALIAS_BYNAME: return si_alias_byname(si, str1);
+		case SI_CALL_HOST_BYNAME: return si_host_byname(si, str1, num1, str3, err);
+		case SI_CALL_HOST_BYADDR: return si_host_byaddr(si, (const void *)str1, num1, str3, err);
+		case SI_CALL_NETWORK_BYNAME: return si_network_byname(si, str1);
+		case SI_CALL_NETWORK_BYADDR: return si_network_byaddr(si, num1);
+		case SI_CALL_SERVICE_BYNAME: return si_service_byname(si, str1, str2);
+		case SI_CALL_SERVICE_BYPORT: return si_service_byport(si, num1, str2);
+		case SI_CALL_PROTOCOL_BYNAME: return si_protocol_byname(si, str1);
+		case SI_CALL_PROTOCOL_BYNUMBER: return si_protocol_bynumber(si, num1);
+		case SI_CALL_RPC_BYNAME: return si_network_byname(si, str1);
+		case SI_CALL_RPC_BYNUMBER: return si_rpc_bynumber(si, num1);
+		case SI_CALL_FS_BYSPEC: return si_fs_byspec(si, str1);
+	    case SI_CALL_FS_BYFILE: return si_fs_byfile(si, str1);
+#ifndef __FreeBSD__		
+		case SI_CALL_NAMEINFO: return si_nameinfo(si, (const struct sockaddr *)str1, num1, str3, err);
+	case SI_CALL_IPNODE_BYNAME: return si_ipnode_byname(si, (const char *)str1, num1, num2, str3, err);
+#endif		
+		case SI_CALL_MAC_BYNAME: return si_mac_byname(si, (const char *)str1);
+		case SI_CALL_MAC_BYMAC: return si_mac_bymac(si, (const char *)str1);
+
+		/* Support for DNS async calls */
+		case SI_CALL_DNS_QUERY:
+		case SI_CALL_DNS_SEARCH:
+		{
+			if (si->vtable->sim_item_call == NULL) return NULL;
+			return si->vtable->sim_item_call(si, call, str1, str2, str3, num1, num2, err);
+		}
+
+		default: return NULL;
+	}
+
+	return NULL;
+}
+
+si_list_t *
+si_list_call(struct si_mod_s *si, int call, const char *str1 __unused, const char *str2 __unused, const char *str3 __unused, uint32_t num1 __unused, uint32_t num2 __unused, uint32_t num3 __unused, uint32_t num4 __unused, uint32_t *err __unused)
+{
+	if (si == NULL) return NULL;
+
+	switch (call)
+	{
+		case SI_CALL_USER_ALL: return si_user_all(si);
+		case SI_CALL_GROUP_ALL: return si_group_all(si);
+		case SI_CALL_ALIAS_ALL: return si_alias_all(si);
+		case SI_CALL_HOST_ALL: return si_host_all(si);
+		case SI_CALL_NETWORK_ALL: return si_network_all(si);
+		case SI_CALL_SERVICE_ALL: return si_service_all(si);
+		case SI_CALL_PROTOCOL_ALL: return si_protocol_all(si);
+		case SI_CALL_RPC_ALL: return si_rpc_all(si);
+		case SI_CALL_FS_ALL: return si_fs_all(si);
+	case SI_CALL_MAC_ALL: return si_mac_all(si);
+#ifndef __FreeBSD__		
+	case SI_CALL_ADDRINFO: return si_addrinfo(si, str1, str2, num1, num2, num3, num4, str3, err);
+#endif		
+		default: return NULL;
+	}
+
+	return NULL;
+}
+
+static void
+si_async_worklist_add_unit(si_async_workunit_t *r)
+{
+	pthread_mutex_lock(&module_mutex);
+	r->next = si_async_worklist;
+	si_async_worklist = r;
+	pthread_mutex_unlock(&module_mutex);
+}
+
+static void
+si_async_worklist_remove_unit(si_async_workunit_t *r)
+{
+	si_async_workunit_t *x;
+
+	pthread_mutex_lock(&module_mutex);
+	if (si_async_worklist == r)
+	{
+		si_async_worklist = r->next;
+	}
+	else
+	{
+		for (x = si_async_worklist; (x != NULL) && (x->next != r); x = x->next) {;}
+		if (x != NULL) x->next = r->next;
+	}
+	pthread_mutex_unlock(&module_mutex);
+}
+
+static si_async_workunit_t*
+si_async_worklist_find_unit(mach_port_t p)
+{
+	si_async_workunit_t *r;
+
+	pthread_mutex_lock(&module_mutex);
+	for (r = si_async_worklist; (r != NULL) && (r->port != p); r = r->next) {;}
+	pthread_mutex_unlock(&module_mutex);
+
+	return r;
+}
+
+static si_async_workunit_t *
+si_async_workunit_create(si_mod_t *si, int call, const char *str1, const char *str2, const char *str3, uint32_t num1, uint32_t num2, uint32_t num3, uint32_t num4, void *callback, void *context)
+{
+	si_async_workunit_t *r;
+	kern_return_t status;
+	mach_port_t reply, send;
+	mach_msg_type_name_t type;
+	char *s1, *s2, *s3;
+
+	s1 = NULL;
+	s2 = NULL;
+	s3 = NULL;
+
+	if (si_call_str1_is_buffer(call))
+	{
+		if (num3 > 0)
+		{
+			s1 = calloc(1, num3);
+			if (s1 == NULL) return NULL;
+			memcpy(s1, str1, num3);
+		}
+	}
+	else if (str1 != NULL)
+	{
+		s1 = strdup(str1);
+		if (s1 == NULL) return NULL;
+	}
+
+	if (str2 != NULL)
+	{
+		s2 = strdup(str2);
+		if (s2 == NULL)
+		{
+			if (s1 != NULL) free(s1);
+			return NULL;
+		}
+	}
+
+	if (str3 != NULL)
+	{
+		s3 = strdup(str3);
+		if (s3 == NULL)
+		{
+			if (s1 != NULL) free(s1);
+			if (s2 != NULL) free(s2);
+			return NULL;
+		}
+	}
+
+	r = (si_async_workunit_t *)calloc(1, sizeof(si_async_workunit_t));
+	if (r == NULL)
+	{
+		if (s1 != NULL) free(s1);
+		if (s2 != NULL) free(s2);
+		if (s3 != NULL) free(s3);
+		return NULL;
+	}
+
+	reply = MACH_PORT_NULL;
+	send = MACH_PORT_NULL;
+	type = 0;
+
+	status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &reply);
+	if (status == KERN_SUCCESS) status = mach_port_extract_right(mach_task_self(), reply, MACH_MSG_TYPE_MAKE_SEND_ONCE, &send, &type);
+	if (status != KERN_SUCCESS)
+	{
+		if (reply != MACH_PORT_NULL) mach_port_mod_refs(mach_task_self(), reply, MACH_PORT_RIGHT_RECEIVE, -1);
+		if (s1 != NULL) free(s1);
+		if (s2 != NULL) free(s2);
+		if (s3 != NULL) free(s3);
+		free(r);
+		return NULL;
+	}
+
+	r->si = si;
+	r->call = call;
+	r->str1 = s1;
+	r->str2 = s2;
+	r->str3 = s3;
+	r->num1 = num1;
+	r->num2 = num2;
+	r->num3 = num3;
+	r->num4 = num4;
+
+	r->refcount = 2;
+	r->flags = 0;
+	if (si_call_returns_list(call)) r->flags |= WORKUNIT_RETURNS_LIST;
+
+	r->callback = callback;
+	r->context = context;
+	r->port = reply;
+	r->send = send;
+
+	si_async_worklist_add_unit(r);
+
+	return r;
+}
+
+static void
+si_async_workunit_release(si_async_workunit_t *r)
+{
+	if (r == NULL) return;
+
+	if (OSAtomicDecrement32Barrier(&(r->refcount)) != 0) return;
+
+#ifdef CALL_TRACE
+	fprintf(stderr, "** %s freeing worklist item %p\n", __func__, r);
+#endif
+
+	si_async_worklist_remove_unit(r);
+
+	if (r->resitem != NULL) si_item_release(r->resitem);
+	if (r->reslist != NULL) si_list_release(r->reslist);
+
+	if (r->str1 != NULL) free(r->str1);
+	if (r->str2 != NULL) free(r->str2);
+	if (r->str3 != NULL) free(r->str3);
+
+	/* release send-once right if it has not been used */
+	if (r->send != MACH_PORT_NULL) mach_port_deallocate(mach_task_self(), r->send);
+
+	/* release receive right */
+	mach_port_mod_refs(mach_task_self(), r->port, MACH_PORT_RIGHT_RECEIVE, -1);
+
+	free(r);
+}
+
+static void
+si_async_launchpad(si_async_workunit_t *r)
+{
+	kern_return_t status;
+	mach_msg_empty_send_t msg;
+
+#ifdef CALL_TRACE
+	fprintf(stderr, "** %s starting worklist item %p\n", __func__, r);
+#endif
+
+	if (r->flags & WORKUNIT_CANCELLED)
+	{
+		si_async_workunit_release(r);
+#ifdef CALL_TRACE
+		fprintf(stderr, "** %s worklist item %p was cancelled early\n", __func__, r);
+#endif
+		return;
+	}
+
+	if (r->flags & WORKUNIT_RETURNS_LIST) r->reslist = si_list_call(r->si, r->call, r->str1, r->str2, r->str3, r->num1, r->num2, r->num3, r->num4, &(r->err));
+	else r->resitem = si_item_call(r->si, r->call, r->str1, r->str2, r->str3, r->num1, r->num2, &(r->err));
+
+	/*
+	 * Test and set the cancelled flag.
+	 * If it was set, then this work item was cancelled.
+	 * Otherwise, setting it here prevents si_async_cancel from cancelling:
+	 * too late to cancel now!
+	 */
+	if (OSAtomicTestAndSetBarrier(WORKUNIT_CANCELLED_BIT_ADDRESS, &(r->flags)) == 1)
+	{
+		si_async_workunit_release(r);
+#ifdef CALL_TRACE
+		fprintf(stderr, "** %s worklist item %p was cancelled in flight\n", __func__, r);
+#endif
+		return;
+	}
+#ifdef CALL_TRACE
+	else fprintf(stderr, "** %s worklist item %p flags are now 0x%08x\n", __func__, r, r->flags);
+#endif
+
+	memset(&msg, 0, sizeof(mach_msg_empty_send_t));
+
+	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, MACH_MSGH_BITS_ZERO);
+	msg.header.msgh_remote_port = r->send;
+	r->send = MACH_PORT_NULL;
+	msg.header.msgh_local_port = MACH_PORT_NULL;
+	msg.header.msgh_size = sizeof(mach_msg_empty_send_t);
+	msg.header.msgh_id = r->call;
+
+	status = mach_msg(&(msg.header), MACH_SEND_MSG, msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+	if (status != MACH_MSG_SUCCESS)
+	{
+		/* receiver failed - clean up to avoid a port leak */
+		mach_msg_destroy(&(msg.header));
+#ifdef CALL_TRACE
+		fprintf(stderr, "** %s mach message send failed for worklist item %p\n", __func__, r);
+#endif
+	}
+
+	si_async_workunit_release(r);
+
+	/*
+	 * The client is now responsible for calling si_async_handle_reply,
+	 * which will invoke the client's callback and then release the workunit.
+	 */
+
+#ifdef CALL_TRACE
+	fprintf(stderr, "** %s completed async worklist item %p\n", __func__, r);
+#endif
+}
+
+mach_port_t
+si_async_call(struct si_mod_s *si, int call, const char *str1, const char *str2, const char *str3, uint32_t num1, uint32_t num2, uint32_t num3, uint32_t num4, void *callback, void *context)
+{
+	si_async_workunit_t *req;
+
+	if (si == NULL) return MACH_PORT_NULL;
+	if (callback == NULL) return MACH_PORT_NULL;
+
+	/* if module does async on it's own, hand off the call */
+	if (si->vtable->sim_async_call != NULL)
+	{
+		return si->vtable->sim_async_call(si, call, str1, str2, str3, num1, num2, num3, num4, callback, context);
+	}
+
+	req = si_async_workunit_create(si, call, str1, str2, str3, num1, num2, num3, num4, callback, context);
+	if (req == NULL) return MACH_PORT_NULL;
+
+	/* queue the work on the global low-priority dispatch queue */
+#ifdef CALL_TRACE
+	fprintf(stderr, "** %s dispatching worklist item %p\n", __func__, req);
+#endif
+	dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, DISPATCH_QUEUE_OVERCOMMIT), ^{ si_async_launchpad(req); });
+
+	return req->port;
+}
+
+void
+si_async_cancel(mach_port_t p)
+{
+	si_async_workunit_t *r;
+
+	r = si_async_worklist_find_unit(p);
+	if (r == NULL)
+	{
+#ifdef CALL_TRACE
+		fprintf(stderr, "** %s can't find worklist item\n", __func__);
+#endif
+		return;
+	}
+
+	/*
+	 * Test and set the WORKUNIT_CANCELLED flag.
+	 * If it was already set, this work item has been executed - too late to really cancel.
+	 */
+	if (OSAtomicTestAndSetBarrier(WORKUNIT_CANCELLED_BIT_ADDRESS, &(r->flags)) == 1)
+	{
+		/* already executed */
+#ifdef CALL_TRACE
+		fprintf(stderr, "** %s worklist item %p has executed\n", __func__, r);
+#endif
+	}
+
+#ifdef CALL_TRACE
+	fprintf(stderr, "** %s calling worklist item %p callback SI_STATUS_CALL_CANCELLED\n", __func__, r);
+#endif
+
+	if (r->callback != NULL)
+	{
+		if (r->flags & WORKUNIT_RETURNS_LIST) ((list_async_callback)(r->callback))(NULL, SI_STATUS_CALL_CANCELLED, r->context);
+		else ((item_async_callback)(r->callback))(NULL, SI_STATUS_CALL_CANCELLED, r->context);
+	}
+
+	si_async_workunit_release(r);
+}
+
+void
+si_async_handle_reply(mach_msg_header_t *msg)
+{
+	si_async_workunit_t *r;
+	mach_port_t reply = msg->msgh_local_port;
+
+	r = si_async_worklist_find_unit(reply);
+	if (r == NULL)
+	{
+#ifdef CALL_TRACE
+		fprintf(stderr, "** %s can't find worklist item\n", __func__);
+#endif
+		return;
+	}
+
+#ifdef CALL_TRACE
+	fprintf(stderr, "** %s worklist item %p flags are 0x%08x\n", __func__, r, r->flags);
+#endif
+	if ((r->flags & WORKUNIT_CANCELLED) == 0)
+	{
+#ifdef CALL_TRACE
+		fprintf(stderr, "** %s workunit thread is still active\n", __func__);
+#endif
+		return;
+	}
+
+	if (r->callback != NULL)
+	{
+		if (r->flags & WORKUNIT_RETURNS_LIST) ((list_async_callback)(r->callback))(r->reslist, r->err, r->context);
+		else ((item_async_callback)(r->callback))(r->resitem, r->err, r->context);
+
+		r->reslist = NULL;
+		r->resitem = NULL;
+	}
+	else
+	{
+#ifdef CALL_TRACE
+		fprintf(stderr, "** %s workunit has no callback\n", __func__);
+#endif
+	}
+
+	si_async_workunit_release(r);
+}
+
+char *
+si_standardize_mac_address(const char *addr)
+{
+	char e[6][3];
+	char *out;
+	struct ether_addr *ether;
+	int i;
+
+	if (addr == NULL) return NULL;
+
+	/* ether_aton isn't thread-safe */
+	pthread_mutex_lock(&module_mutex);
+
+	ether = ether_aton(addr);
+	if (ether == NULL)
+	{
+		pthread_mutex_unlock(&module_mutex);
+		return NULL;
+	}
+
+	for (i = 0; i < 6; i++)
+	{
+		if (ether->ether_addr_octet[i] <= 15)
+		{
+			sprintf(e[i], "0%x", ether->ether_addr_octet[i]);
+		}
+		else
+		{
+			sprintf(e[i], "%x", ether->ether_addr_octet[i]);
+		}
+	}
+
+	pthread_mutex_unlock(&module_mutex);
+
+	out = NULL;
+	asprintf(&out, "%s:%s:%s:%s:%s:%s", e[0], e[1], e[2], e[3], e[4], e[5]);
+	return out;
+}


Property changes on: trunk/lib/libosxsupport/si_module.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/uuid/clear.c
===================================================================
--- trunk/lib/libosxsupport/uuid/clear.c	                        (rev 0)
+++ trunk/lib/libosxsupport/uuid/clear.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,44 @@
+/*
+ * clear.c -- Clear a UUID
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * 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, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 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 ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include "string.h"
+
+#include "uuidP.h"
+
+void uuid_clear(uuid_t uu)
+{
+	memset(uu, 0, 16);
+}
+


Property changes on: trunk/lib/libosxsupport/uuid/clear.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/uuid/copy.c
===================================================================
--- trunk/lib/libosxsupport/uuid/copy.c	                        (rev 0)
+++ trunk/lib/libosxsupport/uuid/copy.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,46 @@
+/*
+ * copy.c --- copy UUIDs
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * 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, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 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 ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include "uuidP.h"
+
+void uuid_copy(uuid_t dst, const uuid_t src)
+{
+	unsigned char		*cp1;
+	const unsigned char	*cp2;
+	int			i;
+
+	for (i=0, cp1 = dst, cp2 = src; i < 16; i++)
+		*cp1++ = *cp2++;
+}


Property changes on: trunk/lib/libosxsupport/uuid/copy.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/uuid/gen_uuid.c
===================================================================
--- trunk/lib/libosxsupport/uuid/gen_uuid.c	                        (rev 0)
+++ trunk/lib/libosxsupport/uuid/gen_uuid.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,696 @@
+/*
+ * gen_uuid.c --- generate a DCE-compatible uuid
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * 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, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 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 ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+/*
+ * Force inclusion of SVID stuff since we need it if we're compiling in
+ * gcc-wall wall mode
+ */
+#define _SVID_SOURCE
+
+#include "config.h"
+#define HAVE_UNISTD_H
+#define HAVE_STDLIB_H
+#define HAVE_NET_IF_H
+#define HAVE_NETINET_IN_H
+#define HAVE_SYS_SOCKET_H
+#define HAVE_SYS_TIME_H
+#define HAVE_SYS_IOCTL_H
+#define HAVE_SYS_RESOURCE_H
+#define HAVE_SYS_UN_H
+#include <sys/types.h>
+#include <sys/param.h>
+
+#ifdef _WIN32
+#define _WIN32_WINNT 0x0500
+#include <windows.h>
+#define UUID MYUUID
+#endif
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/wait.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NET_IF_DL_H
+#include <net/if_dl.h>
+#endif
+#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
+#include <sys/syscall.h>
+#endif
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#include "uuidP.h"
+#include "uuidd.h"
+
+#ifdef HAVE_SRANDOM
+#define srand(x) 	srandom(x)
+#define rand() 		random()
+#endif
+
+#ifdef TLS
+#define THREAD_LOCAL static TLS
+#else
+#define THREAD_LOCAL static
+#endif
+
+#if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48)
+#define DO_JRAND_MIX
+THREAD_LOCAL unsigned short jrand_seed[3];
+#endif
+
+#ifdef _WIN32
+static void gettimeofday (struct timeval *tv, void *dummy)
+{
+	FILETIME	ftime;
+	uint64_t	n;
+
+	GetSystemTimeAsFileTime (&ftime);
+	n = (((uint64_t) ftime.dwHighDateTime << 32)
+	     + (uint64_t) ftime.dwLowDateTime);
+	if (n) {
+		n /= 10;
+		n -= ((369 * 365 + 89) * (uint64_t) 86400) * 1000000;
+	}
+
+	tv->tv_sec = n / 1000000;
+	tv->tv_usec = n % 1000000;
+}
+
+static int getuid (void)
+{
+	return 1;
+}
+#endif
+
+static int get_random_fd(void)
+{
+	struct timeval	tv;
+	static int	fd = -2;
+	int		i;
+
+	if (fd == -2) {
+		gettimeofday(&tv, 0);
+#ifndef _WIN32
+		fd = open("/dev/urandom", O_RDONLY);
+		if (fd == -1)
+			fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+		if (fd >= 0) {
+			i = fcntl(fd, F_GETFD);
+			if (i >= 0)
+				fcntl(fd, F_SETFD, i | FD_CLOEXEC);
+		}
+#endif
+		srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
+#ifdef DO_JRAND_MIX
+		jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF);
+		jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF);
+		jrand_seed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16;
+#endif
+	}
+	/* Crank the random number generator a few times */
+	gettimeofday(&tv, 0);
+	for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
+		rand();
+	return fd;
+}
+
+
+/*
+ * Generate a series of random bytes.  Use /dev/urandom if possible,
+ * and if not, use srandom/random.
+ */
+static void get_random_bytes(void *buf, int nbytes)
+{
+	int i, n = nbytes, fd = get_random_fd();
+	int lose_counter = 0;
+	unsigned char *cp = buf;
+
+	if (fd >= 0) {
+		while (n > 0) {
+			i = read(fd, cp, n);
+			if (i <= 0) {
+				if (lose_counter++ > 16)
+					break;
+				continue;
+			}
+			n -= i;
+			cp += i;
+			lose_counter = 0;
+		}
+	}
+
+	/*
+	 * We do this all the time, but this is the only source of
+	 * randomness if /dev/random/urandom is out to lunch.
+	 */
+	for (cp = buf, i = 0; i < nbytes; i++)
+		*cp++ ^= (rand() >> 7) & 0xFF;
+#ifdef DO_JRAND_MIX
+	{
+		unsigned short tmp_seed[3];
+
+		memcpy(tmp_seed, jrand_seed, sizeof(tmp_seed));
+		jrand_seed[2] = jrand_seed[2] ^ syscall(__NR_gettid);
+		for (cp = buf, i = 0; i < nbytes; i++)
+			*cp++ ^= (jrand48(tmp_seed) >> 7) & 0xFF;
+		memcpy(jrand_seed, tmp_seed,
+		       sizeof(jrand_seed) - sizeof(unsigned short));
+	}
+#endif
+
+	return;
+}
+
+/*
+ * Get the ethernet hardware address, if we can find it...
+ *
+ * XXX for a windows version, probably should use GetAdaptersInfo:
+ * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451
+ * commenting out get_node_id just to get gen_uuid to compile under windows
+ * is not the right way to go!
+ */
+static int get_node_id(unsigned char *node_id)
+{
+#ifdef HAVE_NET_IF_H
+	int 		sd;
+	struct ifreq 	ifr, *ifrp;
+	struct ifconf 	ifc;
+	uint64_t buf[1024/8];
+	int		n, i;
+	unsigned char 	*a;
+#ifdef HAVE_NET_IF_DL_H
+	struct sockaddr_dl *sdlp;
+#endif
+
+/*
+ * BSD 4.4 defines the size of an ifreq to be
+ * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
+ * However, under earlier systems, sa_len isn't present, so the size is
+ * just sizeof(struct ifreq)
+ */
+#ifdef HAVE_SA_LEN
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#define ifreq_size(i) max(sizeof(struct ifreq),\
+     sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
+#else
+#define ifreq_size(i) sizeof(struct ifreq)
+#endif /* HAVE_SA_LEN*/
+
+	sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+	if (sd < 0) {
+		return -1;
+	}
+	memset(buf, 0, sizeof(buf));
+	ifc.ifc_len = sizeof(buf);
+	ifc.ifc_buf = (void *)buf;
+	if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
+		close(sd);
+		return -1;
+	}
+	n = ifc.ifc_len;
+	for (i = 0; i < n; i+= ifreq_size(*ifrp) ) {
+		ifrp = (struct ifreq *)((uint64_t *) buf+(i/8));
+		strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
+#ifdef SIOCGIFHWADDR
+		if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
+			continue;
+		a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
+#else
+#ifdef SIOCGENADDR
+		if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
+			continue;
+		a = (unsigned char *) ifr.ifr_enaddr;
+#else
+#ifdef HAVE_NET_IF_DL_H
+		sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
+		if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
+			continue;
+		a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
+#else
+		/*
+		 * XXX we don't have a way of getting the hardware
+		 * address
+		 */
+		close(sd);
+		return 0;
+#endif /* HAVE_NET_IF_DL_H */
+#endif /* SIOCGENADDR */
+#endif /* SIOCGIFHWADDR */
+		if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
+			continue;
+		if (node_id) {
+			memcpy(node_id, a, 6);
+			close(sd);
+			return 1;
+		}
+	}
+	close(sd);
+#endif
+	return 0;
+}
+
+/* Assume that the gettimeofday() has microsecond granularity */
+#define MAX_ADJUSTMENT 10
+
+static int get_clock(uint32_t *clock_high, uint32_t *clock_low,
+		     uint16_t *ret_clock_seq, int *num)
+{
+	THREAD_LOCAL int		adjustment = 0;
+	THREAD_LOCAL struct timeval	last = {0, 0};
+	THREAD_LOCAL int		state_fd = -2;
+	THREAD_LOCAL FILE		*state_f;
+	THREAD_LOCAL uint16_t		clock_seq;
+	struct timeval 			tv;
+	struct flock			fl;
+	uint64_t			clock_reg;
+	mode_t				save_umask;
+	int				len;
+
+	if (state_fd == -2) {
+		save_umask = umask(0);
+		state_fd = open("/var/lib/libuuid/clock.txt",
+				O_RDWR|O_CREAT, 0660);
+		(void) umask(save_umask);
+		if (state_fd >= 0) {
+			state_f = fdopen(state_fd, "r+");
+			if (!state_f) {
+				close(state_fd);
+				state_fd = -1;
+			}
+		}
+	}
+	fl.l_type = F_WRLCK;
+	fl.l_whence = SEEK_SET;
+	fl.l_start = 0;
+	fl.l_len = 0;
+	fl.l_pid = 0;
+	if (state_fd >= 0) {
+		rewind(state_f);
+		while (fcntl(state_fd, F_SETLKW, &fl) < 0) {
+			if ((errno == EAGAIN) || (errno == EINTR))
+				continue;
+			fclose(state_f);
+			state_fd = -1;
+			break;
+		}
+	}
+	if (state_fd >= 0) {
+		unsigned int cl;
+		unsigned long tv1, tv2;
+		int a;
+
+		if (fscanf(state_f, "clock: %04x tv: %lu %lu adj: %d\n",
+			   &cl, &tv1, &tv2, &a) == 4) {
+			clock_seq = cl & 0x3FFF;
+			last.tv_sec = tv1;
+			last.tv_usec = tv2;
+			adjustment = a;
+		}
+	}
+
+	if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
+		get_random_bytes(&clock_seq, sizeof(clock_seq));
+		clock_seq &= 0x3FFF;
+		gettimeofday(&last, 0);
+		last.tv_sec--;
+	}
+
+try_again:
+	gettimeofday(&tv, 0);
+	if ((tv.tv_sec < last.tv_sec) ||
+	    ((tv.tv_sec == last.tv_sec) &&
+	     (tv.tv_usec < last.tv_usec))) {
+		clock_seq = (clock_seq+1) & 0x3FFF;
+		adjustment = 0;
+		last = tv;
+	} else if ((tv.tv_sec == last.tv_sec) &&
+	    (tv.tv_usec == last.tv_usec)) {
+		if (adjustment >= MAX_ADJUSTMENT)
+			goto try_again;
+		adjustment++;
+	} else {
+		adjustment = 0;
+		last = tv;
+	}
+
+	clock_reg = tv.tv_usec*10 + adjustment;
+	clock_reg += ((uint64_t) tv.tv_sec)*10000000;
+	clock_reg += (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
+
+	if (num && (*num > 1)) {
+		adjustment += *num - 1;
+		last.tv_usec += adjustment / 10;
+		adjustment = adjustment % 10;
+		last.tv_sec += last.tv_usec / 1000000;
+		last.tv_usec = last.tv_usec % 1000000;
+	}
+
+	if (state_fd > 0) {
+		rewind(state_f);
+#ifdef __LP64__
+		len = fprintf(state_f,
+			      "clock: %04x tv: %016lu %08lu adj: %08d\n",
+			      clock_seq, last.tv_sec, (long)last.tv_usec,
+					  adjustment);
+#else
+		len = fprintf(state_f,
+					  "clock: %04x tv: %016u %08lu adj: %08d\n",
+					  clock_seq, last.tv_sec, (long)last.tv_usec,
+					  adjustment);
+#endif
+		fflush(state_f);
+		if (ftruncate(state_fd, len) < 0) {
+			fprintf(state_f, "                   \n");
+			fflush(state_f);
+		}
+		rewind(state_f);
+		fl.l_type = F_UNLCK;
+		if (fcntl(state_fd, F_SETLK, &fl) < 0) {
+			fclose(state_f);
+			state_fd = -1;
+		}
+	}
+
+	*clock_high = clock_reg >> 32;
+	*clock_low = clock_reg;
+	*ret_clock_seq = clock_seq;
+	return 0;
+}
+#ifdef USE_UUIDD
+static ssize_t read_all(int fd, char *buf, size_t count)
+{
+	ssize_t ret;
+	ssize_t c = 0;
+	int tries = 0;
+
+	memset(buf, 0, count);
+	while (count > 0) {
+		ret = read(fd, buf, count);
+		if (ret <= 0) {
+			if ((errno == EAGAIN || errno == EINTR || ret == 0) &&
+			    (tries++ < 5))
+				continue;
+			return c ? c : -1;
+		}
+		if (ret > 0)
+			tries = 0;
+		count -= ret;
+		buf += ret;
+		c += ret;
+	}
+	return c;
+}
+
+/*
+ * Close all file descriptors
+ */
+static void close_all_fds(void)
+{
+	int i, max;
+
+#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
+	max = sysconf(_SC_OPEN_MAX);
+#elif defined(HAVE_GETDTABLESIZE)
+	max = getdtablesize();
+#elif defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
+	struct rlimit rl;
+
+	getrlimit(RLIMIT_NOFILE, &rl);
+	max = rl.rlim_cur;
+#else
+	max = OPEN_MAX;
+#endif
+
+	for (i=0; i < max; i++) {
+		close(i);
+		if (i <= 2)
+			open("/dev/null", O_RDWR);
+	}
+}
+#endif
+
+/*
+ * Try using the uuidd daemon to generate the UUID
+ *
+ * Returns 0 on success, non-zero on failure.
+ */
+static int get_uuid_via_daemon(int op __unused, uuid_t out __unused, int *num __unused)
+{
+#if defined(USE_UUIDD) && defined(HAVE_SYS_UN_H)
+	char op_buf[64];
+	int op_len;
+	int s;
+	ssize_t ret;
+	int32_t reply_len = 0, expected = 16;
+	struct sockaddr_un srv_addr;
+	struct stat st;
+	pid_t pid;
+	static const char *uuidd_path = UUIDD_PATH;
+	static int access_ret = -2;
+	static int start_attempts = 0;
+
+	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+		return -1;
+
+	srv_addr.sun_family = AF_UNIX;
+	strcpy(srv_addr.sun_path, UUIDD_SOCKET_PATH);
+
+	if (connect(s, (const struct sockaddr *) &srv_addr,
+		    sizeof(struct sockaddr_un)) < 0) {
+		if (access_ret == -2)
+			access_ret = access(uuidd_path, X_OK);
+		if (access_ret == 0)
+			access_ret = stat(uuidd_path, &st);
+		if (access_ret == 0 && (st.st_mode & (S_ISUID | S_ISGID)) == 0)
+			access_ret = access(UUIDD_DIR, W_OK);
+		if (access_ret == 0 && start_attempts++ < 5) {
+			if ((pid = fork()) == 0) {
+				close_all_fds();
+				execl(uuidd_path, "uuidd", "-qT", "300",
+				      (char *) NULL);
+				exit(1);
+			}
+			(void) waitpid(pid, 0, 0);
+			if (connect(s, (const struct sockaddr *) &srv_addr,
+				    sizeof(struct sockaddr_un)) < 0)
+				goto fail;
+		} else
+			goto fail;
+	}
+	op_buf[0] = op;
+	op_len = 1;
+	if (op == UUIDD_OP_BULK_TIME_UUID) {
+		memcpy(op_buf+1, num, sizeof(*num));
+		op_len += sizeof(*num);
+		expected += sizeof(*num);
+	}
+
+	ret = write(s, op_buf, op_len);
+	if (ret < 1)
+		goto fail;
+
+	ret = read_all(s, (char *) &reply_len, sizeof(reply_len));
+	if (ret < 0)
+		goto fail;
+
+	if (reply_len != expected)
+		goto fail;
+
+	ret = read_all(s, op_buf, reply_len);
+
+	if (op == UUIDD_OP_BULK_TIME_UUID)
+		memcpy(op_buf+16, num, sizeof(int));
+
+	memcpy(out, op_buf, 16);
+
+	close(s);
+	return ((ret == expected) ? 0 : -1);
+
+fail:
+	close(s);
+#endif
+	return -1;
+}
+
+void uuid__generate_time(uuid_t out, int *num)
+{
+	static unsigned char node_id[6];
+	static int has_init = 0;
+	struct uuid uu;
+	uint32_t	clock_mid;
+
+	if (!has_init) {
+		if (get_node_id(node_id) <= 0) {
+			get_random_bytes(node_id, 6);
+			/*
+			 * Set multicast bit, to prevent conflicts
+			 * with IEEE 802 addresses obtained from
+			 * network cards
+			 */
+			node_id[0] |= 0x01;
+		}
+		has_init = 1;
+	}
+	get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num);
+	uu.clock_seq |= 0x8000;
+	uu.time_mid = (uint16_t) clock_mid;
+	uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000;
+	memcpy(uu.node, node_id, 6);
+	uuid_pack(&uu, out);
+}
+
+void uuid_generate_time(uuid_t out)
+{
+#ifdef TLS
+	THREAD_LOCAL int		num = 0;
+	THREAD_LOCAL struct uuid	uu;
+	THREAD_LOCAL time_t		last_time = 0;
+	time_t				now;
+
+	if (num > 0) {
+		now = time(0);
+		if (now > last_time+1)
+			num = 0;
+	}
+	if (num <= 0) {
+		num = 1000;
+		if (get_uuid_via_daemon(UUIDD_OP_BULK_TIME_UUID,
+					out, &num) == 0) {
+			last_time = time(0);
+			uuid_unpack(out, &uu);
+			num--;
+			return;
+		}
+		num = 0;
+	}
+	if (num > 0) {
+		uu.time_low++;
+		if (uu.time_low == 0) {
+			uu.time_mid++;
+			if (uu.time_mid == 0)
+				uu.time_hi_and_version++;
+		}
+		num--;
+		uuid_pack(&uu, out);
+		return;
+	}
+#else
+	if (get_uuid_via_daemon(UUIDD_OP_TIME_UUID, out, 0) == 0)
+		return;
+#endif
+
+	uuid__generate_time(out, 0);
+}
+
+
+void uuid__generate_random(uuid_t out, int *num)
+{
+	uuid_t	buf;
+	struct uuid uu;
+	int i, n;
+
+	if (!num || !*num)
+		n = 1;
+	else
+		n = *num;
+
+	for (i = 0; i < n; i++) {
+		get_random_bytes(buf, sizeof(buf));
+		uuid_unpack(buf, &uu);
+
+		uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
+		uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF)
+			| 0x4000;
+		uuid_pack(&uu, out);
+		out += sizeof(uuid_t);
+	}
+}
+
+void uuid_generate_random(uuid_t out)
+{
+	int	num = 1;
+	/* No real reason to use the daemon for random uuid's -- yet */
+
+	uuid__generate_random(out, &num);
+}
+
+
+/*
+ * This is the generic front-end to uuid_generate_random and
+ * uuid_generate_time.  It uses uuid_generate_random only if
+ * /dev/urandom is available, since otherwise we won't have
+ * high-quality randomness.
+ */
+void uuid_generate(uuid_t out)
+{
+	if (get_random_fd() >= 0)
+		uuid_generate_random(out);
+	else
+		uuid_generate_time(out);
+}


Property changes on: trunk/lib/libosxsupport/uuid/gen_uuid.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/uuid/isnull.c
===================================================================
--- trunk/lib/libosxsupport/uuid/isnull.c	                        (rev 0)
+++ trunk/lib/libosxsupport/uuid/isnull.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,49 @@
+/*
+ * isnull.c --- Check whether or not the UUID is null
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * 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, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 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 ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include "uuidP.h"
+
+/* Returns 1 if the uuid is the NULL uuid */
+int uuid_is_null(const uuid_t uu)
+{
+	const unsigned char 	*cp;
+	int			i;
+
+	for (i=0, cp = uu; i < 16; i++)
+		if (*cp++)
+			return 0;
+	return 1;
+}
+


Property changes on: trunk/lib/libosxsupport/uuid/isnull.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/uuid/pack.c
===================================================================
--- trunk/lib/libosxsupport/uuid/pack.c	                        (rev 0)
+++ trunk/lib/libosxsupport/uuid/pack.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,70 @@
+/*
+ * Internal routine for packing UUID's
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * 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, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 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 ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <string.h>
+#include "uuidP.h"
+
+void uuid_pack(const struct uuid *uu, uuid_t ptr)
+{
+	uint32_t	tmp;
+	unsigned char	*out = ptr;
+
+	tmp = uu->time_low;
+	out[3] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[2] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[1] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[0] = (unsigned char) tmp;
+
+	tmp = uu->time_mid;
+	out[5] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[4] = (unsigned char) tmp;
+
+	tmp = uu->time_hi_and_version;
+	out[7] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[6] = (unsigned char) tmp;
+
+	tmp = uu->clock_seq;
+	out[9] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[8] = (unsigned char) tmp;
+
+	memcpy(out+10, uu->node, 6);
+}
+


Property changes on: trunk/lib/libosxsupport/uuid/pack.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/uuid/unpack.c
===================================================================
--- trunk/lib/libosxsupport/uuid/unpack.c	                        (rev 0)
+++ trunk/lib/libosxsupport/uuid/unpack.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,64 @@
+/*
+ * Internal routine for unpacking UUID
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * 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, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 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 ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <string.h>
+#include "uuidP.h"
+
+void uuid_unpack(const uuid_t in, struct uuid *uu)
+{
+	const uint8_t	*ptr = in;
+	uint32_t		tmp;
+
+	tmp = *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	uu->time_low = tmp;
+
+	tmp = *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	uu->time_mid = tmp;
+
+	tmp = *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	uu->time_hi_and_version = tmp;
+
+	tmp = *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	uu->clock_seq = tmp;
+
+	memcpy(uu->node, ptr, 6);
+}
+


Property changes on: trunk/lib/libosxsupport/uuid/unpack.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/uuid/unparse.c
===================================================================
--- trunk/lib/libosxsupport/uuid/unparse.c	                        (rev 0)
+++ trunk/lib/libosxsupport/uuid/unparse.c	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,77 @@
+/*
+ * unparse.c -- convert a UUID to string
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * 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, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 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 ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+
+#include "uuidP.h"
+
+static const char *fmt_lower =
+	"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
+
+static const char *fmt_upper =
+	"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X";
+
+#ifdef UUID_UNPARSE_DEFAULT_UPPER
+#define FMT_DEFAULT fmt_upper
+#else
+#define FMT_DEFAULT fmt_lower
+#endif
+
+static void uuid_unparse_x(const uuid_t uu, char *out, const char *fmt)
+{
+	struct uuid uuid;
+
+	uuid_unpack(uu, &uuid);
+	sprintf(out, fmt,
+		uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
+		uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
+		uuid.node[0], uuid.node[1], uuid.node[2],
+		uuid.node[3], uuid.node[4], uuid.node[5]);
+}
+
+void uuid_unparse_lower(const uuid_t uu, char *out)
+{
+	uuid_unparse_x(uu, out,	fmt_lower);
+}
+
+void uuid_unparse_upper(const uuid_t uu, char *out)
+{
+	uuid_unparse_x(uu, out,	fmt_upper);
+}
+
+void uuid_unparse(const uuid_t uu, char *out)
+{
+	uuid_unparse_x(uu, out, FMT_DEFAULT);
+}


Property changes on: trunk/lib/libosxsupport/uuid/unparse.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/uuid/uuidP.h
===================================================================
--- trunk/lib/libosxsupport/uuid/uuidP.h	                        (rev 0)
+++ trunk/lib/libosxsupport/uuid/uuidP.h	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,63 @@
+/*
+ * uuid.h -- private header file for uuids
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * 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, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 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 ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#include <uuid/uuid_types.h>
+#endif
+#include <sys/types.h>
+
+#include <uuid/uuid.h>
+
+/*
+ * Offset between 15-Oct-1582 and 1-Jan-70
+ */
+#define TIME_OFFSET_HIGH 0x01B21DD2
+#define TIME_OFFSET_LOW  0x13814000
+
+struct uuid {
+	uint32_t	time_low;
+	uint16_t	time_mid;
+	uint16_t	time_hi_and_version;
+	uint16_t	clock_seq;
+	uint8_t	node[6];
+};
+
+
+/*
+ * prototypes
+ */
+void uuid_pack(const struct uuid *uu, uuid_t ptr);
+void uuid_unpack(const uuid_t in, struct uuid *uu);


Property changes on: trunk/lib/libosxsupport/uuid/uuidP.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/lib/libosxsupport/uuid/uuidd.h
===================================================================
--- trunk/lib/libosxsupport/uuid/uuidd.h	                        (rev 0)
+++ trunk/lib/libosxsupport/uuid/uuidd.h	2016-08-12 01:15:53 UTC (rev 7700)
@@ -0,0 +1,54 @@
+/*
+ * Definitions used by the uuidd daemon
+ *
+ * Copyright (C) 2007 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * 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, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 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 ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#ifndef _UUID_UUIDD_H
+#define _UUID_UUIDD_H
+
+#define UUIDD_DIR		"/var/lib/libuuid"
+#define UUIDD_SOCKET_PATH	UUIDD_DIR "/request"
+#define UUIDD_PIDFILE_PATH	UUIDD_DIR "/uuidd.pid"
+#define UUIDD_PATH		"/usr/sbin/uuidd"
+
+#define UUIDD_OP_GETPID			0
+#define UUIDD_OP_GET_MAXOP		1
+#define UUIDD_OP_TIME_UUID		2
+#define UUIDD_OP_RANDOM_UUID		3
+#define UUIDD_OP_BULK_TIME_UUID		4
+#define UUIDD_OP_BULK_RANDOM_UUID	5
+#define UUIDD_MAX_OP			UUIDD_OP_BULK_RANDOM_UUID
+
+extern void uuid__generate_time(uuid_t out, int *num);
+extern void uuid__generate_random(uuid_t out, int *num);
+
+#endif /* _UUID_UUID_H */


Property changes on: trunk/lib/libosxsupport/uuid/uuidd.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property


More information about the Midnightbsd-cvs mailing list