29.11.2020

Linux'ta beklenmeyen kapanmalar

İşletim sisteminden bağımsız olarak tüm bilgisayar sistemlerindeki tüm kapanmaların düzgün (graceful) kapanma olması gerekir. Yarım kalan bir yazma işlemi, kapanmamış dosyalar vs bir sonraki açılışta en basitinden birkaç hata ve disk denetlemesinden, geri getirilemez veri kayıpları ve sistemin tekrar kurulmasına kadar sorunları getirebilir.

Beklenmeyen kapanmalar neler olabilir? Bir sistem bileşeni yüzünden sistemin tekrar başlaması (veya sadece kapanması), güç kaybı sebebiyle sistemin kapanması.

last komutuyla sistemdeki açılış ve kapanış olaylarının listesini alabiliriz. Şu kaynakta belirtildiği gibi

$ last -Fxn2 shutdown reboot

-F : Uzun tarih formatı kullan
-x : Kapanma ve çalışma seviyesi değişikliklerini de göster
-n2: En son 2 olayı listele

komudu normal şartlar altında bir kapanışı takip eden bir açılış listelemeli. Eğer normal bir kapanma yoksa iki açılış olayı ile karşı karşıya kalabiliriz. Aşağıdaki çıktıya bakarsak

reboot   system boot  5.9.10-200.fc33. Sun Nov 29 17:09:18 2020   still running
reboot   system boot  5.9.10-200.fc33. Sun Nov 29 16:10:37 2020   still running

16:10'daki açılış da hala "still running" olarak gözüküyor, 17:09'daki açılış da. Bu arada bir beklenmeyen bir kapanış olmuş. Normal bir kapanış ve açılış sonrasında şu gözükür:

reboot   system boot  5.9.10-200.fc33. Sun Nov 29 16:10:37 2020   still running
shutdown system down  5.9.10-200.fc33. Sun Nov 29 01:58:33 2020 - Sun Nov 29 16:10:37 2020  (14:12)

Aynı kaynakta alternatif olarak ausearch aracının kullanılmasından da bahsedilmiş. Örneğin

$ sudo ausearch -i -m system_boot,system_shutdown | tail -4

benim normal olarak kapanmayan sistemimde şu sonuçları verdi:

Option ENRICHED not found - line 9
NOTE - using built-in logs: /var/log/audit/audit.log
----
type=SYSTEM_BOOT msg=audit(29-11-2020 13:10:59.324:106) : pid=778 uid=root auid=unset ses=unset subj=system_u:system_r:init_t:s0 msg=' comm=systemd-update-utmp exe=/usr/lib/systemd/systemd-update-utmp hostname=? addr=? terminal=? res=success'
----
type=SYSTEM_BOOT msg=audit(29-11-2020 14:09:31.491:105) : pid=793 uid=root auid=unset ses=unset subj=system_u:system_r:init_t:s0 msg=' comm=systemd-update-utmp exe=/usr/lib/systemd/systemd-update-utmp hostname=? addr=? terminal=? res=success'

Normal bir kapanış sonrası ise şuna benzer bir kapanış ve sonrasında bir açılış içeren bir çıktı üretmesi gerekirdi:

---
type=SYSTEM_SHUTDOWN msg=audit(29-11-2020 01:58:33.647:1688) : pid=19324 uid=root auid=unset ses=unset subj=system_u:system_r:init_t:s0 msg=' comm=systemd-update-utmp exe=/usr/lib/systemd/systemd-update-utmp hostname=? addr=? terminal=? res=success'
----
type=SYSTEM_BOOT msg=audit(29-11-2020 13:10:59.324:106) : pid=778 uid=root auid=unset ses=unset subj=system_u:system_r:init_t:s0 msg=' comm=systemd-update-utmp exe=/usr/lib/systemd/systemd-update-utmp hostname=? addr=? terminal=? res=success'

Bu iki durumda da 2 değil 1 satır veri görünüyorsa loglarda bir kalıcılık yoktur, ya da yeterli süre açık kalan bir sistemin son açılış sonrasındaki kayıtları silinmiş olabilir.

Daha ilginç bir çözüm olarak bizim sistemimize özel bir hizmet birimi oluşturmamız önerilmiş. Sadece kapanışta çalılştırılacak /etc/systemd/system/set_gracefulshutdown.service dosyasının içeriği olarak şunlar önerilmiş:

Unit]
Description=Set flag for graceful shutdown 
DefaultDependencies=no 
RefuseManualStart=true 
Before=shutdown.target
 
[Service] 
Type=oneshot 
ExecStart=/bin/touch /root/graceful_shutdown
 
[Install]
WantedBy=shutdown.target

Daha sonra

$ sudo systemctl daemon-reload
$ sudo systemctl enable set_gracefulshutdown

ile bunlar etkinleştirilmiş. Bu hizmet birimi kapanışta /root/graceful_shutdown dosyası oluşturacak. Ayrıca bir de açılışlarda çalışacak /etc/systemd/system/check_graceful.service hizmet birimi önerilmiş:

[Unit]
Description=Check if previous system shutdown was graceful ConditionPathExists=/root/graceful_shutdown 
RefuseManualStart=true 
RefuseManualStop=true
 
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/bin/rm /root/graceful_shutdown
 
[Install]
WantedBy=multi-user.target
 
Bu hizmet birimi de açılışta çalışacak ama /root/graceful_shutdown dosyasının varlığı önkoşulu ile. Eğer o dosya yoksa çalışmayacağı için anlayabiliriz ki bir önceki kapanma beklenen bir kapanma değildi. Ayrıca dosya sonraki adımda bu dosyayı sileceği için kapanışta bir dosyanın tekrar oluşturulmasına izin veriyor.

Tereddüt ettiğimizde
 
$ systemctl is-active check_graceful

komutu ile önceki kapanmanın normal olup olmadığını anlayuabiliriz.

En son olarak bir de journalctl ile durum kontorlü önerilmiş.

$ sudo journalctl -b -1 -n

Benim sistemimde bol hatalı bir çıktı üretti, beklenmeyen kapanmanın göstergesi olarak.

26.10.2020

Medya tuşlarıyla videoları kontrol etmemizi sağlayan tarayıcı: Firefox!

Ardı ardına birbirinden güzel özellikler ile karşımıza çıkan açık kaynak kodlu internet tarayıcımız, canımız ciğerimiz: Firefox!

En yeni özelliği yine çok hoşuma gitti. Klavyelerimizde ve kulaklıklarımızda yer alan medya kontrol tuşları ile artık Youtube videolarımızı ve tarayıcımızda oynatılan diğer medyaları kontrol edebiliyoruz.

Yazılanlara göre Windows 7'yi desteklemiyor. Linux'ta gtk tabanlı masaüstlerinde destekleniyor denmiş, ama 3.36.7 gnome-shell'e sahip Fedora 32'de de çalışmadı. Olsun, yakında çalışır.

Olur da bu özelliği kapatmak istersek adres satırına about:config yazdıktan sonra 

media.hardwaremediakeys.enabled = false

yapmamız gerek. Ayrıca bir de timeout özelliğinden bahsedilmiş:

media.mediacontrol.stopcontrol.timer

Bunu etkinleştirdikten ve varsayılan olarak 60 saniyelik bir süre geliyor (onu da media.mediacontrol.stopcontrol.timer.ms ile değiştirebiliyoruz). Firefox'ta çalan medyayı durdurduktan 60 saniye sonra medya kontrol dışına çıkacak.

---

[1] https://docs.google.com/document/d/1c4FivJpvAjjw9Uw-jn7X1UjGOoWkANXOulNyqDWs83w/edit#heading=h.wsp2v2xk20e

13.10.2020

Linux'ta standart akışları yönlendirme

Bir komut satırı uygulaması için 3 temel akış (stream) söz konusu:

0: Giriş için stdin, 
1: çıkış için stdout,
2: hata çıktıları için stderr.

Bir uygulamanın konsolda çalıştığı düşünülerek, bazı giriş ve çıkışlarının olduğu varsayılır. stdin olarak isimlendirilen giriş, klavyedir. Program çıktısını stdout'a yani ekrana basar. Olası hata durumlarında ekrana bazı hata mesajları da basılır ama genellikle hata mesajlarının normal stdout çıktısınıdan ayrı olması istendiği için onun akışı ayrıdır, stderr olarak adlandırılır.

