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