From 03cc46098cf499190f4622702790f5611dd60f17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erkan=20I=C5=9EIK?= Date: Mon, 28 Sep 2026 00:19:15 +0300 Subject: [PATCH] =?UTF-8?q?fix(partition):=20lsblk'in=20"[SWAP]"=20bi?= =?UTF-8?q?=C3=A7imi=20mountpoint'e=20s=C4=B1z=C4=B1yordu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Canlı ISO'ya SSH ile bağlanıp GERÇEK `lsblk` çıktısı okunarak bulundu — tahminle değil: $ lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT -b --noheadings -l /dev/sdb sdb1 524288000 vfat /boot/efi sdb2 1572864000 swap [SWAP] ← köşeli parantezli sdb3 25168969728 ext4 / `read_existing_partitions` mountpoint'i doğrudan alıyordu, yani `CustomPartition::mountpoint = "[SWAP]"` oluyordu. ## İki yere sızıyordu 1. **UI** — tablonun bağlama noktası sütununda `[SWAP]` görünüyordu 2. **MÜKERRER KONTROLÜ** — iki swap'ı olan makinede (Windows diski + Linux diski = çift önyüklemeli kurulumun tipik hali) ikisi de aynı `"[SWAP]"` değerini taşıyor ve kullanıcı VAR OLMAYAN bir "mükerrer bağlama noktası" hatası görüyordu Bu makinede tek swap olduğu için sorun görünmüyordu. Tek swap'lı kurulumda hata hiç ortaya çıkmaz — kolayca kaçar. ## Düzeltme - `normalize_lsblk_mountpoint(raw, fstype)`: `[SWAP]` → `"swap"`. Yalnızca `FsType::Swap` için; diğer dosya sistemlerinde köşeli parantezli tuhaf bir çıktı gelirse DOKUNULMAZ (sessizce yutmak, özgün hatayı gizlemekten daha kötüdür). - Mükerrer kontrolü artık yalnızca **gerçekten bağlanan** dosya sistemlerini karşılaştırır: `Swap`/`Lvm`/`LvmLv` hariç. `mountpoint_required` ile aynı gerekçe — bağlama noktası semantiği olmayan hiçbir şey karşılaştırılmaz. ## fstab etkilenmedi Satır `part.mountpoint`'e değil `part.fstype`'e göre yazılıyor (`FsType::Swap => ("none", "sw", "0", "0")`). Doğrulandı: kurucunun yazdığı /etc/fstab'ta swap satırı `none`. Yani hata fstab'da değil, mükerrer kontrolünde görünüyordu. ## Testler (145 → 150) - `[SWAP]` → `swap` normalleşir - mount edilmemiş swap (sütun boş) de `swap` olur - diğer dosya sistemleri değiştirilmez, `[weird]` de dokunulmaz - ⭐ iki swap mükerrer SAYILMAZ (gerçek lsblk biçimiyle) - iki gerçek `/` hâlâ mükerrer sayılır (filtre körleştirmiyor) - iki LVM PV mükerrer sayılmaz Bir test ilk yazımda kök bölümü içermiyordu ("No root partition" hattı) — beklenti düzeltildi. cargo check --all-targets : 0 hata, 0 uyarı cargo test : 150/150 Co-Authored-By: Claude Opus 4.8 (1M context) --- AGENTS.md | 39 ++++++++- src/steps/partition.rs | 176 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 206 insertions(+), 9 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 5d1de56..aae1cea 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -531,6 +531,39 @@ Kullanıcı tanımı (sda2) → "Biçimlendir" ☑ SEÇİLİ → biçi `mp_skip_format` çeviri anahtarı kullanılmaz hale geldiği için iki locale'den de **silindi** (ölü anahtar bırakılmadı). +### ⭐ `lsblk` AKTİF swap için `[SWAP]` yazar + +**Bu, canlı ISO'ya SSH ile bağlanıp GERÇEK çıktı okunarak bulundu.** +Tahminle değil: + +``` +$ lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT -b --noheadings -l /dev/sdb +sdb1 524288000 vfat /boot/efi +sdb2 1572864000 swap [SWAP] ← köşeli parantezli! +sdb3 25168969728 ext4 / +``` + +`read_existing_partitions` mountpoint'i doğrudan alıyordu, yani +`CustomPartition::mountpoint = "[SWAP]"` oluyordu. İki yere sızıyordu: + +1. **UI** — tablonun bağlama noktası sütununda `[SWAP]` görünüyordu +2. **mükerrer kontrolü** — iki swap'ı olan makinede (Windows diski + + Linux diski = çift önyüklemeli kurulumun tipik hali) ikisi de aynı + `"[SWAP]"` değerini taşıyor ve kullanıcı **var olmayan** bir + "mükerrer bağlama noktası" hatası görüyordu + +Bu makinede tek swap olduğu için sorun görünmüyordu — **kolayca kaçar.** + +| Düzeltme | Yer | +|---|---| +| `normalize_lsblk_mountpoint(raw, fstype)` | `[SWAP]` → `"swap"`. Yalnızca `FsType::Swap` için; diğerleri **dokunulmaz** (sessizce yutmak yok) | +| mükerrer kontrolü | yalnızca **gerçekten bağlanan** dosya sistemleri karşılaştırılır: `Swap`/`Lvm`/`LvmLv` hariç. `mountpoint_required` ile aynı gerekçe | + +> `fstab` işi zaten doğruydu: satırı `part.mountpoint`'e değil +> `part.fstype`'e göre yazıyor (`FsType::Swap => ("none", "sw", …)`). +> Yani mountpoint `"swap"` olması fstab'ı bozmaz — hatta bozmadığı için +> hata fstab'da değil, **mükerrer kontrolünde** görünmüyordu. + ### `selected_disk` hâlâ 3 yerde kullanılıyor 1. Tablo hangi diski gösteriyor + `manual_dual_bars` 2. Diyaloğun varsayılan hedefi @@ -691,11 +724,11 @@ nedeni yorumla sabitlendi. Log bile "MiB" derken argüman "MB" gönderiyordu. ``` cargo check --all-targets : 0 hata, 0 uyarı -cargo test : 145/145 (test modülü sayısı arttıkça güncel tut) +cargo test : 150/150 (test modülü sayısı arttıkça güncel tut) cargo clippy : ~77 uyarı, tamamı stil (collapsed_if, replace zinciri) ``` -Bu oturumda 1 → 145 test. Test modülü olmayan dosyalar (`users.rs`, +Bu oturumda 1 → 150 test. Test modülü olmayan dosyalar (`users.rs`, `location.rs`, `rescue.rs`, `funct.rs`, `autoinstall/mod.rs`, `main.rs`) içine modüller eklendi. Çoklu test modülü paylaşılan yardımcıları `steps/partition.rs::testutil` altındadır (`disk()`, `part()`). @@ -796,7 +829,7 @@ senaryoları dene: |---|---| | `src/jobs/partition.rs` | `plan_disk_layout`, `PhysicalExtent`, `PlannedCreate`, `disk_total_mb`, `read_physical_extents`, `device_map`; `disk_free_regions_mb` silindi | | `src/jobs/cleanup.rs` | **YENİ** — `EmergencyCleanupJob` | -| `src/steps/partition.rs` | **tek diske odaklı tablo, şerit YOK** (diyalogda da disk seçicisi yok), **seçime göre görünen butonlar** (`selected_free`), diske filtreli LVM, `validate_manual_on`, `manual_capacity_error`, `mountpoint_required`, `suggest_mountpoint`, `has_symbolic_remaining`, `build_table_rows`, `on_disk_changed`, `format_checkbox_from`, `skip_format_from`; `multidisk_tests`, `table_scope_tests`, `free_space_tests`, `symbolic_capacity_tests`, `selection_tests`, `edit_flow_tests`, `edit_disk_tests`, `testutil` | +| `src/steps/partition.rs` | **tek diske odaklı tablo, şerit YOK** (diyalogda da disk seçicisi yok), **seçime göre görünen butonlar** (`selected_free`), diske filtreli LVM, `validate_manual_on`, `manual_capacity_error`, `mountpoint_required`, `suggest_mountpoint`, `has_symbolic_remaining`, `build_table_rows`, `normalize_lsblk_mountpoint`, `on_disk_changed`, `format_checkbox_from`, `skip_format_from`; `multidisk_tests`, `table_scope_tests`, `free_space_tests`, `symbolic_capacity_tests`, `selection_tests`, `edit_flow_tests`, `edit_disk_tests`, `testutil` | | `src/jobs/users.rs` | `set_password_via_chpasswd` (stdin pipe) | | `src/jobs/bootloader.rs` | `CRYPTROOT_NAME`, `luks_backing_device`, `mounted_root_device` | | `src/jobs/finish.rs` | `RunComarJob` geri geldi; `ldconfig`/`update-environment`/depo fatal | diff --git a/src/steps/partition.rs b/src/steps/partition.rs index e3cce2a..fab4d46 100644 --- a/src/steps/partition.rs +++ b/src/steps/partition.rs @@ -63,8 +63,22 @@ fn read_existing_partitions(disk_path: &str) -> Vec FsType::Ext4, // bilinmeyen → varsayılan }; - // lsblk mount point alanı boşsa sonraki token gelmez; unwrap_or ile güvenli al - let mountpoint = tokens.next().unwrap_or("").to_string(); + // lsblk mount point alanı boşsa sonraki token gelmez; + // unwrap_or ile güvenli al. + // + // ⚠️ AKTİF swap için lsblk mountpoint sütununa `[SWAP]` + // YAZAR (canlı ISO'dan doğrulandı): + // + // sdb2 1572864000 swap [SWAP] + // + // Bu ham biçim UI'a sızıyordu: tablonun "bağlama noktası" + // sütununda `[SWAP]` görünüyordu ve mükerrer kontrolünde + // iki swap'ın çakışmasına yol açıyordu. Arayüzün kullandığı + // kanonik karşılığa çevriliyor. + let mountpoint = normalize_lsblk_mountpoint( + tokens.next().unwrap_or(""), + fstype.clone(), + ); parts.push(CustomPartition { disk: disk_path.to_string(), @@ -86,6 +100,34 @@ fn read_existing_partitions(disk_path: &str) -> Vec String { + // Başka türlerde köşeli parantezli değerler görürsek dokunma: + // nadir/normalleştirilmemiş bir çıktı olabilir, sessizce yutmayız. + match fstype { + FsType::Swap => { + if raw.eq_ignore_ascii_case("[SWAP]") || raw.is_empty() { + "swap".to_string() + } else { + raw.to_string() + } + } + _ => raw.to_string(), + } +} + /// `/sys/block` altındaki gerçek blok aygıtlarını (partition değil) listeler. /// Aygıt adına (`sda`, `nvme0n1`) bakarak türünü belirler. fn detect_drive_type(name: &str) -> String { @@ -534,13 +576,33 @@ fn validate_manual_on( // sda1'i neredeyse her zaman boş gelir. Boş değerler karşılaştırılırsa // "N tane atanmamış bölüm" kendi kendine mükerrer sayılır ve kullanıcı // var olmayan bir çakışma hatası görürdü. - let mountpoints: std::collections::HashSet<&str> = live_parts + // ⚠️ Yalnızca GERÇEKTEN bağlanan dosya sistemleri karşılaştırılır. + // + // REGRESYON: swap ve LVM satırları da sayılıyordu. `lsblk` AKTİF + // swap için mountpoint sütununa **`[SWAP]`** yazar (canlı ISO'dan + // doğrulandı): + // + // sdb2 1572864000 swap [SWAP] + // + // Bu bir bağlama noktası DEĞİLDİR. İki swap bölümü olan bir + // makinede (Windows'un diski + Linux diski — çift önyüklemeli + // kurulumun tipik hali) ikisi de aynı `"[SWAP]"` değerini alır ve + // kullanıcı var olmayan bir "mükerrer bağlama noktası" hatası + // görür. Tek swap olan makinelerde sorun görünmez, bu yüzden + // kolayca kaçar. + // + // LVM PV'nin de bağlama noktası yoktur (mount edilmez, fstab'a + // girmez) — `mountpoint_required` ile aynı gerekçe. + let is_mountable = |p: &&CustomPartition| { + !p.mountpoint.is_empty() + && !matches!(p.fstype, FsType::Swap | FsType::Lvm | FsType::LvmLv) + }; + let mountable: std::collections::HashSet<&str> = live_parts .iter() + .filter(|p| is_mountable(p)) .map(|p| p.mountpoint.as_str()) - .filter(|m| !m.is_empty()) .collect(); - let assigned = live_parts.iter().filter(|p| !p.mountpoint.is_empty()).count(); - if mountpoints.len() != assigned { + if mountable.len() != live_parts.iter().filter(|p| is_mountable(p)).count() { return Some(t!("mp_duplicate_mountpoint").to_string()); } @@ -3583,6 +3645,108 @@ mod multidisk_tests { // ── REGRESYON: mount EDİLMEMİŞ fiziksel bölüm ────────────── + /// ⭐ `lsblk`in `[SWAP]` biçimi kanonik karşılığa çevrilmeli. + /// + /// Gerçek canlı ISO çıktısı: + /// sdb2 1572864000 swap [SWAP] + #[test] + fn lsblk_swap_marker_is_normalized() { + use super::normalize_lsblk_mountpoint; + assert_eq!( + normalize_lsblk_mountpoint("[SWAP]", FsType::Swap), + "swap", + "lsblk'in [SWAP] biçimi 'swap' olmalı" + ); + // Swap mount edilmemişse sütun boş gelir; yine de swap'tır + assert_eq!( + normalize_lsblk_mountpoint("", FsType::Swap), + "swap", + "mount edilmemiş swap de 'swap' olmalı" + ); + } + + /// Diğer dosya sistemleri DEĞİŞTİRİLMEZ — özellikle köşeli + /// parantezli tuhaf bir çıktı varsa sessizce yutmak yerine + /// olduğu gibi bırakılır. + #[test] + fn non_swap_mountpoints_are_untouched() { + use super::normalize_lsblk_mountpoint; + assert_eq!(normalize_lsblk_mountpoint("", FsType::Ext4), ""); + assert_eq!(normalize_lsblk_mountpoint("/", FsType::Ext4), "/"); + assert_eq!( + normalize_lsblk_mountpoint("/boot/efi", FsType::Fat32), + "/boot/efi" + ); + assert_eq!( + normalize_lsblk_mountpoint("[weird]", FsType::Ext4), + "[weird]", + "swap dışında köşeli parantez normalleştirilmemeli" + ); + } + + /// ⭐ lsblk'in `[SWAP]` biçimi mountpoint'e SIZMASIN. + /// + /// Canlı ISO'dan alınan GERÇEK çıktı: + /// + /// sdb2 1572864000 swap [SWAP] + /// + /// Ham biçim UI'da görünüyor ve mükerrer kontrolüne giriyordu. + /// İki swap'ı olan bir makinede (Windows diski + Linux diski — + /// çift önyüklemeli kurulumun tipik hali) ikisi de `"[SWAP]"` + /// olduğu için "mükerrer bağlama noktası" hatası veriyordu. + #[test] + fn two_swap_partitions_are_not_duplicate_mountpoints() { + let disks = vec![disk("/dev/sda", 250), disk("/dev/sdb", 26)]; + let parts = vec![ + p("/dev/sda", "/dev/sda1", 500, FsType::Ntfs, ""), + p("/dev/sdb", "/dev/sdb1", 512, FsType::Fat32, "/boot/efi"), + // Windows'un swap'ı — lsblk bunlara "[SWAP]" yazar + p("/dev/sda", "/dev/sda2", 2_000, FsType::Swap, "[SWAP]"), + // Linux'un swap'ı + p("/dev/sdb", "/dev/sdb2", 1_500, FsType::Swap, "[SWAP]"), + p("/dev/sdb", "/dev/sdb3", 24_000, FsType::Ext4, "/"), + ]; + assert_eq!( + validate_manual_on(&parts, &[], true, &disks), + None, + "iki swap mükerrer sayılmamalı: {:?}", + validate_manual_on(&parts, &[], true, &disks) + ); + } + + /// İki gerçek mountpoint hâlâ mükerrer sayılmalı — filtre körleştirmemeli. + #[test] + fn two_real_root_mountpoints_are_still_duplicates() { + let disks = vec![disk("/dev/sda", 250), disk("/dev/sdb", 26)]; + let parts = vec![ + p("/dev/sda", "/dev/sda3", 10_000, FsType::Ext4, "/"), + p("/dev/sdb", "/dev/sdb3", 24_000, FsType::Ext4, "/"), + ]; + assert!( + validate_manual_on(&parts, &[], false, &disks).is_some(), + "iki '/' hâlâ geçersiz olmalı" + ); + } + + /// LVM PV'ler de mountpoint'siz sayılmalı — iki PV aynı boş + /// değeri taşısa bile çakışma üretmemeli. + #[test] + fn two_lvm_pvs_are_not_duplicate_mountpoints() { + let disks = vec![disk("/dev/sda", 250), disk("/dev/sdb", 26)]; + let mut pv1 = p("/dev/sda", "/dev/sda2", 10_000, FsType::Lvm, ""); + pv1.orig_device = String::new(); + let mut pv2 = p("/dev/sdb", "/dev/sdb2", 10_000, FsType::Lvm, ""); + pv2.orig_device = String::new(); + // doğrulama bir kök ister + let parts = vec![p("/dev/sdb", "/dev/sdb3", 20_000, FsType::Ext4, "/"), pv1, pv2]; + assert_eq!( + validate_manual_on(&parts, &[], false, &disks), + None, + "iki PV mükerrer sayılmamalı: {:?}", + validate_manual_on(&parts, &[], false, &disks) + ); + } + /// Canlı ISO'da mount edilmemiş fiziksel bölüm (mountpoint boş) /// düzeni GEÇERSİZ kılmamalı. ///