this repo has no description
at fixPythonPipStalling 4561 lines 124 kB view raw
1/* 2 * Copyright (c) 2005-2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_APACHE_LICENSE_HEADER_START@ 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * @APPLE_APACHE_LICENSE_HEADER_END@ 19 */ 20 21#include "config.h" 22#include "launch.h" 23#include "launch_priv.h" 24#include "bootstrap.h" 25#include "vproc.h" 26#include "vproc_priv.h" 27#include "vproc_internal.h" 28#include "bootstrap_priv.h" 29#include "launch_internal.h" 30 31#include <CoreFoundation/CoreFoundation.h> 32#include <CoreFoundation/CFPriv.h> 33#include <CoreFoundation/CFLogUtilities.h> 34#include <TargetConditionals.h> 35#ifndef DARLING 36#include <IOKit/IOKitLib.h> 37#endif // DARLING 38#include <NSSystemDirectories.h> 39#include <mach/mach.h> 40#include <mach-o/getsect.h> 41#include <sys/types.h> 42#include <sys/sysctl.h> 43#include <sys/time.h> 44#include <sys/sysctl.h> 45#include <sys/stat.h> 46#include <sys/socket.h> 47#include <sys/un.h> 48#include <sys/fcntl.h> 49#include <sys/event.h> 50#include <sys/resource.h> 51#include <sys/param.h> 52#include <sys/mount.h> 53#include <sys/reboot.h> 54#include <net/if.h> 55#include <netinet/in.h> 56#include <netinet/in_var.h> 57#include <netinet6/nd6.h> 58#include <unistd.h> 59#include <dirent.h> 60#include <libgen.h> 61#include <libinfo.h> 62#include <pwd.h> 63#include <stdio.h> 64#include <stdlib.h> 65#include <pwd.h> 66#include <grp.h> 67#include <netdb.h> 68#include <syslog.h> 69#include <glob.h> 70#include <readline/readline.h> 71#include <readline/history.h> 72#include <dns_sd.h> 73#include <paths.h> 74#include <utmpx.h> 75#include <bootfiles.h> 76#include <sysexits.h> 77#include <util.h> 78#include <spawn.h> 79#include <sys/syslimits.h> 80#include <fnmatch.h> 81#include <os/assumes.h> 82#include <dlfcn.h> 83#if HAVE_SYSTEMSTATS 84#include <systemstats/systemstats.h> 85#endif 86 87#if HAVE_LIBAUDITD 88#include <bsm/auditd_lib.h> 89#ifndef AUDITD_PLIST_FILE 90#define AUDITD_PLIST_FILE "/System/Library/LaunchDaemons/com.apple.auditd.plist" 91#endif 92#endif 93 94extern char **environ; 95 96#define LAUNCH_SECDIR _PATH_TMP "launch-XXXXXX" 97#define LAUNCH_ENV_KEEPCONTEXT "LaunchKeepContext" 98#define LAUNCH_ENV_BOOTSTRAPPINGSYSTEM "LaunchBootstrappingSystem" 99 100#define CFTypeCheck(cf, type) (CFGetTypeID(cf) == type ## GetTypeID()) 101#define CFReleaseIfNotNULL(cf) if (cf) CFRelease(cf); 102 103#if TARGET_OS_EMBEDDED 104#include <sys/kern_memorystatus.h> 105 106#define XPC_PLIST_CACHE "/System/Library/Caches/com.apple.xpcd/xpcd_cache.dylib" 107#define XPC_PLIST_CACHE_KEY "LaunchDaemons" 108 109#if JETSAM_PRIORITY_REVISION 110#define READ_JETSAM_DEFAULTS 1 111#define JETSAM_PROP_DIR "/System/Library/LaunchDaemons" 112#define JETSAM_PROP_DIR_LENGTH (sizeof(JETSAM_PROP_DIR) - 1) 113#define JETSAM_PROP_PREFIX "com.apple.jetsamproperties." 114#define JETSAM_PROP_PREFIX_LENGTH (sizeof(JETSAM_PROP_PREFIX) - 1) 115#define JETSAM_PROP_SUFFIX ".plist" 116#define JETSAM_PROP_SUFFIX_LENGTH (sizeof(JETSAM_PROP_SUFFIX) - 1) 117#endif 118#endif 119 120struct load_unload_state { 121 launch_data_t pass1; 122 char *session_type; 123 bool editondisk:1, load:1, forceload:1; 124}; 125 126static void launchctl_log(int level, const char *fmt, ...); 127static void launchctl_log_CFString(int level, CFStringRef string); 128static void myCFDictionaryApplyFunction(const void *key, const void *value, void *context); 129static CFTypeRef CFTypeCreateFromLaunchData(launch_data_t obj); 130static CFArrayRef CFArrayCreateFromLaunchArray(launch_data_t arr); 131static CFDictionaryRef CFDictionaryCreateFromLaunchDictionary(launch_data_t dict); 132static bool launch_data_array_append(launch_data_t a, launch_data_t o); 133static void insert_event(launch_data_t, const char *, const char *, launch_data_t); 134static void distill_jobs(launch_data_t); 135static void distill_config_file(launch_data_t); 136static void distill_fsevents(launch_data_t); 137static void sock_dict_cb(launch_data_t what, const char *key, void *context); 138static void sock_dict_edit_entry(launch_data_t tmp, const char *key, launch_data_t fdarray, launch_data_t thejob); 139static launch_data_t CF2launch_data(CFTypeRef); 140static launch_data_t read_plist_file(const char *file, bool editondisk, bool load); 141#if TARGET_OS_EMBEDDED 142static CFPropertyListRef GetPropertyListFromCache(void); 143static CFPropertyListRef CreateMyPropertyListFromCachedFile(const char *posixfile); 144static bool require_jobs_from_cache(void); 145#endif 146static CFPropertyListRef CreateMyPropertyListFromFile(const char *); 147static CFPropertyListRef CFPropertyListCreateFromFile(CFURLRef plistURL); 148static void WriteMyPropertyListToFile(CFPropertyListRef, const char *); 149static bool path_goodness_check(const char *path, bool forceload); 150static void readpath(const char *, struct load_unload_state *); 151static void readfile(const char *, struct load_unload_state *); 152static int _fd(int); 153static int demux_cmd(int argc, char *const argv[]); 154static void submit_job_pass(launch_data_t jobs); 155static void do_mgroup_join(int fd, int family, int socktype, int protocol, const char *mgroup); 156static mach_port_t str2bsport(const char *s); 157static void print_jobs(launch_data_t j, const char *key, void *context); 158static void print_obj(launch_data_t obj, const char *key, void *context); 159static bool str2lim(const char *buf, rlim_t *res); 160static const char *lim2str(rlim_t val, char *buf); 161static const char *num2name(int n); 162static ssize_t name2num(const char *n); 163static void unloadjob(launch_data_t job); 164static void print_key_value(launch_data_t obj, const char *key, void *context); 165static void print_launchd_env(launch_data_t obj, const char *key, void *context); 166static void loopback_setup_ipv4(void); 167static void loopback_setup_ipv6(void); 168static pid_t fwexec(const char *const *argv, int *wstatus); 169static void do_potential_fsck(void); 170static bool path_check(const char *path); 171static bool is_safeboot(void); 172static bool is_netboot(void); 173static void apply_sysctls_from_file(const char *thefile); 174static void empty_dir(const char *thedir, struct stat *psb); 175static int touch_file(const char *path, mode_t m); 176static void do_sysversion_sysctl(void); 177static void do_application_firewall_magic(int sfd, launch_data_t thejob); 178static void preheat_page_cache_hack(void); 179static void do_bootroot_magic(void); 180static void do_single_user_mode(bool); 181static bool do_single_user_mode2(void); 182static void do_crash_debug_mode(void); 183static bool do_crash_debug_mode2(void); 184static void read_launchd_conf(void); 185static bool job_disabled_logic(launch_data_t obj); 186static void fix_bogus_file_metadata(void); 187static void do_file_init(void) __attribute__((constructor)); 188static void setup_system_context(void); 189static void handle_system_bootstrapper_crashes_separately(void); 190static void fatal_signal_handler(int sig, siginfo_t *si, void *uap); 191 192typedef enum { 193 BOOTCACHE_START = 1, 194 BOOTCACHE_TAG, 195 BOOTCACHE_STOP, 196} BootCache_action_t; 197 198static void do_BootCache_magic(BootCache_action_t what); 199 200static int bootstrap_cmd(int argc, char *const argv[]); 201static int load_and_unload_cmd(int argc, char *const argv[]); 202//static int reload_cmd(int argc, char *const argv[]); 203static int start_stop_remove_cmd(int argc, char *const argv[]); 204static int submit_cmd(int argc, char *const argv[]); 205static int list_cmd(int argc, char *const argv[]); 206 207static int setenv_cmd(int argc, char *const argv[]); 208static int unsetenv_cmd(int argc, char *const argv[]); 209static int getenv_and_export_cmd(int argc, char *const argv[]); 210static int wait4debugger_cmd(int argc, char *const argv[]); 211 212static int limit_cmd(int argc, char *const argv[]); 213static int stdio_cmd(int argc, char *const argv[]); 214static int fyi_cmd(int argc, char *const argv[]); 215static int logupdate_cmd(int argc, char *const argv[]); 216static int umask_cmd(int argc, char *const argv[]); 217static int getrusage_cmd(int argc, char *const argv[]); 218static int bsexec_cmd(int argc, char *const argv[]); 219static int _bslist_cmd(mach_port_t bport, unsigned int depth, bool show_job, bool local_only); 220static int bslist_cmd(int argc, char *const argv[]); 221static int _bstree_cmd(mach_port_t bsport, unsigned int depth, bool show_jobs); 222static int bstree_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused))); 223static int managerpid_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused))); 224static int manageruid_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused))); 225static int managername_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused))); 226static int asuser_cmd(int argc, char * const argv[]); 227static int exit_cmd(int argc, char *const argv[]) __attribute__((noreturn)); 228static int help_cmd(int argc, char *const argv[]); 229 230static const struct { 231 const char *name; 232 int (*func)(int argc, char *const argv[]); 233 const char *desc; 234} cmds[] = { 235 { "load", load_and_unload_cmd, "Load configuration files and/or directories" }, 236 { "unload", load_and_unload_cmd, "Unload configuration files and/or directories" }, 237// { "reload", reload_cmd, "Reload configuration files and/or directories" }, 238 { "start", start_stop_remove_cmd, "Start specified job" }, 239 { "stop", start_stop_remove_cmd, "Stop specified job" }, 240 { "submit", submit_cmd, "Submit a job from the command line" }, 241 { "remove", start_stop_remove_cmd, "Remove specified job" }, 242 { "bootstrap", bootstrap_cmd, "Bootstrap launchd" }, 243 { "list", list_cmd, "List jobs and information about jobs" }, 244 { "setenv", setenv_cmd, "Set an environmental variable in launchd" }, 245 { "unsetenv", unsetenv_cmd, "Unset an environmental variable in launchd" }, 246 { "getenv", getenv_and_export_cmd, "Get an environmental variable from launchd" }, 247 { "export", getenv_and_export_cmd, "Export shell settings from launchd" }, 248 { "debug", wait4debugger_cmd, "Set the WaitForDebugger flag for the target job to true." }, 249 { "limit", limit_cmd, "View and adjust launchd resource limits" }, 250 { "stdout", stdio_cmd, "Redirect launchd's standard out to the given path" }, 251 { "stderr", stdio_cmd, "Redirect launchd's standard error to the given path" }, 252 { "shutdown", fyi_cmd, "Prepare for system shutdown" }, 253 { "singleuser", fyi_cmd, "Switch to single-user mode" }, 254 { "getrusage", getrusage_cmd, "Get resource usage statistics from launchd" }, 255 { "log", logupdate_cmd, "Adjust the logging level or mask of launchd" }, 256 { "umask", umask_cmd, "Change launchd's umask" }, 257 { "bsexec", bsexec_cmd, "Execute a process within a different Mach bootstrap subset" }, 258 { "bslist", bslist_cmd, "List Mach bootstrap services and optional servers" }, 259 { "bstree", bstree_cmd, "Show the entire Mach bootstrap tree. Requires root privileges." }, 260 { "managerpid", managerpid_cmd, "Print the PID of the launchd managing this Mach bootstrap." }, 261 { "manageruid", manageruid_cmd, "Print the UID of the launchd managing this Mach bootstrap." }, 262 { "managername", managername_cmd, "Print the name of this Mach bootstrap." }, 263 { "asuser", asuser_cmd, "Execute a subcommand in the given user's context." }, 264 { "exit", exit_cmd, "Exit the interactive invocation of launchctl" }, 265 { "quit", exit_cmd, "Quit the interactive invocation of launchctl" }, 266 { "help", help_cmd, "This help output" }, 267}; 268 269static bool _launchctl_istty; 270static bool _launchctl_verbose; 271static bool _launchctl_is_managed; 272static bool _launchctl_apple_internal; 273static bool _launchctl_system_context; 274static bool _launchctl_uid0_context; 275static bool _launchctl_system_bootstrap; 276static bool _launchctl_peruser_bootstrap; 277static bool _launchctl_verbose_boot = false; 278static bool _launchctl_startup_debugging = false; 279 280static bool _launchctl_overrides_db_changed = false; 281static CFMutableDictionaryRef _launchctl_overrides_db = NULL; 282 283static char *_launchctl_job_overrides_db_path; 284static char *_launchctl_managername = NULL; 285 286#if READ_JETSAM_DEFAULTS 287static CFDictionaryRef _launchctl_jetsam_defaults = NULL; 288static CFDictionaryRef _launchctl_jetsam_defaults_cached = NULL; 289#endif 290 291int 292main(int argc, char *const argv[]) 293{ 294 char *l; 295 296 if (getenv(LAUNCH_ENV_BOOTSTRAPPINGSYSTEM)) { 297 /* We're bootstrapping the install environment, so we can't talk to 298 * mDNSResponder or opendirectoryd. 299 * 300 * See <rdar://problem/9877230>. 301 */ 302 si_search_module_set_flags("mdns", 1); 303 si_search_module_set_flags("ds", 1); 304 } 305 306 int64_t is_managed = 0; 307 (void)vproc_swap_integer(NULL, VPROC_GSK_IS_MANAGED, NULL, &is_managed); 308 _launchctl_is_managed = is_managed; 309 310 _launchctl_istty = isatty(STDIN_FILENO); 311 argc--, argv++; 312 313 if (argc > 0 && argv[0][0] == '-') { 314 char *flago; 315 316 for (flago = argv[0] + 1; *flago; flago++) { 317 switch (*flago) { 318 case 'v': 319 _launchctl_verbose = true; 320 break; 321 case 'u': 322 if (argc > 1) { 323 if (strncmp(argv[1], "root", sizeof("root")) == 0) { 324 _launchctl_uid0_context = true; 325 } else { 326 launchctl_log(LOG_ERR, "Unknown user: %s", argv[1]); 327 exit(EXIT_FAILURE); 328 } 329 argc--, argv++; 330 } else { 331 launchctl_log(LOG_ERR, "-u option requires an argument."); 332 } 333 break; 334 case '1': 335 _launchctl_system_context = true; 336 break; 337 default: 338 launchctl_log(LOG_ERR, "Unknown argument: '-%c'", *flago); 339 break; 340 } 341 } 342 argc--, argv++; 343 } 344 345 /* Running in the context of the root user's per-user launchd is only from 346 * within that session. 347 */ 348 if (_launchctl_uid0_context) { 349 int64_t manager_uid = -1, manager_pid = -1; 350 (void)vproc_swap_integer(NULL, VPROC_GSK_MGR_UID, NULL, &manager_uid); 351 (void)vproc_swap_integer(NULL, VPROC_GSK_MGR_PID, NULL, &manager_pid); 352 if (manager_uid || manager_pid == 1) { 353 launchctl_log(LOG_ERR, "Running in the root user's per-user context is not supported outside of the root user's bootstrap."); 354 exit(EXIT_FAILURE); 355 } 356 } else if (!(_launchctl_system_context || _launchctl_uid0_context)) { 357 /* Running in the system context is implied when we're running as root 358 * and not running as a bootstrapper. 359 */ 360 _launchctl_system_context = (!_launchctl_is_managed && getuid() == 0); 361 } 362 363 if (_launchctl_system_context) { 364 if (getuid() == 0) { 365 setup_system_context(); 366 } else { 367 launchctl_log(LOG_ERR, "You must be root to run in the system context."); 368 exit(EXIT_FAILURE); 369 } 370 } else if (_launchctl_uid0_context) { 371 if (getuid() != 0) { 372 launchctl_log(LOG_ERR, "You must be root to run in the root user context."); 373 exit(EXIT_FAILURE); 374 } 375 } 376 377 if (!readline) { 378 launchctl_log(LOG_ERR, "missing library: readline"); 379 exit(EXIT_FAILURE); 380 } 381 382 if (argc == 0) { 383 while ((l = readline(_launchctl_istty ? "launchd% " : NULL))) { 384 char *inputstring = l, *argv2[100], **ap = argv2; 385 int i = 0; 386 387 while ((*ap = strsep(&inputstring, " \t"))) { 388 if (**ap != '\0') { 389 ap++; 390 i++; 391 } 392 } 393 394 if (i > 0) { 395 demux_cmd(i, argv2); 396 } 397 398 free(l); 399 } 400 401 if (_launchctl_istty) { 402 fputc('\n', stdout); 403 } 404 } 405 406 if (argc > 0) { 407 exit(demux_cmd(argc, argv)); 408 } 409 410 exit(EXIT_SUCCESS); 411} 412 413int 414demux_cmd(int argc, char *const argv[]) 415{ 416 size_t i; 417 418 optind = 1; 419 optreset = 1; 420 421 for (i = 0; i < (sizeof cmds / sizeof cmds[0]); i++) { 422 if (!strcmp(cmds[i].name, argv[0])) { 423 return cmds[i].func(argc, argv); 424 } 425 } 426 427 launchctl_log(LOG_ERR, "%s: unknown subcommand \"%s\"", getprogname(), argv[0]); 428 return 1; 429} 430 431void 432launchctl_log(int level, const char *fmt, ...) 433{ 434 va_list ap; 435 va_start(ap, fmt); 436 437 if (_launchctl_is_managed) { 438 vsyslog(level, fmt, ap); 439 } else { 440 char *buff = NULL; 441 (void)vasprintf(&buff, fmt, ap); 442 443 FILE *where = stdout; 444 if (level < LOG_NOTICE) { 445 where = stderr; 446 } 447 448 fprintf(where, "%s\n", buff); 449 free(buff); 450 } 451 452 va_end(ap); 453} 454 455void 456launchctl_log_CFString(int level, CFStringRef string) 457{ 458 // Big enough. Don't feel like jumping through CF's hoops. 459 char *buff = malloc(4096); 460 (void)CFStringGetCString(string, buff, 4096, kCFStringEncodingUTF8); 461 launchctl_log(level, "%s", buff); 462 free(buff); 463} 464 465void 466read_launchd_conf(void) 467{ 468#if !TARGET_OS_EMBEDDED 469 char s[1000], *c, *av[100]; 470 const char *file; 471 size_t len; 472 int i; 473 FILE *f; 474 475 if (getppid() == 1) { 476 file = "/etc/launchd.conf"; 477 } else { 478 file = "/etc/launchd-user.conf"; 479 } 480 481 if (!(f = fopen(file, "r"))) { 482 return; 483 } 484 485 while ((c = fgets(s, (int) sizeof s, f))) { 486 len = strlen(c); 487 if (len && c[len - 1] == '\n') { 488 c[len - 1] = '\0'; 489 } 490 491 i = 0; 492 493 while ((av[i] = strsep(&c, " \t"))) { 494 if (*(av[i]) != '\0') { 495 i++; 496 } 497 } 498 499 if (i > 0) { 500 demux_cmd(i, av); 501 } 502 } 503 504 fclose(f); 505#endif // !TARGET_OS_EMBEDDED 506} 507 508static CFPropertyListRef 509CFPropertyListCreateFromFile(CFURLRef plistURL) 510{ 511 CFReadStreamRef plistReadStream = CFReadStreamCreateWithFile(NULL, plistURL); 512 513 CFErrorRef streamErr = NULL; 514 if (!CFReadStreamOpen(plistReadStream)) { 515 streamErr = CFReadStreamCopyError(plistReadStream); 516 CFStringRef errString = CFErrorCopyDescription(streamErr); 517 518 launchctl_log_CFString(LOG_ERR, errString); 519 520 CFRelease(errString); 521 CFRelease(streamErr); 522 } 523 524 CFPropertyListRef plist = NULL; 525 if (plistReadStream) { 526 CFStringRef errString = NULL; 527 CFPropertyListFormat plistFormat = 0; 528 plist = CFPropertyListCreateFromStream(NULL, plistReadStream, 0, kCFPropertyListImmutable, &plistFormat, &errString); 529 if (!plist) { 530 launchctl_log_CFString(LOG_ERR, errString); 531 CFRelease(errString); 532 } 533 } 534 535 CFReadStreamClose(plistReadStream); 536 CFRelease(plistReadStream); 537 538 return plist; 539} 540 541int 542unsetenv_cmd(int argc, char *const argv[]) 543{ 544 launch_data_t resp, tmp, msg; 545 546 if (argc != 2) { 547 launchctl_log(LOG_ERR, "%s usage: unsetenv <key>", getprogname()); 548 return 1; 549 } 550 551 msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 552 553 tmp = launch_data_new_string(argv[1]); 554 launch_data_dict_insert(msg, tmp, LAUNCH_KEY_UNSETUSERENVIRONMENT); 555 556 resp = launch_msg(msg); 557 558 launch_data_free(msg); 559 560 if (resp) { 561 launch_data_free(resp); 562 } else { 563 launchctl_log(LOG_ERR, "launch_msg(\"%s\"): %s", LAUNCH_KEY_UNSETUSERENVIRONMENT, strerror(errno)); 564 } 565 566 return 0; 567} 568 569int 570setenv_cmd(int argc, char *const argv[]) 571{ 572 launch_data_t resp, tmp, tmpv, msg; 573 574 if (argc != 3) { 575 launchctl_log(LOG_ERR, "%s usage: setenv <key> <value>", getprogname()); 576 return 1; 577 } 578 579 msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 580 tmp = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 581 582 tmpv = launch_data_new_string(argv[2]); 583 launch_data_dict_insert(tmp, tmpv, argv[1]); 584 launch_data_dict_insert(msg, tmp, LAUNCH_KEY_SETUSERENVIRONMENT); 585 586 resp = launch_msg(msg); 587 launch_data_free(msg); 588 589 if (resp) { 590 launch_data_free(resp); 591 } else { 592 launchctl_log(LOG_ERR, "launch_msg(\"%s\"): %s", LAUNCH_KEY_SETUSERENVIRONMENT, strerror(errno)); 593 } 594 595 return 0; 596} 597 598void 599print_launchd_env(launch_data_t obj, const char *key, void *context) 600{ 601 bool *is_csh = context; 602 603 /* XXX escape the double quotes */ 604 if (*is_csh) { 605 launchctl_log(LOG_NOTICE, "setenv %s \"%s\";", key, launch_data_get_string(obj)); 606 } else { 607 launchctl_log(LOG_NOTICE, "%s=\"%s\"; export %s;", key, launch_data_get_string(obj), key); 608 } 609} 610 611void 612print_key_value(launch_data_t obj, const char *key, void *context) 613{ 614 const char *k = context; 615 616 if (!strcmp(key, k)) { 617 launchctl_log(LOG_NOTICE, "%s", launch_data_get_string(obj)); 618 } 619} 620 621int 622getenv_and_export_cmd(int argc, char *const argv[]) 623{ 624 launch_data_t resp; 625 bool is_csh = false; 626 char *k; 627 628 if (!strcmp(argv[0], "export")) { 629 char *s = getenv("SHELL"); 630 if (s) { 631 is_csh = strstr(s, "csh") ? true : false; 632 } 633 } else if (argc != 2) { 634 launchctl_log(LOG_ERR, "%s usage: getenv <key>", getprogname()); 635 return 1; 636 } 637 638 k = argv[1]; 639 640 if (vproc_swap_complex(NULL, VPROC_GSK_ENVIRONMENT, NULL, &resp) == NULL) { 641 if (!strcmp(argv[0], "export")) { 642 launch_data_dict_iterate(resp, print_launchd_env, &is_csh); 643 } else { 644 launch_data_dict_iterate(resp, print_key_value, k); 645 } 646 launch_data_free(resp); 647 return 0; 648 } else { 649 return 1; 650 } 651 652 return 0; 653} 654 655int 656wait4debugger_cmd(int argc, char * const argv[]) 657{ 658 if (argc != 3) { 659 launchctl_log(LOG_ERR, "%s usage: debug <label> <value>", argv[0]); 660 return 1; 661 } 662 663 int result = 1; 664 int64_t inval = 0; 665 if (strncmp(argv[2], "true", sizeof("true")) == 0) { 666 inval = 1; 667 } else if (strncmp(argv[2], "false", sizeof("false")) != 0) { 668 inval = atoi(argv[2]); 669 inval &= 1; 670 } 671 672 vproc_t vp = vprocmgr_lookup_vproc(argv[1]); 673 if (vp) { 674 vproc_err_t verr = vproc_swap_integer(vp, VPROC_GSK_WAITFORDEBUGGER, &inval, NULL); 675 if (verr) { 676 launchctl_log(LOG_ERR, "Failed to set WaitForDebugger flag on %s.", argv[1]); 677 } else { 678 result = 0; 679 } 680 vproc_release(vp); 681 } 682 683 return result; 684} 685 686void 687unloadjob(launch_data_t job) 688{ 689 launch_data_t tmps; 690 691 tmps = launch_data_dict_lookup(job, LAUNCH_JOBKEY_LABEL); 692 693 if (!tmps) { 694 launchctl_log(LOG_ERR, "%s: Error: Missing Key: %s", getprogname(), LAUNCH_JOBKEY_LABEL); 695 return; 696 } 697 698 if (_vproc_send_signal_by_label(launch_data_get_string(tmps), VPROC_MAGIC_UNLOAD_SIGNAL) != NULL) { 699 launchctl_log(LOG_ERR, "%s: Error unloading: %s", getprogname(), launch_data_get_string(tmps)); 700 } 701} 702 703#if READ_JETSAM_DEFAULTS 704 705static CFDictionaryRef 706read_jetsam_defaults_from_cache(void) { 707 CFPropertyListRef cache = GetPropertyListFromCache(); 708 CFPropertyListRef defaults = NULL; 709 const void **keys = 0; 710 CFIndex count, i; 711 712 if (!cache) { 713 return NULL; 714 } 715 716 CFPropertyListRef cachefiles = CFDictionaryGetValue(cache, CFSTR(XPC_PLIST_CACHE_KEY)); 717 if (!cachefiles) { 718 return NULL; 719 } 720 721 count = CFDictionaryGetCount(cachefiles); 722 keys = (const void **)malloc(sizeof(void *) * count); 723 if (!keys) { 724 return NULL; 725 } 726 727 CFDictionaryGetKeysAndValues(cachefiles, keys, NULL); 728 for (i = 0; i < count; i++) { 729 CFStringRef key = (CFStringRef)keys[i]; 730 CFIndex key_length = CFStringGetLength(key); 731 732 if (key_length <= (CFIndex)(JETSAM_PROP_DIR_LENGTH + JETSAM_PROP_PREFIX_LENGTH + JETSAM_PROP_SUFFIX_LENGTH + 1)) { 733 continue; 734 } 735 736 if (CFStringCompareWithOptions(key, CFSTR(JETSAM_PROP_DIR "/" JETSAM_PROP_PREFIX), 737 CFRangeMake(0, JETSAM_PROP_DIR_LENGTH + JETSAM_PROP_PREFIX_LENGTH + 1), 0)) { 738 continue; 739 } 740 741 if (CFStringCompareWithOptions(key, CFSTR(JETSAM_PROP_SUFFIX), 742 CFRangeMake(key_length - JETSAM_PROP_SUFFIX_LENGTH, JETSAM_PROP_SUFFIX_LENGTH), 0)) { 743 continue; 744 } 745 746 defaults = CFDictionaryGetValue(cachefiles, key); 747 break; 748 } 749 750 free(keys); 751 752 return defaults; 753} 754 755static CFDictionaryRef 756read_jetsam_defaults_from_file(void) { 757 DIR *dirp; 758 struct dirent *dp; 759 CFDictionaryRef defaults = NULL; 760 761 dirp = opendir(JETSAM_PROP_DIR); 762 while ((dp = readdir(dirp)) != NULL) { 763 char *fullpath; 764 765 if (dp->d_namlen <= (JETSAM_PROP_PREFIX_LENGTH + JETSAM_PROP_SUFFIX_LENGTH)) { 766 continue; 767 } 768 769 if (strncmp(dp->d_name, JETSAM_PROP_PREFIX, JETSAM_PROP_PREFIX_LENGTH)) { 770 continue; 771 } 772 773 if (strncmp(dp->d_name + dp->d_namlen - JETSAM_PROP_SUFFIX_LENGTH, JETSAM_PROP_SUFFIX, JETSAM_PROP_SUFFIX_LENGTH)) { 774 continue; 775 } 776 777 if (-1 != asprintf(&fullpath, "%s/%s", JETSAM_PROP_DIR, dp->d_name)) { 778 defaults = (CFDictionaryRef)CreateMyPropertyListFromFile(fullpath); 779 free(fullpath); 780 } 781 782 break; 783 } 784 785 if (dirp) { 786 closedir(dirp); 787 } 788 789 return defaults; 790} 791 792static bool 793submit_cached_defaults(void) { 794 launch_data_t msg, resp; 795 const void **keys = NULL; 796 int i; 797 798 if (_launchctl_jetsam_defaults_cached == NULL) { 799 return false; 800 } 801 802 /* The dictionary to transmit */ 803 CFMutableDictionaryRef payload_dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 804 805 /* Add a key to indicate that this is a special job */ 806 CFBooleanRef ID = kCFBooleanTrue; 807 CFDictionaryAddValue(payload_dict, CFSTR(LAUNCH_JOBKEY_DEFAULTS), ID); 808 809 CFMutableDictionaryRef defaults_dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 810 811 CFDictionaryAddValue(payload_dict, CFSTR(LAUNCHD_JOB_DEFAULTS), defaults_dict); 812 813 /* Compile appropriate launchd dictionary... */ 814 CFIndex count = CFDictionaryGetCount(_launchctl_jetsam_defaults_cached); 815 keys = (const void **)malloc(sizeof(void *) * count); 816 if (!keys) { 817 goto exit; 818 } 819 820 CFDictionaryGetKeysAndValues(_launchctl_jetsam_defaults_cached, keys, NULL); 821 822 for (i = 0; i < count; i++) { 823 CFStringRef label = (CFStringRef)keys[i]; 824 825 /* Get the defaults for the job */ 826 CFDictionaryRef job_defaults_dict = CFDictionaryGetValue(_launchctl_jetsam_defaults_cached, label); 827 if (!(job_defaults_dict && CFTypeCheck(job_defaults_dict, CFDictionary))) { 828 continue; 829 } 830 831 /* Create a new dictionary to represent the job */ 832 CFMutableDictionaryRef job_dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 833 834 /* Add the defaults */ 835 CFDictionaryAddValue(job_dict, CFSTR(LAUNCH_JOBKEY_JETSAMPROPERTIES), job_defaults_dict); 836 837 /* Finally, add the result to the main dictionary */ 838 CFDictionaryAddValue(defaults_dict, label, job_dict); 839 840 /* Cleanup */ 841 CFRelease(job_dict); 842 } 843 844 /* Send the payload */ 845 launch_data_t ldp = CF2launch_data(payload_dict); 846 847 msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 848 launch_data_dict_insert(msg, ldp, LAUNCH_KEY_SUBMITJOB); 849 850 resp = launch_msg(msg); 851 launch_data_free(msg); 852 853 launch_data_free(resp); 854 855exit: 856 CFRelease(defaults_dict); 857 CFRelease(payload_dict); 858 859 free(keys); 860 861 return true; 862} 863 864static boolean_t 865read_jetsam_defaults(void) 866{ 867 /* Current supported version */ 868 const int v = 3; 869 870 CFDictionaryRef jetsam_defaults = NULL; 871 872 if (require_jobs_from_cache()) { 873 jetsam_defaults = read_jetsam_defaults_from_cache(); 874 } else { 875 jetsam_defaults = read_jetsam_defaults_from_file(); 876 } 877 878 if (NULL == jetsam_defaults) { 879 launchctl_log(LOG_NOTICE, "%s: no jetsam property file found", getprogname()); 880 return false; 881 } 882 883 /* Validate the version */ 884 CFNumberRef defaults_vers = CFDictionaryGetValue(jetsam_defaults, CFSTR("Version")); 885 if (!(defaults_vers && CFTypeCheck(defaults_vers, CFNumber))) { 886 return false; 887 } 888 889 CFNumberRef supported_vers = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &v); 890 if (!(kCFCompareEqualTo == CFNumberCompare(defaults_vers, supported_vers, NULL ))) { 891 return false; 892 } 893 894 /* These defaults are merged within launchctl prior to submitting the job */ 895 _launchctl_jetsam_defaults = CFDictionaryGetValue(jetsam_defaults, CFSTR(LAUNCHD_JOB_DEFAULTS)); 896 if (!(_launchctl_jetsam_defaults && CFTypeCheck(_launchctl_jetsam_defaults, CFDictionary))) { 897 _launchctl_jetsam_defaults = NULL; 898 return false; 899 } 900 901 /* Cached defaults (applied by launchd) - parse and submit immediately as a fake job */ 902 _launchctl_jetsam_defaults_cached = CFDictionaryGetValue(jetsam_defaults, CFSTR(LAUNCHD_JOB_DEFAULTS_CACHED)); 903 if (!(_launchctl_jetsam_defaults_cached && CFTypeCheck(_launchctl_jetsam_defaults_cached, CFDictionary))) { 904 _launchctl_jetsam_defaults_cached = NULL; 905 return false; 906 } 907 908 submit_cached_defaults(); 909 910 return true; 911} 912 913#endif /* READ_JETSAM_DEFAULTS */ 914 915launch_data_t 916read_plist_file(const char *file, bool editondisk, bool load) 917{ 918 CFPropertyListRef plist; 919 launch_data_t r = NULL; 920#if TARGET_OS_EMBEDDED 921 if (require_jobs_from_cache()) { 922 plist = CreateMyPropertyListFromCachedFile(file); 923 } else { 924 plist = CreateMyPropertyListFromFile(file); 925 } 926#else 927 plist = CreateMyPropertyListFromFile(file); 928#endif 929 930 if (NULL == plist) { 931 launchctl_log(LOG_ERR, "%s: no plist was returned for: %s", getprogname(), file); 932 return NULL; 933 } 934 935 CFStringRef label = CFDictionaryGetValue(plist, CFSTR(LAUNCH_JOBKEY_LABEL)); 936 if (!(label && CFTypeCheck(label, CFString))) { 937 return NULL; 938 } 939 940 if (_launchctl_overrides_db) { 941 CFDictionaryRef overrides = CFDictionaryGetValue(_launchctl_overrides_db, label); 942 if (overrides && CFTypeCheck(overrides, CFDictionary)) { 943 CFBooleanRef disabled = CFDictionaryGetValue(overrides, CFSTR(LAUNCH_JOBKEY_DISABLED)); 944 if (disabled && CFTypeCheck(disabled, CFBoolean)) { 945 CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR(LAUNCH_JOBKEY_DISABLED), disabled); 946 } 947 } 948 } 949 950 if (editondisk) { 951 if (_launchctl_overrides_db) { 952 CFMutableDictionaryRef job = (CFMutableDictionaryRef)CFDictionaryGetValue(_launchctl_overrides_db, label); 953 if (!job || !CFTypeCheck(job, CFDictionary)) { 954 job = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 955 CFDictionarySetValue(_launchctl_overrides_db, label, job); 956 CFRelease(job); 957 } 958 959 CFDictionarySetValue(job, CFSTR(LAUNCH_JOBKEY_DISABLED), load ? kCFBooleanFalse : kCFBooleanTrue); 960 CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR(LAUNCH_JOBKEY_DISABLED), load ? kCFBooleanFalse : kCFBooleanTrue); 961 _launchctl_overrides_db_changed = true; 962 } else { 963 if (load) { 964 CFDictionaryRemoveValue((CFMutableDictionaryRef)plist, CFSTR(LAUNCH_JOBKEY_DISABLED)); 965 } else { 966 CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR(LAUNCH_JOBKEY_DISABLED), kCFBooleanTrue); 967 } 968 WriteMyPropertyListToFile(plist, file); 969 } 970 } 971 972#if READ_JETSAM_DEFAULTS 973 if (_launchctl_jetsam_defaults) { 974 CFDictionaryRef job_defaults_dict = CFDictionaryGetValue(_launchctl_jetsam_defaults, label); 975 if (job_defaults_dict) { 976 CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR(LAUNCH_JOBKEY_JETSAMPROPERTIES), job_defaults_dict); 977 } 978 } else { 979 /* The plist is missing. Set a default memory limit, since the device will be otherwise unusable */ 980 long default_limit = 0; 981 CFMutableDictionaryRef job_defaults_dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 982 CFNumberRef memory_limit = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongType, &default_limit); 983 if (memory_limit) { 984 CFDictionaryAddValue(job_defaults_dict, CFSTR(LAUNCH_JOBKEY_JETSAMMEMORYLIMIT), memory_limit); 985 CFRelease(memory_limit); 986 } 987 CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR(LAUNCH_JOBKEY_JETSAMPROPERTIES), job_defaults_dict); 988 CFRelease(job_defaults_dict); 989 } 990#endif /* READ_JETSAM_DEFAULTS */ 991 992 r = CF2launch_data(plist); 993 994 CFRelease(plist); 995 996 return r; 997} 998 999static bool 1000sysctl_hw_streq(int mib_slot, const char *str) 1001{ 1002 char buf[1000]; 1003 size_t bufsz = sizeof(buf); 1004 int mib[] = { CTL_HW, mib_slot }; 1005 1006 if (sysctl(mib, 2, buf, &bufsz, NULL, 0) != -1) { 1007 if (strcmp(buf, str) == 0) { 1008 return true; 1009 } 1010 } 1011 1012 return false; 1013} 1014 1015static void 1016limitloadtohardware_iterator(launch_data_t val, const char *key, void *ctx) 1017{ 1018 bool *result = ctx; 1019 1020 char name[128]; 1021 (void)snprintf(name, sizeof(name), "hw.%s", key); 1022 1023 int mib[2]; 1024 size_t sz = 2; 1025 if (*result != true && os_assumes_zero(sysctlnametomib(name, mib, &sz)) == 0) { 1026 if (launch_data_get_type(val) == LAUNCH_DATA_ARRAY) { 1027 size_t c = launch_data_array_get_count(val); 1028 1029 size_t i = 0; 1030 for (i = 0; i < c; i++) { 1031 launch_data_t oai = launch_data_array_get_index(val, i); 1032 if (sysctl_hw_streq(mib[1], launch_data_get_string(oai))) { 1033 *result = true; 1034 i = c; 1035 } 1036 } 1037 } 1038 } 1039} 1040 1041void 1042readfile(const char *what, struct load_unload_state *lus) 1043{ 1044 char ourhostname[1024]; 1045 launch_data_t tmpd, tmps, thejob, tmpa; 1046 bool job_disabled = false; 1047 size_t i, c; 1048 1049 gethostname(ourhostname, sizeof(ourhostname)); 1050 1051 if (NULL == (thejob = read_plist_file(what, lus->editondisk, lus->load))) { 1052 launchctl_log(LOG_ERR, "%s: no plist was returned for: %s", getprogname(), what); 1053 return; 1054 } 1055 1056 1057 if (NULL == launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LABEL)) { 1058 launchctl_log(LOG_ERR, "%s: missing the Label key: %s", getprogname(), what); 1059 goto out_bad; 1060 } 1061 1062 if ((launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_PROGRAM) == NULL) && 1063 (launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_PROGRAMARGUMENTS) == NULL)) { 1064 launchctl_log(LOG_ERR, "%s: neither a Program nor a ProgramArguments key was specified: %s", getprogname(), what); 1065 goto out_bad; 1066 } 1067 1068 if (NULL != (tmpa = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LIMITLOADFROMHOSTS))) { 1069 c = launch_data_array_get_count(tmpa); 1070 1071 for (i = 0; i < c; i++) { 1072 launch_data_t oai = launch_data_array_get_index(tmpa, i); 1073 if (!strcasecmp(ourhostname, launch_data_get_string(oai))) { 1074 goto out_bad; 1075 } 1076 } 1077 } 1078 1079 if (NULL != (tmpa = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LIMITLOADTOHOSTS))) { 1080 c = launch_data_array_get_count(tmpa); 1081 1082 for (i = 0; i < c; i++) { 1083 launch_data_t oai = launch_data_array_get_index(tmpa, i); 1084 if (!strcasecmp(ourhostname, launch_data_get_string(oai))) { 1085 break; 1086 } 1087 } 1088 1089 if (i == c) { 1090 goto out_bad; 1091 } 1092 } 1093 1094 if (NULL != (tmpd = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LIMITLOADTOHARDWARE))) { 1095 bool result = false; 1096 launch_data_dict_iterate(tmpd, limitloadtohardware_iterator, &result); 1097 if (!result) { 1098 goto out_bad; 1099 } 1100 } 1101 1102 if (NULL != (tmpd = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LIMITLOADFROMHARDWARE))) { 1103 bool result = false; 1104 launch_data_dict_iterate(tmpd, limitloadtohardware_iterator, &result); 1105 if (result) { 1106 goto out_bad; 1107 } 1108 } 1109 1110 /* If the manager is Aqua, the LimitLoadToSessionType should default to 1111 * "Aqua". 1112 * 1113 * <rdar://problem/8297909> 1114 */ 1115 if (!_launchctl_managername) { 1116 if (vproc_swap_string(NULL, VPROC_GSK_MGR_NAME, NULL, &_launchctl_managername)) { 1117 if (bootstrap_port) { 1118 /* This is only an error if we are running with a neutered 1119 * bootstrap port, otherwise we wouldn't expect this operating to 1120 * succeed. 1121 * 1122 * <rdar://problem/10514286> 1123 */ 1124 launchctl_log(LOG_ERR, "Could not obtain manager name: ppid/bootstrap: %d/0x%x", getppid(), bootstrap_port); 1125 } 1126 1127 _launchctl_managername = ""; 1128 } 1129 } 1130 1131 if (!lus->session_type) { 1132 if (strcmp(_launchctl_managername, "Aqua") == 0) { 1133 lus->session_type = "Aqua"; 1134 } 1135 } 1136 1137 if (lus->session_type && !(tmpa = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE))) { 1138 tmpa = launch_data_new_string("Aqua"); 1139 launch_data_dict_insert(thejob, tmpa, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE); 1140 } 1141 1142 if ((tmpa = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE))) { 1143 const char *allowed_session; 1144 bool skipjob = true; 1145 1146 /* My sincere apologies to anyone who has to deal with this 1147 * LimitLoadToSessionType madness. It was like this when I got here, but 1148 * I've knowingly made it worse, hopefully to the benefit of the end 1149 * user. 1150 * 1151 * See <rdar://problem/8769211> and <rdar://problem/7114980>. 1152 */ 1153 if (!lus->session_type && launch_data_get_type(tmpa) == LAUNCH_DATA_STRING) { 1154 if (strcasecmp("System", _launchctl_managername) == 0 && strcasecmp("System", launch_data_get_string(tmpa)) == 0) { 1155 skipjob = false; 1156 } 1157 } 1158 1159 if (lus->session_type) switch (launch_data_get_type(tmpa)) { 1160 case LAUNCH_DATA_ARRAY: 1161 c = launch_data_array_get_count(tmpa); 1162 for (i = 0; i < c; i++) { 1163 tmps = launch_data_array_get_index(tmpa, i); 1164 allowed_session = launch_data_get_string(tmps); 1165 if (strcasecmp(lus->session_type, allowed_session) == 0) { 1166 skipjob = false; 1167 /* we have to do the following so job_reparent_hack() works within launchd */ 1168 tmpa = launch_data_new_string(lus->session_type); 1169 launch_data_dict_insert(thejob, tmpa, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE); 1170 break; 1171 } 1172 } 1173 break; 1174 case LAUNCH_DATA_STRING: 1175 allowed_session = launch_data_get_string(tmpa); 1176 if (strcasecmp(lus->session_type, allowed_session) == 0) { 1177 skipjob = false; 1178 } 1179 break; 1180 default: 1181 break; 1182 } 1183 1184 if (skipjob) { 1185 goto out_bad; 1186 } 1187 } 1188 1189 if ((tmpd = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_DISABLED))) { 1190 job_disabled = job_disabled_logic(tmpd); 1191 } 1192 1193 if (lus->forceload) { 1194 job_disabled = false; 1195 } 1196 1197 if (job_disabled && lus->load) { 1198 goto out_bad; 1199 } 1200 1201 if (_launchctl_system_bootstrap || _launchctl_peruser_bootstrap) { 1202 uuid_t uuid; 1203 uuid_clear(uuid); 1204 1205 launch_data_t lduuid = launch_data_new_opaque(uuid, sizeof(uuid_t)); 1206 launch_data_dict_insert(thejob, lduuid, LAUNCH_JOBKEY_SECURITYSESSIONUUID); 1207 } 1208 1209 launch_data_array_append(lus->pass1, thejob); 1210 1211 if (_launchctl_verbose) { 1212 launchctl_log(LOG_NOTICE, "Will load: %s", what); 1213 } 1214 1215 return; 1216out_bad: 1217 if (_launchctl_verbose) { 1218 launchctl_log(LOG_NOTICE, "Ignored: %s", what); 1219 } 1220 launch_data_free(thejob); 1221} 1222 1223static void 1224job_disabled_dict_logic(launch_data_t obj, const char *key, void *context) 1225{ 1226 bool *r = context; 1227 1228 if (launch_data_get_type(obj) != LAUNCH_DATA_STRING) { 1229 return; 1230 } 1231 1232 if (strcasecmp(key, LAUNCH_JOBKEY_DISABLED_MACHINETYPE) == 0) { 1233 if (sysctl_hw_streq(HW_MACHINE, launch_data_get_string(obj))) { 1234 *r = true; 1235 } 1236 } else if (strcasecmp(key, LAUNCH_JOBKEY_DISABLED_MODELNAME) == 0) { 1237 if (sysctl_hw_streq(HW_MODEL, launch_data_get_string(obj))) { 1238 *r = true; 1239 } 1240 } 1241} 1242 1243bool 1244job_disabled_logic(launch_data_t obj) 1245{ 1246 bool r = false; 1247 1248 switch (launch_data_get_type(obj)) { 1249 case LAUNCH_DATA_DICTIONARY: 1250 launch_data_dict_iterate(obj, job_disabled_dict_logic, &r); 1251 break; 1252 case LAUNCH_DATA_BOOL: 1253 r = launch_data_get_bool(obj); 1254 break; 1255 default: 1256 break; 1257 } 1258 1259 return r; 1260} 1261 1262bool 1263path_goodness_check(const char *path, bool forceload) 1264{ 1265 struct stat sb; 1266 1267 if (stat(path, &sb) == -1) { 1268 launchctl_log(LOG_ERR, "%s: Couldn't stat(\"%s\"): %s", getprogname(), path, strerror(errno)); 1269 return false; 1270 } 1271 1272 if (forceload) { 1273 return true; 1274 } 1275 1276 if (sb.st_mode & (S_IWOTH|S_IWGRP)) { 1277 launchctl_log(LOG_ERR, "%s: Dubious permissions on file (skipping): %s", getprogname(), path); 1278 return false; 1279 } 1280 1281 if (sb.st_uid != 0 && sb.st_uid != getuid()) { 1282 launchctl_log(LOG_ERR, "%s: Dubious ownership on file (skipping): %s", getprogname(), path); 1283 return false; 1284 } 1285 1286 if (!(S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode))) { 1287 launchctl_log(LOG_ERR, "%s: Dubious path. Not a regular file or directory (skipping): %s", getprogname(), path); 1288 return false; 1289 } 1290 1291 if ((!S_ISDIR(sb.st_mode)) && (fnmatch("*.plist", path, FNM_CASEFOLD) == FNM_NOMATCH)) { 1292 launchctl_log(LOG_ERR, "%s: Dubious file. Not of type .plist (skipping): %s", getprogname(), path); 1293 return false; 1294 } 1295 1296 return true; 1297} 1298 1299void 1300readpath(const char *what, struct load_unload_state *lus) 1301{ 1302 char buf[MAXPATHLEN]; 1303 struct stat sb; 1304 struct dirent *de; 1305 DIR *d; 1306 1307 if (!path_goodness_check(what, lus->forceload)) { 1308 return; 1309 } 1310 1311 if (stat(what, &sb) == -1) { 1312 return; 1313 } 1314 1315 if (S_ISREG(sb.st_mode)) { 1316 readfile(what, lus); 1317 } else if (S_ISDIR(sb.st_mode)) { 1318 if ((d = opendir(what)) == NULL) { 1319 launchctl_log(LOG_ERR, "%s: opendir() failed to open the directory", getprogname()); 1320 return; 1321 } 1322 1323 while ((de = readdir(d))) { 1324 if (de->d_name[0] == '.') { 1325 continue; 1326 } 1327 snprintf(buf, sizeof(buf), "%s/%s", what, de->d_name); 1328 1329 if (!path_goodness_check(buf, lus->forceload)) { 1330 continue; 1331 } 1332 1333 readfile(buf, lus); 1334 } 1335 closedir(d); 1336 } 1337} 1338 1339void 1340insert_event(launch_data_t job, const char *stream, const char *key, launch_data_t event) 1341{ 1342 launch_data_t launchevents, streamdict; 1343 1344 launchevents = launch_data_dict_lookup(job, LAUNCH_JOBKEY_LAUNCHEVENTS); 1345 if (launchevents == NULL) { 1346 launchevents = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 1347 launch_data_dict_insert(job, launchevents, LAUNCH_JOBKEY_LAUNCHEVENTS); 1348 } 1349 1350 streamdict = launch_data_dict_lookup(launchevents, stream); 1351 if (streamdict == NULL) { 1352 streamdict = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 1353 launch_data_dict_insert(launchevents, streamdict, stream); 1354 } 1355 1356 launch_data_dict_insert(streamdict, event, key); 1357} 1358 1359struct distill_context { 1360 launch_data_t base; 1361 launch_data_t newsockdict; 1362}; 1363 1364void 1365distill_jobs(launch_data_t jobs) 1366{ 1367 size_t i, c = launch_data_array_get_count(jobs); 1368 launch_data_t job; 1369 1370 for (i = 0; i < c; i++) { 1371 job = launch_data_array_get_index(jobs, i); 1372 distill_config_file(job); 1373 distill_fsevents(job); 1374 } 1375} 1376 1377void 1378distill_config_file(launch_data_t id_plist) 1379{ 1380 struct distill_context dc = { id_plist, NULL }; 1381 launch_data_t tmp; 1382 1383 if ((tmp = launch_data_dict_lookup(dc.base, LAUNCH_JOBKEY_SOCKETS))) { 1384 dc.newsockdict = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 1385 launch_data_dict_iterate(tmp, sock_dict_cb, &dc); 1386 launch_data_dict_insert(dc.base, dc.newsockdict, LAUNCH_JOBKEY_SOCKETS); 1387 } 1388} 1389 1390void 1391sock_dict_cb(launch_data_t what, const char *key, void *context) 1392{ 1393 struct distill_context *dc = context; 1394 launch_data_t fdarray = launch_data_alloc(LAUNCH_DATA_ARRAY); 1395 1396 launch_data_dict_insert(dc->newsockdict, fdarray, key); 1397 1398 if (launch_data_get_type(what) == LAUNCH_DATA_DICTIONARY) { 1399 sock_dict_edit_entry(what, key, fdarray, dc->base); 1400 } else if (launch_data_get_type(what) == LAUNCH_DATA_ARRAY) { 1401 launch_data_t tmp; 1402 size_t i; 1403 1404 for (i = 0; i < launch_data_array_get_count(what); i++) { 1405 tmp = launch_data_array_get_index(what, i); 1406 sock_dict_edit_entry(tmp, key, fdarray, dc->base); 1407 } 1408 } 1409} 1410 1411void 1412sock_dict_edit_entry(launch_data_t tmp, const char *key, launch_data_t fdarray, launch_data_t thejob) 1413{ 1414 launch_data_t a, val; 1415 int sfd, st = SOCK_STREAM; 1416 bool passive = true; 1417 1418 if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_TYPE))) { 1419 if (!strcasecmp(launch_data_get_string(val), "stream")) { 1420 st = SOCK_STREAM; 1421 } else if (!strcasecmp(launch_data_get_string(val), "dgram")) { 1422 st = SOCK_DGRAM; 1423 } else if (!strcasecmp(launch_data_get_string(val), "seqpacket")) { 1424 st = SOCK_SEQPACKET; 1425 } 1426 } 1427 1428 if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_PASSIVE))) { 1429 passive = launch_data_get_bool(val); 1430 } 1431 1432 if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_SECUREWITHKEY))) { 1433 char secdir[] = LAUNCH_SECDIR, buf[1024]; 1434 launch_data_t uenv = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES); 1435 1436 if (NULL == uenv) { 1437 uenv = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 1438 launch_data_dict_insert(thejob, uenv, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES); 1439 } 1440 1441 mkdtemp(secdir); 1442 1443 sprintf(buf, "%s/%s", secdir, key); 1444 1445 a = launch_data_new_string(buf); 1446 launch_data_dict_insert(tmp, a, LAUNCH_JOBSOCKETKEY_PATHNAME); 1447 a = launch_data_new_string(buf); 1448 launch_data_dict_insert(uenv, a, launch_data_get_string(val)); 1449 } 1450 1451 if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_PATHNAME))) { 1452 struct sockaddr_un sun; 1453 mode_t sun_mode = 0; 1454 mode_t oldmask; 1455 bool setm = false; 1456 1457 memset(&sun, 0, sizeof(sun)); 1458 1459 sun.sun_family = AF_UNIX; 1460 1461 strncpy(sun.sun_path, launch_data_get_string(val), sizeof(sun.sun_path)); 1462 1463 if (posix_assumes_zero(sfd = _fd(socket(AF_UNIX, st, 0))) == -1) { 1464 return; 1465 } 1466 1467 if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_PATHMODE))) { 1468 sun_mode = (mode_t)launch_data_get_integer(val); 1469 setm = true; 1470 } 1471 1472 if (passive) { 1473 if (unlink(sun.sun_path) == -1 && errno != ENOENT) { 1474 close(sfd); 1475 return; 1476 } 1477 oldmask = umask(S_IRWXG|S_IRWXO); 1478 if (bind(sfd, (struct sockaddr *)&sun, (socklen_t) sizeof sun) == -1) { 1479 close(sfd); 1480 umask(oldmask); 1481 return; 1482 } 1483 umask(oldmask); 1484 if (setm) { 1485 chmod(sun.sun_path, sun_mode); 1486 } 1487 if ((st == SOCK_STREAM || st == SOCK_SEQPACKET) && listen(sfd, -1) == -1) { 1488 close(sfd); 1489 return; 1490 } 1491 } else if (connect(sfd, (struct sockaddr *)&sun, (socklen_t) sizeof sun) == -1) { 1492 close(sfd); 1493 return; 1494 } 1495 1496 val = launch_data_new_fd(sfd); 1497 launch_data_array_append(fdarray, val); 1498 } else { 1499 launch_data_t rnames = NULL; 1500 const char *node = NULL, *serv = NULL, *mgroup = NULL; 1501 char servnbuf[50]; 1502 struct addrinfo hints, *res0, *res; 1503 int gerr, sock_opt = 1; 1504 1505 memset(&hints, 0, sizeof(hints)); 1506 1507 hints.ai_socktype = st; 1508 if (passive) { 1509 hints.ai_flags |= AI_PASSIVE; 1510 } 1511 1512 if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_NODENAME))) { 1513 node = launch_data_get_string(val); 1514 } 1515 if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_MULTICASTGROUP))) { 1516 mgroup = launch_data_get_string(val); 1517 } 1518 if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_SERVICENAME))) { 1519 if (LAUNCH_DATA_INTEGER == launch_data_get_type(val)) { 1520 sprintf(servnbuf, "%lld", launch_data_get_integer(val)); 1521 serv = servnbuf; 1522 } else { 1523 serv = launch_data_get_string(val); 1524 } 1525 } 1526 if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_FAMILY))) { 1527 if (!strcasecmp("IPv4", launch_data_get_string(val))) { 1528 hints.ai_family = AF_INET; 1529 } else if (!strcasecmp("IPv6", launch_data_get_string(val))) { 1530 hints.ai_family = AF_INET6; 1531 } 1532 } 1533 if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_PROTOCOL))) { 1534 if (!strcasecmp("TCP", launch_data_get_string(val))) { 1535 hints.ai_protocol = IPPROTO_TCP; 1536 } else if (!strcasecmp("UDP", launch_data_get_string(val))) { 1537 hints.ai_protocol = IPPROTO_UDP; 1538 } 1539 } 1540 if ((rnames = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_BONJOUR))) { 1541 if (LAUNCH_DATA_BOOL != launch_data_get_type(rnames) || launch_data_get_bool(rnames)) { 1542 launch_data_t newevent; 1543 char eventkey[100]; 1544 1545 newevent = launch_data_copy(tmp); 1546 snprintf(eventkey, sizeof(eventkey), "com.apple.launchd.%s", key); 1547 insert_event(thejob, "com.apple.bonjour.registration", eventkey, newevent); 1548 } 1549 } 1550 1551 if ((gerr = getaddrinfo(node, serv, &hints, &res0)) != 0) { 1552 launchctl_log(LOG_ERR, "getaddrinfo(): %s", gai_strerror(gerr)); 1553 return; 1554 } 1555 1556 for (res = res0; res; res = res->ai_next) { 1557 if ((sfd = _fd(socket(res->ai_family, res->ai_socktype, res->ai_protocol))) == -1) { 1558 launchctl_log(LOG_ERR, "socket(): %s", strerror(errno)); 1559 return; 1560 } 1561 1562 do_application_firewall_magic(sfd, thejob); 1563 1564 if (hints.ai_flags & AI_PASSIVE) { 1565 if (AF_INET6 == res->ai_family && -1 == setsockopt(sfd, IPPROTO_IPV6, IPV6_V6ONLY, 1566 (void *)&sock_opt, (socklen_t) sizeof sock_opt)) { 1567 launchctl_log(LOG_ERR, "setsockopt(IPV6_V6ONLY): %m"); 1568 return; 1569 } 1570 if (mgroup) { 1571 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEPORT, (void *)&sock_opt, (socklen_t) sizeof sock_opt) == -1) { 1572 launchctl_log(LOG_ERR, "setsockopt(SO_REUSEPORT): %s", strerror(errno)); 1573 return; 1574 } 1575 } else { 1576 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt, (socklen_t) sizeof sock_opt) == -1) { 1577 launchctl_log(LOG_ERR, "setsockopt(SO_REUSEADDR): %s", strerror(errno)); 1578 return; 1579 } 1580 } 1581 if (bind(sfd, res->ai_addr, res->ai_addrlen) == -1) { 1582 launchctl_log(LOG_ERR, "bind(): %s", strerror(errno)); 1583 return; 1584 } 1585 /* The kernel may have dynamically assigned some part of the 1586 * address. (The port being a common example.) 1587 */ 1588 if (getsockname(sfd, res->ai_addr, &res->ai_addrlen) == -1) { 1589 launchctl_log(LOG_ERR, "getsockname(): %s", strerror(errno)); 1590 return; 1591 } 1592 1593 if (mgroup) { 1594 do_mgroup_join(sfd, res->ai_family, res->ai_socktype, res->ai_protocol, mgroup); 1595 } 1596 if ((res->ai_socktype == SOCK_STREAM || res->ai_socktype == SOCK_SEQPACKET) && listen(sfd, -1) == -1) { 1597 launchctl_log(LOG_ERR, "listen(): %s", strerror(errno)); 1598 return; 1599 } 1600 } else { 1601 if (connect(sfd, res->ai_addr, res->ai_addrlen) == -1) { 1602 launchctl_log(LOG_ERR, "connect(): %s", strerror(errno)); 1603 return; 1604 } 1605 } 1606 val = launch_data_new_fd(sfd); 1607 launch_data_array_append(fdarray, val); 1608 } 1609 } 1610} 1611 1612void 1613distill_fsevents(launch_data_t id_plist) 1614{ 1615 launch_data_t copy, newevent; 1616 launch_data_t tmp, tmp2; 1617 1618 if ((tmp = launch_data_dict_lookup(id_plist, LAUNCH_JOBKEY_QUEUEDIRECTORIES))) { 1619 copy = launch_data_copy(tmp); 1620 (void)launch_data_dict_remove(id_plist, LAUNCH_JOBKEY_QUEUEDIRECTORIES); 1621 1622 newevent = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 1623 launch_data_dict_insert(newevent, copy, LAUNCH_JOBKEY_QUEUEDIRECTORIES); 1624 insert_event(id_plist, "com.apple.fsevents.matching", "com.apple.launchd." LAUNCH_JOBKEY_QUEUEDIRECTORIES, newevent); 1625 } 1626 1627 if ((tmp = launch_data_dict_lookup(id_plist, LAUNCH_JOBKEY_WATCHPATHS))) { 1628 copy = launch_data_copy(tmp); 1629 (void)launch_data_dict_remove(id_plist, LAUNCH_JOBKEY_WATCHPATHS); 1630 1631 newevent = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 1632 launch_data_dict_insert(newevent, copy, LAUNCH_JOBKEY_WATCHPATHS); 1633 insert_event(id_plist, "com.apple.fsevents.matching", "com.apple.launchd." LAUNCH_JOBKEY_WATCHPATHS, newevent); 1634 } 1635 1636 if ((tmp = launch_data_dict_lookup(id_plist, LAUNCH_JOBKEY_KEEPALIVE))) { 1637 if ((tmp2 = launch_data_dict_lookup(tmp, LAUNCH_JOBKEY_KEEPALIVE_PATHSTATE))) { 1638 copy = launch_data_copy(tmp2); 1639 (void)launch_data_dict_remove(tmp, LAUNCH_JOBKEY_KEEPALIVE_PATHSTATE); 1640 1641 newevent = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 1642 launch_data_dict_insert(newevent, copy, LAUNCH_JOBKEY_KEEPALIVE_PATHSTATE); 1643 insert_event(id_plist, "com.apple.fsevents.matching", "com.apple.launchd." LAUNCH_JOBKEY_KEEPALIVE_PATHSTATE, newevent); 1644 } 1645 } 1646} 1647 1648void 1649do_mgroup_join(int fd, int family, int socktype, int protocol, const char *mgroup) 1650{ 1651 struct addrinfo hints, *res0, *res; 1652 struct ip_mreq mreq; 1653 struct ipv6_mreq m6req; 1654 int gerr; 1655 1656 memset(&hints, 0, sizeof(hints)); 1657 1658 hints.ai_flags |= AI_PASSIVE; 1659 hints.ai_family = family; 1660 hints.ai_socktype = socktype; 1661 hints.ai_protocol = protocol; 1662 1663 if ((gerr = getaddrinfo(mgroup, NULL, &hints, &res0)) != 0) { 1664 launchctl_log(LOG_ERR, "getaddrinfo(): %s", gai_strerror(gerr)); 1665 return; 1666 } 1667 1668 for (res = res0; res; res = res->ai_next) { 1669 if (AF_INET == family) { 1670 memset(&mreq, 0, sizeof(mreq)); 1671 mreq.imr_multiaddr = ((struct sockaddr_in *)res->ai_addr)->sin_addr; 1672 if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, (socklen_t) sizeof mreq) == -1) { 1673 launchctl_log(LOG_ERR, "setsockopt(IP_ADD_MEMBERSHIP): %s", strerror(errno)); 1674 continue; 1675 } 1676 break; 1677 } else if (AF_INET6 == family) { 1678 memset(&m6req, 0, sizeof(m6req)); 1679 m6req.ipv6mr_multiaddr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 1680 if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &m6req, (socklen_t) sizeof m6req) == -1) { 1681 launchctl_log(LOG_ERR, "setsockopt(IPV6_JOIN_GROUP): %s", strerror(errno)); 1682 continue; 1683 } 1684 break; 1685 } else { 1686 launchctl_log(LOG_ERR, "unknown family during multicast group bind!"); 1687 break; 1688 } 1689 } 1690 1691 freeaddrinfo(res0); 1692} 1693 1694#pragma mark XPC Cache 1695 1696#if TARGET_OS_EMBEDDED 1697 1698CFPropertyListRef 1699GetPropertyListFromCache(void) 1700{ 1701 static CFPropertyListRef propertyList; 1702 CFDataRef cacheData; 1703 CFErrorRef error; 1704 1705 if (!propertyList) { 1706 uint8_t *data = NULL; 1707 unsigned long sz = 0; 1708 1709 void *handle = dlopen(XPC_PLIST_CACHE, RTLD_NOW); 1710 1711 if (handle) { 1712 void *fnptr = dlsym(handle, "__xpcd_cache"); 1713 1714 if (fnptr) { 1715 Dl_info image_info; 1716 1717 int rv = dladdr(fnptr, &image_info); 1718 if (rv != 0) { 1719 data = getsectiondata(image_info.dli_fbase, "__TEXT", "__xpcd_cache", &sz); 1720 } else { 1721 launchctl_log(LOG_ERR, "cache loading failed: failed to find address of __xpcd_cache symbol."); 1722 } 1723 } else { 1724 launchctl_log(LOG_ERR, "cache loading failed: failed to find __xpcd_cache symbol in cache."); 1725 } 1726 } else { 1727 launchctl_log(LOG_ERR, "cache loading failed: dlopen returned %s.", dlerror()); 1728 } 1729 1730 if (data) { 1731 cacheData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, data, sz, kCFAllocatorNull); 1732 if (cacheData) { 1733 propertyList = CFPropertyListCreateWithData(kCFAllocatorDefault, cacheData, kCFPropertyListMutableContainersAndLeaves, NULL, &error); 1734 CFRelease(cacheData); 1735 } else { 1736 launchctl_log(LOG_ERR, "cache loading failed: unable to create data out of memory region."); 1737 } 1738 } else { 1739 launchctl_log(LOG_ERR, "cache loading failed: no cache data found in __TEXT,__xpcd_cache segment."); 1740 } 1741 } 1742 1743 return propertyList; 1744} 1745 1746CFPropertyListRef 1747CreateMyPropertyListFromCachedFile(const char *posixfile) 1748{ 1749 CFPropertyListRef cache = GetPropertyListFromCache(); 1750 CFPropertyListRef job = NULL; 1751 1752 if (cache) { 1753 CFPropertyListRef jobs = CFDictionaryGetValue(cache, CFSTR(XPC_PLIST_CACHE_KEY)); 1754 1755 if (jobs) { 1756 CFStringRef key = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, posixfile, kCFStringEncodingUTF8, kCFAllocatorNull); 1757 1758 if (key) { 1759 job = CFDictionaryGetValue(jobs, key); 1760 CFRelease(key); 1761 } 1762 } 1763 } 1764 1765 if (job) { 1766 CFRetain(job); 1767 } 1768 return job; 1769} 1770 1771bool 1772require_jobs_from_cache(void) 1773{ 1774 char buf[1024]; 1775 size_t len; 1776 char *ptr; 1777 unsigned long val; 1778 bool cs_disabled = false; 1779 len = sizeof(buf); 1780 1781 if (sysctlbyname("kern.bootargs", buf, &len, NULL, 0) == 0) { 1782 ptr = strnstr(buf, "cs_enforcement_disable=", len); 1783 if (ptr != NULL) { 1784 val = strtoul(ptr + strlen("cs_enforcement_disable="), NULL, 10); 1785 cs_disabled = (val != 0); 1786 } 1787 ptr = strnstr(buf, "launchctl_enforce_codesign=", len); 1788 if (ptr != NULL) { 1789 char *endptr = NULL; 1790 char *startptr = ptr + strlen("launchctl_enforce_codesign="); 1791 val = strtoul(startptr, &endptr, 10); 1792 cs_disabled = (val == 0 && startptr != endptr); 1793 } 1794 } 1795 1796 return !cs_disabled; 1797} 1798 1799#endif 1800 1801#pragma mark File-based Property Lists 1802 1803CFPropertyListRef 1804CreateMyPropertyListFromFile(const char *posixfile) 1805{ 1806 CFPropertyListRef propertyList; 1807 CFStringRef errorString; 1808 CFDataRef resourceData; 1809 SInt32 errorCode; 1810 CFURLRef fileURL; 1811 1812 fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)posixfile, strlen(posixfile), false); 1813 if (!fileURL) { 1814 launchctl_log(LOG_ERR, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed", getprogname(), posixfile); 1815 } 1816 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) { 1817 launchctl_log(LOG_ERR, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d", getprogname(), posixfile, (int)errorCode); 1818 } 1819 1820 propertyList = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainersAndLeaves, &errorString); 1821 if (fileURL) { 1822 CFRelease(fileURL); 1823 } 1824 1825 if (resourceData) { 1826 CFRelease(resourceData); 1827 } 1828 1829 return propertyList; 1830} 1831 1832void 1833WriteMyPropertyListToFile(CFPropertyListRef plist, const char *posixfile) 1834{ 1835 CFDataRef resourceData; 1836 CFURLRef fileURL; 1837 SInt32 errorCode; 1838 1839 fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)posixfile, strlen(posixfile), false); 1840 if (!fileURL) { 1841 launchctl_log(LOG_ERR, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed", getprogname(), posixfile); 1842 } 1843 resourceData = CFPropertyListCreateXMLData(kCFAllocatorDefault, plist); 1844 if (resourceData == NULL) { 1845 launchctl_log(LOG_ERR, "%s: CFPropertyListCreateXMLData(%s) failed", getprogname(), posixfile); 1846 } 1847 if (!CFURLWriteDataAndPropertiesToResource(fileURL, resourceData, NULL, &errorCode)) { 1848 launchctl_log(LOG_ERR, "%s: CFURLWriteDataAndPropertiesToResource(%s) failed: %d", getprogname(), posixfile, (int)errorCode); 1849 } 1850 1851 if (resourceData) { 1852 CFRelease(resourceData); 1853 } 1854} 1855 1856static inline Boolean 1857_is_launch_data_t(launch_data_t obj) 1858{ 1859 Boolean result = true; 1860 1861 switch (launch_data_get_type(obj)) { 1862 case LAUNCH_DATA_STRING : break; 1863 case LAUNCH_DATA_INTEGER : break; 1864 case LAUNCH_DATA_REAL : break; 1865 case LAUNCH_DATA_BOOL : break; 1866 case LAUNCH_DATA_ARRAY : break; 1867 case LAUNCH_DATA_DICTIONARY : break; 1868 case LAUNCH_DATA_FD : break; 1869 case LAUNCH_DATA_MACHPORT : break; 1870 default : result = false; 1871 } 1872 1873 return result; 1874} 1875 1876static void 1877_launch_data_iterate(launch_data_t obj, const char *key, CFMutableDictionaryRef dict) 1878{ 1879 if (obj && _is_launch_data_t(obj)) { 1880 CFStringRef cfKey = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8); 1881 CFTypeRef cfVal = CFTypeCreateFromLaunchData(obj); 1882 1883 if (cfVal) { 1884 CFDictionarySetValue(dict, cfKey, cfVal); 1885 CFRelease(cfVal); 1886 } 1887 CFRelease(cfKey); 1888 } 1889} 1890 1891static CFTypeRef 1892CFTypeCreateFromLaunchData(launch_data_t obj) 1893{ 1894 CFTypeRef cfObj = NULL; 1895 1896 switch (launch_data_get_type(obj)) { 1897 case LAUNCH_DATA_STRING: { 1898 const char *str = launch_data_get_string(obj); 1899 cfObj = CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8); 1900 break; 1901 } 1902 case LAUNCH_DATA_INTEGER: { 1903 long long integer = launch_data_get_integer(obj); 1904 cfObj = CFNumberCreate(NULL, kCFNumberLongLongType, &integer); 1905 break; 1906 } 1907 case LAUNCH_DATA_REAL: { 1908 double real = launch_data_get_real(obj); 1909 cfObj = CFNumberCreate(NULL, kCFNumberDoubleType, &real); 1910 break; 1911 } 1912 case LAUNCH_DATA_BOOL: { 1913 bool yesno = launch_data_get_bool(obj); 1914 cfObj = yesno ? kCFBooleanTrue : kCFBooleanFalse; 1915 break; 1916 } 1917 case LAUNCH_DATA_ARRAY: { 1918 cfObj = (CFTypeRef)CFArrayCreateFromLaunchArray(obj); 1919 break; 1920 } 1921 case LAUNCH_DATA_DICTIONARY: { 1922 cfObj = (CFTypeRef)CFDictionaryCreateFromLaunchDictionary(obj); 1923 break; 1924 } 1925 case LAUNCH_DATA_FD: { 1926 int fd = launch_data_get_fd(obj); 1927 cfObj = CFNumberCreate(NULL, kCFNumberIntType, &fd); 1928 break; 1929 } 1930 case LAUNCH_DATA_MACHPORT: { 1931 mach_port_t port = launch_data_get_machport(obj); 1932 cfObj = CFNumberCreate(NULL, kCFNumberIntType, &port); 1933 break; 1934 } 1935 default: 1936 break; 1937 } 1938 1939 return cfObj; 1940} 1941 1942#pragma mark CFArray 1943static CFArrayRef 1944CFArrayCreateFromLaunchArray(launch_data_t arr) 1945{ 1946 CFArrayRef result = NULL; 1947 CFMutableArrayRef mutResult = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 1948 1949 if (launch_data_get_type(arr) == LAUNCH_DATA_ARRAY) { 1950 unsigned int count = launch_data_array_get_count(arr); 1951 unsigned int i = 0; 1952 1953 for (i = 0; i < count; i++) { 1954 launch_data_t launch_obj = launch_data_array_get_index(arr, i); 1955 CFTypeRef obj = CFTypeCreateFromLaunchData(launch_obj); 1956 1957 if (obj) { 1958 CFArrayAppendValue(mutResult, obj); 1959 CFRelease(obj); 1960 } 1961 } 1962 1963 result = CFArrayCreateCopy(NULL, mutResult); 1964 } 1965 1966 if (mutResult) { 1967 CFRelease(mutResult); 1968 } 1969 return result; 1970} 1971 1972#pragma mark CFDictionary / CFPropertyList 1973static CFDictionaryRef 1974CFDictionaryCreateFromLaunchDictionary(launch_data_t dict) 1975{ 1976 CFDictionaryRef result = NULL; 1977 1978 if (launch_data_get_type(dict) == LAUNCH_DATA_DICTIONARY) { 1979 CFMutableDictionaryRef mutResult = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1980 1981 launch_data_dict_iterate(dict, (void (*)(launch_data_t, const char *, void *))_launch_data_iterate, mutResult); 1982 1983 result = CFDictionaryCreateCopy(NULL, mutResult); 1984 CFRelease(mutResult); 1985 } 1986 1987 return result; 1988} 1989 1990void 1991myCFDictionaryApplyFunction(const void *key, const void *value, void *context) 1992{ 1993 launch_data_t ik, iw, where = context; 1994 1995 ik = CF2launch_data(key); 1996 iw = CF2launch_data(value); 1997 1998 launch_data_dict_insert(where, iw, launch_data_get_string(ik)); 1999 launch_data_free(ik); 2000} 2001 2002launch_data_t 2003CF2launch_data(CFTypeRef cfr) 2004{ 2005 launch_data_t r; 2006 CFTypeID cft = CFGetTypeID(cfr); 2007 2008 if (cft == CFStringGetTypeID()) { 2009 char buf[4096]; 2010 CFStringGetCString(cfr, buf, sizeof(buf), kCFStringEncodingUTF8); 2011 r = launch_data_alloc(LAUNCH_DATA_STRING); 2012 launch_data_set_string(r, buf); 2013 } else if (cft == CFBooleanGetTypeID()) { 2014 r = launch_data_alloc(LAUNCH_DATA_BOOL); 2015 launch_data_set_bool(r, CFBooleanGetValue(cfr)); 2016 } else if (cft == CFArrayGetTypeID()) { 2017 CFIndex i, ac = CFArrayGetCount(cfr); 2018 r = launch_data_alloc(LAUNCH_DATA_ARRAY); 2019 for (i = 0; i < ac; i++) { 2020 CFTypeRef v = CFArrayGetValueAtIndex(cfr, i); 2021 if (v) { 2022 launch_data_t iv = CF2launch_data(v); 2023 launch_data_array_set_index(r, iv, i); 2024 } 2025 } 2026 } else if (cft == CFDictionaryGetTypeID()) { 2027 r = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 2028 CFDictionaryApplyFunction(cfr, myCFDictionaryApplyFunction, r); 2029 } else if (cft == CFDataGetTypeID()) { 2030 r = launch_data_alloc(LAUNCH_DATA_OPAQUE); 2031 launch_data_set_opaque(r, CFDataGetBytePtr(cfr), CFDataGetLength(cfr)); 2032 } else if (cft == CFNumberGetTypeID()) { 2033 long long n; 2034 double d; 2035 CFNumberType cfnt = CFNumberGetType(cfr); 2036 switch (cfnt) { 2037 case kCFNumberSInt8Type: 2038 case kCFNumberSInt16Type: 2039 case kCFNumberSInt32Type: 2040 case kCFNumberSInt64Type: 2041 case kCFNumberCharType: 2042 case kCFNumberShortType: 2043 case kCFNumberIntType: 2044 case kCFNumberLongType: 2045 case kCFNumberLongLongType: 2046 CFNumberGetValue(cfr, kCFNumberLongLongType, &n); 2047 r = launch_data_alloc(LAUNCH_DATA_INTEGER); 2048 launch_data_set_integer(r, n); 2049 break; 2050 case kCFNumberFloat32Type: 2051 case kCFNumberFloat64Type: 2052 case kCFNumberFloatType: 2053 case kCFNumberDoubleType: 2054 CFNumberGetValue(cfr, kCFNumberDoubleType, &d); 2055 r = launch_data_alloc(LAUNCH_DATA_REAL); 2056 launch_data_set_real(r, d); 2057 break; 2058 default: 2059 r = NULL; 2060 break; 2061 } 2062 } else { 2063 r = NULL; 2064 } 2065 return r; 2066} 2067 2068int 2069help_cmd(int argc, char *const argv[]) 2070{ 2071 size_t i, l, cmdwidth = 0; 2072 2073 int level = LOG_NOTICE; 2074 if (argc == 0 || argv == NULL) { 2075 level = LOG_ERR; 2076 } 2077 2078 launchctl_log(level, "usage: %s <subcommand>", getprogname()); 2079 2080 for (i = 0; i < (sizeof cmds / sizeof cmds[0]); i++) { 2081 l = strlen(cmds[i].name); 2082 if (l > cmdwidth) { 2083 cmdwidth = l; 2084 } 2085 } 2086 2087 for (i = 0; i < (sizeof cmds / sizeof cmds[0]); i++) { 2088 launchctl_log(level, "\t%-*s\t%s", (int)cmdwidth, cmds[i].name, cmds[i].desc); 2089 } 2090 2091 return 0; 2092} 2093 2094int 2095exit_cmd(int argc __attribute__((unused)), char *const argv[] __attribute__((unused))) 2096{ 2097 exit(0); 2098} 2099 2100int 2101_fd(int fd) 2102{ 2103 if (fd >= 0) 2104 fcntl(fd, F_SETFD, 1); 2105 return fd; 2106} 2107 2108void 2109do_single_user_mode(bool sflag) 2110{ 2111 if (sflag) { 2112 while (!do_single_user_mode2()) { 2113 sleep(1); 2114 } 2115 } 2116} 2117 2118bool 2119do_single_user_mode2(void) 2120{ 2121 bool runcom_fsck = true; /* should_fsck(); */ 2122 int wstatus; 2123 int fd; 2124 pid_t p; 2125 2126 switch ((p = fork())) { 2127 case -1: 2128 syslog(LOG_ERR, "can't fork single-user shell, trying again: %m"); 2129 return false; 2130 case 0: 2131 break; 2132 default: 2133 (void)os_assumes_zero(waitpid(p, &wstatus, 0)); 2134 if (WIFEXITED(wstatus)) { 2135 if (WEXITSTATUS(wstatus) == EXIT_SUCCESS) { 2136 return true; 2137 } else { 2138 launchctl_log(LOG_NOTICE, "single user mode: exit status: %d", WEXITSTATUS(wstatus)); 2139 } 2140 } else { 2141 launchctl_log(LOG_NOTICE, "single user mode shell: %s", strsignal(WTERMSIG(wstatus))); 2142 } 2143 return false; 2144 } 2145 2146 revoke(_PATH_CONSOLE); 2147 if (posix_assumes_zero((fd = open(_PATH_CONSOLE, O_RDWR))) == -1) { 2148 _exit(EXIT_FAILURE); 2149 } 2150 if (posix_assumes_zero(login_tty(fd)) == -1) { 2151 _exit(EXIT_FAILURE); 2152 } 2153 2154#ifndef DARLING 2155 mach_timespec_t wt = { 5, 0 }; 2156 IOKitWaitQuiet(kIOMasterPortDefault, &wt); /* This will hopefully return after all the kexts have shut up. */ 2157#endif // DARLING 2158 2159 setenv("TERM", "vt100", 1); 2160 if (runcom_fsck) { 2161 fprintf(stdout, "Singleuser boot -- fsck not done\n"); 2162 fprintf(stdout, "Root device is mounted read-only\n"); 2163 fprintf(stdout, "If you want to make modifications to files:\n"); 2164 fprintf(stdout, "\t/sbin/fsck -fy\n\t/sbin/mount -uw /\n"); 2165 fprintf(stdout, "If you wish to boot the system:\n"); 2166 fprintf(stdout, "\texit\n"); 2167 fflush(stdout); 2168 } 2169 2170 execl(_PATH_BSHELL, "-sh", NULL); 2171 fprintf(stderr, "can't exec %s for single user: %m\n", _PATH_BSHELL); 2172 _exit(EXIT_FAILURE); 2173} 2174 2175void 2176do_crash_debug_mode(void) 2177{ 2178 while (!do_crash_debug_mode2()) { 2179 sleep(1); 2180 } 2181} 2182 2183bool 2184do_crash_debug_mode2(void) 2185{ 2186 int wstatus; 2187 int fd; 2188 pid_t p; 2189 2190 switch ((p = fork())) { 2191 case -1: 2192 syslog(LOG_ERR, "can't fork crash debug shell, trying again: %m"); 2193 return false; 2194 case 0: 2195 break; 2196 default: 2197 (void)os_assumes_zero(waitpid(p, &wstatus, 0)); 2198 if (WIFEXITED(wstatus)) { 2199 if (WEXITSTATUS(wstatus) == EXIT_SUCCESS) { 2200 return true; 2201 } else { 2202 launchctl_log(LOG_NOTICE, "crash debug mode: exit status: %d", WEXITSTATUS(wstatus)); 2203 } 2204 } else { 2205 launchctl_log(LOG_NOTICE, "crash debug mode shell: %s", strsignal(WTERMSIG(wstatus))); 2206 } 2207 return false; 2208 } 2209 2210 revoke(_PATH_CONSOLE); 2211 if (posix_assumes_zero((fd = open(_PATH_CONSOLE, O_RDWR))) == -1) { 2212 _exit(EXIT_FAILURE); 2213 } 2214 if (posix_assumes_zero(login_tty(fd)) == -1) { 2215 _exit(EXIT_FAILURE); 2216 } 2217 2218 /* The idea is to wait until all the kexts have quiesced to prevent a bunch 2219 * of log messages from being slammed onto the console prompt. It mostly 2220 * works. 2221 */ 2222#ifndef DARLING 2223 mach_timespec_t wt = { 5, 0 }; 2224 IOKitWaitQuiet(kIOMasterPortDefault, &wt); 2225#endif // DARLING 2226 2227 setenv("TERM", "vt100", 1); 2228 fprintf(stdout, "Entering boot-time debugging mode...\n"); 2229 fprintf(stdout, "The system bootstrapper process has crashed. To debug:\n"); 2230 fprintf(stdout, "\tgdb attach %i\n", getppid()); 2231 fprintf(stdout, "You can try booting the system with:\n"); 2232 fprintf(stdout, "\tlaunchctl load -S System -D All\n"); 2233 2234 execl(_PATH_BSHELL, "-sh", NULL); 2235 fprintf(stderr, "can't exec %s for crash debug: %m\n", _PATH_BSHELL); 2236 _exit(EXIT_FAILURE); 2237} 2238 2239static void 2240exit_at_sigterm(int sig) 2241{ 2242 if (sig == SIGTERM) { 2243 _exit(EXIT_SUCCESS); 2244 } 2245} 2246 2247void 2248fatal_signal_handler(int sig __attribute__((unused)), siginfo_t *si __attribute__((unused)), void *uap __attribute__((unused))) 2249{ 2250 do_crash_debug_mode(); 2251} 2252 2253void 2254handle_system_bootstrapper_crashes_separately(void) 2255{ 2256 if (!_launchctl_startup_debugging) { 2257 return; 2258 } 2259 2260 fprintf(stdout, "com.apple.launchctl.System\t\t\t*** Handling system bootstrapper crashes separately. ***\n"); 2261 struct sigaction fsa; 2262 2263 fsa.sa_sigaction = fatal_signal_handler; 2264 fsa.sa_flags = SA_SIGINFO; 2265 sigemptyset(&fsa.sa_mask); 2266 2267 (void)posix_assumes_zero(sigaction(SIGILL, &fsa, NULL)); 2268 (void)posix_assumes_zero(sigaction(SIGFPE, &fsa, NULL)); 2269 (void)posix_assumes_zero(sigaction(SIGBUS, &fsa, NULL)); 2270 (void)posix_assumes_zero(sigaction(SIGTRAP, &fsa, NULL)); 2271 (void)posix_assumes_zero(sigaction(SIGABRT, &fsa, NULL)); 2272} 2273 2274#if TARGET_OS_EMBEDDED 2275static void 2276init_data_protection(void) 2277{ 2278 if (path_check("/usr/libexec/init_data_protection")) { 2279 const char *init_cp[] = { "/usr/libexec/init_data_protection", NULL }; 2280 if (fwexec(init_cp, NULL) == -1) { 2281 launchctl_log(LOG_ERR, "Couldn't init content protection: %d: %s", errno, strerror(errno)); 2282 (void)reboot(RB_HALT); 2283 2284 _exit(EXIT_FAILURE); 2285 } 2286 } 2287} 2288#endif 2289 2290static void 2291system_specific_bootstrap(bool sflag) 2292{ 2293 int hnmib[] = { CTL_KERN, KERN_HOSTNAME }; 2294 struct kevent kev; 2295 int kq; 2296#if HAVE_LIBAUDITD 2297 launch_data_t lda, ldb; 2298#endif 2299 2300 handle_system_bootstrapper_crashes_separately(); 2301 2302 // Disable Libinfo lookups to mdns and ds while bootstrapping (8698260) 2303 si_search_module_set_flags("mdns", 1); 2304 si_search_module_set_flags("ds", 1); 2305 2306 /* rc.cdrom's hack to load the system means that we're not the real system 2307 * bootstrapper. So we set this environment variable, and if the real 2308 * bootstrapper detects it, it will disable lookups to mDNSResponder and 2309 * opendirectoryd to prevent deadlocks at boot. 2310 * 2311 * See <rdar://problem/9877230>. 2312 */ 2313 (void)setenv(LAUNCH_ENV_BOOTSTRAPPINGSYSTEM, "1", 1); 2314 2315 do_sysversion_sysctl(); 2316 2317 do_single_user_mode(sflag); 2318 2319 (void)posix_assumes_zero(kq = kqueue()); 2320 EV_SET(&kev, 0, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, 60, 0); 2321 (void)posix_assumes_zero(kevent(kq, &kev, 1, NULL, 0, NULL)); 2322 2323 __OS_COMPILETIME_ASSERT__(SIG_ERR == (typeof(SIG_ERR))-1); 2324 EV_SET(&kev, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); 2325 (void)posix_assumes_zero(kevent(kq, &kev, 1, NULL, 0, NULL)); 2326 (void)posix_assumes_zero(signal(SIGTERM, SIG_IGN)); 2327 (void)posix_assumes_zero(sysctl(hnmib, 2, NULL, NULL, "localhost", sizeof("localhost"))); 2328 2329 loopback_setup_ipv4(); 2330 loopback_setup_ipv6(); 2331 2332 apply_sysctls_from_file("/etc/sysctl.conf"); 2333 2334#if TARGET_OS_EMBEDDED 2335 if (path_check("/etc/rc.boot")) { 2336 const char *rcboot_tool[] = { "/etc/rc.boot", NULL }; 2337 2338 (void)posix_assumes_zero(signal(SIGTERM, exit_at_sigterm)); 2339 (void)posix_assumes_zero(fwexec(rcboot_tool, NULL)); 2340 } 2341#endif 2342 2343 if (path_check("/etc/rc.cdrom")) { 2344 const char *rccdrom_tool[] = { _PATH_BSHELL, "/etc/rc.cdrom", "multiuser", NULL }; 2345 2346 /* The bootstrapper should always be killable during install-time. This 2347 * is a special case for /etc/rc.cdrom, which runs a process and never 2348 * exits. 2349 * 2350 * <rdar://problem/6103485> 2351 */ 2352 (void)posix_assumes_zero(signal(SIGTERM, exit_at_sigterm)); 2353 (void)posix_assumes_zero(fwexec(rccdrom_tool, NULL)); 2354 (void)reboot(RB_HALT); 2355 _exit(EXIT_FAILURE); 2356 } else if (is_netboot()) { 2357 const char *rcnetboot_tool[] = { _PATH_BSHELL, "/etc/rc.netboot", "init", NULL }; 2358 if (posix_assumes_zero(fwexec(rcnetboot_tool, NULL)) == -1) { 2359 (void)reboot(RB_HALT); 2360 _exit(EXIT_FAILURE); 2361 } 2362 } else { 2363 do_potential_fsck(); 2364 } 2365 2366#if TARGET_OS_EMBEDDED 2367 if (path_check("/usr/libexec/tzinit")) { 2368 const char *tzinit_tool[] = { "/usr/libexec/tzinit", NULL }; 2369 (void)posix_assumes_zero(fwexec(tzinit_tool, NULL)); 2370 } 2371#endif 2372 2373#if TARGET_OS_EMBEDDED 2374 if (path_check("/usr/libexec/FinishRestoreFromBackup")) { 2375 const char *finish_restore[] = { "/usr/libexec/FinishRestoreFromBackup", NULL }; 2376 if (fwexec(finish_restore, NULL) == -1) { 2377 launchctl_log(LOG_ERR, "Couldn't finish restore: %d: %s", errno, strerror(errno)); 2378 (void)reboot(RB_HALT); 2379 2380 _exit(EXIT_FAILURE); 2381 } 2382 } 2383#endif 2384 2385 if (path_check("/usr/libexec/cc_fips_test")) { 2386 const char *fips_tool[] = { "/usr/libexec/cc_fips_test", "-P", NULL }; 2387 if (fwexec(fips_tool, NULL) == -1) { 2388 launchctl_log(LOG_ERR, "FIPS self check failure: %d: %s", errno, strerror(errno)); 2389 (void)reboot(RB_HALT); 2390 2391 _exit(EXIT_FAILURE); 2392 } 2393 } 2394 2395 if (path_check("/etc/rc.server")) { 2396 const char *rcserver_tool[] = { _PATH_BSHELL, "/etc/rc.server", NULL }; 2397 (void)posix_assumes_zero(fwexec(rcserver_tool, NULL)); 2398 } 2399 2400 read_launchd_conf(); 2401 2402 if (path_check("/var/account/acct")) { 2403 (void)posix_assumes_zero(acct("/var/account/acct")); 2404 } 2405 2406#if !TARGET_OS_EMBEDDED 2407 if (path_check("/etc/fstab")) { 2408 const char *mount_tool[] = { "mount", "-vat", "nonfs", NULL }; 2409 (void)posix_assumes_zero(fwexec(mount_tool, NULL)); 2410 } 2411#endif 2412 2413 if (path_check("/etc/rc.installer_cleanup")) { 2414 const char *rccleanup_tool[] = { _PATH_BSHELL, "/etc/rc.installer_cleanup", "multiuser", NULL }; 2415 (void)posix_assumes_zero(fwexec(rccleanup_tool, NULL)); 2416 } 2417 2418 if (path_check("/etc/rc.deferred_install")) { 2419 int status = 0; 2420 const char *deferredinstall_tool[] = { _PATH_BSHELL, "/etc/rc.deferred_install", NULL }; 2421 if (posix_assumes_zero(fwexec(deferredinstall_tool, &status)) == 0) { 2422 if (WEXITSTATUS(status) == EXIT_SUCCESS) { 2423 if (_launchctl_apple_internal) { 2424 launchctl_log(LOG_NOTICE, "Deferred install script completed successfully. Rebooting in 3 seconds..."); 2425 sleep(3); 2426 } 2427 2428 (void)remove(deferredinstall_tool[1]); 2429 (void)reboot(RB_AUTOBOOT); 2430 exit(EXIT_FAILURE); 2431 } else { 2432 launchctl_log(LOG_NOTICE, "Deferred install script exited with status %i. Continuing boot and hoping it'll work...", WEXITSTATUS(status)); 2433 (void)remove(deferredinstall_tool[1]); 2434 } 2435 } 2436 } 2437 2438 empty_dir(_PATH_VARRUN, NULL); 2439 empty_dir(_PATH_TMP, NULL); 2440 (void)remove(_PATH_NOLOGIN); 2441 2442 if (path_check("/usr/libexec/dirhelper")) { 2443 const char *dirhelper_tool[] = { "/usr/libexec/dirhelper", "-machineBoot", NULL }; 2444 (void)posix_assumes_zero(fwexec(dirhelper_tool, NULL)); 2445 } 2446 2447 (void)posix_assumes_zero(touch_file(_PATH_UTMPX, DEFFILEMODE)); 2448#if !TARGET_OS_EMBEDDED 2449 (void)posix_assumes_zero(touch_file(_PATH_VARRUN "/.systemStarterRunning", DEFFILEMODE)); 2450#endif 2451 2452#if HAVE_LIBAUDITD 2453 /* Only start auditing if not "Disabled" in auditd plist. */ 2454 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)) { 2455 (void)os_assumes_zero(audit_quick_start()); 2456 launch_data_free(lda); 2457 } 2458#else 2459 if (path_check("/etc/security/rc.audit")) { 2460 const char *audit_tool[] = { _PATH_BSHELL, "/etc/security/rc.audit", NULL }; 2461 (void)posix_assumes_zero(fwexec(audit_tool, NULL)); 2462 } 2463#endif 2464 2465#if HAVE_SYSTEMSTATS 2466 systemstats_boot(); 2467#endif 2468 2469 do_BootCache_magic(BOOTCACHE_START); 2470 2471 preheat_page_cache_hack(); 2472 2473 _vproc_set_global_on_demand(true); 2474 2475 char *load_launchd_items[] = { "load", "-D", "all", NULL }; 2476 int load_launchd_items_cnt = 3; 2477 2478 if (is_safeboot()) { 2479 load_launchd_items[2] = "system"; 2480 } 2481 2482 (void)posix_assumes_zero(load_and_unload_cmd(load_launchd_items_cnt, load_launchd_items)); 2483 2484#ifndef DARLING 2485 /* See <rdar://problem/5066316>. */ 2486 if (!_launchctl_apple_internal) { 2487 mach_timespec_t w = { 5, 0 }; 2488 IOKitWaitQuiet(kIOMasterPortDefault, &w); 2489 } 2490#endif // DARLING 2491 2492 do_BootCache_magic(BOOTCACHE_TAG); 2493 2494 do_bootroot_magic(); 2495 2496 _vproc_set_global_on_demand(false); 2497 2498 (void)posix_assumes_zero(kevent(kq, NULL, 0, &kev, 1, NULL)); 2499 2500 /* warmd now handles cutting off the BootCache. We just kick it off. */ 2501 (void)close(kq); 2502} 2503 2504void 2505do_BootCache_magic(BootCache_action_t what) 2506{ 2507 const char *bcc_tool[] = { "/usr/sbin/BootCacheControl", NULL, NULL }; 2508 2509 if (is_safeboot() || !path_check(bcc_tool[0])) { 2510 return; 2511 } 2512 2513 switch (what) { 2514 case BOOTCACHE_START: 2515 bcc_tool[1] = "start"; 2516 break; 2517 case BOOTCACHE_TAG: 2518 bcc_tool[1] = "tag"; 2519 break; 2520 case BOOTCACHE_STOP: 2521 bcc_tool[1] = "stop"; 2522 break; 2523 } 2524 2525 fwexec(bcc_tool, NULL); 2526} 2527 2528int 2529bootstrap_cmd(int argc, char *const argv[]) 2530{ 2531 char *session = NULL; 2532 bool sflag = false; 2533 int ch; 2534 2535 while ((ch = getopt(argc, argv, "sS:")) != -1) { 2536 switch (ch) { 2537 case 's': 2538 sflag = true; 2539 break; 2540 case 'S': 2541 session = optarg; 2542 break; 2543 case '?': 2544 default: 2545 break; 2546 } 2547 } 2548 2549 optind = 1; 2550 optreset = 1; 2551 2552 if (!session) { 2553 launchctl_log(LOG_ERR, "usage: %s bootstrap [-s] -S <session-type>", getprogname()); 2554 return 1; 2555 } 2556 2557 if (strcasecmp(session, "System") == 0) { 2558 _launchctl_system_bootstrap = true; 2559 system_specific_bootstrap(sflag); 2560 } else { 2561 char *load_launchd_items[] = { 2562 "load", 2563 "-S", 2564 session, 2565 "-D", 2566 "all", 2567 NULL, 2568 NULL, 2569 NULL, 2570 }; 2571 size_t the_argc = 5; 2572 2573 bool bootstrap_login_items = false; 2574 if (strcasecmp(session, VPROCMGR_SESSION_AQUA) == 0) { 2575 bootstrap_login_items = true; 2576 } else if (strcasecmp(session, VPROCMGR_SESSION_BACKGROUND) == 0 2577 || strcasecmp(session, VPROCMGR_SESSION_LOGINWINDOW) == 0) { 2578 /* If we're bootstrapping either the LoginWindow or Background 2579 * sessions, then we only load items from /System and /Library. We 2580 * do not attempt to load anything from a user's home directory, as 2581 * it might not be available at this time. 2582 */ 2583 load_launchd_items[4] = "system"; 2584 if (!is_safeboot()) { 2585 load_launchd_items[5] = "-D"; 2586 load_launchd_items[6] = "local"; 2587 the_argc += 2; 2588 } 2589 2590 if (strcasecmp(session, VPROCMGR_SESSION_BACKGROUND) == 0) { 2591 /* This is to force a bootstrapped job to inherit its security 2592 * session from the launchd that it resides in. 2593 */ 2594 _launchctl_peruser_bootstrap = true; 2595 read_launchd_conf(); 2596 } 2597 } 2598 2599 if (is_safeboot()) { 2600 load_launchd_items[4] = "system"; 2601 } 2602 2603 int result = load_and_unload_cmd(the_argc, load_launchd_items); 2604 if (result) { 2605 syslog(LOG_ERR, "Could not bootstrap session: %s", session); 2606 return 1; 2607 } 2608 2609 /* This will tell launchd to start listening on MachServices again. When 2610 * bootstrapping, launchd ignores requests from everyone but the 2611 * bootstrapper (us), so this unsets the "weird bootstrap" mode. 2612 */ 2613 int64_t junk = 0; 2614 vproc_err_t verr = vproc_swap_integer(NULL, VPROC_GSK_WEIRD_BOOTSTRAP, &junk, NULL); 2615 if (!verr) { 2616#if !TARGET_OS_EMBEDDED 2617 if (bootstrap_login_items) { 2618 void *smf = dlopen("/System/Library/Frameworks/ServiceManagement.framework/Versions/A/ServiceManagement", 0); 2619 if (smf) { 2620 void (*_SMLoginItemBootstrapItemsFunc)(void) = dlsym(smf, "_SMLoginItemBootstrapItems"); 2621 if (_SMLoginItemBootstrapItemsFunc) { 2622 _SMLoginItemBootstrapItemsFunc(); 2623 } else { 2624 launchctl_log(LOG_ERR, "Could not find login item bootstrap function. LoginItems will be unavailable."); 2625 } 2626 } else { 2627 launchctl_log(LOG_ERR, "Failed to open ServiceManagement framework. LoginItems will be unavailable."); 2628 } 2629 } 2630#endif 2631 } else if (bootstrap_login_items) { 2632 launchctl_log(LOG_ERR, "Failed to unset weird bootstrap. LoginItems will be unavailable."); 2633 } 2634 } 2635 2636 return 0; 2637} 2638 2639int 2640load_and_unload_cmd(int argc, char *const argv[]) 2641{ 2642 NSSearchPathEnumerationState es = 0; 2643 char nspath[PATH_MAX * 2]; /* safe side, we need to append */ 2644 bool badopts = false; 2645 struct load_unload_state lus; 2646 size_t i; 2647 int ch; 2648 2649 memset(&lus, 0, sizeof(lus)); 2650 2651 if (strcmp(argv[0], "load") == 0) { 2652 lus.load = true; 2653 } 2654 2655 while ((ch = getopt(argc, argv, "wFS:D:")) != -1) { 2656 switch (ch) { 2657 case 'w': 2658 lus.editondisk = true; 2659 break; 2660 case 'F': 2661 lus.forceload = true; 2662 break; 2663 case 'S': 2664 lus.session_type = optarg; 2665 break; 2666 case 'D': 2667 if (strcasecmp(optarg, "all") == 0) { 2668 es |= NSAllDomainsMask; 2669 } else if (strcasecmp(optarg, "user") == 0) { 2670 es |= NSUserDomainMask; 2671 } else if (strcasecmp(optarg, "local") == 0) { 2672 es |= NSLocalDomainMask; 2673 } else if (strcasecmp(optarg, "network") == 0) { 2674 es |= NSNetworkDomainMask; 2675 } else if (strcasecmp(optarg, "system") == 0) { 2676 es |= NSSystemDomainMask; 2677 } else { 2678 badopts = true; 2679 } 2680 break; 2681 case '?': 2682 default: 2683 badopts = true; 2684 break; 2685 } 2686 } 2687 argc -= optind; 2688 argv += optind; 2689 2690 if (lus.session_type == NULL) { 2691 es &= ~NSUserDomainMask; 2692 } 2693 2694 if (argc == 0 && es == 0) { 2695 badopts = true; 2696 } 2697 2698 if (badopts) { 2699 launchctl_log(LOG_ERR, "usage: %s load [-wF] [-D <user|local|network|system|all>] paths...", getprogname()); 2700 return 1; 2701 } 2702 2703 int dbfd = -1; 2704 vproc_err_t verr = vproc_swap_string(NULL, VPROC_GSK_JOB_OVERRIDES_DB, NULL, &_launchctl_job_overrides_db_path); 2705 if (verr) { 2706 if (bootstrap_port) { 2707 launchctl_log(LOG_ERR, "Could not get location of job overrides database: ppid/bootstrap: %d/0x%x", getppid(), bootstrap_port); 2708 } 2709 } else { 2710 dbfd = open(_launchctl_job_overrides_db_path, O_RDONLY | O_EXLOCK | O_CREAT, S_IRUSR | S_IWUSR); 2711 if (dbfd != -1) { 2712 _launchctl_overrides_db = (CFMutableDictionaryRef)CreateMyPropertyListFromFile(_launchctl_job_overrides_db_path); 2713 if (!_launchctl_overrides_db) { 2714 _launchctl_overrides_db = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 2715 } 2716 } else if (errno != EROFS) { 2717 launchctl_log(LOG_ERR, "Could not open job overrides database at: %s: %d: %s", _launchctl_job_overrides_db_path, errno, strerror(errno)); 2718 } 2719 } 2720 2721#if READ_JETSAM_DEFAULTS 2722 if (!read_jetsam_defaults()) { 2723 launchctl_log(LOG_NOTICE, "Failed to read jetsam defaults; no process limits applied"); 2724 } 2725#endif 2726 2727 /* Only one pass! */ 2728 lus.pass1 = launch_data_alloc(LAUNCH_DATA_ARRAY); 2729 2730 es = NSStartSearchPathEnumeration(NSLibraryDirectory, es); 2731 2732 while ((es = NSGetNextSearchPathEnumeration(es, nspath))) { 2733 if (lus.session_type) { 2734 strcat(nspath, "/LaunchAgents"); 2735 } else { 2736 strcat(nspath, "/LaunchDaemons"); 2737 } 2738 2739 bool should_glob = true; 2740 2741#if TARGET_OS_EMBEDDED 2742 if (require_jobs_from_cache()) { 2743 CFDictionaryRef cache = GetPropertyListFromCache(); 2744 if (cache) { 2745 CFDictionaryRef launchdJobs = CFDictionaryGetValue(cache, CFSTR(XPC_PLIST_CACHE_KEY)); 2746 if (launchdJobs) { 2747 CFIndex sz = CFDictionaryGetCount(launchdJobs); 2748 2749 CFStringRef *keys = malloc(sz * sizeof(CFStringRef)); 2750 CFDictionaryGetKeysAndValues(launchdJobs, (const void**)keys, NULL); 2751 2752 for (i=0; i < (size_t)sz; i++) { 2753 char path[PATH_MAX]; 2754 if (CFStringGetCString(keys[i], path, PATH_MAX, kCFStringEncodingUTF8) && (strncmp(path, nspath, strlen(nspath)) == 0)) { 2755 readpath(path, &lus); 2756 } 2757 } 2758 } 2759 } 2760 2761 should_glob = false; 2762 } 2763#endif 2764 2765 if (should_glob) { 2766 glob_t g; 2767 2768 if (glob(nspath, GLOB_TILDE|GLOB_NOSORT, NULL, &g) == 0) { 2769 for (i = 0; i < g.gl_pathc; i++) { 2770 readpath(g.gl_pathv[i], &lus); 2771 } 2772 globfree(&g); 2773 } 2774 } 2775 } 2776 2777 for (i = 0; i < (size_t)argc; i++) { 2778 readpath(argv[i], &lus); 2779 } 2780 2781 if (launch_data_array_get_count(lus.pass1) == 0) { 2782 if (!_launchctl_is_managed) { 2783 launchctl_log(LOG_ERR, "nothing found to %s", lus.load ? "load" : "unload"); 2784 } 2785 launch_data_free(lus.pass1); 2786 return _launchctl_is_managed ? 0 : 1; 2787 } 2788 2789 if (lus.load) { 2790 distill_jobs(lus.pass1); 2791 submit_job_pass(lus.pass1); 2792 } else { 2793 for (i = 0; i < launch_data_array_get_count(lus.pass1); i++) { 2794 unloadjob(launch_data_array_get_index(lus.pass1, i)); 2795 } 2796 } 2797 2798 if (_launchctl_overrides_db_changed) { 2799 WriteMyPropertyListToFile(_launchctl_overrides_db, _launchctl_job_overrides_db_path); 2800 } 2801 2802 flock(dbfd, LOCK_UN); 2803 close(dbfd); 2804 return 0; 2805} 2806 2807void 2808submit_job_pass(launch_data_t jobs) 2809{ 2810 launch_data_t msg, resp; 2811 size_t i; 2812 int e; 2813 2814 if (launch_data_array_get_count(jobs) == 0) 2815 return; 2816 2817 msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 2818 2819 launch_data_dict_insert(msg, jobs, LAUNCH_KEY_SUBMITJOB); 2820 2821 resp = launch_msg(msg); 2822 2823 if (resp) { 2824 switch (launch_data_get_type(resp)) { 2825 case LAUNCH_DATA_ERRNO: 2826 if ((e = launch_data_get_errno(resp))) 2827 launchctl_log(LOG_ERR, "%s", strerror(e)); 2828 break; 2829 case LAUNCH_DATA_ARRAY: 2830 for (i = 0; i < launch_data_array_get_count(jobs); i++) { 2831 launch_data_t obatind = launch_data_array_get_index(resp, i); 2832 launch_data_t jatind = launch_data_array_get_index(jobs, i); 2833 const char *lab4job = launch_data_get_string(launch_data_dict_lookup(jatind, LAUNCH_JOBKEY_LABEL)); 2834 if (LAUNCH_DATA_ERRNO == launch_data_get_type(obatind)) { 2835 e = launch_data_get_errno(obatind); 2836 switch (e) { 2837 case EEXIST: 2838 launchctl_log(LOG_ERR, "%s: %s", lab4job, "Already loaded"); 2839 break; 2840 case ESRCH: 2841 launchctl_log(LOG_ERR, "%s: %s", lab4job, "Not loaded"); 2842 break; 2843 case ENEEDAUTH: 2844 launchctl_log(LOG_ERR, "%s: %s", lab4job, "Could not set security session"); 2845 default: 2846 launchctl_log(LOG_ERR, "%s: %s", lab4job, strerror(e)); 2847 case 0: 2848 break; 2849 } 2850 } 2851 } 2852 break; 2853 default: 2854 launchctl_log(LOG_ERR, "unknown respose from launchd!"); 2855 break; 2856 } 2857 launch_data_free(resp); 2858 } else { 2859 launchctl_log(LOG_ERR, "launch_msg(): %s", strerror(errno)); 2860 } 2861 2862 launch_data_free(msg); 2863} 2864 2865int 2866start_stop_remove_cmd(int argc, char *const argv[]) 2867{ 2868 launch_data_t resp, msg; 2869 const char *lmsgcmd = LAUNCH_KEY_STOPJOB; 2870 int e, r = 0; 2871 2872 if (0 == strcmp(argv[0], "start")) 2873 lmsgcmd = LAUNCH_KEY_STARTJOB; 2874 2875 if (0 == strcmp(argv[0], "remove")) 2876 lmsgcmd = LAUNCH_KEY_REMOVEJOB; 2877 2878 if (argc != 2) { 2879 launchctl_log(LOG_ERR, "usage: %s %s <job label>", getprogname(), argv[0]); 2880 return 1; 2881 } 2882 2883 msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 2884 launch_data_dict_insert(msg, launch_data_new_string(argv[1]), lmsgcmd); 2885 2886 resp = launch_msg(msg); 2887 launch_data_free(msg); 2888 2889 if (resp == NULL) { 2890 launchctl_log(LOG_ERR, "launch_msg(): %s", strerror(errno)); 2891 return 1; 2892 } else if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) { 2893 if ((e = launch_data_get_errno(resp))) { 2894 launchctl_log(LOG_ERR, "%s %s error: %s", getprogname(), argv[0], strerror(e)); 2895 r = 1; 2896 } 2897 } else { 2898 launchctl_log(LOG_ERR, "%s %s returned unknown response", getprogname(), argv[0]); 2899 r = 1; 2900 } 2901 2902 launch_data_free(resp); 2903 return r; 2904} 2905 2906void 2907print_jobs(launch_data_t j, const char *key __attribute__((unused)), void *context __attribute__((unused))) 2908{ 2909 static size_t depth = 0; 2910 launch_data_t lo = launch_data_dict_lookup(j, LAUNCH_JOBKEY_LABEL); 2911 launch_data_t pido = launch_data_dict_lookup(j, LAUNCH_JOBKEY_PID); 2912 launch_data_t stato = launch_data_dict_lookup(j, LAUNCH_JOBKEY_LASTEXITSTATUS); 2913 const char *label = launch_data_get_string(lo); 2914 size_t i; 2915 2916 if (pido) { 2917 fprintf(stdout, "%lld\t-\t%s\n", launch_data_get_integer(pido), label); 2918 } else if (stato) { 2919 int wstatus = (int)launch_data_get_integer(stato); 2920 if (WIFEXITED(wstatus)) { 2921 fprintf(stdout, "-\t%d\t%s\n", WEXITSTATUS(wstatus), label); 2922 } else if (WIFSIGNALED(wstatus)) { 2923 fprintf(stdout, "-\t-%d\t%s\n", WTERMSIG(wstatus), label); 2924 } else { 2925 fprintf(stdout, "-\t???\t%s\n", label); 2926 } 2927 } else { 2928 fprintf(stdout, "-\t-\t%s\n", label); 2929 } 2930 for (i = 0; i < depth; i++) { 2931 fprintf(stdout, "\t"); 2932 } 2933} 2934 2935void 2936print_obj(launch_data_t obj, const char *key, void *context __attribute__((unused))) 2937{ 2938 static size_t indent = 0; 2939 size_t i, c; 2940 2941 for (i = 0; i < indent; i++) { 2942 fprintf(stdout, "\t"); 2943 } 2944 2945 if (key) { 2946 fprintf(stdout, "\"%s\" = ", key); 2947 } 2948 2949 switch (launch_data_get_type(obj)) { 2950 case LAUNCH_DATA_STRING: 2951 fprintf(stdout, "\"%s\";\n", launch_data_get_string(obj)); 2952 break; 2953 case LAUNCH_DATA_INTEGER: 2954 fprintf(stdout, "%lld;\n", launch_data_get_integer(obj)); 2955 break; 2956 case LAUNCH_DATA_REAL: 2957 fprintf(stdout, "%f;\n", launch_data_get_real(obj)); 2958 break; 2959 case LAUNCH_DATA_BOOL: 2960 fprintf(stdout, "%s;\n", launch_data_get_bool(obj) ? "true" : "false"); 2961 break; 2962 case LAUNCH_DATA_ARRAY: 2963 c = launch_data_array_get_count(obj); 2964 fprintf(stdout, "(\n"); 2965 indent++; 2966 for (i = 0; i < c; i++) { 2967 print_obj(launch_data_array_get_index(obj, i), NULL, NULL); 2968 } 2969 indent--; 2970 for (i = 0; i < indent; i++) { 2971 fprintf(stdout, "\t"); 2972 } 2973 fprintf(stdout, ");\n"); 2974 break; 2975 case LAUNCH_DATA_DICTIONARY: 2976 fprintf(stdout, "{\n"); 2977 indent++; 2978 launch_data_dict_iterate(obj, print_obj, NULL); 2979 indent--; 2980 for (i = 0; i < indent; i++) { 2981 fprintf(stdout, "\t"); 2982 } 2983 fprintf(stdout, "};\n"); 2984 break; 2985 case LAUNCH_DATA_FD: 2986 fprintf(stdout, "file-descriptor-object;\n"); 2987 break; 2988 case LAUNCH_DATA_MACHPORT: 2989 fprintf(stdout, "mach-port-object;\n"); 2990 break; 2991 default: 2992 fprintf(stdout, "???;\n"); 2993 break; 2994 } 2995} 2996 2997int 2998list_cmd(int argc, char *const argv[]) 2999{ 3000 if (_launchctl_is_managed) { 3001 /* This output is meant for a command line, so don't print anything if 3002 * we're managed by launchd. 3003 */ 3004 return 1; 3005 } 3006 3007 launch_data_t resp, msg = NULL; 3008 int r = 0; 3009 3010 bool plist_output = false; 3011 char *label = NULL; 3012 if (argc > 3) { 3013 launchctl_log(LOG_ERR, "usage: %s list [-x] [label]", getprogname()); 3014 return 1; 3015 } else if (argc >= 2) { 3016 plist_output = (strncmp(argv[1], "-x", sizeof("-x")) == 0); 3017 label = plist_output ? argv[2] : argv[1]; 3018 } 3019 3020 if (label) { 3021 msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 3022 launch_data_dict_insert(msg, launch_data_new_string(label), LAUNCH_KEY_GETJOB); 3023 3024 resp = launch_msg(msg); 3025 launch_data_free(msg); 3026 3027 if (resp == NULL) { 3028 launchctl_log(LOG_ERR, "launch_msg(): %s", strerror(errno)); 3029 r = 1; 3030 } else if (launch_data_get_type(resp) == LAUNCH_DATA_DICTIONARY) { 3031 if (plist_output) { 3032 CFDictionaryRef respDict = CFDictionaryCreateFromLaunchDictionary(resp); 3033 CFStringRef plistStr = NULL; 3034 if (respDict) { 3035 CFDataRef plistData = CFPropertyListCreateXMLData(NULL, (CFPropertyListRef)respDict); 3036 CFRelease(respDict); 3037 if (plistData) { 3038 plistStr = CFStringCreateWithBytes(NULL, CFDataGetBytePtr(plistData), CFDataGetLength(plistData), kCFStringEncodingUTF8, false); 3039 CFRelease(plistData); 3040 } else { 3041 r = 1; 3042 } 3043 } else { 3044 r = 1; 3045 } 3046 3047 if (plistStr) { 3048 launchctl_log_CFString(LOG_NOTICE, plistStr); 3049 CFRelease(plistStr); 3050 r = 0; 3051 } 3052 } else { 3053 print_obj(resp, NULL, NULL); 3054 r = 0; 3055 } 3056 launch_data_free(resp); 3057 } else { 3058 launchctl_log(LOG_ERR, "%s %s returned unknown response", getprogname(), argv[0]); 3059 r = 1; 3060 launch_data_free(resp); 3061 } 3062 } else if (vproc_swap_complex(NULL, VPROC_GSK_ALLJOBS, NULL, &resp) == NULL) { 3063 fprintf(stdout, "PID\tStatus\tLabel\n"); 3064 launch_data_dict_iterate(resp, print_jobs, NULL); 3065 launch_data_free(resp); 3066 3067 r = 0; 3068 } 3069 3070 return r; 3071} 3072 3073int 3074stdio_cmd(int argc __attribute__((unused)), char *const argv[]) 3075{ 3076 launchctl_log(LOG_ERR, "%s %s: This sub-command no longer does anything", getprogname(), argv[0]); 3077 return 1; 3078} 3079 3080int 3081fyi_cmd(int argc, char *const argv[]) 3082{ 3083 launch_data_t resp, msg; 3084 const char *lmsgk = NULL; 3085 int e, r = 0; 3086 3087 if (argc != 1) { 3088 launchctl_log(LOG_ERR, "usage: %s %s", getprogname(), argv[0]); 3089 return 1; 3090 } 3091 3092 if (!strcmp(argv[0], "shutdown")) { 3093 lmsgk = LAUNCH_KEY_SHUTDOWN; 3094 } else if (!strcmp(argv[0], "singleuser")) { 3095 lmsgk = LAUNCH_KEY_SINGLEUSER; 3096 } else { 3097 return 1; 3098 } 3099 3100 msg = launch_data_new_string(lmsgk); 3101 resp = launch_msg(msg); 3102 launch_data_free(msg); 3103 3104 if (resp == NULL) { 3105 launchctl_log(LOG_ERR, "launch_msg(): %s", strerror(errno)); 3106 return 1; 3107 } else if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) { 3108 if ((e = launch_data_get_errno(resp))) { 3109 launchctl_log(LOG_ERR, "%s %s error: %s", getprogname(), argv[0], strerror(e)); 3110 r = 1; 3111 } 3112 } else { 3113 launchctl_log(LOG_ERR, "%s %s returned unknown response", getprogname(), argv[0]); 3114 r = 1; 3115 } 3116 3117 launch_data_free(resp); 3118 3119 return r; 3120} 3121 3122int 3123logupdate_cmd(int argc, char *const argv[]) 3124{ 3125 int64_t inval, outval; 3126 bool badargs = false, maskmode = false, onlymode = false, levelmode = false; 3127 static const struct { 3128 const char *name; 3129 int level; 3130 } logtbl[] = { 3131 { "debug", LOG_DEBUG }, 3132 { "info", LOG_INFO }, 3133 { "notice", LOG_NOTICE }, 3134 { "warning", LOG_WARNING }, 3135 { "error", LOG_ERR }, 3136 { "critical", LOG_CRIT }, 3137 { "alert", LOG_ALERT }, 3138 { "emergency", LOG_EMERG }, 3139 }; 3140 size_t i, j, logtblsz = sizeof logtbl / sizeof logtbl[0]; 3141 int m = 0; 3142 3143 if (argc >= 2) { 3144 if (!strcmp(argv[1], "mask")) 3145 maskmode = true; 3146 else if (!strcmp(argv[1], "only")) 3147 onlymode = true; 3148 else if (!strcmp(argv[1], "level")) 3149 levelmode = true; 3150 else 3151 badargs = true; 3152 } 3153 3154 if (maskmode) 3155 m = LOG_UPTO(LOG_DEBUG); 3156 3157 if (argc > 2 && (maskmode || onlymode)) { 3158 for (i = 2; i < (size_t)argc; i++) { 3159 for (j = 0; j < logtblsz; j++) { 3160 if (!strcmp(argv[i], logtbl[j].name)) { 3161 if (maskmode) 3162 m &= ~(LOG_MASK(logtbl[j].level)); 3163 else 3164 m |= LOG_MASK(logtbl[j].level); 3165 break; 3166 } 3167 } 3168 if (j == logtblsz) { 3169 badargs = true; 3170 break; 3171 } 3172 } 3173 } else if (argc > 2 && levelmode) { 3174 for (j = 0; j < logtblsz; j++) { 3175 if (!strcmp(argv[2], logtbl[j].name)) { 3176 m = LOG_UPTO(logtbl[j].level); 3177 break; 3178 } 3179 } 3180 if (j == logtblsz) 3181 badargs = true; 3182 } else if (argc != 1) { 3183 badargs = true; 3184 } 3185 3186 if (badargs) { 3187 launchctl_log(LOG_ERR, "usage: %s [[mask loglevels...] | [only loglevels...] [level loglevel]]", getprogname()); 3188 return 1; 3189 } 3190 3191 inval = m; 3192 3193 if (vproc_swap_integer(NULL, VPROC_GSK_GLOBAL_LOG_MASK, argc != 1 ? &inval : NULL, &outval) == NULL) { 3194 if (argc == 1) { 3195 for (j = 0; j < logtblsz; j++) { 3196 if (outval & LOG_MASK(logtbl[j].level)) { 3197 launchctl_log(LOG_NOTICE, "%s ", logtbl[j].name); 3198 } 3199 } 3200 launchctl_log(LOG_NOTICE, ""); 3201 } 3202 return 0; 3203 } else { 3204 return 1; 3205 } 3206} 3207 3208static const struct { 3209 const char *name; 3210 int lim; 3211} limlookup[] = { 3212 { "cpu", RLIMIT_CPU }, 3213 { "filesize", RLIMIT_FSIZE }, 3214 { "data", RLIMIT_DATA }, 3215 { "stack", RLIMIT_STACK }, 3216 { "core", RLIMIT_CORE }, 3217 { "rss", RLIMIT_RSS }, 3218 { "memlock", RLIMIT_MEMLOCK }, 3219 { "maxproc", RLIMIT_NPROC }, 3220 { "maxfiles", RLIMIT_NOFILE } 3221}; 3222 3223static const size_t limlookupcnt = sizeof limlookup / sizeof limlookup[0]; 3224 3225ssize_t 3226name2num(const char *n) 3227{ 3228 size_t i; 3229 3230 for (i = 0; i < limlookupcnt; i++) { 3231 if (!strcmp(limlookup[i].name, n)) { 3232 return limlookup[i].lim; 3233 } 3234 } 3235 return -1; 3236} 3237 3238const char * 3239num2name(int n) 3240{ 3241 size_t i; 3242 3243 for (i = 0; i < limlookupcnt; i++) { 3244 if (limlookup[i].lim == n) 3245 return limlookup[i].name; 3246 } 3247 return NULL; 3248} 3249 3250const char * 3251lim2str(rlim_t val, char *buf) 3252{ 3253 if (val == RLIM_INFINITY) 3254 strcpy(buf, "unlimited"); 3255 else 3256 sprintf(buf, "%lld", val); 3257 return buf; 3258} 3259 3260bool 3261str2lim(const char *buf, rlim_t *res) 3262{ 3263 char *endptr; 3264 *res = strtoll(buf, &endptr, 10); 3265 if (!strcmp(buf, "unlimited")) { 3266 *res = RLIM_INFINITY; 3267 return false; 3268 } else if (*endptr == '\0') { 3269 return false; 3270 } 3271 return true; 3272} 3273 3274int 3275limit_cmd(int argc, char *const argv[]) 3276{ 3277 char slimstr[100]; 3278 char hlimstr[100]; 3279 struct rlimit *lmts = NULL; 3280 launch_data_t resp, resp1 = NULL, msg, tmp; 3281 int r = 0; 3282 size_t i, lsz = -1; 3283 ssize_t which = 0; 3284 rlim_t slim = -1, hlim = -1; 3285 bool badargs = false; 3286 3287 if (argc > 4) 3288 badargs = true; 3289 3290 if (argc >= 3 && str2lim(argv[2], &slim)) 3291 badargs = true; 3292 else 3293 hlim = slim; 3294 3295 if (argc == 4 && str2lim(argv[3], &hlim)) 3296 badargs = true; 3297 3298 if (argc >= 2 && -1 == (which = name2num(argv[1]))) 3299 badargs = true; 3300 3301 if (badargs) { 3302 launchctl_log(LOG_ERR, "usage: %s %s [", getprogname(), argv[0]); 3303 for (i = 0; i < limlookupcnt; i++) 3304 launchctl_log(LOG_ERR, "%s %s", limlookup[i].name, (i + 1) == limlookupcnt ? "" : "| "); 3305 launchctl_log(LOG_ERR, "[both | soft hard]]"); 3306 return 1; 3307 } 3308 3309 msg = launch_data_new_string(LAUNCH_KEY_GETRESOURCELIMITS); 3310 resp = launch_msg(msg); 3311 launch_data_free(msg); 3312 3313 if (resp == NULL) { 3314 launchctl_log(LOG_ERR, "launch_msg(): %s", strerror(errno)); 3315 return 1; 3316 } else if (launch_data_get_type(resp) == LAUNCH_DATA_OPAQUE) { 3317 lmts = launch_data_get_opaque(resp); 3318 lsz = launch_data_get_opaque_size(resp); 3319 if (argc <= 2) { 3320 for (i = 0; i < (lsz / sizeof(struct rlimit)); i++) { 3321 if (argc == 2 && (size_t)which != i) 3322 continue; 3323 launchctl_log(LOG_NOTICE, "\t%-12s%-15s%-15s", num2name((int)i), 3324 lim2str(lmts[i].rlim_cur, slimstr), 3325 lim2str(lmts[i].rlim_max, hlimstr)); 3326 } 3327 } 3328 } else if (launch_data_get_type(resp) == LAUNCH_DATA_STRING) { 3329 launchctl_log(LOG_ERR, "%s %s error: %s", getprogname(), argv[0], launch_data_get_string(resp)); 3330 r = 1; 3331 } else { 3332 launchctl_log(LOG_ERR, "%s %s returned unknown response", getprogname(), argv[0]); 3333 r = 1; 3334 } 3335 3336 if (argc <= 2 || r != 0) { 3337 launch_data_free(resp); 3338 return r; 3339 } else { 3340 resp1 = resp; 3341 } 3342 3343 lmts[which].rlim_cur = slim; 3344 lmts[which].rlim_max = hlim; 3345 3346 bool maxfiles_exceeded = false; 3347 if (strncmp(argv[1], "maxfiles", sizeof("maxfiles")) == 0) { 3348 if (argc > 2) { 3349 maxfiles_exceeded = (strncmp(argv[2], "unlimited", sizeof("unlimited")) == 0); 3350 } 3351 3352 if (argc > 3) { 3353 maxfiles_exceeded = (maxfiles_exceeded || strncmp(argv[3], "unlimited", sizeof("unlimited")) == 0); 3354 } 3355 3356 if (maxfiles_exceeded) { 3357 launchctl_log(LOG_ERR, "Neither the hard nor soft limit for \"maxfiles\" can be unlimited. Please use a numeric parameter for both."); 3358 return 1; 3359 } 3360 } 3361 3362 msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 3363 tmp = launch_data_new_opaque(lmts, lsz); 3364 launch_data_dict_insert(msg, tmp, LAUNCH_KEY_SETRESOURCELIMITS); 3365 resp = launch_msg(msg); 3366 launch_data_free(msg); 3367 3368 if (resp == NULL) { 3369 launchctl_log(LOG_ERR, "launch_msg(): %s", strerror(errno)); 3370 return 1; 3371 } else if (launch_data_get_type(resp) == LAUNCH_DATA_STRING) { 3372 launchctl_log(LOG_ERR, "%s %s error: %s", getprogname(), argv[0], launch_data_get_string(resp)); 3373 r = 1; 3374 } else if (launch_data_get_type(resp) != LAUNCH_DATA_OPAQUE) { 3375 launchctl_log(LOG_ERR, "%s %s returned unknown response", getprogname(), argv[0]); 3376 r = 1; 3377 } 3378 3379 launch_data_free(resp); 3380 launch_data_free(resp1); 3381 3382 return r; 3383} 3384 3385int 3386umask_cmd(int argc, char *const argv[]) 3387{ 3388 bool badargs = false; 3389 char *endptr; 3390 long m = 0; 3391 int64_t inval, outval; 3392 3393 if (argc == 2) { 3394 m = strtol(argv[1], &endptr, 8); 3395 if (*endptr != '\0' || m > 0777) 3396 badargs = true; 3397 } 3398 3399 if (argc > 2 || badargs) { 3400 launchctl_log(LOG_ERR, "usage: %s %s <mask>", getprogname(), argv[0]); 3401 return 1; 3402 } 3403 3404 inval = m; 3405 3406 if (vproc_swap_integer(NULL, VPROC_GSK_GLOBAL_UMASK, argc == 2 ? &inval : NULL, &outval) == NULL) { 3407 if (argc == 1) { 3408 launchctl_log(LOG_NOTICE, "%o", (unsigned int)outval); 3409 } 3410 return 0; 3411 } else { 3412 return 1; 3413 } 3414} 3415 3416void 3417setup_system_context(void) 3418{ 3419 if (getenv(LAUNCHD_SOCKET_ENV)) { 3420 return; 3421 } 3422 3423 if (getenv(LAUNCH_ENV_KEEPCONTEXT)) { 3424 return; 3425 } 3426 3427 if (geteuid() != 0) { 3428 launchctl_log(LOG_ERR, "You must be the root user to perform this operation."); 3429 return; 3430 } 3431 3432 /* Use the system launchd's socket. */ 3433 setenv("__USE_SYSTEM_LAUNCHD", "1", 0); 3434 3435 /* Put ourselves in the system launchd's bootstrap. */ 3436 mach_port_t rootbs = str2bsport("/"); 3437 mach_port_deallocate(mach_task_self(), bootstrap_port); 3438 task_set_bootstrap_port(mach_task_self(), rootbs); 3439 bootstrap_port = rootbs; 3440} 3441 3442int 3443submit_cmd(int argc, char *const argv[]) 3444{ 3445 launch_data_t msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 3446 launch_data_t job = launch_data_alloc(LAUNCH_DATA_DICTIONARY); 3447 launch_data_t resp, largv = launch_data_alloc(LAUNCH_DATA_ARRAY); 3448 int ch, i, r = 0; 3449 3450 launch_data_dict_insert(job, launch_data_new_bool(false), LAUNCH_JOBKEY_ONDEMAND); 3451 3452 while ((ch = getopt(argc, argv, "l:p:o:e:")) != -1) { 3453 switch (ch) { 3454 case 'l': 3455 launch_data_dict_insert(job, launch_data_new_string(optarg), LAUNCH_JOBKEY_LABEL); 3456 break; 3457 case 'p': 3458 launch_data_dict_insert(job, launch_data_new_string(optarg), LAUNCH_JOBKEY_PROGRAM); 3459 break; 3460 case 'o': 3461 launch_data_dict_insert(job, launch_data_new_string(optarg), LAUNCH_JOBKEY_STANDARDOUTPATH); 3462 break; 3463 case 'e': 3464 launch_data_dict_insert(job, launch_data_new_string(optarg), LAUNCH_JOBKEY_STANDARDERRORPATH); 3465 break; 3466 default: 3467 launchctl_log(LOG_ERR, "usage: %s submit ...", getprogname()); 3468 return 1; 3469 } 3470 } 3471 argc -= optind; 3472 argv += optind; 3473 3474 for (i = 0; argv[i]; i++) { 3475 launch_data_array_append(largv, launch_data_new_string(argv[i])); 3476 } 3477 3478 launch_data_dict_insert(job, largv, LAUNCH_JOBKEY_PROGRAMARGUMENTS); 3479 3480 launch_data_dict_insert(msg, job, LAUNCH_KEY_SUBMITJOB); 3481 3482 resp = launch_msg(msg); 3483 launch_data_free(msg); 3484 3485 if (resp == NULL) { 3486 launchctl_log(LOG_ERR, "launch_msg(): %s", strerror(errno)); 3487 return 1; 3488 } else if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) { 3489 errno = launch_data_get_errno(resp); 3490 if (errno) { 3491 launchctl_log(LOG_ERR, "%s %s error: %s", getprogname(), argv[0], strerror(errno)); 3492 r = 1; 3493 } 3494 } else { 3495 launchctl_log(LOG_ERR, "%s %s error: %s", getprogname(), argv[0], "unknown response"); 3496 } 3497 3498 launch_data_free(resp); 3499 3500 return r; 3501} 3502 3503int 3504getrusage_cmd(int argc, char *const argv[]) 3505{ 3506 launch_data_t resp, msg; 3507 bool badargs = false; 3508 int r = 0; 3509 3510 if (argc != 2) 3511 badargs = true; 3512 else if (strcmp(argv[1], "self") && strcmp(argv[1], "children")) 3513 badargs = true; 3514 3515 if (badargs) { 3516 launchctl_log(LOG_ERR, "usage: %s %s self | children", getprogname(), argv[0]); 3517 return 1; 3518 } 3519 3520 if (!strcmp(argv[1], "self")) { 3521 msg = launch_data_new_string(LAUNCH_KEY_GETRUSAGESELF); 3522 } else { 3523 msg = launch_data_new_string(LAUNCH_KEY_GETRUSAGECHILDREN); 3524 } 3525 3526 resp = launch_msg(msg); 3527 launch_data_free(msg); 3528 3529 if (resp == NULL) { 3530 launchctl_log(LOG_ERR, "launch_msg(): %s", strerror(errno)); 3531 return 1; 3532 } else if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) { 3533 launchctl_log(LOG_ERR, "%s %s error: %s", getprogname(), argv[0], strerror(launch_data_get_errno(resp))); 3534 r = 1; 3535 } else if (launch_data_get_type(resp) == LAUNCH_DATA_OPAQUE) { 3536 struct rusage *rusage = launch_data_get_opaque(resp); 3537 launchctl_log(LOG_NOTICE, "\t%-10f\tuser time used", 3538 (double)rusage->ru_utime.tv_sec + (double)rusage->ru_utime.tv_usec / (double)1000000); 3539 launchctl_log(LOG_NOTICE, "\t%-10f\tsystem time used", 3540 (double)rusage->ru_stime.tv_sec + (double)rusage->ru_stime.tv_usec / (double)1000000); 3541 launchctl_log(LOG_NOTICE, "\t%-10ld\tmax resident set size", rusage->ru_maxrss); 3542 launchctl_log(LOG_NOTICE, "\t%-10ld\tshared text memory size", rusage->ru_ixrss); 3543 launchctl_log(LOG_NOTICE, "\t%-10ld\tunshared data size", rusage->ru_idrss); 3544 launchctl_log(LOG_NOTICE, "\t%-10ld\tunshared stack size", rusage->ru_isrss); 3545 launchctl_log(LOG_NOTICE, "\t%-10ld\tpage reclaims", rusage->ru_minflt); 3546 launchctl_log(LOG_NOTICE, "\t%-10ld\tpage faults", rusage->ru_majflt); 3547 launchctl_log(LOG_NOTICE, "\t%-10ld\tswaps", rusage->ru_nswap); 3548 launchctl_log(LOG_NOTICE, "\t%-10ld\tblock input operations", rusage->ru_inblock); 3549 launchctl_log(LOG_NOTICE, "\t%-10ld\tblock output operations", rusage->ru_oublock); 3550 launchctl_log(LOG_NOTICE, "\t%-10ld\tmessages sent", rusage->ru_msgsnd); 3551 launchctl_log(LOG_NOTICE, "\t%-10ld\tmessages received", rusage->ru_msgrcv); 3552 launchctl_log(LOG_NOTICE, "\t%-10ld\tsignals received", rusage->ru_nsignals); 3553 launchctl_log(LOG_NOTICE, "\t%-10ld\tvoluntary context switches", rusage->ru_nvcsw); 3554 launchctl_log(LOG_NOTICE, "\t%-10ld\tinvoluntary context switches", rusage->ru_nivcsw); 3555 } else { 3556 launchctl_log(LOG_ERR, "%s %s returned unknown response", getprogname(), argv[0]); 3557 r = 1; 3558 } 3559 3560 launch_data_free(resp); 3561 3562 return r; 3563} 3564 3565bool 3566launch_data_array_append(launch_data_t a, launch_data_t o) 3567{ 3568 size_t offt = launch_data_array_get_count(a); 3569 3570 return launch_data_array_set_index(a, o, offt); 3571} 3572 3573mach_port_t 3574str2bsport(const char *s) 3575{ 3576 bool getrootbs = strcmp(s, "/") == 0; 3577 mach_port_t last_bport, bport = bootstrap_port; 3578 task_t task = mach_task_self(); 3579 kern_return_t result; 3580 3581 if (strcmp(s, "..") == 0 || getrootbs) { 3582 do { 3583 last_bport = bport; 3584 result = bootstrap_parent(last_bport, &bport); 3585 3586 if (result == BOOTSTRAP_NOT_PRIVILEGED) { 3587 launchctl_log(LOG_ERR, "Permission denied"); 3588 return 1; 3589 } else if (result != BOOTSTRAP_SUCCESS) { 3590 launchctl_log(LOG_ERR, "bootstrap_parent() %d", result); 3591 return 1; 3592 } 3593 } while (getrootbs && last_bport != bport); 3594 } else if (strcmp(s, "0") == 0 || strcmp(s, "NULL") == 0) { 3595 bport = MACH_PORT_NULL; 3596 } else { 3597 int pid = atoi(s); 3598 3599 result = task_for_pid(mach_task_self(), pid, &task); 3600 3601 if (result != KERN_SUCCESS) { 3602 launchctl_log(LOG_ERR, "task_for_pid() %s", mach_error_string(result)); 3603 return 1; 3604 } 3605 3606 result = task_get_bootstrap_port(task, &bport); 3607 3608 if (result != KERN_SUCCESS) { 3609 launchctl_log(LOG_ERR, "Couldn't get bootstrap port: %s", mach_error_string(result)); 3610 return 1; 3611 } 3612 } 3613 3614 return bport; 3615} 3616 3617int 3618bsexec_cmd(int argc, char *const argv[]) 3619{ 3620 kern_return_t result; 3621 mach_port_t bport; 3622 3623 if (argc < 3) { 3624 launchctl_log(LOG_ERR, "usage: %s bsexec <PID> prog...", getprogname()); 3625 return 1; 3626 } 3627 3628 bport = str2bsport(argv[1]); 3629 3630 result = task_set_bootstrap_port(mach_task_self(), bport); 3631 3632 if (result != KERN_SUCCESS) { 3633 launchctl_log(LOG_ERR, "Couldn't switch to new bootstrap port: %s", mach_error_string(result)); 3634 return 1; 3635 } 3636 3637 setgid(getgid()); 3638 setuid(getuid()); 3639 3640 setenv(LAUNCH_ENV_KEEPCONTEXT, "1", 1); 3641 if (fwexec((const char *const *)argv + 2, NULL) == -1) { 3642 launchctl_log(LOG_ERR, "%s bsexec failed: %s", getprogname(), strerror(errno)); 3643 return 1; 3644 } 3645 3646 return 0; 3647} 3648 3649int 3650_bslist_cmd(mach_port_t bport, unsigned int depth, bool show_job, bool local_only) 3651{ 3652 kern_return_t result; 3653 name_array_t service_names; 3654 name_array_t service_jobs; 3655 mach_msg_type_number_t service_cnt, service_jobs_cnt, service_active_cnt; 3656 bootstrap_status_array_t service_actives; 3657 unsigned int i; 3658 3659 if (bport == MACH_PORT_NULL) { 3660 launchctl_log(LOG_ERR, "Invalid bootstrap port"); 3661 return 1; 3662 } 3663 3664 uint64_t flags = 0; 3665 flags |= local_only ? BOOTSTRAP_FORCE_LOCAL : 0; 3666 result = bootstrap_info(bport, &service_names, &service_cnt, &service_jobs, &service_jobs_cnt, &service_actives, &service_active_cnt, flags); 3667 if (result != BOOTSTRAP_SUCCESS) { 3668 launchctl_log(LOG_ERR, "bootstrap_info(): %d", result); 3669 return 1; 3670 } 3671 3672#define bport_state(x) (((x) == BOOTSTRAP_STATUS_ACTIVE) ? "A" : ((x) == BOOTSTRAP_STATUS_ON_DEMAND) ? "D" : "I") 3673 3674 for (i = 0; i < service_cnt ; i++) { 3675 if (!show_job) { 3676 fprintf(stdout, "%*s%-3s%s\n", depth, "", bport_state((service_actives[i])), service_names[i]); 3677 } else { 3678 fprintf(stdout, "%*s%-3s%s (%s)\n", depth, "", bport_state((service_actives[i])), service_names[i], service_jobs[i]); 3679 } 3680 } 3681 3682 return 0; 3683} 3684 3685int 3686bslist_cmd(int argc, char *const argv[]) 3687{ 3688 if (_launchctl_is_managed) { 3689 /* This output is meant for a command line, so don't print anything if 3690 * we're managed by launchd. 3691 */ 3692 return 1; 3693 } 3694 3695 mach_port_t bport = bootstrap_port; 3696 bool show_jobs = false; 3697 if (argc > 2 && strcmp(argv[2], "-j") == 0) { 3698 show_jobs = true; 3699 } 3700 3701 if (argc > 1) { 3702 if (show_jobs) { 3703 bport = str2bsport(argv[1]); 3704 } else if (strcmp(argv[1], "-j") == 0) { 3705 show_jobs = true; 3706 } 3707 } 3708 3709 if (bport == MACH_PORT_NULL) { 3710 launchctl_log(LOG_ERR, "Invalid bootstrap port"); 3711 return 1; 3712 } 3713 3714 return _bslist_cmd(bport, 0, show_jobs, false); 3715} 3716 3717int 3718_bstree_cmd(mach_port_t bsport, unsigned int depth, bool show_jobs) 3719{ 3720 if (bsport == MACH_PORT_NULL) { 3721 launchctl_log(LOG_ERR, "No root port!"); 3722 return 1; 3723 } 3724 3725 mach_port_array_t child_ports = NULL; 3726 name_array_t child_names = NULL; 3727 bootstrap_property_array_t child_props = NULL; 3728 unsigned int cnt = 0; 3729 3730 kern_return_t kr = bootstrap_lookup_children(bsport, &child_ports, &child_names, &child_props, (mach_msg_type_number_t *)&cnt); 3731 if (kr != BOOTSTRAP_SUCCESS && kr != BOOTSTRAP_NO_CHILDREN) { 3732 if (kr == BOOTSTRAP_NOT_PRIVILEGED) { 3733 launchctl_log(LOG_ERR, "You must be root to perform this operation."); 3734 } else { 3735 launchctl_log(LOG_ERR, "bootstrap_lookup_children(): %d", kr); 3736 } 3737 3738 return 1; 3739 } 3740 3741 unsigned int i = 0; 3742 _bslist_cmd(bsport, depth, show_jobs, true); 3743 3744 for (i = 0; i < cnt; i++) { 3745 char *type = NULL; 3746 if (child_props[i] & BOOTSTRAP_PROPERTY_PERUSER) { 3747 type = "Per-user"; 3748 } else if (child_props[i] & BOOTSTRAP_PROPERTY_EXPLICITSUBSET) { 3749 type = "Explicit Subset"; 3750 } else if (child_props[i] & BOOTSTRAP_PROPERTY_IMPLICITSUBSET) { 3751 type = "Implicit Subset"; 3752 } else if (child_props[i] & BOOTSTRAP_PROPERTY_MOVEDSUBSET) { 3753 type = "Moved Subset"; 3754 } else if (child_props[i] & BOOTSTRAP_PROPERTY_XPC_SINGLETON) { 3755 type = "XPC Singleton Domain"; 3756 } else if (child_props[i] & BOOTSTRAP_PROPERTY_XPC_DOMAIN) { 3757 type = "XPC Private Domain"; 3758 } else { 3759 type = "Unknown"; 3760 } 3761 3762 fprintf(stdout, "%*s%s (%s)/\n", depth, "", child_names[i], type); 3763 if (child_ports[i] != MACH_PORT_NULL) { 3764 _bstree_cmd(child_ports[i], depth + 4, show_jobs); 3765 } 3766 } 3767 3768 return 0; 3769} 3770 3771int 3772bstree_cmd(int argc, char * const argv[]) 3773{ 3774 if (_launchctl_is_managed) { 3775 /* This output is meant for a command line, so don't print anything if 3776 * we're managed by launchd. 3777 */ 3778 return 1; 3779 } 3780 3781 bool show_jobs = false; 3782 if (geteuid() != 0) { 3783 launchctl_log(LOG_ERR, "You must be root to perform this operation."); 3784 return 1; 3785 } else { 3786 if (argc == 2 && strcmp(argv[1], "-j") == 0) { 3787 show_jobs = true; 3788 } 3789 fprintf(stdout, "System/\n"); 3790 } 3791 3792 return _bstree_cmd(str2bsport("/"), 4, show_jobs); 3793} 3794 3795int 3796managerpid_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused))) 3797{ 3798 int64_t manager_pid = 0; 3799 vproc_err_t verr = vproc_swap_integer(NULL, VPROC_GSK_MGR_PID, NULL, (int64_t *)&manager_pid); 3800 if (verr) { 3801 launchctl_log(LOG_NOTICE, "Unknown job manager!"); 3802 return 1; 3803 } 3804 3805 launchctl_log(LOG_NOTICE, "%d", (pid_t)manager_pid); 3806 return 0; 3807} 3808 3809int 3810manageruid_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused))) 3811{ 3812 int64_t manager_uid = 0; 3813 vproc_err_t verr = vproc_swap_integer(NULL, VPROC_GSK_MGR_UID, NULL, (int64_t *)&manager_uid); 3814 if (verr) { 3815 launchctl_log(LOG_NOTICE, "Unknown job manager!"); 3816 return 1; 3817 } 3818 3819 launchctl_log(LOG_NOTICE, "%lli", manager_uid); 3820 return 0; 3821} 3822 3823int 3824managername_cmd(int argc __attribute__((unused)), char * const argv[] __attribute__((unused))) 3825{ 3826 char *manager_name = NULL; 3827 vproc_err_t verr = vproc_swap_string(NULL, VPROC_GSK_MGR_NAME, NULL, &manager_name); 3828 if (verr) { 3829 launchctl_log(LOG_NOTICE, "Unknown job manager!"); 3830 return 1; 3831 } 3832 3833 launchctl_log(LOG_NOTICE, "%s", manager_name); 3834 free(manager_name); 3835 3836 return 0; 3837} 3838 3839int 3840asuser_cmd(int argc, char * const argv[]) 3841{ 3842 /* This code plays fast and loose with Mach ports. Do NOT use it as any sort 3843 * of reference for port handling. Or really anything else in this file. 3844 */ 3845 uid_t req_uid = (uid_t)-2; 3846 if (argc > 2) { 3847 req_uid = atoi(argv[1]); 3848 if (req_uid == (uid_t)-2) { 3849 launchctl_log(LOG_ERR, "You cannot run a command nobody."); 3850 return 1; 3851 } 3852 } else { 3853 launchctl_log(LOG_ERR, "Usage: launchctl asuser <UID> <command> [arguments...]."); 3854 return 1; 3855 } 3856 3857 if (geteuid() != 0) { 3858 launchctl_log(LOG_ERR, "You must be root to run a command as another user."); 3859 return 1; 3860 } 3861 3862 mach_port_t rbs = MACH_PORT_NULL; 3863 kern_return_t kr = bootstrap_get_root(bootstrap_port, &rbs); 3864 if (kr != BOOTSTRAP_SUCCESS) { 3865 launchctl_log(LOG_ERR, "bootstrap_get_root(): %u", kr); 3866 return 1; 3867 } 3868 3869 mach_port_t bp = MACH_PORT_NULL; 3870 kr = bootstrap_look_up_per_user(rbs, NULL, req_uid, &bp); 3871 if (kr != BOOTSTRAP_SUCCESS) { 3872 launchctl_log(LOG_ERR, "bootstrap_look_up_per_user(): %u", kr); 3873 return 1; 3874 } 3875 3876 bootstrap_port = bp; 3877 kr = task_set_bootstrap_port(mach_task_self(), bp); 3878 if (kr != KERN_SUCCESS) { 3879 launchctl_log(LOG_ERR, "task_set_bootstrap_port(): 0x%x: %s", kr, mach_error_string(kr)); 3880 return 1; 3881 } 3882 3883 name_t sockpath; 3884 sockpath[0] = 0; 3885 kr = _vprocmgr_getsocket(sockpath); 3886 if (kr != BOOTSTRAP_SUCCESS) { 3887 launchctl_log(LOG_ERR, "_vprocmgr_getsocket(): %u", kr); 3888 return 1; 3889 } 3890 3891 setenv(LAUNCHD_SOCKET_ENV, sockpath, 1); 3892 setenv(LAUNCH_ENV_KEEPCONTEXT, "1", 1); 3893 if (fwexec((const char *const *)argv + 2, NULL) == -1) { 3894 launchctl_log(LOG_ERR, "Couldn't spawn command: %s", argv[2]); 3895 return 1; 3896 } 3897 3898 return 0; 3899} 3900 3901void 3902loopback_setup_ipv4(void) 3903{ 3904 struct ifaliasreq ifra; 3905 struct ifreq ifr; 3906 int s; 3907 3908 memset(&ifr, 0, sizeof(ifr)); 3909 strcpy(ifr.ifr_name, "lo0"); 3910 3911 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 3912 return; 3913 3914 if (posix_assumes_zero(ioctl(s, SIOCGIFFLAGS, &ifr)) != -1) { 3915 ifr.ifr_flags |= IFF_UP; 3916 (void)posix_assumes_zero(ioctl(s, SIOCSIFFLAGS, &ifr)); 3917 } 3918 3919 memset(&ifra, 0, sizeof(ifra)); 3920 strcpy(ifra.ifra_name, "lo0"); 3921 ((struct sockaddr_in *)&ifra.ifra_addr)->sin_family = AF_INET; 3922 ((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 3923 ((struct sockaddr_in *)&ifra.ifra_addr)->sin_len = sizeof(struct sockaddr_in); 3924 ((struct sockaddr_in *)&ifra.ifra_mask)->sin_family = AF_INET; 3925 ((struct sockaddr_in *)&ifra.ifra_mask)->sin_addr.s_addr = htonl(IN_CLASSA_NET); 3926 ((struct sockaddr_in *)&ifra.ifra_mask)->sin_len = sizeof(struct sockaddr_in); 3927 3928 (void)posix_assumes_zero(ioctl(s, SIOCAIFADDR, &ifra)); 3929 (void)close(s); 3930} 3931 3932void 3933loopback_setup_ipv6(void) 3934{ 3935 struct in6_aliasreq ifra6; 3936 struct ifreq ifr; 3937 int s6; 3938 3939 memset(&ifr, 0, sizeof(ifr)); 3940 strcpy(ifr.ifr_name, "lo0"); 3941 3942 if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) 3943 return; 3944 3945 memset(&ifr, 0, sizeof(ifr)); 3946 strcpy(ifr.ifr_name, "lo0"); 3947 3948 if (posix_assumes_zero(ioctl(s6, SIOCGIFFLAGS, &ifr)) != -1) { 3949 ifr.ifr_flags |= IFF_UP; 3950 (void)posix_assumes_zero(ioctl(s6, SIOCSIFFLAGS, &ifr)); 3951 } 3952 3953 memset(&ifra6, 0, sizeof(ifra6)); 3954 strcpy(ifra6.ifra_name, "lo0"); 3955 3956 ifra6.ifra_addr.sin6_family = AF_INET6; 3957 ifra6.ifra_addr.sin6_addr = in6addr_loopback; 3958 ifra6.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 3959 ifra6.ifra_prefixmask.sin6_family = AF_INET6; 3960 memset(&ifra6.ifra_prefixmask.sin6_addr, 0xff, sizeof(struct in6_addr)); 3961 ifra6.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 3962 ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 3963 ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 3964 3965 if (ioctl(s6, SIOCAIFADDR_IN6, &ifra6) == -1 && errno != EEXIST) { 3966 (void)os_assumes_zero(errno); 3967 } 3968 3969 (void)close(s6); 3970} 3971 3972pid_t 3973fwexec(const char *const *argv, int *wstatus) 3974{ 3975 int wstatus2; 3976 pid_t p; 3977 3978 /* We'd use posix_spawnp(), but we want to workaround: 6288899 */ 3979 if ((p = vfork()) == -1) { 3980 return -1; 3981 } else if (p == 0) { 3982 execvp(argv[0], (char *const *)argv); 3983 _exit(EXIT_FAILURE); 3984 } 3985 3986 if (waitpid(p, wstatus ? wstatus : &wstatus2, 0) == -1) { 3987 return -1; 3988 } 3989 3990 if (wstatus) { 3991 return p; 3992 } else if (WIFEXITED(wstatus2) && WEXITSTATUS(wstatus2) == EXIT_SUCCESS) { 3993 return p; 3994 } 3995 3996 return -1; 3997} 3998 3999void 4000do_potential_fsck(void) 4001{ 4002 /* XXX: This whole function's logic needs to be redone. */ 4003 4004 const char *safe_fsck_tool[] = { "fsck", "-fy", NULL }; 4005 const char *fsck_tool[] = { "fsck", "-q", NULL }; 4006 const char *remount_tool[] = { "mount", "-uw", "/", NULL }; 4007#if TARGET_OS_EMBEDDED 4008 const char *nvram_tool[] = { "/usr/sbin/nvram", "auto-boot=false", NULL }; 4009#endif /* TARGET_OS_EMBEDDED */ 4010 struct statfs sfs; 4011 int status = 0; 4012 4013 if (posix_assumes_zero(statfs("/", &sfs)) == -1) { 4014 return; 4015 } 4016 4017 if (!(sfs.f_flags & MNT_RDONLY)) { 4018 return; 4019 } 4020 4021 if (!is_safeboot()) { 4022#if 0 4023 /* We have disabled this block for now. We need to revisit this optimization after Leopard. */ 4024 if (sfs.f_flags & MNT_JOURNALED) { 4025 goto out; 4026 } 4027#endif 4028 launchctl_log(LOG_NOTICE, "Running fsck on the boot volume..."); 4029 if (fwexec(fsck_tool, &status) != -1) { 4030 if (WEXITSTATUS(status) != 0) { 4031 launchctl_log(LOG_NOTICE, "fsck exited with status: %d", WEXITSTATUS(status)); 4032 } else { 4033 goto out; 4034 } 4035 } else { 4036 launchctl_log(LOG_NOTICE, "fwexec(): %d: %s", errno, strerror(errno)); 4037 } 4038 } 4039 4040 launchctl_log(LOG_NOTICE, "Running safe fsck on the boot volume..."); 4041 if (fwexec(safe_fsck_tool, &status) != -1) { 4042 if (WEXITSTATUS(status) != 0) { 4043 launchctl_log(LOG_NOTICE, "Safe fsck exited with status: %d", WEXITSTATUS(status)); 4044 } else { 4045 goto out; 4046 } 4047 } else { 4048 launchctl_log(LOG_NOTICE, "fwexec(): %d: %s", errno, strerror(errno)); 4049 } 4050 4051 /* someday, we should keep booting read-only, but as of today, other sub-systems cannot handle that scenario */ 4052#if TARGET_OS_EMBEDDED 4053 launchctl_log(LOG_NOTICE, "fsck failed! Booting into restore mode..."); 4054 (void)posix_assumes_zero(fwexec(nvram_tool, NULL)); 4055 (void)reboot(RB_AUTOBOOT); 4056#else 4057 launchctl_log(LOG_NOTICE, "fsck failed! Shutting down in 3 seconds."); 4058 sleep(3); 4059 (void)reboot(RB_HALT); 4060#endif 4061 4062 return; 4063out: 4064 4065#if TARGET_OS_EMBEDDED 4066 /* Once we've validated the root filesystem, kick off any 4067 * tasks needed for data protection before we mount other file 4068 * systems. 4069 */ 4070 init_data_protection(); 4071#endif 4072 4073 /* 4074 * Once this is fixed: 4075 * 4076 * <rdar://problem/3948774> Mount flag updates should be possible with NULL as the forth argument to mount() 4077 * 4078 * We can then do this one system call instead of calling out a full blown process. 4079 * 4080 * assumes(mount(sfs.f_fstypename, "/", MNT_UPDATE, NULL) != -1); 4081 */ 4082#if TARGET_OS_EMBEDDED 4083 if (path_check("/etc/fstab")) { 4084 const char *mount_tool[] = { "mount", "-vat", "nonfs", NULL }; 4085 if (posix_assumes_zero(fwexec(mount_tool, NULL)) == -1) { 4086 (void)fwexec(nvram_tool, NULL); 4087 (void)reboot(RB_AUTOBOOT); 4088 } 4089 } else 4090#endif 4091 { 4092 (void)posix_assumes_zero(fwexec(remount_tool, NULL)); 4093 } 4094 4095 fix_bogus_file_metadata(); 4096} 4097 4098void 4099fix_bogus_file_metadata(void) 4100{ 4101 // Don't do any of this on embedded: <rdar://problem/13212363> 4102#if !TARGET_OS_EMBEDDED 4103 static const struct { 4104 const char *path; 4105 const uid_t owner; 4106 const gid_t group; 4107 const mode_t needed_bits; 4108 const mode_t bad_bits; 4109 const bool create; 4110 } f[] = { 4111 { "/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 }, 4112 { _PATH_TMP, 0, 0, S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO, S_ISUID|S_ISGID, true }, 4113 { _PATH_VARTMP, 0, 0, S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO, S_ISUID|S_ISGID, true }, 4114 { "/var/folders", 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, S_ISUID | S_ISGID, true }, 4115 { LAUNCHD_DB_PREFIX, 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, S_IWGRP | S_IWOTH, true }, 4116 { LAUNCHD_DB_PREFIX "/com.apple.launchd", 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, S_IWGRP | S_IWOTH, true }, 4117 // Fixing <rdar://problem/7571633>. 4118 { _PATH_VARDB, 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, S_IWGRP | S_IWOTH | S_ISUID | S_ISGID, true }, 4119 { _PATH_VARDB "mds/", 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, S_IWGRP | S_IWOTH | S_ISUID | S_ISGID, true }, 4120 // Similar fix for <rdar://problem/6550172>. 4121 { "/Library/StartupItems", 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, S_IWGRP | S_IWOTH | S_ISUID | S_ISGID, true }, 4122 }; 4123 struct stat sb; 4124 size_t i; 4125 4126 for (i = 0; i < (sizeof(f) / sizeof(f[0])); i++) { 4127 mode_t i_needed_bits; 4128 mode_t i_bad_bits; 4129 bool fix_mode = false; 4130 bool fix_id = false; 4131 4132 if (stat(f[i].path, &sb) == -1) { 4133 launchctl_log(LOG_NOTICE, "Crucial filesystem check: Path not present: %s. %s", f[i].path, f[i].create ? "Will create." : ""); 4134 if (f[i].create) { 4135 if (posix_assumes_zero(mkdir(f[i].path, f[i].needed_bits)) == -1) { 4136 continue; 4137 } else if (posix_assumes_zero(stat(f[i].path, &sb)) == -1) { 4138 continue; 4139 } 4140 } else { 4141 continue; 4142 } 4143 } 4144 4145 i_needed_bits = ~sb.st_mode & f[i].needed_bits; 4146 i_bad_bits = sb.st_mode & f[i].bad_bits; 4147 4148 if (i_bad_bits) { 4149 launchctl_log(LOG_ERR, "Crucial filesystem check: Removing bogus mode bits 0%o on path: %s", i_bad_bits, f[i].path); 4150 fix_mode = true; 4151 } 4152 if (i_needed_bits) { 4153 launchctl_log(LOG_ERR, "Crucial filesystem check: Adding missing mode bits 0%o on path: %s", i_needed_bits, f[i].path); 4154 fix_mode = true; 4155 } 4156 if (sb.st_uid != f[i].owner) { 4157 launchctl_log(LOG_ERR, "Crucial filesystem check: Fixing bogus UID %u on path: %s", sb.st_uid, f[i].path); 4158 fix_id = true; 4159 } 4160 if (sb.st_gid != f[i].group) { 4161 launchctl_log(LOG_ERR, "Crucial filesystem check: Fixing bogus GID %u on path: %s", sb.st_gid, f[i].path); 4162 fix_id = true; 4163 } 4164 4165 if (fix_mode) { 4166 (void)posix_assumes_zero(chmod(f[i].path, (sb.st_mode & ~i_bad_bits) | i_needed_bits)); 4167 } 4168 if (fix_id) { 4169 (void)posix_assumes_zero(chown(f[i].path, f[i].owner, f[i].group)); 4170 } 4171 } 4172#endif 4173} 4174 4175 4176bool 4177path_check(const char *path) 4178{ 4179 struct stat sb; 4180 4181 if (stat(path, &sb) == 0) 4182 return true; 4183 return false; 4184} 4185 4186bool 4187is_safeboot(void) 4188{ 4189 int sbmib[] = { CTL_KERN, KERN_SAFEBOOT }; 4190 uint32_t sb = 0; 4191 size_t sbsz = sizeof(sb); 4192 4193 if (posix_assumes_zero(sysctl(sbmib, 2, &sb, &sbsz, NULL, 0)) == -1) { 4194 return false; 4195 } 4196 4197 return (bool)sb; 4198} 4199 4200bool 4201is_netboot(void) 4202{ 4203 int nbmib[] = { CTL_KERN, KERN_NETBOOT }; 4204 uint32_t nb = 0; 4205 size_t nbsz = sizeof(nb); 4206 4207 if (posix_assumes_zero(sysctl(nbmib, 2, &nb, &nbsz, NULL, 0)) == -1) { 4208 return false; 4209 } 4210 4211 return (bool)nb; 4212} 4213 4214void 4215empty_dir(const char *thedir, struct stat *psb) 4216{ 4217 struct dirent *de; 4218 struct stat psb2; 4219 DIR *od; 4220 int currend_dir_fd; 4221 4222 if (!psb) { 4223 psb = &psb2; 4224 if (posix_assumes_zero(lstat(thedir, psb)) == -1) { 4225 return; 4226 } 4227 } 4228 4229 if (posix_assumes_zero(currend_dir_fd = open(".", 0)) == -1) { 4230 return; 4231 } 4232 4233 if (posix_assumes_zero(chdir(thedir)) == -1) { 4234 goto out; 4235 } 4236 4237 if (!(od = opendir("."))) { 4238 (void)os_assumes_zero(errno); 4239 goto out; 4240 } 4241 4242 while ((de = readdir(od))) { 4243 struct stat sb; 4244 4245 if (strcmp(de->d_name, ".") == 0) { 4246 continue; 4247 } 4248 4249 if (strcmp(de->d_name, "..") == 0) { 4250 continue; 4251 } 4252 4253 if (posix_assumes_zero(lstat(de->d_name, &sb)) == -1) { 4254 continue; 4255 } 4256 4257 if (psb->st_dev != sb.st_dev) { 4258 (void)posix_assumes_zero(unmount(de->d_name, MNT_FORCE)); 4259 4260 /* Let's lstat() again to see if the unmount() worked and what was 4261 * under it. 4262 */ 4263 if (posix_assumes_zero(lstat(de->d_name, &sb)) == -1) { 4264 continue; 4265 } 4266 4267 if (os_assumes(psb->st_dev == sb.st_dev)) { 4268 continue; 4269 } 4270 } 4271 4272 if (S_ISDIR(sb.st_mode)) { 4273 empty_dir(de->d_name, &sb); 4274 } 4275 4276 (void)posix_assumes_zero(lchflags(de->d_name, 0)); 4277 (void)posix_assumes_zero(remove(de->d_name)); 4278 } 4279 4280 (void)closedir(od); 4281 4282out: 4283 (void)posix_assumes_zero(fchdir(currend_dir_fd)); 4284 (void)posix_assumes_zero(close(currend_dir_fd)); 4285} 4286 4287int 4288touch_file(const char *path, mode_t m) 4289{ 4290 int fd = open(path, O_CREAT, m); 4291 4292 if (fd == -1) 4293 return -1; 4294 4295 return close(fd); 4296} 4297 4298void 4299apply_sysctls_from_file(const char *thefile) 4300{ 4301 const char *sysctl_tool[] = { "sysctl", "-w", NULL, NULL }; 4302 size_t ln_len = 0; 4303 char *val, *tmpstr; 4304 FILE *sf; 4305 4306 if (!(sf = fopen(thefile, "r"))) 4307 return; 4308 4309 while ((val = fgetln(sf, &ln_len))) { 4310 if (ln_len == 0) { 4311 continue; 4312 } 4313 if (!(tmpstr = malloc(ln_len + 1))) { 4314 (void)os_assumes_zero(errno); 4315 continue; 4316 } 4317 memcpy(tmpstr, val, ln_len); 4318 tmpstr[ln_len] = 0; 4319 val = tmpstr; 4320 4321 if (val[ln_len - 1] == '\n' || val[ln_len - 1] == '\r') { 4322 val[ln_len - 1] = '\0'; 4323 } 4324 4325 while (*val && isspace(*val)) 4326 val++; 4327 if (*val == '\0' || *val == '#') { 4328 goto skip_sysctl_tool; 4329 } 4330 sysctl_tool[2] = val; 4331 (void)posix_assumes_zero(fwexec(sysctl_tool, NULL)); 4332skip_sysctl_tool: 4333 free(tmpstr); 4334 } 4335 4336 (void)fclose(sf); 4337} 4338 4339static CFStringRef 4340copySystemBuildVersion(void) 4341{ 4342 CFStringRef build = NULL; 4343 const char path[] = "/System/Library/CoreServices/SystemVersion.plist"; 4344 CFURLRef plistURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (const uint8_t *)path, sizeof(path) - 1, false); 4345 4346 CFPropertyListRef plist = NULL; 4347 if (plistURL && (plist = CFPropertyListCreateFromFile(plistURL))) { 4348 if (CFTypeCheck(plist, CFDictionary)) { 4349 build = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionBuildVersionKey); 4350 if (build && CFTypeCheck(build, CFString)) { 4351 CFRetain(build); 4352 } else { 4353 build = CFSTR("99Z999"); 4354 } 4355 } 4356 4357 CFRelease(plist); 4358 } else { 4359 build = CFSTR("99Z999"); 4360 } 4361 4362 if (plistURL) { 4363 CFRelease(plistURL); 4364 } 4365 4366 return build; 4367} 4368 4369void 4370do_sysversion_sysctl(void) 4371{ 4372 int mib[] = { CTL_KERN, KERN_OSVERSION }; 4373 CFStringRef buildvers; 4374 char buf[1024]; 4375 size_t bufsz = sizeof(buf); 4376 4377 /* <rdar://problem/4477682> ER: launchd should set kern.osversion very early in boot */ 4378 4379 if (sysctl(mib, 2, buf, &bufsz, NULL, 0) == -1) { 4380 launchctl_log(LOG_ERR, "sysctl(): %s", strerror(errno)); 4381 return; 4382 } 4383 4384 if (buf[0] != '\0') { 4385 return; 4386 } 4387 4388 buildvers = copySystemBuildVersion(); 4389 if (buildvers) { 4390 CFStringGetCString(buildvers, buf, sizeof(buf), kCFStringEncodingUTF8); 4391 (void)posix_assumes_zero(sysctl(mib, 2, NULL, 0, buf, strlen(buf) + 1)); 4392 } 4393 4394 CFRelease(buildvers); 4395} 4396 4397void 4398do_application_firewall_magic(int sfd, launch_data_t thejob) 4399{ 4400 const char *prog = NULL, *partialprog = NULL; 4401 char *path, *pathtmp, **pathstmp; 4402 char *paths[100]; 4403 launch_data_t tmp; 4404 4405 /* 4406 * Sigh... 4407 * <rdar://problem/4684434> setsockopt() with the executable path as the argument 4408 */ 4409 4410 if ((tmp = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_PROGRAM))) { 4411 prog = launch_data_get_string(tmp); 4412 } 4413 4414 if (!prog) { 4415 if ((tmp = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_PROGRAMARGUMENTS))) { 4416 if ((tmp = launch_data_array_get_index(tmp, 0))) { 4417 if ((partialprog = launch_data_get_string(tmp))) { 4418 if (partialprog[0] == '/') { 4419 prog = partialprog; 4420 } 4421 } 4422 } 4423 } 4424 } 4425 4426 if (!prog) { 4427 pathtmp = path = strdup(getenv("PATH")); 4428 4429 pathstmp = paths; 4430 4431 while ((*pathstmp = strsep(&pathtmp, ":"))) { 4432 if (**pathstmp != '\0') { 4433 pathstmp++; 4434 } 4435 } 4436 4437 free(path); 4438 pathtmp = alloca(MAXPATHLEN); 4439 4440 pathstmp = paths; 4441 4442 for (; *pathstmp; pathstmp++) { 4443 snprintf(pathtmp, MAXPATHLEN, "%s/%s", *pathstmp, partialprog); 4444 if (path_check(pathtmp)) { 4445 prog = pathtmp; 4446 break; 4447 } 4448 } 4449 } 4450 4451#ifndef DARLING 4452 if (prog != NULL) { 4453 /* The networking team has asked us to ignore the failure of this API if 4454 * errno == ENOPROTOOPT. 4455 */ 4456 if (setsockopt(sfd, SOL_SOCKET, SO_EXECPATH, prog, (socklen_t)(strlen(prog) + 1)) == -1 && errno != ENOPROTOOPT) { 4457 (void)os_assumes_zero(errno); 4458 } 4459 } 4460#endif // DARLING 4461} 4462 4463 4464void 4465preheat_page_cache_hack(void) 4466{ 4467 struct dirent *de; 4468 DIR *thedir; 4469 4470 /* Disable this hack for now */ 4471 return; 4472 4473 if ((thedir = opendir("/etc/preheat_at_boot")) == NULL) { 4474 return; 4475 } 4476 4477 while ((de = readdir(thedir))) { 4478 struct stat sb; 4479 void *junkbuf; 4480 int fd; 4481 4482 if (de->d_name[0] == '.') { 4483 continue; 4484 } 4485 4486 if ((fd = open(de->d_name, O_RDONLY)) == -1) { 4487 continue; 4488 } 4489 4490 if (fstat(fd, &sb) != -1) { 4491 if ((sb.st_size < 10*1024*1024) && (junkbuf = malloc((size_t)sb.st_size)) != NULL) { 4492 ssize_t n = read(fd, junkbuf, (size_t)sb.st_size); 4493 if (posix_assumes_zero(n) != -1 && n != (ssize_t)sb.st_size) { 4494 (void)os_assumes_zero(n); 4495 } 4496 free(junkbuf); 4497 } 4498 } 4499 4500 close(fd); 4501 } 4502 4503 closedir(thedir); 4504} 4505 4506void 4507do_bootroot_magic(void) 4508{ 4509#ifndef DARLING 4510 const char *kextcache_tool[] = { "kextcache", "-U", "/", NULL }; 4511 CFTypeRef bootrootProp; 4512 io_service_t chosen; 4513 int wstatus; 4514 pid_t p; 4515 4516 chosen = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/chosen"); 4517 4518 if (!os_assumes(chosen)) { 4519 return; 4520 } 4521 4522 bootrootProp = IORegistryEntryCreateCFProperty(chosen, CFSTR(kBootRootActiveKey), kCFAllocatorDefault, 0); 4523 4524 IOObjectRelease(chosen); 4525 4526 if (!bootrootProp) { 4527 return; 4528 } 4529 4530 CFRelease(bootrootProp); 4531 4532 if (posix_assumes_zero(p = fwexec(kextcache_tool, &wstatus)) == -1) { 4533 return; 4534 } 4535 4536 if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == EX_OSFILE) { 4537 (void)reboot(RB_AUTOBOOT); 4538 } 4539#endif // DARLING 4540} 4541 4542void 4543do_file_init(void) 4544{ 4545 struct stat sb; 4546 4547 if (stat("/AppleInternal", &sb) == 0 && stat("/var/db/disableAppleInternal", &sb) == -1) { 4548 _launchctl_apple_internal = true; 4549 } 4550 4551 char bootargs[128]; 4552 size_t len = sizeof(bootargs); 4553 int r = sysctlbyname("kern.bootargs", bootargs, &len, NULL, 0); 4554 if (r == 0 && (strnstr(bootargs, "-v", len) != NULL || strnstr(bootargs, "-s", len))) { 4555 _launchctl_verbose_boot = true; 4556 } 4557 4558 if (stat("/var/db/.launchd_shutdown_debugging", &sb) == 0 && _launchctl_verbose_boot) { 4559 _launchctl_startup_debugging = true; 4560 } 4561}