Revision: 23234 http://trac.macosforge.org/projects/launchd/changeset/23234 Author: zarzycki@apple.com Date: 2007-04-25 16:40:49 -0700 (Wed, 25 Apr 2007) Log Message: ----------- <rdar://problem/5063706> _vprocmgr_move_subset_to_user should set environment variables This is the beginning of the end for launch_msg() being implemented via Unix sockets (they're good for networking, but clumbsy for local IPC). Modified Paths: -------------- trunk/launchd/src/launchd_core_logic.c trunk/launchd/src/liblaunch.c trunk/launchd/src/libvproc.c trunk/launchd/src/libvproc_private.h trunk/launchd/src/protocol_job.defs Added Paths: ----------- trunk/launchd/src/liblaunch_internal.h trunk/launchd/testing/vproc_swap_complex.c Modified: trunk/launchd/src/launchd_core_logic.c =================================================================== --- trunk/launchd/src/launchd_core_logic.c 2007-04-24 19:48:38 UTC (rev 23233) +++ trunk/launchd/src/launchd_core_logic.c 2007-04-25 23:40:49 UTC (rev 23234) @@ -75,6 +75,7 @@ #include "liblaunch_public.h" #include "liblaunch_private.h" +#include "liblaunch_internal.h" #include "libbootstrap_public.h" #include "libbootstrap_private.h" #include "libvproc_public.h" @@ -262,6 +263,7 @@ static void job_export_all2(jobmgr_t jm, launch_data_t where); static void jobmgr_callback(void *obj, struct kevent *kev); static void jobmgr_setup_env_from_other_jobs(jobmgr_t jm); +static void jobmgr_export_env_from_other_jobs(jobmgr_t jm, launch_data_t dict); static struct machservice *jobmgr_lookup_service(jobmgr_t jm, const char *name, bool check_parent, pid_t target_pid); static void jobmgr_logv(jobmgr_t jm, int pri, int err, const char *msg, va_list ap) __attribute__((format(printf, 4, 0))); static void jobmgr_log(jobmgr_t jm, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4))); @@ -2326,12 +2328,43 @@ _exit(EXIT_FAILURE); } -void jobmgr_setup_env_from_other_jobs(jobmgr_t jm) +void +jobmgr_export_env_from_other_jobs(jobmgr_t jm, launch_data_t dict) { + launch_data_t tmp; struct envitem *ei; job_t ji; if (jm->parentmgr) { + jobmgr_export_env_from_other_jobs(jm->parentmgr, dict); + } else { + char **tmpenviron = environ; + for (; *tmpenviron; tmpenviron++) { + char envkey[1024]; + launch_data_t s = launch_data_alloc(LAUNCH_DATA_STRING); + launch_data_set_string(s, strchr(*tmpenviron, '=') + 1); + strncpy(envkey, *tmpenviron, sizeof(envkey)); + *(strchr(envkey, '=')) = '\0'; + launch_data_dict_insert(dict, s, envkey); + } + } + + LIST_FOREACH(ji, &jm->jobs, sle) { + SLIST_FOREACH(ei, &ji->global_env, sle) { + if ((tmp = launch_data_new_string(ei->value))) { + launch_data_dict_insert(dict, tmp, ei->key); + } + } + } +} + +void +jobmgr_setup_env_from_other_jobs(jobmgr_t jm) +{ + struct envitem *ei; + job_t ji; + + if (jm->parentmgr) { jobmgr_setup_env_from_other_jobs(jm->parentmgr); } @@ -4500,6 +4533,76 @@ } kern_return_t +job_mig_swap_complex(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey, + vm_offset_t inval, mach_msg_type_number_t invalCnt, + vm_offset_t *outval, mach_msg_type_number_t *outvalCnt) +{ + const char *action; + launch_data_t input_obj, output_obj; + size_t data_offset = 0; + + *outvalCnt = 10 * 1024 * 1024; + + if (!launchd_assumes(j != NULL)) { + return BOOTSTRAP_NO_MEMORY; + } + + if (inkey && outkey && !job_assumes(j, inkey == outkey)) { + return 1; + } + + if (inkey && outkey) { + action = "Swapping"; + } else if (inkey) { + action = "Setting"; + } else { + action = "Getting"; + } + + job_log(j, LOG_DEBUG, "%s key: %u", action, inkey ? inkey : outkey); + + if (invalCnt && !job_assumes(j, (input_obj = launch_data_unpack((void *)inval, invalCnt, NULL, 0, &data_offset, NULL)) != NULL)) { + return 1; + } + + switch (outkey) { + case VPROC_GSK_ENVIRONMENT: + mig_allocate(outval, *outvalCnt); + if (!job_assumes(j, *outval != 0)) { + return 1; + } + if (job_assumes(j, (output_obj = launch_data_alloc(LAUNCH_DATA_DICTIONARY)))) { + jobmgr_export_env_from_other_jobs(j->mgr, output_obj); + } + if (!job_assumes(j, launch_data_pack(output_obj, (void *)*outval, *outvalCnt, NULL, NULL) != 0)) { + mig_deallocate(*outval, *outvalCnt); + return 1; + } + break; + case 0: + *outval = 0; + *outvalCnt = 0; + break; + default: + return 1; + } + + if (invalCnt) switch (inkey) { + case VPROC_GSK_ENVIRONMENT: + job_assumes(j, false); + break; + case 0: + break; + default: + return 1; + } + + mig_deallocate(inval, invalCnt); + + return 0; +} + +kern_return_t job_mig_swap_integer(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey, int64_t inval, int64_t *outval) { const char *action; @@ -4584,10 +4687,6 @@ break; case 0: break; - case VPROC_GSK_IS_MANAGED: - case VPROC_GSK_LAST_EXIT_STATUS: - case VPROC_GSK_MGR_UID: - case VPROC_GSK_MGR_PID: default: kr = 1; break; Modified: trunk/launchd/src/liblaunch.c =================================================================== --- trunk/launchd/src/liblaunch.c 2007-04-24 19:48:38 UTC (rev 23233) +++ trunk/launchd/src/liblaunch.c 2007-04-25 23:40:49 UTC (rev 23234) @@ -21,6 +21,7 @@ #include "config.h" #include "liblaunch_public.h" #include "liblaunch_private.h" +#include "liblaunch_internal.h" #include <mach/mach.h> #include <libkern/OSByteOrder.h> @@ -139,8 +140,6 @@ int fd; }; -static size_t launch_data_pack(launch_data_t d, void *where, size_t len, int *fd_where, size_t *fdslotsleft); -static launch_data_t launch_data_unpack(void *data, size_t data_size, int *fds, size_t fd_cnt, size_t *data_offset, size_t *fdoffset); static launch_data_t launch_data_array_pop_first(launch_data_t where); static int _fd(int fd); static void launch_client_init(void); Added: trunk/launchd/src/liblaunch_internal.h =================================================================== --- trunk/launchd/src/liblaunch_internal.h (rev 0) +++ trunk/launchd/src/liblaunch_internal.h 2007-04-25 23:40:49 UTC (rev 23234) @@ -0,0 +1,30 @@ +#ifndef _LAUNCH_INTERNAL_H_ +#define _LAUNCH_INTERNAL_H_ +/* + * Copyright (c) 2007 Apple Computer, Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +#pragma GCC visibility push(default) + +size_t launch_data_pack(launch_data_t d, void *where, size_t len, int *fd_where, size_t *fdslotsleft); +launch_data_t launch_data_unpack(void *data, size_t data_size, int *fds, size_t fd_cnt, size_t *data_offset, size_t *fdoffset); + +#pragma GCC visibility pop + +#endif Modified: trunk/launchd/src/libvproc.c =================================================================== --- trunk/launchd/src/libvproc.c 2007-04-24 19:48:38 UTC (rev 23233) +++ trunk/launchd/src/libvproc.c 2007-04-25 23:40:49 UTC (rev 23234) @@ -33,6 +33,7 @@ #include "liblaunch_public.h" #include "liblaunch_private.h" +#include "liblaunch_internal.h" #include "protocol_vproc.h" @@ -57,9 +58,16 @@ return vproc_mig_post_fork_ping(bootstrap_port, mach_task_self()) == 0 ? NULL : _vproc_post_fork_ping; } +static void +setup_env_hack(const launch_data_t obj, const char *key, void *context __attribute__((unused))) +{ + setenv(key, launch_data_get_string(obj), 1); +} + vproc_err_t _vprocmgr_move_subset_to_user(uid_t target_user, char *session_type) { + launch_data_t output_obj; kern_return_t kr = 1; mach_port_t puc = 0, which_port = bootstrap_port; bool is_bkgd = (strcmp(session_type, VPROCMGR_SESSION_BACKGROUND) == 0); @@ -84,7 +92,18 @@ cached_pid = -1; - return kr == 0 ? NULL : (vproc_err_t)_vprocmgr_move_subset_to_user; + if (kr) { + return (vproc_err_t)_vprocmgr_move_subset_to_user; + } + + if (vproc_swap_complex(NULL, VPROC_GSK_ENVIRONMENT, NULL, &output_obj) == NULL) { + if (launch_data_get_type(output_obj) == LAUNCH_DATA_DICTIONARY) { + launch_data_dict_iterate(output_obj, setup_env_hack, NULL); + launch_data_free(output_obj); + } + } + + return NULL; } @@ -304,6 +323,55 @@ return parent_port; } +vproc_err_t +vproc_swap_complex(vproc_t vp __attribute__((unused)), vproc_gsk_t key, launch_data_t inval, launch_data_t *outval) +{ + size_t data_offset = 0, good_enough_size = 10*1024*1024; + mach_msg_type_number_t indata_cnt = 0, outdata_cnt; + vm_offset_t indata = 0, outdata = 0; + launch_data_t out_obj; + void *rval = vproc_swap_complex; + void *buf = NULL; + + if (inval) { + if (!(buf = malloc(good_enough_size))) { + goto out; + } + + if ((indata_cnt = launch_data_pack(inval, buf, good_enough_size, NULL, NULL)) == 0) { + goto out; + } + + indata = (vm_offset_t)buf; + } + + if (vproc_mig_swap_complex(bootstrap_port, inval ? key : 0, outval ? key : 0, indata, indata_cnt, &outdata, &outdata_cnt) != 0) { + goto out; + } + + if (outval) { + if (!(out_obj = launch_data_unpack((void *)outdata, outdata_cnt, NULL, 0, &data_offset, NULL))) { + goto out; + } + + if (!(*outval = launch_data_copy(out_obj))) { + goto out; + } + } + + rval = NULL; +out: + if (buf) { + free(buf); + } + + if (outdata) { + mig_deallocate(outdata, outdata_cnt); + } + + return rval; +} + void * reboot2(uint64_t flags) { Modified: trunk/launchd/src/libvproc_private.h =================================================================== --- trunk/launchd/src/libvproc_private.h 2007-04-24 19:48:38 UTC (rev 23233) +++ trunk/launchd/src/libvproc_private.h 2007-04-25 23:40:49 UTC (rev 23234) @@ -24,6 +24,7 @@ #include <sys/cdefs.h> #include <sys/syslog.h> #include <stdbool.h> +#include <launch.h> __BEGIN_DECLS @@ -39,9 +40,11 @@ VPROC_GSK_START_INTERVAL, VPROC_GSK_IDLE_TIMEOUT, VPROC_GSK_EXIT_TIMEOUT, + VPROC_GSK_ENVIRONMENT, } vproc_gsk_t; vproc_err_t vproc_swap_integer(vproc_t vp, vproc_gsk_t key, int64_t *inval, int64_t *outval); +vproc_err_t vproc_swap_complex(vproc_t vp, vproc_gsk_t key, launch_data_t inval, launch_data_t *outval); vproc_err_t _vproc_get_last_exit_status(int *wstatus); vproc_err_t _vproc_set_global_on_demand(bool val); Modified: trunk/launchd/src/protocol_job.defs =================================================================== --- trunk/launchd/src/protocol_job.defs 2007-04-24 19:48:38 UTC (rev 23233) +++ trunk/launchd/src/protocol_job.defs 2007-04-25 23:40:49 UTC (rev 23234) @@ -156,3 +156,10 @@ __bs_port : job_t; __target_port : mach_port_t; __sessiontype : name_t); + +routine swap_complex( + __bs_port : job_t; + __inkey : vproc_gsk_t; + __outkey : vproc_gsk_t; + __inval : pointer_t; + out __outval : pointer_t, dealloc); Added: trunk/launchd/testing/vproc_swap_complex.c =================================================================== --- trunk/launchd/testing/vproc_swap_complex.c (rev 0) +++ trunk/launchd/testing/vproc_swap_complex.c 2007-04-25 23:40:49 UTC (rev 23234) @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <unistd.h> +#include <assert.h> +#include <vproc.h> +#include <vproc_priv.h> + +static void my_callback(const launch_data_t obj, const char *key, void *context); + +int main(void) +{ + launch_data_t output_obj = NULL; + + assert(vproc_swap_complex(NULL, VPROC_GSK_ENVIRONMENT, NULL, &output_obj) == 0); + + assert(launch_data_get_type(output_obj) == LAUNCH_DATA_DICTIONARY); + + launch_data_dict_iterate(output_obj, my_callback, stdout); + + return 0; +} + +void +my_callback(const launch_data_t obj, const char *key, void *context) +{ + fprintf(context, "%s == %s\n", key, launch_data_get_string(obj)); +}
participants (1)
-
source_changes@macosforge.org