Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 1 Nov 2005 10:29:32 GMT
From:      soc-tyler <soc-tyler@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 86162 for review
Message-ID:  <200511011029.jA1ATWtq043273@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=86162

Change 86162 by soc-tyler@soc-tyler_launchd on 2005/11/01 10:28:46

	Start merging changes from most recent tarball from zarzycki@
	(launchd-117.tar.gz to be linked to from wiki) 
	
	Untested as of yet, merging changes as close to Darwin's launchd
	as to help backward compatibility and future vendor source code updates

Affected files ...

.. //depot/projects/soc2005/launchd/includes/launch.h#14 edit
.. //depot/projects/soc2005/launchd/includes/launch_priv.h#4 edit
.. //depot/projects/soc2005/launchd/includes/launchd.h#11 edit
.. //depot/projects/soc2005/launchd/includes/launchd_core_logic.h#1 add
.. //depot/projects/soc2005/launchd/includes/launchd_unix_ipc.h#1 add
.. //depot/projects/soc2005/launchd/includes/pathnames.h#3 edit
.. //depot/projects/soc2005/launchd/launchd.c#25 edit
.. //depot/projects/soc2005/launchd/launchd_core_logic.c#1 add
.. //depot/projects/soc2005/launchd/launchd_unix_ipc.c#1 add
.. //depot/projects/soc2005/launchd/liblaunch.c#16 edit

Differences ...

==== //depot/projects/soc2005/launchd/includes/launch.h#14 (text+ko) ====


==== //depot/projects/soc2005/launchd/includes/launch_priv.h#4 (text+ko) ====

@@ -25,12 +25,15 @@
 
 #include <sys/types.h>
 
+#define LAUNCH_JOBKEY_FIRSTBORN			"FirstBorn"
+
 #define LAUNCH_KEY_GETUSERENVIRONMENT           "GetUserEnvironment"
 #define LAUNCH_KEY_SETUSERENVIRONMENT           "SetUserEnvironment"
 #define LAUNCH_KEY_UNSETUSERENVIRONMENT         "UnsetUserEnvironment"
 #define LAUNCH_KEY_SETSTDOUT                    "SetStandardOut"
 #define LAUNCH_KEY_SETSTDERR                    "SetStandardError"
-#define LAUNCH_KEY_SHUTDOWN                     "Shutdown"
+#define LAUNCH_KEY_SHUTDOWN			"Shutdown"
+#define LAUNCH_KEY_SINGLEUSER			"SingleUser"
 #define LAUNCH_KEY_GETRESOURCELIMITS            "GetResourceLimits"
 #define LAUNCH_KEY_SETRESOURCELIMITS            "SetResourceLimits"
 #define LAUNCH_KEY_RELOADTTYS                   "ReloadTTYS"

==== //depot/projects/soc2005/launchd/includes/launchd.h#11 (text+ko) ====

@@ -35,13 +35,31 @@
 #include <sys/event.h>
 #include <sys/time.h>
 
+/*
+ * Use launchd_assumes() when we can recover, even if it means we leak or limp along.
+ *
+ * Use launchd_assert() for core initialization routines.
+ */
+#define launchd_assumes(e)	\
+	(__builtin_expect(!(e), 0) ? syslog(LOG_NOTICE, "Please file a bug report: %s:%u in %s(): (%s) == %u", __FILE__, __LINE__, __func__, #e, errno), false : true)
+
+#define launchd_assert(e)	launchd_assumes(e) ? true : abort();
+
+#define PID1_REAP_ADOPTED_CHILDREN
+
+struct kevent;
+struct conncb;
+
 typedef void (*kq_callback)(void *, struct kevent *);
 
 extern kq_callback kqsimple_zombie_reaper;
-extern sigset_t blocked_signals;
+extern uint32_t blocked_signals;
+extern bool shutdown_in_progress;
+extern int batch_disabler_count;
 
 #ifdef PID1_REAP_ADOPTED_CHILDREN
 extern int pid1_child_exit_status;
+bool init_check_pid(pid_t);
 #endif
 
 int kevent_mod(uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t data, void *udata);
@@ -54,9 +72,19 @@
 void clean_ttys(void);
 void catatonia(void);
 void death(void);
-/* </init.c> */
+
+void batch_job_enable(bool e, struct conncb *c);
+
+launch_data_t launchd_setstdio(int d, launch_data_t o);
+void launchd_SessionCreate(void);
+void launchd_shutdown(void);
+void launchd_single_user(void);
+pid_t launchd_fork(void);
+pid_t launchd_ws_fork(void);
+int _fd(int fd);
 
 #ifdef _BUILD_DARWIN_
+boolean_t launchd_mach_ipc_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply);
 extern mach_port_t launchd_bootstrap_port;
 void launchd_SessionCreate(const char *who);
 #endif

==== //depot/projects/soc2005/launchd/includes/pathnames.h#3 (text+ko) ====


==== //depot/projects/soc2005/launchd/launchd.c#25 (text+ko) ====

@@ -32,13 +32,7 @@
 #include <Security/Authorization.h>
 #include <Security/AuthorizationTags.h>
 #include <Security/AuthSession.h>
-
-#ifdef EVFILT_MACH_IMPLEMENTED
-#include <mach/mach_error.h>
-#include <mach/port.h>
-#endif
 #endif
-
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/event.h>
@@ -56,226 +50,143 @@
 #include <sys/ioctl.h>
 #include <sys/mount.h>
 #include <net/if.h>
+#include <netinet/in.h>
 #include <net/if_var.h>
-#include <netinet/in.h>
 #include <netinet/in_var.h>
 #include <netinet6/nd6.h>
 #include <unistd.h>
 #include <signal.h>
 #include <errno.h>
+#include <pthread.h>
 #include <syslog.h>
 #include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <stdbool.h>
-#include <string.h>
-#include <pthread.h>
 #include <paths.h>
 #include <pwd.h>
 #include <grp.h>
+#include <ttyent.h>
 #include <dlfcn.h>
 #include <dirent.h>
+#include <string.h>
 
 #include "launch.h"
 #include "launch_priv.h"
 #include "launchd.h"
-
-#ifdef _BUILD_DARWIN_
-#include "bootstrap_internal.h"
-#endif
+#include "launchd_core_logic.h"
+#include "launchd_unix_ipc.h"
 
-#define LAUNCHD_MIN_JOB_RUN_TIME 10
-#define LAUNCHD_REWARD_JOB_RUN_TIME 60
-#define LAUNCHD_FAILED_EXITS_THRESHOLD 10
 #define PID1LAUNCHD_CONF "/etc/launchd.conf"
 #define LAUNCHD_CONF ".launchd.conf"
-
-#ifdef _BUILD_DARWIN_
+#ifndef LAUNCHCTL_PATH
+#define LAUNCHCTL_PATH "/bin/launchctl"
+#endif
 #define SECURITY_LIB "/System/Library/Frameworks/Security.framework/Versions/A/Security"
 #define VOLFSDIR "/.vol"
-#endif
 
 extern char **environ;
 
-//! launchd's job callback datastruct
-/*!
- * this structure contains all the necessary data for one of the job callbacks
- * such as the PID, the kqueue callback (kq_callback)
- */
-struct jobcb {
-	kq_callback kqjob_callback;
-	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;
-	int *vnodes;
-	size_t vnodes_cnt;
-	int *qdirs;
-	size_t qdirs_cnt;
-	unsigned int start_interval;
-	struct tm *start_cal_interval;
-	unsigned int checkedin:1, firstborn:1, debug:1, throttle:1, futureflags:28;
-	char label[0];
-};
-
-//! launchd's socket connection callback
-/*!
- * this structure contains the basic data needed for our unix socket 
- * connections that we create to communicate with launchctl via 
- * "liblaunch"
- */
-struct conncb {
-	kq_callback kqconn_callback;
-	TAILQ_ENTRY(conncb) tqe;
-	launch_t conn;
-	struct jobcb *j;
-	int disabled_batch:1, futureflags:31;
-};
-
-static TAILQ_HEAD(jobcbhead, jobcb) jobs = TAILQ_HEAD_INITIALIZER(jobs);
-static TAILQ_HEAD(conncbhead, conncb) connections = TAILQ_HEAD_INITIALIZER(connections);
-static int mainkq = 0;
-static int asynckq = 0;
-static int batch_disabler_count = 0;
-
-static launch_data_t load_job(launch_data_t pload);
-static launch_data_t get_jobs(const char *which);
-static launch_data_t setstdio(int d, launch_data_t o);
-static launch_data_t adjust_rlimits(launch_data_t in);
-static void batch_job_enable(bool e, struct conncb *c);
-static void do_shutdown(void);
-
-static void listen_callback(void *, struct kevent *);
 static void async_callback(void);
 static void signal_callback(void *, struct kevent *);
 static void fs_callback(void);
-static void simple_zombie_reaper(void *, struct kevent *);
 static void readcfg_callback(void *, struct kevent *);
 
-static kq_callback kqlisten_callback = listen_callback;
 static kq_callback kqasync_callback = (kq_callback)async_callback;
 static kq_callback kqsignal_callback = signal_callback;
 static kq_callback kqfs_callback = (kq_callback)fs_callback;
 static kq_callback kqreadcfg_callback = readcfg_callback;
-kq_callback kqsimple_zombie_reaper = simple_zombie_reaper;
-
-static void job_watch(struct jobcb *j);
-static void job_ignore(struct jobcb *j);
-static void job_start(struct jobcb *j);
-static void job_start_child(struct jobcb *j, int execfd);
-static void job_setup_attributes(struct jobcb *j);
-static void job_stop(struct jobcb *j);
-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)));
-
-static void ipc_open(int fd, struct jobcb *j);
-static void ipc_close(struct conncb *c);
-static void ipc_callback(void *, struct kevent *);
-static void ipc_readmsg(launch_data_t msg, void *context);
-static void ipc_readmsg2(launch_data_t data, const char *cmd, void *context);
+static kq_callback kqshutdown_callback = (kq_callback)launchd_shutdown;
 
 #ifdef PID1_REAP_ADOPTED_CHILDREN
 static void pid1waitpid(void);
