在你使用 Java 编写软件时实现持久化配置。当你编写一个应用时，你通常都会希望用户能够定制化他们和应用交互的方式，以及应用与系统进行交互的方式。这种方式通常被称为 “ 偏好 preference ” 或者 “ 设置 setting ”，它们被保存在一个 “偏好文件” 或者 “配置文件” 中，有时也直接简称为 “ 配置 config ”。配置文件可以有很多种格式，包括 INI、JSON、YAML 和 XML。每一种编程语言解析这些格式的方式都不同。本文主要讨论，当你在使用 Java 编程语言 来编写软件时，实现持久化配置的方式。选择一个格式编写配置文件是一件相当复杂的事情。我曾经试过把配置项使用逗号分隔保存在一个文本文件里，也试过把配置项保存在非常详细的 YAML 和 XML 中。对于配置文件来说，最重要是要有一致性和规律性，它们使你可以简单快速地编写代码，从配置文件中解析出数据；同时，当用户决定要做出修改时，很方便地保存和更新配置。目前有 几种流行的配置文件格式。对于大多数常见的配置文件格式，Java 都有对应的 库 library 。在本文中，我将使用 XML 格式。对于一些项目，你可能会选择使用 XML，因为它的一个突出特点是能够为包含的数据提供大量相关的元数据，而在另外一些项目中，你可能会因为 XML 的冗长而不选择它。在 Java 中使用 XML 是非常容易的，因为它默认包含了许多健壮的 XML 库。XML 基础讨论 XML 可是一个大话题。我有一本关于 XML 的书，它有超过 700 页的内容。幸运的是，使用 XML 并不需要非常了解它的诸多特性。就像 HTML 一样，XML 是一个带有开始和结束标记的分层标记语言，每一个标记（标签）内可以包含零个或更多数据。下面是一个 XML 的简单示例片段：<xml> <node> <element>Penguin</element> </node> </xml> 在这个 自我描述的 self-descriptive 例子中，XML 解析器使用了以下几个概念： 文档 Document ：<xml> 标签标志着一个 文档 的开始，</xml> 标签标志着这个文档的结束。 节点 Node ：<node> 标签代表了一个 节点。 元素 Element ：<element>Penguin</element> 中，从开头的 < 到最后的 > 表示了一个 元素。 内容 Content ： 在 <element> 元素里，字符串 Penguin 就是 内容。不管你信不信，只要了解了以上几个概念，你就可以开始编写、解析 XML 文件了。创建一个示例配置文件要学习如何解析 XML 文件，只需要一个极简的示例文件就够了。假设现在有一个配置文件，里面保存的是关于一个图形界面窗口的属性：<xml> <window> <theme>Dark</theme> <fullscreen>0</fullscreen> <icons>Tango</icons> </window> </xml> 创建一个名为 ~/.config/DemoXMLParser 的目录：$ mkdir ~/.config/DemoXMLParser 在 Linux 中，~/.config 目录是存放配置文件的默认位置，这是在 自由桌面工作组 的规范中定义的。如果你正在使用一个不遵守 自由桌面工作组 Freedesktop 标准的操作系统，你也仍然可以使用这个目录，只不过你需要自己创建这些目录了。 复制 XML 的示例配置文件，粘贴并保存为 ~/.config/DemoXMLParser/myconfig.xml 文件。使用 Java 解析 XML如果你是 Java 的初学者，你可以先阅读我写的 面向 Java 入门开发者的 7 个小技巧。一旦你对 Java 比较熟悉了，打开你最喜爱的集成开发工具（IDE），创建一个新工程。我会把我的新工程命名为 myConfigParser。刚开始先不要太关注依赖导入和异常捕获这些，你可以先尝试用 javax 和 java.io 包里的标准 Java 扩展来实例化一个解析器。如果你使用了 IDE，它会提示你导入合适的依赖。如果没有，你也可以在文章稍后的部分找到完整的代码，里面就有完整的依赖列表。Path configPath = Paths.get(System.getProperty("user.home"), ".config", "DemoXMLParser"); File configFile = new File(configPath.toString(), "myconfig.xml"); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = null; builder = factory.newDocumentBuilder(); Document doc = null; doc = builder.parse(configFile); doc.getDocumentElement().normalize(); 这段示例代码使用了 java.nio.Paths 类来找到用户的主目录，然后在拼接上默认配置文件的路径。接着，它用 java.io.File 类来把配置文件定义为一个 File 对象。紧接着，它使用了 javax.xml.parsers.DocumentBuilder 和 javax.xml.parsers.DocumentBuilderFactory 这两个类来创建一个内部的文档构造器，这样 Java 程序就可以导入并解析 XML 数据了。最后，Java 创建一个叫 doc 的文档对象，并且把 configFile 文件加载到这个对象里。通过使用 org.w3c.dom 包，它读取并规范化了 XML 数据。基本上就是这样啦。理论上来讲，你已经完成了数据解析的工作。可是，如果你不能够访问数据的话，数据解析也没有多少用处嘛。所以，就让我们再来写一些查询，从你的配置中读取重要的属性值吧。使用 Java 访问 XML 的值从你已经读取的 XML 文档中获取数据，其实就是要先找到一个特定的节点，然后遍历它包含的所有元素。通常我们会使用多个循环语句来遍历节点中的元素，但是为了保持代码可读性，我会尽可能少地使用循环语句：NodeList nodes = doc.getElementsByTagName("window"); for (int i = 0; i < nodes.getLength(); i++) { Node mynode = nodes.item(i); System.out.println("Property = " + mynode.getNodeName()); if (mynode.getNodeType() == Node.ELEMENT_NODE) { Element myelement = (Element) mynode; System.out.println("Theme = " + myelement.getElementsByTagName("theme").item(0).getTextContent()); System.out.println("Fullscreen = " + myelement.getElementsByTagName("fullscreen").item(0).getTextContent()); System.out.println("Icon set = " + myelement.getElementsByTagName("icons").item(0).getTextContent()); } } 这段示例代码使用了 org.w3c.dom.NodeList 类，创建了一个名为 nodes 的 NodeList 对象。这个对象包含了所有名字匹配字符串 window 的子节点，实际上这样的节点只有一个，因为本文的示例配置文件中只配置了一个。紧接着，它使用了一个 for 循环来遍历 nodes 列表。具体过程是：根据节点出现的顺序逐个取出，然后交给一个 if-then 子句处理。这个 if-then 子句创建了一个名为 myelement 的 Element 对象，其中包含了当前节点下的所有元素。你可以使用例如 getChildNodes 和 getElementById 方法来查询这些元素，项目中还 记录了 其他查询方法。在这个示例中，每个元素就是配置的键。而配置的值储存在元素的内容中，你可以使用 .getTextContent 方法来提取出配置的值。在你的 IDE 中运行代码（或者运行编译后的二进制文件）：$ java ./DemoXMLParser.java Property = window Theme = Dark Fullscreen = 0 Icon set = Tango 下面是完整的代码示例：package myConfigParser; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; public class ConfigParser { public static void main(String[] args) { Path configPath = Paths.get(System.getProperty("user.home"), ".config", "DemoXMLParser"); File configFile = new File(configPath.toString(), "myconfig.xml"); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = null; try { builder = factory.newDocumentBuilder(); } catch (ParserConfigurationException e) { e.printStackTrace(); } Document doc = null; try { doc = builder.parse(configFile); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } doc.getDocumentElement().normalize(); NodeList nodes = doc.getElementsByTagName("window"); for (int i = 0; i < nodes.getLength(); i++) { Node mynode = nodes.item(i); System.out.println("Property = " + mynode.getNodeName()); if (mynode.getNodeType() == Node.ELEMENT_NODE) { Element myelement = (Element) mynode; System.out.println("Theme = " + myelement.getElementsByTagName("theme").item(0).getTextContent()); System.out.println("Fullscreen = " + myelement.getElementsByTagName("fullscreen").item(0).getTextContent()); System.out.println("Icon set = " + myelement.getElementsByTagName("icons").item(0).getTextContent()); } // close if } // close for } // close method } //close class 使用 Java 更新 XML用户时不时地会改变某个偏好项，这时候 org.w3c.dom 库就可以帮助你更新某个 XML 元素的内容。你只需要选择这个 XML 元素，就像你读取它时那样。不过，此时你不再使用 .getTextContent 方法，而是使用 .setTextContent 方法。updatePref = myelement.getElementsByTagName("fullscreen").item(0); updatePref.setTextContent("1"); System.out.println("Updated fullscreen to " + myelement.getElementsByTagName("fullscreen").item(0).getTextContent()); 这么做会改变应用程序内存中的 XML 文档，但是还没有把数据写回到磁盘上。配合使用 javax 和 w3c 库，你就可以把读取到的 XML 内容写回到配置文件中。TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer xtransform; xtransform = transformerFactory.newTransformer(); DOMSource mydom = new DOMSource(doc); StreamResult streamResult = new StreamResult(configFile); xtransform.transform(mydom, streamResult); 这么做会没有警告地写入转换后的数据，并覆盖掉之前的配置。下面是完整的代码，包括更新 XML 的操作：package myConfigParser; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; public class ConfigParser { public static void main(String[] args) { Path configPath = Paths.get(System.getProperty("user.home"), ".config", "DemoXMLParser"); File configFile = new File(configPath.toString(), "myconfig.xml"); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = null; try { builder = factory.newDocumentBuilder(); } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } Document doc = null; try { doc = builder.parse(configFile); } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } doc.getDocumentElement().normalize(); Node updatePref = null; // NodeList nodes = doc.getChildNodes(); NodeList nodes = doc.getElementsByTagName("window"); for (int i = 0; i < nodes.getLength(); i++) { Node mynode = nodes.item(i); System.out.println("Property = " + mynode.getNodeName()); if (mynode.getNodeType() == Node.ELEMENT_NODE) { Element myelement = (Element) mynode; System.out.println("Theme = " + myelement.getElementsByTagName("theme").item(0).getTextContent()); System.out.println("Fullscreen = " + myelement.getElementsByTagName("fullscreen").item(0).getTextContent()); System.out.println("Icon set = " + myelement.getElementsByTagName("icons").item(0).getTextContent()); updatePref = myelement.getElementsByTagName("fullscreen").item(0); updatePref.setTextContent("2"); System.out.println("Updated fullscreen to " + myelement.getElementsByTagName("fullscreen").item(0).getTextContent()); } // close if }// close for // write DOM back to the file TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer xtransform; DOMSource mydom = new DOMSource(doc); StreamResult streamResult = new StreamResult(configFile); try { xtransform = transformerFactory.newTransformer(); xtransform.transform(mydom, streamResult); } catch (TransformerException e) { e.printStackTrace(); } } // close method } //close class 如何保证配置不出问题编写配置文件看上去是一个还挺简单的任务。一开始，你可能会用一个简单的文本格式，因为你的应用程序只要寥寥几个配置项而已。但是，随着你引入了更多的配置项，读取或者写入错误的数据可能会给你的应用程序带来意料之外的错误。一种帮助你保持配置过程安全、不出错的方法，就是使用类似 XML 的规范格式，然后依靠你用的编程语言的内置功能来处理这些复杂的事情。这也正是我喜欢使用 Java 和 XML 的原因。每当我试图读取错误的配置值时，Java 就会提醒我。通常，这是由于我在代码中试图获取的节点，并不存在于我期望的 XML 路径中。XML 这种高度结构化的格式帮助了代码保持可靠性，这对用户和开发者来说都是有好处的。via: https://opensource.com/article/21/7/parsing-config-files-java作者：Seth Kenlon 选题：lujun9972 译者：lkxed 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
将配置文件与代码分离，使任何人都可以改变他们的配置，而不需要任何特殊的编程技巧。将程序配置与代码分离是很重要的。它使非程序员能够改变配置而不需要修改程序的代码。如果是编译好的二进制可执行文件，这对非程序员来说是不可能的，因为它不仅需要访问源文件（我们在开源程序中会这样），而且还需要程序员的技能组合。很少有人有这种能力，而且大多数人都不想学习它。对于像 Bash 这样的 shell 语言，由于 shell 脚本没有被编译成二进制格式，所以从定义上讲，源码是可以访问的。尽管有这种开放性，但对于非程序员来说，在 shell 脚本中钻研和修改它们并不是一个特别好的主意。即使是经验丰富的开发人员和系统管理员，也会意外地做出一些导致错误或更糟的改变。因此，将配置项放在容易维护的文本文件中，提供了分离，并允许非程序员编辑配置，而不会有对代码进行意外修改的危险。许多开发者对用编译语言编写的程序都是这样做的，因为他们并不期望用户是开发者。由于许多相同的原因，对解释型 shell 语言这样做也是有意义的。通常的方式和其他许多语言一样, 你可以为 Bash 程序编写代码，来读取并解析 ASCII 文本的配置文件、读取变量名称并在程序代码执行时设置值。例如，一个配置文件可能看起来像这样：var1=LinuxGeek46 var2=Opensource.com 程序将读取文件，解析每一行，并将值设置到每个变量中。源引Bash 使用一种更简单的方法来解析和设置变量, 叫做 源引 sourcing 。从一个可执行的 shell 程序中获取一个外部文件是一种简单的方法，可以将该文件的内容完整地引入 shell 程序中。在某种意义上，这很像编译语言的 include 语句，在运行时包括库文件。这样的文件可以包括任何类型的 Bash 代码，包括变量赋值。（LCTT 译注：对于使用 source 或 . 命令引入另外一个文件的行为，我们首倡翻译为“源引”。）像往常一样，演示比解释更容易。首先，创建一个 ~/bin 目录（如果它还不存在的话），并将其作为当前工作目录（PWD）。Linux 文件系统分层标准 将 ~/bin 定义为用户存储可执行文件的适当位置。在这个目录下创建一个新文件。将其命名为 main，并使其可执行：[dboth@david bin]$ touch main [dboth@david bin]$ chmod +x main [dboth@david bin]$ 在这个可执行文件中添加以下内容：#!/bin/bash Name="LinuxGeek" echo $Name 并执行这个 Bash 程序：[dboth@david bin]$ ./main LinuxGeek [dboth@david bin]$ 创建一个新的文件并命名为 ~/bin/data。这个文件不需要是可执行的。在其中添加以下信息：# Sourced code and variables echo "This is the sourced code from the data file." FirstName="David" LastName="Both" 在 main 程序中增加三行，看起来像这样：#!/bin/bash Name="LinuxGeek" echo $Name source ~/bin/data echo "First name: $FirstName" echo "LastName: $LastName" 重新运行该程序：[dboth@david bin]$ ./main LinuxGeek This is the sourced code from the data file. First name: David LastName: Both [dboth@david bin]$ 关于源引还有一件非常酷的事情要知道。你可以使用一个单点（.）作为 source 命令的快捷方式。改变 main 文件，用 . 代替 source。#!/bin/bash Name="LinuxGeek" echo $Name . ~/bin/data echo "First name: $FirstName" echo "LastName: $LastName" 并再次运行该程序。其结果应该与之前的运行完全相同。运行 Bash每一台使用 Bash 的 Linux 主机（几乎所有主机都是，因为 Bash 是所有发行版的默认 shell），都包括一些优秀的、内置的源引示例。每当 Bash shell 运行时，它的环境必须被配置成可以使用的样子。有五个主要文件和一个目录用于配置 Bash 环境。它们和它们的主要功能如下：/etc/profile: 系统级的环境和启动程序/etc/bashrc: 系统级的函数和别名/etc/profile.d/: 包含系统级的脚本的目录，用于配置各种命令行工具，如 vim 和 mc 以及系统管理员创建的任何自定义配置脚本~/.bash_profile: 用户特定的环境和启动程序~/.bashrc: 用户特定的别名和函数~/.bash_logout: 用户特定的命令，在用户注销时执行试着通过这些文件追踪执行顺序，确定它在非登录 Bash 初始化和登录 Bash 初始化中使用的顺序。我在我的 Linux 培训系列《使用和管理 Linux：从零到系统管理员》的第一卷第 17 章中这样做过。给你一个提示。这一切都从 ~/.bashrc 脚本开始。总结这篇文章探讨了在 Bash 程序中引用代码和变量的方法。这种从配置文件中解析变量的方法是快速、简单和灵活的。它提供了一种将 Bash 代码与变量赋值分开的方法，以使非程序员能够设置这些变量的值。via: https://opensource.com/article/21/6/bash-config作者：David Both 选题：lujun9972 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
这是我怎样设置 Git 来管理我的家目录的方法。我有好几台电脑。一台笔记本电脑用于工作，一台工作站放在家里，一台树莓派（或四台），一台 Pocket CHIP，一台 运行各种不同的 Linux 的 Chromebook，等等。我曾经在每台计算机上或多或少地按照相同的步骤设置我的用户环境，也经常告诉自己让每台计算机都略有不同。例如，我在工作中比在家里更经常使用 Bash 别名，并且我在家里使用的辅助脚本可能对工作没有用。这些年来，我对各种设备的期望开始相融，我会忘记我在家用计算机上建立的功能没有移植到我的工作计算机上，诸如此类。我需要一种标准化我的自定义工具包的方法。使我感到意外的答案是 Git。Git 是版本跟踪软件。它以既可以用在非常大的开源项目也可以用在极小的开源项目而闻名，甚至最大的专有软件公司也在用它。但是它是为源代码设计的，而不是用在一个装满音乐和视频文件、游戏、照片等的家目录。我听说过有人使用 Git 管理其家目录，但我认为这是程序员们进行的一项附带实验，而不是像我这样的现实生活中的用户。用 Git 管理我的家目录是一个不断发展的过程。随着时间的推移我一直在学习和适应。如果你决定使用 Git 管理家目录，则可能需要记住以下几点。1、文本和二进制位置当由 Git 管理时，除了配置文件之外，你的家目录对于所有内容而言都是“无人之地”。这意味着当你打开主目录时，除了可预见的目录的列表之外，你什么都看不到。不应有任何杂乱无章的照片或 LibreOffice 文档，也不应有 “我就在这里放一分钟” 的临时文件。原因很简单：使用 Git 管理家目录时，家目录中所有 未 提交的内容都会变成噪音。每次执行 git status 时，你都必须翻过去之前 Git 未跟踪的任何文件，因此将这些文件保存在子目录（添加到 .gitignore 文件中）至关重要。许多 Linux 发行版提供了一组默认目录：DocumentsDownloadsMusicPhotosTemplatesVideos如果需要，你可以创建更多。例如，我把创作的音乐（Music）和购买来聆听的音乐（Albums）区分开来。同样，我的电影（Cinema）目录包含了其他人的电影，而视频（Videos）目录包含我需要编辑的视频文件。换句话说，我的默认目录结构比大多数 Linux 发行版提供的默认设置更详细，但是我认为这样做有好处。如果没有适合你的目录结构，你更会将其存放在家目录中，因为没有更好的存放位置，因此请提前考虑并规划好适合你的工作目录。你以后总是可以添加更多，但是最好先开始擅长的。2、、设置最优的 .gitignore清理家目录后，你可以像往常一样将其作为 Git 存储库实例化：$ cd $ git init . 你的 Git 仓库中还没有任何内容，你的家目录中的所有内容均未被跟踪。你的第一项工作是筛选未跟踪文件的列表，并确定要保持未跟踪状态的文件。要查看未跟踪的文件：$ git status .AndroidStudio3.2/ .FBReader/ .ICEauthority .Xauthority .Xdefaults .android/ .arduino15/ .ash_history [...] 根据你使用家目录的时间长短，此列表可能很长。简单的是你在上一步中确定的目录。通过将它们添加到名为 .gitignore 的隐藏文件中，你告诉 Git 停止将它们列为未跟踪文件，并且永远不对其进行跟踪：$ \ls -lg | grep ^d | awk '{print $8}' >> ~/.gitignore 完成后，浏览 git status 所示的其余未跟踪文件，并确定是否有其他文件需要排除。这个过程帮助我发现了几个陈旧的配置文件和目录，这些文件和目录最终被我全部丢弃了，而且还发现了一些特定于一台计算机的文件和目录。我在这里非常严格，因为许多配置文件在自动生成时会表现得更好。例如，我从不提交我的 KDE 配置文件，因为许多文件包含了诸如最新文档之类的信息以及其他机器上不存在的其他元素。我会跟踪我的个性化配置文件、脚本和实用程序、配置文件和 Bash 配置，以及速查表和我经常引用的其他文本片段。如果有软件主要负责维护的文件，则将其忽略。当对一个文件不确定时，我将其忽略。你以后总是可以取消忽略它（通过从 .gitignore 文件中删除它）。3、了解你的数据我使用的是 KDE，因此我使用开源扫描程序 Filelight 来了解我的数据概况。Filelight 为你提供了一个图表，可让你查看每个目录的大小。你可以浏览每个目录以查看占用了空间的内容，然后回溯调查其他地方。这是一个令人着迷的系统视图，它使你可以以全新的方式看待你的文件。使用 Filelight 或类似的实用程序查找不需要提交的意外数据缓存。例如，KDE 文件索引器（Baloo）生成了大量特定于其主机的数据，我绝对不希望将其传输到另一台计算机。4、不要忽略你的 .gitignore 文件在某些项目中，我告诉 Git 忽略我的 .gitignore 文件，因为有时我要忽略的内容特定于我的工作目录，并且我不认为同一项目中的其他开发人员需要我告诉他们 .gitignore 文件应该是什么样子。因为我的家目录仅供我使用，所以我 不 会忽略我的家目录的 .gitignore 文件。我将其与其他重要文件一起提交，因此它已在我的所有系统中被继承。当然，从家目录的角度来看，我所有的系统都是相同的：它们具有一组相同的默认文件夹和许多相同的隐藏配置文件。5、不要担心二进制文件我对我的系统进行了数周的严格测试，确信将二进制文件提交到 Git 绝对不是明智之举。我试过 GPG 加密的密码文件、试过 LibreOffice 文档、JPEG、PNG 等等。我甚至有一个脚本，可以在将 LibreOffice 文件添加到 Git 之前先解压缩，提取其中的 XML，以便仅提交 XML，然后重新构建 LibreOffice 文件，以便可以在 LibreOffice 中继续工作。我的理论是，提交 XML 会比使用 ZIP 文件（LibreOffice 文档实际上就是一个 ZIP 文件）会让 Git 存储库更小一些。令我惊讶的是，我发现偶尔提交一些二进制文件并没有大幅增加我的 Git 存储库的大小。我使用 Git 已经很长时间了，我知道如果我要提交几千兆的二进制数据，我的存储库将会受到影响，但是偶尔提交几个二进制文件也不是不惜一切代价要避免的紧急情况。有了这种信心，我将字体 OTF 和 TTF 文件添加到我的标准主存储库，以及 GDM 的 .face 文件以及其他偶尔小型二进制 Blob 文件。不要想太多，不要浪费时间去避免它。只需提交即可。6、使用私有存储库即使托管方提供了私人帐户，也不要将你的主目录提交到公共 Git 存储库。如果你像我一样，拥有 SSH 密钥、GPG 密钥链和 GPG 加密的文件，这些文件不应该出现在任何人的服务器上，而应该出现在我自己的服务器上。我在树莓派上 运行本地 Git 服务器（这比你想象的要容易），因此我可以在家里时随时更新任何一台计算机。我是一名远程工作者，所以通常情况下就足够了，但是我也可以在旅行时通过 虚拟私人网络 访问我的计算机。7、要记得推送Git 的特点是，只有当你告诉它要推送改动时，它才会把改动推送到你的服务器上。如果你是 Git 的老用户，则此过程可能对你很自然。对于可能习惯于 Nextcloud 或 Syncthing 自动同步的新用户，这可能需要一些时间来适应。Git 家目录使用 Git 管理我的常用文件，不仅使我在不同设备上的生活更加便利。我知道我拥有所有配置和实用程序脚本的完整历史记录，这会鼓励我尝试新的想法，因为如果结果变得 很糟糕，则很容易回滚我的更改。Git 曾将我从在 .bashrc 文件中一个欠考虑的 umask 设置中解救出来、从深夜对包管理脚本的拙劣添加中解救出来、从当时看似很酷的 rxvt 配色方案的修改中解救出来，也许还有其他一些错误。在家目录中尝试 Git 吧，因为这些提交会让家目录融合在一起。via: https://opensource.com/article/21/4/git-home作者：Seth Kenlon 选题：lujun9972 译者：stevenzdg988 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
ifdex： 一个由 ESR 出品的给代码考古学家的工具
Eric Raymond 写了一个工具，用来帮助那些无畏的“代码考古学家们”理解“古代”代码的结构。它叫做 ifdex，它的背后有一段故事，拿起你的 Fedora 和赶牛的鞭子，让我讲给你听……在开发 NTPsec 早期， 我们就决定替换它的构建系统——它是如此的难于理解和修改——严重的拖慢了我们的开发进度。古老的 autoconf 构建方式就像一个恐怖的爬行动物，而 NTP 更是一个极端的例子。不完善的宏技术定义了太多的配置符号，为了掌握这些接口，即使你查看了 config.h 也无济于事。尤其是当你要做一些大的修改时，这更是一个问题！我们的一个伙计 Amar Takhar，是 waf 构建系统的专家，当他初步提出迁移的想法时得到了我的积极响应。几个月之后，他就做出了一些 waf 功能，虽然还未完成，但是已经至少可以生成用于实际测试的二进制了。这里我说“未完成”的意思是，代码里面还有一些 waf 构建绝不会设置的 #define 。很多人绝对不会碰那些 autoconf 构建的东西，而另外一些人则不。那些从来用不到的配置开关迷失在大堆的系统头文件和编译器设置的 #define 条件中。我这里说的不是几个或几十个，我最终统计出了有超过 670 个不同的 #define 用在 #if/#ifdef/#ifndef/#elif 条件中，而这些条件，如 John D. Bell 指出的那样，有 2430 个之多。我需要一些办法来检查它们并分成不同的类型：有的来自系统头文件、有的是配置开关，以及其它的……所以我写了一个分析器，它可以对代码树解析每个编译时条件的符号，然后将它们分成单纯的列表或 GCC 类的文件/行错误信息，你可以用 Emacs 的编译模式逐个分析。为了降低干扰，它掌握着一个条件符号的长列表（大概200个），这些可以忽略掉。比如像 \_\_GNUC\_\_ 符号是 GCC 预定义，而 O\_NONBLOCK 宏用于几种系统调用等等。这些符号分成几组，你可以使用命令行选项分别忽略它们。所以，如果你希望忽略列表中所有标准的 POSIX 宏而想看到操作系统相关的任何东西，那就可以做到了。另外一个重要的功能是你可以构造你自己的排除列表及注释。这样当我探索 NTP 编译条件的黑暗森林时，所构造的越来越大的排除列表就代表了我已经了解了的条件符号。最终（我希望）未知符号的报告将缩减为空，那么我就已经了解了所有配置开关的确切意义了。目前为止，我已经搞定了它们之中的 300 个，还有 373 个。这是我用我的漂亮工具在一周内完成的主要工作。噢，从来没有人说过代码考古是如此的容易。最后， ifdef 的主页是： http://www.catb.org/esr/ifdex/，代码库在这里：https://gitlab.com/esr/ifdex 。希望你用的上。
在我的上一篇文章中讲过如何做一个高可用系统：两个树莓派布署上 GlusterFS 集群文件系统，就变成一个容错文件服务器了。在这篇文章中我们会基于这个高可用系统构建另一个容错服务：建立一个简单的 Web 服务器集群。可能你没有看过我的上一篇文章，那我就在这里简单回顾一下上次的内容。我有两个树莓派：Pi1 和 Pi2。Pi1 的 IP 地址为 192.168.0.121，Pi2 的 IP 地址为 192.168.0.122。我把它们组合成为 GlusterFS 集群系统，共享一个存储卷，卷名为 gv0。并且这个 gv0 被挂载在两个树莓派上，挂载点都是 /mnt/gluster1，这样一来，两个树莓派能同时访问到这个共享卷。最后我测试了下系统的容错性，将共享卷挂载到第三个物理机上，并执行共享卷上的一个简单的脚本：打印系统时间并输出到 gv0 上的一个文件内，然后轮着关掉两台树莓派，检测这个冗余系统是否还能用。现在我手上有这个经过检验的存储系统，我要做的是把这个系统做成有容错功能的 Web 服务器集群。树莓派的 CPU 处理速度和内存资源都不是很高，好在对付一个静态 Web 服务器已经是绰绰有余了。我故意把这个例子做得非常简单，因为我觉得如果你能摆平这个简单的例子，你也能处理复杂一点的问题了。安装 Nginx虽然我也比较喜欢 Apache，但在资源有限的情况下，像 Nginx 这样功能全、性能高、资源占用少的 Web 服务器是比较理想的选择。在 Raspbian 的默认源中存在 Nginx，所以我只要登入一台树莓派并且输入以下命令：$ sudo apt-get update $ sudo apt-get install nginx Nginx 安装好后，创建配置文件 /mnt/gluster1/cluster ，内容如下：server { root /mnt/gluster1/www; index index.html index.htm; server_name twopir twopir.example.com; location / { try_files $uri $uri/ /index.html; } } 注意：我这里把服务器命名为“twopir”，你可以根据自己爱好命名你的网站。另外我把 Web 服务器的根目录设置为 /mng/gluster1/www。这样，我就能把我的静态文件放在这个共享存储系统内，从而让两个树莓派主机都访问到它们。现在删除默认的 Nginx 配置文件，将上面配好的配置文件作为 Nginx 的配置文件。在 Debian 系统中，Nginx 将它的配置文件像 Apache 一样放在 sites-available 和 site-enabled 两个目录下面。虚拟主机配置文档放在 sites-available 中，而 sites-enabled 目录包含了你想生效的配置文件的软链接。$ cd /etc/nginx/sites-available $ sudo ln -s /mnt/gluster1/cluster . $ cd /etc/nginx/sites-enabled $ sudo rm default $ sudo ln -s /etc/nginx/sites-available/cluster . 现在我已经放好了配置文件，但系统还不存在上面所说的 Web 服务器根目录。下一步就是创建目录 /mnt/gluster1/www，并复制 index.html 文件进去。当然你也可以建立自己定义的 index.html 文件，但先复制一个已有的文件是个不错的选择：$ sudo mkdir /mnt/gluster1/www $ cp /usr/share/nginx/www/index.html /mnt/gluster1/www 重启 Nginx 服务：$ sudo /etc/init.d/nginx restart 现在去 DNS 服务器为192.168.0.121的树莓派配置记录。你可以根据自己的情况配置你自己的域名和 IP 地址。现在在浏览器上输入 http://twopir/ 然后出现默认的 Nginx 首页。如果你查看下 /var/log/nginx/access.log 文件，你可以看到点击网页留下的记录。Nginx 能正常工作后，配置第二个树莓派。因为我们已经将配置文件都放在 GlusterFS 共享目录下，我们现在要做的只是安装 Nginx，创建相关的软链接，重启 Nginx：$ sudo apt-get update $ sudo apt-get install nginx $ cd /etc/nginx/sites-available $ sudo ln -s /mnt/gluster1/cluster . $ cd /etc/nginx/sites-enabled $ sudo rm default $ sudo ln -s /etc/nginx/sites-available/cluster . $ sudo /etc/init.d/nginx restart DNS 服务器上配置两条 A 记录现在两个主机共享同一份文件，下一步是设置冗余系统的关键步骤。虽然你完全可以设置一个类似心跳的服务用于轮询检测哪个树莓派的 Web 服务是开启的，但这里有个更好的方法：给同一个主机名指定两个 DNS 的 A 记录，分别指向你的两个树莓派（译注：A 记录就是将域名转化为 IP 地址的记录，DNS 包含很多记录方式，如 A 记录、PTR 记录、MX 记录等等），这就是传说中的 DNS 负载均衡，DNS 访问主机时，如果主机名对应多个 IP 地址，DNS 会随机返回这些 IP 地址的顺序：$ dig twopir.example.com A +short 192.168.0.121 192.168.0.122 $ dig twopir.example.com A +short 192.168.0.122 192.168.0.121 因为返回随机的顺序，用户可以均匀地往两台服务器发送请求，这个负载均衡的机制就是由 DNS 服务器的多条 A 记录来提供。相对于 DNS 的负载均衡技术，我更感兴趣的是 Web 浏览器如何处理请求失败的情况。当浏览器通过网页主机获得两条 A 记录，并且第一条记录所在的主机当机了，浏览器几乎立刻就切到另一条记录上。切换效率快到用户根本察觉不出来，这可比传统的心跳线轮循请求主机快多了。所以在你正在使用的 DNS 服务器上添加你的树莓派集群的两个 IP 地址，然后试试 dig 命令，就像我在上面使用过的一样，你也应该能得到两个 IP 地址。当你为同一个域名设置好了两个 A 记录，这套集群就可以提供容错服务了。打开两个终端并分别登录到两个树莓派，运行 tail -f /var/log/ngnix/access.log 命令，你可以监视 Web 服务器的访问情况。当你通过浏览器访问网页时，你可以看到在一台树莓派上产生了访问日志，而在另外一台的日志里什么也没有出现。现在你可以刷新几次页面，当你觉得你对能成功访问到 Web 服务器感到满意了，你可以重启响应你请求的那台树莓派，然后再刷新几次页面。也许浏览器上会出现一个短暂的不可访问信号，但会马上重定向到第二台树莓派上，你会看到一样的页面，并且你能通过终端访问日志了解具体情况。当第一台树莓派启动后，你在浏览器上根本不会察觉到。（译注：如何处理DNS 轮询的多个IP地址，不同浏览器有不同的做法，目前译者收集到的资料显示，只有mozilla的netlib库支持自动重连下一个IP地址的做法。如果读者知道更多的浏览器对DNS轮询的处理策略，请评论给我们。其实，以译者的态度看，DNS轮询根本就不能算作是高可用性的方案，勉强可以算作是负载均衡方案，建议考虑更可靠的其它方案。）随机重启一台树莓派，只要有一台在线，Web 服务器就能提供服务。这是一个非常简单的案例，你可以把你其它的静态文件放到 /mnt/gluster1/www 上，为你提供真正有价值的服务，现在好好享受你的低成本容错集群 Web 服务器吧。via: http://www.linuxjournal.com/content/two-pi-r-2-web-servers译者：bazz2 校对：wxy本文由 LCTT 原创翻译，Linux中国 荣誉推出
你好！ 准备好读另一篇很酷的Linux内核文章了么?接下来，在这个任务中，我们可以启用/禁用"Fusion MPT logging facility"。MPT代表"Message Passing Technology"(消息传递技术)。Fusion驱动是由LSI Logic公司开发。MPT一种进程间使用的特定消息策略。这个技术是同步的意味着进程将会等待所需的消息。在这之后，如果计算机处理拥有火线端口就应该启用"FireWire driver stack"。如果没有，那么就没有必要去启动一个不会使用到的火线驱动。火线很像USB。不过在协议、速度、物理形状和端口布局上不同。通常上，苹果设备使用火线和USB。一些PC有火线端口，但是不像USB口那样普及。一些火线控制器使用OHCI-1394规范(OHCI-1394 controllers)。如果是这样，启用这个驱动。为了使用火线存储设备，启用下一个驱动(Storage devices (SBP-2 protocol))。这个驱动提供了火线存储单元与火线总线通信的协议(the card with the attached FireWire ports)。一些火线扫描仪同样需要这个驱动。IPv4可以用在火线端口(IP networking over 1394)。IEEE 1394或者简单的"1394"就是火线。使用IPv4在火线多播有局限。"Nosy"是"FireWire PCILynx"卡上的流量监控(Nosy - a FireWire traffic sniffer for PCILynx cards)。下一步，可以支持I2O设备(I2O device support)。"Intelligent Input/Output (I2O)"(智能输入/输出)总线使用硬件和操作系统层的驱动。硬件驱动(hardware drivers (HDM))并不特定与任何操作系统而OS驱动(OS drivers (OSM))必须在目标操作系统上使用。OSM可以与任何HDM通信。I2O卡/总线有一个IOP- 输入/输出处理器(Input/Output Processor)。由于主CPU处理更少的数据，所以加速了系统。只在缺乏SUN I2O控制器的系统上启用"Enable LCT notification"。I2C SUN固件不支持LCT通知。 如果目标是RAID，Adaptec I2O控制器需要下一个驱动(Enable Adaptec extensions)。64位的直接内存访问可以在Adaptec I2O控制器上启用(Enable 64-bit DMA)。如果允许，可以配置I2O设备(I2O Configuration support)。这个特性主要用在RAID设定中。可以为I2O启用支持老的输入/输出控制(Enable ioctls (OBSOLETE))。可以启用I2O总线适配器的OSM软件(I2O Bus Adapter OSM)。这组OSM被用来寻找新的在其他适配器末端的I2O设备。下面，可以启用I2O块设备上的OSM(I2O Block OSM)。I2O硬件上的RAID控制器需要这个OSM。下面的OSM用于I2O控制器上的SCSI或者光纤通道设备。如果启用了(I2O /proc support)，可以通过/proc读取I2O设备的信息。在启用/禁用了I2O特性，我们可以继续其他的内核特性。下面，我们看到"Macintosh device drivers"。这只对苹果设备有用。PC的Linux内核不应该有任何这些驱动启用。然而，正如许多说法都有例外一样。一些PC用户可能会使用苹果鼠标、键盘和/或者一些其他的苹果设备。再说一次，最好彻底地理解需求和正在开发的内核。下一步，我们有一个用于网络的驱动(Network device support)。X11和其他的Linux软件不依赖于这个驱动，所以如果内核不会连接到另一台计算机、因特网、内联网或者网络，那么这个特性可以安全地禁用。下面的驱动就像上面，但是特定于核心驱动(Network core driver support)。这个驱动支持Etherchannel(Bonding driver support)。"bonding"是两条或者更多的以太网通道的融合。这也成为中继。使用这个驱动(Dummy net driver support)，可以在Linux中设置一个虚拟网络。虚拟网络(dummy network)就像网络中的/dev/null。任何发送给虚拟网络的数据都会永久消失，因为它会发往/dev/null。IP地址没有设置。用户可以定义他们的网络相当于/dev/null。下一步，可以支持和EQL(EQL (serial line load balancing) support)。这允许两台计算机使用SLIP或者PPP协议在两条串行连接上通信。光纤通道是一种用于连接存储设备到计算机的快速串行协议(Fibre Channel driver support)。TMII收发器需要这个驱动(Generic Media Independent Interface device support)。MII是一种用于最高速度为100Mbit/s以太网的接口。以太网线缆用于连接到PHYceiver，这是一种以太网收发器。为了通过虚拟接口组织许多以太网设备，需要"Ethernet team driver support"。"MAC-VLAN support"允许用户在特定的MAC地址和某个接口上映射数据包。TAP字符设备可以由MAC-VLAN接口生成(MAC-VLAN based tap driver)。TAP设备从内核中获取数据包，这样它们就可以被送往其他地方。下一个特性允许虚拟vxvlan接口在3层网络上创建2层网络(Virtual eXtensible Local Area Network (VXLAN))。这通常用于隧道虚拟网络。内核发送给网络的消息可任意通过这个特性记录下来(Network console logging support)。除非记录网络信息对你很重要时才启用它。禁用这个特性会增强性能。这个特性允许不同参数被改变(Dynamic reconfiguration of logging targets)。这些参数包括端口号、MAC地址、IP地址和其他一些设定。如果用户空间程序希望使用TAP设备，那么启用这个特性可以允许这样的活动(Universal TUN/TAP device driver support)。这个驱动用于本地以太网隧道(Virtual ethernet pair device)。"Virtio network driver"用于QEMU、Xen、KVM和其他虚拟机。下一步，可以启用"ARCnet support"。ARCnet是一种类似令牌环本地局域网络(Local-Area-Network (LAN)协议。ARCnet代表"Attached Resource Computer Network"(附加资源计算器网络)。现在，我们进入到"ATM drivers"。ATM代表"Asynchronous Transfer Mode"(异步传输模式)。ATM用于电信。Marevell以太网交换机芯片需要这个驱动(Marvell 88E6060 ethernet switch chip support)。同样，这类交换机的芯片同样需要依赖模型(Marvell 88E6085/6095/6095F/6131 ethernet switch chip support)和(Marvell 88E6123/6161/6165 ethernet switch chip support)。现在，我们可以学习关于"Ethernet driver support"。首先我们可以启用/禁用"3Com devices"。接下来允许内核开发者选择支持哪些3Com设备。下一组选项是对于不同的"Adaptec devices"和接下来的"Alteon devices"。这些只是特定设备/供应商驱动。通常地，这些驱动被作为模块加入。在设置了这两组选项后，接下来还有"AMD devices"和"Atheros devices"。注意：请记住内核会运行在哪类硬件上。对于大量不同的设备，或许最好把它们作为模块加入这里有不同特定供货商的设备驱动-"Cadence devices"、"Broadcom devices"、"Brocade devices"、"Chelsio devices"、"Cisco devices"、"Digital Equipment devices"。一些其他的特定设备/供应商驱动遵循它们。接下来的驱动并不是特定设备/供应商的 "SLIP (serial line) support"。这个驱动支持SLIP和CSLIP。SLIP(Serial Line Internet Protocol)是一种用于调制解调器和串口的因特网驱动。PPP现在用来代替SLIP。CSLIP是压缩的SLIP。下面，"CSLIP compressed headers"可以启用用来压缩TCP/IP头。CSLIP快于SLIP，但是想要启用CSLIP，传输和接收的计算机都必须理解CSLIP。当在恶劣的模拟线路上使用SLIP时，最好启用"Keepalive and linefill"，这会帮助保持连接。对于质量差的网络或者7bit网络中运行IP而言，最好启用"Six bit SLIP encapsulation"。现在我们可以进入流行的USB系统，但是这些是用于网络的USB驱动。第一个启用/禁用的USB网络设备是"USB CATC NetMate-based Ethernet device support"。这是用于10Mbps的USB以太网EL1210A芯片设备。USB设备将会扮演和成为一个以太网设备即使硬件是USB。接下来，除了设备是KLSI KL5KUSB101B芯片组(USB KLSI KL5USB101-based ethernet device support)，其他与上面的驱动一样。Pegasus USB是USB转以太网的适配器/转换器(USB Pegasus/Pegasus-II based ethernet device support)。接下来是另外一个USB转以太网驱动(USB RTL8150 based ethernet device support)。下一篇文章中，我们将继续配置USB网络系统。via: http://www.linux.org/threads/the-linux-kernel-configuring-the-kernel-part-14.4765/译者：geekpi 校对：wxy本文由 LCTT 原创翻译，Linux中国 荣誉推出
准备好配置更多的驱动了么？还有很多要做。Linux支持两种不同的康柏智能阵列控制器：(Compaq SMART2 support)和(Compaq Smart Array 5xxx support)。阵列控制器是将物理存储单元表现为逻辑单元的设备。这些控制可能同样实现了基于硬件的RAID。硬件和软件RIAD的不同是简单的。Linux管理并见到软件RIAD。Linux将硬件RAID视为另外的存储单元。这意味着Linux没有意识到设备就是RAID驱动器。硬件(阵列控制器)独立于内核管理着RAID系统。这对于系统的性能更好因为内核不必配置或者管理RAID。注意，不同的阵列控制器有不同的RAID能力。上面提到的阵列控制器可以通过这个驱动访问SCSI磁带(SCSI tape drive support for Smart Array 5xxx)。SCSI磁带是使用SCSI协议的磁带机。PCI RAID控制器Mylex DAC960、AcceleRAID和eXtremeRAID在这个驱动中支持(Mylex DAC960/DAC1100 PCI RAID Controller support)。PCI RAID控制器是一个连接到PCI卡的阵列控制器。RAID控制器是拥有RAID功能的阵列控制器。带电源备份的MM5415内存芯片在这个驱动中支持(Micro Memory MM5415 Battery Backed RAM support)。带后备电源内存芯片允许数据在切断电源后继续保存在内存设备中。这有助于保护数据。不然，当电源断开后，当前的计算机会话就会丢失。当启用这个特性后，可以将典型的文件(比如ISO文件)作为一个块设备并挂载它Loopback device support)。这对于从镜像文件中检索文件而不必把文件烧录到光盘或者解压出来。想像一下你从因特网上得到了一份包含了很多文件的ISO文件。如果你只需要包中的一个文件并且用户不希望烧写ISO到光盘上或者不想知道如何打开一个ISO文件。用户可以用挂载ISO来替代。Linux内核在初始化阶段会创建一些回路设备，所以一些回环设备已经准备好并创建了(Number of loop devices to pre-create at init time)。当一个文件(像ISO)或者虚拟设备(就像虚拟磁盘驱动器[vhd])被作为回环设备挂载时会节约一些时间。这个设定允许开发者选择内核可以预 创建多少回环设备。当"Cryptoloop Support"启用后就可以CryptoAPI创建密码。这个用于硬件驱动器加密。然而，并不是所有的文件系统都支持。下面用户可以启用"DRBD Distributed Replicated Block Device support"(译注：Linux上的分布存储系统)。这个就像网络RAID1。这些设备拥有设备文件/dev/drbdx。这些设备通常被用于集群，这里集群中的每台计算机都有一个从主单元镜像过来的存储单元。这意味着每台计算机的硬盘是位于组中心计算机硬盘的镜像拷贝。集群是一组计算机扮演着一台大型强力单元的角色。然而，每个集群都有一台控制计算机称为主节点。余下的计算机是从节点。DRBD支持用于测试IO错误处理的故障注射(DRBD fault injection)。记住，故障注射就是使设备/软件认为发生了一个错误，因此开发者可以测试硬件/软件如何处理错误如果内核要成为网络块设备的客户端，那么启用这个特性(Network block device support)。第一个设备文件是/dev/nd0。网络块设备是通过网络访问的远程存储单元。直接连接SSD到PCI或者PCIe需要这个驱动(NVM Express block device)。用这个特性允许将单独的SCSI OSD(object-based storage,基于对象的存储)对象作为块设备(OSD object-as-blkdev support)。下一个驱动是"Promise SATA SX8 support"。这个驱动用于Promise公司(Promise Technology Inc.)生产的SATA控制器。Linux允许将一部分内存作为块设备(RAM block device support)。这通常见与完全运行于内存上的Linux的live发行版。Linux的live发行版会卸载光盘并接着加载到内存中，所以在尝试一个新的操作系统或者修复另一个系统时不会伤害到已安装的系统。下一个选项允许用户输入"Default number of RAM disks"(默认RAM磁盘数量)。"Default RAM disk size"(默认RAM磁盘大小)可以以KB设置大小。内核可以支持在内存设备的XIP文件系统作为块设备(Support XIP filesystems on RAM block device)。这个特性会增大内核的大小。 XIP (eXecute In Place)文件系统是一个允许可执行文件在相同的文件系统上存储数据而不必像其他应用一样利用内存。在一个驻留在内存上的live版linux系统上运行可执行文件时需要这个文件系统。下面，内核可以支持"Packet writing on CD/DVD media"。(CD/DVD刻录机支持.)内核开发者可以设置最大活跃并发包数量(Free buffers for data gathering)。大的数字会以内存的消耗为代价加速写入性能。一个包会消耗大约64KB。Linux内核可以使用可擦写光盘作为缓存空间(Enable write caching)。这个特性仍然是试验性质。下面的特性允许通过以太网线缆使用ATA规范(ATA over Ethernet support)。下面的驱动允许虚拟块设备创建为virtio(Virtio block driver)。virtio是IO虚拟化平台。一些非常老的硬盘还要一个特殊的驱动(Very old hard disk (MFM/RLL/IDE) driver)。这里有一个驱动用于先前提到的Rados设备(Rados block device (RBD))。下面是一个特殊的设备驱动(IBM FlashSystem 70/80 PCIe SSD Device Driver)。现在，我们可以进入杂项设备。第一个设定是启用/禁用电位器(Analog Devices Digital Potentiometers )。如果电位器在I2C总线上，那么就启用这个(support I2C bus connection)。如果电位器是连接到SPI总线，那么需要这个驱动(support SPI bus connection)。注意:Linux内核支持很多传感器因为Linux内核经常用于天气设备和机器人。这个驱动用于IBM RSA(Condor)服务处理器(Device driver for IBM RSA service processor)。内核同样支持PCI Sensable PHANToM设备驱动(Sensable PHANToM (PCI))。这个驱动指引不同来自并行追踪接口(Parallel Trace Interface (PTI))的追踪数据发往Intel Penwell PTI口 (Parallel Trace Interface for MIPI P1149.7 cJTAG standard)。这个被指领的数据用于调试目的。一些带有IOC4芯片的SGI IO控制器需要这个驱动(SGI IOC4 Base IO support)。SGI IO是由SCI管理的输入/输出设备。IOC4芯片控制着许多由这些设备执行的任务。这是一个基础驱动。其他对这些设备的驱动依赖于这个驱动。这里有很少的TI闪存媒体适配器驱动在Linux内核中，(TI Flash Media interface support) 和(TI Flash Media PCI74xx/PCI76xx host adapter support)。这个驱动("Integrated Circuits ICS932S401")用于ICS932S401时钟控制芯片。Atmel同步串行通信外设(Synchronized Serial Communication peripheral (SSC))有一个驱动在内核中(Device driver for Atmel SSC peripheral)。这个设备提供点对点的设备间的串行连接。"Enclosure Services"特性支持硬盘托架。这是对于CS5535/CS5536芯片的定时器驱动(CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support)。这个驱动让应用可以与HP工业标准服务器中的iLO管理处理器通信(Channel interface driver for the HP iLO processor)。"iLO"代表的是"Integrity Integrated Lights-Out".iLO允许远程服务器管理。Linux内核支持ALS APDS9802光敏传感器(Medfield Avago APDS9802 ALS Sensor module)。一些其他支持的传感器包括：Intersil ISL29003 ambient light sensorIntersil ISL29020 ambient light sensorTaos TSL2550 ambient light sensorROHM BH1780GLI ambient light sensorBH1770GLC / SFH7770 combined ALS - Proximity sensorAPDS990X combined als and proximity sensors注意：如果内核是为广泛的计算机编译的话，大多数驱动应该以模块形式加入。Linux甚至可以使用"Honeywell HMC6352 compass"(一种电子罗盘)。内核同样支持"Dallas DS1682 Total Elapsed Time Recorder with Alarm"。(一种运行时间记录仪)16位的数模转换器通过这个驱动支持(Texas Instruments DAC7512)。"VMware Balloon Driver"将客户机操作系统不需要的物理内存页交给需要那些需要的。这里有两个不同的压力传感器(BMP085 digital pressure sensor on I2C) 和 (BMP085 digital pressure sensor on SPI)。Intel输入/输出集线器(Intel Input/Output Hub (IOH))同样在内核中支持(Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB)。具体地说，这个是Intel Topcliff芯片组的PCH PHUB(Platform Controller Hub Packet Hub)"FSA9480 USB Switch"是检测设备何时插入的检测器。下一个选项允许比特流配置(Lattice ECP3 FPGA bitstream configuration via SPI)。Silicon微控制器使用Silicon实验室C2端口，这需要一个特殊的驱动(Silicon Labs C2 port support)。再说一次，继续留意下一篇文章因为我们还有更多的要做。via: http://www.linux.org/threads/the-linux-kernel-configuring-the-kernel-part-11.4640/译者：geekpi 校对：wxy本文由 LCTT 原创翻译，Linux中国 荣誉推出
自从计算机互连后，各种服务迅速发展。用户使用的电子邮件、社交媒体、在线商城、即时聊天甚至网络会议等服务如雨后春笋般涌现。但从另一方面来说，这些连接服务也具有双刃剑，比如它们当中的病毒、恶意软件、特洛伊木马等会向计算机发送恶意消息。安装 UFW 防火墙作为最大的计算机网络，互联网上可并不都是善意的用户。因此，为了确保我们的计算机或服务器安全，我们需要进行保护。在你的计算机或服务器上一个必须有的组件就是防火墙。在维基百科中，其定义是：防火墙是计算机中一款应用软件或基于硬件的网络安全系统。它根据应用配置的规则，分析数据包，然后决定是否允许此数据包通过，来控制整个系统的网络数据进出访问权限。iptables 是一款广泛使用于服务器的防火墙。它是一款应用程序，它会根据一系列规则来管理服务器上的进出数据流。一般来说，只有可信任的连接才允许进入服务器。但 iptables 是在控制台模式下运行，它非常的复杂。不熟悉 iptables 配置规则和命令的用户可以读读下面的文章，它描述了如何使用iptables防火墙。iptables 基础 (Linux 防火墙) 指南Debian/Ubuntu 系统中安装 UFW 防火墙为了降低 iptables 设置的复杂度，有许多对应的前端应用。如果你运行的是 Ubuntu linux 系统的话， UFW 就是一款默认的防火墙工具。我们开始来探讨 UFW 防火墙吧。什么是 UFWUFW (简单的防火墙) 是广泛使用的 iptables 防火墙 的前端应用，这是非常适合于基于主机的防火墙。UFW 即提供了一套管理网络过滤器的框架，又提供了控制防火墙的命令行界面接口。它给那些不熟悉防火墙概念的 Linux 新用户提供了友好、易使用的用户界面。同时，另一方面，它也提供了命令行界面，为系统管理员准备了一套复杂的命令，用来设置复杂的防火墙规则。UFW 对像 Debian、Ubuntu 和 Linux Mint 这些发布版本来说也是上上之选。UFW 基本用法首先，用如下命令来检查下系统上是否已经安装了 UFW 。$ sudo dpkg --get-selections | grep ufw 如还没有安装，可以使用 apt 命令来安装，如下所示：$ sudo apt-get install ufw 在使用前，你应该检查下 UFW 是否已经在运行。用下面的命令来检查。$ sudo ufw status 如果你发现状态是： inactive , 意思是没有被激活或不起作用。启用/禁用 UFW要启用它，你只需在终端下键入如下命令：$ sudo ufw enable 在系统启动时启用和激活防火墙要禁用，只需输入：$ sudo ufw disable 列出当前UFW规则在防火墙被激活后，你可以向里面添加你自己的规则。如果你想看看默认的规则，可以输入。$ sudo ufw status verbose 输出样例：Status: active Logging: on (low) Default: deny (incoming), allow (outgoing) New profiles: skip $ 添加UFW规则如你所见，默认是不允许所有外部访问连接的。如果你想远程连接你的机器，就得开放相应的端口。例如，你想用 ssh 来连接，下面是添加的命令。允许访问$ sudo ufw allow ssh [sudo] password for pungki : Rule added Rule added (v6) $ 再一次检查状态，会看到如下的一些输出。$ sudo ufw status To Action From -- ----------- ------ 22 ALLOW Anywhere 22 ALLOW Anywhere (v6) 如果你有很多条规则，想快速的在每条规则上加个序号数字的话，请使用 numbered 参数。$ sudo ufw status numbered To Action From ------ ----------- ------ [1] 22 ALLOW Anywhere [2] 22 ALLOW Anywhere (v6) 第一条规则的意思是所有通过22端口访问机器的 tcp 或 udp 数据包都是允许的。如果你希望仅允许 tcp 数据包访问应该怎么办？可以在服务端口后加个 tcp 参数。下面的示例及相应的输出。$ sudo ufw allow ssh/tcp To Action From ------ ----------- ------ 22/tcp ALLOW Anywhere 22/tcp ALLOW Anywhere (v6) 拒绝访问添加拒绝规则也是同样的招数。我们假设你想拒绝 ftp 访问, 你只需输入$ sudo ufw deny ftp To Action From ------ ----------- ------ 21/tcp DENY Anywhere 21/tcp DENY Anywhere (v6) 添加特定端口有时候，我们会自定义一个端口而不是使用标准提供的。让我们试着把机器上 ssh 的 22 端口换成 2290 端口，然后允许从 2290 端口访问，我们像这样添加：$ sudo ufw allow 2290/ssh (译者注：些处演示例子有问题) To Action From -- ----------- ------ 2290 ALLOW Anywhere 2290 ALLOW Anywhere (v6) 你也可以把端口范围添加进规则。如果我们想打开从 2290到2300 的端口以供 tcp 协议使用，命令如下示：$ sudo ufw allow 2290:2300/tcp To Action From ------ ----------- ------ 2290:2300/tcp ALLOW Anywhere 2290:2300/tcp ALLOW Anywhere (v6) 同样你想使用 udp 的话，如下操作。$ sudo ufw allow 2290:2300/udp To Action From ------ ----------- ------ 2290:2300/udp ALLOW Anywhere 2290:2300/udp ALLOW Anywhere (v6) 请注意你得明确的指定是 ‘tcp’ 或 ‘udp’，否则会出现跟下面类似的错误信息。ERROR: Must specify ‘tcp’ or ‘udp’ with multiple ports 添加特定 IP前面我们添加的规则都是基于 服务程序 或 端口 的，UFW 也可以添加基于 IP 地址的规则。下面是命令样例。$ sudo ufw allow from 192.168.0.104 你也可以使用子网掩码来扩宽范围。$ sudo ufw allow form 192.168.0.0/24 To Action From -- ----------- ------ Anywhere ALLOW 192.168.0.104 Anywhere ALLOW 192.168.0.0/24 如你所见， from 参数仅仅限制连接的来源，而目的（用 To 列表示）是所有地方。让我们看看允许访问 22端口(ssh)的例子。$ sudo ufw allow to any port 22 上面的命令会允许从任何地方以及任何协议都可以访问22端口。组合参数对于更具体的规则，你也可以把 IP 地址、协议和端口这些组合在一起用。我们想创建一条规则，限制仅仅来自于 192.168.0.104 的 IP ，而且只能使用 tcp 协议和通过 22端口 来访问本地资源。我们可以用如下所示的命令。$ sudo ufw allow from 192.168.0.104 proto tcp to any port 22 创建拒绝规则的命令和允许的规则类似，仅需要把 allow 参数换成 deny 参数就可以。删除规则某些时候需要删除现有的规则。再一次使用 UFW 删除规则是很简单的。在上面的示例中，已经创建了如下的规则，现在你想删除它们。To Action From -- ----------- ------ 22/tcp ALLOW 192.168.0.104 21/tcp ALLOW Anywhere 21/tcp ALLOW Anywhere (v6) 删除规则有两个方法。方法1下面的命令将会 删除 与 ftp 相关的规则。所以像 21/tcp 这条 ftp 默认访问端口的规则将会被删除掉。$ sudo ufw delete allow ftp 方法2但当你使用如下命令来删除上面例子中的规则时，$ sudo ufw delete allow ssh 或者 $ sudo ufw delete allow 22/tcp 会出现如下所示的一些错误Could not delete non-existent rule Could not delete non-existent rule (v6) 我们还有一招。上面已经提到过，可以序列数字来代替你想删除的规则。让我们试试。$ sudo ufw status numbered To Action From -- ----------- ------ [1] 22/tcp ALLOW 192.168.0.104 [2] 21/tcp ALLOW Anywhere [3] 21/tcp ALLOW Anywhere (v6) 然后我们删除正在使用的第一条规则。按 “ y ” 就会永久的删除这条规则。$ sudo ufw delete 1 Deleting : Allow from 192.168.0.104 to any port 22 proto tcp Proceed with operation (y|n)? y 从这些用法中你就可以发现它们的不同。 方法2 在删除前需要 用户确认 ，而 方法1 不需要。重置所有规则某些情况下，你也许需要 删除/重置 所有的规则。可以输入。$ sudo ufw reset Resetting all rules to installed defaults. Proceed with operation (y|n)? y 如果你输入“ y ”， UFW 在重置你的 ufw 前会备份所有已经存在规则，然后重置。重置操作也会使你的防火墙处于不可用状态，如果你想使用得再一次启用它。高级功能正如我上面所说，UFW防火墙能够做到iptables可以做到的一切。这是通过一些规则文件来完成的，他们只不过是 iptables-restore 所对应的文本文件而已。是否可以通过 ufw 命令微调 UFW 的与/或逻辑来增加 iptables 命令其实就是编辑几个文本文件的事。/etc/default/ufw: 默认策略的主配置文件，支持 IPv6 和 内核模块。/etc/ufw/before[6].rules: 通过 ufw 命令添加进规则之前里面存在的规则会首先计算。/etc/ufw/after[6].rules: 通过 ufw 命令添加进规则之后里面存在的规则会进行计算。/etc/ufw/sysctl.conf: 内核网络可调参数。/etc/ufw/ufw.conf: 设置系统启动时 UFW 是否可用，和设置日志级别。结论UFW 作为 iptables 的前端应用，给用户提供了简单的接口界面。使用着不需要去记非常复杂的 iptables 语法。UFW 也使用了‘ 简单英语 ’作为它的参数。像 Allow、deny、reset 就是他们当中的一部分。我相信有很多很多 iptables 前端应用，但 UFW 绝对是那些想要快速、简单的就建立自己的防火墙，而且还很安全的用户的最佳替代品之一。请输入 man ufw 查看 ufw 用户手册，来了解更多详情。via: http://www.tecmint.com/how-to-install-and-configure-ufw-firewall/译者：runningwater 校对：Caroline本文由 LCTT 原创翻译，Linux中国 荣誉推出
每日Ubuntu小技巧：合上笔记本，系统不睡眠
Ubuntu 是一个处在牛 A 和牛 C 之间的现代操作系统，全世界数百万用户和公司都在使用它。无论是充当工作台还是高级工程机器，Ubuntu 都游刃有余。如果你是 Ubuntu 初学者，使用过程还需要高手指导，那就关注本站吧。我们已经写了数百篇 Ubuntu 教程，足以带你入门。从安装 Ubuntu 到系统基本设置，我们都有涉猎。这篇简单的教程为你介绍当笔记本盖子合上时该干嘛还是干嘛，而不是进入睡眠模式或者直接关机。大多数现代操作系统（包括 Windows）会在笔记本合上时进入睡眠状态。Ubuntu 也是如此。如果你想让你的笔记本盖子合上时不睡眠，就跟着我们学习吧。要达到这个目的，Ubuntu 有两种方法。第一种是打开 System Settings –> Power（中文版是打开 系统设置 -> 电源），然后进行设置。一些用户设置后不会生效。另一个方法是直接编辑 Login Manager 的配置文件（logind.conf）。这个方法基本能生效，建议使用这个。要开始了，按下 Ctrl – Alt – T 组合键，打开终端。然后运行下面的命令打开 logind.conf 文件。你的所有修改都在这个文件内。sudo gedit /etc/systemd/logind.conf 打开文件后修改下面这行：#HandleLidSwitch=suspend 改成这样：HandleLidSwitch=ignore 保存文件，重启 Login Manager 服务：sudo restart systemd-logind 工作完成！配置文件的 “ignore” 值告诉 Ubuntu 当笔记本合上后不要睡眠或挂起。不要改动其它设置然后保存文件。via: http://www.liberiangeek.net/2013/12/daily-ubuntu-tips-do-nothing-when-laptop-lid-is-closed/译者：bazz2 校对：Caroline本文由 LCTT 原创翻译，Linux中国 荣誉推出
vsftpd （ 非常安全的文件传输协议守护进程） 是Unix/Linux系统中的一个安全快速的FTP服务器。 在这篇指导教程中，让我们看看在openSUSE 13.1中怎样使用vsftpd来配置一个基本的FTP服务器。安装 vsftpd作为root用户登录然后输入以下命令。# zypper in vsftpd 启动 vsftpd 服务然后通过设置使它在每次系统重启时自动启动。# systemctl enable vsftpd.service # systemctl start vsftpd.service 配置 vsftpd为ftp用户新建一个文件夹。# mkdir /srv/ftp 创建一个名为 ftp-users 的组。# groupadd ftp-users 让我们来创建一个叫unixmen的示例用户 并设置其主目录为 /srv/ftp 组为 ftp-users 。# useradd -g ftp-users -d /srv/ftp/ unixmen 为新用户设置密码。# passwd unixmen 使ftp主目录 /srv/ftp/ 可以被ftp用户所访问。# chmod 750 /srv/ftp/ # chown unixmen:ftp-users /srv/ftp/ 编辑 vsftpd.conf 文件# nano /etc/vsftpd.conf 设置如下的更改。[...] #Uncomment and Set YES to enable write. write_enable=YES [...] # Uncomment and Set banner name for your website ftpd_banner=Welcome to Unixmen FTP service. [...] # Uncomment ls_recurse_enable=YES [...] # Uncomment and set YES to allow local users to log in. local_enable=YES [...] # To disable anonymous access, set NO. anonymous_enable=NO [...] # Uncomment to enable ascii download and upload. ascii_upload_enable=YES ascii_download_enable=YES [...] ## Add at the end of this file ## use_localtime=YES 保存并退出文件。测试本地FTP服务器首先 让我们按如下步骤尝试登录FTP服务器# ftp localhost Trying ::1:21 ... Connected to localhost. 220 (vsFTPd 3.0.2) Name (localhost:root): unixmen 331 Please specify the password. Password: 230 Login successful. Remote system type is UNIX. Using binary mode to transfer files. ftp> 正如你在上面所输出的那样, 我们能够用unixmen用户登录到ftp服务器。测试远程FTP服务器默认 openSUSE 内置的防火墙不允许远程系统登录FTP。所以让我们允许vsftpd服务通过suse的防火墙。然后我们需要打开： Yast -> 安全性与用户 -> 防火墙.在防火墙界面，进入 允许服务. 在区域选择下拉框中，选择 外部区域 在服务允许下拉框中，选择 vsftpd 服务器 然后点击添加。单击下一步并关闭Yast控制中心现在尝试从远程系统连接FTP。我试着从我的ubuntu桌面系统登录FTP服务器。sk@sk:~$ ftp 192.168.1.53 Connected to 192.168.1.53. 220 (vsFTPd 3.0.2) Name (192.168.1.53:sk): unixmen 331 Please specify the password. Password: 230 Login successful. Remote system type is UNIX. Using binary mode to transfer files. ftp> 正如你在上面输出中所看到的，我能够连接到ftp服务器。如果不允许vsftpd服务通过防火墙，你将会得到一个连接超时的报错。从浏览器连接打开你的浏览器并导航到ftp://ip-address/。输入ftp用户名和密码。使用FileZilla连接到FTP服务器对于新手来说，在命令行模式下工作可能会很烦恼。所以让我们来安装一个叫Filezilla的图形化的FTP客户端。它可以让我们登陆FTP变得更加简单:几乎所有的发行版在它们的官方软件仓库中都有filezilla客户端。 为了在基于Linux的系统上安装filezilla 需要键入以下的命令:在基于Ubuntu的系统中:$ sudo apt-get install filezilla 在Fedora/Redhat系统中:$ sudo yum install filezilla 在openSUSE中:# zypper in filezilla 安装完fielzilla后打开它。输入ftp服务器的IP地址、用户名和密码，然后点击快速连接。为了增加安全性，你可以通过将用户添加到 /etc/vsftpd.chroot\_list文件中来限制特定用户对FTP服务器的访问。编辑 vsftpd.conf 文件,nano /etc/vsftpd.conf 设置如下的更改.[...] # Uncomment and set YES chroot_local_user=YES chroot_list_enable=YES chroot_list_file=/etc/vsftpd.chroot_list [...] 创建 文件 /etc/vsftpd.chroot\_list,nano /etc/vsftpd.chroot_list 添加你希望能够访问FTP服务器的用户。我添加了用户unixmen。unixmen 重启ftp服务.# systemctl restart vsftpd.service 现在你能够使用chroot\_list文件中列出的用户来连接到FTP服务器。如果chroot\_list以外的用户想访问FTP服务器，他们将得到如下错误提示。500 OOPS: could not read chroot() list file:/etc/vsftpd.chroot_list ftp: Login failed 就是现在这样，你的FTP服务器已经可以使用了，好好享受吧!via: http://www.unixmen.com/setup-ftp-server-opensuse-13-1/译者：zsJacky 校对：Caroline本文由 LCTT 原创翻译，Linux中国 荣誉推出