gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1471Shell 174Rust 105Markdown 943556 Sutichaykuna

⎇ 943ea3aac617d65a1f752fe0efde4d6d17210f68 scripts/lib/usuarios-del-home.sh Shell · 83 siq'ikuna · 5.2 KB Ñawpa willay ch'uya

feat(instalador): adoptar la particion en vez de formatearla, con la mudanza de verdad 4b1f19d8d · sergio ·

1#!/bin/sh
2# lib/usuarios-del-home.sh — los usuarios que ya existen en un `/home`, llevados al sistema nuevo.
3#
4# Lo comparten los dos caminos que conservan datos de alguien: `--keep` (el /home está en otra
5# partición) y `--adopt` (el /home está dentro de la partición que se adopta). Es la misma pregunta
6# —cómo hace el sistema nuevo para que esos archivos sigan siendo de quien son— y por eso hay una
7# sola respuesta: dos implementaciones de esto divergen en el caso raro, y el síntoma es un
8# escritorio que no puede escribir en su propia carpeta.
9#
10# Vive aparte para poder certificarla sin root, igual que `lib/adoptar.sh`.
11
12# cosechar_usuarios <dir-de-home> <fichero-salida> — un usuario por DIRECTORIO de primer nivel, con
13# el dueño de ese directorio. Es el mismo criterio para el `/home` que está en otra partición
14# (`--keep`) y para el que está DENTRO de la partición que se adopta (`--adopt`): el uid de los
15# datos manda, y el login es el nombre del directorio. Una sola copia, porque dos criterios de
16# cosecha que se separan dan dos juegos de usuarios distintos para el mismo disco.
17cosechar_usuarios() {
18    _cu_dir="$1"; _cu_out="$2"
19    : > "$_cu_out"
20    for _cu_h in "$_cu_dir"/*; do
21        [ -d "$_cu_h" ] || continue
22        _cu_n=$(basename "$_cu_h")
23        [ "$_cu_n" = "lost+found" ] && continue
24        # Un login que no es un login se rechaza NOMBRÁNDOLO, no se salta en silencio: un directorio
25        # con un nombre raro en /home es justo el que alguien va a echar de menos.
26        case "$_cu_n" in
27            *[!a-z0-9_-]*|-*|"") echo "    ⚠ «$_cu_n» no es un nombre de usuario válido: no creo usuario para ese directorio (los datos NO se tocan)." ;;
28            *)
29                _cu_u=$(stat -c %u "$_cu_h" 2>/dev/null || echo "")
30                _cu_g=$(stat -c %g "$_cu_h" 2>/dev/null || echo "")
31                case "${_cu_u:-x}${_cu_g:-x}" in *x*) echo "    ⚠ no pude leer el dueño de $_cu_h: lo salto." ; continue ;; esac
32                [ "$_cu_u" = "0" ] && { echo "    ⚠ $_cu_h es de root (uid 0): no creo usuario, y los datos NO se tocan."; continue; }
33                echo "${_cu_n}:${_cu_u}:${_cu_g}" >> "$_cu_out"
34                ;;
35        esac
36    done
37}
38
39# usuarios_aplicar <árbol> <lista> — crea en la raíz NUEVA los usuarios que ya existen en el
40# `/home` que se conserva, **con el uid que tienen sus archivos**. Lo comparten `--keep` (el /home
41# en otra partición) y `--adopt` (el /home dentro de la partición que se adopta): es la misma
42# pregunta —cómo hace el sistema nuevo para que esos archivos sigan siendo de quien son— y una sola
43# respuesta, porque dos implementaciones de esto divergen en el caso raro y el síntoma es un
44# escritorio que no puede escribir en su propia carpeta.
45usuarios_aplicar() {
46    _ua_t="$1"; _ua_lista="$2"
47    # ⚠ **Nada se edita EN SITIO.** El árbol del stage son HARDLINKS del rootfs sellado (ADR 0005):
48    # un `>>` sobre `$_ua_t/etc/passwd` escribiría dentro del ARTEFACTO DEL STORE y envenenaría el
49    # corpus para todo el mundo, sin que nada falle. Se escribe un fichero nuevo y se `mv` encima,
50    # que rompe el enlace y deja el inode del store intacto.
51    for _ua_f in etc/passwd etc/group etc/shadow; do
52        [ -e "$_ua_t/$_ua_f" ] || continue
53        cp "$_ua_t/$_ua_f" "$_ua_t/$_ua_f.keep-tmp"
54        mv "$_ua_t/$_ua_f.keep-tmp" "$_ua_t/$_ua_f"
55    done
56    mkdir -p "$_ua_t/etc" "$_ua_t/home"
57    [ -e "$_ua_t/etc/passwd" ] || : > "$_ua_t/etc/passwd"
58    [ -e "$_ua_t/etc/group" ]  || : > "$_ua_t/etc/group"
59    # 1) Los usuarios, con SU uid. Un choque de uid con un usuario de sistema (sshd es 74) no se
60    #    arregla solo: se aborta ANTES de formatear y se dice cuál, porque la salida es del usuario
61    #    —renombrar o renumerar— y no nuestra.
62    while IFS=':' read -r _ua_n _ua_u _ua_g; do
63        [ -n "$_ua_n" ] || continue
64        _ua_choque=$(awk -F: -v u="$_ua_u" -v n="$_ua_n" '$3==u && $1!=n {print $1; exit}' "$_ua_t/etc/passwd")
65        [ -n "$_ua_choque" ] && {
66            echo "takana-install-partition: el uid $_ua_u del /home conservado (usuario «$_ua_n») ya es de" >&2
67            echo "                          «$_ua_choque» en el sistema nuevo. No sigo, y NADA se formateó." >&2
68            echo "                          Salidas: renombrá ese directorio, o instalá sin --keep y copiá a mano." >&2
69            exit 1; }
70        if awk -F: -v n="$_ua_n" '$1==n {found=1} END {exit !found}' "$_ua_t/etc/passwd"; then
71            echo "    · «$_ua_n» ya existe en el sistema nuevo: no lo vuelvo a crear."
72            continue
73        fi
74        printf '%s:x:%s:%s:%s:/home/%s:/bin/sh\n' "$_ua_n" "$_ua_u" "$_ua_g" "$_ua_n" "$_ua_n" >> "$_ua_t/etc/passwd"
75        awk -F: -v g="$_ua_g" 'BEGIN{r=1} $3==g {r=0} END{exit r}' "$_ua_t/etc/group" \
76            || printf '%s:x:%s:\n' "$_ua_n" "$_ua_g" >> "$_ua_t/etc/group"
77        # Contraseña BLOQUEADA, no vacía: `!` no casa con ningún hash, así que no hay login por
78        # consola hasta que alguien le ponga una. Una entrada con campo vacío es login SIN CLAVE.
79        [ -e "$_ua_t/etc/shadow" ] && printf '%s:!:20000:0:99999:7:::\n' "$_ua_n" >> "$_ua_t/etc/shadow"
80        echo "    · usuario «$_ua_n» creado con uid $_ua_u (el mismo que tienen sus archivos)"
81    done < "$_ua_lista"
82}
83