#!/bin/sh
# layout/skeleton.sh — create the AnotherOS versioned-filesystem skeleton.
#
#   layout/skeleton.sh <target-root>
#
# Builds the top-level directory tree, the /System/Index symlink-farm subdirs,
# the package-database dirs, and the compatibility symlinks (/bin, /usr, /etc,
# ...) into <target-root>. Idempotent. Used both by the ncurses installer (target
# = the mounted install partition) and by the host image build (target = a
# staging root). See docs/anotheros-fs-layout.md for the canonical layout.
#
# NAMING: the system directory is /System (formerly /Sys) and user homes live in
# /Users (formerly /Home), matching GoboLinux and the names the Fasadas Finder
# already presents from the initramfs. Per-program trees stay at /Apps/<Name>/
# <Version> — deliberately NOT GoboLinux's /Programs, because /Apps is already
# the proven on-device name and reusing it for something else would silently
# resolve stale references to the wrong kind of directory.
#
# Portable POSIX sh: runs on the build host AND on-device.
set -e
ROOT="${1:?usage: skeleton.sh <target-root>}"

mkdirp() { mkdir -p "$ROOT/$1"; }
# link <linkpath> <target> : create $ROOT/<linkpath> -> <target> if absent.
link() {
    lp="$ROOT/$1"; tgt="$2"
    [ -L "$lp" ] && [ "$(readlink "$lp")" = "$tgt" ] && return 0
    rm -rf "$lp"
    ln -s "$tgt" "$lp"
}

# --- top-level directories -------------------------------------------------
for d in \
    Apps \
    Applications \
    System System/Index System/Index/bin System/Index/sbin System/Index/lib \
    System/Index/libexec System/Index/include System/Index/share \
    System/Index/share/man \
    System/Settings System/Fonts System/Locale \
    System/Kernel System/Kernel/Boot System/Kernel/Modules \
    System/Win32 System/Win32/bin System/Win32/lib \
    System/Win32/share System/Win32/share/tests \
    System/Win32/share/registry System/Win32/share/fonts \
    WinApps \
    Users Users/root \
    Mount Media Files \
    State State/lib State/lib/apkg State/lib/apkg/installed State/lib/apkg/repo \
    State/log State/tmp State/cache State/run \
    tmp dev proc sys
do
    mkdirp "$d"
done
chmod 1777 "$ROOT/tmp" "$ROOT/State/tmp" 2>/dev/null || true

# --- compatibility symlinks into the farm ----------------------------------
# Relative targets so the tree is relocatable (works whether the root is / or a
# staging dir); the kernel walker resolves them against the link's directory.
link bin      System/Index/bin
link sbin     System/Index/sbin
link lib      System/Index/lib
link libexec  System/Index/libexec
link usr      System/Index
link etc      System/Settings
link var      State
link home     Users
link root     Users/root
link mnt      Mount
# /share is a TOP-LEVEL path on AnotherOS, not just /usr/share. It comes from
# the dev-disk root (docker/scripts/merge-liveroot.sh copies tmp/devroot/. to the
# live root wholesale) and the desktop hardcodes it: fasadasd's default
# wallpaper "/share/fasadas/aurora.png", plintusas' and rastinis' icon theme
# "/share/fasadas/icons", the settings panel's wallpaper search path and
# aplayer's default media directory all name it absolutely.
#
# Without this link, farmify moves /share into CoreSystem and the desktop comes
# up with no icons and no wallpaper — the compositor still runs, so it looks
# like a theme bug rather than a layout bug. /usr/share and /share must resolve
# to the same place, exactly as /bin and /usr/bin already do.
link share    System/Index/share
# /usr/local and /usr/X11R6 are SELF-links, exactly as GoboLinux does it
# (Functions/Bootstrap). This is what makes a `--prefix=/usr/local` or
# `--prefix=/usr/X11R6` build land in the index instead of in a private tree
# nothing else can see — a very common default in autotools packages.
#
# Created directly under System/Index, NOT as "usr/local": /usr is itself a
# symlink to System/Index, and creating a symlink THROUGH that symlink fails with
# an I/O error on our ext2 (observed on-device). Targeting the real directory is
# equivalent — /usr/local resolves to System/Index/local either way — and avoids
# the traversal entirely.
link System/Index/local  .
link System/Index/X11R6  .
# TRANSLATIONS LIVE AT /System/Locale, beside /System/Fonts.
#
# It is system data shared by every program, not the private content of any one
# package, so it belongs in /System rather than being farmed per-package into
# the index — the same reasoning that puts fonts and settings there. That also
# makes it a single directory to add a language to, instead of a message
# catalogue scattered across /Apps/<Name>/<Version>/share/locale for every
# installed program.
#
# gettext's search path is baked into each binary at build time (bindtextdomain,
# or a compile-time constant like WebKit's LOCALEDIR), and the overwhelmingly
# common value is <prefix>/share/locale. So the FHS name is a symlink INTO the
# canonical one: a package built with any normal prefix finds its catalogues, and
# a package we control can name /System/Locale directly. Both resolve to the same
# bytes, exactly as /bin and /usr/bin already do.
#
# Created under System/Index/share (the real directory) rather than through the
# /share or /usr symlinks — creating a link THROUGH a symlink fails with an I/O
# error on our ext2, the same trap the local/X11R6 links above avoid.
link System/Index/share/locale ../../Locale
# lib64 -> lib: 32-bit i686 has no separate lib64, but plenty of configure
# scripts and pre-built packages write there. GoboLinux does the same merge.
link System/Index/lib64 lib
# /boot is where bootloaders look for the kernel + initramfs; the canonical
# location is System/Kernel/Boot.
#
# NOTE: no /linuxkpi compat link. LinuxKPI .ko modules are built to
# /lib/modules (kernel.mk), i.e. into the farm at System/Index/lib/modules —
# System/Kernel/Modules is created for the GoboLinux shape but is not yet where
# modules are loaded from. Do not add a link that would make an empty directory
# shadow the populated one.
link boot     System/Kernel/Boot

# /etc/machine-id — a 32-hex-digit machine identifier.
#
# GLib's GDBus needs it and there is NO ENVIRONMENT OVERRIDE, so unlike the
# module-path problems this one can only be fixed by the file existing. Without
# it every GApplication start logs
#
#   Cannot spawn a message bus without a machine-id: Unable to load
#   /Apps/gtk3/Current/var/lib/dbus/machine-id or /etc/machine-id
#
# — note the first path is the BUILD prefix baked into libgio, which is the same
# class of bug as the fontconfig/GIO/pixbuf ones, and the fallback /etc/machine-id
# was simply never created. Epiphany currently survives because ephyrun passes
# --private-instance; without that, D-Bus autolaunch fails and single-instance
# activation misbehaves.
#
# Written into System/Settings (the real directory) rather than through the /etc
# symlink, for the same reason as the locale link above. Content is derived from
# the build so a rebuilt image is stable, but any 32 hex chars satisfy the spec.
if [ ! -f "$ROOT/System/Settings/machine-id" ]; then
    _mid=$( (head -c 16 /dev/urandom 2>/dev/null || date +%s%N) \
            | od -An -tx1 2>/dev/null | tr -d ' \n' | cut -c1-32 )
    while [ ${#_mid} -lt 32 ]; do _mid="${_mid}0"; done
    printf '%s\n' "$_mid" > "$ROOT/System/Settings/machine-id"
    echo "  machine-id $_mid"
fi

echo "AnotherOS skeleton created at: $ROOT"
