Linux中国
1.73K subscribers
777 photos
6.34K links
Linux 中国官方 Telegram 频道
Download Telegram
基于命令行的任务管理器 Taskwarrior

Taskwarrior 在命令行里管理你的 TODO 列表。它灵活,快速,高效,不显眼,它默默做自己的事情让你避免自己管理。Media

via https://linux.cn/article-9644-1.html
探秘“栈”之旅

栈非常重要,因为它追踪着一个程序中运行的函数,而函数又是一个软件的重要组成部分。Media

via https://linux.cn/article-9645-1.html
探秘“栈”之旅

Media早些时候,我们探索了 “内存中的程序之秘”,我们欣赏了在一台电脑中是如何运行我们的程序的。今天,我们去探索栈的调用,它在大多数编程语言和虚拟机中都默默地存在。在此过程中,我们将接触到一些平时很难见到的东西,像闭包closure、递归、以及缓冲溢出等等。但是,我们首先要作的事情是,描绘出栈是如何运作的。栈非常重要,因为它追踪着一个程序中运行的函数,而函数又是一个软件的重要组成部分。事实上,程序的内部操作都是非常简单的。它大部分是由函数向栈中推入数据或者从栈中弹出数据的相互调用组成的,而在堆上为数据分配内存才能在跨函数的调用中保持数据。不论是低级的 C 软件还是像 JavaScript 和 C# 这样的基于虚拟机的语言,它们都是这样的。而对这些行为的深刻理解,对排错、性能调优以及大概了解究竟发生了什么是非常重要的。当一个函数被调用时,将会创建一个栈帧stack frame去支持函数的运行。这个栈帧包含函数的局部变量和调用者传递给它的参数。这个栈帧也包含了允许被调用的函数(callee)安全返回给其调用者的内部事务信息。栈帧的精确内容和结构因处理器架构和函数调用规则而不同。在本文中我们以 Intel x86 架构和使用 C 风格的函数调用(cdecl)的栈为例。下图是一个处于栈顶部的一个单个栈帧:Media在图上的场景中,有三个 CPU 寄存器进入栈。栈指针stack pointer esp(LCTT 译注:扩展栈指针寄存器) 指向到栈的顶部。栈的顶部总是被最后一个推入到栈且还没有弹出的东西所占据,就像现实世界中堆在一起的一叠盘子或者 100 美元大钞一样。保存在 esp 中的地址始终在变化着,因为栈中的东西不停被推入和弹出,而它总是指向栈中的最后一个推入的东西。许多 CPU 指令的一个副作用就是自动更新 esp,离开寄存器而使用栈是行不通的。在 Intel 的架构中,绝大多数情况下,栈的增长是向着低位内存地址的方向。因此,这个“顶部” 在包含数据的栈中是处于低位的内存地址(在这种情况下,包含的数据是 local_buffer)。注意,关于从 esp 到 local_buffer 的箭头不是随意连接的。这个箭头代表着事务:它专门指向到由 local_buffer 所拥有的第一个字节,因为,那是一个保存在 esp 中的精确地址。第二个寄存器跟踪的栈是 ebp(LCTT 译注:扩展基址指针寄存器),它包含一个基指针base pointer或者称为帧指针frame pointer。它指向到一个当前运行的函数的栈帧内的固定位置,并且它为参数和局部变量的访问提供一个稳定的参考点(基址)。仅当开始或者结束调用一个函数时,ebp 的内容才会发生变化。因此,我们可以很容易地处理在栈中的从 ebp 开始偏移后的每个东西。如图所示。不像 esp, ebp 大多数情况下是在程序代码中通过花费很少的 CPU 来进行维护的。有时候,完成抛弃 ebp 有一些性能优势,可以通过 编译标志 来做到这一点。Linux 内核就是一个这样做的示例。最后,eax(LCTT 译注:扩展的 32 位通用数据寄存器)寄存器惯例被用来转换大多数 C 数据类型返回值给调用者。现在,我们来看一下在我们的栈帧中的数据。下图清晰地按字节展示了字节的内容,就像你在一个调试器中所看到的内容一样,内存是从左到右、从顶部至底部增长的,如下图所示:Media局部变量 local_buffer 是一个字节数组,包含一个由 null 终止的 ASCII 字符串,这是 C 程序中的一个基本元素。这个字符串可以读取自任意地方,例如,从键盘输入或者来自一个文件,它只有 7 个字节的长度。因为,local_buffer 只能保存 8 字节,所以还剩下 1 个未使用的字节。这个字节的内容是未知的,因为栈不断地推入和弹出,除了你写入的之外,你根本不会知道内存中保存了什么。这是因为 C 编译器并不为栈帧初始化内存,所以它的内容是未知的并且是随机的 —— 除非是你自己写入。这使得一些人对此很困惑。再往上走,local1 是一个 4 字节的整数,并且你可以看到每个字节的内容。它似乎是一个很大的数字,在8 后面跟着的都是零,在这里可能会误导你。Intel 处理器是小端little endian机器,这表示在内存中的数字也是首先从小的一端开始的。因此,在一个多字节数字中,较小的部分在内存中处于最低端的地址。因为一般情况下是从左边开始显示的,这背离了我们通常的数字表示方式。我们讨论的这种从小到大的机制,使我想起《格里佛游记》:就像小人国的人们吃鸡蛋是从小头开始的一样,Intel 处理器处理它们的数字也是从字节的小端开始的。因此,local1 事实上只保存了一个数字 8,和章鱼的腿数量一样。然而,param1 在第二个字节的位置有一个值 2,因此,它的数学上的值是 2 * 256 = 512(我们与 256 相乘是因为,每个位置值的范围都是从 0 到 255)。同时,param2 承载的数量是 1 * 256 * 256 = 65536。这个栈帧的内部数据是由两个重要的部分组成:前一个栈帧的地址(保存的 ebp 值)和函数退出才会运行的指令的地址(返回地址)。它们一起确保了函数能够正常返回,从而使程序可以继续正常运行。现在,我们来看一下栈帧是如何产生的,以及去建立一个它们如何共同工作的内部蓝图。首先,栈的增长是非常令人困惑的,因为它与你你预期的方式相反。例如,在栈上分配一个 8 字节,就要从 esp 减去 8,去,而减法是与增长不同的奇怪方式。我们来看一个简单的 C 程序:
Simple Add Program - add.cint add(int a, int b){ int result = a + b; return result;}int main(int argc){ int answer; answer = add(40, 2);}
简单的加法程序 - add.c假设我们在 Linux 中不使用命令行参数去运行它。当你运行一个 C 程序时,实际运行的第一行代码是在 C 运行时库里,由它来调用我们的 main 函数。下图展示了程序运行时每一步都发生了什么。每个图链接的 GDB 输出展示了内存和寄存器的状态。你也可以看到所使用的 GDB 命令,以及整个 GDB 输出。如下:Media第 2 步和第 3 步,以及下面的第 4 步,都只是函数的序言prologue,几乎所有的函数都是这样的:ebp 的当前值被保存到了栈的顶部,然后,将 esp 的内容拷贝到 ebp,以建立一个新的栈帧。main 的序言和其它函数一样,但是,不同之处在于,当程序启动时 ebp 被清零。如果你去检查栈下方(右边)的整形变量(argc),你将找到更多的数据,包括指向到程序名和命令行参数(传统的 C 的 argv)、以及指向 Unix 环境变量以及它们真实的内容的指针。但是,在这里这些并不是重点,因此,继续向前调用 add():Media在 main 从 esp 减去 12 之后得到它所需的栈空间,它为 a 和 b 设置值。在内存中的值展示为十六进制,并且是小端格式,与你从调试器中看到的一样。一旦设置了参数值,main 将调用 add,并且开始运行:Media现在,有一点小激动!我们进入了另一个函数序言,但这次你可以明确看到栈帧是如何从 ebp 到栈建立一个链表。这就是调试器和高级语言中的 Exception 对象如何对它们的栈进行跟踪的。当一个新帧产生时,你也可以看到更多这种典型的从 ebp 到 esp 的捕获。我们再次从 esp 中做减法得到更多的栈空间。当 ebp 寄存器的值拷贝到内存时,这里也有一个稍微有些怪异的字节逆转。在这里发生的奇怪事情是,寄存器其实并没有字节顺序:因为对于内存,没有像寄存器那样的“增长的地址”。因此,惯例上调试器以对人类来说最自然的格式展示了寄存器的值:数位从最重要的到最不重要。因此,这个在小端机器中的副本的结果,与内存中常用的从左到右的标记法正好相反。我想用图去展示你将会看到的东西,因此有了下面的图。在比较难懂的部分,我们增加了注释:Media这是一个临时寄存器,用于帮你做加法,因此没有什么警报或者惊喜。对于加法这样的作业,栈的动作正好相反,我们留到下次再讲。对于任何读到这里的人都应该有一个小礼物,因此,我做了一个大的图表展示了 组合到一起的所有步骤。一旦把它们全部布置好了,看上起似乎很乏味。这些小方框给我们提供了很多帮助。事实上,在计算机科学中,这些小方框是主要的展示工具。我希望这些图片和寄存器的移动能够提供一种更直观的构想图,将栈的增长和内存的内容整合到一起。从软件的底层运作来看,我们的软件与一个简单的图灵机器差不多。这就是我们栈探秘的第一部分,再讲一些内容之后,我们将看到构建在这个基础上的高级编程的概念。下周见!via:https://manybutfinite.com/post/journey-to-the-stack/作者:Gustavo Duarte 译者:qhwdw 校对:wxy本文由 LCTT 原创编译,Linux中国 荣誉推出Media

