2019年8月

深入理解 Linux 配置/构建系统是如何工作的。

自从 Linux 内核代码迁移到 Git 以来,Linux 内核配置/构建系统(也称为 Kconfig/kbuild)已存在很长时间了。然而,作为支持基础设施,它很少成为人们关注的焦点;甚至在日常工作中使用它的内核开发人员也从未真正思考过它。

为了探索如何编译 Linux 内核,本文将深入介绍 Kconfig/kbuild 内部的过程,解释如何生成 .config 文件和 vmlinux/bzImage 文件,并介绍一个巧妙的依赖性跟踪技巧。

Kconfig

构建内核的第一步始终是配置。Kconfig 有助于使 Linux 内核高度模块化和可定制。Kconfig 为用户提供了许多配置目标:

配置目标解释
config利用命令行程序更新当前配置
nconfig利用基于 ncurses 菜单的程序更新当前配置
menuconfig利用基于菜单的程序更新当前配置
xconfig利用基于 Qt 的前端程序更新当前配置
gconfig利用基于 GTK+ 的前端程序更新当前配置
oldconfig基于提供的 .config 更新当前配置
localmodconfig更新当前配置,禁用没有载入的模块
localyesconfig更新当前配置,转换本地模块到核心
defconfig带有来自架构提供的 defconcig 默认值的新配置
savedefconfig保存当前配置为 ./defconfig(最小配置)
allnoconfig所有选项回答为 no 的新配置
allyesconfig所有选项回答为 yes 的新配置
allmodconfig尽可能选择所有模块的新配置
alldefconfig所有符号(选项)设置为默认值的新配置
randconfig所有选项随机选择的新配置
listnewconfig列出新选项
olddefconfigoldconfig 一样,但设置新符号(选项)为其默认值而无须提问
kvmconfig启用支持 KVM 访客内核模块的附加选项
xenconfig启用支持 xen 的 dom0 和 访客内核模块的附加选项
tinyconfig配置尽可能小的内核

我认为 menuconfig 是这些目标中最受欢迎的。这些目标由不同的 主程序 host program 处理,这些程序由内核提供并在内核构建期间构建。一些目标有 GUI(为了方便用户),而大多数没有。与 Kconfig 相关的工具和源代码主要位于内核源代码中的 scripts/kconfig/ 下。从 scripts/kconfig/Makefile 中可以看到,这里有几个主程序,包括 confmconfnconf。除了 conf 之外,每个都负责一个基于 GUI 的配置目标,因此,conf 处理大多数目标。

从逻辑上讲,Kconfig 的基础结构有两部分:一部分实现一种新语言来定义配置项(参见内核源代码下的 Kconfig 文件),另一部分解析 Kconfig 语言并处理配置操作。

大多数配置目标具有大致相同的内部过程(如下所示):

请注意,所有配置项都具有默认值。

第一步读取源代码根目录下的 Kconfig 文件,构建初始配置数据库;然后它根据如下优先级读取现有配置文件来更新初始数据库:

  1. .config
  2. /lib/modules/$(shell,uname -r)/.config
  3. /etc/kernel-config
  4. /boot/config-$(shell,uname -r)
  5. ARCH_DEFCONFIG
  6. arch/$(ARCH)/defconfig

如果你通过 menuconfig 进行基于 GUI 的配置或通过 oldconfig 进行基于命令行的配置,则根据你的自定义更新数据库。最后,该配置数据库被转储到 .config 文件中。

.config 文件不是内核构建的最终素材;这就是 syncconfig 目标存在的原因。syncconfig曾经是一个名为 silentoldconfig 的配置目标,但它没有做到其旧名称所说的工作,所以它被重命名。此外,因为它是供内部使用的(不适用于用户),所以它已从上述列表中删除。

以下是 syncconfig 的作用:

syncconfig.config 作为输入并输出许多其他文件,这些文件分为三类:

  • auto.conftristate.conf 用于 makefile 文本处理。例如,你可以在组件的 makefile 中看到这样的语句:obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o
  • autoconf.h 用于 C 语言的源文件。
  • include/config/ 下空的头文件用于 kbuild 期间的配置依赖性跟踪。下面会解释。

配置完成后,我们将知道哪些文件和代码片段未编译。

kbuild

组件式构建,称为递归 make,是 GNU make 管理大型项目的常用方法。kbuild 是递归 make 的一个很好的例子。通过将源文件划分为不同的模块/组件,每个组件都由其自己的 makefile 管理。当你开始构建时,顶级 makefile 以正确的顺序调用每个组件的 makefile、构建组件,并将它们收集到最终的执行程序中。

kbuild 指向到不同类型的 makefile:

  • Makefile 位于源代码根目录的顶级 makefile。
  • .config 是内核配置文件。
  • arch/$(ARCH)/Makefile 是架构的 makefile,它用于补充顶级 makefile。
  • scripts/Makefile.* 描述所有的 kbuild makefile 的通用规则。
  • 最后,大约有 500 个 kbuild makefile。

顶级 makefile 会将架构 makefile 包含进去,读取 .config 文件,下到子目录,在 scripts/ Makefile.* 中定义的例程的帮助下,在每个组件的 makefile 上调用 make,构建每个中间对象,并将所有的中间对象链接为 vmlinux。内核文档 Documentation/kbuild/makefiles.txt 描述了这些 makefile 的方方面面。

作为一个例子,让我们看看如何在 x86-64 上生成 vmlinux

 title=

(此插图基于 Richard Y. Steven 的博客。有过更新,并在作者允许的情况下使用。)

进入 vmlinux 的所有 .o 文件首先进入它们自己的 built-in.a,它通过变量KBUILD_VMLINUX_INITKBUILD_VMLINUX_MAINKBUILD_VMLINUX_LIBS 表示,然后被收集到 vmlinux 文件中。

在下面这个简化的 makefile 代码的帮助下,了解如何在 Linux 内核中实现递归 make:

