Projects
Browse Source     Search     Timeline     Wiki

Changeset 23025

Show
Ignore:
Timestamp:
01/28/07 13:15:53 (22 months ago)
Author:
zarzycki@…
Message:

The last remaining customer (loginwindow) of /etc/ttys has switched to launchd.

This is the easy part or removing init.c. The next stage will be to deal with
single-user-mode in launchd proper and clean up launchd's self-bootstrap logic.
Then we can finally delete init.c.

Location:
trunk/launchd/src
Files:
7 modified

Legend:

Unmodified
Added
Removed
  • trunk/launchd/src/init.c

    r22986 r23025  
    5656static const char *const __rcs_file_version__ = "$Revision$"; 
    5757 
    58 #include <Security/Authorization.h> 
    59 #include <Security/AuthorizationTags.h> 
    60 #include <Security/AuthSession.h> 
    61  
    6258#include <sys/types.h> 
    6359#include <sys/queue.h> 
     
    9288#define _PATH_RUNCOM            "/etc/rc" 
    9389 
    94 /* 
    95  * Sleep times; used to prevent thrashing. 
    96  */ 
    97 #define GETTY_SPACING            5      /* N secs minimum getty spacing */ 
    98 #define GETTY_SLEEP             30      /* sleep N secs after spacing problem */ 
    9990#define STALL_TIMEOUT           30      /* wait N secs after warning */ 
    100 #define DEATH_WATCH             10      /* wait N secs for procs to die */ 
    101 #define FAILED_HW_PASS           5      /* wait N secs before croaking user */ 
    10291 
    10392static void stall(char *, ...); 
     
    118107static void setctty(const char *, int); 
    119108 
    120 // gvdl@next.com 14 Aug 1995 
    121 //   - from ~apps/loginwindow_proj/loginwindow/common.h 
    122 #define REALLY_EXIT_TO_CONSOLE                  229 
    123  
    124 // From old init.c 
    125 // These flags are used in the se_flags field of the init_session structure 
    126 #define SE_SHUTDOWN     0x1             /* session won't be restarted */ 
    127  
    128 // The flags below control what sort of getty is launched. 
    129 #define SE_GETTY_LAUNCH 0x30    /* What type of getty to launch */  
    130 #define SE_COMMON       0x00    /* Usual command that is run - getty */ 
    131 #define SE_ONERROR      0x10    /* Command to run if error condition occurs. 
    132                                  * This will almost always be the windowserver 
    133                                  * and loginwindow.  This is so if the w.s. 
    134                                  * ever dies, that the naive user (stan) 
    135                                  * doesn't ever see the console window. */ 
    136 #define SE_ONOPTION     0x20    /* Command to run when loginwindow exits with 
    137                                  * special error code (229).  This signifies 
    138                                  * that the user typed "console" at l.w. and 
    139                                  * l.w. wants to exit and have init run getty 
    140                                  * which will then put up a console window. */ 
    141  
    142 typedef struct _se_command { 
    143         char    *path;          /* what to run on that port */ 
    144         char    **argv;         /* pre-parsed argument array */ 
    145 } se_cmd_t; 
    146  
    147 typedef struct init_session { 
    148         kq_callback se_callback;        /* run loop callback */ 
    149         int     se_index;               /* index of entry in ttys file */ 
    150         pid_t   se_process;             /* controlling process */ 
    151         time_t  se_started;             /* used to avoid thrashing */ 
    152         int     se_flags;               /* status of session */ 
    153         char    *se_device;             /* filename of port */ 
    154         se_cmd_t se_getty;              /* what to run on that port */ 
    155         se_cmd_t se_onerror;            /* See SE_ONERROR above */ 
    156         se_cmd_t se_onoption;           /* See SE_ONOPTION above */ 
    157         TAILQ_ENTRY(init_session) tqe; 
    158 } *session_t; 
    159  
    160 static TAILQ_HEAD(sessionshead, init_session) sessions = TAILQ_HEAD_INITIALIZER(sessions); 
    161  
    162 static void session_new(int, struct ttyent *); 
    163 static void session_free(session_t); 
    164 static void session_launch(session_t); 
    165 static void session_reap(session_t); 
    166 static void session_callback(void *, struct kevent *); 
    167  
    168 static char **construct_argv(char *); 
    169109static void setsecuritylevel(int); 
    170110static int getsecuritylevel(void); 
    171 static int setupargv(session_t, struct ttyent *); 
    172111static bool should_fsck(void); 
    173112 
     
    184123init_pre_kevent(void) 
    185124{ 
    186         session_t s; 
    187  
    188125        if (single_user_pid || runcom_pid) 
    189126                return; 
     
    201138         * than level 1, then put the kernel into secure mode. 
    202139         */ 
    203         if (getsecuritylevel() == 0) 
     140        if (getsecuritylevel() == 0) { 
    204141                setsecuritylevel(1); 
    205  
    206         TAILQ_FOREACH(s, &sessions, tqe) { 
    207                 if (s->se_process == 0) 
    208                         session_launch(s); 
    209         } 
    210 } 
    211  
    212 static void 
     142        } 
     143} 
     144 
     145void 
    213146stall(char *message, ...) 
    214147{ 
     
    221154} 
    222155 
    223 static int 
     156int 
    224157getsecuritylevel(void) 
    225158{ 
     
    237170} 
    238171 
    239 static void 
     172void 
    240173setsecuritylevel(int newlevel) 
    241174{ 
     
    260193 * Only called by children of init after forking. 
    261194 */ 
    262 static void 
     195void 
    263196setctty(const char *name, int flags) 
    264197{ 
     
    276209} 
    277210 
    278 static void 
     211void 
    279212single_user(void) 
    280213{ 
     
    316249} 
    317250 
    318 static void 
     251void 
    319252single_user_callback(void *obj __attribute__((unused)), struct kevent *kev __attribute__((unused))) 
    320253{ 
     
    339272 
    340273static struct timeval runcom_start_tv = { 0, 0 }; 
     274 
    341275/* 
    342276 * Run the system startup script. 
    343277 */ 
    344 static void 
     278void 
    345279runcom(void) 
    346280{ 
     
    390324} 
    391325 
    392 static void 
     326void 
    393327runcom_callback(void *obj __attribute__((unused)), struct kevent *kev __attribute__((unused))) 
    394328{ 
     
    422356} 
    423357 
    424 /* 
    425  * Construct an argument vector from a command line. 
    426  */ 
    427 char ** 
    428 construct_argv(command) 
    429         char *command; 
    430 { 
    431         int argc = 0; 
    432         char **argv = (char **) malloc(((strlen(command) + 1) / 2 + 1) 
    433                                                 * sizeof (char *)); 
    434         static const char separators[] = " \t"; 
    435  
    436         if ((argv[argc++] = strtok(command, separators)) == 0) 
    437                 return 0; 
    438         while ((argv[argc++] = strtok(NULL, separators))) 
    439                 continue; 
    440         return argv; 
    441 } 
    442  
    443 /* 
    444  * Deallocate a session descriptor. 
    445  */ 
    446  
    447 static void free_command(se_cmd_t *se_cmd) 
    448 { 
    449     if (se_cmd->path) { 
    450         free(se_cmd->path); 
    451         free(se_cmd->argv); 
    452     } 
    453 } 
    454  
    455 void 
    456 session_free(session_t s) 
    457 { 
    458         TAILQ_REMOVE(&sessions, s, tqe); 
    459         if (s->se_process) { 
    460                 if (kevent_mod(s->se_process, EVFILT_PROC, EV_ADD,  
    461                                         NOTE_EXIT, 0, &kqsimple_zombie_reaper) == -1) 
    462                         session_reap(s); 
    463                 else 
    464                         kill(s->se_process, SIGHUP); 
    465         } 
    466         free(s->se_device); 
    467         free_command(&s->se_getty); 
    468         free_command(&s->se_onerror); 
    469         free_command(&s->se_onoption); 
    470         free(s); 
    471 } 
    472  
    473 static int setup_command(se_cmd_t *se_cmd, char *command, char *arg ) 
    474 { 
    475         char *commandWithArg; 
    476  
    477         asprintf(&commandWithArg, "%s %s", command, arg); 
    478  
    479         free_command(se_cmd); 
    480  
    481         se_cmd->path = commandWithArg; 
    482         se_cmd->argv = construct_argv(commandWithArg); 
    483         if (se_cmd->argv == NULL) { 
    484                 free(se_cmd->path); 
    485                 se_cmd->path = NULL; 
    486                 return 0; 
    487         } 
    488         return 1; 
    489 } 
    490  
    491 /* 
    492  * Calculate getty and if useful window argv vectors. 
    493  */ 
    494 static int 
    495 setupargv(sp, typ) 
    496         session_t sp; 
    497         struct ttyent *typ; 
    498 { 
    499     char *type; 
    500  
    501     if ( !setup_command(&sp->se_getty, typ->ty_getty, typ->ty_name) ) 
    502     { 
    503         type = "getty"; 
    504         goto bad_args; 
    505     } 
    506  
    507     if (typ->ty_onerror 
    508     && !setup_command(&sp->se_onerror, typ->ty_onerror, typ->ty_name) ) 
    509     { 
    510         type = "onerror"; 
    511         goto bad_args; 
    512     } 
    513  
    514     if (typ->ty_onoption 
    515     && !setup_command(&sp->se_onoption, typ->ty_onoption, typ->ty_name) ) 
    516     { 
    517         type = "onoption"; 
    518         goto bad_args; 
    519     } 
    520  
    521     return 1; 
    522  
    523 bad_args: 
    524     syslog(LOG_WARNING, "can't parse %s for port %s", type, sp->se_device); 
    525     return 0; 
    526 } 
    527  
    528  
    529 /* 
    530  * Allocate a new session descriptor. 
    531  */ 
    532 void 
    533 session_new(session_index, typ) 
    534         int session_index; 
    535         struct ttyent *typ; 
    536 { 
    537         session_t s; 
    538  
    539         if ((typ->ty_status & TTY_ON) == 0 || 
    540             typ->ty_name == 0 || 
    541             typ->ty_getty == 0) 
    542                 return; 
    543  
    544         s = calloc(1, sizeof(struct init_session)); 
    545  
    546         s->se_callback = session_callback; 
    547         s->se_index = session_index; 
    548  
    549         TAILQ_INSERT_TAIL(&sessions, s, tqe); 
    550  
    551         asprintf(&s->se_device, "%s%s", _PATH_DEV, typ->ty_name); 
    552  
    553         if (setupargv(s, typ) == 0) 
    554                 session_free(s); 
    555 } 
    556  
    557 static void 
    558 session_launch(session_t s) 
    559 { 
    560         pid_t pid; 
    561         sigset_t mask; 
    562         se_cmd_t *se_cmd; 
    563         const char *session_type = NULL; 
    564         time_t current_time      = time(NULL); 
    565         bool is_loginwindow = false; 
    566  
    567         // Setup the default values; 
    568         switch (s->se_flags & SE_GETTY_LAUNCH) { 
    569         case SE_ONOPTION: 
    570                 if (s->se_onoption.path) { 
    571                         se_cmd       = &s->se_onoption; 
    572                         session_type = "onoption"; 
    573                         break; 
    574                 } 
    575                 /* No break */ 
    576         case SE_ONERROR: 
    577                 if (s->se_onerror.path) { 
    578                         se_cmd       = &s->se_onerror; 
    579                         session_type = "onerror"; 
    580                         break; 
    581                 } 
    582                 /* No break */ 
    583         case SE_COMMON: 
    584         default: 
    585                 se_cmd       = &s->se_getty; 
    586                 session_type = "getty"; 
    587                 break; 
    588         } 
    589  
    590         if (strcmp(se_cmd->argv[0], "/System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow") == 0) 
    591                 is_loginwindow = true; 
    592  
    593         pid = launchd_fork(); 
    594  
    595         if (pid == -1) { 
    596                 syslog(LOG_ERR, "can't fork for %s on port %s: %m", 
    597                                 session_type, s->se_device); 
    598                 return; 
    599         } 
    600  
    601         if (pid) { 
    602                 s->se_process = pid; 
    603                 s->se_started = time(NULL); 
    604                 s->se_flags  &= ~SE_GETTY_LAUNCH; // clear down getty launch type 
    605                 if (kevent_mod(pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, &s->se_callback) == -1) 
    606                         session_reap(s); 
    607                 return; 
    608         } 
    609  
    610         if (current_time > s->se_started && 
    611             current_time - s->se_started < GETTY_SPACING) { 
    612                 syslog(LOG_WARNING, "%s repeating too quickly on port %s, sleeping", 
    613                         session_type, s->se_device); 
    614                 sleep(GETTY_SLEEP); 
    615         } 
    616  
    617         sigemptyset(&mask); 
    618         sigprocmask(SIG_SETMASK, &mask, NULL); 
    619  
    620  
    621         if (!is_loginwindow) 
    622                 launchd_SessionCreate(); 
    623  
    624         execv(se_cmd->argv[0], se_cmd->argv); 
    625         stall("can't exec %s '%s' for port %s: %m", session_type, 
    626                 se_cmd->argv[0], s->se_device); 
    627         exit(EXIT_FAILURE); 
    628 } 
    629  
    630 static void 
    631 session_callback(void *obj, struct kevent *kev __attribute__((unused))) 
    632 { 
    633         session_t s = obj; 
    634  
    635         session_reap(s); 
    636         if (s->se_flags & SE_SHUTDOWN) { 
    637                 session_free(s); 
    638         } else { 
    639                 session_launch(s); 
    640         } 
    641 } 
    642  
    643 static void 
    644 session_reap(session_t s) 
    645 { 
    646         char *line; 
    647         int status; 
    648  
    649         if (!launchd_assumes(waitpid(s->se_process, &status, 0) == s->se_process)) 
    650                 return; 
    651  
    652         if (WIFSIGNALED(status)) { 
    653                 syslog(LOG_WARNING, "%s port %s exited abnormally: %s", 
    654                                 s->se_getty.path, s->se_device, strsignal(WTERMSIG(status))); 
    655                 s->se_flags |= SE_ONERROR;  
    656         } else if (WEXITSTATUS(status) == REALLY_EXIT_TO_CONSOLE) { 
    657                 /* WIFEXITED(status) assumed */ 
    658                 s->se_flags |= SE_ONOPTION; 
    659         } else { 
    660                 s->se_flags |= SE_ONERROR; 
    661         } 
    662  
    663         s->se_process = 0; 
    664         line = s->se_device + sizeof(_PATH_DEV) - 1; 
    665  
    666         if (logout(line)) 
    667                 logwtmp(line, "", ""); 
    668 } 
    669  
    670 /* 
    671  * This is an n-squared algorithm.  We hope it isn't run often... 
    672  */ 
    673 void 
    674 update_ttys(void) 
    675 { 
    676         session_t sp; 
    677         struct ttyent *typ; 
    678         int session_index = 0; 
    679         int devlen; 
    680  
    681         devlen = sizeof(_PATH_DEV) - 1; 
    682         while ((typ = getttyent())) { 
    683                 ++session_index; 
    684  
    685                 TAILQ_FOREACH(sp, &sessions, tqe) { 
    686                         if (strcmp(typ->ty_name, sp->se_device + devlen) == 0) 
    687                                 break; 
    688                 } 
    689  
    690                 if (sp == NULL) { 
    691                         session_new(session_index, typ); 
    692                         continue; 
    693                 } 
    694  
    695                 if (sp->se_index != session_index) { 
    696                         syslog(LOG_INFO, "port %s changed utmp index from %d to %d", 
    697                                sp->se_device, sp->se_index, 
    698                                session_index); 
    699                         sp->se_index = session_index; 
    700                 } 
    701  
    702                 if ((typ->ty_status & TTY_ON) == 0 || 
    703                     typ->ty_getty == 0) { 
    704                         session_free(sp); 
    705                         continue; 
    706                 } 
    707  
    708                 sp->se_flags &= ~SE_SHUTDOWN; 
    709  
    710                 if (setupargv(sp, typ) == 0) { 
    711                         syslog(LOG_WARNING, "can't parse getty for port %s", 
    712                                 sp->se_device); 
    713                         session_free(sp); 
    714                 } 
    715         } 
    716  
    717         endttyent(); 
    718 } 
    719  
    720 /* 
    721  * Block further logins. 
    722  */ 
    723 void 
    724 catatonia(void) 
    725 { 
    726         session_t s; 
    727  
    728         TAILQ_FOREACH(s, &sessions, tqe) 
    729                 s->se_flags |= SE_SHUTDOWN; 
    730 } 
    731  
    732 bool init_check_pid(pid_t p) 
    733 { 
    734         session_t s; 
    735  
    736         TAILQ_FOREACH(s, &sessions, tqe) { 
    737                 if (s->se_process == p) 
    738                         return true; 
    739         } 
    740  
     358bool 
     359init_check_pid(pid_t p) 
     360{ 
    741361        if (single_user_pid == p) 
    742362                return true; 
  • trunk/launchd/src/launchctl.1

    r20790 r23025  
    141141.Nm launchd 
    142142to prepare for shutdown by removing all jobs. 
    143 .It Ar reloadttys 
    144 Tell 
    145 .Nm launchd 
    146 to reread /etc/ttys. This option may go away in a future release. 
    147143.It Ar umask Op Ar newmask 
    148144Get or optionally set the 
  • trunk/launchd/src/launchctl.c

    r23014 r23025  
    135135static int touch_file(const char *path, mode_t m); 
    136136static void do_sysversion_sysctl(void); 
    137 static void workaround4465949(void); 
    138137static void do_application_firewall_magic(int sfd, launch_data_t thejob); 
    139138static void preheat_page_cache_hack(void); 
     
    186185        { "shutdown",   fyi_cmd,                "Prepare for system shutdown" }, 
    187186        { "singleuser", fyi_cmd,                "Switch to single-user mode" }, 
    188         { "reloadttys", fyi_cmd,                "Reload /etc/ttys" }, 
    189187        { "getrusage",  getrusage_cmd,          "Get resource usage statistics from launchd" }, 
    190188        { "log",        logupdate_cmd,          "Adjust the logging level or mask of launchd" }, 
     
    12801278        assumes(fwexec(SystemStarter_tool, false) != -1); 
    12811279 
    1282         workaround4465949(); 
    1283  
    12841280        if (path_check("/etc/rc.local")) { 
    12851281                const char *rc_local_tool[] = { _PATH_BSHELL, "/etc/rc.local", NULL }; 
     
    12881284 
    12891285        return 0; 
    1290 } 
    1291  
    1292 void 
    1293 workaround4465949(void) 
    1294 { 
    1295         const char *pbs_tool[] = { "/System/Library/CoreServices/pbs", NULL }; 
    1296         const char *lca_tool[] = { "/System/Library/CoreServices/Language Chooser.app/Contents/MacOS/Language Chooser", NULL}; 
    1297         char *const reloadttys_argv[] = { "reloadttys", NULL }; 
    1298         int wstatus; 
    1299         pid_t pbs_p; 
    1300  
    1301         if (path_check("/System/Library/LaunchDaemons/com.apple.loginwindow.plist")) { 
    1302                 return; 
    1303         } 
    1304  
    1305         if (path_check(pbs_tool[0]) && path_check(lca_tool[0]) && 
    1306                         !path_check("/var/db/.AppleSetupDone") && 
    1307                         path_check("/var/db/.RunLanguageChooserToo")) { 
    1308                 if (assumes((pbs_p = fwexec(pbs_tool, false)) != -1)) { 
    1309                         assumes(fwexec(lca_tool, true) != -1); 
    1310                         assumes(kill(pbs_p, SIGTERM) != -1); 
    1311                         assumes(waitpid(pbs_p, &wstatus, 0) != -1); 
    1312                 } 
    1313         } 
    1314  
    1315         assumes(fyi_cmd(1, reloadttys_argv) == 0); 
    13161286} 
    13171287 
     
    17641734{ 
    17651735        launch_data_t resp, msg; 
    1766         const char *lmsgk = LAUNCH_KEY_RELOADTTYS; 
     1736        const char *lmsgk = NULL; 
    17671737        int e, r = 0; 
    17681738 
     
    17761746        } else if (!strcmp(argv[0], "singleuser")) { 
    17771747                lmsgk = LAUNCH_KEY_SINGLEUSER; 
     1748        } else { 
     1749                return 1; 
    17781750        } 
    17791751 
  • trunk/launchd/src/launchd.c

    r23020 r23025  
    470470 
    471471        jobmgr_remove_all_inactive(root_jobmgr); 
    472  
    473         if (getpid() == 1) { 
    474                 catatonia(); 
    475         } 
    476472} 
    477473 
  • trunk/launchd/src/launchd.h

    r22956 r23025  
    5656void init_pre_kevent(void); 
    5757 
    58 void update_ttys(void); 
    59 void catatonia(void); 
    60  
    6158void mach_start_shutdown(void); 
    6259void mach_init_init(mach_port_t); 
  • trunk/launchd/src/launchd_unix_ipc.c

    r22943 r23025  
    353353                                resp = launch_data_new_errno(EACCES); 
    354354                        } 
    355                 } else if (!strcmp(cmd, LAUNCH_KEY_RELOADTTYS)) { 
    356                         update_ttys(); 
    357                         resp = launch_data_new_errno(0); 
    358355                } else if (!strcmp(cmd, LAUNCH_KEY_SHUTDOWN)) { 
    359356                        launchd_shutdown(); 
  • trunk/launchd/src/liblaunch_private.h

    r23007 r23025  
    3838#define LAUNCH_KEY_GETRESOURCELIMITS    "GetResourceLimits" 
    3939#define LAUNCH_KEY_SETRESOURCELIMITS    "SetResourceLimits" 
    40 #define LAUNCH_KEY_RELOADTTYS           "ReloadTTYS" 
    4140#define LAUNCH_KEY_SETLOGMASK           "SetLogMask" 
    4241#define LAUNCH_KEY_GETLOGMASK           "GetLogMask"