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
|
# 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
|
# stub.c are freestanding and build unchanged for either side, which is the
|
||||||
# whole point of having written them that way.
|
# 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) \
|
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)
|
$(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
|
$(BUILD)/ldls/guest/%.o: ldls/%.c ldls/ko.h ldls/btf.h ldls/stub.h
|
||||||
@mkdir -p $(BUILD)/ldls/guest
|
@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
|
# The KPI -- the Linux symbols, implemented. Guest-only: it reaches /dev/pci
|
||||||
# and /dev/netdev, which exist on SchOS and nowhere else.
|
# 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
|
$(BUILD)/ldls/guest/kpi/%.o: ldls/kpi/%.c ldls/kpi/kpi.h ldls/kpi/link_modes.inc
|
||||||
@mkdir -p $(BUILD)/ldls/guest/kpi
|
@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)
|
$(BUILD)/cmd/ldlsd: cmd/ldlsd/main.c $(ULIB) $(LDLS_GUEST)
|
||||||
@mkdir -p $(BUILD)/cmd
|
@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 $@ \
|
$(LD) $(LDFLAGS) $(LD_LOWBASE) -e _start -Ttext 0x4000 -o $@ \
|
||||||
$(BUILD)/cmd/ldlsd.o $(LDLS_GUEST) $(ULIB)
|
$(BUILD)/cmd/ldlsd.o $(LDLS_GUEST) $(ULIB)
|
||||||
$(OBJCOPY) -S $@
|
$(OBJCOPY) -S $@
|
||||||
|
|
@ -1427,21 +1435,33 @@ LDLS_FWDIR ?= /run/current-system/firmware
|
||||||
LDLS_R8169 = drivers/net/phy/mdio-bus drivers/net/phy/libphy \
|
LDLS_R8169 = drivers/net/phy/mdio-bus drivers/net/phy/libphy \
|
||||||
drivers/net/phy/mdio_devres drivers/net/phy/realtek/realtek \
|
drivers/net/phy/mdio_devres drivers/net/phy/realtek/realtek \
|
||||||
drivers/net/ethernet/realtek/r8169
|
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:
|
ldls-r8169:
|
||||||
@mkdir -p $(SYSROOT)/lib/modules $(SYSROOT)/lib/firmware/rtl_nic
|
@mkdir -p $(SYSROOT)/lib/modules $(SYSROOT)/lib/firmware/rtl_nic
|
||||||
@set -e; list=; for m in $(LDLS_R8169); do \
|
@set -e; list=; for m in $(LDLS_R8169); do \
|
||||||
f=$$(ls $(LDLS_KDIR)/$$m.ko* | head -1); n=$$(basename $$m).ko; \
|
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 \
|
t=$(SYSROOT)/lib/modules/$$n; \
|
||||||
> $(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; \
|
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' \
|
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 \
|
@for f in $(LDLS_FWDIR)/rtl_nic/rtl8168*.fw*; do \
|
||||||
n=$$(basename $$f); case $$n in \
|
n=$$(basename $$f); case $$n in \
|
||||||
*.zst) zstd -qdc $$f > $(SYSROOT)/lib/firmware/rtl_nic/$${n%.zst};; \
|
*.zst) out=$${n%.zst}; zstd -qdc $$f > $(SYSROOT)/lib/firmware/rtl_nic/$$out.new;; \
|
||||||
*.xz) xz -dc $$f > $(SYSROOT)/lib/firmware/rtl_nic/$${n%.xz};; \
|
*.xz) out=$${n%.xz}; xz -dc $$f > $(SYSROOT)/lib/firmware/rtl_nic/$$out.new;; \
|
||||||
*) cp $$f $(SYSROOT)/lib/firmware/rtl_nic/;; esac; done
|
*) 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)"
|
@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
|
# `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
|
/* Where the bar goes. Derived, not stored, so nothing can set it and then have
|
||||||
* the screen change underneath it.
|
* the screen change underneath it.
|
||||||
*
|
*
|
||||||
* The bar is exactly the mark's width and sits directly beneath it: the two are
|
* The track is wider than the mark and sits beneath it: a mark with a recessed
|
||||||
* one object, and a bar wider than the mark it belongs to reads as a separate
|
* track and one line of type, centred, on the same graphite the boot manager
|
||||||
* thing that happens to be nearby.
|
* 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
|
static void
|
||||||
bar_geometry(void)
|
bar_geometry(void)
|
||||||
{
|
{
|
||||||
PROG_W = ui_mark_width();
|
PROG_W = 220 * SC;
|
||||||
PROG_H = BAR_H;
|
PROG_H = 6 * SC;
|
||||||
PROG_X = ((int)FB.width - PROG_W) / 2;
|
PROG_X = ((int)FB.width - PROG_W) / 2;
|
||||||
|
|
||||||
int mark_h = (LOGO_H * PROG_W) / LOGO_W;
|
int mw = ui_mark_width() * SC;
|
||||||
int group_h = mark_h + MARK_GAP + PROG_H;
|
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;
|
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
|
void
|
||||||
ui_splash(const char *subtitle)
|
ui_splash(const char *subtitle)
|
||||||
{
|
{
|
||||||
if (!ACTIVE)
|
if (!ACTIVE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ui_clear();
|
nv_backdrop();
|
||||||
bar_geometry();
|
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 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);
|
ui_logo(top, w);
|
||||||
|
LOGO_BG = saved;
|
||||||
|
|
||||||
if (subtitle)
|
if (subtitle)
|
||||||
ui_text_centered(PROG_Y + PROG_H + SUB_GAP, subtitle, SCH_DIM);
|
ui_progress_label(subtitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Niveus -----------------------------------------------------------------
|
/* --- Niveus -----------------------------------------------------------------
|
||||||
|
|
@ -912,6 +929,25 @@ ui_notice(const char *title, const char *const *lines, int n,
|
||||||
box(title, lines, 0, n, button, hint);
|
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
|
void
|
||||||
ui_progress_begin(const char *label, ui_u32 total)
|
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_LAST_PX = 0;
|
||||||
PROG_ACTIVE = 1;
|
PROG_ACTIVE = 1;
|
||||||
|
|
||||||
/* The unfilled track: a recess, not a colour. Drawn once -- repainting it
|
progress_paint(0);
|
||||||
* 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);
|
|
||||||
if (label)
|
if (label)
|
||||||
ui_progress_label(label);
|
ui_progress_label(label);
|
||||||
}
|
}
|
||||||
|
|
@ -938,11 +971,16 @@ ui_progress_label(const char *label)
|
||||||
if (!ACTIVE || !label)
|
if (!ACTIVE || !label)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Clear the line first. A shorter label after a longer one would otherwise
|
/* Repaint the backdrop under the line first. A shorter label after a longer
|
||||||
* leave the tail of the old one behind. */
|
* one would otherwise leave the tail of the old one behind. */
|
||||||
int y = PROG_Y + PROG_H + SUB_GAP;
|
int h = nv_height(F_BODY) + 4 * SC;
|
||||||
ui_fill_rect(0, y, (int)FB.width, GLYPH_H, SCH_BG);
|
int y = PROG_Y + PROG_H + 18 * SC;
|
||||||
ui_text_centered(y, label, SCH_DIM);
|
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
|
void
|
||||||
|
|
@ -956,16 +994,8 @@ ui_progress_tick(ui_u32 done)
|
||||||
PROG_DONE = done;
|
PROG_DONE = done;
|
||||||
|
|
||||||
int px = (int)(((ui_u64)PROG_DONE * (ui_u64)PROG_W) / PROG_TOTAL);
|
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) {
|
if (px > PROG_LAST_PX) {
|
||||||
/* The fill is metal too, shaded across the bar's height, so it looks
|
progress_paint(px);
|
||||||
* 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));
|
|
||||||
PROG_LAST_PX = 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.
|
/* 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
|
* `budget` is a countdown in milliseconds that survives across calls: a
|
||||||
* caller that returns here after a hover continues the same ten seconds
|
* caller that returns here after a hover continues the same ten seconds
|
||||||
* instead of being given a fresh ten. NULL waits for ever.
|
* 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
|
static int
|
||||||
wait_event(EFI_INPUT_KEY *key, int *item, UINTN *budget)
|
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_X = (int)ui_width() / 2;
|
||||||
PTR_Y = (int)ui_height() / 2;
|
PTR_Y = (int)ui_height() / 2;
|
||||||
}
|
}
|
||||||
|
if (have)
|
||||||
|
PTR_ACTIVE = 1;
|
||||||
ui_cursor(PTR_X, PTR_Y, PTR_ACTIVE);
|
ui_cursor(PTR_X, PTR_Y, PTR_ACTIVE);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (ST->ConIn && !EFI_ERROR(ST->ConIn->ReadKeyStroke(ST->ConIn, key)))
|
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++;
|
PTR_RESCANS++;
|
||||||
pointers_find();
|
pointers_find();
|
||||||
have = PTR_NREL + PTR_NABS;
|
have = PTR_NREL + PTR_NABS;
|
||||||
|
if (have && !PTR_ACTIVE) {
|
||||||
|
PTR_ACTIVE = 1;
|
||||||
|
ui_cursor(PTR_X, PTR_Y, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (have) {
|
if (have) {
|
||||||
int e = pointer_poll();
|
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.
|
- **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
|
- **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.
|
`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
|
- **Runs as an ordinary user** where there is one: `startx` works by group permission alone
|
||||||
([users.md](users.md)); X itself is still a single seat with no logind or seatd.
|
([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
|
## What you meet
|
||||||
|
|
||||||
- **`login` on tty1–tty5.** `etc/schos-getty` takes the terminal back from
|
- **`login` on all twelve terminals, tty1–tty12.** `etc/schos-getty` takes the
|
||||||
whoever had it and runs `login`, which asks who is there and starts their
|
terminal back from whoever had it and runs `login`, which asks who is there
|
||||||
shell; when the shell exits `schinit` starts the prompt again.
|
and starts their shell; when the shell exits `schinit` starts the prompt
|
||||||
- **tty6 is a root shell with no login**, on purpose: the way in when login
|
again. Alt+F1…F12 (or Ctrl+Alt+F1…F12) switches between them. (There is no
|
||||||
itself is what is broken.
|
longer a login-free root shell on tty6.)
|
||||||
- **Two accounts in the image.** `root`, and `schos` (uid 1000, home
|
- **One account in the image: `root`**, with an empty password, so `login` lets
|
||||||
`/home/schos`, in `wheel tty video input audio cdrom`). Both have empty
|
it in without asking — it is a live image. `passwd` sets one. More users are
|
||||||
passwords, so `login` lets them in without asking — it is a live image.
|
an `adduser` away; `wheel` is empty, so `su` and `doas` have no one to serve
|
||||||
`passwd` sets one.
|
until then.
|
||||||
- **`su` and `passwd`** (`cmd/su`, `cmd/passwd`) are setuid root and small
|
- **`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
|
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
|
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
|
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
|
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
|
[mode]` per line (`tools/posix/mkaroot.sh` writes it: the modes of `/tmp`,
|
||||||
0700`, and the modes of `/tmp`, `/var/tmp` and `/root`). The setuid bits are set
|
`/var/tmp` and `/root`). The setuid bits are set
|
||||||
on `su`, `passwd` and `doas` in the root tree directly, because `apk` run as an
|
on `su`, `passwd` and `doas` in the root tree directly, because `apk` run as an
|
||||||
ordinary user may have dropped them.
|
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.
|
# 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
|
||||||
# NVT is 6 (include/dev/vt.h) and the kernel creates all six terminals, but only
|
# range, because schinit has no notion of a template.
|
||||||
# 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.
|
|
||||||
|
|
||||||
Label = os.schos.tty3-shell
|
Label = os.schos.tty3-shell
|
||||||
Program = /bin/sh
|
Program = /bin/sh
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,6 @@
|
||||||
# An interactive shell on /dev/tty4.
|
# 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
|
||||||
# NVT is 6 (include/dev/vt.h) and the kernel creates all six terminals, but only
|
# range, because schinit has no notion of a template.
|
||||||
# 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.
|
|
||||||
|
|
||||||
Label = os.schos.tty4-shell
|
Label = os.schos.tty4-shell
|
||||||
Program = /bin/sh
|
Program = /bin/sh
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,6 @@
|
||||||
# An interactive shell on /dev/tty5.
|
# 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
|
||||||
# NVT is 6 (include/dev/vt.h) and the kernel creates all six terminals, but only
|
# range, because schinit has no notion of a template.
|
||||||
# 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.
|
|
||||||
|
|
||||||
Label = os.schos.tty5-shell
|
Label = os.schos.tty5-shell
|
||||||
Program = /bin/sh
|
Program = /bin/sh
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,15 @@
|
||||||
# A root shell on /dev/tty6, with no login: the way in when login itself is
|
# A login on /dev/tty6: every one of the twelve virtual terminals asks who is there.
|
||||||
# what has broken. Every other terminal 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.
|
||||||
# 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.
|
|
||||||
|
|
||||||
Label = os.schos.tty6-shell
|
Label = os.schos.tty6-shell
|
||||||
Program = /bin/zsh
|
Program = /bin/sh
|
||||||
Args = -zsh
|
Args = sh /etc/schos-getty
|
||||||
RunAtLoad = yes
|
RunAtLoad = yes
|
||||||
KeepAlive = yes
|
KeepAlive = yes
|
||||||
|
|
||||||
Environment = TERM=linux
|
Environment = TERM=linux
|
||||||
Environment = PATH=/bin:/usr/bin
|
Environment = PATH=/bin:/usr/bin
|
||||||
Environment = HOME=/root
|
|
||||||
Environment = SHELL=/bin/zsh
|
|
||||||
|
|
||||||
ControllingTerminal = yes
|
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');
|
uartputc('\b'); uartputc(' '); uartputc('\b');
|
||||||
if (!cons_serial_only) {
|
if (!cons_serial_only) {
|
||||||
struct vt *v = vt_current();
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -452,8 +452,12 @@ erase_one(struct vt *v)
|
||||||
v->in.e--;
|
v->in.e--;
|
||||||
if (v->tio.c_lflag & ECHOE) {
|
if (v->tio.c_lflag & ECHOE) {
|
||||||
if (v == vt_current()) { uartputc('\b'); uartputc(' '); uartputc('\b'); }
|
if (v == vt_current()) { uartputc('\b'); uartputc(' '); uartputc('\b'); }
|
||||||
if (!cons_serial_only)
|
// Back, blank, back -- and through vt_feed, which keeps the text cursor
|
||||||
vt_putc(v, '\b');
|
// 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 1: return consoleread(ip, off, dst, n);
|
||||||
case 2: return nullread(ip, off, dst, n);
|
case 2: return nullread(ip, off, dst, n);
|
||||||
case 3: return consoleread(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(). */
|
minor to a terminal; see vt_for_minor(). */
|
||||||
case 10: case 11: case 12: case 13: case 14: case 15: case 16:
|
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);
|
return consoleread(ip, off, dst, n);
|
||||||
case 5: return zeroread(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
|
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) {
|
switch(ip->minor) {
|
||||||
case 1: return consolewrite(ip, off, dst, n);
|
case 1: return consolewrite(ip, off, dst, n);
|
||||||
case 10: case 11: case 12: case 13: case 14: case 15: case 16:
|
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);
|
return consolewrite(ip, off, dst, n);
|
||||||
case 7: return fullwrite(ip, off, dst, n); // /dev/full: always ENOSPC
|
case 7: return fullwrite(ip, off, dst, n); // /dev/full: always ENOSPC
|
||||||
case 3: // /dev/keyboard: discarded
|
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++)
|
for (int c = 0; c < cell_w; c++)
|
||||||
gfx_draw_pixel(x + c, y + r, bg);
|
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 == ' ')
|
if (cp == ' ')
|
||||||
return; // nothing to draw over the background
|
return; // nothing to draw over the background
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1241,20 +1241,26 @@ vt_cycle(int dir)
|
||||||
void
|
void
|
||||||
vt_feed(struct vt *v, int c)
|
vt_feed(struct vt *v, int c)
|
||||||
{
|
{
|
||||||
// The grid is the truth, so the old cursor cell can be repainted from it
|
// A plain glyph is drawn over the cell the cursor sits on, which repaints it
|
||||||
// *after* the byte is consumed -- which lets two cases cost nothing:
|
// anyway (unless a wrap is pending, when it lands on the next line), so the
|
||||||
// - a byte inside an escape sequence changes nothing on screen;
|
// cursor needs no separate erase there.
|
||||||
// - 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).
|
|
||||||
int mid = v->esc_state != VE_NORMAL;
|
int mid = v->esc_state != VE_NORMAL;
|
||||||
int over = !mid && !v->wrap_pending && c >= 0x20 && c < 0x7f &&
|
int over = !mid && !v->wrap_pending && c >= 0x20 && c < 0x7f &&
|
||||||
v->u8_need == 0;
|
v->u8_need == 0;
|
||||||
|
|
||||||
|
if (over) {
|
||||||
vt_feed_1(v, c);
|
vt_feed_1(v, c);
|
||||||
if (mid && v->esc_state != VE_NORMAL)
|
|
||||||
return;
|
|
||||||
if (over)
|
|
||||||
v->curs_drawn = 0;
|
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);
|
cursor_erase(v);
|
||||||
|
vt_feed_1(v, c);
|
||||||
cursor_draw(v);
|
cursor_draw(v);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ static uint64
|
||||||
linux_tty_rdev(uint32 major, uint32 minor)
|
linux_tty_rdev(uint32 major, uint32 minor)
|
||||||
{
|
{
|
||||||
if (major == 1 && minor == 0) return linux_makedev(4, 0);
|
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 == 10) return linux_makedev(5, 0);
|
||||||
if (major == 1 && minor == 1) return linux_makedev(5, 1);
|
if (major == 1 && minor == 1) return linux_makedev(5, 1);
|
||||||
// Pseudo-terminals, as Linux numbers them: ptmx (5, 2), slaves 136.
|
// Pseudo-terminals, as Linux numbers them: ptmx (5, 2), slaves 136.
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,5 @@ libinput-udev
|
||||||
libseat
|
libseat
|
||||||
seatd
|
seatd
|
||||||
seatd-launch
|
seatd-launch
|
||||||
xf86-input-libinput
|
|
||||||
# lsusb that reads /sys/bus/usb/devices, which busybox's does not.
|
# lsusb that reads /sys/bus/usb/devices, which busybox's does not.
|
||||||
usbutils
|
usbutils
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,6 @@ xcalc-1.1.3-r0.apk 2f0d9ab5674a5f82f4adfb6dd5f0a9c944421feea2d6aaf18998b0326fe4c
|
||||||
xclock-1.1.1-r0.apk ae2a3cb515664cf34dd9cd0f81945cad75d0b6bbf44696830f29f1ab4713b475 community
|
xclock-1.1.1-r0.apk ae2a3cb515664cf34dd9cd0f81945cad75d0b6bbf44696830f29f1ab4713b475 community
|
||||||
xeyes-1.3.1-r0.apk 4b31dabe8d7f5000d82a24445972859bf960c1b07bca3d4f87e80b3c710902c6 community
|
xeyes-1.3.1-r0.apk 4b31dabe8d7f5000d82a24445972859bf960c1b07bca3d4f87e80b3c710902c6 community
|
||||||
xf86-input-evdev-2.11.0-r0.apk 1f3fcd3e837b43ad5e32005e03095b547ddbfc25973f0511e9ff74bf342d2fe0 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
|
xf86-video-fbdev-0.5.0-r6.apk 6a8a1b16f82d8810896f00c00b356c8b8d923e9aa0ce64737ae8274ca82f507a community
|
||||||
xinit-1.4.4-r0.apk efb5dc1e7929824f5add7d5d51d0ecb34ecfd0a773dfca4f061adc8a353b234f community
|
xinit-1.4.4-r0.apk efb5dc1e7929824f5add7d5d51d0ecb34ecfd0a773dfca4f061adc8a353b234f community
|
||||||
xkbcomp-1.5.0-r0.apk 8bfbd3c8ce7180e8cf599d5a0b791993b61fa98f3a19c47aaf5fcbe30c12d0ba main
|
xkbcomp-1.5.0-r0.apk 8bfbd3c8ce7180e8cf599d5a0b791993b61fa98f3a19c47aaf5fcbe30c12d0ba main
|
||||||
|
|
|
||||||
|
|
@ -358,46 +358,24 @@ chmod 1777 "$ROOT/tmp" "$ROOT/var/tmp"
|
||||||
# --- accounts -------------------------------------------------------------------
|
# --- accounts -------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# Alpine's baselayout has root and the system accounts, with root's password
|
# 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
|
# locked. A live image needs a way in, so: root, with no password -- login lets
|
||||||
# ordinary user, `schos`, who can become root with doas and su (they are in the
|
# root in without asking, and `passwd` sets one. That is the only account; an
|
||||||
# wheel group) and uses the desktop. Both have empty passwords -- login lets
|
# ordinary user is one `adduser` away, and the permission checks, su and doas
|
||||||
# them in without asking -- and `passwd` sets one.
|
# are all still there for when there is 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
|
|
||||||
}
|
|
||||||
sed -i 's/^root:[^:]*:/root::/' "$ROOT/etc/shadow"
|
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"
|
chmod 640 "$ROOT/etc/shadow"
|
||||||
|
|
||||||
# Who may become root with doas: the wheel group, without being asked again.
|
# doas: members of wheel run anything, without being asked again. Nobody is in
|
||||||
# The file has to be root's and not writable by anyone else, or doas refuses it.
|
# wheel yet. The file has to be root's and not writable by anyone else.
|
||||||
cat > "$ROOT/etc/doas.conf" <<'DEOF'
|
cat > "$ROOT/etc/doas.conf" <<'DEOF'
|
||||||
# doas: see doas.conf(5). Members of wheel run anything as anyone.
|
# doas: see doas.conf(5). Members of wheel run anything as anyone.
|
||||||
permit nopass :wheel
|
permit nopass :wheel
|
||||||
DEOF
|
DEOF
|
||||||
chmod 644 "$ROOT/etc/doas.conf"
|
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.
|
# zsh offers to write one on first login; /etc/zsh is where the settings are.
|
||||||
: > "$ROOT/home/schos/.zshrc"
|
: > "$ROOT/root/.zshrc"
|
||||||
chmod 700 "$ROOT/home/schos" "$ROOT/root"
|
chmod 700 "$ROOT/root"
|
||||||
|
|
||||||
# The setuid programs. Run as an ordinary user, apk may have dropped the bit,
|
# The setuid programs. Run as an ordinary user, apk may have dropped the bit,
|
||||||
# and nothing here should depend on whether it did.
|
# 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
|
done
|
||||||
|
|
||||||
# Who owns what inside the image: everything is root's -- the build host's
|
# 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'
|
cat > "$OUT/owners" <<'OEOF'
|
||||||
/home/schos 1000 1000 0700
|
|
||||||
/root 0 0 0700
|
/root 0 0 0700
|
||||||
/tmp 0 0 1777
|
/tmp 0 0 1777
|
||||||
/var/tmp 0 0 1777
|
/var/tmp 0 0 1777
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue