PERFORCE change 86162 for review
soc-tyler
soc-tyler at FreeBSD.org
Tue Nov 1 02:29:34 PST 2005
http://perforce.freebsd.org/chv.cgi?CH=86162
Change 86162 by soc-tyler at 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) <<<
More information about the p4-projects
mailing list