PERFORCE change 82813 for review
soc-tyler
soc-tyler at FreeBSD.org
Tue Aug 30 02:47:27 GMT 2005
http://perforce.freebsd.org/chv.cgi?CH=82813
Change 82813 by soc-tyler at soc-tyler_launchd on 2005/08/30 02:46:50
Merge zarzycki@'s developmental changes (i.e. experiemental code from Cupertino)
to take advantage of some of the features "im bau."
Affected files ...
.. //depot/projects/soc2005/launchd/launchctl/launchctl.c#12 edit
.. //depot/projects/soc2005/launchd/launchd.c#16 edit
Differences ...
==== //depot/projects/soc2005/launchd/launchctl/launchctl.c#12 (text+ko) ====
@@ -41,6 +41,7 @@
#include <sys/event.h>
#include <sys/resource.h>
#include <sys/param.h>
+#include <sys/wait.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
@@ -81,16 +82,17 @@
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);
-static void readpath(const char *, launch_data_t, launch_data_t, bool editondisk, bool load);
+static void readpath(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 void submit_job_pass(launch_data_t jobs);
+static void do_mgroup_join(int fd, int family, int socktype, int protocol, const char *mgroup);
// Mac OS X/Darwin related functions (for backwards compat.)
#ifdef _BUILD_DARWIN_
static launch_data_t CF2launch_data(const void *);
static launch_data_t read_plist_file(const char *file, bool editondisk, bool load);
-static const void *CreateMyPropertyListFromFile(const char *);
+static CFPropertyListRef CreateMyPropertyListFromFile(const char *);
static void WriteMyPropertyListToFile(CFPropertyListRef, const char *);
static launch_data_t do_rendezvous_magic(const struct addrinfo *res, const char *serv);
#endif
@@ -102,7 +104,8 @@
static int load_and_unload_cmd(int argc, char *const argv[]);
//static int reload_cmd(int argc, char *const argv[]);
-static int start_and_stop_cmd(int argc, char *const argv[]);
+static int start_stop_remove_cmd(int argc, char *const argv[]);
+static int submit_cmd(int argc, char *const argv[]);
static int list_cmd(int argc, char *const argv[]);
static int setenv_cmd(int argc, char *const argv[]);
@@ -127,8 +130,10 @@
{ "load", load_and_unload_cmd, "Load configuration files and/or directories" },
{ "unload", load_and_unload_cmd, "Unload configuration files and/or directories" },
// { "reload", reload_cmd, "Reload configuration files and/or directories" },
- { "start", start_and_stop_cmd, "Start specified jobs" },
- { "stop", start_and_stop_cmd, "Stop specified jobs" },
+ { "start", start_stop_remove_cmd, "Start specified job" },
+ { "stop", start_stop_remove_cmd, "Stop specified job" },
+ { "submit", submit_cmd, "Submit a job from the command line" },
+ { "remove", start_stop_remove_cmd, "Remove specified job" },
{ "list", list_cmd, "List jobs and information about jobs" },
{ "setenv", setenv_cmd, "Set an environmental variable in launchd" },
{ "unsetenv", unsetenv_cmd, "Unset an environmental variable in launchd" },
@@ -144,22 +149,25 @@
{ "umask", umask_cmd, "Change launchd's umask" },
{ "help", help_cmd, "This help output" },
{"exit", exit_cmd, "Exit launchctl" },
+ {"quit", exit_cmd, "Quit launchctl"},
};
-int main(int argc, char *const argv[])
-{
- bool istty = isatty(STDIN_FILENO);
+static bool istty = false;
+
+int main(int argc, char *const argv[]) {
char *l;
if (argc > 1)
exit(demux_cmd(argc - 1, argv + 1));
+ istty = isatty(STDIN_FILENO);
+
if (NULL == readline) {
fprintf(stderr, "missing library: readline\n");
exit(EXIT_FAILURE);
}
- while ((l = readline(istty ? "launchctl% " : NULL))) {
+ while ((l = readline(istty ? "launchd% " : NULL))) {
char *inputstring = l, *argv2[100], **ap = argv2;
int i = 0;
@@ -415,31 +423,75 @@
return res;
}
-static void readfile(const char *what, launch_data_t pass1, launch_data_t pass2, bool editondisk, bool load)
+static void readfile(const char *what, launch_data_t pass1, launch_data_t pass2, bool editondisk, bool load, bool forceload)
{
- launch_data_t tmpd, thejob;
+ char ourhostname[1024];
+ launch_data_t tmpd, thejob, tmpa;
bool job_disabled = false;
+ size_t i, c;
+ gethostname(ourhostname, sizeof(ourhostname));
+#ifndef _BUILD_DARWIN_
if (NULL == (thejob = read_conf_file(what, editondisk, load))) {
- fprintf(stderr, "%s: no plist was returned for: %s\n", getprogname(), what);
+ fprintf(stderr, "%s: no config file was returned for: %s\n", getprogname(), what);
return;
}
+#endif
+#ifdef _BUILD_DARWIN_
+ if (NULL == (thejob = read_plist_file(what, editondisk, load))) {
+ fprintf(stderr, "%s: no plist was returned for: %s\n", getprogname(), what);
+ return;
+ }
+#endif
- if ((tmpd = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_DISABLED)))
- job_disabled = launch_data_get_bool(tmpd);
+ if (NULL == launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LABEL)) {
+ fprintf(stderr, "%s: missing the Label key: %s\n", getprogname(), what);
+ goto out_bad;
+ }
+
+ if (NULL != (tmpa = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LIMITLOADFROMHOSTS))) {
+ c = launch_data_array_get_count(tmpa);
+
+ for (i = 0; i < c; i++) {
+ launch_data_t oai = launch_data_array_get_index(tmpa, i);
+ if (!strcasecmp(ourhostname, launch_data_get_string(oai)))
+ goto out_bad;
+ }
+ }
+
+ if (NULL != (tmpa = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LIMITLOADTOHOSTS))) {
+ c = launch_data_array_get_count(tmpa);
+
+ for (i = 0; i < c; i++) {
+ launch_data_t oai = launch_data_array_get_index(tmpa, i);
+ if (!strcasecmp(ourhostname, launch_data_get_string(oai)))
+ break;
+ }
+
+ if (i == c)
+ goto out_bad;
+ }
+
+ if ((tmpd = launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_DISABLED)))
+ job_disabled = launch_data_get_bool(tmpd);
+
+ if (forceload)
+ job_disabled = false;
+
+ if (job_disabled && load)
+ goto out_bad;
- if (job_disabled && load) {
- launch_data_free(thejob);
- return;
- }
+ if (delay_to_second_pass(thejob))
+ launch_data_array_append(pass2, thejob);
+ else
+ launch_data_array_append(pass1, thejob);
- if (delay_to_second_pass(thejob))
- launch_data_array_append(pass2, thejob);
- else
- launch_data_array_append(pass1, thejob);
+ return;
+out_bad:
+ launch_data_free(thejob);
}
-static void readpath(const char *what, launch_data_t pass1, launch_data_t pass2, bool editondisk, bool load)
+static void readpath(const char *what, launch_data_t pass1, launch_data_t pass2, bool editondisk, bool load, bool forceload)
{
char buf[MAXPATHLEN];
struct stat sb;
@@ -450,7 +502,7 @@
return;
if (S_ISREG(sb.st_mode) && !(sb.st_mode & S_IWOTH)) {
- readfile(what, pass1, pass2, editondisk, load);
+ readfile(what, pass1, pass2, editondisk, load, forceload);
} else {
if ((d = opendir(what)) == NULL) {
fprintf(stderr, "%s: opendir() failed to open the directory\n", getprogname());
@@ -462,7 +514,7 @@
continue;
snprintf(buf, sizeof(buf), "%s/%s", what, de->d_name);
- readfile(buf, pass1, pass2, editondisk, load);
+ readfile(buf, pass1, pass2, editondisk, load, forceload);
}
closedir(d);
}
@@ -578,7 +630,7 @@
launch_data_array_append(fdarray, val);
} else {
launch_data_t rnames = NULL;
- const char *node = NULL, *serv = NULL;
+ const char *node = NULL, *serv = NULL, *mgroup = NULL;
char servnbuf[50];
struct addrinfo hints, *res0, *res;
int gerr, sock_opt = 1;
@@ -592,6 +644,8 @@
if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_NODENAME)))
node = launch_data_get_string(val);
+ if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_MULTICASTGROUP)))
+ mgroup = launch_data_get_string(val);
if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_SERVICENAME))) {
if (LAUNCH_DATA_INTEGER == launch_data_get_type(val)) {
sprintf(servnbuf, "%lld", launch_data_get_integer(val));
@@ -635,14 +689,24 @@
fprintf(stderr, "setsockopt(IPV6_V6ONLY): %m");
return;
}
- if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt, sizeof(sock_opt)) == -1) {
- fprintf(stderr, "socket(): %s\n", strerror(errno));
- return;
- }
+ if (mgroup) {
+ if (setsockopt(sfd, SOL_SOCKET, SO_REUSEPORT, (void *)&sock_opt, sizeof(sock_opt)) == -1) {
+ fprintf(stderr, "setsockopt(SO_REUSEPORT): %s\n", strerror(errno));
+ return;
+ }
+ } else {
+ if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt, sizeof(sock_opt)) == -1) {
+ fprintf(stderr, "setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
+ return;
+ }
+ }
if (bind(sfd, res->ai_addr, res->ai_addrlen) == -1) {
fprintf(stderr, "bind(): %s\n", strerror(errno));
return;
}
+ if (mgroup) {
+ do_mgroup_join(sfd, res->ai_family, res->ai_socktype, res->ai_protocol, mgroup);
+ }
if ((res->ai_socktype == SOCK_STREAM || res->ai_socktype == SOCK_SEQPACKET)
&& listen(sfd, SOMAXCONN) == -1) {
fprintf(stderr, "listen(): %s\n", strerror(errno));
@@ -698,6 +762,45 @@
}
}
+static void do_mgroup_join(int fd, int family, int socktype, int protocol, const char *mgroup) {
+ struct addrinfo hints, *res0, *res;
+ struct ip_mreq mreq;
+ struct ipv6_mreq m6req; int gerr;
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_flags |= AI_PASSIVE;
+ hints.ai_family = family;
+ hints.ai_socktype = socktype;
+ hints.ai_protocol = protocol;
+ if ((gerr = getaddrinfo(mgroup, NULL, &hints, &res0)) != 0) {
+ fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(gerr));
+ return;
+ }
+
+ for (res = res0; res; res = res->ai_next) {
+ if (AF_INET == family) { memset(&mreq, 0, sizeof(mreq));
+ mreq.imr_multiaddr = ((struct sockaddr_in *)res->ai_addr)->sin_addr;
+ if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) { fprintf(stderr, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno));
+ continue;
+ } break;
+ } else if (AF_INET6 == family) {
+ memset(&m6req, 0, sizeof(m6req));
+ m6req.ipv6mr_multiaddr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &m6req, sizeof(m6req)) == -1) {
+ fprintf(stderr, "setsockopt(IPV6_JOIN_GROUP): %s\n", strerror(errno));
+ continue;
+ }
+ break;
+ } else {
+ fprintf(stderr, "unknown family during multicast group bind!\n");
+ break;
+ } }
+
+ freeaddrinfo(res0);
+}
+
+
#ifdef _BUILD_DARWIN_
static launch_data_t do_rendezvous_magic(const struct addrinfo *res, const char *serv)
{
@@ -730,7 +833,7 @@
return NULL;
}
-static const void *CreateMyPropertyListFromFile(const char *posixfile)
+static CFPropertyListRef CreateMyPropertyListFromFile(const char *posixfile)
{
CFPropertyListRef propertyList;
CFStringRef errorString;
@@ -738,7 +841,7 @@
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))
@@ -756,7 +859,7 @@
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);
@@ -777,7 +880,7 @@
launch_data_free(ik);
}
-static launch_data_t CF2launch_data(const void *cfr)
+static launch_data_t CF2launch_data(CFTypeRef cfr)
{
launch_data_t r;
CFTypeID cft = CFGetTypeID(cfr);
@@ -794,7 +897,7 @@
CFIndex i, ac = CFArrayGetCount(cfr);
r = launch_data_alloc(LAUNCH_DATA_ARRAY);
for (i = 0; i < ac; i++) {
- const void *v = CFArrayGetValueAtIndex(cfr, i);
+ CFTypeRef v = CFArrayGetValueAtIndex(cfr, i);
if (v) {
launch_data_t iv = CF2launch_data(v);
launch_data_array_set_index(r, iv, i);
@@ -811,7 +914,6 @@
double d;
CFNumberType cfnt = CFNumberGetType(cfr);
switch (cfnt) {
- case kCFNumberSInt8Type:
case kCFNumberSInt16Type:
case kCFNumberSInt32Type:
case kCFNumberSInt64Type:
@@ -853,18 +955,24 @@
where = stderr;
fprintf(where, "usage: %s <subcommand>\n", getprogname());
+
for (i = 0; i < (sizeof cmds / sizeof cmds[0]); i++) {
- l = strlen(cmds[i].name);
- if (l > cmdwidth)
- cmdwidth = l;
- }
- for (i = 0; i < (sizeof cmds / sizeof cmds[0]); i++)
- fprintf(where, "\t%-*s\t%s\n", cmdwidth, cmds[i].name, cmds[i].desc);
+ l = strlen(cmds[i].name);
+ if (l > cmdwidth)
+ cmdwidth = l;
+ }
+
+ for (i = 0; i < (sizeof cmds / sizeof cmds[0]); i++) {
+ if (cmds[i].func == exit_cmd && istty == false)
+ continue;
+ fprintf(where, "\t%-*s\t%s\n", cmdwidth, cmds[i].name, cmds[i].desc);
+ }
return 0;
}
-static int exit_cmd(int argc, char *const argv[]) {
+static int exit_cmd(int argc __attribute__((unused)), char *const argv[] __attribute__((unused)))
+{
exit(EXIT_SUCCESS);
return 0; // god help us if we get here ;)
@@ -883,22 +991,22 @@
int i, ch;
bool wflag = false;
bool lflag = false;
+ bool Fflag = false;
if (!strcmp(argv[0], "load"))
lflag = true;
- while ((ch = getopt(argc, argv, "w")) != -1) {
- switch (ch) {
- case 'w':
- wflag = true;
- break;
- default:
- fprintf(stderr, "usage: %s load [-w] paths...\n", getprogname());
- return 1;
- }
- }
- argc -= optind;
- argv += optind;
+ while ((ch = getopt(argc, argv, "wF")) != -1) {
+ switch (ch) {
+ case 'w': wflag = true; break;
+ case 'F': Fflag = true; break;
+ default:
+ fprintf(stderr, "usage: %s load [-wF] paths...\n", getprogname());
+ return 1;
+ }
+ }
+ argc -= optind;
+ argv += optind;
if (argc == 0) {
fprintf(stderr, "usage: %s load [-w] paths...\n", getprogname());
@@ -917,7 +1025,7 @@
pass2 = launch_data_alloc(LAUNCH_DATA_ARRAY);
for (i = 0; i < argc; i++)
- readpath(argv[i], pass1, pass2, wflag, lflag);
+ readpath(argv[i], pass1, pass2, wflag, lflag, Fflag);
if (0 == launch_data_array_get_count(pass1) && 0 == launch_data_array_get_count(pass2)) {
fprintf(stderr, "nothing found to %s\n", lflag ? "load" : "unload");
@@ -998,15 +1106,18 @@
launch_data_free(msg);
}
-static int start_and_stop_cmd(int argc, char *const argv[])
+static int start_stop_remove_cmd(int argc, char *const argv[])
{
launch_data_t resp, msg;
const char *lmsgcmd = LAUNCH_KEY_STOPJOB;
int e, r = 0;
- if (!strcmp(argv[0], "start"))
+ if (0 == strcmp(argv[0], "start"))
lmsgcmd = LAUNCH_KEY_STARTJOB;
+ if (0 == strcmp(argv[0], "remove"))
+ lmsgcmd = LAUNCH_KEY_REMOVEJOB;
+
if (argc != 2) {
fprintf(stderr, "usage: %s %s <job label>\n", getprogname(), argv[0]);
return 1;
@@ -1037,48 +1148,65 @@
static void print_jobs(launch_data_t j __attribute__((unused)), const char *label, void *context __attribute__((unused)))
{
- fprintf(stdout, "%s\n", label);
+ launch_data_t pido = launch_data_dict_lookup(j, LAUNCH_JOBKEY_PID);
+ launch_data_t stato = launch_data_dict_lookup(j, LAUNCH_JOBKEY_LASTEXITSTATUS);
+
+ if (pido) {
+ fprintf(stdout, "%lld\t-\t%s\n", launch_data_get_integer(pido), label);
+ } else if (stato) {
+ int wstatus = (int)launch_data_get_integer(stato);
+ if (WIFEXITED(wstatus)) {
+ fprintf(stdout, "-\t%d\t%s\n", WEXITSTATUS(wstatus), label);
+ } else if (WIFSIGNALED(wstatus)) {
+ fprintf(stdout, "-\t-%d\t%s\n", WTERMSIG(wstatus), label);
+ } else {
+ fprintf(stdout, "-\t???\t%s\n", label);
+ }
+ } else {
+ fprintf(stdout, "-\t-\t%s\n", label);
+ }
}
static int list_cmd(int argc, char *const argv[])
{
launch_data_t resp, msg;
- int ch, r = 0;
- bool vflag = false;
+ int ch, r = 0;
+ bool vflag = false;
- while ((ch = getopt(argc, argv, "v")) != -1) {
- switch (ch) {
- case 'v':
- vflag = true;
- break;
- default:
- fprintf(stderr, "usage: %s list [-v]\n", getprogname());
- return 1;
- }
- }
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ vflag = true;
+ break;
+ default:
+ fprintf(stderr, "usage: %s list [-v]\n", getprogname());
+ return 1;
+ }
+ }
- if (vflag) {
- fprintf(stderr, "usage: %s list: \"-v\" flag not implemented yet\n", getprogname());
- return 1;
- }
+ if (vflag) {
+ fprintf(stderr, "usage: %s list: \"-v\" flag not implemented yet\n", getprogname());
+ return 1;
+ }
- msg = launch_data_new_string(LAUNCH_KEY_GETJOBS);
- resp = launch_msg(msg);
- launch_data_free(msg);
+ msg = launch_data_new_string(LAUNCH_KEY_GETJOBS);
+ resp = launch_msg(msg);
+ launch_data_free(msg);
- if (resp == NULL) {
- fprintf(stderr, "launch_msg(): %s\n", strerror(errno));
- return 1;
- } else if (launch_data_get_type(resp) == LAUNCH_DATA_DICTIONARY) {
- launch_data_dict_iterate(resp, print_jobs, NULL);
- } else {
- fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]);
- r = 1;
- }
+ if (resp == NULL) {
+ fprintf(stderr, "launch_msg(): %s\n", strerror(errno));
+ return 1;
+ } else if (launch_data_get_type(resp) == LAUNCH_DATA_DICTIONARY) {
+ fprintf(stdout, "PID\tStatus\tLabel\n");
+ launch_data_dict_iterate(resp, print_jobs, NULL);
+ } else {
+ fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]);
+ r = 1;
+ }
- launch_data_free(resp);
+ launch_data_free(resp);
- return r;
+ return r;
}
static int stdio_cmd(int argc, char *const argv[])
@@ -1420,48 +1548,108 @@
static int umask_cmd(int argc, char *const argv[])
{
launch_data_t resp, msg;
- bool badargs = false;
- char *endptr;
- long m = 0;
- int r = 0;
+ bool badargs = false;
+ char *endptr;
+ long m = 0;
+ int r = 0;
+
+ if (argc == 2) {
+ m = strtol(argv[1], &endptr, 8);
+ if (*endptr != '\0' || m > 0777)
+ badargs = true;
+ }
+
+ if (argc > 2 || badargs) {
+ fprintf(stderr, "usage: %s %s <mask>\n", getprogname(), argv[0]);
+ return 1;
+ }
+
+
+ if (argc == 1) {
+ msg = launch_data_new_string(LAUNCH_KEY_GETUMASK);
+ } else {
+ msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
+ launch_data_dict_insert(msg, launch_data_new_integer(m), LAUNCH_KEY_SETUMASK);
+ }
+ resp = launch_msg(msg);
+ launch_data_free(msg);
+
+ if (resp == NULL) {
+ fprintf(stderr, "launch_msg(): %s\n", strerror(errno));
+ return 1;
+ } else if (launch_data_get_type(resp) == LAUNCH_DATA_STRING) {
+ fprintf(stderr, "%s %s error: %s\n", getprogname(), argv[0], launch_data_get_string(resp));
+ r = 1;
+ } else if (launch_data_get_type(resp) != LAUNCH_DATA_INTEGER) {
+ fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]);
+ r = 1;
+ } else if (argc == 1) {
+ fprintf(stdout, "%o\n", (unsigned int)launch_data_get_integer(resp));
+ }
+
+ launch_data_free(resp);
+
+ return r;
+}
+
+static int submit_cmd(int argc, char *const argv[])
+{
+ launch_data_t msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
+ launch_data_t job = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
+ launch_data_t resp, largv = launch_data_alloc(LAUNCH_DATA_ARRAY);
+ int ch, i, r = 0;
+
+ launch_data_dict_insert(job, launch_data_new_bool(false), LAUNCH_JOBKEY_ONDEMAND);
+
+ while ((ch = getopt(argc, argv, "l:p:o:e:")) != -1) {
+ switch (ch) {
+ case 'l':
+ launch_data_dict_insert(job, launch_data_new_string(optarg), LAUNCH_JOBKEY_LABEL);
+ break;
+ case 'p':
+ launch_data_dict_insert(job, launch_data_new_string(optarg), LAUNCH_JOBKEY_PROGRAM);
+ break;
+ case 'o':
+ launch_data_dict_insert(job, launch_data_new_string(optarg), LAUNCH_JOBKEY_STANDARDOUTPATH);
+ break;
+ case 'e':
+ launch_data_dict_insert(job, launch_data_new_string(optarg), LAUNCH_JOBKEY_STANDARDERRORPATH);
+ break;
+ default:
+ fprintf(stderr, "usage: %s submit ...\n", getprogname());
+ return 1;
+ }
+ }
+ argc -= optind;
+ argv += optind;
- if (argc == 2) {
- m = strtol(argv[1], &endptr, 8);
- if (*endptr != '\0' || m > 0777)
- badargs = true;
- }
+ for (i = 0; argv[i]; i++) {
+ launch_data_array_append(largv, launch_data_new_string(argv[i]));
+ }
- if (argc > 2 || badargs) {
- fprintf(stderr, "usage: %s %s <mask>\n", getprogname(), argv[0]);
- return 1;
- }
+ launch_data_dict_insert(job, largv, LAUNCH_JOBKEY_PROGRAMARGUMENTS);
+ launch_data_dict_insert(msg, job, LAUNCH_KEY_SUBMITJOB);
- if (argc == 1) {
- msg = launch_data_new_string(LAUNCH_KEY_GETUMASK);
- } else {
- msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
- launch_data_dict_insert(msg, launch_data_new_integer(m), LAUNCH_KEY_SETUMASK);
- }
- resp = launch_msg(msg);
- launch_data_free(msg);
+ resp = launch_msg(msg);
+ launch_data_free(msg);
- if (resp == NULL) {
- fprintf(stderr, "launch_msg(): %s\n", strerror(errno));
- return 1;
- } else if (launch_data_get_type(resp) == LAUNCH_DATA_STRING) {
- fprintf(stderr, "%s %s error: %s\n", getprogname(), argv[0], launch_data_get_string(resp));
- r = 1;
- } else if (launch_data_get_type(resp) != LAUNCH_DATA_INTEGER) {
- fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]);
- r = 1;
- } else if (argc == 1) {
- fprintf(stdout, "%o\n", (unsigned int)launch_data_get_integer(resp));
- }
+ if (resp == NULL) {
+ fprintf(stderr, "launch_msg(): %s\n", strerror(errno));
+ return 1;
+ } else if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) {
+ errno = launch_data_get_errno(resp);
+ if (errno) {
+ fprintf(stderr, "%s %s error: %s\n", getprogname(), argv[0], strerror(errno));
+ r = 1;
+ }
+ } else {
+ fprintf(stderr, "%s %s error: %s\n", getprogname(), argv[0], "unknown response");
+ }
- launch_data_free(resp);
+ launch_data_free(resp);
- return r;
+ return r;
}
static int getrusage_cmd(int argc, char *const argv[])
==== //depot/projects/soc2005/launchd/launchd.c#16 (text+ko) ====
@@ -110,6 +110,7 @@
TAILQ_ENTRY(jobcb) tqe;
launch_data_t ldj;
pid_t p;
+ int last_exit_status;
int execfd;
time_t start_time;
size_t failed_exits;
@@ -167,6 +168,7 @@
static void job_reap(struct jobcb *j);
static void job_remove(struct jobcb *j);
static void job_set_alarm(struct jobcb *j);
+static launch_data_t job_export(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)));
@@ -347,7 +349,7 @@
init_pre_kevent();
} else {
if (TAILQ_EMPTY(&jobs) && TAILQ_EMPTY(&connections)) {
- /* launched on demand */
+ /* liblaunch will restart launchd if we're needed again */
timeoutp = &timeout;
} else if (shutdown_in_progress && total_children == 0) {
exit(EXIT_SUCCESS);
@@ -885,6 +887,24 @@
kill(j->p, SIGTERM);
}
+static launch_data_t job_export(struct jobcb *j)
+{
+ launch_data_t tmp, r = launch_data_copy(j->ldj);
+
+ if (r) {
+ tmp = launch_data_new_integer(j->last_exit_status);
+ if (tmp)
+ launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_LASTEXITSTATUS);
+ if (j->p) {
+ tmp = launch_data_new_integer(j->p);
+ if (tmp)
+ launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_PID);
+ }
+ }
+
+ return r;
+}
+
static void job_remove(struct jobcb *j)
{
launch_data_t tmp;
@@ -1263,7 +1283,7 @@
if (which) {
TAILQ_FOREACH(j, &jobs, tqe) {
if (!strcmp(which, j->label))
- resp = launch_data_copy(j->ldj);
+ resp = job_export(j);
}
if (resp == NULL)
resp = launch_data_new_errno(ESRCH);
@@ -1271,7 +1291,7 @@
resp = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
TAILQ_FOREACH(j, &jobs, tqe) {
- tmp = launch_data_copy(j->ldj);
+ tmp = job_export(j);
launch_data_dict_insert(resp, tmp, j->label);
}
}
@@ -1483,6 +1503,7 @@
}
total_children--;
+ j->last_exit_status = status;
j->p = 0;
}
@@ -1539,8 +1560,8 @@
startnow = false;
}
}
- } else if (kev->filter == EVFILT_TIMER && kev->fflags & NOTE_ABSOLUTE) {
- job_set_alarm(j);
+ } else if (kev->filter == EVFILT_TIMER && (void *)kev->ident == j->start_cal_interval) {
+ job_set_alarm(j);
} else if (kev->filter == EVFILT_VNODE) {
size_t i;
const char *thepath = NULL;
@@ -1606,6 +1627,7 @@
}
}
+
static void job_start(struct jobcb *j)
{
int spair[2];
@@ -2416,43 +2438,48 @@
* 1 5 4 4
* 5 1 -4 7 + -4
*/
- if (delta > 0)
- otherlatertm.tm_mday += delta;
- else if (delta < 0)
- otherlatertm.tm_mday += 7 + delta;
- else if (-1 != j->start_cal_interval->tm_hour && otherlatertm.tm_hour <= nowtm->tm_hour)
- otherlatertm.tm_mday += 7;
- else if (-1 != j->start_cal_interval->tm_min && otherlatertm.tm_min <= nowtm->tm_min)
- otherlatertm.tm_hour++;
- else
- otherlatertm.tm_min++;
+ if (delta > 0) {
+ otherlatertm.tm_mday += delta;
+ } else if (delta < 0) {
+ otherlatertm.tm_mday += 7 + delta;
+ } else if (-1 != j->start_cal_interval->tm_hour && otherlatertm.tm_hour <= nowtm->tm_hour) {
+ otherlatertm.tm_mday += 7;
+ } else if (-1 != j->start_cal_interval->tm_min && otherlatertm.tm_min <= nowtm->tm_min) {
+ otherlatertm.tm_hour++;
+ } else {
+ otherlatertm.tm_min++;
+ }
- otherlater = mktime(&otherlatertm);
+ otherlater = mktime(&otherlatertm);
}
- if (-1 != j->start_cal_interval->tm_mon && latertm.tm_mon <= nowtm->tm_mon) {
- latertm.tm_year++;
- } else if (-1 != j->start_cal_interval->tm_mday && latertm.tm_mday <= nowtm->tm_mday) {
- latertm.tm_mon++;
- } else if (-1 != j->start_cal_interval->tm_hour && latertm.tm_hour <= nowtm->tm_hour) {
- latertm.tm_mday++;
- } else if (-1 != j->start_cal_interval->tm_min && latertm.tm_min <= nowtm->tm_min) {
- latertm.tm_hour++;
- } else {
- latertm.tm_min++;
- }
+ if (-1 != j->start_cal_interval->tm_mon && latertm.tm_mon <= nowtm->tm_mon) {
+ latertm.tm_year++;
+ } else if (-1 != j->start_cal_interval->tm_mday && latertm.tm_mday <= nowtm->tm_mday) {
+ latertm.tm_mon++;
+ } else if (-1 != j->start_cal_interval->tm_hour && latertm.tm_hour <= nowtm->tm_hour) {
+ latertm.tm_mday++;
+ } else if (-1 != j->start_cal_interval->tm_min && latertm.tm_min <= nowtm->tm_min) {
+ latertm.tm_hour++;
+ } else {
+ latertm.tm_min++;
+ }
+
+ later = mktime(&latertm);
- later = mktime(&latertm);
+ if (otherlater) {
+ if (-1 != j->start_cal_interval->tm_mday)
+ later = later < otherlater ? later : otherlater;
+ else
+ later = otherlater;
+ }
- if (otherlater) {
- if (-1 != j->start_cal_interval->tm_mday)
- later = later < otherlater ? later : otherlater;
- else
- later = otherlater;
- }
+ if (-1 == kevent_mod((uintptr_t)j->start_cal_interval, EVFILT_TIMER, EV_ADD, NOTE_ABSOLUTE|NOTE_SECONDS, later, &j->kqjob_callback)) {
+ job_log_error(j, LOG_ERR, "adding kevent alarm");
+ } else {
+ job_log(j, LOG_INFO, "scheduled to run again at %s", ctime(&later));
+ }
- if (-1 == kevent_mod((uintptr_t)j->start_cal_interval, EVFILT_TIMER, EV_ADD, NOTE_ABSOLUTE|NOTE_SECONDS, later, &j->kqjob_callback))
- job_log_error(j, LOG_ERR, "adding kevent alarm");
}
static void job_log_error(struct jobcb *j, int pri, const char *msg, ...)
More information about the p4-projects
mailing list