via https://linux.cn/article-9645-1.html?utm_source=rss&utm_medium=rss
从专有到开源的十个简单步骤

这个共同福利并不适用于专有软件:保持隐藏的东西是不能照亮或丰富这个世界的。Media

via https://linux.cn/article-9646-1.html
如何在 Linux 中使用 find

使用正确的参数,find 命令是在你的系统上找到数据的强大而灵活的方式。Media

via https://linux.cn/article-9648-1.html
如何在 Linux 中使用 find

使用正确的参数,find 命令是在你的系统上找到数据的强大而灵活的方式。Media最近的一篇文章中,Lewis Cowles 介绍了 find 命令。find 是日常工具箱中功能更强大、更灵活的命令行工具之一,因此值得花费更多的时间。最简单的,find 跟上路径寻找一些东西。例如:
find /
它将找到(并打印出)系统中的每个文件。而且由于一切都是文件,你会得到很多需要整理的输出。这可能不能帮助你找到你要找的东西。你可以改变路径参数来缩小范围,但它不会比使用 ls 命令更有帮助。所以你需要考虑你想要找的东西。也许你想在主目录中找到所有的 JPEG 文件。 -name 参数允许你将结果限制为与给定模式匹配的文件。
find ~ -name '*jpg'
可是等等!如果它们中的一些是大写的扩展名会怎么样?-iname 就像 -name,但是不区分大小写。
find ~ -iname '*jpg'
很好!但是 8.3 名称方案是如此的老。一些图片可能是 .jpeg 扩展名。幸运的是,我们可以将模式用“或”(表示为 -o)来组合。
find ~ ( -iname 'jpeg' -o -iname 'jpg' )
我们正在接近目标。但是如果你有一些以 jpg 结尾的目录呢? (为什么你要命名一个 bucketofjpg 而不是 pictures 的目录就超出了本文的范围。)我们使用 -type 参数修改我们的命令来查找文件。
find ~ \( -iname '*jpeg' -o -iname '*jpg' \) -type f
或者,也许你想找到那些命名奇怪的目录,以便稍后重命名它们:
find ~ \( -iname '*jpeg' -o -iname '*jpg' \) -type d
你最近拍了很多照片,所以让我们把它缩小到上周更改的文件。
find ~ \( -iname '*jpeg' -o -iname '*jpg' \) -type f -mtime -7
你可以根据文件状态更改时间 (ctime)、修改时间 (mtime) 或访问时间 (atime) 来执行时间过滤。 这些是在几天内,所以如果你想要更细粒度的控制,你可以表示为在几分钟内(分别是 cmin、mmin 和 amin)。 除非你确切地知道你想要的时间,否则你可能会在 + (大于)或 - (小于)的后面加上数字。但也许你不关心你的照片。也许你的磁盘空间不够用,所以你想在 log 目录下找到所有巨大的(让我们定义为“大于 1GB”)文件:
find /var/log -size +1G
或者,也许你想在 /data 中找到 bcotton 拥有的所有文件:
find /data -owner bcotton
你还可以根据权限查找文件。也许你想在你的主目录中找到对所有人可读的文件,以确保你不会过度分享。
find ~ -perm -o=r
这篇文章只说了 find 能做什么的表面。将测试条件与布尔逻辑相结合可以为你提供难以置信的灵活性,以便准确找到要查找的文件。并且像 -exec 或 -delete 这样的参数,你可以让 find 对它发现的内容采取行动。你有任何最喜欢的 find 表达式么?在评论中分享它们!via: https://opensource.com/article/18/4/how-use-find-linux作者:Ben Cotton 选题:lujun9972 译者:geekpi 校对:wxy本文由 LCTT 原创编译,Linux中国 荣誉推出Media