stdin yönlendirmesi

Tüm girişin klavyeden değil de, bir programın çıktısından ya da bir dosyadan olması gereken durumlarda kullanılır.

$ head < dosya.txt

Yönlendirme operatörü olarak "<"  kullanıldı.

stdout yönlendirmesi

Genelde bir komutun planlanan tüm çıktılarını başka bir komuta veya dosyaya yönlendirmek için kullanılır.

$ ls -ld */  | wc -l # tüm klasörleri say

$ last -s 2019-05-01 | awk '{print $1}' #tarihten sonra yeniden başlatan kullanıcıları isimleri

$ find . -iname "*.txt" -newermt "5 months ago" -ls > new_txt_files.log # son 5 ayda değiştirilen dosyaların listesini new_txt_files.log'a yaz

Burada > operatörünün yanında boru "|" operatörünün de kullanıldığına dikkat.

stderr yönlendirmesi

3 klasörün içeriklerini bir dosyaya yazdığımızı düşünelim. Ama üçüncü klasör var olmayan bir yolu gösteriyor.

$ ls Belgeler Resimler Filmler > dosya_listesi.txt

Bu komut Belgeler ve Resimler klasörünün çıktısını belirtilen dosya_listesi.txt dosyasına yazarken, Filmler klasorunun var olmadığına dair hatayı sadece ekrana yazar ve dosya_listesi.txt dosyasına bir mesaj yazmaz. Bunun sebebi, hata çıktısının farklı bir kanaldan gönderilmesidir. İki seçeneğimiz var. Ya stderr akışını hata.txt dosyası gibi bir dosyaya yazabilir, ya da hataları da dosya_listesi.txt dosyasına atabiliriz. İlk durum için komudumuz şöyle olabilir:

$ ls Belgeler Resimler Filmler 2> hata.txt 1> dosya_listesi.txt

İkinci durum için komudumuz şöyle olabilirdi:

$ ls Belgeler Resimler Filmler > dosya_listesi.txt 2>&1

Burada sonda yer alan 2 numaralı stderr akışını &1'e yönlendirme bölümünün stdout'un dosya_listesi.txt'ye yönlendirmesi (> dosya_listesi.tx) bölümünden sonra olması önemli. Eğer sıra değişirse sadede stdout dosyaya yazılır (çünkü stderr > stdout yönlendirmesi sırasında stdout dosyaya yönlendirilmemiş olur)

Alternatif olarak bash'e özel &> kısaltması (2>&1 ile aynı anlama gelir) kullanılabilir:

$  ls Belgeler Resimler Filmler &> dosya_listesi.txt

---

[1] https://linuxize.com/post/bash-redirect-stderr-stdout/

[2] https://linuxhandbook.com/redirection-linux/

[3] https://www.guru99.com/linux-redirection.html

[4] https://www.putorius.net/linux-io-file-descriptors-and-redirection.html

[5] https://linuxconfig.org/bash-scripting-tutorial-for-beginners

13.08.2020

Linux, static route ve netplan

Ubuntu 18.04 ve sonrası artık route tablosuna giriş eklemek için netplan kullanıyor.

Bir örnek üzerinden gidelim. Yerel ağımızdaki IP aralığı 192.168.1.0/24 olsun. Bir de uzak ofisimiz var, onun da IP aralığı 192.168.2.0/24. Uzak ofisteki kullanıcıların merkeze ulaşması için kurulan router'ın IP adresi de 192.168.2.101 olsun.

Bu durumda iletişimin sağlanabilmesi için, örneğin, uzak ofisteki bir ubuntu makinenin üzerinde

$ sudo ip route add 192.168.1.0/24 via 192.168.2.101 dev ens32

gibi bir yönlendirme girişi yapmak gerek. Ancak bu kalıcı olmayacak. Bir sonraki yeniden başlatmada da geçerli olmasını sağlayabilmek için /etc/netplan altındaki dosyayı düzenlememiz gerekecek. Bu klasörde ismi standart olmayan bir dosya vardır, kast edilen dosya bu. Elle IP adresi ataması yapılmış bir bilgisayar için bu dosyanın içeriği şu şekilde olabilir:

network:
    ethernets:
        ens32:
            addresses:
            - 192.168.2.7/24
            dhcp4: false
            gateway4: 192.168.2.1
            nameservers:
                addresses:
                - 192.168.2.2

Buraya, gördüğüm kadarıyla gateway4'ün hemen altına, şu satırları girmek gerek:

- to: 192.168.1.0/24
  via: 192.168.2.101
Yani tam içerik şöyle olacak:

network:
    ethernets:
        ens32:
            addresses:
            - 192.168.2.7/24
            dhcp4: false
            gateway4: 192.168.2.1
             - to: 192.168.1.0/24
               via: 192.168.2.101
            nameservers:
                addresses:
                - 192.168.2.2

Bu şekilde işlem tamam.

---

2020-12-28 ek: Netplan yaml dosyasındaki hatalardan dolayı yapılandırma uygulanmazsa bunun kaydını görmek için

$ journalctl -b -g netplan # NETPLAN (büyük harflerle) de olabilir

kullanılabilir. Ayrıca yaml dosyasındaki hataları görebilmek için netplan komutu ile birlikte aşağıdaki parametreler kullanılabilir:

# netplan try # yaml dosyasındaki ayarları uygula, hata varsa mevcut duruma geri dön

# netplan apply # yaml dosyasındaki ayarları uygula

# netplan ip leases ens33 # arayüz üzerindeki DHCP atamalarını görüntüle

Bunların haricinde üzerinde çalıştığımız sistem IP adresini bir DHCP sunucudan almışsa bu sunucuyu bulmak için

$ journalctl -b -g DHCP # anahtar kelime konusunda yaratıcı olmak gerekebilir

Veya çoğu dağıtğımda /var/lib/dhclient/dhclient.leases gibi bir dosyanın içeriğini inceleyebiliriz:

$ cat /var/lib/dhclient/dhclient.leases

Bunlar işimizi görmezse UDP 68 üzerinden gerçekleşen ağdaki DHCP trafiğine göz atmak istersek:

# tcpdump -i eth0 -nev udp port 68

ve hatta ağdaki DHCP sunucuyu bulabilmek için bir dhcp-discover paketi göndermek için

# nmap --script broadcast-dhcp-discover -e eth0

DHCP'nin mevcut atamasını serbest bırakıp yeniden istekte bulunmak için

# dhclient -r

Şu anda sistemin kullandığı DNS sunucuyu görmek için

# resolvectl dns

Gerekli durumda ağ hizmetlerini tekrar başlatmak için

$ sudo systemctl restart network-manager

---

https://netplan.io/examples/

29.07.2020

Reklamlar, reklam engelleyiciler ve paranın etiğe etkisi

İlk başta internet reklamları vardı. Sonra reklam engelleyiciler geldi. Bir tarafta ürünlerini satmak için reklam bütçesi ayıran firmalar, diğer yanda da internette reklamlar aracılığıyla ücretsiz sunulan hizmetleri kullanan ama reklam görmek istemeyen kullanıcılar. Evet, ortada bir dengesizlik var. Ama dengesizliğin ilk çıktığı yerin reklam aracı kuruluşları olduğunu düşünüyorum.

Yeni okuduğum bir habere göre reklamlarının hedef kitlelere ulaşmadığını gören büyük reklam verici firmalar çözümü Adblock'a gizli gizli para yedirmekte bulmuşlar. "Kabul edilebilir reklamlar" adı altında "bazı" reklamlar artık kullanıcılar adına "beyazlisteye" alınmaya başlanmış. Amerikalı senatör Ron Wyden da bu beyazlisteyi inceleme konusunu gündeme getirmiş. Perdeler arkasında neler oluyor...

28.07.2020

Windows'da stderr akışını yönlendirme

Konsolda çalışan uygulamalar için 3 temel akış vardır:
  1. Standart Giriş (stdin)
  2. Standart Çıkış (stdoout)
  3. Standart Hata (stderr)
Bir program standart bilgilendirmesini stdout'a yapar. Microsoft'un örneği üzerinden gidelim. Eğer olmayan bir dosyayı dir ile listelemek ve çıktısını bir dosyaya yazmak istersek:

