1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
# Hammerhead override of services/hammerhead/console-login.toml shipped
# by zyginit. Removes the syslogd dependency so that:
#
# - console-login starts in the earliest tier that satisfies utmpd
# (so ttymon claims /dev/console as ctty before any other daemon)
# - syslogd's override (overrides/syslogd.toml) declares the reverse
# edge: requires = ["network", "console-login"]
#
# Without this override, both files together form a dependency cycle
# (console-login → syslogd → console-login) and zyginit refuses to boot
# with "depgraph: dependency cycle detected, cannot boot".
#
# Pairs with zyginit bug 001. Drop both overrides once the supervisor
# is fixed upstream.
[service]
name = "console-login"
description = "Console login (ttymon on /dev/console)"
type = "daemon"
[exec]
start = "/etc/zyginit/services/console-login/start.sh"
[dependencies]
requires = ["utmpd"]
[restart]
on = "failure"
delay = 5
max_retries = 3
[contract]
param = ["inherit", "noorphan"]
fatal = ["hwerr"]
#!/bin/zsh
# console-login — exec ttymon on /dev/console with a properly quoted prompt.
#
# Wrapping ttymon in a script (instead of inlining in exec.start) sidesteps
# zyginit's str.split-on-space tokenizer, which doesn't honor shell quotes.
# Inline the ttymon invocation here where the shell DOES quote correctly,
# then exec so ttymon becomes the supervisor's direct child.
set -e
set -u
# Write a LOGIN_PROCESS utmpx entry for the PID that's about to become
# ttymon (this script's PID, since we use `exec` below). ttymon's
# getty_account() (tmutmp.c) updates an existing entry — it does not
# create one — so without this, login(1) walks utmpx, finds nothing
# matching its PID, and exits with "No utmpx entry. You must exec
# login from the lowest level shell."
/etc/zyginit/services/console-login/write_login_utmpx co console $$
# -T sun-color: tell the login session to use the sun-color terminfo
# entry, which matches illumos's in-kernel `tem` console emulator.
# Without this, zshenv's fallback to TERM=xterm leaks raw ANSI escapes
# ((B, [B, etc.) through the zsh prompt because tem doesn't implement
# the full xterm spec.
exec /usr/lib/saf/ttymon \
-g \
-d /dev/console \
-l console \
-m ldterm,ttcompat \
-T sun-color \
-h \
-p "hammerhead console login: "
/*
* write_login_utmpx — write a LOGIN_PROCESS utmpx entry for a target PID.
*
* Usage: write_login_utmpx <ut_id> <ut_line> <ut_pid>
*
* Background: illumos `login(1)` walks utmpx and requires an entry whose
* ut_pid matches login's own PID. ttymon updates an existing entry via
* pututxline() — it does NOT create one. Standard illumos init writes
* INIT_PROCESS entries when spawning getty/ttymon from inittab; zyginit
* doesn't, so ttymon has nothing to update and login eventually errors
* out with "No utmpx entry. You must exec login from the lowest level
* shell."
*
* This helper writes a LOGIN_PROCESS entry for a target PID and exits.
* Called from console-login/start.sh just before `exec ttymon`, with
* $$ (the wrapper script's PID, which becomes ttymon's PID after exec)
* as the third argument.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <utmpx.h>
int
main(int argc, char **argv)
{
struct utmpx ux;
pid_t target_pid;
if (argc < 4) {
(void) fprintf(stderr,
"Usage: %s <ut_id> <ut_line> <ut_pid>\n", argv[0]);
return (1);
}
target_pid = (pid_t)atoi(argv[3]);
(void) memset(&ux, 0, sizeof (ux));
(void) strncpy(ux.ut_id, argv[1], sizeof (ux.ut_id));
(void) strncpy(ux.ut_line, argv[2], sizeof (ux.ut_line));
(void) strncpy(ux.ut_user, "LOGIN", sizeof (ux.ut_user));
ux.ut_pid = target_pid;
ux.ut_type = LOGIN_PROCESS;
(void) time(&ux.ut_tv.tv_sec);
setutxent();
if (pututxline(&ux) == NULL) {
(void) fprintf(stderr, "%s: pututxline failed\n", argv[0]);
endutxent();
return (1);
}
endutxent();
return (0);
}
|