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: 23792 $";
24 #include "launch_priv.h"
25 #include "bootstrap.h"
27 #include "vproc_priv.h"
28 #include "vproc_internal.h"
30 #include <CoreFoundation/CoreFoundation.h>
31 #include <CoreFoundation/CFPriv.h>
32 #include <TargetConditionals.h>
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>
73 #include <bootfiles.h>
78 #define LAUNCH_SECDIR "/tmp/launch-XXXXXX"
80 #define MACHINIT_JOBKEY_ONDEMAND "OnDemand"
81 #define MACHINIT_JOBKEY_SERVICENAME "ServiceName"
82 #define MACHINIT_JOBKEY_COMMAND "Command"
83 #define MACHINIT_JOBKEY_SERVERPORT "ServerPort"
84 #define MACHINIT_JOBKEY_SERVICEPORT "ServicePort"
87 (__builtin_expect(!(e), 0) ? _log_launchctl_bug(__rcs_file_version__, __FILE__, __LINE__, #e), false : true)
90 struct load_unload_state
{
95 unsigned int editondisk
:1, load
:1, forceload
:1, __pad
:29;
98 static void myCFDictionaryApplyFunction(const void *key
, const void *value
, void *context
);
99 static bool launch_data_array_append(launch_data_t a
, launch_data_t o
);
100 static void distill_jobs(launch_data_t
);
101 static void distill_config_file(launch_data_t
);
102 static void sock_dict_cb(launch_data_t what
, const char *key
, void *context
);
103 static void sock_dict_edit_entry(launch_data_t tmp
, const char *key
, launch_data_t fdarray
, launch_data_t thejob
);
104 static launch_data_t
CF2launch_data(CFTypeRef
);
105 static launch_data_t
read_plist_file(const char *file
, bool editondisk
, bool load
);
106 static CFPropertyListRef
CreateMyPropertyListFromFile(const char *);
107 static void WriteMyPropertyListToFile(CFPropertyListRef
, const char *);
108 static bool path_goodness_check(const char *path
, bool forceload
);
109 static void readpath(const char *, struct load_unload_state
*);
110 static void readfile(const char *, struct load_unload_state
*);
112 static int demux_cmd(int argc
, char *const argv
[]);
113 static launch_data_t
do_rendezvous_magic(const struct addrinfo
*res
, const char *serv
);
114 static void submit_job_pass(launch_data_t jobs
);
115 static void submit_mach_jobs(launch_data_t jobs
);
116 static void let_go_of_mach_jobs(launch_data_t jobs
);
117 static void do_mgroup_join(int fd
, int family
, int socktype
, int protocol
, const char *mgroup
);
118 static mach_port_t
str2bsport(const char *s
);
119 static void print_jobs(launch_data_t j
, const char *key
, void *context
);
120 static void print_obj(launch_data_t obj
, const char *key
, void *context
);
121 static bool is_legacy_mach_job(launch_data_t obj
);
122 static bool delay_to_second_pass(launch_data_t o
);
123 static void delay_to_second_pass2(launch_data_t o
, const char *key
, void *context
);
124 static bool str2lim(const char *buf
, rlim_t
*res
);
125 static const char *lim2str(rlim_t val
, char *buf
);
126 static const char *num2name(int n
);
127 static ssize_t
name2num(const char *n
);
128 static void unloadjob(launch_data_t job
);
129 static void print_key_value(launch_data_t obj
, const char *key
, void *context
);
130 static void print_launchd_env(launch_data_t obj
, const char *key
, void *context
);
131 static void _log_launchctl_bug(const char *rcs_rev
, const char *path
, unsigned int line
, const char *test
);
132 static void loopback_setup_ipv4(void);
133 static void loopback_setup_ipv6(void);
134 static pid_t
fwexec(const char *const *argv
, bool _wait
);
135 static void do_potential_fsck(void);
136 static bool path_check(const char *path
);
137 static bool is_safeboot(void);
138 static bool is_netboot(void);
139 static void apply_sysctls_from_file(const char *thefile
);
140 static void empty_dir(const char *thedir
, struct stat
*psb
);
141 static int touch_file(const char *path
, mode_t m
);
142 static void do_sysversion_sysctl(void);
143 static void do_application_firewall_magic(int sfd
, launch_data_t thejob
);
144 static void preheat_page_cache_hack(void);
145 static void do_bootroot_magic(void);
146 static void do_single_user_mode(bool);
147 static bool do_single_user_mode2(void);
148 static void read_launchd_conf(void);
149 static bool job_disabled_logic(launch_data_t obj
);
150 static void fix_bogus_file_metadata(void);
156 } BootCache_action_t
;
158 static void do_BootCache_magic(BootCache_action_t what
);
160 static int bootstrap_cmd(int argc
, char *const argv
[]);
161 static int load_and_unload_cmd(int argc
, char *const argv
[]);
162 //static int reload_cmd(int argc, char *const argv[]);
163 static int start_stop_remove_cmd(int argc
, char *const argv
[]);
164 static int submit_cmd(int argc
, char *const argv
[]);
165 static int list_cmd(int argc
, char *const argv
[]);
167 static int setenv_cmd(int argc
, char *const argv
[]);
168 static int unsetenv_cmd(int argc
, char *const argv
[]);
169 static int getenv_and_export_cmd(int argc
, char *const argv
[]);
171 static int limit_cmd(int argc
, char *const argv
[]);
172 static int stdio_cmd(int argc
, char *const argv
[]);
173 static int fyi_cmd(int argc
, char *const argv
[]);
174 static int logupdate_cmd(int argc
, char *const argv
[]);
175 static int umask_cmd(int argc
, char *const argv
[]);
176 static int getrusage_cmd(int argc
, char *const argv
[]);
177 static int bsexec_cmd(int argc
, char *const argv
[]);
178 static int bslist_cmd(int argc
, char *const argv
[]);
180 static int exit_cmd(int argc
, char *const argv
[]) __attribute__((noreturn
));
181 static int help_cmd(int argc
, char *const argv
[]);
183 static const struct {
185 int (*func
)(int argc
, char *const argv
[]);
188 { "load", load_and_unload_cmd
, "Load configuration files and/or directories" },
189 { "unload", load_and_unload_cmd
, "Unload configuration files and/or directories" },
190 // { "reload", reload_cmd, "Reload configuration files and/or directories" },
191 { "start", start_stop_remove_cmd
, "Start specified job" },
192 { "stop", start_stop_remove_cmd
, "Stop specified job" },
193 { "submit", submit_cmd
, "Submit a job from the command line" },
194 { "remove", start_stop_remove_cmd
, "Remove specified job" },
195 { "bootstrap", bootstrap_cmd
, "Bootstrap launchd" },
196 { "list", list_cmd
, "List jobs and information about jobs" },
197 { "setenv", setenv_cmd
, "Set an environmental variable in launchd" },
198 { "unsetenv", unsetenv_cmd
, "Unset an environmental variable in launchd" },
199 { "getenv", getenv_and_export_cmd
, "Get an environmental variable from launchd" },
200 { "export", getenv_and_export_cmd
, "Export shell settings from launchd" },
201 { "limit", limit_cmd
, "View and adjust launchd resource limits" },
202 { "stdout", stdio_cmd
, "Redirect launchd's standard out to the given path" },
203 { "stderr", stdio_cmd
, "Redirect launchd's standard error to the given path" },
204 { "shutdown", fyi_cmd
, "Prepare for system shutdown" },
205 { "singleuser", fyi_cmd
, "Switch to single-user mode" },
206 { "getrusage", getrusage_cmd
, "Get resource usage statistics from launchd" },
207 { "log", logupdate_cmd
, "Adjust the logging level or mask of launchd" },
208 { "umask", umask_cmd
, "Change launchd's umask" },
209 { "bsexec", bsexec_cmd
, "Execute a process within a different Mach bootstrap subset" },
210 { "bslist", bslist_cmd
, "List Mach bootstrap services and optional servers" },
211 { "exit", exit_cmd
, "Exit the interactive invocation of launchctl" },
212 { "quit", exit_cmd
, "Quit the interactive invocation of launchctl" },
213 { "help", help_cmd
, "This help output" },
218 static bool is_managed
;
221 main(int argc
, char *const argv
[])
223 int64_t is_managed_val
= 0;
226 if (vproc_swap_integer(NULL
, VPROC_GSK_IS_MANAGED
, NULL
, &is_managed_val
) == NULL
&& is_managed_val
) {
230 if (getuid() == 0 && !is_managed
) {
231 mach_port_t root_bs
= str2bsport("/");
232 task_set_bootstrap_port(mach_task_self(), root_bs
);
233 mach_port_deallocate(mach_task_self(), bootstrap_port
);
234 bootstrap_port
= root_bs
;
237 istty
= isatty(STDIN_FILENO
);
241 if (argc
> 0 && argv
[0][0] == '-') {
244 for (flago
= argv
[0] + 1; *flago
; flago
++) {
250 fprintf(stderr
, "Unknown argument: '-%c'\n", *flago
);
257 if (NULL
== readline
) {
258 fprintf(stderr
, "missing library: readline\n");
263 while ((l
= readline(istty
? "launchd% " : NULL
))) {
264 char *inputstring
= l
, *argv2
[100], **ap
= argv2
;
267 while ((*ap
= strsep(&inputstring
, " \t"))) {
287 exit(demux_cmd(argc
, argv
));
294 demux_cmd(int argc
, char *const argv
[])
301 for (i
= 0; i
< (sizeof cmds
/ sizeof cmds
[0]); i
++) {
302 if (!strcmp(cmds
[i
].name
, argv
[0])) {
303 return cmds
[i
].func(argc
, argv
);
307 fprintf(stderr
, "%s: unknown subcommand \"%s\"\n", getprogname(), argv
[0]);
312 read_launchd_conf(void)
314 char s
[1000], *c
, *av
[100];
319 if (getppid() == 1) {
320 file
= "/etc/launchd.conf";
322 file
= "/etc/launchd-user.conf";
325 if (!(f
= fopen(file
, "r"))) {
329 while ((c
= fgets(s
, sizeof(s
), f
))) {
331 if (len
&& c
[len
- 1] == '\n') {
337 while ((av
[i
] = strsep(&c
, " \t"))) {
338 if (*(av
[i
]) != '\0') {
352 unsetenv_cmd(int argc
, char *const argv
[])
354 launch_data_t resp
, tmp
, msg
;
357 fprintf(stderr
, "%s usage: unsetenv <key>\n", getprogname());
361 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
363 tmp
= launch_data_new_string(argv
[1]);
364 launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_UNSETUSERENVIRONMENT
);
366 resp
= launch_msg(msg
);
368 launch_data_free(msg
);
371 launch_data_free(resp
);
373 fprintf(stderr
, "launch_msg(\"%s\"): %s\n", LAUNCH_KEY_UNSETUSERENVIRONMENT
, strerror(errno
));
380 setenv_cmd(int argc
, char *const argv
[])
382 launch_data_t resp
, tmp
, tmpv
, msg
;
385 fprintf(stderr
, "%s usage: setenv <key> <value>\n", getprogname());
389 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
390 tmp
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
392 tmpv
= launch_data_new_string(argv
[2]);
393 launch_data_dict_insert(tmp
, tmpv
, argv
[1]);
394 launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_SETUSERENVIRONMENT
);
396 resp
= launch_msg(msg
);
397 launch_data_free(msg
);
400 launch_data_free(resp
);
402 fprintf(stderr
, "launch_msg(\"%s\"): %s\n", LAUNCH_KEY_SETUSERENVIRONMENT
, strerror(errno
));
409 print_launchd_env(launch_data_t obj
, const char *key
, void *context
)
411 bool *is_csh
= context
;
413 /* XXX escape the double quotes */
415 fprintf(stdout
, "setenv %s \"%s\";\n", key
, launch_data_get_string(obj
));
417 fprintf(stdout
, "%s=\"%s\"; export %s;\n", key
, launch_data_get_string(obj
), key
);
422 print_key_value(launch_data_t obj
, const char *key
, void *context
)
424 const char *k
= context
;
426 if (!strcmp(key
, k
)) {
427 fprintf(stdout
, "%s\n", launch_data_get_string(obj
));
432 getenv_and_export_cmd(int argc
, char *const argv
[])
438 if (!strcmp(argv
[0], "export")) {
439 char *s
= getenv("SHELL");
441 is_csh
= strstr(s
, "csh") ? true : false;
443 } else if (argc
!= 2) {
444 fprintf(stderr
, "%s usage: getenv <key>\n", getprogname());
450 if (vproc_swap_complex(NULL
, VPROC_GSK_ENVIRONMENT
, NULL
, &resp
) == NULL
) {
451 if (!strcmp(argv
[0], "export")) {
452 launch_data_dict_iterate(resp
, print_launchd_env
, &is_csh
);
454 launch_data_dict_iterate(resp
, print_key_value
, k
);
456 launch_data_free(resp
);
466 unloadjob(launch_data_t job
)
470 tmps
= launch_data_dict_lookup(job
, LAUNCH_JOBKEY_LABEL
);
473 fprintf(stderr
, "%s: Error: Missing Key: %s\n", getprogname(), LAUNCH_JOBKEY_LABEL
);
477 if (_vproc_send_signal_by_label(launch_data_get_string(tmps
), VPROC_MAGIC_UNLOAD_SIGNAL
) != NULL
) {
478 fprintf(stderr
, "%s: Error unloading: %s\n", getprogname(), launch_data_get_string(tmps
));
483 read_plist_file(const char *file
, bool editondisk
, bool load
)
485 CFPropertyListRef plist
= CreateMyPropertyListFromFile(file
);
486 launch_data_t r
= NULL
;
489 fprintf(stderr
, "%s: no plist was returned for: %s\n", getprogname(), file
);
495 CFDictionaryRemoveValue((CFMutableDictionaryRef
)plist
, CFSTR(LAUNCH_JOBKEY_DISABLED
));
497 CFDictionarySetValue((CFMutableDictionaryRef
)plist
, CFSTR(LAUNCH_JOBKEY_DISABLED
), kCFBooleanTrue
);
499 WriteMyPropertyListToFile(plist
, file
);
502 r
= CF2launch_data(plist
);
510 delay_to_second_pass2(launch_data_t o
, const char *key
, void *context
)
515 if (key
&& 0 == strcmp(key
, LAUNCH_JOBSOCKETKEY_BONJOUR
)) {
520 switch (launch_data_get_type(o
)) {
521 case LAUNCH_DATA_DICTIONARY
:
522 launch_data_dict_iterate(o
, delay_to_second_pass2
, context
);
524 case LAUNCH_DATA_ARRAY
:
525 for (i
= 0; i
< launch_data_array_get_count(o
); i
++) {
526 delay_to_second_pass2(launch_data_array_get_index(o
, i
), NULL
, context
);
535 delay_to_second_pass(launch_data_t o
)
539 launch_data_t socks
= launch_data_dict_lookup(o
, LAUNCH_JOBKEY_SOCKETS
);
545 delay_to_second_pass2(socks
, NULL
, &res
);
551 readfile(const char *what
, struct load_unload_state
*lus
)
553 char ourhostname
[1024];
554 launch_data_t tmpd
, tmps
, thejob
, tmpa
;
555 bool job_disabled
= false;
558 gethostname(ourhostname
, sizeof(ourhostname
));
560 if (NULL
== (thejob
= read_plist_file(what
, lus
->editondisk
, lus
->load
))) {
561 fprintf(stderr
, "%s: no plist was returned for: %s\n", getprogname(), what
);
565 if (is_legacy_mach_job(thejob
)) {
566 fprintf(stderr
, "%s: Please convert the following to launchd: %s\n", getprogname(), what
);
567 launch_data_array_append(lus
->pass0
, thejob
);
571 if (NULL
== launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LABEL
)) {
572 fprintf(stderr
, "%s: missing the Label key: %s\n", getprogname(), what
);
576 if (NULL
!= (tmpa
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LIMITLOADFROMHOSTS
))) {
577 c
= launch_data_array_get_count(tmpa
);
579 for (i
= 0; i
< c
; i
++) {
580 launch_data_t oai
= launch_data_array_get_index(tmpa
, i
);
581 if (!strcasecmp(ourhostname
, launch_data_get_string(oai
))) {
587 if (NULL
!= (tmpa
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LIMITLOADTOHOSTS
))) {
588 c
= launch_data_array_get_count(tmpa
);
590 for (i
= 0; i
< c
; i
++) {
591 launch_data_t oai
= launch_data_array_get_index(tmpa
, i
);
592 if (!strcasecmp(ourhostname
, launch_data_get_string(oai
))) {
602 if (lus
->session_type
&& !(tmpa
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE
))) {
603 tmpa
= launch_data_new_string("Aqua");
604 launch_data_dict_insert(thejob
, tmpa
, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE
);
607 if ((tmpa
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE
))) {
608 const char *allowed_session
;
611 if (lus
->session_type
) switch (launch_data_get_type(tmpa
)) {
612 case LAUNCH_DATA_ARRAY
:
613 c
= launch_data_array_get_count(tmpa
);
614 for (i
= 0; i
< c
; i
++) {
615 tmps
= launch_data_array_get_index(tmpa
, i
);
616 allowed_session
= launch_data_get_string(tmps
);
617 if (strcasecmp(lus
->session_type
, allowed_session
) == 0) {
619 /* we have to do the following so job_reparent_hack() works within launchd */
620 tmpa
= launch_data_new_string(lus
->session_type
);
621 launch_data_dict_insert(thejob
, tmpa
, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE
);
626 case LAUNCH_DATA_STRING
:
627 allowed_session
= launch_data_get_string(tmpa
);
628 if (strcasecmp(lus
->session_type
, allowed_session
) == 0) {
641 if ((tmpd
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_DISABLED
))) {
642 job_disabled
= job_disabled_logic(tmpd
);
645 if (lus
->forceload
) {
646 job_disabled
= false;
649 if (job_disabled
&& lus
->load
) {
653 if (delay_to_second_pass(thejob
)) {
654 launch_data_array_append(lus
->pass2
, thejob
);
656 launch_data_array_append(lus
->pass1
, thejob
);
660 fprintf(stdout
, "Will load: %s\n", what
);
666 fprintf(stdout
, "Ignored: %s\n", what
);
668 launch_data_free(thejob
);
672 sysctl_hw_streq(int mib_slot
, const char *str
)
675 size_t bufsz
= sizeof(buf
);
676 int mib
[] = { CTL_HW
, mib_slot
};
678 if (sysctl(mib
, 2, buf
, &bufsz
, NULL
, 0) != -1) {
679 if (strcmp(buf
, str
) == 0) {
688 job_disabled_dict_logic(launch_data_t obj
, const char *key
, void *context
)
692 if (launch_data_get_type(obj
) != LAUNCH_DATA_STRING
) {
696 if (strcasecmp(key
, LAUNCH_JOBKEY_DISABLED_MACHINETYPE
) == 0) {
697 if (sysctl_hw_streq(HW_MACHINE
, launch_data_get_string(obj
))) {
700 } else if (strcasecmp(key
, LAUNCH_JOBKEY_DISABLED_MODELNAME
) == 0) {
701 if (sysctl_hw_streq(HW_MODEL
, launch_data_get_string(obj
))) {
708 job_disabled_logic(launch_data_t obj
)
712 switch (launch_data_get_type(obj
)) {
713 case LAUNCH_DATA_DICTIONARY
:
714 launch_data_dict_iterate(obj
, job_disabled_dict_logic
, &r
);
716 case LAUNCH_DATA_BOOL
:
717 r
= launch_data_get_bool(obj
);
727 path_goodness_check(const char *path
, bool forceload
)
731 if (stat(path
, &sb
) == -1) {
732 fprintf(stderr
, "%s: Couldn't stat(\"%s\"): %s\n", getprogname(), path
, strerror(errno
));
740 if (sb
.st_mode
& (S_IWOTH
|S_IWGRP
)) {
741 fprintf(stderr
, "%s: Dubious permissions on file (skipping): %s\n", getprogname(), path
);
745 if (sb
.st_uid
!= 0 && sb
.st_uid
!= getuid()) {
746 fprintf(stderr
, "%s: Dubious ownership on file (skipping): %s\n", getprogname(), path
);
750 if (!(S_ISREG(sb
.st_mode
) || S_ISDIR(sb
.st_mode
))) {
751 fprintf(stderr
, "%s: Dubious path. Not a regular file or directory (skipping): %s\n", getprogname(), path
);
759 readpath(const char *what
, struct load_unload_state
*lus
)
761 char buf
[MAXPATHLEN
];
766 if (!path_goodness_check(what
, lus
->forceload
)) {
770 if (stat(what
, &sb
) == -1) {
774 if (S_ISREG(sb
.st_mode
)) {
776 } else if (S_ISDIR(sb
.st_mode
)) {
777 if ((d
= opendir(what
)) == NULL
) {
778 fprintf(stderr
, "%s: opendir() failed to open the directory\n", getprogname());
782 while ((de
= readdir(d
))) {
783 if ((de
->d_name
[0] == '.')) {
786 snprintf(buf
, sizeof(buf
), "%s/%s", what
, de
->d_name
);
788 if (!path_goodness_check(buf
, lus
->forceload
)) {
798 struct distill_context
{
800 launch_data_t newsockdict
;
804 distill_jobs(launch_data_t jobs
)
806 size_t i
, c
= launch_data_array_get_count(jobs
);
808 for (i
= 0; i
< c
; i
++)
809 distill_config_file(launch_data_array_get_index(jobs
, i
));
813 distill_config_file(launch_data_t id_plist
)
815 struct distill_context dc
= { id_plist
, NULL
};
818 if ((tmp
= launch_data_dict_lookup(dc
.base
, LAUNCH_JOBKEY_SOCKETS
))) {
819 dc
.newsockdict
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
820 launch_data_dict_iterate(tmp
, sock_dict_cb
, &dc
);
821 launch_data_dict_insert(dc
.base
, dc
.newsockdict
, LAUNCH_JOBKEY_SOCKETS
);
826 sock_dict_cb(launch_data_t what
, const char *key
, void *context
)
828 struct distill_context
*dc
= context
;
829 launch_data_t fdarray
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
831 launch_data_dict_insert(dc
->newsockdict
, fdarray
, key
);
833 if (launch_data_get_type(what
) == LAUNCH_DATA_DICTIONARY
) {
834 sock_dict_edit_entry(what
, key
, fdarray
, dc
->base
);
835 } else if (launch_data_get_type(what
) == LAUNCH_DATA_ARRAY
) {
839 for (i
= 0; i
< launch_data_array_get_count(what
); i
++) {
840 tmp
= launch_data_array_get_index(what
, i
);
841 sock_dict_edit_entry(tmp
, key
, fdarray
, dc
->base
);
847 sock_dict_edit_entry(launch_data_t tmp
, const char *key
, launch_data_t fdarray
, launch_data_t thejob
)
849 launch_data_t a
, val
;
850 int sfd
, st
= SOCK_STREAM
;
853 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_TYPE
))) {
854 if (!strcasecmp(launch_data_get_string(val
), "stream")) {
856 } else if (!strcasecmp(launch_data_get_string(val
), "dgram")) {
858 } else if (!strcasecmp(launch_data_get_string(val
), "seqpacket")) {
863 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_PASSIVE
))) {
864 passive
= launch_data_get_bool(val
);
867 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_SECUREWITHKEY
))) {
868 char secdir
[] = LAUNCH_SECDIR
, buf
[1024];
869 launch_data_t uenv
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES
);
872 uenv
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
873 launch_data_dict_insert(thejob
, uenv
, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES
);
878 sprintf(buf
, "%s/%s", secdir
, key
);
880 a
= launch_data_new_string(buf
);
881 launch_data_dict_insert(tmp
, a
, LAUNCH_JOBSOCKETKEY_PATHNAME
);
882 a
= launch_data_new_string(buf
);
883 launch_data_dict_insert(uenv
, a
, launch_data_get_string(val
));
886 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_PATHNAME
))) {
887 struct sockaddr_un sun
;
892 memset(&sun
, 0, sizeof(sun
));
894 sun
.sun_family
= AF_UNIX
;
896 strncpy(sun
.sun_path
, launch_data_get_string(val
), sizeof(sun
.sun_path
));
898 if ((sfd
= _fd(socket(AF_UNIX
, st
, 0))) == -1) {
902 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_PATHMODE
))) {
903 sun_mode
= (mode_t
)launch_data_get_integer(val
);
908 if (unlink(sun
.sun_path
) == -1 && errno
!= ENOENT
) {
912 oldmask
= umask(S_IRWXG
|S_IRWXO
);
913 if (bind(sfd
, (struct sockaddr
*)&sun
, sizeof(sun
)) == -1) {
920 chmod(sun
.sun_path
, sun_mode
);
922 if ((st
== SOCK_STREAM
|| st
== SOCK_SEQPACKET
) && listen(sfd
, SOMAXCONN
) == -1) {
926 } else if (connect(sfd
, (struct sockaddr
*)&sun
, sizeof(sun
)) == -1) {
931 val
= launch_data_new_fd(sfd
);
932 launch_data_array_append(fdarray
, val
);
934 launch_data_t rnames
= NULL
;
935 const char *node
= NULL
, *serv
= NULL
, *mgroup
= NULL
;
937 struct addrinfo hints
, *res0
, *res
;
938 int gerr
, sock_opt
= 1;
939 bool rendezvous
= false;
941 memset(&hints
, 0, sizeof(hints
));
943 hints
.ai_socktype
= st
;
945 hints
.ai_flags
|= AI_PASSIVE
;
948 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_NODENAME
))) {
949 node
= launch_data_get_string(val
);
951 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_MULTICASTGROUP
))) {
952 mgroup
= launch_data_get_string(val
);
954 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_SERVICENAME
))) {
955 if (LAUNCH_DATA_INTEGER
== launch_data_get_type(val
)) {
956 sprintf(servnbuf
, "%lld", launch_data_get_integer(val
));
959 serv
= launch_data_get_string(val
);
962 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_FAMILY
))) {
963 if (!strcasecmp("IPv4", launch_data_get_string(val
))) {
964 hints
.ai_family
= AF_INET
;
965 } else if (!strcasecmp("IPv6", launch_data_get_string(val
))) {
966 hints
.ai_family
= AF_INET6
;
969 if ((val
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_PROTOCOL
))) {
970 if (!strcasecmp("TCP", launch_data_get_string(val
))) {
971 hints
.ai_protocol
= IPPROTO_TCP
;
972 } else if (!strcasecmp("UDP", launch_data_get_string(val
))) {
973 hints
.ai_protocol
= IPPROTO_UDP
;
976 if ((rnames
= launch_data_dict_lookup(tmp
, LAUNCH_JOBSOCKETKEY_BONJOUR
))) {
978 if (LAUNCH_DATA_BOOL
== launch_data_get_type(rnames
)) {
979 rendezvous
= launch_data_get_bool(rnames
);
984 if ((gerr
= getaddrinfo(node
, serv
, &hints
, &res0
)) != 0) {
985 fprintf(stderr
, "getaddrinfo(): %s\n", gai_strerror(gerr
));
989 for (res
= res0
; res
; res
= res
->ai_next
) {
990 launch_data_t rvs_fd
= NULL
;
991 if ((sfd
= _fd(socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
))) == -1) {
992 fprintf(stderr
, "socket(): %s\n", strerror(errno
));
996 do_application_firewall_magic(sfd
, thejob
);
998 if (hints
.ai_flags
& AI_PASSIVE
) {
999 if (AF_INET6
== res
->ai_family
&& -1 == setsockopt(sfd
, IPPROTO_IPV6
, IPV6_V6ONLY
,
1000 (void *)&sock_opt
, sizeof(sock_opt
))) {
1001 fprintf(stderr
, "setsockopt(IPV6_V6ONLY): %m");
1005 if (setsockopt(sfd
, SOL_SOCKET
, SO_REUSEPORT
, (void *)&sock_opt
, sizeof(sock_opt
)) == -1) {
1006 fprintf(stderr
, "setsockopt(SO_REUSEPORT): %s\n", strerror(errno
));
1010 if (setsockopt(sfd
, SOL_SOCKET
, SO_REUSEADDR
, (void *)&sock_opt
, sizeof(sock_opt
)) == -1) {
1011 fprintf(stderr
, "setsockopt(SO_REUSEADDR): %s\n", strerror(errno
));
1015 if (bind(sfd
, res
->ai_addr
, res
->ai_addrlen
) == -1) {
1016 fprintf(stderr
, "bind(): %s\n", strerror(errno
));
1019 /* The kernel may have dynamically assigned some part of the
1020 * address. (The port being a common example.)
1022 if (getsockname(sfd
, res
->ai_addr
, &res
->ai_addrlen
) == -1) {
1023 fprintf(stderr
, "getsockname(): %s\n", strerror(errno
));
1028 do_mgroup_join(sfd
, res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
, mgroup
);
1030 if ((res
->ai_socktype
== SOCK_STREAM
|| res
->ai_socktype
== SOCK_SEQPACKET
) && listen(sfd
, SOMAXCONN
) == -1) {
1031 fprintf(stderr
, "listen(): %s\n", strerror(errno
));
1034 if (rendezvous
&& (res
->ai_family
== AF_INET
|| res
->ai_family
== AF_INET6
) &&
1035 (res
->ai_socktype
== SOCK_STREAM
|| res
->ai_socktype
== SOCK_DGRAM
)) {
1036 launch_data_t rvs_fds
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_BONJOURFDS
);
1037 if (NULL
== rvs_fds
) {
1038 rvs_fds
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
1039 launch_data_dict_insert(thejob
, rvs_fds
, LAUNCH_JOBKEY_BONJOURFDS
);
1041 if (NULL
== rnames
) {
1042 rvs_fd
= do_rendezvous_magic(res
, serv
);
1044 launch_data_array_append(rvs_fds
, rvs_fd
);
1046 } else if (LAUNCH_DATA_STRING
== launch_data_get_type(rnames
)) {
1047 rvs_fd
= do_rendezvous_magic(res
, launch_data_get_string(rnames
));
1049 launch_data_array_append(rvs_fds
, rvs_fd
);
1051 } else if (LAUNCH_DATA_ARRAY
== launch_data_get_type(rnames
)) {
1052 size_t rn_i
, rn_ac
= launch_data_array_get_count(rnames
);
1054 for (rn_i
= 0; rn_i
< rn_ac
; rn_i
++) {
1055 launch_data_t rn_tmp
= launch_data_array_get_index(rnames
, rn_i
);
1057 rvs_fd
= do_rendezvous_magic(res
, launch_data_get_string(rn_tmp
));
1059 launch_data_array_append(rvs_fds
, rvs_fd
);
1065 if (connect(sfd
, res
->ai_addr
, res
->ai_addrlen
) == -1) {
1066 fprintf(stderr
, "connect(): %s\n", strerror(errno
));
1070 val
= launch_data_new_fd(sfd
);
1072 /* <rdar://problem/3964648> Launchd should not register the same service more than once */
1073 /* <rdar://problem/3965154> Switch to DNSServiceRegisterAddrInfo() */
1076 launch_data_array_append(fdarray
, val
);
1082 do_mgroup_join(int fd
, int family
, int socktype
, int protocol
, const char *mgroup
)
1084 struct addrinfo hints
, *res0
, *res
;
1085 struct ip_mreq mreq
;
1086 struct ipv6_mreq m6req
;
1089 memset(&hints
, 0, sizeof(hints
));
1091 hints
.ai_flags
|= AI_PASSIVE
;
1092 hints
.ai_family
= family
;
1093 hints
.ai_socktype
= socktype
;
1094 hints
.ai_protocol
= protocol
;
1096 if ((gerr
= getaddrinfo(mgroup
, NULL
, &hints
, &res0
)) != 0) {
1097 fprintf(stderr
, "getaddrinfo(): %s\n", gai_strerror(gerr
));
1101 for (res
= res0
; res
; res
= res
->ai_next
) {
1102 if (AF_INET
== family
) {
1103 memset(&mreq
, 0, sizeof(mreq
));
1104 mreq
.imr_multiaddr
= ((struct sockaddr_in
*)res
->ai_addr
)->sin_addr
;
1105 if (setsockopt(fd
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &mreq
, sizeof(mreq
)) == -1) {
1106 fprintf(stderr
, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno
));
1110 } else if (AF_INET6
== family
) {
1111 memset(&m6req
, 0, sizeof(m6req
));
1112 m6req
.ipv6mr_multiaddr
= ((struct sockaddr_in6
*)res
->ai_addr
)->sin6_addr
;
1113 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &m6req
, sizeof(m6req
)) == -1) {
1114 fprintf(stderr
, "setsockopt(IPV6_JOIN_GROUP): %s\n", strerror(errno
));
1119 fprintf(stderr
, "unknown family during multicast group bind!\n");
1129 do_rendezvous_magic(const struct addrinfo
*res
, const char *serv
)
1132 DNSServiceRef service
;
1133 DNSServiceErrorType error
;
1136 static int statres
= 1;
1139 statres
= stat("/usr/sbin/mDNSResponder", &sb
);
1142 if (-1 == statres
) {
1146 sprintf(rvs_buf
, "_%s._%s.", serv
, res
->ai_socktype
== SOCK_STREAM
? "tcp" : "udp");
1148 if (res
->ai_family
== AF_INET
) {
1149 port
= ((struct sockaddr_in
*)res
->ai_addr
)->sin_port
;
1151 port
= ((struct sockaddr_in6
*)res
->ai_addr
)->sin6_port
;
1154 error
= DNSServiceRegister(&service
, 0, 0, NULL
, rvs_buf
, NULL
, NULL
, port
, 0, NULL
, NULL
, NULL
);
1156 if (error
== kDNSServiceErr_NoError
) {
1157 return launch_data_new_fd(DNSServiceRefSockFD(service
));
1160 fprintf(stderr
, "DNSServiceRegister(\"%s\"): %d\n", serv
, error
);
1165 CreateMyPropertyListFromFile(const char *posixfile
)
1167 CFPropertyListRef propertyList
;
1168 CFStringRef errorString
;
1169 CFDataRef resourceData
;
1173 fileURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault
, (const UInt8
*)posixfile
, strlen(posixfile
), false);
1175 fprintf(stderr
, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile
);
1177 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, fileURL
, &resourceData
, NULL
, NULL
, &errorCode
)) {
1178 fprintf(stderr
, "%s: CFURLCreateDataAndPropertiesFromResource(%s) failed: %d\n", getprogname(), posixfile
, (int)errorCode
);
1180 propertyList
= CFPropertyListCreateFromXMLData(kCFAllocatorDefault
, resourceData
, kCFPropertyListMutableContainers
, &errorString
);
1181 if (!propertyList
) {
1182 fprintf(stderr
, "%s: propertyList is NULL\n", getprogname());
1185 return propertyList
;
1189 WriteMyPropertyListToFile(CFPropertyListRef plist
, const char *posixfile
)
1191 CFDataRef resourceData
;
1195 fileURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault
, (const UInt8
*)posixfile
, strlen(posixfile
), false);
1197 fprintf(stderr
, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile
);
1199 resourceData
= CFPropertyListCreateXMLData(kCFAllocatorDefault
, plist
);
1200 if (resourceData
== NULL
) {
1201 fprintf(stderr
, "%s: CFPropertyListCreateXMLData(%s) failed", getprogname(), posixfile
);
1203 if (!CFURLWriteDataAndPropertiesToResource(fileURL
, resourceData
, NULL
, &errorCode
)) {
1204 fprintf(stderr
, "%s: CFURLWriteDataAndPropertiesToResource(%s) failed: %d\n", getprogname(), posixfile
, (int)errorCode
);
1209 myCFDictionaryApplyFunction(const void *key
, const void *value
, void *context
)
1211 launch_data_t ik
, iw
, where
= context
;
1213 ik
= CF2launch_data(key
);
1214 iw
= CF2launch_data(value
);
1216 launch_data_dict_insert(where
, iw
, launch_data_get_string(ik
));
1217 launch_data_free(ik
);
1221 CF2launch_data(CFTypeRef cfr
)
1224 CFTypeID cft
= CFGetTypeID(cfr
);
1226 if (cft
== CFStringGetTypeID()) {
1228 CFStringGetCString(cfr
, buf
, sizeof(buf
), kCFStringEncodingUTF8
);
1229 r
= launch_data_alloc(LAUNCH_DATA_STRING
);
1230 launch_data_set_string(r
, buf
);
1231 } else if (cft
== CFBooleanGetTypeID()) {
1232 r
= launch_data_alloc(LAUNCH_DATA_BOOL
);
1233 launch_data_set_bool(r
, CFBooleanGetValue(cfr
));
1234 } else if (cft
== CFArrayGetTypeID()) {
1235 CFIndex i
, ac
= CFArrayGetCount(cfr
);
1236 r
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
1237 for (i
= 0; i
< ac
; i
++) {
1238 CFTypeRef v
= CFArrayGetValueAtIndex(cfr
, i
);
1240 launch_data_t iv
= CF2launch_data(v
);
1241 launch_data_array_set_index(r
, iv
, i
);
1244 } else if (cft
== CFDictionaryGetTypeID()) {
1245 r
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
1246 CFDictionaryApplyFunction(cfr
, myCFDictionaryApplyFunction
, r
);
1247 } else if (cft
== CFDataGetTypeID()) {
1248 r
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
1249 launch_data_set_opaque(r
, CFDataGetBytePtr(cfr
), CFDataGetLength(cfr
));
1250 } else if (cft
== CFNumberGetTypeID()) {
1253 CFNumberType cfnt
= CFNumberGetType(cfr
);
1255 case kCFNumberSInt8Type
:
1256 case kCFNumberSInt16Type
:
1257 case kCFNumberSInt32Type
:
1258 case kCFNumberSInt64Type
:
1259 case kCFNumberCharType
:
1260 case kCFNumberShortType
:
1261 case kCFNumberIntType
:
1262 case kCFNumberLongType
:
1263 case kCFNumberLongLongType
:
1264 CFNumberGetValue(cfr
, kCFNumberLongLongType
, &n
);
1265 r
= launch_data_alloc(LAUNCH_DATA_INTEGER
);
1266 launch_data_set_integer(r
, n
);
1268 case kCFNumberFloat32Type
:
1269 case kCFNumberFloat64Type
:
1270 case kCFNumberFloatType
:
1271 case kCFNumberDoubleType
:
1272 CFNumberGetValue(cfr
, kCFNumberDoubleType
, &d
);
1273 r
= launch_data_alloc(LAUNCH_DATA_REAL
);
1274 launch_data_set_real(r
, d
);
1287 help_cmd(int argc
, char *const argv
[])
1289 FILE *where
= stdout
;
1290 int l
, cmdwidth
= 0;
1293 if (argc
== 0 || argv
== NULL
)
1296 fprintf(where
, "usage: %s <subcommand>\n", getprogname());
1298 for (i
= 0; i
< (sizeof cmds
/ sizeof cmds
[0]); i
++) {
1299 l
= strlen(cmds
[i
].name
);
1304 for (i
= 0; i
< (sizeof cmds
/ sizeof cmds
[0]); i
++) {
1305 fprintf(where
, "\t%-*s\t%s\n", cmdwidth
, cmds
[i
].name
, cmds
[i
].desc
);
1312 exit_cmd(int argc
__attribute__((unused
)), char *const argv
[] __attribute__((unused
)))
1321 fcntl(fd
, F_SETFD
, 1);
1326 do_single_user_mode(bool sflag
)
1329 while (!do_single_user_mode2()) {
1336 do_single_user_mode2(void)
1338 bool runcom_fsck
= true; /* should_fsck(); */
1343 switch ((p
= fork())) {
1345 syslog(LOG_ERR
, "can't fork single-user shell, trying again: %m");
1350 assumes(waitpid(p
, &wstatus
, 0) != -1);
1351 if (WIFEXITED(wstatus
)) {
1352 if (WEXITSTATUS(wstatus
) == EXIT_SUCCESS
) {
1355 fprintf(stdout
, "single user mode: exit status: %d\n", WEXITSTATUS(wstatus
));
1358 fprintf(stdout
, "single user mode shell: %s\n", strsignal(WTERMSIG(wstatus
)));
1363 revoke(_PATH_CONSOLE
);
1364 if (!assumes((fd
= open(_PATH_CONSOLE
, O_RDWR
)) != -1)) {
1365 _exit(EXIT_FAILURE
);
1367 if (!assumes(login_tty(fd
) != -1)) {
1368 _exit(EXIT_FAILURE
);
1370 setenv("TERM", "vt100", 1);
1372 fprintf(stdout
, "Singleuser boot -- fsck not done\n");
1373 fprintf(stdout
, "Root device is mounted read-only\n\n");
1374 fprintf(stdout
, "If you want to make modifications to files:\n");
1375 fprintf(stdout
, "\t/sbin/fsck -fy\n\t/sbin/mount -uw /\n\n");
1376 fprintf(stdout
, "If you wish to boot the system:\n");
1377 fprintf(stdout
, "\texit\n\n");
1381 execl(_PATH_BSHELL
, "-sh", NULL
);
1382 syslog(LOG_ERR
, "can't exec %s for single user: %m", _PATH_BSHELL
);
1383 _exit(EXIT_FAILURE
);
1387 system_specific_bootstrap(bool sflag
)
1389 int hnmib
[] = { CTL_KERN
, KERN_HOSTNAME
};
1394 do_sysversion_sysctl();
1396 do_single_user_mode(sflag
);
1398 assumes((kq
= kqueue()) != -1);
1400 EV_SET(&kev
, 0, EVFILT_TIMER
, EV_ADD
|EV_ONESHOT
, NOTE_SECONDS
, 60, 0);
1401 assumes(kevent(kq
, &kev
, 1, NULL
, 0, NULL
) != -1);
1403 EV_SET(&kev
, SIGTERM
, EVFILT_SIGNAL
, EV_ADD
, 0, 0, 0);
1404 assumes(kevent(kq
, &kev
, 1, NULL
, 0, NULL
) != -1);
1405 assumes(signal(SIGTERM
, SIG_IGN
) != SIG_ERR
);
1407 assumes(sysctl(hnmib
, 2, NULL
, NULL
, "localhost", sizeof("localhost")) != -1);
1409 loopback_setup_ipv4();
1410 loopback_setup_ipv6();
1412 #if TARGET_OS_EMBEDDED
1413 if (path_check("/etc/rc.boot")) {
1414 const char *rcboot_tool
[] = { "/etc/rc.boot", NULL
};
1415 assumes(fwexec(rcboot_tool
, true) != -1);
1419 apply_sysctls_from_file("/etc/sysctl.conf");
1421 if (path_check("/etc/rc.cdrom")) {
1422 const char *rccdrom_tool
[] = { _PATH_BSHELL
, "/etc/rc.cdrom", "multiuser", NULL
};
1423 assumes(fwexec(rccdrom_tool
, true) != -1);
1424 assumes(reboot(RB_HALT
) != -1);
1425 _exit(EXIT_FAILURE
);
1426 } else if (is_netboot()) {
1427 const char *rcnetboot_tool
[] = { _PATH_BSHELL
, "/etc/rc.netboot", "init", NULL
};
1428 if (!assumes(fwexec(rcnetboot_tool
, true) != -1)) {
1429 assumes(reboot(RB_HALT
) != -1);
1430 _exit(EXIT_FAILURE
);
1433 do_potential_fsck();
1436 if (path_check("/etc/rc.server")) {
1437 const char *rcserver_tool
[] = { _PATH_BSHELL
, "/etc/rc.server", NULL
};
1438 assumes(fwexec(rcserver_tool
, true) != -1);
1441 read_launchd_conf();
1443 if (path_check("/var/account/acct")) {
1444 assumes(acct("/var/account/acct") != -1);
1447 #if !TARGET_OS_EMBEDDED
1448 if (path_check("/etc/fstab")) {
1449 const char *mount_tool
[] = { "mount", "-vat", "nonfs", NULL
};
1450 assumes(fwexec(mount_tool
, true) != -1);
1454 if (path_check("/etc/rc.installer_cleanup")) {
1455 const char *rccleanup_tool
[] = { _PATH_BSHELL
, "/etc/rc.installer_cleanup", "multiuser", NULL
};
1456 assumes(fwexec(rccleanup_tool
, true) != -1);
1459 empty_dir(_PATH_VARRUN
, NULL
);
1460 empty_dir(_PATH_TMP
, NULL
);
1461 remove(_PATH_NOLOGIN
);
1463 if (path_check("/usr/libexec/dirhelper")) {
1464 const char *dirhelper_tool
[] = { "/usr/libexec/dirhelper", "-machineBoot", NULL
};
1465 assumes(fwexec(dirhelper_tool
, true) != -1);
1468 assumes(touch_file(_PATH_UTMPX
, DEFFILEMODE
) != -1);
1469 assumes(touch_file(_PATH_VARRUN
"/.systemStarterRunning", DEFFILEMODE
) != -1);
1471 if (path_check("/etc/security/rc.audit")) {
1472 const char *audit_tool
[] = { _PATH_BSHELL
, "/etc/security/rc.audit", NULL
};
1473 assumes(fwexec(audit_tool
, true) != -1);
1476 do_BootCache_magic(BOOTCACHE_START
);
1478 preheat_page_cache_hack();
1480 _vproc_set_global_on_demand(true);
1482 char *load_launchd_items
[] = { "load", "-D", "all", "/etc/mach_init.d",
1483 #if TARGET_OS_EMBEDDED
1484 "/var/mobile/Library/LaunchAgents",
1488 if (is_safeboot()) {
1489 load_launchd_items
[2] = "system";
1492 assumes(load_and_unload_cmd(4, load_launchd_items
) == 0);
1497 * We need to revisit this after Leopard ships.
1499 * I want a plist defined knob for jobs to give advisory hints that
1500 * will "hopefully" serialize bootstrap. Reasons for doing so include
1501 * pragmatic performance optimizations and attempts to workaround bugs
1502 * in jobs. My current thought is something like what follows.
1504 * The BootCache would switch to launchd and add this to the plist:
1506 * <key>HopefullyStartsSerially<key>
1508 * <key>ReadyTimeout</key>
1509 * <integer>2</integer>
1512 * And kextd would add the following:
1514 * <key>HopefullyStartsSerially<key>
1516 * <key>ReadyTimeout</key>
1517 * <integer>5</integer>
1518 * <key>HopefullyStartsAfter</key>
1519 * <string>com.apple.BootCache.daemon</string>
1523 * Then both the BootCache and kextd could call something like:
1525 * vproc_declare_ready_state();
1527 * To tell launchd to short circuit the readiness timeout and let the
1528 * next wave of jobs start.
1530 * Yes, this mechanism smells a lot like SystemStarter, rc.d and
1531 * friends. I think as long as we document that artificial
1532 * serialization is only advisory and not guaranteed, we should be
1533 * fine. Remember: IPC is the preferred way to serialize operations.
1536 mach_timespec_t w
= { 5, 0 };
1537 IOKitWaitQuiet(kIOMasterPortDefault
, &w
);
1539 do_BootCache_magic(BOOTCACHE_TAG
);
1541 do_bootroot_magic();
1543 _vproc_set_global_on_demand(false);
1545 assumes(kevent(kq
, NULL
, 0, &kev
, 1, NULL
) == 1);
1547 do_BootCache_magic(BOOTCACHE_STOP
);
1549 assumes(close(kq
) != -1);
1553 do_BootCache_magic(BootCache_action_t what
)
1555 const char *bcc_tool
[] = { "/usr/sbin/BootCacheControl", "-f", "/var/db/BootCache.playlist", NULL
, NULL
};
1557 if (is_safeboot() || !path_check(bcc_tool
[0])) {
1562 case BOOTCACHE_START
:
1563 bcc_tool
[3] = "start";
1566 bcc_tool
[3] = "tag";
1568 case BOOTCACHE_STOP
:
1569 bcc_tool
[3] = "stop";
1576 fwexec(bcc_tool
, true);
1580 bootstrap_cmd(int argc
, char *const argv
[])
1582 char *session_type
= NULL
;
1586 while ((ch
= getopt(argc
, argv
, "sS:")) != -1) {
1592 session_type
= optarg
;
1603 if (!session_type
) {
1604 fprintf(stderr
, "usage: %s bootstrap [-s] -S <session-type>\n", getprogname());
1608 if (strcasecmp(session_type
, "System") == 0) {
1609 system_specific_bootstrap(sflag
);
1611 char *load_launchd_items
[] = { "load", "-S", session_type
, "-D", "all", NULL
, NULL
, NULL
, NULL
};
1614 if (is_safeboot()) {
1615 load_launchd_items
[4] = "system";
1618 if (strcasecmp(session_type
, VPROCMGR_SESSION_BACKGROUND
) == 0 || strcasecmp(session_type
, VPROCMGR_SESSION_LOGINWINDOW
) == 0) {
1619 load_launchd_items
[4] = "system";
1620 if (!is_safeboot()) {
1621 load_launchd_items
[5] = "-D";
1622 load_launchd_items
[6] = "local";
1625 if (strcasecmp(session_type
, VPROCMGR_SESSION_LOGINWINDOW
) == 0) {
1626 load_launchd_items
[the_argc
] = "/etc/mach_init_per_login_session.d";
1629 } else if (strcasecmp(session_type
, VPROCMGR_SESSION_AQUA
) == 0) {
1630 load_launchd_items
[5] = "/etc/mach_init_per_user.d";
1634 if (strcasecmp(session_type
, VPROCMGR_SESSION_BACKGROUND
) == 0) {
1635 read_launchd_conf();
1637 assumes(SessionCreate(sessionKeepCurrentBootstrap
, 0) == 0);
1641 return load_and_unload_cmd(the_argc
, load_launchd_items
);
1648 load_and_unload_cmd(int argc
, char *const argv
[])
1650 NSSearchPathEnumerationState es
= 0;
1651 char nspath
[PATH_MAX
* 2]; /* safe side, we need to append */
1652 bool badopts
= false;
1653 struct load_unload_state lus
;
1657 memset(&lus
, 0, sizeof(lus
));
1659 if (strcmp(argv
[0], "load") == 0) {
1663 while ((ch
= getopt(argc
, argv
, "wFS:D:")) != -1) {
1666 lus
.editondisk
= true;
1669 lus
.forceload
= true;
1672 lus
.session_type
= optarg
;
1675 if (strcasecmp(optarg
, "all") == 0) {
1676 es
|= NSAllDomainsMask
;
1677 } else if (strcasecmp(optarg
, "user") == 0) {
1678 es
|= NSUserDomainMask
;
1679 } else if (strcasecmp(optarg
, "local") == 0) {
1680 es
|= NSLocalDomainMask
;
1681 } else if (strcasecmp(optarg
, "network") == 0) {
1682 es
|= NSNetworkDomainMask
;
1683 } else if (strcasecmp(optarg
, "system") == 0) {
1684 es
|= NSSystemDomainMask
;
1698 if (lus
.session_type
== NULL
) {
1699 es
&= ~NSUserDomainMask
;
1702 if (argc
== 0 && es
== 0) {
1707 fprintf(stderr
, "usage: %s load [-wF] [-D <user|local|network|system|all>] paths...\n", getprogname());
1711 /* I wish I didn't need to do three passes, but I need to load mDNSResponder and use it too.
1712 * And loading legacy mach init jobs is extra fun.
1714 * In later versions of launchd, I hope to load everything in the first pass,
1715 * then do the Bonjour magic on the jobs that need it, and reload them, but for now,
1716 * I haven't thought through the various complexities of reloading jobs, and therefore
1717 * launchd doesn't have reload support right now.
1720 lus
.pass0
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
1721 lus
.pass1
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
1722 lus
.pass2
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
1724 es
= NSStartSearchPathEnumeration(NSLibraryDirectory
, es
);
1726 while ((es
= NSGetNextSearchPathEnumeration(es
, nspath
))) {
1729 if (lus
.session_type
) {
1730 strcat(nspath
, "/LaunchAgents");
1732 strcat(nspath
, "/LaunchDaemons");
1735 if (glob(nspath
, GLOB_TILDE
|GLOB_NOSORT
, NULL
, &g
) == 0) {
1736 for (i
= 0; i
< g
.gl_pathc
; i
++) {
1737 readpath(g
.gl_pathv
[i
], &lus
);
1743 for (i
= 0; i
< (size_t)argc
; i
++) {
1744 readpath(argv
[i
], &lus
);
1747 if (launch_data_array_get_count(lus
.pass0
) == 0 &&
1748 launch_data_array_get_count(lus
.pass1
) == 0 &&
1749 launch_data_array_get_count(lus
.pass2
) == 0) {
1751 fprintf(stderr
, "nothing found to %s\n", lus
.load
? "load" : "unload");
1753 launch_data_free(lus
.pass0
);
1754 launch_data_free(lus
.pass1
);
1755 launch_data_free(lus
.pass2
);
1756 return is_managed
? 0 : 1;
1760 distill_jobs(lus
.pass1
);
1761 submit_mach_jobs(lus
.pass0
);
1762 submit_job_pass(lus
.pass1
);
1763 let_go_of_mach_jobs(lus
.pass0
);
1764 distill_jobs(lus
.pass2
);
1765 submit_job_pass(lus
.pass2
);
1767 for (i
= 0; i
< launch_data_array_get_count(lus
.pass1
); i
++) {
1768 unloadjob(launch_data_array_get_index(lus
.pass1
, i
));
1770 for (i
= 0; i
< launch_data_array_get_count(lus
.pass2
); i
++) {
1771 unloadjob(launch_data_array_get_index(lus
.pass2
, i
));
1779 submit_mach_jobs(launch_data_t jobs
)
1783 c
= launch_data_array_get_count(jobs
);
1785 for (i
= 0; i
< c
; i
++) {
1786 launch_data_t tmp
, oai
= launch_data_array_get_index(jobs
, i
);
1787 const char *sn
= NULL
, *cmd
= NULL
;
1789 mach_port_t msr
, msv
;
1793 if ((tmp
= launch_data_dict_lookup(oai
, MACHINIT_JOBKEY_ONDEMAND
)))
1794 d
= launch_data_get_bool(tmp
);
1795 if ((tmp
= launch_data_dict_lookup(oai
, MACHINIT_JOBKEY_SERVICENAME
)))
1796 sn
= launch_data_get_string(tmp
);
1797 if ((tmp
= launch_data_dict_lookup(oai
, MACHINIT_JOBKEY_COMMAND
)))
1798 cmd
= launch_data_get_string(tmp
);
1800 if ((kr
= bootstrap_create_server(bootstrap_port
, (char *)cmd
, u
, d
, &msr
)) != KERN_SUCCESS
) {
1801 fprintf(stderr
, "%s: bootstrap_create_server(): %d\n", getprogname(), kr
);
1804 if ((kr
= bootstrap_create_service(msr
, (char*)sn
, &msv
)) != KERN_SUCCESS
) {
1805 fprintf(stderr
, "%s: bootstrap_create_service(): %d\n", getprogname(), kr
);
1806 mach_port_destroy(mach_task_self(), msr
);
1809 launch_data_dict_insert(oai
, launch_data_new_machport(msr
), MACHINIT_JOBKEY_SERVERPORT
);
1810 launch_data_dict_insert(oai
, launch_data_new_machport(msv
), MACHINIT_JOBKEY_SERVICEPORT
);
1815 let_go_of_mach_jobs(launch_data_t jobs
)
1817 size_t i
, c
= launch_data_array_get_count(jobs
);
1819 for (i
= 0; i
< c
; i
++) {
1820 launch_data_t tmp
, oai
= launch_data_array_get_index(jobs
, i
);
1821 if ((tmp
= launch_data_dict_lookup(oai
, MACHINIT_JOBKEY_SERVICEPORT
))) {
1822 mach_port_destroy(mach_task_self(), launch_data_get_machport(tmp
));
1824 fprintf(stderr
, "%s: ack! missing service port!\n", getprogname());
1826 if ((tmp
= launch_data_dict_lookup(oai
, MACHINIT_JOBKEY_SERVERPORT
))) {
1827 mach_port_destroy(mach_task_self(), launch_data_get_machport(tmp
));
1829 fprintf(stderr
, "%s: ack! missing server port!\n", getprogname());
1835 submit_job_pass(launch_data_t jobs
)
1837 launch_data_t msg
, resp
;
1841 if (launch_data_array_get_count(jobs
) == 0)
1844 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
1846 launch_data_dict_insert(msg
, jobs
, LAUNCH_KEY_SUBMITJOB
);
1848 resp
= launch_msg(msg
);
1851 switch (launch_data_get_type(resp
)) {
1852 case LAUNCH_DATA_ERRNO
:
1853 if ((e
= launch_data_get_errno(resp
)))
1854 fprintf(stderr
, "%s\n", strerror(e
));
1856 case LAUNCH_DATA_ARRAY
:
1857 for (i
= 0; i
< launch_data_array_get_count(jobs
); i
++) {
1858 launch_data_t obatind
= launch_data_array_get_index(resp
, i
);
1859 launch_data_t jatind
= launch_data_array_get_index(jobs
, i
);
1860 const char *lab4job
= launch_data_get_string(launch_data_dict_lookup(jatind
, LAUNCH_JOBKEY_LABEL
));
1861 if (LAUNCH_DATA_ERRNO
== launch_data_get_type(obatind
)) {
1862 e
= launch_data_get_errno(obatind
);
1865 fprintf(stderr
, "%s: %s\n", lab4job
, "Already loaded");
1868 fprintf(stderr
, "%s: %s\n", lab4job
, "Not loaded");
1871 fprintf(stderr
, "%s: %s\n", lab4job
, strerror(e
));
1879 fprintf(stderr
, "unknown respose from launchd!\n");
1882 launch_data_free(resp
);
1884 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
));
1887 launch_data_free(msg
);
1891 start_stop_remove_cmd(int argc
, char *const argv
[])
1893 launch_data_t resp
, msg
;
1894 const char *lmsgcmd
= LAUNCH_KEY_STOPJOB
;
1897 if (0 == strcmp(argv
[0], "start"))
1898 lmsgcmd
= LAUNCH_KEY_STARTJOB
;
1900 if (0 == strcmp(argv
[0], "remove"))
1901 lmsgcmd
= LAUNCH_KEY_REMOVEJOB
;
1904 fprintf(stderr
, "usage: %s %s <job label>\n", getprogname(), argv
[0]);
1908 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
1909 launch_data_dict_insert(msg
, launch_data_new_string(argv
[1]), lmsgcmd
);
1911 resp
= launch_msg(msg
);
1912 launch_data_free(msg
);
1915 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
));
1917 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) {
1918 if ((e
= launch_data_get_errno(resp
))) {
1919 fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], strerror(e
));
1923 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]);
1927 launch_data_free(resp
);
1932 print_jobs(launch_data_t j
, const char *key
__attribute__((unused
)), void *context
__attribute__((unused
)))
1934 static size_t depth
= 0;
1935 launch_data_t lo
= launch_data_dict_lookup(j
, LAUNCH_JOBKEY_LABEL
);
1936 launch_data_t pido
= launch_data_dict_lookup(j
, LAUNCH_JOBKEY_PID
);
1937 launch_data_t stato
= launch_data_dict_lookup(j
, LAUNCH_JOBKEY_LASTEXITSTATUS
);
1938 const char *label
= launch_data_get_string(lo
);
1942 fprintf(stdout
, "%lld\t-\t", launch_data_get_integer(pido
));
1944 int wstatus
= (int)launch_data_get_integer(stato
);
1945 if (WIFEXITED(wstatus
)) {
1946 fprintf(stdout
, "-\t%d\t", WEXITSTATUS(wstatus
));
1947 } else if (WIFSIGNALED(wstatus
)) {
1948 fprintf(stdout
, "-\t-%d\t", WTERMSIG(wstatus
));
1950 fprintf(stdout
, "-\t???\t");
1953 fprintf(stdout
, "-\t-\t");
1955 for (i
= 0; i
< depth
; i
++)
1956 fprintf(stdout
, "\t");
1958 fprintf(stdout
, "%s\n", label
);
1962 print_obj(launch_data_t obj
, const char *key
, void *context
__attribute__((unused
)))
1964 static size_t indent
= 0;
1967 for (i
= 0; i
< indent
; i
++)
1968 fprintf(stdout
, "\t");
1971 fprintf(stdout
, "\"%s\" = ", key
);
1973 switch (launch_data_get_type(obj
)) {
1974 case LAUNCH_DATA_STRING
:
1975 fprintf(stdout
, "\"%s\";\n", launch_data_get_string(obj
));
1977 case LAUNCH_DATA_INTEGER
:
1978 fprintf(stdout
, "%lld;\n", launch_data_get_integer(obj
));
1980 case LAUNCH_DATA_REAL
:
1981 fprintf(stdout
, "%f;\n", launch_data_get_real(obj
));
1983 case LAUNCH_DATA_BOOL
:
1984 fprintf(stdout
, "%s;\n", launch_data_get_bool(obj
) ? "true" : "false");
1986 case LAUNCH_DATA_ARRAY
:
1987 c
= launch_data_array_get_count(obj
);
1988 fprintf(stdout
, "(\n");
1990 for (i
= 0; i
< c
; i
++)
1991 print_obj(launch_data_array_get_index(obj
, i
), NULL
, NULL
);
1993 for (i
= 0; i
< indent
; i
++)
1994 fprintf(stdout
, "\t");
1995 fprintf(stdout
, ");\n");
1997 case LAUNCH_DATA_DICTIONARY
:
1998 fprintf(stdout
, "{\n");
2000 launch_data_dict_iterate(obj
, print_obj
, NULL
);
2002 for (i
= 0; i
< indent
; i
++)
2003 fprintf(stdout
, "\t");
2004 fprintf(stdout
, "};\n");
2006 case LAUNCH_DATA_FD
:
2007 fprintf(stdout
, "file-descriptor-object;\n");
2009 case LAUNCH_DATA_MACHPORT
:
2010 fprintf(stdout
, "mach-port-object;\n");
2013 fprintf(stdout
, "???;\n");
2019 list_cmd(int argc
, char *const argv
[])
2021 launch_data_t resp
, msg
;
2025 fprintf(stderr
, "usage: %s list [label]\n", getprogname());
2027 } else if (argc
== 2) {
2028 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
2029 launch_data_dict_insert(msg
, launch_data_new_string(argv
[1]), LAUNCH_KEY_GETJOB
);
2030 } else if (vproc_swap_complex(NULL
, VPROC_GSK_ALLJOBS
, NULL
, &resp
) == NULL
) {
2031 fprintf(stdout
, "PID\tStatus\tLabel\n");
2032 launch_data_dict_iterate(resp
, print_jobs
, NULL
);
2033 launch_data_free(resp
);
2039 resp
= launch_msg(msg
);
2040 launch_data_free(msg
);
2043 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
));
2045 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_DICTIONARY
) {
2046 print_obj(resp
, NULL
, NULL
);
2048 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]);
2052 launch_data_free(resp
);
2058 stdio_cmd(int argc
__attribute__((unused
)), char *const argv
[])
2060 fprintf(stderr
, "%s %s: This sub-command no longer does anything\n", getprogname(), argv
[0]);
2065 fyi_cmd(int argc
, char *const argv
[])
2067 launch_data_t resp
, msg
;
2068 const char *lmsgk
= NULL
;
2072 fprintf(stderr
, "usage: %s %s\n", getprogname(), argv
[0]);
2076 if (!strcmp(argv
[0], "shutdown")) {
2077 lmsgk
= LAUNCH_KEY_SHUTDOWN
;
2078 } else if (!strcmp(argv
[0], "singleuser")) {
2079 lmsgk
= LAUNCH_KEY_SINGLEUSER
;
2084 msg
= launch_data_new_string(lmsgk
);
2085 resp
= launch_msg(msg
);
2086 launch_data_free(msg
);
2089 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
));
2091 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) {
2092 if ((e
= launch_data_get_errno(resp
))) {
2093 fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], strerror(e
));
2097 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]);
2101 launch_data_free(resp
);
2107 logupdate_cmd(int argc
, char *const argv
[])
2109 int64_t inval
, outval
;
2111 bool badargs
= false, maskmode
= false, onlymode
= false, levelmode
= false;
2112 static const struct {
2116 { "debug", LOG_DEBUG
},
2117 { "info", LOG_INFO
},
2118 { "notice", LOG_NOTICE
},
2119 { "warning", LOG_WARNING
},
2120 { "error", LOG_ERR
},
2121 { "critical", LOG_CRIT
},
2122 { "alert", LOG_ALERT
},
2123 { "emergency", LOG_EMERG
},
2125 int logtblsz
= sizeof logtbl
/ sizeof logtbl
[0];
2128 if (!strcmp(argv
[1], "mask"))
2130 else if (!strcmp(argv
[1], "only"))
2132 else if (!strcmp(argv
[1], "level"))
2139 m
= LOG_UPTO(LOG_DEBUG
);
2141 if (argc
> 2 && (maskmode
|| onlymode
)) {
2142 for (i
= 2; i
< argc
; i
++) {
2143 for (j
= 0; j
< logtblsz
; j
++) {
2144 if (!strcmp(argv
[i
], logtbl
[j
].name
)) {
2146 m
&= ~(LOG_MASK(logtbl
[j
].level
));
2148 m
|= LOG_MASK(logtbl
[j
].level
);
2152 if (j
== logtblsz
) {
2157 } else if (argc
> 2 && levelmode
) {
2158 for (j
= 0; j
< logtblsz
; j
++) {
2159 if (!strcmp(argv
[2], logtbl
[j
].name
)) {
2160 m
= LOG_UPTO(logtbl
[j
].level
);
2166 } else if (argc
!= 1) {
2171 fprintf(stderr
, "usage: %s [[mask loglevels...] | [only loglevels...] [level loglevel]]\n", getprogname());
2177 if (vproc_swap_integer(NULL
, VPROC_GSK_GLOBAL_LOG_MASK
, argc
!= 1 ? &inval
: NULL
, &outval
) == NULL
) {
2179 for (j
= 0; j
< logtblsz
; j
++) {
2180 if (outval
& LOG_MASK(logtbl
[j
].level
)) {
2181 fprintf(stdout
, "%s ", logtbl
[j
].name
);
2184 fprintf(stdout
, "\n");
2192 static const struct {
2196 { "cpu", RLIMIT_CPU
},
2197 { "filesize", RLIMIT_FSIZE
},
2198 { "data", RLIMIT_DATA
},
2199 { "stack", RLIMIT_STACK
},
2200 { "core", RLIMIT_CORE
},
2201 { "rss", RLIMIT_RSS
},
2202 { "memlock", RLIMIT_MEMLOCK
},
2203 { "maxproc", RLIMIT_NPROC
},
2204 { "maxfiles", RLIMIT_NOFILE
}
2207 static const size_t limlookupcnt
= sizeof limlookup
/ sizeof limlookup
[0];
2210 name2num(const char *n
)
2214 for (i
= 0; i
< limlookupcnt
; i
++) {
2215 if (!strcmp(limlookup
[i
].name
, n
)) {
2216 return limlookup
[i
].lim
;
2227 for (i
= 0; i
< limlookupcnt
; i
++) {
2228 if (limlookup
[i
].lim
== n
)
2229 return limlookup
[i
].name
;
2235 lim2str(rlim_t val
, char *buf
)
2237 if (val
== RLIM_INFINITY
)
2238 strcpy(buf
, "unlimited");
2240 sprintf(buf
, "%lld", val
);
2245 str2lim(const char *buf
, rlim_t
*res
)
2248 *res
= strtoll(buf
, &endptr
, 10);
2249 if (!strcmp(buf
, "unlimited")) {
2250 *res
= RLIM_INFINITY
;
2252 } else if (*endptr
== '\0') {
2259 limit_cmd(int argc
__attribute__((unused
)), char *const argv
[])
2263 struct rlimit
*lmts
= NULL
;
2264 launch_data_t resp
, resp1
= NULL
, msg
, tmp
;
2268 rlim_t slim
= -1, hlim
= -1;
2269 bool badargs
= false;
2274 if (argc
>= 3 && str2lim(argv
[2], &slim
))
2279 if (argc
== 4 && str2lim(argv
[3], &hlim
))
2282 if (argc
>= 2 && -1 == (which
= name2num(argv
[1])))
2286 fprintf(stderr
, "usage: %s %s [", getprogname(), argv
[0]);
2287 for (i
= 0; i
< limlookupcnt
; i
++)
2288 fprintf(stderr
, "%s %s", limlookup
[i
].name
, (i
+ 1) == limlookupcnt
? "" : "| ");
2289 fprintf(stderr
, "[both | soft hard]]\n");
2293 msg
= launch_data_new_string(LAUNCH_KEY_GETRESOURCELIMITS
);
2294 resp
= launch_msg(msg
);
2295 launch_data_free(msg
);
2298 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
));
2300 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_OPAQUE
) {
2301 lmts
= launch_data_get_opaque(resp
);
2302 lsz
= launch_data_get_opaque_size(resp
);
2304 for (i
= 0; i
< (lsz
/ sizeof(struct rlimit
)); i
++) {
2305 if (argc
== 2 && (size_t)which
!= i
)
2307 fprintf(stdout
, "\t%-12s%-15s%-15s\n", num2name(i
),
2308 lim2str(lmts
[i
].rlim_cur
, slimstr
),
2309 lim2str(lmts
[i
].rlim_max
, hlimstr
));
2312 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_STRING
) {
2313 fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], launch_data_get_string(resp
));
2316 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]);
2320 if (argc
<= 2 || r
!= 0) {
2321 launch_data_free(resp
);
2327 lmts
[which
].rlim_cur
= slim
;
2328 lmts
[which
].rlim_max
= hlim
;
2330 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
2331 tmp
= launch_data_new_opaque(lmts
, lsz
);
2332 launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_SETRESOURCELIMITS
);
2333 resp
= launch_msg(msg
);
2334 launch_data_free(msg
);
2337 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
));
2339 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_STRING
) {
2340 fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], launch_data_get_string(resp
));
2342 } else if (launch_data_get_type(resp
) != LAUNCH_DATA_OPAQUE
) {
2343 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]);
2347 launch_data_free(resp
);
2348 launch_data_free(resp1
);
2354 umask_cmd(int argc
, char *const argv
[])
2356 bool badargs
= false;
2359 int64_t inval
, outval
;
2362 m
= strtol(argv
[1], &endptr
, 8);
2363 if (*endptr
!= '\0' || m
> 0777)
2367 if (argc
> 2 || badargs
) {
2368 fprintf(stderr
, "usage: %s %s <mask>\n", getprogname(), argv
[0]);
2374 if (vproc_swap_integer(NULL
, VPROC_GSK_GLOBAL_UMASK
, argc
== 2 ? &inval
: NULL
, &outval
) == NULL
) {
2376 fprintf(stdout
, "%o\n", (unsigned int)outval
);
2385 submit_cmd(int argc
, char *const argv
[])
2387 launch_data_t msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
2388 launch_data_t job
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
2389 launch_data_t resp
, largv
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
2392 launch_data_dict_insert(job
, launch_data_new_bool(false), LAUNCH_JOBKEY_ONDEMAND
);
2394 while ((ch
= getopt(argc
, argv
, "l:p:o:e:")) != -1) {
2397 launch_data_dict_insert(job
, launch_data_new_string(optarg
), LAUNCH_JOBKEY_LABEL
);
2400 launch_data_dict_insert(job
, launch_data_new_string(optarg
), LAUNCH_JOBKEY_PROGRAM
);
2403 launch_data_dict_insert(job
, launch_data_new_string(optarg
), LAUNCH_JOBKEY_STANDARDOUTPATH
);
2406 launch_data_dict_insert(job
, launch_data_new_string(optarg
), LAUNCH_JOBKEY_STANDARDERRORPATH
);
2409 fprintf(stderr
, "usage: %s submit ...\n", getprogname());
2416 for (i
= 0; argv
[i
]; i
++) {
2417 launch_data_array_append(largv
, launch_data_new_string(argv
[i
]));
2420 launch_data_dict_insert(job
, largv
, LAUNCH_JOBKEY_PROGRAMARGUMENTS
);
2422 launch_data_dict_insert(msg
, job
, LAUNCH_KEY_SUBMITJOB
);
2424 resp
= launch_msg(msg
);
2425 launch_data_free(msg
);
2428 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
));
2430 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) {
2431 errno
= launch_data_get_errno(resp
);
2433 fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], strerror(errno
));
2437 fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], "unknown response");
2440 launch_data_free(resp
);
2446 getrusage_cmd(int argc
, char *const argv
[])
2448 launch_data_t resp
, msg
;
2449 bool badargs
= false;
2454 else if (strcmp(argv
[1], "self") && strcmp(argv
[1], "children"))
2458 fprintf(stderr
, "usage: %s %s self | children\n", getprogname(), argv
[0]);
2462 if (!strcmp(argv
[1], "self")) {
2463 msg
= launch_data_new_string(LAUNCH_KEY_GETRUSAGESELF
);
2465 msg
= launch_data_new_string(LAUNCH_KEY_GETRUSAGECHILDREN
);
2468 resp
= launch_msg(msg
);
2469 launch_data_free(msg
);
2472 fprintf(stderr
, "launch_msg(): %s\n", strerror(errno
));
2474 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
) {
2475 fprintf(stderr
, "%s %s error: %s\n", getprogname(), argv
[0], strerror(launch_data_get_errno(resp
)));
2477 } else if (launch_data_get_type(resp
) == LAUNCH_DATA_OPAQUE
) {
2478 struct rusage
*rusage
= launch_data_get_opaque(resp
);
2479 fprintf(stdout
, "\t%-10f\tuser time used\n",
2480 (double)rusage
->ru_utime
.tv_sec
+ (double)rusage
->ru_utime
.tv_usec
/ (double)1000000);
2481 fprintf(stdout
, "\t%-10f\tsystem time used\n",
2482 (double)rusage
->ru_stime
.tv_sec
+ (double)rusage
->ru_stime
.tv_usec
/ (double)1000000);
2483 fprintf(stdout
, "\t%-10ld\tmax resident set size\n", rusage
->ru_maxrss
);
2484 fprintf(stdout
, "\t%-10ld\tshared text memory size\n", rusage
->ru_ixrss
);
2485 fprintf(stdout
, "\t%-10ld\tunshared data size\n", rusage
->ru_idrss
);
2486 fprintf(stdout
, "\t%-10ld\tunshared stack size\n", rusage
->ru_isrss
);
2487 fprintf(stdout
, "\t%-10ld\tpage reclaims\n", rusage
->ru_minflt
);
2488 fprintf(stdout
, "\t%-10ld\tpage faults\n", rusage
->ru_majflt
);
2489 fprintf(stdout
, "\t%-10ld\tswaps\n", rusage
->ru_nswap
);
2490 fprintf(stdout
, "\t%-10ld\tblock input operations\n", rusage
->ru_inblock
);
2491 fprintf(stdout
, "\t%-10ld\tblock output operations\n", rusage
->ru_oublock
);
2492 fprintf(stdout
, "\t%-10ld\tmessages sent\n", rusage
->ru_msgsnd
);
2493 fprintf(stdout
, "\t%-10ld\tmessages received\n", rusage
->ru_msgrcv
);
2494 fprintf(stdout
, "\t%-10ld\tsignals received\n", rusage
->ru_nsignals
);
2495 fprintf(stdout
, "\t%-10ld\tvoluntary context switches\n", rusage
->ru_nvcsw
);
2496 fprintf(stdout
, "\t%-10ld\tinvoluntary context switches\n", rusage
->ru_nivcsw
);
2498 fprintf(stderr
, "%s %s returned unknown response\n", getprogname(), argv
[0]);
2502 launch_data_free(resp
);
2508 launch_data_array_append(launch_data_t a
, launch_data_t o
)
2510 size_t offt
= launch_data_array_get_count(a
);
2512 return launch_data_array_set_index(a
, o
, offt
);
2516 str2bsport(const char *s
)
2518 bool getrootbs
= strcmp(s
, "/") == 0;
2519 mach_port_t last_bport
, bport
= bootstrap_port
;
2520 task_t task
= mach_task_self();
2521 kern_return_t result
;
2523 if (strcmp(s
, "..") == 0 || getrootbs
) {
2526 result
= bootstrap_parent(last_bport
, &bport
);
2528 if (result
== BOOTSTRAP_NOT_PRIVILEGED
) {
2529 fprintf(stderr
, "Permission denied\n");
2531 } else if (result
!= BOOTSTRAP_SUCCESS
) {
2532 fprintf(stderr
, "bootstrap_parent() %d\n", result
);
2535 } while (getrootbs
&& last_bport
!= bport
);
2539 result
= task_for_pid(mach_task_self(), pid
, &task
);
2541 if (result
!= KERN_SUCCESS
) {
2542 fprintf(stderr
, "task_for_pid() %s\n", mach_error_string(result
));
2546 result
= task_get_bootstrap_port(task
, &bport
);
2548 if (result
!= KERN_SUCCESS
) {
2549 fprintf(stderr
, "Couldn't get bootstrap port: %s\n", mach_error_string(result
));
2558 bsexec_cmd(int argc
, char *const argv
[])
2560 kern_return_t result
;
2564 fprintf(stderr
, "usage: %s bsexec <PID> prog...\n", getprogname());
2568 bport
= str2bsport(argv
[1]);
2570 result
= task_set_bootstrap_port(mach_task_self(), bport
);
2572 if (result
!= KERN_SUCCESS
) {
2573 fprintf(stderr
, "Couldn't switch to new bootstrap port: %s\n", mach_error_string(result
));
2580 if (fwexec((const char *const *)argv
+ 2, true) == -1) {
2581 fprintf(stderr
, "%s bsexec failed: %s\n", getprogname(), strerror(errno
));
2589 bslist_cmd(int argc
, char *const argv
[])
2591 kern_return_t result
;
2592 mach_port_t bport
= bootstrap_port
;
2593 name_array_t service_names
;
2594 mach_msg_type_number_t service_cnt
, service_active_cnt
;
2595 bootstrap_status_array_t service_actives
;
2599 bport
= str2bsport(argv
[1]);
2601 if (bport
== MACH_PORT_NULL
) {
2602 fprintf(stderr
, "Invalid bootstrap port\n");
2606 result
= bootstrap_info(bport
, &service_names
, &service_cnt
, &service_actives
, &service_active_cnt
);
2607 if (result
!= BOOTSTRAP_SUCCESS
) {
2608 fprintf(stderr
, "bootstrap_info(): %d\n", result
);
2612 #define bport_state(x) (((x) == BOOTSTRAP_STATUS_ACTIVE) ? "A" : ((x) == BOOTSTRAP_STATUS_ON_DEMAND) ? "D" : "I")
2614 for (i
= 0; i
< service_cnt
; i
++)
2615 fprintf(stdout
, "%-3s%s\n", bport_state((service_actives
[i
])), service_names
[i
]);
2621 is_legacy_mach_job(launch_data_t obj
)
2623 bool has_servicename
= launch_data_dict_lookup(obj
, MACHINIT_JOBKEY_SERVICENAME
);
2624 bool has_command
= launch_data_dict_lookup(obj
, MACHINIT_JOBKEY_COMMAND
);
2625 bool has_label
= launch_data_dict_lookup(obj
, LAUNCH_JOBKEY_LABEL
);
2627 return has_command
&& has_servicename
&& !has_label
;
2631 _log_launchctl_bug(const char *rcs_rev
, const char *path
, unsigned int line
, const char *test
)
2633 int saved_errno
= errno
;
2635 const char *file
= strrchr(path
, '/');
2636 char *rcs_rev_tmp
= strchr(rcs_rev
, ' ');
2645 strlcpy(buf
, rcs_rev
, sizeof(buf
));
2647 strlcpy(buf
, rcs_rev_tmp
+ 1, sizeof(buf
));
2648 rcs_rev_tmp
= strchr(buf
, ' ');
2650 *rcs_rev_tmp
= '\0';
2653 fprintf(stderr
, "Bug: %s:%u (%s):%u: %s\n", file
, line
, buf
, saved_errno
, test
);
2657 loopback_setup_ipv4(void)
2659 struct ifaliasreq ifra
;
2663 memset(&ifr
, 0, sizeof(ifr
));
2664 strcpy(ifr
.ifr_name
, "lo0");
2666 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
2669 if (assumes(ioctl(s
, SIOCGIFFLAGS
, &ifr
) != -1)) {
2670 ifr
.ifr_flags
|= IFF_UP
;
2671 assumes(ioctl(s
, SIOCSIFFLAGS
, &ifr
) != -1);
2674 memset(&ifra
, 0, sizeof(ifra
));
2675 strcpy(ifra
.ifra_name
, "lo0");
2676 ((struct sockaddr_in
*)&ifra
.ifra_addr
)->sin_family
= AF_INET
;
2677 ((struct sockaddr_in
*)&ifra
.ifra_addr
)->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
2678 ((struct sockaddr_in
*)&ifra
.ifra_addr
)->sin_len
= sizeof(struct sockaddr_in
);
2679 ((struct sockaddr_in
*)&ifra
.ifra_mask
)->sin_family
= AF_INET
;
2680 ((struct sockaddr_in
*)&ifra
.ifra_mask
)->sin_addr
.s_addr
= htonl(IN_CLASSA_NET
);
2681 ((struct sockaddr_in
*)&ifra
.ifra_mask
)->sin_len
= sizeof(struct sockaddr_in
);
2683 assumes(ioctl(s
, SIOCAIFADDR
, &ifra
) != -1);
2685 assumes(close(s
) == 0);
2689 loopback_setup_ipv6(void)
2691 struct in6_aliasreq ifra6
;
2695 memset(&ifr
, 0, sizeof(ifr
));
2696 strcpy(ifr
.ifr_name
, "lo0");
2698 if ((s6
= socket(AF_INET6
, SOCK_DGRAM
, 0)) == -1)
2701 memset(&ifr
, 0, sizeof(ifr
));
2702 strcpy(ifr
.ifr_name
, "lo0");
2704 if (assumes(ioctl(s6
, SIOCGIFFLAGS
, &ifr
) != -1)) {
2705 ifr
.ifr_flags
|= IFF_UP
;
2706 assumes(ioctl(s6
, SIOCSIFFLAGS
, &ifr
) != -1);
2709 memset(&ifra6
, 0, sizeof(ifra6
));
2710 strcpy(ifra6
.ifra_name
, "lo0");
2712 ifra6
.ifra_addr
.sin6_family
= AF_INET6
;
2713 ifra6
.ifra_addr
.sin6_addr
= in6addr_loopback
;
2714 ifra6
.ifra_addr
.sin6_len
= sizeof(struct sockaddr_in6
);
2715 ifra6
.ifra_prefixmask
.sin6_family
= AF_INET6
;
2716 memset(&ifra6
.ifra_prefixmask
.sin6_addr
, 0xff, sizeof(struct in6_addr
));
2717 ifra6
.ifra_prefixmask
.sin6_len
= sizeof(struct sockaddr_in6
);
2718 ifra6
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
2719 ifra6
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
2721 assumes(ioctl(s6
, SIOCAIFADDR_IN6
, &ifra6
) != -1);
2723 assumes(close(s6
) == 0);
2727 fwexec(const char *const *argv
, bool _wait
)
2732 switch ((p
= fork())) {
2739 execvp(argv
[0], (char *const *)argv
);
2740 _exit(EXIT_FAILURE
);
2745 if (p
== waitpid(p
, &wstatus
, 0)) {
2746 if (WIFEXITED(wstatus
) && WEXITSTATUS(wstatus
) == EXIT_SUCCESS
)
2756 do_potential_fsck(void)
2758 const char *safe_fsck_tool
[] = { "fsck", "-fy", NULL
};
2759 const char *fsck_tool
[] = { "fsck", "-p", NULL
};
2760 const char *remount_tool
[] = { "mount", "-uw", "/", NULL
};
2763 if (!assumes(statfs("/", &sfs
) != -1)) {
2767 if (!(sfs
.f_flags
& MNT_RDONLY
)) {
2771 if (!is_safeboot()) {
2773 /* We have disabled this block for now. We need to revisit this optimization after Leopard. */
2774 if (sfs
.f_flags
& MNT_JOURNALED
) {
2779 if (fwexec(fsck_tool
, true) != -1) {
2784 if (fwexec(safe_fsck_tool
, true) != -1) {
2788 fprintf(stderr
, "fsck failed!\n");
2790 /* someday, we should keep booting read-only, but as of today, other sub-systems cannot handle that scenario */
2791 #if TARGET_OS_EMBEDDED
2792 const char *nvram_tool
[] = { "/usr/sbin/nvram", "auto-boot=false", NULL
};
2793 assumes(fwexec(nvram_tool
, true) != -1);
2794 assumes(reboot(RB_AUTOBOOT
) != -1);
2796 assumes(reboot(RB_HALT
) != -1);
2802 * Once this is fixed:
2804 * <rdar://problem/3948774> Mount flag updates should be possible with NULL as the forth argument to mount()
2806 * We can then do this one system call instead of calling out a full blown process.
2808 * assumes(mount(sfs.f_fstypename, "/", MNT_UPDATE, NULL) != -1);
2811 #if TARGET_OS_EMBEDDED
2812 if (path_check("/etc/fstab")) {
2813 const char *mount_tool
[] = { "mount", "-vat", "nonfs", NULL
};
2814 if (!assumes(fwexec(mount_tool
, true) != -1)) {
2815 assumes(fwexec(nvram_tool
, true) != -1);
2816 assumes(reboot(RB_AUTOBOOT
) != -1);
2821 assumes(fwexec(remount_tool
, true) != -1);
2824 fix_bogus_file_metadata();
2828 fix_bogus_file_metadata(void)
2830 static const struct {
2834 const mode_t needed_bits
;
2835 const mode_t bad_bits
;
2837 { "/sbin/launchd", 0, 0, S_IRUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
, S_ISUID
|S_ISGID
|S_ISVTX
|S_IWOTH
},
2838 { _PATH_TMP
, 0, 0, S_ISTXT
|S_IRWXU
|S_IRWXG
|S_IRWXO
, S_ISUID
|S_ISGID
},
2839 { _PATH_VARTMP
, 0, 0, S_ISTXT
|S_IRWXU
|S_IRWXG
|S_IRWXO
, S_ISUID
|S_ISGID
},
2844 for (i
= 0; i
< (sizeof(f
) / sizeof(f
[0])); i
++) {
2845 mode_t i_needed_bits
;
2847 bool fix_mode
= false;
2848 bool fix_id
= false;
2850 if (!assumes(stat(f
[i
].path
, &sb
) != -1)) {
2854 i_needed_bits
= ~sb
.st_mode
& f
[i
].needed_bits
;
2855 i_bad_bits
= sb
.st_mode
& f
[i
].bad_bits
;
2858 fprintf(stderr
, "Crucial filesystem check: Removing bogus mode bits 0%o on path: %s\n", i_bad_bits
, f
[i
].path
);
2861 if (i_needed_bits
) {
2862 fprintf(stderr
, "Crucial filesystem check: Adding missing mode bits 0%o on path: %s\n", i_needed_bits
, f
[i
].path
);
2865 if (sb
.st_uid
!= f
[i
].owner
) {
2866 fprintf(stderr
, "Crucial filesystem check: Fixing bogus UID %u on path: %s\n", sb
.st_uid
, f
[i
].path
);
2869 if (sb
.st_gid
!= f
[i
].group
) {
2870 fprintf(stderr
, "Crucial filesystem check: Fixing bogus GID %u on path: %s\n", sb
.st_gid
, f
[i
].path
);
2875 assumes(chmod(f
[i
].path
, (sb
.st_mode
& ~i_bad_bits
) | i_needed_bits
) != -1);
2878 assumes(chown(f
[i
].path
, f
[i
].owner
, f
[i
].group
) != -1);
2884 path_check(const char *path
)
2888 if (stat(path
, &sb
) == 0)
2896 int sbmib
[] = { CTL_KERN
, KERN_SAFEBOOT
};
2898 size_t sbsz
= sizeof(sb
);
2900 if (!assumes(sysctl(sbmib
, 2, &sb
, &sbsz
, NULL
, 0) == 0))
2909 int nbmib
[] = { CTL_KERN
, KERN_NETBOOT
};
2911 size_t nbsz
= sizeof(nb
);
2913 if (!assumes(sysctl(nbmib
, 2, &nb
, &nbsz
, NULL
, 0) == 0))
2920 empty_dir(const char *thedir
, struct stat
*psb
)
2929 if (!assumes(lstat(thedir
, psb
) != -1)) {
2934 if (!assumes((currend_dir_fd
= open(".", 0)) != -1)) {
2938 if (!assumes(chdir(thedir
) != -1)) {
2942 if (!assumes(od
= opendir("."))) {
2946 while ((de
= readdir(od
))) {
2949 if (strcmp(de
->d_name
, ".") == 0) {
2953 if (strcmp(de
->d_name
, "..") == 0) {
2957 if (!assumes(lstat(de
->d_name
, &sb
) != -1)) {
2961 if (psb
->st_dev
!= sb
.st_dev
) {
2962 assumes(unmount(de
->d_name
, MNT_FORCE
) != -1);
2964 /* Let's lstat() again to see if the unmount() worked and what was under it */
2965 if (!assumes(lstat(de
->d_name
, &sb
) != -1)) {
2969 if (!assumes(psb
->st_dev
== sb
.st_dev
)) {
2974 if (S_ISDIR(sb
.st_mode
)) {
2975 empty_dir(de
->d_name
, &sb
);
2978 assumes(lchflags(de
->d_name
, 0) != -1);
2979 assumes(remove(de
->d_name
) != -1);
2982 assumes(closedir(od
) != -1);
2985 assumes(fchdir(currend_dir_fd
) != -1);
2986 assumes(close(currend_dir_fd
) != -1);
2990 touch_file(const char *path
, mode_t m
)
2992 int fd
= open(path
, O_CREAT
, m
);
3001 apply_sysctls_from_file(const char *thefile
)
3003 const char *sysctl_tool
[] = { "sysctl", "-w", NULL
, NULL
};
3008 if (!(sf
= fopen(thefile
, "r")))
3011 while ((val
= fgetln(sf
, &ln_len
))) {
3015 if (!assumes((tmpstr
= malloc(ln_len
+ 1)) != NULL
)) {
3018 memcpy(tmpstr
, val
, ln_len
);
3022 if (val
[ln_len
- 1] == '\n' || val
[ln_len
- 1] == '\r') {
3023 val
[ln_len
- 1] = '\0';
3026 while (*val
&& isspace(*val
))
3028 if (*val
== '\0' || *val
== '#') {
3029 goto skip_sysctl_tool
;
3031 sysctl_tool
[2] = val
;
3032 assumes(fwexec(sysctl_tool
, true) != -1);
3037 assumes(fclose(sf
) == 0);
3041 do_sysversion_sysctl(void)
3043 int mib
[] = { CTL_KERN
, KERN_OSVERSION
};
3044 CFDictionaryRef versdict
;
3045 CFStringRef buildvers
;
3047 size_t bufsz
= sizeof(buf
);
3049 /* <rdar://problem/4477682> ER: launchd should set kern.osversion very early in boot */
3051 if (sysctl(mib
, 2, buf
, &bufsz
, NULL
, 0) == -1) {
3052 fprintf(stderr
, "sysctl(): %s\n", strerror(errno
));
3056 if (buf
[0] != '\0') {
3060 if (!assumes((versdict
= _CFCopySystemVersionDictionary()))) {
3064 if (assumes((buildvers
= CFDictionaryGetValue(versdict
, _kCFSystemVersionBuildVersionKey
)))) {
3065 CFStringGetCString(buildvers
, buf
, sizeof(buf
), kCFStringEncodingUTF8
);
3067 assumes(sysctl(mib
, 2, NULL
, 0, buf
, strlen(buf
) + 1) != -1);
3070 CFRelease(versdict
);
3074 do_application_firewall_magic(int sfd
, launch_data_t thejob
)
3076 const char *prog
= NULL
, *partialprog
= NULL
;
3077 char *path
, *pathtmp
, **pathstmp
;
3083 * <rdar://problem/4684434> setsockopt() with the executable path as the argument
3086 if ((tmp
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_PROGRAM
))) {
3087 prog
= launch_data_get_string(tmp
);
3091 if ((tmp
= launch_data_dict_lookup(thejob
, LAUNCH_JOBKEY_PROGRAMARGUMENTS
))) {
3092 if ((tmp
= launch_data_array_get_index(tmp
, 0))) {
3093 if (assumes((partialprog
= launch_data_get_string(tmp
)) != NULL
)) {
3094 if (partialprog
[0] == '/') {
3103 pathtmp
= path
= strdup(getenv("PATH"));
3107 while ((*pathstmp
= strsep(&pathtmp
, ":"))) {
3108 if (**pathstmp
!= '\0') {
3114 pathtmp
= alloca(MAXPATHLEN
);
3118 for (; *pathstmp
; pathstmp
++) {
3119 snprintf(pathtmp
, MAXPATHLEN
, "%s/%s", *pathstmp
, partialprog
);
3120 if (path_check(pathtmp
)) {
3127 if (assumes(prog
!= NULL
)) {
3128 /* The networking team has asked us to ignore the failure of this API if errno == ENOPROTOOPT */
3129 assumes(setsockopt(sfd
, SOL_SOCKET
, SO_EXECPATH
, prog
, strlen(prog
) + 1) != -1 || errno
== ENOPROTOOPT
);
3135 preheat_page_cache_hack(void)
3140 /* Disable this hack for now */
3143 if ((thedir
= opendir("/etc/preheat_at_boot")) == NULL
) {
3147 while ((de
= readdir(thedir
))) {
3152 if (de
->d_name
[0] == '.') {
3156 if ((fd
= open(de
->d_name
, O_RDONLY
)) == -1) {
3160 if (fstat(fd
, &sb
) != -1) {
3161 if ((sb
.st_size
< 10*1024*1024) && (junkbuf
= malloc((size_t)sb
.st_size
)) != NULL
) {
3162 assumes(read(fd
, junkbuf
, (size_t)sb
.st_size
) == (ssize_t
)sb
.st_size
);
3175 do_bootroot_magic(void)
3177 const char *kextcache_tool
[] = { "kextcache", "-U", "/", NULL
};
3178 CFTypeRef bootrootProp
;
3179 io_service_t chosen
;
3183 chosen
= IORegistryEntryFromPath(kIOMasterPortDefault
, "IODeviceTree:/chosen");
3185 if (!assumes(chosen
)) {
3189 bootrootProp
= IORegistryEntryCreateCFProperty(chosen
, CFSTR(kBootRootActiveKey
), kCFAllocatorDefault
, 0);
3191 IOObjectRelease(chosen
);
3193 if (!bootrootProp
) {
3197 CFRelease(bootrootProp
);
3199 if (!assumes((p
= fwexec(kextcache_tool
, false)) != -1)) {
3203 if (!assumes(waitpid(p
, &wstatus
, 0) != -1)) {
3207 if (WIFEXITED(wstatus
) && WEXITSTATUS(wstatus
) == EX_OSFILE
) {
3208 assumes(reboot(RB_AUTOBOOT
) != -1);