| 1 | POSIX and init: |
| 2 | -------------- |
| 3 | |
| 4 | POSIX.1 does not define 'init' but it mentions it in a few places. |
| 5 | |
| 6 | B.2.2.2, p205 line 873: |
| 7 | |
| 8 | This is part of the extensive 'job control' glossary entry. |
| 9 | This specific reference says that 'init' must by default provide |
| 10 | protection from job control signals to jobs it starts -- |
| 11 | it sets SIGTSTP, SIGTTIN and SIGTTOU to SIG_IGN. |
| 12 | |
| 13 | B.2.2.2, p206 line 889: |
| 14 | |
| 15 | Here is a reference to 'vhangup'. It says, 'POSIX.1 does |
| 16 | not specify how controlling terminal access is affected by |
| 17 | a user logging out (that is, by a controlling process |
| 18 | terminating).' vhangup() is recognized as one way to handle |
| 19 | the problem. I'm not clear what happens in Reno; I have |
| 20 | the impression that when the controlling process terminates, |
| 21 | references to the controlling terminal are converted to |
| 22 | references to a 'dead' vnode. I don't know whether vhangup() |
| 23 | is required. |
| 24 | |
| 25 | B.2.2.2, p206 line 921: |
| 26 | |
| 27 | Orphaned process groups bear indirectly on this issue. A |
| 28 | session leader's process group is considered to be orphaned; |
| 29 | that is, it's immune to job control signals from the terminal. |
| 30 | |
| 31 | B.2.2.2, p233 line 2055: |
| 32 | |
| 33 | 'Historically, the implementation-dependent process that |
| 34 | inherits children whose parents have terminated without |
| 35 | waiting on them is called "init" and has a process ID of 1.' |
| 36 | |
| 37 | It goes on to note that it used to be the case that 'init' |
| 38 | was responsible for sending SIGHUP to the foreground process |
| 39 | group of a tty whose controlling process has exited, using |
| 40 | vhangup(). It is now the responsibility of the kernel to |
| 41 | do this when the controlling process calls _exit(). The |
| 42 | kernel is also responsible for sending SIGCONT to stopped |
| 43 | process groups that become orphaned. This is like old BSD |
| 44 | but entire process groups are signaled instead of individual |
| 45 | processes. |
| 46 | |
| 47 | In general it appears that the kernel now automatically |
| 48 | takes care of orphans, relieving 'init' of any responsibility. |
| 49 | Specifics are listed on the _exit() page (p50). |
| 50 | |
| 51 | On setsid(): |
| 52 | ----------- |
| 53 | |
| 54 | It appears that neither getty nor login call setsid(), so init must |
| 55 | do this -- seems reasonable. B.4.3.2 p 248 implies that this is the |
| 56 | way that 'init' should work; it says that setsid() should be called |
| 57 | after forking. |
| 58 | |
| 59 | Process group leaders cannot call setsid() -- another reason to |
| 60 | fork! Of course setsid() causes the current process to become a |
| 61 | process group leader, so we can only call setsid() once. Note that |
| 62 | the controlling terminal acquires the session leader's process |
| 63 | group when opened. |
| 64 | |
| 65 | Controlling terminals: |
| 66 | --------------------- |
| 67 | |
| 68 | B.7.1.1.3 p276: 'POSIX.1 does not specify a mechanism by which to |
| 69 | allocate a controlling terminal. This is normally done by a system |
| 70 | utility (such as 'getty') and is considered ... outside the scope |
| 71 | of POSIX.1.' It goes on to say that historically the first open() |
| 72 | of a tty in a session sets the controlling terminal. P130 has the |
| 73 | full details; nothing particularly surprising. |
| 74 | |
| 75 | The glossary p12 describes a 'controlling process' as the first |
| 76 | process in a session that acquires a controlling terminal. Access |
| 77 | to the terminal from the session is revoked if the controlling |
| 78 | process exits (see p50, in the discussion of process termination). |
| 79 | |
| 80 | Design notes: |
| 81 | ------------ |
| 82 | |
| 83 | your generic finite state machine |
| 84 | we are fascist about which signals we elect to receive, |
| 85 | even signals purportedly generated by hardware |
| 86 | handle fatal errors gracefully if possible (we reboot if we goof!!) |
| 87 | if we get a segmentation fault etc., print a message on the console |
| 88 | and spin for a while before rebooting |
| 89 | (this at least decreases the amount of paper consumed :-) |
| 90 | apply hysteresis to rapidly exiting gettys |
| 91 | check wait status of children we reap |
| 92 | don't wait for stopped children |
| 93 | don't use SIGCHILD, it's too expensive |
| 94 | but it may close windows and avoid races, sigh |
| 95 | look for EINTR in case we need to change state |
| 96 | init is responsible for utmp and wtmp maintenance (ick) |
| 97 | maybe now we can consider replacements? maintain them in parallel |
| 98 | init only removes utmp and closes out wtmp entries... |
| 99 | |
| 100 | necessary states and state transitions (gleaned from the man page): |
| 101 | 1: single user shell (with password checking?); on exit, go to 2 |
| 102 | 2: rc script: on exit 0, go to 3; on exit N (error), go to 1 |
| 103 | 3: read ttys file: on completion, go to 4 |
| 104 | 4: multi-user operation: on SIGTERM, go to 7; on SIGHUP, go to 5; |
| 105 | on SIGTSTP, go to 6 |
| 106 | 5: clean up mode (re-read ttys file, killing off controlling processes |
| 107 | on lines that are now 'off', starting them on lines newly 'on') |
| 108 | on completion, go to 4 |
| 109 | 6: boring mode (no new sessions); signals as in 4 |
| 110 | 7: death: send SIGHUP to all controlling processes, reap for 30 seconds, |
| 111 | then go to 1 (warn if not all processes died, i.e. wait blocks) |
| 112 | Given the -s flag, we start at state 1; otherwise state 2 |