X-Git-Url: https://git.saurik.com/apple/launchd.git/blobdiff_plain/ab36757d38bc3680d699f3d9d5c21650195fc635..6a39f10ba7d971808de0505562b857d62cdd5818:/launchd/src/launchctl.c diff --git a/launchd/src/launchctl.c b/launchd/src/launchctl.c index 5142250..fbdbfb3 100644 --- a/launchd/src/launchctl.c +++ b/launchd/src/launchctl.c @@ -21,6 +21,8 @@ * @APPLE_LICENSE_HEADER_END@ */ #include +#include +#include #include #include #include @@ -50,7 +52,15 @@ #define LAUNCH_SECDIR "/tmp/launch-XXXXXX" +#define MACHINIT_JOBKEY_ONDEMAND "OnDemand" +#define MACHINIT_JOBKEY_SERVICENAME "ServiceName" +#define MACHINIT_JOBKEY_COMMAND "Command" +#define MACHINIT_JOBKEY_ISKUNCSERVER "isKUNCServer" + + +static void myCFDictionaryApplyFunction(const void *key, const void *value, void *context); static bool launch_data_array_append(launch_data_t a, launch_data_t o); +static void distill_jobs(launch_data_t); static void distill_config_file(launch_data_t); 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); @@ -59,11 +69,17 @@ static launch_data_t read_plist_file(const char *file, bool editondisk, bool loa static CFPropertyListRef CreateMyPropertyListFromFile(const char *); static void WriteMyPropertyListToFile(CFPropertyListRef, const char *); 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 int load_and_unload_cmd(int argc, char *const argv[]); //static int reload_cmd(int argc, char *const argv[]); @@ -216,21 +232,29 @@ static int setenv_cmd(int argc, char *const argv[]) return 0; } +static void print_launchd_env(launch_data_t obj, const char *key, void *context) +{ + bool *is_csh = context; + + if (*is_csh) + fprintf(stdout, "setenv %s %s;\n", key, launch_data_get_string(obj)); + else + fprintf(stdout, "%s=%s; export %s;\n", key, launch_data_get_string(obj), key); +} + +static void print_key_value(launch_data_t obj, const char *key, void *context) +{ + const char *k = context; + + if (!strcmp(key, k)) + fprintf(stdout, "%s\n", launch_data_get_string(obj)); +} + static int getenv_and_export_cmd(int argc, char *const argv[] __attribute__((unused))) { launch_data_t resp, msg; bool is_csh = false; - const char *k; - void print_launchd_env(launch_data_t obj, const char *key, void *context __attribute__((unused))) { - if (is_csh) - fprintf(stdout, "setenv %s %s;\n", key, launch_data_get_string(obj)); - else - fprintf(stdout, "%s=%s; export %s;\n", key, launch_data_get_string(obj), key); - } - void print_key_value(launch_data_t obj, const char *key, void *context __attribute__((unused))) { - if (!strcmp(key, k)) - fprintf(stdout, "%s\n", launch_data_get_string(obj)); - } + char *k; if (!strcmp(argv[0], "export")) { char *s = getenv("SHELL"); @@ -249,7 +273,10 @@ static int getenv_and_export_cmd(int argc, char *const argv[] __attribute__((unu launch_data_free(msg); if (resp) { - launch_data_dict_iterate(resp, (!strcmp(argv[0], "export")) ? print_launchd_env : print_key_value, NULL); + if (!strcmp(argv[0], "export")) + launch_data_dict_iterate(resp, print_launchd_env, &is_csh); + else + launch_data_dict_iterate(resp, print_key_value, k); launch_data_free(resp); } else { fprintf(stderr, "launch_msg(\"" LAUNCH_KEY_GETUSERENVIRONMENT "\"): %s\n", strerror(errno)); @@ -286,7 +313,8 @@ static void unloadjob(launch_data_t job) launch_data_free(resp); } -static launch_data_t read_plist_file(const char *file, bool editondisk, bool load) +launch_data_t +read_plist_file(const char *file, bool editondisk, bool load) { CFPropertyListRef plist = CreateMyPropertyListFromFile(file); launch_data_t r = NULL; @@ -311,44 +339,8 @@ static launch_data_t read_plist_file(const char *file, bool editondisk, bool loa return r; } -static 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; - } -} - -static 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; -} - -static void readfile(const char *what, launch_data_t pass1, launch_data_t pass2, bool editondisk, bool load, bool forceload) +void +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; @@ -358,6 +350,11 @@ static void readfile(const char *what, launch_data_t pass1, launch_data_t pass2, return; } + if (is_legacy_mach_job(thejob)) { + launch_data_array_append(pass0, thejob); + return; + } + if (NULL == launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LABEL)) { fprintf(stderr, "%s: missing the Label key: %s\n", getprogname(), what); launch_data_free(thejob); @@ -375,13 +372,11 @@ static void readfile(const char *what, launch_data_t pass1, launch_data_t pass2, 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); } -static void readpath(const char *what, launch_data_t pass1, launch_data_t pass2, bool editondisk, bool load, bool forceload) +void +readpath(const char *what, launch_data_t pass0, launch_data_t pass1, bool editondisk, bool load, bool forceload) { char buf[MAXPATHLEN]; struct stat sb; @@ -392,7 +387,7 @@ static void readpath(const char *what, launch_data_t pass1, launch_data_t pass2, return; if (S_ISREG(sb.st_mode) && !(sb.st_mode & S_IWOTH)) { - readfile(what, 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()); @@ -404,7 +399,7 @@ static void readpath(const char *what, launch_data_t pass1, launch_data_t pass2, continue; snprintf(buf, sizeof(buf), "%s/%s", what, de->d_name); - readfile(buf, pass1, pass2, editondisk, load, forceload); + readfile(buf, pass0, pass1, editondisk, load, forceload); } closedir(d); } @@ -415,7 +410,17 @@ struct distill_context { launch_data_t newsockdict; }; -static void distill_config_file(launch_data_t id_plist) +void +distill_jobs(launch_data_t jobs) +{ + size_t i, c = launch_data_array_get_count(jobs); + + for (i = 0; i < c; i++) + distill_config_file(launch_data_array_get_index(jobs, i)); +} + +void +distill_config_file(launch_data_t id_plist) { struct distill_context dc = { id_plist, NULL }; launch_data_t tmp; @@ -450,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; @@ -487,6 +496,9 @@ static void sock_dict_edit_entry(launch_data_t tmp, const char *key, launch_data if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_PATHNAME))) { struct sockaddr_un sun; + mode_t sun_mode = 0; + mode_t oldmask; + bool setm = false; memset(&sun, 0, sizeof(sun)); @@ -497,15 +509,26 @@ static void sock_dict_edit_entry(launch_data_t tmp, const char *key, launch_data if ((sfd = _fd(socket(AF_UNIX, st, 0))) == -1) return; + if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_PATHMODE))) { + sun_mode = (mode_t)launch_data_get_integer(val); + setm = true; + } + if (passive) { if (unlink(sun.sun_path) == -1 && errno != ENOENT) { close(sfd); return; } + oldmask = umask(S_IRWXG|S_IRWXO); if (bind(sfd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { close(sfd); + umask(oldmask); return; } + umask(oldmask); + if (setm) { + chmod(sun.sun_path, sun_mode); + } if ((st == SOCK_STREAM || st == SOCK_SEQPACKET) && listen(sfd, SOMAXCONN) == -1) { close(sfd); @@ -568,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; @@ -605,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) { @@ -637,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); } } @@ -692,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 (1 == statres) - statres = stat("/usr/sbin/mDNSResponder", &sb); + if (fork() != 0) + return; + + signal(SIGHUP, SIG_IGN); + setsid(); + sleep(30); - if (-1 == statres) - return NULL; + msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + msgpayload = launch_data_alloc(LAUNCH_DATA_DICTIONARY); + + 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) @@ -732,7 +792,7 @@ static CFPropertyListRef CreateMyPropertyListFromFile(const char *posixfile) SInt32 errorCode; CFURLRef fileURL; - fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, posixfile, strlen(posixfile), false); + fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)posixfile, strlen(posixfile), false); if (!fileURL) fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile); if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) @@ -750,7 +810,7 @@ static void WriteMyPropertyListToFile(CFPropertyListRef plist, const char *posix CFURLRef fileURL; SInt32 errorCode; - fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, posixfile, strlen(posixfile), false); + fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)posixfile, strlen(posixfile), false); if (!fileURL) fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile); resourceData = CFPropertyListCreateXMLData(kCFAllocatorDefault, plist); @@ -866,7 +926,7 @@ static int _fd(int fd) static int load_and_unload_cmd(int argc, char *const argv[]) { - launch_data_t pass1, pass2; + launch_data_t pass0, pass1; int i, ch; bool wflag = false; bool lflag = false; @@ -892,7 +952,8 @@ static int load_and_unload_cmd(int argc, char *const argv[]) return 1; } - /* I wish I didn't need to do two 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, * then do the Bonjour magic on the jobs that need it, and reload them, but for now, @@ -900,44 +961,102 @@ static int load_and_unload_cmd(int argc, char *const argv[]) * launchd doesn't have reload support right now. */ + 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], pass1, pass2, wflag, lflag, Fflag); + readpath(argv[i], pass0, pass1, wflag, lflag, Fflag); - if (0 == launch_data_array_get_count(pass1) && 0 == launch_data_array_get_count(pass2)) { + if (launch_data_array_get_count(pass0) == 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) { - if (0 < launch_data_array_get_count(pass1)) { - submit_job_pass(pass1); - } - if (0 < launch_data_array_get_count(pass2)) { - submit_job_pass(pass2); - } + distill_jobs(pass1); + submit_mach_jobs(pass0); + workaround_bonjour_asynchronously(); + submit_job_pass(pass1); + let_go_of_mach_jobs(); } 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; } -static void submit_job_pass(launch_data_t jobs) +static mach_port_t *msrvs = NULL; +static size_t msrvs_cnt = 0; + +void +submit_mach_jobs(launch_data_t jobs) +{ + size_t i, c; + + c = launch_data_array_get_count(jobs); + + msrvs = calloc(1, sizeof(mach_port_t) * c); + msrvs_cnt = c; + + for (i = 0; i < c; i++) { + launch_data_t tmp, oai = launch_data_array_get_index(jobs, i); + const char *sn = NULL, *cmd = NULL; + bool d = true, k = false; + mach_port_t msr, msv, mhp; + kern_return_t kr; + uid_t u = getuid(); + + if ((tmp = launch_data_dict_lookup(oai, MACHINIT_JOBKEY_ONDEMAND))) + d = launch_data_get_bool(tmp); + if ((tmp = launch_data_dict_lookup(oai, MACHINIT_JOBKEY_ISKUNCSERVER))) + k = launch_data_get_bool(tmp); + if ((tmp = launch_data_dict_lookup(oai, MACHINIT_JOBKEY_SERVICENAME))) + sn = launch_data_get_string(tmp); + if ((tmp = launch_data_dict_lookup(oai, MACHINIT_JOBKEY_COMMAND))) + cmd = launch_data_get_string(tmp); + + if ((kr = bootstrap_create_server(bootstrap_port, (char *)cmd, u, d, &msr)) != KERN_SUCCESS) { + fprintf(stderr, "%s: bootstrap_create_server(): %d\n", getprogname(), kr); + continue; + } + if ((kr = bootstrap_create_service(msr, (char*)sn, &msv)) != KERN_SUCCESS) { + fprintf(stderr, "%s: bootstrap_create_service(): %d\n", getprogname(), kr); + mach_port_destroy(mach_task_self(), msr); + continue; + } + if (k) { + mhp = mach_host_self(); + if ((kr = host_set_UNDServer(mhp, msv)) != KERN_SUCCESS) + fprintf(stderr, "%s: host_set_UNDServer(): %s\n", getprogname(), mach_error_string(kr)); + mach_port_deallocate(mach_task_self(), mhp); + } + mach_port_deallocate(mach_task_self(), msv); + msrvs[i] = msr; + } +} + +void +let_go_of_mach_jobs(void) +{ + size_t i; + + for (i = 0; i < msrvs_cnt; i++) + mach_port_destroy(mach_task_self(), msrvs[i]); +} + +void +submit_job_pass(launch_data_t jobs) { launch_data_t msg, resp; size_t i; int e; - for (i = 0; i < launch_data_array_get_count(jobs); i++) - distill_config_file(launch_data_array_get_index(jobs, i)); + if (launch_data_array_get_count(jobs) == 0) + return; msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); @@ -1262,6 +1381,68 @@ static int logupdate_cmd(int argc, char *const argv[]) return r; } +static const struct { + const char *name; + int lim; +} limlookup[] = { + { "cpu", RLIMIT_CPU }, + { "filesize", RLIMIT_FSIZE }, + { "data", RLIMIT_DATA }, + { "stack", RLIMIT_STACK }, + { "core", RLIMIT_CORE }, + { "rss", RLIMIT_RSS }, + { "memlock", RLIMIT_MEMLOCK }, + { "maxproc", RLIMIT_NPROC }, + { "maxfiles", RLIMIT_NOFILE } +}; + +static const size_t limlookupcnt = sizeof limlookup / sizeof limlookup[0]; + +static ssize_t name2num(const char *n) +{ + size_t i; + + for (i = 0; i < limlookupcnt; i++) { + if (!strcmp(limlookup[i].name, n)) { + return limlookup[i].lim; + } + } + return -1; +} + +static const char *num2name(int n) +{ + size_t i; + + for (i = 0; i < limlookupcnt; i++) { + if (limlookup[i].lim == n) + return limlookup[i].name; + } + return NULL; +} + +static const char *lim2str(rlim_t val, char *buf) +{ + if (val == RLIM_INFINITY) + strcpy(buf, "unlimited"); + else + sprintf(buf, "%lld", val); + return buf; +} + +static bool str2lim(const char *buf, rlim_t *res) +{ + char *endptr; + *res = strtoll(buf, &endptr, 10); + if (!strcmp(buf, "unlimited")) { + *res = RLIM_INFINITY; + return false; + } else if (*endptr == '\0') { + return false; + } + return true; +} + static int limit_cmd(int argc __attribute__((unused)), char *const argv[]) { char slimstr[100]; @@ -1269,58 +1450,10 @@ static int limit_cmd(int argc __attribute__((unused)), char *const argv[]) struct rlimit *lmts = NULL; launch_data_t resp, resp1 = NULL, msg, tmp; int r = 0; - size_t i, lsz = -1, which = 0; + size_t i, lsz = -1; + ssize_t which = 0; rlim_t slim = -1, hlim = -1; bool badargs = false; - static const struct { - const char *name; - int lim; - } limlookup[] = { - { "cpu", RLIMIT_CPU }, - { "filesize", RLIMIT_FSIZE }, - { "data", RLIMIT_DATA }, - { "stack", RLIMIT_STACK }, - { "core", RLIMIT_CORE }, - { "rss", RLIMIT_RSS }, - { "memlock", RLIMIT_MEMLOCK }, - { "maxproc", RLIMIT_NPROC }, - { "maxfiles", RLIMIT_NOFILE } - }; - size_t limlookupcnt = sizeof limlookup / sizeof limlookup[0]; - bool name2num(const char *n) { - for (i = 0; i < limlookupcnt; i++) { - if (!strcmp(limlookup[i].name, n)) { - which = limlookup[i].lim; - return false; - } - } - return true; - }; - const char *num2name(int n) { - for (i = 0; i < limlookupcnt; i++) { - if (limlookup[i].lim == n) - return limlookup[i].name; - } - return NULL; - }; - const char *lim2str(rlim_t val, char *buf) { - if (val == RLIM_INFINITY) - strcpy(buf, "unlimited"); - else - sprintf(buf, "%lld", val); - return buf; - }; - bool str2lim(const char *buf, rlim_t *res) { - char *endptr; - *res = strtoll(buf, &endptr, 10); - if (!strcmp(buf, "unlimited")) { - *res = RLIM_INFINITY; - return false; - } else if (*endptr == '\0') { - return false; - } - return true; - }; if (argc > 4) badargs = true; @@ -1333,7 +1466,7 @@ static int limit_cmd(int argc __attribute__((unused)), char *const argv[]) if (argc == 4 && str2lim(argv[3], &hlim)) badargs = true; - if (argc >= 2 && name2num(argv[1])) + if (argc >= 2 && -1 == (which = name2num(argv[1]))) badargs = true; if (badargs) { @@ -1356,7 +1489,7 @@ static int limit_cmd(int argc __attribute__((unused)), char *const argv[]) lsz = launch_data_get_opaque_size(resp); if (argc <= 2) { for (i = 0; i < (lsz / sizeof(struct rlimit)); i++) { - if (argc == 2 && which != i) + if (argc == 2 && (size_t)which != i) continue; fprintf(stdout, "\t%-12s%-15s%-15s\n", num2name(i), lim2str(lmts[i].rlim_cur, slimstr), @@ -1518,3 +1651,13 @@ static bool launch_data_array_append(launch_data_t a, launch_data_t o) return launch_data_array_set_index(a, o, offt); } + +bool +is_legacy_mach_job(launch_data_t obj) +{ + bool has_servicename = launch_data_dict_lookup(obj, MACHINIT_JOBKEY_SERVICENAME); + bool has_command = launch_data_dict_lookup(obj, MACHINIT_JOBKEY_COMMAND); + bool has_label = launch_data_dict_lookup(obj, LAUNCH_JOBKEY_LABEL); + + return has_command && has_servicename && !has_label; +}