|
root / base / usr / src / zyginit / services / console-login
console-login Plain Text 118 lines 3.8 KB
  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);
}