[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, ¬imeout);
+ 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