2 * Copyright (c) 1999-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@
22 #include "libvproc_public.h"
23 #include "libvproc_private.h"
24 #include "libvproc_internal.h"
26 #include <mach/mach.h>
27 #include <mach/vm_map.h>
28 #include <sys/param.h>
36 #include "liblaunch_public.h"
37 #include "liblaunch_private.h"
38 #include "liblaunch_internal.h"
40 #include "protocol_vproc.h"
44 static mach_port_t
get_root_bootstrap_port(void);
46 static int64_t cached_pid
= -1;
49 _vproc_grab_subset(mach_port_t bp
, mach_port_t
*reqport
, mach_port_t
*rcvright
, launch_data_t
*outval
,
50 mach_port_array_t
*ports
, mach_msg_type_number_t
*portCnt
)
52 mach_msg_type_number_t outdata_cnt
;
53 vm_offset_t outdata
= 0;
54 size_t data_offset
= 0;
55 launch_data_t out_obj
;
58 if ((kr
= vproc_mig_take_subset(bp
, reqport
, rcvright
, &outdata
, &outdata_cnt
, ports
, portCnt
))) {
62 if ((out_obj
= launch_data_unpack((void *)outdata
, outdata_cnt
, NULL
, 0, &data_offset
, NULL
))) {
63 *outval
= launch_data_copy(out_obj
);
70 mig_deallocate(outdata
, outdata_cnt
);
77 _vproc_post_fork_ping(void)
79 return vproc_mig_post_fork_ping(bootstrap_port
, mach_task_self()) == 0 ? NULL
: _vproc_post_fork_ping
;
83 setup_env_hack(const launch_data_t obj
, const char *key
, void *context
__attribute__((unused
)))
85 setenv(key
, launch_data_get_string(obj
), 1);
89 _vprocmgr_init(const char *session_type
)
91 if (vproc_mig_move_subset(bootstrap_port
, MACH_PORT_NULL
, (char *)session_type
) == 0) {
95 return (vproc_err_t
)_vprocmgr_init
;
99 _vprocmgr_move_subset_to_user(uid_t target_user
, const char *session_type
)
101 launch_data_t output_obj
;
102 kern_return_t kr
= 0;
103 bool is_bkgd
= (strcmp(session_type
, VPROCMGR_SESSION_BACKGROUND
) == 0);
104 int64_t ldpid
, lduid
;
106 if (vproc_swap_integer(NULL
, VPROC_GSK_MGR_PID
, 0, &ldpid
) != 0) {
107 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
110 if (vproc_swap_integer(NULL
, VPROC_GSK_MGR_UID
, 0, &lduid
) != 0) {
111 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
114 if (!is_bkgd
&& ldpid
!= 1) {
115 if (lduid
== getuid()) {
119 * Not all sessions can be moved.
120 * We should clean up this mess someday.
122 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
125 if (is_bkgd
|| target_user
) {
126 mach_port_t puc
= 0, rootbs
= get_root_bootstrap_port();
128 if (vproc_mig_lookup_per_user_context(rootbs
, target_user
, &puc
) != 0) {
129 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
133 task_set_bootstrap_port(mach_task_self(), puc
);
134 mach_port_deallocate(mach_task_self(), bootstrap_port
);
135 bootstrap_port
= puc
;
137 kr
= vproc_mig_move_subset(puc
, bootstrap_port
, (char *)session_type
);
138 mach_port_deallocate(mach_task_self(), puc
);
141 kr
= _vprocmgr_init(session_type
) ? 1 : 0;
147 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
150 /* XXX We need to give 'nohup' a better API after Leopard ships */
151 if (getprogname() && strcmp(getprogname(), "nohup") != 0) {
152 if (vproc_swap_complex(NULL
, VPROC_GSK_ENVIRONMENT
, NULL
, &output_obj
) == NULL
) {
153 if (launch_data_get_type(output_obj
) == LAUNCH_DATA_DICTIONARY
) {
154 launch_data_dict_iterate(output_obj
, setup_env_hack
, NULL
);
155 launch_data_free(output_obj
);
160 return _vproc_post_fork_ping();
165 _spawn_via_launchd(const char *label
, const char *const *argv
, const struct spawn_via_launchd_attr
*spawn_attrs
, int struct_version
)
167 size_t i
, good_enough_size
= 10*1024*1024;
168 mach_msg_type_number_t indata_cnt
= 0;
169 vm_offset_t indata
= 0;
170 mach_port_t obsvr_port
= MACH_PORT_NULL
;
171 launch_data_t tmp
, tmp_array
, in_obj
;
172 const char *const *tmpp
;
173 kern_return_t kr
= 1;
177 if ((in_obj
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
)) == NULL
) {
181 if ((tmp
= launch_data_new_string(label
)) == NULL
) {
185 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_LABEL
);
187 if ((tmp_array
= launch_data_alloc(LAUNCH_DATA_ARRAY
)) == NULL
) {
191 for (i
= 0; *argv
; i
++, argv
++) {
192 tmp
= launch_data_new_string(*argv
);
197 launch_data_array_set_index(tmp_array
, tmp
, i
);
200 launch_data_dict_insert(in_obj
, tmp_array
, LAUNCH_JOBKEY_PROGRAMARGUMENTS
);
202 if (spawn_attrs
) switch (struct_version
) {
204 if (spawn_attrs
->spawn_quarantine
) {
205 char qbuf
[QTN_SERIALIZED_DATA_MAX
];
206 size_t qbuf_sz
= QTN_SERIALIZED_DATA_MAX
;
208 if (qtn_proc_to_data(spawn_attrs
->spawn_quarantine
, qbuf
, &qbuf_sz
) == 0) {
209 tmp
= launch_data_new_opaque(qbuf
, qbuf_sz
);
210 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_QUARANTINEDATA
);
214 if (spawn_attrs
->spawn_seatbelt_profile
) {
215 tmp
= launch_data_new_string(spawn_attrs
->spawn_seatbelt_profile
);
216 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_SANDBOXPROFILE
);
219 if (spawn_attrs
->spawn_seatbelt_flags
) {
220 tmp
= launch_data_new_integer(*spawn_attrs
->spawn_seatbelt_flags
);
221 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_SANDBOXFLAGS
);
226 if (spawn_attrs
->spawn_binpref
) {
227 tmp_array
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
228 for (i
= 0; i
< spawn_attrs
->spawn_binpref_cnt
; i
++) {
229 tmp
= launch_data_new_integer(spawn_attrs
->spawn_binpref
[i
]);
230 launch_data_array_set_index(tmp_array
, tmp
, i
);
232 launch_data_dict_insert(in_obj
, tmp_array
, LAUNCH_JOBKEY_BINARYORDERPREFERENCE
);
236 if (spawn_attrs
->spawn_flags
& SPAWN_VIA_LAUNCHD_STOPPED
) {
237 tmp
= launch_data_new_bool(true);
238 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_WAITFORDEBUGGER
);
241 if (spawn_attrs
->spawn_env
) {
242 launch_data_t tmp_dict
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
244 for (tmpp
= spawn_attrs
->spawn_env
; *tmpp
; tmpp
++) {
245 char *eqoff
, tmpstr
[strlen(*tmpp
) + 1];
247 strcpy(tmpstr
, *tmpp
);
249 eqoff
= strchr(tmpstr
, '=');
257 launch_data_dict_insert(tmp_dict
, launch_data_new_string(eqoff
+ 1), tmpstr
);
260 launch_data_dict_insert(in_obj
, tmp_dict
, LAUNCH_JOBKEY_ENVIRONMENTVARIABLES
);
263 if (spawn_attrs
->spawn_path
) {
264 tmp
= launch_data_new_string(spawn_attrs
->spawn_path
);
265 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_PROGRAM
);
268 if (spawn_attrs
->spawn_chdir
) {
269 tmp
= launch_data_new_string(spawn_attrs
->spawn_chdir
);
270 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_WORKINGDIRECTORY
);
273 if (spawn_attrs
->spawn_umask
) {
274 tmp
= launch_data_new_integer(*spawn_attrs
->spawn_umask
);
275 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_UMASK
);
283 if (!(buf
= malloc(good_enough_size
))) {
287 if ((indata_cnt
= launch_data_pack(in_obj
, buf
, good_enough_size
, NULL
, NULL
)) == 0) {
291 indata
= (vm_offset_t
)buf
;
293 kr
= vproc_mig_spawn(bootstrap_port
, indata
, indata_cnt
, &p
, &obsvr_port
);
295 if (kr
== VPROC_ERR_TRY_PER_USER
) {
298 if (vproc_mig_lookup_per_user_context(bootstrap_port
, 0, &puc
) == 0) {
299 kr
= vproc_mig_spawn(puc
, indata
, indata_cnt
, &p
, &obsvr_port
);
300 mach_port_deallocate(mach_task_self(), puc
);
306 launch_data_free(in_obj
);
314 case BOOTSTRAP_SUCCESS
:
315 if (spawn_attrs
&& spawn_attrs
->spawn_observer_port
) {
316 *spawn_attrs
->spawn_observer_port
= obsvr_port
;
318 mach_port_deallocate(mach_task_self(), obsvr_port
);
321 case BOOTSTRAP_NOT_PRIVILEGED
:
322 errno
= EPERM
; break;
323 case BOOTSTRAP_NO_MEMORY
:
324 errno
= ENOMEM
; break;
325 case BOOTSTRAP_NAME_IN_USE
:
326 errno
= EEXIST
; break;
330 errno
= EINVAL
; break;
337 mpm_wait(mach_port_t ajob
__attribute__((unused
)), int *wstatus
)
339 return vproc_mig_wait(ajob
, wstatus
);
343 mpm_uncork_fork(mach_port_t ajob
)
345 return vproc_mig_uncork_fork(ajob
);
349 _vprocmgr_getsocket(name_t sockpath
)
351 return vproc_mig_getsocket(bootstrap_port
, sockpath
);
355 _vproc_get_last_exit_status(int *wstatus
)
359 if (vproc_swap_integer(NULL
, VPROC_GSK_LAST_EXIT_STATUS
, 0, &val
) == 0) {
364 return (vproc_err_t
)_vproc_get_last_exit_status
;
368 _vproc_send_signal_by_label(const char *label
, int sig
)
370 if (vproc_mig_send_signal(bootstrap_port
, (char *)label
, sig
) == 0) {
374 return _vproc_send_signal_by_label
;
378 _vprocmgr_log_forward(mach_port_t mp
, void *data
, size_t len
)
380 if (vproc_mig_log_forward(mp
, (vm_offset_t
)data
, len
) == 0) {
384 return _vprocmgr_log_forward
;
388 _vprocmgr_log_drain(vproc_t vp
__attribute__((unused
)), pthread_mutex_t
*mutex
, _vprocmgr_log_drain_callback_t func
)
390 mach_msg_type_number_t outdata_cnt
, tmp_cnt
;
391 vm_offset_t outdata
= 0;
395 return _vprocmgr_log_drain
;
398 if (vproc_mig_log_drain(bootstrap_port
, &outdata
, &outdata_cnt
) != 0) {
399 return _vprocmgr_log_drain
;
402 tmp_cnt
= outdata_cnt
;
405 pthread_mutex_lock(mutex
);
408 for (lm
= (struct logmsg_s
*)outdata
; tmp_cnt
> 0; lm
= ((void *)lm
+ lm
->obj_sz
)) {
409 lm
->from_name
+= (size_t)lm
;
410 lm
->about_name
+= (size_t)lm
;
411 lm
->msg
+= (size_t)lm
;
412 lm
->session_name
+= (size_t)lm
;
414 func(&lm
->when
, lm
->from_pid
, lm
->about_pid
, lm
->sender_uid
, lm
->sender_gid
, lm
->pri
,
415 lm
->from_name
, lm
->about_name
, lm
->session_name
, lm
->msg
);
417 tmp_cnt
-= lm
->obj_sz
;
421 pthread_mutex_unlock(mutex
);
425 mig_deallocate(outdata
, outdata_cnt
);
432 vproc_swap_integer(vproc_t vp
__attribute__((unused
)), vproc_gsk_t key
, int64_t *inval
, int64_t *outval
)
434 static int64_t cached_is_managed
= -1;
435 int64_t dummyval
= 0;
438 case VPROC_GSK_MGR_PID
:
439 if (cached_pid
!= -1 && outval
) {
440 *outval
= cached_pid
;
444 case VPROC_GSK_IS_MANAGED
:
445 if (cached_is_managed
!= -1 && outval
) {
446 *outval
= cached_is_managed
;
454 if (vproc_mig_swap_integer(bootstrap_port
, inval
? key
: 0, outval
? key
: 0, inval
? *inval
: 0, outval
? outval
: &dummyval
) == 0) {
456 case VPROC_GSK_MGR_PID
:
457 cached_pid
= outval
? *outval
: dummyval
;
459 case VPROC_GSK_IS_MANAGED
:
460 cached_is_managed
= outval
? *outval
: dummyval
;
468 return (vproc_err_t
)vproc_swap_integer
;
472 get_root_bootstrap_port(void)
474 mach_port_t parent_port
= 0;
475 mach_port_t previous_port
= 0;
479 if (previous_port
!= bootstrap_port
) {
480 mach_port_deallocate(mach_task_self(), previous_port
);
482 previous_port
= parent_port
;
484 previous_port
= bootstrap_port
;
487 if (bootstrap_parent(previous_port
, &parent_port
) != 0) {
488 return MACH_PORT_NULL
;
491 } while (parent_port
!= previous_port
);
497 vproc_swap_complex(vproc_t vp
__attribute__((unused
)), vproc_gsk_t key
, launch_data_t inval
, launch_data_t
*outval
)
499 size_t data_offset
= 0, good_enough_size
= 10*1024*1024;
500 mach_msg_type_number_t indata_cnt
= 0, outdata_cnt
;
501 vm_offset_t indata
= 0, outdata
= 0;
502 launch_data_t out_obj
;
503 void *rval
= vproc_swap_complex
;
507 if (!(buf
= malloc(good_enough_size
))) {
511 if ((indata_cnt
= launch_data_pack(inval
, buf
, good_enough_size
, NULL
, NULL
)) == 0) {
515 indata
= (vm_offset_t
)buf
;
518 if (vproc_mig_swap_complex(bootstrap_port
, inval
? key
: 0, outval
? key
: 0, indata
, indata_cnt
, &outdata
, &outdata_cnt
) != 0) {
523 if (!(out_obj
= launch_data_unpack((void *)outdata
, outdata_cnt
, NULL
, 0, &data_offset
, NULL
))) {
527 if (!(*outval
= launch_data_copy(out_obj
))) {
539 mig_deallocate(outdata
, outdata_cnt
);
546 reboot2(uint64_t flags
)
548 if (vproc_mig_reboot2(get_root_bootstrap_port(), flags
) == 0) {
556 _vproc_set_global_on_demand(bool state
)
558 int64_t val
= state
? ~0 : 0;
560 if (vproc_swap_integer(NULL
, VPROC_GSK_GLOBAL_ON_DEMAND
, &val
, NULL
) == 0) {
564 return (vproc_err_t
)_vproc_set_global_on_demand
;
568 _vproc_logv(int pri
, int err
, const char *msg
, va_list ap
)
572 vsnprintf(flat_msg
, sizeof(flat_msg
), msg
, ap
);
574 vproc_mig_log(bootstrap_port
, pri
, err
, flat_msg
);
578 _vproc_log(int pri
, const char *msg
, ...)
583 _vproc_logv(pri
, 0, msg
, ap
);
588 _vproc_log_error(int pri
, const char *msg
, ...)
590 int saved_errno
= errno
;
594 _vproc_logv(pri
, saved_errno
, msg
, ap
);