-static bool launchd_check_pid(pid_t p);
 #endif
 static void pid1_magic_init(bool sflag, bool vflag, bool xflag);
-static void launchd_server_init(bool create_session);
-static void conceive_firstborn(char *argv[]);
+static struct jobcb *conceive_firstborn(char *argv[], const char *session_user);
 
 static void usage(FILE *where);
-static int _fd(int fd);
 
 static void loopback_setup(void);
+static void workaround3048875(int argc, char *argv[]);
+static void testfd_or_openfd(int fd, const char *path, int flags);
 static void reload_launchd_config(void);
-static int dir_has_files(const char *path);
-static void setup_job_env(launch_data_t obj, const char *key, void *context);
-static void unsetup_job_env(launch_data_t obj, const char *key, void *context);
 
-
-static size_t total_children = 0;
+static int mainkq = 0;
+static int asynckq = 0;
 static pid_t readcfg_pid = 0;
-static pid_t launchd_proper_pid = 0;
-static bool launchd_inited = false;
-static bool shutdown_in_progress = false;
+static bool re_exec_in_single_user_mode = false;
+static char *pending_stdout = NULL;
+static char *pending_stderr = NULL;
+static struct jobcb *fbj = NULL;
 
-sigset_t blocked_signals;
-
+/* Darwin's sigset_t datatype is a simple uint32_t */
 #ifdef _BUILD_DARWIN_
-
-#ifdef EVFILT_MACH_IMPLEMENTED
-static void *mach_demand_loop(void *);
-static void mach_callback(void *, struct kevent *);
-static kq_callback kqmach_callback = mach_callback;
+sigset_t blocked_signals = 0;
+#else 
+/* FreeBSD's is a struct */
+uint32_t blocked_signals = 0;
 #endif
+bool shutdown_in_progress = false;
+int batch_disabler_count = 0;
 
