12.10.2017

Günlük ihtiyaçlar için Powershell

Bu yazı, standart komut satırı araçlarının Powershell eşdeğerlerini listelemeyi amaçlıyor. Aşağıda önce komut satırı çözümünü, sonrasında da Powershell eşdeğerini yazacağım.

Dosya sistemi işleri

Dosya sistemi temel komutları olan cd, dir, del, mkdir gibi komutları aynen Powershell'de de kullanabiliyoruz. Bunlar alias'lar aracılığıyla oluyor. Ama aslında arka tarafta komut satırı penceresinin iç komutlarından başka komutlar çalışıyor.

C:\> dir
PS C:\> Get-ChildItem

C:\> cd 
PS C:\> Set-Location

C:\> del
PS C:\> Remove-Item

C:\> mkdir
PS C:\> New-Item

Bunlara ek olarak örneğin tüm alt klasörlerde bulunan ve isminde fatura geçen dosyaları bulmak için

C:\> dir *fatura* /s
eşdeğeri
PS C:\>dir -Include *fatura* -Recurse

Hatta daha da fazlasını yapıp içinde fatura geçen dosyaların son 1 ayda oluşturulanlarını bulmak için ise

PS C:\> dir -Include *fatura* -Recurse | ? {$_.CreationTime -gt (Get-Date).AddMonths(-1)} | select CreationTime, LastWriteTime, Fullname

kullanılabilir.

En çok ihtiyaç duyduğum başka bir şey ise içinde belli bir kelime veya karakter kümesi geçen belli tipte uzantıya sahip dosyaları bulmak. Bunu klasik komut satırında şu şekilde yapıyordum:


C:\> findstr /s /i "admin" *.log

Bunun eşdeğeri de Select-String cmdlet'i. Alias'ı ise sls:

PS C:\> dir *.log -Recurse | sls -Pattern "admin"


findstr.exe alt klasörleri de kapsama alabilecek /s anahtarına sahip. Select-String (sls) cmdlet'inin böyle bir yeteneği yok ama Get-ChildItem (dir) cmdlet'inin çıktısını ona yönlendirerek bu ihtiyacı karşılayabiliyoruz. Eğer alt klasörler değil de sadece mevcut klasördeki bazı dosyalar içinde arama yapacaksak dir (Get-ChildItem) komtuna ihtiyaç yok. Doğrudan sls (Select-String) kullanabiliriz:

PS C:\> sls -Path C:\*.log -Pattern "admin" 

Select-String cmdlet'i varsayılan olarak küçük/büyük ayrımı yapmaz (case insensitive). Özellikle küçük/büyük harf ayrımı olmasını isterseniz -CaseSensitive parametresini kullanmalısınız.

Ağ sorun giderme

Komut satırının meşhur ping komutu harici bir komut olduğu için Powershell'de ping çalışıyor. Ama bunun yerine başka bir alternatif komut daha var.

C:\> ping 192.168.1.1                                   
                                                        
Pinging 192.168.1.1 with 32 bytes of data:              
Reply from 192.168.1.1: bytes=32 time<1ms TTL=128       
Reply from 192.168.1.1: bytes=32 time<1ms TTL=128       
Reply from 192.168.1.1: bytes=32 time<1ms TTL=128       
Reply from 192.168.1.1: bytes=32 time<1ms TTL=128       
                                                        
Ping statistics for 192.168.1.1:                        
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:          
    Minimum = 0ms, Maximum = 0ms, Average = 0ms         


PS C:\> Test-Connection -Computarname 192.168.1.1                 
                                                                  
Source    Destination   IPV4Address  IPV6Address Bytes    Time(ms)
------    -----------   -----------  ----------- -----    --------
MET8      192.168.1.1   192.168.1.1              32       0       
MET8      192.168.1.1   192.168.1.1              32       0       
MET8      192.168.1.1   192.168.1.1              32       0       
MET8      192.168.1.1   192.168.1.1              32       0      
 


Bu bildiğimiz ICMP ping.exe'nin karşılığı. Aynı ping.exe'de olduğu gibi varsayılan olarak 32 byte'lık paketler gönderiyor. Varsayılan olarak 1 saniye bekliyor, varsayılan olarak 4 paket gönderip duruyor. Sırasıyla bu parametreleri değiştirmek için -BufferSize, -Delay ve -Count kullanmak gerek.

Ayrıca ICMP ile değil de, TCP ile herhangi bir portu denemek istersek de

PS C:\> Test-NetConnection -ComputarName server01 -Port 21

kullanabiliriz. Bunun eşdeğeri klasik komut satırında yoktu. Bunun yerine psping veya benzer uygulamaları kullanıyorduk.

Hizmetler

Yerel bilgisayardaki hizmetlerin bir listesini almak için komut:

PS C:\> Get-Service

veya kısaca

PS C:\> gsv

yeterli. Ama hayat her zaman bu kadar kolay olmuyor. İlgilendiğimiz sadece DHCP client hizmeti ise şu şekilde bir komut ile durumunu sorgulayabiliriz:

PS C:\> gsv dhcp

Status   Name               DisplayName
------   ----               -----------
Running  Dhcp               DHCP Client