via https://linux.cn/article-9648-1.html?utm_source=rss&utm_medium=rss
在 Gentoo 中使用 Yubikey PGP 卡

PGP 卡是一种智能卡,这种智能卡可以执行加密、解密、数字签名/验证、认证等任务。它允许我们安全地存储密钥。Media

via https://linux.cn/article-9641-1.html
在 5 分钟内重置丢失的 root 密码

如何快速简单地在 Fedora 、 CentOS 及类似的 Linux 发行版上重置 root 密码。Media

via https://linux.cn/article-9649-1.html
在 5 分钟内重置丢失的 root 密码

如何快速简单地在 Fedora 、 CentOS 及类似的 Linux 发行版上重置 root 密码。Media系统管理员可以轻松地为忘记密码的用户重置密码。但是如果系统管理员忘记 root 密码或他从公司离职了,会发生什么情况?本指南将向你介绍如何在不到 5 分钟的时间内在 Red Hat 兼容系统(包括 Fedora 和 CentOS)上重置丢失或忘记的 root 密码。请注意,如果整个系统硬盘已用 LUKS 加密,则需要在出现提示时提供 LUKS 密码。此外,此过程适用于运行 systemd 的系统,该系统自 Fedora 15、CentOS 7.14.04 和 Red Hat Enterprise Linux 7.0 以来一直是缺省的初始系统。首先你需要中断启动的过程,因此你需要启动或者如果已经启动就重启它。第一步可能有点棘手因为 GRUB 菜单会在屏幕上快速地闪烁过去。你可能需要尝试几次,直到你能够做到这一点。当你看到这个屏幕时,按下键盘上的 e 键:Media如果你正确地做了这点,你应该看到一个类似于这个的屏幕:Media使用箭头键移动到 Linux16 这行:Media使用你的 del 键或你的 backspace 键,删除 rhgb quiet 并替换为以下内容:
rd.break enforcing=0
Media设置 enforcing=0 可以避免执行完整的系统 SELinux 重标记。一旦系统重新启动,你只需要为 /etc/shadow 恢复正确的 SELinux 上下文。我会告诉你如何做到这一点。按下 Ctrl-x 启动。系统现在将处于紧急模式。以读写权限重新挂载硬盘驱动器:
# mount –o remount,rw /sysroot
运行 chroot 来访问系统:
# chroot /sysroot
你现在可以更改 root 密码:
# passwd
出现提示时,输入新的 root 密码两次。如果成功,你应该看到一条消息显示 “all authentication tokens updated successfully”。输入 exit 两次以重新启动系统。以 root 身份登录并恢复 /etc/shadow 的 SELinux 标签。
# restorecon -v /etc/shadow
将 SELinux 回到 enforce 模式:
# setenforce 1
via: https://opensource.com/article/18/4/reset-lost-root-password作者:Curt Warfield 选题:lujun9972 译者:geekpi 校对:wxy本文由 LCTT 原创编译,Linux中国 荣誉推出Media

