sys/veri_detay/#007

Sistem Asistanı (v1.1)

Son Senkronizasyon: 16.12.2025
disk_sagligi.py 249 satır • 11.47 KB
# sayfalar/disk_sagligi.py
from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, 
                             QComboBox, QTextEdit, QProgressBar, QMessageBox, QApplication)
from gorsel_araclar import SayfaBasligi, SvgIkonOlusturucu
import subprocess
import os

class DiskSagligiSayfasi(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QVBoxLayout(self)
        icon = SvgIkonOlusturucu.health_ikonu("#33AADD", 32)
        layout.addWidget(SayfaBasligi("Disk Sağlığı Analizi", icon))

        if os.path.exists("/usr/sbin/smartctl"):
            self.smart_bin = "/usr/sbin/smartctl"
        elif os.path.exists("/sbin/smartctl"):
            self.smart_bin = "/sbin/smartctl"
        else:
            self.smart_bin = "/usr/sbin/smartctl"

        h_sel = QHBoxLayout()
        self.combo_disk = QComboBox()
        self.diskleri_bul()
        h_sel.addWidget(QLabel("Disk Seç:"))
        h_sel.addWidget(self.combo_disk)
        
        btn_tara = QPushButton("🩺 Sağlık Taraması Yap")
        btn_tara.setStyleSheet("background-color: #33AADD; color: white; font-weight: bold;")
        btn_tara.clicked.connect(self.tara)
        h_sel.addWidget(btn_tara)
        layout.addLayout(h_sel)

        self.lbl_sonuc = QLabel("Durum: Bekleniyor")
        self.lbl_sonuc.setStyleSheet("font-size: 14pt; font-weight: bold; margin: 10px;")
        layout.addWidget(self.lbl_sonuc)

        self.txt_detay = QTextEdit()
        self.txt_detay.setReadOnly(True)
        # Daha modern, konsol benzeri font ve hafif koyu arka plan (eğer tema açıksa bile okunur olsun)
        self.txt_detay.setStyleSheet("font-family: 'Consolas', 'Monospace'; font-size: 10pt; line-height: 1.2;")
        layout.addWidget(self.txt_detay)

        # Onarım Butonu
        btn_onar = QPushButton("🛠️ Disk Hatalarını Onar (fsck - Reboot Gerekir)")
        btn_onar.setStyleSheet("background-color: #e67e22; color: white; font-weight: bold; padding: 10px;")
        btn_onar.clicked.connect(self.onarim_baslat)
        layout.addWidget(btn_onar)

    def diskleri_bul(self):
        self.combo_disk.clear() 
        try:
            out = subprocess.check_output("lsblk -d -n -o NAME,MODEL,TYPE", shell=True, text=True)
            for line in out.splitlines():
                if "disk" in line:
                    parts = line.split()
                    name = parts[0]
                    model = " ".join(parts[1:-1])
                    self.combo_disk.addItem(f"/dev/{name} - {model}", f"/dev/{name}")
        except: pass

    def raporu_detayli_turkcelestir(self, ham_metin):
        """Smartctl çıktısını analiz edip modern, detaylı Türkçe rapor çıkarır."""
        kimlik = []
        saglik = []
        istatistik = []
        hatalar = []
        
        lines = ham_metin.splitlines()
        disk_turu = "SATA/HDD"
        if "NVMe" in ham_metin: disk_turu = "NVMe/SSD"

        for line in lines:
            line = line.strip()
            
            # --- 1. KİMLİK BİLGİLERİ ---
            if line.startswith("Model Family:") or line.startswith("Model Number:"):
                kimlik.append(f"• Model:         {line.split(':', 1)[1].strip()}")
            elif line.startswith("Serial Number:"):
                kimlik.append(f"• Seri No:       {line.split(':', 1)[1].strip()}")
            elif line.startswith("User Capacity:"):
                cap = line.split(':', 1)[1].strip()
                if "[" in cap: cap = cap.split("[")[1].replace("]", "")
                kimlik.append(f"• Kapasite:      {cap}")
            elif line.startswith("Firmware Version:"):
                kimlik.append(f"• Yazılım Sür.:  {line.split(':', 1)[1].strip()}")

            # --- 2. SAĞLIK DURUMU ---
            elif "SMART overall-health" in line:
                stat = line.split(':', 1)[1].strip()
                saglik.append(f"• GENEL DURUM:   {'✅ SAĞLAM' if 'PASSED' in stat else '❌ BAŞARISIZ'}")
            elif "SMART Health Status:" in line:
                stat = line.split(':', 1)[1].strip()
                saglik.append(f"• GENEL DURUM:   {'✅ SAĞLAM' if 'OK' in stat else '❌ HATA'}")
            elif "Critical Warning:" in line:
                warn = line.split(':', 1)[1].strip()
                durum = "✅ Yok" if warn == "0x00" else f"⚠️ VAR ({warn})"
                saglik.append(f"• Kritik Uyarı:  {durum}")

            # --- 3. İSTATİSTİKLER (SATA ve NVMe Karışık) ---
            elif "Power_On_Hours" in line:
                # SATA formatı: ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE
                parts = line.split()
                if len(parts) > 9: istatistik.append(f"• Çalışma Süresi: {parts[-1]} Saat")
            elif "Power On Hours:" in line: # NVMe formatı
                istatistik.append(f"• Çalışma Süresi: {line.split(':', 1)[1].strip().replace(',','')} Saat")
                
            elif "Power_Cycle_Count" in line:
                parts = line.split()
                if len(parts) > 9: istatistik.append(f"• Açma/Kapama:    {parts[-1]} Kez")
            elif "Power Cycles:" in line: # NVMe
                istatistik.append(f"• Açma/Kapama:    {line.split(':', 1)[1].strip().replace(',','')} Kez")

            elif "Temperature_Celsius" in line:
                parts = line.split()
                if len(parts) > 9: istatistik.append(f"• Sıcaklık:       {parts[-1]} °C")
            elif "Temperature:" in line and "Celsius" in line:
                temp = line.split()[1]
                if temp != "0": istatistik.append(f"• Sıcaklık:       {temp} °C")

            # NVMe Özel Veri (Toplam Yazılan)
            elif "Data Units Written:" in line:
                # Genelde 512 byte units verilir, kabaca TB'a çevirelim
                raw_val = line.split(':', 1)[1].split('[')[0].strip().replace(',', '')
                try:
                    tb_val = int(raw_val) * 512 / (1024**4) # TB hesabı
                    istatistik.append(f"• Toplam Yazılan: {tb_val:.2f} TB")
                except: pass

            # --- 4. KRİTİK HATALAR (Eğer 0 değilse göster) ---
            # Reallocated_Sector_Ct
            if "Reallocated_Sector_Ct" in line:
                parts = line.split()
                raw = int(parts[-1])
                if raw > 0: hatalar.append(f"⚠️ Bozuk Sektör (Reallocated): {raw}")
            
            # Current_Pending_Sector
            elif "Current_Pending_Sector" in line:
                parts = line.split()
                raw = int(parts[-1])
                if raw > 0: hatalar.append(f"⚠️ Bekleyen Sektör (Pending): {raw}")
            
            # UDMA_CRC_Error_Count (Kablo hatası)
            elif "UDMA_CRC_Error_Count" in line:
                parts = line.split()
                raw = int(parts[-1])
                if raw > 0: hatalar.append(f"ℹ️ İletişim Hatası (CRC): {raw} (Kabloyu kontrol et)")
            
            # Media_and_Data_Integrity_Errors (NVMe)
            elif "Media and Data Integrity Errors:" in line:
                val = line.split(':', 1)[1].strip()
                if val != "0": hatalar.append(f"⚠️ Veri Bütünlüğü Hatası: {val}")

        # --- RAPOR OLUŞTURMA ---
        final_report = []
        final_report.append(f"=== {disk_turu} SAĞLIK RAPORU ===")
        final_report.append("")
        
        final_report.append("--- [1] CİHAZ BİLGİLERİ ---")
        final_report.extend(kimlik)
        final_report.append("")
        
        final_report.append("--- [2] SAĞLIK DURUMU ---")
        final_report.extend(saglik)
        if not hatalar:
            final_report.append("• Disk yüzeyinde kritik hata tespit edilmedi.")
        final_report.append("")
        
        if hatalar:
            final_report.append("--- [!] TESPİT EDİLEN SORUNLAR ---")
            final_report.extend(hatalar)
            final_report.append("")

        final_report.append("--- [3] İSTATİSTİKLER ---")
        final_report.extend(istatistik)
        
        return "\n".join(final_report)

    def tara(self):
        if not os.path.exists(self.smart_bin):
            QMessageBox.critical(self, "Eksik Bileşen", "smartmontools paketi eksik.\nKurmak için: sudo apt install smartmontools"); return

        dev = self.combo_disk.currentData()
        if not dev: return
        
        self.lbl_sonuc.setText("Taranıyor...")
        self.txt_detay.clear()
        QApplication.processEvents()
        
        final_output = ""
        
        try:
            # TEK SEFERDE YETKİLENDİRME (Auto -> SCSI Fallback)
            shell_cmd = (
                f"output=$({self.smart_bin} -a -d auto {dev} 2>&1); "
                f"if echo \"$output\" | grep -E -q 'Unknown USB bridge|specify device type'; then "
                f"{self.smart_bin} -a -d scsi {dev}; "
                f"else echo \"$output\"; fi"
            )
            
            cmd = ["pkexec", "sh", "-c", shell_cmd]
            process = subprocess.run(cmd, capture_output=True, text=True)
            final_output = process.stdout
            
            if not final_output.strip() and process.stderr:
                final_output = process.stderr

        except Exception as e:
            final_output = str(e)

        # Çıktıyı DETAYLI Türkçeleştir ve Göster
        # Eğer çok kısa bir çıktıysa (hata veya desteklenmiyor) direkt göster
        if len(final_output) < 300 and "Unknown" in final_output:
             self.txt_detay.setText(f"Disk verisi tam okunamadı.\nHata:\n{final_output}")
        else:
             turkce_cikti = self.raporu_detayli_turkcelestir(final_output)
             self.txt_detay.setText(turkce_cikti)
        
        # --- DURUM BELİRLEME (Görsel Renklendirme) ---
        durum = "BELIRSIZ"
        
        if "SMART Health Status: OK" in final_output: durum = "SAGLAM"
        elif "test result: PASSED" in final_output: durum = "SAGLAM"
        elif "Health Status: OK" in final_output: durum = "SAGLAM"
        elif "Critical Warning: 0x00" in final_output: durum = "SAGLAM"
        elif "test result: FAILED" in final_output or "Health Status: BAD" in final_output: durum = "HATALI"
        elif "Unknown USB bridge" in final_output: 
            self.lbl_sonuc.setText("⚠️ USB Tanınamadı")
            self.lbl_sonuc.setStyleSheet("font-size: 14pt; font-weight: bold; color: #f1c40f;")
            return

        if durum == "SAGLAM":
            self.lbl_sonuc.setText("✅ Durum: SAĞLAM")
            self.lbl_sonuc.setStyleSheet("font-size: 14pt; font-weight: bold; color: #2ecc71;")
        elif durum == "HATALI":
            self.lbl_sonuc.setText("❌ Durum: HATALI")
            self.lbl_sonuc.setStyleSheet("font-size: 14pt; font-weight: bold; color: #e74c3c;")
        else:
            self.lbl_sonuc.setText("⚠️ Durum: Veri Yok / Belirsiz")
            self.lbl_sonuc.setStyleSheet("font-size: 14pt; font-weight: bold; color: #f1c40f;")

    def onarim_baslat(self):
        dev = self.combo_disk.currentData()
        if not dev: return
        if QMessageBox.question(self, "Onarım Planla", f"{dev} için fsck onarımı planlanacak (Yeniden başlatma gerekir).", QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) == QMessageBox.StandardButton.Yes:
            try:
                subprocess.run(["pkexec", "touch", "/forcefsck"], check=True)
                QMessageBox.information(self, "Başarılı", "Onarım planlandı. Bilgisayarı yeniden başlatın.")
            except: QMessageBox.critical(self, "Hata", "Onarım planlanamadı.")
DATA_PAYLOAD (Açıklama)
Kapak

Sistem temizliği (detaylı ve kullanışlı ve tam kontrol sağlayacak şekilde güncellendi), Usb İso yazdırıcı (Artık kendi penceresinde ve detaylı şekilde dd modda usb'nize iso dosyalarınızı daha güvenle yazdırır) , Uygulama pencere boyutu (700 px altına dolayısı ile notebook vb küçük ekranlar içinde uyumlu olacak şekilde, özellikler güncellendi.

Pardus 25 (Debian 13) ve Pardus 23 (Debian 12) tabanlı Linux dağıtımları için geliştirilmiş; sistem izleme, bakım, onarım ve yönetim işlemlerini tek bir modern arayüzde toplayan gelişmiş bir araçtır.

Pardus 25 uyumlu sürümü indirmek için sağ taraftaki "indir" butonuna tıklayın ve çift tıklayıp kurun. Tüm bağımlılıkları 1 kere indirip internetsiz de çalışabilmektedir.

----

Özellikler

Uygulama modüler bir yapıya sahiptir ve aşağıdaki temel araçları içerir:

Sistem İzleme & Donanım

Genel Bakış: CPU, RAM, Swap kullanımı, anlık ağ trafiği ve harita üzerinde konum bilgisi. HUD Modu: Masaüstünde yüzen, kompakt sistem bilgi penceresi. Donanım Bilgisi: İşlemci, GPU, Batarya sağlığı, BIOS ve Çekirdek bilgileri. Süreç Yöneticisi: Çalışan işlemleri (PID, CPU, RAM) izleme ve sonlandırma.

Ağ & İnternet Ağ Tarayıcı: Wifi ağınızda kaç cihaz bağlı, ip adresleri, isim ve markaları gibi bilgileri görün. Wi-Fi Analizörü: Çevredeki ağları tarama, sinyal gücü grafiği ve kanal önerisi (2.4GHz optimizasyonu). Hız Testi: Çoklu iş parçacığı ile İndirme (Download), Yükleme (Upload) ve Gecikme (Ping) testi. DNS Yönetimi: Tek tıkla Google, Cloudflare, OpenDNS veya Otomatik DNS geçişi. Site Engelleyici: /etc/hosts üzerinden istenmeyen siteleri engelleme. Port Yöneticisi: Açık portları listeleme ve güvenlik duvarı (UFW) üzerinden port açma/kapama.

Bakım & Onarım

Sistem Temizliği: Apt önbelleği, eski kernel logları, tarayıcı çöp dosyaları ve çöp kutusu temizliği. Disk Sağlığı: Disk ömrü analizi ve sağlık raporu. Açılış Analizi: Sistemi yavaşlatan başlangıç servislerinin tespiti. Otomatik Bakım: Paket güncellemeleri, bozuk paket onarımı ve GRUB güncelleme araçları.

Disk & Dosya

Disk Analizcisi: Klasör boyutlarını ağaç yapısında görselleştirme. USB Yazdırıcı: ISO dosyalarını USB belleklere yazdırma (dd arayüzü).

Yönetim & Otomasyon

Cron Yöneticisi: Zamanlanmış görevleri grafik arayüzle ekleme/silme. Özel Komutlar: Sık kullandığınız uzun terminal komutlarını butonlara dönüştürme. Başlangıç Yöneticisi: Sistem açılışında çalışan uygulamaları yönetme.

Kurulum

Bu proje, sistem kütüphanelerindeki farklılıklar nedeniyle Pardus 25 ve Pardus 23 için ayrı paketleme yöntemleri sunar.

Yöntem 1: .deb Paketi ile Kurulum (En Kolay)

GitHub Releases sayfasından sisteminize uygun olan sürümü indirin ve kurun:

Pardus 25 / Debian 13 İçin: sistem-asistani_1.1_amd64.deb

Pardus 23 / Debian 12 İçin: sistem-asistani_1.0_pardus23_amd64.deb

sudo dpkg -i indirilen_paket_adi.deb
sudo apt-get install -f  # Eksik bağımlılık varsa tamamlar

Yöntem 2: Paketleme Sihirbazı ile Kurulum (Önerilen)

Bu yöntem, kaynak kodları indirir, gerekli Python kütüphanelerini internetten çeker ve sizin sisteminize özel, internetsiz çalışabilen bir .deb paketi üretir.

Yan taraftan "Kaynak Kod İndir" tıklayın :

ya da Kaynak Kod İndir Zip

Sisteminize Uygun Scripti Çalıştırın:

Pardus 25 (Debian 13) Kullanıyorsanız:

sudo sh ./paketle_pardus25.sh

Pardus 23 (Debian 12) Kullanıyorsanız:

sudo sh ./paketle_pardus23.sh

Oluşan Paketi Kurun: İşlem bittiğinde oluşan .deb paketini çift tıklayarak kurun ya da : (* yerine paketadiniz.deb)

sudo dpkg -i *.deb

Önemli Notlar

Root Yetkisi: Uygulama, sistem dosyalarına müdahale ettiği için (güncelleme, UFW, hosts vb.) kritik işlemlerde pkexec (veya Pardus 23’te policykit) aracılığıyla root şifrenizi isteyecektir.

Uyumluluk:

Pardus 25 / Debian 12 (Bookworm): Tam uyumlu.

Pardus 23 / Debian 11 (Bullseye): Tam uyumlu (Özel paketleme scripti ile).

Meta Veri (Özet)

Linux Sistem, Yönetim, Takip, Bakım, Kontrol aracı

4,587
Sinyal (Ağ Hiti)
288.29 KB
Kapasite

Ağda Paylaş