Bu hizmeti tekrar başlatmak için boru karakteri ile Get-Service cmdletinin yukarıdaki çıktısını Restart-Service cmdlet'ine yönlendirebiliriz.

PS C:\> gsv dhcp | Restart-Service

Bazen de adını tam bilmediğimiz bir hizmetin durumunu öğrenmek isteriz. Örneğin "Bit Locker Drive Encryption Service"in kısa servis adını bulmak için şunu yapabiliriz:

PS C:\> gsv | select DisplayName, Name, Status | sls "bit"

@{DisplayName=BitLocker Drive Encryption Service; Name=BDESVC; Status=Stopped}
@{DisplayName=VMware USB Arbitration Service; Name=VMUSBArbService; Status=Running}


2 tane hizmet döndü, bunların ilki bizim aradığımız. Kırmızı ile belirttiğim kısa hizmet adının hemen devamında da Status = Stopped olarak gözüküyor. Bunu tekrar başlatmak istersek

PS C:\> Start-Service BDESVC

dememiz yeterli.

Sadece çalışan servisleri başlatmak için kullanabileceğimiz bir parametresi yok Get-Service cmdlet'inin. Bunun yerine Get-Service'in çıktısını Where-Object cmdlet'ine yönlendirerek sadece çalışanları süzebiliriz:

PS C:\> gsv | ? {$_.Status -eq "Running"}

Eğer bu işi yerel makinede değil de uzaktaki bir makinede yapmak istiyorsak Get-Service cmdlet'ine -ComputerName parametresi ile uzak makine adını belirmek gerek.

PS C:\> gsv -Computername server01| ?{$_.Status -eq "Running"}

Windows Olayları

En sık kullanılan araçlardan biri de Windows Olaylarıdır. Örneğin sistem olay günlüğüne bakmak için şu cmdlet'i kullanabiliriz:

PS C:\> get-eventlog -LogName system

Tabi bu binlerde kayıt dönebilir. Bunun yerine en yeni 10 olaya

PS C:\> get-eventlog system -Newest 10

ya da son 1 saatte meydana gelen olaylara bakmak isteyebiliriz:

PS C:\> get-eventlog system -After (Get-Date).AddHours(-1)

Eğer belli bir Event ID'ye sahip olayları süzmek isterseniz bu noktada yine Where-Object'e başvurmak gerek.

PS C:\> Get-Eventlog -LogName system -Newest 10 | Where-Object {$_.EventID -eq 7040}

Where-Object'e başvurmadan doğrudan Get-Eventlog tarafından süzme işleminin yapılabiliyor olması güzel olurdu, ama olmamış. Bunun ne dezavantajı var? Yukarıdaki örnekte öncelikle son 10 olayı görmek istiyor, sonrasında da bu olayların içinde Event ID'si 7040 olanları seçiyoruz. Bu durumda dönen olay sayısı 10 da olabilir, 0 da olabilir. Yani Event ID'si 7040 olan son 10 olayı almak istersek bu sefer olayın sırasını değiştirmek lazım:

PS C:\> Get-EventLog -LogName system | Where-Object {$_.EventID -eq 7040} | Select-Object -First 10

Ancak bu da nispeten ilk duruma göre çok daha fazla uzun sürecek. Çünkü Get-Eventlog çalışmaya başlayınca en yeni olaylardan başlayarak olayları getirir. Belli bir ölçüt belirtilmişse o ölçüte göre (son 5 olay, son 1 saatte olan olaylar, belli bir kaynaktan gelenler vs.) göre işlem yapar. Ancak son örnekteki gibi bir ölçüt yoksa tüm olayları tarar, ve sonrasında bunların içinden süzme işlemi yapar. Bu da hem daha fazla işlemci hem de daha fazla bellek kullanımını gerektirir.

Kayıt Defteri

Windows Kayıt defteri ile uğraşmak nispeten komut satırına göre daha kolaydır. Yolunu bildiğiniz bir kayıt defteri konumunu sanki dosya sisteminde bir konumda çalışıyormuş gibi cd (Get-ChildItem) cmdlet'iyle görebilirsiniz.

PS C:\> dir HKLM:\Software\Microsoft\Windows\CurrentVersion\Run

Üstelik de her adımda tab ile tamamlama imkanıyla.

Get-ChildItem ile gezilebilecek yerler dosya sistemi ile kayıt defterinden ibaret değil. Bu tip nesnelere PowerShell Drive deniyor. Tüm PSDrive sürücülerinin listesi için

PS C:\> Get-PSDrive                                         
Name    Used (GB) Free (GB) Provider      Root              
----    --------- --------- --------      ----              

Alias                       Alias                           
C                           FileSystem    C:\               
Cert                        Certificate   \                 
D                           FileSystem    D:\               
Env                         Environment                     
Function                    Function                        
S                           FileSystem    \\server\paylasim 
HKCU                        Registry      HKEY_CURRENT_USER 
HKLM                        Registry      HKEY_LOCAL_MACHINE
WSMan                       WSMan                           


