From e91b9f68c8f72465f3a6a45ce0aa2ad44c776f32 Mon Sep 17 00:00:00 2001 From: Apple Date: Mon, 11 Apr 2005 01:49:25 +0000 Subject: [PATCH] launchd-106.tar.gz --- Makefile | 18 + launchd/AUTHORS | 4 + launchd/COPYING | 367 + launchd/ChangeLog | 0 launchd/INSTALL | 229 + launchd/Makefile.am | 1 + launchd/Makefile.in | 397 + launchd/NEWS | 0 launchd/README | 0 launchd/TODO | 20 + launchd/aclocal.m4 | 836 ++ launchd/compile | 99 + launchd/configure | 7442 +++++++++++++++++ launchd/configure.ac | 44 + launchd/depcomp | 423 + launchd/doc/Makefile.am | 3 + launchd/doc/Makefile.in | 203 + launchd/doc/StartupItem-NOTES.rtf | 96 + launchd/doc/com.apple.launchdebugd.xml | 30 + launchd/install-sh | 251 + launchd/missing | 336 + launchd/mkinstalldirs | 99 + launchd/src/ConsoleMessage.8 | 105 + launchd/src/ConsoleMessage.c | 327 + launchd/src/IPC.c | 399 + launchd/src/IPC.h | 47 + launchd/src/Makefile.am | 77 + launchd/src/Makefile.in | 919 ++ launchd/src/StartupItemContext.8 | 35 + launchd/src/StartupItemContext.c | 99 + launchd/src/StartupItems.c | 1085 +++ launchd/src/StartupItems.h | 117 + launchd/src/StartupItems/Apache | 52 + launchd/src/StartupItems/Apache.plist | 5 + launchd/src/StartupItems/AppServices | 27 + launchd/src/StartupItems/AppServices.plist | 4 + launchd/src/StartupItems/AppleShare | 27 + launchd/src/StartupItems/AppleShare.plist | 5 + launchd/src/StartupItems/AuthServer | 31 + launchd/src/StartupItems/AuthServer.plist | 4 + launchd/src/StartupItems/Disks | 33 + launchd/src/StartupItems/Disks.plist | 6 + launchd/src/StartupItems/IPServices | 28 + launchd/src/StartupItems/IPServices.plist | 5 + launchd/src/StartupItems/NFS | 126 + launchd/src/StartupItems/NFS.plist | 5 + launchd/src/StartupItems/NIS | 79 + launchd/src/StartupItems/NIS.plist | 4 + launchd/src/StartupItems/NetworkTime | 42 + launchd/src/StartupItems/NetworkTime.plist | 4 + launchd/src/SystemStarter.8 | 109 + launchd/src/SystemStarter.c | 402 + launchd/src/SystemStarter.h | 55 + launchd/src/SystemStarterIPC.h | 92 + launchd/src/bootstrap.c | 1021 +++ launchd/src/bootstrap.defs | 360 + launchd/src/bootstrap_internal.h | 60 + launchd/src/config.h.in | 163 + launchd/src/hostconfig | 12 + launchd/src/init.8 | 295 + launchd/src/init.c | 860 ++ launchd/src/launch.h | 180 + launchd/src/launch_priv.h | 66 + launchd/src/launchctl.1 | 126 + launchd/src/launchctl.c | 1451 ++++ launchd/src/launchd.8 | 69 + launchd/src/launchd.c | 2371 ++++++ launchd/src/launchd.conf.5 | 27 + launchd/src/launchd.h | 49 + launchd/src/launchd.plist.5 | 297 + launchd/src/launchd_debugd.8 | 21 + launchd/src/launchdebugd.c | 178 + launchd/src/launchproxy.8 | 19 + launchd/src/launchproxy.c | 208 + launchd/src/liblaunch.c | 927 ++ launchd/src/lists.c | 484 ++ launchd/src/lists.h | 155 + launchd/src/rc | 305 + launchd/src/rc.8 | 108 + launchd/src/rc.common | 93 + launchd/src/rc.netboot | 215 + launchd/src/rc.shutdown | 14 + launchd/src/register_mach_bootstrap_servers.c | 169 + launchd/src/rpc_services.c | 846 ++ launchd/src/service | 165 + launchd/src/service.8 | 29 + launchd/src/wait4path.1 | 13 + launchd/src/wait4path.c | 59 + launchd/testing/StartInterval.plist | 15 + launchd/testing/badexec.plist | 14 + launchd/testing/badexit.plist | 14 + launchd/testing/missed-EVFILT_WRITE.c | 156 + launchd/testing/missing_req_keys.plist | 6 + launchd/testing/secsock.plist | 21 + launchd/testing/signaldeath.plist | 16 + 95 files changed, 26910 insertions(+) create mode 100644 Makefile create mode 100644 launchd/AUTHORS create mode 100644 launchd/COPYING create mode 100644 launchd/ChangeLog create mode 100644 launchd/INSTALL create mode 100644 launchd/Makefile.am create mode 100644 launchd/Makefile.in create mode 100644 launchd/NEWS create mode 100644 launchd/README create mode 100644 launchd/TODO create mode 100644 launchd/aclocal.m4 create mode 100755 launchd/compile create mode 100755 launchd/configure create mode 100644 launchd/configure.ac create mode 100755 launchd/depcomp create mode 100644 launchd/doc/Makefile.am create mode 100644 launchd/doc/Makefile.in create mode 100644 launchd/doc/StartupItem-NOTES.rtf create mode 100644 launchd/doc/com.apple.launchdebugd.xml create mode 100755 launchd/install-sh create mode 100755 launchd/missing create mode 100755 launchd/mkinstalldirs create mode 100644 launchd/src/ConsoleMessage.8 create mode 100644 launchd/src/ConsoleMessage.c create mode 100644 launchd/src/IPC.c create mode 100644 launchd/src/IPC.h create mode 100644 launchd/src/Makefile.am create mode 100644 launchd/src/Makefile.in create mode 100644 launchd/src/StartupItemContext.8 create mode 100644 launchd/src/StartupItemContext.c create mode 100644 launchd/src/StartupItems.c create mode 100644 launchd/src/StartupItems.h create mode 100644 launchd/src/StartupItems/Apache create mode 100644 launchd/src/StartupItems/Apache.plist create mode 100644 launchd/src/StartupItems/AppServices create mode 100644 launchd/src/StartupItems/AppServices.plist create mode 100644 launchd/src/StartupItems/AppleShare create mode 100644 launchd/src/StartupItems/AppleShare.plist create mode 100644 launchd/src/StartupItems/AuthServer create mode 100644 launchd/src/StartupItems/AuthServer.plist create mode 100644 launchd/src/StartupItems/Disks create mode 100644 launchd/src/StartupItems/Disks.plist create mode 100644 launchd/src/StartupItems/IPServices create mode 100644 launchd/src/StartupItems/IPServices.plist create mode 100644 launchd/src/StartupItems/NFS create mode 100644 launchd/src/StartupItems/NFS.plist create mode 100644 launchd/src/StartupItems/NIS create mode 100644 launchd/src/StartupItems/NIS.plist create mode 100644 launchd/src/StartupItems/NetworkTime create mode 100644 launchd/src/StartupItems/NetworkTime.plist create mode 100644 launchd/src/SystemStarter.8 create mode 100644 launchd/src/SystemStarter.c create mode 100644 launchd/src/SystemStarter.h create mode 100644 launchd/src/SystemStarterIPC.h create mode 100644 launchd/src/bootstrap.c create mode 100644 launchd/src/bootstrap.defs create mode 100644 launchd/src/bootstrap_internal.h create mode 100644 launchd/src/config.h.in create mode 100644 launchd/src/hostconfig create mode 100644 launchd/src/init.8 create mode 100644 launchd/src/init.c create mode 100644 launchd/src/launch.h create mode 100644 launchd/src/launch_priv.h create mode 100644 launchd/src/launchctl.1 create mode 100644 launchd/src/launchctl.c create mode 100644 launchd/src/launchd.8 create mode 100644 launchd/src/launchd.c create mode 100644 launchd/src/launchd.conf.5 create mode 100644 launchd/src/launchd.h create mode 100644 launchd/src/launchd.plist.5 create mode 100644 launchd/src/launchd_debugd.8 create mode 100644 launchd/src/launchdebugd.c create mode 100644 launchd/src/launchproxy.8 create mode 100644 launchd/src/launchproxy.c create mode 100644 launchd/src/liblaunch.c create mode 100644 launchd/src/lists.c create mode 100644 launchd/src/lists.h create mode 100644 launchd/src/rc create mode 100644 launchd/src/rc.8 create mode 100644 launchd/src/rc.common create mode 100644 launchd/src/rc.netboot create mode 100644 launchd/src/rc.shutdown create mode 100644 launchd/src/register_mach_bootstrap_servers.c create mode 100644 launchd/src/rpc_services.c create mode 100755 launchd/src/service create mode 100644 launchd/src/service.8 create mode 100644 launchd/src/wait4path.1 create mode 100644 launchd/src/wait4path.c create mode 100644 launchd/testing/StartInterval.plist create mode 100644 launchd/testing/badexec.plist create mode 100644 launchd/testing/badexit.plist create mode 100644 launchd/testing/missed-EVFILT_WRITE.c create mode 100644 launchd/testing/missing_req_keys.plist create mode 100644 launchd/testing/secsock.plist create mode 100644 launchd/testing/signaldeath.plist diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6cbc3ea --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +Project = launchd +Extra_Configure_Flags = --sbindir=/sbin --bindir=/bin --sysconfdir=/private/etc +GnuAfterInstall = launchd_after_install +include $(MAKEFILEPATH)/CoreOS/ReleaseControl/GNUSource.make +Install_Flags = DESTDIR=$(DSTROOT) + +launchd_after_install:: +ifeq ($(RC_ProjectName),launchd_libs) + -find -d $(DSTROOT) -type f | grep -v /usr/local/lib/system | xargs rm + -find -d $(DSTROOT) -type l | grep -v /usr/local/lib/system | xargs rm + -find -d $(DSTROOT) -type d | grep -v /usr/local/lib/system | xargs rmdir +else + mkdir -p $(DSTROOT)/Library/StartupItems + chmod 755 $(DSTROOT)/Library/StartupItems + rm -rf $(DSTROOT)/usr/local/lib/system +endif + +launchd_libs:: install diff --git a/launchd/AUTHORS b/launchd/AUTHORS new file mode 100644 index 0000000..9881eeb --- /dev/null +++ b/launchd/AUTHORS @@ -0,0 +1,4 @@ +Dave Zarzycki zarzycki@apple.com Most everything here. +Fred Sanchez wsanchez@apple.com The original SystemStarter. +BSD et. al. init +CMU et. al. mach_init diff --git a/launchd/COPYING b/launchd/COPYING new file mode 100644 index 0000000..fe81a60 --- /dev/null +++ b/launchd/COPYING @@ -0,0 +1,367 @@ +APPLE PUBLIC SOURCE LICENSE +Version 2.0 - August 6, 2003 + +Please read this License carefully before downloading this software. +By downloading or using this software, you are agreeing to be bound by +the terms of this License. If you do not or cannot agree to the terms +of this License, please do not download or use the software. + +1. General; Definitions. This License applies to any program or other +work which Apple Computer, Inc. ("Apple") makes publicly available and +which contains a notice placed by Apple identifying such program or +work as "Original Code" and stating that it is subject to the terms of +this Apple Public Source License version 2.0 ("License"). As used in +this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is +the grantor of rights, (i) claims of patents that are now or hereafter +acquired, owned by or assigned to Apple and (ii) that cover subject +matter contained in the Original Code, but only to the extent +necessary to use, reproduce and/or distribute the Original Code +without infringement; and (b) in the case where You are the grantor of +rights, (i) claims of patents that are now or hereafter acquired, +owned by or assigned to You and (ii) that cover subject matter in Your +Modifications, taken alone or in combination with Original Code. + +1.2 "Contributor" means any person or entity that creates or +contributes to the creation of Modifications. + +1.3 "Covered Code" means the Original Code, Modifications, the +combination of Original Code and any Modifications, and/or any +respective portions thereof. + +1.4 "Externally Deploy" means: (a) to sublicense, distribute or +otherwise make Covered Code available, directly or indirectly, to +anyone other than You; and/or (b) to use Covered Code, alone or as +part of a Larger Work, in any way to provide a service, including but +not limited to delivery of content, through electronic communication +with a client other than You. + +1.5 "Larger Work" means a work which combines Covered Code or portions +thereof with code not governed by the terms of this License. + +1.6 "Modifications" mean any addition to, deletion from, and/or change +to, the substance and/or structure of the Original Code, any previous +Modifications, the combination of Original Code and any previous +Modifications, and/or any respective portions thereof. When code is +released as a series of files, a Modification is: (a) any addition to +or deletion from the contents of a file containing Covered Code; +and/or (b) any new file or other representation of computer program +statements that contains any part of Covered Code. + +1.7 "Original Code" means (a) the Source Code of a program or other +work as originally made available by Apple under this License, +including the Source Code of any updates or upgrades to such programs +or works made available by Apple under this License, and that has been +expressly identified by Apple as such in the header file(s) of such +work; and (b) the object code compiled from such Source Code and +originally made available by Apple under this License. + +1.8 "Source Code" means the human readable form of a program or other +work that is suitable for making modifications to it, including all +modules it contains, plus any associated interface definition files, +scripts used to control compilation and installation of an executable +(object code). + +1.9 "You" or "Your" means an individual or a legal entity exercising +rights under this License. For legal entities, "You" or "Your" +includes any entity which controls, is controlled by, or is under +common control with, You, where "control" means (a) the power, direct +or indirect, to cause the direction or management of such entity, +whether by contract or otherwise, or (b) ownership of fifty percent +(50%) or more of the outstanding shares or beneficial ownership of +such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms +and conditions of this License, Apple hereby grants You, effective on +the date You accept this License and download the Original Code, a +world-wide, royalty-free, non-exclusive license, to the extent of +Apple's Applicable Patent Rights and copyrights covering the Original +Code, to do the following: + +2.1 Unmodified Code. You may use, reproduce, display, perform, +internally distribute within Your organization, and Externally Deploy +verbatim, unmodified copies of the Original Code, for commercial or +non-commercial purposes, provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the +copyright and other proprietary notices and disclaimers of Apple as +they appear in the Original Code, and keep intact all notices in the +Original Code that refer to this License; and + +(b) You must include a copy of this License with every copy of Source +Code of Covered Code and documentation You distribute or Externally +Deploy, and You may not offer or impose any terms on such Source Code +that alter or restrict this License or the recipients' rights +hereunder, except as permitted under Section 6. + +2.2 Modified Code. You may modify Covered Code and use, reproduce, +display, perform, internally distribute within Your organization, and +Externally Deploy Your Modifications and Covered Code, for commercial +or non-commercial purposes, provided that in each instance You also +meet all of these conditions: + +(a) You must satisfy all the conditions of Section 2.1 with respect to +the Source Code of the Covered Code; + +(b) You must duplicate, to the extent it does not already exist, the +notice in Exhibit A in each file of the Source Code of all Your +Modifications, and cause the modified files to carry prominent notices +stating that You changed the files and the date of any change; and + +(c) If You Externally Deploy Your Modifications, You must make +Source Code of all Your Externally Deployed Modifications either +available to those to whom You have Externally Deployed Your +Modifications, or publicly available. Source Code of Your Externally +Deployed Modifications must be released under the terms set forth in +this License, including the license grants set forth in Section 3 +below, for as long as you Externally Deploy the Covered Code or twelve +(12) months from the date of initial External Deployment, whichever is +longer. You should preferably distribute the Source Code of Your +Externally Deployed Modifications electronically (e.g. download from a +web site). + +2.3 Distribution of Executable Versions. In addition, if You +Externally Deploy Covered Code (Original Code and/or Modifications) in +object code, executable form only, You must include a prominent +notice, in the code itself as well as in related documentation, +stating that Source Code of the Covered Code is available under the +terms of this License with information on how and where to obtain such +Source Code. + +2.4 Third Party Rights. You expressly acknowledge and agree that +although Apple and each Contributor grants the licenses to their +respective portions of the Covered Code set forth herein, no +assurances are provided by Apple or any Contributor that the Covered +Code does not infringe the patent or other intellectual property +rights of any other entity. Apple and each Contributor disclaim any +liability to You for claims brought by any other entity based on +infringement of intellectual property rights or otherwise. As a +condition to exercising the rights and licenses granted hereunder, You +hereby assume sole responsibility to secure any other intellectual +property rights needed, if any. For example, if a third party patent +license is required to allow You to distribute the Covered Code, it is +Your responsibility to acquire that license before distributing the +Covered Code. + +3. Your Grants. In consideration of, and as a condition to, the +licenses granted to You under this License, You hereby grant to any +person or entity receiving or distributing Covered Code under this +License a non-exclusive, royalty-free, perpetual, irrevocable license, +under Your Applicable Patent Rights and other intellectual property +rights (other than patent) owned or controlled by You, to use, +reproduce, display, perform, modify, sublicense, distribute and +Externally Deploy Your Modifications of the same scope and extent as +Apple's licenses under Sections 2.1 and 2.2 above. + +4. Larger Works. You may create a Larger Work by combining Covered +Code with other code not governed by the terms of this License and +distribute the Larger Work as a single product. In each such instance, +You must make sure the requirements of this License are fulfilled for +the Covered Code or any portion thereof. + +5. Limitations on Patent License. Except as expressly stated in +Section 2, no other patent rights, express or implied, are granted by +Apple herein. Modifications and/or Larger Works may require additional +patent licenses from Apple which Apple may grant in its sole +discretion. + +6. Additional Terms. You may choose to offer, and to charge a fee for, +warranty, support, indemnity or liability obligations and/or other +rights consistent with the scope of the license granted herein +("Additional Terms") to one or more recipients of Covered Code. +However, You may do so only on Your own behalf and as Your sole +responsibility, and not on behalf of Apple or any Contributor. You +must obtain the recipient's agreement that any such Additional Terms +are offered by You alone, and You hereby agree to indemnify, defend +and hold Apple and every Contributor harmless for any liability +incurred by or claims asserted against Apple or such Contributor by +reason of any such Additional Terms. + +7. Versions of the License. Apple may publish revised and/or new +versions of this License from time to time. Each version will be given +a distinguishing version number. Once Original Code has been published +under a particular version of this License, You may continue to use it +under the terms of that version. You may also choose to use such +Original Code under the terms of any subsequent version of this +License published by Apple. No one other than Apple has the right to +modify the terms applicable to Covered Code created under this +License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in +part pre-release, untested, or not fully tested works. The Covered +Code may contain errors that could cause failures or loss of data, and +may be incomplete or contain inaccuracies. You expressly acknowledge +and agree that use of the Covered Code, or any portion thereof, is at +Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND +WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND +APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE +PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM +ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF +MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR +PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD +PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST +INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE +FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS, +THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR +ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO +ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE +AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. +You acknowledge that the Covered Code is not intended for use in the +operation of nuclear facilities, aircraft navigation, communication +systems, or air traffic control machines in which case the failure of +the Covered Code could lead to death, personal injury, or severe +physical or environmental damage. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO +EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING +TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR +ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY, +TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF +APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY +REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF +INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY +TO YOU. In no event shall Apple's total liability to You for all +damages (other than as may be required by applicable law) under this +License exceed the amount of fifty dollars ($50.00). + +10. Trademarks. This License does not grant any rights to use the +trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS", +"QuickTime", "QuickTime Streaming Server" or any other trademarks, +service marks, logos or trade names belonging to Apple (collectively +"Apple Marks") or to any trademark, service mark, logo or trade name +belonging to any Contributor. You agree not to use any Apple Marks in +or as part of the name of products derived from the Original Code or +to endorse or promote products derived from the Original Code other +than as expressly permitted by and in strict compliance at all times +with Apple's third party trademark usage guidelines which are posted +at http://www.apple.com/legal/guidelinesfor3rdparties.html. + +11. Ownership. Subject to the licenses granted under this License, +each Contributor retains all rights, title and interest in and to any +Modifications made by such Contributor. Apple retains all rights, +title and interest in and to the Original Code and any Modifications +made by or on behalf of Apple ("Apple Modifications"), and such Apple +Modifications will not be automatically subject to this License. Apple +may, at its sole discretion, choose to license such Apple +Modifications under this License, or on different terms from those +contained in this License or may choose not to license them at all. + +12. Termination. + +12.1 Termination. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Apple if You fail to comply with +any term(s) of this License and fail to cure such breach within 30 +days of becoming aware of such breach; + +(b) immediately in the event of the circumstances described in Section +13.5(b); or + +(c) automatically without notice from Apple if You, at any time during +the term of this License, commence an action for patent infringement +against Apple; provided that Apple did not first commence +an action for patent infringement against You in that instance. + +12.2 Effect of Termination. Upon termination, You agree to immediately +stop any further use, reproduction, modification, sublicensing and +distribution of the Covered Code. All sublicenses to the Covered Code +which have been properly granted prior to termination shall survive +any termination of this License. Provisions which, by their nature, +should remain in effect beyond the termination of this License shall +survive, including but not limited to Sections 3, 5, 8, 9, 10, 11, +12.2 and 13. No party will be liable to any other for compensation, +indemnity or damages of any sort solely as a result of terminating +this License in accordance with its terms, and termination of this +License will be without prejudice to any other right or remedy of +any party. + +13. Miscellaneous. + +13.1 Government End Users. The Covered Code is a "commercial item" as +defined in FAR 2.101. Government software and technical data rights in +the Covered Code include only those rights customarily provided to the +public as defined in this License. This customary commercial license +in technical data and software is provided in accordance with FAR +12.211 (Technical Data) and 12.212 (Computer Software) and, for +Department of Defense purchases, DFAR 252.227-7015 (Technical Data -- +Commercial Items) and 227.7202-3 (Rights in Commercial Computer +Software or Computer Software Documentation). Accordingly, all U.S. +Government End Users acquire Covered Code with only those rights set +forth herein. + +13.2 Relationship of Parties. This License will not be construed as +creating an agency, partnership, joint venture or any other form of +legal association between or among You, Apple or any Contributor, and +You will not represent to the contrary, whether expressly, by +implication, appearance or otherwise. + +13.3 Independent Development. Nothing in this License will impair +Apple's right to acquire, license, develop, have others develop for +it, market and/or distribute technology or products that perform the +same or similar functions as, or otherwise compete with, +Modifications, Larger Works, technology or products that You may +develop, produce, market or distribute. + +13.4 Waiver; Construction. Failure by Apple or any Contributor to +enforce any provision of this License will not be deemed a waiver of +future enforcement of that or any other provision. Any law or +regulation which provides that the language of a contract shall be +construed against the drafter will not apply to this License. + +13.5 Severability. (a) If for any reason a court of competent +jurisdiction finds any provision of this License, or portion thereof, +to be unenforceable, that provision of the License will be enforced to +the maximum extent permissible so as to effect the economic benefits +and intent of the parties, and the remainder of this License will +continue in full force and effect. (b) Notwithstanding the foregoing, +if applicable law prohibits or restricts You from fully and/or +specifically complying with Sections 2 and/or 3 or prevents the +enforceability of either of those Sections, this License will +immediately terminate and You must immediately discontinue any use of +the Covered Code and destroy all copies of it that are in your +possession or control. + +13.6 Dispute Resolution. Any litigation or other dispute resolution +between You and Apple relating to this License shall take place in the +Northern District of California, and You and Apple hereby consent to +the personal jurisdiction of, and venue in, the state and federal +courts within that District with respect to this License. The +application of the United Nations Convention on Contracts for the +International Sale of Goods is expressly excluded. + +13.7 Entire Agreement; Governing Law. This License constitutes the +entire agreement between the parties with respect to the subject +matter hereof. This License shall be governed by the laws of the +United States and the State of California, except that body of +California law concerning conflicts of law. + +Where You are located in the province of Quebec, Canada, the following +clause applies: The parties hereby confirm that they have requested +that this License and all related documents be drafted in English. Les +parties ont exige que le present contrat et tous les documents +connexes soient rediges en anglais. + +EXHIBIT A. + +"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights +Reserved. + +This file contains Original Code and/or Modifications of Original Code +as defined in and that are subject to the Apple Public Source License +Version 2.0 (the 'License'). You may not use this file except in +compliance with the License. Please obtain a copy of the License at +http://www.opensource.apple.com/apsl/ and read it before using this +file. + +The Original Code and all software distributed under the License are +distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +Please see the License for the specific language governing rights and +limitations under the License." diff --git a/launchd/ChangeLog b/launchd/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/launchd/INSTALL b/launchd/INSTALL new file mode 100644 index 0000000..a4b3414 --- /dev/null +++ b/launchd/INSTALL @@ -0,0 +1,229 @@ +Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software +Foundation, Inc. + + This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/launchd/Makefile.am b/launchd/Makefile.am new file mode 100644 index 0000000..af437a6 --- /dev/null +++ b/launchd/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/launchd/Makefile.in b/launchd/Makefile.in new file mode 100644 index 0000000..613b3bf --- /dev/null +++ b/launchd/Makefile.in @@ -0,0 +1,397 @@ +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = . + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AWK = @AWK@ +CC = @CC@ +DEPDIR = @DEPDIR@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ +SUBDIRS = src +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/src/config.h +CONFIG_CLEAN_FILES = +DIST_SOURCES = + +RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \ + uninstall-info-recursive all-recursive install-data-recursive \ + install-exec-recursive installdirs-recursive install-recursive \ + uninstall-recursive check-recursive installcheck-recursive +DIST_COMMON = README AUTHORS COPYING ChangeLog INSTALL Makefile.am \ + Makefile.in NEWS TODO aclocal.m4 compile configure configure.ac \ + depcomp install-sh missing mkinstalldirs +DIST_SUBDIRS = $(SUBDIRS) +all: all-recursive + +.SUFFIXES: + +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe) + +$(top_builddir)/config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck +$(srcdir)/configure: $(srcdir)/configure.ac $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) + cd $(srcdir) && $(AUTOCONF) + +$(ACLOCAL_M4): configure.ac + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +uninstall-info-am: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +ETAGS = etags +ETAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = . +distdir = $(PACKAGE)-$(VERSION) + +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } + +GZIP_ENV = --best +distcleancheck_listfiles = find . -type f -print + +distdir: $(DISTFILES) + $(am__remove_distdir) + mkdir $(distdir) + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" \ + distdir=../$(distdir)/$$subdir \ + distdir) \ + || exit 1; \ + fi; \ + done + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist dist-all: distdir + $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + $(am__remove_distdir) + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf - + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/=build + mkdir $(distdir)/=inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/=inst && pwd` \ + && cd $(distdir)/=build \ + && ../configure --srcdir=.. --prefix=$$dc_install_base \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && (test `find $$dc_install_base -type f -print | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + find $$dc_install_base -type f -print ; \ + exit 1; } >&2 ) \ + && $(MAKE) $(AM_MAKEFLAGS) dist-gzip \ + && rm -f $(distdir).tar.gz \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @echo "$(distdir).tar.gz is ready for distribution" | \ + sed 'h;s/./=/g;p;x;p;x' +distcleancheck: distclean + if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: + +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf autom4te.cache +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic + +uninstall-am: uninstall-info-am + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) GTAGS all all-am check check-am clean \ + clean-generic clean-recursive dist dist-all dist-gzip distcheck \ + distclean distclean-generic distclean-recursive distclean-tags \ + distcleancheck distdir dvi dvi-am dvi-recursive info info-am \ + info-recursive install install-am install-data install-data-am \ + install-data-recursive install-exec install-exec-am \ + install-exec-recursive install-info install-info-am \ + install-info-recursive install-man install-recursive \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am installdirs-recursive maintainer-clean \ + maintainer-clean-generic maintainer-clean-recursive mostlyclean \ + mostlyclean-generic mostlyclean-recursive tags tags-recursive \ + uninstall uninstall-am uninstall-info-am \ + uninstall-info-recursive uninstall-recursive + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/launchd/NEWS b/launchd/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/launchd/README b/launchd/README new file mode 100644 index 0000000..e69de29 diff --git a/launchd/TODO b/launchd/TODO new file mode 100644 index 0000000..d739d48 --- /dev/null +++ b/launchd/TODO @@ -0,0 +1,20 @@ +per user support +\_ job mgmt +\_ tmp dir +job exponential backoff and recursion prevention + + + +file system events +mach events +cron +at +legacy parsers +monitor +\_ cocoa +\_ cli +documentation +code audit +init support +anacron support +sample dameon diff --git a/launchd/aclocal.m4 b/launchd/aclocal.m4 new file mode 100644 index 0000000..d78e9d0 --- /dev/null +++ b/launchd/aclocal.m4 @@ -0,0 +1,836 @@ +# aclocal.m4 generated automatically by aclocal 1.6.3 -*- Autoconf -*- + +# Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# Do all the work for Automake. -*- Autoconf -*- + +# This macro actually does too much some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 8 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +AC_PREREQ([2.52]) + +# Autoconf 2.50 wants to disallow AM_ names. We explicitly allow +# the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl + AC_REQUIRE([AC_PROG_INSTALL])dnl +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl + AC_SUBST([PACKAGE], [AC_PACKAGE_TARNAME])dnl + AC_SUBST([VERSION], [AC_PACKAGE_VERSION])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_MISSING_PROG(AMTAR, tar) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl + +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_][CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_][CC], + defn([AC_PROG_][CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_][CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_][CXX], + defn([AC_PROG_][CXX])[_AM_DEPENDENCIES(CXX)])])dnl +]) +]) + +# Copyright 2002 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +AC_DEFUN([AM_AUTOMAKE_VERSION],[am__api_version="1.6"]) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION so it can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], + [AM_AUTOMAKE_VERSION([1.6.3])]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright 2001, 2002 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 2 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# +# Check to make sure that the build environment is sane. +# + +# Copyright 1996, 1997, 2000, 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 3 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# -*- Autoconf -*- + + +# Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 3 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# AM_AUX_DIR_EXPAND + +# Copyright 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +# Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50]) + +AC_DEFUN([AM_AUX_DIR_EXPAND], [ +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. + +# Copyright 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"$am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# AM_PROG_INSTALL_STRIP + +# Copyright 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# serial 4 -*- Autoconf -*- + +# Copyright 1999, 2000, 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + echo '#include "conftest.h"' > conftest.c + echo 'int i;' > conftest.h + echo "${am__include} ${am__quote}conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=conftest.c object=conftest.o \ + depfile=conftest.Po tmpdepfile=conftest.TPo \ + $SHELL ./depcomp $depcc -c conftest.c -o conftest.o >/dev/null 2>&1 && + grep conftest.h conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[rm -f .deps 2>/dev/null +mkdir .deps 2>/dev/null +if test -d .deps; then + DEPDIR=.deps +else + # MS-DOS does not allow filenames that begin with a dot. + DEPDIR=_deps +fi +rmdir .deps 2>/dev/null +AC_SUBST([DEPDIR]) +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking Speeds up one-time builds + --enable-dependency-tracking Do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH]) +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +#serial 2 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + grep '^DEP_FILES *= *[[^ @%:@]]' < "$mf" > /dev/null || continue + # Extract the definition of DEP_FILES from the Makefile without + # running `make'. + DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"` + test -z "$DEPDIR" && continue + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n -e '/^U = / s///p' < "$mf"` + test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR" + # We invoke sed twice because it is the simplest approach to + # changing $(DEPDIR) to its actual value in the expansion. + for file in `sed -n -e ' + /^DEP_FILES = .*\\\\$/ { + s/^DEP_FILES = // + :loop + s/\\\\$// + p + n + /\\\\$/ b loop + p + } + /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Copyright 2001 Free Software Foundation, Inc. -*- Autoconf -*- + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 2 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +doit: + @echo done +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | fgrep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST(am__include) +AC_SUBST(am__quote) +AC_MSG_RESULT($_am_result) +rm -f confinc confmf +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright 1997, 2000, 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 5 + +AC_PREREQ(2.52) + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE]) +AC_SUBST([$1_FALSE]) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([conditional \"$1\" was never defined. +Usually this means the macro was only invoked conditionally.]) +fi])]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. -*- Autoconf -*- + +# Copyright 1996, 1997, 2000, 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +AC_PREREQ([2.52]) + +# serial 6 + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. We must strip everything past the first ":", +# and everything past the last "/". + +# _AM_DIRNAME(PATH) +# ----------------- +# Like AS_DIRNAME, only do it during macro expansion +AC_DEFUN([_AM_DIRNAME], + [m4_if(regexp([$1], [^.*[^/]//*[^/][^/]*/*$]), -1, + m4_if(regexp([$1], [^//\([^/]\|$\)]), -1, + m4_if(regexp([$1], [^/.*]), -1, + [.], + patsubst([$1], [^\(/\).*], [\1])), + patsubst([$1], [^\(//\)\([^/].*\|$\)], [\1])), + patsubst([$1], [^\(.*[^/]\)//*[^/][^/]*/*$], [\1]))[]dnl +])# _AM_DIRNAME + + +# The stamp files are numbered to have different names. +# We could number them on a directory basis, but that's additional +# complications, let's have a unique counter. +m4_define([_AM_STAMP_Count], [0]) + + +# _AM_STAMP(HEADER) +# ----------------- +# The name of the stamp file for HEADER. +AC_DEFUN([_AM_STAMP], +[m4_define([_AM_STAMP_Count], m4_incr(_AM_STAMP_Count))dnl +AS_ESCAPE(_AM_DIRNAME(patsubst([$1], + [:.*])))/stamp-h[]_AM_STAMP_Count]) + + +# _AM_CONFIG_HEADER(HEADER[:SOURCES], COMMANDS, INIT-COMMANDS) +# ------------------------------------------------------------ +# We used to try to get a real timestamp in stamp-h. But the fear is that +# that will cause unnecessary cvs conflicts. +AC_DEFUN([_AM_CONFIG_HEADER], +[# Add the stamp file to the list of files AC keeps track of, +# along with our hook. +AC_CONFIG_HEADERS([$1], + [# update the timestamp +echo 'timestamp for $1' >"_AM_STAMP([$1])" +$2], + [$3]) +])# _AM_CONFIG_HEADER + + +# AM_CONFIG_HEADER(HEADER[:SOURCES]..., COMMANDS, INIT-COMMANDS) +# -------------------------------------------------------------- +AC_DEFUN([AM_CONFIG_HEADER], +[AC_FOREACH([_AM_File], [$1], [_AM_CONFIG_HEADER(_AM_File, [$2], [$3])]) +])# AM_CONFIG_HEADER + diff --git a/launchd/compile b/launchd/compile new file mode 100755 index 0000000..9bb997a --- /dev/null +++ b/launchd/compile @@ -0,0 +1,99 @@ +#! /bin/sh + +# Wrapper for compilers which do not understand `-c -o'. + +# Copyright 1999, 2000 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Usage: +# compile PROGRAM [ARGS]... +# `-o FOO.o' is removed from the args passed to the actual compile. + +prog=$1 +shift + +ofile= +cfile= +args= +while test $# -gt 0; do + case "$1" in + -o) + # configure might choose to run compile as `compile cc -o foo foo.c'. + # So we do something ugly here. + ofile=$2 + shift + case "$ofile" in + *.o | *.obj) + ;; + *) + args="$args -o $ofile" + ofile= + ;; + esac + ;; + *.c) + cfile=$1 + args="$args $1" + ;; + *) + args="$args $1" + ;; + esac + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no `-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # `.c' file was seen then we are probably linking. That is also + # ok. + exec "$prog" $args +fi + +# Name of file we expect compiler to create. +cofile=`echo $cfile | sed -e 's|^.*/||' -e 's/\.c$/.o/'` + +# Create the lock directory. +# Note: use `[/.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo $cofile | sed -e 's|[/.-]|_|g'`.d +while true; do + if mkdir $lockdir > /dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir $lockdir; exit 1" 1 2 15 + +# Run the compile. +"$prog" $args +status=$? + +if test -f "$cofile"; then + mv "$cofile" "$ofile" +fi + +rmdir $lockdir +exit $status diff --git a/launchd/configure b/launchd/configure new file mode 100755 index 0000000..546984a --- /dev/null +++ b/launchd/configure @@ -0,0 +1,7442 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59 for launchd 1.0. +# +# Report bugs to . +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME='launchd' +PACKAGE_TARNAME='launchd' +PACKAGE_VERSION='1.0' +PACKAGE_STRING='launchd 1.0' +PACKAGE_BUGREPORT='launchd-bug-reports@group.apple.com' + +ac_unique_file="src/ConsoleMessage.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO AMTAR install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM AWK SET_MAKE CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE RANLIB ac_ct_RANLIB CPP EGREP LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures launchd 1.0 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of launchd 1.0:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-dependency-tracking Speeds up one-time builds + --enable-dependency-tracking Do not reject slow dependency extractors + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF +launchd configure 1.0 +generated by GNU Autoconf 2.59 + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by launchd $as_me 1.0, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + + + + + + + + + +am__api_version="1.6" +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +test "$program_prefix" != NONE && + program_transform_name="s,^,$program_prefix,;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$,$program_suffix,;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm conftest.sed + + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$AWK" && break +done + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + # test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +# Define the identity of the package. + PACKAGE=launchd + VERSION=1.0 + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +install_sh=${install_sh-"$am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. + + + +# Add the stamp file to the list of files AC keeps track of, +# along with our hook. + ac_config_headers="$ac_config_headers src/config.h" + + + + +# Checks for programs. +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +rm -f .deps 2>/dev/null +mkdir .deps 2>/dev/null +if test -d .deps; then + DEPDIR=.deps +else + # MS-DOS does not allow filenames that begin with a dot. + DEPDIR=_deps +fi +rmdir .deps 2>/dev/null + + + ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +doit: + @echo done +END +# If we don't find an include directive, just comment out the code. +echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6 +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | fgrep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6 +rm -f confinc confmf + +# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval="$enable_dependency_tracking" + +fi; +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + + +if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + + +depcc="$CC" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + echo '#include "conftest.h"' > conftest.c + echo 'int i;' > conftest.h + echo "${am__include} ${am__quote}conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=conftest.c object=conftest.o \ + depfile=conftest.Po tmpdepfile=conftest.TPo \ + $SHELL ./depcomp $depcc -c conftest.c -o conftest.o >/dev/null 2>&1 && + grep conftest.h conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +# Checks for libraries. + +# Checks for header files. + + + + + + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do + as_ac_Header=`echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_hdr that defines DIR" >&5 +echo $ECHO_N "checking for $ac_hdr that defines DIR... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include <$ac_hdr> + +int +main () +{ +if ((DIR *) 0) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 +_ACEOF + +ac_header_dirent=$ac_hdr; break +fi + +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then + echo "$as_me:$LINENO: checking for library containing opendir" >&5 +echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6 +if test "${ac_cv_search_opendir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +ac_cv_search_opendir=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir (); +int +main () +{ +opendir (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="none required" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "$ac_cv_search_opendir" = no; then + for ac_lib in dir; do + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir (); +int +main () +{ +opendir (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="-l$ac_lib" +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done +fi +LIBS=$ac_func_search_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 +echo "${ECHO_T}$ac_cv_search_opendir" >&6 +if test "$ac_cv_search_opendir" != no; then + test "$ac_cv_search_opendir" = "none required" || LIBS="$ac_cv_search_opendir $LIBS" + +fi + +else + echo "$as_me:$LINENO: checking for library containing opendir" >&5 +echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6 +if test "${ac_cv_search_opendir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +ac_cv_search_opendir=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir (); +int +main () +{ +opendir (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="none required" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "$ac_cv_search_opendir" = no; then + for ac_lib in x; do + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir (); +int +main () +{ +opendir (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="-l$ac_lib" +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done +fi +LIBS=$ac_func_search_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 +echo "${ECHO_T}$ac_cv_search_opendir" >&6 +if test "$ac_cv_search_opendir" != no; then + test "$ac_cv_search_opendir" = "none required" || LIBS="$ac_cv_search_opendir $LIBS" + +fi + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for sys/wait.h that is POSIX.1 compatible" >&5 +echo $ECHO_N "checking for sys/wait.h that is POSIX.1 compatible... $ECHO_C" >&6 +if test "${ac_cv_header_sys_wait_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +int +main () +{ + int s; + wait (&s); + s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_sys_wait_h=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_sys_wait_h=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_header_sys_wait_h" >&5 +echo "${ECHO_T}$ac_cv_header_sys_wait_h" >&6 +if test $ac_cv_header_sys_wait_h = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SYS_WAIT_H 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + + + + +for ac_header in fcntl.h limits.h mach/mach.h stdlib.h string.h syslog.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------------- ## +## Report this to launchd-bug-reports@group.apple.com ## +## -------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# Checks for typedefs, structures, and compiler characteristics. +echo "$as_me:$LINENO: checking for stdbool.h that conforms to C99" >&5 +echo $ECHO_N "checking for stdbool.h that conforms to C99... $ECHO_C" >&6 +if test "${ac_cv_header_stdbool_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#ifndef bool +# error bool is not defined +#endif +#ifndef false +# error false is not defined +#endif +#if false +# error false is not 0 +#endif +#ifndef true +# error true is not defined +#endif +#if true != 1 +# error true is not 1 +#endif +#ifndef __bool_true_false_are_defined +# error __bool_true_false_are_defined is not defined +#endif + + struct s { _Bool s: 1; _Bool t; } s; + + char a[true == 1 ? 1 : -1]; + char b[false == 0 ? 1 : -1]; + char c[__bool_true_false_are_defined == 1 ? 1 : -1]; + char d[(bool) -0.5 == true ? 1 : -1]; + bool e = &s; + char f[(_Bool) -0.0 == false ? 1 : -1]; + char g[true]; + char h[sizeof (_Bool)]; + char i[sizeof s.t]; + +int +main () +{ + return !a + !b + !c + !d + !e + !f + !g + !h + !i; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdbool_h=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdbool_h=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdbool_h" >&5 +echo "${ECHO_T}$ac_cv_header_stdbool_h" >&6 +echo "$as_me:$LINENO: checking for _Bool" >&5 +echo $ECHO_N "checking for _Bool... $ECHO_C" >&6 +if test "${ac_cv_type__Bool+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((_Bool *) 0) + return 0; +if (sizeof (_Bool)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type__Bool=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type__Bool=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type__Bool" >&5 +echo "${ECHO_T}$ac_cv_type__Bool" >&6 +if test $ac_cv_type__Bool = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE__BOOL 1 +_ACEOF + + +fi + +if test $ac_cv_header_stdbool_h = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_STDBOOL_H 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_const=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for mode_t" >&5 +echo $ECHO_N "checking for mode_t... $ECHO_C" >&6 +if test "${ac_cv_type_mode_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((mode_t *) 0) + return 0; +if (sizeof (mode_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_mode_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_mode_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_mode_t" >&5 +echo "${ECHO_T}$ac_cv_type_mode_t" >&6 +if test $ac_cv_type_mode_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define mode_t int +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for off_t" >&5 +echo $ECHO_N "checking for off_t... $ECHO_C" >&6 +if test "${ac_cv_type_off_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((off_t *) 0) + return 0; +if (sizeof (off_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_off_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_off_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_off_t" >&5 +echo "${ECHO_T}$ac_cv_type_off_t" >&6 +if test $ac_cv_type_off_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define off_t long +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for pid_t" >&5 +echo $ECHO_N "checking for pid_t... $ECHO_C" >&6 +if test "${ac_cv_type_pid_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((pid_t *) 0) + return 0; +if (sizeof (pid_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_pid_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_pid_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_pid_t" >&5 +echo "${ECHO_T}$ac_cv_type_pid_t" >&6 +if test $ac_cv_type_pid_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define pid_t int +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for size_t" >&5 +echo $ECHO_N "checking for size_t... $ECHO_C" >&6 +if test "${ac_cv_type_size_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((size_t *) 0) + return 0; +if (sizeof (size_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_size_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_size_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 +echo "${ECHO_T}$ac_cv_type_size_t" >&6 +if test $ac_cv_type_size_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for uid_t in sys/types.h" >&5 +echo $ECHO_N "checking for uid_t in sys/types.h... $ECHO_C" >&6 +if test "${ac_cv_type_uid_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "uid_t" >/dev/null 2>&1; then + ac_cv_type_uid_t=yes +else + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi +echo "$as_me:$LINENO: result: $ac_cv_type_uid_t" >&5 +echo "${ECHO_T}$ac_cv_type_uid_t" >&6 +if test $ac_cv_type_uid_t = no; then + +cat >>confdefs.h <<\_ACEOF +#define uid_t int +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define gid_t int +_ACEOF + +fi + + +# Checks for library functions. +echo "$as_me:$LINENO: checking whether closedir returns void" >&5 +echo $ECHO_N "checking whether closedir returns void... $ECHO_C" >&6 +if test "${ac_cv_func_closedir_void+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_closedir_void=yes +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header_dirent> +#ifndef __cplusplus +int closedir (); +#endif + +int +main () +{ +exit (closedir (opendir (".")) != 0); + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_closedir_void=no +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_closedir_void=yes +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_func_closedir_void" >&5 +echo "${ECHO_T}$ac_cv_func_closedir_void" >&6 +if test $ac_cv_func_closedir_void = yes; then + +cat >>confdefs.h <<\_ACEOF +#define CLOSEDIR_VOID 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for error_at_line" >&5 +echo $ECHO_N "checking for error_at_line... $ECHO_C" >&6 +if test "${ac_cv_lib_error_at_line+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +error_at_line (0, 0, "", 0, ""); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_error_at_line=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_error_at_line=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_error_at_line" >&5 +echo "${ECHO_T}$ac_cv_lib_error_at_line" >&6 +if test $ac_cv_lib_error_at_line = no; then + case $LIBOBJS in + "error.$ac_objext" | \ + *" error.$ac_objext" | \ + "error.$ac_objext "* | \ + *" error.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS error.$ac_objext" ;; +esac + +fi + + + +for ac_header in unistd.h vfork.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------------- ## +## Report this to launchd-bug-reports@group.apple.com ## +## -------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_func in fork vfork +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +if test "x$ac_cv_func_fork" = xyes; then + echo "$as_me:$LINENO: checking for working fork" >&5 +echo $ECHO_N "checking for working fork... $ECHO_C" >&6 +if test "${ac_cv_func_fork_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_fork_works=cross +else + cat >conftest.$ac_ext <<_ACEOF +/* By Ruediger Kuhlmann. */ + #include + #if HAVE_UNISTD_H + # include + #endif + /* Some systems only have a dummy stub for fork() */ + int main () + { + if (fork() < 0) + exit (1); + exit (0); + } +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_fork_works=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_fork_works=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_func_fork_works" >&5 +echo "${ECHO_T}$ac_cv_func_fork_works" >&6 + +else + ac_cv_func_fork_works=$ac_cv_func_fork +fi +if test "x$ac_cv_func_fork_works" = xcross; then + case $host in + *-*-amigaos* | *-*-msdosdjgpp*) + # Override, as these systems have only a dummy fork() stub + ac_cv_func_fork_works=no + ;; + *) + ac_cv_func_fork_works=yes + ;; + esac + { echo "$as_me:$LINENO: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 +echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} +fi +ac_cv_func_vfork_works=$ac_cv_func_vfork +if test "x$ac_cv_func_vfork" = xyes; then + echo "$as_me:$LINENO: checking for working vfork" >&5 +echo $ECHO_N "checking for working vfork... $ECHO_C" >&6 +if test "${ac_cv_func_vfork_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_vfork_works=cross +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Thanks to Paul Eggert for this test. */ +#include +#include +#include +#include +#include +#if HAVE_UNISTD_H +# include +#endif +#if HAVE_VFORK_H +# include +#endif +/* On some sparc systems, changes by the child to local and incoming + argument registers are propagated back to the parent. The compiler + is told about this with #include , but some compilers + (e.g. gcc -O) don't grok . Test for this by using a + static variable whose address is put into a register that is + clobbered by the vfork. */ +static void +#ifdef __cplusplus +sparc_address_test (int arg) +# else +sparc_address_test (arg) int arg; +#endif +{ + static pid_t child; + if (!child) { + child = vfork (); + if (child < 0) { + perror ("vfork"); + _exit(2); + } + if (!child) { + arg = getpid(); + write(-1, "", 0); + _exit (arg); + } + } +} + +int +main () +{ + pid_t parent = getpid (); + pid_t child; + + sparc_address_test (0); + + child = vfork (); + + if (child == 0) { + /* Here is another test for sparc vfork register problems. This + test uses lots of local variables, at least as many local + variables as main has allocated so far including compiler + temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris + 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should + reuse the register of parent for one of the local variables, + since it will think that parent can't possibly be used any more + in this routine. Assigning to the local variable will thus + munge parent in the parent process. */ + pid_t + p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), + p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); + /* Convince the compiler that p..p7 are live; otherwise, it might + use the same hardware register for all 8 local variables. */ + if (p != p1 || p != p2 || p != p3 || p != p4 + || p != p5 || p != p6 || p != p7) + _exit(1); + + /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent + from child file descriptors. If the child closes a descriptor + before it execs or exits, this munges the parent's descriptor + as well. Test for this by closing stdout in the child. */ + _exit(close(fileno(stdout)) != 0); + } else { + int status; + struct stat st; + + while (wait(&status) != child) + ; + exit( + /* Was there some problem with vforking? */ + child < 0 + + /* Did the child fail? (This shouldn't happen.) */ + || status + + /* Did the vfork/compiler bug occur? */ + || parent != getpid() + + /* Did the file descriptor bug occur? */ + || fstat(fileno(stdout), &st) != 0 + ); + } +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_vfork_works=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_vfork_works=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_func_vfork_works" >&5 +echo "${ECHO_T}$ac_cv_func_vfork_works" >&6 + +fi; +if test "x$ac_cv_func_fork_works" = xcross; then + ac_cv_func_vfork_works=$ac_cv_func_vfork + { echo "$as_me:$LINENO: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 +echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} +fi + +if test "x$ac_cv_func_vfork_works" = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_WORKING_VFORK 1 +_ACEOF + +else + +cat >>confdefs.h <<\_ACEOF +#define vfork fork +_ACEOF + +fi +if test "x$ac_cv_func_fork_works" = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_WORKING_FORK 1 +_ACEOF + +fi + + +for ac_header in stdlib.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------------- ## +## Report this to launchd-bug-reports@group.apple.com ## +## -------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +echo "$as_me:$LINENO: checking for GNU libc compatible malloc" >&5 +echo $ECHO_N "checking for GNU libc compatible malloc... $ECHO_C" >&6 +if test "${ac_cv_func_malloc_0_nonnull+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_malloc_0_nonnull=no +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#if STDC_HEADERS || HAVE_STDLIB_H +# include +#else +char *malloc (); +#endif + +int +main () +{ +exit (malloc (0) ? 0 : 1); + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_malloc_0_nonnull=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_malloc_0_nonnull=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_func_malloc_0_nonnull" >&5 +echo "${ECHO_T}$ac_cv_func_malloc_0_nonnull" >&6 +if test $ac_cv_func_malloc_0_nonnull = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_MALLOC 1 +_ACEOF + +else + cat >>confdefs.h <<\_ACEOF +#define HAVE_MALLOC 0 +_ACEOF + + case $LIBOBJS in + "malloc.$ac_objext" | \ + *" malloc.$ac_objext" | \ + "malloc.$ac_objext "* | \ + *" malloc.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; +esac + + +cat >>confdefs.h <<\_ACEOF +#define malloc rpl_malloc +_ACEOF + +fi + + + + + +for ac_header in stdlib.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------------- ## +## Report this to launchd-bug-reports@group.apple.com ## +## -------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_func in getpagesize +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +echo "$as_me:$LINENO: checking for working mmap" >&5 +echo $ECHO_N "checking for working mmap... $ECHO_C" >&6 +if test "${ac_cv_func_mmap_fixed_mapped+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_mmap_fixed_mapped=no +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +/* malloc might have been renamed as rpl_malloc. */ +#undef malloc + +/* Thanks to Mike Haertel and Jim Avera for this test. + Here is a matrix of mmap possibilities: + mmap private not fixed + mmap private fixed at somewhere currently unmapped + mmap private fixed at somewhere already mapped + mmap shared not fixed + mmap shared fixed at somewhere currently unmapped + mmap shared fixed at somewhere already mapped + For private mappings, we should verify that changes cannot be read() + back from the file, nor mmap's back from the file at a different + address. (There have been systems where private was not correctly + implemented like the infamous i386 svr4.0, and systems where the + VM page cache was not coherent with the file system buffer cache + like early versions of FreeBSD and possibly contemporary NetBSD.) + For shared mappings, we should conversely verify that changes get + propagated back to all the places they're supposed to be. + + Grep wants private fixed already mapped. + The main things grep needs to know about mmap are: + * does it exist and is it safe to write into the mmap'd area + * how to use it (BSD variants) */ + +#include +#include + +#if !STDC_HEADERS && !HAVE_STDLIB_H +char *malloc (); +#endif + +/* This mess was copied from the GNU getpagesize.h. */ +#if !HAVE_GETPAGESIZE +/* Assume that all systems that can run configure have sys/param.h. */ +# if !HAVE_SYS_PARAM_H +# define HAVE_SYS_PARAM_H 1 +# endif + +# ifdef _SC_PAGESIZE +# define getpagesize() sysconf(_SC_PAGESIZE) +# else /* no _SC_PAGESIZE */ +# if HAVE_SYS_PARAM_H +# include +# ifdef EXEC_PAGESIZE +# define getpagesize() EXEC_PAGESIZE +# else /* no EXEC_PAGESIZE */ +# ifdef NBPG +# define getpagesize() NBPG * CLSIZE +# ifndef CLSIZE +# define CLSIZE 1 +# endif /* no CLSIZE */ +# else /* no NBPG */ +# ifdef NBPC +# define getpagesize() NBPC +# else /* no NBPC */ +# ifdef PAGESIZE +# define getpagesize() PAGESIZE +# endif /* PAGESIZE */ +# endif /* no NBPC */ +# endif /* no NBPG */ +# endif /* no EXEC_PAGESIZE */ +# else /* no HAVE_SYS_PARAM_H */ +# define getpagesize() 8192 /* punt totally */ +# endif /* no HAVE_SYS_PARAM_H */ +# endif /* no _SC_PAGESIZE */ + +#endif /* no HAVE_GETPAGESIZE */ + +int +main () +{ + char *data, *data2, *data3; + int i, pagesize; + int fd; + + pagesize = getpagesize (); + + /* First, make a file with some known garbage in it. */ + data = (char *) malloc (pagesize); + if (!data) + exit (1); + for (i = 0; i < pagesize; ++i) + *(data + i) = rand (); + umask (0); + fd = creat ("conftest.mmap", 0600); + if (fd < 0) + exit (1); + if (write (fd, data, pagesize) != pagesize) + exit (1); + close (fd); + + /* Next, try to mmap the file at a fixed address which already has + something else allocated at it. If we can, also make sure that + we see the same garbage. */ + fd = open ("conftest.mmap", O_RDWR); + if (fd < 0) + exit (1); + data2 = (char *) malloc (2 * pagesize); + if (!data2) + exit (1); + data2 += (pagesize - ((long) data2 & (pagesize - 1))) & (pagesize - 1); + if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, fd, 0L)) + exit (1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data2 + i)) + exit (1); + + /* Finally, make sure that changes to the mapped area do not + percolate back to the file as seen by read(). (This is a bug on + some variants of i386 svr4.0.) */ + for (i = 0; i < pagesize; ++i) + *(data2 + i) = *(data2 + i) + 1; + data3 = (char *) malloc (pagesize); + if (!data3) + exit (1); + if (read (fd, data3, pagesize) != pagesize) + exit (1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data3 + i)) + exit (1); + close (fd); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_mmap_fixed_mapped=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_mmap_fixed_mapped=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_func_mmap_fixed_mapped" >&5 +echo "${ECHO_T}$ac_cv_func_mmap_fixed_mapped" >&6 +if test $ac_cv_func_mmap_fixed_mapped = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_MMAP 1 +_ACEOF + +fi +rm -f conftest.mmap + +echo "$as_me:$LINENO: checking return type of signal handlers" >&5 +echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6 +if test "${ac_cv_type_signal+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#ifdef signal +# undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +int +main () +{ +int i; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_signal=void +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_signal=int +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5 +echo "${ECHO_T}$ac_cv_type_signal" >&6 + +cat >>confdefs.h <<_ACEOF +#define RETSIGTYPE $ac_cv_type_signal +_ACEOF + + +echo "$as_me:$LINENO: checking whether lstat dereferences a symlink specified with a trailing slash" >&5 +echo $ECHO_N "checking whether lstat dereferences a symlink specified with a trailing slash... $ECHO_C" >&6 +if test "${ac_cv_func_lstat_dereferences_slashed_symlink+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + rm -f conftest.sym conftest.file +echo >conftest.file +if test "$as_ln_s" = "ln -s" && ln -s conftest.file conftest.sym; then + if test "$cross_compiling" = yes; then + ac_cv_func_lstat_dereferences_slashed_symlink=no +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +struct stat sbuf; + /* Linux will dereference the symlink and fail. + That is better in the sense that it means we will not + have to compile and use the lstat wrapper. */ + exit (lstat ("conftest.sym/", &sbuf) ? 0 : 1); + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_lstat_dereferences_slashed_symlink=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_lstat_dereferences_slashed_symlink=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +else + # If the `ln -s' command failed, then we probably don't even + # have an lstat function. + ac_cv_func_lstat_dereferences_slashed_symlink=no +fi +rm -f conftest.sym conftest.file + +fi +echo "$as_me:$LINENO: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5 +echo "${ECHO_T}$ac_cv_func_lstat_dereferences_slashed_symlink" >&6 + +test $ac_cv_func_lstat_dereferences_slashed_symlink = yes && + +cat >>confdefs.h <<_ACEOF +#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +_ACEOF + + +if test $ac_cv_func_lstat_dereferences_slashed_symlink = no; then + case $LIBOBJS in + "lstat.$ac_objext" | \ + *" lstat.$ac_objext" | \ + "lstat.$ac_objext "* | \ + *" lstat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS lstat.$ac_objext" ;; +esac + +fi + +echo "$as_me:$LINENO: checking whether stat accepts an empty string" >&5 +echo $ECHO_N "checking whether stat accepts an empty string... $ECHO_C" >&6 +if test "${ac_cv_func_stat_empty_string_bug+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_stat_empty_string_bug=yes +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +struct stat sbuf; + exit (stat ("", &sbuf) ? 1 : 0); + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_stat_empty_string_bug=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_stat_empty_string_bug=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_func_stat_empty_string_bug" >&5 +echo "${ECHO_T}$ac_cv_func_stat_empty_string_bug" >&6 +if test $ac_cv_func_stat_empty_string_bug = yes; then + case $LIBOBJS in + "stat.$ac_objext" | \ + *" stat.$ac_objext" | \ + "stat.$ac_objext "* | \ + *" stat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS stat.$ac_objext" ;; +esac + + +cat >>confdefs.h <<_ACEOF +#define HAVE_STAT_EMPTY_STRING_BUG 1 +_ACEOF + +fi + + + + +for ac_func in memmove munmap strerror +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + ac_config_files="$ac_config_files Makefile src/Makefile doc/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by launchd $as_me 1.0, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +launchd config.status 1.0 +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS section. +# + +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "src/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "src/config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@PACKAGE@,$PACKAGE,;t t +s,@VERSION@,$VERSION,;t t +s,@ACLOCAL@,$ACLOCAL,;t t +s,@AUTOCONF@,$AUTOCONF,;t t +s,@AUTOMAKE@,$AUTOMAKE,;t t +s,@AUTOHEADER@,$AUTOHEADER,;t t +s,@MAKEINFO@,$MAKEINFO,;t t +s,@AMTAR@,$AMTAR,;t t +s,@install_sh@,$install_sh,;t t +s,@STRIP@,$STRIP,;t t +s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t +s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t +s,@AWK@,$AWK,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@DEPDIR@,$DEPDIR,;t t +s,@am__include@,$am__include,;t t +s,@am__quote@,$am__quote,;t t +s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t +s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t +s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t +s,@CCDEPMODE@,$CCDEPMODE,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + # Do quote $f, to prevent DOS paths from being IFS'd. + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi + # Run the commands associated with the file. + case $ac_file in + src/config.h ) # update the timestamp +echo 'timestamp for src/config.h' >"src/stamp-h1" + ;; + esac +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_COMMANDS section. +# +for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue + ac_dest=`echo "$ac_file" | sed 's,:.*,,'` + ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_dir=`(dirname "$ac_dest") 2>/dev/null || +$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_dest" : 'X\(//\)[^/]' \| \ + X"$ac_dest" : 'X\(//\)$' \| \ + X"$ac_dest" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_dest" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 +echo "$as_me: executing $ac_dest commands" >&6;} + case $ac_dest in + depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`(dirname "$mf") 2>/dev/null || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + else + continue + fi + grep '^DEP_FILES *= *[^ #]' < "$mf" > /dev/null || continue + # Extract the definition of DEP_FILES from the Makefile without + # running `make'. + DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"` + test -z "$DEPDIR" && continue + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n -e '/^U = / s///p' < "$mf"` + test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR" + # We invoke sed twice because it is the simplest approach to + # changing $(DEPDIR) to its actual value in the expansion. + for file in `sed -n -e ' + /^DEP_FILES = .*\\\\$/ { + s/^DEP_FILES = // + :loop + s/\\\\$// + p + n + /\\\\$/ b loop + p + } + /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`(dirname "$file") 2>/dev/null || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p $dirpart/$fdir + else + as_dir=$dirpart/$fdir + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5 +echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;} + { (exit 1); exit 1; }; }; } + + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + esac +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/launchd/configure.ac b/launchd/configure.ac new file mode 100644 index 0000000..331a254 --- /dev/null +++ b/launchd/configure.ac @@ -0,0 +1,44 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(launchd, 1.0, launchd-bug-reports@group.apple.com) +AC_CONFIG_SRCDIR([src/ConsoleMessage.c]) +AM_INIT_AUTOMAKE +AM_CONFIG_HEADER([src/config.h]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_RANLIB + +# Checks for libraries. + +# Checks for header files. +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS([fcntl.h limits.h mach/mach.h stdlib.h string.h syslog.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_HEADER_STDBOOL +AC_C_CONST +AC_TYPE_MODE_T +AC_TYPE_OFF_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_UID_T + +# Checks for library functions. +AC_FUNC_CLOSEDIR_VOID +AC_FUNC_ERROR_AT_LINE +AC_FUNC_FORK +AC_FUNC_MALLOC +AC_FUNC_MMAP +AC_TYPE_SIGNAL +AC_FUNC_STAT +AC_CHECK_FUNCS([memmove munmap strerror]) + +AC_CONFIG_FILES([Makefile + src/Makefile + doc/Makefile]) +AC_OUTPUT diff --git a/launchd/depcomp b/launchd/depcomp new file mode 100755 index 0000000..807b991 --- /dev/null +++ b/launchd/depcomp @@ -0,0 +1,423 @@ +#! /bin/sh + +# depcomp - compile a program generating dependencies as side-effects +# Copyright 1999, 2000 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi +# `libtool' can also be set to `yes' or `no'. + +if test -z "$depfile"; then + base=`echo "$object" | sed -e 's,^.*/,,' -e 's,\.\([^.]*\)$,.P\1,'` + dir=`echo "$object" | sed 's,/.*$,/,'` + if test "$dir" = "$object"; then + dir= + fi + # FIXME: should be _deps on DOS. + depfile="$dir.deps/$base" +fi + +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. This file always lives in the current directory. + # Also, the AIX compiler puts `$object:' at the start of each line; + # $object doesn't have directory information. + stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + outname="$stripped.o" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + tmpdepfile1="$dir.libs/$base.lo.d" + tmpdepfile2="$dir.libs/$base.d" + "$@" -Wc,-MD + else + tmpdepfile1="$dir$base.o.d" + tmpdepfile2="$dir$base.d" + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + if test -f "$tmpdepfile1"; then + tmpdepfile="$tmpdepfile1" + else + tmpdepfile="$tmpdepfile2" + fi + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a space and a tab in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. We will use -o /dev/null later, + # however we can't do the remplacement now because + # `-o $object' might simply not be used + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + "$@" -o /dev/null $dashmflag | sed 's:^[^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + -*) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 diff --git a/launchd/doc/Makefile.am b/launchd/doc/Makefile.am new file mode 100644 index 0000000..ce05d62 --- /dev/null +++ b/launchd/doc/Makefile.am @@ -0,0 +1,3 @@ +install-data-hook: + mkdir -p $(DESTDIR)/System/Library/LaunchDaemons + cp $(srcdir)/com.apple.launchdebugd.xml $(DESTDIR)/System/Library/LaunchDaemons/com.apple.launchd_debugd.plist diff --git a/launchd/doc/Makefile.in b/launchd/doc/Makefile.in new file mode 100644 index 0000000..e42f6db --- /dev/null +++ b/launchd/doc/Makefile.in @@ -0,0 +1,203 @@ +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AWK = @AWK@ +CC = @CC@ +DEPDIR = @DEPDIR@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ +subdir = doc +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/src/config.h +CONFIG_CLEAN_FILES = +DIST_SOURCES = +DIST_COMMON = Makefile.am Makefile.in +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu doc/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) +uninstall-info-am: +tags: TAGS +TAGS: + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile + +installdirs: + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-data-hook + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +uninstall-am: uninstall-info-am + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic uninstall uninstall-am uninstall-info-am + +install-data-hook: + mkdir -p $(DESTDIR)/System/Library/LaunchDaemons + cp $(srcdir)/com.apple.launchdebugd.xml $(DESTDIR)/System/Library/LaunchDaemons/com.apple.launchd_debugd.plist +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/launchd/doc/StartupItem-NOTES.rtf b/launchd/doc/StartupItem-NOTES.rtf new file mode 100644 index 0000000..4000ad7 --- /dev/null +++ b/launchd/doc/StartupItem-NOTES.rtf @@ -0,0 +1,96 @@ +{\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\fswiss\fcharset77 Helvetica-Bold;\f1\fswiss\fcharset77 Helvetica;\f2\fmodern\fcharset77 Courier; +\f3\fswiss\fcharset77 Helvetica-Oblique;} +{\colortbl;\red255\green255\blue255;} +\vieww12840\viewh12820\viewkind0 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f0\b\fs24 \cf0 Logistics of Startup Items:\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f1\b0 \cf0 \ + Startup items are directory bundles which contain, at a minimum, an executable file and a property list text file. For a startup item named "Foo", the bundle will be a directory named "Foo" containing (at a minimum) an executable "Foo" and a plist file "StartupParameters.plist".\ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f0\b \cf0 Search Paths for Startup Items:\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f1\b0 \cf0 \ + Startup items may be placed in the "Library" subdirectory of the primary file domains ("System", "Local", and "Network"). The search order is defined by routines defined in NSSystemDirectories.h: Local, then Network, then System. However, because the Network mounts have not been established at the beginning of system startup, bundles in /Network is currently not searched; this may be fixed later such that /Network is searched when ti becomes available. This search order does not define the startup order, but it does effect the handling of conflicts between bundles which provide the same services.\ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f0\b \cf0 Startup Actions:\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f1\b0 \cf0 \ + Presently, SystemStarter looks for an executable file with the name of the bundle (eg. Foo/Foo), and runs that file with a single argument.\ +\ + \'a5 A "start" argument indicates that the service(s) provided by the item are expected to start if they are configured to run. The program may opt to do nothing if the service is not configured to run.\ +\ + \'a5 A "stop" argument indicates that the service(s) provided by the item are expected to stop if it is running, regardless of whether it is configured to run.\ +\ + \'a5 A "restart" argument indicates that the service(s) provided by the item are expected to one of two things:\ + \'a5 Stop if the service is running, then start if the service is configured to run. (Same as stop followed by start.)\ + \'a5 If the service is running and not configured to run, stop the service; if the service is not running and configured to run, start the service; if the service is running and it is configured to run, reconfigure the service (eg. send the server a HUP signal).\ +\ + Startup items should take no action if they receive an unknown request and should therefore take care not to ignore the argument altogether; for example, a "stop" argument should most certainly not cause the item to start a service.\ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f0\b \cf0 Item Launch Ordering:\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f1\b0 \cf0 \ + The plist file contains parameters which tell SystemStarter some information about the executable, such as what services is provides, which services are prerequisites to its use, and so on. The plist contains the following attributes:\ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f2 \cf0 \{\ + Description = "blah blah";\ + Provides = ("service", ...);\ + Requires = ("service", ...);\ + Uses = ("service", ...);\ + OrderPreference = "time";\ + Messages =\ + \{\ + start = "Starting blah.";\ + stop = "Stopping blah.";\ + \}\ + \}\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f1 \cf0 \ + Note that while the above example is writing in the old NeXT-style property list format for compactness, the new XML property lists are also handled. You may prefer using PropertyListEditor.app to editing the property list files manually.\ +\ + Provides is an array that declares the services are provided by this bundle. A typical bundle provides a single service. Two bundles may not provide the same service; should multiple bundles which provide the same service be installed on a system, the first one encountered will be run, while the others will be disabled. It is therefore undesireable to provide multiple services in a single bundle unless they are co-dependent, as the overriding of one will effectively override all services in a given bundle (see also "Search Paths for Startup Items").\ +\ + Requires and Uses comprise the primary method for sorting bundles into the startup order. Requires is an array of services, provided by other bundles, that must be successfully started before the bundle can be run. If no such service is provided by any other bundle, the requiring bundle will not run. Uses is similar to Requires in that the bundle will attempt wait for the listed services before running, but it will still launch even if no such service can be provided by another bundle.\ +\ + OrderPreference provides a hint as to the ordering used when a set of bundles are all ready to load. Bundles which have their prerequisites met (that is, all Requires services are launched and all Uses services are either launched or deemed unavailable) are prioritized in this order, based on OrderPreference:\ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f2 \cf0 First\ + Early\ + None (default)\ + Late\ + Last\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f1 \cf0 \ + Note that +\f3\i other than the above ordering rules, there are no guarantees about the startup order of items +\f1\i0 . That is, if multiple items are prioritized equally given the above constraints, there is no rule for which starts first. You must use the dependency mechanism to ensure the correct dependencies have been met. Note also that OrderPreference is merely a suggestion, and that SystemStarter may opt to disregard it. In particular, startup items are run parallel, and items which have dependencies met will be run without waiting for items of a lower OrderPreference to complete.\ +\ + Description is a general-use string describing the item, for use by Admin tools. The Messages property provides strings which are displayed by SystemStarter during startup and shutdown.\ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f0\b \cf0 Shutdown:\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f1\b0 \cf0 \ + The intent is to add a shutdown sequence in the future so that the computer can be brought down more cleanly and give services a change to store state before exiting. The mechanism for this is still in the design stage.\ +} \ No newline at end of file diff --git a/launchd/doc/com.apple.launchdebugd.xml b/launchd/doc/com.apple.launchdebugd.xml new file mode 100644 index 0000000..a79f99f --- /dev/null +++ b/launchd/doc/com.apple.launchdebugd.xml @@ -0,0 +1,30 @@ + + + + + Disabled + + Label + com.apple.launchd_debugd + ProgramArguments + + launchd_debugd + + Sockets + + Listeners + + + SockServiceName + 12345 + SockPassive + + SockType + SOCK_STREAM + + + + ServiceIPC + + + diff --git a/launchd/install-sh b/launchd/install-sh new file mode 100755 index 0000000..c1bdb1b --- /dev/null +++ b/launchd/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip} -S" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + : +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=$mkdirprog + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f "$src" ] || [ -d "$src" ] + then + : + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + : + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + : + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' + ' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + : + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + : + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/launchd/missing b/launchd/missing new file mode 100755 index 0000000..44c013f --- /dev/null +++ b/launchd/missing @@ -0,0 +1,336 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997, 1999, 2000, 2002 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. +exit 0 +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch]" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing 0.4 - GNU automake" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. + You can get \`$1Help2man' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then + # We have makeinfo, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + tar) + shift + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + fi + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/launchd/mkinstalldirs b/launchd/mkinstalldirs new file mode 100755 index 0000000..8ab885e --- /dev/null +++ b/launchd/mkinstalldirs @@ -0,0 +1,99 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +errstatus=0 +dirmode="" + +usage="\ +Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..." + +# process command line arguments +while test $# -gt 0 ; do + case "${1}" in + -h | --help | --h* ) # -h for help + echo "${usage}" 1>&2; exit 0 ;; + -m ) # -m PERM arg + shift + test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; } + dirmode="${1}" + shift ;; + -- ) shift; break ;; # stop option processing + -* ) echo "${usage}" 1>&2; exit 1 ;; # unknown option + * ) break ;; # first non-opt arg + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in +0) exit 0 ;; +esac + +case $dirmode in +'') + if mkdir -p -- . 2>/dev/null; then + echo "mkdir -p -- $*" + exec mkdir -p -- "$@" + fi ;; +*) + if mkdir -m "$dirmode" -p -- . 2>/dev/null; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + fi ;; +esac + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + + lasterr="" + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 3 +# End: +# mkinstalldirs ends here diff --git a/launchd/src/ConsoleMessage.8 b/launchd/src/ConsoleMessage.8 new file mode 100644 index 0000000..79f7ddc --- /dev/null +++ b/launchd/src/ConsoleMessage.8 @@ -0,0 +1,105 @@ +.Dd April 12, 2002 +.Dt ConsoleMessage 8 +.Os Darwin +.Sh NAME +.Nm ConsoleMessage +.\" The following lines are read in generating the apropos(man -k) database. Use only key +.\" words here as the database is built based on the words here and in the .ND line. +.\" Use .Nm macro to designate other names for the documented program. +.Nd Send a message to +.Nm SystemStarter +.Sh SYNOPSIS +.Nm +.Op Fl v +.Ar message +.Nm +.Op Fl v +.Fl S +.Nm +.Op Fl v +.Fl F +.Nm +.Op Fl v +.Fl s Ar service +.Nm +.Op Fl v +.Fl f Ar service +.Nm +.Op Fl v +.Fl q Ar setting +.Nm +.Op Fl v +.Fl b Ar path +.Nm +.Op Fl v +.Fl u +.Sh DESCRIPTION +The +.Nm +utility may be used by startup item scripts to send messages to +.Nm SystemStarter +(see SystemStarter(8)). +.Pp +The default behavior is to send the specified +.Ar message +to +.Nm SystemStarter +to be displayed on the console. +.Nm SystemStarter +will attempt to localize the string using the current startup item's localization dictionaries. +.Pp +.Nm +may also be used to give feedback to +.Nm SystemStarter +indicating which services provided by the startup item have succeeded or failed. +.Sh OPTIONS +.Bl -tag -width -indent +.It Fl v +verbose mode (prints errors to stdout) +.It Fl S +mark all services provided by this item as successful +.It Fl F +mark all services provided by this item as failed +.It Fl s +mark the +.Ar service +as successful +.It Fl f +mark the +.Ar service +as failed +.It Fl q +query +.Nm SystemStarter +for the value of the configuration variable +.Ar setting +(result will be printed to stdout). +.It Fl b +Tell +.Nm SystemStarter +to load the display bundle at the specified +.Ar path +.It Fl u +Tell +.Nm SystemStarter +to unload the current display bundle +.El +.Sh NOTES +When a +.Ar service +name is not specified, +.Nm +assumes its parent process identification (see getppid(2)) is that of a startup item script, and uses that token to find the correct list of services provided by the current item. If the process calling +.Nm +is not a startup item script, it is necessary to explicitly provide +.Ar service +names. +.Sh SEE ALSO +.\" List links in ascending order by section, alphabetically within a section. +.\" Please do not reference files that do not exist without filing a bug report +.Xr SystemStarter 8 +.\" .Sh BUGS \" Document known, unremedied bugs +.Sh HISTORY +The +.Nm +utility appeared in Darwin 6.0 diff --git a/launchd/src/ConsoleMessage.c b/launchd/src/ConsoleMessage.c new file mode 100644 index 0000000..a07f4ab --- /dev/null +++ b/launchd/src/ConsoleMessage.c @@ -0,0 +1,327 @@ +/** + * ConsoleMessage.c - ConsoleMessage main + * Wilfredo Sanchez | wsanchez@opensource.apple.com + * Kevin Van Vechten | kevinvv@uclink4.berkeley.edu + * $Apple$ + ** + * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.1 (the "License"). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + ** + * The ConsoleMessage utility sends an IPC message to SystemStarter + * containing the message specified on the command line. SystemStarter + * will perform the localization. The message is also printed to + * the system log. + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "SystemStarterIPC.h" + +static CFDataRef sendIPCMessage(CFStringRef aPortName, CFDataRef aData, CFStringRef aRunLoopMode); + +static void usage() __attribute__((__noreturn__)); +static void +usage() +{ + /* char* aProgram = **_NSGetArgv(); */ + fprintf(stderr, "usage:\n" + "\tConsoleMessage [-v] \n" + "\tConsoleMessage [-v] -S\n" + "\tConsoleMessage [-v] -F\n" + "\tConsoleMessage [-v] -s \n" + "\tConsoleMessage [-v] -f \n" + "\tConsoleMessage [-v] -q \n" + "\tConsoleMessage [-v] -b \n" + "\tConsoleMessage [-v] -u\n" + "\noptions:\n" + "\t-v: verbose (prints errors to stdout)\n" + "\t-S: mark all services as successful\n" + "\t-F: mark all services as failed\n" + "\t-s: mark a specific service as successful\n" + "\t-f: mark a specific service as failed\n" + "\t-q: query a configuration setting\n" + "\t-b: (ignored)\n" + "\t-u: (ignored)\n"); + exit(1); +} + +enum { + kActionConsoleMessage, + kActionSuccess, + kActionFailure, + kActionQuery, +}; + +int +main(int argc, char *argv[]) +{ + int anExitCode = 0; + int aVerboseFlag = 0; + int anAction = kActionConsoleMessage; + char *aProgram = argv[0]; + char *anArgCStr = NULL; + char c; + pid_t w4lw_pid = 0; + FILE *w4lw_f; + + /** + * Handle command line. + **/ + while ((c = getopt(argc, argv, "?vSFs:f:q:b:u")) != -1) { + switch (c) { + case '?': + usage(); + break; + case 'v': + aVerboseFlag = 1; + break; + case 'S': + anAction = kActionSuccess; + anArgCStr = NULL; + break; + case 'F': + anAction = kActionFailure; + anArgCStr = NULL; + break; + case 's': + anAction = kActionSuccess; + anArgCStr = optarg; + break; + case 'f': + anAction = kActionFailure; + anArgCStr = optarg; + break; + case 'q': + anAction = kActionQuery; + anArgCStr = optarg; + break; + case 'b': + exit(EXIT_SUCCESS); + break; + case 'u': + w4lw_f = fopen("/var/run/waiting4loginwindow.pid", "r"); + if (w4lw_f) { + fscanf(w4lw_f, "%d\n", &w4lw_pid); + if (w4lw_pid) + kill(w4lw_pid, SIGTERM); + } + exit(EXIT_SUCCESS); + break; + default: + fprintf(stderr, "ignoring unknown option '-%c'\n", c); + break; + } + } + argc -= optind; + argv += optind; + + if ((anAction == kActionConsoleMessage && argc != 1) || + (anAction == kActionSuccess && argc != 0) || + (anAction == kActionFailure && argc != 0) || + (anAction == kActionQuery && argc != 0)) { + usage(); + } + if (getuid() != 0) { + fprintf(stderr, "you must be root to run %s\n", aProgram); + exit(1); + } else { + CFMutableDictionaryRef anIPCMessage = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + if (anIPCMessage) { + CFStringRef anArg = NULL; + CFIndex aPID = getppid(); + CFNumberRef aPIDNumber = CFNumberCreate(NULL, kCFNumberCFIndexType, &aPID); + + /* + * Parent process id is the process id of the startup + * item that called ConsoleMessage. + */ + CFDictionarySetValue(anIPCMessage, kIPCProcessIDKey, aPIDNumber); + CFRelease(aPIDNumber); + + if (anArgCStr) { + anArg = CFStringCreateWithCString(NULL, anArgCStr, kCFStringEncodingUTF8); + } + if (anAction == kActionSuccess || anAction == kActionFailure) { + CFBooleanRef aStatus = (anAction == kActionSuccess) ? kCFBooleanTrue : kCFBooleanFalse; + CFDictionarySetValue(anIPCMessage, kIPCMessageKey, kIPCStatusMessage); + CFDictionarySetValue(anIPCMessage, kIPCStatusKey, aStatus); + if (anArg) + CFDictionarySetValue(anIPCMessage, kIPCServiceNameKey, anArg); + } else if (anAction == kActionQuery && anArg) { + CFDictionarySetValue(anIPCMessage, kIPCMessageKey, kIPCQueryMessage); + CFDictionarySetValue(anIPCMessage, kIPCConfigSettingKey, anArg); + } else if (anAction == kActionConsoleMessage) { + char *aConsoleMessageCStr = argv[0]; + CFStringRef aConsoleMessage = CFStringCreateWithCString(NULL, aConsoleMessageCStr, kCFStringEncodingUTF8); + + syslog(LOG_INFO, "%s", aConsoleMessageCStr); + + CFDictionarySetValue(anIPCMessage, kIPCMessageKey, kIPCConsoleMessage); + CFDictionarySetValue(anIPCMessage, kIPCConsoleMessageKey, aConsoleMessage); + CFRelease(aConsoleMessage); + } + if (anArg) + CFRelease(anArg); + + { + CFDataRef aData = CFPropertyListCreateXMLData(NULL, anIPCMessage); + if (aData) { + CFDataRef aResultData = sendIPCMessage(CFSTR(kSystemStarterMessagePort), aData, kCFRunLoopDefaultMode); + + /* aResultData should be ASCIZ */ + if (aResultData) { + fprintf(stdout, "%s", CFDataGetBytePtr(aResultData)); + CFRelease(aResultData); + } else { + char *aConsoleMessageCStr = argv[0]; + fprintf(stdout, "%s\n", aConsoleMessageCStr); + + if (aVerboseFlag) + fprintf(stderr, "%s could not connect to SystemStarter.\n", aProgram); + anExitCode = 0; + } + CFRelease(aData); + } else { + if (aVerboseFlag) + fprintf(stderr, "%s: not enough memory to create IPC message.\n", aProgram); + anExitCode = 1; + } + } + } else { + if (aVerboseFlag) + fprintf(stderr, "%s: not enough memory to create IPC message.\n", aProgram); + anExitCode = 1; + } + } + exit(anExitCode); +} + + +static void +dummyCallback(void) +{ +} + +static void replyCallback(CFMachPortRef port __attribute__((unused)), void *aPtr, CFIndex aSize __attribute__((unused)), CFDataRef * aReply) { + SystemStarterIPCMessage *aMessage = (SystemStarterIPCMessage *) aPtr; + + if (aReply != NULL && + aMessage->aProtocol == kIPCProtocolVersion && + aMessage->aByteLength >= 0) { + *aReply = CFDataCreate(NULL, (char *) aMessage + aMessage->aByteLength, aMessage->aByteLength); + } else if (aReply != NULL) { + *aReply = NULL; + } +} + + +static CFDataRef +sendIPCMessage(CFStringRef aPortName, CFDataRef aData, CFStringRef aRunLoopMode) +{ + SystemStarterIPCMessage *aMessage = NULL; + CFRunLoopSourceRef aSource = NULL; + CFMachPortRef aMachPort = NULL, aReplyPort = NULL; + CFMachPortContext aContext; + kern_return_t aKernReturn = KERN_FAILURE; + mach_port_t aBootstrapPort, aNativePort; + char *aPortNameUTF8String; + CFDataRef aReply = NULL; + SInt32 aStrLen; + + aContext.version = 0; + aContext.info = (void *) NULL; + aContext.retain = 0; + aContext.release = 0; + aContext.copyDescription = 0; + + /* Look up the remote port by name */ + + aStrLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(aPortName) + 1, kCFStringEncodingUTF8); + aPortNameUTF8String = malloc(aStrLen); + if (aPortNameUTF8String) { + CFStringGetCString(aPortName, aPortNameUTF8String, aStrLen, kCFStringEncodingUTF8); + task_get_bootstrap_port(mach_task_self(), &aBootstrapPort); + aKernReturn = bootstrap_look_up(aBootstrapPort, aPortNameUTF8String, &aNativePort); + aMachPort = (KERN_SUCCESS == aKernReturn) ? CFMachPortCreateWithPort(NULL, aNativePort, (CFMachPortCallBack) dummyCallback, &aContext, NULL) : NULL; + free(aPortNameUTF8String); + } + /* Create a reply port and associated run loop source */ + aContext.info = &aReply; + aReplyPort = CFMachPortCreate(NULL, (CFMachPortCallBack) replyCallback, &aContext, NULL); + if (aReplyPort) { + aSource = CFMachPortCreateRunLoopSource(NULL, aReplyPort, 0); + if (aSource) { + CFRunLoopAddSource(CFRunLoopGetCurrent(), aSource, aRunLoopMode); + } + } + /* Allocate a buffer for the message */ + if (aData && aMachPort && aReplyPort) { + SInt32 aSize = (sizeof(SystemStarterIPCMessage) + (CFDataGetLength(aData) + 3)) & ~0x3; + aMessage = (SystemStarterIPCMessage *) malloc(aSize); + if (aMessage) { + aMessage->aHeader.msgh_id = 1; + aMessage->aHeader.msgh_size = aSize; + aMessage->aHeader.msgh_remote_port = CFMachPortGetPort(aMachPort); + aMessage->aHeader.msgh_local_port = CFMachPortGetPort(aReplyPort); + aMessage->aHeader.msgh_reserved = 0; + aMessage->aHeader.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); + aMessage->aBody.msgh_descriptor_count = 0; + aMessage->aProtocol = kIPCProtocolVersion; + aMessage->aByteLength = CFDataGetLength(aData); + memmove((uint8_t *) aMessage + sizeof(SystemStarterIPCMessage), + CFDataGetBytePtr(aData), + CFDataGetLength(aData)); + } + } + /* Wait up to 1 second to send the message */ + if (aMessage) { + aKernReturn = mach_msg((mach_msg_header_t *) aMessage, MACH_SEND_MSG | MACH_SEND_TIMEOUT, aMessage->aHeader.msgh_size, 0, MACH_PORT_NULL, 1000.0, MACH_PORT_NULL); + free(aMessage); + } + /* Wait up to 30 seconds for the reply */ + if (aSource && aKernReturn == MACH_MSG_SUCCESS) { + CFRetain(aReplyPort); + CFRunLoopRunInMode(aRunLoopMode, 30.0, true); + /* + * aReplyPort's replyCallback will set the local aReply + * variable + */ + CFRelease(aReplyPort); + } + if (aMachPort) + CFRelease(aMachPort); + if (aReplyPort) + CFRelease(aReplyPort); + if (aSource) { + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), aSource, aRunLoopMode); + CFRelease(aSource); + } + return aReply; +} diff --git a/launchd/src/IPC.c b/launchd/src/IPC.c new file mode 100644 index 0000000..b8e4dd6 --- /dev/null +++ b/launchd/src/IPC.c @@ -0,0 +1,399 @@ +/** + * IPC.c - System Starter IPC routines + * Wilfredo Sanchez | wsanchez@opensource.apple.com + * Kevin Van Vechten | kevinvv@uclink4.berkeley.edu + * $Apple$ + ** + * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.1 (the "License"). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + **/ + +#include +#include +#include +#include +#include +#include +#include +#include "IPC.h" +#include "StartupItems.h" +#include "SystemStarter.h" +#include "SystemStarterIPC.h" + +/* Structure to pass StartupContext and anItem to the termination handler. */ +typedef struct TerminationContextStorage { + StartupContext aStartupContext; + CFMutableDictionaryRef anItem; +} *TerminationContext; + +/** + * A CFMachPort invalidation callback that records the termination of + * a startup item task. Stops the current run loop to give system_starter + * another go at running items. + **/ +static void +startupItemTerminated(CFMachPortRef aMachPort, void *anInfo) +{ + TerminationContext aTerminationContext = (TerminationContext) anInfo; + + if (aMachPort) { + mach_port_deallocate(mach_task_self(), CFMachPortGetPort(aMachPort)); + } + if (aTerminationContext && aTerminationContext->anItem) { + pid_t aPID = 0; + pid_t rPID = 0; + int aStatus = 0; + CFMutableDictionaryRef anItem = aTerminationContext->anItem; + StartupContext aStartupContext = aTerminationContext->aStartupContext; + + /* Get the exit status */ + if (anItem) { + aPID = StartupItemGetPID(anItem); + if (aPID > 0) + rPID = waitpid(aPID, &aStatus, 0); + } + if (aStartupContext) { + --aStartupContext->aRunningCount; + + /* Record the item's status */ + if (aStartupContext->aStatusDict) { + StartupItemExit(aStartupContext->aStatusDict, anItem, (WIFEXITED(aStatus) && WEXITSTATUS(aStatus) == 0)); + if (aStatus) { + CF_syslog(LOG_WARNING, CFSTR("%@ (%d) did not complete successfully"), CFDictionaryGetValue(anItem, CFSTR("Description")), aPID); + } else { + CF_syslog(LOG_DEBUG, CFSTR("Finished %@ (%d)"), CFDictionaryGetValue(anItem, CFSTR("Description")), aPID); + } + } + /* + * If the item failed to start, then add it to the + * failed list + */ + if (WEXITSTATUS(aStatus) || WTERMSIG(aStatus) || WCOREDUMP(aStatus)) { + CFDictionarySetValue(anItem, kErrorKey, kErrorReturnNonZero); + AddItemToFailedList(aStartupContext, anItem); + } + /* + * Remove the item from the waiting list regardless + * if it was successful or it failed. + */ + RemoveItemFromWaitingList(aStartupContext, anItem); + } + } + if (aTerminationContext) + free(aTerminationContext); +} + +void +MonitorStartupItem(StartupContext aStartupContext, CFMutableDictionaryRef anItem) +{ + pid_t aPID = StartupItemGetPID(anItem); + if (anItem && aPID > 0) { + mach_port_t aPort; + kern_return_t aResult; + CFMachPortContext aContext; + CFMachPortRef aMachPort; + CFRunLoopSourceRef aSource; + TerminationContext aTerminationContext = (TerminationContext) malloc(sizeof(struct TerminationContextStorage)); + + aTerminationContext->aStartupContext = aStartupContext; + aTerminationContext->anItem = anItem; + + aContext.version = 0; + aContext.info = aTerminationContext; + aContext.retain = 0; + aContext.release = 0; + + if ((aResult = task_for_pid(mach_task_self(), aPID, &aPort)) != KERN_SUCCESS) + goto out_bad; + + if (!(aMachPort = CFMachPortCreateWithPort(NULL, aPort, NULL, &aContext, NULL))) + goto out_bad; + + if (!(aSource = CFMachPortCreateRunLoopSource(NULL, aMachPort, 0))) { + CFRelease(aMachPort); + goto out_bad; + } + CFMachPortSetInvalidationCallBack(aMachPort, startupItemTerminated); + CFRunLoopAddSource(CFRunLoopGetCurrent(), aSource, kCFRunLoopCommonModes); + CFRelease(aSource); + CFRelease(aMachPort); + return; +out_bad: + /* + * The assumption is something failed, the task already + * terminated. + */ + startupItemTerminated(NULL, aTerminationContext); + } +} + +/** + * Returns a reference to an item based on tokens passed in an IPC message. + * This is useful for figuring out which item the message came from. + * + * Currently two tokens are supported: + * kIPCProcessIDKey - the pid of the running startup script + * kIPCServiceNameKey - a name of a service that the item provides. This + * takes precedence over the pid key when both are present. + **/ +static CFMutableDictionaryRef +itemFromIPCMessage(StartupContext aStartupContext, CFDictionaryRef anIPCMessage) +{ + CFMutableDictionaryRef anItem = NULL; + + if (aStartupContext && anIPCMessage) { + CFStringRef aServiceName = CFDictionaryGetValue(anIPCMessage, kIPCServiceNameKey); + CFIndex aPID = 0; + CFNumberRef aPIDNumber = CFDictionaryGetValue(anIPCMessage, kIPCProcessIDKey); + + if (aServiceName && CFGetTypeID(aServiceName) == CFStringGetTypeID()) { + anItem = StartupItemListGetProvider(aStartupContext->aWaitingList, aServiceName); + } else if (aPIDNumber && + CFGetTypeID(aPIDNumber) == CFNumberGetTypeID() && + CFNumberGetValue(aPIDNumber, kCFNumberCFIndexType, &aPID)) { + anItem = StartupItemWithPID(aStartupContext->aWaitingList, aPID); + } + } + return anItem; +} + +/** + * Displays a message on the console. + * aConsoleMessage will be localized according to the dictionary in the specified item. + * Running tems may be specified by their current process id. Items may also be specified + * by one of the service names they provide. + **/ +static void +consoleMessage(StartupContext aStartupContext, CFDictionaryRef anIPCMessage) +{ + if (aStartupContext && anIPCMessage) { + CFStringRef aConsoleMessage = CFDictionaryGetValue(anIPCMessage, kIPCConsoleMessageKey); + + if (aConsoleMessage && CFGetTypeID(aConsoleMessage) == CFStringGetTypeID()) { + CF_syslog(LOG_INFO, CFSTR("%@"), aConsoleMessage); + } + } +} + +/** + * Records the success or failure or a particular service. + * If no service name is specified, but a pid is, then all services provided + * by the item are flagged. + **/ +static void +statusMessage(StartupContext aStartupContext, CFDictionaryRef anIPCMessage) +{ + if (anIPCMessage && aStartupContext && aStartupContext->aStatusDict) { + CFMutableDictionaryRef anItem = itemFromIPCMessage(aStartupContext, anIPCMessage); + CFStringRef aServiceName = CFDictionaryGetValue(anIPCMessage, kIPCServiceNameKey); + CFBooleanRef aStatus = CFDictionaryGetValue(anIPCMessage, kIPCStatusKey); + + if (anItem && aStatus && + CFGetTypeID(aStatus) == CFBooleanGetTypeID() && + (!aServiceName || CFGetTypeID(aServiceName) == CFStringGetTypeID())) { + StartupItemSetStatus(aStartupContext->aStatusDict, anItem, aServiceName, CFBooleanGetValue(aStatus), TRUE); + } + } +} + +/** + * Queries one of several configuration settings. + */ +static CFDataRef +queryConfigSetting(StartupContext aStartupContext, CFDictionaryRef anIPCMessage) +{ + char *aValue = ""; + + if (anIPCMessage) { + CFStringRef aSetting = CFDictionaryGetValue(anIPCMessage, kIPCConfigSettingKey); + + if (aSetting && CFGetTypeID(aSetting) == CFStringGetTypeID()) { + if (CFEqual(aSetting, kIPCConfigSettingVerboseFlag)) { + aValue = gVerboseFlag ? "-YES-" : "-NO-"; + } else if (CFEqual(aSetting, kIPCConfigSettingNetworkUp)) { + Boolean aNetworkUpFlag = FALSE; + if (aStartupContext && aStartupContext->aStatusDict) { + aNetworkUpFlag = CFDictionaryContainsKey(aStartupContext->aStatusDict, CFSTR("Network")); + } + aValue = aNetworkUpFlag ? "-YES-" : "-NO-"; + } + } + } + return CFDataCreate(NULL, aValue, strlen(aValue) + 1); /* aValue + null */ +} + +static void *handleIPCMessage(void *aMsgParam, CFIndex aMessageSize __attribute__((unused)), CFAllocatorRef anAllocator __attribute__((unused)), void *aMachPort) { + SystemStarterIPCMessage *aMessage = (SystemStarterIPCMessage *) aMsgParam; + SystemStarterIPCMessage *aReplyMessage = NULL; + + CFDataRef aResult = NULL; + CFDataRef aData = NULL; + + if (aMessage->aHeader.msgh_bits & MACH_MSGH_BITS_COMPLEX) { + syslog(LOG_WARNING, "Ignoring out-of-line IPC message"); + return NULL; + } else { + mach_msg_security_trailer_t *aSecurityTrailer = (mach_msg_security_trailer_t *) + ((uint8_t *) aMessage + round_msg(sizeof(SystemStarterIPCMessage) + aMessage->aByteLength)); + + /* + * CFRunLoop includes the format 0 message trailer with the + * passed message. + */ + if (aSecurityTrailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0 && + aSecurityTrailer->msgh_sender.val[0] != 0) { + syslog(LOG_WARNING, "Ignoring IPC message sent from uid %d", aSecurityTrailer->msgh_sender.val[0]); + return NULL; + } + } + + if (aMessage->aProtocol != kIPCProtocolVersion) { + syslog(LOG_WARNING, "Unsupported IPC protocol version number: %d. Message ignored", aMessage->aProtocol); + return NULL; + } + aData = CFDataCreateWithBytesNoCopy(NULL, + (uint8_t *) aMessage + sizeof(SystemStarterIPCMessage), + aMessage->aByteLength, + kCFAllocatorNull); + /* + * Dispatch the IPC message. + */ + if (aData) { + StartupContext aStartupContext = NULL; + CFStringRef anErrorString = NULL; + CFDictionaryRef anIPCMessage = (CFDictionaryRef) CFPropertyListCreateFromXMLData(NULL, aData, kCFPropertyListImmutable, &anErrorString); + + CF_syslog(LOG_DEBUG, CFSTR("IPC message = %@"), anIPCMessage); + + if (aMachPort) { + CFMachPortContext aMachPortContext; + CFMachPortGetContext((CFMachPortRef) aMachPort, &aMachPortContext); + aStartupContext = (StartupContext) aMachPortContext.info; + } + if (anIPCMessage && CFGetTypeID(anIPCMessage) == CFDictionaryGetTypeID()) { + /* switch on the type of the IPC message */ + CFStringRef anIPCMessageType = CFDictionaryGetValue(anIPCMessage, kIPCMessageKey); + if (anIPCMessageType && CFGetTypeID(anIPCMessageType) == CFStringGetTypeID()) { + if (CFEqual(anIPCMessageType, kIPCConsoleMessage)) { + consoleMessage(aStartupContext, anIPCMessage); + } else if (CFEqual(anIPCMessageType, kIPCStatusMessage)) { + statusMessage(aStartupContext, anIPCMessage); + } else if (CFEqual(anIPCMessageType, kIPCQueryMessage)) { + aResult = queryConfigSetting(aStartupContext, anIPCMessage); + } + } + } else { + CF_syslog(LOG_ERR, CFSTR("Unable to parse IPC message: %@"), anErrorString); + } + CFRelease(aData); + } else { + syslog(LOG_ERR, "Out of memory. Could not allocate space for IPC message"); + } + + /* + * Generate a Mach message for the result data. + */ + if (!aResult) + aResult = CFDataCreateWithBytesNoCopy(NULL, "", 1, kCFAllocatorNull); + if (aResult) { + CFIndex aDataSize = CFDataGetLength(aResult); + CFIndex aReplyMessageSize = round_msg(sizeof(SystemStarterIPCMessage) + aDataSize + 3); + aReplyMessage = CFAllocatorAllocate(kCFAllocatorSystemDefault, aReplyMessageSize, 0); + if (aReplyMessage) { + aReplyMessage->aHeader.msgh_id = -1 * (SInt32) aMessage->aHeader.msgh_id; + aReplyMessage->aHeader.msgh_size = aReplyMessageSize; + aReplyMessage->aHeader.msgh_remote_port = aMessage->aHeader.msgh_remote_port; + aReplyMessage->aHeader.msgh_local_port = MACH_PORT_NULL; + aReplyMessage->aHeader.msgh_reserved = 0; + aReplyMessage->aHeader.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0); + aReplyMessage->aBody.msgh_descriptor_count = 0; + aReplyMessage->aProtocol = kIPCProtocolVersion; + aReplyMessage->aByteLength = CFDataGetLength(aResult); + memmove((uint8_t *) aReplyMessage + sizeof(SystemStarterIPCMessage), + CFDataGetBytePtr(aResult), + CFDataGetLength(aResult)); + } + CFRelease(aResult); + } + if (!aReplyMessage) { + syslog(LOG_ERR, "Out of memory. Could not allocate IPC result"); + } + return aReplyMessage; +} + + +static mach_port_t +getIPCPort(void *anInfo) +{ + return anInfo ? CFMachPortGetPort((CFMachPortRef) anInfo) : MACH_PORT_NULL; +} + +CFRunLoopSourceRef +CreateIPCRunLoopSource(CFStringRef aPortName, StartupContext aStartupContext) +{ + CFRunLoopSourceRef aSource = NULL; + CFMachPortRef aMachPort = NULL; + CFMachPortContext aContext; + kern_return_t aKernReturn = KERN_FAILURE; + + aContext.version = 0; + aContext.info = (void *) aStartupContext; + aContext.retain = 0; + aContext.release = 0; + aContext.copyDescription = 0; + aMachPort = CFMachPortCreate(NULL, NULL, &aContext, NULL); + + if (aMachPort && aPortName) { + CFIndex aPortNameLength = CFStringGetLength(aPortName); + CFIndex aPortNameSize = CFStringGetMaximumSizeForEncoding(aPortNameLength, kCFStringEncodingUTF8) + 1; + uint8_t *aBuffer = CFAllocatorAllocate(NULL, aPortNameSize, 0); + if (aBuffer && CFStringGetCString(aPortName, + aBuffer, + aPortNameSize, + kCFStringEncodingUTF8)) { + mach_port_t aBootstrapPort; + task_get_bootstrap_port(mach_task_self(), &aBootstrapPort); + aKernReturn = bootstrap_register(aBootstrapPort, aBuffer, CFMachPortGetPort(aMachPort)); + } + if (aBuffer) + CFAllocatorDeallocate(NULL, aBuffer); + } + if (aMachPort && aKernReturn == KERN_SUCCESS) { + CFRunLoopSourceContext1 aSourceContext; + aSourceContext.version = 1; + aSourceContext.info = aMachPort; + aSourceContext.retain = CFRetain; + aSourceContext.release = CFRelease; + aSourceContext.copyDescription = CFCopyDescription; + aSourceContext.equal = CFEqual; + aSourceContext.hash = CFHash; + aSourceContext.getPort = getIPCPort; + aSourceContext.perform = (void *) handleIPCMessage; + aSource = CFRunLoopSourceCreate(NULL, 0, (CFRunLoopSourceContext *) & aSourceContext); + } + if (aMachPort && (!aSource || aKernReturn != KERN_SUCCESS)) { + CFMachPortInvalidate(aMachPort); + CFRelease(aMachPort); + aMachPort = NULL; + } + return aSource; +} diff --git a/launchd/src/IPC.h b/launchd/src/IPC.h new file mode 100644 index 0000000..13e49d5 --- /dev/null +++ b/launchd/src/IPC.h @@ -0,0 +1,47 @@ +/** + * IPC.h - System Starter IPC routines + * Wilfredo Sanchez | wsanchez@opensource.apple.com + * Kevin Van Vechten | kevinvv@uclink4.berkeley.edu + * $Apple$ + ** + * Copyright (c) 1999-2001 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.1 (the "License"). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + **/ + +#ifndef _IPC_H_ +#define _IPC_H_ + +#include "SystemStarter.h" + +/** + * Monitor a startup item task. Creates a mach port and uses the + * invalidation callback to notify system starter when the process + * terminates. + **/ +void MonitorStartupItem (StartupContext aStartupContext, CFMutableDictionaryRef anItem); + +/** + * Creates a named mach port and run loop source. The name is encoded using UTF-8. + **/ +CFRunLoopSourceRef CreateIPCRunLoopSource(CFStringRef aPortName, StartupContext aStartupContext); + +#endif /* _IPC_H_ */ diff --git a/launchd/src/Makefile.am b/launchd/src/Makefile.am new file mode 100644 index 0000000..b27efc5 --- /dev/null +++ b/launchd/src/Makefile.am @@ -0,0 +1,77 @@ +AM_CFLAGS = -no-cpp-precomp -F/System/Library/PrivateFrameworks -Wall -W -Wshadow -Wpadded -Werror -fconstant-cfstrings + +sbin_SCRIPTS = service + +noinst_LIBRARIES = liblaunch.a liblaunch_profile.a + +bin_PROGRAMS = launchctl wait4path +sbin_PROGRAMS = launchd SystemStarter launchd_debugd +libexec_PROGRAMS = ConsoleMessage register_mach_bootstrap_servers StartupItemContext launchproxy + +sysconf_DATA = hostconfig rc rc.common rc.netboot rc.shutdown + +ConsoleMessage_LDFLAGS = -framework CoreFoundation + +launchctl_LDFLAGS = -framework CoreFoundation -weak_library /usr/lib/libedit.dylib + +register_mach_bootstrap_servers_LDFLAGS = -framework CoreFoundation + +launchd_debugd_CFLAGS = -mdynamic-no-pic $(AM_CFLAGS) +launchd_debugd_SOURCES = launchdebugd.c + +liblaunch_a_SOURCES = liblaunch.c + +liblaunch_profile_a_CFLAGS = -pg $(AM_CFLAGS) +liblaunch_profile_a_SOURCES = liblaunch.c + +SystemStarter_CFLAGS = -mdynamic-no-pic $(AM_CFLAGS) +SystemStarter_LDFLAGS = -framework CoreFoundation +SystemStarter_SOURCES = StartupItems.c IPC.c SystemStarter.c + +launchd_CFLAGS = -DPID1_REAP_ADOPTED_CHILDREN -mdynamic-no-pic $(AM_CFLAGS) -Wno-unused-parameter +launchd_LDFLAGS = -lbsm +launchd_SOURCES = launchd.c init.c bootstrap.c lists.c rpc_services.c bootstrapServer.c + +launchproxy_LDFLAGS = -weak_framework Security + +CLEANFILES = bootstrap.h bootstrapServer.c bootstrapUser.c + +bootstrap.c:: bootstrap.h + +bootstrap.h bootstrapServer.c bootstrapUser.c: $(srcdir)/bootstrap.defs + mig $(MIGFLAGS) $(srcdir)/bootstrap.defs + +man1_MANS = wait4path.1 launchctl.1 + +man5_MANS = launchd.plist.5 launchd.conf.5 + +man8_MANS = ConsoleMessage.8 StartupItemContext.8 SystemStarter.8 init.8 rc.8 launchd.8 service.8 launchproxy.8 launchd_debugd.8 + +STARTUPITEMS = $(basename $(notdir $(wildcard $(srcdir)/StartupItems/*.plist))) + +$(addprefix $(DESTDIR)/System/Library/StartupItems/, $(STARTUPITEMS)): + mkdir -p $@ + cp $(srcdir)/StartupItems/$(notdir $@) $@ + chmod 755 $@/$(notdir $@) + cp $(srcdir)/StartupItems/$(notdir $@).plist $@/StartupParameters.plist + +install-startupitems: $(addprefix $(DESTDIR)/System/Library/StartupItems/, $(STARTUPITEMS)) + +install-data-hook: install-startupitems + mkdir -p $(DESTDIR)/usr/local/lib/system + cp liblaunch.a $(DESTDIR)/usr/local/lib/system + cp liblaunch.a $(DESTDIR)/usr/local/lib/system/liblaunch_debug.a + cp liblaunch_profile.a $(DESTDIR)/usr/local/lib/system/liblaunch_profile.a + mkdir -p $(DESTDIR)/usr/include + cp $(srcdir)/launch.h $(DESTDIR)/usr/include + mkdir -p $(DESTDIR)/usr/local/include + cp $(srcdir)/launch_priv.h $(DESTDIR)/usr/local/include + mkdir -p $(DESTDIR)/$(sysconfdir)/mach_init.d + mkdir -p $(DESTDIR)/$(sysconfdir)/mach_init_per_user.d + mkdir -p $(DESTDIR)/Library/LaunchDaemons + mkdir -p $(DESTDIR)/Library/LaunchAgents + mkdir -p $(DESTDIR)/System/Library/LaunchDaemons + mkdir -p $(DESTDIR)/System/Library/LaunchAgents + +install-exec-hook: + chmod u+s $(DESTDIR)/$(sbindir)/launchd diff --git a/launchd/src/Makefile.in b/launchd/src/Makefile.in new file mode 100644 index 0000000..239c295 --- /dev/null +++ b/launchd/src/Makefile.in @@ -0,0 +1,919 @@ +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AWK = @AWK@ +CC = @CC@ +DEPDIR = @DEPDIR@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ +AM_CFLAGS = -no-cpp-precomp -F/System/Library/PrivateFrameworks -Wall -W -Wshadow -Wpadded -Werror -fconstant-cfstrings + +sbin_SCRIPTS = service + +noinst_LIBRARIES = liblaunch.a liblaunch_profile.a + +bin_PROGRAMS = launchctl wait4path +sbin_PROGRAMS = launchd SystemStarter launchd_debugd +libexec_PROGRAMS = ConsoleMessage register_mach_bootstrap_servers StartupItemContext launchproxy + +sysconf_DATA = hostconfig rc rc.common rc.netboot rc.shutdown + +ConsoleMessage_LDFLAGS = -framework CoreFoundation + +launchctl_LDFLAGS = -framework CoreFoundation -weak_library /usr/lib/libedit.dylib + +register_mach_bootstrap_servers_LDFLAGS = -framework CoreFoundation + +launchd_debugd_CFLAGS = -mdynamic-no-pic $(AM_CFLAGS) +launchd_debugd_SOURCES = launchdebugd.c + +liblaunch_a_SOURCES = liblaunch.c + +liblaunch_profile_a_CFLAGS = -pg $(AM_CFLAGS) +liblaunch_profile_a_SOURCES = liblaunch.c + +SystemStarter_CFLAGS = -mdynamic-no-pic $(AM_CFLAGS) +SystemStarter_LDFLAGS = -framework CoreFoundation +SystemStarter_SOURCES = StartupItems.c IPC.c SystemStarter.c + +launchd_CFLAGS = -DPID1_REAP_ADOPTED_CHILDREN -mdynamic-no-pic $(AM_CFLAGS) -Wno-unused-parameter +launchd_LDFLAGS = -lbsm +launchd_SOURCES = launchd.c init.c bootstrap.c lists.c rpc_services.c bootstrapServer.c + +launchproxy_LDFLAGS = -weak_framework Security + +CLEANFILES = bootstrap.h bootstrapServer.c bootstrapUser.c + +man1_MANS = wait4path.1 launchctl.1 + +man5_MANS = launchd.plist.5 launchd.conf.5 + +man8_MANS = ConsoleMessage.8 StartupItemContext.8 SystemStarter.8 init.8 rc.8 launchd.8 service.8 launchproxy.8 launchd_debugd.8 + +STARTUPITEMS = $(basename $(notdir $(wildcard $(srcdir)/StartupItems/*.plist))) +subdir = src +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +liblaunch_a_AR = $(AR) cru +liblaunch_a_LIBADD = +am_liblaunch_a_OBJECTS = liblaunch.$(OBJEXT) +liblaunch_a_OBJECTS = $(am_liblaunch_a_OBJECTS) +liblaunch_profile_a_AR = $(AR) cru +liblaunch_profile_a_LIBADD = +am_liblaunch_profile_a_OBJECTS = liblaunch_profile_a-liblaunch.$(OBJEXT) +liblaunch_profile_a_OBJECTS = $(am_liblaunch_profile_a_OBJECTS) +bin_PROGRAMS = launchctl$(EXEEXT) wait4path$(EXEEXT) +libexec_PROGRAMS = ConsoleMessage$(EXEEXT) \ + register_mach_bootstrap_servers$(EXEEXT) \ + StartupItemContext$(EXEEXT) launchproxy$(EXEEXT) +sbin_PROGRAMS = launchd$(EXEEXT) SystemStarter$(EXEEXT) \ + launchd_debugd$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) $(libexec_PROGRAMS) $(sbin_PROGRAMS) + +ConsoleMessage_SOURCES = ConsoleMessage.c +ConsoleMessage_OBJECTS = ConsoleMessage.$(OBJEXT) +ConsoleMessage_LDADD = $(LDADD) +ConsoleMessage_DEPENDENCIES = +StartupItemContext_SOURCES = StartupItemContext.c +StartupItemContext_OBJECTS = StartupItemContext.$(OBJEXT) +StartupItemContext_LDADD = $(LDADD) +StartupItemContext_DEPENDENCIES = +StartupItemContext_LDFLAGS = +am_SystemStarter_OBJECTS = SystemStarter-StartupItems.$(OBJEXT) \ + SystemStarter-IPC.$(OBJEXT) \ + SystemStarter-SystemStarter.$(OBJEXT) +SystemStarter_OBJECTS = $(am_SystemStarter_OBJECTS) +SystemStarter_LDADD = $(LDADD) +SystemStarter_DEPENDENCIES = +launchctl_SOURCES = launchctl.c +launchctl_OBJECTS = launchctl.$(OBJEXT) +launchctl_LDADD = $(LDADD) +launchctl_DEPENDENCIES = +am_launchd_OBJECTS = launchd-launchd.$(OBJEXT) launchd-init.$(OBJEXT) \ + launchd-bootstrap.$(OBJEXT) launchd-lists.$(OBJEXT) \ + launchd-rpc_services.$(OBJEXT) \ + launchd-bootstrapServer.$(OBJEXT) +launchd_OBJECTS = $(am_launchd_OBJECTS) +launchd_LDADD = $(LDADD) +launchd_DEPENDENCIES = +am_launchd_debugd_OBJECTS = launchd_debugd-launchdebugd.$(OBJEXT) +launchd_debugd_OBJECTS = $(am_launchd_debugd_OBJECTS) +launchd_debugd_LDADD = $(LDADD) +launchd_debugd_DEPENDENCIES = +launchd_debugd_LDFLAGS = +launchproxy_SOURCES = launchproxy.c +launchproxy_OBJECTS = launchproxy.$(OBJEXT) +launchproxy_LDADD = $(LDADD) +launchproxy_DEPENDENCIES = +register_mach_bootstrap_servers_SOURCES = \ + register_mach_bootstrap_servers.c +register_mach_bootstrap_servers_OBJECTS = \ + register_mach_bootstrap_servers.$(OBJEXT) +register_mach_bootstrap_servers_LDADD = $(LDADD) +register_mach_bootstrap_servers_DEPENDENCIES = +wait4path_SOURCES = wait4path.c +wait4path_OBJECTS = wait4path.$(OBJEXT) +wait4path_LDADD = $(LDADD) +wait4path_DEPENDENCIES = +wait4path_LDFLAGS = +SCRIPTS = $(sbin_SCRIPTS) + + +DEFS = @DEFS@ +DEFAULT_INCLUDES = -I. -I$(srcdir) -I. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/ConsoleMessage.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/StartupItemContext.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/SystemStarter-IPC.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/SystemStarter-StartupItems.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/SystemStarter-SystemStarter.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/launchctl.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/launchd-bootstrap.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/launchd-bootstrapServer.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/launchd-init.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/launchd-launchd.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/launchd-lists.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/launchd-rpc_services.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/launchd_debugd-launchdebugd.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/launchproxy.Po ./$(DEPDIR)/liblaunch.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/liblaunch_profile_a-liblaunch.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/register_mach_bootstrap_servers.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/wait4path.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +CFLAGS = @CFLAGS@ +DIST_SOURCES = $(liblaunch_a_SOURCES) $(liblaunch_profile_a_SOURCES) \ + ConsoleMessage.c StartupItemContext.c $(SystemStarter_SOURCES) \ + launchctl.c $(launchd_SOURCES) $(launchd_debugd_SOURCES) \ + launchproxy.c register_mach_bootstrap_servers.c wait4path.c + +NROFF = nroff +MANS = $(man1_MANS) $(man5_MANS) $(man8_MANS) +DATA = $(sysconf_DATA) + +DIST_COMMON = Makefile.am Makefile.in config.h.in +SOURCES = $(liblaunch_a_SOURCES) $(liblaunch_profile_a_SOURCES) ConsoleMessage.c StartupItemContext.c $(SystemStarter_SOURCES) launchctl.c $(launchd_SOURCES) $(launchd_debugd_SOURCES) launchproxy.c register_mach_bootstrap_servers.c wait4path.c + +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status src/config.h + +$(srcdir)/config.h.in: $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOHEADER) + touch $(srcdir)/config.h.in + +distclean-hdr: + -rm -f config.h stamp-h1 + +AR = ar + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +liblaunch.a: $(liblaunch_a_OBJECTS) $(liblaunch_a_DEPENDENCIES) + -rm -f liblaunch.a + $(liblaunch_a_AR) liblaunch.a $(liblaunch_a_OBJECTS) $(liblaunch_a_LIBADD) + $(RANLIB) liblaunch.a +liblaunch_profile_a-liblaunch.$(OBJEXT): liblaunch.c +liblaunch_profile.a: $(liblaunch_profile_a_OBJECTS) $(liblaunch_profile_a_DEPENDENCIES) + -rm -f liblaunch_profile.a + $(liblaunch_profile_a_AR) liblaunch_profile.a $(liblaunch_profile_a_OBJECTS) $(liblaunch_profile_a_LIBADD) + $(RANLIB) liblaunch_profile.a +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +libexecPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-libexecPROGRAMS: $(libexec_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(libexecdir) + @list='$(libexec_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(libexecPROGRAMS_INSTALL) $$p $(DESTDIR)$(libexecdir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(libexecPROGRAMS_INSTALL) $$p $(DESTDIR)$(libexecdir)/$$f; \ + else :; fi; \ + done + +uninstall-libexecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(libexec_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(libexecdir)/$$f"; \ + rm -f $(DESTDIR)$(libexecdir)/$$f; \ + done + +clean-libexecPROGRAMS: + -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) +sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \ + rm -f $(DESTDIR)$(sbindir)/$$f; \ + done + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) +ConsoleMessage$(EXEEXT): $(ConsoleMessage_OBJECTS) $(ConsoleMessage_DEPENDENCIES) + @rm -f ConsoleMessage$(EXEEXT) + $(LINK) $(ConsoleMessage_LDFLAGS) $(ConsoleMessage_OBJECTS) $(ConsoleMessage_LDADD) $(LIBS) +StartupItemContext$(EXEEXT): $(StartupItemContext_OBJECTS) $(StartupItemContext_DEPENDENCIES) + @rm -f StartupItemContext$(EXEEXT) + $(LINK) $(StartupItemContext_LDFLAGS) $(StartupItemContext_OBJECTS) $(StartupItemContext_LDADD) $(LIBS) +SystemStarter-StartupItems.$(OBJEXT): StartupItems.c +SystemStarter-IPC.$(OBJEXT): IPC.c +SystemStarter-SystemStarter.$(OBJEXT): SystemStarter.c +SystemStarter$(EXEEXT): $(SystemStarter_OBJECTS) $(SystemStarter_DEPENDENCIES) + @rm -f SystemStarter$(EXEEXT) + $(LINK) $(SystemStarter_LDFLAGS) $(SystemStarter_OBJECTS) $(SystemStarter_LDADD) $(LIBS) +launchctl$(EXEEXT): $(launchctl_OBJECTS) $(launchctl_DEPENDENCIES) + @rm -f launchctl$(EXEEXT) + $(LINK) $(launchctl_LDFLAGS) $(launchctl_OBJECTS) $(launchctl_LDADD) $(LIBS) +launchd-launchd.$(OBJEXT): launchd.c +launchd-init.$(OBJEXT): init.c +launchd-bootstrap.$(OBJEXT): bootstrap.c +launchd-lists.$(OBJEXT): lists.c +launchd-rpc_services.$(OBJEXT): rpc_services.c +launchd-bootstrapServer.$(OBJEXT): bootstrapServer.c +launchd$(EXEEXT): $(launchd_OBJECTS) $(launchd_DEPENDENCIES) + @rm -f launchd$(EXEEXT) + $(LINK) $(launchd_LDFLAGS) $(launchd_OBJECTS) $(launchd_LDADD) $(LIBS) +launchd_debugd-launchdebugd.$(OBJEXT): launchdebugd.c +launchd_debugd$(EXEEXT): $(launchd_debugd_OBJECTS) $(launchd_debugd_DEPENDENCIES) + @rm -f launchd_debugd$(EXEEXT) + $(LINK) $(launchd_debugd_LDFLAGS) $(launchd_debugd_OBJECTS) $(launchd_debugd_LDADD) $(LIBS) +launchproxy$(EXEEXT): $(launchproxy_OBJECTS) $(launchproxy_DEPENDENCIES) + @rm -f launchproxy$(EXEEXT) + $(LINK) $(launchproxy_LDFLAGS) $(launchproxy_OBJECTS) $(launchproxy_LDADD) $(LIBS) +register_mach_bootstrap_servers$(EXEEXT): $(register_mach_bootstrap_servers_OBJECTS) $(register_mach_bootstrap_servers_DEPENDENCIES) + @rm -f register_mach_bootstrap_servers$(EXEEXT) + $(LINK) $(register_mach_bootstrap_servers_LDFLAGS) $(register_mach_bootstrap_servers_OBJECTS) $(register_mach_bootstrap_servers_LDADD) $(LIBS) +wait4path$(EXEEXT): $(wait4path_OBJECTS) $(wait4path_DEPENDENCIES) + @rm -f wait4path$(EXEEXT) + $(LINK) $(wait4path_LDFLAGS) $(wait4path_OBJECTS) $(wait4path_LDADD) $(LIBS) +sbinSCRIPT_INSTALL = $(INSTALL_SCRIPT) +install-sbinSCRIPTS: $(sbin_SCRIPTS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_SCRIPTS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f $$d$$p; then \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " $(sbinSCRIPT_INSTALL) $$d$$p $(DESTDIR)$(sbindir)/$$f"; \ + $(sbinSCRIPT_INSTALL) $$d$$p $(DESTDIR)$(sbindir)/$$f; \ + else :; fi; \ + done + +uninstall-sbinSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_SCRIPTS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \ + rm -f $(DESTDIR)$(sbindir)/$$f; \ + done + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ConsoleMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StartupItemContext.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SystemStarter-IPC.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SystemStarter-StartupItems.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SystemStarter-SystemStarter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchctl.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-bootstrap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-bootstrapServer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-init.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-launchd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-lists.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-rpc_services.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd_debugd-launchdebugd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchproxy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblaunch.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblaunch_profile_a-liblaunch.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/register_mach_bootstrap_servers.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wait4path.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `cygpath -w $<` + +liblaunch_profile_a-liblaunch.o: liblaunch.c +@AMDEP_TRUE@ source='liblaunch.c' object='liblaunch_profile_a-liblaunch.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/liblaunch_profile_a-liblaunch.Po' tmpdepfile='$(DEPDIR)/liblaunch_profile_a-liblaunch.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -c -o liblaunch_profile_a-liblaunch.o `test -f 'liblaunch.c' || echo '$(srcdir)/'`liblaunch.c + +liblaunch_profile_a-liblaunch.obj: liblaunch.c +@AMDEP_TRUE@ source='liblaunch.c' object='liblaunch_profile_a-liblaunch.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/liblaunch_profile_a-liblaunch.Po' tmpdepfile='$(DEPDIR)/liblaunch_profile_a-liblaunch.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblaunch_profile_a_CFLAGS) $(CFLAGS) -c -o liblaunch_profile_a-liblaunch.obj `cygpath -w liblaunch.c` + +SystemStarter-StartupItems.o: StartupItems.c +@AMDEP_TRUE@ source='StartupItems.c' object='SystemStarter-StartupItems.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/SystemStarter-StartupItems.Po' tmpdepfile='$(DEPDIR)/SystemStarter-StartupItems.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -c -o SystemStarter-StartupItems.o `test -f 'StartupItems.c' || echo '$(srcdir)/'`StartupItems.c + +SystemStarter-StartupItems.obj: StartupItems.c +@AMDEP_TRUE@ source='StartupItems.c' object='SystemStarter-StartupItems.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/SystemStarter-StartupItems.Po' tmpdepfile='$(DEPDIR)/SystemStarter-StartupItems.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -c -o SystemStarter-StartupItems.obj `cygpath -w StartupItems.c` + +SystemStarter-IPC.o: IPC.c +@AMDEP_TRUE@ source='IPC.c' object='SystemStarter-IPC.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/SystemStarter-IPC.Po' tmpdepfile='$(DEPDIR)/SystemStarter-IPC.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -c -o SystemStarter-IPC.o `test -f 'IPC.c' || echo '$(srcdir)/'`IPC.c + +SystemStarter-IPC.obj: IPC.c +@AMDEP_TRUE@ source='IPC.c' object='SystemStarter-IPC.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/SystemStarter-IPC.Po' tmpdepfile='$(DEPDIR)/SystemStarter-IPC.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -c -o SystemStarter-IPC.obj `cygpath -w IPC.c` + +SystemStarter-SystemStarter.o: SystemStarter.c +@AMDEP_TRUE@ source='SystemStarter.c' object='SystemStarter-SystemStarter.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/SystemStarter-SystemStarter.Po' tmpdepfile='$(DEPDIR)/SystemStarter-SystemStarter.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -c -o SystemStarter-SystemStarter.o `test -f 'SystemStarter.c' || echo '$(srcdir)/'`SystemStarter.c + +SystemStarter-SystemStarter.obj: SystemStarter.c +@AMDEP_TRUE@ source='SystemStarter.c' object='SystemStarter-SystemStarter.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/SystemStarter-SystemStarter.Po' tmpdepfile='$(DEPDIR)/SystemStarter-SystemStarter.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(SystemStarter_CFLAGS) $(CFLAGS) -c -o SystemStarter-SystemStarter.obj `cygpath -w SystemStarter.c` + +launchd-launchd.o: launchd.c +@AMDEP_TRUE@ source='launchd.c' object='launchd-launchd.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/launchd-launchd.Po' tmpdepfile='$(DEPDIR)/launchd-launchd.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd.o `test -f 'launchd.c' || echo '$(srcdir)/'`launchd.c + +launchd-launchd.obj: launchd.c +@AMDEP_TRUE@ source='launchd.c' object='launchd-launchd.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/launchd-launchd.Po' tmpdepfile='$(DEPDIR)/launchd-launchd.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd.obj `cygpath -w launchd.c` + +launchd-init.o: init.c +@AMDEP_TRUE@ source='init.c' object='launchd-init.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/launchd-init.Po' tmpdepfile='$(DEPDIR)/launchd-init.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-init.o `test -f 'init.c' || echo '$(srcdir)/'`init.c + +launchd-init.obj: init.c +@AMDEP_TRUE@ source='init.c' object='launchd-init.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/launchd-init.Po' tmpdepfile='$(DEPDIR)/launchd-init.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-init.obj `cygpath -w init.c` + +launchd-bootstrap.o: bootstrap.c +@AMDEP_TRUE@ source='bootstrap.c' object='launchd-bootstrap.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/launchd-bootstrap.Po' tmpdepfile='$(DEPDIR)/launchd-bootstrap.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-bootstrap.o `test -f 'bootstrap.c' || echo '$(srcdir)/'`bootstrap.c + +launchd-bootstrap.obj: bootstrap.c +@AMDEP_TRUE@ source='bootstrap.c' object='launchd-bootstrap.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/launchd-bootstrap.Po' tmpdepfile='$(DEPDIR)/launchd-bootstrap.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-bootstrap.obj `cygpath -w bootstrap.c` + +launchd-lists.o: lists.c +@AMDEP_TRUE@ source='lists.c' object='launchd-lists.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/launchd-lists.Po' tmpdepfile='$(DEPDIR)/launchd-lists.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-lists.o `test -f 'lists.c' || echo '$(srcdir)/'`lists.c + +launchd-lists.obj: lists.c +@AMDEP_TRUE@ source='lists.c' object='launchd-lists.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/launchd-lists.Po' tmpdepfile='$(DEPDIR)/launchd-lists.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-lists.obj `cygpath -w lists.c` + +launchd-rpc_services.o: rpc_services.c +@AMDEP_TRUE@ source='rpc_services.c' object='launchd-rpc_services.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/launchd-rpc_services.Po' tmpdepfile='$(DEPDIR)/launchd-rpc_services.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-rpc_services.o `test -f 'rpc_services.c' || echo '$(srcdir)/'`rpc_services.c + +launchd-rpc_services.obj: rpc_services.c +@AMDEP_TRUE@ source='rpc_services.c' object='launchd-rpc_services.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/launchd-rpc_services.Po' tmpdepfile='$(DEPDIR)/launchd-rpc_services.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-rpc_services.obj `cygpath -w rpc_services.c` + +launchd-bootstrapServer.o: bootstrapServer.c +@AMDEP_TRUE@ source='bootstrapServer.c' object='launchd-bootstrapServer.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/launchd-bootstrapServer.Po' tmpdepfile='$(DEPDIR)/launchd-bootstrapServer.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-bootstrapServer.o `test -f 'bootstrapServer.c' || echo '$(srcdir)/'`bootstrapServer.c + +launchd-bootstrapServer.obj: bootstrapServer.c +@AMDEP_TRUE@ source='bootstrapServer.c' object='launchd-bootstrapServer.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/launchd-bootstrapServer.Po' tmpdepfile='$(DEPDIR)/launchd-bootstrapServer.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-bootstrapServer.obj `cygpath -w bootstrapServer.c` + +launchd_debugd-launchdebugd.o: launchdebugd.c +@AMDEP_TRUE@ source='launchdebugd.c' object='launchd_debugd-launchdebugd.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/launchd_debugd-launchdebugd.Po' tmpdepfile='$(DEPDIR)/launchd_debugd-launchdebugd.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_debugd_CFLAGS) $(CFLAGS) -c -o launchd_debugd-launchdebugd.o `test -f 'launchdebugd.c' || echo '$(srcdir)/'`launchdebugd.c + +launchd_debugd-launchdebugd.obj: launchdebugd.c +@AMDEP_TRUE@ source='launchdebugd.c' object='launchd_debugd-launchdebugd.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/launchd_debugd-launchdebugd.Po' tmpdepfile='$(DEPDIR)/launchd_debugd-launchdebugd.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_debugd_CFLAGS) $(CFLAGS) -c -o launchd_debugd-launchdebugd.obj `cygpath -w launchdebugd.c` +CCDEPMODE = @CCDEPMODE@ +uninstall-info-am: + +man1dir = $(mandir)/man1 +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(man1dir) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \ + done +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \ + rm -f $(DESTDIR)$(man1dir)/$$inst; \ + done + +man5dir = $(mandir)/man5 +install-man5: $(man5_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(man5dir) + @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 5*) ;; \ + *) ext='5' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst; \ + done +uninstall-man5: + @$(NORMAL_UNINSTALL) + @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man5dir)/$$inst"; \ + rm -f $(DESTDIR)$(man5dir)/$$inst; \ + done + +man8dir = $(mandir)/man8 +install-man8: $(man8_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(man8dir) + @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 8*) ;; \ + *) ext='8' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ + done +uninstall-man8: + @$(NORMAL_UNINSTALL) + @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ + rm -f $(DESTDIR)$(man8dir)/$$inst; \ + done +sysconfDATA_INSTALL = $(INSTALL_DATA) +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(sysconfDATA_INSTALL) $$d$$p $(DESTDIR)$(sysconfdir)/$$f"; \ + $(sysconfDATA_INSTALL) $$d$$p $(DESTDIR)$(sysconfdir)/$$f; \ + done + +uninstall-sysconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(sysconf_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \ + rm -f $(DESTDIR)$(sysconfdir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(SCRIPTS) $(MANS) $(DATA) \ + config.h + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(libexecdir) $(DESTDIR)$(sbindir) $(DESTDIR)$(sbindir) $(DESTDIR)$(man1dir) $(DESTDIR)$(man5dir) $(DESTDIR)$(man8dir) $(DESTDIR)$(sysconfdir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libexecPROGRAMS \ + clean-noinstLIBRARIES clean-sbinPROGRAMS mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-hdr distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: install-man + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-data-hook + +install-exec-am: install-binPROGRAMS install-libexecPROGRAMS \ + install-sbinPROGRAMS install-sbinSCRIPTS install-sysconfDATA + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook + +install-info: install-info-am + +install-man: install-man1 install-man5 install-man8 + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am \ + uninstall-libexecPROGRAMS uninstall-man uninstall-sbinPROGRAMS \ + uninstall-sbinSCRIPTS uninstall-sysconfDATA + +uninstall-man: uninstall-man1 uninstall-man5 uninstall-man8 + +.PHONY: GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libexecPROGRAMS clean-noinstLIBRARIES \ + clean-sbinPROGRAMS distclean distclean-compile distclean-depend \ + distclean-generic distclean-hdr distclean-tags distdir dvi \ + dvi-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-libexecPROGRAMS \ + install-man install-man1 install-man5 install-man8 \ + install-sbinPROGRAMS install-sbinSCRIPTS install-strip \ + install-sysconfDATA installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic tags uninstall \ + uninstall-am uninstall-binPROGRAMS uninstall-info-am \ + uninstall-libexecPROGRAMS uninstall-man uninstall-man1 \ + uninstall-man5 uninstall-man8 uninstall-sbinPROGRAMS \ + uninstall-sbinSCRIPTS uninstall-sysconfDATA + + +bootstrap.c:: bootstrap.h + +bootstrap.h bootstrapServer.c bootstrapUser.c: $(srcdir)/bootstrap.defs + mig $(MIGFLAGS) $(srcdir)/bootstrap.defs + +$(addprefix $(DESTDIR)/System/Library/StartupItems/, $(STARTUPITEMS)): + mkdir -p $@ + cp $(srcdir)/StartupItems/$(notdir $@) $@ + chmod 755 $@/$(notdir $@) + cp $(srcdir)/StartupItems/$(notdir $@).plist $@/StartupParameters.plist + +install-startupitems: $(addprefix $(DESTDIR)/System/Library/StartupItems/, $(STARTUPITEMS)) + +install-data-hook: install-startupitems + mkdir -p $(DESTDIR)/usr/local/lib/system + cp liblaunch.a $(DESTDIR)/usr/local/lib/system + cp liblaunch.a $(DESTDIR)/usr/local/lib/system/liblaunch_debug.a + cp liblaunch_profile.a $(DESTDIR)/usr/local/lib/system/liblaunch_profile.a + mkdir -p $(DESTDIR)/usr/include + cp $(srcdir)/launch.h $(DESTDIR)/usr/include + mkdir -p $(DESTDIR)/usr/local/include + cp $(srcdir)/launch_priv.h $(DESTDIR)/usr/local/include + mkdir -p $(DESTDIR)/$(sysconfdir)/mach_init.d + mkdir -p $(DESTDIR)/$(sysconfdir)/mach_init_per_user.d + mkdir -p $(DESTDIR)/Library/LaunchDaemons + mkdir -p $(DESTDIR)/Library/LaunchAgents + mkdir -p $(DESTDIR)/System/Library/LaunchDaemons + mkdir -p $(DESTDIR)/System/Library/LaunchAgents + +install-exec-hook: + chmod u+s $(DESTDIR)/$(sbindir)/launchd +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/launchd/src/StartupItemContext.8 b/launchd/src/StartupItemContext.8 new file mode 100644 index 0000000..eff4ab4 --- /dev/null +++ b/launchd/src/StartupItemContext.8 @@ -0,0 +1,35 @@ +.Dd July 7, 2002 +.Dt StartupItemContext 8 +.Os Darwin +.Sh NAME +.Nm StartupItemContext +.\" The following lines are read in generating the apropos(man -k) database. Use only key +.\" words here as the database is built based on the words here and in the .ND line. +.\" Use .Nm macro to designate other names for the documented program. +.Nd Execute a program in StartupItem context +.Sh SYNOPSIS +.Nm +.Op Ar program Op Ar arguments +.Sh DESCRIPTION +The +.Nm +utility launches the specified program in StartupItem bootstrap context. Each Darwin +and Mac OS X login creates a unique bootstrap subset context to contain login specific +Mach port registrations with the bootstrap server. All such registrations performed +within the context of that subset are only visible to other processes within that +context or subsequent subsets of it. Therefore, a Mach port based service/daemon +launched within a login context will not be visible to other such contexts. +.Pp +To override this, a root user can use the +.Nm +utility to launch the program within the same bootstrap context as all other +StartupItems. All subsequent Mach port bootstrap registrations perfomed by the program +will be visible system-wide. +.Sh NOTES +All bootstrap port lookups will also be resticted +to the StartupItem context. The services provided on a per-login basis (clipboard, +etc...) will not be available to the program. +.Sh SEE ALSO +.\" List links in ascending order by section, alphabetically within a section. +.\" Please do not reference files that do not exist without filing a bug report +.Xr SystemStarter 8 diff --git a/launchd/src/StartupItemContext.c b/launchd/src/StartupItemContext.c new file mode 100644 index 0000000..529618b --- /dev/null +++ b/launchd/src/StartupItemContext.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include + +#include + +int main(int argc, char *argv[]) +{ + mach_port_t root_bootstrap_port; + kern_return_t ret; +#if 0 + task_t init_task; + int err; +#endif + + if (argc < 2) { + fprintf(stderr, "usage: %s executable [args...]\n", argv[0]); + exit(1); + } + + if (geteuid() != 0) { + fprintf(stderr, "%s: permission denied: must be run as root\n", argv[0]); + return(EPERM); + exit(1); + } + +#if 0 + /* get init's task port */ + ret = task_for_pid((mach_task_self)(), 1, &init_task); + if (ret != KERN_SUCCESS) { + fprintf(stderr, "%s: task_for_pid() failed: permission denied\n", + argv[0]); + exit(1); + } + /* extract its bootstrap port, which should be the root */ + ret = task_get_bootstrap_port(init_task, &root_bootstrap_port); + if (ret != KERN_SUCCESS) { + fprintf(stderr, "%s: task_get_bootstrap_port() failed: %s\n", + argv[0], mach_error_string(ret)); + exit(2); + } +#else + /* + * Keep looping, getting out bootstrap's parent until it repeats, then we + * know we are at the root/startupItem context. + */ + { + mach_port_t cur_bootstrap; + + root_bootstrap_port = bootstrap_port; + do { + cur_bootstrap = root_bootstrap_port; + ret = bootstrap_parent(cur_bootstrap, &root_bootstrap_port); + if (ret == BOOTSTRAP_NOT_PRIVILEGED) { + fprintf(stderr, "%s: must be run as root\n", argv[0]); + exit(1); + } + } while (root_bootstrap_port != cur_bootstrap); + } +#endif + + /* set that as our bootstrap port */ + ret = task_set_bootstrap_port(mach_task_self(), root_bootstrap_port); + if (ret != KERN_SUCCESS) { + fprintf(stderr, "%s: task_set_bootstrap_port() failed: %s\n", + argv[0], mach_error_string(ret)); + exit(3); + } + + /* exec the program called for */ + execv(argv[1], &argv[1]); /* should not return */ + fprintf(stderr, "%s: exec failed: %s(%d)\n", argv[0], strerror(errno), errno); + return(4); +} diff --git a/launchd/src/StartupItems.c b/launchd/src/StartupItems.c new file mode 100644 index 0000000..46f0e1a --- /dev/null +++ b/launchd/src/StartupItems.c @@ -0,0 +1,1085 @@ +/** + * StartupItems.c - Startup Item management routines + * Wilfredo Sanchez | wsanchez@opensource.apple.com + * Kevin Van Vechten | kevinvv@uclink4.berkeley.edu + * $Apple$ + ** + * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.1 (the "License"). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "StartupItems.h" + +#define kStartupItemsPath "/StartupItems" +#define kParametersFile "StartupParameters.plist" +#define kDisabledFile ".disabled" + +#define kRunSuccess CFSTR("success") +#define kRunFailure CFSTR("failure") + +typedef enum { + kPriorityLast = 1, + kPriorityLate = 2, + kPriorityNone = 3, + kPriorityEarly = 4, + kPriorityFirst = 5, + kPriorityNetwork = 10, + kPriorityLocal = 20, +} Priority; + +static Priority +priorityFromString(CFStringRef aPriority) +{ + if (aPriority) { + if (CFEqual(aPriority, CFSTR("Last"))) + return kPriorityLast; + else if (CFEqual(aPriority, CFSTR("Late"))) + return kPriorityLate; + else if (CFEqual(aPriority, CFSTR("None"))) + return kPriorityNone; + else if (CFEqual(aPriority, CFSTR("Early"))) + return kPriorityEarly; + else if (CFEqual(aPriority, CFSTR("First"))) + return kPriorityFirst; + } + return kPriorityNone; +} + +static const char * +argumentForAction(Action anAction) +{ + switch (anAction) { + case kActionStart:return "start"; + case kActionStop: + return "stop"; + case kActionRestart: + return "restart"; + default: + return NULL; + } +} + +#define checkTypeOfValue(aKey,aTypeID) \ + { \ + CFStringRef aProperty = CFDictionaryGetValue(aConfig, aKey); \ + if (aProperty && CFGetTypeID(aProperty) != aTypeID) \ + return FALSE; \ + } + +static int +StartupItemValidate(CFDictionaryRef aConfig) +{ + if (aConfig && CFGetTypeID(aConfig) == CFDictionaryGetTypeID()) { + checkTypeOfValue(kProvidesKey, CFArrayGetTypeID()); + checkTypeOfValue(kRequiresKey, CFArrayGetTypeID()); + + return TRUE; + } + return FALSE; +} + +/* + * remove item from waiting list + */ +void +RemoveItemFromWaitingList(StartupContext aStartupContext, CFMutableDictionaryRef anItem) +{ + /* Remove the item from the waiting list. */ + if (aStartupContext && anItem && aStartupContext->aWaitingList) { + CFRange aRange = {0, CFArrayGetCount(aStartupContext->aWaitingList)}; + CFIndex anIndex = CFArrayGetFirstIndexOfValue(aStartupContext->aWaitingList, aRange, anItem); + + if (anIndex >= 0) { + CFArrayRemoveValueAtIndex(aStartupContext->aWaitingList, anIndex); + } + } +} + +/* + * add item to failed list, create list if it doesn't exist + * return and fail quietly if it can't create list + */ +void +AddItemToFailedList(StartupContext aStartupContext, CFMutableDictionaryRef anItem) +{ + if (aStartupContext && anItem) { + /* create the failed list if it doesn't exist */ + if (!aStartupContext->aFailedList) { + aStartupContext->aFailedList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + if (aStartupContext->aFailedList) { + CFArrayAppendValue(aStartupContext->aFailedList, anItem); + } + } +} + + +/** + * startupItemListGetMatches returns an array of items which contain the string aService in the key aKey + **/ +static CFMutableArrayRef +startupItemListGetMatches(CFArrayRef anItemList, CFStringRef aKey, CFStringRef aService) +{ + CFMutableArrayRef aResult = NULL; + + if (anItemList && aKey && aService) { + CFIndex anItemCount = CFArrayGetCount(anItemList); + CFIndex anItemIndex = 0; + + aResult = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + + for (anItemIndex = 0; anItemIndex < anItemCount; ++anItemIndex) { + CFMutableDictionaryRef anItem = (CFMutableDictionaryRef) CFArrayGetValueAtIndex(anItemList, anItemIndex); + CFArrayRef aList = CFDictionaryGetValue(anItem, aKey); + + if (aList) { + if (CFArrayContainsValue(aList, CFRangeMake(0, CFArrayGetCount(aList)), aService) && + !CFArrayContainsValue(aResult, CFRangeMake(0, CFArrayGetCount(aResult)), anItem)) { + CFArrayAppendValue(aResult, anItem); + } + } + } + } + return aResult; +} + +static void +SpecialCasesStartupItemHandler(CFMutableDictionaryRef aConfig) +{ + static const CFStringRef stubitems[] = { + CFSTR("Accounting"), + CFSTR("System Tuning"), + CFSTR("SecurityServer"), + CFSTR("Portmap"), + CFSTR("System Log"), + CFSTR("Resolver"), + CFSTR("LDAP"), + CFSTR("NetInfo"), + CFSTR("NetworkExtensions"), + CFSTR("DirectoryServices"), + CFSTR("Network Configuration"), + CFSTR("mDNSResponder"), + CFSTR("Cron"), + CFSTR("Core Graphics"), + CFSTR("Network"), + NULL + }; + CFMutableArrayRef aList, aNewList; + CFIndex i, aCount; + CFStringRef ci, type = kRequiresKey; + const CFStringRef *c; + +again: + aList = (CFMutableArrayRef) CFDictionaryGetValue(aConfig, type); + if (aList) { + aCount = CFArrayGetCount(aList); + + aNewList = CFArrayCreateMutable(kCFAllocatorDefault, aCount, &kCFTypeArrayCallBacks); + + for (i = 0; i < aCount; i++) { + ci = CFArrayGetValueAtIndex(aList, i); + CF_syslog(LOG_DEBUG, CFSTR("%@: Evaluating %@"), type, ci); + for (c = stubitems; *c; c++) { + if (CFEqual(*c, ci)) + break; + } + if (*c == NULL) { + CFRetain(ci); + CFArrayAppendValue(aNewList, ci); + CF_syslog(LOG_DEBUG, CFSTR("%@: Keeping %@"), type, ci); + } + } + + CFDictionaryReplaceValue(aConfig, type, aNewList); + } + if (type == kUsesKey) + return; + type = kUsesKey; + goto again; +} + +CFIndex +StartupItemListCountServices(CFArrayRef anItemList) +{ + CFIndex aResult = 0; + + if (anItemList) { + CFIndex anItemCount = CFArrayGetCount(anItemList); + CFIndex anItemIndex = 0; + + for (anItemIndex = 0; anItemIndex < anItemCount; ++anItemIndex) { + CFDictionaryRef anItem = CFArrayGetValueAtIndex(anItemList, anItemIndex); + CFArrayRef aProvidesList = CFDictionaryGetValue(anItem, kProvidesKey); + + if (aProvidesList) + aResult += CFArrayGetCount(aProvidesList); + } + } + return aResult; +} + +static bool +StartupItemSecurityCheck(const char *aPath) +{ + struct stat aStatBuf; + bool r = true; + + /* should use lstatx_np() on Tiger? */ + if (lstat(aPath, &aStatBuf) == -1) { + if (errno != ENOENT) + syslog(LOG_ERR, "lstat(\"%s\"): %m", aPath); + return false; + } + if (!(S_ISREG(aStatBuf.st_mode) || S_ISDIR(aStatBuf.st_mode))) { + syslog(LOG_WARNING, "\"%s\" failed security check: not a directory or regular file", aPath); + r = false; + } + if ((aStatBuf.st_mode & ALLPERMS) & ~(S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { + syslog(LOG_WARNING, "\"%s\" failed security check: permissions", aPath); + r = false; + } + if (aStatBuf.st_uid != 0) { + syslog(LOG_WARNING, "\"%s\" failed security check: not owned by UID 0", aPath); + r = false; + } + if (aStatBuf.st_gid != 0) { + syslog(LOG_WARNING, "\"%s\" failed security check: not owned by GID 0", aPath); + r = false; + } + if (r == false) { + mkdir(kFixerDir, ACCESSPERMS); + close(open(kFixerPath, O_RDWR|O_CREAT, DEFFILEMODE)); + } + return r; +} + +CFMutableArrayRef +StartupItemListCreateWithMask(NSSearchPathDomainMask aMask) +{ + CFMutableArrayRef anItemList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + + char aPath[PATH_MAX]; + CFIndex aDomainIndex = 0; + + NSSearchPathEnumerationState aState = NSStartSearchPathEnumeration(NSLibraryDirectory, aMask); + + while ((aState = NSGetNextSearchPathEnumeration(aState, aPath))) { + DIR *aDirectory; + + strcpy(aPath + strlen(aPath), kStartupItemsPath); + ++aDomainIndex; + + if (!StartupItemSecurityCheck(aPath)) + continue; + + if ((aDirectory = opendir(aPath))) { + struct dirent *aBundle; + + while ((aBundle = readdir(aDirectory))) { + struct stat aStatBuf; + char *aBundleName = aBundle->d_name; + char aBundlePath[PATH_MAX]; + char aBundleExecutablePath[PATH_MAX]; + char aConfigFile[PATH_MAX]; + char aDisabledFile[PATH_MAX]; + + if (aBundleName[0] == '.') + continue; + + syslog(LOG_DEBUG, "Found item: %s", aBundleName); + + sprintf(aBundlePath, "%s/%s", aPath, aBundleName); + sprintf(aBundleExecutablePath, "%s/%s", aBundlePath, aBundleName); + sprintf(aConfigFile, "%s/%s", aBundlePath, kParametersFile); + sprintf(aDisabledFile, "%s/%s", aBundlePath, kDisabledFile); + + if (lstat(aDisabledFile, &aStatBuf) == 0) { + syslog(LOG_NOTICE, "Skipping disabled StartupItem: %s", aBundlePath); + continue; + } + if (!StartupItemSecurityCheck(aBundlePath)) + continue; + if (!StartupItemSecurityCheck(aBundleExecutablePath)) + continue; + if (!StartupItemSecurityCheck(aConfigFile)) + continue; + + /* Stow away the plist data for each bundle */ + { + int aConfigFileDescriptor; + + if ((aConfigFileDescriptor = open(aConfigFile, O_RDONLY, (mode_t) 0)) != -1) { + struct stat aConfigFileStatBuffer; + + if (stat(aConfigFile, &aConfigFileStatBuffer) != -1) { + off_t aConfigFileContentsSize = aConfigFileStatBuffer.st_size; + char *aConfigFileContentsBuffer; + + if ((aConfigFileContentsBuffer = + mmap((caddr_t) 0, aConfigFileContentsSize, + PROT_READ, MAP_FILE | MAP_PRIVATE, + aConfigFileDescriptor, (off_t) 0)) != (caddr_t) - 1) { + CFDataRef aConfigData = NULL; + CFMutableDictionaryRef aConfig = NULL; + + aConfigData = + CFDataCreateWithBytesNoCopy(NULL, + aConfigFileContentsBuffer, + aConfigFileContentsSize, + kCFAllocatorNull); + + if (aConfigData) { + aConfig = (CFMutableDictionaryRef) + CFPropertyListCreateFromXMLData(NULL, aConfigData, + kCFPropertyListMutableContainers, NULL); + } + if (StartupItemValidate(aConfig)) { + CFStringRef aBundlePathString = + CFStringCreateWithCString(NULL, aBundlePath, kCFStringEncodingUTF8); + + CFNumberRef aDomainNumber = + CFNumberCreate(NULL, kCFNumberCFIndexType, &aDomainIndex); + + CFDictionarySetValue(aConfig, kBundlePathKey, aBundlePathString); + CFDictionarySetValue(aConfig, kDomainKey, aDomainNumber); + CFRelease(aDomainNumber); + SpecialCasesStartupItemHandler(aConfig); + CFArrayAppendValue(anItemList, aConfig); + + CFRelease(aBundlePathString); + } else { + syslog(LOG_ERR, "Malformatted parameters file: %s", aConfigFile); + } + + if (aConfig) + CFRelease(aConfig); + if (aConfigData) + CFRelease(aConfigData); + + if (munmap(aConfigFileContentsBuffer, aConfigFileContentsSize) == -1) { + syslog(LOG_WARNING, "Unable to unmap parameters file %s for item %s: %m", aConfigFile, aBundleName); + } + } else { + syslog(LOG_ERR, "Unable to map parameters file %s for item %s: %m", aConfigFile, aBundleName); + } + } else { + syslog(LOG_ERR, "Unable to stat parameters file %s for item %s: %m", aConfigFile, aBundleName); + } + + if (close(aConfigFileDescriptor) == -1) { + syslog(LOG_ERR, "Unable to close parameters file %s for item %s: %m", aConfigFile, aBundleName); + } + } else { + syslog(LOG_ERR, "Unable to open parameters file %s for item %s: %m", aConfigFile, aBundleName); + } + } + } + if (closedir(aDirectory) == -1) { + syslog(LOG_WARNING, "Unable to directory bundle %s: %m", aPath); + } + } else { + if (errno != ENOENT) { + syslog(LOG_WARNING, "Open on directory %s failed: %m", aPath); + return (NULL); + } + } + } + + return anItemList; +} + +CFMutableDictionaryRef +StartupItemListGetProvider(CFArrayRef anItemList, CFStringRef aService) +{ + CFMutableDictionaryRef aResult = NULL; + CFMutableArrayRef aList = startupItemListGetMatches(anItemList, kProvidesKey, aService); + + if (aList && CFArrayGetCount(aList) > 0) + aResult = (CFMutableDictionaryRef) CFArrayGetValueAtIndex(aList, 0); + + return aResult; +} + +CFArrayRef +StartupItemListGetRunning(CFArrayRef anItemList) +{ + CFMutableArrayRef aResult = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (aResult) { + CFIndex anIndex, aCount = CFArrayGetCount(anItemList); + for (anIndex = 0; anIndex < aCount; ++anIndex) { + CFDictionaryRef anItem = CFArrayGetValueAtIndex(anItemList, anIndex); + if (anItem) { + CFNumberRef aPID = CFDictionaryGetValue(anItem, kPIDKey); + if (aPID) + CFArrayAppendValue(aResult, anItem); + } + } + } + return aResult; +} + +/* + * Append items in anItemList to aDependents which depend on + * aParentItem. + * If anAction is kActionStart, dependent items are those which + * require any service provided by aParentItem. + * If anAction is kActionStop, dependent items are those which provide + * any service required by aParentItem. + */ +static void +appendDependents(CFMutableArrayRef aDependents, + CFArrayRef anItemList, CFDictionaryRef aParentItem, + Action anAction) +{ + CFStringRef anInnerKey, anOuterKey; + CFArrayRef anOuterList; + + /* Append the parent item to the list (avoiding duplicates) */ + if (!CFArrayContainsValue(aDependents, CFRangeMake(0, CFArrayGetCount(aDependents)), aParentItem)) + CFArrayAppendValue(aDependents, aParentItem); + + /** + * Recursively append any children of the parent item for kStartAction and kStopAction. + * Do nothing for other actions. + **/ + switch (anAction) { + case kActionStart: + anInnerKey = kProvidesKey; + anOuterKey = kRequiresKey; + break; + case kActionStop: + anInnerKey = kRequiresKey; + anOuterKey = kProvidesKey; + break; + default: + return; + } + + anOuterList = CFDictionaryGetValue(aParentItem, anOuterKey); + + if (anOuterList) { + CFIndex anOuterCount = CFArrayGetCount(anOuterList); + CFIndex anOuterIndex; + + for (anOuterIndex = 0; anOuterIndex < anOuterCount; anOuterIndex++) { + CFStringRef anOuterElement = CFArrayGetValueAtIndex(anOuterList, anOuterIndex); + CFIndex anItemCount = CFArrayGetCount(anItemList); + CFIndex anItemIndex; + + for (anItemIndex = 0; anItemIndex < anItemCount; anItemIndex++) { + CFDictionaryRef anItem = CFArrayGetValueAtIndex(anItemList, anItemIndex); + CFArrayRef anInnerList = CFDictionaryGetValue(anItem, anInnerKey); + + if (anInnerList && + CFArrayContainsValue(anInnerList, CFRangeMake(0, CFArrayGetCount(anInnerList)), anOuterElement) && + !CFArrayContainsValue(aDependents, CFRangeMake(0, CFArrayGetCount(aDependents)), anItem)) + appendDependents(aDependents, anItemList, anItem, anAction); + } + } + } +} + +CFMutableArrayRef +StartupItemListCreateDependentsList(CFMutableArrayRef anItemList, CFStringRef aService, Action anAction) +{ + CFMutableArrayRef aDependents = NULL; + CFMutableDictionaryRef anItem = NULL; + + if (anItemList && aService) + anItem = StartupItemListGetProvider(anItemList, aService); + + if (anItem) { + switch (anAction) { + case kActionRestart: + case kActionStart: + case kActionStop: + aDependents = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + + if (!aDependents) { + CF_syslog(LOG_EMERG, CFSTR("Failed to allocate dependancy list for item %@"), anItem); + return NULL; + } + appendDependents(aDependents, anItemList, anItem, anAction); + break; + + default: + break; + } + } + return aDependents; +} + +/** + * countUnmetRequirements counts the number of items in anItemList + * which are pending in aStatusDict. + **/ +static int +countUnmetRequirements(CFDictionaryRef aStatusDict, CFArrayRef anItemList) +{ + int aCount = 0; + CFIndex anItemCount = CFArrayGetCount(anItemList); + CFIndex anItemIndex; + + for (anItemIndex = 0; anItemIndex < anItemCount; anItemIndex++) { + CFStringRef anItem = CFArrayGetValueAtIndex(anItemList, anItemIndex); + CFStringRef aStatus = CFDictionaryGetValue(aStatusDict, anItem); + + if (!aStatus || !CFEqual(aStatus, kRunSuccess)) { + CF_syslog(LOG_DEBUG, CFSTR("\tFailed requirement/uses: %@"), anItem); + aCount++; + } + } + + return aCount; +} + +/** + * countDependantsPresent counts the number of items in aWaitingList + * which depend on items in anItemList. + **/ +static int +countDependantsPresent(CFArrayRef aWaitingList, CFArrayRef anItemList, CFStringRef aKey) +{ + int aCount = 0; + CFIndex anItemCount = CFArrayGetCount(anItemList); + CFIndex anItemIndex; + + for (anItemIndex = 0; anItemIndex < anItemCount; anItemIndex++) { + CFStringRef anItem = CFArrayGetValueAtIndex(anItemList, anItemIndex); + CFArrayRef aMatchesList = startupItemListGetMatches(aWaitingList, aKey, anItem); + + if (aMatchesList) { + aCount = aCount + CFArrayGetCount(aMatchesList); + CFRelease(aMatchesList); + } + } + + return aCount; +} + +/** + * pendingAntecedents returns TRUE if any antecedents of this item + * are currently running, have not yet run, or none exist. + **/ +static Boolean +pendingAntecedents(CFArrayRef aWaitingList, CFDictionaryRef aStatusDict, CFArrayRef anAntecedentList, Action anAction) +{ + int aPendingFlag = FALSE; + + CFIndex anAntecedentCount = CFArrayGetCount(anAntecedentList); + CFIndex anAntecedentIndex; + + for (anAntecedentIndex = 0; anAntecedentIndex < anAntecedentCount; ++anAntecedentIndex) { + CFStringRef anAntecedent = CFArrayGetValueAtIndex(anAntecedentList, anAntecedentIndex); + CFStringRef aKey = (anAction == kActionStart) ? kProvidesKey : kUsesKey; + CFArrayRef aMatchesList = startupItemListGetMatches(aWaitingList, aKey, anAntecedent); + + if (aMatchesList) { + CFIndex aMatchesListCount = CFArrayGetCount(aMatchesList); + CFIndex aMatchesListIndex; + + for (aMatchesListIndex = 0; aMatchesListIndex < aMatchesListCount; ++aMatchesListIndex) { + CFDictionaryRef anItem = CFArrayGetValueAtIndex(aMatchesList, aMatchesListIndex); + + if (!anItem || + !CFDictionaryGetValue(anItem, kPIDKey) || + !CFDictionaryGetValue(aStatusDict, anAntecedent)) { + aPendingFlag = TRUE; + break; + } + } + + CFRelease(aMatchesList); + + if (aPendingFlag) + break; + } + } + return (aPendingFlag); +} + +/** + * checkForDuplicates returns TRUE if an item provides the same service as a + * pending item, or an item that already succeeded. + **/ +static Boolean +checkForDuplicates(CFArrayRef aWaitingList, CFDictionaryRef aStatusDict, CFDictionaryRef anItem) +{ + int aDuplicateFlag = FALSE; + + CFArrayRef aProvidesList = CFDictionaryGetValue(anItem, kProvidesKey); + CFIndex aProvidesCount = aProvidesList ? CFArrayGetCount(aProvidesList) : 0; + CFIndex aProvidesIndex; + + for (aProvidesIndex = 0; aProvidesIndex < aProvidesCount; ++aProvidesIndex) { + CFStringRef aProvides = CFArrayGetValueAtIndex(aProvidesList, aProvidesIndex); + + /* If the service succeeded, return true. */ + CFStringRef aStatus = CFDictionaryGetValue(aStatusDict, aProvides); + if (aStatus && CFEqual(aStatus, kRunSuccess)) { + aDuplicateFlag = TRUE; + break; + } + /* + * Otherwise test if any item is currently running which + * might provide that service. + */ + else { + CFArrayRef aMatchesList = startupItemListGetMatches(aWaitingList, kProvidesKey, aProvides); + if (aMatchesList) { + CFIndex aMatchesListCount = CFArrayGetCount(aMatchesList); + CFIndex aMatchesListIndex; + + for (aMatchesListIndex = 0; aMatchesListIndex < aMatchesListCount; ++aMatchesListIndex) { + CFDictionaryRef anDupItem = CFArrayGetValueAtIndex(aMatchesList, aMatchesListIndex); + if (anDupItem && CFDictionaryGetValue(anDupItem, kPIDKey)) { + /* + * Item is running, avoid + * race condition. + */ + aDuplicateFlag = TRUE; + break; + } else { + CFNumberRef anItemDomain = CFDictionaryGetValue(anItem, kDomainKey); + CFNumberRef anotherItemDomain = CFDictionaryGetValue(anDupItem, kDomainKey); + /* + * If anItem was found later + * than aDupItem, stall + * anItem until aDupItem + * runs. + */ + if (anItemDomain && + anotherItemDomain && + CFNumberCompare(anItemDomain, anotherItemDomain, NULL) == kCFCompareGreaterThan) { + /* + * Item not running, + * but takes + * precedence. + */ + aDuplicateFlag = TRUE; + break; + } + } + } + + CFRelease(aMatchesList); + if (aDuplicateFlag) + break; + } + } + } + return (aDuplicateFlag); +} + +CFMutableDictionaryRef +StartupItemListGetNext(CFArrayRef aWaitingList, CFDictionaryRef aStatusDict, Action anAction) +{ + CFMutableDictionaryRef aNextItem = NULL; + CFIndex aWaitingCount = CFArrayGetCount(aWaitingList); + + switch (anAction) { + case kActionStart: + break; + case kActionStop: + break; + case kActionRestart: + break; + default: + return NULL; + } + + if (aWaitingList && aStatusDict && aWaitingCount > 0) { + Priority aMaxPriority = kPriorityLast; + int aMinFailedAntecedents = INT_MAX; + CFIndex aWaitingIndex; + + /** + * Iterate through the items in aWaitingList and look for an optimally ready item. + **/ + for (aWaitingIndex = 0; aWaitingIndex < aWaitingCount; aWaitingIndex++) { + CFMutableDictionaryRef anItem = (CFMutableDictionaryRef) CFArrayGetValueAtIndex(aWaitingList, aWaitingIndex); + CFArrayRef anAntecedentList; + + /* Filter out running items. */ + if (CFDictionaryGetValue(anItem, kPIDKey)) + goto next_item; + + /* + * Filter out dupilicate services; if someone has + * provided what we provide, we don't run. + */ + if (checkForDuplicates(aWaitingList, aStatusDict, anItem)) { + CF_syslog(LOG_DEBUG, CFSTR("Skipping %@ because of duplicate service."), CFDictionaryGetValue(anItem, kDescriptionKey)); + goto next_item; + } + /* + * Dependencies don't matter when restarting an item; + * stop here. + */ + if (anAction == kActionRestart) { + aNextItem = anItem; + break; + } + anAntecedentList = CFDictionaryGetValue(anItem, ((anAction == kActionStart) ? kRequiresKey : kProvidesKey)); + + CF_syslog(LOG_DEBUG, CFSTR("Checking %@"), CFDictionaryGetValue(anItem, kDescriptionKey)); + + if (anAntecedentList) + CF_syslog(LOG_DEBUG, CFSTR("Antecedents: %@"), anAntecedentList); + else + syslog(LOG_DEBUG, "No antecedents"); + + /** + * Filter out the items which have unsatisfied antecedents. + **/ + if (anAntecedentList && + ((anAction == kActionStart) ? + countUnmetRequirements(aStatusDict, anAntecedentList) : + countDependantsPresent(aWaitingList, anAntecedentList, kRequiresKey))) + goto next_item; + + /** + * anItem has all hard dependancies met; check for soft dependancies. + * We'll favor the item with the fewest unmet soft dependancies here. + **/ + { + int aFailedAntecedentsCount = 0; /* Number of unmet soft + * depenancies */ + Boolean aBestPick = FALSE; /* Is this the best pick + * so far? */ + + anAntecedentList = CFDictionaryGetValue(anItem, ((anAction == kActionStart) ? + kUsesKey : kProvidesKey)); + + if (anAntecedentList) + CF_syslog(LOG_DEBUG, CFSTR("Soft dependancies: %@"), anAntecedentList); + else + syslog(LOG_DEBUG, "No soft dependancies"); + + if (anAntecedentList) { + aFailedAntecedentsCount = + ((anAction == kActionStart) ? + countUnmetRequirements(aStatusDict, anAntecedentList) : + countDependantsPresent(aWaitingList, anAntecedentList, kUsesKey)); + } else { + if (aMinFailedAntecedents > 0) + aBestPick = TRUE; + } + + /* + * anItem has unmet dependencies that will + * likely be met in the future, so delay it + */ + if (aFailedAntecedentsCount > 0 && + pendingAntecedents(aWaitingList, aStatusDict, anAntecedentList, anAction)) { + goto next_item; + } + if (aFailedAntecedentsCount > 0) + syslog(LOG_DEBUG, "Total: %d", aFailedAntecedentsCount); + + if (aFailedAntecedentsCount > aMinFailedAntecedents) + goto next_item; /* Another item already + * won out */ + if (aFailedAntecedentsCount < aMinFailedAntecedents) + aBestPick = TRUE; + + { + Priority aPriority = priorityFromString(CFDictionaryGetValue(anItem, kPriorityKey)); + + if (aBestPick) { + /* + * anItem has less unmet + * dependancies than any + * other item so far, so it + * wins. + */ + syslog(LOG_DEBUG, "Best pick so far, based on failed dependancies (%d->%d)", + aMinFailedAntecedents, aFailedAntecedentsCount); + } else if ((anAction == kActionStart) ? + (aPriority >= aMaxPriority) : + (aPriority <= aMaxPriority)) { + /* + * anItem has a best + * priority, so it wins. + */ + syslog(LOG_DEBUG, "Best pick so far, based on Priority (%d->%d)", + aMaxPriority, aPriority); + } else + goto next_item; /* No soup for you! */ + + /* + * We have a winner! Update success + * parameters to match anItem. + */ + aMinFailedAntecedents = aFailedAntecedentsCount; + aMaxPriority = aPriority; + aNextItem = anItem; + } + + } /* End of uses section. */ + + next_item: + continue; + + } /* End of waiting list loop. */ + + } /* if (aWaitingList && aWaitingCount > 0) */ + return aNextItem; +} + +CFStringRef +StartupItemGetDescription(CFMutableDictionaryRef anItem) +{ + CFStringRef aString = NULL; + + if (anItem) + aString = CFDictionaryGetValue(anItem, kDescriptionKey); + if (aString) + CFRetain(aString); + return aString; +} + +pid_t +StartupItemGetPID(CFDictionaryRef anItem) +{ + CFIndex anItemPID = 0; + CFNumberRef aPIDNumber = anItem ? CFDictionaryGetValue(anItem, kPIDKey) : NULL; + if (aPIDNumber && CFNumberGetValue(aPIDNumber, kCFNumberCFIndexType, &anItemPID)) + return (pid_t) anItemPID; + else + return 0; +} + +CFMutableDictionaryRef +StartupItemWithPID(CFArrayRef anItemList, pid_t aPID) +{ + CFIndex anItemCount = CFArrayGetCount(anItemList); + CFIndex anItemIndex; + + for (anItemIndex = 0; anItemIndex < anItemCount; anItemIndex++) { + CFMutableDictionaryRef anItem = (CFMutableDictionaryRef) CFArrayGetValueAtIndex(anItemList, anItemIndex); + CFNumberRef aPIDNumber = CFDictionaryGetValue(anItem, kPIDKey); + CFIndex anItemPID; + + if (aPIDNumber) { + CFNumberGetValue(aPIDNumber, kCFNumberCFIndexType, &anItemPID); + + if ((pid_t) anItemPID == aPID) + return anItem; + } + } + + return NULL; +} + +int +StartupItemRun(CFMutableDictionaryRef aStatusDict, CFMutableDictionaryRef anItem, Action anAction) +{ + int anError = -1; + CFArrayRef aProvidesList = CFDictionaryGetValue(anItem, kProvidesKey); + static const CFStringRef stubitems[] = { + CFSTR("BootROMUpdater"), /* 3893064 */ + CFSTR("FCUUpdater"), /* 3893064 */ + CFSTR("AutoProtect Daemon"), /* 3965785 */ + CFSTR("Check For Missed Tasks"), /* 3965785 */ + CFSTR("Privacy"), /* 3933484 */ + CFSTR("Firmware Update Checking"), /* 4001504 */ + + CFSTR("M-Audio FireWire Audio Support"), /* 3931757 */ + CFSTR("help for M-Audio Delta Family"), /* 3931757 */ + CFSTR("help for M-Audio Devices"), /* 3931757 */ + CFSTR("help for M-Audio Revo 5.1"), /* 3931757 */ + CFSTR("M-Audio USB Duo Configuration Service"), /* 3931757 */ + CFSTR("firmware loader for M-Audio devices"), /* 3931757 */ + CFSTR("M-Audio MobilePre USB Configuration Service"), /* 3931757 */ + CFSTR("M-Audio OmniStudio USB Configuration Service"), /* 3931757 */ + CFSTR("M-Audio Transit USB Configuration Service"), /* 3931757 */ + CFSTR("M-Audio Audiophile USB Configuration Service"), /* 3931757 */ + NULL + }; + const CFStringRef *c; + + if (aProvidesList && anAction == kActionStop) { + CFIndex aProvidesCount = CFArrayGetCount(aProvidesList); + for (c = stubitems; *c; c++) { + if (CFArrayContainsValue(aProvidesList, CFRangeMake(0, aProvidesCount), *c)) { + CFIndex aPID = -1; + CFNumberRef aProcessNumber = CFNumberCreate(NULL, kCFNumberCFIndexType, &aPID); + + CFDictionarySetValue(anItem, kPIDKey, aProcessNumber); + CFRelease(aProcessNumber); + + StartupItemExit(aStatusDict, anItem, TRUE); + return -1; + } + } + } + + if (anAction == kActionNone) { + StartupItemExit(aStatusDict, anItem, TRUE); + anError = 0; + } else { + CFStringRef aBundlePathString = CFDictionaryGetValue(anItem, kBundlePathKey); + size_t aBundlePathCLength = + CFStringGetMaximumSizeForEncoding(CFStringGetLength(aBundlePathString), kCFStringEncodingUTF8) + 1; + char *aBundlePath = (char *) malloc(aBundlePathCLength); + char anExecutable[PATH_MAX] = ""; + + if (!aBundlePath) { + syslog(LOG_EMERG, "malloc() failed; out of memory while running item %s", aBundlePathString); + return (anError); + } + if (!CFStringGetCString(aBundlePathString, aBundlePath, aBundlePathCLength, kCFStringEncodingUTF8)) { + CF_syslog(LOG_EMERG, CFSTR("Internal error while running item %@"), aBundlePathString); + return (anError); + } + /* Compute path to excecutable */ + { + char *tmp; + strcpy(anExecutable, aBundlePath); /* .../foo */ + tmp = rindex(anExecutable, '/'); /* /foo */ + strncat(anExecutable, tmp, strlen(tmp)); /* .../foo/foo */ + } + + free(aBundlePath); + + /** + * Run the bundle + **/ + + if (access(anExecutable, X_OK)) { + /* + * Add PID key so that this item is marked as having + * been run. + */ + CFIndex aPID = -1; + CFNumberRef aProcessNumber = CFNumberCreate(NULL, kCFNumberCFIndexType, &aPID); + + CFDictionarySetValue(anItem, kPIDKey, aProcessNumber); + CFRelease(aProcessNumber); + + CFDictionarySetValue(anItem, kErrorKey, kErrorPermissions); + StartupItemExit(aStatusDict, anItem, FALSE); + syslog(LOG_ERR, "No executable file %s", anExecutable); + } else { + pid_t aProccessID = fork(); + + switch (aProccessID) { + case -1: /* SystemStarter (fork failed) */ + CFDictionarySetValue(anItem, kErrorKey, kErrorFork); + StartupItemExit(aStatusDict, anItem, FALSE); + + CF_syslog(LOG_ERR, CFSTR("Failed to fork for item %@: %s"), + aBundlePathString, strerror(errno)); + + break; + + default: /* SystemStarter (fork succeeded) */ + { + CFIndex aPID = (CFIndex) aProccessID; + CFNumberRef aProcessNumber = CFNumberCreate(NULL, kCFNumberCFIndexType, &aPID); + + CFDictionarySetValue(anItem, kPIDKey, aProcessNumber); + CFRelease(aProcessNumber); + + syslog(LOG_DEBUG, "Running command (%d): %s %s", + aProccessID, anExecutable, argumentForAction(anAction)); + anError = 0; + } + break; + + case 0:/* Child */ + { + setpriority(PRIO_PROCESS, 0, 0); + if (setsid() == -1) + syslog(LOG_WARNING, "Unable to create session for item %s: %m", anExecutable); + + anError = execl(anExecutable, anExecutable, argumentForAction(anAction), NULL); + + /* We shouldn't get here. */ + + syslog(LOG_ERR, "execl(\"%s\"): %m", anExecutable); + + exit(anError); + } + } + } + } + + return (anError); +} + +void +StartupItemSetStatus(CFMutableDictionaryRef aStatusDict, CFMutableDictionaryRef anItem, CFStringRef aServiceName, Boolean aSuccess, Boolean aReplaceFlag) +{ + void (*anAction) (CFMutableDictionaryRef, const void *, const void *) = aReplaceFlag ? + CFDictionarySetValue : CFDictionaryAddValue; + + if (aStatusDict && anItem) { + CFArrayRef aProvidesList = CFDictionaryGetValue(anItem, kProvidesKey); + if (aProvidesList) { + CFIndex aProvidesCount = CFArrayGetCount(aProvidesList); + CFIndex aProvidesIndex; + + /* + * If a service name was specified, and it is valid, + * use only it. + */ + if (aServiceName && CFArrayContainsValue(aProvidesList, CFRangeMake(0, aProvidesCount), aServiceName)) { + aProvidesList = CFArrayCreate(NULL, (const void **) &aServiceName, 1, &kCFTypeArrayCallBacks); + aProvidesCount = 1; + } else { + CFRetain(aProvidesList); + } + + for (aProvidesIndex = 0; aProvidesIndex < aProvidesCount; aProvidesIndex++) { + CFStringRef aService = CFArrayGetValueAtIndex(aProvidesList, aProvidesIndex); + + if (aSuccess) + anAction(aStatusDict, aService, kRunSuccess); + else + anAction(aStatusDict, aService, kRunFailure); + } + + CFRelease(aProvidesList); + } + } +} + +void +StartupItemExit(CFMutableDictionaryRef aStatusDict, CFMutableDictionaryRef anItem, Boolean aSuccess) +{ + StartupItemSetStatus(aStatusDict, anItem, NULL, aSuccess, FALSE); +} diff --git a/launchd/src/StartupItems.h b/launchd/src/StartupItems.h new file mode 100644 index 0000000..aa9f202 --- /dev/null +++ b/launchd/src/StartupItems.h @@ -0,0 +1,117 @@ +/** + * StartupItems.h - Startup Item management routines + * Wilfredo Sanchez | wsanchez@opensource.apple.com + * Kevin Van Vechten | kevinvv@uclink4.berkeley.edu + * $Apple$ + ** + * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.1 (the "License"). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + **/ + +#ifndef _StartupItems_H_ +#define _StartupItems_H_ + +#include + +#include +#include + +#include "SystemStarter.h" + +#define kProvidesKey CFSTR("Provides") +#define kRequiresKey CFSTR("Requires") +#define kDescriptionKey CFSTR("Description") +#define kUsesKey CFSTR("Uses") +#define kErrorKey CFSTR("Error") +#define kPriorityKey CFSTR("OrderPreference") +#define kBundlePathKey CFSTR("PathToBundle") +#define kPIDKey CFSTR("ProcessID") +#define kDomainKey CFSTR("Domain") + + +#define kErrorPermissions CFSTR("incorrect permissions") +#define kErrorInternal CFSTR("SystemStarter internal error") +#define kErrorReturnNonZero CFSTR("execution of Startup script failed") +#define kErrorFork CFSTR("could not fork() StartupItem") + + +/* + * Find all available startup items in NSDomains specified by aMask. + */ +CFMutableArrayRef StartupItemListCreateWithMask (NSSearchPathDomainMask aMask); + +/* + * Returns the item responsible for providing aService. + */ +CFMutableDictionaryRef StartupItemListGetProvider (CFArrayRef anItemList, CFStringRef aService); + +/* + * Creates a list of items in anItemList which depend on anItem, given anAction. + */ +CFMutableArrayRef StartupItemListCreateDependentsList (CFMutableArrayRef anItemList, + CFStringRef aService , + Action anAction ); + +/* + * Given aWaitingList of startup items, and aStatusDict describing the + * current startup state, returns the next startup item to run, if any. + * Returns nil if none is available. + * The startup order depends on the dependancies between items and the + * priorities of the items. + * Note that this is not necessarily deterministic; if more than one + * startup item with the same priority is ready to run, which item gets + * returned is not specified. + */ +CFMutableDictionaryRef StartupItemListGetNext (CFArrayRef aWaitingList, + CFDictionaryRef aStatusDict , + Action anAction ); + +CFMutableDictionaryRef StartupItemWithPID (CFArrayRef anItemList, pid_t aPID); +pid_t StartupItemGetPID(CFDictionaryRef anItem); + +CFStringRef StartupItemGetDescription(CFMutableDictionaryRef anItem); + +/* + * Returns a list of currently executing startup items. + */ +CFArrayRef StartupItemListGetRunning(CFArrayRef anItemList); + +/* + * Returns the total number of "Provides" entries of all loaded items. + */ +CFIndex StartupItemListCountServices (CFArrayRef anItemList); + + +/* + * Utility functions + */ +void RemoveItemFromWaitingList(StartupContext aStartupContext, CFMutableDictionaryRef anItem); +void AddItemToFailedList(StartupContext aStartupContext, CFMutableDictionaryRef anItem); + +/* + * Run the startup item. + */ +int StartupItemRun (CFMutableDictionaryRef aStatusDict, CFMutableDictionaryRef anItem, Action anAction); +void StartupItemExit (CFMutableDictionaryRef aStatusDict, CFMutableDictionaryRef anItem, Boolean aSuccess); +void StartupItemSetStatus(CFMutableDictionaryRef aStatusDict, CFMutableDictionaryRef anItem, CFStringRef aServiceName, Boolean aSuccess, Boolean aReplaceFlag); + +#endif /* _StartupItems_H_ */ diff --git a/launchd/src/StartupItems/Apache b/launchd/src/StartupItems/Apache new file mode 100644 index 0000000..f84e6a5 --- /dev/null +++ b/launchd/src/StartupItems/Apache @@ -0,0 +1,52 @@ +#!/bin/sh + +## +# Apache HTTP Server +## + +. /etc/rc.common + +StartService () +{ + if [ "${WEBSERVER:=-NO-}" = "-YES-" ]; then + echo "Starting Apache web server" + if [ ! -e /etc/httpd/httpd.conf ] ; then + cp -p /etc/httpd/httpd.conf.default /etc/httpd/httpd.conf + fi + apachectl start + if [ "${WEBPERFCACHESERVER:=-NO-}" = "-YES-" ]; then + if [ -x /usr/sbin/webperfcachectl ]; then + echo "Starting web performance cache server" + /usr/sbin/webperfcachectl start + fi + fi + fi +} + +StopService () +{ + if [ -x /usr/sbin/webperfcachectl ]; then + echo "Stopping web performance cache server" + /usr/sbin/webperfcachectl stop + fi + echo "Stopping Apache web server" + apachectl stop +} + +RestartService () +{ + if [ "${WEBSERVER:=-NO-}" = "-YES-" ]; then + echo "Restarting Apache web server" + apachectl restart + if [ "${WEBPERFCACHESERVER:=-NO-}" = "-YES-" ]; then + if [ -x /usr/sbin/webperfcachectl ]; then + echo "Restarting web performance cache server" + /usr/sbin/webperfcachectl restart + fi + fi + else + StopService + fi +} + +RunService "$1" diff --git a/launchd/src/StartupItems/Apache.plist b/launchd/src/StartupItems/Apache.plist new file mode 100644 index 0000000..92fe708 --- /dev/null +++ b/launchd/src/StartupItems/Apache.plist @@ -0,0 +1,5 @@ +{ + Description = "Apache web server"; + Provides = ("Web Server"); + Uses = ("Disks", "NFS"); +} diff --git a/launchd/src/StartupItems/AppServices b/launchd/src/StartupItems/AppServices new file mode 100644 index 0000000..cb7f2ca --- /dev/null +++ b/launchd/src/StartupItems/AppServices @@ -0,0 +1,27 @@ +#!/bin/sh + +## +# Application Services +## + +. /etc/rc.common + +StartService () +{ + # Launch Services + if [ -x /System/Library/Frameworks/ApplicationServices.framework/Frameworks/LaunchServices.framework/Versions/Current/Support/lsregister ]; then + /System/Library/Frameworks/ApplicationServices.framework/Frameworks/LaunchServices.framework/Versions/Current/Support/lsregister -load + fi +} + +StopService () +{ + return 0 +} + +RestartService () +{ + return 0 +} + +RunService "$1" diff --git a/launchd/src/StartupItems/AppServices.plist b/launchd/src/StartupItems/AppServices.plist new file mode 100644 index 0000000..90254aa --- /dev/null +++ b/launchd/src/StartupItems/AppServices.plist @@ -0,0 +1,4 @@ +{ + Description = "application services"; + Provides = ("Core Services"); +} diff --git a/launchd/src/StartupItems/AppleShare b/launchd/src/StartupItems/AppleShare new file mode 100644 index 0000000..7d2af69 --- /dev/null +++ b/launchd/src/StartupItems/AppleShare @@ -0,0 +1,27 @@ +#!/bin/sh + +## +# Apple File Protocol +## + +. /etc/rc.common + +StartService () +{ + if [ "${AFPSERVER:=-NO-}" = "-YES-" ]; then + echo "Starting Apple File Service" + /usr/sbin/AppleFileServer + fi +} + +StopService () +{ + return 0 +} + +RestartService () +{ + return 0 +} + +RunService "$1" diff --git a/launchd/src/StartupItems/AppleShare.plist b/launchd/src/StartupItems/AppleShare.plist new file mode 100644 index 0000000..4dda863 --- /dev/null +++ b/launchd/src/StartupItems/AppleShare.plist @@ -0,0 +1,5 @@ +{ + Description = "Apple File Service"; + Provides = ("Apple File Service"); + Requires = ("Disks"); +} diff --git a/launchd/src/StartupItems/AuthServer b/launchd/src/StartupItems/AuthServer new file mode 100644 index 0000000..58d564b --- /dev/null +++ b/launchd/src/StartupItems/AuthServer @@ -0,0 +1,31 @@ +#!/bin/sh + +## +# Authentication Server +## + +. /etc/rc.common + +StartService () +{ + if [ "${AUTHSERVER:=-NO-}" = "-YES-" ]; then + echo "Starting Authentication Server" + tim + fi +} + +StopService () +{ + if [ "${AUTHSERVER:=-NO-}" = "-YES-" ]; then + echo "Stopping Authentication Server" + fi + killall -TERM tim > /dev/null 2>&1 +} + +RestartService () +{ + StopService + StartService +} + +RunService "$1" diff --git a/launchd/src/StartupItems/AuthServer.plist b/launchd/src/StartupItems/AuthServer.plist new file mode 100644 index 0000000..f88ca20 --- /dev/null +++ b/launchd/src/StartupItems/AuthServer.plist @@ -0,0 +1,4 @@ +{ + Description = "authentication service"; + Provides = ("TIM"); +} diff --git a/launchd/src/StartupItems/Disks b/launchd/src/StartupItems/Disks new file mode 100644 index 0000000..86c00e3 --- /dev/null +++ b/launchd/src/StartupItems/Disks @@ -0,0 +1,33 @@ +#!/bin/sh + +## +# Local filesystems +## + +. /etc/rc.common + +StartService () +{ + if [ ! -f /var/db/volinfo.database ]; then Uninitialized_VSDB=-YES-; fi + + echo "Checking disks" + /sbin/autodiskmount -va + + if [ "${Uninitialized_VSDB:=-NO-}" = "-YES-" ]; then + if [ -x /usr/sbin/vsdbutil ]; then + /usr/sbin/vsdbutil -i + fi + fi +} + +StopService () +{ + return 0; +} + +RestartService () +{ + return 0; +} + +RunService "$1" diff --git a/launchd/src/StartupItems/Disks.plist b/launchd/src/StartupItems/Disks.plist new file mode 100644 index 0000000..d4046b0 --- /dev/null +++ b/launchd/src/StartupItems/Disks.plist @@ -0,0 +1,6 @@ +{ + Description = "local disks"; + Provides = ("Disks"); + Uses = ("System Tuning"); + Requires = ("SecurityServer"); +} diff --git a/launchd/src/StartupItems/IPServices b/launchd/src/StartupItems/IPServices new file mode 100644 index 0000000..bb2ae9a --- /dev/null +++ b/launchd/src/StartupItems/IPServices @@ -0,0 +1,28 @@ +#!/bin/sh + +## +# IP Services +## + +. /etc/rc.common + +StartService () +{ + if [ -a /etc/com.apple.named.conf.proxy ] + then + echo "Starting Internet address sharing" + /usr/libexec/InternetSharing + fi +} + +StopService () +{ + return 0 +} + +RestartService () +{ + return 0 +} + +RunService "$1" diff --git a/launchd/src/StartupItems/IPServices.plist b/launchd/src/StartupItems/IPServices.plist new file mode 100644 index 0000000..ffb68b0 --- /dev/null +++ b/launchd/src/StartupItems/IPServices.plist @@ -0,0 +1,5 @@ +{ + Description = "Internet services"; + Provides = ("Super Server", "Config Server"); + Uses = ("mDNSResponder", "Portmap"); +} diff --git a/launchd/src/StartupItems/NFS b/launchd/src/StartupItems/NFS new file mode 100644 index 0000000..ac16c5e --- /dev/null +++ b/launchd/src/StartupItems/NFS @@ -0,0 +1,126 @@ +#!/bin/sh + +## +# Network File System +## + +. /etc/rc.common + +AUTOMOUNTDIR=/private/var/automount + +StartService () +{ + CheckForNetwork + if [ "${NETWORKUP}" = "-NO-" ]; then exit; fi + lockfile -r 0 /var/run/NFS.StartupItem || exit 0 + + ## + # Set up NFS client. + ## + echo "Starting network file system" + + if [ -d ${AUTOMOUNTDIR} ]; then + chflags -R nouchg ${AUTOMOUNTDIR} + rm -rf ${AUTOMOUNTDIR} + fi + + # nsfiod is the NFS asynchronous block I/O daemon, which implements + # NFS read-ahead and write-behind caching on NFS clients. + nfsiod -n 4 + + ## + # The rpc.lockd/rpc.statd daemons are needed on both the client and + # the server in order to support file locking over NFS. + # + # If NFSLOCKS = -AUTOMATIC-, we start the daemons if we are a server + # but if we are only a client, we start the daemons once we know we + # need them. + ## + + ## + # gather list of NFS exports + ## + exports_ni=$(niutil -list . /exports 2> /dev/null | wc -w) + # Look for exports in /etc/exports, ignoring comments and blank lines. + exports_etc=$(grep -v '^[[:space:]]*\(#\|$\)' /etc/exports 2> /dev/null | wc -l) + exports=$(($exports_ni + $exports_etc)) + + # if we are an NFS server, turn on NFS locking by default: + if [ "${exports}" -gt 0 ]; then + if [ "${NFSLOCKS:=-AUTOMATIC-}" = "-AUTOMATIC-" ]; then + NFSLOCKS=-YES-; + fi + fi + + if [ "${NFSLOCKS:=-AUTOMATIC-}" = "-YES-" ]; then + # we definitely want locks on, so turn them on now + rpc.statd + rpc.lockd + fi + if [ "${NFSLOCKS:=-AUTOMATIC-}" = "-AUTOMATIC-" ]; then + # delay starting daemons until we know we need them + + # invoke rpc.statd to send any SM_NOTIFY messages and quit. + rpc.statd -n + + # -w says to wait for signal from kernel, then start daemons + rpc.lockd -w + fi + + ## + # Set up NFS server. + ## + + # If exportfs finds something to export (either using /etc/exports or the + # exports NetInfo directory), then start the NFS daemons (which service + # NFS requests) and the mount server (which services NFS mount requests). + + # Clear the table of exported filesystems. + rm -f /var/db/mountdtab + + if [ "${exports}" -gt 0 ]; then + echo "Starting Network File System server" + mountd + + # If the NetInfo config/nfsd directory contains startup args for nfsd, use those. + arguments=`niutil -readprop . /config/nfsd arguments` + if [ "${arguments}" = "" ]; then + arguments="-t -u -n 6" + fi + nfsd ${arguments} + fi + + ## + # Start the automounter + ## + + if [ "${AUTOMOUNT:=-YES-}" = "-YES-" ]; then + automount -m /Network -nsl -mnt ${AUTOMOUNTDIR} + ln -s /automount/Library /Network/Library + automount -m /automount/Servers -fstab -mnt /private/Network/Servers \ + -m /automount/static -static -mnt ${AUTOMOUNTDIR} + ln -s /automount/Servers /Network/Servers + + # + # Hint that the name /Network should be localized: + # + ln -s . /Network/.localized + fi + + # + # Leave a mark upon completion of the automounter startup: + # + touch /var/run/automount.initialized +} + +StopService () +{ + return 0 +} + +RestartService () +{ + return 0 +} + +RunService "$1" diff --git a/launchd/src/StartupItems/NFS.plist b/launchd/src/StartupItems/NFS.plist new file mode 100644 index 0000000..c3d949f --- /dev/null +++ b/launchd/src/StartupItems/NFS.plist @@ -0,0 +1,5 @@ +{ + Description = "network file system"; + Provides = ("NFS"); + Uses = ("Disks"); +} diff --git a/launchd/src/StartupItems/NIS b/launchd/src/StartupItems/NIS new file mode 100644 index 0000000..9eaddb9 --- /dev/null +++ b/launchd/src/StartupItems/NIS @@ -0,0 +1,79 @@ +#!/bin/sh + +## +# Network Information Service +## + +. /etc/rc.common + + +Startyppasswdd() +{ + # rpc.yppasswdd is run on NIS masters + if [ -f "${VARYP}/${NISDOMAIN}/ypservers.db" ]; then + NISMASTER=$(makedbm -U "${VARYP}/${NISDOMAIN}/ypservers" | sed -n '/YP_MASTER_NAME/p' | awk '{print $2}') + if [ "$NISMASTER" = "$(hostname)" ]; then + rpc.yppasswdd + fi + fi +} + +StartService () +{ + ## + # Network Information Service. + ## + CheckForNetwork + if [ -f /var/run/NIS.StartupItem -o "${NETWORKUP}" = "-NO-" ]; then exit; fi + touch /var/run/NIS.StartupItem + + if [ "${NISDOMAIN:=-NO-}" != "-NO-" ]; then + + VARYP=/var/yp + + echo "Starting Network Information Service" + + echo "Setting NIS domainname to ${NISDOMAIN}" + domainname "${NISDOMAIN}" + + # ypserv is run on NIS servers - machines with an ${VARYP}/${NISDOMAIN} dir + if [ -d "${VARYP}/${NISDOMAIN}" ]; then + if ! pid=$(GetPID ypserv); then + ypserv + fi + fi + + Startyppasswdd + + # ypbind is run on all NIS clients + ypbind + fi +} + +StopService () +{ + echo "Stopping Network Information Service" + killall -TERM ypbind > /dev/null 2>&1 + killall -TERM rpc.yppasswdd > /dev/null 2>&1 + + if pid=$(GetPID ypserv); then + kill -TERM "${pid}" + fi +} + +RestartService () +{ + echo "Restarting Network Information Service" + killall -TERM ypbind > /dev/null 2>&1 + killall -TERM rpc.yppasswdd > /dev/null 2>&1 + + if pid=$(GetPID ypserv); then + kill -HUP "${pid}" + Startyppasswdd + ypbind + else + StartService + fi +} + +RunService "$1" diff --git a/launchd/src/StartupItems/NIS.plist b/launchd/src/StartupItems/NIS.plist new file mode 100644 index 0000000..9c7ba6f --- /dev/null +++ b/launchd/src/StartupItems/NIS.plist @@ -0,0 +1,4 @@ +{ + Description = "Network Information Service"; + Provides = ("NIS"); +} diff --git a/launchd/src/StartupItems/NetworkTime b/launchd/src/StartupItems/NetworkTime new file mode 100644 index 0000000..b80cfd3 --- /dev/null +++ b/launchd/src/StartupItems/NetworkTime @@ -0,0 +1,42 @@ +#!/bin/sh + +## +# Network Time +## + +. /etc/rc.common + +StartService () +{ + if [ "${TIMESYNC:=-YES-}" = "-YES-" ] && + ! GetPID ntpd > /dev/null; then + + CheckForNetwork + + if [ -f /var/run/NetworkTime.StartupItem -o "${NETWORKUP}" = "-NO-" ]; then exit; fi + touch /var/run/NetworkTime.StartupItem + + + echo "Starting network time synchronization" + + # Synchronize our clock to the network's time, + # then fire off ntpd to keep the clock in sync. + ntpdate -bvs + ntpd -f /var/run/ntp.drift -p /var/run/ntpd.pid + fi +} + +StopService () +{ + if pid=$(GetPID ntpd); then + echo "Stopping network time synchronization" + kill -TERM "${pid}" + else + echo "ntpd is not running." + fi + rm -f /var/run/NetworkTime.StartupItem +} + +RestartService () { StopService; StartService; } + +RunService "$1" diff --git a/launchd/src/StartupItems/NetworkTime.plist b/launchd/src/StartupItems/NetworkTime.plist new file mode 100644 index 0000000..fb5fd19 --- /dev/null +++ b/launchd/src/StartupItems/NetworkTime.plist @@ -0,0 +1,4 @@ +{ + Description = "network time synchronization"; + Provides = ("Network Time"); +} diff --git a/launchd/src/SystemStarter.8 b/launchd/src/SystemStarter.8 new file mode 100644 index 0000000..2e13a67 --- /dev/null +++ b/launchd/src/SystemStarter.8 @@ -0,0 +1,109 @@ +.Dd April 12, 2002 +.Dt SystemStarter 8 +.Os Darwin +.Sh NAME +.Nm SystemStarter +.\" The following lines are read in generating the apropos(man -k) database. Use only key +.\" words here as the database is built based on the words here and in the .ND line. +.\" Use .Nm macro to designate other names for the documented program. +.Nd Start, stop, and restart system services +.Sh SYNOPSIS +.Nm +.Op Fl gvxdDqn +.Op Ar action Op Ar service +.Sh DESCRIPTION +The +.Nm +utility may be used to start, stop, and restart the system services which +are described in the +.Pa /Library/StartupItems/ +and +.Pa /System/Library/StartupItems/ +paths. +.Pp +The optional +.Ar action +argument specifies which action +.Nm +performs on the startup items. The optional +.Ar service +argument specifies which startup items to perform the action on. If no +.Ar service +is specified, all startup items will be acted on; otherwise, only the item providing the +.Ar service , +any items it requires, or any items that depend on it will be acted on. +.Pp +During boot +.Nm +is invoked by +.Nm rc +(see rc(8)) and is responsible for +starting all startup items in an order that satisfies each item's +requirements. +.Sh ACTIONS +.Bl -tag -width -indent +.It Nm start +start all items, or start the item that provides the specified +.Ar service +and all items providing services it requires. +.It Nm stop +stop all items, or stop the item that provides the specified +.Ar service +and all items that depend on it. +.It Nm restart +restart all items, or restart the item providing the specified +.Ar service . +.El +.Sh OPTIONS +.Bl -tag -width -indent +.It Fl g +(ignored) +.It Fl v +verbose (text mode) startup +.It Fl x +(ignored) +.It Fl r +(ignored) +.It Fl d +print debugging output +.It Fl D +print debugging output and dependencies +.It Fl q +be quiet (disable debugging output) +.It Fl n +don't actually perform action on items (no-run mode) +.El +.Sh NOTES +Unless an explicit call to +.Nm ConsoleMessage +is made, +.Nm +examines the exit status of the startup item scripts to determine the success or failure of the services provided by that script. +.Pp +In Darwin it is preferable to create custom startup items than to modify +.Nm rc , +and at some point +.Nm +may entirely encompass the role of +.Nm rc . +.Sh FILES +.Bl -tag -width -/System/Library/StartupItems -compact +.It Pa /Library/StartupItems/ +User-installed startup items. +.It Pa /System/Library/StartupItems/ +System-provided startup items. +.El +.Sh SEE ALSO +.\" List links in ascending order by section, alphabetically within a section. +.\" Please do not reference files that do not exist without filing a bug report +.Xr ConsoleMessage 8 +.Pp +.Xr rc 8 +.\" .Sh BUGS \" Document known, unremedied bugs +.Sh HISTORY +The +.Nm +utility appeared in Darwin 1.0 +.Pp +.Nm +was extended in Darwin 6.0 to support partial startup and interprocess communication. diff --git a/launchd/src/SystemStarter.c b/launchd/src/SystemStarter.c new file mode 100644 index 0000000..ccefdb2 --- /dev/null +++ b/launchd/src/SystemStarter.c @@ -0,0 +1,402 @@ +/** + * System Starter main + * Wilfredo Sanchez | wsanchez@opensource.apple.com + * $Apple$ + ** + * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.1 (the "License"). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + **/ + +#include +#include +#include +#include +#include +#include +#include "IPC.h" +#include "StartupItems.h" +#include "SystemStarter.h" +#include "SystemStarterIPC.h" + +bool gDebugFlag = false; +bool gVerboseFlag = false; +bool gNoRunFlag = false; + +static void usage(void) __attribute__((noreturn)); +static int system_starter(Action anAction, const char *aService); +static void doCFnote(void); + +int +main(int argc, char *argv[]) +{ + Action anAction = kActionStart; + char *aService = NULL; + int ch; + + while ((ch = getopt(argc, argv, "gvxirdDqn?")) != -1) { + switch (ch) { + case 'v': + gVerboseFlag = true; + break; + case 'x': + case 'g': + case 'r': + case 'q': + break; + case 'd': + case 'D': + gDebugFlag = true; + break; + case 'n': + gNoRunFlag = true; + break; + case '?': + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc > 2) + usage(); + + openlog(getprogname(), LOG_PID|LOG_CONS|(gDebugFlag ? LOG_PERROR : 0), LOG_DAEMON); + setlogmask(LOG_UPTO(LOG_NOTICE)); + if (gVerboseFlag) + setlogmask(LOG_UPTO(LOG_INFO)); + if (gDebugFlag) + setlogmask(LOG_UPTO(LOG_DEBUG)); + + if (!gNoRunFlag && (getuid() != 0)) { + syslog(LOG_ERR, "must be root to run"); + exit(EXIT_FAILURE); + } + + if (argc > 0) { + if (strcmp(argv[0], "start") == 0) { + anAction = kActionStart; + } else if (strcmp(argv[0], "stop") == 0) { + anAction = kActionStop; + } else if (strcmp(argv[0], "restart") == 0) { + anAction = kActionRestart; + } else { + usage(); + } + } + + atexit(doCFnote); + + unlink(kFixerPath); + + if (argc == 2) { + aService = argv[1]; + } else if (!gDebugFlag && anAction != kActionStop) { + pid_t ipwa; + int status; + + setpriority(PRIO_PROCESS, 0, 20); + daemon(0, 0); + + /* Too many old StartupItems had implicit dependancies on + * "Network" via other StartupItems that are now no-ops. + * + * SystemStarter is not on the critical path for boot up, + * so we'll stall here to deal with this legacy dependancy + * problem. + */ + switch ((ipwa = fork())) { + case -1: + syslog(LOG_WARNING, "fork(): %m"); + break; + case 0: + execl("/usr/sbin/ipconfig", "ipconfig", "waitall", NULL); + syslog(LOG_WARNING, "execl(): %m"); + exit(EXIT_FAILURE); + default: + if (waitpid(ipwa, &status, 0) == -1) { + syslog(LOG_WARNING, "waitpid(): %m"); + break; + } else if (WIFEXITED(status)) { + if (WEXITSTATUS(status) == 0) { + break; + } else { + syslog(LOG_WARNING, "ipconfig waitall exit status: %d", WEXITSTATUS(status)); + } + } else { + /* must have died due to signal */ + syslog(LOG_WARNING, "ipconfig waitall: %s", strsignal(WTERMSIG(status))); + } + break; + } + } + + exit(system_starter(anAction, aService)); +} + + +/** + * checkForActivity checks to see if any items have completed since the last invokation. + * If not, a message is displayed showing what item(s) are being waited on. + **/ +static void +checkForActivity(StartupContext aStartupContext) +{ + static CFIndex aLastStatusDictionaryCount = -1; + static CFStringRef aWaitingForString = NULL; + + if (aStartupContext && aStartupContext->aStatusDict) { + CFIndex aCount = CFDictionaryGetCount(aStartupContext->aStatusDict); + + if (!aWaitingForString) { + aWaitingForString = CFSTR("Waiting for %@"); + } + if (aLastStatusDictionaryCount == aCount) { + CFArrayRef aRunningList = StartupItemListGetRunning(aStartupContext->aWaitingList); + if (aRunningList && CFArrayGetCount(aRunningList) > 0) { + CFMutableDictionaryRef anItem = (CFMutableDictionaryRef) CFArrayGetValueAtIndex(aRunningList, 0); + CFStringRef anItemDescription = StartupItemGetDescription(anItem); + CFStringRef aString = aWaitingForString && anItemDescription ? + CFStringCreateWithFormat(NULL, NULL, aWaitingForString, anItemDescription) : NULL; + + if (aString) { + CF_syslog(LOG_INFO, CFSTR("%@"), aString); + CFRelease(aString); + } + if (anItemDescription) + CFRelease(anItemDescription); + } + if (aRunningList) + CFRelease(aRunningList); + } + aLastStatusDictionaryCount = aCount; + } +} + +/* + * print out any error messages to the log regarding non starting StartupItems + */ +void +displayErrorMessages(StartupContext aStartupContext) +{ + if (aStartupContext->aFailedList && CFArrayGetCount(aStartupContext->aFailedList) > 0) { + CFIndex anItemCount = CFArrayGetCount(aStartupContext->aFailedList); + CFIndex anItemIndex; + + + syslog(LOG_WARNING, "The following StartupItems failed to properly start:"); + + for (anItemIndex = 0; anItemIndex < anItemCount; anItemIndex++) { + CFMutableDictionaryRef anItem = (CFMutableDictionaryRef) CFArrayGetValueAtIndex(aStartupContext->aFailedList, anItemIndex); + CFStringRef anErrorDescription = CFDictionaryGetValue(anItem, kErrorKey); + CFStringRef anItemPath = CFDictionaryGetValue(anItem, kBundlePathKey); + + if (anItemPath) { + CF_syslog(LOG_WARNING, CFSTR("%@"), anItemPath); + } + if (anErrorDescription) { + CF_syslog(LOG_WARNING, CFSTR(" - %@"), anErrorDescription); + } else { + CF_syslog(LOG_WARNING, CFSTR(" - %@"), kErrorInternal); + } + } + } + if (CFArrayGetCount(aStartupContext->aWaitingList) > 0) { + CFIndex anItemCount = CFArrayGetCount(aStartupContext->aWaitingList); + CFIndex anItemIndex; + + syslog(LOG_WARNING, "The following StartupItems were not attempted due to failure of a required service:"); + + for (anItemIndex = 0; anItemIndex < anItemCount; anItemIndex++) { + CFMutableDictionaryRef anItem = (CFMutableDictionaryRef) CFArrayGetValueAtIndex(aStartupContext->aWaitingList, anItemIndex); + CFStringRef anItemPath = CFDictionaryGetValue(anItem, kBundlePathKey); + if (anItemPath) { + CF_syslog(LOG_WARNING, CFSTR("%@"), anItemPath); + } + } + } +} + + +static int +system_starter(Action anAction, const char *aService_cstr) +{ + CFRunLoopSourceRef anIPCSource = NULL; + CFStringRef aService = NULL; + NSSearchPathDomainMask aMask; + + if (aService_cstr) + aService = CFStringCreateWithCString(kCFAllocatorDefault, aService_cstr, kCFStringEncodingUTF8); + + StartupContext aStartupContext = (StartupContext) malloc(sizeof(struct StartupContextStorage)); + if (!aStartupContext) { + syslog(LOG_ERR, "Not enough memory to allocate startup context"); + return (1); + } + if (gDebugFlag && gNoRunFlag) + sleep(1); + + /** + * Create the IPC port + **/ + anIPCSource = CreateIPCRunLoopSource(CFSTR(kSystemStarterMessagePort), aStartupContext); + if (anIPCSource) { + CFRunLoopAddSource(CFRunLoopGetCurrent(), anIPCSource, kCFRunLoopCommonModes); + CFRelease(anIPCSource); + } else { + syslog(LOG_ERR, "Could not create IPC bootstrap port: %s", kSystemStarterMessagePort); + return (1); + } + + /** + * Get a list of Startup Items which are in /Local and /System. + * We can't search /Network yet because the network isn't up. + **/ + aMask = NSSystemDomainMask | NSLocalDomainMask; + + aStartupContext->aWaitingList = StartupItemListCreateWithMask(aMask); + aStartupContext->aFailedList = NULL; + aStartupContext->aStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + aStartupContext->aServicesCount = 0; + aStartupContext->aRunningCount = 0; + + if (aService) { + CFMutableArrayRef aDependentsList = StartupItemListCreateDependentsList(aStartupContext->aWaitingList, aService, anAction); + + if (aDependentsList) { + CFRelease(aStartupContext->aWaitingList); + aStartupContext->aWaitingList = aDependentsList; + } else { + CF_syslog(LOG_ERR, CFSTR("Unknown service: %@"), aService); + return (1); + } + } + aStartupContext->aServicesCount = StartupItemListCountServices(aStartupContext->aWaitingList); + + /** + * Do the run loop + **/ + while (1) { + CFMutableDictionaryRef anItem = StartupItemListGetNext(aStartupContext->aWaitingList, aStartupContext->aStatusDict, anAction); + + if (anItem) { + int err = StartupItemRun(aStartupContext->aStatusDict, anItem, anAction); + if (!err) { + ++aStartupContext->aRunningCount; + MonitorStartupItem(aStartupContext, anItem); + } else { + /* add item to failed list */ + AddItemToFailedList(aStartupContext, anItem); + + /* Remove the item from the waiting list. */ + RemoveItemFromWaitingList(aStartupContext, anItem); + } + } else { + /* + * If no item was selected to run, and if no items + * are running, startup is done. + */ + if (aStartupContext->aRunningCount == 0) { + syslog(LOG_DEBUG, "none left"); + break; + } + /* + * Process incoming IPC messages and item + * terminations + */ + switch (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 3.0, true)) { + case kCFRunLoopRunTimedOut: + checkForActivity(aStartupContext); + break; + case kCFRunLoopRunFinished: + break; + case kCFRunLoopRunStopped: + break; + case kCFRunLoopRunHandledSource: + break; + default: + /* unknown return value */ + break; + } + } + } + + /** + * Good-bye. + **/ + displayErrorMessages(aStartupContext); + + /* clean up */ + if (aStartupContext->aStatusDict) + CFRelease(aStartupContext->aStatusDict); + if (aStartupContext->aWaitingList) + CFRelease(aStartupContext->aWaitingList); + if (aStartupContext->aFailedList) + CFRelease(aStartupContext->aFailedList); + + free(aStartupContext); + return (0); +} + +void +CF_syslog(int level, CFStringRef message,...) +{ + char buf[8192]; + CFStringRef cooked_msg; + va_list ap; + + va_start(ap, message); + cooked_msg = CFStringCreateWithFormatAndArguments(NULL, NULL, message, ap); + va_end(ap); + + if (CFStringGetCString(cooked_msg, buf, sizeof(buf), kCFStringEncodingUTF8)) + syslog(level, buf); + + CFRelease(cooked_msg); +} + +static void +usage(void) +{ + fprintf(stderr, "usage: %s [-vdqn?] [ [ ] ]\n" + "\t: action to take (start|stop|restart); default is start\n" + "\t : name of item to act on; default is all items\n" + "options:\n" + "\t-v: verbose startup\n" + "\t-d: print debugging output\n" + "\t-q: be quiet (disable debugging output)\n" + "\t-n: don't actually perform action on items (pretend mode)\n" + "\t-?: show this help\n", + getprogname()); + exit(EXIT_FAILURE); +} + +static void doCFnote(void) +{ + CFNotificationCenterPostNotificationWithOptions( + CFNotificationCenterGetDistributedCenter(), + CFSTR("com.apple.startupitems.completed"), + NULL, NULL, + kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions); +} diff --git a/launchd/src/SystemStarter.h b/launchd/src/SystemStarter.h new file mode 100644 index 0000000..37fb4d5 --- /dev/null +++ b/launchd/src/SystemStarter.h @@ -0,0 +1,55 @@ +/** + * SystemStarter.h - System Starter driver + * Wilfredo Sanchez | wsanchez@opensource.apple.com + * $Apple$ + ** + * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.1 (the "License"). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + **/ + +#ifndef _SYSTEM_STARTER_H_ +#define _SYSTEM_STARTER_H_ + +/* Structure to pass common objects from system_starter to the IPC handlers */ +typedef struct StartupContextStorage { + CFMutableArrayRef aWaitingList; + CFMutableArrayRef aFailedList; + CFMutableDictionaryRef aStatusDict; + int aServicesCount; + int aRunningCount; +} *StartupContext; + +#define kFixerDir "/var/db/fixer" +#define kFixerPath "/var/db/fixer/StartupItems" + +/* Action types */ +typedef enum { + kActionNone = 0, + kActionStart, + kActionStop, + kActionRestart +} Action; + +void CF_syslog(int level, CFStringRef message, ...); +extern bool gVerboseFlag; + +#endif /* _SYSTEM_STARTER_H_ */ diff --git a/launchd/src/SystemStarterIPC.h b/launchd/src/SystemStarterIPC.h new file mode 100644 index 0000000..d031f1b --- /dev/null +++ b/launchd/src/SystemStarterIPC.h @@ -0,0 +1,92 @@ +/** + * SystemStarterIPC.h - System Starter IPC definitions + * Wilfredo Sanchez | wsanchez@opensource.apple.com + * Kevin Van Vechten | kevinvv@uclink4.berkeley.edu + ** + * Copyright (c) 1999-2001 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.1 (the "License"). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + ** + * Definitions used for IPC communications with SystemStarter. + * SystemStarter listens on a CFMessagePort with the name defined by + * kSystemStarterMessagePort. The messageID of each message should + * be set to the kIPCProtocolVersion constant. The contents of each + * message should be an XML plist containing a dictionary using + * the keys defined in this file. + **/ + +#ifndef _SYSTEM_STARTER_IPC_H +#define _SYSTEM_STARTER_IPC_H + +#include +#include + +/* Compatible with inline CFMessagePort messages. */ +typedef struct SystemStarterIPCMessage { + mach_msg_header_t aHeader; + mach_msg_body_t aBody; + SInt32 aProtocol; + SInt32 aByteLength; + /* Data follows. */ +} SystemStarterIPCMessage; + +/* Name of the CFMessagePort SystemStarter listens on. */ +#define kSystemStarterMessagePort "com.apple.SystemStarter" + +/* kIPCProtocolVersion should be passed as the messageID of the CFMessage. */ +#define kIPCProtocolVersion 0 + +/* kIPCTypeKey should be provided for all messages. */ +#define kIPCMessageKey CFSTR("Message") + +/* Messages are one of the following types: */ +#define kIPCConsoleMessage CFSTR("ConsoleMessage") +#define kIPCStatusMessage CFSTR("StatusMessage") +#define kIPCQueryMessage CFSTR("QueryMessage") +#define kIPCLoadDisplayBundleMessage CFSTR("LoadDisplayBundle") +#define kIPCUnloadDisplayBundleMessage CFSTR("UnloadDisplayBundle") + +/* kIPCServiceNameKey identifies a startup item by one of the services it provides. */ +#define kIPCServiceNameKey CFSTR("ServiceName") + +/* kIPCProcessIDKey identifies a running startup item by its process id. */ +#define kIPCProcessIDKey CFSTR("ProcessID") + +/* kIPCConsoleMessageKey contains the non-localized string to + * display for messages of type kIPCTypeConsoleMessage. + */ +#define kIPCConsoleMessageKey CFSTR("ConsoleMessage") + +/* kIPCStatus key contains a boolean value. True for success, false for failure. */ +#define kIPCStatusKey CFSTR("StatusKey") + +/* kIPCDisplayBundlePathKey contains a string path to the display bundle + SystemStarter should attempt to load. */ +#define kIPCDisplayBundlePathKey CFSTR("DisplayBundlePath") + +/* kIPCConfigNamegKey contains the name of a config setting to query */ +#define kIPCConfigSettingKey CFSTR("ConfigSetting") + +/* Some config settings */ +#define kIPCConfigSettingVerboseFlag CFSTR("VerboseFlag") +#define kIPCConfigSettingNetworkUp CFSTR("NetworkUp") + +#endif /* _SYSTEM_STARTER_IPC_H */ diff --git a/launchd/src/bootstrap.c b/launchd/src/bootstrap.c new file mode 100644 index 0000000..e309a31 --- /dev/null +++ b/launchd/src/bootstrap.c @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * bootstrap -- fundamental service initiator and port server + * Mike DeMoney, NeXT, Inc. + * Copyright, 1990. All rights reserved. + * + * bootstrap.c -- implementation of bootstrap main service loop + */ + +/* + * Imports + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bootstrap.h" +#include "bootstrap_internal.h" +#include "lists.h" +#include "launchd.h" + +/* Mig should produce a declaration for this, but doesn't */ +extern boolean_t bootstrap_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP); + +auditinfo_t inherited_audit; +mach_port_t inherited_bootstrap_port = MACH_PORT_NULL; +bool forward_ok = false; +bool debugging = false; +bool register_self = false; +const char *register_name = NULL; +task_t bootstrap_self = MACH_PORT_NULL; + +static uid_t inherited_uid = 0; +static bool shutdown_in_progress = false; + +#ifndef ASSERT +#define ASSERT(p) +#endif + +/* + * Private macros + */ +#define NELEM(x) (sizeof(x)/sizeof(x[0])) +#define END_OF(x) (&(x)[NELEM(x)]) +#define streq(a,b) (strcmp(a,b) == 0) + +/* + * Private declarations + */ +static void init_ports(void); +static void start_server(server_t *serverp); +static void exec_server(server_t *serverp); +static char **argvize(const char *string); +static void *demand_loop(void *arg); +void *mach_server_loop(void *); +extern kern_return_t bootstrap_register +( + mach_port_t bootstrapport, + name_t servicename, + mach_port_t serviceport +); + +/* + * Private ports we hold receive rights for. We also hold receive rights + * for all the privileged ports. Those are maintained in the server + * structs. + */ +mach_port_t bootstrap_port_set; +mach_port_t demand_port_set; +pthread_t demand_thread; + +mach_port_t notify_port; +mach_port_t backup_port; + + +static mach_msg_return_t +inform_server_loop( + mach_port_name_t about, + mach_msg_option_t options) +{ + mach_port_destroyed_notification_t not; + mach_msg_size_t size = sizeof(not) - sizeof(not.trailer); + + not.not_header.msgh_id = DEMAND_REQUEST; + not.not_header.msgh_remote_port = backup_port; + not.not_header.msgh_local_port = MACH_PORT_NULL; + not.not_header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); + not.not_header.msgh_size = size; + not.not_body.msgh_descriptor_count = 1; + not.not_port.type = MACH_MSG_PORT_DESCRIPTOR; + not.not_port.disposition = MACH_MSG_TYPE_PORT_NAME; + not.not_port.name = about; + return mach_msg(¬.not_header, MACH_SEND_MSG|options, size, + 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); +} + +static void +notify_server_loop(mach_port_name_t about) +{ + mach_msg_return_t result; + + result = inform_server_loop(about, MACH_MSG_OPTION_NONE); + if (result != MACH_MSG_SUCCESS) + syslog(LOG_ERR, "notify_server_loop: mach_msg(): %s", mach_error_string(result)); +} + +void mach_start_shutdown(__unused int signalnum) +{ + shutdown_in_progress = TRUE; + (void) inform_server_loop(MACH_PORT_NULL, MACH_SEND_TIMEOUT); +} + +mach_port_t mach_init_init(void) +{ + kern_return_t result; + pthread_attr_t attr; + + bootstrap_self = mach_task_self(); + inherited_uid = getuid(); + getaudit(&inherited_audit); + init_lists(); + init_ports(); + + result = task_get_bootstrap_port(bootstrap_self, &inherited_bootstrap_port); + if (result != KERN_SUCCESS) { + syslog(LOG_ALERT, "task_get_bootstrap_port(): %s", mach_error_string(result)); + exit(EXIT_FAILURE); + } + if (inherited_bootstrap_port == MACH_PORT_NULL) + forward_ok = FALSE; + + /* We set this explicitly as we start each child */ + task_set_bootstrap_port(bootstrap_self, MACH_PORT_NULL); + + /* register "self" port with anscestor */ + if (register_self && forward_ok) { + result = bootstrap_register(inherited_bootstrap_port, + (char *)register_name, + bootstraps.bootstrap_port); + if (result != KERN_SUCCESS) + panic("register self(): %s", mach_error_string(result)); + } + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + result = pthread_create(&demand_thread, &attr, demand_loop, NULL); + if (result) + panic("pthread_create(): %s", strerror(result)); + pthread_attr_destroy(&attr); + + return bootstraps.bootstrap_port; +} + +static void +init_ports(void) +{ + kern_return_t result; + + /* + * This task will become the bootstrap task. + */ + /* Create port set that server loop listens to */ + result = mach_port_allocate( + bootstrap_self, + MACH_PORT_RIGHT_PORT_SET, + &bootstrap_port_set); + if (result != KERN_SUCCESS) + panic("port_set_allocate(): %s", mach_error_string(result)); + + /* Create demand port set that second thread listens to */ + result = mach_port_allocate( + bootstrap_self, + MACH_PORT_RIGHT_PORT_SET, + &demand_port_set); + if (result != KERN_SUCCESS) + panic("port_set_allocate(): %s", mach_error_string(result)); + + /* Create notify port and add to server port set */ + result = mach_port_allocate( + bootstrap_self, + MACH_PORT_RIGHT_RECEIVE, + ¬ify_port); + if (result != KERN_SUCCESS) + panic("mach_port_allocate(): %s", mach_error_string(result)); + + result = mach_port_move_member( + bootstrap_self, + notify_port, + bootstrap_port_set); + if (result != KERN_SUCCESS) + panic("mach_port_move_member(): %s", mach_error_string(result)); + + /* Create backup port and add to server port set */ + result = mach_port_allocate( + bootstrap_self, + MACH_PORT_RIGHT_RECEIVE, + &backup_port); + if (result != KERN_SUCCESS) + panic("mach_port_allocate(): %s", mach_error_string(result)); + + result = mach_port_move_member( + bootstrap_self, + backup_port, + bootstrap_port_set); + if (result != KERN_SUCCESS) + panic("mach_port_move_member(): %s", mach_error_string(result)); + + /* Create "self" port and add to server port set */ + result = mach_port_allocate( + bootstrap_self, + MACH_PORT_RIGHT_RECEIVE, + &bootstraps.bootstrap_port); + if (result != KERN_SUCCESS) + panic("mach_port_allocate(): %s", mach_error_string(result)); + result = mach_port_insert_right( + bootstrap_self, + bootstraps.bootstrap_port, + bootstraps.bootstrap_port, + MACH_MSG_TYPE_MAKE_SEND); + if (result != KERN_SUCCESS) + panic("mach_port_insert_right(): %s", mach_error_string(result)); + + /* keep the root bootstrap port "active" */ + bootstraps.requestor_port = bootstraps.bootstrap_port; + + result = mach_port_move_member( + bootstrap_self, + bootstraps.bootstrap_port, + bootstrap_port_set); + if (result != KERN_SUCCESS) + panic("mach_port_move_member(): %s", mach_error_string(result)); +} + +boolean_t +active_bootstrap(bootstrap_info_t *bootstrap) +{ + return (bootstrap->requestor_port != MACH_PORT_NULL); +} + +boolean_t +useless_server(server_t *serverp) +{ + return ( !active_bootstrap(serverp->bootstrap) || + !lookup_service_by_server(serverp) || + !serverp->activity); +} + +boolean_t +active_server(server_t *serverp) +{ + return ( serverp->port || + serverp->task_port || serverp->active_services); +} + +static void +reap_server(server_t *serverp) +{ + kern_return_t result; + pid_t presult; + int wstatus; + + /* + * Reap our children. + */ + presult = waitpid(serverp->pid, &wstatus, WNOHANG); + switch (presult) { + case -1: + syslog(LOG_DEBUG, "waitpid: cmd = %s: %m", serverp->cmd); + break; + + case 0: + { + /* process must have switched mach tasks */ + mach_port_t old_port; + + old_port = serverp->task_port; + mach_port_deallocate(mach_task_self(), old_port); + serverp->task_port = MACH_PORT_NULL; + + result = task_for_pid( mach_task_self(), + serverp->pid, + &serverp->task_port); + if (result != KERN_SUCCESS) { + syslog(LOG_INFO, "race getting new server task port for pid[%d]: %s", + serverp->pid, mach_error_string(result)); + break; + } + + /* Request dead name notification to tell when new task dies */ + result = mach_port_request_notification( + mach_task_self(), + serverp->task_port, + MACH_NOTIFY_DEAD_NAME, + 0, + notify_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + &old_port); + if (result != KERN_SUCCESS) { + syslog(LOG_INFO, "race setting up notification for new server task port for pid[%d]: %s", + serverp->pid, mach_error_string(result)); + break; + } + return; + } + + default: + if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus)) { + syslog(LOG_NOTICE, "Server %x in bootstrap %x uid %d: \"%s\"[%d]: exited with status: %d", + serverp->port, serverp->bootstrap->bootstrap_port, + serverp->uid, serverp->cmd, serverp->pid, WEXITSTATUS(wstatus)); + } else if (WIFSIGNALED(wstatus)) { + syslog(LOG_NOTICE, "Server %x in bootstrap %x uid %d: \"%s\"[%d]: exited abnormally: %s", + serverp->port, serverp->bootstrap->bootstrap_port, + serverp->uid, serverp->cmd, serverp->pid, strsignal(WTERMSIG(wstatus))); + } + break; + } + + + serverp->pid = 0; + + /* + * Release the server task port reference, if we ever + * got it in the first place. + */ + if (serverp->task_port != MACH_PORT_NULL) { + result = mach_port_deallocate( + mach_task_self(), + serverp->task_port); + if (result != KERN_SUCCESS) + syslog(LOG_ERR, "mach_port_deallocate(): %s", mach_error_string(result)); + serverp->task_port = MACH_PORT_NULL; + } +} + +static void +demand_server(server_t *serverp) +{ + service_t *servicep; + kern_return_t result; + + /* + * For on-demand servers, make sure that the service ports are + * back in on-demand portset. Active service ports should come + * back through a PORT_DESTROYED notification. We only have to + * worry about the inactive ports that may have been previously + * pulled from the set but never checked-in by the server. + */ + + for ( servicep = FIRST(services) + ; !IS_END(servicep, services) + ; servicep = NEXT(servicep)) + { + if (serverp == servicep->server && !servicep->isActive) { + result = mach_port_move_member( + mach_task_self(), + servicep->port, + demand_port_set); + if (result != KERN_SUCCESS) + panic("mach_port_move_member(): %s", mach_error_string(result)); + } + } +} + +static +void dispatch_server(server_t *serverp) +{ + if (!active_server(serverp)) { + if (useless_server(serverp) || shutdown_in_progress) + delete_server(serverp); + else if (serverp->servertype == RESTARTABLE) + start_server(serverp); + else if (serverp->servertype == DEMAND) + demand_server(serverp); + } +} + +void +setup_server(server_t *serverp) +{ + kern_return_t result; + mach_port_t old_port; + + /* Allocate privileged port for requests from service */ + result = mach_port_allocate(mach_task_self(), + MACH_PORT_RIGHT_RECEIVE , + &serverp->port); + syslog(LOG_INFO, "Allocating port %x for server %s", serverp->port, serverp->cmd); + if (result != KERN_SUCCESS) + panic("port_allocate(): %s", mach_error_string(result)); + + /* Request no-senders notification so we can tell when server dies */ + result = mach_port_request_notification(mach_task_self(), + serverp->port, + MACH_NOTIFY_NO_SENDERS, + 1, + serverp->port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + &old_port); + if (result != KERN_SUCCESS) + panic("mach_port_request_notification(): %s", mach_error_string(result)); + + /* Add privileged server port to bootstrap port set */ + result = mach_port_move_member(mach_task_self(), + serverp->port, + bootstrap_port_set); + if (result != KERN_SUCCESS) + panic("mach_port_move_member(): %s", mach_error_string(result)); +} + +pid_t +fork_with_bootstrap_port(mach_port_t p) +{ + static pthread_mutex_t forklock = PTHREAD_MUTEX_INITIALIZER; + kern_return_t result; + pid_t r; + size_t i; + + pthread_mutex_lock(&forklock); + + sigprocmask(SIG_BLOCK, &blocked_signals, NULL); + + result = task_set_bootstrap_port(mach_task_self(), p); + if (result != KERN_SUCCESS) + panic("task_set_bootstrap_port(): %s", mach_error_string(result)); + + if (launchd_bootstrap_port != p) { + result = mach_port_deallocate(mach_task_self(), p); + if (result != KERN_SUCCESS) + panic("mach_port_deallocate(): %s", mach_error_string(result)); + } + + r = fork(); + + if (r > 0) { + /* Post Tiger: + * + * We should set the bootstrap back to MACH_PORT_NULL instead + * of launchd_bootstrap_port. This will expose rare latent race + * condition bugs, given that some programs assume that the PID + * 1's bootstrap port is constant. This function clearly + * demonstrates that is no longer true. + * + * Those programs should be calling bootstrap_parent(), and not + * task_for_pid(1) followed by a call to get the bootstrap port + * on the task. + */ + result = task_set_bootstrap_port(mach_task_self(), launchd_bootstrap_port); + if (result != KERN_SUCCESS) + panic("task_set_bootstrap_port(): %s", mach_error_string(result)); + } else { + for (i = 0; i <= NSIG; i++) { + if (sigismember(&blocked_signals, i)) + signal(i, SIG_DFL); + } + } + + sigprocmask(SIG_UNBLOCK, &blocked_signals, NULL); + + pthread_mutex_unlock(&forklock); + + return r; +} + +static void +start_server(server_t *serverp) +{ + kern_return_t result; + mach_port_t old_port; + int pid; + + /* + * Do what's appropriate to get bootstrap port setup in server task + */ + switch (serverp->servertype) { + + case MACHINIT: + break; + + case SERVER: + case DEMAND: + case RESTARTABLE: + if (!serverp->port) + setup_server(serverp); + + serverp->activity = 0; + + /* Insert a send right */ + result = mach_port_insert_right(mach_task_self(), + serverp->port, + serverp->port, + MACH_MSG_TYPE_MAKE_SEND); + if (result != KERN_SUCCESS) + panic("mach_port_insert_right(): %s", mach_error_string(result)); + + pid = fork_with_bootstrap_port(serverp->port); + if (pid < 0) { + syslog(LOG_WARNING, "fork(): %m"); + } else if (pid == 0) { /* CHILD */ + exec_server(serverp); + exit(EXIT_FAILURE); + } else { /* PARENT */ + syslog(LOG_INFO, "Launched server %x in bootstrap %x uid %d: \"%s\": [pid %d]", + serverp->port, serverp->bootstrap->bootstrap_port, + serverp->uid, serverp->cmd, pid); + serverp->pid = pid; + result = task_for_pid( + mach_task_self(), + pid, + &serverp->task_port); + if (result != KERN_SUCCESS) { + syslog(LOG_ERR, "getting server task port(): %s", mach_error_string(result)); + reap_server(serverp); + dispatch_server(serverp); + break; + } + + /* Request dead name notification to tell when task dies */ + result = mach_port_request_notification( + mach_task_self(), + serverp->task_port, + MACH_NOTIFY_DEAD_NAME, + 0, + notify_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + &old_port); + if (result != KERN_SUCCESS) { + syslog(LOG_ERR, "mach_port_request_notification(): %s", mach_error_string(result)); + reap_server(serverp); + dispatch_server(serverp); + } + } + break; + } +} + +static void +exec_server(server_t *serverp) +{ + char **argv; + sigset_t mask; + + /* + * Setup environment for server, someday this should be Mach stuff + * rather than Unix crud + */ + argv = argvize(serverp->cmd); + closelog(); + + /* + * Set up the audit state for the user (if necessesary). + */ + if (inherited_uid == 0 && + (serverp->auinfo.ai_auid != inherited_uid || + serverp->auinfo.ai_asid != inherited_audit.ai_asid)) { + struct passwd *pwd = NULL; + + pwd = getpwuid(serverp->auinfo.ai_auid); + if (pwd == NULL) { + panic("Disabled server %x bootstrap %x: \"%s\": getpwuid(%d) failed", + serverp->port, serverp->bootstrap->bootstrap_port, + serverp->cmd, serverp->auinfo.ai_auid); + + } else if (au_user_mask(pwd->pw_name, &serverp->auinfo.ai_mask) != 0) { + panic("Disabled server %x bootstrap %x: \"%s\": au_user_mask(%s) failed", + serverp->port, serverp->bootstrap->bootstrap_port, + serverp->cmd, pwd->pw_name); + } else if (setaudit(&serverp->auinfo) != 0) + panic("Disabled server %x bootstrap %x: \"%s\": setaudit()", + serverp->port, serverp->bootstrap->bootstrap_port, + serverp->cmd); + } + + if (serverp->uid != inherited_uid) + if (setuid(serverp->uid) < 0) + panic("Disabled server %x bootstrap %x: \"%s\": setuid(%d): %s", + serverp->port, serverp->bootstrap->bootstrap_port, + serverp->cmd, serverp->uid, strerror(errno)); + + if (setsid() < 0) { + /* + * We can't keep this from happening, but we shouldn't start + * the server not as a process group leader. So, just fake like + * there was real activity, and exit the child. If needed, + * we'll re-launch it under another pid. + */ + serverp->activity = 1; + panic("Temporary failure server %x bootstrap %x: \"%s\": setsid(): %s", + serverp->port, serverp->bootstrap->bootstrap_port, + serverp->cmd, strerror(errno)); + } + + sigemptyset(&mask); + (void) sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL); + + setpriority(PRIO_PROCESS, 0, 0); + execv(argv[0], argv); + panic("Disabled server %x bootstrap %x: \"%s\": exec(): %s", + serverp->port, + serverp->bootstrap->bootstrap_port, + serverp->cmd, + strerror(errno)); +} + +static char ** +argvize(const char *string) +{ + static char *argv[100], args[1000]; + const char *cp; + char *argp, term; + unsigned int nargs; + + /* + * Convert a command line into an argv for execv + */ + nargs = 0; + argp = args; + + for (cp = string; *cp;) { + while (isspace(*cp)) + cp++; + term = (*cp == '"') ? *cp++ : '\0'; + if (nargs < NELEM(argv)) + argv[nargs++] = argp; + while (*cp && (term ? *cp != term : !isspace(*cp)) + && argp < END_OF(args)) { + if (*cp == '\\') + cp++; + *argp++ = *cp; + if (*cp) + cp++; + } + *argp++ = '\0'; + } + argv[nargs] = NULL; + return argv; +} + +static void * +demand_loop(void *arg __attribute__((unused))) +{ + mach_msg_empty_rcv_t dummy; + kern_return_t dresult; + + + for(;;) { + mach_port_name_array_t members; + mach_msg_type_number_t membersCnt; + mach_port_status_t status; + mach_msg_type_number_t statusCnt; + unsigned int i; + + /* + * Receive indication of message on demand service + * ports without actually receiving the message (we'll + * let the actual server do that. + */ + dresult = mach_msg( + &dummy.header, + MACH_RCV_MSG|MACH_RCV_LARGE, + 0, + 0, + demand_port_set, + 0, + MACH_PORT_NULL); + if (dresult != MACH_RCV_TOO_LARGE) { + syslog(LOG_ERR, "demand_loop: mach_msg(): %s", mach_error_string(dresult)); + continue; + } + + /* + * Some port(s) now have messages on them, find out + * which ones (there is no indication of which port + * triggered in the MACH_RCV_TOO_LARGE indication). + */ + dresult = mach_port_get_set_status( + mach_task_self(), + demand_port_set, + &members, + &membersCnt); + if (dresult != KERN_SUCCESS) { + syslog(LOG_ERR, "demand_loop: mach_port_get_set_status(): %s", mach_error_string(dresult)); + continue; + } + + for (i = 0; i < membersCnt; i++) { + statusCnt = MACH_PORT_RECEIVE_STATUS_COUNT; + dresult = mach_port_get_attributes( + mach_task_self(), + members[i], + MACH_PORT_RECEIVE_STATUS, + (mach_port_info_t)&status, + &statusCnt); + if (dresult != KERN_SUCCESS) { + syslog(LOG_ERR, "demand_loop: mach_port_get_attributes(): %s", mach_error_string(dresult)); + continue; + } + + /* + * For each port with messages, take it out of the + * demand service portset, and inform the main thread + * that it might have to start the server responsible + * for it. + */ + if (status.mps_msgcount) { + dresult = mach_port_move_member( + mach_task_self(), + members[i], + MACH_PORT_NULL); + if (dresult != KERN_SUCCESS) { + syslog(LOG_ERR, "demand_loop: mach_port_move_member(): %s", mach_error_string(dresult)); + continue; + } + notify_server_loop(members[i]); + } + } + + dresult = vm_deallocate( + mach_task_self(), + (vm_address_t) members, + (vm_size_t) membersCnt * sizeof(mach_port_name_t)); + if (dresult != KERN_SUCCESS) { + syslog(LOG_ERR, "demand_loop: vm_deallocate(): %s", mach_error_string(dresult)); + continue; + } + } + return NULL; +} + +/* + * server_demux -- processes requests off our service port + * Also handles notifications + */ + +static boolean_t +server_demux( + mach_msg_header_t *Request, + mach_msg_header_t *Reply) +{ + bootstrap_info_t *bootstrap; + service_t *servicep; + server_t *serverp; + kern_return_t result; + mig_reply_error_t *reply; + + syslog(LOG_DEBUG, "received message on port %x", Request->msgh_local_port); + + reply = (mig_reply_error_t *)Reply; + + /* + * Pick off notification messages + */ + if (Request->msgh_local_port == notify_port) { + mach_port_name_t np; + + memset(reply, 0, sizeof(*reply)); + switch (Request->msgh_id) { + case MACH_NOTIFY_DEAD_NAME: + np = ((mach_dead_name_notification_t *)Request)->not_port; + syslog(LOG_DEBUG, "Notified dead name %x", np); + + if (np == inherited_bootstrap_port) { + inherited_bootstrap_port = MACH_PORT_NULL; + forward_ok = FALSE; + } + + /* + * Check to see if a subset requestor port was deleted. + */ + while ((bootstrap = lookup_bootstrap_by_req_port(np)) != NULL) { + syslog(LOG_DEBUG, "Received dead name notification for bootstrap subset %x requestor port %x", + bootstrap->bootstrap_port, bootstrap->requestor_port); + mach_port_deallocate( + mach_task_self(), + bootstrap->requestor_port); + bootstrap->requestor_port = MACH_PORT_NULL; + deactivate_bootstrap(bootstrap); + } + + /* + * Check to see if a defined service has gone + * away. + */ + while ((servicep = lookup_service_by_port(np)) != NULL) { + /* + * Port gone, registered service died. + */ + syslog(LOG_DEBUG, "Received dead name notification for service %s " + "on bootstrap port %x\n", + servicep->name, servicep->bootstrap); + syslog(LOG_DEBUG, "Service %s failed - deallocate", servicep->name); + delete_service(servicep); + } + + /* + * Check to see if a launched server task has gone + * away. + */ + if ((serverp = lookup_server_by_task_port(np)) != NULL) { + /* + * Port gone, server died or picked up new task. + */ + syslog(LOG_DEBUG, "Received task death notification for server %s ", + serverp->cmd); + reap_server(serverp); + dispatch_server(serverp); + } + + mach_port_deallocate(mach_task_self(), np); + reply->RetCode = KERN_SUCCESS; + break; + + case MACH_NOTIFY_PORT_DELETED: + np = ((mach_port_deleted_notification_t *)Request)->not_port; + syslog(LOG_DEBUG, "port deleted notification on 0x%x", np); + reply->RetCode = KERN_SUCCESS; + break; + + case MACH_NOTIFY_SEND_ONCE: + syslog(LOG_DEBUG, "notification send-once right went unused"); + reply->RetCode = KERN_SUCCESS; + break; + + default: + syslog(LOG_ERR, "Unexpected notification: %d", Request->msgh_id); + reply->RetCode = KERN_FAILURE; + break; + } + } + + else if (Request->msgh_local_port == backup_port) { + mach_port_name_t np; + + memset(reply, 0, sizeof(*reply)); + + np = ((mach_port_destroyed_notification_t *)Request)->not_port.name; + servicep = lookup_service_by_port(np); + if (servicep != NULL) { + serverp = servicep->server; + + switch (Request->msgh_id) { + + case MACH_NOTIFY_PORT_DESTROYED: + /* + * Port sent back to us, server died. + */ + syslog(LOG_DEBUG, "Received destroyed notification for service %s", + servicep->name); + syslog(LOG_DEBUG, "Service %x bootstrap %x backed up: %s", + servicep->port, servicep->bootstrap->bootstrap_port, + servicep->name); + ASSERT(canReceive(servicep->port)); + servicep->isActive = FALSE; + serverp->active_services--; + dispatch_server(serverp); + reply->RetCode = KERN_SUCCESS; + break; + + case DEMAND_REQUEST: + /* message reflected over from demand start thread */ + if (!active_server(serverp)) + start_server(serverp); + reply->RetCode = KERN_SUCCESS; + break; + + default: + syslog(LOG_DEBUG, "Mysterious backup_port notification %d", Request->msgh_id); + reply->RetCode = KERN_FAILURE; + break; + } + } else { + syslog(LOG_DEBUG, "Backup_port notification - previously deleted service"); + reply->RetCode = KERN_FAILURE; + } + } + + else if (Request->msgh_id == MACH_NOTIFY_NO_SENDERS) { + mach_port_t ns = Request->msgh_local_port; + + if ((serverp = lookup_server_by_port(ns)) != NULL_SERVER) { + /* + * A server we launched has released his bootstrap + * port send right. We won't re-launch him unless + * his services came back to roost. But we need to + * destroy the bootstrap port for fear of leaking. + */ + syslog(LOG_DEBUG, "server %s dropped server port", serverp->cmd); + serverp->port = MACH_PORT_NULL; + dispatch_server(serverp); + } else if ((bootstrap = lookup_bootstrap_by_port(ns)) != NULL) { + /* + * The last direct user of a deactivated bootstrap went away. + * We can finally free it. + */ + syslog(LOG_DEBUG, "Deallocating bootstrap %x: no more clients", ns); + bootstrap->bootstrap_port = MACH_PORT_NULL; + deallocate_bootstrap(bootstrap); + } + + result = mach_port_mod_refs( + mach_task_self(), + ns, + MACH_PORT_RIGHT_RECEIVE, + -1); + if (result != KERN_SUCCESS) + panic("mach_port_mod_refs(): %s", mach_error_string(result)); + + memset(reply, 0, sizeof(*reply)); + reply->RetCode = KERN_SUCCESS; + } + + else { /* must be a service request */ + syslog(LOG_DEBUG, "Handled request."); + return bootstrap_server(Request, Reply); + } + return TRUE; +} + +/* + * server_loop -- pick requests off our service port and process them + * Also handles notifications + */ +#define bootstrapMaxRequestSize 1024 +#define bootstrapMaxReplySize 1024 + +void * +mach_server_loop(void *arg __attribute__((unused))) +{ + mach_msg_return_t mresult; + + for (;;) { + mresult = mach_msg_server( + server_demux, + bootstrapMaxRequestSize, + bootstrap_port_set, + MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)| + MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)); + if (mresult != MACH_MSG_SUCCESS) + syslog(LOG_ERR, "mach_msg_server(): %s", mach_error_string(mresult)); + } + return NULL; +} + +bool +canReceive(mach_port_t port) +{ + mach_port_type_t p_type; + kern_return_t result; + + result = mach_port_type(mach_task_self(), port, &p_type); + if (result != KERN_SUCCESS) { + syslog(LOG_ERR, "port_type(): %s", mach_error_string(result)); + return FALSE; + } + return ((p_type & MACH_PORT_TYPE_RECEIVE) != 0); +} + + +bool +canSend(mach_port_t port) +{ + mach_port_type_t p_type; + kern_return_t result; + + result = mach_port_type(mach_task_self(), port, &p_type); + if (result != KERN_SUCCESS) { + syslog(LOG_ERR, "port_type(): %s", mach_error_string(result)); + return FALSE; + } + return ((p_type & MACH_PORT_TYPE_PORT_RIGHTS) != 0); +} diff --git a/launchd/src/bootstrap.defs b/launchd/src/bootstrap.defs new file mode 100644 index 0000000..cc7f9e8 --- /dev/null +++ b/launchd/src/bootstrap.defs @@ -0,0 +1,360 @@ +/* + * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * bootstrap -- fundamental service initiator and port server + * Mike DeMoney, NeXT, Inc. + * Copyright, 1990. All rights reserved. + * + * bootstrap.defs -- Mig interface definition + */ + +subsystem bootstrap 400; + +/* + * Interface: Bootstrap server + * + * The bootstrap server is the first user-mode task initiated by the Mach + * kernel at system boot time. The bootstrap server provides two services, + * it initiates other system tasks, and manages a table of name-port bindings + * for fundamental system services (e.g. lookupd, Window Manager, etc...). + * + * Name-port bindings can be established with the bootstrap server by either + * of two mechanisms: + * + * 1. The binding can be indicated, in advance of the service that backs it + * being available, via a "service create" request. In this case, bootstrap + * will immediately create a port and bind the indicated name with that port. + * At a later time, a service may "checkin" for the name-port + * binding and will be returned receive rights for the bound port. Lookup's + * on bindings created by this mechanism will return send rights to the port, + * even if no service has "checked-in". In this case, requests sent to the + * bound port will be queued until a server has checked-in and can satisfy the + * request. + * + * 2. Bindings can be established dynamically via a "register" request. In + * this case, the register request provides bootstrap with a name and send + * rights for a port. Bootstrap will provide send rights for the bound port + * to any requestor via the lookup request. + * + * Bootstrap provides its service port to descendant tasks via the Mach + * "bootstrap" special task port. All direct descendants of bootstrap receive + * a "privileged" bootstrap service port. System services that initiate + * untrusted tasks should replace the Mach bootstrap task special port with + * a subset bootstrap port to prevent them from infecting the namespace. + * + * The bootstrap server creates a "backup" port for each service that it + * creates. This is used to detect when a checked out service is no longer + * being served. The bootstrap server regains all rights to the port and + * it is marked available for check-out again. This allows crashed servers to + * resume service to previous clients. Lookup's on this named port will + * continue to be serviced by bootstrap while holding receive rights for the + * bound port. A client may detect that the service is inactive via the + * bootstrap status request. If an inactive service re-registers rather + * than "checking-in" the original bound port is destroyed. + * + * The status of a named service may be obtained via the "status" request. + * A service is "active" if a name-port binding exists and receive rights + * to the bound port are held by a task other than bootstrap. + * + * The bootstrap server may also (re)start server processes associated with + * with a set of services. The definition of the server process is done + * through the "create server" request. The server will be launched in the + * same bootstrap context in which it was registered. + */ + +#include +#include +import ; + +type cmd_t = c_string[512]; +type name_t = c_string[128]; +type cmd_array_t = ^array [] of cmd_t; +type name_array_t = ^array [] of name_t; +type bootstrap_status_t = integer_t; +type bootstrap_status_array_t = ^array [] of bootstrap_status_t; + +serverprefix x_; + +/* + * kern_return_t + * bootstrap_create_server(mach_port_t __bs_port, + * cmd_t __server_command, + * natural_t __server_uid, + * boolean_t __on_demand, + * mach_port_t *__server_port) + * + * Declares a server that mach_init will re-spawn within the specified + * bootstrap context. The server is considered already "active" + * (i.e. will not be re-spawned) until the returned server_port is + * deallocated. + * + * In the meantime, services can be declared against the server, + * by using the server_port as the privileged bootstrap target of + * subsequent bootstrap_create_service() calls. + * + * When mach_init re-spawns the server, its task bootstrap port + * is set to the privileged sever_port. Through this special + * bootstrap port, it can access all of parent bootstrap's context + * (and all services are created in the parent's namespace). But + * all additional service declarations (and declaration removals) + * will be associated with this particular server. + * + * Only a holder of the server_port privilege bootstrap port can + * check in or register over those services. + * + * When all services associated with a server are deleted, and the server + * exits, it will automatically be deleted itself. + * + * If the server is declared "on_demand," then a non-running server + * will be re-launched on first use of one of the service ports + * registered against it. Otherwise, it will be re-launched + * immediately upon exiting (whether any client is actively using + * any of the service ports or not). + * + * Errors: Returns appropriate kernel errors on rpc failure. + * Returns BOOTSTRAP_NOT_PRIVILEGED, bootstrap or uid invalid. + */ +routine bootstrap_create_server( + __bs_port : mach_port_t; + __server_cmd : cmd_t; + __server_uid : natural_t; + __on_demand : boolean_t; + ServerAuditToken token : audit_token_t; + out __server_port : mach_port_make_send_t); + +/* + * kern_return_t + * bootstrap_unprivileged(mach_port_t __bs_port, + * mach_port_t *__unpriv_port) + * + * Given a bootstrap port, return its unprivileged equivalent. If + * the port is already unprivileged, another reference to the same + * port is returned. + * + * This is most often used by servers, which are launched with their + * bootstrap port set to the privileged port for the server, to get + * an unprivileged version of the same port for use by its unprivileged + * children (or any offspring that it does not want to count as part + * of the "server" for mach_init registration and re-launch purposes). + */ +routine bootstrap_unprivileged( + __bs_port : mach_port_t; + out __unpriv_port : mach_port_t); + +/* + * kern_return_t + * bootstrap_check_in(mach_port_t __bs_port, + * name_t __service_name, + * mach_port_t *__service_port) + * + * Returns the receive right for the service named by service_name. The + * service must have previously been declared in this bootstrap context via + * a call to bootstrap_create_service(). Attempts to check_in a service + * which is already active are not allowed. + * + * If the service was declared as being associated with a server, the + * check_in must come from the server's privileged port (server_port). + * + * Errors: Returns appropriate kernel errors on rpc failure. + * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist. + * Returns BOOTSTRAP_NOT_PRIVILEGED, if request directed to + * bootstrap port without privilege. + * Returns BOOTSTRAP_SERVICE_ACTIVE, if service has already been + * registered or checked-in. + */ +routine bootstrap_check_in( + __bs_port : mach_port_t; + __service_name : name_t; + out __service_port : mach_port_move_receive_t); + +/* + * kern_return_t + * bootstrap_register(mach_port_t __bs_port, + * name_t __service_name, + * mach_port_t __service_port) + * + * Registers a send right for service_port with the service identified by + * service_name. Attempts to register a service where an active binding + * already exists are rejected. + * + * If the service was previously declared with bootstrap_create_service(), + * but is not currently active, this call can be used to undeclare the + * service. The bootstrap port used must have sufficient privilege to + * do so. (Registering MACH_PORT_NULL is especially useful for shutting + * down declared services). + * + * Errors: Returns appropriate kernel errors on rpc failure. + * Returns BOOTSTRAP_NOT_PRIVILEGED, if request directed to + * bootstrap port without privilege. + * Returns BOOTSTRAP_NAME_IN_USE, if service has already been + * register or checked-in. + */ +routine bootstrap_register( + __bs_port : mach_port_t; + __service_name : name_t; + __service_port : mach_port_t); + +/* + * kern_return_t + * bootstrap_look_up(mach_port_t __bs_port, + * name_t __service_name, + * mach_port_t *__service_port) + * + * Returns a send right for the service port declared/registered under the + * name service_name. The service is not guaranteed to be active. Use the + * bootstrap_status call to determine the status of the service. + * + * Errors: Returns appropriate kernel errors on rpc failure. + * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist. + */ +routine bootstrap_look_up( + __bs_port : mach_port_t; + __service_name : name_t; + out __service_port : mach_port_t); + +/* + * kern_return_t + * bootstrap_look_up_array(mach_port_t __bs_port, + * name_array_t __service_names, + * int __service_names_cnt, + * port_array_t *__service_port, + * int *__service_ports_cnt, + * boolean_t *__all_services_known) + * + * Returns port send rights in corresponding entries of the array service_ports + * for all services named in the array service_names. Service_ports_cnt is + * returned and will always equal service_names_cnt (assuming service_names_cnt + * is greater than or equal to zero). + * + * Errors: Returns appropriate kernel errors on rpc failure. + * Returns BOOTSTRAP_NO_MEMORY, if server couldn't obtain memory + * for response. + * Unknown service names have the corresponding service port set + * to PORT_NULL. + * If all services are known, all_services_known is true on + * return, if any service is unknown, it's false. + */ +routine bootstrap_look_up_array( + __bs_port : mach_port_t; + __service_names : name_array_t; + out __service_ports : mach_port_array_t; + out __all_services_known: boolean_t); + +/* + * kern_return_t + * bootstrap_parent(mach_port_t __bs_port, + * mach_port_t *__parent_port); + * + * Given a bootstrap subset port, return the parent bootstrap port. + * If the specified bootstrap port is already the root subset, + * MACH_PORT_NULL will be returned. + * + * Errors: + * Returns BOOTSTRAP_NOT_PRIVILEGED if the caller is not running + * with an effective user id of root (as determined by the security + * token in the message trailer). + */ +routine bootstrap_parent( + __bs_port : mach_port_t; + ServerSecToken __token : security_token_t; + out __parent_port : mach_port_make_send_t); + +/* + * kern_return_t + * bootstrap_status(mach_port_t __bs_port, + * name_t __service_name, + * bootstrap_status_t *__service_active); + * + * Returns: service_active indicates if service is active, inactive, or + * associated with a launch-on-demand server. + * + * Errors: Returns appropriate kernel errors on rpc failure. + * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist. + */ +routine bootstrap_status( + __bs_port : mach_port_t; + __service_name : name_t; + out __service_active: bootstrap_status_t); + +/* + * kern_return_t + * bootstrap_info(port_t __bs_port, + * name_array_t *__service_names, + * int *__service_names_cnt, + * name_array_t *__server_names, + * int *__server_names_cnt, + * bool_array_t *__service_active, + * int *__service_active_cnt); + * + * Errors: Returns appropriate kernel errors on rpc failure. + */ +routine bootstrap_info( + __bs_port : mach_port_t; + out __service_names : name_array_t, dealloc; + out __server_names : name_array_t, dealloc; + out __service_active : bootstrap_status_array_t, dealloc); + +/* + * kern_return_t + * bootstrap_subset(mach_port_t __bs_port, + * mach_port_t __requestor_port, + * mach_port_t *__subset_port); + * + * Returns a new port to use as a bootstrap port. This port behaves + * exactly like the previous bootstrap_port, except that ports dynamically + * registered via bootstrap_register() are available only to users of this + * specific subset_port. Lookups on the subset_port will return ports + * registered with this port specifically, and ports registered with + * ancestors of this subset_port. Duplications of services already + * registered with an ancestor port may be registered with the subset port + * are allowed. Services already advertised may then be effectively removed + * by registering PORT_NULL for the service. + * When it is detected that the requestor_port is destroyed the subset + * port and all services advertized by it are destroied as well. + * + * Errors: Returns appropriate kernel errors on rpc failure. + */ +routine bootstrap_subset( + __bs_port : mach_port_t; + __requestor_port: mach_port_t; + out __subset_port : mach_port_t); + +/* + * kern_return_t + * bootstrap_create_service(mach_port_t __bs_port, + * name_t __service_name, + * mach_port_t *__service_port) + * + * Creates a service named "service_name" and returns send rights to that + * port in "service_port." The port may later be checked in as if this + * port were configured in the bootstrap configuration file. + * + * Errors: Returns appropriate kernel errors on rpc failure. + * Returns BOOTSTRAP_SERVICE_ACTIVE, if service already exists. + */ +routine bootstrap_create_service( + __bs_port : mach_port_t; + __service_name : name_t; + out __service_port : mach_port_t); + diff --git a/launchd/src/bootstrap_internal.h b/launchd/src/bootstrap_internal.h new file mode 100644 index 0000000..b2f4808 --- /dev/null +++ b/launchd/src/bootstrap_internal.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * bootstrap -- fundamental service initiator and port server + * Mike DeMoney, NeXT, Inc. + * Copyright, 1990. All rights reserved. + * + * bootstrap_internal.h -- global internal data definitions + */ + +#include +#include +#include +#include + +#define BASEPRI_USER 31 /* AOF 20/02/2002 */ + +#define ANYWHERE TRUE /* For use with vm_allocate() */ + +#define DEMAND_REQUEST MACH_NOTIFY_LAST /* demand service messaged */ + +__private_extern__ void mach_start_shutdown(int); +__private_extern__ mach_port_t mach_init_init(void); +__private_extern__ void *mach_server_loop(void*); +__private_extern__ pid_t fork_with_bootstrap_port(mach_port_t); + +__private_extern__ mach_port_t lookup_only_port; +__private_extern__ mach_port_t inherited_bootstrap_port; +__private_extern__ mach_port_t self_port; /* Compatability hack */ +__private_extern__ bool forward_ok; +__private_extern__ bool debugging; +__private_extern__ mach_port_t bootstrap_port_set; +__private_extern__ mach_port_t demand_port_set; +__private_extern__ mach_port_t notify_port; +__private_extern__ mach_port_t backup_port; +__private_extern__ bool canReceive(mach_port_t); +__private_extern__ bool canSend(mach_port_t); +__private_extern__ bool register_self; +__private_extern__ const char *register_name; diff --git a/launchd/src/config.h.in b/launchd/src/config.h.in new file mode 100644 index 0000000..a71db1a --- /dev/null +++ b/launchd/src/config.h.in @@ -0,0 +1,163 @@ +/* src/config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if the `closedir' function returns void instead of `int'. */ +#undef CLOSEDIR_VOID + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_DIRENT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `fork' function. */ +#undef HAVE_FORK + +/* Define to 1 if you have the `getpagesize' function. */ +#undef HAVE_GETPAGESIZE + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MACH_MACH_H + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#undef HAVE_MALLOC + +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the `munmap' function. */ +#undef HAVE_MUNMAP + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +#undef HAVE_NDIR_H + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +#undef HAVE_STAT_EMPTY_STRING_BUG + +/* Define to 1 if stdbool.h conforms to C99. */ +#undef HAVE_STDBOOL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_DIR_H + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_NDIR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vfork' function. */ +#undef HAVE_VFORK + +/* Define to 1 if you have the header file. */ +#undef HAVE_VFORK_H + +/* Define to 1 if `fork' works. */ +#undef HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#undef HAVE_WORKING_VFORK + +/* Define to 1 if the system has the type `_Bool'. */ +#undef HAVE__BOOL + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#undef LSTAT_FOLLOWS_SLASHED_SYMLINK + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `int' if doesn't define. */ +#undef gid_t + +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to `int' if does not define. */ +#undef mode_t + +/* Define to `long' if does not define. */ +#undef off_t + +/* Define to `int' if does not define. */ +#undef pid_t + +/* Define to `unsigned' if does not define. */ +#undef size_t + +/* Define to `int' if doesn't define. */ +#undef uid_t + +/* Define as `fork' if `vfork' does not work. */ +#undef vfork diff --git a/launchd/src/hostconfig b/launchd/src/hostconfig new file mode 100644 index 0000000..0f7fac0 --- /dev/null +++ b/launchd/src/hostconfig @@ -0,0 +1,12 @@ +AFPSERVER=-NO- +AUTHSERVER=-NO- +AUTOMOUNT=-YES- +CUPS=-AUTOMATIC- +NFSLOCKS=-AUTOMATIC- +NISDOMAIN=-NO- +TIMESYNC=-NO- +QTSSERVER=-NO- +WEBSERVER=-NO- +SMBSERVER=-NO- +SNMPSERVER=-NO- +SPOTLIGHT=-YES- diff --git a/launchd/src/init.8 b/launchd/src/init.8 new file mode 100644 index 0000000..8db766d --- /dev/null +++ b/launchd/src/init.8 @@ -0,0 +1,295 @@ +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Donn Seeley at Berkeley Software Design, Inc. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)init.8 8.6 (Berkeley) 5/26/95 +.\" +.Dd May 26, 1995 +.Dt INIT 8 +.Os BSD 4 +.Sh NAME +.Nm init +.Nd process control initialization +.Sh SYNOPSIS +.Nm init +.Sh DESCRIPTION +The +.Nm init +program +is the last stage of the boot process. +It normally runs the automatic reboot sequence as described in +.Xr reboot 8 , +and if this succeeds, begins multi-user operation. +If the reboot scripts fail, +.Nm init +commences single user operation by giving +the super-user a shell on the console. +The +.Nm init +program may be passed parameters +from the boot program to +prevent the system from going multi-user and to instead execute +a single user shell without starting the normal daemons. +The system is then quiescent for maintenance work and may +later be made to go to multi-user by exiting the +single-user shell (with ^D). +This +causes +.Nm init +to run the +.Pa /etc/rc +start up command file in fastboot mode (skipping disk checks). +.Pp +If the +.Nm console +entry in the +.Xr ttys 5 +file is marked ``insecure'', +then +.Nm init +will require that the superuser password be +entered before the system will start a single-user shell. +The password check is skipped if the +.Nm console +is marked as ``secure''. +.Pp +The kernel runs with four different levels of security. +Any superuser process can raise the security level, but only +.Nm init +can lower it. +Security levels are defined as follows: +.Bl -tag -width flag +.It Ic -1 +Permanently insecure mode \- always run system in level 0 mode. +.It Ic 0 +Insecure mode \- immutable and append-only flags may be turned off. +All devices may be read or written subject to their permissions. +.It Ic 1 +Secure mode \- immutable and append-only flags may not be changed; +disks for mounted filesystems, +.Pa /dev/mem , +and +.Pa /dev/kmem +are read-only. +The +.Xr settimeofday 2 +system call can only advance the time. +.It Ic 2 +Highly secure mode \- same as secure mode, plus disks are always +read-only whether mounted or not. +This level precludes tampering with filesystems by unmounting them, +but also inhibits running +.Xr newfs 8 +while the system is multi-user. +.El +.Pp +Normally, the system runs in level 0 mode while single user +and in level 1 mode while multiuser. +If the level 2 mode is desired while running multiuser, +it can be set in the startup script +.Pa /etc/rc +using +.Xr sysctl 8 . +If it is desired to run the system in level 0 mode while multiuser, +the administrator must build a kernel with the variable +.Nm securelevel +defined in the file +.Pa /sys/compile/MACHINE/param.c +and initialize it to -1. +.Pp +In multi-user operation, +.Nm init +maintains +processes for the terminal ports found in the file +.Xr ttys 5 . +.Nm Init +reads this file, and executes the command found in the second field. +This command is usually +.Xr getty 8 ; +.Xr getty +opens and initializes the tty line +and +executes the +.Xr login +program. +The +.Xr login +program, when a valid user logs in, +executes a shell for that user. When this shell +dies, either because the user logged out +or an abnormal termination occurred (a signal), +the +.Nm init +program wakes up, deletes the user +from the +.Xr utmp 5 +file of current users and records the logout in the +.Xr wtmp +file. +The cycle is +then restarted by +.Nm init +executing a new +.Xr getty +for the line. +.pl +1 +.Pp +Line status (on, off, secure, getty, or window information) +may be changed in the +.Xr ttys +file without a reboot by sending the signal +.Dv SIGHUP +to +.Nm init +with the command +.Dq Li "kill \-s HUP 1" . +On receipt of this signal, +.Nm init +re-reads the +.Xr ttys +file. +When a line is turned off in +.Xr ttys , +.Nm init +will send a SIGHUP signal to the controlling process +for the session associated with the line. +For any lines that were previously turned off in the +.Xr ttys +file and are now on, +.Nm init +executes a new +.Xr getty +to enable a new login. +If the getty or window field for a line is changed, +the change takes effect at the end of the current +login session (e.g., the next time +.Nm init +starts a process on the line). +If a line is commented out or deleted from +.Xr ttys , +.Nm init +will not do anything at all to that line. +However, it will complain that the relationship between lines +in the +.Xr ttys +file and records in the +.Xr utmp +file is out of sync, +so this practice is not recommended. +.Pp +.Nm Init +will terminate multi-user operations and resume single-user mode +if sent a terminate +.Pq Dv TERM +signal, for example, +.Dq Li "kill \-s TERM 1" . +If there are processes outstanding that are deadlocked (because of +hardware or software failure), +.Xr init +will not wait for them all to die (which might take forever), but +will time out after 30 seconds and print a warning message. +.Pp +.Nm Init +will cease creating new +.Xr getty Ns 's +and allow the system to slowly die away, if it is sent a terminal stop +.Pq Dv TSTP +signal, i.e. +.Dq Li "kill \-s TSTP 1" . +A later hangup will resume full +multi-user operations, or a terminate will start a single user shell. +This hook is used by +.Xr reboot 8 +and +.Xr halt 8 . +.Pp +The role of +.Nm init +is so critical that if it dies, the system will reboot itself +automatically. +If, at bootstrap time, the +.Xr init +process cannot be located, the system will panic with the message +``panic: "init died (signal %d, exit %d)''. +.Sh DIAGNOSTICS +.Bl -diag +.It "getty repeating too quickly on port %s, sleeping" +A process being started to service a line is exiting quickly +each time it is started. +This is often caused by a ringing or noisy terminal line. +.Em "Init will sleep for 10 seconds" , +.Em "then continue trying to start the process" . +.Pp +.It "some processes would not die; ps axl advised." +A process +is hung and could not be killed when the system was shutting down. +This condition is usually caused by a process +that is stuck in a device driver because of +a persistent device error condition. +.El +.Sh FILES +.Bl -tag -width /var/log/wtmp -compact +.It Pa /dev/console +System console device. +.It Pa /dev/tty* +Terminal ports found in +.Xr ttys . +.It Pa /var/run/utmp +Record of Current users on the system. +.It Pa /var/log/wtmp +Record of all logins and logouts. +.It Pa /etc/ttys +The terminal initialization information file. +.It Pa /etc/rc +System startup commands. +.El +.Sh SEE ALSO +.Xr login 1 , +.Xr kill 1 , +.Xr sh 1 , +.Xr ttys 5 , +.Xr crash 8 , +.Xr getty 8 , +.Xr rc 8 , +.Xr reboot 8 , +.Xr halt 8 , +.Xr shutdown 8 +.Sh HISTORY +A +.Nm +command appeared in +.At v6 . +.Sh BUGS +Systems without +.Xr sysctl +behave as though they have security level \-1. diff --git a/launchd/src/init.c b/launchd/src/init.c new file mode 100644 index 0000000..05abab3 --- /dev/null +++ b/launchd/src/init.c @@ -0,0 +1,860 @@ +/* + * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Donn Seeley at Berkeley Software Design, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "launchd.h" +#include "bootstrap_internal.h" + +#define _PATH_RUNCOM "/etc/rc" + +/* + * Sleep times; used to prevent thrashing. + */ +#define GETTY_SPACING 5 /* N secs minimum getty spacing */ +#define GETTY_SLEEP 30 /* sleep N secs after spacing problem */ +#define STALL_TIMEOUT 30 /* wait N secs after warning */ +#define DEATH_WATCH 10 /* wait N secs for procs to die */ +#define FAILED_HW_PASS 5 /* wait N secs before croaking user */ + +static void stall(char *, ...); + +static void single_user_callback(void *, struct kevent *); +static kq_callback kqsingle_user_callback = single_user_callback; +static void runcom_callback(void *, struct kevent *); +static kq_callback kqruncom_callback = runcom_callback; + +static void single_user(void); +static void runcom(void); + +static bool runcom_verbose = false; +static bool runcom_safe = false; +static bool runcom_fsck = true; +static bool runcom_netboot = false; +static bool single_user_mode = false; +static bool run_runcom = true; +static pid_t single_user_pid = 0; +static pid_t runcom_pid = 0; + +static void setctty(const char *, int); + +// gvdl@next.com 14 Aug 1995 +// - from ~apps/loginwindow_proj/loginwindow/common.h +#define REALLY_EXIT_TO_CONSOLE 229 + +// From old init.c +// These flags are used in the se_flags field of the init_session structure +#define SE_SHUTDOWN 0x1 /* session won't be restarted */ + +// The flags below control what sort of getty is launched. +#define SE_GETTY_LAUNCH 0x30 /* What type of getty to launch */ +#define SE_COMMON 0x00 /* Usual command that is run - getty */ +#define SE_ONERROR 0x10 /* Command to run if error condition occurs. + * This will almost always be the windowserver + * and loginwindow. This is so if the w.s. + * ever dies, that the naive user (stan) + * doesn't ever see the console window. */ +#define SE_ONOPTION 0x20 /* Command to run when loginwindow exits with + * special error code (229). This signifies + * that the user typed "console" at l.w. and + * l.w. wants to exit and have init run getty + * which will then put up a console window. */ + +typedef struct _se_command { + char *path; /* what to run on that port */ + char **argv; /* pre-parsed argument array */ +} se_cmd_t; + +typedef struct init_session { + kq_callback se_callback; /* run loop callback */ + int se_index; /* index of entry in ttys file */ + pid_t se_process; /* controlling process */ + time_t se_started; /* used to avoid thrashing */ + int se_flags; /* status of session */ + char *se_device; /* filename of port */ + se_cmd_t se_getty; /* what to run on that port */ + se_cmd_t se_onerror; /* See SE_ONERROR above */ + se_cmd_t se_onoption; /* See SE_ONOPTION above */ + TAILQ_ENTRY(init_session) tqe; +} *session_t; + +static TAILQ_HEAD(sessionshead, init_session) sessions = TAILQ_HEAD_INITIALIZER(sessions); + +static void session_new(int, struct ttyent *); +static void session_free(session_t); +static void session_launch(session_t); +static void session_reap(session_t); +static void session_callback(void *, struct kevent *); + +static char **construct_argv(char *); +static void setsecuritylevel(int); +static int getsecuritylevel(void); +static int setupargv(session_t, struct ttyent *); + +void +init_boot(bool sflag, bool vflag, bool xflag) +{ + int nbmib[2] = { CTL_KERN, KERN_NETBOOT }; + uint64_t nb = 0; + size_t nbsz = sizeof(nb); + + if (sflag) { + single_user_mode = true; + run_runcom = false; + } + if (vflag) + runcom_verbose = true; + if (xflag) + runcom_safe = true; + + if (sysctl(nbmib, 2, &nb, &nbsz, NULL, 0) == 0) { + /* The following assignment of nb to itself if the size of data + * returned is 32 bits instead of 64 is a clever C trick to + * move the 32 bits on big endian systems to the least + * significant bytes of the 64 mem variable. + * + * On little endian systems, this is effectively a no-op. + */ + if (nbsz == 4) + nb = *(uint32_t *)&nb; + if (nb != 0) + runcom_netboot = true; + } else { + syslog(LOG_WARNING, "sysctl(\"kern.netboot\") %m"); + } + +} + +void +init_pre_kevent(void) +{ + session_t s; + + if (single_user_mode && single_user_pid == 0) + single_user(); + + if (run_runcom) + runcom(); + + if (!single_user_mode && !run_runcom && runcom_pid == 0) { + /* + * If the administrator has not set the security level to -1 + * to indicate that the kernel should not run multiuser in secure + * mode, and the run script has not set a higher level of security + * than level 1, then put the kernel into secure mode. + */ + if (getsecuritylevel() == 0) + setsecuritylevel(1); + + TAILQ_FOREACH(s, &sessions, tqe) { + if (s->se_process == 0) + session_launch(s); + } + } +} + +static void +stall(char *message, ...) +{ + va_list ap; + va_start(ap, message); + + vsyslog(LOG_ALERT, message, ap); + va_end(ap); + sleep(STALL_TIMEOUT); +} + +static int +getsecuritylevel(void) +{ + int name[2], curlevel; + size_t len; + + name[0] = CTL_KERN; + name[1] = KERN_SECURELVL; + len = sizeof (curlevel); + if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) { + syslog(LOG_ALERT, "cannot get kernel security level: %m"); + return -1; + } + return curlevel; +} + +static void +setsecuritylevel(int newlevel) +{ + int name[2], curlevel; + + curlevel = getsecuritylevel(); + if (newlevel == curlevel) + return; + name[0] = CTL_KERN; + name[1] = KERN_SECURELVL; + if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) { + syslog(LOG_ALERT, "cannot change kernel security level from %d to %d: %m", + curlevel, newlevel); + return; + } + syslog(LOG_INFO, "kernel security level changed from %d to %d", + curlevel, newlevel); +} + +/* + * Start a session and allocate a controlling terminal. + * Only called by children of init after forking. + */ +static void +setctty(const char *name, int flags) +{ + int fd; + + revoke(name); + if ((fd = open(name, flags | O_RDWR)) == -1) { + stall("can't open %s: %m", name); + exit(EXIT_FAILURE); + } + if (login_tty(fd) == -1) { + stall("can't get %s for controlling terminal: %m", name); + exit(EXIT_FAILURE); + } +} + +static void +single_user(void) +{ + char *argv[2]; + + if (getsecuritylevel() > 0) + setsecuritylevel(0); + + if ((single_user_pid = fork_with_bootstrap_port(launchd_bootstrap_port)) == -1) { + syslog(LOG_ERR, "can't fork single-user shell, trying again: %m"); + return; + } else if (single_user_pid == 0) { + setctty(_PATH_CONSOLE, O_POPUP); + + setenv("TERM", "vt100", 1); + setenv("SafeBoot", runcom_safe ? "-x" : "", 1); + setenv("VerboseFlag", "-v", 1); /* single user mode implies verbose mode */ + setenv("FsckSlash", runcom_fsck ? "-F" : "", 1); + setenv("NetBoot", runcom_netboot ? "-N" : "", 1); + + if (runcom_fsck) { + fprintf(stdout, "Singleuser boot -- fsck not done\n"); + fprintf(stdout, "Root device is mounted read-only\n\n"); + fprintf(stdout, "If you want to make modifications to files:\n"); + fprintf(stdout, "\t/sbin/fsck -fy\n\t/sbin/mount -uw /\n\n"); + fprintf(stdout, "If you wish to boot the system, but stay in single user mode:\n"); + fprintf(stdout, "\tsh /etc/rc\n"); + fflush(stdout); + } + + argv[0] = "-sh"; + argv[1] = NULL; + setpriority(PRIO_PROCESS, 0, 0); + execv(_PATH_BSHELL, argv); + syslog(LOG_ERR, "can't exec %s for single user: %m", _PATH_BSHELL); + sleep(STALL_TIMEOUT); + exit(EXIT_FAILURE); + } else { + runcom_fsck = false; + if (kevent_mod(single_user_pid, EVFILT_PROC, EV_ADD, + NOTE_EXIT, 0, &kqsingle_user_callback) == -1) + single_user_callback(NULL, NULL); + } +} + +static void +single_user_callback(void *obj __attribute__((unused)), struct kevent *kev __attribute__((unused))) +{ + int status, r = single_user_pid; + +#ifdef PID1_REAP_ADOPTED_CHILDREN + status = pid1_child_exit_status; +#else + r = waitpid(single_user_pid, &status, 0); +#endif + + if (r != single_user_pid) { + if (r == -1) + syslog(LOG_ERR, "single_user_callback(): waitpid(): %m"); + if (r == 0) + syslog(LOG_ERR, "single_user_callback(): waitpid() returned 0"); + return; + } + + if (WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS) { + syslog(LOG_INFO, "single user shell terminated, restarting"); + run_runcom = true; + single_user_mode = false; + } else { + syslog(LOG_INFO, "single user shell terminated."); + run_runcom = false; + if (WTERMSIG(status) != SIGKILL) + single_user_mode = true; + } + + single_user_pid = 0; +} + +static struct timeval runcom_start_tv = { 0, 0 }; +/* + * Run the system startup script. + */ +static void +runcom(void) +{ + char *argv[3]; + struct termios term; + int vdisable; + + gettimeofday(&runcom_start_tv, NULL); + + if ((runcom_pid = fork_with_bootstrap_port(launchd_bootstrap_port)) == -1) { + syslog(LOG_ERR, "can't fork for %s on %s: %m", _PATH_BSHELL, _PATH_RUNCOM); + sleep(STALL_TIMEOUT); + runcom_pid = 0; + single_user_mode = true; + return; + } else if (runcom_pid > 0) { + run_runcom = false; + runcom_fsck = false; + if (kevent_mod(runcom_pid, EVFILT_PROC, EV_ADD, + NOTE_EXIT, 0, &kqruncom_callback) == -1) { + runcom_callback(NULL, NULL); + } + return; + } + + setctty(_PATH_CONSOLE, 0); + + if ((vdisable = fpathconf(STDIN_FILENO, _PC_VDISABLE)) == -1) { + syslog(LOG_WARNING, "fpathconf(\"%s\") %m", _PATH_CONSOLE); + } else if (tcgetattr(STDIN_FILENO, &term) == -1) { + syslog(LOG_WARNING, "tcgetattr(\"%s\") %m", _PATH_CONSOLE); + } else { + term.c_cc[VINTR] = vdisable; + term.c_cc[VKILL] = vdisable; + term.c_cc[VQUIT] = vdisable; + term.c_cc[VSUSP] = vdisable; + term.c_cc[VSTART] = vdisable; + term.c_cc[VSTOP] = vdisable; + term.c_cc[VDSUSP] = vdisable; + + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term) == -1) + syslog(LOG_WARNING, "tcsetattr(\"%s\") %m", _PATH_CONSOLE); + } + + argv[0] = "sh"; + argv[1] = _PATH_RUNCOM; + argv[2] = NULL; + + setenv("SafeBoot", runcom_safe ? "-x" : "", 1); + setenv("VerboseFlag", runcom_verbose ? "-v" : "", 1); + setenv("FsckSlash", runcom_fsck ? "-F" : "", 1); + setenv("NetBoot", runcom_netboot ? "-N" : "", 1); + + setpriority(PRIO_PROCESS, 0, 0); + execv(_PATH_BSHELL, argv); + stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNCOM); + exit(EXIT_FAILURE); +} + +static void +runcom_callback(void *obj __attribute__((unused)), struct kevent *kev __attribute__((unused))) +{ + int status; + struct timeval runcom_end_tv, runcom_total_tv; + double sec; + pid_t r = runcom_pid; + + gettimeofday(&runcom_end_tv, NULL); + timersub(&runcom_end_tv, &runcom_start_tv, &runcom_total_tv); + sec = runcom_total_tv.tv_sec; + sec += (double)runcom_total_tv.tv_usec / (double)1000000; + syslog(LOG_INFO, "%s finished in: %.3f seconds", _PATH_RUNCOM, sec); + +#ifdef PID1_REAP_ADOPTED_CHILDREN + status = pid1_child_exit_status; +#else + r = waitpid(runcom_pid, &status, 0); +#endif + + if (r == runcom_pid) { + runcom_pid = 0; + } else { + if (r == -1) + syslog(LOG_ERR, "waitpid() for '%s %s' failed: %m", _PATH_BSHELL, _PATH_RUNCOM); + if (r == 0) + syslog(LOG_ERR, "waitpid() for '%s %s' returned 0", _PATH_BSHELL, _PATH_RUNCOM); + syslog(LOG_ERR, "going to single user mode"); + single_user_mode = true; + return; + } + + if (WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS) { + logwtmp("~", "reboot", ""); + update_ttys(); + return; + } else if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGTERM || WTERMSIG(status) == SIGKILL)) { + return; + } + + syslog(LOG_ERR, "%s on %s terminated abnormally, going to single user mode", + _PATH_BSHELL, _PATH_RUNCOM); + single_user_mode = true; +} + +/* + * Construct an argument vector from a command line. + */ +char ** +construct_argv(command) + char *command; +{ + int argc = 0; + char **argv = (char **) malloc(((strlen(command) + 1) / 2 + 1) + * sizeof (char *)); + static const char separators[] = " \t"; + + if ((argv[argc++] = strtok(command, separators)) == 0) + return 0; + while ((argv[argc++] = strtok(NULL, separators))) + continue; + return argv; +} + +/* + * Deallocate a session descriptor. + */ + +static void free_command(se_cmd_t *se_cmd) +{ + if (se_cmd->path) { + free(se_cmd->path); + free(se_cmd->argv); + } +} + +void +session_free(session_t s) +{ + TAILQ_REMOVE(&sessions, s, tqe); + if (s->se_process) { + if (kevent_mod(s->se_process, EVFILT_PROC, EV_ADD, + NOTE_EXIT, 0, &kqsimple_zombie_reaper) == -1) + session_reap(s); + else + kill(s->se_process, SIGHUP); + } + free(s->se_device); + free_command(&s->se_getty); + free_command(&s->se_onerror); + free_command(&s->se_onoption); + free(s); +} + +static int setup_command(se_cmd_t *se_cmd, char *command, char *arg ) +{ + char *commandWithArg; + + asprintf(&commandWithArg, "%s %s", command, arg); + + free_command(se_cmd); + + se_cmd->path = commandWithArg; + se_cmd->argv = construct_argv(commandWithArg); + if (se_cmd->argv == NULL) { + free(se_cmd->path); + se_cmd->path = NULL; + return 0; + } + return 1; +} + +/* + * Calculate getty and if useful window argv vectors. + */ +static int +setupargv(sp, typ) + session_t sp; + struct ttyent *typ; +{ + char *type; + + if ( !setup_command(&sp->se_getty, typ->ty_getty, typ->ty_name) ) + { + type = "getty"; + goto bad_args; + } + + if (typ->ty_onerror + && !setup_command(&sp->se_onerror, typ->ty_onerror, typ->ty_name) ) + { + type = "onerror"; + goto bad_args; + } + + if (typ->ty_onoption + && !setup_command(&sp->se_onoption, typ->ty_onoption, typ->ty_name) ) + { + type = "onoption"; + goto bad_args; + } + + return 1; + +bad_args: + syslog(LOG_WARNING, "can't parse %s for port %s", type, sp->se_device); + return 0; +} + + +/* + * Allocate a new session descriptor. + */ +void +session_new(session_index, typ) + int session_index; + struct ttyent *typ; +{ + session_t s; + + if ((typ->ty_status & TTY_ON) == 0 || + typ->ty_name == 0 || + typ->ty_getty == 0) + return; + + s = calloc(1, sizeof(struct init_session)); + + s->se_callback = session_callback; + s->se_index = session_index; + + TAILQ_INSERT_TAIL(&sessions, s, tqe); + + asprintf(&s->se_device, "%s%s", _PATH_DEV, typ->ty_name); + + if (setupargv(s, typ) == 0) + session_free(s); +} + +static void +session_launch(session_t s) +{ + pid_t pid; + sigset_t mask; + se_cmd_t *se_cmd; + const char *session_type = NULL; + time_t current_time = time(NULL); + + // Setup the default values; + switch (s->se_flags & SE_GETTY_LAUNCH) { + case SE_ONOPTION: + if (s->se_onoption.path) { + se_cmd = &s->se_onoption; + session_type = "onoption"; + break; + } + /* No break */ + case SE_ONERROR: + if (s->se_onerror.path) { + se_cmd = &s->se_onerror; + session_type = "onerror"; + break; + } + /* No break */ + case SE_COMMON: + default: + se_cmd = &s->se_getty; + session_type = "getty"; + break; + } + + /* fork(), not vfork() -- we can't afford to block. */ + if ((pid = fork_with_bootstrap_port(launchd_bootstrap_port)) == -1) { + syslog(LOG_ERR, "can't fork for %s on port %s: %m", + session_type, s->se_device); + update_ttys(); + return; + } + + if (pid) { + s->se_process = pid; + s->se_started = time(NULL); + s->se_flags &= ~SE_GETTY_LAUNCH; // clear down getty launch type + if (kevent_mod(pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, &s->se_callback) == -1) + session_reap(s); + return; + } + + if (current_time > s->se_started && + current_time - s->se_started < GETTY_SPACING) { + syslog(LOG_WARNING, "%s repeating too quickly on port %s, sleeping", + session_type, s->se_device); + sleep(GETTY_SLEEP); + } + + sigemptyset(&mask); + sigprocmask(SIG_SETMASK, &mask, NULL); + + setpriority(PRIO_PROCESS, 0, 0); + + if (strcmp(se_cmd->argv[0], "/System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow")) + launchd_SessionCreate(se_cmd->argv[0]); + + execv(se_cmd->argv[0], se_cmd->argv); + stall("can't exec %s '%s' for port %s: %m", session_type, + se_cmd->argv[0], s->se_device); + exit(EXIT_FAILURE); +} + +static void +session_callback(void *obj, struct kevent *kev __attribute__((unused))) +{ + session_t s = obj; + + session_reap(s); + if (s->se_flags & SE_SHUTDOWN) { + session_free(s); + } else { + session_launch(s); + } +} + +static void +session_reap(session_t s) +{ + pid_t pr = s->se_process; + char *line; + int status; + +#ifdef PID1_REAP_ADOPTED_CHILDREN + status = pid1_child_exit_status; +#else + pr = waitpid(s->se_process, &status, 0); +#endif + + switch (pr) { + case -1: + syslog(LOG_ERR, "waitpid(): %m"); + return; + case 0: + syslog(LOG_ERR, "waitpid() == 0"); + return; + default: + if (WIFSIGNALED(status)) { + syslog(LOG_WARNING, "%s port %s exited abnormally: %s", + s->se_getty.path, s->se_device, strsignal(WTERMSIG(status))); + s->se_flags |= SE_ONERROR; + } else if (WEXITSTATUS(status) == REALLY_EXIT_TO_CONSOLE) { + /* WIFEXITED(status) assumed */ + s->se_flags |= SE_ONOPTION; + } else { + s->se_flags |= SE_ONERROR; + } + s->se_process = 0; + line = s->se_device + sizeof(_PATH_DEV) - 1; + if (logout(line)) + logwtmp(line, "", ""); + break; + } +} + +/* + * This is an n-squared algorithm. We hope it isn't run often... + */ +void +update_ttys(void) +{ + session_t sp; + struct ttyent *typ; + int session_index = 0; + int devlen; + + devlen = sizeof(_PATH_DEV) - 1; + while ((typ = getttyent())) { + ++session_index; + + TAILQ_FOREACH(sp, &sessions, tqe) { + if (strcmp(typ->ty_name, sp->se_device + devlen) == 0) + break; + } + + if (sp == NULL) { + session_new(session_index, typ); + continue; + } + + if (sp->se_index != session_index) { + syslog(LOG_INFO, "port %s changed utmp index from %d to %d", + sp->se_device, sp->se_index, + session_index); + sp->se_index = session_index; + } + + if ((typ->ty_status & TTY_ON) == 0 || + typ->ty_getty == 0) { + session_free(sp); + continue; + } + + sp->se_flags &= ~SE_SHUTDOWN; + + if (setupargv(sp, typ) == 0) { + syslog(LOG_WARNING, "can't parse getty for port %s", + sp->se_device); + session_free(sp); + } + } + + endttyent(); +} + +/* + * Block further logins. + */ +void +catatonia(void) +{ + session_t s; + + TAILQ_FOREACH(s, &sessions, tqe) + s->se_flags |= SE_SHUTDOWN; +} + +/* + * Bring the system down to single user. + */ +void +death(void) +{ + int i; + static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL }; + + catatonia(); + + single_user_mode = true; + + /* NB: should send a message to the session logger to avoid blocking. */ + logwtmp("~", "shutdown", ""); + + for (i = 0; i < 3; ++i) { + if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH) + return; + syslog(LOG_ERR, "we should be trying to detect a valid clean-up"); + sleep(DEATH_WATCH); + } + + syslog(LOG_WARNING, "some processes would not die; ps axl advised"); +} + +#ifdef PID1_REAP_ADOPTED_CHILDREN +__private_extern__ bool init_check_pid(pid_t p) +{ + struct kevent kev; + session_t s; + + TAILQ_FOREACH(s, &sessions, tqe) { + if (s->se_process == p) { + EV_SET(&kev, p, EVFILT_PROC, 0, 0, 0, s); + s->se_callback(s, &kev); + return true; + } + } + if (single_user_pid == p) { + single_user_callback(NULL, NULL); + return true; + } + if (runcom_pid == p) { + runcom_callback(NULL, NULL); + return true; + } + return false; +} +#endif diff --git a/launchd/src/launch.h b/launchd/src/launch.h new file mode 100644 index 0000000..b4d9557 --- /dev/null +++ b/launchd/src/launch.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef _LAUNCH_H_ +#define _LAUNCH_H_ + +#include +#include + + +#define LAUNCH_KEY_SUBMITJOB "SubmitJob" +#define LAUNCH_KEY_REMOVEJOB "RemoveJob" +#define LAUNCH_KEY_STARTJOB "StartJob" +#define LAUNCH_KEY_STOPJOB "StopJob" +#define LAUNCH_KEY_GETJOB "GetJob" +#define LAUNCH_KEY_GETJOBWITHHANDLES "GetJobWithHandles" +#define LAUNCH_KEY_GETJOBS "GetJobs" +#define LAUNCH_KEY_CHECKIN "CheckIn" + +#define LAUNCH_JOBKEY_LABEL "Label" +#define LAUNCH_JOBKEY_DISABLED "Disabled" +#define LAUNCH_JOBKEY_USERNAME "UserName" +#define LAUNCH_JOBKEY_GROUPNAME "GroupName" +#define LAUNCH_JOBKEY_TIMEOUT "TimeOut" +#define LAUNCH_JOBKEY_INITGROUPS "InitGroups" +#define LAUNCH_JOBKEY_SOCKETS "Sockets" +#define LAUNCH_JOBKEY_EVENTSOURCES "EventSources" +#define LAUNCH_JOBKEY_INETDCOMPATIBILITY "inetdCompatibility" +#define LAUNCH_JOBKEY_PROGRAMARGUMENTS "ProgramArguments" +#define LAUNCH_JOBKEY_PROGRAM "Program" +#define LAUNCH_JOBKEY_ONDEMAND "OnDemand" +#define LAUNCH_JOBKEY_RUNATLOAD "RunAtLoad" +#define LAUNCH_JOBKEY_ROOTDIRECTORY "RootDirectory" +#define LAUNCH_JOBKEY_WORKINGDIRECTORY "WorkingDirectory" +#define LAUNCH_JOBKEY_SERVICEDESCRIPTION "ServiceDescription" +#define LAUNCH_JOBKEY_ENVIRONMENTVARIABLES "EnvironmentVariables" +#define LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES "UserEnvironmentVariables" +#define LAUNCH_JOBKEY_PID "PID" +#define LAUNCH_JOBKEY_UMASK "Umask" +#define LAUNCH_JOBKEY_NICE "Nice" +#define LAUNCH_JOBKEY_LOWPRIORITYIO "LowPriorityIO" +#define LAUNCH_JOBKEY_SESSIONCREATE "SessionCreate" +#define LAUNCH_JOBKEY_SOFTRESOURCELIMITS "SoftResourceLimits" +#define LAUNCH_JOBKEY_HARDRESOURCELIMITS "HardResourceLimits" +#define LAUNCH_JOBKEY_SERVICEIPC "ServiceIPC" +#define LAUNCH_JOBKEY_STANDARDOUTPATH "StandardOutPath" +#define LAUNCH_JOBKEY_STANDARDERRORPATH "StandardErrorPath" +#define LAUNCH_JOBKEY_DEBUG "Debug" +#define LAUNCH_JOBKEY_QUEUEDIRECTORIES "QueueDirectories" +#define LAUNCH_JOBKEY_WATCHPATHS "WatchPaths" +#define LAUNCH_JOBKEY_STARTINTERVAL "StartInterval" +#define LAUNCH_JOBKEY_STARTCALENDARINTERVAL "StartCalendarInterval" +#define LAUNCH_JOBKEY_BONJOURFDS "BonjourFDs" + +#define LAUNCH_JOBINETDCOMPATIBILITY_WAIT "Wait" + +#define LAUNCH_JOBKEY_CAL_MINUTE "Minute" +#define LAUNCH_JOBKEY_CAL_HOUR "Hour" +#define LAUNCH_JOBKEY_CAL_DAY "Day" +#define LAUNCH_JOBKEY_CAL_WEEKDAY "Weekday" +#define LAUNCH_JOBKEY_CAL_MONTH "Month" + +#define LAUNCH_JOBKEY_RESOURCELIMIT_CORE "Core" +#define LAUNCH_JOBKEY_RESOURCELIMIT_CPU "CPU" +#define LAUNCH_JOBKEY_RESOURCELIMIT_DATA "Data" +#define LAUNCH_JOBKEY_RESOURCELIMIT_FSIZE "FileSize" +#define LAUNCH_JOBKEY_RESOURCELIMIT_MEMLOCK "MemoryLock" +#define LAUNCH_JOBKEY_RESOURCELIMIT_NOFILE "NumberOfFiles" +#define LAUNCH_JOBKEY_RESOURCELIMIT_NPROC "NumberOfProcesses" +#define LAUNCH_JOBKEY_RESOURCELIMIT_RSS "ResidentSetSize" +#define LAUNCH_JOBKEY_RESOURCELIMIT_STACK "Stack" + +#define LAUNCH_JOBSOCKETKEY_TYPE "SockType" +#define LAUNCH_JOBSOCKETKEY_PASSIVE "SockPassive" +#define LAUNCH_JOBSOCKETKEY_BONJOUR "Bonjour" +#define LAUNCH_JOBSOCKETKEY_SECUREWITHKEY "SecureSocketWithKey" +#define LAUNCH_JOBSOCKETKEY_PATHNAME "SockPathName" +#define LAUNCH_JOBSOCKETKEY_NODENAME "SockNodeName" +#define LAUNCH_JOBSOCKETKEY_SERVICENAME "SockServiceName" +#define LAUNCH_JOBSOCKETKEY_FAMILY "SockFamily" +#define LAUNCH_JOBSOCKETKEY_PROTOCOL "SockProtocol" +#define LAUNCH_JOBSOCKETKEY_FD "SockFD" +#define LAUNCH_JOBSOCKETKEY_ADDRINFORESULTS "AddrinfoResults" + +typedef struct _launch_data *launch_data_t; + +typedef enum { + LAUNCH_DATA_DICTIONARY = 1, + LAUNCH_DATA_ARRAY, + LAUNCH_DATA_FD, + LAUNCH_DATA_INTEGER, + LAUNCH_DATA_REAL, + LAUNCH_DATA_BOOL, + LAUNCH_DATA_STRING, + LAUNCH_DATA_OPAQUE, + LAUNCH_DATA_ERRNO, +} launch_data_type_t; + +launch_data_t launch_data_alloc(launch_data_type_t); +launch_data_t launch_data_copy(launch_data_t); +launch_data_type_t launch_data_get_type(launch_data_t); +void launch_data_free(launch_data_t); + +/* Generic Dictionaries */ +/* the value should not be changed while iterating */ +bool launch_data_dict_insert(launch_data_t, launch_data_t, const char *); +launch_data_t launch_data_dict_lookup(launch_data_t, const char *); +bool launch_data_dict_remove(launch_data_t, const char *); +void launch_data_dict_iterate(launch_data_t, void (*)(launch_data_t, const char *, void *), void *); +size_t launch_data_dict_get_count(launch_data_t); + +/* Generic Arrays */ +bool launch_data_array_set_index(launch_data_t, launch_data_t, size_t); +launch_data_t launch_data_array_get_index(launch_data_t, size_t); +size_t launch_data_array_get_count(launch_data_t); + +launch_data_t launch_data_new_fd(int); +launch_data_t launch_data_new_integer(long long); +launch_data_t launch_data_new_bool(bool); +launch_data_t launch_data_new_real(double); +launch_data_t launch_data_new_string(const char *); +launch_data_t launch_data_new_opaque(const void *, size_t); + +bool launch_data_set_fd(launch_data_t, int); +bool launch_data_set_integer(launch_data_t, long long); +bool launch_data_set_bool(launch_data_t, bool); +bool launch_data_set_real(launch_data_t, double); +bool launch_data_set_string(launch_data_t, const char *); +bool launch_data_set_opaque(launch_data_t, const void *, size_t); + +int launch_data_get_fd(launch_data_t); +long long launch_data_get_integer(launch_data_t); +bool launch_data_get_bool(launch_data_t); +double launch_data_get_real(launch_data_t); +const char * launch_data_get_string(launch_data_t); +void * launch_data_get_opaque(launch_data_t); +size_t launch_data_get_opaque_size(launch_data_t); +int launch_data_get_errno(launch_data_t); + + +/* launch_get_fd() + * + * Use this to get the FD if you're doing asynchronous I/O with select(), + * poll() or kevent(). + */ +int launch_get_fd(void); + +/* launch_msg() + * + * Use this API to send and receive messages. + * Calling launch_msg() with no message to send is a valid way to get + * asynchronously received messages. + * + * If a message was to be sent, it returns NULL and errno on failure. + * + * If no messages were to be sent, it returns NULL and errno is set to zero if + * no more asynchronous messages are available. + */ +launch_data_t launch_msg(launch_data_t); + +#endif diff --git a/launchd/src/launch_priv.h b/launchd/src/launch_priv.h new file mode 100644 index 0000000..c5d297e --- /dev/null +++ b/launchd/src/launch_priv.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef _LAUNCH_PRIV_H_ +#define _LAUNCH_PRIV_H_ + +#define LAUNCH_KEY_GETUSERENVIRONMENT "GetUserEnvironment" +#define LAUNCH_KEY_SETUSERENVIRONMENT "SetUserEnvironment" +#define LAUNCH_KEY_UNSETUSERENVIRONMENT "UnsetUserEnvironment" +#define LAUNCH_KEY_SETSTDOUT "SetStandardOut" +#define LAUNCH_KEY_SETSTDERR "SetStandardError" +#define LAUNCH_KEY_SHUTDOWN "Shutdown" +#define LAUNCH_KEY_GETRESOURCELIMITS "GetResourceLimits" +#define LAUNCH_KEY_SETRESOURCELIMITS "SetResourceLimits" +#define LAUNCH_KEY_RELOADTTYS "ReloadTTYS" +#define LAUNCH_KEY_SETLOGMASK "SetLogMask" +#define LAUNCH_KEY_GETLOGMASK "GetLogMask" +#define LAUNCH_KEY_SETUMASK "SetUmask" +#define LAUNCH_KEY_GETUMASK "GetUmask" +#define LAUNCH_KEY_GETRUSAGESELF "GetResourceUsageSelf" +#define LAUNCH_KEY_GETRUSAGECHILDREN "GetResourceUsageChildren" + +#define LAUNCHD_SOCKET_ENV "LAUNCHD_SOCKET" +#define LAUNCHD_SOCK_PREFIX "/var/launchd" +#define LAUNCHD_TRUSTED_FD_ENV "__LAUNCHD_FD" +#define LAUNCHD_ASYNC_MSG_KEY "_AsyncMessage" +#define LAUNCH_KEY_BATCHCONTROL "BatchControl" +#define LAUNCH_KEY_BATCHQUERY "BatchQuery" + +typedef struct _launch *launch_t; + +launch_t launchd_fdopen(int); +int launchd_getfd(launch_t); +void launchd_close(launch_t); + +launch_data_t launch_data_new_errno(int); +bool launch_data_set_errno(launch_data_t, int); + +int launchd_msg_send(launch_t, launch_data_t); +int launchd_msg_recv(launch_t, void (*)(launch_data_t, void *), void *); + +/* batch jobs will be implicity re-enabled when the last application who + * disabled them exits */ +void launchd_batch_enable(bool); +bool launchd_batch_query(void); + +#endif diff --git a/launchd/src/launchctl.1 b/launchd/src/launchctl.1 new file mode 100644 index 0000000..6049792 --- /dev/null +++ b/launchd/src/launchctl.1 @@ -0,0 +1,126 @@ +.Dd September 30, 2004 +.Dt launchctl 1 +.Os Darwin +.Sh NAME +.Nm launchctl +.Nd Interfaces with launchd +.Sh SYNOPSIS +.Nm +.Op Ar subcommand Op Ar arguments ... +.Sh DESCRIPTION +.Nm +interfaces with +.Nm launchd +to load, unload daemons/agents and generally control +.Nm launchd . +.Nm +supports taking subcommands on the command line, interactively or even redirected from standard input. +These commands can be stored in +.Nm $HOME/.launchd.conf +or +.Nm /etc/launchd.conf +to be read at the time +.Nm launchd +starts. +.Sh SUBCOMMANDS +.Bl -tag -width -indent +.It Xo Ar load Op Fl w +.Ar paths ... +.Xc +Load the specified configuration files or directories of configuration files. +.Bl -tag -width -indent +.It Fl w +Remove the disabled key and write the configuration files back out to disk. +.El +.It Xo Ar unload Op Fl w +.Ar paths ... +.Xc +Unload the specified configuration files or directories of configuration files. +.Bl -tag -width -indent +.It Fl w +Add the disabled key and write the configuration files back out to disk. +.El +.It Ar start Ar joblabels ... +Start the specified jobs by label. +.It Ar stop Ar joblabels ... +Stop the specified jobs by label. Jobs may restart automatically if demand driven. +.It Ar list +List all of the jobs loaded into +.Nm launchd . +.It Ar setenv Ar key Ar value +Set an environmental variable inside of +.Nm launchd . +.It Ar unsetenv Ar key +Unset an environmental variable inside of +.Nm launchd . +.It Ar getenv Ar key +Get an environmental variable inside of +.Nm launchd . +.It Ar export +Export all of the environmental variables of +.Nm launchd +for use in a shell eval statement. +.It Ar getrusage self | children +Get the resource utilization statistics for +.Nm launchd +or the children of +.Nm launchd . +.It Xo Ar log +.Op Ar level loglevel +.Op Ar only | mask loglevels... +.Xc +Get and set the +.Xr syslog 3 +log level mask. The available log levels are: debug, info, notice, warning, error, critical, alert and emergency. +.It Xo Ar limit +.Op Ar cpu | filesize | data | stack | core | rss | memlock | maxproc | maxfiles +.Op Ar both Op Ar soft | hard +.Xc +With no arguments, this command prints all the resource limits of +.Nm launchd +as found via +.Xr getrlimit 2 . +When a given resource is specified, it prints the limits for that resource. +With a third argument, it sets both the hard and soft limits to that value. +With four arguments, the third and forth argument represent the soft and hard limits respectively. +See +.Xr setrlimit 2 . +.It Ar stdout path +Set the standard out file descriptor to the given path. +.Nm launchd +.It Ar stderr path +Set the standard error file descriptor to the given path. +.Nm launchd +.It Ar shutdown +Tell +.Nm launchd +to prepare for shutdown by removing all jobs. +.It Ar reloadttys +Tell +.Nm launchd +to reread /etc/ttys. This option may go away in a future release. +.It Ar umask Op Ar newmask +Get or optionally set the +.Xr umask 2 +of +.Nm launchd . +.It Ar help +Print out a quick usage statement. +.El +.Sh FILES +.Bl -tag -width "/System/Library/LaunchDaemons" -compact +.It Pa ~/Library/LaunchAgents +Per-user agents provided by the user. +.It Pa /Library/LaunchAgents +Per-user agents provided by the administrator. +.It Pa /Library/LaunchDaemons +System wide daemons provided by the administrator. +.It Pa /System/Library/LaunchAgents +Mac OS X Per-user agents. +.It Pa /System/Library/LaunchDaemons +Mac OS X System wide daemons. +.El +.Sh SEE ALSO +.Xr launchd.plist 5 , +.Xr launchd.conf 5 , +.Xr launchd 8 diff --git a/launchd/src/launchctl.c b/launchd/src/launchctl.c new file mode 100644 index 0000000..f6911d5 --- /dev/null +++ b/launchd/src/launchctl.c @@ -0,0 +1,1451 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "launch.h" +#include "launch_priv.h" + +#define LAUNCH_SECDIR "/tmp/launch-XXXXXX" + +static bool launch_data_array_append(launch_data_t a, launch_data_t o); +static void distill_config_file(launch_data_t); +static void sock_dict_cb(launch_data_t what, const char *key, void *context); +static void sock_dict_edit_entry(launch_data_t tmp, const char *key, launch_data_t fdarray, launch_data_t thejob); +static launch_data_t CF2launch_data(CFTypeRef); +static launch_data_t read_plist_file(const char *file, bool editondisk, bool load); +static CFPropertyListRef CreateMyPropertyListFromFile(const char *); +static void WriteMyPropertyListToFile(CFPropertyListRef, const char *); +static void readpath(const char *, launch_data_t, launch_data_t, bool editondisk, bool load); +static int _fd(int); +static int demux_cmd(int argc, char *const argv[]); +static launch_data_t do_rendezvous_magic(const struct addrinfo *res, const char *serv); +static void submit_job_pass(launch_data_t jobs); + +static int load_and_unload_cmd(int argc, char *const argv[]); +//static int reload_cmd(int argc, char *const argv[]); +static int start_and_stop_cmd(int argc, char *const argv[]); +static int list_cmd(int argc, char *const argv[]); + +static int setenv_cmd(int argc, char *const argv[]); +static int unsetenv_cmd(int argc, char *const argv[]); +static int getenv_and_export_cmd(int argc, char *const argv[]); + +static int limit_cmd(int argc, char *const argv[]); +static int stdio_cmd(int argc, char *const argv[]); +static int fyi_cmd(int argc, char *const argv[]); +static int logupdate_cmd(int argc, char *const argv[]); +static int umask_cmd(int argc, char *const argv[]); +static int getrusage_cmd(int argc, char *const argv[]); + +static int help_cmd(int argc, char *const argv[]); + +static const struct { + const char *name; + int (*func)(int argc, char *const argv[]); + const char *desc; +} cmds[] = { + { "load", load_and_unload_cmd, "Load configuration files and/or directories" }, + { "unload", load_and_unload_cmd, "Unload configuration files and/or directories" }, +// { "reload", reload_cmd, "Reload configuration files and/or directories" }, + { "start", start_and_stop_cmd, "Start specified jobs" }, + { "stop", start_and_stop_cmd, "Stop specified jobs" }, + { "list", list_cmd, "List jobs and information about jobs" }, + { "setenv", setenv_cmd, "Set an environmental variable in launchd" }, + { "unsetenv", unsetenv_cmd, "Unset an environmental variable in launchd" }, + { "getenv", getenv_and_export_cmd, "Get an environmental variable from launchd" }, + { "export", getenv_and_export_cmd, "Export shell settings from launchd" }, + { "limit", limit_cmd, "View and adjust launchd resource limits" }, + { "stdout", stdio_cmd, "Redirect launchd's standard out to the given path" }, + { "stderr", stdio_cmd, "Redirect launchd's standard error to the given path" }, + { "shutdown", fyi_cmd, "Prepare for system shutdown" }, + { "reloadttys", fyi_cmd, "Reload /etc/ttys" }, + { "getrusage", getrusage_cmd, "Get resource usage statistics from launchd" }, + { "log", logupdate_cmd, "Adjust the logging level or mask of launchd" }, + { "umask", umask_cmd, "Change launchd's umask" }, + { "help", help_cmd, "This help output" }, +}; + +int main(int argc, char *const argv[]) +{ + bool istty = isatty(STDIN_FILENO); + char *l; + + if (argc > 1) + exit(demux_cmd(argc - 1, argv + 1)); + + if (NULL == readline) { + fprintf(stderr, "missing library: readline\n"); + exit(EXIT_FAILURE); + } + + while ((l = readline(istty ? "launchd% " : NULL))) { + char *inputstring = l, *argv2[100], **ap = argv2; + int i = 0; + + while ((*ap = strsep(&inputstring, " \t"))) { + if (**ap != '\0') { + ap++; + i++; + } + } + + if (i > 0) + demux_cmd(i, argv2); + + free(l); + } + + if (istty) + fputc('\n', stdout); + + exit(EXIT_SUCCESS); +} + +static int demux_cmd(int argc, char *const argv[]) +{ + size_t i; + + optind = 1; + optreset = 1; + + for (i = 0; i < (sizeof cmds / sizeof cmds[0]); i++) { + if (!strcmp(cmds[i].name, argv[0])) + return cmds[i].func(argc, argv); + } + + fprintf(stderr, "%s: unknown subcommand \"%s\"\n", getprogname(), argv[0]); + return 1; +} + +static int unsetenv_cmd(int argc, char *const argv[]) +{ + launch_data_t resp, tmp, msg; + + if (argc != 2) { + fprintf(stderr, "%s usage: unsetenv \n", getprogname()); + return 1; + } + + msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + + tmp = launch_data_new_string(argv[1]); + launch_data_dict_insert(msg, tmp, LAUNCH_KEY_UNSETUSERENVIRONMENT); + + resp = launch_msg(msg); + + launch_data_free(msg); + + if (resp) { + launch_data_free(resp); + } else { + fprintf(stderr, "launch_msg(\"%s\"): %s\n", LAUNCH_KEY_UNSETUSERENVIRONMENT, strerror(errno)); + } + + return 0; +} + +static int setenv_cmd(int argc, char *const argv[]) +{ + launch_data_t resp, tmp, tmpv, msg; + + if (argc != 3) { + fprintf(stderr, "%s usage: setenv \n", getprogname()); + return 1; + } + + msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + tmp = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + + tmpv = launch_data_new_string(argv[2]); + launch_data_dict_insert(tmp, tmpv, argv[1]); + launch_data_dict_insert(msg, tmp, LAUNCH_KEY_SETUSERENVIRONMENT); + + resp = launch_msg(msg); + launch_data_free(msg); + + if (resp) { + launch_data_free(resp); + } else { + fprintf(stderr, "launch_msg(\"%s\"): %s\n", LAUNCH_KEY_SETUSERENVIRONMENT, strerror(errno)); + } + + return 0; +} + +static int getenv_and_export_cmd(int argc, char *const argv[] __attribute__((unused))) +{ + launch_data_t resp, msg; + bool is_csh = false; + const char *k; + void print_launchd_env(launch_data_t obj, const char *key, void *context __attribute__((unused))) { + if (is_csh) + fprintf(stdout, "setenv %s %s;\n", key, launch_data_get_string(obj)); + else + fprintf(stdout, "%s=%s; export %s;\n", key, launch_data_get_string(obj), key); + } + void print_key_value(launch_data_t obj, const char *key, void *context __attribute__((unused))) { + if (!strcmp(key, k)) + fprintf(stdout, "%s\n", launch_data_get_string(obj)); + } + + if (!strcmp(argv[0], "export")) { + char *s = getenv("SHELL"); + if (s) + is_csh = strstr(s, "csh") ? true : false; + } else if (argc != 2) { + fprintf(stderr, "%s usage: getenv \n", getprogname()); + return 1; + } + + k = argv[1]; + + msg = launch_data_new_string(LAUNCH_KEY_GETUSERENVIRONMENT); + + resp = launch_msg(msg); + launch_data_free(msg); + + if (resp) { + launch_data_dict_iterate(resp, (!strcmp(argv[0], "export")) ? print_launchd_env : print_key_value, NULL); + launch_data_free(resp); + } else { + fprintf(stderr, "launch_msg(\"" LAUNCH_KEY_GETUSERENVIRONMENT "\"): %s\n", strerror(errno)); + } + return 0; +} + +static void unloadjob(launch_data_t job) +{ + launch_data_t resp, tmp, tmps, msg; + int e; + + msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + tmp = launch_data_alloc(LAUNCH_DATA_STRING); + tmps = launch_data_dict_lookup(job, LAUNCH_JOBKEY_LABEL); + + if (!tmps) { + fprintf(stderr, "%s: Error: Missing Key: %s\n", getprogname(), LAUNCH_JOBKEY_LABEL); + return; + } + + launch_data_set_string(tmp, launch_data_get_string(tmps)); + launch_data_dict_insert(msg, tmp, LAUNCH_KEY_REMOVEJOB); + resp = launch_msg(msg); + launch_data_free(msg); + if (!resp) { + fprintf(stderr, "%s: Error: launch_msg(): %s\n", getprogname(), strerror(errno)); + return; + } + if (LAUNCH_DATA_ERRNO == launch_data_get_type(resp)) { + if ((e = launch_data_get_errno(resp))) + fprintf(stderr, "%s\n", strerror(e)); + } + launch_data_free(resp); +} + +static launch_data_t read_plist_file(const char *file, bool editondisk, bool load) +{ + CFPropertyListRef plist = CreateMyPropertyListFromFile(file); + launch_data_t r = NULL; + + if (NULL == plist) { + fprintf(stderr, "%s: no plist was returned for: %s\n", getprogname(), file); + return NULL; + } + + if (editondisk) { + if (load) + CFDictionaryRemoveValue((CFMutableDictionaryRef)plist, CFSTR(LAUNCH_JOBKEY_DISABLED)); + else + CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR(LAUNCH_JOBKEY_DISABLED), kCFBooleanTrue); + WriteMyPropertyListToFile(plist, file); + } + + r = CF2launch_data(plist); + + CFRelease(plist); + + return r; +} + +static void delay_to_second_pass2(launch_data_t o, const char *key, void *context) +{ + bool *res = context; + size_t i; + + if (key && 0 == strcmp(key, LAUNCH_JOBSOCKETKEY_BONJOUR)) { + *res = true; + return; + } + + switch (launch_data_get_type(o)) { + case LAUNCH_DATA_DICTIONARY: + launch_data_dict_iterate(o, delay_to_second_pass2, context); + break; + case LAUNCH_DATA_ARRAY: + for (i = 0; i < launch_data_array_get_count(o); i++) + delay_to_second_pass2(launch_data_array_get_index(o, i), NULL, context); + break; + default: + break; + } +} + +static bool delay_to_second_pass(launch_data_t o) +{ + bool res = false; + + launch_data_t socks = launch_data_dict_lookup(o, LAUNCH_JOBKEY_SOCKETS); + + if (NULL == socks) + return false; + + delay_to_second_pass2(socks, NULL, &res); + + return res; +} + +static void readfile(const char *what, launch_data_t pass1, launch_data_t pass2, bool editondisk, bool load) +{ + launch_data_t tmpd, thejob; + bool job_disabled = false; + + if (NULL == (thejob = read_plist_file(what, editondisk, load))) { + fprintf(stderr, "%s: no plist was returned for: %s\n", getprogname(), what); + return; + } + + if ((tmpd = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_DISABLED))) + job_disabled = launch_data_get_bool(tmpd); + + if (job_disabled && load) { + launch_data_free(thejob); + return; + } + + if (delay_to_second_pass(thejob)) + launch_data_array_append(pass2, thejob); + else + launch_data_array_append(pass1, thejob); +} + +static void readpath(const char *what, launch_data_t pass1, launch_data_t pass2, bool editondisk, bool load) +{ + char buf[MAXPATHLEN]; + struct stat sb; + struct dirent *de; + DIR *d; + + if (stat(what, &sb) == -1) + return; + + if (S_ISREG(sb.st_mode) && !(sb.st_mode & S_IWOTH)) { + readfile(what, pass1, pass2, editondisk, load); + } else { + if ((d = opendir(what)) == NULL) { + fprintf(stderr, "%s: opendir() failed to open the directory\n", getprogname()); + return; + } + + while ((de = readdir(d))) { + if ((de->d_name[0] == '.')) + continue; + snprintf(buf, sizeof(buf), "%s/%s", what, de->d_name); + + readfile(buf, pass1, pass2, editondisk, load); + } + closedir(d); + } +} + +struct distill_context { + launch_data_t base; + launch_data_t newsockdict; +}; + +static void distill_config_file(launch_data_t id_plist) +{ + struct distill_context dc = { id_plist, NULL }; + launch_data_t tmp; + + if ((tmp = launch_data_dict_lookup(id_plist, LAUNCH_JOBKEY_SOCKETS))) { + dc.newsockdict = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + launch_data_dict_iterate(tmp, sock_dict_cb, &dc); + launch_data_dict_insert(dc.base, dc.newsockdict, LAUNCH_JOBKEY_SOCKETS); + } +} + +static void sock_dict_cb(launch_data_t what, const char *key, void *context) +{ + struct distill_context *dc = context; + launch_data_t fdarray = launch_data_alloc(LAUNCH_DATA_ARRAY); + + launch_data_dict_insert(dc->newsockdict, fdarray, key); + + if (launch_data_get_type(what) == LAUNCH_DATA_DICTIONARY) { + sock_dict_edit_entry(what, key, fdarray, dc->base); + } else if (launch_data_get_type(what) == LAUNCH_DATA_ARRAY) { + launch_data_t tmp; + size_t i; + + for (i = 0; i < launch_data_array_get_count(what); i++) { + tmp = launch_data_array_get_index(what, i); + sock_dict_edit_entry(tmp, key, fdarray, dc->base); + } + } +} + +static void sock_dict_edit_entry(launch_data_t tmp, const char *key, launch_data_t fdarray, launch_data_t thejob) +{ + launch_data_t a, val; + int sfd, st = SOCK_STREAM; + bool passive = true; + + if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_TYPE))) { + if (!strcasecmp(launch_data_get_string(val), "stream")) { + st = SOCK_STREAM; + } else if (!strcasecmp(launch_data_get_string(val), "dgram")) { + st = SOCK_DGRAM; + } else if (!strcasecmp(launch_data_get_string(val), "seqpacket")) { + st = SOCK_SEQPACKET; + } + } + + if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_PASSIVE))) + passive = launch_data_get_bool(val); + + if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_SECUREWITHKEY))) { + char secdir[] = LAUNCH_SECDIR, buf[1024]; + launch_data_t uenv = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES); + + if (NULL == uenv) { + uenv = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + launch_data_dict_insert(thejob, uenv, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES); + } + + mkdtemp(secdir); + + sprintf(buf, "%s/%s", secdir, key); + + a = launch_data_new_string(buf); + launch_data_dict_insert(tmp, a, LAUNCH_JOBSOCKETKEY_PATHNAME); + a = launch_data_new_string(buf); + launch_data_dict_insert(uenv, a, launch_data_get_string(val)); + } + + if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_PATHNAME))) { + struct sockaddr_un sun; + + memset(&sun, 0, sizeof(sun)); + + sun.sun_family = AF_UNIX; + + strncpy(sun.sun_path, launch_data_get_string(val), sizeof(sun.sun_path)); + + if ((sfd = _fd(socket(AF_UNIX, st, 0))) == -1) + return; + + if (passive) { + if (unlink(sun.sun_path) == -1 && errno != ENOENT) { + close(sfd); + return; + } + if (bind(sfd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { + close(sfd); + return; + } + if ((st == SOCK_STREAM || st == SOCK_SEQPACKET) + && listen(sfd, SOMAXCONN) == -1) { + close(sfd); + return; + } + } else if (connect(sfd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { + close(sfd); + return; + } + + val = launch_data_new_fd(sfd); + launch_data_array_append(fdarray, val); + } else { + launch_data_t rnames = NULL; + const char *node = NULL, *serv = NULL; + char servnbuf[50]; + struct addrinfo hints, *res0, *res; + int gerr, sock_opt = 1; + bool rendezvous = false; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_socktype = st; + if (passive) + hints.ai_flags |= AI_PASSIVE; + + if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_NODENAME))) + node = launch_data_get_string(val); + if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_SERVICENAME))) { + if (LAUNCH_DATA_INTEGER == launch_data_get_type(val)) { + sprintf(servnbuf, "%lld", launch_data_get_integer(val)); + serv = servnbuf; + } else { + serv = launch_data_get_string(val); + } + } + if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_FAMILY))) { + if (!strcasecmp("IPv4", launch_data_get_string(val))) + hints.ai_family = AF_INET; + else if (!strcasecmp("IPv6", launch_data_get_string(val))) + hints.ai_family = AF_INET6; + } + if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_PROTOCOL))) { + if (!strcasecmp("TCP", launch_data_get_string(val))) + hints.ai_protocol = IPPROTO_TCP; + } + if ((rnames = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_BONJOUR))) { + rendezvous = true; + if (LAUNCH_DATA_BOOL == launch_data_get_type(rnames)) { + rendezvous = launch_data_get_bool(rnames); + rnames = NULL; + } + } + + if ((gerr = getaddrinfo(node, serv, &hints, &res0)) != 0) { + fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(gerr)); + return; + } + + for (res = res0; res; res = res->ai_next) { + launch_data_t rvs_fd = NULL; + if ((sfd = _fd(socket(res->ai_family, res->ai_socktype, res->ai_protocol))) == -1) { + fprintf(stderr, "socket(): %s\n", strerror(errno)); + return; + } + if (hints.ai_flags & AI_PASSIVE) { + if (AF_INET6 == res->ai_family && -1 == setsockopt(sfd, IPPROTO_IPV6, IPV6_V6ONLY, + (void *)&sock_opt, sizeof(sock_opt))) { + fprintf(stderr, "setsockopt(IPV6_V6ONLY): %m"); + return; + } + if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt, sizeof(sock_opt)) == -1) { + fprintf(stderr, "socket(): %s\n", strerror(errno)); + return; + } + if (bind(sfd, res->ai_addr, res->ai_addrlen) == -1) { + fprintf(stderr, "bind(): %s\n", strerror(errno)); + return; + } + if ((res->ai_socktype == SOCK_STREAM || res->ai_socktype == SOCK_SEQPACKET) + && listen(sfd, SOMAXCONN) == -1) { + fprintf(stderr, "listen(): %s\n", strerror(errno)); + return; + } + if (rendezvous && (res->ai_family == AF_INET || res->ai_family == AF_INET6) && + (res->ai_socktype == SOCK_STREAM || res->ai_socktype == SOCK_DGRAM)) { + launch_data_t rvs_fds = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_BONJOURFDS); + if (NULL == rvs_fds) { + rvs_fds = launch_data_alloc(LAUNCH_DATA_ARRAY); + launch_data_dict_insert(thejob, rvs_fds, LAUNCH_JOBKEY_BONJOURFDS); + } + if (NULL == rnames) { + rvs_fd = do_rendezvous_magic(res, serv); + if (rvs_fd) + launch_data_array_append(rvs_fds, rvs_fd); + } else if (LAUNCH_DATA_STRING == launch_data_get_type(rnames)) { + rvs_fd = do_rendezvous_magic(res, launch_data_get_string(rnames)); + if (rvs_fd) + launch_data_array_append(rvs_fds, rvs_fd); + } else if (LAUNCH_DATA_ARRAY == launch_data_get_type(rnames)) { + size_t rn_i, rn_ac = launch_data_array_get_count(rnames); + + for (rn_i = 0; rn_i < rn_ac; rn_i++) { + launch_data_t rn_tmp = launch_data_array_get_index(rnames, rn_i); + + rvs_fd = do_rendezvous_magic(res, launch_data_get_string(rn_tmp)); + if (rvs_fd) + launch_data_array_append(rvs_fds, rvs_fd); + } + } + } + } else { + if (connect(sfd, res->ai_addr, res->ai_addrlen) == -1) { + fprintf(stderr, "connect(): %s\n", strerror(errno)); + return; + } + } + val = launch_data_new_fd(sfd); + if (rvs_fd) { + /* Launchd should not register the same service more than once */ + /* Switch to DNSServiceRegisterAddrInfo() */ + rendezvous = false; + } + launch_data_array_append(fdarray, val); + } + } +} + +static launch_data_t do_rendezvous_magic(const struct addrinfo *res, const char *serv) +{ + struct stat sb; + DNSServiceRef service; + DNSServiceErrorType error; + char rvs_buf[200]; + short port; + static int statres = 1; + + if (1 == statres) + statres = stat("/usr/sbin/mDNSResponder", &sb); + + if (-1 == statres) + return NULL; + + sprintf(rvs_buf, "_%s._%s.", serv, res->ai_socktype == SOCK_STREAM ? "tcp" : "udp"); + + if (res->ai_family == AF_INET) + port = ((struct sockaddr_in *)res->ai_addr)->sin_port; + else + port = ((struct sockaddr_in6 *)res->ai_addr)->sin6_port; + + error = DNSServiceRegister(&service, 0, 0, NULL, rvs_buf, NULL, NULL, port, 0, NULL, NULL, NULL); + + if (error == kDNSServiceErr_NoError) + return launch_data_new_fd(DNSServiceRefSockFD(service)); + + fprintf(stderr, "DNSServiceRegister(\"%s\"): %d\n", serv, error); + return NULL; +} + +static CFPropertyListRef CreateMyPropertyListFromFile(const char *posixfile) +{ + CFPropertyListRef propertyList; + CFStringRef errorString; + CFDataRef resourceData; + SInt32 errorCode; + CFURLRef fileURL; + + fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, posixfile, strlen(posixfile), false); + if (!fileURL) + fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile); + if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) + fprintf(stderr, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), posixfile, (int)errorCode); + propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainers, &errorString); + if (!propertyList) + fprintf(stderr, "%s: propertyList is NULL\n", getprogname()); + + return propertyList; +} + +static void WriteMyPropertyListToFile(CFPropertyListRef plist, const char *posixfile) +{ + CFDataRef resourceData; + CFURLRef fileURL; + SInt32 errorCode; + + fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, posixfile, strlen(posixfile), false); + if (!fileURL) + fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile); + resourceData = CFPropertyListCreateXMLData(kCFAllocatorDefault, plist); + if (resourceData == NULL) + fprintf(stderr, "%s: CFPropertyListCreateXMLData(%s) failed", getprogname(), posixfile); + if (!CFURLWriteDataAndPropertiesToResource(fileURL, resourceData, NULL, &errorCode)) + fprintf(stderr, "%s: CFURLWriteDataAndPropertiesToResource(%s) failed: %d\n", getprogname(), posixfile, (int)errorCode); +} + +void myCFDictionaryApplyFunction(const void *key, const void *value, void *context) +{ + launch_data_t ik, iw, where = context; + + ik = CF2launch_data(key); + iw = CF2launch_data(value); + + launch_data_dict_insert(where, iw, launch_data_get_string(ik)); + launch_data_free(ik); +} + +static launch_data_t CF2launch_data(CFTypeRef cfr) +{ + launch_data_t r; + CFTypeID cft = CFGetTypeID(cfr); + + if (cft == CFStringGetTypeID()) { + char buf[4096]; + CFStringGetCString(cfr, buf, sizeof(buf), kCFStringEncodingUTF8); + r = launch_data_alloc(LAUNCH_DATA_STRING); + launch_data_set_string(r, buf); + } else if (cft == CFBooleanGetTypeID()) { + r = launch_data_alloc(LAUNCH_DATA_BOOL); + launch_data_set_bool(r, CFBooleanGetValue(cfr)); + } else if (cft == CFArrayGetTypeID()) { + CFIndex i, ac = CFArrayGetCount(cfr); + r = launch_data_alloc(LAUNCH_DATA_ARRAY); + for (i = 0; i < ac; i++) { + CFTypeRef v = CFArrayGetValueAtIndex(cfr, i); + if (v) { + launch_data_t iv = CF2launch_data(v); + launch_data_array_set_index(r, iv, i); + } + } + } else if (cft == CFDictionaryGetTypeID()) { + r = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + CFDictionaryApplyFunction(cfr, myCFDictionaryApplyFunction, r); + } else if (cft == CFDataGetTypeID()) { + r = launch_data_alloc(LAUNCH_DATA_ARRAY); + launch_data_set_opaque(r, CFDataGetBytePtr(cfr), CFDataGetLength(cfr)); + } else if (cft == CFNumberGetTypeID()) { + long long n; + double d; + CFNumberType cfnt = CFNumberGetType(cfr); + switch (cfnt) { + case kCFNumberSInt8Type: + case kCFNumberSInt16Type: + case kCFNumberSInt32Type: + case kCFNumberSInt64Type: + case kCFNumberCharType: + case kCFNumberShortType: + case kCFNumberIntType: + case kCFNumberLongType: + case kCFNumberLongLongType: + CFNumberGetValue(cfr, kCFNumberLongLongType, &n); + r = launch_data_alloc(LAUNCH_DATA_INTEGER); + launch_data_set_integer(r, n); + break; + case kCFNumberFloat32Type: + case kCFNumberFloat64Type: + case kCFNumberFloatType: + case kCFNumberDoubleType: + CFNumberGetValue(cfr, kCFNumberDoubleType, &d); + r = launch_data_alloc(LAUNCH_DATA_REAL); + launch_data_set_real(r, d); + break; + default: + r = NULL; + break; + } + } else { + r = NULL; + } + return r; +} + +static int help_cmd(int argc, char *const argv[]) +{ + FILE *where = stdout; + int l, cmdwidth = 0; + size_t i; + + if (argc == 0 || argv == NULL) + where = stderr; + + fprintf(where, "usage: %s \n", getprogname()); + for (i = 0; i < (sizeof cmds / sizeof cmds[0]); i++) { + l = strlen(cmds[i].name); + if (l > cmdwidth) + cmdwidth = l; + } + for (i = 0; i < (sizeof cmds / sizeof cmds[0]); i++) + fprintf(where, "\t%-*s\t%s\n", cmdwidth, cmds[i].name, cmds[i].desc); + + return 0; +} + +static int _fd(int fd) +{ + if (fd >= 0) + fcntl(fd, F_SETFD, 1); + return fd; +} + +static int load_and_unload_cmd(int argc, char *const argv[]) +{ + launch_data_t pass1, pass2; + int i, ch; + bool wflag = false; + bool lflag = false; + + if (!strcmp(argv[0], "load")) + lflag = true; + + while ((ch = getopt(argc, argv, "w")) != -1) { + switch (ch) { + case 'w': + wflag = true; + break; + default: + fprintf(stderr, "usage: %s load [-w] paths...\n", getprogname()); + return 1; + } + } + argc -= optind; + argv += optind; + + if (argc == 0) { + fprintf(stderr, "usage: %s load [-w] paths...\n", getprogname()); + return 1; + } + + /* I wish I didn't need to do two passes, but I need to load mDNSResponder and use it too. + * + * In later versions of launchd, I hope to load everything in the first pass, + * then do the Bonjour magic on the jobs that need it, and reload them, but for now, + * I haven't thought through the various complexities of reloading jobs, and therefore + * launchd doesn't have reload support right now. + */ + + pass1 = launch_data_alloc(LAUNCH_DATA_ARRAY); + pass2 = launch_data_alloc(LAUNCH_DATA_ARRAY); + + for (i = 0; i < argc; i++) + readpath(argv[i], pass1, pass2, wflag, lflag); + + if (0 == launch_data_array_get_count(pass1) && 0 == launch_data_array_get_count(pass2)) { + fprintf(stderr, "nothing found to %s\n", lflag ? "load" : "unload"); + launch_data_free(pass1); + launch_data_free(pass2); + return 1; + } + + if (lflag) { + if (0 < launch_data_array_get_count(pass1)) { + submit_job_pass(pass1); + } + if (0 < launch_data_array_get_count(pass2)) { + submit_job_pass(pass2); + } + } else { + for (i = 0; i < (int)launch_data_array_get_count(pass1); i++) + unloadjob(launch_data_array_get_index(pass1, i)); + for (i = 0; i < (int)launch_data_array_get_count(pass2); i++) + unloadjob(launch_data_array_get_index(pass2, i)); + } + + return 0; +} + +static void submit_job_pass(launch_data_t jobs) +{ + launch_data_t msg, resp; + size_t i; + int e; + + for (i = 0; i < launch_data_array_get_count(jobs); i++) + distill_config_file(launch_data_array_get_index(jobs, i)); + + msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + + launch_data_dict_insert(msg, jobs, LAUNCH_KEY_SUBMITJOB); + + resp = launch_msg(msg); + + if (resp) { + switch (launch_data_get_type(resp)) { + case LAUNCH_DATA_ERRNO: + if ((e = launch_data_get_errno(resp))) + fprintf(stderr, "%s\n", strerror(e)); + break; + case LAUNCH_DATA_ARRAY: + for (i = 0; i < launch_data_array_get_count(jobs); i++) { + launch_data_t obatind = launch_data_array_get_index(resp, i); + launch_data_t jatind = launch_data_array_get_index(jobs, i); + const char *lab4job = launch_data_get_string(launch_data_dict_lookup(jatind, LAUNCH_JOBKEY_LABEL)); + if (LAUNCH_DATA_ERRNO == launch_data_get_type(obatind)) { + e = launch_data_get_errno(obatind); + switch (e) { + case EEXIST: + fprintf(stderr, "%s: %s\n", lab4job, "Already loaded"); + break; + case ESRCH: + fprintf(stderr, "%s: %s\n", lab4job, "Not loaded"); + break; + default: + fprintf(stderr, "%s: %s\n", lab4job, strerror(e)); + case 0: + break; + } + } + } + break; + default: + fprintf(stderr, "unknown respose from launchd!\n"); + break; + } + launch_data_free(resp); + } else { + fprintf(stderr, "launch_msg(): %s\n", strerror(errno)); + } + + launch_data_free(msg); +} + +static int start_and_stop_cmd(int argc, char *const argv[]) +{ + launch_data_t resp, msg; + const char *lmsgcmd = LAUNCH_KEY_STOPJOB; + int e, r = 0; + + if (!strcmp(argv[0], "start")) + lmsgcmd = LAUNCH_KEY_STARTJOB; + + if (argc != 2) { + fprintf(stderr, "usage: %s %s \n", getprogname(), argv[0]); + return 1; + } + + msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + launch_data_dict_insert(msg, launch_data_new_string(argv[1]), lmsgcmd); + + resp = launch_msg(msg); + launch_data_free(msg); + + if (resp == NULL) { + fprintf(stderr, "launch_msg(): %s\n", strerror(errno)); + return 1; + } else if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) { + if ((e = launch_data_get_errno(resp))) { + fprintf(stderr, "%s %s error: %s\n", getprogname(), argv[0], strerror(e)); + r = 1; + } + } else { + fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]); + r = 1; + } + + launch_data_free(resp); + return r; +} + +static void print_jobs(launch_data_t j __attribute__((unused)), const char *label, void *context __attribute__((unused))) +{ + fprintf(stdout, "%s\n", label); +} + +static int list_cmd(int argc, char *const argv[]) +{ + launch_data_t resp, msg; + int ch, r = 0; + bool vflag = false; + + while ((ch = getopt(argc, argv, "v")) != -1) { + switch (ch) { + case 'v': + vflag = true; + break; + default: + fprintf(stderr, "usage: %s list [-v]\n", getprogname()); + return 1; + } + } + + if (vflag) { + fprintf(stderr, "usage: %s list: \"-v\" flag not implemented yet\n", getprogname()); + return 1; + } + + msg = launch_data_new_string(LAUNCH_KEY_GETJOBS); + resp = launch_msg(msg); + launch_data_free(msg); + + if (resp == NULL) { + fprintf(stderr, "launch_msg(): %s\n", strerror(errno)); + return 1; + } else if (launch_data_get_type(resp) == LAUNCH_DATA_DICTIONARY) { + launch_data_dict_iterate(resp, print_jobs, NULL); + } else { + fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]); + r = 1; + } + + launch_data_free(resp); + + return r; +} + +static int stdio_cmd(int argc, char *const argv[]) +{ + launch_data_t resp, msg, tmp; + int e, fd = -1, r = 0; + + if (argc != 2) { + fprintf(stderr, "usage: %s %s \n", getprogname(), argv[0]); + return 1; + } + + fd = open(argv[1], O_CREAT|O_APPEND|O_WRONLY, DEFFILEMODE); + + msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + + if (fd == -1) { + tmp = launch_data_new_string(argv[1]); + } else { + tmp = launch_data_new_fd(fd); + } + + if (!strcmp(argv[0], "stdout")) { + launch_data_dict_insert(msg, tmp, LAUNCH_KEY_SETSTDOUT); + } else { + launch_data_dict_insert(msg, tmp, LAUNCH_KEY_SETSTDERR); + } + + resp = launch_msg(msg); + launch_data_free(msg); + + if (resp == NULL) { + fprintf(stderr, "launch_msg(): %s\n", strerror(errno)); + return 1; + } else if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) { + if ((e = launch_data_get_errno(resp))) { + fprintf(stderr, "%s %s error: %s\n", getprogname(), argv[0], strerror(e)); + r = 1; + } + } else { + fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]); + r = 1; + } + + if (fd != -1) + close(fd); + + launch_data_free(resp); + + return r; +} + +static int fyi_cmd(int argc, char *const argv[]) +{ + launch_data_t resp, msg; + const char *lmsgk = LAUNCH_KEY_RELOADTTYS; + int e, r = 0; + + if (argc != 1) { + fprintf(stderr, "usage: %s %s\n", getprogname(), argv[0]); + return 1; + } + + if (!strcmp(argv[0], "shutdown")) + lmsgk = LAUNCH_KEY_SHUTDOWN; + + msg = launch_data_new_string(lmsgk); + resp = launch_msg(msg); + launch_data_free(msg); + + if (resp == NULL) { + fprintf(stderr, "launch_msg(): %s\n", strerror(errno)); + return 1; + } else if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) { + if ((e = launch_data_get_errno(resp))) { + fprintf(stderr, "%s %s error: %s\n", getprogname(), argv[0], strerror(e)); + r = 1; + } + } else { + fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]); + r = 1; + } + + launch_data_free(resp); + + return r; +} + +static int logupdate_cmd(int argc, char *const argv[]) +{ + launch_data_t resp, msg; + int e, i, j, r = 0, m = 0; + bool badargs = false, maskmode = false, onlymode = false, levelmode = false; + const char *whichcmd = LAUNCH_KEY_SETLOGMASK; + static const struct { + const char *name; + int level; + } logtbl[] = { + { "debug", LOG_DEBUG }, + { "info", LOG_INFO }, + { "notice", LOG_NOTICE }, + { "warning", LOG_WARNING }, + { "error", LOG_ERR }, + { "critical", LOG_CRIT }, + { "alert", LOG_ALERT }, + { "emergency", LOG_EMERG }, + }; + int logtblsz = sizeof logtbl / sizeof logtbl[0]; + + if (argc >= 2) { + if (!strcmp(argv[1], "mask")) + maskmode = true; + else if (!strcmp(argv[1], "only")) + onlymode = true; + else if (!strcmp(argv[1], "level")) + levelmode = true; + else + badargs = true; + } + + if (maskmode) + m = LOG_UPTO(LOG_DEBUG); + + if (argc > 2 && (maskmode || onlymode)) { + for (i = 2; i < argc; i++) { + for (j = 0; j < logtblsz; j++) { + if (!strcmp(argv[i], logtbl[j].name)) { + if (maskmode) + m &= ~(LOG_MASK(logtbl[j].level)); + else + m |= LOG_MASK(logtbl[j].level); + break; + } + } + if (j == logtblsz) { + badargs = true; + break; + } + } + } else if (argc > 2 && levelmode) { + for (j = 0; j < logtblsz; j++) { + if (!strcmp(argv[2], logtbl[j].name)) { + m = LOG_UPTO(logtbl[j].level); + break; + } + } + if (j == logtblsz) + badargs = true; + } else if (argc == 1) { + whichcmd = LAUNCH_KEY_GETLOGMASK; + } else { + badargs = true; + } + + if (badargs) { + fprintf(stderr, "usage: %s [[mask loglevels...] | [only loglevels...] [level loglevel]]\n", getprogname()); + return 1; + } + + if (whichcmd == LAUNCH_KEY_SETLOGMASK) { + msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + launch_data_dict_insert(msg, launch_data_new_integer(m), whichcmd); + } else { + msg = launch_data_new_string(whichcmd); + } + + resp = launch_msg(msg); + launch_data_free(msg); + + if (resp == NULL) { + fprintf(stderr, "launch_msg(): %s\n", strerror(errno)); + return 1; + } else if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) { + if ((e = launch_data_get_errno(resp))) { + fprintf(stderr, "%s %s error: %s\n", getprogname(), argv[0], strerror(e)); + r = 1; + } + } else if (launch_data_get_type(resp) == LAUNCH_DATA_INTEGER) { + if (whichcmd == LAUNCH_KEY_GETLOGMASK) { + m = launch_data_get_integer(resp); + for (j = 0; j < logtblsz; j++) { + if (m & LOG_MASK(logtbl[j].level)) + fprintf(stdout, "%s ", logtbl[j].name); + } + fprintf(stdout, "\n"); + } + } else { + fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]); + r = 1; + } + + launch_data_free(resp); + + return r; +} + +static int limit_cmd(int argc __attribute__((unused)), char *const argv[]) +{ + char slimstr[100]; + char hlimstr[100]; + struct rlimit *lmts = NULL; + launch_data_t resp, resp1 = NULL, msg, tmp; + int r = 0; + size_t i, lsz = -1, which = 0; + rlim_t slim = -1, hlim = -1; + bool badargs = false; + static const struct { + const char *name; + int lim; + } limlookup[] = { + { "cpu", RLIMIT_CPU }, + { "filesize", RLIMIT_FSIZE }, + { "data", RLIMIT_DATA }, + { "stack", RLIMIT_STACK }, + { "core", RLIMIT_CORE }, + { "rss", RLIMIT_RSS }, + { "memlock", RLIMIT_MEMLOCK }, + { "maxproc", RLIMIT_NPROC }, + { "maxfiles", RLIMIT_NOFILE } + }; + size_t limlookupcnt = sizeof limlookup / sizeof limlookup[0]; + bool name2num(const char *n) { + for (i = 0; i < limlookupcnt; i++) { + if (!strcmp(limlookup[i].name, n)) { + which = limlookup[i].lim; + return false; + } + } + return true; + }; + const char *num2name(int n) { + for (i = 0; i < limlookupcnt; i++) { + if (limlookup[i].lim == n) + return limlookup[i].name; + } + return NULL; + }; + const char *lim2str(rlim_t val, char *buf) { + if (val == RLIM_INFINITY) + strcpy(buf, "unlimited"); + else + sprintf(buf, "%lld", val); + return buf; + }; + bool str2lim(const char *buf, rlim_t *res) { + char *endptr; + *res = strtoll(buf, &endptr, 10); + if (!strcmp(buf, "unlimited")) { + *res = RLIM_INFINITY; + return false; + } else if (*endptr == '\0') { + return false; + } + return true; + }; + + if (argc > 4) + badargs = true; + + if (argc >= 3 && str2lim(argv[2], &slim)) + badargs = true; + else + hlim = slim; + + if (argc == 4 && str2lim(argv[3], &hlim)) + badargs = true; + + if (argc >= 2 && name2num(argv[1])) + badargs = true; + + if (badargs) { + fprintf(stderr, "usage: %s %s [", getprogname(), argv[0]); + for (i = 0; i < limlookupcnt; i++) + fprintf(stderr, "%s %s", limlookup[i].name, (i + 1) == limlookupcnt ? "" : "| "); + fprintf(stderr, "[both | soft hard]]\n"); + return 1; + } + + msg = launch_data_new_string(LAUNCH_KEY_GETRESOURCELIMITS); + resp = launch_msg(msg); + launch_data_free(msg); + + if (resp == NULL) { + fprintf(stderr, "launch_msg(): %s\n", strerror(errno)); + return 1; + } else if (launch_data_get_type(resp) == LAUNCH_DATA_OPAQUE) { + lmts = launch_data_get_opaque(resp); + lsz = launch_data_get_opaque_size(resp); + if (argc <= 2) { + for (i = 0; i < (lsz / sizeof(struct rlimit)); i++) { + if (argc == 2 && which != i) + continue; + fprintf(stdout, "\t%-12s%-15s%-15s\n", num2name(i), + lim2str(lmts[i].rlim_cur, slimstr), + lim2str(lmts[i].rlim_max, hlimstr)); + } + } + } else if (launch_data_get_type(resp) == LAUNCH_DATA_STRING) { + fprintf(stderr, "%s %s error: %s\n", getprogname(), argv[0], launch_data_get_string(resp)); + r = 1; + } else { + fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]); + r = 1; + } + + if (argc <= 2 || r != 0) { + launch_data_free(resp); + return r; + } else { + resp1 = resp; + } + + lmts[which].rlim_cur = slim; + lmts[which].rlim_max = hlim; + + msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + tmp = launch_data_new_opaque(lmts, lsz); + launch_data_dict_insert(msg, tmp, LAUNCH_KEY_SETRESOURCELIMITS); + resp = launch_msg(msg); + launch_data_free(msg); + + if (resp == NULL) { + fprintf(stderr, "launch_msg(): %s\n", strerror(errno)); + return 1; + } else if (launch_data_get_type(resp) == LAUNCH_DATA_STRING) { + fprintf(stderr, "%s %s error: %s\n", getprogname(), argv[0], launch_data_get_string(resp)); + r = 1; + } else if (launch_data_get_type(resp) != LAUNCH_DATA_OPAQUE) { + fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]); + r = 1; + } + + launch_data_free(resp); + launch_data_free(resp1); + + return r; +} + +static int umask_cmd(int argc, char *const argv[]) +{ + launch_data_t resp, msg; + bool badargs = false; + char *endptr; + long m = 0; + int r = 0; + + if (argc == 2) { + m = strtol(argv[1], &endptr, 8); + if (*endptr != '\0' || m > 0777) + badargs = true; + } + + if (argc > 2 || badargs) { + fprintf(stderr, "usage: %s %s \n", getprogname(), argv[0]); + return 1; + } + + + if (argc == 1) { + msg = launch_data_new_string(LAUNCH_KEY_GETUMASK); + } else { + msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + launch_data_dict_insert(msg, launch_data_new_integer(m), LAUNCH_KEY_SETUMASK); + } + resp = launch_msg(msg); + launch_data_free(msg); + + if (resp == NULL) { + fprintf(stderr, "launch_msg(): %s\n", strerror(errno)); + return 1; + } else if (launch_data_get_type(resp) == LAUNCH_DATA_STRING) { + fprintf(stderr, "%s %s error: %s\n", getprogname(), argv[0], launch_data_get_string(resp)); + r = 1; + } else if (launch_data_get_type(resp) != LAUNCH_DATA_INTEGER) { + fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]); + r = 1; + } else if (argc == 1) { + fprintf(stdout, "%o\n", (unsigned int)launch_data_get_integer(resp)); + } + + launch_data_free(resp); + + return r; +} + +static int getrusage_cmd(int argc, char *const argv[]) +{ + launch_data_t resp, msg; + bool badargs = false; + int r = 0; + + if (argc != 2) + badargs = true; + else if (strcmp(argv[1], "self") && strcmp(argv[1], "children")) + badargs = true; + + if (badargs) { + fprintf(stderr, "usage: %s %s self | children\n", getprogname(), argv[0]); + return 1; + } + + if (!strcmp(argv[1], "self")) { + msg = launch_data_new_string(LAUNCH_KEY_GETRUSAGESELF); + } else { + msg = launch_data_new_string(LAUNCH_KEY_GETRUSAGECHILDREN); + } + + resp = launch_msg(msg); + launch_data_free(msg); + + if (resp == NULL) { + fprintf(stderr, "launch_msg(): %s\n", strerror(errno)); + return 1; + } else if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) { + fprintf(stderr, "%s %s error: %s\n", getprogname(), argv[0], strerror(launch_data_get_errno(resp))); + r = 1; + } else if (launch_data_get_type(resp) == LAUNCH_DATA_OPAQUE) { + struct rusage *rusage = launch_data_get_opaque(resp); + fprintf(stdout, "\t%-10f\tuser time used\n", + (double)rusage->ru_utime.tv_sec + (double)rusage->ru_utime.tv_usec / (double)1000000); + fprintf(stdout, "\t%-10f\tsystem time used\n", + (double)rusage->ru_stime.tv_sec + (double)rusage->ru_stime.tv_usec / (double)1000000); + fprintf(stdout, "\t%-10ld\tmax resident set size\n", rusage->ru_maxrss); + fprintf(stdout, "\t%-10ld\tshared text memory size\n", rusage->ru_ixrss); + fprintf(stdout, "\t%-10ld\tunshared data size\n", rusage->ru_idrss); + fprintf(stdout, "\t%-10ld\tunshared stack size\n", rusage->ru_isrss); + fprintf(stdout, "\t%-10ld\tpage reclaims\n", rusage->ru_minflt); + fprintf(stdout, "\t%-10ld\tpage faults\n", rusage->ru_majflt); + fprintf(stdout, "\t%-10ld\tswaps\n", rusage->ru_nswap); + fprintf(stdout, "\t%-10ld\tblock input operations\n", rusage->ru_inblock); + fprintf(stdout, "\t%-10ld\tblock output operations\n", rusage->ru_oublock); + fprintf(stdout, "\t%-10ld\tmessages sent\n", rusage->ru_msgsnd); + fprintf(stdout, "\t%-10ld\tmessages received\n", rusage->ru_msgrcv); + fprintf(stdout, "\t%-10ld\tsignals received\n", rusage->ru_nsignals); + fprintf(stdout, "\t%-10ld\tvoluntary context switches\n", rusage->ru_nvcsw); + fprintf(stdout, "\t%-10ld\tinvoluntary context switches\n", rusage->ru_nivcsw); + } else { + fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]); + r = 1; + } + + launch_data_free(resp); + + return r; +} + +static bool launch_data_array_append(launch_data_t a, launch_data_t o) +{ + size_t offt = launch_data_array_get_count(a); + + return launch_data_array_set_index(a, o, offt); +} diff --git a/launchd/src/launchd.8 b/launchd/src/launchd.8 new file mode 100644 index 0000000..e1d3e51 --- /dev/null +++ b/launchd/src/launchd.8 @@ -0,0 +1,69 @@ +.Dd September 30, 2004 +.Dt launchd 8 +.Os Darwin +.Sh NAME +.Nm launchd +.Nd System wide and per-user daemon/agent manager +.Sh SYNOPSIS +.Nm +.Op Fl v +.Op Fl s +.Op Fl x +.Op Ar -- command Op Ar args ... +.Sh DESCRIPTION +.Nm +manages daemons, both for the system as a whole and for individual users. Ideal daemons can launch +on demand based on criteria specified in their respective XML property lists located in one of the +directories specified in the FILES section. +.Pp +When run with a command, a specific instance of +.Nm +is created and the command is implicitly added to the list of jobs maintained by +.Nm . +If the command exits, that instance of +.Nm +will clean up all jobs maintained by itself and exit. All children of the command will use that +instance of +.Nm . +.Pp +During boot +.Nm +is invoked by the kernel to run as the first process on the system and to further bootstrap the rest of the system. +.Sh OPTIONS WHEN RUN AS PID 1 +.Bl -tag -width -indent +.It Fl v +Verbose boot. +.It Fl s +Single user mode. Instructs +.Nm launchd +to give a shell prompt before booting the system. +.It Fl x +Safe mode boot. Instructs the system to boot conservatively. +.El +.Sh NOTES +In Darwin it is preferable to have your daemon launch via launchd instead of modifying +.Nm rc +or creating a +.Nm SystemStarter +Startup Item. +.Pp +At some point in the future, we hope to completely phase out the use of +.Nm rc . +.Sh FILES +.Bl -tag -width "/System/Library/LaunchDaemons" -compact +.It Pa ~/Library/LaunchAgents +Per-user agents provided by the user. +.It Pa /Library/LaunchAgents +Per-user agents provided by the administrator. +.It Pa /Library/LaunchDaemons +System wide daemons provided by the administrator. +.It Pa /System/Library/LaunchAgents +Mac OS X Per-user agents. +.It Pa /System/Library/LaunchDaemons +Mac OS X System wide daemons. +.El +.Sh SEE ALSO +.Xr launchctl 1 , +.Xr launchd.plist 5 , +.Xr rc 8 , +.Xr SystemStarter 8 diff --git a/launchd/src/launchd.c b/launchd/src/launchd.c new file mode 100644 index 0000000..7078394 --- /dev/null +++ b/launchd/src/launchd.c @@ -0,0 +1,2371 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include +#ifdef EVFILT_MACH_IMPLEMENTED +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "launch.h" +#include "launch_priv.h" +#include "launchd.h" + +#include "bootstrap_internal.h" + +#define LAUNCHD_MIN_JOB_RUN_TIME 10 +#define LAUNCHD_REWARD_JOB_RUN_TIME 60 +#define LAUNCHD_FAILED_EXITS_THRESHOLD 10 +#define PID1LAUNCHD_CONF "/etc/launchd.conf" +#define LAUNCHD_CONF ".launchd.conf" +#define LAUNCHCTL_PATH "/bin/launchctl" +#define SECURITY_LIB "/System/Library/Frameworks/Security.framework/Versions/A/Security" +#define VOLFSDIR "/.vol" + +extern char **environ; + +struct jobcb { + kq_callback kqjob_callback; + TAILQ_ENTRY(jobcb) tqe; + launch_data_t ldj; + pid_t p; + int execfd; + time_t start_time; + size_t failed_exits; + int *vnodes; + size_t vnodes_cnt; + int *qdirs; + size_t qdirs_cnt; + unsigned int start_interval; + struct tm *start_cal_interval; + unsigned int checkedin:1, firstborn:1, debug:1, throttle:1, futureflags:28; + char label[0]; +}; + +struct conncb { + kq_callback kqconn_callback; + TAILQ_ENTRY(conncb) tqe; + launch_t conn; + struct jobcb *j; + int disabled_batch:1, futureflags:31; +}; + +static TAILQ_HEAD(jobcbhead, jobcb) jobs = TAILQ_HEAD_INITIALIZER(jobs); +static TAILQ_HEAD(conncbhead, conncb) connections = TAILQ_HEAD_INITIALIZER(connections); +static int mainkq = 0; +static int asynckq = 0; +static int batch_disabler_count = 0; + +static launch_data_t load_job(launch_data_t pload); +static launch_data_t get_jobs(const char *which); +static launch_data_t setstdio(int d, launch_data_t o); +static launch_data_t adjust_rlimits(launch_data_t in); +static void batch_job_enable(bool e, struct conncb *c); +static void do_shutdown(void); + +static void listen_callback(void *, struct kevent *); +static void async_callback(void); +static void signal_callback(void *, struct kevent *); +static void fs_callback(void); +static void simple_zombie_reaper(void *, struct kevent *); +static void readcfg_callback(void *, struct kevent *); + +static kq_callback kqlisten_callback = listen_callback; +static kq_callback kqasync_callback = (kq_callback)async_callback; +static kq_callback kqsignal_callback = signal_callback; +static kq_callback kqfs_callback = (kq_callback)fs_callback; +static kq_callback kqreadcfg_callback = readcfg_callback; +kq_callback kqsimple_zombie_reaper = simple_zombie_reaper; + +static void job_watch(struct jobcb *j); +static void job_ignore(struct jobcb *j); +static void job_start(struct jobcb *j); +static void job_start_child(struct jobcb *j, int execfd); +static void job_setup_attributes(struct jobcb *j); +static void job_stop(struct jobcb *j); +static void job_reap(struct jobcb *j); +static void job_remove(struct jobcb *j); +static void job_set_alarm(struct jobcb *j); +static void job_callback(void *obj, struct kevent *kev); +static void job_log(struct jobcb *j, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4))); +static void job_log_error(struct jobcb *j, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4))); + +static void ipc_open(int fd, struct jobcb *j); +static void ipc_close(struct conncb *c); +static void ipc_callback(void *, struct kevent *); +static void ipc_readmsg(launch_data_t msg, void *context); +static void ipc_readmsg2(launch_data_t data, const char *cmd, void *context); + +#ifdef PID1_REAP_ADOPTED_CHILDREN +static void pid1waitpid(void); +static bool launchd_check_pid(pid_t p); +#endif +static void pid1_magic_init(bool sflag, bool vflag, bool xflag); +static void launchd_server_init(bool create_session); +static void conceive_firstborn(char *argv[]); + +#ifdef EVFILT_MACH_IMPLEMENTED +static void *mach_demand_loop(void *); +static void mach_callback(void *, struct kevent *); +static kq_callback kqmach_callback = mach_callback; +#endif + +static void usage(FILE *where); +static int _fd(int fd); + +static void loopback_setup(void); +static void workaround3048875(int argc, char *argv[]); +static void reload_launchd_config(void); +static int dir_has_files(const char *path); +static void setup_job_env(launch_data_t obj, const char *key, void *context); +static void unsetup_job_env(launch_data_t obj, const char *key, void *context); + + +static size_t total_children = 0; +static pid_t readcfg_pid = 0; +static bool launchd_inited = false; +static bool shutdown_in_progress = false; +static pthread_t mach_server_loop_thread; +mach_port_t launchd_bootstrap_port = MACH_PORT_NULL; +sigset_t blocked_signals = 0; +static char *pending_stdout = NULL; +static char *pending_stderr = NULL; + +int main(int argc, char *argv[]) +{ + static const int sigigns[] = { SIGHUP, SIGINT, SIGPIPE, SIGALRM, + SIGTERM, SIGURG, SIGTSTP, SIGTSTP, SIGCONT, /*SIGCHLD,*/ + SIGTTIN, SIGTTOU, SIGIO, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, + SIGWINCH, SIGINFO, SIGUSR1, SIGUSR2 }; + void testfd_or_openfd(int fd, const char *path, int flags) { + int tmpfd; + + if (-1 != (tmpfd = dup(fd))) { + close(tmpfd); + } else { + if (-1 == (tmpfd = open(path, flags))) { + syslog(LOG_ERR, "open(\"%s\", ...): %m", path); + } else if (tmpfd != fd) { + dup2(tmpfd, fd); + close(tmpfd); + } + } + }; + struct kevent kev; + size_t i; + bool sflag = false, xflag = false, vflag = false, dflag = false; + int ch; + + if (getpid() == 1) + workaround3048875(argc, argv); + + setegid(getgid()); + seteuid(getuid()); + + testfd_or_openfd(STDIN_FILENO, _PATH_DEVNULL, O_RDONLY); + testfd_or_openfd(STDOUT_FILENO, _PATH_DEVNULL, O_WRONLY); + testfd_or_openfd(STDERR_FILENO, _PATH_DEVNULL, O_WRONLY); + + openlog(getprogname(), LOG_CONS|(getpid() != 1 ? LOG_PID|LOG_PERROR : 0), LOG_LAUNCHD); + setlogmask(LOG_UPTO(LOG_NOTICE)); + + while ((ch = getopt(argc, argv, "dhsvx")) != -1) { + switch (ch) { + case 'd': dflag = true; break; + case 's': sflag = true; break; + case 'x': xflag = true; break; + case 'v': vflag = true; break; + case 'h': usage(stdout); break; + default: + syslog(LOG_WARNING, "ignoring unknown arguments"); + usage(stderr); + break; + } + } + argc -= optind; + argv += optind; + + if (dflag && daemon(0, 0) == -1) + syslog(LOG_WARNING, "couldn't daemonize: %m"); + + if ((mainkq = kqueue()) == -1) { + syslog(LOG_EMERG, "kqueue(): %m"); + abort(); + } + + if ((asynckq = kqueue()) == -1) { + syslog(LOG_ERR, "kqueue(): %m"); + abort(); + } + + if (kevent_mod(asynckq, EVFILT_READ, EV_ADD, 0, 0, &kqasync_callback) == -1) { + syslog(LOG_ERR, "kevent_mod(asynckq, EVFILT_READ): %m"); + abort(); + } + + sigemptyset(&blocked_signals); + + for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) { + if (kevent_mod(sigigns[i], EVFILT_SIGNAL, EV_ADD, 0, 0, &kqsignal_callback) == -1) + syslog(LOG_ERR, "failed to add kevent for signal: %d: %m", sigigns[i]); + sigaddset(&blocked_signals, sigigns[i]); + signal(sigigns[i], SIG_IGN); + } + + /* sigh... ignoring SIGCHLD has side effects: we can't call wait*() */ + if (kevent_mod(SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, &kqsignal_callback) == -1) + syslog(LOG_ERR, "failed to add kevent for signal: %d: %m", SIGCHLD); + + if (getpid() == 1) { + pid1_magic_init(sflag, vflag, xflag); + } else { + launchd_bootstrap_port = bootstrap_port; + launchd_server_init(argv[0] ? true : false); + } + + /* do this after pid1_magic_init() to not catch ourselves mounting stuff */ + if (kevent_mod(0, EVFILT_FS, EV_ADD, 0, 0, &kqfs_callback) == -1) + syslog(LOG_ERR, "kevent_mod(EVFILT_FS, &kqfs_callback): %m"); + + + if (argv[0]) + conceive_firstborn(argv); + + reload_launchd_config(); + + if (argv[0]) + job_start(TAILQ_FIRST(&jobs)); + + for (;;) { + static struct timespec timeout = { 30, 0 }; + struct timespec *timeoutp = NULL; + + if (getpid() == 1) { + if (readcfg_pid == 0) + init_pre_kevent(); + } else { + if (TAILQ_EMPTY(&jobs)) { + /* launched on demand */ + timeoutp = &timeout; + } else if (shutdown_in_progress && total_children == 0) { + exit(EXIT_SUCCESS); + } + } + + switch (kevent(mainkq, NULL, 0, &kev, 1, timeoutp)) { + case -1: + syslog(LOG_DEBUG, "kevent(): %m"); + break; + case 1: + (*((kq_callback *)kev.udata))(kev.udata, &kev); + break; + case 0: + if (timeoutp) + exit(EXIT_SUCCESS); + else + syslog(LOG_DEBUG, "kevent(): spurious return with infinite timeout"); + break; + default: + syslog(LOG_DEBUG, "unexpected: kevent() returned something != 0, -1 or 1"); + break; + } + } +} + +static void pid1_magic_init(bool sflag, bool vflag, bool xflag) +{ + pthread_attr_t attr; + int memmib[2] = { CTL_HW, HW_PHYSMEM }; + int mvnmib[2] = { CTL_KERN, KERN_MAXVNODES }; + int hnmib[2] = { CTL_KERN, KERN_HOSTNAME }; + uint64_t mem = 0; + uint32_t mvn; + size_t memsz = sizeof(mem); + int pthr_r; + + setpriority(PRIO_PROCESS, 0, -1); + + if (setsid() == -1) + syslog(LOG_ERR, "setsid(): %m"); + + if (chdir("/") == -1) + syslog(LOG_ERR, "chdir(\"/\"): %m"); + + if (sysctl(memmib, 2, &mem, &memsz, NULL, 0) == -1) { + syslog(LOG_WARNING, "sysctl(\"%s\"): %m", "hw.physmem"); + } else { + /* The following assignment of mem to itself if the size + * of data returned is 32 bits instead of 64 is a clever + * C trick to move the 32 bits on big endian systems to + * the least significant bytes of the 64 mem variable. + * + * On little endian systems, this is effectively a no-op. + */ + if (memsz == 4) + mem = *(uint32_t *)&mem; + mvn = mem / (64 * 1024) + 1024; + if (sysctl(mvnmib, 2, NULL, NULL, &mvn, sizeof(mvn)) == -1) + syslog(LOG_WARNING, "sysctl(\"%s\"): %m", "kern.maxvnodes"); + } + if (sysctl(hnmib, 2, NULL, NULL, "localhost", sizeof("localhost")) == -1) + syslog(LOG_WARNING, "sysctl(\"%s\"): %m", "kern.hostname"); + + if (setlogin("root") == -1) + syslog(LOG_ERR, "setlogin(\"root\"): %m"); + + loopback_setup(); + + if (mount("fdesc", "/dev", MNT_UNION, NULL) == -1) + syslog(LOG_ERR, "mount(\"%s\", \"%s\", ...): %m", "fdesc", "/dev/"); + + setenv("PATH", _PATH_STDPATH, 1); + + launchd_bootstrap_port = mach_init_init(); + task_set_bootstrap_port(mach_task_self(), launchd_bootstrap_port); + bootstrap_port = MACH_PORT_NULL; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + pthr_r = pthread_create(&mach_server_loop_thread, &attr, mach_server_loop, NULL); + if (pthr_r != 0) { + syslog(LOG_ERR, "pthread_create(mach_server_loop): %s", strerror(pthr_r)); + exit(EXIT_FAILURE); + } + + pthread_attr_destroy(&attr); + + init_boot(sflag, vflag, xflag); +} + + +#ifdef PID1_REAP_ADOPTED_CHILDREN +static bool launchd_check_pid(pid_t p) +{ + struct kevent kev; + struct jobcb *j; + + TAILQ_FOREACH(j, &jobs, tqe) { + if (j->p == p) { + EV_SET(&kev, p, EVFILT_PROC, 0, 0, 0, j); + j->kqjob_callback(j, &kev); + return true; + } + } + + if (p == readcfg_pid) { + readcfg_callback(NULL, NULL); + return true; + } + + return false; +} +#endif + +static char *sockdir = NULL; +static char *sockpath = NULL; + +static void launchd_clean_up(void) +{ + seteuid(0); + setegid(0); + + if (-1 == unlink(sockpath)) + syslog(LOG_WARNING, "unlink(\"%s\"): %m", sockpath); + else if (-1 == rmdir(sockdir)) + syslog(LOG_WARNING, "rmdir(\"%s\"): %m", sockdir); + + setegid(getgid()); + seteuid(getuid()); +} + +static void launchd_server_init(bool create_session) +{ + struct sockaddr_un sun; + mode_t oldmask; + int r, fd = -1, ourdirfd = -1; + char ourdir[1024]; + + memset(&sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; + + if (create_session) { + snprintf(ourdir, sizeof(ourdir), "%s/%u.%u", LAUNCHD_SOCK_PREFIX, getuid(), getpid()); + snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%u.%u/sock", LAUNCHD_SOCK_PREFIX, getuid(), getpid()); + setenv(LAUNCHD_SOCKET_ENV, sun.sun_path, 1); + } else { + snprintf(ourdir, sizeof(ourdir), "%s/%u", LAUNCHD_SOCK_PREFIX, getuid()); + snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%u/sock", LAUNCHD_SOCK_PREFIX, getuid()); + } + + seteuid(0); + setegid(0); + + if (mkdir(LAUNCHD_SOCK_PREFIX, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) == -1) { + if (errno == EROFS) { + goto out_bad; + } else if (errno == EEXIST) { + struct stat sb; + stat(LAUNCHD_SOCK_PREFIX, &sb); + if (!S_ISDIR(sb.st_mode)) { + errno = EEXIST; + syslog(LOG_ERR, "mkdir(\"%s\"): %m", LAUNCHD_SOCK_PREFIX); + goto out_bad; + } + } else { + syslog(LOG_ERR, "mkdir(\"%s\"): %m", LAUNCHD_SOCK_PREFIX); + goto out_bad; + } + } + + unlink(ourdir); + if (mkdir(ourdir, S_IRWXU) == -1) { + if (errno == EROFS) { + goto out_bad; + } else if (errno == EEXIST) { + struct stat sb; + stat(ourdir, &sb); + if (!S_ISDIR(sb.st_mode)) { + errno = EEXIST; + syslog(LOG_ERR, "mkdir(\"%s\"): %m", LAUNCHD_SOCK_PREFIX); + goto out_bad; + } + } else { + syslog(LOG_ERR, "mkdir(\"%s\"): %m", ourdir); + goto out_bad; + } + } + if (chown(ourdir, getuid(), getgid()) == -1) + syslog(LOG_WARNING, "chown(\"%s\"): %m", ourdir); + + ourdirfd = _fd(open(ourdir, O_RDONLY)); + if (ourdirfd == -1) { + syslog(LOG_ERR, "open(\"%s\"): %m", ourdir); + goto out_bad; + } + + if (flock(ourdirfd, LOCK_EX|LOCK_NB) == -1) { + if (errno == EWOULDBLOCK) { + exit(EXIT_SUCCESS); + } else { + syslog(LOG_ERR, "flock(\"%s\"): %m", ourdir); + goto out_bad; + } + } + + if (unlink(sun.sun_path) == -1 && errno != ENOENT) { + if (errno != EROFS) + syslog(LOG_ERR, "unlink(\"thesocket\"): %m"); + goto out_bad; + } + if ((fd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1) { + syslog(LOG_ERR, "socket(\"thesocket\"): %m"); + goto out_bad; + } + oldmask = umask(077); + r = bind(fd, (struct sockaddr *)&sun, sizeof(sun)); + umask(oldmask); + if (r == -1) { + if (errno != EROFS) + syslog(LOG_ERR, "bind(\"thesocket\"): %m"); + goto out_bad; + } + if (chown(sun.sun_path, getuid(), getgid()) == -1) + syslog(LOG_WARNING, "chown(\"thesocket\"): %m"); + + if (listen(fd, SOMAXCONN) == -1) { + syslog(LOG_ERR, "listen(\"thesocket\"): %m"); + goto out_bad; + } + + if (kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, &kqlisten_callback) == -1) { + syslog(LOG_ERR, "kevent_mod(\"thesocket\", EVFILT_READ): %m"); + goto out_bad; + } + + launchd_inited = true; + + sockdir = strdup(ourdir); + sockpath = strdup(sun.sun_path); + + atexit(launchd_clean_up); + +out_bad: + setegid(getgid()); + seteuid(getuid()); + + if (!launchd_inited) { + if (fd != -1) + close(fd); + if (ourdirfd != -1) + close(ourdirfd); + } +} + +static long long job_get_integer(launch_data_t j, const char *key) +{ + launch_data_t t = launch_data_dict_lookup(j, key); + if (t) + return launch_data_get_integer(t); + else + return 0; +} + +static const char *job_get_string(launch_data_t j, const char *key) +{ + launch_data_t t = launch_data_dict_lookup(j, key); + if (t) + return launch_data_get_string(t); + else + return NULL; +} + +static const char *job_get_file2exec(launch_data_t j) +{ + launch_data_t tmpi, tmp = launch_data_dict_lookup(j, LAUNCH_JOBKEY_PROGRAM); + + if (tmp) { + return launch_data_get_string(tmp); + } else { + tmp = launch_data_dict_lookup(j, LAUNCH_JOBKEY_PROGRAMARGUMENTS); + if (tmp) { + tmpi = launch_data_array_get_index(tmp, 0); + if (tmpi) + return launch_data_get_string(tmpi); + } + return NULL; + } +} + +static bool job_get_bool(launch_data_t j, const char *key) +{ + launch_data_t t = launch_data_dict_lookup(j, key); + if (t) + return launch_data_get_bool(t); + else + return false; +} + +static void ipc_open(int fd, struct jobcb *j) +{ + struct conncb *c = calloc(1, sizeof(struct conncb)); + + fcntl(fd, F_SETFL, O_NONBLOCK); + + c->kqconn_callback = ipc_callback; + c->conn = launchd_fdopen(fd); + c->j = j; + TAILQ_INSERT_TAIL(&connections, c, tqe); + kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, &c->kqconn_callback); +} + +static void simple_zombie_reaper(void *obj __attribute__((unused)), struct kevent *kev) +{ + waitpid(kev->ident, NULL, 0); +} + +static void listen_callback(void *obj __attribute__((unused)), struct kevent *kev) +{ + struct sockaddr_un sun; + socklen_t sl = sizeof(sun); + int cfd; + + if ((cfd = _fd(accept(kev->ident, (struct sockaddr *)&sun, &sl))) == -1) { + return; + } + + ipc_open(cfd, NULL); +} + +static void ipc_callback(void *obj, struct kevent *kev) +{ + struct conncb *c = obj; + int r; + + if (kev->filter == EVFILT_READ) { + if (launchd_msg_recv(c->conn, ipc_readmsg, c) == -1 && errno != EAGAIN) { + if (errno != ECONNRESET) + syslog(LOG_DEBUG, "%s(): recv: %m", __func__); + ipc_close(c); + } + } else if (kev->filter == EVFILT_WRITE) { + r = launchd_msg_send(c->conn, NULL); + if (r == -1) { + if (errno != EAGAIN) { + syslog(LOG_DEBUG, "%s(): send: %m", __func__); + ipc_close(c); + } + } else if (r == 0) { + kevent_mod(launchd_getfd(c->conn), EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + } + } else { + syslog(LOG_DEBUG, "%s(): unknown filter type!", __func__); + ipc_close(c); + } +} + +static void set_user_env(launch_data_t obj, const char *key, void *context __attribute__((unused))) +{ + setenv(key, launch_data_get_string(obj), 1); +} + +static void launch_data_close_fds(launch_data_t o) +{ + size_t i; + + switch (launch_data_get_type(o)) { + case LAUNCH_DATA_DICTIONARY: + launch_data_dict_iterate(o, (void (*)(launch_data_t, const char *, void *))launch_data_close_fds, NULL); + break; + case LAUNCH_DATA_ARRAY: + for (i = 0; i < launch_data_array_get_count(o); i++) + launch_data_close_fds(launch_data_array_get_index(o, i)); + break; + case LAUNCH_DATA_FD: + if (launch_data_get_fd(o) != -1) + close(launch_data_get_fd(o)); + break; + default: + break; + } +} + +static void launch_data_revoke_fds(launch_data_t o) +{ + size_t i; + + switch (launch_data_get_type(o)) { + case LAUNCH_DATA_DICTIONARY: + launch_data_dict_iterate(o, (void (*)(launch_data_t, const char *, void *))launch_data_revoke_fds, NULL); + break; + case LAUNCH_DATA_ARRAY: + for (i = 0; i < launch_data_array_get_count(o); i++) + launch_data_revoke_fds(launch_data_array_get_index(o, i)); + break; + case LAUNCH_DATA_FD: + launch_data_set_fd(o, -1); + break; + default: + break; + } +} + +static void job_ignore_fds(launch_data_t o, const char *key __attribute__((unused)), void *cookie) +{ + struct jobcb *j = cookie; + size_t i; + int fd; + + switch (launch_data_get_type(o)) { + case LAUNCH_DATA_DICTIONARY: + launch_data_dict_iterate(o, job_ignore_fds, cookie); + break; + case LAUNCH_DATA_ARRAY: + for (i = 0; i < launch_data_array_get_count(o); i++) + job_ignore_fds(launch_data_array_get_index(o, i), NULL, cookie); + break; + case LAUNCH_DATA_FD: + fd = launch_data_get_fd(o); + if (-1 != fd) { + job_log(j, LOG_DEBUG, "Ignoring FD: %d", fd); + kevent_mod(fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); + } + break; + default: + break; + } +} + +static void job_ignore(struct jobcb *j) +{ + launch_data_t j_sockets = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_SOCKETS); + size_t i; + + if (j_sockets) + job_ignore_fds(j_sockets, NULL, j); + + for (i = 0; i < j->vnodes_cnt; i++) { + kevent_mod(j->vnodes[i], EVFILT_VNODE, EV_DELETE, 0, 0, NULL); + } + for (i = 0; i < j->qdirs_cnt; i++) { + kevent_mod(j->qdirs[i], EVFILT_VNODE, EV_DELETE, 0, 0, NULL); + } +} + +static void job_watch_fds(launch_data_t o, const char *key __attribute__((unused)), void *cookie) +{ + struct jobcb *j = cookie; + size_t i; + int fd; + + switch (launch_data_get_type(o)) { + case LAUNCH_DATA_DICTIONARY: + launch_data_dict_iterate(o, job_watch_fds, cookie); + break; + case LAUNCH_DATA_ARRAY: + for (i = 0; i < launch_data_array_get_count(o); i++) + job_watch_fds(launch_data_array_get_index(o, i), NULL, cookie); + break; + case LAUNCH_DATA_FD: + fd = launch_data_get_fd(o); + if (-1 != fd) { + job_log(j, LOG_DEBUG, "Watching FD: %d", fd); + kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, cookie); + } + break; + default: + break; + } +} + +static void job_watch(struct jobcb *j) +{ + launch_data_t ld_qdirs = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_QUEUEDIRECTORIES); + launch_data_t ld_vnodes = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_WATCHPATHS); + launch_data_t j_sockets = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_SOCKETS); + size_t i; + + if (j_sockets) + job_watch_fds(j_sockets, NULL, &j->kqjob_callback); + + for (i = 0; i < j->vnodes_cnt; i++) { + if (-1 == j->vnodes[i]) { + launch_data_t ld_idx = launch_data_array_get_index(ld_vnodes, i); + const char *thepath = launch_data_get_string(ld_idx); + + if (-1 == (j->vnodes[i] = _fd(open(thepath, O_EVTONLY)))) + job_log_error(j, LOG_ERR, "open(\"%s\", O_EVTONLY)", thepath); + } + kevent_mod(j->vnodes[i], EVFILT_VNODE, EV_ADD|EV_CLEAR, + NOTE_WRITE|NOTE_EXTEND|NOTE_DELETE|NOTE_RENAME|NOTE_REVOKE|NOTE_ATTRIB|NOTE_LINK, + 0, &j->kqjob_callback); + } + + for (i = 0; i < j->qdirs_cnt; i++) { + kevent_mod(j->qdirs[i], EVFILT_VNODE, EV_ADD|EV_CLEAR, + NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK, 0, &j->kqjob_callback); + } + + for (i = 0; i < j->qdirs_cnt; i++) { + launch_data_t ld_idx = launch_data_array_get_index(ld_qdirs, i); + const char *thepath = launch_data_get_string(ld_idx); + int dcc_r; + + if (-1 == (dcc_r = dir_has_files(thepath))) { + job_log_error(j, LOG_ERR, "dir_has_files(\"%s\", ...)", thepath); + } else if (dcc_r > 0) { + job_start(j); + break; + } + } +} + +static void job_stop(struct jobcb *j) +{ + if (j->p) + kill(j->p, SIGTERM); +} + +static void job_remove(struct jobcb *j) +{ + launch_data_t tmp; + size_t i; + + job_log(j, LOG_DEBUG, "Removed"); + + TAILQ_REMOVE(&jobs, j, tqe); + if (j->p) { + if (kevent_mod(j->p, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, &kqsimple_zombie_reaper) == -1) { + job_reap(j); + } else { + job_stop(j); + } + } + if ((tmp = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES))) + launch_data_dict_iterate(tmp, unsetup_job_env, NULL); + launch_data_close_fds(j->ldj); + launch_data_free(j->ldj); + if (j->execfd) + close(j->execfd); + for (i = 0; i < j->vnodes_cnt; i++) + if (-1 != j->vnodes[i]) + close(j->vnodes[i]); + if (j->vnodes) + free(j->vnodes); + for (i = 0; i < j->qdirs_cnt; i++) + if (-1 != j->qdirs[i]) + close(j->qdirs[i]); + if (j->qdirs) + free(j->qdirs); + if (j->start_interval) + kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); + if (j->start_cal_interval) { + kevent_mod((uintptr_t)j->start_cal_interval, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); + free(j->start_cal_interval); + } + kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); + free(j); +} + +struct readmsg_context { + struct conncb *c; + launch_data_t resp; +}; + +static void ipc_readmsg(launch_data_t msg, void *context) +{ + struct readmsg_context rmc = { context, NULL }; + + if (LAUNCH_DATA_DICTIONARY == launch_data_get_type(msg)) { + launch_data_dict_iterate(msg, ipc_readmsg2, &rmc); + } else if (LAUNCH_DATA_STRING == launch_data_get_type(msg)) { + ipc_readmsg2(NULL, launch_data_get_string(msg), &rmc); + } else { + rmc.resp = launch_data_new_errno(EINVAL); + } + + if (NULL == rmc.resp) + rmc.resp = launch_data_new_errno(ENOSYS); + + launch_data_close_fds(msg); + + if (launchd_msg_send(rmc.c->conn, rmc.resp) == -1) { + if (errno == EAGAIN) { + kevent_mod(launchd_getfd(rmc.c->conn), EVFILT_WRITE, EV_ADD, 0, 0, &rmc.c->kqconn_callback); + } else { + syslog(LOG_DEBUG, "launchd_msg_send() == -1: %m"); + ipc_close(rmc.c); + } + } + launch_data_free(rmc.resp); +} + + +static void ipc_readmsg2(launch_data_t data, const char *cmd, void *context) +{ + struct readmsg_context *rmc = context; + launch_data_t resp = NULL; + struct jobcb *j; + + if (rmc->resp) + return; + + if (!strcmp(cmd, LAUNCH_KEY_STARTJOB)) { + TAILQ_FOREACH(j, &jobs, tqe) { + if (!strcmp(j->label, launch_data_get_string(data))) { + job_start(j); + resp = launch_data_new_errno(0); + } + } + if (NULL == resp) + resp = launch_data_new_errno(ESRCH); + } else if (!strcmp(cmd, LAUNCH_KEY_STOPJOB)) { + TAILQ_FOREACH(j, &jobs, tqe) { + if (!strcmp(j->label, launch_data_get_string(data))) { + job_stop(j); + resp = launch_data_new_errno(0); + } + } + if (NULL == resp) + resp = launch_data_new_errno(ESRCH); + } else if (!strcmp(cmd, LAUNCH_KEY_REMOVEJOB)) { + TAILQ_FOREACH(j, &jobs, tqe) { + if (!strcmp(j->label, launch_data_get_string(data))) { + job_remove(j); + resp = launch_data_new_errno(0); + } + } + if (NULL == resp) + resp = launch_data_new_errno(ESRCH); + } else if (!strcmp(cmd, LAUNCH_KEY_SUBMITJOB)) { + if (launch_data_get_type(data) == LAUNCH_DATA_ARRAY) { + launch_data_t tmp; + size_t i; + + resp = launch_data_alloc(LAUNCH_DATA_ARRAY); + for (i = 0; i < launch_data_array_get_count(data); i++) { + tmp = load_job(launch_data_array_get_index(data, i)); + launch_data_array_set_index(resp, tmp, i); + } + } else { + resp = load_job(data); + } + } else if (!strcmp(cmd, LAUNCH_KEY_UNSETUSERENVIRONMENT)) { + unsetenv(launch_data_get_string(data)); + resp = launch_data_new_errno(0); + } else if (!strcmp(cmd, LAUNCH_KEY_GETUSERENVIRONMENT)) { + char **tmpenviron = environ; + resp = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + for (; *tmpenviron; tmpenviron++) { + char envkey[1024]; + launch_data_t s = launch_data_alloc(LAUNCH_DATA_STRING); + launch_data_set_string(s, strchr(*tmpenviron, '=') + 1); + strncpy(envkey, *tmpenviron, sizeof(envkey)); + *(strchr(envkey, '=')) = '\0'; + launch_data_dict_insert(resp, s, envkey); + } + } else if (!strcmp(cmd, LAUNCH_KEY_SETUSERENVIRONMENT)) { + launch_data_dict_iterate(data, set_user_env, NULL); + resp = launch_data_new_errno(0); + } else if (!strcmp(cmd, LAUNCH_KEY_CHECKIN)) { + if (rmc->c->j) { + resp = launch_data_copy(rmc->c->j->ldj); + if (NULL == launch_data_dict_lookup(resp, LAUNCH_JOBKEY_TIMEOUT)) { + launch_data_t to = launch_data_new_integer(LAUNCHD_MIN_JOB_RUN_TIME); + launch_data_dict_insert(resp, to, LAUNCH_JOBKEY_TIMEOUT); + } + rmc->c->j->checkedin = true; + } else { + resp = launch_data_new_errno(EACCES); + } + } else if (!strcmp(cmd, LAUNCH_KEY_RELOADTTYS)) { + update_ttys(); + resp = launch_data_new_errno(0); + } else if (!strcmp(cmd, LAUNCH_KEY_SHUTDOWN)) { + do_shutdown(); + resp = launch_data_new_errno(0); + } else if (!strcmp(cmd, LAUNCH_KEY_GETJOBS)) { + resp = get_jobs(NULL); + launch_data_revoke_fds(resp); + } else if (!strcmp(cmd, LAUNCH_KEY_GETRESOURCELIMITS)) { + resp = adjust_rlimits(NULL); + } else if (!strcmp(cmd, LAUNCH_KEY_SETRESOURCELIMITS)) { + resp = adjust_rlimits(data); + } else if (!strcmp(cmd, LAUNCH_KEY_GETJOB)) { + resp = get_jobs(launch_data_get_string(data)); + launch_data_revoke_fds(resp); + } else if (!strcmp(cmd, LAUNCH_KEY_GETJOBWITHHANDLES)) { + resp = get_jobs(launch_data_get_string(data)); + } else if (!strcmp(cmd, LAUNCH_KEY_SETLOGMASK)) { + resp = launch_data_new_integer(setlogmask(launch_data_get_integer(data))); + } else if (!strcmp(cmd, LAUNCH_KEY_GETLOGMASK)) { + int oldmask = setlogmask(LOG_UPTO(LOG_DEBUG)); + resp = launch_data_new_integer(oldmask); + setlogmask(oldmask); + } else if (!strcmp(cmd, LAUNCH_KEY_SETUMASK)) { + resp = launch_data_new_integer(umask(launch_data_get_integer(data))); + } else if (!strcmp(cmd, LAUNCH_KEY_GETUMASK)) { + mode_t oldmask = umask(0); + resp = launch_data_new_integer(oldmask); + umask(oldmask); + } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGESELF)) { + struct rusage rusage; + getrusage(RUSAGE_SELF, &rusage); + resp = launch_data_new_opaque(&rusage, sizeof(rusage)); + } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGECHILDREN)) { + struct rusage rusage; + getrusage(RUSAGE_CHILDREN, &rusage); + resp = launch_data_new_opaque(&rusage, sizeof(rusage)); + } else if (!strcmp(cmd, LAUNCH_KEY_SETSTDOUT)) { + resp = setstdio(STDOUT_FILENO, data); + } else if (!strcmp(cmd, LAUNCH_KEY_SETSTDERR)) { + resp = setstdio(STDERR_FILENO, data); + } else if (!strcmp(cmd, LAUNCH_KEY_BATCHCONTROL)) { + batch_job_enable(launch_data_get_bool(data), rmc->c); + resp = launch_data_new_errno(0); + } else if (!strcmp(cmd, LAUNCH_KEY_BATCHQUERY)) { + resp = launch_data_alloc(LAUNCH_DATA_BOOL); + launch_data_set_bool(resp, batch_disabler_count == 0); + } + + rmc->resp = resp; +} + +static launch_data_t setstdio(int d, launch_data_t o) +{ + launch_data_t resp = launch_data_new_errno(0); + + if (launch_data_get_type(o) == LAUNCH_DATA_STRING) { + char **where = &pending_stderr; + if (d == STDOUT_FILENO) + where = &pending_stdout; + if (*where) + free(*where); + *where = strdup(launch_data_get_string(o)); + } else if (launch_data_get_type(o) == LAUNCH_DATA_FD) { + dup2(launch_data_get_fd(o), d); + } else { + launch_data_set_errno(resp, EINVAL); + } + + return resp; +} + +static void batch_job_enable(bool e, struct conncb *c) +{ + if (e && c->disabled_batch) { + batch_disabler_count--; + c->disabled_batch = 0; + if (batch_disabler_count == 0) + kevent_mod(asynckq, EVFILT_READ, EV_ENABLE, 0, 0, &kqasync_callback); + } else if (!e && !c->disabled_batch) { + if (batch_disabler_count == 0) + kevent_mod(asynckq, EVFILT_READ, EV_DISABLE, 0, 0, &kqasync_callback); + batch_disabler_count++; + c->disabled_batch = 1; + } +} + +static launch_data_t load_job(launch_data_t pload) +{ + launch_data_t tmp, resp; + const char *label; + struct jobcb *j; + bool startnow; + + if ((label = job_get_string(pload, LAUNCH_JOBKEY_LABEL))) { + TAILQ_FOREACH(j, &jobs, tqe) { + if (!strcmp(j->label, label)) { + resp = launch_data_new_errno(EEXIST); + goto out; + } + } + } else { + resp = launch_data_new_errno(EINVAL); + goto out; + } + if (launch_data_dict_lookup(pload, LAUNCH_JOBKEY_PROGRAMARGUMENTS) == NULL) { + resp = launch_data_new_errno(EINVAL); + goto out; + } + + j = calloc(1, sizeof(struct jobcb) + strlen(label) + 1); + strcpy(j->label, label); + j->ldj = launch_data_copy(pload); + launch_data_revoke_fds(pload); + j->kqjob_callback = job_callback; + + + if (launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_ONDEMAND) == NULL) { + tmp = launch_data_alloc(LAUNCH_DATA_BOOL); + launch_data_set_bool(tmp, true); + launch_data_dict_insert(j->ldj, tmp, LAUNCH_JOBKEY_ONDEMAND); + } + + TAILQ_INSERT_TAIL(&jobs, j, tqe); + + j->debug = job_get_bool(j->ldj, LAUNCH_JOBKEY_DEBUG); + + startnow = !job_get_bool(j->ldj, LAUNCH_JOBKEY_ONDEMAND); + + if (job_get_bool(j->ldj, LAUNCH_JOBKEY_RUNATLOAD)) + startnow = true; + + if ((tmp = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_QUEUEDIRECTORIES))) { + size_t i; + + j->qdirs_cnt = launch_data_array_get_count(tmp); + j->qdirs = malloc(sizeof(int) * j->qdirs_cnt); + + for (i = 0; i < j->qdirs_cnt; i++) { + const char *thepath = launch_data_get_string(launch_data_array_get_index(tmp, i)); + + if (-1 == (j->qdirs[i] = _fd(open(thepath, O_EVTONLY)))) + job_log_error(j, LOG_ERR, "open(\"%s\", O_EVTONLY)", thepath); + } + + } + + if ((tmp = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_STARTINTERVAL))) { + j->start_interval = launch_data_get_integer(tmp); + + if (j->start_interval == 0) + job_log(j, LOG_WARNING, "StartInterval is zero, ignoring"); + else if (-1 == kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, j->start_interval, &j->kqjob_callback)) + job_log_error(j, LOG_ERR, "adding kevent timer"); + } + + if ((tmp = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_STARTCALENDARINTERVAL))) { + launch_data_t tmp_k; + + j->start_cal_interval = calloc(1, sizeof(struct tm)); + + if (LAUNCH_DATA_DICTIONARY == launch_data_get_type(tmp)) { + if ((tmp_k = launch_data_dict_lookup(tmp, LAUNCH_JOBKEY_CAL_MINUTE))) + j->start_cal_interval->tm_min = launch_data_get_integer(tmp_k); + if ((tmp_k = launch_data_dict_lookup(tmp, LAUNCH_JOBKEY_CAL_HOUR))) + j->start_cal_interval->tm_hour = launch_data_get_integer(tmp_k); + if ((tmp_k = launch_data_dict_lookup(tmp, LAUNCH_JOBKEY_CAL_DAY))) + j->start_cal_interval->tm_mday = launch_data_get_integer(tmp_k); + if ((tmp_k = launch_data_dict_lookup(tmp, LAUNCH_JOBKEY_CAL_WEEKDAY))) { + j->start_cal_interval->tm_wday = launch_data_get_integer(tmp_k); + if (j->start_cal_interval->tm_wday == 0) + j->start_cal_interval->tm_wday = 7; + } + if ((tmp_k = launch_data_dict_lookup(tmp, LAUNCH_JOBKEY_CAL_MONTH))) + j->start_cal_interval->tm_mon = launch_data_get_integer(tmp_k); + } + + job_set_alarm(j); + } + + if ((tmp = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_WATCHPATHS))) { + size_t i; + + j->vnodes_cnt = launch_data_array_get_count(tmp); + j->vnodes = malloc(sizeof(int) * j->vnodes_cnt); + + for (i = 0; i < j->vnodes_cnt; i++) { + const char *thepath = launch_data_get_string(launch_data_array_get_index(tmp, i)); + + if (-1 == (j->vnodes[i] = _fd(open(thepath, O_EVTONLY)))) + job_log_error(j, LOG_ERR, "open(\"%s\", O_EVTONLY)", thepath); + } + + } + + if ((tmp = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES))) + launch_data_dict_iterate(tmp, setup_job_env, NULL); + + if (job_get_bool(j->ldj, LAUNCH_JOBKEY_ONDEMAND)) + job_watch(j); + + if (startnow) + job_start(j); + + resp = launch_data_new_errno(0); +out: + return resp; +} + +static launch_data_t get_jobs(const char *which) +{ + struct jobcb *j; + launch_data_t tmp, resp = NULL; + + if (which) { + TAILQ_FOREACH(j, &jobs, tqe) { + if (!strcmp(which, j->label)) + resp = launch_data_copy(j->ldj); + } + if (resp == NULL) + resp = launch_data_new_errno(ESRCH); + } else { + resp = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + + TAILQ_FOREACH(j, &jobs, tqe) { + tmp = launch_data_copy(j->ldj); + launch_data_dict_insert(resp, tmp, j->label); + } + } + + return resp; +} + +static void usage(FILE *where) +{ + fprintf(where, "%s: [-d] [-- command [args ...]]\n", getprogname()); + fprintf(where, "\t-d\tdaemonize\n"); + fprintf(where, "\t-h\tthis usage statement\n"); + + if (where == stdout) + exit(EXIT_SUCCESS); +} + +#ifdef EVFILT_MACH_IMPLEMENTED +static void **machcbtable = NULL; +static size_t machcbtable_cnt = 0; +static int machcbreadfd = -1; +static int machcbwritefd = -1; +static mach_port_t mach_demand_port_set = MACH_PORT_NULL; +static pthread_t mach_demand_thread; + +static void mach_callback(void *obj __attribute__((unused)), struct kevent *kev __attribute__((unused))) +{ + struct kevent mkev; + mach_port_t mp; + + read(machcbreadfd, &mp, sizeof(mp)); + + EV_SET(&mkev, mp, EVFILT_MACHPORT, 0, 0, 0, machcbtable[MACH_PORT_INDEX(mp)]); + + (*((kq_callback *)mkev.udata))(mkev.udata, &mkev); +} +#endif + +int kevent_mod(uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t data, void *udata) +{ + struct kevent kev; + int q = mainkq; +#ifdef EVFILT_MACH_IMPLEMENTED + kern_return_t kr; + pthread_attr_t attr; + int pthr_r, pfds[2]; +#endif + + if (EVFILT_TIMER == filter || EVFILT_VNODE == filter) + q = asynckq; + + if (flags & EV_ADD && NULL == udata) { + syslog(LOG_ERR, "%s(): kev.udata == NULL!!!", __func__); + syslog(LOG_ERR, "kev: ident %d filter %d flags 0x%x fflags 0x%x", + ident, filter, flags, fflags); + errno = EINVAL; + return -1; + } + +#ifdef EVFILT_MACH_IMPLEMENTED + if (filter != EVFILT_MACHPORT) { +#endif +#ifdef PID1_REAP_ADOPTED_CHILDREN + if (filter == EVFILT_PROC && getpid() == 1) + return 0; +#endif + EV_SET(&kev, ident, filter, flags, fflags, data, udata); + return kevent(q, &kev, 1, NULL, 0, NULL); +#ifdef EVFILT_MACH_IMPLEMENTED + } + + if (machcbtable == NULL) { + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + pthr_r = pthread_create(&mach_demand_thread, &attr, mach_demand_loop, NULL); + if (pthr_r != 0) { + syslog(LOG_ERR, "pthread_create(mach_demand_loop): %s", strerror(pthr_r)); + exit(EXIT_FAILURE); + } + + pthread_attr_destroy(&attr); + + machcbtable = malloc(0); + pipe(pfds); + machcbwritefd = _fd(pfds[1]); + machcbreadfd = _fd(pfds[0]); + kevent_mod(machcbreadfd, EVFILT_READ, EV_ADD, 0, 0, &kqmach_callback); + kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &mach_demand_port_set); + if (kr != KERN_SUCCESS) { + syslog(LOG_ERR, "mach_port_allocate(demand_port_set): %s", mach_error_string(kr)); + exit(EXIT_FAILURE); + } + } + + if (flags & EV_ADD) { + kr = mach_port_move_member(mach_task_self(), ident, mach_demand_port_set); + if (kr != KERN_SUCCESS) { + syslog(LOG_ERR, "mach_port_move_member(): %s", mach_error_string(kr)); + exit(EXIT_FAILURE); + } + + if (MACH_PORT_INDEX(ident) > machcbtable_cnt) + machcbtable = realloc(machcbtable, MACH_PORT_INDEX(ident) * sizeof(void *)); + + machcbtable[MACH_PORT_INDEX(ident)] = udata; + } else if (flags & EV_DELETE) { + kr = mach_port_move_member(mach_task_self(), ident, MACH_PORT_NULL); + if (kr != KERN_SUCCESS) { + syslog(LOG_ERR, "mach_port_move_member(): %s", mach_error_string(kr)); + exit(EXIT_FAILURE); + } + } else { + syslog(LOG_DEBUG, "kevent_mod(EVFILT_MACHPORT) with flags: %d", flags); + errno = EINVAL; + return -1; + } + + return 0; +#endif +} + +static int _fd(int fd) +{ + if (fd >= 0) + fcntl(fd, F_SETFD, 1); + return fd; +} + +static void ipc_close(struct conncb *c) +{ + batch_job_enable(true, c); + + TAILQ_REMOVE(&connections, c, tqe); + launchd_close(c->conn); + free(c); +} + +static void setup_job_env(launch_data_t obj, const char *key, void *context __attribute__((unused))) +{ + if (LAUNCH_DATA_STRING == launch_data_get_type(obj)) + setenv(key, launch_data_get_string(obj), 1); +} + +static void unsetup_job_env(launch_data_t obj, const char *key, void *context __attribute__((unused))) +{ + if (LAUNCH_DATA_STRING == launch_data_get_type(obj)) + unsetenv(key); +} + +static void job_reap(struct jobcb *j) +{ + bool od = job_get_bool(j->ldj, LAUNCH_JOBKEY_ONDEMAND); + time_t td = time(NULL) - j->start_time; + bool bad_exit = false; + int status; + + job_log(j, LOG_DEBUG, "Reaping"); + + if (j->execfd) { + close(j->execfd); + j->execfd = 0; + } + +#ifdef PID1_REAP_ADOPTED_CHILDREN + if (getpid() == 1) + status = pid1_child_exit_status; + else +#endif + if (-1 == waitpid(j->p, &status, 0)) { + job_log_error(j, LOG_ERR, "waitpid(%d, ...)", j->p); + return; + } + + if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { + job_log(j, LOG_WARNING, "exited with exit code: %d", WEXITSTATUS(status)); + bad_exit = true; + } + + if (WIFSIGNALED(status)) { + int s = WTERMSIG(status); + if (SIGKILL == s || SIGTERM == s) { + job_log(j, LOG_NOTICE, "exited: %s", strsignal(s)); + } else { + job_log(j, LOG_WARNING, "exited abnormally: %s", strsignal(s)); + bad_exit = true; + } + } + + if (!od) { + if (td < LAUNCHD_MIN_JOB_RUN_TIME) { + job_log(j, LOG_WARNING, "respawning too quickly! throttling"); + bad_exit = true; + j->throttle = true; + } else if (td >= LAUNCHD_REWARD_JOB_RUN_TIME) { + job_log(j, LOG_INFO, "lived long enough, forgiving past exit failures"); + j->failed_exits = 0; + } + } + + if (bad_exit) + j->failed_exits++; + + if (j->failed_exits > 0) { + int failures_left = LAUNCHD_FAILED_EXITS_THRESHOLD - j->failed_exits; + if (failures_left) + job_log(j, LOG_WARNING, "%d more failure%s without living at least %d seconds will cause job removal", + failures_left, failures_left > 1 ? "s" : "", LAUNCHD_REWARD_JOB_RUN_TIME); + } + + total_children--; + j->p = 0; +} + +static bool job_restart_fitness_test(struct jobcb *j) +{ + bool od = job_get_bool(j->ldj, LAUNCH_JOBKEY_ONDEMAND); + + if (j->firstborn) { + job_log(j, LOG_DEBUG, "first born died, begin shutdown"); + do_shutdown(); + return false; + } else if (job_get_bool(j->ldj, LAUNCH_JOBKEY_SERVICEIPC) && !j->checkedin) { + job_log(j, LOG_WARNING, "failed to checkin"); + job_remove(j); + return false; + } else if (od || shutdown_in_progress) { + if (!od && shutdown_in_progress) + job_log(j, LOG_NOTICE, "exited while shutdown is in progress, will not restart unless demand requires it"); + job_watch(j); + return false; + } else if (j->failed_exits >= LAUNCHD_FAILED_EXITS_THRESHOLD) { + job_log(j, LOG_WARNING, "too many failures in a row for a job that should be alive all the time"); + job_remove(j); + return false; + } + + return true; +} + +static void job_callback(void *obj, struct kevent *kev) +{ + struct jobcb *j = obj; + bool d = j->debug; + bool startnow = true; + int oldmask = 0; + + if (d) { + oldmask = setlogmask(LOG_UPTO(LOG_DEBUG)); + job_log(j, LOG_DEBUG, "log level debug temporarily enabled while processing job"); + } + + if (kev->filter == EVFILT_PROC) { + job_reap(j); + + startnow = job_restart_fitness_test(j); + + if (startnow && j->throttle) { + j->throttle = false; + job_log(j, LOG_WARNING, "will restart in %d seconds", LAUNCHD_MIN_JOB_RUN_TIME); + if (-1 == kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_ADD|EV_ONESHOT, + NOTE_SECONDS, LAUNCHD_MIN_JOB_RUN_TIME, &j->kqjob_callback)) { + job_log_error(j, LOG_WARNING, "failed to setup timer callback!, starting now!"); + } else { + startnow = false; + } + } + } else if (kev->filter == EVFILT_TIMER && kev->fflags & NOTE_ABSOLUTE) { + job_set_alarm(j); + } else if (kev->filter == EVFILT_VNODE) { + size_t i; + const char *thepath = NULL; + + for (i = 0; i < j->vnodes_cnt; i++) { + if (j->vnodes[i] == (int)kev->ident) { + launch_data_t ld_vnodes = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_WATCHPATHS); + + thepath = launch_data_get_string(launch_data_array_get_index(ld_vnodes, i)); + + job_log(j, LOG_DEBUG, "watch path modified: %s", thepath); + + if ((NOTE_DELETE|NOTE_RENAME|NOTE_REVOKE) & kev->fflags) { + job_log(j, LOG_DEBUG, "watch path invalidated: %s", thepath); + close(j->vnodes[i]); + j->vnodes[i] = -1; /* this will get fixed in job_watch() */ + } + } + } + + for (i = 0; i < j->qdirs_cnt; i++) { + if (j->qdirs[i] == (int)kev->ident) { + launch_data_t ld_qdirs = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_QUEUEDIRECTORIES); + int dcc_r; + + thepath = launch_data_get_string(launch_data_array_get_index(ld_qdirs, i)); + + job_log(j, LOG_DEBUG, "queue directory modified: %s", thepath); + + if (-1 == (dcc_r = dir_has_files(thepath))) { + job_log_error(j, LOG_ERR, "dir_has_files(\"%s\", ...)", thepath); + } else if (0 == dcc_r) { + job_log(j, LOG_DEBUG, "spurious wake up, directory empty: %s", thepath); + startnow = false; + } + } + } + /* if we get here, then the vnodes either wasn't a qdir, or if it was, it has entries in it */ + } else if (kev->filter == EVFILT_READ && (int)kev->ident == j->execfd) { + if (kev->data > 0) { + int e; + + read(j->execfd, &e, sizeof(e)); + errno = e; + job_log_error(j, LOG_ERR, "execve()"); + job_remove(j); + j = NULL; + startnow = false; + } else { + close(j->execfd); + j->execfd = 0; + } + startnow = false; + } + + if (startnow) + job_start(j); + + if (d) { + /* the job might have been removed, must not call job_log() */ + syslog(LOG_DEBUG, "restoring original log mask"); + setlogmask(oldmask); + } +} + +static void job_start(struct jobcb *j) +{ + int spair[2]; + int execspair[2]; + bool sipc; + char nbuf[64]; + pid_t c; + + job_log(j, LOG_DEBUG, "Starting"); + + if (j->p) { + job_log(j, LOG_DEBUG, "already running"); + return; + } + + j->checkedin = false; + + sipc = job_get_bool(j->ldj, LAUNCH_JOBKEY_SERVICEIPC); + + if (job_get_bool(j->ldj, LAUNCH_JOBKEY_INETDCOMPATIBILITY)) + sipc = true; + + if (sipc) + socketpair(AF_UNIX, SOCK_STREAM, 0, spair); + + socketpair(AF_UNIX, SOCK_STREAM, 0, execspair); + + time(&j->start_time); + + switch (c = fork_with_bootstrap_port(launchd_bootstrap_port)) { + case -1: + job_log_error(j, LOG_ERR, "fork() failed, will try again in one second"); + close(execspair[0]); + close(execspair[1]); + if (sipc) { + close(spair[0]); + close(spair[1]); + } + if (job_get_bool(j->ldj, LAUNCH_JOBKEY_ONDEMAND)) + job_ignore(j); + break; + case 0: + close(execspair[0]); + /* wait for our parent to say they've attached a kevent to us */ + read(_fd(execspair[1]), &c, sizeof(c)); + if (j->firstborn) { + setpgid(getpid(), getpid()); + if (isatty(STDIN_FILENO)) { + if (tcsetpgrp(STDIN_FILENO, getpid()) == -1) + job_log_error(j, LOG_WARNING, "tcsetpgrp()"); + } + } + + if (sipc) { + close(spair[0]); + sprintf(nbuf, "%d", spair[1]); + setenv(LAUNCHD_TRUSTED_FD_ENV, nbuf, 1); + } + job_start_child(j, execspair[1]); + break; + default: + close(execspair[1]); + j->execfd = _fd(execspair[0]); + if (sipc) { + close(spair[1]); + ipc_open(_fd(spair[0]), j); + } + if (kevent_mod(j->execfd, EVFILT_READ, EV_ADD, 0, 0, &j->kqjob_callback) == -1) + job_log_error(j, LOG_ERR, "kevent_mod(j->execfd): %m"); + if (kevent_mod(c, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, &j->kqjob_callback) == -1) { + job_log_error(j, LOG_ERR, "kevent()"); + job_reap(j); + } else { + j->p = c; + total_children++; + if (job_get_bool(j->ldj, LAUNCH_JOBKEY_ONDEMAND)) + job_ignore(j); + } + /* this unblocks the child and avoids a race + * between the above fork() and the kevent_mod() */ + write(j->execfd, &c, sizeof(c)); + break; + } +} + +static void job_start_child(struct jobcb *j, int execfd) +{ + launch_data_t ldpa = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_PROGRAMARGUMENTS); + bool inetcompat = job_get_bool(j->ldj, LAUNCH_JOBKEY_INETDCOMPATIBILITY); + size_t i, argv_cnt; + const char **argv, *file2exec = "/usr/libexec/launchproxy"; + + job_setup_attributes(j); + + argv_cnt = launch_data_array_get_count(ldpa); + argv = alloca((argv_cnt + 2) * sizeof(char *)); + for (i = 0; i < argv_cnt; i++) + argv[i + 1] = launch_data_get_string(launch_data_array_get_index(ldpa, i)); + argv[argv_cnt + 1] = NULL; + + if (inetcompat) { + argv[0] = file2exec; + } else { + argv++; + file2exec = job_get_file2exec(j->ldj); + } + + if (-1 == execvp(file2exec, (char *const*)argv)) { + int e = errno; /* errno is a macro that expands, best not to take the address of it */ + write(execfd, &e, sizeof(e)); + job_log_error(j, LOG_ERR, "execvp(\"%s\", ...)", file2exec); + } + _exit(EXIT_FAILURE); +} + +static void job_setup_attributes(struct jobcb *j) +{ + launch_data_t srl = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_SOFTRESOURCELIMITS); + launch_data_t hrl = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_HARDRESOURCELIMITS); + bool inetcompat = job_get_bool(j->ldj, LAUNCH_JOBKEY_INETDCOMPATIBILITY); + launch_data_t tmp; + size_t i; + const char *tmpstr; + struct group *gre = NULL; + gid_t gre_g = 0; + static const struct { + const char *key; + int val; + } limits[] = { + { LAUNCH_JOBKEY_RESOURCELIMIT_CORE, RLIMIT_CORE }, + { LAUNCH_JOBKEY_RESOURCELIMIT_CPU, RLIMIT_CPU }, + { LAUNCH_JOBKEY_RESOURCELIMIT_DATA, RLIMIT_DATA }, + { LAUNCH_JOBKEY_RESOURCELIMIT_FSIZE, RLIMIT_FSIZE }, + { LAUNCH_JOBKEY_RESOURCELIMIT_MEMLOCK, RLIMIT_MEMLOCK }, + { LAUNCH_JOBKEY_RESOURCELIMIT_NOFILE, RLIMIT_NOFILE }, + { LAUNCH_JOBKEY_RESOURCELIMIT_NPROC, RLIMIT_NPROC }, + { LAUNCH_JOBKEY_RESOURCELIMIT_RSS, RLIMIT_RSS }, + { LAUNCH_JOBKEY_RESOURCELIMIT_STACK, RLIMIT_STACK }, + }; + + setpriority(PRIO_PROCESS, 0, job_get_integer(j->ldj, LAUNCH_JOBKEY_NICE)); + + if (srl || hrl) { + for (i = 0; i < (sizeof(limits) / sizeof(limits[0])); i++) { + struct rlimit rl; + + if (getrlimit(limits[i].val, &rl) == -1) { + job_log_error(j, LOG_WARNING, "getrlimit()"); + continue; + } + + if (hrl) + rl.rlim_max = job_get_integer(hrl, limits[i].key); + if (srl) + rl.rlim_cur = job_get_integer(srl, limits[i].key); + + if (setrlimit(limits[i].val, &rl) == -1) + job_log_error(j, LOG_WARNING, "setrlimit()"); + } + } + + if (!inetcompat && job_get_bool(j->ldj, LAUNCH_JOBKEY_SESSIONCREATE)) + launchd_SessionCreate(job_get_file2exec(j->ldj)); + + if (job_get_bool(j->ldj, LAUNCH_JOBKEY_LOWPRIORITYIO)) { + int lowprimib[] = { CTL_KERN, KERN_PROC_LOW_PRI_IO }; + int val = 1; + + if (sysctl(lowprimib, sizeof(lowprimib) / sizeof(lowprimib[0]), NULL, NULL, &val, sizeof(val)) == -1) + job_log_error(j, LOG_WARNING, "sysctl(\"%s\")", "kern.proc_low_pri_io"); + } + if ((tmpstr = job_get_string(j->ldj, LAUNCH_JOBKEY_ROOTDIRECTORY))) { + chroot(tmpstr); + chdir("."); + } + if ((tmpstr = job_get_string(j->ldj, LAUNCH_JOBKEY_GROUPNAME))) { + gre = getgrnam(tmpstr); + if (gre) { + gre_g = gre->gr_gid; + if (-1 == setgid(gre_g)) { + job_log_error(j, LOG_ERR, "setgid(%d)", gre_g); + _exit(EXIT_FAILURE); + } + } else { + job_log(j, LOG_ERR, "getgrnam(\"%s\") failed", tmpstr); + _exit(EXIT_FAILURE); + } + } + if ((tmpstr = job_get_string(j->ldj, LAUNCH_JOBKEY_USERNAME))) { + struct passwd *pwe = getpwnam(tmpstr); + if (pwe) { + uid_t pwe_u = pwe->pw_uid; + uid_t pwe_g = pwe->pw_gid; + + if (pwe->pw_expire && time(NULL) >= pwe->pw_expire) { + job_log(j, LOG_ERR, "expired account: %s", tmpstr); + _exit(EXIT_FAILURE); + } + if (job_get_bool(j->ldj, LAUNCH_JOBKEY_INITGROUPS)) { + if (-1 == initgroups(tmpstr, gre ? gre_g : pwe_g)) { + job_log_error(j, LOG_ERR, "initgroups()"); + _exit(EXIT_FAILURE); + } + } + if (!gre) { + if (-1 == setgid(pwe_g)) { + job_log_error(j, LOG_ERR, "setgid(%d)", pwe_g); + _exit(EXIT_FAILURE); + } + } + if (-1 == setuid(pwe_u)) { + job_log_error(j, LOG_ERR, "setuid(%d)", pwe_u); + _exit(EXIT_FAILURE); + } + } else { + job_log(j, LOG_WARNING, "getpwnam(\"%s\") failed", tmpstr); + _exit(EXIT_FAILURE); + } + } + if ((tmpstr = job_get_string(j->ldj, LAUNCH_JOBKEY_WORKINGDIRECTORY))) + chdir(tmpstr); + if (launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_UMASK)) + umask(job_get_integer(j->ldj, LAUNCH_JOBKEY_UMASK)); + if ((tmpstr = job_get_string(j->ldj, LAUNCH_JOBKEY_STANDARDOUTPATH))) { + int sofd = open(tmpstr, O_WRONLY|O_APPEND|O_CREAT, DEFFILEMODE); + if (sofd == -1) { + job_log_error(j, LOG_WARNING, "open(\"%s\", ...)", tmpstr); + } else { + dup2(sofd, STDOUT_FILENO); + close(sofd); + } + } + if ((tmpstr = job_get_string(j->ldj, LAUNCH_JOBKEY_STANDARDERRORPATH))) { + int sefd = open(tmpstr, O_WRONLY|O_APPEND|O_CREAT, DEFFILEMODE); + if (sefd == -1) { + job_log_error(j, LOG_WARNING, "open(\"%s\", ...)", tmpstr); + } else { + dup2(sefd, STDERR_FILENO); + close(sefd); + } + } + if ((tmp = launch_data_dict_lookup(j->ldj, LAUNCH_JOBKEY_ENVIRONMENTVARIABLES))) + launch_data_dict_iterate(tmp, setup_job_env, NULL); + + setsid(); +} + +#ifdef PID1_REAP_ADOPTED_CHILDREN +__private_extern__ int pid1_child_exit_status = 0; +static void pid1waitpid(void) +{ + pid_t p; + + while ((p = waitpid(-1, &pid1_child_exit_status, WNOHANG)) > 0) { + if (!launchd_check_pid(p)) + init_check_pid(p); + } +} +#endif + +static void do_shutdown(void) +{ + struct jobcb *j; + + shutdown_in_progress = true; + + kevent_mod(asynckq, EVFILT_READ, EV_DISABLE, 0, 0, &kqasync_callback); + + TAILQ_FOREACH(j, &jobs, tqe) + job_stop(j); + + if (getpid() == 1) { + catatonia(); + mach_start_shutdown(SIGTERM); + } +} + +static void signal_callback(void *obj __attribute__((unused)), struct kevent *kev) +{ + switch (kev->ident) { + case SIGHUP: + update_ttys(); + reload_launchd_config(); + break; + case SIGTERM: + do_shutdown(); + break; +#ifdef PID1_REAP_ADOPTED_CHILDREN + case SIGCHLD: + /* Please automatically reap processes reparented to PID 1 */ + if (getpid() == 1) + pid1waitpid(); + break; +#endif + default: + break; + } +} + +static void fs_callback(void) +{ + static bool mounted_volfs = false; + + if (1 != getpid()) + mounted_volfs = true; + + if (pending_stdout) { + int fd = open(pending_stdout, O_CREAT|O_APPEND|O_WRONLY, DEFFILEMODE); + if (fd != -1) { + dup2(fd, STDOUT_FILENO); + close(fd); + free(pending_stdout); + pending_stdout = NULL; + } + } + if (pending_stderr) { + int fd = open(pending_stderr, O_CREAT|O_APPEND|O_WRONLY, DEFFILEMODE); + if (fd != -1) { + dup2(fd, STDERR_FILENO); + close(fd); + free(pending_stderr); + pending_stderr = NULL; + } + } + + if (!mounted_volfs) { + int r = mount("volfs", VOLFSDIR, MNT_RDONLY, NULL); + + if (-1 == r && errno == ENOENT) { + mkdir(VOLFSDIR, ACCESSPERMS & ~(S_IWUSR|S_IWGRP|S_IWOTH)); + r = mount("volfs", VOLFSDIR, MNT_RDONLY, NULL); + } + + if (-1 == r) { + syslog(LOG_WARNING, "mount(\"%s\", \"%s\", ...): %m", "volfs", VOLFSDIR); + } else { + mounted_volfs = true; + } + } + + if (!launchd_inited) + launchd_server_init(false); +} + +static void readcfg_callback(void *obj __attribute__((unused)), struct kevent *kev __attribute__((unused))) +{ + int status; + +#ifdef PID1_REAP_ADOPTED_CHILDREN + if (getpid() == 1) + status = pid1_child_exit_status; + else +#endif + if (-1 == waitpid(readcfg_pid, &status, 0)) { + syslog(LOG_WARNING, "waitpid(readcfg_pid, ...): %m"); + return; + } + + readcfg_pid = 0; + + if (WIFEXITED(status)) { + if (WEXITSTATUS(status)) + syslog(LOG_WARNING, "Unable to read launchd.conf: launchctl exited with status: %d", WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + syslog(LOG_WARNING, "Unable to read launchd.conf: launchctl exited abnormally: %s", strsignal(WTERMSIG(status))); + } else { + syslog(LOG_WARNING, "Unable to read launchd.conf: launchctl exited abnormally"); + } +} + +#ifdef EVFILT_MACH_IMPLEMENTED +static void *mach_demand_loop(void *arg __attribute__((unused))) +{ + mach_msg_empty_rcv_t dummy; + kern_return_t kr; + mach_port_name_array_t members; + mach_msg_type_number_t membersCnt; + mach_port_status_t status; + mach_msg_type_number_t statusCnt; + unsigned int i; + + for (;;) { + + /* + * Receive indication of message on demand service + * ports without actually receiving the message (we'll + * let the actual server do that. + */ + kr = mach_msg(&dummy.header, MACH_RCV_MSG|MACH_RCV_LARGE, + 0, 0, mach_demand_port_set, 0, MACH_PORT_NULL); + if (kr != MACH_RCV_TOO_LARGE) { + syslog(LOG_WARNING, "%s(): mach_msg(): %s", __func__, mach_error_string(kr)); + continue; + } + + /* + * Some port(s) now have messages on them, find out + * which ones (there is no indication of which port + * triggered in the MACH_RCV_TOO_LARGE indication). + */ + kr = mach_port_get_set_status(mach_task_self(), + mach_demand_port_set, &members, &membersCnt); + if (kr != KERN_SUCCESS) { + syslog(LOG_WARNING, "%s(): mach_port_get_set_status(): %s", __func__, mach_error_string(kr)); + continue; + } + + for (i = 0; i < membersCnt; i++) { + statusCnt = MACH_PORT_RECEIVE_STATUS_COUNT; + kr = mach_port_get_attributes(mach_task_self(), members[i], + MACH_PORT_RECEIVE_STATUS, (mach_port_info_t)&status, &statusCnt); + if (kr != KERN_SUCCESS) { + syslog(LOG_WARNING, "%s(): mach_port_get_attributes(): %s", __func__, mach_error_string(kr)); + continue; + } + + /* + * For each port with messages, take it out of the + * demand service portset, and inform the main thread + * that it might have to start the server responsible + * for it. + */ + if (status.mps_msgcount) { + kr = mach_port_move_member(mach_task_self(), members[i], MACH_PORT_NULL); + if (kr != KERN_SUCCESS) { + syslog(LOG_WARNING, "%s(): mach_port_move_member(): %s", __func__, mach_error_string(kr)); + continue; + } + write(machcbwritefd, &(members[i]), sizeof(members[i])); + } + } + + kr = vm_deallocate(mach_task_self(), (vm_address_t) members, + (vm_size_t) membersCnt * sizeof(mach_port_name_t)); + if (kr != KERN_SUCCESS) { + syslog(LOG_WARNING, "%s(): vm_deallocate(): %s", __func__, mach_error_string(kr)); + continue; + } + } + + return NULL; +} +#endif + +static void reload_launchd_config(void) +{ + struct stat sb; + static char *ldconf = PID1LAUNCHD_CONF; + const char *h = getenv("HOME"); + + if (h && ldconf == PID1LAUNCHD_CONF) + asprintf(&ldconf, "%s/%s", h, LAUNCHD_CONF); + + if (!ldconf) + return; + + if (lstat(ldconf, &sb) == 0) { + int spair[2]; + socketpair(AF_UNIX, SOCK_STREAM, 0, spair); + readcfg_pid = fork_with_bootstrap_port(launchd_bootstrap_port); + if (readcfg_pid == 0) { + char nbuf[100]; + close(spair[0]); + sprintf(nbuf, "%d", spair[1]); + setenv(LAUNCHD_TRUSTED_FD_ENV, nbuf, 1); + int fd = open(ldconf, O_RDONLY); + if (fd == -1) { + syslog(LOG_ERR, "open(\"%s\"): %m", ldconf); + _exit(EXIT_FAILURE); + } + dup2(fd, STDIN_FILENO); + close(fd); + execl(LAUNCHCTL_PATH, LAUNCHCTL_PATH, NULL); + syslog(LOG_ERR, "execl(\"%s\", ...): %m", LAUNCHCTL_PATH); + _exit(EXIT_FAILURE); + } else if (readcfg_pid == -1) { + close(spair[0]); + close(spair[1]); + syslog(LOG_ERR, "fork(): %m"); + readcfg_pid = 0; + } else { + close(spair[1]); + ipc_open(_fd(spair[0]), NULL); + if (kevent_mod(readcfg_pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, &kqreadcfg_callback) == -1) + syslog(LOG_ERR, "kevent_mod(EVFILT_PROC, &kqreadcfg_callback): %m"); + } + } +} + +static void conceive_firstborn(char *argv[]) +{ + launch_data_t r, d = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + launch_data_t args = launch_data_alloc(LAUNCH_DATA_ARRAY); + launch_data_t l = launch_data_new_string("com.apple.launchd.firstborn"); + size_t i; + + for (i = 0; *argv; argv++, i++) + launch_data_array_set_index(args, launch_data_new_string(*argv), i); + + launch_data_dict_insert(d, args, LAUNCH_JOBKEY_PROGRAMARGUMENTS); + launch_data_dict_insert(d, l, LAUNCH_JOBKEY_LABEL); + + r = load_job(d); + + launch_data_free(r); + launch_data_free(d); + + TAILQ_FIRST(&jobs)->firstborn = true; +} + +static void loopback_setup(void) +{ + struct ifaliasreq ifra; + struct in6_aliasreq ifra6; + struct ifreq ifr; + int s, s6; + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, "lo0"); + + if (-1 == (s = socket(AF_INET, SOCK_DGRAM, 0))) + syslog(LOG_ERR, "%s: socket(%s, ...): %m", __PRETTY_FUNCTION__, "AF_INET"); + if (-1 == (s6 = socket(AF_INET6, SOCK_DGRAM, 0))) + syslog(LOG_ERR, "%s: socket(%s, ...): %m", __PRETTY_FUNCTION__, "AF_INET6"); + + if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) { + syslog(LOG_ERR, "ioctl(SIOCGIFFLAGS): %m"); + } else { + ifr.ifr_flags |= IFF_UP; + + if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1) + syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m"); + } + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, "lo0"); + + if (ioctl(s6, SIOCGIFFLAGS, &ifr) == -1) { + syslog(LOG_ERR, "ioctl(SIOCGIFFLAGS): %m"); + } else { + ifr.ifr_flags |= IFF_UP; + + if (ioctl(s6, SIOCSIFFLAGS, &ifr) == -1) + syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m"); + } + + memset(&ifra, 0, sizeof(ifra)); + strcpy(ifra.ifra_name, "lo0"); + + ((struct sockaddr_in *)&ifra.ifra_addr)->sin_family = AF_INET; + ((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + ((struct sockaddr_in *)&ifra.ifra_addr)->sin_len = sizeof(struct sockaddr_in); + ((struct sockaddr_in *)&ifra.ifra_mask)->sin_family = AF_INET; + ((struct sockaddr_in *)&ifra.ifra_mask)->sin_addr.s_addr = htonl(IN_CLASSA_NET); + ((struct sockaddr_in *)&ifra.ifra_mask)->sin_len = sizeof(struct sockaddr_in); + + if (ioctl(s, SIOCAIFADDR, &ifra) == -1) + syslog(LOG_ERR, "ioctl(SIOCAIFADDR ipv4): %m"); + + memset(&ifra6, 0, sizeof(ifra6)); + strcpy(ifra6.ifra_name, "lo0"); + + ifra6.ifra_addr.sin6_family = AF_INET6; + ifra6.ifra_addr.sin6_addr = in6addr_loopback; + ifra6.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); + ifra6.ifra_prefixmask.sin6_family = AF_INET6; + memset(&ifra6.ifra_prefixmask.sin6_addr, 0xff, sizeof(struct in6_addr)); + ifra6.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); + ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; + ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; + + if (ioctl(s6, SIOCAIFADDR_IN6, &ifra6) == -1) + syslog(LOG_ERR, "ioctl(SIOCAIFADDR ipv6): %m"); + + close(s); + close(s6); +} + +static void workaround3048875(int argc, char *argv[]) +{ + int i; + char **ap, *newargv[100], *p = argv[1]; + + if (argc == 1 || argc > 2) + return; + + newargv[0] = argv[0]; + for (ap = newargv + 1, i = 1; ap < &newargv[100]; ap++, i++) { + if ((*ap = strsep(&p, " \t")) == NULL) + break; + if (**ap == '\0') { + *ap = NULL; + break; + } + } + + if (argc == i) + return; + + execv(newargv[0], newargv); +} + +static launch_data_t adjust_rlimits(launch_data_t in) +{ + static struct rlimit *l = NULL; + static size_t lsz = sizeof(struct rlimit) * RLIM_NLIMITS; + struct rlimit *ltmp; + size_t i,ltmpsz; + + if (l == NULL) { + l = malloc(lsz); + for (i = 0; i < RLIM_NLIMITS; i++) { + if (getrlimit(i, l + i) == -1) + syslog(LOG_WARNING, "getrlimit(): %m"); + } + } + + if (in) { + ltmp = launch_data_get_opaque(in); + ltmpsz = launch_data_get_opaque_size(in); + + if (ltmpsz > lsz) { + syslog(LOG_WARNING, "Too much rlimit data sent!"); + ltmpsz = lsz; + } + + for (i = 0; i < (ltmpsz / sizeof(struct rlimit)); i++) { + if (ltmp[i].rlim_cur == l[i].rlim_cur && ltmp[i].rlim_max == l[i].rlim_max) + continue; + + if (readcfg_pid && getpid() == 1) { + int gmib[] = { CTL_KERN, KERN_MAXPROC }; + int pmib[] = { CTL_KERN, KERN_MAXPROCPERUID }; + const char *gstr = "kern.maxproc"; + const char *pstr = "kern.maxprocperuid"; + int gval = ltmp[i].rlim_max; + int pval = ltmp[i].rlim_cur; + switch (i) { + case RLIMIT_NOFILE: + gmib[1] = KERN_MAXFILES; + pmib[1] = KERN_MAXFILESPERPROC; + gstr = "kern.maxfiles"; + pstr = "kern.maxfilesperproc"; + break; + case RLIMIT_NPROC: + /* kernel will not clamp to this value, we must */ + if (gval > (2048 + 20)) + gval = 2048 + 20; + break; + default: + break; + } + if (sysctl(gmib, 2, NULL, NULL, &gval, sizeof(gval)) == -1) + syslog(LOG_WARNING, "sysctl(\"%s\"): %m", gstr); + if (sysctl(pmib, 2, NULL, NULL, &pval, sizeof(pval)) == -1) + syslog(LOG_WARNING, "sysctl(\"%s\"): %m", pstr); + } + if (setrlimit(i, ltmp + i) == -1) + syslog(LOG_WARNING, "setrlimit(): %m"); + /* the kernel may have clamped the values we gave it */ + if (getrlimit(i, l + i) == -1) + syslog(LOG_WARNING, "getrlimit(): %m"); + } + } + + return launch_data_new_opaque(l, sizeof(struct rlimit) * RLIM_NLIMITS); +} + +__private_extern__ void launchd_SessionCreate(const char *who) +{ + void *seclib = dlopen(SECURITY_LIB, RTLD_LAZY); + OSStatus (*sescr)(SessionCreationFlags flags, SessionAttributeBits attributes); + + if (seclib) { + sescr = dlsym(seclib, "SessionCreate"); + + if (sescr) { + OSStatus scr = sescr(0, 0); + if (scr != noErr) + syslog(LOG_WARNING, "%s: SessionCreate() failed: %d", who, scr); + } else { + syslog(LOG_WARNING, "%s: couldn't find SessionCreate() in %s", who, SECURITY_LIB); + } + + dlclose(seclib); + } else { + syslog(LOG_WARNING, "%s: dlopen(\"%s\",...): %s", who, SECURITY_LIB, dlerror()); + } +} + +static int dir_has_files(const char *path) +{ + DIR *dd = opendir(path); + struct dirent *de; + bool r = 0; + + if (!dd) + return -1; + + while ((de = readdir(dd))) { + if (strcmp(de->d_name, ".") && strcmp(de->d_name, "..")) { + r = 1; + break; + } + } + + closedir(dd); + return r; +} + +static void job_set_alarm(struct jobcb *j) +{ + struct tm otherlatertm, latertm, *nowtm; + time_t later, otherlater = 0, now = time(NULL); + + nowtm = localtime(&now); + + latertm = *nowtm; + + latertm.tm_sec = 0; + latertm.tm_isdst = -1; + + + if (j->start_cal_interval->tm_min) + latertm.tm_min = j->start_cal_interval->tm_min; + if (j->start_cal_interval->tm_hour) + latertm.tm_hour = j->start_cal_interval->tm_hour; + + otherlatertm = latertm; + + if (j->start_cal_interval->tm_mday) + latertm.tm_mday = j->start_cal_interval->tm_mday; + if (j->start_cal_interval->tm_mon) + latertm.tm_mon = j->start_cal_interval->tm_mon; + + /* cron semantics are fun */ + if (j->start_cal_interval->tm_wday) { + int delta, realwday = j->start_cal_interval->tm_wday; + + if (realwday == 7) + realwday = 0; + + delta = realwday - nowtm->tm_wday; + + /* Now Later Delta Desired + * 0 6 6 6 + * 6 0 -6 7 + -6 + * 1 5 4 4 + * 5 1 -4 7 + -4 + */ + if (delta > 0) + otherlatertm.tm_mday += delta; + else if (delta < 0) + otherlatertm.tm_mday += 7 + delta; + else if (otherlatertm.tm_hour < nowtm->tm_hour) + otherlatertm.tm_mday += 7; + else if (otherlatertm.tm_min < nowtm->tm_min) + otherlatertm.tm_hour++; + else + otherlatertm.tm_min++; + + otherlater = mktime(&otherlatertm); + } + + if (latertm.tm_mon < nowtm->tm_mon) { + latertm.tm_year++; + } else if (latertm.tm_mday < nowtm->tm_mday) { + latertm.tm_mon++; + } else if (latertm.tm_hour < nowtm->tm_hour) { + latertm.tm_mday++; + } else if (latertm.tm_min < nowtm->tm_min) { + latertm.tm_hour++; + } else { + latertm.tm_min++; + } + + later = mktime(&latertm); + + if (otherlater) { + if (j->start_cal_interval->tm_mday) + later = later < otherlater ? later : otherlater; + else + later = otherlater; + } + + if (-1 == kevent_mod((uintptr_t)j->start_cal_interval, EVFILT_TIMER, EV_ADD, NOTE_ABSOLUTE|NOTE_SECONDS, later, &j->kqjob_callback)) + job_log_error(j, LOG_ERR, "adding kevent alarm"); +} + +static void job_log_error(struct jobcb *j, int pri, const char *msg, ...) +{ + size_t newmsg_sz = strlen(msg) + strlen(j->label) + 200; + char *newmsg = alloca(newmsg_sz); + va_list ap; + + sprintf(newmsg, "%s: %s: %s", j->label, msg, strerror(errno)); + + va_start(ap, msg); + + vsyslog(pri, newmsg, ap); + + va_end(ap); +} + +static void job_log(struct jobcb *j, int pri, const char *msg, ...) +{ + size_t newmsg_sz = strlen(msg) + sizeof(": ") + strlen(j->label); + char *newmsg = alloca(newmsg_sz); + va_list ap; + + sprintf(newmsg, "%s: %s", j->label, msg); + + va_start(ap, msg); + + vsyslog(pri, newmsg, ap); + + va_end(ap); +} + +static void async_callback(void) +{ + struct timespec timeout = { 0, 0 }; + struct kevent kev; + + switch (kevent(asynckq, NULL, 0, &kev, 1, &timeout)) { + case -1: + syslog(LOG_DEBUG, "kevent(): %m"); + break; + case 1: + (*((kq_callback *)kev.udata))(kev.udata, &kev); + case 0: + break; + default: + syslog(LOG_DEBUG, "unexpected: kevent() returned something != 0, -1 or 1"); + } +} diff --git a/launchd/src/launchd.conf.5 b/launchd/src/launchd.conf.5 new file mode 100644 index 0000000..1bae129 --- /dev/null +++ b/launchd/src/launchd.conf.5 @@ -0,0 +1,27 @@ +.Dd January 10, 2005 +.Dt launchd.conf 5 +.Os Darwin +.Sh NAME +.Nm launchd.conf +.Nd launchd configuration file +.Sh SYNOPSIS +.Nm $HOME/.launchd.conf +.Nm /etc/launchd.conf +.Sh DESCRIPTION +.Nm +contains a list of subcommands to run via +.Nm launchctl +when +.Nm launchd +starts. +.Sh FILES +.Bl -tag -width "$HOME/.launchd.conf" -compact +.It Pa $HOME/.launchd.conf +Your launchd configuration file. +.It Pa /etc/launchd.conf +The system's launchd configuration file. +.El +.Sh SEE ALSO +.Xr launchctl 1 , +.Xr launchd 8 , +.Xr launchd.plist 5 diff --git a/launchd/src/launchd.h b/launchd/src/launchd.h new file mode 100644 index 0000000..551cfd1 --- /dev/null +++ b/launchd/src/launchd.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef __LAUNCHD_H__ +#define __LAUNCHD_H__ + +#include + +typedef void (*kq_callback)(void *, struct kevent *); + +extern kq_callback kqsimple_zombie_reaper; +extern mach_port_t launchd_bootstrap_port; +extern sigset_t blocked_signals; + +#ifdef PID1_REAP_ADOPTED_CHILDREN +extern int pid1_child_exit_status; +#endif + +int kevent_mod(uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t data, void *udata); +void launchd_SessionCreate(const char *who); + +void init_boot(bool sflag, bool vflag, bool xflag); +void init_pre_kevent(void); +bool init_check_pid(pid_t); + +void update_ttys(void); +void catatonia(void); +void death(void); + +#endif diff --git a/launchd/src/launchd.plist.5 b/launchd/src/launchd.plist.5 new file mode 100644 index 0000000..96844de --- /dev/null +++ b/launchd/src/launchd.plist.5 @@ -0,0 +1,297 @@ +.Dd September 30, 2004 +.Dt launchd.plist 5 +.Os Darwin +.Sh NAME +.Nm launchd.plist +.Nd System wide and per-user daemon/agent configuration files +.Sh DESCRIPTION +This document details the parameters that can be given to an XML property list that can be loaded into +.Nm launchd +with +.Nm launchctl . +.Sh EXPECTATIONS +Daemons or agents managed by +.Nm launchd +are expected to behave certain ways. +.Pp +A daemon or agent launched by +.Nm launchd +MUST NOT do the following in the process directly launched by +.Nm launchd : +.Pp +.Bl -bullet -offset indent -compact +.It +.Xr fork 2 +and have the parent process +.Xr exit 3 +or +.Xr _exit 2 . +.It +Call +.Xr daemon 3 +.El +.Pp +A daemon or agent launched by +.Nm launchd +SHOULD NOT do the following as a part of their startup initialization: +.Pp +.Bl -bullet -offset indent -compact +.It +Setup the user ID or group ID. +.It +Setup the working directory. +.It +.Xr chroot 2 +.It +.Xr setsid 2 +.It +Close "stray" file descriptors. +.It +Change +.Xr stdio 3 +to /dev/null. +.It +Setup resource limits with +.Xr setrusage 2 . +.It +Setup priority with +.Xr setpriority 2 . +.It +Ignore the SIGTERM signal. +.El +.Pp +A daemon or agent launched by +.Nm launchd +SHOULD: +.Pp +.Bl -bullet -offset indent -compact +.It +Launch on demand given criteria specified in the XML property list. +More information can be found in +.Xr launch 3 . +.It +Catch the SIGTERM signal. +.El +.Sh XML PROPERTY LIST KEYS +The follow keys can be used to describe the configuration details of your daemon or agent. +Property lists files are expected to have their name end in ".plist" but that is not strictly required. +.Pp +.Bl -ohang +.It Sy Label +This required key uniquely identifies the job to +.Nm launchd . +.It Sy Disabled +This optional key is used to disable your job. The default is false. +.It Sy UserName +This optional key specifies the user to run the job as. The default is the user who submitted the job to +.Nm launchd . +.It Sy GroupName +This optional key specifies the user to run the job as. The default is the group of the user who submitted the job to +.Nm launchd . +.It Sy inetdCompatibility +The presence of this key specifies that the daemon expects to be run as if it were launched from +.Xr inetd 8 . +.Bl -ohang -offset indent +.It Sy Wait +This flag corresponds to the "wait" or "nowait" option of +.Xr inetd 8 . +.El +.It Sy ProgramArguments +This required key maps to the second argument of +.Xr execvp 3 . +.It Sy Program +This optional key maps to the first argument of +.Xr execvp 3 . +If this key is missing, then the first element of the array of strings provided to the ProgramArguments will be used instead. +.It Sy OnDemand +This optional key is used to control whether your job is launched based on demand or to be kept continuously running. The default is true. +.It Sy RunAtLoad +This optional key is used to control whether your job is launched once at the time the job is loaded. The default is false. +.It Sy RootDirectory +This optional key is used to specific a directory to +.Xr chroot 2 +to before running the job. +.It Sy WorkingDirectory +This optional key is used to specific a directory to +.Xr chdir 2 +to before running the job. +.It Sy ServiceDescription +This optional key is used to specify a human readable description of the purpose of the job. +.It Sy EnvironmentVariables +This optional key is used to specify additional environmental variables to be setup before running the job. +.It Sy Umask +This optional key specifies what value should be passed to +.Xr umask 2 +before running the job. +.It Sy ServiceIPC +This optional key specifies whether the job participates in advanced communication with +.Nm launchd . +The default is false. +.It Sy TimeOut +The recommended time out to pass to the job. If no value is specified, a default time out will be supplied by +.Nm launchd +for use by the job at check in time. +.It Sy InitGroups +This optional key specifies whether the job should have +.Xr initgroups 3 +should be called before running the job. +The default is false. +.It Sy WatchPaths +This optional key causes the job to be started if any one of the listed paths are modified. +.It Sy QueueDirectories +Much like the WatchPaths option, this key will watch the paths for modifications. The difference being that the job will only be started if the path is a directory and the directory is not empty. +.It Sy StartInterval +This optional key causes the job to be started every N seconds. +.It Sy StartCalendarInterval +This optional key causes the job to be started every calendar interval as specified. Missing arguments are considered to be wildcard. The semantics are much like +.Xr crontab 5 +. +.Bl -ohang -offset indent +.It Sy Minute +The minute on which this job will be run. +.It Sy Hour +The hour on which this job will be run. +.It Sy Day +The day on which this job will be run. +.It Sy Weekday +The weekday on which this job will be run (0 and 7 are Sunday). +.It Sy Month +The month on which this job will be run. +.El +.It Sy StandardOutPath +This optional key specifies what file should be used for data being sent to stdout when using +.Xr stdio 3 . +.It Sy StandardErrorPath +This optional key specifies what file should be used for data being sent to stderr when using +.Xr stdio 3 . +.It Sy Debug +This optional key specifies that +.Nm launchd +should adjust its log mask temporarily to LOG_DEBUG while dealing with this job. +.Xr stdio 3 . +.It Sy SoftResourceLimits +.It Sy HardResourceLimits +Resource limits to be imposed on the job. These adjust variables set with +.Xr setrlimit 2 . +The following keys apply: +.Bl -ohang -offset indent +.It Sy Core +The largest size (in bytes) core file that may be created. +.It Sy CPU +The maximum amount of cpu time (in seconds) to be used by each process. +.It Sy Data +The maximum size (in bytes) of the data segment for a process; this defines how far a program may extend its break with the +.Xr sbrk 2 +system call. +.It Sy FileSize +The largest size (in bytes) file that may be created. +.It Sy MemoryLock +The maximum size (in bytes) which a process may lock into memory using the +.Xr mlock 2 +function. +.It Sy NumberOfFiles +The maximum number of open files for this process. +.It Sy NumberOfProcesses +The maximum number of simultaneous processes for this user id. +.It Sy ResidentSetSize +The maximum size (in bytes) to which a process's resident set size may grow. +This imposes a limit on the amount of physical memory to be given to a process; +if memory is tight, the system will prefer to take memory from processes that +are exceeding their declared resident set size. +.It Sy Stack +The maximum size (in bytes) of the stack segment for a process; this defines +how far a program's stack segment may be extended. Stack extension is +performed automatically by the system. +.El +.It Sy Nice +This optional key specifies what +.Xr nice 3 +value should be applied to the daemon. +.It Sy LowPriorityIO +This optional key specifies whether the kernel should consider this daemon to be low priority when doing file system I/O. +.It Sy Sockets +This optional key is used to specify launch on demand sockets that can be used to let +.Nm launchd +know when to run the job. The job can check-in and get a copy of the file descriptors using APIs outlined in +.Xr launch 3 . +The paramters below are used as inputs to call +.Xr getaddrinfo 3 . +.Bl -ohang -offset indent +.It Sy SockType +This optional key tells +.Nm launchctl +what type of socket to create. The default is "stream" and other valid values for this key +are "dgram" and "seqpacket" respectively. +.It Sy SockPassive +This optional key specifies whether +.Xr listen 2 +or +.Xr connect 2 +should be called on the created file descriptor. The default is true ("to listen"). +.It Sy SockNodeName +This optional key specifies the node to +.Xr connect 2 +or +.Xr bind 2 +to. +.It Sy SockServiceName +This optional key specifies the service on the node to +.Xr connect 2 +or +.Xr bind 2 +to. +.It Sy SockFamily +This optional key can be used to specifically request that "IPv4" or "IPv6" socket(s) be created. +.It Sy SockProtocol +This optional key specifies the protocol to be passed to +.Xr socket 2 . +The only value understood by this key at the moment is "TCP". +.It Sy SockPathName +This optional key implies SockFamily is set to "Unix". It specifies the path to +.Xr connect 2 +or +.Xr bind 2 +to. +.It Sy Bonjour +This optional key can be used to request that the service be registered with the +.Xr mDNSResponder 8 . +If the value is boolean, the service name is inferred from the SockServiceName. +.El +.El +.Pp +.Sh EXAMPLE XML PROPERTY LISTS +.Pp +The following XML Property List simply keeps "exampled" running continuously: +.Pp +.Dl +.Dl +.Dl +.Dl +.Dl Label +.Dl com.example.exampled +.Dl ProgramArguments +.Dl +.Dl exampled +.Dl +.Dl OnDemand +.Dl +.Dl +.Dl +.Pp +.Sh FILES +.Bl -tag -width "/System/Library/LaunchDaemons" -compact +.It Pa ~/Library/LaunchAgents +Per-user agents provided by the user. +.It Pa /Library/LaunchAgents +Per-user agents provided by the administrator. +.It Pa /Library/LaunchDaemons +System wide daemons provided by the administrator. +.It Pa /System/Library/LaunchAgents +Mac OS X Per-user agents. +.It Pa /System/Library/LaunchDaemons +Mac OS X System wide daemons. +.El +.Sh SEE ALSO +.Xr launchctl 1 , +.Xr launch 3 , +.Xr launchd 8 diff --git a/launchd/src/launchd_debugd.8 b/launchd/src/launchd_debugd.8 new file mode 100644 index 0000000..f8464e5 --- /dev/null +++ b/launchd/src/launchd_debugd.8 @@ -0,0 +1,21 @@ +.Dd February 2, 2005 +.Dt launchd_debugd 8 +.Os Darwin +.Sh NAME +.Nm launchd_debugd +.Nd Simple HTTP server to display job data +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +.Nm +Provides a simple HTTP server to display all jobs loaded into +.Nm launchd . +This program may be merged into +.Nm launchd +in the future. +.Pp +To enable (as root): "launchctl load -w /System/Library/LaunchDaemons/com.apple.launchd_helperd.plist" +.Sh SEE ALSO +.Xr launchctl 1 , +.Xr launchd.plist 5 , +.Xr launchd 8 diff --git a/launchd/src/launchdebugd.c b/launchd/src/launchdebugd.c new file mode 100644 index 0000000..7d746c4 --- /dev/null +++ b/launchd/src/launchdebugd.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "launch.h" + +static void launch_print_obj(launch_data_t o, FILE *w); + +static int kq = -1; + +static void find_fds(launch_data_t o, const char *key __attribute__((unused)), void *context __attribute__((unused))) +{ + struct kevent kev; + size_t i; + + switch (launch_data_get_type(o)) { + case LAUNCH_DATA_FD: + EV_SET(&kev, launch_data_get_fd(o), EVFILT_READ, EV_ADD, 0, 0, NULL); + if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) + syslog(LOG_DEBUG, "kevent(): %m"); + break; + case LAUNCH_DATA_ARRAY: + for (i = 0; i < launch_data_array_get_count(o); i++) + find_fds(launch_data_array_get_index(o, i), NULL, NULL); + break; + case LAUNCH_DATA_DICTIONARY: + launch_data_dict_iterate(o, find_fds, NULL); + break; + default: + break; + } +} + +int main(void) +{ + int r; + struct sockaddr_storage ss; + socklen_t slen = sizeof(ss); + struct kevent kev; + FILE *c; + launch_data_t tmp, resp, msg = launch_data_alloc(LAUNCH_DATA_STRING); + + kq = kqueue(); + + launch_data_set_string(msg, LAUNCH_KEY_CHECKIN); + + openlog(getprogname(), LOG_PERROR|LOG_PID|LOG_CONS, LOG_DAEMON); + + if ((resp = launch_msg(msg)) == NULL) { + syslog(LOG_ERR, "launch_msg(\"" LAUNCH_KEY_CHECKIN "\"): %m"); + exit(EXIT_FAILURE); + } + + tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS); + if (tmp) { + find_fds(tmp, NULL, NULL); + } else { + syslog(LOG_ERR, "No FDs found to answer requests on!"); + exit(EXIT_FAILURE); + } + + launch_data_free(resp); + + if ((r = kevent(kq, NULL, 0, &kev, 1, NULL)) == -1) { + syslog(LOG_ERR, "kevent(): %m"); + exit(EXIT_FAILURE); + } else if (r == 0) { + exit(EXIT_SUCCESS); + } + if ((r = accept(kev.ident, (struct sockaddr *)&ss, &slen)) == -1) { + syslog(LOG_ERR, "accept(): %m"); + exit(EXIT_FAILURE); + } + + c = fdopen(r, "r+"); + + fprintf(c, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"); + + fprintf(c, "\n\n"); + + launch_data_set_string(msg, LAUNCH_KEY_GETJOBS); + + resp = launch_msg(msg); + + launch_print_obj(resp, c); + + fprintf(c, "\n\n"); + + fclose(c); + + exit(EXIT_SUCCESS); +} + +static void launch_print_obj(launch_data_t o, FILE *w) +{ + size_t i; + void launch_print_obj_dict_callback(launch_data_t obj, const char *key, void *context __attribute__((unused))) { + fprintf(w, "%s\n", key); + if (launch_data_get_type(obj) != LAUNCH_DATA_ARRAY && + launch_data_get_type(obj) != LAUNCH_DATA_DICTIONARY) + fprintf(w, "
  • \n"); + launch_print_obj(obj, w); + if (launch_data_get_type(obj) != LAUNCH_DATA_ARRAY && + launch_data_get_type(obj) != LAUNCH_DATA_DICTIONARY) + fprintf(w, "
\n"); + } + + + switch (launch_data_get_type(o)) { + case LAUNCH_DATA_DICTIONARY: + fprintf(w, "
  • \n"); + launch_data_dict_iterate(o, launch_print_obj_dict_callback, NULL); + fprintf(w, "
\n"); + break; + case LAUNCH_DATA_ARRAY: + fprintf(w, "
    \n"); + for (i = 0; i < launch_data_array_get_count(o); i++) { + fprintf(w, "
  1. "); + launch_print_obj(launch_data_array_get_index(o, i), w); + fprintf(w, "
  2. \n"); + } + fprintf(w, "
\n"); + break; + case LAUNCH_DATA_INTEGER: + fprintf(w, "Number: %lld", launch_data_get_integer(o)); + break; + case LAUNCH_DATA_REAL: + fprintf(w, "Float: %f", launch_data_get_real(o)); + break; + case LAUNCH_DATA_STRING: + fprintf(w, "String: %s", launch_data_get_string(o)); + break; + case LAUNCH_DATA_OPAQUE: + fprintf(w, "Opaque: %p size %zu", launch_data_get_opaque(o), launch_data_get_opaque_size(o)); + break; + case LAUNCH_DATA_FD: + fprintf(w, "FD: %d", launch_data_get_fd(o)); + break; + case LAUNCH_DATA_BOOL: + fprintf(w, "Bool: %s", launch_data_get_bool(o) ? "true" : "false"); + break; + default: + fprintf(w, "type %d is unknown", launch_data_get_type(o)); + break; + } +} diff --git a/launchd/src/launchproxy.8 b/launchd/src/launchproxy.8 new file mode 100644 index 0000000..c667843 --- /dev/null +++ b/launchd/src/launchproxy.8 @@ -0,0 +1,19 @@ +.Dd February 2, 2005 +.Dt launchproxy 8 +.Os Darwin +.Sh NAME +.Nm launchproxy +.Nd inetd job emulation helper +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +.Nm +handles the inetd emulation for +.Nm launchd . +This program may be merged into +.Nm launchd +in the future. +.Sh SEE ALSO +.Xr launchctl 1 , +.Xr launchd.plist 5 , +.Xr launchd 8 diff --git a/launchd/src/launchproxy.c b/launchd/src/launchproxy.c new file mode 100644 index 0000000..481c8eb --- /dev/null +++ b/launchd/src/launchproxy.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "launch.h" + +static int kq = 0; + +static void find_fds(launch_data_t o, const char *key __attribute__((unused)), void *context __attribute__((unused))) +{ + struct kevent kev; + size_t i; + int fd; + + switch (launch_data_get_type(o)) { + case LAUNCH_DATA_FD: + fd = launch_data_get_fd(o); + if (-1 == fd) + break; + fcntl(fd, F_SETFD, 1); + EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, NULL); + if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) + syslog(LOG_DEBUG, "kevent(%d): %m", fd); + break; + case LAUNCH_DATA_ARRAY: + for (i = 0; i < launch_data_array_get_count(o); i++) + find_fds(launch_data_array_get_index(o, i), NULL, NULL); + break; + case LAUNCH_DATA_DICTIONARY: + launch_data_dict_iterate(o, find_fds, NULL); + break; + default: + break; + } +} + +int main(int argc __attribute__((unused)), char *argv[]) +{ + struct timespec timeout = { 10, 0 }; + struct sockaddr_storage ss; + socklen_t slen = sizeof(ss); + struct kevent kev; + int r, ec = EXIT_FAILURE; + launch_data_t tmp, resp, msg = launch_data_alloc(LAUNCH_DATA_STRING); + const char *prog = argv[1]; + bool w = false, dupstdout = true, dupstderr = true; + + launch_data_set_string(msg, LAUNCH_KEY_CHECKIN); + + openlog(getprogname(), LOG_PERROR|LOG_PID|LOG_CONS, LOG_LAUNCHD); + + kq = kqueue(); + + if ((resp = launch_msg(msg)) == NULL) { + syslog(LOG_ERR, "launch_msg(%s): %m", LAUNCH_KEY_CHECKIN); + goto out; + } + + launch_data_free(msg); + + tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS); + if (tmp) { + find_fds(tmp, NULL, NULL); + } else { + syslog(LOG_ERR, "No FDs found to answer requests on!"); + goto out; + } + + tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_TIMEOUT); + if (tmp) + timeout.tv_sec = launch_data_get_integer(tmp); + + tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_PROGRAM); + if (tmp) + prog = launch_data_get_string(tmp); + + tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_INETDCOMPATIBILITY); + if (tmp) { + tmp = launch_data_dict_lookup(tmp, LAUNCH_JOBINETDCOMPATIBILITY_WAIT); + if (tmp) + w = launch_data_get_bool(tmp); + } + + if (launch_data_dict_lookup(resp, LAUNCH_JOBKEY_STANDARDOUTPATH)) + dupstdout = false; + + if (launch_data_dict_lookup(resp, LAUNCH_JOBKEY_STANDARDERRORPATH)) + dupstderr = false; + + if (!w) + signal(SIGCHLD, SIG_IGN); + + for (;;) { + if ((r = kevent(kq, NULL, 0, &kev, 1, &timeout)) == -1) { + syslog(LOG_DEBUG, "kevent(): %m"); + goto out; + } else if (r == 0) { + ec = EXIT_SUCCESS; + goto out; + } + + if (w) { + dup2(kev.ident, STDIN_FILENO); + if (dupstdout) + dup2(kev.ident, STDOUT_FILENO); + if (dupstderr) + dup2(kev.ident, STDERR_FILENO); + execv(prog, argv + 1); + syslog(LOG_ERR, "execv(): %m"); + exit(EXIT_FAILURE); + } + + if ((r = accept(kev.ident, (struct sockaddr *)&ss, &slen)) == -1) { + if (errno == EWOULDBLOCK) + continue; + syslog(LOG_DEBUG, "accept(): %m"); + goto out; + } else { + char fromhost[NI_MAXHOST]; + char fromport[NI_MAXSERV]; + int gni_r; + + gni_r = getnameinfo((struct sockaddr *)&ss, slen, + fromhost, sizeof(fromhost), + fromport, sizeof(fromport), + NI_NUMERICHOST | NI_NUMERICSERV); + + if (gni_r) { + syslog(LOG_WARNING, "%s: getnameinfo(): %s", prog, gai_strerror(gni_r)); + } else { + syslog(LOG_INFO, "%s: Connection from: %s on port: %s", prog, fromhost, fromport); + } + + switch (fork()) { + case -1: + syslog(LOG_WARNING, "fork(): %m"); + goto out; + case 0: + break; + default: + close(r); + continue; + } + + if ((tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SESSIONCREATE)) && launch_data_get_bool(tmp)) { + if (SessionCreate) { + OSStatus scr = SessionCreate(0, 0); + if (scr != noErr) + syslog(LOG_NOTICE, "%s: SessionCreate() failed: %d", prog, scr); + } else { + syslog(LOG_NOTICE, "%s: SessionCreate == NULL!", prog); + } + } + fcntl(r, F_SETFL, 0); + dup2(r, STDIN_FILENO); + if (dupstdout) + dup2(r, STDOUT_FILENO); + if (dupstderr) + dup2(r, STDERR_FILENO); + signal(SIGCHLD, SIG_DFL); + execv(prog, argv + 1); + syslog(LOG_ERR, "execv(): %m"); + exit(EXIT_FAILURE); + } + } + +out: + exit(ec); +} diff --git a/launchd/src/liblaunch.c b/launchd/src/liblaunch.c new file mode 100644 index 0000000..cc23170 --- /dev/null +++ b/launchd/src/liblaunch.c @@ -0,0 +1,927 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "launch.h" +#include "launch_priv.h" + +struct _launch_data { + launch_data_type_t type; + union { + struct { + launch_data_t *_array; + size_t _array_cnt; + }; + struct { + char *string; + size_t string_len; + }; + struct { + void *opaque; + size_t opaque_size; + }; + int fd; + int err; + long long number; + bool boolean; + double float_num; + }; +}; + +struct _launch { + void *sendbuf; + int *sendfds; + void *recvbuf; + int *recvfds; + size_t sendlen; + size_t sendfdcnt; + size_t recvlen; + size_t recvfdcnt; + int fd; +}; + +static void make_msg_and_cmsg(launch_data_t, void **, size_t *, int **, size_t *); +static launch_data_t make_data(launch_t, size_t *, size_t *); +static int _fd(int fd); + +static pthread_once_t _lc_once = PTHREAD_ONCE_INIT; + +static struct _launch_client { + pthread_mutex_t mtx; + launch_t l; + launch_data_t async_resp; +} *_lc = NULL; + +static void launch_client_init(void) +{ + struct sockaddr_un sun; + char *where = getenv(LAUNCHD_SOCKET_ENV); + char *_launchd_fd = getenv(LAUNCHD_TRUSTED_FD_ENV); + int r, dfd, lfd = -1, tries; + + _lc = calloc(1, sizeof(struct _launch_client)); + + if (!_lc) + return; + + pthread_mutex_init(&_lc->mtx, NULL); + + if (_launchd_fd) { + lfd = strtol(_launchd_fd, NULL, 10); + if ((dfd = dup(lfd)) >= 0) { + close(dfd); + _fd(lfd); + } else { + lfd = -1; + } + unsetenv(LAUNCHD_TRUSTED_FD_ENV); + } + if (lfd == -1) { + memset(&sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; + + if (where) + strncpy(sun.sun_path, where, sizeof(sun.sun_path)); + else + snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%u/sock", LAUNCHD_SOCK_PREFIX, getuid()); + + if ((lfd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1) + goto out_bad; + + for (tries = 0; tries < 10; tries++) { + r = connect(lfd, (struct sockaddr *)&sun, sizeof(sun)); + if (r == -1) { + if (getuid() != 0 && fork() == 0) + execl("/sbin/launchd", "/sbin/launchd", NULL); + sleep(1); + } else { + break; + } + } + if (r == -1) { + close(lfd); + goto out_bad; + } + } + if (!(_lc->l = launchd_fdopen(lfd))) { + close(lfd); + goto out_bad; + } + if (!(_lc->async_resp = launch_data_alloc(LAUNCH_DATA_ARRAY))) + goto out_bad; + + return; +out_bad: + if (_lc->l) + launchd_close(_lc->l); + if (_lc) + free(_lc); + _lc = NULL; +} + +launch_data_t launch_data_alloc(launch_data_type_t t) +{ + launch_data_t d = calloc(1, sizeof(struct _launch)); + + if (d) { + d->type = t; + switch (t) { + case LAUNCH_DATA_DICTIONARY: + case LAUNCH_DATA_ARRAY: + d->_array = malloc(0); + break; + default: + break; + } + } + + return d; +} + +launch_data_type_t launch_data_get_type(launch_data_t d) +{ + return d->type; +} + +void launch_data_free(launch_data_t d) +{ + size_t i; + + switch (d->type) { + case LAUNCH_DATA_DICTIONARY: + case LAUNCH_DATA_ARRAY: + for (i = 0; i < d->_array_cnt; i++) + launch_data_free(d->_array[i]); + free(d->_array); + break; + case LAUNCH_DATA_STRING: + if (d->string) + free(d->string); + break; + case LAUNCH_DATA_OPAQUE: + if (d->opaque) + free(d->opaque); + break; + default: + break; + } + free(d); +} + +size_t launch_data_dict_get_count(launch_data_t dict) +{ + return dict->_array_cnt / 2; +} + + +bool launch_data_dict_insert(launch_data_t dict, launch_data_t what, const char *key) +{ + size_t i; + launch_data_t thekey = launch_data_alloc(LAUNCH_DATA_STRING); + + launch_data_set_string(thekey, key); + + for (i = 0; i < dict->_array_cnt; i += 2) { + if (!strcasecmp(key, dict->_array[i]->string)) { + launch_data_array_set_index(dict, thekey, i); + launch_data_array_set_index(dict, what, i + 1); + return true; + } + } + launch_data_array_set_index(dict, thekey, i); + launch_data_array_set_index(dict, what, i + 1); + return true; +} + +launch_data_t launch_data_dict_lookup(launch_data_t dict, const char *key) +{ + size_t i; + + if (LAUNCH_DATA_DICTIONARY != dict->type) + return NULL; + + for (i = 0; i < dict->_array_cnt; i += 2) { + if (!strcasecmp(key, dict->_array[i]->string)) + return dict->_array[i + 1]; + } + + return NULL; +} + +bool launch_data_dict_remove(launch_data_t dict, const char *key) +{ + size_t i; + + for (i = 0; i < dict->_array_cnt; i += 2) { + if (!strcasecmp(key, dict->_array[i]->string)) + break; + } + if (i == dict->_array_cnt) + return false; + launch_data_free(dict->_array[i]); + launch_data_free(dict->_array[i + 1]); + memmove(dict->_array + i, dict->_array + i + 2, (dict->_array_cnt - (i + 2)) * sizeof(launch_data_t)); + dict->_array_cnt -= 2; + return true; +} + +void launch_data_dict_iterate(launch_data_t dict, void (*cb)(launch_data_t, const char *, void *), void *context) +{ + size_t i; + + if (LAUNCH_DATA_DICTIONARY != dict->type) + return; + + for (i = 0; i < dict->_array_cnt; i += 2) + cb(dict->_array[i + 1], dict->_array[i]->string, context); +} + +bool launch_data_array_set_index(launch_data_t where, launch_data_t what, size_t ind) +{ + if ((ind + 1) >= where->_array_cnt) { + where->_array = realloc(where->_array, (ind + 1) * sizeof(launch_data_t)); + memset(where->_array + where->_array_cnt, 0, (ind + 1 - where->_array_cnt) * sizeof(launch_data_t)); + where->_array_cnt = ind + 1; + } + + if (where->_array[ind]) + launch_data_free(where->_array[ind]); + where->_array[ind] = what; + return true; +} + +launch_data_t launch_data_array_get_index(launch_data_t where, size_t ind) +{ + if (LAUNCH_DATA_ARRAY != where->type) + return NULL; + if (ind < where->_array_cnt) + return where->_array[ind]; + return NULL; +} + +launch_data_t launch_data_array_pop_first(launch_data_t where) +{ + launch_data_t r = NULL; + + if (where->_array_cnt > 0) { + r = where->_array[0]; + memmove(where->_array, where->_array + 1, (where->_array_cnt - 1) * sizeof(launch_data_t)); + where->_array_cnt--; + } + return r; +} + +size_t launch_data_array_get_count(launch_data_t where) +{ + if (LAUNCH_DATA_ARRAY != where->type) + return 0; + return where->_array_cnt; +} + +bool launch_data_set_errno(launch_data_t d, int e) +{ + d->err = e; + return true; +} + +bool launch_data_set_fd(launch_data_t d, int fd) +{ + d->fd = fd; + return true; +} + +bool launch_data_set_integer(launch_data_t d, long long n) +{ + d->number = n; + return true; +} + +bool launch_data_set_bool(launch_data_t d, bool b) +{ + d->boolean = b; + return true; +} + +bool launch_data_set_real(launch_data_t d, double n) +{ + d->float_num = n; + return true; +} + +bool launch_data_set_string(launch_data_t d, const char *s) +{ + if (d->string) + free(d->string); + d->string = strdup(s); + if (d->string) { + d->string_len = strlen(d->string); + return true; + } + return false; +} + +bool launch_data_set_opaque(launch_data_t d, const void *o, size_t os) +{ + d->opaque_size = os; + if (d->opaque) + free(d->opaque); + d->opaque = malloc(os); + if (d->opaque) { + memcpy(d->opaque, o, os); + return true; + } + return false; +} + +int launch_data_get_errno(launch_data_t d) +{ + return d->err; +} + +int launch_data_get_fd(launch_data_t d) +{ + return d->fd; +} + +long long launch_data_get_integer(launch_data_t d) +{ + return d->number; +} + +bool launch_data_get_bool(launch_data_t d) +{ + return d->boolean; +} + +double launch_data_get_real(launch_data_t d) +{ + return d->float_num; +} + +const char *launch_data_get_string(launch_data_t d) +{ + if (LAUNCH_DATA_STRING != d->type) + return NULL; + return d->string; +} + +void *launch_data_get_opaque(launch_data_t d) +{ + if (LAUNCH_DATA_OPAQUE != d->type) + return NULL; + return d->opaque; +} + +size_t launch_data_get_opaque_size(launch_data_t d) +{ + return d->opaque_size; +} + +int launchd_getfd(launch_t l) +{ + return l->fd; +} + +launch_t launchd_fdopen(int fd) +{ + launch_t c; + + c = calloc(1, sizeof(struct _launch)); + if (!c) + return NULL; + + c->fd = fd; + + fcntl(fd, F_SETFL, O_NONBLOCK); + + if ((c->sendbuf = malloc(0)) == NULL) + goto out_bad; + if ((c->sendfds = malloc(0)) == NULL) + goto out_bad; + if ((c->recvbuf = malloc(0)) == NULL) + goto out_bad; + if ((c->recvfds = malloc(0)) == NULL) + goto out_bad; + + return c; + +out_bad: + if (c->sendbuf) + free(c->sendbuf); + if (c->sendfds) + free(c->sendfds); + if (c->recvbuf) + free(c->recvbuf); + if (c->recvfds) + free(c->recvfds); + free(c); + return NULL; +} + +void launchd_close(launch_t lh) +{ + if (lh->sendbuf) + free(lh->sendbuf); + if (lh->sendfds) + free(lh->sendfds); + if (lh->recvbuf) + free(lh->recvbuf); + if (lh->recvfds) + free(lh->recvfds); + close(lh->fd); + free(lh); +} + +static void make_msg_and_cmsg(launch_data_t d, void **where, size_t *len, int **fd_where, size_t *fdcnt) +{ + size_t i; + + *where = realloc(*where, *len + sizeof(struct _launch_data)); + memcpy(*where + *len, d, sizeof(struct _launch_data)); + *len += sizeof(struct _launch_data); + + switch (d->type) { + case LAUNCH_DATA_FD: + if (d->fd != -1) { + *fd_where = realloc(*fd_where, (*fdcnt + 1) * sizeof(int)); + (*fd_where)[*fdcnt] = d->fd; + (*fdcnt)++; + } + break; + case LAUNCH_DATA_STRING: + *where = realloc(*where, *len + strlen(d->string) + 1); + memcpy(*where + *len, d->string, strlen(d->string) + 1); + *len += strlen(d->string) + 1; + break; + case LAUNCH_DATA_OPAQUE: + *where = realloc(*where, *len + d->opaque_size); + memcpy(*where + *len, d->opaque, d->opaque_size); + *len += d->opaque_size; + break; + case LAUNCH_DATA_DICTIONARY: + case LAUNCH_DATA_ARRAY: + *where = realloc(*where, *len + (d->_array_cnt * sizeof(launch_data_t))); + memcpy(*where + *len, d->_array, d->_array_cnt * sizeof(launch_data_t)); + *len += d->_array_cnt * sizeof(launch_data_t); + + for (i = 0; i < d->_array_cnt; i++) + make_msg_and_cmsg(d->_array[i], where, len, fd_where, fdcnt); + break; + default: + break; + } +} + +static launch_data_t make_data(launch_t conn, size_t *data_offset, size_t *fdoffset) +{ + launch_data_t r = conn->recvbuf + *data_offset; + size_t i; + + if ((conn->recvlen - *data_offset) < sizeof(struct _launch_data)) + return NULL; + *data_offset += sizeof(struct _launch_data); + + switch (r->type) { + case LAUNCH_DATA_DICTIONARY: + case LAUNCH_DATA_ARRAY: + if ((conn->recvlen - *data_offset) < (r->_array_cnt * sizeof(launch_data_t))) { + errno = EAGAIN; + return NULL; + } + r->_array = conn->recvbuf + *data_offset; + *data_offset += r->_array_cnt * sizeof(launch_data_t); + for (i = 0; i < r->_array_cnt; i++) { + r->_array[i] = make_data(conn, data_offset, fdoffset); + if (r->_array[i] == NULL) + return NULL; + } + break; + case LAUNCH_DATA_STRING: + if ((conn->recvlen - *data_offset) < (r->string_len + 1)) { + errno = EAGAIN; + return NULL; + } + r->string = conn->recvbuf + *data_offset; + *data_offset += r->string_len + 1; + break; + case LAUNCH_DATA_OPAQUE: + if ((conn->recvlen - *data_offset) < r->opaque_size) { + errno = EAGAIN; + return NULL; + } + r->opaque = conn->recvbuf + *data_offset; + *data_offset += r->opaque_size; + break; + case LAUNCH_DATA_FD: + if (r->fd != -1) { + r->fd = _fd(conn->recvfds[*fdoffset]); + *fdoffset += 1; + } + break; + case LAUNCH_DATA_INTEGER: + case LAUNCH_DATA_REAL: + case LAUNCH_DATA_BOOL: + case LAUNCH_DATA_ERRNO: + break; + default: + errno = EINVAL; + return NULL; + break; + } + + return r; +} + +int launchd_msg_send(launch_t lh, launch_data_t d) +{ + struct cmsghdr *cm = NULL; + struct msghdr mh; + struct iovec iov; + int r; + size_t sentctrllen = 0; + + memset(&mh, 0, sizeof(mh)); + + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + + if (d) + make_msg_and_cmsg(d, &lh->sendbuf, &lh->sendlen, &lh->sendfds, &lh->sendfdcnt); + + if (lh->sendfdcnt > 0) { + sentctrllen = mh.msg_controllen = CMSG_SPACE(lh->sendfdcnt * sizeof(int)); + cm = alloca(mh.msg_controllen); + mh.msg_control = cm; + + memset(cm, 0, mh.msg_controllen); + + cm->cmsg_len = CMSG_LEN(lh->sendfdcnt * sizeof(int)); + cm->cmsg_level = SOL_SOCKET; + cm->cmsg_type = SCM_RIGHTS; + + memcpy(CMSG_DATA(cm), lh->sendfds, lh->sendfdcnt * sizeof(int)); + } + + iov.iov_base = lh->sendbuf; + iov.iov_len = lh->sendlen; + + if ((r = sendmsg(lh->fd, &mh, 0)) == -1) { + return -1; + } else if (r == 0) { + errno = ECONNRESET; + return -1; + } else if (sentctrllen != mh.msg_controllen) { + errno = ECONNRESET; + return -1; + } + + lh->sendlen -= r; + if (lh->sendlen > 0) { + memmove(lh->sendbuf, lh->sendbuf + r, lh->sendlen); + } else { + free(lh->sendbuf); + lh->sendbuf = malloc(0); + } + + lh->sendfdcnt = 0; + free(lh->sendfds); + lh->sendfds = malloc(0); + + if (lh->sendlen > 0) { + errno = EAGAIN; + return -1; + } + + return 0; +} + + +int launch_get_fd(void) +{ + pthread_once(&_lc_once, launch_client_init); + + if (!_lc) { + errno = ENOTCONN; + return -1; + } + + return _lc->l->fd; +} + +static void launch_msg_getmsgs(launch_data_t m, void *context) +{ + launch_data_t async_resp, *sync_resp = context; + + if ((LAUNCH_DATA_DICTIONARY == launch_data_get_type(m)) && (async_resp = launch_data_dict_lookup(m, LAUNCHD_ASYNC_MSG_KEY))) { + launch_data_array_set_index(_lc->async_resp, launch_data_copy(async_resp), launch_data_array_get_count(_lc->async_resp)); + } else { + *sync_resp = launch_data_copy(m); + } +} + +launch_data_t launch_msg(launch_data_t d) +{ + launch_data_t resp = NULL; + + pthread_once(&_lc_once, launch_client_init); + + if (!_lc) { + errno = ENOTCONN; + return NULL; + } + + pthread_mutex_lock(&_lc->mtx); + + if (d && launchd_msg_send(_lc->l, d) == -1) { + do { + if (errno != EAGAIN) + goto out; + } while (launchd_msg_send(_lc->l, NULL) == -1); + } + + while (resp == NULL) { + if (d == NULL && launch_data_array_get_count(_lc->async_resp) > 0) { + resp = launch_data_array_pop_first(_lc->async_resp); + goto out; + } + if (launchd_msg_recv(_lc->l, launch_msg_getmsgs, &resp) == -1) { + if (errno != EAGAIN) { + goto out; + } else if (d == NULL) { + errno = 0; + goto out; + } else { + fd_set rfds; + + FD_ZERO(&rfds); + FD_SET(_lc->l->fd, &rfds); + + select(_lc->l->fd + 1, &rfds, NULL, NULL, NULL); + } + } + } + +out: + pthread_mutex_unlock(&_lc->mtx); + + return resp; +} + +int launchd_msg_recv(launch_t lh, void (*cb)(launch_data_t, void *), void *context) +{ + struct cmsghdr *cm = alloca(4096); + launch_data_t rmsg; + size_t data_offset, fd_offset; + struct msghdr mh; + struct iovec iov; + int r; + + memset(&mh, 0, sizeof(mh)); + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + + lh->recvbuf = realloc(lh->recvbuf, lh->recvlen + 8*1024); + + iov.iov_base = lh->recvbuf + lh->recvlen; + iov.iov_len = 8*1024; + mh.msg_control = cm; + mh.msg_controllen = 4096; + + if ((r = recvmsg(lh->fd, &mh, 0)) == -1) + return -1; + if (r == 0) { + errno = ECONNRESET; + return -1; + } + if (mh.msg_flags & MSG_CTRUNC) { + errno = ECONNABORTED; + return -1; + } + lh->recvlen += r; + if (mh.msg_controllen > 0) { + lh->recvfds = realloc(lh->recvfds, lh->recvfdcnt * sizeof(int) + mh.msg_controllen - sizeof(struct cmsghdr)); + memcpy(lh->recvfds + lh->recvfdcnt, CMSG_DATA(cm), mh.msg_controllen - sizeof(struct cmsghdr)); + lh->recvfdcnt += (mh.msg_controllen - sizeof(struct cmsghdr)) / sizeof(int); + } + +parse_more: + data_offset = 0; + fd_offset = 0; + + rmsg = make_data(lh, &data_offset, &fd_offset); + + if (rmsg) { + cb(rmsg, context); + + lh->recvlen -= data_offset; + if (lh->recvlen > 0) { + memmove(lh->recvbuf, lh->recvbuf + data_offset, lh->recvlen); + } else { + free(lh->recvbuf); + lh->recvbuf = malloc(0); + } + + lh->recvfdcnt -= fd_offset; + if (lh->recvfdcnt > 0) { + memmove(lh->recvfds, lh->recvfds + fd_offset, lh->recvfdcnt * sizeof(int)); + } else { + free(lh->recvfds); + lh->recvfds = malloc(0); + } + + if (lh->recvlen > 0) + goto parse_more; + else + r = 0; + } else { + errno = EAGAIN; + r = -1; + } + + return r; +} + +launch_data_t launch_data_copy(launch_data_t o) +{ + launch_data_t r = launch_data_alloc(o->type); + size_t i; + + free(r->_array); + memcpy(r, o, sizeof(struct _launch_data)); + + switch (o->type) { + case LAUNCH_DATA_DICTIONARY: + case LAUNCH_DATA_ARRAY: + r->_array = calloc(1, o->_array_cnt * sizeof(launch_data_t)); + for (i = 0; i < o->_array_cnt; i++) { + if (o->_array[i]) + r->_array[i] = launch_data_copy(o->_array[i]); + } + break; + case LAUNCH_DATA_STRING: + r->string = strdup(o->string); + break; + case LAUNCH_DATA_OPAQUE: + r->opaque = malloc(o->opaque_size); + memcpy(r->opaque, o->opaque, o->opaque_size); + break; + default: + break; + } + + return r; +} + +void launchd_batch_enable(bool val) +{ + launch_data_t resp, tmp, msg; + + tmp = launch_data_alloc(LAUNCH_DATA_BOOL); + launch_data_set_bool(tmp, val); + + msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + launch_data_dict_insert(msg, tmp, LAUNCH_KEY_BATCHCONTROL); + + resp = launch_msg(msg); + + launch_data_free(msg); + + if (resp) + launch_data_free(resp); +} + +bool launchd_batch_query(void) +{ + launch_data_t resp, msg = launch_data_alloc(LAUNCH_DATA_STRING); + bool rval = true; + + launch_data_set_string(msg, LAUNCH_KEY_BATCHQUERY); + + resp = launch_msg(msg); + + launch_data_free(msg); + + if (resp) { + if (launch_data_get_type(resp) == LAUNCH_DATA_BOOL) + rval = launch_data_get_bool(resp); + launch_data_free(resp); + } + return rval; +} + +static int _fd(int fd) +{ + if (fd >= 0) + fcntl(fd, F_SETFD, 1); + return fd; +} + +launch_data_t launch_data_new_errno(int e) +{ + launch_data_t r = launch_data_alloc(LAUNCH_DATA_ERRNO); + + if (r) + launch_data_set_errno(r, e); + + return r; +} + +launch_data_t launch_data_new_fd(int fd) +{ + launch_data_t r = launch_data_alloc(LAUNCH_DATA_FD); + + if (r) + launch_data_set_fd(r, fd); + + return r; +} + +launch_data_t launch_data_new_integer(long long n) +{ + launch_data_t r = launch_data_alloc(LAUNCH_DATA_INTEGER); + + if (r) + launch_data_set_integer(r, n); + + return r; +} + +launch_data_t launch_data_new_bool(bool b) +{ + launch_data_t r = launch_data_alloc(LAUNCH_DATA_BOOL); + + if (r) + launch_data_set_bool(r, b); + + return r; +} + +launch_data_t launch_data_new_real(double d) +{ + launch_data_t r = launch_data_alloc(LAUNCH_DATA_REAL); + + if (r) + launch_data_set_real(r, d); + + return r; +} + +launch_data_t launch_data_new_string(const char *s) +{ + launch_data_t r = launch_data_alloc(LAUNCH_DATA_STRING); + + if (r == NULL) + return NULL; + + if (!launch_data_set_string(r, s)) { + launch_data_free(r); + return NULL; + } + + return r; +} + +launch_data_t launch_data_new_opaque(const void *o, size_t os) +{ + launch_data_t r = launch_data_alloc(LAUNCH_DATA_OPAQUE); + + if (r == NULL) + return NULL; + + if (!launch_data_set_opaque(r, o, os)) { + launch_data_free(r); + return NULL; + } + + return r; +} diff --git a/launchd/src/lists.c b/launchd/src/lists.c new file mode 100644 index 0000000..8e3eed7 --- /dev/null +++ b/launchd/src/lists.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * bootstrap -- fundamental service initiator and port server + * Mike DeMoney, NeXT, Inc. + * Copyright, 1990. All rights reserved. + * + * lists.c -- implementation of list handling routines + */ + +#include +#include + +#include +#include +#include + +#include + +#include "bootstrap_internal.h" +#include "lists.h" + +/* + * Exports + */ +bootstrap_info_t bootstraps; /* head of list of all bootstrap ports */ +server_t servers; /* head of list of all servers */ +service_t services; /* head of list of all services */ +unsigned nservices; /* number of services in list */ + +#ifndef ASSERT +#define ASSERT(p) +#endif + +/* + * Private macros + */ +#define NEW(type, num) ((type *)ckmalloc(sizeof(type) * num)) +#define STREQ(a, b) (strcmp(a, b) == 0) +#define NELEM(x) (sizeof(x)/sizeof((x)[0])) +#define LAST_ELEMENT(x) ((x)[NELEM(x)-1]) + +void +init_lists(void) +{ + bootstraps.ref_count = 2; /* make sure we never deallocate this one */ + bootstraps.next = bootstraps.prev = &bootstraps; + bootstraps.parent = &bootstraps; + servers.next = servers.prev = &servers; + services.next = services.prev = &services; + nservices = 0; +} + +server_t * +new_server( + bootstrap_info_t *bootstrap, + const char *cmd, + uid_t uid, + servertype_t servertype, + auditinfo_t auinfo) +{ + server_t *serverp; + + syslog(LOG_DEBUG, "adding new server \"%s\" with uid %d", cmd, uid); + serverp = NEW(server_t, 1); + if (serverp != NULL) { + /* Doubly linked list */ + servers.prev->next = serverp; + serverp->prev = servers.prev; + serverp->next = &servers; + servers.prev = serverp; + + bootstrap->ref_count++; + serverp->bootstrap = bootstrap; + + serverp->pid = NO_PID; + serverp->task_port = MACH_PORT_NULL; + + serverp->uid = uid; + serverp->auinfo = auinfo; + + serverp->port = MACH_PORT_NULL; + serverp->servertype = servertype; + serverp->activity = 0; + serverp->active_services = 0; + strncpy(serverp->cmd, cmd, sizeof serverp->cmd); + LAST_ELEMENT(serverp->cmd) = '\0'; + } + return serverp; +} + +service_t * +new_service( + bootstrap_info_t *bootstrap, + const char *name, + mach_port_t serviceport, + boolean_t isActive, + servicetype_t servicetype, + server_t *serverp) +{ + service_t *servicep; + + servicep = NEW(service_t, 1); + if (servicep != NULL) { + /* Doubly linked list */ + services.prev->next = servicep; + servicep->prev = services.prev; + servicep->next = &services; + services.prev = servicep; + + nservices += 1; + + strncpy(servicep->name, name, sizeof servicep->name); + LAST_ELEMENT(servicep->name) = '\0'; + servicep->servicetype = servicetype; + servicep->bootstrap = bootstrap; + servicep->port = serviceport; + servicep->server = serverp; + servicep->isActive = isActive; + } + return servicep; +} + +bootstrap_info_t * +new_bootstrap( + bootstrap_info_t *parent, + mach_port_t bootstrapport, + mach_port_t requestorport) +{ + bootstrap_info_t *bootstrap; + + bootstrap = NEW(bootstrap_info_t, 1); + if (bootstrap != NULL) { + /* Doubly linked list */ + bootstraps.prev->next = bootstrap; + bootstrap->prev = bootstraps.prev; + bootstrap->next = &bootstraps; + bootstraps.prev = bootstrap; + + bootstrap->bootstrap_port = bootstrapport; + bootstrap->requestor_port = requestorport; + + bootstrap->ref_count = 1; + bootstrap->parent = parent; + parent->ref_count++; + } + return bootstrap; +} + +bootstrap_info_t * +lookup_bootstrap_by_port(mach_port_t port) +{ + bootstrap_info_t *bootstrap; + bootstrap_info_t *first; + server_t *serverp; + + bootstrap = first = FIRST(bootstraps); + do { + if (bootstrap->bootstrap_port == port) + return bootstrap; + bootstrap = NEXT(bootstrap); + } while (bootstrap != first); + + for ( serverp = FIRST(servers) + ; !IS_END(serverp, servers) + ; serverp = NEXT(serverp)) + { + if (port == serverp->port) + return serverp->bootstrap; + } + return NULL; +} + +bootstrap_info_t * +lookup_bootstrap_by_req_port(mach_port_t port) +{ + bootstrap_info_t *bootstrap; + + for ( bootstrap = FIRST(bootstraps) + ; !IS_END(bootstrap, bootstraps) + ; bootstrap = NEXT(bootstrap)) + { + if (bootstrap->requestor_port == port) + return bootstrap; + } + + return NULL; +} + +service_t * +lookup_service_by_name(bootstrap_info_t *bootstrap, name_t name) +{ + service_t *servicep; + + if (bootstrap) + do { + for ( servicep = FIRST(services) + ; !IS_END(servicep, services) + ; servicep = NEXT(servicep)) + { + if (!STREQ(name, servicep->name)) + continue; + if (bootstrap && servicep->bootstrap != bootstrap) + continue; + return servicep; + } + } while (bootstrap != &bootstraps && + (bootstrap = bootstrap->parent)); + return NULL; +} + +void +unlink_service(service_t *servicep) +{ + ASSERT(servicep->prev->next == servicep); + ASSERT(servicep->next->prev == servicep); + servicep->prev->next = servicep->next; + servicep->next->prev = servicep->prev; + servicep->prev = servicep->next = servicep; // idempotent +} + +void +delete_service(service_t *servicep) +{ + unlink_service(servicep); + switch (servicep->servicetype) { + case REGISTERED: + syslog(LOG_INFO, "Registered service %s deleted", servicep->name); + mach_port_deallocate(mach_task_self(), servicep->port); + break; + case DECLARED: + syslog(LOG_INFO, "Declared service %s now unavailable", servicep->name); + mach_port_deallocate(mach_task_self(), servicep->port); + mach_port_mod_refs(mach_task_self(), servicep->port, + MACH_PORT_RIGHT_RECEIVE, -1); + break; + default: + syslog(LOG_ERR, "unknown service type %d", servicep->servicetype); + break; + } + free(servicep); + nservices -= 1; +} + +void +delete_bootstrap_services(bootstrap_info_t *bootstrap) +{ + server_t *serverp; + service_t *servicep; + service_t *next; + + for ( servicep = FIRST(services) + ; !IS_END(servicep, services) + ; servicep = next) + { + next = NEXT(servicep); + if (bootstrap != servicep->bootstrap) + continue; + + if (!servicep->isActive || !servicep->server) { + delete_service(servicep); + continue; + } + + serverp = servicep->server; + delete_service(servicep); + serverp->active_services--; + if (!active_server(serverp)) + delete_server(serverp); + } +} + +service_t * +lookup_service_by_port(mach_port_t port) +{ + service_t *servicep; + + for ( servicep = FIRST(services) + ; !IS_END(servicep, services) + ; servicep = NEXT(servicep)) + { + if (port == servicep->port) + return servicep; + } + return NULL; +} + +service_t * +lookup_service_by_server(server_t *serverp) +{ + service_t *servicep; + + for ( servicep = FIRST(services) + ; !IS_END(servicep, services) + ; servicep = NEXT(servicep)) + { + if (serverp == servicep->server) + return servicep; + } + return NULL; +} + +server_t * +lookup_server_by_task_port(mach_port_t port) +{ + server_t *serverp; + + for ( serverp = FIRST(servers) + ; !IS_END(serverp, servers) + ; serverp = NEXT(serverp)) + { + if (port == serverp->task_port) + return serverp; + } + return NULL; +} + +server_t * +lookup_server_by_port(mach_port_t port) +{ + server_t *serverp; + + for ( serverp = FIRST(servers) + ; !IS_END(serverp, servers) + ; serverp = NEXT(serverp)) + { + if (port == serverp->port) + return serverp; + } + return NULL; +} + +void +delete_server(server_t *serverp) +{ + service_t *servicep; + service_t *next; + + syslog(LOG_INFO, "Deleting server %s", serverp->cmd); + ASSERT(serverp->prev->next == serverp); + ASSERT(serverp->next->prev == serverp); + serverp->prev->next = serverp->next; + serverp->next->prev = serverp->prev; + + for ( servicep = FIRST(services) + ; !IS_END(servicep, services) + ; servicep = next) + { + next = NEXT(servicep); + if (serverp == servicep->server) + delete_service(servicep); + } + + deallocate_bootstrap(serverp->bootstrap); + + if (serverp->port) + mach_port_mod_refs(mach_task_self(), serverp->port, + MACH_PORT_RIGHT_RECEIVE, -1); + + free(serverp); +} + +void +deactivate_bootstrap(bootstrap_info_t *bootstrap) +{ + bootstrap_info_t *deactivating_bootstraps; + bootstrap_info_t *query_bootstrap; + bootstrap_info_t *next_limit; + bootstrap_info_t *limit; + + /* + * we need to recursively deactivate the whole subset tree below + * this point. But we don't want to do real recursion because + * we don't have a limit on the depth. So, build up a chain of + * active bootstraps anywhere underneath this one. + */ + deactivating_bootstraps = bootstrap; + bootstrap->deactivate = NULL; + for (next_limit = deactivating_bootstraps, limit = NULL + ; deactivating_bootstraps != limit + ; limit = next_limit, next_limit = deactivating_bootstraps) + { + for (bootstrap = deactivating_bootstraps + ; bootstrap != limit + ; bootstrap = bootstrap->deactivate) + { + for ( query_bootstrap = FIRST(bootstraps) + ; !IS_END(query_bootstrap, bootstraps) + ; query_bootstrap = NEXT(query_bootstrap)) + { + if (query_bootstrap->parent == bootstrap && + query_bootstrap->requestor_port != MACH_PORT_NULL) { + mach_port_deallocate( + mach_task_self(), + query_bootstrap->requestor_port); + query_bootstrap->requestor_port = MACH_PORT_NULL; + query_bootstrap->deactivate = deactivating_bootstraps; + deactivating_bootstraps = query_bootstrap; + } + } + } + } + + /* + * The list is ordered with the furthest away progeny being + * at the front, and concluding with the one we started with. + * This allows us to safely deactivate and remove the reference + * each holds on their parent without fear of the chain getting + * corrupted (because each active parent holds a reference on + * itself and that doesn't get removed until we reach its spot + * in the list). + */ + do { + bootstrap = deactivating_bootstraps; + deactivating_bootstraps = bootstrap->deactivate; + + syslog(LOG_INFO, "deactivating bootstrap %x", bootstrap->bootstrap_port); + + delete_bootstrap_services(bootstrap); + + mach_port_deallocate(mach_task_self(), bootstrap->bootstrap_port); + + { + mach_port_t previous; + mach_port_request_notification( + mach_task_self(), + bootstrap->bootstrap_port, + MACH_NOTIFY_NO_SENDERS, + 1, + bootstrap->bootstrap_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + &previous); + } + } while (deactivating_bootstraps != NULL); +} + +void +deallocate_bootstrap(bootstrap_info_t *bootstrap) +{ + ASSERT(bootstrap->prev->next == bootstrap); + ASSERT(bootstrap->next->prev == bootstrap); + if (--bootstrap->ref_count > 0) + return; + + bootstrap->prev->next = bootstrap->next; + bootstrap->next->prev = bootstrap->prev; + deallocate_bootstrap(bootstrap->parent); + free(bootstrap); +} + +void * +ckmalloc(unsigned nbytes) +{ + void *cp; + + if ((cp = malloc(nbytes)) == NULL) { + syslog(LOG_EMERG, "malloc(): %m"); + exit(EXIT_FAILURE); + } + return cp; +} + + diff --git a/launchd/src/lists.h b/launchd/src/lists.h new file mode 100644 index 0000000..1d65fd9 --- /dev/null +++ b/launchd/src/lists.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * bootstrap -- fundamental service initiator and port server + * Mike DeMoney, NeXT, Inc. + * Copyright, 1990. All rights reserved. + * + * lists.h -- interface to list routines + */ + +#include +#include +#include +#include + +#include + +#ifndef NULL +#define NULL ((void *)0) +#endif NULL + +typedef struct bootstrap bootstrap_info_t; +typedef struct service service_t; +typedef struct server server_t; + +/* Bootstrap info */ +struct bootstrap { + bootstrap_info_t *next; /* list of all bootstraps */ + bootstrap_info_t *prev; + bootstrap_info_t *parent; + bootstrap_info_t *deactivate; /* list being deactivated */ + mach_port_name_t bootstrap_port; + mach_port_name_t requestor_port; + unsigned int ref_count; +}; + +/* Service types */ +typedef enum { + DECLARED, /* Declared in config file */ + REGISTERED /* Registered dynamically */ +} servicetype_t; + +struct service { + service_t *next; /* list of all services */ + service_t *prev; + name_t name; /* service name */ + mach_port_name_t port; /* service port, + may have all rights if inactive */ + bootstrap_info_t *bootstrap; /* bootstrap port(s) used at this + * level. */ + boolean_t isActive; /* server is running */ + servicetype_t servicetype; /* Declared, Registered, or Machport */ + server_t *server; /* server, declared services only */ +}; + +/* Server types */ +typedef enum { + SERVER, /* Launchable server */ + RESTARTABLE, /* Restartable server */ + DEMAND, /* Restartable server - on demand */ + MACHINIT, /* mach_init doesn't get launched. */ +} servertype_t; + +#define NULL_SERVER NULL +#define ACTIVE TRUE + +struct server { + server_t *next; /* list of all servers */ + server_t *prev; + servertype_t servertype; + cmd_t cmd; /* server command to exec */ + uid_t uid; /* uid to exec server with */ + auditinfo_t auinfo; /* server's audit information */ + mach_port_t port; /* server's priv bootstrap port */ + mach_port_t task_port; /* server's task port */ + pid_t pid; /* server's pid */ + int activity; /* count of checkins/registers this instance */ + int active_services;/* count of active services */ + bootstrap_info_t *bootstrap; /* bootstrap context */ +}; + +#define NO_PID (-1) + +extern void init_lists(void); + +extern server_t *new_server( + bootstrap_info_t *bootstrap, + const char *cmd, + uid_t uid, + servertype_t servertype, + auditinfo_t auinfo); + +extern service_t *new_service( + bootstrap_info_t *bootstrap, + const char *name, + mach_port_t serviceport, + boolean_t isActive, + servicetype_t servicetype, + server_t *serverp); + +extern bootstrap_info_t *new_bootstrap( + bootstrap_info_t *parent, + mach_port_name_t bootstrapport, + mach_port_name_t requestorport); + +extern server_t *lookup_server_by_port(mach_port_t port); +extern server_t *lookup_server_by_task_port(mach_port_t port); +extern void setup_server(server_t *serverp); +extern void delete_server(server_t *serverp); +extern boolean_t active_server(server_t *serverp); +extern boolean_t useless_server(server_t *serverp); + +extern void delete_service(service_t *servicep); +extern service_t *lookup_service_by_name(bootstrap_info_t *bootstrap, name_t name); +extern service_t *lookup_service_by_port(mach_port_t port); +extern service_t *lookup_service_by_server(server_t *serverp); + +extern bootstrap_info_t *lookup_bootstrap_by_port(mach_port_t port); +extern bootstrap_info_t *lookup_bootstrap_by_req_port(mach_port_t port); +extern void deactivate_bootstrap(bootstrap_info_t *bootstrap); +extern void deallocate_bootstrap(bootstrap_info_t *bootstrap); +extern boolean_t active_bootstrap(bootstrap_info_t *bootstrap); + +extern void *ckmalloc(unsigned nbytes); + +extern bootstrap_info_t bootstraps; /* head of list of bootstrap ports */ +extern server_t servers; /* head of list of all servers */ +extern service_t services; /* head of list of all services */ +extern unsigned nservices; /* number of services in list */ + +#define FIRST(q) ((q).next) +#define NEXT(qe) ((qe)->next) +#define PREV(qe) ((qe)->prev) +#define IS_END(qe, q) ((qe) == &(q)) diff --git a/launchd/src/rc b/launchd/src/rc new file mode 100644 index 0000000..9a89261 --- /dev/null +++ b/launchd/src/rc @@ -0,0 +1,305 @@ +#!/bin/sh +# Copyright 1997-2004 Apple Computer, Inc. + +. /etc/rc.common + +export -n SafeBoot +export -n VerboseFlag +export -n FsckSlash +export -n NetBoot + +if [ -d /System/Installation -a -f /etc/rc.cdrom ]; then + /etc/rc.cdrom multiuser + # We shouldn't get here; CDIS should reboot the machine when done + echo "CD-ROM boot procedure complete" + halt +fi + +if [ "${NetBoot}" = "-N" ] ; then + echo "Initializing NetBoot" + if ! sh /etc/rc.netboot start ; then + echo NetBoot initialization failed, shut down in 10 seconds... + sleep 10 + halt + fi +fi + +if [ "${FsckSlash}" = "-F" ]; then + # Benignly clean up ("preen") any dirty filesystems. + # fsck -p will skip disks which were properly unmounted during + # a normal shutdown. + echo "Checking disk" + if [ "${SafeBoot}" = "-x" ]; then + fsck -fy || halt + else + fsck -p || fsck -fy || halt + fi +fi + +echo "Mounting local filesystems" +mount -uw / +[ -f /etc/fstab ] && mount -vat nonfs + +BootCacheControl=/System/Library/Extensions/BootCache.kext/Contents/Resources/BootCacheControl +if [ ! -f $BootCacheControl ]; then + BootCacheControl=/usr/sbin/BootCacheControl +fi +if [ "${SafeBoot}" != "-x" -a -x "${BootCacheControl}" ]; then + ${BootCacheControl} start +fi + +if [ -f /etc/sysctl-macosxserver.conf ]; then + awk '{ if (!index($1, "#") && index($1, "=")) print $1 }' < /etc/sysctl-macosxserver.conf | while read + do + sysctl -w ${REPLY} + done +fi +if [ -f /etc/sysctl.conf ]; then + awk '{ if (!index($1, "#") && index($1, "=")) print $1 }' < /etc/sysctl.conf | while read + do + sysctl -w ${REPLY} + done +fi + +sysctl -w kern.sysv.shmmax=4194304 kern.sysv.shmmin=1 kern.sysv.shmmni=32 kern.sysv.shmseg=8 kern.sysv.shmall=1024 + +if [ -f /var/account/acct ]; then + accton /var/account/acct +fi + +if [ -f /etc/rc.installer_cleanup ]; then + /etc/rc.installer_cleanup multiuser +fi + +echo "Resetting files and devices" + +RMRF_ITEMS="/mach.sym /var/tmp/folders.*" +## +# Attempt to recover the passwd file, if needed. This procedure is +# primarily historical and makes sense only when the passwd file is edited +# using the vipw command. +## +if [ -s /etc/ptmp ]; then + if [ -s /etc/passwd ]; then + echo -n "Passwd file conflict with ptmp: " + ls -l /etc/passwd /etc/ptmp + echo "Moving ptmp to ptmp.save" + mv -f /etc/ptmp /etc/ptmp.save + else + echo "Passwd file recovered from ptmp" + mv /etc/ptmp /etc/passwd + fi +elif [ -r /etc/ptmp ]; then + echo "Removing passwd lock file" + RMRF_ITEMS="$RMRF_ITEMS /etc/ptmp" +fi + +## +# If the shutdown command was used to shut the system down, the file +# /etc/nologin may have been created to prevent users from logging in. +# Remove it so that logins are enabled when the system comes up. +## +RMRF_ITEMS="$RMRF_ITEMS /etc/nologin" + +# Clean out /private/tmp. +if [ -d /private/tmp ]; then + # blow away any _tmp_ in case it exists as well + if [ -e /private/_tmp_ ]; then + chflags -R -P 0 /private/_tmp_ + rm -rf /private/_tmp_ + fi + mv /private/tmp /private/_tmp_ + chflags -R -P 0 /private/_tmp_ + RMRF_ITEMS="$RMRF_ITEMS /private/_tmp_" +fi +mkdir -p -m 01777 /private/var/tmp /private/tmp + +# Move /var/run out of the way +if [ -d /var/run ]; then + # blow away any _run_ in case it exists as well + if [ -e /var/_run_ ]; then + chflags -R -P 0 /var/_run_ + rm -rf /var/_run_ + fi + mv /var/run /var/_run_ +fi + +# Make new /var/run +mkdir -m 775 /var/run +mkdir -m 775 /var/run/StartupItems /var/run/davlocks +mkdir -m 755 /var/run/proxy +chown root:daemon /var/run /var/run/StartupItems +chown www:www /var/run/proxy /var/run/davlocks + +# Move sudo back to /var/run, touch the contents of /var/run/sudo/* back to the epoch +if [ -d /var/_run_/sudo ]; then + mv /var/_run_/sudo /var/run/sudo + touch -t 198501010000 /var/run/sudo/* +fi + +# Clear utmp (who is logged on). +touch /var/run/utmp /var/run/utmpx + +# purge the _run_ directory if it exists +if [ -d /var/_run_ ]; then + chflags -R -P 0 /var/_run_ + RMRF_ITEMS="$RMRF_ITEMS /var/_run_" +fi + +# Clear /var/spool/lock +if [ -d /var/spool/lock ]; then + find /var/spool/lock -not -type d -print0 | xargs -0 rm -f +fi + + +# if "/Desktop Folder" exists and has contents, make sure there is a +# "/Desktop (Mac OS 9)" symlink to it +# if "/Desktop Folder" does not exist, exists but has no contents, or exists +# and has only a single file, ".DS_Store" then there should be no +# "/Desktop (Mac OS 9)" symlink +# if there is some other file or directory with the name "/Desktop (Mac OS 9)" +# then just exit +needlink=0 +if [ -d "/Desktop Folder" ]; then + needlink=$(ls -a1 "/Desktop Folder" | wc -l) + if [ "${needlink}" -eq 3 ]; then + if [ -f "/Desktop Folder/.DS_Store" ]; then + needlink=0 + fi + fi +fi + +if [ "${needlink}" -lt 3 ]; then + if [ -h "/Desktop (Mac OS 9)" ]; then + rm -f "/Desktop (Mac OS 9)" + fi +else + if ! [ -e "/Desktop (Mac OS 9)" ]; then + ln -s "/Desktop Folder" "/Desktop (Mac OS 9)" + fi +fi + +echo "Starting virtual memory" + +swapdir=/private/var/vm +if [ "${NetBoot}" = "-N" ]; then + sh /etc/rc.netboot setup_vm ${swapdir} +fi + +if [ ! -d ${swapdir} ]; then + echo "Creating default swap directory" + mkdir -p -m 755 ${swapdir} + chown root:wheel ${swapdir} +else + RMRF_ITEMS="${RMRF_ITEMS} ${swapdir}/swap*" +fi + +echo Removing $RMRF_ITEMS +rm -rf $RMRF_ITEMS + +if [ ${ENCRYPTSWAP:=-NO-} = "-YES-" ]; then + encryptswap="-E" +else + encryptswap="" +fi +/sbin/dynamic_pager ${encryptswap} -F ${swapdir}/swapfile + +appprofiledir=/private/var/vm/app_profile + +if [ ! -d ${appprofiledir} ]; then + if [ -f ${appprofiledir} ]; then + mv -f ${appprofiledir} "${appprofiledir}_" + fi + mkdir -p -m 711 ${appprofiledir} + chown root:wheel ${appprofiledir} +fi + +# Create mach symbol file +sysctl -n kern.symfile +if [ -f /mach.sym ]; then + ln -sf /mach.sym /mach +else + ln -sf /mach_kernel /mach +fi + +if [ "${SafeBoot}" = "-x" ]; then + echo "Configuring kernel extensions for safe boot" + touch /private/tmp/.SafeBoot + kextd -x +else + echo "Configuring kernel extensions" + kextd +fi + +if [ "${SafeBoot}" != "-x" -a -x "${BootCacheControl}" ]; then + ${BootCacheControl} tag +fi + +# Create local NetInfo database if it doesn't exist +if [ ! -d /var/db/netinfo/local.nidb ]; then + echo "Creating local NetInfo database" + mkdir -p /var/db/netinfo + /usr/libexec/create_nidb + rm -f /var/db/.AppleSetupDone +fi + +if [ -f /etc/security/rc.audit ]; then + . /etc/security/rc.audit +fi + +if [ -f /Library/Preferences/com.apple.sharing.firewall.plist ]; then + /usr/libexec/FirewallTool +fi + +# Load [ideally on demand] daemons +/usr/libexec/register_mach_bootstrap_servers /etc/mach_init.d +if [ "${SafeBoot}" = "-x" ]; then + launchctl load /System/Library/LaunchDaemons +else + launchctl load /Library/LaunchDaemons /System/Library/LaunchDaemons + SystemStarter ${VerboseFlag} +fi + +/usr/sbin/update + +if [ "${NetBoot}" = "-N" ]; then + sh /etc/rc.netboot setup_computername +fi + +# Set language from CDIS.custom - assumes this is parse-able by sh +if [ -f /var/log/CDIS.custom ]; then + . /var/log/CDIS.custom +fi + +# Start the Language Chooser. This code should be able to go away as far as I +# know once loginwindow becomes more dynamic. +STARTPBS="/System/Library/CoreServices/pbs" # apps stall w/o +BUDDYCOOKIE="/var/db/.AppleSetupDone" +LCACOOKIE="/var/db/.RunLanguageChooserToo" +STARTLCA="/System/Library/CoreServices/Language Chooser.app/Contents/MacOS/Language Chooser" + +if [ -x "$STARTLCA" -a -x "$STARTPBS" -a ! -f "$BUDDYCOOKIE" -a -f "$LCACOOKIE" ]; then + "$STARTPBS" & + pbspid=$! + "$STARTLCA" + kill $pbspid # XSelect does this independently +fi + +if [ ! -s "/var/log/CDIS.custom" ]; then + echo "Language Chooser seems to have failed; defaulting to English" + echo "LANGUAGE=English" > "/var/log/CDIS.custom" +fi + +export LANGUAGE + +if [ -f /etc/rc.local ]; then + sh /etc/rc.local +fi + +touch /var/run/.systemStarterRunning + +if [ "${VerboseFlag}" != "-v" ] ; then + /usr/libexec/WaitingForLoginWindow +fi + +exit 0 diff --git a/launchd/src/rc.8 b/launchd/src/rc.8 new file mode 100644 index 0000000..c02fb0b --- /dev/null +++ b/launchd/src/rc.8 @@ -0,0 +1,108 @@ +.\" $NetBSD: rc.8,v 1.3 1994/11/30 19:36:26 jtc Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)rc.8 8.2 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt RC 8 +.Os BSD 4 +.Sh NAME +.Nm rc +.Nd command script for auto\-reboot and daemons +.Sh SYNOPSIS +.Nm rc +.Nm rc.local +.Sh DESCRIPTION +.Nm Rc +is the command script which controls the automatic reboot and +.Nm rc.local +is the script holding commands which are pertinent only +to a specific site. +.Pp +When an automatic reboot is in progress, +.Nm rc +is invoked with the argument +.Em autoboot . +The first portion of +.Nm rc +runs an +.Xr fsck 8 +with option +.Fl p +to ``preen'' all the disks of minor inconsistencies resulting +from the last system shutdown and to check for serious inconsistencies +caused by hardware or software failure. +If this auto-check and repair succeeds, then the second part of +.Nm rc +is run. +.Pp +The second part of +.Nm rc , +which is run after an auto-reboot succeeds and also if +.Nm rc +is invoked when a single user shell terminates (see +.Xr init 8 ) , +starts all the daemons on the system, preserves editor files +and clears the scratch directory +.Pa /tmp . +.Pp +.Nm Rc.local +is executed immediately before any other commands after a successful +.Xr fsck . +Normally, the first commands placed in the +.Nm rc.local +file define the machine's name, using +.Xr hostname 1 , +and save any possible core image that might have been +generated as a result of a system crash, with +.Xr savecore 8 . +The latter command is included in the +.Nm rc.local +file because the directory in which core dumps are saved +is usually site specific. +.Pp +Following tradition, the startup files +.Nm rc +and +.Nm rc.local +reside in +.Pa /etc . +.Sh SEE ALSO +.Xr init 8 , +.Xr reboot 8 , +.Xr savecore 8 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.0 . diff --git a/launchd/src/rc.common b/launchd/src/rc.common new file mode 100644 index 0000000..677842e --- /dev/null +++ b/launchd/src/rc.common @@ -0,0 +1,93 @@ +## +# Common setup for startup scripts. +## +# Copyright 1998-2002 Apple Computer, Inc. +## + +####################### +# Configure the shell # +####################### + +## +# Be strict +## +#set -e +set -u + +## +# Set command search path +## +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/libexec:/System/Library/CoreServices; export PATH + +## +# Set the terminal mode +## +#if [ -x /usr/bin/tset ] && [ -f /usr/share/misc/termcap ]; then +# TERM=$(tset - -Q); export TERM +#fi + +#################### +# Useful functions # +#################### + +## +# Determine if the network is up by looking for any non-loopback +# internet network interfaces. +## +CheckForNetwork() +{ + local test + + if [ -z "${NETWORKUP:=}" ]; then + test=$(ifconfig -a inet 2>/dev/null | sed -n -e '/127.0.0.1/d' -e '/0.0.0.0/d' -e '/inet/p' | wc -l) + if [ "${test}" -gt 0 ]; then + NETWORKUP="-YES-" + else + NETWORKUP="-NO-" + fi + fi +} + +## +# Process management +## +GetPID () +{ + local program="$1" + local pidfile="${PIDFILE:=/var/run/${program}.pid}" + local pid="" + + if [ -f "${pidfile}" ]; then + pid=$(head -1 "${pidfile}") + if ! kill -0 "${pid}" 2> /dev/null; then + echo "Bad pid file $pidfile; deleting." + pid="" + rm -f "${pidfile}" + fi + fi + + if [ -n "${pid}" ]; then + echo "${pid}" + return 0 + else + return 1 + fi +} + +## +# Generic action handler +## +RunService () +{ + case $1 in + start ) StartService ;; + stop ) StopService ;; + restart) RestartService ;; + * ) echo "$0: unknown argument: $1";; + esac +} + +########################## +# Get host configuration # +########################## +. /etc/hostconfig diff --git a/launchd/src/rc.netboot b/launchd/src/rc.netboot new file mode 100644 index 0000000..2488976 --- /dev/null +++ b/launchd/src/rc.netboot @@ -0,0 +1,215 @@ +#!/bin/sh +## +# Copyright 2002 Apple Computer, Inc. +# +# This script configures NetBoot +## + +. /etc/rc.common + +# +# Define: NETBOOT_SHADOW +# Purpose: +# To change the behavior of the system when choosing a netboot shadow +# to use. +# Values: +# -NETWORK- Try to use the network for the shadow file, if +# that fails, use the local drive +# -NETWORK_ONLY- Only use the network, fail if not available +# -LOCAL- Use the local drive for the shadow file, if that +# fails, use the network +# -LOCAL_ONLY- Only use the local drive for the shadow, fail if +# not available + +NETBOOT_MOUNT=/var/netboot +NETBOOT_SHADOW=${NETBOOT_SHADOW:-NETWORK-} + +Failed() +{ + echo rc.netboot: $1 + exit 1 +} + +common_start() +{ + netboot_dir=$1 + netboot_shadow=$2 + if [ "${netboot_dir}" = "" ] ; then + Failed "netboot_dir is empty" + fi + if [ "${netboot_shadow}" = "" ] ; then + Failed "netboot_shadow is empty" + fi + netboot_shadow="${netboot_dir}/${netboot_shadow}" + if ! mkdir -p "${netboot_dir}" ; then + Failed "create ${netboot_dir} failed" + fi + chmod 700 "${netboot_dir}" + mount -u -o ro / + root_device=$(mount | sed -n 's:/dev/\(.*\) on / .*:\1:p') + case "${root_device}" in + vn*) + if ! touch "${netboot_shadow}" ; then + Failed "create ${netboot_shadow} failed" + fi + chmod 600 "${netboot_shadow}" + if ! /usr/libexec/vndevice shadow "/dev/r${root_device}" "${netboot_shadow}" ; then + Failed "vndevice shadow failed" + fi + ;; + "") + Failed "root device unknown" + ;; + *) + if ! touch "${netboot_shadow}" ; then + Failed "failed to create shadow ${netboot_shadow}" + fi + chmod 600 "${netboot_shadow}" + if ! /usr/bin/nbdst -recycle "${root_device}" "${netboot_shadow}" ; then + Failed "nbdst failed" + fi + ;; + esac +} + +local_mount() +{ + volinfo=`autodiskmount -F 2>/dev/null` + if [ $? -ne 0 ]; then + echo "autodiskmount -F found no local drives" + return 1 + fi + set ${volinfo} + devname=$1 + fstype=$2 + + mount -t "${fstype}" -o nosuid,nodev "/dev/${devname}" "${NETBOOT_MOUNT}" 2>&1 + if [ $? -ne 0 ]; then + echo "mount of ${devname} failed" + return 1 + fi + common_start "${NETBOOT_MOUNT}/.com.apple.NetBootX" shadowfile + return 0 +} + +network_mount() +{ + mount_from=$(ipconfig netbootoption shadow_mount_path 2>&1) + if [ $? -ne 0 ]; then + echo "no network shadow mount path available" + return 1 + fi + shadow_path=$(ipconfig netbootoption shadow_file_path 2>&1) + if [ $? -ne 0 ]; then + echo "no network shadow file path available" + return 1 + fi + case "${mount_from}" in + afp:*) fstype=afp;; + nfs:*) fstype=nfs;; + *) echo "unknown network filesystem mount from ${mount_from}" + return 1 + ;; + esac + mount -t "${fstype}" "${mount_from}" "${NETBOOT_MOUNT}" + if [ $? -ne 0 ]; then + echo "mount -t ${fstype} ${mount_from} ${NETBOOT_MOUNT} failed" + return 1 + fi + common_start "${NETBOOT_MOUNT}" "${shadow_path}" + return 0 +} + +do_start() +{ + case "${NETBOOT_SHADOW}" in + -LOCAL_ONLY-) + err=$(local_mount) + if [ $? -ne 0 ]; then + Failed "${err}" + fi + ;; + -LOCAL-) + err=$(local_mount) + if [ $? -ne 0 ]; then + err=$(network_mount) + if [ $? -ne 0 ]; then + Failed "Could not find a local or network drive" + fi + fi + ;; + -NETWORK_ONLY-) + err=$(network_mount) + if [ $? -ne 0 ]; then + Failed "${err}" + fi + ;; + + *) + err=$(network_mount) + if [ $? -ne 0 ]; then + err=$(local_mount) + if [ $? -ne 0 ]; then + Failed "Could not find a network or local drive" + fi + fi + ;; + esac + +} + +do_computername() +{ + machine_name=$(ipconfig netbootoption machine_name 2>&1) + if [ $? -ne 0 ]; then + echo "no machine name option available" + else + echo "Setting ComputerName to ${machine_name}" + scutil --set ComputerName "${machine_name}" + fi +} + +do_vm() +{ + swapdir=${1:-/private/var/vm} + + mounted_from=$(mount | sed -n 's:\(.*\) on .*/var/netboot.*:\1:p') + + case "${mounted_from}" in + /dev/*) + netboot_dir="${NETBOOT_MOUNT}/.com.apple.NetBootX" + if [ -d "${netboot_dir}" ]; then + rm -rf "${netboot_dir}/app_profile" + rm -rf "${swapdir}" + ln -s "${netboot_dir}" "${swapdir}" + fi + ;; + *) + ;; + esac +} + +if [ $# -lt 1 ] ; then + exit 0 +fi + +command=$1 + +shift + +case "${command}" in + start) + do_start $@ + ;; + setup_vm) + do_vm $@ + ;; + setup_computername) + do_computername $@ + ;; +esac + +## +# Exit +## +exit 0 diff --git a/launchd/src/rc.shutdown b/launchd/src/rc.shutdown new file mode 100644 index 0000000..0738e8d --- /dev/null +++ b/launchd/src/rc.shutdown @@ -0,0 +1,14 @@ +#!/bin/sh +# Copyright 1997-2004 Apple Computer, Inc. + +. /etc/rc.common + +if [ -f /etc/rc.shutdown.local ]; then + sh /etc/rc.shutdown.local +fi + +SystemStarter stop + +kill -TERM 1 + +exit 0 diff --git a/launchd/src/register_mach_bootstrap_servers.c b/launchd/src/register_mach_bootstrap_servers.c new file mode 100644 index 0000000..2476911 --- /dev/null +++ b/launchd/src/register_mach_bootstrap_servers.c @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void regServ(uid_t u, bool on_demand, bool is_kunc, const char *serv_name, const char *serv_cmd); +static void handleConfigFile(const char *file); +static CFPropertyListRef CreateMyPropertyListFromFile(const char *posixfile); + +int main(int argc, char *argv[]) +{ + DIR *d; + struct dirent *de; + struct stat sb; + + if (argc != 2) { + fprintf(stderr, "usage: %s: \n", getprogname()); + exit(EXIT_FAILURE); + } + + stat(argv[1], &sb); + + if (S_ISREG(sb.st_mode)) { + handleConfigFile(argv[1]); + exit(EXIT_SUCCESS); + } + + if (getenv("SECURITYSESSIONID")) { + if (fork() == 0) { + const char *h = getenv("HOME"); + struct passwd *pwe = getpwuid(getuid()); + char *buf; + asprintf(&buf, "%s/%s", h ? h : pwe->pw_dir, "Library/LaunchAgents"); + execlp("launchctl", "launchctl", "load", buf, "/Library/LaunchAgents", "/System/Library/LaunchAgents", NULL); + exit(EXIT_SUCCESS); + } + } + + if ((d = opendir(argv[1])) == NULL) { + fprintf(stderr, "%s: opendir() failed to open the directory\n", getprogname()); + exit(EXIT_FAILURE); + } + + while ((de = readdir(d)) != NULL) { + if ((de->d_name[0] != '.')) { + char *foo; + if (asprintf(&foo, "%s/%s", argv[1], de->d_name)) + handleConfigFile(foo); + free(foo); + } + } + + exit(EXIT_SUCCESS); +} + +static void handleConfigFile(const char *file) +{ + bool on_demand = true, is_kunc = false; + uid_t u = getuid(); + struct passwd *pwe; + char usr[4096]; + char serv_name[4096]; + char serv_cmd[4096]; + CFPropertyListRef plist = CreateMyPropertyListFromFile(file); + + if (plist) { + if (CFDictionaryContainsKey(plist, CFSTR("Username"))) { + const void *v = CFDictionaryGetValue(plist, CFSTR("Username")); + + if (v) CFStringGetCString(v, usr, sizeof(usr), kCFStringEncodingUTF8); + else goto out; + + if ((pwe = getpwnam(usr))) { + u = pwe->pw_uid; + } else { + fprintf(stderr, "%s: user not found\n", getprogname()); + goto out; + } + } + if (CFDictionaryContainsKey(plist, CFSTR("OnDemand"))) { + const void *v = CFDictionaryGetValue(plist, CFSTR("OnDemand")); + if (v) + on_demand = CFBooleanGetValue(v); + else goto out; + } + if (CFDictionaryContainsKey(plist, CFSTR("ServiceName"))) { + const void *v = CFDictionaryGetValue(plist, CFSTR("ServiceName")); + + if (v) CFStringGetCString(v, serv_name, sizeof(serv_name), kCFStringEncodingUTF8); + else goto out; + } + if (CFDictionaryContainsKey(plist, CFSTR("Command"))) { + const void *v = CFDictionaryGetValue(plist, CFSTR("Command")); + + if (v) CFStringGetCString(v, serv_cmd, sizeof(serv_cmd), kCFStringEncodingUTF8); + else goto out; + } + if (CFDictionaryContainsKey(plist, CFSTR("isKUNCServer"))) { + const void *v = CFDictionaryGetValue(plist, CFSTR("isKUNCServer")); + if (v && CFBooleanGetValue(v)) is_kunc = true; + else goto out; + } + regServ(u, on_demand, is_kunc, serv_name, serv_cmd); + goto out_good; +out: + fprintf(stdout, "%s: failed to register: %s\n", getprogname(), file); +out_good: + CFRelease(plist); + } else { + fprintf(stderr, "%s: no plist was returned for: %s\n", getprogname(), file); + } +} + +static void regServ(uid_t u, bool on_demand, bool is_kunc, const char *serv_name, const char *serv_cmd) +{ + kern_return_t kr; + mach_port_t msr, msv, mhp; + + if ((kr = bootstrap_create_server(bootstrap_port, (char*)serv_cmd, u, on_demand, &msr)) != KERN_SUCCESS) { + fprintf(stderr, "%s: bootstrap_create_server(): %d\n", getprogname(), kr); + return; + } + if ((kr = bootstrap_create_service(msr, (char*)serv_name, &msv)) != KERN_SUCCESS) { + fprintf(stderr, "%s: bootstrap_register(): %d\n", getprogname(), kr); + return; + } + if (is_kunc) { + mhp = mach_host_self(); + if ((kr = host_set_UNDServer(mhp, msv)) != KERN_SUCCESS) { + fprintf(stderr, "%s: host_set_UNDServer(): %s\n", getprogname(), mach_error_string(kr)); + return; + } + mach_port_deallocate(mach_task_self(), mhp); + } +} + +static CFPropertyListRef CreateMyPropertyListFromFile(const char *posixfile) +{ + CFPropertyListRef propertyList; + CFStringRef errorString; + CFDataRef resourceData; + SInt32 errorCode; + CFURLRef fileURL; + + fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, posixfile, strlen(posixfile), false); + if (!fileURL) + fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile); + if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) + fprintf(stderr, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), posixfile, (int)errorCode); + propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListImmutable, &errorString); + if (!propertyList) { + fprintf(stderr, "%s: propertyList is NULL\n", getprogname()); + if (errorString) + CFRelease(errorString); + } + if (resourceData) + CFRelease(resourceData); + if (fileURL) + CFRelease(fileURL); + + return propertyList; +} diff --git a/launchd/src/rpc_services.c b/launchd/src/rpc_services.c new file mode 100644 index 0000000..4336258 --- /dev/null +++ b/launchd/src/rpc_services.c @@ -0,0 +1,846 @@ +/* + * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * bootstrap -- fundamental service initiator and port server + * Mike DeMoney, NeXT, Inc. + * Copyright, 1990. All rights reserved. + * + * rpc_services.c -- implementation of bootstrap rpc services + */ + +#include +#include +#include +#include + +#include +#include + +#include "bootstrap_internal.h" +#include "lists.h" +#include "bootstrap.h" + +#ifndef ASSERT +#define ASSERT(p) +#endif + +#ifndef NULL +#define NULL ((void *)0) +#endif NULL + +#define bsstatus(servicep) \ + (((servicep)->isActive) ? BOOTSTRAP_STATUS_ACTIVE : \ + (((servicep)->server && (servicep)->server->servertype == DEMAND) ? \ + BOOTSTRAP_STATUS_ON_DEMAND : BOOTSTRAP_STATUS_INACTIVE)) + +/* extern port_all_t backup_port; */ + +/* + * kern_return_t + * bootstrap_create_server(mach_port_t bootstrap_port, + * cmd_t server_cmd, + * integer_t server_uid, + * boolean_t on_demand, + * mach_port_t *server_portp) + * + * Returns send rights to server_port of service. At this point, the + * server appears active, so nothing will try to launch it. The server_port + * can be used to delare services associated with this server by calling + * bootstrap_create_service() and passing server_port as the bootstrap port. + * + * Errors: Returns appropriate kernel errors on rpc failure. + * Returns BOOTSTRAP_NOT_PRIVILEGED, if bootstrap port invalid. + */ +__private_extern__ kern_return_t +x_bootstrap_create_server( + mach_port_t bootstrapport, + cmd_t server_cmd, + uid_t server_uid, + boolean_t on_demand, + audit_token_t client_audit_token, + mach_port_t *server_portp) +{ + server_t *serverp; + struct auditinfo audit_info; + bootstrap_info_t *bootstrap; + + uid_t client_euid; + + bootstrap = lookup_bootstrap_by_port(bootstrapport); + syslog(LOG_DEBUG, "Server create attempt: \"%s\" bootstrap %x", + server_cmd, bootstrapport); + + /* No forwarding allowed for this call - security risk (we run as root) */ + if (!bootstrap || !active_bootstrap(bootstrap)) { + syslog(LOG_DEBUG, "Server create: \"%s\": invalid bootstrap %x", + server_cmd, bootstrapport); + return BOOTSTRAP_NOT_PRIVILEGED; + } + + /* get the identity of the requestor and set up audit_info of server */ + audit_token_to_au32(client_audit_token, + &audit_info.ai_auid, + &client_euid, + NULL /* egid */, + NULL /* ruid */, + NULL /* rgid */, + NULL /* pid */, + &audit_info.ai_asid, + &audit_info.ai_termid); + + if (client_euid != 0 && client_euid != server_uid) { + syslog(LOG_NOTICE, "Server create: \"%s\": insufficient privilege for specified uid (euid-%d != requested-%d)", + server_cmd, client_euid, server_uid); + return BOOTSTRAP_NOT_PRIVILEGED; + } + + serverp = new_server( + bootstrap, + server_cmd, + server_uid, + (on_demand) ? DEMAND : RESTARTABLE, + audit_info); + setup_server(serverp); + + syslog(LOG_INFO, "New server %x in bootstrap %x: \"%s\"", + serverp->port, bootstrapport, server_cmd); + *server_portp = serverp->port; + return BOOTSTRAP_SUCCESS; +} + +/* + * kern_return_t + * bootstrap_unprivileged(mach_port_t bootstrapport, + * mach_port_t *unprivportp) + * + * Given a bootstrap port, return its unprivileged equivalent. If + * the port is already unprivileged, another reference to the same + * port is returned. + * + * This is most often used by servers, which are launched with their + * bootstrap port set to the privileged port for the server, to get + * an unprivileged version of the same port for use by its unprivileged + * children (or any offspring that it does not want to count as part + * of the "server" for mach_init registration and re-launch purposes). + */ +__private_extern__ kern_return_t +x_bootstrap_unprivileged( + mach_port_t bootstrapport, + mach_port_t *unprivportp) +{ + bootstrap_info_t *bootstrap; + + syslog(LOG_DEBUG, "Get unprivileged attempt for bootstrap %x", bootstrapport); + + bootstrap = lookup_bootstrap_by_port(bootstrapport); + if (!bootstrap) { + syslog(LOG_DEBUG, "Get unprivileged: invalid bootstrap %x", bootstrapport); + return BOOTSTRAP_NOT_PRIVILEGED; + } + + *unprivportp = bootstrap->bootstrap_port; + + syslog(LOG_DEBUG, "Get unpriv bootstrap %x returned for bootstrap %x", + bootstrap->bootstrap_port, bootstrapport); + return BOOTSTRAP_SUCCESS; +} + + +/* + * kern_return_t + * bootstrap_check_in(mach_port_t bootstrapport, + * name_t servicename, + * mach_port_t *serviceportp) + * + * Returns receive rights to service_port of service named by service_name. + * + * Errors: Returns appropriate kernel errors on rpc failure. + * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist. + * Returns BOOTSTRAP_SERVICE_NOT_DECLARED, if service not declared + * in /etc/bootstrap.conf. + * Returns BOOTSTRAP_SERVICE_ACTIVE, if service has already been + * registered or checked-in. + */ +__private_extern__ kern_return_t +x_bootstrap_check_in( + mach_port_t bootstrapport, + name_t servicename, + mach_port_t *serviceportp) +{ + kern_return_t result; + mach_port_t previous; + service_t *servicep; + server_t *serverp; + bootstrap_info_t *bootstrap; + + serverp = lookup_server_by_port(bootstrapport); + bootstrap = lookup_bootstrap_by_port(bootstrapport); + syslog(LOG_DEBUG, "Service checkin attempt for service %s bootstrap %x", + servicename, bootstrapport); + + servicep = lookup_service_by_name(bootstrap, servicename); + if (servicep == NULL || servicep->port == MACH_PORT_NULL) { + syslog(LOG_DEBUG, "bootstrap_check_in service %s unknown%s", servicename, + forward_ok ? " forwarding" : ""); + return forward_ok ? + bootstrap_check_in( + inherited_bootstrap_port, + servicename, + serviceportp) : + BOOTSTRAP_UNKNOWN_SERVICE; + } + if (servicep->server != NULL && servicep->server != serverp) { + syslog(LOG_DEBUG, "bootstrap_check_in service %s not privileged", + servicename); + return BOOTSTRAP_NOT_PRIVILEGED; + } + if (!canReceive(servicep->port)) { + ASSERT(servicep->isActive); + syslog(LOG_DEBUG, "bootstrap_check_in service %s already active", + servicename); + return BOOTSTRAP_SERVICE_ACTIVE; + } + syslog(LOG_DEBUG, "Checkin service %s for bootstrap %x", servicename, + bootstrap->bootstrap_port); + ASSERT(servicep->isActive == FALSE); + servicep->isActive = TRUE; + + if (servicep->server != NULL_SERVER) { + /* registered server - service needs backup */ + serverp->activity++; + serverp->active_services++; + result = mach_port_request_notification( + mach_task_self(), + servicep->port, + MACH_NOTIFY_PORT_DESTROYED, + 0, + backup_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + &previous); + if (result != KERN_SUCCESS) + panic("mach_port_request_notification(): %s", mach_error_string(result)); + } else { + /* one time use/created service */ + servicep->servicetype = REGISTERED; + result = mach_port_request_notification( + mach_task_self(), + servicep->port, + MACH_NOTIFY_DEAD_NAME, + 0, + notify_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + &previous); + if (result != KERN_SUCCESS) + panic("mach_port_request_notification(): %s", mach_error_string(result)); + else if (previous != MACH_PORT_NULL) { + syslog(LOG_DEBUG, "deallocating old notification port (%x) for checked in service %x", + previous, servicep->port); + result = mach_port_deallocate( + mach_task_self(), + previous); + if (result != KERN_SUCCESS) + panic("mach_port_deallocate(): %s", mach_error_string(result)); + } + } + + syslog(LOG_INFO, "Check-in service %x in bootstrap %x: %s", + servicep->port, servicep->bootstrap->bootstrap_port, servicep->name); + + *serviceportp = servicep->port; + return BOOTSTRAP_SUCCESS; +} + +/* + * kern_return_t + * bootstrap_register(mach_port_t bootstrapport, + * name_t servicename, + * mach_port_t serviceport) + * + * Registers send rights for the port service_port for the service named by + * service_name. Registering a declared service or registering a service for + * which bootstrap has receive rights via a port backup notification is + * allowed. + * The previous service port will be deallocated. Restarting services wishing + * to resume service for previous clients must first attempt to checkin to the + * service. + * + * Errors: Returns appropriate kernel errors on rpc failure. + * Returns BOOTSTRAP_NOT_PRIVILEGED, if request directed to + * unprivileged bootstrap port. + * Returns BOOTSTRAP_SERVICE_ACTIVE, if service has already been + * register or checked-in. + */ +__private_extern__ kern_return_t +x_bootstrap_register( + mach_port_t bootstrapport, + name_t servicename, + mach_port_t serviceport) +{ + kern_return_t result; + service_t *servicep; + server_t *serverp; + bootstrap_info_t *bootstrap; + mach_port_t old_port; + + syslog(LOG_DEBUG, "Register attempt for service %s port %x", + servicename, serviceport); + + /* + * Validate the bootstrap. + */ + bootstrap = lookup_bootstrap_by_port(bootstrapport); + if (!bootstrap || !active_bootstrap(bootstrap)) + return BOOTSTRAP_NOT_PRIVILEGED; + + /* + * If this bootstrap port is for a server, or it's an unprivileged + * bootstrap can't register the port. + */ + serverp = lookup_server_by_port(bootstrapport); + servicep = lookup_service_by_name(bootstrap, servicename); + if (servicep && servicep->server && servicep->server != serverp) + return BOOTSTRAP_NOT_PRIVILEGED; + + if (servicep == NULL || servicep->bootstrap != bootstrap) { + servicep = new_service(bootstrap, + servicename, + serviceport, + ACTIVE, + REGISTERED, + NULL_SERVER); + syslog(LOG_DEBUG, "Registered new service %s", servicename); + } else { + if (servicep->isActive) { + syslog(LOG_DEBUG, "Register: service %s already active, port %x", + servicep->name, servicep->port); + ASSERT(!canReceive(servicep->port)); + return BOOTSTRAP_SERVICE_ACTIVE; + } + old_port = servicep->port; + if (servicep->servicetype == DECLARED) { + servicep->servicetype = REGISTERED; + + if (servicep->server) { + ASSERT(servicep->server == serverp); + ASSERT(active_server(serverp)); + servicep->server = NULL_SERVER; + serverp->activity++; + } + + result = mach_port_mod_refs( + mach_task_self(), + old_port, + MACH_PORT_RIGHT_RECEIVE, + -1); + if (result != KERN_SUCCESS) + panic("mach_port_mod_refs(): %s", mach_error_string(result)); + } + result = mach_port_deallocate( + mach_task_self(), + old_port); + if (result != KERN_SUCCESS) + panic("mach_port_mod_refs(): %s", mach_error_string(result)); + + servicep->port = serviceport; + servicep->isActive = TRUE; + syslog(LOG_DEBUG, "Re-registered inactive service %x bootstrap %x: %s", + servicep->port, servicep->bootstrap->bootstrap_port, servicename); + } + + /* detect the new service port going dead */ + result = mach_port_request_notification( + mach_task_self(), + serviceport, + MACH_NOTIFY_DEAD_NAME, + 0, + notify_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + &old_port); + if (result != KERN_SUCCESS) { + syslog(LOG_DEBUG, "Can't request notification on service %x bootstrap %x: %s", + service_port, servicep->bootstrap->bootstrap_port, "must be dead"); + delete_service(servicep); + return BOOTSTRAP_SUCCESS; + } else if (old_port != MACH_PORT_NULL) { + syslog(LOG_DEBUG, "deallocating old notification port (%x) for service %x", + old_port, serviceport); + result = mach_port_deallocate( + mach_task_self(), + old_port); + if (result != KERN_SUCCESS) + panic("mach_port_deallocate(): %s", mach_error_string(result)); + } + syslog(LOG_INFO, "Registered service %x bootstrap %x: %s", + servicep->port, servicep->bootstrap->bootstrap_port, servicep->name); + return BOOTSTRAP_SUCCESS; +} + +/* + * kern_return_t + * bootstrap_look_up(mach_port_t bootstrapport, + * name_t servicename, + * mach_port_t *serviceportp) + * + * Returns send rights for the service port of the service named by + * service_name in *service_portp. Service is not guaranteed to be active. + * + * Errors: Returns appropriate kernel errors on rpc failure. + * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist. + */ +__private_extern__ kern_return_t +x_bootstrap_look_up( + mach_port_t bootstrapport, + name_t servicename, + mach_port_t *serviceportp) +{ + service_t *servicep; + bootstrap_info_t *bootstrap; + + bootstrap = lookup_bootstrap_by_port(bootstrapport); + servicep = lookup_service_by_name(bootstrap, servicename); + if (servicep == NULL || servicep->port == MACH_PORT_NULL) { + if (forward_ok) { + syslog(LOG_DEBUG, "bootstrap_look_up service %s forwarding", + servicename); + return bootstrap_look_up(inherited_bootstrap_port, + servicename, + serviceportp); + } else { + syslog(LOG_DEBUG, "bootstrap_look_up service %s unknown", + servicename); + return BOOTSTRAP_UNKNOWN_SERVICE; + } + } + *serviceportp = servicep->port; + syslog(LOG_DEBUG, "Lookup returns port %x for service %s", servicep->port, servicep->name); + return BOOTSTRAP_SUCCESS; +} + +/* + * kern_return_t + * bootstrap_look_up_array(mach_port_t bootstrapport, + * name_array_t servicenames, + * int servicenames_cnt, + * mach_port_array_t *serviceports, + * int *serviceports_cnt, + * boolean_t *allservices_known) + * + * Returns port send rights in corresponding entries of the array service_ports + * for all services named in the array service_names. Service_ports_cnt is + * returned and will always equal service_names_cnt (assuming service_names_cnt + * is greater than or equal to zero). + * + * Errors: Returns appropriate kernel errors on rpc failure. + * Returns BOOTSTRAP_NO_MEMORY, if server couldn't obtain memory + * for response. + * Unknown service names have the corresponding service + * port set to MACH_PORT_NULL. + * If all services are known, all_services_known is true on + * return, + * if any service is unknown, it's false. + */ +__private_extern__ kern_return_t +x_bootstrap_look_up_array( + mach_port_t bootstrapport, + name_array_t servicenames, + unsigned int servicenames_cnt, + mach_port_array_t *serviceportsp, + unsigned int *serviceports_cnt, + boolean_t *allservices_known) +{ + unsigned int i; + static mach_port_t service_ports[BOOTSTRAP_MAX_LOOKUP_COUNT]; + + if (servicenames_cnt > BOOTSTRAP_MAX_LOOKUP_COUNT) + return BOOTSTRAP_BAD_COUNT; + *serviceports_cnt = servicenames_cnt; + *allservices_known = TRUE; + for (i = 0; i < servicenames_cnt; i++) { + if ( x_bootstrap_look_up(bootstrapport, + servicenames[i], + &service_ports[i]) + != BOOTSTRAP_SUCCESS) + { + *allservices_known = FALSE; + service_ports[i] = MACH_PORT_NULL; + } + } + syslog(LOG_DEBUG, "bootstrap_look_up_array returns %d ports", servicenames_cnt); + *serviceportsp = service_ports; + return BOOTSTRAP_SUCCESS; +} + +/* + * kern_return_t + * bootstrap_parent(mach_port_t bootstrapport, + * mach_port_t *parentport); + * + * Given a bootstrap subset port, return the parent bootstrap port. + * If the specified bootstrap port is already the root subset, + * MACH_PORT_NULL will be returned. + * + * Errors: + * Returns BOOTSTRAP_NOT_PRIVILEGED if the caller is not running + * with an effective user id of root (as determined by the security + * token in the message trailer). + */ +__private_extern__ kern_return_t +x_bootstrap_parent( + mach_port_t bootstrapport, + security_token_t sectoken, + mach_port_t *parentport) +{ + bootstrap_info_t *bootstrap; + + syslog(LOG_DEBUG, "Parent attempt for bootstrap %x", bootstrapport); + + bootstrap = lookup_bootstrap_by_port(bootstrapport); + if (!bootstrap) { + syslog(LOG_DEBUG, "Parent attempt for bootstrap %x: invalid bootstrap", + bootstrapport); + return BOOTSTRAP_NOT_PRIVILEGED; + } + if (sectoken.val[0]) { + syslog(LOG_NOTICE, "Bootstrap parent for bootstrap %x: invalid security token (%d)", + bootstrapport, sectoken.val[0]); + return BOOTSTRAP_NOT_PRIVILEGED; + } + syslog(LOG_DEBUG, "Returning bootstrap parent %x for bootstrap %x", + bootstrap->parent->bootstrap_port, bootstrapport); + *parentport = bootstrap->parent->bootstrap_port; + return BOOTSTRAP_SUCCESS; +} + +/* + * kern_return_t + * bootstrap_status(mach_port_t bootstrapport, + * name_t servicename, + * bootstrap_status_t *serviceactive); + * + * Returns: service_active indicates if service is available. + * + * Errors: Returns appropriate kernel errors on rpc failure. + * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist. + */ +__private_extern__ kern_return_t +x_bootstrap_status( + mach_port_t bootstrapport, + name_t servicename, + bootstrap_status_t *serviceactivep) +{ + service_t *servicep; + bootstrap_info_t *bootstrap; + + bootstrap = lookup_bootstrap_by_port(bootstrapport); + servicep = lookup_service_by_name(bootstrap, servicename); + if (servicep == NULL) { + if (forward_ok) { + syslog(LOG_DEBUG, "bootstrap_status forwarding status, server %s", + servicename); + return bootstrap_status(inherited_bootstrap_port, + servicename, + serviceactivep); + } else { + syslog(LOG_DEBUG, "bootstrap_status service %s unknown", + servicename); + return BOOTSTRAP_UNKNOWN_SERVICE; + } + } + *serviceactivep = bsstatus(servicep); + + syslog(LOG_DEBUG, "bootstrap_status server %s %sactive", servicename, + servicep->isActive ? "" : "in"); + return BOOTSTRAP_SUCCESS; +} + +/* + * kern_return_t + * bootstrap_info(mach_port_t bootstrapport, + * name_array_t *servicenamesp, + * int *servicenames_cnt, + * name_array_t *servernamesp, + * int *servernames_cnt, + * bootstrap_status_array_t *serviceactivesp, + * int *serviceactive_cnt); + * + * Returns bootstrap status for all known services. + * + * Errors: Returns appropriate kernel errors on rpc failure. + */ +__private_extern__ kern_return_t +x_bootstrap_info( + mach_port_t bootstrapport, + name_array_t *servicenamesp, + unsigned int *servicenames_cnt, + name_array_t *servernamesp, + unsigned int *servernames_cnt, + bootstrap_status_array_t *serviceactivesp, + unsigned int *serviceactives_cnt) +{ + kern_return_t result; + unsigned int i, cnt; + service_t *servicep; + server_t *serverp; + bootstrap_info_t *bootstrap; + name_array_t service_names; + name_array_t server_names; + bootstrap_status_array_t service_actives; + + bootstrap = lookup_bootstrap_by_port(bootstrapport); + + for ( cnt = i = 0, servicep = services.next + ; i < nservices + ; servicep = servicep->next, i++) + { + if (lookup_service_by_name(bootstrap, servicep->name) == servicep) + { + cnt++; + } + } + result = vm_allocate(mach_task_self(), + (vm_address_t *)&service_names, + cnt * sizeof(service_names[0]), + ANYWHERE); + if (result != KERN_SUCCESS) + return BOOTSTRAP_NO_MEMORY; + + result = vm_allocate(mach_task_self(), + (vm_address_t *)&server_names, + cnt * sizeof(server_names[0]), + ANYWHERE); + if (result != KERN_SUCCESS) { + (void)vm_deallocate(mach_task_self(), + (vm_address_t)service_names, + cnt * sizeof(service_names[0])); + return BOOTSTRAP_NO_MEMORY; + } + result = vm_allocate(mach_task_self(), + (vm_address_t *)&service_actives, + cnt * sizeof(service_actives[0]), + ANYWHERE); + if (result != KERN_SUCCESS) { + (void)vm_deallocate(mach_task_self(), + (vm_address_t)service_names, + cnt * sizeof(service_names[0])); + (void)vm_deallocate(mach_task_self(), + (vm_address_t)server_names, + cnt * sizeof(server_names[0])); + return BOOTSTRAP_NO_MEMORY; + } + + for ( i = 0, servicep = services.next + ; i < cnt + ; servicep = servicep->next) + { + if ( lookup_service_by_name(bootstrap, servicep->name) + != servicep) + continue; + strncpy(service_names[i], + servicep->name, + sizeof(service_names[0])); + service_names[i][sizeof(service_names[0]) - 1] = '\0'; + if (servicep->server) { + serverp = servicep->server; + strncpy(server_names[i], + serverp->cmd, + sizeof(server_names[0])); + server_names[i][sizeof(server_names[0]) - 1] = '\0'; + syslog(LOG_DEBUG, "bootstrap info service %s server %s %sactive", + servicep->name, + serverp->cmd, servicep->isActive ? "" : "in"); + } else { + server_names[i][0] = '\0'; + syslog(LOG_DEBUG, "bootstrap info service %s %sactive", + servicep->name, servicep->isActive ? "" : "in"); + } + service_actives[i] = bsstatus(servicep); + i++; + } + *servicenamesp = service_names; + *servernamesp = server_names; + *serviceactivesp = service_actives; + *servicenames_cnt = *servernames_cnt = *serviceactives_cnt = cnt; + + return BOOTSTRAP_SUCCESS; +} + +/* + * kern_return_t + * bootstrap_subset(mach_port_t bootstrapport, + * mach_port_t requestorport, + * mach_port_t *subsetport); + * + * Returns a new port to use as a bootstrap port. This port behaves + * exactly like the previous bootstrap_port, except that ports dynamically + * registered via bootstrap_register() are available only to users of this + * specific subset_port. Lookups on the subset_port will return ports + * registered with this port specifically, and ports registered with + * ancestors of this subset_port. Duplications of services already + * registered with an ancestor port may be registered with the subset port + * are allowed. Services already advertised may then be effectively removed + * by registering MACH_PORT_NULL for the service. + * When it is detected that the requestor_port is destroied the subset + * port and all services advertized by it are destroied as well. + * + * Errors: Returns appropriate kernel errors on rpc failure. + */ +__private_extern__ kern_return_t +x_bootstrap_subset( + mach_port_t bootstrapport, + mach_port_t requestorport, + mach_port_t *subsetportp) +{ + kern_return_t result; + bootstrap_info_t *bootstrap; + bootstrap_info_t *subset; + mach_port_t new_bootstrapport; + mach_port_t previous; + + syslog(LOG_DEBUG, "Subset create attempt: bootstrap %x, requestor: %x", + bootstrapport, requestorport); + + bootstrap = lookup_bootstrap_by_port(bootstrapport); + if (!bootstrap || !active_bootstrap(bootstrap)) + return BOOTSTRAP_NOT_PRIVILEGED; + + result = mach_port_allocate( + mach_task_self(), + MACH_PORT_RIGHT_RECEIVE, + &new_bootstrapport); + if (result != KERN_SUCCESS) + panic("mach_port_allocate(): %s", mach_error_string(result)); + + result = mach_port_insert_right( + mach_task_self(), + new_bootstrapport, + new_bootstrapport, + MACH_MSG_TYPE_MAKE_SEND); + if (result != KERN_SUCCESS) + panic("failed to insert send right(): %s", mach_error_string(result)); + + result = mach_port_insert_member( + mach_task_self(), + new_bootstrapport, + bootstrap_port_set); + if (result != KERN_SUCCESS) + panic("port_set_add(): %s", mach_error_string(result)); + + subset = new_bootstrap(bootstrap, new_bootstrapport, requestorport); + + result = mach_port_request_notification( + mach_task_self(), + requestorport, + MACH_NOTIFY_DEAD_NAME, + 0, + notify_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + &previous); + if (result != KERN_SUCCESS) { + syslog(LOG_ERR, "mach_port_request_notification(): %s", mach_error_string(result)); + mach_port_deallocate(mach_task_self(), requestorport); + subset->requestor_port = MACH_PORT_NULL; + deactivate_bootstrap(subset); + } else if (previous != MACH_PORT_NULL) { + syslog(LOG_DEBUG, "deallocating old notification port (%x) for requestor %x", + previous, requestorport); + result = mach_port_deallocate( + mach_task_self(), + previous); + if (result != KERN_SUCCESS) + panic("mach_port_deallocate(): %s", mach_error_string(result)); + } + + syslog(LOG_INFO, "Created bootstrap subset %x parent %x requestor %x", + new_bootstrapport, bootstrapport, requestorport); + *subsetportp = new_bootstrapport; + return BOOTSTRAP_SUCCESS; +} + +/* + * kern_return_t + * bootstrap_create_service(mach_port_t bootstrapport, + * name_t servicename, + * mach_port_t *serviceportp) + * + * Creates a service named "service_name" and returns send rights to that + * port in "service_port." The port may later be checked in as if this + * port were configured in the bootstrap configuration file. + * + * Errors: Returns appropriate kernel errors on rpc failure. + * Returns BOOTSTRAP_NAME_IN_USE, if service already exists. + */ +__private_extern__ kern_return_t +x_bootstrap_create_service( + mach_port_t bootstrapport, + name_t servicename, + mach_port_t *serviceportp) +{ + server_t *serverp; + service_t *servicep; + bootstrap_info_t *bootstrap; + kern_return_t result; + + bootstrap = lookup_bootstrap_by_port(bootstrapport); + if (!bootstrap || !active_bootstrap(bootstrap)) + return BOOTSTRAP_NOT_PRIVILEGED; + + syslog(LOG_DEBUG, "Service creation attempt for service %s bootstrap %x", + servicename, bootstrapport); + + servicep = lookup_service_by_name(bootstrap, servicename); + if (servicep) { + syslog(LOG_DEBUG, "Service creation attempt for service %s failed, " + "service already exists", servicename); + return BOOTSTRAP_NAME_IN_USE; + } + + serverp = lookup_server_by_port(bootstrapport); + + result = mach_port_allocate(mach_task_self(), + MACH_PORT_RIGHT_RECEIVE, + serviceportp); + if (result != KERN_SUCCESS) + panic("port_allocate(): %s", mach_error_string(result)); + result = mach_port_insert_right(mach_task_self(), + *serviceportp, + *serviceportp, + MACH_MSG_TYPE_MAKE_SEND); + if (result != KERN_SUCCESS) + panic("failed to insert send right(): %s", mach_error_string(result)); + + if (serverp) + serverp->activity++; + + servicep = new_service(bootstrap, + servicename, + *serviceportp, + !ACTIVE, + DECLARED, + serverp); + + syslog(LOG_INFO, "Created new service %x in bootstrap %x: %s", + servicep->port, bootstrap->bootstrap_port, servicename); + + return BOOTSTRAP_SUCCESS; +} diff --git a/launchd/src/service b/launchd/src/service new file mode 100755 index 0000000..be42d2b --- /dev/null +++ b/launchd/src/service @@ -0,0 +1,165 @@ +#!/bin/sh + +set -e + +# don't let people kill us. We shouldn't be long, so this isn't a big deal. + +trap "" TSTP +trap "" HUP +trap "" INT +trap "" QUIT +trap "" TERM + +function restart_xinetd () +{ + lockfile -r-1 /var/run/.xinetd-restart.lock + kill -HUP $(cat /var/run/xinetd.pid 2>/dev/null) 2>/dev/null || /usr/sbin/xinetd -pidfile /var/run/xinetd.pid + rm -f /var/run/.xinetd-restart.lock +} + +function restart_xinetd_hard () +{ + lockfile -r-1 /var/run/.xinetd-restart.lock + kill -TERM $(cat /var/run/xinetd.pid 2>/dev/null) 2>/dev/null || echo >/dev/null + kill -0 $(cat /var/run/xinetd.pid 2>/dev/null) 2>/dev/null && sleep 1 + /usr/sbin/xinetd -pidfile /var/run/xinetd.pid + rm -f /var/run/.xinetd-restart.lock +} + +if [ $# -eq 0 ] +then + echo "Usage: $(basename $0) --list | " >&2 + exit 1 +fi + +if [ "$1" == "--list" ] +then + echo smtp + echo fax-receive + cd /etc/xinetd.d 2>/dev/null + ls -1 + cd /System/Library/LaunchDaemons 2>/dev/null + ls -1 | egrep '.plist$' | sed 's,.plist$,,g' + exit 0 +elif [ "$1" == "--test-if-configured-on" ] +then + if [ -f "/etc/xinetd.d/$2" ] + then + egrep "disable.*=.*no" /etc/xinetd.d/$2 >/dev/null 2>&1 + exit $? + fi + if [ -f /System/Library/LaunchDaemons/$2.plist ] + then + IS_OFF=$(defaults read /System/Library/LaunchDaemons/$2 Disabled 2>/dev/null || true) + if [ "$IS_OFF" = 1 ] + then + exit 1 + else + exit 0 + fi + fi + if [ "$2" = "smtp" ] + then + egrep '^MAILSERVER.*-YES-' /etc/hostconfig >/dev/null 2>&1 + exit $? + fi + if [ "$2" = "fax-receive" ] + then + egrep '^fax.*unknown.*on$' /etc/ttys >/dev/null 2>&1 + exit $? + fi + exit 1 +elif [ "$1" == "--test-if-available" ] +then + [ -f /System/Library/LaunchDaemons/$2.plist ] && exit 0 + [ "$2" = "smtp" ] && exit 0 + [ "$2" = "fax-receive" ] && exit 0 + [ ! -f "/etc/xinetd.d/$2" ] && exit 1 + SERVER_FILE=$(egrep 'server[ ]' "/etc/xinetd.d/$2" | sed 's,.*server[ ]*=[ ]*\(.*\),\1,g') + [ ! -f "$SERVER_FILE" ] && exit 1 + exit 0 +elif [ -f "/etc/xinetd.d/$1" ] +then + if [ $UID != 0 ] + then + echo "You must be root to run this option" >&2 + exit 1 + fi + # yes, /var/run is gross, but it is tmp directory cleaned up a boot, + # writable only by root (so i don't need to worry about the security + # implications of mktemp) + TMPFILE=$(mktemp /var/run/xinetd.tmp.$$.XXXXXX) + cp -f "/etc/xinetd.d/$1" $TMPFILE + if [ "$2" == start ] + then + sed 's/disable.*=.*/disable = no/g' < $TMPFILE > "/etc/xinetd.d/$1" + restart_xinetd + elif [ "$2" == stop ] + then + sed 's/disable.*=.*/disable = yes/g' < $TMPFILE > "/etc/xinetd.d/$1" + if [ "$1" == "nmbd" ] + then + restart_xinetd_hard + kill -TERM $(cat /var/run/nmbd.pid) || echo >/dev/null + else + restart_xinetd + fi + else + echo "No such service command" >&2 + fi + rm -f $TMPFILE +elif [ -f "/System/Library/LaunchDaemons/$1.plist" ] +then + [ "$2" == start ] && launchctl load -w /System/Library/LaunchDaemons/$1.plist + [ "$2" == stop ] && launchctl unload -w /System/Library/LaunchDaemons/$1.plist +elif [ "$1" = "smtp" ] +then + if [ $UID != 0 ] + then + echo "You must be root to run this option" >&2 + exit 1 + fi + TMPFILE=$(mktemp /var/run/xinetd.tmp.$$.XXXXXX) + cp -f /etc/hostconfig $TMPFILE + if [ "$2" == start ] + then + if grep -q MAILSERVER=-NO- /etc/hostconfig ; then + sed 's,^MAILSERVER=-NO-,MAILSERVER=-YES-,g' < $TMPFILE > /etc/hostconfig + fi + postfix start + postfix flush + elif [ "$2" == stop ] + then + if grep -q MAILSERVER=-YES- /etc/hostconfig ; then + sed 's,^MAILSERVER=-YES-,MAILSERVER=-NO-,g' < $TMPFILE > /etc/hostconfig + fi + postfix stop + else + echo "No such service command" >&2 + fi + rm -f $TMPFILE +elif [ "$1" = "fax-receive" ] +then + if [ $UID != 0 ] + then + echo "You must be root to run this option" >&2 + exit 1 + fi + TMPFILE=$(mktemp /var/run/xinetd.tmp.$$.XXXXXX) + cp -f /etc/ttys $TMPFILE + if [ "$2" == start ] + then + sed 's,^fax\(.*\)off$,fax\1on,g' < $TMPFILE > /etc/ttys + kill -HUP 1 + elif [ "$2" == stop ] + then + sed 's,^fax\(.*\)on$,fax\1off,g' < $TMPFILE > /etc/ttys + kill -HUP 1 + else + echo "No such service command" >&2 + fi + rm -f $TMPFILE +else + echo "No such service $1" >&2 + exit 1 +fi diff --git a/launchd/src/service.8 b/launchd/src/service.8 new file mode 100644 index 0000000..adb0f83 --- /dev/null +++ b/launchd/src/service.8 @@ -0,0 +1,29 @@ +.Dd October 15, 2004 +.Dt SERVICE 8 +.Os Darwin +.Sh NAME +.Nm service +.Sh SYNOPSIS +.Nm +.Ar service Ar command +.Nm +.Fl -list +.Nm +.Fl -test-if-configured-on Ar service +.Nm +.Fl -test-if-available Ar service +.Sh DESCRIPTION +.Nm +is a simple script to abstract the management of services provided by the system. +It can be used to start and stop services, as well as to determine the status of services. +.Sh OPTIONS +.Bl -tag -width indent +.It Ar service Ar command +Attempt to execute a given command for a given service. Currently, the available commands are 'start' and 'stop'. +.It Fl -list +List all available services. +.It Fl -test-if-configured-on Ar service +Exit with status 0 if the service is currently enabled. Otherwise, exit with status 1. +.It Fl -test-if-available Ar service +Exit with status 0 if the service's daemon exists on your system. Otherwise, exit with status 1. +.El diff --git a/launchd/src/wait4path.1 b/launchd/src/wait4path.1 new file mode 100644 index 0000000..18a2abf --- /dev/null +++ b/launchd/src/wait4path.1 @@ -0,0 +1,13 @@ +.Dd April 6, 2004 +.Dt WAIT4PATH 1 +.Os "Mac OS X" 10.4 +.Sh NAME +.Nm wait4path +.Nd wait for given path to show up in the namespace +.Sh SYNOPSIS +.Nm +.Ao Ar path Ac +.Sh DESCRIPTION +The +.Nm +program simply checks to see if the given path exists, and if so, it exits. Otherwise, it sleeps until the mount table is updated and checks again. The program will loop indefinitely until the path shows up in the file system namespace. diff --git a/launchd/src/wait4path.c b/launchd/src/wait4path.c new file mode 100644 index 0000000..7bc333f --- /dev/null +++ b/launchd/src/wait4path.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int kq = kqueue(); + struct kevent kev; + struct stat sb; + + if (argc != 2) { + fprintf(stderr, "usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + EV_SET(&kev, 0, EVFILT_FS, EV_ADD, 0, 0, 0); + + if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) { + fprintf(stderr, "adding EVFILT_FS to kqueue failed: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + for (;;) { + kevent(kq, NULL, 0, &kev, 1, NULL); + if (stat(argv[1], &sb) == 0) + break; + } + + exit(EXIT_SUCCESS); +} diff --git a/launchd/testing/StartInterval.plist b/launchd/testing/StartInterval.plist new file mode 100644 index 0000000..bbaa92c --- /dev/null +++ b/launchd/testing/StartInterval.plist @@ -0,0 +1,15 @@ + + + + + Label + com.apple.launchd.test.StartInterval + ProgramArguments + + echo + StartInterval + + StartInterval + 3 + + diff --git a/launchd/testing/badexec.plist b/launchd/testing/badexec.plist new file mode 100644 index 0000000..652809e --- /dev/null +++ b/launchd/testing/badexec.plist @@ -0,0 +1,14 @@ + + + + + Label + com.apple.launchd.test.badexec + ProgramArguments + + / + + OnDemand + + + diff --git a/launchd/testing/badexit.plist b/launchd/testing/badexit.plist new file mode 100644 index 0000000..ea84c23 --- /dev/null +++ b/launchd/testing/badexit.plist @@ -0,0 +1,14 @@ + + + + + Label + com.apple.launchd.test.badexit + ProgramArguments + + false + + OnDemand + + + diff --git a/launchd/testing/missed-EVFILT_WRITE.c b/launchd/testing/missed-EVFILT_WRITE.c new file mode 100644 index 0000000..2b346d7 --- /dev/null +++ b/launchd/testing/missed-EVFILT_WRITE.c @@ -0,0 +1,156 @@ +/* + * Lots of hangs in GetLaunchDaemonService state + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void do_parent(int thefd); +static void do_child(int thefd); + +int main(void) +{ + int sp[2]; + + if (-1 == socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) { + fprintf(stderr, "socketpair(): %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + switch (fork()) { + case -1: + fprintf(stderr, "fork(): %s\n", strerror(errno)); + exit(EXIT_FAILURE); + case 0: + close(sp[0]); + do_child(sp[1]); + break; + default: + close(sp[1]); + do_parent(sp[0]); + break; + } + + exit(EXIT_SUCCESS); +} + +static void do_child(int thefd) +{ + char buf[500000]; + fd_set rfds; + int r, readhunks = 2; + + if (-1 == fcntl(thefd, F_SETFL, O_NONBLOCK)) { + fprintf(stderr, "fcntl(): %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + for (;;) { + if (2 == readhunks) { + if (-1 == write(thefd, buf, 1)) { + fprintf(stderr, "%d: write(): %s\n", __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + readhunks = 0; + } + r = read(thefd, buf, sizeof(buf)); + + if (-1 == r && errno != EAGAIN) { + fprintf(stderr, "%d: read(): %s\n", __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (r > 0) + readhunks++; + + if (readhunks == 2) + continue; + + FD_ZERO(&rfds); + FD_SET(thefd, &rfds); + + select(thefd + 1, &rfds, NULL, NULL, NULL); + } +} + +static void do_parent(int thefd) +{ + struct timespec timeout = { 1, 0 }; + char buf[500000]; + struct kevent kev; + int iter = 0, kq = kqueue(); + + if (-1 == (kq = kqueue())) { + fprintf(stderr, "kqueue(): %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + if (-1 == fcntl(thefd, F_SETFL, O_NONBLOCK)) { + fprintf(stderr, "fcntl(): %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + EV_SET(&kev, thefd, EVFILT_READ, EV_ADD, 0, 0, NULL); + + if (-1 == kevent(kq, &kev, 1, NULL, 0, NULL)) { + fprintf(stderr, "%d: kevent(): %s\n", __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + for (;;) { + switch (kevent(kq, NULL, 0, &kev, 1, &timeout)) { + case -1: + fprintf(stderr, "%d: kevent(): %s\n", __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + case 0: + fprintf(stderr, "After %d iterations, 4038866 still exists!\n", iter); + exit(EXIT_FAILURE); + case 1: + break; + default: + fprintf(stderr, "kevent should only return -1, 0 or 1 for this case!\n"); + exit(EXIT_FAILURE); + } + + switch (kev.filter) { + case EVFILT_READ: + if (-1 == read(thefd, buf, sizeof(buf))) { + fprintf(stderr, "read(): %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + if (-1 == write(thefd, buf, sizeof(buf))) { + fprintf(stderr, "%d: write(): %s\n", __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + EV_SET(&kev, thefd, EVFILT_WRITE, EV_ADD, 0, 0, NULL); + if (-1 == kevent(kq, &kev, 1, NULL, 0, NULL)) { + fprintf(stderr, "%d: kevent(): %s\n", __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + break; + case EVFILT_WRITE: + if (-1 == write(thefd, buf, 1)) { + fprintf(stderr, "%d: write(): %s\n", __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + EV_SET(&kev, thefd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + if (-1 == kevent(kq, &kev, 1, NULL, 0, NULL)) { + fprintf(stderr, "%d: kevent(): %s\n", __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + break; + default: + fprintf(stderr, "kevent filter isn't EVFILT_READ or EVFILT_WRITE!\n"); + exit(EXIT_FAILURE); + } + iter++; + } +} diff --git a/launchd/testing/missing_req_keys.plist b/launchd/testing/missing_req_keys.plist new file mode 100644 index 0000000..6056e7d --- /dev/null +++ b/launchd/testing/missing_req_keys.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/launchd/testing/secsock.plist b/launchd/testing/secsock.plist new file mode 100644 index 0000000..46e4281 --- /dev/null +++ b/launchd/testing/secsock.plist @@ -0,0 +1,21 @@ + + + + + Label + com.apple.launchd.test.secsock + ProgramArguments + + sleep + 10000 + + Sockets + + AuthSock + + SecureSocketWithKey + SSH_AUTH_SOCK + + + + diff --git a/launchd/testing/signaldeath.plist b/launchd/testing/signaldeath.plist new file mode 100644 index 0000000..bf84a3e --- /dev/null +++ b/launchd/testing/signaldeath.plist @@ -0,0 +1,16 @@ + + + + + Label + com.apple.launchd.test.signaldeath + ProgramArguments + + kill + -1 + 0 + + OnDemand + + + -- 2.45.2