Lazy loaded image
Linux 设备权限实战:从串口到 GPIO 的免-sudo 之道(
Words 1665Read Time 5 min
2026-9-2
🎯
一句话主线:免 sudo 访问硬件,不是"放开权限",而是把"谁能碰这个设备"显式建模成 Linux 组
设备树管"节点存不存在"、udev 管"节点归谁/权限多少"、组管"用户算不算自己人"——三层各司其职,缺一层都白搭。

0. 适用场景

  • 服务账号(如 pipeline3d)访问 ttyUSB / i2c / spidev / gpiochip,报 Permission deniedaccess-fail
  • 不想给业务进程 root,也不愿每条命令都 sudo
  • 目标平台:i.MX8 等嵌入式 Linux(Yocto / Buildroot / Debian rootfs 均适用)

1. 第一性原理:组 = 硬件访问的授权单位

Linux 把"对某类资源的访问权"打包成 组(group)。设备节点带一个属组,只要用户属于该组,就能按权限位读写——无需 root。
三层授权模型:
负责回答
由谁决定
资源
设备节点存不存在(/dev/i2c-3…)
设备树 + 内核驱动
属组
节点归哪个组、权限几位
udev 规则
成员
用户算不算"自己人"
usermod -aG
udev 在做什么:
记住这条链,串口 / i2c / spi / gpio 乃至任何字符设备,都是同一套打法。

2. 入门案例:串口与 dialout

2.1 dialout 是什么

  • 名字来源:早年通过 modem「拨号外联(dial out)」访问串口,组因此得名。
  • 管什么:udev 把这些节点的属组设为 dialout——
    • /dev/ttyS*(板载串口)
    • /dev/ttyUSB*(USB 转串口,如 CP210x / FTDI)
    • /dev/ttyACM*(USB CDC,如 Arduino、部分调试器)
  • 典型权限crw-rw---- root dialout,即只有 root 与 dialout 成员可读写。
⚠️
dialoutDebian/Ubuntu 系惯例。Arch 及部分发行版用 uucp 管串口。换平台前先 ls -l 看真实属组,别默认。

2.2 诊断五连

先在板子上跑这套,定位到底是"权限"还是"占用"问题:
命令
含义
作用
id pipeline3d
打印 UID/GID 及所属附加组
确认账号当前在哪些组(重点看有无 dialout)
groups pipeline3d
只列出所属组名
与上条互证,更直观
ls -l 设备节点
看权限位、属主、属组;吞掉报错、永不中断脚本
判断设备归哪个组、权限是否 rw-rw----
sudo -u 测试 -r/-w
以 pipeline3d 身份实测可读可写
最关键:把"猜权限"变成"实测权限"
fuser -v 设备
列出正在占用该设备的进程
排查"被别的进程独占",与权限问题区分

2.3 修复 + 生效

  • usermod -a -G dialout:把账号追加进 dialout 组。
  • systemctl restart:进程的组身份在启动时确定,不重启进程,新组权限不生效——这正是要重启服务的原因。

2.4 两个坑

  1. -a 不能漏usermod -G(无 -a)会清空其它附加组。
  1. dialout 不一定是真实属组:若 ls -l 显示设备属组是 tty / uucp / 自定义组,加进 dialout 就是无效操作。先看属组,再决定加哪个组

3. 常见 Linux 组速查

类别
组名
授权访问
设备
dialout
串口 / modem(ttyUSB、ttyACM、ttyS)
设备
tty
终端设备 /dev/tty*
设备
audio / video
声卡 /dev/snd、摄像头/帧缓冲 /dev/video、/dev/fb
设备
i2c / spi / gpio
嵌入式总线设备(本文重点)
设备
plugdev
可热插拔设备(U 盘等)
设备
kvm / render
/dev/kvm、GPU 渲染节点 /dev/dri/render*
提权
sudo(Debian系)/ wheel(RHEL/Arch系)
允许用 sudo 提权
提权
adm
读系统日志 /var/log/*(只读排障常用)
服务
docker
访问 Docker daemon(≈ root,慎加)
服务
www-data / nginx
Web 服务运行身份
网络
netdev
管理网络接口
历史
uucp
历史 UUCP;部分发行版用它管串口
自查命令(比背列表有用):

4. 进阶战场:i.MX8 上 gpio / i2c / spi 免 sudo

套路恒定三步:建组 → 写 udev 规则 → 加组重登

4.1 第一步:建组并加用户

加组后必须重新登录(或重启服务),当前会话不会自动刷新组身份。

4.2 第二步:写 udev 规则

写入 /etc/udev/rules.d/99-embedded.rules

4.3 第三步:重载并验证

4.4 GPIO 的两套接口(最易卡住)

新接口(推荐)
旧接口(已废弃)
路径
/dev/gpiochip*(字符设备)
/sys/class/gpio/(sysfs export)
工具
libgpiod:gpioget / gpioset / gpiomon
echo N > export 手动导出
udev 能否搞定
✅ 上面那条规则直接生效
⚠️ 麻烦,见下
强烈建议直接上 libgpiod(新接口)i.MX8 内核早已支持,sysfs 接口在 5.x 起标记 deprecated。
若被迫用旧 sysfs:echo N > export动态新建 gpioN 目录且属主 root,普通 GROUP= 抓不住后生成的子节点,需脚本 hook:
%p 是 udev 占位符(设备 sysfs 路径)。即便如此 export 新引脚仍可能有竞态——这就是该迁移到 chardev 的理由

4.5 i.MX8 特定三坑

  1. 先确认 init 是 systemd-udev 还是 busybox mdev。很多 NXP BSP / Buildroot 镜像用 mdev,那 /etc/udev/rules.d/ 根本不被读取,得改 /etc/mdev.conf
    1. 判断:ps | grep -E 'udevd|mdev'
  1. 设备树要先 enable 对应节点/dev/i2c-3/dev/spidev1.0 不会凭空出现——dts 里 &i2c3 / &ecspi*status = "okay";spidev 还需子节点声明 compatible(新内核对 spidev 直接绑定会 warn,可能要加白名单)。没节点,udev 规则无的放矢
  1. 只读 rootfs(Yocto):若 /etc 只读,规则要打进 image recipe(recipes-core/udev-rules),而非运行时写入。

5. 通用 Checklist

免 sudo 五步自检:
  1. 建组 groupadd -f <grp>
  1. 写规则 /etc/udev/rules.d/*.rules(确认是 udev 而非 mdev)
  1. 重载 udevadm control --reload-rules && udevadm trigger
  1. 加组 usermod -aG <grp> <user>-a 别漏),重登或重启服务
  1. 验证 ls -l 看属组/权限 + 以目标用户实测 -r/-w
一句话收尾:设备树管"存不存在",udev 管"归谁/权限",组管"算不算自己人"。三层模型记牢,权限问题不再靠 sudo 硬扛。
上一篇
C++ String 常用操作
下一篇
嵌入式工程师习题集

Comments
Loading...