2  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_APACHE_LICENSE_HEADER_START@ 
   6  * Licensed under the Apache License, Version 2.0 (the "License"); 
   7  * you may not use this file except in compliance with the License. 
   8  * You may obtain a copy of the License at 
  10  *     http://www.apache.org/licenses/LICENSE-2.0 
  12  * Unless required by applicable law or agreed to in writing, software 
  13  * distributed under the License is distributed on an "AS IS" BASIS, 
  14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  15  * See the License for the specific language governing permissions and 
  16  * limitations under the License. 
  18  * @APPLE_APACHE_LICENSE_HEADER_END@ 
  21 static const char *const __rcs_file_version__ 
= "$Revision: 23457 $"; 
  23 #include "liblaunch_public.h" 
  24 #include "liblaunch_private.h" 
  25 #include "libbootstrap_public.h" 
  26 #include "libvproc_public.h" 
  27 #include "libvproc_private.h" 
  28 #include "libvproc_internal.h" 
  30 #include <CoreFoundation/CoreFoundation.h> 
  31 #include <CoreFoundation/CFPriv.h> 
  32 #include <TargetConditionals.h> 
  33 #if !TARGET_OS_EMBEDDED 
  34 #include <Security/Security.h> 
  35 #include <Security/AuthSession.h> 
  37 #include <IOKit/IOKitLib.h> 
  38 #include <NSSystemDirectories.h> 
  39 #include <mach/mach.h> 
  40 #include <sys/types.h> 
  41 #include <sys/sysctl.h> 
  43 #include <sys/sysctl.h> 
  45 #include <sys/socket.h> 
  47 #include <sys/fcntl.h> 
  48 #include <sys/event.h> 
  49 #include <sys/resource.h> 
  50 #include <sys/param.h> 
  51 #include <sys/mount.h> 
  52 #include <sys/reboot.h> 
  54 #include <netinet/in.h> 
  55 #include <netinet/in_var.h> 
  56 #include <netinet6/nd6.h> 
  68 #include <readline/readline.h> 
  69 #include <readline/history.h> 
  74 #include <bootfiles.h> 
  79 #define LAUNCH_SECDIR "/tmp/launch-XXXXXX" 
  81 #define MACHINIT_JOBKEY_ONDEMAND        "OnDemand" 
  82 #define MACHINIT_JOBKEY_SERVICENAME     "ServiceName" 
  83 #define MACHINIT_JOBKEY_COMMAND         "Command" 
  84 #define MACHINIT_JOBKEY_SERVERPORT      "ServerPort" 
  85 #define MACHINIT_JOBKEY_SERVICEPORT     "ServicePort" 
  88         (__builtin_expect(!(e), 0) ? _log_launchctl_bug(__rcs_file_version__, __FILE__, __LINE__, #e), false : true) 
  91 struct load_unload_state 
{ 
  96         unsigned int editondisk
:1, load
:1, forceload
:1, __pad
:29; 
  99 static void myCFDictionaryApplyFunction(const void *key
, const void *value
, void *context
); 
 100 static bool launch_data_array_append(launch_data_t a
, launch_data_t o
); 
 101 static void distill_jobs(launch_data_t
); 
 102 static void distill_config_file(launch_data_t
); 
 103 static void sock_dict_cb(launch_data_t what
, const char *key
, void *context
); 
 104 static void sock_dict_edit_entry(launch_data_t tmp
, const char *key
, launch_data_t fdarray
, launch_data_t thejob
); 
 105 static launch_data_t 
CF2launch_data(CFTypeRef
); 
 106 static launch_data_t 
read_plist_file(const char *file
, bool editondisk
, bool load
); 
 107 static CFPropertyListRef 
CreateMyPropertyListFromFile(const char *); 
 108 static void WriteMyPropertyListToFile(CFPropertyListRef
, const char *); 
 109 static bool path_goodness_check(const char *path
, bool forceload
); 
 110 static void readpath(const char *, struct load_unload_state 
*); 
 111 static void readfile(const char *, struct load_unload_state 
*); 
 113 static int demux_cmd(int argc
, char *const argv
[]); 
 114 static launch_data_t 
do_rendezvous_magic(const struct addrinfo 
*res
, const char *serv
); 
 115 static void submit_job_pass(launch_data_t jobs
); 
 116 static void submit_mach_jobs(launch_data_t jobs
); 
 117 static void let_go_of_mach_jobs(launch_data_t jobs
); 
 118 static void do_mgroup_join(int fd
, int family
, int socktype
, int protocol
, const char *mgroup
); 
 119 static mach_port_t 
str2bsport(const char *s
); 
 120 static void print_jobs(launch_data_t j
, const char *key
, void *context
); 
 121 static void print_obj(launch_data_t obj
, const char *key
, void *context
); 
 122 static bool is_legacy_mach_job(launch_data_t obj
); 
 123 static bool delay_to_second_pass(launch_data_t o
); 
 124 static void delay_to_second_pass2(launch_data_t o
, const char *key
, void *context
); 
 125 static bool str2lim(const char *buf
, rlim_t 
*res
); 
 126 static const char *lim2str(rlim_t val
, char *buf
); 
 127 static const char *num2name(int n
); 
 128 static ssize_t 
name2num(const char *n
); 
 129 static void unloadjob(launch_data_t job
); 
 130 static void print_key_value(launch_data_t obj
, const char *key
, void *context
); 
 131 static void print_launchd_env(launch_data_t obj
, const char *key
, void *context
); 
 132 static void _log_launchctl_bug(const char *rcs_rev
, const char *path
, unsigned int line
, const char *test
); 
 133 static void loopback_setup_ipv4(void); 
 134 static void loopback_setup_ipv6(void); 
 135 static pid_t 
fwexec(const char *const *argv
, bool _wait
); 
 136 static void do_potential_fsck(void); 
 137 static bool path_check(const char *path
); 
 138 static bool is_safeboot(void); 
 139 static bool is_netboot(void); 
 140 static void apply_sysctls_from_file(const char *thefile
); 
 141 static void empty_dir(const char *thedir
, struct stat 
*psb
); 
 142 static int touch_file(const char *path
, mode_t m
); 
 143 static void do_sysversion_sysctl(void); 
 144 static void do_application_firewall_magic(int sfd
, launch_data_t thejob
); 
 145 static void preheat_page_cache_hack(void); 
 146 static void do_bootroot_magic(void); 
 147 static void do_single_user_mode(bool); 
 148 static bool do_single_user_mode2(void); 
 149 static void read_launchd_conf(void); 
 150 static bool job_disabled_logic(launch_data_t obj
); 
 151 static void fix_bogus_file_metadata(void); 
 157 } BootCache_action_t
; 
 159 static void do_BootCache_magic(BootCache_action_t what
); 
 161 static int bootstrap_cmd(int argc
, char *const argv
[]); 
 162 static int load_and_unload_cmd(int argc
, char *const argv
[]); 
 163 //static int reload_cmd(int argc, char *const argv[]); 
 164 static int start_stop_remove_cmd(int argc
, char *const argv
[]); 
 165 static int submit_cmd(int argc
, char *const argv
[]); 
 166 static int list_cmd(int argc
, char *const argv
[]); 
 168 static int setenv_cmd(int argc
, char *const argv
[]); 
 169 static int unsetenv_cmd(int argc
, char *const argv
[]); 
 170 static int getenv_and_export_cmd(int argc
, char *const argv
[]); 
 172 static int limit_cmd(int argc
, char *const argv
[]); 
 173 static int stdio_cmd(int argc
, char *const argv
[]); 
 174 static int fyi_cmd(int argc
, char *const argv
[]); 
 175 static int logupdate_cmd(int argc
, char *const argv
[]); 
 176 static int umask_cmd(int argc
, char *const argv
[]); 
 177 static int getrusage_cmd(int argc
, char *const argv
[]); 
 178 static int bsexec_cmd(int argc
, char *const argv
[]); 
 179 static int bslist_cmd(int argc
, char *const argv
[]); 
 181 static int exit_cmd(int argc
, char *const argv
[]) __attribute__((noreturn
)); 
 182 static int help_cmd(int argc
, char *const argv
[]); 
 184 static const struct { 
 186         int (*func
)(int argc
, char *const argv
[]); 
 189         { "load",       load_and_unload_cmd
,    "Load configuration files and/or directories" }, 
 190         { "unload",     load_and_unload_cmd
,    "Unload configuration files and/or directories" }, 
 191 //      { "reload",     reload_cmd,             "Reload configuration files and/or directories" }, 
 192         { "start",      start_stop_remove_cmd
,  "Start specified job" }, 
 193         { "stop",       start_stop_remove_cmd
,  "Stop specified job" }, 
 194         { "submit",     submit_cmd
,             "Submit a job from the command line" }, 
 195         { "remove",     start_stop_remove_cmd
,  "Remove specified job" }, 
 196         { "bootstrap",  bootstrap_cmd
,          "Bootstrap launchd" }, 
 197         { "list",       list_cmd
,               "List jobs and information about jobs" }, 
 198         { "setenv",     setenv_cmd
,             "Set an environmental variable in launchd" }, 
 199         { "unsetenv",   unsetenv_cmd
,           "Unset an environmental variable in launchd" }, 
 200         { "getenv",     getenv_and_export_cmd
,  "Get an environmental variable from launchd" }, 
 201         { "export",     getenv_and_export_cmd
,  "Export shell settings from launchd" }, 
 202         { "limit",      limit_cmd
,              "View and adjust launchd resource limits" }, 
 203         { "stdout",     stdio_cmd
,              "Redirect launchd's standard out to the given path" }, 
 204         { "stderr",     stdio_cmd
,              "Redirect launchd's standard error to the given path" }, 
 205         { "shutdown",   fyi_cmd
,                "Prepare for system shutdown" }, 
 206         { "singleuser", fyi_cmd
,                "Switch to single-user mode" }, 
 207         { "getrusage",  getrusage_cmd
,          "Get resource usage statistics from launchd" }, 
 208         { "log",        logupdate_cmd
,          "Adjust the logging level or mask of launchd" }, 
 209         { "umask",      umask_cmd
,              "Change launchd's umask" }, 
 210         { "bsexec",     bsexec_cmd
,             "Execute a process within a different Mach bootstrap subset" }, 
 211         { "bslist",     bslist_cmd
,             "List Mach bootstrap services and optional servers" }, 
 212         { "exit",       exit_cmd
,               "Exit the interactive invocation of launchctl" }, 
 213         { "quit",       exit_cmd
,               "Quit the interactive invocation of launchctl" }, 
 214         { "help",       help_cmd
,               "This help output" }, 
 219 static bool is_managed
; 
 222 main(int argc
, char *const argv
[]) 
 224         int64_t is_managed_val 
= 0; 
 227         if (vproc_swap_integer(NULL
, VPROC_GSK_IS_MANAGED
, NULL
, &is_managed_val
) == NULL 
&& is_managed_val
) { 
 231         if (getuid() == 0 && !is_managed
) { 
 232                 mach_port_t root_bs 
= str2bsport("/"); 
 233                 task_set_bootstrap_port(mach_task_self(), root_bs
); 
 234                 mach_port_deallocate(mach_task_self(), bootstrap_port
); 
 235                 bootstrap_port 
= root_bs
; 
 238         istty 
= isatty(STDIN_FILENO
); 
 242         if (argc 
> 0 && argv
[0][0] == '-') { 
 245                 for (flago 
= argv
[0] + 1; *flago
; flago
++) { 
 251                                 fprintf(stderr
, "Unknown argument: '-%c'\n", *flago
); 
 258         if (NULL 
== readline
) { 
 259                 fprintf(stderr
, "missing library: readline\n"); 
 264                 while ((l 
= readline(istty 
? "launchd% " : NULL
))) { 
 265                         char *inputstring 
= l
, *argv2
[100], **ap 
= argv2
; 
 268                         while ((*ap 
= strsep(&inputstring
, " \t"))) { 
 288                 exit(demux_cmd(argc
, argv
)); 
 295 demux_cmd(int argc
, char *const argv
[]) 
 302         for (i 
= 0; i 
< (sizeof cmds 
/ sizeof cmds
[0]); i
++) { 
 303                 if (!strcmp(cmds
[i
].name
, argv
[0])) { 
 304                         return cmds
[i
].func(argc
, argv
); 
 308         fprintf(stderr
, "%s: unknown subcommand \"%s\"\n", getprogname(), argv
[0]); 
 313 read_launchd_conf(void) 
 315         char s
[1000], *c
, *av
[100]; 
 319         if (!(f 
= fopen("/etc/launchd.conf", "r"))) { 
 323         while ((c 
= fgets(s
, sizeof(s
), f
))) { 
 325                 if (len 
&& c
[len 
- 1] == '\n') { 
 331                 while ((av
[i
] = strsep(&c
, " \t"))) { 
 332                         if (*(av
[i
]) != '\0') { 
 346 unsetenv_cmd(int argc
, char *const argv
[]) 
 348         launch_data_t resp
, tmp
, msg
; 
 351                 fprintf(stderr
, "%s usage: unsetenv <key>\n", getprogname()); 
 355         msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
 357         tmp 
= launch_data_new_string(argv
[1]); 
 358         launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_UNSETUSERENVIRONMENT
); 
 360         resp 
= launch_msg(msg
); 
 362         launch_data_free(msg
); 
 365                 launch_data_free(resp
); 
 367                 fprintf(stderr
, "launch_msg(\"%s\"): %s\n", LAUNCH_KEY_UNSETUSERENVIRONMENT
, strerror(errno
)); 
 374 setenv_cmd(int argc
, char *const argv
[]) 
 376         launch_data_t resp
, tmp
, tmpv
, msg
; 
 379                 fprintf(stderr
, "%s usage: setenv <key> <value>\n", getprogname()); 
 383         msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
 384         tmp 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
 386         tmpv 
= launch_data_new_string(argv
[2]); 
 387         launch_data_dict_insert(tmp
, tmpv
, argv
[1]); 
 388         launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_SETUSERENVIRONMENT
); 
 390         resp 
= launch_msg(msg
); 
 391         launch_data_free(msg
); 
 394                 launch_data_free(resp
); 
 396                 fprintf(stderr
, "launch_msg(\"%s\"): %s\n", LAUNCH_KEY_SETUSERENVIRONMENT
, strerror(errno
)); 
 403 print_launchd_env(launch_data_t obj
, const char *key
, void *context
) 
 405         bool *is_csh 
= context
; 
 407         /* XXX escape the double quotes */ 
 409                 fprintf(stdout
, "setenv %s \"%s\";\n", key
, launch_data_get_string(obj
)); 
 411                 fprintf(stdout
, "%s=\"%s\"; export %s;\n", key
, launch_data_get_string(obj
), key
); 
 416 print_key_value(launch_data_t obj
, const char *key
, void *context
) 
 418         const char *k 
= context
; 
 420         if (!strcmp(key
, k
)) { 
 421                 fprintf(stdout
, "%s\n", launch_data_get_string(obj
)); 
 426 getenv_and_export_cmd(int argc
, char *const argv
[]) 
 432         if (!strcmp(argv
[0], "export")) { 
 433                 char *s 
= getenv("SHELL"); 
 435                         is_csh 
= strstr(s
, "csh") ? true : false; 
 437         } else if (argc 
!= 2) { 
 438                 fprintf(stderr
, "%s usage: getenv <key>\n", getprogname()); 
 444         if (vproc_swap_complex(NULL
, VPROC_GSK_ENVIRONMENT
, NULL
, &resp
) == NULL
) { 
 445                 if (!strcmp(argv
[0], "export")) { 
 446                         launch_data_dict_iterate(resp
, print_launchd_env
, &is_csh
); 
 448                         launch_data_dict_iterate(resp
, print_key_value
, k
); 
 450                 launch_data_free(resp
); 
 460 unloadjob(launch_data_t job
) 
 464         tmps 
= launch_data_dict_lookup(job
, LAUNCH_JOBKEY_LABEL
); 
 467                 fprintf(stderr
, "%s: Error: Missing Key: %s\n", getprogname(), LAUNCH_JOBKEY_LABEL
); 
 471         if (_vproc_send_signal_by_label(launch_data_get_string(tmps
), VPROC_MAGIC_UNLOAD_SIGNAL
) != NULL
) { 
 472                 fprintf(stderr
, "%s: Error unloading: %s\n", getprogname(), launch_data_get_string(tmps
)); 
 477 read_plist_file(const char *file
, bool editondisk
, bool load
) 
 479         CFPropertyListRef plist 
= CreateMyPropertyListFromFile(file
); 
 480         launch_data_t r 
= NULL
; 
 483                 fprintf(stderr
, "%s: no plist was returned for: %s\n", getprogname(), file
); 
 489                         CFDictionaryRemoveValue((CFMutableDictionaryRef
)plist
, CFSTR(LAUNCH_JOBKEY_DISABLED
)); 
 491                         CFDictionarySetValue((CFMutableDictionaryRef
)plist
, CFSTR(LAUNCH_JOBKEY_DISABLED
), kCFBooleanTrue
); 
 493                 WriteMyPropertyListToFile(plist
, file
); 
 496         r 
= CF2launch_data(plist
); 
 504 delay_to_second_pass2(launch_data_t o
, const char *key
, void *context
) 
 509         if (key 
&& 0 == strcmp(key
, LAUNCH_JOBSOCKETKEY_BONJOUR
)) { 
 514         switch (launch_data_get_type(o
)) { 
 515         case LAUNCH_DATA_DICTIONARY
: 
 516                 launch_data_dict_iterate(o
, delay_to_second_pass2
, context
); 
 518         case LAUNCH_DATA_ARRAY
: 
 519                 for (i 
= 0; i 
< launch_data_array_get_count(o
); i
++) { 
 520                         delay_to_second_pass2(launch_data_array_get_index(o
, i
), NULL
, context
); 
 529 delay_to_second_pass(launch_data_t o
) 
 533         launch_data_t socks 
= launch_data_dict_lookup(o
, LAUNCH_JOBKEY_SOCKETS
); 
 539         delay_to_second_pass2(socks
, NULL
, &res
); 
 545 readfile(const char *what
, struct load_unload_state 
*lus
) 
 547         char ourhostname
[1024]; 
 548         launch_data_t tmpd
, tmps
, thejob
, tmpa
; 
 549         bool job_disabled 
= false; 
 552         gethostname(ourhostname
, sizeof(ourhostname
)); 
 554         if (NULL 
== (thejob 
= read_plist_file(what
, lus
->editondisk
, lus
->load
))) { 
 555                 fprintf(stderr
, "%s: no plist was returned for: %s\n", getprogname(), what
); 
 559         if (is_legacy_mach_job(thejob
)) { 
 560                 fprintf(stderr
, "%s: Please convert the following to launchd: %s\n", getprogname(), what
); 
 561                 launch_data_array_append(lus
->pass0
, thejob
); 
 565         if (NULL 
== launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LABEL
)) { 
 566                 fprintf(stderr
, "%s: missing the Label key: %s\n", getprogname(), what
); 
 570         if (NULL 
!= (tmpa 
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LIMITLOADFROMHOSTS
))) { 
 571                 c 
= launch_data_array_get_count(tmpa
); 
 573                 for (i 
= 0; i 
< c
; i
++) { 
 574                         launch_data_t oai 
= launch_data_array_get_index(tmpa
, i
); 
 575                         if (!strcasecmp(ourhostname
, launch_data_get_string(oai
))) { 
 581         if (NULL 
!= (tmpa 
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LIMITLOADTOHOSTS
))) { 
 582                 c 
= launch_data_array_get_count(tmpa
); 
 584                 for (i 
= 0; i 
< c
; i
++) { 
 585                         launch_data_t oai 
= launch_data_array_get_index(tmpa
, i
); 
 586                         if (!strcasecmp(ourhostname
, launch_data_get_string(oai
))) { 
 596         if (lus
->session_type 
&& !(tmpa 
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE
))) { 
 597                 tmpa 
= launch_data_new_string("Aqua"); 
 598                 launch_data_dict_insert(thejob
, tmpa
, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE
); 
 601         if ((tmpa 
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE
))) { 
 602                 const char *allowed_session
; 
 605                 if (lus
->session_type
) switch (launch_data_get_type(tmpa
)) { 
 606                 case LAUNCH_DATA_ARRAY
: 
 607                         c 
= launch_data_array_get_count(tmpa
); 
 608                         for (i 
= 0; i 
< c
; i
++) { 
 609                                 tmps 
= launch_data_array_get_index(tmpa
, i
); 
 610                                 allowed_session 
= launch_data_get_string(tmps
); 
 611                                 if (strcasecmp(lus
->session_type
, allowed_session
) == 0) { 
 613                                         /* we have to do the following so job_reparent_hack() works within launchd */ 
 614                                         tmpa 
= launch_data_new_string(lus
->session_type
); 
 615                                         launch_data_dict_insert(thejob
, tmpa
, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE
); 
 620                 case LAUNCH_DATA_STRING
: 
 621                         allowed_session 
= launch_data_get_string(tmpa
); 
 622                         if (strcasecmp(lus
->session_type
, allowed_session
) == 0) { 
 635         if ((tmpd 
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_DISABLED
))) { 
 636                 job_disabled 
= job_disabled_logic(tmpd
); 
 639         if (lus
->forceload
) { 
 640                 job_disabled 
= false; 
 643         if (job_disabled 
&& lus
->load
) { 
 647         if (delay_to_second_pass(thejob
)) { 
 648                 launch_data_array_append(lus
->pass2
, thejob
); 
 650                 launch_data_array_append(lus
->pass1
, thejob
); 
 654                 fprintf(stdout
, "Will load: %s\n", what
); 
 660                 fprintf(stdout
, "Ignored: %s\n", what
); 
 662         launch_data_free(thejob
); 
 666 sysctl_hw_streq(int mib_slot
, const char *str
) 
 669         size_t bufsz 
= sizeof(buf
); 
 670         int mib
[] = { CTL_HW
, mib_slot 
}; 
 672         if (sysctl(mib
, 2, buf
, &bufsz
, NULL
, 0) != -1) { 
 673                 if (strcmp(buf
, str
) == 0) { 
 682 job_disabled_dict_logic(launch_data_t obj
, const char *key
, void *context
) 
 686         if (launch_data_get_type(obj
) != LAUNCH_DATA_STRING
) { 
 690         if (strcasecmp(key
, LAUNCH_JOBKEY_DISABLED_MACHINETYPE
) == 0) { 
 691                 if (sysctl_hw_streq(HW_MACHINE
, launch_data_get_string(obj
))) { 
 694         } else if (strcasecmp(key
, LAUNCH_JOBKEY_DISABLED_MODELNAME
) == 0) { 
 695                 if (sysctl_hw_streq(HW_MODEL
, launch_data_get_string(obj
))) { 
 702 job_disabled_logic(launch_data_t obj
) 
 706         switch (launch_data_get_type(obj
)) { 
 707         case LAUNCH_DATA_DICTIONARY
: 
 708                 launch_data_dict_iterate(obj
, job_disabled_dict_logic
, &r
); 
 710         case LAUNCH_DATA_BOOL
: 
 711                 r 
= launch_data_get_bool(obj
); 
 721 path_goodness_check(const char *path
, bool forceload
) 
 725         if (stat(path
, &sb
) == -1) { 
 726                 fprintf(stderr
, "%s: Couldn't stat(\"%s\"): %s\n", getprogname(), path
, strerror(errno
)); 
 734         if (sb
.st_mode 
& (S_IWOTH
|S_IWGRP
)) { 
 735                 fprintf(stderr
, "%s: Dubious permissions on file (skipping): %s\n", getprogname(), path
); 
 739         if (sb
.st_uid 
!= 0 && sb
.st_uid 
!= getuid()) { 
 740                 fprintf(stderr
, "%s: Dubious ownership on file (skipping): %s\n", getprogname(), path
); 
 744         if (!(S_ISREG(sb
.st_mode
) || S_ISDIR(sb
.st_mode
))) { 
 745                 fprintf(stderr
, "%s: Dubious path. Not a regular file or directory (skipping): %s\n", getprogname(), path
); 
 753 readpath(const char *what
, struct load_unload_state 
*lus
) 
 755         char buf
[MAXPATHLEN
]; 
 760         if (!path_goodness_check(what
, lus
->forceload
)) { 
 764         if (stat(what
, &sb
) == -1) { 
 768         if (S_ISREG(sb
.st_mode
)) { 
 770         } else if (S_ISDIR(sb
.st_mode
)) { 
 771                 if ((d 
= opendir(what
)) == NULL
) { 
 772                         fprintf(stderr
, "%s: opendir() failed to open the directory\n", getprogname()); 
 776                 while ((de 
= readdir(d
))) { 
 777                         if ((de
->d_name
[0] == '.')) { 
 780                         snprintf(buf
, sizeof(buf
), "%s/%s", what
, de
->d_name
); 
 782                         if (!path_goodness_check(buf
, lus
->forceload
)) { 
 792 struct distill_context 
{ 
 794         launch_data_t newsockdict
; 
 798 distill_jobs(launch_data_t jobs
) 
 800         size_t i
, c 
= launch_data_array_get_count(jobs
); 
 802         for (i 
= 0; i 
< c
; i
++) 
 803                 distill_config_file(launch_data_array_get_index(jobs
, i
)); 
 807 distill_config_file(launch_data_t id_plist
) 
 809         struct distill_context dc 
= { id_plist
, NULL 
}; 
 812         if ((tmp 
= launch_data_dict_lookup(dc
.base
, LAUNCH_JOBKEY_SOCKETS
))) { 
 813                 dc
.newsockdict 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
 814                 launch_data_dict_iterate(tmp
, sock_dict_cb
, &dc
); 
 815                 launch_data_dict_insert(dc
.base
, dc
.newsockdict
, LAUNCH_JOBKEY_SOCKETS
); 
 820 sock_dict_cb(launch_data_t what
, const char *key
, void *context
) 
 822         struct distill_context 
*dc 
= context
; 
 823         launch_data_t fdarray 
= launch_data_alloc(LAUNCH_DATA_ARRAY
); 
 825         launch_data_dict_insert(dc
->newsockdict
, fdarray
, key
); 
 827         if (launch_data_get_type(what
) == LAUNCH_DATA_DICTIONARY
) { 
 828                 sock_dict_edit_entry(what
, key
, fdarray
, dc
->base
); 
 829         } else if (launch_data_get_type(what
) == LAUNCH_DATA_ARRAY
) { 
 833                 for (i 
= 0; i 
< launch_data_array_get_count(what
); i
++) { 
 834                         tmp 
= launch_data_array_get_index(what
, i
); 
 835                         sock_dict_edit_entry(tmp
, key
, fdarray
, dc
->base
); 
 841 sock_dict_edit_entry(launch_data_t tmp
, const char *key
, launch_data_t fdarray
, launch_data_t thejob
) 
 843         launch_data_t a
, val
; 
 844         int sfd
, st 
= SOCK_STREAM
; 
 847         if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_TYPE
))) { 
 848                 if (!strcasecmp(launch_data_get_string(val
), "stream")) { 
 850                 } else if (!strcasecmp(launch_data_get_string(val
), "dgram")) { 
 852                 } else if (!strcasecmp(launch_data_get_string(val
), "seqpacket")) { 
 857         if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_PASSIVE
))) { 
 858                 passive 
= launch_data_get_bool(val
); 
 861         if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_SECUREWITHKEY
))) { 
 862                 char secdir
[] = LAUNCH_SECDIR
, buf
[1024]; 
 863                 launch_data_t uenv 
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES
); 
 866                         uenv 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
 867                         launch_data_dict_insert(thejob
, uenv
, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES
); 
 872                 sprintf(buf
, "%s/%s", secdir
, key
); 
 874                 a 
= launch_data_new_string(buf
); 
 875                 launch_data_dict_insert(tmp
, a
, LAUNCH_JOBSOCKETKEY_PATHNAME
); 
 876                 a 
= launch_data_new_string(buf
); 
 877                 launch_data_dict_insert(uenv
, a
, launch_data_get_string(val
)); 
 880         if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_PATHNAME
))) { 
 881                 struct sockaddr_un sun
; 
 886                 memset(&sun
, 0, sizeof(sun
)); 
 888                 sun
.sun_family 
= AF_UNIX
; 
 890                 strncpy(sun
.sun_path
, launch_data_get_string(val
), sizeof(sun
.sun_path
)); 
 892                 if ((sfd 
= _fd(socket(AF_UNIX
, st
, 0))) == -1) { 
 896                 if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_PATHMODE
))) { 
 897                         sun_mode 
= (mode_t
)launch_data_get_integer(val
); 
 902                         if (unlink(sun
.sun_path
) == -1 && errno 
!= ENOENT
) { 
 906                         oldmask 
= umask(S_IRWXG
|S_IRWXO
); 
 907                         if (bind(sfd
, (struct sockaddr 
*)&sun
, sizeof(sun
)) == -1) { 
 914                                 chmod(sun
.sun_path
, sun_mode
); 
 916                         if ((st 
== SOCK_STREAM 
|| st 
== SOCK_SEQPACKET
) && listen(sfd
, SOMAXCONN
) == -1) { 
 920                 } else if (connect(sfd
, (struct sockaddr 
*)&sun
, sizeof(sun
)) == -1) { 
 925                 val 
= launch_data_new_fd(sfd
); 
 926                 launch_data_array_append(fdarray
, val
); 
 928                 launch_data_t rnames 
= NULL
; 
 929                 const char *node 
= NULL
, *serv 
= NULL
, *mgroup 
= NULL
; 
 931                 struct addrinfo hints
, *res0
, *res
; 
 932                 int gerr
, sock_opt 
= 1; 
 933                 bool rendezvous 
= false; 
 935                 memset(&hints
, 0, sizeof(hints
)); 
 937                 hints
.ai_socktype 
= st
; 
 939                         hints
.ai_flags 
|= AI_PASSIVE
; 
 942                 if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_NODENAME
))) { 
 943                         node 
= launch_data_get_string(val
); 
 945                 if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_MULTICASTGROUP
))) { 
 946                         mgroup 
= launch_data_get_string(val
); 
 948                 if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_SERVICENAME
))) { 
 949                         if (LAUNCH_DATA_INTEGER 
== launch_data_get_type(val
)) { 
 950                                 sprintf(servnbuf
, "%lld", launch_data_get_integer(val
)); 
 953                                 serv 
= launch_data_get_string(val
); 
 956                 if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_FAMILY
))) { 
 957                         if (!strcasecmp("IPv4", launch_data_get_string(val
))) { 
 958                                 hints
.ai_family 
= AF_INET
; 
 959                         } else if (!strcasecmp("IPv6", launch_data_get_string(val
))) { 
 960                                 hints
.ai_family 
= AF_INET6
; 
 963                 if ((val 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_PROTOCOL
))) { 
 964                         if (!strcasecmp("TCP", launch_data_get_string(val
))) { 
 965                                 hints
.ai_protocol 
= IPPROTO_TCP
; 
 966                         } else if (!strcasecmp("UDP", launch_data_get_string(val
))) { 
 967                                 hints
.ai_protocol 
= IPPROTO_UDP
; 
 970                 if ((rnames 
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_BONJOUR
))) { 
 972                         if (LAUNCH_DATA_BOOL 
== launch_data_get_type(rnames
)) { 
 973                                 rendezvous 
= launch_data_get_bool(rnames
); 
 978                 if ((gerr 
= getaddrinfo(node
, serv
, &hints
, &res0
)) != 0) { 
 979                         fprintf(stderr
, "getaddrinfo(): %s\n", gai_strerror(gerr
)); 
 983                 for (res 
= res0
; res
; res 
= res
->ai_next
) { 
 984                         launch_data_t rvs_fd 
= NULL
; 
 985                         if ((sfd 
= _fd(socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
))) == -1) { 
 986                                 fprintf(stderr
, "socket(): %s\n", strerror(errno
)); 
 990                         do_application_firewall_magic(sfd
, thejob
); 
 992                         if (hints
.ai_flags 
& AI_PASSIVE
) { 
 993                                 if (AF_INET6 
== res
->ai_family 
&& -1 == setsockopt(sfd
, IPPROTO_IPV6
, IPV6_V6ONLY
, 
 994                                                         (void *)&sock_opt
, sizeof(sock_opt
))) { 
 995                                         fprintf(stderr
, "setsockopt(IPV6_V6ONLY): %m"); 
 999                                         if (setsockopt(sfd
, SOL_SOCKET
, SO_REUSEPORT
, (void *)&sock_opt
, sizeof(sock_opt
)) == -1) { 
1000                                                 fprintf(stderr
, "setsockopt(SO_REUSEPORT): %s\n", strerror(errno
)); 
1004                                         if (setsockopt(sfd
, SOL_SOCKET
, SO_REUSEADDR
, (void *)&sock_opt
, sizeof(sock_opt
)) == -1) { 
1005                                                 fprintf(stderr
, "setsockopt(SO_REUSEADDR): %s\n", strerror(errno
)); 
1009                                 if (bind(sfd
, res
->ai_addr
, res
->ai_addrlen
) == -1) { 
1010                                         fprintf(stderr
, "bind(): %s\n", strerror(errno
)); 
1013                                 /* The kernel may have dynamically assigned some part of the 
1014                                  * address. (The port being a common example.) 
1016                                 if (getsockname(sfd
, res
->ai_addr
, &res
->ai_addrlen
) == -1) { 
1017                                         fprintf(stderr
, "getsockname(): %s\n", strerror(errno
)); 
1022                                         do_mgroup_join(sfd
, res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
, mgroup
); 
1024                                 if ((res
->ai_socktype 
== SOCK_STREAM 
|| res
->ai_socktype 
== SOCK_SEQPACKET
) && listen(sfd
, SOMAXCONN
) == -1) { 
1025                                         fprintf(stderr
, "listen(): %s\n", strerror(errno
)); 
1028                                 if (rendezvous 
&& (res
->ai_family 
== AF_INET 
|| res
->ai_family 
== AF_INET6
) && 
1029                                                 (res
->ai_socktype 
== SOCK_STREAM 
|| res
->ai_socktype 
== SOCK_DGRAM
)) { 
1030                                         launch_data_t rvs_fds 
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_BONJOURFDS
); 
1031                                         if (NULL 
== rvs_fds
) { 
1032                                                 rvs_fds 
= launch_data_alloc(LAUNCH_DATA_ARRAY
); 
1033                                                 launch_data_dict_insert(thejob
, rvs_fds
, LAUNCH_JOBKEY_BONJOURFDS
); 
1035                                         if (NULL 
== rnames
) { 
1036                                                 rvs_fd 
= do_rendezvous_magic(res
, serv
); 
1038                                                         launch_data_array_append(rvs_fds
, rvs_fd
); 
1040                                         } else if (LAUNCH_DATA_STRING 
== launch_data_get_type(rnames
)) { 
1041                                                 rvs_fd 
= do_rendezvous_magic(res
, launch_data_get_string(rnames
)); 
1043                                                         launch_data_array_append(rvs_fds
, rvs_fd
); 
1045                                         } else if (LAUNCH_DATA_ARRAY 
== launch_data_get_type(rnames
)) { 
1046                                                 size_t rn_i
, rn_ac 
= launch_data_array_get_count(rnames
); 
1048                                                 for (rn_i 
= 0; rn_i 
< rn_ac
; rn_i
++) { 
1049                                                         launch_data_t rn_tmp 
= launch_data_array_get_index(rnames
, rn_i
); 
1051                                                         rvs_fd 
= do_rendezvous_magic(res
, launch_data_get_string(rn_tmp
)); 
1053                                                                 launch_data_array_append(rvs_fds
, rvs_fd
); 
1059                                 if (connect(sfd
, res
->ai_addr
, res
->ai_addrlen
) == -1) { 
1060                                         fprintf(stderr
, "connect(): %s\n", strerror(errno
)); 
1064                         val 
= launch_data_new_fd(sfd
); 
1066                                 /* <rdar://problem/3964648> Launchd should not register the same service more than once */ 
1067                                 /* <rdar://problem/3965154> Switch to DNSServiceRegisterAddrInfo() */ 
1070                         launch_data_array_append(fdarray
, val
); 
1076 do_mgroup_join(int fd
, int family
, int socktype
, int protocol
, const char *mgroup
) 
1078         struct addrinfo hints
, *res0
, *res
; 
1079         struct ip_mreq mreq
; 
1080         struct ipv6_mreq m6req
; 
1083         memset(&hints
, 0, sizeof(hints
)); 
1085         hints
.ai_flags 
|= AI_PASSIVE
; 
1086         hints
.ai_family 
= family
; 
1087         hints
.ai_socktype 
= socktype
; 
1088         hints
.ai_protocol 
= protocol
; 
1090         if ((gerr 
= getaddrinfo(mgroup
, NULL
, &hints
, &res0
)) != 0) { 
1091                 fprintf(stderr
, "getaddrinfo(): %s\n", gai_strerror(gerr
)); 
1095         for (res 
= res0
; res
; res 
= res
->ai_next
) { 
1096                 if (AF_INET 
== family
) { 
1097                         memset(&mreq
, 0, sizeof(mreq
)); 
1098                         mreq
.imr_multiaddr 
= ((struct sockaddr_in 
*)res
->ai_addr
)->sin_addr
; 
1099                         if (setsockopt(fd
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &mreq
, sizeof(mreq
)) == -1) { 
1100                                 fprintf(stderr
, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno
)); 
1104                 } else if (AF_INET6 
== family
) { 
1105                         memset(&m6req
, 0, sizeof(m6req
)); 
1106                         m6req
.ipv6mr_multiaddr 
= ((struct sockaddr_in6 
*)res
->ai_addr
)->sin6_addr
; 
1107                         if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &m6req
, sizeof(m6req
)) == -1) { 
1108                                 fprintf(stderr
, "setsockopt(IPV6_JOIN_GROUP): %s\n", strerror(errno
)); 
1113                         fprintf(stderr
, "unknown family during multicast group bind!\n"); 
1123 do_rendezvous_magic(const struct addrinfo 
*res
, const char *serv
) 
1126         DNSServiceRef service
; 
1127         DNSServiceErrorType error
; 
1130         static int statres 
= 1; 
1133                 statres 
= stat("/usr/sbin/mDNSResponder", &sb
); 
1136         if (-1 == statres
) { 
1140         sprintf(rvs_buf
, "_%s._%s.", serv
, res
->ai_socktype 
== SOCK_STREAM 
? "tcp" : "udp"); 
1142         if (res
->ai_family 
== AF_INET
) { 
1143                 port 
= ((struct sockaddr_in 
*)res
->ai_addr
)->sin_port
; 
1145                 port 
= ((struct sockaddr_in6 
*)res
->ai_addr
)->sin6_port
; 
1148         error 
= DNSServiceRegister(&service
, 0, 0, NULL
, rvs_buf
, NULL
, NULL
, port
, 0, NULL
, NULL
, NULL
); 
1150         if (error 
== kDNSServiceErr_NoError
) { 
1151                 return launch_data_new_fd(DNSServiceRefSockFD(service
)); 
1154         fprintf(stderr
, "DNSServiceRegister(\"%s\"): %d\n", serv
, error
); 
1159 CreateMyPropertyListFromFile(const char *posixfile
) 
1161         CFPropertyListRef propertyList
; 
1162         CFStringRef       errorString
; 
1163         CFDataRef         resourceData
; 
1167         fileURL 
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault
, (const UInt8 
*)posixfile
, strlen(posixfile
), false); 
1169                 fprintf(stderr
, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile
); 
1171         if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, fileURL
, &resourceData
, NULL
, NULL
, &errorCode
)) { 
1172                 fprintf(stderr
, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), posixfile
, (int)errorCode
); 
1174         propertyList 
= CFPropertyListCreateFromXMLData(kCFAllocatorDefault
, resourceData
, kCFPropertyListMutableContainers
, &errorString
); 
1175         if (!propertyList
) { 
1176                 fprintf(stderr
, "%s: propertyList is NULL\n", getprogname()); 
1179         return propertyList
; 
1183 WriteMyPropertyListToFile(CFPropertyListRef plist
, const char *posixfile
) 
1185         CFDataRef       resourceData
; 
1189         fileURL 
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault
, (const UInt8 
*)posixfile
, strlen(posixfile
), false); 
1191                 fprintf(stderr
, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile
); 
1193         resourceData 
= CFPropertyListCreateXMLData(kCFAllocatorDefault
, plist
); 
1194         if (resourceData 
== NULL
) { 
1195                 fprintf(stderr
, "%s: CFPropertyListCreateXMLData(%s) failed", getprogname(), posixfile
); 
1197         if (!CFURLWriteDataAndPropertiesToResource(fileURL
, resourceData
, NULL
, &errorCode
)) { 
1198                 fprintf(stderr
, "%s: CFURLWriteDataAndPropertiesToResource(%s) failed: %d\n", getprogname(), posixfile
, (int)errorCode
); 
1203 myCFDictionaryApplyFunction(const void *key
, const void *value
, void *context
) 
1205         launch_data_t ik
, iw
, where 
= context
; 
1207         ik 
= CF2launch_data(key
); 
1208         iw 
= CF2launch_data(value
); 
1210         launch_data_dict_insert(where
, iw
, launch_data_get_string(ik
)); 
1211         launch_data_free(ik
); 
1215 CF2launch_data(CFTypeRef cfr
) 
1218         CFTypeID cft 
= CFGetTypeID(cfr
); 
1220         if (cft 
== CFStringGetTypeID()) { 
1222                 CFStringGetCString(cfr
, buf
, sizeof(buf
), kCFStringEncodingUTF8
); 
1223                 r 
= launch_data_alloc(LAUNCH_DATA_STRING
); 
1224                 launch_data_set_string(r
, buf
); 
1225         } else if (cft 
== CFBooleanGetTypeID()) { 
1226                 r 
= launch_data_alloc(LAUNCH_DATA_BOOL
); 
1227                 launch_data_set_bool(r
, CFBooleanGetValue(cfr
)); 
1228         } else if (cft 
== CFArrayGetTypeID()) { 
1229                 CFIndex i
, ac 
= CFArrayGetCount(cfr
); 
1230                 r 
= launch_data_alloc(LAUNCH_DATA_ARRAY
); 
1231                 for (i 
= 0; i 
< ac
; i
++) { 
1232                         CFTypeRef v 
= CFArrayGetValueAtIndex(cfr
, i
); 
1234                                 launch_data_t iv 
= CF2launch_data(v
); 
1235                                 launch_data_array_set_index(r
, iv
, i
); 
1238         } else if (cft 
== CFDictionaryGetTypeID()) { 
1239                 r 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
1240                 CFDictionaryApplyFunction(cfr
, myCFDictionaryApplyFunction
, r
); 
1241         } else if (cft 
== CFDataGetTypeID()) { 
1242                 r 
= launch_data_alloc(LAUNCH_DATA_ARRAY
); 
1243                 launch_data_set_opaque(r
, CFDataGetBytePtr(cfr
), CFDataGetLength(cfr
)); 
1244         } else if (cft 
== CFNumberGetTypeID()) { 
1247                 CFNumberType cfnt 
= CFNumberGetType(cfr
); 
1249                 case kCFNumberSInt8Type
: 
1250                 case kCFNumberSInt16Type
: 
1251                 case kCFNumberSInt32Type
: 
1252                 case kCFNumberSInt64Type
: 
1253                 case kCFNumberCharType
: 
1254                 case kCFNumberShortType
: 
1255                 case kCFNumberIntType
: 
1256                 case kCFNumberLongType
: 
1257                 case kCFNumberLongLongType
: 
1258                         CFNumberGetValue(cfr
, kCFNumberLongLongType
, &n
); 
1259                         r 
= launch_data_alloc(LAUNCH_DATA_INTEGER
); 
1260                         launch_data_set_integer(r
, n
); 
1262                 case kCFNumberFloat32Type
: 
1263                 case kCFNumberFloat64Type
: 
1264                 case kCFNumberFloatType
: 
1265                 case kCFNumberDoubleType
: 
1266                         CFNumberGetValue(cfr
, kCFNumberDoubleType
, &d
); 
1267                         r 
= launch_data_alloc(LAUNCH_DATA_REAL
); 
1268                         launch_data_set_real(r
, d
); 
1281 help_cmd(int argc
, char *const argv
[]) 
1283         FILE *where 
= stdout
; 
1284         int l
, cmdwidth 
= 0; 
1287         if (argc 
== 0 || argv 
== NULL
) 
1290         fprintf(where
, "usage: %s <subcommand>\n", getprogname()); 
1292         for (i 
= 0; i 
< (sizeof cmds 
/ sizeof cmds
[0]); i
++) { 
1293                 l 
= strlen(cmds
[i
].name
); 
1298         for (i 
= 0; i 
< (sizeof cmds 
/ sizeof cmds
[0]); i
++) { 
1299                 fprintf(where
, "\t%-*s\t%s\n", cmdwidth
, cmds
[i
].name
, cmds
[i
].desc
); 
1306 exit_cmd(int argc 
__attribute__((unused
)), char *const argv
[] __attribute__((unused
))) 
1315                 fcntl(fd
, F_SETFD
, 1); 
1320 do_single_user_mode(bool sflag
) 
1323                 while (!do_single_user_mode2()) { 
1330 do_single_user_mode2(void) 
1332         bool runcom_fsck 
= true; /* should_fsck(); */ 
1337         switch ((p 
= fork())) { 
1339                 syslog(LOG_ERR
, "can't fork single-user shell, trying again: %m"); 
1344                 assumes(waitpid(p
, &wstatus
, 0) != -1); 
1345                 if (WIFEXITED(wstatus
)) { 
1346                         if (WEXITSTATUS(wstatus
) == EXIT_SUCCESS
) { 
1349                                 fprintf(stdout
, "single user mode: exit status: %d\n", WEXITSTATUS(wstatus
)); 
1352                         fprintf(stdout
, "single user mode shell: %s\n", strsignal(WTERMSIG(wstatus
))); 
1357         revoke(_PATH_CONSOLE
); 
1358         if (!assumes((fd 
= open(_PATH_CONSOLE
, O_RDWR
)) != -1)) { 
1359                 _exit(EXIT_FAILURE
); 
1361         if (!assumes(login_tty(fd
) != -1)) { 
1362                 _exit(EXIT_FAILURE
); 
1364         setenv("TERM", "vt100", 1); 
1366                 fprintf(stdout
, "Singleuser boot -- fsck not done\n"); 
1367                 fprintf(stdout
, "Root device is mounted read-only\n\n"); 
1368                 fprintf(stdout
, "If you want to make modifications to files:\n"); 
1369                 fprintf(stdout
, "\t/sbin/fsck -fy\n\t/sbin/mount -uw /\n\n"); 
1370                 fprintf(stdout
, "If you wish to boot the system:\n"); 
1371                 fprintf(stdout
, "\texit\n\n"); 
1375         execl(_PATH_BSHELL
, "-sh", NULL
); 
1376         syslog(LOG_ERR
, "can't exec %s for single user: %m", _PATH_BSHELL
); 
1377         _exit(EXIT_FAILURE
); 
1381 system_specific_bootstrap(bool sflag
) 
1383         int hnmib
[] = { CTL_KERN
, KERN_HOSTNAME 
}; 
1388         do_sysversion_sysctl(); 
1390         do_single_user_mode(sflag
); 
1392         assumes((kq 
= kqueue()) != -1); 
1394         EV_SET(&kev
, 0, EVFILT_TIMER
, EV_ADD
|EV_ONESHOT
, NOTE_SECONDS
, 60, 0); 
1395         assumes(kevent(kq
, &kev
, 1, NULL
, 0, NULL
) != -1); 
1397         EV_SET(&kev
, SIGTERM
, EVFILT_SIGNAL
, EV_ADD
, 0, 0, 0); 
1398         assumes(kevent(kq
, &kev
, 1, NULL
, 0, NULL
) != -1); 
1399         assumes(signal(SIGTERM
, SIG_IGN
) != SIG_ERR
); 
1401         assumes(sysctl(hnmib
, 2, NULL
, NULL
, "localhost", sizeof("localhost")) != -1); 
1403         loopback_setup_ipv4(); 
1404         loopback_setup_ipv6(); 
1406         if (path_check("/etc/rc.server")) { 
1407                 const char *rcserver_tool
[] = { _PATH_BSHELL
, "/etc/rc.server", NULL 
}; 
1408                 assumes(fwexec(rcserver_tool
, true) != -1); 
1411         apply_sysctls_from_file("/etc/sysctl.conf"); 
1413         if (path_check("/etc/rc.cdrom")) { 
1414                 const char *rccdrom_tool
[] = { _PATH_BSHELL
, "/etc/rc.cdrom", "multiuser", NULL 
}; 
1415                 assumes(fwexec(rccdrom_tool
, true) != -1); 
1416                 assumes(reboot(RB_HALT
) != -1); 
1417                 _exit(EXIT_FAILURE
); 
1418         } else if (is_netboot()) { 
1419                 const char *rcnetboot_tool
[] = { _PATH_BSHELL
, "/etc/rc.netboot", "init", NULL 
}; 
1420                 if (!assumes(fwexec(rcnetboot_tool
, true) != -1)) { 
1421                         assumes(reboot(RB_HALT
) != -1); 
1422                         _exit(EXIT_FAILURE
); 
1425                 do_potential_fsck(); 
1428         read_launchd_conf(); 
1430         if (path_check("/var/account/acct")) { 
1431                 assumes(acct("/var/account/acct") != -1); 
1434         if (path_check("/etc/fstab")) { 
1435                 const char *mount_tool
[] = { "mount", "-vat", "nonfs", NULL 
}; 
1436                 assumes(fwexec(mount_tool
, true) != -1); 
1439         if (path_check("/etc/rc.installer_cleanup")) { 
1440                 const char *rccleanup_tool
[] = { _PATH_BSHELL
, "/etc/rc.installer_cleanup", "multiuser", NULL 
}; 
1441                 assumes(fwexec(rccleanup_tool
, true) != -1); 
1444         empty_dir(_PATH_VARRUN
, NULL
); 
1445         empty_dir(_PATH_TMP
, NULL
); 
1446         remove(_PATH_NOLOGIN
); 
1448         if (path_check("/usr/libexec/dirhelper")) { 
1449                 const char *dirhelper_tool
[] = { "/usr/libexec/dirhelper", "-machineBoot", NULL 
}; 
1450                 assumes(fwexec(dirhelper_tool
, true) != -1); 
1453         assumes(touch_file(_PATH_UTMPX
, DEFFILEMODE
) != -1); 
1454         assumes(touch_file(_PATH_VARRUN 
"/.systemStarterRunning", DEFFILEMODE
) != -1); 
1456         if (path_check("/etc/security/rc.audit")) { 
1457                 const char *audit_tool
[] = { _PATH_BSHELL
, "/etc/security/rc.audit", NULL 
}; 
1458                 assumes(fwexec(audit_tool
, true) != -1); 
1461         do_BootCache_magic(BOOTCACHE_START
); 
1463         preheat_page_cache_hack(); 
1465         _vproc_set_global_on_demand(true); 
1467         char *load_launchd_items
[] = { "load", "-D", "all", "/etc/mach_init.d", NULL 
}; 
1469         if (is_safeboot()) { 
1470                 load_launchd_items
[2] = "system"; 
1473         assumes(load_and_unload_cmd(4, load_launchd_items
) == 0); 
1478          * We need to revisit this after Leopard ships. 
1480          * I want a plist defined knob for jobs to give advisory hints that 
1481          * will "hopefully" serialize bootstrap. Reasons for doing so include 
1482          * pragmatic performance optimizations and attempts to workaround bugs 
1483          * in jobs. My current thought is something like what follows. 
1485          * The BootCache would switch to launchd and add this to the plist: 
1487          * <key>HopefullyStartsSerially<key> 
1489          *      <key>ReadyTimeout</key> 
1490          *      <integer>2</integer> 
1493          * And kextd would add the following: 
1495          * <key>HopefullyStartsSerially<key> 
1497          *      <key>ReadyTimeout</key> 
1498          *      <integer>5</integer> 
1499          *      <key>HopefullyStartsAfter</key> 
1500          *      <string>com.apple.BootCache.daemon</string> 
1504          * Then both the BootCache and kextd could call something like: 
1506          * vproc_declare_ready_state(); 
1508          * To tell launchd to short circuit the readiness timeout and let the 
1509          * next wave of jobs start. 
1511          * Yes, this mechanism smells a lot like SystemStarter, rc.d and 
1512          * friends. I think as long as we document that artificial 
1513          * serialization is only advisory and not guaranteed, we should be 
1514          * fine. Remember: IPC is the preferred way to serialize operations. 
1517         mach_timespec_t w 
= { 5, 0 }; 
1518         IOKitWaitQuiet(kIOMasterPortDefault
, &w
); 
1520         do_BootCache_magic(BOOTCACHE_TAG
); 
1522         do_bootroot_magic(); 
1524         _vproc_set_global_on_demand(false); 
1526         assumes(kevent(kq
, NULL
, 0, &kev
, 1, NULL
) == 1); 
1528         do_BootCache_magic(BOOTCACHE_STOP
); 
1530         assumes(close(kq
) != -1); 
1534 do_BootCache_magic(BootCache_action_t what
) 
1536         const char *bcc_tool
[] = { "BootCacheControl", "-f", "/var/db/BootCache.playlist", NULL
, NULL 
}; 
1538         if (is_safeboot()) { 
1543         case BOOTCACHE_START
: 
1544                 bcc_tool
[3] = "start"; 
1547                 bcc_tool
[3] = "tag"; 
1549         case BOOTCACHE_STOP
: 
1550                 bcc_tool
[3] = "stop"; 
1557         fwexec(bcc_tool
, true); 
1561 bootstrap_cmd(int argc
, char *const argv
[]) 
1563         char *session_type 
= NULL
; 
1567         while ((ch 
= getopt(argc
, argv
, "sS:")) != -1) { 
1573                         session_type 
= optarg
; 
1584         if (!session_type
) { 
1585                 fprintf(stderr
, "usage: %s bootstrap [-s] -S <session-type>\n", getprogname()); 
1589         if (strcasecmp(session_type
, "System") == 0) { 
1590                 system_specific_bootstrap(sflag
); 
1592                 char *load_launchd_items
[] = { "load", "-S", session_type
, "-D", "all", NULL
, NULL
, NULL
, NULL 
}; 
1595                 if (is_safeboot()) { 
1596                         load_launchd_items
[4] = "system"; 
1599                 if (strcasecmp(session_type
, VPROCMGR_SESSION_BACKGROUND
) == 0 || strcasecmp(session_type
, VPROCMGR_SESSION_LOGINWINDOW
) == 0) { 
1600                         load_launchd_items
[4] = "system"; 
1601                         if (!is_safeboot()) { 
1602                                 load_launchd_items
[5] = "-D"; 
1603                                 load_launchd_items
[6] = "local"; 
1606                         if (strcasecmp(session_type
, VPROCMGR_SESSION_LOGINWINDOW
) == 0) { 
1607                                 load_launchd_items
[the_argc
] = "/etc/mach_init_per_login_session.d"; 
1610                 } else if (strcasecmp(session_type
, VPROCMGR_SESSION_AQUA
) == 0) { 
1611                         load_launchd_items
[5] = "/etc/mach_init_per_user.d"; 
1615 #if !TARGET_OS_EMBEDDED 
1616                 if (strcasecmp(session_type
, VPROCMGR_SESSION_BACKGROUND
) == 0) { 
1617                         assumes(SessionCreate(sessionKeepCurrentBootstrap
, 0) == 0); 
1621                 return load_and_unload_cmd(the_argc
, load_launchd_items
); 
1628 load_and_unload_cmd(int argc
, char *const argv
[]) 
1630         NSSearchPathEnumerationState es 
= 0; 
1631         char nspath
[PATH_MAX 
* 2]; /* safe side, we need to append */ 
1632         bool badopts 
= false; 
1633         struct load_unload_state lus
; 
1637         memset(&lus
, 0, sizeof(lus
)); 
1639         if (strcmp(argv
[0], "load") == 0) { 
1643         while ((ch 
= getopt(argc
, argv
, "wFS:D:")) != -1) { 
1646                         lus
.editondisk 
= true; 
1649                         lus
.forceload 
= true; 
1652                         lus
.session_type 
= optarg
; 
1655                         if (strcasecmp(optarg
, "all") == 0) { 
1656                                 es 
|= NSAllDomainsMask
; 
1657                         } else if (strcasecmp(optarg
, "user") == 0) { 
1658                                 es 
|= NSUserDomainMask
; 
1659                         } else if (strcasecmp(optarg
, "local") == 0) { 
1660                                 es 
|= NSLocalDomainMask
; 
1661                         } else if (strcasecmp(optarg
, "network") == 0) { 
1662                                 es 
|= NSNetworkDomainMask
; 
1663                         } else if (strcasecmp(optarg
, "system") == 0) { 
1664                                 es 
|= NSSystemDomainMask
; 
1678         if (lus
.session_type 
== NULL
) { 
1679                 es 
&= ~NSUserDomainMask
; 
1682         if (argc 
== 0 && es 
== 0) { 
1687                 fprintf(stderr
, "usage: %s load [-wF] [-D <user|local|network|system|all>] paths...\n", getprogname()); 
1691         /* I wish I didn't need to do three passes, but I need to load mDNSResponder and use it too. 
1692          * And loading legacy mach init jobs is extra fun. 
1694          * In later versions of launchd, I hope to load everything in the first pass, 
1695          * then do the Bonjour magic on the jobs that need it, and reload them, but for now, 
1696          * I haven't thought through the various complexities of reloading jobs, and therefore 
1697          * launchd doesn't have reload support right now. 
1700         lus
.pass0 
= launch_data_alloc(LAUNCH_DATA_ARRAY
); 
1701         lus
.pass1 
= launch_data_alloc(LAUNCH_DATA_ARRAY
); 
1702         lus
.pass2 
= launch_data_alloc(LAUNCH_DATA_ARRAY
); 
1704         es 
= NSStartSearchPathEnumeration(NSLibraryDirectory
, es
); 
1706         while ((es 
= NSGetNextSearchPathEnumeration(es
, nspath
))) { 
1709                 if (lus
.session_type
) { 
1710                         strcat(nspath
, "/LaunchAgents"); 
1712                         strcat(nspath
, "/LaunchDaemons"); 
1715                 if (glob(nspath
, GLOB_TILDE
|GLOB_NOSORT
, NULL
, &g
) == 0) { 
1716                         for (i 
= 0; i 
< g
.gl_pathc
; i
++) { 
1717                                 readpath(g
.gl_pathv
[i
], &lus
); 
1723         for (i 
= 0; i 
< (size_t)argc
; i
++) { 
1724                 readpath(argv
[i
], &lus
); 
1727         if (launch_data_array_get_count(lus
.pass0
) == 0 && 
1728                         launch_data_array_get_count(lus
.pass1
) == 0 && 
1729                         launch_data_array_get_count(lus
.pass2
) == 0) { 
1731                         fprintf(stderr
, "nothing found to %s\n", lus
.load 
? "load" : "unload"); 
1733                 launch_data_free(lus
.pass0
); 
1734                 launch_data_free(lus
.pass1
); 
1735                 launch_data_free(lus
.pass2
); 
1736                 return is_managed 
? 0 : 1; 
1740                 distill_jobs(lus
.pass1
); 
1741                 submit_mach_jobs(lus
.pass0
); 
1742                 submit_job_pass(lus
.pass1
); 
1743                 let_go_of_mach_jobs(lus
.pass0
); 
1744                 distill_jobs(lus
.pass2
); 
1745                 submit_job_pass(lus
.pass2
); 
1747                 for (i 
= 0; i 
< launch_data_array_get_count(lus
.pass1
); i
++) { 
1748                         unloadjob(launch_data_array_get_index(lus
.pass1
, i
)); 
1750                 for (i 
= 0; i 
< launch_data_array_get_count(lus
.pass2
); i
++) { 
1751                         unloadjob(launch_data_array_get_index(lus
.pass2
, i
)); 
1759 submit_mach_jobs(launch_data_t jobs
) 
1763         c 
= launch_data_array_get_count(jobs
); 
1765         for (i 
= 0; i 
< c
; i
++) { 
1766                 launch_data_t tmp
, oai 
= launch_data_array_get_index(jobs
, i
); 
1767                 const char *sn 
= NULL
, *cmd 
= NULL
; 
1769                 mach_port_t msr
, msv
; 
1773                 if ((tmp 
= launch_data_dict_lookup(oai
, MACHINIT_JOBKEY_ONDEMAND
))) 
1774                         d 
= launch_data_get_bool(tmp
); 
1775                 if ((tmp 
= launch_data_dict_lookup(oai
, MACHINIT_JOBKEY_SERVICENAME
))) 
1776                         sn 
= launch_data_get_string(tmp
); 
1777                 if ((tmp 
= launch_data_dict_lookup(oai
, MACHINIT_JOBKEY_COMMAND
))) 
1778                         cmd 
= launch_data_get_string(tmp
); 
1780                 if ((kr 
= bootstrap_create_server(bootstrap_port
, (char *)cmd
, u
, d
, &msr
)) != KERN_SUCCESS
) { 
1781                         fprintf(stderr
, "%s: bootstrap_create_server(): %d\n", getprogname(), kr
); 
1784                 if ((kr 
= bootstrap_create_service(msr
, (char*)sn
, &msv
)) != KERN_SUCCESS
) { 
1785                         fprintf(stderr
, "%s: bootstrap_create_service(): %d\n", getprogname(), kr
); 
1786                         mach_port_destroy(mach_task_self(), msr
); 
1789                 launch_data_dict_insert(oai
, launch_data_new_machport(msr
), MACHINIT_JOBKEY_SERVERPORT
); 
1790                 launch_data_dict_insert(oai
, launch_data_new_machport(msv
), MACHINIT_JOBKEY_SERVICEPORT
); 
1795 let_go_of_mach_jobs(launch_data_t jobs
) 
1797         size_t i
, c 
= launch_data_array_get_count(jobs
); 
1799         for (i 
= 0; i 
< c
; i
++) { 
1800                 launch_data_t tmp
, oai 
= launch_data_array_get_index(jobs
, i
); 
1801                 if ((tmp 
= launch_data_dict_lookup(oai
, MACHINIT_JOBKEY_SERVICEPORT
))) { 
1802                         mach_port_destroy(mach_task_self(), launch_data_get_machport(tmp
)); 
1804                         fprintf(stderr
, "%s: ack! missing service port!\n", getprogname()); 
1806                 if ((tmp 
= launch_data_dict_lookup(oai
, MACHINIT_JOBKEY_SERVERPORT
))) { 
1807                         mach_port_destroy(mach_task_self(), launch_data_get_machport(tmp
)); 
1809                         fprintf(stderr
, "%s: ack! missing server port!\n", getprogname()); 
1815 submit_job_pass(launch_data_t jobs
) 
1817         launch_data_t msg
, resp
; 
1821         if (launch_data_array_get_count(jobs
) == 0) 
1824         msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
1826         launch_data_dict_insert(msg
, jobs
, LAUNCH_KEY_SUBMITJOB
); 
1828         resp 
= launch_msg(msg
); 
1831                 switch (launch_data_get_type(resp
)) { 
1832                 case LAUNCH_DATA_ERRNO
: 
1833                         if ((e 
= launch_data_get_errno(resp
))) 
1834                                 fprintf(stderr
, "%s\n", strerror(e
)); 
1836                 case LAUNCH_DATA_ARRAY
: 
1837                         for (i 
= 0; i 
< launch_data_array_get_count(jobs
); i
++) { 
1838                                 launch_data_t obatind 
= launch_data_array_get_index(resp
, i
); 
1839                                 launch_data_t jatind 
= launch_data_array_get_index(jobs
, i
); 
1840                                 const char *lab4job 
= launch_data_get_string(launch_data_dict_lookup(jatind
, LAUNCH_JOBKEY_LABEL
)); 
1841                                 if (LAUNCH_DATA_ERRNO 
== launch_data_get_type(obatind
)) { 
1842                                         e 
= launch_data_get_errno(obatind
); 
1845                                                 fprintf(stderr
, "%s: %s\n", lab4job
, "Already loaded"); 
1848                                                 fprintf(stderr
, "%s: %s\n", lab4job
, "Not loaded"); 
1851                                                 fprintf(stderr
, "%s: %s\n", lab4job
, strerror(e
)); 
1859                         fprintf(stderr
, "unknown respose from launchd!\n"); 
1862                 launch_data_free(resp
); 
1864                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
1867         launch_data_free(msg
); 
1871 start_stop_remove_cmd(int argc
, char *const argv
[]) 
1873         launch_data_t resp
, msg
; 
1874         const char *lmsgcmd 
= LAUNCH_KEY_STOPJOB
; 
1877         if (0 == strcmp(argv
[0], "start")) 
1878                 lmsgcmd 
= LAUNCH_KEY_STARTJOB
; 
1880         if (0 == strcmp(argv
[0], "remove")) 
1881                 lmsgcmd 
= LAUNCH_KEY_REMOVEJOB
; 
1884                 fprintf(stderr
, "usage: %s %s <job label>\n", getprogname(), argv
[0]); 
1888         msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
1889         launch_data_dict_insert(msg
, launch_data_new_string(argv
[1]), lmsgcmd
); 
1891         resp 
= launch_msg(msg
); 
1892         launch_data_free(msg
); 
1895                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
1897         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) { 
1898                 if ((e 
= launch_data_get_errno(resp
))) { 
1899                         fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], strerror(e
)); 
1903                 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]); 
1907         launch_data_free(resp
); 
1912 print_jobs(launch_data_t j
, const char *key 
__attribute__((unused
)), void *context 
__attribute__((unused
))) 
1914         static size_t depth 
= 0; 
1915         launch_data_t lo 
= launch_data_dict_lookup(j
, LAUNCH_JOBKEY_LABEL
); 
1916         launch_data_t pido 
= launch_data_dict_lookup(j
, LAUNCH_JOBKEY_PID
); 
1917         launch_data_t stato 
= launch_data_dict_lookup(j
, LAUNCH_JOBKEY_LASTEXITSTATUS
); 
1918         const char *label 
= launch_data_get_string(lo
); 
1922                 fprintf(stdout
, "%lld\t-\t", launch_data_get_integer(pido
)); 
1924                 int wstatus 
= (int)launch_data_get_integer(stato
); 
1925                 if (WIFEXITED(wstatus
)) { 
1926                         fprintf(stdout
, "-\t%d\t", WEXITSTATUS(wstatus
)); 
1927                 } else if (WIFSIGNALED(wstatus
)) { 
1928                         fprintf(stdout
, "-\t-%d\t", WTERMSIG(wstatus
)); 
1930                         fprintf(stdout
, "-\t???\t"); 
1933                 fprintf(stdout
, "-\t-\t"); 
1935         for (i 
= 0; i 
< depth
; i
++) 
1936                 fprintf(stdout
, "\t"); 
1938         fprintf(stdout
, "%s\n", label
); 
1942 print_obj(launch_data_t obj
, const char *key
, void *context 
__attribute__((unused
))) 
1944         static size_t indent 
= 0; 
1947         for (i 
= 0; i 
< indent
; i
++) 
1948                 fprintf(stdout
, "\t"); 
1951                 fprintf(stdout
, "\"%s\" = ", key
); 
1953         switch (launch_data_get_type(obj
)) { 
1954         case LAUNCH_DATA_STRING
: 
1955                 fprintf(stdout
, "\"%s\";\n", launch_data_get_string(obj
)); 
1957         case LAUNCH_DATA_INTEGER
: 
1958                 fprintf(stdout
, "%lld;\n", launch_data_get_integer(obj
)); 
1960         case LAUNCH_DATA_REAL
: 
1961                 fprintf(stdout
, "%f;\n", launch_data_get_real(obj
)); 
1963         case LAUNCH_DATA_BOOL
: 
1964                 fprintf(stdout
, "%s;\n", launch_data_get_bool(obj
) ? "true" : "false"); 
1966         case LAUNCH_DATA_ARRAY
: 
1967                 c 
= launch_data_array_get_count(obj
); 
1968                 fprintf(stdout
, "(\n"); 
1970                 for (i 
= 0; i 
< c
; i
++) 
1971                         print_obj(launch_data_array_get_index(obj
, i
), NULL
, NULL
); 
1973                 for (i 
= 0; i 
< indent
; i
++) 
1974                         fprintf(stdout
, "\t"); 
1975                 fprintf(stdout
, ");\n"); 
1977         case LAUNCH_DATA_DICTIONARY
: 
1978                 fprintf(stdout
, "{\n"); 
1980                 launch_data_dict_iterate(obj
, print_obj
, NULL
); 
1982                 for (i 
= 0; i 
< indent
; i
++) 
1983                         fprintf(stdout
, "\t"); 
1984                 fprintf(stdout
, "};\n"); 
1986         case LAUNCH_DATA_FD
: 
1987                 fprintf(stdout
, "file-descriptor-object;\n"); 
1989         case LAUNCH_DATA_MACHPORT
: 
1990                 fprintf(stdout
, "mach-port-object;\n"); 
1993                 fprintf(stdout
, "???;\n"); 
1999 list_cmd(int argc
, char *const argv
[]) 
2001         launch_data_t resp
, msg
; 
2005                 fprintf(stderr
, "usage: %s list [label]\n", getprogname()); 
2007         } else if (argc 
== 2) { 
2008                 msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
2009                 launch_data_dict_insert(msg
, launch_data_new_string(argv
[1]), LAUNCH_KEY_GETJOB
); 
2010         } else if (vproc_swap_complex(NULL
, VPROC_GSK_ALLJOBS
, NULL
, &resp
) == NULL
) { 
2011                 fprintf(stdout
, "PID\tStatus\tLabel\n"); 
2012                 launch_data_dict_iterate(resp
, print_jobs
, NULL
); 
2013                 launch_data_free(resp
); 
2019         resp 
= launch_msg(msg
); 
2020         launch_data_free(msg
); 
2023                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
2025         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_DICTIONARY
) { 
2026                 print_obj(resp
, NULL
, NULL
); 
2028                 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]); 
2032         launch_data_free(resp
); 
2038 stdio_cmd(int argc 
__attribute__((unused
)), char *const argv
[]) 
2040         fprintf(stderr
, "%s %s: This sub-command no longer does anything\n", getprogname(), argv
[0]); 
2045 fyi_cmd(int argc
, char *const argv
[]) 
2047         launch_data_t resp
, msg
; 
2048         const char *lmsgk 
= NULL
; 
2052                 fprintf(stderr
, "usage: %s %s\n", getprogname(), argv
[0]); 
2056         if (!strcmp(argv
[0], "shutdown")) { 
2057                 lmsgk 
= LAUNCH_KEY_SHUTDOWN
; 
2058         } else if (!strcmp(argv
[0], "singleuser")) { 
2059                 lmsgk 
= LAUNCH_KEY_SINGLEUSER
; 
2064         msg 
= launch_data_new_string(lmsgk
); 
2065         resp 
= launch_msg(msg
); 
2066         launch_data_free(msg
); 
2069                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
2071         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) { 
2072                 if ((e 
= launch_data_get_errno(resp
))) { 
2073                         fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], strerror(e
)); 
2077                 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]); 
2081         launch_data_free(resp
); 
2087 logupdate_cmd(int argc
, char *const argv
[]) 
2089         int64_t inval
, outval
; 
2091         bool badargs 
= false, maskmode 
= false, onlymode 
= false, levelmode 
= false; 
2092         static const struct { 
2096                 { "debug",      LOG_DEBUG 
}, 
2097                 { "info",       LOG_INFO 
}, 
2098                 { "notice",     LOG_NOTICE 
}, 
2099                 { "warning",    LOG_WARNING 
}, 
2100                 { "error",      LOG_ERR 
}, 
2101                 { "critical",   LOG_CRIT 
}, 
2102                 { "alert",      LOG_ALERT 
}, 
2103                 { "emergency",  LOG_EMERG 
}, 
2105         int logtblsz 
= sizeof logtbl 
/ sizeof logtbl
[0]; 
2108                 if (!strcmp(argv
[1], "mask")) 
2110                 else if (!strcmp(argv
[1], "only")) 
2112                 else if (!strcmp(argv
[1], "level")) 
2119                 m 
= LOG_UPTO(LOG_DEBUG
); 
2121         if (argc 
> 2 && (maskmode 
|| onlymode
)) { 
2122                 for (i 
= 2; i 
< argc
; i
++) { 
2123                         for (j 
= 0; j 
< logtblsz
; j
++) { 
2124                                 if (!strcmp(argv
[i
], logtbl
[j
].name
)) { 
2126                                                 m 
&= ~(LOG_MASK(logtbl
[j
].level
)); 
2128                                                 m 
|= LOG_MASK(logtbl
[j
].level
); 
2132                         if (j 
== logtblsz
) { 
2137         } else if (argc 
> 2 && levelmode
) { 
2138                 for (j 
= 0; j 
< logtblsz
; j
++) { 
2139                         if (!strcmp(argv
[2], logtbl
[j
].name
)) { 
2140                                 m 
= LOG_UPTO(logtbl
[j
].level
); 
2146         } else if (argc 
!= 1) { 
2151                 fprintf(stderr
, "usage: %s [[mask loglevels...] | [only loglevels...] [level loglevel]]\n", getprogname()); 
2157         if (vproc_swap_integer(NULL
, VPROC_GSK_GLOBAL_LOG_MASK
, argc 
!= 1 ? &inval 
: NULL
, &outval
) == NULL
) { 
2159                         for (j 
= 0; j 
< logtblsz
; j
++) { 
2160                                 if (outval 
& LOG_MASK(logtbl
[j
].level
)) { 
2161                                         fprintf(stdout
, "%s ", logtbl
[j
].name
); 
2164                         fprintf(stdout
, "\n"); 
2172 static const struct { 
2176         { "cpu",        RLIMIT_CPU 
}, 
2177         { "filesize",   RLIMIT_FSIZE 
}, 
2178         { "data",       RLIMIT_DATA 
}, 
2179         { "stack",      RLIMIT_STACK 
}, 
2180         { "core",       RLIMIT_CORE 
}, 
2181         { "rss",        RLIMIT_RSS 
}, 
2182         { "memlock",    RLIMIT_MEMLOCK 
}, 
2183         { "maxproc",    RLIMIT_NPROC 
}, 
2184         { "maxfiles",   RLIMIT_NOFILE 
} 
2187 static const size_t limlookupcnt 
= sizeof limlookup 
/ sizeof limlookup
[0]; 
2190 name2num(const char *n
) 
2194         for (i 
= 0; i 
< limlookupcnt
; i
++) { 
2195                 if (!strcmp(limlookup
[i
].name
, n
)) { 
2196                         return limlookup
[i
].lim
; 
2207         for (i 
= 0; i 
< limlookupcnt
; i
++) { 
2208                 if (limlookup
[i
].lim 
== n
) 
2209                         return limlookup
[i
].name
; 
2215 lim2str(rlim_t val
, char *buf
) 
2217         if (val 
== RLIM_INFINITY
) 
2218                 strcpy(buf
, "unlimited"); 
2220                 sprintf(buf
, "%lld", val
); 
2225 str2lim(const char *buf
, rlim_t 
*res
) 
2228         *res 
= strtoll(buf
, &endptr
, 10); 
2229         if (!strcmp(buf
, "unlimited")) { 
2230                 *res 
= RLIM_INFINITY
; 
2232         } else if (*endptr 
== '\0') { 
2239 limit_cmd(int argc 
__attribute__((unused
)), char *const argv
[]) 
2243         struct rlimit 
*lmts 
= NULL
; 
2244         launch_data_t resp
, resp1 
= NULL
, msg
, tmp
; 
2248         rlim_t slim 
= -1, hlim 
= -1; 
2249         bool badargs 
= false; 
2254         if (argc 
>= 3 && str2lim(argv
[2], &slim
)) 
2259         if (argc 
== 4 && str2lim(argv
[3], &hlim
)) 
2262         if (argc 
>= 2 && -1 == (which 
= name2num(argv
[1]))) 
2266                 fprintf(stderr
, "usage: %s %s [", getprogname(), argv
[0]); 
2267                 for (i 
= 0; i 
< limlookupcnt
; i
++) 
2268                         fprintf(stderr
, "%s %s", limlookup
[i
].name
, (i 
+ 1) == limlookupcnt 
? "" : "| "); 
2269                 fprintf(stderr
, "[both | soft hard]]\n"); 
2273         msg 
= launch_data_new_string(LAUNCH_KEY_GETRESOURCELIMITS
); 
2274         resp 
= launch_msg(msg
); 
2275         launch_data_free(msg
); 
2278                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
2280         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_OPAQUE
) { 
2281                 lmts 
= launch_data_get_opaque(resp
); 
2282                 lsz 
= launch_data_get_opaque_size(resp
); 
2284                         for (i 
= 0; i 
< (lsz 
/ sizeof(struct rlimit
)); i
++) { 
2285                                 if (argc 
== 2 && (size_t)which 
!= i
) 
2287                                 fprintf(stdout
, "\t%-12s%-15s%-15s\n", num2name(i
), 
2288                                                 lim2str(lmts
[i
].rlim_cur
, slimstr
), 
2289                                                 lim2str(lmts
[i
].rlim_max
, hlimstr
)); 
2292         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_STRING
) { 
2293                 fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], launch_data_get_string(resp
)); 
2296                 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]); 
2300         if (argc 
<= 2 || r 
!= 0) { 
2301                 launch_data_free(resp
); 
2307         lmts
[which
].rlim_cur 
= slim
; 
2308         lmts
[which
].rlim_max 
= hlim
; 
2310         msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
2311         tmp 
= launch_data_new_opaque(lmts
, lsz
); 
2312         launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_SETRESOURCELIMITS
); 
2313         resp 
= launch_msg(msg
); 
2314         launch_data_free(msg
); 
2317                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
2319         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_STRING
) { 
2320                 fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], launch_data_get_string(resp
)); 
2322         } else if (launch_data_get_type(resp
) != LAUNCH_DATA_OPAQUE
) { 
2323                 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]); 
2327         launch_data_free(resp
); 
2328         launch_data_free(resp1
); 
2334 umask_cmd(int argc
, char *const argv
[]) 
2336         bool badargs 
= false; 
2339         int64_t inval
, outval
; 
2342                 m 
= strtol(argv
[1], &endptr
, 8); 
2343                 if (*endptr 
!= '\0' || m 
> 0777) 
2347         if (argc 
> 2 || badargs
) { 
2348                 fprintf(stderr
, "usage: %s %s <mask>\n", getprogname(), argv
[0]); 
2354         if (vproc_swap_integer(NULL
, VPROC_GSK_GLOBAL_UMASK
, argc 
== 2 ? &inval 
: NULL
, &outval
) == NULL
) { 
2356                         fprintf(stdout
, "%o\n", (unsigned int)outval
); 
2365 submit_cmd(int argc
, char *const argv
[]) 
2367         launch_data_t msg 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
2368         launch_data_t job 
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
); 
2369         launch_data_t resp
, largv 
= launch_data_alloc(LAUNCH_DATA_ARRAY
); 
2372         launch_data_dict_insert(job
, launch_data_new_bool(false), LAUNCH_JOBKEY_ONDEMAND
); 
2374         while ((ch 
= getopt(argc
, argv
, "l:p:o:e:")) != -1) { 
2377                         launch_data_dict_insert(job
, launch_data_new_string(optarg
), LAUNCH_JOBKEY_LABEL
); 
2380                         launch_data_dict_insert(job
, launch_data_new_string(optarg
), LAUNCH_JOBKEY_PROGRAM
); 
2383                         launch_data_dict_insert(job
, launch_data_new_string(optarg
), LAUNCH_JOBKEY_STANDARDOUTPATH
); 
2386                         launch_data_dict_insert(job
, launch_data_new_string(optarg
), LAUNCH_JOBKEY_STANDARDERRORPATH
); 
2389                         fprintf(stderr
, "usage: %s submit ...\n", getprogname()); 
2396         for (i 
= 0; argv
[i
]; i
++) { 
2397                 launch_data_array_append(largv
, launch_data_new_string(argv
[i
])); 
2400         launch_data_dict_insert(job
, largv
, LAUNCH_JOBKEY_PROGRAMARGUMENTS
); 
2402         launch_data_dict_insert(msg
, job
, LAUNCH_KEY_SUBMITJOB
); 
2404         resp 
= launch_msg(msg
); 
2405         launch_data_free(msg
); 
2408                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
2410         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) { 
2411                 errno 
= launch_data_get_errno(resp
); 
2413                         fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], strerror(errno
)); 
2417                 fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], "unknown response"); 
2420         launch_data_free(resp
); 
2426 getrusage_cmd(int argc
, char *const argv
[]) 
2428         launch_data_t resp
, msg
; 
2429         bool badargs 
= false; 
2434         else if (strcmp(argv
[1], "self") && strcmp(argv
[1], "children")) 
2438                 fprintf(stderr
, "usage: %s %s self | children\n", getprogname(), argv
[0]); 
2442         if (!strcmp(argv
[1], "self")) { 
2443                 msg 
= launch_data_new_string(LAUNCH_KEY_GETRUSAGESELF
); 
2445                 msg 
= launch_data_new_string(LAUNCH_KEY_GETRUSAGECHILDREN
); 
2448         resp 
= launch_msg(msg
); 
2449         launch_data_free(msg
); 
2452                 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
)); 
2454         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) { 
2455                 fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], strerror(launch_data_get_errno(resp
))); 
2457         } else if (launch_data_get_type(resp
) == LAUNCH_DATA_OPAQUE
) { 
2458                 struct rusage 
*rusage 
= launch_data_get_opaque(resp
); 
2459                 fprintf(stdout
, "\t%-10f\tuser time used\n", 
2460                                 (double)rusage
->ru_utime
.tv_sec 
+ (double)rusage
->ru_utime
.tv_usec 
/ (double)1000000); 
2461                 fprintf(stdout
, "\t%-10f\tsystem time used\n", 
2462                                 (double)rusage
->ru_stime
.tv_sec 
+ (double)rusage
->ru_stime
.tv_usec 
/ (double)1000000); 
2463                 fprintf(stdout
, "\t%-10ld\tmax resident set size\n", rusage
->ru_maxrss
); 
2464                 fprintf(stdout
, "\t%-10ld\tshared text memory size\n", rusage
->ru_ixrss
); 
2465                 fprintf(stdout
, "\t%-10ld\tunshared data size\n", rusage
->ru_idrss
); 
2466                 fprintf(stdout
, "\t%-10ld\tunshared stack size\n", rusage
->ru_isrss
); 
2467                 fprintf(stdout
, "\t%-10ld\tpage reclaims\n", rusage
->ru_minflt
); 
2468                 fprintf(stdout
, "\t%-10ld\tpage faults\n", rusage
->ru_majflt
); 
2469                 fprintf(stdout
, "\t%-10ld\tswaps\n", rusage
->ru_nswap
); 
2470                 fprintf(stdout
, "\t%-10ld\tblock input operations\n", rusage
->ru_inblock
); 
2471                 fprintf(stdout
, "\t%-10ld\tblock output operations\n", rusage
->ru_oublock
); 
2472                 fprintf(stdout
, "\t%-10ld\tmessages sent\n", rusage
->ru_msgsnd
); 
2473                 fprintf(stdout
, "\t%-10ld\tmessages received\n", rusage
->ru_msgrcv
); 
2474                 fprintf(stdout
, "\t%-10ld\tsignals received\n", rusage
->ru_nsignals
); 
2475                 fprintf(stdout
, "\t%-10ld\tvoluntary context switches\n", rusage
->ru_nvcsw
); 
2476                 fprintf(stdout
, "\t%-10ld\tinvoluntary context switches\n", rusage
->ru_nivcsw
); 
2478                 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]); 
2482         launch_data_free(resp
); 
2488 launch_data_array_append(launch_data_t a
, launch_data_t o
) 
2490         size_t offt 
= launch_data_array_get_count(a
); 
2492         return launch_data_array_set_index(a
, o
, offt
); 
2496 str2bsport(const char *s
) 
2498         bool getrootbs 
= strcmp(s
, "/") == 0; 
2499         mach_port_t last_bport
, bport 
= bootstrap_port
; 
2500         task_t task 
= mach_task_self(); 
2501         kern_return_t result
; 
2503         if (strcmp(s
, "..") == 0 || getrootbs
) { 
2506                         result 
= bootstrap_parent(last_bport
, &bport
); 
2508                         if (result 
== BOOTSTRAP_NOT_PRIVILEGED
) { 
2509                                 fprintf(stderr
, "Permission denied\n"); 
2511                         } else if (result 
!= BOOTSTRAP_SUCCESS
) { 
2512                                 fprintf(stderr
, "bootstrap_parent() %d\n", result
); 
2515                 } while (getrootbs 
&& last_bport 
!= bport
); 
2519                 result 
= task_for_pid(mach_task_self(), pid
, &task
); 
2521                 if (result 
!= KERN_SUCCESS
) { 
2522                         fprintf(stderr
, "task_for_pid() %s\n", mach_error_string(result
)); 
2526                 result 
= task_get_bootstrap_port(task
, &bport
); 
2528                 if (result 
!= KERN_SUCCESS
) { 
2529                         fprintf(stderr
, "Couldn't get bootstrap port: %s\n", mach_error_string(result
)); 
2538 bsexec_cmd(int argc
, char *const argv
[]) 
2540         kern_return_t result
; 
2544                 fprintf(stderr
, "usage: %s bsexec <PID> prog...\n", getprogname()); 
2548         bport 
= str2bsport(argv
[1]); 
2550         result 
= task_set_bootstrap_port(mach_task_self(), bport
); 
2552         if (result 
!= KERN_SUCCESS
) { 
2553                 fprintf(stderr
, "Couldn't switch to new bootstrap port: %s\n", mach_error_string(result
)); 
2560         if (fwexec((const char *const *)argv 
+ 2, true) == -1) { 
2561                 fprintf(stderr
, "%s bsexec failed: %s\n", getprogname(), strerror(errno
)); 
2569 bslist_cmd(int argc
, char *const argv
[]) 
2571         kern_return_t result
; 
2572         mach_port_t bport 
= bootstrap_port
; 
2573         name_array_t service_names
; 
2574         mach_msg_type_number_t service_cnt
, service_active_cnt
; 
2575         bootstrap_status_array_t service_actives
; 
2579                 bport 
= str2bsport(argv
[1]); 
2581         if (bport 
== MACH_PORT_NULL
) { 
2582                 fprintf(stderr
, "Invalid bootstrap port\n"); 
2586         result 
= bootstrap_info(bport
, &service_names
, &service_cnt
, &service_actives
, &service_active_cnt
); 
2587         if (result 
!= BOOTSTRAP_SUCCESS
) { 
2588                 fprintf(stderr
, "bootstrap_info(): %d\n", result
); 
2592 #define bport_state(x)  (((x) == BOOTSTRAP_STATUS_ACTIVE) ? "A" : ((x) == BOOTSTRAP_STATUS_ON_DEMAND) ? "D" : "I") 
2594         for (i 
= 0; i 
< service_cnt 
; i
++) 
2595                 fprintf(stdout
, "%-3s%s\n", bport_state((service_actives
[i
])), service_names
[i
]); 
2601 is_legacy_mach_job(launch_data_t obj
) 
2603         bool has_servicename 
= launch_data_dict_lookup(obj
, MACHINIT_JOBKEY_SERVICENAME
); 
2604         bool has_command 
= launch_data_dict_lookup(obj
, MACHINIT_JOBKEY_COMMAND
); 
2605         bool has_label 
= launch_data_dict_lookup(obj
, LAUNCH_JOBKEY_LABEL
); 
2607         return has_command 
&& has_servicename 
&& !has_label
; 
2611 _log_launchctl_bug(const char *rcs_rev
, const char *path
, unsigned int line
, const char *test
) 
2613         int saved_errno 
= errno
; 
2615         const char *file 
= strrchr(path
, '/'); 
2616         char *rcs_rev_tmp 
= strchr(rcs_rev
, ' '); 
2625                 strlcpy(buf
, rcs_rev
, sizeof(buf
)); 
2627                 strlcpy(buf
, rcs_rev_tmp 
+ 1, sizeof(buf
)); 
2628                 rcs_rev_tmp 
= strchr(buf
, ' '); 
2630                         *rcs_rev_tmp 
= '\0'; 
2633         fprintf(stderr
, "Bug: %s:%u (%s):%u: %s\n", file
, line
, buf
, saved_errno
, test
); 
2637 loopback_setup_ipv4(void) 
2639         struct ifaliasreq ifra
; 
2643         memset(&ifr
, 0, sizeof(ifr
)); 
2644         strcpy(ifr
.ifr_name
, "lo0"); 
2646         if ((s 
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) 
2649         if (assumes(ioctl(s
, SIOCGIFFLAGS
, &ifr
) != -1)) { 
2650                 ifr
.ifr_flags 
|= IFF_UP
; 
2651                 assumes(ioctl(s
, SIOCSIFFLAGS
, &ifr
) != -1); 
2654         memset(&ifra
, 0, sizeof(ifra
)); 
2655         strcpy(ifra
.ifra_name
, "lo0"); 
2656         ((struct sockaddr_in 
*)&ifra
.ifra_addr
)->sin_family 
= AF_INET
; 
2657         ((struct sockaddr_in 
*)&ifra
.ifra_addr
)->sin_addr
.s_addr 
= htonl(INADDR_LOOPBACK
); 
2658         ((struct sockaddr_in 
*)&ifra
.ifra_addr
)->sin_len 
= sizeof(struct sockaddr_in
); 
2659         ((struct sockaddr_in 
*)&ifra
.ifra_mask
)->sin_family 
= AF_INET
; 
2660         ((struct sockaddr_in 
*)&ifra
.ifra_mask
)->sin_addr
.s_addr 
= htonl(IN_CLASSA_NET
); 
2661         ((struct sockaddr_in 
*)&ifra
.ifra_mask
)->sin_len 
= sizeof(struct sockaddr_in
); 
2663         assumes(ioctl(s
, SIOCAIFADDR
, &ifra
) != -1); 
2665         assumes(close(s
) == 0); 
2669 loopback_setup_ipv6(void) 
2671         struct in6_aliasreq ifra6
; 
2675         memset(&ifr
, 0, sizeof(ifr
)); 
2676         strcpy(ifr
.ifr_name
, "lo0"); 
2678         if ((s6 
= socket(AF_INET6
, SOCK_DGRAM
, 0)) == -1) 
2681         memset(&ifr
, 0, sizeof(ifr
)); 
2682         strcpy(ifr
.ifr_name
, "lo0"); 
2684         if (assumes(ioctl(s6
, SIOCGIFFLAGS
, &ifr
) != -1)) { 
2685                 ifr
.ifr_flags 
|= IFF_UP
; 
2686                 assumes(ioctl(s6
, SIOCSIFFLAGS
, &ifr
) != -1); 
2689         memset(&ifra6
, 0, sizeof(ifra6
)); 
2690         strcpy(ifra6
.ifra_name
, "lo0"); 
2692         ifra6
.ifra_addr
.sin6_family 
= AF_INET6
; 
2693         ifra6
.ifra_addr
.sin6_addr 
= in6addr_loopback
; 
2694         ifra6
.ifra_addr
.sin6_len 
= sizeof(struct sockaddr_in6
); 
2695         ifra6
.ifra_prefixmask
.sin6_family 
= AF_INET6
; 
2696         memset(&ifra6
.ifra_prefixmask
.sin6_addr
, 0xff, sizeof(struct in6_addr
)); 
2697         ifra6
.ifra_prefixmask
.sin6_len 
= sizeof(struct sockaddr_in6
); 
2698         ifra6
.ifra_lifetime
.ia6t_vltime 
= ND6_INFINITE_LIFETIME
; 
2699         ifra6
.ifra_lifetime
.ia6t_pltime 
= ND6_INFINITE_LIFETIME
; 
2701         assumes(ioctl(s6
, SIOCAIFADDR_IN6
, &ifra6
) != -1); 
2703         assumes(close(s6
) == 0); 
2707 fwexec(const char *const *argv
, bool _wait
) 
2712         switch ((p 
= fork())) { 
2719                 execvp(argv
[0], (char *const *)argv
); 
2720                 _exit(EXIT_FAILURE
); 
2725                 if (p 
== waitpid(p
, &wstatus
, 0)) { 
2726                         if (WIFEXITED(wstatus
) && WEXITSTATUS(wstatus
) == EXIT_SUCCESS
) 
2736 do_potential_fsck(void) 
2738         const char *safe_fsck_tool
[] = { "fsck", "-fy", NULL 
}; 
2739         const char *fsck_tool
[] = { "fsck", "-p", NULL 
}; 
2740         const char *remount_tool
[] = { "mount", "-uw", "/", NULL 
}; 
2743         if (!assumes(statfs("/", &sfs
) != -1)) { 
2747         if (!(sfs
.f_flags 
& MNT_RDONLY
)) { 
2751         if (!is_safeboot()) { 
2753                 /* We have disabled this block for now. We need to revisit this optimization after Leopard. */ 
2754                 if (sfs
.f_flags 
& MNT_JOURNALED
) { 
2759                 if (fwexec(fsck_tool
, true) != -1) { 
2764         if (fwexec(safe_fsck_tool
, true) != -1) { 
2768         fprintf(stderr
, "fsck failed!\n"); 
2770         /* someday, we should keep booting read-only, but as of today, other sub-systems cannot handle that scenario */ 
2771         assumes(reboot(RB_HALT
) != -1); 
2776          * Once this is fixed: 
2778          * <rdar://problem/3948774> Mount flag updates should be possible with NULL as the forth argument to mount() 
2780          * We can then do this one system call instead of calling out a full blown process. 
2782          * assumes(mount(sfs.f_fstypename, "/", MNT_UPDATE, NULL) != -1); 
2785         assumes(fwexec(remount_tool
, true) != -1); 
2787         fix_bogus_file_metadata(); 
2791 fix_bogus_file_metadata(void) 
2793         static const struct { 
2797                 const mode_t needed_bits
; 
2798                 const mode_t bad_bits
; 
2800                 { "/sbin/launchd", 0, 0, S_IRUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
, S_ISUID
|S_ISGID
|S_ISVTX
|S_IWOTH 
}, 
2801                 { _PATH_TMP
, 0, 0, S_ISTXT
|S_IRWXU
|S_IRWXG
|S_IRWXO
, S_ISUID
|S_ISGID 
}, 
2802                 { _PATH_VARTMP
, 0, 0, S_ISTXT
|S_IRWXU
|S_IRWXG
|S_IRWXO
, S_ISUID
|S_ISGID 
}, 
2807         for (i 
= 0; i 
< (sizeof(f
) / sizeof(f
[0])); i
++) { 
2808                 mode_t i_needed_bits
; 
2810                 bool fix_mode 
= false; 
2811                 bool fix_id 
= false; 
2813                 if (!assumes(stat(f
[i
].path
, &sb
) != -1)) { 
2817                 i_needed_bits 
= ~sb
.st_mode 
& f
[i
].needed_bits
; 
2818                 i_bad_bits 
= sb
.st_mode 
& f
[i
].bad_bits
; 
2821                         fprintf(stderr
, "Crucial filesystem check: Removing bogus mode bits 0%o on path: %s\n", i_bad_bits
, f
[i
].path
); 
2824                 if (i_needed_bits
) { 
2825                         fprintf(stderr
, "Crucial filesystem check: Adding missing mode bits 0%o on path: %s\n", i_needed_bits
, f
[i
].path
); 
2828                 if (sb
.st_uid 
!= f
[i
].owner
) { 
2829                         fprintf(stderr
, "Crucial filesystem check: Fixing bogus UID %u on path: %s\n", sb
.st_uid
, f
[i
].path
); 
2832                 if (sb
.st_gid 
!= f
[i
].group
) { 
2833                         fprintf(stderr
, "Crucial filesystem check: Fixing bogus GID %u on path: %s\n", sb
.st_gid
, f
[i
].path
); 
2838                         assumes(chmod(f
[i
].path
, (sb
.st_mode 
& ~i_bad_bits
) | i_needed_bits
) != -1); 
2841                         assumes(chown(f
[i
].path
, f
[i
].owner
, f
[i
].group
) != -1); 
2847 path_check(const char *path
) 
2851         if (stat(path
, &sb
) == 0) 
2859         int sbmib
[] = { CTL_KERN
, KERN_SAFEBOOT 
}; 
2861         size_t sbsz 
= sizeof(sb
); 
2863         if (!assumes(sysctl(sbmib
, 2, &sb
, &sbsz
, NULL
, 0) == 0)) 
2872         int nbmib
[] = { CTL_KERN
, KERN_NETBOOT 
}; 
2874         size_t nbsz 
= sizeof(nb
); 
2876         if (!assumes(sysctl(nbmib
, 2, &nb
, &nbsz
, NULL
, 0) == 0)) 
2883 empty_dir(const char *thedir
, struct stat 
*psb
) 
2892                 if (!assumes(lstat(thedir
, psb
) != -1)) { 
2897         if (!assumes((currend_dir_fd 
= open(".", 0)) != -1)) { 
2901         if (!assumes(chdir(thedir
) != -1)) { 
2905         if (!assumes(od 
= opendir("."))) { 
2909         while ((de 
= readdir(od
))) { 
2912                 if (strcmp(de
->d_name
, ".") == 0) { 
2916                 if (strcmp(de
->d_name
, "..") == 0) { 
2920                 if (!assumes(lstat(de
->d_name
, &sb
) != -1)) { 
2924                 if (psb
->st_dev 
!= sb
.st_dev
) { 
2925                         assumes(unmount(de
->d_name
, MNT_FORCE
) != -1); 
2927                         /* Let's lstat() again to see if the unmount() worked and what was under it */ 
2928                         if (!assumes(lstat(de
->d_name
, &sb
) != -1)) { 
2932                         if (!assumes(psb
->st_dev 
== sb
.st_dev
)) { 
2937                 if (S_ISDIR(sb
.st_mode
)) { 
2938                         empty_dir(de
->d_name
, &sb
); 
2941                 assumes(lchflags(de
->d_name
, 0) != -1); 
2942                 assumes(remove(de
->d_name
) != -1); 
2945         assumes(closedir(od
) != -1); 
2948         assumes(fchdir(currend_dir_fd
) != -1); 
2949         assumes(close(currend_dir_fd
) != -1); 
2953 touch_file(const char *path
, mode_t m
) 
2955         int fd 
= open(path
, O_CREAT
, m
); 
2964 apply_sysctls_from_file(const char *thefile
) 
2966         const char *sysctl_tool
[] = { "sysctl", "-w", NULL
, NULL 
}; 
2971         if (!(sf 
= fopen(thefile
, "r"))) 
2974         while ((val 
= fgetln(sf
, &ln_len
))) { 
2978                 if (!assumes((tmpstr 
= malloc(ln_len 
+ 1)) != NULL
)) { 
2981                 memcpy(tmpstr
, val
, ln_len
); 
2985                 if (val
[ln_len 
- 1] == '\n' || val
[ln_len 
- 1] == '\r') { 
2986                         val
[ln_len 
- 1] = '\0'; 
2989                 while (*val 
&& isspace(*val
)) 
2991                 if (*val 
== '\0' || *val 
== '#') { 
2992                         goto skip_sysctl_tool
; 
2994                 sysctl_tool
[2] = val
; 
2995                 assumes(fwexec(sysctl_tool
, true) != -1); 
3000         assumes(fclose(sf
) == 0); 
3004 do_sysversion_sysctl(void) 
3006         int mib
[] = { CTL_KERN
, KERN_OSVERSION 
}; 
3007         CFDictionaryRef versdict
; 
3008         CFStringRef buildvers
; 
3010         size_t bufsz 
= sizeof(buf
); 
3012         /* <rdar://problem/4477682> ER: launchd should set kern.osversion very early in boot */ 
3014         if (sysctl(mib
, 2, buf
, &bufsz
, NULL
, 0) == -1) { 
3015                 fprintf(stderr
, "sysctl(): %s\n", strerror(errno
)); 
3019         if (buf
[0] != '\0') { 
3023         if (!assumes((versdict 
= _CFCopySystemVersionDictionary()))) { 
3027         if (assumes((buildvers 
= CFDictionaryGetValue(versdict
, _kCFSystemVersionBuildVersionKey
)))) { 
3028                 CFStringGetCString(buildvers
, buf
, sizeof(buf
), kCFStringEncodingUTF8
); 
3030                 assumes(sysctl(mib
, 2, NULL
, 0, buf
, strlen(buf
) + 1) != -1); 
3033         CFRelease(versdict
); 
3037 do_application_firewall_magic(int sfd
, launch_data_t thejob
) 
3039         const char *prog 
= NULL
, *partialprog 
= NULL
; 
3040         char *path
, *pathtmp
, **pathstmp
; 
3046          * <rdar://problem/4684434> setsockopt() with the executable path as the argument 
3049         if ((tmp 
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_PROGRAM
))) { 
3050                 prog 
= launch_data_get_string(tmp
); 
3054                 if ((tmp 
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_PROGRAMARGUMENTS
))) { 
3055                         if ((tmp 
= launch_data_array_get_index(tmp
, 0))) { 
3056                                 if (assumes((partialprog 
= launch_data_get_string(tmp
)) != NULL
)) { 
3057                                         if (partialprog
[0] == '/') { 
3066                 pathtmp 
= path 
= strdup(getenv("PATH")); 
3070                 while ((*pathstmp 
= strsep(&pathtmp
, ":"))) { 
3071                         if (**pathstmp 
!= '\0') { 
3077                 pathtmp 
= alloca(MAXPATHLEN
); 
3081                 for (; *pathstmp
; pathstmp
++) { 
3082                         snprintf(pathtmp
, MAXPATHLEN
, "%s/%s", *pathstmp
, partialprog
); 
3083                         if (path_check(pathtmp
)) { 
3090         if (assumes(prog 
!= NULL
)) { 
3091                 /* The networking team has asked us to ignore the failure of this API if errno == ENOPROTOOPT */ 
3092                 assumes(setsockopt(sfd
, SOL_SOCKET
, SO_EXECPATH
, prog
, strlen(prog
) + 1) != -1 || errno 
== ENOPROTOOPT
); 
3098 preheat_page_cache_hack(void) 
3103         /* Disable this hack for now */ 
3106         if ((thedir 
= opendir("/etc/preheat_at_boot")) == NULL
) { 
3110         while ((de 
= readdir(thedir
))) { 
3115                 if (de
->d_name
[0] == '.') { 
3119                 if ((fd 
= open(de
->d_name
, O_RDONLY
)) == -1) { 
3123                 if (fstat(fd
, &sb
) != -1) {  
3124                         if ((sb
.st_size 
< 10*1024*1024) && (junkbuf 
= malloc((size_t)sb
.st_size
)) != NULL
) { 
3125                                 assumes(read(fd
, junkbuf
, (size_t)sb
.st_size
) == (ssize_t
)sb
.st_size
); 
3138 do_bootroot_magic(void) 
3140         const char *kextcache_tool
[] = { "kextcache", "-U", "/", NULL 
}; 
3141         CFTypeRef bootrootProp
; 
3142         io_service_t chosen
; 
3146         chosen 
= IORegistryEntryFromPath(kIOMasterPortDefault
, "IODeviceTree:/chosen"); 
3148         if (!assumes(chosen
)) { 
3152         bootrootProp 
= IORegistryEntryCreateCFProperty(chosen
, CFSTR(kBootRootActiveKey
), kCFAllocatorDefault
, 0); 
3154         IOObjectRelease(chosen
); 
3156         if (!bootrootProp
) { 
3160         CFRelease(bootrootProp
); 
3162         if (!assumes((p 
= fwexec(kextcache_tool
, false)) != -1)) { 
3166         if (!assumes(waitpid(p
, &wstatus
, 0) != -1)) { 
3170         if (WIFEXITED(wstatus
) && WEXITSTATUS(wstatus
) == EX_OSFILE
) { 
3171                 assumes(reboot(RB_AUTOBOOT
) != -1);