# In top Makefile
vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps)
                +$(call if_changed,link-vmlinux)

# Variable assignments
vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN) $(KBUILD_VMLINUX_LIBS)

export KBUILD_VMLINUX_INIT := $(head-y) $(init-y)
export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y2) $(drivers-y) $(net-y) $(virt-y)
export KBUILD_VMLINUX_LIBS := $(libs-y1)
export KBUILD_LDS          := arch/$(SRCARCH)/kernel/vmlinux.lds

init-y          := init/
drivers-y       := drivers/ sound/ firmware/
net-y           := net/
libs-y          := lib/
core-y          := usr/
virt-y          := virt/

# Transform to corresponding built-in.a
init-y          := $(patsubst %/, %/built-in.a, $(init-y))
core-y          := $(patsubst %/, %/built-in.a, $(core-y))
drivers-y       := $(patsubst %/, %/built-in.a, $(drivers-y))
net-y           := $(patsubst %/, %/built-in.a, $(net-y))
libs-y1         := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2         := $(patsubst %/, %/built-in.a, $(filter-out %.a, $(libs-y)))
virt-y          := $(patsubst %/, %/built-in.a, $(virt-y))

# Setup the dependency. vmlinux-deps are all intermediate objects, vmlinux-dirs
# are phony targets, so every time comes to this rule, the recipe of vmlinux-dirs
# will be executed. Refer "4.6 Phony Targets" of `info make`
$(sort $(vmlinux-deps)): $(vmlinux-dirs) ;

# Variable vmlinux-dirs is the directory part of each built-in.a
vmlinux-dirs    := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
                     $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
                     $(net-y) $(net-m) $(libs-y) $(libs-m) $(virt-y)))

# The entry of recursive make
$(vmlinux-dirs):
                $(Q)$(MAKE) $(build)=$@ need-builtin=1

递归 make 的 配方 recipe 被扩展开是这样的:

make -f scripts/Makefile.build obj=init need-builtin=1

这意味着 make 将进入 scripts/Makefile.build 以继续构建每个 built-in.a。在scripts/link-vmlinux.sh 的帮助下,vmlinux 文件最终位于源根目录下。

vmlinux 与 bzImage 对比

许多 Linux 内核开发人员可能不清楚 vmlinuxbzImage 之间的关系。例如,这是他们在 x86-64 中的关系:

源代码根目录下的 vmlinux 被剥离、压缩后,放入 piggy.S,然后与其他对等对象链接到 arch/x86/boot/compressed/vmlinux。同时,在 arch/x86/boot 下生成一个名为 setup.bin 的文件。可能有一个可选的第三个文件,它带有重定位信息,具体取决于 CONFIG_X86_NEED_RELOCS 的配置。

由内核提供的称为 build 的宿主程序将这两个(或三个)部分构建到最终的 bzImage 文件中。

依赖跟踪

kbuild 跟踪三种依赖关系:

  1. 所有必备文件(*.c*.h
  2. 所有必备文件中使用的 CONFIG_ 选项
  3. 用于编译该目标的命令行依赖项

第一个很容易理解,但第二个和第三个呢? 内核开发人员经常会看到如下代码:

#ifdef CONFIG_SMP
__boot_cpu_id = cpu;
#endif

CONFIG_SMP 改变时,这段代码应该重新编译。编译源文件的命令行也很重要,因为不同的命令行可能会导致不同的目标文件。

.c 文件通过 #include 指令使用头文件时,你需要编写如下规则:

main.o: defs.h
        recipe...

管理大型项目时,需要大量的这些规则;把它们全部写下来会很乏味无聊。幸运的是,大多数现代 C 编译器都可以通过查看源文件中的 #include 行来为你编写这些规则。对于 GNU 编译器集合(GCC),只需添加一个命令行参数:-MD depfile

# In scripts/Makefile.lib
c_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
                 -include $(srctree)/include/linux/compiler_types.h       \
                 $(__c_flags) $(modkern_cflags)                           \
                 $(basename_flags) $(modname_flags)

这将生成一个 .d 文件,内容如下:

init_task.o: init/init_task.c include/linux/kconfig.h \
    include/generated/autoconf.h include/linux/init_task.h \
    include/linux/rcupdate.h include/linux/types.h \
    ...

然后主程序 fixdep 通过将 depfile 文件和命令行作为输入来处理其他两个依赖项,然后以 makefile 格式输出一个 .<target>.cmd 文件,它记录命令行和目标的所有先决条件(包括配置)。 它看起来像这样:

# The command line used to compile the target
cmd_init/init_task.o := gcc -Wp,-MD,init/.init_task.o.d  -nostdinc ...
...
# The dependency files
deps_init/init_task.o := \
    $(wildcard include/config/posix/timers.h) \
    $(wildcard include/config/arch/task/struct/on/stack.h) \
    $(wildcard include/config/thread/info/in/task.h) \
    ...
    include/uapi/linux/types.h \
    arch/x86/include/uapi/asm/types.h \
    include/uapi/asm-generic/types.h \
    ...

在递归 make 中,.<target>.cmd 文件将被包含,以提供所有依赖关系信息并帮助决定是否重建目标。

这背后的秘密是 fixdep 将解析 depfile(.d 文件),然后解析里面的所有依赖文件,搜索所有 CONFIG_ 字符串的文本,将它们转换为相应的空的头文件,并将它们添加到目标的先决条件。每次配置更改时,相应的空的头文件也将更新,因此 kbuild 可以检测到该更改并重建依赖于它的目标。因为还记录了命令行,所以很容易比较最后和当前的编译参数。

展望未来

Kconfig/kbuild 在很长一段时间内没有什么变化,直到新的维护者 Masahiro Yamada 于 2017 年初加入,现在 kbuild 正在再次积极开发中。如果你不久后看到与本文中的内容不同的内容,请不要感到惊讶。


via: https://opensource.com/article/18/10/kbuild-and-kconfig

作者:Cao Jin 选题:lujun9972 译者:wxy 校对:wxy

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

如果你曾经使用过老牌的 MS-DOS,你可能已经使用或听说过 DF-EDIT。DF-EDIT,意即 Directory File Edit,它是一个鲜为人知的 DOS 文件管理器,最初由 Larry Kroeker 为 MS-DOS 和 PC-DOS 系统而编写。它用于在 MS-DOS 和 PC-DOS 系统中显示给定目录或文件的内容。今天,我偶然发现了一个名为 DF-SHOW 的类似实用程序(Directory File Show),这是一个类 Unix 操作系统的终端文件管理器。它是鲜为人知的 DF-EDIT 文件管理器的 Unix 重写版本,其基于 1986 年发布的 DF-EDIT 2.3d。DF-SHOW 完全是自由开源的,并在 GPLv3 下发布。

DF-SHOW 可以:

  • 列出目录的内容,
  • 查看文件,
  • 使用你的默认文件编辑器编辑文件,
  • 将文件复制到不同位置,
  • 重命名文件,
  • 删除文件,
  • 在 DF-SHOW 界面中创建新目录,
  • 更新文件权限,所有者和组,
  • 搜索与搜索词匹配的文件,
  • 启动可执行文件。

DF-SHOW 用法

DF-SHOW 实际上是两个程序的结合,名为 showsf

Show 命令

show 程序(类似于 ls 命令)用于显示目录的内容、创建新目录、重命名和删除文件/文件夹、更新权限、搜索文件等。

要查看目录中的内容列表,请使用以下命令:

$ show <directory path>

示例:

$ show dfshow

这里,dfshow 是一个目录。如果在未指定目录路径的情况下调用 show 命令,它将显示当前目录的内容。

这是 DF-SHOW 默认界面的样子。

如你所见,DF-SHOW 的界面不言自明。

在顶部栏上,你会看到可用的选项列表,例如复制、删除、编辑、修改等。

完整的可用选项列表如下:

  • C opy(复制)
  • D elete(删除)
  • E dit(编辑)
  • H idden(隐藏)
  • M odify(修改)
  • Q uit(退出)
  • R ename(重命名)
  • S how(显示)
  • h U nt(文件内搜索)
  • e X ec(执行)
  • R un command(运行命令)
  • E dit file(编辑文件)
  • H elp(帮助)
  • M ake dir(创建目录)
  • S how dir(显示目录)

在每个选项中,有一个字母以大写粗体标记。只需按下该字母即可执行相应的操作。例如,要重命名文件,只需按 R 并键入新名称,然后按回车键重命名所选项目。

要显示所有选项或取消操作,只需按 ESC 键即可。

此外,你将在 DF-SHOW 界面的底部看到一堆功能键,以浏览目录的内容。

  • UP / DOWN 箭头或 F1 / F2 - 上下移动(一次一行),
  • PgUp / PgDn - 一次移动一页,
  • F3 / F4 - 立即转到列表的顶部和底部,
  • F5 - 刷新,
  • F6 - 标记/取消标记文件(标记的文件将在它们前面用 * 表示),
  • F7 / F8 - 一次性标记/取消标记所有文件,
  • F9 - 按以下顺序对列表排序 - 日期和时间、名称、大小。

h 了解有关 show 命令及其选项的更多详细信息。

要退出 DF-SHOW,只需按 q 即可。

SF 命令

sf (显示文件)用于显示文件的内容。

$ sf <file>

h 了解更多 sf 命令及其选项。要退出,请按 q

想试试看?很好,让我们继续在 Linux 系统上安装 DF-SHOW,如下所述。

安装 DF-SHOW

DF-SHOW 在 AUR 中可用,因此你可以使用 AUR 程序(如 yay)在任何基于 Arch 的系统上安装它。

$ yay -S dfshow

在 Ubuntu 及其衍生版上:

$ sudo add-apt-repository ppa:ian-hawdon/dfshow
$ sudo apt-get update
$ sudo apt-get install dfshow

在其他 Linux 发行版上,你可以从源代码编译和构建它,如下所示。

$ git clone https://github.com/roberthawdon/dfshow
$ cd dfshow
$ ./bootstrap
$ ./configure
$ make
$ sudo make install

DF-SHOW 项目的作者只重写了 DF-EDIT 实用程序的一些应用程序。由于源代码可以在 GitHub 上免费获得,因此你可以添加更多功能、改进代码并提交或修复错误(如果有的话)。它仍处于 beta 阶段,但功能齐全。

你有没试过吗?如果试过,觉得如何?请在下面的评论部分告诉我们你的体验。

不管如何,希望这有用。还有更多好东西。敬请关注!


via: https://www.ostechnix.com/df-show-a-terminal-file-manager-based-on-an-old-dos-application/

作者:SK 选题:lujun9972 译者:wxy 校对:wxy

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

交流是非常重要的。你的电脑可能正试图告诉你一些重要的事情。但是,如果你没有正确配置邮件传输代理(MTA),那么你可能不会收到通知。Postfix 是一个易于配置且以强大的安全记录而闻名)的 MTA。遵循以下步骤,以确保从本地服务发送的电子邮件通知将通过 Postfix MTA 路由到你的互联网电子邮件账户中。

安装软件包

使用 dnf 来安装一些必须软件包(你应该配置了 sudo,对吧?):

$ sudo -i
# dnf install postfix mailx

如果以前配置了不同的 MTA,那么你可能需要将 Postfix 设置为系统默认。使用 alternatives 命令设置系统默认 MTA:

$ sudo alternatives --config mta
There are 2 programs which provide 'mta'.
  Selection    Command
*+ 1           /usr/sbin/sendmail.sendmail
   2           /usr/sbin/sendmail.postfix
Enter to keep the current selection[+], or type selection number: 2

创建一个 password\_maps 文件

你需要创建一个 Postfix 查询表条目,其中包含你要用于发送电子邮件账户的地址和密码:

# [email protected]
# MY_EMAIL_PASSWORD=abcdefghijklmnop
# MY_SMTP_SERVER=smtp.gmail.com
# MY_SMTP_SERVER_PORT=587
# echo "[$MY_SMTP_SERVER]:$MY_SMTP_SERVER_PORT $MY_EMAIL_ADDRESS:$MY_EMAIL_PASSWORD" >> /etc/postfix/password_maps
# chmod 600 /etc/postfix/password_maps
# unset MY_EMAIL_PASSWORD
# history -c

如果你使用的是 Gmail 账户,那么你需要为 Postfix 配置一个“应用程序密码”而不是使用你的 Gmail 密码。有关配置应用程序密码的说明,参阅“使用应用程序密码登录”。

接下来,你必须对 Postfix 查询表运行 postmap 命令,以创建或更新 Postfix 实际使用的文件的散列版本:

# postmap /etc/postfix/password_maps

散列后的版本将具有相同的文件名,但后缀为 .db

更新 main.cf 文件

更新 Postfix 的 main.cf 配置文件,以引用刚刚创建 Postfix 查询表。编辑该文件并添加以下行:

relayhost = smtp.gmail.com:587
smtp_tls_security_level = verify
smtp_tls_mandatory_ciphers = high
smtp_tls_verify_cert_match = hostname
smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/password_maps

这里假设你使用 Gmail 作为 relayhost 设置,但是你可以用正确的主机名和端口替换系统应该将邮件发送到的邮件主机。

有关上述配置选项的最新详细信息,参考 man 帮助:

$ man postconf.5

启用、启动和测试 Postfix

更新 main.cf 文件后,启用并启动 Postfix 服务:

# systemctl enable --now postfix.service

然后,你可以使用 exit 命令或 Ctrl+D 以 root 身份退出 sudo 会话。你现在应该能够使用 mail 命令测试你的配置:

$ echo 'It worked!' | mail -s "Test: $(date)" [email protected]

更新服务

如果你安装了像 logwatchmdadmfail2banapcupsdcertwatch 这样的服务,你现在可以更新它们的配置,以便它们的电子邮件通知转到你的 Internet 电子邮件地址。

另外,你可能希望将发送到本地系统 root 账户的所有电子邮件都转到互联网电子邮件地址中,将以下行添加到系统的 /etc/alises 文件中(你需要使用 sudo 编辑此文件,或首先切换到 root 账户):

root: [email protected]

现在运行此命令重新读取别名:

# newaliases
  • 提示: 如果你使用的是 Gmail,那么你可以在用户名和 @ 符号之间添加字母数字标记,如上所示,以便更轻松地识别和过滤从计算机收到的电子邮件。

常用命令

查看邮件队列:

$ mailq

清除队列中的所有电子邮件:

# postsuper -d ALL

过滤设置,以获得感兴趣的值:

$ postconf | grep "^relayhost\|^smtp_"

查看 postfix/smtp 日志:

$ journalctl --no-pager -t postfix/smtp

进行配置更改后重新加载 postfix:

$ systemctl reload postfix

via: https://fedoramagazine.org/use-postfix-to-get-email-from-your-fedora-system/

作者:Gregory Bartholomew 选题:lujun9972 译者:MjSeven 校对:wxy

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

从计算机自由先驱的口中探寻操作系统兼容性标准背后的本质。

POSIX 是什么?为什么如此重要?你可能在很多的技术类文章中看到这个术语,但往往会在探寻其本质时迷失在 技术初始主义 techno-initialisms 的海洋或是 以 X 结尾的行话 jargon-that-ends-in-X 中。我给 Richard Stallman 博士(在黑客圈里面常称之为 RMS)发了邮件以探寻这个术语的起源及其背后的概念。

Richard Stallman 认为用 “开源” 和 “闭源” 来归类软件是一种错误的方法。Stallman 将程序分类为 尊重自由的 freedom-respecting (“ 自由 free ” 或 “ 自由(西语) libre ”)和 践踏自由的 freedom-trampling (“ 非自由 non-free ” 或 “ 专有 proprietary ”)。开源讨论通常会为了(用户)实际得到的 优势/便利 advantages 考虑去鼓励某些做法,而非作为道德层面上的约束。

Stallman 在由其本人于 1984 年发起的 自由软件运动 The free software movement 表明,不仅仅是这些 优势/便利 advantages 受到了威胁。计算机的用户 理应得到 deserve 计算机的控制权,因此拒绝被用户控制的程序即是 非正义 injustice ,理应被 拒绝 rejected 排斥 eliminated 。对于用户的控制权,程序应当给予用户 四项基本自由

  • 自由度 0:无论用户出于何种目的,必须可以按照用户意愿,自由地运行该软件。
  • 自由度 1:用户可以自由地学习并修改该软件,以便按照自己的意愿进行计算。作为前提,用户必须可以访问到该软件的源代码。
  • 自由度 2:用户可以自由地分发该软件的副本,以便可以帮助他人。
  • 自由度 3:用户可以自由地分发该软件修改后的副本。借此,你可以让整个社区受益于你的改进。作为前提,用户必须可以访问到该软件的源代码。

关于 POSIX

Seth: POSIX 标准是由 IEEE 发布,用于描述 “ 可移植操作系统 portable operating system ” 的文档。只要开发人员编写符合此描述的程序,他们生产的便是符合 POSIX 的程序。在科技行业,我们称之为 “ 规范 specification ” 或将其简写为 “spec”。就技术用语而言,这是可以理解的,但我们不禁要问是什么使操作系统 “可移植”?

RMS: 我认为是 接口 interface 应该(在不同系统之间)是可移植的,而非任何一种系统。实际上,内部构造不同的各种系统都支持部分的 POSIX 接口规范。

Seth: 因此,如果两个系统皆具有符合 POSIX 的程序,那么它们便可以彼此假设,从而知道如何相互 “交谈”。我了解到 “POSIX” 这个简称是你想出来的。那你是怎么想出来的呢?它是如何就被 IEEE 采纳了呢?

RMS: IEEE 已经完成了规范的开发,但还没为其想好简练的名称。标题类似是 “可移植操作系统接口”,虽然我已记不清确切的单词。委员会倾向于将 “IEEEIX” 作为简称。而我认为那不太好。发音有点怪 - 听起来像恐怖的尖叫,“Ayeee!” - 所以我觉得人们反而会倾向于称之为 “Unix”。

但是,由于 GNU 并不是 Unix GNU’s Not Unix ,并且它打算取代之,我不希望人们将 GNU 称为 “Unix 系统”。因此,我提出了人们可能会实际使用的简称。那个时候也没有什么灵感,我就用了一个并不是非常聪明的方式创造了这个简称:我使用了 “ 可移植操作系统 portable operating system ” 的首字母缩写,并在末尾添加了 “ix” 作为简称。IEEE 也欣然接受了。

Seth: POSIX 缩写中的 “操作系统” 是仅涉及 Unix 和类 Unix 的系统(如 GNU)呢?还是意图包含所有操作系统?

RMS: 术语 “操作系统” 抽象地说,涵盖了完全不像 Unix 的系统、完全和 POSIX 规范无关的系统。但是,POSIX 规范适用于大量类 Unix 系统;也只有这样的系统才适合 POSIX 规范。

Seth: 你是否参与审核或更新当前版本的 POSIX 标准?

RMS: 现在不了。

Seth: GNU Autotools 工具链可以使应用程序更容易移植,至少在构建和安装时如此。所以可以认为 Autotools 是构建可移植基础设施的重要一环吗?

RMS: 是的,因为即使在遵循 POSIX 的系统中,也存在着诸多差异。而 Autotools 可以使程序更容易适应这些差异。顺带一提,如果有人想助力 Autotools 的开发,可以发邮件联系我。

Seth: 我想,当 GNU 刚刚开始让人们意识到一个非 Unix 的系统可以从专有的技术中解放出来的时候,关于自由软件如何协作方面,这其间一定存在一些空白区域吧。

RMS: 我不认为有任何空白或不确定性。我只是照着 BSD 的接口写而已。

Seth: 一些 GNU 应用程序符合 POSIX 标准,而另一些 GNU 应用程序的 GNU 特定的功能,要么不在 POSIX 规范中,要么缺少该规范要求的功能。对于 GNU 应用程序 POSIX 合规性有多重要?

RMS: 遵循标准对于利于用户的程度很重要。我们不将标准视为权威,而是且将其作为可能有用的指南来遵循。因此,我们谈论的是 遵循 following 标准而不是“ 遵守 complying ”。可以参考 GNU 编码标准 GNU Coding Standards 中的 非 GNU 标准 段落。

我们努力在大多数问题上与标准兼容,因为在大多数的问题上这最有利于用户。但也偶有例外。

例如,POSIX 指定某些实用程序以 512 字节为单位测量磁盘空间。我要求委员会将其改为 1K,但被拒绝了,说是有个 官僚主义的规则 bureaucratic rule 强迫选用 512。我不记得有多少人试图争辩说,用户会对这个决定感到满意的。

由于 GNU 在用户的 自由 freedom 之后的第二优先级,是用户的 便利 convenience ,我们使 GNU 程序以默认 1K 为单位按块测量磁盘空间。

然而,为了防止竞争对手利用这点给 GNU 安上 “ 不合规 noncompliant ” 的骂名,我们实现了遵循 POSIX 和 ISO C 的可选模式,这种妥协着实可笑。想要遵循 POSIX,只需设置环境变量 POSIXLY_CORRECT,即可使程序符合 POSIX 以 512 字节为单位列出磁盘空间。如果有人知道实际使用 POSIXLY_CORRECT 或者 GCC 中对应的 --pedantic 会为某些用户提供什么实际好处的话,请务必告诉我。

Seth: 符合 POSIX 标准的自由软件项目是否更容易移植到其他类 Unix 系统?

RMS: 我认为是这样,但自上世纪 80 年代开始,我决定不再把时间浪费在将软件移植到 GNU 以外的系统上。我开始专注于推进 GNU 系统,使其不必使用任何非自由软件。至于将 GNU 程序移植到非类 GNU 系统就留给想在其他系统上运行它们的人们了。

Seth: POSIX 对于软件的自由很重要吗?

RMS: 本质上说,(遵不遵循 POSIX)其实没有任何区别。但是,POSIX 和 ISO C 的标准化确实使 GNU 系统更容易迁移,这有助于我们更快地实现从非自由软件中解放用户的目标。这个目标于上世纪 90 年代早期达成,当时Linux成为自由软件,同时也填补了 GNU 中内核的空白。

POSIX 采纳 GNU 的创新

我还问过 Stallman 博士,是否有任何 GNU 特定的创新或惯例后来被采纳为 POSIX 标准。他无法回想起具体的例子,但友好地代我向几位开发者发了邮件。

开发者 Giacomo Catenazzi,James Youngman,Eric Blake,Arnold Robbins 和 Joshua Judson Rosen 对以前的 POSIX 迭代以及仍在进行中的 POSIX 迭代做出了回应。POSIX 是一个 “ 活的 living ” 标准,因此会不断被行业专业人士更新和评审,许多从事 GNU 项目的开发人员提出了对 GNU 特性的包含。

为了回顾这些有趣的历史,接下来会罗列一些已经融入 POSIX 的流行的 GNU 特性。

Make

一些 GNU Make 的特性已经被 POSIX 的 make 定义所采用。相关的 规范 提供了从现有实现中借来的特性的详细归因。

Diff 和 patch

diffpatch 命令都直接从这些工具的 GNU 版本中引进了 -u-U 选项。

C 库

POSIX 采用了 GNU C 库 glibc 的许多特性。 血统 Lineage 一时已难以追溯,但 James Youngman 如是写道:

“我非常确定 GCC 首创了许多 ISO C 的特性。例如,\_Noreturn 是 C11 中的新特性,但 GCC-1.35 便具有此功能(使用 volatile 作为声明函数的修饰符)。另外尽管我不确定,GCC-1.35 支持的可变长度数组似乎与现代 C 中的( 柔性数组 conformant array )非常相似。”

Giacomo Catenazzi 援引 Open Group 的 strftime 文章,并指出其归因:“这是基于某版本 GNU libc 的 strftime() 的特性。”

Eric Blake 指出,对于 getline() 和各种基于语言环境的 *_l() 函数,GNU 绝对是这方面的先驱。

Joshua Judson Rosen 补充道,他清楚地记得,在全然不同的操作系统的代码中奇怪地目睹了熟悉的 GNU 式的行为后,对 getline() 函数的采用给他留下了深刻的印象。

“等等……那不是 GNU 特有的吗?哦,显然已经不再是了。”

Rosen 向我指出了 getline 手册页 中写道:

getline()getdelim() 最初都是 GNU 扩展。在 POSIX.1-2008 中被标准化。

Eric Blake 向我发送了一份其他扩展的列表,这些扩展可能会在下一个 POSIX 修订版中添加(代号为 Issue 8,大约在 2021 年前后):

关于用户空间的扩展

POSIX 不仅为开发人员定义了函数和特性,还为用户空间定义了标准行为。

ls

-A 选项会排除来自 ls 命令结果中的符号 .(代表当前位置)和 ..(代表上一级目录)。它被 POSIX 2008 采纳。

find

find 命令是一个 特别的 ad hoc for 循环 工具,也是 并行 parallel 处理的出入口。

一些从 GNU 引入到 POSIX 的 便捷操作 conveniences ,包括 -path-perm 选项。

-path 选项帮你过滤与文件系统路径模式匹配的搜索结果,并且从 1996 年(根据 findutil 的 Git 仓库中最早的记录)GNU 版本的 find 便可使用此选项。James Youngman 指出 HP-UX 也很早就有这个选项,所以究竟是 GNU 还是 HP-UX 做出的这一创新(抑或两者兼而有之)无法考证。

-perm 选项帮你按文件权限过滤搜索结果。这在 1996 年 GNU 版本的 find 中便已存在,随后被纳入 POSIX 标准 “IEEE Std 1003.1,2004 Edition” 中。

xargs 命令是 findutils 软件包的一部分,1996 年的时候就有一个 -p 选项会将 xargs 置于交互模式(用户将被提示是否继续),随后被纳入 POSIX 标准 “IEEE Std 1003.1, 2004 Edition” 中。

Awk

GNU awk(即 /usr/bin 目录中的 gawk 命令,可能也是符号链接 awk 的目标地址)的维护者 Arnold Robbins 说道,gawkmawk(另一个GPL 的 awk 实现)允许 RS(记录分隔符)是一个正则表达式,即这时 RS 的长度会大于 1。这一特性还不是 POSIX 的特性,但有 迹象表明它即将会是

NUL 在扩展正则表达式中产生的未定义行为允许 GNU gawk 程序未来可以扩展以处理二进制数据。

使用多字符 RS 值的未指定行为是为了未来可能的扩展,它是基于用于记录分隔符(RS)的扩展正则表达式的。目前的历史实现为采用该字符串的第一个字符而忽略其他字符。

这是一个重大的增强,因为 RS 符号定义了记录之间的分隔符。可能是逗号、分号、短划线、或者是任何此类字符,但如果它是字符序列,则只会使用第一个字符,除非你使用的是 gawkmawk。想象一下这种情况,使用省略号(连续的三个点)作为解析 IP 地址文档的分隔记录,只是想获取在每个 IP 地址的每个点处解析的结果。

mawk 首先支持这个功能,但是几年来没有维护者,留下来的火把由 gawk 接过。(mawk 已然获得了一个新的维护者,可以说是大家薪火传承地将这一特性推向共同的预期值。)

POSIX 规范

总的来说,Giacomo Catenzzi 指出,“……因为 GNU 的实用程序使用广泛,而且许多其他的选项和行为又对标规范。在 shell 的每次更改中,Bash 都会(作为一等公民)被用作比较。” 当某些东西被纳入 POSIX 规范时,无需提及 GNU 或任何其他影响,你可以简单地认为 POSIX 规范会受到许多方面的影响,GNU 只是其中之一。

共识是 POSIX 存在的意义所在。一群技术人员共同努力为了实现共同规范,再分享给数以百计各异的开发人员,经由他们的赋能,从而实现软件的独立性,以及开发人员和用户的自由。


via: https://opensource.com/article/19/7/what-posix-richard-stallman-explains

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

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

获取我们关于安装两者的简化说明。

 title=

如果你渴望学习基于开源 Lucene 库的著名开源搜索引擎 Elasticsearch,那么没有比在本地安装它更好的方法了。这个过程在 Elasticsearch 网站中有详细介绍,但如果你是初学者,官方说明就比必要的信息多得多。本文采用一种简化的方法。

添加 Elasticsearch 仓库

首先,将 Elasticsearch 仓库添加到你的系统,以便你可以根据需要安装它并接收更新。如何做取决于你的发行版。在基于 RPM 的系统上,例如 FedoraCentOSRed Hat Enterprise Linux(RHEL)openSUSE,(本文任何地方引用 Fedora 或 RHEL 的也适用于 CentOS 和 openSUSE)在 /etc/yum.repos.d/ 中创建一个名为 elasticsearch.repo 的仓库描述文件:

$ cat << EOF | sudo tee /etc/yum.repos.d/elasticsearch.repo
[elasticsearch-7.x]
name=Elasticsearch repository for 7.x packages
baseurl=https://artifacts.elastic.co/packages/oss-7.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
EOF

在 Ubuntu 或 Debian 上,不要使用 add-apt-repository 工具。由于它自身默认的和 Elasticsearch 仓库提供的不匹配而导致错误。相反,设置这个:

$ echo "deb https://artifacts.elastic.co/packages/oss-7.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-7.x.list

在你从该仓库安装之前,导入 GPG 公钥,然后更新:

$ sudo apt-key adv --keyserver \
hkp://keyserver.ubuntu.com:80 \
--recv D27D666CD88E42B4
$ sudo apt update

此存储库仅包含 Elasticsearch 的开源功能,在 Apache 许可证下发布,没有提供订阅版本的额外功能。如果你需要仅限订阅的功能(这些功能是并不开源),那么 baseurl 必须设置为:

baseurl=https://artifacts.elastic.co/packages/7.x/yum

安装 Elasticsearch

你需要安装的软件包的名称取决于你使用的是开源版本还是订阅版本。本文使用开源版本,包名最后有 -oss 后缀。如果包名后没有 -oss,那么表示你请求的是仅限订阅版本。

如果你创建了订阅版本的仓库却尝试安装开源版本,那么就会收到“非指定”的错误。如果你创建了一个开源版本仓库却没有将 -oss 添加到包名后,那么你也会收到错误。

使用包管理器安装 Elasticsearch。例如,在 Fedora、CentOS 或 RHEL 上运行以下命令:

$ sudo dnf install elasticsearch-oss

在 Ubuntu 或 Debian 上,运行:

$ sudo apt install elasticsearch-oss

如果你在安装 Elasticsearch 时遇到错误,那么你可能安装的是错误的软件包。如果你想如本文这样使用开源包,那么请确保使用正确的 apt 仓库或在 Yum 配置正确的 baseurl

启动并启用 Elasticsearch

安装 Elasticsearch 后,你必须启动并启用它:

$ sudo systemctl daemon-reload
$ sudo systemctl enable --now elasticsearch.service

要确认 Elasticsearch 在其默认端口 9200 上运行,请在 Web 浏览器中打开 localhost:9200。你可以使用 GUI 浏览器,也可以在终端中执行此操作:

$ curl localhost:9200
{

  "name" : "fedora30",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "OqSbb16NQB2M0ysynnX1hA",
  "version" : {
    "number" : "7.2.0",
    "build_flavor" : "oss",
    "build_type" : "rpm",
    "build_hash" : "508c38a",
    "build_date" : "2019-06-20T15:54:18.811730Z",
    "build_snapshot" : false,
    "lucene_version" : "8.0.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

安装 Kibana

Kibana 是 Elasticsearch 数据可视化的图形界面。它包含在 Elasticsearch 仓库,因此你可以使用包管理器进行安装。与 Elasticsearch 本身一样,如果你使用的是 Elasticsearch 的开源版本,那么必须将 -oss 放到包名最后,订阅版本则不用(两者安装需要匹配):

$ sudo dnf install kibana-oss

在 Ubuntu 或 Debian 上:

$ sudo apt install kibana-oss

Kibana 在端口 5601 上运行,因此打开图形化 Web 浏览器并进入 localhost:5601 来开始使用 Kibana,如下所示:

 title=

故障排除

如果在安装 Elasticsearch 时出现错误,请尝试手动安装 Java 环境。在 Fedora、CentOS 和 RHEL 上:

$ sudo dnf install java-openjdk-devel java-openjdk

在 Ubuntu 上:

$ sudo apt install default-jdk

如果所有其他方法都失败,请尝试直接从 Elasticsearch 服务器安装 Elasticsearch RPM:

$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-7.2.0-x86_64.rpm{,.sha512}
$ shasum -a 512 -c elasticsearch-oss-7.2.0-x86_64.rpm.sha512 && sudo rpm --install elasticsearch-oss-7.2.0-x86_64.rpm

在 Ubuntu 或 Debian 上,请使用 DEB 包。

如果你无法使用 Web 浏览器访问 Elasticsearch 或 Kibana,那么可能是你的防火墙阻止了这些端口。你可以通过调整防火墙设置来允许这些端口上的流量。例如,如果你运行的是 firewalld(Fedora 和 RHEL 上的默认防火墙,并且可以在 Debian 和 Ubuntu 上安装),那么你可以使用 firewall-cmd

$ sudo firewall-cmd --add-port=9200/tcp --permanent
$ sudo firewall-cmd --add-port=5601/tcp --permanent
$ sudo firewall-cmd --reload

设置完成了,你可以关注我们接下来的 Elasticsearch 和 Kibana 安装文章。


via: https://opensource.com/article/19/7/install-elasticsearch-and-kibana-linux

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

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

你可能设置过 cron 任务 来在特定时间备份重要文件或执行系统相关任务。也许你配置了一个日志服务器在特定时间间隔轮转日志。但如果你的时钟不同步,这些任务将无法按时执行。这就是要在 Linux 系统上设置正确的时区并保持时钟与互联网同步的原因。本指南介绍如何在 Ubuntu Linux 上设置时间同步。下面的步骤已经在 Ubuntu 18.04 上进行了测试,但是对于使用 systemd 的 timesyncd 服务的其他基于 Ubuntu 的系统它们是相同的。

在 Ubuntu 上设置时间同步

通常,我们在安装时设置时区。但是,你可以根据需要更改或设置不同的时区。

首先,让我们使用 date 命令查看 Ubuntu 系统中的当前时区:

$ date

示例输出:

Tue Jul 30 11:47:39 UTC 2019

如上所见,date 命令显示实际日期和当前时间。这里,我当前的时区是 UTC,代表协调世界时

或者,你可以在 /etc/timezone 文件中查找当前时区。

$ cat /etc/timezone
UTC

现在,让我们看看时钟是否与互联网同步。只需运行:

$ timedatectl

示例输出:

Local time: Tue 2019-07-30 11:53:58 UTC
Universal time: Tue 2019-07-30 11:53:58 UTC
RTC time: Tue 2019-07-30 11:53:59
Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
systemd-timesyncd.service active: yes
RTC in local TZ: no

如你所见,timedatectl 命令显示本地时间、世界时、时区以及系统时钟是否与互联网服务器同步,以及 systemd-timesyncd.service 是处于活动状态还是非活动状态。就我而言,系统时钟已与互联网时间服务器同步。

如果时钟不同步,你会看到下面截图中显示的 System clock synchronized: no

时间同步已禁用。

注意:上面的截图是旧截图。这就是你看到不同日期的原因。

如果你看到 System clock synchronized: 值设置为 no,那么 timesyncd 服务可能处于非活动状态。因此,只需重启服务并看下是否正常。

$ sudo systemctl restart systemd-timesyncd.service

现在检查 timesyncd 服务状态:

$ sudo systemctl status systemd-timesyncd.service
● systemd-timesyncd.service - Network Time Synchronization
Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2019-07-30 10:50:18 UTC; 1h 11min ago
Docs: man:systemd-timesyncd.service(8)
Main PID: 498 (systemd-timesyn)
Status: "Synchronized to time server [2001:67c:1560:8003::c7]:123 (ntp.ubuntu.com)."
Tasks: 2 (limit: 2319)
CGroup: /system.slice/systemd-timesyncd.service
└─498 /lib/systemd/systemd-timesyncd

Jul 30 10:50:30 ubuntuserver systemd-timesyncd[498]: Network configuration changed, trying to estab
Jul 30 10:50:31 ubuntuserver systemd-timesyncd[498]: Network configuration changed, trying to estab
Jul 30 10:50:31 ubuntuserver systemd-timesyncd[498]: Network configuration changed, trying to estab
Jul 30 10:50:32 ubuntuserver systemd-timesyncd[498]: Network configuration changed, trying to estab
Jul 30 10:50:32 ubuntuserver systemd-timesyncd[498]: Network configuration changed, trying to estab
Jul 30 10:50:35 ubuntuserver systemd-timesyncd[498]: Network configuration changed, trying to estab
Jul 30 10:50:35 ubuntuserver systemd-timesyncd[498]: Network configuration changed, trying to estab
Jul 30 10:50:35 ubuntuserver systemd-timesyncd[498]: Network configuration changed, trying to estab
Jul 30 10:50:35 ubuntuserver systemd-timesyncd[498]: Network configuration changed, trying to estab
Jul 30 10:51:06 ubuntuserver systemd-timesyncd[498]: Synchronized to time server [2001:67c:1560:800

如果此服务已启用并处于活动状态,那么系统时钟应与互联网时间服务器同步。

你可以使用命令验证是否启用了时间同步:

$ timedatectl

如果仍然不起作用,请运行以下命令以启用时间同步:

$ sudo timedatectl set-ntp true

现在,你的系统时钟将与互联网时间服务器同步。

使用 timedatectl 命令更改时区

如果我想使用 UTC 以外的其他时区怎么办?这很容易!

首先,使用命令列出可用时区:

$ timedatectl list-timezones

你将看到类似于下图的输出。

使用 timedatectl 命令列出时区

你可以使用以下命令设置所需的时区(例如,Asia/Shanghai):

(LCTT 译注:本文原文使用印度时区作为示例,这里为了便于使用,换为中国标准时区 CST。另外,在时区设置中,要注意 CST 这个缩写会代表四个不同的时区,因此建议使用城市和 UTC+8 来说设置。)

$ sudo timedatectl set-timezone Asia/Shanghai

使用 date 命令再次检查时区是否已真正更改:

$ date
Tue Jul 30 20:22:33 CST 2019

或者,如果需要详细输出,请使用 timedatectl 命令:

$ timedatectl
Local time: Tue 2019-07-30 20:22:35 CST
Universal time: Tue 2019-07-30 12:22:35 UTC
RTC time: Tue 2019-07-30 12:22:36
Time zone: Asia/Shanghai (CST, +0800)
System clock synchronized: yes
systemd-timesyncd.service active: yes
RTC in local TZ: no

如你所见,我已将时区从 UTC 更改为 CST(中国标准时间)。()

要切换回 UTC 时区,只需运行:

$ sudo timedatectl set-timezone UTC

使用 tzdata 更改时区

在较旧的 Ubuntu 版本中,没有 timedatectl 命令。这种情况下,你可以使用 tzdata(Time zone data)来设置时间同步。

$ sudo dpkg-reconfigure tzdata

选择你居住的地理区域。对我而言,我选择 Asia。选择 OK,然后按回车键。

接下来,选择与你的时区对应的城市或地区。这里,我选择了 Kolkata(LCTT 译注:中国用户请相应使用 Shanghai 等城市)。

最后,你将在终端中看到类似下面的输出。

Current default time zone: 'Asia/Shanghai'
Local time is now: Tue Jul 30 21:59:25 CST 2019.
Universal Time is now: Tue Jul 30 13:59:25 UTC 2019.

在图形模式下配置时区

有些用户可能对命令行方式不太满意。如果你是其中之一,那么你可以轻松地在图形模式的系统设置面板中进行设置。

点击 Super 键(Windows 键),在 Ubuntu dash 中输入 settings,然后点击设置图标。

从 Ubuntu dash 启动系统的设置

或者,单击位于 Ubuntu 桌面右上角的向下箭头,然后单击左上角的“设置”图标。

从顶部面板启动系统的设置

在下一个窗口中,选择“细节”,然后单击“日期与时间”选项。打开“自动的日期与时间”和“自动的时区”。

在 Ubuntu 中设置自动时区

关闭设置窗口就行了!你的系统始终应该与互联网时间服务器同步了。


via: https://www.ostechnix.com/how-to-set-up-time-synchronization-on-ubuntu/

作者:sk 选题:lujun9972 译者:geekpi 校对:wxy

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