via https://linux.cn/article-9649-1.html?utm_source=rss&utm_medium=rss
使用 syslog-ng 可靠地记录物联网事件

用增强的日志守护进程 syslog-ng 来监控你的物联网设备。Media

via https://linux.cn/article-9650-1.html
如何利用虚拟化技术解决物联网开发难题?从了解 ACRN 开始

为了满足当前物联网市场的发展趋势,Linux 基金会推出了开源项目 —— ACRN。 ACRN 是一个专为嵌入式设备设计的 hypervisorMedia

via https://linux.cn/article-9651-1.html
在 KVM 中测试 IPv6 网络:第 2 部分

今天,我们将使用 KVM 创建一个网络,去测试上一星期学习的 IPv6 的内容。Media

via https://linux.cn/article-9652-1.html
成为你所在社区的美好力量

明白如何传递美好,了解积极意愿的力量,以及更多。Media

via https://linux.cn/article-9653-1.html
使用树莓派和 projectx/os 托管你自己的电子邮件

这个开源项目可以通过低成本的服务器设施帮助你保护你的数据隐私和所有权。Media

via https://linux.cn/article-9654-1.html
使用 AppImageLauncher 轻松运行和集成 AppImage 文件

你有没有下载过 AppImage 文件,而你不知道如何使用它?或许你可能知道如何使用它,但是你每次要运行它时必须要进入到下载了该 .AppImage 的文件夹中来运行它,或者手动为其创建启动程序。Media

