# Export système pour revue `scripts/backup.sh` produit un **candidat privé hors du dépôt**. La commande sans argument ne met plus à jour `pkglist/`, `inventory/`, `rootfs/` ni `templates/` suivis par Git. Elle ne sauvegarde ni données personnelles, dotfiles, clés Secure Boot, connexions réseau, secrets, ni fichiers Trainlog. La zone locale d’export n’est pas une preuve de sauvegarde hors disque ou de restauration possible. Ce code n’a été testé ici que sur des fixtures. ## Interface et destination ```text backup.sh [--output-dir REPERTOIRE_PARENT] backup.sh --dry-run [--output-dir REPERTOIRE_PARENT] backup.sh --help ``` `--output-dir` désigne un **parent** : chaque invocation crée un sous-répertoire unique. Par défaut, le parent est `${XDG_STATE_HOME:-$HOME/.local/state}/arch-system/exports`. Un `XDG_STATE_HOME` relatif est ignoré avec diagnostic, selon la [spécification XDG](https://specifications.freedesktop.org/basedir/0.8/) ; le chemin par défaut sous `HOME` est alors employé. Un parent explicite relatif est résolu depuis le répertoire courant. Les chemins sont normalisés ; la destination égale au dépôt ou située dedans, les alias vers celui-ci et les parents traversant un lien symbolique sont refusés. Un parent final existant doit appartenir à l’utilisateur et ne pas être ouvert au groupe ou aux autres. Les nouveaux répertoires sont créés privés, sans `chmod`/`chown` des ancêtres. Un parent contenant des espaces ou un antislash littéral reste accepté ; le calcul des empreintes ne dépend pas de la représentation de son nom. `--dry-run` affiche les sources, les catégories obligatoire/facultatif, le parent et les transformations ; il ne crée rien et ne lance ni sudo, ni collecteur, ni demande de mot de passe. Il ne prouve pas la réussite des lectures futures. La collecte refuse une invocation en root ; les fichiers de sortie sont écrits par l’utilisateur sous `umask 077`. Les lectures privilégiées utilisent `sudo -n`, un contrôle d’état strict et seulement les sources explicitement autorisées. Aucun résultat n’est installé avec sudo. ## Collecteurs et états | Classe | Collecteurs | Raison | |---|---|---| | Obligatoire | `pacman -Qqen`, `-Qqem` ; unités système activées, en cours et timers ; `lsblk`, `findmnt`, `/etc/fstab`, Btrfs subvolumes/usage, mémoire et swap ; `pacman.conf`, `makepkg.conf`, `mkinitcpio.conf` | Sans ces éléments, le candidat annoncé manquerait son noyau d’inventaire et de configuration. | | Facultatif | `pacman -Qdtq` ; unités en échec et unités utilisateur ; scrub Btrfs ; SMART de `/dev/nvme0` ; `nftables.conf`, limine-snapper-sync, TLP, zram-generator, Snapper, deux helpers root ; modèle Limine | Leur absence ou indisponibilité peut être légitime selon la machine, l’utilisateur ou le matériel. Elle reste visible dans le manifeste. | `SUCCESS` indique un fichier collecté non vide ; `EMPTY`, une commande réussie avec résultat vide permis ; `ABSENT`, une absence effectivement établie pour une source facultative ; `UNAVAILABLE`, un outil ou `nvme0` indisponible ; `CHECK_ERROR`, un contrôle impossible ou une réponse invalide ; `COLLECT_ERROR`, une commande ou lecture échouée. `PORTABILITY_REVIEW` marque le modèle Limine à relire, même après une transformation reconnue. Une erreur obligatoire interdit la finalisation ; une erreur facultative produit `COMPLETE_WITH_WARNINGS` si le noyau obligatoire a réussi. `COMPLETE` est réservé à un ensemble sans avertissement. En pratique, un modèle Limine présent entraîne une alerte de portabilité. Les listes sont des **observations** : « natif » ne prouve pas dans tous les cas « dépôt officiel », et « étranger » ne prouve pas « AUR ». `pacman -Qdtq` désigne les dépendances orphelines selon [pacman(8)](https://man.archlinux.org/man/pacman.8.en). La documentation primaire ne justifie pas une règle générale « code 1 = aucun orphelin » : une sortie vide avec code non nul reste `COLLECT_ERROR`, avec une cause à examiner. Les résultats vides de commandes revenues avec succès sont distingués. Le relevé SMART éventuel concerne **seulement** `/dev/nvme0`, pas tous les disques. ## Finalisation, manifeste et limites La collecte commence dans un répertoire `.incomplete.*` privé, doté d’un `manifest.tsv` au statut `INCOMPLETE`. Les sorties sont d’abord reçues dans une zone de travail privée ; une commande qui écrit partiellement puis échoue ne publie pas ce fichier comme relevé valide. Après les éléments obligatoires, le manifeste est terminé et le répertoire est renommé localement en `export-*` sans remplacer un nom existant. Chaque invocation a son espace ; avant un renommage réussi, une erreur ou un `INT`/`TERM` conserve son reliquat marqué `INCOMPLETE` et annoncé. Après le renommage réussi, un `INT`/`TERM` conserve le candidat complet et annonce son chemin avec le diagnostic « finalisation acquise, terminaison interrompue ». L'exporteur reconnaît ce renommage par la disparition du staging et l'identité de l'objet au chemin final ; la simple présence d'une destination préexistante ne suffit pas. Une collision conserve le staging incomplet sans revendiquer cet autre export. Les exports antérieurs ne sont ni supprimés ni remplacés. Les codes sont `0` pour simulation ou candidat finalisé, `1` pour erreur, `2` pour usage invalide, `130`/`143` pour `INT`/`TERM`. `SIGKILL` et une coupure d’alimentation ne sont pas interceptés ; aucune garantie de durabilité après coupure n’est revendiquée. Le manifeste contient version, début/fin UTC, révision source, statut global, état de chaque collecteur et SHA-256 des **fichiers de sortie finalisés**. Chaque empreinte est calculée via l'entrée standard, après vérification de l'ouverture du fichier et du succès de la commande ; seule une réponse de 64 chiffres hexadécimaux est acceptée. Un échec ou une réponse malformée interdit la finalisation. Le manifeste ne contient pas son propre hash. Vérifier les empreintes et lire le contenu avant toute utilisation. Les lectures ne forment pas un instantané atomique : services et fichiers peuvent changer pendant la collecte. Les vérifications de chemins réduisent les risques d’alias et de liens ; elles ne remplacent pas une exclusion des modifications concurrentes de la machine. Le modèle Limine candidat est produit **uniquement dans l’export**. La section commençant par `### Auto-generated by limine-snapper-sync` est retirée. Les formes `root=UUID=` et `root=PARTUUID=` deviennent des placeholders distincts. Une forme `root=` non reconnue est signalée ; tous les autres champs demeurent soumis à revue. Ni `ESP_PATH`, ni signatures, ni snapshots ne sont changés. Le modèle n’est pas déclaré universellement portable. ## Revue avant toute promotion manuelle Examiner les fichiers et le manifeste hors du dépôt, particulièrement identifiants de stockage, noms de services, `nftables.conf`, `fstab` et Limine. Aucun filtrage simple ne certifie l’absence de secrets ; **ne pas publier automatiquement**. Les listes de déploiement et la politique réseau restent des décisions de reconstruction distinctes de l’état observé. Une éventuelle reprise manuelle dans Git demande une revue spécifique des contenus et de leur portée. L’existence du candidat n’apporte ni copie externe, ni restauration testée.