Twelve login terminals, root only, console fixes, a faster build, a Niveus splash, and X back on evdev
- tty1-tty12 all run login; the image has only root. /dev/tty7..12 could not be written (cdev.c knew minors 10-16 only), which sent their jobs into a restart storm that took the supervisor down; fixed, and stat reports them as Linux's tty7..12. - Erasing text at a prompt did nothing: erase_one sent a bare backspace, which only moves; it and the echo path now send back-blank-back through vt_feed. - A white cursor block was left at the end of every line of a verbose boot: a line feed at the bottom scrolls the pixels, cursor included, and the cursor was erased after the scroll. It comes off first now. A blank cell is also marked dirty, which it was not. - ldlsd died with a general protection fault on real hardware in its variadic log function: Linux module code calls with an 8-byte-aligned stack and an unset %al, and the prologue's movaps faults. LDLS guest code is built with -mstackrealign. - make iso took over a minute for any change, because staging r8169 rewrote the same files and every mtime moved; it now replaces files only if their contents differ (about 10 s). - The loader's splash is redrawn in the boot manager's style, and the boot manager shows its cursor whenever a pointer device exists. - xf86-input-libinput is out of the image again: with it Xorg took both keyboard and pointer from libinput and, on the user's laptop, neither worked. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVRhxi9zpdW2uDUN4FVcao
This commit is contained in:
parent
b3785343f8
commit
2aef583aad
23 changed files with 290 additions and 155 deletions
40
Makefile
40
Makefile
|
|
@ -1120,22 +1120,30 @@ $(BUILD)/lib/%.o: lib/%.S
|
|||
# own -- a specific rule beats the pattern one below. ldls/ko.c, btf.c and
|
||||
# stub.c are freestanding and build unchanged for either side, which is the
|
||||
# whole point of having written them that way.
|
||||
# A Linux module is compiled with an 8-byte-aligned stack and, being kernel
|
||||
# code, never sets %al for a variadic call -- so it arrives in this code with
|
||||
# the stack off by eight and %al garbage. Any function here that takes `...`
|
||||
# then opens with `movaps %xmm0, -0xb0(%rbp)`, which faults on a misaligned
|
||||
# address: that was the general-protection fault in ldlsd on real hardware, in
|
||||
# the log function, the moment the first driver message was printed.
|
||||
# -mstackrealign makes every function re-align its own stack on entry.
|
||||
LDLS_ALIGN = -mstackrealign
|
||||
LDLS_GUEST = $(addprefix $(BUILD)/ldls/guest/, ko.o btf.o stub.o) \
|
||||
$(addprefix $(BUILD)/ldls/guest/kpi/, kpi.o pci.o io.o net.o skb.o string.o work.o thunk.o base.o)
|
||||
|
||||
$(BUILD)/ldls/guest/%.o: ldls/%.c ldls/ko.h ldls/btf.h ldls/stub.h
|
||||
@mkdir -p $(BUILD)/ldls/guest
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
$(CC) $(CFLAGS) $(LDLS_ALIGN) -c $< -o $@
|
||||
|
||||
# The KPI -- the Linux symbols, implemented. Guest-only: it reaches /dev/pci
|
||||
# and /dev/netdev, which exist on SchOS and nowhere else.
|
||||
$(BUILD)/ldls/guest/kpi/%.o: ldls/kpi/%.c ldls/kpi/kpi.h ldls/kpi/link_modes.inc
|
||||
@mkdir -p $(BUILD)/ldls/guest/kpi
|
||||
$(CC) $(CFLAGS) -I./ldls -c $< -o $@
|
||||
$(CC) $(CFLAGS) $(LDLS_ALIGN) -I./ldls -c $< -o $@
|
||||
|
||||
$(BUILD)/cmd/ldlsd: cmd/ldlsd/main.c $(ULIB) $(LDLS_GUEST)
|
||||
@mkdir -p $(BUILD)/cmd
|
||||
$(CC) $(CFLAGS) -I./ldls -c $< -o $(BUILD)/cmd/ldlsd.o
|
||||
$(CC) $(CFLAGS) $(LDLS_ALIGN) -I./ldls -c $< -o $(BUILD)/cmd/ldlsd.o
|
||||
$(LD) $(LDFLAGS) $(LD_LOWBASE) -e _start -Ttext 0x4000 -o $@ \
|
||||
$(BUILD)/cmd/ldlsd.o $(LDLS_GUEST) $(ULIB)
|
||||
$(OBJCOPY) -S $@
|
||||
|
|
@ -1427,21 +1435,33 @@ LDLS_FWDIR ?= /run/current-system/firmware
|
|||
LDLS_R8169 = drivers/net/phy/mdio-bus drivers/net/phy/libphy \
|
||||
drivers/net/phy/mdio_devres drivers/net/phy/realtek/realtek \
|
||||
drivers/net/ethernet/realtek/r8169
|
||||
# Every file is replaced only if its contents differ. sysroot.stamp records the
|
||||
# mtime of each staged file, `make iso` runs this every time, and rewriting the
|
||||
# same bytes moved every mtime -- which rebuilt the root image and compressed it
|
||||
# at zstd -19 (a minute) after a one-line kernel change.
|
||||
|
||||
ldls-r8169:
|
||||
@mkdir -p $(SYSROOT)/lib/modules $(SYSROOT)/lib/firmware/rtl_nic
|
||||
@set -e; list=; for m in $(LDLS_R8169); do \
|
||||
f=$$(ls $(LDLS_KDIR)/$$m.ko* | head -1); n=$$(basename $$m).ko; \
|
||||
case $$f in *.xz) xz -dc $$f;; *.zst) zstd -qdc $$f;; *) cat $$f;; esac \
|
||||
> $(SYSROOT)/lib/modules/$$n; \
|
||||
t=$(SYSROOT)/lib/modules/$$n; \
|
||||
case $$f in *.xz) xz -dc $$f;; *.zst) zstd -qdc $$f;; *) cat $$f;; esac > $$t.new; \
|
||||
if cmp -s $$t.new $$t; then rm -f $$t.new; else mv -f $$t.new $$t; fi; \
|
||||
list=$$list$${list:+,}/lib/modules/$$n; done; \
|
||||
cp /sys/kernel/btf/vmlinux $(SYSROOT)/lib/modules/btf; \
|
||||
if ! cmp -s /sys/kernel/btf/vmlinux $(SYSROOT)/lib/modules/btf; then \
|
||||
cp /sys/kernel/btf/vmlinux $(SYSROOT)/lib/modules/btf; fi; \
|
||||
printf '#!/bin/sh\nmkdir -p /var/log\nexec /bin/ldlsd %s /lib/modules/btf > /var/log/ldls-r8169.log 2>&1\n' \
|
||||
"$$list" > $(SYSROOT)/lib/modules/ldls-r8169.sh
|
||||
"$$list" > $(SYSROOT)/lib/modules/ldls-r8169.sh.new; \
|
||||
if cmp -s $(SYSROOT)/lib/modules/ldls-r8169.sh.new $(SYSROOT)/lib/modules/ldls-r8169.sh; then \
|
||||
rm -f $(SYSROOT)/lib/modules/ldls-r8169.sh.new; \
|
||||
else mv -f $(SYSROOT)/lib/modules/ldls-r8169.sh.new $(SYSROOT)/lib/modules/ldls-r8169.sh; fi
|
||||
@for f in $(LDLS_FWDIR)/rtl_nic/rtl8168*.fw*; do \
|
||||
n=$$(basename $$f); case $$n in \
|
||||
*.zst) zstd -qdc $$f > $(SYSROOT)/lib/firmware/rtl_nic/$${n%.zst};; \
|
||||
*.xz) xz -dc $$f > $(SYSROOT)/lib/firmware/rtl_nic/$${n%.xz};; \
|
||||
*) cp $$f $(SYSROOT)/lib/firmware/rtl_nic/;; esac; done
|
||||
*.zst) out=$${n%.zst}; zstd -qdc $$f > $(SYSROOT)/lib/firmware/rtl_nic/$$out.new;; \
|
||||
*.xz) out=$${n%.xz}; xz -dc $$f > $(SYSROOT)/lib/firmware/rtl_nic/$$out.new;; \
|
||||
*) out=$$n; cp $$f $(SYSROOT)/lib/firmware/rtl_nic/$$out.new;; esac; \
|
||||
d=$(SYSROOT)/lib/firmware/rtl_nic/$$out; \
|
||||
if cmp -s $$d.new $$d; then rm -f $$d.new; else mv -f $$d.new $$d; fi; done
|
||||
@echo "staged Linux r8169 ($(shell uname -r)) into $(SYSROOT)"
|
||||
|
||||
# `make iso` runs this first: the ISO ships Linux's r8169 set (NOTICE), so stage it whenever
|
||||
|
|
|
|||
|
|
@ -265,40 +265,57 @@ ui_logo(int y, int w)
|
|||
/* Where the bar goes. Derived, not stored, so nothing can set it and then have
|
||||
* the screen change underneath it.
|
||||
*
|
||||
* The bar is exactly the mark's width and sits directly beneath it: the two are
|
||||
* one object, and a bar wider than the mark it belongs to reads as a separate
|
||||
* thing that happens to be nearby.
|
||||
* The track is wider than the mark and sits beneath it: a mark with a recessed
|
||||
* track and one line of type, centred, on the same graphite the boot manager
|
||||
* uses. Laid out from the middle outwards so it reads the same at 800x600 and
|
||||
* at 4K. S() is defined further down with the rest of the Niveus code, so the
|
||||
* scale is applied through SC directly.
|
||||
*/
|
||||
static void
|
||||
bar_geometry(void)
|
||||
{
|
||||
PROG_W = ui_mark_width();
|
||||
PROG_H = BAR_H;
|
||||
PROG_W = 220 * SC;
|
||||
PROG_H = 6 * SC;
|
||||
PROG_X = ((int)FB.width - PROG_W) / 2;
|
||||
|
||||
int mark_h = (LOGO_H * PROG_W) / LOGO_W;
|
||||
int group_h = mark_h + MARK_GAP + PROG_H;
|
||||
int mw = ui_mark_width() * SC;
|
||||
if (mw > LOGO_W) mw = LOGO_W;
|
||||
int mark_h = (LOGO_H * mw) / LOGO_W;
|
||||
int gap = 34 * SC;
|
||||
int group_h = mark_h + gap + PROG_H;
|
||||
int top = ((int)FB.height - group_h) / 2;
|
||||
PROG_Y = top + mark_h + MARK_GAP;
|
||||
PROG_Y = top + mark_h + gap;
|
||||
}
|
||||
|
||||
static ui_u32 bg_at(int y);
|
||||
static void nv_backdrop(void);
|
||||
static int nv_width(const struct nvfont *f, const char *s);
|
||||
static void nv_text(const struct nvfont *f, int x, int base, const char *s,
|
||||
ui_u32 fg, ui_u32 bgtop, ui_u32 bgbot, int y0, int h);
|
||||
static void rrect(int x, int y, int w, int h, int r, ui_u32 top, ui_u32 bot,
|
||||
ui_u32 bgtop, ui_u32 bgbot, int bgy, int bgh);
|
||||
|
||||
void
|
||||
ui_splash(const char *subtitle)
|
||||
{
|
||||
if (!ACTIVE)
|
||||
return;
|
||||
|
||||
ui_clear();
|
||||
nv_backdrop();
|
||||
bar_geometry();
|
||||
|
||||
int w = PROG_W;
|
||||
int w = ui_mark_width() * SC;
|
||||
if (w > LOGO_W) w = LOGO_W;
|
||||
int mark_h = (LOGO_H * w) / LOGO_W;
|
||||
int top = PROG_Y - MARK_GAP - mark_h;
|
||||
int top = PROG_Y - 34 * SC - mark_h;
|
||||
|
||||
ui_u32 saved = LOGO_BG;
|
||||
LOGO_BG = bg_at(top + mark_h / 2);
|
||||
ui_logo(top, w);
|
||||
LOGO_BG = saved;
|
||||
|
||||
if (subtitle)
|
||||
ui_text_centered(PROG_Y + PROG_H + SUB_GAP, subtitle, SCH_DIM);
|
||||
ui_progress_label(subtitle);
|
||||
}
|
||||
|
||||
/* --- Niveus -----------------------------------------------------------------
|
||||
|
|
@ -912,6 +929,25 @@ ui_notice(const char *title, const char *const *lines, int n,
|
|||
box(title, lines, 0, n, button, hint);
|
||||
}
|
||||
|
||||
/* The track is a recess, the fill is the accent, lit from above -- the same two
|
||||
* materials as a well and a selected key in the boot manager. The fill is
|
||||
* redrawn from the left edge on every tick rather than extended, because its
|
||||
* rounded end moves; the bar is small enough that this costs nothing. */
|
||||
static void
|
||||
progress_paint(int px)
|
||||
{
|
||||
int r = PROG_H / 2;
|
||||
ui_u32 bg = bg_at(PROG_Y + PROG_H / 2);
|
||||
|
||||
rrect(PROG_X, PROG_Y, PROG_W, PROG_H, r, 0x0A0A0Bu, 0x151517u, bg, bg, 0, 1);
|
||||
if (px >= PROG_H) {
|
||||
ui_u32 top = mix(SCH_ACCENT, 0xFFFFFFu, 28, 100);
|
||||
ui_u32 bot = mix(SCH_ACCENT, 0x000000u, 24, 100);
|
||||
rrect(PROG_X + 1, PROG_Y + 1, px - 2, PROG_H - 2, r - 1, top, bot,
|
||||
0x0A0A0Bu, 0x151517u, PROG_Y, PROG_H);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ui_progress_begin(const char *label, ui_u32 total)
|
||||
{
|
||||
|
|
@ -924,10 +960,7 @@ ui_progress_begin(const char *label, ui_u32 total)
|
|||
PROG_LAST_PX = 0;
|
||||
PROG_ACTIVE = 1;
|
||||
|
||||
/* The unfilled track: a recess, not a colour. Drawn once -- repainting it
|
||||
* on every tick is what makes a progress bar flicker. */
|
||||
ui_fill_rect(PROG_X, PROG_Y, PROG_W, PROG_H, 0x1B1F28u);
|
||||
ui_fill_rect(PROG_X, PROG_Y, PROG_W, 1, 0x101319u);
|
||||
progress_paint(0);
|
||||
if (label)
|
||||
ui_progress_label(label);
|
||||
}
|
||||
|
|
@ -938,11 +971,16 @@ ui_progress_label(const char *label)
|
|||
if (!ACTIVE || !label)
|
||||
return;
|
||||
|
||||
/* Clear the line first. A shorter label after a longer one would otherwise
|
||||
* leave the tail of the old one behind. */
|
||||
int y = PROG_Y + PROG_H + SUB_GAP;
|
||||
ui_fill_rect(0, y, (int)FB.width, GLYPH_H, SCH_BG);
|
||||
ui_text_centered(y, label, SCH_DIM);
|
||||
/* Repaint the backdrop under the line first. A shorter label after a longer
|
||||
* one would otherwise leave the tail of the old one behind. */
|
||||
int h = nv_height(F_BODY) + 4 * SC;
|
||||
int y = PROG_Y + PROG_H + 18 * SC;
|
||||
for (int r = 0; r < h; r++)
|
||||
ui_fill_rect(0, y + r, (int)FB.width, 1, bg_at(y + r));
|
||||
|
||||
int tw = nv_width(F_BODY, label);
|
||||
nv_text(F_BODY, ((int)FB.width - tw) / 2, y + F_BODY->ascent, label, NV_TXT3,
|
||||
bg_at(y), bg_at(y + h), y, h);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -956,16 +994,8 @@ ui_progress_tick(ui_u32 done)
|
|||
PROG_DONE = done;
|
||||
|
||||
int px = (int)(((ui_u64)PROG_DONE * (ui_u64)PROG_W) / PROG_TOTAL);
|
||||
|
||||
/* Only the newly filled part. Filling from zero each time is O(width) per
|
||||
* tick and visibly slower than the thing it is reporting on. */
|
||||
if (px > PROG_LAST_PX) {
|
||||
/* The fill is metal too, shaded across the bar's height, so it looks
|
||||
* like the same material as the mark rather than a coloured rectangle
|
||||
* that happens to be underneath it. */
|
||||
for (int r = 0; r < PROG_H; r++)
|
||||
ui_fill_rect(PROG_X + PROG_LAST_PX, PROG_Y + r,
|
||||
px - PROG_LAST_PX, 1, metal(r, PROG_H));
|
||||
progress_paint(px);
|
||||
PROG_LAST_PX = px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1063,15 +1063,15 @@ pointer_poll(void)
|
|||
}
|
||||
|
||||
/* Wait for a key, a click on a key, or the pointer moving onto one.
|
||||
*
|
||||
* The cursor is shown whenever a pointer device is present: hiding it until
|
||||
* something moved left a machine whose pointer sends no events to the
|
||||
* loader with nothing on screen to say a pointer was even looked for.
|
||||
*
|
||||
* `budget` is a countdown in milliseconds that survives across calls: a
|
||||
* caller that returns here after a hover continues the same ten seconds
|
||||
* instead of being given a fresh ten. NULL waits for ever.
|
||||
*
|
||||
* The cursor stays hidden until the pointer has actually done something. The
|
||||
* firmware's console layer installs a pointer protocol whether or not a mouse
|
||||
* is attached, so "a protocol exists" proves nothing -- and a cursor parked in
|
||||
* the middle of the menu of a laptop with no mouse is worse than none. */
|
||||
*/
|
||||
static int
|
||||
wait_event(EFI_INPUT_KEY *key, int *item, UINTN *budget)
|
||||
{
|
||||
|
|
@ -1082,6 +1082,8 @@ wait_event(EFI_INPUT_KEY *key, int *item, UINTN *budget)
|
|||
PTR_X = (int)ui_width() / 2;
|
||||
PTR_Y = (int)ui_height() / 2;
|
||||
}
|
||||
if (have)
|
||||
PTR_ACTIVE = 1;
|
||||
ui_cursor(PTR_X, PTR_Y, PTR_ACTIVE);
|
||||
for (;;) {
|
||||
if (ST->ConIn && !EFI_ERROR(ST->ConIn->ReadKeyStroke(ST->ConIn, key)))
|
||||
|
|
@ -1094,6 +1096,10 @@ wait_event(EFI_INPUT_KEY *key, int *item, UINTN *budget)
|
|||
PTR_RESCANS++;
|
||||
pointers_find();
|
||||
have = PTR_NREL + PTR_NABS;
|
||||
if (have && !PTR_ACTIVE) {
|
||||
PTR_ACTIVE = 1;
|
||||
ui_cursor(PTR_X, PTR_Y, 1);
|
||||
}
|
||||
}
|
||||
if (have) {
|
||||
int e = pointer_poll();
|
||||
|
|
|
|||
|
|
@ -75,5 +75,5 @@ through ACPI, and reach X as a mouse: pointer, click and tap.
|
|||
- **Touchpads are mice**: no two-finger scroll, no gestures, no palm rejection.
|
||||
- **No resolution change from inside X.** The mode is the console's; `schmode` changes the
|
||||
`vgpud` head only, and the loader's menu is where a real panel's mode is chosen.
|
||||
- **Runs as an ordinary user.** `startx` as `schos` works by group permission alone
|
||||
([users.md](users.md)); X itself is still a single seat with no logind or seatd.
|
||||
- **Runs as an ordinary user** where there is one: `startx` works by group permission alone
|
||||
([users.md](users.md)); the image has only root; X itself is still a single seat with no logind or seatd.
|
||||
|
|
|
|||
|
|
@ -6,15 +6,15 @@ the part that makes it a multi-user system.
|
|||
|
||||
## What you meet
|
||||
|
||||
- **`login` on tty1–tty5.** `etc/schos-getty` takes the terminal back from
|
||||
whoever had it and runs `login`, which asks who is there and starts their
|
||||
shell; when the shell exits `schinit` starts the prompt again.
|
||||
- **tty6 is a root shell with no login**, on purpose: the way in when login
|
||||
itself is what is broken.
|
||||
- **Two accounts in the image.** `root`, and `schos` (uid 1000, home
|
||||
`/home/schos`, in `wheel tty video input audio cdrom`). Both have empty
|
||||
passwords, so `login` lets them in without asking — it is a live image.
|
||||
`passwd` sets one.
|
||||
- **`login` on all twelve terminals, tty1–tty12.** `etc/schos-getty` takes the
|
||||
terminal back from whoever had it and runs `login`, which asks who is there
|
||||
and starts their shell; when the shell exits `schinit` starts the prompt
|
||||
again. Alt+F1…F12 (or Ctrl+Alt+F1…F12) switches between them. (There is no
|
||||
longer a login-free root shell on tty6.)
|
||||
- **One account in the image: `root`**, with an empty password, so `login` lets
|
||||
it in without asking — it is a live image. `passwd` sets one. More users are
|
||||
an `adduser` away; `wheel` is empty, so `su` and `doas` have no one to serve
|
||||
until then.
|
||||
- **`su` and `passwd`** (`cmd/su`, `cmd/passwd`) are setuid root and small
|
||||
programs of their own, not toybox applets: toybox is one binary under every
|
||||
name, and a setuid copy of it can be asked for any applet by naming it, as
|
||||
|
|
@ -61,8 +61,8 @@ kernel's devices with the answers the kernel gave.
|
|||
|
||||
Everything in the image is owned by root: the build host's user means nothing
|
||||
inside it. `mkschfs --owners FILE` takes the exceptions, one `path uid gid
|
||||
[mode]` per line (`tools/posix/mkaroot.sh` writes it: `/home/schos 1000 1000
|
||||
0700`, and the modes of `/tmp`, `/var/tmp` and `/root`). The setuid bits are set
|
||||
[mode]` per line (`tools/posix/mkaroot.sh` writes it: the modes of `/tmp`,
|
||||
`/var/tmp` and `/root`). The setuid bits are set
|
||||
on `su`, `passwd` and `doas` in the root tree directly, because `apk` run as an
|
||||
ordinary user may have dropped them.
|
||||
|
||||
|
|
|
|||
20
etc/schinit/tty10-shell.job
Normal file
20
etc/schinit/tty10-shell.job
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# A login on /dev/tty10: every one of the twelve virtual terminals asks who is there.
|
||||
# Alt+F10 (or Ctrl+Alt+F10) shows it. Twelve manifests rather than one with a
|
||||
# range, because schinit has no notion of a template.
|
||||
|
||||
Label = os.schos.tty10-shell
|
||||
Program = /bin/sh
|
||||
Args = sh /etc/schos-getty
|
||||
RunAtLoad = yes
|
||||
KeepAlive = yes
|
||||
|
||||
Environment = TERM=linux
|
||||
Environment = PATH=/bin:/usr/bin
|
||||
|
||||
ControllingTerminal = yes
|
||||
|
||||
StandardIn = /dev/tty10
|
||||
StandardOut = /dev/tty10
|
||||
StandardError = /dev/tty10
|
||||
|
||||
ThrottleInterval = 1
|
||||
20
etc/schinit/tty11-shell.job
Normal file
20
etc/schinit/tty11-shell.job
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# A login on /dev/tty11: every one of the twelve virtual terminals asks who is there.
|
||||
# Alt+F11 (or Ctrl+Alt+F11) shows it. Twelve manifests rather than one with a
|
||||
# range, because schinit has no notion of a template.
|
||||
|
||||
Label = os.schos.tty11-shell
|
||||
Program = /bin/sh
|
||||
Args = sh /etc/schos-getty
|
||||
RunAtLoad = yes
|
||||
KeepAlive = yes
|
||||
|
||||
Environment = TERM=linux
|
||||
Environment = PATH=/bin:/usr/bin
|
||||
|
||||
ControllingTerminal = yes
|
||||
|
||||
StandardIn = /dev/tty11
|
||||
StandardOut = /dev/tty11
|
||||
StandardError = /dev/tty11
|
||||
|
||||
ThrottleInterval = 1
|
||||
20
etc/schinit/tty12-shell.job
Normal file
20
etc/schinit/tty12-shell.job
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# A login on /dev/tty12: every one of the twelve virtual terminals asks who is there.
|
||||
# Alt+F12 (or Ctrl+Alt+F12) shows it. Twelve manifests rather than one with a
|
||||
# range, because schinit has no notion of a template.
|
||||
|
||||
Label = os.schos.tty12-shell
|
||||
Program = /bin/sh
|
||||
Args = sh /etc/schos-getty
|
||||
RunAtLoad = yes
|
||||
KeepAlive = yes
|
||||
|
||||
Environment = TERM=linux
|
||||
Environment = PATH=/bin:/usr/bin
|
||||
|
||||
ControllingTerminal = yes
|
||||
|
||||
StandardIn = /dev/tty12
|
||||
StandardOut = /dev/tty12
|
||||
StandardError = /dev/tty12
|
||||
|
||||
ThrottleInterval = 1
|
||||
|
|
@ -1,13 +1,6 @@
|
|||
# An interactive shell on /dev/tty3.
|
||||
#
|
||||
# NVT is 6 (include/dev/vt.h) and the kernel creates all six terminals, but only
|
||||
# two ever had anything running on them -- so Alt+F3 switched to a terminal
|
||||
# that was working perfectly and had nobody to talk to, which looks exactly
|
||||
# like a broken one.
|
||||
#
|
||||
# Identical to tty2-shell apart from the number. Six manifests rather than one
|
||||
# with a range, because schinit has no notion of a template and inventing one
|
||||
# for six lines each is the wrong trade.
|
||||
# A login on /dev/tty3: every one of the twelve virtual terminals asks who is there.
|
||||
# Alt+F3 (or Ctrl+Alt+F3) shows it. Twelve manifests rather than one with a
|
||||
# range, because schinit has no notion of a template.
|
||||
|
||||
Label = os.schos.tty3-shell
|
||||
Program = /bin/sh
|
||||
|
|
|
|||
|
|
@ -1,13 +1,6 @@
|
|||
# An interactive shell on /dev/tty4.
|
||||
#
|
||||
# NVT is 6 (include/dev/vt.h) and the kernel creates all six terminals, but only
|
||||
# two ever had anything running on them -- so Alt+F4 switched to a terminal
|
||||
# that was working perfectly and had nobody to talk to, which looks exactly
|
||||
# like a broken one.
|
||||
#
|
||||
# Identical to tty2-shell apart from the number. Six manifests rather than one
|
||||
# with a range, because schinit has no notion of a template and inventing one
|
||||
# for six lines each is the wrong trade.
|
||||
# A login on /dev/tty4: every one of the twelve virtual terminals asks who is there.
|
||||
# Alt+F4 (or Ctrl+Alt+F4) shows it. Twelve manifests rather than one with a
|
||||
# range, because schinit has no notion of a template.
|
||||
|
||||
Label = os.schos.tty4-shell
|
||||
Program = /bin/sh
|
||||
|
|
|
|||
|
|
@ -1,13 +1,6 @@
|
|||
# An interactive shell on /dev/tty5.
|
||||
#
|
||||
# NVT is 6 (include/dev/vt.h) and the kernel creates all six terminals, but only
|
||||
# two ever had anything running on them -- so Alt+F5 switched to a terminal
|
||||
# that was working perfectly and had nobody to talk to, which looks exactly
|
||||
# like a broken one.
|
||||
#
|
||||
# Identical to tty2-shell apart from the number. Six manifests rather than one
|
||||
# with a range, because schinit has no notion of a template and inventing one
|
||||
# for six lines each is the wrong trade.
|
||||
# A login on /dev/tty5: every one of the twelve virtual terminals asks who is there.
|
||||
# Alt+F5 (or Ctrl+Alt+F5) shows it. Twelve manifests rather than one with a
|
||||
# range, because schinit has no notion of a template.
|
||||
|
||||
Label = os.schos.tty5-shell
|
||||
Program = /bin/sh
|
||||
|
|
|
|||
|
|
@ -1,27 +1,15 @@
|
|||
# A root shell on /dev/tty6, with no login: the way in when login itself is
|
||||
# what has broken. Every other terminal asks who is there.
|
||||
#
|
||||
# An interactive shell on /dev/tty6.
|
||||
#
|
||||
# NVT is 6 (include/dev/vt.h) and the kernel creates all six terminals, but only
|
||||
# two ever had anything running on them -- so Alt+F6 switched to a terminal
|
||||
# that was working perfectly and had nobody to talk to, which looks exactly
|
||||
# like a broken one.
|
||||
#
|
||||
# Identical to tty2-shell apart from the number. Six manifests rather than one
|
||||
# with a range, because schinit has no notion of a template and inventing one
|
||||
# for six lines each is the wrong trade.
|
||||
# A login on /dev/tty6: every one of the twelve virtual terminals asks who is there.
|
||||
# Alt+F6 (or Ctrl+Alt+F6) shows it. Twelve manifests rather than one with a
|
||||
# range, because schinit has no notion of a template.
|
||||
|
||||
Label = os.schos.tty6-shell
|
||||
Program = /bin/zsh
|
||||
Args = -zsh
|
||||
Program = /bin/sh
|
||||
Args = sh /etc/schos-getty
|
||||
RunAtLoad = yes
|
||||
KeepAlive = yes
|
||||
|
||||
Environment = TERM=linux
|
||||
Environment = PATH=/bin:/usr/bin
|
||||
Environment = HOME=/root
|
||||
Environment = SHELL=/bin/zsh
|
||||
|
||||
ControllingTerminal = yes
|
||||
|
||||
|
|
|
|||
20
etc/schinit/tty7-shell.job
Normal file
20
etc/schinit/tty7-shell.job
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# A login on /dev/tty7: every one of the twelve virtual terminals asks who is there.
|
||||
# Alt+F7 (or Ctrl+Alt+F7) shows it. Twelve manifests rather than one with a
|
||||
# range, because schinit has no notion of a template.
|
||||
|
||||
Label = os.schos.tty7-shell
|
||||
Program = /bin/sh
|
||||
Args = sh /etc/schos-getty
|
||||
RunAtLoad = yes
|
||||
KeepAlive = yes
|
||||
|
||||
Environment = TERM=linux
|
||||
Environment = PATH=/bin:/usr/bin
|
||||
|
||||
ControllingTerminal = yes
|
||||
|
||||
StandardIn = /dev/tty7
|
||||
StandardOut = /dev/tty7
|
||||
StandardError = /dev/tty7
|
||||
|
||||
ThrottleInterval = 1
|
||||
20
etc/schinit/tty8-shell.job
Normal file
20
etc/schinit/tty8-shell.job
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# A login on /dev/tty8: every one of the twelve virtual terminals asks who is there.
|
||||
# Alt+F8 (or Ctrl+Alt+F8) shows it. Twelve manifests rather than one with a
|
||||
# range, because schinit has no notion of a template.
|
||||
|
||||
Label = os.schos.tty8-shell
|
||||
Program = /bin/sh
|
||||
Args = sh /etc/schos-getty
|
||||
RunAtLoad = yes
|
||||
KeepAlive = yes
|
||||
|
||||
Environment = TERM=linux
|
||||
Environment = PATH=/bin:/usr/bin
|
||||
|
||||
ControllingTerminal = yes
|
||||
|
||||
StandardIn = /dev/tty8
|
||||
StandardOut = /dev/tty8
|
||||
StandardError = /dev/tty8
|
||||
|
||||
ThrottleInterval = 1
|
||||
20
etc/schinit/tty9-shell.job
Normal file
20
etc/schinit/tty9-shell.job
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# A login on /dev/tty9: every one of the twelve virtual terminals asks who is there.
|
||||
# Alt+F9 (or Ctrl+Alt+F9) shows it. Twelve manifests rather than one with a
|
||||
# range, because schinit has no notion of a template.
|
||||
|
||||
Label = os.schos.tty9-shell
|
||||
Program = /bin/sh
|
||||
Args = sh /etc/schos-getty
|
||||
RunAtLoad = yes
|
||||
KeepAlive = yes
|
||||
|
||||
Environment = TERM=linux
|
||||
Environment = PATH=/bin:/usr/bin
|
||||
|
||||
ControllingTerminal = yes
|
||||
|
||||
StandardIn = /dev/tty9
|
||||
StandardOut = /dev/tty9
|
||||
StandardError = /dev/tty9
|
||||
|
||||
ThrottleInterval = 1
|
||||
|
|
@ -302,7 +302,7 @@ consputc(int c)
|
|||
uartputc('\b'); uartputc(' '); uartputc('\b');
|
||||
if (!cons_serial_only) {
|
||||
struct vt *v = vt_current();
|
||||
vt_putc(v, '\b'); vt_putc(v, ' '); vt_putc(v, '\b');
|
||||
vt_feed(v, '\b'); vt_feed(v, ' '); vt_feed(v, '\b');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -452,8 +452,12 @@ erase_one(struct vt *v)
|
|||
v->in.e--;
|
||||
if (v->tio.c_lflag & ECHOE) {
|
||||
if (v == vt_current()) { uartputc('\b'); uartputc(' '); uartputc('\b'); }
|
||||
if (!cons_serial_only)
|
||||
vt_putc(v, '\b');
|
||||
// Back, blank, back -- and through vt_feed, which keeps the text cursor
|
||||
// in step. A bare \b only moves (see vt.c), so this used to leave the
|
||||
// rubbed-out character on screen and the cursor block behind it.
|
||||
if (!cons_serial_only) {
|
||||
vt_feed(v, '\b'); vt_feed(v, ' '); vt_feed(v, '\b');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -149,9 +149,10 @@ memread(struct inode *ip, uint64 off, char *dst, int n)
|
|||
case 1: return consoleread(ip, off, dst, n);
|
||||
case 2: return nullread(ip, off, dst, n);
|
||||
case 3: return consoleread(ip, off, dst, n);
|
||||
/* 10 = /dev/tty, 11..16 = /dev/tty1..tty6. consoleread resolves the
|
||||
/* 10 = /dev/tty, 11..22 = /dev/tty1..tty12. consoleread resolves the
|
||||
minor to a terminal; see vt_for_minor(). */
|
||||
case 10: case 11: case 12: case 13: case 14: case 15: case 16:
|
||||
case 17: case 18: case 19: case 20: case 21: case 22:
|
||||
return consoleread(ip, off, dst, n);
|
||||
case 5: return zeroread(ip, off, dst, n);
|
||||
case 7: return zeroread(ip, off, dst, n); // /dev/full reads as zeros
|
||||
|
|
@ -169,6 +170,7 @@ memwrite(struct inode *ip, uint64 off, char *dst, int n)
|
|||
switch(ip->minor) {
|
||||
case 1: return consolewrite(ip, off, dst, n);
|
||||
case 10: case 11: case 12: case 13: case 14: case 15: case 16:
|
||||
case 17: case 18: case 19: case 20: case 21: case 22:
|
||||
return consolewrite(ip, off, dst, n);
|
||||
case 7: return fullwrite(ip, off, dst, n); // /dev/full: always ENOSPC
|
||||
case 3: // /dev/keyboard: discarded
|
||||
|
|
|
|||
|
|
@ -406,6 +406,11 @@ draw_glyph_px(int x, int y, uint32 cp, uint32 fg, uint32 bg)
|
|||
for (int c = 0; c < cell_w; c++)
|
||||
gfx_draw_pixel(x + c, y + r, bg);
|
||||
|
||||
// Dirty before the early return: a blank cell is a background fill and
|
||||
// nothing else, and that fill is what rubs the text cursor out. Marked
|
||||
// only after the glyph, the blank was drawn to the back buffer and never
|
||||
// copied to the screen -- a block left at the end of every line.
|
||||
dirty(x, y, x + cell_w - 1, y + cell_h - 1);
|
||||
if (cp == ' ')
|
||||
return; // nothing to draw over the background
|
||||
|
||||
|
|
|
|||
|
|
@ -1241,20 +1241,26 @@ vt_cycle(int dir)
|
|||
void
|
||||
vt_feed(struct vt *v, int c)
|
||||
{
|
||||
// The grid is the truth, so the old cursor cell can be repainted from it
|
||||
// *after* the byte is consumed -- which lets two cases cost nothing:
|
||||
// - a byte inside an escape sequence changes nothing on screen;
|
||||
// - a plain glyph is drawn over the cell the cursor sat on, which repaints
|
||||
// it anyway (unless a wrap is pending, when it lands on the next line).
|
||||
// A plain glyph is drawn over the cell the cursor sits on, which repaints it
|
||||
// anyway (unless a wrap is pending, when it lands on the next line), so the
|
||||
// cursor needs no separate erase there.
|
||||
int mid = v->esc_state != VE_NORMAL;
|
||||
int over = !mid && !v->wrap_pending && c >= 0x20 && c < 0x7f &&
|
||||
v->u8_need == 0;
|
||||
|
||||
if (over) {
|
||||
vt_feed_1(v, c);
|
||||
if (mid && v->esc_state != VE_NORMAL)
|
||||
return;
|
||||
if (over)
|
||||
v->curs_drawn = 0;
|
||||
else
|
||||
cursor_draw(v);
|
||||
return;
|
||||
}
|
||||
|
||||
// Anything else may move the cursor, and a line feed at the bottom scrolls
|
||||
// the *pixels*, block and all. So the cursor comes off first. Erased after
|
||||
// the scroll, it was repainted where the cell had been and the old block
|
||||
// went up a row with the text: a white block at the end of every line of a
|
||||
// verbose boot.
|
||||
cursor_erase(v);
|
||||
vt_feed_1(v, c);
|
||||
cursor_draw(v);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ static uint64
|
|||
linux_tty_rdev(uint32 major, uint32 minor)
|
||||
{
|
||||
if (major == 1 && minor == 0) return linux_makedev(4, 0);
|
||||
if (major == 1 && minor >= 11 && minor <= 16) return linux_makedev(4, minor - 10);
|
||||
if (major == 1 && minor >= 11 && minor <= 22) return linux_makedev(4, minor - 10);
|
||||
if (major == 1 && minor == 10) return linux_makedev(5, 0);
|
||||
if (major == 1 && minor == 1) return linux_makedev(5, 1);
|
||||
// Pseudo-terminals, as Linux numbers them: ptmx (5, 2), slaves 136.
|
||||
|
|
|
|||
|
|
@ -76,6 +76,5 @@ libinput-udev
|
|||
libseat
|
||||
seatd
|
||||
seatd-launch
|
||||
xf86-input-libinput
|
||||
# lsusb that reads /sys/bus/usb/devices, which busybox's does not.
|
||||
usbutils
|
||||
|
|
|
|||
|
|
@ -181,7 +181,6 @@ xcalc-1.1.3-r0.apk 2f0d9ab5674a5f82f4adfb6dd5f0a9c944421feea2d6aaf18998b0326fe4c
|
|||
xclock-1.1.1-r0.apk ae2a3cb515664cf34dd9cd0f81945cad75d0b6bbf44696830f29f1ab4713b475 community
|
||||
xeyes-1.3.1-r0.apk 4b31dabe8d7f5000d82a24445972859bf960c1b07bca3d4f87e80b3c710902c6 community
|
||||
xf86-input-evdev-2.11.0-r0.apk 1f3fcd3e837b43ad5e32005e03095b547ddbfc25973f0511e9ff74bf342d2fe0 community
|
||||
xf86-input-libinput-1.5.0-r0.apk 2bd4b9257f755bc68c7460068821e954ee6ca484e6b05637e673d5b9abace0e8 community
|
||||
xf86-video-fbdev-0.5.0-r6.apk 6a8a1b16f82d8810896f00c00b356c8b8d923e9aa0ce64737ae8274ca82f507a community
|
||||
xinit-1.4.4-r0.apk efb5dc1e7929824f5add7d5d51d0ecb34ecfd0a773dfca4f061adc8a353b234f community
|
||||
xkbcomp-1.5.0-r0.apk 8bfbd3c8ce7180e8cf599d5a0b791993b61fa98f3a19c47aaf5fcbe30c12d0ba main
|
||||
|
|
|
|||
|
|
@ -358,46 +358,24 @@ chmod 1777 "$ROOT/tmp" "$ROOT/var/tmp"
|
|||
# --- accounts -------------------------------------------------------------------
|
||||
#
|
||||
# Alpine's baselayout has root and the system accounts, with root's password
|
||||
# locked. A live image needs a way in, so: root with no password, and an
|
||||
# ordinary user, `schos`, who can become root with doas and su (they are in the
|
||||
# wheel group) and uses the desktop. Both have empty passwords -- login lets
|
||||
# them in without asking -- and `passwd` sets one.
|
||||
#
|
||||
# The numbers are Alpine's: wheel 10, tty 5, video 27, input 23, audio 18.
|
||||
add_member() { # add_member GROUP USER
|
||||
if grep -q "^$1:[^:]*:[^:]*:$" "$ROOT/etc/group"; then
|
||||
sed -i "s/^\($1:[^:]*:[^:]*:\)$/\1$2/" "$ROOT/etc/group"
|
||||
else
|
||||
sed -i "s/^\($1:[^:]*:[^:]*:.*\)$/\1,$2/" "$ROOT/etc/group"
|
||||
fi
|
||||
}
|
||||
# locked. A live image needs a way in, so: root, with no password -- login lets
|
||||
# root in without asking, and `passwd` sets one. That is the only account; an
|
||||
# ordinary user is one `adduser` away, and the permission checks, su and doas
|
||||
# are all still there for when there is one.
|
||||
sed -i 's/^root:[^:]*:/root::/' "$ROOT/etc/shadow"
|
||||
grep -q '^schos:' "$ROOT/etc/passwd" ||
|
||||
echo 'schos:x:1000:1000:SchOS user:/home/schos:/bin/zsh' >> "$ROOT/etc/passwd"
|
||||
grep -q '^schos:' "$ROOT/etc/group" ||
|
||||
echo 'schos:x:1000:' >> "$ROOT/etc/group"
|
||||
grep -q '^schos:' "$ROOT/etc/shadow" ||
|
||||
echo 'schos::0:0:::::' >> "$ROOT/etc/shadow"
|
||||
for g in wheel tty video input audio cdrom; do
|
||||
grep -q "^$g:.*[:,]schos\(,\|\$\)" "$ROOT/etc/group" || add_member $g schos
|
||||
done
|
||||
chmod 640 "$ROOT/etc/shadow"
|
||||
|
||||
# Who may become root with doas: the wheel group, without being asked again.
|
||||
# The file has to be root's and not writable by anyone else, or doas refuses it.
|
||||
# doas: members of wheel run anything, without being asked again. Nobody is in
|
||||
# wheel yet. The file has to be root's and not writable by anyone else.
|
||||
cat > "$ROOT/etc/doas.conf" <<'DEOF'
|
||||
# doas: see doas.conf(5). Members of wheel run anything as anyone.
|
||||
permit nopass :wheel
|
||||
DEOF
|
||||
chmod 644 "$ROOT/etc/doas.conf"
|
||||
|
||||
# The user's home, with what startx wants there. root's are in /root.
|
||||
mkdir -p "$ROOT/home/schos"
|
||||
cp "$ROOT/root/.xinitrc" "$ROOT/root/.xserverrc" "$ROOT/home/schos/"
|
||||
chmod 755 "$ROOT/home/schos/.xserverrc"
|
||||
# zsh offers to write one on first login; /etc/zsh is where the settings are.
|
||||
: > "$ROOT/home/schos/.zshrc"
|
||||
chmod 700 "$ROOT/home/schos" "$ROOT/root"
|
||||
: > "$ROOT/root/.zshrc"
|
||||
chmod 700 "$ROOT/root"
|
||||
|
||||
# The setuid programs. Run as an ordinary user, apk may have dropped the bit,
|
||||
# and nothing here should depend on whether it did.
|
||||
|
|
@ -406,9 +384,8 @@ for f in bin/su usr/bin/passwd usr/bin/doas; do
|
|||
done
|
||||
|
||||
# Who owns what inside the image: everything is root's -- the build host's
|
||||
# user means nothing here -- except the user's home.
|
||||
# user means nothing here.
|
||||
cat > "$OUT/owners" <<'OEOF'
|
||||
/home/schos 1000 1000 0700
|
||||
/root 0 0 0700
|
||||
/tmp 0 0 1777
|
||||
/var/tmp 0 0 1777
|
||||
|
|
|
|||
Loading…
Reference in a new issue