gibi bir sonuç elde ederiz. Bu da demektir ki örneğin alias'lar hakkında bilgi için Get-Alias ve Get-Help'in dışında doğrudan

PS C:\> cd Alias:

komutunu kullanıp dir ile tüm alias listesini alabiliriz.

Kayıt defteri konusuna gelelim. HKLM\Software\Microsoft\CurrentVersion\Run altındaki değerleri sorgulayalım:

PS C:\> cd HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\run
PS C:\> dir

Burada bazı değerler olmasına rağmen içerik gözükmedi. dir (Get-ChildItem) sadece alt anahtarları listeler. Değerleri görmek için

PS C:\> Get-ItemProperty .                                          
Apoint      : C:\Program Files\DellTPad\Apoint.exe                  
PSPath      : Microsoft.PShell.Core\Registry::HKEY_LOCAL_MACHINE\...
PSParentPath: Microsoft.PShell.Core\Registry::HKEY_LOCAL_MACHINE\...
PSChildName : run                                                   
PSDrive     : HKLM                                                  
PSProvider  : Microsoft.PowerShell.Core\Registry                    


kullanabiliriz (ekrana sığsın diye kısalttım). Burada Run anahtarı altında yer alan değer Apoint'ti.

Yeni Registry değeri yaratmak için

PS C:\> New-Item Adobe

ve bu alt anahtarın altında kayıt defteri değerleri yaratmak için ise

PS C:\> New-ItemProperty -Path . -Name "Disable" -Type DWord -Value 1

kullanabiliriz. Aynı şekilde alt anahtarları silmek için Remove-Item, değerleri silmek için ise Remove-ItemProperty kullanılmalı.

Ortam Değişkenleri

Ortam değişkenleri de bir sistemin işleyişinde önemli yere sahip. Önceki başlıkta Get-PSDrive ile gezinmeye uygun nesneleri listelerken Env de çıkmıştı. Yani ortam değişkenlerinden PATH'i görmek için

PS C:\> cd ENV:                                                   
PS C:\> dir Path                                                  
Name                        Value                                 
----                        -----                                 
Path                        C:\ProgramData\Oracle\Java\javapath...


kullanmak mümkün. Ayrıca

PS C:\> $ENV:Path

de aynı işi yapar. Daha okunaklı bir liste için

PS C:\> ($Env:Path).Split(";")

yapabiliriz. Bu listeye örneğin C:\Scripts klasörünü eklemek istersek yapmamız gereken

$Env:Path += ";C:\Scripts"

Veya bunu tekrar silmek için

$Env:Path = $Env:Path.Replace(";C:\Script","")

yapabiliriz.

Son olarak bazı durumlarda uyumsuz veri tiplerinin gizemini çözmek için kullanılabilecek cmdlet Get-Member'a örnek vereyim:

PS C:\> $Env:Path | Get-Member

Uzun bir liste verecek. İlk sırada yer alacak

TypeName: System.String

bizim için anahtar. Örnek bir kullanım için tüm alias'lar içinde hizmetlerin yönetimi için kaç alias yaratıldığını bulmak isteyelim.

PS C:\> dir Alias:

komutu ile  tüm alias'ları listeleyebiliriz. Ama acaba bunların kaçının içinde "service" geçiyor. Select-String (sls) cmdlet'iyle içinde service geçenleri bulmaya çalışalım:

PS C:\> dir Alias: | sls "service"

Hiçbir şey dönmedi. Neden? Çünkü adından da anlaşılacağı gibi Select-String cmdlet'i sadece string veri tipi üzerinde çalışır. Sebebi dir Alias: komutunun string veri tipi dönmemesi olabilir mi? Bakalım:

PS C:\> dir Alias: | Get-Member                                  
                                                                 
   TypeName: System.Management.Automation.AliasInfo              
                                                                 
Name                MemberType     Definition                    
----                ----------     ----------                    
Equals              Method         bool Equals(System.Object obj)
GetHashCode         Method         int GetHashCode()             
GetType             Method         type GetType()                


diye uzayan bir çıktı üretir. İlk satırda yazan

   TypeName: System.Management.Automation.AliasInfo              

bizim için önemli. Yani string veri tipi dönmemiş. Bir array döndüğü için array'in ilk elemanının tüm özelliklerini (property) yazalım:

PS C:\> (dir Alias:)[0] | fl *         
                                       
DisplayName       : % -> ForEach-Object
CommandType       : Alias              
Definition        : ForEach-Object     
ReferencedCommand : ForEach-Object     
ResolvedCommand   : ForEach-Object     


Burada çok şaşırtıcı olmayan "DisplayName" adında bir alan var. Bu alanın tipini kontrol edelim:

PS C:\> (dir Alias:)[0].DisplayName | Get-Member 
                                                 
   TypeName: System.String                       

String'i bulduk. Demek ki Select-String'in girişi bu alan olmalı.

PS C:\> (dir Alias:).DisplayName | sls "service"
                                                
gsv -> Get-Service                              
sasv -> Start-Service                           
spsv -> Stop-Service                            


Sonuçta 3 alias olduğunu gördük. İlla ki powershell saysın dersek:

PS C:\> (dir Alias:).DisplayName | sls "service" | Measure
                                                          