-// workaround for an OpenFirmware and Darwin kernel bug
-static void workaround3048875(int argc, char *argv[]);
-static pthread_t mach_server_loop_thread;
-mach_port_t launchd_bootstrap_port = MACH_PORT_NULL;
-blocked_signals = 0;
-#endif
-
-static char *pending_stdout = NULL;
-static char *pending_stderr = NULL;
-
-int main(int argc, char *argv[]) {
+int main(int argc, char *argv[])
+{
 	static const int sigigns[] = { SIGHUP, SIGINT, SIGPIPE, SIGALRM,
 		SIGTERM, SIGURG, SIGTSTP, SIGTSTP, SIGCONT, /*SIGCHLD,*/
 		SIGTTIN, SIGTTOU, SIGIO, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF,
-		SIGWINCH, SIGINFO, SIGUSR1, SIGUSR2 };
-	void testfd_or_openfd(int fd, const char *path, int flags) {
-		int tmpfd;
-
-		if (-1 != (tmpfd = dup(fd))) {
-			close(tmpfd);
-		} else {
-			if (-1 == (tmpfd = open(path, flags))) {
-				syslog(LOG_ERR, "open(\"%s\", ...): %m", path);
-			} else if (tmpfd != fd) {
-				dup2(tmpfd, fd);
-				close(tmpfd);
-			}
-		}
+		SIGWINCH, SIGINFO, SIGUSR1, SIGUSR2
 	};
+	bool sflag = false, xflag = false, vflag = false, dflag = false;
+	const char *session_type = NULL;
+	const char *session_user = NULL;
+	const char *optargs = NULL;
 	struct kevent kev;
 	size_t i;
-	bool sflag = false, xflag = false, vflag = false, dflag = false;
-	int ch;
+	int ch, ker;
+
+	/* main() phase one: sanitize the process */
 
-// workaround for that nasty OpenFirmware bug, zoinks!
-#ifdef _BUILD_DARWIN_
-	if (getpid() == 1)
+	if (getpid() == 1) {
 		workaround3048875(argc, argv);
-#endif
+	} else {
+		int sigi, fdi, dts = getdtablesize();
+		sigset_t emptyset;
 
-	setegid(getgid());
-	seteuid(getuid());
+		for (fdi = STDERR_FILENO + 1; fdi < dts; fdi++)
+			launchd_assumes(close(fdi) == 0);
+		for (sigi = 1; sigi < NSIG; sigi++)
+			launchd_assumes(signal(sigi, SIG_DFL) != SIG_ERR);
+		sigemptyset(&emptyset);
+		launchd_assumes(sigprocmask(SIG_SETMASK, &emptyset, NULL) == 0);
+	}
 
 	testfd_or_openfd(STDIN_FILENO, _PATH_DEVNULL, O_RDONLY);
 	testfd_or_openfd(STDOUT_FILENO, _PATH_DEVNULL, O_WRONLY);
 	testfd_or_openfd(STDERR_FILENO, _PATH_DEVNULL, O_WRONLY);
 
-	openlog(getprogname(), LOG_CONS|(getpid() != 1 ? LOG_PID|LOG_PERROR : 0), LOG_LAUNCHD);
-	setlogmask(LOG_UPTO(LOG_NOTICE));
-	
-	while ((ch = getopt(argc, argv, "dhsvx")) != -1) {
+	/* main phase two: parse arguments */
+
+	if (getpid() == 1) {
+		optargs = "svx";
+	} else if (getuid() == 0) {
+		optargs = "S:U:dh";
+	} else {
+		optargs = "dh";
+	}
+
+	while ((ch = getopt(argc, argv, optargs)) != -1) {
 		switch (ch) {
-		case 'd': dflag = true;   break;
-		case 's': sflag = true;   break;
-		case 'x': xflag = true;   break;
-		case 'v': vflag = true;   break;
-		case 'h': usage(stdout);  break;
+		case 'S': session_type = optarg; break;	/* what type of session we're creating */
+		case 'U': session_user = optarg; break;	/* which user to create a session as */
+		case 'd': dflag = true;   break;	/* daemonize */
+		case 's': sflag = true;   break;	/* single user */
+		case 'x': xflag = true;   break;	/* safe boot */
+		case 'v': vflag = true;   break;	/* verbose boot */
+		case 'h': usage(stdout);  break;	/* help */
+		case '?': /* we should do something with the global optopt variable here */
 		default:
-			syslog(LOG_WARNING, "ignoring unknown arguments");
+			fprintf(stderr, "ignoring unknown arguments\n");
 			usage(stderr);
 			break;
 		}
@@ -283,121 +194,149 @@
 	argc -= optind;
 	argv += optind;
 
-	if (dflag && daemon(0, 0) == -1)
-		syslog(LOG_WARNING, "couldn't daemonize: %m");
+	if ((session_type && !session_user) || (!session_user && session_type)) {
+		fprintf(stderr, "-S and -U must be used together\n");
+		exit(EXIT_FAILURE);
+	}
+
+	/* main phase three: if we need to become a user, do so ASAP */
+	
+	if (session_user) {
+		struct passwd *pwe = getpwnam(session_user);
+		uid_t u = pwe ? pwe->pw_uid : 0;
+		gid_t g = pwe ? pwe->pw_gid : 0;
+		
+		if (pwe == NULL) {
+			fprintf(stderr, "lookup of user %s failed!\n", session_user);
+			exit(EXIT_FAILURE);
+		}
+
+		launchd_assert(initgroups(session_user, g) != -1);
+
+		launchd_assert(setgid(g) != -1);
 
-	if ((mainkq = kqueue()) == -1) {
-		syslog(LOG_EMERG, "kqueue(): %m");
-		abort();
+		launchd_assert(setuid(u) != -1);
 	}
 
-	if ((asynckq = kqueue()) == -1) {
-		syslog(LOG_ERR, "kqueue(): %m");
-		abort();
-	}
+	/* main phase four: get the party started */
+
+	if (dflag)
+		launchd_assumes(daemon(0, 0) == 0);
+
+	openlog(getprogname(), LOG_CONS|(getpid() != 1 ? LOG_PID|LOG_PERROR : 0), LOG_LAUNCHD);
+	setlogmask(LOG_UPTO(LOG_NOTICE));
+
+	launchd_assert((mainkq = kqueue()) != -1);
+
+	launchd_assert((asynckq = kqueue()) != -1);
 	
-	if (kevent_mod(asynckq, EVFILT_READ, EV_ADD, 0, 0, &kqasync_callback) == -1) {
-		syslog(LOG_ERR, "kevent_mod(asynckq, EVFILT_READ): %m");
-		abort();
-	}
+	launchd_assert(kevent_mod(asynckq, EVFILT_READ, EV_ADD, 0, 0, &kqasync_callback) != -1);
 
 	sigemptyset(&blocked_signals);
 
 	for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
-		if (kevent_mod(sigigns[i], EVFILT_SIGNAL, EV_ADD, 0, 0, &kqsignal_callback) == -1)
-			syslog(LOG_ERR, "failed to add kevent for signal: %d: %m", sigigns[i]);
+		launchd_assumes(kevent_mod(sigigns[i], EVFILT_SIGNAL, EV_ADD, 0, 0, &kqsignal_callback) != -1);
 		sigaddset(&blocked_signals, sigigns[i]);
-		signal(sigigns[i], SIG_IGN);
+		launchd_assumes(signal(sigigns[i], SIG_IGN) != SIG_ERR);
 	}
 
 	/* sigh... ignoring SIGCHLD has side effects: we can't call wait*() */
-	if (kevent_mod(SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, &kqsignal_callback) == -1)
-		syslog(LOG_ERR, "failed to add kevent for signal: %d: %m", SIGCHLD);
-	
+	launchd_assert(kevent_mod(SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, &kqsignal_callback) != -1);
+
+#ifdef _BUILD_DARWIN_
+	mach_init_init();
+#endif
+
+	if (argv[0] || (session_type != NULL && 0 == strcasecmp(session_type, "tty")))
+		fbj = conceive_firstborn(argv, session_user);
+
+	if (NULL == getenv("PATH"))
+		setenv("PATH", _PATH_STDPATH, 1);
+
 	if (getpid() == 1) {
 		pid1_magic_init(sflag, vflag, xflag);
 	} else {
-#ifdef _BUILD_DARWIN_	
-		launchd_bootstrap_port = bootstrap_port;
-#endif
-	/* 
-	 * launchd_server_init() is called now if we're not assuming PID 1, 
-	 * i.e. all filesystems are mounted and marked rw; otherwise, we call
-	 * launchd_server_init() from fs_callback() 
-	 */
-		launchd_server_init(argv[0] ? true : false);
+		ipc_server_init();
 	}
 
-	/* this registers for the kqfs_callback (fs_callback()) function to be 
-	 * called when the mount table is updated, so we can call some PID 1 stuff */
-	 
 	/* do this after pid1_magic_init() to not catch ourselves mounting stuff */
-	if (kevent_mod(0, EVFILT_FS, EV_ADD, 0, 0, &kqfs_callback) == -1)
-		syslog(LOG_ERR, "kevent_mod(EVFILT_FS, &kqfs_callback): %m");
+	launchd_assumes(kevent_mod(0, EVFILT_FS, EV_ADD, 0, 0, &kqfs_callback) != -1);
+
+	if (session_type) {
+		pid_t pp = getppid();
+
+		/* As a per session launchd, we need to exit if our parent dies.
+		 *
+		 * Normally, in Unix, SIGHUP would cause us to exit, but we're a
+		 * daemon, and daemons use SIGHUP to signal the need to reread
+		 * configuration files. "Weee."
+		 */
+
+		if (pp == 1)
+			exit(EXIT_SUCCESS);
 
+		ker = kevent_mod(pp, EVFILT_PROC, EV_ADD, 0, 0, &kqshutdown_callback);
 
-	if (argv[0])
-		conceive_firstborn(argv);
+		if (ker == -1)
+			exit(launchd_assumes(errno == ESRCH) ? EXIT_SUCCESS : EXIT_FAILURE);
+	}
 
 	reload_launchd_config();
 
-	if (argv[0])
-		job_start(TAILQ_FIRST(&jobs));
+	if (fbj)
+		job_start(fbj);
 
 	for (;;) {
-		static struct timespec timeout = { 30, 0 };
-		struct timespec *timeoutp = NULL;
+		if (getpid() == 1 && readcfg_pid == 0)
+			init_pre_kevent();
+
+		if (shutdown_in_progress && total_children == 0) {
+			job_remove_all();
+#ifdef _BUILD_DARWIN_
+			mach_init_reap();
+#endif
+
+			shutdown_in_progress = false;
 
-		if (getpid() == 1) {
-			if (readcfg_pid == 0)
-				init_pre_kevent();
-		} else {
-			/* in theory, this will make sure we don't exit if we
-			 * have (a) any more jobs nd (b) open socket connections
-			 * to say, something like, launchctl? ;)
-			 */
-			if (TAILQ_EMPTY(&jobs) && TAILQ_EMPTY(&connections)) {
-				/* liblaunch will restart us if we're needed again */
-				timeoutp = &timeout;
-			} else if (shutdown_in_progress && total_children == 0) {
+			if (getpid() != 1) {
 				exit(EXIT_SUCCESS);
+			} else if (re_exec_in_single_user_mode) {
+				re_exec_in_single_user_mode = false;
+				launchd_assumes(execl("/sbin/launchd", "/sbin/launchd", "-s", NULL) != -1);
 			}
 		}
-		
-		switch (kevent(mainkq, NULL, 0, &kev, 1, timeoutp)) {
-			case -1:
-				syslog(LOG_DEBUG, "kevent(): %m");
-				break;
-			case 1:
-				(*((kq_callback *)kev.udata))(kev.udata, &kev);
-				break;
-			case 0:
-				/* we exit here if and once we're done processing all jobs
-				 * assigned to us
-				 */
-				if (timeoutp)
-					exit(EXIT_SUCCESS);
-				else
-					syslog(LOG_DEBUG, "kevent(): spurious return with infinite timeout");
-				break;
-			default:
-				syslog(LOG_DEBUG, "unexpected: kevent() returned something != 0, -1 or 1");
-				break;
-		}
+
+		if (launchd_assumes(kevent(mainkq, NULL, 0, &kev, 1, NULL) == 1))
+			(*((kq_callback *)kev.udata))(kev.udata, &kev);
 	}
 }
 
 static void pid1_magic_init(bool sflag, bool vflag, bool xflag)
 {
-	int memmib[2] = { CTL_HW, HW_PHYSMEM };
+#ifdef _BUILD_DARWIN_
+	int memmib[2] = { CTL_HW, HW_MEMSIZE };
+#else
+	int memmib[2] = { CTL_HW, HW_REALMEM };
+#endif
 	int mvnmib[2] = { CTL_KERN, KERN_MAXVNODES };
 	int hnmib[2] = { CTL_KERN, KERN_HOSTNAME };
 	uint64_t mem = 0;
 	uint32_t mvn;
 	size_t memsz = sizeof(mem);
-#ifdef _BUILD_DARWIN_
-	pthread_attr_t attr;
-	int pthr_r;
+#ifdef KERN_TFP
+	struct group *tfp_gr;
+		
+	if (launchd_assumes((tfp_gr = getgrnam("procview")) != NULL)) {
+		int tfp_r_mib[3] = { CTL_KERN, KERN_TFP, KERN_TFP_READ_GROUP };
+		gid_t tfp_r_gid = tfp_gr->gr_gid;
+		launchd_assumes(sysctl(tfp_r_mib, 3, NULL, NULL, &tfp_r_gid, sizeof(tfp_r_gid)) != -1);
+	}
+
+	if (launchd_assumes((tfp_gr = getgrnam("procmod")) != NULL)) {
+		int tfp_rw_mib[3] = { CTL_KERN, KERN_TFP, KERN_TFP_RW_GROUP };
+		gid_t tfp_rw_gid = tfp_gr->gr_gid;
+		launchd_assumes(sysctl(tfp_rw_mib, 3, NULL, NULL, &tfp_rw_gid, sizeof(tfp_rw_gid)) != -1);
+	}
 #endif
 
 	setpriority(PRIO_PROCESS, 0, -1);
@@ -411,1547 +350,141 @@
 	if (sysctl(memmib, 2, &mem, &memsz, NULL, 0) == -1) {
 		syslog(LOG_WARNING, "sysctl(\"%s\"): %m", "hw.physmem");
 	} else {
-		/* The following assignment of mem to itself if the size
-		 * of data returned is 32 bits instead of 64 is a clever
-		 * C trick to move the 32 bits on big endian systems to
-		 * the least significant bytes of the 64 mem variable.
-		 *
-		 * On little endian systems, this is effectively a no-op.
-		 */
-		if (memsz == 4)
-			mem = *(uint32_t *)&mem;
 		mvn = mem / (64 * 1024) + 1024;
-		
-		// Performance note: change the max # of vnodes
 		if (sysctl(mvnmib, 2, NULL, NULL, &mvn, sizeof(mvn)) == -1)
 			syslog(LOG_WARNING, "sysctl(\"%s\"): %m", "kern.maxvnodes");
 	}
-	
-	// Performance note: set our hostname to localhost for now
 	if (sysctl(hnmib, 2, NULL, NULL, "localhost", sizeof("localhost")) == -1)
 		syslog(LOG_WARNING, "sysctl(\"%s\"): %m", "kern.hostname");
 
 	if (setlogin("root") == -1)
 		syslog(LOG_ERR, "setlogin(\"root\"): %m");
-	
-	// Performance note: setup our loopback interface inline
+
 	loopback_setup();
 
 	if (mount("fdesc", "/dev", MNT_UNION, NULL) == -1)
 		syslog(LOG_ERR, "mount(\"%s\", \"%s\", ...): %m", "fdesc", "/dev/");
 
-	setenv("PATH", _PATH_STDPATH, 1);
-#ifdef _BUILD_DARWIN_
-	launchd_bootstrap_port = mach_init_init();
-	task_set_bootstrap_port(mach_task_self(), launchd_bootstrap_port);
-	bootstrap_port = MACH_PORT_NULL;
-
-	pthread_attr_init(&attr);
-	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-	
-	pthr_r = pthread_create(&mach_server_loop_thread, &attr, mach_server_loop, NULL);
-	if (pthr_r != 0) {
-		syslog(LOG_ERR, "pthread_create(mach_server_loop): %s", strerror(pthr_r));
-		exit(EXIT_FAILURE);
-	}
-	
-	pthread_attr_destroy(&attr);
-#endif
-
 	init_boot(sflag, vflag, xflag);
 }
 
-#ifdef PID1_REAP_ADOPTED_CHILDREN
-static bool launchd_check_pid(pid_t p)
-{
-	struct kevent kev;
-	struct jobcb *j;
 
-	TAILQ_FOREACH(j, &jobs, tqe) {
-		if (j->p == p) {
-			EV_SET(&kev, p, EVFILT_PROC, 0, 0, 0, j);
-			j->kqjob_callback(j, &kev);
-			return true;
-		}
-	}
-
-	if (p == readcfg_pid) {
-		readcfg_callback(NULL, NULL);
-		return true;
-	}
-
-	return false;
-}
-#endif
-
-static char *sockdir = NULL;
-static char *sockpath = NULL;
-
-static void launchd_clean_up(void)
+void usage(FILE *where)
 {
-	seteuid(0);
-	setegid(0);
+	const char *opts = "[-d]";
 
-	if (-1 == unlink(sockpath))
-		syslog(LOG_WARNING, "unlink(\"%s\"): %m", sockpath);
-	else if (-1 == rmdir(sockdir))
-		syslog(LOG_WARNING, "rmdir(\"%s\"): %m", sockdir);
+	if (getuid() == 0)
+		opts = "[-d] [-S <type> -U <user>]";
 
-	setegid(getgid());
-	seteuid(getuid());
-}
+	fprintf(where, "%s: %s [-- command [args ...]]\n", getprogname(), opts);
 
-static void launchd_server_init(bool create_session)
-{
-	struct sockaddr_un sun;
-	mode_t oldmask;
-	int r, fd = -1, ourdirfd = -1;
-	char ourdir[1024];
+	fprintf(where, "\t-d          Daemonize.\n");
+	fprintf(where, "\t-h          This usage statement.\n");
 
-	memset(&sun, 0, sizeof(sun));
-	sun.sun_family = AF_UNIX;
-
-	if (create_session) {
-		snprintf(ourdir, sizeof(ourdir), "%s/%u.%u", LAUNCHD_SOCK_PREFIX, getuid(), getpid());
-		snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%u.%u/sock", LAUNCHD_SOCK_PREFIX, getuid(), getpid());
-		setenv(LAUNCHD_SOCKET_ENV, sun.sun_path, 1);
-	} else {
-		snprintf(ourdir, sizeof(ourdir), "%s/%u", LAUNCHD_SOCK_PREFIX, getuid());
-		snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%u/sock", LAUNCHD_SOCK_PREFIX, getuid());
-	}
-
-	seteuid(0);
-	setegid(0);
-
-	if (mkdir(LAUNCHD_SOCK_PREFIX, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) == -1) {
-		if (errno == EROFS) {
-			goto out_bad;
-		} else if (errno == EEXIST) {
-			struct stat sb;
-			stat(LAUNCHD_SOCK_PREFIX, &sb);
-			if (!S_ISDIR(sb.st_mode)) {
-				errno = EEXIST;
-				syslog(LOG_ERR, "mkdir(\"%s\"): %m", LAUNCHD_SOCK_PREFIX);
-				goto out_bad;
-			}
-		} else {
-			syslog(LOG_ERR, "mkdir(\"%s\"): %m", LAUNCHD_SOCK_PREFIX);
-			goto out_bad;
-		}
+	if (getuid() == 0) {
+		fprintf(where, "\t-S <type>   What type of session to create (Aqua, tty or X11).\n");
+		fprintf(where, "\t-U <user>   Which user to create the session as.\n");
 	}
 
-	unlink(ourdir);
-	if (mkdir(ourdir, S_IRWXU) == -1) {
-		if (errno == EROFS) {
-			goto out_bad;
-		} else if (errno == EEXIST) {
-			struct stat sb;
-			stat(ourdir, &sb);
-			if (!S_ISDIR(sb.st_mode)) {
-				errno = EEXIST;
-				syslog(LOG_ERR, "mkdir(\"%s\"): %m", LAUNCHD_SOCK_PREFIX);
-				goto out_bad;
-			}
-		} else {
-			syslog(LOG_ERR, "mkdir(\"%s\"): %m", ourdir);
-			goto out_bad;
-		}
-	}
-
-	if (chown(ourdir, getuid(), getgid()) == -1)
-		syslog(LOG_WARNING, "chown(\"%s\"): %m", ourdir);
-
-	setegid(getgid());
-	seteuid(getuid());
-
-	ourdirfd = _fd(open(ourdir, O_RDONLY));
-	if (ourdirfd == -1) {
-		syslog(LOG_ERR, "open(\"%s\"): %m", ourdir);
-		goto out_bad;
-	}
-
-	if (flock(ourdirfd, LOCK_EX|LOCK_NB) == -1) {
-		if (errno == EWOULDBLOCK) {
-			exit(EXIT_SUCCESS);
-		} else {
-			syslog(LOG_ERR, "flock(\"%s\"): %m", ourdir);
-			goto out_bad;
-		}
-	}
-
-	if (unlink(sun.sun_path) == -1 && errno != ENOENT) {
-		if (errno != EROFS)
-			syslog(LOG_ERR, "unlink(\"thesocket\"): %m");
-		goto out_bad;
-	}
-	if ((fd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1) {
-		syslog(LOG_ERR, "socket(\"thesocket\"): %m");
-		goto out_bad;
-	}
-	oldmask = umask(077);
-	r = bind(fd, (struct sockaddr *)&sun, sizeof(sun));
-	umask(oldmask);
-	if (r == -1) {
-		if (errno != EROFS)
-			syslog(LOG_ERR, "bind(\"thesocket\"): %m");
-		goto out_bad;
-	}
-
-	if (listen(fd, SOMAXCONN) == -1) {
-		syslog(LOG_ERR, "listen(\"thesocket\"): %m");
-		goto out_bad;
-	}
-
-	if (kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, &kqlisten_callback) == -1) {
-		syslog(LOG_ERR, "kevent_mod(\"thesocket\", EVFILT_READ): %m");
-		goto out_bad;
-	}
-
-	launchd_inited = true;
-
-	sockdir = strdup(ourdir);
-	sockpath = strdup(sun.sun_path);
-
-	launchd_proper_pid = getpid();
-	atexit(launchd_clean_up);
-
-out_bad:
-	setegid(getgid());
-	seteuid(getuid());
-
-	if (!launchd_inited) {
-		if (fd != -1)
-			close(fd);
-		if (ourdirfd != -1)
-			close(ourdirfd);
-	}
-}
-
-static long long job_get_integer(launch_data_t j, const char *key)
-{
-	launch_data_t t = launch_data_dict_lookup(j, key);
-	if (t)
-		return launch_data_get_integer(t);
-	else
-		return 0;
-}
-
-static const char *job_get_string(launch_data_t j, const char *key)
-{
-	launch_data_t t = launch_data_dict_lookup(j, key);
-	if (t)
-		return launch_data_get_string(t);
-	else
-		return NULL;
-}
-
-static const char *job_get_file2exec(launch_data_t j)
-{
-	launch_data_t tmpi, tmp = launch_data_dict_lookup(j, LAUNCH_JOBKEY_PROGRAM);
-
-	if (tmp) {
-		return launch_data_get_string(tmp);
-	} else {
-		tmp = launch_data_dict_lookup(j, LAUNCH_JOBKEY_PROGRAMARGUMENTS);
-		if (tmp) {
-			tmpi = launch_data_array_get_index(tmp, 0);
-			if (tmpi)
-				return launch_data_get_string(tmpi);
-		}
-		return NULL;
-	}
-}
-
-static bool job_get_bool(launch_data_t j, const char *key)
-{
-	launch_data_t t = launch_data_dict_lookup(j, key);
-	if (t)
-		return launch_data_get_bool(t);
-	else
-		return false;
-}
-
-static void ipc_open(int fd, struct jobcb *j)
-{
-	struct conncb *c = calloc(1, sizeof(struct conncb));
-
-	fcntl(fd, F_SETFL, O_NONBLOCK);
-
-	c->kqconn_callback = ipc_callback;
-	c->conn = launchd_fdopen(fd);
-	c->j = j;
-	TAILQ_INSERT_TAIL(&connections, c, tqe);
-	kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, &c->kqconn_callback);
-}
-
-static void simple_zombie_reaper(void *obj __attribute__((unused)), struct kevent *kev)
-{
-	waitpid(kev->ident, NULL, 0);
-}
-
-static void listen_callback(void *obj __attribute__((unused)), struct kevent *kev)
-{
-	struct sockaddr_un sun;
-	socklen_t sl = sizeof(sun);
-	int cfd;
-
-	if ((cfd = _fd(accept(kev->ident, (struct sockaddr *)&sun, &sl))) == -1) {
-		return;
-	}
-
-	ipc_open(cfd, NULL);
-}
-
-static void ipc_callback(void *obj, struct kevent *kev)
-{
-	struct conncb *c = obj;
-	int r;
-	
-	if (kev->filter == EVFILT_READ) {
-		if (launchd_msg_recv(c->conn, ipc_readmsg, c) == -1 && errno != EAGAIN) {
-			if (errno != ECONNRESET)
-				syslog(LOG_DEBUG, "%s(): recv: %m", __func__);
-			ipc_close(c);
-		}
-	} else if (kev->filter == EVFILT_WRITE) {
-		r = launchd_msg_send(c->conn, NULL);
-		if (r == -1) {
-			if (errno != EAGAIN) {
-				syslog(LOG_DEBUG, "%s(): send: %m", __func__);
-				ipc_close(c);
-			}
-		} else if (r == 0) {
-			kevent_mod(launchd_getfd(c->conn), EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
-		}
-	} else {
-		syslog(LOG_DEBUG, "%s(): unknown filter type!", __func__);
-		ipc_close(c);
-	}
-}
-
-static void set_user_env(launch_data_t obj, const char *key, void *context __attribute__((unused)))
-{
-	setenv(key, launch_data_get_string(obj), 1);
-}
-
-static void launch_data_close_fds(launch_data_t o)
-{
-	size_t i;
-
-	switch (launch_data_get_type(o)) {
-	case LAUNCH_DATA_DICTIONARY:
-		launch_data_dict_iterate(o, (void (*)(launch_data_t, const char *, void *))launch_data_close_fds, NULL);
-		break;
-	case LAUNCH_DATA_ARRAY:
-		for (i = 0; i < launch_data_array_get_count(o); i++)
-			launch_data_close_fds(launch_data_array_get_index(o, i));
-		break;
-	case LAUNCH_DATA_FD:
-		if (launch_data_get_fd(o) != -1)
-			close(launch_data_get_fd(o));
-		break;
-	default:
-		break;
-	}
-}

>>> TRUNCATED FOR MAIL (1000 lines) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200511011029.jA1ATWtq043273>