forked from pisilinux-rs/yali-rs
fix(partition): lsblk'in "[SWAP]" biçimi mountpoint'e sızıyordu
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) <noreply@anthropic.com>
This commit is contained in:
@@ -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 |
|
||||
|
||||
+170
-6
@@ -63,8 +63,22 @@ fn read_existing_partitions(disk_path: &str) -> Vec<crate::installer::CustomPart
|
||||
_ => 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<crate::installer::CustomPart
|
||||
parts
|
||||
}
|
||||
|
||||
/// `lsblk` MOUNTPOINT sütununu arayüzün kullandığı biçime çevirir.
|
||||
///
|
||||
/// ⚠️ AKTİF swap için lsblk mountpoint sütununa **`[SWAP]`** yazar
|
||||
/// (canlı ISO'dan doğrulandı):
|
||||
///
|
||||
/// sdb2 1572864000 swap [SWAP]
|
||||
///
|
||||
/// Ham biçim iki yere sızıyordu:
|
||||
/// 1. tablonun "bağlama noktası" sütununda `[SWAP]` görünüyordu
|
||||
/// 2. mükerrer kontrolünde iki swap çakışma üretiyordu
|
||||
///
|
||||
/// Swap kanonik karşılığı `"swap"`'tir (`COMMON_MOUNTPOINTS` ve fstab
|
||||
/// işi `FsType::Swap`'e bakar, mountpoint'e değil).
|
||||
fn normalize_lsblk_mountpoint(raw: &str, fstype: FsType) -> 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ı.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user