via https://linux.cn/article-9655-1.html
如何创建适合移动设备的文档

帮助用户在智能手机或平板上快速轻松地找到他们所需的信息。Media

via https://linux.cn/article-9656-1.html
Linux 局域网路由新手指南:第 1 部分

现在我们继续深入学习 Linux 中的 IPv4 路由的基础知识。Media

via https://linux.cn/article-9657-1.html
使用交互式 shell 来增强你的 Python

本文将介绍 Fedora 软件包集合中提供的一些有用的 Python shell 来简化开发。Media

via https://linux.cn/article-9658-1.html
如何使用 Ansible 打补丁以及安装应用

使用 Ansible IT 自动化引擎节省更新的时间。Media

via https://linux.cn/article-9659-1.html
如何使用 Ansible 打补丁以及安装应用

使用 Ansible IT 自动化引擎节省更新的时间。Media你有没有想过,如何打补丁、重启系统,然后继续工作?如果你的回答是肯定的,那就需要了解一下 Ansible 了。它是一个配置管理工具,对于一些复杂的有时候需要几个小时才能完成的系统管理任务,又或者对安全性有比较高要求的时候,使用 Ansible 能够大大简化工作流程。以我作为系统管理员的经验,打补丁是一项最有难度的工作。每次遇到公共漏洞批露Common Vulnearbilities and Exposure(CVE)通知或者信息保障漏洞预警Information Assurance Vulnerability Alert(IAVA)时都必须要高度关注安全漏洞,否则安全部门将会严肃追究自己的责任。使用 Ansible 可以通过运行封装模块以缩短打补丁的时间,下面以 yum 模块更新系统为例,使用 Ansible 可以执行安装、更新、删除、从其它地方安装(例如持续集成/持续开发中的 rpmbuild)。以下是系统更新的任务:
 - name: update the system yum: name: "*" state: latest
在第一行,我们给这个任务命名,这样可以清楚 Ansible 的工作内容。第二行表示使用 yum 模块在CentOS虚拟机中执行更新操作。第三行 name: "*" 表示更新所有程序。最后一行 state: latest 表示更新到最新的 RPM。系统更新结束之后,需要重新启动并重新连接:
 - name: restart system to reboot to newest kernel shell: "sleep 5 && reboot" async: 1 poll: 0 - name: wait for 10 seconds pause: seconds: 10 - name: wait for the system to reboot wait_for_connection: connect_timeout: 20 sleep: 5 delay: 5 timeout: 60 - name: install epel-release yum: name: epel-release state: latest
shell 模块中的命令让系统在 5 秒休眠之后重新启动,我们使用 sleep 来保持连接不断开,使用 async 设定最大等待时长以避免发生超时,poll 设置为 0 表示直接执行不需要等待执行结果。暂停 10 秒钟以等待虚拟机恢复,使用 wait_for_connection 在虚拟机恢复连接后尽快连接。随后由 install epel-release 任务检查 RPM 的安装情况。你可以对这个剧本执行多次来验证它的幂等性,唯一会显示造成影响的是重启操作,因为我们使用了 shell 模块。如果不想造成实际的影响,可以在使用 shell 模块的时候 changed_when: False。现在我们已经知道如何对系统进行更新、重启虚拟机、重新连接、安装 RPM 包。下面我们通过 Ansible Lightbulb 来安装 NGINX:
 - name: Ensure nginx packages are present yum: name: nginx, python-pip, python-devel, devel state: present notify: restart-nginx-service - name: Ensure uwsgi package is present pip: name: uwsgi state: present notify: restart-nginx-service - name: Ensure latest default.conf is present template: src: templates/nginx.conf.j2 dest: /etc/nginx/nginx.conf backup: yes notify: restart-nginx-service - name: Ensure latest index.html is present template: src: templates/index.html.j2 dest: /usr/share/nginx/html/index.html - name: Ensure nginx service is started and enabled service: name: nginx state: started enabled: yes - name: Ensure proper response from localhost can be received uri: url: "http://localhost:80/" return_content: yes register: response until: 'nginx_test_message in response.content' retries: 10 delay: 1
以及用来重启 nginx 服务的操作文件:
# 安装 nginx 的操作文件 - name: restart-nginx-service service: name: nginx state: restarted
在这个角色里,我们使用 RPM 安装了 nginx、python-pip、python-devel、devel,用 PIP 安装了 uwsgi,接下来使用 template 模块复制 nginx.conf 和 index.html 以显示页面,并确保服务在系统启动时启动。然后就可以使用 uri 模块检查到页面的连接了。这个是一个系统更新、系统重启、安装 RPM 包的剧本示例,后续可以继续安装 nginx,当然这里可以替换成任何你想要的角色和应用程序。
 - hosts: all roles: - centos-update - nginx-simple
 这只是关于如何更新系统、重启以及后续工作的示例。简单起见,我只添加了不带变量的包,当你在操作大量主机的时候,你就需要修改其中的一些设置了:async & pollserialforks这是由于在生产环境中如果你想逐一更新每一台主机的系统,你需要花相当一段时间去等待主机重启才能够继续下去。via: https://opensource.com/article/18/3/ansible-patch-systems作者:Jonathan Lozada De La Matta 译者:HankChow 校对:wxy本文由 LCTT 原创编译,Linux中国 荣誉推出Media

via https://linux.cn/article-9659-1.html?utm_source=rss&utm_medium=rss
如何改善应用程序在 Linux 中的启动时间

大多数 Linux 发行版在默认配置下已经足够快了。但是,我们仍然可以借助一些额外的应用程序和方法让它们启动更快一点。Media

via https://linux.cn/article-9660-1.html