2 * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
23 #include "launch_priv.h"
24 #include "bootstrap.h"
26 #include "vproc_priv.h"
27 #include "vproc_internal.h"
28 #include "bootstrap_priv.h"
29 #include "launch_internal.h"
31 #include <CoreFoundation/CoreFoundation.h>
32 #include <CoreFoundation/CFPriv.h>
33 #include <CoreFoundation/CFLogUtilities.h>
34 #include <TargetConditionals.h>
35 #include <IOKit/IOKitLib.h>
36 #include <NSSystemDirectories.h>
37 #include <mach/mach.h>
38 #include <mach-o/getsect.h>
39 #include <sys/types.h>
40 #include <sys/sysctl.h>
42 #include <sys/sysctl.h>
44 #include <sys/socket.h>
46 #include <sys/fcntl.h>
47 #include <sys/event.h>
48 #include <sys/resource.h>
49 #include <sys/param.h>
50 #include <sys/mount.h>
51 #include <sys/reboot.h>
53 #include <netinet/in.h>
54 #include <netinet/in_var.h>
55 #include <netinet6/nd6.h>
68 #include <readline/readline.h>
69 #include <readline/history.h>
73 #include <bootfiles.h>
77 #include <sys/syslimits.h>
79 #include <os/assumes.h>
82 #include <systemstats/systemstats.h>
86 #include <bsm/auditd_lib.h>
87 #ifndef AUDITD_PLIST_FILE
88 #define AUDITD_PLIST_FILE "/System/Library/LaunchDaemons/com.apple.auditd.plist"
92 extern char **environ
;
94 #define LAUNCH_SECDIR _PATH_TMP "launch-XXXXXX"
95 #define LAUNCH_ENV_KEEPCONTEXT "LaunchKeepContext"
96 #define LAUNCH_ENV_BOOTSTRAPPINGSYSTEM "LaunchBootstrappingSystem"
98 #define CFTypeCheck(cf, type) (CFGetTypeID(cf) == type ## GetTypeID())
99 #define CFReleaseIfNotNULL(cf) if (cf) CFRelease(cf);
101 #if TARGET_OS_EMBEDDED
102 #include <sys/kern_memorystatus.h>
104 #define XPC_PLIST_CACHE "/System/Library/Caches/com.apple.xpcd/xpcd_cache.dylib"
105 #define XPC_PLIST_CACHE_KEY "LaunchDaemons"
107 #if JETSAM_PRIORITY_REVISION
108 #define READ_JETSAM_DEFAULTS 1
109 #define JETSAM_PROP_DIR "/System/Library/LaunchDaemons"
110 #define JETSAM_PROP_DIR_LENGTH (sizeof(JETSAM_PROP_DIR) - 1)
111 #define JETSAM_PROP_PREFIX "com.apple.jetsamproperties."
112 #define JETSAM_PROP_PREFIX_LENGTH (sizeof(JETSAM_PROP_PREFIX) - 1)
113 #define JETSAM_PROP_SUFFIX ".plist"
114 #define JETSAM_PROP_SUFFIX_LENGTH (sizeof(JETSAM_PROP_SUFFIX) - 1)
118 struct load_unload_state
{
121 bool editondisk
:1, load
:1, forceload
:1;
124 static void launchctl_log(int level
, const char *fmt
, ...);
125 static void launchctl_log_CFString(int level
, CFStringRef string
);
126 static void myCFDictionaryApplyFunction(const void *key
, const void *value
, void *context
);
127 static CFTypeRef
CFTypeCreateFromLaunchData(launch_data_t obj
);
128 static CFArrayRef
CFArrayCreateFromLaunchArray(launch_data_t arr
);
129 static CFDictionaryRef
CFDictionaryCreateFromLaunchDictionary(launch_data_t dict
);
130 static bool launch_data_array_append(launch_data_t a
, launch_data_t o
);
131 static void insert_event(launch_data_t
, const char *, const char *, launch_data_t
);
132 static void distill_jobs(launch_data_t
);
133 static void distill_config_file(launch_data_t
);
134 static void distill_fsevents(launch_data_t
);
135 static void sock_dict_cb(launch_data_t what
, const char *key
, void *context
);
136 static void sock_dict_edit_entry(launch_data_t tmp
, const char *key
, launch_data_t fdarray
, launch_data_t thejob
);
137 static launch_data_t
CF2launch_data(CFTypeRef
);
138 static launch_data_t
read_plist_file(const char *file
, bool editondisk
, bool load
);
139 #if TARGET_OS_EMBEDDED
140 static CFPropertyListRef
GetPropertyListFromCache(void);
141 static CFPropertyListRef
CreateMyPropertyListFromCachedFile(const char *posixfile
);
142 static bool require_jobs_from_cache(void);
144 static CFPropertyListRef
CreateMyPropertyListFromFile(const char *);
145 static CFPropertyListRef
CFPropertyListCreateFromFile(CFURLRef plistURL
);
146 static void WriteMyPropertyListToFile(CFPropertyListRef
, const char *);
147 static bool path_goodness_check(const char *path
, bool forceload
);
148 static void readpath(const char *, struct load_unload_state
*);
149 static void readfile(const char *, struct load_unload_state
*);
151 static int demux_cmd(int argc
, char *const argv
[]);
152 static void submit_job_pass(launch_data_t jobs
);
153 static void do_mgroup_join(int fd
, int family
, int socktype
, int protocol
, const char *mgroup
);
154 static mach_port_t
str2bsport(const char *s
);
155 static void print_jobs(launch_data_t j
, const char *key
, void *context
);
156 static void print_obj(launch_data_t obj
, const char *key
, void *context
);
157 static bool str2lim(const char *buf
, rlim_t
*res
);
158 static const char *lim2str(rlim_t val
, char *buf
);
159 static const char *num2name(int n
);
160 static ssize_t
name2num(const char *n
);
161 static void unloadjob(launch_data_t job
);
162 static void print_key_value(launch_data_t obj
, const char *key
, void *context
);
163 static void print_launchd_env(launch_data_t obj
, const char *key
, void *context
);
164 static void loopback_setup_ipv4(void);
165 static void loopback_setup_ipv6(void);
166 static pid_t
fwexec(const char *const *argv
, int *wstatus
);
167 static void do_potential_fsck(void);
168 static bool path_check(const char *path
);
169 static bool is_safeboot(void);
170 static bool is_netboot(void);
171 static void apply_sysctls_from_file(const char *thefile
);
172 static void empty_dir(const char *thedir
, struct stat
*psb
);
173 static int touch_file(const char *path
, mode_t m
);
174 static void do_sysversion_sysctl(void);
175 static void do_application_firewall_magic(int sfd
, launch_data_t thejob
);
176 static void preheat_page_cache_hack(void);
177 static void do_bootroot_magic(void);
178 static void do_single_user_mode(bool);
179 static bool do_single_user_mode2(void);
180 static void do_crash_debug_mode(void);
181 static bool do_crash_debug_mode2(void);
182 static void read_launchd_conf(void);
183 static bool job_disabled_logic(launch_data_t obj
);
184 static void fix_bogus_file_metadata(void);
185 static void do_file_init(void) __attribute__((constructor
));
186 static void setup_system_context(void);
187 static void handle_system_bootstrapper_crashes_separately(void);
188 static void fatal_signal_handler(int sig
, siginfo_t
*si
, void *uap
);
194 } BootCache_action_t
;
196 static void do_BootCache_magic(BootCache_action_t what
);
198 static int bootstrap_cmd(int argc
, char *const argv
[]);
199 static int load_and_unload_cmd(int argc
, char *const argv
[]);
200 //static int reload_cmd(int argc, char *const argv[]);
201 static int start_stop_remove_cmd(int argc
, char *const argv
[]);
202 static int submit_cmd(int argc
, char *const argv
[]);
203 static int list_cmd(int argc
, char *const argv
[]);
205 static int setenv_cmd(int argc
, char *const argv
[]);
206 static int unsetenv_cmd(int argc
, char *const argv
[]);
207 static int getenv_and_export_cmd(int argc
, char *const argv
[]);
208 static int wait4debugger_cmd(int argc
, char *const argv
[]);
210 static int limit_cmd(int argc
, char *const argv
[]);
211 static int stdio_cmd(int argc
, char *const argv
[]);
212 static int fyi_cmd(int argc
, char *const argv
[]);
213 static int logupdate_cmd(int argc
, char *const argv
[]);
214 static int umask_cmd(int argc
, char *const argv
[]);
215 static int getrusage_cmd(int argc
, char *const argv
[]);
216 static int bsexec_cmd(int argc
, char *const argv
[]);
217 static int _bslist_cmd(mach_port_t bport
, unsigned int depth
, bool show_job
, bool local_only
);
218 static int bslist_cmd(int argc
, char *const argv
[]);
219 static int _bstree_cmd(mach_port_t bsport
, unsigned int depth
, bool show_jobs
);
220 static int bstree_cmd(int argc
__attribute__((unused
)), char * const argv
[] __attribute__((unused
)));
221 static int managerpid_cmd(int argc
__attribute__((unused
)), char * const argv
[] __attribute__((unused
)));
222 static int manageruid_cmd(int argc
__attribute__((unused
)), char * const argv
[] __attribute__((unused
)));
223 static int managername_cmd(int argc
__attribute__((unused
)), char * const argv
[] __attribute__((unused
)));
224 static int asuser_cmd(int argc
, char * const argv
[]);
225 static int exit_cmd(int argc
, char *const argv
[]) __attribute__((noreturn
));
226 static int help_cmd(int argc
, char *const argv
[]);
228 static const struct {
230 int (*func
)(int argc
, char *const argv
[]);
233 { "load", load_and_unload_cmd
, "Load configuration files and/or directories" },
234 { "unload", load_and_unload_cmd
, "Unload configuration files and/or directories" },
235 // { "reload", reload_cmd, "Reload configuration files and/or directories" },
236 { "start", start_stop_remove_cmd
, "Start specified job" },
237 { "stop", start_stop_remove_cmd
, "Stop specified job" },
238 { "submit", submit_cmd
, "Submit a job from the command line" },
239 { "remove", start_stop_remove_cmd
, "Remove specified job" },
240 { "bootstrap", bootstrap_cmd
, "Bootstrap launchd" },
241 { "list", list_cmd
, "List jobs and information about jobs" },
242 { "setenv", setenv_cmd
, "Set an environmental variable in launchd" },
243 { "unsetenv", unsetenv_cmd
, "Unset an environmental variable in launchd" },
244 { "getenv", getenv_and_export_cmd
, "Get an environmental variable from launchd" },
245 { "export", getenv_and_export_cmd
, "Export shell settings from launchd" },
246 { "debug", wait4debugger_cmd
, "Set the WaitForDebugger flag for the target job to true." },
247 { "limit", limit_cmd
, "View and adjust launchd resource limits" },
248 { "stdout", stdio_cmd
, "Redirect launchd's standard out to the given path" },
249 { "stderr", stdio_cmd
, "Redirect launchd's standard error to the given path" },
250 { "shutdown", fyi_cmd
, "Prepare for system shutdown" },
251 { "singleuser", fyi_cmd
, "Switch to single-user mode" },
252 { "getrusage", getrusage_cmd
, "Get resource usage statistics from launchd" },
253 { "log", logupdate_cmd
, "Adjust the logging level or mask of launchd" },
254 { "umask", umask_cmd
, "Change launchd's umask" },
255 { "bsexec", bsexec_cmd
, "Execute a process within a different Mach bootstrap subset" },
256 { "bslist", bslist_cmd
, "List Mach bootstrap services and optional servers" },
257 { "bstree", bstree_cmd
, "Show the entire Mach bootstrap tree. Requires root privileges." },
258 { "managerpid", managerpid_cmd
, "Print the PID of the launchd managing this Mach bootstrap." },
259 { "manageruid", manageruid_cmd
, "Print the UID of the launchd managing this Mach bootstrap." },
260 { "managername", managername_cmd
, "Print the name of this Mach bootstrap." },
261 { "asuser", asuser_cmd
, "Execute a subcommand in the given user's context." },
262 { "exit", exit_cmd
, "Exit the interactive invocation of launchctl" },
263 { "quit", exit_cmd
, "Quit the interactive invocation of launchctl" },
264 { "help", help_cmd
, "This help output" },
267 static bool _launchctl_istty
;
268 static bool _launchctl_verbose
;
269 static bool _launchctl_is_managed
;
270 static bool _launchctl_apple_internal
;
271 static bool _launchctl_system_context
;
272 static bool _launchctl_uid0_context
;
273 static bool _launchctl_system_bootstrap
;
274 static bool _launchctl_peruser_bootstrap
;
275 static bool _launchctl_verbose_boot
= false;
276 static bool _launchctl_startup_debugging
= false;
278 static bool _launchctl_overrides_db_changed
= false;
279 static CFMutableDictionaryRef _launchctl_overrides_db
= NULL
;
281 static char *_launchctl_job_overrides_db_path
;
282 static char *_launchctl_managername
= NULL
;
284 #if READ_JETSAM_DEFAULTS
285 static CFDictionaryRef _launchctl_jetsam_defaults
= NULL
;
286 static CFDictionaryRef _launchctl_jetsam_defaults_cached
= NULL
;
290 main(int argc
, char *const argv
[])
294 if (getenv(LAUNCH_ENV_BOOTSTRAPPINGSYSTEM
)) {
295 /* We're bootstrapping the install environment, so we can't talk to
296 * mDNSResponder or opendirectoryd.
298 * See <rdar://problem/9877230>.
300 si_search_module_set_flags("mdns", 1);
301 si_search_module_set_flags("ds", 1);
304 int64_t is_managed
= 0;
305 (void)vproc_swap_integer(NULL
, VPROC_GSK_IS_MANAGED
, NULL
, &is_managed
);
306 _launchctl_is_managed
= is_managed
;
308 _launchctl_istty
= isatty(STDIN_FILENO
);
311 if (argc
> 0 && argv
[0][0] == '-') {
314 for (flago
= argv
[0] + 1; *flago
; flago
++) {
317 _launchctl_verbose
= true;
321 if (strncmp(argv
[1], "root", sizeof("root")) == 0) {
322 _launchctl_uid0_context
= true;
324 launchctl_log(LOG_ERR
, "Unknown user: %s", argv
[1]);
329 launchctl_log(LOG_ERR
, "-u option requires an argument.");
333 _launchctl_system_context
= true;
336 launchctl_log(LOG_ERR
, "Unknown argument: '-%c'", *flago
);
343 /* Running in the context of the root user's per-user launchd is only from
344 * within that session.
346 if (_launchctl_uid0_context
) {
347 int64_t manager_uid
= -1, manager_pid
= -1;
348 (void)vproc_swap_integer(NULL
, VPROC_GSK_MGR_UID
, NULL
, &manager_uid
);
349 (void)vproc_swap_integer(NULL
, VPROC_GSK_MGR_PID
, NULL
, &manager_pid
);
350 if (manager_uid
|| manager_pid
== 1) {
351 launchctl_log(LOG_ERR
, "Running in the root user's per-user context is not supported outside of the root user's bootstrap.");
354 } else if (!(_launchctl_system_context
|| _launchctl_uid0_context
)) {
355 /* Running in the system context is implied when we're running as root
356 * and not running as a bootstrapper.
358 _launchctl_system_context
= (!_launchctl_is_managed
&& getuid() == 0);
361 if (_launchctl_system_context
) {
363 setup_system_context();
365 launchctl_log(LOG_ERR
, "You must be root to run in the system context.");
368 } else if (_launchctl_uid0_context
) {
370 launchctl_log(LOG_ERR
, "You must be root to run in the root user context.");
376 launchctl_log(LOG_ERR
, "missing library: readline");
381 while ((l
= readline(_launchctl_istty
? "launchd% " : NULL
))) {
382 char *inputstring
= l
, *argv2
[100], **ap
= argv2
;
385 while ((*ap
= strsep(&inputstring
, " \t"))) {
399 if (_launchctl_istty
) {
405 exit(demux_cmd(argc
, argv
));
412 demux_cmd(int argc
, char *const argv
[])
419 for (i
= 0; i
< (sizeof cmds
/ sizeof cmds
[0]); i
++) {
420 if (!strcmp(cmds
[i
].name
, argv
[0])) {
421 return cmds
[i
].func(argc
, argv
);
425 launchctl_log(LOG_ERR
, "%s: unknown subcommand \"%s\"", getprogname(), argv
[0]);
430 launchctl_log(int level
, const char *fmt
, ...)
435 if (_launchctl_is_managed
) {
436 vsyslog(level
, fmt
, ap
);
439 (void)vasprintf(&buff
, fmt
, ap
);
441 FILE *where
= stdout
;
442 if (level
< LOG_NOTICE
) {
446 fprintf(where
, "%s\n", buff
);
454 launchctl_log_CFString(int level
, CFStringRef string
)
456 // Big enough. Don't feel like jumping through CF's hoops.
457 char *buff
= malloc(4096);
458 (void)CFStringGetCString(string
, buff
, 4096, kCFStringEncodingUTF8
);
459 launchctl_log(level
, "%s", buff
);
464 read_launchd_conf(void)
466 #if !TARGET_OS_EMBEDDED
467 char s
[1000], *c
, *av
[100];
473 if (getppid() == 1) {
474 file
= "/etc/launchd.conf";
476 file
= "/etc/launchd-user.conf";
479 if (!(f
= fopen(file
, "r"))) {
483 while ((c
= fgets(s
, (int) sizeof s
, f
))) {
485 if (len
&& c
[len
- 1] == '\n') {
491 while ((av
[i
] = strsep(&c
, " \t"))) {
492 if (*(av
[i
]) != '\0') {
503 #endif // !TARGET_OS_EMBEDDED
506 static CFPropertyListRef
507 CFPropertyListCreateFromFile(CFURLRef plistURL
)
509 CFReadStreamRef plistReadStream
= CFReadStreamCreateWithFile(NULL
, plistURL
);
511 CFErrorRef streamErr
= NULL
;
512 if (!CFReadStreamOpen(plistReadStream
)) {
513 streamErr
= CFReadStreamCopyError(plistReadStream
);
514 CFStringRef errString
= CFErrorCopyDescription(streamErr
);
516 launchctl_log_CFString(LOG_ERR
, errString
);
518 CFRelease(errString
);
519 CFRelease(streamErr
);
522 CFPropertyListRef plist
= NULL
;
523 if (plistReadStream
) {
524 CFStringRef errString
= NULL
;
525 CFPropertyListFormat plistFormat
= 0;
526 plist
= CFPropertyListCreateFromStream(NULL
, plistReadStream
, 0, kCFPropertyListImmutable
, &plistFormat
, &errString
);
528 launchctl_log_CFString(LOG_ERR
, errString
);
529 CFRelease(errString
);
533 CFReadStreamClose(plistReadStream
);
534 CFRelease(plistReadStream
);
540 unsetenv_cmd(int argc
, char *const argv
[])
542 launch_data_t resp
, tmp
, msg
;
545 launchctl_log(LOG_ERR
, "%s usage: unsetenv <key>", getprogname());
549 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
551 tmp
= launch_data_new_string(argv
[1]);
552 launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_UNSETUSERENVIRONMENT
);
554 resp
= launch_msg(msg
);
556 launch_data_free(msg
);
559 launch_data_free(resp
);
561 launchctl_log(LOG_ERR
, "launch_msg(\"%s\"): %s", LAUNCH_KEY_UNSETUSERENVIRONMENT
, strerror(errno
));
568 setenv_cmd(int argc
, char *const argv
[])
570 launch_data_t resp
, tmp
, tmpv
, msg
;
573 launchctl_log(LOG_ERR
, "%s usage: setenv <key> <value>", getprogname());
577 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
578 tmp
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
580 tmpv
= launch_data_new_string(argv
[2]);
581 launch_data_dict_insert(tmp
, tmpv
, argv
[1]);
582 launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_SETUSERENVIRONMENT
);
584 resp
= launch_msg(msg
);
585 launch_data_free(msg
);
588 launch_data_free(resp
);
590 launchctl_log(LOG_ERR
, "launch_msg(\"%s\"): %s", LAUNCH_KEY_SETUSERENVIRONMENT
, strerror(errno
));
597 print_launchd_env(launch_data_t obj
, const char *key
, void *context
)
599 bool *is_csh
= context
;
601 /* XXX escape the double quotes */
603 launchctl_log(LOG_NOTICE
, "setenv %s \"%s\";", key
, launch_data_get_string(obj
));
605 launchctl_log(LOG_NOTICE
, "%s=\"%s\"; export %s;", key
, launch_data_get_string(obj
), key
);
610 print_key_value(launch_data_t obj
, const char *key
, void *context
)
612 const char *k
= context
;
614 if (!strcmp(key
, k
)) {
615 launchctl_log(LOG_NOTICE
, "%s", launch_data_get_string(obj
));
620 getenv_and_export_cmd(int argc
, char *const argv
[])
626 if (!strcmp(argv
[0], "export")) {
627 char *s
= getenv("SHELL");
629 is_csh
= strstr(s
, "csh") ? true : false;
631 } else if (argc
!= 2) {
632 launchctl_log(LOG_ERR
, "%s usage: getenv <key>", getprogname());
638 if (vproc_swap_complex(NULL
, VPROC_GSK_ENVIRONMENT
, NULL
, &resp
) == NULL
) {
639 if (!strcmp(argv
[0], "export")) {
640 launch_data_dict_iterate(resp
, print_launchd_env
, &is_csh
);
642 launch_data_dict_iterate(resp
, print_key_value
, k
);
644 launch_data_free(resp
);
654 wait4debugger_cmd(int argc
, char * const argv
[])
657 launchctl_log(LOG_ERR
, "%s usage: debug <label> <value>", argv
[0]);
663 if (strncmp(argv
[2], "true", sizeof("true")) == 0) {
665 } else if (strncmp(argv
[2], "false", sizeof("false")) != 0) {
666 inval
= atoi(argv
[2]);
670 vproc_t vp
= vprocmgr_lookup_vproc(argv
[1]);
672 vproc_err_t verr
= vproc_swap_integer(vp
, VPROC_GSK_WAITFORDEBUGGER
, &inval
, NULL
);
674 launchctl_log(LOG_ERR
, "Failed to set WaitForDebugger flag on %s.", argv
[1]);
685 unloadjob(launch_data_t job
)
689 tmps
= launch_data_dict_lookup(job
, LAUNCH_JOBKEY_LABEL
);
692 launchctl_log(LOG_ERR
, "%s: Error: Missing Key: %s", getprogname(), LAUNCH_JOBKEY_LABEL
);
696 if (_vproc_send_signal_by_label(launch_data_get_string(tmps
), VPROC_MAGIC_UNLOAD_SIGNAL
) != NULL
) {
697 launchctl_log(LOG_ERR
, "%s: Error unloading: %s", getprogname(), launch_data_get_string(tmps
));
701 #if READ_JETSAM_DEFAULTS
703 static CFDictionaryRef
704 read_jetsam_defaults_from_cache(void) {
705 CFPropertyListRef cache
= GetPropertyListFromCache();
706 CFPropertyListRef defaults
= NULL
;
707 const void **keys
= 0;
714 CFPropertyListRef cachefiles
= CFDictionaryGetValue(cache
, CFSTR(XPC_PLIST_CACHE_KEY
));
719 count
= CFDictionaryGetCount(cachefiles
);
720 keys
= (const void **)malloc(sizeof(void *) * count
);
725 CFDictionaryGetKeysAndValues(cachefiles
, keys
, NULL
);
726 for (i
= 0; i
< count
; i
++) {
727 CFStringRef key
= (CFStringRef
)keys
[i
];
728 CFIndex key_length
= CFStringGetLength(key
);
730 if (key_length
<= (CFIndex
)(JETSAM_PROP_DIR_LENGTH
+ JETSAM_PROP_PREFIX_LENGTH
+ JETSAM_PROP_SUFFIX_LENGTH
+ 1)) {
734 if (CFStringCompareWithOptions(key
, CFSTR(JETSAM_PROP_DIR
"/" JETSAM_PROP_PREFIX
),
735 CFRangeMake(0, JETSAM_PROP_DIR_LENGTH
+ JETSAM_PROP_PREFIX_LENGTH
+ 1), 0)) {
739 if (CFStringCompareWithOptions(key
, CFSTR(JETSAM_PROP_SUFFIX
),
740 CFRangeMake(key_length
- JETSAM_PROP_SUFFIX_LENGTH
, JETSAM_PROP_SUFFIX_LENGTH
), 0)) {
744 defaults
= CFDictionaryGetValue(cachefiles
, key
);
753 static CFDictionaryRef
754 read_jetsam_defaults_from_file(void) {
757 CFDictionaryRef defaults
= NULL
;
759 dirp
= opendir(JETSAM_PROP_DIR
);
760 while ((dp
= readdir(dirp
)) != NULL
) {
763 if (dp
->d_namlen
<= (JETSAM_PROP_PREFIX_LENGTH
+ JETSAM_PROP_SUFFIX_LENGTH
)) {
767 if (strncmp(dp
->d_name
, JETSAM_PROP_PREFIX
, JETSAM_PROP_PREFIX_LENGTH
)) {
771 if (strncmp(dp
->d_name
+ dp
->d_namlen
- JETSAM_PROP_SUFFIX_LENGTH
, JETSAM_PROP_SUFFIX
, JETSAM_PROP_SUFFIX_LENGTH
)) {
775 if (-1 != asprintf(&fullpath
, "%s/%s", JETSAM_PROP_DIR
, dp
->d_name
)) {
776 defaults
= (CFDictionaryRef
)CreateMyPropertyListFromFile(fullpath
);
791 submit_cached_defaults(void) {
792 launch_data_t msg
, resp
;
793 const void **keys
= NULL
;
796 if (_launchctl_jetsam_defaults_cached
== NULL
) {
800 /* The dictionary to transmit */
801 CFMutableDictionaryRef payload_dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
803 /* Add a key to indicate that this is a special job */
804 CFBooleanRef ID
= kCFBooleanTrue
;
805 CFDictionaryAddValue(payload_dict
, CFSTR(LAUNCH_JOBKEY_DEFAULTS
), ID
);
807 CFMutableDictionaryRef defaults_dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
809 CFDictionaryAddValue(payload_dict
, CFSTR(LAUNCHD_JOB_DEFAULTS
), defaults_dict
);
811 /* Compile appropriate launchd dictionary... */
812 CFIndex count
= CFDictionaryGetCount(_launchctl_jetsam_defaults_cached
);
813 keys
= (const void **)malloc(sizeof(void *) * count
);
818 CFDictionaryGetKeysAndValues(_launchctl_jetsam_defaults_cached
, keys
, NULL
);
820 for (i
= 0; i
< count
; i
++) {
821 CFStringRef label
= (CFStringRef
)keys
[i
];
823 /* Get the defaults for the job */
824 CFDictionaryRef job_defaults_dict
= CFDictionaryGetValue(_launchctl_jetsam_defaults_cached
, label
);
825 if (!(job_defaults_dict
&& CFTypeCheck(job_defaults_dict
, CFDictionary
))) {
829 /* Create a new dictionary to represent the job */
830 CFMutableDictionaryRef job_dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
832 /* Add the defaults */
833 CFDictionaryAddValue(job_dict
, CFSTR(LAUNCH_JOBKEY_JETSAMPROPERTIES
), job_defaults_dict
);
835 /* Finally, add the result to the main dictionary */
836 CFDictionaryAddValue(defaults_dict
, label
, job_dict
);
842 /* Send the payload */
843 launch_data_t ldp
= CF2launch_data(payload_dict
);
845 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
846 launch_data_dict_insert(msg
, ldp
, LAUNCH_KEY_SUBMITJOB
);
848 resp
= launch_msg(msg
);
849 launch_data_free(msg
);
851 launch_data_free(resp
);
854 CFRelease(defaults_dict
);
855 CFRelease(payload_dict
);
863 read_jetsam_defaults(void)
865 /* Current supported version */
868 CFDictionaryRef jetsam_defaults
= NULL
;
870 if (require_jobs_from_cache()) {
871 jetsam_defaults
= read_jetsam_defaults_from_cache();
873 jetsam_defaults
= read_jetsam_defaults_from_file();
876 if (NULL
== jetsam_defaults
) {
877 launchctl_log(LOG_NOTICE
, "%s: no jetsam property file found", getprogname());
881 /* Validate the version */
882 CFNumberRef defaults_vers
= CFDictionaryGetValue(jetsam_defaults
, CFSTR("Version"));
883 if (!(defaults_vers
&& CFTypeCheck(defaults_vers
, CFNumber
))) {
887 CFNumberRef supported_vers
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &v
);
888 if (!(kCFCompareEqualTo
== CFNumberCompare(defaults_vers
, supported_vers
, NULL
))) {
892 /* These defaults are merged within launchctl prior to submitting the job */
893 _launchctl_jetsam_defaults
= CFDictionaryGetValue(jetsam_defaults
, CFSTR(LAUNCHD_JOB_DEFAULTS
));
894 if (!(_launchctl_jetsam_defaults
&& CFTypeCheck(_launchctl_jetsam_defaults
, CFDictionary
))) {
895 _launchctl_jetsam_defaults
= NULL
;
899 /* Cached defaults (applied by launchd) - parse and submit immediately as a fake job */
900 _launchctl_jetsam_defaults_cached
= CFDictionaryGetValue(jetsam_defaults
, CFSTR(LAUNCHD_JOB_DEFAULTS_CACHED
));
901 if (!(_launchctl_jetsam_defaults_cached
&& CFTypeCheck(_launchctl_jetsam_defaults_cached
, CFDictionary
))) {
902 _launchctl_jetsam_defaults_cached
= NULL
;
906 submit_cached_defaults();
911 #endif /* READ_JETSAM_DEFAULTS */
914 read_plist_file(const char *file
, bool editondisk
, bool load
)
916 CFPropertyListRef plist
;
917 launch_data_t r
= NULL
;
918 #if TARGET_OS_EMBEDDED
919 if (require_jobs_from_cache()) {
920 plist
= CreateMyPropertyListFromCachedFile(file
);
922 plist
= CreateMyPropertyListFromFile(file
);
925 plist
= CreateMyPropertyListFromFile(file
);
929 launchctl_log(LOG_ERR
, "%s: no plist was returned for: %s", getprogname(), file
);
933 CFStringRef label
= CFDictionaryGetValue(plist
, CFSTR(LAUNCH_JOBKEY_LABEL
));
934 if (!(label
&& CFTypeCheck(label
, CFString
))) {
938 if (_launchctl_overrides_db
) {
939 CFDictionaryRef overrides
= CFDictionaryGetValue(_launchctl_overrides_db
, label
);
940 if (overrides
&& CFTypeCheck(overrides
, CFDictionary
)) {
941 CFBooleanRef disabled
= CFDictionaryGetValue(overrides
, CFSTR(LAUNCH_JOBKEY_DISABLED
));
942 if (disabled
&& CFTypeCheck(disabled
, CFBoolean
)) {
943 CFDictionarySetValue((CFMutableDictionaryRef
)plist
, CFSTR(LAUNCH_JOBKEY_DISABLED
), disabled
);
949 if (_launchctl_overrides_db
) {
950 CFMutableDictionaryRef job
= (CFMutableDictionaryRef
)CFDictionaryGetValue(_launchctl_overrides_db
, label
);
951 if (!job
|| !CFTypeCheck(job
, CFDictionary
)) {
952 job
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
953 CFDictionarySetValue(_launchctl_overrides_db
, label
, job
);
957 CFDictionarySetValue(job
, CFSTR(LAUNCH_JOBKEY_DISABLED
), load
? kCFBooleanFalse
: kCFBooleanTrue
);
958 CFDictionarySetValue((CFMutableDictionaryRef
)plist
, CFSTR(LAUNCH_JOBKEY_DISABLED
), load
? kCFBooleanFalse
: kCFBooleanTrue
);
959 _launchctl_overrides_db_changed
= true;
962 CFDictionaryRemoveValue((CFMutableDictionaryRef
)plist
, CFSTR(LAUNCH_JOBKEY_DISABLED
));
964 CFDictionarySetValue((CFMutableDictionaryRef
)plist
, CFSTR(LAUNCH_JOBKEY_DISABLED
), kCFBooleanTrue
);
966 WriteMyPropertyListToFile(plist
, file
);
970 #if READ_JETSAM_DEFAULTS
971 if (_launchctl_jetsam_defaults
) {
972 CFDictionaryRef job_defaults_dict
= CFDictionaryGetValue(_launchctl_jetsam_defaults
, label
);
973 if (job_defaults_dict
) {
974 CFDictionarySetValue((CFMutableDictionaryRef
)plist
, CFSTR(LAUNCH_JOBKEY_JETSAMPROPERTIES
), job_defaults_dict
);
977 /* The plist is missing. Set a default memory limit, since the device will be otherwise unusable */
978 long default_limit
= 0;
979 CFMutableDictionaryRef job_defaults_dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
980 CFNumberRef memory_limit
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberLongType
, &default_limit
);
982 CFDictionaryAddValue(job_defaults_dict
, CFSTR(LAUNCH_JOBKEY_JETSAMMEMORYLIMIT
), memory_limit
);
983 CFRelease(memory_limit
);
985 CFDictionarySetValue((CFMutableDictionaryRef
)plist
, CFSTR(LAUNCH_JOBKEY_JETSAMPROPERTIES
), job_defaults_dict
);
986 CFRelease(job_defaults_dict
);
988 #endif /* READ_JETSAM_DEFAULTS */
990 r
= CF2launch_data(plist
);
998 sysctl_hw_streq(int mib_slot
, const char *str
)
1001 size_t bufsz
= sizeof(buf
);
1002 int mib
[] = { CTL_HW
, mib_slot
};
1004 if (sysctl(mib
, 2, buf
, &bufsz
, NULL
, 0) != -1) {
1005 if (strcmp(buf
, str
) == 0) {
1014 limitloadtohardware_iterator(launch_data_t val
, const char *key
, void *ctx
)
1019 (void)snprintf(name
, sizeof(name
), "hw.%s", key
);
1023 if (*result
!= true && os_assumes_zero(sysctlnametomib(name
, mib
, &sz
)) == 0) {
1024 if (launch_data_get_type(val
) == LAUNCH_DATA_ARRAY
) {
1025 size_t c
= launch_data_array_get_count(val
);
1028 for (i
= 0; i
< c
; i
++) {
1029 launch_data_t oai
= launch_data_array_get_index(val
, i
);
1030 if (sysctl_hw_streq(mib
[1], launch_data_get_string(oai
))) {
1040 readfile(const char *what
, struct load_unload_state
*lus
)
1042 char ourhostname
[1024];
1043 launch_data_t tmpd
, tmps
, thejob
, tmpa
;
1044 bool job_disabled
= false;
1047 gethostname(ourhostname
, sizeof(ourhostname
));
1049 if (NULL
== (thejob
= read_plist_file(what
, lus
->editondisk
, lus
->load
))) {
1050 launchctl_log(LOG_ERR
, "%s: no plist was returned for: %s", getprogname(), what
);
1055 if (NULL
== launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LABEL
)) {
1056 launchctl_log(LOG_ERR
, "%s: missing the Label key: %s", getprogname(), what
);
1060 if ((launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_PROGRAM
) == NULL
) &&
1061 (launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_PROGRAMARGUMENTS
) == NULL
)) {
1062 launchctl_log(LOG_ERR
, "%s: neither a Program nor a ProgramArguments key was specified: %s", getprogname(), what
);
1066 if (NULL
!= (tmpa
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LIMITLOADFROMHOSTS
))) {
1067 c
= launch_data_array_get_count(tmpa
);
1069 for (i
= 0; i
< c
; i
++) {
1070 launch_data_t oai
= launch_data_array_get_index(tmpa
, i
);
1071 if (!strcasecmp(ourhostname
, launch_data_get_string(oai
))) {
1077 if (NULL
!= (tmpa
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LIMITLOADTOHOSTS
))) {
1078 c
= launch_data_array_get_count(tmpa
);
1080 for (i
= 0; i
< c
; i
++) {
1081 launch_data_t oai
= launch_data_array_get_index(tmpa
, i
);
1082 if (!strcasecmp(ourhostname
, launch_data_get_string(oai
))) {
1092 if (NULL
!= (tmpd
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LIMITLOADTOHARDWARE
))) {
1093 bool result
= false;
1094 launch_data_dict_iterate(tmpd
, limitloadtohardware_iterator
, &result
);
1100 if (NULL
!= (tmpd
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LIMITLOADFROMHARDWARE
))) {
1101 bool result
= false;
1102 launch_data_dict_iterate(tmpd
, limitloadtohardware_iterator
, &result
);
1108 /* If the manager is Aqua, the LimitLoadToSessionType should default to
1111 * <rdar://problem/8297909>
1113 if (!_launchctl_managername
) {
1114 if (vproc_swap_string(NULL
, VPROC_GSK_MGR_NAME
, NULL
, &_launchctl_managername
)) {
1115 if (bootstrap_port
) {
1116 /* This is only an error if we are running with a neutered
1117 * bootstrap port, otherwise we wouldn't expect this operating to
1120 * <rdar://problem/10514286>
1122 launchctl_log(LOG_ERR
, "Could not obtain manager name: ppid/bootstrap: %d/0x%x", getppid(), bootstrap_port
);
1125 _launchctl_managername
= "";
1129 if (!lus
->session_type
) {
1130 if (strcmp(_launchctl_managername
, "Aqua") == 0) {
1131 lus
->session_type
= "Aqua";
1135 if (lus
->session_type
&& !(tmpa
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE
))) {
1136 tmpa
= launch_data_new_string("Aqua");
1137 launch_data_dict_insert(thejob
, tmpa
, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE
);
1140 if ((tmpa
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE
))) {
1141 const char *allowed_session
;
1142 bool skipjob
= true;
1144 /* My sincere apologies to anyone who has to deal with this
1145 * LimitLoadToSessionType madness. It was like this when I got here, but
1146 * I've knowingly made it worse, hopefully to the benefit of the end
1149 * See <rdar://problem/8769211> and <rdar://problem/7114980>.
1151 if (!lus
->session_type
&& launch_data_get_type(tmpa
) == LAUNCH_DATA_STRING
) {
1152 if (strcasecmp("System", _launchctl_managername
) == 0 && strcasecmp("System", launch_data_get_string(tmpa
)) == 0) {
1157 if (lus
->session_type
) switch (launch_data_get_type(tmpa
)) {
1158 case LAUNCH_DATA_ARRAY
:
1159 c
= launch_data_array_get_count(tmpa
);
1160 for (i
= 0; i
< c
; i
++) {
1161 tmps
= launch_data_array_get_index(tmpa
, i
);
1162 allowed_session
= launch_data_get_string(tmps
);
1163 if (strcasecmp(lus
->session_type
, allowed_session
) == 0) {
1165 /* we have to do the following so job_reparent_hack() works within launchd */
1166 tmpa
= launch_data_new_string(lus
->session_type
);
1167 launch_data_dict_insert(thejob
, tmpa
, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE
);
1172 case LAUNCH_DATA_STRING
:
1173 allowed_session
= launch_data_get_string(tmpa
);
1174 if (strcasecmp(lus
->session_type
, allowed_session
) == 0) {
1187 if ((tmpd
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_DISABLED
))) {
1188 job_disabled
= job_disabled_logic(tmpd
);
1191 if (lus
->forceload
) {
1192 job_disabled
= false;
1195 if (job_disabled
&& lus
->load
) {
1199 if (_launchctl_system_bootstrap
|| _launchctl_peruser_bootstrap
) {
1203 launch_data_t lduuid
= launch_data_new_opaque(uuid
, sizeof(uuid_t
));
1204 launch_data_dict_insert(thejob
, lduuid
, LAUNCH_JOBKEY_SECURITYSESSIONUUID
);
1207 launch_data_array_append(lus
->pass1
, thejob
);
1209 if (_launchctl_verbose
) {
1210 launchctl_log(LOG_NOTICE
, "Will load: %s", what
);
1215 if (_launchctl_verbose
) {
1216 launchctl_log(LOG_NOTICE
, "Ignored: %s", what
);
1218 launch_data_free(thejob
);
1222 job_disabled_dict_logic(launch_data_t obj
, const char *key
, void *context
)
1226 if (launch_data_get_type(obj
) != LAUNCH_DATA_STRING
) {
1230 if (strcasecmp(key
, LAUNCH_JOBKEY_DISABLED_MACHINETYPE
) == 0) {
1231 if (sysctl_hw_streq(HW_MACHINE
, launch_data_get_string(obj
))) {
1234 } else if (strcasecmp(key
, LAUNCH_JOBKEY_DISABLED_MODELNAME
) == 0) {
1235 if (sysctl_hw_streq(HW_MODEL
, launch_data_get_string(obj
))) {
1242 job_disabled_logic(launch_data_t obj
)
1246 switch (launch_data_get_type(obj
)) {
1247 case LAUNCH_DATA_DICTIONARY
:
1248 launch_data_dict_iterate(obj
, job_disabled_dict_logic
, &r
);
1250 case LAUNCH_DATA_BOOL
:
1251 r
= launch_data_get_bool(obj
);
1261 path_goodness_check(const char *path
, bool forceload
)
1265 if (stat(path
, &sb
) == -1) {
1266 launchctl_log(LOG_ERR
, "%s: Couldn't stat(\"%s\"): %s", getprogname(), path
, strerror(errno
));
1274 if (sb
.st_mode
& (S_IWOTH
|S_IWGRP
)) {
1275 launchctl_log(LOG_ERR
, "%s: Dubious permissions on file (skipping): %s", getprogname(), path
);
1279 if (sb
.st_uid
!= 0 && sb
.st_uid
!= getuid()) {
1280 launchctl_log(LOG_ERR
, "%s: Dubious ownership on file (skipping): %s", getprogname(), path
);
1284 if (!(S_ISREG(sb
.st_mode
) || S_ISDIR(sb
.st_mode
))) {
1285 launchctl_log(LOG_ERR
, "%s: Dubious path. Not a regular file or directory (skipping): %s", getprogname(), path
);
1289 if ((!S_ISDIR(sb
.st_mode
)) && (fnmatch("*.plist", path
, FNM_CASEFOLD
) == FNM_NOMATCH
)) {
1290 launchctl_log(LOG_ERR
, "%s: Dubious file. Not of type .plist (skipping): %s", getprogname(), path
);
1298 readpath(const char *what
, struct load_unload_state
*lus
)
1300 char buf
[MAXPATHLEN
];
1305 if (!path_goodness_check(what
, lus
->forceload
)) {
1309 if (stat(what
, &sb
) == -1) {
1313 if (S_ISREG(sb
.st_mode
)) {
1314 readfile(what
, lus
);
1315 } else if (S_ISDIR(sb
.st_mode
)) {
1316 if ((d
= opendir(what
)) == NULL
) {
1317 launchctl_log(LOG_ERR
, "%s: opendir() failed to open the directory", getprogname());
1321 while ((de
= readdir(d
))) {
1322 if (de
->d_name
[0] == '.') {
1325 snprintf(buf
, sizeof(buf
), "%s/%s", what
, de
->d_name
);
1327 if (!path_goodness_check(buf
, lus
->forceload
)) {
1338 insert_event(launch_data_t job
, const char *stream
, const char *key
, launch_data_t event
)
1340 launch_data_t launchevents
, streamdict
;
1342 launchevents
= launch_data_dict_lookup(job
, LAUNCH_JOBKEY_LAUNCHEVENTS
);
1343 if (launchevents
== NULL
) {
1344 launchevents
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
1345 launch_data_dict_insert(job
, launchevents
, LAUNCH_JOBKEY_LAUNCHEVENTS
);
1348 streamdict
= launch_data_dict_lookup(launchevents
, stream
);
1349 if (streamdict
== NULL
) {
1350 streamdict
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
1351 launch_data_dict_insert(launchevents
, streamdict
, stream
);
1354 launch_data_dict_insert(streamdict
, event
, key
);
1357 struct distill_context
{
1359 launch_data_t newsockdict
;
1363 distill_jobs(launch_data_t jobs
)
1365 size_t i
, c
= launch_data_array_get_count(jobs
);
1368 for (i
= 0; i
< c
; i
++) {
1369 job
= launch_data_array_get_index(jobs
, i
);
1370 distill_config_file(job
);
1371 distill_fsevents(job
);
1376 distill_config_file(launch_data_t id_plist
)
1378 struct distill_context dc
= { id_plist
, NULL
};
1381 if ((tmp
= launch_data_dict_lookup(dc
.base
, LAUNCH_JOBKEY_SOCKETS
))) {
1382 dc
.newsockdict
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
1383 launch_data_dict_iterate(tmp
, sock_dict_cb
, &dc
);
1384 launch_data_dict_insert(dc
.base
, dc
.newsockdict
, LAUNCH_JOBKEY_SOCKETS
);
1389 sock_dict_cb(launch_data_t what
, const char *key
, void *context
)
1391 struct distill_context
*dc
= context
;
1392 launch_data_t fdarray
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
1394 launch_data_dict_insert(dc
->newsockdict
, fdarray
, key
);
1396 if (launch_data_get_type(what
) == LAUNCH_DATA_DICTIONARY
) {
1397 sock_dict_edit_entry(what
, key
, fdarray
, dc
->base
);
1398 } else if (launch_data_get_type(what
) == LAUNCH_DATA_ARRAY
) {
1402 for (i
= 0; i
< launch_data_array_get_count(what
); i
++) {
1403 tmp
= launch_data_array_get_index(what
, i
);
1404 sock_dict_edit_entry(tmp
, key
, fdarray
, dc
->base
);
1410 sock_dict_edit_entry(launch_data_t tmp
, const char *key
, launch_data_t fdarray
, launch_data_t thejob
)
1412 launch_data_t a
, val
;
1413 int sfd
, st
= SOCK_STREAM
;
1414 bool passive
= true;
1416 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_TYPE
))) {
1417 if (!strcasecmp(launch_data_get_string(val
), "stream")) {
1419 } else if (!strcasecmp(launch_data_get_string(val
), "dgram")) {
1421 } else if (!strcasecmp(launch_data_get_string(val
), "seqpacket")) {
1422 st
= SOCK_SEQPACKET
;
1426 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_PASSIVE
))) {
1427 passive
= launch_data_get_bool(val
);
1430 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_SECUREWITHKEY
))) {
1431 char secdir
[] = LAUNCH_SECDIR
, buf
[1024];
1432 launch_data_t uenv
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES
);
1435 uenv
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
1436 launch_data_dict_insert(thejob
, uenv
, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES
);
1441 sprintf(buf
, "%s/%s", secdir
, key
);
1443 a
= launch_data_new_string(buf
);
1444 launch_data_dict_insert(tmp
, a
, LAUNCH_JOBSOCKETKEY_PATHNAME
);
1445 a
= launch_data_new_string(buf
);
1446 launch_data_dict_insert(uenv
, a
, launch_data_get_string(val
));
1449 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_PATHNAME
))) {
1450 struct sockaddr_un sun
;
1451 mode_t sun_mode
= 0;
1455 memset(&sun
, 0, sizeof(sun
));
1457 sun
.sun_family
= AF_UNIX
;
1459 strncpy(sun
.sun_path
, launch_data_get_string(val
), sizeof(sun
.sun_path
));
1461 if (posix_assumes_zero(sfd
= _fd(socket(AF_UNIX
, st
, 0))) == -1) {
1465 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_PATHMODE
))) {
1466 sun_mode
= (mode_t
)launch_data_get_integer(val
);
1471 if (unlink(sun
.sun_path
) == -1 && errno
!= ENOENT
) {
1475 oldmask
= umask(S_IRWXG
|S_IRWXO
);
1476 if (bind(sfd
, (struct sockaddr
*)&sun
, (socklen_t
) sizeof sun
) == -1) {
1483 chmod(sun
.sun_path
, sun_mode
);
1485 if ((st
== SOCK_STREAM
|| st
== SOCK_SEQPACKET
) && listen(sfd
, -1) == -1) {
1489 } else if (connect(sfd
, (struct sockaddr
*)&sun
, (socklen_t
) sizeof sun
) == -1) {
1494 val
= launch_data_new_fd(sfd
);
1495 launch_data_array_append(fdarray
, val
);
1497 launch_data_t rnames
= NULL
;
1498 const char *node
= NULL
, *serv
= NULL
, *mgroup
= NULL
;
1500 struct addrinfo hints
, *res0
, *res
;
1501 int gerr
, sock_opt
= 1;
1503 memset(&hints
, 0, sizeof(hints
));
1505 hints
.ai_socktype
= st
;
1507 hints
.ai_flags
|= AI_PASSIVE
;
1510 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_NODENAME
))) {
1511 node
= launch_data_get_string(val
);
1513 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_MULTICASTGROUP
))) {
1514 mgroup
= launch_data_get_string(val
);
1516 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_SERVICENAME
))) {
1517 if (LAUNCH_DATA_INTEGER
== launch_data_get_type(val
)) {
1518 sprintf(servnbuf
, "%lld", launch_data_get_integer(val
));
1521 serv
= launch_data_get_string(val
);
1524 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_FAMILY
))) {
1525 if (!strcasecmp("IPv4", launch_data_get_string(val
))) {
1526 hints
.ai_family
= AF_INET
;
1527 } else if (!strcasecmp("IPv6", launch_data_get_string(val
))) {
1528 hints
.ai_family
= AF_INET6
;
1531 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_PROTOCOL
))) {
1532 if (!strcasecmp("TCP", launch_data_get_string(val
))) {
1533 hints
.ai_protocol
= IPPROTO_TCP
;
1534 } else if (!strcasecmp("UDP", launch_data_get_string(val
))) {
1535 hints
.ai_protocol
= IPPROTO_UDP
;
1538 if ((rnames
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_BONJOUR
))) {
1539 if (LAUNCH_DATA_BOOL
!= launch_data_get_type(rnames
) || launch_data_get_bool(rnames
)) {
1540 launch_data_t newevent
;
1543 newevent
= launch_data_copy(tmp
);
1544 snprintf(eventkey
, sizeof(eventkey
), "com.apple.launchd.%s", key
);
1545 insert_event(thejob
, "com.apple.bonjour.registration", eventkey
, newevent
);
1549 if ((gerr
= getaddrinfo(node
, serv
, &hints
, &res0
)) != 0) {
1550 launchctl_log(LOG_ERR
, "getaddrinfo(): %s", gai_strerror(gerr
));
1554 for (res
= res0
; res
; res
= res
->ai_next
) {
1555 if ((sfd
= _fd(socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
))) == -1) {
1556 launchctl_log(LOG_ERR
, "socket(): %s", strerror(errno
));
1560 do_application_firewall_magic(sfd
, thejob
);
1562 if (hints
.ai_flags
& AI_PASSIVE
) {
1563 if (AF_INET6
== res
->ai_family
&& -1 == setsockopt(sfd
, IPPROTO_IPV6
, IPV6_V6ONLY
,
1564 (void *)&sock_opt
, (socklen_t
) sizeof sock_opt
)) {
1565 launchctl_log(LOG_ERR
, "setsockopt(IPV6_V6ONLY): %m");
1569 if (setsockopt(sfd
, SOL_SOCKET
, SO_REUSEPORT
, (void *)&sock_opt
, (socklen_t
) sizeof sock_opt
) == -1) {
1570 launchctl_log(LOG_ERR
, "setsockopt(SO_REUSEPORT): %s", strerror(errno
));
1574 if (setsockopt(sfd
, SOL_SOCKET
, SO_REUSEADDR
, (void *)&sock_opt
, (socklen_t
) sizeof sock_opt
) == -1) {
1575 launchctl_log(LOG_ERR
, "setsockopt(SO_REUSEADDR): %s", strerror(errno
));
1579 if (bind(sfd
, res
->ai_addr
, res
->ai_addrlen
) == -1) {
1580 launchctl_log(LOG_ERR
, "bind(): %s", strerror(errno
));
1583 /* The kernel may have dynamically assigned some part of the
1584 * address. (The port being a common example.)
1586 if (getsockname(sfd
, res
->ai_addr
, &res
->ai_addrlen
) == -1) {
1587 launchctl_log(LOG_ERR
, "getsockname(): %s", strerror(errno
));
1592 do_mgroup_join(sfd
, res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
, mgroup
);
1594 if ((res
->ai_socktype
== SOCK_STREAM
|| res
->ai_socktype
== SOCK_SEQPACKET
) && listen(sfd
, -1) == -1) {
1595 launchctl_log(LOG_ERR
, "listen(): %s", strerror(errno
));
1599 if (connect(sfd
, res
->ai_addr
, res
->ai_addrlen
) == -1) {
1600 launchctl_log(LOG_ERR
, "connect(): %s", strerror(errno
));
1604 val
= launch_data_new_fd(sfd
);
1605 launch_data_array_append(fdarray
, val
);
1611 distill_fsevents(launch_data_t id_plist
)
1613 launch_data_t copy
, newevent
;
1614 launch_data_t tmp
, tmp2
;
1616 if ((tmp
= launch_data_dict_lookup(id_plist
, LAUNCH_JOBKEY_QUEUEDIRECTORIES
))) {
1617 copy
= launch_data_copy(tmp
);
1618 (void)launch_data_dict_remove(id_plist
, LAUNCH_JOBKEY_QUEUEDIRECTORIES
);
1620 newevent
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
1621 launch_data_dict_insert(newevent
, copy
, LAUNCH_JOBKEY_QUEUEDIRECTORIES
);
1622 insert_event(id_plist
, "com.apple.fsevents.matching", "com.apple.launchd." LAUNCH_JOBKEY_QUEUEDIRECTORIES
, newevent
);
1625 if ((tmp
= launch_data_dict_lookup(id_plist
, LAUNCH_JOBKEY_WATCHPATHS
))) {
1626 copy
= launch_data_copy(tmp
);
1627 (void)launch_data_dict_remove(id_plist
, LAUNCH_JOBKEY_WATCHPATHS
);
1629 newevent
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
1630 launch_data_dict_insert(newevent
, copy
, LAUNCH_JOBKEY_WATCHPATHS
);
1631 insert_event(id_plist
, "com.apple.fsevents.matching", "com.apple.launchd." LAUNCH_JOBKEY_WATCHPATHS
, newevent
);
1634 if ((tmp
= launch_data_dict_lookup(id_plist
, LAUNCH_JOBKEY_KEEPALIVE
))) {
1635 if ((tmp2
= launch_data_dict_lookup(tmp
, LAUNCH_JOBKEY_KEEPALIVE_PATHSTATE
))) {
1636 copy
= launch_data_copy(tmp2
);
1637 (void)launch_data_dict_remove(tmp
, LAUNCH_JOBKEY_KEEPALIVE_PATHSTATE
);
1639 newevent
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
1640 launch_data_dict_insert(newevent
, copy
, LAUNCH_JOBKEY_KEEPALIVE_PATHSTATE
);
1641 insert_event(id_plist
, "com.apple.fsevents.matching", "com.apple.launchd." LAUNCH_JOBKEY_KEEPALIVE_PATHSTATE
, newevent
);
1647 do_mgroup_join(int fd
, int family
, int socktype
, int protocol
, const char *mgroup
)
1649 struct addrinfo hints
, *res0
, *res
;
1650 struct ip_mreq mreq
;
1651 struct ipv6_mreq m6req
;
1654 memset(&hints
, 0, sizeof(hints
));
1656 hints
.ai_flags
|= AI_PASSIVE
;
1657 hints
.ai_family
= family
;
1658 hints
.ai_socktype
= socktype
;
1659 hints
.ai_protocol
= protocol
;
1661 if ((gerr
= getaddrinfo(mgroup
, NULL
, &hints
, &res0
)) != 0) {
1662 launchctl_log(LOG_ERR
, "getaddrinfo(): %s", gai_strerror(gerr
));
1666 for (res
= res0
; res
; res
= res
->ai_next
) {
1667 if (AF_INET
== family
) {
1668 memset(&mreq
, 0, sizeof(mreq
));
1669 mreq
.imr_multiaddr
= ((struct sockaddr_in
*)res
->ai_addr
)->sin_addr
;
1670 if (setsockopt(fd
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &mreq
, (socklen_t
) sizeof mreq
) == -1) {
1671 launchctl_log(LOG_ERR
, "setsockopt(IP_ADD_MEMBERSHIP): %s", strerror(errno
));
1675 } else if (AF_INET6
== family
) {
1676 memset(&m6req
, 0, sizeof(m6req
));
1677 m6req
.ipv6mr_multiaddr
= ((struct sockaddr_in6
*)res
->ai_addr
)->sin6_addr
;
1678 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &m6req
, (socklen_t
) sizeof m6req
) == -1) {
1679 launchctl_log(LOG_ERR
, "setsockopt(IPV6_JOIN_GROUP): %s", strerror(errno
));
1684 launchctl_log(LOG_ERR
, "unknown family during multicast group bind!");
1692 #pragma mark XPC Cache
1694 #if TARGET_OS_EMBEDDED
1697 GetPropertyListFromCache(void)
1699 static CFPropertyListRef propertyList
;
1700 CFDataRef cacheData
;
1703 if (!propertyList
) {
1704 uint8_t *data
= NULL
;
1705 unsigned long sz
= 0;
1707 void *handle
= dlopen(XPC_PLIST_CACHE
, RTLD_NOW
);
1710 void *fnptr
= dlsym(handle
, "__xpcd_cache");
1715 int rv
= dladdr(fnptr
, &image_info
);
1717 data
= getsectiondata(image_info
.dli_fbase
, "__TEXT", "__xpcd_cache", &sz
);
1719 launchctl_log(LOG_ERR
, "cache loading failed: failed to find address of __xpcd_cache symbol.");
1722 launchctl_log(LOG_ERR
, "cache loading failed: failed to find __xpcd_cache symbol in cache.");
1725 launchctl_log(LOG_ERR
, "cache loading failed: dlopen returned %s.", dlerror());
1729 cacheData
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, data
, sz
, kCFAllocatorNull
);
1731 propertyList
= CFPropertyListCreateWithData(kCFAllocatorDefault
, cacheData
, kCFPropertyListMutableContainersAndLeaves
, NULL
, &error
);
1732 CFRelease(cacheData
);
1734 launchctl_log(LOG_ERR
, "cache loading failed: unable to create data out of memory region.");
1737 launchctl_log(LOG_ERR
, "cache loading failed: no cache data found in __TEXT,__xpcd_cache segment.");
1741 return propertyList
;
1745 CreateMyPropertyListFromCachedFile(const char *posixfile
)
1747 CFPropertyListRef cache
= GetPropertyListFromCache();
1748 CFPropertyListRef job
= NULL
;
1751 CFPropertyListRef jobs
= CFDictionaryGetValue(cache
, CFSTR(XPC_PLIST_CACHE_KEY
));
1754 CFStringRef key
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, posixfile
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1757 job
= CFDictionaryGetValue(jobs
, key
);
1770 require_jobs_from_cache(void)
1776 bool cs_disabled
= false;
1779 if (sysctlbyname("kern.bootargs", buf
, &len
, NULL
, 0) == 0) {
1780 ptr
= strnstr(buf
, "cs_enforcement_disable=", len
);
1782 val
= strtoul(ptr
+ strlen("cs_enforcement_disable="), NULL
, 10);
1783 cs_disabled
= (val
!= 0);
1785 ptr
= strnstr(buf
, "launchctl_enforce_codesign=", len
);
1787 char *endptr
= NULL
;
1788 char *startptr
= ptr
+ strlen("launchctl_enforce_codesign=");
1789 val
= strtoul(startptr
, &endptr
, 10);
1790 cs_disabled
= (val
== 0 && startptr
!= endptr
);
1794 return !cs_disabled
;
1799 #pragma mark File-based Property Lists
1802 CreateMyPropertyListFromFile(const char *posixfile
)
1804 CFPropertyListRef propertyList
;
1805 CFStringRef errorString
;
1806 CFDataRef resourceData
;
1810 fileURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault
, (const UInt8
*)posixfile
, strlen(posixfile
), false);
1812 launchctl_log(LOG_ERR
, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed", getprogname(), posixfile
);
1814 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, fileURL
, &resourceData
, NULL
, NULL
, &errorCode
)) {
1815 launchctl_log(LOG_ERR
, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d", getprogname(), posixfile
, (int)errorCode
);
1818 propertyList
= CFPropertyListCreateFromXMLData(kCFAllocatorDefault
, resourceData
, kCFPropertyListMutableContainersAndLeaves
, &errorString
);
1824 CFRelease(resourceData
);
1827 return propertyList
;
1831 WriteMyPropertyListToFile(CFPropertyListRef plist
, const char *posixfile
)
1833 CFDataRef resourceData
;
1837 fileURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault
, (const UInt8
*)posixfile
, strlen(posixfile
), false);
1839 launchctl_log(LOG_ERR
, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed", getprogname(), posixfile
);
1841 resourceData
= CFPropertyListCreateXMLData(kCFAllocatorDefault
, plist
);
1842 if (resourceData
== NULL
) {
1843 launchctl_log(LOG_ERR
, "%s: CFPropertyListCreateXMLData(%s) failed", getprogname(), posixfile
);
1845 if (!CFURLWriteDataAndPropertiesToResource(fileURL
, resourceData
, NULL
, &errorCode
)) {
1846 launchctl_log(LOG_ERR
, "%s: CFURLWriteDataAndPropertiesToResource(%s) failed: %d", getprogname(), posixfile
, (int)errorCode
);
1850 CFRelease(resourceData
);
1854 static inline Boolean
1855 _is_launch_data_t(launch_data_t obj
)
1857 Boolean result
= true;
1859 switch (launch_data_get_type(obj
)) {
1860 case LAUNCH_DATA_STRING
: break;
1861 case LAUNCH_DATA_INTEGER
: break;
1862 case LAUNCH_DATA_REAL
: break;
1863 case LAUNCH_DATA_BOOL
: break;
1864 case LAUNCH_DATA_ARRAY
: break;
1865 case LAUNCH_DATA_DICTIONARY
: break;
1866 case LAUNCH_DATA_FD
: break;
1867 case LAUNCH_DATA_MACHPORT
: break;
1868 default : result
= false;
1875 _launch_data_iterate(launch_data_t obj
, const char *key
, CFMutableDictionaryRef dict
)
1877 if (obj
&& _is_launch_data_t(obj
)) {
1878 CFStringRef cfKey
= CFStringCreateWithCString(NULL
, key
, kCFStringEncodingUTF8
);
1879 CFTypeRef cfVal
= CFTypeCreateFromLaunchData(obj
);
1882 CFDictionarySetValue(dict
, cfKey
, cfVal
);
1890 CFTypeCreateFromLaunchData(launch_data_t obj
)
1892 CFTypeRef cfObj
= NULL
;
1894 switch (launch_data_get_type(obj
)) {
1895 case LAUNCH_DATA_STRING
: {
1896 const char *str
= launch_data_get_string(obj
);
1897 cfObj
= CFStringCreateWithCString(NULL
, str
, kCFStringEncodingUTF8
);
1900 case LAUNCH_DATA_INTEGER
: {
1901 long long integer
= launch_data_get_integer(obj
);
1902 cfObj
= CFNumberCreate(NULL
, kCFNumberLongLongType
, &integer
);
1905 case LAUNCH_DATA_REAL
: {
1906 double real
= launch_data_get_real(obj
);
1907 cfObj
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &real
);
1910 case LAUNCH_DATA_BOOL
: {
1911 bool yesno
= launch_data_get_bool(obj
);
1912 cfObj
= yesno
? kCFBooleanTrue
: kCFBooleanFalse
;
1915 case LAUNCH_DATA_ARRAY
: {
1916 cfObj
= (CFTypeRef
)CFArrayCreateFromLaunchArray(obj
);
1919 case LAUNCH_DATA_DICTIONARY
: {
1920 cfObj
= (CFTypeRef
)CFDictionaryCreateFromLaunchDictionary(obj
);
1923 case LAUNCH_DATA_FD
: {
1924 int fd
= launch_data_get_fd(obj
);
1925 cfObj
= CFNumberCreate(NULL
, kCFNumberIntType
, &fd
);
1928 case LAUNCH_DATA_MACHPORT
: {
1929 mach_port_t port
= launch_data_get_machport(obj
);
1930 cfObj
= CFNumberCreate(NULL
, kCFNumberIntType
, &port
);
1940 #pragma mark CFArray
1942 CFArrayCreateFromLaunchArray(launch_data_t arr
)
1944 CFArrayRef result
= NULL
;
1945 CFMutableArrayRef mutResult
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1947 if (launch_data_get_type(arr
) == LAUNCH_DATA_ARRAY
) {
1948 unsigned int count
= launch_data_array_get_count(arr
);
1951 for (i
= 0; i
< count
; i
++) {
1952 launch_data_t launch_obj
= launch_data_array_get_index(arr
, i
);
1953 CFTypeRef obj
= CFTypeCreateFromLaunchData(launch_obj
);
1956 CFArrayAppendValue(mutResult
, obj
);
1961 result
= CFArrayCreateCopy(NULL
, mutResult
);
1965 CFRelease(mutResult
);
1970 #pragma mark CFDictionary / CFPropertyList
1971 static CFDictionaryRef
1972 CFDictionaryCreateFromLaunchDictionary(launch_data_t dict
)
1974 CFDictionaryRef result
= NULL
;
1976 if (launch_data_get_type(dict
) == LAUNCH_DATA_DICTIONARY
) {
1977 CFMutableDictionaryRef mutResult
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1979 launch_data_dict_iterate(dict
, (void (*)(launch_data_t
, const char *, void *))_launch_data_iterate
, mutResult
);
1981 result
= CFDictionaryCreateCopy(NULL
, mutResult
);
1982 CFRelease(mutResult
);
1989 myCFDictionaryApplyFunction(const void *key
, const void *value
, void *context
)
1991 launch_data_t ik
, iw
, where
= context
;
1993 ik
= CF2launch_data(key
);
1994 iw
= CF2launch_data(value
);
1996 launch_data_dict_insert(where
, iw
, launch_data_get_string(ik
));
1997 launch_data_free(ik
);
2001 CF2launch_data(CFTypeRef cfr
)
2004 CFTypeID cft
= CFGetTypeID(cfr
);
2006 if (cft
== CFStringGetTypeID()) {
2008 CFStringGetCString(cfr
, buf
, sizeof(buf
), kCFStringEncodingUTF8
);
2009 r
= launch_data_alloc(LAUNCH_DATA_STRING
);
2010 launch_data_set_string(r
, buf
);
2011 } else if (cft
== CFBooleanGetTypeID()) {
2012 r
= launch_data_alloc(LAUNCH_DATA_BOOL
);
2013 launch_data_set_bool(r
, CFBooleanGetValue(cfr
));
2014 } else if (cft
== CFArrayGetTypeID()) {
2015 CFIndex i
, ac
= CFArrayGetCount(cfr
);
2016 r
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
2017 for (i
= 0; i
< ac
; i
++) {
2018 CFTypeRef v
= CFArrayGetValueAtIndex(cfr
, i
);
2020 launch_data_t iv
= CF2launch_data(v
);
2021 launch_data_array_set_index(r
, iv
, i
);
2024 } else if (cft
== CFDictionaryGetTypeID()) {
2025 r
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
2026 CFDictionaryApplyFunction(cfr
, myCFDictionaryApplyFunction
, r
);
2027 } else if (cft
== CFDataGetTypeID()) {
2028 r
= launch_data_alloc(LAUNCH_DATA_OPAQUE
);
2029 launch_data_set_opaque(r
, CFDataGetBytePtr(cfr
), CFDataGetLength(cfr
));
2030 } else if (cft
== CFNumberGetTypeID()) {
2033 CFNumberType cfnt
= CFNumberGetType(cfr
);
2035 case kCFNumberSInt8Type
:
2036 case kCFNumberSInt16Type
:
2037 case kCFNumberSInt32Type
:
2038 case kCFNumberSInt64Type
:
2039 case kCFNumberCharType
:
2040 case kCFNumberShortType
:
2041 case kCFNumberIntType
:
2042 case kCFNumberLongType
:
2043 case kCFNumberLongLongType
:
2044 CFNumberGetValue(cfr
, kCFNumberLongLongType
, &n
);
2045 r
= launch_data_alloc(LAUNCH_DATA_INTEGER
);
2046 launch_data_set_integer(r
, n
);
2048 case kCFNumberFloat32Type
:
2049 case kCFNumberFloat64Type
:
2050 case kCFNumberFloatType
:
2051 case kCFNumberDoubleType
:
2052 CFNumberGetValue(cfr
, kCFNumberDoubleType
, &d
);
2053 r
= launch_data_alloc(LAUNCH_DATA_REAL
);
2054 launch_data_set_real(r
, d
);
2067 help_cmd(int argc
, char *const argv
[])
2069 size_t i
, l
, cmdwidth
= 0;
2071 int level
= LOG_NOTICE
;
2072 if (argc
== 0 || argv
== NULL
) {
2076 launchctl_log(level
, "usage: %s <subcommand>", getprogname());
2078 for (i
= 0; i
< (sizeof cmds
/ sizeof cmds
[0]); i
++) {
2079 l
= strlen(cmds
[i
].name
);
2085 for (i
= 0; i
< (sizeof cmds
/ sizeof cmds
[0]); i
++) {
2086 launchctl_log(level
, "\t%-*s\t%s", (int)cmdwidth
, cmds
[i
].name
, cmds
[i
].desc
);
2093 exit_cmd(int argc
__attribute__((unused
)), char *const argv
[] __attribute__((unused
)))
2102 fcntl(fd
, F_SETFD
, 1);
2107 do_single_user_mode(bool sflag
)
2110 while (!do_single_user_mode2()) {
2117 do_single_user_mode2(void)
2119 bool runcom_fsck
= true; /* should_fsck(); */
2124 switch ((p
= fork())) {
2126 syslog(LOG_ERR
, "can't fork single-user shell, trying again: %m");
2131 (void)os_assumes_zero(waitpid(p
, &wstatus
, 0));
2132 if (WIFEXITED(wstatus
)) {
2133 if (WEXITSTATUS(wstatus
) == EXIT_SUCCESS
) {
2136 launchctl_log(LOG_NOTICE
, "single user mode: exit status: %d", WEXITSTATUS(wstatus
));
2139 launchctl_log(LOG_NOTICE
, "single user mode shell: %s", strsignal(WTERMSIG(wstatus
)));
2144 revoke(_PATH_CONSOLE
);
2145 if (posix_assumes_zero((fd
= open(_PATH_CONSOLE
, O_RDWR
))) == -1) {
2146 _exit(EXIT_FAILURE
);
2148 if (posix_assumes_zero(login_tty(fd
)) == -1) {
2149 _exit(EXIT_FAILURE
);
2152 mach_timespec_t wt
= { 5, 0 };
2153 IOKitWaitQuiet(kIOMasterPortDefault
, &wt
); /* This will hopefully return after all the kexts have shut up. */
2155 setenv("TERM", "vt100", 1);
2157 fprintf(stdout
, "Singleuser boot -- fsck not done\n");
2158 fprintf(stdout
, "Root device is mounted read-only\n");
2159 fprintf(stdout
, "If you want to make modifications to files:\n");
2160 fprintf(stdout
, "\t/sbin/fsck -fy\n\t/sbin/mount -uw /\n");
2161 fprintf(stdout
, "If you wish to boot the system:\n");
2162 fprintf(stdout
, "\texit\n");
2166 execl(_PATH_BSHELL
, "-sh", NULL
);
2167 fprintf(stderr
, "can't exec %s for single user: %m\n", _PATH_BSHELL
);
2168 _exit(EXIT_FAILURE
);
2172 do_crash_debug_mode(void)
2174 while (!do_crash_debug_mode2()) {
2180 do_crash_debug_mode2(void)
2186 switch ((p
= fork())) {
2188 syslog(LOG_ERR
, "can't fork crash debug shell, trying again: %m");
2193 (void)os_assumes_zero(waitpid(p
, &wstatus
, 0));
2194 if (WIFEXITED(wstatus
)) {
2195 if (WEXITSTATUS(wstatus
) == EXIT_SUCCESS
) {
2198 launchctl_log(LOG_NOTICE
, "crash debug mode: exit status: %d", WEXITSTATUS(wstatus
));
2201 launchctl_log(LOG_NOTICE
, "crash debug mode shell: %s", strsignal(WTERMSIG(wstatus
)));
2206 revoke(_PATH_CONSOLE
);
2207 if (posix_assumes_zero((fd
= open(_PATH_CONSOLE
, O_RDWR
))) == -1) {
2208 _exit(EXIT_FAILURE
);
2210 if (posix_assumes_zero(login_tty(fd
)) == -1) {
2211 _exit(EXIT_FAILURE
);
2214 /* The idea is to wait until all the kexts have quiesced to prevent a bunch
2215 * of log messages from being slammed onto the console prompt. It mostly
2218 mach_timespec_t wt
= { 5, 0 };
2219 IOKitWaitQuiet(kIOMasterPortDefault
, &wt
);
2221 setenv("TERM", "vt100", 1);
2222 fprintf(stdout
, "Entering boot-time debugging mode...\n");
2223 fprintf(stdout
, "The system bootstrapper process has crashed. To debug:\n");
2224 fprintf(stdout
, "\tgdb attach %i\n", getppid());
2225 fprintf(stdout
, "You can try booting the system with:\n");
2226 fprintf(stdout
, "\tlaunchctl load -S System -D All\n");
2228 execl(_PATH_BSHELL
, "-sh", NULL
);
2229 fprintf(stderr
, "can't exec %s for crash debug: %m\n", _PATH_BSHELL
);
2230 _exit(EXIT_FAILURE
);
2234 exit_at_sigterm(int sig
)
2236 if (sig
== SIGTERM
) {
2237 _exit(EXIT_SUCCESS
);
2242 fatal_signal_handler(int sig
__attribute__((unused
)), siginfo_t
*si
__attribute__((unused
)), void *uap
__attribute__((unused
)))
2244 do_crash_debug_mode();
2248 handle_system_bootstrapper_crashes_separately(void)
2250 if (!_launchctl_startup_debugging
) {
2254 fprintf(stdout
, "com.apple.launchctl.System\t\t\t*** Handling system bootstrapper crashes separately. ***\n");
2255 struct sigaction fsa
;
2257 fsa
.sa_sigaction
= fatal_signal_handler
;
2258 fsa
.sa_flags
= SA_SIGINFO
;
2259 sigemptyset(&fsa
.sa_mask
);
2261 (void)posix_assumes_zero(sigaction(SIGILL
, &fsa
, NULL
));
2262 (void)posix_assumes_zero(sigaction(SIGFPE
, &fsa
, NULL
));
2263 (void)posix_assumes_zero(sigaction(SIGBUS
, &fsa
, NULL
));
2264 (void)posix_assumes_zero(sigaction(SIGTRAP
, &fsa
, NULL
));
2265 (void)posix_assumes_zero(sigaction(SIGABRT
, &fsa
, NULL
));
2268 #if TARGET_OS_EMBEDDED
2270 init_data_protection(void)
2272 if (path_check("/usr/libexec/init_data_protection")) {
2273 const char *init_cp
[] = { "/usr/libexec/init_data_protection", NULL
};
2274 if (fwexec(init_cp
, NULL
) == -1) {
2275 launchctl_log(LOG_ERR
, "Couldn't init content protection: %d: %s", errno
, strerror(errno
));
2276 (void)reboot(RB_HALT
);
2278 _exit(EXIT_FAILURE
);
2285 system_specific_bootstrap(bool sflag
)
2287 int hnmib
[] = { CTL_KERN
, KERN_HOSTNAME
};
2291 launch_data_t lda
, ldb
;
2294 handle_system_bootstrapper_crashes_separately();
2296 // Disable Libinfo lookups to mdns and ds while bootstrapping (8698260)
2297 si_search_module_set_flags("mdns", 1);
2298 si_search_module_set_flags("ds", 1);
2300 /* rc.cdrom's hack to load the system means that we're not the real system
2301 * bootstrapper. So we set this environment variable, and if the real
2302 * bootstrapper detects it, it will disable lookups to mDNSResponder and
2303 * opendirectoryd to prevent deadlocks at boot.
2305 * See <rdar://problem/9877230>.
2307 (void)setenv(LAUNCH_ENV_BOOTSTRAPPINGSYSTEM
, "1", 1);
2309 do_sysversion_sysctl();
2311 do_single_user_mode(sflag
);
2313 (void)posix_assumes_zero(kq
= kqueue());
2314 EV_SET(&kev
, 0, EVFILT_TIMER
, EV_ADD
|EV_ONESHOT
, NOTE_SECONDS
, 60, 0);
2315 (void)posix_assumes_zero(kevent(kq
, &kev
, 1, NULL
, 0, NULL
));
2317 __OS_COMPILETIME_ASSERT__(SIG_ERR
== (typeof(SIG_ERR
))-1);
2318 EV_SET(&kev
, SIGTERM
, EVFILT_SIGNAL
, EV_ADD
, 0, 0, 0);
2319 (void)posix_assumes_zero(kevent(kq
, &kev
, 1, NULL
, 0, NULL
));
2320 (void)posix_assumes_zero(signal(SIGTERM
, SIG_IGN
));
2321 (void)posix_assumes_zero(sysctl(hnmib
, 2, NULL
, NULL
, "localhost", sizeof("localhost")));
2323 loopback_setup_ipv4();
2324 loopback_setup_ipv6();
2326 apply_sysctls_from_file("/etc/sysctl.conf");
2328 #if TARGET_OS_EMBEDDED
2329 if (path_check("/etc/rc.boot")) {
2330 const char *rcboot_tool
[] = { "/etc/rc.boot", NULL
};
2332 (void)posix_assumes_zero(signal(SIGTERM
, exit_at_sigterm
));
2333 (void)posix_assumes_zero(fwexec(rcboot_tool
, NULL
));
2337 if (path_check("/etc/rc.cdrom")) {
2338 const char *rccdrom_tool
[] = { _PATH_BSHELL
, "/etc/rc.cdrom", "multiuser", NULL
};
2340 /* The bootstrapper should always be killable during install-time. This
2341 * is a special case for /etc/rc.cdrom, which runs a process and never
2344 * <rdar://problem/6103485>
2346 (void)posix_assumes_zero(signal(SIGTERM
, exit_at_sigterm
));
2347 (void)posix_assumes_zero(fwexec(rccdrom_tool
, NULL
));
2348 (void)reboot(RB_HALT
);
2349 _exit(EXIT_FAILURE
);
2350 } else if (is_netboot()) {
2351 const char *rcnetboot_tool
[] = { _PATH_BSHELL
, "/etc/rc.netboot", "init", NULL
};
2352 if (posix_assumes_zero(fwexec(rcnetboot_tool
, NULL
)) == -1) {
2353 (void)reboot(RB_HALT
);
2354 _exit(EXIT_FAILURE
);
2357 do_potential_fsck();
2360 #if TARGET_OS_EMBEDDED
2361 if (path_check("/usr/libexec/tzinit")) {
2362 const char *tzinit_tool
[] = { "/usr/libexec/tzinit", NULL
};
2363 (void)posix_assumes_zero(fwexec(tzinit_tool
, NULL
));
2367 #if TARGET_OS_EMBEDDED
2368 if (path_check("/usr/libexec/FinishRestoreFromBackup")) {
2369 const char *finish_restore
[] = { "/usr/libexec/FinishRestoreFromBackup", NULL
};
2370 if (fwexec(finish_restore
, NULL
) == -1) {
2371 launchctl_log(LOG_ERR
, "Couldn't finish restore: %d: %s", errno
, strerror(errno
));
2372 (void)reboot(RB_HALT
);
2374 _exit(EXIT_FAILURE
);
2379 if (path_check("/usr/libexec/cc_fips_test")) {
2380 const char *fips_tool
[] = { "/usr/libexec/cc_fips_test", "-P", NULL
};
2381 if (fwexec(fips_tool
, NULL
) == -1) {
2382 launchctl_log(LOG_ERR
, "FIPS self check failure: %d: %s", errno
, strerror(errno
));
2383 (void)reboot(RB_HALT
);
2385 _exit(EXIT_FAILURE
);
2389 if (path_check("/etc/rc.server")) {
2390 const char *rcserver_tool
[] = { _PATH_BSHELL
, "/etc/rc.server", NULL
};
2391 (void)posix_assumes_zero(fwexec(rcserver_tool
, NULL
));
2394 read_launchd_conf();
2396 if (path_check("/var/account/acct")) {
2397 (void)posix_assumes_zero(acct("/var/account/acct"));
2400 #if !TARGET_OS_EMBEDDED
2401 if (path_check("/etc/fstab")) {
2402 const char *mount_tool
[] = { "mount", "-vat", "nonfs", NULL
};
2403 (void)posix_assumes_zero(fwexec(mount_tool
, NULL
));
2407 if (path_check("/etc/rc.installer_cleanup")) {
2408 const char *rccleanup_tool
[] = { _PATH_BSHELL
, "/etc/rc.installer_cleanup", "multiuser", NULL
};
2409 (void)posix_assumes_zero(fwexec(rccleanup_tool
, NULL
));
2412 if (path_check("/etc/rc.deferred_install")) {
2414 const char *deferredinstall_tool
[] = { _PATH_BSHELL
, "/etc/rc.deferred_install", NULL
};
2415 if (posix_assumes_zero(fwexec(deferredinstall_tool
, &status
)) == 0) {
2416 if (WEXITSTATUS(status
) == EXIT_SUCCESS
) {
2417 if (_launchctl_apple_internal
) {
2418 launchctl_log(LOG_NOTICE
, "Deferred install script completed successfully. Rebooting in 3 seconds...");
2422 (void)remove(deferredinstall_tool
[1]);
2423 (void)reboot(RB_AUTOBOOT
);
2426 launchctl_log(LOG_NOTICE
, "Deferred install script exited with status %i. Continuing boot and hoping it'll work...", WEXITSTATUS(status
));
2427 (void)remove(deferredinstall_tool
[1]);
2432 empty_dir(_PATH_VARRUN
, NULL
);
2433 empty_dir(_PATH_TMP
, NULL
);
2434 (void)remove(_PATH_NOLOGIN
);
2436 if (path_check("/usr/libexec/dirhelper")) {
2437 const char *dirhelper_tool
[] = { "/usr/libexec/dirhelper", "-machineBoot", NULL
};
2438 (void)posix_assumes_zero(fwexec(dirhelper_tool
, NULL
));
2441 (void)posix_assumes_zero(touch_file(_PATH_UTMPX
, DEFFILEMODE
));
2442 #if !TARGET_OS_EMBEDDED
2443 (void)posix_assumes_zero(touch_file(_PATH_VARRUN
"/.systemStarterRunning", DEFFILEMODE
));
2447 /* Only start auditing if not "Disabled" in auditd plist. */
2448 if ((lda
= read_plist_file(AUDITD_PLIST_FILE
, false, false)) != NULL
&& ((ldb
= launch_data_dict_lookup(lda
, LAUNCH_JOBKEY_DISABLED
)) == NULL
|| job_disabled_logic(ldb
) == false)) {
2449 (void)os_assumes_zero(audit_quick_start());
2450 launch_data_free(lda
);
2453 if (path_check("/etc/security/rc.audit")) {
2454 const char *audit_tool
[] = { _PATH_BSHELL
, "/etc/security/rc.audit", NULL
};
2455 (void)posix_assumes_zero(fwexec(audit_tool
, NULL
));
2459 #if HAVE_SYSTEMSTATS
2463 do_BootCache_magic(BOOTCACHE_START
);
2465 preheat_page_cache_hack();
2467 _vproc_set_global_on_demand(true);
2469 char *load_launchd_items
[] = { "load", "-D", "all", NULL
};
2470 int load_launchd_items_cnt
= 3;
2472 if (is_safeboot()) {
2473 load_launchd_items
[2] = "system";
2476 (void)posix_assumes_zero(load_and_unload_cmd(load_launchd_items_cnt
, load_launchd_items
));
2478 /* See <rdar://problem/5066316>. */
2479 if (!_launchctl_apple_internal
) {
2480 mach_timespec_t w
= { 5, 0 };
2481 IOKitWaitQuiet(kIOMasterPortDefault
, &w
);
2484 do_BootCache_magic(BOOTCACHE_TAG
);
2486 do_bootroot_magic();
2488 _vproc_set_global_on_demand(false);
2490 (void)posix_assumes_zero(kevent(kq
, NULL
, 0, &kev
, 1, NULL
));
2492 /* warmd now handles cutting off the BootCache. We just kick it off. */
2497 do_BootCache_magic(BootCache_action_t what
)
2499 const char *bcc_tool
[] = { "/usr/sbin/BootCacheControl", NULL
, NULL
};
2501 if (is_safeboot() || !path_check(bcc_tool
[0])) {
2506 case BOOTCACHE_START
:
2507 bcc_tool
[1] = "start";
2510 bcc_tool
[1] = "tag";
2512 case BOOTCACHE_STOP
:
2513 bcc_tool
[1] = "stop";
2517 fwexec(bcc_tool
, NULL
);
2521 bootstrap_cmd(int argc
, char *const argv
[])
2523 char *session
= NULL
;
2527 while ((ch
= getopt(argc
, argv
, "sS:")) != -1) {
2545 launchctl_log(LOG_ERR
, "usage: %s bootstrap [-s] -S <session-type>", getprogname());
2549 if (strcasecmp(session
, "System") == 0) {
2550 _launchctl_system_bootstrap
= true;
2551 system_specific_bootstrap(sflag
);
2553 char *load_launchd_items
[] = {
2563 size_t the_argc
= 5;
2565 bool bootstrap_login_items
= false;
2566 if (strcasecmp(session
, VPROCMGR_SESSION_AQUA
) == 0) {
2567 bootstrap_login_items
= true;
2568 } else if (strcasecmp(session
, VPROCMGR_SESSION_BACKGROUND
) == 0
2569 || strcasecmp(session
, VPROCMGR_SESSION_LOGINWINDOW
) == 0) {
2570 /* If we're bootstrapping either the LoginWindow or Background
2571 * sessions, then we only load items from /System and /Library. We
2572 * do not attempt to load anything from a user's home directory, as
2573 * it might not be available at this time.
2575 load_launchd_items
[4] = "system";
2576 if (!is_safeboot()) {
2577 load_launchd_items
[5] = "-D";
2578 load_launchd_items
[6] = "local";
2582 if (strcasecmp(session
, VPROCMGR_SESSION_BACKGROUND
) == 0) {
2583 /* This is to force a bootstrapped job to inherit its security
2584 * session from the launchd that it resides in.
2586 _launchctl_peruser_bootstrap
= true;
2587 read_launchd_conf();
2591 if (is_safeboot()) {
2592 load_launchd_items
[4] = "system";
2595 int result
= load_and_unload_cmd(the_argc
, load_launchd_items
);
2597 syslog(LOG_ERR
, "Could not bootstrap session: %s", session
);
2601 /* This will tell launchd to start listening on MachServices again. When
2602 * bootstrapping, launchd ignores requests from everyone but the
2603 * bootstrapper (us), so this unsets the "weird bootstrap" mode.
2606 vproc_err_t verr
= vproc_swap_integer(NULL
, VPROC_GSK_WEIRD_BOOTSTRAP
, &junk
, NULL
);
2608 #if !TARGET_OS_EMBEDDED
2609 if (bootstrap_login_items
) {
2610 void *smf
= dlopen("/System/Library/Frameworks/ServiceManagement.framework/Versions/A/ServiceManagement", 0);
2612 void (*_SMLoginItemBootstrapItemsFunc
)(void) = dlsym(smf
, "_SMLoginItemBootstrapItems");
2613 if (_SMLoginItemBootstrapItemsFunc
) {
2614 _SMLoginItemBootstrapItemsFunc();
2616 launchctl_log(LOG_ERR
, "Could not find login item bootstrap function. LoginItems will be unavailable.");
2619 launchctl_log(LOG_ERR
, "Failed to open ServiceManagement framework. LoginItems will be unavailable.");
2623 } else if (bootstrap_login_items
) {
2624 launchctl_log(LOG_ERR
, "Failed to unset weird bootstrap. LoginItems will be unavailable.");
2632 load_and_unload_cmd(int argc
, char *const argv
[])
2634 NSSearchPathEnumerationState es
= 0;
2635 char nspath
[PATH_MAX
* 2]; /* safe side, we need to append */
2636 bool badopts
= false;
2637 struct load_unload_state lus
;
2641 memset(&lus
, 0, sizeof(lus
));
2643 if (strcmp(argv
[0], "load") == 0) {
2647 while ((ch
= getopt(argc
, argv
, "wFS:D:")) != -1) {
2650 lus
.editondisk
= true;
2653 lus
.forceload
= true;
2656 lus
.session_type
= optarg
;
2659 if (strcasecmp(optarg
, "all") == 0) {
2660 es
|= NSAllDomainsMask
;
2661 } else if (strcasecmp(optarg
, "user") == 0) {
2662 es
|= NSUserDomainMask
;
2663 } else if (strcasecmp(optarg
, "local") == 0) {
2664 es
|= NSLocalDomainMask
;
2665 } else if (strcasecmp(optarg
, "network") == 0) {
2666 es
|= NSNetworkDomainMask
;
2667 } else if (strcasecmp(optarg
, "system") == 0) {
2668 es
|= NSSystemDomainMask
;
2682 if (lus
.session_type
== NULL
) {
2683 es
&= ~NSUserDomainMask
;
2686 if (argc
== 0 && es
== 0) {
2691 launchctl_log(LOG_ERR
, "usage: %s load [-wF] [-D <user|local|network|system|all>] paths...", getprogname());
2696 vproc_err_t verr
= vproc_swap_string(NULL
, VPROC_GSK_JOB_OVERRIDES_DB
, NULL
, &_launchctl_job_overrides_db_path
);
2698 if (bootstrap_port
) {
2699 launchctl_log(LOG_ERR
, "Could not get location of job overrides database: ppid/bootstrap: %d/0x%x", getppid(), bootstrap_port
);
2702 dbfd
= open(_launchctl_job_overrides_db_path
, O_RDONLY
| O_EXLOCK
| O_CREAT
, S_IRUSR
| S_IWUSR
);
2704 _launchctl_overrides_db
= (CFMutableDictionaryRef
)CreateMyPropertyListFromFile(_launchctl_job_overrides_db_path
);
2705 if (!_launchctl_overrides_db
) {
2706 _launchctl_overrides_db
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2708 } else if (errno
!= EROFS
) {
2709 launchctl_log(LOG_ERR
, "Could not open job overrides database at: %s: %d: %s", _launchctl_job_overrides_db_path
, errno
, strerror(errno
));
2713 #if READ_JETSAM_DEFAULTS
2714 if (!read_jetsam_defaults()) {
2715 launchctl_log(LOG_NOTICE
, "Failed to read jetsam defaults; no process limits applied");
2719 /* Only one pass! */
2720 lus
.pass1
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
2722 es
= NSStartSearchPathEnumeration(NSLibraryDirectory
, es
);
2724 while ((es
= NSGetNextSearchPathEnumeration(es
, nspath
))) {
2725 if (lus
.session_type
) {
2726 strcat(nspath
, "/LaunchAgents");
2728 strcat(nspath
, "/LaunchDaemons");
2731 bool should_glob
= true;
2733 #if TARGET_OS_EMBEDDED
2734 if (require_jobs_from_cache()) {
2735 CFDictionaryRef cache
= GetPropertyListFromCache();
2737 CFDictionaryRef launchdJobs
= CFDictionaryGetValue(cache
, CFSTR(XPC_PLIST_CACHE_KEY
));
2739 CFIndex sz
= CFDictionaryGetCount(launchdJobs
);
2741 CFStringRef
*keys
= malloc(sz
* sizeof(CFStringRef
));
2742 CFDictionaryGetKeysAndValues(launchdJobs
, (const void**)keys
, NULL
);
2744 for (i
=0; i
< (size_t)sz
; i
++) {
2745 char path
[PATH_MAX
];
2746 if (CFStringGetCString(keys
[i
], path
, PATH_MAX
, kCFStringEncodingUTF8
) && (strncmp(path
, nspath
, strlen(nspath
)) == 0)) {
2747 readpath(path
, &lus
);
2753 should_glob
= false;
2760 if (glob(nspath
, GLOB_TILDE
|GLOB_NOSORT
, NULL
, &g
) == 0) {
2761 for (i
= 0; i
< g
.gl_pathc
; i
++) {
2762 readpath(g
.gl_pathv
[i
], &lus
);
2769 for (i
= 0; i
< (size_t)argc
; i
++) {
2770 readpath(argv
[i
], &lus
);
2773 if (launch_data_array_get_count(lus
.pass1
) == 0) {
2774 if (!_launchctl_is_managed
) {
2775 launchctl_log(LOG_ERR
, "nothing found to %s", lus
.load
? "load" : "unload");
2777 launch_data_free(lus
.pass1
);
2778 return _launchctl_is_managed
? 0 : 1;
2782 distill_jobs(lus
.pass1
);
2783 submit_job_pass(lus
.pass1
);
2785 for (i
= 0; i
< launch_data_array_get_count(lus
.pass1
); i
++) {
2786 unloadjob(launch_data_array_get_index(lus
.pass1
, i
));
2790 if (_launchctl_overrides_db_changed
) {
2791 WriteMyPropertyListToFile(_launchctl_overrides_db
, _launchctl_job_overrides_db_path
);
2794 flock(dbfd
, LOCK_UN
);
2800 submit_job_pass(launch_data_t jobs
)
2802 launch_data_t msg
, resp
;
2806 if (launch_data_array_get_count(jobs
) == 0)
2809 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
2811 launch_data_dict_insert(msg
, jobs
, LAUNCH_KEY_SUBMITJOB
);
2813 resp
= launch_msg(msg
);
2816 switch (launch_data_get_type(resp
)) {
2817 case LAUNCH_DATA_ERRNO
:
2818 if ((e
= launch_data_get_errno(resp
)))
2819 launchctl_log(LOG_ERR
, "%s", strerror(e
));
2821 case LAUNCH_DATA_ARRAY
:
2822 for (i
= 0; i
< launch_data_array_get_count(jobs
); i
++) {
2823 launch_data_t obatind
= launch_data_array_get_index(resp
, i
);
2824 launch_data_t jatind
= launch_data_array_get_index(jobs
, i
);
2825 const char *lab4job
= launch_data_get_string(launch_data_dict_lookup(jatind
, LAUNCH_JOBKEY_LABEL
));
2826 if (LAUNCH_DATA_ERRNO
== launch_data_get_type(obatind
)) {
2827 e
= launch_data_get_errno(obatind
);
2830 launchctl_log(LOG_ERR
, "%s: %s", lab4job
, "Already loaded");
2833 launchctl_log(LOG_ERR
, "%s: %s", lab4job
, "Not loaded");
2836 launchctl_log(LOG_ERR
, "%s: %s", lab4job
, "Could not set security session");
2838 launchctl_log(LOG_ERR
, "%s: %s", lab4job
, strerror(e
));
2846 launchctl_log(LOG_ERR
, "unknown respose from launchd!");
2849 launch_data_free(resp
);
2851 launchctl_log(LOG_ERR
, "launch_msg(): %s", strerror(errno
));
2854 launch_data_free(msg
);
2858 start_stop_remove_cmd(int argc
, char *const argv
[])
2860 launch_data_t resp
, msg
;
2861 const char *lmsgcmd
= LAUNCH_KEY_STOPJOB
;
2864 if (0 == strcmp(argv
[0], "start"))
2865 lmsgcmd
= LAUNCH_KEY_STARTJOB
;
2867 if (0 == strcmp(argv
[0], "remove"))
2868 lmsgcmd
= LAUNCH_KEY_REMOVEJOB
;
2871 launchctl_log(LOG_ERR
, "usage: %s %s <job label>", getprogname(), argv
[0]);
2875 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
2876 launch_data_dict_insert(msg
, launch_data_new_string(argv
[1]), lmsgcmd
);
2878 resp
= launch_msg(msg
);
2879 launch_data_free(msg
);
2882 launchctl_log(LOG_ERR
, "launch_msg(): %s", strerror(errno
));
2884 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) {
2885 if ((e
= launch_data_get_errno(resp
))) {
2886 launchctl_log(LOG_ERR
, "%s %s error: %s", getprogname(), argv
[0], strerror(e
));
2890 launchctl_log(LOG_ERR
, "%s %s returned unknown response", getprogname(), argv
[0]);
2894 launch_data_free(resp
);
2899 print_jobs(launch_data_t j
, const char *key
__attribute__((unused
)), void *context
__attribute__((unused
)))
2901 static size_t depth
= 0;
2902 launch_data_t lo
= launch_data_dict_lookup(j
, LAUNCH_JOBKEY_LABEL
);
2903 launch_data_t pido
= launch_data_dict_lookup(j
, LAUNCH_JOBKEY_PID
);
2904 launch_data_t stato
= launch_data_dict_lookup(j
, LAUNCH_JOBKEY_LASTEXITSTATUS
);
2905 const char *label
= launch_data_get_string(lo
);
2909 fprintf(stdout
, "%lld\t-\t%s\n", launch_data_get_integer(pido
), label
);
2911 int wstatus
= (int)launch_data_get_integer(stato
);
2912 if (WIFEXITED(wstatus
)) {
2913 fprintf(stdout
, "-\t%d\t%s\n", WEXITSTATUS(wstatus
), label
);
2914 } else if (WIFSIGNALED(wstatus
)) {
2915 fprintf(stdout
, "-\t-%d\t%s\n", WTERMSIG(wstatus
), label
);
2917 fprintf(stdout
, "-\t???\t%s\n", label
);
2920 fprintf(stdout
, "-\t-\t%s\n", label
);
2922 for (i
= 0; i
< depth
; i
++) {
2923 fprintf(stdout
, "\t");
2928 print_obj(launch_data_t obj
, const char *key
, void *context
__attribute__((unused
)))
2930 static size_t indent
= 0;
2933 for (i
= 0; i
< indent
; i
++) {
2934 fprintf(stdout
, "\t");
2938 fprintf(stdout
, "\"%s\" = ", key
);
2941 switch (launch_data_get_type(obj
)) {
2942 case LAUNCH_DATA_STRING
:
2943 fprintf(stdout
, "\"%s\";\n", launch_data_get_string(obj
));
2945 case LAUNCH_DATA_INTEGER
:
2946 fprintf(stdout
, "%lld;\n", launch_data_get_integer(obj
));
2948 case LAUNCH_DATA_REAL
:
2949 fprintf(stdout
, "%f;\n", launch_data_get_real(obj
));
2951 case LAUNCH_DATA_BOOL
:
2952 fprintf(stdout
, "%s;\n", launch_data_get_bool(obj
) ? "true" : "false");
2954 case LAUNCH_DATA_ARRAY
:
2955 c
= launch_data_array_get_count(obj
);
2956 fprintf(stdout
, "(\n");
2958 for (i
= 0; i
< c
; i
++) {
2959 print_obj(launch_data_array_get_index(obj
, i
), NULL
, NULL
);
2962 for (i
= 0; i
< indent
; i
++) {
2963 fprintf(stdout
, "\t");
2965 fprintf(stdout
, ");\n");
2967 case LAUNCH_DATA_DICTIONARY
:
2968 fprintf(stdout
, "{\n");
2970 launch_data_dict_iterate(obj
, print_obj
, NULL
);
2972 for (i
= 0; i
< indent
; i
++) {
2973 fprintf(stdout
, "\t");
2975 fprintf(stdout
, "};\n");
2977 case LAUNCH_DATA_FD
:
2978 fprintf(stdout
, "file-descriptor-object;\n");
2980 case LAUNCH_DATA_MACHPORT
:
2981 fprintf(stdout
, "mach-port-object;\n");
2984 fprintf(stdout
, "???;\n");
2990 list_cmd(int argc
, char *const argv
[])
2992 if (_launchctl_is_managed
) {
2993 /* This output is meant for a command line, so don't print anything if
2994 * we're managed by launchd.
2999 launch_data_t resp
, msg
= NULL
;
3002 bool plist_output
= false;
3005 launchctl_log(LOG_ERR
, "usage: %s list [-x] [label]", getprogname());
3007 } else if (argc
>= 2) {
3008 plist_output
= (strncmp(argv
[1], "-x", sizeof("-x")) == 0);
3009 label
= plist_output
? argv
[2] : argv
[1];
3013 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
3014 launch_data_dict_insert(msg
, launch_data_new_string(label
), LAUNCH_KEY_GETJOB
);
3016 resp
= launch_msg(msg
);
3017 launch_data_free(msg
);
3020 launchctl_log(LOG_ERR
, "launch_msg(): %s", strerror(errno
));
3022 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_DICTIONARY
) {
3024 CFDictionaryRef respDict
= CFDictionaryCreateFromLaunchDictionary(resp
);
3025 CFStringRef plistStr
= NULL
;
3027 CFDataRef plistData
= CFPropertyListCreateXMLData(NULL
, (CFPropertyListRef
)respDict
);
3028 CFRelease(respDict
);
3030 plistStr
= CFStringCreateWithBytes(NULL
, CFDataGetBytePtr(plistData
), CFDataGetLength(plistData
), kCFStringEncodingUTF8
, false);
3031 CFRelease(plistData
);
3040 launchctl_log_CFString(LOG_NOTICE
, plistStr
);
3041 CFRelease(plistStr
);
3045 print_obj(resp
, NULL
, NULL
);
3048 launch_data_free(resp
);
3050 launchctl_log(LOG_ERR
, "%s %s returned unknown response", getprogname(), argv
[0]);
3052 launch_data_free(resp
);
3054 } else if (vproc_swap_complex(NULL
, VPROC_GSK_ALLJOBS
, NULL
, &resp
) == NULL
) {
3055 fprintf(stdout
, "PID\tStatus\tLabel\n");
3056 launch_data_dict_iterate(resp
, print_jobs
, NULL
);
3057 launch_data_free(resp
);
3066 stdio_cmd(int argc
__attribute__((unused
)), char *const argv
[])
3068 launchctl_log(LOG_ERR
, "%s %s: This sub-command no longer does anything", getprogname(), argv
[0]);
3073 fyi_cmd(int argc
, char *const argv
[])
3075 launch_data_t resp
, msg
;
3076 const char *lmsgk
= NULL
;
3080 launchctl_log(LOG_ERR
, "usage: %s %s", getprogname(), argv
[0]);
3084 if (!strcmp(argv
[0], "shutdown")) {
3085 lmsgk
= LAUNCH_KEY_SHUTDOWN
;
3086 } else if (!strcmp(argv
[0], "singleuser")) {
3087 lmsgk
= LAUNCH_KEY_SINGLEUSER
;
3092 msg
= launch_data_new_string(lmsgk
);
3093 resp
= launch_msg(msg
);
3094 launch_data_free(msg
);
3097 launchctl_log(LOG_ERR
, "launch_msg(): %s", strerror(errno
));
3099 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) {
3100 if ((e
= launch_data_get_errno(resp
))) {
3101 launchctl_log(LOG_ERR
, "%s %s error: %s", getprogname(), argv
[0], strerror(e
));
3105 launchctl_log(LOG_ERR
, "%s %s returned unknown response", getprogname(), argv
[0]);
3109 launch_data_free(resp
);
3115 logupdate_cmd(int argc
, char *const argv
[])
3117 int64_t inval
, outval
;
3118 bool badargs
= false, maskmode
= false, onlymode
= false, levelmode
= false;
3119 static const struct {
3123 { "debug", LOG_DEBUG
},
3124 { "info", LOG_INFO
},
3125 { "notice", LOG_NOTICE
},
3126 { "warning", LOG_WARNING
},
3127 { "error", LOG_ERR
},
3128 { "critical", LOG_CRIT
},
3129 { "alert", LOG_ALERT
},
3130 { "emergency", LOG_EMERG
},
3132 size_t i
, j
, logtblsz
= sizeof logtbl
/ sizeof logtbl
[0];
3136 if (!strcmp(argv
[1], "mask"))
3138 else if (!strcmp(argv
[1], "only"))
3140 else if (!strcmp(argv
[1], "level"))
3147 m
= LOG_UPTO(LOG_DEBUG
);
3149 if (argc
> 2 && (maskmode
|| onlymode
)) {
3150 for (i
= 2; i
< (size_t)argc
; i
++) {
3151 for (j
= 0; j
< logtblsz
; j
++) {
3152 if (!strcmp(argv
[i
], logtbl
[j
].name
)) {
3154 m
&= ~(LOG_MASK(logtbl
[j
].level
));
3156 m
|= LOG_MASK(logtbl
[j
].level
);
3160 if (j
== logtblsz
) {
3165 } else if (argc
> 2 && levelmode
) {
3166 for (j
= 0; j
< logtblsz
; j
++) {
3167 if (!strcmp(argv
[2], logtbl
[j
].name
)) {
3168 m
= LOG_UPTO(logtbl
[j
].level
);
3174 } else if (argc
!= 1) {
3179 launchctl_log(LOG_ERR
, "usage: %s [[mask loglevels...] | [only loglevels...] [level loglevel]]", getprogname());
3185 if (vproc_swap_integer(NULL
, VPROC_GSK_GLOBAL_LOG_MASK
, argc
!= 1 ? &inval
: NULL
, &outval
) == NULL
) {
3187 for (j
= 0; j
< logtblsz
; j
++) {
3188 if (outval
& LOG_MASK(logtbl
[j
].level
)) {
3189 launchctl_log(LOG_NOTICE
, "%s ", logtbl
[j
].name
);
3192 launchctl_log(LOG_NOTICE
, "");
3200 static const struct {
3204 { "cpu", RLIMIT_CPU
},
3205 { "filesize", RLIMIT_FSIZE
},
3206 { "data", RLIMIT_DATA
},
3207 { "stack", RLIMIT_STACK
},
3208 { "core", RLIMIT_CORE
},
3209 { "rss", RLIMIT_RSS
},
3210 { "memlock", RLIMIT_MEMLOCK
},
3211 { "maxproc", RLIMIT_NPROC
},
3212 { "maxfiles", RLIMIT_NOFILE
}
3215 static const size_t limlookupcnt
= sizeof limlookup
/ sizeof limlookup
[0];
3218 name2num(const char *n
)
3222 for (i
= 0; i
< limlookupcnt
; i
++) {
3223 if (!strcmp(limlookup
[i
].name
, n
)) {
3224 return limlookup
[i
].lim
;
3235 for (i
= 0; i
< limlookupcnt
; i
++) {
3236 if (limlookup
[i
].lim
== n
)
3237 return limlookup
[i
].name
;
3243 lim2str(rlim_t val
, char *buf
)
3245 if (val
== RLIM_INFINITY
)
3246 strcpy(buf
, "unlimited");
3248 sprintf(buf
, "%lld", val
);
3253 str2lim(const char *buf
, rlim_t
*res
)
3256 *res
= strtoll(buf
, &endptr
, 10);
3257 if (!strcmp(buf
, "unlimited")) {
3258 *res
= RLIM_INFINITY
;
3260 } else if (*endptr
== '\0') {
3267 limit_cmd(int argc
, char *const argv
[])
3271 struct rlimit
*lmts
= NULL
;
3272 launch_data_t resp
, resp1
= NULL
, msg
, tmp
;
3276 rlim_t slim
= -1, hlim
= -1;
3277 bool badargs
= false;
3282 if (argc
>= 3 && str2lim(argv
[2], &slim
))
3287 if (argc
== 4 && str2lim(argv
[3], &hlim
))
3290 if (argc
>= 2 && -1 == (which
= name2num(argv
[1])))
3294 launchctl_log(LOG_ERR
, "usage: %s %s [", getprogname(), argv
[0]);
3295 for (i
= 0; i
< limlookupcnt
; i
++)
3296 launchctl_log(LOG_ERR
, "%s %s", limlookup
[i
].name
, (i
+ 1) == limlookupcnt
? "" : "| ");
3297 launchctl_log(LOG_ERR
, "[both | soft hard]]");
3301 msg
= launch_data_new_string(LAUNCH_KEY_GETRESOURCELIMITS
);
3302 resp
= launch_msg(msg
);
3303 launch_data_free(msg
);
3306 launchctl_log(LOG_ERR
, "launch_msg(): %s", strerror(errno
));
3308 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_OPAQUE
) {
3309 lmts
= launch_data_get_opaque(resp
);
3310 lsz
= launch_data_get_opaque_size(resp
);
3312 for (i
= 0; i
< (lsz
/ sizeof(struct rlimit
)); i
++) {
3313 if (argc
== 2 && (size_t)which
!= i
)
3315 launchctl_log(LOG_NOTICE
, "\t%-12s%-15s%-15s", num2name((int)i
),
3316 lim2str(lmts
[i
].rlim_cur
, slimstr
),
3317 lim2str(lmts
[i
].rlim_max
, hlimstr
));
3320 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_STRING
) {
3321 launchctl_log(LOG_ERR
, "%s %s error: %s", getprogname(), argv
[0], launch_data_get_string(resp
));
3324 launchctl_log(LOG_ERR
, "%s %s returned unknown response", getprogname(), argv
[0]);
3328 if (argc
<= 2 || r
!= 0) {
3329 launch_data_free(resp
);
3335 lmts
[which
].rlim_cur
= slim
;
3336 lmts
[which
].rlim_max
= hlim
;
3338 bool maxfiles_exceeded
= false;
3339 if (strncmp(argv
[1], "maxfiles", sizeof("maxfiles")) == 0) {
3341 maxfiles_exceeded
= (strncmp(argv
[2], "unlimited", sizeof("unlimited")) == 0);
3345 maxfiles_exceeded
= (maxfiles_exceeded
|| strncmp(argv
[3], "unlimited", sizeof("unlimited")) == 0);
3348 if (maxfiles_exceeded
) {
3349 launchctl_log(LOG_ERR
, "Neither the hard nor soft limit for \"maxfiles\" can be unlimited. Please use a numeric parameter for both.");
3354 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
3355 tmp
= launch_data_new_opaque(lmts
, lsz
);
3356 launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_SETRESOURCELIMITS
);
3357 resp
= launch_msg(msg
);
3358 launch_data_free(msg
);
3361 launchctl_log(LOG_ERR
, "launch_msg(): %s", strerror(errno
));
3363 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_STRING
) {
3364 launchctl_log(LOG_ERR
, "%s %s error: %s", getprogname(), argv
[0], launch_data_get_string(resp
));
3366 } else if (launch_data_get_type(resp
) != LAUNCH_DATA_OPAQUE
) {
3367 launchctl_log(LOG_ERR
, "%s %s returned unknown response", getprogname(), argv
[0]);
3371 launch_data_free(resp
);
3372 launch_data_free(resp1
);
3378 umask_cmd(int argc
, char *const argv
[])
3380 bool badargs
= false;
3383 int64_t inval
, outval
;
3386 m
= strtol(argv
[1], &endptr
, 8);
3387 if (*endptr
!= '\0' || m
> 0777)
3391 if (argc
> 2 || badargs
) {
3392 launchctl_log(LOG_ERR
, "usage: %s %s <mask>", getprogname(), argv
[0]);
3398 if (vproc_swap_integer(NULL
, VPROC_GSK_GLOBAL_UMASK
, argc
== 2 ? &inval
: NULL
, &outval
) == NULL
) {
3400 launchctl_log(LOG_NOTICE
, "%o", (unsigned int)outval
);
3409 setup_system_context(void)
3411 if (getenv(LAUNCHD_SOCKET_ENV
)) {
3415 if (getenv(LAUNCH_ENV_KEEPCONTEXT
)) {
3419 if (geteuid() != 0) {
3420 launchctl_log(LOG_ERR
, "You must be the root user to perform this operation.");
3424 /* Use the system launchd's socket. */
3425 setenv("__USE_SYSTEM_LAUNCHD", "1", 0);
3427 /* Put ourselves in the system launchd's bootstrap. */
3428 mach_port_t rootbs
= str2bsport("/");
3429 mach_port_deallocate(mach_task_self(), bootstrap_port
);
3430 task_set_bootstrap_port(mach_task_self(), rootbs
);
3431 bootstrap_port
= rootbs
;
3435 submit_cmd(int argc
, char *const argv
[])
3437 launch_data_t msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
3438 launch_data_t job
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
3439 launch_data_t resp
, largv
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
3442 launch_data_dict_insert(job
, launch_data_new_bool(false), LAUNCH_JOBKEY_ONDEMAND
);
3444 while ((ch
= getopt(argc
, argv
, "l:p:o:e:")) != -1) {
3447 launch_data_dict_insert(job
, launch_data_new_string(optarg
), LAUNCH_JOBKEY_LABEL
);
3450 launch_data_dict_insert(job
, launch_data_new_string(optarg
), LAUNCH_JOBKEY_PROGRAM
);
3453 launch_data_dict_insert(job
, launch_data_new_string(optarg
), LAUNCH_JOBKEY_STANDARDOUTPATH
);
3456 launch_data_dict_insert(job
, launch_data_new_string(optarg
), LAUNCH_JOBKEY_STANDARDERRORPATH
);
3459 launchctl_log(LOG_ERR
, "usage: %s submit ...", getprogname());
3466 for (i
= 0; argv
[i
]; i
++) {
3467 launch_data_array_append(largv
, launch_data_new_string(argv
[i
]));
3470 launch_data_dict_insert(job
, largv
, LAUNCH_JOBKEY_PROGRAMARGUMENTS
);
3472 launch_data_dict_insert(msg
, job
, LAUNCH_KEY_SUBMITJOB
);
3474 resp
= launch_msg(msg
);
3475 launch_data_free(msg
);
3478 launchctl_log(LOG_ERR
, "launch_msg(): %s", strerror(errno
));
3480 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) {
3481 errno
= launch_data_get_errno(resp
);
3483 launchctl_log(LOG_ERR
, "%s %s error: %s", getprogname(), argv
[0], strerror(errno
));
3487 launchctl_log(LOG_ERR
, "%s %s error: %s", getprogname(), argv
[0], "unknown response");
3490 launch_data_free(resp
);
3496 getrusage_cmd(int argc
, char *const argv
[])
3498 launch_data_t resp
, msg
;
3499 bool badargs
= false;
3504 else if (strcmp(argv
[1], "self") && strcmp(argv
[1], "children"))
3508 launchctl_log(LOG_ERR
, "usage: %s %s self | children", getprogname(), argv
[0]);
3512 if (!strcmp(argv
[1], "self")) {
3513 msg
= launch_data_new_string(LAUNCH_KEY_GETRUSAGESELF
);
3515 msg
= launch_data_new_string(LAUNCH_KEY_GETRUSAGECHILDREN
);
3518 resp
= launch_msg(msg
);
3519 launch_data_free(msg
);
3522 launchctl_log(LOG_ERR
, "launch_msg(): %s", strerror(errno
));
3524 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) {
3525 launchctl_log(LOG_ERR
, "%s %s error: %s", getprogname(), argv
[0], strerror(launch_data_get_errno(resp
)));
3527 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_OPAQUE
) {
3528 struct rusage
*rusage
= launch_data_get_opaque(resp
);
3529 launchctl_log(LOG_NOTICE
, "\t%-10f\tuser time used",
3530 (double)rusage
->ru_utime
.tv_sec
+ (double)rusage
->ru_utime
.tv_usec
/ (double)1000000);
3531 launchctl_log(LOG_NOTICE
, "\t%-10f\tsystem time used",
3532 (double)rusage
->ru_stime
.tv_sec
+ (double)rusage
->ru_stime
.tv_usec
/ (double)1000000);
3533 launchctl_log(LOG_NOTICE
, "\t%-10ld\tmax resident set size", rusage
->ru_maxrss
);
3534 launchctl_log(LOG_NOTICE
, "\t%-10ld\tshared text memory size", rusage
->ru_ixrss
);
3535 launchctl_log(LOG_NOTICE
, "\t%-10ld\tunshared data size", rusage
->ru_idrss
);
3536 launchctl_log(LOG_NOTICE
, "\t%-10ld\tunshared stack size", rusage
->ru_isrss
);
3537 launchctl_log(LOG_NOTICE
, "\t%-10ld\tpage reclaims", rusage
->ru_minflt
);
3538 launchctl_log(LOG_NOTICE
, "\t%-10ld\tpage faults", rusage
->ru_majflt
);
3539 launchctl_log(LOG_NOTICE
, "\t%-10ld\tswaps", rusage
->ru_nswap
);
3540 launchctl_log(LOG_NOTICE
, "\t%-10ld\tblock input operations", rusage
->ru_inblock
);
3541 launchctl_log(LOG_NOTICE
, "\t%-10ld\tblock output operations", rusage
->ru_oublock
);
3542 launchctl_log(LOG_NOTICE
, "\t%-10ld\tmessages sent", rusage
->ru_msgsnd
);
3543 launchctl_log(LOG_NOTICE
, "\t%-10ld\tmessages received", rusage
->ru_msgrcv
);
3544 launchctl_log(LOG_NOTICE
, "\t%-10ld\tsignals received", rusage
->ru_nsignals
);
3545 launchctl_log(LOG_NOTICE
, "\t%-10ld\tvoluntary context switches", rusage
->ru_nvcsw
);
3546 launchctl_log(LOG_NOTICE
, "\t%-10ld\tinvoluntary context switches", rusage
->ru_nivcsw
);
3548 launchctl_log(LOG_ERR
, "%s %s returned unknown response", getprogname(), argv
[0]);
3552 launch_data_free(resp
);
3558 launch_data_array_append(launch_data_t a
, launch_data_t o
)
3560 size_t offt
= launch_data_array_get_count(a
);
3562 return launch_data_array_set_index(a
, o
, offt
);
3566 str2bsport(const char *s
)
3568 bool getrootbs
= strcmp(s
, "/") == 0;
3569 mach_port_t last_bport
, bport
= bootstrap_port
;
3570 task_t task
= mach_task_self();
3571 kern_return_t result
;
3573 if (strcmp(s
, "..") == 0 || getrootbs
) {
3576 result
= bootstrap_parent(last_bport
, &bport
);
3578 if (result
== BOOTSTRAP_NOT_PRIVILEGED
) {
3579 launchctl_log(LOG_ERR
, "Permission denied");
3581 } else if (result
!= BOOTSTRAP_SUCCESS
) {
3582 launchctl_log(LOG_ERR
, "bootstrap_parent() %d", result
);
3585 } while (getrootbs
&& last_bport
!= bport
);
3586 } else if (strcmp(s
, "0") == 0 || strcmp(s
, "NULL") == 0) {
3587 bport
= MACH_PORT_NULL
;
3591 result
= task_for_pid(mach_task_self(), pid
, &task
);
3593 if (result
!= KERN_SUCCESS
) {
3594 launchctl_log(LOG_ERR
, "task_for_pid() %s", mach_error_string(result
));
3598 result
= task_get_bootstrap_port(task
, &bport
);
3600 if (result
!= KERN_SUCCESS
) {
3601 launchctl_log(LOG_ERR
, "Couldn't get bootstrap port: %s", mach_error_string(result
));
3610 bsexec_cmd(int argc
, char *const argv
[])
3612 kern_return_t result
;
3616 launchctl_log(LOG_ERR
, "usage: %s bsexec <PID> prog...", getprogname());
3620 bport
= str2bsport(argv
[1]);
3622 result
= task_set_bootstrap_port(mach_task_self(), bport
);
3624 if (result
!= KERN_SUCCESS
) {
3625 launchctl_log(LOG_ERR
, "Couldn't switch to new bootstrap port: %s", mach_error_string(result
));
3632 setenv(LAUNCH_ENV_KEEPCONTEXT
, "1", 1);
3633 if (fwexec((const char *const *)argv
+ 2, NULL
) == -1) {
3634 launchctl_log(LOG_ERR
, "%s bsexec failed: %s", getprogname(), strerror(errno
));
3642 _bslist_cmd(mach_port_t bport
, unsigned int depth
, bool show_job
, bool local_only
)
3644 kern_return_t result
;
3645 name_array_t service_names
;
3646 name_array_t service_jobs
;
3647 mach_msg_type_number_t service_cnt
, service_jobs_cnt
, service_active_cnt
;
3648 bootstrap_status_array_t service_actives
;
3651 if (bport
== MACH_PORT_NULL
) {
3652 launchctl_log(LOG_ERR
, "Invalid bootstrap port");
3657 flags
|= local_only
? BOOTSTRAP_FORCE_LOCAL
: 0;
3658 result
= bootstrap_info(bport
, &service_names
, &service_cnt
, &service_jobs
, &service_jobs_cnt
, &service_actives
, &service_active_cnt
, flags
);
3659 if (result
!= BOOTSTRAP_SUCCESS
) {
3660 launchctl_log(LOG_ERR
, "bootstrap_info(): %d", result
);
3664 #define bport_state(x) (((x) == BOOTSTRAP_STATUS_ACTIVE) ? "A" : ((x) == BOOTSTRAP_STATUS_ON_DEMAND) ? "D" : "I")
3666 for (i
= 0; i
< service_cnt
; i
++) {
3668 fprintf(stdout
, "%*s%-3s%s\n", depth
, "", bport_state((service_actives
[i
])), service_names
[i
]);
3670 fprintf(stdout
, "%*s%-3s%s (%s)\n", depth
, "", bport_state((service_actives
[i
])), service_names
[i
], service_jobs
[i
]);
3678 bslist_cmd(int argc
, char *const argv
[])
3680 if (_launchctl_is_managed
) {
3681 /* This output is meant for a command line, so don't print anything if
3682 * we're managed by launchd.
3687 mach_port_t bport
= bootstrap_port
;
3688 bool show_jobs
= false;
3689 if (argc
> 2 && strcmp(argv
[2], "-j") == 0) {
3695 bport
= str2bsport(argv
[1]);
3696 } else if (strcmp(argv
[1], "-j") == 0) {
3701 if (bport
== MACH_PORT_NULL
) {
3702 launchctl_log(LOG_ERR
, "Invalid bootstrap port");
3706 return _bslist_cmd(bport
, 0, show_jobs
, false);
3710 _bstree_cmd(mach_port_t bsport
, unsigned int depth
, bool show_jobs
)
3712 if (bsport
== MACH_PORT_NULL
) {
3713 launchctl_log(LOG_ERR
, "No root port!");
3717 mach_port_array_t child_ports
= NULL
;
3718 name_array_t child_names
= NULL
;
3719 bootstrap_property_array_t child_props
= NULL
;
3720 unsigned int cnt
= 0;
3722 kern_return_t kr
= bootstrap_lookup_children(bsport
, &child_ports
, &child_names
, &child_props
, (mach_msg_type_number_t
*)&cnt
);
3723 if (kr
!= BOOTSTRAP_SUCCESS
&& kr
!= BOOTSTRAP_NO_CHILDREN
) {
3724 if (kr
== BOOTSTRAP_NOT_PRIVILEGED
) {
3725 launchctl_log(LOG_ERR
, "You must be root to perform this operation.");
3727 launchctl_log(LOG_ERR
, "bootstrap_lookup_children(): %d", kr
);
3734 _bslist_cmd(bsport
, depth
, show_jobs
, true);
3736 for (i
= 0; i
< cnt
; i
++) {
3738 if (child_props
[i
] & BOOTSTRAP_PROPERTY_PERUSER
) {
3740 } else if (child_props
[i
] & BOOTSTRAP_PROPERTY_EXPLICITSUBSET
) {
3741 type
= "Explicit Subset";
3742 } else if (child_props
[i
] & BOOTSTRAP_PROPERTY_IMPLICITSUBSET
) {
3743 type
= "Implicit Subset";
3744 } else if (child_props
[i
] & BOOTSTRAP_PROPERTY_MOVEDSUBSET
) {
3745 type
= "Moved Subset";
3746 } else if (child_props
[i
] & BOOTSTRAP_PROPERTY_XPC_SINGLETON
) {
3747 type
= "XPC Singleton Domain";
3748 } else if (child_props
[i
] & BOOTSTRAP_PROPERTY_XPC_DOMAIN
) {
3749 type
= "XPC Private Domain";
3754 fprintf(stdout
, "%*s%s (%s)/\n", depth
, "", child_names
[i
], type
);
3755 if (child_ports
[i
] != MACH_PORT_NULL
) {
3756 _bstree_cmd(child_ports
[i
], depth
+ 4, show_jobs
);
3764 bstree_cmd(int argc
, char * const argv
[])
3766 if (_launchctl_is_managed
) {
3767 /* This output is meant for a command line, so don't print anything if
3768 * we're managed by launchd.
3773 bool show_jobs
= false;
3774 if (geteuid() != 0) {
3775 launchctl_log(LOG_ERR
, "You must be root to perform this operation.");
3778 if (argc
== 2 && strcmp(argv
[1], "-j") == 0) {
3781 fprintf(stdout
, "System/\n");
3784 return _bstree_cmd(str2bsport("/"), 4, show_jobs
);
3788 managerpid_cmd(int argc
__attribute__((unused
)), char * const argv
[] __attribute__((unused
)))
3790 int64_t manager_pid
= 0;
3791 vproc_err_t verr
= vproc_swap_integer(NULL
, VPROC_GSK_MGR_PID
, NULL
, (int64_t *)&manager_pid
);
3793 launchctl_log(LOG_NOTICE
, "Unknown job manager!");
3797 launchctl_log(LOG_NOTICE
, "%d", (pid_t
)manager_pid
);
3802 manageruid_cmd(int argc
__attribute__((unused
)), char * const argv
[] __attribute__((unused
)))
3804 int64_t manager_uid
= 0;
3805 vproc_err_t verr
= vproc_swap_integer(NULL
, VPROC_GSK_MGR_UID
, NULL
, (int64_t *)&manager_uid
);
3807 launchctl_log(LOG_NOTICE
, "Unknown job manager!");
3811 launchctl_log(LOG_NOTICE
, "%lli", manager_uid
);
3816 managername_cmd(int argc
__attribute__((unused
)), char * const argv
[] __attribute__((unused
)))
3818 char *manager_name
= NULL
;
3819 vproc_err_t verr
= vproc_swap_string(NULL
, VPROC_GSK_MGR_NAME
, NULL
, &manager_name
);
3821 launchctl_log(LOG_NOTICE
, "Unknown job manager!");
3825 launchctl_log(LOG_NOTICE
, "%s", manager_name
);
3832 asuser_cmd(int argc
, char * const argv
[])
3834 /* This code plays fast and loose with Mach ports. Do NOT use it as any sort
3835 * of reference for port handling. Or really anything else in this file.
3837 uid_t req_uid
= (uid_t
)-2;
3839 req_uid
= atoi(argv
[1]);
3840 if (req_uid
== (uid_t
)-2) {
3841 launchctl_log(LOG_ERR
, "You cannot run a command nobody.");
3845 launchctl_log(LOG_ERR
, "Usage: launchctl asuser <UID> <command> [arguments...].");
3849 if (geteuid() != 0) {
3850 launchctl_log(LOG_ERR
, "You must be root to run a command as another user.");
3854 mach_port_t rbs
= MACH_PORT_NULL
;
3855 kern_return_t kr
= bootstrap_get_root(bootstrap_port
, &rbs
);
3856 if (kr
!= BOOTSTRAP_SUCCESS
) {
3857 launchctl_log(LOG_ERR
, "bootstrap_get_root(): %u", kr
);
3861 mach_port_t bp
= MACH_PORT_NULL
;
3862 kr
= bootstrap_look_up_per_user(rbs
, NULL
, req_uid
, &bp
);
3863 if (kr
!= BOOTSTRAP_SUCCESS
) {
3864 launchctl_log(LOG_ERR
, "bootstrap_look_up_per_user(): %u", kr
);
3868 bootstrap_port
= bp
;
3869 kr
= task_set_bootstrap_port(mach_task_self(), bp
);
3870 if (kr
!= KERN_SUCCESS
) {
3871 launchctl_log(LOG_ERR
, "task_set_bootstrap_port(): 0x%x: %s", kr
, mach_error_string(kr
));
3877 kr
= _vprocmgr_getsocket(sockpath
);
3878 if (kr
!= BOOTSTRAP_SUCCESS
) {
3879 launchctl_log(LOG_ERR
, "_vprocmgr_getsocket(): %u", kr
);
3883 setenv(LAUNCHD_SOCKET_ENV
, sockpath
, 1);
3884 setenv(LAUNCH_ENV_KEEPCONTEXT
, "1", 1);
3885 if (fwexec((const char *const *)argv
+ 2, NULL
) == -1) {
3886 launchctl_log(LOG_ERR
, "Couldn't spawn command: %s", argv
[2]);
3894 loopback_setup_ipv4(void)
3896 struct ifaliasreq ifra
;
3900 memset(&ifr
, 0, sizeof(ifr
));
3901 strcpy(ifr
.ifr_name
, "lo0");
3903 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
3906 if (posix_assumes_zero(ioctl(s
, SIOCGIFFLAGS
, &ifr
)) != -1) {
3907 ifr
.ifr_flags
|= IFF_UP
;
3908 (void)posix_assumes_zero(ioctl(s
, SIOCSIFFLAGS
, &ifr
));
3911 memset(&ifra
, 0, sizeof(ifra
));
3912 strcpy(ifra
.ifra_name
, "lo0");
3913 ((struct sockaddr_in
*)&ifra
.ifra_addr
)->sin_family
= AF_INET
;
3914 ((struct sockaddr_in
*)&ifra
.ifra_addr
)->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
3915 ((struct sockaddr_in
*)&ifra
.ifra_addr
)->sin_len
= sizeof(struct sockaddr_in
);
3916 ((struct sockaddr_in
*)&ifra
.ifra_mask
)->sin_family
= AF_INET
;
3917 ((struct sockaddr_in
*)&ifra
.ifra_mask
)->sin_addr
.s_addr
= htonl(IN_CLASSA_NET
);
3918 ((struct sockaddr_in
*)&ifra
.ifra_mask
)->sin_len
= sizeof(struct sockaddr_in
);
3920 (void)posix_assumes_zero(ioctl(s
, SIOCAIFADDR
, &ifra
));
3925 loopback_setup_ipv6(void)
3927 struct in6_aliasreq ifra6
;
3931 memset(&ifr
, 0, sizeof(ifr
));
3932 strcpy(ifr
.ifr_name
, "lo0");
3934 if ((s6
= socket(AF_INET6
, SOCK_DGRAM
, 0)) == -1)
3937 memset(&ifr
, 0, sizeof(ifr
));
3938 strcpy(ifr
.ifr_name
, "lo0");
3940 if (posix_assumes_zero(ioctl(s6
, SIOCGIFFLAGS
, &ifr
)) != -1) {
3941 ifr
.ifr_flags
|= IFF_UP
;
3942 (void)posix_assumes_zero(ioctl(s6
, SIOCSIFFLAGS
, &ifr
));
3945 memset(&ifra6
, 0, sizeof(ifra6
));
3946 strcpy(ifra6
.ifra_name
, "lo0");
3948 ifra6
.ifra_addr
.sin6_family
= AF_INET6
;
3949 ifra6
.ifra_addr
.sin6_addr
= in6addr_loopback
;
3950 ifra6
.ifra_addr
.sin6_len
= sizeof(struct sockaddr_in6
);
3951 ifra6
.ifra_prefixmask
.sin6_family
= AF_INET6
;
3952 memset(&ifra6
.ifra_prefixmask
.sin6_addr
, 0xff, sizeof(struct in6_addr
));
3953 ifra6
.ifra_prefixmask
.sin6_len
= sizeof(struct sockaddr_in6
);
3954 ifra6
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
3955 ifra6
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
3957 if (ioctl(s6
, SIOCAIFADDR_IN6
, &ifra6
) == -1 && errno
!= EEXIST
) {
3958 (void)os_assumes_zero(errno
);
3965 fwexec(const char *const *argv
, int *wstatus
)
3970 /* We'd use posix_spawnp(), but we want to workaround: 6288899 */
3971 if ((p
= vfork()) == -1) {
3973 } else if (p
== 0) {
3974 execvp(argv
[0], (char *const *)argv
);
3975 _exit(EXIT_FAILURE
);
3978 if (waitpid(p
, wstatus
? wstatus
: &wstatus2
, 0) == -1) {
3984 } else if (WIFEXITED(wstatus2
) && WEXITSTATUS(wstatus2
) == EXIT_SUCCESS
) {
3992 do_potential_fsck(void)
3994 /* XXX: This whole function's logic needs to be redone. */
3996 const char *safe_fsck_tool
[] = { "fsck", "-fy", NULL
};
3997 const char *fsck_tool
[] = { "fsck", "-q", NULL
};
3998 const char *remount_tool
[] = { "mount", "-uw", "/", NULL
};
3999 #if TARGET_OS_EMBEDDED
4000 const char *nvram_tool
[] = { "/usr/sbin/nvram", "auto-boot=false", NULL
};
4001 #endif /* TARGET_OS_EMBEDDED */
4005 if (posix_assumes_zero(statfs("/", &sfs
)) == -1) {
4009 if (!(sfs
.f_flags
& MNT_RDONLY
)) {
4013 if (!is_safeboot()) {
4015 /* We have disabled this block for now. We need to revisit this optimization after Leopard. */
4016 if (sfs
.f_flags
& MNT_JOURNALED
) {
4020 launchctl_log(LOG_NOTICE
, "Running fsck on the boot volume...");
4021 if (fwexec(fsck_tool
, &status
) != -1) {
4022 if (WEXITSTATUS(status
) != 0) {
4023 launchctl_log(LOG_NOTICE
, "fsck exited with status: %d", WEXITSTATUS(status
));
4028 launchctl_log(LOG_NOTICE
, "fwexec(): %d: %s", errno
, strerror(errno
));
4032 launchctl_log(LOG_NOTICE
, "Running safe fsck on the boot volume...");
4033 if (fwexec(safe_fsck_tool
, &status
) != -1) {
4034 if (WEXITSTATUS(status
) != 0) {
4035 launchctl_log(LOG_NOTICE
, "Safe fsck exited with status: %d", WEXITSTATUS(status
));
4040 launchctl_log(LOG_NOTICE
, "fwexec(): %d: %s", errno
, strerror(errno
));
4043 /* someday, we should keep booting read-only, but as of today, other sub-systems cannot handle that scenario */
4044 #if TARGET_OS_EMBEDDED
4045 launchctl_log(LOG_NOTICE
, "fsck failed! Booting into restore mode...");
4046 (void)posix_assumes_zero(fwexec(nvram_tool
, NULL
));
4047 (void)reboot(RB_AUTOBOOT
);
4049 launchctl_log(LOG_NOTICE
, "fsck failed! Shutting down in 3 seconds.");
4051 (void)reboot(RB_HALT
);
4057 #if TARGET_OS_EMBEDDED
4058 /* Once we've validated the root filesystem, kick off any
4059 * tasks needed for data protection before we mount other file
4062 init_data_protection();
4066 * Once this is fixed:
4068 * <rdar://problem/3948774> Mount flag updates should be possible with NULL as the forth argument to mount()
4070 * We can then do this one system call instead of calling out a full blown process.
4072 * assumes(mount(sfs.f_fstypename, "/", MNT_UPDATE, NULL) != -1);
4074 #if TARGET_OS_EMBEDDED
4075 if (path_check("/etc/fstab")) {
4076 const char *mount_tool
[] = { "mount", "-vat", "nonfs", NULL
};
4077 if (posix_assumes_zero(fwexec(mount_tool
, NULL
)) == -1) {
4078 (void)fwexec(nvram_tool
, NULL
);
4079 (void)reboot(RB_AUTOBOOT
);
4084 (void)posix_assumes_zero(fwexec(remount_tool
, NULL
));
4087 fix_bogus_file_metadata();
4091 fix_bogus_file_metadata(void)
4093 // Don't do any of this on embedded: <rdar://problem/13212363>
4094 #if !TARGET_OS_EMBEDDED
4095 static const struct {
4099 const mode_t needed_bits
;
4100 const mode_t bad_bits
;
4103 { "/sbin/launchd", 0, 0, S_IRUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
, S_ISUID
|S_ISGID
|S_ISVTX
|S_IWOTH
, false },
4104 { _PATH_TMP
, 0, 0, S_ISTXT
|S_IRWXU
|S_IRWXG
|S_IRWXO
, S_ISUID
|S_ISGID
, true },
4105 { _PATH_VARTMP
, 0, 0, S_ISTXT
|S_IRWXU
|S_IRWXG
|S_IRWXO
, S_ISUID
|S_ISGID
, true },
4106 { "/var/folders", 0, 0, S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
, S_ISUID
| S_ISGID
, true },
4107 { LAUNCHD_DB_PREFIX
, 0, 0, S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
, S_IWGRP
| S_IWOTH
, true },
4108 { LAUNCHD_DB_PREFIX
"/com.apple.launchd", 0, 0, S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
, S_IWGRP
| S_IWOTH
, true },
4109 // Fixing <rdar://problem/7571633>.
4110 { _PATH_VARDB
, 0, 0, S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
, S_IWGRP
| S_IWOTH
| S_ISUID
| S_ISGID
, true },
4111 { _PATH_VARDB
"mds/", 0, 0, S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
, S_IWGRP
| S_IWOTH
| S_ISUID
| S_ISGID
, true },
4112 // Similar fix for <rdar://problem/6550172>.
4113 { "/Library/StartupItems", 0, 0, S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
, S_IWGRP
| S_IWOTH
| S_ISUID
| S_ISGID
, true },
4118 for (i
= 0; i
< (sizeof(f
) / sizeof(f
[0])); i
++) {
4119 mode_t i_needed_bits
;
4121 bool fix_mode
= false;
4122 bool fix_id
= false;
4124 if (stat(f
[i
].path
, &sb
) == -1) {
4125 launchctl_log(LOG_NOTICE
, "Crucial filesystem check: Path not present: %s. %s", f
[i
].path
, f
[i
].create
? "Will create." : "");
4127 if (posix_assumes_zero(mkdir(f
[i
].path
, f
[i
].needed_bits
)) == -1) {
4129 } else if (posix_assumes_zero(stat(f
[i
].path
, &sb
)) == -1) {
4137 i_needed_bits
= ~sb
.st_mode
& f
[i
].needed_bits
;
4138 i_bad_bits
= sb
.st_mode
& f
[i
].bad_bits
;
4141 launchctl_log(LOG_ERR
, "Crucial filesystem check: Removing bogus mode bits 0%o on path: %s", i_bad_bits
, f
[i
].path
);
4144 if (i_needed_bits
) {
4145 launchctl_log(LOG_ERR
, "Crucial filesystem check: Adding missing mode bits 0%o on path: %s", i_needed_bits
, f
[i
].path
);
4148 if (sb
.st_uid
!= f
[i
].owner
) {
4149 launchctl_log(LOG_ERR
, "Crucial filesystem check: Fixing bogus UID %u on path: %s", sb
.st_uid
, f
[i
].path
);
4152 if (sb
.st_gid
!= f
[i
].group
) {
4153 launchctl_log(LOG_ERR
, "Crucial filesystem check: Fixing bogus GID %u on path: %s", sb
.st_gid
, f
[i
].path
);
4158 (void)posix_assumes_zero(chmod(f
[i
].path
, (sb
.st_mode
& ~i_bad_bits
) | i_needed_bits
));
4161 (void)posix_assumes_zero(chown(f
[i
].path
, f
[i
].owner
, f
[i
].group
));
4169 path_check(const char *path
)
4173 if (stat(path
, &sb
) == 0)
4181 int sbmib
[] = { CTL_KERN
, KERN_SAFEBOOT
};
4183 size_t sbsz
= sizeof(sb
);
4185 if (posix_assumes_zero(sysctl(sbmib
, 2, &sb
, &sbsz
, NULL
, 0)) == -1) {
4195 int nbmib
[] = { CTL_KERN
, KERN_NETBOOT
};
4197 size_t nbsz
= sizeof(nb
);
4199 if (posix_assumes_zero(sysctl(nbmib
, 2, &nb
, &nbsz
, NULL
, 0)) == -1) {
4207 empty_dir(const char *thedir
, struct stat
*psb
)
4216 if (posix_assumes_zero(lstat(thedir
, psb
)) == -1) {
4221 if (posix_assumes_zero(currend_dir_fd
= open(".", 0)) == -1) {
4225 if (posix_assumes_zero(chdir(thedir
)) == -1) {
4229 if (!(od
= opendir("."))) {
4230 (void)os_assumes_zero(errno
);
4234 while ((de
= readdir(od
))) {
4237 if (strcmp(de
->d_name
, ".") == 0) {
4241 if (strcmp(de
->d_name
, "..") == 0) {
4245 if (posix_assumes_zero(lstat(de
->d_name
, &sb
)) == -1) {
4249 if (psb
->st_dev
!= sb
.st_dev
) {
4250 (void)posix_assumes_zero(unmount(de
->d_name
, MNT_FORCE
));
4252 /* Let's lstat() again to see if the unmount() worked and what was
4255 if (posix_assumes_zero(lstat(de
->d_name
, &sb
)) == -1) {
4259 if (os_assumes(psb
->st_dev
== sb
.st_dev
)) {
4264 if (S_ISDIR(sb
.st_mode
)) {
4265 empty_dir(de
->d_name
, &sb
);
4268 (void)posix_assumes_zero(lchflags(de
->d_name
, 0));
4269 (void)posix_assumes_zero(remove(de
->d_name
));
4275 (void)posix_assumes_zero(fchdir(currend_dir_fd
));
4276 (void)posix_assumes_zero(close(currend_dir_fd
));
4280 touch_file(const char *path
, mode_t m
)
4282 int fd
= open(path
, O_CREAT
, m
);
4291 apply_sysctls_from_file(const char *thefile
)
4293 const char *sysctl_tool
[] = { "sysctl", "-w", NULL
, NULL
};
4298 if (!(sf
= fopen(thefile
, "r")))
4301 while ((val
= fgetln(sf
, &ln_len
))) {
4305 if (!(tmpstr
= malloc(ln_len
+ 1))) {
4306 (void)os_assumes_zero(errno
);
4309 memcpy(tmpstr
, val
, ln_len
);
4313 if (val
[ln_len
- 1] == '\n' || val
[ln_len
- 1] == '\r') {
4314 val
[ln_len
- 1] = '\0';
4317 while (*val
&& isspace(*val
))
4319 if (*val
== '\0' || *val
== '#') {
4320 goto skip_sysctl_tool
;
4322 sysctl_tool
[2] = val
;
4323 (void)posix_assumes_zero(fwexec(sysctl_tool
, NULL
));
4332 copySystemBuildVersion(void)
4334 CFStringRef build
= NULL
;
4335 const char path
[] = "/System/Library/CoreServices/SystemVersion.plist";
4336 CFURLRef plistURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, (const uint8_t *)path
, sizeof(path
) - 1, false);
4338 CFPropertyListRef plist
= NULL
;
4339 if (plistURL
&& (plist
= CFPropertyListCreateFromFile(plistURL
))) {
4340 if (CFTypeCheck(plist
, CFDictionary
)) {
4341 build
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)plist
, _kCFSystemVersionBuildVersionKey
);
4342 if (build
&& CFTypeCheck(build
, CFString
)) {
4345 build
= CFSTR("99Z999");
4351 build
= CFSTR("99Z999");
4355 CFRelease(plistURL
);
4362 do_sysversion_sysctl(void)
4364 int mib
[] = { CTL_KERN
, KERN_OSVERSION
};
4365 CFStringRef buildvers
;
4367 size_t bufsz
= sizeof(buf
);
4369 /* <rdar://problem/4477682> ER: launchd should set kern.osversion very early in boot */
4371 if (sysctl(mib
, 2, buf
, &bufsz
, NULL
, 0) == -1) {
4372 launchctl_log(LOG_ERR
, "sysctl(): %s", strerror(errno
));
4376 if (buf
[0] != '\0') {
4380 buildvers
= copySystemBuildVersion();
4382 CFStringGetCString(buildvers
, buf
, sizeof(buf
), kCFStringEncodingUTF8
);
4383 (void)posix_assumes_zero(sysctl(mib
, 2, NULL
, 0, buf
, strlen(buf
) + 1));
4386 CFRelease(buildvers
);
4390 do_application_firewall_magic(int sfd
, launch_data_t thejob
)
4392 const char *prog
= NULL
, *partialprog
= NULL
;
4393 char *path
, *pathtmp
, **pathstmp
;
4399 * <rdar://problem/4684434> setsockopt() with the executable path as the argument
4402 if ((tmp
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_PROGRAM
))) {
4403 prog
= launch_data_get_string(tmp
);
4407 if ((tmp
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_PROGRAMARGUMENTS
))) {
4408 if ((tmp
= launch_data_array_get_index(tmp
, 0))) {
4409 if ((partialprog
= launch_data_get_string(tmp
))) {
4410 if (partialprog
[0] == '/') {
4419 pathtmp
= path
= strdup(getenv("PATH"));
4423 while ((*pathstmp
= strsep(&pathtmp
, ":"))) {
4424 if (**pathstmp
!= '\0') {
4430 pathtmp
= alloca(MAXPATHLEN
);
4434 for (; *pathstmp
; pathstmp
++) {
4435 snprintf(pathtmp
, MAXPATHLEN
, "%s/%s", *pathstmp
, partialprog
);
4436 if (path_check(pathtmp
)) {
4444 /* The networking team has asked us to ignore the failure of this API if
4445 * errno == ENOPROTOOPT.
4447 if (setsockopt(sfd
, SOL_SOCKET
, SO_EXECPATH
, prog
, (socklen_t
)(strlen(prog
) + 1)) == -1 && errno
!= ENOPROTOOPT
) {
4448 (void)os_assumes_zero(errno
);
4455 preheat_page_cache_hack(void)
4460 /* Disable this hack for now */
4463 if ((thedir
= opendir("/etc/preheat_at_boot")) == NULL
) {
4467 while ((de
= readdir(thedir
))) {
4472 if (de
->d_name
[0] == '.') {
4476 if ((fd
= open(de
->d_name
, O_RDONLY
)) == -1) {
4480 if (fstat(fd
, &sb
) != -1) {
4481 if ((sb
.st_size
< 10*1024*1024) && (junkbuf
= malloc((size_t)sb
.st_size
)) != NULL
) {
4482 ssize_t n
= read(fd
, junkbuf
, (size_t)sb
.st_size
);
4483 if (posix_assumes_zero(n
) != -1 && n
!= (ssize_t
)sb
.st_size
) {
4484 (void)os_assumes_zero(n
);
4497 do_bootroot_magic(void)
4499 const char *kextcache_tool
[] = { "kextcache", "-U", "/", NULL
};
4500 CFTypeRef bootrootProp
;
4501 io_service_t chosen
;
4505 chosen
= IORegistryEntryFromPath(kIOMasterPortDefault
, "IODeviceTree:/chosen");
4507 if (!os_assumes(chosen
)) {
4511 bootrootProp
= IORegistryEntryCreateCFProperty(chosen
, CFSTR(kBootRootActiveKey
), kCFAllocatorDefault
, 0);
4513 IOObjectRelease(chosen
);
4515 if (!bootrootProp
) {
4519 CFRelease(bootrootProp
);
4521 if (posix_assumes_zero(p
= fwexec(kextcache_tool
, &wstatus
)) == -1) {
4525 if (WIFEXITED(wstatus
) && WEXITSTATUS(wstatus
) == EX_OSFILE
) {
4526 (void)reboot(RB_AUTOBOOT
);
4535 if (stat("/AppleInternal", &sb
) == 0 && stat("/var/db/disableAppleInternal", &sb
) == -1) {
4536 _launchctl_apple_internal
= true;
4540 size_t len
= sizeof(bootargs
);
4541 int r
= sysctlbyname("kern.bootargs", bootargs
, &len
, NULL
, 0);
4542 if (r
== 0 && (strnstr(bootargs
, "-v", len
) != NULL
|| strnstr(bootargs
, "-s", len
))) {
4543 _launchctl_verbose_boot
= true;
4546 if (stat("/var/db/.launchd_shutdown_debugging", &sb
) == 0 && _launchctl_verbose_boot
) {
4547 _launchctl_startup_debugging
= true;