- Anonymous memory can be reserved without being backed: large mappings, MAP_NORESERVE and PROT_NONE are recorded and each page appears, zeroed, on first touch -- from trap() for the program, from uva2ka() for the kernel on its behalf. WebKit reserves 4 GB at start and touches a sliver; backing it all failed with ENOMEM and Epiphany aborted. - r8169: the 8168G generation and later (the laptop's 8168H, XID 541) are taken from the firmware's out-of-band mode, get their PLL powered, the receive gate opened, and their PHY reached through the OCP window. The PHY's power-down bit is cleared; the old code kept it while restarting autonegotiation. Untested on the hardware so far. - The network thread follows each device's link into lwIP. The link was read once at attach, 0.02 s into boot; real autonegotiation takes seconds, so on hardware the interface stayed down for good. - Twelve terminals, switched with Ctrl+Alt+F1..F12 by default: the keys X uses, so the console and the desktop agree. AltGr+F-key is gone from the defaults (chvt -c altgr+F brings it back). - SO_PASSCRED on Unix sockets, with SCM_CREDENTIALS delivered by recvmsg. WebKit sets it on its IPC sockets and aborted when refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
204 lines
6.1 KiB
C
204 lines
6.1 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
//
|
|
// chvt N -- show virtual terminal N.
|
|
//
|
|
// The same name and the same argument as the Linux tool, because it does the
|
|
// same thing and nobody should have to learn a second one. The chord does
|
|
// this from the keyboard; this does it from a script, and from a serial
|
|
// console where there are no function keys to press.
|
|
//
|
|
// chvt report the active terminal, those in use, and the chord
|
|
// chvt 2 switch to /dev/tty2
|
|
// chvt -c <spec> set the switch chord
|
|
// chvt -c off unbind it entirely; chvt stays the only way to switch
|
|
//
|
|
// The chord is settable because the right value is a property of the *host*,
|
|
// not of SchOS. A display manager that grabs Ctrl+Alt+F<n> takes it before the
|
|
// guest sees anything, and it matches loosely -- extra modifiers do not get
|
|
// past it -- so a chord that works on one machine is dead on the next. The
|
|
// guest cannot detect this: a key the host swallowed is indistinguishable from
|
|
// a key nobody pressed. So it is a setting.
|
|
//
|
|
// chvt -c ctrl+alt+F Ctrl+Alt+F1..F12 (the default)
|
|
// chvt -c altgr+F AltGr+F1..F12
|
|
// chvt -c ctrl+shift+F Ctrl+Shift+F1..F12
|
|
// chvt -c alt+1 Alt+1..9
|
|
// chvt -c off no chord at all
|
|
//
|
|
// Whatever the modifiers are, they also bind minus and equals to the previous
|
|
// and next terminal in use -- Ctrl+Alt+- and Ctrl+Alt+= by default.
|
|
|
|
#include "core/types.h"
|
|
#include "uapi/user.h"
|
|
#include "uapi/fcntl.h"
|
|
#include "uapi/posix.h"
|
|
|
|
// No printf in lib/, and this needs one string and two small numbers.
|
|
static void
|
|
puts(const char *s)
|
|
{
|
|
int n = 0;
|
|
while (s[n]) n++;
|
|
write(1, (void *)s, n);
|
|
}
|
|
|
|
static void
|
|
putn(int v)
|
|
{
|
|
char b[12];
|
|
int i = 0;
|
|
if (v < 0) { write(1, "-", 1); v = -v; }
|
|
if (v == 0) { write(1, "0", 1); return; }
|
|
while (v > 0) { b[i++] = '0' + (v % 10); v /= 10; }
|
|
while (i-- > 0) write(1, &b[i], 1);
|
|
}
|
|
|
|
static int
|
|
num(const char *s)
|
|
{
|
|
int v = 0;
|
|
while (*s >= '0' && *s <= '9')
|
|
v = v * 10 + (*s++ - '0');
|
|
return v;
|
|
}
|
|
|
|
static int
|
|
same(const char *a, const char *b, int n)
|
|
{
|
|
for (int i = 0; i < n; i++)
|
|
if (a[i] != b[i]) return 0;
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
eq(const char *a, const char *b)
|
|
{
|
|
while (*a && *a == *b) { a++; b++; }
|
|
return *a == 0 && *b == 0;
|
|
}
|
|
|
|
// "ctrl+shift+F", "alt+1", "off". Modifiers by name, then a base: F for the
|
|
// function keys, 1 for the number row.
|
|
static int
|
|
parse_chord(const char *spec, struct vt_chord *out)
|
|
{
|
|
out->mods = 0;
|
|
out->base = 0;
|
|
|
|
if (eq(spec, "off") || eq(spec, "none"))
|
|
return 1; // no modifiers: the chord is disabled
|
|
|
|
const char *p = spec;
|
|
while (*p) {
|
|
const char *start = p;
|
|
while (*p && *p != '+') p++;
|
|
int n = (int)(p - start);
|
|
|
|
if (n == 4 && same(start, "ctrl", 4)) out->mods |= VTC_CTRL;
|
|
else if (n == 5 && same(start, "shift", 5)) out->mods |= VTC_SHIFT;
|
|
else if (n == 3 && same(start, "alt", 3)) out->mods |= VTC_ALT;
|
|
else if (n == 5 && same(start, "altgr", 5)) out->mods |= VTC_RALT;
|
|
else if (n == 1 && (*start == 'F' || *start == 'f')) out->base = VTC_BASE_F1;
|
|
else if (n == 1 && *start == '1') out->base = VTC_BASE_1;
|
|
else return 0;
|
|
|
|
if (*p == '+') p++;
|
|
}
|
|
// A base with no modifiers would bind a bare function key, which every
|
|
// full-screen program wants. Refuse it here rather than in the kernel, so
|
|
// the message can say why.
|
|
if (out->base && !out->mods)
|
|
return 0;
|
|
if (out->mods && !out->base)
|
|
out->base = VTC_BASE_F1;
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
show_chord(const struct vt_chord *c)
|
|
{
|
|
if (c->mods == 0) {
|
|
puts("off (use chvt N)\n");
|
|
return;
|
|
}
|
|
if (c->mods & VTC_CTRL) puts("Ctrl+");
|
|
if (c->mods & VTC_ALT) puts("Alt+");
|
|
if (c->mods & VTC_SHIFT) puts("Shift+");
|
|
if (c->mods & VTC_RALT) puts("AltGr+");
|
|
if (c->base == VTC_BASE_F1) puts("F1..F6");
|
|
else puts("1..6");
|
|
puts(", and ");
|
|
if (c->mods & VTC_CTRL) puts("Ctrl+");
|
|
if (c->mods & VTC_ALT) puts("Alt+");
|
|
if (c->mods & VTC_SHIFT) puts("Shift+");
|
|
if (c->mods & VTC_RALT) puts("AltGr+");
|
|
puts("- / + to step\n");
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
// /dev/console rather than fd 0: the caller may have redirected its input,
|
|
// and the terminal being asked about is the machine's, not whichever one
|
|
// this process happens to be reading from.
|
|
int fd = open("/dev/console", O_RDWR);
|
|
if (fd < 0) {
|
|
puts("chvt: cannot open /dev/console\n");
|
|
exit();
|
|
}
|
|
|
|
if (argc == 3 && argv[1][0] == '-' && argv[1][1] == 'c') {
|
|
struct vt_chord c;
|
|
if (!parse_chord(argv[2], &c)) {
|
|
puts("chvt: bad chord -- try ctrl+shift+F, alt+1, or off\n");
|
|
exit();
|
|
}
|
|
if (ioctl(fd, VT_SETCHORD, &c) < 0) {
|
|
puts("chvt: kernel refused that chord\n");
|
|
exit();
|
|
}
|
|
puts("chord set to ");
|
|
show_chord(&c);
|
|
exit();
|
|
}
|
|
|
|
if (argc == 1) {
|
|
struct vt_stat st;
|
|
if (ioctl(fd, VT_GETSTATE, &st) < 0) {
|
|
puts("chvt: VT_GETSTATE failed\n");
|
|
exit();
|
|
}
|
|
puts("active: tty");
|
|
putn(st.v_active);
|
|
puts("\nin use:");
|
|
for (int i = 1; i <= 16; i++)
|
|
if (st.v_state & (1 << i)) {
|
|
puts(" tty");
|
|
putn(i);
|
|
}
|
|
puts("\n");
|
|
struct vt_chord c;
|
|
if (ioctl(fd, VT_GETCHORD, &c) == 0) {
|
|
puts("chord: ");
|
|
show_chord(&c);
|
|
}
|
|
exit();
|
|
}
|
|
|
|
int n = num(argv[1]);
|
|
if (n < 1) {
|
|
puts("usage: chvt N\n");
|
|
exit();
|
|
}
|
|
|
|
// The argument goes by value, not through a pointer -- Linux defines
|
|
// VT_ACTIVATE that way and so does SchOS. Passing a pointer here would
|
|
// switch to whatever the address happened to be.
|
|
if (ioctl(fd, VT_ACTIVATE, (void *)(long)n) < 0) {
|
|
puts("chvt: no terminal ");
|
|
putn(n);
|
|
puts("\n");
|
|
exit();
|
|
}
|
|
exit();
|
|
}
|