Count    : 3                                              
Average  :                                                
Sum      :                                                
Maximum  :                                                
Minimum  :                                                
Property :                                                

Powershell'e giriş

Windows'da komut satırının yeteneklerinin günümüz beklentilerinin altında kalmasına çözüm olarak ortaya çıkan Powershell faydalı ve kullanışlı bir framework haline geldi. .Net altyapısı üzerine inşa edilen sistem her yeni sürümde daha faydalı işlevler sunuyor

Powershell komutlarına cmdlet deniyor. Bir fiil ve ismin tire işareti ile birleşiminden oluşuyorlar. Örneğin çalışan süreçlerin listesini almak için kullanılacak komut (cmdlet):

Get-Process
Ama her seferinde bu kadar uzun komutlar girmemek için kısaltma amaçlı "alias"lar eklenmiş. Her seferinde Get-Process yazmak elbette mümkün, ama kısaltmak isterseniz

gps
veya
ps
de aynı işi yapıyor. Bu alias elbette linuxtaki eşdeğeri ps komutundan geliyor. Ama linux eşdeğerinden farklı olarak tamamen nesne yönelimli (object oriented). Tüm çalışan süreçlerin listesini değil de sadece svc ile başlayan süreçlerin listesini görmek istersek yapılacak
ps svc*
yazmak. Bunun sonucunda aşağıdaki gibi bir çıktı üretecek:

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    844      30    19016      21172    90             232 svchost
   1005      37   112316     114080   190             396 svchost
   2163      71    72416      72612   349             412 svchost
    652      34    12444      20520   145             452 svchost
    527      19     8504      14744    82             756 svchost
    547      18     6752      10376    71             796 svchost
   1250     183    24952      28980  1309            1240 svchost
    325      19     3396       8688    54            1508 svchost
    489      38    27524      28188   116            1532 svchost
    108      10     3316       3040    42            1844 svchost
     55       6      712       1224    21            2036 svchost
    369      17     5584      10000    91            2044 svchost
     53       6      712       1280    21            2088 svchost
    100       8     1312       2224    24            2136 svchost
    165      14     4176       5092    48            2568 svchost
    145      11     2148       5920    43            5968 svchost


Buradaki sütünların açıklamaları [1] ve [2] de var.
Örneğin handle sayısı 1000'den fazla olan ve svc ile başlayan süreçleri listelemek için

ps svc* | ? {$_.Handles -gt 1000}

yazmak yeterli. Bu komutun kısaltılmış hali. Uzun uzun alias kullanmadan yazmak istersek komut şöyle olurdu:
Get-Process -Process svc* | Where-Object {$_.Handles -gt 1000}
Soru işareti (?) Where-Object cmdlet'inin bir alias'ı. Get-Process cmdlet'inin varsayılan parametresi de Process olduğu için ayrıca -Process yazmaya gerek yok. Önemli olan kısmı boru karakterinden (|) sonrası. Komut satırında olduğu gibi burada da boru karakteri bir komutun çıktısını diğer komuta giriş olarak veriyor. svc ile başlayan süreçlerlerin listesini al, Where-Object komuduna ver. O da bunları bir döngüye soksun (küme parantezleri sanal bir for döngüsü gibi), sadece Handles değeri 1000'den büyük olanları çıkış olarak üretsin. Burada $_ sanal for döngüsündeki döngü değişkeninin yerine geçiyor. Döngünün her adımında nesnenin Handles özelliğini alıp -gt ile "büyüktür" (greater than) işlemine tabi tutuyor. Sonucunda da şu çıkıyor:

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
   1008      38   114932     113968   193             396 svchost
   2226      71    75344      73328   347             412 svchost
   1245     182    24888      28940  1308            1240 svchost


Tam da istenen bu. Powershell bunun için güzel :)

Hatta bunları da Working Set değerine göre azalan şekilde sıralamak istersek yazılması gereken bir boru karakteri daha var:
ps svc* | ? {$_.Handles -gt 1000} | sort WS -Desc
Bu komutu da uzun uzadıya yazmak istersek
Get-Process -ProcessName svc* | Where-Object {$_.Handles -gt 1000} | Sort-Object -Property WS -Descending
olurdu. Tabloyu çok karmaşık bulursanız, sadece Handles ve Working Set değerlerni süreç isim ve ID'leriyle görmek isterseniz bu alanlardan sadece bazılarını select ile seçmeniz gerekir:
ps svc* | ? {$_.Handles -gt 1000} | sort WS -Desc | select Id, ProcessName, WS, Handles

Bu noktadan sonra uzunlarını yazmaya gerek yok bence.

Hala eklenebilecek şeyler var. Working Set sütununun sayısal biçimlendirmesini beğenmeyenler binlik ayraç kullanmak isteyebilir. Bu durumda
ps svc* | ? {$_.Handles -gt 1000} | sort WS -Desc | select Id, ProcessName, @{N="WorkingSet";E={"{0,13:N0}" -f $_.WS}}, Handles

