00 udev nedir: kernel'dan udevd'ye akış
udev, Linux çekirdeğinin ürettiği cihaz olaylarını yakalayan, /dev dosya sistemini yöneten ve kullanıcı alanı kurallarını çalıştıran dinamik cihaz yöneticisidir.
Genel bakış
Linux'ta her donanım bileşeni çekirdek tarafından soyutlanır ve bir cihaz dosyasıyla temsil edilir. Tarihsel olarak /dev dizini statik bir dosya kümesiydi; her olası cihaz için önceden oluşturulmuş dosyalar içeriyordu. udev bu yaklaşımı değiştirdi: cihazlar fiziksel olarak bağlandığında /dev'de yaratılır, çıkarıldığında silinir.
kernel → netlink → udevd → rules akışı
Bir USB cihazı takıldığında çekirdek önce cihazı tanır, gerekli driver'ı yükler ve ardından netlink soketi üzerinden bir "uevent" mesajı yayar. udevd (veya modern systemd altında systemd-udevd) bu mesajı dinler. Uevent'i aldığında kural dosyalarını tarar, eşleşen kuralları sırayla uygular ve son olarak /dev'de cihaz dosyasını oluşturur.
Donanım takıl → kernel driver probe → uevent (netlink) → udevd → kural eşleşmesi → /dev/cihaz oluştur + RUN çalıştır
# Kernel ve udev olaylarını eş zamanlı izle
udevadm monitor
# Yalnızca kernel olayları
udevadm monitor --kernel
# Yalnızca udev olayları (kurallar uygulandıktan sonra)
udevadm monitor --udev
# Örnek çıktı (USB cihaz takıldığında):
# KERNEL[12345.678] add /devices/pci.../usb1/1-1 (usb)
# KERNEL[12345.680] add /devices/pci.../usb1/1-1/1-1:1.0 (usb)
# UDEV [12345.720] add /devices/pci.../usb1/1-1 (usb)
# UDEV [12345.730] add /devices/pci.../ttyUSB0 (tty)
/dev sanal dosya sistemi
Modern Linux sistemlerinde /dev, devtmpfs sanal dosya sistemiyle bağlanır. Çekirdek, driver probe başarılı olduğunda devtmpfs'e cihaz node'u oluşturur; udevd ardından izinleri, sahipliği ve sembolik linkleri ayarlar.
| Dosya Sistemi | Kim yönetir | Ne zaman |
|---|---|---|
| devtmpfs | Kernel | Driver probe'da node oluşturur |
| udevd kuralları | Userspace (udevd) | Uevent'ten sonra izin/symlink/script |
| /run/udev/ | udevd | Cihaz metadata önbelleği |
udev kural dosyalarının konumu
Kural dosyaları alfabetik/numerik sırayla işlenir. 99-custom.rules gibi yüksek numaralı dosyalar dağıtım kurallarının üzerine yazabilir. Özel kurallar için /etc/udev/rules.d/ kullanın ve dosyaya 50- ile 99- arasında bir önek verin.
Bu bölümde
- udev: dinamik /dev yönetimi; cihaz takılınca oluştur, çıkarılınca sil
- Akış: kernel uevent → netlink → udevd → kural eşleşmesi → node + symlink + script
- udevadm monitor: kernel ve udev olaylarını eş zamanlı izler
- Kural önceliği: /etc/udev/rules.d/ > /usr/lib/udev/rules.d/ > /lib/udev/rules.d/
01 udevadm ile cihaz keşfi
udevadm, udev sistemini incelemek ve test etmek için temel araçtır. Cihaz özelliklerini sorgulama, olay izleme ve kural testi için kullanılır.
udevadm info: cihaz özelliklerini sorgulama
# Tüm özellikleri sorgula (kural yazmak için hangi ATTRS kullanılacağını göster)
udevadm info --query=all --name=/dev/ttyUSB0
# Örnek çıktı:
# P: /devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2:1.0/ttyUSB0/tty/ttyUSB0
# N: ttyUSB0
# S: serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_...-if00-port0
# E: DEVLINKS=/dev/serial/by-id/usb-Silicon_Labs_... /dev/serial/by-path/...
# E: DEVNAME=/dev/ttyUSB0
# E: ID_VENDOR_ID=10c4
# E: ID_MODEL_ID=ea60
# E: ID_SERIAL=Silicon_Labs_CP2102_...
# Üst cihazlarla birlikte özellik zincirini göster (ATTRS için kritik)
udevadm info --attribute-walk --name=/dev/ttyUSB0
# Kısaltılmış çıktı: yalnızca özellikler
udevadm info -q property -n /dev/ttyUSB0
attribute-walk çıktısını okuma
Kural yazarken hangi ATTRS{} anahtarlarını kullanabileceğinizi öğrenmek için --attribute-walk çıktısını dikkatli okuyun. Çıktı hiyerarşik yapıdadır: en alttaki blok cihazın kendisi, üsttekiler ana cihazlardır.
udevadm info --attribute-walk --name=/dev/ttyUSB0
# Udevadm info starts with the device specified by the devpath and then
# walks up the chain of parent devices...
# --- Cihazın kendisi (ttyUSB0) ---
# looking at device '/devices/.../ttyUSB0/tty/ttyUSB0':
# KERNEL=="ttyUSB0"
# SUBSYSTEM=="tty"
# DRIVER==""
# --- Üst USB interface ---
# looking at parent device '/devices/.../1-2:1.0':
# ATTRS{bInterfaceClass}=="ff"
# ATTRS{bInterfaceNumber}=="00"
# ATTRS{bInterfaceProtocol}=="00"
# --- USB cihaz kökü ---
# looking at parent device '/devices/.../1-2':
# ATTRS{idVendor}=="10c4"
# ATTRS{idProduct}=="ea60"
# ATTRS{manufacturer}=="Silicon Labs"
# ATTRS{product}=="CP2102 USB to UART Bridge Controller"
# ATTRS{serial}=="0001"
udevadm monitor: canlı olay izleme
# Tüm olayları izle (USB tak/çıkar denerken)
udevadm monitor --property
# Yalnızca belirli subsystem
udevadm monitor --subsystem-match=tty
udevadm monitor --subsystem-match=usb
udevadm monitor --subsystem-match=net
# Örnek çıktı (USB seri cihaz takıldığında):
# KERNEL[...] add /devices/.../ttyUSB0 (tty)
# ACTION=add
# DEVNAME=/dev/ttyUSB0
# SUBSYSTEM=tty
# ID_VENDOR_ID=10c4
# ID_MODEL_ID=ea60
Sysfs üzerinden doğrudan erişim
# USB cihazların vendor/product ID'lerini bul
cat /sys/bus/usb/devices/1-2/idVendor
cat /sys/bus/usb/devices/1-2/idProduct
cat /sys/bus/usb/devices/1-2/manufacturer
# tty subsystem cihazlarını listele
ls /sys/class/tty/ | grep USB
# Net arayüzleri
ls /sys/class/net/
# Belirli bir cihazın sysfs yolunu bul
udevadm info -q path -n /dev/ttyUSB0
# /devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2:1.0/ttyUSB0/tty/ttyUSB0
Bu bölümde
- udevadm info --query=all --name=/dev/X: ENV değişkenleri ve sembolik link bilgisi
- udevadm info --attribute-walk: kural yazmak için ATTRS{} anahtarlarını keşfet
- udevadm monitor --property: canlı olay akışını izle; kural test için olmazmazı
- Sysfs: /sys/bus/usb/devices/ ve /sys/class/ üzerinden doğrudan özellik okuma
02 Kural dosyası anatomisi
udev kural dosyaları, eşleştirme anahtarları (match keys) ve atama anahtarları (assignment keys) içeren satırlardan oluşur. Bir satırdaki tüm eşleştirmeler doğru olduğunda atamalar uygulanır.
Kural satırı yapısı
Her kural satırı virgülle ayrılmış anahtar=değer çiftlerinden oluşur. Eşleştirme anahtarları (== veya !=) cihazın özelliklerini sorgular; atama anahtarları (=, +=, :=) işlemleri tanımlar.
| Operatör | Tür | Anlamı |
|---|---|---|
== | Eşleştirme | Değer eşitse kural geçerli |
!= | Eşleştirme | Değer eşit değilse kural geçerli |
= | Atama | Değeri ata (önceki değerleri sil) |
+= | Atama | Değeri listeye ekle (SYMLINK için) |
:= | Atama | Değeri ata ve sonraki kuralların değiştirmesini engelle |
Temel eşleştirme anahtarları
# SUBSYSTEM: cihaz alt sistemi
SUBSYSTEM=="tty" # TTY cihazları
SUBSYSTEM=="usb" # USB cihazları
SUBSYSTEM=="net" # Ağ arayüzleri
SUBSYSTEM=="block" # Blok cihazlar (disk, SD kart)
# ACTION: cihaz olayı türü
ACTION=="add" # Cihaz takıldı / driver yüklendi
ACTION=="remove" # Cihaz çıkarıldı
ACTION=="change" # Cihaz durumu değişti
ACTION=="bind" # Driver cihaza bağlandı
ACTION=="unbind" # Driver cihazdan ayrıldı
# KERNEL: /dev'deki cihaz adı kalıbı
KERNEL=="ttyUSB*" # ttyUSB0, ttyUSB1, ...
KERNEL=="sd[a-z]" # sda, sdb, ... (disk)
KERNEL=="video[0-9]*" # video0, video1, ...
# ATTRS{}: üst cihaz özelliği (attribute-walk ile keşfedilir)
ATTRS{idVendor}=="10c4" # Silicon Labs USB vendor ID
ATTRS{idProduct}=="ea60" # CP2102 product ID
ATTRS{manufacturer}=="Silicon Labs"
ATTRS{serial}=="AB12CD34"
# ENV{}: ortam değişkeni
ENV{ID_VENDOR_ID}=="10c4"
ENV{ID_BUS}=="usb"
# DEVPATH: sysfs yolu
DEVPATH=="/devices/pci*/usb[0-9]*/1-1/*"
Temel atama anahtarları
# NAME: /dev'deki cihaz adını değiştir
NAME="myuart" # /dev/myuart olarak oluşturulur
# SYMLINK: sembolik link ekle
SYMLINK+="sensor_uart" # /dev/sensor_uart → /dev/ttyUSB0
# MODE: dosya izinleri
MODE="0666" # Herkes okuyup yazabilir
MODE="0660" # Sahip ve grup okuyup yazabilir
# OWNER/GROUP: sahip ve grup
OWNER="root"
GROUP="dialout"
# RUN: shell komutu veya script çalıştır
RUN+="/usr/local/bin/hotplug.sh"
RUN+="/bin/sh -c 'echo connected > /tmp/device_status'"
# ENV{}: ortam değişkeni ata
ENV{MY_DEVICE_TYPE}="sensor"
# LABEL/GOTO: kural akışı kontrolü
LABEL="end"
GOTO="end"
Joker karakterler ve değişkenler
# Joker karakterler
# * — sıfır veya daha fazla karakter
# ? — tam olarak bir karakter
# [] — karakter kümesi
KERNEL=="ttyUSB*" # ttyUSB0..ttyUSB9...
KERNEL=="ttyS?" # ttyS0..ttyS9 (tek haneli)
KERNEL=="sd[a-d][0-9]" # sda1, sdb3, vb.
# Yerleşik değişkenler (NAME/SYMLINK/RUN içinde)
# %k — KERNEL adı (örn. ttyUSB0)
# %n — cihaz numarası (örn. 0)
# %p — DEVPATH
# %E{ENV_VAR} — ortam değişkeni değeri
# %s{attr} — sysfs özelliği
SYMLINK+="serial-%k" # serial-ttyUSB0
RUN+="/bin/sh -c 'logger udev: %k bağlandı'"
Bu bölümde
- == eşleştirme, = atama, += listeye ekleme, := sabitleyerek atama
- SUBSYSTEM, ACTION, KERNEL, ATTRS{}, ENV{}: temel eşleştirme anahtarları
- NAME, SYMLINK, MODE, OWNER, GROUP, RUN: temel atama anahtarları
- %k, %n, %p, %E{}: kural içi değişkenler; dinamik sembol oluşturmak için
03 Kalıcı isimler ve sembolik linkler
USB cihazlarının sırası değişebilir: bugün ttyUSB0 olan yarın ttyUSB1 olabilir. Vendor/Product ID veya seri numarasına dayalı kalıcı isimler bu sorunu çözer.
Neden kalıcı isimler gerekir
Linux, USB cihazlara sıralı isimler atar; ama bu sıra takma/çıkarma sırasına göre değişir. Bir üretim ortamında iki USB seri dönüştürücü kullanıyorsanız hangisinin /dev/ttyUSB0, hangisinin /dev/ttyUSB1 olduğunu bilemezsiniz. Seri numarası veya USB port konum bilgisi (DEVPATH) kullanarak her zaman aynı cihazın aynı isimle görünmesi sağlanır.
# Seri numarasına göre kalıcı symlink
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", \
ATTRS{serial}=="AB12CD34", SYMLINK+="sensor_a"
# Farklı seri numarası, farklı cihaz
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", \
ATTRS{serial}=="EF56GH78", SYMLINK+="sensor_b"
# USB port konumuna göre (seri numarası yoksa)
# usb1/1-1.1 = ilk hub, port 1
SUBSYSTEM=="tty", KERNELS=="1-1.1:1.0", SYMLINK+="gps_uart"
# Birden fazla sembolik link
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", \
SYMLINK+="ftdi_uart serial/ftdi-%k"
NAME direktifi ile cihaz adını değiştirme
SYMLINK yalnızca ek link oluşturur; asıl /dev/ttyUSBX dosyası da varlığını sürdürür. NAME ise asıl adı değiştirir. Ancak NAME değiştirmek bazı araçlarla (örn. ModemManager) uyumsuzluk yaratabilir; SYMLINK tercih edilir.
# Asıl cihaz adını değiştir (dikkatli kullan)
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", \
NAME="custom_uart0"
# Kullanımdan sonra: /dev/custom_uart0 (ttyUSB0 artık yok)
ls -la /dev/custom_uart0
# crw-rw---- 1 root dialout 188, 0 /dev/custom_uart0
Ağ arayüzleri için kalıcı isimler
Ağ arayüzlerinde de benzer sorun yaşanır: eth0/eth1 sırası değişebilir. systemd-udevd bunu /lib/udev/rules.d/80-net-setup-link.rules ile MAC adresine göre çözer. Özel kurallar da yazılabilir.
# MAC adresine göre sabit isim
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="aa:bb:cc:dd:ee:ff", \
NAME="eth_mgmt"
# USB ağ adaptörü için
SUBSYSTEM=="net", ACTION=="add", ATTRS{idVendor}=="0b95", \
ATTRS{idProduct}=="1790", NAME="usb_eth0"
# Belirli PCI slotundaki kart
SUBSYSTEM=="net", ACTION=="add", KERNELS=="0000:01:00.0", \
NAME="wan0"
Mevcut sembolik linkleri görme
# Seri cihazlar için udev tarafından oluşturulan kalıcı linkler
ls -la /dev/serial/by-id/
# lrwxrwxrwx ... usb-Silicon_Labs_CP2102_...-if00-port0 -> ../../ttyUSB0
ls -la /dev/serial/by-path/
# lrwxrwxrwx ... pci-0000:00:14.0-usb-0:2:1.0-port0 -> ../../ttyUSB0
# Kendi tanımladığımız linkler
ls -la /dev/sensor_a /dev/sensor_b
Bu bölümde
- SYMLINK+=: kalıcı sembolik link oluşturur; asıl ttyUSBX dosyası korunur
- ATTRS{serial} veya KERNELS (USB port konum): cihazı benzersiz olarak tanımlar
- NAME=: asıl cihaz adını değiştirir; dikkatli kullanılmalı, SYMLINK genellikle yeterli
- /dev/serial/by-id/ ve /dev/serial/by-path/: udev'in varsayılan kalıcı link dizinleri
04 Script tetikleme ve ortam değişkenleri
RUN+ direktifi ile cihaz takıldığında veya çıkarıldığında otomatik olarak script veya komut çalıştırılır. Ortam değişkenleri ile bağlam bilgisi script'e aktarılır.
RUN direktifi
RUN, kural eşleştiğinde çalıştırılacak programı belirtir. Program, udevd tarafından arka planda yürütülür. Dikkat: udevd zaman aşımına duyarlıdır; uzun süren işlemler için systemd service başlatılmalıdır.
# Basit komut çalıştırma
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ACTION=="add", \
RUN+="/usr/local/bin/sensor_connect.sh"
# Shell komutları (sh -c ile)
SUBSYSTEM=="tty", ACTION=="add", KERNEL=="ttyUSB*", \
RUN+="/bin/sh -c 'echo %k >> /tmp/plugged_devices'"
# Cihaz çıkarılınca farklı script
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ACTION=="remove", \
RUN+="/usr/local/bin/sensor_disconnect.sh"
# systemd servisi başlat (uzun işlemler için)
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ACTION=="add", \
RUN+="/bin/systemctl start sensor-daemon.service"
# Birden fazla komut
SUBSYSTEM=="usb", ACTION=="add", ATTRS{idVendor}=="1234", \
RUN+="/usr/local/bin/init_device.sh", \
RUN+="/bin/logger 'Custom USB device connected'"
Ortam değişkenleri: script'e bağlam aktarma
udevd, RUN script'ini çalıştırırken uevent özelliklerini ortam değişkeni olarak aktarır. Script içinde $ACTION, $DEVNAME, $ID_VENDOR_ID gibi değişkenler kullanılabilir.
# Kural içinde ENV set et — script'ten erişilir
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", \
ENV{DEVICE_TYPE}="cp2102_uart", \
ENV{BAUD_RATE}="115200", \
RUN+="/usr/local/bin/configure_uart.sh"
#!/bin/bash
# udev tarafından çalıştırılan hotplug script
# udevd'nin aktardığı ortam değişkenleri
DEVICE="$DEVNAME" # /dev/ttyUSB0
ACTION_TYPE="$ACTION" # add / remove
VENDOR="$ID_VENDOR_ID" # 10c4
PRODUCT="$ID_MODEL_ID" # ea60
SERIAL="$ID_SERIAL_SHORT" # AB12CD34
BAUD="$BAUD_RATE" # 115200 (kural içinde set edildi)
# Log yaz
logger -t udev-hotplug "Action=$ACTION_TYPE Device=$DEVICE Vendor=$VENDOR"
if [ "$ACTION_TYPE" = "add" ]; then
# Baud rate ayarla
stty -F "$DEVICE" "$BAUD"
# Servise bildir (FIFO, socket veya dosya üzerinden)
echo "CONNECTED:$DEVICE:$SERIAL" > /run/sensor/event_fifo
# Lock dosyası oluştur
touch "/run/sensor/device_${SERIAL}.lock"
fi
if [ "$ACTION_TYPE" = "remove" ]; then
rm -f "/run/sensor/device_${SERIAL}.lock"
echo "DISCONNECTED:$DEVICE:$SERIAL" > /run/sensor/event_fifo
fi
ENV değişkenini sonraki kuralda okuma
# İlk kural: cihaz türünü belirle
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", \
ENV{MY_UART_TYPE}="ftdi"
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", \
ENV{MY_UART_TYPE}="cp210x"
# İkinci kural: türe göre farklı grup ata
SUBSYSTEM=="tty", ENV{MY_UART_TYPE}=="ftdi", GROUP="ftdi_users"
SUBSYSTEM=="tty", ENV{MY_UART_TYPE}=="cp210x", GROUP="sensor_users"
# Üçüncü kural: hepsini ortak dizine symlink et
SUBSYSTEM=="tty", ENV{MY_UART_TYPE}!="", \
SYMLINK+="uart/%E{MY_UART_TYPE}/%k"
Bu bölümde
- RUN+="/path/script": kural eşleştiğinde çalıştırılır; add/remove eylemine göre farklılaştırılabilir
- Uzun işlemler için: RUN+="/bin/systemctl start service" — udevd zaman aşımına uğramaz
- Script içinde $DEVNAME, $ACTION, $ID_VENDOR_ID: udevd'nin aktardığı ortam değişkenleri
- ENV{KEY}="value": kural zincirinde sonraki kurallara bağlam aktarımı
05 Seri port ve CAN kuralları
Embedded geliştirmenin temel ihtiyaçları: USB-seri dönüştürücüler için kalıcı isimler, CAN arayüzleri için otomatik başlatma ve doğru grup izinleri.
USB-seri dönüştürücü kuralları
# CP2102 (Silicon Labs) — sensor bağlantısı
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", \
ATTRS{serial}=="0001", \
SYMLINK+="sensor_uart", \
GROUP="dialout", \
MODE="0660"
# FTDI FT232 — debug konsolu
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", \
SYMLINK+="debug_uart", \
GROUP="dialout", \
MODE="0660"
# CH340/CH341 (ucuz USB-UART) — programlama portu
SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", \
SYMLINK+="prog_uart", \
GROUP="dialout", \
MODE="0666"
# PL2303 (Prolific) — GPS modülü
SUBSYSTEM=="tty", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", \
SYMLINK+="gps_uart", \
GROUP="dialout", \
MODE="0660", \
RUN+="/usr/local/bin/init_gps.sh"
CAN arayüzü kuralları
USB-CAN adaptörleri (slcan, gs_usb driver'ı kullanan Canable/PCAN gibi) Linux'ta özel yapılandırma gerektirir. udev kuralı hem sembolik link hem de otomatik ip link set up yapabilir.
# gs_usb driver (CANable, Canable Pro, STM32 bazlı CAN adaptörleri)
SUBSYSTEM=="net", ACTION=="add", \
ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="606f", \
NAME="can_vehicle", \
RUN+="/sbin/ip link set can_vehicle type can bitrate 500000"
RUN+="/sbin/ip link set can_vehicle up"
# slcan (Serial Line CAN — UART üzerinden)
SUBSYSTEM=="tty", ACTION=="add", \
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", \
ATTRS{interface}=="SLCAN", \
SYMLINK+="can_serial", \
RUN+="/usr/local/bin/slcan_init.sh"
# KVASER USB CAN
SUBSYSTEM=="net", ACTION=="add", \
ATTRS{idVendor}=="0bfd", \
ENV{KVASER_CHANNEL}="%n", \
NAME="kvcan%n"
#!/bin/bash
# slcan: seri port üzerinden CAN arayüzü başlatma
UART_DEV="$DEVNAME"
CAN_IFACE="slcan0"
BITRATE="500000"
# slcand daemon'u başlat
/usr/bin/slcand -o -s6 -t hw -S "$BITRATE" "$UART_DEV" "$CAN_IFACE"
# Kısa bekleme
sleep 0.5
# Arayüzü aç
/sbin/ip link set "$CAN_IFACE" up
logger -t udev-can "slcan başlatıldı: $UART_DEV -> $CAN_IFACE"
OWNER, GROUP ve MODE
# Grup izinleri — kullanıcıyı gruba eklemek yeterli
SUBSYSTEM=="tty", KERNEL=="ttyUSB*", \
GROUP="dialout", MODE="0660"
# Tüm kullanıcılara izin (geliştirme ortamı için)
SUBSYSTEM=="tty", KERNEL=="ttyUSB*", \
MODE="0666"
# Belirli kullanıcıya sahiplik
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", \
OWNER="ubuntu", GROUP="ubuntu", MODE="0660"
# Kullanıcıyı dialout grubuna ekle (kural değişikliği gerektirmez)
sudo usermod -aG dialout $USER
# Etkinleştirmek için oturumu yenile veya:
newgrp dialout
Bu bölümde
- CP2102/FTDI/CH340: ATTRS{idVendor}+ATTRS{idProduct} ile kalıcı SYMLINK ve GROUP ataması
- gs_usb CAN: NAME= ile sabit arayüz adı, RUN= ile bitrate ayarı ve ip link up
- slcan: UART'ı CAN arayüzüne dönüştürme script'i; slcand daemon ile
- GROUP="dialout" + MODE="0660": kullanıcıyı gruba eklemek yeterli, sudo gerekmez
06 Kural debug ve yeniden yükleme
udev kurallarını test etmek, hata ayıklamak ve yeniden yüklemek için gerekli komutlar — sistemi yeniden başlatmadan kural geliştirme döngüsü.
udevadm test ile kural simülasyonu
udevadm test, gerçekten bir cihaz takılmadan kuralların nasıl çalışacağını simüle eder. /dev'de değişiklik yapmaz ancak hangi kuralların eşleştiğini ve hangi atamaların yapıldığını gösterir.
# Önce sysfs yolunu bul
udevadm info -q path -n /dev/ttyUSB0
# /devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2:1.0/ttyUSB0/tty/ttyUSB0
# Kural simülasyonu (gerçek değişiklik yapmaz)
udevadm test /devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2:1.0/ttyUSB0/tty/ttyUSB0
# Örnek çıktı:
# Reading rules file: /lib/udev/rules.d/60-serial.rules
# Reading rules file: /etc/udev/rules.d/99-usb-serial.rules
# LINK '/dev/sensor_uart' /dev/ttyUSB0
# GROUP 'dialout' /dev/ttyUSB0
# MODE '0660' /dev/ttyUSB0
# RUN '/usr/local/bin/sensor_connect.sh'
# Kural eşleşmelerini detaylı göster
udevadm test --action=add /devices/.../ttyUSB0/tty/ttyUSB0 2>&1 | grep -E "IMPORT|RUN|LINK|GROUP"
Kuralları yeniden yükleme
# Kural dosyalarını yeniden yükle (udevd'ye sinyal gönder)
sudo udevadm control --reload-rules
# Kısaltma
sudo udevadm control -R
# Yeniden yükle + halihazırda bağlı cihazlara kuralları tekrar uygula
sudo udevadm control --reload-rules && sudo udevadm trigger
# Yalnızca belirli subsystem için tetikle
sudo udevadm trigger --subsystem-match=tty
sudo udevadm trigger --subsystem-match=usb
# Belirli cihaz için tetikle
sudo udevadm trigger --sysname-match=ttyUSB0
# Tamamlanmasını bekle
sudo udevadm settle
udevadm ile hata ayıklama
# udevd'yi debug modunda çalıştır (verbose)
sudo udevadm control --log-priority=debug
journalctl -f -u systemd-udevd
# Belirli bir kural dosyasını syntax kontrol
udevadm verify /etc/udev/rules.d/99-custom.rules
# Cihaz için hangi kuralların eşleştiğini tam log ile gör
sudo udevadm test --action=add \
$(udevadm info -q path -n /dev/ttyUSB0) 2>&1
# RUN script'inin çıktısını görmek için log ekle
# Script içine: logger -t my-udev-script "debug message"
journalctl -t my-udev-script -f
# Tüm cihaz özelliklerini dump et
udevadm info --export-db | grep -A5 "ttyUSB0"
Yaygın hatalar ve çözümleri
| Hata | Sebep | Çözüm |
|---|---|---|
| Kural eşleşmiyor | ATTRS{} yanlış hiyerarşide | --attribute-walk ile doğru seviyeyi bul |
| Symlink oluşmuyor | SYMLINK yerine NAME kullanılmış | SYMLINK+= kullan |
| Script çalışmıyor | Çalıştırma izni yok | chmod +x /path/script.sh |
| Script çalışmıyor | Shebang eksik veya yanlış | #!/bin/bash satırını kontrol et |
| Script timeout | Uzun süren işlem | systemctl start service ile at |
| Kural trigger etmiyor | udevd kuralları yüklenmemiş | udevadm control --reload-rules |
Bu bölümde
- udevadm test [sysfs-path]: gerçek değişiklik olmadan kural simülasyonu
- udevadm control --reload-rules: kural dosyaları değiştikten sonra yenile
- udevadm trigger: halihazırda bağlı cihazlara kuralları yeniden uygula
- --log-priority=debug + journalctl: udevd'nin tam log akışını izle
07 udev ve systemd entegrasyonu
systemd, udev'i kendi cihaz yönetim altyapısına entegre eder. Device unit'ler, conditional service başlatma ve socket activation ile donanım-tetiklemeli servisler oluşturulur.
Device unit (.device)
systemd, udev'in oluşturduğu her cihaz için otomatik olarak bir .device unit oluşturur. Bu unit'in adı, sysfs yolundan türetilir. Diğer unit'ler bu device unit'e bağlı hale getirilebilir.
# Device unit adını bul
systemctl list-units --type=device | grep ttyUSB
# dev-ttyUSB0.device loaded active plugged /dev/ttyUSB0
# Device unit detayı
systemctl status dev-ttyUSB0.device
# Adlandırma kuralı: /dev/ttyUSB0 → dev-ttyUSB0.device
# /dev/sda1 → dev-sda1.device
# (/ yerine - kullanılır, sonuna .device eklenir)
SYSTEMD_WANTS: cihaz takılınca servis başlat
udev kuralı içinde ENV{SYSTEMD_WANTS} ile cihaz takıldığında otomatik olarak bir systemd servisi başlatılabilir. Bu yöntem RUN+ ile script çalıştırmaktan daha güvenilirdir çünkü systemd servis yaşam döngüsünü yönetir.
# Cihaz takılınca sensor-daemon servisi başlat
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", \
ACTION=="add", \
ENV{SYSTEMD_WANTS}="sensor-daemon@%k.service"
# Template service: sensor-daemon@ttyUSB0.service
# %k = kernel name (ttyUSB0)
[Unit]
Description=Sensor Daemon for %I
BindsTo=dev-%i.device
After=dev-%i.device
[Service]
Type=simple
ExecStart=/usr/local/bin/sensor-daemon /dev/%I
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
ConditionPathExists ile bağımlılık
[Unit]
Description=GPS Logger Service
# /dev/gps_uart mevcut değilse başlama
ConditionPathExists=/dev/gps_uart
After=dev-gps_uart.device
Requires=dev-gps_uart.device
[Service]
ExecStart=/usr/local/bin/gps-logger --device=/dev/gps_uart
Restart=on-failure
[Install]
WantedBy=multi-user.target
Socket activation ile USB cihaz bekleme
# systemd-path ile belirli bir dosya/cihaz görününce servis başlat
# /etc/systemd/system/sensor-watch.path
cat <<'EOF' | sudo tee /etc/systemd/system/sensor-watch.path
[Unit]
Description=Watch for sensor UART
[Path]
PathExists=/dev/sensor_uart
Unit=sensor-daemon.service
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable sensor-watch.path
sudo systemctl start sensor-watch.path
# /dev/sensor_uart oluştuğunda sensor-daemon.service otomatik başlar
Bu bölümde
- /dev/ttyUSB0 → dev-ttyUSB0.device: systemd her cihaz için otomatik .device unit oluşturur
- ENV{SYSTEMD_WANTS}: udev kuralından template servis başlatmanın güvenilir yolu
- BindsTo=dev-%i.device: cihaz çıkarılınca servis de durur
- PathExists= unit: /dev/sensor_uart gibi bir yol oluşunca servis başlatır
08 Pratik: özel USB cihazı ve embedded alternatifler
Özel bir USB cihazı için uçtan uca kural yazımı, grup yetkilendirmesi ve kaynak kısıtlı embedded sistemlerde udev alternatifleri: eudev ve mdev.
Özel USB cihazı için tam kural seti
# lsusb ile tüm USB cihazları listele
lsusb
# Bus 001 Device 004: ID 1234:5678 MyCompany Custom Device
# Detaylı bilgi
lsusb -v -d 1234:5678
# udevadm ile tam özellik listesi
udevadm info --attribute-walk --name=/dev/ttyUSB0 | \
grep -E "idVendor|idProduct|serial|manufacturer"
# Özel USB cihazı: vendor=1234, product=5678
# Adım 1: Cihazı tanımla, ENV ata
SUBSYSTEM=="tty", \
ATTRS{idVendor}=="1234", ATTRS{idProduct}=="5678", \
ENV{MY_DEVICE}="1"
# Adım 2: Seri numarasına göre farklılaştır
SUBSYSTEM=="tty", ENV{MY_DEVICE}=="1", \
ATTRS{serial}=="SN001", \
SYMLINK+="mydevice/primary", \
ENV{MY_DEVICE_ROLE}="primary"
SUBSYSTEM=="tty", ENV{MY_DEVICE}=="1", \
ATTRS{serial}=="SN002", \
SYMLINK+="mydevice/secondary", \
ENV{MY_DEVICE_ROLE}="secondary"
# Adım 3: Ortak izinler (seri numarası ne olursa olsun)
SUBSYSTEM=="tty", ENV{MY_DEVICE}=="1", \
GROUP="mydevice_group", \
MODE="0660"
# Adım 4: Bağlantı bildirimi
SUBSYSTEM=="tty", ENV{MY_DEVICE}=="1", ACTION=="add", \
RUN+="/usr/local/bin/mydevice-init.sh"
SUBSYSTEM=="tty", ENV{MY_DEVICE}=="1", ACTION=="remove", \
RUN+="/usr/local/bin/mydevice-cleanup.sh"
# Grup oluştur
sudo groupadd mydevice_group
# Kullanıcıyı gruba ekle
sudo usermod -aG mydevice_group $USER
# Kuralı yükle ve tetikle
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=tty
# Test et
ls -la /dev/mydevice/
# lrwxrwxrwx root mydevice_group primary -> ../../ttyUSB0
# lrwxrwxrwx root mydevice_group secondary -> ../../ttyUSB1
Embedded alternatifler: eudev ve mdev
Tam udev (systemd-udevd) gömülü sistemler için fazla ağır olabilir. Buildroot ve OpenWrt gibi dağıtımlar daha hafif alternatifler sunar.
| Araç | Boyut | Kural uyumluluğu | Kullanım |
|---|---|---|---|
| systemd-udevd | ~500KB + deps | Tam udev uyumlu | Desktop/server Linux |
| eudev | ~200KB | Tam udev uyumlu | Systemd olmayan embedded |
| mdev (busybox) | ~20KB | Basit, sınırlı | Minimal OpenWrt, initramfs |
| mdevd | ~30KB | mdev benzeri | s6-init, runit tabanlı |
# Buildroot menuconfig
make menuconfig
# System configuration → /dev management → Dynamic using eudev
# eudev kural dosyaları: normal udev kurallarıyla aynı format
# /etc/udev/rules.d/ dizinine koyulur
# mdev kuralları farklı formattadır:
# regex owner:group octal_mode [=|>|!symlink] [cmd]
# ttyUSB cihazları: root:dialout, 0660
ttyUSB[0-9]+ root:dialout 0660
# Script tetikleme ($MDEV ortam değişkeni cihaz adını içerir)
ttyUSB[0-9]+ root:dialout 0660 */usr/local/bin/uart_hotplug.sh
# Kural sözdizimi: * = her iki yönde, @ = eklenince, $ = kaldırılınca
ttyUSB[0-9]+ root:dialout 0660 @/bin/sh -c "echo $MDEV connected"
# mdev'i hotplug handler olarak kaydet
echo /sbin/mdev > /proc/sys/kernel/hotplug
Bu bölümde
- Tam kural seti: ENV zinciri → seri no. ayrımı → ortak izin → add/remove script
- groupadd + usermod -aG: grup temelli yetkilendirme; sudo gerektirmez
- eudev: systemd olmadan tam udev kural uyumluluğu; Buildroot'ta kolayca etkinleştirilebilir
- mdev (busybox): minimal /etc/mdev.conf formatı; ~20KB, initramfs için ideal