Làm chủ quy tắc udev: Cố định tên thiết bị USB và tự động hóa phần cứng trên Linux

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

Nỗi ám ảnh mang tên: Tên thiết bị thay đổi liên tục

Tôi đã từng suýt xóa sạch một cơ sở dữ liệu production chỉ vì script sao lưu của mình nhắm vào /dev/sdb1. Nó hoạt động ổn định trong nhiều tuần cho đến khi tôi cắm thêm một chiếc USB dự phòng và khởi động lại máy. Đột nhiên, ổ đĩa sao lưu của tôi biến thành /dev/sdc1, và script cứ thế mù quáng đổ dữ liệu vào một chiếc USB cài đặt 16GB ngẫu nhiên. Đó chính là lúc tôi nhận ra mình phải bắt đầu sử dụng udev.

Trên Linux, udev là trình quản lý thiết bị nằm trong thư mục /dev. Nó theo dõi kernel, nắm bắt thời điểm phần cứng được cắm vào và áp dụng các quy tắc (rule) cụ thể để xác định tên thiết bị và quyền truy cập. Cho dù bạn muốn một chiếc Arduino luôn được mount tại /dev/arduino hay cần một script tự động chạy ngay khi camera kết nối, udev chính là công cụ bạn cần.

Bắt đầu nhanh: Thiết lập quy tắc udev trong 5 phút

Hãy bỏ qua lý thuyết rườm rà và đi thẳng vào giải pháp. Giả sử bạn có một ổ SSD gắn ngoài cần quyền đọc/ghi cho tất cả mọi người (0666) và một cái tên không bao giờ thay đổi, bất kể bạn cắm vào cổng nào.

1. Xác định thông tin phần cứng

Cắm thiết bị vào và lấy ID của nó bằng lệnh lsusb:

lsusb
# Ví dụ kết quả trả về:
# Bus 002 Device 003: ID 0bc2:ab44 Seagate RSS LLC Expansion Portable

Trong trường hợp này, 0bc2idVendorab44idProduct của bạn.

2. Tạo file quy tắc (rule file)

Linux xử lý các quy tắc udev trong thư mục /etc/udev/rules.d/ theo thứ tự bảng chữ cái. Để đảm bảo quy tắc của bạn được ưu tiên, hãy bắt đầu tên file bằng một số lớn như 99.

sudo nano /etc/udev/rules.d/99-external-ssd.rules

3. Viết logic

Thêm dòng sau vào file, nhớ thay bằng các ID cụ thể của bạn:

SUBSYSTEM=="usb", ATTRS{idVendor}=="0bc2", ATTRS{idProduct}=="ab44", MODE="0666", SYMLINK+="backup_disk"

4. Tải lại hệ thống

Buộc udev nhận diện các hướng dẫn mới:

sudo udevadm control --reload-rules
sudo udevadm trigger

Giờ đây, mỗi khi bạn cắm ổ đĩa đó vào, một symlink sẽ xuất hiện tại /dev/backup_disk. Không còn phải đoán tên thiết bị nữa.

Đi sâu tìm hiểu: Quy tắc udev thực sự hoạt động như thế nào

Hãy coi một quy tắc udev như một cổng logic đơn giản: Nếu [Khóa khớp – Match Keys], thì [Khóa gán – Assignment Keys].

Khóa khớp (Câu lệnh ‘Nếu’)

Các khóa này kiểm tra xem thiết bị có khớp với tiêu chí của bạn hay không bằng toán tử ==.

  • KERNEL: Lọc theo tên mặc định của kernel (như sd* hoặc ttyUSB*).
  • SUBSYSTEM: Nhắm vào danh mục thiết bị (ví dụ: block cho ổ đĩa, net cho card mạng).
  • ATTRS{attribute}: Kiểm tra các chi tiết ở cấp độ phần cứng như số sê-ri hoặc chuỗi nhà sản xuất.

Khóa gán (Câu lệnh ‘Thì’)

Khi udev tìm thấy kết quả khớp, nó sẽ thực hiện các hành động này bằng toán tử = hoặc +=.

  • SYMLINK: Tạo một bí danh dễ nhớ trong /dev. Hãy dùng cái này thay cho NAME.
  • OWNER, GROUP, MODE: Quy định ai thực sự có quyền sử dụng thiết bị.
  • RUN: Kích hoạt một script bên ngoài.

