├── SystemStarter ├── IPC.c ├── IPC.h ├── StartupItemContext ├── StartupItemContext.8 ├── StartupItems.c ├── StartupItems.h ├── SystemStarter.8 ├── SystemStarter.c ├── SystemStarter.h ├── SystemStarterIPC.h ├── com.apple.SystemStarter.plist └── hostconfig ├── launchd.xcodeproj └── project.pbxproj ├── liblaunch ├── bootstrap.h ├── bootstrap_priv.h ├── launch.h ├── launch_internal.h ├── launch_priv.h ├── launchd.ops ├── libbootstrap.c ├── liblaunch.c ├── libvproc.c ├── reboot2.h ├── vproc.h ├── vproc_internal.h └── vproc_priv.h ├── man ├── launchctl.1 ├── launchd.8 ├── launchd.conf.5 ├── launchd.plist.5 ├── launchproxy.8 ├── rc.8 └── wait4path.1 ├── rc ├── rc.common └── rc.netboot ├── src ├── config.h ├── core.c ├── core.h ├── helper.defs ├── internal.defs ├── ipc.c ├── ipc.h ├── job.defs ├── job_forward.defs ├── job_reply.defs ├── job_types.defs ├── kill2.c ├── kill2.h ├── ktrace.c ├── ktrace.h ├── launchd.c ├── launchd.h ├── log.c ├── log.h ├── protocol_jobmgr.defs ├── runtime.c └── runtime.h ├── support ├── launchctl.c ├── launchproxy.c └── wait4path.c ├── xcconfigs ├── common.xcconfig ├── launchctl.xcconfig ├── launchd.xcconfig └── liblaunch.xcconfig └── xcscripts ├── SystemStarter-postflight.sh ├── launchctl-postflight.sh ├── launchd-postflight.sh └── liblaunch-postflight.sh /SystemStarter/IPC.c: -------------------------------------------------------------------------------- 1 | /** 2 | * IPC.c - System Starter IPC routines 3 | * Wilfredo Sanchez | wsanchez@opensource.apple.com 4 | * Kevin Van Vechten | kevinvv@uclink4.berkeley.edu 5 | * $Apple$ 6 | ** 7 | * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. 8 | * 9 | * @APPLE_APACHE_LICENSE_HEADER_START@ 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * 15 | * http://www.apache.org/licenses/LICENSE-2.0 16 | * 17 | * Unless required by applicable law or agreed to in writing, software 18 | * distributed under the License is distributed on an "AS IS" BASIS, 19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | * See the License for the specific language governing permissions and 21 | * limitations under the License. 22 | * 23 | * @APPLE_APACHE_LICENSE_HEADER_END@ 24 | **/ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "bootstrap.h" 34 | 35 | #include "IPC.h" 36 | #include "StartupItems.h" 37 | #include "SystemStarter.h" 38 | #include "SystemStarterIPC.h" 39 | 40 | /* Structure to pass StartupContext and anItem to the termination handler. */ 41 | typedef struct TerminationContextStorage { 42 | StartupContext aStartupContext; 43 | CFMutableDictionaryRef anItem; 44 | } *TerminationContext; 45 | 46 | /** 47 | * A CFMachPort invalidation callback that records the termination of 48 | * a startup item task. Stops the current run loop to give system_starter 49 | * another go at running items. 50 | **/ 51 | static void 52 | startupItemTerminated(CFMachPortRef aMachPort, void *anInfo) 53 | { 54 | TerminationContext aTerminationContext = (TerminationContext) anInfo; 55 | 56 | if (aMachPort) { 57 | mach_port_deallocate(mach_task_self(), CFMachPortGetPort(aMachPort)); 58 | } 59 | if (aTerminationContext && aTerminationContext->anItem) { 60 | pid_t aPID = 0; 61 | pid_t rPID = 0; 62 | int aStatus = 0; 63 | CFMutableDictionaryRef anItem = aTerminationContext->anItem; 64 | StartupContext aStartupContext = aTerminationContext->aStartupContext; 65 | 66 | /* Get the exit status */ 67 | if (anItem) { 68 | aPID = StartupItemGetPID(anItem); 69 | if (aPID > 0) 70 | rPID = waitpid(aPID, &aStatus, 0); 71 | } 72 | if (aStartupContext) { 73 | --aStartupContext->aRunningCount; 74 | 75 | /* Record the item's status */ 76 | if (aStartupContext->aStatusDict) { 77 | StartupItemExit(aStartupContext->aStatusDict, anItem, (WIFEXITED(aStatus) && WEXITSTATUS(aStatus) == 0)); 78 | if (aStatus) { 79 | CF_syslog(LOG_WARNING, CFSTR("%@ (%d) did not complete successfully"), CFDictionaryGetValue(anItem, CFSTR("Description")), aPID); 80 | } else { 81 | CF_syslog(LOG_DEBUG, CFSTR("Finished %@ (%d)"), CFDictionaryGetValue(anItem, CFSTR("Description")), aPID); 82 | } 83 | } 84 | /* 85 | * If the item failed to start, then add it to the 86 | * failed list 87 | */ 88 | if (WEXITSTATUS(aStatus) || WTERMSIG(aStatus) || WCOREDUMP(aStatus)) { 89 | CFDictionarySetValue(anItem, kErrorKey, kErrorReturnNonZero); 90 | AddItemToFailedList(aStartupContext, anItem); 91 | } 92 | /* 93 | * Remove the item from the waiting list regardless 94 | * if it was successful or it failed. 95 | */ 96 | RemoveItemFromWaitingList(aStartupContext, anItem); 97 | } 98 | } 99 | if (aTerminationContext) 100 | free(aTerminationContext); 101 | } 102 | 103 | void 104 | MonitorStartupItem(StartupContext aStartupContext, CFMutableDictionaryRef anItem) 105 | { 106 | pid_t aPID = StartupItemGetPID(anItem); 107 | if (anItem && aPID > 0) { 108 | mach_port_t aPort; 109 | kern_return_t aResult; 110 | CFMachPortContext aContext; 111 | CFMachPortRef aMachPort; 112 | CFRunLoopSourceRef aSource; 113 | TerminationContext aTerminationContext = (TerminationContext) malloc(sizeof(struct TerminationContextStorage)); 114 | 115 | aTerminationContext->aStartupContext = aStartupContext; 116 | aTerminationContext->anItem = anItem; 117 | 118 | aContext.version = 0; 119 | aContext.info = aTerminationContext; 120 | aContext.retain = 0; 121 | aContext.release = 0; 122 | 123 | if ((aResult = task_name_for_pid(mach_task_self(), aPID, &aPort)) != KERN_SUCCESS) 124 | goto out_bad; 125 | 126 | if (!(aMachPort = CFMachPortCreateWithPort(NULL, aPort, NULL, &aContext, NULL))) 127 | goto out_bad; 128 | 129 | if (!(aSource = CFMachPortCreateRunLoopSource(NULL, aMachPort, 0))) { 130 | CFRelease(aMachPort); 131 | goto out_bad; 132 | } 133 | CFMachPortSetInvalidationCallBack(aMachPort, startupItemTerminated); 134 | CFRunLoopAddSource(CFRunLoopGetCurrent(), aSource, kCFRunLoopCommonModes); 135 | CFRelease(aSource); 136 | CFRelease(aMachPort); 137 | return; 138 | out_bad: 139 | /* 140 | * The assumption is something failed, the task already 141 | * terminated. 142 | */ 143 | startupItemTerminated(NULL, aTerminationContext); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /SystemStarter/IPC.h: -------------------------------------------------------------------------------- 1 | /** 2 | * IPC.h - System Starter IPC routines 3 | * Wilfredo Sanchez | wsanchez@opensource.apple.com 4 | * Kevin Van Vechten | kevinvv@uclink4.berkeley.edu 5 | * $Apple$ 6 | ** 7 | * Copyright (c) 1999-2001 Apple Computer, Inc. All rights reserved. 8 | * 9 | * @APPLE_APACHE_LICENSE_HEADER_START@ 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * 15 | * http://www.apache.org/licenses/LICENSE-2.0 16 | * 17 | * Unless required by applicable law or agreed to in writing, software 18 | * distributed under the License is distributed on an "AS IS" BASIS, 19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | * See the License for the specific language governing permissions and 21 | * limitations under the License. 22 | * 23 | * @APPLE_APACHE_LICENSE_HEADER_END@ 24 | **/ 25 | 26 | #ifndef _IPC_H_ 27 | #define _IPC_H_ 28 | 29 | #include "SystemStarter.h" 30 | 31 | /** 32 | * Monitor a startup item task. Creates a mach port and uses the 33 | * invalidation callback to notify system starter when the process 34 | * terminates. 35 | **/ 36 | void MonitorStartupItem (StartupContext aStartupContext, CFMutableDictionaryRef anItem); 37 | 38 | #endif /* _IPC_H_ */ 39 | -------------------------------------------------------------------------------- /SystemStarter/StartupItemContext: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | unset LAUNCHD_SOCKET 4 | 5 | exec launchctl bsexec / "$@" 6 | -------------------------------------------------------------------------------- /SystemStarter/StartupItemContext.8: -------------------------------------------------------------------------------- 1 | .Dd July 7, 2002 2 | .Dt StartupItemContext 8 3 | .Os Darwin 4 | .Sh NAME 5 | .Nm StartupItemContext 6 | .\" The following lines are read in generating the apropos(man -k) database. Use only key 7 | .\" words here as the database is built based on the words here and in the .ND line. 8 | .\" Use .Nm macro to designate other names for the documented program. 9 | .Nd Execute a program in StartupItem context 10 | .Sh SYNOPSIS 11 | .Nm 12 | .Op Ar program Op Ar arguments 13 | .Sh DESCRIPTION 14 | The 15 | .Nm 16 | utility launches the specified program in StartupItem bootstrap context. Each Darwin 17 | and Mac OS X login creates a unique bootstrap subset context to contain login specific 18 | Mach port registrations with the bootstrap server. All such registrations performed 19 | within the context of that subset are only visible to other processes within that 20 | context or subsequent subsets of it. Therefore, a Mach port based service/daemon 21 | launched within a login context will not be visible to other such contexts. 22 | .Pp 23 | To override this, a root user can use the 24 | .Nm 25 | utility to launch the program within the same bootstrap context as all other 26 | StartupItems. All subsequent Mach port bootstrap registrations perfomed by the program 27 | will be visible system-wide. 28 | .Sh NOTES 29 | All bootstrap port lookups will also be resticted 30 | to the StartupItem context. The services provided on a per-login basis (clipboard, 31 | etc...) will not be available to the program. 32 | .Sh SEE ALSO 33 | .\" List links in ascending order by section, alphabetically within a section. 34 | .\" Please do not reference files that do not exist without filing a bug report 35 | .Xr SystemStarter 8 36 | -------------------------------------------------------------------------------- /SystemStarter/StartupItems.h: -------------------------------------------------------------------------------- 1 | /** 2 | * StartupItems.h - Startup Item management routines 3 | * Wilfredo Sanchez | wsanchez@opensource.apple.com 4 | * Kevin Van Vechten | kevinvv@uclink4.berkeley.edu 5 | * $Apple$ 6 | ** 7 | * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. 8 | * 9 | * @APPLE_APACHE_LICENSE_HEADER_START@ 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * 15 | * http://www.apache.org/licenses/LICENSE-2.0 16 | * 17 | * Unless required by applicable law or agreed to in writing, software 18 | * distributed under the License is distributed on an "AS IS" BASIS, 19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | * See the License for the specific language governing permissions and 21 | * limitations under the License. 22 | * 23 | * @APPLE_APACHE_LICENSE_HEADER_END@ 24 | **/ 25 | 26 | #ifndef _StartupItems_H_ 27 | #define _StartupItems_H_ 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | #include "SystemStarter.h" 35 | 36 | #define kProvidesKey CFSTR("Provides") 37 | #define kRequiresKey CFSTR("Requires") 38 | #define kDescriptionKey CFSTR("Description") 39 | #define kUsesKey CFSTR("Uses") 40 | #define kErrorKey CFSTR("Error") 41 | #define kBundlePathKey CFSTR("PathToBundle") 42 | #define kPIDKey CFSTR("ProcessID") 43 | #define kDomainKey CFSTR("Domain") 44 | 45 | 46 | #define kErrorPermissions CFSTR("incorrect permissions") 47 | #define kErrorInternal CFSTR("SystemStarter internal error") 48 | #define kErrorReturnNonZero CFSTR("execution of Startup script failed") 49 | #define kErrorFork CFSTR("could not fork() StartupItem") 50 | 51 | 52 | /* 53 | * Find all available startup items in NSDomains specified by aMask. 54 | */ 55 | CFMutableArrayRef StartupItemListCreateWithMask (NSSearchPathDomainMask aMask); 56 | 57 | /* 58 | * Returns the item responsible for providing aService. 59 | */ 60 | CFMutableDictionaryRef StartupItemListGetProvider (CFArrayRef anItemList, CFStringRef aService); 61 | 62 | /* 63 | * Creates a list of items in anItemList which depend on anItem, given anAction. 64 | */ 65 | CFMutableArrayRef StartupItemListCreateDependentsList (CFMutableArrayRef anItemList, 66 | CFStringRef aService , 67 | Action anAction ); 68 | 69 | /* 70 | * Given aWaitingList of startup items, and aStatusDict describing the current 71 | * startup state, returns the next startup item to run, if any. Returns nil if 72 | * none is available. 73 | * Note that this is not necessarily deterministic; if more than one startup 74 | * item is ready to run, which item gets returned is not specified. An item is 75 | * not ready to run if the specified dependencies are not satisfied yet. 76 | */ 77 | CFMutableDictionaryRef StartupItemListGetNext (CFArrayRef aWaitingList, 78 | CFDictionaryRef aStatusDict , 79 | Action anAction ); 80 | 81 | CFMutableDictionaryRef StartupItemWithPID (CFArrayRef anItemList, pid_t aPID); 82 | pid_t StartupItemGetPID(CFDictionaryRef anItem); 83 | 84 | CFStringRef StartupItemCreateDescription(CFMutableDictionaryRef anItem); 85 | 86 | /* 87 | * Returns a list of currently executing startup items. 88 | */ 89 | CFArrayRef StartupItemListCreateFromRunning(CFArrayRef anItemList); 90 | 91 | /* 92 | * Returns the total number of "Provides" entries of all loaded items. 93 | */ 94 | CFIndex StartupItemListCountServices (CFArrayRef anItemList); 95 | 96 | 97 | /* 98 | * Utility functions 99 | */ 100 | void RemoveItemFromWaitingList(StartupContext aStartupContext, CFMutableDictionaryRef anItem); 101 | void AddItemToFailedList(StartupContext aStartupContext, CFMutableDictionaryRef anItem); 102 | 103 | /* 104 | * Run the startup item. 105 | */ 106 | int StartupItemRun (CFMutableDictionaryRef aStatusDict, CFMutableDictionaryRef anItem, Action anAction); 107 | void StartupItemExit (CFMutableDictionaryRef aStatusDict, CFMutableDictionaryRef anItem, Boolean aSuccess); 108 | void StartupItemSetStatus(CFMutableDictionaryRef aStatusDict, CFMutableDictionaryRef anItem, CFStringRef aServiceName, Boolean aSuccess, Boolean aReplaceFlag); 109 | 110 | /* 111 | * Check whether file was created before boot and has proper permissions to run. 112 | */ 113 | bool StartupItemSecurityCheck(const char *aPath); 114 | 115 | #endif /* _StartupItems_H_ */ 116 | -------------------------------------------------------------------------------- /SystemStarter/SystemStarter.8: -------------------------------------------------------------------------------- 1 | .Dd April 12, 2002 2 | .Dt SystemStarter 8 3 | .Os Darwin 4 | .Sh NAME 5 | .Nm SystemStarter 6 | .\" The following lines are read in generating the apropos(man -k) database. Use only key 7 | .\" words here as the database is built based on the words here and in the .ND line. 8 | .\" Use .Nm macro to designate other names for the documented program. 9 | .Nd Start, stop, and restart system services 10 | .Sh SYNOPSIS 11 | .Nm 12 | .Op Fl gvxdDqn 13 | .Op Ar action Op Ar service 14 | .Sh DESCRIPTION 15 | The 16 | .Nm 17 | utility is deprecated. System services should instead be described by a 18 | .Xr launchd.plist 5 . 19 | See 20 | .Xr launchd 8 21 | for more details. 22 | The 23 | .Nm launchd 24 | utility is available on Mac OS X 10.4 and later. 25 | .Pp 26 | In earlier versions of Mac OS X, the 27 | .Nm 28 | utility is used to start, stop, and restart the system services which 29 | are described in the 30 | .Pa /Library/StartupItems/ 31 | and 32 | .Pa /System/Library/StartupItems/ 33 | paths. 34 | .Pp 35 | The optional 36 | .Ar action 37 | argument specifies which action 38 | .Nm 39 | performs on the startup items. The optional 40 | .Ar service 41 | argument specifies which startup items to perform the action on. If no 42 | .Ar service 43 | is specified, all startup items will be acted on; otherwise, only the item providing the 44 | .Ar service , 45 | any items it requires, or any items that depend on it will be acted on. 46 | .Pp 47 | During boot 48 | .Nm 49 | is invoked by 50 | .Xr launchd 8 51 | and is responsible for 52 | starting all startup items in an order that satisfies each item's 53 | requirements. 54 | .Sh ACTIONS 55 | .Bl -tag -width -indent 56 | .It Nm start 57 | start all items, or start the item that provides the specified 58 | .Ar service 59 | and all items providing services it requires. 60 | .It Nm stop 61 | stop all items, or stop the item that provides the specified 62 | .Ar service 63 | and all items that depend on it. 64 | .It Nm restart 65 | restart all items, or restart the item providing the specified 66 | .Ar service . 67 | .El 68 | .Sh OPTIONS 69 | .Bl -tag -width -indent 70 | .It Fl g 71 | (ignored) 72 | .It Fl v 73 | verbose (text mode) startup 74 | .It Fl x 75 | (ignored) 76 | .It Fl r 77 | (ignored) 78 | .It Fl d 79 | print debugging output 80 | .It Fl D 81 | print debugging output and dependencies 82 | .It Fl q 83 | be quiet (disable debugging output) 84 | .It Fl n 85 | don't actually perform action on items (no-run mode) 86 | .El 87 | .Sh NOTES 88 | Unless an explicit call to 89 | .Nm ConsoleMessage 90 | is made, 91 | .Nm 92 | examines the exit status of the startup item scripts to determine the success or failure of the services provided by that script. 93 | .Pp 94 | .Sh FILES 95 | .Bl -tag -width -/System/Library/StartupItems -compact 96 | .It Pa /Library/StartupItems/ 97 | User-installed startup items. 98 | .It Pa /System/Library/StartupItems/ 99 | System-provided startup items. 100 | .El 101 | .Sh SEE ALSO 102 | .\" List links in ascending order by section, alphabetically within a section. 103 | .\" Please do not reference files that do not exist without filing a bug report 104 | .Xr ConsoleMessage 8 , 105 | .Xr launchd 8 , 106 | .Xr launchd.plist 5 , 107 | .Xr rc 8 108 | .\" .Sh BUGS \" Document known, unremedied bugs 109 | .Sh HISTORY 110 | The 111 | .Nm 112 | utility appeared in Darwin 1.0 and 113 | was extended in Darwin 6.0 to support partial startup and interprocess communication. 114 | .Nm 115 | was deprecated by 116 | .Xr launchd 8 117 | in Darwin 8.0. 118 | -------------------------------------------------------------------------------- /SystemStarter/SystemStarter.c: -------------------------------------------------------------------------------- 1 | /** 2 | * System Starter main 3 | * Wilfredo Sanchez | wsanchez@opensource.apple.com 4 | * $Apple$ 5 | ** 6 | * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. 7 | * 8 | * @APPLE_APACHE_LICENSE_HEADER_START@ 9 | * 10 | * Licensed under the Apache License, Version 2.0 (the "License"); 11 | * you may not use this file except in compliance with the License. 12 | * You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, software 17 | * distributed under the License is distributed on an "AS IS" BASIS, 18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | * See the License for the specific language governing permissions and 20 | * limitations under the License. 21 | * 22 | * @APPLE_APACHE_LICENSE_HEADER_END@ 23 | **/ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include "IPC.h" 40 | #include "StartupItems.h" 41 | #include "SystemStarter.h" 42 | #include "SystemStarterIPC.h" 43 | 44 | bool gDebugFlag = false; 45 | bool gVerboseFlag = false; 46 | bool gNoRunFlag = false; 47 | 48 | static void usage(void) __attribute__((noreturn)); 49 | static int system_starter(Action anAction, const char *aService); 50 | static void displayErrorMessages(StartupContext aStartupContext, Action anAction); 51 | static pid_t fwexec(const char *cmd, ...) __attribute__((sentinel)); 52 | static void autodiskmount(void); 53 | static void dummy_sig(int signo __attribute__((unused))) 54 | { 55 | } 56 | 57 | int 58 | main(int argc, char *argv[]) 59 | { 60 | struct kevent kev; 61 | Action anAction = kActionStart; 62 | int ch, r, kq = kqueue(); 63 | 64 | assert(kq != -1); 65 | 66 | EV_SET(&kev, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); 67 | r = kevent(kq, &kev, 1, NULL, 0, NULL); 68 | assert(r != -1); 69 | signal(SIGTERM, dummy_sig); 70 | 71 | while ((ch = getopt(argc, argv, "gvxirdDqn?")) != -1) { 72 | switch (ch) { 73 | case 'v': 74 | gVerboseFlag = true; 75 | break; 76 | case 'x': 77 | case 'g': 78 | case 'r': 79 | case 'q': 80 | break; 81 | case 'd': 82 | case 'D': 83 | gDebugFlag = true; 84 | break; 85 | case 'n': 86 | gNoRunFlag = true; 87 | break; 88 | case '?': 89 | default: 90 | usage(); 91 | break; 92 | } 93 | } 94 | argc -= optind; 95 | argv += optind; 96 | 97 | if (argc > 2) { 98 | usage(); 99 | } 100 | 101 | openlog(getprogname(), LOG_PID|LOG_CONS|(gDebugFlag ? LOG_PERROR : 0), LOG_DAEMON); 102 | if (gDebugFlag) { 103 | setlogmask(LOG_UPTO(LOG_DEBUG)); 104 | } else if (gVerboseFlag) { 105 | setlogmask(LOG_UPTO(LOG_INFO)); 106 | } else { 107 | setlogmask(LOG_UPTO(LOG_NOTICE)); 108 | } 109 | 110 | if (!gNoRunFlag && (getuid() != 0)) { 111 | syslog(LOG_ERR, "must be root to run"); 112 | exit(EXIT_FAILURE); 113 | } 114 | 115 | if (argc > 0) { 116 | if (strcmp(argv[0], "start") == 0) { 117 | anAction = kActionStart; 118 | } else if (strcmp(argv[0], "stop") == 0) { 119 | anAction = kActionStop; 120 | } else if (strcmp(argv[0], "restart") == 0) { 121 | anAction = kActionRestart; 122 | } else { 123 | usage(); 124 | } 125 | } 126 | 127 | if (argc == 2) { 128 | exit(system_starter(anAction, argv[1])); 129 | } 130 | 131 | unlink(kFixerPath); 132 | 133 | mach_timespec_t w = { 600, 0 }; 134 | kern_return_t kr; 135 | 136 | /* 137 | * Too many old StartupItems had implicit dependancies on "Network" via 138 | * other StartupItems that are now no-ops. 139 | * 140 | * SystemStarter is not on the critical path for boot up, so we'll 141 | * stall here to deal with this legacy dependancy problem. 142 | */ 143 | 144 | if ((kr = IOKitWaitQuiet(kIOMasterPortDefault, &w)) != kIOReturnSuccess) { 145 | syslog(LOG_NOTICE, "IOKitWaitQuiet: %d\n", kr); 146 | } 147 | 148 | fwexec("/usr/sbin/ipconfig", "waitall", NULL); 149 | autodiskmount(); /* wait for Disk Arbitration to report idle */ 150 | 151 | system_starter(kActionStart, NULL); 152 | 153 | if (StartupItemSecurityCheck("/etc/rc.local")) { 154 | fwexec(_PATH_BSHELL, "/etc/rc.local", NULL); 155 | } 156 | 157 | CFNotificationCenterPostNotificationWithOptions( 158 | CFNotificationCenterGetDistributedCenter(), 159 | CFSTR("com.apple.startupitems.completed"), 160 | NULL, NULL, 161 | kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions); 162 | 163 | r = kevent(kq, NULL, 0, &kev, 1, NULL); 164 | assert(r != -1); 165 | assert(kev.filter == EVFILT_SIGNAL && kev.ident == SIGTERM); 166 | 167 | if (StartupItemSecurityCheck("/etc/rc.shutdown.local")) { 168 | fwexec(_PATH_BSHELL, "/etc/rc.shutdown.local", NULL); 169 | } 170 | 171 | system_starter(kActionStop, NULL); 172 | 173 | exit(EXIT_SUCCESS); 174 | } 175 | 176 | 177 | /** 178 | * checkForActivity checks to see if any items have completed since the last invokation. 179 | * If not, a message is displayed showing what item(s) are being waited on. 180 | **/ 181 | static void 182 | checkForActivity(StartupContext aStartupContext) 183 | { 184 | static CFIndex aLastStatusDictionaryCount = -1; 185 | static CFStringRef aWaitingForString = NULL; 186 | 187 | if (aStartupContext && aStartupContext->aStatusDict) { 188 | CFIndex aCount = CFDictionaryGetCount(aStartupContext->aStatusDict); 189 | 190 | if (!aWaitingForString) { 191 | aWaitingForString = CFSTR("Waiting for %@"); 192 | } 193 | if (aLastStatusDictionaryCount == aCount) { 194 | CFArrayRef aRunningList = StartupItemListCreateFromRunning(aStartupContext->aWaitingList); 195 | if (aRunningList && CFArrayGetCount(aRunningList) > 0) { 196 | CFMutableDictionaryRef anItem = (CFMutableDictionaryRef) CFArrayGetValueAtIndex(aRunningList, 0); 197 | CFStringRef anItemDescription = StartupItemCreateDescription(anItem); 198 | CFStringRef aString = aWaitingForString && anItemDescription ? 199 | CFStringCreateWithFormat(NULL, NULL, aWaitingForString, anItemDescription) : NULL; 200 | 201 | if (aString) { 202 | CF_syslog(LOG_INFO, CFSTR("%@"), aString); 203 | CFRelease(aString); 204 | } 205 | if (anItemDescription) 206 | CFRelease(anItemDescription); 207 | } 208 | if (aRunningList) 209 | CFRelease(aRunningList); 210 | } 211 | aLastStatusDictionaryCount = aCount; 212 | } 213 | } 214 | 215 | /* 216 | * print out any error messages to the log regarding non starting StartupItems 217 | */ 218 | void 219 | displayErrorMessages(StartupContext aStartupContext, Action anAction) 220 | { 221 | if (aStartupContext->aFailedList && CFArrayGetCount(aStartupContext->aFailedList) > 0) { 222 | CFIndex anItemCount = CFArrayGetCount(aStartupContext->aFailedList); 223 | CFIndex anItemIndex; 224 | 225 | 226 | syslog(LOG_WARNING, "The following StartupItems failed to %s properly:", (anAction == kActionStart) ? "start" : "stop"); 227 | 228 | for (anItemIndex = 0; anItemIndex < anItemCount; anItemIndex++) { 229 | CFMutableDictionaryRef anItem = (CFMutableDictionaryRef) CFArrayGetValueAtIndex(aStartupContext->aFailedList, anItemIndex); 230 | CFStringRef anErrorDescription = CFDictionaryGetValue(anItem, kErrorKey); 231 | CFStringRef anItemPath = CFDictionaryGetValue(anItem, kBundlePathKey); 232 | 233 | if (anItemPath) { 234 | CF_syslog(LOG_WARNING, CFSTR("%@"), anItemPath); 235 | } 236 | if (anErrorDescription) { 237 | CF_syslog(LOG_WARNING, CFSTR(" - %@"), anErrorDescription); 238 | } else { 239 | CF_syslog(LOG_WARNING, CFSTR(" - %@"), kErrorInternal); 240 | } 241 | } 242 | } 243 | if (CFArrayGetCount(aStartupContext->aWaitingList) > 0) { 244 | CFIndex anItemCount = CFArrayGetCount(aStartupContext->aWaitingList); 245 | CFIndex anItemIndex; 246 | 247 | syslog(LOG_WARNING, "The following StartupItems were not attempted due to failure of a required service:"); 248 | 249 | for (anItemIndex = 0; anItemIndex < anItemCount; anItemIndex++) { 250 | CFMutableDictionaryRef anItem = (CFMutableDictionaryRef) CFArrayGetValueAtIndex(aStartupContext->aWaitingList, anItemIndex); 251 | CFStringRef anItemPath = CFDictionaryGetValue(anItem, kBundlePathKey); 252 | if (anItemPath) { 253 | CF_syslog(LOG_WARNING, CFSTR("%@"), anItemPath); 254 | } 255 | } 256 | } 257 | } 258 | 259 | 260 | static int 261 | system_starter(Action anAction, const char *aService_cstr) 262 | { 263 | CFStringRef aService = NULL; 264 | NSSearchPathDomainMask aMask; 265 | 266 | if (aService_cstr) 267 | aService = CFStringCreateWithCString(kCFAllocatorDefault, aService_cstr, kCFStringEncodingUTF8); 268 | 269 | StartupContext aStartupContext = (StartupContext) malloc(sizeof(struct StartupContextStorage)); 270 | if (!aStartupContext) { 271 | syslog(LOG_ERR, "Not enough memory to allocate startup context"); 272 | return (1); 273 | } 274 | if (gDebugFlag && gNoRunFlag) 275 | sleep(1); 276 | 277 | /** 278 | * Get a list of Startup Items which are in /Local and /System. 279 | * We can't search /Network yet because the network isn't up. 280 | **/ 281 | aMask = NSSystemDomainMask | NSLocalDomainMask; 282 | 283 | aStartupContext->aWaitingList = StartupItemListCreateWithMask(aMask); 284 | aStartupContext->aFailedList = NULL; 285 | aStartupContext->aStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, 286 | &kCFTypeDictionaryValueCallBacks); 287 | aStartupContext->aServicesCount = 0; 288 | aStartupContext->aRunningCount = 0; 289 | 290 | if (aService) { 291 | CFMutableArrayRef aDependentsList = StartupItemListCreateDependentsList(aStartupContext->aWaitingList, aService, anAction); 292 | 293 | if (aDependentsList) { 294 | CFRelease(aStartupContext->aWaitingList); 295 | aStartupContext->aWaitingList = aDependentsList; 296 | } else { 297 | CF_syslog(LOG_ERR, CFSTR("Unknown service: %@"), aService); 298 | return (1); 299 | } 300 | } 301 | aStartupContext->aServicesCount = StartupItemListCountServices(aStartupContext->aWaitingList); 302 | 303 | /** 304 | * Do the run loop 305 | **/ 306 | while (1) { 307 | CFMutableDictionaryRef anItem = StartupItemListGetNext(aStartupContext->aWaitingList, aStartupContext->aStatusDict, anAction); 308 | 309 | if (anItem) { 310 | int err = StartupItemRun(aStartupContext->aStatusDict, anItem, anAction); 311 | if (!err) { 312 | ++aStartupContext->aRunningCount; 313 | MonitorStartupItem(aStartupContext, anItem); 314 | } else { 315 | /* add item to failed list */ 316 | AddItemToFailedList(aStartupContext, anItem); 317 | 318 | /* Remove the item from the waiting list. */ 319 | RemoveItemFromWaitingList(aStartupContext, anItem); 320 | } 321 | } else { 322 | /* 323 | * If no item was selected to run, and if no items 324 | * are running, startup is done. 325 | */ 326 | if (aStartupContext->aRunningCount == 0) { 327 | syslog(LOG_DEBUG, "none left"); 328 | break; 329 | } 330 | /* 331 | * Process incoming IPC messages and item 332 | * terminations 333 | */ 334 | switch (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 3.0, true)) { 335 | case kCFRunLoopRunTimedOut: 336 | checkForActivity(aStartupContext); 337 | break; 338 | case kCFRunLoopRunFinished: 339 | break; 340 | case kCFRunLoopRunStopped: 341 | break; 342 | case kCFRunLoopRunHandledSource: 343 | break; 344 | default: 345 | /* unknown return value */ 346 | break; 347 | } 348 | } 349 | } 350 | 351 | /** 352 | * Good-bye. 353 | **/ 354 | displayErrorMessages(aStartupContext, anAction); 355 | 356 | /* clean up */ 357 | if (aStartupContext->aStatusDict) 358 | CFRelease(aStartupContext->aStatusDict); 359 | if (aStartupContext->aWaitingList) 360 | CFRelease(aStartupContext->aWaitingList); 361 | if (aStartupContext->aFailedList) 362 | CFRelease(aStartupContext->aFailedList); 363 | 364 | free(aStartupContext); 365 | return (0); 366 | } 367 | 368 | void 369 | CF_syslog(int level, CFStringRef message,...) 370 | { 371 | char buf[8192]; 372 | CFStringRef cooked_msg; 373 | va_list ap; 374 | 375 | va_start(ap, message); 376 | cooked_msg = CFStringCreateWithFormatAndArguments(NULL, NULL, message, ap); 377 | va_end(ap); 378 | 379 | if (CFStringGetCString(cooked_msg, buf, sizeof(buf), kCFStringEncodingUTF8)) 380 | syslog(level, "%s", buf); 381 | 382 | CFRelease(cooked_msg); 383 | } 384 | 385 | static void 386 | usage(void) 387 | { 388 | fprintf(stderr, "usage: %s [-vdqn?] [ [ ] ]\n" 389 | "\t: action to take (start|stop|restart); default is start\n" 390 | "\t : name of item to act on; default is all items\n" 391 | "options:\n" 392 | "\t-v: verbose startup\n" 393 | "\t-d: print debugging output\n" 394 | "\t-q: be quiet (disable debugging output)\n" 395 | "\t-n: don't actually perform action on items (pretend mode)\n" 396 | "\t-?: show this help\n", 397 | getprogname()); 398 | exit(EXIT_FAILURE); 399 | } 400 | 401 | pid_t 402 | fwexec(const char *cmd, ...) 403 | { 404 | const char *argv[100] = { cmd }; 405 | va_list ap; 406 | int wstatus, i = 1; 407 | pid_t p; 408 | 409 | va_start(ap, cmd); 410 | do { 411 | argv[i] = va_arg(ap, char *); 412 | } while (argv[i++]); 413 | va_end(ap); 414 | 415 | switch ((p = fork())) { 416 | case -1: 417 | return -1; 418 | case 0: 419 | execvp(argv[0], (char *const *)argv); 420 | _exit(EXIT_FAILURE); 421 | break; 422 | default: 423 | if (waitpid(p, &wstatus, 0) == -1) { 424 | return -1; 425 | } else if (WIFEXITED(wstatus)) { 426 | if (WEXITSTATUS(wstatus) == 0) { 427 | return 0; 428 | } else { 429 | syslog(LOG_WARNING, "%s exit status: %d", argv[0], WEXITSTATUS(wstatus)); 430 | } 431 | } else { 432 | /* must have died due to signal */ 433 | syslog(LOG_WARNING, "%s died: %s", argv[0], strsignal(WTERMSIG(wstatus))); 434 | } 435 | break; 436 | } 437 | 438 | return -1; 439 | } 440 | 441 | static void 442 | autodiskmount_idle(void* context __attribute__((unused))) 443 | { 444 | CFRunLoopStop(CFRunLoopGetCurrent()); 445 | } 446 | 447 | static void 448 | autodiskmount(void) 449 | { 450 | DASessionRef session = DASessionCreate(NULL); 451 | if (session) { 452 | DASessionScheduleWithRunLoop(session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); 453 | DARegisterIdleCallback(session, autodiskmount_idle, NULL); 454 | CFRunLoopRun(); 455 | CFRelease(session); 456 | } 457 | } 458 | -------------------------------------------------------------------------------- /SystemStarter/SystemStarter.h: -------------------------------------------------------------------------------- 1 | /** 2 | * SystemStarter.h - System Starter driver 3 | * Wilfredo Sanchez | wsanchez@opensource.apple.com 4 | * $Apple$ 5 | ** 6 | * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. 7 | * 8 | * @APPLE_APACHE_LICENSE_HEADER_START@ 9 | * 10 | * Licensed under the Apache License, Version 2.0 (the "License"); 11 | * you may not use this file except in compliance with the License. 12 | * You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, software 17 | * distributed under the License is distributed on an "AS IS" BASIS, 18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | * See the License for the specific language governing permissions and 20 | * limitations under the License. 21 | * 22 | * @APPLE_APACHE_LICENSE_HEADER_END@ 23 | **/ 24 | 25 | #ifndef _SYSTEM_STARTER_H_ 26 | #define _SYSTEM_STARTER_H_ 27 | 28 | /* Structure to pass common objects from system_starter to the IPC handlers */ 29 | typedef struct StartupContextStorage { 30 | CFMutableArrayRef aWaitingList; 31 | CFMutableArrayRef aFailedList; 32 | CFMutableDictionaryRef aStatusDict; 33 | int aServicesCount; 34 | int aRunningCount; 35 | } *StartupContext; 36 | 37 | #define kFixerDir "/var/db/fixer" 38 | #define kFixerPath "/var/db/fixer/StartupItems" 39 | 40 | /* Action types */ 41 | typedef enum { 42 | kActionNone = 0, 43 | kActionStart, 44 | kActionStop, 45 | kActionRestart 46 | } Action; 47 | 48 | void CF_syslog(int level, CFStringRef message, ...); 49 | extern bool gVerboseFlag; 50 | 51 | #endif /* _SYSTEM_STARTER_H_ */ 52 | -------------------------------------------------------------------------------- /SystemStarter/SystemStarterIPC.h: -------------------------------------------------------------------------------- 1 | /** 2 | * SystemStarterIPC.h - System Starter IPC definitions 3 | * Wilfredo Sanchez | wsanchez@opensource.apple.com 4 | * Kevin Van Vechten | kevinvv@uclink4.berkeley.edu 5 | ** 6 | * Copyright (c) 1999-2001 Apple Computer, Inc. All rights reserved. 7 | * 8 | * @APPLE_APACHE_LICENSE_HEADER_START@ 9 | * 10 | * Licensed under the Apache License, Version 2.0 (the "License"); 11 | * you may not use this file except in compliance with the License. 12 | * You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, software 17 | * distributed under the License is distributed on an "AS IS" BASIS, 18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | * See the License for the specific language governing permissions and 20 | * limitations under the License. 21 | * 22 | * @APPLE_APACHE_LICENSE_HEADER_END@ 23 | ** 24 | * Definitions used for IPC communications with SystemStarter. 25 | * SystemStarter listens on a CFMessagePort with the name defined by 26 | * kSystemStarterMessagePort. The messageID of each message should 27 | * be set to the kIPCProtocolVersion constant. The contents of each 28 | * message should be an XML plist containing a dictionary using 29 | * the keys defined in this file. 30 | **/ 31 | 32 | #ifndef _SYSTEM_STARTER_IPC_H 33 | #define _SYSTEM_STARTER_IPC_H 34 | 35 | #include 36 | #include 37 | 38 | /* Compatible with inline CFMessagePort messages. */ 39 | typedef struct SystemStarterIPCMessage { 40 | mach_msg_header_t aHeader; 41 | mach_msg_body_t aBody; 42 | SInt32 aProtocol; 43 | SInt32 aByteLength; 44 | /* Data follows. */ 45 | } SystemStarterIPCMessage; 46 | 47 | /* Name of the CFMessagePort SystemStarter listens on. */ 48 | #define kSystemStarterMessagePort "com.apple.SystemStarter" 49 | 50 | /* kIPCProtocolVersion should be passed as the messageID of the CFMessage. */ 51 | #define kIPCProtocolVersion 0 52 | 53 | /* kIPCTypeKey should be provided for all messages. */ 54 | #define kIPCMessageKey CFSTR("Message") 55 | 56 | /* Messages are one of the following types: */ 57 | #define kIPCConsoleMessage CFSTR("ConsoleMessage") 58 | #define kIPCStatusMessage CFSTR("StatusMessage") 59 | #define kIPCQueryMessage CFSTR("QueryMessage") 60 | #define kIPCLoadDisplayBundleMessage CFSTR("LoadDisplayBundle") 61 | #define kIPCUnloadDisplayBundleMessage CFSTR("UnloadDisplayBundle") 62 | 63 | /* kIPCServiceNameKey identifies a startup item by one of the services it provides. */ 64 | #define kIPCServiceNameKey CFSTR("ServiceName") 65 | 66 | /* kIPCProcessIDKey identifies a running startup item by its process id. */ 67 | #define kIPCProcessIDKey CFSTR("ProcessID") 68 | 69 | /* kIPCConsoleMessageKey contains the non-localized string to 70 | * display for messages of type kIPCTypeConsoleMessage. 71 | */ 72 | #define kIPCConsoleMessageKey CFSTR("ConsoleMessage") 73 | 74 | /* kIPCStatus key contains a boolean value. True for success, false for failure. */ 75 | #define kIPCStatusKey CFSTR("StatusKey") 76 | 77 | /* kIPCDisplayBundlePathKey contains a string path to the display bundle 78 | SystemStarter should attempt to load. */ 79 | #define kIPCDisplayBundlePathKey CFSTR("DisplayBundlePath") 80 | 81 | /* kIPCConfigNamegKey contains the name of a config setting to query */ 82 | #define kIPCConfigSettingKey CFSTR("ConfigSetting") 83 | 84 | /* Some config settings */ 85 | #define kIPCConfigSettingVerboseFlag CFSTR("VerboseFlag") 86 | #define kIPCConfigSettingNetworkUp CFSTR("NetworkUp") 87 | 88 | #endif /* _SYSTEM_STARTER_IPC_H */ 89 | -------------------------------------------------------------------------------- /SystemStarter/com.apple.SystemStarter.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | KeepAlive 6 | 7 | PathState 8 | 9 | /etc/rc.local 10 | 11 | /etc/rc.shutdown.local 12 | 13 | 14 | 15 | Label 16 | com.apple.SystemStarter 17 | Program 18 | /sbin/SystemStarter 19 | QueueDirectories 20 | 21 | /Library/StartupItems 22 | /System/Library/StartupItems 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /SystemStarter/hostconfig: -------------------------------------------------------------------------------- 1 | # This file is going away 2 | 3 | AFPSERVER=-NO- 4 | AUTHSERVER=-NO- 5 | TIMESYNC=-NO- 6 | QTSSERVER=-NO- 7 | -------------------------------------------------------------------------------- /liblaunch/bootstrap.h: -------------------------------------------------------------------------------- 1 | #ifndef __BOOTSTRAP_H__ 2 | #define __BOOTSTRAP_H__ 3 | /* 4 | * Copyright (c) 1999-2005 Apple Computer, Inc. All rights reserved. 5 | * 6 | * @APPLE_APACHE_LICENSE_HEADER_START@ 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * @APPLE_APACHE_LICENSE_HEADER_END@ 21 | */ 22 | 23 | /* 24 | * bootstrap -- fundamental service initiator and port server 25 | * Mike DeMoney, NeXT, Inc. 26 | * Copyright, 1990. All rights reserved. 27 | */ 28 | 29 | /* 30 | * Interface: Bootstrap server 31 | * 32 | * The bootstrap server is the first user-mode task initiated by the Mach 33 | * kernel at system boot time. The bootstrap server provides two services, 34 | * it initiates other system tasks, and manages a table of name-port bindings 35 | * for fundamental system services (e.g. lookupd, Window Manager, etc...). 36 | * 37 | * Name-port bindings can be established with the bootstrap server by either 38 | * of two mechanisms: 39 | * 40 | * 1. The binding can be indicated, in advance of the service that backs it 41 | * being available, via a "service create" request. In this case, bootstrap 42 | * will immediately create a port and bind the indicated name with that port. 43 | * At a later time, a service may "checkin" for the name-port 44 | * binding and will be returned receive rights for the bound port. Lookup's 45 | * on bindings created by this mechanism will return send rights to the port, 46 | * even if no service has "checked-in". In this case, requests sent to the 47 | * bound port will be queued until a server has checked-in and can satisfy the 48 | * request. 49 | * 50 | * 2. Bindings can be established dynamically via a "register" request. In 51 | * this case, the register request provides bootstrap with a name and send 52 | * rights for a port. Bootstrap will provide send rights for the bound port 53 | * to any requestor via the lookup request. 54 | * 55 | * Bootstrap provides its service port to descendant tasks via the Mach 56 | * "bootstrap" special task port. All direct descendants of bootstrap receive 57 | * a "privileged" bootstrap service port. System services that initiate 58 | * untrusted tasks should replace the Mach bootstrap task special port with 59 | * a subset bootstrap port to prevent them from infecting the namespace. 60 | * 61 | * The bootstrap server creates a "backup" port for each service that it 62 | * creates. This is used to detect when a checked out service is no longer 63 | * being served. The bootstrap server regains all rights to the port and 64 | * it is marked available for check-out again. This allows crashed servers to 65 | * resume service to previous clients. Lookup's on this named port will 66 | * continue to be serviced by bootstrap while holding receive rights for the 67 | * bound port. A client may detect that the service is inactive via the 68 | * bootstrap status request. If an inactive service re-registers rather 69 | * than "checking-in" the original bound port is destroyed. 70 | * 71 | * The status of a named service may be obtained via the "status" request. 72 | * A service is "active" if a name-port binding exists and receive rights 73 | * to the bound port are held by a task other than bootstrap. 74 | * 75 | * The bootstrap server may also (re)start server processes associated with 76 | * with a set of services. The definition of the server process is done 77 | * through the "create server" request. The server will be launched in the 78 | * same bootstrap context in which it was registered. 79 | */ 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | 87 | __BEGIN_DECLS 88 | 89 | #pragma GCC visibility push(default) 90 | 91 | #define BOOTSTRAP_MAX_NAME_LEN 128 92 | #define BOOTSTRAP_MAX_CMD_LEN 512 93 | 94 | typedef char name_t[BOOTSTRAP_MAX_NAME_LEN]; 95 | typedef char cmd_t[BOOTSTRAP_MAX_CMD_LEN]; 96 | typedef name_t *name_array_t; 97 | typedef int bootstrap_status_t; 98 | typedef bootstrap_status_t *bootstrap_status_array_t; 99 | typedef unsigned int bootstrap_property_t; 100 | typedef bootstrap_property_t * bootstrap_property_array_t; 101 | 102 | typedef boolean_t *bool_array_t; 103 | 104 | #define BOOTSTRAP_MAX_LOOKUP_COUNT 20 105 | 106 | #define BOOTSTRAP_SUCCESS 0 107 | #define BOOTSTRAP_NOT_PRIVILEGED 1100 108 | #define BOOTSTRAP_NAME_IN_USE 1101 109 | #define BOOTSTRAP_UNKNOWN_SERVICE 1102 110 | #define BOOTSTRAP_SERVICE_ACTIVE 1103 111 | #define BOOTSTRAP_BAD_COUNT 1104 112 | #define BOOTSTRAP_NO_MEMORY 1105 113 | #define BOOTSTRAP_NO_CHILDREN 1106 114 | 115 | #define BOOTSTRAP_STATUS_INACTIVE 0 116 | #define BOOTSTRAP_STATUS_ACTIVE 1 117 | #define BOOTSTRAP_STATUS_ON_DEMAND 2 118 | 119 | /* 120 | * After main() starts, it is safe to assume that this variable is always set. 121 | */ 122 | extern mach_port_t bootstrap_port; 123 | 124 | /* 125 | * bootstrap_create_server() 126 | * 127 | * Declares a server that mach_init will re-spawn within the specified 128 | * bootstrap context. The server is considered already "active" 129 | * (i.e. will not be re-spawned) until the returned server_port is 130 | * deallocated. 131 | * 132 | * In the meantime, services can be declared against the server, 133 | * by using the server_port as the privileged bootstrap target of 134 | * subsequent bootstrap_create_service() calls. 135 | * 136 | * When mach_init re-spawns the server, its task bootstrap port 137 | * is set to the privileged sever_port. Through this special 138 | * bootstrap port, it can access all of parent bootstrap's context 139 | * (and all services are created in the parent's namespace). But 140 | * all additional service declarations (and declaration removals) 141 | * will be associated with this particular server. 142 | * 143 | * Only a holder of the server_port privilege bootstrap port can 144 | * check in or register over those services. 145 | * 146 | * When all services associated with a server are deleted, and the server 147 | * exits, it will automatically be deleted itself. 148 | * 149 | * If the server is declared "on_demand," then a non-running server 150 | * will be re-launched on first use of one of the service ports 151 | * registered against it. Otherwise, it will be re-launched 152 | * immediately upon exiting (whether any client is actively using 153 | * any of the service ports or not). 154 | * 155 | * Errors: Returns appropriate kernel errors on rpc failure. 156 | * Returns BOOTSTRAP_NOT_PRIVILEGED, bootstrap or uid invalid. 157 | */ 158 | kern_return_t bootstrap_create_server( 159 | mach_port_t bp, 160 | cmd_t server_cmd, 161 | uid_t server_uid, 162 | boolean_t on_demand, 163 | mach_port_t *server_port); 164 | 165 | /* 166 | * bootstrap_subset() 167 | * 168 | * Returns a new port to use as a bootstrap port. This port behaves 169 | * exactly like the previous bootstrap_port, except that ports dynamically 170 | * registered via bootstrap_register() are available only to users of this 171 | * specific subset_port. Lookups on the subset_port will return ports 172 | * registered with this port specifically, and ports registered with 173 | * ancestors of this subset_port. Duplications of services already 174 | * registered with an ancestor port may be registered with the subset port 175 | * are allowed. Services already advertised may then be effectively removed 176 | * by registering PORT_NULL for the service. 177 | * When it is detected that the requestor_port is destroyed the subset 178 | * port and all services advertized by it are destroyed as well. 179 | * 180 | * Errors: Returns appropriate kernel errors on rpc failure. 181 | */ 182 | kern_return_t bootstrap_subset( 183 | mach_port_t bp, 184 | mach_port_t requestor_port, 185 | mach_port_t *subset_port); 186 | 187 | /* 188 | * bootstrap_unprivileged() 189 | * 190 | * Given a bootstrap port, return its unprivileged equivalent. If 191 | * the port is already unprivileged, another reference to the same 192 | * port is returned. 193 | * 194 | * This is most often used by servers, which are launched with their 195 | * bootstrap port set to the privileged port for the server, to get 196 | * an unprivileged version of the same port for use by its unprivileged 197 | * children (or any offspring that it does not want to count as part 198 | * of the "server" for mach_init registration and re-launch purposes). 199 | * 200 | * Native launchd jobs are always started with an unprivileged port. 201 | */ 202 | kern_return_t bootstrap_unprivileged( 203 | mach_port_t bp, 204 | mach_port_t *unpriv_port) 205 | AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5; 206 | 207 | /* 208 | * bootstrap_parent() 209 | * 210 | * Given a bootstrap subset port, return the parent bootstrap port. 211 | * If the specified bootstrap port is already the root subset, 212 | * the same port will be returned. Much like "." and ".." are the same 213 | * in the file system name space for the root directory ("/"). 214 | * 215 | * Errors: 216 | * Returns BOOTSTRAP_NOT_PRIVILEGED if the caller is not running 217 | * with an effective user id of root (as determined by the security 218 | * token in the message trailer). 219 | */ 220 | kern_return_t bootstrap_parent( 221 | mach_port_t bp, 222 | mach_port_t *parent_port); 223 | 224 | /* 225 | * bootstrap_register() 226 | * 227 | * Registers a send right for service_port with the service identified by 228 | * service_name. Attempts to register a service where an active binding 229 | * already exists are rejected. 230 | * 231 | * If the service was previously declared with bootstrap_create_service(), 232 | * but is not currently active, this call can be used to undeclare the 233 | * service. The bootstrap port used must have sufficient privilege to 234 | * do so. (Registering MACH_PORT_NULL is especially useful for shutting 235 | * down declared services). 236 | * 237 | * This API is deprecated. Old scenarios and recommendations: 238 | * 239 | * 1) Code that used to call bootstrap_check_in() and then bootstrap_register() 240 | * can now always call bootstrap_check_in(). 241 | * 242 | * 2) If the code was registering a well known name, please switch to launchd. 243 | * 244 | * 3) If the code was registering a dynamically generated string and passing 245 | * the string to other applications, please rewrite the code to send a Mach 246 | * send-right directly. 247 | * 248 | * 4) If the launchd job maintained an optional Mach service, please reserve 249 | * the name with launchd and control the presense of the service through 250 | * ownership of the Mach receive right like so. 251 | * 252 | * MachServices 253 | * 254 | * com.apple.windowserver 255 | * 256 | * com.apple.windowserver.active 257 | * 258 | * HideUntilCheckIn 259 | * 260 | * 261 | * 262 | * 263 | * 264 | * Errors: Returns appropriate kernel errors on rpc failure. 265 | * Returns BOOTSTRAP_NOT_PRIVILEGED, if request directed to 266 | * bootstrap port without privilege. 267 | * Returns BOOTSTRAP_NAME_IN_USE, if service has already been 268 | * register or checked-in. 269 | */ 270 | AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5 271 | kern_return_t 272 | bootstrap_register(mach_port_t bp, name_t service_name, mach_port_t sp); 273 | 274 | /* 275 | * bootstrap_create_service() 276 | * 277 | * Creates a service named "service_name" and returns a send right to that 278 | * port in "service_port." The port may later be checked in as if this 279 | * port were configured in the bootstrap configuration file. 280 | * 281 | * This API is deprecated. Please call bootstrap_check_in() instead. 282 | * 283 | * Errors: Returns appropriate kernel errors on rpc failure. 284 | * Returns BOOTSTRAP_SERVICE_ACTIVE, if service already exists. 285 | */ 286 | #ifdef AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 287 | AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6 288 | #endif 289 | kern_return_t 290 | bootstrap_create_service(mach_port_t bp, name_t service_name, mach_port_t *sp); 291 | 292 | /* 293 | * bootstrap_check_in() 294 | * 295 | * Returns the receive right for the service named by service_name. The 296 | * service must have been declared in the launchd.plist(5) file associated 297 | * with the job. Attempts to check_in a service which is already active 298 | * are not allowed. 299 | * 300 | * If the service was declared as being associated with a server, the 301 | * check_in must come from the server's privileged port (server_port). 302 | * 303 | * Errors: Returns appropriate kernel errors on rpc failure. 304 | * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist. 305 | * Returns BOOTSTRAP_NOT_PRIVILEGED, if request directed to 306 | * bootstrap port without privilege. 307 | * Returns BOOTSTRAP_SERVICE_ACTIVE, if service has already been 308 | * registered or checked-in. 309 | */ 310 | kern_return_t bootstrap_check_in( 311 | mach_port_t bp, 312 | const name_t service_name, 313 | mach_port_t *sp); 314 | 315 | /* 316 | * bootstrap_look_up() 317 | * 318 | * Returns a send right for the service port declared/registered under the 319 | * name service_name. The service is not guaranteed to be active. Use the 320 | * bootstrap_status call to determine the status of the service. 321 | * 322 | * Errors: Returns appropriate kernel errors on rpc failure. 323 | * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist. 324 | */ 325 | kern_return_t bootstrap_look_up( 326 | mach_port_t bp, 327 | const name_t service_name, 328 | mach_port_t *sp); 329 | 330 | /* 331 | * bootstrap_status() 332 | * 333 | * In practice, this call was used to preflight whether the following two 334 | * APIs would succeed. 335 | * 336 | * bootstrap_look_up() 337 | * bootstrap_check_in() 338 | * 339 | * Please don't bother. Just call the above two APIs directly and check 340 | * for failure. 341 | */ 342 | kern_return_t bootstrap_status( 343 | mach_port_t bp, 344 | name_t service_name, 345 | bootstrap_status_t *service_active) 346 | AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5; 347 | 348 | /* bootstrap_strerror() 349 | * 350 | * Translate a return value from the bootstrap_*() APIs to a string. 351 | */ 352 | const char *bootstrap_strerror(kern_return_t r) __attribute__((__nothrow__, __pure__, __warn_unused_result__)); 353 | 354 | #pragma GCC visibility pop 355 | 356 | __END_DECLS 357 | 358 | #endif /* __BOOTSTRAP_H__ */ 359 | -------------------------------------------------------------------------------- /liblaunch/bootstrap_priv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #ifndef __BOOTSTRAP_PRIVATE_H__ 22 | #define __BOOTSTRAP_PRIVATE_H__ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | __BEGIN_DECLS 29 | 30 | #pragma GCC visibility push(default) 31 | 32 | #define BOOTSTRAP_PER_PID_SERVICE (1 << 0) 33 | #define BOOTSTRAP_ALLOW_LOOKUP (1 << 1) 34 | #define BOOTSTRAP_DENY_JOB_CREATION (1 << 2) 35 | #define BOOTSTRAP_PRIVILEGED_SERVER (1 << 3) 36 | #define BOOTSTRAP_FORCE_LOCAL (1 << 4) 37 | #define BOOTSTRAP_SPECIFIC_INSTANCE (1 << 5) 38 | #define BOOTSTRAP_STRICT_CHECKIN (1 << 6) 39 | #define BOOTSTRAP_STRICT_LOOKUP (1 << 7) 40 | 41 | #define BOOTSTRAP_PROPERTY_EXPLICITSUBSET (1 << 0) /* Created via bootstrap_subset(). */ 42 | #define BOOTSTRAP_PROPERTY_IMPLICITSUBSET (1 << 1) /* Created via _vprocmgr_switch_to_session(). */ 43 | #define BOOTSTRAP_PROPERTY_MOVEDSUBSET (1 << 2) /* Created via _vprocmgr_move_subset_to_user(). */ 44 | #define BOOTSTRAP_PROPERTY_PERUSER (1 << 3) /* A per-user launchd's root bootstrap. */ 45 | #define BOOTSTRAP_PROPERTY_XPC_DOMAIN (1 << 4) /* An XPC domain. Duh. */ 46 | #define BOOTSTRAP_PROPERTY_XPC_SINGLETON (1 << 5) /* A singleton XPC domain. */ 47 | 48 | void bootstrap_init(void); 49 | 50 | kern_return_t bootstrap_register2(mach_port_t bp, name_t service_name, mach_port_t sp, uint64_t flags); 51 | 52 | kern_return_t bootstrap_look_up2(mach_port_t bp, const name_t service_name, mach_port_t *sp, pid_t target_pid, uint64_t flags); 53 | 54 | kern_return_t bootstrap_check_in2(mach_port_t bp, const name_t service_name, mach_port_t *sp, uint64_t flags); 55 | 56 | kern_return_t bootstrap_look_up_per_user(mach_port_t bp, const name_t service_name, uid_t target_user, mach_port_t *sp); 57 | 58 | kern_return_t bootstrap_lookup_children(mach_port_t bp, mach_port_array_t *children, name_array_t *names, bootstrap_property_array_t *properties, mach_msg_type_number_t *n_children); 59 | 60 | kern_return_t bootstrap_look_up3(mach_port_t bp, const name_t service_name, mach_port_t *sp, pid_t target_pid, const uuid_t instance_id, uint64_t flags); 61 | 62 | kern_return_t bootstrap_check_in3(mach_port_t bp, const name_t service_name, mach_port_t *sp, uuid_t instance_id, uint64_t flags); 63 | 64 | kern_return_t bootstrap_get_root(mach_port_t bp, mach_port_t *root); 65 | 66 | #pragma GCC visibility pop 67 | 68 | __END_DECLS 69 | 70 | #endif /* __BOOTSTRAP_PRIVATE_H__ */ 71 | -------------------------------------------------------------------------------- /liblaunch/launch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #ifndef __LAUNCH_H__ 22 | #define __LAUNCH_H__ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #pragma GCC visibility push(default) 30 | 31 | __BEGIN_DECLS 32 | 33 | #ifdef __GNUC__ 34 | #define __ld_normal __attribute__((__nothrow__)) 35 | #define __ld_setter __attribute__((__nothrow__, __nonnull__)) 36 | #define __ld_getter __attribute__((__nothrow__, __nonnull__, __pure__, __warn_unused_result__)) 37 | #define __ld_iterator(x, y) __attribute__((__nonnull__(x, y))) 38 | #define __ld_allocator __attribute__((__nothrow__, __malloc__, __nonnull__, __warn_unused_result__)) 39 | #else 40 | #define __ld_normal 41 | #define __ld_setter 42 | #define __ld_getter 43 | #define __ld_iterator(x, y) 44 | #define __ld_allocator 45 | #endif 46 | 47 | #define LAUNCH_KEY_SUBMITJOB "SubmitJob" 48 | #define LAUNCH_KEY_REMOVEJOB "RemoveJob" 49 | #define LAUNCH_KEY_STARTJOB "StartJob" 50 | #define LAUNCH_KEY_STOPJOB "StopJob" 51 | #define LAUNCH_KEY_GETJOB "GetJob" 52 | #define LAUNCH_KEY_GETJOBS "GetJobs" 53 | #define LAUNCH_KEY_CHECKIN "CheckIn" 54 | 55 | #define LAUNCH_JOBKEY_DEFAULTS "__Defaults" 56 | 57 | #define LAUNCH_JOBKEY_LABEL "Label" 58 | #define LAUNCH_JOBKEY_DISABLED "Disabled" 59 | #define LAUNCH_JOBKEY_USERNAME "UserName" 60 | #define LAUNCH_JOBKEY_GROUPNAME "GroupName" 61 | #define LAUNCH_JOBKEY_TIMEOUT "TimeOut" 62 | #define LAUNCH_JOBKEY_EXITTIMEOUT "ExitTimeOut" 63 | #define LAUNCH_JOBKEY_INITGROUPS "InitGroups" 64 | #define LAUNCH_JOBKEY_SOCKETS "Sockets" 65 | #define LAUNCH_JOBKEY_MACHSERVICES "MachServices" 66 | #define LAUNCH_JOBKEY_MACHSERVICELOOKUPPOLICIES "MachServiceLookupPolicies" 67 | #define LAUNCH_JOBKEY_INETDCOMPATIBILITY "inetdCompatibility" 68 | #define LAUNCH_JOBKEY_ENABLEGLOBBING "EnableGlobbing" 69 | #define LAUNCH_JOBKEY_PROGRAMARGUMENTS "ProgramArguments" 70 | #define LAUNCH_JOBKEY_PROGRAM "Program" 71 | #define LAUNCH_JOBKEY_ONDEMAND "OnDemand" 72 | #define LAUNCH_JOBKEY_KEEPALIVE "KeepAlive" 73 | #define LAUNCH_JOBKEY_LIMITLOADTOHOSTS "LimitLoadToHosts" 74 | #define LAUNCH_JOBKEY_LIMITLOADFROMHOSTS "LimitLoadFromHosts" 75 | #define LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE "LimitLoadToSessionType" 76 | #define LAUNCH_JOBKEY_LIMITLOADTOHARDWARE "LimitLoadToHardware" 77 | #define LAUNCH_JOBKEY_LIMITLOADFROMHARDWARE "LimitLoadFromHardware" 78 | #define LAUNCH_JOBKEY_RUNATLOAD "RunAtLoad" 79 | #define LAUNCH_JOBKEY_ROOTDIRECTORY "RootDirectory" 80 | #define LAUNCH_JOBKEY_WORKINGDIRECTORY "WorkingDirectory" 81 | #define LAUNCH_JOBKEY_ENVIRONMENTVARIABLES "EnvironmentVariables" 82 | #define LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES "UserEnvironmentVariables" 83 | #define LAUNCH_JOBKEY_UMASK "Umask" 84 | #define LAUNCH_JOBKEY_NICE "Nice" 85 | #define LAUNCH_JOBKEY_HOPEFULLYEXITSFIRST "HopefullyExitsFirst" 86 | #define LAUNCH_JOBKEY_HOPEFULLYEXITSLAST "HopefullyExitsLast" 87 | #define LAUNCH_JOBKEY_LOWPRIORITYIO "LowPriorityIO" 88 | #define LAUNCH_JOBKEY_SESSIONCREATE "SessionCreate" 89 | #define LAUNCH_JOBKEY_STARTONMOUNT "StartOnMount" 90 | #define LAUNCH_JOBKEY_SOFTRESOURCELIMITS "SoftResourceLimits" 91 | #define LAUNCH_JOBKEY_HARDRESOURCELIMITS "HardResourceLimits" 92 | #define LAUNCH_JOBKEY_STANDARDINPATH "StandardInPath" 93 | #define LAUNCH_JOBKEY_STANDARDOUTPATH "StandardOutPath" 94 | #define LAUNCH_JOBKEY_STANDARDERRORPATH "StandardErrorPath" 95 | #define LAUNCH_JOBKEY_DEBUG "Debug" 96 | #define LAUNCH_JOBKEY_WAITFORDEBUGGER "WaitForDebugger" 97 | #define LAUNCH_JOBKEY_QUEUEDIRECTORIES "QueueDirectories" 98 | #define LAUNCH_JOBKEY_WATCHPATHS "WatchPaths" 99 | #define LAUNCH_JOBKEY_STARTINTERVAL "StartInterval" 100 | #define LAUNCH_JOBKEY_STARTCALENDARINTERVAL "StartCalendarInterval" 101 | #define LAUNCH_JOBKEY_BONJOURFDS "BonjourFDs" 102 | #define LAUNCH_JOBKEY_LASTEXITSTATUS "LastExitStatus" 103 | #define LAUNCH_JOBKEY_PID "PID" 104 | #define LAUNCH_JOBKEY_THROTTLEINTERVAL "ThrottleInterval" 105 | #define LAUNCH_JOBKEY_LAUNCHONLYONCE "LaunchOnlyOnce" 106 | #define LAUNCH_JOBKEY_ABANDONPROCESSGROUP "AbandonProcessGroup" 107 | #define LAUNCH_JOBKEY_IGNOREPROCESSGROUPATSHUTDOWN "IgnoreProcessGroupAtShutdown" 108 | #define LAUNCH_JOBKEY_POLICIES "Policies" 109 | #define LAUNCH_JOBKEY_ENABLETRANSACTIONS "EnableTransactions" 110 | #define LAUNCH_JOBKEY_CFBUNDLEIDENTIFIER "CFBundleIdentifier" 111 | #define LAUNCH_JOBKEY_PROCESSTYPE "ProcessType" 112 | #define LAUNCH_KEY_PROCESSTYPE_APP "App" 113 | #define LAUNCH_KEY_PROCESSTYPE_STANDARD "Standard" 114 | #define LAUNCH_KEY_PROCESSTYPE_BACKGROUND "Background" 115 | #define LAUNCH_KEY_PROCESSTYPE_INTERACTIVE "Interactive" 116 | #define LAUNCH_KEY_PROCESSTYPE_ADAPTIVE "Adaptive" 117 | 118 | #define LAUNCH_JOBPOLICY_DENYCREATINGOTHERJOBS "DenyCreatingOtherJobs" 119 | 120 | #define LAUNCH_JOBINETDCOMPATIBILITY_WAIT "Wait" 121 | 122 | #define LAUNCH_JOBKEY_MACH_RESETATCLOSE "ResetAtClose" 123 | #define LAUNCH_JOBKEY_MACH_HIDEUNTILCHECKIN "HideUntilCheckIn" 124 | #define LAUNCH_JOBKEY_MACH_DRAINMESSAGESONCRASH "DrainMessagesOnCrash" 125 | #define LAUNCH_JOBKEY_MACH_PINGEVENTUPDATES "PingEventUpdates" 126 | 127 | #define LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT "SuccessfulExit" 128 | #define LAUNCH_JOBKEY_KEEPALIVE_NETWORKSTATE "NetworkState" 129 | #define LAUNCH_JOBKEY_KEEPALIVE_PATHSTATE "PathState" 130 | #define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBACTIVE "OtherJobActive" 131 | #define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBENABLED "OtherJobEnabled" 132 | #define LAUNCH_JOBKEY_KEEPALIVE_AFTERINITIALDEMAND "AfterInitialDemand" 133 | #define LAUNCH_JOBKEY_KEEPALIVE_CRASHED "Crashed" 134 | 135 | #define LAUNCH_JOBKEY_LAUNCHEVENTS "LaunchEvents" 136 | 137 | #define LAUNCH_JOBKEY_CAL_MINUTE "Minute" 138 | #define LAUNCH_JOBKEY_CAL_HOUR "Hour" 139 | #define LAUNCH_JOBKEY_CAL_DAY "Day" 140 | #define LAUNCH_JOBKEY_CAL_WEEKDAY "Weekday" 141 | #define LAUNCH_JOBKEY_CAL_MONTH "Month" 142 | 143 | #define LAUNCH_JOBKEY_RESOURCELIMIT_CORE "Core" 144 | #define LAUNCH_JOBKEY_RESOURCELIMIT_CPU "CPU" 145 | #define LAUNCH_JOBKEY_RESOURCELIMIT_DATA "Data" 146 | #define LAUNCH_JOBKEY_RESOURCELIMIT_FSIZE "FileSize" 147 | #define LAUNCH_JOBKEY_RESOURCELIMIT_MEMLOCK "MemoryLock" 148 | #define LAUNCH_JOBKEY_RESOURCELIMIT_NOFILE "NumberOfFiles" 149 | #define LAUNCH_JOBKEY_RESOURCELIMIT_NPROC "NumberOfProcesses" 150 | #define LAUNCH_JOBKEY_RESOURCELIMIT_RSS "ResidentSetSize" 151 | #define LAUNCH_JOBKEY_RESOURCELIMIT_STACK "Stack" 152 | 153 | #define LAUNCH_JOBKEY_DISABLED_MACHINETYPE "MachineType" 154 | #define LAUNCH_JOBKEY_DISABLED_MODELNAME "ModelName" 155 | 156 | #define LAUNCH_JOBSOCKETKEY_TYPE "SockType" 157 | #define LAUNCH_JOBSOCKETKEY_PASSIVE "SockPassive" 158 | #define LAUNCH_JOBSOCKETKEY_BONJOUR "Bonjour" 159 | #define LAUNCH_JOBSOCKETKEY_SECUREWITHKEY "SecureSocketWithKey" 160 | #define LAUNCH_JOBSOCKETKEY_PATHNAME "SockPathName" 161 | #define LAUNCH_JOBSOCKETKEY_PATHMODE "SockPathMode" 162 | #define LAUNCH_JOBSOCKETKEY_NODENAME "SockNodeName" 163 | #define LAUNCH_JOBSOCKETKEY_SERVICENAME "SockServiceName" 164 | #define LAUNCH_JOBSOCKETKEY_FAMILY "SockFamily" 165 | #define LAUNCH_JOBSOCKETKEY_PROTOCOL "SockProtocol" 166 | #define LAUNCH_JOBSOCKETKEY_MULTICASTGROUP "MulticastGroup" 167 | 168 | /* These APIs are NOT suitable for general use. Their use should be constrained 169 | * to checking into launchd to obtain socket file descriptors using the 170 | * LAUNCH_CHECK_IN message type. 171 | */ 172 | typedef struct _launch_data *launch_data_t; 173 | 174 | typedef enum { 175 | LAUNCH_DATA_DICTIONARY = 1, 176 | LAUNCH_DATA_ARRAY, 177 | LAUNCH_DATA_FD, 178 | LAUNCH_DATA_INTEGER, 179 | LAUNCH_DATA_REAL, 180 | LAUNCH_DATA_BOOL, 181 | LAUNCH_DATA_STRING, 182 | LAUNCH_DATA_OPAQUE, 183 | LAUNCH_DATA_ERRNO, 184 | LAUNCH_DATA_MACHPORT, 185 | } launch_data_type_t; 186 | 187 | __ld_allocator 188 | launch_data_t 189 | launch_data_alloc(launch_data_type_t); 190 | 191 | __ld_allocator 192 | launch_data_t 193 | launch_data_copy(launch_data_t); 194 | 195 | __ld_getter 196 | launch_data_type_t 197 | launch_data_get_type(const launch_data_t); 198 | 199 | __ld_setter 200 | void 201 | launch_data_free(launch_data_t); 202 | 203 | __ld_setter 204 | bool 205 | launch_data_dict_insert(launch_data_t, const launch_data_t, const char *); 206 | 207 | __ld_getter 208 | launch_data_t 209 | launch_data_dict_lookup(const launch_data_t, const char *); 210 | 211 | __ld_setter 212 | bool 213 | launch_data_dict_remove(launch_data_t, const char *); 214 | 215 | __ld_iterator(1, 2) 216 | void 217 | launch_data_dict_iterate(const launch_data_t, 218 | void (*)(const launch_data_t, const char *, void *), void *); 219 | 220 | __ld_getter 221 | size_t 222 | launch_data_dict_get_count(const launch_data_t); 223 | 224 | __ld_setter 225 | bool 226 | launch_data_array_set_index(launch_data_t, const launch_data_t, size_t); 227 | 228 | __ld_getter 229 | launch_data_t 230 | launch_data_array_get_index(const launch_data_t, size_t); 231 | 232 | __ld_getter 233 | size_t 234 | launch_data_array_get_count(const launch_data_t); 235 | 236 | __ld_allocator 237 | launch_data_t 238 | launch_data_new_fd(int); 239 | 240 | __ld_allocator 241 | launch_data_t 242 | launch_data_new_machport(mach_port_t); 243 | 244 | __ld_allocator 245 | launch_data_t 246 | launch_data_new_integer(long long); 247 | 248 | __ld_allocator 249 | launch_data_t 250 | launch_data_new_bool(bool); 251 | 252 | __ld_allocator 253 | launch_data_t 254 | launch_data_new_real(double); 255 | 256 | __ld_allocator 257 | launch_data_t 258 | launch_data_new_string(const char *); 259 | 260 | __ld_allocator 261 | launch_data_t 262 | launch_data_new_opaque(const void *, size_t); 263 | 264 | __ld_setter 265 | bool 266 | launch_data_set_fd(launch_data_t, int); 267 | 268 | __ld_setter 269 | bool 270 | launch_data_set_machport(launch_data_t, mach_port_t); 271 | 272 | __ld_setter 273 | bool 274 | launch_data_set_integer(launch_data_t, long long); 275 | 276 | __ld_setter 277 | bool 278 | launch_data_set_bool(launch_data_t, bool); 279 | 280 | __ld_setter 281 | bool 282 | launch_data_set_real(launch_data_t, double); 283 | 284 | __ld_setter 285 | bool 286 | launch_data_set_string(launch_data_t, const char *); 287 | 288 | __ld_setter 289 | bool 290 | launch_data_set_opaque(launch_data_t, const void *, size_t); 291 | 292 | __ld_getter 293 | int 294 | launch_data_get_fd(const launch_data_t); 295 | 296 | __ld_getter 297 | mach_port_t 298 | launch_data_get_machport(const launch_data_t); 299 | 300 | __ld_getter 301 | long long 302 | launch_data_get_integer(const launch_data_t); 303 | 304 | __ld_getter 305 | bool 306 | launch_data_get_bool(const launch_data_t); 307 | 308 | __ld_getter 309 | double 310 | launch_data_get_real(const launch_data_t); 311 | 312 | __ld_getter 313 | const char * 314 | launch_data_get_string(const launch_data_t); 315 | 316 | __ld_getter 317 | void * 318 | launch_data_get_opaque(const launch_data_t); 319 | 320 | __ld_getter 321 | size_t 322 | launch_data_get_opaque_size(const launch_data_t); 323 | 324 | __ld_getter 325 | int 326 | launch_data_get_errno(const launch_data_t); 327 | 328 | 329 | /* launch_get_fd() 330 | * 331 | * Use this to get the FD if you're doing asynchronous I/O with select(), 332 | * poll() or kevent(). 333 | */ 334 | __ld_normal 335 | int 336 | launch_get_fd(void); 337 | 338 | /* launch_msg() 339 | * 340 | * Use this API to check in. Nothing else. 341 | */ 342 | __ld_normal 343 | launch_data_t 344 | launch_msg(const launch_data_t); 345 | 346 | __END_DECLS 347 | 348 | #pragma GCC visibility pop 349 | 350 | #endif /* __LAUNCH_H__ */ 351 | -------------------------------------------------------------------------------- /liblaunch/launch_internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2012 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #ifndef __LAUNCH_INTERNAL_H__ 22 | #define __LAUNCH_INTERNAL_H__ 23 | 24 | #include "vproc_priv.h" 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #if __has_include() 31 | #include 32 | #if defined(OS_ALLOC_ONCE_KEY_LIBLAUNCH) 33 | #define _LIBLAUNCH_HAS_ALLOC_ONCE 1 34 | #endif 35 | #endif 36 | 37 | typedef struct _launch *launch_t; 38 | 39 | struct launch_globals_s { 40 | // liblaunch.c 41 | pthread_once_t lc_once; 42 | pthread_mutex_t lc_mtx; 43 | launch_t l; 44 | launch_data_t async_resp; 45 | 46 | launch_t in_flight_msg_recv_client; 47 | 48 | int64_t s_am_embedded_god; 49 | 50 | // libvproc.c 51 | dispatch_queue_t _vproc_gone2zero_queue; 52 | _vproc_transaction_callout _vproc_gone2zero_callout; 53 | void *_vproc_gone2zero_ctx; 54 | 55 | dispatch_once_t _vproc_transaction_once; 56 | uint64_t _vproc_transaction_enabled; 57 | dispatch_queue_t _vproc_transaction_queue; 58 | int64_t _vproc_transaction_cnt; 59 | }; 60 | typedef struct launch_globals_s *launch_globals_t; 61 | 62 | void _launch_init_globals(launch_globals_t globals); 63 | 64 | #if !_LIBLAUNCH_HAS_ALLOC_ONCE 65 | launch_globals_t _launch_globals_impl(void); 66 | #endif 67 | 68 | __attribute__((__pure__)) 69 | static inline launch_globals_t 70 | _launch_globals(void) { 71 | #if _LIBLAUNCH_HAS_ALLOC_ONCE 72 | return (launch_globals_t)os_alloc_once(OS_ALLOC_ONCE_KEY_LIBLAUNCH, 73 | sizeof(struct launch_globals_s), 74 | (void*)&_launch_init_globals); 75 | #else 76 | return _launch_globals_impl(); 77 | #endif 78 | } 79 | 80 | #pragma GCC visibility push(default) 81 | 82 | #define LAUNCHD_DB_PREFIX "/private/var/db/launchd.db" 83 | #define LAUNCHD_LOG_PREFIX "/private/var/log" 84 | 85 | #define LAUNCHD_JOB_DEFAULTS "Defaults" 86 | #define LAUNCHD_JOB_DEFAULTS_CACHED "CachedDefaults" 87 | 88 | launch_t launchd_fdopen(int, int); 89 | int launchd_getfd(launch_t); 90 | void launchd_close(launch_t, __typeof__(close) closefunc); 91 | 92 | launch_data_t launch_data_new_errno(int); 93 | bool launch_data_set_errno(launch_data_t, int); 94 | 95 | int launchd_msg_send(launch_t, launch_data_t); 96 | int launchd_msg_recv(launch_t, void (*)(launch_data_t, void *), void *); 97 | 98 | size_t launch_data_pack(launch_data_t d, void *where, size_t len, int *fd_where, size_t *fdslotsleft); 99 | launch_data_t launch_data_unpack(void *data, size_t data_size, int *fds, size_t fd_cnt, size_t *data_offset, size_t *fdoffset); 100 | 101 | #pragma GCC visibility pop 102 | 103 | #endif /* __LAUNCH_INTERNAL_H__*/ 104 | -------------------------------------------------------------------------------- /liblaunch/launch_priv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #ifndef __LAUNCH_PRIVATE_H__ 22 | #define __LAUNCH_PRIVATE_H__ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #pragma GCC visibility push(default) 32 | 33 | __BEGIN_DECLS 34 | 35 | #define LAUNCH_EXITSTATUS_FAIRPLAY_FAIL (INT64_MAX) 36 | 37 | #define LAUNCH_KEY_SETUSERENVIRONMENT "SetUserEnvironment" 38 | #define LAUNCH_KEY_UNSETUSERENVIRONMENT "UnsetUserEnvironment" 39 | #define LAUNCH_KEY_SHUTDOWN "Shutdown" 40 | #define LAUNCH_KEY_SINGLEUSER "SingleUser" 41 | #define LAUNCH_KEY_GETRESOURCELIMITS "GetResourceLimits" 42 | #define LAUNCH_KEY_SETRESOURCELIMITS "SetResourceLimits" 43 | #define LAUNCH_KEY_GETRUSAGESELF "GetResourceUsageSelf" 44 | #define LAUNCH_KEY_GETRUSAGECHILDREN "GetResourceUsageChildren" 45 | 46 | #define LAUNCHD_SOCKET_ENV "LAUNCHD_SOCKET" 47 | #define LAUNCHD_SOCK_PREFIX _PATH_VARTMP "launchd" 48 | #define LAUNCHD_TRUSTED_FD_ENV "__LAUNCHD_FD" 49 | #define LAUNCHD_ASYNC_MSG_KEY "_AsyncMessage" 50 | #define LAUNCH_KEY_BATCHCONTROL "BatchControl" 51 | #define LAUNCH_KEY_BATCHQUERY "BatchQuery" 52 | 53 | #define LAUNCH_JOBKEY_TRANSACTIONCOUNT "TransactionCount" 54 | #define LAUNCH_JOBKEY_QUARANTINEDATA "QuarantineData" 55 | #define LAUNCH_JOBKEY_SANDBOXPROFILE "SandboxProfile" 56 | #define LAUNCH_JOBKEY_SANDBOXFLAGS "SandboxFlags" 57 | #define LAUNCH_JOBKEY_SANDBOX_NAMED "Named" 58 | #define LAUNCH_JOBKEY_SANDBOXCONTAINER "SandboxContainer" 59 | #define LAUNCH_JOBKEY_JETSAMPROPERTIES "JetsamProperties" 60 | #define LAUNCH_JOBKEY_JETSAMPRIORITY "JetsamPriority" 61 | #define LAUNCH_JOBKEY_JETSAMMEMORYLIMIT "JetsamMemoryLimit" 62 | #define LAUNCH_JOBKEY_JETSAMMEMORYLIMITBACKGROUND "JetsamMemoryLimitBackground" 63 | #define LAUNCH_JOBKEY_SECURITYSESSIONUUID "SecuritySessionUUID" 64 | #define LAUNCH_JOBKEY_DISABLEASLR "DisableASLR" 65 | #define LAUNCH_JOBKEY_XPCDOMAIN "XPCDomain" 66 | #define LAUNCH_JOBKEY_POSIXSPAWNTYPE "POSIXSpawnType" 67 | 68 | #define LAUNCH_KEY_JETSAMLABEL "JetsamLabel" 69 | #define LAUNCH_KEY_JETSAMFRONTMOST "JetsamFrontmost" 70 | #define LAUNCH_KEY_JETSAMACTIVE "JetsamActive" 71 | #define LAUNCH_KEY_JETSAMPRIORITY LAUNCH_JOBKEY_JETSAMPRIORITY 72 | #define LAUNCH_KEY_JETSAMMEMORYLIMIT LAUNCH_JOBKEY_JETSAMMEMORYLIMIT 73 | 74 | #define LAUNCH_KEY_POSIXSPAWNTYPE_APP LAUNCH_KEY_PROCESSTYPE_APP 75 | #define LAUNCH_KEY_POSIXSPAWNTYPE_SYSTEMAPP "SystemApp" 76 | #define LAUNCH_KEY_POSIXSPAWNTYPE_STANDARD LAUNCH_KEY_PROCESSTYPE_STANDARD 77 | #define LAUNCH_KEY_POSIXSPAWNTYPE_BACKGROUND LAUNCH_KEY_PROCESSTYPE_BACKGROUND 78 | #define LAUNCH_KEY_POSIXSPAWNTYPE_INTERACTIVE LAUNCH_KEY_PROCESSTYPE_INTERACTIVE 79 | #define LAUNCH_KEY_POSIXSPAWNTYPE_ADAPTIVE LAUNCH_KEY_PROCESSTYPE_ADAPTIVE 80 | #define LAUNCH_KEY_POSIXSPAWNTYPE_TALAPP "TALApp" 81 | 82 | #define LAUNCH_JOBKEY_EMBEDDEDPRIVILEGEDISPENSATION "EmbeddedPrivilegeDispensation" 83 | #define LAUNCH_JOBKEY_EMBEDDEDHOMESCREEN "EmbeddedHomeScreen" 84 | #define LAUNCH_JOBKEY_EMBEDDEDMAINTHREADPRIORITY "EmbeddedMainThreadPriority" 85 | 86 | #define LAUNCH_JOBKEY_ENTERKERNELDEBUGGERBEFOREKILL "EnterKernelDebuggerBeforeKill" 87 | #define LAUNCH_JOBKEY_PERJOBMACHSERVICES "PerJobMachServices" 88 | #define LAUNCH_JOBKEY_SERVICEIPC "ServiceIPC" 89 | #define LAUNCH_JOBKEY_BINARYORDERPREFERENCE "BinaryOrderPreference" 90 | #define LAUNCH_JOBKEY_MACHEXCEPTIONHANDLER "MachExceptionHandler" 91 | #define LAUNCH_JOBKEY_MULTIPLEINSTANCES "MultipleInstances" 92 | #define LAUNCH_JOBKEY_EVENTMONITOR "EventMonitor" 93 | #define LAUNCH_JOBKEY_SHUTDOWNMONITOR "ShutdownMonitor" 94 | #define LAUNCH_JOBKEY_BEGINTRANSACTIONATSHUTDOWN "BeginTransactionAtShutdown" 95 | #define LAUNCH_JOBKEY_XPCDOMAINBOOTSTRAPPER "XPCDomainBootstrapper" 96 | #define LAUNCH_JOBKEY_ASID "AuditSessionID" 97 | #define LAUNCH_JOBKEY_JOINGUISESSION "JoinGUISession" 98 | 99 | #define LAUNCH_JOBKEY_MACH_KUNCSERVER "kUNCServer" 100 | #define LAUNCH_JOBKEY_MACH_EXCEPTIONSERVER "ExceptionServer" 101 | #define LAUNCH_JOBKEY_MACH_TASKSPECIALPORT "TaskSpecialPort" 102 | #define LAUNCH_JOBKEY_MACH_HOSTSPECIALPORT "HostSpecialPort" 103 | #define LAUNCH_JOBKEY_MACH_ENTERKERNELDEBUGGERONCLOSE "EnterKernelDebuggerOnClose" 104 | #define LAUNCH_JOBKEY_LOWPRIORITYBACKGROUNDIO "LowPriorityBackgroundIO" 105 | 106 | #define LAUNCH_ENV_INSTANCEID "LaunchInstanceID" 107 | 108 | #define JETSAM_PROPERTY_PRIORITY "Priority" 109 | #define JETSAM_PROPERTY_MEMORYLIMIT "MemoryLimitMB" 110 | 111 | /* For LoginWindow. 112 | * 113 | * After this call, the task's bootstrap port is set to the per session launchd. 114 | * 115 | * This returns 1 on success (it used to return otherwise), and -1 on failure. 116 | */ 117 | #define LOAD_ONLY_SAFEMODE_LAUNCHAGENTS (1 << 0) 118 | #define LAUNCH_GLOBAL_ON_DEMAND (1 << 1) 119 | pid_t 120 | create_and_switch_to_per_session_launchd(const char *, int flags, ...); 121 | 122 | /* Also for LoginWindow. 123 | * 124 | * This is will load jobs at the LoginWindow prompt. 125 | */ 126 | void 127 | load_launchd_jobs_at_loginwindow_prompt(int flags, ...); 128 | 129 | /* For CoreProcesses */ 130 | #define SPAWN_VIA_LAUNCHD_STOPPED 0x0001 131 | #define SPAWN_VIA_LAUNCHD_TALAPP 0x0002 132 | #define SPAWN_VIA_LAUNCHD_WIDGET 0x0004 133 | #define SPAWN_VIA_LAUNCHD_DISABLE_ASLR 0x0008 134 | 135 | struct spawn_via_launchd_attr { 136 | uint64_t spawn_flags; 137 | const char *spawn_path; 138 | const char *spawn_chdir; 139 | const char * const * spawn_env; 140 | const mode_t *spawn_umask; 141 | mach_port_t *spawn_observer_port; 142 | const cpu_type_t *spawn_binpref; 143 | size_t spawn_binpref_cnt; 144 | void * spawn_quarantine; 145 | const char *spawn_seatbelt_profile; 146 | const uint64_t *spawn_seatbelt_flags; 147 | }; 148 | 149 | #define spawn_via_launchd(a, b, c) _spawn_via_launchd(a, b, c, 3) 150 | pid_t 151 | _spawn_via_launchd(const char *label, const char * const *argv, 152 | const struct spawn_via_launchd_attr *spawn_attrs, int struct_version); 153 | 154 | int 155 | launch_wait(mach_port_t port); 156 | 157 | /* The mpm_*() APIs no longer do anything. */ 158 | kern_return_t 159 | mpm_wait(mach_port_t ajob, int *wstatus); 160 | 161 | kern_return_t 162 | mpm_uncork_fork(mach_port_t ajob); 163 | 164 | launch_data_t 165 | launch_socket_service_check_in(void); 166 | 167 | __END_DECLS 168 | 169 | #pragma GCC visibility pop 170 | 171 | 172 | #endif /* __LAUNCH_PRIVATE_H__ */ 173 | -------------------------------------------------------------------------------- /liblaunch/launchd.ops: -------------------------------------------------------------------------------- 1 | < mach* > 2 | mach-per-user-lookup 3 | -------------------------------------------------------------------------------- /liblaunch/libbootstrap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999-2005 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #include "config.h" 22 | #include "launch.h" 23 | #include "launch_priv.h" 24 | #include "bootstrap.h" 25 | #include "bootstrap_priv.h" 26 | #include "vproc.h" 27 | #include "vproc_priv.h" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "job.h" 38 | 39 | void 40 | bootstrap_init(void) 41 | { 42 | kern_return_t kr = task_get_special_port(task_self_trap(), TASK_BOOTSTRAP_PORT, &bootstrap_port); 43 | if (kr != KERN_SUCCESS) { 44 | abort(); 45 | } 46 | } 47 | 48 | kern_return_t 49 | bootstrap_create_server(mach_port_t bp, cmd_t server_cmd, uid_t server_uid, boolean_t on_demand, mach_port_t *server_port) 50 | { 51 | kern_return_t kr; 52 | 53 | kr = vproc_mig_create_server(bp, server_cmd, server_uid, on_demand, server_port); 54 | 55 | if (kr == VPROC_ERR_TRY_PER_USER) { 56 | mach_port_t puc; 57 | 58 | if (vproc_mig_lookup_per_user_context(bp, 0, &puc) == 0) { 59 | kr = vproc_mig_create_server(puc, server_cmd, server_uid, on_demand, server_port); 60 | mach_port_deallocate(mach_task_self(), puc); 61 | } 62 | } 63 | 64 | return kr; 65 | } 66 | 67 | kern_return_t 68 | bootstrap_subset(mach_port_t bp, mach_port_t requestor_port, mach_port_t *subset_port) 69 | { 70 | return vproc_mig_subset(bp, requestor_port, subset_port); 71 | } 72 | 73 | kern_return_t 74 | bootstrap_unprivileged(mach_port_t bp, mach_port_t *unpriv_port) 75 | { 76 | kern_return_t kr; 77 | 78 | *unpriv_port = MACH_PORT_NULL; 79 | 80 | kr = mach_port_mod_refs(mach_task_self(), bp, MACH_PORT_RIGHT_SEND, 1); 81 | 82 | if (kr == KERN_SUCCESS) { 83 | *unpriv_port = bp; 84 | } 85 | 86 | return kr; 87 | } 88 | 89 | kern_return_t 90 | bootstrap_parent(mach_port_t bp, mach_port_t *parent_port) 91 | { 92 | return vproc_mig_parent(bp, parent_port); 93 | } 94 | 95 | kern_return_t 96 | bootstrap_register(mach_port_t bp, name_t service_name, mach_port_t sp) 97 | { 98 | return bootstrap_register2(bp, service_name, sp, 0); 99 | } 100 | 101 | kern_return_t 102 | bootstrap_register2(mach_port_t bp, name_t service_name, mach_port_t sp, uint64_t flags) 103 | { 104 | kern_return_t kr = vproc_mig_register2(bp, service_name, sp, flags); 105 | 106 | if (kr == VPROC_ERR_TRY_PER_USER) { 107 | mach_port_t puc; 108 | 109 | if (vproc_mig_lookup_per_user_context(bp, 0, &puc) == 0) { 110 | kr = vproc_mig_register2(puc, service_name, sp, flags); 111 | mach_port_deallocate(mach_task_self(), puc); 112 | } 113 | } 114 | 115 | return kr; 116 | } 117 | 118 | kern_return_t 119 | bootstrap_create_service(mach_port_t bp, name_t service_name, mach_port_t *sp) 120 | { 121 | kern_return_t kr; 122 | 123 | if ((kr = bootstrap_check_in(bp, service_name, sp))) { 124 | return kr; 125 | } 126 | 127 | if ((kr = mach_port_mod_refs(mach_task_self(), *sp, MACH_PORT_RIGHT_RECEIVE, -1))) { 128 | return kr; 129 | } 130 | 131 | return bootstrap_look_up(bp, service_name, sp); 132 | } 133 | 134 | kern_return_t 135 | bootstrap_check_in(mach_port_t bp, const name_t service_name, mach_port_t *sp) 136 | { 137 | uuid_t junk; 138 | (void)bzero(junk, sizeof(junk)); 139 | return vproc_mig_check_in2(bp, (char *)service_name, sp, junk, 0); 140 | } 141 | 142 | kern_return_t 143 | bootstrap_check_in2(mach_port_t bp, const name_t service_name, mach_port_t *sp, uint64_t flags) 144 | { 145 | uuid_t junk; 146 | (void)bzero(junk, sizeof(junk)); 147 | return vproc_mig_check_in2(bp, (char *)service_name, sp, junk, flags); 148 | } 149 | 150 | kern_return_t 151 | bootstrap_look_up_per_user(mach_port_t bp, const name_t service_name, uid_t target_user, mach_port_t *sp) 152 | { 153 | audit_token_t au_tok; 154 | kern_return_t kr; 155 | mach_port_t puc; 156 | 157 | /* See rdar://problem/4890134. */ 158 | 159 | if ((kr = vproc_mig_lookup_per_user_context(bp, target_user, &puc)) != 0) { 160 | return kr; 161 | } 162 | 163 | if (!service_name) { 164 | *sp = puc; 165 | } else { 166 | uuid_t junk; 167 | kr = vproc_mig_look_up2(puc, (char *)service_name, sp, &au_tok, 0, junk, 0); 168 | mach_port_deallocate(mach_task_self(), puc); 169 | } 170 | 171 | return kr; 172 | } 173 | 174 | kern_return_t 175 | bootstrap_lookup_children(mach_port_t bp, mach_port_array_t *children, name_array_t *names, bootstrap_property_array_t *properties, mach_msg_type_number_t *n_children) 176 | { 177 | mach_msg_type_number_t junk = 0; 178 | return vproc_mig_lookup_children(bp, children, &junk, names, n_children, properties, &junk); 179 | } 180 | 181 | kern_return_t 182 | bootstrap_look_up(mach_port_t bp, const name_t service_name, mach_port_t *sp) 183 | { 184 | return bootstrap_look_up2(bp, service_name, sp, 0, 0); 185 | } 186 | 187 | kern_return_t 188 | bootstrap_look_up2(mach_port_t bp, const name_t service_name, mach_port_t *sp, pid_t target_pid, uint64_t flags) 189 | { 190 | uuid_t instance_id; 191 | return bootstrap_look_up3(bp, service_name, sp, target_pid, instance_id, flags); 192 | } 193 | 194 | kern_return_t 195 | bootstrap_look_up3(mach_port_t bp, const name_t service_name, mach_port_t *sp, pid_t target_pid, const uuid_t instance_id, uint64_t flags) 196 | { 197 | audit_token_t au_tok; 198 | bool privileged_server_lookup = flags & BOOTSTRAP_PRIVILEGED_SERVER; 199 | kern_return_t kr = 0; 200 | mach_port_t puc; 201 | 202 | // We have to cast instance_id here because the MIG-generated method 203 | // doesn't expect a const parameter. 204 | if ((kr = vproc_mig_look_up2(bp, (char *)service_name, sp, &au_tok, target_pid, (unsigned char*)instance_id, flags)) != VPROC_ERR_TRY_PER_USER) { 205 | goto out; 206 | } 207 | 208 | if ((kr = vproc_mig_lookup_per_user_context(bp, 0, &puc)) != 0) { 209 | goto out; 210 | } 211 | 212 | kr = vproc_mig_look_up2(puc, (char *)service_name, sp, &au_tok, target_pid, (unsigned char*)instance_id, flags); 213 | mach_port_deallocate(mach_task_self(), puc); 214 | 215 | out: 216 | if ((kr == 0) && privileged_server_lookup) { 217 | uid_t server_euid; 218 | 219 | /* 220 | * The audit token magic is dependent on the per-user launchd 221 | * forwarding MIG requests to the root launchd when it cannot 222 | * find the answer locally. 223 | */ 224 | 225 | /* This API should be in Libsystem, but is not */ 226 | //audit_token_to_au32(au_tok, NULL, &server_euid, NULL, NULL, NULL, NULL, NULL, NULL); 227 | 228 | server_euid = au_tok.val[1]; 229 | 230 | if (server_euid) { 231 | mach_port_deallocate(mach_task_self(), *sp); 232 | *sp = MACH_PORT_NULL; 233 | kr = BOOTSTRAP_NOT_PRIVILEGED; 234 | } 235 | } 236 | 237 | return kr; 238 | } 239 | 240 | kern_return_t 241 | bootstrap_check_in3(mach_port_t bp, const name_t service_name, mach_port_t *sp, uuid_t instance_id, uint64_t flags) 242 | { 243 | return vproc_mig_check_in2(bp, (char *)service_name, sp, instance_id, flags); 244 | } 245 | 246 | kern_return_t 247 | bootstrap_get_root(mach_port_t bp, mach_port_t *root) 248 | { 249 | return vproc_mig_get_root_bootstrap(bp, root); 250 | } 251 | 252 | kern_return_t 253 | bootstrap_status(mach_port_t bp, name_t service_name, bootstrap_status_t *service_active) 254 | { 255 | kern_return_t kr; 256 | mach_port_t p; 257 | 258 | if ((kr = bootstrap_look_up(bp, service_name, &p))) { 259 | return kr; 260 | } 261 | 262 | mach_port_deallocate(mach_task_self(), p); 263 | *service_active = BOOTSTRAP_STATUS_ACTIVE; 264 | 265 | if (bootstrap_check_in(bp, service_name, &p) == BOOTSTRAP_SUCCESS) { 266 | mach_port_mod_refs(mach_task_self(), p, MACH_PORT_RIGHT_RECEIVE, -1); 267 | *service_active = BOOTSTRAP_STATUS_ON_DEMAND; 268 | } 269 | 270 | return BOOTSTRAP_SUCCESS; 271 | } 272 | 273 | kern_return_t 274 | bootstrap_info(mach_port_t bp, 275 | name_array_t *service_names, mach_msg_type_number_t *service_namesCnt, 276 | name_array_t *service_jobs, mach_msg_type_number_t *service_jobsCnt, 277 | bootstrap_status_array_t *service_active, mach_msg_type_number_t *service_activeCnt, 278 | uint64_t flags) 279 | { 280 | return vproc_mig_info(bp, service_names, service_namesCnt, service_jobs, service_jobsCnt, service_active, service_activeCnt, flags); 281 | } 282 | 283 | const char * 284 | bootstrap_strerror(kern_return_t r) 285 | { 286 | switch (r) { 287 | case BOOTSTRAP_SUCCESS: 288 | return "Success"; 289 | case BOOTSTRAP_NOT_PRIVILEGED: 290 | return "Permission denied"; 291 | case BOOTSTRAP_NAME_IN_USE: 292 | case BOOTSTRAP_SERVICE_ACTIVE: 293 | return "Service name already exists"; 294 | case BOOTSTRAP_UNKNOWN_SERVICE: 295 | return "Unknown service name"; 296 | case BOOTSTRAP_BAD_COUNT: 297 | return "Too many lookups were requested in one request"; 298 | case BOOTSTRAP_NO_MEMORY: 299 | return "Out of memory"; 300 | default: 301 | return mach_error_string(r); 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /liblaunch/reboot2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #ifndef __REBOOT2_H__ 22 | #define __REBOOT2_H__ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | __BEGIN_DECLS 29 | 30 | #define RB2_FULLREBOOT 0x8000000000000000llu 31 | 32 | /* Returns NULL on success. Not NULL on failure */ 33 | 34 | __attribute__((visibility("default"))) 35 | void *reboot2(uint64_t flags); 36 | 37 | __END_DECLS 38 | 39 | #endif /* __REBOOT2_H__ */ 40 | -------------------------------------------------------------------------------- /liblaunch/vproc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #ifndef __VPROC_H__ 22 | #define __VPROC_H__ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #ifndef VPROC_HAS_TRANSACTIONS 29 | #define VPROC_HAS_TRANSACTIONS 30 | #endif 31 | 32 | __BEGIN_DECLS 33 | 34 | #pragma GCC visibility push(default) 35 | 36 | typedef void * vproc_err_t; 37 | 38 | typedef struct vproc_s * vproc_t; 39 | typedef void * vprocmgr_t; 40 | 41 | const char *vproc_strerror(vproc_err_t r); 42 | 43 | /*! 44 | * @header vproc 45 | * 46 | * Processes have two reference counts associated with them: 47 | * 48 | * Transactions Tracks unfinished work. For example: saving a modified 49 | * document. 50 | * Standby Tracks outstanding callbacks from external subsystems. 51 | * 52 | * Descriptive aliases: 53 | * 54 | * A process with no outstanding transactions is called "clean." 55 | * A process with outstanding transactions is called "dirty." 56 | * A process with no standby work is called "idle." 57 | * 58 | * Sometimes, the operating system needs processes to exit. Unix has two 59 | * primary signals to kill applications: 60 | * 61 | * SIGKILL Not catchable by the application. 62 | * SIGTERM Catchable by the application. 63 | * 64 | * If a process is clean, the operating system is free to SIGKILL it at 65 | * shutdown or logout. This behavior is opt in. 66 | * 67 | * If a process is clean and idle, the operating system may send SIGKILL after 68 | * a application specified timeout. This behavior is opt in. 69 | * 70 | * If a process is dirty and idle, the operating system may send SIGTERM after 71 | * a application specified timeout. This behavior is opt in. 72 | * 73 | * 74 | * launchd jobs should update their property lists accordingly. 75 | * 76 | * We plan to have LaunchServices use private methods to coordinate 77 | * whether GUI applications have opted into this design. 78 | */ 79 | 80 | /*! 81 | * @typedef vproc_transaction_t 82 | * 83 | * @abstract 84 | * An opaque handle used to track outstanding transactions. 85 | */ 86 | typedef struct vproc_transaction_s *vproc_transaction_t; 87 | 88 | /*! 89 | * @function vproc_transaction_begin 90 | * 91 | * @param virtual_proc 92 | * This is meant for future API improvements. Pass NULL for now. 93 | * 94 | * @result 95 | * Returns an opaque handle to be passed to vproc_transaction_end(). 96 | * 97 | * @abstract 98 | * Call this API before creating data that needs to be saved via I/O later. 99 | */ 100 | vproc_transaction_t 101 | vproc_transaction_begin(vproc_t virtual_proc) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0); 102 | 103 | /*! 104 | * @function vproc_transaction_end 105 | * 106 | * @param virtual_proc 107 | * This is meant for future API improvements. Pass NULL for now. 108 | * 109 | * @param handle 110 | * The handle previously created with vproc_transaction_begin(). 111 | * 112 | * @abstract 113 | * Call this API after the data has either been flushed or otherwise resolved. 114 | * 115 | * @discussion 116 | * Calling this API with the same handle more than once is undefined. 117 | */ 118 | void 119 | vproc_transaction_end(vproc_t virtual_proc, vproc_transaction_t handle) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0); 120 | 121 | /*! 122 | * @typedef vproc_standby_t 123 | * 124 | * @abstract 125 | * An opaque handle used to track outstanding standby requests. 126 | */ 127 | typedef struct vproc_standby_s *vproc_standby_t; 128 | 129 | /*! 130 | * @function vproc_standby_begin 131 | * 132 | * @param virtual_proc 133 | * This is meant for future API improvements. Pass NULL for now. 134 | * 135 | * @result 136 | * Returns an opaque handle to be passed to vproc_standby_end(). 137 | * 138 | * @abstract 139 | * Call this API before registering notifications. For example: timers network 140 | * state change, or when monitoring keyboard/mouse events. 141 | * 142 | * @discussion 143 | * This API is undefined and is currently a no-op. 144 | */ 145 | vproc_standby_t 146 | vproc_standby_begin(vproc_t virtual_proc) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_NA); 147 | 148 | /*! 149 | * @function vproc_standby_end 150 | * 151 | * @param virtual_proc 152 | * This is meant for future API improvements. Pass NULL for now. 153 | * 154 | * @param handle 155 | * The handle previously created with vproc_standby_begin(). 156 | * 157 | * @abstract 158 | * Call this API when deregistering notifications. 159 | * 160 | * @discussion 161 | * Calling this API with the same handle more than once is undefined. 162 | * This API is undefined and is currently a no-op. 163 | */ 164 | void 165 | vproc_standby_end(vproc_t virtual_proc, vproc_standby_t handle) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_NA); 166 | 167 | #pragma GCC visibility pop 168 | 169 | __END_DECLS 170 | 171 | #endif /* __VPROC_H__ */ 172 | -------------------------------------------------------------------------------- /liblaunch/vproc_internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2007 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #ifndef __VPROC_INTERNAL_H__ 22 | #define __VPROC_INTERNAL_H__ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "launch.h" 31 | #include "bootstrap_priv.h" 32 | #include "vproc.h" 33 | 34 | typedef char * _internal_string_t; 35 | typedef char * logmsg_t; 36 | typedef pid_t * pid_array_t; 37 | typedef mach_port_t vproc_mig_t; 38 | 39 | #if defined(job_MSG_COUNT) || defined (xpc_domain_MSG_COUNT) 40 | /* HACK */ 41 | #include "core.h" 42 | #endif 43 | 44 | #define VPROC_ERR_TRY_PER_USER 1099 45 | 46 | #pragma GCC visibility push(default) 47 | 48 | vproc_err_t _vprocmgr_init(const char *session_type); 49 | vproc_err_t _vproc_post_fork_ping(void); 50 | 51 | #if !TARGET_OS_EMBEDDED 52 | #define _audit_session_self(v) (mach_port_t)syscall(SYS_audit_session_self) 53 | #define _audit_session_join(s) (au_asid_t)syscall(SYS_audit_session_join, session) 54 | #else 55 | #define _audit_session_self(v) MACH_PORT_NULL 56 | #define _audit_session_join(s) 0 57 | #endif 58 | 59 | #define __LAUNCH_MACH_PORT_CONTEXT_T_DEFINED__ 0 60 | 61 | #define SPAWN_HAS_PATH 0x0001 62 | #define SPAWN_HAS_WDIR 0x0002 63 | #define SPAWN_HAS_UMASK 0x0004 64 | #define SPAWN_WANTS_WAIT4DEBUGGER 0x0008 65 | 66 | kern_return_t 67 | _vproc_grab_subset(mach_port_t bp, mach_port_t *reqport, mach_port_t *rcvright, launch_data_t *outval, 68 | mach_port_array_t *ports, mach_msg_type_number_t *portCnt); 69 | 70 | kern_return_t _vprocmgr_getsocket(name_t); 71 | 72 | struct logmsg_s { 73 | union { 74 | STAILQ_ENTRY(logmsg_s) sqe; 75 | uint64_t __pad; 76 | }; 77 | int64_t when; 78 | pid_t from_pid; 79 | pid_t about_pid; 80 | uid_t sender_uid; 81 | gid_t sender_gid; 82 | int err_num; 83 | int pri; 84 | union { 85 | const char *from_name; 86 | uint64_t from_name_offset; 87 | }; 88 | union { 89 | const char *about_name; 90 | uint64_t about_name_offset; 91 | }; 92 | union { 93 | const char *session_name; 94 | uint64_t session_name_offset; 95 | }; 96 | union { 97 | const char *msg; 98 | uint64_t msg_offset; 99 | }; 100 | uint64_t obj_sz; 101 | char data[0]; 102 | }; 103 | 104 | 105 | vproc_err_t _vprocmgr_log_forward(mach_port_t mp, void *data, size_t len); 106 | 107 | kern_return_t 108 | bootstrap_info(mach_port_t bp, 109 | name_array_t *service_names, 110 | mach_msg_type_number_t *service_namesCnt, 111 | name_array_t *service_jobs, 112 | mach_msg_type_number_t *service_jobsCnt, 113 | bootstrap_status_array_t *service_active, 114 | mach_msg_type_number_t *service_activeCnt, 115 | uint64_t flags); 116 | 117 | #pragma GCC visibility pop 118 | 119 | #endif /* __VPROC_INTERNAL_H__ */ 120 | -------------------------------------------------------------------------------- /liblaunch/vproc_priv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2012 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #ifndef __VPROC_PRIVATE_H__ 22 | #define __VPROC_PRIVATE_H__ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #ifndef VPROC_HAS_TRANSACTIONS 37 | #define VPROC_HAS_TRANSACTIONS 1 38 | #endif 39 | 40 | __BEGIN_DECLS 41 | 42 | #define VPROCMGR_SESSION_LOGINWINDOW "LoginWindow" 43 | #define VPROCMGR_SESSION_BACKGROUND "Background" 44 | #define VPROCMGR_SESSION_AQUA "Aqua" 45 | #define VPROCMGR_SESSION_STANDARDIO "StandardIO" 46 | #define VPROCMGR_SESSION_SYSTEM "System" 47 | 48 | #define XPC_DOMAIN_TYPE_SYSTEM "XPCSystem" 49 | #define XPC_DOMAIN_TYPE_PERUSER "XPCPerUser" 50 | #define XPC_DOMAIN_TYPE_PERSESSION "XPCPerSession" 51 | #define XPC_DOMAIN_TYPE_PERAPPLICATION "XPCPerApplication" 52 | 53 | #pragma GCC visibility push(default) 54 | 55 | /* DO NOT use this. This is a hack for 'launchctl' */ 56 | #define VPROC_MAGIC_UNLOAD_SIGNAL 0x4141504C 57 | 58 | typedef void (*_vproc_transaction_callout)(void *); 59 | 60 | typedef enum { 61 | VPROC_GSK_ZERO, 62 | VPROC_GSK_LAST_EXIT_STATUS, 63 | VPROC_GSK_GLOBAL_ON_DEMAND, 64 | VPROC_GSK_MGR_UID, 65 | VPROC_GSK_MGR_PID, 66 | VPROC_GSK_IS_MANAGED, 67 | VPROC_GSK_MGR_NAME, 68 | VPROC_GSK_BASIC_KEEPALIVE, 69 | VPROC_GSK_START_INTERVAL, 70 | VPROC_GSK_IDLE_TIMEOUT, 71 | VPROC_GSK_EXIT_TIMEOUT, 72 | VPROC_GSK_ENVIRONMENT, 73 | VPROC_GSK_ALLJOBS, 74 | VPROC_GSK_GLOBAL_LOG_MASK, 75 | VPROC_GSK_GLOBAL_UMASK, 76 | VPROC_GSK_ABANDON_PROCESS_GROUP, 77 | VPROC_GSK_TRANSACTIONS_ENABLED, 78 | VPROC_GSK_WEIRD_BOOTSTRAP, 79 | VPROC_GSK_WAITFORDEBUGGER, 80 | VPROC_GSK_SECURITYSESSION, 81 | VPROC_GSK_SHUTDOWN_DEBUGGING, 82 | VPROC_GSK_VERBOSE_BOOT, 83 | VPROC_GSK_PERUSER_SUSPEND, 84 | VPROC_GSK_PERUSER_RESUME, 85 | VPROC_GSK_JOB_OVERRIDES_DB, 86 | VPROC_GSK_JOB_CACHE_DB, 87 | VPROC_GSK_EMBEDDEDROOTEQUIVALENT, 88 | } vproc_gsk_t; 89 | 90 | typedef unsigned int vproc_flags_t; 91 | /* For _vproc_kickstart_by_label() -- instructs launchd to kickstart the job to stall before exec(2). */ 92 | #define VPROCFLAG_STALL_JOB_EXEC 1 << 1 93 | 94 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0) 95 | vproc_t 96 | vprocmgr_lookup_vproc(const char *label); 97 | 98 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0) 99 | vproc_t 100 | vproc_retain(vproc_t vp); 101 | 102 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0) 103 | void 104 | vproc_release(vproc_t vp); 105 | 106 | __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_3_0) 107 | vproc_err_t 108 | vproc_swap_integer(vproc_t vp, vproc_gsk_t key, 109 | int64_t *inval, int64_t *outval); 110 | 111 | __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_3_0) 112 | vproc_err_t 113 | vproc_swap_complex(vproc_t vp, vproc_gsk_t key, 114 | launch_data_t inval, launch_data_t *outval); 115 | 116 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_4_0) 117 | vproc_err_t 118 | vproc_swap_string(vproc_t vp, vproc_gsk_t key, 119 | const char *instr, char **outstr); 120 | 121 | __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) 122 | vproc_err_t 123 | _vproc_get_last_exit_status(int *wstatus); 124 | 125 | __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_3_0) 126 | vproc_err_t 127 | _vproc_set_global_on_demand(bool val); 128 | 129 | __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_3_0) 130 | vproc_err_t 131 | _vproc_send_signal_by_label(const char *label, int sig); 132 | 133 | __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_3_0) 134 | vproc_err_t 135 | _vproc_kickstart_by_label(const char *label, pid_t *out_pid, 136 | mach_port_t *out_port_name, mach_port_t *out_obsrvr_port, 137 | vproc_flags_t flags); 138 | 139 | /* _vprocmgr_log_drain() is specific to syslogd. It is not for general use. */ 140 | typedef void (*_vprocmgr_log_drain_callback_t)(struct timeval *when, pid_t 141 | from_pid, pid_t about_pid, uid_t sender_uid, gid_t sender_gid, int priority, 142 | const char *from_name, const char *about_name, const char *session_name, 143 | const char *msg); 144 | 145 | vproc_err_t 146 | _vprocmgr_log_drain(vproc_t vp, pthread_mutex_t *optional_mutex_around_callback, 147 | _vprocmgr_log_drain_callback_t func); 148 | 149 | __attribute__((format(printf, 2, 3))) 150 | void 151 | _vproc_log(int pri, const char *msg, ...); 152 | 153 | __attribute__((format(printf, 2, 3))) 154 | void 155 | _vproc_log_error(int pri, const char *msg, ...); 156 | 157 | __attribute__((format(printf, 3, 0))) 158 | void 159 | _vproc_logv(int pri, int err, const char *msg, va_list ap); 160 | 161 | /* One day, we'll be able to get rid of this... */ 162 | vproc_err_t 163 | _vprocmgr_move_subset_to_user(uid_t target_user, const char *session_type, 164 | uint64_t flags); 165 | 166 | vproc_err_t 167 | _vprocmgr_switch_to_session(const char *target_session, vproc_flags_t flags); 168 | 169 | vproc_err_t 170 | _vprocmgr_detach_from_console(vproc_flags_t flags); 171 | 172 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA) 173 | void 174 | _vproc_standby_begin(void); 175 | 176 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA) 177 | void 178 | _vproc_standby_end(void); 179 | 180 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA) 181 | size_t 182 | _vproc_standby_count(void); 183 | 184 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA) 185 | size_t 186 | _vproc_standby_timeout(void); 187 | 188 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA) 189 | kern_return_t 190 | _vproc_transaction_count_for_pid(pid_t p, int32_t *count, bool *condemned); 191 | 192 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA) 193 | bool 194 | _vproc_pid_is_managed(pid_t p); 195 | 196 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA) 197 | void 198 | _vproc_transaction_try_exit(int status); 199 | 200 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0) 201 | void 202 | _vproc_transaction_begin(void); 203 | 204 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0) 205 | void 206 | _vproc_transaction_end(void); 207 | 208 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_NA) 209 | size_t 210 | _vproc_transaction_count(void); 211 | 212 | void 213 | _vproc_transaction_set_clean_callback(dispatch_queue_t targetq, void *ctx, 214 | dispatch_function_t func); 215 | 216 | void 217 | _vproc_transactions_enable(void); 218 | 219 | #pragma GCC visibility pop 220 | 221 | __END_DECLS 222 | 223 | #endif /* __VPROC_PRIVATE_H__ */ 224 | -------------------------------------------------------------------------------- /man/launchctl.1: -------------------------------------------------------------------------------- 1 | .Dd 1 May, 2009 2 | .Dt launchctl 1 3 | .Os Darwin 4 | .Sh NAME 5 | .Nm launchctl 6 | .Nd Interfaces with launchd 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Ar subcommand Op Ar arguments ... 10 | .Sh DESCRIPTION 11 | .Nm 12 | interfaces with 13 | .Nm launchd 14 | to load, unload daemons/agents and generally control 15 | .Nm launchd . 16 | .Nm 17 | supports taking subcommands on the command line, interactively or even redirected from standard input. 18 | These commands can be stored in 19 | .Nm $HOME/.launchd.conf 20 | or 21 | .Nm /etc/launchd.conf 22 | to be read at the time 23 | .Nm launchd 24 | starts. 25 | .Sh SUBCOMMANDS 26 | .Bl -tag -width -indent 27 | .It Xo Ar load Op Fl wF 28 | .Op Fl S Ar sessiontype 29 | .Op Fl D Ar domain 30 | .Ar paths ... 31 | .Xc 32 | Load the specified configuration files or directories of configuration files. 33 | Jobs that are not on-demand will be started as soon as possible. 34 | All specified jobs will be loaded before any of them are allowed to start. 35 | Note that per-user configuration files (LaunchAgents) must be owned by the user 36 | loading them. All system-wide daemons (LaunchDaemons) must be owned by root. Configuration files 37 | must not be group- or world-writable. These restrictions are in place for security reasons, 38 | as allowing writability to a launchd configuration file allows one to specify which executable 39 | will be launched. 40 | .Pp 41 | Note that allowing non-root write access to the /System/Library/LaunchDaemons directory WILL render your system unbootable. 42 | .Bl -tag -width -indent 43 | .It Fl w 44 | Overrides the Disabled key and sets it to false. In previous versions, this option 45 | would modify the configuration file. Now the state of the Disabled key is stored 46 | elsewhere on-disk. 47 | .It Fl F 48 | Force the loading of the plist. Ignore the Disabled key. 49 | .It Fl S Ar sessiontype 50 | Some jobs only make sense in certain contexts. This flag instructs 51 | .Nm launchctl 52 | to look for jobs in a different location when using the -D flag, and allows 53 | .Nm launchctl 54 | to restrict which jobs are loaded into which session types. Currently known 55 | session types include: Aqua, LoginWindow, Background, StandardIO and System. 56 | .It Fl D Ar domain 57 | Look for 58 | .Xr plist 5 files ending in *.plist in the domain given. Valid domains include 59 | "system," "local," "network" and "all." When providing a session type, an additional 60 | domain is available for use called "user." For example, without a session type given, 61 | "-D system" would load from property list files from /System/Library/LaunchDaemons. 62 | With a session type passed, it would load from /System/Library/LaunchAgents. 63 | .El 64 | .It Xo Ar unload Op Fl w 65 | .Op Fl S Ar sessiontype 66 | .Op Fl D Ar domain 67 | .Ar paths ... 68 | .Xc 69 | Unload the specified configuration files or directories of configuration files. 70 | This will also stop the job if it is running. 71 | .Bl -tag -width -indent 72 | .It Fl w 73 | Overrides the Disabled key and sets it to true. In previous versions, this option 74 | would modify the configuration file. Now the state of the Disabled key is stored 75 | elsewhere on-disk. 76 | .It Fl S Ar sessiontype 77 | Some jobs only make sense in certain contexts. This flag instructs 78 | .Nm launchctl 79 | to look for jobs in a different location when using the -D flag, and allows 80 | .Nm launchctl 81 | to restrict which jobs are loaded into which session types. Currently known 82 | session types include: Aqua, LoginWindow, Background, StandardIO and System. 83 | .It Fl D Ar domain 84 | Look for 85 | .Xr plist 5 files ending in *.plist in the domain given. Valid domains include 86 | "system," "local," "network" and "all." When providing a session type, an additional 87 | domain is available for use called "user." For example, without a session type given, 88 | "-D system" would load from property list files from /System/Library/LaunchDaemons. 89 | With a session type passed, it would load from /System/Library/LaunchAgents. 90 | .El 91 | .It Xo Ar submit Fl l Ar label 92 | .Op Fl p Ar executable 93 | .Op Fl o Ar path 94 | .Op Fl e Ar path 95 | .Ar -- command 96 | .Op Ar args 97 | .Xc 98 | A simple way of submitting a program to run without a configuration file. This mechanism also tells launchd to keep the program alive in the event of failure. 99 | .Bl -tag -width -indent 100 | .It Fl l Ar label 101 | What unique label to assign this job to launchd. 102 | .It Fl p Ar program 103 | What program to really execute, regardless of what follows the -- in the submit sub-command. 104 | .It Fl o Ar path 105 | Where to send the stdout of the program. 106 | .It Fl e Ar path 107 | Where to send the stderr of the program. 108 | .El 109 | .It Ar remove Ar job_label 110 | Remove the job from launchd by label. 111 | .It Ar start Ar job_label 112 | Start the specified job by label. The expected use of this subcommand is for 113 | debugging and testing so that one can manually kick-start an on-demand server. 114 | .It Ar stop Ar job_label 115 | Stop the specified job by label. If a job is on-demand, launchd may immediately 116 | restart the job if launchd finds any criteria that is satisfied. 117 | Non-demand based jobs will always be restarted. Use of this subcommand is discouraged. 118 | Jobs should ideally idle timeout by themselves. 119 | .It Xo Ar list 120 | .Op Ar -x 121 | .Op Ar label 122 | .Xc 123 | With no arguments, list all of the jobs loaded into 124 | .Nm launchd 125 | in three columns. The first column displays the PID of the job if it is running. 126 | The second column displays the last exit status of the job. If the number in this 127 | column is negative, it represents the negative of the signal which killed the job. 128 | Thus, "-15" would indicate that the job was terminated with SIGTERM. The third column 129 | is the job's label. 130 | .Pp 131 | Note that you may see some jobs in the list whose labels are in the style "0xdeadbeef.anonymous.program". 132 | These are jobs which are not managed by 133 | .Nm launchd , 134 | but, at one point, made a request to it. 135 | .Nm launchd 136 | claims no ownership and makes no guarantees regarding these jobs. They are stored purely for 137 | bookkeeping purposes. 138 | .Pp 139 | Similarly, you may see labels of the style "0xdeadbeef.mach_init.program". These are legacy jobs that run 140 | under mach_init emulation. This mechanism will be removed in future versions, and all remaining mach_init 141 | jobs should be converted over to 142 | .Nm launchd . 143 | .Pp 144 | If 145 | .Op Ar label 146 | is specified, prints information about the requested job. If 147 | .Op Ar -x 148 | is specified, the information for the specified job is output as an XML property list. 149 | .It Ar setenv Ar key Ar value 150 | Set an environmental variable inside of 151 | .Nm launchd . 152 | .It Ar unsetenv Ar key 153 | Unset an environmental variable inside of 154 | .Nm launchd . 155 | .It Ar getenv Ar key 156 | Get an environmental variable inside of 157 | .Nm launchd . 158 | .It Ar export 159 | Export all of the environmental variables of 160 | .Nm launchd 161 | for use in a shell eval statement. 162 | .It Ar getrusage self | children 163 | Get the resource utilization statistics for 164 | .Nm launchd 165 | or the children of 166 | .Nm launchd . 167 | .It Xo Ar log 168 | .Op Ar level loglevel 169 | .Op Ar only | mask loglevels... 170 | .Xc 171 | Get and set the 172 | .Xr syslog 3 173 | log level mask. The available log levels are: debug, info, notice, warning, error, critical, alert and emergency. 174 | .It Xo Ar limit 175 | .Op Ar cpu | filesize | data | stack | core | rss | memlock | maxproc | maxfiles 176 | .Op Ar both Op Ar soft | hard 177 | .Xc 178 | With no arguments, this command prints all the resource limits of 179 | .Nm launchd 180 | as found via 181 | .Xr getrlimit 2 . 182 | When a given resource is specified, it prints the limits for that resource. 183 | With a third argument, it sets both the hard and soft limits to that value. 184 | With four arguments, the third and forth argument represent the soft and hard limits respectively. 185 | See 186 | .Xr setrlimit 2 . 187 | .It Ar shutdown 188 | Tell 189 | .Nm launchd 190 | to prepare for shutdown by removing all jobs. 191 | .It Ar umask Op Ar newmask 192 | Get or optionally set the 193 | .Xr umask 2 194 | of 195 | .Nm launchd . 196 | .It Xo Ar bslist 197 | .Op Ar PID | .. 198 | .Op Ar -j 199 | .Xc 200 | This prints out Mach bootstrap services and their respective states. While the 201 | namespace appears flat, it is in fact hierarchical, thus allowing for certain 202 | services to be only available to a subset of processes. The three states a 203 | service can be in are active ("A"), inactive ("I") and on-demand ("D"). 204 | .Pp 205 | If 206 | .Op Ar PID 207 | is specified, print the Mach bootstrap services available to that PID. If 208 | .Op Ar .. 209 | is specified, print the Mach bootstrap services available in the parent of the 210 | current bootstrap. Note that in Mac OS X v10.6, the per-user Mach bootstrap namespace 211 | is flat, so you will only see a different set of services in a per-user bootstrap 212 | if you are in an explicitly-created bootstrap subset. 213 | .Pp 214 | If 215 | .Op Ar -j 216 | is specified, each service name will be followed by the name of the job which registered 217 | it. 218 | .It Ar bsexec Ar PID command Op Ar args 219 | This executes the given command in the same Mach bootstrap namespace hierachy 220 | as the given PID. 221 | .It Ar bstree Op Ar -j 222 | This prints a hierarchical view of the entire Mach bootstrap tree. If 223 | .Op Ar -j 224 | is specified, each service name will be followed by the name of the job which registered it. 225 | Requires root 226 | privileges. 227 | .It Ar managerpid 228 | This prints the PID of the launchd which manages the current bootstrap. 229 | .It Ar manageruid 230 | This prints the UID of the launchd which manages the current bootstrap. 231 | .It Ar managername 232 | This prints the name of the launchd job manager which manages the current bootstrap. 233 | See LimitLoadToSessionType in 234 | .Xr launchd.plist 5 235 | for more details. 236 | .It Ar help 237 | Print out a quick usage statement. 238 | .El 239 | .Sh ENVIRONMENTAL VARIABLES 240 | .Bl -tag -width -indent 241 | .It Pa LAUNCHD_SOCKET 242 | This variable informs launchctl how to find the correct launchd to talk to. If it is missing, launchctl will use a built-in default. 243 | .El 244 | .Sh FILES 245 | .Bl -tag -width "/System/Library/LaunchDaemons" -compact 246 | .It Pa ~/Library/LaunchAgents 247 | Per-user agents provided by the user. 248 | .It Pa /Library/LaunchAgents 249 | Per-user agents provided by the administrator. 250 | .It Pa /Library/LaunchDaemons 251 | System wide daemons provided by the administrator. 252 | .It Pa /System/Library/LaunchAgents 253 | Mac OS X Per-user agents. 254 | .It Pa /System/Library/LaunchDaemons 255 | Mac OS X System wide daemons. 256 | .El 257 | .Sh SEE ALSO 258 | .Xr launchd.plist 5 , 259 | .Xr launchd.conf 5 , 260 | .Xr launchd 8 261 | -------------------------------------------------------------------------------- /man/launchd.8: -------------------------------------------------------------------------------- 1 | .Dd 1 May, 2009 2 | .Dt launchd 8 3 | .Os Darwin 4 | .Sh NAME 5 | .Nm launchd 6 | .Nd System wide and per-user daemon/agent manager 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl d 10 | .Op Fl D 11 | .Op Fl s 12 | .Op Fl S Ar SessionType 13 | .Op Ar -- command Op Ar args ... 14 | .Sh DESCRIPTION 15 | .Nm 16 | manages processes, both for the system as a whole and for individual users. 17 | The primary and preferred interface to 18 | .Nm 19 | is via the 20 | .Xr launchctl 1 21 | tool which (among other options) allows the user or administrator to load and unload jobs. 22 | Where possible, it is preferable for jobs to launch on demand based on criteria specified 23 | in their respective configuration files. 24 | .Pp 25 | During boot 26 | .Nm 27 | is invoked by the kernel to run as the first process on the system and to further bootstrap the rest of the system. 28 | .Pp 29 | You cannot invoke 30 | .Nm 31 | directly. 32 | .Sh ENVIRONMENTAL VARIABLES 33 | .Bl -tag -width -indent 34 | .It Pa LAUNCHD_SOCKET 35 | This variable is exported when invoking a command via the launchd command line. It informs launchctl how to find the correct launchd to talk to. 36 | .El 37 | .Sh NOTES 38 | In Darwin, the canonical way to launch a daemon is through 39 | .Nm launchd 40 | as opposed to more traditional mechanisms or mechanisms provided in earlier versions of Mac OS X. These alternate methods should 41 | be considered deprecated and not suitable for new projects. 42 | .Pp 43 | In the 44 | .Nm launchd 45 | lexicon, a "daemon" is, by definition, a system-wide service of which there is one instance for all clients. An "agent" is a service that runs on 46 | a per-user basis. Daemons should not attempt to display UI or interact directly with a user's login session. Any and all work that involves interacting 47 | with a user should be done through agents. 48 | .Pp 49 | If you wish your service to run as a certain user, in that user's environment, making it a 50 | .Nm launchd 51 | agent is the ONLY supported means of accomplishing this on Mac OS X. In other words, it is not sufficient to perform a 52 | .Xr setuid 2 53 | to become a user in the truest sense on Mac OS X. 54 | .Sh FILES 55 | .Bl -tag -width "/System/Library/LaunchDaemons" -compact 56 | .It Pa ~/Library/LaunchAgents 57 | Per-user agents provided by the user. 58 | .It Pa /Library/LaunchAgents 59 | Per-user agents provided by the administrator. 60 | .It Pa /Library/LaunchDaemons 61 | System-wide daemons provided by the administrator. 62 | .It Pa /System/Library/LaunchAgents 63 | Per-user agents provided by Mac OS X. 64 | .It Pa /System/Library/LaunchDaemons 65 | System-wide daemons provided by Mac OS X. 66 | .El 67 | .Sh SEE ALSO 68 | .Xr launchctl 1 , 69 | .Xr launchd.plist 5 , 70 | -------------------------------------------------------------------------------- /man/launchd.conf.5: -------------------------------------------------------------------------------- 1 | .Dd 1 May, 2009 2 | .Dt launchd.conf 5 3 | .Os Darwin 4 | .Sh NAME 5 | .Nm launchd.conf 6 | .Nd launchd configuration file 7 | .Sh SYNOPSIS 8 | .Nm $HOME/.launchd.conf 9 | .Nm /etc/launchd.conf 10 | .Sh DESCRIPTION 11 | .Nm 12 | contains a list of subcommands 13 | .Ar ( load , 14 | .Ar unload , 15 | etc.) to run via 16 | .Xr launchctl 1 17 | when 18 | .Xr launchd 8 19 | starts. 20 | .Sh FILES 21 | .Bl -tag -width "$HOME/.launchd.conf" -compact 22 | .It Pa $HOME/.launchd.conf 23 | Your launchd configuration file (currently unsupported). 24 | .It Pa /etc/launchd.conf 25 | The system's launchd configuration file. 26 | .El 27 | .Sh SEE ALSO 28 | .Xr launchctl 1 , 29 | .Xr launchd 8 , 30 | .Xr launchd.plist 5 31 | -------------------------------------------------------------------------------- /man/launchproxy.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2005 2 | .Dt launchproxy 8 3 | .Os Darwin 4 | .Sh NAME 5 | .Nm launchproxy 6 | .Nd inetd job emulation helper 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Sh DESCRIPTION 10 | .Nm 11 | handles the inetd emulation for 12 | .Nm launchd . 13 | This program may be merged into 14 | .Nm launchd 15 | in the future. 16 | .Sh SEE ALSO 17 | .Xr launchctl 1 , 18 | .Xr launchd.plist 5 , 19 | .Xr launchd 8 20 | -------------------------------------------------------------------------------- /man/rc.8: -------------------------------------------------------------------------------- 1 | .Dd 1 May, 2009 2 | .Dt RC 8 3 | .Os Darwin 4 | .Sh NAME 5 | .Nm rc 6 | .Nd command script for boot 7 | .Sh SYNOPSIS 8 | .Nm rc 9 | .Nm rc.local 10 | .Sh DESCRIPTION 11 | .Nm rc.local 12 | is now unsupported and has been replaced with 13 | .Xr launchd 8 , 14 | which bootstraps itself via the 15 | .Xr launchctl 1 16 | .Ar bootstrap 17 | subcommand to read in 18 | .Xr launchd 8 19 | jobs from the standard locations. 20 | .Sh SEE ALSO 21 | .Xr launchd 8 , 22 | .Xr launchctl 1 23 | -------------------------------------------------------------------------------- /man/wait4path.1: -------------------------------------------------------------------------------- 1 | .Dd April 6, 2004 2 | .Dt WAIT4PATH 1 3 | .Os "Mac OS X" 10.4 4 | .Sh NAME 5 | .Nm wait4path 6 | .Nd wait for given path to show up in the namespace 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Ao Ar path Ac 10 | .Sh DESCRIPTION 11 | The 12 | .Nm 13 | 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. 14 | -------------------------------------------------------------------------------- /rc/rc.common: -------------------------------------------------------------------------------- 1 | ## 2 | # Common setup for startup scripts. 3 | ## 4 | # Copyright 1998-2002 Apple Computer, Inc. 5 | ## 6 | 7 | ####################### 8 | # Configure the shell # 9 | ####################### 10 | 11 | ## 12 | # Be strict 13 | ## 14 | #set -e 15 | set -u 16 | 17 | ## 18 | # Set command search path 19 | ## 20 | PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/libexec:/System/Library/CoreServices; export PATH 21 | 22 | ## 23 | # Set the terminal mode 24 | ## 25 | #if [ -x /usr/bin/tset ] && [ -f /usr/share/misc/termcap ]; then 26 | # TERM=$(tset - -Q); export TERM 27 | #fi 28 | 29 | #################### 30 | # Useful functions # 31 | #################### 32 | 33 | ## 34 | # Determine if the network is up by looking for any non-loopback 35 | # internet network interfaces. 36 | ## 37 | CheckForNetwork() 38 | { 39 | local test 40 | 41 | if [ -z "${NETWORKUP:=}" ]; then 42 | 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) 43 | if [ "${test}" -gt 0 ]; then 44 | NETWORKUP="-YES-" 45 | else 46 | NETWORKUP="-NO-" 47 | fi 48 | fi 49 | } 50 | 51 | alias ConsoleMessage=echo 52 | 53 | ## 54 | # Process management 55 | ## 56 | GetPID () 57 | { 58 | local program="$1" 59 | local pidfile="${PIDFILE:=/var/run/${program}.pid}" 60 | local pid="" 61 | 62 | if [ -f "${pidfile}" ]; then 63 | pid=$(head -1 "${pidfile}") 64 | if ! kill -0 "${pid}" 2> /dev/null; then 65 | echo "Bad pid file $pidfile; deleting." 66 | pid="" 67 | rm -f "${pidfile}" 68 | fi 69 | fi 70 | 71 | if [ -n "${pid}" ]; then 72 | echo "${pid}" 73 | return 0 74 | else 75 | return 1 76 | fi 77 | } 78 | 79 | ## 80 | # Generic action handler 81 | ## 82 | RunService () 83 | { 84 | case $1 in 85 | start ) StartService ;; 86 | stop ) StopService ;; 87 | restart) RestartService ;; 88 | * ) echo "$0: unknown argument: $1";; 89 | esac 90 | } 91 | 92 | ########################## 93 | # Get host configuration # 94 | ########################## 95 | . /etc/hostconfig 96 | -------------------------------------------------------------------------------- /rc/rc.netboot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ## 3 | # Copyright 2002-2009 Apple Inc. 4 | # 5 | # This script configures NetBoot 6 | ## 7 | 8 | . /etc/rc.common 9 | 10 | # 11 | # Define: NETBOOT_SHADOW 12 | # Purpose: 13 | # To change the behavior of the system when choosing a netboot shadow 14 | # to use. 15 | # Values: 16 | # -NETWORK- Try to use the network for the shadow file, if 17 | # that fails, use the local drive 18 | # -NETWORK_ONLY- Only use the network, fail if not available 19 | # -LOCAL- Use the local drive for the shadow file, if that 20 | # fails, use the network 21 | # -LOCAL_ONLY- Only use the local drive for the shadow, fail if 22 | # not available 23 | 24 | NETBOOT_MOUNT=/var/netboot 25 | NETBOOT_SHADOW=${NETBOOT_SHADOW:-NETWORK-} 26 | 27 | Failed() 28 | { 29 | echo rc.netboot: $1 30 | echo rc.netboot: $1 > /dev/console 31 | sleep 5 32 | exit 1 33 | } 34 | 35 | common_start() 36 | { 37 | netboot_dir=$1 38 | netboot_shadow=$2 39 | if [ "${netboot_dir}" = "" ] ; then 40 | Failed "netboot_dir is empty" 41 | fi 42 | if [ "${netboot_shadow}" = "" ] ; then 43 | Failed "netboot_shadow is empty" 44 | fi 45 | netboot_shadow="${netboot_dir}/${netboot_shadow}" 46 | if ! mkdir -p "${netboot_dir}" ; then 47 | Failed "create ${netboot_dir} failed" 48 | fi 49 | chmod 700 "${netboot_dir}" 50 | mount -u -o ro / 51 | root_device=$(mount | sed -n 's:/dev/\(.*\) on / .*:\1:p') 52 | case "${root_device}" in 53 | vn*) 54 | if ! touch "${netboot_shadow}" ; then 55 | Failed "create ${netboot_shadow} failed" 56 | fi 57 | chmod 600 "${netboot_shadow}" 58 | if ! /usr/libexec/vndevice shadow "/dev/r${root_device}" "${netboot_shadow}" ; then 59 | Failed "vndevice shadow failed" 60 | fi 61 | ;; 62 | "") 63 | Failed "root device unknown" 64 | ;; 65 | *) 66 | if ! touch "${netboot_shadow}" ; then 67 | Failed "failed to create shadow ${netboot_shadow}" 68 | fi 69 | chmod 600 "${netboot_shadow}" 70 | if ! /usr/bin/nbdst -recycle "${root_device}" "${netboot_shadow}" ; then 71 | Failed "nbdst failed" 72 | fi 73 | ;; 74 | esac 75 | } 76 | 77 | local_mount() 78 | { 79 | tries=0 80 | limit=11 81 | while [ $tries -lt $limit ]; do 82 | tries=$(( tries + 1 )) 83 | volinfo=`autodiskmount -F 2>/dev/null` 84 | if [ $? -ne 0 ]; then 85 | if [ $tries -lt $limit ]; then 86 | echo "Waiting for local drives..." 87 | echo "Waiting for local drives (retry ${tries}/$(( limit - 1 )))..." > /dev/console 88 | sleep 5 89 | else 90 | echo "autodiskmount -F found no local drives" 91 | return 1 92 | fi 93 | else 94 | tries=$limit 95 | fi 96 | done 97 | set ${volinfo} 98 | devname=$1 99 | fstype=$2 100 | 101 | mount -t "${fstype}" -o nosuid,nodev "/dev/${devname}" "${NETBOOT_MOUNT}" 2>&1 102 | if [ $? -ne 0 ]; then 103 | echo "mount of ${devname} failed" 104 | return 1 105 | fi 106 | common_start "${NETBOOT_MOUNT}/.com.apple.NetBootX" shadowfile 107 | return 0 108 | } 109 | 110 | network_mount() 111 | { 112 | mount_from=$(ipconfig netbootoption shadow_mount_path 2>&1) 113 | if [ $? -ne 0 ]; then 114 | echo "no network shadow mount path available" 115 | return 1 116 | fi 117 | shadow_path=$(ipconfig netbootoption shadow_file_path 2>&1) 118 | if [ $? -ne 0 ]; then 119 | echo "no network shadow file path available" 120 | return 1 121 | fi 122 | case "${mount_from}" in 123 | afp:*) 124 | fstype=afp 125 | kextload -v 0 /System/Library/Filesystems/AppleShare/asp_tcp.kext 126 | kextload -v 0 /System/Library/Filesystems/AppleShare/afpfs.kext 127 | ;; 128 | nfs:*) fstype=nfs;; 129 | *) echo "unknown network filesystem mount from ${mount_from}" 130 | return 1 131 | ;; 132 | esac 133 | mount -t "${fstype}" -o nobrowse "${mount_from}" "${NETBOOT_MOUNT}" 134 | if [ $? -ne 0 ]; then 135 | echo "mount -t ${fstype} -o nobrowse ${mount_from} ${NETBOOT_MOUNT} failed" 136 | return 1 137 | fi 138 | common_start "${NETBOOT_MOUNT}" "${shadow_path}" 139 | return 0 140 | } 141 | 142 | do_start() 143 | { 144 | case "${NETBOOT_SHADOW}" in 145 | -LOCAL_ONLY-) 146 | err=$(local_mount) 147 | if [ $? -ne 0 ]; then 148 | Failed "${err}" 149 | fi 150 | ;; 151 | -LOCAL-) 152 | err=$(local_mount) 153 | if [ $? -ne 0 ]; then 154 | err=$(network_mount) 155 | if [ $? -ne 0 ]; then 156 | Failed "Could not find a local or network drive" 157 | fi 158 | fi 159 | ;; 160 | -NETWORK_ONLY-) 161 | err=$(network_mount) 162 | if [ $? -ne 0 ]; then 163 | Failed "${err}" 164 | fi 165 | ;; 166 | 167 | *) 168 | err=$(network_mount) 169 | if [ $? -ne 0 ]; then 170 | err=$(local_mount) 171 | if [ $? -ne 0 ]; then 172 | Failed "Could not find a network or local drive" 173 | fi 174 | fi 175 | ;; 176 | esac 177 | 178 | } 179 | 180 | do_init() 181 | { 182 | # attach the shadow file to the root disk image 183 | do_start 184 | 185 | # make sure the root filesystem is clean 186 | fsck -p || fsck -fy || Failed "Could not clean root filesystem" 187 | 188 | # make it writable 189 | mount -uw / 190 | 191 | # adjust /private/var/vm to point to the writable area (if not diskless) 192 | swapdir=/private/var/vm 193 | mounted_from=$(mount | sed -n 's:\(.*\) on .*/var/netboot.*:\1:p') 194 | case "${mounted_from}" in 195 | /dev/*) 196 | netboot_dir="${NETBOOT_MOUNT}/.com.apple.NetBootX" 197 | if [ -d "${netboot_dir}" ]; then 198 | rm -rf "${swapdir}" 199 | ln -s "${netboot_dir}" "${swapdir}" 200 | fi 201 | ;; 202 | *) 203 | ;; 204 | esac 205 | 206 | # set the ComputerName based on what the NetBoot server told us it was 207 | machine_name=$(ipconfig netbootoption machine_name 2>&1) 208 | if [ $? -ne 0 ]; then 209 | echo "no machine name option available" 210 | else 211 | echo "Setting ComputerName to ${machine_name}" 212 | scutil --set ComputerName "${machine_name}" 213 | fi 214 | } 215 | 216 | 217 | if [ $# -lt 1 ] ; then 218 | exit 0 219 | fi 220 | 221 | command=$1 222 | 223 | shift 224 | 225 | case "${command}" in 226 | init) 227 | do_init $@ 228 | ;; 229 | esac 230 | 231 | ## 232 | # Exit 233 | ## 234 | exit 0 235 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONFIG_H__ 2 | #define __CONFIG_H__ 3 | 4 | #include 5 | 6 | #if __has_include() 7 | #define HAVE_QUARANTINE 1 8 | #else 9 | #define HAVE_QUARANTINE 0 10 | #endif 11 | 12 | #if __has_include() 13 | #define HAVE_RESPONSIBILITY 1 14 | #else 15 | #define HAVE_RESPONSIBILITY 0 16 | #endif 17 | 18 | #if __has_include() 19 | #define HAVE_SANDBOX 1 20 | #else 21 | #define HAVE_SANDBOX 0 22 | #endif 23 | 24 | #define HAVE_LIBAUDITD !TARGET_OS_EMBEDDED 25 | 26 | #if !TARGET_OS_EMBEDDED && __has_include() 27 | #define HAVE_SYSTEMSTATS 1 28 | #else 29 | #define HAVE_SYSTEMSTATS 0 30 | #endif 31 | 32 | #endif /* __CONFIG_H__ */ 33 | -------------------------------------------------------------------------------- /src/core.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #ifndef __LAUNCHD_CORE_LOGIC__ 22 | #define __LAUNCHD_CORE_LOGIC__ 23 | 24 | #include "runtime.h" 25 | #include "bootstrap.h" 26 | #include "launch.h" 27 | #include 28 | 29 | typedef struct job_s *job_t; 30 | typedef struct jobmgr_s *jobmgr_t; 31 | 32 | extern jobmgr_t root_jobmgr; 33 | extern mach_port_t launchd_audit_port; 34 | extern au_asid_t launchd_audit_session; 35 | extern bool launchd_flat_mach_namespace; 36 | extern bool launchd_embedded_handofgod; 37 | 38 | void jobmgr_init(bool); 39 | jobmgr_t jobmgr_shutdown(jobmgr_t jm); 40 | void jobmgr_dispatch_all_semaphores(jobmgr_t jm); 41 | void jobmgr_dispatch_all_interested(jobmgr_t jm, job_t j); 42 | jobmgr_t jobmgr_delete_anything_with_port(jobmgr_t jm, mach_port_t port); 43 | 44 | launch_data_t job_export_all(void); 45 | 46 | job_t job_dispatch(job_t j, bool kickstart); /* returns j on success, NULL on job removal */ 47 | job_t job_find(jobmgr_t jm, const char *label); 48 | job_t job_find_by_service_port(mach_port_t p); 49 | bool job_ack_port_destruction(mach_port_t p); 50 | bool job_is_anonymous(job_t j); 51 | launch_data_t job_export(job_t j); 52 | void job_stop(job_t j); 53 | void job_checkin(job_t j); 54 | void job_remove(job_t j); 55 | bool job_is_god(job_t j); 56 | job_t job_import(launch_data_t pload); 57 | launch_data_t job_import_bulk(launch_data_t pload); 58 | job_t job_mig_intran(mach_port_t mp); 59 | void job_mig_destructor(job_t j); 60 | void job_ack_no_senders(job_t j); 61 | void job_log(job_t j, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4))); 62 | void job_set_pid_crashed(pid_t p); 63 | 64 | bool xpc_event_demux(mach_port_t p, xpc_object_t request, xpc_object_t *reply); 65 | bool xpc_process_demux(mach_port_t p, xpc_object_t request, xpc_object_t *reply); 66 | 67 | #endif /* __LAUNCHD_CORE_LOGIC__ */ 68 | -------------------------------------------------------------------------------- /src/helper.defs: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | import "vproc.h"; 4 | import "vproc_priv.h"; 5 | import "vproc_internal.h"; 6 | 7 | subsystem launchd_helper 4241011; 8 | 9 | userprefix helper_downcall_; 10 | serverprefix helper_recv_; 11 | 12 | skip; 13 | 14 | /* For coreservicesd to harvest exit status, not actually for UserEventAgent. */ 15 | simpleroutine 16 | wait( 17 | p : mach_port_move_send_once_t; 18 | status : int 19 | ); 20 | -------------------------------------------------------------------------------- /src/internal.defs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | subsystem internal 137000; 22 | 23 | #include 24 | #include 25 | 26 | serverprefix x_; 27 | 28 | routine 29 | handle_kqueue( 30 | p : mach_port_t; 31 | fd : integer_t 32 | ); 33 | -------------------------------------------------------------------------------- /src/ipc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #include "config.h" 22 | #include "ipc.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | #include "launch.h" 51 | #include "launch_priv.h" 52 | #include "launchd.h" 53 | #include "runtime.h" 54 | #include "core.h" 55 | 56 | extern char **environ; 57 | 58 | static LIST_HEAD(, conncb) connections; 59 | 60 | static launch_data_t adjust_rlimits(launch_data_t in); 61 | 62 | static void ipc_readmsg2(launch_data_t data, const char *cmd, void *context); 63 | static void ipc_readmsg(launch_data_t msg, void *context); 64 | 65 | static void ipc_listen_callback(void *obj __attribute__((unused)), struct kevent *kev); 66 | 67 | static kq_callback kqipc_listen_callback = ipc_listen_callback; 68 | 69 | static pid_t ipc_self = 0; 70 | 71 | char *sockpath = NULL; 72 | static char *sockdir = NULL; 73 | 74 | static bool ipc_inited = false; 75 | 76 | static void 77 | ipc_clean_up(void) 78 | { 79 | if (ipc_self != getpid()) { 80 | return; 81 | } 82 | 83 | if (-1 == unlink(sockpath)) { 84 | launchd_syslog(LOG_WARNING, "unlink(\"%s\"): %s", sockpath, strerror(errno)); 85 | } else if (-1 == rmdir(sockdir)) { 86 | launchd_syslog(LOG_WARNING, "rmdir(\"%s\"): %s", sockdir, strerror(errno)); 87 | } 88 | } 89 | 90 | void 91 | ipc_server_init(void) 92 | { 93 | struct sockaddr_un sun; 94 | mode_t oldmask; 95 | int r, fd = -1; 96 | char ourdir[1024]; 97 | 98 | if (ipc_inited) { 99 | return; 100 | } 101 | 102 | memset(&sun, 0, sizeof(sun)); 103 | sun.sun_family = AF_UNIX; 104 | 105 | if (pid1_magic) { 106 | strcpy(ourdir, LAUNCHD_SOCK_PREFIX); 107 | strncpy(sun.sun_path, LAUNCHD_SOCK_PREFIX "/sock", sizeof(sun.sun_path)); 108 | 109 | unlink(ourdir); 110 | if (mkdir(ourdir, S_IRWXU) == -1) { 111 | if (errno == EROFS) { 112 | goto out_bad; 113 | } else if (errno == EEXIST) { 114 | struct stat sb; 115 | stat(ourdir, &sb); 116 | if (!S_ISDIR(sb.st_mode)) { 117 | errno = EEXIST; 118 | launchd_syslog(LOG_ERR, "mkdir(\"%s\"): %s", LAUNCHD_SOCK_PREFIX, strerror(errno)); 119 | goto out_bad; 120 | } 121 | } else { 122 | launchd_syslog(LOG_ERR, "mkdir(\"%s\"): %s", ourdir, strerror(errno)); 123 | goto out_bad; 124 | } 125 | } 126 | } else { 127 | snprintf(ourdir, sizeof(ourdir), _PATH_TMP "launchd-%u.XXXXXX", getpid()); 128 | if (mkdtemp(ourdir) == NULL) { 129 | launchd_syslog(LOG_ERR, "Could not create critical directory \"%s\": %s", ourdir, strerror(errno)); 130 | goto out_bad; 131 | } 132 | snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/sock", ourdir); 133 | } 134 | 135 | if (unlink(sun.sun_path) == -1 && errno != ENOENT) { 136 | if (errno != EROFS) { 137 | launchd_syslog(LOG_ERR, "unlink(\"thesocket\"): %s", strerror(errno)); 138 | } 139 | goto out_bad; 140 | } 141 | 142 | if (posix_assumes_zero(fd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1) { 143 | goto out_bad; 144 | } 145 | 146 | oldmask = umask(S_IRWXG|S_IRWXO); 147 | r = bind(fd, (struct sockaddr *)&sun, sizeof(sun)); 148 | umask(oldmask); 149 | 150 | if (r == -1) { 151 | if (errno != EROFS) { 152 | launchd_syslog(LOG_ERR, "bind(\"thesocket\"): %s", strerror(errno)); 153 | } 154 | goto out_bad; 155 | } 156 | 157 | if (listen(fd, SOMAXCONN) == -1) { 158 | launchd_syslog(LOG_ERR, "listen(\"thesocket\"): %s", strerror(errno)); 159 | goto out_bad; 160 | } 161 | 162 | if (kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, &kqipc_listen_callback) == -1) { 163 | launchd_syslog(LOG_ERR, "kevent_mod(\"thesocket\", EVFILT_READ): %s", strerror(errno)); 164 | goto out_bad; 165 | } 166 | 167 | ipc_inited = true; 168 | 169 | sockdir = strdup(ourdir); 170 | sockpath = strdup(sun.sun_path); 171 | ipc_self = getpid(); 172 | atexit(ipc_clean_up); 173 | 174 | out_bad: 175 | if (!ipc_inited && fd != -1) { 176 | (void)runtime_close(fd); 177 | } 178 | } 179 | 180 | void 181 | ipc_open(int fd, job_t j) 182 | { 183 | struct conncb *c = calloc(1, sizeof(struct conncb)); 184 | 185 | fcntl(fd, F_SETFL, O_NONBLOCK); 186 | 187 | c->kqconn_callback = ipc_callback; 188 | if (j) { 189 | c->conn = launchd_fdopen(-1, fd); 190 | } else { 191 | c->conn = launchd_fdopen(fd, -1); 192 | } 193 | 194 | c->j = j; 195 | LIST_INSERT_HEAD(&connections, c, sle); 196 | kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, &c->kqconn_callback); 197 | } 198 | 199 | void 200 | ipc_listen_callback(void *obj __attribute__((unused)), struct kevent *kev) 201 | { 202 | struct sockaddr_un sun; 203 | socklen_t sl = sizeof(sun); 204 | int cfd; 205 | 206 | if ((cfd = _fd(accept(kev->ident, (struct sockaddr *)&sun, &sl))) == -1) { 207 | return; 208 | } 209 | 210 | if (geteuid() == 0) { 211 | uid_t euid, guid; 212 | if (getpeereid(cfd, &euid, &guid) == -1) { 213 | launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** launchd[%d] failed to getpeereid on incoming caller (%d)", getpid(), errno); 214 | (void)runtime_close(cfd); 215 | return; 216 | } 217 | 218 | if (euid != geteuid()) { 219 | launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** launchd[%d] failed to euid check on incoming caller (%d != %d)", getpid(), euid, geteuid()); 220 | (void)runtime_close(cfd); 221 | return; 222 | } 223 | } 224 | 225 | ipc_open(cfd, NULL); 226 | } 227 | 228 | void 229 | ipc_callback(void *obj, struct kevent *kev) 230 | { 231 | struct conncb *c = obj; 232 | int r; 233 | 234 | if (kev->filter == EVFILT_READ) { 235 | if (launchd_msg_recv(c->conn, ipc_readmsg, c) == -1 && errno != EAGAIN) { 236 | if (errno != ECONNRESET) { 237 | launchd_syslog(LOG_DEBUG, "%s(): recv: %s", __func__, strerror(errno)); 238 | } 239 | ipc_close(c); 240 | } 241 | } else if (kev->filter == EVFILT_WRITE) { 242 | r = launchd_msg_send(c->conn, NULL); 243 | if (r == -1) { 244 | if (errno != EAGAIN) { 245 | launchd_syslog(LOG_DEBUG, "%s(): send: %s", __func__, strerror(errno)); 246 | ipc_close(c); 247 | } 248 | } else if (r == 0) { 249 | kevent_mod(launchd_getfd(c->conn), EVFILT_WRITE, EV_DELETE, 0, 0, NULL); 250 | } 251 | } else { 252 | launchd_syslog(LOG_DEBUG, "%s(): unknown filter type!", __func__); 253 | ipc_close(c); 254 | } 255 | } 256 | 257 | static void 258 | set_user_env(launch_data_t obj, const char *key, void *context __attribute__((unused))) 259 | { 260 | const char *v = launch_data_get_string(obj); 261 | if (v) { 262 | setenv(key, v, 1); 263 | } else { 264 | launchd_syslog(LOG_WARNING, "Attempt to set NULL environment variable: %s (type = %d)", key, launch_data_get_type(obj)); 265 | } 266 | } 267 | 268 | void 269 | ipc_close_all_with_job(job_t j) 270 | { 271 | struct conncb *ci, *cin; 272 | 273 | LIST_FOREACH_SAFE(ci, &connections, sle, cin) { 274 | if (ci->j == j) { 275 | ipc_close(ci); 276 | } 277 | } 278 | } 279 | 280 | void 281 | ipc_close_fds(launch_data_t o) 282 | { 283 | size_t i; 284 | 285 | switch (launch_data_get_type(o)) { 286 | case LAUNCH_DATA_DICTIONARY: 287 | launch_data_dict_iterate(o, (void (*)(launch_data_t, const char *, void *))ipc_close_fds, NULL); 288 | break; 289 | case LAUNCH_DATA_ARRAY: 290 | for (i = 0; i < launch_data_array_get_count(o); i++) 291 | ipc_close_fds(launch_data_array_get_index(o, i)); 292 | break; 293 | case LAUNCH_DATA_FD: 294 | if (launch_data_get_fd(o) != -1) { 295 | (void)runtime_close(launch_data_get_fd(o)); 296 | } 297 | break; 298 | default: 299 | break; 300 | } 301 | } 302 | 303 | void 304 | ipc_revoke_fds(launch_data_t o) 305 | { 306 | size_t i; 307 | 308 | switch (launch_data_get_type(o)) { 309 | case LAUNCH_DATA_DICTIONARY: 310 | launch_data_dict_iterate(o, (void (*)(launch_data_t, const char *, void *))ipc_revoke_fds, NULL); 311 | break; 312 | case LAUNCH_DATA_ARRAY: 313 | for (i = 0; i < launch_data_array_get_count(o); i++) 314 | ipc_revoke_fds(launch_data_array_get_index(o, i)); 315 | break; 316 | case LAUNCH_DATA_FD: 317 | launch_data_set_fd(o, -1); 318 | break; 319 | default: 320 | break; 321 | } 322 | } 323 | 324 | struct readmsg_context { 325 | struct conncb *c; 326 | launch_data_t resp; 327 | }; 328 | 329 | void 330 | ipc_readmsg(launch_data_t msg, void *context) 331 | { 332 | struct readmsg_context rmc = { context, NULL }; 333 | 334 | if (LAUNCH_DATA_DICTIONARY == launch_data_get_type(msg)) { 335 | launch_data_dict_iterate(msg, ipc_readmsg2, &rmc); 336 | } else if (LAUNCH_DATA_STRING == launch_data_get_type(msg)) { 337 | ipc_readmsg2(NULL, launch_data_get_string(msg), &rmc); 338 | } else { 339 | rmc.resp = launch_data_new_errno(EINVAL); 340 | } 341 | 342 | if (NULL == rmc.resp) { 343 | rmc.resp = launch_data_new_errno(ENOSYS); 344 | } 345 | 346 | ipc_close_fds(msg); 347 | 348 | if (launchd_msg_send(rmc.c->conn, rmc.resp) == -1) { 349 | if (errno == EAGAIN) { 350 | kevent_mod(launchd_getfd(rmc.c->conn), EVFILT_WRITE, EV_ADD, 0, 0, &rmc.c->kqconn_callback); 351 | } else { 352 | launchd_syslog(LOG_DEBUG, "launchd_msg_send() == -1: %s", strerror(errno)); 353 | ipc_close(rmc.c); 354 | } 355 | } 356 | launch_data_free(rmc.resp); 357 | } 358 | 359 | void 360 | ipc_readmsg2(launch_data_t data, const char *cmd, void *context) 361 | { 362 | struct readmsg_context *rmc = context; 363 | launch_data_t resp = NULL; 364 | job_t j; 365 | 366 | if (rmc->resp) { 367 | return; 368 | } 369 | 370 | /* Do not allow commands other than check-in to come over the trusted socket 371 | * on the Desktop. On Embedded, allow all commands over the trusted socket 372 | * if the job has the God Mode key set. 373 | */ 374 | #if TARGET_OS_EMBEDDED 375 | bool allow_privileged_ops = (!rmc->c->j || job_is_god(rmc->c->j)); 376 | #else 377 | bool allow_privileged_ops = !rmc->c->j; 378 | #endif 379 | 380 | if (rmc->c->j && strcmp(cmd, LAUNCH_KEY_CHECKIN) == 0) { 381 | resp = job_export(rmc->c->j); 382 | job_checkin(rmc->c->j); 383 | } else if (allow_privileged_ops) { 384 | #if TARGET_OS_EMBEDDED 385 | launchd_embedded_handofgod = rmc->c->j && job_is_god(rmc->c->j); 386 | #endif 387 | if (data == NULL) { 388 | if (!strcmp(cmd, LAUNCH_KEY_SHUTDOWN)) { 389 | launchd_shutdown(); 390 | resp = launch_data_new_errno(0); 391 | } else if (!strcmp(cmd, LAUNCH_KEY_GETJOBS)) { 392 | resp = job_export_all(); 393 | ipc_revoke_fds(resp); 394 | } else if (!strcmp(cmd, LAUNCH_KEY_GETRESOURCELIMITS)) { 395 | resp = adjust_rlimits(NULL); 396 | } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGESELF)) { 397 | struct rusage rusage; 398 | getrusage(RUSAGE_SELF, &rusage); 399 | resp = launch_data_new_opaque(&rusage, sizeof(rusage)); 400 | } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGECHILDREN)) { 401 | struct rusage rusage; 402 | getrusage(RUSAGE_CHILDREN, &rusage); 403 | resp = launch_data_new_opaque(&rusage, sizeof(rusage)); 404 | } 405 | } else { 406 | if (!strcmp(cmd, LAUNCH_KEY_STARTJOB)) { 407 | if ((j = job_find(NULL, launch_data_get_string(data))) != NULL) { 408 | errno = job_dispatch(j, true) ? 0 : errno; 409 | } 410 | resp = launch_data_new_errno(errno); 411 | } else if (!strcmp(cmd, LAUNCH_KEY_STOPJOB)) { 412 | if ((j = job_find(NULL, launch_data_get_string(data))) != NULL) { 413 | errno = 0; 414 | job_stop(j); 415 | } 416 | resp = launch_data_new_errno(errno); 417 | } else if (!strcmp(cmd, LAUNCH_KEY_REMOVEJOB)) { 418 | if ((j = job_find(NULL, launch_data_get_string(data))) != NULL) { 419 | errno = 0; 420 | job_remove(j); 421 | } 422 | resp = launch_data_new_errno(errno); 423 | } else if (!strcmp(cmd, LAUNCH_KEY_SUBMITJOB)) { 424 | if (launch_data_get_type(data) == LAUNCH_DATA_ARRAY) { 425 | resp = job_import_bulk(data); 426 | } else { 427 | if (job_import(data)) { 428 | errno = 0; 429 | } 430 | resp = launch_data_new_errno(errno); 431 | } 432 | } else if (!strcmp(cmd, LAUNCH_KEY_UNSETUSERENVIRONMENT)) { 433 | unsetenv(launch_data_get_string(data)); 434 | resp = launch_data_new_errno(0); 435 | } else if (!strcmp(cmd, LAUNCH_KEY_SETUSERENVIRONMENT)) { 436 | launch_data_dict_iterate(data, set_user_env, NULL); 437 | resp = launch_data_new_errno(0); 438 | } else if (!strcmp(cmd, LAUNCH_KEY_SETRESOURCELIMITS)) { 439 | resp = adjust_rlimits(data); 440 | } else if (!strcmp(cmd, LAUNCH_KEY_GETJOB)) { 441 | if ((j = job_find(NULL, launch_data_get_string(data))) == NULL) { 442 | resp = launch_data_new_errno(errno); 443 | } else { 444 | resp = job_export(j); 445 | ipc_revoke_fds(resp); 446 | } 447 | } 448 | } 449 | #if TARGET_OS_EMBEDDED 450 | launchd_embedded_handofgod = false; 451 | #endif 452 | } else { 453 | resp = launch_data_new_errno(EACCES); 454 | } 455 | 456 | rmc->resp = resp; 457 | } 458 | 459 | static int 460 | close_abi_fixup(int fd) 461 | { 462 | return runtime_close(fd); 463 | } 464 | 465 | void 466 | ipc_close(struct conncb *c) 467 | { 468 | LIST_REMOVE(c, sle); 469 | launchd_close(c->conn, close_abi_fixup); 470 | free(c); 471 | } 472 | 473 | launch_data_t 474 | adjust_rlimits(launch_data_t in) 475 | { 476 | /* If I never have to deal with this rlimit nonsense again, I'll be a very 477 | * happy man. 478 | */ 479 | struct rlimit l[RLIM_NLIMITS]; 480 | struct rlimit *ltmp; 481 | size_t i,ltmpsz; 482 | 483 | for (i = 0; i < RLIM_NLIMITS; i++) { 484 | (void)posix_assumes_zero(getrlimit(i, l + i)); 485 | } 486 | 487 | if (in) { 488 | ltmp = launch_data_get_opaque(in); 489 | ltmpsz = launch_data_get_opaque_size(in); 490 | 491 | if (ltmpsz > sizeof(l)) { 492 | launchd_syslog(LOG_WARNING, "Too much rlimit data sent!"); 493 | ltmpsz = sizeof(l); 494 | } 495 | 496 | for (i = 0; i < (ltmpsz / sizeof(struct rlimit)); i++) { 497 | if (ltmp[i].rlim_cur == l[i].rlim_cur && ltmp[i].rlim_max == l[i].rlim_max) { 498 | continue; 499 | } 500 | 501 | if (/* XXX readcfg_pid && */ pid1_magic && (i == RLIMIT_NOFILE || i == RLIMIT_NPROC)) { 502 | int gmib[] = { CTL_KERN, KERN_MAXPROC }; 503 | int pmib[] = { CTL_KERN, KERN_MAXPROCPERUID }; 504 | const char *gstr = "kern.maxproc"; 505 | const char *pstr = "kern.maxprocperuid"; 506 | int gval = ltmp[i].rlim_max; 507 | int pval = ltmp[i].rlim_cur; 508 | switch (i) { 509 | case RLIMIT_NOFILE: 510 | gmib[1] = KERN_MAXFILES; 511 | pmib[1] = KERN_MAXFILESPERPROC; 512 | gstr = "kern.maxfiles"; 513 | pstr = "kern.maxfilesperproc"; 514 | break; 515 | default: 516 | break; 517 | } 518 | 519 | if (gval > 0) { 520 | (void)posix_assumes_zero(sysctl(gmib, 2, NULL, NULL, &gval, sizeof(gval))); 521 | } else { 522 | launchd_syslog(LOG_WARNING, "sysctl(\"%s\"): can't be zero", gstr); 523 | } 524 | if (pval > 0) { 525 | (void)posix_assumes_zero(sysctl(pmib, 2, NULL, NULL, &pval, sizeof(pval))); 526 | } else { 527 | launchd_syslog(LOG_WARNING, "sysctl(\"%s\"): can't be zero", pstr); 528 | } 529 | } 530 | (void)posix_assumes_zero(setrlimit(i, ltmp + i)); 531 | /* the kernel may have clamped the values we gave it */ 532 | (void)posix_assumes_zero(getrlimit(i, l + i)); 533 | } 534 | } 535 | 536 | return launch_data_new_opaque(l, sizeof(struct rlimit) * RLIM_NLIMITS); 537 | } 538 | -------------------------------------------------------------------------------- /src/ipc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #ifndef __LAUNCHD_IPC_H__ 22 | #define __LAUNCHD_IPC_H__ 23 | 24 | #include 25 | #include "runtime.h" 26 | #include "core.h" 27 | #include "launch_priv.h" 28 | #include "launch_internal.h" 29 | 30 | struct conncb { 31 | kq_callback kqconn_callback; 32 | LIST_ENTRY(conncb) sle; 33 | launch_t conn; 34 | job_t j; 35 | }; 36 | 37 | extern char *sockpath; 38 | 39 | void ipc_open(int fd, job_t j); 40 | void ipc_close_all_with_job(job_t j); 41 | void ipc_close(struct conncb *c); 42 | void ipc_callback(void *, struct kevent *); 43 | void ipc_revoke_fds(launch_data_t o); 44 | void ipc_close_fds(launch_data_t o); 45 | void ipc_server_init(void); 46 | 47 | #endif /* __LAUNCHD_IPC_H__ */ 48 | -------------------------------------------------------------------------------- /src/job.defs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | /* 21 | * bootstrap -- fundamental service initiator and port server 22 | * Mike DeMoney, NeXT, Inc. 23 | * Copyright, 1990. All rights reserved. 24 | */ 25 | 26 | subsystem job 400; 27 | 28 | #include 29 | #include 30 | #include "job_types.defs" 31 | import "vproc.h"; 32 | import "vproc_priv.h"; 33 | import "vproc_internal.h"; 34 | 35 | userprefix vproc_mig_; 36 | serverprefix job_mig_; 37 | 38 | routine 39 | create_server( 40 | j : job_t; 41 | servercmd : cmd_t; 42 | serveruid : uid_t; 43 | ondemand : boolean_t; 44 | out serverport : mach_port_make_send_t 45 | ); 46 | 47 | routine 48 | reboot2( 49 | j : job_t; 50 | flags : uint64_t 51 | ); 52 | 53 | routine 54 | check_in2( 55 | j : job_t; 56 | servicename : name_t; 57 | out serviceport : mach_port_move_receive_t; 58 | out instanceid : uuid_t; 59 | flags : uint64_t 60 | ); 61 | 62 | routine 63 | register2( 64 | j : job_t; 65 | servicename : name_t; 66 | serviceport : mach_port_t; 67 | flags : uint64_t 68 | ); 69 | 70 | routine 71 | look_up2( 72 | j : job_t; 73 | sreplyport rp : mach_port_make_send_once_t; 74 | servicename : name_t; 75 | out serviceport : mach_port_t; 76 | UserAuditToken servercreds : audit_token_t; 77 | targetpid : pid_t; 78 | instanceid : uuid_t; 79 | flags : uint64_t 80 | ); 81 | 82 | routine 83 | send_signal( 84 | j : job_t; 85 | sreplyport rp : mach_port_make_send_once_t; 86 | label : name_t; 87 | sig : integer_t 88 | ); 89 | 90 | routine 91 | parent( 92 | j : job_t; 93 | sreplyport rp : mach_port_make_send_once_t; 94 | out parentport : mach_port_make_send_t 95 | ); 96 | 97 | routine 98 | post_fork_ping( 99 | j : job_t; 100 | taskport : task_t; 101 | out asport : mach_port_t 102 | ); 103 | 104 | routine 105 | info( 106 | j : job_t; 107 | out names : name_array_t, dealloc; 108 | out jobs : name_array_t, dealloc; 109 | out actives : bootstrap_status_array_t, dealloc; 110 | flags : uint64_t 111 | ); 112 | 113 | routine 114 | subset( 115 | j : job_t; 116 | reqport : mach_port_t; 117 | out subsetport : mach_port_make_send_t 118 | ); 119 | 120 | skip; /* Formerly setup_shmem. */ 121 | 122 | routine 123 | take_subset( 124 | j : job_t; 125 | out reqport : mach_port_move_send_t; 126 | out recvport : mach_port_move_receive_t; 127 | out jobs : pointer_t, dealloc; 128 | out ports : mach_port_move_send_array_t, dealloc 129 | ); 130 | 131 | routine 132 | getsocket( 133 | j : job_t; 134 | out sockpath : name_t 135 | ); 136 | 137 | skip; /* Formerly spawn. */ 138 | 139 | skip; /* Formerly wait. */ 140 | 141 | skip; /* Formerly uncork_fork. */ 142 | 143 | routine 144 | swap_integer( 145 | j : job_t; 146 | inkey : vproc_gsk_t; 147 | outkey : vproc_gsk_t; 148 | inval : int64_t; 149 | out outval : int64_t 150 | ); 151 | 152 | routine 153 | log( 154 | j : job_t; 155 | pri : integer_t; 156 | err : integer_t; 157 | message : logmsg_t 158 | ); 159 | 160 | routine 161 | lookup_per_user_context( 162 | j : job_t; 163 | uid : uid_t; 164 | out userbport : mach_port_t 165 | ); 166 | 167 | routine 168 | move_subset( 169 | j : job_t; 170 | targetport : mach_port_t; 171 | session : name_t; 172 | asport : mach_port_t; 173 | flags : uint64_t 174 | ); 175 | 176 | routine 177 | swap_complex( 178 | j : job_t; 179 | inkey : vproc_gsk_t; 180 | outkey : vproc_gsk_t; 181 | inval : pointer_t; 182 | out outval : pointer_t, dealloc 183 | ); 184 | 185 | routine 186 | log_drain( 187 | j : job_t; 188 | sreplyport rp : mach_port_make_send_once_t; 189 | out outval : pointer_t, dealloc 190 | ); 191 | 192 | routine 193 | log_forward( 194 | j : job_t; 195 | inval : pointer_t 196 | ); 197 | 198 | routine 199 | kickstart( 200 | j : job_t; 201 | label : name_t; 202 | out pid : pid_t; 203 | flags : natural_t 204 | ); 205 | 206 | skip; /* Formerly embedded_wait. */ 207 | 208 | routine 209 | lookup_children( 210 | j : job_t; 211 | out childports : mach_port_move_send_array_t, dealloc; 212 | out childnames : name_array_t, dealloc; 213 | out childprops : bootstrap_property_array_t, dealloc 214 | ); 215 | 216 | routine 217 | switch_to_session( 218 | j : job_t; 219 | reqport : mach_port_t; 220 | session : name_t; 221 | asport : mach_port_t; 222 | out newbsport : mach_port_make_send_t 223 | ); 224 | 225 | skip; /* Formerly transaction_count_for_pid. */ 226 | 227 | routine 228 | pid_is_managed( 229 | j : job_t; 230 | pid : pid_t; 231 | out managed : boolean_t 232 | ); 233 | 234 | routine 235 | port_for_label( 236 | j : job_t; 237 | label : name_t; 238 | out jport : mach_port_make_send_t 239 | ); 240 | 241 | routine 242 | init_session( 243 | j : job_t; 244 | session : name_t; 245 | asport : mach_port_t 246 | ); 247 | 248 | routine 249 | set_security_session( 250 | j : job_t; 251 | uuid : uuid_t; 252 | asport : mach_port_t 253 | ); 254 | 255 | skip; /* Formerly wait2. */ 256 | 257 | skip; /* Formerly event_source_check_in. */ 258 | 259 | skip; /* Formerly event_set_state. */ 260 | 261 | routine 262 | spawn2( 263 | j : job_t; 264 | sreplyport rp : mach_port_make_send_once_t; 265 | job : pointer_t; 266 | asport : mach_port_t; 267 | out outpid : pid_t; 268 | out obsrvport : mach_port_move_receive_t 269 | ); 270 | 271 | routine 272 | get_root_bootstrap( 273 | j : job_t; 274 | out rootbs : mach_port_move_send_t 275 | ); 276 | 277 | routine 278 | legacy_ipc_request( 279 | j : job_t; 280 | request : pointer_t; 281 | request_fds : mach_port_move_send_array_t; 282 | out reply : pointer_t, dealloc; 283 | out reply_fds : mach_port_move_send_array_t, dealloc; 284 | asport : mach_port_t 285 | ); 286 | 287 | routine 288 | get_listener_port_rights( 289 | j : job_t; 290 | out sports : mach_port_make_send_array_t, dealloc 291 | ); 292 | 293 | routine 294 | register_gui_session( 295 | j : job_t; 296 | asport : mach_port_t 297 | ); 298 | -------------------------------------------------------------------------------- /src/job_forward.defs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | subsystem job_forward 400; 22 | 23 | #include 24 | #include 25 | #include "job_types.defs" 26 | import "vproc.h"; 27 | import "vproc_priv.h"; 28 | import "vproc_internal.h"; 29 | 30 | userprefix vproc_mig_; 31 | serverprefix job_mig_; 32 | 33 | skip; /* create_server */ 34 | 35 | skip; /* reboot2 */ 36 | 37 | skip; /* check_in */ 38 | 39 | skip; /* register2 */ 40 | 41 | simpleroutine 42 | look_up2_forward( 43 | j : job_t; 44 | replyport rp : mach_port_move_send_once_t; 45 | servicename : name_t; 46 | targetpid : pid_t; 47 | instanceid : uuid_t; 48 | flags : uint64_t 49 | ); 50 | 51 | skip; /* send_signal */ 52 | 53 | simpleroutine 54 | parent_forward( 55 | j : job_t; 56 | replyport rp : mach_port_move_send_once_t 57 | ); 58 | 59 | -------------------------------------------------------------------------------- /src/job_reply.defs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | subsystem job_reply 500; 22 | 23 | #include 24 | #include 25 | #include "job_types.defs" 26 | import "bootstrap.h"; 27 | import "vproc.h"; 28 | import "vproc_internal.h"; 29 | 30 | skip; /* create_server */ 31 | 32 | skip; /* reboot2 */ 33 | 34 | skip; /* check_in2 */ 35 | 36 | skip; /* register2 */ 37 | 38 | skip; /* look_up2 */ 39 | 40 | simpleroutine 41 | job_mig_send_signal_reply( 42 | rp : mach_port_move_send_once_t; 43 | kr : kern_return_t, RetCode 44 | ); 45 | 46 | skip; /* parent */ 47 | 48 | skip; /* post_fork_ping */ 49 | 50 | skip; /* info */ 51 | 52 | skip; /* subset */ 53 | 54 | skip; /* setup_shmem */ 55 | 56 | skip; /* take_subset */ 57 | 58 | skip; /* getsocket */ 59 | 60 | skip; /* spawn */ 61 | 62 | skip; /* wait */ 63 | 64 | skip; /* uncork_fork */ 65 | 66 | skip; /* swap_integer */ 67 | 68 | skip; /* log */ 69 | 70 | skip; /* lookup_per_user_context */ 71 | 72 | skip; /* move_subset */ 73 | 74 | skip; /* swap_complex */ 75 | 76 | simpleroutine 77 | job_mig_log_drain_reply( 78 | rp : mach_port_move_send_once_t; 79 | kr : kern_return_t, RetCode; 80 | outval : pointer_t 81 | ); 82 | 83 | skip; /* log_forward */ 84 | 85 | skip; /* kickstart */ 86 | 87 | skip; /* embedded_wait */ 88 | 89 | skip; /* lookup_children */ 90 | 91 | skip; /* switch_to_session */ 92 | 93 | skip; /* transaction_count_for_pid */ 94 | 95 | skip; /* pid_is_managed */ 96 | 97 | skip; /* port_for_label */ 98 | 99 | skip; /* init_session */ 100 | 101 | skip; /* set_security_session */ 102 | 103 | skip; /* wait2 */ 104 | 105 | skip; /* event_source_check_in */ 106 | 107 | skip; /* event_set_state */ 108 | 109 | simpleroutine 110 | job_mig_spawn2_reply( 111 | rp : mach_port_move_send_once_t; 112 | kr : kern_return_t, RetCode; 113 | pid : pid_t; 114 | obsrvp : mach_port_move_receive_t 115 | ); 116 | 117 | skip; /* get_root_bootstrap */ 118 | 119 | skip; /* legacy_ipc_request */ 120 | -------------------------------------------------------------------------------- /src/job_types.defs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999-2006 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | /* 21 | * bootstrap -- fundamental service initiator and port server 22 | * Mike DeMoney, NeXT, Inc. 23 | * Copyright, 1990. All rights reserved. 24 | */ 25 | 26 | /* These really should be a part of the standard types... */ 27 | type mach_port_move_send_array_t = array[] of mach_port_move_send_t 28 | ctype: mach_port_array_t; 29 | type mach_port_make_send_array_t = array[] of mach_port_make_send_t 30 | ctype: mach_port_array_t; 31 | 32 | type pid_t = integer_t; 33 | type pid_array_t = ^array [] of pid_t; 34 | type uid_t = natural_t; 35 | type gid_t = natural_t; 36 | type vproc_gsk_t = integer_t; 37 | type logmsg_t = c_string[*:2048]; 38 | type cmd_t = c_string[512]; 39 | type name_t = c_string[128]; 40 | type name_array_t = ^array [] of name_t; 41 | type bootstrap_property_t = natural_t; 42 | type bootstrap_property_array_t = ^array [] of bootstrap_property_t; 43 | type bootstrap_status_t = integer_t; 44 | type bootstrap_status_array_t = ^array [] of bootstrap_status_t; 45 | type uuid_t = array [16] of MACH_MSG_TYPE_BYTE; 46 | 47 | type job_t = mach_port_t 48 | intran : job_t job_mig_intran(mach_port_t) 49 | outtran : mach_port_t job_mig_outtran(job_t) 50 | destructor : job_mig_destructor(job_t) 51 | cusertype : vproc_mig_t; 52 | -------------------------------------------------------------------------------- /src/kill2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "kill2.h" 26 | 27 | int 28 | kill2(pid_t pid, int sig) 29 | { 30 | /* 31 | * POSIX defines consistency over correctness, and consequently 32 | * kill/killpg now returns EPERM instead of ESRCH. 33 | * 34 | * I've filed 5487498 to get a non-portable kill(). 35 | * We'll regretfully take advantage of implementation details for now. 36 | */ 37 | return syscall(SYS_kill, pid, sig, 0); 38 | } 39 | 40 | int 41 | killpg2(pid_t pgrp, int sig) 42 | { 43 | return kill2(-pgrp, sig); 44 | } 45 | -------------------------------------------------------------------------------- /src/kill2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | #ifndef __LAUNCHD_KILL2_H__ 21 | #define __LAUNCHD_KILL2_H__ 22 | 23 | #include 24 | 25 | int kill2(pid_t pid, int sig); 26 | int killpg2(pid_t pgrp, int sig); 27 | 28 | #endif /* __LAUNCHD_KILL2_H__ */ 29 | -------------------------------------------------------------------------------- /src/ktrace.c: -------------------------------------------------------------------------------- 1 | #include "ktrace.h" 2 | 3 | void 4 | runtime_ktrace1(runtime_ktrace_code_t code) 5 | { 6 | void *ra = __builtin_extract_return_addr(__builtin_return_address(1)); 7 | 8 | /* This syscall returns EINVAL when the trace isn't enabled. */ 9 | if (launchd_apple_internal) { 10 | syscall(180, code, 0, 0, 0, (long)ra); 11 | } 12 | } 13 | 14 | void 15 | runtime_ktrace0(runtime_ktrace_code_t code) 16 | { 17 | void *ra = __builtin_extract_return_addr(__builtin_return_address(0)); 18 | 19 | /* This syscall returns EINVAL when the trace isn't enabled. */ 20 | if (launchd_apple_internal) { 21 | syscall(180, code, 0, 0, 0, (long)ra); 22 | } 23 | } 24 | 25 | void 26 | runtime_ktrace(runtime_ktrace_code_t code, long a, long b, long c) 27 | { 28 | void *ra = __builtin_extract_return_addr(__builtin_return_address(0)); 29 | 30 | /* This syscall returns EINVAL when the trace isn't enabled. */ 31 | if (launchd_apple_internal) { 32 | syscall(180, code, a, b, c, (long)ra); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/ktrace.h: -------------------------------------------------------------------------------- 1 | #ifndef __LAUNCHD_KTRACE_H__ 2 | #define __LAUNCHD_KTRACE_H__ 3 | 4 | #include 5 | #include 6 | 7 | extern bool launchd_apple_internal; 8 | 9 | #ifndef DBG_LAUNCHD 10 | #define DBG_LAUNCHD 34 11 | #endif /* DBG_LAUNCHD */ 12 | 13 | /* Class(8) | SubClass(8) | Code(14) | Qual(2) */ 14 | #define RTKT_CODE(c) ((DBG_LAUNCHD << 24) | (((c) & 0x3fffff) << 2)) 15 | 16 | typedef enum { 17 | RTKT_LAUNCHD_STARTING = RTKT_CODE(1), 18 | RTKT_LAUNCHD_EXITING = RTKT_CODE(2), 19 | RTKT_LAUNCHD_FINDING_STRAY_PG = RTKT_CODE(3), 20 | RTKT_LAUNCHD_FINDING_ALL_STRAYS = RTKT_CODE(4), 21 | RTKT_LAUNCHD_FINDING_EXECLESS = RTKT_CODE(5), 22 | RTKT_LAUNCHD_FINDING_WEIRD_UIDS = RTKT_CODE(6), 23 | RTKT_LAUNCHD_DATA_PACK = RTKT_CODE(7), 24 | RTKT_LAUNCHD_DATA_UNPACK = RTKT_CODE(8), 25 | RTKT_LAUNCHD_BUG = RTKT_CODE(9), 26 | RTKT_LAUNCHD_MACH_IPC = RTKT_CODE(10), 27 | RTKT_LAUNCHD_BSD_KEVENT = RTKT_CODE(11), 28 | RTKT_VPROC_TRANSACTION_INCREMENT = RTKT_CODE(12), 29 | RTKT_VPROC_TRANSACTION_DECREMENT = RTKT_CODE(13), 30 | } runtime_ktrace_code_t; 31 | 32 | /* All of these log the return address as "arg4" */ 33 | void runtime_ktrace1(runtime_ktrace_code_t code); 34 | void runtime_ktrace0(runtime_ktrace_code_t code); 35 | void runtime_ktrace(runtime_ktrace_code_t code, long a, long b, long c); 36 | 37 | #endif /* __LAUNCHD_KTRACE_H__ */ 38 | -------------------------------------------------------------------------------- /src/launchd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #include "config.h" 22 | #include "launchd.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | 69 | #if HAVE_LIBAUDITD 70 | #include 71 | #include 72 | #endif 73 | 74 | #include "bootstrap.h" 75 | #include "vproc.h" 76 | #include "vproc_priv.h" 77 | #include "vproc_internal.h" 78 | #include "launch.h" 79 | #include "launch_internal.h" 80 | 81 | #include "runtime.h" 82 | #include "core.h" 83 | #include "ipc.h" 84 | 85 | #define LAUNCHD_CONF ".launchd.conf" 86 | 87 | extern char **environ; 88 | 89 | static void pfsystem_callback(void *, struct kevent *); 90 | 91 | static kq_callback kqpfsystem_callback = pfsystem_callback; 92 | 93 | static void pid1_magic_init(void); 94 | 95 | static void testfd_or_openfd(int fd, const char *path, int flags); 96 | static bool get_network_state(void); 97 | static void monitor_networking_state(void); 98 | static void fatal_signal_handler(int sig, siginfo_t *si, void *uap); 99 | static void handle_pid1_crashes_separately(void); 100 | static void do_pid1_crash_diagnosis_mode(const char *msg); 101 | static int basic_fork(void); 102 | static bool do_pid1_crash_diagnosis_mode2(const char *msg); 103 | 104 | static void *update_thread(void *nothing); 105 | 106 | static void *crash_addr; 107 | static pid_t crash_pid; 108 | 109 | char *_launchd_database_dir; 110 | char *_launchd_log_dir; 111 | 112 | bool launchd_shutting_down; 113 | bool network_up; 114 | uid_t launchd_uid; 115 | FILE *launchd_console = NULL; 116 | int32_t launchd_sync_frequency = 30; 117 | 118 | int 119 | main(int argc, char *const *argv) 120 | { 121 | bool sflag = false; 122 | int ch; 123 | 124 | /* This needs to be cleaned up. Currently, we risk tripping assumes() macros 125 | * before we've properly set things like launchd's log database paths, the 126 | * global launchd label for syslog messages and the like. Luckily, these are 127 | * operations that will probably never fail, like test_of_openfd(), the 128 | * stuff in launchd_runtime_init() and the stuff in 129 | * handle_pid1_crashes_separately(). 130 | */ 131 | testfd_or_openfd(STDIN_FILENO, _PATH_DEVNULL, O_RDONLY); 132 | testfd_or_openfd(STDOUT_FILENO, _PATH_DEVNULL, O_WRONLY); 133 | testfd_or_openfd(STDERR_FILENO, _PATH_DEVNULL, O_WRONLY); 134 | 135 | if (launchd_use_gmalloc) { 136 | if (!getenv("DYLD_INSERT_LIBRARIES")) { 137 | setenv("DYLD_INSERT_LIBRARIES", "/usr/lib/libgmalloc.dylib", 1); 138 | setenv("MALLOC_STRICT_SIZE", "1", 1); 139 | execv(argv[0], argv); 140 | } else { 141 | unsetenv("DYLD_INSERT_LIBRARIES"); 142 | unsetenv("MALLOC_STRICT_SIZE"); 143 | } 144 | } else if (launchd_malloc_log_stacks) { 145 | if (!getenv("MallocStackLogging")) { 146 | setenv("MallocStackLogging", "1", 1); 147 | execv(argv[0], argv); 148 | } else { 149 | unsetenv("MallocStackLogging"); 150 | } 151 | } 152 | 153 | while ((ch = getopt(argc, argv, "s")) != -1) { 154 | switch (ch) { 155 | case 's': sflag = true; break; /* single user */ 156 | case '?': /* we should do something with the global optopt variable here */ 157 | default: 158 | fprintf(stderr, "%s: ignoring unknown arguments\n", getprogname()); 159 | break; 160 | } 161 | } 162 | 163 | if (getpid() != 1 && getppid() != 1) { 164 | fprintf(stderr, "%s: This program is not meant to be run directly.\n", getprogname()); 165 | exit(EXIT_FAILURE); 166 | } 167 | 168 | launchd_runtime_init(); 169 | 170 | if (NULL == getenv("PATH")) { 171 | setenv("PATH", _PATH_STDPATH, 1); 172 | } 173 | 174 | if (pid1_magic) { 175 | pid1_magic_init(); 176 | 177 | int cfd = -1; 178 | if ((cfd = open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY)) != -1) { 179 | _fd(cfd); 180 | if (!(launchd_console = fdopen(cfd, "w"))) { 181 | (void)close(cfd); 182 | } 183 | } 184 | 185 | char *extra = ""; 186 | if (launchd_osinstaller) { 187 | extra = " in the OS Installer"; 188 | } else if (sflag) { 189 | extra = " in single-user mode"; 190 | } 191 | 192 | launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** launchd[1] has started up%s. ***", extra); 193 | if (launchd_use_gmalloc) { 194 | launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Using libgmalloc. ***"); 195 | } 196 | 197 | if (launchd_verbose_boot) { 198 | launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Verbose boot, will log to /dev/console. ***"); 199 | } 200 | 201 | if (launchd_shutdown_debugging) { 202 | launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Shutdown debugging is enabled. ***"); 203 | } 204 | 205 | if (launchd_log_shutdown) { 206 | launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Shutdown logging is enabled. ***"); 207 | } 208 | 209 | if (launchd_log_perf) { 210 | launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Performance logging is enabled. ***"); 211 | } 212 | 213 | if (launchd_log_debug) { 214 | launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Debug logging is enabled. ***"); 215 | } 216 | 217 | handle_pid1_crashes_separately(); 218 | 219 | /* Start the update thread. 220 | * 221 | * 222 | */ 223 | pthread_t t = NULL; 224 | (void)os_assumes_zero(pthread_create(&t, NULL, update_thread, NULL)); 225 | (void)os_assumes_zero(pthread_detach(t)); 226 | 227 | /* PID 1 doesn't have a flat namespace. */ 228 | launchd_flat_mach_namespace = false; 229 | fflush(launchd_console); 230 | } else { 231 | launchd_uid = getuid(); 232 | launchd_var_available = true; 233 | if (asprintf(&launchd_label, "com.apple.launchd.peruser.%u", launchd_uid) == 0) { 234 | launchd_label = "com.apple.launchd.peruser.unknown"; 235 | } 236 | 237 | struct passwd *pwent = getpwuid(launchd_uid); 238 | if (pwent) { 239 | launchd_username = strdup(pwent->pw_name); 240 | } else { 241 | launchd_username = "(unknown)"; 242 | } 243 | 244 | if (asprintf(&_launchd_database_dir, LAUNCHD_DB_PREFIX "/com.apple.launchd.peruser.%u", launchd_uid) == 0) { 245 | _launchd_database_dir = ""; 246 | } 247 | 248 | if (asprintf(&_launchd_log_dir, LAUNCHD_LOG_PREFIX "/com.apple.launchd.peruser.%u", launchd_uid) == 0) { 249 | _launchd_log_dir = ""; 250 | } 251 | 252 | if (launchd_allow_global_dyld_envvars) { 253 | launchd_syslog(LOG_WARNING, "Per-user launchd will allow DYLD_* environment variables in the global environment."); 254 | } 255 | 256 | ipc_server_init(); 257 | launchd_log_push(); 258 | 259 | auditinfo_addr_t auinfo; 260 | if (posix_assumes_zero(getaudit_addr(&auinfo, sizeof(auinfo))) != -1) { 261 | launchd_audit_session = auinfo.ai_asid; 262 | launchd_syslog(LOG_DEBUG, "Our audit session ID is %i", launchd_audit_session); 263 | } 264 | 265 | launchd_audit_port = _audit_session_self(); 266 | 267 | vproc_transaction_begin(NULL); 268 | vproc_transaction_end(NULL, NULL); 269 | 270 | launchd_syslog(LOG_DEBUG, "Per-user launchd started (UID/username): %u/%s.", launchd_uid, launchd_username); 271 | } 272 | 273 | monitor_networking_state(); 274 | jobmgr_init(sflag); 275 | 276 | launchd_runtime_init2(); 277 | launchd_runtime(); 278 | } 279 | 280 | void 281 | handle_pid1_crashes_separately(void) 282 | { 283 | struct sigaction fsa; 284 | 285 | fsa.sa_sigaction = fatal_signal_handler; 286 | fsa.sa_flags = SA_SIGINFO; 287 | sigemptyset(&fsa.sa_mask); 288 | 289 | (void)posix_assumes_zero(sigaction(SIGILL, &fsa, NULL)); 290 | (void)posix_assumes_zero(sigaction(SIGFPE, &fsa, NULL)); 291 | (void)posix_assumes_zero(sigaction(SIGBUS, &fsa, NULL)); 292 | (void)posix_assumes_zero(sigaction(SIGTRAP, &fsa, NULL)); 293 | (void)posix_assumes_zero(sigaction(SIGABRT, &fsa, NULL)); 294 | (void)posix_assumes_zero(sigaction(SIGSEGV, &fsa, NULL)); 295 | } 296 | 297 | void * 298 | update_thread(void *nothing __attribute__((unused))) 299 | { 300 | (void)posix_assumes_zero(setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD, IOPOL_THROTTLE)); 301 | 302 | while (launchd_sync_frequency) { 303 | sync(); 304 | sleep(launchd_sync_frequency); 305 | } 306 | 307 | launchd_syslog(LOG_DEBUG, "Update thread exiting."); 308 | return NULL; 309 | } 310 | 311 | #define PID1_CRASH_LOGFILE "/var/log/launchd-pid1.crash" 312 | 313 | /* This hack forces the dynamic linker to resolve these symbols ASAP */ 314 | static __attribute__((unused)) typeof(sync) *__junk_dyld_trick1 = sync; 315 | static __attribute__((unused)) typeof(sleep) *__junk_dyld_trick2 = sleep; 316 | static __attribute__((unused)) typeof(reboot) *__junk_dyld_trick3 = reboot; 317 | 318 | void 319 | do_pid1_crash_diagnosis_mode(const char *msg) 320 | { 321 | if (launchd_wsp) { 322 | kill(launchd_wsp, SIGKILL); 323 | sleep(3); 324 | launchd_wsp = 0; 325 | } 326 | 327 | while (launchd_shutdown_debugging && !do_pid1_crash_diagnosis_mode2(msg)) { 328 | sleep(1); 329 | } 330 | } 331 | 332 | int 333 | basic_fork(void) 334 | { 335 | int wstatus = 0; 336 | pid_t p; 337 | 338 | switch ((p = fork())) { 339 | case -1: 340 | launchd_syslog(LOG_ERR | LOG_CONSOLE, "Can't fork PID 1 copy for crash debugging: %m"); 341 | return p; 342 | case 0: 343 | return p; 344 | default: 345 | do { 346 | (void)waitpid(p, &wstatus, 0); 347 | } while(!WIFEXITED(wstatus)); 348 | 349 | fprintf(stdout, "PID 1 copy: exit status: %d\n", WEXITSTATUS(wstatus)); 350 | 351 | return 1; 352 | } 353 | 354 | return -1; 355 | } 356 | 357 | bool 358 | do_pid1_crash_diagnosis_mode2(const char *msg) 359 | { 360 | if (basic_fork() == 0) { 361 | /* Neuter our bootstrap port so that the shell doesn't try talking to us 362 | * while we're blocked waiting on it. 363 | */ 364 | if (launchd_console) { 365 | fflush(launchd_console); 366 | } 367 | 368 | task_set_bootstrap_port(mach_task_self(), MACH_PORT_NULL); 369 | if (basic_fork() != 0) { 370 | if (launchd_console) { 371 | fflush(launchd_console); 372 | } 373 | 374 | return true; 375 | } 376 | } else { 377 | return true; 378 | } 379 | 380 | int fd; 381 | revoke(_PATH_CONSOLE); 382 | if ((fd = open(_PATH_CONSOLE, O_RDWR)) == -1) { 383 | _exit(2); 384 | } 385 | if (login_tty(fd) == -1) { 386 | _exit(3); 387 | } 388 | 389 | setenv("TERM", "vt100", 1); 390 | fprintf(stdout, "\n"); 391 | fprintf(stdout, "Entering launchd PID 1 debugging mode...\n"); 392 | fprintf(stdout, "The PID 1 launchd has crashed %s.\n", msg); 393 | fprintf(stdout, "It has fork(2)ed itself for debugging.\n"); 394 | fprintf(stdout, "To debug the crashing thread of PID 1:\n"); 395 | fprintf(stdout, " gdb attach %d\n", getppid()); 396 | fprintf(stdout, "To exit this shell and shut down:\n"); 397 | fprintf(stdout, " kill -9 1\n"); 398 | fprintf(stdout, "A sample of PID 1 has been written to %s\n", PID1_CRASH_LOGFILE); 399 | fprintf(stdout, "\n"); 400 | fflush(stdout); 401 | 402 | execl(_PATH_BSHELL, "-sh", NULL); 403 | syslog(LOG_ERR, "can't exec %s for PID 1 crash debugging: %m", _PATH_BSHELL); 404 | _exit(EXIT_FAILURE); 405 | } 406 | 407 | void 408 | fatal_signal_handler(int sig, siginfo_t *si, void *uap __attribute__((unused))) 409 | { 410 | const char *doom_why = "at instruction"; 411 | char msg[128]; 412 | #if 0 413 | char *sample_args[] = { "/usr/bin/sample", "1", "1", "-file", PID1_CRASH_LOGFILE, NULL }; 414 | pid_t sample_p; 415 | int wstatus; 416 | #endif 417 | 418 | crash_addr = si->si_addr; 419 | crash_pid = si->si_pid; 420 | #if 0 421 | setenv("XPC_SERVICES_UNAVAILABLE", "1", 0); 422 | unlink(PID1_CRASH_LOGFILE); 423 | 424 | switch ((sample_p = vfork())) { 425 | case 0: 426 | execve(sample_args[0], sample_args, environ); 427 | _exit(EXIT_FAILURE); 428 | break; 429 | default: 430 | waitpid(sample_p, &wstatus, 0); 431 | break; 432 | case -1: 433 | break; 434 | } 435 | #endif 436 | switch (sig) { 437 | default: 438 | case 0: 439 | break; 440 | case SIGBUS: 441 | case SIGSEGV: 442 | doom_why = "trying to read/write"; 443 | case SIGILL: 444 | case SIGFPE: 445 | case SIGTRAP: 446 | snprintf(msg, sizeof(msg), "%s: %p (%s sent by PID %u)", doom_why, crash_addr, strsignal(sig), crash_pid); 447 | sync(); 448 | do_pid1_crash_diagnosis_mode(msg); 449 | sleep(3); 450 | reboot(0); 451 | break; 452 | } 453 | } 454 | 455 | void 456 | pid1_magic_init(void) 457 | { 458 | launchd_label = "com.apple.launchd"; 459 | launchd_username = "system"; 460 | 461 | _launchd_database_dir = LAUNCHD_DB_PREFIX "/com.apple.launchd"; 462 | _launchd_log_dir = LAUNCHD_LOG_PREFIX "/com.apple.launchd"; 463 | 464 | (void)posix_assumes_zero(setsid()); 465 | (void)posix_assumes_zero(chdir("/")); 466 | (void)posix_assumes_zero(setlogin("root")); 467 | 468 | #if !TARGET_OS_EMBEDDED 469 | auditinfo_addr_t auinfo = { 470 | .ai_termid = { 471 | .at_type = AU_IPv4 472 | }, 473 | .ai_asid = AU_ASSIGN_ASID, 474 | .ai_auid = AU_DEFAUDITID, 475 | .ai_flags = AU_SESSION_FLAG_IS_INITIAL, 476 | }; 477 | 478 | if (setaudit_addr(&auinfo, sizeof(auinfo)) == -1) { 479 | launchd_syslog(LOG_WARNING | LOG_CONSOLE, "Could not set audit session: %d: %s.", errno, strerror(errno)); 480 | _exit(EXIT_FAILURE); 481 | } 482 | 483 | launchd_audit_session = auinfo.ai_asid; 484 | launchd_syslog(LOG_DEBUG, "Audit Session ID: %i", launchd_audit_session); 485 | 486 | launchd_audit_port = _audit_session_self(); 487 | #endif // !TARGET_OS_EMBEDDED 488 | } 489 | 490 | char * 491 | launchd_copy_persistent_store(int type, const char *file) 492 | { 493 | char *result = NULL; 494 | if (!file) { 495 | file = ""; 496 | } 497 | 498 | switch (type) { 499 | case LAUNCHD_PERSISTENT_STORE_DB: 500 | (void)asprintf(&result, "%s/%s", _launchd_database_dir, file); 501 | break; 502 | case LAUNCHD_PERSISTENT_STORE_LOGS: 503 | (void)asprintf(&result, "%s/%s", _launchd_log_dir, file); 504 | break; 505 | default: 506 | break; 507 | } 508 | 509 | return result; 510 | } 511 | 512 | int 513 | _fd(int fd) 514 | { 515 | if (fd >= 0) { 516 | (void)posix_assumes_zero(fcntl(fd, F_SETFD, 1)); 517 | } 518 | return fd; 519 | } 520 | 521 | void 522 | launchd_shutdown(void) 523 | { 524 | int64_t now; 525 | 526 | if (launchd_shutting_down) { 527 | return; 528 | } 529 | 530 | runtime_ktrace0(RTKT_LAUNCHD_EXITING); 531 | 532 | launchd_shutting_down = true; 533 | launchd_log_push(); 534 | 535 | now = runtime_get_wall_time(); 536 | 537 | char *term_who = pid1_magic ? "System shutdown" : "Per-user launchd termination for "; 538 | launchd_syslog(LOG_INFO, "%s%s began", term_who, pid1_magic ? "" : launchd_username); 539 | 540 | os_assert(jobmgr_shutdown(root_jobmgr) != NULL); 541 | 542 | #if HAVE_LIBAUDITD 543 | if (pid1_magic) { 544 | (void)os_assumes_zero(audit_quick_stop()); 545 | } 546 | #endif 547 | } 548 | 549 | void 550 | launchd_SessionCreate(void) 551 | { 552 | #if !TARGET_OS_EMBEDDED 553 | auditinfo_addr_t auinfo = { 554 | .ai_termid = { .at_type = AU_IPv4 }, 555 | .ai_asid = AU_ASSIGN_ASID, 556 | .ai_auid = getuid(), 557 | .ai_flags = 0, 558 | }; 559 | if (setaudit_addr(&auinfo, sizeof(auinfo)) == 0) { 560 | char session[16]; 561 | snprintf(session, sizeof(session), "%x", auinfo.ai_asid); 562 | setenv("SECURITYSESSIONID", session, 1); 563 | } else { 564 | launchd_syslog(LOG_WARNING, "Could not set audit session: %d: %s.", errno, strerror(errno)); 565 | } 566 | #endif // !TARGET_OS_EMBEDDED 567 | } 568 | 569 | void 570 | testfd_or_openfd(int fd, const char *path, int flags) 571 | { 572 | int tmpfd; 573 | 574 | if (-1 != (tmpfd = dup(fd))) { 575 | (void)posix_assumes_zero(runtime_close(tmpfd)); 576 | } else { 577 | if (-1 == (tmpfd = open(path, flags | O_NOCTTY, DEFFILEMODE))) { 578 | launchd_syslog(LOG_ERR, "open(\"%s\", ...): %m", path); 579 | } else if (tmpfd != fd) { 580 | (void)posix_assumes_zero(dup2(tmpfd, fd)); 581 | (void)posix_assumes_zero(runtime_close(tmpfd)); 582 | } 583 | } 584 | } 585 | 586 | bool 587 | get_network_state(void) 588 | { 589 | struct ifaddrs *ifa, *ifai; 590 | bool up = false; 591 | int r; 592 | 593 | /* Workaround 4978696: getifaddrs() reports false ENOMEM */ 594 | while ((r = getifaddrs(&ifa)) == -1 && errno == ENOMEM) { 595 | launchd_syslog(LOG_DEBUG, "Worked around bug: 4978696"); 596 | (void)posix_assumes_zero(sched_yield()); 597 | } 598 | 599 | if (posix_assumes_zero(r) == -1) { 600 | return network_up; 601 | } 602 | 603 | for (ifai = ifa; ifai; ifai = ifai->ifa_next) { 604 | if (!(ifai->ifa_flags & IFF_UP)) { 605 | continue; 606 | } 607 | if (ifai->ifa_flags & IFF_LOOPBACK) { 608 | continue; 609 | } 610 | if (ifai->ifa_addr->sa_family != AF_INET && ifai->ifa_addr->sa_family != AF_INET6) { 611 | continue; 612 | } 613 | up = true; 614 | break; 615 | } 616 | 617 | freeifaddrs(ifa); 618 | 619 | return up; 620 | } 621 | 622 | void 623 | monitor_networking_state(void) 624 | { 625 | int pfs = _fd(socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT)); 626 | struct kev_request kev_req; 627 | 628 | network_up = get_network_state(); 629 | 630 | if (pfs == -1) { 631 | (void)os_assumes_zero(errno); 632 | return; 633 | } 634 | 635 | memset(&kev_req, 0, sizeof(kev_req)); 636 | kev_req.vendor_code = KEV_VENDOR_APPLE; 637 | kev_req.kev_class = KEV_NETWORK_CLASS; 638 | 639 | if (posix_assumes_zero(ioctl(pfs, SIOCSKEVFILT, &kev_req)) == -1) { 640 | runtime_close(pfs); 641 | return; 642 | } 643 | 644 | (void)posix_assumes_zero(kevent_mod(pfs, EVFILT_READ, EV_ADD, 0, 0, &kqpfsystem_callback)); 645 | } 646 | 647 | void 648 | pfsystem_callback(void *obj __attribute__((unused)), struct kevent *kev) 649 | { 650 | bool new_networking_state; 651 | char buf[1024]; 652 | 653 | (void)posix_assumes_zero(read((int)kev->ident, &buf, sizeof(buf))); 654 | 655 | new_networking_state = get_network_state(); 656 | 657 | if (new_networking_state != network_up) { 658 | network_up = new_networking_state; 659 | jobmgr_dispatch_all_semaphores(root_jobmgr); 660 | } 661 | } 662 | -------------------------------------------------------------------------------- /src/launchd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #ifndef __LAUNCHD_H__ 22 | #define __LAUNCHD_H__ 23 | 24 | #include 25 | #include 26 | #include "launch.h" 27 | #include "bootstrap.h" 28 | #include "runtime.h" 29 | 30 | struct kevent; 31 | struct conncb; 32 | 33 | extern bool pid1_magic; 34 | extern bool launchd_shutting_down; 35 | extern bool fake_launchd_shutting_down; 36 | extern bool network_up; 37 | extern FILE *launchd_console; 38 | extern uid_t launchd_uid; 39 | 40 | void launchd_SessionCreate(void); 41 | void launchd_shutdown(void); 42 | 43 | enum { 44 | LAUNCHD_PERSISTENT_STORE_DB, 45 | LAUNCHD_PERSISTENT_STORE_LOGS, 46 | }; 47 | char *launchd_copy_persistent_store(int type, const char *file); 48 | 49 | int _fd(int fd); 50 | 51 | #endif /* __LAUNCHD_H__ */ 52 | -------------------------------------------------------------------------------- /src/log.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "job_reply.h" 4 | 5 | #include "launchd.h" 6 | #include "launch_internal.h" 7 | #include "vproc_internal.h" 8 | #include "log.h" 9 | 10 | #define ROUND_TO_64BIT_WORD_SIZE(x) ((x + 7) & ~7) 11 | #define LAUNCHD_DEBUG_LOG "launchd-debug.%s.log" 12 | #define LAUNCHD_PERF_LOG "launchd-perf.%s.log" 13 | #define LAUNCHD_SHUTDOWN_LOG "launchd-shutdown.%s.log" 14 | #define LAUNCHD_LOWLEVEL_LOG "launchd-lowlevel.%s.log" 15 | 16 | os_redirect_assumes(_launchd_os_redirect); 17 | 18 | char *launchd_username = "unknown"; 19 | char *launchd_label = "com.apple.launchd.unknown"; 20 | mach_port_t launchd_drain_reply_port; 21 | bool launchd_var_available = false; 22 | int64_t launchd_system_start; 23 | 24 | static FILE *_launchd_shutdown_log; 25 | static FILE *_launchd_debug_log; 26 | static FILE *_launchd_perf_log; 27 | static STAILQ_HEAD(, logmsg_s) _launchd_logq = STAILQ_HEAD_INITIALIZER(_launchd_logq); 28 | static size_t _launchd_logq_sz; 29 | static size_t _launchd_logq_cnt; 30 | static int _launchd_log_up2 = LOG_UPTO(LOG_NOTICE); 31 | 32 | static int64_t _launchd_shutdown_start; 33 | 34 | struct _launchd_open_log_ctx_s { 35 | const char *path; 36 | FILE **filep; 37 | }; 38 | 39 | static void 40 | _launchd_open_log_once(void *ctx) 41 | { 42 | struct _launchd_open_log_ctx_s *ctx2 = ctx; 43 | const char *path = ctx2->path; 44 | FILE **filep = ctx2->filep; 45 | 46 | char saved[PATH_MAX]; 47 | snprintf(saved, sizeof(saved), "%s.1", path); 48 | (void)rename(path, saved); 49 | 50 | FILE *file = fopen(path, "w"); 51 | if (file) { 52 | (void)_fd(fileno(file)); 53 | *filep = file; 54 | } else if (launchd_console) { 55 | fprintf(launchd_console, "Could not open %s: %d: %s\n", path, errno, strerror(errno)); 56 | } 57 | } 58 | 59 | static void 60 | _launchd_shutdown_start_once(void *ctx __attribute__((unused))) 61 | { 62 | _launchd_shutdown_start = runtime_get_wall_time(); 63 | } 64 | 65 | int 66 | runtime_setlogmask(int maskpri) 67 | { 68 | _launchd_log_up2 = maskpri; 69 | return _launchd_log_up2; 70 | } 71 | 72 | static bool 73 | _logmsg_add(struct launchd_syslog_attr *attr, int err_num, const char *msg) 74 | { 75 | size_t lm_sz = sizeof(struct logmsg_s) + strlen(msg) + strlen(attr->from_name) + strlen(attr->about_name) + strlen(attr->session_name) + 4; 76 | char *data_off; 77 | struct logmsg_s *lm; 78 | 79 | /* Force the unpacking for the log_drain cause unalignment faults. */ 80 | lm_sz = ROUND_TO_64BIT_WORD_SIZE(lm_sz); 81 | 82 | if (unlikely((lm = calloc(1, lm_sz)) == NULL)) { 83 | return false; 84 | } 85 | 86 | data_off = lm->data; 87 | 88 | lm->when = runtime_get_wall_time(); 89 | lm->from_pid = attr->from_pid; 90 | lm->about_pid = attr->about_pid; 91 | lm->err_num = err_num; 92 | lm->pri = attr->priority; 93 | lm->obj_sz = lm_sz; 94 | lm->msg = data_off; 95 | data_off += sprintf(data_off, "%s", msg) + 1; 96 | lm->from_name = data_off; 97 | data_off += sprintf(data_off, "%s", attr->from_name) + 1; 98 | lm->about_name = data_off; 99 | data_off += sprintf(data_off, "%s", attr->about_name) + 1; 100 | lm->session_name = data_off; 101 | data_off += sprintf(data_off, "%s", attr->session_name) + 1; 102 | 103 | STAILQ_INSERT_TAIL(&_launchd_logq, lm, sqe); 104 | _launchd_logq_sz += lm_sz; 105 | _launchd_logq_cnt++; 106 | 107 | return true; 108 | } 109 | 110 | static void 111 | _logmsg_remove(struct logmsg_s *lm) 112 | { 113 | STAILQ_REMOVE(&_launchd_logq, lm, logmsg_s, sqe); 114 | _launchd_logq_sz -= lm->obj_sz; 115 | _launchd_logq_cnt--; 116 | 117 | free(lm); 118 | } 119 | 120 | bool 121 | _launchd_os_redirect(const char *message) 122 | { 123 | launchd_syslog(LOG_ERR, "%s", message); 124 | return true; 125 | } 126 | 127 | void 128 | launchd_syslog(int pri, const char *message, ...) 129 | { 130 | struct launchd_syslog_attr attr = { 131 | .from_name = launchd_label, 132 | .about_name = launchd_label, 133 | .session_name = pid1_magic ? "System" : "Background", 134 | .priority = pri, 135 | .from_uid = launchd_uid, 136 | .from_pid = getpid(), 137 | .about_pid = getpid(), 138 | }; 139 | 140 | va_list ap; 141 | 142 | va_start(ap, message); 143 | launchd_vsyslog(&attr, message, ap); 144 | va_end(ap); 145 | } 146 | 147 | void 148 | launchd_vsyslog(struct launchd_syslog_attr *attr, const char *fmt, va_list args) 149 | { 150 | int saved_errno = errno; 151 | char message[2048]; 152 | 153 | static dispatch_once_t perf_once = 0; 154 | static dispatch_once_t shutdown_once = 0; 155 | static dispatch_once_t shutdown_start_once = 0; 156 | static dispatch_once_t debug_once = 0; 157 | 158 | bool echo2console = (attr->priority & LOG_CONSOLE); 159 | attr->priority &= ~LOG_CONSOLE; 160 | if (attr->priority == LOG_APPLEONLY && launchd_apple_internal) { 161 | attr->priority = LOG_NOTICE; 162 | } 163 | 164 | FILE *log2here = NULL; 165 | 166 | /* launchctl is responsible for mounting /var as read-write. So we need to 167 | * wait until /var/log is available before trying to log anything to our log 168 | * anything to our auxilliary log files. This is kind of a hack because 169 | * we'll lose the first few relevant messages at boot for debug and 170 | * performance logging, but the loss isn't too bad. 171 | */ 172 | if (launchd_var_available) { 173 | /* This file is for logging low-level errors where we can't necessarily be 174 | * assured that we can write to the console or use syslog. 175 | */ 176 | char *store = launchd_copy_persistent_store(LAUNCHD_PERSISTENT_STORE_LOGS, NULL); 177 | char path[PATH_MAX]; 178 | 179 | if (attr->priority == LOG_PERF) { 180 | if (launchd_log_perf) { 181 | (void)snprintf(path, sizeof(path), "%s" LAUNCHD_PERF_LOG, store, launchd_username); 182 | 183 | struct _launchd_open_log_ctx_s ctx2 = { 184 | .path = path, 185 | .filep = &_launchd_perf_log, 186 | }; 187 | dispatch_once_f(&perf_once, &ctx2, _launchd_open_log_once); 188 | log2here = _launchd_perf_log; 189 | } 190 | 191 | // Don't log performance messages to the normal syslog store. 192 | attr->priority = LOG_DEBUG + 1; 193 | } else { 194 | if (launchd_shutting_down && launchd_log_shutdown) { 195 | dispatch_once_f(&shutdown_start_once, NULL, _launchd_shutdown_start_once); 196 | 197 | (void)snprintf(path, sizeof(path), "%s" LAUNCHD_SHUTDOWN_LOG, store, launchd_username); 198 | 199 | struct _launchd_open_log_ctx_s ctx2 = { 200 | .path = path, 201 | .filep = &_launchd_shutdown_log, 202 | }; 203 | dispatch_once_f(&shutdown_once, &ctx2, _launchd_open_log_once); 204 | log2here = _launchd_shutdown_log; 205 | } else if (launchd_log_debug) { 206 | (void)snprintf(path, sizeof(path), "%s" LAUNCHD_DEBUG_LOG, store, launchd_username); 207 | 208 | struct _launchd_open_log_ctx_s ctx2 = { 209 | .path = path, 210 | .filep = &_launchd_debug_log, 211 | }; 212 | dispatch_once_f(&debug_once, &ctx2, _launchd_open_log_once); 213 | log2here = _launchd_debug_log; 214 | } 215 | } 216 | 217 | free(store); 218 | 219 | } 220 | 221 | vsnprintf(message, sizeof(message), fmt, args); 222 | if (echo2console && launchd_console) { 223 | fprintf(launchd_console, "%-32s %-8u %-64s %-8u %s\n", attr->from_name, attr->from_pid, attr->about_name, attr->about_pid, message); 224 | } 225 | 226 | if (log2here) { 227 | int64_t delta = 0; 228 | if (log2here == _launchd_shutdown_log) { 229 | delta = runtime_get_wall_time() - _launchd_shutdown_start; 230 | } else { 231 | delta = runtime_get_wall_time() - launchd_system_start; 232 | } 233 | 234 | fprintf(log2here, "%-8lld %-32s %-8u %-24s %-8u %s\n", delta, attr->from_name, attr->from_pid, attr->about_name, attr->about_pid, message); 235 | } 236 | 237 | if ((LOG_MASK(attr->priority) & _launchd_log_up2)) { 238 | _logmsg_add(attr, saved_errno, message); 239 | } 240 | } 241 | 242 | static kern_return_t 243 | _launchd_log_pack(vm_offset_t *outval, mach_msg_type_number_t *outvalCnt) 244 | { 245 | struct logmsg_s *lm; 246 | void *offset; 247 | 248 | *outvalCnt = _launchd_logq_sz; 249 | 250 | mig_allocate(outval, *outvalCnt); 251 | 252 | if (unlikely(*outval == 0)) { 253 | return 1; 254 | } 255 | 256 | offset = (void *)*outval; 257 | while ((lm = STAILQ_FIRST(&_launchd_logq))) { 258 | lm->from_name_offset = lm->from_name - (char *)lm; 259 | lm->about_name_offset = lm->about_name - (char *)lm; 260 | lm->msg_offset = lm->msg - (char *)lm; 261 | lm->session_name_offset = lm->session_name - (char *)lm; 262 | 263 | memcpy(offset, lm, lm->obj_sz); 264 | 265 | offset += lm->obj_sz; 266 | 267 | _logmsg_remove(lm); 268 | } 269 | 270 | return 0; 271 | } 272 | 273 | static void 274 | _launchd_log_uncork_pending_drain(void) 275 | { 276 | mach_msg_type_number_t outvalCnt; 277 | mach_port_t tmp_port; 278 | vm_offset_t outval; 279 | 280 | if (!launchd_drain_reply_port) { 281 | return; 282 | } 283 | 284 | if (_launchd_logq_cnt == 0) { 285 | return; 286 | } 287 | 288 | if (_launchd_log_pack(&outval, &outvalCnt) != 0) { 289 | return; 290 | } 291 | 292 | tmp_port = launchd_drain_reply_port; 293 | launchd_drain_reply_port = MACH_PORT_NULL; 294 | 295 | if (unlikely(errno = job_mig_log_drain_reply(tmp_port, 0, outval, outvalCnt))) { 296 | if (errno != MACH_SEND_INVALID_DEST) { 297 | (void)os_assumes_zero(errno); 298 | } 299 | (void)os_assumes_zero(launchd_mport_deallocate(tmp_port)); 300 | } 301 | 302 | mig_deallocate(outval, outvalCnt); 303 | } 304 | 305 | void 306 | launchd_log_push(void) 307 | { 308 | vm_offset_t outval = 0; 309 | mach_msg_type_number_t outvalCnt = 0; 310 | 311 | if (!pid1_magic) { 312 | if (_launchd_perf_log) { 313 | (void)fflush(_launchd_perf_log); 314 | } 315 | if (_launchd_shutdown_log) { 316 | (void)fflush(_launchd_shutdown_log); 317 | } 318 | if (_launchd_debug_log) { 319 | (void)fflush(_launchd_debug_log); 320 | } 321 | 322 | if (_launchd_logq_cnt && _launchd_log_pack(&outval, &outvalCnt) == 0) { 323 | (void)_vprocmgr_log_forward(inherited_bootstrap_port, (void *)outval, outvalCnt); 324 | mig_deallocate(outval, outvalCnt); 325 | } 326 | } else { 327 | _launchd_log_uncork_pending_drain(); 328 | } 329 | } 330 | 331 | kern_return_t 332 | launchd_log_forward(uid_t forward_uid, gid_t forward_gid, vm_offset_t inval, mach_msg_type_number_t invalCnt) 333 | { 334 | struct logmsg_s *lm, *lm_walk; 335 | mach_msg_type_number_t data_left = invalCnt; 336 | 337 | if (inval == 0) { 338 | return 0; 339 | } 340 | 341 | for (lm_walk = (struct logmsg_s *)inval; (data_left > 0) && (lm_walk->obj_sz <= data_left); lm_walk = ((void *)lm_walk + lm_walk->obj_sz)) { 342 | /* malloc(3) returns non-NULL when you ask for zero bytes. If our object 343 | * is zero bytes, something is wrong. 344 | */ 345 | if (lm_walk->obj_sz == 0) { 346 | launchd_syslog(LOG_WARNING, "Encountered a log message of size 0 with %u bytes left in forwarded data. Ignoring remaining messages.", data_left); 347 | break; 348 | } 349 | 350 | if (!(lm = malloc(lm_walk->obj_sz))) { 351 | launchd_syslog(LOG_WARNING, "Failed to allocate %llu bytes for log message with %u bytes left in forwarded data. Ignoring remaining messages.", lm_walk->obj_sz, data_left); 352 | break; 353 | } 354 | 355 | memcpy(lm, lm_walk, lm_walk->obj_sz); 356 | lm->sender_uid = forward_uid; 357 | lm->sender_gid = forward_gid; 358 | 359 | lm->from_name += (size_t)lm; 360 | lm->about_name += (size_t)lm; 361 | lm->msg += (size_t)lm; 362 | lm->session_name += (size_t)lm; 363 | 364 | STAILQ_INSERT_TAIL(&_launchd_logq, lm, sqe); 365 | _launchd_logq_sz += lm->obj_sz; 366 | _launchd_logq_cnt++; 367 | 368 | data_left -= lm->obj_sz; 369 | } 370 | 371 | mig_deallocate(inval, invalCnt); 372 | 373 | return 0; 374 | } 375 | 376 | kern_return_t 377 | launchd_log_drain(mach_port_t srp, vm_offset_t *outval, mach_msg_type_number_t *outvalCnt) 378 | { 379 | (void)os_assumes_zero(launchd_drain_reply_port); 380 | 381 | if ((_launchd_logq_cnt == 0) || launchd_shutting_down) { 382 | launchd_drain_reply_port = srp; 383 | (void)os_assumes_zero(launchd_mport_notify_req(launchd_drain_reply_port, MACH_NOTIFY_DEAD_NAME)); 384 | 385 | return MIG_NO_REPLY; 386 | } 387 | 388 | return _launchd_log_pack(outval, outvalCnt); 389 | } 390 | 391 | void 392 | launchd_closelog(void) 393 | { 394 | launchd_log_push(); 395 | 396 | if (_launchd_shutdown_log) { 397 | (void)fflush(_launchd_shutdown_log); 398 | (void)runtime_fsync(fileno(_launchd_shutdown_log)); 399 | } 400 | } 401 | -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __LAUNCHD_LOG_H__ 2 | #define __LAUNCHD_LOG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | extern char *launchd_username; 21 | extern char *launchd_label; 22 | extern mach_port_t launchd_drain_reply_port; 23 | extern bool launchd_var_available; 24 | extern int64_t launchd_system_start; 25 | 26 | struct launchd_syslog_attr { 27 | const char *from_name; 28 | const char *about_name; 29 | const char *session_name; 30 | int priority; 31 | uid_t from_uid; 32 | pid_t from_pid; 33 | pid_t about_pid; 34 | }; 35 | 36 | /* These constants must not have the high bit set so we can safely mask them 37 | * mask them with LOG_CONSOLE. 38 | */ 39 | #define LOG_PERF 0x5252615d 40 | #define LOG_APPLEONLY 0x4141504c 41 | #define LOG_CONSOLE (1 << 31) 42 | 43 | __attribute__((visibility("default"))) 44 | __attribute__((used)) 45 | extern bool 46 | _launchd_os_redirect(const char *message); 47 | 48 | int 49 | runtime_setlogmask(int maskpri); 50 | 51 | void 52 | launchd_closelog(void); 53 | 54 | __attribute__((format(printf, 2, 3))) 55 | void 56 | launchd_syslog(int pri, const char *message, ...); 57 | 58 | __attribute__((format(printf, 2, 0))) 59 | void 60 | launchd_vsyslog(struct launchd_syslog_attr *attr, const char *message, va_list args); 61 | 62 | void 63 | launchd_log_push(void); 64 | 65 | kern_return_t 66 | launchd_log_forward(uid_t forward_uid, gid_t forward_gid, vm_offset_t inval, mach_msg_type_number_t invalCnt); 67 | 68 | kern_return_t 69 | launchd_log_drain(mach_port_t srp, vm_offset_t *outval, mach_msg_type_number_t *outvalCnt); 70 | 71 | #endif /* __LAUNCHD_LOG_H__ */ 72 | -------------------------------------------------------------------------------- /src/protocol_jobmgr.defs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | /* 21 | * bootstrap -- fundamental service initiator and port server 22 | * Mike DeMoney, NeXT, Inc. 23 | * Copyright, 1990. All rights reserved. 24 | */ 25 | 26 | subsystem bootstrap 400; 27 | 28 | #include 29 | #include 30 | #include "launchd_mig_types.defs" 31 | import "bootstrap_public.h"; 32 | import "bootstrap_private.h"; 33 | 34 | userprefix vproc_mig_; 35 | serverprefix job_mig_; 36 | 37 | routine create_server( 38 | __bs_port : job_t; 39 | __server_cmd : cmd_t; 40 | __server_uid : natural_t; 41 | __on_demand : boolean_t; 42 | ServerAuditToken __token : audit_token_t; 43 | out __server_port : mach_port_make_send_t); 44 | 45 | skip; /* Last used in 10.4. Was bootstrap_unprivileged() */ 46 | 47 | routine check_in( 48 | __bs_port : job_t; 49 | __service_name : name_t; 50 | ServerAuditToken __token : audit_token_t; 51 | out __service_port : mach_port_move_receive_t); 52 | 53 | routine register( 54 | __bs_port : job_t; 55 | ServerAuditToken __token : audit_token_t; 56 | __service_name : name_t; 57 | __service_port : mach_port_t); 58 | 59 | routine look_up( 60 | __bs_port : job_t; 61 | ServerAuditToken __token : audit_token_t; 62 | __service_name : name_t; 63 | out __service_port : mach_port_send_t); 64 | 65 | skip; /* last used in 10.4 */ 66 | 67 | routine parent( 68 | __bs_port : job_t; 69 | out __parent_port : mach_port_send_t); 70 | 71 | skip; /* last used in 10.4 */ 72 | 73 | routine info( 74 | __bs_port : job_t; 75 | out __service_names : name_array_t, dealloc; 76 | out __service_active : bootstrap_status_array_t, dealloc); 77 | 78 | routine subset( 79 | __bs_port : job_t; 80 | __requestor_port: mach_port_t; 81 | out __subset_port : mach_port_make_send_t); 82 | 83 | routine create_service( 84 | __bs_port : job_t; 85 | __service_name : name_t; 86 | out __service_port : mach_port_t); 87 | 88 | routine transfer_subset( 89 | __bs_port : job_t; 90 | out __bs_reqport : mach_port_t; 91 | out __bs_rcvright : mach_port_move_receive_t; 92 | out __service_names : name_array_t, dealloc; 93 | out __service_pids : pointer_t, dealloc; 94 | out __service_ports : mach_port_array_t, dealloc); 95 | 96 | routine getsocket( 97 | __bs_port : job_t; 98 | out __sockpath : name_t); 99 | 100 | routine spawn( 101 | __bs_port : job_t; 102 | ServerAuditToken __token : audit_token_t; 103 | __chars : _internal_string_t; 104 | __argc : uint32_t; 105 | __envc : uint32_t; 106 | __flags : uint64_t; 107 | __umask : uint16_t; 108 | out __pid : pid_t; 109 | out __obsvr_port : mach_port_make_send_t); 110 | 111 | routine wait( 112 | __bs_port : job_t; 113 | sreplyport __rport : mach_port_make_send_once_t; 114 | ServerAuditToken __token : audit_token_t; 115 | out __waitval : integer_t); 116 | 117 | routine uncork_fork( 118 | __bs_port : job_t; 119 | ServerAuditToken __token : audit_token_t); 120 | 121 | /* Essentially the inverse of bootstrap_unprivileged() */ 122 | routine get_self( 123 | __bs_port : job_t; 124 | ServerAuditToken __token : audit_token_t; 125 | out __job_port : mach_port_make_send_t); 126 | -------------------------------------------------------------------------------- /src/runtime.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | 21 | #ifndef __LAUNCHD_RUNTIME_H__ 22 | #define __LAUNCHD_RUNTIME_H__ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "kill2.h" 34 | #include "ktrace.h" 35 | #include "log.h" 36 | 37 | #define likely(x) __builtin_expect((bool)(x), true) 38 | #define unlikely(x) __builtin_expect((bool)(x), false) 39 | 40 | struct ldcred { 41 | uid_t euid; 42 | uid_t uid; 43 | gid_t egid; 44 | gid_t gid; 45 | pid_t pid; 46 | au_asid_t asid; 47 | mach_port_t asport; 48 | }; 49 | 50 | typedef void (*kq_callback)(void *, struct kevent *); 51 | typedef boolean_t (*mig_callback)(mach_msg_header_t *, mach_msg_header_t *); 52 | typedef void (*timeout_callback)(void); 53 | 54 | extern bool launchd_verbose_boot; 55 | /* Configuration knobs set in do_file_init(). */ 56 | extern bool launchd_shutdown_debugging; 57 | extern bool launchd_use_gmalloc; 58 | extern bool launchd_malloc_log_stacks; 59 | extern bool launchd_log_shutdown; 60 | extern bool launchd_log_debug; 61 | extern bool launchd_log_perf; 62 | extern bool launchd_trap_sigkill_bugs; 63 | extern bool launchd_no_jetsam_perm_check; 64 | extern bool launchd_osinstaller; 65 | extern bool launchd_allow_global_dyld_envvars; 66 | #if TARGET_OS_EMBEDDED 67 | extern bool launchd_appletv; 68 | #endif 69 | 70 | extern bool launchd_runtime_busy_time; 71 | extern mach_port_t inherited_bootstrap_port; 72 | extern size_t runtime_busy_cnt; 73 | extern int32_t launchd_sync_frequency; 74 | extern pid_t launchd_wsp; 75 | 76 | mach_port_t runtime_get_kernel_port(void); 77 | extern boolean_t launchd_internal_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply); 78 | 79 | void runtime_add_ref(void); 80 | void runtime_del_ref(void); 81 | void runtime_add_weak_ref(void); 82 | void runtime_del_weak_ref(void); 83 | void runtime_install_timer(void); 84 | void runtime_remove_timer(void); 85 | 86 | void launchd_runtime_init(void); 87 | void launchd_runtime_init2(void); 88 | void launchd_runtime(void) __attribute__((noreturn)); 89 | 90 | void launchd_log_vm_stats(void); 91 | 92 | int runtime_close(int fd); 93 | int runtime_fsync(int fd); 94 | 95 | #define RUNTIME_ADVISABLE_IDLE_TIMEOUT 30 96 | 97 | void runtime_set_timeout(timeout_callback to_cb, unsigned int sec); 98 | kern_return_t runtime_add_mport(mach_port_t name, mig_callback demux); 99 | kern_return_t runtime_remove_mport(mach_port_t name); 100 | void runtime_record_caller_creds(audit_token_t *token); 101 | struct ldcred *runtime_get_caller_creds(void); 102 | audit_token_t *runtime_get_caller_token(void); 103 | 104 | const char *signal_to_C_name(unsigned int sig); 105 | const char *reboot_flags_to_C_names(unsigned int flags); 106 | 107 | int kevent_bulk_mod(struct kevent *kev, size_t kev_cnt); 108 | int kevent_mod(uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t data, void *udata); 109 | void log_kevent_struct(int level, struct kevent *kev_base, int indx); 110 | 111 | pid_t runtime_fork(mach_port_t bsport); 112 | 113 | mach_msg_return_t launchd_exc_runtime_once(mach_port_t port, mach_msg_size_t rcv_msg_size, mach_msg_size_t send_msg_size, mig_reply_error_t *bufRequest, mig_reply_error_t *bufReply, mach_msg_timeout_t to); 114 | 115 | int64_t runtime_get_wall_time(void) __attribute__((warn_unused_result)); 116 | uint64_t runtime_get_opaque_time(void) __attribute__((warn_unused_result)); 117 | uint64_t runtime_get_opaque_time_of_event(void) __attribute__((pure, warn_unused_result)); 118 | uint64_t runtime_opaque_time_to_nano(uint64_t o) __attribute__((const, warn_unused_result)); 119 | uint64_t runtime_get_nanoseconds_since(uint64_t o) __attribute__((pure, warn_unused_result)); 120 | 121 | kern_return_t launchd_set_bport(mach_port_t name); 122 | kern_return_t launchd_get_bport(mach_port_t *name); 123 | kern_return_t launchd_mport_notify_req(mach_port_t name, mach_msg_id_t which); 124 | kern_return_t launchd_mport_create_recv(mach_port_t *name); 125 | kern_return_t launchd_mport_deallocate(mach_port_t name); 126 | kern_return_t launchd_mport_make_send(mach_port_t name); 127 | kern_return_t launchd_mport_copy_send(mach_port_t name); 128 | kern_return_t launchd_mport_make_send_once(mach_port_t name, mach_port_t *so); 129 | kern_return_t launchd_mport_close_recv(mach_port_t name); 130 | 131 | uint64_t runtime_get_uniqueid(void); 132 | 133 | #endif /* __LAUNCHD_RUNTIME_H__ */ 134 | -------------------------------------------------------------------------------- /support/launchproxy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | #include "config.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #if !TARGET_OS_EMBEDDED 40 | #include 41 | #include 42 | #endif // !TARGET_OS_EMBEDDED 43 | 44 | #include "launch.h" 45 | 46 | static int kq = 0; 47 | 48 | static void find_fds(launch_data_t o, const char *key __attribute__((unused)), void *context __attribute__((unused))) 49 | { 50 | struct kevent kev; 51 | size_t i; 52 | int fd; 53 | 54 | switch (launch_data_get_type(o)) { 55 | case LAUNCH_DATA_FD: 56 | fd = launch_data_get_fd(o); 57 | if (-1 == fd) 58 | break; 59 | fcntl(fd, F_SETFD, 1); 60 | EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, NULL); 61 | if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) 62 | syslog(LOG_DEBUG, "kevent(%d): %m", fd); 63 | break; 64 | case LAUNCH_DATA_ARRAY: 65 | for (i = 0; i < launch_data_array_get_count(o); i++) 66 | find_fds(launch_data_array_get_index(o, i), NULL, NULL); 67 | break; 68 | case LAUNCH_DATA_DICTIONARY: 69 | launch_data_dict_iterate(o, find_fds, NULL); 70 | break; 71 | default: 72 | break; 73 | } 74 | } 75 | 76 | int main(int argc __attribute__((unused)), char *argv[]) 77 | { 78 | struct timespec timeout = { 10, 0 }; 79 | struct sockaddr_storage ss; 80 | socklen_t slen = (socklen_t)sizeof ss; 81 | struct kevent kev; 82 | int r, ec = EXIT_FAILURE; 83 | launch_data_t tmp, resp, msg = launch_data_alloc(LAUNCH_DATA_STRING); 84 | const char *prog = argv[1]; 85 | bool w = false, dupstdout = true, dupstderr = true; 86 | 87 | launch_data_set_string(msg, LAUNCH_KEY_CHECKIN); 88 | 89 | openlog(getprogname(), LOG_PERROR|LOG_PID|LOG_CONS, LOG_LAUNCHD); 90 | 91 | kq = kqueue(); 92 | 93 | if ((resp = launch_msg(msg)) == NULL) { 94 | syslog(LOG_ERR, "launch_msg(%s): %m", LAUNCH_KEY_CHECKIN); 95 | goto out; 96 | } 97 | 98 | launch_data_free(msg); 99 | 100 | tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS); 101 | if (tmp) { 102 | find_fds(tmp, NULL, NULL); 103 | } else { 104 | syslog(LOG_ERR, "No FDs found to answer requests on!"); 105 | goto out; 106 | } 107 | 108 | tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_TIMEOUT); 109 | if (tmp) 110 | timeout.tv_sec = (int)launch_data_get_integer(tmp); 111 | 112 | tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_PROGRAM); 113 | if (tmp) 114 | prog = launch_data_get_string(tmp); 115 | 116 | tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_INETDCOMPATIBILITY); 117 | if (tmp) { 118 | tmp = launch_data_dict_lookup(tmp, LAUNCH_JOBINETDCOMPATIBILITY_WAIT); 119 | if (tmp) 120 | w = launch_data_get_bool(tmp); 121 | } 122 | 123 | if (launch_data_dict_lookup(resp, LAUNCH_JOBKEY_STANDARDOUTPATH)) 124 | dupstdout = false; 125 | 126 | if (launch_data_dict_lookup(resp, LAUNCH_JOBKEY_STANDARDERRORPATH)) 127 | dupstderr = false; 128 | 129 | if (!w) 130 | signal(SIGCHLD, SIG_IGN); 131 | 132 | for (;;) { 133 | if ((r = kevent(kq, NULL, 0, &kev, 1, &timeout)) == -1) { 134 | syslog(LOG_DEBUG, "kevent(): %m"); 135 | goto out; 136 | } else if (r == 0) { 137 | ec = EXIT_SUCCESS; 138 | goto out; 139 | } 140 | 141 | if (w) { 142 | dup2((int)kev.ident, STDIN_FILENO); 143 | if (dupstdout) 144 | dup2((int)kev.ident, STDOUT_FILENO); 145 | if (dupstderr) 146 | dup2((int)kev.ident, STDERR_FILENO); 147 | execv(prog, argv + 1); 148 | syslog(LOG_ERR, "execv(): %m"); 149 | exit(EXIT_FAILURE); 150 | } 151 | 152 | if ((r = accept((int)kev.ident, (struct sockaddr *)&ss, &slen)) == -1) { 153 | if (errno == EWOULDBLOCK) 154 | continue; 155 | syslog(LOG_WARNING, "accept(): %m"); 156 | goto out; 157 | } else { 158 | if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) { 159 | char fromhost[NI_MAXHOST]; 160 | char fromport[NI_MAXSERV]; 161 | int gni_r; 162 | 163 | gni_r = getnameinfo((struct sockaddr *)&ss, slen, 164 | fromhost, (socklen_t) sizeof fromhost, 165 | fromport, (socklen_t) sizeof fromport, 166 | NI_NUMERICHOST | NI_NUMERICSERV); 167 | 168 | if (gni_r) { 169 | syslog(LOG_WARNING, "%s: getnameinfo(): %s", prog, gai_strerror(gni_r)); 170 | } else { 171 | syslog(LOG_INFO, "%s: Connection from: %s on port: %s", prog, fromhost, fromport); 172 | } 173 | } else { 174 | syslog(LOG_WARNING, "%s: getnameinfo() only supports IPv4/IPv6. Connection from address family: %u", prog, ss.ss_family); 175 | } 176 | 177 | switch (fork()) { 178 | case -1: 179 | syslog(LOG_WARNING, "fork(): %m"); 180 | if (errno != ENOMEM) { 181 | continue; 182 | } 183 | goto out; 184 | case 0: 185 | break; 186 | default: 187 | close(r); 188 | continue; 189 | } 190 | 191 | setpgid(0, 0); 192 | 193 | #if !TARGET_OS_EMBEDDED 194 | if ((tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SESSIONCREATE)) && launch_data_get_bool(tmp)) { 195 | auditinfo_addr_t auinfo = { 196 | .ai_termid = { .at_type = AU_IPv4 }, 197 | .ai_asid = AU_ASSIGN_ASID, 198 | .ai_auid = getuid(), 199 | .ai_flags = 0, 200 | }; 201 | if (setaudit_addr(&auinfo, sizeof(auinfo)) == 0) { 202 | char session[16]; 203 | snprintf(session, sizeof(session), "%x", auinfo.ai_asid); 204 | setenv("SECURITYSESSIONID", session, 1); 205 | } else { 206 | syslog(LOG_NOTICE, "%s: Setting Audit Session ID failed: %d", prog, errno); 207 | } 208 | } 209 | #endif // !TARGET_OS_EMBEDDED 210 | fcntl(r, F_SETFL, 0); 211 | fcntl(r, F_SETFD, 1); 212 | dup2(r, STDIN_FILENO); 213 | if (dupstdout) 214 | dup2(r, STDOUT_FILENO); 215 | if (dupstderr) 216 | dup2(r, STDERR_FILENO); 217 | signal(SIGCHLD, SIG_DFL); 218 | execv(prog, argv + 1); 219 | syslog(LOG_ERR, "execv(): %m"); 220 | exit(EXIT_FAILURE); 221 | } 222 | } 223 | 224 | out: 225 | exit(ec); 226 | } 227 | -------------------------------------------------------------------------------- /support/wait4path.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ 19 | */ 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | int main(int argc, char *argv[]) 32 | { 33 | int kq = kqueue(); 34 | struct kevent kev; 35 | struct stat sb; 36 | 37 | if (argc != 2) { 38 | fprintf(stderr, "usage: %s \n", argv[0]); 39 | exit(EXIT_FAILURE); 40 | } 41 | 42 | EV_SET(&kev, 0, EVFILT_FS, EV_ADD, 0, 0, 0); 43 | 44 | if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) { 45 | fprintf(stderr, "adding EVFILT_FS to kqueue failed: %s\n", strerror(errno)); 46 | exit(EXIT_FAILURE); 47 | } 48 | 49 | if (stat(argv[1], &sb) == 0) { 50 | exit(EXIT_SUCCESS); 51 | } 52 | 53 | for (;;) { 54 | kevent(kq, NULL, 0, &kev, 1, NULL); 55 | if (stat(argv[1], &sb) == 0) { 56 | break; 57 | } 58 | } 59 | 60 | exit(EXIT_SUCCESS); 61 | } 62 | -------------------------------------------------------------------------------- /xcconfigs/common.xcconfig: -------------------------------------------------------------------------------- 1 | #include "/Makefiles/CoreOS/Xcode/BSD.xcconfig" 2 | 3 | BUILD_XCSUPPORT_DIR = $(PROJECT_DIR)/xcsupport 4 | BUILD_XCSCRIPTS_DIR = $(PROJECT_DIR)/xcscripts 5 | BUILD_XCCONFIG_DIR = $(PROJECT_DIR)/xcconfig 6 | 7 | CRASHREPORTER_LINKER_FLAGS[sdk=macosx*]= -lCrashReporterClient 8 | CRASHREPORTER_LINKER_FLAGS[sdk=macosx10.6] = 9 | CRASHREPORTER_LINKER_FLAGS[sdk=iphoneos*] = 10 | 11 | COPY_PHASE_STRIP = YES 12 | STRIP_STYLE = non-global 13 | 14 | VERSIONING_SYSTEM = apple-generic 15 | CURRENT_PROJECT_VERSION = $(RC_ProjectSourceVersion) 16 | DEAD_CODE_STRIPPING = YES 17 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 18 | GCC_SYMBOLS_PRIVATE_EXTERN = YES 19 | GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES 20 | GCC_TREAT_WARNINGS_AS_ERRORS = YES 21 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = 22 | GCC_WARN_SHADOW = YES 23 | INSTALL_MODE_FLAG = ugo-w,a+rX 24 | OTHER_CFLAGS = -D__MigTypeCheck=1 -Dmig_external=__private_extern__ -D_DARWIN_USE_64_BIT_INODE=1 25 | WARNING_CFLAGS = -Wall -Wextra -Waggregate-return 26 | HEADER_SEARCH_PATHS = $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders $(PROJECT_DIR)/src $(PROJECT_DIR)/liblaunch 27 | USE_HEADERMAP = NO 28 | -------------------------------------------------------------------------------- /xcconfigs/launchctl.xcconfig: -------------------------------------------------------------------------------- 1 | #include "launchd.xcconfig" 2 | 3 | INSTALL_PATH = /bin 4 | PRODUCT_NAME = launchctl 5 | -------------------------------------------------------------------------------- /xcconfigs/launchd.xcconfig: -------------------------------------------------------------------------------- 1 | #include "common.xcconfig" 2 | 3 | // Xcode-defined flags. 4 | ARCHS = $(ARCHS_STANDARD_32_64_BIT) 5 | ONLY_ACTIVE_ARCH = NO 6 | BUILD_VARIANTS = normal 7 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 8 | GCC_TREAT_WARNINGS_AS_ERRORS = YES 9 | DEPLOYMENT_LOCATION = YES 10 | MACH_O_TYPE = mh_execute 11 | INSTALL_PATH = /sbin 12 | PRODUCT_NAME = launchd 13 | ALWAYS_SEARCH_USER_PATHS = NO 14 | GCC_ENABLE_BUILTIN_FUNCTIONS = YES 15 | OTHER_CFLAGS = $(OTHER_CFLAGS) -DXPC_BUILDING_LAUNCHD=1 16 | OTHER_MIGFLAGS = -DXPC_BUILDING_LAUNCHD=1 -I$(PROJECT_DIR)/src -I$(SDKROOT)/usr/local/include 17 | OTHER_LDFLAGS = 18 | -------------------------------------------------------------------------------- /xcconfigs/liblaunch.xcconfig: -------------------------------------------------------------------------------- 1 | #include "common.xcconfig" 2 | 3 | // Xcode-defined flags. 4 | ARCHS = $(ARCHS_STANDARD_32_64_BIT) 5 | SUPPORTED_PLATFORMS = macosx iphoneos 6 | ONLY_ACTIVE_ARCH = NO 7 | BUILD_VARIANTS = normal debug 8 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 9 | GCC_TREAT_WARNINGS_AS_ERRORS = YES 10 | DYLIB_CURRENT_VERSION = $(RC_ProjectSourceVersion) 11 | DYLIB_COMPATIBILITY_VERSION = 1 12 | DEPLOYMENT_LOCATION = YES 13 | INSTALL_PATH = /usr/lib/system 14 | ORDER_FILE[sdk=macosx*] = $(SDKROOT)/$(APPLE_INTERNAL_DIR)/OrderFiles/liblaunch.order 15 | ORDER_FILE[sdk=iphonesimulator*] = 16 | LINK_WITH_STANDARD_LIBRARIES = NO 17 | OTHER_LDFLAGS = -umbrella System -L/usr/lib/system -ldyld -lcompiler_rt -lsystem_kernel -lsystem_platform -lsystem_pthread -lsystem_malloc -lsystem_c -lquarantine -ldispatch $(CRASHREPORTER_LINKER_FLAGS) 18 | OTHER_LDFLAGS[sdk=iphone*] = -umbrella System -L/usr/lib/system -ldyld -lcompiler_rt -lsystem_kernel -lsystem_platform -lsystem_pthread -lsystem_malloc -lsystem_c -ldispatch $(CRASHREPORTER_LINKER_FLAGS) 19 | LD_DYLIB_INSTALL_NAME = $(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH) 20 | MACH_O_TYPE = mh_dylib 21 | EXECUTABLE_PREFIX = lib 22 | PRODUCT_NAME = launch 23 | PUBLIC_HEADERS_FOLDER_PATH = /usr/include 24 | PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include 25 | ALWAYS_SEARCH_USER_PATHS = NO 26 | GCC_ENABLE_BUILTIN_FUNCTIONS = YES 27 | GCC_PREPROCESSOR_DEFINITIONS_normal = __MigTypeCheck=1 mig_external=__private_extern__ 28 | GCC_PREPROCESSOR_DEFINITIONS_debug = $(GCC_PREPROCESSOR_DEFINITIONS_normal) 29 | OTHER_CFLAGS_normal = -DXPC_BUILDING_LAUNCHD=1 -D__DARWIN_NON_CANCELABLE=1 -D_DARWIN_USE_64_BIT_INODE=1 30 | OTHER_CFLAGS_debug = $(OTHER_CFLAGS_normal) -D__LAUNCH_DEBUG__=1 -O0 31 | VERSION_INFO_PREFIX = _ 32 | USE_HEADERMAP = NO 33 | -------------------------------------------------------------------------------- /xcscripts/SystemStarter-postflight.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | install -o "$INSTALL_OWNER" -g "$INSTALL_GROUP" -m 0755 -d "$DSTROOT"/System/Library/StartupItems 4 | install -o "$INSTALL_OWNER" -g "$INSTALL_GROUP" -m 0755 -d "$DSTROOT"/Library/StartupItems 5 | -------------------------------------------------------------------------------- /xcscripts/launchctl-postflight.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | install -o "$INSTALL_OWNER" -g "$INSTALL_GROUP" -m 0755 -d "$DSTROOT"/System/Library/LaunchAgents 4 | install -o "$INSTALL_OWNER" -g "$INSTALL_GROUP" -m 0755 -d "$DSTROOT"/System/Library/LaunchDaemons 5 | install -o "$INSTALL_OWNER" -g "$INSTALL_GROUP" -m 0755 -d "$DSTROOT"/Library/LaunchAgents 6 | install -o "$INSTALL_OWNER" -g "$INSTALL_GROUP" -m 0755 -d "$DSTROOT"/Library/LaunchDaemons 7 | -------------------------------------------------------------------------------- /xcscripts/launchd-postflight.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mkdir -p "$DSTROOT/private/var/db/launchd.db/com.apple.launchd" 4 | chown root:wheel "$DSTROOT/private/var/db/launchd.db" 5 | chown root:wheel "$DSTROOT/private/var/db/launchd.db/com.apple.launchd" 6 | 7 | mkdir -p "$DSTROOT/private/var/log/com.apple.launchd" 8 | chown root:wheel "$DSTROOT/private/var/log/com.apple.launchd" 9 | 10 | # These directories need to be here to satisfy certain third-party dependencies. 11 | mkdir -p "$DSTROOT/private/etc/mach_init.d" 12 | mkdir -p "$DSTROOT/private/etc/mach_init_per_user.d" 13 | mkdir -p "$DSTROOT/private/etc/mach_init_per_login_session.d" 14 | chown root:wheel "$DSTROOT/private/etc/mach_init.d" 15 | chown root:wheel "$DSTROOT/private/etc/mach_init_per_user.d" 16 | chown root:wheel "$DSTROOT/private/etc/mach_init_per_login_session.d" 17 | -------------------------------------------------------------------------------- /xcscripts/liblaunch-postflight.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | install -o "$INSTALL_OWNER" -g "$INSTALL_GROUP" -m 0755 -d "$DSTROOT"/usr/include/servers 4 | mv "$DSTROOT"/usr/include/bootstrap.h "$DSTROOT"/usr/include/servers/ 5 | ln -sf bootstrap.h "$DSTROOT"/usr/include/servers/bootstrap_defs.h 6 | --------------------------------------------------------------------------------