macOS Sistem Yönetimi: launchd Rehberi
macOS sistemlerinde süreç yönetimi ve servis otomasyonu için temel yapı taşı olan launchd, modern bir sistem yöneticisinin veya ileri düzey kullanıcının mutlaka hakim olması gereken bir araçtır.
Apple tarafından geliştirilen launchd, sistem servislerini (daemons) ve kullanıcı uygulamalarını (agents) yöneten açık kaynaklı bir çerçevedir. Geleneksel Linux sistemlerindeki init, cron, inetd ve watchdog gibi birçok farklı aracın işlevini tek başına üstlenir.
1. Temel Kavramlar: Daemons ve Agents
launchd dünyasında iki temel çalışma türü vardır:
Launch Daemons: Sistem genelinde çalışır. Kullanıcı oturum açsa da açmasa da arka planda aktiftirler. Genellikle
rootyetkileriyle çalışırlar.Launch Agents: Kullanıcı bazlıdır. Yalnızca ilgili kullanıcı oturum açtığında çalışmaya başlarlar. Kullanıcının grafik arayüzüne (GUI) erişim yetkileri vardır.
Dosya Konumları
launchd yapılandırma dosyaları .plist (XML tabanlı) formatındadır ve şu dizinlerde bulunur:
| Konum | Tür | Yetki / Kapsam |
~/Library/LaunchAgents | Launch Agent | Mevcut kullanıcının kendi servisleri. |
/Library/LaunchAgents | Launch Agent | Tüm kullanıcılar için geçerli kullanıcı servisleri. |
/Library/LaunchDaemons | Launch Daemon | Tüm sistem için geçerli sistem servisleri. |
/System/Library/... | Sistem | macOS'in kendi çekirdek servisleri (Müdahale edilmemelidir). |
2. Bir .plist Dosyasının Anatomisi
Bir servisin ne zaman ve nasıl çalışacağını belirlemek için bir XML dosyası oluşturulur. İşte temel bir örnek:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.kullanici.betikadi</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/python3</string>
<string>/Users/kullanici/scripts/backup.py</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>3600</integer>
</dict>
</plist>
Önemli Anahtarlar (Keys):
Label: Servisin benzersiz adıdır.
ProgramArguments: Çalıştırılacak komut ve parametreler listesidir. (Tam dosya yolu verilmelidir).
RunAtLoad: Dosya
launchd'ye yüklendiği anda çalışıp çalışmayacağını belirler.StartInterval: İşlemin kaç saniyede bir tekrarlanacağını belirler (Örn: 3600 = 1 saat).
StartCalendarInterval: Belirli bir saat veya günde çalıştırmak için kullanılır (Cron benzeri).
KeepAlive: Servis çökerse veya kapanırsa otomatik olarak yeniden başlatılmasını sağlar.
3. launchctl: Komut Satırı Yönetimi
launchd ile etkileşime geçmek için launchctl komutu kullanılır.
Servisi Yüklemek (Aktif Etmek):
Bash:launchctl load ~/Library/LaunchAgents/com.kullanici.betikadi.plistServisi Kaldırmak (Durdurmak):
Bash:launchctl unload ~/Library/LaunchAgents/com.kullanici.betikadi.plistServis Durumunu Kontrol Etmek:
Bash:launchctl list | grep com.kullanici.betikadi
Not: Modern macOS sürümlerinde (Big Sur ve sonrası)
bootstrapvebootoutkomutları önerilse de,load/unloadhala yaygın olarak çalışmaktadır.
4. İleri Düzey Özellikler
Dosya Değişikliğini İzleme (WatchPaths)
Belirli bir klasöre dosya eklendiğinde veya bir dosya değiştiğinde betiğinizin çalışmasını istiyorsanız bu anahtarı kullanabilirsiniz:
<key>WatchPaths</key>
<array>
<string>/Users/kullanici/Downloads/</string>
</array>
Standart Çıktı ve Hata Kaydı (Logging)
Hata ayıklama yapmak için çıktıları dosyalara yönlendirmek çok kritiktir:
<key>StandardOutPath</key>
<string>/tmp/my_script.log</string>
<key>StandardErrorPath</key>
<string>/tmp/my_script.err</string>
5. Özet ve Dikkat Edilmesi Gerekenler
Tam Yollar (Absolute Paths):
launchdortam değişkenlerini (PATH) her zaman okumayabilir. Bu yüzden/usr/bin/python3gibi tam yolları kullanın.Dosya İzinleri: Plist dosyasının izinlerinin doğru olduğundan emin olun (Genellikle
644).Hata Ayıklama: Servis çalışmıyorsa
/var/log/system.logdosyasını veyaConsole.appuygulamasını kontrol edin.
launchd, macOS üzerinde periyodik yedeklemelerden ağ servislerine kadar her türlü otomasyonu profesyonelce yönetmenizi sağlar.
Her gün saat 17:30'da masaüstündeki dosyaları "Yedek" isimli bir klasöre taşıyan gerçek bir otomasyon senaryosu hazırlayalım.
Bu uygulama, launchd mantığını kavramak için mükemmel bir pratik olacaktır.
Senaryo: Günlük Otomatik Yedekleme
Bu işlem iki aşamadan oluşur:
Betik (Script): İşi yapacak olan kod.
Launch Agent: Bu kodu belirli zamanda tetikleyecek olan yapılandırma dosyası.
Adım 1: Yedekleme Betiğini Hazırlama
Önce terminali aç ve basit bir Bash betiği oluştur:
nano ~/backup_script.sh
İçine şu kodları yapıştır:
#!/bin/bash
# Masaüstündeki tüm PDF'leri Yedek klasörüne taşır
mkdir -p ~/Documents/Yedek
mv ~/Desktop/*.pdf ~/Documents/Yedek/ 2>/dev/null
echo "Yedekleme yapıldı: $(date)" >> ~/backup_log.txt
Dosyayı kaydedip çık (Ctrl+O, Enter, Ctrl+X). Ardından çalıştırma izni ver:
chmod +x ~/backup_script.sh
Adım 2: .plist Dosyasını Oluşturma
Şimdi bu betiği her gün 17:30'da çalıştıracak olan launchd dosyasını hazırlayalım.
nano ~/Library/LaunchAgents/com.nuritiras.gunlukyedek.plist
İçine şu XML yapısını ekle:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.nuritiras.gunlukyedek</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/Users/kullaniciadi/backup_script.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>17</integer>
<key>Minute</key>
<integer>30</integer>
</dict>
<key>StandardOutPath</key>
<string>/tmp/gunlukyedek.log</string>
<key>StandardErrorPath</key>
<string>/tmp/gunlukyedek.err</string>
</dict>
</plist>
Önemli:
/Users/kullaniciadi/kısmını kendi macOS kullanıcı adınla değiştirmeyi unutma!
Adım 3: Servisi Aktifleştirme (Yükleme)
Oluşturduğumuz bu dosyayı sisteme tanıtmak için şu komutu çalıştır:
launchctl load ~/Library/LaunchAgents/com.nuritiras.gunlukyedek.plist
Artık her gün saat 17:30 olduğunda (bilgisayarın açıksa) bu görev otomatik olarak çalışacaktır.
Sık Karşılaşılan Sorunlar ve Çözümler
Tam Yol (Full Path): Launchd,
~/sembolünü her zaman tanımaz. Bu yüzden plist içinde/Users/adiniz/...şeklinde tam yol yazmak en güvenlisidir.İzinler: Eğer macOS "Disk Erişimi" uyarısı verirse,
System Settings > Privacy & Security > Full Disk Accesskısmına giderek Terminal'e veya ilgili betiğe izin vermen gerekebilir.Test Etme: Zamanı beklemeden servisi hemen çalıştırmak istersen:
launchctl start com.nuritiras.gunlukyedek
Özellikle sistem yöneticilerinin çok işine yarayan KeepAlive (Sürekli Çalıştırma) ve WatchPaths (Dosya İzleme) özelliklerini de ekleyerek blogun için tam profesyonel bir içerik haline getirelim.
macOS Otomasyonunun Kalbi: launchd ve Gelişmiş Özellikler
macOS ekosisteminde arka plan işlemlerini yönetmek, Linux'taki systemd veya cron yapısına aşina olanlar için başlangıçta farklı gelebilir. Ancak launchd, sunduğu gelişmiş kontrol mekanizmalarıyla çok daha esnek bir yapı sunar.
1. Servislerin Sürekliliği: KeepAlive
Bir servisin (örneğin bir Python sunucusu veya veri tabanı dinleyicisi) kapandığı anda otomatik olarak yeniden başlatılmasını istiyorsanız KeepAlive anahtarını kullanmalısınız.
Örnek Kullanım:
<key>KeepAlive</key>
<true/>
Bu komut, servis herhangi bir sebeple durursa launchd'nin onu hemen tekrar ayağa kaldırmasını sağlar. Eğer servisin sadece belirli bir hata koduyla (crash) kapandığında çalışmasını isterseniz, daha spesifik bir ayar da yapabilirsiniz:
<key>KeepAlive</key>
<dict>
<key>Crashed</key>
<true/>
</dict>
2. Olay Tabanlı Tetikleme: WatchPaths
Sadece zamana bağlı değil, sistemdeki bir değişikliğe bağlı işlem yapmak macOS otomasyonunun en güçlü yanlarından biridir. WatchPaths ile belirli bir klasöre yeni bir dosya geldiğinde betiğinizi tetikleyebilirsiniz.
Senaryo: "İndirilenler" klasörüne her yeni dosya geldiğinde bir düzenleme betiği çalışsın.
<key>WatchPaths</key>
<array>
<string>/Users/nuritiras/Downloads</string>
</array>
3. launchd vs. Cron: Hangisi Daha İyi?
Linux dünyasından gelenler için cron vazgeçilmezdir. Ancak macOS'te launchd kullanmanın kritik bir avantajı vardır: Uyku Modu.
Cron: Bilgisayar uyku modundaysa ve o an bir görev tanımlıysa, o görev atlanır ve bilgisayar uyandığında çalıştırılmaz.
launchd: Bilgisayar uykudayken kaçırılan bir görev varsa, bilgisayar uyandığı ilk fırsatta o görevi hemen çalıştırır. Bu, özellikle yedekleme işlemleri için hayati önem taşır.
4. Hata Ayıklama (Troubleshooting) İpuçları
Bir .plist dosyası hazırladınız ama çalışmıyor mu? Şu adımları izleyin:
Sözdizimi Kontrolü: Plist dosyasının XML yapısında hata olup olmadığını şu komutla kontrol edin:
plutil -lint ~/Library/LaunchAgents/dosya_adi.plistLogları İzleme: Terminal üzerinden canlı olarak sistem loglarına bakın:
log stream --predicate 'process == "launchd"'Çıkış Kodları:
launchctl listkomutunu kullandığınızda, servis isminin yanındaki sayı 0 değilse (örneğin 78), bu bir yapılandırma hatasına işaret eder.
Örnekleri uygularken dosya yollarının mutlak yol (absolute path) olduğundan emin olun. /usr/local/bin/python3 gibi tam yollar kullanmak, launchd'nin ortam değişkenlerinden bağımsız sorunsuz çalışmasını sağlar.
Python ve PyQt projelerini macOS tarafına taşıdığında, bu uygulamaların bilgisayar açılır açılmaz (veya kullanıcı oturum açtığında) otomatik olarak ve düzgün bir grafik arayüz desteğiyle başlaması için özel bir yapılandırma gerekir.
Özellikle GUI (Görsel Arayüz) uygulamalarında launchd kullanırken dikkat edilmesi gereken en kritik nokta, uygulamanın kullanıcının grafik oturumuna (Aqua session) erişebilmesidir.
İşte projelerin için kullanabileceğin macOS Python GUI Otomatik Başlatma Şablonu:
1. Proje Hazırlığı: Python Sanal Ortam (venv)
Pardus'taki projelerinde olduğu gibi macOS'te de venv kullanmak en sağlıklı yöntemdir. Proje klasörünün /Users/nuritiras/Proje olduğunu varsayalım.
2. Başlatıcı .plist Dosyası
Aşağıdaki içeriği ~/Library/LaunchAgents/com.nuritiras.gui_app.plist adıyla kaydet:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.nuritiras.gui_app</string>
<key>ProgramArguments</key>
<array>
<string>/Users/nuritiras/Proje/venv/bin/python3</string>
<string>/Users/nuritiras/Proje/main.py</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<dict>
<key>Crashed</key>
<true/>
</dict>
<key>WorkingDirectory</key>
<string>/Users/nuritiras/Proje</string>
<key>StandardOutPath</key>
<string>/tmp/my_gui_app.log</string>
<key>StandardErrorPath</key>
<string>/tmp/my_gui_app.err</string>
</dict>
</plist>
3. GUI Uygulamaları İçin Önemli İpuçları
ProcessType: Eğer uygulamanın arka planda sistem kaynaklarını daha az tüketmesini istersen
<key>ProcessType</key><string>Interactive</string>ekleyebilirsin. GUI uygulamaları için "Interactive" idealdir.LimitLoadToSessionType: GUI uygulamaları için bazen
<key>LimitLoadToSessionType</key><string>Aqua</string>eklemek gerekebilir. Bu, uygulamanın sadece görsel ekran (GUI) hazır olduğunda çalışmasını garanti eder.Path Çözümleme:
main.pydosyan içinde resim veya ikon yolları kullanıyorsan, bu yolları mutlakaos.path.dirname(os.path.abspath(__file__))ile dinamik olarak oluştur. Aksi takdirdelaunchdçalışma dizinini farklı algılayabilir.
4. Aktivasyon
Terminal üzerinden şu komutla yeni servisini aktif edebilirsin:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.nuritiras.gui_app.plist
Yorumlar