yazılabilir. Sonuç şu şekilde olur:

 Id  ProcessName       WorkingSet                          Handles
 --  -----------       ----------                          -------
 396 svchost           114.790.400                           1005
 412 svchost            72.474.624                           2173
1240 svchost            29.532.160                           1245


Çıkışı buraya sığdırmak için boşlukları sildiğimi itiraf etmeliyim. Ama bunu gerek kalmadan sonuç üretmek için de Format-Table * -Autosize ekleyebilirdim. Yani:
ps svc* | ? {$_.Handles -gt 1000} | sort WS -Desc | select Id, ProcessName, @{N="WorkingSet";E={"{0,13:N0}" -f $_.WS}}, Handles | ft -AutoSize
Sonuç şöyle olurdu:

  Id ProcessName WorkingSet    Handles
  -- ----------- ----------    -------
 396 svchost       114.221.056    1005
 412 svchost        72.462.336    2173
1240 svchost        29.532.160    1247


Temiz ve güzel.

9.10.2017

Fedora'da dnf kullanımı

Fedora'da yum'ın yerini alan dnf gayet pratik. Ama özetlemek için birkaç önemli noktayı yazmak istedim, biraz da apt ile kıyaslayarak (// işaretinden sonrası Ubuntu için).

Repository'leri güncellemek

# dnf check-update  // apt update
Kurulu bütün paketleri güncellemek
# dnf update // apt upgrade
Tek bir paketi güncelleme
# dnf update firefox // apt upgrade firefox
Veya daha da öncesinde paket kurmak
# dnf install firefox // apt install firefox
Paketi kaldırmak
# dnf remove firefox // apt remove firefox
Bazen log dosyaları vs ile birlikte programın tüm artıklarından kurtulmak gerekir. Bu işin dnf'te karşılığı yok.
 # --------- // apt purge firefox (veya apt remove --purge firefox)
Kurulu paketi tekrar kurmak
# dnf reinstall firefox  //  apt reinstall firefox
Başka bir programın bağımlılığı olarak kurulmuş ama şu anda ihtiyaç duyulmayan paketleri kaldırmak için
# dnf autoremove // apt autoremove
Güncellenebilir (veya kurulu) olan paketlerin listesini almak için
# dnf list --upgrades (--installed) // apt list --upgradable (--installed)
Bir paket aramak
# dnf search (all) firefox // apt-cache search firefox
Bir paket hakkında ayrıntılı bilgi almak
# dnf info firefox // apt show firefox
Kurulu ve depolardaki sürüm hakkında bilgi almak
# dnf info firefox // apt-cache policy firefox
Bir dosyayı hangi paket kurdu
# dnf provides <dosya_adi> //  dpkg -S <dosya_adi> (veya # apt-file search <dosya_adi>
Komut geçmişini incelemek
# dnf history // # less /var/log/apt/history.log [bkz. 2]
Ubuntu ile aralarındaki bir küçük fark da örneğin dnf update sonrasında emin misiniz sorusunun cevabının varsayılan olarak "hayır (H)" olması. Ubuntu'da bu varsayılan olarak evetti.

[1] https://www.digitalocean.com/community/tutorials/package-management-basics-apt-yum-dnf-pkg
[2] https://askubuntu.com/questions/21657/how-do-i-show-apt-get-package-management-history-via-command-line

27.09.2017

takas bölümünü etkinleştirmek

Mevcutta bir linux kurulumuna sahip bir makineye ikinci bir linux yüklüyorum. İkinci linux için partition hazır. Ama takas (swap) bölümünü diğer linux kurulumu ile paylaşmak istiyorum. Çok yüksek güvenlikli bir sistem olsaydı bunu yapmamak lazım. Ama kullandığım öyle bir sistem değil ve bunu yapmak mümkün.

İkinci linuxun kurulumu sırasında sda7'yi / (kök) olarak mount etmeyi seçtim, ama swap için bir partition seçmedim. Seçersem bu partition'ı formatlayacak, ve diğer linuxun bu disk bölümüne bağlantısı kopacak.

İkinci linuxun kurulumu tamamlandıktan sonra

$ free
          total     used      free    shared    buff/cache   available
Mem:     1828852    796260    445196   141164     587396        627628
Swap:       0          0         0

yazarak sistemin herhangi bir swap kullanmadığını (Swap satırındaki değerler tümü 0) doğruladım. Mevcut sistemdeki takas bölümünün (swap partition) hangisi olduğunu bulmak için fdisk'i kullandım:

$ sudo fdisk -l

Bu komutun çıktısında türü Linux takas olarak listelenen tek bölümün sda8 olduğunu gördüm. Birinci kurduğum linux zaten bu bölümün yapılandırmasını yaptığı için

$ sudo mkswap /dev/sda8

yapmama gerek kalmadı. Eğer ilk defa yapılandırıyor olsaydım bu komutu kullanmam gerekecekti. Bölüm hazır olduğu için doğrudan

$ sudo swapon /dev/sda8
Komutu ile takas alanını etkinleştirdim. Bunu doğrulamak için

$ free
           total        Used      free     Shared   buff/cache       available

Mem:       1828852     796260    445196    141164   587396             627628
Swap:      3771388         0    3771388


Komutunu kullandım. Son satırda total sütununda swap'ın sıfırdan farklı bir değerde olması yeterli.

Yalnız bu, bir sonraki açılışta takas bölümünün tekrar bağlanacağını garantilemiyor. Bunu garantilemek için /etc/fstab dosyasına ilgili girişin yapılması gerekiyor. Yeni linux sistemlerinde disk bölümlerine UUID'ler ile erişiliyor. Mevcut disk bölümlerinin UUID'lerine erişmek için blkid komutunu kullanmak gerek.

$ sudo blkid
Bu komutun sonunda /dev/sda8 bölümüne ait UUID'yi kopyalayarak /etc/fstab dosyasına şu şekilde girdim:

UUID="....."        swap          swap        defaults     0  0

Bir sonraki açılışta free komutu ile takas bölümünün mount edildiğini doğruladım, konu kapandı.

24.09.2017

xfce masaüstü özelleştirmeleri

Fedora xfce spin kullandığım bir dizüstü bilgisayarda ses açma / kapama ve medya tuşlarının (durdur, ileri, geri gibi) çalışmadığını farkettim. Bu duruma şu şekilde bir çözüm buldum:

Klavye ayarlarına girerek kısayollar sekmesine geçtim. Önce bir terminal penceresinde şu komutların ses açma / kapama görevi görüp görmediğini denedim:

amixer set Master 10000+
amixer set Master 10000-
Bu komutların işe yaradığını görerek klavye kısayollarına yeni tuşuna basarak bu komutları birer birer ekledim. Bittikten sonra da klavyedeki ilgili düğmeye basarak atamayı tamamladım.

Ses kapatma (mute) işlevi için de

amixer set Master toggle

komutunu kullandım. Profilimin altına .Xmodmap diye bir dosya oluşturmak ve içine

keycode 174 = XF86AudioLowerVolume
keycode 176 = XF86AudioRaiseVolume
keycode 162 = XF86AudioPlay
keycode 164 = XF86AudioStop
keycode 144 = XF86AudioPrev
keycode 153 = XF86AudioNext

ekleyerek xmodmap .Xmodmap komutunu çalıştırmak işe yaramadı maalesef.

Medya tuşları için kısayollar pragha uygulamasına atanmıştı. Kullanmadığım bir uygulamaydı,

sudo dnf remove pragha

komuduyla bu uygulamadan kurtuldum. Ama klavye kısayollarında bu kaldı. Bu kısayolları Spotify ile kullanabilmek istiyordum. Bu girişleri çift tıklayarak durdurma için
dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.PlayPause
komudunu kullandım. Karşısındaki XF86AudioPlay durum için uygundu; dokunmadım. Sonraki şarkıya geçiş için
dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Next
komudunu kullandım. Karşısındaki XF86AudioNext durum için uygundu; değiştirmedim. Önceki şarı geçişi için
dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Previous
komudunu kullandım. Bunun karşısındaki XF86AudioPrev de uygundu, değiştirmedim.

Şu anda Spotify'ı sorunsuz olarak kullanabiliyorum.

Ayrıca şifre ekranındaki duvar kağıdını değiştirebileceğim bir yer de bulamıyordum. Bunun çözümünü de şöyle buldum:

/etc/lightdm/ klasörünün altındaki lightdm-gtk-greeter.conf dosyasını root ile (ya da sudo) açıp [greeter] başlığının altındaki background öğesinin değerini değiştirdim. Yalnız profilimin altındaki bir yolu göstermem çözüm olmadı. Bunun için istediğim dosyayı da /usr/share/background/ klasörüne kopyaladım.

16.01.2017

Fedora'da i ve ı harflerini basamamak

Fedora'yı 24'ten 25'e yükseltince i ve ı harflerini (küçüç/büyük) basamadığımı farkettim. Arama yaptığımda bu sorunun aslında 22'den beri olduğunu, ancak bazı donanımlarda ortaya çıktığını gördüm. Gerçi benim makinemde birkaç sürümdür kuruluydu Fedora ama nedense 25. sürümde ortaya çıkmaya karar vermiş. Çözüm olarak Wayland'i GDM için devre dışı bırakmaktan bahsedilmiş. Bunun için tercih edilen metin editörünüzü root ile çalıştırdıktan sonra
/etc/gdm/custom.conf 

dosyasını açarak
#WaylandEnable=false
satırının başındaki # işaretini kaldırarak
WaylandEnable=false
haline getirip kaydetmek ve sistemi tekrar başlatmak gerek. i harfine basamadan favori metin editörümü root ile başlatmak için biraz yaratıcılığımı kullanmam gerekti :)