C:\> dir abc.def > dosya.txt
File Not Found

hala "File Not Found" hatasını ekranda görürüz. Üstelik bu çıktı dosya.txt'ye de yazılmaz. Çünkü dosyaya yazılan kısım stdout'a gönderilen, "File Not Found" ise stderr'a gönderilen bilgidir.

Bu durumda "File Not Found" mesajını hata.txt dosyasına, geri kalan tüm stdout'ları da dosya.txt dosyasına göndermeyi seçebiliriz:

C:\> dir abc.def 2>hata.txt > dosya.txt

Ya da hataları görmek istemiyorsak stderr'u nul'a yönlendirebiliriz. Dikkat, Windows'da nul tek "l" ile yazılır.

C:\> dir abc.def 2>nul > dosya.txt

Bunlar Linux'ta, Windows komut satırında (cmd.exe) ve Powershell'de de geçerli.

Linux ve Powershell'de geçerli olup da Windows komut satırında geçerli olmayan stderr'un stdout'a yönlendirilmesi. Bunu Linux ve Powershell'de şu şekilde yapabiliriz:

C:\> dir abc.def 2>&1

ya da linux'ta

 $ ls abc.def 2>&1

Bunun sonucunda olmayan bir dosyayı listeleme girişimimizde oluşturulan tüm çıktı stdout'a gitmiş olur. Bunu da toplu olarak bir dosyaya yazabiliriz:

C:\> dir abc.def 2>&1 > dosya.txt

Ama bu iş Windows komut satırında olmadı.

Tüm bunlar nerden aklıma geldi; ffprob'u kullanırken üretilen çıktıların tümü stderr'a gönderiliyor; garip bir şekilde. Bunları bir dosyaya yazdıramadım. Ama stderr yönlendirmesi başarılı oldu.

[1]'e göre bir de console çıktımız varmış.
[2]'ye göre powershell'de daha da fazlası varmış.
---
[1] https://www.robvanderwoude.com/battech_redirection.php
[2] https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_redirection?view=powershell-7

Komut satırından toplu resim kırpma

Elimde aynı yerinden kırpılması gereken çok sayıda resim var. Kırpılan resimleri de başka bir klasöre kaydetmem gerek. Bunu komut satırından nasıl yapabilirim diye düşünürken aklıma ffmpeg geldi. Resim kırpma için şu sayfada bulduğum bilgileri poweshell ile birleştirerek aşağıdaki satırı yazdım. Resimlerin asılları D:\kaynak klasöründe resim.xxx.png ismiyle bulunuyor (xxx: 3 haneli ardışıl sayılar). Kırpılan resimleri D:\kirpilmis klasörüne kaydedeceğim.

PS> dir D:\kaynak\resim*.png |
% {ffmpeg -i $_ `
-vf "crop=200:200:200:0" `
(Join-Path -Path "D:\kirpilmis" -ChildPath `
(Split-Path $_ -Leaf))}

Burada crop parametresi ile verilen sayılar kırpma işleminin yerini ve boyutlarını tarif ediyor:
crop=genişlik:yükseklik:x:y
x ve y, kırpmanın x ve y koordinatı olarak başlangıç noktası.

Blog sayfasında güzel gözüksün diye satırı backtick (`) karakteri kullanarak böldüm, tek satır yapmak için bu karakterleri çıkarmak gerek. İlk satırda kullanmadım, çünkü dikey çizgi (|) karakteri kullanılabildiği durumlarda satır bölücü olarak iş görüyor.

ffmpeg, uzantıya göre formatı otomatik seçtiği için sadece dosya uzantısını değiştirerek jpg veya başka bir formatta da kayıt yapılabilir.

21.07.2020

vSphere client is no longer authenticated hatası

Bir süredir Chrome ve Firefox üzerinde yaşadığımız şu hata çok can sıkıcı olmaya başlamıştı.


Çözüm olarak Firefox'un "Private Windows" gibi gezinme bırakmayan güvenli kipleri ile açıyordum ama alışkanlıkları ve düzeni (!) olan biri için bu bile çok zor.

Neyse, bir süre önce bu konu ile ilgili arama yapmıştım ama doğru sonuçlara ulaşamamışım anlaşılan. Şimdi baktığımda daha güzel sonuçlar buldum. Örneğin şu sayfa. Çözüm olabilecek 3 olasılıktan bahsedilmiş:

1. Çok olası olmamakla birlikte ESX sunucu üzerinde /etc/vmware/vsphere-client/webclient.properties içindeki

session.timeout=120

değerini tekrar ayarlamaktan bahsedilmiş. Bu adımı doğrudan atladım, çünkü buraya bir müdahalem olmadı.

2. Daha da zayıf bir ihtimalle yerel ağda SSO hizmetinin çalışmasını sağlayan isim çözümleme sisteminin farklı bir DNS sunucu kullanımı ile bozulması olasılığından bahsedilmiş. Bunu da atladım.

3. Tarayıcıda cookie'lerin bozulmuş olması durumu. Hemen Firefox > Options'a (Firefox > Seçenekler) girdim. Oradan Privacy & Security (Gizlilik & Güvenlik) alt alanına geldim. Burada Cookies and Site Data (Çerezler ve Site Verisi) başlığı altındaki "Manage Data" (Verileri Yönet) düğmesine basarak tarayıcımdaki tüm çerezleri görüntüledim.


Bu çok karışık olduğu için vCenter Appliance sunucumun ismini yazarak listeyi sınırladım.


Gösterilen tüm çerezler benim hedefimdekiler olduğu için aşağıdaki "Remove All Shown" düğmesine tıklayarak tüm çerezleri sildim.

Bundan sonra herşey eskisi gibi oldu. Bu eskiye merak ne menem birşeyse...

18.07.2020

Firefox Containers

Arama motorlarının genel arama alışkanlıklarımız hakkında gereğinden çok fazla bilgiye sahip olmasına, alışveriş sitelerde incelediğimiz şeylerin daha sonra başka yerlerdeki Google reklamları ile de karşımıza gelmesine, kişisel verilerimizin sanal dünyanın zimmetli malı haline gelmesine karşıyım. Bu sebeple alışveriş sitesinde aradıklarımın orda kalmasını, arama motorlarında aradıklarımın anında unutulmasını ve her girdiğim sitenin arka planda benim ile ilgili yüzlerce veri tutmasını istemiyorum.

Bu konular hakkında söylenecek çok şey var ama uzatmadan konuya girmek istiyorum. Firefox'un yeni bir özelliği var: Containers. Türkçe sürümünde kapsayıcı sekme olarak geçiyor. Ama ben bu yazıda Containers'ı kullanacağım.

Amaç şu: her siteye girdiğimizde çerezler kullanıyoruz. İşleyiş açısından çerezlerin kaçınılmaz olduğu durumlar var. Ama kesinlikle kaçınılmaz olduğu durumlar da var. Containers işte bu amaçla tarayıcı sekmelerini gruplayarak iki grubun birbirlerinin çerezlerine erişimlerini engelleyen bir yöntem. Bu özelliği kullanmak için bir eklenti yüklemek gerekiyor. Eklenti de Mozilla Vakfı'nın bir ürünü: Multi-Account Containers.

Yükledikten sonra örneğin sosyal medya siteleri için bir container yaratıp tüm sosyal medya sitelerini bu container içinde açarsanız diğer sitelerin sosyal medya sitelerinde açtığınız oturumlardan hiç haberi olmuyor. Veya alışveriş siteleri için bir container yaratıp tüm alışverişlerinizi bu siteler içinde yaparsanız diğer sitelerde bu alışveriş sitelerinde yaptığınız gezintiden hiç bilgisi olmuyor.

Firefox'u seviyorum. Bu tür gizlilik ilkelerine önem verip kullanıcıların verilerini koruyup rahatça gezinmelerini sağlayacak adımlar atıyor. Ama pazar payı gittikçe azalıyor. Bu durumda rakiplerinin karşısında bir gün "artık devam edemiyoruz" diyecekler diye de korkuyorum.

26.06.2020

Windows'a çevrimiçi duvar kağıtları

Şu yazımda Bing'in günlük resimlerinin Fedora'da nasıl duvar kağıdı olarak kullanılabileceğini yazmıştım. Bu aslında internetten bulduğum bir içerikti.

Buradan esinlenerek bu işi Windows'da nasıl yapabilirim diye düşündüm. Powershell'de aynısını yapmaya karar verdim.

Önce gereken değişkenleri tanımlayalım:
$bing="www.bing.com"
$xmlURL="http://www.bing.com/HPImageArchive.aspx?format=xml&idx=0&n=1&mkt=en-US"
$saveDir="D:\wallpapers\"
$picExt=".jpg"
$desiredPicRes="_1440x900"
$fullstop = $false 
$saveDir ile belirtilen klasörün var olduğundan emin olmalıyız. Fedora için yaptığımız gibi var olsun olmasın yaratılması için
New-Item -ItemType Directory -Path $saveDir -ErrorAction SilentlyContinue | Out-Null
Ya da powershell'e özgü Test-Path ile kontrol edip daha sonra yaratmaya gidebiliriz.
if (-Not Test-Path $saveDir)
{
    New-Item -ItemType Directory _path $saveDir
}
gibi.

Bing'in günlük duvar kağıdı bilgilerini paylaştığı bir xml çevrimiçi verisi var, $xmlURL değişkeni ile verilen adreste. Bu verinin içinde <urlbase> tag'inin içeriğini kullanarak istediğimiz çözünürlükte (varsa) resmi edinebiliriz. Her durumda bu olmayabiliyor. İstdediğimiz çözünürlükte resim yoksa varsayılanı kullanmayı deneyebiliriz.
[xml]$response = (New-Object System.Net.WebClient).DownloadString($xmlURL)

$defaultPicURL = $response.images.image.url
$desiredPicURL = $response.images.image.urlbase + $desiredPicRes + $picExt
<urlbase> tagından elde edilen dosya isimleri şu formatta oluyor:

/th?id=OHR.MontageJupiterIo_EN-US2310290045

Ben bunları şu formatta kaydetmek istiyorum:

MontageJupiterIo_EN-US2310290045_1440x900.jpg

Bunun için de aşağıdaki kırpma işlemlerine tabi tutuyorum:
 
$checkfile = $defaultPicURL.split("&")[0]
$checkfile = $checkfile.split(".")[1] + "." + $checkfile.split(".")[2]
 
Fedora için bu adımları orijinal olarak öneren kişi resimleri günlük olarak tutuyor, yenisini indirince siliyordu. Ben silmemeyi tercih ettim. Ama bu da bir resmin ikinciye indirilme girişimini kontrol etmemi gerektirdi. Bunun için yukarıdaki checkfile değişkeni içinde saklanan dosya adını biraz daha kırpıp dosya uzantısını yok ettim:

$checkfile = $checkfile.substring(0,$checkfile.length-4)

Bu aşamadan sonra bir if bloğunun içinde istenen çözünürlükte dosya var mı diye kontrol ediyorum.
 
if ((dir (Join-Path -Path $saveDir -ChildPath ($checkfile + "*"))).Count -eq 0)
 
Gerçekten bu kadar ayrıntılı bir if koşuluna gerek yoktu aslında, ama benim bu resimleri indirdiğim klasördeki isim karmaşası bunu gerektirdi. Neyse, yukarıdaki if koşulunun doğru olduğu durum için aşağıdaki gibi uzun bir kod var. Burada önce istenen çözünürlük var mı, onu kontrol ediyorum, iwr (Invoke-WebRequest) ile. Sadece dosyanın var olup olmadığını öğrenmek için HTTP HEAD yöntemini kullanması için de -Method parametresi ile head değerini gönderiyorum, ilk try bloğunun içinde. Yoksa iwr'in bir error throw etmesi için de -EA stop kullandım. Catch'in içinde de istenen çöznürlüğün yerine varsayılan çözünürlüğün kullanılmasını sağladım. İç içe iki try-catch ile varsayılan çözünürlükteki resmin de olup olmadığını kontrol ettim. finally bloğunun içinde de bulunan (istenen çözünürlük veya varsayılan) resmin download edilmesini, duvarkağıdı olarak ayarlanmasını sağlayan fonksiyonu çağırdım. Birkaç log tutma satırı ile birlikte.

try {
      $resp = iwr -Uri ($bing + $desiredPicURL) -EA Stop -Method Head

      # desired URL OK
      Write-Host "desired res OK."
      $picName = $desiredPicURL.split(".")[1] + "." + $desiredPicURL.split(".")[2]
      $fullPath = Join-Path -Path $saveDir -ChildPath $picName
  }
  catch {
      # desired not available
      try {
          $resp = iwr -Uri ($bing + $defaultPicURL) -EA Stop -Method Head
          Write-Host "desired not found, falling back to default."
          $picName = $defaultPicURL.split("&")[0]
          $picName = $picName.split(".")[1] + "." + $picName.split(".")[2]
          $fullPath = Join-Path -Path $saveDir -ChildPath $picName
      }
      catch {
          # neither default available
          Write-Host "None available right now."
          $fullstop = $true
          Break
      }

  }
  finally {
      if ($fullstop) {
          # here means nothing found
          Add-Content -Path $logfile -Value "$bugun - nothing found."
      }
      else {
          # hear means something is found, either desired or default
          try {
              $resp = iwr -Uri ($bing + $defaultPicURL) -OutFile $fullPath
              Add-Content -Path $logfile -Value "$bugun - downloaded : $fullpath"
              Set-WallPaper $fullpath
          }
          catch {
              $hata = $PSItem.Exception.ToString()
              Write-Host "last stage error: $hata"
              Add-Content -Path $logfile -Value "$bugun - last stage error."
          }
      }
  }
 
Bir adım önceki if'e ait else bloğunda da eğer dosya zaten varsa bir daha indirilmemesini ve işlem kaydı düşülmesini sağladım.

else {
    Write-Host "File is already downloaded:" (dir (Join-Path -Path $saveDir -ChildPath ($checkfile + "*")))[0]
    Add-Content -Path $logfile -Value "$bugun - file is already downloaded."
}

Hayatını kodlama ile kazananlar; yukarıdaki karmaşa için kusura bakmayın.

Sonrasında bunu Görev Zamanlayıcısıyla otomatik çalıştırmaya ayarlamak kalıyor. Bunun için Set-ExecutionPolicy ile çalıştırma politikasını uygun şekilde değiştirmek, ps1 dosyasını imzalamak ya da komut satırından powershell.exe ile birlikte -ExecutionPolicy anahtarını kullanmak gerekebilir.

28.06.2020 Düzenleme: Registry'deki anahtarı değiştirip daha sonra rundll32.exe'yi kullanarak UpdatePerUserSystemParameters çağrısı yeni sistemlerde pek işe yaramıyor. Bunun yerine şurada SystemParametersInfo API'sinin kullanılması önerilmiş. Bunu powershell'de nasıl yapabiliriz diye düşünürken önce Matt Graeber'in blog'unda yazdıklarına denk geldim. Çok faydalı olarak PInvoke.com sitesini önermiş. Ama burdan sonra yapılacak bir dünya iş vardı ve ben bu notasyona aşina değildim. Daha fazla aramayla Jose Espitia'nın bloguna denk geldim. Bu işte tam aradığım şeydi. SystemParametersInfo'nun Powershell'den çağrılabilir hale getirilmişi. Bunu kullanarak tam sonuca ulaştım.

Function Set-WallPaper($Image) {
<#
.SYNOPSIS
Applies a specified wallpaper to the current user's desktop
   
.PARAMETER Image
Provide the exact path to the image
.EXAMPLE
Set-WallPaper -Image "C:\Wallpaper\Default.jpg"
#>
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
public class Params
{
    [DllImport("User32.dll",CharSet=CharSet.Unicode)]
    public static extern int SystemParametersInfo (Int32 uAction,
                                                   Int32 uParam,
                                                   String lpvParam,
                                                   Int32 fuWinIni);
}
'@
$SPI_SETDESKWALLPAPER = 0x0014
$UpdateIniFile = 0x01
$SendChangeEvent = 0x02
$fWinIni = $UpdateIniFile -bor $SendChangeEvent
$ret = [Params]::SystemParametersInfo($SPI_SETDESKWALLPAPER, 0, $Image, $fWinIni)
}

Linux'ta diskte yer açmak

Bir süredir hakkında kısa kısa bilgiler biriktirdiğim konuları hızlıca blog'a koymaya başladım. Sanırım anlatımlar biraz eksik kaldı. Umarım yakın zamanda tekrar üzerinden geçerim. Bu dil ile ilgili daha fazla beklentileri olanlardan özür niteliğinde olsun.

Son zamanlarda kullandığım dağıtımlar Fedora ve Arch/Manjaro'dan ibaret. Bu sebeple bu başlığın hedefleri bu dağıtımlar.

Bir süre kullanılan linux kurulumları gerek paket güncellemeleri gerekse loglar sebebiyle çok yer kaplamaya başlayabilir. Öncelikle paket ön belleğini konrol edebiliriz.

Fedora
Fedora'da paket önbelleği /var/cache/dnf klasörü altında tutulur. Kaç paket için önbellek olduğunu göremek için
$ ls /var/cache/dnf | wc -l
ya da toplamda bu klasör ne kadar yer kaplıyor diye bakabilmek için
$ du -sh /var/cache/dnf
kullanılabilir. Bu klasörün en kapsamlı temizliği için
$ sudo dnf clean all
komutunu kullanabiliriz. Ama /var/cache/dnf klasörünün tüm içeriği cache verisi olmayabilir.
 
Gereksiz bağımlılıklardan kurtulmak için
$ sudo dnf autoremove
Arch/Manjaro
Arch türevlerinde ise paket önbelleği /var/cache/pacman/pkg altında tutulur. Kaç dosya var diye bakmak için
$ ls /var/cache/pacman/pkg | wc -l
ya da burası diskte ne kadar yer kaplıyor diye bakmak için
$ du -sh /var/cache/pacman/pkg
Arch veya türevlerinde paket önbelleğini temizlemenin birkaç farklı yolu var. Kaldırılmış paketleri temizlemek için
$ sudo pacman -Sc
ya da kurulu olanları bile kaldırmak için
$ sudo pacman -Scc
veya daha ayrıntılı olarak sadece son 3 sürümü hariç eski sürümleri silmek için
$ sudo paccache -r
ve hatta sadece 1 sürüm bırakmak için
$ sudo paccache -ruk0
kullanılabilir. "Yetim" olarak adlandırılan gereksiz bağımlılıkları görmek için
$ pacman -Qtdq
ve bu gereksiz bağımlılıklardan kurtulmak için
$ sudo pacman -Rns $(pacman -Qtdq)
kullanılabilir.

Kullanıcı önbelleği
Kullanıcı hesabınıza özel önbellek alanının boyutunu kontrol etmek için
$ du -sh ~/.cache/
temizlemek için
$ rm -rf ~/.cache/
kullanılabilir, dağıtımdan bağımsız olarak.

journal loglarını temizlemek
Bu işlem de dağıtım bağımsız olarak yapılabilir. Mevcut boyutu kontrol etmek için
$ journalctl --disk-usage
komutu kullanılabilir. Sonrasında örneğin en yeni 50 MB'lık veriyi bırakıp eskileri silmek için
$ journalctl --vacuum-size=50MB
ya da son 4 hafta hariç tüm kayıtları silmek için
$ journalctl --vacuum-time=4weeks
kullanılabilir.
 
Fedora'da kurulu programlardan en çok yer kaplayanları bulmak için:

$ rpm -qa --queryformat '%{name} %{size}\n' | sort -n -k 2 -r | head -n 20

Bunların hepsi geçici yöntemlerdir. Bunları uyguluyorsak artık diski büyütme zamanı gelmiştir. Bunlar sadece biraz daha zaman kazandırabilir.

Fedora'ya VirtualBox kurmak

Virtualbox'ı Fedora'ya kurmanın birkaç yolu var. Ama gördüğüm kadarıyla doğru yolu şu:

Öncelikle root olalım:

$ sudo -i

Sonra
cd /etc/yum.repos.d/
klasörünün altına gidelim. Buraya
http://download.virtualbox.org/virtualbox/rpm/fedora/virtualbox.repo
altından virtualbox deposunu indirelim.
wget http://download.virtualbox.org/virtualbox/rpm/fedora/virtualbox.repo
Ardından bir dnf update yapalım:
# dnf update
Şimdi de şu bağımlılıkları kuralım:
# dnf install binutils gcc make patch libgomp glibc-headers glibc-devel kernel-headers kernel-devel dkms qt5-qtx11extras libxkbcommon
Nihayet Virtualbox-6.1 paketini kurabiliriz. Dikkat! VirtualBox paketi değil, sonunda sürüm numarası yazan.
# dnf install VirtualBox-6.1
Bu aşamadan sonra vboxusers grubu yaratılmış olur. VirtualBox'ı kullanacak kullanıcımız bu grubun üyesi olmalı.
# usermod -aG vboxusers metin
Ayrıca ilgili çekirdek modülleri de derlenmiş olmalı. İlerde tekrar derleme (bir çekirdek sürümü güncellemsi sonrasında) gerektiği durumlarda şu script çalıştırılabilir:
# /usr/lib/virtualbox/vboxdrv.sh setup
Daha fazla ayrıntı için [1]'e bakılabilir.

---
[1] https://www.if-not-true-then-false.com/2010/install-virtualbox-with-yum-on-fedora-centos-red-hat-rhel/

Opera'da oynatılamayan videolar

Her ne kadar sonuna kadar Firefox'u desteklesem de Opera'nın bazı avantajları yok değil. Ama maalesef videoları oynatması için gereken codecler eksik geliyor. En azından linux altında.

Şu bilgileri buldum:
- Opera ile birlikte gelen /usr/lib64/opera klasörü altında libffmpeg.so modülü kısıtlı bir sürüm. Bunun tam sürümü çeşitli yazılımlarla birlikte geliyor. Anladığım kadarıyla debian ve türevleri için (hatta belki ArchLinux ve türevleri için de) kullanılabilecek chromium-codecpack paketi bunun tam sürümünü içeriyor. Ama Fedora'da böyle bir paket yok maalesef.
- Visual Studio Code kuruluysa bunun altında
/usr/share/code/libffmpeg.so
da iş yapar.
- Ama bu yoksa mecburen libffmpeg.so'nun tam sürümünü bir yerlerden edinmek gerek. Bu amaçla yine Reddit'te bir uzman demiş ki; https://github.com/iteufel/nwjs-ffmpeg-prebuilt/releases sayfasından ilgili binary'leri indirerek bir yere kaydedin. Sonra da bunu /usr/share/code/libffmpeg.so üzerine kopyalayın.
Yalnız şöyle bir durum var; bu her güncelleme sonrası tekrarlanmalı. Yoksa Opera, her yeni sürümle yine eski kısıtlı sürüm dosyasını getirerek bizim tam sürümün üzerine yazacak. Daha iyisini bulamadım :/

25.06.2020

Fedora'ya çevrimiçi duvar kağıtları

Manjaro'da kullandığım günlük otomatik internetten duvar kağıdı indirme özelliğinin benzerini Fedora'da uygulamak istedim. Youtube'da denk geldiğim şu video üzerinde çalışmaya başladım. Videonun yorumlarında bağlantısı verilen zip dosyasını indirerek işe başladım. Süreç otomatik değil; yönergeleri en azından Fedora 32'de uygulayınca olmadı, ama ufak değişikliklerle çalıştırmayı başardım.

İşin özü bir shell scripti tarafından gerçekleştiriliyor. Adım adım anlatmaya çalışacağım.

Öncelikle bing adresini bir değişkene atalım:
bing="www.bing.com"
Arkasından Bing'de günlük duvar kağıdını almak için kullanılacak adres bir değişkende toplanmış:
xmlURL="http://www.bing.com/HPImageArchive.aspx?format=xml&idx=0&n=1&mkt=en-US"
Bing'in günlük duvar kağıdının kaydedileceği yeri /Resimler klasörümün altındaki bingwallpapers olarak belirledim ve bunu da bir değişkene atalım:
saveDir=$HOME'/Resimler/bingwallpapers/'
Bu klasör -yoksa bile- yaratmak için aşağıdaki komudu çalıştıralım:
mkdir -p $saveDir
Geçerli seçeneklerin arasında

none
wallpaper
centered
scaled
stretched
zoom
spanned

olan resim seçenekleri için varsayılan olarak zoom seçilmiş:
picOpts="zoom"
Kullanmak istediğimiz resim uzantısını (farklı seçenekleri denemedim) seçelim:
picExt=".jpg"
Ekranımıza göre resim çözünürlüğünü belirliyoruz:
desiredPicRes="_1920x1080"
Burada string'in ilk karakterinin bir alt-tire olduğuna dikkat. Resim çözünürlüğü olarak örneğin "_1366x768" de kullanabilirdik.

Her resmin her çözünürlükte kopyası bulunmuyor sanırım. Bu sebeple eğer istediğimiz çözünürlük yoksa varsayılan çözünürlüğü kullanacağız.

Şimdi yukarıda xmlURL olarak verilen URL'deki içeriğin ilk birkaç satırını inceleyelim:
<images>
<image>
<startdate>20200625</startdate>
<fullstartdate>202006250000</fullstartdate>
<enddate>20200626</enddate>
<url>
/th?id=OHR.GorchFock_EN-US6157323134_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp
</url>

<urlBase>/th?id=OHR.GorchFock_EN-US6157323134</urlBase>
<copyright>
German navy tall ship Gorch Fock in waters off Reykjavík, Iceland (© DEEPOL by plainpicture/Henn Photography)
</copyright>
Burada dikkat edilecek bölümleri kalın olarak yazmaya çalıştım:

url tag'ının içindeki kısım varsayılan çözünürlükteki resmin kısmi yolu (başına bing eklenecek). Bu amaçla aşağıdaki değişkeni yaratıyoruz:
defaultPicURL=$bing$(echo $(curl -s $xmlURL) | grep -oP "<url>(.*)</url>" | 
cut -d ">" -f 2 | cut -d "<" -f 1)
urlBase tag'ının içindeki kısım ise bizim istediğimiz çözünürlükteki resmi elde etmek için kullanacağımız kısmi yol. Bu amaçla da aşağıdaki değişkeni yaratıyoruz:
desiredPicURL=$bing$(echo $(curl -s $xmlURL) | grep -oP "<urlBase>(.*)</urlBase>" | 
cut -d ">" -f 2 | cut -d "<" -f 1)$desiredPicRes$picExt
Sonra istediğimiz çözünürlükte resim URL'i geçerli mi diye bir if koşulu içinde gerekli denetimi gerçekleştirip geçerli ise bu adresi, geçerli değilse varsayılanı indirmeyi gerçekleştiriyoruz (çok fazla hata denetimi yok).
if wget --quiet --spider "$desiredPicURL"
then
    picName=${desiredPicURL##*OHR.}
    curl -s -o $saveDir$picName $desiredPicURL
else
    picName=${defaultPicURL##*OHR.}
    picName=${picName%%&*}
    curl -s -o $saveDir$picName $defaultPicURL
fi
Burada indirdiğimi resmin adını da picName değişkeninde depoladık. Şimdi bu indirdiğimiz resmi gsettings aracını kullanarak duvar kağıdı olarak değiştirelim:
gsettings set org.gnome.desktop.background picture-uri "$saveDir$picName"
Sonra da resmin duvar kağıdı olarak nasıl ölçeklendirileceğini seçelim:
gsettings set org.gnome.desktop.background picture-options $picOpts
Şimdi bir tek bu script'i oturum açışta çalıştırmak kaldı. Bunu yapmak için de Youtube videosındaki Laberinto kullanıcısı ev klasörünün altındaki .config klasörünün altında autostart alt klasörü oluşturup, içine daha önce indirdiğimiz zi dosyasının içinden çıkan  bingwallpapers.desktop dosyasını yapıştırmış. Bu iki dosya için de çalıştırma yetkileri vermeyi unutmayalım.

Bu şekilde bing.com'un günlük resimlerini duvarkağıdı olarak kullanabiliriz :)

22.06.2020

Robocopy

Çoğu durumlarda grafik arayüzün dosya kopyalama yetenekleri ile yetiniyoruz. Bunun dezavantajlarından biri olabilecekler hakkında önceden karar verilemiyor olması. Oluşan sıra dışı durumlar veya hatalar (dosya üzerine yazma, hedefteki dosyanın kaynaktakinden yeni olması vs) ile ilgili oluştuğu anda soru sorar. Bu da tüm süreç boyunca klavyenin başında oturulmasını gerektirir. Düz komut satırı aracı copy ise daha az şeyler sunar.

Bunun alternatifi, yine bir Windows aracı olan Robocopy olabilir.

C:\Klasor1 klasörü kaynak, D:\Klasor2 de hedef konumumuz olsun.

Düz kopyalama
C:\robocopy C:\Klasor1 D:\Klasor2
Bu yöntem ile boş klasörler kopyalanmaz.

Boş klasörleri de hedefte yarat
C:\robocopy C:\Klasor1 D:\Klasor2 /E
Taşı
C:\robocopy C:\Klasor1 D:\Klasor2 /E /MOVE
Bu şekilde C:\Klasor1 de silinir, tüm içerik D:\Klasor2 içine taşınmış olur.

Taşı ama klasör yapısını silme
C:\robocopy C:\Klasor1 D:\Klasor2 /E /MOV
Sadece MOVE anahtarının son harfini silerek kaynak konumun klasör yapısını bozmadan taşıma işleminin yapılmasını sağlar. Bu şekilde kaynaktaki klasör yapısının var olmasını bekleyen başka programların çalışması olumsuz etkilenmez.

Aynalama
C:\robocopy C:\Klasor1 D:\Klasor2 /E /MIR 
Kaynak klasörün tüm dosya yapısının aynısı hedefte oluşturulur. Eğer tüm dosyalar mevcutsa ve robocopy işlemi tekrarlanıyorsa kaynaktaki yeni oluşturulan dosyalar hedefe ilave edilir, veya kaynakta silinmiş dosyalar hedeften de silinir.

Hariç Tutma
Bir klasörü hariç tutarak taşımayı tamamlamak için /XD anahtarı kullanılır.
C:\robocopy C:\Klasor1 D:\Klasor2 /E /XD "C:\Klasor1\temp"
Burada klasör ismi yukarıdaki gibi tam yol ile verilebileceği gibi wildcard'lar ile de verilebilir:
C:\robocopy C:\Klasor1 D:\Klasor2 /E /XD "*temp*"
Benzer şekilde dosya hariç tutma için /XF anahtarı kullanılır.
C:\robocopy C:\Klasor1 D:\Klasor2 /E /XD "C:\Klasor1\bilgi.txt"
Burada da dosya adı tam yol veya wildcard'larla belirtilebilir.

    C:\robocopy C:\Klasor1 D:\Klasor2 /E /XD "*.txt"
---
[1] https://www.youtube.com/watch?v=gTzTeHmKMKw

Farklı dağıtımlardaki grub komutları

Grub komutları her dağıtımda farklılık gösterebiliyor. Örneğin Ubuntu'da

$ sudo update-grub
komutu ile grub menüsü güncellenebiliyor. Ama bakınca aslında grub-mkconfig'i kullanan basit bir script'ten başka birşey değil. İçeriği kabaca şöyle:

grub-mkconfig -o /boot/grub/grub.cfg

Hatta update-grub2 de, update-grub'a bir kısayol.

Grub diskin başına yazmak için kullanılan komutsa Ubuntu'da şöyle:

$ sudo grub-install /dev/sda
Fedora'da ise update-grub ya da update-grub2 gibi bir şey söz konusu değil. Grub menüsünü yeniden oluşturmak için kullanılacak komut şöyle:

$ sudo grub2-mkconfig -o /boot/efi/EFI/grub.cfg
Benzer şekilde grub'ı diskin başına yazmak için ise

$ sudo grub2-install /dev/sda
kullanılıyor.

Fedora'da grub menüsünü düzenlemek için kullanılan grubby adında diğer dağıtımlarda bulamadığım bir araç da var.

Yine Fedora'da rescue çekirdeği ve initramfs'i tutuluyor. Bunları silmeniz durumunda tekrar yaratmak için dracut kullanılıyor. Var olanların üzerine yazmak için --force parametresi kullanılabilir.

Arch / Manjaro'da da Ubuntu'ya benzer şekilde update-grub var ki o da arka planda grub-mkconfig'i kullanan bir script. Ama burada update-grub2 gibi bir kısayol söz konusu değil.

$ sudo update-grub
Grub'ı diskin başına yazmak içinse yine

$ sudo grub-install /dev/sda
kullanılıyor. Tüm grub-install'ları BIOS sistemler için yazdım. UEFI sistemlerde ise kullanılacak komut şöyle:

$ grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=manjaro --recheck

Systemd zamanlayıcıları (timers)

Uzun yıllardır linux dünyasındaki cron görevlerinin yerini systemd ile birlikte zamanlayıcılar almaya başlıyor. Yeni bir zamanlayıcı yaratmaya çalışacağım.

Örnek olarak her pazar gecesi çalışması gereken bir "eski dosyaları silme" görevimiz olsun. Bu iş için eski_dosyalari_sil.sh dosyasının içeriği şöyle olabilir:

#!/bin/bash
find /user/metin/ -mtime -180 -exec rm -rf {} -

Bu dosyayı örneğin profilimizin altına kaydedip, çalıştırma yetkisi vermeyi unutmamak gerek:

$ chmod +x /home/metin/eski_dosyalari_sil.sh

Yapılması gereken 2 adımlı işimizin ilk adımı bir service birimi oluşturmak.

/usr/lib/systemd/system/temizlik.service

gibi bir yol ile kaydedeceğimiz dosyanın içeriği şöyle olabilir:

[Unit]
Description=Eski Dosyalari Silme

[Service]
Type=simple
ExecStart=/home/metin

[Install]

WantedBy=multi-user.target

İkinci adımda da bir zamanlayıcı (timer) birimi oluştırmalıyız. Bunun için de

/usr/lib/systemd/system/backup.timer

yolu ile şöyle bir dosya oluşturabiliriz:

[Unit]
Description=Execute backup every night

[Timer]
OnCalendar=*-*-* 00:00:00
Unit=temizlik.service

[Install]
WantedBy=multi-user.target

Bu adımdan sonra yapılacak tek şey zamanlayıcı birimini systemctl ile etkinleştirip başlatmak:

$ sudo systemctl enable temizlik.timer
$ sudo systemctl start temizlik.timer

temizlik.timer birim dosyası içinde OnCalendar satırında ne zaman çalışacağı belirtiliyor. Yukarıdaki örnekte yazılan

Calendar=*-*-* 00:00:00

UTC'ye göre 00:00:00 her gün demek. cron görevlerindeki zamanlama gibi buradaki sıra da yıl *-*-* için yıl-ay-gün şeklinde. Bundan sonraki 00:00:00 günün saati anlamında. Bunun yerine

Calendar=daily

de kullanılabilirdi.
Daha fazla örnek için [3] veya [4]'e bakılabilir. Persistent=true gibi bir komutla sistem açıldığında kaçırlmış görevlerin de çalıştırılması sağlanabilir.

service veya timer dosyalarında bir değişiklik yaptıktan sonra etkili olabilmesi için hizmetleri tekrar çalıştırma veya aşağıdaki gibi tekrar yüklemeliyiz:

# systemctl daemon-reload

Mevcut sistemdeki tüm aktif zamanlayıcıları görmek için

$ systemctl list-timers

kullanılabilir. Pasif olanları da görmek için --all anahtarı eklenebilir.

---

9.06.2020

journalctl ile loglara erişmek

systemd ile gelen başka bir araç da journalctl komutu. Varsayılan olarak çıkışını less komutu ile sayfalandırıyor (tüm less kısayolları geçerli). Sayfalama yapmamaması için --no-pager kullanılabilir, ama bu ciddi miktarda çıktı üreteceğinden sadece --no-pager ile kullanmak mantıklı/pratik değil. Hiçir parametre kullanmadan çalıştırınca varsayılan olarak en eski kayıtlar yukarıda, aşağıya gittikçe daha yenileri gösterecek şekilde listeleme yapar.

$ journalctl
-- Logs begin at Mon 2018-05-21 18:00:03 +03, end at Tue 2020-06-09 17:38:48 +03. --
May 21 20:59:27 localhost.localdomain kernel: Linux version 4.16.3-301.fc28.x86_64 (mockbuild@bkerne>
May 21 20:59:27 localhost.localdomain kernel: Command line: BOOT_IMAGE=/vmlinuz-4.16.3-301.fc28.x86_

Varsayılan olarak tarih kısmında yıl gösterilmez. Tarih bilgisini göstermek için --output=short-iso parametresi kullanılabilir.

$ journalctl -b --output=short-iso
2020-04-09T10:23:01+0000 localhost.localdomain solr[860]: Started Solr server on port 8983 (pid=999). Happy searching!
2020-04-09T10:23:01+0000 localhost.localdomain su[866]: pam_unix(su-l:session): session closed for user solr


Sırayı tersine çevirmek (en yeni kayıtlar yukarıda, aşağıya doğru daha eski kayıtları gösterecek şekilde) göstermesi için -r (reverse) kullanılabilir. Bu durumda yine sayfalama yapacaktır.

Eğer kayıtlar silinmemişse işletim sisteminin kurulduğu ilk günden bugüne kadar kayıtları gösterecektir. Bunun yerine herhangi bir tarihten sonrası, ya da herhangi bir açılıştan sonrası gösterilebilir. Öncelikle sistemdeki açılışları bilmek için tüm açılışları --list-boots parmetresiyle görebiliriz.

$ journalctl --list-boots
-63 b98547c039284c9dbd71c029316c09e4 Mon 2018-05-21 20:59:27 +03—Mon 2018-05-21 18:17:11 +03
-62 160231536b4148cfb98ed0b37a301813 Wed 2018-07-04 16:07:22 +03—Wed 2018-07-04 16:46:48 +03
-61 0e8d3a7031924ed3a4a8b47fdd30107e Wed 2018-08-15 16:07:10 +03—Wed 2018-08-15 16:27:05 +03
-60 ccf2109a7ec54f2a949eb156a95adb79 Tue 2018-09-25 14:27:04 +03—Wed 2018-09-26 08:13:28 +03
-59 37577ce61f3a44ac96c32ee35824263e Mon 2018-10-15 09:40:47 +03—Mon 2018-10-15 13:17:31 +03
-58 d9805c69dc0d4a72a185e256a284a299 Mon 2018-10-22 09:25:03 +03—Mon 2018-10-22 12:08:36 +03

Burada listelenecek açılışlar last reboot komutuyla eşleşir. Yukarıdaki satır (en küçün negatif ID) en eski açılış olup şu anki açılış 0 ID'si ile en altta listelenir. ID'si ile herhangi bir açılışın kayıtlarına erişmek için örneğin -b -63 şeklinde en eski açılışa ait loglar listelenebilir. Mevcut açılış için -b 0 ya da sadece -b kullanılabilir.

Kayıtların içinde anahtar kelimesi araması yapmak için bu komutun çıktısı grep'e aktarılabileceği gibi -g parametresi ile bu iş arka planda da yapılabilir (büyük küçük harf duyarlı olmadan, aynen grep ile -i kullanılmış gibi).

$ journalctl -b -g usb

Sadece bir birimin (unit) ya da hizmetin kayıtlarını görmek için -u ile birlikte birim adı yazılabilir.

$ journalctl -b -u lightdm

Unit isimleri için

$ systemctl list-units

kullanılabilir.

Sadece çekirdek (kernel) kayıtları için -k anahtarı kullanılır.

$ journalctl -b -k
Haz 09 16:59:19 localhost.localdomain kernel: Linux version 5.3.16-300.fc31.x86_64 (mockbuild>
Haz 09 16:59:19 localhost.localdomain kernel: Command line: BOOT_IMAGE=(hd0,msdos1)/vmlinuz-5>
Haz 09 16:59:19 localhost.localdomain kernel: Disabled fast string operations

Çıkış formatını değiştirmek için -o ile birlikte short, verbose, json, json-pretty ve cat kullanılabilir.

$ journalctl -b -u lightdm -o cat
Starting Light Display Manager...
Started Light Display Manager.
pam_unix(lightdm-greeter:session): session opened for user lightdm by (uid=0)
gkr-pam: unable to locate daemon control file

Tüm journalctl logları /var/log/journal konumunda depolanır. journald hizmetinin ayarları da /etc/systemd/journald.conf dosyasında tutulur. Örneğin logları dosya boyutu kısıtlaması olmaksızın tutmak için başındaki # sembolü kaldırılarak Storage=persistent yapılabilir. Bundan sonra systemd-journald unit'i tekrar başlatılmalıdır.

$ sudo systemd restart systemd-journald

Mevcut boyutlar hakkında bilgi için

$ journalctl -b -u systemd-journald

ve

$ journalctl --disk-usage

kullanılabileceği gibi

$ du /var/log/journal -h

de kullanılabilir. Çok yer kaplayan logları silerek yer kazanmak istersek

$ journalctl --vacuum-size=2G

ya da

$ journalctl --vacuum-time=1years

ve hatta

$ journalctl --vacuum-files=10

kullanılabilir. Ayrıca conf dosyasındaki şu ayarlar da işe yarayabilir:

Storage: persistent ise geriye dönük kayıtlar hatırlanır. Auto olursa
SystemMaxUse : kayıtlar için kullanılabilecek azami disk alanı
SystemKeepFree : kayıtlar yazılırken bırakılması gereken asgari boş disk alanı
SystemMaxFileSize : Yeni dosyaya geçmeden her kayıt dosyasının en fazla ne kadar büyüyebileceği (persistent modu)
RuntimeMaxUse: Persistent olmayan mod volatile (uçucu, geçici) mod olarak isimlendiriliyor. Bu modda en fazla ne kadar disk alanı kullanılabileceği (/run/log/journal içinde)
RuntimeKeepFree : Uçucu modda asgari boş bırakılması gereken disk alanı boyutu (/run/log/journal içinde).
RuntimeMaxFileSize : Uçucu modda bir kayıt dosyasının yeni bir dosyaya geçmeden ne kadar büyüyebileceği (/run/log/journal içinde)

Varsayılan olarak sıkıştırma kullanılır denmiş, 512 byte'tan büyük girişler için [3]. Değiştirmek için Compress=1k gibi bir değerin girilebileceğinden bahsedilmiş.

journal kayıtlarının hata seviyeleri (log levels) öncelikler (priority) olarak bilinir. Şu öncelikler vardır:
  1. "emerg" (0)
  2. "alert" (1)
  3. "crit" (2)
  4. "err" (3)
  5. "warning" (4)
  6. "notice" (5)
  7. "info" (6)
  8. "debug" (7)
Sadece hata mesajlarını görmek için
$ journalctl -b -p 3
veya anahtar kelime kullanarak
$ journalctl -b -p err
kullanılabilir. Ayrıca acil alamr (alert), kritik (crit) ve hata (err) mesajlarını görmek istiyorsak aralık da belirtebiliriz:
$ journalctl -b -p 1..3
Bir zaman aralığında oluşan kayıtlarla ilgileniyorsak --since ve --until parametereleri aşağıdaki gibi kullanılabilir.

$ journalctl --since "2015-06-01 15:00" --until "2015-06-31 23:59"

Varsayılan olarak zaman bilgileri yerel sistem saati olarak kabul edilir. Ayrıca aşağıdaki gibi kelimeler de kullanılabilir:

$ journalctl --since yesterday
$ journalctl --since 09:00 --until "1 hour ago"

Bir kullanıcı tarafından çalıştırılan süreçlere ait hata kayıtları için kullanıcı id'si kullanılarak sorgu yapılabilir. Öncelikle ilgili kullanıcı hesabının id'sini elde etmek gerek. Örneğin rtkit hesabı için
$ id rtkit
ile uid bilgisi öğrenilir, daha sonra aşağıda kullanılır:
$ journalctl _UID=133
En son 10 kaydı göstermek için

$ journalctl -n 10

Hizmetlerden birini başlatırken oluşan hata mesajlarında kayıtlara
 
$ journalctl -xe
 
ile bakmamız önerilir. Burada -x anahtarı açıklamaları eklemesini, -e ise doğrudan en sona gitmesini söyler.

Canlı olarak oluşan loglara bağlanmak için de -f anahtarı kullanılabilir.

$ journalctl -f

---

22.04.2020

uBlock Origin yeni yetkiler istiyor

Firefox'taki favori eklentim uBlock Origin. Sadece reklamlardan kurtulmak için değil, popup'ları engelemek hatta takipçilerden kurtulmak için de mükemmel.

Son zamanlarda Firefox üzerinde yeni izinler istiyordu. İnceleme fırsatım olmadığı için bir süre erteledim bu izni verme işini. Ama karantina zamanlarında vakit bulabildim.

Öncelikle yeni farkettim, https://ublock.org/ diye bir çakma site var. İlk başta bunu resmi eklenti sitesi sandım. Ama bu adrese girmeye çalıştığımda uBlock bunu engelleyince ziller çalmaya başladı.


Girmeyelim, girenleri engelleyelim.

Projenin resmi sayfası github üzerinde https://github.com/gorhill/uBlock  adresinde. Wiki sayfası ise https://github.com/gorhill/uBlock/wiki adresinde.

Bu konuyu açıklığa kavuşturduktan sonra gelelim izne. Firefox'un üç çizgili menüsünün üzerinde sarı ünlem işareti çıkıyor. Tıklayınca da aşağıdaki gibi bir mesaj.


Yeni izinler vermeyi tıklayınca da aşağıdaki gibi:


Konu uBO wiki sayfasında açıklanmış ama çok daha basit bir açıklamayı r/uBlockOrigin subreddit'inde bulabildim. Nihai olarak şöyle diyor:

kotusite.com gibi bir engellenmiş siteniz bulunuyor. Sizin hergün girdiğiniz ornek.com sitesi de kotusite.com'un takipçi kodlarını kullanmak istiyor. Ama doğrudan kullansa sizin karalistenizde olduğundan yükleyemeyecek. Bunun için ks.ornek.com gibi bir alan adı yaratıyor, bunu da kotusite.com adresine yönlendiriyor. Bu şekilde kotusite.com'un bütün istenmeyen kodları çalışmaya başlıyor.

Bu iki alan adının aslında aynı IP adresine işaret ettiğini bilmemiz durumunda engellemeyi yapabileceğimiz gerçeğinden yola çıkarak uBO bizden bu isim-IP çözümlemesini yapma yetkisi istiyor.

Bilişim camiası bunda bir sakınca görmemiş. Yapabiliriz.

1.03.2020

Kodi Youtube eklentisi hatası

Raspberry PI Kodi üzerinde kurulu Youtube eklentisi bir süredir hata veriyordu. Anlam veremediğim hata ile ilgili internette yaptığım aramada Youtbe eklentisinin geliştiricisinin uygulama API anahtarları artık geçerli olmadığını öğrendim. OSMC formundaki bir başlıkta gördüğüm fzinken kullanıcısının çözüm önerisi başarılı sonuç verdi. Adımlar şöyle:

Google hesabınız ile https://console.developers.google.com/ adresine giriş yapın ve yeni proje yaratmayı seçin. Projeye bir isim verin.
Daha sonra API kütüphanesine giderek API ve hizmetleri etkinleştirin.
Youtube Data API v3'ü seçin
Etkinleştiri seçin
Yeni kimlik bilgisi oluşturmayı seçin
Kimlik bilgisi tercihlerini şöyle yapabilirsiniz:
Nihayetinde 1 API anahtarı ve 1 OAuth 2.0 istemci kimliği yaratmanız gerekecek. OAuth 2.0 istemci kimliğinin altında bir de istemci sırrını bulacaksınız. Bunları bir yere kopyalayın.

Kodi'de Youtube eklentisinin ayarlarına gelerek sol menüde altlarda yer alan API sekmesini seçin. Burada eğer henüz etkinleştirilmemişse Enable Personal API keys'i etkinleştirin. Ardından altında yer alan 3 alana şu verileri girin:

API Key: yukarıda belirttiğim API anahtarı
API ID: OAuth 2.0 istemci kimliği
API secret : OAuth 2.0 istemci sırrı

Bunları girdikten sonra youtube eklentisi çalışacak :)

Bu uzun karakterleri tek tek yazmak zor, eğer Rasberry PI kullanıyorsanız Kore veya Yatse kullanabilirsiniz, kopyalayıp uzaktan yapıştırmak için.