Sức mạnh của udevadm info

Kết quả từ lsusb thông thường thường quá sơ sài đối với các quy tắc phức tạp. Để xem mọi thuộc tính mà udev có thể theo dõi, hãy sử dụng lệnh info để duyệt qua cây thiết bị:

udevadm info -a -p $(udevadm info -q path -n /dev/sdb)

Lệnh này sẽ đưa ra danh sách mọi thiết bị cha và các thuộc tính của nó. Một quy tắc quan trọng: Bạn có thể lấy thuộc tính từ các thiết bị cha khác nhau, nhưng bạn không được trộn lẫn các thuộc tính từ hai thiết bị cha khác nhau trong cùng một dòng quy tắc.

Cách dùng nâng cao: Tự động hóa và sự bền vững

Một khi bạn đã thuần thục việc tạo symlink, bạn có thể bắt đầu tự động hóa toàn bộ quy trình làm việc của mình.

Cố định tên giao diện mạng

Bạn mệt mỏi vì eth0 bỗng dưng biến thành eth1 sau khi cập nhật kernel? Hãy khớp card mạng (NIC) bằng địa chỉ MAC của nó để cố định tên:

SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="00:e0:4c:53:44:58", NAME="wan_internal"

Tự động kích hoạt đồng bộ ảnh

Đây là phần thú vị nhất. Bạn có thể kích hoạt một script tự động chạy khi một thẻ nhớ SD cụ thể được cắm vào:

SUBSYSTEM=="block", ACTION=="add", ATTRS{serial}=="5744-2D58", RUN+="/usr/local/bin/backup_photos.sh"

Lưu ý: udev sẽ bị treo nếu script của bạn chạy quá lâu. Nếu tác vụ của bạn kéo dài hơn 5 giây, hãy sử dụng systemd-run hoặc chạy ngầm (background) tiến trình để giữ cho hệ thống luôn phản hồi.

Lời khuyên thực tiễn từ kinh nghiệm thực tế

Tôi đã quản lý hơn 15 máy chủ Linux trong 4 năm, và ba quy tắc sau đây đã giúp tôi tiết kiệm vô số giờ sửa lỗi.

1. Kiểm tra kỹ trước khi áp dụng

Đừng bao giờ mặc định một quy tắc sẽ hoạt động chỉ vì nó trông có vẻ đúng. Hãy sử dụng udevadm test để mô phỏng một sự kiện thiết bị. Nó sẽ cho bạn biết chính xác quy tắc nào sẽ được kích hoạt mà bạn không cần phải chạm vào một sợi dây cáp nào.

# Mô phỏng một sự kiện cho /dev/sdb
udevadm test $(udevadm info -q path -n /dev/sdb)

2. Theo dõi dòng sự kiện trực tiếp

Nếu một quy tắc không hoạt động, hãy mở một cửa sổ terminal thứ hai và chạy udevadm monitor. Nó giống như một bản log thời gian thực về mọi sự kiện phần cứng tác động đến kernel. Bạn sẽ thấy chính xác quá trình khớp lệnh bị lỗi ở đâu.

3. Sử dụng Group thay vì 0666

Thiết lập quyền truy cập thành 0666 là một rủi ro bảo mật—nó cho phép bất kỳ người dùng cục bộ hoặc dịch vụ nào bị xâm nhập đều có thể truy cập phần cứng của bạn. Thay vào đó, hãy gán thiết bị cho một nhóm (group) cụ thể:

SUBSYSTEM=="usb", ATTRS{idVendor}=="1a86", GROUP="developer", MODE="0660"

Điều này đảm quả chỉ những người dùng trong nhóm developer mới có thể thao tác với thiết bị, giúp môi trường production của bạn an toàn hơn nhiều.

Udev có vẻ trông đáng sợ with những dấu bằng kép và ngoặc nhọn, nhưng nó là một trong những thành phần đáng tin cậy nhất của hệ thống Linux. Nó biến một mớ hỗn độn các thiết bị phần cứng cắm nóng (hot-swappable) thành một hệ thống có thể dự đoán và tự động hóa. Hãy bắt đầu với một symlink đơn giản, và bạn sẽ không bao giờ muốn quay lại cảnh phải đi tìm tên thiết bị thay đổi liên tục nữa đâu.

Share: