this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Adding libnotify source, build scripts for libinfo/dns&util

+16732
+1
CMakeLists.txt
··· 17 17 18 18 add_subdirectory(libc) 19 19 add_subdirectory(libm) 20 + add_subdirectory(libinfo) 20 21 add_subdirectory(libmalloc) 21 22 add_subdirectory(libsystem) 22 23 add_subdirectory(keymgr)
+29
libinfo/CMakeLists.txt
··· 1 + project(libinfo) 2 + 3 + cmake_minimum_required(VERSION 2.4.0) 4 + 5 + if(CMAKE_SIZEOF_VOID_P EQUAL 4 OR CMAKE_INSTALL_LIBDIR STREQUAL "lib32") 6 + set(BITS 32) 7 + add_definitions(-DTARGET_CPU_X86=1) 8 + else(CMAKE_SIZEOF_VOID_P EQUAL 4 OR CMAKE_INSTALL_LIBDIR STREQUAL "lib32") 9 + set(BITS 64) 10 + add_definitions(-DTARGET_CPU_X86_64=1) 11 + endif(CMAKE_SIZEOF_VOID_P EQUAL 4 OR CMAKE_INSTALL_LIBDIR STREQUAL "lib32") 12 + 13 + add_definitions(-DTARGET_OS_MAC=1) 14 + add_definitions(-DHAVE_STDINT_H=1) 15 + add_definitions(-D__APPLE__ -D__DYNAMIC__) 16 + add_definitions(-D__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__=1080) 17 + 18 + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdinc -D__DARWIN_UNIX03 -fPIC -w") 19 + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -nostdlib -Wl,--unresolved-symbols=ignore-all") 20 + 21 + add_subdirectory(util.subproj) 22 + add_subdirectory(dns.subproj) 23 + #add_subdirectory(lookup.subproj) 24 + 25 + add_library(system_info SHARED $<TARGET_OBJECTS:info-util> 26 + $<TARGET_OBJECTS:info-dns> 27 + #$<TARGET_OBJECTS:info-lookup> # lookup doesn't build yet 28 + ) 29 + target_link_libraries(system_info system_c)
+18
libinfo/dns.subproj/CMakeLists.txt
··· 1 + project(libinfo-dns) 2 + 3 + cmake_minimum_required(VERSION 2.4.0) 4 + 5 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libc/locale) 6 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libc/locale/FreeBSD) 7 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libc/pthreads) 8 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libc/stdtime/FreeBSD) 9 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../external/libdispatch/) 10 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../lookup.subproj) 11 + 12 + set(info-dns_sources 13 + herror.c 14 + res_comp.c 15 + res_query.c 16 + ) 17 + 18 + add_library(info-dns OBJECT ${info-dns_sources})
+30
libinfo/lookup.subproj/CMakeLists.txt
··· 1 + project(libinfo-lookup) 2 + 3 + cmake_minimum_required(VERSION 2.4.0) 4 + 5 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libc/locale) 6 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libc/locale/FreeBSD) 7 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libc/pthreads) 8 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libc/stdtime/FreeBSD) 9 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../external/libdispatch/) 10 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 11 + 12 + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fblocks") 13 + 14 + set(info-lookup_sources 15 + cache_module.c 16 + ds_module.c 17 + file_module.c 18 + getnameinfo_link.c 19 + ils.c 20 + kvbuf.c 21 + libinfo.c 22 + mdns_module.c 23 + search_module.c 24 + si_data.c 25 + si_getaddrinfo.c 26 + si_module.c 27 + thread_data.c 28 + ) 29 + 30 + add_library(info-lookup OBJECT ${info-lookup_sources})
+15
libinfo/util.subproj/CMakeLists.txt
··· 1 + project(libinfo-util) 2 + 3 + cmake_minimum_required(VERSION 2.4.0) 4 + 5 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libc/locale) 6 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libc/locale/FreeBSD) 7 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libc/pthreads) 8 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libc/stdtime/FreeBSD) 9 + 10 + set(info-util_sources 11 + hton.c 12 + rcmd.c 13 + ) 14 + 15 + add_library(info-util OBJECT ${info-util_sources})
+372
libnotify/APPLE_LICENSE
··· 1 + APPLE PUBLIC SOURCE LICENSE 2 + Version 1.1 - April 19,1999 3 + 4 + Please read this License carefully before downloading this software. 5 + By downloading and using this software, you are agreeing to be bound 6 + by the terms of this License. If you do not or cannot agree to the 7 + terms of this License, please do not download or use the software. 8 + 9 + 1. General; Definitions. This License applies to any program or other 10 + work which Apple Computer, Inc. ("Apple") publicly announces as 11 + subject to this Apple Public Source License and which contains a 12 + notice placed by Apple identifying such program or work as "Original 13 + Code" and stating that it is subject to the terms of this Apple Public 14 + Source License version 1.1 (or subsequent version thereof), as it may 15 + be revised from time to time by Apple ("License"). As used in this 16 + License: 17 + 18 + 1.1 "Affected Original Code" means only those specific portions of 19 + Original Code that allegedly infringe upon any party's intellectual 20 + property rights or are otherwise the subject of a claim of 21 + infringement. 22 + 23 + 1.2 "Applicable Patent Rights" mean: (a) in the case where Apple is 24 + the grantor of rights, (i) claims of patents that are now or hereafter 25 + acquired, owned by or assigned to Apple and (ii) that cover subject 26 + matter contained in the Original Code, but only to the extent 27 + necessary to use, reproduce and/or distribute the Original Code 28 + without infringement; and (b) in the case where You are the grantor of 29 + rights, (i) claims of patents that are now or hereafter acquired, 30 + owned by or assigned to You and (ii) that cover subject matter in Your 31 + Modifications, taken alone or in combination with Original Code. 32 + 33 + 1.3 "Covered Code" means the Original Code, Modifications, the 34 + combination of Original Code and any Modifications, and/or any 35 + respective portions thereof. 36 + 37 + 1.4 "Deploy" means to use, sublicense or distribute Covered Code other 38 + than for Your internal research and development (R&D), and includes 39 + without limitation, any and all internal use or distribution of 40 + Covered Code within Your business or organization except for R&D use, 41 + as well as direct or indirect sublicensing or distribution of Covered 42 + Code by You to any third party in any form or manner. 43 + 44 + 1.5 "Larger Work" means a work which combines Covered Code or portions 45 + thereof with code not governed by the terms of this License. 46 + 47 + 1.6 "Modifications" mean any addition to, deletion from, and/or change 48 + to, the substance and/or structure of Covered Code. When code is 49 + released as a series of files, a Modification is: (a) any addition to 50 + or deletion from the contents of a file containing Covered Code; 51 + and/or (b) any new file or other representation of computer program 52 + statements that contains any part of Covered Code. 53 + 54 + 1.7 "Original Code" means (a) the Source Code of a program or other 55 + work as originally made available by Apple under this License, 56 + including the Source Code of any updates or upgrades to such programs 57 + or works made available by Apple under this License, and that has been 58 + expressly identified by Apple as such in the header file(s) of such 59 + work; and (b) the object code compiled from such Source Code and 60 + originally made available by Apple under this License. 61 + 62 + 1.8 "Source Code" means the human readable form of a program or other 63 + work that is suitable for making modifications to it, including all 64 + modules it contains, plus any associated interface definition files, 65 + scripts used to control compilation and installation of an executable 66 + (object code). 67 + 68 + 1.9 "You" or "Your" means an individual or a legal entity exercising 69 + rights under this License. For legal entities, "You" or "Your" 70 + includes any entity which controls, is controlled by, or is under 71 + common control with, You, where "control" means (a) the power, direct 72 + or indirect, to cause the direction or management of such entity, 73 + whether by contract or otherwise, or (b) ownership of fifty percent 74 + (50%) or more of the outstanding shares or beneficial ownership of 75 + such entity. 76 + 77 + 2. Permitted Uses; Conditions & Restrictions. Subject to the terms 78 + and conditions of this License, Apple hereby grants You, effective on 79 + the date You accept this License and download the Original Code, a 80 + world-wide, royalty-free, non- exclusive license, to the extent of 81 + Apple's Applicable Patent Rights and copyrights covering the Original 82 + Code, to do the following: 83 + 84 + 2.1 You may use, copy, modify and distribute Original Code, with or 85 + without Modifications, solely for Your internal research and 86 + development, provided that You must in each instance: 87 + 88 + (a) retain and reproduce in all copies of Original Code the copyright 89 + and other proprietary notices and disclaimers of Apple as they appear 90 + in the Original Code, and keep intact all notices in the Original Code 91 + that refer to this License; 92 + 93 + (b) include a copy of this License with every copy of Source Code of 94 + Covered Code and documentation You distribute, and You may not offer 95 + or impose any terms on such Source Code that alter or restrict this 96 + License or the recipients' rights hereunder, except as permitted under 97 + Section 6; and 98 + 99 + (c) completely and accurately document all Modifications that you have 100 + made and the date of each such Modification, designate the version of 101 + the Original Code you used, prominently include a file carrying such 102 + information with the Modifications, and duplicate the notice in 103 + Exhibit A in each file of the Source Code of all such Modifications. 104 + 105 + 2.2 You may Deploy Covered Code, provided that You must in each 106 + instance: 107 + 108 + (a) satisfy all the conditions of Section 2.1 with respect to the 109 + Source Code of the Covered Code; 110 + 111 + (b) make all Your Deployed Modifications publicly available in Source 112 + Code form via electronic distribution (e.g. download from a web site) 113 + under the terms of this License and subject to the license grants set 114 + forth in Section 3 below, and any additional terms You may choose to 115 + offer under Section 6. You must continue to make the Source Code of 116 + Your Deployed Modifications available for as long as you Deploy the 117 + Covered Code or twelve (12) months from the date of initial 118 + Deployment, whichever is longer; 119 + 120 + (c) if You Deploy Covered Code containing Modifications made by You, 121 + inform others of how to obtain those Modifications by filling out and 122 + submitting the information found at 123 + http://www.apple.com/publicsource/modifications.html, if available; 124 + and 125 + 126 + (d) if You Deploy Covered Code in object code, executable form only, 127 + include a prominent notice, in the code itself as well as in related 128 + documentation, stating that Source Code of the Covered Code is 129 + available under the terms of this License with information on how and 130 + where to obtain such Source Code. 131 + 132 + 3. Your Grants. In consideration of, and as a condition to, the 133 + licenses granted to You under this License: 134 + 135 + (a) You hereby grant to Apple and all third parties a non-exclusive, 136 + royalty-free license, under Your Applicable Patent Rights and other 137 + intellectual property rights owned or controlled by You, to use, 138 + reproduce, modify, distribute and Deploy Your Modifications of the 139 + same scope and extent as Apple's licenses under Sections 2.1 and 2.2; 140 + and 141 + 142 + (b) You hereby grant to Apple and its subsidiaries a non-exclusive, 143 + worldwide, royalty-free, perpetual and irrevocable license, under Your 144 + Applicable Patent Rights and other intellectual property rights owned 145 + or controlled by You, to use, reproduce, execute, compile, display, 146 + perform, modify or have modified (for Apple and/or its subsidiaries), 147 + sublicense and distribute Your Modifications, in any form, through 148 + multiple tiers of distribution. 149 + 150 + 4. Larger Works. You may create a Larger Work by combining Covered 151 + Code with other code not governed by the terms of this License and 152 + distribute the Larger Work as a single product. In each such 153 + instance, You must make sure the requirements of this License are 154 + fulfilled for the Covered Code or any portion thereof. 155 + 156 + 5. Limitations on Patent License. Except as expressly stated in 157 + Section 2, no other patent rights, express or implied, are granted by 158 + Apple herein. Modifications and/or Larger Works may require 159 + additional patent licenses from Apple which Apple may grant in its 160 + sole discretion. 161 + 162 + 6. Additional Terms. You may choose to offer, and to charge a fee 163 + for, warranty, support, indemnity or liability obligations and/or 164 + other rights consistent with the scope of the license granted herein 165 + ("Additional Terms") to one or more recipients of Covered 166 + Code. However, You may do so only on Your own behalf and as Your sole 167 + responsibility, and not on behalf of Apple. You must obtain the 168 + recipient's agreement that any such Additional Terms are offered by 169 + You alone, and You hereby agree to indemnify, defend and hold Apple 170 + harmless for any liability incurred by or claims asserted against 171 + Apple by reason of any such Additional Terms. 172 + 173 + 7. Versions of the License. Apple may publish revised and/or new 174 + versions of this License from time to time. Each version will be 175 + given a distinguishing version number. Once Original Code has been 176 + published under a particular version of this License, You may continue 177 + to use it under the terms of that version. You may also choose to use 178 + such Original Code under the terms of any subsequent version of this 179 + License published by Apple. No one other than Apple has the right to 180 + modify the terms applicable to Covered Code created under this 181 + License. 182 + 183 + 8. NO WARRANTY OR SUPPORT. The Original Code may contain in whole or 184 + in part pre-release, untested, or not fully tested works. The 185 + Original Code may contain errors that could cause failures or loss of 186 + data, and may be incomplete or contain inaccuracies. You expressly 187 + acknowledge and agree that use of the Original Code, or any portion 188 + thereof, is at Your sole and entire risk. THE ORIGINAL CODE IS 189 + PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND 190 + AND APPLE AND APPLE'S LICENSOR(S) (FOR THE PURPOSES OF SECTIONS 8 AND 191 + 9, APPLE AND APPLE'S LICENSOR(S) ARE COLLECTIVELY REFERRED TO AS 192 + "APPLE") EXPRESSLY DISCLAIM ALL WARRANTIES AND/OR CONDITIONS, EXPRESS 193 + OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 194 + AND/OR CONDITIONS OF MERCHANTABILITY OR SATISFACTORY QUALITY AND 195 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY 196 + RIGHTS. APPLE DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED IN THE 197 + ORIGINAL CODE WILL MEET YOUR REQUIREMENTS, OR THAT THE OPERATION OF 198 + THE ORIGINAL CODE WILL BE UNINTERRUPTED OR ERROR- FREE, OR THAT 199 + DEFECTS IN THE ORIGINAL CODE WILL BE CORRECTED. NO ORAL OR WRITTEN 200 + INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED 201 + REPRESENTATIVE SHALL CREATE A WARRANTY OR IN ANY WAY INCREASE THE 202 + SCOPE OF THIS WARRANTY. You acknowledge that the Original Code is not 203 + intended for use in the operation of nuclear facilities, aircraft 204 + navigation, communication systems, or air traffic control machines in 205 + which case the failure of the Original Code could lead to death, 206 + personal injury, or severe physical or environmental damage. 207 + 208 + 9. Liability. 209 + 210 + 9.1 Infringement. If any portion of, or functionality implemented by, 211 + the Original Code becomes the subject of a claim of infringement, 212 + Apple may, at its option: (a) attempt to procure the rights necessary 213 + for Apple and You to continue using the Affected Original Code; (b) 214 + modify the Affected Original Code so that it is no longer infringing; 215 + or (c) suspend Your rights to use, reproduce, modify, sublicense and 216 + distribute the Affected Original Code until a final determination of 217 + the claim is made by a court or governmental administrative agency of 218 + competent jurisdiction and Apple lifts the suspension as set forth 219 + below. Such suspension of rights will be effective immediately upon 220 + Apple's posting of a notice to such effect on the Apple web site that 221 + is used for implementation of this License. Upon such final 222 + determination being made, if Apple is legally able, without the 223 + payment of a fee or royalty, to resume use, reproduction, 224 + modification, sublicensing and distribution of the Affected Original 225 + Code, Apple will lift the suspension of rights to the Affected 226 + Original Code by posting a notice to such effect on the Apple web site 227 + that is used for implementation of this License. If Apple suspends 228 + Your rights to Affected Original Code, nothing in this License shall 229 + be construed to restrict You, at Your option and subject to applicable 230 + law, from replacing the Affected Original Code with non-infringing 231 + code or independently negotiating for necessary rights from such third 232 + party. 233 + 234 + 9.2 LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES SHALL APPLE BE 235 + LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES 236 + ARISING OUT OF OR RELATING TO THIS LICENSE OR YOUR USE OR INABILITY TO 237 + USE THE ORIGINAL CODE, OR ANY PORTION THEREOF, WHETHER UNDER A THEORY 238 + OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY 239 + OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF 240 + SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF 241 + ANY REMEDY. In no event shall Apple's total liability to You for all 242 + damages under this License exceed the amount of fifty dollars 243 + ($50.00). 244 + 245 + 10. Trademarks. This License does not grant any rights to use the 246 + trademarks or trade names "Apple", "Apple Computer", "Mac OS X", "Mac 247 + OS X Server" or any other trademarks or trade names belonging to Apple 248 + (collectively "Apple Marks") and no Apple Marks may be used to endorse 249 + or promote products derived from the Original Code other than as 250 + permitted by and in strict compliance at all times with Apple's third 251 + party trademark usage guidelines which are posted at 252 + http://www.apple.com/legal/guidelinesfor3rdparties.html. 253 + 254 + 11. Ownership. Apple retains all rights, title and interest in and to 255 + the Original Code and any Modifications made by or on behalf of Apple 256 + ("Apple Modifications"), and such Apple Modifications will not be 257 + automatically subject to this License. Apple may, at its sole 258 + discretion, choose to license such Apple Modifications under this 259 + License, or on different terms from those contained in this License or 260 + may choose not to license them at all. Apple's development, use, 261 + reproduction, modification, sublicensing and distribution of Covered 262 + Code will not be subject to this License. 263 + 264 + 12. Termination. 265 + 266 + 12.1 Termination. This License and the rights granted hereunder will 267 + terminate: 268 + 269 + (a) automatically without notice from Apple if You fail to comply with 270 + any term(s) of this License and fail to cure such breach within 30 271 + days of becoming aware of such breach; (b) immediately in the event of 272 + the circumstances described in Section 13.5(b); or (c) automatically 273 + without notice from Apple if You, at any time during the term of this 274 + License, commence an action for patent infringement against Apple. 275 + 276 + 12.2 Effect of Termination. Upon termination, You agree to 277 + immediately stop any further use, reproduction, modification, 278 + sublicensing and distribution of the Covered Code and to destroy all 279 + copies of the Covered Code that are in your possession or control. 280 + All sublicenses to the Covered Code which have been properly granted 281 + prior to termination shall survive any termination of this License. 282 + Provisions which, by their nature, should remain in effect beyond the 283 + termination of this License shall survive, including but not limited 284 + to Sections 3, 5, 8, 9, 10, 11, 12.2 and 13. Neither party will be 285 + liable to the other for compensation, indemnity or damages of any sort 286 + solely as a result of terminating this License in accordance with its 287 + terms, and termination of this License will be without prejudice to 288 + any other right or remedy of either party. 289 + 290 + 13. Miscellaneous. 291 + 292 + 13.1 Government End Users. The Covered Code is a "commercial item" as 293 + defined in FAR 2.101. Government software and technical data rights 294 + in the Covered Code include only those rights customarily provided to 295 + the public as defined in this License. This customary commercial 296 + license in technical data and software is provided in accordance with 297 + FAR 12.211 (Technical Data) and 12.212 (Computer Software) and, for 298 + Department of Defense purchases, DFAR 252.227-7015 (Technical Data -- 299 + Commercial Items) and 227.7202-3 (Rights in Commercial Computer 300 + Software or Computer Software Documentation). Accordingly, all U.S. 301 + Government End Users acquire Covered Code with only those rights set 302 + forth herein. 303 + 304 + 13.2 Relationship of Parties. This License will not be construed as 305 + creating an agency, partnership, joint venture or any other form of 306 + legal association between You and Apple, and You will not represent to 307 + the contrary, whether expressly, by implication, appearance or 308 + otherwise. 309 + 310 + 13.3 Independent Development. Nothing in this License will impair 311 + Apple's right to acquire, license, develop, have others develop for 312 + it, market and/or distribute technology or products that perform the 313 + same or similar functions as, or otherwise compete with, 314 + Modifications, Larger Works, technology or products that You may 315 + develop, produce, market or distribute. 316 + 317 + 13.4 Waiver; Construction. Failure by Apple to enforce any provision 318 + of this License will not be deemed a waiver of future enforcement of 319 + that or any other provision. Any law or regulation which provides 320 + that the language of a contract shall be construed against the drafter 321 + will not apply to this License. 322 + 323 + 13.5 Severability. (a) If for any reason a court of competent 324 + jurisdiction finds any provision of this License, or portion thereof, 325 + to be unenforceable, that provision of the License will be enforced to 326 + the maximum extent permissible so as to effect the economic benefits 327 + and intent of the parties, and the remainder of this License will 328 + continue in full force and effect. (b) Notwithstanding the foregoing, 329 + if applicable law prohibits or restricts You from fully and/or 330 + specifically complying with Sections 2 and/or 3 or prevents the 331 + enforceability of either of those Sections, this License will 332 + immediately terminate and You must immediately discontinue any use of 333 + the Covered Code and destroy all copies of it that are in your 334 + possession or control. 335 + 336 + 13.6 Dispute Resolution. Any litigation or other dispute resolution 337 + between You and Apple relating to this License shall take place in the 338 + Northern District of California, and You and Apple hereby consent to 339 + the personal jurisdiction of, and venue in, the state and federal 340 + courts within that District with respect to this License. The 341 + application of the United Nations Convention on Contracts for the 342 + International Sale of Goods is expressly excluded. 343 + 344 + 13.7 Entire Agreement; Governing Law. This License constitutes the 345 + entire agreement between the parties with respect to the subject 346 + matter hereof. This License shall be governed by the laws of the 347 + United States and the State of California, except that body of 348 + California law concerning conflicts of law. 349 + 350 + Where You are located in the province of Quebec, Canada, the following 351 + clause applies: The parties hereby confirm that they have requested 352 + that this License and all related documents be drafted in English. Les 353 + parties ont exige que le present contrat et tous les documents 354 + connexes soient rediges en anglais. 355 + 356 + EXHIBIT A. 357 + 358 + "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights 359 + Reserved. This file contains Original Code and/or Modifications of 360 + Original Code as defined in and that are subject to the Apple Public 361 + Source License Version 1.1 (the "License"). You may not use this file 362 + except in compliance with the License. Please obtain a copy of the 363 + License at http://www.apple.com/publicsource and read it before using 364 + this file. 365 + 366 + The Original Code and all software distributed under the License are 367 + distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 368 + EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 369 + INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 370 + FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the 371 + License for the specific language governing rights and limitations 372 + under the License."
+698
libnotify/Libnotify.xcodeproj/project.pbxproj
··· 1 + // !$*UTF8*$! 2 + { 3 + archiveVersion = 1; 4 + classes = { 5 + }; 6 + objectVersion = 45; 7 + objects = { 8 + 9 + /* Begin PBXAggregateTarget section */ 10 + 3FA21AC7148AA93000099D2F /* cli_apps */ = { 11 + isa = PBXAggregateTarget; 12 + buildConfigurationList = 3FA21AC8148AA93000099D2F /* Build configuration list for PBXAggregateTarget "cli_apps" */; 13 + buildPhases = ( 14 + 3F947784191C32DC00A93E8E /* No Simulator Man Pages */, 15 + ); 16 + dependencies = ( 17 + 3FA21ACB148AA94A00099D2F /* PBXTargetDependency */, 18 + 3FA21ACD148AA94A00099D2F /* PBXTargetDependency */, 19 + ); 20 + name = cli_apps; 21 + productName = cli_apps; 22 + }; 23 + /* End PBXAggregateTarget section */ 24 + 25 + /* Begin PBXBuildFile section */ 26 + 2D312B76102CA2E300F90022 /* libnotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D312B73102CA2E300F90022 /* libnotify.c */; }; 27 + 2D312B77102CA2E300F90022 /* notify_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D312B74102CA2E300F90022 /* notify_client.c */; }; 28 + 2D312B78102CA2E300F90022 /* table.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D312B75102CA2E300F90022 /* table.c */; }; 29 + 2D312B7A102CA30200F90022 /* notify_ipc.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2D312B79102CA30200F90022 /* notify_ipc.defs */; settings = {ATTRIBUTES = (Client, ); }; }; 30 + 2D312B7E102CA32500F90022 /* notify_keys.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D312B7C102CA32500F90022 /* notify_keys.h */; settings = {ATTRIBUTES = (Public, ); }; }; 31 + 2D312B7F102CA32500F90022 /* notify.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D312B7D102CA32500F90022 /* notify.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32 + 2D312B82102CA34D00F90022 /* libnotify.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D312B81102CA34D00F90022 /* libnotify.h */; settings = {ATTRIBUTES = (Private, ); }; }; 33 + 2D312B87102CA36C00F90022 /* table.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D312B85102CA36C00F90022 /* table.h */; }; 34 + 2D38AA0A102CD88300D3D622 /* notify.3 in Copy man3 Files */ = {isa = PBXBuildFile; fileRef = 2D312B92102CA38F00F90022 /* notify.3 */; }; 35 + 2D38AA0B102CD89B00D3D622 /* notify_cancel.3 in Copy man3 Files */ = {isa = PBXBuildFile; fileRef = 2D312B88102CA38F00F90022 /* notify_cancel.3 */; }; 36 + 2D38AA0C102CD89B00D3D622 /* notify_check.3 in Copy man3 Files */ = {isa = PBXBuildFile; fileRef = 2D312B89102CA38F00F90022 /* notify_check.3 */; }; 37 + 2D38AA0D102CD8B800D3D622 /* notify_get_state.3 in Copy man3 Files */ = {isa = PBXBuildFile; fileRef = 2D312B8A102CA38F00F90022 /* notify_get_state.3 */; }; 38 + 2D38AA0E102CD8B800D3D622 /* notify_is_valid_token.3 in Copy man3 Files */ = {isa = PBXBuildFile; fileRef = 2D6D820D18DA602A0034E7B4 /* notify_is_valid_token.3 */; }; 39 + 2D38AA0F102CD8B800D3D622 /* notify_post.3 in Copy man3 Files */ = {isa = PBXBuildFile; fileRef = 2D312B8B102CA38F00F90022 /* notify_post.3 */; }; 40 + 2D38AA10102CD8B800D3D622 /* notify_register_check.3 in Copy man3 Files */ = {isa = PBXBuildFile; fileRef = 2D312B8C102CA38F00F90022 /* notify_register_check.3 */; }; 41 + 2D38AA11102CD8B800D3D622 /* notify_register_dispatch.3 in Copy man3 Files */ = {isa = PBXBuildFile; fileRef = 2D312B8D102CA38F00F90022 /* notify_register_dispatch.3 */; }; 42 + 2D38AA12102CD8B800D3D622 /* notify_register_file_descriptor.3 in Copy man3 Files */ = {isa = PBXBuildFile; fileRef = 2D312B8E102CA38F00F90022 /* notify_register_file_descriptor.3 */; }; 43 + 2D38AA13102CD8B800D3D622 /* notify_register_mach_port.3 in Copy man3 Files */ = {isa = PBXBuildFile; fileRef = 2D312B8F102CA38F00F90022 /* notify_register_mach_port.3 */; }; 44 + 2D38AA14102CD8B800D3D622 /* notify_register_signal.3 in Copy man3 Files */ = {isa = PBXBuildFile; fileRef = 2D312B90102CA38F00F90022 /* notify_register_signal.3 */; }; 45 + 2D38AA15102CD8B800D3D622 /* notify_set_state.3 in Copy man3 Files */ = {isa = PBXBuildFile; fileRef = 2D312B91102CA38F00F90022 /* notify_set_state.3 */; }; 46 + 2DCB287210D99ADA00DF3A8D /* notify_private.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DCB287110D99ADA00DF3A8D /* notify_private.h */; settings = {ATTRIBUTES = (Private, ); }; }; 47 + 3FA21ACF148AAA5000099D2F /* notify_proc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FA21A9C148AA7FA00099D2F /* notify_proc.c */; }; 48 + 3FA21AD0148AAA5000099D2F /* notifyd.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FA21A9E148AA7FA00099D2F /* notifyd.c */; }; 49 + 3FA21AD1148AAA5000099D2F /* pathwatch.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FA21AA0148AA7FA00099D2F /* pathwatch.c */; }; 50 + 3FA21AD2148AAA5000099D2F /* service.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FA21AA2148AA7FA00099D2F /* service.c */; }; 51 + 3FA21AD3148AAA5000099D2F /* timer.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FA21AA5148AA7FA00099D2F /* timer.c */; }; 52 + 3FA21AD4148AAA5D00099D2F /* notifyd.8 in Install man page */ = {isa = PBXBuildFile; fileRef = 3FA21A9D148AA7FA00099D2F /* notifyd.8 */; }; 53 + 3FA21AD5148AAA6E00099D2F /* notifyutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FA21AA9148AA82700099D2F /* notifyutil.c */; }; 54 + 3FA21AD6148AAA7500099D2F /* notifyutil.1 in Install man page */ = {isa = PBXBuildFile; fileRef = 3FA21AA8148AA82700099D2F /* notifyutil.1 */; }; 55 + 3FA21AD8148AAABE00099D2F /* com.apple.notifyd.plist in Install launchd.plist */ = {isa = PBXBuildFile; fileRef = 3FA21A99148AA7FA00099D2F /* com.apple.notifyd.plist */; }; 56 + 3FA21AE6148AAEAC00099D2F /* notify_ipc.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2D312B79102CA30200F90022 /* notify_ipc.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; }; 57 + 3FD0DBAD148AB12000C50811 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3FD0DBAC148AB12000C50811 /* libbsm.dylib */; }; 58 + FC7B7A53155781930064D203 /* notify_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = FC7B7A52155781930064D203 /* notify_internal.h */; }; 59 + /* End PBXBuildFile section */ 60 + 61 + /* Begin PBXContainerItemProxy section */ 62 + 3FA21ACA148AA94A00099D2F /* PBXContainerItemProxy */ = { 63 + isa = PBXContainerItemProxy; 64 + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; 65 + proxyType = 1; 66 + remoteGlobalIDString = 3FA21AAF148AA8E300099D2F; 67 + remoteInfo = notifyd; 68 + }; 69 + 3FA21ACC148AA94A00099D2F /* PBXContainerItemProxy */ = { 70 + isa = PBXContainerItemProxy; 71 + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; 72 + proxyType = 1; 73 + remoteGlobalIDString = 3FA21ABD148AA8F000099D2F; 74 + remoteInfo = notifyutil; 75 + }; 76 + /* End PBXContainerItemProxy section */ 77 + 78 + /* Begin PBXCopyFilesBuildPhase section */ 79 + 2D38AA09102CD87C00D3D622 /* Copy man3 Files */ = { 80 + isa = PBXCopyFilesBuildPhase; 81 + buildActionMask = 8; 82 + dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man3"; 83 + dstSubfolderSpec = 0; 84 + files = ( 85 + 2D38AA0A102CD88300D3D622 /* notify.3 in Copy man3 Files */, 86 + 2D38AA0B102CD89B00D3D622 /* notify_cancel.3 in Copy man3 Files */, 87 + 2D38AA0C102CD89B00D3D622 /* notify_check.3 in Copy man3 Files */, 88 + 2D38AA0D102CD8B800D3D622 /* notify_get_state.3 in Copy man3 Files */, 89 + 2D38AA0E102CD8B800D3D622 /* notify_is_valid_token.3 in Copy man3 Files */, 90 + 2D38AA0F102CD8B800D3D622 /* notify_post.3 in Copy man3 Files */, 91 + 2D38AA10102CD8B800D3D622 /* notify_register_check.3 in Copy man3 Files */, 92 + 2D38AA11102CD8B800D3D622 /* notify_register_dispatch.3 in Copy man3 Files */, 93 + 2D38AA12102CD8B800D3D622 /* notify_register_file_descriptor.3 in Copy man3 Files */, 94 + 2D38AA13102CD8B800D3D622 /* notify_register_mach_port.3 in Copy man3 Files */, 95 + 2D38AA14102CD8B800D3D622 /* notify_register_signal.3 in Copy man3 Files */, 96 + 2D38AA15102CD8B800D3D622 /* notify_set_state.3 in Copy man3 Files */, 97 + ); 98 + name = "Copy man3 Files"; 99 + runOnlyForDeploymentPostprocessing = 1; 100 + }; 101 + 3FA21AAE148AA8E300099D2F /* Install man page */ = { 102 + isa = PBXCopyFilesBuildPhase; 103 + buildActionMask = 2147483647; 104 + dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man8"; 105 + dstSubfolderSpec = 0; 106 + files = ( 107 + 3FA21AD4148AAA5D00099D2F /* notifyd.8 in Install man page */, 108 + ); 109 + name = "Install man page"; 110 + runOnlyForDeploymentPostprocessing = 1; 111 + }; 112 + 3FA21ABC148AA8F000099D2F /* Install man page */ = { 113 + isa = PBXCopyFilesBuildPhase; 114 + buildActionMask = 2147483647; 115 + dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man1"; 116 + dstSubfolderSpec = 0; 117 + files = ( 118 + 3FA21AD6148AAA7500099D2F /* notifyutil.1 in Install man page */, 119 + ); 120 + name = "Install man page"; 121 + runOnlyForDeploymentPostprocessing = 1; 122 + }; 123 + 3FA21AD7148AAAA600099D2F /* Install launchd.plist */ = { 124 + isa = PBXCopyFilesBuildPhase; 125 + buildActionMask = 8; 126 + dstPath = "$(INSTALL_PATH_PREFIX)/System/Library/LaunchDaemons"; 127 + dstSubfolderSpec = 0; 128 + files = ( 129 + 3FA21AD8148AAABE00099D2F /* com.apple.notifyd.plist in Install launchd.plist */, 130 + ); 131 + name = "Install launchd.plist"; 132 + runOnlyForDeploymentPostprocessing = 1; 133 + }; 134 + /* End PBXCopyFilesBuildPhase section */ 135 + 136 + /* Begin PBXFileReference section */ 137 + 2D312B73102CA2E300F90022 /* libnotify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = libnotify.c; sourceTree = "<group>"; }; 138 + 2D312B74102CA2E300F90022 /* notify_client.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = notify_client.c; sourceTree = "<group>"; }; 139 + 2D312B75102CA2E300F90022 /* table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = table.c; sourceTree = "<group>"; }; 140 + 2D312B79102CA30200F90022 /* notify_ipc.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = notify_ipc.defs; sourceTree = "<group>"; }; 141 + 2D312B7C102CA32500F90022 /* notify_keys.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; path = notify_keys.h; sourceTree = "<group>"; }; 142 + 2D312B7D102CA32500F90022 /* notify.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = notify.h; sourceTree = "<group>"; }; 143 + 2D312B81102CA34D00F90022 /* libnotify.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libnotify.h; sourceTree = "<group>"; }; 144 + 2D312B84102CA36C00F90022 /* notify_ipc_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = notify_ipc_types.h; sourceTree = "<group>"; }; 145 + 2D312B85102CA36C00F90022 /* table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = table.h; sourceTree = "<group>"; }; 146 + 2D312B88102CA38F00F90022 /* notify_cancel.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = notify_cancel.3; sourceTree = "<group>"; }; 147 + 2D312B89102CA38F00F90022 /* notify_check.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = notify_check.3; sourceTree = "<group>"; }; 148 + 2D312B8A102CA38F00F90022 /* notify_get_state.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = notify_get_state.3; sourceTree = "<group>"; }; 149 + 2D312B8B102CA38F00F90022 /* notify_post.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = notify_post.3; sourceTree = "<group>"; }; 150 + 2D312B8C102CA38F00F90022 /* notify_register_check.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = notify_register_check.3; sourceTree = "<group>"; }; 151 + 2D312B8D102CA38F00F90022 /* notify_register_dispatch.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = notify_register_dispatch.3; sourceTree = "<group>"; }; 152 + 2D312B8E102CA38F00F90022 /* notify_register_file_descriptor.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = notify_register_file_descriptor.3; sourceTree = "<group>"; }; 153 + 2D312B8F102CA38F00F90022 /* notify_register_mach_port.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = notify_register_mach_port.3; sourceTree = "<group>"; }; 154 + 2D312B90102CA38F00F90022 /* notify_register_signal.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = notify_register_signal.3; sourceTree = "<group>"; }; 155 + 2D312B91102CA38F00F90022 /* notify_set_state.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = notify_set_state.3; sourceTree = "<group>"; }; 156 + 2D312B92102CA38F00F90022 /* notify.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = notify.3; sourceTree = "<group>"; }; 157 + 2D6D820D18DA602A0034E7B4 /* notify_is_valid_token.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = notify_is_valid_token.3; sourceTree = "<group>"; }; 158 + 2DCB287110D99ADA00DF3A8D /* notify_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = notify_private.h; sourceTree = "<group>"; }; 159 + 2DF9EA0B102CF33400DE9E8D /* APPLE_LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = APPLE_LICENSE; sourceTree = "<group>"; }; 160 + 3F82235D12B18551005DD509 /* libnotify.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = libnotify.xcconfig; sourceTree = "<group>"; }; 161 + 3F8223B412B18877005DD509 /* libsystem_notify.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsystem_notify.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 162 + 3F947780191C322100A93E8E /* no-sim-man.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "no-sim-man.sh"; sourceTree = "<group>"; }; 163 + 3F947781191C322100A93E8E /* sim-compat-symlink.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "sim-compat-symlink.sh"; sourceTree = "<group>"; }; 164 + 3F999961185C474E00EAD3A0 /* base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = base.xcconfig; sourceTree = "<group>"; }; 165 + 3F999963185C474E00EAD3A0 /* notifyd.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = notifyd.xcconfig; sourceTree = "<group>"; }; 166 + 3F999964185C474E00EAD3A0 /* notifyutil.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = notifyutil.xcconfig; sourceTree = "<group>"; }; 167 + 3FA21A99148AA7FA00099D2F /* com.apple.notifyd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.notifyd.plist; sourceTree = "<group>"; }; 168 + 3FA21A9A148AA7FA00099D2F /* notify.conf */ = {isa = PBXFileReference; lastKnownFileType = text; path = notify.conf; sourceTree = "<group>"; }; 169 + 3FA21A9B148AA7FA00099D2F /* notify.conf.iPhone */ = {isa = PBXFileReference; lastKnownFileType = text; name = notify.conf.iPhone; path = ../notify.conf.iPhone; sourceTree = "<group>"; }; 170 + 3FA21A9C148AA7FA00099D2F /* notify_proc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = notify_proc.c; sourceTree = "<group>"; }; 171 + 3FA21A9D148AA7FA00099D2F /* notifyd.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = notifyd.8; sourceTree = "<group>"; }; 172 + 3FA21A9E148AA7FA00099D2F /* notifyd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = notifyd.c; sourceTree = "<group>"; }; 173 + 3FA21A9F148AA7FA00099D2F /* notifyd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = notifyd.h; sourceTree = "<group>"; }; 174 + 3FA21AA0148AA7FA00099D2F /* pathwatch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pathwatch.c; sourceTree = "<group>"; }; 175 + 3FA21AA1148AA7FA00099D2F /* pathwatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathwatch.h; sourceTree = "<group>"; }; 176 + 3FA21AA2148AA7FA00099D2F /* service.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = service.c; sourceTree = "<group>"; }; 177 + 3FA21AA3148AA7FA00099D2F /* service.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = service.h; sourceTree = "<group>"; }; 178 + 3FA21AA4148AA7FA00099D2F /* table.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = table.h; sourceTree = "<group>"; }; 179 + 3FA21AA5148AA7FA00099D2F /* timer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = timer.c; sourceTree = "<group>"; }; 180 + 3FA21AA6148AA7FA00099D2F /* timer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = timer.h; sourceTree = "<group>"; }; 181 + 3FA21AA8148AA82700099D2F /* notifyutil.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = notifyutil.1; sourceTree = "<group>"; }; 182 + 3FA21AA9148AA82700099D2F /* notifyutil.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = notifyutil.c; sourceTree = "<group>"; }; 183 + 3FA21AB0148AA8E300099D2F /* notifyd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = notifyd; sourceTree = BUILT_PRODUCTS_DIR; }; 184 + 3FA21ABE148AA8F000099D2F /* notifyutil */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = notifyutil; sourceTree = BUILT_PRODUCTS_DIR; }; 185 + 3FA21ADD148AABA900099D2F /* mk_notify_conf.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = mk_notify_conf.sh; sourceTree = "<group>"; }; 186 + 3FA21ADF148AACA000099D2F /* notify.conf.MacOSX */ = {isa = PBXFileReference; lastKnownFileType = text; name = notify.conf.MacOSX; path = notifyd/notify.conf.MacOSX; sourceTree = SOURCE_ROOT; }; 187 + 3FD0DBAC148AB12000C50811 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = /usr/lib/libbsm.dylib; sourceTree = "<absolute>"; }; 188 + FC7B7A52155781930064D203 /* notify_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = notify_internal.h; sourceTree = "<group>"; }; 189 + /* End PBXFileReference section */ 190 + 191 + /* Begin PBXFrameworksBuildPhase section */ 192 + 3FA21AAD148AA8E300099D2F /* Frameworks */ = { 193 + isa = PBXFrameworksBuildPhase; 194 + buildActionMask = 2147483647; 195 + files = ( 196 + 3FD0DBAD148AB12000C50811 /* libbsm.dylib in Frameworks */, 197 + ); 198 + runOnlyForDeploymentPostprocessing = 0; 199 + }; 200 + 3FA21ABB148AA8F000099D2F /* Frameworks */ = { 201 + isa = PBXFrameworksBuildPhase; 202 + buildActionMask = 2147483647; 203 + files = ( 204 + ); 205 + runOnlyForDeploymentPostprocessing = 0; 206 + }; 207 + D289987405E68DCB004EDB86 /* Frameworks */ = { 208 + isa = PBXFrameworksBuildPhase; 209 + buildActionMask = 2147483647; 210 + files = ( 211 + ); 212 + runOnlyForDeploymentPostprocessing = 0; 213 + }; 214 + /* End PBXFrameworksBuildPhase section */ 215 + 216 + /* Begin PBXGroup section */ 217 + 08FB7794FE84155DC02AAC07 /* Libnotify */ = { 218 + isa = PBXGroup; 219 + children = ( 220 + 3F94777F191C322100A93E8E /* xcodescripts */, 221 + 3F999960185C474E00EAD3A0 /* xcodeconfig */, 222 + 2D312B79102CA30200F90022 /* notify_ipc.defs */, 223 + 3FA21A97148AA7CD00099D2F /* libsystem_notify */, 224 + 3FA21AA7148AA82700099D2F /* notifyutil */, 225 + 3FA21A98148AA7FA00099D2F /* notifyd */, 226 + 2DF9EA0A102CF31700DE9E8D /* Additional Files */, 227 + 3FA21ACE148AAA0D00099D2F /* Products */, 228 + ); 229 + name = Libnotify; 230 + sourceTree = "<group>"; 231 + }; 232 + 2D312B72102CA2C400F90022 /* Source */ = { 233 + isa = PBXGroup; 234 + children = ( 235 + 2D312B73102CA2E300F90022 /* libnotify.c */, 236 + 2D312B74102CA2E300F90022 /* notify_client.c */, 237 + 2D312B75102CA2E300F90022 /* table.c */, 238 + ); 239 + name = Source; 240 + sourceTree = "<group>"; 241 + }; 242 + 2D312B7B102CA30600F90022 /* Public Headers */ = { 243 + isa = PBXGroup; 244 + children = ( 245 + 2D312B7C102CA32500F90022 /* notify_keys.h */, 246 + 2D312B7D102CA32500F90022 /* notify.h */, 247 + ); 248 + name = "Public Headers"; 249 + sourceTree = "<group>"; 250 + }; 251 + 2D312B80102CA33600F90022 /* Private Headers */ = { 252 + isa = PBXGroup; 253 + children = ( 254 + 2DCB287110D99ADA00DF3A8D /* notify_private.h */, 255 + 2D312B81102CA34D00F90022 /* libnotify.h */, 256 + ); 257 + name = "Private Headers"; 258 + sourceTree = "<group>"; 259 + }; 260 + 2D312B83102CA35300F90022 /* Project Headers */ = { 261 + isa = PBXGroup; 262 + children = ( 263 + FC7B7A52155781930064D203 /* notify_internal.h */, 264 + 2D312B84102CA36C00F90022 /* notify_ipc_types.h */, 265 + 2D312B85102CA36C00F90022 /* table.h */, 266 + ); 267 + name = "Project Headers"; 268 + sourceTree = "<group>"; 269 + }; 270 + 2DF9EA0A102CF31700DE9E8D /* Additional Files */ = { 271 + isa = PBXGroup; 272 + children = ( 273 + 2DF9EA0B102CF33400DE9E8D /* APPLE_LICENSE */, 274 + ); 275 + name = "Additional Files"; 276 + sourceTree = "<group>"; 277 + }; 278 + 3F94777F191C322100A93E8E /* xcodescripts */ = { 279 + isa = PBXGroup; 280 + children = ( 281 + 3F947780191C322100A93E8E /* no-sim-man.sh */, 282 + 3F947781191C322100A93E8E /* sim-compat-symlink.sh */, 283 + ); 284 + path = xcodescripts; 285 + sourceTree = "<group>"; 286 + }; 287 + 3F999960185C474E00EAD3A0 /* xcodeconfig */ = { 288 + isa = PBXGroup; 289 + children = ( 290 + 3F999961185C474E00EAD3A0 /* base.xcconfig */, 291 + 3F82235D12B18551005DD509 /* libnotify.xcconfig */, 292 + 3F999963185C474E00EAD3A0 /* notifyd.xcconfig */, 293 + 3F999964185C474E00EAD3A0 /* notifyutil.xcconfig */, 294 + ); 295 + path = xcodeconfig; 296 + sourceTree = "<group>"; 297 + }; 298 + 3FA21A97148AA7CD00099D2F /* libsystem_notify */ = { 299 + isa = PBXGroup; 300 + children = ( 301 + 2D312B83102CA35300F90022 /* Project Headers */, 302 + 2D312B80102CA33600F90022 /* Private Headers */, 303 + 2D312B7B102CA30600F90022 /* Public Headers */, 304 + 2D312B72102CA2C400F90022 /* Source */, 305 + C6A0FF2B0290797F04C91782 /* Documentation */, 306 + ); 307 + name = libsystem_notify; 308 + sourceTree = "<group>"; 309 + }; 310 + 3FA21A98148AA7FA00099D2F /* notifyd */ = { 311 + isa = PBXGroup; 312 + children = ( 313 + 3FA21ADC148AABA900099D2F /* Build Support */, 314 + 3FA21A99148AA7FA00099D2F /* com.apple.notifyd.plist */, 315 + 3FA21A9A148AA7FA00099D2F /* notify.conf */, 316 + 3FA21AAA148AA85300099D2F /* Source */, 317 + 3FA21A9D148AA7FA00099D2F /* notifyd.8 */, 318 + 3FA21AAB148AA86600099D2F /* Private Headers */, 319 + ); 320 + path = notifyd; 321 + sourceTree = "<group>"; 322 + }; 323 + 3FA21AA7148AA82700099D2F /* notifyutil */ = { 324 + isa = PBXGroup; 325 + children = ( 326 + 3FA21AA8148AA82700099D2F /* notifyutil.1 */, 327 + 3FA21AA9148AA82700099D2F /* notifyutil.c */, 328 + ); 329 + path = notifyutil; 330 + sourceTree = "<group>"; 331 + }; 332 + 3FA21AAA148AA85300099D2F /* Source */ = { 333 + isa = PBXGroup; 334 + children = ( 335 + 3FA21A9C148AA7FA00099D2F /* notify_proc.c */, 336 + 3FA21A9E148AA7FA00099D2F /* notifyd.c */, 337 + 3FA21AA0148AA7FA00099D2F /* pathwatch.c */, 338 + 3FA21AA2148AA7FA00099D2F /* service.c */, 339 + 3FA21AA5148AA7FA00099D2F /* timer.c */, 340 + ); 341 + name = Source; 342 + sourceTree = "<group>"; 343 + }; 344 + 3FA21AAB148AA86600099D2F /* Private Headers */ = { 345 + isa = PBXGroup; 346 + children = ( 347 + 3FA21A9F148AA7FA00099D2F /* notifyd.h */, 348 + 3FA21AA1148AA7FA00099D2F /* pathwatch.h */, 349 + 3FA21AA3148AA7FA00099D2F /* service.h */, 350 + 3FA21AA4148AA7FA00099D2F /* table.h */, 351 + 3FA21AA6148AA7FA00099D2F /* timer.h */, 352 + ); 353 + name = "Private Headers"; 354 + sourceTree = "<group>"; 355 + }; 356 + 3FA21ACE148AAA0D00099D2F /* Products */ = { 357 + isa = PBXGroup; 358 + children = ( 359 + 3F8223B412B18877005DD509 /* libsystem_notify.dylib */, 360 + 3FA21AB0148AA8E300099D2F /* notifyd */, 361 + 3FA21ABE148AA8F000099D2F /* notifyutil */, 362 + ); 363 + name = Products; 364 + sourceTree = "<group>"; 365 + }; 366 + 3FA21ADC148AABA900099D2F /* Build Support */ = { 367 + isa = PBXGroup; 368 + children = ( 369 + 3FD0DBAC148AB12000C50811 /* libbsm.dylib */, 370 + 3FA21ADF148AACA000099D2F /* notify.conf.MacOSX */, 371 + 3FA21A9B148AA7FA00099D2F /* notify.conf.iPhone */, 372 + 3FA21ADD148AABA900099D2F /* mk_notify_conf.sh */, 373 + ); 374 + name = "Build Support"; 375 + path = xcodescripts; 376 + sourceTree = "<group>"; 377 + }; 378 + C6A0FF2B0290797F04C91782 /* Documentation */ = { 379 + isa = PBXGroup; 380 + children = ( 381 + 2D312B88102CA38F00F90022 /* notify_cancel.3 */, 382 + 2D312B89102CA38F00F90022 /* notify_check.3 */, 383 + 2D312B8A102CA38F00F90022 /* notify_get_state.3 */, 384 + 2D6D820D18DA602A0034E7B4 /* notify_is_valid_token.3 */, 385 + 2D312B8B102CA38F00F90022 /* notify_post.3 */, 386 + 2D312B8C102CA38F00F90022 /* notify_register_check.3 */, 387 + 2D312B8D102CA38F00F90022 /* notify_register_dispatch.3 */, 388 + 2D312B8E102CA38F00F90022 /* notify_register_file_descriptor.3 */, 389 + 2D312B8F102CA38F00F90022 /* notify_register_mach_port.3 */, 390 + 2D312B90102CA38F00F90022 /* notify_register_signal.3 */, 391 + 2D312B91102CA38F00F90022 /* notify_set_state.3 */, 392 + 2D312B92102CA38F00F90022 /* notify.3 */, 393 + ); 394 + name = Documentation; 395 + sourceTree = "<group>"; 396 + }; 397 + /* End PBXGroup section */ 398 + 399 + /* Begin PBXHeadersBuildPhase section */ 400 + D2AAC043055464E500DB518D /* Headers */ = { 401 + isa = PBXHeadersBuildPhase; 402 + buildActionMask = 2147483647; 403 + files = ( 404 + 2D312B7E102CA32500F90022 /* notify_keys.h in Headers */, 405 + 2D312B7F102CA32500F90022 /* notify.h in Headers */, 406 + 2D312B82102CA34D00F90022 /* libnotify.h in Headers */, 407 + 2D312B87102CA36C00F90022 /* table.h in Headers */, 408 + 2DCB287210D99ADA00DF3A8D /* notify_private.h in Headers */, 409 + FC7B7A53155781930064D203 /* notify_internal.h in Headers */, 410 + ); 411 + runOnlyForDeploymentPostprocessing = 0; 412 + }; 413 + /* End PBXHeadersBuildPhase section */ 414 + 415 + /* Begin PBXNativeTarget section */ 416 + 3FA21AAF148AA8E300099D2F /* notifyd */ = { 417 + isa = PBXNativeTarget; 418 + buildConfigurationList = 3FA21AB8148AA8E300099D2F /* Build configuration list for PBXNativeTarget "notifyd" */; 419 + buildPhases = ( 420 + 3FA21AAC148AA8E300099D2F /* Sources */, 421 + 3FA21AAD148AA8E300099D2F /* Frameworks */, 422 + 3FA21AAE148AA8E300099D2F /* Install man page */, 423 + 3FA21AD7148AAAA600099D2F /* Install launchd.plist */, 424 + 3FA21ADB148AAB1C00099D2F /* Install notify.conf */, 425 + ); 426 + buildRules = ( 427 + ); 428 + dependencies = ( 429 + ); 430 + name = notifyd; 431 + productName = notifyd; 432 + productReference = 3FA21AB0148AA8E300099D2F /* notifyd */; 433 + productType = "com.apple.product-type.tool"; 434 + }; 435 + 3FA21ABD148AA8F000099D2F /* notifyutil */ = { 436 + isa = PBXNativeTarget; 437 + buildConfigurationList = 3FA21AC5148AA8F000099D2F /* Build configuration list for PBXNativeTarget "notifyutil" */; 438 + buildPhases = ( 439 + 3FA21ABA148AA8F000099D2F /* Sources */, 440 + 3FA21ABB148AA8F000099D2F /* Frameworks */, 441 + 3FA21ABC148AA8F000099D2F /* Install man page */, 442 + ); 443 + buildRules = ( 444 + ); 445 + dependencies = ( 446 + ); 447 + name = notifyutil; 448 + productName = notifyutil; 449 + productReference = 3FA21ABE148AA8F000099D2F /* notifyutil */; 450 + productType = "com.apple.product-type.tool"; 451 + }; 452 + D2AAC045055464E500DB518D /* libnotify */ = { 453 + isa = PBXNativeTarget; 454 + buildConfigurationList = 1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "libnotify" */; 455 + buildPhases = ( 456 + D2AAC043055464E500DB518D /* Headers */, 457 + D2AAC044055464E500DB518D /* Sources */, 458 + D289987405E68DCB004EDB86 /* Frameworks */, 459 + 2D38AA09102CD87C00D3D622 /* Copy man3 Files */, 460 + 3F947782191C324900A93E8E /* No Simulator Man Pages */, 461 + 3F947783191C327700A93E8E /* Sim compat symlink */, 462 + ); 463 + buildRules = ( 464 + ); 465 + dependencies = ( 466 + ); 467 + name = libnotify; 468 + productName = Libnotify; 469 + productReference = 3F8223B412B18877005DD509 /* libsystem_notify.dylib */; 470 + productType = "com.apple.product-type.library.dynamic"; 471 + }; 472 + /* End PBXNativeTarget section */ 473 + 474 + /* Begin PBXProject section */ 475 + 08FB7793FE84155DC02AAC07 /* Project object */ = { 476 + isa = PBXProject; 477 + attributes = { 478 + }; 479 + buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "Libnotify" */; 480 + compatibilityVersion = "Xcode 3.1"; 481 + developmentRegion = English; 482 + hasScannedForEncodings = 1; 483 + knownRegions = ( 484 + English, 485 + Japanese, 486 + French, 487 + German, 488 + ); 489 + mainGroup = 08FB7794FE84155DC02AAC07 /* Libnotify */; 490 + productRefGroup = 08FB7794FE84155DC02AAC07 /* Libnotify */; 491 + projectDirPath = ""; 492 + projectRoot = ""; 493 + targets = ( 494 + D2AAC045055464E500DB518D /* libnotify */, 495 + 3FA21AAF148AA8E300099D2F /* notifyd */, 496 + 3FA21ABD148AA8F000099D2F /* notifyutil */, 497 + 3FA21AC7148AA93000099D2F /* cli_apps */, 498 + ); 499 + }; 500 + /* End PBXProject section */ 501 + 502 + /* Begin PBXShellScriptBuildPhase section */ 503 + 3F947782191C324900A93E8E /* No Simulator Man Pages */ = { 504 + isa = PBXShellScriptBuildPhase; 505 + buildActionMask = 8; 506 + files = ( 507 + ); 508 + inputPaths = ( 509 + "$(SRCROOT)/xcodescripts/no-sim-man.sh", 510 + ); 511 + name = "No Simulator Man Pages"; 512 + outputPaths = ( 513 + ); 514 + runOnlyForDeploymentPostprocessing = 1; 515 + shellPath = "/bin/bash -e -x"; 516 + shellScript = "exec \"${SCRIPT_INPUT_FILE_0}\""; 517 + }; 518 + 3F947783191C327700A93E8E /* Sim compat symlink */ = { 519 + isa = PBXShellScriptBuildPhase; 520 + buildActionMask = 8; 521 + files = ( 522 + ); 523 + inputPaths = ( 524 + "$(SRCROOT)/xcodescripts/sim-compat-symlink.sh", 525 + ); 526 + name = "Sim compat symlink"; 527 + outputPaths = ( 528 + ); 529 + runOnlyForDeploymentPostprocessing = 1; 530 + shellPath = "/bin/bash -e -x"; 531 + shellScript = "exec \"${SCRIPT_INPUT_FILE_0}\""; 532 + }; 533 + 3F947784191C32DC00A93E8E /* No Simulator Man Pages */ = { 534 + isa = PBXShellScriptBuildPhase; 535 + buildActionMask = 8; 536 + files = ( 537 + ); 538 + inputPaths = ( 539 + "$(SRCROOT)/xcodescripts/no-sim-man.sh", 540 + ); 541 + name = "No Simulator Man Pages"; 542 + outputPaths = ( 543 + ); 544 + runOnlyForDeploymentPostprocessing = 1; 545 + shellPath = "/bin/bash -e -x"; 546 + shellScript = "exec \"${SCRIPT_INPUT_FILE_0}\""; 547 + }; 548 + 3FA21ADB148AAB1C00099D2F /* Install notify.conf */ = { 549 + isa = PBXShellScriptBuildPhase; 550 + buildActionMask = 8; 551 + files = ( 552 + ); 553 + inputPaths = ( 554 + "$(SRCROOT)/notifyd/xcodescripts/mk_notify_conf.sh", 555 + ); 556 + name = "Install notify.conf"; 557 + outputPaths = ( 558 + ); 559 + runOnlyForDeploymentPostprocessing = 1; 560 + shellPath = "/bin/bash -e -x"; 561 + shellScript = "exec \"${SCRIPT_INPUT_FILE_0}\""; 562 + }; 563 + /* End PBXShellScriptBuildPhase section */ 564 + 565 + /* Begin PBXSourcesBuildPhase section */ 566 + 3FA21AAC148AA8E300099D2F /* Sources */ = { 567 + isa = PBXSourcesBuildPhase; 568 + buildActionMask = 2147483647; 569 + files = ( 570 + 3FA21AE6148AAEAC00099D2F /* notify_ipc.defs in Sources */, 571 + 3FA21ACF148AAA5000099D2F /* notify_proc.c in Sources */, 572 + 3FA21AD0148AAA5000099D2F /* notifyd.c in Sources */, 573 + 3FA21AD1148AAA5000099D2F /* pathwatch.c in Sources */, 574 + 3FA21AD2148AAA5000099D2F /* service.c in Sources */, 575 + 3FA21AD3148AAA5000099D2F /* timer.c in Sources */, 576 + ); 577 + runOnlyForDeploymentPostprocessing = 0; 578 + }; 579 + 3FA21ABA148AA8F000099D2F /* Sources */ = { 580 + isa = PBXSourcesBuildPhase; 581 + buildActionMask = 2147483647; 582 + files = ( 583 + 3FA21AD5148AAA6E00099D2F /* notifyutil.c in Sources */, 584 + ); 585 + runOnlyForDeploymentPostprocessing = 0; 586 + }; 587 + D2AAC044055464E500DB518D /* Sources */ = { 588 + isa = PBXSourcesBuildPhase; 589 + buildActionMask = 2147483647; 590 + files = ( 591 + 2D312B7A102CA30200F90022 /* notify_ipc.defs in Sources */, 592 + 2D312B76102CA2E300F90022 /* libnotify.c in Sources */, 593 + 2D312B77102CA2E300F90022 /* notify_client.c in Sources */, 594 + 2D312B78102CA2E300F90022 /* table.c in Sources */, 595 + ); 596 + runOnlyForDeploymentPostprocessing = 0; 597 + }; 598 + /* End PBXSourcesBuildPhase section */ 599 + 600 + /* Begin PBXTargetDependency section */ 601 + 3FA21ACB148AA94A00099D2F /* PBXTargetDependency */ = { 602 + isa = PBXTargetDependency; 603 + target = 3FA21AAF148AA8E300099D2F /* notifyd */; 604 + targetProxy = 3FA21ACA148AA94A00099D2F /* PBXContainerItemProxy */; 605 + }; 606 + 3FA21ACD148AA94A00099D2F /* PBXTargetDependency */ = { 607 + isa = PBXTargetDependency; 608 + target = 3FA21ABD148AA8F000099D2F /* notifyutil */; 609 + targetProxy = 3FA21ACC148AA94A00099D2F /* PBXContainerItemProxy */; 610 + }; 611 + /* End PBXTargetDependency section */ 612 + 613 + /* Begin XCBuildConfiguration section */ 614 + 1DEB91ED08733DB70010E9CD /* Release */ = { 615 + isa = XCBuildConfiguration; 616 + baseConfigurationReference = 3F82235D12B18551005DD509 /* libnotify.xcconfig */; 617 + buildSettings = { 618 + }; 619 + name = Release; 620 + }; 621 + 1DEB91F108733DB70010E9CD /* Release */ = { 622 + isa = XCBuildConfiguration; 623 + buildSettings = { 624 + APPLY_RULES_IN_COPY_FILES = YES; 625 + }; 626 + name = Release; 627 + }; 628 + 3FA21AB9148AA8E300099D2F /* Release */ = { 629 + isa = XCBuildConfiguration; 630 + baseConfigurationReference = 3F999963185C474E00EAD3A0 /* notifyd.xcconfig */; 631 + buildSettings = { 632 + PRODUCT_NAME = "$(TARGET_NAME)"; 633 + }; 634 + name = Release; 635 + }; 636 + 3FA21AC6148AA8F000099D2F /* Release */ = { 637 + isa = XCBuildConfiguration; 638 + baseConfigurationReference = 3F999964185C474E00EAD3A0 /* notifyutil.xcconfig */; 639 + buildSettings = { 640 + PRODUCT_NAME = "$(TARGET_NAME)"; 641 + }; 642 + name = Release; 643 + }; 644 + 3FA21AC9148AA93000099D2F /* Release */ = { 645 + isa = XCBuildConfiguration; 646 + baseConfigurationReference = 3F999961185C474E00EAD3A0 /* base.xcconfig */; 647 + buildSettings = { 648 + PRODUCT_NAME = "$(TARGET_NAME)"; 649 + }; 650 + name = Release; 651 + }; 652 + /* End XCBuildConfiguration section */ 653 + 654 + /* Begin XCConfigurationList section */ 655 + 1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "libnotify" */ = { 656 + isa = XCConfigurationList; 657 + buildConfigurations = ( 658 + 1DEB91ED08733DB70010E9CD /* Release */, 659 + ); 660 + defaultConfigurationIsVisible = 0; 661 + defaultConfigurationName = Release; 662 + }; 663 + 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "Libnotify" */ = { 664 + isa = XCConfigurationList; 665 + buildConfigurations = ( 666 + 1DEB91F108733DB70010E9CD /* Release */, 667 + ); 668 + defaultConfigurationIsVisible = 0; 669 + defaultConfigurationName = Release; 670 + }; 671 + 3FA21AB8148AA8E300099D2F /* Build configuration list for PBXNativeTarget "notifyd" */ = { 672 + isa = XCConfigurationList; 673 + buildConfigurations = ( 674 + 3FA21AB9148AA8E300099D2F /* Release */, 675 + ); 676 + defaultConfigurationIsVisible = 0; 677 + defaultConfigurationName = Release; 678 + }; 679 + 3FA21AC5148AA8F000099D2F /* Build configuration list for PBXNativeTarget "notifyutil" */ = { 680 + isa = XCConfigurationList; 681 + buildConfigurations = ( 682 + 3FA21AC6148AA8F000099D2F /* Release */, 683 + ); 684 + defaultConfigurationIsVisible = 0; 685 + defaultConfigurationName = Release; 686 + }; 687 + 3FA21AC8148AA93000099D2F /* Build configuration list for PBXAggregateTarget "cli_apps" */ = { 688 + isa = XCConfigurationList; 689 + buildConfigurations = ( 690 + 3FA21AC9148AA93000099D2F /* Release */, 691 + ); 692 + defaultConfigurationIsVisible = 0; 693 + defaultConfigurationName = Release; 694 + }; 695 + /* End XCConfigurationList section */ 696 + }; 697 + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; 698 + }
+1544
libnotify/libnotify.c
··· 1 + /* 2 + * Copyright (c) 2003-2012 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #include <sys/types.h> 25 + #include <stdio.h> 26 + #include <fcntl.h> 27 + #include <stdlib.h> 28 + #include <unistd.h> 29 + #include <sys/socket.h> 30 + #include <netinet/in.h> 31 + #include <sys/un.h> 32 + #include <sys/ipc.h> 33 + #include <signal.h> 34 + #include <mach/mach.h> 35 + #include <mach/mach_time.h> 36 + #include <errno.h> 37 + #include <pthread.h> 38 + 39 + #include "libnotify.h" 40 + #include "notify.h" 41 + #include "notify_internal.h" 42 + 43 + #define USER_PROTECTED_UID_PREFIX "user.uid." 44 + #define USER_PROTECTED_UID_PREFIX_LEN 9 45 + 46 + uint64_t 47 + make_client_id(pid_t pid, int token) 48 + { 49 + uint64_t cid; 50 + 51 + cid = pid; 52 + cid <<= 32; 53 + cid |= token; 54 + 55 + return cid; 56 + } 57 + 58 + notify_state_t * 59 + _notify_lib_notify_state_new(uint32_t flags, uint32_t table_size) 60 + { 61 + notify_state_t *ns; 62 + 63 + ns = (notify_state_t *)calloc(1, sizeof(notify_state_t)); 64 + if (ns == NULL) return NULL; 65 + 66 + ns->flags = flags; 67 + ns->sock = -1; 68 + 69 + if (ns->flags & NOTIFY_STATE_USE_LOCKS) 70 + { 71 + ns->lock = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); 72 + if (ns->lock == NULL) 73 + { 74 + free(ns); 75 + return NULL; 76 + } 77 + 78 + pthread_mutex_init(ns->lock, NULL); 79 + } 80 + 81 + ns->name_table = _nc_table_new(table_size); 82 + ns->name_id_table = _nc_table_new(table_size); 83 + ns->client_table = _nc_table_new(table_size); 84 + ns->port_table = _nc_table_new(table_size); 85 + ns->proc_table = _nc_table_new(table_size); 86 + 87 + if ((ns->name_table == NULL) || (ns->name_id_table == NULL) || (ns->client_table == NULL) || (ns->port_table == NULL) || (ns->proc_table == NULL)) 88 + { 89 + free(ns->lock); 90 + _nc_table_free(ns->name_table); 91 + _nc_table_free(ns->name_id_table); 92 + _nc_table_free(ns->client_table); 93 + _nc_table_free(ns->port_table); 94 + _nc_table_free(ns->proc_table); 95 + free(ns); 96 + return NULL; 97 + } 98 + 99 + return ns; 100 + } 101 + 102 + void 103 + _notify_lib_notify_state_free(notify_state_t *ns) 104 + { 105 + if (ns == NULL) return; 106 + 107 + _nc_table_free(ns->name_table); 108 + _nc_table_free(ns->name_id_table); 109 + _nc_table_free(ns->client_table); 110 + _nc_table_free(ns->port_table); 111 + _nc_table_free(ns->proc_table); 112 + 113 + if (ns->lock != NULL) 114 + { 115 + pthread_mutex_destroy(ns->lock); 116 + free(ns->lock); 117 + } 118 + 119 + if (ns->sock != -1) 120 + { 121 + shutdown(ns->sock, 2); 122 + close(ns->sock); 123 + } 124 + 125 + if (ns->controlled_name != NULL) free(ns->controlled_name); 126 + } 127 + 128 + static client_t * 129 + _internal_client_new(notify_state_t *ns, pid_t pid, int token) 130 + { 131 + client_t *c; 132 + uint64_t cid = make_client_id(pid, token); 133 + 134 + if (ns == NULL) return NULL; 135 + 136 + /* detect duplicates - should never happen, but it would be bad */ 137 + c = _nc_table_find_64(ns->client_table, cid); 138 + if (c != NULL) return NULL; 139 + 140 + c = calloc(1, sizeof(client_t)); 141 + if (c == NULL) return NULL; 142 + 143 + ns->stat_client_alloc++; 144 + 145 + c->client_id = cid; 146 + c->pid = pid; 147 + c->send_val = token; 148 + 149 + _nc_table_insert_64(ns->client_table, cid, c); 150 + 151 + return c; 152 + } 153 + 154 + static void 155 + _internal_client_release(notify_state_t *ns, client_t *c) 156 + { 157 + uint64_t cid; 158 + 159 + if (ns == NULL) return; 160 + if (c == NULL) return; 161 + 162 + cid = c->client_id; 163 + _nc_table_delete_64(ns->client_table, cid); 164 + 165 + switch (c->notify_type) 166 + { 167 + case NOTIFY_TYPE_SIGNAL: 168 + { 169 + break; 170 + } 171 + case NOTIFY_TYPE_FILE: 172 + { 173 + if (c->fd > 0) close(c->fd); 174 + c->fd = -1; 175 + break; 176 + } 177 + case NOTIFY_TYPE_PORT: 178 + { 179 + if (c->port != MACH_PORT_NULL) 180 + { 181 + /* release my send right to the port */ 182 + mach_port_deallocate(mach_task_self(), c->port); 183 + } 184 + break; 185 + } 186 + default: 187 + { 188 + break; 189 + } 190 + } 191 + 192 + free(c); 193 + ns->stat_client_free++; 194 + } 195 + 196 + static name_info_t * 197 + _internal_new_name(notify_state_t *ns, const char *name) 198 + { 199 + name_info_t *n; 200 + size_t namelen; 201 + 202 + if (ns == NULL) return NULL; 203 + if (name == NULL) return NULL; 204 + 205 + namelen = strlen(name) + 1; 206 + 207 + n = (name_info_t *)calloc(1, sizeof(name_info_t) + namelen); 208 + if (n == NULL) return NULL; 209 + 210 + ns->stat_name_alloc++; 211 + 212 + n->name = (char *)n + sizeof(name_info_t); 213 + memcpy(n->name, name, namelen); 214 + 215 + notify_globals_t globals = _notify_globals(); 216 + n->name_id = globals->name_id++; 217 + 218 + n->access = NOTIFY_ACCESS_DEFAULT; 219 + n->slot = (uint32_t)-1; 220 + n->val = 1; 221 + 222 + _nc_table_insert_no_copy(ns->name_table, n->name, n); 223 + _nc_table_insert_64(ns->name_id_table, n->name_id, n); 224 + 225 + return n; 226 + } 227 + 228 + static void 229 + _internal_insert_controlled_name(notify_state_t *ns, name_info_t *n) 230 + { 231 + int i, j; 232 + 233 + if (ns == NULL) return; 234 + if (n == NULL) return; 235 + 236 + if (ns->controlled_name == NULL) ns->controlled_name_count = 0; 237 + 238 + for (i = 0; i < ns->controlled_name_count; i++) 239 + { 240 + if (ns->controlled_name[i] == n) return; 241 + } 242 + 243 + ns->controlled_name = (name_info_t **)reallocf(ns->controlled_name, (ns->controlled_name_count + 1) * sizeof(name_info_t *)); 244 + 245 + /* 246 + * Insert name in reverse sorted order (longer names preceed shorter names). 247 + * this means that in _internal_check_access, we check subspaces from the bottom up 248 + * i.e. we check access for the "deepest" controlled subspace. 249 + */ 250 + 251 + for (i = 0; i < ns->controlled_name_count; i++) 252 + { 253 + if (strcmp(n->name, ns->controlled_name[i]->name) > 0) break; 254 + } 255 + 256 + for (j = ns->controlled_name_count; j > i; j--) 257 + { 258 + ns->controlled_name[j] = ns->controlled_name[j-1]; 259 + } 260 + 261 + ns->controlled_name[i] = n; 262 + ns->controlled_name_count++; 263 + } 264 + 265 + static void 266 + _internal_remove_controlled_name(notify_state_t *ns, name_info_t *n) 267 + { 268 + uint32_t i, j; 269 + 270 + for (i = 0; i < ns->controlled_name_count; i++) 271 + { 272 + if (ns->controlled_name[i] == n) 273 + { 274 + for (j = i + 1; j < ns->controlled_name_count; j++) 275 + { 276 + ns->controlled_name[j-1] = ns->controlled_name[j]; 277 + } 278 + 279 + ns->controlled_name_count--; 280 + if (ns->controlled_name_count == 0) 281 + { 282 + free(ns->controlled_name); 283 + ns->controlled_name = NULL; 284 + } 285 + else 286 + { 287 + ns->controlled_name = (name_info_t **)reallocf(ns->controlled_name, ns->controlled_name_count * sizeof(name_info_t *)); 288 + } 289 + 290 + return; 291 + } 292 + } 293 + } 294 + 295 + static uint32_t 296 + _internal_check_access(notify_state_t *ns, const char *name, uid_t uid, gid_t gid, int req) 297 + { 298 + uint32_t i, len, plen; 299 + name_info_t *p; 300 + char str[64]; 301 + 302 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 303 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 304 + 305 + /* root may do anything */ 306 + if (uid == 0) return NOTIFY_STATUS_OK; 307 + 308 + /* if name has "user.uid." as a prefix, it is a user-protected namespace */ 309 + if (!strncmp(name, USER_PROTECTED_UID_PREFIX, USER_PROTECTED_UID_PREFIX_LEN)) 310 + { 311 + snprintf(str, sizeof(str) - 1, "%s%d", USER_PROTECTED_UID_PREFIX, uid); 312 + len = strlen(str); 313 + 314 + /* user <uid> may access user.uid.<uid> or a subtree name */ 315 + if ((!strncmp(name, str, len)) && ((name[len] == '\0') || (name[len] == '.'))) return NOTIFY_STATUS_OK; 316 + return NOTIFY_STATUS_NOT_AUTHORIZED; 317 + } 318 + 319 + len = strlen(name); 320 + 321 + if (ns->controlled_name == NULL) ns->controlled_name_count = 0; 322 + for (i = 0; i < ns->controlled_name_count; i++) 323 + { 324 + p = ns->controlled_name[i]; 325 + if (p == NULL) break; 326 + if (p->name == NULL) continue; 327 + 328 + plen = strlen(p->name); 329 + if (plen > len) continue; 330 + if (strncmp(p->name, name, plen)) continue; 331 + 332 + /* Found a match or a prefix, check if restrictions apply to this uid/gid */ 333 + if ((p->uid == uid) && (p->access & (req << NOTIFY_ACCESS_USER_SHIFT))) break; 334 + if ((p->gid == gid) && (p->access & (req << NOTIFY_ACCESS_GROUP_SHIFT))) break; 335 + if (p->access & (req << NOTIFY_ACCESS_OTHER_SHIFT)) break; 336 + 337 + return NOTIFY_STATUS_NOT_AUTHORIZED; 338 + } 339 + 340 + return NOTIFY_STATUS_OK; 341 + } 342 + 343 + uint32_t 344 + _notify_lib_check_controlled_access(notify_state_t *ns, char *name, uid_t uid, gid_t gid, int req) 345 + { 346 + uint32_t status; 347 + 348 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 349 + 350 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 351 + status = _internal_check_access(ns, name, uid, gid, req); 352 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 353 + 354 + return status; 355 + } 356 + 357 + uint32_t 358 + _notify_lib_port_proc_new(notify_state_t *ns, mach_port_t port, pid_t proc, uint32_t state, dispatch_source_t src) 359 + { 360 + portproc_data_t *pdata; 361 + 362 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 363 + if ((proc == 0) && (port == MACH_PORT_NULL)) return NOTIFY_STATUS_FAILED; 364 + 365 + pdata = (portproc_data_t *)calloc(1, sizeof(portproc_data_t)); 366 + if (pdata == NULL) return NOTIFY_STATUS_FAILED; 367 + 368 + ns->stat_portproc_alloc++; 369 + 370 + pdata->refcount = 1; 371 + pdata->flags = state; 372 + pdata->src = src; 373 + 374 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 375 + if (proc == 0) _nc_table_insert_n(ns->port_table, port, pdata); 376 + else _nc_table_insert_n(ns->proc_table, proc, pdata); 377 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 378 + 379 + return NOTIFY_STATUS_OK; 380 + } 381 + 382 + portproc_data_t * 383 + _notify_lib_port_proc_find(notify_state_t *ns, mach_port_t port, pid_t proc) 384 + { 385 + portproc_data_t *pdata = NULL; 386 + 387 + if (ns == NULL) return NULL; 388 + if ((proc == 0) && (port == MACH_PORT_NULL)) return NULL; 389 + 390 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 391 + 392 + if (proc == 0) pdata = _nc_table_find_n(ns->port_table, port); 393 + else pdata = _nc_table_find_n(ns->proc_table, proc); 394 + 395 + if (pdata != NULL) pdata->refcount++; 396 + 397 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 398 + 399 + return pdata; 400 + } 401 + 402 + void 403 + _notify_lib_port_proc_release(notify_state_t *ns, mach_port_t port, pid_t proc) 404 + { 405 + portproc_data_t *pdata = NULL; 406 + 407 + if (ns == NULL) return; 408 + if ((proc == 0) && (port == MACH_PORT_NULL)) return; 409 + 410 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 411 + 412 + if (proc == 0) pdata = _nc_table_find_n(ns->port_table, port); 413 + else pdata = _nc_table_find_n(ns->proc_table, proc); 414 + 415 + if (pdata != NULL) 416 + { 417 + if (pdata->refcount > 0) pdata->refcount--; 418 + if (pdata->refcount == 0) 419 + { 420 + if (proc == 0) _nc_table_delete_n(ns->port_table, port); 421 + else _nc_table_delete_n(ns->proc_table, proc); 422 + 423 + dispatch_source_cancel(pdata->src); 424 + dispatch_release(pdata->src); 425 + 426 + free(pdata); 427 + ns->stat_portproc_free++; 428 + } 429 + } 430 + 431 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 432 + } 433 + 434 + /* 435 + * Send notification to a subscriber 436 + */ 437 + static uint32_t 438 + _internal_send(notify_state_t *ns, client_t *c) 439 + { 440 + uint32_t send; 441 + portproc_data_t *pdata; 442 + 443 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 444 + if (c == NULL) return NOTIFY_STATUS_FAILED; 445 + 446 + if (c->state & NOTIFY_CLIENT_STATE_SUSPENDED) 447 + { 448 + c->state |= NOTIFY_CLIENT_STATE_PENDING; 449 + return NOTIFY_STATUS_OK; 450 + } 451 + 452 + pdata = _nc_table_find_n(ns->proc_table, c->pid); 453 + if ((pdata != NULL) && (pdata->flags & NOTIFY_PORT_PROC_STATE_SUSPENDED)) 454 + { 455 + c->suspend_count++; 456 + c->state |= NOTIFY_CLIENT_STATE_SUSPENDED; 457 + c->state |= NOTIFY_CLIENT_STATE_PENDING; 458 + return NOTIFY_STATUS_OK; 459 + } 460 + 461 + send = c->send_val; 462 + 463 + switch (c->notify_type) 464 + { 465 + case NOTIFY_TYPE_SIGNAL: 466 + { 467 + int rc = 0; 468 + 469 + if (c->pid == NOTIFY_CLIENT_SELF) rc = kill(getpid(), c->sig); 470 + else rc = kill(c->pid, c->sig); 471 + 472 + if (rc != 0) return NOTIFY_STATUS_FAILED; 473 + 474 + c->state &= ~NOTIFY_CLIENT_STATE_PENDING; 475 + c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT; 476 + 477 + return NOTIFY_STATUS_OK; 478 + } 479 + 480 + case NOTIFY_TYPE_FILE: 481 + { 482 + ssize_t len; 483 + 484 + if (c->fd >= 0) 485 + { 486 + send = htonl(send); 487 + len = write(c->fd, &send, sizeof(uint32_t)); 488 + if (len != sizeof(uint32_t)) 489 + { 490 + close(c->fd); 491 + c->fd = -1; 492 + return NOTIFY_STATUS_FAILED; 493 + } 494 + } 495 + 496 + c->state &= ~NOTIFY_CLIENT_STATE_PENDING; 497 + c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT; 498 + 499 + return NOTIFY_STATUS_OK; 500 + } 501 + 502 + case NOTIFY_TYPE_PORT: 503 + { 504 + kern_return_t kstatus; 505 + mach_msg_empty_send_t msg; 506 + mach_msg_option_t opts = MACH_SEND_MSG | MACH_SEND_TIMEOUT; 507 + 508 + pdata = _nc_table_find_n(ns->port_table, c->port); 509 + if ((pdata != NULL) && (pdata->flags & NOTIFY_PORT_PROC_STATE_SUSPENDED)) 510 + { 511 + c->suspend_count++; 512 + c->state |= NOTIFY_CLIENT_STATE_SUSPENDED; 513 + c->state |= NOTIFY_CLIENT_STATE_PENDING; 514 + return NOTIFY_STATUS_OK; 515 + } 516 + 517 + if (ns->flags & NOTIFY_STATE_ENABLE_RESEND) opts |= MACH_SEND_NOTIFY; 518 + 519 + memset(&msg, 0, sizeof(mach_msg_empty_send_t)); 520 + msg.header.msgh_size = sizeof(mach_msg_empty_send_t); 521 + msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSGH_BITS_ZERO); 522 + msg.header.msgh_local_port = MACH_PORT_NULL; 523 + msg.header.msgh_remote_port = c->port; 524 + msg.header.msgh_id = (mach_msg_id_t)send; 525 + 526 + kstatus = mach_msg(&msg.header, opts, msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 527 + 528 + if (kstatus == MACH_SEND_TIMED_OUT) 529 + { 530 + /* deallocate port rights obtained via pseudo-receive after failed mach_msg() send */ 531 + mach_msg_destroy(&msg.header); 532 + if (ns->flags & NOTIFY_STATE_ENABLE_RESEND) 533 + { 534 + /* 535 + * Suspend on timeout. 536 + * notifyd will get a MACH_NOTIFY_SEND_POSSIBLE and trigger a retry. 537 + * c->suspend_count must be zero, or we would not be trying to send. 538 + */ 539 + c->suspend_count++; 540 + c->state |= NOTIFY_CLIENT_STATE_SUSPENDED; 541 + c->state |= NOTIFY_CLIENT_STATE_PENDING; 542 + c->state |= NOTIFY_CLIENT_STATE_TIMEOUT; 543 + 544 + return NOTIFY_STATUS_OK; 545 + } 546 + 547 + return NOTIFY_STATUS_FAILED; 548 + } 549 + else if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 550 + 551 + c->state &= ~NOTIFY_CLIENT_STATE_PENDING; 552 + c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT; 553 + 554 + return NOTIFY_STATUS_OK; 555 + } 556 + 557 + default: 558 + { 559 + break; 560 + } 561 + } 562 + 563 + c->state &= ~NOTIFY_CLIENT_STATE_PENDING; 564 + c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT; 565 + 566 + return NOTIFY_STATUS_OK; 567 + } 568 + 569 + uint32_t 570 + _notify_lib_post_client(notify_state_t *ns, client_t *c) 571 + { 572 + uint32_t status; 573 + 574 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 575 + if (c == NULL) return NOTIFY_STATUS_FAILED; 576 + 577 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 578 + status = _internal_send(ns, c); 579 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 580 + 581 + return status; 582 + } 583 + 584 + static uint32_t 585 + _internal_post_name(notify_state_t *ns, name_info_t *n, uid_t uid, gid_t gid) 586 + { 587 + int auth; 588 + list_t *l; 589 + client_t *c; 590 + 591 + if (n == NULL) return NOTIFY_STATUS_INVALID_NAME; 592 + 593 + auth = _internal_check_access(ns, n->name, uid, gid, NOTIFY_ACCESS_WRITE); 594 + if (auth != 0) return NOTIFY_STATUS_NOT_AUTHORIZED; 595 + 596 + n->val++; 597 + 598 + for (l = n->subscriptions; l != NULL; l = _nc_list_next(l)) 599 + { 600 + c = _nc_list_data(l); 601 + if (c != NULL) _internal_send(ns, c); 602 + } 603 + 604 + return NOTIFY_STATUS_OK; 605 + } 606 + 607 + /* 608 + * Notify subscribers of this name. 609 + */ 610 + uint32_t 611 + _notify_lib_post(notify_state_t *ns, const char *name, uid_t uid, gid_t gid) 612 + { 613 + name_info_t *n; 614 + uint32_t status; 615 + 616 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 617 + 618 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 619 + 620 + n = (name_info_t *)_nc_table_find(ns->name_table, name); 621 + if (n == NULL) 622 + { 623 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 624 + return NOTIFY_STATUS_INVALID_NAME; 625 + } 626 + 627 + status = _internal_post_name(ns, n, uid, gid); 628 + 629 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 630 + return status; 631 + } 632 + 633 + uint32_t 634 + _notify_lib_post_nid(notify_state_t *ns, uint64_t nid, uid_t uid, gid_t gid) 635 + { 636 + name_info_t *n; 637 + uint32_t status; 638 + 639 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 640 + 641 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 642 + 643 + n = (name_info_t *)_nc_table_find_64(ns->name_id_table, nid); 644 + if (n == NULL) 645 + { 646 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 647 + return NOTIFY_STATUS_INVALID_NAME; 648 + } 649 + 650 + status = _internal_post_name(ns, n, uid, gid); 651 + 652 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 653 + return status; 654 + } 655 + 656 + static void 657 + _internal_release_name_info(notify_state_t *ns, name_info_t *n) 658 + { 659 + if (ns == NULL) return; 660 + if (n == NULL) return; 661 + 662 + if (n->refcount > 0) n->refcount--; 663 + if (n->refcount == 0) 664 + { 665 + _internal_remove_controlled_name(ns, n); 666 + _nc_table_delete(ns->name_table, n->name); 667 + _nc_table_delete_64(ns->name_id_table, n->name_id); 668 + _nc_list_release_list(n->subscriptions); 669 + free(n); 670 + ns->stat_name_free++; 671 + } 672 + } 673 + 674 + /* 675 + * Cancel (delete) a client 676 + */ 677 + static void 678 + _internal_cancel(notify_state_t *ns, uint64_t cid) 679 + { 680 + client_t *c; 681 + name_info_t *n; 682 + 683 + if (ns == NULL) return; 684 + 685 + c = NULL; 686 + n = NULL; 687 + 688 + c = _nc_table_find_64(ns->client_table, cid); 689 + if (c == NULL) return; 690 + 691 + n = c->name_info; 692 + if (n == NULL) return; 693 + 694 + n->subscriptions =_nc_list_find_release(n->subscriptions, c); 695 + _internal_client_release(ns, c); 696 + _internal_release_name_info(ns, n); 697 + } 698 + 699 + void 700 + _notify_lib_cancel(notify_state_t *ns, pid_t pid, int token) 701 + { 702 + uint64_t cid; 703 + 704 + if (ns == NULL) return; 705 + 706 + cid = make_client_id(pid, token); 707 + 708 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 709 + _internal_cancel(ns, cid); 710 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 711 + } 712 + 713 + void 714 + _notify_lib_suspend(notify_state_t *ns, pid_t pid, int token) 715 + { 716 + client_t *c; 717 + uint64_t cid; 718 + 719 + if (ns == NULL) return; 720 + 721 + cid = make_client_id(pid, token); 722 + 723 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 724 + 725 + c = _nc_table_find_64(ns->client_table, cid); 726 + if (c != NULL) 727 + { 728 + c->state |= NOTIFY_CLIENT_STATE_SUSPENDED; 729 + if (c->suspend_count < UINT32_MAX) c->suspend_count++; 730 + } 731 + 732 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 733 + } 734 + 735 + uint32_t 736 + _notify_lib_resume(notify_state_t *ns, pid_t pid, int token) 737 + { 738 + client_t *c; 739 + uint64_t cid; 740 + uint32_t status = NOTIFY_STATUS_OK; 741 + 742 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 743 + 744 + cid = make_client_id(pid, token); 745 + 746 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 747 + 748 + c = _nc_table_find_64(ns->client_table, cid); 749 + if (c != NULL) 750 + { 751 + if (c->suspend_count > 0) c->suspend_count--; 752 + if (c->suspend_count == 0) 753 + { 754 + c->state &= ~NOTIFY_CLIENT_STATE_SUSPENDED; 755 + c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT; 756 + 757 + if (c->state & NOTIFY_CLIENT_STATE_PENDING) 758 + { 759 + status = _internal_send(ns, c); 760 + } 761 + } 762 + } 763 + 764 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 765 + 766 + return status; 767 + } 768 + 769 + void 770 + _notify_lib_suspend_proc(notify_state_t *ns, pid_t pid) 771 + { 772 + portproc_data_t *pdata; 773 + 774 + if (ns == NULL) return; 775 + 776 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 777 + 778 + pdata = _nc_table_find_n(ns->proc_table, pid); 779 + if (pdata != NULL) pdata->flags |= NOTIFY_PORT_PROC_STATE_SUSPENDED; 780 + 781 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 782 + } 783 + 784 + void 785 + _notify_lib_resume_proc(notify_state_t *ns, pid_t pid) 786 + { 787 + client_t *c; 788 + void *tt; 789 + portproc_data_t *pdata; 790 + 791 + if (ns == NULL) return; 792 + 793 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 794 + 795 + /* Resume all subscriptions for this process */ 796 + pdata = _nc_table_find_n(ns->proc_table, pid); 797 + if (pdata != NULL) pdata->flags &= ~NOTIFY_PORT_PROC_STATE_SUSPENDED; 798 + 799 + tt = _nc_table_traverse_start(ns->client_table); 800 + while (tt != NULL) 801 + { 802 + c = _nc_table_traverse(ns->client_table, tt); 803 + if (c == NULL) break; 804 + 805 + if (c->pid == pid) 806 + { 807 + if (c->suspend_count > 0) c->suspend_count--; 808 + if (c->suspend_count == 0) 809 + { 810 + c->state &= ~NOTIFY_CLIENT_STATE_SUSPENDED; 811 + c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT; 812 + 813 + if (c->state & NOTIFY_CLIENT_STATE_PENDING) 814 + { 815 + _internal_send(ns, c); 816 + } 817 + } 818 + } 819 + } 820 + _nc_table_traverse_end(ns->client_table, tt); 821 + 822 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 823 + } 824 + 825 + void 826 + _notify_lib_suspend_port(notify_state_t *ns, mach_port_t port) 827 + { 828 + portproc_data_t *pdata; 829 + 830 + if (ns == NULL) return; 831 + 832 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 833 + 834 + pdata = _nc_table_find_n(ns->port_table, port); 835 + if (pdata != NULL) pdata->flags |= NOTIFY_PORT_PROC_STATE_SUSPENDED; 836 + 837 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 838 + } 839 + 840 + void 841 + _notify_lib_resume_port(notify_state_t *ns, mach_port_t port) 842 + { 843 + client_t *c; 844 + void *tt; 845 + portproc_data_t *pdata; 846 + 847 + if (ns == NULL) return; 848 + 849 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 850 + 851 + /* Resume all subscriptions with this port */ 852 + pdata = _nc_table_find_n(ns->port_table, port); 853 + if (pdata != NULL) pdata->flags &= ~NOTIFY_PORT_PROC_STATE_SUSPENDED; 854 + 855 + tt = _nc_table_traverse_start(ns->client_table); 856 + while (tt != NULL) 857 + { 858 + c = _nc_table_traverse(ns->client_table, tt); 859 + if (c == NULL) break; 860 + 861 + if (c->port == port) 862 + { 863 + if (c->suspend_count > 0) c->suspend_count--; 864 + if (c->suspend_count == 0) 865 + { 866 + c->state &= ~NOTIFY_CLIENT_STATE_SUSPENDED; 867 + c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT; 868 + 869 + if (c->state & NOTIFY_CLIENT_STATE_PENDING) 870 + { 871 + _internal_send(ns, c); 872 + } 873 + } 874 + } 875 + } 876 + _nc_table_traverse_end(ns->client_table, tt); 877 + 878 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 879 + } 880 + 881 + /* 882 + * Delete all clients for a process 883 + * N.B. notifyd does not use this routine. 884 + */ 885 + void 886 + _notify_lib_cancel_proc(notify_state_t *ns, pid_t pid) 887 + { 888 + client_t *c; 889 + void *tt; 890 + list_t *l, *x; 891 + 892 + if (ns == NULL) return; 893 + 894 + x = NULL; 895 + 896 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 897 + 898 + tt = _nc_table_traverse_start(ns->client_table); 899 + while (tt != NULL) 900 + { 901 + c = _nc_table_traverse(ns->client_table, tt); 902 + if (c == NULL) break; 903 + 904 + if (c->pid == pid) x = _nc_list_prepend(x, _nc_list_new(c)); 905 + } 906 + _nc_table_traverse_end(ns->client_table, tt); 907 + 908 + for (l = x; l != NULL; l = _nc_list_next(l)) 909 + { 910 + c = _nc_list_data(l); 911 + _internal_cancel(ns, c->client_id); 912 + } 913 + 914 + _nc_list_release_list(x); 915 + 916 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 917 + } 918 + 919 + /* 920 + * Delete all clients for a port 921 + * N.B. notifyd does not use this routine. 922 + */ 923 + void 924 + _notify_lib_cancel_port(notify_state_t *ns, mach_port_t port) 925 + { 926 + client_t *c; 927 + void *tt; 928 + list_t *l, *x; 929 + 930 + if (ns == NULL) return; 931 + 932 + x = NULL; 933 + 934 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 935 + 936 + tt = _nc_table_traverse_start(ns->client_table); 937 + while (tt != NULL) 938 + { 939 + c = _nc_table_traverse(ns->client_table, tt); 940 + if (c == NULL) break; 941 + 942 + if (c->port == port) x = _nc_list_prepend(x, _nc_list_new(c)); 943 + } 944 + _nc_table_traverse_end(ns->client_table, tt); 945 + 946 + for (l = x; l != NULL; l = _nc_list_next(l)) 947 + { 948 + c = _nc_list_data(l); 949 + _internal_cancel(ns, c->client_id); 950 + } 951 + 952 + _nc_list_release_list(x); 953 + 954 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 955 + } 956 + 957 + /* 958 + * Check if a name has changed since the last time this client checked. 959 + * Returns true, false, or error. 960 + */ 961 + uint32_t 962 + _notify_lib_check(notify_state_t *ns, pid_t pid, int token, int *check) 963 + { 964 + client_t *c; 965 + uint64_t cid; 966 + 967 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 968 + if (check == NULL) return NOTIFY_STATUS_FAILED; 969 + 970 + cid = make_client_id(pid, token); 971 + 972 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 973 + 974 + c = _nc_table_find_64(ns->client_table, cid); 975 + 976 + if (c == NULL) 977 + { 978 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 979 + return NOTIFY_STATUS_INVALID_TOKEN; 980 + } 981 + 982 + if (c->name_info == NULL) 983 + { 984 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 985 + return NOTIFY_STATUS_INVALID_TOKEN; 986 + } 987 + 988 + if (c->name_info->val == c->lastval) 989 + { 990 + *check = 0; 991 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 992 + return NOTIFY_STATUS_OK; 993 + } 994 + 995 + c->lastval = c->name_info->val; 996 + *check = 1; 997 + 998 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 999 + return NOTIFY_STATUS_OK; 1000 + } 1001 + 1002 + /* 1003 + * SPI: get value for a name. 1004 + */ 1005 + uint32_t 1006 + _notify_lib_peek(notify_state_t *ns, pid_t pid, int token, int *val) 1007 + { 1008 + client_t *c; 1009 + uint64_t cid; 1010 + 1011 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 1012 + if (val == NULL) return NOTIFY_STATUS_FAILED; 1013 + 1014 + cid = make_client_id(pid, token); 1015 + 1016 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 1017 + 1018 + c = _nc_table_find_64(ns->client_table, cid); 1019 + 1020 + if (c == NULL) 1021 + { 1022 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1023 + return NOTIFY_STATUS_INVALID_TOKEN; 1024 + } 1025 + 1026 + if (c->name_info == NULL) 1027 + { 1028 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1029 + return NOTIFY_STATUS_INVALID_TOKEN; 1030 + } 1031 + 1032 + *val = c->name_info->val; 1033 + 1034 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1035 + return NOTIFY_STATUS_OK; 1036 + } 1037 + 1038 + int * 1039 + _notify_lib_check_addr(notify_state_t *ns, pid_t pid, int token) 1040 + { 1041 + client_t *c; 1042 + int *addr; 1043 + uint64_t cid; 1044 + 1045 + if (ns == NULL) return NULL; 1046 + 1047 + cid = make_client_id(pid, token); 1048 + 1049 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 1050 + 1051 + c = _nc_table_find_64(ns->client_table, cid); 1052 + 1053 + if (c == NULL) 1054 + { 1055 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1056 + return NULL; 1057 + } 1058 + 1059 + if (c->name_info == NULL) 1060 + { 1061 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1062 + return NULL; 1063 + } 1064 + 1065 + addr = (int *)&(c->name_info->val); 1066 + 1067 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1068 + return addr; 1069 + } 1070 + 1071 + /* 1072 + * Get state value for a name. 1073 + */ 1074 + uint32_t 1075 + _notify_lib_get_state(notify_state_t *ns, uint64_t nid, uint64_t *state, uid_t uid, gid_t gid) 1076 + { 1077 + name_info_t *n; 1078 + 1079 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 1080 + if (state == NULL) return NOTIFY_STATUS_FAILED; 1081 + 1082 + *state = 0; 1083 + 1084 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 1085 + 1086 + n = (name_info_t *)_nc_table_find_64(ns->name_id_table, nid); 1087 + 1088 + if (n == NULL) 1089 + { 1090 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1091 + return NOTIFY_STATUS_INVALID_NAME; 1092 + } 1093 + 1094 + #ifdef GET_STATE_AUTH_CHECK 1095 + int auth = _internal_check_access(ns, n->name, uid, gid, NOTIFY_ACCESS_READ); 1096 + if (auth != 0) 1097 + { 1098 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1099 + return NOTIFY_STATUS_NOT_AUTHORIZED; 1100 + } 1101 + #endif 1102 + 1103 + *state = n->state; 1104 + 1105 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1106 + return NOTIFY_STATUS_OK; 1107 + } 1108 + 1109 + /* 1110 + * Set state value for a name. 1111 + */ 1112 + uint32_t 1113 + _notify_lib_set_state(notify_state_t *ns, uint64_t nid, uint64_t state, uid_t uid, gid_t gid) 1114 + { 1115 + name_info_t *n; 1116 + int auth; 1117 + 1118 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 1119 + 1120 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 1121 + 1122 + n = (name_info_t *)_nc_table_find_64(ns->name_id_table, nid); 1123 + 1124 + if (n == NULL) 1125 + { 1126 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1127 + return NOTIFY_STATUS_INVALID_NAME; 1128 + } 1129 + 1130 + auth = _internal_check_access(ns, n->name, uid, gid, NOTIFY_ACCESS_WRITE); 1131 + if (auth != 0) 1132 + { 1133 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1134 + return NOTIFY_STATUS_NOT_AUTHORIZED; 1135 + } 1136 + 1137 + n->state = state; 1138 + n->state_time = mach_absolute_time(); 1139 + 1140 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1141 + return NOTIFY_STATUS_OK; 1142 + } 1143 + 1144 + static uint32_t 1145 + _internal_register_common(notify_state_t *ns, const char *name, pid_t pid, int token, uid_t uid, gid_t gid, client_t **outc) 1146 + { 1147 + client_t *c; 1148 + name_info_t *n; 1149 + int is_new_name; 1150 + uint32_t status; 1151 + 1152 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 1153 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1154 + if (outc == NULL) return NOTIFY_STATUS_OK; 1155 + 1156 + status = _internal_check_access(ns, name, uid, gid, NOTIFY_ACCESS_READ); 1157 + if (status != NOTIFY_STATUS_OK) return NOTIFY_STATUS_NOT_AUTHORIZED; 1158 + 1159 + *outc = NULL; 1160 + is_new_name = 0; 1161 + 1162 + n = (name_info_t *)_nc_table_find(ns->name_table, name); 1163 + if (n == NULL) 1164 + { 1165 + is_new_name = 1; 1166 + 1167 + n = _internal_new_name(ns, name); 1168 + if (n == NULL) return NOTIFY_STATUS_FAILED; 1169 + } 1170 + 1171 + c = _internal_client_new(ns, pid, token); 1172 + if (c == NULL) 1173 + { 1174 + if (is_new_name == 1) 1175 + { 1176 + _nc_table_delete(ns->name_table, n->name); 1177 + _nc_list_release_list(n->subscriptions); 1178 + free(n); 1179 + ns->stat_name_free++; 1180 + } 1181 + 1182 + return NOTIFY_STATUS_FAILED; 1183 + } 1184 + 1185 + n->refcount++; 1186 + 1187 + c->name_info = n; 1188 + n->subscriptions = _nc_list_prepend(n->subscriptions, _nc_list_new(c)); 1189 + 1190 + *outc = c; 1191 + 1192 + return NOTIFY_STATUS_OK; 1193 + } 1194 + 1195 + /* 1196 + * Register for signal. 1197 + * Returns the client_id; 1198 + */ 1199 + uint32_t 1200 + _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) 1201 + { 1202 + client_t *c; 1203 + uint32_t status; 1204 + 1205 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 1206 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1207 + 1208 + c = NULL; 1209 + 1210 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 1211 + 1212 + status = _internal_register_common(ns, name, pid, token, uid, gid, &c); 1213 + if (status != NOTIFY_STATUS_OK) 1214 + { 1215 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1216 + return status; 1217 + } 1218 + 1219 + c->notify_type = NOTIFY_TYPE_SIGNAL; 1220 + c->pid = pid; 1221 + c->sig = sig; 1222 + *out_nid = c->name_info->name_id; 1223 + 1224 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1225 + return NOTIFY_STATUS_OK; 1226 + } 1227 + 1228 + /* 1229 + * Register for notification on a file descriptor. 1230 + * Returns the client_id; 1231 + */ 1232 + uint32_t 1233 + _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) 1234 + { 1235 + client_t *c; 1236 + uint32_t status; 1237 + 1238 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 1239 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1240 + 1241 + c = NULL; 1242 + 1243 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 1244 + 1245 + status = _internal_register_common(ns, name, pid, token, uid, gid, &c); 1246 + if (status != NOTIFY_STATUS_OK) 1247 + { 1248 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1249 + return status; 1250 + } 1251 + 1252 + c->notify_type = NOTIFY_TYPE_FILE; 1253 + c->fd = fd; 1254 + *out_nid = c->name_info->name_id; 1255 + 1256 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1257 + return NOTIFY_STATUS_OK; 1258 + } 1259 + 1260 + /* 1261 + * Register for notification on a mach port. 1262 + * Returns the client_id; 1263 + */ 1264 + uint32_t 1265 + _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) 1266 + { 1267 + client_t *c; 1268 + uint32_t status; 1269 + 1270 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 1271 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1272 + 1273 + c = NULL; 1274 + 1275 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 1276 + 1277 + status = _internal_register_common(ns, name, pid, token, uid, gid, &c); 1278 + if (status != NOTIFY_STATUS_OK) 1279 + { 1280 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1281 + return status; 1282 + } 1283 + 1284 + c->notify_type = NOTIFY_TYPE_PORT; 1285 + c->port = port; 1286 + *out_nid = c->name_info->name_id; 1287 + 1288 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1289 + return NOTIFY_STATUS_OK; 1290 + } 1291 + 1292 + /* 1293 + * Plain registration - only for notify_check() 1294 + * Returns the client_id. 1295 + */ 1296 + uint32_t 1297 + _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) 1298 + { 1299 + client_t *c; 1300 + uint32_t status; 1301 + 1302 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 1303 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1304 + 1305 + c = NULL; 1306 + 1307 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 1308 + 1309 + status = _internal_register_common(ns, name, pid, token, uid, gid, &c); 1310 + if (status != NOTIFY_STATUS_OK) 1311 + { 1312 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1313 + return status; 1314 + } 1315 + 1316 + if (slot == SLOT_NONE) 1317 + { 1318 + c->notify_type = NOTIFY_TYPE_PLAIN; 1319 + } 1320 + else 1321 + { 1322 + c->notify_type = NOTIFY_TYPE_MEMORY; 1323 + c->name_info->slot = slot; 1324 + } 1325 + 1326 + *out_nid = c->name_info->name_id; 1327 + 1328 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1329 + return NOTIFY_STATUS_OK; 1330 + } 1331 + 1332 + uint32_t 1333 + _notify_lib_set_owner(notify_state_t *ns, const char *name, uid_t uid, gid_t gid) 1334 + { 1335 + name_info_t *n; 1336 + 1337 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 1338 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1339 + 1340 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 1341 + 1342 + n = (name_info_t *)_nc_table_find(ns->name_table, name); 1343 + if (n == NULL) 1344 + { 1345 + /* create new name */ 1346 + n = _internal_new_name(ns, name); 1347 + if (n == NULL) 1348 + { 1349 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1350 + return NOTIFY_STATUS_FAILED; 1351 + } 1352 + 1353 + /* 1354 + * Setting the refcount here allows the namespace to be "pre-populated" 1355 + * with controlled names. notifyd does this for reserved names in 1356 + * its configuration file. 1357 + */ 1358 + n->refcount++; 1359 + } 1360 + 1361 + n->uid = uid; 1362 + n->gid = gid; 1363 + 1364 + _internal_insert_controlled_name(ns, n); 1365 + 1366 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1367 + return NOTIFY_STATUS_OK; 1368 + } 1369 + 1370 + uint32_t 1371 + _notify_lib_get_owner(notify_state_t *ns, const char *name, uint32_t *uid, uint32_t *gid) 1372 + { 1373 + name_info_t *n; 1374 + int i, nlen, len; 1375 + 1376 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 1377 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1378 + 1379 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 1380 + 1381 + n = (name_info_t *)_nc_table_find(ns->name_table, name); 1382 + if (n != NULL) 1383 + { 1384 + *uid = n->uid; 1385 + *gid = n->gid; 1386 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1387 + return NOTIFY_STATUS_OK; 1388 + } 1389 + 1390 + len = strlen(name); 1391 + 1392 + for (i = 0; i < ns->controlled_name_count; i++) 1393 + { 1394 + n = ns->controlled_name[i]; 1395 + if (n == NULL) break; 1396 + 1397 + nlen = strlen(n->name); 1398 + 1399 + if (!strcmp(n->name, name)) 1400 + { 1401 + *uid = n->uid; 1402 + *gid = n->gid; 1403 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1404 + return NOTIFY_STATUS_OK; 1405 + } 1406 + 1407 + /* check if this key is a prefix */ 1408 + if (nlen >= len) continue; 1409 + if (strncmp(n->name, name, nlen)) continue; 1410 + 1411 + *uid = n->uid; 1412 + *gid = n->gid; 1413 + 1414 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1415 + return NOTIFY_STATUS_OK; 1416 + } 1417 + 1418 + *uid = 0; 1419 + *gid = 0; 1420 + 1421 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1422 + return NOTIFY_STATUS_OK; 1423 + } 1424 + 1425 + uint32_t 1426 + _notify_lib_set_access(notify_state_t *ns, const char *name, uint32_t mode) 1427 + { 1428 + name_info_t *n; 1429 + 1430 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 1431 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1432 + 1433 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 1434 + 1435 + n = (name_info_t *)_nc_table_find(ns->name_table, name); 1436 + if (n == NULL) 1437 + { 1438 + /* create new name */ 1439 + n = _internal_new_name(ns, name); 1440 + if (n == NULL) 1441 + { 1442 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1443 + return NOTIFY_STATUS_FAILED; 1444 + } 1445 + 1446 + /* 1447 + * Setting the refcount here allows the namespace to be "pre-populated" 1448 + * with controlled names. notifyd does this for reserved names in 1449 + * its configuration file. 1450 + */ 1451 + n->refcount++; 1452 + } 1453 + 1454 + n->access = mode; 1455 + 1456 + _internal_insert_controlled_name(ns, n); 1457 + 1458 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1459 + return NOTIFY_STATUS_OK; 1460 + } 1461 + 1462 + uint32_t 1463 + _notify_lib_get_access(notify_state_t *ns, const char *name, uint32_t *mode) 1464 + { 1465 + name_info_t *n; 1466 + int i, nlen, len; 1467 + 1468 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 1469 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1470 + 1471 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 1472 + 1473 + n = (name_info_t *)_nc_table_find(ns->name_table, name); 1474 + if (n != NULL) 1475 + { 1476 + *mode = n->access; 1477 + 1478 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1479 + return NOTIFY_STATUS_OK; 1480 + } 1481 + 1482 + len = strlen(name); 1483 + 1484 + for (i = 0; i < ns->controlled_name_count; i++) 1485 + { 1486 + n = ns->controlled_name[i]; 1487 + if (n == NULL) break; 1488 + if (n->name == NULL) continue; 1489 + 1490 + nlen = strlen(n->name); 1491 + 1492 + if (!strcmp(n->name, name)) 1493 + { 1494 + *mode = n->access; 1495 + 1496 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1497 + return NOTIFY_STATUS_OK; 1498 + } 1499 + 1500 + /* check if this key is a prefix */ 1501 + if (nlen >= len) continue; 1502 + if (strncmp(n->name, name, nlen)) continue; 1503 + 1504 + *mode = n->access; 1505 + 1506 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1507 + return NOTIFY_STATUS_OK; 1508 + } 1509 + 1510 + *mode = NOTIFY_ACCESS_DEFAULT; 1511 + 1512 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1513 + return NOTIFY_STATUS_OK; 1514 + } 1515 + 1516 + uint32_t 1517 + _notify_lib_release_name(notify_state_t *ns, const char *name, uid_t uid, gid_t gid) 1518 + { 1519 + name_info_t *n; 1520 + 1521 + if (ns == NULL) return NOTIFY_STATUS_FAILED; 1522 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1523 + 1524 + if (ns->lock != NULL) pthread_mutex_lock(ns->lock); 1525 + 1526 + n = (name_info_t *)_nc_table_find(ns->name_table, name); 1527 + if (n == NULL) 1528 + { 1529 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1530 + return NOTIFY_STATUS_INVALID_NAME; 1531 + } 1532 + 1533 + /* Owner and root may release */ 1534 + if ((n->uid != uid) && (uid != 0)) 1535 + { 1536 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1537 + return NOTIFY_STATUS_NOT_AUTHORIZED; 1538 + } 1539 + 1540 + _internal_release_name_info(ns, n); 1541 + 1542 + if (ns->lock != NULL) pthread_mutex_unlock(ns->lock); 1543 + return NOTIFY_STATUS_OK; 1544 + }
+216
libnotify/libnotify.h
··· 1 + /* 2 + * Copyright (c) 2003-2012 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #ifndef _LIBNOTIFY_H_ 25 + #define _LIBNOTIFY_H_ 26 + 27 + #include <pthread.h> 28 + #include <mach/mach.h> 29 + #include <dispatch/dispatch.h> 30 + #include "table.h" 31 + 32 + #include <TargetConditionals.h> 33 + 34 + #if TARGET_IPHONE_SIMULATOR 35 + extern const char *_notify_shm_id(); 36 + #define SHM_ID _notify_shm_id() 37 + #else 38 + #define SHM_ID "apple.shm.notification_center" 39 + #endif 40 + 41 + #define NOTIFY_IPC_VERSION_NAME "com.apple.system.notify.ipc_version" 42 + #define NOTIFY_IPC_VERSION_NAME_LEN 35 43 + #define NOTIFY_SERVICE_NAME "com.apple.system.notification_center" 44 + #define NOTIFY_SERVICE_NAME_LEN 36 45 + 46 + #define COMMON_PORT_KEY "com.apple.system.notify.common" 47 + 48 + /* Notification types */ 49 + #define NOTIFY_TYPE_NONE 0x00000000 50 + #define NOTIFY_TYPE_MEMORY 0x00000001 51 + #define NOTIFY_TYPE_PLAIN 0x00000002 52 + #define NOTIFY_TYPE_PORT 0x00000004 53 + #define NOTIFY_TYPE_FILE 0x00000008 54 + #define NOTIFY_TYPE_SIGNAL 0x00000010 55 + #define NOTIFY_TYPE_MASK 0x000000ff 56 + #define NOTIFY_FLAG_SELF 0x80000000 57 + #define NOTIFY_FLAG_REGEN 0x40000000 58 + #define NOTIFY_FLAG_RELEASE_SEND 0x20000000 59 + 60 + /* Return values for notify_check() */ 61 + #define NOTIFY_CHECK_FALSE 0 62 + #define NOTIFY_CHECK_TRUE 1 63 + #define NOTIFY_CHECK_ERROR 2 64 + 65 + /* Access control */ 66 + #define NOTIFY_ACCESS_READ 1 67 + #define NOTIFY_ACCESS_WRITE 2 68 + 69 + #define NOTIFY_ACCESS_OTHER_SHIFT 8 70 + #define NOTIFY_ACCESS_GROUP_SHIFT 4 71 + #define NOTIFY_ACCESS_USER_SHIFT 0 72 + 73 + #define NOTIFY_ACCESS_DEFAULT 0x00000333 74 + #define NOTIFY_ACCESS_USER_RW 0x00000003 75 + 76 + /* Filesystem Services */ 77 + #define NOTIFY_SERVICE_FILE_STATUS_QUO 0x00 78 + #define NOTIFY_SERVICE_FILE_ADD 0x01 79 + #define NOTIFY_SERVICE_FILE_DELETE 0x02 80 + #define NOTIFY_SERVICE_FILE_MODIFY 0x04 81 + #define NOTIFY_SERVICE_FILE_ATTR 0x08 82 + 83 + #define NOTIFY_SERVICE_DIR_FILE_ADD 0x10 84 + #define NOTIFY_SERVICE_DIR_FILE_DELETE 0x20 85 + 86 + #define NOTIFY_CLIENT_STATE_SUSPENDED 0x00000001 87 + #define NOTIFY_CLIENT_STATE_PENDING 0x00000002 88 + #define NOTIFY_CLIENT_STATE_TIMEOUT 0x00000004 89 + 90 + #define NOTIFY_PORT_PROC_TYPE_PORT 0x00000010 91 + #define NOTIFY_PORT_PROC_TYPE_PROC 0x00000020 92 + #define NOTIFY_PORT_PROC_TYPE_MASK 0x000000f0 93 + #define NOTIFY_PORT_PROC_STATE_INVALID 0x00000001 94 + #define NOTIFY_PORT_PROC_STATE_SUSPENDED 0x00000002 95 + #define NOTIFY_PORT_PROC_STATE_MASK 0x0000000f 96 + 97 + /* notify state flags */ 98 + #define NOTIFY_STATE_USE_LOCKS 0x00000001 99 + #define NOTIFY_STATE_ENABLE_RESEND 0x00000002 100 + 101 + #define NOTIFY_CLIENT_SELF 0 102 + #define SIGNAL_NONE -1 103 + #define FD_NONE -1 104 + #define SLOT_NONE -1 105 + 106 + #define _notify_lib_port_new(A,B,C,D) _notify_lib_port_proc_new(A,B,0,C,D) 107 + #define _notify_lib_proc_new(A,B,C,D) _notify_lib_port_proc_new(A,MACH_PORT_NULL,B,C,D) 108 + #define _notify_lib_port_find(A,B) _notify_lib_port_proc_find(A,B,0) 109 + #define _notify_lib_proc_find(A,B) _notify_lib_port_proc_find(A,MACH_PORT_NULL,B) 110 + #define _notify_lib_port_release(A,B) _notify_lib_port_proc_release(A,B,0) 111 + #define _notify_lib_proc_release(A,B) _notify_lib_port_proc_release(A,MACH_PORT_NULL,B) 112 + 113 + typedef struct 114 + { 115 + char *name; 116 + uint64_t name_id; 117 + uint32_t uid; 118 + uint32_t gid; 119 + uint32_t access; 120 + uint32_t slot; 121 + uint32_t refcount; 122 + uint32_t val; 123 + uint64_t state; 124 + uint64_t state_time; 125 + void *private; 126 + list_t *subscriptions; 127 + } name_info_t; 128 + 129 + typedef struct 130 + { 131 + uint64_t client_id; 132 + uint32_t state; 133 + name_info_t *name_info; 134 + uint32_t suspend_count; 135 + uint32_t notify_type; 136 + uint32_t lastval; 137 + mach_port_t port; 138 + int fd; 139 + uint32_t send_val; 140 + uint32_t pid; 141 + uint32_t sig; 142 + void *private; 143 + } client_t; 144 + 145 + typedef struct 146 + { 147 + uint32_t refcount; 148 + uint32_t flags; 149 + dispatch_source_t src; 150 + } portproc_data_t; 151 + 152 + typedef struct 153 + { 154 + uint32_t flags; 155 + table_t *name_table; 156 + table_t *name_id_table; 157 + table_t *client_table; 158 + table_t *port_table; 159 + table_t *proc_table; 160 + name_info_t **controlled_name; 161 + uint32_t controlled_name_count; 162 + pthread_mutex_t *lock; 163 + int sock; 164 + uint32_t stat_name_alloc; 165 + uint32_t stat_name_free; 166 + uint32_t stat_client_alloc; 167 + uint32_t stat_client_free; 168 + uint32_t stat_portproc_alloc; 169 + uint32_t stat_portproc_free; 170 + } notify_state_t; 171 + 172 + notify_state_t *_notify_lib_notify_state_new(uint32_t flags, uint32_t table_size); 173 + void _notify_lib_notify_state_free(notify_state_t *ns); 174 + 175 + uint32_t _notify_lib_post(notify_state_t *ns, const char *name, uint32_t uid, uint32_t gid); 176 + uint32_t _notify_lib_post_nid(notify_state_t *ns, uint64_t nid, uid_t uid, gid_t gid); 177 + uint32_t _notify_lib_post_client(notify_state_t *ns, client_t *c); 178 + 179 + uint32_t _notify_lib_check(notify_state_t *ns, pid_t pid, int token, int *check); 180 + uint32_t _notify_lib_get_state(notify_state_t *ns, uint64_t nid, uint64_t *state, uint32_t uid, uint32_t gid); 181 + uint32_t _notify_lib_set_state(notify_state_t *ns, uint64_t nid, uint64_t state, uint32_t uid, uint32_t gid); 182 + 183 + 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); 184 + 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); 185 + 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); 186 + 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); 187 + 188 + uint32_t _notify_lib_get_owner(notify_state_t *ns, const char *name, uint32_t *uid, uint32_t *gid); 189 + uint32_t _notify_lib_get_access(notify_state_t *ns, const char *name, uint32_t *access); 190 + 191 + uint32_t _notify_lib_set_owner(notify_state_t *ns, const char *name, uint32_t uid, uint32_t gid); 192 + uint32_t _notify_lib_set_access(notify_state_t *ns, const char *name, uint32_t access); 193 + 194 + uint32_t _notify_lib_release_name(notify_state_t *ns, const char *name, uint32_t uid, uint32_t gid); 195 + 196 + void _notify_lib_cancel(notify_state_t *ns, pid_t pid, int token); 197 + void _notify_lib_suspend(notify_state_t *ns, pid_t pid, int token); 198 + uint32_t _notify_lib_resume(notify_state_t *ns, pid_t pid, int token); 199 + 200 + void _notify_lib_cancel_proc(notify_state_t *ns, pid_t pid); 201 + void _notify_lib_suspend_proc(notify_state_t *ns, pid_t pid); 202 + void _notify_lib_resume_proc(notify_state_t *ns, pid_t pid); 203 + 204 + void _notify_lib_suspend_port(notify_state_t *ns, mach_port_t port); 205 + void _notify_lib_resume_port(notify_state_t *ns, mach_port_t port); 206 + 207 + uint32_t _notify_lib_check_controlled_access(notify_state_t *ns, char *name, uid_t uid, gid_t gid, int req); 208 + 209 + uint64_t make_client_id(pid_t pid, int token); 210 + 211 + 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); 212 + portproc_data_t *_notify_lib_port_proc_find(notify_state_t *ns, mach_port_t port, pid_t proc); 213 + void _notify_lib_port_proc_release(notify_state_t *ns, mach_port_t port, pid_t proc); 214 + 215 + 216 + #endif /* _LIBNOTIFY_H_ */
+419
libnotify/notify.3
··· 1 + .\" Copyright (c) 2003-2014 Apple Inc. All rights reserved. 2 + .\" 3 + .\" @APPLE_LICENSE_HEADER_START@ 4 + .\" 5 + .\" Portions Copyright (c) 2003-2010 Apple Inc. All Rights Reserved. 6 + .\" 7 + .\" This file contains Original Code and/or Modifications of Original Code 8 + .\" as defined in and that are subject to the Apple Public Source License 9 + .\" Version 2.0 (the 'License'). You may not use this file except in 10 + .\" compliance with the License. Please obtain a copy of the License at 11 + .\" http://www.opensource.apple.com/apsl/ and read it before using this 12 + .\" file. 13 + .\" 14 + .\" The Original Code and all software distributed under the License are 15 + .\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 + .\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 + .\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 + .\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 19 + .\" Please see the License for the specific language governing rights and 20 + .\" limitations under the License. 21 + .\" 22 + .\" @APPLE_LICENSE_HEADER_END@ 23 + .\" 24 + .\" 25 + .Dd September 3, 2008 26 + .Dt notify 3 27 + .Os "Mac OS X" 28 + .Sh NAME 29 + .Nm notify_post , 30 + .Nm notify_register_check , 31 + .Nm notify_register_dispatch , 32 + .Nm notify_register_signal , 33 + .Nm notify_register_mach_port , 34 + .Nm notify_register_file_descriptor , 35 + .Nm notify_check , 36 + .Nm notify_get_state , 37 + .Nm notify_set_state , 38 + .Nm notify_suspend , 39 + .Nm notify_resume , 40 + .Nm notify_cancel , 41 + .Nm notify_is_valid_token 42 + .Nd event distribution functions 43 + .Sh SYNOPSIS 44 + .Fd #include <notify.h> 45 + .Ft uint32_t 46 + .Fn notify_post "const char *name" 47 + .Ft uint32_t 48 + .Fn notify_register_check "const char *name, int *out_token" 49 + .Ft uint32_t 50 + .Fn notify_register_dispatch "const char *name, int *out_token" "dispatch_queue_t queue" "notify_handler_t handler" 51 + .Ft uint32_t 52 + .Fn notify_register_signal "const char *name, int sig, int *out_token" 53 + .Ft uint32_t 54 + .Fn notify_register_mach_port "const char *name, mach_port_t *notify_port, int flags, int *out_token" 55 + .Ft uint32_t 56 + .Fn notify_register_file_descriptor "const char *name, int *notify_fd, int flags, int *out_token" 57 + .Ft uint32_t 58 + .Fn notify_check "int token, int *check" 59 + .Ft uint32_t 60 + .Fn notify_set_state "int token, uint64_t state" 61 + .Ft uint32_t 62 + .Fn notify_get_state "int token, uint64_t *state" 63 + .Ft uint32_t 64 + .Fn notify_suspend "int token" 65 + .Ft uint32_t 66 + .Fn notify_resume "int token" 67 + .Ft uint32_t 68 + .Fn notify_cancel "int token" 69 + .Ft bool 70 + .Fn notify_is_valid_token "int val" 71 + .Sh DESCRIPTION 72 + These routines allow processes to exchange stateless notification events. 73 + Processes post notifications to a single system-wide notification server, 74 + which then distributes notifications to client processes that have 75 + registered to receive those notifications, including processes run by 76 + other users. 77 + .Pp 78 + Notifications are associated with names in a namespace shared by all 79 + clients of the system. 80 + Clients may post notifications for names, and 81 + may monitor names for posted notifications. 82 + Clients may request 83 + notification delivery by a number of different methods. 84 + .Pp 85 + Clients desiring to monitor names in the notification system must 86 + register with the system, providing a name and other information 87 + required for the desired notification delivery method. 88 + Clients are 89 + given an integer token representing the registration. 90 + Token values are zero or positive integers. 91 + .Pp 92 + The kernel provides limited queues for mach message and file descriptor messages. 93 + It is important to make sure that clients read mach ports and file descriptors frequently 94 + to prevent messages from being lost due to resource limitations. 95 + Clients that use signal-based notification should be aware that signals 96 + are not delivered to a process while it is running in a signal handler. 97 + This may affect the delivery of signals in close succession. 98 + .Pp 99 + Notifications may be coalesced in some cases. 100 + Multiple events posted 101 + for a name in rapid succession may result in a single notification sent 102 + to clients registered for notification for that name. 103 + Clients checking 104 + for changes using the notify_check() routine cannot determine if 105 + more than one event has been posted since a previous call to 106 + notify_check() for that name. 107 + .Pp 108 + "False positives" may occur in notify_check() when used with a token 109 + generated by notify_register_check() due to implementation constraints. 110 + This behavior may vary in future releases. 111 + .Ss notify_post 112 + This routine causes the system to send a notification for the given 113 + name to all clients that have registered for notifications of this name. 114 + This is the only API required for an application that only produces 115 + notifications. 116 + .Ss notify_register_check 117 + Registers for passive notification for the given name. 118 + The routine generates 119 + a token that may be used with the 120 + .Fn notify_check 121 + routine to check if any notifications have been posted for the name. 122 + The check is implemented using a shared memory scheme, making the check 123 + very fast and efficient. 124 + The implementation has a limited amount 125 + of shared memory, so developers are encouraged to use this mechanism 126 + sparingly. 127 + It is also important to release the resources consumed 128 + by a registration with 129 + .Fn notify_cancel 130 + when they are no longer required by the application. 131 + .Ss notify_register_dispatch 132 + registers a callback handler in the form of a block which will be 133 + dispatched to the queue when a notification for the given name is 134 + received. This is a convenient way to register callbacks without any 135 + management of file descriptors, mach ports, or signals on the part of 136 + the application. The given queue is retained by the system for the 137 + lifetime of the notification. Use 138 + .Fn notify_cancel 139 + to release the notification and its reference to the queue. 140 + .Ss notify_register_signal 141 + registers a client for notification delivery via a signal. 142 + This fits 143 + well with the design of many UNIX daemons that use a signal such as SIGHUP 144 + to reinitialize of reset internal state information. 145 + Clients may use the 146 + registration token generated by this routine to check for notifications using 147 + .Fn notify_check . 148 + This allows the application to determine if a signal was received as the 149 + result of a notification, or if the signal was generated by some other source. 150 + It also permits the application that registers for signal notification for 151 + multiple names to determine which name was associated with the notification. 152 + .Ss notify_register_mach_port 153 + registers a client for notification delivery via mach messaging. 154 + Notifications are delivered by an empty message sent to a mach port. 155 + By default, a new port is created by a call to this routine. 156 + A mach port 157 + previously created by a call to this routine may be used for notifications 158 + if a pointer to that port is passed in to the routine and NOTIFY_REUSE is 159 + set in the flags parameter. 160 + The notification service must be able to extract 161 + send rights to the port. 162 + .Pp 163 + Note that the kernel limits the size of the message queue for any port. 164 + If it is important that notifications should not be lost due to queue 165 + overflow, clients should service messages quickly, and be cautious in 166 + using the same port for notifications for more than one name. 167 + .Pp 168 + A notification message has an empty message body. 169 + The msgh_id field 170 + in the mach message header will have the value of the notification 171 + token. 172 + If a port is reused for multiple notification registrations, 173 + the msgh_id value may be used to determine which name generated 174 + the notification. 175 + .Ss notify_register_file_descriptor 176 + Register for notification by a write to a file descriptor. 177 + .Pp 178 + By default, a new file descriptor is created and a pointer to it 179 + is returned as the value of the "notify_fd" parameter. 180 + A file descriptor 181 + created by a previous call to this routine may be used for notifications 182 + if a pointer to that file descriptor is passed in to the routine and 183 + NOTIFY_REUSE is set in the flags parameter. 184 + .Pp 185 + Note that the kernel limits the buffer space for queued writes on a 186 + file descriptor. 187 + If it is important that notifications should not be 188 + lost due to queue overflow, clients should service messages quickly, 189 + and be cautious in using the same file descriptor for notifications 190 + for more than one name. 191 + .Pp 192 + Notifications are delivered by an integer value written to the 193 + file descriptor. 194 + The value is sent in network byte order. 195 + When converted to host byte order, for example by using 196 + .Fn ntohl , 197 + it will match the notification token 198 + for which the notification was generated. 199 + .Ss notify_check 200 + Checks if any notifications have been posted for a name. 201 + The output 202 + parameter "check" is set to 0 for false, 1 for true. 203 + A true indication is 204 + returned the first time notify_check is called for a token. 205 + Subsequent calls 206 + give a true indication when notifications have been posted for the name 207 + associated with the notification token. 208 + .Pp 209 + .Fn notify_check 210 + may be used with any notification token produced by any of the notification 211 + registration routines. 212 + A fast check based on a shared memory implementation 213 + is used when the token was generated by 214 + .Fn notify_register_check . 215 + Other tokens are checked by a call to the notification server. 216 + .Ss notify_set_state 217 + Set a 64-bit unsigned integer variable associated with a token. 218 + .Pp 219 + Each registered notification key has an associated 64-bit integer variable, 220 + which may be set using this routine and examined using the 221 + .Fn notify_get_state 222 + routine. 223 + The state variable is free to be used by clients of the notification API. 224 + It may be used to synchronize state information between cooperating processes or threads. 225 + (Available in Mac OS X 10.5 or later.) 226 + .Ss notify_get_state 227 + Get the 64-bit unsigned integer value associated with a token. 228 + The default value of a state variable is zero. 229 + (Available in Mac OS X 10.5 or later.) 230 + .Ss notify_suspend 231 + Suspends delivery of notifications for a notification token. 232 + Any notifications corresponding to a token that are posted while it is suspended 233 + will be coalesced, and pended until notifications are resumed using 234 + .Fn notify_resume . 235 + .Pp 236 + Calls to 237 + .Fn notify_suspend 238 + may be nested. 239 + Notifications will resume only when a matching number of calls are made to 240 + .Fn notify_resume . 241 + .Ss notify_resume 242 + Removes one level of suspension for a token previously suspended by a call to 243 + .Fn notify_suspend . 244 + When resumed, notifications will be delivered normally. 245 + A single notification will be generated if any notifications were pended while the token was suspended. 246 + .Ss notify_cancel 247 + Cancel notification and free resources associated with a notification 248 + token. 249 + Mach ports and file descriptor associated with a token are released 250 + (deallocated or closed) when all registration tokens associated with 251 + the port or file descriptor have been cancelled. 252 + .Pp 253 + .Ss notify_is_valid_token 254 + Determines if an integer value is valid for a current registration. 255 + Negative integers are never valid. 256 + A positive or zero value is valid if the current process has a registration associated with the given value. 257 + .Sh NAMESPACE CONVENTIONS 258 + Names in the namespace must be NULL-terminated. 259 + Names should be encoded as UTF-8 strings. 260 + .Pp 261 + The namespace supported by the system is unstructured, but users of 262 + this API are highly encouraged to follow the reverse-ICANN domain 263 + name convention used for Java package names and for System Preferences 264 + on Mac OS X. 265 + For example, "com.mydomain.example.event". 266 + .Pp 267 + Apple reserves the portion 268 + of the namespace prefixed by "com.apple.". 269 + This policy is not 270 + enforced in the current implementation, but may be in the future. 271 + .Pp 272 + Names in the space "user.uid.UID", where UID is a numeric user ID number 273 + are reserved for processes with that UID. 274 + Names in this protected space may only be accessed or modified by processes 275 + with the effective UID specified as the UID in the name. 276 + The name "user.uid.UID" is protected for the given UID, as are any 277 + names of the form "user.uid.UID.<sub-path>". 278 + In the latter case, the name must have a dot character following the UID. 279 + .Pp 280 + Third party developers are encouraged to choose a prefix for names 281 + that will avoid conflicts in the shared namespace. 282 + .Pp 283 + The portion of the namespace prefixed by the string "self." is set aside 284 + for private use by applications. 285 + That is, each client may use that part 286 + of the namespace for intra-process notifications. 287 + These notifications 288 + are private to each individual process and are not propagated between 289 + processes. 290 + .Sh USAGE EXAMPLES 291 + A notification producer. 292 + .Pp 293 + #include <notify.h> 294 + ... 295 + .Pp 296 + notify_post("com.eg.random.event"); 297 + .Pp 298 + A client using notify_check() to determine when to invalidate a cache. 299 + .Pp 300 + #include <stdio.h> 301 + #include <stdlib.h> 302 + #include <notify.h> 303 + .Pp 304 + int 305 + main(int argc, char *argv[]) 306 + { 307 + uint32_t status; 308 + int token, check; 309 + .Pp 310 + status = notify_register_check("com.eg.update", &token); 311 + if (status != NOTIFY_STATUS_OK) 312 + { 313 + fprintf(stderr, "registration failed (%u)\\n", status); 314 + exit(status); 315 + } 316 + .Pp 317 + build_my_cache(); 318 + .Pp 319 + ... 320 + .Pp 321 + status = notify_check(token, &check); 322 + if ((status == NOTIFY_STATUS_OK) && (check != 0)) 323 + { 324 + /* An update has occurred - invalidate the cache */ 325 + reset_my_cache(); 326 + } 327 + .Pp 328 + ... 329 + .Pp 330 + A client using file descriptor notifications. 331 + .Pp 332 + #include <stdio.h> 333 + #include <stdlib.h> 334 + #include <string.h> 335 + #include <errno.h> 336 + #include <sys/types.h> 337 + #include <sys/time.h> 338 + #include <unistd.h> 339 + #include <notify.h> 340 + .Pp 341 + int 342 + main(int argc, char *argv[]) 343 + { 344 + uint32_t status; 345 + int nf, rtoken, qtoken, t, ret; 346 + fd_set readfds; 347 + .Pp 348 + status = notify_register_file_descriptor("com.eg.random.event", 349 + &nf, 0, &rtoken); 350 + if (status != NOTIFY_STATUS_OK) 351 + { 352 + fprintf(stderr, "registration failed (%u)\\n", status); 353 + exit(status); 354 + } 355 + .Pp 356 + status = notify_register_file_descriptor("com.eg.random.quit", 357 + &nf, NOTIFY_REUSE, &qtoken); 358 + if (status != NOTIFY_STATUS_OK) 359 + { 360 + fprintf(stderr, "registration failed (%u)\\n", status); 361 + exit(status); 362 + } 363 + .Pp 364 + FD_ZERO(&readfds); 365 + FD_SET(nf, &readfds); 366 + .Pp 367 + for (;;) 368 + { 369 + ret = select(nf+1, &readfds, NULL, NULL, NULL); 370 + if (ret <= 0) continue; 371 + if (!FD_ISSET(nf, &readfds)) continue; 372 + .Pp 373 + status = read(nf, &t, sizeof(int)); 374 + if (status < 0) 375 + { 376 + perror("read"); 377 + break; 378 + } 379 + .Pp 380 + t = ntohl(t); 381 + .Pp 382 + if (t == rtoken) printf("random event\\n"); 383 + else if (t == qtoken) break; 384 + } 385 + .Pp 386 + printf("shutting down\\n"); 387 + notify_cancel(rtoken); 388 + notify_cancel(qtoken); 389 + exit(0); 390 + } 391 + .Pp 392 + A client using dispatch notifications. 393 + .Pp 394 + #include <stdio.h> 395 + #include <stdlib.h> 396 + #include <notify.h> 397 + #include <dispatch/dispatch.h> 398 + .Pp 399 + int 400 + main(void) 401 + { 402 + uint32_t status; 403 + int token; 404 + .Pp 405 + status = notify_register_dispatch("com.eg.random.event", &token, 406 + dispatch_get_main_queue(), ^(int t) { 407 + printf("com.eg.random.event received!\\n"); }); 408 + .Pp 409 + dispatch_main(); 410 + exit(0); 411 + } 412 + .Sh HISTORY 413 + These functions first appeared in 414 + Mac OS X 10.3. 415 + .Sh SEE ALSO 416 + .Xr ntohl 3 , 417 + .Xr read 2 , 418 + .Xr select 2 , 419 + .Xr signal 3
+338
libnotify/notify.h
··· 1 + /* 2 + * Copyright (c) 2003-2010 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * Portions Copyright (c) 2003-2010 Apple Inc. All Rights Reserved. 7 + * 8 + * This file contains Original Code and/or Modifications of Original Code 9 + * as defined in and that are subject to the Apple Public Source License 10 + * Version 2.0 (the 'License'). You may not use this file except in 11 + * compliance with the License. Please obtain a copy of the License at 12 + * http://www.opensource.apple.com/apsl/ and read it before using this 13 + * file. 14 + * 15 + * The Original Code and all software distributed under the License are 16 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 17 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 18 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 19 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 20 + * Please see the License for the specific language governing rights and 21 + * limitations under the License. 22 + * 23 + * @APPLE_LICENSE_HEADER_END@ 24 + */ 25 + 26 + #ifndef __NOTIFICATION_H__ 27 + #define __NOTIFICATION_H__ 28 + 29 + #include <sys/cdefs.h> 30 + #include <stdint.h> 31 + #include <mach/message.h> 32 + #include <Availability.h> 33 + #ifdef __BLOCKS__ 34 + #include <dispatch/dispatch.h> 35 + #endif /* __BLOCKS__ */ 36 + 37 + /*! @header 38 + * These routines allow processes to exchange stateless notification events. 39 + * Processes post notifications to a single system-wide notification server, 40 + * which then distributes notifications to client processes that have 41 + * registered to receive those notifications, including processes run by 42 + * other users. 43 + * 44 + * Notifications are associated with names in a namespace shared by all 45 + * clients of the system. Clients may post notifications for names, and 46 + * may monitor names for posted notifications. Clients may request 47 + * notification delivery by a number of different methods. 48 + * 49 + * Clients desiring to monitor names in the notification system must 50 + * register with the system, providing a name and other information 51 + * required for the desired notification delivery method. Clients are 52 + * given an integer token representing the registration. 53 + * 54 + * Note that the kernel provides limited queues for mach message and file 55 + * descriptor messages. It is important to make sure that clients read 56 + * mach ports and file descriptors frequently to prevent messages from 57 + * being lost due to resource limitations. Clients that use signal-based 58 + * notification should be aware that signals are not delivered to 59 + * a process while it is running in a signal handler. This may affect 60 + * the delivery of signals in close succession. 61 + * 62 + * Notifications may be coalesced in some cases. Multiple events posted 63 + * for a name in rapid succession may result in a single notification sent 64 + * to clients registered for notification for that name. Clients checking 65 + * for changes using the notify_check() routine cannot determine if 66 + * more than one event pas been posted since a previous call to 67 + * notify_check() for that name. 68 + * 69 + * "False positives" may occur in notify_check() when used with a token 70 + * generated by notify_register_check() due to implementation constraints. 71 + * This behavior may vary in future releases. 72 + * 73 + * Synchronization between two processes may be achieved using the 74 + * notify_set_state() and notify_get_state() routines. 75 + */ 76 + 77 + /*! @defineblock Status Codes 78 + * Status codes returned by the API. 79 + */ 80 + #define NOTIFY_STATUS_OK 0 81 + #define NOTIFY_STATUS_INVALID_NAME 1 82 + #define NOTIFY_STATUS_INVALID_TOKEN 2 83 + #define NOTIFY_STATUS_INVALID_PORT 3 84 + #define NOTIFY_STATUS_INVALID_FILE 4 85 + #define NOTIFY_STATUS_INVALID_SIGNAL 5 86 + #define NOTIFY_STATUS_INVALID_REQUEST 6 87 + #define NOTIFY_STATUS_NOT_AUTHORIZED 7 88 + #define NOTIFY_STATUS_FAILED 1000000 89 + /*! @/defineblock */ 90 + 91 + /*! 92 + * Flag bits used for registration. 93 + */ 94 + #define NOTIFY_REUSE 0x00000001 95 + 96 + 97 + /*! 98 + * Token values are zero or positive integers. 99 + * NOTIFY_TOKEN_INVALID is useful as an initial value for 100 + * a token value passed as an in/out parameter to one of 101 + * the registration routines below. 102 + */ 103 + #define NOTIFY_TOKEN_INVALID -1 104 + 105 + __BEGIN_DECLS 106 + 107 + /*! 108 + * Post a notification for a name. 109 + * 110 + * This is the only call that is required for a notification producer. 111 + * Returns status. 112 + */ 113 + uint32_t notify_post(const char *name); 114 + 115 + 116 + #ifdef __BLOCKS__ 117 + typedef void (^notify_handler_t)(int token); 118 + 119 + /*! 120 + * @function notify_register 121 + * @abstract Request notification delivery to a dispatch queue. 122 + * @discussion When notifications are received by the process, the notify 123 + * subsystem will deliver the registered Block to the target 124 + * dispatch queue. Notification blocks are not re-entrant, 125 + * and subsequent notification Blocks will not be delivered 126 + * for the same registration until the previous Block has 127 + * returned. 128 + * @param name (input) The notification name. 129 + * @param out_token (output) The registration token. 130 + * @param queue (input) The dispatch queue to which the Block is submitted. 131 + * The dispatch queue is retained by the notify subsystem while 132 + * the notification is registered, and will be released when 133 + * notification is canceled. 134 + * @param block (input) The Block to invoke on the dispatch queue in response 135 + * to a notification. The notification token is passed to the 136 + * Block as an argument so that the callee can modify the state 137 + * of the notification or cancel the registration. 138 + * @result Returns status. 139 + */ 140 + uint32_t notify_register_dispatch(const char *name, int *out_token, dispatch_queue_t queue, notify_handler_t handler) 141 + __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_3_2); 142 + #endif /* __BLOCKS__ */ 143 + 144 + /*! 145 + * Creates a registration token be used with notify_check(), 146 + * but no active notifications will be delivered. 147 + * 148 + * @param name 149 + * (input) notification name 150 + * @param out_token 151 + * (output) registration token 152 + * @result Returns status. 153 + */ 154 + uint32_t notify_register_check(const char *name, int *out_token); 155 + 156 + /*! 157 + * Request notification delivery by UNIX signal. 158 + * 159 + * A client may request signal notification for multiple names. After a signal 160 + * is delivered, the notify_check() routine may be called with each notification 161 + * token to determine which name (if any) generated the signal notification. 162 + * 163 + * @param name (input) notification name 164 + * @param sig (input) signal number (see signal(3)) 165 + * @param out_token (output) notification token 166 + * @result Returns status. 167 + */ 168 + uint32_t notify_register_signal(const char *name, int sig, int *out_token); 169 + 170 + /*! 171 + * Request notification by mach message. 172 + * 173 + * Notifications are delivered by an empty message sent to a mach port. 174 + * By default, a new port is allocated and a pointer to it is returned 175 + * as the value of "notify_port". A mach port previously returned by a 176 + * call to this routine may be used for notifications if a pointer to that 177 + * port is passed in to the routine and NOTIFY_REUSE is set in the flags 178 + * parameter. The notification service must be able to extract send 179 + * rights to the port. 180 + * 181 + * Note that the kernel limits the size of the message queue for any port. 182 + * If it is important that notifications should not be lost due to queue 183 + * overflow, clients should service messages quickly, and be careful about 184 + * using the same port for notifications for more than one name. 185 + * 186 + * A notification message has an empty message body. The msgh_id field 187 + * in the mach message header will have the value of the notification 188 + * token. If a port is reused for multiple notification registrations, 189 + * the msgh_id value may be used to determine which name generated 190 + * the notification. 191 + * 192 + * @param name 193 + * (input) notification name 194 + * @param out_token 195 + * (output) notification token 196 + * @param notify_port 197 + * (input/output) pointer to a mach port 198 + * @result Returns status. 199 + */ 200 + uint32_t notify_register_mach_port(const char *name, mach_port_t *notify_port, int flags, int *out_token); 201 + 202 + /* 203 + * Request notification by a write to a file descriptor. 204 + * 205 + * Notifications are delivered by a write to a file descriptor. 206 + * By default, a new file descriptor is created and a pointer to it 207 + * is returned as the value of "notify_fd". A file descriptor created 208 + * by a previous call to this routine may be used for notifications if 209 + * a pointer to that file descriptor is passed in to the routine and 210 + * NOTIFY_REUSE is set in the flags parameter. 211 + * 212 + * Note that the kernel limits the buffer space for queued writes on a 213 + * file descriptor. If it is important that notifications should not be 214 + * lost due to queue overflow, clients should service messages quickly, 215 + * and be careful about using the same file descriptor for notifications 216 + * for more than one name. 217 + * 218 + * Notifications are delivered by an integer value written to the 219 + * file descriptor. The value will match the notification token 220 + * for which the notification was generated. 221 + * 222 + * @param name 223 + * (input) notification name 224 + * @param out_token 225 + * (output) notification token 226 + * @param notify_fd 227 + * (input/output) pointer to a file descriptor 228 + * @result Returns status. 229 + */ 230 + uint32_t notify_register_file_descriptor(const char *name, int *notify_fd, int flags, int *out_token); 231 + 232 + /*! 233 + * Check if any notifications have been posted. 234 + * 235 + * Output parameter check is set to 0 for false, 1 for true. Returns status. 236 + * check is set to true the first time notify_check is called for a token. 237 + * Subsequent calls set check to true when notifications have been posted for 238 + * the name associated with the notification token. This routine is independent 239 + * of notify_post(). That is, check will be true if an application calls 240 + * notify_post() for a name and then calls notify_check() for a token associated 241 + * with that name. 242 + * 243 + * @param token 244 + * (input)notification token 245 + * @param check 246 + * (output) true/false indication 247 + * @result Returns status. 248 + */ 249 + uint32_t notify_check(int token, int *check); 250 + 251 + /*! 252 + * Cancel notification and free resources associated with a notification 253 + * token. Mach ports and file descriptor associated with a token are released 254 + * (deallocated or closed) when all registration tokens associated with 255 + * the port or file descriptor have been cancelled. 256 + * 257 + * @param token 258 + * (input) notification token 259 + * @result Returns status. 260 + */ 261 + uint32_t notify_cancel(int token); 262 + 263 + /*! 264 + * Suspend delivery of notifications for a token. Notifications for this token will be 265 + * pended and coalesced, then delivered following a matching call to notify_resume. 266 + * Calls to notify_suspend may be nested. Notifications remain suspended until 267 + * an equal number of calls have been made to notify_resume. 268 + * 269 + * @param token 270 + * (input) notification token 271 + * @result Returns status. 272 + */ 273 + uint32_t notify_suspend(int token) 274 + __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0); 275 + 276 + /*! 277 + * Removes one level of suspension for a token previously suspended 278 + * by a call to notify_suspend. Notifications will resume when a matching 279 + * call to notify_resume is made for each previous call to notify_suspend. 280 + * Notifications posted while a token is suspended are coalesced into 281 + * a single notification sent following a resumption. 282 + * 283 + * @param token 284 + * (input) notification token 285 + * @result Returns status. 286 + */ 287 + uint32_t notify_resume(int token) 288 + __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0); 289 + 290 + /*! 291 + * Set or get a state value associated with a notification token. 292 + * Each key in the notification namespace has an associated integer value available 293 + * for use by clients as for application-specific purposes. A common usage is to 294 + * allow two processes or threads to synchronize their activities. For example, a 295 + * server process may need send a notification when a resource becomes available. 296 + * A client process can register for the notification, but when it starts up it will 297 + * not know whether the resource is available. The server can set the state value, 298 + * and the client can check the value at startup time to synchronize with the server. 299 + * 300 + * Set the 64-bit integer state value. 301 + * 302 + * @param token 303 + * (input) notification token 304 + * @param state64 305 + * (input) 64-bit unsigned integer value 306 + * @result Returns status. 307 + */ 308 + uint32_t notify_set_state(int token, uint64_t state64) 309 + __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0); 310 + 311 + /*! 312 + * Get the 64-bit integer state value. 313 + * 314 + * @param token 315 + * (input) notification token 316 + * @param state64 317 + * (output) 64-bit unsigned integer value 318 + * @result Returns status. 319 + */ 320 + uint32_t notify_get_state(int token, uint64_t *state64) 321 + __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0); 322 + 323 + /*! 324 + * Determine if a token is valid (currently registered). 325 + * Negative integer values are always invalid. Positive or 326 + * zero values are valid only if they are associated with an 327 + * existing registratiom. 328 + * 329 + * @param val 330 + * (input) integer value 331 + * @result Returns true if the value is a valid token, false otherwise. 332 + */ 333 + bool notify_is_valid_token(int val) 334 + __OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0); 335 + 336 + __END_DECLS 337 + 338 + #endif /* __NOTIFICATION_H__ */
+1
libnotify/notify_cancel.3
··· 1 + .so man3/notify.3
+1
libnotify/notify_check.3
··· 1 + .so man3/notify.3
+2465
libnotify/notify_client.c
··· 1 + /* 2 + * Copyright (c) 2003-2012 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #include <assert.h> 25 + #include <sys/types.h> 26 + #include <sys/stat.h> 27 + #include <stdio.h> 28 + #include <stdlib.h> 29 + #include <unistd.h> 30 + #include <signal.h> 31 + #include <sys/socket.h> 32 + #include <netinet/in.h> 33 + #include <sys/un.h> 34 + #include <sys/ipc.h> 35 + #include <sys/signal.h> 36 + #include <sys/syslimits.h> 37 + #include <mach/mach.h> 38 + #include <mach/mach_time.h> 39 + #include <sys/mman.h> 40 + #include <sys/fcntl.h> 41 + #include <sys/time.h> 42 + #include <bootstrap_priv.h> 43 + #include <errno.h> 44 + #include <pthread.h> 45 + #include <TargetConditionals.h> 46 + #include <AvailabilityMacros.h> 47 + #include <libkern/OSAtomic.h> 48 + #include <Block.h> 49 + #include <dispatch/dispatch.h> 50 + #include <dispatch/private.h> 51 + #include <_simple.h> 52 + 53 + #include "libnotify.h" 54 + 55 + #include "notify.h" 56 + #include "notify_internal.h" 57 + #include "notify_ipc.h" 58 + #include "notify_private.h" 59 + 60 + #define INITIAL_TOKEN_ID 0 61 + 62 + // <rdar://problem/10385540> 63 + WEAK_IMPORT_ATTRIBUTE bool _dispatch_is_multithreaded(void); 64 + 65 + #define EVENT_INIT 0 66 + #define EVENT_REGEN 1 67 + 68 + #define SELF_PREFIX "self." 69 + #define SELF_PREFIX_LEN 5 70 + 71 + #define COMMON_SELF_PORT_KEY "self.com.apple.system.notify.common" 72 + 73 + #define MULTIPLE_REGISTRATION_WARNING_TRIGGER 20 74 + 75 + extern uint32_t _notify_lib_peek(notify_state_t *ns, pid_t pid, int token, int *val); 76 + extern int *_notify_lib_check_addr(notify_state_t *ns, pid_t pid, int token); 77 + 78 + #define CLIENT_TOKEN_TABLE_SIZE 256 79 + 80 + #define NID_UNSET 0xffffffffffffffffL 81 + #define NID_CALLED_ONCE 0xfffffffffffffffeL 82 + 83 + #define NO_LOCK 1 84 + 85 + typedef struct 86 + { 87 + uint32_t refcount; 88 + uint64_t name_id; 89 + } name_table_node_t; 90 + 91 + typedef struct 92 + { 93 + uint32_t refcount; 94 + const char *name; 95 + size_t namelen; 96 + name_table_node_t *name_node; 97 + uint32_t token; 98 + uint32_t slot; 99 + uint32_t val; 100 + uint32_t flags; 101 + int fd; 102 + int signal; 103 + mach_port_t mp; 104 + uint32_t client_id; 105 + uint64_t set_state_time; 106 + uint64_t set_state_val; 107 + char * path; 108 + int path_flags; 109 + dispatch_queue_t queue; 110 + notify_handler_t block; 111 + } token_table_node_t; 112 + 113 + /* FORWARD */ 114 + static void _notify_lib_regenerate(int src); 115 + static void notify_retain_mach_port(mach_port_t mp, int mine); 116 + static void _notify_dispatch_handle(mach_port_t port); 117 + static notify_state_t *_notify_lib_self_state(); 118 + 119 + #if TARGET_IPHONE_SIMULATOR 120 + const char * 121 + _notify_shm_id() 122 + { 123 + static dispatch_once_t once; 124 + static char *shm_id; 125 + 126 + dispatch_once(&once, ^{ 127 + // According to documentation, our shm_id must be no more than 31 characters long 128 + // but in practice, even 31 characters is too long (<rdar://problem/16860882>), 129 + // so we jump through some hoops to make a smaller string based on our UDID. 130 + const char *udid = getenv("SIMULATOR_UDID"); 131 + if (udid && strlen(udid) == 36) { 132 + char scratch[34]; // 32 characters, 2 NUL 133 + 134 + // 01234567890123456789012345678901234567890 135 + // UUUUUUUU-UUUU-UUUU-LLLL-LLLLLLLLLLLL 136 + memcpy(scratch, udid, 8); 137 + memcpy(scratch+8, udid+9, 4); 138 + memcpy(scratch+12, udid+14, 4); 139 + scratch[16] = '\0'; 140 + 141 + memcpy(scratch+17, udid+19, 4); 142 + memcpy(scratch+21, udid+24, 12); 143 + scratch[33] = '\0'; 144 + 145 + // If the input is invalid, these will end up being undefined 146 + // values, but they'll still be values we can use. 147 + uint64_t upper = strtoull(scratch, NULL, 16); 148 + uint64_t lower = strtoull(scratch + 17, NULL, 16); 149 + 150 + const char *c64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; 151 + scratch[0] = c64[(upper >> 57) & 0xf]; 152 + scratch[1] = c64[(upper >> 50) & 0xf]; 153 + scratch[2] = c64[(upper >> 43) & 0xf]; 154 + scratch[3] = c64[(upper >> 36) & 0xf]; 155 + scratch[4] = c64[(upper >> 29) & 0xf]; 156 + scratch[5] = c64[(upper >> 22) & 0xf]; 157 + scratch[6] = c64[(upper >> 15) & 0xf]; 158 + scratch[7] = c64[(upper >> 8) & 0xf]; 159 + scratch[8] = c64[(upper >> 1) & 0xf]; 160 + // Drop a bit on the floor, but that probably doesn't matter. It does not need to be reversible 161 + 162 + scratch[10] = c64[(lower >> 57) & 0xf]; 163 + scratch[11] = c64[(lower >> 50) & 0xf]; 164 + scratch[12] = c64[(lower >> 43) & 0xf]; 165 + scratch[13] = c64[(lower >> 36) & 0xf]; 166 + scratch[14] = c64[(lower >> 29) & 0xf]; 167 + scratch[15] = c64[(lower >> 22) & 0xf]; 168 + scratch[16] = c64[(lower >> 15) & 0xf]; 169 + scratch[17] = c64[(lower >> 8) & 0xf]; 170 + scratch[18] = c64[(lower >> 1) & 0xf]; 171 + // Drop a bit on the floor, but that probably doesn't matter. It does not need to be reversible 172 + 173 + scratch[19] = '\0'; 174 + 175 + asprintf(&shm_id, "sim.not.%s", scratch); 176 + assert(shm_id); 177 + } 178 + 179 + if (!shm_id) { 180 + shm_id = "apple.shm.notification_center"; 181 + } 182 + }); 183 + 184 + return shm_id; 185 + } 186 + #endif 187 + 188 + static int 189 + shm_attach(uint32_t size) 190 + { 191 + int32_t shmfd; 192 + notify_globals_t globals = _notify_globals(); 193 + 194 + shmfd = shm_open(SHM_ID, O_RDONLY, 0); 195 + if (shmfd == -1) return -1; 196 + 197 + globals->shm_base = mmap(NULL, size, PROT_READ, MAP_SHARED, shmfd, 0); 198 + close(shmfd); 199 + 200 + if (globals->shm_base == (uint32_t *)-1) globals->shm_base = NULL; 201 + if (globals->shm_base == NULL) return -1; 202 + 203 + return 0; 204 + } 205 + 206 + #ifdef NOTDEF 207 + static void 208 + shm_detach(void) 209 + { 210 + if (shm_base != NULL) 211 + { 212 + shmdt(shm_base); 213 + shm_base = NULL; 214 + } 215 + } 216 + #endif 217 + 218 + /* 219 + * Initialization of global variables. Called once per process. 220 + */ 221 + void 222 + _notify_init_globals(void * /* notify_globals_t */ _globals) 223 + { 224 + notify_globals_t globals = _globals; 225 + 226 + pthread_mutex_init(&globals->notify_lock, NULL); 227 + globals->token_id = INITIAL_TOKEN_ID; 228 + globals->notify_common_token = -1; 229 + } 230 + 231 + #if !_NOTIFY_HAS_ALLOC_ONCE 232 + notify_globals_t 233 + _notify_globals_impl(void) 234 + { 235 + static dispatch_once_t once; 236 + static notify_globals_t globals; 237 + dispatch_once(&once, ^{ 238 + globals = calloc(1, sizeof(struct notify_globals_s)); 239 + _notify_init_globals(globals); 240 + }); 241 + return globals; 242 + } 243 + #endif 244 + 245 + /* 246 + * _notify_lib_init is called for each new registration (event = EVENT_INIT). 247 + * It is also called to re-initialize when the library has detected that 248 + * notifyd has restarted (event = EVENT_REGEN). 249 + */ 250 + static uint32_t 251 + _notify_lib_init(uint32_t event) 252 + { 253 + __block kern_return_t kstatus; 254 + __block bool first = false; 255 + int status, cid; 256 + uint64_t state; 257 + 258 + notify_globals_t globals = _notify_globals(); 259 + 260 + /* notifyd sets NOTIFY_OPT_DISABLE to avoid re-entrancy issues */ 261 + if (globals->client_opts & NOTIFY_OPT_DISABLE) return NOTIFY_STATUS_FAILED; 262 + 263 + /* Look up the notifyd server port just once. */ 264 + kstatus = KERN_SUCCESS; 265 + dispatch_once(&globals->notify_server_port_once, ^{ 266 + first = true; 267 + kstatus = bootstrap_look_up2(bootstrap_port, NOTIFY_SERVICE_NAME, &globals->notify_server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER); 268 + }); 269 + 270 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 271 + 272 + pthread_mutex_lock(&globals->notify_lock); 273 + 274 + /* 275 + * _dispatch_is_multithreaded() tells us if it is safe to use dispatch queues for 276 + * a shared port for all registratios, and to watch for notifyd exiting / restarting. 277 + * 278 + * Note that _dispatch_is_multithreaded is weak imported, <rdar://problem/10385540> 279 + */ 280 + if (_dispatch_is_multithreaded) 281 + { 282 + if (_dispatch_is_multithreaded()) globals->client_opts |= (NOTIFY_OPT_DEMUX | NOTIFY_OPT_REGEN); 283 + } 284 + 285 + /* 286 + * Look up the server's PID and supported IPC version on the first call, 287 + * and on a regeneration event (when the server has restarted). 288 + */ 289 + if (first || (event == EVENT_REGEN)) 290 + { 291 + pid_t last_pid = globals->notify_server_pid; 292 + 293 + globals->notify_ipc_version = 0; 294 + globals->notify_server_pid = 0; 295 + 296 + kstatus = _notify_server_register_plain(globals->notify_server_port, NOTIFY_IPC_VERSION_NAME, NOTIFY_IPC_VERSION_NAME_LEN, &cid, &status); 297 + if ((kstatus == KERN_SUCCESS) && (status == NOTIFY_STATUS_OK)) 298 + { 299 + kstatus = _notify_server_get_state(globals->notify_server_port, cid, &state, &status); 300 + if ((kstatus == KERN_SUCCESS) && (status == NOTIFY_STATUS_OK)) 301 + { 302 + globals->notify_ipc_version = state; 303 + state >>= 32; 304 + globals->notify_server_pid = state; 305 + } 306 + 307 + _notify_server_cancel(globals->notify_server_port, cid, &status); 308 + 309 + if ((last_pid == globals->notify_server_pid) && (event == EVENT_REGEN)) 310 + { 311 + pthread_mutex_unlock(&globals->notify_lock); 312 + return NOTIFY_STATUS_INVALID_REQUEST; 313 + } 314 + } 315 + 316 + if (globals->server_proc_source != NULL) 317 + { 318 + dispatch_source_cancel(globals->server_proc_source); 319 + dispatch_release(globals->server_proc_source); 320 + globals->server_proc_source = NULL; 321 + } 322 + } 323 + 324 + if (globals->notify_ipc_version < 2) 325 + { 326 + /* regen is not supported below version 2 */ 327 + globals->client_opts &= ~NOTIFY_OPT_REGEN; 328 + } 329 + 330 + /* 331 + * Create a source (DISPATCH_SOURCE_TYPE_PROC) to invoke _notify_lib_regenerate if notifyd restarts. 332 + * Available in IPC version 2. 333 + */ 334 + if ((globals->server_proc_source == NULL) && (globals->client_opts & NOTIFY_OPT_REGEN) && (globals->notify_server_pid != 0)) 335 + { 336 + 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)); 337 + dispatch_source_set_event_handler(globals->server_proc_source, ^{ _notify_lib_regenerate(1); }); 338 + dispatch_resume(globals->server_proc_source); 339 + } 340 + 341 + /* 342 + * Create the shared multiplex ports if NOTIFY_OPT_DEMUX is set. 343 + */ 344 + if ((globals->client_opts & NOTIFY_OPT_DEMUX) && (globals->notify_common_port == MACH_PORT_NULL)) 345 + { 346 + kern_return_t kr; 347 + task_t task = mach_task_self(); 348 + 349 + kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &globals->notify_common_port); 350 + if (kr == KERN_SUCCESS) 351 + { 352 + 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)); 353 + dispatch_source_set_event_handler(globals->notify_dispatch_source, ^{ 354 + notify_globals_t globals = _notify_globals(); 355 + _notify_dispatch_handle(globals->notify_common_port); 356 + }); 357 + dispatch_source_set_cancel_handler(globals->notify_dispatch_source, ^{ 358 + task_t task = mach_task_self(); 359 + notify_globals_t globals = _notify_globals(); 360 + mach_port_mod_refs(task, globals->notify_common_port, MACH_PORT_RIGHT_RECEIVE, -1); 361 + }); 362 + dispatch_resume(globals->notify_dispatch_source); 363 + } 364 + } 365 + 366 + pthread_mutex_unlock(&globals->notify_lock); 367 + 368 + if (globals->notify_common_port != MACH_PORT_NULL && (first || event == EVENT_REGEN)) 369 + { 370 + /* register the common port with notifyd */ 371 + status = notify_register_mach_port(COMMON_PORT_KEY, &globals->notify_common_port, NOTIFY_REUSE, &globals->notify_common_token); 372 + } 373 + 374 + return NOTIFY_STATUS_OK; 375 + } 376 + 377 + /* Reset all internal state at fork */ 378 + void 379 + _notify_fork_child(void) 380 + { 381 + notify_globals_t globals = _notify_globals(); 382 + 383 + _notify_init_globals(globals); 384 + 385 + /* 386 + * Expressly disable notify in the child side of a fork if it had 387 + * been initialized in the parent. Using notify in the child process 388 + * can lead to deadlock (see <rdar://problem/11498014>). 389 + * 390 + * Also disable notify in the forked child of a multi-threaded parent that 391 + * used dispatch, since notify will use dispatch, and that will blow up. 392 + * It's OK to make that check here by calling _dispatch_is_multithreaded(), 393 + * since we will actually be looking at the parent's state. 394 + */ 395 + if (globals->notify_server_port != MACH_PORT_NULL) globals->client_opts = NOTIFY_OPT_DISABLE; 396 + if (_dispatch_is_multithreaded) // weak imported symbol 397 + { 398 + if (_dispatch_is_multithreaded()) globals->client_opts = NOTIFY_OPT_DISABLE; 399 + } 400 + 401 + globals->self_state = NULL; 402 + globals->notify_server_port = MACH_PORT_NULL; 403 + globals->notify_ipc_version = 0; 404 + globals->notify_server_pid = 0; 405 + 406 + globals->token_table = NULL; 407 + globals->token_name_table = NULL; 408 + 409 + globals->fd_count = 0; 410 + globals->fd_clnt = NULL; 411 + globals->fd_srv = NULL; 412 + globals->fd_refcount = NULL; 413 + 414 + globals->mp_count = 0; 415 + globals->mp_list = NULL; 416 + globals->mp_refcount = NULL; 417 + globals->mp_mine = NULL; 418 + 419 + globals->shm_base = NULL; 420 + } 421 + 422 + static uint32_t 423 + 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) 424 + { 425 + token_table_node_t *t; 426 + name_table_node_t *n; 427 + uint32_t warn_count = 0; 428 + notify_globals_t globals = _notify_globals(); 429 + 430 + dispatch_once(&globals->token_table_once, ^{ 431 + globals->token_table = _nc_table_new(CLIENT_TOKEN_TABLE_SIZE); 432 + globals->token_name_table = _nc_table_new(CLIENT_TOKEN_TABLE_SIZE); 433 + }); 434 + 435 + if (globals->token_table == NULL) return -1; 436 + if (globals->token_name_table == NULL) return -1; 437 + if (name == NULL) return -1; 438 + 439 + t = (token_table_node_t *)calloc(1, sizeof(token_table_node_t)); 440 + if (t == NULL) return -1; 441 + 442 + t->refcount = 1; 443 + 444 + /* we will get t->name from the token_name_table */ 445 + t->name = NULL; 446 + 447 + t->namelen = namelen; 448 + t->token = token; 449 + t->slot = slot; 450 + t->val = 0; 451 + t->flags = flags; 452 + t->fd = fd; 453 + t->mp = mp; 454 + t->client_id = cid; 455 + 456 + if (lock != NO_LOCK) pthread_mutex_lock(&globals->notify_lock); 457 + _nc_table_insert_n(globals->token_table, t->token, t); 458 + 459 + /* check if we have this name in the name table */ 460 + n = _nc_table_find_get_key(globals->token_name_table, name, &(t->name)); 461 + if (n == NULL) 462 + { 463 + char *copy_name = strdup(name); 464 + if (copy_name == NULL) 465 + { 466 + free(t); 467 + if (lock != NO_LOCK) pthread_mutex_unlock(&globals->notify_lock); 468 + return -1; 469 + } 470 + 471 + t->name = (const char *)copy_name; 472 + 473 + /* create a new name table node */ 474 + n = (name_table_node_t *)calloc(1, sizeof(name_table_node_t)); 475 + if (n != NULL) 476 + { 477 + n->refcount = 1; 478 + n->name_id = nid; 479 + 480 + /* the name table node "owns" the name */ 481 + _nc_table_insert_pass(globals->token_name_table, copy_name, n); 482 + t->name_node = n; 483 + } 484 + } 485 + else 486 + { 487 + /* this token retains the name table node */ 488 + t->name_node = n; 489 + n->refcount++; 490 + 491 + if ((n->refcount % MULTIPLE_REGISTRATION_WARNING_TRIGGER) == 0) 492 + { 493 + warn_count = n->refcount; 494 + } 495 + } 496 + 497 + if (lock != NO_LOCK) pthread_mutex_unlock(&globals->notify_lock); 498 + 499 + if (warn_count > 0) 500 + { 501 + char *msg; 502 + asprintf(&msg, "notify name \"%s\" has been registered %d times - this may be a leak", name, warn_count); 503 + if (msg) 504 + _simple_asl_log(ASL_LEVEL_WARNING, "com.apple.notify", msg); 505 + free(msg); 506 + } 507 + 508 + return 0; 509 + } 510 + 511 + static token_table_node_t * 512 + token_table_find_retain(uint32_t token) 513 + { 514 + token_table_node_t *t; 515 + notify_globals_t globals = _notify_globals(); 516 + 517 + pthread_mutex_lock(&globals->notify_lock); 518 + 519 + t = (token_table_node_t *)_nc_table_find_n(globals->token_table, token); 520 + if (t != NULL) t->refcount++; 521 + 522 + pthread_mutex_unlock(&globals->notify_lock); 523 + 524 + return t; 525 + } 526 + 527 + static token_table_node_t * 528 + token_table_find_no_lock(uint32_t token) 529 + { 530 + notify_globals_t globals = _notify_globals(); 531 + return (token_table_node_t *)_nc_table_find_n(globals->token_table, token); 532 + } 533 + 534 + static name_table_node_t * 535 + name_table_find_retain_no_lock(const char *name) 536 + { 537 + name_table_node_t *n; 538 + notify_globals_t globals = _notify_globals(); 539 + 540 + n = (name_table_node_t *)_nc_table_find(globals->token_name_table, name); 541 + if (n != NULL) n->refcount++; 542 + 543 + return n; 544 + } 545 + 546 + static void 547 + name_table_release_no_lock(const char *name) 548 + { 549 + name_table_node_t *n; 550 + notify_globals_t globals = _notify_globals(); 551 + 552 + n = (name_table_node_t *)_nc_table_find(globals->token_name_table, name); 553 + if (n != NULL) 554 + { 555 + if (n->refcount > 0) n->refcount--; 556 + if (n->refcount == 0) 557 + { 558 + _nc_table_delete(globals->token_name_table, name); 559 + free(n); 560 + } 561 + } 562 + } 563 + 564 + static void 565 + name_table_set_nid(const char *name, uint64_t nid) 566 + { 567 + name_table_node_t *n; 568 + notify_globals_t globals = _notify_globals(); 569 + 570 + pthread_mutex_lock(&globals->notify_lock); 571 + 572 + n = (name_table_node_t *)_nc_table_find(globals->token_name_table, name); 573 + if (n != NULL) n->name_id = nid; 574 + 575 + pthread_mutex_unlock(&globals->notify_lock); 576 + } 577 + 578 + static void 579 + _notify_lib_regenerate_token(token_table_node_t *t) 580 + { 581 + uint32_t type; 582 + int status, new_slot; 583 + kern_return_t kstatus; 584 + mach_port_t port; 585 + uint64_t new_nid; 586 + size_t pathlen; 587 + 588 + if (t == NULL) return; 589 + if (t->name == NULL) return; 590 + if (t->flags & NOTIFY_FLAG_SELF) return; 591 + if ((t->flags & NOTIFY_FLAG_REGEN) == 0) return; 592 + if (!strcmp(t->name, COMMON_PORT_KEY)) return; 593 + 594 + notify_globals_t globals = _notify_globals(); 595 + 596 + port = MACH_PORT_NULL; 597 + if (t->flags & NOTIFY_TYPE_PORT) 598 + { 599 + port = globals->notify_common_port; 600 + } 601 + 602 + pathlen = 0; 603 + if (t->path != NULL) pathlen = strlen(t->path); 604 + type = t->flags & 0x000000ff; 605 + 606 + 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); 607 + 608 + if (kstatus != KERN_SUCCESS) status = NOTIFY_STATUS_FAILED; 609 + if (status != NOTIFY_STATUS_OK) return; 610 + 611 + t->slot = new_slot; 612 + 613 + /* reset the name_id in the name table node */ 614 + if (t->name_node != NULL) t->name_node->name_id = new_nid; 615 + } 616 + 617 + /* 618 + * Invoked when server has died. 619 + * Regenerates all registrations and state. 620 + */ 621 + static void 622 + _notify_lib_regenerate(int src) 623 + { 624 + void *tt; 625 + token_table_node_t *t; 626 + notify_globals_t globals = _notify_globals(); 627 + 628 + if ((globals->client_opts & NOTIFY_OPT_REGEN) == 0) return; 629 + 630 + /* _notify_lib_init returns an error if regeneration is unnecessary */ 631 + if (_notify_lib_init(EVENT_REGEN) == NOTIFY_STATUS_OK) 632 + { 633 + pthread_mutex_lock(&globals->notify_lock); 634 + 635 + tt = _nc_table_traverse_start(globals->token_table); 636 + while (tt != NULL) 637 + { 638 + t = _nc_table_traverse(globals->token_table, tt); 639 + if (t == NULL) break; 640 + _notify_lib_regenerate_token(t); 641 + } 642 + 643 + _nc_table_traverse_end(globals->token_table, tt); 644 + 645 + pthread_mutex_unlock(&globals->notify_lock); 646 + } 647 + } 648 + 649 + /* 650 + * Regenerate if the server PID (shared memory slot 0) has changed. 651 + */ 652 + static inline void 653 + regenerate_check() 654 + { 655 + notify_globals_t globals = _notify_globals(); 656 + 657 + if ((globals->client_opts & NOTIFY_OPT_REGEN) == 0) return; 658 + 659 + if ((globals->shm_base != NULL) && (globals->shm_base[0] != globals->notify_server_pid)) _notify_lib_regenerate(0); 660 + } 661 + 662 + /* notify_lock is required in notify_retain_file_descriptor */ 663 + static void 664 + notify_retain_file_descriptor(int clnt, int srv) 665 + { 666 + int x, i; 667 + notify_globals_t globals = _notify_globals(); 668 + 669 + if (clnt < 0) return; 670 + if (srv < 0) return; 671 + 672 + pthread_mutex_lock(&globals->notify_lock); 673 + 674 + x = -1; 675 + for (i = 0; (i < globals->fd_count) && (x < 0); i++) 676 + { 677 + if (globals->fd_clnt[i] == clnt) x = i; 678 + } 679 + 680 + if (x >= 0) 681 + { 682 + globals->fd_refcount[x]++; 683 + pthread_mutex_unlock(&globals->notify_lock); 684 + return; 685 + } 686 + 687 + x = globals->fd_count; 688 + globals->fd_count++; 689 + 690 + if (x == 0) 691 + { 692 + globals->fd_clnt = (int *)calloc(1, sizeof(int)); 693 + globals->fd_srv = (int *)calloc(1, sizeof(int)); 694 + globals->fd_refcount = (int *)calloc(1, sizeof(int)); 695 + } 696 + else 697 + { 698 + globals->fd_clnt = (int *)reallocf(globals->fd_clnt, globals->fd_count * sizeof(int)); 699 + globals->fd_srv = (int *)reallocf(globals->fd_srv, globals->fd_count * sizeof(int)); 700 + globals->fd_refcount = (int *)reallocf(globals->fd_refcount, globals->fd_count * sizeof(int)); 701 + } 702 + 703 + if ((globals->fd_clnt == NULL) || (globals->fd_srv == NULL) || (globals->fd_refcount == NULL)) 704 + { 705 + free(globals->fd_clnt); 706 + free(globals->fd_srv); 707 + free(globals->fd_refcount); 708 + globals->fd_count = 0; 709 + } 710 + else 711 + { 712 + globals->fd_clnt[x] = clnt; 713 + globals->fd_srv[x] = srv; 714 + globals->fd_refcount[x] = 1; 715 + } 716 + 717 + pthread_mutex_unlock(&globals->notify_lock); 718 + } 719 + 720 + /* notify_lock is NOT required in notify_release_file_descriptor */ 721 + static void 722 + notify_release_file_descriptor(int fd) 723 + { 724 + int x, i, j; 725 + notify_globals_t globals = _notify_globals(); 726 + 727 + if (fd < 0) return; 728 + 729 + x = -1; 730 + for (i = 0; (i < globals->fd_count) && (x < 0); i++) 731 + { 732 + if (globals->fd_clnt[i] == fd) x = i; 733 + } 734 + 735 + if (x < 0) return; 736 + 737 + if (globals->fd_refcount[x] > 0) globals->fd_refcount[x]--; 738 + if (globals->fd_refcount[x] > 0) return; 739 + 740 + close(globals->fd_clnt[x]); 741 + close(globals->fd_srv[x]); 742 + 743 + if (globals->fd_count == 1) 744 + { 745 + free(globals->fd_clnt); 746 + free(globals->fd_srv); 747 + free(globals->fd_refcount); 748 + globals->fd_count = 0; 749 + return; 750 + } 751 + 752 + for (i = x + 1, j = x; i < globals->fd_count; i++, j++) 753 + { 754 + globals->fd_clnt[j] = globals->fd_clnt[i]; 755 + globals->fd_srv[j] = globals->fd_srv[i]; 756 + globals->fd_refcount[j] = globals->fd_refcount[i]; 757 + } 758 + 759 + globals->fd_count--; 760 + 761 + globals->fd_clnt = (int *)reallocf(globals->fd_clnt, globals->fd_count * sizeof(int)); 762 + globals->fd_srv = (int *)reallocf(globals->fd_srv, globals->fd_count * sizeof(int)); 763 + globals->fd_refcount = (int *)reallocf(globals->fd_refcount, globals->fd_count * sizeof(int)); 764 + 765 + if ((globals->fd_clnt == NULL) || (globals->fd_srv == NULL) || (globals->fd_refcount == NULL)) 766 + { 767 + free(globals->fd_clnt); 768 + free(globals->fd_srv); 769 + free(globals->fd_refcount); 770 + globals->fd_count = 0; 771 + } 772 + } 773 + 774 + /* notify_lock is required in notify_retain_mach_port */ 775 + static void 776 + notify_retain_mach_port(mach_port_t mp, int mine) 777 + { 778 + int x, i; 779 + notify_globals_t globals = _notify_globals(); 780 + 781 + if (mp == MACH_PORT_NULL) return; 782 + 783 + pthread_mutex_lock(&globals->notify_lock); 784 + 785 + x = -1; 786 + for (i = 0; (i < globals->mp_count) && (x < 0); i++) 787 + { 788 + if (globals->mp_list[i] == mp) x = i; 789 + } 790 + 791 + if (x >= 0) 792 + { 793 + globals->mp_refcount[x]++; 794 + pthread_mutex_unlock(&globals->notify_lock); 795 + return; 796 + } 797 + 798 + x = globals->mp_count; 799 + globals->mp_count++; 800 + 801 + if (x == 0) 802 + { 803 + globals->mp_list = (mach_port_t *)calloc(1, sizeof(mach_port_t)); 804 + globals->mp_refcount = (int *)calloc(1, sizeof(int)); 805 + globals->mp_mine = (int *)calloc(1, sizeof(int)); 806 + } 807 + else 808 + { 809 + globals->mp_list = (mach_port_t *)reallocf(globals->mp_list, globals->mp_count * sizeof(mach_port_t)); 810 + globals->mp_refcount = (int *)reallocf(globals->mp_refcount, globals->mp_count * sizeof(int)); 811 + globals->mp_mine = (int *)reallocf(globals->mp_mine, globals->mp_count * sizeof(int)); 812 + } 813 + 814 + if ((globals->mp_list == NULL) || (globals->mp_refcount == NULL) || (globals->mp_mine == NULL)) 815 + { 816 + if (globals->mp_list != NULL) free(globals->mp_list); 817 + if (globals->mp_refcount != NULL) free(globals->mp_refcount); 818 + if (globals->mp_mine != NULL) free(globals->mp_mine); 819 + globals->mp_count = 0; 820 + } 821 + else 822 + { 823 + globals->mp_list[x] = mp; 824 + globals->mp_refcount[x] = 1; 825 + globals->mp_mine[x] = mine; 826 + } 827 + 828 + pthread_mutex_unlock(&globals->notify_lock); 829 + } 830 + 831 + /* notify_lock is NOT required in notify_release_mach_port */ 832 + static void 833 + notify_release_mach_port(mach_port_t mp, uint32_t flags) 834 + { 835 + int x, i; 836 + notify_globals_t globals = _notify_globals(); 837 + 838 + if (mp == MACH_PORT_NULL) return; 839 + 840 + x = -1; 841 + for (i = 0; (i < globals->mp_count) && (x < 0); i++) 842 + { 843 + if (globals->mp_list[i] == mp) x = i; 844 + } 845 + 846 + if (x < 0) return; 847 + 848 + if (globals->mp_refcount[x] > 0) globals->mp_refcount[x]--; 849 + if (globals->mp_refcount[x] > 0) return; 850 + 851 + if (globals->mp_mine[x] == 1) 852 + { 853 + mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_RECEIVE, -1); 854 + 855 + /* release send right if this is a self notification */ 856 + if (flags & NOTIFY_FLAG_SELF) mach_port_deallocate(mach_task_self(), mp); 857 + } 858 + 859 + if (flags & NOTIFY_FLAG_RELEASE_SEND) 860 + { 861 + /* multiplexed registration holds a send right in Libnotify */ 862 + mach_port_deallocate(mach_task_self(), mp); 863 + } 864 + 865 + if (globals->mp_count == 1) 866 + { 867 + if (globals->mp_list != NULL) free(globals->mp_list); 868 + if (globals->mp_refcount != NULL) free(globals->mp_refcount); 869 + if (globals->mp_mine != NULL) free(globals->mp_mine); 870 + globals->mp_count = 0; 871 + return; 872 + } 873 + 874 + for (i = x + 1; i < globals->mp_count; i++) 875 + { 876 + globals->mp_list[i - 1] = globals->mp_list[i]; 877 + globals->mp_refcount[i - 1] = globals->mp_refcount[i]; 878 + globals->mp_mine[i - 1] = globals->mp_mine[i]; 879 + } 880 + 881 + globals->mp_count--; 882 + 883 + globals->mp_list = (mach_port_t *)reallocf(globals->mp_list, globals->mp_count * sizeof(mach_port_t)); 884 + globals->mp_refcount = (int *)reallocf(globals->mp_refcount, globals->mp_count * sizeof(int)); 885 + globals->mp_mine = (int *)reallocf(globals->mp_mine, globals->mp_count * sizeof(int)); 886 + 887 + if ((globals->mp_list == NULL) || (globals->mp_refcount == NULL) || (globals->mp_mine == NULL)) 888 + { 889 + if (globals->mp_list != NULL) free(globals->mp_list); 890 + if (globals->mp_refcount != NULL) free(globals->mp_refcount); 891 + if (globals->mp_mine != NULL) free(globals->mp_mine); 892 + globals->mp_count = 0; 893 + } 894 + } 895 + 896 + static void 897 + token_table_release_no_lock(token_table_node_t *t) 898 + { 899 + notify_globals_t globals = _notify_globals(); 900 + 901 + if (t == NULL) return; 902 + 903 + if (t->refcount > 0) t->refcount--; 904 + if (t->refcount > 0) return; 905 + 906 + notify_release_file_descriptor(t->fd); 907 + notify_release_mach_port(t->mp, t->flags); 908 + 909 + if (t->block != NULL) 910 + { 911 + dispatch_async_f(t->queue, t->block, (dispatch_function_t)_Block_release); 912 + } 913 + 914 + t->block = NULL; 915 + 916 + if (t->queue != NULL) dispatch_release(t->queue); 917 + t->queue = NULL; 918 + 919 + _nc_table_delete_n(globals->token_table, t->token); 920 + name_table_release_no_lock(t->name); 921 + 922 + free(t->path); 923 + free(t); 924 + } 925 + 926 + static void 927 + token_table_release(token_table_node_t *t) 928 + { 929 + notify_globals_t globals = _notify_globals(); 930 + 931 + pthread_mutex_lock(&globals->notify_lock); 932 + token_table_release_no_lock(t); 933 + pthread_mutex_unlock(&globals->notify_lock); 934 + } 935 + 936 + static notify_state_t * 937 + _notify_lib_self_state() 938 + { 939 + notify_globals_t globals = _notify_globals(); 940 + 941 + dispatch_once(&globals->self_state_once, ^{ 942 + globals->self_state = _notify_lib_notify_state_new(NOTIFY_STATE_USE_LOCKS, 0); 943 + }); 944 + 945 + return globals->self_state; 946 + } 947 + 948 + /* SPI */ 949 + void 950 + notify_set_options(uint32_t opts) 951 + { 952 + notify_globals_t globals = _notify_globals(); 953 + 954 + /* NOTIFY_OPT_DISABLE can be unset with NOTIFY_OPT_ENABLE */ 955 + if (globals->client_opts & NOTIFY_OPT_DISABLE) 956 + { 957 + if ((opts & NOTIFY_OPT_ENABLE) == 0) return; 958 + 959 + /* re-enable by swapping in the saved server port and saved opts*/ 960 + pthread_mutex_lock(&globals->notify_lock); 961 + 962 + globals->client_opts = globals->saved_opts; 963 + globals->notify_server_port = globals->saved_server_port; 964 + 965 + pthread_mutex_unlock(&globals->notify_lock); 966 + return; 967 + } 968 + 969 + /* 970 + * A client can disable the library even if the server port has already been fetched. 971 + * Note that this could race with another thread making a Libnotify call. 972 + */ 973 + if (opts & NOTIFY_OPT_DISABLE) 974 + { 975 + pthread_mutex_lock(&globals->notify_lock); 976 + 977 + globals->saved_opts = globals->client_opts; 978 + globals->client_opts = NOTIFY_OPT_DISABLE; 979 + 980 + globals->saved_server_port = globals->notify_server_port; 981 + globals->notify_server_port = MACH_PORT_NULL; 982 + 983 + pthread_mutex_unlock(&globals->notify_lock); 984 + return; 985 + } 986 + 987 + globals->client_opts = opts; 988 + 989 + /* call _notify_lib_init to create ports / dispatch sources as required */ 990 + _notify_lib_init(EVENT_INIT); 991 + } 992 + 993 + /* 994 + * PUBLIC API 995 + */ 996 + 997 + /* 998 + * notify_post is a very simple API, but the implementation is 999 + * more complex to try to optimize the time it takes. 1000 + * 1001 + * The server - notifyd - keeps a unique ID number for each key 1002 + * in the namespace. Although it's reasonably fast to call 1003 + * _notify_server_post_4 (a MIG simpleroutine), the MIG call 1004 + * allocates VM and copies the name string. It's much faster to 1005 + * call using the ID number. The problem is mapping from name to 1006 + * ID number. The token table keeps track of all registered names 1007 + * (in the client), but the registration calls are simpleroutines, 1008 + * except for notify_register_check. notify_register_check saves 1009 + * the name ID in the token table, but the other routines set it 1010 + * to NID_UNSET. 1011 + * 1012 + * In notify_post, we check if the name is known. If it is not, 1013 + * then the client is doing a "cold call". There may be no 1014 + * clients for this name anywhere on the system. In this case 1015 + * we simply send the name. We take the allocate/copy cost, but 1016 + * the latency is still not too bad since we use a simpleroutine. 1017 + * 1018 + * If the name in registered and the ID number is known, we send 1019 + * the ID using a simpleroutine. This is very fast. 1020 + * 1021 + * If the name is registered but the ID number is NID_UNSET, we 1022 + * send the name (as in a "cold call". It *might* just be that 1023 + * this client process just posts once, and we don't want to incur 1024 + * any addition cost. The ID number is reset to NID_CALLED_ONCE. 1025 + * 1026 + * If the client posts the same name again (the ID number is 1027 + * NID_CALLED_ONCE, we do a synchronous call to notifyd, sending 1028 + * the name string and getting back the name ID, whcih we save 1029 + * in the token table. This is simply a zero/one/many heuristic: 1030 + * If the client posts the same name more than once, we make the 1031 + * guess that it's going to do it more frequently, and it's worth 1032 + * the time it takes to fetch the ID from notifyd. 1033 + */ 1034 + uint32_t 1035 + notify_post(const char *name) 1036 + { 1037 + notify_state_t *ns_self; 1038 + kern_return_t kstatus; 1039 + uint32_t status; 1040 + size_t namelen = 0; 1041 + name_table_node_t *n; 1042 + uint64_t nid = UINT64_MAX; 1043 + notify_globals_t globals = _notify_globals(); 1044 + 1045 + regenerate_check(); 1046 + 1047 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1048 + 1049 + if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN)) 1050 + { 1051 + ns_self = _notify_lib_self_state(); 1052 + if (ns_self == NULL) return NOTIFY_STATUS_FAILED; 1053 + _notify_lib_post(ns_self, name, 0, 0); 1054 + return NOTIFY_STATUS_OK; 1055 + } 1056 + 1057 + if (globals->notify_server_port == MACH_PORT_NULL) 1058 + { 1059 + status = _notify_lib_init(EVENT_INIT); 1060 + if (status != 0) return NOTIFY_STATUS_FAILED; 1061 + } 1062 + 1063 + if (globals->notify_ipc_version == 0) 1064 + { 1065 + namelen = strlen(name); 1066 + kstatus = _notify_server_post(globals->notify_server_port, (caddr_t)name, namelen, (int32_t *)&status); 1067 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 1068 + return status; 1069 + } 1070 + 1071 + namelen = strlen(name); 1072 + 1073 + /* Lock to prevent a race with notify cancel over the use of name IDs */ 1074 + pthread_mutex_lock(&globals->notify_lock); 1075 + 1076 + /* See if we have a name ID for this name. */ 1077 + n = name_table_find_retain_no_lock(name); 1078 + if (n != NULL) 1079 + { 1080 + if (n->name_id == NID_UNSET) 1081 + { 1082 + /* First post goes using the name string. */ 1083 + kstatus = _notify_server_post_4(globals->notify_server_port, (caddr_t)name, namelen); 1084 + if (kstatus != KERN_SUCCESS) 1085 + { 1086 + name_table_release_no_lock(name); 1087 + pthread_mutex_unlock(&globals->notify_lock); 1088 + return NOTIFY_STATUS_FAILED; 1089 + } 1090 + 1091 + n->name_id = NID_CALLED_ONCE; 1092 + name_table_release_no_lock(name); 1093 + pthread_mutex_unlock(&globals->notify_lock); 1094 + return NOTIFY_STATUS_OK; 1095 + } 1096 + else if (n->name_id == NID_CALLED_ONCE) 1097 + { 1098 + /* Post and fetch the name ID. Slow, but subsequent posts will be very fast. */ 1099 + kstatus = _notify_server_post_2(globals->notify_server_port, (caddr_t)name, namelen, &nid, (int32_t *)&status); 1100 + if (kstatus != KERN_SUCCESS) 1101 + { 1102 + name_table_release_no_lock(name); 1103 + pthread_mutex_unlock(&globals->notify_lock); 1104 + return NOTIFY_STATUS_FAILED; 1105 + } 1106 + 1107 + if (status == NOTIFY_STATUS_OK) n->name_id = nid; 1108 + name_table_release_no_lock(name); 1109 + pthread_mutex_unlock(&globals->notify_lock); 1110 + return status; 1111 + } 1112 + else 1113 + { 1114 + /* We have the name ID. Do an async post using the name ID. Very fast. */ 1115 + kstatus = _notify_server_post_3(globals->notify_server_port, n->name_id); 1116 + name_table_release_no_lock(name); 1117 + pthread_mutex_unlock(&globals->notify_lock); 1118 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 1119 + return NOTIFY_STATUS_OK; 1120 + } 1121 + } 1122 + 1123 + pthread_mutex_unlock(&globals->notify_lock); 1124 + 1125 + /* Do an async post using the name string. Fast (but not as fast as using name ID). */ 1126 + kstatus = _notify_server_post_4(globals->notify_server_port, (caddr_t)name, namelen); 1127 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 1128 + return NOTIFY_STATUS_OK; 1129 + } 1130 + 1131 + uint32_t 1132 + notify_set_owner(const char *name, uint32_t uid, uint32_t gid) 1133 + { 1134 + notify_state_t *ns_self; 1135 + kern_return_t kstatus; 1136 + uint32_t status; 1137 + notify_globals_t globals = _notify_globals(); 1138 + 1139 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1140 + 1141 + if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN)) 1142 + { 1143 + ns_self = _notify_lib_self_state(); 1144 + if (ns_self == NULL) return NOTIFY_STATUS_FAILED; 1145 + status = _notify_lib_set_owner(ns_self, name, uid, gid); 1146 + return status; 1147 + } 1148 + 1149 + if (globals->notify_server_port == MACH_PORT_NULL) 1150 + { 1151 + status = _notify_lib_init(EVENT_INIT); 1152 + if (status != 0) return NOTIFY_STATUS_FAILED; 1153 + } 1154 + 1155 + kstatus = _notify_server_set_owner(globals->notify_server_port, (caddr_t)name, strlen(name), uid, gid, (int32_t *)&status); 1156 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 1157 + return status; 1158 + } 1159 + 1160 + uint32_t 1161 + notify_get_owner(const char *name, uint32_t *uid, uint32_t *gid) 1162 + { 1163 + notify_state_t *ns_self; 1164 + kern_return_t kstatus; 1165 + uint32_t status; 1166 + notify_globals_t globals = _notify_globals(); 1167 + 1168 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1169 + 1170 + if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN)) 1171 + { 1172 + ns_self = _notify_lib_self_state(); 1173 + if (ns_self == NULL) return NOTIFY_STATUS_FAILED; 1174 + status = _notify_lib_get_owner(ns_self, name, uid, gid); 1175 + return status; 1176 + } 1177 + 1178 + if (globals->notify_server_port == MACH_PORT_NULL) 1179 + { 1180 + status = _notify_lib_init(EVENT_INIT); 1181 + if (status != 0) return NOTIFY_STATUS_FAILED; 1182 + } 1183 + 1184 + kstatus = _notify_server_get_owner(globals->notify_server_port, (caddr_t)name, strlen(name), (int32_t *)uid, (int32_t *)gid, (int32_t *)&status); 1185 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 1186 + return status; 1187 + } 1188 + 1189 + uint32_t 1190 + notify_set_access(const char *name, uint32_t access) 1191 + { 1192 + notify_state_t *ns_self; 1193 + kern_return_t kstatus; 1194 + uint32_t status; 1195 + notify_globals_t globals = _notify_globals(); 1196 + 1197 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1198 + 1199 + if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN)) 1200 + { 1201 + ns_self = _notify_lib_self_state(); 1202 + if (ns_self == NULL) return NOTIFY_STATUS_FAILED; 1203 + status = _notify_lib_set_access(ns_self, name, access); 1204 + return status; 1205 + } 1206 + 1207 + if (globals->notify_server_port == MACH_PORT_NULL) 1208 + { 1209 + status = _notify_lib_init(EVENT_INIT); 1210 + if (status != 0) return NOTIFY_STATUS_FAILED; 1211 + } 1212 + 1213 + kstatus = _notify_server_set_access(globals->notify_server_port, (caddr_t)name, strlen(name), access, (int32_t *)&status); 1214 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 1215 + return status; 1216 + } 1217 + 1218 + uint32_t 1219 + notify_get_access(const char *name, uint32_t *access) 1220 + { 1221 + notify_state_t *ns_self; 1222 + kern_return_t kstatus; 1223 + uint32_t status; 1224 + notify_globals_t globals = _notify_globals(); 1225 + 1226 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1227 + 1228 + if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN)) 1229 + { 1230 + ns_self = _notify_lib_self_state(); 1231 + if (ns_self == NULL) return NOTIFY_STATUS_FAILED; 1232 + status = _notify_lib_get_access(ns_self, name, access); 1233 + return status; 1234 + } 1235 + 1236 + if (globals->notify_server_port == MACH_PORT_NULL) 1237 + { 1238 + status = _notify_lib_init(EVENT_INIT); 1239 + if (status != 0) return NOTIFY_STATUS_FAILED; 1240 + } 1241 + 1242 + kstatus = _notify_server_get_access(globals->notify_server_port, (caddr_t)name, strlen(name), (int32_t *)access, (int32_t *)&status); 1243 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 1244 + return status; 1245 + } 1246 + 1247 + /* notifyd retains and releases a name when clients register and cancel. */ 1248 + uint32_t 1249 + notify_release_name(const char *name) 1250 + { 1251 + return NOTIFY_STATUS_OK; 1252 + } 1253 + 1254 + static void 1255 + _notify_dispatch_handle(mach_port_t port) 1256 + { 1257 + token_table_node_t *t; 1258 + int token; 1259 + mach_msg_empty_rcv_t msg; 1260 + kern_return_t status; 1261 + 1262 + if (port == MACH_PORT_NULL) return; 1263 + 1264 + memset(&msg, 0, sizeof(msg)); 1265 + 1266 + status = mach_msg(&msg.header, MACH_RCV_MSG, 0, sizeof(msg), port, 0, MACH_PORT_NULL); 1267 + if (status != KERN_SUCCESS) return; 1268 + 1269 + token = msg.header.msgh_id; 1270 + 1271 + t = token_table_find_retain(token); 1272 + 1273 + if (t != NULL) 1274 + { 1275 + if ((t->queue != NULL) && (t->block != NULL)) 1276 + { 1277 + /* 1278 + * Don't reference into the token table node after token_table_release(). 1279 + * If the block calls notify_cancel, the node can get trashed, so 1280 + * we keep anything we need from the block (properly retained and released) 1281 + * in local variables. Concurrent notify_cancel() calls in the block are safe. 1282 + */ 1283 + notify_handler_t theblock = Block_copy(t->block); 1284 + dispatch_queue_t thequeue = t->queue; 1285 + dispatch_retain(thequeue); 1286 + 1287 + dispatch_async(thequeue, ^{ 1288 + token_table_node_t *t = token_table_find_no_lock(token); 1289 + if (t != NULL) theblock(token); 1290 + }); 1291 + 1292 + _Block_release(theblock); 1293 + dispatch_release(thequeue); 1294 + } 1295 + 1296 + token_table_release(t); 1297 + } 1298 + } 1299 + 1300 + uint32_t 1301 + notify_register_dispatch(const char *name, int *out_token, dispatch_queue_t queue, notify_handler_t handler) 1302 + { 1303 + __block uint32_t status; 1304 + token_table_node_t *t; 1305 + notify_globals_t globals = _notify_globals(); 1306 + 1307 + regenerate_check(); 1308 + 1309 + if (queue == NULL) return NOTIFY_STATUS_FAILED; 1310 + if (handler == NULL) return NOTIFY_STATUS_FAILED; 1311 + 1312 + /* client is using dispatch: enable local demux and regeneration */ 1313 + notify_set_options(NOTIFY_OPT_DEMUX | NOTIFY_OPT_REGEN); 1314 + 1315 + status = notify_register_mach_port(name, &globals->notify_common_port, NOTIFY_REUSE, out_token); 1316 + if (status != NOTIFY_STATUS_OK) return status; 1317 + 1318 + t = token_table_find_retain(*out_token); 1319 + if (t == NULL) return NOTIFY_STATUS_FAILED; 1320 + 1321 + t->queue = queue; 1322 + dispatch_retain(t->queue); 1323 + t->block = Block_copy(handler); 1324 + token_table_release(t); 1325 + 1326 + return NOTIFY_STATUS_OK; 1327 + } 1328 + 1329 + /* note this does not get self names */ 1330 + static uint32_t 1331 + notify_register_mux_fd(const char *name, int *out_token, int rfd, int wfd) 1332 + { 1333 + __block uint32_t status; 1334 + token_table_node_t *t; 1335 + int val; 1336 + notify_globals_t globals = _notify_globals(); 1337 + 1338 + status = NOTIFY_STATUS_OK; 1339 + 1340 + if (globals->notify_common_port == MACH_PORT_NULL) return NOTIFY_STATUS_FAILED; 1341 + 1342 + status = notify_register_mach_port(name, &globals->notify_common_port, NOTIFY_REUSE, out_token); 1343 + 1344 + t = token_table_find_retain(*out_token); 1345 + if (t == NULL) return NOTIFY_STATUS_FAILED; 1346 + 1347 + t->token = *out_token; 1348 + t->fd = rfd; 1349 + t->queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 1350 + dispatch_retain(t->queue); 1351 + val = htonl(t->token); 1352 + t->block = (notify_handler_t)Block_copy(^(int unused){ write(wfd, &val, sizeof(val)); }); 1353 + 1354 + token_table_release(t); 1355 + 1356 + return NOTIFY_STATUS_OK; 1357 + } 1358 + 1359 + uint32_t 1360 + notify_register_check(const char *name, int *out_token) 1361 + { 1362 + notify_state_t *ns_self; 1363 + kern_return_t kstatus; 1364 + uint32_t status, token; 1365 + uint64_t nid; 1366 + int32_t slot, shmsize; 1367 + size_t namelen; 1368 + uint32_t cid; 1369 + notify_globals_t globals = _notify_globals(); 1370 + 1371 + regenerate_check(); 1372 + 1373 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1374 + if (out_token == NULL) return NOTIFY_STATUS_FAILED; 1375 + 1376 + *out_token = -1; 1377 + namelen = strlen(name); 1378 + 1379 + if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN)) 1380 + { 1381 + ns_self = _notify_lib_self_state(); 1382 + if (ns_self == NULL) return NOTIFY_STATUS_FAILED; 1383 + 1384 + token = OSAtomicIncrement32((int32_t *)&globals->token_id); 1385 + status = _notify_lib_register_plain(ns_self, name, NOTIFY_CLIENT_SELF, token, SLOT_NONE, 0, 0, &nid); 1386 + if (status != NOTIFY_STATUS_OK) return status; 1387 + 1388 + cid = token; 1389 + token_table_add(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_FLAG_SELF | NOTIFY_TYPE_PLAIN, SIGNAL_NONE, FD_NONE, MACH_PORT_NULL, 0); 1390 + 1391 + *out_token = token; 1392 + return NOTIFY_STATUS_OK; 1393 + } 1394 + 1395 + if (globals->notify_server_port == MACH_PORT_NULL) 1396 + { 1397 + status = _notify_lib_init(EVENT_INIT); 1398 + if (status != 0) return NOTIFY_STATUS_FAILED; 1399 + } 1400 + 1401 + token = OSAtomicIncrement32((int32_t *)&globals->token_id); 1402 + kstatus = KERN_SUCCESS; 1403 + 1404 + if (globals->notify_ipc_version == 0) 1405 + { 1406 + nid = NID_UNSET; 1407 + kstatus = _notify_server_register_check(globals->notify_server_port, (caddr_t)name, namelen, &shmsize, &slot, (int32_t *)&cid, (int32_t *)&status); 1408 + } 1409 + else 1410 + { 1411 + cid = token; 1412 + kstatus = _notify_server_register_check_2(globals->notify_server_port, (caddr_t)name, namelen, token, &shmsize, &slot, &nid, (int32_t *)&status); 1413 + } 1414 + 1415 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 1416 + if (status != NOTIFY_STATUS_OK) return status; 1417 + 1418 + if (shmsize != -1) 1419 + { 1420 + if (globals->shm_base == NULL) 1421 + { 1422 + if (shm_attach(shmsize) != 0) return NOTIFY_STATUS_FAILED; 1423 + if (globals->shm_base == NULL) return NOTIFY_STATUS_FAILED; 1424 + } 1425 + 1426 + token_table_add(name, namelen, nid, token, cid, slot, NOTIFY_TYPE_MEMORY | NOTIFY_FLAG_REGEN, SIGNAL_NONE, FD_NONE, MACH_PORT_NULL, 0); 1427 + } 1428 + else 1429 + { 1430 + token_table_add(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_TYPE_PLAIN | NOTIFY_FLAG_REGEN, SIGNAL_NONE, FD_NONE, MACH_PORT_NULL, 0); 1431 + } 1432 + 1433 + *out_token = token; 1434 + return status; 1435 + } 1436 + 1437 + uint32_t 1438 + notify_register_plain(const char *name, int *out_token) 1439 + { 1440 + notify_state_t *ns_self; 1441 + kern_return_t kstatus; 1442 + uint32_t status; 1443 + uint64_t nid; 1444 + size_t namelen; 1445 + int token; 1446 + uint32_t cid; 1447 + notify_globals_t globals = _notify_globals(); 1448 + 1449 + regenerate_check(); 1450 + 1451 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1452 + 1453 + namelen = strlen(name); 1454 + 1455 + if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN)) 1456 + { 1457 + ns_self = _notify_lib_self_state(); 1458 + if (ns_self == NULL) return NOTIFY_STATUS_FAILED; 1459 + 1460 + token = OSAtomicIncrement32((int32_t *)&globals->token_id); 1461 + status = _notify_lib_register_plain(ns_self, name, NOTIFY_CLIENT_SELF, token, SLOT_NONE, 0, 0, &nid); 1462 + if (status != NOTIFY_STATUS_OK) return status; 1463 + 1464 + cid = token; 1465 + token_table_add(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_FLAG_SELF | NOTIFY_TYPE_PLAIN, SIGNAL_NONE, FD_NONE, MACH_PORT_NULL, 0); 1466 + 1467 + *out_token = token; 1468 + return NOTIFY_STATUS_OK; 1469 + } 1470 + 1471 + if (globals->notify_server_port == MACH_PORT_NULL) 1472 + { 1473 + status = _notify_lib_init(EVENT_INIT); 1474 + if (status != 0) return NOTIFY_STATUS_FAILED; 1475 + } 1476 + 1477 + token = OSAtomicIncrement32((int32_t *)&globals->token_id); 1478 + 1479 + if (globals->notify_ipc_version == 0) 1480 + { 1481 + kstatus = _notify_server_register_plain(globals->notify_server_port, (caddr_t)name, namelen, (int32_t *)&cid, (int32_t *)&status); 1482 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 1483 + if (status != NOTIFY_STATUS_OK) return status; 1484 + } 1485 + else 1486 + { 1487 + cid = token; 1488 + kstatus = _notify_server_register_plain_2(globals->notify_server_port, (caddr_t)name, namelen, token); 1489 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 1490 + } 1491 + 1492 + 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); 1493 + 1494 + *out_token = token; 1495 + return NOTIFY_STATUS_OK; 1496 + } 1497 + 1498 + uint32_t 1499 + notify_register_signal(const char *name, int sig, int *out_token) 1500 + { 1501 + notify_state_t *ns_self; 1502 + kern_return_t kstatus; 1503 + uint32_t status; 1504 + uint64_t nid; 1505 + size_t namelen; 1506 + int token; 1507 + uint32_t cid; 1508 + notify_globals_t globals = _notify_globals(); 1509 + 1510 + regenerate_check(); 1511 + 1512 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1513 + 1514 + namelen = strlen(name); 1515 + 1516 + if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN)) 1517 + { 1518 + ns_self = _notify_lib_self_state(); 1519 + if (ns_self == NULL) return NOTIFY_STATUS_FAILED; 1520 + 1521 + token = OSAtomicIncrement32((int32_t *)&globals->token_id); 1522 + status = _notify_lib_register_signal(ns_self, name, NOTIFY_CLIENT_SELF, token, sig, 0, 0, &nid); 1523 + if (status != NOTIFY_STATUS_OK) return status; 1524 + 1525 + cid = token; 1526 + token_table_add(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_FLAG_SELF | NOTIFY_TYPE_SIGNAL, sig, FD_NONE, MACH_PORT_NULL, 0); 1527 + 1528 + *out_token = token; 1529 + return NOTIFY_STATUS_OK; 1530 + } 1531 + 1532 + if (globals->client_opts & NOTIFY_OPT_DEMUX) 1533 + { 1534 + return notify_register_dispatch(name, out_token, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(int unused){ kill(getpid(), sig); }); 1535 + } 1536 + 1537 + if (globals->notify_server_port == MACH_PORT_NULL) 1538 + { 1539 + status = _notify_lib_init(EVENT_INIT); 1540 + if (status != 0) return NOTIFY_STATUS_FAILED; 1541 + } 1542 + 1543 + token = OSAtomicIncrement32((int32_t *)&globals->token_id); 1544 + 1545 + if (globals->notify_ipc_version == 0) 1546 + { 1547 + kstatus = _notify_server_register_signal(globals->notify_server_port, (caddr_t)name, namelen, sig, (int32_t *)&cid, (int32_t *)&status); 1548 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 1549 + if (status != NOTIFY_STATUS_OK) return status; 1550 + } 1551 + else 1552 + { 1553 + cid = token; 1554 + kstatus = _notify_server_register_signal_2(globals->notify_server_port, (caddr_t)name, namelen, token, sig); 1555 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 1556 + } 1557 + 1558 + token_table_add(name, namelen, NID_UNSET, token, cid, SLOT_NONE, NOTIFY_TYPE_SIGNAL | NOTIFY_FLAG_REGEN, sig, FD_NONE, MACH_PORT_NULL, 0); 1559 + 1560 + *out_token = token; 1561 + return NOTIFY_STATUS_OK; 1562 + } 1563 + 1564 + uint32_t 1565 + notify_register_mach_port(const char *name, mach_port_name_t *notify_port, int flags, int *out_token) 1566 + { 1567 + notify_state_t *ns_self; 1568 + kern_return_t kstatus; 1569 + uint32_t status; 1570 + uint64_t nid; 1571 + task_t task; 1572 + int token, mine; 1573 + size_t namelen; 1574 + uint32_t cid, tflags; 1575 + token_table_node_t *t; 1576 + mach_port_name_t port; 1577 + notify_globals_t globals = _notify_globals(); 1578 + 1579 + regenerate_check(); 1580 + 1581 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1582 + if (notify_port == NULL) return NOTIFY_STATUS_INVALID_PORT; 1583 + 1584 + mine = 0; 1585 + namelen = strlen(name); 1586 + 1587 + task = mach_task_self(); 1588 + 1589 + if ((flags & NOTIFY_REUSE) == 0) 1590 + { 1591 + mine = 1; 1592 + kstatus = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, notify_port); 1593 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 1594 + } 1595 + 1596 + kstatus = mach_port_insert_right(task, *notify_port, *notify_port, MACH_MSG_TYPE_MAKE_SEND); 1597 + if (kstatus != KERN_SUCCESS) 1598 + { 1599 + if (mine == 1) mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1); 1600 + return NOTIFY_STATUS_FAILED; 1601 + } 1602 + 1603 + if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN)) 1604 + { 1605 + ns_self = _notify_lib_self_state(); 1606 + if (ns_self == NULL) 1607 + { 1608 + if (mine == 1) 1609 + { 1610 + mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1); 1611 + } 1612 + 1613 + mach_port_deallocate(task, *notify_port); 1614 + return NOTIFY_STATUS_FAILED; 1615 + } 1616 + 1617 + token = OSAtomicIncrement32((int32_t *)&globals->token_id); 1618 + status = _notify_lib_register_mach_port(ns_self, name, NOTIFY_CLIENT_SELF, token, *notify_port, 0, 0, &nid); 1619 + if (status != NOTIFY_STATUS_OK) 1620 + { 1621 + if (mine == 1) 1622 + { 1623 + mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1); 1624 + } 1625 + 1626 + mach_port_deallocate(task, *notify_port); 1627 + return status; 1628 + } 1629 + 1630 + cid = token; 1631 + token_table_add(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_FLAG_SELF | NOTIFY_TYPE_PORT, SIGNAL_NONE, FD_NONE, *notify_port, 0); 1632 + 1633 + *out_token = token; 1634 + notify_retain_mach_port(*notify_port, mine); 1635 + 1636 + return NOTIFY_STATUS_OK; 1637 + } 1638 + 1639 + if (globals->notify_server_port == MACH_PORT_NULL) 1640 + { 1641 + status = _notify_lib_init(EVENT_INIT); 1642 + if (status != 0) 1643 + { 1644 + if (mine == 1) 1645 + { 1646 + mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1); 1647 + } 1648 + 1649 + mach_port_deallocate(task, *notify_port); 1650 + return NOTIFY_STATUS_FAILED; 1651 + } 1652 + } 1653 + 1654 + if ((globals->client_opts & NOTIFY_OPT_DEMUX) && (*notify_port != globals->notify_common_port)) 1655 + { 1656 + port = globals->notify_common_port; 1657 + kstatus = mach_port_insert_right(task, globals->notify_common_port, globals->notify_common_port, MACH_MSG_TYPE_MAKE_SEND); 1658 + } 1659 + else 1660 + { 1661 + port = *notify_port; 1662 + kstatus = KERN_SUCCESS; 1663 + } 1664 + 1665 + if (kstatus == KERN_SUCCESS) 1666 + { 1667 + token = OSAtomicIncrement32((int32_t *)&globals->token_id); 1668 + 1669 + if (globals->notify_ipc_version == 0) 1670 + { 1671 + kstatus = _notify_server_register_mach_port(globals->notify_server_port, (caddr_t)name, namelen, port, token, (int32_t *)&cid, (int32_t *)&status); 1672 + if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE; 1673 + } 1674 + else 1675 + { 1676 + cid = token; 1677 + kstatus = _notify_server_register_mach_port_2(globals->notify_server_port, (caddr_t)name, namelen, token, port); 1678 + } 1679 + } 1680 + 1681 + if (kstatus != KERN_SUCCESS) 1682 + { 1683 + if (mine == 1) 1684 + { 1685 + mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1); 1686 + } 1687 + 1688 + mach_port_deallocate(task, *notify_port); 1689 + return NOTIFY_STATUS_FAILED; 1690 + } 1691 + 1692 + tflags = NOTIFY_TYPE_PORT; 1693 + if (port == globals->notify_common_port) tflags |= NOTIFY_FLAG_REGEN; 1694 + token_table_add(name, namelen, NID_UNSET, token, cid, SLOT_NONE, tflags, SIGNAL_NONE, FD_NONE, *notify_port, 0); 1695 + 1696 + if ((globals->client_opts & NOTIFY_OPT_DEMUX) && (*notify_port != globals->notify_common_port)) 1697 + { 1698 + t = token_table_find_retain(token); 1699 + if (t == NULL) return NOTIFY_STATUS_FAILED; 1700 + 1701 + /* remember to release the send right when this gets cancelled */ 1702 + t->flags |= NOTIFY_FLAG_RELEASE_SEND; 1703 + 1704 + port = *notify_port; 1705 + t->queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 1706 + dispatch_retain(t->queue); 1707 + t->block = (notify_handler_t)Block_copy(^(int unused){ 1708 + mach_msg_empty_send_t msg; 1709 + kern_return_t kstatus; 1710 + 1711 + /* send empty message to the port with msgh_id = token; */ 1712 + memset(&msg, 0, sizeof(msg)); 1713 + msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSGH_BITS_ZERO); 1714 + msg.header.msgh_remote_port = port; 1715 + msg.header.msgh_local_port = MACH_PORT_NULL; 1716 + msg.header.msgh_size = sizeof(mach_msg_empty_send_t); 1717 + msg.header.msgh_id = token; 1718 + 1719 + kstatus = mach_msg(&(msg.header), MACH_SEND_MSG | MACH_SEND_TIMEOUT, msg.header.msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); 1720 + }); 1721 + 1722 + token_table_release(t); 1723 + } 1724 + 1725 + *out_token = token; 1726 + notify_retain_mach_port(*notify_port, mine); 1727 + 1728 + return NOTIFY_STATUS_OK; 1729 + } 1730 + 1731 + static char * 1732 + _notify_mk_tmp_path(int tid) 1733 + { 1734 + #if TARGET_OS_EMBEDDED 1735 + int freetmp = 0; 1736 + char *path, *tmp = getenv("TMPDIR"); 1737 + 1738 + if (tmp == NULL) 1739 + { 1740 + asprintf(&tmp, "/tmp/com.apple.notify.%d", geteuid()); 1741 + mkdir(tmp, 0755); 1742 + freetmp = 1; 1743 + } 1744 + 1745 + if (tmp == NULL) return NULL; 1746 + 1747 + asprintf(&path, "%s/com.apple.notify.%d.%d", tmp, getpid(), tid); 1748 + if (freetmp) free(tmp); 1749 + return path; 1750 + #else 1751 + char tmp[PATH_MAX], *path; 1752 + 1753 + if (confstr(_CS_DARWIN_USER_TEMP_DIR, tmp, sizeof(tmp)) <= 0) return NULL; 1754 + #endif 1755 + 1756 + path = NULL; 1757 + asprintf(&path, "%s/com.apple.notify.%d.%d", tmp, getpid(), tid); 1758 + return path; 1759 + } 1760 + 1761 + uint32_t 1762 + notify_register_file_descriptor(const char *name, int *notify_fd, int flags, int *out_token) 1763 + { 1764 + notify_state_t *ns_self; 1765 + uint32_t i, status; 1766 + uint64_t nid; 1767 + int token, mine, fdpair[2]; 1768 + size_t namelen; 1769 + fileport_t fileport; 1770 + kern_return_t kstatus; 1771 + uint32_t cid; 1772 + notify_globals_t globals = _notify_globals(); 1773 + 1774 + regenerate_check(); 1775 + 1776 + mine = 0; 1777 + 1778 + if (name == NULL) return NOTIFY_STATUS_INVALID_NAME; 1779 + if (notify_fd == NULL) return NOTIFY_STATUS_INVALID_FILE; 1780 + 1781 + namelen = strlen(name); 1782 + 1783 + if ((flags & NOTIFY_REUSE) == 0) 1784 + { 1785 + if (pipe(fdpair) < 0) return NOTIFY_STATUS_FAILED; 1786 + 1787 + mine = 1; 1788 + *notify_fd = fdpair[0]; 1789 + } 1790 + else 1791 + { 1792 + /* check the file descriptor - it must be one of "ours" */ 1793 + for (i = 0; i < globals->fd_count; i++) 1794 + { 1795 + if (globals->fd_clnt[i] == *notify_fd) break; 1796 + } 1797 + 1798 + if (i >= globals->fd_count) return NOTIFY_STATUS_INVALID_FILE; 1799 + 1800 + fdpair[0] = globals->fd_clnt[i]; 1801 + fdpair[1] = globals->fd_srv[i]; 1802 + } 1803 + 1804 + if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN)) 1805 + { 1806 + ns_self = _notify_lib_self_state(); 1807 + if (ns_self == NULL) 1808 + { 1809 + if (mine == 1) 1810 + { 1811 + close(fdpair[0]); 1812 + close(fdpair[1]); 1813 + } 1814 + 1815 + return NOTIFY_STATUS_FAILED; 1816 + } 1817 + 1818 + token = OSAtomicIncrement32((int32_t *)&globals->token_id); 1819 + status = _notify_lib_register_file_descriptor(ns_self, name, NOTIFY_CLIENT_SELF, token, fdpair[1], 0, 0, &nid); 1820 + if (status != NOTIFY_STATUS_OK) 1821 + { 1822 + if (mine == 1) 1823 + { 1824 + close(fdpair[0]); 1825 + close(fdpair[1]); 1826 + } 1827 + 1828 + return status; 1829 + } 1830 + 1831 + cid = token; 1832 + token_table_add(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_FLAG_SELF | NOTIFY_TYPE_FILE, SIGNAL_NONE, *notify_fd, MACH_PORT_NULL, 0); 1833 + 1834 + *out_token = token; 1835 + notify_retain_file_descriptor(fdpair[0], fdpair[1]); 1836 + 1837 + return NOTIFY_STATUS_OK; 1838 + } 1839 + 1840 + if (globals->client_opts & NOTIFY_OPT_DEMUX) 1841 + { 1842 + /* 1843 + * Use dispatch to do a write() on fdpair[1] when notified. 1844 + */ 1845 + status = notify_register_mux_fd(name, out_token, fdpair[0], fdpair[1]); 1846 + if (status != NOTIFY_STATUS_OK) 1847 + { 1848 + if (mine == 1) 1849 + { 1850 + close(fdpair[0]); 1851 + close(fdpair[1]); 1852 + } 1853 + 1854 + return status; 1855 + } 1856 + 1857 + notify_retain_file_descriptor(fdpair[0], fdpair[1]); 1858 + return NOTIFY_STATUS_OK; 1859 + } 1860 + 1861 + if (globals->notify_server_port == MACH_PORT_NULL) 1862 + { 1863 + status = _notify_lib_init(EVENT_INIT); 1864 + if (status != 0) 1865 + { 1866 + if (mine == 1) 1867 + { 1868 + close(fdpair[0]); 1869 + close(fdpair[1]); 1870 + } 1871 + 1872 + return NOTIFY_STATUS_FAILED; 1873 + } 1874 + } 1875 + 1876 + /* send fdpair[1] (the sender's fd) to notifyd using a fileport */ 1877 + fileport = MACH_PORT_NULL; 1878 + if (fileport_makeport(fdpair[1], (fileport_t *)&fileport) < 0) 1879 + { 1880 + if (mine == 1) 1881 + { 1882 + close(fdpair[0]); 1883 + close(fdpair[1]); 1884 + } 1885 + 1886 + return NOTIFY_STATUS_FAILED; 1887 + } 1888 + 1889 + token = OSAtomicIncrement32((int32_t *)&globals->token_id); 1890 + 1891 + if (globals->notify_ipc_version == 0) 1892 + { 1893 + 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); 1894 + if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE; 1895 + } 1896 + else 1897 + { 1898 + kstatus = _notify_server_register_file_descriptor_2(globals->notify_server_port, (caddr_t)name, namelen, token, (mach_port_t)fileport); 1899 + } 1900 + 1901 + if (kstatus != KERN_SUCCESS) 1902 + { 1903 + if (mine == 1) 1904 + { 1905 + close(fdpair[0]); 1906 + close(fdpair[1]); 1907 + } 1908 + 1909 + return NOTIFY_STATUS_FAILED; 1910 + } 1911 + 1912 + token_table_add(name, namelen, NID_UNSET, token, cid, SLOT_NONE, NOTIFY_TYPE_FILE, SIGNAL_NONE, *notify_fd, MACH_PORT_NULL, 0); 1913 + 1914 + *out_token = token; 1915 + notify_retain_file_descriptor(fdpair[0], fdpair[1]); 1916 + 1917 + return NOTIFY_STATUS_OK; 1918 + } 1919 + 1920 + uint32_t 1921 + notify_check(int token, int *check) 1922 + { 1923 + kern_return_t kstatus; 1924 + uint32_t status, val; 1925 + token_table_node_t *t; 1926 + uint32_t tid; 1927 + notify_globals_t globals = _notify_globals(); 1928 + 1929 + regenerate_check(); 1930 + 1931 + pthread_mutex_lock(&globals->notify_lock); 1932 + 1933 + t = token_table_find_no_lock(token); 1934 + if (t == NULL) 1935 + { 1936 + pthread_mutex_unlock(&globals->notify_lock); 1937 + return NOTIFY_STATUS_INVALID_TOKEN; 1938 + } 1939 + 1940 + if (t->flags & NOTIFY_FLAG_SELF) 1941 + { 1942 + /* _notify_lib_check returns NOTIFY_STATUS_FAILED if self_state is NULL */ 1943 + status = _notify_lib_check(globals->self_state, NOTIFY_CLIENT_SELF, token, check); 1944 + pthread_mutex_unlock(&globals->notify_lock); 1945 + return status; 1946 + } 1947 + 1948 + if (t->flags & NOTIFY_TYPE_MEMORY) 1949 + { 1950 + if (globals->shm_base == NULL) 1951 + { 1952 + pthread_mutex_unlock(&globals->notify_lock); 1953 + return NOTIFY_STATUS_FAILED; 1954 + } 1955 + 1956 + *check = 0; 1957 + val = globals->shm_base[t->slot]; 1958 + if (t->val != val) 1959 + { 1960 + *check = 1; 1961 + t->val = val; 1962 + } 1963 + 1964 + pthread_mutex_unlock(&globals->notify_lock); 1965 + return NOTIFY_STATUS_OK; 1966 + } 1967 + 1968 + tid = token; 1969 + if (globals->notify_ipc_version == 0) tid = t->client_id; 1970 + 1971 + pthread_mutex_unlock(&globals->notify_lock); 1972 + 1973 + if (globals->notify_server_port == MACH_PORT_NULL) 1974 + { 1975 + status = _notify_lib_init(EVENT_INIT); 1976 + if (status != 0) return NOTIFY_STATUS_FAILED; 1977 + } 1978 + 1979 + kstatus = _notify_server_check(globals->notify_server_port, tid, check, (int32_t *)&status); 1980 + 1981 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 1982 + return status; 1983 + } 1984 + 1985 + uint32_t 1986 + notify_peek(int token, uint32_t *val) 1987 + { 1988 + token_table_node_t *t; 1989 + uint32_t status; 1990 + notify_globals_t globals = _notify_globals(); 1991 + 1992 + regenerate_check(); 1993 + 1994 + t = token_table_find_retain(token); 1995 + if (t == NULL) return NOTIFY_STATUS_INVALID_TOKEN; 1996 + 1997 + if (t->flags & NOTIFY_FLAG_SELF) 1998 + { 1999 + /* _notify_lib_peek returns NOTIFY_STATUS_FAILED if self_state is NULL */ 2000 + status = _notify_lib_peek(globals->self_state, NOTIFY_CLIENT_SELF, token, (int *)val); 2001 + token_table_release(t); 2002 + return status; 2003 + } 2004 + 2005 + if (t->flags & NOTIFY_TYPE_MEMORY) 2006 + { 2007 + if (globals->shm_base == NULL) 2008 + { 2009 + token_table_release(t); 2010 + return NOTIFY_STATUS_FAILED; 2011 + } 2012 + 2013 + *val = globals->shm_base[t->slot]; 2014 + token_table_release(t); 2015 + return NOTIFY_STATUS_OK; 2016 + } 2017 + 2018 + token_table_release(t); 2019 + return NOTIFY_STATUS_INVALID_REQUEST; 2020 + } 2021 + 2022 + int * 2023 + notify_check_addr(int token) 2024 + { 2025 + token_table_node_t *t; 2026 + uint32_t slot; 2027 + int *val; 2028 + notify_globals_t globals = _notify_globals(); 2029 + 2030 + regenerate_check(); 2031 + 2032 + t = token_table_find_retain(token); 2033 + if (t == NULL) return NULL; 2034 + 2035 + if (t->flags & NOTIFY_FLAG_SELF) 2036 + { 2037 + /* _notify_lib_check_addr returns NOTIFY_STATUS_FAILED if self_state is NULL */ 2038 + val = _notify_lib_check_addr(globals->self_state, NOTIFY_CLIENT_SELF, token); 2039 + token_table_release(t); 2040 + return val; 2041 + } 2042 + 2043 + if (t->flags & NOTIFY_TYPE_MEMORY) 2044 + { 2045 + slot = t->slot; 2046 + token_table_release(t); 2047 + 2048 + if (globals->shm_base == NULL) return NULL; 2049 + return (int *)&(globals->shm_base[slot]); 2050 + } 2051 + 2052 + token_table_release(t); 2053 + return NULL; 2054 + } 2055 + 2056 + uint32_t 2057 + notify_monitor_file(int token, char *path, int flags) 2058 + { 2059 + kern_return_t kstatus; 2060 + uint32_t status, len; 2061 + token_table_node_t *t; 2062 + char *dup; 2063 + notify_globals_t globals = _notify_globals(); 2064 + 2065 + regenerate_check(); 2066 + 2067 + if (path == NULL) return NOTIFY_STATUS_INVALID_REQUEST; 2068 + 2069 + t = token_table_find_retain(token); 2070 + if (t == NULL) return NOTIFY_STATUS_INVALID_TOKEN; 2071 + 2072 + if (t->flags & NOTIFY_FLAG_SELF) 2073 + { 2074 + token_table_release(t); 2075 + return NOTIFY_STATUS_INVALID_REQUEST; 2076 + } 2077 + 2078 + /* can only monitor one path with a token */ 2079 + if (t->path != NULL) 2080 + { 2081 + token_table_release(t); 2082 + return NOTIFY_STATUS_INVALID_REQUEST; 2083 + } 2084 + 2085 + if (globals->notify_server_port == MACH_PORT_NULL) 2086 + { 2087 + status = _notify_lib_init(EVENT_INIT); 2088 + if (status != 0) 2089 + { 2090 + token_table_release(t); 2091 + return NOTIFY_STATUS_FAILED; 2092 + } 2093 + } 2094 + 2095 + len = strlen(path); 2096 + dup = strdup(path); 2097 + if (dup == NULL) return NOTIFY_STATUS_FAILED; 2098 + 2099 + if (globals->notify_ipc_version == 0) 2100 + { 2101 + kstatus = _notify_server_monitor_file(globals->notify_server_port, t->client_id, path, len, flags, (int32_t *)&status); 2102 + if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE; 2103 + } 2104 + else 2105 + { 2106 + kstatus = _notify_server_monitor_file_2(globals->notify_server_port, token, path, len, flags); 2107 + } 2108 + 2109 + t->path = dup; 2110 + t->path_flags = flags; 2111 + 2112 + token_table_release(t); 2113 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 2114 + return NOTIFY_STATUS_OK; 2115 + } 2116 + 2117 + uint32_t 2118 + notify_get_event(int token, int *ev, char *buf, int *len) 2119 + { 2120 + if (ev != NULL) *ev = 0; 2121 + if (len != NULL) *len = 0; 2122 + 2123 + return NOTIFY_STATUS_OK; 2124 + } 2125 + 2126 + uint32_t 2127 + notify_get_state(int token, uint64_t *state) 2128 + { 2129 + kern_return_t kstatus; 2130 + uint32_t status; 2131 + token_table_node_t *t; 2132 + uint64_t nid; 2133 + notify_globals_t globals = _notify_globals(); 2134 + 2135 + regenerate_check(); 2136 + 2137 + t = token_table_find_retain(token); 2138 + if (t == NULL) return NOTIFY_STATUS_INVALID_TOKEN; 2139 + if (t->name_node == NULL) 2140 + { 2141 + token_table_release(t); 2142 + return NOTIFY_STATUS_INVALID_TOKEN; 2143 + } 2144 + 2145 + if (t->flags & NOTIFY_FLAG_SELF) 2146 + { 2147 + /* _notify_lib_get_state returns NOTIFY_STATUS_FAILED if self_state is NULL */ 2148 + status = _notify_lib_get_state(globals->self_state, t->name_node->name_id, state, 0, 0); 2149 + token_table_release(t); 2150 + return status; 2151 + } 2152 + 2153 + if (globals->notify_server_port == MACH_PORT_NULL) 2154 + { 2155 + status = _notify_lib_init(EVENT_INIT); 2156 + if (status != 0) 2157 + { 2158 + token_table_release(t); 2159 + return NOTIFY_STATUS_FAILED; 2160 + } 2161 + } 2162 + 2163 + if (globals->notify_ipc_version == 0) 2164 + { 2165 + kstatus = _notify_server_get_state(globals->notify_server_port, t->client_id, state, (int32_t *)&status); 2166 + if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE; 2167 + } 2168 + else 2169 + { 2170 + if (t->name_node->name_id >= NID_CALLED_ONCE) 2171 + { 2172 + kstatus = _notify_server_get_state_3(globals->notify_server_port, t->token, state, (uint64_t *)&nid, (int32_t *)&status); 2173 + if ((kstatus == KERN_SUCCESS) && (status == NOTIFY_STATUS_OK)) name_table_set_nid(t->name, nid); 2174 + } 2175 + else 2176 + { 2177 + kstatus = _notify_server_get_state_2(globals->notify_server_port, t->name_node->name_id, state, (int32_t *)&status); 2178 + } 2179 + } 2180 + 2181 + token_table_release(t); 2182 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 2183 + return status; 2184 + } 2185 + 2186 + uint32_t 2187 + notify_set_state(int token, uint64_t state) 2188 + { 2189 + kern_return_t kstatus; 2190 + uint32_t status; 2191 + token_table_node_t *t; 2192 + uint64_t nid; 2193 + notify_globals_t globals = _notify_globals(); 2194 + 2195 + regenerate_check(); 2196 + 2197 + t = token_table_find_retain(token); 2198 + if (t == NULL) return NOTIFY_STATUS_INVALID_TOKEN; 2199 + if (t->name_node == NULL) 2200 + { 2201 + token_table_release(t); 2202 + return NOTIFY_STATUS_INVALID_TOKEN; 2203 + } 2204 + 2205 + if (t->flags & NOTIFY_FLAG_SELF) 2206 + { 2207 + /* _notify_lib_set_state returns NOTIFY_STATUS_FAILED if self_state is NULL */ 2208 + status = _notify_lib_set_state(globals->self_state, t->name_node->name_id, state, 0, 0); 2209 + token_table_release(t); 2210 + return status; 2211 + } 2212 + 2213 + if (globals->notify_server_port == MACH_PORT_NULL) 2214 + { 2215 + status = _notify_lib_init(EVENT_INIT); 2216 + if (status != 0) 2217 + { 2218 + token_table_release(t); 2219 + return NOTIFY_STATUS_FAILED; 2220 + } 2221 + } 2222 + 2223 + status = NOTIFY_STATUS_OK; 2224 + 2225 + if (globals->notify_ipc_version == 0) 2226 + { 2227 + kstatus = _notify_server_set_state(globals->notify_server_port, t->client_id, state, (int32_t *)&status); 2228 + if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE; 2229 + } 2230 + else 2231 + { 2232 + if (t->name_node->name_id >= NID_CALLED_ONCE) 2233 + { 2234 + kstatus = _notify_server_set_state_3(globals->notify_server_port, t->token, state, (uint64_t *)&nid, (int32_t *)&status); 2235 + if ((kstatus == KERN_SUCCESS) && (status == NOTIFY_STATUS_OK)) name_table_set_nid(t->name, nid); 2236 + } 2237 + else 2238 + { 2239 + status = NOTIFY_STATUS_OK; 2240 + kstatus = _notify_server_set_state_2(globals->notify_server_port, t->name_node->name_id, state); 2241 + } 2242 + } 2243 + 2244 + if ((kstatus == KERN_SUCCESS) && (status == NOTIFY_STATUS_OK)) 2245 + { 2246 + t->set_state_time = mach_absolute_time(); 2247 + t->set_state_val = state; 2248 + } 2249 + 2250 + token_table_release(t); 2251 + if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 2252 + return NOTIFY_STATUS_OK; 2253 + } 2254 + 2255 + uint32_t 2256 + notify_cancel(int token) 2257 + { 2258 + token_table_node_t *t; 2259 + uint32_t status; 2260 + kern_return_t kstatus; 2261 + notify_globals_t globals = _notify_globals(); 2262 + 2263 + regenerate_check(); 2264 + 2265 + /* 2266 + * Lock to prevent a race with notify_post, which uses the name ID. 2267 + * If we are cancelling the last registration for this name, then we need 2268 + * to block those routines from getting the name ID from the name table. 2269 + * Once notifyd gets the cancellation, the name may vanish, and the name ID 2270 + * held in the name table would go stale. 2271 + * 2272 + * Uses token_table_find_no_lock() which does not retain, and 2273 + * token_table_release_no_lock() which releases the token. 2274 + */ 2275 + pthread_mutex_lock(&globals->notify_lock); 2276 + 2277 + t = token_table_find_no_lock(token); 2278 + if (t == NULL) 2279 + { 2280 + pthread_mutex_unlock(&globals->notify_lock); 2281 + return NOTIFY_STATUS_INVALID_TOKEN; 2282 + } 2283 + 2284 + if (t->flags & NOTIFY_FLAG_SELF) 2285 + { 2286 + /* 2287 + * _notify_lib_cancel returns NOTIFY_STATUS_FAILED if self_state is NULL 2288 + * We let it fail quietly. 2289 + */ 2290 + _notify_lib_cancel(globals->self_state, NOTIFY_CLIENT_SELF, t->token); 2291 + 2292 + token_table_release_no_lock(t); 2293 + pthread_mutex_unlock(&globals->notify_lock); 2294 + return NOTIFY_STATUS_OK; 2295 + } 2296 + 2297 + if (globals->notify_ipc_version == 0) 2298 + { 2299 + kstatus = _notify_server_cancel(globals->notify_server_port, t->client_id, (int32_t *)&status); 2300 + if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE; 2301 + } 2302 + else 2303 + { 2304 + kstatus = _notify_server_cancel_2(globals->notify_server_port, token); 2305 + } 2306 + 2307 + token_table_release_no_lock(t); 2308 + pthread_mutex_unlock(&globals->notify_lock); 2309 + 2310 + if ((kstatus == MIG_SERVER_DIED) || (kstatus == MACH_SEND_INVALID_DEST)) return NOTIFY_STATUS_OK; 2311 + else if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; 2312 + 2313 + return NOTIFY_STATUS_OK; 2314 + } 2315 + 2316 + bool 2317 + notify_is_valid_token(int val) 2318 + { 2319 + token_table_node_t *t; 2320 + bool valid = false; 2321 + 2322 + if (val < 0) return false; 2323 + 2324 + notify_globals_t globals = _notify_globals(); 2325 + 2326 + pthread_mutex_lock(&globals->notify_lock); 2327 + 2328 + t = (token_table_node_t *)_nc_table_find_n(globals->token_table, val); 2329 + if (t != NULL) valid = true; 2330 + 2331 + pthread_mutex_unlock(&globals->notify_lock); 2332 + 2333 + return valid; 2334 + } 2335 + 2336 + uint32_t 2337 + notify_suspend(int token) 2338 + { 2339 + token_table_node_t *t; 2340 + uint32_t status, tid; 2341 + kern_return_t kstatus; 2342 + notify_globals_t globals = _notify_globals(); 2343 + 2344 + regenerate_check(); 2345 + 2346 + t = token_table_find_retain(token); 2347 + if (t == NULL) return NOTIFY_STATUS_INVALID_TOKEN; 2348 + 2349 + if (t->flags & NOTIFY_FLAG_SELF) 2350 + { 2351 + _notify_lib_suspend(globals->self_state, NOTIFY_CLIENT_SELF, t->token); 2352 + token_table_release(t); 2353 + return NOTIFY_STATUS_OK; 2354 + } 2355 + 2356 + if (globals->notify_server_port == MACH_PORT_NULL) 2357 + { 2358 + status = _notify_lib_init(EVENT_INIT); 2359 + if (status != 0) 2360 + { 2361 + token_table_release(t); 2362 + return NOTIFY_STATUS_FAILED; 2363 + } 2364 + } 2365 + 2366 + tid = token; 2367 + if (globals->notify_ipc_version == 0) tid = t->client_id; 2368 + 2369 + kstatus = _notify_server_suspend(globals->notify_server_port, tid, (int32_t *)&status); 2370 + 2371 + token_table_release(t); 2372 + if (kstatus != KERN_SUCCESS) status = NOTIFY_STATUS_FAILED; 2373 + return status; 2374 + } 2375 + 2376 + uint32_t 2377 + notify_resume(int token) 2378 + { 2379 + token_table_node_t *t; 2380 + uint32_t status, tid; 2381 + kern_return_t kstatus; 2382 + notify_globals_t globals = _notify_globals(); 2383 + 2384 + regenerate_check(); 2385 + 2386 + t = token_table_find_retain(token); 2387 + if (t == NULL) return NOTIFY_STATUS_INVALID_TOKEN; 2388 + 2389 + if (t->flags & NOTIFY_FLAG_SELF) 2390 + { 2391 + _notify_lib_resume(globals->self_state, NOTIFY_CLIENT_SELF, t->token); 2392 + token_table_release(t); 2393 + return NOTIFY_STATUS_OK; 2394 + } 2395 + 2396 + if (globals->notify_server_port == MACH_PORT_NULL) 2397 + { 2398 + status = _notify_lib_init(EVENT_INIT); 2399 + if (status != 0) 2400 + { 2401 + token_table_release(t); 2402 + return NOTIFY_STATUS_FAILED; 2403 + } 2404 + } 2405 + 2406 + tid = token; 2407 + if (globals->notify_ipc_version == 0) tid = t->client_id; 2408 + 2409 + kstatus = _notify_server_resume(globals->notify_server_port, tid, (int32_t *)&status); 2410 + 2411 + token_table_release(t); 2412 + if (kstatus != KERN_SUCCESS) status = NOTIFY_STATUS_FAILED; 2413 + return status; 2414 + } 2415 + 2416 + uint32_t 2417 + notify_suspend_pid(pid_t pid) 2418 + { 2419 + uint32_t status; 2420 + kern_return_t kstatus; 2421 + notify_globals_t globals = _notify_globals(); 2422 + 2423 + if (globals->notify_server_port == MACH_PORT_NULL) 2424 + { 2425 + status = _notify_lib_init(EVENT_INIT); 2426 + if (status != 0) 2427 + { 2428 + return NOTIFY_STATUS_FAILED; 2429 + } 2430 + } 2431 + 2432 + kstatus = _notify_server_suspend_pid(globals->notify_server_port, pid, (int32_t *)&status); 2433 + 2434 + if (kstatus != KERN_SUCCESS) status = NOTIFY_STATUS_FAILED; 2435 + return status; 2436 + } 2437 + 2438 + uint32_t 2439 + notify_resume_pid(pid_t pid) 2440 + { 2441 + uint32_t status; 2442 + kern_return_t kstatus; 2443 + notify_globals_t globals = _notify_globals(); 2444 + 2445 + if (globals->notify_server_port == MACH_PORT_NULL) 2446 + { 2447 + status = _notify_lib_init(EVENT_INIT); 2448 + if (status != 0) 2449 + { 2450 + return NOTIFY_STATUS_FAILED; 2451 + } 2452 + } 2453 + 2454 + kstatus = _notify_server_resume_pid(globals->notify_server_port, pid, (int32_t *)&status); 2455 + 2456 + if (kstatus != KERN_SUCCESS) status = NOTIFY_STATUS_FAILED; 2457 + return status; 2458 + } 2459 + 2460 + /* Deprecated SPI */ 2461 + uint32_t 2462 + notify_simple_post(const char *name) 2463 + { 2464 + return notify_post(name); 2465 + }
+1
libnotify/notify_get_state.3
··· 1 + .so man3/notify.3
+99
libnotify/notify_internal.h
··· 1 + /* 2 + * Copyright (c) 2012 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #include <dispatch/dispatch.h> 25 + #include <mach/mach.h> 26 + #include <pthread.h> 27 + #include <stdint.h> 28 + #include <TargetConditionals.h> 29 + 30 + struct notify_globals_s { 31 + // Global lock. 32 + pthread_mutex_t notify_lock; 33 + 34 + int32_t notify_ipc_version; 35 + pid_t notify_server_pid; 36 + 37 + uint32_t client_opts; 38 + uint32_t saved_opts; 39 + 40 + // Last allocated name id. 41 + uint64_t name_id; 42 + 43 + dispatch_once_t self_state_once; 44 + notify_state_t *self_state; 45 + 46 + dispatch_once_t notify_server_port_once; 47 + mach_port_t notify_server_port; 48 + mach_port_t saved_server_port; 49 + 50 + mach_port_t notify_common_port; 51 + int notify_common_token; 52 + dispatch_source_t notify_dispatch_source; 53 + dispatch_source_t server_proc_source; 54 + 55 + dispatch_once_t token_table_once; 56 + table_t *token_table; 57 + table_t *token_name_table; 58 + uint32_t token_id; 59 + 60 + // File descriptor list. 61 + uint32_t fd_count; 62 + int *fd_clnt; 63 + int *fd_srv; 64 + int *fd_refcount; 65 + 66 + // Mach port list. 67 + uint32_t mp_count; 68 + mach_port_t *mp_list; 69 + int *mp_refcount; 70 + int *mp_mine; 71 + 72 + // Shared memory base address. 73 + uint32_t *shm_base; 74 + }; 75 + typedef struct notify_globals_s *notify_globals_t; 76 + 77 + #if __has_include(<os/alloc_once_private.h>) 78 + #include <os/alloc_once_private.h> 79 + #if defined(OS_ALLOC_ONCE_KEY_LIBSYSTEM_NOTIFY) 80 + #define _NOTIFY_HAS_ALLOC_ONCE 1 81 + #endif 82 + #endif 83 + 84 + __attribute__((visibility("hidden"))) 85 + void _notify_init_globals(void * /* notify_globals_t */ globals); 86 + 87 + __attribute__((visibility("hidden"))) 88 + notify_globals_t _notify_globals_impl(void); 89 + 90 + __attribute__((__pure__)) 91 + static inline notify_globals_t 92 + _notify_globals(void) { 93 + #if _NOTIFY_HAS_ALLOC_ONCE 94 + return (notify_globals_t)os_alloc_once(OS_ALLOC_ONCE_KEY_LIBSYSTEM_NOTIFY, 95 + sizeof(struct notify_globals_s), &_notify_init_globals); 96 + #else 97 + return _notify_globals_impl(); 98 + #endif 99 + }
+373
libnotify/notify_ipc.defs
··· 1 + /* 2 + * Copyright (c) 2003-2011 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #include <mach/std_types.defs> 25 + #include <mach/mach_types.defs> 26 + 27 + subsystem notify_ipc 78945668; 28 + serverprefix _; 29 + 30 + import <sys/types.h>; 31 + 32 + import "notify_ipc_types.h"; 33 + 34 + type notify_name = ^ array [] of MACH_MSG_TYPE_BYTE 35 + ctype : caddr_t; 36 + 37 + routine _notify_server_post 38 + ( 39 + server : mach_port_t; 40 + name : notify_name; 41 + out status : int; 42 + ServerAuditToken audit : audit_token_t 43 + ); 44 + 45 + routine _notify_server_register_plain 46 + ( 47 + server : mach_port_t; 48 + name : notify_name; 49 + out token : int; 50 + out status : int; 51 + ServerAuditToken audit : audit_token_t 52 + ); 53 + 54 + routine _notify_server_register_check 55 + ( 56 + server : mach_port_t; 57 + name : notify_name; 58 + out size : int; 59 + out slot : int; 60 + out token : int; 61 + out status : int; 62 + ServerAuditToken audit : audit_token_t 63 + ); 64 + 65 + routine _notify_server_register_signal 66 + ( 67 + server : mach_port_t; 68 + name : notify_name; 69 + sig: int; 70 + out token : int; 71 + out status : int; 72 + ServerAuditToken audit : audit_token_t 73 + ); 74 + 75 + routine _notify_server_register_file_descriptor 76 + ( 77 + server : mach_port_t; 78 + name : notify_name; 79 + fileport : mach_port_move_send_t; 80 + ntoken : int; 81 + out token : int; 82 + out status : int; 83 + ServerAuditToken audit : audit_token_t 84 + ); 85 + 86 + routine _notify_server_register_mach_port 87 + ( 88 + server : mach_port_t; 89 + name : notify_name; 90 + port : mach_port_move_send_t; 91 + ntoken : int; 92 + out token : int; 93 + out status : int; 94 + ServerAuditToken audit : audit_token_t 95 + ); 96 + 97 + routine _notify_server_set_owner 98 + ( 99 + server : mach_port_t; 100 + name : notify_name; 101 + user : int; 102 + group : int; 103 + out status : int; 104 + ServerAuditToken audit : audit_token_t 105 + ); 106 + 107 + routine _notify_server_get_owner 108 + ( 109 + server : mach_port_t; 110 + name : notify_name; 111 + out user : int; 112 + out group : int; 113 + out status : int; 114 + ServerAuditToken audit : audit_token_t 115 + ); 116 + 117 + routine _notify_server_set_access 118 + ( 119 + server : mach_port_t; 120 + name : notify_name; 121 + mode : int; 122 + out status : int; 123 + ServerAuditToken audit : audit_token_t 124 + ); 125 + 126 + routine _notify_server_get_access 127 + ( 128 + server : mach_port_t; 129 + name : notify_name; 130 + out mode : int; 131 + out status : int; 132 + ServerAuditToken audit : audit_token_t 133 + ); 134 + 135 + routine _notify_server_release_name 136 + ( 137 + server : mach_port_t; 138 + name : notify_name; 139 + out status : int; 140 + ServerAuditToken audit : audit_token_t 141 + ); 142 + 143 + routine _notify_server_cancel 144 + ( 145 + server : mach_port_t; 146 + token : int; 147 + out status : int; 148 + ServerAuditToken audit : audit_token_t 149 + ); 150 + 151 + routine _notify_server_check 152 + ( 153 + server : mach_port_t; 154 + token : int; 155 + out check : int; 156 + out status : int; 157 + ServerAuditToken audit : audit_token_t 158 + ); 159 + 160 + routine _notify_server_get_state 161 + ( 162 + server : mach_port_t; 163 + token : int; 164 + out state : uint64_t; 165 + out status : int; 166 + ServerAuditToken audit : audit_token_t 167 + ); 168 + 169 + routine _notify_server_set_state 170 + ( 171 + server : mach_port_t; 172 + token : int; 173 + state : uint64_t; 174 + out status : int; 175 + ServerAuditToken audit : audit_token_t 176 + ); 177 + 178 + skip; /* formerly _notify_server_get_val */ 179 + 180 + skip; /* formerly _notify_server_set_val */ 181 + 182 + routine _notify_server_monitor_file 183 + ( 184 + server : mach_port_t; 185 + token : int; 186 + path : notify_name; 187 + flags : int; 188 + out status : int; 189 + ServerAuditToken audit : audit_token_t 190 + ); 191 + 192 + routine _notify_server_suspend 193 + ( 194 + server : mach_port_t; 195 + token : int; 196 + out status : int; 197 + ServerAuditToken audit : audit_token_t 198 + ); 199 + 200 + routine _notify_server_resume 201 + ( 202 + server : mach_port_t; 203 + token : int; 204 + out status : int; 205 + ServerAuditToken audit : audit_token_t 206 + ); 207 + 208 + routine _notify_server_suspend_pid 209 + ( 210 + server : mach_port_t; 211 + pid : int; 212 + out status : int; 213 + ServerAuditToken audit : audit_token_t 214 + ); 215 + 216 + routine _notify_server_resume_pid 217 + ( 218 + server : mach_port_t; 219 + pid : int; 220 + out status : int; 221 + ServerAuditToken audit : audit_token_t 222 + ); 223 + 224 + simpleroutine _notify_server_simple_post 225 + ( 226 + server : mach_port_t; 227 + name : notify_name; 228 + ServerAuditToken audit : audit_token_t 229 + ); 230 + 231 + /* Additions for version 2 - more async support */ 232 + 233 + routine _notify_server_post_2 234 + ( 235 + server : mach_port_t; 236 + name : notify_name; 237 + out name_id : uint64_t; 238 + out status : int; 239 + ServerAuditToken audit : audit_token_t 240 + ); 241 + 242 + simpleroutine _notify_server_post_3 243 + ( 244 + server : mach_port_t; 245 + name_id : uint64_t; 246 + ServerAuditToken audit : audit_token_t 247 + ); 248 + 249 + simpleroutine _notify_server_post_4 250 + ( 251 + server : mach_port_t; 252 + name : notify_name; 253 + ServerAuditToken audit : audit_token_t 254 + ); 255 + 256 + simpleroutine _notify_server_register_plain_2 257 + ( 258 + server : mach_port_t; 259 + name : notify_name; 260 + token : int; 261 + ServerAuditToken audit : audit_token_t 262 + ); 263 + 264 + routine _notify_server_register_check_2 265 + ( 266 + server : mach_port_t; 267 + name : notify_name; 268 + token: int; 269 + out size : int; 270 + out slot : int; 271 + out name_id : uint64_t; 272 + out status : int; 273 + ServerAuditToken audit : audit_token_t 274 + ); 275 + 276 + simpleroutine _notify_server_register_signal_2 277 + ( 278 + server : mach_port_t; 279 + name : notify_name; 280 + token : int; 281 + sig: int; 282 + ServerAuditToken audit : audit_token_t 283 + ); 284 + 285 + simpleroutine _notify_server_register_file_descriptor_2 286 + ( 287 + server : mach_port_t; 288 + name : notify_name; 289 + token: int; 290 + fileport : mach_port_move_send_t; 291 + ServerAuditToken audit : audit_token_t 292 + ); 293 + 294 + simpleroutine _notify_server_register_mach_port_2 295 + ( 296 + server : mach_port_t; 297 + name : notify_name; 298 + token: int; 299 + port : mach_port_move_send_t; 300 + ServerAuditToken audit : audit_token_t 301 + ); 302 + 303 + simpleroutine _notify_server_cancel_2 304 + ( 305 + server : mach_port_t; 306 + token : int; 307 + ServerAuditToken audit : audit_token_t 308 + ); 309 + 310 + routine _notify_server_get_state_2 311 + ( 312 + server : mach_port_t; 313 + name_id : uint64_t; 314 + out state : uint64_t; 315 + out status : int; 316 + ServerAuditToken audit : audit_token_t 317 + ); 318 + 319 + routine _notify_server_get_state_3 320 + ( 321 + server : mach_port_t; 322 + token : int; 323 + out state : uint64_t; 324 + out nid : uint64_t; 325 + out status : int; 326 + ServerAuditToken audit : audit_token_t 327 + ); 328 + 329 + simpleroutine _notify_server_set_state_2 330 + ( 331 + server : mach_port_t; 332 + name_id : uint64_t; 333 + state : uint64_t; 334 + ServerAuditToken audit : audit_token_t 335 + ); 336 + 337 + routine _notify_server_set_state_3 338 + ( 339 + server : mach_port_t; 340 + token : int; 341 + state : uint64_t; 342 + out nid : uint64_t; 343 + out status : int; 344 + ServerAuditToken audit : audit_token_t 345 + ); 346 + 347 + simpleroutine _notify_server_monitor_file_2 348 + ( 349 + server : mach_port_t; 350 + token : int; 351 + path : notify_name; 352 + flags : int; 353 + ServerAuditToken audit : audit_token_t 354 + ); 355 + 356 + routine _notify_server_regenerate 357 + ( 358 + server : mach_port_t; 359 + name : notify_name; 360 + token : int; 361 + reg_type : uint32_t; 362 + port : mach_port_make_send_t; 363 + sig: int; 364 + prev_slot: int; 365 + prev_state : uint64_t; 366 + prev_time : uint64_t; 367 + path : notify_name; 368 + path_flags: int; 369 + out new_slot : int; 370 + out new_name_id : uint64_t; 371 + out status : int; 372 + ServerAuditToken audit : audit_token_t 373 + );
+32
libnotify/notify_ipc_types.h
··· 1 + /* 2 + * Copyright (c) 2003-2009 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * Portions Copyright (c) 2003-2009 Apple Inc. All Rights Reserved. 7 + * 8 + * This file contains Original Code and/or Modifications of Original Code 9 + * as defined in and that are subject to the Apple Public Source License 10 + * Version 2.0 (the 'License'). You may not use this file except in 11 + * compliance with the License. Please obtain a copy of the License at 12 + * http://www.opensource.apple.com/apsl/ and read it before using this 13 + * file. 14 + * 15 + * The Original Code and all software distributed under the License are 16 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 17 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 18 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 19 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 20 + * Please see the License for the specific language governing rights and 21 + * limitations under the License. 22 + * 23 + * @APPLE_LICENSE_HEADER_END@ 24 + */ 25 + 26 + #ifndef _NOTIFY_IPC_TYPES_H_ 27 + #define _NOTIFY_IPC_TYPES_H_ 28 + 29 + #include <sys/types.h> 30 + typedef char inline_data_t[2048]; 31 + 32 + #endif
+1
libnotify/notify_is_valid_token.3
··· 1 + .so man3/notify.3
+83
libnotify/notify_keys.h
··· 1 + /* 2 + * Copyright (c) 2007-2009 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * Portions Copyright (c) 2007-2009 Apple Inc. All Rights Reserved. 7 + * 8 + * This file contains Original Code and/or Modifications of Original Code 9 + * as defined in and that are subject to the Apple Public Source License 10 + * Version 2.0 (the 'License'). You may not use this file except in 11 + * compliance with the License. Please obtain a copy of the License at 12 + * http://www.opensource.apple.com/apsl/ and read it before using this 13 + * file. 14 + * 15 + * The Original Code and all software distributed under the License are 16 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 17 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 18 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 19 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 20 + * Please see the License for the specific language governing rights and 21 + * limitations under the License. 22 + * 23 + * @APPLE_LICENSE_HEADER_END@ 24 + */ 25 + 26 + /* 27 + * This file lists notification keys that are posted using the 28 + * notify_post() API by various Mac OS X system services. 29 + * The exact circumstances under which services post these 30 + * notifications is controlled by those services, and may change 31 + * in future software releases. 32 + */ 33 + 34 + /* 35 + * Directory Service notifications 36 + * These are posted by the DirectoryService daemon to advise clients that 37 + * cached data should be invalidated. 38 + */ 39 + #define kNotifyDSCacheInvalidation "com.apple.system.DirectoryService.InvalidateCache" 40 + #define kNotifyDSCacheInvalidationGroup "com.apple.system.DirectoryService.InvalidateCache.group" 41 + #define kNotifyDSCacheInvalidationHost "com.apple.system.DirectoryService.InvalidateCache.host" 42 + #define kNotifyDSCacheInvalidationService "com.apple.system.DirectoryService.InvalidateCache.service" 43 + #define kNotifyDSCacheInvalidationUser "com.apple.system.DirectoryService.InvalidateCache.user" 44 + 45 + /* 46 + * File System notifications 47 + * These advise clients of various filesystem events. 48 + */ 49 + #define kNotifyVFSMount "com.apple.system.kernel.mount" 50 + #define kNotifyVFSUnmount "com.apple.system.kernel.unmount" 51 + #define kNotifyVFSUpdate "com.apple.system.kernel.mountupdate" 52 + #define kNotifyVFSLowDiskSpace "com.apple.system.lowdiskspace" 53 + #define kNotifyVFSLowDiskSpaceRootFS "com.apple.system.lowdiskspace.system" 54 + #define kNotifyVFSLowDiskSpaceOtherFS "com.apple.system.lowdiskspace.user" 55 + 56 + /* 57 + * System Configuration notifications 58 + * These advise clients of changes in the system configuration 59 + * managed by the system configuration server (configd). 60 + * Note that a much richer set of notifications are available to 61 + * clients using the SCDynamicStore API. 62 + */ 63 + #define kNotifySCHostNameChange "com.apple.system.hostname" 64 + #define kNotifySCNetworkChange "com.apple.system.config.network_change" 65 + 66 + /* 67 + * ASL notifications 68 + * Sent by syslogd to advise clients that new log messages have been 69 + * added to the ASL database. 70 + */ 71 + #define kNotifyASLDBUpdate "com.apple.system.logger.message" 72 + 73 + /* 74 + * Time Zone change notification 75 + * Sent by notifyd when the system's timezone changes. 76 + */ 77 + #define kNotifyTimeZoneChange "com.apple.system.timezone" 78 + 79 + /* 80 + * System clock change notification 81 + * Sent when a process modifies the system clock using the settimeofday system call. 82 + */ 83 + #define kNotifyClockSet "com.apple.system.clock_set"
+1
libnotify/notify_post.3
··· 1 + .so man3/notify.3
+47
libnotify/notify_private.h
··· 1 + /* 2 + * Copyright (c) 2009-2010 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #ifndef __NOTIFY_PRIVATE_H__ 25 + #define __NOTIFY_PRIVATE_H__ 26 + 27 + #include <stdint.h> 28 + #include <Availability.h> 29 + 30 + #define NOTIFY_OPT_DEMUX 0x00000001 31 + #define NOTIFY_OPT_REGEN 0x00000002 32 + #define NOTIFY_OPT_ENABLE 0x04000000 33 + #define NOTIFY_OPT_DISABLE 0x08000000 34 + 35 + uint32_t notify_suspend_pid(pid_t pid) 36 + __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0); 37 + 38 + uint32_t notify_resume_pid(pid_t pid) 39 + __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0); 40 + 41 + uint32_t notify_simple_post(const char *name) 42 + __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_3); 43 + 44 + void notify_set_options(uint32_t opts) 45 + __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_6_0); 46 + 47 + #endif /* __NOTIFY_PRIVATE_H__ */
+1
libnotify/notify_register_check.3
··· 1 + .so man3/notify.3
+1
libnotify/notify_register_dispatch.3
··· 1 + .so man3/notify.3
+1
libnotify/notify_register_file_descriptor.3
··· 1 + .so man3/notify.3
+1
libnotify/notify_register_mach_port.3
··· 1 + .so man3/notify.3
+1
libnotify/notify_register_signal.3
··· 1 + .so man3/notify.3
+1
libnotify/notify_set_state.3
··· 1 + .so man3/notify.3
+31
libnotify/notifyd/com.apple.notifyd.plist
··· 1 + <?xml version="1.0" encoding="UTF-8"?> 2 + <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 + <plist version="1.0"> 4 + <dict> 5 + <key>EnableTransactions</key> 6 + <true/> 7 + <key>Label</key> 8 + <string>com.apple.notifyd</string> 9 + <key>EnvironmentVariables</key> 10 + <dict> 11 + <key>ASL_DISABLE</key> 12 + <string>1</string> 13 + </dict> 14 + <key>MachServices</key> 15 + <dict> 16 + <key>com.apple.system.notification_center</key> 17 + <true/> 18 + </dict> 19 + <key>ProgramArguments</key> 20 + <array> 21 + <string>/usr/sbin/notifyd</string> 22 + </array> 23 + <key>JetsamProperties</key> 24 + <dict> 25 + <key>JetsamPriority</key> 26 + <integer>-1000</integer> 27 + </dict> 28 + <key>POSIXSpawnType</key> 29 + <string>Interactive</string> 30 + </dict> 31 + </plist>
+10
libnotify/notifyd/notify.conf.MacOSX
··· 1 + # 2 + # Notification Center configuration file 3 + # 4 + 5 + reserve com.apple.system. 0 0 rwr-r- 6 + monitor com.apple.system.timezone /etc/localtime 7 + monitor com.apple.system.info:/etc/hosts /etc/hosts 8 + monitor com.apple.system.info:/etc/services /etc/services 9 + monitor com.apple.system.info:/etc/protocols /etc/protocols 10 +
+7
libnotify/notifyd/notify.conf.iPhone
··· 1 + # 2 + # Notification Center configuration file 3 + # 4 + 5 + reserve com.apple.system. 0 0 rwr-r- 6 + reserve com.apple.system.clock_set 0 501 rwrwr- 7 + monitor com.apple.system.timezone /var/db/timezone/localtime
+1623
libnotify/notifyd/notify_proc.c
··· 1 + /* 2 + * Copyright (c) 2003-2010 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #include <stdio.h> 25 + #include <stdlib.h> 26 + #include <string.h> 27 + #include <asl.h> 28 + #include <bsm/libbsm.h> 29 + #include <mach/mach.h> 30 + #include <mach/mach_error.h> 31 + #include <mach/mach_traps.h> 32 + #include <sys/sysctl.h> 33 + #include <pthread.h> 34 + #include <sys/fcntl.h> 35 + #include <dispatch/private.h> 36 + #include "notify.h" 37 + #include "notifyd.h" 38 + #include "service.h" 39 + #include "notify_ipc.h" 40 + #include "notify_ipcServer.h" 41 + 42 + static void 43 + cancel_subscription(client_t *c) 44 + { 45 + name_info_t *n; 46 + int token; 47 + 48 + if (global.notify_state == NULL) return; 49 + if (c == NULL) return; 50 + 51 + call_statistics.cleanup++; 52 + 53 + token = c->client_id; 54 + 55 + if (c->private != NULL) 56 + { 57 + service_close(c->private); 58 + c->private = NULL; 59 + } 60 + 61 + n = c->name_info; 62 + if ((n != NULL) && (n->refcount == 1) && (n->private != NULL)) 63 + { 64 + service_close(n->private); 65 + n->private = NULL; 66 + } 67 + 68 + _notify_lib_port_proc_release(global.notify_state, MACH_PORT_NULL, c->pid); 69 + 70 + if (c->notify_type == NOTIFY_TYPE_MEMORY) 71 + { 72 + global.shared_memory_refcount[n->slot]--; 73 + } 74 + else if (c->notify_type == NOTIFY_TYPE_PORT) 75 + { 76 + _notify_lib_port_proc_release(global.notify_state, c->port, 0); 77 + } 78 + 79 + _notify_lib_cancel(global.notify_state, c->pid, token); 80 + } 81 + 82 + static void 83 + cancel_proc(void *px) 84 + { 85 + void *tt; 86 + long lpid = (long)px; 87 + pid_t pid; 88 + client_t *c; 89 + list_t *l, *x; 90 + 91 + if (global.notify_state == NULL) return; 92 + 93 + pid = lpid; 94 + x = NULL; 95 + 96 + tt = _nc_table_traverse_start(global.notify_state->client_table); 97 + while (tt != NULL) 98 + { 99 + c = _nc_table_traverse(global.notify_state->client_table, tt); 100 + if (c == NULL) break; 101 + 102 + if (c->pid == pid) x = _nc_list_prepend(x, _nc_list_new(c)); 103 + } 104 + _nc_table_traverse_end(global.notify_state->client_table, tt); 105 + 106 + for (l = x; l != NULL; l = _nc_list_next(l)) 107 + { 108 + c = _nc_list_data(l); 109 + cancel_subscription(c); 110 + } 111 + 112 + _nc_list_release_list(x); 113 + } 114 + 115 + static void 116 + cancel_port(mach_port_t port, dispatch_source_t src) 117 + { 118 + void *tt; 119 + client_t *c; 120 + list_t *l, *x; 121 + 122 + if (global.notify_state == NULL) return; 123 + 124 + x = NULL; 125 + 126 + tt = _nc_table_traverse_start(global.notify_state->client_table); 127 + while (tt != NULL) 128 + { 129 + c = _nc_table_traverse(global.notify_state->client_table, tt); 130 + if (c == NULL) break; 131 + 132 + if (c->port == port) x = _nc_list_prepend(x, _nc_list_new(c)); 133 + } 134 + _nc_table_traverse_end(global.notify_state->client_table, tt); 135 + 136 + for (l = x; l != NULL; l = _nc_list_next(l)) 137 + { 138 + c = _nc_list_data(l); 139 + cancel_subscription(c); 140 + } 141 + 142 + _nc_list_release_list(x); 143 + } 144 + 145 + static void 146 + port_event(void *px) 147 + { 148 + long lport = (long)px; 149 + mach_port_t port; 150 + unsigned long data; 151 + portproc_data_t *pp; 152 + 153 + if (global.notify_state == NULL) return; 154 + 155 + port = (mach_port_t)lport; 156 + if (port == MACH_PORT_NULL) return; 157 + 158 + pp = _notify_lib_port_proc_find(global.notify_state, port, 0); 159 + if (pp == NULL) 160 + { 161 + log_message(ASL_LEVEL_DEBUG, "can't find port source for %u\n", port); 162 + return; 163 + } 164 + 165 + data = dispatch_source_get_data(pp->src); 166 + 167 + if (data & DISPATCH_MACH_SEND_DEAD) 168 + { 169 + cancel_port(port, pp->src); 170 + } 171 + else if (data & DISPATCH_MACH_SEND_POSSIBLE) 172 + { 173 + _notify_lib_resume_port(global.notify_state, port); 174 + } 175 + else 176 + { 177 + log_message(ASL_LEVEL_DEBUG, "unknown data 0x%lx for %u\n", data, port); 178 + } 179 + 180 + _notify_lib_port_proc_release(global.notify_state, port, 0); 181 + } 182 + 183 + static void 184 + port_dealloc(void *px) 185 + { 186 + long lport = (long)px; 187 + mach_port_t port = (mach_port_t)lport; 188 + 189 + if (port == MACH_PORT_NULL) return; 190 + mach_port_deallocate(mach_task_self(), port); 191 + } 192 + 193 + static void 194 + port_registration_complete(void *px) 195 + { 196 + long lport = (long)px; 197 + mach_port_t port; 198 + 199 + if (global.notify_state == NULL) return; 200 + 201 + port = (mach_port_t)lport; 202 + _notify_lib_resume_port(global.notify_state, port); 203 + } 204 + 205 + static void 206 + register_pid(pid_t pid) 207 + { 208 + dispatch_source_t src; 209 + long lpid; 210 + portproc_data_t *pp; 211 + 212 + if (global.notify_state == NULL) return; 213 + if (pid <= 0) return; 214 + 215 + /* 216 + * Check if this pid has already registered. 217 + * N.B. This call retains the portproc_data_t. We want that. 218 + */ 219 + pp = _notify_lib_port_proc_find(global.notify_state, MACH_PORT_NULL, pid); 220 + if (pp != NULL) return; 221 + 222 + src = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT, global.work_q); 223 + dispatch_source_set_event_handler_f(src, (dispatch_function_t)cancel_proc); 224 + 225 + lpid = pid; 226 + dispatch_set_context(src, (void *)lpid); 227 + 228 + _notify_lib_port_proc_new(global.notify_state, MACH_PORT_NULL, pid, 0, src); 229 + 230 + dispatch_resume(src); 231 + } 232 + 233 + static void 234 + register_port(client_t *c) 235 + { 236 + dispatch_source_t src; 237 + long lport; 238 + portproc_data_t *pp; 239 + 240 + if (c == NULL) return; 241 + 242 + /* ignore MACH_PORT_DEAD */ 243 + if (c->port == MACH_PORT_DEAD) return; 244 + 245 + /* 246 + * Check if this port has already registered. 247 + * N.B. This call retains the portproc_data_t. We want that. 248 + */ 249 + pp = _notify_lib_port_proc_find(global.notify_state, c->port, 0); 250 + if (pp != NULL) return; 251 + 252 + src = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, c->port, DISPATCH_MACH_SEND_DEAD | DISPATCH_MACH_SEND_POSSIBLE, global.work_q); 253 + 254 + dispatch_source_set_event_handler_f(src, (dispatch_function_t)port_event); 255 + 256 + /* retain send right for port - port_dealloc() will release when the source goes away */ 257 + mach_port_mod_refs(mach_task_self(), c->port, MACH_PORT_RIGHT_SEND, +1); 258 + dispatch_source_set_cancel_handler_f(src, (dispatch_function_t)port_dealloc); 259 + 260 + lport = c->port; 261 + dispatch_set_context(src, (void *)lport); 262 + 263 + dispatch_source_set_registration_handler_f(src, (dispatch_function_t)port_registration_complete); 264 + 265 + _notify_lib_port_proc_new(global.notify_state, c->port, 0, NOTIFY_PORT_PROC_STATE_SUSPENDED, src); 266 + 267 + dispatch_resume(src); 268 + } 269 + 270 + static uint32_t 271 + server_preflight(caddr_t name, mach_msg_type_number_t nameCnt, audit_token_t audit, int token, uid_t *uid, gid_t *gid, pid_t *pid, uint64_t *cid) 272 + { 273 + pid_t xpid; 274 + 275 + if ((name == NULL) && (nameCnt != 0)) return NOTIFY_STATUS_INVALID_NAME; 276 + 277 + if (global.notify_state == NULL) 278 + { 279 + if (name != NULL) vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 280 + return NOTIFY_STATUS_FAILED; 281 + } 282 + 283 + if ((name != NULL) && (name[nameCnt] != '\0')) 284 + { 285 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 286 + return NOTIFY_STATUS_INVALID_NAME; 287 + } 288 + 289 + audit_token_to_au32(audit, NULL, uid, gid, NULL, NULL, &xpid, NULL, NULL); 290 + if (pid != NULL) *pid = xpid; 291 + 292 + if (token > 0) 293 + { 294 + client_t *c; 295 + uint64_t xcid = make_client_id(xpid, token); 296 + if (cid != NULL) *cid = xcid; 297 + 298 + c = _nc_table_find_64(global.notify_state->client_table, xcid); 299 + if (c != NULL) 300 + { 301 + /* duplicate tokens can occur if a process exec()s */ 302 + log_message(ASL_LEVEL_DEBUG, "duplicate token %d sent from PID %d\n", token, xpid); 303 + cancel_subscription(c); 304 + } 305 + } 306 + 307 + return NOTIFY_STATUS_OK; 308 + } 309 + 310 + kern_return_t __notify_server_post_3 311 + ( 312 + mach_port_t server, 313 + uint64_t name_id, 314 + audit_token_t audit 315 + ) 316 + { 317 + uid_t uid = (uid_t)-1; 318 + gid_t gid = (gid_t)-1; 319 + 320 + if (global.notify_state == NULL) return KERN_SUCCESS; 321 + 322 + call_statistics.post++; 323 + call_statistics.post_by_id++; 324 + 325 + log_message(ASL_LEVEL_DEBUG, "__notify_server_post name_id %llu\n", name_id); 326 + 327 + audit_token_to_au32(audit, NULL, &uid, &gid, NULL, NULL, NULL, NULL, NULL); 328 + 329 + daemon_post_nid(name_id, uid, gid); 330 + return KERN_SUCCESS; 331 + } 332 + 333 + kern_return_t __notify_server_post_2 334 + ( 335 + mach_port_t server, 336 + caddr_t name, 337 + mach_msg_type_number_t nameCnt, 338 + uint64_t *name_id, 339 + int *status, 340 + audit_token_t audit 341 + ) 342 + { 343 + uid_t uid = (uid_t)-1; 344 + gid_t gid = (gid_t)-1; 345 + name_info_t *n; 346 + 347 + *name_id = 0; 348 + 349 + *status = server_preflight(name, nameCnt, audit, -1, &uid, &gid, NULL, NULL); 350 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 351 + 352 + call_statistics.post++; 353 + call_statistics.post_by_name_and_fetch_id++; 354 + 355 + *status = _notify_lib_check_controlled_access(global.notify_state, name, uid, gid, NOTIFY_ACCESS_WRITE); 356 + if (*status != NOTIFY_STATUS_OK) 357 + { 358 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 359 + return KERN_SUCCESS; 360 + } 361 + 362 + n = NULL; 363 + *status = daemon_post(name, uid, gid); 364 + if (*status == NOTIFY_STATUS_OK) 365 + { 366 + n = (name_info_t *)_nc_table_find(global.notify_state->name_table, name); 367 + } 368 + 369 + if (n == NULL) 370 + { 371 + *status = NOTIFY_STATUS_INVALID_NAME; 372 + *name_id = UINT64_MAX; 373 + call_statistics.post_no_op++; 374 + } 375 + else 376 + { 377 + *name_id = n->name_id; 378 + } 379 + 380 + if (*name_id == UINT64_MAX) log_message(ASL_LEVEL_DEBUG, "__notify_server_post %s\n", name); 381 + else log_message(ASL_LEVEL_DEBUG, "__notify_server_post %s [%llu]\n", name, *name_id); 382 + 383 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 384 + 385 + return KERN_SUCCESS; 386 + } 387 + 388 + kern_return_t __notify_server_post_4 389 + ( 390 + mach_port_t server, 391 + caddr_t name, 392 + mach_msg_type_number_t nameCnt, 393 + audit_token_t audit 394 + ) 395 + { 396 + uint64_t ignored_name_id; 397 + int ignored_status; 398 + kern_return_t kstatus; 399 + 400 + kstatus = __notify_server_post_2(server, name, nameCnt, &ignored_name_id, &ignored_status, audit); 401 + 402 + call_statistics.post_by_name_and_fetch_id--; 403 + call_statistics.post_by_name++; 404 + 405 + return kstatus; 406 + } 407 + 408 + kern_return_t __notify_server_post 409 + ( 410 + mach_port_t server, 411 + caddr_t name, 412 + mach_msg_type_number_t nameCnt, 413 + int *status, 414 + audit_token_t audit 415 + ) 416 + { 417 + uint64_t ignored_name_id; 418 + kern_return_t kstatus; 419 + 420 + *status = NOTIFY_STATUS_OK; 421 + 422 + kstatus = __notify_server_post_2(server, name, nameCnt, &ignored_name_id, status, audit); 423 + 424 + call_statistics.post_by_name_and_fetch_id--; 425 + call_statistics.post_by_name++; 426 + 427 + if (*status == NOTIFY_STATUS_INVALID_NAME) *status = NOTIFY_STATUS_OK; 428 + 429 + return kstatus; 430 + } 431 + 432 + kern_return_t __notify_server_register_plain_2 433 + ( 434 + mach_port_t server, 435 + caddr_t name, 436 + mach_msg_type_number_t nameCnt, 437 + int token, 438 + audit_token_t audit 439 + ) 440 + { 441 + client_t *c; 442 + uint64_t nid, cid; 443 + uint32_t status; 444 + uid_t uid = (uid_t)-1; 445 + gid_t gid = (gid_t)-1; 446 + pid_t pid = (pid_t)-1; 447 + 448 + call_statistics.reg++; 449 + call_statistics.reg_plain++; 450 + 451 + status = server_preflight(name, nameCnt, audit, token, &uid, &gid, &pid, &cid); 452 + if (status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 453 + 454 + log_message(ASL_LEVEL_DEBUG, "__notify_server_register_plain %s %d %d\n", name, pid, token); 455 + 456 + status = _notify_lib_register_plain(global.notify_state, name, pid, token, -1, uid, gid, &nid); 457 + if (status != NOTIFY_STATUS_OK) 458 + { 459 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 460 + return KERN_SUCCESS; 461 + } 462 + 463 + c = _nc_table_find_64(global.notify_state->client_table, cid); 464 + 465 + if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, uid, gid); 466 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 467 + 468 + register_pid(pid); 469 + 470 + return KERN_SUCCESS; 471 + } 472 + 473 + kern_return_t __notify_server_register_check_2 474 + ( 475 + mach_port_t server, 476 + caddr_t name, 477 + mach_msg_type_number_t nameCnt, 478 + int token, 479 + int *size, 480 + int *slot, 481 + uint64_t *name_id, 482 + int *status, 483 + audit_token_t audit 484 + ) 485 + { 486 + name_info_t *n; 487 + uint32_t i, j, x, new_slot; 488 + uint64_t cid; 489 + client_t *c; 490 + uid_t uid = (uid_t)-1; 491 + gid_t gid = (gid_t)-1; 492 + pid_t pid = (pid_t)-1; 493 + 494 + *size = 0; 495 + *slot = 0; 496 + *name_id = 0; 497 + *status = NOTIFY_STATUS_OK; 498 + 499 + *status = server_preflight(name, nameCnt, audit, token, &uid, &gid, &pid, &cid); 500 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 501 + 502 + call_statistics.reg++; 503 + call_statistics.reg_check++; 504 + 505 + if (global.nslots == 0) 506 + { 507 + *size = -1; 508 + *slot = -1; 509 + return __notify_server_register_plain_2(server, name, nameCnt, token, audit); 510 + } 511 + 512 + x = (uint32_t)-1; 513 + 514 + n = (name_info_t *)_nc_table_find(global.notify_state->name_table, name); 515 + if (n != NULL) x = n->slot; 516 + 517 + new_slot = 0; 518 + if (x == (uint32_t)-1) 519 + { 520 + /* find a slot */ 521 + new_slot = 1; 522 + 523 + /* 524 + * Check slots beginning at the current slot_id + 1, since it's likely that the 525 + * next slot will be available. Keep looking until we have examined all the 526 + * slots (skipping slot 0, which is reserved for notifyd). Stop if we find 527 + * an unused (refcount == 0) slot. 528 + */ 529 + for (i = 1, j = global.slot_id + 1; i < global.nslots; i++, j++) 530 + { 531 + if (j >= global.nslots) j = 1; 532 + if (global.shared_memory_refcount[j] == 0) 533 + { 534 + x = j; 535 + break; 536 + } 537 + } 538 + 539 + if (x == (uint32_t)-1) 540 + { 541 + /* 542 + * We did not find an unused slot. At this point, the shared 543 + * memory table is full, so we start re-using slots, beginning at 544 + * global.slot_id + 1. 545 + */ 546 + global.slot_id++; 547 + 548 + /* wrap around to slot 1 (slot 0 is reserved for notifyd) */ 549 + if (global.slot_id >= global.nslots) global.slot_id = 1; 550 + log_message(ASL_LEVEL_DEBUG, "reused shared memory slot %u\n", global.slot_id); 551 + x = global.slot_id; 552 + } 553 + else 554 + { 555 + /* found a free slot */ 556 + global.slot_id = x; 557 + } 558 + } 559 + 560 + if (new_slot == 1) global.shared_memory_base[x] = 1; 561 + global.shared_memory_refcount[x]++; 562 + 563 + log_message(ASL_LEVEL_DEBUG, "__notify_server_register_check %s %d %d\n", name, pid, token); 564 + 565 + *size = global.nslots * sizeof(uint32_t); 566 + *slot = x; 567 + *status = _notify_lib_register_plain(global.notify_state, name, pid, token, x, uid, gid, name_id); 568 + if (*status != NOTIFY_STATUS_OK) 569 + { 570 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 571 + return KERN_SUCCESS; 572 + } 573 + 574 + c = _nc_table_find_64(global.notify_state->client_table, cid); 575 + 576 + if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, uid, gid); 577 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 578 + 579 + register_pid(pid); 580 + 581 + return KERN_SUCCESS; 582 + } 583 + 584 + kern_return_t __notify_server_register_signal_2 585 + ( 586 + mach_port_t server, 587 + caddr_t name, 588 + mach_msg_type_number_t nameCnt, 589 + int token, 590 + int sig, 591 + audit_token_t audit 592 + ) 593 + { 594 + client_t *c; 595 + uint64_t name_id, cid; 596 + uint32_t status; 597 + uid_t uid = (uid_t)-1; 598 + gid_t gid = (gid_t)-1; 599 + pid_t pid = (pid_t)-1; 600 + 601 + status = server_preflight(name, nameCnt, audit, token, &uid, &gid, &pid, &cid); 602 + if (status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 603 + 604 + call_statistics.reg++; 605 + call_statistics.reg_signal++; 606 + 607 + log_message(ASL_LEVEL_DEBUG, "__notify_server_register_signal %s %d %d %d\n", name, pid, token, sig); 608 + 609 + status = _notify_lib_register_signal(global.notify_state, name, pid, token, sig, uid, gid, &name_id); 610 + if (status != NOTIFY_STATUS_OK) 611 + { 612 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 613 + return KERN_SUCCESS; 614 + } 615 + 616 + c = _nc_table_find_64(global.notify_state->client_table, cid); 617 + 618 + if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, uid, gid); 619 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 620 + 621 + register_pid(pid); 622 + 623 + return KERN_SUCCESS; 624 + } 625 + 626 + kern_return_t __notify_server_register_file_descriptor_2 627 + ( 628 + mach_port_t server, 629 + caddr_t name, 630 + mach_msg_type_number_t nameCnt, 631 + int token, 632 + fileport_t fileport, 633 + audit_token_t audit 634 + ) 635 + { 636 + client_t *c; 637 + int fd, flags; 638 + uint32_t status; 639 + uint64_t name_id, cid; 640 + uid_t uid = (uid_t)-1; 641 + gid_t gid = (gid_t)-1; 642 + pid_t pid = (pid_t)-1; 643 + 644 + status = server_preflight(name, nameCnt, audit, token, &uid, &gid, &pid, &cid); 645 + if (status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 646 + 647 + call_statistics.reg++; 648 + call_statistics.reg_file++; 649 + 650 + log_message(ASL_LEVEL_DEBUG, "__notify_server_register_file_descriptor %s %d %d\n", name, pid, token); 651 + 652 + fd = fileport_makefd(fileport); 653 + mach_port_deallocate(mach_task_self(), fileport); 654 + if (fd < 0) 655 + { 656 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 657 + return KERN_SUCCESS; 658 + } 659 + 660 + flags = fcntl(fd, F_GETFL, 0); 661 + if (flags < 0) 662 + { 663 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 664 + return KERN_SUCCESS; 665 + } 666 + 667 + flags |= O_NONBLOCK; 668 + if (fcntl(fd, F_SETFL, flags) < 0) 669 + { 670 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 671 + return KERN_SUCCESS; 672 + } 673 + 674 + status = _notify_lib_register_file_descriptor(global.notify_state, name, pid, token, fd, uid, gid, &name_id); 675 + if (status != NOTIFY_STATUS_OK) 676 + { 677 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 678 + return KERN_SUCCESS; 679 + } 680 + 681 + c = _nc_table_find_64(global.notify_state->client_table, cid); 682 + 683 + if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, uid, gid); 684 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 685 + 686 + register_pid(pid); 687 + 688 + return KERN_SUCCESS; 689 + } 690 + 691 + kern_return_t __notify_server_register_mach_port_2 692 + ( 693 + mach_port_t server, 694 + caddr_t name, 695 + mach_msg_type_number_t nameCnt, 696 + int token, 697 + mach_port_t port, 698 + audit_token_t audit 699 + ) 700 + { 701 + client_t *c; 702 + uint64_t name_id, cid; 703 + uint32_t status; 704 + uid_t uid = (uid_t)-1; 705 + gid_t gid = (gid_t)-1; 706 + pid_t pid = (pid_t)-1; 707 + 708 + if (port == MACH_PORT_DEAD) return KERN_SUCCESS; 709 + 710 + status = server_preflight(name, nameCnt, audit, token, &uid, &gid, &pid, &cid); 711 + if (status != NOTIFY_STATUS_OK) 712 + { 713 + mach_port_deallocate(mach_task_self(), port); 714 + return KERN_SUCCESS; 715 + } 716 + 717 + call_statistics.reg++; 718 + call_statistics.reg_port++; 719 + 720 + log_message(ASL_LEVEL_DEBUG, "__notify_server_register_mach_port %s %d %d\n", name, pid, token); 721 + 722 + status = _notify_lib_register_mach_port(global.notify_state, name, pid, token, port, uid, gid, &name_id); 723 + if (status != NOTIFY_STATUS_OK) 724 + { 725 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 726 + mach_port_deallocate(mach_task_self(), port); 727 + return KERN_SUCCESS; 728 + } 729 + 730 + c = _nc_table_find_64(global.notify_state->client_table,cid); 731 + 732 + if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, uid, gid); 733 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 734 + 735 + register_pid(pid); 736 + register_port(c); 737 + 738 + return KERN_SUCCESS; 739 + } 740 + 741 + kern_return_t __notify_server_cancel 742 + ( 743 + mach_port_t server, 744 + int token, 745 + int *status, 746 + audit_token_t audit 747 + ) 748 + { 749 + client_t *c; 750 + uid_t uid = (uid_t)-1; 751 + pid_t pid = (pid_t)-1; 752 + 753 + *status = server_preflight(NULL, 0, audit, -1, &uid, NULL, &pid, NULL); 754 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 755 + 756 + call_statistics.cancel++; 757 + 758 + log_message(ASL_LEVEL_DEBUG, "__notify_server_cancel %d %d\n", pid, token); 759 + 760 + *status = NOTIFY_STATUS_OK; 761 + 762 + c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 763 + if (c == NULL) *status = NOTIFY_STATUS_FAILED; 764 + else cancel_subscription(c); 765 + 766 + return KERN_SUCCESS; 767 + } 768 + 769 + kern_return_t __notify_server_cancel_2 770 + ( 771 + mach_port_t server, 772 + int token, 773 + audit_token_t audit 774 + ) 775 + { 776 + int ignored; 777 + return __notify_server_cancel(server, token, &ignored, audit); 778 + } 779 + 780 + kern_return_t __notify_server_suspend 781 + ( 782 + mach_port_t server, 783 + int token, 784 + int *status, 785 + audit_token_t audit 786 + ) 787 + { 788 + pid_t pid = (pid_t)-1; 789 + 790 + *status = server_preflight(NULL, 0, audit, -1, NULL, NULL, &pid, NULL); 791 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 792 + 793 + call_statistics.suspend++; 794 + 795 + log_message(ASL_LEVEL_DEBUG, "__notify_server_suspend %d %d\n", pid, token); 796 + 797 + _notify_lib_suspend(global.notify_state, pid, token); 798 + *status = NOTIFY_STATUS_OK; 799 + 800 + return KERN_SUCCESS; 801 + } 802 + 803 + kern_return_t __notify_server_resume 804 + ( 805 + mach_port_t server, 806 + int token, 807 + int *status, 808 + audit_token_t audit 809 + ) 810 + { 811 + pid_t pid = (pid_t)-1; 812 + 813 + *status = server_preflight(NULL, 0, audit, -1, NULL, NULL, &pid, NULL); 814 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 815 + 816 + call_statistics.resume++; 817 + 818 + log_message(ASL_LEVEL_DEBUG, "__notify_server_resume %d %d\n", pid, token); 819 + 820 + _notify_lib_resume(global.notify_state, pid, token); 821 + *status = NOTIFY_STATUS_OK; 822 + 823 + return KERN_SUCCESS; 824 + } 825 + 826 + static uid_t 827 + uid_for_pid(pid_t pid) 828 + { 829 + int mib[4]; 830 + struct kinfo_proc info; 831 + size_t size = sizeof(struct kinfo_proc); 832 + 833 + mib[0] = CTL_KERN; 834 + mib[1] = KERN_PROC; 835 + mib[2] = KERN_PROC_PID; 836 + mib[3] = pid; 837 + 838 + sysctl(mib, 4, &info, &size, 0, 0); 839 + 840 + return (uid_t)info.kp_eproc.e_ucred.cr_uid; 841 + } 842 + 843 + kern_return_t __notify_server_suspend_pid 844 + ( 845 + mach_port_t server, 846 + int pid, 847 + int *status, 848 + audit_token_t audit 849 + ) 850 + { 851 + uid_t uid, target_uid; 852 + 853 + uid = (uid_t)-1; 854 + 855 + *status = server_preflight(NULL, 0, audit, -1, &uid, NULL, NULL, NULL); 856 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 857 + 858 + call_statistics.suspend_pid++; 859 + 860 + log_message(ASL_LEVEL_DEBUG, "__notify_server_suspend_pid %d\n", pid); 861 + 862 + target_uid = uid_for_pid(pid); 863 + 864 + if ((uid != 0) && (target_uid != uid)) 865 + { 866 + *status = NOTIFY_STATUS_NOT_AUTHORIZED; 867 + return KERN_SUCCESS; 868 + } 869 + 870 + *status = NOTIFY_STATUS_OK; 871 + 872 + _notify_lib_suspend_proc(global.notify_state, pid); 873 + 874 + return KERN_SUCCESS; 875 + } 876 + 877 + kern_return_t __notify_server_resume_pid 878 + ( 879 + mach_port_t server, 880 + int pid, 881 + int *status, 882 + audit_token_t audit 883 + ) 884 + { 885 + uid_t uid, target_uid; 886 + 887 + uid = (uid_t)-1; 888 + 889 + *status = server_preflight(NULL, 0, audit, -1, &uid, NULL, NULL, NULL); 890 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 891 + 892 + call_statistics.resume_pid++; 893 + 894 + log_message(ASL_LEVEL_DEBUG, "__notify_server_resume_pid %d\n", pid); 895 + 896 + target_uid = uid_for_pid(pid); 897 + 898 + if ((uid != 0) && (target_uid != uid)) 899 + { 900 + *status = NOTIFY_STATUS_NOT_AUTHORIZED; 901 + return KERN_SUCCESS; 902 + } 903 + 904 + *status = NOTIFY_STATUS_OK; 905 + 906 + _notify_lib_resume_proc(global.notify_state, pid); 907 + 908 + return KERN_SUCCESS; 909 + } 910 + 911 + kern_return_t __notify_server_check 912 + ( 913 + mach_port_t server, 914 + int token, 915 + int *check, 916 + int *status, 917 + audit_token_t audit 918 + ) 919 + { 920 + pid_t pid = (gid_t)-1; 921 + 922 + *check = 0; 923 + 924 + call_statistics.check++; 925 + 926 + audit_token_to_au32(audit, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); 927 + 928 + log_message(ASL_LEVEL_DEBUG, "__notify_server_check %d %d\n", pid, token); 929 + 930 + *status = _notify_lib_check(global.notify_state, pid, token, check); 931 + return KERN_SUCCESS; 932 + } 933 + 934 + kern_return_t __notify_server_get_state 935 + ( 936 + mach_port_t server, 937 + int token, 938 + uint64_t *state, 939 + int *status, 940 + audit_token_t audit 941 + ) 942 + { 943 + uid_t uid = (uid_t)-1; 944 + gid_t gid = (gid_t)-1; 945 + pid_t pid = (pid_t)-1; 946 + client_t *c; 947 + 948 + *state = 0; 949 + 950 + *status = server_preflight(NULL, 0, audit, -1, &uid, &gid, &pid, NULL); 951 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 952 + 953 + call_statistics.get_state++; 954 + call_statistics.get_state_by_client++; 955 + 956 + log_message(ASL_LEVEL_DEBUG, "__notify_server_get_state %d %d\n", pid, token); 957 + 958 + c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 959 + if ((c == NULL) || (c->name_info == NULL)) 960 + { 961 + *status = NOTIFY_STATUS_FAILED; 962 + } 963 + else 964 + { 965 + *status = _notify_lib_get_state(global.notify_state, c->name_info->name_id, state, uid, gid); 966 + } 967 + 968 + return KERN_SUCCESS; 969 + } 970 + 971 + kern_return_t __notify_server_get_state_2 972 + ( 973 + mach_port_t server, 974 + uint64_t name_id, 975 + uint64_t *state, 976 + int *status, 977 + audit_token_t audit 978 + ) 979 + { 980 + uid_t uid = (uid_t)-1; 981 + gid_t gid = (gid_t)-1; 982 + 983 + *state = 0; 984 + 985 + *status = server_preflight(NULL, 0, audit, -1, &uid, &gid, NULL, NULL); 986 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 987 + 988 + log_message(ASL_LEVEL_DEBUG, "__notify_server_get_state_2 %llu\n", name_id); 989 + 990 + *status = _notify_lib_get_state(global.notify_state, name_id, state, uid, gid); 991 + return KERN_SUCCESS; 992 + } 993 + 994 + kern_return_t __notify_server_get_state_3 995 + ( 996 + mach_port_t server, 997 + int token, 998 + uint64_t *state, 999 + uint64_t *name_id, 1000 + int *status, 1001 + audit_token_t audit 1002 + ) 1003 + { 1004 + uid_t uid = (uid_t)-1; 1005 + gid_t gid = (gid_t)-1; 1006 + pid_t pid = (pid_t)-1; 1007 + client_t *c; 1008 + 1009 + *state = 0; 1010 + *name_id = 0; 1011 + 1012 + *status = server_preflight(NULL, 0, audit, -1, &uid, &gid, &pid, NULL); 1013 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1014 + 1015 + call_statistics.get_state++; 1016 + call_statistics.get_state_by_client_and_fetch_id++; 1017 + 1018 + c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 1019 + if ((c == NULL) || (c->name_info == NULL)) 1020 + { 1021 + *status = NOTIFY_STATUS_FAILED; 1022 + *name_id = UINT64_MAX; 1023 + } 1024 + else 1025 + { 1026 + *status = _notify_lib_get_state(global.notify_state, c->name_info->name_id, state, uid, gid); 1027 + *name_id = c->name_info->name_id; 1028 + } 1029 + 1030 + if (*name_id == UINT64_MAX) log_message(ASL_LEVEL_DEBUG, "__notify_server_get_state_3 %d %d\n", pid, token); 1031 + else log_message(ASL_LEVEL_DEBUG, "__notify_server_get_state_3 %d %d [%llu]\n", pid, token, *name_id); 1032 + 1033 + return KERN_SUCCESS; 1034 + } 1035 + 1036 + kern_return_t __notify_server_set_state_3 1037 + ( 1038 + mach_port_t server, 1039 + int token, 1040 + uint64_t state, 1041 + uint64_t *name_id, 1042 + int *status, 1043 + audit_token_t audit 1044 + ) 1045 + { 1046 + client_t *c; 1047 + uid_t uid = (uid_t)-1; 1048 + gid_t gid = (gid_t)-1; 1049 + pid_t pid = (pid_t)-1; 1050 + 1051 + *name_id = 0; 1052 + 1053 + *status = server_preflight(NULL, 0, audit, -1, &uid, &gid, &pid, NULL); 1054 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1055 + 1056 + call_statistics.set_state++; 1057 + call_statistics.set_state_by_client_and_fetch_id++; 1058 + 1059 + c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 1060 + if ((c == NULL) || (c->name_info == NULL)) 1061 + { 1062 + *status = NOTIFY_STATUS_FAILED; 1063 + *name_id = UINT64_MAX; 1064 + } 1065 + else 1066 + { 1067 + *status = _notify_lib_set_state(global.notify_state, c->name_info->name_id, state, uid, gid); 1068 + *name_id = c->name_info->name_id; 1069 + } 1070 + 1071 + if (*name_id == UINT64_MAX) log_message(ASL_LEVEL_DEBUG, "__notify_server_set_state_3 %d %d %llu\n", pid, token, state); 1072 + else log_message(ASL_LEVEL_DEBUG, "__notify_server_set_state_3 %d %d %llu [%llu]\n", pid, token, state, *name_id); 1073 + 1074 + return KERN_SUCCESS; 1075 + } 1076 + 1077 + kern_return_t __notify_server_set_state 1078 + ( 1079 + mach_port_t server, 1080 + int token, 1081 + uint64_t state, 1082 + int *status, 1083 + audit_token_t audit 1084 + ) 1085 + { 1086 + uint64_t ignored; 1087 + kern_return_t kstatus; 1088 + 1089 + *status = NOTIFY_STATUS_OK; 1090 + 1091 + kstatus = __notify_server_set_state_3(server, token, state, &ignored, status, audit); 1092 + 1093 + call_statistics.set_state_by_client_and_fetch_id--; 1094 + call_statistics.set_state_by_client++; 1095 + 1096 + return kstatus; 1097 + } 1098 + 1099 + kern_return_t __notify_server_set_state_2 1100 + ( 1101 + mach_port_t server, 1102 + uint64_t name_id, 1103 + uint64_t state, 1104 + audit_token_t audit 1105 + ) 1106 + { 1107 + uint32_t status; 1108 + uid_t uid = (uid_t)-1; 1109 + gid_t gid = (gid_t)-1; 1110 + 1111 + if (global.notify_state == NULL) return KERN_SUCCESS; 1112 + 1113 + call_statistics.set_state++; 1114 + call_statistics.set_state_by_id++; 1115 + 1116 + audit_token_to_au32(audit, NULL, &uid, &gid, NULL, NULL, NULL, NULL, NULL); 1117 + 1118 + log_message(ASL_LEVEL_DEBUG, "__notify_server_set_state_2 %llu %llu\n", name_id, state); 1119 + 1120 + status = _notify_lib_set_state(global.notify_state, name_id, state, uid, gid); 1121 + return KERN_SUCCESS; 1122 + } 1123 + 1124 + kern_return_t __notify_server_set_owner 1125 + ( 1126 + mach_port_t server, 1127 + caddr_t name, 1128 + mach_msg_type_number_t nameCnt, 1129 + int uid, 1130 + int gid, 1131 + int *status, 1132 + audit_token_t audit 1133 + ) 1134 + { 1135 + uid_t auid = (uid_t)-1; 1136 + 1137 + *status = server_preflight(name, nameCnt, audit, -1, &auid, NULL, NULL, NULL); 1138 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1139 + 1140 + call_statistics.set_owner++; 1141 + 1142 + log_message(ASL_LEVEL_DEBUG, "__notify_server_set_owner %s %d %d\n", name, uid, gid); 1143 + 1144 + /* only root may set owner for names */ 1145 + if (auid != 0) 1146 + { 1147 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1148 + *status = NOTIFY_STATUS_NOT_AUTHORIZED; 1149 + return KERN_SUCCESS; 1150 + } 1151 + 1152 + *status = _notify_lib_set_owner(global.notify_state, name, uid, gid); 1153 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1154 + return KERN_SUCCESS; 1155 + } 1156 + 1157 + kern_return_t __notify_server_get_owner 1158 + ( 1159 + mach_port_t server, 1160 + caddr_t name, 1161 + mach_msg_type_number_t nameCnt, 1162 + int *uid, 1163 + int *gid, 1164 + int *status, 1165 + audit_token_t audit 1166 + ) 1167 + { 1168 + *uid = 0; 1169 + *gid = 0; 1170 + 1171 + *status = server_preflight(name, nameCnt, audit, -1, NULL, NULL, NULL, NULL); 1172 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1173 + 1174 + call_statistics.get_owner++; 1175 + 1176 + log_message(ASL_LEVEL_DEBUG, "__notify_server_get_owner %s\n", name); 1177 + 1178 + *status = _notify_lib_get_owner(global.notify_state, name, (uint32_t *)uid, (uint32_t *)gid); 1179 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1180 + return KERN_SUCCESS; 1181 + } 1182 + 1183 + kern_return_t __notify_server_set_access 1184 + ( 1185 + mach_port_t server, 1186 + caddr_t name, 1187 + mach_msg_type_number_t nameCnt, 1188 + int mode, 1189 + int *status, 1190 + audit_token_t audit 1191 + ) 1192 + { 1193 + uint32_t u, g; 1194 + uid_t uid = (uid_t)-1; 1195 + gid_t gid = (gid_t)-1; 1196 + 1197 + *status = server_preflight(name, nameCnt, audit, -1, &uid, &gid, NULL, NULL); 1198 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1199 + 1200 + call_statistics.set_access++; 1201 + 1202 + log_message(ASL_LEVEL_DEBUG, "__notify_server_set_access %s 0x%03x\n", name, mode); 1203 + 1204 + _notify_lib_get_owner(global.notify_state, name, &u, &g); 1205 + 1206 + /* only root and owner may set access for names */ 1207 + if ((uid != 0) && (uid != u)) 1208 + { 1209 + *status = NOTIFY_STATUS_NOT_AUTHORIZED; 1210 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1211 + return KERN_SUCCESS; 1212 + } 1213 + 1214 + *status = _notify_lib_set_access(global.notify_state, name, mode); 1215 + if ((u != 0) || (g != 0)) *status = _notify_lib_set_owner(global.notify_state, name, u, g); 1216 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1217 + return KERN_SUCCESS; 1218 + } 1219 + 1220 + kern_return_t __notify_server_get_access 1221 + ( 1222 + mach_port_t server, 1223 + caddr_t name, 1224 + mach_msg_type_number_t nameCnt, 1225 + int *mode, 1226 + int *status, 1227 + audit_token_t audit 1228 + ) 1229 + { 1230 + *mode = 0; 1231 + 1232 + *status = server_preflight(name, nameCnt, audit, -1, NULL, NULL, NULL, NULL); 1233 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1234 + 1235 + call_statistics.get_access++; 1236 + 1237 + log_message(ASL_LEVEL_DEBUG, "__notify_server_get_access %s\n", name); 1238 + 1239 + *status = _notify_lib_get_access(global.notify_state, name, (uint32_t *)mode); 1240 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1241 + return KERN_SUCCESS; 1242 + } 1243 + 1244 + /* Unsupported because it makes no sense */ 1245 + kern_return_t __notify_server_release_name 1246 + ( 1247 + mach_port_t server, 1248 + caddr_t name, 1249 + mach_msg_type_number_t nameCnt, 1250 + int *status, 1251 + audit_token_t audit 1252 + ) 1253 + { 1254 + *status = NOTIFY_STATUS_FAILED; 1255 + return KERN_SUCCESS; 1256 + } 1257 + 1258 + kern_return_t __notify_server_monitor_file 1259 + ( 1260 + mach_port_t server, 1261 + int token, 1262 + caddr_t path, 1263 + mach_msg_type_number_t pathCnt, 1264 + int flags, 1265 + int *status, 1266 + audit_token_t audit 1267 + ) 1268 + { 1269 + client_t *c; 1270 + name_info_t *n; 1271 + uid_t uid = (uid_t)-1; 1272 + gid_t gid = (gid_t)-1; 1273 + pid_t pid = (pid_t)-1; 1274 + uint32_t ubits = (uint32_t)flags; 1275 + 1276 + *status = server_preflight(path, pathCnt, audit, -1, &uid, &gid, &pid, NULL); 1277 + if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1278 + 1279 + call_statistics.monitor_file++; 1280 + 1281 + log_message(ASL_LEVEL_DEBUG, "__notify_server_monitor_file %d %d %s 0x%08x\n", pid, token, path, ubits); 1282 + 1283 + c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 1284 + if (c == NULL) 1285 + { 1286 + vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1287 + *status = NOTIFY_STATUS_INVALID_REQUEST; 1288 + return KERN_SUCCESS; 1289 + } 1290 + 1291 + n = c->name_info; 1292 + if (n == NULL) 1293 + { 1294 + vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1295 + *status = NOTIFY_STATUS_INVALID_REQUEST; 1296 + return KERN_SUCCESS; 1297 + } 1298 + 1299 + *status = service_open_path_private(n->name, c, path, uid, gid, ubits); 1300 + vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1301 + 1302 + return KERN_SUCCESS; 1303 + } 1304 + 1305 + kern_return_t __notify_server_monitor_file_2 1306 + ( 1307 + mach_port_t server, 1308 + int token, 1309 + caddr_t path, 1310 + mach_msg_type_number_t pathCnt, 1311 + int flags, 1312 + audit_token_t audit 1313 + ) 1314 + { 1315 + int ignored; 1316 + return __notify_server_monitor_file(server, token, path, pathCnt, flags, &ignored, audit); 1317 + } 1318 + 1319 + /* 1320 + * Original routines provide compatibility for legacy clients. 1321 + * iOS simulator uses them. 1322 + */ 1323 + 1324 + /* 1325 + * Generates a integer "token" for legacy client registrations. 1326 + */ 1327 + static int 1328 + generate_token(audit_token_t audit) 1329 + { 1330 + static int legacy_id = 0; 1331 + 1332 + if (++legacy_id == -1) legacy_id = 1; 1333 + return legacy_id; 1334 + } 1335 + 1336 + kern_return_t __notify_server_register_plain 1337 + ( 1338 + mach_port_t server, 1339 + caddr_t name, 1340 + mach_msg_type_number_t nameCnt, 1341 + int *client_id, 1342 + int *status, 1343 + audit_token_t audit 1344 + ) 1345 + { 1346 + int token = generate_token(audit); 1347 + 1348 + *client_id = token; 1349 + *status = NOTIFY_STATUS_OK; 1350 + 1351 + return __notify_server_register_plain_2(server, name, nameCnt, token, audit); 1352 + } 1353 + 1354 + kern_return_t __notify_server_register_check 1355 + ( 1356 + mach_port_t server, 1357 + caddr_t name, 1358 + mach_msg_type_number_t nameCnt, 1359 + int *size, 1360 + int *slot, 1361 + int *client_id, 1362 + int *status, 1363 + audit_token_t audit 1364 + ) 1365 + { 1366 + *size = 0; 1367 + *slot = 0; 1368 + *status = NOTIFY_STATUS_OK; 1369 + 1370 + uint64_t nid; 1371 + int token = generate_token(audit); 1372 + 1373 + *client_id = token; 1374 + 1375 + return __notify_server_register_check_2(server, name, nameCnt, token, size, slot, &nid, status, audit); 1376 + } 1377 + 1378 + kern_return_t __notify_server_register_signal 1379 + ( 1380 + mach_port_t server, 1381 + caddr_t name, 1382 + mach_msg_type_number_t nameCnt, 1383 + int sig, 1384 + int *client_id, 1385 + int *status, 1386 + audit_token_t audit 1387 + ) 1388 + { 1389 + int token = generate_token(audit); 1390 + 1391 + *client_id = token; 1392 + *status = NOTIFY_STATUS_OK; 1393 + 1394 + return __notify_server_register_signal_2(server, name, nameCnt, token, sig, audit); 1395 + } 1396 + 1397 + kern_return_t __notify_server_register_file_descriptor 1398 + ( 1399 + mach_port_t server, 1400 + caddr_t name, 1401 + mach_msg_type_number_t nameCnt, 1402 + fileport_t fileport, 1403 + int ntoken, 1404 + int *client_id, 1405 + int *status, 1406 + audit_token_t audit 1407 + ) 1408 + { 1409 + kern_return_t kstatus; 1410 + client_t *c; 1411 + pid_t pid = (pid_t)-1; 1412 + int token = generate_token(audit); 1413 + 1414 + *client_id = token; 1415 + *status = NOTIFY_STATUS_OK; 1416 + 1417 + kstatus = __notify_server_register_file_descriptor_2(server, name, nameCnt, token, fileport, audit); 1418 + if (kstatus == KERN_SUCCESS) 1419 + { 1420 + audit_token_to_au32(audit, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); 1421 + c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 1422 + if (c == NULL) *status = NOTIFY_STATUS_FAILED; 1423 + else c->send_val = ntoken; 1424 + } 1425 + 1426 + return kstatus; 1427 + } 1428 + 1429 + kern_return_t __notify_server_register_mach_port 1430 + ( 1431 + mach_port_t server, 1432 + caddr_t name, 1433 + mach_msg_type_number_t nameCnt, 1434 + mach_port_t port, 1435 + int ntoken, 1436 + int *client_id, 1437 + int *status, 1438 + audit_token_t audit 1439 + ) 1440 + { 1441 + kern_return_t kstatus; 1442 + client_t *c; 1443 + pid_t pid = (pid_t)-1; 1444 + int token; 1445 + 1446 + *client_id = 0; 1447 + *status = NOTIFY_STATUS_OK; 1448 + 1449 + if (port == MACH_PORT_DEAD) 1450 + { 1451 + if ((name != NULL) && (nameCnt > 0)) vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1452 + *status = NOTIFY_STATUS_INVALID_REQUEST; 1453 + return KERN_SUCCESS; 1454 + } 1455 + 1456 + token = generate_token(audit); 1457 + 1458 + *client_id = token; 1459 + *status = NOTIFY_STATUS_OK; 1460 + 1461 + kstatus = __notify_server_register_mach_port_2(server, name, nameCnt, token, port, audit); 1462 + if (kstatus == KERN_SUCCESS) 1463 + { 1464 + audit_token_to_au32(audit, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); 1465 + c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 1466 + if (c == NULL) *status = NOTIFY_STATUS_FAILED; 1467 + else c->send_val = ntoken; 1468 + } 1469 + 1470 + return kstatus; 1471 + } 1472 + 1473 + kern_return_t __notify_server_simple_post 1474 + ( 1475 + mach_port_t server, 1476 + caddr_t name, 1477 + mach_msg_type_number_t nameCnt, 1478 + audit_token_t audit 1479 + ) 1480 + { 1481 + return __notify_server_post_4(server, name, nameCnt, audit); 1482 + } 1483 + 1484 + kern_return_t __notify_server_regenerate 1485 + ( 1486 + mach_port_t server, 1487 + caddr_t name, 1488 + mach_msg_type_number_t nameCnt, 1489 + int token, 1490 + uint32_t reg_type, 1491 + mach_port_t port, 1492 + int sig, 1493 + int prev_slot, 1494 + uint64_t prev_state, 1495 + uint64_t prev_time, 1496 + caddr_t path, 1497 + mach_msg_type_number_t pathCnt, 1498 + int path_flags, 1499 + int *new_slot, 1500 + uint64_t *new_nid, 1501 + int *status, 1502 + audit_token_t audit 1503 + ) 1504 + { 1505 + kern_return_t kstatus; 1506 + pid_t pid = (pid_t)-1; 1507 + int size; 1508 + name_info_t *n; 1509 + client_t *c; 1510 + uint64_t cid; 1511 + 1512 + *new_slot = 0; 1513 + *new_nid = 0; 1514 + *status = NOTIFY_STATUS_OK; 1515 + 1516 + if (name == NULL) 1517 + { 1518 + if (path != NULL) vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1519 + *status = NOTIFY_STATUS_INVALID_NAME; 1520 + return KERN_SUCCESS; 1521 + } 1522 + 1523 + if (name[nameCnt] != '\0') 1524 + { 1525 + if (path != NULL) vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1526 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1527 + *status = NOTIFY_STATUS_INVALID_NAME; 1528 + return KERN_SUCCESS; 1529 + } 1530 + 1531 + if ((path != NULL) && (path[pathCnt] != '\0')) 1532 + { 1533 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1534 + vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1535 + *status = NOTIFY_STATUS_INVALID_REQUEST; 1536 + return KERN_SUCCESS; 1537 + } 1538 + 1539 + call_statistics.regenerate++; 1540 + 1541 + audit_token_to_au32(audit, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); 1542 + 1543 + log_message(ASL_LEVEL_DEBUG, "__notify_server_regenerate %s %d %d %d %u %d %d %llu %s %d\n", name, pid, token, reg_type, port, sig, prev_slot, prev_state, path, path_flags); 1544 + 1545 + cid = make_client_id(pid, token); 1546 + c = (client_t *)_nc_table_find_64(global.notify_state->client_table, cid); 1547 + if (c != NULL) 1548 + { 1549 + /* duplicate client - this should never happen */ 1550 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1551 + if ((path != NULL) && (pathCnt > 0)) vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1552 + *status = NOTIFY_STATUS_FAILED; 1553 + return KERN_SUCCESS; 1554 + } 1555 + 1556 + switch (reg_type) 1557 + { 1558 + case NOTIFY_TYPE_MEMORY: 1559 + { 1560 + /* prev_slot must be between 0 and global.nslots */ 1561 + if ((prev_slot < 0) || (prev_slot >= global.nslots)) 1562 + { 1563 + *status = NOTIFY_STATUS_INVALID_REQUEST; 1564 + return KERN_SUCCESS; 1565 + } 1566 + 1567 + kstatus = __notify_server_register_check_2(server, name, nameCnt, token, &size, new_slot, new_nid, status, audit); 1568 + if (*status == NOTIFY_STATUS_OK) 1569 + { 1570 + if ((*new_slot != UINT32_MAX) && (global.last_shm_base != NULL)) 1571 + { 1572 + global.shared_memory_base[*new_slot] = global.shared_memory_base[*new_slot] + global.last_shm_base[prev_slot] - 1; 1573 + global.last_shm_base[prev_slot] = 0; 1574 + } 1575 + } 1576 + break; 1577 + } 1578 + case NOTIFY_TYPE_PLAIN: 1579 + { 1580 + kstatus = __notify_server_register_plain_2(server, name, nameCnt, token, audit); 1581 + break; 1582 + } 1583 + case NOTIFY_TYPE_PORT: 1584 + { 1585 + kstatus = __notify_server_register_mach_port_2(server, name, nameCnt, token, port, audit); 1586 + break; 1587 + } 1588 + case NOTIFY_TYPE_SIGNAL: 1589 + { 1590 + kstatus = __notify_server_register_signal_2(server, name, nameCnt, token, sig, audit); 1591 + break; 1592 + } 1593 + case NOTIFY_TYPE_FILE: /* fall through */ 1594 + default: 1595 + { 1596 + /* can not regenerate this type */ 1597 + vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1598 + if ((path != NULL) && (pathCnt > 0)) vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1599 + *status = NOTIFY_STATUS_FAILED; 1600 + return KERN_SUCCESS; 1601 + } 1602 + } 1603 + 1604 + if (path != NULL) 1605 + { 1606 + __notify_server_monitor_file_2(server, token, path, pathCnt, path_flags, audit); 1607 + } 1608 + 1609 + c = (client_t *)_nc_table_find_64(global.notify_state->client_table, cid); 1610 + if (c == NULL) 1611 + { 1612 + *status = NOTIFY_STATUS_FAILED; 1613 + } 1614 + else 1615 + { 1616 + *status = NOTIFY_STATUS_OK; 1617 + n = c->name_info; 1618 + *new_nid = n->name_id; 1619 + if (prev_time > n->state_time) n->state = prev_state; 1620 + } 1621 + 1622 + return KERN_SUCCESS; 1623 + }
+68
libnotify/notifyd/notifyd.8
··· 1 + .\" Copyright (c) 2003-2013 Apple Inc. All rights reserved. 2 + .\" 3 + .\" @APPLE_LICENSE_HEADER_START@ 4 + .\" 5 + .\" Portions Copyright (c) 2003-2010 Apple Inc. All Rights Reserved. 6 + .\" 7 + .\" This file contains Original Code and/or Modifications of Original Code 8 + .\" as defined in and that are subject to the Apple Public Source License 9 + .\" Version 2.0 (the 'License'). You may not use this file except in 10 + .\" compliance with the License. Please obtain a copy of the License at 11 + .\" http://www.opensource.apple.com/apsl/ and read it before using this 12 + .\" file. 13 + .\" 14 + .\" The Original Code and all software distributed under the License are 15 + .\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 + .\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 + .\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 + .\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 19 + .\" Please see the License for the specific language governing rights and 20 + .\" limitations under the License. 21 + .\" 22 + .\" @APPLE_LICENSE_HEADER_END@ 23 + .\" 24 + .\" 25 + .Dd March 24, 2003 26 + .Dt notifyd 8 27 + .Os "Mac OS X" 28 + .Sh NAME 29 + .Nm notifyd 30 + .Nd notification server 31 + .Sh SYNOPSIS 32 + .Nm 33 + .Op Fl d 34 + .Op Fl log_file Ar path 35 + .Op Fl shm_pages Ar npages 36 + .Sh DESCRIPTION 37 + .Nm 38 + is the server for the Mac OS X notification system described in 39 + .Xr notify 3 . 40 + The server is started automatically by 41 + .Nm launchd 42 + during system startup. 43 + .Pp 44 + The 45 + .Fl d 46 + option causes 47 + .Nm notifyd 48 + to log debugging messages to a log file. 49 + Messages are not logged to ASL to avoid potential deadlocks, 50 + since the ASL system makes use of the 51 + .Xr notify 3 52 + system. 53 + .Pp 54 + The default log file is 55 + .Pa /var/log/notifyd.log . 56 + An alternate log file path may be specified following the 57 + .Fl log_file 58 + flag. 59 + .Pp 60 + The 61 + .Fl shm_pages Ar npages 62 + option sets the number of shared memory pages used for passive notification. 63 + The default is one page. 64 + If a value of zero is specified, 65 + shared memory is disabled and passive notifications are performed 66 + using IPC between the client and the server. 67 + .Sh SEE ALSO 68 + .Xr notify 3 .
+1265
libnotify/notifyd/notifyd.c
··· 1 + /* 2 + * Copyright (c) 2003-2012 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #include <sys/types.h> 25 + #include <sys/stat.h> 26 + #include <signal.h> 27 + #include <stdio.h> 28 + #include <stdlib.h> 29 + #include <errno.h> 30 + #include <sys/un.h> 31 + #include <sys/ipc.h> 32 + #include <sys/mman.h> 33 + #include <sys/fcntl.h> 34 + #include <sys/syslimits.h> 35 + #include <sys/param.h> 36 + #include <sys/resource.h> 37 + #include <asl.h> 38 + #include <assert.h> 39 + #include <inttypes.h> 40 + #include <CrashReporterClient.h> 41 + #include <TargetConditionals.h> 42 + #include "pathwatch.h" 43 + #include "notifyd.h" 44 + #include "service.h" 45 + #include "pathwatch.h" 46 + #include "timer.h" 47 + 48 + #include "notify_ipc.h" 49 + #include "notify_private.h" 50 + 51 + #define forever for(;;) 52 + #define IndexNull -1 53 + 54 + /* Compile flags */ 55 + #define RUN_TIME_CHECKS 56 + 57 + #if TARGET_IPHONE_SIMULATOR 58 + static const char *_config_file_path; 59 + #define CONFIG_FILE_PATH _config_file_path 60 + 61 + static const char *_debug_log_path; 62 + #define DEBUG_LOG_PATH _debug_log_path 63 + #else 64 + #define CONFIG_FILE_PATH "/etc/notify.conf" 65 + #define DEBUG_LOG_PATH "/var/log/notifyd.log" 66 + #endif 67 + 68 + #define STATUS_REQUEST_SHORT 0 69 + #define STATUS_REQUEST_LONG 1 70 + 71 + #define N_NOTIFY_TYPES 6 72 + 73 + static int notifyd_token; 74 + 75 + static char *status_file = NULL; 76 + 77 + typedef union 78 + { 79 + mach_msg_header_t head; 80 + union __RequestUnion__notify_ipc_subsystem request; 81 + } notify_request_msg; 82 + 83 + typedef union 84 + { 85 + mach_msg_header_t head; 86 + union __ReplyUnion__notify_ipc_subsystem reply; 87 + } notify_reply_msg; 88 + 89 + extern boolean_t notify_ipc_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP); 90 + 91 + static const char * 92 + notify_type_name(uint32_t t) 93 + { 94 + switch (t) 95 + { 96 + case NOTIFY_TYPE_NONE: return "none "; 97 + case NOTIFY_TYPE_MEMORY: return "memory"; 98 + case NOTIFY_TYPE_PLAIN: return "plain "; 99 + case NOTIFY_TYPE_PORT: return "port "; 100 + case NOTIFY_TYPE_FILE: return "file "; 101 + case NOTIFY_TYPE_SIGNAL: return "signal"; 102 + default: return "unknown"; 103 + } 104 + 105 + return "unknown"; 106 + } 107 + 108 + static void 109 + fprint_client(FILE *f, client_t *c) 110 + { 111 + int token; 112 + 113 + if (c == NULL) 114 + { 115 + fprintf(f, "NULL client\n"); 116 + return; 117 + } 118 + 119 + token = c->client_id; 120 + 121 + fprintf(f, "client_id: %llu\n", c->client_id); 122 + fprintf(f, "pid: %d\n", c->pid); 123 + fprintf(f, "token: %d\n", token); 124 + fprintf(f, "lastval: %u\n", c->lastval); 125 + fprintf(f, "suspend_count: %u\n", c->suspend_count); 126 + fprintf(f, "type: %s\n", notify_type_name(c->notify_type)); 127 + switch(c->notify_type) 128 + { 129 + case NOTIFY_TYPE_NONE: 130 + break; 131 + 132 + case NOTIFY_TYPE_PLAIN: 133 + break; 134 + 135 + case NOTIFY_TYPE_MEMORY: 136 + break; 137 + 138 + case NOTIFY_TYPE_PORT: 139 + fprintf(f, "mach port: 0x%08x\n", c->port); 140 + break; 141 + 142 + case NOTIFY_TYPE_FILE: 143 + fprintf(f, "fd: %d\n", c->fd); 144 + break; 145 + 146 + case NOTIFY_TYPE_SIGNAL: 147 + fprintf(f, "signal: %d\n", c->sig); 148 + break; 149 + 150 + default: break; 151 + } 152 + } 153 + 154 + static void 155 + fprint_quick_client(FILE *f, client_t *c, int pname) 156 + { 157 + int token; 158 + if (c == NULL) return; 159 + 160 + token = c->client_id; 161 + 162 + if (pname == 1) fprintf(f, " [%s]", c->name_info->name); 163 + fprintf(f, " %u %u", c->pid, token); 164 + if (c->suspend_count > 0) fprintf(f, " suspend %d", c->suspend_count); 165 + if (c->state & NOTIFY_CLIENT_STATE_PENDING) fprintf(f, " pending"); 166 + if (c->state & NOTIFY_CLIENT_STATE_TIMEOUT) fprintf(f, " timeout"); 167 + fprintf(f, " %s", notify_type_name(c->notify_type)); 168 + if (c->notify_type == NOTIFY_TYPE_SIGNAL) fprintf(f, " %d", c->sig); 169 + fprintf(f, "\n"); 170 + } 171 + 172 + static void 173 + fprint_quick_name_info(FILE *f, name_info_t *n) 174 + { 175 + list_t *sl; 176 + client_t *c; 177 + 178 + if (n == NULL) return; 179 + 180 + fprintf(f, "\"%s\" uid=%u gid=%u %03x", n->name, n->uid, n->gid, n->access); 181 + if (n->slot != -1) 182 + { 183 + fprintf(f, " slot %u", n->slot); 184 + if (global.shared_memory_refcount[n->slot] != -1) fprintf(f, " = %u", global.shared_memory_base[n->slot]); 185 + } 186 + 187 + fprintf(f, "\n"); 188 + 189 + for (sl = n->subscriptions; sl != NULL; sl = _nc_list_next(sl)) 190 + { 191 + c = _nc_list_data(sl); 192 + if (c == NULL) break; 193 + 194 + fprint_quick_client(f, c, 0); 195 + } 196 + 197 + fprintf(f, "\n"); 198 + } 199 + 200 + static void 201 + fprint_name_info(FILE *f, const char *name, name_info_t *n, table_t *pid_table, pid_t *max_pid) 202 + { 203 + list_t *sl; 204 + client_t *c; 205 + uint32_t i, reg[N_NOTIFY_TYPES]; 206 + 207 + if (n == NULL) 208 + { 209 + fprintf(f, "%s unknown\n", name); 210 + return; 211 + } 212 + 213 + fprintf(f, "name: %s\n", n->name); 214 + fprintf(f, "id: %llu\n", n->name_id); 215 + fprintf(f, "uid: %u\n", n->uid); 216 + fprintf(f, "gid: %u\n", n->gid); 217 + fprintf(f, "access: %03x\n", n->access); 218 + fprintf(f, "refcount: %u\n", n->refcount); 219 + if (n->slot == -1) fprintf(f, "slot: -unassigned-"); 220 + else 221 + { 222 + fprintf(f, "slot: %u", n->slot); 223 + if (global.shared_memory_refcount[n->slot] != -1) 224 + fprintf(f, " = %u (%u)", global.shared_memory_base[n->slot], global.shared_memory_refcount[n->slot]); 225 + } 226 + fprintf(f, "\n"); 227 + fprintf(f, "val: %u\n", n->val); 228 + fprintf(f, "state: %llu\n", n->state); 229 + 230 + for (i = 0; i < N_NOTIFY_TYPES; i++) reg[i] = 0; 231 + 232 + for (sl = n->subscriptions; sl != NULL; sl = _nc_list_next(sl)) 233 + { 234 + list_t *l; 235 + 236 + c = _nc_list_data(sl); 237 + if (c == NULL) break; 238 + 239 + if ((c->pid != (pid_t)-1) && (c->pid > *max_pid)) *max_pid = c->pid; 240 + 241 + l = _nc_table_find_n(pid_table, c->pid); 242 + if (l == NULL) 243 + { 244 + _nc_table_insert_n(pid_table, (uint32_t)c->pid, _nc_list_new(c)); 245 + } 246 + else 247 + { 248 + _nc_list_concat(l, _nc_list_new(c)); 249 + } 250 + 251 + switch (c->notify_type) 252 + { 253 + case NOTIFY_TYPE_MEMORY: reg[1]++; break; 254 + case NOTIFY_TYPE_PLAIN: reg[2]++; break; 255 + case NOTIFY_TYPE_PORT: reg[3]++; break; 256 + case NOTIFY_TYPE_FILE: reg[4]++; break; 257 + case NOTIFY_TYPE_SIGNAL: reg[5]++; break; 258 + default: reg[0]++; 259 + } 260 + } 261 + 262 + fprintf(f, "types: none %u memory %u plain %u port %u file %u signal %u\n", reg[0], reg[1], reg[2], reg[3], reg[4], reg[5]); 263 + 264 + for (sl = n->subscriptions; sl != NULL; sl = _nc_list_next(sl)) 265 + { 266 + c = _nc_list_data(sl); 267 + if (c == NULL) break; 268 + 269 + fprintf(f, "\n"); 270 + fprint_client(f, c); 271 + } 272 + } 273 + 274 + static void 275 + fprint_quick_status(FILE *f) 276 + { 277 + void *tt; 278 + name_info_t *n; 279 + 280 + tt = _nc_table_traverse_start(global.notify_state->name_table); 281 + 282 + while (tt != NULL) 283 + { 284 + n = _nc_table_traverse(global.notify_state->name_table, tt); 285 + if (n == NULL) break; 286 + fprint_quick_name_info(f, n); 287 + } 288 + 289 + _nc_table_traverse_end(global.notify_state->name_table, tt); 290 + fprintf(f, "\n"); 291 + } 292 + 293 + static void 294 + fprint_status(FILE *f) 295 + { 296 + void *tt; 297 + name_info_t *n; 298 + int32_t i; 299 + client_t *c; 300 + svc_info_t *info; 301 + path_node_t *node; 302 + timer_t *timer; 303 + table_t *pid_table; 304 + pid_t pid, max_pid; 305 + uint32_t count; 306 + portproc_data_t *pdata; 307 + 308 + pid_table = _nc_table_new(0); 309 + max_pid = 0; 310 + 311 + fprintf(f, "--- GLOBALS ---\n"); 312 + fprintf(f, "%u slots (current id %u)\n", global.nslots, global.slot_id); 313 + fprintf(f, "%u log_cutoff (default %u)\n", global.log_cutoff, global.log_default); 314 + fprintf(f, "\n"); 315 + 316 + fprintf(f, "--- STATISTICS ---\n"); 317 + fprintf(f, "post %llu\n", call_statistics.post); 318 + fprintf(f, " id %llu\n", call_statistics.post_by_id); 319 + fprintf(f, " name %llu\n", call_statistics.post_by_name); 320 + fprintf(f, " fetch %llu\n", call_statistics.post_by_name_and_fetch_id); 321 + fprintf(f, " no_op %llu\n", call_statistics.post_no_op); 322 + fprintf(f, "\n"); 323 + fprintf(f, "register %llu\n", call_statistics.reg); 324 + fprintf(f, " plain %llu\n", call_statistics.reg_plain); 325 + fprintf(f, " check %llu\n", call_statistics.reg_check); 326 + fprintf(f, " signal %llu\n", call_statistics.reg_signal); 327 + fprintf(f, " file %llu\n", call_statistics.reg_file); 328 + fprintf(f, " port %llu\n", call_statistics.reg_port); 329 + fprintf(f, "\n"); 330 + fprintf(f, "check %llu\n", call_statistics.check); 331 + fprintf(f, "cancel %llu\n", call_statistics.cancel); 332 + fprintf(f, "cleanup %llu\n", call_statistics.cleanup); 333 + fprintf(f, "regenerate %llu\n", call_statistics.regenerate); 334 + fprintf(f, "\n"); 335 + fprintf(f, "suspend %llu\n", call_statistics.suspend); 336 + fprintf(f, "resume %llu\n", call_statistics.resume); 337 + fprintf(f, "suspend_pid %llu\n", call_statistics.suspend_pid); 338 + fprintf(f, "resume_pid %llu\n", call_statistics.resume_pid); 339 + fprintf(f, "\n"); 340 + fprintf(f, "get_state %llu\n", call_statistics.get_state); 341 + fprintf(f, " id %llu\n", call_statistics.get_state_by_id); 342 + fprintf(f, " client %llu\n", call_statistics.get_state_by_client); 343 + fprintf(f, " fetch %llu\n", call_statistics.get_state_by_client_and_fetch_id); 344 + fprintf(f, "\n"); 345 + fprintf(f, "set_state %llu\n", call_statistics.set_state); 346 + fprintf(f, " id %llu\n", call_statistics.set_state_by_id); 347 + fprintf(f, " client %llu\n", call_statistics.set_state_by_client); 348 + fprintf(f, " fetch %llu\n", call_statistics.set_state_by_client_and_fetch_id); 349 + fprintf(f, "\n"); 350 + fprintf(f, "get_owner %llu\n", call_statistics.get_owner); 351 + fprintf(f, "set_owner %llu\n", call_statistics.set_owner); 352 + fprintf(f, "\n"); 353 + fprintf(f, "get_access %llu\n", call_statistics.get_access); 354 + fprintf(f, "set_access %llu\n", call_statistics.set_access); 355 + fprintf(f, "\n"); 356 + fprintf(f, "monitor %llu\n", call_statistics.monitor_file); 357 + fprintf(f, "svc_path %llu\n", call_statistics.service_path); 358 + fprintf(f, "svc_timer %llu\n", call_statistics.service_timer); 359 + 360 + fprintf(f, "\n"); 361 + fprintf(f, "name alloc %9u free %9u extant %9u\n", global.notify_state->stat_name_alloc , global.notify_state->stat_name_free, global.notify_state->stat_name_alloc - global.notify_state->stat_name_free); 362 + fprintf(f, "subscription alloc %9u free %9u extant %9u\n", global.notify_state->stat_client_alloc , global.notify_state->stat_client_free, global.notify_state->stat_client_alloc - global.notify_state->stat_client_free); 363 + fprintf(f, "portproc alloc %9u free %9u extant %9u\n", global.notify_state->stat_portproc_alloc , global.notify_state->stat_portproc_free, global.notify_state->stat_portproc_alloc - global.notify_state->stat_portproc_free); 364 + fprintf(f, "\n"); 365 + 366 + count = 0; 367 + tt = _nc_table_traverse_start(global.notify_state->port_table); 368 + while (tt != NULL) 369 + { 370 + pdata = _nc_table_traverse(global.notify_state->port_table, tt); 371 + if (pdata == NULL) break; 372 + count++; 373 + } 374 + _nc_table_traverse_end(global.notify_state->port_table, tt); 375 + fprintf(f, "port count %u\n", count); 376 + 377 + count = 0; 378 + tt = _nc_table_traverse_start(global.notify_state->proc_table); 379 + while (tt != NULL) 380 + { 381 + pdata = _nc_table_traverse(global.notify_state->proc_table, tt); 382 + if (pdata == NULL) break; 383 + count++; 384 + } 385 + _nc_table_traverse_end(global.notify_state->proc_table, tt); 386 + fprintf(f, "proc count %u\n", count); 387 + fprintf(f, "\n"); 388 + 389 + fprintf(f, "--- NAME TABLE ---\n"); 390 + count = 0; 391 + tt = _nc_table_traverse_start(global.notify_state->name_table); 392 + 393 + while (tt != NULL) 394 + { 395 + n = _nc_table_traverse(global.notify_state->name_table, tt); 396 + if (n == NULL) break; 397 + fprint_name_info(f, n->name, n, pid_table, &max_pid); 398 + fprintf(f, "\n"); 399 + count++; 400 + } 401 + 402 + fprintf(f, "--- NAME COUNT %u ---\n", count); 403 + _nc_table_traverse_end(global.notify_state->name_table, tt); 404 + fprintf(f, "\n"); 405 + 406 + fprintf(f, "--- SUBSCRIPTION TABLE ---\n"); 407 + count = 0; 408 + tt = _nc_table_traverse_start(global.notify_state->client_table); 409 + 410 + while (tt != NULL) 411 + { 412 + c = _nc_table_traverse(global.notify_state->client_table, tt); 413 + if (c == NULL) break; 414 + fprint_quick_client(f, c, 1); 415 + count++; 416 + } 417 + 418 + fprintf(f, "--- SUBSCRIPTION COUNT %u ---\n", count); 419 + _nc_table_traverse_end(global.notify_state->client_table, tt); 420 + fprintf(f, "\n"); 421 + 422 + fprintf(f, "--- CONTROLLED NAME ---\n"); 423 + for (i = 0; i < global.notify_state->controlled_name_count; i++) 424 + { 425 + fprintf(f, "%s %u %u %03x\n", global.notify_state->controlled_name[i]->name, global.notify_state->controlled_name[i]->uid, global.notify_state->controlled_name[i]->gid, global.notify_state->controlled_name[i]->access); 426 + } 427 + fprintf(f, "--- CONTROLLED NAME COUNT %u ---\n", global.notify_state->controlled_name_count); 428 + fprintf(f, "\n"); 429 + 430 + fprintf(f, "--- PUBLIC SERVICE ---\n"); 431 + count = 0; 432 + tt = _nc_table_traverse_start(global.notify_state->name_table); 433 + while (tt != NULL) 434 + { 435 + n = _nc_table_traverse(global.notify_state->name_table, tt); 436 + if (n == NULL) break; 437 + if (n->private == NULL) continue; 438 + 439 + count++; 440 + info = (svc_info_t *)n->private; 441 + 442 + if (info->type == 0) 443 + { 444 + fprintf(f, "Null service: %s\n", n->name); 445 + } 446 + if (info->type == SERVICE_TYPE_PATH_PUBLIC) 447 + { 448 + node = (path_node_t *)info->private; 449 + fprintf(f, "Path Service: %s <- %s\n", n->name, node->path); 450 + } 451 + else if (info->type == SERVICE_TYPE_TIMER_PUBLIC) 452 + { 453 + timer = (timer_t *)info->private; 454 + switch (timer->type) 455 + { 456 + case TIME_EVENT_ONESHOT: 457 + { 458 + fprintf(f, "Time Service: %s <- Oneshot %llu\n", n->name, timer->start); 459 + break; 460 + } 461 + case TIME_EVENT_CLOCK: 462 + { 463 + fprintf(f, "Time Service: %s <- Clock start %lld freq %u end %lld\n", n->name, timer->start, timer->freq, timer->end); 464 + break; 465 + } 466 + case TIME_EVENT_CAL: 467 + { 468 + fprintf(f, "Time Service: %s <- Calendar start %lld freq %u end %lld day %d\n", n->name, timer->start, timer->freq, timer->end, timer->day); 469 + break; 470 + } 471 + } 472 + } 473 + else 474 + { 475 + fprintf(f, "Unknown service: %s (%u)\n", n->name, info->type); 476 + } 477 + } 478 + 479 + fprintf(f, "--- PUBLIC SERVICE COUNT %u ---\n", count); 480 + _nc_table_traverse_end(global.notify_state->name_table, tt); 481 + fprintf(f, "\n"); 482 + 483 + fprintf(f, "--- PRIVATE SERVICE ---\n"); 484 + count = 0; 485 + tt = _nc_table_traverse_start(global.notify_state->client_table); 486 + while (tt != NULL) 487 + { 488 + c = _nc_table_traverse(global.notify_state->client_table, tt); 489 + if (c == NULL) break; 490 + if (c->private == NULL) continue; 491 + 492 + count++; 493 + info = (svc_info_t *)c->private; 494 + n = c->name_info; 495 + 496 + if (info->type == 0) 497 + { 498 + fprintf(f, "PID %u Null service: %s\n", c->pid, n->name); 499 + } 500 + if (info->type == SERVICE_TYPE_PATH_PRIVATE) 501 + { 502 + node = (path_node_t *)info->private; 503 + fprintf(f, "PID %u Path Service: %s <- %s (UID %d GID %d)\n", c->pid, n->name, node->path, node->uid, node->gid); 504 + } 505 + else if (info->type == SERVICE_TYPE_TIMER_PRIVATE) 506 + { 507 + timer = (timer_t *)info->private; 508 + switch (timer->type) 509 + { 510 + case TIME_EVENT_ONESHOT: 511 + { 512 + fprintf(f, "PID %u Time Service: %s <- Oneshot %"PRId64"\n", c->pid, n->name, timer->start); 513 + break; 514 + } 515 + case TIME_EVENT_CLOCK: 516 + { 517 + fprintf(f, "PID %u Time Service: %s <- Clock start %"PRId64" freq %"PRIu32" end %"PRId64"\n", c->pid, n->name, timer->start, timer->freq, timer->end); 518 + break; 519 + } 520 + case TIME_EVENT_CAL: 521 + { 522 + fprintf(f, "PID %u Time Service: %s <- Calendar start %"PRId64" freq %"PRIu32" end %"PRId64" day %"PRId32"\n", c->pid, n->name, timer->start, timer->freq, timer->end, timer->day); 523 + break; 524 + } 525 + } 526 + } 527 + } 528 + 529 + fprintf(f, "--- PRIVATE SERVICE COUNT %u ---\n", count); 530 + _nc_table_traverse_end(global.notify_state->client_table, tt); 531 + fprintf(f, "\n"); 532 + 533 + fprintf(f, "--- PROCESSES ---\n"); 534 + for (pid = 0; pid <= max_pid; pid++) 535 + { 536 + int mem_count, plain_count, file_count, port_count, sig_count, com_port_count; 537 + mach_port_t common_port = MACH_PORT_NULL; 538 + 539 + list_t *x; 540 + list_t *l = _nc_table_find_n(pid_table, pid); 541 + if (l == NULL) continue; 542 + 543 + mem_count = 0; 544 + plain_count = 0; 545 + file_count = 0; 546 + port_count = 0; 547 + sig_count = 0; 548 + com_port_count = 0; 549 + 550 + for (x = l; x != NULL; x = _nc_list_next(x)) 551 + { 552 + c = _nc_list_data(x); 553 + if (c != NULL) 554 + { 555 + if ((c->notify_type == NOTIFY_TYPE_PORT) && (!strcmp(c->name_info->name, COMMON_PORT_KEY))) common_port = c->port; 556 + } 557 + } 558 + 559 + for (x = l; x != NULL; x = _nc_list_next(x)) 560 + { 561 + c = _nc_list_data(x); 562 + if (c != NULL) 563 + { 564 + switch(c->notify_type) 565 + { 566 + case NOTIFY_TYPE_NONE: 567 + break; 568 + 569 + case NOTIFY_TYPE_PLAIN: 570 + plain_count++; 571 + break; 572 + 573 + case NOTIFY_TYPE_MEMORY: 574 + mem_count++; 575 + break; 576 + 577 + case NOTIFY_TYPE_PORT: 578 + port_count++; 579 + if (c->port == common_port) com_port_count++; 580 + break; 581 + 582 + case NOTIFY_TYPE_FILE: 583 + file_count++; 584 + break; 585 + 586 + case NOTIFY_TYPE_SIGNAL: 587 + sig_count++; 588 + break; 589 + 590 + default: break; 591 + } 592 + } 593 + } 594 + 595 + fprintf(f, "pid: %u ", pid); 596 + if (file_count + sig_count == 0) 597 + { 598 + if (port_count == 0) fprintf(f, "regenerable / polling\n"); 599 + else if (port_count == com_port_count) fprintf(f, "regenerable\n"); 600 + else if (com_port_count > 0) fprintf(f, "partially regenerable\n"); 601 + else fprintf(f, "non-regenerable\n"); 602 + } 603 + else 604 + { 605 + if (com_port_count == 0) fprintf(f, "non-regenerable\n"); 606 + else fprintf(f, "partially regenerable\n"); 607 + } 608 + 609 + fprintf(f, "memory %u plain %u port %u file %u signal %u common port %u\n", mem_count, plain_count, port_count, file_count, sig_count, com_port_count); 610 + for (x = l; x != NULL; x = _nc_list_next(x)) 611 + { 612 + c = _nc_list_data(x); 613 + if (c != NULL) 614 + { 615 + fprintf(f, " %s: %s\n", notify_type_name(c->notify_type), c->name_info->name); 616 + } 617 + } 618 + 619 + fprintf(f, "\n"); 620 + _nc_list_release_list(l); 621 + } 622 + fprintf(f, "\n"); 623 + _nc_table_free(pid_table); 624 + } 625 + 626 + void 627 + dump_status(uint32_t level) 628 + { 629 + FILE *f; 630 + 631 + if (status_file == NULL) 632 + { 633 + asprintf(&status_file, "/var/run/notifyd_%u.status", getpid()); 634 + if (status_file == NULL) return; 635 + } 636 + 637 + unlink(status_file); 638 + f = fopen(status_file, "w"); 639 + if (f == NULL) return; 640 + 641 + if (level == STATUS_REQUEST_SHORT) fprint_quick_status(f); 642 + else if (level == STATUS_REQUEST_LONG) fprint_status(f); 643 + 644 + fclose(f); 645 + } 646 + 647 + void 648 + log_message(int priority, const char *str, ...) 649 + { 650 + time_t t; 651 + char now[32]; 652 + va_list ap; 653 + FILE *lfp; 654 + 655 + if (priority > global.log_cutoff) return; 656 + if (global.log_path == NULL) return; 657 + 658 + lfp = fopen(global.log_path, "a"); 659 + if (lfp == NULL) return; 660 + 661 + va_start(ap, str); 662 + 663 + t = time(NULL); 664 + memset(now, 0, 32); 665 + strftime(now, 32, "%b %e %T", localtime(&t)); 666 + 667 + fprintf(lfp, "%s: ", now); 668 + vfprintf(lfp, str, ap); 669 + fflush(lfp); 670 + 671 + va_end(ap); 672 + fclose(lfp); 673 + } 674 + 675 + uint32_t 676 + daemon_post(const char *name, uint32_t u, uint32_t g) 677 + { 678 + name_info_t *n; 679 + uint32_t status; 680 + 681 + if (name == NULL) return 0; 682 + 683 + n = (name_info_t *)_nc_table_find(global.notify_state->name_table, name); 684 + if (n == NULL) return 0; 685 + 686 + if (n->slot != (uint32_t)-1) global.shared_memory_base[n->slot]++; 687 + 688 + status = _notify_lib_post(global.notify_state, name, u, g); 689 + return status; 690 + } 691 + 692 + uint32_t 693 + daemon_post_nid(uint64_t nid, uint32_t u, uint32_t g) 694 + { 695 + name_info_t *n; 696 + uint32_t status; 697 + 698 + n = (name_info_t *)_nc_table_find_64(global.notify_state->name_id_table, nid); 699 + if (n == NULL) return 0; 700 + 701 + if (n->slot != (uint32_t)-1) global.shared_memory_base[n->slot]++; 702 + 703 + status = _notify_lib_post_nid(global.notify_state, nid, u, g); 704 + return status; 705 + } 706 + 707 + void 708 + daemon_post_client(uint64_t cid) 709 + { 710 + client_t *c; 711 + 712 + c = _nc_table_find_64(global.notify_state->client_table, cid); 713 + if (c == NULL) return; 714 + 715 + if ((c->notify_type == NOTIFY_TYPE_MEMORY) && (c->name_info != NULL) && (c->name_info->slot != (uint32_t)-1)) 716 + { 717 + global.shared_memory_base[c->name_info->slot]++; 718 + } 719 + 720 + _notify_lib_post_client(global.notify_state, c); 721 + } 722 + 723 + void 724 + daemon_set_state(const char *name, uint64_t val) 725 + { 726 + name_info_t *n; 727 + 728 + if (name == NULL) return; 729 + 730 + n = (name_info_t *)_nc_table_find(global.notify_state->name_table, name); 731 + if (n == NULL) return; 732 + 733 + n->state = val; 734 + } 735 + 736 + static void 737 + init_launch_config(const char *name) 738 + { 739 + launch_data_t tmp, pdict; 740 + 741 + tmp = launch_data_new_string(LAUNCH_KEY_CHECKIN); 742 + global.launch_dict = launch_msg(tmp); 743 + launch_data_free(tmp); 744 + 745 + if (global.launch_dict == NULL) 746 + { 747 + fprintf(stderr, "%d launchd checkin failed\n", getpid()); 748 + exit(1); 749 + } 750 + 751 + tmp = launch_data_dict_lookup(global.launch_dict, LAUNCH_JOBKEY_MACHSERVICES); 752 + if (tmp == NULL) 753 + { 754 + fprintf(stderr, "%d launchd lookup of LAUNCH_JOBKEY_MACHSERVICES failed\n", getpid()); 755 + exit(1); 756 + } 757 + 758 + pdict = launch_data_dict_lookup(tmp, name); 759 + if (pdict == NULL) 760 + { 761 + fprintf(stderr, "%d launchd lookup of name %s failed\n", getpid(), name); 762 + exit(1); 763 + } 764 + 765 + global.server_port = launch_data_get_machport(pdict); 766 + if (global.server_port == MACH_PORT_NULL) 767 + { 768 + fprintf(stderr, "%d launchd lookup of server port for name %s failed\n", getpid(), name); 769 + exit(1); 770 + } 771 + } 772 + 773 + static void 774 + string_list_free(char **l) 775 + { 776 + int i; 777 + 778 + if (l == NULL) return; 779 + for (i = 0; l[i] != NULL; i++) 780 + { 781 + if (l[i] != NULL) free(l[i]); 782 + l[i] = NULL; 783 + } 784 + free(l); 785 + } 786 + 787 + static char ** 788 + string_insert(char *s, char **l, unsigned int x) 789 + { 790 + int i, len; 791 + 792 + if (s == NULL) return l; 793 + if (l == NULL) 794 + { 795 + l = (char **)malloc(2 * sizeof(char *)); 796 + l[0] = strdup(s); 797 + l[1] = NULL; 798 + return l; 799 + } 800 + 801 + for (i = 0; l[i] != NULL; i++); 802 + len = i + 1; /* count the NULL on the end of the list too! */ 803 + 804 + l = (char **)realloc(l, (len + 1) * sizeof(char *)); 805 + 806 + if ((x >= (len - 1)) || (x == IndexNull)) 807 + { 808 + l[len - 1] = strdup(s); 809 + l[len] = NULL; 810 + return l; 811 + } 812 + 813 + for (i = len; i > x; i--) l[i] = l[i - 1]; 814 + l[x] = strdup(s); 815 + return l; 816 + } 817 + 818 + static char ** 819 + string_append(char *s, char **l) 820 + { 821 + return string_insert(s, l, IndexNull); 822 + } 823 + 824 + static unsigned int 825 + string_list_length(char **l) 826 + { 827 + int i; 828 + 829 + if (l == NULL) return 0; 830 + for (i = 0; l[i] != NULL; i++); 831 + return i; 832 + } 833 + 834 + static unsigned int 835 + string_index(char c, char *s) 836 + { 837 + int i; 838 + char *p; 839 + 840 + if (s == NULL) return IndexNull; 841 + 842 + for (i = 0, p = s; p[0] != '\0'; p++, i++) 843 + { 844 + if (p[0] == c) return i; 845 + } 846 + 847 + return IndexNull; 848 + } 849 + 850 + static char ** 851 + explode(char *s, char *delim) 852 + { 853 + char **l = NULL; 854 + char *p, *t; 855 + int i, n; 856 + 857 + if (s == NULL) return NULL; 858 + 859 + p = s; 860 + while (p[0] != '\0') 861 + { 862 + for (i = 0; ((p[i] != '\0') && (string_index(p[i], delim) == IndexNull)); i++); 863 + n = i; 864 + t = malloc(n + 1); 865 + for (i = 0; i < n; i++) t[i] = p[i]; 866 + t[n] = '\0'; 867 + l = string_append(t, l); 868 + free(t); 869 + t = NULL; 870 + if (p[i] == '\0') return l; 871 + if (p[i + 1] == '\0') l = string_append("", l); 872 + p = p + i + 1; 873 + } 874 + return l; 875 + } 876 + 877 + static uint32_t 878 + atoaccess(char *s) 879 + { 880 + uint32_t a; 881 + 882 + if (s == NULL) return 0; 883 + if (strlen(s) != 6) return 0; 884 + 885 + a = 0; 886 + if (s[0] == 'r') a |= (NOTIFY_ACCESS_READ << NOTIFY_ACCESS_USER_SHIFT); 887 + if (s[1] == 'w') a |= (NOTIFY_ACCESS_WRITE << NOTIFY_ACCESS_USER_SHIFT); 888 + 889 + if (s[2] == 'r') a |= (NOTIFY_ACCESS_READ << NOTIFY_ACCESS_GROUP_SHIFT); 890 + if (s[3] == 'w') a |= (NOTIFY_ACCESS_WRITE << NOTIFY_ACCESS_GROUP_SHIFT); 891 + 892 + if (s[4] == 'r') a |= (NOTIFY_ACCESS_READ << NOTIFY_ACCESS_OTHER_SHIFT); 893 + if (s[5] == 'w') a |= (NOTIFY_ACCESS_WRITE << NOTIFY_ACCESS_OTHER_SHIFT); 894 + 895 + return a; 896 + } 897 + 898 + static void 899 + init_config() 900 + { 901 + FILE *f; 902 + struct stat sb; 903 + char line[1024]; 904 + char **args; 905 + uint32_t status, argslen; 906 + uint32_t uid, gid, access; 907 + uint64_t nid, val64; 908 + 909 + /* 910 + * Set IPC Version Number & PID 911 + */ 912 + val64 = getpid(); 913 + val64 <<= 32; 914 + val64 |= NOTIFY_IPC_VERSION; 915 + 916 + _notify_lib_register_plain(global.notify_state, NOTIFY_IPC_VERSION_NAME, -1, notifyd_token++, -1, 0, 0, &nid); 917 + _notify_lib_set_state(global.notify_state, nid, val64, 0, 0); 918 + 919 + /* Check config file */ 920 + if (stat(CONFIG_FILE_PATH, &sb) != 0) return; 921 + 922 + if (sb.st_uid != 0) 923 + { 924 + log_message(ASL_LEVEL_ERR, "config file %s not owned by root: ignored\n", CONFIG_FILE_PATH); 925 + return; 926 + } 927 + 928 + if (sb.st_mode & 02) 929 + { 930 + log_message(ASL_LEVEL_ERR, "config file %s is world-writable: ignored\n", CONFIG_FILE_PATH); 931 + return; 932 + } 933 + 934 + /* Read config file */ 935 + f = fopen(CONFIG_FILE_PATH, "r"); 936 + if (f == NULL) return; 937 + 938 + forever 939 + { 940 + if (fgets(line, 1024, f) == NULL) break; 941 + if (line[0] == '\0') continue; 942 + if (line[0] == '#') continue; 943 + 944 + line[strlen(line) - 1] = '\0'; 945 + args = explode(line, "\t "); 946 + argslen = string_list_length(args); 947 + if (argslen == 0) continue; 948 + 949 + if (!strcasecmp(args[0], "monitor")) 950 + { 951 + if (argslen < 3) 952 + { 953 + string_list_free(args); 954 + continue; 955 + } 956 + _notify_lib_register_plain(global.notify_state, args[1], -1, notifyd_token++, -1, 0, 0, &nid); 957 + service_open_path(args[1], args[2], 0, 0); 958 + } 959 + 960 + if (!strcasecmp(args[0], "timer")) 961 + { 962 + if (argslen < 3) 963 + { 964 + string_list_free(args); 965 + continue; 966 + } 967 + _notify_lib_register_plain(global.notify_state, args[1], -1, notifyd_token++, -1, 0, 0, &nid); 968 + status = service_open_timer(args[1], args[2]); 969 + } 970 + 971 + else if (!strcasecmp(args[0], "set")) 972 + { 973 + if (argslen < 3) 974 + { 975 + string_list_free(args); 976 + continue; 977 + } 978 + 979 + val64 = atoll(args[2]); 980 + 981 + _notify_lib_register_plain(global.notify_state, args[1], -1, notifyd_token++, -1, 0, 0, &nid); 982 + _notify_lib_set_state(global.notify_state, nid, val64, 0, 0); 983 + } 984 + 985 + else if (!strcasecmp(args[0], "reserve")) 986 + { 987 + if (argslen == 1) 988 + { 989 + string_list_free(args); 990 + continue; 991 + } 992 + 993 + uid = 0; 994 + gid = 0; 995 + access = NOTIFY_ACCESS_DEFAULT; 996 + 997 + if (argslen > 2) uid = atoi(args[2]); 998 + if (argslen > 3) gid = atoi(args[3]); 999 + if (argslen > 4) access = atoaccess(args[4]); 1000 + 1001 + if ((uid != 0) || (gid != 0)) _notify_lib_set_owner(global.notify_state, args[1], uid, gid); 1002 + if (access != NOTIFY_ACCESS_DEFAULT) _notify_lib_set_access(global.notify_state, args[1], access); 1003 + } 1004 + else if (!strcasecmp(args[0], "quit")) 1005 + { 1006 + string_list_free(args); 1007 + break; 1008 + } 1009 + 1010 + string_list_free(args); 1011 + } 1012 + 1013 + fclose(f); 1014 + } 1015 + 1016 + static void 1017 + service_mach_message(bool blocking) 1018 + { 1019 + __block kern_return_t status; 1020 + uint32_t rbits, sbits; 1021 + notify_request_msg *request; 1022 + notify_reply_msg *reply; 1023 + char rbuf[sizeof(notify_request_msg) + MAX_TRAILER_SIZE]; 1024 + char sbuf[sizeof(notify_reply_msg) + MAX_TRAILER_SIZE]; 1025 + 1026 + forever 1027 + { 1028 + memset(rbuf, 0, sizeof(rbuf)); 1029 + memset(sbuf, 0, sizeof(sbuf)); 1030 + 1031 + request = (notify_request_msg *)rbuf; 1032 + reply = (notify_reply_msg *)sbuf; 1033 + 1034 + request->head.msgh_local_port = global.server_port; 1035 + request->head.msgh_size = global.request_size; 1036 + 1037 + rbits = MACH_RCV_MSG | (blocking ? 0 : MACH_RCV_TIMEOUT) | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) | MACH_RCV_VOUCHER; 1038 + sbits = MACH_SEND_MSG; 1039 + 1040 + status = mach_msg(&(request->head), rbits, 0, global.request_size, global.server_port, 0, MACH_PORT_NULL); 1041 + if (status != KERN_SUCCESS) return; 1042 + 1043 + voucher_mach_msg_state_t voucher = voucher_mach_msg_adopt(&(request->head)); 1044 + 1045 + #if TARGET_OS_EMBEDDED 1046 + /* Synchronize with work_q since on embedded main() calls this 1047 + * from the global concurrent queue. */ 1048 + dispatch_sync(global.work_q, ^{ 1049 + status = notify_ipc_server(&(request->head), &(reply->head)); 1050 + }); 1051 + #else 1052 + status = notify_ipc_server(&(request->head), &(reply->head)); 1053 + #endif 1054 + 1055 + if (!status && (request->head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) 1056 + { 1057 + /* destroy the request - but not the reply port */ 1058 + request->head.msgh_remote_port = MACH_PORT_NULL; 1059 + mach_msg_destroy(&(request->head)); 1060 + } 1061 + 1062 + if (reply->head.msgh_remote_port) 1063 + { 1064 + status = mach_msg(&(reply->head), sbits, reply->head.msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); 1065 + if (status == MACH_SEND_INVALID_DEST || status == MACH_SEND_TIMED_OUT) 1066 + { 1067 + /* deallocate reply port rights not consumed by failed mach_msg() send */ 1068 + mach_msg_destroy(&(reply->head)); 1069 + } 1070 + } 1071 + 1072 + voucher_mach_msg_revert(voucher); 1073 + } 1074 + } 1075 + 1076 + static int32_t 1077 + open_shared_memory(const char *name) 1078 + { 1079 + int32_t shmfd, isnew; 1080 + uint32_t size; 1081 + 1082 + size = global.nslots * sizeof(uint32_t); 1083 + 1084 + isnew = 1; 1085 + shmfd = shm_open(name, O_RDWR, 0644); 1086 + if (shmfd != -1) 1087 + { 1088 + isnew = 0; 1089 + } 1090 + else 1091 + { 1092 + shmfd = shm_open(name, O_RDWR | O_CREAT, 0644); 1093 + } 1094 + 1095 + if (shmfd == -1) 1096 + { 1097 + char error_message[1024]; 1098 + snprintf(error_message, sizeof(error_message), "shm_open %s failed: %s\n", name, strerror(errno)); 1099 + 1100 + CRSetCrashLogMessage(error_message); 1101 + log_message(ASL_LEVEL_NOTICE, "%s", error_message); 1102 + return -1; 1103 + } 1104 + 1105 + ftruncate(shmfd, size); 1106 + global.shared_memory_base = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0); 1107 + close(shmfd); 1108 + 1109 + if (isnew == 0) 1110 + { 1111 + global.last_shm_base = malloc(size); 1112 + if (global.last_shm_base != NULL) memcpy(global.last_shm_base, global.shared_memory_base, size); 1113 + } 1114 + 1115 + memset(global.shared_memory_base, 0, size); 1116 + global.shared_memory_refcount = (uint32_t *)malloc(size); 1117 + if (global.shared_memory_refcount == NULL) return -1; 1118 + 1119 + memset(global.shared_memory_refcount, 0, size); 1120 + 1121 + /* slot 0 is notifyd's pid */ 1122 + global.shared_memory_base[0] = getpid(); 1123 + global.shared_memory_refcount[0] = 1; 1124 + global.slot_id = 0; 1125 + 1126 + return 0; 1127 + } 1128 + 1129 + int 1130 + main(int argc, const char *argv[]) 1131 + { 1132 + dispatch_queue_t main_q; 1133 + const char *service_name; 1134 + const char *shm_name; 1135 + uint32_t i, status; 1136 + struct rlimit rlim; 1137 + 1138 + #if TARGET_IPHONE_SIMULATOR 1139 + asprintf(&_config_file_path, "%s/private/etc/notify.conf", getenv("SIMULATOR_ROOT")); 1140 + asprintf(&_debug_log_path, "%s/var/log/notifyd.log", getenv("SIMULATOR_LOG_ROOT")); 1141 + #endif 1142 + 1143 + service_name = NOTIFY_SERVICE_NAME; 1144 + shm_name = SHM_ID; 1145 + 1146 + notify_set_options(NOTIFY_OPT_DISABLE); 1147 + 1148 + /* remove limit of number of file descriptors */ 1149 + rlim.rlim_max = RLIM_INFINITY; 1150 + rlim.rlim_cur = MIN(OPEN_MAX, rlim.rlim_max); 1151 + setrlimit(RLIMIT_NOFILE, &rlim); 1152 + 1153 + signal(SIGPIPE, SIG_IGN); 1154 + signal(SIGHUP, SIG_IGN); 1155 + signal(SIGUSR1, SIG_IGN); 1156 + signal(SIGUSR2, SIG_IGN); 1157 + signal(SIGWINCH, SIG_IGN); 1158 + 1159 + memset(&call_statistics, 0, sizeof(struct call_statistics_s)); 1160 + 1161 + global.request_size = sizeof(notify_request_msg) + MAX_TRAILER_SIZE; 1162 + global.reply_size = sizeof(notify_reply_msg) + MAX_TRAILER_SIZE; 1163 + global.nslots = getpagesize() / sizeof(uint32_t); 1164 + global.notify_state = _notify_lib_notify_state_new(NOTIFY_STATE_ENABLE_RESEND, 1024); 1165 + global.log_cutoff = ASL_LEVEL_ERR; 1166 + global.log_path = strdup(DEBUG_LOG_PATH); 1167 + global.slot_id = (uint32_t)-1; 1168 + 1169 + for (i = 1; i < argc; i++) 1170 + { 1171 + if (!strcmp(argv[i], "-d")) 1172 + { 1173 + global.log_cutoff = ASL_LEVEL_DEBUG; 1174 + } 1175 + else if (!strcmp(argv[i], "-log_cutoff")) 1176 + { 1177 + global.log_cutoff = atoi(argv[++i]); 1178 + } 1179 + else if (!strcmp(argv[i], "-log_file")) 1180 + { 1181 + free(global.log_path); 1182 + global.log_path = strdup(argv[++i]); 1183 + } 1184 + else if (!strcmp(argv[i], "-service")) 1185 + { 1186 + service_name = argv[++i]; 1187 + } 1188 + else if (!strcmp(argv[i], "-shm")) 1189 + { 1190 + shm_name = argv[++i]; 1191 + } 1192 + else if (!strcmp(argv[i], "-shm_pages")) 1193 + { 1194 + global.nslots = atoi(argv[++i]) * (getpagesize() / sizeof(uint32_t)); 1195 + } 1196 + } 1197 + 1198 + global.log_default = global.log_cutoff; 1199 + 1200 + log_message(ASL_LEVEL_DEBUG, "--------------------\nnotifyd start PID %u\n", getpid()); 1201 + 1202 + init_launch_config(service_name); 1203 + 1204 + if (global.nslots > 0) 1205 + { 1206 + status = open_shared_memory(shm_name); 1207 + assert(status == 0); 1208 + } 1209 + 1210 + /* init from config file before starting the work queue */ 1211 + init_config(); 1212 + 1213 + main_q = dispatch_get_main_queue(); 1214 + assert(main_q != NULL); 1215 + 1216 + global.work_q = dispatch_queue_create("WorkQ", NULL); 1217 + assert(global.work_q != NULL); 1218 + 1219 + #if TARGET_OS_EMBEDDED 1220 + /* Block a thread in mach_msg() to avoid the syscall overhead of frequent 1221 + * dispatch source wakeup, and synchronize with work_q after message 1222 + * reception in service_mach_message(). <rdar://problem/8785140> */ 1223 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 1224 + forever service_mach_message(true); 1225 + }); 1226 + #else 1227 + global.mach_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, global.server_port, 0, global.work_q); 1228 + assert(global.mach_src != NULL); 1229 + 1230 + dispatch_source_set_event_handler(global.mach_src, ^{ 1231 + service_mach_message(false); 1232 + }); 1233 + dispatch_resume(global.mach_src); 1234 + #endif 1235 + 1236 + /* Set up SIGUSR1 */ 1237 + global.sig_usr1_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t)SIGUSR1, 0, main_q); 1238 + assert(global.sig_usr1_src != NULL); 1239 + dispatch_source_set_event_handler(global.sig_usr1_src, ^{ 1240 + dispatch_async(global.work_q, ^{ dump_status(STATUS_REQUEST_SHORT); }); 1241 + }); 1242 + dispatch_resume(global.sig_usr1_src); 1243 + 1244 + /* Set up SIGUSR2 */ 1245 + global.sig_usr2_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t)SIGUSR2, 0, main_q); 1246 + assert(global.sig_usr2_src != NULL); 1247 + dispatch_source_set_event_handler(global.sig_usr2_src, ^{ 1248 + dispatch_async(global.work_q, ^{ dump_status(STATUS_REQUEST_LONG); }); 1249 + }); 1250 + dispatch_resume(global.sig_usr2_src); 1251 + 1252 + /* Set up SIGWINCH */ 1253 + global.sig_winch_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t)SIGWINCH, 0, main_q); 1254 + assert(global.sig_winch_src != NULL); 1255 + dispatch_source_set_event_handler(global.sig_winch_src, ^{ 1256 + if (global.log_cutoff == ASL_LEVEL_DEBUG) global.log_cutoff = global.log_default; 1257 + else global.log_cutoff = ASL_LEVEL_DEBUG; 1258 + }); 1259 + dispatch_resume(global.sig_winch_src); 1260 + 1261 + dispatch_main(); 1262 + 1263 + /* NOTREACHED */ 1264 + return 0; 1265 + }
+101
libnotify/notifyd/notifyd.h
··· 1 + /* 2 + * Copyright (c) 2003-2010 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #ifndef _NOTIFY_DAEMON_H_ 25 + #define _NOTIFY_DAEMON_H_ 26 + 27 + #include <libnotify.h> 28 + #include <mach/mach.h> 29 + #include <launch.h> 30 + #include <dispatch/dispatch.h> 31 + 32 + #define NOTIFY_IPC_VERSION 2 33 + 34 + struct global_s 35 + { 36 + mach_port_t server_port; 37 + launch_data_t launch_dict; 38 + notify_state_t *notify_state; 39 + dispatch_queue_t work_q; 40 + dispatch_source_t mach_src; 41 + dispatch_source_t sig_usr1_src; 42 + dispatch_source_t sig_usr2_src; 43 + dispatch_source_t sig_winch_src; 44 + uint32_t request_size; 45 + uint32_t reply_size; 46 + uint32_t nslots; 47 + uint32_t slot_id; 48 + uint32_t *shared_memory_base; 49 + uint32_t *shared_memory_refcount; 50 + uint32_t *last_shm_base; 51 + uint32_t log_cutoff; 52 + uint32_t log_default; 53 + char *log_path; 54 + } global; 55 + 56 + struct call_statistics_s 57 + { 58 + uint64_t post; 59 + uint64_t post_no_op; 60 + uint64_t post_by_id; 61 + uint64_t post_by_name; 62 + uint64_t post_by_name_and_fetch_id; 63 + uint64_t reg; 64 + uint64_t reg_plain; 65 + uint64_t reg_check; 66 + uint64_t reg_signal; 67 + uint64_t reg_file; 68 + uint64_t reg_port; 69 + uint64_t cancel; 70 + uint64_t suspend; 71 + uint64_t resume; 72 + uint64_t suspend_pid; 73 + uint64_t resume_pid; 74 + uint64_t check; 75 + uint64_t get_state; 76 + uint64_t get_state_by_client; 77 + uint64_t get_state_by_id; 78 + uint64_t get_state_by_client_and_fetch_id; 79 + uint64_t set_state; 80 + uint64_t set_state_by_client; 81 + uint64_t set_state_by_id; 82 + uint64_t set_state_by_client_and_fetch_id; 83 + uint64_t get_owner; 84 + uint64_t set_owner; 85 + uint64_t get_access; 86 + uint64_t set_access; 87 + uint64_t monitor_file; 88 + uint64_t service_timer; 89 + uint64_t service_path; 90 + uint64_t cleanup; 91 + uint64_t regenerate; 92 + } call_statistics; 93 + 94 + extern void log_message(int priority, const char *str, ...); 95 + extern uint32_t daemon_post(const char *name, uint32_t u, uint32_t g); 96 + extern uint32_t daemon_post_nid(uint64_t nid, uint32_t u, uint32_t g); 97 + extern void daemon_post_client(uint64_t cid); 98 + extern void daemon_set_state(const char *name, uint64_t val); 99 + extern void dump_status(uint32_t level); 100 + 101 + #endif /* _NOTIFY_DAEMON_H_ */
+953
libnotify/notifyd/pathwatch.c
··· 1 + /* 2 + * Copyright (c) 2009-2010 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + /* 25 + * These routines, accessed through path_node_create() and path_node_release(), 26 + * provide an API for monitoring a path in the filesystem. The path may contain 27 + * directories and symbolic links. The path may not even exist! If the path 28 + * does exist, this code will respond to path deletions, component renaming, and 29 + * access control changes that either delete the path or make it inaccessible to a 30 + * target user/group. A notification will be provided if the path comes back into 31 + * existance or again becomes accessible. 32 + * 33 + * path_node_create() returns a path_node_t object, which contains a dispatch_source_t. 34 + * This source behaves very much like a DISPATCH_SOURCE_TYPE_VNODE, except that it also 35 + * triggers on the creation of a path. 36 + * 37 + * Internally, the work of monitoring a path is done by a set of helper vnode_t 38 + * objects. A vnode_t contains a dispatch_source_t (of type DISPATCH_SOURCE_TYPE_VNODE) 39 + * for a particular vnode. When a path_node_t is created, it creates (or shares) 40 + * vnode_t objects for each component of the desired path. For example, a path_node_t 41 + * for "/a/b/c" will create (or share, if some other path_node_t has already created) a 42 + * dispatch_source_t for "/", "/a", "/a/b", and "/a/b/c". If any of these sources is 43 + * notified of a change, the vnode_t will trigger an update for all path_node_t 44 + * objects that contain that path component. 45 + * 46 + * When a path_node_t update is triggered by a vnode_t component, the node re-evaluates 47 + * the target path that it is charged with monitoring. If the path exists and the end-point 48 + * vnode changed, then the update operation will trigger its dispatch_source_t to notify the 49 + * end-user of the change. If an intermediate path component is removed, renamed, or becomes 50 + * blocked by an access-control change, then the end-point dispatch_source_t is triggered to 51 + * indicate that the path has been deleted. However, the path_node_t remains active and 52 + * monitors the path components that still exist. Eventually, if the path is recreated or 53 + * if access controls change so that the path becomes visible to the target user, then the 54 + * end-point dispatch_source_t is triggered with a PATH_NODE_CREATE bit set in its data flags. 55 + * 56 + * path_node_releases() releases a path_node_t object and all of the vnode_t objects 57 + * that were monitoring components of its target path. 58 + */ 59 + 60 + #include <stdio.h> 61 + #include <stdlib.h> 62 + #include <string.h> 63 + #include <errno.h> 64 + #include <sys/stat.h> 65 + #include <sys/param.h> 66 + #include <sys/syscall.h> 67 + #include <sys/kauth.h> 68 + #include <pwd.h> 69 + #include <fcntl.h> 70 + #include <assert.h> 71 + #include <tzfile.h> 72 + #include "pathwatch.h" 73 + 74 + #define forever for(;;) 75 + #define streq(A,B) (strcmp(A,B)==0) 76 + #define DISPATCH_VNODE_ALL 0x7f 77 + 78 + #define PATH_STAT_OK 0 79 + #define PATH_STAT_FAILED 1 80 + #define PATH_STAT_ACCESS 2 81 + 82 + #define VPATH_NODE_TYPE_REG 0 83 + #define VPATH_NODE_TYPE_LINK 1 84 + #define VPATH_NODE_TYPE_DELETED 2 85 + 86 + #define DISPATCH_VNODE_UNAVAIL (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME | DISPATCH_VNODE_REVOKE) 87 + 88 + /* Libinfo global */ 89 + extern uint32_t gL1CacheEnabled; 90 + 91 + /* 92 + * vnode_t represents a vnode. 93 + * 94 + * The dispatch source is of type DISPATCH_SOURCE_TYPE_VNODE for file descriptor fd. 95 + * The handler for the source triggers an update routine for all the path_node_t 96 + * objects in the path_node list. 97 + */ 98 + typedef struct 99 + { 100 + char *path; 101 + uint32_t type; 102 + int fd; 103 + struct timespec mtime; 104 + struct timespec ctime; 105 + dispatch_source_t src; 106 + uint32_t path_node_count; 107 + path_node_t **path_node; 108 + } vnode_t; 109 + 110 + static struct 111 + { 112 + dispatch_once_t pathwatch_init; 113 + dispatch_queue_t pathwatch_queue; 114 + uint32_t vnode_count; 115 + vnode_t **vnode; 116 + char *tzdir; 117 + size_t tzdir_len; 118 + } _global = {0}; 119 + 120 + /* forward */ 121 + static void _path_node_update(path_node_t *pnode, uint32_t flags, vnode_t *vnode); 122 + 123 + /* 124 + * stat() or lstat() a path as a particular user/group. 125 + */ 126 + static int 127 + _path_stat(const char *path, int link, uid_t uid, gid_t gid) 128 + { 129 + struct stat sb; 130 + gid_t orig_gidset[NGROUPS_MAX]; 131 + int ngroups, status, stat_status; 132 + struct passwd *p; 133 + uint32_t orig_cache_enabled; 134 + 135 + /* disable L1 cache to avoid notification deadlock */ 136 + orig_cache_enabled = gL1CacheEnabled; 137 + gL1CacheEnabled = 0; 138 + 139 + /* get my group list */ 140 + memset(orig_gidset, 0, sizeof(orig_gidset)); 141 + ngroups = getgroups(NGROUPS_MAX, orig_gidset); 142 + if (ngroups < 0) 143 + { 144 + return PATH_STAT_FAILED; 145 + } 146 + 147 + /* look up user name */ 148 + p = getpwuid(uid); 149 + if (p == NULL) 150 + { 151 + gL1CacheEnabled = orig_cache_enabled; 152 + return PATH_STAT_FAILED; 153 + } 154 + 155 + /* switch to user's grouplist */ 156 + status = initgroups(p->pw_name, gid); 157 + if (status < 0) 158 + { 159 + gL1CacheEnabled = orig_cache_enabled; 160 + return PATH_STAT_FAILED; 161 + } 162 + 163 + /* reset gL1CacheEnabled */ 164 + gL1CacheEnabled = orig_cache_enabled; 165 + 166 + /* set thread credentials */ 167 + pthread_setugid_np(uid, gid); 168 + 169 + /* stat the file */ 170 + stat_status = -1; 171 + if (link != 0) 172 + { 173 + stat_status = lstat(path, &sb); 174 + } 175 + else 176 + { 177 + stat_status = stat(path, &sb); 178 + } 179 + 180 + /* unset thread credentials */ 181 + pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE); 182 + 183 + /* restore original grouplist for UID 0 */ 184 + status = syscall(SYS_initgroups, ngroups, orig_gidset, 0); 185 + if (status < 0) 186 + { 187 + return PATH_STAT_FAILED; 188 + } 189 + 190 + /* return status */ 191 + if (stat_status == 0) 192 + { 193 + return PATH_STAT_OK; 194 + } 195 + 196 + if (errno == EACCES) 197 + { 198 + return PATH_STAT_ACCESS; 199 + } 200 + 201 + return PATH_STAT_FAILED; 202 + } 203 + 204 + /* 205 + * Check access to a path by a particular user/group. 206 + * Sets ftype output parameter if it is non-NULL. 207 + */ 208 + static int 209 + _path_stat_check_access(const char *path, uid_t uid, gid_t gid, uint32_t *ftype) 210 + { 211 + struct stat sb; 212 + char buf[MAXPATHLEN + 1]; 213 + int status, t; 214 + 215 + if (path == NULL) return PATH_STAT_FAILED; 216 + 217 + if (ftype != NULL) *ftype = PATH_NODE_TYPE_GHOST; 218 + 219 + /* Paths must be absolute */ 220 + if (path[0] != '/') return PATH_STAT_FAILED; 221 + 222 + /* Root dir is readable */ 223 + if (path[1] == '\0') 224 + { 225 + if (ftype != NULL) *ftype = PATH_NODE_TYPE_DIR; 226 + return PATH_STAT_OK; 227 + } 228 + 229 + memset(&sb, 0, sizeof(struct stat)); 230 + status = lstat(path, &sb); 231 + 232 + if (status != 0) return PATH_STAT_FAILED; 233 + else if ((sb.st_mode & S_IFMT) == S_IFDIR) t = PATH_NODE_TYPE_DIR; 234 + else if ((sb.st_mode & S_IFMT) == S_IFREG) t = PATH_NODE_TYPE_FILE; 235 + else if ((sb.st_mode & S_IFMT) == S_IFLNK) t = PATH_NODE_TYPE_LINK; 236 + else t = PATH_NODE_TYPE_OTHER; 237 + 238 + if (ftype != NULL) *ftype = t; 239 + 240 + if (t == PATH_NODE_TYPE_OTHER) return PATH_STAT_FAILED; 241 + 242 + /* skip access control check if uid is zero */ 243 + if (uid == 0) return 0; 244 + 245 + /* special case: anything in the timezone directory is OK */ 246 + memset(buf, 0, sizeof(buf)); 247 + if (realpath(path, buf) == NULL) return PATH_STAT_FAILED; 248 + if ((_global.tzdir != NULL) && (!strncasecmp(buf, _global.tzdir, _global.tzdir_len))) 249 + { 250 + return PATH_STAT_OK; 251 + } 252 + 253 + /* call _path_stat to check access as the user/group provided */ 254 + if (t == PATH_NODE_TYPE_FILE) 255 + { 256 + status = _path_stat(path, 0, uid, gid); 257 + if ((status == PATH_STAT_ACCESS) && (ftype != NULL)) *ftype = PATH_NODE_TYPE_GHOST; 258 + return status; 259 + } 260 + else if (t == PATH_NODE_TYPE_LINK) 261 + { 262 + status = _path_stat(path, 1, uid, gid); 263 + if ((status == PATH_STAT_ACCESS) && (ftype != NULL)) *ftype = PATH_NODE_TYPE_GHOST; 264 + return status; 265 + } 266 + else if (t == PATH_NODE_TYPE_DIR) 267 + { 268 + snprintf(buf, MAXPATHLEN, "%s/.", path); 269 + status = _path_stat(buf, 0, uid, gid); 270 + if ((status == PATH_STAT_ACCESS) && (ftype != NULL)) *ftype = PATH_NODE_TYPE_GHOST; 271 + return status; 272 + } 273 + 274 + /* we don't ever get here, but... */ 275 + return PATH_STAT_FAILED; 276 + } 277 + 278 + /* 279 + * Uniquely add a pnode to a vnode's list of path nodes. 280 + */ 281 + static void 282 + _vnode_add_pnode(vnode_t *vnode, path_node_t *pnode) 283 + { 284 + uint32_t i; 285 + 286 + for (i = 0; i < vnode->path_node_count; i++) 287 + { 288 + if (vnode->path_node[i] == pnode) return; 289 + } 290 + 291 + for (i = 0; i < vnode->path_node_count; i++) 292 + { 293 + if (vnode->path_node[i] == NULL) 294 + { 295 + vnode->path_node[i] = pnode; 296 + return; 297 + } 298 + } 299 + 300 + if (vnode->path_node_count == 0) 301 + { 302 + vnode->path_node = (path_node_t **)calloc(1, sizeof(path_node_t *)); 303 + } 304 + else 305 + { 306 + vnode->path_node = (path_node_t **)reallocf(vnode->path_node, (vnode->path_node_count + 1) * sizeof(path_node_t *)); 307 + } 308 + 309 + assert(vnode->path_node != NULL); 310 + 311 + vnode->path_node[vnode->path_node_count++] = pnode; 312 + } 313 + 314 + /* 315 + * Free a vnode_t and cancel/release its dispatch source. 316 + */ 317 + static void 318 + _vnode_free(vnode_t *vnode) 319 + { 320 + dispatch_source_cancel(vnode->src); 321 + 322 + /* 323 + * Actually free the vnode on the pathwatch queue. This allows any 324 + * enqueued _vnode_event operations to complete before the vnode disappears. 325 + * _vnode_event() quietly returns if the source has been cancelled. 326 + */ 327 + dispatch_async(_global.pathwatch_queue, ^{ 328 + dispatch_release(vnode->src); 329 + free(vnode->path); 330 + free(vnode->path_node); 331 + free(vnode); 332 + }); 333 + } 334 + 335 + /* 336 + * Handler routine for vnode_t objects. 337 + * Invokes the _path_node_update routine for all of the vnode's pnodes. 338 + */ 339 + static void 340 + _vnode_event(vnode_t *vnode) 341 + { 342 + uint32_t i, flags; 343 + unsigned long ulf; 344 + struct stat sb; 345 + 346 + if (vnode == NULL) return; 347 + if ((vnode->src != NULL) && (dispatch_source_testcancel(vnode->src))) return; 348 + 349 + ulf = dispatch_source_get_data(vnode->src); 350 + flags = ulf; 351 + 352 + memset(&sb, 0, sizeof(struct stat)); 353 + if (fstat(vnode->fd, &sb) == 0) 354 + { 355 + if ((vnode->mtime.tv_sec != sb.st_mtimespec.tv_sec) || (vnode->mtime.tv_nsec != sb.st_mtimespec.tv_nsec)) 356 + { 357 + flags |= PATH_NODE_MTIME; 358 + vnode->mtime = sb.st_mtimespec; 359 + } 360 + 361 + if ((vnode->ctime.tv_sec != sb.st_ctimespec.tv_sec) || (vnode->ctime.tv_nsec != sb.st_ctimespec.tv_nsec)) 362 + { 363 + flags |= PATH_NODE_CTIME; 364 + vnode->ctime = sb.st_ctimespec; 365 + } 366 + } 367 + 368 + /* 369 + * Flag deleted sources. 370 + * We can't delete them here, since _path_node_update may need them. 371 + * However, _path_node_update will release them and they will get cleaned 372 + * up in a _vnode_sweep later on. 373 + */ 374 + if (flags & DISPATCH_VNODE_DELETE) vnode->type = VPATH_NODE_TYPE_DELETED; 375 + 376 + for (i = 0; i < vnode->path_node_count; i++) 377 + { 378 + _path_node_update(vnode->path_node[i], flags, vnode); 379 + } 380 + } 381 + 382 + /* 383 + * Creates a vnode_t object. 384 + */ 385 + static vnode_t * 386 + _vnode_create(const char *path, uint32_t type, path_node_t *pnode) 387 + { 388 + int fd, flags; 389 + uint32_t i; 390 + vnode_t *vnode; 391 + dispatch_source_t src; 392 + struct stat sb; 393 + 394 + if (path == NULL) path = "/"; 395 + if (path[0] == '\0') path = "/"; 396 + 397 + for (i = 0; i < _global.vnode_count; i++) 398 + { 399 + vnode = _global.vnode[i]; 400 + if (vnode == NULL) continue; 401 + 402 + if ((vnode->type == type) && (streq(path, vnode->path))) 403 + { 404 + _vnode_add_pnode(vnode, pnode); 405 + return vnode; 406 + } 407 + } 408 + 409 + vnode = NULL; 410 + 411 + flags = O_EVTONLY; 412 + if (type == VPATH_NODE_TYPE_LINK) flags |= O_SYMLINK; 413 + 414 + fd = open(path, flags, 0); 415 + if (fd < 0) return NULL; 416 + 417 + src = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, (uintptr_t)fd, DISPATCH_VNODE_ALL, _global.pathwatch_queue); 418 + if (src == NULL) 419 + { 420 + close(fd); 421 + return NULL; 422 + } 423 + 424 + vnode = (vnode_t *)calloc(1, sizeof(vnode_t)); 425 + assert(vnode != NULL); 426 + 427 + vnode->type = type; 428 + vnode->path = strdup(path); 429 + assert(vnode->path != NULL); 430 + 431 + vnode->fd = fd; 432 + vnode->src = src; 433 + 434 + memset(&sb, 0, sizeof(struct stat)); 435 + if (fstat(fd, &sb) == 0) 436 + { 437 + vnode->mtime = sb.st_mtimespec; 438 + vnode->ctime = sb.st_ctimespec; 439 + } 440 + 441 + _vnode_add_pnode(vnode, pnode); 442 + 443 + dispatch_source_set_event_handler(src, ^{ _vnode_event(vnode); }); 444 + dispatch_source_set_cancel_handler(src, ^{ close(fd); }); 445 + 446 + if (_global.vnode_count == 0) 447 + { 448 + _global.vnode = (vnode_t **)calloc(1, sizeof(vnode_t *)); 449 + } 450 + else 451 + { 452 + _global.vnode = (vnode_t **)reallocf(_global.vnode, (_global.vnode_count + 1) * sizeof(vnode_t *)); 453 + } 454 + 455 + assert(_global.vnode != NULL); 456 + 457 + _global.vnode[_global.vnode_count++] = vnode; 458 + 459 + dispatch_resume(src); 460 + 461 + return vnode; 462 + } 463 + 464 + static vnode_t * 465 + _vnode_create_real_path(const char *path, uint32_t type, path_node_t *pnode) 466 + { 467 + char real[MAXPATHLEN + 1]; 468 + 469 + if (path == NULL) return _vnode_create(path, type, pnode); 470 + 471 + if (NULL != realpath(path, real)) return _vnode_create(real, type, pnode); 472 + 473 + return NULL; 474 + } 475 + 476 + /* 477 + * Examines all the vnode_t objects (held in the _global data), 478 + * frees any that have no path nodes. 479 + */ 480 + static void 481 + _vnode_sweep() 482 + { 483 + uint32_t i, j, new_vnode_count, new_path_node_count; 484 + vnode_t **new_source, *vnode; 485 + path_node_t **new_path_node; 486 + 487 + new_source = NULL; 488 + 489 + for (i = 0; i < _global.vnode_count; i++) 490 + { 491 + vnode = _global.vnode[i]; 492 + if (vnode == NULL) continue; 493 + 494 + new_path_node_count = 0; 495 + new_path_node = NULL; 496 + 497 + for (j = 0; j < vnode->path_node_count; j++) 498 + { 499 + if (vnode->path_node[j] != NULL) new_path_node_count++; 500 + } 501 + 502 + if (new_path_node_count == vnode->path_node_count) 503 + { 504 + /* no change */ 505 + continue; 506 + } 507 + else if (new_path_node_count > 0) 508 + { 509 + new_path_node = (path_node_t **)calloc(new_path_node_count, sizeof(path_node_t *)); 510 + assert(new_path_node != NULL); 511 + 512 + new_path_node_count = 0; 513 + for (j = 0; j < vnode->path_node_count; j++) 514 + { 515 + if (vnode->path_node[j] != NULL) 516 + { 517 + new_path_node[new_path_node_count++] = vnode->path_node[j]; 518 + } 519 + } 520 + } 521 + 522 + free(vnode->path_node); 523 + vnode->path_node = new_path_node; 524 + vnode->path_node_count = new_path_node_count; 525 + } 526 + 527 + new_vnode_count = 0; 528 + for (i = 0; i < _global.vnode_count; i++) 529 + { 530 + vnode = _global.vnode[i]; 531 + if (vnode == NULL) continue; 532 + if (vnode->path_node_count > 0) new_vnode_count++; 533 + } 534 + 535 + if (new_vnode_count == _global.vnode_count) 536 + { 537 + /* no change */ 538 + return; 539 + } 540 + else if (new_vnode_count > 0) 541 + { 542 + new_source = (vnode_t **)calloc(new_vnode_count, sizeof(vnode_t *)); 543 + assert(new_source != NULL); 544 + 545 + new_vnode_count = 0; 546 + for (i = 0; i < _global.vnode_count; i++) 547 + { 548 + vnode = _global.vnode[i]; 549 + if (vnode == NULL) continue; 550 + 551 + if (vnode->path_node_count > 0) 552 + { 553 + new_source[new_vnode_count++] = vnode; 554 + } 555 + else 556 + { 557 + _vnode_free(vnode); 558 + } 559 + } 560 + } 561 + 562 + free(_global.vnode); 563 + _global.vnode = new_source; 564 + _global.vnode_count = new_vnode_count; 565 + } 566 + 567 + /* 568 + * Releases sources that have a particular node on their list. 569 + * This is a deferred release mechanism for vnode_t objects. 570 + * The calling routine must call _vnode_sweep subsequent to 571 + * calling this routine. 572 + * _vnode_sweep will actually free any vnode_t objects 573 + * that have a no path nodes. 574 + */ 575 + static void 576 + _vnode_release_for_node(path_node_t *pnode) 577 + { 578 + uint32_t i, j; 579 + vnode_t *vnode; 580 + 581 + for (i = 0; i < _global.vnode_count; i++) 582 + { 583 + vnode = _global.vnode[i]; 584 + if (vnode == NULL) continue; 585 + 586 + for (j = 0; j < vnode->path_node_count; j++) 587 + { 588 + if (vnode->path_node[j] == pnode) 589 + { 590 + vnode->path_node[j] = NULL; 591 + break; 592 + } 593 + } 594 + } 595 + } 596 + 597 + /* 598 + * Retain a path_node_t object. 599 + * Dispatched on _global.pathwatch_queue. 600 + */ 601 + static void 602 + _path_node_retain(path_node_t *pnode) 603 + { 604 + if (pnode == NULL) return; 605 + pnode->refcount++; 606 + } 607 + 608 + /* 609 + * Free a path_node_t object. 610 + * Dispatched on _global.pathwatch_queue. 611 + */ 612 + static void 613 + _path_node_free(path_node_t *pnode) 614 + { 615 + uint32_t i, n; 616 + 617 + if (pnode == NULL) return; 618 + 619 + /* 620 + * Remove this path node from all vnodes. 621 + */ 622 + _vnode_release_for_node(pnode); 623 + _vnode_sweep(); 624 + 625 + free(pnode->path); 626 + 627 + if (pnode->pname != NULL) 628 + { 629 + n = pnode->pname_count; 630 + pnode->pname_count = 0; 631 + 632 + for (i = 0; i < n; i++) 633 + { 634 + free(pnode->pname[i]); 635 + pnode->pname[i] = NULL; 636 + } 637 + 638 + free(pnode->pname); 639 + } 640 + 641 + free(pnode->contextp); 642 + 643 + dispatch_release(pnode->src); 644 + dispatch_release(pnode->src_queue); 645 + 646 + memset(pnode, 0, sizeof(path_node_t)); 647 + free(pnode); 648 + } 649 + 650 + /* 651 + * Release a path_node_t object. 652 + */ 653 + static void 654 + _path_node_release(path_node_t *pnode) 655 + { 656 + if (pnode == NULL) return; 657 + 658 + /* 659 + * We need to make sure that the node's event handler isn't currently 660 + * executing before freeing the node. We dispatch on the src_queue, so 661 + * that when the block executes there will be no more events in the queue. 662 + * From there, we dispatch async back to the pathwatch_queue to do the 663 + * data structure cleanup. 664 + */ 665 + dispatch_async(pnode->src_queue, ^{ 666 + dispatch_async(_global.pathwatch_queue, ^{ 667 + if (pnode->refcount > 0) pnode->refcount--; 668 + if (pnode->refcount == 0) _path_node_free(pnode); 669 + }); 670 + }); 671 + } 672 + 673 + /* 674 + * Frees a path_node_t object. 675 + * The work is actually done on the global pathwatch_queue to make this safe. 676 + */ 677 + void 678 + path_node_close(path_node_t *pnode) 679 + { 680 + if (pnode == NULL) return; 681 + 682 + if (pnode->src != NULL) dispatch_source_cancel(pnode->src); 683 + _path_node_release(pnode); 684 + } 685 + 686 + static void 687 + _pathwatch_init() 688 + { 689 + char buf[MAXPATHLEN]; 690 + 691 + /* Create serial queue for node creation / deletion operations */ 692 + _global.pathwatch_queue = dispatch_queue_create("pathwatch", NULL); 693 + 694 + _global.tzdir = NULL; 695 + _global.tzdir_len = 0; 696 + 697 + /* Get the real path to TZDIR */ 698 + if (realpath(TZDIR, buf) != NULL) 699 + { 700 + _global.tzdir_len = strlen(buf); 701 + _global.tzdir = strdup(buf); 702 + if (_global.tzdir == NULL) _global.tzdir_len = 0; 703 + } 704 + } 705 + 706 + /* 707 + * _path_node_init is responsible for allocating a path_node_t structure, 708 + * and for creating the pname array and setting the path component. 709 + * The path is a sanatized version of the caller's path with redundant "/" 710 + * characters stripped out. The pname array contains each "/" separated 711 + * component of the path. 712 + * 713 + * For example, _path_node_init("///foo////bar//baz/") creates: 714 + * pnode->path = "/foo/bar/baz" 715 + * pnode->pname_count = 3 716 + * pnode->pname[0] = "foo" 717 + * pnode->pname[1] = "bar" 718 + * pnode->pname[2] = "baz" 719 + */ 720 + static path_node_t * 721 + _path_node_init(const char *path) 722 + { 723 + size_t len; 724 + uint32_t i; 725 + path_node_t *pnode; 726 + const char *start, *end; 727 + char *name; 728 + 729 + if (path == NULL) path = "/"; 730 + if (path[0] != '/') return NULL; 731 + 732 + pnode = (path_node_t *)calloc(1, sizeof(path_node_t)); 733 + assert(pnode != NULL); 734 + 735 + pnode->plen = 1; 736 + start = path; 737 + while (*start == '/') start++; 738 + 739 + forever 740 + { 741 + end = strchr(start, '/'); 742 + if (end == NULL) end = strchr(start, '\0'); 743 + 744 + len = end - start; 745 + if (len == 0) break; 746 + 747 + pnode->plen += (len + 1); 748 + 749 + name = NULL; 750 + if (end == NULL) 751 + { 752 + name = strdup(start); 753 + } 754 + else 755 + { 756 + name = malloc(len + 1); 757 + assert(name != NULL); 758 + strncpy(name, start, len); 759 + name[len] = '\0'; 760 + } 761 + 762 + if (pnode->pname_count == 0) 763 + { 764 + pnode->pname = (char **)calloc(1, sizeof(char *)); 765 + } 766 + else 767 + { 768 + pnode->pname = (char **)reallocf(pnode->pname, (pnode->pname_count + 1) * sizeof(char *)); 769 + } 770 + 771 + assert(pnode->pname != NULL); 772 + pnode->pname[pnode->pname_count] = name; 773 + pnode->pname_count++; 774 + 775 + start = end; 776 + if (start != NULL) 777 + { 778 + /* skip '/' chars */ 779 + while (*start == '/') start++; 780 + } 781 + } 782 + 783 + pnode->path = calloc(1, pnode->plen); 784 + assert(pnode->path != NULL); 785 + /* 786 + * Reconstruct the path here to strip out excess "/" chars. 787 + * This ensures that path comparisons in _path_node_update are correct. 788 + */ 789 + for (i = 0; i < pnode->pname_count; i++) 790 + { 791 + strlcat(pnode->path, "/", pnode->plen); 792 + strlcat(pnode->path, pnode->pname[i], pnode->plen); 793 + } 794 + 795 + return pnode; 796 + } 797 + 798 + /* dispatched on _global.pathwatch_queue */ 799 + static void 800 + _path_node_update(path_node_t *pnode, uint32_t flags, vnode_t *vnode) 801 + { 802 + char *buf, fixed[MAXPATHLEN + 1]; 803 + uint32_t i, old_type; 804 + int status; 805 + unsigned long data; 806 + struct stat sb; 807 + 808 + if (pnode == NULL) return; 809 + if ((pnode->src != NULL) && (dispatch_source_testcancel(pnode->src))) return; 810 + 811 + old_type = pnode->type; 812 + 813 + status = _path_stat_check_access(pnode->path, pnode->uid, pnode->gid, &(pnode->type)); 814 + if (status == PATH_STAT_ACCESS) flags |= DISPATCH_VNODE_REVOKE; 815 + 816 + data = 0; 817 + 818 + if (vnode != NULL) 819 + { 820 + /* update status */ 821 + 822 + if (flags & DISPATCH_VNODE_UNAVAIL) 823 + { 824 + pnode->type = PATH_NODE_TYPE_GHOST; 825 + data |= (flags & DISPATCH_VNODE_UNAVAIL); 826 + data |= DISPATCH_VNODE_DELETE; 827 + } 828 + 829 + if ((vnode->path != NULL) && (pnode->path != NULL) && streq(vnode->path, pnode->path)) 830 + { 831 + /* this is the target VNODE - transfer flags to src data */ 832 + data |= flags; 833 + } 834 + 835 + if (old_type == PATH_NODE_TYPE_GHOST) 836 + { 837 + /* transition from ghost to non-ghost */ 838 + if (pnode->type != PATH_NODE_TYPE_GHOST) 839 + { 840 + data |= PATH_NODE_CREATE; 841 + } 842 + else 843 + { 844 + data = 0; 845 + } 846 + } 847 + else if (pnode->type == PATH_NODE_TYPE_GHOST) 848 + { 849 + /* transition from non-ghost to ghost */ 850 + data |= PATH_NODE_DELETE; 851 + } 852 + 853 + data &= (pnode->flags & PATH_NODE_ALL); 854 + if (data != 0) 855 + { 856 + if ((pnode->flags & PATH_SRC_SUSPENDED) == 0) 857 + { 858 + /* suspend pnode->src, and fire it after PNODE_COALESCE_TIME */ 859 + pnode->flags |= PATH_SRC_SUSPENDED; 860 + dispatch_suspend(pnode->src); 861 + 862 + dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, PNODE_COALESCE_TIME); 863 + _path_node_retain(pnode); 864 + 865 + dispatch_after(delay, _global.pathwatch_queue, ^{ 866 + pnode->flags &= ~PATH_SRC_SUSPENDED; 867 + dispatch_resume(pnode->src); 868 + _path_node_release(pnode); 869 + }); 870 + } 871 + 872 + dispatch_source_merge_data(pnode->src, data); 873 + } 874 + } 875 + 876 + buf = NULL; 877 + if (pnode->plen < MAXPATHLEN) buf = fixed; 878 + else buf = malloc(pnode->plen); 879 + assert(buf != NULL); 880 + 881 + /* "autorelease" current sources (_vnode_sweep() will delete those with zero refcount) */ 882 + _vnode_release_for_node(pnode); 883 + 884 + /* create new sources (may re-use existing sources) */ 885 + _vnode_create(NULL, 0, pnode); 886 + 887 + memset(buf, 0, pnode->plen); 888 + for (i = 0; i < pnode->pname_count; i++) 889 + { 890 + assert((strlen(buf) + 1) <= pnode->plen); 891 + strlcat(buf, "/", pnode->plen); 892 + 893 + assert(pnode->pname[i] != NULL); 894 + assert((strlen(buf) + strlen(pnode->pname[i])) <= pnode->plen); 895 + strlcat(buf, pnode->pname[i], pnode->plen); 896 + 897 + memset(&sb, 0, sizeof(struct stat)); 898 + if (lstat(buf, &sb) < 0) 899 + { 900 + /* the path stops existing here */ 901 + break; 902 + } 903 + 904 + if ((sb.st_mode & S_IFMT) == S_IFLNK) 905 + { 906 + /* open the symlink itself */ 907 + _vnode_create(buf, VPATH_NODE_TYPE_LINK, pnode); 908 + 909 + /* open the symlink target */ 910 + _vnode_create_real_path(buf, 0, pnode); 911 + } 912 + else 913 + { 914 + _vnode_create(buf, 0, pnode); 915 + } 916 + } 917 + 918 + /* sweep source list (deletes those with zero refcount) */ 919 + _vnode_sweep(); 920 + 921 + if (buf != fixed) free(buf); 922 + } 923 + 924 + /* 925 + * Creates a dispatch source that activates when a path changes. 926 + * Internally, creates a data structure (path_node_t) that represents the entire path. 927 + * Also creates dispatch sources (vnode_t) for each path component. These vnodes may 928 + * be shared with other path_node_t structures. 929 + */ 930 + path_node_t * 931 + path_node_create(const char *path, uid_t uid, gid_t gid, uint32_t mask, dispatch_queue_t queue) 932 + { 933 + path_node_t *pnode; 934 + 935 + dispatch_once(&(_global.pathwatch_init), ^{ _pathwatch_init(); }); 936 + 937 + pnode = _path_node_init(path); 938 + if (pnode == NULL) return NULL; 939 + 940 + pnode->refcount = 1; 941 + pnode->uid = uid; 942 + pnode->gid = gid; 943 + 944 + dispatch_sync(_global.pathwatch_queue, ^{ _path_node_update(pnode, 0, NULL); }); 945 + 946 + dispatch_retain(queue); 947 + 948 + pnode->src = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_OR, 0, 0, queue); 949 + pnode->src_queue = queue; 950 + pnode->flags = mask & PATH_NODE_ALL; 951 + 952 + return pnode; 953 + }
+84
libnotify/notifyd/pathwatch.h
··· 1 + /* 2 + * Copyright (c) 2009-2010 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #ifndef _PATHWATCH_H_ 25 + #define _PATHWATCH_H_ 26 + 27 + #include <dispatch/dispatch.h> 28 + /* 29 + * types for virtual path nodes (path_node_t) 30 + */ 31 + #define PATH_NODE_TYPE_GHOST 0 32 + #define PATH_NODE_TYPE_FILE 1 33 + #define PATH_NODE_TYPE_LINK 2 34 + #define PATH_NODE_TYPE_DIR 3 35 + #define PATH_NODE_TYPE_OTHER 4 36 + 37 + 38 + enum 39 + { 40 + PATH_NODE_DELETE = 0x0001, /* node or path deleted */ 41 + PATH_NODE_WRITE = 0x0002, /* node written */ 42 + PATH_NODE_EXTEND = 0x0004, /* node extended */ 43 + PATH_NODE_ATTRIB = 0x0008, /* node attributes changed (mtime or ctime) */ 44 + PATH_NODE_LINK = 0x0010, /* node link count changed */ 45 + PATH_NODE_RENAME = 0x0020, /* node renamed, always accompanied by PATH_NODE_DELETE */ 46 + PATH_NODE_REVOKE = 0x0040, /* access revoked, always accompanied by PATH_NODE_DELETE */ 47 + PATH_NODE_CREATE = 0x0080, /* path created or access re-acquired */ 48 + PATH_NODE_MTIME = 0x0100, /* path mtime changed, always accompanied by PATH_NODE_ATTRIB */ 49 + PATH_NODE_CTIME = 0x0200 /* path ctime changed, always accompanied by PATH_NODE_ATTRIB */ 50 + }; 51 + 52 + /* all bits mask */ 53 + #define PATH_NODE_ALL 0x000003ff 54 + /* src is suspended */ 55 + #define PATH_SRC_SUSPENDED 0x10000000 56 + 57 + /* Path changes coalesce for 100 milliseconds */ 58 + #define PNODE_COALESCE_TIME 100000000 59 + 60 + /* 61 + * path_node_t represents a virtual path 62 + */ 63 + typedef struct 64 + { 65 + char *path; 66 + size_t plen; 67 + uid_t uid; 68 + gid_t gid; 69 + uint32_t pname_count; 70 + char **pname; 71 + uint32_t type; 72 + uint32_t flags; 73 + dispatch_source_t src; 74 + dispatch_queue_t src_queue; 75 + void *contextp; 76 + uint32_t context32; 77 + uint64_t context64; 78 + uint32_t refcount; 79 + } path_node_t; 80 + 81 + path_node_t *path_node_create(const char *path, uid_t uid, gid_t gid, uint32_t mask, dispatch_queue_t queue); 82 + void path_node_close(path_node_t *pnode); 83 + 84 + #endif /* _PATHWATCH_H_ */
+523
libnotify/notifyd/service.c
··· 1 + /* 2 + * Copyright (c) 2003-2010 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #include <stdio.h> 25 + #include <stdlib.h> 26 + #include <string.h> 27 + #include <unistd.h> 28 + #include <assert.h> 29 + #include <asl.h> 30 + #include "notify.h" 31 + #include "notifyd.h" 32 + #include "service.h" 33 + #include "pathwatch.h" 34 + #include "timer.h" 35 + 36 + #define NOTIFY_PATH_SERVICE "path:" 37 + #define NOTIFY_PATH_SERVICE_LEN 5 38 + #define NOTIFY_TIMER_SERVICE "timer:" 39 + #define NOTIFY_TIMER_SERVICE_LEN 6 40 + 41 + /* Libinfo global */ 42 + extern uint32_t gL1CacheEnabled; 43 + 44 + static uint32_t 45 + service_type(const char *name) 46 + { 47 + uint32_t len; 48 + 49 + len = SERVICE_PREFIX_LEN; 50 + if (strncmp(name, SERVICE_PREFIX, len)) return SERVICE_TYPE_NONE; 51 + else if (!strncmp(name + len, NOTIFY_PATH_SERVICE, NOTIFY_PATH_SERVICE_LEN)) return SERVICE_TYPE_PATH_PRIVATE; 52 + else if (!strncmp(name + len, NOTIFY_TIMER_SERVICE, NOTIFY_TIMER_SERVICE_LEN)) return SERVICE_TYPE_TIMER_PRIVATE; 53 + 54 + return SERVICE_TYPE_NONE; 55 + } 56 + 57 + /* 58 + * Request notifications for changes on a filesystem path. 59 + * This creates a new pathwatch node and sets it to post notifications for 60 + * the specified name. 61 + * 62 + * If the notify name already has a pathwatch node for this path, this routine 63 + * does nothing and allows the client to piggypack on the existing path watcher. 64 + * 65 + * Note that this routine is only called for path monitoring as directed by 66 + * a "monitor" command in /etc/notify.conf, so only an admin can set up a path 67 + * that gets public notifications. A client being serviced by the server-side 68 + * routines in notify_proc.c will only be able to register for a private 69 + * (per-client) notification for a path. This prevents a client from 70 + * piggybacking on another client's notifications, and thus prevents the client 71 + * from getting notifications for a path to which they don't have access. 72 + */ 73 + int 74 + service_open_path(const char *name, const char *path, uid_t uid, gid_t gid) 75 + { 76 + name_info_t *n; 77 + svc_info_t *info; 78 + path_node_t *node; 79 + 80 + call_statistics.service_path++; 81 + 82 + if (path == NULL) return NOTIFY_STATUS_INVALID_REQUEST; 83 + 84 + n = (name_info_t *)_nc_table_find(global.notify_state->name_table, name); 85 + if (n == NULL) return NOTIFY_STATUS_INVALID_NAME; 86 + 87 + if (n->private != NULL) 88 + { 89 + /* a notify key may only have one service associated with it */ 90 + info = (svc_info_t *)n->private; 91 + if (info->type != SERVICE_TYPE_PATH_PUBLIC) return NOTIFY_STATUS_INVALID_REQUEST; 92 + 93 + /* the client must be asking for the same path that is being monitored */ 94 + node = (path_node_t *)info->private; 95 + if (strcmp(path, node->path)) return NOTIFY_STATUS_INVALID_REQUEST; 96 + 97 + /* the name is already getting notifications for this path */ 98 + return NOTIFY_STATUS_OK; 99 + } 100 + 101 + node = path_node_create(path, uid, gid, PATH_NODE_ALL, dispatch_get_main_queue()); 102 + if (node == NULL) return NOTIFY_STATUS_FAILED; 103 + 104 + node->contextp = strdup(name); 105 + 106 + info = (svc_info_t *)calloc(1, sizeof(svc_info_t)); 107 + assert(info != NULL); 108 + 109 + info->type = SERVICE_TYPE_PATH_PUBLIC; 110 + info->private = node; 111 + n->private = info; 112 + 113 + dispatch_source_set_event_handler(node->src, ^{ 114 + dispatch_async(global.work_q, ^{ 115 + if (0 == dispatch_source_testcancel(node->src)) 116 + { 117 + daemon_post((const char *)node->contextp, uid, gid); 118 + } 119 + }); 120 + }); 121 + 122 + dispatch_resume(node->src); 123 + 124 + return NOTIFY_STATUS_OK; 125 + } 126 + 127 + /* 128 + * The private (per-client) path watch service. 129 + */ 130 + int 131 + service_open_path_private(const char *name, client_t *c, const char *path, uid_t uid, gid_t gid, uint32_t flags) 132 + { 133 + name_info_t *n; 134 + svc_info_t *info; 135 + path_node_t *node; 136 + 137 + call_statistics.service_path++; 138 + 139 + if (path == NULL) return NOTIFY_STATUS_INVALID_REQUEST; 140 + 141 + n = (name_info_t *)_nc_table_find(global.notify_state->name_table, name); 142 + if (n == NULL) return NOTIFY_STATUS_INVALID_NAME; 143 + if (c == NULL) return NOTIFY_STATUS_FAILED; 144 + 145 + if (c->private != NULL) 146 + { 147 + /* a client may only have one service */ 148 + info = (svc_info_t *)c->private; 149 + if (info->type != SERVICE_TYPE_PATH_PRIVATE) return NOTIFY_STATUS_INVALID_REQUEST; 150 + 151 + /* the client must be asking for the same path that is being monitored */ 152 + node = (path_node_t *)info->private; 153 + if (strcmp(path, node->path)) return NOTIFY_STATUS_INVALID_REQUEST; 154 + 155 + /* the client is already getting notifications for this path */ 156 + return NOTIFY_STATUS_OK; 157 + } 158 + 159 + if (flags == 0) flags = PATH_NODE_ALL; 160 + 161 + node = path_node_create(path, uid, gid, flags, dispatch_get_main_queue()); 162 + if (node == NULL) return NOTIFY_STATUS_FAILED; 163 + 164 + node->context64 = c->client_id; 165 + 166 + info = (svc_info_t *)calloc(1, sizeof(svc_info_t)); 167 + assert(info != NULL); 168 + 169 + info->type = SERVICE_TYPE_PATH_PRIVATE; 170 + info->private = node; 171 + c->private = info; 172 + 173 + dispatch_source_set_event_handler(node->src, ^{ 174 + dispatch_async(global.work_q, ^{ 175 + if (0 == dispatch_source_testcancel(node->src)) 176 + { 177 + daemon_post_client(node->context64); 178 + } 179 + }); 180 + }); 181 + 182 + dispatch_resume(node->src); 183 + 184 + return NOTIFY_STATUS_OK; 185 + } 186 + 187 + /* format: [+]nnnn[s|m|h|d] */ 188 + static int 189 + parse_single_arg(const char *arg, int relative_ok, time_t *t) 190 + { 191 + const char *p, *q; 192 + time_t now, val; 193 + 194 + if (arg == NULL) return -1; 195 + p = arg; 196 + 197 + now = 0; 198 + 199 + if ((relative_ok != 0) && ((*p == '+') || (*p == '-'))) 200 + { 201 + p++; 202 + now = time(NULL); 203 + } 204 + 205 + if ((*p < '0') || (*p > '9')) return -1; 206 + 207 + q = strchr(p, '.'); 208 + if (q != NULL) q--; 209 + else q = arg + strlen(arg) - 1; 210 + 211 + #ifdef __LP64__ 212 + val = (time_t)atoll(p); 213 + #else 214 + val = (time_t)atoi(p); 215 + #endif 216 + 217 + if ((*q >= '0') && (*q <= '9')) 218 + {} 219 + else if (*q == 's') 220 + {} 221 + else if (*q == 'm') 222 + { 223 + val *= 60; 224 + } 225 + else if (*q == 'h') 226 + { 227 + val *= 3600; 228 + } 229 + else if (*q == 'd') 230 + { 231 + val *= 86400; 232 + } 233 + else 234 + { 235 + return -1; 236 + } 237 + 238 + if (*arg == '-') *t = now - val; 239 + else *t = now + val; 240 + 241 + return 0; 242 + } 243 + 244 + static uint32_t 245 + parse_timer_args(const char *args, time_t *s, time_t *f, time_t *e, int32_t *d) 246 + { 247 + char *p; 248 + uint32_t t; 249 + 250 + if (args == NULL) return TIME_EVENT_NONE; 251 + 252 + /* first arg is start time */ 253 + if (parse_single_arg(args, 1, s) != 0) return TIME_EVENT_NONE; 254 + t = TIME_EVENT_ONESHOT; 255 + 256 + p = strchr(args, '.'); 257 + if (p != NULL) 258 + { 259 + /* second arg is frequency */ 260 + p++; 261 + if (parse_single_arg(p, 0, f) != 0) return TIME_EVENT_NONE; 262 + t = TIME_EVENT_CLOCK; 263 + 264 + p = strchr(p, '.'); 265 + if (p != NULL) 266 + { 267 + /* third arg is end time */ 268 + p++; 269 + if (parse_single_arg(args, 1, e) != 0) return TIME_EVENT_NONE; 270 + 271 + p = strchr(p, '.'); 272 + if (p != NULL) 273 + { 274 + /* fourth arg is day number */ 275 + p++; 276 + *d = atoi(p); 277 + t = TIME_EVENT_CAL; 278 + } 279 + } 280 + } 281 + 282 + if (f == 0) t = TIME_EVENT_ONESHOT; 283 + 284 + return t; 285 + } 286 + 287 + int 288 + service_open_timer(const char *name, const char *args) 289 + { 290 + uint32_t t; 291 + time_t s, f, e; 292 + int32_t d; 293 + name_info_t *n; 294 + svc_info_t *info; 295 + timer_t *timer; 296 + 297 + call_statistics.service_timer++; 298 + 299 + n = (name_info_t *)_nc_table_find(global.notify_state->name_table, name); 300 + if (n == NULL) return NOTIFY_STATUS_INVALID_NAME; 301 + 302 + s = f = e = 0; 303 + d = 0; 304 + 305 + t = parse_timer_args(args, &s, &f, &e, &d); 306 + if (t == TIME_EVENT_NONE) return NOTIFY_STATUS_INVALID_REQUEST; 307 + 308 + if (n->private != NULL) 309 + { 310 + /* a notify key may only have one service associated with it */ 311 + info = (svc_info_t *)n->private; 312 + if (info->type != SERVICE_TYPE_TIMER_PUBLIC) return NOTIFY_STATUS_INVALID_REQUEST; 313 + 314 + /* the client must be asking for the same timer that is active */ 315 + timer = (timer_t *)info->private; 316 + if ((timer->type != t) || (timer->start != s) || (timer->freq != f) || (timer->end != e) || (timer->day != d)) return NOTIFY_STATUS_INVALID_REQUEST; 317 + 318 + /* the name is already getting notifications for this timer */ 319 + return NOTIFY_STATUS_OK; 320 + } 321 + 322 + switch (t) 323 + { 324 + case TIME_EVENT_ONESHOT: 325 + { 326 + timer = timer_oneshot(s, dispatch_get_main_queue()); 327 + break; 328 + } 329 + case TIME_EVENT_CLOCK: 330 + { 331 + timer = timer_clock(s, f, e, dispatch_get_main_queue()); 332 + break; 333 + } 334 + case TIME_EVENT_CAL: 335 + { 336 + timer = timer_calendar(s, f, d, e, dispatch_get_main_queue()); 337 + break; 338 + } 339 + default: 340 + { 341 + return NOTIFY_STATUS_FAILED; 342 + } 343 + } 344 + 345 + if (timer == NULL) return NOTIFY_STATUS_FAILED; 346 + timer->contextp = strdup(name); 347 + 348 + info = (svc_info_t *)calloc(1, sizeof(svc_info_t)); 349 + assert(info != NULL); 350 + 351 + info->type = SERVICE_TYPE_TIMER_PUBLIC; 352 + info->private = timer; 353 + n->private = info; 354 + 355 + dispatch_source_set_event_handler(timer->src, ^{ 356 + dispatch_async(global.work_q, ^{ 357 + if (0 == dispatch_source_testcancel(timer->src)) 358 + { 359 + daemon_post((const char *)timer->contextp, 0, 0); 360 + } 361 + }); 362 + }); 363 + 364 + dispatch_resume(timer->src); 365 + 366 + return NOTIFY_STATUS_OK; 367 + } 368 + 369 + int 370 + service_open_timer_private(const char *name, client_t *c, const char *args) 371 + { 372 + uint32_t t; 373 + time_t s, f, e; 374 + int32_t d; 375 + name_info_t *n; 376 + svc_info_t *info; 377 + timer_t *timer; 378 + 379 + call_statistics.service_timer++; 380 + 381 + n = (name_info_t *)_nc_table_find(global.notify_state->name_table, name); 382 + if (n == NULL) return NOTIFY_STATUS_INVALID_NAME; 383 + if (c == NULL) return NOTIFY_STATUS_FAILED; 384 + 385 + s = f = e = 0; 386 + d = 0; 387 + 388 + t = parse_timer_args(args, &s, &f, &e, &d); 389 + if (t == TIME_EVENT_NONE) return NOTIFY_STATUS_INVALID_REQUEST; 390 + 391 + if (c->private != NULL) 392 + { 393 + /* a client may only have one service */ 394 + info = (svc_info_t *)c->private; 395 + if (info->type != SERVICE_TYPE_TIMER_PRIVATE) return NOTIFY_STATUS_INVALID_REQUEST; 396 + 397 + /* the client must be asking for the same timer that is active */ 398 + timer = (timer_t *)info->private; 399 + if ((timer->type != t) || (timer->start != s) || (timer->freq != f) || (timer->end != e) || (timer->day != d)) return NOTIFY_STATUS_INVALID_REQUEST; 400 + 401 + /* the client is already getting notifications for this timer */ 402 + return NOTIFY_STATUS_OK; 403 + } 404 + 405 + switch (t) 406 + { 407 + case TIME_EVENT_ONESHOT: 408 + { 409 + timer = timer_oneshot(s, dispatch_get_main_queue()); 410 + break; 411 + } 412 + case TIME_EVENT_CLOCK: 413 + { 414 + timer = timer_clock(s, f, e, dispatch_get_main_queue()); 415 + break; 416 + } 417 + case TIME_EVENT_CAL: 418 + { 419 + timer = timer_calendar(s, f, d, e, dispatch_get_main_queue()); 420 + break; 421 + } 422 + default: 423 + { 424 + return NOTIFY_STATUS_FAILED; 425 + } 426 + } 427 + 428 + if (timer == NULL) return NOTIFY_STATUS_FAILED; 429 + timer->context64 = c->client_id; 430 + 431 + info = (svc_info_t *)calloc(1, sizeof(svc_info_t)); 432 + assert(info != NULL); 433 + 434 + info->type = SERVICE_TYPE_TIMER_PRIVATE; 435 + info->private = timer; 436 + c->private = info; 437 + 438 + dispatch_source_set_event_handler(timer->src, ^{ 439 + dispatch_async(global.work_q, ^{ 440 + if (0 == dispatch_source_testcancel(timer->src)) 441 + { 442 + daemon_post_client(timer->context64); 443 + } 444 + }); 445 + }); 446 + 447 + dispatch_resume(timer->src); 448 + 449 + return NOTIFY_STATUS_OK; 450 + } 451 + 452 + /* called from server-side routines in notify_proc - services are private to the client */ 453 + int 454 + service_open(const char *name, client_t *client, uint32_t uid, uint32_t gid) 455 + { 456 + uint32_t t, flags; 457 + char *p, *q; 458 + 459 + t = service_type(name); 460 + 461 + switch (t) 462 + { 463 + case SERVICE_TYPE_NONE: 464 + { 465 + return NOTIFY_STATUS_OK; 466 + } 467 + case SERVICE_TYPE_PATH_PRIVATE: 468 + { 469 + p = strchr(name, ':'); 470 + if (p != NULL) p++; 471 + 472 + flags = 0; 473 + 474 + q = strchr(p, ':'); 475 + if (q != NULL) 476 + { 477 + flags = strtol(p, NULL, 0); 478 + p = q + 1; 479 + } 480 + 481 + return service_open_path_private(name, client, p, uid, gid, flags); 482 + } 483 + case SERVICE_TYPE_TIMER_PRIVATE: 484 + { 485 + p = strchr(name, ':'); 486 + if (p != NULL) p++; 487 + return service_open_timer_private(name, client, p); 488 + } 489 + default: 490 + { 491 + return NOTIFY_STATUS_INVALID_REQUEST; 492 + } 493 + } 494 + 495 + return NOTIFY_STATUS_INVALID_REQUEST; 496 + } 497 + 498 + void 499 + service_close(svc_info_t *info) 500 + { 501 + if (info == NULL) return; 502 + 503 + switch (info->type) 504 + { 505 + case SERVICE_TYPE_PATH_PUBLIC: 506 + case SERVICE_TYPE_PATH_PRIVATE: 507 + { 508 + path_node_close((path_node_t *)info->private); 509 + break; 510 + } 511 + case SERVICE_TYPE_TIMER_PUBLIC: 512 + case SERVICE_TYPE_TIMER_PRIVATE: 513 + { 514 + timer_close((timer_t *)info->private); 515 + break; 516 + } 517 + default: 518 + { 519 + } 520 + } 521 + 522 + free(info); 523 + }
+49
libnotify/notifyd/service.h
··· 1 + /* 2 + * Copyright (c) 2003-2010 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #ifndef _NOTIFY_SERVICE_H_ 25 + #define _NOTIFY_SERVICE_H_ 26 + 27 + #define SERVICE_TYPE_NONE 0 28 + #define SERVICE_TYPE_PATH_PUBLIC 1 29 + #define SERVICE_TYPE_PATH_PRIVATE 2 30 + #define SERVICE_TYPE_TIMER_PUBLIC 3 31 + #define SERVICE_TYPE_TIMER_PRIVATE 4 32 + 33 + #define SERVICE_PREFIX "com.apple.system.notify.service." 34 + #define SERVICE_PREFIX_LEN 32 35 + 36 + typedef struct 37 + { 38 + uint32_t type; 39 + void *private; 40 + } svc_info_t; 41 + 42 + int service_open(const char *name, client_t *client, uint32_t uid, uint32_t gid); 43 + int service_open_path(const char *name, const char *path, uid_t uid, gid_t gid); 44 + int service_open_path_private(const char *name, client_t *client, const char *path, uid_t uid, gid_t gid, uint32_t flags); 45 + int service_open_timer(const char *name, const char *args); 46 + int service_open_timer_private(const char *name, client_t *client, const char *args); 47 + void service_close(svc_info_t *info); 48 + 49 + #endif /* _NOTIFY_SERVICE_H_ */
+86
libnotify/notifyd/table.h
··· 1 + /* 2 + * Copyright (c) 2003-2011 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #ifndef _NOTIFY_TABLE_H_ 25 + #define _NOTIFY_TABLE_H_ 26 + 27 + #include <stdint.h> 28 + 29 + typedef struct __table_private table_t; 30 + typedef struct __list_private list_t; 31 + 32 + extern table_t *_nc_table_new(uint32_t n); 33 + 34 + extern void _nc_table_insert(table_t *t, const char *key, void *datum); 35 + extern void _nc_table_insert_no_copy(table_t *t, const char *key, void *datum); 36 + extern void _nc_table_insert_n(table_t *t, uint32_t key, void *datum); 37 + extern void _nc_table_insert_64(table_t *t, uint64_t key, void *datum); 38 + 39 + extern void *_nc_table_find(table_t *t, const char *key); 40 + extern void *_nc_table_find_n(table_t *t, uint32_t key); 41 + extern void *_nc_table_find_64(table_t *t, uint64_t key); 42 + 43 + extern void _nc_table_delete(table_t *t, const char *key); 44 + extern void _nc_table_delete_n(table_t *t, uint32_t key); 45 + extern void _nc_table_delete_64(table_t *t, uint64_t key); 46 + 47 + extern void *_nc_table_traverse_start(table_t *tin); 48 + extern void *_nc_table_traverse(table_t *tin, void *ttin); 49 + extern void _nc_table_traverse_end(table_t *tin, void *ttin); 50 + 51 + extern void _nc_table_free(table_t *tin); 52 + 53 + extern list_t *_nc_list_new(void *d); 54 + 55 + extern list_t *_nc_list_retain(list_t *l); 56 + extern list_t *_nc_list_retain_list(list_t *l); 57 + 58 + extern void _nc_list_release(list_t *l); 59 + extern void _nc_list_release_list(list_t *l); 60 + 61 + extern list_t *_nc_list_prev(list_t *l); 62 + extern list_t *_nc_list_next(list_t *l); 63 + 64 + extern void _nc_list_set_next(list_t *l, list_t *n); 65 + extern void _nc_list_set_prev(list_t *l, list_t *p); 66 + 67 + extern list_t *_nc_list_head(list_t *l); 68 + extern list_t *_nc_list_tail(list_t *l); 69 + 70 + extern list_t *_nc_list_prepend(list_t *l, list_t *n); 71 + extern list_t *_nc_list_append(list_t *l, list_t *n); 72 + 73 + extern list_t *_nc_list_concat(list_t *a, list_t *b); 74 + 75 + extern void *_nc_list_data(list_t *l); 76 + extern void _nc_list_set_data(list_t *l, void *d); 77 + 78 + extern list_t *_nc_list_find(list_t *l, void *d); 79 + extern list_t *_nc_list_find_release(list_t *l, void *d); 80 + 81 + extern list_t * _nc_list_reverse(list_t *l); 82 + extern uint32_t _nc_list_count(list_t *l); 83 + extern list_t *_nc_list_extract(list_t *n); 84 + extern list_t *_nc_list_chop(list_t *l); 85 + 86 + #endif /* _NOTIFY_TABLE_H_ */
+465
libnotify/notifyd/timer.c
··· 1 + /* 2 + * Copyright (c) 2009-2010 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #include <stdlib.h> 25 + #include <string.h> 26 + #include <Block.h> 27 + #include "timer.h" 28 + 29 + #define MINUTE 60 30 + #define HOUR 3600 31 + #define DAY 86400 32 + 33 + static const uint8_t mlen[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 34 + 35 + /* 36 + * Timed events 37 + * 38 + * Supported event types: 39 + * 40 + * Oneshot 41 + * Every n seconds/minutes/hours/days/weeks 42 + * Specific day of the month, every n months 43 + * Specific weekday following specific day of the month, every n months 44 + * 45 + */ 46 + static time_t 47 + timer_next(timer_t *t, time_t now) 48 + { 49 + uint32_t y, m; 50 + int32_t d, x, a, b, dd, wd; 51 + struct tm tmp; 52 + time_t next, tt, tod; 53 + 54 + if (t == NULL) return 0; 55 + 56 + switch (t->type) 57 + { 58 + case TIME_EVENT_ONESHOT: 59 + { 60 + /* 61 + * oneshot time event 62 + */ 63 + if (t->start < now) return 0; 64 + return t->start; 65 + } 66 + case TIME_EVENT_CLOCK: 67 + { 68 + /* 69 + * event recurs every t->freq seconds 70 + */ 71 + 72 + /* t->end is the cut-off. If it's in the past, return 0 */ 73 + if ((t->end != 0) && (t->end < now)) return 0; 74 + 75 + /* If the start time is in the future, that's the next occurrence */ 76 + if (t->start >= now) return t->start; 77 + 78 + /* shouldn't happen, as TIME_EVENT_CLOCK should always recur */ 79 + if (t->freq == 0) return 0; 80 + 81 + x = ((t->freq - 1) + now - t->start) / t->freq; 82 + next = t->start + (x * t->freq); 83 + return next; 84 + } 85 + case TIME_EVENT_CAL: 86 + { 87 + /* 88 + * event recurs every t->freq months 89 + * t->base gives us the starting month and year, and the time of day 90 + * t->day specifies the day of the month (negative means relative to last day of the month) 91 + * t->day is > 100 or < 100, then it means a weekday 92 + * 101 = first monday, 102 = first tuesday, ..., 108 = second monday, and so on 93 + * -101 = last monday, -102 = last tuesday, ..., -108 = second last monday, and so on 94 + */ 95 + 96 + /* t->end is the cut-off. If it's in the past, return 0 */ 97 + if ((t->end != 0) && (t->end < now)) return 0; 98 + 99 + /* If the start time is in the future, that's the next occurrence */ 100 + if (t->start >= now) return t->start; 101 + 102 + next = t->start; 103 + 104 + /* If t->next is set from the last time we ran, and it is in the past, we can start there. */ 105 + if ((t->next > 0) && (t->next < now)) next = t->next; 106 + 107 + while (next < now) 108 + { 109 + /* determine year, month, and time-of-day (clock time) of the next occurance */ 110 + memset(&tmp, 0, sizeof(struct tm)); 111 + localtime_r((const time_t *)&(next), &tmp); 112 + y = tmp.tm_year; 113 + m = tmp.tm_mon; 114 + tod = tmp.tm_sec + (MINUTE * tmp.tm_min) + (HOUR * tmp.tm_hour); 115 + 116 + m += t->freq; 117 + if (m > 11) 118 + { 119 + y += (m / 12); 120 + m %= 12; 121 + } 122 + 123 + /* we now have a year (y), a month (m), and a time of day (tod) */ 124 + 125 + if (t->day > 0) 126 + { 127 + if (t->day < 100) 128 + { 129 + /* easy case: day is the date of the month */ 130 + 131 + memset(&tmp, 0, sizeof(struct tm)); 132 + tmp.tm_year = y; 133 + tmp.tm_mon = m; 134 + tmp.tm_mday = t->day; 135 + tmp.tm_isdst = -1; 136 + next = mktime(&tmp) + tod; 137 + continue; 138 + } 139 + else 140 + { 141 + /* t->day is a weekday */ 142 + 143 + wd = t->day - 100; 144 + 145 + /* start by finding out the weekday of the first of the month */ 146 + memset(&tmp, 0, sizeof(struct tm)); 147 + tmp.tm_year = y; 148 + tmp.tm_mon = m; 149 + tmp.tm_mday = 1; 150 + tmp.tm_isdst = -1; 151 + tt = mktime(&tmp); 152 + localtime_r((const time_t *)&tt, &tmp); 153 + 154 + if (tmp.tm_wday == 0) tmp.tm_wday = 7; 155 + 156 + x = 0; 157 + if (tmp.tm_wday > (wd % 7)) x = (wd + 7) - tmp.tm_wday; 158 + else x = wd - tmp.tm_wday; 159 + 160 + tmp.tm_mday += x; 161 + tmp.tm_isdst = -1; 162 + next = mktime(&tmp) + tod; 163 + continue; 164 + } 165 + } 166 + 167 + if (t->day > -100) 168 + { 169 + /* nth day from the end of the month */ 170 + if (m == 1) 171 + { 172 + /* determine weekday of last day of February (== March 0) */ 173 + memset(&tmp, 0, sizeof(struct tm)); 174 + tmp.tm_year = y; 175 + tmp.tm_mon = 2; 176 + tmp.tm_mday = 0; 177 + tmp.tm_isdst = -1; 178 + tt = mktime(&tmp); 179 + memset(&tmp, 0, sizeof(struct tm)); 180 + localtime_r((const time_t *)&(tt), &tmp); 181 + d = tmp.tm_mday + t->day; 182 + } 183 + else 184 + { 185 + d = mlen[m] + t->day; 186 + } 187 + 188 + memset(&tmp, 0, sizeof(struct tm)); 189 + tmp.tm_year = y; 190 + tmp.tm_mon = m; 191 + tmp.tm_mday = d; 192 + tmp.tm_isdst = -1; 193 + next = mktime(&tmp) + tod; 194 + continue; 195 + } 196 + 197 + /* t->day is a weekday relative to the end of the month */ 198 + if (m == 1) 199 + { 200 + /* determine weekday of last day of February (== March 0) */ 201 + memset(&tmp, 0, sizeof(struct tm)); 202 + tmp.tm_year = y; 203 + tmp.tm_mon = 2; 204 + tmp.tm_mday = 0; 205 + tmp.tm_isdst = -1; 206 + tt = mktime(&tmp); 207 + memset(&tmp, 0, sizeof(struct tm)); 208 + localtime_r((const time_t *)&(tt), &tmp); 209 + d = tmp.tm_mday; 210 + } 211 + else 212 + { 213 + d = mlen[m]; 214 + } 215 + 216 + memset(&tmp, 0, sizeof(struct tm)); 217 + tmp.tm_year = y; 218 + tmp.tm_mon = m; 219 + tmp.tm_mday = d; 220 + tmp.tm_isdst = -1; 221 + 222 + dd = -1 * (t->day + 100); 223 + a = dd % 7; 224 + b = (dd + 6) / 7; 225 + if (a <= tmp.tm_wday) b--; 226 + tmp.tm_mday = ((a - tmp.tm_wday) + d) - (b * 7); 227 + next = mktime(&tmp) + tod; 228 + } 229 + 230 + t->next = next; 231 + return next; 232 + } 233 + default: 234 + { 235 + return 0; 236 + } 237 + } 238 + 239 + return 0; 240 + } 241 + 242 + /* 243 + * This does the actual free. 244 + * It is dispatched on the timer's dispatch source queue to make it safe. 245 + */ 246 + static void 247 + timer_free(timer_t *t) 248 + { 249 + if (t == NULL) return; 250 + if (t->deactivation_handler != NULL) Block_release(t->deactivation_handler); 251 + if (t->contextp != NULL) free(t->contextp); 252 + 253 + dispatch_release(t->t_src); 254 + dispatch_release(t->t_queue); 255 + 256 + memset(t, 0, sizeof(timer_t)); 257 + free(t); 258 + } 259 + 260 + void 261 + timer_close(timer_t *t) 262 + { 263 + if (t == NULL) return; 264 + 265 + if (t->t_src != NULL) dispatch_source_cancel(t->t_src); 266 + 267 + /* 268 + * We need to make sure that the source's event handler isn't currently running 269 + * before we free the timer. We let the source's queue do the actual free. 270 + */ 271 + dispatch_async(t->t_queue, ^{ timer_free(t); }); 272 + } 273 + 274 + timer_t * 275 + timer_oneshot(time_t when, dispatch_queue_t queue) 276 + { 277 + timer_t *t; 278 + time_t now; 279 + dispatch_time_t trigger; 280 + 281 + /* refuse a trigger time in the past */ 282 + now = time(0); 283 + if (when <= now) return NULL; 284 + 285 + t = calloc(1, sizeof(timer_t)); 286 + if (t == NULL) return NULL; 287 + 288 + dispatch_retain(queue); 289 + 290 + t->type = TIME_EVENT_ONESHOT; 291 + t->start = when; 292 + t->t_queue = queue; 293 + 294 + t->t_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); 295 + t->src = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue); 296 + 297 + trigger = dispatch_walltime(NULL, (t->start - now) * NSEC_PER_SEC); 298 + dispatch_source_set_timer(t->t_src, trigger, NSEC_PER_SEC, 0); 299 + 300 + dispatch_source_set_event_handler(t->t_src, ^{ 301 + dispatch_source_merge_data(t->src, 1); 302 + dispatch_source_cancel(t->t_src); 303 + if (t->deactivation_handler != NULL) 304 + { 305 + dispatch_async(t->t_queue, ^{ t->deactivation_handler(); }); 306 + } 307 + }); 308 + 309 + dispatch_resume(t->t_src); 310 + return t; 311 + } 312 + 313 + void 314 + timer_set_deactivation_handler(timer_t *t, void(^handler)()) 315 + { 316 + if (t == NULL) return; 317 + 318 + if (t->deactivation_handler != NULL) Block_release(t->deactivation_handler); 319 + t->deactivation_handler = Block_copy(handler); 320 + } 321 + 322 + timer_t * 323 + timer_clock(time_t first, time_t freq_sec, time_t end, dispatch_queue_t queue) 324 + { 325 + timer_t *t; 326 + time_t now; 327 + dispatch_time_t trigger; 328 + int64_t x; 329 + 330 + if (freq_sec == 0) return timer_oneshot(first, queue); 331 + 332 + now = time(0); 333 + 334 + t = calloc(1, sizeof(timer_t)); 335 + if (t == NULL) return NULL; 336 + 337 + t->type = TIME_EVENT_CLOCK; 338 + 339 + if (first < now) 340 + { 341 + x = ((freq_sec - 1) + now - first) / freq_sec; 342 + t->start = first + (x * freq_sec); 343 + } 344 + else 345 + { 346 + t->start = first; 347 + } 348 + 349 + t->end = end; 350 + t->freq = freq_sec; 351 + t->t_queue = queue; 352 + 353 + t->t_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); 354 + t->src = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue); 355 + 356 + trigger = dispatch_walltime(NULL, (t->start - now) * NSEC_PER_SEC); 357 + dispatch_source_set_timer(t->t_src, trigger, freq_sec * NSEC_PER_SEC, 0); 358 + 359 + dispatch_source_set_event_handler(t->t_src, ^{ 360 + unsigned long n = dispatch_source_get_data(t->t_src); 361 + dispatch_source_merge_data(t->src, n); 362 + 363 + /* deactivate if this is the last time we want to trigger the client source */ 364 + if ((t->end > 0) && (t->end < (time(0) + freq_sec))) 365 + { 366 + dispatch_source_cancel(t->t_src); 367 + if (t->deactivation_handler != NULL) 368 + { 369 + dispatch_async(t->t_queue, ^{ t->deactivation_handler(); }); 370 + } 371 + } 372 + }); 373 + 374 + dispatch_resume(t->t_src); 375 + 376 + return t; 377 + } 378 + 379 + timer_t * 380 + timer_calendar(time_t first, time_t freq_mth, time_t end, int day, dispatch_queue_t queue) 381 + { 382 + timer_t *t; 383 + time_t next, now; 384 + dispatch_time_t trigger; 385 + 386 + if (freq_mth == 0) return timer_oneshot(first, queue); 387 + 388 + now = time(0); 389 + 390 + t = calloc(1, sizeof(timer_t)); 391 + if (t == NULL) return NULL; 392 + 393 + t->type = TIME_EVENT_CAL; 394 + t->start = first; 395 + t->day = day; 396 + t->end = end; 397 + t->freq = freq_mth; 398 + t->t_queue = queue; 399 + 400 + t->t_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); 401 + t->src = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue); 402 + 403 + next = timer_next(t, now); 404 + trigger = dispatch_walltime(NULL, (next - now) * NSEC_PER_SEC); 405 + dispatch_source_set_timer(t->t_src, trigger, NSEC_PER_SEC, 0); 406 + 407 + dispatch_source_set_event_handler(t->t_src, ^{ 408 + unsigned long n = dispatch_source_get_data(t->t_src); 409 + dispatch_source_merge_data(t->src, n); 410 + 411 + time_t now = time(0); 412 + time_t x = timer_next(t, now); 413 + 414 + /* deactivate when there is no next time */ 415 + if (x == 0) 416 + { 417 + dispatch_source_cancel(t->t_src); 418 + if (t->deactivation_handler != NULL) 419 + { 420 + dispatch_async(t->t_queue, ^{ t->deactivation_handler(); }); 421 + } 422 + } 423 + else 424 + { 425 + dispatch_source_set_timer(t->t_src, dispatch_walltime(NULL, (x - now) * NSEC_PER_SEC), NSEC_PER_SEC, 0); 426 + } 427 + }); 428 + 429 + dispatch_resume(t->t_src); 430 + 431 + return t; 432 + } 433 + 434 + timer_t * 435 + timer_calendar_long(uint32_t start_year, uint32_t start_month, uint32_t start_day, uint32_t start_hour, uint32_t start_min, uint32_t start_sec, time_t freq, int day, uint32_t end_year, uint32_t end_month, uint32_t end_day, uint32_t end_hour, uint32_t end_min, uint32_t end_sec, dispatch_queue_t queue) 436 + { 437 + struct tm tmp; 438 + time_t first, last; 439 + 440 + memset(&tmp, 0, sizeof(struct tm)); 441 + tmp.tm_year = start_year - 1900; 442 + tmp.tm_mon = start_month; 443 + tmp.tm_mday = start_day; 444 + tmp.tm_isdst = -1; 445 + tmp.tm_hour = start_hour; 446 + tmp.tm_min = start_min; 447 + tmp.tm_sec = start_sec; 448 + 449 + first = mktime(&tmp); 450 + 451 + if (freq == 0) return timer_oneshot(first, queue); 452 + 453 + memset(&tmp, 0, sizeof(struct tm)); 454 + tmp.tm_year = end_year; 455 + tmp.tm_mon = end_month; 456 + tmp.tm_mday = end_day; 457 + tmp.tm_isdst = -1; 458 + tmp.tm_hour = end_hour; 459 + tmp.tm_min = end_min; 460 + tmp.tm_sec = end_sec; 461 + 462 + last = mktime(&tmp); 463 + 464 + return timer_calendar(first, freq, day, last, queue); 465 + }
+59
libnotify/notifyd/timer.h
··· 1 + /* 2 + * Copyright (c) 2009-2010 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #include <time.h> 25 + #include <stdint.h> 26 + #include <dispatch/dispatch.h> 27 + 28 + #define TIME_EVENT_NONE 0 29 + #define TIME_EVENT_ONESHOT 1 30 + #define TIME_EVENT_CLOCK 2 31 + #define TIME_EVENT_CAL 3 32 + 33 + /* 34 + * Timer Event 35 + */ 36 + typedef struct 37 + { 38 + uint32_t type; 39 + int64_t start; 40 + int64_t end; 41 + uint32_t freq; 42 + int32_t day; 43 + int64_t next; 44 + void (^deactivation_handler)(); 45 + dispatch_source_t src; 46 + dispatch_source_t t_src; 47 + dispatch_queue_t t_queue; 48 + void *contextp; 49 + uint32_t context32; 50 + uint64_t context64; 51 + } timer_t; 52 + 53 + timer_t *timer_oneshot(time_t when, dispatch_queue_t queue); 54 + timer_t *timer_clock(time_t first, time_t freq_sec, time_t end, dispatch_queue_t queue); 55 + timer_t *timer_calendar(time_t first, time_t freq_mth, time_t end, int day, dispatch_queue_t queue); 56 + timer_t *timer_calendar_long(uint32_t yf, uint32_t mf, uint32_t df, uint32_t hf, uint32_t nf, uint32_t sf, time_t fm, int d, uint32_t ye, uint32_t me, uint32_t de, uint32_t he, uint32_t ne, uint32_t se, dispatch_queue_t queue); 57 + 58 + void timer_set_deactivation_handler(timer_t *t, void(^handler)()); 59 + void timer_close(timer_t *t);
+6
libnotify/notifyd/xcodescripts/mk_notify_conf.sh
··· 1 + set -e -x 2 + ETCDIR="$DSTROOT$INSTALL_PATH_PREFIX"/private/etc 3 + install -d -o root -g wheel -m 0755 "$ETCDIR" 4 + install -c -o root -g wheel -m 0644 \ 5 + "$SRCROOT"/notifyd/"$NOTIFY_CONFIG" \ 6 + "$ETCDIR"/notify.conf
+220
libnotify/notifyutil/notifyutil.1
··· 1 + .\" Copyright (c) 2006-2011 Apple Inc. All rights reserved. 2 + .\" 3 + .\" @APPLE_LICENSE_HEADER_START@ 4 + .\" 5 + .\" This file contains Original Code and/or Modifications of Original Code 6 + .\" as defined in and that are subject to the Apple Public Source License 7 + .\" Version 2.0 (the 'License'). You may not use this file except in 8 + .\" compliance with the License. Please obtain a copy of the License at 9 + .\" http://www.opensource.apple.com/apsl/ and read it before using this 10 + .\" file. 11 + .\" 12 + .\" The Original Code and all software distributed under the License are 13 + .\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 + .\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 + .\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 + .\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 17 + .\" Please see the License for the specific language governing rights and 18 + .\" limitations under the License. 19 + .\" 20 + .\" @APPLE_LICENSE_HEADER_END@ 21 + .\" 22 + .\" 23 + .Dd November 4, 2011 24 + .Dt notifyutil 1 25 + .Os "Mac OS X" 26 + .Sh NAME 27 + .Nm notifyutil 28 + .Nd notification command line utility 29 + .Sh SYNOPSIS 30 + .Nm 31 + .Op Fl q 32 + .Op Fl v 33 + .Op Fl z Ar msec 34 + .Op Fl M 35 + .Op Fl R 36 + .Op command Li ... 37 + .Pp 38 + .Sh DESCRIPTION 39 + .Nm 40 + is a command-line utility for interacting with the 41 + .Xr notify 3 42 + notification system and the 43 + .Xr notifyd 8 44 + server. 45 + It may be used to post notifications, detect and report notifications, 46 + and to examine and set the state values associated with notification keys. 47 + .Pp 48 + If 49 + .Nm 50 + is used to monitor one or more notification keys, 51 + it prints the notification key when the corresponding notification is received. 52 + The 53 + .Fl v 54 + (verbose) 55 + and 56 + .Fl q 57 + (quiet) flags, if specified, modify the output behavior. 58 + .Pp 59 + The 60 + .Fl v 61 + flag causes 62 + .Nm 63 + to print a time stamp, the notification key, the current state value for that key, 64 + and the type of the notification (port, file, etc). 65 + The 66 + .Fl q 67 + flag supresses any output except for state values fetched following a 68 + .Fl g 69 + command. 70 + .Pp 71 + Commands listed in the table below are processed in left to right order from the command line. 72 + .Pp 73 + .Bl -tag -width "-signal [#]" -compact -offset indent 74 + .It Fl p Ar key 75 + Post a notification for 76 + .Ar key . 77 + .It Fl w Ar key 78 + Register for 79 + .Ar key 80 + and wait forever for notifications. 81 + .It Fl Ar # Ar key 82 + Register for 83 + .Ar key 84 + and wait for 85 + .Ar # 86 + (an integer) notifications. 87 + .It "" 88 + .Li E.g. 89 + .Fl 1 Ar key 90 + waits for a single notification. 91 + .It Fl g Ar key 92 + Get state value for 93 + .Ar key . 94 + .It Fl s Ar key Ar val 95 + Set state value for 96 + .Ar key . 97 + .It Fl port 98 + Use mach port notifications for subsequent 99 + .Fl w 100 + or 101 + .Fl Ar # 102 + registrations. 103 + .It "" 104 + This is the default registration type. 105 + .It Fl file 106 + Use file descriptor notifications for subsequent registrations. 107 + .It Fl check 108 + Use shared memory notifications for subsequent registrations. 109 + .It Fl signal Op Ar # 110 + Use signal notifications for subsequent registrations. 111 + .It "" 112 + Signal 1 (HUP) is the default, but an alternate signal may be specified. 113 + .It Fl dispatch 114 + Use dispatch for subsequent registrations. 115 + .El 116 + .Pp 117 + When invoked with any combination of 118 + .Fl w 119 + and 120 + .Fl Ar # 121 + actions, 122 + .Nm 123 + registers for notification for the specified key(s). 124 + If any key is given with a 125 + .Fl w 126 + action, 127 + .Nm 128 + runs until interrupted with Control-C. 129 + If all registrations are invoked with 130 + .Fl Ar # , 131 + the program continues to run until the corresponding number of notifications for each key have been received. 132 + .Pp 133 + By default, 134 + .Nm 135 + uses mach port registration (using 136 + .Fn notify_register_mach_port ) 137 + for keys given with a 138 + .Fl w 139 + or 140 + .Fl Ar # 141 + flag. 142 + The 143 + .Fl file 144 + command causes 145 + .Nm 146 + to use 147 + .Fn notify_register_file_descriptor 148 + for any subsequent 149 + .Fl w 150 + or 151 + .Fl Ar # 152 + registrations. 153 + Similarly, 154 + .Fl check 155 + causes 156 + .Nm 157 + to use 158 + .Fn notify_register_check 159 + for subsequent registrations, 160 + .Fl signal 161 + switches to 162 + .Fn notify_register_signal , 163 + and 164 + .Fl dispatch 165 + causes it to use 166 + .Fn notify_register_dispatch 167 + for subsequent registrations. 168 + .Pp 169 + If any registrations are made following the use of the 170 + .Fl check 171 + command, 172 + .Nm 173 + will start a timer and check for shared memory notifications every 100 milliseconds. 174 + An alternate timer value may be set following the 175 + .Fl z 176 + flag. 177 + .Pp 178 + The 179 + .Fl M 180 + flag causes 181 + .Nm 182 + to use multiplex all notifications over a single mach connection with 183 + .Nm notifyd . 184 + Notifications (except shared memory notifications) 185 + are received and redistributed by a dispatch handler. 186 + .Pp 187 + The 188 + .Fl R 189 + flag causes 190 + .Nm notifyutil 191 + to regenerate all its registrations in the unlikely event that 192 + .Nm notifyd 193 + restarts. 194 + .Pp 195 + Note that a notification key and its associated state variable only exist 196 + when there are one or more current registrations for that key. 197 + Setting the state for a key that has no registrations has no effect. 198 + Thus the command 199 + .Pp 200 + .Dl notifyutil -s foo.bar 123 -g foo.bar 201 + .Pp 202 + will print 203 + .Pp 204 + .Dl foo.bar 0 205 + .Pp 206 + unless foo.bar is registered by some other process. 207 + However, the command 208 + .Pp 209 + .Dl notifyutil -w foo.bar -s foo.bar 123 -g foo.bar 210 + .Pp 211 + prints 212 + .Pp 213 + .Dl foo.bar 123 214 + .Pp 215 + since the 216 + .Dq -w foo.bar 217 + registration ensures the key and its state variable exist before the value is set, 218 + and continue to exist when the value is fetched. 219 + .Sh SEE ALSO 220 + notify(3), notifyd(8)
+751
libnotify/notifyutil/notifyutil.c
··· 1 + /* 2 + * Copyright (c) 2006-2010 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #include <stdio.h> 25 + #include <stdint.h> 26 + #include <stdlib.h> 27 + #include <unistd.h> 28 + #include <string.h> 29 + #include <time.h> 30 + #include <sys/time.h> 31 + #include <mach/mach.h> 32 + #include <notify.h> 33 + #include <notify_private.h> 34 + #include <signal.h> 35 + #include <dispatch/dispatch.h> 36 + 37 + #define forever for(;;) 38 + #define IndexNull ((uint32_t)-1) 39 + 40 + #define PRINT_QUIET 0x00000000 41 + #define PRINT_KEY 0x00000001 42 + #define PRINT_STATE 0x00000002 43 + #define PRINT_TIME 0x00000004 44 + #define PRINT_TYPE 0x00000008 45 + #define PRINT_VERBOSE 0xffffffff 46 + 47 + #ifndef USEC_PER_SEC 48 + #define USEC_PER_SEC 1000000 49 + #endif 50 + 51 + #define TYPE_NULL 0 52 + #define TYPE_PORT 1 53 + #define TYPE_FILE 2 54 + #define TYPE_DISPATCH 3 55 + #define TYPE_SIGNAL 4 56 + #define TYPE_CHECK 5 57 + #define TYPE_PLAIN 6 58 + 59 + static const char *typename[] = 60 + { 61 + "unknown", 62 + "port", 63 + "file", 64 + "dispatch", 65 + "signal", 66 + "check", 67 + "plain" 68 + }; 69 + 70 + extern uint32_t notify_register_plain(const char *name, int *out_token); 71 + 72 + typedef struct 73 + { 74 + uint32_t token; 75 + uint32_t type; 76 + uint32_t signum; 77 + uint32_t count; 78 + char *name; 79 + } reg_entry_t; 80 + 81 + static reg_entry_t *reg; 82 + static uint32_t reg_count = 0; 83 + 84 + static int printopt; 85 + static int port_flag; 86 + static int file_flag; 87 + static int watch_file; 88 + static mach_port_t watch_port; 89 + dispatch_source_t timer_src; 90 + dispatch_source_t port_src; 91 + dispatch_source_t file_src; 92 + dispatch_source_t sig_src[__DARWIN_NSIG]; 93 + dispatch_queue_t watch_queue; 94 + 95 + static void 96 + usage(const char *name) 97 + { 98 + fprintf(stderr, "usage: %s [-q] [-v] [-z msec] [-M] [-R] [command ...]\n", name); 99 + fprintf(stderr, " -q quiet mode\n"); 100 + fprintf(stderr, " -v verbose - prints time, key, state value, and type\n"); 101 + fprintf(stderr, " -z msec pause msec milliseconds after posting [default 100]\n"); 102 + fprintf(stderr, " -M multiplex notifications from notifyd over a single mach port\n"); 103 + fprintf(stderr, " -R regenerate registrations if notifyd restarts\n"); 104 + fprintf(stderr, "commands:\n"); 105 + fprintf(stderr, " -port switch to mach port for subsequent registrations [default]\n"); 106 + fprintf(stderr, " -file switch to file descriptor for subsequent registrations\n"); 107 + fprintf(stderr, " -check switch to shared memory for subsequent registrations\n"); 108 + fprintf(stderr, " -signal [#] switch to signal [#] for subsequent registrations\n"); 109 + fprintf(stderr, " initial default for signal is 1 (SIGHUP)\n"); 110 + fprintf(stderr, " -dispatch switch to dispatch for subsequent registrations\n"); 111 + fprintf(stderr, " -p key post a notifcation for key\n"); 112 + fprintf(stderr, " -w key register for key and report notifications\n"); 113 + fprintf(stderr, " -# key (# is an integer value, eg \"-1\") register for key and report # notifications\n"); 114 + fprintf(stderr, " -g key get state value for key\n"); 115 + fprintf(stderr, " -s key val set state value for key\n"); 116 + } 117 + 118 + static const char * 119 + notify_status_strerror(int status) 120 + { 121 + switch (status) 122 + { 123 + case NOTIFY_STATUS_OK: return("OK"); 124 + case NOTIFY_STATUS_INVALID_NAME: return "Invalid Name"; 125 + case NOTIFY_STATUS_INVALID_TOKEN: return "Invalid Token"; 126 + case NOTIFY_STATUS_INVALID_PORT: return "Invalid Port"; 127 + case NOTIFY_STATUS_INVALID_FILE: return "Invalid File"; 128 + case NOTIFY_STATUS_INVALID_SIGNAL: return "Invalid Signal"; 129 + case NOTIFY_STATUS_INVALID_REQUEST: return "Invalid Request"; 130 + case NOTIFY_STATUS_NOT_AUTHORIZED: return "Not Authorized"; 131 + case NOTIFY_STATUS_FAILED: 132 + default: return "Failed"; 133 + } 134 + } 135 + 136 + static void 137 + reg_add(uint32_t tid, uint32_t type, uint32_t signum, uint32_t count, const char *name) 138 + { 139 + if (name == NULL) return; 140 + 141 + reg = (reg_entry_t *)reallocf(reg, (reg_count + 1) * sizeof(reg_entry_t)); 142 + if (reg == NULL) 143 + { 144 + fprintf(stderr, "Can't allocate memory!\n"); 145 + reg_count = 0; 146 + return; 147 + } 148 + 149 + reg[reg_count].token = tid; 150 + reg[reg_count].type = type; 151 + reg[reg_count].signum = signum; 152 + reg[reg_count].count = count; 153 + reg[reg_count].name = strdup(name); 154 + if (reg[reg_count].name == NULL) 155 + { 156 + fprintf(stderr, "Can't allocate memory!\n"); 157 + reg = NULL; 158 + reg_count = 0; 159 + return; 160 + } 161 + 162 + reg_count++; 163 + } 164 + 165 + static void 166 + reg_delete(uint32_t index) 167 + { 168 + uint32_t i; 169 + 170 + if (index == IndexNull) return; 171 + if (index >= reg_count) return; 172 + 173 + free(reg[index].name); 174 + 175 + for (i = index + 1; i < reg_count; i++) reg[i - 1] = reg[i]; 176 + reg_count--; 177 + 178 + if (reg_count == 0) 179 + { 180 + free(reg); 181 + reg = NULL; 182 + } 183 + else 184 + { 185 + reg = (reg_entry_t *)reallocf(reg, reg_count * sizeof(reg_entry_t)); 186 + if (reg == NULL) 187 + { 188 + fprintf(stderr, "Can't allocate memory!\n"); 189 + reg_count = 0; 190 + } 191 + } 192 + } 193 + 194 + static uint32_t 195 + reg_find_name(const char *name) 196 + { 197 + uint32_t i; 198 + 199 + for (i = 0; i < reg_count; i++) if (!strcmp(reg[i].name, name)) return i; 200 + return IndexNull; 201 + } 202 + 203 + static uint32_t 204 + reg_find_token(uint32_t tid) 205 + { 206 + uint32_t i; 207 + 208 + for (i = 0; i < reg_count; i++) if (tid == reg[i].token) return i; 209 + return IndexNull; 210 + } 211 + 212 + static void 213 + process_event(int tid) 214 + { 215 + struct timeval now; 216 + char tstr[32]; 217 + int status, index, needspace; 218 + uint64_t state; 219 + 220 + gettimeofday(&now, NULL); 221 + 222 + index = reg_find_token(tid); 223 + if (index == IndexNull) return; 224 + 225 + needspace = 0; 226 + 227 + if (printopt & PRINT_TIME) 228 + { 229 + snprintf(tstr, sizeof(tstr), "%llu", now.tv_usec + USEC_PER_SEC + 500); 230 + tstr[4] = '\0'; 231 + printf("%d.%s", (int)now.tv_sec, tstr+1); 232 + needspace = 1; 233 + } 234 + 235 + if (printopt & PRINT_KEY) 236 + { 237 + if (needspace) printf(" "); 238 + printf("%s", reg[index].name); 239 + needspace = 1; 240 + } 241 + 242 + if (printopt & PRINT_STATE) 243 + { 244 + if (needspace) printf(" "); 245 + state = 0; 246 + status = notify_get_state(tid, &state); 247 + if (status == NOTIFY_STATUS_OK) printf("%llu",(unsigned long long)state); 248 + else printf(": %s", notify_status_strerror(status)); 249 + needspace = 1; 250 + } 251 + 252 + if (printopt & PRINT_TYPE) 253 + { 254 + if (needspace) printf(" "); 255 + printf("%s", typename[reg[index].type]); 256 + needspace = 1; 257 + } 258 + 259 + if (printopt != PRINT_QUIET) printf("\n"); 260 + 261 + if ((reg[index].count != IndexNull) && (reg[index].count != 0)) reg[index].count--; 262 + if (reg[index].count == 0) 263 + { 264 + status = notify_cancel(tid); 265 + reg_delete(index); 266 + } 267 + } 268 + 269 + static void 270 + file_handler(int fd) 271 + { 272 + ssize_t i; 273 + int tid; 274 + 275 + if (fd < 0) return; 276 + 277 + i = read(fd, &tid, sizeof(tid)); 278 + if (i < 0) return; 279 + 280 + tid = ntohl(tid); 281 + process_event(tid); 282 + 283 + if (reg_count == 0) exit(0); 284 + } 285 + 286 + static void 287 + port_handler(mach_port_t port) 288 + { 289 + int tid; 290 + mach_msg_empty_rcv_t msg; 291 + kern_return_t status; 292 + 293 + if (port == MACH_PORT_NULL) return; 294 + 295 + memset(&msg, 0, sizeof(msg)); 296 + status = mach_msg(&msg.header, MACH_RCV_MSG, 0, sizeof(msg), port, 0, MACH_PORT_NULL); 297 + if (status != KERN_SUCCESS) return; 298 + 299 + tid = msg.header.msgh_id; 300 + process_event(tid); 301 + 302 + if (reg_count == 0) exit(0); 303 + } 304 + 305 + static void 306 + signal_handler(uint32_t sig) 307 + { 308 + uint32_t i, status; 309 + int check; 310 + 311 + if (printopt != PRINT_QUIET) printf("SIGNAL %u\n", sig); 312 + for (i = 0; i < reg_count; i++) 313 + { 314 + if ((reg[i].type == TYPE_SIGNAL) && (reg[i].signum == sig)) 315 + { 316 + check = 0; 317 + status = notify_check(reg[i].token, &check); 318 + if ((status == NOTIFY_STATUS_OK) && (check != 0)) process_event(reg[i].token); 319 + } 320 + } 321 + 322 + if (reg_count == 0) exit(0); 323 + } 324 + 325 + static void 326 + dispatch_handler(const char *name) 327 + { 328 + uint32_t index = reg_find_name(name); 329 + if (index == IndexNull) return; 330 + 331 + process_event(reg[index].token); 332 + } 333 + 334 + static void 335 + timer_handler(void) 336 + { 337 + uint32_t i, status; 338 + int check; 339 + 340 + for (i = 0; i < reg_count; i++) 341 + { 342 + if ((reg[i].type == TYPE_CHECK) || (reg[i].type == TYPE_PLAIN)) 343 + { 344 + check = 0; 345 + status = notify_check(reg[i].token, &check); 346 + if ((status == NOTIFY_STATUS_OK) && (check != 0)) process_event(reg[i].token); 347 + } 348 + } 349 + 350 + if (reg_count == 0) exit(0); 351 + } 352 + 353 + static uint32_t 354 + do_register(const char *name, uint32_t type, uint32_t signum, uint32_t count) 355 + { 356 + int tid, check; 357 + uint32_t status; 358 + 359 + switch (type) 360 + { 361 + case TYPE_PORT: 362 + { 363 + status = notify_register_mach_port(name, &watch_port, port_flag, &tid); 364 + if (status != NOTIFY_STATUS_OK) return status; 365 + 366 + port_flag = NOTIFY_REUSE; 367 + if (port_src == NULL) 368 + { 369 + port_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, watch_port, 0, watch_queue); 370 + dispatch_source_set_event_handler(port_src, ^{ 371 + port_handler(watch_port); 372 + }); 373 + dispatch_resume(port_src); 374 + } 375 + 376 + break; 377 + } 378 + 379 + case TYPE_FILE: 380 + { 381 + status = notify_register_file_descriptor(name, &watch_file, file_flag, &tid); 382 + if (status != NOTIFY_STATUS_OK) return status; 383 + 384 + file_flag = NOTIFY_REUSE; 385 + if (file_src == NULL) 386 + { 387 + file_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, (uintptr_t)watch_file, 0, watch_queue); 388 + dispatch_source_set_event_handler(file_src, ^{ 389 + file_handler(watch_file); 390 + }); 391 + dispatch_resume(file_src); 392 + } 393 + 394 + break; 395 + } 396 + 397 + case TYPE_SIGNAL: 398 + { 399 + signal(signum, SIG_IGN); 400 + 401 + status = notify_register_signal(name, signum, &tid); 402 + if (status != NOTIFY_STATUS_OK) return status; 403 + 404 + status = notify_check(tid, &check); 405 + 406 + if (sig_src[signum] == NULL) 407 + { 408 + sig_src[signum] = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t)signum, 0, watch_queue); 409 + dispatch_source_set_event_handler(sig_src[signum], ^{ 410 + signal_handler(signum); 411 + }); 412 + dispatch_resume(sig_src[signum]); 413 + } 414 + 415 + break; 416 + } 417 + 418 + case TYPE_DISPATCH: 419 + { 420 + status = notify_register_dispatch(name, &tid, watch_queue, ^(int x){ dispatch_handler(name); }); 421 + if (status != NOTIFY_STATUS_OK) return status; 422 + break; 423 + } 424 + 425 + case TYPE_CHECK: 426 + { 427 + status = notify_register_check(name, &tid); 428 + if (status != NOTIFY_STATUS_OK) return status; 429 + 430 + status = notify_check(tid, &check); 431 + 432 + if (timer_src == NULL) 433 + { 434 + timer_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, watch_queue); 435 + dispatch_source_set_event_handler(timer_src, ^{ 436 + timer_handler(); 437 + }); 438 + dispatch_source_set_timer(timer_src, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 10), NSEC_PER_SEC / 10, 0); 439 + dispatch_resume(timer_src); 440 + } 441 + 442 + break; 443 + } 444 + 445 + case TYPE_PLAIN: 446 + { 447 + status = notify_register_plain(name, &tid); 448 + if (status != NOTIFY_STATUS_OK) return status; 449 + 450 + status = notify_check(tid, &check); 451 + 452 + if (timer_src == NULL) 453 + { 454 + timer_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, watch_queue); 455 + dispatch_source_set_event_handler(timer_src, ^{ 456 + timer_handler(); 457 + }); 458 + dispatch_source_set_timer(timer_src, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 10), NSEC_PER_SEC / 10, 0); 459 + dispatch_resume(timer_src); 460 + } 461 + 462 + break; 463 + } 464 + 465 + default: return NOTIFY_STATUS_FAILED; 466 + } 467 + 468 + reg_add(tid, type, signum, count, name); 469 + return NOTIFY_STATUS_OK; 470 + } 471 + 472 + int 473 + main(int argc, const char *argv[]) 474 + { 475 + const char *name; 476 + uint32_t i, n, index, signum, ntype, status, opts, nap; 477 + int tid; 478 + uint64_t state; 479 + 480 + for (i = 0; i < __DARWIN_NSIG; i++) sig_src[i] = NULL; 481 + 482 + ntype = TYPE_PORT; 483 + signum = 1; 484 + watch_file = -1; 485 + watch_port = MACH_PORT_NULL; 486 + printopt = PRINT_KEY; 487 + opts = 0; 488 + nap = 100000; 489 + 490 + watch_queue = dispatch_queue_create("Watch Q", NULL); 491 + 492 + name = strrchr(argv[0], '/'); 493 + if (name == NULL) name = argv[0]; 494 + else name++; 495 + 496 + for (i = 1; i < argc; i++) 497 + { 498 + if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "-h"))) 499 + { 500 + usage(name); 501 + exit(0); 502 + } 503 + else if (!strcmp(argv[i], "-q")) 504 + { 505 + printopt = PRINT_QUIET; 506 + } 507 + else if (!strcmp(argv[i], "-v")) 508 + { 509 + printopt |= PRINT_VERBOSE; 510 + } 511 + else if (!strcmp(argv[i], "-M")) 512 + { 513 + opts |= NOTIFY_OPT_DEMUX; 514 + } 515 + else if (!strcmp(argv[i], "-R")) 516 + { 517 + opts |= NOTIFY_OPT_REGEN; 518 + } 519 + else if (!strcmp(argv[i], "-z")) 520 + { 521 + if ((i + 1) >= argc) 522 + { 523 + fprintf(stderr, "timer value must be supplied following -z\n"); 524 + usage(name); 525 + exit(1); 526 + } 527 + 528 + i++; 529 + 530 + if ((argv[i][0] < '0') || (argv[i][1] > '9')) 531 + { 532 + fprintf(stderr, "-z %s is invalid\n", argv[i]); 533 + fprintf(stderr, "timer value must be an integer\n"); 534 + usage(name); 535 + exit(1); 536 + } 537 + nap = 1000 * atoi(argv[i]); 538 + } 539 + else if (!strcmp(argv[i], "-port")) 540 + {} 541 + else if (!strcmp(argv[i], "-file")) 542 + {} 543 + else if ((!strcmp(argv[i], "-sig")) || (!strcmp(argv[i], "-signal"))) 544 + { 545 + if ((i + 1) >= argc) continue; 546 + if (argv[i + 1][0] == '-') continue; 547 + 548 + i++; 549 + 550 + if ((argv[i][0] < '0') || (argv[i][1] > '9')) 551 + { 552 + fprintf(stderr, "-signal %s is invalid\n", argv[i]); 553 + fprintf(stderr, "signals must be specified as integer values\n"); 554 + usage(name); 555 + exit(1); 556 + } 557 + 558 + } 559 + else if (!strcmp(argv[i], "-dispatch")) 560 + {} 561 + else if (!strcmp(argv[i], "-check")) 562 + {} 563 + else if (!strcmp(argv[i], "-plain")) 564 + {} 565 + else if (!strcmp(argv[i], "-p")) 566 + { 567 + if ((i + 1) >= argc) 568 + { 569 + fprintf(stderr, "name required following -p\n"); 570 + usage(name); 571 + exit(1); 572 + } 573 + 574 + i++; 575 + } 576 + else if ((argv[i][0] == '-') && ((argv[i][1] == 'w') || ((argv[i][1] >= '0') && (argv[i][1] <= '9')))) 577 + { 578 + if ((i + 1) >= argc) 579 + { 580 + fprintf(stderr, "name required following %s\n", argv[i]); 581 + usage(name); 582 + exit(1); 583 + } 584 + 585 + i++; 586 + } 587 + else if (!strcmp(argv[i], "-g")) 588 + { 589 + if ((i + 1) >= argc) 590 + { 591 + fprintf(stderr, "name required following -g\n"); 592 + usage(name); 593 + exit(1); 594 + } 595 + 596 + i++; 597 + } 598 + else if (!strcmp(argv[i], "-s")) 599 + { 600 + if ((i + 1) >= argc) 601 + { 602 + fprintf(stderr, "name required following -s\n"); 603 + usage(name); 604 + exit(1); 605 + } 606 + 607 + i++; 608 + 609 + if ((i + 1) >= argc) 610 + { 611 + fprintf(stderr, "value required following -s name\n"); 612 + usage(name); 613 + exit(1); 614 + } 615 + 616 + i++; 617 + state = atoll(argv[i]); 618 + if ((state == 0) && (strcmp(argv[i], "0"))) 619 + { 620 + fprintf(stderr, "value following -s name must be a 64-bit integer\n"); 621 + } 622 + } 623 + else 624 + { 625 + fprintf(stderr, "unrecognized option: %s\n", argv[i]); 626 + usage(name); 627 + exit(1); 628 + } 629 + } 630 + 631 + if (opts != 0) notify_set_options(opts); 632 + 633 + for (i = 1; i < argc; i++) 634 + { 635 + if (!strcmp(argv[i], "-port")) 636 + { 637 + ntype = TYPE_PORT; 638 + } 639 + else if (!strcmp(argv[i], "-file")) 640 + { 641 + ntype = TYPE_FILE; 642 + } 643 + else if ((!strcmp(argv[i], "-sig")) || (!strcmp(argv[i], "-signal"))) 644 + { 645 + 646 + ntype = TYPE_SIGNAL; 647 + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) 648 + { 649 + i++; 650 + signum = atoi(argv[i]); 651 + } 652 + } 653 + else if (!strcmp(argv[i], "-dispatch")) 654 + { 655 + ntype = TYPE_DISPATCH; 656 + } 657 + else if (!strcmp(argv[i], "-check")) 658 + { 659 + ntype = TYPE_CHECK; 660 + } 661 + else if (!strcmp(argv[i], "-plain")) 662 + { 663 + ntype = TYPE_PLAIN; 664 + } 665 + else if (!strcmp(argv[i], "-p")) 666 + { 667 + if ((i + 1) >= argc) 668 + { 669 + usage(name); 670 + exit(1); 671 + } 672 + 673 + i++; 674 + 675 + status = notify_post(argv[i]); 676 + if (status != NOTIFY_STATUS_OK) printf("%s: %s\n", argv[i], notify_status_strerror(status)); 677 + else if (nap > 0) usleep(nap); 678 + } 679 + else if ((argv[i][0] == '-') && ((argv[i][1] == 'w') || ((argv[i][1] >= '0') && (argv[i][1] <= '9')))) 680 + { 681 + if ((i + 1) >= argc) 682 + { 683 + usage(name); 684 + exit(1); 685 + } 686 + 687 + n = IndexNull; 688 + if (argv[i][1] != 'w') n = atoi(argv[i] + 1); 689 + 690 + i++; 691 + tid = IndexNull; 692 + 693 + index = reg_find_name(argv[i]); 694 + if (index != IndexNull) 695 + { 696 + fprintf(stderr, "Already watching for %s\n", argv[i]); 697 + continue; 698 + } 699 + 700 + status = do_register(argv[i], ntype, signum, n); 701 + if (status != NOTIFY_STATUS_OK) printf("%s: %s\n", argv[i], notify_status_strerror(status)); 702 + } 703 + else if (!strcmp(argv[i], "-g")) 704 + { 705 + if ((i + 1) >= argc) 706 + { 707 + usage(name); 708 + exit(1); 709 + } 710 + 711 + i++; 712 + state = 0; 713 + tid = IndexNull; 714 + 715 + status = notify_register_plain(argv[i], &tid); 716 + if (status == NOTIFY_STATUS_OK) 717 + { 718 + status = notify_get_state(tid, &state); 719 + notify_cancel(tid); 720 + } 721 + 722 + if (status == NOTIFY_STATUS_OK) printf("%s %llu\n", argv[i], (unsigned long long)state); 723 + else printf("%s: %s\n", argv[i], notify_status_strerror(status)); 724 + } 725 + else if (!strcmp(argv[i], "-s")) 726 + { 727 + if ((i + 2) >= argc) 728 + { 729 + usage(name); 730 + exit(1); 731 + } 732 + 733 + i++; 734 + tid = IndexNull; 735 + status = notify_register_plain(argv[i], &tid); 736 + if (status == NOTIFY_STATUS_OK) 737 + { 738 + state = atoll(argv[i + 1]); 739 + status = notify_set_state(tid, state); 740 + notify_cancel(tid); 741 + } 742 + 743 + if (status != NOTIFY_STATUS_OK) printf("%s: %s\n", argv[i], notify_status_strerror(status)); 744 + i++; 745 + } 746 + } 747 + 748 + if (reg_count == 0) exit(0); 749 + 750 + dispatch_main(); 751 + }
+763
libnotify/table.c
··· 1 + /* 2 + * Copyright (c) 2003-2011 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #include <stdlib.h> 25 + #include <string.h> 26 + #include <syslog.h> 27 + #include <sys/types.h> 28 + #include <os/assumes.h> 29 + #include "table.h" 30 + 31 + #define KEY_UNKNOWN 0 32 + #define KEY_INT 1 33 + #define KEY_STR_MINE 2 34 + #define KEY_STR_SHARED 3 35 + 36 + #define DEFAULT_SIZE 256 37 + 38 + typedef struct table_node_s 39 + { 40 + union 41 + { 42 + char *string; 43 + const char *const_string; 44 + uint64_t uint64; 45 + } key; 46 + void *datum; 47 + struct table_node_s *next; 48 + } table_node_t; 49 + 50 + typedef struct __table_private 51 + { 52 + uint32_t type; 53 + uint32_t bucket_count; 54 + table_node_t **bucket; 55 + } table_private_t; 56 + 57 + typedef struct 58 + { 59 + uint32_t bucket_index; 60 + table_node_t *node; 61 + } table_traverse_t; 62 + 63 + typedef struct __list_private 64 + { 65 + struct __list_private *prev; 66 + struct __list_private *next; 67 + uint32_t refcount; 68 + void *data; 69 + } list_private_t; 70 + 71 + table_t * 72 + _nc_table_new(uint32_t n) 73 + { 74 + table_private_t *t; 75 + 76 + t = (table_t *)malloc(sizeof(table_t)); 77 + if (t == NULL) return NULL; 78 + 79 + if (n == 0) n = DEFAULT_SIZE; 80 + 81 + t->type = KEY_UNKNOWN; 82 + t->bucket_count = n; 83 + t->bucket = (table_node_t **)calloc(t->bucket_count, sizeof(table_node_t *)); 84 + if (t->bucket == NULL) 85 + { 86 + free(t); 87 + return NULL; 88 + } 89 + 90 + return (table_t *)t; 91 + } 92 + 93 + static uint32_t 94 + hash_key(int size, const char *key) 95 + { 96 + uint32_t v; 97 + char *p; 98 + 99 + if (key == NULL) return 0; 100 + 101 + v = 0; 102 + for (p = (char *)key; *p != '\0'; p++) 103 + { 104 + v = (v << 1) ^ (v ^ *p); 105 + } 106 + 107 + v %= size; 108 + return v; 109 + } 110 + 111 + static uint32_t 112 + hash_nkey(uint32_t size, uint64_t key) 113 + { 114 + uint32_t x = key; 115 + uint32_t y = key >> 32; 116 + return ((x ^ y) % size); 117 + } 118 + 119 + void * 120 + _nc_table_find_get_key(table_t *tin, const char *key, const char **shared_key) 121 + { 122 + table_private_t *t; 123 + table_node_t *n; 124 + uint32_t b; 125 + 126 + if (tin == NULL) return NULL; 127 + if (key == NULL) return NULL; 128 + 129 + if (shared_key != NULL) *shared_key = NULL; 130 + 131 + t = (table_private_t *)tin; 132 + b = hash_key(t->bucket_count, key); 133 + 134 + for (n = t->bucket[b]; n != NULL; n = n->next) 135 + { 136 + if ((n->key.string != NULL) && (!strcmp(key, n->key.string))) 137 + { 138 + if (shared_key != NULL) *shared_key = n->key.const_string; 139 + return n->datum; 140 + } 141 + } 142 + 143 + return NULL; 144 + } 145 + 146 + void * 147 + _nc_table_find(table_t *tin, const char *key) 148 + { 149 + return _nc_table_find_get_key(tin, key, NULL); 150 + } 151 + 152 + void * 153 + _nc_table_find_64(table_t *tin, uint64_t key) 154 + { 155 + table_private_t *t; 156 + table_node_t *n; 157 + uint32_t b; 158 + 159 + if (tin == NULL) return NULL; 160 + 161 + t = (table_private_t *)tin; 162 + b = hash_nkey(t->bucket_count, key); 163 + 164 + for (n = t->bucket[b]; n != NULL; n = n->next) 165 + { 166 + if ((n->key.uint64 != (uint64_t)-1) && (key == n->key.uint64)) return n->datum; 167 + } 168 + 169 + return NULL; 170 + } 171 + 172 + void * 173 + _nc_table_find_n(table_t *tin, uint32_t key) 174 + { 175 + uint64_t n64 = key; 176 + return _nc_table_find_64(tin, n64); 177 + } 178 + 179 + static void 180 + _nc_table_insert_type(table_t *tin, int type, char *key, const char *ckey, void *datum) 181 + { 182 + table_private_t *t; 183 + table_node_t *n; 184 + uint32_t b; 185 + 186 + if (tin == NULL) return; 187 + if ((key == NULL) && (ckey == NULL)) return; 188 + if (datum == NULL) return; 189 + 190 + t = (table_private_t *)tin; 191 + if (t->type == KEY_UNKNOWN) t->type = type; 192 + else os_assumes(t->type == type); 193 + 194 + n = (table_node_t *)malloc(sizeof(table_node_t)); 195 + 196 + if (key != NULL) 197 + { 198 + b = hash_key(t->bucket_count, key); 199 + n->key.string = key; 200 + } 201 + else 202 + { 203 + b = hash_key(t->bucket_count, ckey); 204 + n->key.const_string = ckey; 205 + } 206 + 207 + n->datum = datum; 208 + n->next = t->bucket[b]; 209 + t->bucket[b] = n; 210 + } 211 + 212 + void 213 + _nc_table_insert(table_t *tin, const char *key, void *datum) 214 + { 215 + char *dup; 216 + 217 + if (tin == NULL) return; 218 + if (key == NULL) return; 219 + if (datum == NULL) return; 220 + 221 + dup = strdup(key); 222 + if (dup == NULL) return; 223 + 224 + _nc_table_insert_type(tin, KEY_STR_MINE, dup, NULL, datum); 225 + } 226 + 227 + void 228 + _nc_table_insert_no_copy(table_t *tin, const char *key, void *datum) 229 + { 230 + if (tin == NULL) return; 231 + if (key == NULL) return; 232 + if (datum == NULL) return; 233 + 234 + _nc_table_insert_type(tin, KEY_STR_SHARED, NULL, key, datum); 235 + } 236 + 237 + void 238 + _nc_table_insert_pass(table_t *tin, char *key, void *datum) 239 + { 240 + if (tin == NULL) return; 241 + if (key == NULL) return; 242 + if (datum == NULL) return; 243 + 244 + _nc_table_insert_type(tin, KEY_STR_MINE, key, NULL, datum); 245 + } 246 + 247 + void 248 + _nc_table_insert_64(table_t *tin, uint64_t key, void *datum) 249 + { 250 + table_private_t *t; 251 + table_node_t *n; 252 + uint32_t b; 253 + 254 + if (tin == NULL) return; 255 + if (datum == NULL) return; 256 + 257 + t = (table_private_t *)tin; 258 + if (t->type == KEY_UNKNOWN) t->type = KEY_INT; 259 + else os_assumes(t->type == KEY_INT); 260 + 261 + b = hash_nkey(t->bucket_count, key); 262 + n = (table_node_t *)malloc(sizeof(table_node_t)); 263 + n->key.uint64 = key; 264 + n->datum = datum; 265 + n->next = t->bucket[b]; 266 + t->bucket[b] = n; 267 + } 268 + 269 + void 270 + _nc_table_insert_n(table_t *tin, uint32_t key, void *datum) 271 + { 272 + uint64_t n64 = key; 273 + _nc_table_insert_64(tin, n64, datum); 274 + } 275 + 276 + void 277 + _nc_table_delete(table_t *tin, const char *key) 278 + { 279 + table_private_t *t; 280 + table_node_t *n, *p; 281 + uint32_t b; 282 + 283 + if (tin == NULL) return; 284 + if (key == NULL) return; 285 + 286 + t = (table_private_t *)tin; 287 + os_assumes((t->type == KEY_STR_MINE) || (t->type == KEY_STR_SHARED)); 288 + 289 + b = hash_key(t->bucket_count, key); 290 + 291 + p = NULL; 292 + for (n = t->bucket[b]; n != NULL; n = n->next) 293 + { 294 + if ((n->key.string != NULL) && (!strcmp(key, n->key.string))) 295 + { 296 + if (p == NULL) t->bucket[b] = n->next; 297 + else p->next = n->next; 298 + if (t->type == KEY_STR_MINE) free(n->key.string); 299 + free(n); 300 + return; 301 + } 302 + p = n; 303 + } 304 + } 305 + 306 + void 307 + _nc_table_delete_64(table_t *tin, uint64_t key) 308 + { 309 + table_private_t *t; 310 + table_node_t *n, *p; 311 + uint32_t b; 312 + 313 + if (tin == NULL) return; 314 + 315 + t = (table_private_t *)tin; 316 + os_assumes(t->type == KEY_INT); 317 + 318 + b = hash_nkey(t->bucket_count, key); 319 + 320 + p = NULL; 321 + for (n = t->bucket[b]; n != NULL; n = n->next) 322 + { 323 + if ((n->key.uint64 != (uint64_t)-1) && (key == n->key.uint64)) 324 + { 325 + if (p == NULL) t->bucket[b] = n->next; 326 + else p->next = n->next; 327 + free(n); 328 + return; 329 + } 330 + p = n; 331 + } 332 + } 333 + 334 + void 335 + _nc_table_delete_n(table_t *tin, uint32_t key) 336 + { 337 + uint64_t n64 = key; 338 + _nc_table_delete_64(tin, n64); 339 + } 340 + 341 + void * 342 + _nc_table_traverse_start(table_t *tin) 343 + { 344 + table_traverse_t *tt; 345 + table_private_t *t; 346 + uint32_t b; 347 + 348 + if (tin == NULL) return NULL; 349 + 350 + t = (table_private_t *)tin; 351 + if (t->bucket_count == 0) return NULL; 352 + 353 + for (b = 0; b < t->bucket_count; b++) 354 + { 355 + if (t->bucket[b] != NULL) 356 + { 357 + tt = (table_traverse_t *)malloc(sizeof(table_traverse_t)); 358 + if (tt == NULL) return NULL; 359 + tt->bucket_index = b; 360 + tt->node = t->bucket[b]; 361 + return (void *)tt; 362 + } 363 + } 364 + 365 + return NULL; 366 + } 367 + 368 + void * 369 + _nc_table_traverse(table_t *tin, void *ttin) 370 + { 371 + table_private_t *t; 372 + table_traverse_t *tt; 373 + void *datum; 374 + uint32_t b; 375 + 376 + if (tin == NULL) return NULL; 377 + if (ttin == NULL) return NULL; 378 + 379 + t = (table_private_t *)tin; 380 + tt = (table_traverse_t *)ttin; 381 + 382 + if (tt->node == NULL) return NULL; 383 + 384 + datum = tt->node->datum; 385 + tt->node = tt->node->next; 386 + if (tt->node != NULL) return datum; 387 + 388 + for (b = tt->bucket_index + 1; b < t->bucket_count; b++) 389 + { 390 + if (t->bucket[b] != NULL) 391 + { 392 + tt->bucket_index = b; 393 + tt->node = t->bucket[b]; 394 + return datum; 395 + } 396 + } 397 + 398 + tt->bucket_index = b; 399 + tt->node = NULL; 400 + 401 + return datum; 402 + } 403 + 404 + void 405 + _nc_table_traverse_end(table_t *tin, void *ttin) 406 + { 407 + if (ttin == NULL) return; 408 + free(ttin); 409 + } 410 + 411 + void 412 + _nc_table_free(table_t *tin) 413 + { 414 + table_private_t *t; 415 + table_node_t *n, *x; 416 + uint32_t b; 417 + 418 + if (tin == NULL) return; 419 + 420 + t = (table_private_t *)tin; 421 + 422 + for (b = 0; b < t->bucket_count; b++) 423 + { 424 + x = NULL; 425 + for (n = t->bucket[b]; n != NULL; n = x) 426 + { 427 + x = n->next; 428 + if (t->type == KEY_STR_MINE) free(n->key.string); 429 + free(n); 430 + } 431 + } 432 + 433 + free(t->bucket); 434 + free(t); 435 + } 436 + 437 + /* Linked List */ 438 + 439 + /* 440 + * Make a new node 441 + */ 442 + list_t * 443 + _nc_list_new(void *d) 444 + { 445 + list_t *n; 446 + 447 + n = (list_t *)calloc(1, sizeof(list_t)); 448 + if (n == NULL) return NULL; 449 + 450 + n->refcount = 1; 451 + n->data = d; 452 + return n; 453 + } 454 + 455 + /* 456 + * Release a node 457 + */ 458 + void 459 + _nc_list_release(list_t *l) 460 + { 461 + if (l == NULL) return; 462 + l->refcount--; 463 + if (l->refcount > 0) return; 464 + 465 + free(l); 466 + } 467 + 468 + /* 469 + * Retain a node 470 + */ 471 + list_t * 472 + _nc_list_retain(list_t *l) 473 + { 474 + if (l == NULL) return NULL; 475 + l->refcount++; 476 + return l; 477 + } 478 + 479 + /* 480 + * Retain a list 481 + */ 482 + list_t * 483 + _nc_list_retain_list(list_t *l) 484 + { 485 + list_t *n; 486 + 487 + for (n = l; n != NULL; n = n->next) n->refcount++; 488 + return l; 489 + } 490 + 491 + /* 492 + * Get previous node 493 + */ 494 + list_t * 495 + _nc_list_prev(list_t *l) 496 + { 497 + if (l == NULL) return NULL; 498 + return l->prev; 499 + } 500 + 501 + /* 502 + * Get next node 503 + */ 504 + list_t * 505 + _nc_list_next(list_t *l) 506 + { 507 + if (l == NULL) return NULL; 508 + return l->next; 509 + } 510 + 511 + /* 512 + * Get head (first node) of list 513 + */ 514 + list_t * 515 + _nc_list_head(list_t *l) 516 + { 517 + list_t *p; 518 + 519 + if (l == NULL) return NULL; 520 + 521 + for (p = l; p->prev != NULL; p = p->prev); 522 + 523 + return p; 524 + } 525 + 526 + /* 527 + * Get tail (last node) of list 528 + */ 529 + list_t * 530 + _nc_list_tail(list_t *l) 531 + { 532 + list_t *p; 533 + 534 + if (l == NULL) return NULL; 535 + 536 + for (p = l; p->next != NULL; p = p->next); 537 + 538 + return p; 539 + } 540 + 541 + /* 542 + * Insert a node in front of another node. 543 + * Cuts list if n is NULL. 544 + */ 545 + list_t * 546 + _nc_list_prepend(list_t *l, list_t *n) 547 + { 548 + if (l == NULL) return n; 549 + 550 + if (n != NULL) 551 + { 552 + n->next = l; 553 + n->prev = l->prev; 554 + } 555 + 556 + if (l->prev != NULL) l->prev->next = n; 557 + l->prev = n; 558 + 559 + return n; 560 + } 561 + 562 + /* 563 + * Append a node after another node. 564 + * Cuts list if n is NULL. 565 + */ 566 + list_t * 567 + _nc_list_append(list_t *l, list_t *n) 568 + { 569 + if (l == NULL) return n; 570 + 571 + if (n != NULL) 572 + { 573 + n->prev = l; 574 + n->next = l->next; 575 + } 576 + 577 + if (l->next != NULL) n->next->prev = n; 578 + l->next = n; 579 + 580 + return n; 581 + } 582 + 583 + /* 584 + * Set next pointer - use with care. 585 + */ 586 + void 587 + _nc_list_set_next(list_t *l, list_t *n) 588 + { 589 + if (l == NULL) return; 590 + l->next = n; 591 + } 592 + 593 + /* 594 + * Set prev pointer - use with care. 595 + */ 596 + void 597 + _nc_list_set_prev(list_t *l, list_t *p) 598 + { 599 + if (l == NULL) return; 600 + l->prev = p; 601 + } 602 + 603 + /* 604 + * Concatenate two lists. 605 + * Returns new head. 606 + */ 607 + list_t * 608 + _nc_list_concat(list_t *a, list_t *b) 609 + { 610 + list_t *p; 611 + 612 + if (a == NULL) return b; 613 + if (b == NULL) return a; 614 + 615 + for (p = a; p->next != NULL; p = p->next); 616 + 617 + p->next = b; 618 + b->prev = p; 619 + 620 + for (p = a; p->prev != NULL; p = p->prev); 621 + 622 + return p; 623 + } 624 + 625 + uint32_t 626 + _nc_list_count(list_t *l) 627 + { 628 + uint32_t n; 629 + list_t *p; 630 + 631 + n = 0; 632 + for (p = l; p != NULL; p = p->next) n++; 633 + return n; 634 + } 635 + 636 + void * 637 + _nc_list_data(list_t *l) 638 + { 639 + if (l == NULL) return NULL; 640 + return l->data; 641 + } 642 + 643 + void 644 + _nc_list_set_data(list_t *l, void *d) 645 + { 646 + if (l != NULL) l->data = d; 647 + } 648 + 649 + list_t * 650 + _nc_list_find(list_t *l, void *d) 651 + { 652 + list_t *p; 653 + 654 + if (l == NULL) return NULL; 655 + 656 + for (p = l; p != NULL; p = p->next) 657 + { 658 + if (p->data == d) return p; 659 + } 660 + 661 + return NULL; 662 + } 663 + 664 + list_t * 665 + _nc_list_find_release(list_t *l, void *d) 666 + { 667 + list_t *p; 668 + 669 + if (l == NULL) return NULL; 670 + 671 + if (l->data == d) 672 + { 673 + p = l->next; 674 + if (p != NULL) p->prev = NULL; 675 + _nc_list_release(l); 676 + return p; 677 + } 678 + 679 + for (p = l->next; p != NULL; p = p->next) 680 + { 681 + if (p->data == d) 682 + { 683 + p->prev->next = p->next; 684 + if (p->next != NULL) p->next->prev = p->prev; 685 + _nc_list_release(p); 686 + return l; 687 + } 688 + } 689 + 690 + return l; 691 + } 692 + 693 + list_t * 694 + _nc_list_reverse(list_t *l) 695 + { 696 + list_t *x, *s, *r; 697 + 698 + if (l == NULL) return NULL; 699 + 700 + x = l->prev; 701 + r = l; 702 + s = l->next; 703 + 704 + while (s != NULL) 705 + { 706 + s = r->next; 707 + r->next = r->prev; 708 + r->prev = s; 709 + if (s != NULL) r = s; 710 + } 711 + 712 + if (x != NULL) 713 + { 714 + x->next = r; 715 + r->prev = x; 716 + } 717 + 718 + return r; 719 + } 720 + 721 + list_t * 722 + _nc_list_extract(list_t *n) 723 + { 724 + if (n == NULL) return NULL; 725 + 726 + if (n->prev != NULL) n->prev->next = n->next; 727 + if (n->next != NULL) n->next->prev = n->prev; 728 + 729 + n->prev = NULL; 730 + n->next = NULL; 731 + 732 + return n; 733 + } 734 + 735 + list_t * 736 + _nc_list_chop(list_t *l) 737 + { 738 + list_t *p; 739 + 740 + if (l == NULL) return NULL; 741 + p = l->next; 742 + if (p != NULL) p->prev = NULL; 743 + 744 + _nc_list_release(l); 745 + return p; 746 + } 747 + 748 + void 749 + _nc_list_release_list(list_t *l) 750 + { 751 + list_t *p, *n; 752 + 753 + if (l == NULL) return; 754 + if (l->prev != NULL) l->prev->next = NULL; 755 + 756 + p = l; 757 + while (p != NULL) 758 + { 759 + n = p->next; 760 + _nc_list_release(p); 761 + p = n; 762 + } 763 + }
+88
libnotify/table.h
··· 1 + /* 2 + * Copyright (c) 2003-2011 Apple Inc. All rights reserved. 3 + * 4 + * @APPLE_LICENSE_HEADER_START@ 5 + * 6 + * This file contains Original Code and/or Modifications of Original Code 7 + * as defined in and that are subject to the Apple Public Source License 8 + * Version 2.0 (the 'License'). You may not use this file except in 9 + * compliance with the License. Please obtain a copy of the License at 10 + * http://www.opensource.apple.com/apsl/ and read it before using this 11 + * file. 12 + * 13 + * The Original Code and all software distributed under the License are 14 + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 + * Please see the License for the specific language governing rights and 19 + * limitations under the License. 20 + * 21 + * @APPLE_LICENSE_HEADER_END@ 22 + */ 23 + 24 + #ifndef _NOTIFY_TABLE_H_ 25 + #define _NOTIFY_TABLE_H_ 26 + 27 + #include <stdint.h> 28 + 29 + typedef struct __table_private table_t; 30 + typedef struct __list_private list_t; 31 + 32 + extern table_t *_nc_table_new(uint32_t n); 33 + 34 + extern void _nc_table_insert(table_t *t, const char *key, void *datum); 35 + extern void _nc_table_insert_no_copy(table_t *t, const char *key, void *datum); 36 + extern void _nc_table_insert_pass(table_t *t, char *key, void *datum); 37 + extern void _nc_table_insert_n(table_t *t, uint32_t key, void *datum); 38 + extern void _nc_table_insert_64(table_t *t, uint64_t key, void *datum); 39 + 40 + extern void *_nc_table_find(table_t *t, const char *key); 41 + extern void *_nc_table_find_get_key(table_t *tin, const char *key, const char **shared_key); 42 + extern void *_nc_table_find_n(table_t *t, uint32_t key); 43 + extern void *_nc_table_find_64(table_t *t, uint64_t key); 44 + 45 + extern void _nc_table_delete(table_t *t, const char *key); 46 + extern void _nc_table_delete_n(table_t *t, uint32_t key); 47 + extern void _nc_table_delete_64(table_t *t, uint64_t key); 48 + 49 + extern void *_nc_table_traverse_start(table_t *tin); 50 + extern void *_nc_table_traverse(table_t *tin, void *ttin); 51 + extern void _nc_table_traverse_end(table_t *tin, void *ttin); 52 + 53 + extern void _nc_table_free(table_t *tin); 54 + 55 + extern list_t *_nc_list_new(void *d); 56 + 57 + extern list_t *_nc_list_retain(list_t *l); 58 + extern list_t *_nc_list_retain_list(list_t *l); 59 + 60 + extern void _nc_list_release(list_t *l); 61 + extern void _nc_list_release_list(list_t *l); 62 + 63 + extern list_t *_nc_list_prev(list_t *l); 64 + extern list_t *_nc_list_next(list_t *l); 65 + 66 + extern void _nc_list_set_next(list_t *l, list_t *n); 67 + extern void _nc_list_set_prev(list_t *l, list_t *p); 68 + 69 + extern list_t *_nc_list_head(list_t *l); 70 + extern list_t *_nc_list_tail(list_t *l); 71 + 72 + extern list_t *_nc_list_prepend(list_t *l, list_t *n); 73 + extern list_t *_nc_list_append(list_t *l, list_t *n); 74 + 75 + extern list_t *_nc_list_concat(list_t *a, list_t *b); 76 + 77 + extern void *_nc_list_data(list_t *l); 78 + extern void _nc_list_set_data(list_t *l, void *d); 79 + 80 + extern list_t *_nc_list_find(list_t *l, void *d); 81 + extern list_t *_nc_list_find_release(list_t *l, void *d); 82 + 83 + extern list_t * _nc_list_reverse(list_t *l); 84 + extern uint32_t _nc_list_count(list_t *l); 85 + extern list_t *_nc_list_extract(list_t *n); 86 + extern list_t *_nc_list_chop(list_t *l); 87 + 88 + #endif /* _NOTIFY_TABLE_H_ */
+29
libnotify/xcodeconfig/base.xcconfig
··· 1 + #include "<DEVELOPER_DIR>/Makefiles/CoreOS/Xcode/BSD.xcconfig" 2 + #include "<DEVELOPER_DIR>/AppleInternal/XcodeConfig/SimulatorSupport.xcconfig" 3 + 4 + INSTALL_PATH[sdk=macosx*] = $(INSTALL_PATH_ACTUAL) 5 + 6 + ALWAYS_SEARCH_USER_PATHS = YES 7 + HEADER_SEARCH_PATHS = $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders $(PROJECT_DIR) 8 + ARCHS = $(ARCHS_STANDARD_32_64_BIT) 9 + CODE_SIGN_IDENTITY = - 10 + DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 11 + GCC_ENABLE_CPP_EXCEPTIONS = NO 12 + GCC_ENABLE_CPP_RTTI = NO 13 + GCC_ENABLE_OBJC_EXCEPTIONS = NO 14 + GCC_PREPROCESSOR_DEFINITIONS = __DARWIN_NON_CANCELABLE=1 15 + GCC_C_LANGUAGE_STANDARD = gnu99 16 + GCC_WARN_ABOUT_RETURN_TYPE = YES 17 + GCC_WARN_UNUSED_VARIABLE = YES 18 + //GCC_WARN_64_TO_32_BIT_CONVERSION = YES 19 + //GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES 20 + //GCC_WARN_ABOUT_RETURN_TYPE = YES 21 + OTHER_CFLAGS = -fno-exceptions 22 + OTHER_CFLAGS_debug = -O0 23 + CURRENT_PROJECT_VERSION = 24 + CURRENT_PROJECT_VERSION = $(RC_ProjectSourceVersion) 25 + VERSION_INFO_PREFIX = __ 26 + VERSIONING_SYSTEM = apple-generic 27 + PREBINDING = NO 28 + NOTIFY_CONFIG = notify.conf.MacOSX 29 + NOTIFY_CONFIG[sdk=iphoneos*] = notify.conf.iPhone
+31
libnotify/xcodeconfig/libnotify.xcconfig
··· 1 + #include "base.xcconfig" 2 + 3 + PRODUCT_NAME = libsystem_notify 4 + INSTALL_PATH_ACTUAL = /usr/lib/system 5 + PRIVATE_HEADERS_FOLDER_PATH = $(INSTALL_PATH_PREFIX)/usr/local/include 6 + PUBLIC_HEADERS_FOLDER_PATH = $(INSTALL_PATH_PREFIX)/usr/include 7 + DYLIB_CURRENT_VERSION = $(CURRENT_PROJECT_VERSION) 8 + EXECUTABLE_PREFIX = 9 + BUILD_VARIANTS = normal 10 + CURRENT_PROJECT_VERSION = $(RC_ProjectSourceVersion) 11 + VERSION_INFO_PREFIX = __ 12 + VERSIONING_SYSTEM = apple-generic 13 + 14 + LINK_WITH_STANDARD_LIBRARIES = NO 15 + OTHER_LDFLAGS = -umbrella System -L/usr/lib/system $(LDFLAGS_DYLD) $(LDFLAGS_COMPILER_RT) $(LDFLAGS_SYSCALL) $(LDFLAGS_PLATFORM) $(LDFLAGS_PTHREAD) $(LDFLAGS_MALLOC) $(LDFLAGS_C) $(LDFLAGS_BLOCKS) $(LDFLAGS_DISPATCH) $(LDFLAGS_XPC) 16 + 17 + LDFLAGS_DYLD = -ldyld 18 + LDFLAGS_COMPILER_RT = -lcompiler_rt 19 + LDFLAGS_SYSCALL = -lsystem_kernel 20 + LDFLAGS_SYSCALL[sdk=iphonesimulator*] = -lsystem_sim_kernel 21 + LDFLAGS_PLATFORM = -lsystem_platform 22 + LDFLAGS_PLATFORM[sdk=iphonesimulator*] = -lsystem_sim_platform 23 + LDFLAGS_PTHREAD = -lsystem_pthread 24 + LDFLAGS_PTHREAD[sdk=iphonesimulator*] = -lsystem_sim_pthread 25 + LDFLAGS_MALLOC = -lsystem_malloc 26 + LDFLAGS_C = -lsystem_c 27 + LDFLAGS_C[sdk=iphonesimulator*] = -lsystem_sim_c 28 + LDFLAGS_BLOCKS = -lsystem_blocks 29 + LDFLAGS_BLOCKS[sdk=iphonesimulator*] = -lsystem_sim_blocks 30 + LDFLAGS_DISPATCH = -ldispatch 31 + LDFLAGS_XPC = -lxpc
+5
libnotify/xcodeconfig/notifyd.xcconfig
··· 1 + #include "base.xcconfig" 2 + 3 + INSTALL_PATH_ACTUAL = /usr/sbin 4 + 5 + OTHER_LDFLAGS = -lCrashReporterClient
+4
libnotify/xcodeconfig/notifyutil.xcconfig
··· 1 + #include "base.xcconfig" 2 + 3 + INSTALL_PATH_ACTUAL = /usr/bin 4 +
+5
libnotify/xcodescripts/no-sim-man.sh
··· 1 + #!/bin/bash -ex 2 + 3 + if [[ "${PLATFORM_NAME}" =~ "simulator" ]]; then 4 + rm -rf ${DSTROOT}${INSTALL_PATH_PREFIX}/usr/share/man 5 + fi
+5
libnotify/xcodescripts/sim-compat-symlink.sh
··· 1 + #!/bin/bash -ex 2 + 3 + if [[ "${PLATFORM_NAME}" =~ "simulator" ]]; then 4 + ln -s libsystem_notify.dylib ${DSTROOT}${INSTALL_PATH}/libnotify_sim.dylib 5 + fi
+2711
platform-include/dns_sd.h
··· 1 + /* -*- Mode: C; tab-width: 4 -*- 2 + * 3 + * Copyright (c) 2003-2013 Apple Computer, Inc. All rights reserved. 4 + * 5 + * Redistribution and use in source and binary forms, with or without 6 + * modification, are permitted provided that the following conditions are met: 7 + * 8 + * 1. Redistributions of source code must retain the above copyright notice, 9 + * this list of conditions and the following disclaimer. 10 + * 2. Redistributions in binary form must reproduce the above copyright notice, 11 + * this list of conditions and the following disclaimer in the documentation 12 + * and/or other materials provided with the distribution. 13 + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its 14 + * contributors may be used to endorse or promote products derived from this 15 + * software without specific prior written permission. 16 + * 17 + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 + */ 28 + 29 + 30 + /*! @header DNS Service Discovery 31 + * 32 + * @discussion This section describes the functions, callbacks, and data structures 33 + * that make up the DNS Service Discovery API. 34 + * 35 + * The DNS Service Discovery API is part of Bonjour, Apple's implementation 36 + * of zero-configuration networking (ZEROCONF). 37 + * 38 + * Bonjour allows you to register a network service, such as a 39 + * printer or file server, so that it can be found by name or browsed 40 + * for by service type and domain. Using Bonjour, applications can 41 + * discover what services are available on the network, along with 42 + * all the information -- such as name, IP address, and port -- 43 + * necessary to access a particular service. 44 + * 45 + * In effect, Bonjour combines the functions of a local DNS server and 46 + * AppleTalk. Bonjour allows applications to provide user-friendly printer 47 + * and server browsing, among other things, over standard IP networks. 48 + * This behavior is a result of combining protocols such as multicast and 49 + * DNS to add new functionality to the network (such as multicast DNS). 50 + * 51 + * Bonjour gives applications easy access to services over local IP 52 + * networks without requiring the service or the application to support 53 + * an AppleTalk or a Netbeui stack, and without requiring a DNS server 54 + * for the local network. 55 + */ 56 + 57 + /* _DNS_SD_H contains the API version number for this header file 58 + * The API version defined in this header file symbol allows for compile-time 59 + * checking, so that C code building with earlier versions of the header file 60 + * can avoid compile errors trying to use functions that aren't even defined 61 + * in those earlier versions. Similar checks may also be performed at run-time: 62 + * => weak linking -- to avoid link failures if run with an earlier 63 + * version of the library that's missing some desired symbol, or 64 + * => DNSServiceGetProperty(DaemonVersion) -- to verify whether the running daemon 65 + * ("system service" on Windows) meets some required minimum functionality level. 66 + */ 67 + 68 + #ifndef _DNS_SD_H 69 + #define _DNS_SD_H 5610101 70 + 71 + #ifdef __cplusplus 72 + extern "C" { 73 + #endif 74 + 75 + /* Set to 1 if libdispatch is supported 76 + * Note: May also be set by project and/or Makefile 77 + */ 78 + #ifndef _DNS_SD_LIBDISPATCH 79 + #define _DNS_SD_LIBDISPATCH 1 80 + #endif /* ndef _DNS_SD_LIBDISPATCH */ 81 + 82 + /* standard calling convention under Win32 is __stdcall */ 83 + /* Note: When compiling Intel EFI (Extensible Firmware Interface) under MS Visual Studio, the */ 84 + /* _WIN32 symbol is defined by the compiler even though it's NOT compiling code for Windows32 */ 85 + #if defined(_WIN32) && !defined(EFI32) && !defined(EFI64) 86 + #define DNSSD_API __stdcall 87 + #else 88 + #define DNSSD_API 89 + #endif 90 + 91 + /* stdint.h does not exist on FreeBSD 4.x; its types are defined in sys/types.h instead */ 92 + #if defined(__FreeBSD__) && (__FreeBSD__ < 5) 93 + #include <sys/types.h> 94 + 95 + /* Likewise, on Sun, standard integer types are in sys/types.h */ 96 + #elif defined(__sun__) 97 + #include <sys/types.h> 98 + 99 + /* EFI does not have stdint.h, or anything else equivalent */ 100 + #elif defined(EFI32) || defined(EFI64) || defined(EFIX64) 101 + #include "Tiano.h" 102 + #if !defined(_STDINT_H_) 103 + typedef UINT8 uint8_t; 104 + typedef INT8 int8_t; 105 + typedef UINT16 uint16_t; 106 + typedef INT16 int16_t; 107 + typedef UINT32 uint32_t; 108 + typedef INT32 int32_t; 109 + #endif 110 + /* Windows has its own differences */ 111 + #elif defined(_WIN32) 112 + #include <windows.h> 113 + #define _UNUSED 114 + #ifndef _MSL_STDINT_H 115 + typedef UINT8 uint8_t; 116 + typedef INT8 int8_t; 117 + typedef UINT16 uint16_t; 118 + typedef INT16 int16_t; 119 + typedef UINT32 uint32_t; 120 + typedef INT32 int32_t; 121 + #endif 122 + 123 + /* All other Posix platforms use stdint.h */ 124 + #else 125 + #include <stdint.h> 126 + #endif 127 + 128 + #if _DNS_SD_LIBDISPATCH 129 + #include <dispatch/dispatch.h> 130 + #endif 131 + 132 + /* DNSServiceRef, DNSRecordRef 133 + * 134 + * Opaque internal data types. 135 + * Note: client is responsible for serializing access to these structures if 136 + * they are shared between concurrent threads. 137 + */ 138 + 139 + typedef struct _DNSServiceRef_t *DNSServiceRef; 140 + typedef struct _DNSRecordRef_t *DNSRecordRef; 141 + 142 + struct sockaddr; 143 + 144 + /*! @enum General flags 145 + * Most DNS-SD API functions and callbacks include a DNSServiceFlags parameter. 146 + * As a general rule, any given bit in the 32-bit flags field has a specific fixed meaning, 147 + * regardless of the function or callback being used. For any given function or callback, 148 + * typically only a subset of the possible flags are meaningful, and all others should be zero. 149 + * The discussion section for each API call describes which flags are valid for that call 150 + * and callback. In some cases, for a particular call, it may be that no flags are currently 151 + * defined, in which case the DNSServiceFlags parameter exists purely to allow future expansion. 152 + * In all cases, developers should expect that in future releases, it is possible that new flag 153 + * values will be defined, and write code with this in mind. For example, code that tests 154 + * if (flags == kDNSServiceFlagsAdd) ... 155 + * will fail if, in a future release, another bit in the 32-bit flags field is also set. 156 + * The reliable way to test whether a particular bit is set is not with an equality test, 157 + * but with a bitwise mask: 158 + * if (flags & kDNSServiceFlagsAdd) ... 159 + * With the exception of kDNSServiceFlagsValidate, each flag can be valid(be set) 160 + * EITHER only as an input to one of the DNSService*() APIs OR only as an output 161 + * (provide status) through any of the callbacks used. For example, kDNSServiceFlagsAdd 162 + * can be set only as an output in the callback, whereas the kDNSServiceFlagsIncludeP2P 163 + * can be set only as an input to the DNSService*() APIs. See comments on kDNSServiceFlagsValidate 164 + * defined in enum below. 165 + */ 166 + enum 167 + { 168 + kDNSServiceFlagsMoreComing = 0x1, 169 + /* MoreComing indicates to a callback that at least one more result is 170 + * queued and will be delivered following immediately after this one. 171 + * When the MoreComing flag is set, applications should not immediately 172 + * update their UI, because this can result in a great deal of ugly flickering 173 + * on the screen, and can waste a great deal of CPU time repeatedly updating 174 + * the screen with content that is then immediately erased, over and over. 175 + * Applications should wait until MoreComing is not set, and then 176 + * update their UI when no more changes are imminent. 177 + * When MoreComing is not set, that doesn't mean there will be no more 178 + * answers EVER, just that there are no more answers immediately 179 + * available right now at this instant. If more answers become available 180 + * in the future they will be delivered as usual. 181 + */ 182 + 183 + kDNSServiceFlagsAdd = 0x2, 184 + kDNSServiceFlagsDefault = 0x4, 185 + /* Flags for domain enumeration and browse/query reply callbacks. 186 + * "Default" applies only to enumeration and is only valid in 187 + * conjunction with "Add". An enumeration callback with the "Add" 188 + * flag NOT set indicates a "Remove", i.e. the domain is no longer 189 + * valid. 190 + */ 191 + 192 + kDNSServiceFlagsNoAutoRename = 0x8, 193 + /* Flag for specifying renaming behavior on name conflict when registering 194 + * non-shared records. By default, name conflicts are automatically handled 195 + * by renaming the service. NoAutoRename overrides this behavior - with this 196 + * flag set, name conflicts will result in a callback. The NoAutorename flag 197 + * is only valid if a name is explicitly specified when registering a service 198 + * (i.e. the default name is not used.) 199 + */ 200 + 201 + kDNSServiceFlagsShared = 0x10, 202 + kDNSServiceFlagsUnique = 0x20, 203 + /* Flag for registering individual records on a connected 204 + * DNSServiceRef. Shared indicates that there may be multiple records 205 + * with this name on the network (e.g. PTR records). Unique indicates that the 206 + * record's name is to be unique on the network (e.g. SRV records). 207 + */ 208 + 209 + kDNSServiceFlagsBrowseDomains = 0x40, 210 + kDNSServiceFlagsRegistrationDomains = 0x80, 211 + /* Flags for specifying domain enumeration type in DNSServiceEnumerateDomains. 212 + * BrowseDomains enumerates domains recommended for browsing, RegistrationDomains 213 + * enumerates domains recommended for registration. 214 + */ 215 + 216 + kDNSServiceFlagsLongLivedQuery = 0x100, 217 + /* Flag for creating a long-lived unicast query for the DNSServiceQueryRecord call. */ 218 + 219 + kDNSServiceFlagsAllowRemoteQuery = 0x200, 220 + /* Flag for creating a record for which we will answer remote queries 221 + * (queries from hosts more than one hop away; hosts not directly connected to the local link). 222 + */ 223 + 224 + kDNSServiceFlagsForceMulticast = 0x400, 225 + /* Flag for signifying that a query or registration should be performed exclusively via multicast 226 + * DNS, even for a name in a domain (e.g. foo.apple.com.) that would normally imply unicast DNS. 227 + */ 228 + 229 + kDNSServiceFlagsForce = 0x800, // This flag is deprecated. 230 + 231 + kDNSServiceFlagsKnownUnique = 0x800, 232 + /* 233 + * Client guarantees that record names are unique, so we can skip sending out initial 234 + * probe messages. Standard name conflict resolution is still done if a conflict is discovered. 235 + * Currently only valid for a DNSServiceRegister call. 236 + */ 237 + 238 + kDNSServiceFlagsReturnIntermediates = 0x1000, 239 + /* Flag for returning intermediate results. 240 + * For example, if a query results in an authoritative NXDomain (name does not exist) 241 + * then that result is returned to the client. However the query is not implicitly 242 + * cancelled -- it remains active and if the answer subsequently changes 243 + * (e.g. because a VPN tunnel is subsequently established) then that positive 244 + * result will still be returned to the client. 245 + * Similarly, if a query results in a CNAME record, then in addition to following 246 + * the CNAME referral, the intermediate CNAME result is also returned to the client. 247 + * When this flag is not set, NXDomain errors are not returned, and CNAME records 248 + * are followed silently without informing the client of the intermediate steps. 249 + * (In earlier builds this flag was briefly calledkDNSServiceFlagsReturnCNAME) 250 + */ 251 + 252 + kDNSServiceFlagsNonBrowsable = 0x2000, 253 + /* A service registered with the NonBrowsable flag set can be resolved using 254 + * DNSServiceResolve(), but will not be discoverable using DNSServiceBrowse(). 255 + * This is for cases where the name is actually a GUID; it is found by other means; 256 + * there is no end-user benefit to browsing to find a long list of opaque GUIDs. 257 + * Using the NonBrowsable flag creates SRV+TXT without the cost of also advertising 258 + * an associated PTR record. 259 + */ 260 + 261 + kDNSServiceFlagsShareConnection = 0x4000, 262 + /* For efficiency, clients that perform many concurrent operations may want to use a 263 + * single Unix Domain Socket connection with the background daemon, instead of having a 264 + * separate connection for each independent operation. To use this mode, clients first 265 + * call DNSServiceCreateConnection(&MainRef) to initialize the main DNSServiceRef. 266 + * For each subsequent operation that is to share that same connection, the client copies 267 + * the MainRef, and then passes the address of that copy, setting the ShareConnection flag 268 + * to tell the library that this DNSServiceRef is not a typical uninitialized DNSServiceRef; 269 + * it's a copy of an existing DNSServiceRef whose connection information should be reused. 270 + * 271 + * For example: 272 + * 273 + * DNSServiceErrorType error; 274 + * DNSServiceRef MainRef; 275 + * error = DNSServiceCreateConnection(&MainRef); 276 + * if (error) ... 277 + * DNSServiceRef BrowseRef = MainRef; // Important: COPY the primary DNSServiceRef first... 278 + * error = DNSServiceBrowse(&BrowseRef, kDNSServiceFlagsShareConnection, ...); // then use the copy 279 + * if (error) ... 280 + * ... 281 + * DNSServiceRefDeallocate(BrowseRef); // Terminate the browse operation 282 + * DNSServiceRefDeallocate(MainRef); // Terminate the shared connection 283 + * Also see Point 4.(Don't Double-Deallocate if the MainRef has been Deallocated) in Notes below: 284 + * 285 + * Notes: 286 + * 287 + * 1. Collective kDNSServiceFlagsMoreComing flag 288 + * When callbacks are invoked using a shared DNSServiceRef, the 289 + * kDNSServiceFlagsMoreComing flag applies collectively to *all* active 290 + * operations sharing the same parent DNSServiceRef. If the MoreComing flag is 291 + * set it means that there are more results queued on this parent DNSServiceRef, 292 + * but not necessarily more results for this particular callback function. 293 + * The implication of this for client programmers is that when a callback 294 + * is invoked with the MoreComing flag set, the code should update its 295 + * internal data structures with the new result, and set a variable indicating 296 + * that its UI needs to be updated. Then, later when a callback is eventually 297 + * invoked with the MoreComing flag not set, the code should update *all* 298 + * stale UI elements related to that shared parent DNSServiceRef that need 299 + * updating, not just the UI elements related to the particular callback 300 + * that happened to be the last one to be invoked. 301 + * 302 + * 2. Canceling operations and kDNSServiceFlagsMoreComing 303 + * Whenever you cancel any operation for which you had deferred UI updates 304 + * waiting because of a kDNSServiceFlagsMoreComing flag, you should perform 305 + * those deferred UI updates. This is because, after cancelling the operation, 306 + * you can no longer wait for a callback *without* MoreComing set, to tell 307 + * you do perform your deferred UI updates (the operation has been canceled, 308 + * so there will be no more callbacks). An implication of the collective 309 + * kDNSServiceFlagsMoreComing flag for shared connections is that this 310 + * guideline applies more broadly -- any time you cancel an operation on 311 + * a shared connection, you should perform all deferred UI updates for all 312 + * operations sharing that connection. This is because the MoreComing flag 313 + * might have been referring to events coming for the operation you canceled, 314 + * which will now not be coming because the operation has been canceled. 315 + * 316 + * 3. Only share DNSServiceRef's created with DNSServiceCreateConnection 317 + * Calling DNSServiceCreateConnection(&ref) creates a special shareable DNSServiceRef. 318 + * DNSServiceRef's created by other calls like DNSServiceBrowse() or DNSServiceResolve() 319 + * cannot be shared by copying them and using kDNSServiceFlagsShareConnection. 320 + * 321 + * 4. Don't Double-Deallocate if the MainRef has been Deallocated 322 + * Calling DNSServiceRefDeallocate(ref) for a particular operation's DNSServiceRef terminates 323 + * just that operation. Calling DNSServiceRefDeallocate(ref) for the main shared DNSServiceRef 324 + * (the parent DNSServiceRef, originally created by DNSServiceCreateConnection(&ref)) 325 + * automatically terminates the shared connection and all operations that were still using it. 326 + * After doing this, DO NOT then attempt to deallocate any remaining subordinate DNSServiceRef's. 327 + * The memory used by those subordinate DNSServiceRef's has already been freed, so any attempt 328 + * to do a DNSServiceRefDeallocate (or any other operation) on them will result in accesses 329 + * to freed memory, leading to crashes or other equally undesirable results. 330 + * 331 + * 5. Thread Safety 332 + * The dns_sd.h API does not presuppose any particular threading model, and consequently 333 + * does no locking of its own (which would require linking some specific threading library). 334 + * If client code calls API routines on the same DNSServiceRef concurrently 335 + * from multiple threads, it is the client's responsibility to use a mutext 336 + * lock or take similar appropriate precautions to serialize those calls. 337 + */ 338 + 339 + kDNSServiceFlagsSuppressUnusable = 0x8000, 340 + /* 341 + * This flag is meaningful only in DNSServiceQueryRecord which suppresses unusable queries on the 342 + * wire. If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name) 343 + * but this host has no routable IPv6 address, then the call will not try to look up IPv6 addresses 344 + * for "hostname", since any addresses it found would be unlikely to be of any use anyway. Similarly, 345 + * if this host has no routable IPv4 address, the call will not try to look up IPv4 addresses for 346 + * "hostname". 347 + */ 348 + 349 + kDNSServiceFlagsTimeout = 0x10000, 350 + /* 351 + * When kDNServiceFlagsTimeout is passed to DNSServiceQueryRecord or DNSServiceGetAddrInfo, the query is 352 + * stopped after a certain number of seconds have elapsed. The time at which the query will be stopped 353 + * is determined by the system and cannot be configured by the user. The query will be stopped irrespective 354 + * of whether a response was given earlier or not. When the query is stopped, the callback will be called 355 + * with an error code of kDNSServiceErr_Timeout and a NULL sockaddr will be returned for DNSServiceGetAddrInfo 356 + * and zero length rdata will be returned for DNSServiceQueryRecord. 357 + */ 358 + 359 + kDNSServiceFlagsIncludeP2P = 0x20000, 360 + /* 361 + * Include P2P interfaces when kDNSServiceInterfaceIndexAny is specified. 362 + * By default, specifying kDNSServiceInterfaceIndexAny does not include P2P interfaces. 363 + */ 364 + 365 + kDNSServiceFlagsWakeOnResolve = 0x40000, 366 + /* 367 + * This flag is meaningful only in DNSServiceResolve. When set, it tries to send a magic packet 368 + * to wake up the client. 369 + */ 370 + 371 + kDNSServiceFlagsBackgroundTrafficClass = 0x80000, 372 + /* 373 + * This flag is meaningful for Unicast DNS queries. When set, it uses the background traffic 374 + * class for packets that service the request. 375 + */ 376 + 377 + kDNSServiceFlagsIncludeAWDL = 0x100000, 378 + /* 379 + * Include AWDL interface when kDNSServiceInterfaceIndexAny is specified. 380 + */ 381 + 382 + kDNSServiceFlagsValidate = 0x200000, 383 + /* 384 + * This flag is meaningful in DNSServiceGetAddrInfo and DNSServiceQueryRecord. This is the ONLY flag to be valid 385 + * as an input to the APIs and also an output through the callbacks in the APIs. 386 + * 387 + * When this flag is passed to DNSServiceQueryRecord and DNSServiceGetAddrInfo to resolve unicast names, 388 + * the response will be validated using DNSSEC. The validation results are delivered using the flags field in 389 + * the callback and kDNSServiceFlagsValidate is marked in the flags to indicate that DNSSEC status is also available. 390 + * When the callback is called to deliver the query results, the validation results may or may not be available. 391 + * If it is not delivered along with the results, the validation status is delivered when the validation completes. 392 + * 393 + * When the validation results are delivered in the callback, it is indicated by marking the flags with 394 + * kDNSServiceFlagsValidate and kDNSServiceFlagsAdd along with the DNSSEC status flags (described below) and a NULL 395 + * sockaddr will be returned for DNSServiceGetAddrInfo and zero length rdata will be returned for DNSServiceQueryRecord. 396 + * DNSSEC validation results are for the whole RRSet and not just individual records delivered in the callback. When 397 + * kDNSServiceFlagsAdd is not set in the flags, applications should implicitly assume that the DNSSEC status of the 398 + * RRSet that has been delivered up until that point is not valid anymore, till another callback is called with 399 + * kDNSServiceFlagsAdd and kDNSServiceFlagsValidate. 400 + * 401 + * The following four flags indicate the status of the DNSSEC validation and marked in the flags field of the callback. 402 + * When any of the four flags is set, kDNSServiceFlagsValidate will also be set. To check the validation status, the 403 + * other applicable output flags should be masked. See kDNSServiceOutputFlags below. 404 + */ 405 + 406 + kDNSServiceFlagsSecure = 0x200010, 407 + /* 408 + * The response has been validated by verifying all the signaures in the response and was able to 409 + * build a successful authentication chain starting from a known trust anchor. 410 + */ 411 + 412 + kDNSServiceFlagsInsecure = 0x200020, 413 + /* 414 + * A chain of trust cannot be built starting from a known trust anchor to the response. 415 + */ 416 + 417 + kDNSServiceFlagsBogus = 0x200040, 418 + /* 419 + * If the response cannot be verified to be secure due to expired signatures, missing signatures etc., 420 + * then the results are considered to be bogus. 421 + */ 422 + 423 + kDNSServiceFlagsIndeterminate = 0x200080, 424 + /* 425 + * There is no valid trust anchor that can be used to determine whether a response is secure or not. 426 + */ 427 + 428 + kDNSServiceFlagsUnicastResponse = 0x400000, 429 + /* 430 + * Request unicast response to query. 431 + */ 432 + kDNSServiceFlagsValidateOptional = 0x800000, 433 + 434 + /* 435 + * This flag is identical to kDNSServiceFlagsValidate except for the case where the response 436 + * cannot be validated. If this flag is set in DNSServiceQueryRecord or DNSServiceGetAddrInfo, 437 + * the DNSSEC records will be requested for validation. If they cannot be received for some reason 438 + * during the validation (e.g., zone is not signed, zone is signed but cannot be traced back to 439 + * root, recursive server does not understand DNSSEC etc.), then this will fallback to the default 440 + * behavior where the validation will not be performed and no DNSSEC results will be provided. 441 + * 442 + * If the zone is signed and there is a valid path to a known trust anchor configured in the system 443 + * and the application requires DNSSEC validation irrespective of the DNSSEC awareness in the current 444 + * network, then this option MUST not be used. This is only intended to be used during the transition 445 + * period where the different nodes participating in the DNS resolution may not understand DNSSEC or 446 + * managed properly (e.g. missing DS record) but still want to be able to resolve DNS successfully. 447 + */ 448 + 449 + kDNSServiceFlagsWakeOnlyService = 0x1000000, 450 + /* 451 + * This flag is meaningful only in DNSServiceRegister. When set, the service will not be registered 452 + * with sleep proxy server during sleep. 453 + */ 454 + 455 + kDNSServiceFlagsThresholdOne = 0x2000000, 456 + kDNSServiceFlagsThresholdFinder = 0x4000000, 457 + kDNSServiceFlagsThresholdReached = kDNSServiceFlagsThresholdOne, 458 + /* 459 + * kDNSServiceFlagsThresholdOne is meaningful only in DNSServiceBrowse. When set, 460 + * the system will stop issuing browse queries on the network once the number 461 + * of answers returned is one or more. It will issue queries on the network 462 + * again if the number of answers drops to zero. 463 + * This flag is for Apple internal use only. Third party developers 464 + * should not rely on this behavior being supported in any given software release. 465 + * 466 + * kDNSServiceFlagsThresholdFinder is meaningful only in DNSServiceBrowse. When set, 467 + * the system will stop issuing browse queries on the network once the number 468 + * of answers has reached the threshold set for Finder. 469 + * It will issue queries on the network again if the number of answers drops below 470 + * this threshold. 471 + * This flag is for Apple internal use only. Third party developers 472 + * should not rely on this behavior being supported in any given software release. 473 + * 474 + * When kDNSServiceFlagsThresholdReached is set in the client callback add or remove event, 475 + * it indicates that the browse answer threshold has been reached and no 476 + * browse requests will be generated on the network until the number of answers falls 477 + * below the threshold value. Add and remove events can still occur based 478 + * on incoming Bonjour traffic observed by the system. 479 + * The set of services return to the client is not guaranteed to represent the 480 + * entire set of services present on the network once the threshold has been reached. 481 + * 482 + * Note, while kDNSServiceFlagsThresholdReached and kDNSServiceFlagsThresholdOne 483 + * have the same value, there isn't a conflict because kDNSServiceFlagsThresholdReached 484 + * is only set in the callbacks and kDNSServiceFlagsThresholdOne is only set on 485 + * input to a DNSServiceBrowse call. 486 + */ 487 + kDNSServiceFlagsDenyCellular = 0x8000000, 488 + /* 489 + * This flag is meaningful only for Unicast DNS queries. When set, the kernel will restrict 490 + * DNS resolutions on the cellular interface for that request. 491 + */ 492 + 493 + kDNSServiceFlagsServiceIndex = 0x10000000, 494 + /* 495 + * This flag is meaningful only for DNSServiceGetAddrInfo() for Unicast DNS queries. 496 + * When set, DNSServiceGetAddrInfo() will interpret the "interfaceIndex" argument of the call 497 + * as the "serviceIndex". 498 + */ 499 + 500 + kDNSServiceFlagsDenyExpensive = 0x20000000 501 + /* 502 + * This flag is meaningful only for Unicast DNS queries. When set, the kernel will restrict 503 + * DNS resolutions on interfaces defined as expensive for that request. 504 + */ 505 + 506 + }; 507 + 508 + #define kDNSServiceOutputFlags (kDNSServiceFlagsValidate | kDNSServiceFlagsValidateOptional | kDNSServiceFlagsMoreComing | kDNSServiceFlagsAdd | kDNSServiceFlagsDefault) 509 + /* All the output flags excluding the DNSSEC Status flags. Typically used to check DNSSEC Status */ 510 + 511 + /* Possible protocol values */ 512 + enum 513 + { 514 + /* for DNSServiceGetAddrInfo() */ 515 + kDNSServiceProtocol_IPv4 = 0x01, 516 + kDNSServiceProtocol_IPv6 = 0x02, 517 + /* 0x04 and 0x08 reserved for future internetwork protocols */ 518 + 519 + /* for DNSServiceNATPortMappingCreate() */ 520 + kDNSServiceProtocol_UDP = 0x10, 521 + kDNSServiceProtocol_TCP = 0x20 522 + /* 0x40 and 0x80 reserved for future transport protocols, e.g. SCTP [RFC 2960] 523 + * or DCCP [RFC 4340]. If future NAT gateways are created that support port 524 + * mappings for these protocols, new constants will be defined here. 525 + */ 526 + }; 527 + 528 + /* 529 + * The values for DNS Classes and Types are listed in RFC 1035, and are available 530 + * on every OS in its DNS header file. Unfortunately every OS does not have the 531 + * same header file containing DNS Class and Type constants, and the names of 532 + * the constants are not consistent. For example, BIND 8 uses "T_A", 533 + * BIND 9 uses "ns_t_a", Windows uses "DNS_TYPE_A", etc. 534 + * For this reason, these constants are also listed here, so that code using 535 + * the DNS-SD programming APIs can use these constants, so that the same code 536 + * can compile on all our supported platforms. 537 + */ 538 + 539 + enum 540 + { 541 + kDNSServiceClass_IN = 1 /* Internet */ 542 + }; 543 + 544 + enum 545 + { 546 + kDNSServiceType_A = 1, /* Host address. */ 547 + kDNSServiceType_NS = 2, /* Authoritative server. */ 548 + kDNSServiceType_MD = 3, /* Mail destination. */ 549 + kDNSServiceType_MF = 4, /* Mail forwarder. */ 550 + kDNSServiceType_CNAME = 5, /* Canonical name. */ 551 + kDNSServiceType_SOA = 6, /* Start of authority zone. */ 552 + kDNSServiceType_MB = 7, /* Mailbox domain name. */ 553 + kDNSServiceType_MG = 8, /* Mail group member. */ 554 + kDNSServiceType_MR = 9, /* Mail rename name. */ 555 + kDNSServiceType_NULL = 10, /* Null resource record. */ 556 + kDNSServiceType_WKS = 11, /* Well known service. */ 557 + kDNSServiceType_PTR = 12, /* Domain name pointer. */ 558 + kDNSServiceType_HINFO = 13, /* Host information. */ 559 + kDNSServiceType_MINFO = 14, /* Mailbox information. */ 560 + kDNSServiceType_MX = 15, /* Mail routing information. */ 561 + kDNSServiceType_TXT = 16, /* One or more text strings (NOT "zero or more..."). */ 562 + kDNSServiceType_RP = 17, /* Responsible person. */ 563 + kDNSServiceType_AFSDB = 18, /* AFS cell database. */ 564 + kDNSServiceType_X25 = 19, /* X_25 calling address. */ 565 + kDNSServiceType_ISDN = 20, /* ISDN calling address. */ 566 + kDNSServiceType_RT = 21, /* Router. */ 567 + kDNSServiceType_NSAP = 22, /* NSAP address. */ 568 + kDNSServiceType_NSAP_PTR = 23, /* Reverse NSAP lookup (deprecated). */ 569 + kDNSServiceType_SIG = 24, /* Security signature. */ 570 + kDNSServiceType_KEY = 25, /* Security key. */ 571 + kDNSServiceType_PX = 26, /* X.400 mail mapping. */ 572 + kDNSServiceType_GPOS = 27, /* Geographical position (withdrawn). */ 573 + kDNSServiceType_AAAA = 28, /* IPv6 Address. */ 574 + kDNSServiceType_LOC = 29, /* Location Information. */ 575 + kDNSServiceType_NXT = 30, /* Next domain (security). */ 576 + kDNSServiceType_EID = 31, /* Endpoint identifier. */ 577 + kDNSServiceType_NIMLOC = 32, /* Nimrod Locator. */ 578 + kDNSServiceType_SRV = 33, /* Server Selection. */ 579 + kDNSServiceType_ATMA = 34, /* ATM Address */ 580 + kDNSServiceType_NAPTR = 35, /* Naming Authority PoinTeR */ 581 + kDNSServiceType_KX = 36, /* Key Exchange */ 582 + kDNSServiceType_CERT = 37, /* Certification record */ 583 + kDNSServiceType_A6 = 38, /* IPv6 Address (deprecated) */ 584 + kDNSServiceType_DNAME = 39, /* Non-terminal DNAME (for IPv6) */ 585 + kDNSServiceType_SINK = 40, /* Kitchen sink (experimental) */ 586 + kDNSServiceType_OPT = 41, /* EDNS0 option (meta-RR) */ 587 + kDNSServiceType_APL = 42, /* Address Prefix List */ 588 + kDNSServiceType_DS = 43, /* Delegation Signer */ 589 + kDNSServiceType_SSHFP = 44, /* SSH Key Fingerprint */ 590 + kDNSServiceType_IPSECKEY = 45, /* IPSECKEY */ 591 + kDNSServiceType_RRSIG = 46, /* RRSIG */ 592 + kDNSServiceType_NSEC = 47, /* Denial of Existence */ 593 + kDNSServiceType_DNSKEY = 48, /* DNSKEY */ 594 + kDNSServiceType_DHCID = 49, /* DHCP Client Identifier */ 595 + kDNSServiceType_NSEC3 = 50, /* Hashed Authenticated Denial of Existence */ 596 + kDNSServiceType_NSEC3PARAM = 51, /* Hashed Authenticated Denial of Existence */ 597 + 598 + kDNSServiceType_HIP = 55, /* Host Identity Protocol */ 599 + 600 + kDNSServiceType_SPF = 99, /* Sender Policy Framework for E-Mail */ 601 + kDNSServiceType_UINFO = 100, /* IANA-Reserved */ 602 + kDNSServiceType_UID = 101, /* IANA-Reserved */ 603 + kDNSServiceType_GID = 102, /* IANA-Reserved */ 604 + kDNSServiceType_UNSPEC = 103, /* IANA-Reserved */ 605 + 606 + kDNSServiceType_TKEY = 249, /* Transaction key */ 607 + kDNSServiceType_TSIG = 250, /* Transaction signature. */ 608 + kDNSServiceType_IXFR = 251, /* Incremental zone transfer. */ 609 + kDNSServiceType_AXFR = 252, /* Transfer zone of authority. */ 610 + kDNSServiceType_MAILB = 253, /* Transfer mailbox records. */ 611 + kDNSServiceType_MAILA = 254, /* Transfer mail agent records. */ 612 + kDNSServiceType_ANY = 255 /* Wildcard match. */ 613 + }; 614 + 615 + /* possible error code values */ 616 + enum 617 + { 618 + kDNSServiceErr_NoError = 0, 619 + kDNSServiceErr_Unknown = -65537, /* 0xFFFE FFFF */ 620 + kDNSServiceErr_NoSuchName = -65538, 621 + kDNSServiceErr_NoMemory = -65539, 622 + kDNSServiceErr_BadParam = -65540, 623 + kDNSServiceErr_BadReference = -65541, 624 + kDNSServiceErr_BadState = -65542, 625 + kDNSServiceErr_BadFlags = -65543, 626 + kDNSServiceErr_Unsupported = -65544, 627 + kDNSServiceErr_NotInitialized = -65545, 628 + kDNSServiceErr_AlreadyRegistered = -65547, 629 + kDNSServiceErr_NameConflict = -65548, 630 + kDNSServiceErr_Invalid = -65549, 631 + kDNSServiceErr_Firewall = -65550, 632 + kDNSServiceErr_Incompatible = -65551, /* client library incompatible with daemon */ 633 + kDNSServiceErr_BadInterfaceIndex = -65552, 634 + kDNSServiceErr_Refused = -65553, 635 + kDNSServiceErr_NoSuchRecord = -65554, 636 + kDNSServiceErr_NoAuth = -65555, 637 + kDNSServiceErr_NoSuchKey = -65556, 638 + kDNSServiceErr_NATTraversal = -65557, 639 + kDNSServiceErr_DoubleNAT = -65558, 640 + kDNSServiceErr_BadTime = -65559, /* Codes up to here existed in Tiger */ 641 + kDNSServiceErr_BadSig = -65560, 642 + kDNSServiceErr_BadKey = -65561, 643 + kDNSServiceErr_Transient = -65562, 644 + kDNSServiceErr_ServiceNotRunning = -65563, /* Background daemon not running */ 645 + kDNSServiceErr_NATPortMappingUnsupported = -65564, /* NAT doesn't support PCP, NAT-PMP or UPnP */ 646 + kDNSServiceErr_NATPortMappingDisabled = -65565, /* NAT supports PCP, NAT-PMP or UPnP, but it's disabled by the administrator */ 647 + kDNSServiceErr_NoRouter = -65566, /* No router currently configured (probably no network connectivity) */ 648 + kDNSServiceErr_PollingMode = -65567, 649 + kDNSServiceErr_Timeout = -65568 650 + 651 + /* mDNS Error codes are in the range 652 + * FFFE FF00 (-65792) to FFFE FFFF (-65537) */ 653 + }; 654 + 655 + /* Maximum length, in bytes, of a service name represented as a */ 656 + /* literal C-String, including the terminating NULL at the end. */ 657 + 658 + #define kDNSServiceMaxServiceName 64 659 + 660 + /* Maximum length, in bytes, of a domain name represented as an *escaped* C-String */ 661 + /* including the final trailing dot, and the C-String terminating NULL at the end. */ 662 + 663 + #define kDNSServiceMaxDomainName 1009 664 + 665 + /* 666 + * Notes on DNS Name Escaping 667 + * -- or -- 668 + * "Why is kDNSServiceMaxDomainName 1009, when the maximum legal domain name is 256 bytes?" 669 + * 670 + * All strings used in the DNS-SD APIs are UTF-8 strings. Apart from the exceptions noted below, 671 + * the APIs expect the strings to be properly escaped, using the conventional DNS escaping rules: 672 + * 673 + * '\\' represents a single literal '\' in the name 674 + * '\.' represents a single literal '.' in the name 675 + * '\ddd', where ddd is a three-digit decimal value from 000 to 255, 676 + * represents a single literal byte with that value. 677 + * A bare unescaped '.' is a label separator, marking a boundary between domain and subdomain. 678 + * 679 + * The exceptions, that do not use escaping, are the routines where the full 680 + * DNS name of a resource is broken, for convenience, into servicename/regtype/domain. 681 + * In these routines, the "servicename" is NOT escaped. It does not need to be, since 682 + * it is, by definition, just a single literal string. Any characters in that string 683 + * represent exactly what they are. The "regtype" portion is, technically speaking, 684 + * escaped, but since legal regtypes are only allowed to contain letters, digits, 685 + * and hyphens, there is nothing to escape, so the issue is moot. The "domain" 686 + * portion is also escaped, though most domains in use on the public Internet 687 + * today, like regtypes, don't contain any characters that need to be escaped. 688 + * As DNS-SD becomes more popular, rich-text domains for service discovery will 689 + * become common, so software should be written to cope with domains with escaping. 690 + * 691 + * The servicename may be up to 63 bytes of UTF-8 text (not counting the C-String 692 + * terminating NULL at the end). The regtype is of the form _service._tcp or 693 + * _service._udp, where the "service" part is 1-15 characters, which may be 694 + * letters, digits, or hyphens. The domain part of the three-part name may be 695 + * any legal domain, providing that the resulting servicename+regtype+domain 696 + * name does not exceed 256 bytes. 697 + * 698 + * For most software, these issues are transparent. When browsing, the discovered 699 + * servicenames should simply be displayed as-is. When resolving, the discovered 700 + * servicename/regtype/domain are simply passed unchanged to DNSServiceResolve(). 701 + * When a DNSServiceResolve() succeeds, the returned fullname is already in 702 + * the correct format to pass to standard system DNS APIs such as res_query(). 703 + * For converting from servicename/regtype/domain to a single properly-escaped 704 + * full DNS name, the helper function DNSServiceConstructFullName() is provided. 705 + * 706 + * The following (highly contrived) example illustrates the escaping process. 707 + * Suppose you have an service called "Dr. Smith\Dr. Johnson", of type "_ftp._tcp" 708 + * in subdomain "4th. Floor" of subdomain "Building 2" of domain "apple.com." 709 + * The full (escaped) DNS name of this service's SRV record would be: 710 + * Dr\.\032Smith\\Dr\.\032Johnson._ftp._tcp.4th\.\032Floor.Building\0322.apple.com. 711 + */ 712 + 713 + 714 + /* 715 + * Constants for specifying an interface index 716 + * 717 + * Specific interface indexes are identified via a 32-bit unsigned integer returned 718 + * by the if_nametoindex() family of calls. 719 + * 720 + * If the client passes 0 for interface index, that means "do the right thing", 721 + * which (at present) means, "if the name is in an mDNS local multicast domain 722 + * (e.g. 'local.', '254.169.in-addr.arpa.', '{8,9,A,B}.E.F.ip6.arpa.') then multicast 723 + * on all applicable interfaces, otherwise send via unicast to the appropriate 724 + * DNS server." Normally, most clients will use 0 for interface index to 725 + * automatically get the default sensible behaviour. 726 + * 727 + * If the client passes a positive interface index, then for multicast names that 728 + * indicates to do the operation only on that one interface. For unicast names the 729 + * interface index is ignored unless kDNSServiceFlagsForceMulticast is also set. 730 + * 731 + * If the client passes kDNSServiceInterfaceIndexLocalOnly when registering 732 + * a service, then that service will be found *only* by other local clients 733 + * on the same machine that are browsing using kDNSServiceInterfaceIndexLocalOnly 734 + * or kDNSServiceInterfaceIndexAny. 735 + * If a client has a 'private' service, accessible only to other processes 736 + * running on the same machine, this allows the client to advertise that service 737 + * in a way such that it does not inadvertently appear in service lists on 738 + * all the other machines on the network. 739 + * 740 + * If the client passes kDNSServiceInterfaceIndexLocalOnly when browsing 741 + * then it will find *all* records registered on that same local machine. 742 + * Clients explicitly wishing to discover *only* LocalOnly services can 743 + * accomplish this by inspecting the interfaceIndex of each service reported 744 + * to their DNSServiceBrowseReply() callback function, and discarding those 745 + * where the interface index is not kDNSServiceInterfaceIndexLocalOnly. 746 + * 747 + * kDNSServiceInterfaceIndexP2P is meaningful only in Browse, QueryRecord, Register, 748 + * and Resolve operations. It should not be used in other DNSService APIs. 749 + * 750 + * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceBrowse or 751 + * DNSServiceQueryRecord, it restricts the operation to P2P. 752 + * 753 + * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceRegister, it is 754 + * mapped internally to kDNSServiceInterfaceIndexAny with the kDNSServiceFlagsIncludeP2P 755 + * set. 756 + * 757 + * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceResolve, it is 758 + * mapped internally to kDNSServiceInterfaceIndexAny with the kDNSServiceFlagsIncludeP2P 759 + * set, because resolving a P2P service may create and/or enable an interface whose 760 + * index is not known a priori. The resolve callback will indicate the index of the 761 + * interface via which the service can be accessed. 762 + * 763 + * If applications pass kDNSServiceInterfaceIndexAny to DNSServiceBrowse 764 + * or DNSServiceQueryRecord, they must set the kDNSServiceFlagsIncludeP2P flag 765 + * to include P2P. In this case, if a service instance or the record being queried 766 + * is found over P2P, the resulting ADD event will indicate kDNSServiceInterfaceIndexP2P 767 + * as the interface index. 768 + */ 769 + 770 + #define kDNSServiceInterfaceIndexAny 0 771 + #define kDNSServiceInterfaceIndexLocalOnly ((uint32_t)-1) 772 + #define kDNSServiceInterfaceIndexUnicast ((uint32_t)-2) 773 + #define kDNSServiceInterfaceIndexP2P ((uint32_t)-3) 774 + 775 + typedef uint32_t DNSServiceFlags; 776 + typedef uint32_t DNSServiceProtocol; 777 + typedef int32_t DNSServiceErrorType; 778 + 779 + 780 + /********************************************************************************************* 781 + * 782 + * Version checking 783 + * 784 + *********************************************************************************************/ 785 + 786 + /* DNSServiceGetProperty() Parameters: 787 + * 788 + * property: The requested property. 789 + * Currently the only property defined is kDNSServiceProperty_DaemonVersion. 790 + * 791 + * result: Place to store result. 792 + * For retrieving DaemonVersion, this should be the address of a uint32_t. 793 + * 794 + * size: Pointer to uint32_t containing size of the result location. 795 + * For retrieving DaemonVersion, this should be sizeof(uint32_t). 796 + * On return the uint32_t is updated to the size of the data returned. 797 + * For DaemonVersion, the returned size is always sizeof(uint32_t), but 798 + * future properties could be defined which return variable-sized results. 799 + * 800 + * return value: Returns kDNSServiceErr_NoError on success, or kDNSServiceErr_ServiceNotRunning 801 + * if the daemon (or "system service" on Windows) is not running. 802 + */ 803 + 804 + DNSServiceErrorType DNSSD_API DNSServiceGetProperty 805 + ( 806 + const char *property, /* Requested property (i.e. kDNSServiceProperty_DaemonVersion) */ 807 + void *result, /* Pointer to place to store result */ 808 + uint32_t *size /* size of result location */ 809 + ); 810 + 811 + /* 812 + * When requesting kDNSServiceProperty_DaemonVersion, the result pointer must point 813 + * to a 32-bit unsigned integer, and the size parameter must be set to sizeof(uint32_t). 814 + * 815 + * On return, the 32-bit unsigned integer contains the API version number 816 + * 817 + * For example, Mac OS X 10.4.9 has API version 1080400. 818 + * This allows applications to do simple greater-than and less-than comparisons: 819 + * e.g. an application that requires at least API version 1080400 can check: 820 + * if (version >= 1080400) ... 821 + * 822 + * Example usage: 823 + * uint32_t version; 824 + * uint32_t size = sizeof(version); 825 + * DNSServiceErrorType err = DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &version, &size); 826 + * if (!err) printf("DNS_SD API version is %d.%d\n", version / 10000, version / 100 % 100); 827 + */ 828 + 829 + #define kDNSServiceProperty_DaemonVersion "DaemonVersion" 830 + 831 + 832 + // Map the source port of the local UDP socket that was opened for sending the DNS query 833 + // to the process ID of the application that triggered the DNS resolution. 834 + // 835 + /* DNSServiceGetPID() Parameters: 836 + * 837 + * srcport: Source port (in network byte order) of the UDP socket that was created by 838 + * the daemon to send the DNS query on the wire. 839 + * 840 + * pid: Process ID of the application that started the name resolution which triggered 841 + * the daemon to send the query on the wire. The value can be -1 if the srcport 842 + * cannot be mapped. 843 + * 844 + * return value: Returns kDNSServiceErr_NoError on success, or kDNSServiceErr_ServiceNotRunning 845 + * if the daemon is not running. The value of the pid is undefined if the return 846 + * value has error. 847 + */ 848 + DNSServiceErrorType DNSSD_API DNSServiceGetPID 849 + ( 850 + uint16_t srcport, 851 + int32_t *pid 852 + ); 853 + 854 + /********************************************************************************************* 855 + * 856 + * Unix Domain Socket access, DNSServiceRef deallocation, and data processing functions 857 + * 858 + *********************************************************************************************/ 859 + 860 + /* DNSServiceRefSockFD() 861 + * 862 + * Access underlying Unix domain socket for an initialized DNSServiceRef. 863 + * The DNS Service Discovery implementation uses this socket to communicate between the client and 864 + * the daemon. The application MUST NOT directly read from or write to this socket. 865 + * Access to the socket is provided so that it can be used as a kqueue event source, a CFRunLoop 866 + * event source, in a select() loop, etc. When the underlying event management subsystem (kqueue/ 867 + * select/CFRunLoop etc.) indicates to the client that data is available for reading on the 868 + * socket, the client should call DNSServiceProcessResult(), which will extract the daemon's 869 + * reply from the socket, and pass it to the appropriate application callback. By using a run 870 + * loop or select(), results from the daemon can be processed asynchronously. Alternatively, 871 + * a client can choose to fork a thread and have it loop calling "DNSServiceProcessResult(ref);" 872 + * If DNSServiceProcessResult() is called when no data is available for reading on the socket, it 873 + * will block until data does become available, and then process the data and return to the caller. 874 + * The application is reponsible for checking the return value of DNSServiceProcessResult() to determine 875 + * if the socket is valid and if it should continue to process data on the socket. 876 + * When data arrives on the socket, the client is responsible for calling DNSServiceProcessResult(ref) 877 + * in a timely fashion -- if the client allows a large backlog of data to build up the daemon 878 + * may terminate the connection. 879 + * 880 + * sdRef: A DNSServiceRef initialized by any of the DNSService calls. 881 + * 882 + * return value: The DNSServiceRef's underlying socket descriptor, or -1 on 883 + * error. 884 + */ 885 + 886 + int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef); 887 + 888 + 889 + /* DNSServiceProcessResult() 890 + * 891 + * Read a reply from the daemon, calling the appropriate application callback. This call will 892 + * block until the daemon's response is received. Use DNSServiceRefSockFD() in 893 + * conjunction with a run loop or select() to determine the presence of a response from the 894 + * server before calling this function to process the reply without blocking. Call this function 895 + * at any point if it is acceptable to block until the daemon's response arrives. Note that the 896 + * client is responsible for ensuring that DNSServiceProcessResult() is called whenever there is 897 + * a reply from the daemon - the daemon may terminate its connection with a client that does not 898 + * process the daemon's responses. 899 + * 900 + * sdRef: A DNSServiceRef initialized by any of the DNSService calls 901 + * that take a callback parameter. 902 + * 903 + * return value: Returns kDNSServiceErr_NoError on success, otherwise returns 904 + * an error code indicating the specific failure that occurred. 905 + */ 906 + 907 + DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef); 908 + 909 + 910 + /* DNSServiceRefDeallocate() 911 + * 912 + * Terminate a connection with the daemon and free memory associated with the DNSServiceRef. 913 + * Any services or records registered with this DNSServiceRef will be deregistered. Any 914 + * Browse, Resolve, or Query operations called with this reference will be terminated. 915 + * 916 + * Note: If the reference's underlying socket is used in a run loop or select() call, it should 917 + * be removed BEFORE DNSServiceRefDeallocate() is called, as this function closes the reference's 918 + * socket. 919 + * 920 + * Note: If the reference was initialized with DNSServiceCreateConnection(), any DNSRecordRefs 921 + * created via this reference will be invalidated by this call - the resource records are 922 + * deregistered, and their DNSRecordRefs may not be used in subsequent functions. Similarly, 923 + * if the reference was initialized with DNSServiceRegister, and an extra resource record was 924 + * added to the service via DNSServiceAddRecord(), the DNSRecordRef created by the Add() call 925 + * is invalidated when this function is called - the DNSRecordRef may not be used in subsequent 926 + * functions. 927 + * 928 + * Note: This call is to be used only with the DNSServiceRef defined by this API. 929 + * 930 + * sdRef: A DNSServiceRef initialized by any of the DNSService calls. 931 + * 932 + */ 933 + 934 + void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef); 935 + 936 + 937 + /********************************************************************************************* 938 + * 939 + * Domain Enumeration 940 + * 941 + *********************************************************************************************/ 942 + 943 + /* DNSServiceEnumerateDomains() 944 + * 945 + * Asynchronously enumerate domains available for browsing and registration. 946 + * 947 + * The enumeration MUST be cancelled via DNSServiceRefDeallocate() when no more domains 948 + * are to be found. 949 + * 950 + * Note that the names returned are (like all of DNS-SD) UTF-8 strings, 951 + * and are escaped using standard DNS escaping rules. 952 + * (See "Notes on DNS Name Escaping" earlier in this file for more details.) 953 + * A graphical browser displaying a hierarchical tree-structured view should cut 954 + * the names at the bare dots to yield individual labels, then de-escape each 955 + * label according to the escaping rules, and then display the resulting UTF-8 text. 956 + * 957 + * DNSServiceDomainEnumReply Callback Parameters: 958 + * 959 + * sdRef: The DNSServiceRef initialized by DNSServiceEnumerateDomains(). 960 + * 961 + * flags: Possible values are: 962 + * kDNSServiceFlagsMoreComing 963 + * kDNSServiceFlagsAdd 964 + * kDNSServiceFlagsDefault 965 + * 966 + * interfaceIndex: Specifies the interface on which the domain exists. (The index for a given 967 + * interface is determined via the if_nametoindex() family of calls.) 968 + * 969 + * errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise indicates 970 + * the failure that occurred (other parameters are undefined if errorCode is nonzero). 971 + * 972 + * replyDomain: The name of the domain. 973 + * 974 + * context: The context pointer passed to DNSServiceEnumerateDomains. 975 + * 976 + */ 977 + 978 + typedef void (DNSSD_API *DNSServiceDomainEnumReply) 979 + ( 980 + DNSServiceRef sdRef, 981 + DNSServiceFlags flags, 982 + uint32_t interfaceIndex, 983 + DNSServiceErrorType errorCode, 984 + const char *replyDomain, 985 + void *context 986 + ); 987 + 988 + 989 + /* DNSServiceEnumerateDomains() Parameters: 990 + * 991 + * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds 992 + * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError, 993 + * and the enumeration operation will run indefinitely until the client 994 + * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate(). 995 + * 996 + * flags: Possible values are: 997 + * kDNSServiceFlagsBrowseDomains to enumerate domains recommended for browsing. 998 + * kDNSServiceFlagsRegistrationDomains to enumerate domains recommended 999 + * for registration. 1000 + * 1001 + * interfaceIndex: If non-zero, specifies the interface on which to look for domains. 1002 + * (the index for a given interface is determined via the if_nametoindex() 1003 + * family of calls.) Most applications will pass 0 to enumerate domains on 1004 + * all interfaces. See "Constants for specifying an interface index" for more details. 1005 + * 1006 + * callBack: The function to be called when a domain is found or the call asynchronously 1007 + * fails. 1008 + * 1009 + * context: An application context pointer which is passed to the callback function 1010 + * (may be NULL). 1011 + * 1012 + * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous 1013 + * errors are delivered to the callback), otherwise returns an error code indicating 1014 + * the error that occurred (the callback is not invoked and the DNSServiceRef 1015 + * is not initialized). 1016 + */ 1017 + 1018 + DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains 1019 + ( 1020 + DNSServiceRef *sdRef, 1021 + DNSServiceFlags flags, 1022 + uint32_t interfaceIndex, 1023 + DNSServiceDomainEnumReply callBack, 1024 + void *context /* may be NULL */ 1025 + ); 1026 + 1027 + 1028 + /********************************************************************************************* 1029 + * 1030 + * Service Registration 1031 + * 1032 + *********************************************************************************************/ 1033 + 1034 + /* Register a service that is discovered via Browse() and Resolve() calls. 1035 + * 1036 + * DNSServiceRegisterReply() Callback Parameters: 1037 + * 1038 + * sdRef: The DNSServiceRef initialized by DNSServiceRegister(). 1039 + * 1040 + * flags: When a name is successfully registered, the callback will be 1041 + * invoked with the kDNSServiceFlagsAdd flag set. When Wide-Area 1042 + * DNS-SD is in use, it is possible for a single service to get 1043 + * more than one success callback (e.g. one in the "local" multicast 1044 + * DNS domain, and another in a wide-area unicast DNS domain). 1045 + * If a successfully-registered name later suffers a name conflict 1046 + * or similar problem and has to be deregistered, the callback will 1047 + * be invoked with the kDNSServiceFlagsAdd flag not set. The callback 1048 + * is *not* invoked in the case where the caller explicitly terminates 1049 + * the service registration by calling DNSServiceRefDeallocate(ref); 1050 + * 1051 + * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will 1052 + * indicate the failure that occurred (including name conflicts, 1053 + * if the kDNSServiceFlagsNoAutoRename flag was used when registering.) 1054 + * Other parameters are undefined if errorCode is nonzero. 1055 + * 1056 + * name: The service name registered (if the application did not specify a name in 1057 + * DNSServiceRegister(), this indicates what name was automatically chosen). 1058 + * 1059 + * regtype: The type of service registered, as it was passed to the callout. 1060 + * 1061 + * domain: The domain on which the service was registered (if the application did not 1062 + * specify a domain in DNSServiceRegister(), this indicates the default domain 1063 + * on which the service was registered). 1064 + * 1065 + * context: The context pointer that was passed to the callout. 1066 + * 1067 + */ 1068 + 1069 + typedef void (DNSSD_API *DNSServiceRegisterReply) 1070 + ( 1071 + DNSServiceRef sdRef, 1072 + DNSServiceFlags flags, 1073 + DNSServiceErrorType errorCode, 1074 + const char *name, 1075 + const char *regtype, 1076 + const char *domain, 1077 + void *context 1078 + ); 1079 + 1080 + 1081 + /* DNSServiceRegister() Parameters: 1082 + * 1083 + * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds 1084 + * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError, 1085 + * and the registration will remain active indefinitely until the client 1086 + * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate(). 1087 + * 1088 + * interfaceIndex: If non-zero, specifies the interface on which to register the service 1089 + * (the index for a given interface is determined via the if_nametoindex() 1090 + * family of calls.) Most applications will pass 0 to register on all 1091 + * available interfaces. See "Constants for specifying an interface index" for more details. 1092 + * 1093 + * flags: Indicates the renaming behavior on name conflict (most applications 1094 + * will pass 0). See flag definitions above for details. 1095 + * 1096 + * name: If non-NULL, specifies the service name to be registered. 1097 + * Most applications will not specify a name, in which case the computer 1098 + * name is used (this name is communicated to the client via the callback). 1099 + * If a name is specified, it must be 1-63 bytes of UTF-8 text. 1100 + * If the name is longer than 63 bytes it will be automatically truncated 1101 + * to a legal length, unless the NoAutoRename flag is set, 1102 + * in which case kDNSServiceErr_BadParam will be returned. 1103 + * 1104 + * regtype: The service type followed by the protocol, separated by a dot 1105 + * (e.g. "_ftp._tcp"). The service type must be an underscore, followed 1106 + * by 1-15 characters, which may be letters, digits, or hyphens. 1107 + * The transport protocol must be "_tcp" or "_udp". New service types 1108 + * should be registered at <http://www.dns-sd.org/ServiceTypes.html>. 1109 + * 1110 + * Additional subtypes of the primary service type (where a service 1111 + * type has defined subtypes) follow the primary service type in a 1112 + * comma-separated list, with no additional spaces, e.g. 1113 + * "_primarytype._tcp,_subtype1,_subtype2,_subtype3" 1114 + * Subtypes provide a mechanism for filtered browsing: A client browsing 1115 + * for "_primarytype._tcp" will discover all instances of this type; 1116 + * a client browsing for "_primarytype._tcp,_subtype2" will discover only 1117 + * those instances that were registered with "_subtype2" in their list of 1118 + * registered subtypes. 1119 + * 1120 + * The subtype mechanism can be illustrated with some examples using the 1121 + * dns-sd command-line tool: 1122 + * 1123 + * % dns-sd -R Simple _test._tcp "" 1001 & 1124 + * % dns-sd -R Better _test._tcp,HasFeatureA "" 1002 & 1125 + * % dns-sd -R Best _test._tcp,HasFeatureA,HasFeatureB "" 1003 & 1126 + * 1127 + * Now: 1128 + * % dns-sd -B _test._tcp # will find all three services 1129 + * % dns-sd -B _test._tcp,HasFeatureA # finds "Better" and "Best" 1130 + * % dns-sd -B _test._tcp,HasFeatureB # finds only "Best" 1131 + * 1132 + * Subtype labels may be up to 63 bytes long, and may contain any eight- 1133 + * bit byte values, including zero bytes. However, due to the nature of 1134 + * using a C-string-based API, conventional DNS escaping must be used for 1135 + * dots ('.'), commas (','), backslashes ('\') and zero bytes, as shown below: 1136 + * 1137 + * % dns-sd -R Test '_test._tcp,s\.one,s\,two,s\\three,s\000four' local 123 1138 + * 1139 + * When a service is registered, all the clients browsing for the registered 1140 + * type ("regtype") will discover it. If the discovery should be 1141 + * restricted to a smaller set of well known peers, the service can be 1142 + * registered with additional data (group identifier) that is known 1143 + * only to a smaller set of peers. The group identifier should follow primary 1144 + * service type using a colon (":") as a delimeter. If subtypes are also present, 1145 + * it should be given before the subtype as shown below. 1146 + * 1147 + * % dns-sd -R _test1 _http._tcp:mygroup1 local 1001 1148 + * % dns-sd -R _test2 _http._tcp:mygroup2 local 1001 1149 + * % dns-sd -R _test3 _http._tcp:mygroup3,HasFeatureA local 1001 1150 + * 1151 + * Now: 1152 + * % dns-sd -B _http._tcp:"mygroup1" # will discover only test1 1153 + * % dns-sd -B _http._tcp:"mygroup2" # will discover only test2 1154 + * % dns-sd -B _http._tcp:"mygroup3",HasFeatureA # will discover only test3 1155 + * 1156 + * By specifying the group information, only the members of that group are 1157 + * discovered. 1158 + * 1159 + * The group identifier itself is not sent in clear. Only a hash of the group 1160 + * identifier is sent and the clients discover them anonymously. The group identifier 1161 + * may be up to 256 bytes long and may contain any eight bit values except comma which 1162 + * should be escaped. 1163 + * 1164 + * domain: If non-NULL, specifies the domain on which to advertise the service. 1165 + * Most applications will not specify a domain, instead automatically 1166 + * registering in the default domain(s). 1167 + * 1168 + * host: If non-NULL, specifies the SRV target host name. Most applications 1169 + * will not specify a host, instead automatically using the machine's 1170 + * default host name(s). Note that specifying a non-NULL host does NOT 1171 + * create an address record for that host - the application is responsible 1172 + * for ensuring that the appropriate address record exists, or creating it 1173 + * via DNSServiceRegisterRecord(). 1174 + * 1175 + * port: The port, in network byte order, on which the service accepts connections. 1176 + * Pass 0 for a "placeholder" service (i.e. a service that will not be discovered 1177 + * by browsing, but will cause a name conflict if another client tries to 1178 + * register that same name). Most clients will not use placeholder services. 1179 + * 1180 + * txtLen: The length of the txtRecord, in bytes. Must be zero if the txtRecord is NULL. 1181 + * 1182 + * txtRecord: The TXT record rdata. A non-NULL txtRecord MUST be a properly formatted DNS 1183 + * TXT record, i.e. <length byte> <data> <length byte> <data> ... 1184 + * Passing NULL for the txtRecord is allowed as a synonym for txtLen=1, txtRecord="", 1185 + * i.e. it creates a TXT record of length one containing a single empty string. 1186 + * RFC 1035 doesn't allow a TXT record to contain *zero* strings, so a single empty 1187 + * string is the smallest legal DNS TXT record. 1188 + * As with the other parameters, the DNSServiceRegister call copies the txtRecord 1189 + * data; e.g. if you allocated the storage for the txtRecord parameter with malloc() 1190 + * then you can safely free that memory right after the DNSServiceRegister call returns. 1191 + * 1192 + * callBack: The function to be called when the registration completes or asynchronously 1193 + * fails. The client MAY pass NULL for the callback - The client will NOT be notified 1194 + * of the default values picked on its behalf, and the client will NOT be notified of any 1195 + * asynchronous errors (e.g. out of memory errors, etc.) that may prevent the registration 1196 + * of the service. The client may NOT pass the NoAutoRename flag if the callback is NULL. 1197 + * The client may still deregister the service at any time via DNSServiceRefDeallocate(). 1198 + * 1199 + * context: An application context pointer which is passed to the callback function 1200 + * (may be NULL). 1201 + * 1202 + * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous 1203 + * errors are delivered to the callback), otherwise returns an error code indicating 1204 + * the error that occurred (the callback is never invoked and the DNSServiceRef 1205 + * is not initialized). 1206 + */ 1207 + 1208 + DNSServiceErrorType DNSSD_API DNSServiceRegister 1209 + ( 1210 + DNSServiceRef *sdRef, 1211 + DNSServiceFlags flags, 1212 + uint32_t interfaceIndex, 1213 + const char *name, /* may be NULL */ 1214 + const char *regtype, 1215 + const char *domain, /* may be NULL */ 1216 + const char *host, /* may be NULL */ 1217 + uint16_t port, /* In network byte order */ 1218 + uint16_t txtLen, 1219 + const void *txtRecord, /* may be NULL */ 1220 + DNSServiceRegisterReply callBack, /* may be NULL */ 1221 + void *context /* may be NULL */ 1222 + ); 1223 + 1224 + 1225 + /* DNSServiceAddRecord() 1226 + * 1227 + * Add a record to a registered service. The name of the record will be the same as the 1228 + * registered service's name. 1229 + * The record can later be updated or deregistered by passing the RecordRef initialized 1230 + * by this function to DNSServiceUpdateRecord() or DNSServiceRemoveRecord(). 1231 + * 1232 + * Note that the DNSServiceAddRecord/UpdateRecord/RemoveRecord are *NOT* thread-safe 1233 + * with respect to a single DNSServiceRef. If you plan to have multiple threads 1234 + * in your program simultaneously add, update, or remove records from the same 1235 + * DNSServiceRef, then it's the caller's responsibility to use a mutext lock 1236 + * or take similar appropriate precautions to serialize those calls. 1237 + * 1238 + * Parameters; 1239 + * 1240 + * sdRef: A DNSServiceRef initialized by DNSServiceRegister(). 1241 + * 1242 + * RecordRef: A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this 1243 + * call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord(). 1244 + * If the above DNSServiceRef is passed to DNSServiceRefDeallocate(), RecordRef is also 1245 + * invalidated and may not be used further. 1246 + * 1247 + * flags: Currently ignored, reserved for future use. 1248 + * 1249 + * rrtype: The type of the record (e.g. kDNSServiceType_TXT, kDNSServiceType_SRV, etc) 1250 + * 1251 + * rdlen: The length, in bytes, of the rdata. 1252 + * 1253 + * rdata: The raw rdata to be contained in the added resource record. 1254 + * 1255 + * ttl: The time to live of the resource record, in seconds. 1256 + * Most clients should pass 0 to indicate that the system should 1257 + * select a sensible default value. 1258 + * 1259 + * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an 1260 + * error code indicating the error that occurred (the RecordRef is not initialized). 1261 + */ 1262 + 1263 + DNSServiceErrorType DNSSD_API DNSServiceAddRecord 1264 + ( 1265 + DNSServiceRef sdRef, 1266 + DNSRecordRef *RecordRef, 1267 + DNSServiceFlags flags, 1268 + uint16_t rrtype, 1269 + uint16_t rdlen, 1270 + const void *rdata, 1271 + uint32_t ttl 1272 + ); 1273 + 1274 + 1275 + /* DNSServiceUpdateRecord 1276 + * 1277 + * Update a registered resource record. The record must either be: 1278 + * - The primary txt record of a service registered via DNSServiceRegister() 1279 + * - A record added to a registered service via DNSServiceAddRecord() 1280 + * - An individual record registered by DNSServiceRegisterRecord() 1281 + * 1282 + * Parameters: 1283 + * 1284 + * sdRef: A DNSServiceRef that was initialized by DNSServiceRegister() 1285 + * or DNSServiceCreateConnection(). 1286 + * 1287 + * RecordRef: A DNSRecordRef initialized by DNSServiceAddRecord, or NULL to update the 1288 + * service's primary txt record. 1289 + * 1290 + * flags: Currently ignored, reserved for future use. 1291 + * 1292 + * rdlen: The length, in bytes, of the new rdata. 1293 + * 1294 + * rdata: The new rdata to be contained in the updated resource record. 1295 + * 1296 + * ttl: The time to live of the updated resource record, in seconds. 1297 + * Most clients should pass 0 to indicate that the system should 1298 + * select a sensible default value. 1299 + * 1300 + * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an 1301 + * error code indicating the error that occurred. 1302 + */ 1303 + 1304 + DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord 1305 + ( 1306 + DNSServiceRef sdRef, 1307 + DNSRecordRef RecordRef, /* may be NULL */ 1308 + DNSServiceFlags flags, 1309 + uint16_t rdlen, 1310 + const void *rdata, 1311 + uint32_t ttl 1312 + ); 1313 + 1314 + 1315 + /* DNSServiceRemoveRecord 1316 + * 1317 + * Remove a record previously added to a service record set via DNSServiceAddRecord(), or deregister 1318 + * an record registered individually via DNSServiceRegisterRecord(). 1319 + * 1320 + * Parameters: 1321 + * 1322 + * sdRef: A DNSServiceRef initialized by DNSServiceRegister() (if the 1323 + * record being removed was registered via DNSServiceAddRecord()) or by 1324 + * DNSServiceCreateConnection() (if the record being removed was registered via 1325 + * DNSServiceRegisterRecord()). 1326 + * 1327 + * recordRef: A DNSRecordRef initialized by a successful call to DNSServiceAddRecord() 1328 + * or DNSServiceRegisterRecord(). 1329 + * 1330 + * flags: Currently ignored, reserved for future use. 1331 + * 1332 + * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an 1333 + * error code indicating the error that occurred. 1334 + */ 1335 + 1336 + DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord 1337 + ( 1338 + DNSServiceRef sdRef, 1339 + DNSRecordRef RecordRef, 1340 + DNSServiceFlags flags 1341 + ); 1342 + 1343 + 1344 + /********************************************************************************************* 1345 + * 1346 + * Service Discovery 1347 + * 1348 + *********************************************************************************************/ 1349 + 1350 + /* Browse for instances of a service. 1351 + * 1352 + * DNSServiceBrowseReply() Parameters: 1353 + * 1354 + * sdRef: The DNSServiceRef initialized by DNSServiceBrowse(). 1355 + * 1356 + * flags: Possible values are kDNSServiceFlagsMoreComing and kDNSServiceFlagsAdd. 1357 + * See flag definitions for details. 1358 + * 1359 + * interfaceIndex: The interface on which the service is advertised. This index should 1360 + * be passed to DNSServiceResolve() when resolving the service. 1361 + * 1362 + * errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise will 1363 + * indicate the failure that occurred. Other parameters are undefined if 1364 + * the errorCode is nonzero. 1365 + * 1366 + * serviceName: The discovered service name. This name should be displayed to the user, 1367 + * and stored for subsequent use in the DNSServiceResolve() call. 1368 + * 1369 + * regtype: The service type, which is usually (but not always) the same as was passed 1370 + * to DNSServiceBrowse(). One case where the discovered service type may 1371 + * not be the same as the requested service type is when using subtypes: 1372 + * The client may want to browse for only those ftp servers that allow 1373 + * anonymous connections. The client will pass the string "_ftp._tcp,_anon" 1374 + * to DNSServiceBrowse(), but the type of the service that's discovered 1375 + * is simply "_ftp._tcp". The regtype for each discovered service instance 1376 + * should be stored along with the name, so that it can be passed to 1377 + * DNSServiceResolve() when the service is later resolved. 1378 + * 1379 + * domain: The domain of the discovered service instance. This may or may not be the 1380 + * same as the domain that was passed to DNSServiceBrowse(). The domain for each 1381 + * discovered service instance should be stored along with the name, so that 1382 + * it can be passed to DNSServiceResolve() when the service is later resolved. 1383 + * 1384 + * context: The context pointer that was passed to the callout. 1385 + * 1386 + */ 1387 + 1388 + typedef void (DNSSD_API *DNSServiceBrowseReply) 1389 + ( 1390 + DNSServiceRef sdRef, 1391 + DNSServiceFlags flags, 1392 + uint32_t interfaceIndex, 1393 + DNSServiceErrorType errorCode, 1394 + const char *serviceName, 1395 + const char *regtype, 1396 + const char *replyDomain, 1397 + void *context 1398 + ); 1399 + 1400 + 1401 + /* DNSServiceBrowse() Parameters: 1402 + * 1403 + * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds 1404 + * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError, 1405 + * and the browse operation will run indefinitely until the client 1406 + * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate(). 1407 + * 1408 + * flags: Currently ignored, reserved for future use. 1409 + * 1410 + * interfaceIndex: If non-zero, specifies the interface on which to browse for services 1411 + * (the index for a given interface is determined via the if_nametoindex() 1412 + * family of calls.) Most applications will pass 0 to browse on all available 1413 + * interfaces. See "Constants for specifying an interface index" for more details. 1414 + * 1415 + * regtype: The service type being browsed for followed by the protocol, separated by a 1416 + * dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp". 1417 + * A client may optionally specify a single subtype to perform filtered browsing: 1418 + * e.g. browsing for "_primarytype._tcp,_subtype" will discover only those 1419 + * instances of "_primarytype._tcp" that were registered specifying "_subtype" 1420 + * in their list of registered subtypes. Additionally, a group identifier may 1421 + * also be specified before the subtype e.g., _primarytype._tcp:GroupID, which 1422 + * will discover only the members that register the service with GroupID. See 1423 + * DNSServiceRegister for more details. 1424 + * 1425 + * domain: If non-NULL, specifies the domain on which to browse for services. 1426 + * Most applications will not specify a domain, instead browsing on the 1427 + * default domain(s). 1428 + * 1429 + * callBack: The function to be called when an instance of the service being browsed for 1430 + * is found, or if the call asynchronously fails. 1431 + * 1432 + * context: An application context pointer which is passed to the callback function 1433 + * (may be NULL). 1434 + * 1435 + * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous 1436 + * errors are delivered to the callback), otherwise returns an error code indicating 1437 + * the error that occurred (the callback is not invoked and the DNSServiceRef 1438 + * is not initialized). 1439 + */ 1440 + 1441 + DNSServiceErrorType DNSSD_API DNSServiceBrowse 1442 + ( 1443 + DNSServiceRef *sdRef, 1444 + DNSServiceFlags flags, 1445 + uint32_t interfaceIndex, 1446 + const char *regtype, 1447 + const char *domain, /* may be NULL */ 1448 + DNSServiceBrowseReply callBack, 1449 + void *context /* may be NULL */ 1450 + ); 1451 + 1452 + 1453 + /* DNSServiceResolve() 1454 + * 1455 + * Resolve a service name discovered via DNSServiceBrowse() to a target host name, port number, and 1456 + * txt record. 1457 + * 1458 + * Note: Applications should NOT use DNSServiceResolve() solely for txt record monitoring - use 1459 + * DNSServiceQueryRecord() instead, as it is more efficient for this task. 1460 + * 1461 + * Note: When the desired results have been returned, the client MUST terminate the resolve by calling 1462 + * DNSServiceRefDeallocate(). 1463 + * 1464 + * Note: DNSServiceResolve() behaves correctly for typical services that have a single SRV record 1465 + * and a single TXT record. To resolve non-standard services with multiple SRV or TXT records, 1466 + * DNSServiceQueryRecord() should be used. 1467 + * 1468 + * DNSServiceResolveReply Callback Parameters: 1469 + * 1470 + * sdRef: The DNSServiceRef initialized by DNSServiceResolve(). 1471 + * 1472 + * flags: Possible values: kDNSServiceFlagsMoreComing 1473 + * 1474 + * interfaceIndex: The interface on which the service was resolved. 1475 + * 1476 + * errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise will 1477 + * indicate the failure that occurred. Other parameters are undefined if 1478 + * the errorCode is nonzero. 1479 + * 1480 + * fullname: The full service domain name, in the form <servicename>.<protocol>.<domain>. 1481 + * (This name is escaped following standard DNS rules, making it suitable for 1482 + * passing to standard system DNS APIs such as res_query(), or to the 1483 + * special-purpose functions included in this API that take fullname parameters. 1484 + * See "Notes on DNS Name Escaping" earlier in this file for more details.) 1485 + * 1486 + * hosttarget: The target hostname of the machine providing the service. This name can 1487 + * be passed to functions like gethostbyname() to identify the host's IP address. 1488 + * 1489 + * port: The port, in network byte order, on which connections are accepted for this service. 1490 + * 1491 + * txtLen: The length of the txt record, in bytes. 1492 + * 1493 + * txtRecord: The service's primary txt record, in standard txt record format. 1494 + * 1495 + * context: The context pointer that was passed to the callout. 1496 + * 1497 + * NOTE: In earlier versions of this header file, the txtRecord parameter was declared "const char *" 1498 + * This is incorrect, since it contains length bytes which are values in the range 0 to 255, not -128 to +127. 1499 + * Depending on your compiler settings, this change may cause signed/unsigned mismatch warnings. 1500 + * These should be fixed by updating your own callback function definition to match the corrected 1501 + * function signature using "const unsigned char *txtRecord". Making this change may also fix inadvertent 1502 + * bugs in your callback function, where it could have incorrectly interpreted a length byte with value 250 1503 + * as being -6 instead, with various bad consequences ranging from incorrect operation to software crashes. 1504 + * If you need to maintain portable code that will compile cleanly with both the old and new versions of 1505 + * this header file, you should update your callback function definition to use the correct unsigned value, 1506 + * and then in the place where you pass your callback function to DNSServiceResolve(), use a cast to eliminate 1507 + * the compiler warning, e.g.: 1508 + * DNSServiceResolve(sd, flags, index, name, regtype, domain, (DNSServiceResolveReply)MyCallback, context); 1509 + * This will ensure that your code compiles cleanly without warnings (and more importantly, works correctly) 1510 + * with both the old header and with the new corrected version. 1511 + * 1512 + */ 1513 + 1514 + typedef void (DNSSD_API *DNSServiceResolveReply) 1515 + ( 1516 + DNSServiceRef sdRef, 1517 + DNSServiceFlags flags, 1518 + uint32_t interfaceIndex, 1519 + DNSServiceErrorType errorCode, 1520 + const char *fullname, 1521 + const char *hosttarget, 1522 + uint16_t port, /* In network byte order */ 1523 + uint16_t txtLen, 1524 + const unsigned char *txtRecord, 1525 + void *context 1526 + ); 1527 + 1528 + 1529 + /* DNSServiceResolve() Parameters 1530 + * 1531 + * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds 1532 + * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError, 1533 + * and the resolve operation will run indefinitely until the client 1534 + * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate(). 1535 + * 1536 + * flags: Specifying kDNSServiceFlagsForceMulticast will cause query to be 1537 + * performed with a link-local mDNS query, even if the name is an 1538 + * apparently non-local name (i.e. a name not ending in ".local.") 1539 + * 1540 + * interfaceIndex: The interface on which to resolve the service. If this resolve call is 1541 + * as a result of a currently active DNSServiceBrowse() operation, then the 1542 + * interfaceIndex should be the index reported in the DNSServiceBrowseReply 1543 + * callback. If this resolve call is using information previously saved 1544 + * (e.g. in a preference file) for later use, then use interfaceIndex 0, because 1545 + * the desired service may now be reachable via a different physical interface. 1546 + * See "Constants for specifying an interface index" for more details. 1547 + * 1548 + * name: The name of the service instance to be resolved, as reported to the 1549 + * DNSServiceBrowseReply() callback. 1550 + * 1551 + * regtype: The type of the service instance to be resolved, as reported to the 1552 + * DNSServiceBrowseReply() callback. 1553 + * 1554 + * domain: The domain of the service instance to be resolved, as reported to the 1555 + * DNSServiceBrowseReply() callback. 1556 + * 1557 + * callBack: The function to be called when a result is found, or if the call 1558 + * asynchronously fails. 1559 + * 1560 + * context: An application context pointer which is passed to the callback function 1561 + * (may be NULL). 1562 + * 1563 + * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous 1564 + * errors are delivered to the callback), otherwise returns an error code indicating 1565 + * the error that occurred (the callback is never invoked and the DNSServiceRef 1566 + * is not initialized). 1567 + */ 1568 + 1569 + DNSServiceErrorType DNSSD_API DNSServiceResolve 1570 + ( 1571 + DNSServiceRef *sdRef, 1572 + DNSServiceFlags flags, 1573 + uint32_t interfaceIndex, 1574 + const char *name, 1575 + const char *regtype, 1576 + const char *domain, 1577 + DNSServiceResolveReply callBack, 1578 + void *context /* may be NULL */ 1579 + ); 1580 + 1581 + 1582 + /********************************************************************************************* 1583 + * 1584 + * Querying Individual Specific Records 1585 + * 1586 + *********************************************************************************************/ 1587 + 1588 + /* DNSServiceQueryRecord 1589 + * 1590 + * Query for an arbitrary DNS record. 1591 + * 1592 + * DNSServiceQueryRecordReply() Callback Parameters: 1593 + * 1594 + * sdRef: The DNSServiceRef initialized by DNSServiceQueryRecord(). 1595 + * 1596 + * flags: Possible values are kDNSServiceFlagsMoreComing and 1597 + * kDNSServiceFlagsAdd. The Add flag is NOT set for PTR records 1598 + * with a ttl of 0, i.e. "Remove" events. 1599 + * 1600 + * interfaceIndex: The interface on which the query was resolved (the index for a given 1601 + * interface is determined via the if_nametoindex() family of calls). 1602 + * See "Constants for specifying an interface index" for more details. 1603 + * 1604 + * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will 1605 + * indicate the failure that occurred. Other parameters are undefined if 1606 + * errorCode is nonzero. 1607 + * 1608 + * fullname: The resource record's full domain name. 1609 + * 1610 + * rrtype: The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc) 1611 + * 1612 + * rrclass: The class of the resource record (usually kDNSServiceClass_IN). 1613 + * 1614 + * rdlen: The length, in bytes, of the resource record rdata. 1615 + * 1616 + * rdata: The raw rdata of the resource record. 1617 + * 1618 + * ttl: If the client wishes to cache the result for performance reasons, 1619 + * the TTL indicates how long the client may legitimately hold onto 1620 + * this result, in seconds. After the TTL expires, the client should 1621 + * consider the result no longer valid, and if it requires this data 1622 + * again, it should be re-fetched with a new query. Of course, this 1623 + * only applies to clients that cancel the asynchronous operation when 1624 + * they get a result. Clients that leave the asynchronous operation 1625 + * running can safely assume that the data remains valid until they 1626 + * get another callback telling them otherwise. 1627 + * 1628 + * context: The context pointer that was passed to the callout. 1629 + * 1630 + */ 1631 + 1632 + typedef void (DNSSD_API *DNSServiceQueryRecordReply) 1633 + ( 1634 + DNSServiceRef sdRef, 1635 + DNSServiceFlags flags, 1636 + uint32_t interfaceIndex, 1637 + DNSServiceErrorType errorCode, 1638 + const char *fullname, 1639 + uint16_t rrtype, 1640 + uint16_t rrclass, 1641 + uint16_t rdlen, 1642 + const void *rdata, 1643 + uint32_t ttl, 1644 + void *context 1645 + ); 1646 + 1647 + 1648 + /* DNSServiceQueryRecord() Parameters: 1649 + * 1650 + * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds 1651 + * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError, 1652 + * and the query operation will run indefinitely until the client 1653 + * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate(). 1654 + * 1655 + * flags: kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery. 1656 + * Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast 1657 + * query to a unicast DNS server that implements the protocol. This flag 1658 + * has no effect on link-local multicast queries. 1659 + * 1660 + * interfaceIndex: If non-zero, specifies the interface on which to issue the query 1661 + * (the index for a given interface is determined via the if_nametoindex() 1662 + * family of calls.) Passing 0 causes the name to be queried for on all 1663 + * interfaces. See "Constants for specifying an interface index" for more details. 1664 + * 1665 + * fullname: The full domain name of the resource record to be queried for. 1666 + * 1667 + * rrtype: The numerical type of the resource record to be queried for 1668 + * (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc) 1669 + * 1670 + * rrclass: The class of the resource record (usually kDNSServiceClass_IN). 1671 + * 1672 + * callBack: The function to be called when a result is found, or if the call 1673 + * asynchronously fails. 1674 + * 1675 + * context: An application context pointer which is passed to the callback function 1676 + * (may be NULL). 1677 + * 1678 + * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous 1679 + * errors are delivered to the callback), otherwise returns an error code indicating 1680 + * the error that occurred (the callback is never invoked and the DNSServiceRef 1681 + * is not initialized). 1682 + */ 1683 + 1684 + DNSServiceErrorType DNSSD_API DNSServiceQueryRecord 1685 + ( 1686 + DNSServiceRef *sdRef, 1687 + DNSServiceFlags flags, 1688 + uint32_t interfaceIndex, 1689 + const char *fullname, 1690 + uint16_t rrtype, 1691 + uint16_t rrclass, 1692 + DNSServiceQueryRecordReply callBack, 1693 + void *context /* may be NULL */ 1694 + ); 1695 + 1696 + 1697 + /********************************************************************************************* 1698 + * 1699 + * Unified lookup of both IPv4 and IPv6 addresses for a fully qualified hostname 1700 + * 1701 + *********************************************************************************************/ 1702 + 1703 + /* DNSServiceGetAddrInfo 1704 + * 1705 + * Queries for the IP address of a hostname by using either Multicast or Unicast DNS. 1706 + * 1707 + * DNSServiceGetAddrInfoReply() parameters: 1708 + * 1709 + * sdRef: The DNSServiceRef initialized by DNSServiceGetAddrInfo(). 1710 + * 1711 + * flags: Possible values are kDNSServiceFlagsMoreComing and 1712 + * kDNSServiceFlagsAdd. 1713 + * 1714 + * interfaceIndex: The interface to which the answers pertain. 1715 + * 1716 + * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will 1717 + * indicate the failure that occurred. Other parameters are 1718 + * undefined if errorCode is nonzero. 1719 + * 1720 + * hostname: The fully qualified domain name of the host to be queried for. 1721 + * 1722 + * address: IPv4 or IPv6 address. 1723 + * 1724 + * ttl: If the client wishes to cache the result for performance reasons, 1725 + * the TTL indicates how long the client may legitimately hold onto 1726 + * this result, in seconds. After the TTL expires, the client should 1727 + * consider the result no longer valid, and if it requires this data 1728 + * again, it should be re-fetched with a new query. Of course, this 1729 + * only applies to clients that cancel the asynchronous operation when 1730 + * they get a result. Clients that leave the asynchronous operation 1731 + * running can safely assume that the data remains valid until they 1732 + * get another callback telling them otherwise. 1733 + * 1734 + * context: The context pointer that was passed to the callout. 1735 + * 1736 + */ 1737 + 1738 + typedef void (DNSSD_API *DNSServiceGetAddrInfoReply) 1739 + ( 1740 + DNSServiceRef sdRef, 1741 + DNSServiceFlags flags, 1742 + uint32_t interfaceIndex, 1743 + DNSServiceErrorType errorCode, 1744 + const char *hostname, 1745 + const struct sockaddr *address, 1746 + uint32_t ttl, 1747 + void *context 1748 + ); 1749 + 1750 + 1751 + /* DNSServiceGetAddrInfo() Parameters: 1752 + * 1753 + * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it 1754 + * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the query 1755 + * begins and will last indefinitely until the client terminates the query 1756 + * by passing this DNSServiceRef to DNSServiceRefDeallocate(). 1757 + * 1758 + * flags: kDNSServiceFlagsForceMulticast 1759 + * 1760 + * interfaceIndex: The interface on which to issue the query. Passing 0 causes the query to be 1761 + * sent on all active interfaces via Multicast or the primary interface via Unicast. 1762 + * 1763 + * protocol: Pass in kDNSServiceProtocol_IPv4 to look up IPv4 addresses, or kDNSServiceProtocol_IPv6 1764 + * to look up IPv6 addresses, or both to look up both kinds. If neither flag is 1765 + * set, the system will apply an intelligent heuristic, which is (currently) 1766 + * that it will attempt to look up both, except: 1767 + * 1768 + * * If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name) 1769 + * but this host has no routable IPv6 address, then the call will not try to 1770 + * look up IPv6 addresses for "hostname", since any addresses it found would be 1771 + * unlikely to be of any use anyway. Similarly, if this host has no routable 1772 + * IPv4 address, the call will not try to look up IPv4 addresses for "hostname". 1773 + * 1774 + * hostname: The fully qualified domain name of the host to be queried for. 1775 + * 1776 + * callBack: The function to be called when the query succeeds or fails asynchronously. 1777 + * 1778 + * context: An application context pointer which is passed to the callback function 1779 + * (may be NULL). 1780 + * 1781 + * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous 1782 + * errors are delivered to the callback), otherwise returns an error code indicating 1783 + * the error that occurred. 1784 + */ 1785 + 1786 + DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo 1787 + ( 1788 + DNSServiceRef *sdRef, 1789 + DNSServiceFlags flags, 1790 + uint32_t interfaceIndex, 1791 + DNSServiceProtocol protocol, 1792 + const char *hostname, 1793 + DNSServiceGetAddrInfoReply callBack, 1794 + void *context /* may be NULL */ 1795 + ); 1796 + 1797 + 1798 + /********************************************************************************************* 1799 + * 1800 + * Special Purpose Calls: 1801 + * DNSServiceCreateConnection(), DNSServiceRegisterRecord(), DNSServiceReconfirmRecord() 1802 + * (most applications will not use these) 1803 + * 1804 + *********************************************************************************************/ 1805 + 1806 + /* DNSServiceCreateConnection() 1807 + * 1808 + * Create a connection to the daemon allowing efficient registration of 1809 + * multiple individual records. 1810 + * 1811 + * Parameters: 1812 + * 1813 + * sdRef: A pointer to an uninitialized DNSServiceRef. Deallocating 1814 + * the reference (via DNSServiceRefDeallocate()) severs the 1815 + * connection and deregisters all records registered on this connection. 1816 + * 1817 + * return value: Returns kDNSServiceErr_NoError on success, otherwise returns 1818 + * an error code indicating the specific failure that occurred (in which 1819 + * case the DNSServiceRef is not initialized). 1820 + */ 1821 + 1822 + DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef); 1823 + 1824 + /* DNSServiceRegisterRecord 1825 + * 1826 + * Register an individual resource record on a connected DNSServiceRef. 1827 + * 1828 + * Note that name conflicts occurring for records registered via this call must be handled 1829 + * by the client in the callback. 1830 + * 1831 + * DNSServiceRegisterRecordReply() parameters: 1832 + * 1833 + * sdRef: The connected DNSServiceRef initialized by 1834 + * DNSServiceCreateConnection(). 1835 + * 1836 + * RecordRef: The DNSRecordRef initialized by DNSServiceRegisterRecord(). If the above 1837 + * DNSServiceRef is passed to DNSServiceRefDeallocate(), this DNSRecordRef is 1838 + * invalidated, and may not be used further. 1839 + * 1840 + * flags: Currently unused, reserved for future use. 1841 + * 1842 + * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will 1843 + * indicate the failure that occurred (including name conflicts.) 1844 + * Other parameters are undefined if errorCode is nonzero. 1845 + * 1846 + * context: The context pointer that was passed to the callout. 1847 + * 1848 + */ 1849 + 1850 + typedef void (DNSSD_API *DNSServiceRegisterRecordReply) 1851 + ( 1852 + DNSServiceRef sdRef, 1853 + DNSRecordRef RecordRef, 1854 + DNSServiceFlags flags, 1855 + DNSServiceErrorType errorCode, 1856 + void *context 1857 + ); 1858 + 1859 + 1860 + /* DNSServiceRegisterRecord() Parameters: 1861 + * 1862 + * sdRef: A DNSServiceRef initialized by DNSServiceCreateConnection(). 1863 + * 1864 + * RecordRef: A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this 1865 + * call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord(). 1866 + * (To deregister ALL records registered on a single connected DNSServiceRef 1867 + * and deallocate each of their corresponding DNSServiceRecordRefs, call 1868 + * DNSServiceRefDeallocate()). 1869 + * 1870 + * flags: Possible values are kDNSServiceFlagsShared or kDNSServiceFlagsUnique 1871 + * (see flag type definitions for details). 1872 + * 1873 + * interfaceIndex: If non-zero, specifies the interface on which to register the record 1874 + * (the index for a given interface is determined via the if_nametoindex() 1875 + * family of calls.) Passing 0 causes the record to be registered on all interfaces. 1876 + * See "Constants for specifying an interface index" for more details. 1877 + * 1878 + * fullname: The full domain name of the resource record. 1879 + * 1880 + * rrtype: The numerical type of the resource record (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc) 1881 + * 1882 + * rrclass: The class of the resource record (usually kDNSServiceClass_IN) 1883 + * 1884 + * rdlen: Length, in bytes, of the rdata. 1885 + * 1886 + * rdata: A pointer to the raw rdata, as it is to appear in the DNS record. 1887 + * 1888 + * ttl: The time to live of the resource record, in seconds. 1889 + * Most clients should pass 0 to indicate that the system should 1890 + * select a sensible default value. 1891 + * 1892 + * callBack: The function to be called when a result is found, or if the call 1893 + * asynchronously fails (e.g. because of a name conflict.) 1894 + * 1895 + * context: An application context pointer which is passed to the callback function 1896 + * (may be NULL). 1897 + * 1898 + * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous 1899 + * errors are delivered to the callback), otherwise returns an error code indicating 1900 + * the error that occurred (the callback is never invoked and the DNSRecordRef is 1901 + * not initialized). 1902 + */ 1903 + 1904 + DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord 1905 + ( 1906 + DNSServiceRef sdRef, 1907 + DNSRecordRef *RecordRef, 1908 + DNSServiceFlags flags, 1909 + uint32_t interfaceIndex, 1910 + const char *fullname, 1911 + uint16_t rrtype, 1912 + uint16_t rrclass, 1913 + uint16_t rdlen, 1914 + const void *rdata, 1915 + uint32_t ttl, 1916 + DNSServiceRegisterRecordReply callBack, 1917 + void *context /* may be NULL */ 1918 + ); 1919 + 1920 + 1921 + /* DNSServiceReconfirmRecord 1922 + * 1923 + * Instruct the daemon to verify the validity of a resource record that appears 1924 + * to be out of date (e.g. because TCP connection to a service's target failed.) 1925 + * Causes the record to be flushed from the daemon's cache (as well as all other 1926 + * daemons' caches on the network) if the record is determined to be invalid. 1927 + * Use this routine conservatively. Reconfirming a record necessarily consumes 1928 + * network bandwidth, so this should not be done indiscriminately. 1929 + * 1930 + * Parameters: 1931 + * 1932 + * flags: Not currently used. 1933 + * 1934 + * interfaceIndex: Specifies the interface of the record in question. 1935 + * The caller must specify the interface. 1936 + * This API (by design) causes increased network traffic, so it requires 1937 + * the caller to be precise about which record should be reconfirmed. 1938 + * It is not possible to pass zero for the interface index to perform 1939 + * a "wildcard" reconfirmation, where *all* matching records are reconfirmed. 1940 + * 1941 + * fullname: The resource record's full domain name. 1942 + * 1943 + * rrtype: The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc) 1944 + * 1945 + * rrclass: The class of the resource record (usually kDNSServiceClass_IN). 1946 + * 1947 + * rdlen: The length, in bytes, of the resource record rdata. 1948 + * 1949 + * rdata: The raw rdata of the resource record. 1950 + * 1951 + */ 1952 + 1953 + DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord 1954 + ( 1955 + DNSServiceFlags flags, 1956 + uint32_t interfaceIndex, 1957 + const char *fullname, 1958 + uint16_t rrtype, 1959 + uint16_t rrclass, 1960 + uint16_t rdlen, 1961 + const void *rdata 1962 + ); 1963 + 1964 + #ifndef __OPEN_SOURCE__ 1965 + 1966 + /* PeerConnectionRelease() Parameters 1967 + * 1968 + * Release P2P connection resources associated with the service instance. 1969 + * When a service is resolved over a P2P interface, a connection is brought up to the 1970 + * peer advertising the service instance. This call will free the resources associated 1971 + * with that connection. Note that the reference to the service instance will only 1972 + * be maintained by the daemon while the browse for the service type is still 1973 + * running. Thus the sequence of calls to discover, resolve, and then terminate the connection 1974 + * associated with a given P2P service instance would be: 1975 + * 1976 + * DNSServiceRef BrowseRef, ResolveRef; 1977 + * DNSServiceBrowse(&BrowseRef, ...) // browse for all instances of the service 1978 + * DNSServiceResolve(&ResolveRef, ...) // resolving a service instance creates a 1979 + * // connection to the peer device advertising that service 1980 + * DNSServiceRefDeallocate(ResolveRef) // Stop the resolve, which does not close the peer connection 1981 + * 1982 + * // Communicate with the peer application. 1983 + * 1984 + * PeerConnectionRelease() // release the connection to the peer device for the specified service instance 1985 + * 1986 + * DNSServiceRefDeallocate(BrowseRef) // stop the browse 1987 + * // Any further calls to PeerConnectionRelease() will have no affect since the 1988 + * // service instance to peer connection relationship is only maintained by the 1989 + * // daemon while the browse is running. 1990 + * 1991 + * 1992 + * flags: Not currently used. 1993 + * 1994 + * name: The name of the service instance to be resolved, as reported to the 1995 + * DNSServiceBrowseReply() callback. 1996 + * 1997 + * regtype: The type of the service instance to be resolved, as reported to the 1998 + * DNSServiceBrowseReply() callback. 1999 + * 2000 + * domain: The domain of the service instance to be resolved, as reported to the 2001 + * DNSServiceBrowseReply() callback. 2002 + * 2003 + * return value: Returns kDNSServiceErr_NoError on success or the error that occurred. 2004 + */ 2005 + 2006 + DNSServiceErrorType DNSSD_API PeerConnectionRelease 2007 + ( 2008 + DNSServiceFlags flags, 2009 + const char *name, 2010 + const char *regtype, 2011 + const char *domain 2012 + ); 2013 + 2014 + #endif // __OPEN_SOURCE__ 2015 + 2016 + /********************************************************************************************* 2017 + * 2018 + * NAT Port Mapping 2019 + * 2020 + *********************************************************************************************/ 2021 + 2022 + /* DNSServiceNATPortMappingCreate 2023 + * 2024 + * Request a port mapping in the NAT gateway, which maps a port on the local machine 2025 + * to an external port on the NAT. The NAT should support either PCP, NAT-PMP or the 2026 + * UPnP/IGD protocol for this API to create a successful mapping. Note that this API 2027 + * currently supports IPv4 addresses/mappings only. If the NAT gateway supports PCP and 2028 + * returns an IPv6 address (incorrectly, since this API specifically requests IPv4 2029 + * addresses), the DNSServiceNATPortMappingReply callback will be invoked with errorCode 2030 + * kDNSServiceErr_NATPortMappingUnsupported. 2031 + * 2032 + * The port mapping will be renewed indefinitely until the client process exits, or 2033 + * explicitly terminates the port mapping request by calling DNSServiceRefDeallocate(). 2034 + * The client callback will be invoked, informing the client of the NAT gateway's 2035 + * external IP address and the external port that has been allocated for this client. 2036 + * The client should then record this external IP address and port using whatever 2037 + * directory service mechanism it is using to enable peers to connect to it. 2038 + * (Clients advertising services using Wide-Area DNS-SD DO NOT need to use this API 2039 + * -- when a client calls DNSServiceRegister() NAT mappings are automatically created 2040 + * and the external IP address and port for the service are recorded in the global DNS. 2041 + * Only clients using some directory mechanism other than Wide-Area DNS-SD need to use 2042 + * this API to explicitly map their own ports.) 2043 + * 2044 + * It's possible that the client callback could be called multiple times, for example 2045 + * if the NAT gateway's IP address changes, or if a configuration change results in a 2046 + * different external port being mapped for this client. Over the lifetime of any long-lived 2047 + * port mapping, the client should be prepared to handle these notifications of changes 2048 + * in the environment, and should update its recorded address and/or port as appropriate. 2049 + * 2050 + * NOTE: There are two unusual aspects of how the DNSServiceNATPortMappingCreate API works, 2051 + * which were intentionally designed to help simplify client code: 2052 + * 2053 + * 1. It's not an error to request a NAT mapping when the machine is not behind a NAT gateway. 2054 + * In other NAT mapping APIs, if you request a NAT mapping and the machine is not behind a NAT 2055 + * gateway, then the API returns an error code -- it can't get you a NAT mapping if there's no 2056 + * NAT gateway. The DNSServiceNATPortMappingCreate API takes a different view. Working out 2057 + * whether or not you need a NAT mapping can be tricky and non-obvious, particularly on 2058 + * a machine with multiple active network interfaces. Rather than make every client recreate 2059 + * this logic for deciding whether a NAT mapping is required, the PortMapping API does that 2060 + * work for you. If the client calls the PortMapping API when the machine already has a 2061 + * routable public IP address, then instead of complaining about it and giving an error, 2062 + * the PortMapping API just invokes your callback, giving the machine's public address 2063 + * and your own port number. This means you don't need to write code to work out whether 2064 + * your client needs to call the PortMapping API -- just call it anyway, and if it wasn't 2065 + * necessary, no harm is done: 2066 + * 2067 + * - If the machine already has a routable public IP address, then your callback 2068 + * will just be invoked giving your own address and port. 2069 + * - If a NAT mapping is required and obtained, then your callback will be invoked 2070 + * giving you the external address and port. 2071 + * - If a NAT mapping is required but not obtained from the local NAT gateway, 2072 + * or the machine has no network connectivity, then your callback will be 2073 + * invoked giving zero address and port. 2074 + * 2075 + * 2. In other NAT mapping APIs, if a laptop computer is put to sleep and woken up on a new 2076 + * network, it's the client's job to notice this, and work out whether a NAT mapping 2077 + * is required on the new network, and make a new NAT mapping request if necessary. 2078 + * The DNSServiceNATPortMappingCreate API does this for you, automatically. 2079 + * The client just needs to make one call to the PortMapping API, and its callback will 2080 + * be invoked any time the mapping state changes. This property complements point (1) above. 2081 + * If the client didn't make a NAT mapping request just because it determined that one was 2082 + * not required at that particular moment in time, the client would then have to monitor 2083 + * for network state changes to determine if a NAT port mapping later became necessary. 2084 + * By unconditionally making a NAT mapping request, even when a NAT mapping not to be 2085 + * necessary, the PortMapping API will then begin monitoring network state changes on behalf of 2086 + * the client, and if a NAT mapping later becomes necessary, it will automatically create a NAT 2087 + * mapping and inform the client with a new callback giving the new address and port information. 2088 + * 2089 + * DNSServiceNATPortMappingReply() parameters: 2090 + * 2091 + * sdRef: The DNSServiceRef initialized by DNSServiceNATPortMappingCreate(). 2092 + * 2093 + * flags: Currently unused, reserved for future use. 2094 + * 2095 + * interfaceIndex: The interface through which the NAT gateway is reached. 2096 + * 2097 + * errorCode: Will be kDNSServiceErr_NoError on success. 2098 + * Will be kDNSServiceErr_DoubleNAT when the NAT gateway is itself behind one or 2099 + * more layers of NAT, in which case the other parameters have the defined values. 2100 + * For other failures, will indicate the failure that occurred, and the other 2101 + * parameters are undefined. 2102 + * 2103 + * externalAddress: Four byte IPv4 address in network byte order. 2104 + * 2105 + * protocol: Will be kDNSServiceProtocol_UDP or kDNSServiceProtocol_TCP or both. 2106 + * 2107 + * internalPort: The port on the local machine that was mapped. 2108 + * 2109 + * externalPort: The actual external port in the NAT gateway that was mapped. 2110 + * This is likely to be different than the requested external port. 2111 + * 2112 + * ttl: The lifetime of the NAT port mapping created on the gateway. 2113 + * This controls how quickly stale mappings will be garbage-collected 2114 + * if the client machine crashes, suffers a power failure, is disconnected 2115 + * from the network, or suffers some other unfortunate demise which 2116 + * causes it to vanish without explicitly removing its NAT port mapping. 2117 + * It's possible that the ttl value will differ from the requested ttl value. 2118 + * 2119 + * context: The context pointer that was passed to the callout. 2120 + * 2121 + */ 2122 + 2123 + typedef void (DNSSD_API *DNSServiceNATPortMappingReply) 2124 + ( 2125 + DNSServiceRef sdRef, 2126 + DNSServiceFlags flags, 2127 + uint32_t interfaceIndex, 2128 + DNSServiceErrorType errorCode, 2129 + uint32_t externalAddress, /* four byte IPv4 address in network byte order */ 2130 + DNSServiceProtocol protocol, 2131 + uint16_t internalPort, /* In network byte order */ 2132 + uint16_t externalPort, /* In network byte order and may be different than the requested port */ 2133 + uint32_t ttl, /* may be different than the requested ttl */ 2134 + void *context 2135 + ); 2136 + 2137 + 2138 + /* DNSServiceNATPortMappingCreate() Parameters: 2139 + * 2140 + * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it 2141 + * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the nat 2142 + * port mapping will last indefinitely until the client terminates the port 2143 + * mapping request by passing this DNSServiceRef to DNSServiceRefDeallocate(). 2144 + * 2145 + * flags: Currently ignored, reserved for future use. 2146 + * 2147 + * interfaceIndex: The interface on which to create port mappings in a NAT gateway. Passing 0 causes 2148 + * the port mapping request to be sent on the primary interface. 2149 + * 2150 + * protocol: To request a port mapping, pass in kDNSServiceProtocol_UDP, or kDNSServiceProtocol_TCP, 2151 + * or (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP) to map both. 2152 + * The local listening port number must also be specified in the internalPort parameter. 2153 + * To just discover the NAT gateway's external IP address, pass zero for protocol, 2154 + * internalPort, externalPort and ttl. 2155 + * 2156 + * internalPort: The port number in network byte order on the local machine which is listening for packets. 2157 + * 2158 + * externalPort: The requested external port in network byte order in the NAT gateway that you would 2159 + * like to map to the internal port. Pass 0 if you don't care which external port is chosen for you. 2160 + * 2161 + * ttl: The requested renewal period of the NAT port mapping, in seconds. 2162 + * If the client machine crashes, suffers a power failure, is disconnected from 2163 + * the network, or suffers some other unfortunate demise which causes it to vanish 2164 + * unexpectedly without explicitly removing its NAT port mappings, then the NAT gateway 2165 + * will garbage-collect old stale NAT port mappings when their lifetime expires. 2166 + * Requesting a short TTL causes such orphaned mappings to be garbage-collected 2167 + * more promptly, but consumes system resources and network bandwidth with 2168 + * frequent renewal packets to keep the mapping from expiring. 2169 + * Requesting a long TTL is more efficient on the network, but in the event of the 2170 + * client vanishing, stale NAT port mappings will not be garbage-collected as quickly. 2171 + * Most clients should pass 0 to use a system-wide default value. 2172 + * 2173 + * callBack: The function to be called when the port mapping request succeeds or fails asynchronously. 2174 + * 2175 + * context: An application context pointer which is passed to the callback function 2176 + * (may be NULL). 2177 + * 2178 + * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous 2179 + * errors are delivered to the callback), otherwise returns an error code indicating 2180 + * the error that occurred. 2181 + * 2182 + * If you don't actually want a port mapped, and are just calling the API 2183 + * because you want to find out the NAT's external IP address (e.g. for UI 2184 + * display) then pass zero for protocol, internalPort, externalPort and ttl. 2185 + */ 2186 + 2187 + DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate 2188 + ( 2189 + DNSServiceRef *sdRef, 2190 + DNSServiceFlags flags, 2191 + uint32_t interfaceIndex, 2192 + DNSServiceProtocol protocol, /* TCP and/or UDP */ 2193 + uint16_t internalPort, /* network byte order */ 2194 + uint16_t externalPort, /* network byte order */ 2195 + uint32_t ttl, /* time to live in seconds */ 2196 + DNSServiceNATPortMappingReply callBack, 2197 + void *context /* may be NULL */ 2198 + ); 2199 + 2200 + 2201 + /********************************************************************************************* 2202 + * 2203 + * General Utility Functions 2204 + * 2205 + *********************************************************************************************/ 2206 + 2207 + /* DNSServiceConstructFullName() 2208 + * 2209 + * Concatenate a three-part domain name (as returned by the above callbacks) into a 2210 + * properly-escaped full domain name. Note that callbacks in the above functions ALREADY ESCAPE 2211 + * strings where necessary. 2212 + * 2213 + * Parameters: 2214 + * 2215 + * fullName: A pointer to a buffer that where the resulting full domain name is to be written. 2216 + * The buffer must be kDNSServiceMaxDomainName (1009) bytes in length to 2217 + * accommodate the longest legal domain name without buffer overrun. 2218 + * 2219 + * service: The service name - any dots or backslashes must NOT be escaped. 2220 + * May be NULL (to construct a PTR record name, e.g. 2221 + * "_ftp._tcp.apple.com."). 2222 + * 2223 + * regtype: The service type followed by the protocol, separated by a dot 2224 + * (e.g. "_ftp._tcp"). 2225 + * 2226 + * domain: The domain name, e.g. "apple.com.". Literal dots or backslashes, 2227 + * if any, must be escaped, e.g. "1st\. Floor.apple.com." 2228 + * 2229 + * return value: Returns kDNSServiceErr_NoError (0) on success, kDNSServiceErr_BadParam on error. 2230 + * 2231 + */ 2232 + 2233 + DNSServiceErrorType DNSSD_API DNSServiceConstructFullName 2234 + ( 2235 + char * const fullName, 2236 + const char * const service, /* may be NULL */ 2237 + const char * const regtype, 2238 + const char * const domain 2239 + ); 2240 + 2241 + 2242 + /********************************************************************************************* 2243 + * 2244 + * TXT Record Construction Functions 2245 + * 2246 + *********************************************************************************************/ 2247 + 2248 + /* 2249 + * A typical calling sequence for TXT record construction is something like: 2250 + * 2251 + * Client allocates storage for TXTRecord data (e.g. declare buffer on the stack) 2252 + * TXTRecordCreate(); 2253 + * TXTRecordSetValue(); 2254 + * TXTRecordSetValue(); 2255 + * TXTRecordSetValue(); 2256 + * ... 2257 + * DNSServiceRegister( ... TXTRecordGetLength(), TXTRecordGetBytesPtr() ... ); 2258 + * TXTRecordDeallocate(); 2259 + * Explicitly deallocate storage for TXTRecord data (if not allocated on the stack) 2260 + */ 2261 + 2262 + 2263 + /* TXTRecordRef 2264 + * 2265 + * Opaque internal data type. 2266 + * Note: Represents a DNS-SD TXT record. 2267 + */ 2268 + 2269 + typedef union _TXTRecordRef_t { char PrivateData[16]; char *ForceNaturalAlignment; } TXTRecordRef; 2270 + 2271 + 2272 + /* TXTRecordCreate() 2273 + * 2274 + * Creates a new empty TXTRecordRef referencing the specified storage. 2275 + * 2276 + * If the buffer parameter is NULL, or the specified storage size is not 2277 + * large enough to hold a key subsequently added using TXTRecordSetValue(), 2278 + * then additional memory will be added as needed using malloc(). 2279 + * 2280 + * On some platforms, when memory is low, malloc() may fail. In this 2281 + * case, TXTRecordSetValue() will return kDNSServiceErr_NoMemory, and this 2282 + * error condition will need to be handled as appropriate by the caller. 2283 + * 2284 + * You can avoid the need to handle this error condition if you ensure 2285 + * that the storage you initially provide is large enough to hold all 2286 + * the key/value pairs that are to be added to the record. 2287 + * The caller can precompute the exact length required for all of the 2288 + * key/value pairs to be added, or simply provide a fixed-sized buffer 2289 + * known in advance to be large enough. 2290 + * A no-value (key-only) key requires (1 + key length) bytes. 2291 + * A key with empty value requires (1 + key length + 1) bytes. 2292 + * A key with non-empty value requires (1 + key length + 1 + value length). 2293 + * For most applications, DNS-SD TXT records are generally 2294 + * less than 100 bytes, so in most cases a simple fixed-sized 2295 + * 256-byte buffer will be more than sufficient. 2296 + * Recommended size limits for DNS-SD TXT Records are discussed in 2297 + * <http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt> 2298 + * 2299 + * Note: When passing parameters to and from these TXT record APIs, 2300 + * the key name does not include the '=' character. The '=' character 2301 + * is the separator between the key and value in the on-the-wire 2302 + * packet format; it is not part of either the key or the value. 2303 + * 2304 + * txtRecord: A pointer to an uninitialized TXTRecordRef. 2305 + * 2306 + * bufferLen: The size of the storage provided in the "buffer" parameter. 2307 + * 2308 + * buffer: Optional caller-supplied storage used to hold the TXTRecord data. 2309 + * This storage must remain valid for as long as 2310 + * the TXTRecordRef. 2311 + */ 2312 + 2313 + void DNSSD_API TXTRecordCreate 2314 + ( 2315 + TXTRecordRef *txtRecord, 2316 + uint16_t bufferLen, 2317 + void *buffer 2318 + ); 2319 + 2320 + 2321 + /* TXTRecordDeallocate() 2322 + * 2323 + * Releases any resources allocated in the course of preparing a TXT Record 2324 + * using TXTRecordCreate()/TXTRecordSetValue()/TXTRecordRemoveValue(). 2325 + * Ownership of the buffer provided in TXTRecordCreate() returns to the client. 2326 + * 2327 + * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate(). 2328 + * 2329 + */ 2330 + 2331 + void DNSSD_API TXTRecordDeallocate 2332 + ( 2333 + TXTRecordRef *txtRecord 2334 + ); 2335 + 2336 + 2337 + /* TXTRecordSetValue() 2338 + * 2339 + * Adds a key (optionally with value) to a TXTRecordRef. If the "key" already 2340 + * exists in the TXTRecordRef, then the current value will be replaced with 2341 + * the new value. 2342 + * Keys may exist in four states with respect to a given TXT record: 2343 + * - Absent (key does not appear at all) 2344 + * - Present with no value ("key" appears alone) 2345 + * - Present with empty value ("key=" appears in TXT record) 2346 + * - Present with non-empty value ("key=value" appears in TXT record) 2347 + * For more details refer to "Data Syntax for DNS-SD TXT Records" in 2348 + * <http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt> 2349 + * 2350 + * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate(). 2351 + * 2352 + * key: A null-terminated string which only contains printable ASCII 2353 + * values (0x20-0x7E), excluding '=' (0x3D). Keys should be 2354 + * 9 characters or fewer (not counting the terminating null). 2355 + * 2356 + * valueSize: The size of the value. 2357 + * 2358 + * value: Any binary value. For values that represent 2359 + * textual data, UTF-8 is STRONGLY recommended. 2360 + * For values that represent textual data, valueSize 2361 + * should NOT include the terminating null (if any) 2362 + * at the end of the string. 2363 + * If NULL, then "key" will be added with no value. 2364 + * If non-NULL but valueSize is zero, then "key=" will be 2365 + * added with empty value. 2366 + * 2367 + * return value: Returns kDNSServiceErr_NoError on success. 2368 + * Returns kDNSServiceErr_Invalid if the "key" string contains 2369 + * illegal characters. 2370 + * Returns kDNSServiceErr_NoMemory if adding this key would 2371 + * exceed the available storage. 2372 + */ 2373 + 2374 + DNSServiceErrorType DNSSD_API TXTRecordSetValue 2375 + ( 2376 + TXTRecordRef *txtRecord, 2377 + const char *key, 2378 + uint8_t valueSize, /* may be zero */ 2379 + const void *value /* may be NULL */ 2380 + ); 2381 + 2382 + 2383 + /* TXTRecordRemoveValue() 2384 + * 2385 + * Removes a key from a TXTRecordRef. The "key" must be an 2386 + * ASCII string which exists in the TXTRecordRef. 2387 + * 2388 + * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate(). 2389 + * 2390 + * key: A key name which exists in the TXTRecordRef. 2391 + * 2392 + * return value: Returns kDNSServiceErr_NoError on success. 2393 + * Returns kDNSServiceErr_NoSuchKey if the "key" does not 2394 + * exist in the TXTRecordRef. 2395 + */ 2396 + 2397 + DNSServiceErrorType DNSSD_API TXTRecordRemoveValue 2398 + ( 2399 + TXTRecordRef *txtRecord, 2400 + const char *key 2401 + ); 2402 + 2403 + 2404 + /* TXTRecordGetLength() 2405 + * 2406 + * Allows you to determine the length of the raw bytes within a TXTRecordRef. 2407 + * 2408 + * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate(). 2409 + * 2410 + * return value: Returns the size of the raw bytes inside a TXTRecordRef 2411 + * which you can pass directly to DNSServiceRegister() or 2412 + * to DNSServiceUpdateRecord(). 2413 + * Returns 0 if the TXTRecordRef is empty. 2414 + */ 2415 + 2416 + uint16_t DNSSD_API TXTRecordGetLength 2417 + ( 2418 + const TXTRecordRef *txtRecord 2419 + ); 2420 + 2421 + 2422 + /* TXTRecordGetBytesPtr() 2423 + * 2424 + * Allows you to retrieve a pointer to the raw bytes within a TXTRecordRef. 2425 + * 2426 + * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate(). 2427 + * 2428 + * return value: Returns a pointer to the raw bytes inside the TXTRecordRef 2429 + * which you can pass directly to DNSServiceRegister() or 2430 + * to DNSServiceUpdateRecord(). 2431 + */ 2432 + 2433 + const void * DNSSD_API TXTRecordGetBytesPtr 2434 + ( 2435 + const TXTRecordRef *txtRecord 2436 + ); 2437 + 2438 + 2439 + /********************************************************************************************* 2440 + * 2441 + * TXT Record Parsing Functions 2442 + * 2443 + *********************************************************************************************/ 2444 + 2445 + /* 2446 + * A typical calling sequence for TXT record parsing is something like: 2447 + * 2448 + * Receive TXT record data in DNSServiceResolve() callback 2449 + * if (TXTRecordContainsKey(txtLen, txtRecord, "key")) then do something 2450 + * val1ptr = TXTRecordGetValuePtr(txtLen, txtRecord, "key1", &len1); 2451 + * val2ptr = TXTRecordGetValuePtr(txtLen, txtRecord, "key2", &len2); 2452 + * ... 2453 + * memcpy(myval1, val1ptr, len1); 2454 + * memcpy(myval2, val2ptr, len2); 2455 + * ... 2456 + * return; 2457 + * 2458 + * If you wish to retain the values after return from the DNSServiceResolve() 2459 + * callback, then you need to copy the data to your own storage using memcpy() 2460 + * or similar, as shown in the example above. 2461 + * 2462 + * If for some reason you need to parse a TXT record you built yourself 2463 + * using the TXT record construction functions above, then you can do 2464 + * that using TXTRecordGetLength and TXTRecordGetBytesPtr calls: 2465 + * TXTRecordGetValue(TXTRecordGetLength(x), TXTRecordGetBytesPtr(x), key, &len); 2466 + * 2467 + * Most applications only fetch keys they know about from a TXT record and 2468 + * ignore the rest. 2469 + * However, some debugging tools wish to fetch and display all keys. 2470 + * To do that, use the TXTRecordGetCount() and TXTRecordGetItemAtIndex() calls. 2471 + */ 2472 + 2473 + /* TXTRecordContainsKey() 2474 + * 2475 + * Allows you to determine if a given TXT Record contains a specified key. 2476 + * 2477 + * txtLen: The size of the received TXT Record. 2478 + * 2479 + * txtRecord: Pointer to the received TXT Record bytes. 2480 + * 2481 + * key: A null-terminated ASCII string containing the key name. 2482 + * 2483 + * return value: Returns 1 if the TXT Record contains the specified key. 2484 + * Otherwise, it returns 0. 2485 + */ 2486 + 2487 + int DNSSD_API TXTRecordContainsKey 2488 + ( 2489 + uint16_t txtLen, 2490 + const void *txtRecord, 2491 + const char *key 2492 + ); 2493 + 2494 + 2495 + /* TXTRecordGetValuePtr() 2496 + * 2497 + * Allows you to retrieve the value for a given key from a TXT Record. 2498 + * 2499 + * txtLen: The size of the received TXT Record 2500 + * 2501 + * txtRecord: Pointer to the received TXT Record bytes. 2502 + * 2503 + * key: A null-terminated ASCII string containing the key name. 2504 + * 2505 + * valueLen: On output, will be set to the size of the "value" data. 2506 + * 2507 + * return value: Returns NULL if the key does not exist in this TXT record, 2508 + * or exists with no value (to differentiate between 2509 + * these two cases use TXTRecordContainsKey()). 2510 + * Returns pointer to location within TXT Record bytes 2511 + * if the key exists with empty or non-empty value. 2512 + * For empty value, valueLen will be zero. 2513 + * For non-empty value, valueLen will be length of value data. 2514 + */ 2515 + 2516 + const void * DNSSD_API TXTRecordGetValuePtr 2517 + ( 2518 + uint16_t txtLen, 2519 + const void *txtRecord, 2520 + const char *key, 2521 + uint8_t *valueLen 2522 + ); 2523 + 2524 + 2525 + /* TXTRecordGetCount() 2526 + * 2527 + * Returns the number of keys stored in the TXT Record. The count 2528 + * can be used with TXTRecordGetItemAtIndex() to iterate through the keys. 2529 + * 2530 + * txtLen: The size of the received TXT Record. 2531 + * 2532 + * txtRecord: Pointer to the received TXT Record bytes. 2533 + * 2534 + * return value: Returns the total number of keys in the TXT Record. 2535 + * 2536 + */ 2537 + 2538 + uint16_t DNSSD_API TXTRecordGetCount 2539 + ( 2540 + uint16_t txtLen, 2541 + const void *txtRecord 2542 + ); 2543 + 2544 + 2545 + /* TXTRecordGetItemAtIndex() 2546 + * 2547 + * Allows you to retrieve a key name and value pointer, given an index into 2548 + * a TXT Record. Legal index values range from zero to TXTRecordGetCount()-1. 2549 + * It's also possible to iterate through keys in a TXT record by simply 2550 + * calling TXTRecordGetItemAtIndex() repeatedly, beginning with index zero 2551 + * and increasing until TXTRecordGetItemAtIndex() returns kDNSServiceErr_Invalid. 2552 + * 2553 + * On return: 2554 + * For keys with no value, *value is set to NULL and *valueLen is zero. 2555 + * For keys with empty value, *value is non-NULL and *valueLen is zero. 2556 + * For keys with non-empty value, *value is non-NULL and *valueLen is non-zero. 2557 + * 2558 + * txtLen: The size of the received TXT Record. 2559 + * 2560 + * txtRecord: Pointer to the received TXT Record bytes. 2561 + * 2562 + * itemIndex: An index into the TXT Record. 2563 + * 2564 + * keyBufLen: The size of the string buffer being supplied. 2565 + * 2566 + * key: A string buffer used to store the key name. 2567 + * On return, the buffer contains a null-terminated C string 2568 + * giving the key name. DNS-SD TXT keys are usually 2569 + * 9 characters or fewer. To hold the maximum possible 2570 + * key name, the buffer should be 256 bytes long. 2571 + * 2572 + * valueLen: On output, will be set to the size of the "value" data. 2573 + * 2574 + * value: On output, *value is set to point to location within TXT 2575 + * Record bytes that holds the value data. 2576 + * 2577 + * return value: Returns kDNSServiceErr_NoError on success. 2578 + * Returns kDNSServiceErr_NoMemory if keyBufLen is too short. 2579 + * Returns kDNSServiceErr_Invalid if index is greater than 2580 + * TXTRecordGetCount()-1. 2581 + */ 2582 + 2583 + DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex 2584 + ( 2585 + uint16_t txtLen, 2586 + const void *txtRecord, 2587 + uint16_t itemIndex, 2588 + uint16_t keyBufLen, 2589 + char *key, 2590 + uint8_t *valueLen, 2591 + const void **value 2592 + ); 2593 + 2594 + #if _DNS_SD_LIBDISPATCH 2595 + /* 2596 + * DNSServiceSetDispatchQueue 2597 + * 2598 + * Allows you to schedule a DNSServiceRef on a serial dispatch queue for receiving asynchronous 2599 + * callbacks. It's the clients responsibility to ensure that the provided dispatch queue is running. 2600 + * 2601 + * A typical application that uses CFRunLoopRun or dispatch_main on its main thread will 2602 + * usually schedule DNSServiceRefs on its main queue (which is always a serial queue) 2603 + * using "DNSServiceSetDispatchQueue(sdref, dispatch_get_main_queue());" 2604 + * 2605 + * If there is any error during the processing of events, the application callback will 2606 + * be called with an error code. For shared connections, each subordinate DNSServiceRef 2607 + * will get its own error callback. Currently these error callbacks only happen 2608 + * if the daemon is manually terminated or crashes, and the error 2609 + * code in this case is kDNSServiceErr_ServiceNotRunning. The application must call 2610 + * DNSServiceRefDeallocate to free the DNSServiceRef when it gets such an error code. 2611 + * These error callbacks are rare and should not normally happen on customer machines, 2612 + * but application code should be written defensively to handle such error callbacks 2613 + * gracefully if they occur. 2614 + * 2615 + * After using DNSServiceSetDispatchQueue on a DNSServiceRef, calling DNSServiceProcessResult 2616 + * on the same DNSServiceRef will result in undefined behavior and should be avoided. 2617 + * 2618 + * Once the application successfully schedules a DNSServiceRef on a serial dispatch queue using 2619 + * DNSServiceSetDispatchQueue, it cannot remove the DNSServiceRef from the dispatch queue, or use 2620 + * DNSServiceSetDispatchQueue a second time to schedule the DNSServiceRef onto a different serial dispatch 2621 + * queue. Once scheduled onto a dispatch queue a DNSServiceRef will deliver events to that queue until 2622 + * the application no longer requires that operation and terminates it using DNSServiceRefDeallocate. 2623 + * 2624 + * service: DNSServiceRef that was allocated and returned to the application, when the 2625 + * application calls one of the DNSService API. 2626 + * 2627 + * queue: dispatch queue where the application callback will be scheduled 2628 + * 2629 + * return value: Returns kDNSServiceErr_NoError on success. 2630 + * Returns kDNSServiceErr_NoMemory if it cannot create a dispatch source 2631 + * Returns kDNSServiceErr_BadParam if the service param is invalid or the 2632 + * queue param is invalid 2633 + */ 2634 + 2635 + DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue 2636 + ( 2637 + DNSServiceRef service, 2638 + dispatch_queue_t queue 2639 + ); 2640 + #endif //_DNS_SD_LIBDISPATCH 2641 + 2642 + #if !defined(_WIN32) 2643 + typedef void (DNSSD_API *DNSServiceSleepKeepaliveReply) 2644 + ( 2645 + DNSServiceRef sdRef, 2646 + DNSServiceErrorType errorCode, 2647 + void *context 2648 + ); 2649 + DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive 2650 + ( 2651 + DNSServiceRef *sdRef, 2652 + DNSServiceFlags flags, 2653 + int fd, 2654 + unsigned int timeout, 2655 + DNSServiceSleepKeepaliveReply callBack, 2656 + void *context 2657 + ); 2658 + #endif 2659 + 2660 + #ifdef APPLE_OSX_mDNSResponder 2661 + /* DNSServiceCreateDelegateConnection() 2662 + * 2663 + * Create a delegate connection to the daemon allowing efficient registration of 2664 + * multiple individual records. 2665 + * 2666 + * Parameters: 2667 + * 2668 + * sdRef: A pointer to an uninitialized DNSServiceRef. Deallocating 2669 + * the reference (via DNSServiceRefDeallocate()) severs the 2670 + * connection and deregisters all records registered on this connection. 2671 + * 2672 + * pid : Process ID of the delegate 2673 + * 2674 + * uuid: UUID of the delegate 2675 + * 2676 + * Note that only one of the two arguments (pid or uuid) can be specified. If pid 2677 + * is zero, uuid will be assumed to be a valid value; otherwise pid will be used. 2678 + * 2679 + * return value: Returns kDNSServiceErr_NoError on success, otherwise returns 2680 + * an error code indicating the specific failure that occurred (in which 2681 + * case the DNSServiceRef is not initialized). kDNSServiceErr_NotAuth is 2682 + * returned to indicate that the calling process does not have entitlements 2683 + * to use this API. 2684 + */ 2685 + DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid); 2686 + #endif 2687 + 2688 + #ifdef __APPLE_API_PRIVATE 2689 + 2690 + #define kDNSServiceCompPrivateDNS "PrivateDNS" 2691 + #define kDNSServiceCompMulticastDNS "MulticastDNS" 2692 + 2693 + #endif //__APPLE_API_PRIVATE 2694 + 2695 + /* Some C compiler cleverness. We can make the compiler check certain things for us, 2696 + * and report errors at compile-time if anything is wrong. The usual way to do this would 2697 + * be to use a run-time "if" statement or the conventional run-time "assert" mechanism, but 2698 + * then you don't find out what's wrong until you run the software. This way, if the assertion 2699 + * condition is false, the array size is negative, and the complier complains immediately. 2700 + */ 2701 + 2702 + struct CompileTimeAssertionChecks_DNS_SD 2703 + { 2704 + char assert0[(sizeof(union _TXTRecordRef_t) == 16) ? 1 : -1]; 2705 + }; 2706 + 2707 + #ifdef __cplusplus 2708 + } 2709 + #endif 2710 + 2711 + #endif /* _DNS_SD_H */