标签 设备 下的文章

使用 udev 管理你的 Linux 系统处理物理设备的方式。

 title=

Linux 能够出色地自动识别、加载、并公开接入的无数厂商的硬件设备。事实上,很多年以前,正是这个特性说服我,坚持让我的雇主将整个基础设施转换到 Linux。痛点在于 Redmond 的某家公司(LCTT 译注:指微软)不能在我们的 Compaq 台式机上加载集成网卡的驱动,而 Linux 可以轻松实现这一点。

从那以后的岁月里,Linux 的识别设备库随着该过程的复杂化而与日俱增,而 udev 就是解决这个问题的希望之星。udev 负责监听 Linux 内核发出的改变设备状态的事件。它可能是一个新 USB 设备被插入或拔出,也可能是一个无线鼠标因浸入洒出的咖啡中而脱机。

udev 负责处理所有的状态变更,比如指定访问设备使用的名称和权限。这些更改的记录可以通过 dmesg 获取。由于 dmesg 的输出通常有几千行,对结果进行过滤通常是聪明的选择。下面的例子说明了 Linux 如何识别我的 WiFi 接口。这个例子展示了我的无线设备使用的芯片组(ath9k)、启动过程早期阶段分配的原始名称(wlan0)、以及正在使用的又臭又长的永久名称(wlxec086b1ef0b3):

$ dmesg | grep wlan
[    5.396874] ath9k_htc 1-3:1.0 wlxec086b1ef0b3: renamed from wlan0

在这篇文章中,我会讨论为何有人想要使用这样的名称。在这个过程中,我会探索剖析 udev 的配置文件,然后展示如何更改 udev 的设置,包括编辑系统命名设备的方式。这篇文件基于我的新课程中《Linux 系统优化》的一个模块。

理解 udev 配置系统

使用 systemd 的机器上,udev 操作由 systemd-udevd 守护进程管理,你可以通过常规的 systemd 方式使用 systemctl status systemd-udevd 检查 udev 守护进程的状态。

严格来说,udev 的工作方式是试图将它收到的每个系统事件与 /lib/udev/rules.d//etc/udev/rules.d/ 目录下找到的规则集进行匹配。规则文件包括匹配键和分配键,可用的匹配键包括 actionnamesubsystem。这意味着如果探测到一个属于某个子系统的、带有特定名称的设备,就会给设备指定一个预设的配置。

接着,“分配”键值对被拿来应用想要的配置。例如,你可以给设备分配一个新名称、将其关联到文件系统中的一个符号链接、或者限制为只能由特定的所有者或组访问。这是从我的工作站摘出的一条规则:

$ cat /lib/udev/rules.d/73-usb-net-by-mac.rules
# Use MAC based names for network interfaces which are directly or indirectly
# on USB and have an universally administered (stable) MAC address (second bit
# is 0). Don't do this when ifnames is disabled via kernel command line or
# customizing/disabling 99-default.link (or previously 80-net-setup-link.rules).

IMPORT{cmdline}="net.ifnames"
ENV{net.ifnames}=="0", GOTO="usb_net_by_mac_end"

ACTION=="add", SUBSYSTEM=="net", SUBSYSTEMS=="usb", NAME=="", \
    ATTR{address}=="?[014589cd]:*", \
    TEST!="/etc/udev/rules.d/80-net-setup-link.rules", \
    TEST!="/etc/systemd/network/99-default.link", \
    IMPORT{builtin}="net_id", NAME="$env{ID_NET_NAME_MAC}"

add 动作告诉 udev,只要新插入的设备属于网络子系统,并且是一个 USB 设备,就执行操作。此外,如果我理解正确的话,只有设备的 MAC 地址由特定范围内的字符组成,并且 80-net-setup-link.rules99-default.link 文件存在时,规则才会生效。

假定所有的条件都满足,接口 ID 会改变以匹配设备的 MAC 地址。还记得之前的 dmesg 信息显示我的接口名称从 wlan0 改成了讨厌的 wlxec086b1ef0b3 吗?那都是这条规则的功劳。我怎么知道?因为 ec:08:6b:1e:f0:b3 是设备的 MAC 地址(不包括冒号)。