Bunun uzun vadede ne gibi sonuçları olacak, bilmiyorum. Gelecekte bir ara bunu değiştirmek gerekebilir ama sürüm 22'de bile aynı hataların alındığını görünce bunun pek kısa vadede olacağını da sanmıyorum.

5.01.2017

Windows ve Bellek

Windows'da bellek kullanımı konusu oldukça karmaşık bir konudur. Görev Yöneticisinde yer alan sanal bellek, çalışan küme, takas dosyası gibi terimler kafaları karışabilir. En basitinden bir programın işletim sisteminden ne kadar bellek talebinde bulunduğunu nasıl anlayabiliriz?

Windows'da genel olarak bellek konusu sadece fiziksel bellek (RAM) ile sınırlı değildir. Ana kartın bellek yuvalarına takılan RAM ünitelerinden bağımız olarak, çalışan her süreç için geniş bir sanal adres alanı sunulur. 32-bitlik sistemlerde bu 2 GB, yeni 64-bitlik sistemlerde ise bu çok daha fazladır (128 GB gibi). Bu sanal bellek elbette. Her çalışan program 128 GB bellek kullanabilir demek değil.

İşletim sisteminde ise belli bir sınıra kadar çalışan süreçlere bellek tahsisi yapılabilir. Bu sınır da makinedeki RAM ile takas dosyası boyutunun toplamı kadardır. Bu değere kaydetme sınırı (commit limit) denir.

Diyelim ki Word'ü açtık ve uzunca bir belge hazırladık. İçine de bir sürü resim ekledik, tablolar falan... Derken sayfalarca uzunluğunda bir belge oluştu. Bunu yaparken uzun bir süre harcadık. Nihayetinde Word yazdığımız tüm içeriği kaybetmememk için işletim sisteminden sürekli bellek talebinde bulundu, bunları hafızada tuttu. Bunu yaparken de arka planda diyelim ki müzik dinliyorduk, Firefox'ta bir sürü sekme açıktı, ayrıca bir sürü başka program da açıp kapattık, bellek ihtiyacı sadece Word ile sınırlı kalmadı. Bu sürede bilgisayar Word için ayrılan bellek miktarının bir kısmını boşaltarak diğer uygulamalara verir. Ancak Word'ün verilerini de kaybetmemek için onları takas dosyasına yazar. Bu işi yaparken de en eski oluşturulmuş, en uzun süre önce üzerinde işlem yapışmış bellek alanlarını seçer. Word tekrar bu verilere ihtiyaç duyduğu anda ise bu bellek alanı takas dosyasından okunarak tekrar belleğe alnır; muhtemelen başka programların uzun süredir kullanılmayan verilerini yine takas dosyasına kaydederek.

Burada şu ayrımı yapmak gerek; Word ile çalışırken verilerin bir kısmı bellekte tutuluyordu, diğer bir kısmı da takas dosyasında tutuluyordu. Başka programlar için de aynı şey geçerli. Firefox yeni açtığım sekmeye ait verileri bellekte tutarken, ilk açtığım sekmedeki verileri takas dosyasına atmıştı. Bu süreçlerden her biri sanal bellek alanında 2 GB'a kadar (32 bitlik bir sistem olduğunu farzedersek) adresleme yapıyor olabilir, ancak her süreç için bellekte ayrılabilecek o kadar alan olmayabilir. Bu durumda bu 2 GB'lık sanal bellek alanındaki verilerin bir kısmı bellekte değil, takas dosyasında tutuluyor olabilir.

Ayrıca Word bazı sistem özellikerini kullanabilmek için (pencereyi çizebilmek, yapılandırma diyaloglarını görüntüleyebilmek, yazıcıdan çıktı alabilmek vs) bazı sistem dll dosyalarını yükleyecek ve kullanacaktır. Bu veriler diğer süreçlerle paylaşılan bir bellek alanı oluşturur.

Bu noktada bazı bellek terimlerini isimlendirelim:

Çalışma kümesi (working set) : Süreç tarafından işletim sisteminden talep edilen ve henüz bellekte tutulan (takas dosyasına gönderilmemiş) alan ile paylaşılan (dll dosyaları gibi) veriler. Bu alanda hem sürece özel üretilen veriler hem de paylaşılan kodlar depolanır.

Ayırma boyutu (commit size) : Bu ise programa tahsis edilen tüm sanal bellek miktarını gösterir. Bu veriler paylaşılmış veriler değil, diğer süreçler tarafından erişilemeyen, bu süreç tarafından üretilen özel verilerdir. Çalışma kümesinden farklı olarak bu rakama dahil olan bellek alanlarının tümünün RAM'de tutulduğunun garantisi yoktur. Eski verilerin bir kısmı takas dosyasına gönderilmiş olabilir. Bu alanda paylaşılan kodlar depolanmaz.


Yukarıdaki ekran görüntüsünde de notepad.exe sürecinin kullandığı bellek alanını inceleyelim. Bu resimde bellek ile ilgili iki sütun görüntüleniyor; Çalışma Kümesi ve Ayırma Boyutu. Notepad.exe için Çalışma Kümesi sütununda gösterilen 12.744 KB veri doğrudan RAM üzerinde tutulan not defteri verisi. Ancak buna paylaşılmış bellek (dll gibi) de dahil. Ayırma Boyutu sütununda gösterilen rakam ise not defteri tarafından ihtiyaç duyulan tüm veri miktarını gösterir. Bunun bir kısmı takas dosyasında olabilir, ancak bu rakama paylaşılan bellek miktarı dahil değildir.

