]>
Commit | Line | Data |
---|---|---|
5b0a4722 A |
1 | /* |
2 | * Copyright (c) 1999-2005 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_APACHE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | * you may not use this file except in compliance with the License. | |
8 | * You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, software | |
13 | * distributed under the License is distributed on an "AS IS" BASIS, | |
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | * See the License for the specific language governing permissions and | |
16 | * limitations under the License. | |
17 | * | |
18 | * @APPLE_APACHE_LICENSE_HEADER_END@ | |
19 | */ | |
20 | ||
21 | #include "config.h" | |
ef398931 A |
22 | #include "vproc.h" |
23 | #include "vproc_priv.h" | |
24 | #include "vproc_internal.h" | |
5b0a4722 A |
25 | |
26 | #include <mach/mach.h> | |
27 | #include <mach/vm_map.h> | |
28 | #include <sys/param.h> | |
29 | #include <stdlib.h> | |
30 | #include <stdio.h> | |
31 | #include <errno.h> | |
32 | #include <unistd.h> | |
33 | #include <syslog.h> | |
34 | #include <pthread.h> | |
f36da725 A |
35 | #if HAVE_QUARANTINE |
36 | #include <quarantine.h> | |
37 | #endif | |
5b0a4722 | 38 | |
ef398931 A |
39 | #include "launch.h" |
40 | #include "launch_priv.h" | |
41 | #include "launch_internal.h" | |
5b0a4722 A |
42 | |
43 | #include "protocol_vproc.h" | |
44 | ||
45 | #include "reboot2.h" | |
46 | ||
47 | static mach_port_t get_root_bootstrap_port(void); | |
48 | ||
49 | static int64_t cached_pid = -1; | |
50 | ||
51 | kern_return_t | |
52 | _vproc_grab_subset(mach_port_t bp, mach_port_t *reqport, mach_port_t *rcvright, launch_data_t *outval, | |
53 | mach_port_array_t *ports, mach_msg_type_number_t *portCnt) | |
54 | { | |
55 | mach_msg_type_number_t outdata_cnt; | |
56 | vm_offset_t outdata = 0; | |
57 | size_t data_offset = 0; | |
58 | launch_data_t out_obj; | |
59 | kern_return_t kr; | |
60 | ||
61 | if ((kr = vproc_mig_take_subset(bp, reqport, rcvright, &outdata, &outdata_cnt, ports, portCnt))) { | |
62 | goto out; | |
63 | } | |
64 | ||
65 | if ((out_obj = launch_data_unpack((void *)outdata, outdata_cnt, NULL, 0, &data_offset, NULL))) { | |
66 | *outval = launch_data_copy(out_obj); | |
67 | } else { | |
68 | kr = 1; | |
69 | } | |
70 | ||
71 | out: | |
72 | if (outdata) { | |
73 | mig_deallocate(outdata, outdata_cnt); | |
74 | } | |
75 | ||
76 | return kr; | |
77 | } | |
78 | ||
79 | vproc_err_t | |
80 | _vproc_post_fork_ping(void) | |
81 | { | |
82 | return vproc_mig_post_fork_ping(bootstrap_port, mach_task_self()) == 0 ? NULL : _vproc_post_fork_ping; | |
83 | } | |
84 | ||
85 | static void | |
86 | setup_env_hack(const launch_data_t obj, const char *key, void *context __attribute__((unused))) | |
87 | { | |
88 | setenv(key, launch_data_get_string(obj), 1); | |
89 | } | |
90 | ||
91 | vproc_err_t | |
92 | _vprocmgr_init(const char *session_type) | |
93 | { | |
94 | if (vproc_mig_move_subset(bootstrap_port, MACH_PORT_NULL, (char *)session_type) == 0) { | |
95 | return NULL; | |
96 | } | |
97 | ||
98 | return (vproc_err_t)_vprocmgr_init; | |
99 | } | |
100 | ||
101 | vproc_err_t | |
102 | _vprocmgr_move_subset_to_user(uid_t target_user, const char *session_type) | |
103 | { | |
104 | launch_data_t output_obj; | |
105 | kern_return_t kr = 0; | |
106 | bool is_bkgd = (strcmp(session_type, VPROCMGR_SESSION_BACKGROUND) == 0); | |
107 | int64_t ldpid, lduid; | |
108 | ||
109 | if (vproc_swap_integer(NULL, VPROC_GSK_MGR_PID, 0, &ldpid) != 0) { | |
110 | return (vproc_err_t)_vprocmgr_move_subset_to_user; | |
111 | } | |
112 | ||
113 | if (vproc_swap_integer(NULL, VPROC_GSK_MGR_UID, 0, &lduid) != 0) { | |
114 | return (vproc_err_t)_vprocmgr_move_subset_to_user; | |
115 | } | |
116 | ||
117 | if (!is_bkgd && ldpid != 1) { | |
118 | if (lduid == getuid()) { | |
119 | return NULL; | |
120 | } | |
121 | /* | |
122 | * Not all sessions can be moved. | |
123 | * We should clean up this mess someday. | |
124 | */ | |
125 | return (vproc_err_t)_vprocmgr_move_subset_to_user; | |
126 | } | |
127 | ||
128 | if (is_bkgd || target_user) { | |
129 | mach_port_t puc = 0, rootbs = get_root_bootstrap_port(); | |
130 | ||
131 | if (vproc_mig_lookup_per_user_context(rootbs, target_user, &puc) != 0) { | |
132 | return (vproc_err_t)_vprocmgr_move_subset_to_user; | |
133 | } | |
134 | ||
135 | if (is_bkgd) { | |
136 | task_set_bootstrap_port(mach_task_self(), puc); | |
137 | mach_port_deallocate(mach_task_self(), bootstrap_port); | |
138 | bootstrap_port = puc; | |
139 | } else { | |
140 | kr = vproc_mig_move_subset(puc, bootstrap_port, (char *)session_type); | |
141 | mach_port_deallocate(mach_task_self(), puc); | |
142 | } | |
143 | } else { | |
144 | kr = _vprocmgr_init(session_type) ? 1 : 0; | |
145 | } | |
146 | ||
147 | cached_pid = -1; | |
148 | ||
149 | if (kr) { | |
150 | return (vproc_err_t)_vprocmgr_move_subset_to_user; | |
151 | } | |
152 | ||
153 | /* XXX We need to give 'nohup' a better API after Leopard ships */ | |
154 | if (getprogname() && strcmp(getprogname(), "nohup") != 0) { | |
155 | if (vproc_swap_complex(NULL, VPROC_GSK_ENVIRONMENT, NULL, &output_obj) == NULL) { | |
156 | if (launch_data_get_type(output_obj) == LAUNCH_DATA_DICTIONARY) { | |
157 | launch_data_dict_iterate(output_obj, setup_env_hack, NULL); | |
158 | launch_data_free(output_obj); | |
159 | } | |
160 | } | |
161 | } | |
162 | ||
163 | return _vproc_post_fork_ping(); | |
164 | } | |
165 | ||
166 | ||
167 | pid_t | |
168 | _spawn_via_launchd(const char *label, const char *const *argv, const struct spawn_via_launchd_attr *spawn_attrs, int struct_version) | |
169 | { | |
170 | size_t i, good_enough_size = 10*1024*1024; | |
171 | mach_msg_type_number_t indata_cnt = 0; | |
172 | vm_offset_t indata = 0; | |
173 | mach_port_t obsvr_port = MACH_PORT_NULL; | |
174 | launch_data_t tmp, tmp_array, in_obj; | |
175 | const char *const *tmpp; | |
176 | kern_return_t kr = 1; | |
177 | void *buf = NULL; | |
178 | pid_t p = -1; | |
179 | ||
180 | if ((in_obj = launch_data_alloc(LAUNCH_DATA_DICTIONARY)) == NULL) { | |
181 | goto out; | |
182 | } | |
183 | ||
184 | if ((tmp = launch_data_new_string(label)) == NULL) { | |
185 | goto out; | |
186 | } | |
187 | ||
188 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_LABEL); | |
189 | ||
190 | if ((tmp_array = launch_data_alloc(LAUNCH_DATA_ARRAY)) == NULL) { | |
191 | goto out; | |
192 | } | |
193 | ||
194 | for (i = 0; *argv; i++, argv++) { | |
195 | tmp = launch_data_new_string(*argv); | |
196 | if (tmp == NULL) { | |
197 | goto out; | |
198 | } | |
199 | ||
200 | launch_data_array_set_index(tmp_array, tmp, i); | |
201 | } | |
202 | ||
203 | launch_data_dict_insert(in_obj, tmp_array, LAUNCH_JOBKEY_PROGRAMARGUMENTS); | |
204 | ||
205 | if (spawn_attrs) switch (struct_version) { | |
206 | case 2: | |
f36da725 | 207 | #if HAVE_QUARANTINE |
5b0a4722 A |
208 | if (spawn_attrs->spawn_quarantine) { |
209 | char qbuf[QTN_SERIALIZED_DATA_MAX]; | |
210 | size_t qbuf_sz = QTN_SERIALIZED_DATA_MAX; | |
211 | ||
212 | if (qtn_proc_to_data(spawn_attrs->spawn_quarantine, qbuf, &qbuf_sz) == 0) { | |
213 | tmp = launch_data_new_opaque(qbuf, qbuf_sz); | |
214 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_QUARANTINEDATA); | |
215 | } | |
216 | } | |
f36da725 | 217 | #endif |
5b0a4722 A |
218 | |
219 | if (spawn_attrs->spawn_seatbelt_profile) { | |
220 | tmp = launch_data_new_string(spawn_attrs->spawn_seatbelt_profile); | |
221 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_SANDBOXPROFILE); | |
222 | } | |
223 | ||
224 | if (spawn_attrs->spawn_seatbelt_flags) { | |
225 | tmp = launch_data_new_integer(*spawn_attrs->spawn_seatbelt_flags); | |
226 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_SANDBOXFLAGS); | |
227 | } | |
228 | ||
229 | /* fall through */ | |
230 | case 1: | |
231 | if (spawn_attrs->spawn_binpref) { | |
232 | tmp_array = launch_data_alloc(LAUNCH_DATA_ARRAY); | |
233 | for (i = 0; i < spawn_attrs->spawn_binpref_cnt; i++) { | |
234 | tmp = launch_data_new_integer(spawn_attrs->spawn_binpref[i]); | |
235 | launch_data_array_set_index(tmp_array, tmp, i); | |
236 | } | |
237 | launch_data_dict_insert(in_obj, tmp_array, LAUNCH_JOBKEY_BINARYORDERPREFERENCE); | |
238 | } | |
239 | /* fall through */ | |
240 | case 0: | |
241 | if (spawn_attrs->spawn_flags & SPAWN_VIA_LAUNCHD_STOPPED) { | |
242 | tmp = launch_data_new_bool(true); | |
243 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_WAITFORDEBUGGER); | |
244 | } | |
245 | ||
246 | if (spawn_attrs->spawn_env) { | |
247 | launch_data_t tmp_dict = launch_data_alloc(LAUNCH_DATA_DICTIONARY); | |
248 | ||
249 | for (tmpp = spawn_attrs->spawn_env; *tmpp; tmpp++) { | |
250 | char *eqoff, tmpstr[strlen(*tmpp) + 1]; | |
251 | ||
252 | strcpy(tmpstr, *tmpp); | |
253 | ||
254 | eqoff = strchr(tmpstr, '='); | |
255 | ||
256 | if (!eqoff) { | |
257 | goto out; | |
258 | } | |
259 | ||
260 | *eqoff = '\0'; | |
261 | ||
262 | launch_data_dict_insert(tmp_dict, launch_data_new_string(eqoff + 1), tmpstr); | |
263 | } | |
264 | ||
265 | launch_data_dict_insert(in_obj, tmp_dict, LAUNCH_JOBKEY_ENVIRONMENTVARIABLES); | |
266 | } | |
267 | ||
268 | if (spawn_attrs->spawn_path) { | |
269 | tmp = launch_data_new_string(spawn_attrs->spawn_path); | |
270 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_PROGRAM); | |
271 | } | |
272 | ||
273 | if (spawn_attrs->spawn_chdir) { | |
274 | tmp = launch_data_new_string(spawn_attrs->spawn_chdir); | |
275 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_WORKINGDIRECTORY); | |
276 | } | |
277 | ||
278 | if (spawn_attrs->spawn_umask) { | |
279 | tmp = launch_data_new_integer(*spawn_attrs->spawn_umask); | |
280 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_UMASK); | |
281 | } | |
282 | ||
283 | break; | |
284 | default: | |
285 | break; | |
286 | } | |
287 | ||
288 | if (!(buf = malloc(good_enough_size))) { | |
289 | goto out; | |
290 | } | |
291 | ||
292 | if ((indata_cnt = launch_data_pack(in_obj, buf, good_enough_size, NULL, NULL)) == 0) { | |
293 | goto out; | |
294 | } | |
295 | ||
296 | indata = (vm_offset_t)buf; | |
297 | ||
298 | kr = vproc_mig_spawn(bootstrap_port, indata, indata_cnt, &p, &obsvr_port); | |
299 | ||
300 | if (kr == VPROC_ERR_TRY_PER_USER) { | |
301 | mach_port_t puc; | |
302 | ||
303 | if (vproc_mig_lookup_per_user_context(bootstrap_port, 0, &puc) == 0) { | |
304 | kr = vproc_mig_spawn(puc, indata, indata_cnt, &p, &obsvr_port); | |
305 | mach_port_deallocate(mach_task_self(), puc); | |
306 | } | |
307 | } | |
308 | ||
309 | out: | |
310 | if (in_obj) { | |
311 | launch_data_free(in_obj); | |
312 | } | |
313 | ||
314 | if (buf) { | |
315 | free(buf); | |
316 | } | |
317 | ||
318 | switch (kr) { | |
319 | case BOOTSTRAP_SUCCESS: | |
320 | if (spawn_attrs && spawn_attrs->spawn_observer_port) { | |
321 | *spawn_attrs->spawn_observer_port = obsvr_port; | |
322 | } else { | |
323 | mach_port_deallocate(mach_task_self(), obsvr_port); | |
324 | } | |
325 | return p; | |
326 | case BOOTSTRAP_NOT_PRIVILEGED: | |
327 | errno = EPERM; break; | |
328 | case BOOTSTRAP_NO_MEMORY: | |
329 | errno = ENOMEM; break; | |
330 | case BOOTSTRAP_NAME_IN_USE: | |
331 | errno = EEXIST; break; | |
332 | case 1: | |
333 | errno = EIO; break; | |
334 | default: | |
335 | errno = EINVAL; break; | |
336 | } | |
337 | ||
338 | return -1; | |
339 | } | |
340 | ||
341 | kern_return_t | |
342 | mpm_wait(mach_port_t ajob __attribute__((unused)), int *wstatus) | |
343 | { | |
344 | return vproc_mig_wait(ajob, wstatus); | |
345 | } | |
346 | ||
347 | kern_return_t | |
348 | mpm_uncork_fork(mach_port_t ajob) | |
349 | { | |
350 | return vproc_mig_uncork_fork(ajob); | |
351 | } | |
352 | ||
353 | kern_return_t | |
354 | _vprocmgr_getsocket(name_t sockpath) | |
355 | { | |
356 | return vproc_mig_getsocket(bootstrap_port, sockpath); | |
357 | } | |
358 | ||
359 | vproc_err_t | |
360 | _vproc_get_last_exit_status(int *wstatus) | |
361 | { | |
362 | int64_t val; | |
363 | ||
364 | if (vproc_swap_integer(NULL, VPROC_GSK_LAST_EXIT_STATUS, 0, &val) == 0) { | |
365 | *wstatus = (int)val; | |
366 | return NULL; | |
367 | } | |
368 | ||
369 | return (vproc_err_t)_vproc_get_last_exit_status; | |
370 | } | |
371 | ||
372 | vproc_err_t | |
373 | _vproc_send_signal_by_label(const char *label, int sig) | |
374 | { | |
375 | if (vproc_mig_send_signal(bootstrap_port, (char *)label, sig) == 0) { | |
376 | return NULL; | |
377 | } | |
378 | ||
379 | return _vproc_send_signal_by_label; | |
380 | } | |
381 | ||
382 | vproc_err_t | |
383 | _vprocmgr_log_forward(mach_port_t mp, void *data, size_t len) | |
384 | { | |
385 | if (vproc_mig_log_forward(mp, (vm_offset_t)data, len) == 0) { | |
386 | return NULL; | |
387 | } | |
388 | ||
389 | return _vprocmgr_log_forward; | |
390 | } | |
391 | ||
392 | vproc_err_t | |
393 | _vprocmgr_log_drain(vproc_t vp __attribute__((unused)), pthread_mutex_t *mutex, _vprocmgr_log_drain_callback_t func) | |
394 | { | |
395 | mach_msg_type_number_t outdata_cnt, tmp_cnt; | |
396 | vm_offset_t outdata = 0; | |
397 | struct logmsg_s *lm; | |
398 | ||
399 | if (!func) { | |
400 | return _vprocmgr_log_drain; | |
401 | } | |
402 | ||
403 | if (vproc_mig_log_drain(bootstrap_port, &outdata, &outdata_cnt) != 0) { | |
404 | return _vprocmgr_log_drain; | |
405 | } | |
406 | ||
407 | tmp_cnt = outdata_cnt; | |
408 | ||
409 | if (mutex) { | |
410 | pthread_mutex_lock(mutex); | |
411 | } | |
412 | ||
413 | for (lm = (struct logmsg_s *)outdata; tmp_cnt > 0; lm = ((void *)lm + lm->obj_sz)) { | |
414 | lm->from_name += (size_t)lm; | |
415 | lm->about_name += (size_t)lm; | |
416 | lm->msg += (size_t)lm; | |
417 | lm->session_name += (size_t)lm; | |
418 | ||
419 | func(&lm->when, lm->from_pid, lm->about_pid, lm->sender_uid, lm->sender_gid, lm->pri, | |
420 | lm->from_name, lm->about_name, lm->session_name, lm->msg); | |
421 | ||
422 | tmp_cnt -= lm->obj_sz; | |
423 | } | |
424 | ||
425 | if (mutex) { | |
426 | pthread_mutex_unlock(mutex); | |
427 | } | |
428 | ||
429 | if (outdata) { | |
430 | mig_deallocate(outdata, outdata_cnt); | |
431 | } | |
432 | ||
433 | return NULL; | |
434 | } | |
435 | ||
436 | vproc_err_t | |
437 | vproc_swap_integer(vproc_t vp __attribute__((unused)), vproc_gsk_t key, int64_t *inval, int64_t *outval) | |
438 | { | |
439 | static int64_t cached_is_managed = -1; | |
440 | int64_t dummyval = 0; | |
441 | ||
442 | switch (key) { | |
443 | case VPROC_GSK_MGR_PID: | |
444 | if (cached_pid != -1 && outval) { | |
445 | *outval = cached_pid; | |
446 | return NULL; | |
447 | } | |
448 | break; | |
449 | case VPROC_GSK_IS_MANAGED: | |
450 | if (cached_is_managed != -1 && outval) { | |
451 | *outval = cached_is_managed; | |
452 | return NULL; | |
453 | } | |
454 | break; | |
455 | default: | |
456 | break; | |
457 | } | |
458 | ||
459 | if (vproc_mig_swap_integer(bootstrap_port, inval ? key : 0, outval ? key : 0, inval ? *inval : 0, outval ? outval : &dummyval) == 0) { | |
460 | switch (key) { | |
461 | case VPROC_GSK_MGR_PID: | |
462 | cached_pid = outval ? *outval : dummyval; | |
463 | break; | |
464 | case VPROC_GSK_IS_MANAGED: | |
465 | cached_is_managed = outval ? *outval : dummyval; | |
466 | break; | |
467 | default: | |
468 | break; | |
469 | } | |
470 | return NULL; | |
471 | } | |
472 | ||
473 | return (vproc_err_t)vproc_swap_integer; | |
474 | } | |
475 | ||
476 | mach_port_t | |
477 | get_root_bootstrap_port(void) | |
478 | { | |
479 | mach_port_t parent_port = 0; | |
480 | mach_port_t previous_port = 0; | |
481 | ||
482 | do { | |
483 | if (previous_port) { | |
484 | if (previous_port != bootstrap_port) { | |
485 | mach_port_deallocate(mach_task_self(), previous_port); | |
486 | } | |
487 | previous_port = parent_port; | |
488 | } else { | |
489 | previous_port = bootstrap_port; | |
490 | } | |
491 | ||
492 | if (bootstrap_parent(previous_port, &parent_port) != 0) { | |
493 | return MACH_PORT_NULL; | |
494 | } | |
495 | ||
496 | } while (parent_port != previous_port); | |
497 | ||
498 | return parent_port; | |
499 | } | |
500 | ||
501 | vproc_err_t | |
502 | vproc_swap_complex(vproc_t vp __attribute__((unused)), vproc_gsk_t key, launch_data_t inval, launch_data_t *outval) | |
503 | { | |
504 | size_t data_offset = 0, good_enough_size = 10*1024*1024; | |
505 | mach_msg_type_number_t indata_cnt = 0, outdata_cnt; | |
506 | vm_offset_t indata = 0, outdata = 0; | |
507 | launch_data_t out_obj; | |
508 | void *rval = vproc_swap_complex; | |
509 | void *buf = NULL; | |
510 | ||
511 | if (inval) { | |
512 | if (!(buf = malloc(good_enough_size))) { | |
513 | goto out; | |
514 | } | |
515 | ||
516 | if ((indata_cnt = launch_data_pack(inval, buf, good_enough_size, NULL, NULL)) == 0) { | |
517 | goto out; | |
518 | } | |
519 | ||
520 | indata = (vm_offset_t)buf; | |
521 | } | |
522 | ||
523 | if (vproc_mig_swap_complex(bootstrap_port, inval ? key : 0, outval ? key : 0, indata, indata_cnt, &outdata, &outdata_cnt) != 0) { | |
524 | goto out; | |
525 | } | |
526 | ||
527 | if (outval) { | |
528 | if (!(out_obj = launch_data_unpack((void *)outdata, outdata_cnt, NULL, 0, &data_offset, NULL))) { | |
529 | goto out; | |
530 | } | |
531 | ||
532 | if (!(*outval = launch_data_copy(out_obj))) { | |
533 | goto out; | |
534 | } | |
535 | } | |
536 | ||
537 | rval = NULL; | |
538 | out: | |
539 | if (buf) { | |
540 | free(buf); | |
541 | } | |
542 | ||
543 | if (outdata) { | |
544 | mig_deallocate(outdata, outdata_cnt); | |
545 | } | |
546 | ||
547 | return rval; | |
548 | } | |
549 | ||
550 | void * | |
551 | reboot2(uint64_t flags) | |
552 | { | |
553 | if (vproc_mig_reboot2(get_root_bootstrap_port(), flags) == 0) { | |
554 | return NULL; | |
555 | } | |
556 | ||
557 | return reboot2; | |
558 | } | |
559 | ||
f36da725 A |
560 | vproc_err_t |
561 | _vproc_kickstart_by_label(const char *label, pid_t *out_pid, mach_port_t *out_port_name) | |
562 | { | |
563 | if (vproc_mig_embedded_kickstart(bootstrap_port, (char *)label, out_pid, out_port_name) == 0) { | |
564 | return NULL; | |
565 | } | |
566 | ||
567 | return (vproc_err_t)_vproc_kickstart_by_label; | |
568 | } | |
569 | ||
570 | vproc_err_t | |
571 | _vproc_wait_by_label(const char *label, int *out_wstatus) | |
572 | { | |
573 | if (vproc_mig_embedded_wait(bootstrap_port, (char *)label, out_wstatus) == 0) { | |
574 | return NULL; | |
575 | } | |
576 | ||
577 | return (vproc_err_t)_vproc_wait_by_label; | |
578 | } | |
579 | ||
5b0a4722 A |
580 | vproc_err_t |
581 | _vproc_set_global_on_demand(bool state) | |
582 | { | |
583 | int64_t val = state ? ~0 : 0; | |
584 | ||
585 | if (vproc_swap_integer(NULL, VPROC_GSK_GLOBAL_ON_DEMAND, &val, NULL) == 0) { | |
586 | return NULL; | |
587 | } | |
588 | ||
589 | return (vproc_err_t)_vproc_set_global_on_demand; | |
590 | } | |
591 | ||
592 | void | |
593 | _vproc_logv(int pri, int err, const char *msg, va_list ap) | |
594 | { | |
595 | char flat_msg[3000]; | |
596 | ||
597 | vsnprintf(flat_msg, sizeof(flat_msg), msg, ap); | |
598 | ||
599 | vproc_mig_log(bootstrap_port, pri, err, flat_msg); | |
600 | } | |
601 | ||
602 | void | |
603 | _vproc_log(int pri, const char *msg, ...) | |
604 | { | |
605 | va_list ap; | |
606 | ||
607 | va_start(ap, msg); | |
608 | _vproc_logv(pri, 0, msg, ap); | |
609 | va_end(ap); | |
610 | } | |
611 | ||
612 | void | |
613 | _vproc_log_error(int pri, const char *msg, ...) | |
614 | { | |
615 | int saved_errno = errno; | |
616 | va_list ap; | |
617 | ||
618 | va_start(ap, msg); | |
619 | _vproc_logv(pri, saved_errno, msg, ap); | |
620 | va_end(ap); | |
621 | } |