$ ifconfig -a
wlxec086b1ef0b3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.0.103  netmask 255.255.255.0  broadcast 192.168.0.255
        inet6 fe80::7484:3120:c6a3:e3d1  prefixlen 64  scopeid 0x20<link>
        ether ec:08:6b:1e:f0:b3  txqueuelen 1000  (Ethernet)
        RX packets 682098  bytes 714517869 (714.5 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 472448  bytes 201773965 (201.7 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Linux 默认包含这条 udev 规则,我不需要自己写。但是为什么费力进行这样的命名呢——尤其是看到这样的接口命名这么难使用后?仔细看一下包含在规则中的注释:

对直接或间接插入在 USB 上的网络接口使用基于 MAC 的名称,并且用一个普遍提供的(稳定的)MAC 地址(第二位是 0)。当 ifnames 通过内核命令行或 customizing/disabling 99-default.link(或之前的 80-net-setup-link.rules)被禁用时,不要这样做。

注意,这个规则专为基于 USB 的网络接口设计的。和 PCI 网络接口卡(NIC)不同,USB 设备很可能时不时地被移除或者替换,这意味着无法保证它们的 ID 不变。某一天 ID 可能是 wlan0,第二天却变成了 wlan3。为了避免迷惑应用程序,指定绝对 ID 给设备——就像分配给我的 USB 接口的 ID。

操作 udev 的设置

下一个示例中,我将从 VirtualBox 虚拟机里抓取以太网接口的 MAC 地址和当前接口 ID,然后用这些信息创建一个改变接口 ID 的 udev 新规则。为什么这么做?也许我打算从命令行操作设备,需要输入那么长的名称让人十分烦恼。下面是工作原理。

改变接口 ID 之前,我需要关闭 Netplan 当前的网络配置,促使 Linux 使用新的配置。下面是 /etc/netplan/ 目录下我的当前网络接口配置文件:

$ less /etc/netplan/50-cloud-init.yaml
# This file is generated from information provided by
# the datasource.  Changes to it will not persist across an instance.
# To disable cloud-init's network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    ethernets:
        enp0s3:
            addresses: []
            dhcp4: true
    version: 2

50-cloud-init.yaml 文件包含一个非常基本的接口定义,但是注释中也包含一些禁用配置的重要信息。为此,我将移动到 /etc/cloud/cloud.cfg.d 目录,创建一个名为 /etc/cloud/cloud.cfg.d 的新文件,插入 network: {config: disabled} 字符串。

尽管我只在 Ubuntu 发行版上测试了这个方法,但它应该在任何一个带有 systemd 的 Linux(几乎所有的 Linux 发行版都有 systemd)上都可以工作。不管你使用哪个,都可以很好地了解编写 udev 配置文件并对其进行测试。

接下来,我需要收集一些系统信息。执行 ip 命令,显示我的以太网接口名为 enp0s3,MAC 地址是 08:00:27:1d:28:10

$ ip a
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:1d:28:10 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.115/24 brd 192.168.0.255 scope global dynamic enp0s3

现在,我要在 /etc/udev/rules.d 目录创建一个名为 peristent-net.rules 的新文件。我将给文件一个以较小的数字开头的名称,比如 10:

$ cat /etc/udev/rules.d/10-persistent-network.rules
ACTION=="add", SUBSYSTEM=="net",ATTR{address}=="08:00:27:1d:28:10",NAME="eth3"

数字越小,Linux 越早执行文件,我想要这个文件早点执行。文件被添加时,包含其中的代码就会分配名称 eth3 给网络设备——只要设备的地址能够匹配 08:00:27:1d:28:10,即我的接口的 MAC 地址 。

保存文件并重启计算机后,我的新接口名应该就会生效。我可能需要直接登录虚拟机,使用 dhclient 手动让 Linux 为这个新命名的网络请求一个 IP 地址。在执行下列命令前,可能无法打开 SSH 会话:

$ sudo dhclient eth3

大功告成。现在你能够促使 udev 控制计算机按照你想要的方式指向一个网卡,但更重要的是,你已经有了一些工具,可以弄清楚如何管理任何不听话的设备。


via: https://opensource.com/article/20/2/linux-systemd-udevd

作者:David Clinton 选题:lujun9972 译者:YungeG 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

创建这样一个脚本,当指定的设备插入时触发你的计算机去做一个指定动作。

udev 是一个为你的计算机提供设备事件的 Linux 子系统。通俗来讲就是,当你的计算机上插入了像网卡、外置硬盘(包括 U 盘)、鼠标、键盘、游戏操纵杆和手柄、DVD-ROM 驱动器等等设备时,代码能够检测到它们。这样就能写出很多可能非常有用的实用程序,而它已经很好了,普通用户就可以写出脚本去做一些事情,比如当某个硬盘驱动器插入时,执行某个任务。

这篇文章教你去如何写一个由一些 udev 事件触发的 udev 脚本,比如插入了一个 U 盘。当你理解了 udev 的工作原理,你就可以用它去做各种事情,比如当一个游戏手柄连接后加载一个指定的驱动程序,或者当你用于备份的驱动器连接后,自动执行备份工作。

一个初级的脚本

使用 udev 的最佳方式是从一个小的代码块开始。不要指望从一开始就写出完整的脚本,而是从最简单的确认 udev 触发了某些指定的事件开始。

对于你的脚本,依据你的目标,并不是在任何情况下都能保证你亲眼看到你的脚本运行结果的,因此需要在你的脚本日志中确认它成功触发了。而日志文件通常放在 /var 目录下,但那个目录通常是 root 用户的领地。对于测试目的,可以使用 /tmp,它可以被普通用户访问并且在重启动后就被清除了。

打开你喜欢的文本编辑器,然后输入下面的简单脚本:

#!/usr/bin/bash

echo $date > /tmp/udev.log

把这个脚本放在 /usr/local/bin 或缺省可运行路径的位置中。将它命名为 trigger.sh,并运行 chmod +x 授予可运行权限:

$ sudo mv trigger.sh /usr/local/bin
$ sudo chmod +x /usr/local/bin/trigger.sh

这个脚本没有任何和 udev 有关的事情。当它运行时,这个脚本将在文件 /tmp/udev.log 中放入当前的时间戳。你可以自己测试一下这个脚本:

$ /usr/local/bin/trigger.sh
$ cat /tmp/udev.log
Tue Oct 31 01:05:28 NZDT 2035

接下来让 udev 去触发这个脚本。

唯一设备识别

为了让你的脚本能够被一个设备事件触发,udev 必须要知道在什么情况下调用该脚本。在现实中,你可以通过它的颜色、制造商、以及插入到你的计算机这一事实来识别一个 U 盘。而你的计算机,它需要一系列不同的标准。

udev 通过序列号、制造商、以及提供商 ID 和产品 ID 号来识别设备。由于现在你的 udev 脚本还处于它的生命周期的早期阶段,因此要尽可能地宽泛、非特定和包容。换句话说就是,你希望首先去捕获尽可能多的有效 udev 事件来触发你的脚本。

使用 udevadm monitor 命令你可以实时利用 udev,并且可以看到当你插入不同设备时发生了什么。用 root 权限试一试。

$ su
# udevadm monitor

该监视函数输出接收到的事件:

  • UDEV:在规则处理之后发出 udev 事件
  • KERNEL:内核发送 uevent 事件

udevadm monitor 命令运行时,插入一个 U 盘,你将看到各种信息在你的屏幕上滚动而出。注意那一个 ADD 事件的事件类型。这是你所需要的识别事件类型的一个好方法。

udevadm monitor 命令提供了许多很好的信息,但是你可以使用 udevadm info 命令以更好看的格式来看到它,假如你知道你的 U 盘当前已经位于你的 /dev 树。如果不在这个树下,拔下它并重新插入,然后立即运行这个命令:

$ su -c 'dmesg | tail | fgrep -i sd*'

举例来说,如果那个命令返回 sdb: sdb1,说明内核已经给你的 U 盘分配了 sdb 卷标。

或者,你可以使用 lsblk 命令去查看所有连接到你的系统上的驱动器,包括它的大小和分区。

现在,你的驱动器已经处于你的文件系统中了,你可以使用下面的命令去查看那个设备的相关 udev 信息:

# udevadm info -a -n /dev/sdb | less

这个命令将返回许多信息。现在我们只关心信息中的第一个块。

你的任务是从 udev 的报告中找出能唯一标识那个设备的部分,然后当计算机检测到这些唯一属性时,告诉 udev 去触发你的脚本。

udevadm info 命令处理一个(由设备路径指定的)设备上的报告,接着“遍历”父级设备链。对于找到的大多数设备,它以一个“键值对”格式输出所有可能的属性。你可以写一个规则,从一个单个的父级设备属性上去匹配插入设备的属性。

looking at device '/devices/000:000/blah/blah//block/sdb':
  KERNEL=="sdb"
  SUBSYSTEM=="block"
  DRIVER==""
  ATTR{ro}=="0"
  ATTR{size}=="125722368"
  ATTR{stat}==" 2765 1537 5393"
  ATTR{range}=="16"
  ATTR{discard\_alignment}=="0"
  ATTR{removable}=="1"
  ATTR{blah}=="blah"

一个 udev 规则必须包含来自单个父级设备的一个属性。

父级属性是描述一个设备的最基本的东西,比如它是插入到一个物理端口的东西、或是一个容量多大的东西、或这是一个可移除的设备。

由于 KERNEL 卷标 sdb 可能会由于分配给在它之前插入的其它驱动器而发生变化,因此卷标并不是一个 udev 规则的父级属性的好选择。但是,在做概念论证时你可以使用它。一个事件的最佳候选者是 SUBSYSTEM 属性,它表示那个设备是一个 “block” 系统设备(也就是为什么我们要使用 lsblk 命令来列出设备的原因)。

/etc/udev/rules.d 目录中打开一个名为 80-local.rules 的文件,然后输入如下代码:

SUBSYSTEM=="block", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"

保存文件,拔下你的测试 U 盘,然后重启动系统。

等等,重启动 Linux 机器?

理论上说,你只需要运行 udevadm control —reload 即可,它将重新加载所有规则,但是在我们实验的现阶段,最好要排除可能影响实验结果的所有因素。udev 是非常复杂的,为了不让你躺在床上整晚都在思考为什么这个规则不能正常工作,是因为语法错误吗?还是应该重启动一下。所以,不管 POSIX 自负地告诉你过什么,你都应该去重启动一下。

当你的系统重启动完毕之后,(使用 Ctl+Alt+F3 或类似快捷键)切换到一个文本控制台,并插入你的 U 盘。如果你运行了一个最新的内核,当你插入 U 盘后你或许可以看到一大堆输出。如果看到一个错误信息,比如 “Could not execute /usr/local/bin/trigger.sh”,或许是因为你忘了授予这个脚本可运行的权限。否则你将看到的是,一个设备插入,它得到内核设备分配的一些东西,等等。

现在,见证奇迹的时刻到了。

$ cat /tmp/udev.log
Tue Oct 31 01:35:28 NZDT 2035

如果你在 /tmp/udev.log 中看到了最新的日期和时间,那么说明 udev 已经成功触发了你的脚本。

改进规则做一些有用的事情

现在的问题是使用的规则太通用了。插入一个鼠标、一个 U 盘、或某个人的 U 盘都将盲目地触发这个脚本。现在,我们开始专注于希望触发你的脚本的是确定的某个 U 盘。

实现上述目标的一种方式是使用提供商 ID 和产品 ID。你可以使用 lsusb 命令去得到这些数字。

$ lsusb
Bus 001 Device 002: ID 8087:0024 Slacker Corp. Hub
Bus 002 Device 002: ID 8087:0024 Slacker Corp. Hub
Bus 003 Device 005: ID 03f0:3307 TyCoon Corp.
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 hub
Bus 001 Device 003: ID 13d3:5165 SBo Networks

在这个例子中,TyCoon Corp 前面的 03f0:3307 就表示了提供商 ID 和产品 ID 的属性。你也可以通过 udevadm info -a -n /dev/sdb | grep vendor 的输出来查看这些数字,但是从 lsusb 的输出中可以很容易地一眼找到这些数字。

现在,可以在你的脚本中包含这些属性了。

SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/thumb.sh"

测试它(是的,为了确保不会有来自 udev 的影响因素,我们仍然建议先重新启动一下),它应该会像前面一样工作,现在,如果你插入一个不同公司制造的 U 盘(因为它们的提供商 ID 不一样)、或插入一个鼠标、或插入一个打印机,这个脚本将不会被触发。

继续添加新属性来进一步专注于你希望去触发你的脚本的那个唯一的 U 盘。使用 udevadm info -a -n /dev/sdb 命令,你可以找出像提供商名字、序列号、或产品名这样的东西。

为了保证思路清晰,确保每次只添加一个新属性。我们(和在网上看到的其他人)在 udev 规则中所遇到的大多数错误都是因为一次添加了太多的属性,而奇怪为什么不能正常工作了。逐个测试属性是最安全的作法,这样可以确保 udev 能够成功识别到你的设备。

安全

编写 udev 规则当插入一个驱动器后自动去做一些事情,将带来安全方面的担忧。在我的机器上,我甚至都没有打开自动挂载功能,而基于本文的目的,当设备插入时,脚本和规则可以运行一些命令来做一些事情。

在这里需要记住两个事情。

  1. 聚焦于你的 udev 规则,当你真实地使用它们时,一旦让规则发挥作用将触发脚本。执行一个脚本去盲目地复制数据到你的计算上,或从你的计算机上复制出数据,是一个很糟糕的主意,因为有可能会遇到一个人拿着和你相同品牌的 U 盘插入到你的机器上的情况。
  2. 不要在写了 udev 规则和脚本后忘记了它们的存在。我知道哪个计算上有我的 udev 规则,这些机器一般是我的个人计算机,而不是那些我带着去开会或办公室工作的计算机。一台计算机的 “社交” 程度越高,它就越不能有 udev 规则存在于它上面,因为它将潜在地导致我的数据最终可能会出现在某个人的设备、或某个人的数据中、或在我的设备上出现恶意程序。

换句话说就是,随着一个 GNU 系统提供了一个这么强大的功能,你的任务是小心地如何使用它们的强大功能。如果你滥用它或不小心谨慎地使用它,最终将让你出问题,它非常可能会导致可怕的问题。

现实中的 Udev

现在,你可以确认你的脚本是由 udev 触发的,那么,可以将你的关注点转到脚本功能上了。到目前为止,这个脚本是没有用的,它除了记录脚本已经运行过了这一事实外,再没有做更多的事情。

我使用 udev 去触发我的 U 盘的 自动备份 。这个创意是,将我正在处理的文档的主副本保存在我的 U 盘上(因为我随身带着它,这样就可以随时处理它),并且在我每次将 U 盘插入到那台机器上时,这些主文档将备份回我的计算机上。换句话说就是,我的计算机是备份驱动器,而产生的数据是移动的。源代码是可用的,你可以随意查看 attachup 的代码,以进一步限制你的 udev 的测试示例。

虽然我使用 udev 最多的情况就是这个例子,但是 udev 能抓取很多的事件,像游戏手柄(当连接游戏手柄时,让系统去加载 xboxdrv 模块)、摄像头、麦克风(当指定的麦克风连接时用于去设置输入),所以应该意识到,它能做的事情远比这个示例要多。

我的备份系统的一个简化版本是由两个命令组成的一个过程:

SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", SYMLINK+="safety%n"
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"

第一行使用属性去检测我的 U 盘,这在前面已经讨论过了,接着在设备树中为我的 U 盘分配一个符号链接,给它分配的符号连接是 safety%n。这个 %n 是一个 udev 宏,它是内核分配给这个设备的任意数字,比如 sdb1、sdb2、sdb3、等等。因此 %n 应该是 1 或 2 或 3。

这将在 dev 树中创建一个符号链接,因此它不会干涉插入一个设备的正常过程。这意味着,如果你在自动挂载设备的桌面环境中使用它,将不会出现问题。

第二行运行这个脚本。

我的备份脚本如下:

#!/usr/bin/bash

mount /dev/safety1 /mnt/hd
sleep 2
rsync -az /mnt/hd/ /home/seth/backups/ && umount /dev/safety1

这个脚本使用符号链接,这将避免出现 udev 命名导致的意外情况(例如,假设一个命名为 DISK 的 U 盘已经插入到我的计算机上,而我插入的其它 U 盘恰好名字也是 DISK,那么第二个 U 盘的卷标将被命名为 DISK_,这将导致我的脚本不会正常运行),它在我喜欢的挂载点 /mnt/hd 上挂载了 safety1(驱动器的第一个分区)。

一旦 safely 挂载之后,它将使用 rsync 将驱动器备份到我的备份文件夹(我真实使用的脚本用的是 rdiff-backup,而你可以使用任何一个你喜欢的自动备份解决方案)。

udev 让你的设备你做主

udev 是一个非常灵活的系统,它可以让你用其它系统很少敢提供给用户的方式去定义规则和功能。学习它,使用它,去享受 POSIX 的强大吧。

本文内容来自 Slackermedia Handbook,它以 GNU Free Documentation License 1.3 许可证授权使用。


via: https://opensource.com/article/18/11/udev

作者:Seth Kenlon 选题:lujun9972 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

名词缩写:

  • API 应用程序接口 Application Program Interface
  • ABI 应用系统二进制接口 Application Binary Interface

设备驱动是操作系统的一部分,它能够通过一些特定的编程接口便于硬件设备的使用,这样软件就可以控制并且运行那些设备了。因为每个驱动都对应不同的操作系统,所以你就需要不同的 Linux、Windows 或 Unix 设备驱动,以便能够在不同的计算机上使用你的设备。这就是为什么当你雇佣一个驱动开发者或者选择一个研发服务商提供者的时候,查看他们为各种操作系统平台开发驱动的经验是非常重要的。

驱动开发的第一步是理解每个操作系统处理它的驱动的不同方式、底层驱动模型、它使用的架构、以及可用的开发工具。例如,Linux 驱动程序模型就与 Windows 非常不同。虽然 Windows 提倡驱动程序开发和操作系统开发分别进行,并通过一组 ABI 调用来结合驱动程序和操作系统,但是 Linux 设备驱动程序开发不依赖任何稳定的 ABI 或 API,所以它的驱动代码并没有被纳入内核中。每一种模型都有自己的优点和缺点,但是如果你想为你的设备提供全面支持,那么重要的是要全面的了解它们。

在本文中,我们将比较 Windows 和 Linux 设备驱动程序,探索不同的架构,API,构建开发和分发,希望让您比较深入的理解如何开始为每一个操作系统编写设备驱动程序。

1. 设备驱动架构

Windows 设备驱动程序的体系结构和 Linux 中使用的不同,它们各有优缺点。差异主要受以下原因的影响:Windows 是闭源操作系统,而 Linux 是开源操作系统。比较 Linux 和 Windows 设备驱动程序架构将帮助我们理解 Windows 和 Linux 驱动程序背后的核心差异。

1.1. Windows 驱动架构

虽然 Linux 内核分发时带着 Linux 驱动,而 Windows 内核则不包括设备驱动程序。与之不同的是,现代 Windows 设备驱动程序编写使用 Windows 驱动模型(WDM),这是一种完全支持即插即用和电源管理的模型,所以可以根据需要加载和卸载驱动程序。

处理来自应用的请求,是由 Windows 内核的中被称为 I/O 管理器的部分来完成的。I/O 管理器的作用是是转换这些请求到 I/O 请求数据包 IO Request Packets (IRP),IRP 可以被用来在驱动层识别请求并且传输数据。

Windows 驱动模型 WDM 提供三种驱动, 它们形成了三个层:

  • 过滤 Filter 驱动提供关于 IRP 的可选附加处理。
  • 功能 Function 驱动是实现接口和每个设备通信的主要驱动。
  • 总线 Bus 驱动服务不同的配适器和不同的总线控制器,来实现主机模式控制设备。

一个 IRP 通过这些层就像它们经过 I/O 管理器到达底层硬件那样。每个层能够独立的处理一个 IRP 并且把它们送回 I/O 管理器。在硬件底层中有硬件抽象层(HAL),它提供一个通用的接口到物理设备。

1.2. Linux 驱动架构

相比于 Windows 设备驱动,Linux 设备驱动架构根本性的不同就是 Linux 没有一个标准的驱动模型也没有一个干净分隔的层。每一个设备驱动都被当做一个能够自动的从内核中加载和卸载的模块来实现。Linux 为即插即用设备和电源管理设备提供一些方式,以便那些驱动可以使用它们来正确地管理这些设备,但这并不是必须的。

模式输出那些它们提供的函数,并通过调用这些函数和传入随意定义的数据结构来沟通。请求来自文件系统或网络层的用户应用,并被转化为需要的数据结构。模块能够按层堆叠,在一个模块进行处理之后,另外一个再处理,有些模块提供了对一类设备的公共调用接口,例如 USB 设备。

Linux 设备驱动程序支持三种设备:

  • 实现一个字节流接口的 字符 Character 设备。
  • 用于存放文件系统和处理多字节数据块 IO 的 Block 设备。
  • 用于通过网络传输数据包的 网络 Network 接口。

Linux 也有一个硬件抽象层(HAL),它实际扮演了物理硬件的设备驱动接口。

2. 设备驱动 API

Linux 和 Windows 驱动 API 都属于事件驱动类型:只有当某些事件发生的时候,驱动代码才执行——当用户的应用程序希望从设备获取一些东西,或者当设备有某些请求需要告知操作系统。

2.1. 初始化

在 Windows 上,驱动被表示为 DriverObject 结构,它在 DriverEntry 函数的执行过程中被初始化。这些入口点也注册一些回调函数,用来响应设备的添加和移除、驱动卸载和处理新进入的 IRP。当一个设备连接的时候,Windows 创建一个设备对象,这个设备对象在设备驱动后面处理所有应用请求。

相比于 Windows,Linux 设备驱动生命周期由内核模块的 module_initmodule_exit 函数负责管理,它们分别用于模块的加载和卸载。它们负责注册模块来通过使用内核接口来处理设备的请求。这个模块需要创建一个设备文件(或者一个网络接口),为其所希望管理的设备指定一个数字识别号,并注册一些当用户与设备文件交互的时候所使用的回调函数。

2.2. 命名和声明设备

在 Windows 上注册设备

Windows 设备驱动在新连接设备时是由回调函数 AddDevice 通知的。它接下来就去创建一个 设备对象 device object ,用于识别该设备的特定的驱动实例。取决于驱动的类型,设备对象可以是 物理设备对象 Physical Device Object (PDO), 功能设备对象 Function Device Object (FDO),或者 过滤设备对象 Filter Device Object (FIDO)。设备对象能够堆叠,PDO 在底层。

设备对象在这个设备连接在计算机期间一直存在。DeviceExtension 结构能够被用于关联到一个设备对象的全局数据。

设备对象可以有如下形式的名字 \Device\DeviceName,这被系统用来识别和定位它们。应用可以使用 CreateFile API 函数来打开一个有上述名字的文件,获得一个可以用于和设备交互的句柄。

然而,通常只有 PDO 有自己的名字。未命名的设备能够通过设备级接口来访问。设备驱动注册一个或多个接口,以 128 位全局唯一标识符(GUID)来标示它们。用户应用能够使用已知的 GUID 来获取一个设备的句柄。

在 Linux 上注册设备

在 Linux 平台上,用户应用通过文件系统入口访问设备,它通常位于 /dev 目录。在模块初始化的时候,它通过调用内核函数 register_chrdev 创建了所有需要的入口。应用可以发起 open 系统调用来获取一个文件描述符来与设备进行交互。这个调用后来被发送到回调函数,这个调用(以及将来对该返回的文件描述符的进一步调用,例如 readwriteclose)会被分配到由该模块安装到 file_operations 或者 block_device_operations这样的数据结构中的回调函数。

设备驱动模块负责分配和保持任何需要用于操作的数据结构。传送进文件系统回调函数的 file 结构有一个 private_data 字段,它可以被用来存放指向具体驱动数据的指针。块设备和网络接口 API 也提供类似的字段。

虽然应用使用文件系统的节点来定位设备,但是 Linux 在内部使用一个 主设备号 major numbers 次设备号 minor numbers 的概念来识别设备及其驱动。主设备号被用来识别设备驱动,而次设备号由驱动使用来识别它所管理的设备。驱动为了去管理一个或多个固定的主设备号,必须首先注册自己或者让系统来分配未使用的设备号给它。

目前,Linux 为 主次设备对 major-minor pairs 使用一个 32 位的值,其中 12 位分配主设备号,并允许多达 4096 个不同的设备。主次设备对对于字符设备和块设备是不同的,所以一个字符设备和一个块设备能使用相同的设备对而不导致冲突。网络接口是通过像 eth0 的符号名来识别,这些又是区别于主次设备的字符设备和块设备的。

2.3. 交换数据

Linux 和 Windows 都支持在用户级应用程序和内核级驱动程序之间传输数据的三种方式:

  • 缓冲型输入输出 Buffered Input-Output 它使用由内核管理的缓冲区。对于写操作,内核从用户空间缓冲区中拷贝数据到内核分配的缓冲区,并且把它传送到设备驱动中。读操作也一样,由内核将数据从内核缓冲区中拷贝到应用提供的缓冲区中。
  • 直接型输入输出 Direct Input-Output 它不使用拷贝功能。代替它的是,内核在物理内存中钉死一块用户分配的缓冲区以便它可以一直留在那里,以便在数据传输过程中不被交换出去。
  • 内存映射 Memory mapping 它也能够由内核管理,这样内核和用户空间应用就能够通过不同的地址访问同样的内存页。
Windows 上的驱动程序 I/O 模式

支持缓冲型 I/O 是 WDM 的内置功能。缓冲区能够被设备驱动通过在 IRP 结构中的 AssociatedIrp.SystemBuffer 字段访问。当需要和用户空间通讯的时候,驱动只需从这个缓冲区中进行读写操作。

Windows 上的直接 I/O 由 内存描述符列表 memory descriptor lists (MDL)介导。这种半透明的结构是通过在 IRP 中的 MdlAddress 字段来访问的。它们被用来定位由用户应用程序分配的缓冲区的物理地址,并在 I/O 请求期间钉死不动。

在 Windows 上进行数据传输的第三个选项称为 METHOD_NEITHER。 在这种情况下,内核需要传送用户空间的输入输出缓冲区的虚拟地址给驱动,而不需要确定它们有效或者保证它们映射到一个可以由设备驱动访问的物理内存地址。设备驱动负责处理这些数据传输的细节。

Linux 上的驱动程序 I/O 模式

Linux 提供许多函数例如,clear_usercopy_to_userstrncpy_from_user 和一些其它的用来在内核和用户内存之间进行缓冲区数据传输的函数。这些函数保证了指向数据缓存区指针的有效,并且通过在内存区域之间安全地拷贝数据缓冲区来处理数据传输的所有细节。

然而,块设备的驱动对已知大小的整个数据块进行操作,它可以在内核和用户地址区域之间被快速移动而不需要拷贝它们。这种情况是由 Linux 内核来自动处理所有的块设备驱动。块请求队列处理传送数据块而不用多余的拷贝,而 Linux 系统调用接口来转换文件系统请求到块请求中。

最终,设备驱动能够从内核地址区域分配一些存储页面(不可交换的)并且使用 remap_pfn_range 函数来直接映射这些页面到用户进程的地址空间。然后应用能获取这些缓冲区的虚拟地址并且使用它来和设备驱动交流。

3. 设备驱动开发环境

3.1. 设备驱动框架

Windows 驱动程序工具包

Windows 是一个闭源操作系统。Microsoft 提供 Windows 驱动程序工具包以方便非 Microsoft 供应商开发 Windows 设备驱动。工具包中包含开发、调试、检验和打包 Windows 设备驱动等所需的所有内容。

Windows 驱动模型 Windows Driver Model (WDM)为设备驱动定义了一个干净的接口框架。Windows 保持这些接口的源代码和二进制的兼容性。编译好的 WDM 驱动通常是前向兼容性:也就是说,一个较旧的驱动能够在没有重新编译的情况下在较新的系统上运行,但是它当然不能够访问系统提供的新功能。但是,驱动不保证后向兼容性。

Linux 源代码

和 Windows 相对比,Linux 是一个开源操作系统,因此 Linux 的整个源代码是用于驱动开发的 SDK。没有驱动设备的正式框架,但是 Linux 内核包含许多提供了如驱动注册这样的通用服务的子系统。这些子系统的接口在内核头文件中描述。

尽管 Linux 有定义接口,但这些接口在设计上并不稳定。Linux 不提供有关前向和后向兼容的任何保证。设备驱动对于不同的内核版本需要重新编译。没有稳定性的保证可以让 Linux 内核进行快速开发,因为开发人员不必去支持旧的接口,并且能够使用最好的方法解决手头的这些问题。

当为 Linux 写 树内 in-tree (指当前 Linux 内核开发主干)驱动程序时,这种不断变化的环境不会造成任何问题,因为它们作为内核源代码的一部分,与内核本身同步更新。然而,闭源驱动必须单独开发,并且在 树外 out-of-tree ,必须维护它们以支持不同的内核版本。因此,Linux 鼓励设备驱动程序开发人员在树内维护他们的驱动。

3.2. 为设备驱动构建系统

Windows 驱动程序工具包为 Microsoft Visual Studio 添加了驱动开发支持,并包括用来构建驱动程序代码的编译器。开发 Windows 设备驱动程序与在 IDE 中开发用户空间应用程序没有太大的区别。Microsoft 提供了一个企业 Windows 驱动程序工具包,提供了类似于 Linux 命令行的构建环境。

Linux 使用 Makefile 作为树内和树外系统设备驱动程序的构建系统。Linux 构建系统非常发达,通常是一个设备驱动程序只需要少数行就产生一个可工作的二进制代码。开发人员可以使用任何 IDE,只要它可以处理 Linux 源代码库和运行 make ,他们也可以很容易地从终端手动编译驱动程序。

3.3. 文档支持

Windows 对于驱动程序的开发有良好的文档支持。Windows 驱动程序工具包包括文档和示例驱动程序代码,通过 MSDN 可获得关于内核接口的大量信息,并存在大量的有关驱动程序开发和 Windows 底层的参考和指南。

Linux 文档不是描述性的,但整个 Linux 源代码可供驱动开发人员使用缓解了这一问题。源代码树中的 Documentation 目录描述了一些 Linux 的子系统,但是有几本书介绍了关于 Linux 设备驱动程序开发和 Linux 内核概览,它们更详细。

Linux 没有提供设备驱动程序的指定样本,但现有生产级驱动程序的源代码可用,可以用作开发新设备驱动程序的参考。

3.4. 调试支持

Linux 和 Windows 都有可用于追踪调试驱动程序代码的日志机制。在 Windows 上将使用 DbgPrint 函数,而在 Linux 上使用的函数称为 printk。然而,并不是每个问题都可以通过只使用日志记录和源代码来解决。有时断点更有用,因为它们允许检查驱动代码的动态行为。交互式调试对于研究崩溃的原因也是必不可少的。

Windows 通过其内核级调试器 WinDbg 支持交互式调试。这需要通过一个串行端口连接两台机器:一台计算机运行被调试的内核,另一台运行调试器和控制被调试的操作系统。Windows 驱动程序工具包包括 Windows 内核的调试符号,因此 Windows 的数据结构将在调试器中部分可见。

Linux 还支持通过 KDBKGDB 进行的交互式调试。调试支持可以内置到内核,并可在启动时启用。之后,可以直接通过物理键盘调试系统,或通过串行端口从另一台计算机连接到它。KDB 提供了一个简单的命令行界面,这是唯一的在同一台机器上来调试内核的方法。然而,KDB 缺乏源代码级调试支持。KGDB 通过串行端口提供了一个更复杂的接口。它允许使用像 GDB 这样标准的应用程序调试器来调试 Linux 内核,就像任何其它用户空间应用程序一样。

4. 设备驱动分发

4.1. 安装设备驱动

在 Windows 上安装的驱动程序,是由被称为为 INF 的文本文件描述的,通常存储在 C:\Windows\INF 目录中。这些文件由驱动供应商提供,并且定义哪些设备由该驱动程序服务,哪里可以找到驱动程序的二进制文件,和驱动程序的版本等。

当一个新设备插入计算机时,Windows 通过查看已经安装的驱动程序并且选择适当的一个加载。当设备被移除的时候,驱动会自动卸载它。

在 Linux 上,一些驱动被构建到内核中并且保持永久的加载。非必要的驱动被构建为内核模块,它们通常是存储在 /lib/modules/kernel-version 目录中。这个目录还包含各种配置文件,如 modules.dep,用于描述内核模块之间的依赖关系。

虽然 Linux 内核可以在自身启动时加载一些模块,但通常模块加载由用户空间应用程序监督。例如,init 进程可能在系统初始化期间加载一些模块,udev 守护程序负责跟踪新插入的设备并为它们加载适当的模块。

4.2. 更新设备驱动

Windows 为设备驱动程序提供了稳定的二进制接口,因此在某些情况下,无需与系统一起更新驱动程序二进制文件。任何必要的更新由 Windows Update 服务处理,它负责定位、下载和安装适用于系统的最新版本的驱动程序。

然而,Linux 不提供稳定的二进制接口,因此有必要在每次内核更新时重新编译和更新所有必需的设备驱动程序。显然,内置在内核中的设备驱动程序会自动更新,但是树外模块会产生轻微的问题。 维护最新的模块二进制文件的任务通常用 DKMS 来解决:这是一个当安装新的内核版本时自动重建所有注册的内核模块的服务。

4.3. 安全方面的考虑

所有 Windows 设备驱动程序在 Windows 加载它们之前必须被数字签名。在开发期间可以使用自签名证书,但是分发给终端用户的驱动程序包必须使用 Microsoft 信任的有效证书进行签名。供应商可以从 Microsoft 授权的任何受信任的证书颁发机构获取 软件出版商证书 Software Publisher Certificate 。然后,此证书由 Microsoft 交叉签名,并且生成的交叉证书用于在发行之前签署驱动程序包。

Linux 内核也能配置为在内核模块被加载前校验签名,并禁止不可信的内核模块。被内核所信任的公钥集在构建时是固定的,并且是完全可配置的。由内核执行的检查,这个检查严格性在构建时也是可配置的,范围从简单地为不可信模块发出警告,到拒绝加载有效性可疑的任何东西。

5. 结论

如上所示,Windows 和 Linux 设备驱动程序基础设施有一些共同点,例如调用 API 的方法,但更多的细节是相当不同的。最突出的差异源于 Windows 是由商业公司开发的封闭源操作系统这个事实。这使得 Windows 上有好的、文档化的、稳定的驱动 ABI 和正式框架,而在 Linux 上,更多的是源代码做了一个有益的补充。文档支持也在 Windows 环境中更加发达,因为 Microsoft 具有维护它所需的资源。

另一方面,Linux 不会使用框架来限制设备驱动程序开发人员,并且内核和产品级设备驱动程序的源代码可以在需要的时候有所帮助。缺乏接口稳定性也有其作用,因为它意味着最新的设备驱动程序总是使用最新的接口,内核本身承载较小的后向兼容性负担,这带来了更干净的代码。

了解这些差异以及每个系统的具体情况是为您的设备提供有效的驱动程序开发和支持的关键的第一步。我们希望这篇文章对 Windows 和 Linux 设备驱动程序开发做的对比,有助于您理解它们,并在设备驱动程序开发过程的研究中,将此作为一个伟大的起点。


via: http://xmodulo.com/linux-vs-windows-device-driver-model.html

作者:Dennis Turpitka 译者:FrankXinqi &YangYang 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

来自赛门铁克研究员的消息,这个病毒通过2012年出现的 PHP 漏洞传播

据美国国际数据集团(IDG)的新闻 —— 一个新的蠕虫病毒将目标指向那些运行了 Linux 和 PHP 的 x86 架构计算机,其变种还会对运行在其他芯片架构上的设备(诸如家用路由器和机顶盒)造成威胁。

根据赛门铁克研究员的介绍,这种病毒利用 php-cgi 上的一个漏洞进行传播,这个 php-cgi 组件的功能是允许 PHP 代码在通用网关接口(CGI)的配置环境下被执行。此漏洞的代号为 CVE-2012-1823(通过这个漏洞,攻击者可以远程执行任意代码,所以这种漏洞又叫“远程任意代码执行漏洞” —— 译者注)。2012年5月份,PHP 5.4.3 和 PHP 5.3.13 这两个版本已经打上补丁修复了这个漏洞。

这个赛门铁克的研究员在博客中写道:这个名为“Linux.Darlloz”的新蠕虫病毒基于去年10月份放出的 PoC 代码(PoC:proof of concept,概念验证。利用目标计算机的漏洞,为对其进行攻击而设计的代码称为 exploit,而一个没有充分利用漏洞的 exploit,就是 PoC —— 译者注)。

“在传播过程中,这段蠕虫代码会随机产生 IP 地址,通过特殊途径,利用普通的用户名密码发送 HTTP POST 请求,探测漏洞”,研究员解释道:“如果一个目标没有打上 CVE-2012-1823 的补丁,这台机器就会从病毒服务器下载蠕虫病毒,之后寻找下一个目标。”

这个唯一的蠕虫变种目前为止只感染了 x86 系统,这是因为这个病毒的二进制格式为 Intel 架构下的 ELF (Executable and Linkable Format)格式。

然而这个研究员警告说,黑客也为其他架构开发了病毒,包括 ARM,PPC,MIPS 和 MIPSEL。

这些计算机架构主要用于诸如家用路由器、网络监视器、机顶盒以及其他嵌入式设备。

“攻击者显然试图在最大范围内感染运行 Linux 的设备”,研究员又说:“然而我们还没有证实他们有没有攻击非 PC 设备。”

很多嵌入式设备的固件都使用 Linux 作为操作系统,并且使用 PHP 作为 Web 服务管理界面。这些设备比 PC 机 或服务器更容易被攻陷,因为它们不会经常更新软件。

在嵌入式设备为一个漏洞打上补丁,从来都不是件容易的事。很多厂商都不会定期公布更新信息,而当他们公布时,用户也不会被告知说这些更新解决了哪些安全问题。

并且,在嵌入式设备上更新软件比在计算机上需要更多的工作,以及更多的技术知识。用户需要知道哪些网站能提供这些更新,然后下载下来,通过 Web 界面更新到他们的设备中。

“很多用户也许压根就不知道他们家里或办公室的设备存在漏洞,”啰嗦的研究员说:“我们面临的另一个问题是,即使用户注意到他们用的是有漏洞的设备,这些设备的供应商却没有提供补丁,原因是技术落后,或者完全就是硬件的限制:内存不足,或 CPU 太慢,不足以支持这些软件的新版本。”

“为了保护他们的设备免受蠕虫感染,用户需要确认这些设备是否运行在最新的固件版本上,必要的话,升级固件,设置高强度的管理员密码,在防火墙那儿,或任何独立的设备那儿,屏蔽任何对 -/cgi-bin/php, -/cgi-bin/php5, -/cgi-bin/php-cgi, -/cgi-bin/php.cgi and -/cgi-bin/php4 的 HTTP POST 请求。”没完没了的赛门铁克研究员说道。


via: http://www.computerworld.com/s/article/9244409/This_new_worm_targets_Linux_PCs_and_embedded_devices?taxonomyId=122

译者:bazz2 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

下面的教程会指导所有的Linux使用者如何在系统上安装SSH,以便通过安卓智能手机远程访问他们的电脑。

如今我们所有人都拥有一台平板或触屏手机,我们经常使用它们在深夜里看电影或电视节目,听歌或者阅读一本好书。你可以把这篇文章称作是为那些懒人们准备的教程,他们在大晚上会因为太过疲惫而懒得去开启他们电脑上的某些程序,更懒得去移动、删除、复制或重命名某些文件,甚至关掉PC。

的确,已经有各种各样的远程桌面解决方案,但是许多方案费用很高,或者实现效果很糟糕,无法像预期一样运行,逼得你最终还是得去电脑上做你原本想做的事情。

在这个教程里面,我们将使用一种简单、安全、高效的协议,它被称为SSH (Secure SHell),它很容易从默认的软件仓库中安装(在Arch linx中是openssh,在Ubuntu中时openssh-server)。

配置SSH服务器

在安装完成后,你需要为SSH服务器进行基本配置。为此,你需要使用文本编辑器编辑/etc/ssh/sshd\_config这个文件。

1.在文件尾部添加下面一行(下面的yourusername使用你的Linux机器上实际存在的用户名代替)

AllowUsers yourusername

2.取消"#PermitRootLogin"这行注释,把"no"替换成"yes":

PermitRootLogin no

3.为了安全起见,你需要修改SSH连接默认的22端口到一个更大编号的端口,譬如在我们的例子中是55441 (建议不要跟着我使用55441,这是我选择的,你可以找另一个四位或者五位数字)。因此,取消注释并编辑"#Port 22"如下(译注:你可以选择大于1024,小于65535的其它端口,前提是没有被其它服务所占用,为什么不试试你的幸运数字?):

Port 55441 

开启SSH服务器

在Ubuntu上,SSH服务通过下面的命令启动:

sudo /etc/init.d/ssh start 

当你每次修改上述配置文件时,都需要通过下面的命令重启:

sudo /etc/init.d/ssh restart 

在Arch Linux上,你可以使用下面的命令启动SSH服务:

sudo systemctl start sshd 

配置安卓设备上的SSH客户端

JuiceSSH似乎是安卓上最好的SSH客户端之一,而且是免费的。此外,如果你认为它的功能简单,也可以花费少量的钱得到更多高级的特性,譬如亚马逊 AWS/EC2 集成,团队协作,以及更多其它的特性。

一旦软件安装完毕,运行它,然后你会要求输入一个加密的密码以保证安全连接的安全。这个密码由AES-256进行加密,因此除非你的设备被偷,否则没有人能够获取他们。

现在,添加一个新连接,选择名称,你的电脑的IP地址,上面设定的端口号和一个需要被创建的身份。

这就是我的Arch Linux机器,可以通过我的安卓平板上的JuiceSSH客户端访问到。如果在这个教程中你遇到问题,请在下面进行评论。


via: http://news.softpedia.com/news/How-to-Control-Your-Linux-PC-with-an-Android-Device-396004.shtml

译者:KayGuoWhu 校对:Caroline

本文由 LCTT 原创翻译,Linux中国 荣誉推出

为了修复一些 bug 从而增强系统稳定性,在连着跳票几周后,最新的 Fedora Linux 终于要在12月份出来了。Fedora 是一款为 RHEL 做软件测试用的开源操作系统(即 Red Hat 公司会将那些在 Fedora 系统运行稳定的软件版本吸收到 RHEL 系统中 —— 译者注),这次更新将会带来什么样的变化呢?让我们来看一下。

早在10月末,Fedora 项目就宣布 Fedora 20 正式版要延迟一周发布(Fedora 项目计划在每年的4月和10月发布新的版本,但几乎每次都在跳票,所以见怪不怪了 —— 译者的吐槽)。在11月1号,Fedora 项目又宣布将 Fedora 20 推迟一周。而现在的计划再次变成11月12日发布 Beta 版,12月17日发布正式版。

这个三连跳不禁又要让 Fedora 用户伤心一阵子了,但开发者说不断的修改发布计划,是为了让 Fedora 以更完美的姿态出现在大众眼前。(Fedora 这种追求完美的策略,与 Canonical 旗下的 Ubuntu 追求效率的策略形成鲜明的对比。Ubuntu 更愿意按计划发布新版本,这有助于它抢占 Linux 市场。)

抛下进度不提,Fedora 用户还是可以对这次最新最棒的版本更新抱有很大期望的。比如为了将桌面轻量化,Fedora 20 不再默认安装一些软件,像 syslog 和 sendmail。

NetworkManager 增加了一些很有用的功能,比如支持网桥和网卡绑定,在以前,要实现这两个酷酷的功能,需要通过复杂的命令行操作。在布署复杂的网络环境,特别是在云计算和软件定义网络(SDN)中,现在的 Fedora 对用户来说更有吸引力了。

Fedora 20 的目标是完全支持 ARM 设备(特别是 ARM7hl),这个目标能让它在移动终端和一些新兴硬件产品占有一席之地。

这些改进能让 Fedora 20 成为本季度最引人注目的 Linux 桌面发行版 —— 特别是在上月发布的 Unbuntu 13.10 的衬托下。Ubuntu 13.10 为桌面用户带来极少的更新。(它更多的是针对服务器和云的更新。)

由于 Red Hat 公司会从 Fedora 中挑选稳定可靠的软件版本并吸收到 RHEL 中,所以 Fedora 社区里会有很多高端用户。而对于社区中的这些用户来说,本次更新也是有重要意义的。他们应该在12月(如果不再跳票)就可以拿到 Fedora 20 正式版了,并且会期待着 Red Hat 公司什么时候能将这些新特性加入到 RHEL 中。


via: http://thevarguy.com/open-source-application-software-companies/red-hat-fedora-20-linux-new-networking-arm-features

译者:bazz2 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出