From 6a39f10ba7d971808de0505562b857d62cdd5818 Mon Sep 17 00:00:00 2001 From: Apple Date: Tue, 2 May 2006 18:01:55 +0000 Subject: [PATCH] launchd-106.14.tar.gz --- launchd/src/bootstrap.c | 13 +++ launchd/src/launch_priv.h | 2 + launchd/src/launchctl.c | 198 ++++++++++++++++++-------------------- launchd/src/launchd.c | 64 ++++++++++-- 4 files changed, 165 insertions(+), 112 deletions(-) diff --git a/launchd/src/bootstrap.c b/launchd/src/bootstrap.c index 82ef86a..0dac261 100644 --- a/launchd/src/bootstrap.c +++ b/launchd/src/bootstrap.c @@ -1045,3 +1045,16 @@ canSend(mach_port_t port) } return ((p_type & MACH_PORT_TYPE_PORT_RIGHTS) != 0); } + +/* Sigh... Libc's panic() call fails to abort and continues afterwards */ +void +panic(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + vfprintf(stderr, msg, ap); + va_end(ap); + + _exit(EXIT_FAILURE); +} diff --git a/launchd/src/launch_priv.h b/launchd/src/launch_priv.h index c5d297e..fddafd6 100644 --- a/launchd/src/launch_priv.h +++ b/launchd/src/launch_priv.h @@ -39,6 +39,8 @@ #define LAUNCH_KEY_GETRUSAGESELF "GetResourceUsageSelf" #define LAUNCH_KEY_GETRUSAGECHILDREN "GetResourceUsageChildren" +#define LAUNCH_KEY_WORKAROUNDBONJOUR "WorkaroundBonjour" + #define LAUNCHD_SOCKET_ENV "LAUNCHD_SOCKET" #define LAUNCHD_SOCK_PREFIX "/var/launchd" #define LAUNCHD_TRUSTED_FD_ENV "__LAUNCHD_FD" diff --git a/launchd/src/launchctl.c b/launchd/src/launchctl.c index a0a405c..fbdbfb3 100644 --- a/launchd/src/launchctl.c +++ b/launchd/src/launchctl.c @@ -68,19 +68,18 @@ static launch_data_t CF2launch_data(CFTypeRef); static launch_data_t read_plist_file(const char *file, bool editondisk, bool load); static CFPropertyListRef CreateMyPropertyListFromFile(const char *); static void WriteMyPropertyListToFile(CFPropertyListRef, const char *); -static void readpath(const char *, launch_data_t, launch_data_t, launch_data_t, bool editondisk, bool load, bool forceload); -static void readfile(const char *, launch_data_t, launch_data_t, launch_data_t, bool editondisk, bool load, bool forceload); +static void readpath(const char *, launch_data_t, launch_data_t, bool editondisk, bool load, bool forceload); +static void readfile(const char *, launch_data_t, launch_data_t, bool editondisk, bool load, bool forceload); static int _fd(int); static int demux_cmd(int argc, char *const argv[]); -static launch_data_t do_rendezvous_magic(const struct addrinfo *res, const char *serv); +static void do_rendezvous_magic(const struct addrinfo *res, const char *serv, const char *label); +static void workaround_bonjour_asynchronously(void); static void submit_job_pass(launch_data_t jobs); static void submit_mach_jobs(launch_data_t jobs); static void let_go_of_mach_jobs(void); static void do_mgroup_join(int fd, int family, int socktype, int protocol, const char *mgroup); static void print_jobs(launch_data_t j, const char *label, void *context); static bool is_legacy_mach_job(launch_data_t obj); -static bool delay_to_second_pass(launch_data_t o); -static void delay_to_second_pass2(launch_data_t o, const char *key, void *context); static int load_and_unload_cmd(int argc, char *const argv[]); //static int reload_cmd(int argc, char *const argv[]); @@ -341,46 +340,7 @@ read_plist_file(const char *file, bool editondisk, bool load) } void -delay_to_second_pass2(launch_data_t o, const char *key, void *context) -{ - bool *res = context; - size_t i; - - if (key && 0 == strcmp(key, LAUNCH_JOBSOCKETKEY_BONJOUR)) { - *res = true; - return; - } - - switch (launch_data_get_type(o)) { - case LAUNCH_DATA_DICTIONARY: - launch_data_dict_iterate(o, delay_to_second_pass2, context); - break; - case LAUNCH_DATA_ARRAY: - for (i = 0; i < launch_data_array_get_count(o); i++) - delay_to_second_pass2(launch_data_array_get_index(o, i), NULL, context); - break; - default: - break; - } -} - -bool -delay_to_second_pass(launch_data_t o) -{ - bool res = false; - - launch_data_t socks = launch_data_dict_lookup(o, LAUNCH_JOBKEY_SOCKETS); - - if (NULL == socks) - return false; - - delay_to_second_pass2(socks, NULL, &res); - - return res; -} - -void -readfile(const char *what, launch_data_t pass0, launch_data_t pass1, launch_data_t pass2, bool editondisk, bool load, bool forceload) +readfile(const char *what, launch_data_t pass0, launch_data_t pass1, bool editondisk, bool load, bool forceload) { launch_data_t tmpd, thejob; bool job_disabled = false; @@ -412,14 +372,11 @@ readfile(const char *what, launch_data_t pass0, launch_data_t pass1, launch_data return; } - if (delay_to_second_pass(thejob)) - launch_data_array_append(pass2, thejob); - else - launch_data_array_append(pass1, thejob); + launch_data_array_append(pass1, thejob); } void -readpath(const char *what, launch_data_t pass0, launch_data_t pass1, launch_data_t pass2, bool editondisk, bool load, bool forceload) +readpath(const char *what, launch_data_t pass0, launch_data_t pass1, bool editondisk, bool load, bool forceload) { char buf[MAXPATHLEN]; struct stat sb; @@ -430,7 +387,7 @@ readpath(const char *what, launch_data_t pass0, launch_data_t pass1, launch_data return; if (S_ISREG(sb.st_mode) && !(sb.st_mode & S_IWOTH)) { - readfile(what, pass0, pass1, pass2, editondisk, load, forceload); + readfile(what, pass0, pass1, editondisk, load, forceload); } else { if ((d = opendir(what)) == NULL) { fprintf(stderr, "%s: opendir() failed to open the directory\n", getprogname()); @@ -442,7 +399,7 @@ readpath(const char *what, launch_data_t pass0, launch_data_t pass1, launch_data continue; snprintf(buf, sizeof(buf), "%s/%s", what, de->d_name); - readfile(buf, pass0, pass1, pass2, editondisk, load, forceload); + readfile(buf, pass0, pass1, editondisk, load, forceload); } closedir(d); } @@ -498,9 +455,13 @@ static void sock_dict_cb(launch_data_t what, const char *key, void *context) static void sock_dict_edit_entry(launch_data_t tmp, const char *key, launch_data_t fdarray, launch_data_t thejob) { launch_data_t a, val; + const char *joblabel; int sfd, st = SOCK_STREAM; bool passive = true; + assert((val = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LABEL)) != NULL); + joblabel = launch_data_get_string(val); + if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_TYPE))) { if (!strcasecmp(launch_data_get_string(val), "stream")) { st = SOCK_STREAM; @@ -630,7 +591,6 @@ static void sock_dict_edit_entry(launch_data_t tmp, const char *key, launch_data } for (res = res0; res; res = res->ai_next) { - launch_data_t rvs_fd = NULL; if ((sfd = _fd(socket(res->ai_family, res->ai_socktype, res->ai_protocol))) == -1) { fprintf(stderr, "socket(): %s\n", strerror(errno)); return; @@ -667,30 +627,22 @@ static void sock_dict_edit_entry(launch_data_t tmp, const char *key, launch_data } if (rendezvous && (res->ai_family == AF_INET || res->ai_family == AF_INET6) && (res->ai_socktype == SOCK_STREAM || res->ai_socktype == SOCK_DGRAM)) { - launch_data_t rvs_fds = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_BONJOURFDS); - if (NULL == rvs_fds) { - rvs_fds = launch_data_alloc(LAUNCH_DATA_ARRAY); - launch_data_dict_insert(thejob, rvs_fds, LAUNCH_JOBKEY_BONJOURFDS); - } if (NULL == rnames) { - rvs_fd = do_rendezvous_magic(res, serv); - if (rvs_fd) - launch_data_array_append(rvs_fds, rvs_fd); + do_rendezvous_magic(res, serv, joblabel); } else if (LAUNCH_DATA_STRING == launch_data_get_type(rnames)) { - rvs_fd = do_rendezvous_magic(res, launch_data_get_string(rnames)); - if (rvs_fd) - launch_data_array_append(rvs_fds, rvs_fd); + do_rendezvous_magic(res, launch_data_get_string(rnames), joblabel); } else if (LAUNCH_DATA_ARRAY == launch_data_get_type(rnames)) { size_t rn_i, rn_ac = launch_data_array_get_count(rnames); for (rn_i = 0; rn_i < rn_ac; rn_i++) { launch_data_t rn_tmp = launch_data_array_get_index(rnames, rn_i); - rvs_fd = do_rendezvous_magic(res, launch_data_get_string(rn_tmp)); - if (rvs_fd) - launch_data_array_append(rvs_fds, rvs_fd); + do_rendezvous_magic(res, launch_data_get_string(rn_tmp), joblabel); } } + /* Launchd should not register the same service more than once */ + /* Switch to DNSServiceRegisterAddrInfo() */ + rendezvous = false; } } else { if (connect(sfd, res->ai_addr, res->ai_addrlen) == -1) { @@ -699,11 +651,6 @@ static void sock_dict_edit_entry(launch_data_t tmp, const char *key, launch_data } } val = launch_data_new_fd(sfd); - if (rvs_fd) { - /* Launchd should not register the same service more than once */ - /* Switch to DNSServiceRegisterAddrInfo() */ - rendezvous = false; - } launch_data_array_append(fdarray, val); } } @@ -754,36 +701,87 @@ static void do_mgroup_join(int fd, int family, int socktype, int protocol, const freeaddrinfo(res0); } +struct bonjour_magic { + SLIST_ENTRY(bonjour_magic) sle; + char *str; + int port; + char label[0]; +}; + +static SLIST_HEAD(, bonjour_magic) bm_later = { NULL }; -static launch_data_t do_rendezvous_magic(const struct addrinfo *res, const char *serv) +void +do_rendezvous_magic(const struct addrinfo *res, const char *serv, const char *joblabel) { - struct stat sb; - DNSServiceRef service; + struct bonjour_magic *bm = calloc(1, sizeof(struct bonjour_magic) + strlen(joblabel) + 1); + const char *typestr = "udp"; + + if (res->ai_socktype == SOCK_STREAM) + typestr = "tcp"; + + strcpy(bm->label, joblabel); + + asprintf(&bm->str, "_%s._%s.", serv, typestr); + + if (res->ai_family == AF_INET) { + bm->port = ((struct sockaddr_in *)res->ai_addr)->sin_port; + } else { + bm->port = ((struct sockaddr_in6 *)res->ai_addr)->sin6_port; + } + + SLIST_INSERT_HEAD(&bm_later, bm, sle); +} + + +void +workaround_bonjour_asynchronously(void) +{ + launch_data_t resp, msg, msgpayload, tmpa; + struct bonjour_magic *bm; DNSServiceErrorType error; - char rvs_buf[200]; - short port; - static int statres = 1; + DNSServiceRef service; + int fd; + + if (fork() != 0) + return; + + signal(SIGHUP, SIG_IGN); + setsid(); + sleep(30); - if (1 == statres) - statres = stat("/usr/sbin/mDNSResponder", &sb); + msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + msgpayload = launch_data_alloc(LAUNCH_DATA_DICTIONARY); - if (-1 == statres) - return NULL; + SLIST_FOREACH(bm, &bm_later, sle) { + service = NULL; + error = DNSServiceRegister(&service, 0, 0, NULL, bm->str, NULL, NULL, bm->port, 0, NULL, NULL, NULL); + if (error != kDNSServiceErr_NoError) { + fprintf(stderr, "DNSServiceRegister(\"%s\"): %d\n", bm->str, error); + continue; + } + fd = DNSServiceRefSockFD(service); + tmpa = launch_data_dict_lookup(msgpayload, bm->label); + if (!tmpa) { + tmpa = launch_data_alloc(LAUNCH_DATA_ARRAY); + launch_data_dict_insert(msgpayload, tmpa, bm->label); + } + launch_data_array_append(tmpa, launch_data_new_fd(fd)); + } - sprintf(rvs_buf, "_%s._%s.", serv, res->ai_socktype == SOCK_STREAM ? "tcp" : "udp"); + launch_data_dict_insert(msg, msgpayload, LAUNCH_KEY_WORKAROUNDBONJOUR); - if (res->ai_family == AF_INET) - port = ((struct sockaddr_in *)res->ai_addr)->sin_port; - else - port = ((struct sockaddr_in6 *)res->ai_addr)->sin6_port; + resp = launch_msg(msg); - error = DNSServiceRegister(&service, 0, 0, NULL, rvs_buf, NULL, NULL, port, 0, NULL, NULL, NULL); + launch_data_free(msg); - if (error == kDNSServiceErr_NoError) - return launch_data_new_fd(DNSServiceRefSockFD(service)); + if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) { + errno = launch_data_get_errno(resp); + fprintf(stderr, "Workaround Bonjour: %s\n", strerror(errno)); + } - fprintf(stderr, "DNSServiceRegister(\"%s\"): %d\n", serv, error); - return NULL; + launch_data_free(resp); + + _exit(EXIT_SUCCESS); } static CFPropertyListRef CreateMyPropertyListFromFile(const char *posixfile) @@ -928,7 +926,7 @@ static int _fd(int fd) static int load_and_unload_cmd(int argc, char *const argv[]) { - launch_data_t pass0, pass1, pass2; + launch_data_t pass0, pass1; int i, ch; bool wflag = false; bool lflag = false; @@ -954,7 +952,7 @@ static int load_and_unload_cmd(int argc, char *const argv[]) return 1; } - /* I wish I didn't need to do three passes, but I need to load mDNSResponder and use it too. + /* I wish I didn't need to do multiple passes, but I need to load mDNSResponder and use it too. * And loading legacy mach init jobs is extra fun. * * In later versions of launchd, I hope to load everything in the first pass, @@ -965,33 +963,27 @@ static int load_and_unload_cmd(int argc, char *const argv[]) pass0 = launch_data_alloc(LAUNCH_DATA_ARRAY); pass1 = launch_data_alloc(LAUNCH_DATA_ARRAY); - pass2 = launch_data_alloc(LAUNCH_DATA_ARRAY); for (i = 0; i < argc; i++) - readpath(argv[i], pass0, pass1, pass2, wflag, lflag, Fflag); + readpath(argv[i], pass0, pass1, wflag, lflag, Fflag); if (launch_data_array_get_count(pass0) == 0 && - launch_data_array_get_count(pass1) == 0 && - launch_data_array_get_count(pass2) == 0) { + launch_data_array_get_count(pass1) == 0) { fprintf(stderr, "nothing found to %s\n", lflag ? "load" : "unload"); launch_data_free(pass0); launch_data_free(pass1); - launch_data_free(pass2); return 1; } if (lflag) { distill_jobs(pass1); submit_mach_jobs(pass0); + workaround_bonjour_asynchronously(); submit_job_pass(pass1); let_go_of_mach_jobs(); - distill_jobs(pass2); - submit_job_pass(pass2); } else { for (i = 0; i < (int)launch_data_array_get_count(pass1); i++) unloadjob(launch_data_array_get_index(pass1, i)); - for (i = 0; i < (int)launch_data_array_get_count(pass2); i++) - unloadjob(launch_data_array_get_index(pass2, i)); } return 0; diff --git a/launchd/src/launchd.c b/launchd/src/launchd.c index bc3d348..5e14f60 100644 --- a/launchd/src/launchd.c +++ b/launchd/src/launchd.c @@ -143,6 +143,7 @@ static void job_set_alarm(struct jobcb *j); static void job_callback(void *obj, struct kevent *kev); static void job_log(struct jobcb *j, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4))); static void job_log_error(struct jobcb *j, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4))); +static void job_prep_log_msg(struct jobcb *j, char *buf, const char *msg, int err); static void ipc_open(int fd, struct jobcb *j); static void ipc_close(struct conncb *c); @@ -323,7 +324,7 @@ int main(int argc, char *argv[]) static void pid1_magic_init(bool sflag, bool vflag, bool xflag) { pthread_attr_t attr; - int memmib[2] = { CTL_HW, HW_PHYSMEM }; + int memmib[2] = { CTL_HW, HW_MEMSIZE }; int mvnmib[2] = { CTL_KERN, KERN_MAXVNODES }; int hnmib[2] = { CTL_KERN, KERN_HOSTNAME }; #ifdef KERN_TFP @@ -913,6 +914,22 @@ static void ipc_readmsg(launch_data_t msg, void *context) launch_data_free(rmc.resp); } +static void +attach_bonjourfds_to_job(launch_data_t o, const char *key, void *context __attribute__((unused))) +{ + struct jobcb *j = NULL; + + TAILQ_FOREACH(j, &jobs, tqe) { + if (strcmp(j->label, key) == 0) + break; + } + + if (j == NULL) + return; + + launch_data_dict_insert(j->ldj, launch_data_copy(o), LAUNCH_JOBKEY_BONJOURFDS); + launch_data_revoke_fds(o); +} static void ipc_readmsg2(launch_data_t data, const char *cmd, void *context) { @@ -963,6 +980,9 @@ static void ipc_readmsg2(launch_data_t data, const char *cmd, void *context) } else { resp = load_job(data); } + } else if (!strcmp(cmd, LAUNCH_KEY_WORKAROUNDBONJOUR)) { + launch_data_dict_iterate(data, attach_bonjourfds_to_job, NULL); + resp = launch_data_new_errno(0); } else if (!strcmp(cmd, LAUNCH_KEY_UNSETUSERENVIRONMENT)) { unsetenv(launch_data_get_string(data)); resp = launch_data_new_errno(0); @@ -2311,13 +2331,39 @@ static void job_set_alarm(struct jobcb *j) } } -static void job_log_error(struct jobcb *j, int pri, const char *msg, ...) +void +job_prep_log_msg(struct jobcb *j, char *buf, const char *msg, int err) +{ + size_t lsz = strlen(j->label); + size_t i, o; + + for (i = 0, o = 0; i < lsz; i++, o++) { + if (j->label[i] == '%') { + buf[o] = '%'; + o++; + buf[o] = '%'; + } else { + buf[o] = j->label[i]; + } + } + + buf[o++] = ':'; + buf[o++] = ' '; + + if (err) { + sprintf(buf + o, "%s: %s", msg, strerror(err)); + } else { + strcpy(buf + o, msg); + } +} + +void +job_log_error(struct jobcb *j, int pri, const char *msg, ...) { - size_t newmsg_sz = strlen(msg) + strlen(j->label) + 200; - char *newmsg = alloca(newmsg_sz); + char newmsg[10000]; va_list ap; - sprintf(newmsg, "%s: %s: %s", j->label, msg, strerror(errno)); + job_prep_log_msg(j, newmsg, msg, errno); va_start(ap, msg); @@ -2326,13 +2372,13 @@ static void job_log_error(struct jobcb *j, int pri, const char *msg, ...) va_end(ap); } -static void job_log(struct jobcb *j, int pri, const char *msg, ...) +void +job_log(struct jobcb *j, int pri, const char *msg, ...) { - size_t newmsg_sz = strlen(msg) + sizeof(": ") + strlen(j->label); - char *newmsg = alloca(newmsg_sz); + char newmsg[10000]; va_list ap; - sprintf(newmsg, "%s: %s", j->label, msg); + job_prep_log_msg(j, newmsg, msg, 0); va_start(ap, msg); -- 2.45.2