Revision: 23082 http://trac.macosforge.org/projects/launchd/changeset/23082 Author: zarzycki@apple.com Date: 2007-02-18 18:03:20 -0800 (Sun, 18 Feb 2007) Log Message: ----------- Major changes: 1) init.c is 100% dead. 2) single-user-mode is now a feature of launchctl. 3) The 'jobmgr' concept is better able to self-bootstrap now. 4) Some per process kevents have been moved to the root jobmgr. 5) The user's "background" session is now being bootstrapped. 6) Deleted dead code: launchctl stdout/stderr sub commands. 7) Miscellaneous. Work to be done: 1) Restore launchd.conf functionality. 2) Make jobmgr self-bootstrap atomic WRT bootstrap_look_up(). 3) Self-bootstrap sub jobmgr objects. Modified Paths: -------------- trunk/launchd/src/Makefile.am trunk/launchd/src/Makefile.in trunk/launchd/src/launchctl.1 trunk/launchd/src/launchctl.c trunk/launchd/src/launchd.c trunk/launchd/src/launchd.h trunk/launchd/src/launchd_core_logic.c trunk/launchd/src/launchd_core_logic.h trunk/launchd/src/launchd_runtime.c trunk/launchd/src/launchd_runtime.h trunk/launchd/src/launchd_unix_ipc.c trunk/launchd/src/launchd_unix_ipc.h trunk/launchd/src/liblaunch_private.h trunk/launchd/src/libvproc_public.h Removed Paths: ------------- trunk/launchd/src/init.c Modified: trunk/launchd/src/Makefile.am =================================================================== --- trunk/launchd/src/Makefile.am 2007-02-18 18:48:19 UTC (rev 23081) +++ trunk/launchd/src/Makefile.am 2007-02-19 02:03:20 UTC (rev 23082) @@ -45,7 +45,7 @@ launchd_CFLAGS = -mdynamic-no-pic $(AM_CFLAGS) -Wno-unused-parameter launchd_LDFLAGS = -lbsm -launchd_SOURCES = launchd.c launchd_core_logic.c launchd_unix_ipc.c init.c protocol_vprocServer.c notifyServer.c launchd_internalUser.c launchd_internalServer.c job_replyUser.c launchd_runtime.c +launchd_SOURCES = launchd.c launchd_core_logic.c launchd_unix_ipc.c protocol_vprocServer.c notifyServer.c launchd_internalUser.c launchd_internalServer.c job_replyUser.c launchd_runtime.c launchd_runtime.c:: notifyServer.h launchd_internal.h launchd_core_logic.c:: protocol_vproc.h job_reply.h protocol_vprocServer.h Modified: trunk/launchd/src/Makefile.in =================================================================== --- trunk/launchd/src/Makefile.in 2007-02-18 18:48:19 UTC (rev 23081) +++ trunk/launchd/src/Makefile.in 2007-02-19 02:03:20 UTC (rev 23082) @@ -91,13 +91,12 @@ launchctl_OBJECTS = launchctl-launchctl.$(OBJEXT) launchctl_LDADD = $(LDADD) am__launchd_SOURCES_DIST = launchd.c launchd_core_logic.c \ - launchd_unix_ipc.c init.c protocol_vprocServer.c \ - notifyServer.c launchd_internalUser.c launchd_internalServer.c \ + launchd_unix_ipc.c protocol_vprocServer.c notifyServer.c \ + launchd_internalUser.c launchd_internalServer.c \ job_replyUser.c launchd_runtime.c @LIBS_ONLY_FALSE@am_launchd_OBJECTS = launchd-launchd.$(OBJEXT) \ @LIBS_ONLY_FALSE@ launchd-launchd_core_logic.$(OBJEXT) \ @LIBS_ONLY_FALSE@ launchd-launchd_unix_ipc.$(OBJEXT) \ -@LIBS_ONLY_FALSE@ launchd-init.$(OBJEXT) \ @LIBS_ONLY_FALSE@ launchd-protocol_vprocServer.$(OBJEXT) \ @LIBS_ONLY_FALSE@ launchd-notifyServer.$(OBJEXT) \ @LIBS_ONLY_FALSE@ launchd-launchd_internalUser.$(OBJEXT) \ @@ -244,7 +243,7 @@ @LIBS_ONLY_FALSE@SystemStarter_SOURCES = StartupItems.c IPC.c SystemStarter.c @LIBS_ONLY_FALSE@launchd_CFLAGS = -mdynamic-no-pic $(AM_CFLAGS) -Wno-unused-parameter @LIBS_ONLY_FALSE@launchd_LDFLAGS = -lbsm -@LIBS_ONLY_FALSE@launchd_SOURCES = launchd.c launchd_core_logic.c launchd_unix_ipc.c init.c protocol_vprocServer.c notifyServer.c launchd_internalUser.c launchd_internalServer.c job_replyUser.c launchd_runtime.c +@LIBS_ONLY_FALSE@launchd_SOURCES = launchd.c launchd_core_logic.c launchd_unix_ipc.c protocol_vprocServer.c notifyServer.c launchd_internalUser.c launchd_internalServer.c job_replyUser.c launchd_runtime.c @LIBS_ONLY_FALSE@launchproxy_LDFLAGS = -weak_framework Security @LIBS_ONLY_FALSE@man1_MANS = wait4path.1 launchctl.1 @LIBS_ONLY_FALSE@man5_MANS = launchd.plist.5 launchd.conf.5 @@ -425,7 +424,6 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SystemStarter-StartupItems.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SystemStarter-SystemStarter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchctl-launchctl.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-init.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-job_replyUser.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-launchd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/launchd-launchd_core_logic.Po@am__quote@ @@ -614,20 +612,6 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-launchd_unix_ipc.obj `if test -f 'launchd_unix_ipc.c'; then $(CYGPATH_W) 'launchd_unix_ipc.c'; else $(CYGPATH_W) '$(srcdir)/launchd_unix_ipc.c'; fi` -launchd-init.o: init.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-init.o -MD -MP -MF "$(DEPDIR)/launchd-init.Tpo" -c -o launchd-init.o `test -f 'init.c' || echo '$(srcdir)/'`init.c; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/launchd-init.Tpo" "$(DEPDIR)/launchd-init.Po"; else rm -f "$(DEPDIR)/launchd-init.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='init.c' object='launchd-init.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-init.o `test -f 'init.c' || echo '$(srcdir)/'`init.c - -launchd-init.obj: init.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-init.obj -MD -MP -MF "$(DEPDIR)/launchd-init.Tpo" -c -o launchd-init.obj `if test -f 'init.c'; then $(CYGPATH_W) 'init.c'; else $(CYGPATH_W) '$(srcdir)/init.c'; fi`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/launchd-init.Tpo" "$(DEPDIR)/launchd-init.Po"; else rm -f "$(DEPDIR)/launchd-init.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='init.c' object='launchd-init.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -c -o launchd-init.obj `if test -f 'init.c'; then $(CYGPATH_W) 'init.c'; else $(CYGPATH_W) '$(srcdir)/init.c'; fi` - launchd-protocol_vprocServer.o: protocol_vprocServer.c @am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(launchd_CFLAGS) $(CFLAGS) -MT launchd-protocol_vprocServer.o -MD -MP -MF "$(DEPDIR)/launchd-protocol_vprocServer.Tpo" -c -o launchd-protocol_vprocServer.o `test -f 'protocol_vprocServer.c' || echo '$(srcdir)/'`protocol_vprocServer.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/launchd-protocol_vprocServer.Tpo" "$(DEPDIR)/launchd-protocol_vprocServer.Po"; else rm -f "$(DEPDIR)/launchd-protocol_vprocServer.Tpo"; exit 1; fi Deleted: trunk/launchd/src/init.c =================================================================== --- trunk/launchd/src/init.c 2007-02-18 18:48:19 UTC (rev 23081) +++ trunk/launchd/src/init.c 2007-02-19 02:03:20 UTC (rev 23082) @@ -1,383 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_APACHE_LICENSE_HEADER_START@ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * @APPLE_APACHE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Donn Seeley at Berkeley Software Design, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -static const char *const __rcs_file_version__ = "$Revision$"; - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/param.h> -#include <sys/mount.h> -#include <sys/sysctl.h> -#include <sys/wait.h> -#include <sys/time.h> -#include <sys/resource.h> - -#include <errno.h> -#include <fcntl.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <stdbool.h> -#include <string.h> -#include <syslog.h> -#include <time.h> -#include <ttyent.h> -#include <unistd.h> -#include <paths.h> -#include <util.h> -#include <libgen.h> -#include <paths.h> -#include <termios.h> - -#include "launchd.h" -#include "launchd_runtime.h" - -#define _PATH_RUNCOM "/etc/rc" - -#define STALL_TIMEOUT 30 /* wait N secs after warning */ - -static void stall(char *, ...); - -static void single_user_callback(void *, struct kevent *); -static kq_callback kqsingle_user_callback = single_user_callback; -static void runcom_callback(void *, struct kevent *); -static kq_callback kqruncom_callback = runcom_callback; - -static void single_user(void); -static void runcom(void); - -static bool single_user_mode = false; -static bool run_runcom = true; -static pid_t single_user_pid = 0; -static pid_t runcom_pid = 0; - -static void setctty(const char *, int); - -static void setsecuritylevel(int); -static int getsecuritylevel(void); -static bool should_fsck(void); - -void -init_boot(bool sflag) -{ - if (sflag) { - single_user_mode = true; - run_runcom = false; - } -} - -void -init_pre_kevent(void) -{ - if (single_user_pid || runcom_pid) - return; - - if (single_user_mode) - return single_user(); - - if (run_runcom) - return runcom(); - - /* - * If the administrator has not set the security level to -1 - * to indicate that the kernel should not run multiuser in secure - * mode, and the run script has not set a higher level of security - * than level 1, then put the kernel into secure mode. - */ - if (getsecuritylevel() == 0) { - setsecuritylevel(1); - } -} - -void -stall(char *message, ...) -{ - va_list ap; - va_start(ap, message); - - vsyslog(LOG_ALERT, message, ap); - va_end(ap); - sleep(STALL_TIMEOUT); -} - -int -getsecuritylevel(void) -{ - int name[2], curlevel; - size_t len; - - name[0] = CTL_KERN; - name[1] = KERN_SECURELVL; - len = sizeof (curlevel); - if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) { - syslog(LOG_ALERT, "cannot get kernel security level: %m"); - return -1; - } - return curlevel; -} - -void -setsecuritylevel(int newlevel) -{ - int name[2], curlevel; - - curlevel = getsecuritylevel(); - if (newlevel == curlevel) - return; - name[0] = CTL_KERN; - name[1] = KERN_SECURELVL; - if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) { - syslog(LOG_ALERT, "cannot change kernel security level from %d to %d: %m", - curlevel, newlevel); - return; - } - syslog(LOG_INFO, "kernel security level changed from %d to %d", - curlevel, newlevel); -} - -/* - * Start a session and allocate a controlling terminal. - * Only called by children of init after forking. - */ -void -setctty(const char *name, int flags) -{ - int fd; - - revoke(name); - if ((fd = open(name, flags | O_RDWR)) == -1) { - stall("can't open %s: %m", name); - exit(EXIT_FAILURE); - } - if (login_tty(fd) == -1) { - stall("can't get %s for controlling terminal: %m", name); - exit(EXIT_FAILURE); - } -} - -void -single_user(void) -{ - bool runcom_fsck = should_fsck(); - char *argv[2]; - - if (getsecuritylevel() > 0) - setsecuritylevel(0); - - if ((single_user_pid = launchd_fork()) == -1) { - syslog(LOG_ERR, "can't fork single-user shell, trying again: %m"); - return; - } else if (single_user_pid == 0) { - setctty(_PATH_CONSOLE, O_POPUP); - - setenv("TERM", "vt100", 1); - - if (runcom_fsck) { - fprintf(stdout, "Singleuser boot -- fsck not done\n"); - fprintf(stdout, "Root device is mounted read-only\n\n"); - fprintf(stdout, "If you want to make modifications to files:\n"); - fprintf(stdout, "\t/sbin/fsck -fy\n\t/sbin/mount -uw /\n\n"); - fprintf(stdout, "If you wish to boot the system:\n"); - fprintf(stdout, "\texit\n\n"); - fflush(stdout); - } - - argv[0] = "-sh"; - argv[1] = NULL; - execv(_PATH_BSHELL, argv); - syslog(LOG_ERR, "can't exec %s for single user: %m", _PATH_BSHELL); - sleep(STALL_TIMEOUT); - exit(EXIT_FAILURE); - } else { - if (kevent_mod(single_user_pid, EVFILT_PROC, EV_ADD, - NOTE_EXIT, 0, &kqsingle_user_callback) == -1) - single_user_callback(NULL, NULL); - } -} - -void -single_user_callback(void *obj __attribute__((unused)), struct kevent *kev __attribute__((unused))) -{ - int status; - - if (!launchd_assumes(waitpid(single_user_pid, &status, 0) == single_user_pid)) - return; - - if (WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS) { - syslog(LOG_INFO, "single user shell terminated, restarting"); - run_runcom = true; - single_user_mode = false; - } else { - syslog(LOG_INFO, "single user shell terminated."); - run_runcom = false; - if (WTERMSIG(status) != SIGKILL) - single_user_mode = true; - } - - single_user_pid = 0; -} - -static struct timeval runcom_start_tv = { 0, 0 }; - -/* - * Run the system startup script. - */ -void -runcom(void) -{ - char *argv[] = { "/bin/launchctl", "bootstrap", NULL }; - struct termios term; - int vdisable; - - gettimeofday(&runcom_start_tv, NULL); - - if ((runcom_pid = launchd_fork()) == -1) { - syslog(LOG_ERR, "can't fork for %s on %s: %m", _PATH_BSHELL, _PATH_RUNCOM); - sleep(STALL_TIMEOUT); - runcom_pid = 0; - single_user_mode = true; - return; - } else if (runcom_pid > 0) { - run_runcom = false; - if (kevent_mod(runcom_pid, EVFILT_PROC, EV_ADD, - NOTE_EXIT, 0, &kqruncom_callback) == -1) { - runcom_callback(NULL, NULL); - } - return; - } - - setctty(_PATH_CONSOLE, 0); - - if ((vdisable = fpathconf(STDIN_FILENO, _PC_VDISABLE)) == -1) { - syslog(LOG_WARNING, "fpathconf(\"%s\") %m", _PATH_CONSOLE); - } else if (tcgetattr(STDIN_FILENO, &term) == -1) { - syslog(LOG_WARNING, "tcgetattr(\"%s\") %m", _PATH_CONSOLE); - } else { - term.c_cc[VINTR] = vdisable; - term.c_cc[VKILL] = vdisable; - term.c_cc[VQUIT] = vdisable; - term.c_cc[VSUSP] = vdisable; - term.c_cc[VSTART] = vdisable; - term.c_cc[VSTOP] = vdisable; - term.c_cc[VDSUSP] = vdisable; - - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term) == -1) - syslog(LOG_WARNING, "tcsetattr(\"%s\") %m", _PATH_CONSOLE); - } - - execv(argv[0], argv); - stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNCOM); - exit(EXIT_FAILURE); -} - -void -runcom_callback(void *obj __attribute__((unused)), struct kevent *kev __attribute__((unused))) -{ - int status; - struct timeval runcom_end_tv, runcom_total_tv; - double sec; - - gettimeofday(&runcom_end_tv, NULL); - timersub(&runcom_end_tv, &runcom_start_tv, &runcom_total_tv); - sec = runcom_total_tv.tv_sec; - sec += (double)runcom_total_tv.tv_usec / (double)1000000; - syslog(LOG_INFO, "%s finished in: %.3f seconds", _PATH_RUNCOM, sec); - - if (launchd_assumes(waitpid(runcom_pid, &status, 0) == runcom_pid)) { - runcom_pid = 0; - } else { - syslog(LOG_ERR, "going to single user mode"); - single_user_mode = true; - return; - } - - if (WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS) { - return; - } else if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGTERM || WTERMSIG(status) == SIGKILL)) { - return; - } - - syslog(LOG_ERR, "%s on %s terminated abnormally, going to single user mode", - _PATH_BSHELL, _PATH_RUNCOM); - single_user_mode = true; -} - -bool -init_check_pid(pid_t p) -{ - if (single_user_pid == p) - return true; - - if (runcom_pid == p) - return true; - - return false; -} - -bool -should_fsck(void) -{ - struct statfs sfs; - bool r = true; - - if (launchd_assumes(statfs("/", &sfs) != -1)) { - if (!(sfs.f_flags & MNT_RDONLY)) { - r = false; - } - } - - return r; -} Modified: trunk/launchd/src/launchctl.1 =================================================================== --- trunk/launchd/src/launchctl.1 2007-02-18 18:48:19 UTC (rev 23081) +++ trunk/launchd/src/launchctl.1 2007-02-19 02:03:20 UTC (rev 23082) @@ -130,12 +130,6 @@ With four arguments, the third and forth argument represent the soft and hard limits respectively. See .Xr setrlimit 2 . -.It Ar stdout path -Set the standard out file descriptor to the given path. -.Nm launchd -.It Ar stderr path -Set the standard error file descriptor to the given path. -.Nm launchd .It Ar shutdown Tell .Nm launchd Modified: trunk/launchd/src/launchctl.c =================================================================== --- trunk/launchd/src/launchctl.c 2007-02-18 18:48:19 UTC (rev 23081) +++ trunk/launchd/src/launchctl.c 2007-02-19 02:03:20 UTC (rev 23082) @@ -61,6 +61,7 @@ #include <utmpx.h> #include <bootfiles.h> #include <sysexits.h> +#include <util.h> #include "libbootstrap_public.h" #include "libvproc_public.h" @@ -137,6 +138,8 @@ static void do_application_firewall_magic(int sfd, launch_data_t thejob); static void preheat_page_cache_hack(void); static void do_bootroot_magic(void); +static void do_single_user_mode(bool); +static bool do_single_user_mode2(void); static int bootstrap_cmd(int argc, char *const argv[]); static int load_and_unload_cmd(int argc, char *const argv[]); @@ -1174,16 +1177,74 @@ return fd; } -int -bootstrap_cmd(int argc __attribute__((unused)), char *const argv[] __attribute__((unused))) +void +do_single_user_mode(bool sflag) { + if (sflag) { + while (!do_single_user_mode2()) { + sleep(1); + } + } +} + +bool +do_single_user_mode2(void) +{ + bool runcom_fsck = true; /* should_fsck(); */ + int wstatus; + int fd; + pid_t p; + + switch ((p = fork())) { + case -1: + syslog(LOG_ERR, "can't fork single-user shell, trying again: %m"); + return false; + case 0: + break; + default: + assumes(waitpid(p, &wstatus, 0) != -1); + if (WIFEXITED(wstatus)) { + if (WEXITSTATUS(wstatus) == EXIT_SUCCESS) { + return true; + } else { + fprintf(stdout, "single user mode: exit status: %d\n", WEXITSTATUS(wstatus)); + } + } else { + fprintf(stdout, "single user mode shell: %s\n", strsignal(WTERMSIG(wstatus))); + } + return false; + } + + revoke(_PATH_CONSOLE); + if (!assumes((fd = open(_PATH_CONSOLE, O_RDWR)) != -1)) { + _exit(EXIT_FAILURE); + } + if (!assumes(login_tty(fd) != -1)) { + _exit(EXIT_FAILURE); + } + setenv("TERM", "vt100", 1); + if (runcom_fsck) { + fprintf(stdout, "Singleuser boot -- fsck not done\n"); + fprintf(stdout, "Root device is mounted read-only\n\n"); + fprintf(stdout, "If you want to make modifications to files:\n"); + fprintf(stdout, "\t/sbin/fsck -fy\n\t/sbin/mount -uw /\n\n"); + fprintf(stdout, "If you wish to boot the system:\n"); + fprintf(stdout, "\texit\n\n"); + fflush(stdout); + } + + execl(_PATH_BSHELL, "-sh", NULL); + syslog(LOG_ERR, "can't exec %s for single user: %m", _PATH_BSHELL); + _exit(EXIT_FAILURE); +} + +static void +very_pid2_specific_bootstrap(bool sflag) +{ int hnmib[] = { CTL_KERN, KERN_HOSTNAME }; struct group *tfp_gr; - if (getuid() != 0) { - fprintf(stderr, "%s: Only root can run the 'bootstrap' sub-command right now.\n", getprogname()); - return 1; - } + do_single_user_mode(sflag); if (assumes((tfp_gr = getgrnam("procview")) != NULL)) { int tfp_r_mib[3] = { CTL_KERN, KERN_TFP, KERN_TFP_READ_GROUP }; @@ -1262,9 +1323,12 @@ _vproc_set_global_on_demand(true); - char *load_launchd_items[] = { "load", "-D", "all", "/etc/mach_init.d", NULL }; - if (is_safeboot()) + char *load_launchd_items[] = { "load", "-D", "all", "/etc/mach_init.d", NULL, NULL }; + + if (is_safeboot()) { load_launchd_items[2] = "system"; + } + assumes(load_and_unload_cmd(4, load_launchd_items) == 0); const char *bcc_tag_tool[] = { "BootCacheControl", "tag", NULL }; @@ -1273,7 +1337,23 @@ do_bootroot_magic(); _vproc_set_global_on_demand(false); +} +int +bootstrap_cmd(int argc, char *const argv[] __attribute__((unused))) +{ + if (getpid() == 2 && getuid() == 0) { + very_pid2_specific_bootstrap(argc == 2); + } else if (getuid() != 0) { + char *load_launchd_items[] = { "load", "-D", "all", "-S", "Background", NULL }; + + if (is_safeboot()) { + load_launchd_items[2] = "system"; + } + + assumes(load_and_unload_cmd(5, load_launchd_items) == 0); + } + return 0; } @@ -1680,45 +1760,10 @@ } int -stdio_cmd(int argc, char *const argv[]) +stdio_cmd(int argc __attribute__((unused)), char *const argv[]) { - launch_data_t resp, msg, tmp; - int e, r = 0; - - if (argc != 2) { - fprintf(stderr, "usage: %s %s <path>\n", getprogname(), argv[0]); - return 1; - } - - msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); - - tmp = launch_data_new_string(argv[1]); - - if (!strcmp(argv[0], "stdout")) { - launch_data_dict_insert(msg, tmp, LAUNCH_KEY_SETSTDOUT); - } else { - launch_data_dict_insert(msg, tmp, LAUNCH_KEY_SETSTDERR); - } - - 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_ERRNO) { - if ((e = launch_data_get_errno(resp))) { - fprintf(stderr, "%s %s error: %s\n", getprogname(), argv[0], strerror(e)); - r = 1; - } - } else { - fprintf(stderr, "%s %s returned unknown response\n", getprogname(), argv[0]); - r = 1; - } - - launch_data_free(resp); - - return r; + fprintf(stderr, "%s %s: This sub-command no longer does anything\n", getprogname(), argv[0]); + return 1; } int Modified: trunk/launchd/src/launchd.c =================================================================== --- trunk/launchd/src/launchd.c 2007-02-18 18:48:19 UTC (rev 23081) +++ trunk/launchd/src/launchd.c 2007-02-19 02:03:20 UTC (rev 23082) @@ -70,13 +70,11 @@ #include "libvproc_public.h" #include "libvproc_internal.h" #include "liblaunch_public.h" -#include "liblaunch_private.h" #include "launchd_runtime.h" #include "launchd_core_logic.h" #include "launchd_unix_ipc.h" -#define PID1LAUNCHD_CONF "/etc/launchd.conf" #define LAUNCHD_CONF ".launchd.conf" #define SECURITY_LIB "/System/Library/Frameworks/Security.framework/Versions/A/Security" #define SHUTDOWN_LOG_DIR "/var/log/shutdown" @@ -84,16 +82,12 @@ extern char **environ; -static void signal_callback(void *, struct kevent *); static void pfsystem_callback(void *, struct kevent *); -static kq_callback kqsignal_callback = signal_callback; static kq_callback kqpfsystem_callback = pfsystem_callback; -static void pid1_magic_init(bool sflag); +static void pid1_magic_init(void); -static void usage(FILE *where); - static void testfd_or_openfd(int fd, const char *path, int flags); static bool get_network_state(void); static void monitor_networking_state(void); @@ -102,13 +96,9 @@ static void prep_shutdown_log_dir(void); static bool re_exec_in_single_user_mode = false; -static job_t rlcj = NULL; -static jmp_buf doom_doom_doom; static void *crash_addr; static pid_t crash_pid; -static const char *launchctl_bootstrap_tool[] = { "/bin/launchctl", /* "bootstrap", */ NULL }; -sigset_t blocked_signals = 0; static bool shutdown_in_progress = false; bool debug_shutdown_hangs = false; bool network_up = false; @@ -118,187 +108,61 @@ main(int argc, char *const *argv) { static const int sigigns[] = { SIGHUP, SIGINT, SIGPIPE, SIGALRM, - SIGTERM, SIGURG, SIGTSTP, SIGTSTP, SIGCONT, /*SIGCHLD,*/ - SIGTTIN, SIGTTOU, SIGIO, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, + SIGTERM, SIGURG, SIGTSTP, SIGTSTP, SIGCONT, SIGTTIN, + SIGTTOU, SIGIO, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGINFO, SIGUSR1, SIGUSR2 }; - bool sflag = false, Dflag = false; - char ldconf[PATH_MAX] = PID1LAUNCHD_CONF; - const char *h = getenv("HOME"); - const char *optargs = NULL; - struct stat sb; - size_t i, checkin_fdcnt = 0; - int *checkin_fds = NULL; - mach_port_t checkin_mport = MACH_PORT_NULL; - int ch, logopts; + bool sflag = false; + size_t i; + int ch; 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); - /* main() phase one: sanitize the process */ - - if (getpid() != 1) { - launch_data_t ldresp, ldmsg = launch_data_new_string(LAUNCH_KEY_CHECKIN); - - if ((ldresp = launch_msg(ldmsg))) { - if (launch_data_get_type(ldresp) == LAUNCH_DATA_DICTIONARY) { - const char *ldlabel = launch_data_get_string(launch_data_dict_lookup(ldresp, LAUNCH_JOBKEY_LABEL)); - launch_data_t tmp; - - if ((tmp = launch_data_dict_lookup(ldresp, LAUNCH_JOBKEY_SOCKETS))) { - if ((tmp = launch_data_dict_lookup(tmp, "LaunchIPC"))) { - checkin_fdcnt = launch_data_array_get_count(tmp); - checkin_fds = alloca(sizeof(int) * checkin_fdcnt); - for (i = 0; i < checkin_fdcnt; i++) { - checkin_fds[i] = _fd(launch_data_get_fd(launch_data_array_get_index(tmp, i))); - } - } - } - if ((tmp = launch_data_dict_lookup(ldresp, LAUNCH_JOBKEY_MACHSERVICES))) { - if ((tmp = launch_data_dict_lookup(tmp, ldlabel))) { - checkin_mport = launch_data_get_machport(tmp); - } - } - } - launch_data_free(ldresp); - } else { - int sigi, fdi, dts = getdtablesize(); - sigset_t emptyset; - - /* We couldn't check-in. - * - * Assume the worst and clean up whatever mess our parent process left us with... - */ - - for (fdi = STDERR_FILENO + 1; fdi < dts; fdi++) - close(fdi); - for (sigi = 1; sigi < NSIG; sigi++) { - switch (sigi) { - case SIGKILL: - case SIGSTOP: - break; - default: - launchd_assumes(signal(sigi, SIG_DFL) != SIG_ERR); - break; - } - } - sigemptyset(&emptyset); - launchd_assumes(sigprocmask(SIG_SETMASK, &emptyset, NULL) == 0); - } - - launch_data_free(ldmsg); - } - - launchd_runtime_init(); - - /* main() phase two: parse arguments */ - - if (getpid() == 1) { - optargs = "s"; - } else { - optargs = "Dh"; - } - - while ((ch = getopt(argc, argv, optargs)) != -1) { + while ((ch = getopt(argc, argv, "s")) != -1) { switch (ch) { - case 'D': Dflag = true; break; /* debug */ case 's': sflag = true; break; /* single user */ - case 'h': usage(stdout); break; /* help */ case '?': /* we should do something with the global optopt variable here */ default: - fprintf(stderr, "ignoring unknown arguments\n"); - usage(stderr); + fprintf(stderr, "%s: ignoring unknown arguments\n", getprogname()); break; } } - argc -= optind; - argv += optind; - /* main phase three: get the party started */ - - logopts = LOG_PID|LOG_CONS; - if (Dflag) { - logopts |= LOG_PERROR; + if (getpid() != 1 && getppid() != 1) { + fprintf(stderr, "%s: This program is not meant to be run directly.\n", getprogname()); + exit(EXIT_FAILURE); } - openlog(getprogname(), logopts, LOG_LAUNCHD); - setlogmask(LOG_UPTO(Dflag ? LOG_DEBUG : LOG_NOTICE)); + launchd_runtime_init(); - sigemptyset(&blocked_signals); + openlog(getprogname(), LOG_PID|LOG_CONS, LOG_LAUNCHD); + setlogmask(LOG_UPTO(/* LOG_DEBUG */ LOG_NOTICE)); for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) { - launchd_assumes(kevent_mod(sigigns[i], EVFILT_SIGNAL, EV_ADD, 0, 0, &kqsignal_callback) != -1); - sigaddset(&blocked_signals, sigigns[i]); launchd_assumes(signal(sigigns[i], SIG_IGN) != SIG_ERR); } - /* sigh... ignoring SIGCHLD has side effects: we can't call wait*() */ - launchd_assert(kevent_mod(SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, &kqsignal_callback) != -1); - - mach_init_init(checkin_mport); - - if (h) { - snprintf(ldconf, sizeof(ldconf), "%s/%s", h, LAUNCHD_CONF); - } - - rlcj = job_new(root_jobmgr, READCONF_LABEL, NULL, launchctl_bootstrap_tool, ldconf); - launchd_assert(rlcj != NULL); - if (NULL == getenv("PATH")) { setenv("PATH", _PATH_STDPATH, 1); } if (getpid() == 1) { - pid1_magic_init(sflag); + pid1_magic_init(); } else { - ipc_server_init(checkin_fds, checkin_fdcnt); + ipc_server_init(); } monitor_networking_state(); - /* - * We cannot stat() anything in the home directory right now. - * - * The per-user launchd can easily be demand launched by the tool doing - * the mount of the home directory. The result is an ugly deadlock. - * - * We hope to someday have a non-blocking stat(), but for now, we have - * to skip it. - */ - if (!h && stat(ldconf, &sb) == 0) { - rlcj = job_dispatch(rlcj, true); - } - char *doom_why = "at instruction"; - switch (setjmp(doom_doom_doom)) { - case 0: - break; - case SIGBUS: - case SIGSEGV: - doom_why = "trying to read/write"; - case SIGILL: - case SIGFPE: - syslog(LOG_EMERG, "We crashed %s: %p (sent by PID %u)", doom_why, crash_addr, crash_pid); - default: - sync(); - sleep(3); - /* the kernel will panic() when PID 1 exits */ - _exit(EXIT_FAILURE); - /* we should never get here */ - reboot(0); - /* or here either */ - break; - } - if (getpid() == 1) { handle_pid1_crashes_separately(); - - if (!job_active(rlcj)) { - init_pre_kevent(); - } } + jobmgr_init(sflag); + launchd_runtime(); } @@ -322,6 +186,7 @@ void fatal_signal_handler(int sig, siginfo_t *si, void *uap) { + const char *doom_why = "at instruction"; char *sample_args[] = { "/usr/bin/sample", "1", "1", "-file", PID1_CRASH_LOGFILE, NULL }; pid_t sample_p; int wstatus; @@ -338,51 +203,42 @@ break; default: waitpid(sample_p, &wstatus, 0); - sync(); break; case -1: break; } - longjmp(doom_doom_doom, sig); + switch (sig) { + default: + case 0: + break; + case SIGBUS: + case SIGSEGV: + doom_why = "trying to read/write"; + case SIGILL: + case SIGFPE: + syslog(LOG_EMERG, "We crashed %s: %p (sent by PID %u)", doom_why, crash_addr, crash_pid); + sync(); + sleep(3); + /* the kernel will panic() when PID 1 exits */ + _exit(EXIT_FAILURE); + /* we should never get here */ + reboot(0); + /* or here either */ + break; + } } void -pid1_magic_init(bool sflag) +pid1_magic_init(void) { launchd_assumes(setsid() != -1); launchd_assumes(chdir("/") != -1); launchd_assumes(setlogin("root") != -1); launchd_assumes(mount("fdesc", "/dev", MNT_UNION, NULL) != -1); - - init_boot(sflag); } -void -usage(FILE *where) -{ - const char *opts = "[-d]"; - - if (getuid() == 0) { - opts = "[-d] [-S <type> -U <user>]"; - } - - fprintf(where, "%s: %s [-- command [args ...]]\n", getprogname(), opts); - - fprintf(where, "\t-d Daemonize.\n"); - fprintf(where, "\t-h This usage statement.\n"); - - 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"); - } - - if (where == stdout) { - exit(EXIT_SUCCESS); - } -} - int _fd(int fd) { @@ -395,46 +251,7 @@ void prep_shutdown_log_dir(void) { - struct stat sb; - struct dirent *de; - DIR *thedir = NULL; - - if (!launchd_assumes(mkdir(SHUTDOWN_LOG_DIR, S_IRWXU) != -1 || errno == EEXIST)) { - goto out; - } - - if (!launchd_assumes(lstat(SHUTDOWN_LOG_DIR, &sb) != -1)) { - goto out; - } - - if (!launchd_assumes(S_ISDIR(sb.st_mode))) { - goto out; - } - - if (!launchd_assumes(chdir(SHUTDOWN_LOG_DIR) != -1)) { - goto out; - } - - if (!launchd_assumes((thedir = opendir(".")) != NULL)) { - goto out; - } - - while ((de = readdir(thedir))) { - if (strcmp(de->d_name, ".") == 0) { - continue; - } else if (strcmp(de->d_name, "..") == 0) { - continue; - } else { - launchd_assumes(remove(de->d_name) != -1); - } - } - -out: - if (thedir) { - closedir(thedir); - } - - chdir("/"); + launchd_assumes(mkdir(SHUTDOWN_LOG_DIR, S_IRWXU) != -1 || errno == EEXIST); } void @@ -457,8 +274,6 @@ debug_shutdown_hangs = true; } - rlcj = NULL; - launchd_assert(jobmgr_shutdown(root_jobmgr) != NULL); } @@ -476,24 +291,6 @@ kill(-1, SIGKILL); } -static void signal_callback(void *obj __attribute__((unused)), struct kevent *kev) -{ - syslog(LOG_DEBUG, "Received signal: %u", kev->ident); - - switch (kev->ident) { - case SIGHUP: - if (rlcj) { - rlcj = job_dispatch(rlcj, true); - } - break; - case SIGTERM: - launchd_shutdown(); - break; - default: - break; - } -} - void launchd_SessionCreate(void) { @@ -525,30 +322,6 @@ } } -launch_data_t -launchd_setstdio(int d, launch_data_t o) -{ - launch_data_t resp = launch_data_new_errno(0); - - if (launch_data_get_type(o) == LAUNCH_DATA_STRING) { - switch (d) { - case STDOUT_FILENO: - jobmgr_set_stdout(root_jobmgr, launch_data_get_string(o)); - break; - case STDERR_FILENO: - jobmgr_set_stderr(root_jobmgr, launch_data_get_string(o)); - break; - default: - launch_data_set_errno(resp, EINVAL); - break; - } - } else { - launch_data_set_errno(resp, EINVAL); - } - - return resp; -} - void batch_job_enable(bool e, struct conncb *c) { @@ -662,26 +435,3 @@ syslog(LOG_NOTICE, "Bug: %s:%u (%s):%u: %s", file, line, buf, saved_errno, test); } - -void -launchd_post_kevent(void) -{ -#if 0 - if (shutdown_in_progress && jobmgr_is_idle(root_jobmgr)) { - shutdown_in_progress = false; - - if (getpid() == 1) { - if (re_exec_in_single_user_mode) { - kill(-1, SIGKILL); /* One last time, just to clear the room */ - launchd_assumes(execl("/sbin/launchd", "/sbin/launchd", "-s", NULL) != -1); - } - } - } -#endif - if (getpid() == 1) { - if (rlcj && job_active(rlcj)) { - return; - } - init_pre_kevent(); - } -} Modified: trunk/launchd/src/launchd.h =================================================================== --- trunk/launchd/src/launchd.h 2007-02-18 18:48:19 UTC (rev 23081) +++ trunk/launchd/src/launchd.h 2007-02-19 02:03:20 UTC (rev 23082) @@ -26,12 +26,11 @@ #include "libbootstrap_public.h" #include "launchd_runtime.h" -#define READCONF_LABEL "com.apple.launchd.readconfig" +#define SHUTDOWN_LOG_DIR "/var/log/shutdown" struct kevent; struct conncb; -extern sigset_t blocked_signals; extern bool debug_shutdown_hangs; extern bool network_up; extern int batch_disabler_count; @@ -45,15 +44,9 @@ void launchd_SessionCreate(void); void launchd_shutdown(void); void launchd_single_user(void); -void launchd_post_kevent(void); -pid_t launchd_fork(void); boolean_t launchd_mach_ipc_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply); -void init_boot(bool sflag); -void init_pre_kevent(void); - void mach_start_shutdown(void); -void mach_init_init(mach_port_t); int _fd(int fd); Modified: trunk/launchd/src/launchd_core_logic.c =================================================================== --- trunk/launchd/src/launchd_core_logic.c 2007-02-18 18:48:19 UTC (rev 23081) +++ trunk/launchd/src/launchd_core_logic.c 2007-02-19 02:03:20 UTC (rev 23082) @@ -194,6 +194,7 @@ static void semaphoreitem_ignore(job_t j, struct semaphoreitem *si); struct jobmgr_s { + kq_callback kqjobmgr_callback; SLIST_ENTRY(jobmgr_s) sle; SLIST_HEAD(, jobmgr_s) submgrs; TAILQ_HEAD(, job_s) jobs; @@ -201,8 +202,6 @@ mach_port_t req_port; jobmgr_t parentmgr; job_t anonj; - char *jm_stdout; - char *jm_stderr; int reboot_flags; unsigned int global_on_demand_cnt; unsigned int sent_stop_to_hopeful_jobs:1, shutting_down:1; @@ -212,7 +211,7 @@ #define jobmgr_assumes(jm, e) \ (__builtin_expect(!(e), 0) ? jobmgr_log_bug(jm, __rcs_file_version__, __FILE__, __LINE__, #e), false : true) -static jobmgr_t jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t checkin_port); +static jobmgr_t jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t transfer_port, bool sflag); static jobmgr_t jobmgr_parent(jobmgr_t jm); static jobmgr_t jobmgr_do_garbage_collection(jobmgr_t jm); static bool jobmgr_is_idle(jobmgr_t jm); @@ -222,6 +221,7 @@ static job_t jobmgr_new_anonymous(jobmgr_t jm); static job_t job_mig_intran2(jobmgr_t jm, mach_port_t p); static void job_export_all2(jobmgr_t jm, launch_data_t where); +static void jobmgr_callback(void *obj, struct kevent *kev); static pid_t jobmgr_fork(jobmgr_t jm); static void jobmgr_setup_env_from_other_jobs(jobmgr_t jm); static struct machservice *jobmgr_lookup_service(jobmgr_t jm, const char *name, bool check_parent); @@ -229,8 +229,6 @@ static void jobmgr_log(jobmgr_t jm, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4))); /* static void jobmgr_log_error(jobmgr_t jm, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4))); */ static void jobmgr_log_bug(jobmgr_t jm, const char *rcs_rev, const char *path, unsigned int line, const char *test); -static char *jobmgr_get_stdout(jobmgr_t jm); -static char *jobmgr_get_stderr(jobmgr_t jm); struct job_s { kq_callback kqjob_callback; @@ -255,7 +253,6 @@ char *workingdir; char *username; char *groupname; - char *stdinpath; char *stdoutpath; char *stderrpath; pid_t p; @@ -311,6 +308,7 @@ static void job_callback_timer(job_t j, void *ident); static void job_callback_read(job_t j, int ident); static launch_data_t job_export2(job_t j, bool subjobs); +static job_t job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *argv); static job_t job_new_spawn(job_t j, const char *label, const char *path, const char *workingdir, const char *const *argv, const char *const *env, mode_t *u_mask, bool w4d); static job_t job_new_via_mach_init(job_t j, const char *cmd, uid_t uid, bool ond); static const char *job_prog(job_t j); @@ -577,14 +575,6 @@ jobmgr_assumes(jm, launchd_mport_close_recv(jm->jm_port) == KERN_SUCCESS); } - if (jm->jm_stdout) { - free(jm->jm_stdout); - } - - if (jm->jm_stderr) { - free(jm->jm_stderr); - } - if (jm->parentmgr) { SLIST_REMOVE(&jm->parentmgr->submgrs, jm, jobmgr_s, sle); } else if (getpid() == 1) { @@ -677,9 +667,6 @@ if (j->groupname) { free(j->groupname); } - if (j->stdinpath) { - free(j->stdinpath); - } if (j->stdoutpath) { free(j->stdoutpath); } @@ -797,7 +784,7 @@ /* preflight the string so we know how big it is */ snprintf(buf, sizeof(buf), "%s.%s", sizeof(void *) == 8 ? "0xdeadbeeffeedface" : "0xbabecafe", basename((char *)argv[0])); - jr = job_new(j->mgr, buf, NULL, argv, NULL); + jr = job_new(j->mgr, buf, NULL, argv); free(argv); @@ -852,7 +839,7 @@ return NULL; } - jr = job_new(j->mgr, label, path, argv, NULL); + jr = job_new(j->mgr, label, path, argv); if (!jr) { return NULL; @@ -907,7 +894,7 @@ snprintf(newlabel, sizeof(newlabel), "%u.anonymous", MACH_PORT_INDEX(jm->jm_port)); - if ((jr = job_new(jm, newlabel, procname, NULL, NULL))) { + if ((jr = job_new(jm, newlabel, procname, NULL))) { jr->anonymous = true; } @@ -915,14 +902,15 @@ } job_t -job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *argv, const char *stdinpath) +job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *argv) { - char compile_time_assert[offsetof(struct job_s, kqjob_callback) == 0 ? 1 : -1] __attribute__((unused)); const char *const *argv_tmp = argv; char *co; int i, cc = 0; job_t j; + launchd_assert(offsetof(struct job_s, kqjob_callback) == 0); + if (jm->shutting_down) { errno = EINVAL; return NULL; @@ -956,13 +944,6 @@ } } - if (stdinpath) { - j->stdinpath = strdup(stdinpath); - if (!job_assumes(j, j->stdinpath != NULL)) { - goto out_bad; - } - } - if (argv) { while (*argv_tmp++) j->argc++; @@ -996,9 +977,6 @@ if (j->prog) { free(j->prog); } - if (j->stdinpath) { - free(j->stdinpath); - } free(j); return NULL; @@ -1488,7 +1466,7 @@ return NULL; } - if ((j = job_new(root_jobmgr, label, prog, argv, NULL))) { + if ((j = job_new(root_jobmgr, label, prog, argv))) { launch_data_dict_iterate(pload, job_import_keys, j); } @@ -1801,7 +1779,7 @@ j->sent_sigkill = true; job_assumes(j, kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER, - EV_ADD|EV_ONESHOT, NOTE_SECONDS, LAUNCHD_SIGKILL_TIMEOUT, j) != -1); + EV_ADD, NOTE_SECONDS, LAUNCHD_SIGKILL_TIMEOUT, j) != -1); } void @@ -1832,8 +1810,15 @@ job_dispatch(j, true); } else if (&j->exit_timeout == ident) { if (j->sent_sigkill) { - job_log(j, LOG_ERR, "Did not die after sending SIGKILL %u seconds ago...", LAUNCHD_SIGKILL_TIMEOUT); - if (debug_shutdown_hangs) { + struct timeval tvd, tve; + double delta; + + job_assumes(j, gettimeofday(&tve, NULL) != -1); + timersub(&tve, &j->sent_sigterm_time, &tvd); + delta = (double)tvd.tv_sec + (double)tvd.tv_usec / (double)1000000; + delta -= (double)j->exit_timeout; + job_log(j, LOG_ERR, "Did not die after sending SIGKILL %f seconds ago...", delta); + if (debug_shutdown_hangs && delta > 60) { job_assumes(j, host_reboot(mach_host_self(), HOST_REBOOT_DEBUGGER) == KERN_SUCCESS); } } else { @@ -1857,6 +1842,25 @@ } void +jobmgr_callback(void *obj, struct kevent *kev) +{ + jobmgr_t jm = obj; + + switch (kev->filter) { + case EVFILT_SIGNAL: + switch (kev->ident) { + case SIGTERM: + return launchd_shutdown(); + default: + return (void)jobmgr_assumes(jm, false); + } + break; + default: + return (void)jobmgr_assumes(jm, false); + } +} + +void job_callback(void *obj, struct kevent *kev) { job_t j = obj; @@ -1915,10 +1919,7 @@ j->sent_sigterm_time.tv_sec = 0; j->sent_sigterm_time.tv_usec = 0; - /* FIXME, using stdinpath is a hack for re-reading the conf file */ - if (j->stdinpath) { - sipc = true; - } else if (!j->legacy_mach_job) { + if (!j->legacy_mach_job) { sipc = (!SLIST_EMPTY(&j->sockets) || !SLIST_EMPTY(&j->machservices)); } @@ -2056,6 +2057,10 @@ job_assumes(j, binpref_out_cnt == j->j_binpref_cnt); } + for (i = 1; i < NSIG; i++) { + signal(i, SIG_DFL); + } + if (j->prog) { errno = posix_spawn(&junk_pid, j->inetcompat ? file2exec : j->prog, NULL, &spattr, (char *const*)argv, environ); job_log_error(j, LOG_ERR, "posix_spawn(\"%s\", ...)", j->prog); @@ -2262,9 +2267,8 @@ umask(j->mask); } - job_setup_fd(j, STDIN_FILENO, j->stdinpath, O_RDONLY); - job_setup_fd(j, STDOUT_FILENO, j->stdoutpath ? j->stdoutpath : jobmgr_get_stdout(j->mgr), O_WRONLY|O_APPEND|O_CREAT); - job_setup_fd(j, STDERR_FILENO, j->stderrpath ? j->stderrpath : jobmgr_get_stderr(j->mgr), O_WRONLY|O_APPEND|O_CREAT); + job_setup_fd(j, STDOUT_FILENO, j->stdoutpath, O_WRONLY|O_APPEND|O_CREAT); + job_setup_fd(j, STDERR_FILENO, j->stderrpath, O_WRONLY|O_APPEND|O_CREAT); jobmgr_setup_env_from_other_jobs(j->mgr); @@ -2278,43 +2282,10 @@ void job_setup_fd(job_t j, int target_fd, const char *path, int flags) { -#if 0 - char newpath[PATH_MAX]; -#endif int fd; if (!path) { -#if 0 - switch (target_fd) { - case STDOUT_FILENO: - case STDERR_FILENO: - flags |= O_TRUNC; - break; - default: - return; - } - - if (getuid() == 0) { - snprintf(newpath, sizeof(newpath), "/var/log/launchd"); - } else { - struct passwd *pwe; - - if (!job_assumes(j, (pwe = getpwuid(getuid())) != NULL)) { - return; - } - - snprintf(newpath, sizeof(newpath), "%s/Library/Logs/launchd", pwe->pw_dir); - } - - mkdir(newpath, ACCESSPERMS); - - strcat(newpath, "/"); - strcat(newpath, j->label); - - path = newpath; -#else return; -#endif } if ((fd = open(path, flags|O_NOCTTY, DEFFILEMODE)) == -1) { @@ -2427,10 +2398,10 @@ void job_logv(job_t j, int pri, int err, const char *msg, va_list ap) { - char newmsg[10000]; + char *newmsg; char *newlabel; int oldmask = 0; - size_t i, o, jlabel_len = strlen(j->label); + size_t i, o, jlabel_len = strlen(j->label), newmsgsz; /* * Hack: If bootstrap_port is set, we must be on the child side of a @@ -2442,6 +2413,8 @@ } newlabel = alloca((jlabel_len + 1) * 2); + newmsgsz = (jlabel_len + 1) * 2 + strlen(msg) + 100; + newmsg = alloca(newmsgsz); for (i = 0, o = 0; i < jlabel_len; i++, o++) { if (j->label[i] == '%') { @@ -2453,16 +2426,16 @@ newlabel[o] = '\0'; if (err) { - snprintf(newmsg, sizeof(newmsg), "%s: %s: %s", newlabel, msg, strerror(err)); + snprintf(newmsg, newmsgsz, "%s: %s: %s", newlabel, msg, strerror(err)); } else { - snprintf(newmsg, sizeof(newmsg), "%s: %s", newlabel, msg); + snprintf(newmsg, newmsgsz, "%s: %s", newlabel, msg); } if (j->debug) { oldmask = setlogmask(LOG_UPTO(LOG_DEBUG)); } - vsyslog(pri, newmsg, ap); + jobmgr_logv(j->mgr, pri, 0, newmsg, ap); if (j->debug) { setlogmask(oldmask); @@ -2514,9 +2487,34 @@ void jobmgr_logv(jobmgr_t jm, int pri, int err, const char *msg, va_list ap) { - if (launchd_assumes(jm->anonj)) { - job_logv(jm->anonj, pri, err, msg, ap); + char *newmsg; + char *newname; + size_t i, o, jmname_len = strlen(jm->name), newmsgsz; + + newname = alloca((jmname_len + 1) * 2); + newmsgsz = (jmname_len + 1) * 2 + strlen(msg) + 100; + newmsg = alloca(newmsgsz); + + for (i = 0, o = 0; i < jmname_len; i++, o++) { + if (jm->name[i] == '%') { + newname[o] = '%'; + o++; + } + newname[o] = jm->name[i]; } + newname[o] = '\0'; + + if (err) { + snprintf(newmsg, newmsgsz, "%s: %s: %s", newname, msg, strerror(err)); + } else { + snprintf(newmsg, newmsgsz, "%s: %s", newname, msg); + } + + if (jm->parentmgr) { + jobmgr_logv(jm->parentmgr, pri, 0, newmsg, ap); + } else { + vsyslog(pri, newmsg, ap); + } } void @@ -3045,20 +3043,12 @@ } pid_t -launchd_fork(void) -{ - return jobmgr_fork(root_jobmgr); -} - -pid_t jobmgr_fork(jobmgr_t jm) { mach_port_t p = jm->jm_port; pid_t r = -1; int saved_errno; - sigprocmask(SIG_BLOCK, &blocked_signals, NULL); - jobmgr_assumes(jm, launchd_mport_make_send(p) == KERN_SUCCESS); jobmgr_assumes(jm, launchd_set_bport(p) == KERN_SUCCESS); jobmgr_assumes(jm, launchd_mport_deallocate(p) == KERN_SUCCESS); @@ -3069,18 +3059,8 @@ if (r != 0) { jobmgr_assumes(jm, launchd_set_bport(MACH_PORT_NULL) == KERN_SUCCESS); - } else if (r == 0) { - size_t i; - - for (i = 0; i < NSIG; i++) { - if (sigismember(&blocked_signals, i)) { - signal(i, SIG_DFL); - } - } } - sigprocmask(SIG_UNBLOCK, &blocked_signals, NULL); - errno = saved_errno; return r; } @@ -3360,50 +3340,6 @@ return true; } -void -jobmgr_set_stdout(jobmgr_t jm, const char *what) -{ - if (jm->jm_stdout) { - free(jm->jm_stdout); - } - - jm->jm_stdout = strdup(what); -} - -void -jobmgr_set_stderr(jobmgr_t jm, const char *what) -{ - if (jm->jm_stderr) { - free(jm->jm_stderr); - } - - jm->jm_stderr = strdup(what); -} - -char * -jobmgr_get_stdout(jobmgr_t jm) -{ - if (jm->jm_stdout) { - return jm->jm_stdout; - } else if (jm->parentmgr == NULL) { - return NULL; - } - - return jobmgr_get_stdout(jm->parentmgr); -} - -char * -jobmgr_get_stderr(jobmgr_t jm) -{ - if (jm->jm_stderr) { - return jm->jm_stderr; - } else if (jm->parentmgr == NULL) { - return NULL; - } - - return jobmgr_get_stderr(jm->parentmgr); -} - jobmgr_t jobmgr_parent(jobmgr_t jm) { @@ -3424,25 +3360,33 @@ } jobmgr_t -jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t checkin_port) +jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t transfer_port, bool sflag) { + const char *bootstrap_tool[] = { "/bin/launchctl", "bootstrap", NULL, NULL }; mach_msg_size_t mxmsgsz; + job_t bootstrapper = NULL; jobmgr_t jmr; - if (requestorport == MACH_PORT_NULL) { - if (jm) { - jobmgr_log(jm, LOG_ERR, "Mach sub-bootstrap create request requires a requester port"); - } + if (sflag) { + bootstrap_tool[2] = "-s"; + } + + launchd_assert(offsetof(struct jobmgr_s, kqjobmgr_callback) == 0); + + if (jm && requestorport == MACH_PORT_NULL) { + jobmgr_log(jm, LOG_ERR, "Mach sub-bootstrap create request requires a requester port"); return NULL; } - jmr = calloc(1, sizeof(struct jobmgr_s) + strlen("LoginWindow") + 1); + jmr = calloc(1, sizeof(struct jobmgr_s) + 30); if (jmr == NULL) { return NULL; } TAILQ_INIT(&jmr->jobs); + jmr->kqjobmgr_callback = jobmgr_callback; + strcpy(jmr->name, "In-utero"); jmr->req_port = requestorport; @@ -3450,17 +3394,44 @@ SLIST_INSERT_HEAD(&jm->submgrs, jmr, sle); } - if (!jobmgr_assumes(jmr, launchd_mport_notify_req(jmr->req_port, MACH_NOTIFY_DEAD_NAME) == KERN_SUCCESS)) { + if (jm && !jobmgr_assumes(jmr, launchd_mport_notify_req(jmr->req_port, MACH_NOTIFY_DEAD_NAME) == KERN_SUCCESS)) { goto out_bad; } - if (checkin_port != MACH_PORT_NULL) { - jmr->jm_port = checkin_port; + if (transfer_port != MACH_PORT_NULL) { + jobmgr_assumes(jmr, jm != NULL); + jmr->jm_port = transfer_port; + } else if (!jm && getpid() != 1) { + char *trusted_fd = getenv(LAUNCHD_TRUSTED_FD_ENV); + name_t service_buf; + + snprintf(service_buf, sizeof(service_buf), "com.apple.launchd.peruser.%u", getuid()); + + if (!jobmgr_assumes(jmr, bootstrap_check_in(bootstrap_port, service_buf, &jmr->jm_port) == 0)) { + goto out_bad; + } + + if (trusted_fd) { + int dfd, lfd = strtol(trusted_fd, NULL, 10); + + if ((dfd = dup(lfd)) >= 0) { + jobmgr_assumes(jmr, close(dfd) != -1); + jobmgr_assumes(jmr, close(lfd) != -1); + } + + unsetenv(LAUNCHD_TRUSTED_FD_ENV); + } + + inherited_bootstrap_port = bootstrap_port; + /* cut off the Libc cache, we don't want to deadlock against ourself */ + bootstrap_port = MACH_PORT_NULL; + /* We set this explicitly as we start each child */ + launchd_assert(launchd_set_bport(MACH_PORT_NULL) == KERN_SUCCESS); } else if (!jobmgr_assumes(jmr, launchd_mport_create_recv(&jmr->jm_port) == KERN_SUCCESS)) { goto out_bad; } - snprintf(jmr->name, strlen(jmr->name) + 1, "%u", MACH_PORT_INDEX(jmr->jm_port)); + sprintf(jmr->name, "%u", MACH_PORT_INDEX(jmr->jm_port)); /* Sigh... at the moment, MIG has maxsize == sizeof(reply union) */ mxmsgsz = sizeof(union __RequestUnion__job_mig_protocol_vproc_subsystem); @@ -3472,16 +3443,20 @@ goto out_bad; } - if (jm) { - jobmgr_log(jm, LOG_DEBUG, "Mach sub-bootstrap created: %s", jmr->name); - } + jobmgr_assumes(jmr, (jmr->anonj = jobmgr_new_anonymous(jmr)) != NULL); - jmr->anonj = jobmgr_new_anonymous(jmr); + bootstrapper = job_new(jmr, "com.apple.launchctld", NULL, bootstrap_tool); - jobmgr_assumes(jmr, jmr->anonj != NULL); + if (!jm) { + jobmgr_assumes(jmr, kevent_mod(SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, jmr) != -1); + } - jobmgr_log(jmr, LOG_DEBUG, "Created job manager"); + jobmgr_log(jmr, LOG_DEBUG, "Created job manager%s%s", jm ? " with parent: " : ".", jm ? jm->name : ""); + if (!jm && jobmgr_assumes(jmr, bootstrapper != NULL)) { + jobmgr_assumes(jmr, job_dispatch(bootstrapper, true) != NULL); + } + return jmr; out_bad: @@ -3759,9 +3734,11 @@ } snprintf(pidstr, sizeof(pidstr), "%u", j->p); - snprintf(logfile, sizeof(logfile), "/var/log/shutdown/%s-%u.sample.txt", j->label, j->p); + snprintf(logfile, sizeof(logfile), SHUTDOWN_LOG_DIR "/%s-%u.sample.txt", j->label, j->p); - job_assumes(j, mkdir("/var/log/shutdown", S_IRWXU) != -1 || errno == EEXIST); + if (!job_assumes(j, unlink(logfile) != -1 || errno == ENOENT)) { + goto out; + } /* * This will stall launchd for as long as the 'sample' tool runs. @@ -3777,6 +3754,8 @@ goto out; } + sync(); + if (!job_assumes(j, WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0)) { goto out; } @@ -4194,7 +4173,7 @@ return BOOTSTRAP_NO_MEMORY; } - ipc_server_init(NULL, 0); + ipc_server_init(); if (!sockpath) { return BOOTSTRAP_NO_MEMORY; @@ -4262,7 +4241,7 @@ sprintf(lbuf, "com.apple.launchd.peruser.%u", which_user); - ji = job_new(root_jobmgr, lbuf, "/sbin/launchd", NULL, NULL); + ji = job_new(root_jobmgr, lbuf, "/sbin/launchd", NULL); if (ji == NULL) { return BOOTSTRAP_NO_MEMORY; @@ -4562,7 +4541,7 @@ launchd_assert(l2l_name_cnt == l2l_port_cnt); - if ((jmr = jobmgr_new(j->mgr, reqport, rcvright)) == NULL) { + if ((jmr = jobmgr_new(j->mgr, reqport, rcvright, false)) == NULL) { kr = BOOTSTRAP_NO_MEMORY; goto out; } @@ -4691,7 +4670,7 @@ return BOOTSTRAP_NO_MEMORY; } - if ((jmr = jobmgr_new(j->mgr, requestorport, MACH_PORT_NULL)) == NULL) { + if ((jmr = jobmgr_new(j->mgr, requestorport, MACH_PORT_NULL, false)) == NULL) { if (requestorport == MACH_PORT_NULL) { return BOOTSTRAP_NOT_PRIVILEGED; } @@ -4864,30 +4843,7 @@ } void -mach_init_init(mach_port_t checkin_port) +jobmgr_init(bool sflag) { - job_t ji, anon_job = NULL; - - launchd_assert((root_jobmgr = jobmgr_new(NULL, mach_task_self(), checkin_port)) != NULL); - - TAILQ_FOREACH(ji, &root_jobmgr->jobs, sle) { - if (ji->anonymous) { - anon_job = ji; - break; - } - } - - launchd_assert(anon_job != NULL); - - launchd_assert(launchd_get_bport(&inherited_bootstrap_port) == KERN_SUCCESS); - - if (getpid() != 1) { - launchd_assumes(inherited_bootstrap_port != MACH_PORT_NULL); - } - - /* We set this explicitly as we start each child */ - launchd_assert(launchd_set_bport(MACH_PORT_NULL) == KERN_SUCCESS); - - /* cut off the Libc cache, we don't want to deadlock against ourself */ - bootstrap_port = MACH_PORT_NULL; + launchd_assert((root_jobmgr = jobmgr_new(NULL, MACH_PORT_NULL, MACH_PORT_NULL, sflag)) != NULL); } Modified: trunk/launchd/src/launchd_core_logic.h =================================================================== --- trunk/launchd/src/launchd_core_logic.h 2007-02-18 18:48:19 UTC (rev 23081) +++ trunk/launchd/src/launchd_core_logic.h 2007-02-19 02:03:20 UTC (rev 23082) @@ -28,8 +28,7 @@ extern jobmgr_t root_jobmgr; -void jobmgr_set_stdout(jobmgr_t jm, const char *what); -void jobmgr_set_stderr(jobmgr_t jm, const char *what); +void jobmgr_init(bool); jobmgr_t jobmgr_shutdown(jobmgr_t jm); void jobmgr_dispatch_all_semaphores(jobmgr_t jm); job_t jobmgr_find(jobmgr_t jm, const char *label); @@ -39,7 +38,6 @@ launch_data_t job_export_all(void); -job_t job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *argv, const char *stdinpath); job_t job_dispatch(job_t j, bool kickstart); /* returns j on success, NULL on job removal */ bool job_active(job_t j); launch_data_t job_export(job_t j); Modified: trunk/launchd/src/launchd_runtime.c =================================================================== --- trunk/launchd/src/launchd_runtime.c 2007-02-18 18:48:19 UTC (rev 23081) +++ trunk/launchd/src/launchd_runtime.c 2007-02-19 02:03:20 UTC (rev 23082) @@ -73,6 +73,7 @@ static void *mport_demand_loop(void *arg); static void *kqueue_demand_loop(void *arg); +static void log_kevent_struct(int level, struct kevent *kev); static void async_callback(void); static kq_callback kqasync_callback = (kq_callback)async_callback; @@ -143,7 +144,51 @@ return NULL; } -static void +const char * +signal_to_C_name(unsigned int sig) +{ + static char unknown[25]; + +#define SIG2CASE(sg) case sg: return #sg + + switch (sig) { + SIG2CASE(SIGHUP); + SIG2CASE(SIGINT); + SIG2CASE(SIGQUIT); + SIG2CASE(SIGILL); + SIG2CASE(SIGTRAP); + SIG2CASE(SIGABRT); + SIG2CASE(SIGFPE); + SIG2CASE(SIGKILL); + SIG2CASE(SIGBUS); + SIG2CASE(SIGSEGV); + SIG2CASE(SIGSYS); + SIG2CASE(SIGPIPE); + SIG2CASE(SIGALRM); + SIG2CASE(SIGTERM); + SIG2CASE(SIGURG); + SIG2CASE(SIGSTOP); + SIG2CASE(SIGTSTP); + SIG2CASE(SIGCONT); + SIG2CASE(SIGCHLD); + SIG2CASE(SIGTTIN); + SIG2CASE(SIGTTOU); + SIG2CASE(SIGIO); + SIG2CASE(SIGXCPU); + SIG2CASE(SIGXFSZ); + SIG2CASE(SIGVTALRM); + SIG2CASE(SIGPROF); + SIG2CASE(SIGWINCH); + SIG2CASE(SIGINFO); + SIG2CASE(SIGUSR1); + SIG2CASE(SIGUSR2); + default: + snprintf(unknown, sizeof(unknown), "%u", sig); + return unknown; + } +} + +void log_kevent_struct(int level, struct kevent *kev) { const char *filter_str; @@ -245,42 +290,7 @@ break; case EVFILT_SIGNAL: filter_str = "EVFILT_SIGNAL"; - switch (kev->ident) { -#define SIG2CASE(sg) case sg: sprintf(ident_buf, #sg); break - SIG2CASE(SIGHUP); - SIG2CASE(SIGINT); - SIG2CASE(SIGQUIT); - SIG2CASE(SIGILL); - SIG2CASE(SIGTRAP); - SIG2CASE(SIGABRT); - SIG2CASE(SIGFPE); - SIG2CASE(SIGKILL); - SIG2CASE(SIGBUS); - SIG2CASE(SIGSEGV); - SIG2CASE(SIGSYS); - SIG2CASE(SIGPIPE); - SIG2CASE(SIGALRM); - SIG2CASE(SIGTERM); - SIG2CASE(SIGURG); - SIG2CASE(SIGSTOP); - SIG2CASE(SIGTSTP); - SIG2CASE(SIGCONT); - SIG2CASE(SIGCHLD); - SIG2CASE(SIGTTIN); - SIG2CASE(SIGTTOU); - SIG2CASE(SIGIO); - SIG2CASE(SIGXCPU); - SIG2CASE(SIGXFSZ); - SIG2CASE(SIGVTALRM); - SIG2CASE(SIGPROF); - SIG2CASE(SIGWINCH); - SIG2CASE(SIGINFO); - SIG2CASE(SIGUSR1); - SIG2CASE(SIGUSR2); - default: - sprintf(ident_buf, "%ld", kev->ident); - break; - } + strcpy(ident_buf, signal_to_C_name(kev->ident)); break; case EVFILT_TIMER: filter_str = "EVFILT_TIMER"; @@ -404,8 +414,6 @@ #endif } - launchd_post_kevent(); - return 0; } Modified: trunk/launchd/src/launchd_runtime.h =================================================================== --- trunk/launchd/src/launchd_runtime.h 2007-02-18 18:48:19 UTC (rev 23081) +++ trunk/launchd/src/launchd_runtime.h 2007-02-19 02:03:20 UTC (rev 23082) @@ -45,7 +45,7 @@ #define launchd_blame(e, b) \ (__builtin_expect(!(e), 0) ? syslog(LOG_DEBUG, "Encountered bug: %d", b), false : true) -#define launchd_assert(e) launchd_assumes(e) ? true : abort(); +#define launchd_assert(e) if (__builtin_constant_p(e)) { char __compile_time_assert__[e ? 1 : -1] __attribute__((unused)); } else if (!launchd_assumes(e)) { abort(); } void _log_launchd_bug(const char *rcs_rev, const char *path, unsigned int line, const char *test); @@ -64,6 +64,7 @@ kern_return_t runtime_remove_mport(mach_port_t name); bool runtime_get_caller_creds(struct ldcred *ldc); +const char *signal_to_C_name(unsigned int sig); int kevent_mod(uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t data, void *udata); Modified: trunk/launchd/src/launchd_unix_ipc.c =================================================================== --- trunk/launchd/src/launchd_unix_ipc.c 2007-02-18 18:48:19 UTC (rev 23081) +++ trunk/launchd/src/launchd_unix_ipc.c 2007-02-19 02:03:20 UTC (rev 23082) @@ -88,22 +88,17 @@ } void -ipc_server_init(int *fds, size_t fd_cnt) +ipc_server_init(void) { struct sockaddr_un sun; mode_t oldmask; int r, fd = -1; char ourdir[1024]; - size_t i; if (ipc_inited) { return; } - if (fds) { - goto add_fds; - } - memset(&sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; @@ -163,27 +158,17 @@ goto out_bad; } -add_fds: - if (fds) { - for (i = 0; i < fd_cnt; i++) { - if (kevent_mod(fds[i], EVFILT_READ, EV_ADD, 0, 0, &kqipc_listen_callback) == -1) { - syslog(LOG_ERR, "kevent_mod(%d, EVFILT_READ): %m", fds[i]); - goto out_bad; - } - } - } else if (kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, &kqipc_listen_callback) == -1) { + if (kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, &kqipc_listen_callback) == -1) { syslog(LOG_ERR, "kevent_mod(\"thesocket\", EVFILT_READ): %m"); goto out_bad; } ipc_inited = true; - if (!fds) { - sockdir = strdup(ourdir); - sockpath = strdup(sun.sun_path); - ipc_self = getpid(); - atexit(ipc_clean_up); - } + sockdir = strdup(ourdir); + sockpath = strdup(sun.sun_path); + ipc_self = getpid(); + atexit(ipc_clean_up); out_bad: if (!ipc_inited && fd != -1) { @@ -446,10 +431,6 @@ resp = launch_data_new_integer(setlogmask(launch_data_get_integer(data))); } else if (!strcmp(cmd, LAUNCH_KEY_SETUMASK)) { resp = launch_data_new_integer(umask(launch_data_get_integer(data))); - } else if (!strcmp(cmd, LAUNCH_KEY_SETSTDOUT)) { - resp = launchd_setstdio(STDOUT_FILENO, data); - } else if (!strcmp(cmd, LAUNCH_KEY_SETSTDERR)) { - resp = launchd_setstdio(STDERR_FILENO, data); } else if (!strcmp(cmd, LAUNCH_KEY_BATCHCONTROL)) { batch_job_enable(launch_data_get_bool(data), rmc->c); resp = launch_data_new_errno(0); Modified: trunk/launchd/src/launchd_unix_ipc.h =================================================================== --- trunk/launchd/src/launchd_unix_ipc.h 2007-02-18 18:48:19 UTC (rev 23081) +++ trunk/launchd/src/launchd_unix_ipc.h 2007-02-19 02:03:20 UTC (rev 23082) @@ -43,6 +43,6 @@ void ipc_revoke_fds(launch_data_t o); void ipc_close_fds(launch_data_t o); void ipc_clean_up(void); -void ipc_server_init(int *, size_t); +void ipc_server_init(void); #endif Modified: trunk/launchd/src/liblaunch_private.h =================================================================== --- trunk/launchd/src/liblaunch_private.h 2007-02-18 18:48:19 UTC (rev 23081) +++ trunk/launchd/src/liblaunch_private.h 2007-02-19 02:03:20 UTC (rev 23082) @@ -31,8 +31,6 @@ #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_SINGLEUSER "SingleUser" #define LAUNCH_KEY_GETRESOURCELIMITS "GetResourceLimits" @@ -76,7 +74,7 @@ * This returns 1 on success (it used to return otherwise), and -1 on failure. */ #define LOAD_ONLY_SAFEMODE_LAUNCHAGENTS 1 -pid_t create_and_switch_to_per_session_launchd(const char *login, int flags, ...); +pid_t create_and_switch_to_per_session_launchd(const char * /* loginname */, int flags, ...); /* Also for LoginWindow. * Modified: trunk/launchd/src/libvproc_public.h =================================================================== --- trunk/launchd/src/libvproc_public.h 2007-02-18 18:48:19 UTC (rev 23081) +++ trunk/launchd/src/libvproc_public.h 2007-02-19 02:03:20 UTC (rev 23082) @@ -26,60 +26,11 @@ typedef void * vproc_err_t; -#if 0 - typedef void * vproc_t; typedef void * vprocmgr_t; -/* By default, pass NULL for vprocmgr_t or vproc_t to get notions of self or "my manager" */ - -vproc_err_t vprocmgr_create_vproc(vprocmgr_t vpm, launch_data_t the_vproc, vproc_t *vp); - -/* If creating multiple jobs, it is wise to create them atomically with respect to each other */ -vproc_err_t vprocmgr_create_vprocs(vprocmgr_t vpm, launch_data_t *the_vprocs, vproc_t *vp, size_t cnt); - -vproc_err_t vprocmgr_delete_vproc(vprocmgr_t vpm, vproc_t vp); - -/* The virtual process managers are arranged in a hierarchy */ -vproc_err_t vprocmgr_get_parent(vprocmgr_t vpm, vprocmgr_t *vpm_parent); - -vproc_err_t vprocmgr_get_all_vprocs(vprocmgr_t vpm, vproc_t **vps, size_t *vp_cnt); - -vproc_err_t vprocmgr_lookup_vproc(vprocmgr_t vpm, const char *label, vproc_t *vp); - -vproc_err_t vprocmgr_lookup_vprocmgr_for_user(vprocmgr_t vpm, const char *user, vprocmgr_t *vpm_out); - -vproc_err_t vprocmgr_lookup_mach_service(vprocmgr_t vpm, const char *service, mach_port_t *service_port); - -/* For controlling speculative and optimistical spawning of vprocs */ -vproc_err_t vprocmgr_set_force_on_demand(vproc_mgr_t vpm, bool force); -vproc_err_t vprocmgr_get_force_on_demand(vproc_mgr_t vpm, bool *force); - -/* Only release those vprocmgr_t objects that returned from APIs. */ -vproc_err_t vprocmgr_release(vprocmgr_t vpm); - - -/* Get meta-data and IPC handles from launchd */ -vproc_err_t vproc_checkin(launch_data_t *out); - -/* Get only meta-data from launchd */ -vproc_err_t vproc_get_info(vproc_t vp, launch_data_t *out); - -/* Lookup a Mach service amongst our peers and progenitors */ -vproc_err_t vproc_lookup_mach_service(vproc_t vp, const char *service, mach_port_t *service_port); - -/* Sending signals to a program that isn't running will return an error */ -vproc_err_t vproc_send_signal(vproc_t vp, int signum); - -/* Only release those vproc_t objects that returned from APIs. */ -vproc_err_t vproc_release(vproc_t vp); - - - const char *vproc_strerror(vproc_err_t r); -#endif - __END_DECLS #endif
participants (1)
-
source_changes@macosforge.org