Bu alanlara ek olarak Windows 7 ve sonrası sürümlerde gelen "Özel Çalışma Kümesi" alanı var. Bu alana paylaşılan bellek miktarı dahil değil. RAM'de saklanan sürecin özel verilerini gösteriyor. Bu alanı görebilmek için menüden Görünüm>Sütun Seç ile Bellek-Özel Çalışma Kümesi'ne ait kutuya işaret koymamız gerek.


Görüldüğü gibi not defteri için (seçili satır) özel çalışma kümesi de 7.948 KB. Çalışma Kümesi alanından bu veriyi çıkartarak 4.797 KB'lık veri paylaşılan bellek miktarı oluyor. Not defterin ayrılan toplamda 8.216 KB'lık verinin ne kadarı takas dosyasına atılmış olabilir? 8.216'dan 7.948'i çıkararak bulabileceğimiz 268 KB da "muhtemelen" takas dosyasına atılan miktar olabilir. Muhtemelen diyorum, çünkü süreçlere ait uzun süredir kullanılmayan alanlar hemen takas dosyasına gönderilmez. Bir süre daha belleğin bekleme alanında bekletilir, tekrar ihtiyaç duyulma ihtimaline karşı. Bir süre sonraki durak elbette takas dosyası olacaktır.

Bellekteki bu işlemler "sayfa" denen 4 KB'lık bölümler üzerinden yapılır. Tüm bellek 4 KB'lık sayfalara bölünmüştür. Süreç, işletim sisteminden her yeni bellek talep ettiğinde bu sayfaların katı miktarda alan tahsis edilir. Bellekten takas dosyasına veya tam tersi yöndeki taşıma işlemlerinin tümü bu 4 KB'lık sayfa boyutu üzerinden yapılır. Bellekte en uzun süredir kullanılmayan alanlar yine bu sayfa boyutları üzerinden belirlenir. Yani 1 byte'lık bir alan bile talep edilse 4 KB'lık bir sayfa ayrılır. Bu sebeple yukarıdaki bellek verilerinin tümü 4'e bölünebilen sayılardır.

Bir sürecin erişmek istediği veri doğrudan çalışma kümesi içindeyse o verilere doğrudan erişir, veriler veya kodlar farketmez. Ancak veriler ayırma boyutu alanına taşınmışsa onlara doğrudan erişemeyecek, erişim bir sayfa hatasına (page fault) sebep olacaktır. Söz konusu sayfa henüz bekleme alanındaysa (standby memory) bu bir yazılımsal sayfa hatası (soft page fault), aksi takdirde veri takas dosyasına gönderildiyse bir donanımsal sayfa hatasına (hard page fault) sebep olur. Görüldüğü gibi sayfa hatalarının aslında bir hatayla ilgisi yok, tamamen normal bir işleyiş.

Örneğin Word ile hazırladığımız belgenin yazıcıdan çıktısını almak istiyoruz. Menüden yazdır komutunu verdikten sonra sistem yazıcı ile ilgili sistem dosyalarına ihtiyaç duyacaktır. Bu sistem dosyaları bilgisayar açıldığından beri hiç kullanılmadıysa (veya kullanıldıysa ama üzerinden yeteri kadar uzun bir süre geçtiyse ve artık hafızada değillerse) bir donanımsal sayfa hatası oluşur. Veriler diskten okunur, işlevlerin kullanılabilmesi için gereken yordamlar belleğe alınır. Bu miktar çalışma kümesi alanına eklenir. Aradan bir süre geçtikten sonra bu sistem dosyaları için ayrılan alan önce bekleme alanına gider. Tam bu anda tekrar çıktı almak istersek bu sistem dosyalarına yapılan referans için bir yazılımsal sayfa hatası oluşur, diske hiç ihtiyaç duyulmadan işlem tamamlanır. Ama yeteri kadar uzun süre geçtikten sonra tekrar çıktı almak istersek bu bir donanımsal sayfa hatası oluşur. Veriler tekrar diskten okunur. Ama bu veriler paylaşılan sistem dosyalarına ait olduğu için bu veriler hiçbir zaman takas dosyasına yazılmaz, doğrudan diskten tekrar okunur.


Windows sanal bellek miktarı üzerindek çalışan bir işletim sistemi olduğundan, her bir sürece yapılan sanal bellek atamalarının (ayırma boyutu / committed bytes) toplamı ile çekirdek (kernel) işlemleri için yapılan bellek ayırmaların sayfalanmış (paged) miktarının toplamı sistem toplam kaydetme miktarı (commit charge) ile ifade edilir. Eğer bu miktar sistem ayırma sınırına (system commit limit, yukarıda açıkladığım gibi sistem RAM'i ile takas dosyasının boytunun toplamı) ulaşırsa bellek problemi uyarıları ile karşılaşırız. Takas dosyası otomatik olarak (eğer öyle ayarlandıysa) büyütülmeye çalışılır. Çok nadir de olsa bu gibi durumlarla karşılaşıldığında hangi sürecin bu durumda aşırı bellek kullandığını incelemek gerekebilir.

Çok uzun oldu. Evet, anlaşılması da kolay olmadı, Türkçe terimleri de işin içine katınca. Üzgünüm.