Merge remote-tracking branch 'LCTT/master'

This commit is contained in:
Xingyu.Wang 2018-06-22 14:54:56 +08:00
commit de14b3f70f
11 changed files with 291 additions and 297 deletions

View File

@ -1,12 +1,13 @@
# 将 DEB 软件包转换成 Arch Linux 软件包
将 DEB 软件包转换成 Arch Linux 软件包
============
![](https://www.ostechnix.com/wp-content/uploads/2017/10/Debtap-720x340.png)
我们已经学会了如何[**为多个平台构建包**][1],以及如何从[**源代码构建包**][2]。 今天,我们将学习如何将 DEB 包转换为 Arch Linux 包。 您可能会问AUR 是这个星球上的大型软件存储库,几乎所有的软件都可以在其中使用。 为什么我需要将 DEB 软件包转换为 Arch Linux 软件包? 这的确没错! 但是,某些软件包无法编译(封闭源代码软件包),或者由于各种原因(如编译时出错或文件不可用)而无法从 AUR 生成。 或者,开发人员懒得在 AUR 中构建一个包,或者他/她不想创建 AUR 包。 在这种情况下,我们可以使用这种快速但有点粗糙的方法将 DEB 包转换成 Arch Linux 包。
我们已经学会了如何[为多个平台构建包][1],以及如何从[源代码构建包][2]。 今天,我们将学习如何将 DEB 包转换为 Arch Linux 包。 您可能会问AUR 是这个星球上的大型软件存储库,几乎所有的软件都可以在其中使用。 为什么我需要将 DEB 软件包转换为 Arch Linux 软件包? 这的确没错! 但是,由于某些软件包无法编译(封闭源代码软件包),或者由于各种原因(如编译时出错或文件不可用)而无法从 AUR 生成。 或者,开发人员懒得在 AUR 中构建一个包,或者他/她不想创建 AUR 包。 在这种情况下,我们可以使用这种快速但有点粗糙的方法将 DEB 包转换成 Arch Linux 包。
### Debtap - 将 DEB 包转换成 Arch Linux 包
为此,我们将使用名为 “Debtap” 的实用程序。 它代表了 **DEB** **T** o **A** rch Linux **P** ackage。 Debtap 在 AUR 中可以使用,因此您可以使用 AUR 辅助工具(如 [Pacaur][3][Packer][4] 或 [Yaourt][5] )来安装它。
为此,我们将使用名为 “Debtap” 的实用程序。 它代表了 **DEB** **T** o **A** rch Linux **P** ackage。 Debtap 在 AUR 中可以使用,因此您可以使用 AUR 辅助工具(如 [Pacaur][3][Packer][4] 或 [Yaourt][5] )来安装它。
使用 pacaur 安装 debtap 运行:
@ -26,7 +27,7 @@ packer -S debtap
yaourt -S debtap
```
同时,你的 Arch 系统也应该已经安装好了 **bash** **binutils** **pkgfile** 和 **fakeroot** 包。
同时,你的 Arch 系统也应该已经安装好了 `bash` `binutils` `pkgfile` 和 `fakeroot` 包。
在安装 Debtap 和所有上述依赖关系之后,运行以下命令来创建/更新 pkgfile 和 debtap 数据库。
@ -73,11 +74,11 @@ sudo debtap -u
==> All steps successfully completed!
```
你至少需要运行上述命令一次
你至少需要运行上述命令一次
现在是时候开始转换包了。
比如说要使用 debtap 转换包 **Quadrapassel**,你可以这样做:
比如说要使用 debtap 转换包 Quadrapassel你可以这样做
```
debtap quadrapassel_3.22.0-1.1_arm64.deb
@ -95,17 +96,17 @@ debtap quadrapassel_3.22.0-1.1_arm64.deb
==> Generating .PKGINFO file...
:: Enter Packager name:
**quadrapassel**
quadrapassel
:: Enter package license (you can enter multiple licenses comma separated):
**GPL**
GPL
*** Creation of .PKGINFO file in progress. It may take a few minutes, please wait...
Warning: These dependencies (depend = fields) could not be translated into Arch Linux packages names:
gsettings-backend
== > Checking and generating .INSTALL file (if necessary)...
==> Checking and generating .INSTALL file (if necessary)...
:: If you want to edit .PKGINFO and .INSTALL files (in this order), press (1) For vi (2) For nano (3) For default editor (4) For a custom editor or any other key to continue:
@ -118,25 +119,25 @@ gsettings-backend
**注**Quadrapassel 在 Arch Linux 官方的软件库中早已可用,我只是用它来说明一下。
如果在包转化的过程中,你不想回答任何问题,使用 **-q** 略过除了编辑元数据的所有问题。
如果在包转化的过程中,你不想回答任何问题,使用 `-q` 略过除了编辑元数据之外的所有问题。
```
debtap -q quadrapassel_3.22.0-1.1_arm64.deb
```
为了略过所有的问题(不推荐),使用 -Q。
为了略过所有的问题(不推荐),使用 `-Q`
```
debtap -Q quadrapassel_3.22.0-1.1_arm64.deb
```
转换完成后,您可以使用 “pacman” 在 Arch 系统中安装新转换的软件包,如下所示。
转换完成后,您可以使用 `pacman` 在 Arch 系统中安装新转换的软件包,如下所示。
```
sudo pacman -U <package-name>
```
显示帮助文档,使用 -h
显示帮助文档,使用 `-h`
```
$ debtap -h
@ -154,7 +155,7 @@ Options:
-P --P -Pkgbuild --Pkgbuild Generate a PKGBUILD file only
```
这就是现在要讲的。希望这个工具有所帮助。如果你发现我们的指南有用,请花一点时间在你的社交、专业网络分享并在 OSTechNix 支持我们!
这就是现在要讲的。希望这个工具有所帮助。如果你发现我们的指南有用,请花一点时间在你的社交、专业网络分享并支持我们!
更多的好东西来了。请继续关注!
@ -168,7 +169,7 @@ via: https://www.ostechnix.com/convert-deb-packages-arch-linux-packages/
作者:[SK][a]
译者:[amwps290](https://github.com/amwps290)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -1,16 +1,18 @@
8 个基本的 Docker 容器管理命令
======
利用这 8 个命令可以学习 Docker 容器的基本管理方式。这是一个为 Docker 初学者准备的,带有示范命令输出的指南。
> 利用这 8 个命令可以学习 Docker 容器的基本管理方式。这是一个为 Docker 初学者准备的,带有示范命令输出的指南。
![Docker 容器管理命令][1]
在这篇文章中,我们将带你学习 8 个基本的 Docker 容器命令,它们操控着 Docker 容器的基本活动,例如 <ruby>运行<rt>run</rt></ruby>, <ruby>列举<rt>list</rt></ruby>, <ruby>停止<rt>stop</rt></ruby>, <ruby>查看历史纪录<rt>view logs</rt></ruby>, <ruby>删除<rt>delete</rt></ruby>, 等等。如果你对 Docker 的概念很陌生,推荐你看看我们的 [介绍指南][2],来了解 Docker 的基本内容以及 [如何][3] 在 Linux 上安装 Docker. 现在让我们赶快进入要了解的命令:
在这篇文章中,我们将带你学习 8 个基本的 Docker 容器命令,它们操控着 Docker 容器的基本活动,例如 <ruby>运行<rt>run</rt></ruby> <ruby>列举<rt>list</rt></ruby> <ruby>停止<rt>stop</rt></ruby>、 查看<ruby>历史纪录<rt>logs</rt></ruby> <ruby>删除<rt>delete</rt></ruby> 等等。如果你对 Docker 的概念很陌生,推荐你看看我们的 [介绍指南][2],来了解 Docker 的基本内容以及 [如何][3] 在 Linux 上安装 Docker 现在让我们赶快进入要了解的命令:
### 如何运行 Docker 容器?
众所周知Docker 容器只是一个运行于<ruby>宿主操作系统<rt>host OS</rt></ruby>上的应用进程所以你需要一个镜像来运行它。Docker 镜像运行时的进程就叫做 Docker 容器。你可以加载本地 Docker 镜像,也可以从 Docker Hub 上下载。Docker Hub 是一个提供公有和私有镜像来进行<ruby>拉取<rt>pull</rt></ruby>操作的集中仓库。官方的 Docker Hub 位于 [hub.docker.com][4]. 当你指示 Docker 引擎运行容器时,它会首先搜索本地镜像,如果没有找到,它会从 Docker Hub 上拉取相应的镜像。
众所周知Docker 容器只是一个运行于<ruby>宿主操作系统<rt>host OS</rt></ruby>上的应用进程所以你需要一个镜像来运行它。Docker 镜像以进程的方式运行时就叫做 Docker 容器。你可以加载本地 Docker 镜像,也可以从 Docker Hub 上下载。Docker Hub 是一个提供公有和私有镜像来进行<ruby>拉取<rt>pull</rt></ruby>操作的集中仓库。官方的 Docker Hub 位于 [hub.docker.com][4]。 当你指示 Docker 引擎运行容器时,它会首先搜索本地镜像,如果没有找到,它会从 Docker Hub 上拉取相应的镜像。
让我们运行一个 Apache web 服务器的 Docker 镜像,比如 httpd 进程。你需要运行 `docker container run` 命令。旧的命令为 `docker run` 但后来 Docker 添加了子命令部分,所以新版本支持下列命令:
让我们运行一个 Apache web-server 的 Docker 镜像,比如 httpd 进程。你需要运行 `docker container run` 命令。旧的命令为 `docker run`, 但后来 Docker 添加了子命令部分,所以新版本支持<ruby>附属命令<rt>below command</rt></ruby> -
```
root@kerneltalks # docker container run -d -p 80:80 httpd
@ -28,18 +30,16 @@ Status: Downloaded newer image for httpd:latest
c46f2e9e4690f5c28ee7ad508559ceee0160ac3e2b1688a61561ce9f7d99d682
```
Docker 的 `run` 命令将镜像名作为强制参数,另外还有很多可选参数。常用的参数有 -
Docker 的 `run` 命令将镜像名作为强制参数,另外还有很多可选参数。常用的参数有
* `-d` : Detach container from current shell
* `-p X:Y` : Bind container port Y with hosts port X
* `--name` : Name your container. If not used, it will be assigned randomly generated name
* `-e` : Pass environmental variables and their values while starting container
* `-d`:从当前 shell 脱离容器
* `-p X:Y`:绑定容器的端口 Y 到宿主机的端口 X
* `--name`:命名你的容器。如果未指定,它将被赋予随机生成的名字
* `-e`:当启动容器时传递环境编辑及其值
通过以上输出你可以看到,我们将 `httpd` 作为镜像名来运行容器。接着本地镜像没有找到Docker 引擎从 Docker Hub 拉取了它。注意,它下载了镜像 `httpd:latest` 其中 `:` 后面跟着版本号。如果你需要运行特定版本的容器你可以在镜像名后面注明版本名。如果不提供版本名Docker 引擎会自动拉取最新的版本。
通过以上输出你可以看到,我们将 `httpd` 作为镜像名来运行容器。接着本地镜像没有找到Docker 引擎从 Docker Hub 拉取了它。注意,它下载了镜像 **httpd:latest**, 其中 : 后面跟着版本号。如果你需要运行特定版本的容器你可以在镜像名后面注明版本名。如果不提供版本名Docker 引擎会自动拉取最新的版本。
输出的最后一行显示了你新运行的 httpd 容器的特有 ID。
输出的最后一行显示了你新运行的 httpd 容器的唯一 ID。
### 如何列出所有运行中的 Docker 容器?
@ -51,9 +51,9 @@ CONTAINER ID IMAGE COMMAND CREATED
c46f2e9e4690 httpd "httpd-foreground" 11 minutes ago Up 11 minutes 0.0.0.0:80->80/tcp cranky_cori
```
列出的结果是按列显示的。每一列的值分别为 -
列出的结果是按列显示的。每一列的值分别为
1. Container ID :一开始的几个字符对应你特有的容器 ID
1. Container ID :一开始的几个字符对应你的容器的唯一 ID
2. Image :你运行容器的镜像名
3. Command :容器启动后运行的命令
4. Created :创建时间
@ -61,11 +61,9 @@ c46f2e9e4690 httpd "httpd-foreground" 11 minutes ago
6. Ports :与宿主端口相连接的端口信息
7. Names :容器名(如果你没有命名你的容器,那么会随机创建)
### 如何查看 Docker 容器的历史纪录?
在第一步我们使用了 -d 参数来将容器,在它一开始运行的时候,就从当前的 shell 中离出来。在这种情况下我们不知道容器里面发生了什么。所以为了查看容器的历史纪录Docker 提供了 `logs` 命令。它采用容器名称或 ID 作为参数。
在第一步我们使用了 `-d` 参数来将容器,在它一开始运行的时候,就从当前的 shell 中离出来。在这种情况下我们不知道容器里面发生了什么。所以为了查看容器的历史纪录Docker 提供了 `logs` 命令。它采用容器名称或 ID 作为参数。
```
root@kerneltalks # docker container logs cranky_cori
@ -99,7 +97,7 @@ bin 15731 15702 0 18:35 ? 00:00:00 httpd -DFOREGROUND
root 15993 15957 0 18:59 pts/0 00:00:00 grep --color=auto -i 15702
```
在第一个输出中,列出了容器产生的进程的列表。它包含了所有细节,包括用途,<ruby>进程号<rt>pid</rt></ruby><ruby>父进程号<rt>ppid</rt></ruby>,开始时间,命令,等等。这里所有的进程号你都可以在宿主的进程表里搜索到。这就是我们在第二个命令里做得。这证明了容器确实是宿主系统中的进程。
在第一个输出中,列出了容器产生的进程的列表。它包含了所有细节,包括<ruby>用户号<rt>uid</rt></ruby><ruby>进程号<rt>pid</rt></ruby><ruby>父进程号<rt>ppid</rt></ruby>、开始时间、命令,等等。这里所有的进程号你都可以在宿主的进程表里搜索到。这就是我们在第二个命令里做得。这证明了容器确实是宿主系统中的进程。
### 如何停止 Docker 容器?
@ -128,7 +126,7 @@ CONTAINER ID IMAGE COMMAND CREATED
c46f2e9e4690 httpd "httpd-foreground" 33 minutes ago Exited (0) 2 minutes ago cranky_cori
```
有了 `-a` 参数,现在我们可以查看已停止的容器。注意这些容器的状态被标注为 <ru by>已退出<rt>exited</rt></ruby>。既然容器只是一个进程,那么用“退出”比“停止”更合适!
有了 `-a` 参数,现在我们可以查看已停止的容器。注意这些容器的状态被标注为 <ruby>已退出<rt>exited</rt></ruby>。既然容器只是一个进程,那么用“退出”比“停止”更合适!
### 如何(重新)启动 Docker 容器?
@ -145,7 +143,7 @@ c46f2e9e4690 httpd "httpd-foreground" 35 minutes ago
### 如何移除 Docker 容器?
我们使用 `rm` 命令来移容器。你不可以移除运行中的容器。移除之前需要先停止容器。你可以使用 `-f` 参数搭配 `rm` 命令来强制移除容器,但并不推荐这么做。
我们使用 `rm` 命令来移容器。你不可以移除运行中的容器。移除之前需要先停止容器。你可以使用 `-f` 参数搭配 `rm` 命令来强制移除容器,但并不推荐这么做。
```
root@kerneltalks # docker container rm cranky_cori
@ -162,8 +160,8 @@ via: https://kerneltalks.com/virtualization/8-basic-docker-container-management-
作者:[Shrikant Lavhate][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[lonaparte](https://github.com/译者ID/lonaparte)
校对:[校对者ID](https://github.com/校对者ID)
译者:[lonaparte](https://github.com/lonaparte)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -1,100 +0,0 @@
translating by sunxi
How debuggers really work
======
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/annoyingbugs.png?itok=ywFZ99Gs)
Image by : opensource.com
A debugger is one of those pieces of software that most, if not every, developer uses at least once during their software engineering career, but how many of you know how they actually work? During my talk at [linux.conf.au 2018][1] in Sydney, I will be talking about writing a debugger from scratch... in [Rust][2]!
In this article, the terms debugger/tracer are interchangeably. "Tracee" refers to the process being traced by the tracer.
### The ptrace system call
Most debuggers heavily rely on a system call known as `ptrace(2)`, which has the prototype:
```
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
```
This is a system call that can manipulate almost all aspects of a process; however, before the debugger can attach to a process, the "tracee" has to call `ptrace` with the request `PTRACE_TRACEME`. This tells Linux that it is legitimate for the parent to attach via `ptrace` to this process. But... how do we coerce a process into calling `ptrace`? Easy-peasy! `fork/execve` provides an easy way of calling `ptrace` after `fork` but before the tracee really starts using `execve`. Conveniently, `fork` will also return the `pid` of the tracee, which is required for using `ptrace` later.
Now that the tracee can be traced by the debugger, important changes take place:
* Every time a signal is delivered to the tracee, it stops and a wait-event is delivered to the tracer that can be captured by the `wait` family of system calls.
* Each `execve` system call will cause a `SIGTRAP` to be delivered to the tracee. (Combined with the previous item, this means the tracee is stopped before an `execve` can fully take place.)
This means that, once we issue the `PTRACE_TRACEME` request and call the `execve` system call to actually start the program in the tracee, the tracee will immediately stop, since `execve` delivers a `SIGTRAP`, and that is caught by a wait-event in the tracer. How do we continue? As one would expect, `ptrace` has a number of requests that can be used for telling the tracee it's fine to continue:
* `PTRACE_CONT`: This is the simplest. The tracee runs until it receives a signal, at which point a wait-event is delivered to the tracer. This is most commonly used to implement "continue-until-breakpoint" and "continue-forever" options of a real-world debugger. Breakpoints will be covered below.
* `PTRACE_SYSCALL`: Very similar to `PTRACE_CONT`, but stops before a system call is entered and also before a system call returns to userspace. It can be used in combination with other requests (which we will cover later in this article) to monitor and modify a system call's arguments or return value. `strace`, the system call tracer, uses this request heavily to figure out what system calls are made by a process.
* `PTRACE_SINGLESTEP`: This one is pretty self-explanatory. If you used a debugger before, this request executes the next instruction, but stops immediately after.
We can stop the process with a variety of requests, but how do we get the state of the tracee? The state of a process is mostly captured by its registers, so of course `ptrace` has a request to get (or modify!) the registers:
* `PTRACE_GETREGS`: This request will give the registers' state as it was when a tracee was stopped.
* `PTRACE_SETREGS`: If the tracer has the values of registers from a previous call to `PTRACE_GETREGS`, it can modify the values in that structure and set the registers to the new values via this request.
* `PTRACE_PEEKUSER` and `PTRACE_POKEUSER`: These allow reading from the tracee's `USER` area, which holds the registers and other useful information. This can be used to modify a single register, without the more heavyweight `PTRACE_{GET,SET}REGS`.
Modifying the registers isn't always sufficient in a debugger. A debugger will sometimes need to read some parts of the memory or even modify it. The GNU Project Debugger (GDB) can use `print` to get the value of a memory location or a variable. `ptrace` has the functionality to implement this:
* `PTRACE_PEEKTEXT` and `PTRACE_POKETEXT`: These allow reading and writing a word in the address space of the tracee. Of course, the tracee has to be stopped for this to work.
Real-world debuggers also have features like breakpoints and watchpoints. In the next section, I'll dive into the architectural details of debugging support. For the purposes of clarity and conciseness, this article will consider x86 only.
### Architectural support
`ptrace` is all cool, but how does it work? In the previous section, we've seen that `ptrace` has quite a bit to do with signals: `SIGTRAP` can be delivered during single-stepping, before `execve` and before or after system calls. Signals can be generated a number of ways, but we will look at two specific examples that can be used by debuggers to stop a program (effectively creating a breakpoint!) at a given location:
* **Undefined instructions:** When a process tries to execute an undefined instruction, an exception is raised by the CPU. This exception is handled via a CPU interrupt, and a handler corresponding to the interrupt in the kernel is called. This will result in a `SIGILL` being sent to the process. This, in turn, causes the process to stop, and the tracer is notified via a wait-event. It can then decide what to do. On x86, an instruction `ud2` is guaranteed to be always undefined.
* **Debugging interrupt:** The problem with the previous approach is that the `ud2` instruction takes two bytes of machine code. A special instruction exists that takes one byte and raises an interrupt. It's `int $3` and the machine code is `0xCC`. When this interrupt is raised, the kernel sends a `SIGTRAP` to the process and, just as before, the tracer is notified.
This is fine, but how do we coerce the tracee to execute these instructions? Easy: `ptrace` has `PTRACE_POKETEXT`, which can override a word at a memory location. A debugger would read the original word at the location using `PTRACE_PEEKTEXT` and replace it with `0xCC`, remembering the original byte and the fact that it is a breakpoint in its internal state. The next time the tracee executes at the location, it is automatically stopped by the virtue of a `SIGTRAP`. The debugger's end user can then decide how to continue (for instance, inspect the registers).
Okay, we've covered breakpoints, but what about watchpoints? How does a debugger stop a program when a certain memory location is read or written? Surely you wouldn't just overwrite every instruction with `int $3` that could read or write some memory location. Meet debug registers, a set of registers designed to fulfill this goal more efficiently:
* `DR0` to `DR3`: Each of these registers contains an address (a memory location), where the debugger wants the tracee to stop for some reason. The reason is specified as a bitmask in `DR7`.
* `DR4` and `DR5`: These obsolete aliases to `DR6` and `DR7`, respectively.
* `DR6`: Debug status. Contains information about which `DR0` to `DR3` caused the debugging exception to be raised. This is used by Linux to figure out the information passed along with the `SIGTRAP` to the tracee.
* `DR7`: Debug control. Using the bits in these registers, the debugger can control how the addresses specified in `DR0` to `DR3` are interpreted. A bitmask controls the size of the watchpoint (whether 1, 2, 4, or 8 bytes are monitored) and whether to raise an exception on execution, reading, writing, or either of reading and writing.
Because the debug registers form part of the `USER` area of a process, the debugger can use `PTRACE_POKEUSER` to write values into the debug registers. The debug registers are only relevant to a specific process and are thus restored to the value at preemption before the process regains control of the CPU.
### Tip of the iceberg
We've glanced at the iceberg a debugger is: we've covered `ptrace`, went over some of its functionality, then we had a look at how `ptrace` is implemented. Some parts of `ptrace` can be implemented in software, but other parts have to be implemented in hardware, otherwise they'd be very expensive or even impossible.
There's plenty that we didn't cover, of course. Questions, like "how does a debugger know where a variable is in memory?" remain open due to space and time constraints, but I hope you've learned something from this article; if it piqued your interest, there are plenty of resources available online to learn more.
For more, attend Levente Kurusa's talk, [Let's Write a Debugger!][3], at [linux.conf.au][1], which will be held January 22-26 in Sydney.
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/1/how-debuggers-really-work
作者:[Levente Kurusa][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/lkurusa
[1]:https://linux.conf.au/index.html
[2]:https://www.rust-lang.org
[3]:https://rego.linux.conf.au/schedule/presentation/91/

View File

@ -1,109 +0,0 @@
translating---geekpi
How To Run A Command For A Specific Time In Linux
======
![](https://www.ostechnix.com/wp-content/uploads/2018/02/Run-A-Command-For-A-Specific-Time-In-Linux-1-720x340.png)
The other day I was transferring a large file using rsync to another system on my local area network. Since it is very big file, It took around 20 minutes to complete. I dont want to wait that longer, and I dont want to terminate the process by pressing CTRL+C either. I was just wondering if there could be any easy ways to run a command for a specific time and kill it automatically once the time is out in Unix-like operating systems hence this post. Read on.
### Run A Command For A Specific Time In Linux
We can do this in two methods.
#### Method 1 Using “timeout” command
The most common method is using **timeout** command. For those who dont know, the timeout command will effectively limit the absolute execution time of a process. The timeout command is part of the GNU coreutils package, so it comes pre-installed in all GNU/Linux systems.
Let us say, you want to run a command for only 5 seconds, and then kill it. To do so, we use:
```
$ timeout <time-limit-interval> <command>
```
For example, the following command will terminate after 10 seconds.
```
$ timeout 10s tail -f /var/log/pacman.log
```
![][2]
You also dont have to specify the suffix “s” for seconds. The following command is same as above.
```
$ timeout 10 tail -f /var/log/pacman.log
```
The other available suffixes are:
* m for minutes,
* h for hours
* d for days.
If you run this **tail -f /var/log/pacman.log** command, it will keep running until you manually end it by pressing CTRL+C. However, if you run it along with **timeout** command, it will be killed automatically after the given time interval. If the command is till running after the time out, you can send a **kill** signal like below.
```
$ timeout -k 20 10 tail -f /var/log/pacman.log
```
In this case, if you the tail command still running after 10 seconds, the timeout command will send it a kill signal after 20 seconds and end it.
For more details, check the man pages.
```
$ man timeout
```
Sometimes, a particular program might take long time to complete and end up freezing your system. In such cases, you can use this trick to end the process automatically after a particular time.
Also, consider using **Cpulimit** , a simple application to limit the CPU usage of a process. For more details, check the following link.
#### Method 2 Using “Timelimit” program
The Timelimit utility executes a given command with the supplied arguments and terminates the spawned process after a given time with a given signal. First, it will pass the warning signal and then after timeout, it will send the **kill** signal.
Unlike the timeout utility, the Timelimit has more options. You can pass number of arguments such as killsig, warnsig, killtime, warntime etc. It is available in the default repositories of Debian-based systems. So, you can install it using command:
```
$ sudo apt-get install timelimit
```
For Arch-based systems, it is available in the AUR. So, you can install it using any AUR helper programs such as [**Pacaur**][3], [**Packer**][4], [**Yay**][5], [**Yaourt**][6] etc.
For other distributions, download the source [**from here**][7] and manually install it. After installing Timelimit program, run the following command for a specific time, for example 10 seconds:
```
$ timelimit -t10 tail -f /var/log/pacman.log
```
If you run timelimit without any arguments, it will use the default values: warntime=3600 seconds, warnsig=15, killtime=120, killsig=9. For more details, refer the man pages and the projects website given at the end of this guide.
```
$ man timelimit
```
And, thats all for today. I hope this was useful. More good stuffs to come. Stay tuned!
Cheers!
--------------------------------------------------------------------------------
via: https://www.ostechnix.com/run-command-specific-time-linux/
作者:[SK][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.ostechnix.com/author/sk/
[2]:http://www.ostechnix.com/wp-content/uploads/2018/02/Timeout.gif
[3]:https://www.ostechnix.com/install-pacaur-arch-linux/
[4]:https://www.ostechnix.com/install-packer-arch-linux-2/
[5]:https://www.ostechnix.com/yay-found-yet-another-reliable-aur-helper/
[6]:https://www.ostechnix.com/install-yaourt-arch-linux/
[7]:http://devel.ringlet.net/sysutils/timelimit/#download

View File

@ -1,3 +1,4 @@
translating by stenphenxs
How to get a core dump for a segfault on Linux
============================================================

View File

@ -1,3 +1,5 @@
translated by hopefully2333
5 trending open source machine learning JavaScript frameworks
======
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/web-spider-frame-framework-2.png?itok=ng6O0fd4)

View File

@ -1,3 +1,4 @@
translating by amwps290
Complete Sed Command Guide [Explained with Practical Examples]
======
In a previous article, I showed the [basic usage of Sed][1], the stream editor, on a practical use case. Today, be prepared to gain more insight about Sed as we will take an in-depth tour of the sed execution model. This will be also an opportunity to make an exhaustive review of all Sed commands and to dive into their details and subtleties. So, if you are ready, launch a terminal, [download the test files][2] and sit comfortably before your keyboard: we will start our exploration right now!

View File

@ -1,3 +1,5 @@
translating---geekpi
How to disable iptables firewall temporarily
======

View File

@ -1,26 +1,25 @@
怎么去转换任何系统调用为一个事件:介绍 eBPF 内核探针
怎么去转换任何系统调用为一个事件:对 eBPF 内核探针的介绍
============================================================
长文预警:在最新的 Linux 内核(>=4.4)中使用 eBPF你可以将任何内核函数调用转换为一个带有任意数据的用户空间的事件。这通过 bcc 来做很容易。这个探针是用 C 语言写的,而数据是由 Python 来处理的。
长文预警:在最新的 Linux 内核(>=4.4)中使用 eBPF你可以使用任意数据将任何内核函数调用转换为一个用户空间事件。这通过 bcc 来做很容易。这个探针是用 C 语言写的,而数据是由 Python 来处理的
如果你对 eBPF 或者 Linux 跟踪不熟悉,那你应该好好阅读一下整篇文章。本文尝试逐步去解决我在使用 bcc/eBPF 时遇到的困难,以为您节省我在搜索和挖掘上花费的时间
如果你对 eBPF 或者 Linux 跟踪不熟悉,那你应该好好阅读一下本文。它尝试逐步去克服我在使用 bcc/eBPF 时遇到的困难,同时也节省了我在搜索和挖掘上花费的时间。
### 在 Linux 的世界中关于推送与轮询的一个看法
### 在 Linux 的世界中关于 push vs pull 的一个提示
当我开始在容器上工作的时候,我想知道我们怎么基于一个真实的系统状态去动态更新一个负载均衡器的配置。一个通用的策略是这样做的,无论什么时候只要一个容器启动,容器编排器触发一个负载均衡配置更新动作,负载均衡器去轮询每个容器,直到它的健康状态检查结束。它只是简单进行 “SYN” 测试。
当我开始在容器上工作的时候,我想知道我们怎么基于一个真实的系统状态去动态更新一个负载均衡器的配置。一个通用的策略是这样做的,无论什么时候只要一个容器启动,容器编排器触发一个负载均衡配置更新动作,负载均衡器去轮询每个容器,直到它的健康状态检查结束。它也许只是简单进行 “SYN” 测试。
虽然这种配置方式可以有效工作,但是它的缺点是你的负载均衡器为了让一些系统变得可用需要等待,而不是 … 让负载去均衡。
可以做的更好吗?
当你希望在一个系统中让一个程序对一些变化做出反应,这里有两种可能的策略。程序可以去 _轮询_  系统去检测变化,或者,如果系统支持,系统可以  _推送_ 事件并且让程序对它作出反应。你希望去使用推送还是轮询取决于上下文环境。一个好的经验法则是,基于处理时间的考虑,如果事件发生的频率较低时使用推送,而当事件发生的较快或者让系统变得不可用时切换为轮询。例如,一般情况下,网络驱动将等待来自网卡的事件,但是,像 dpdk 这样的框架对事件将激活对网卡的轮询,以达到高吞吐低延迟的目的。
当你希望在一个系统中让一个程序对一些变化做出反应,这里有两种可能的策略。程序可以去 _轮询_  系统去检测变化,或者,如果系统支持,系统可以  _推送_ 事件并且让程序对它作出反应。你希望去使用推送还是轮询取决于上下文环境。一个好的经验法则是,基于处理时间的考虑,如果事件发生的频率较低时使用推送,而当事件发生的较快或者让系统变得不可用时切换为轮询。例如,一般情况下,网络驱动程序将等待来自网卡的事件,但是,像 dpdk 这样的框架对事件将主动轮询网卡,以达到高吞吐低延迟的目的。
理想状态下,我们将有一些内核接口告诉我们:
> * “容器管理器,你好,我刚才为容器 _servestaticfiles_ 的 Nginx-ware 创建了一个套接字,或许你应该去更新你的状态?
>
> * “好的,操作系统,感谢你告诉我这个事件
> * “好的,操作系统,感谢你告诉我这个事件
虽然 Linux 有大量的接口去处理事件,对于文件事件高达 3 个,但是没有专门的接口去得到套接字事件提示。你可以得到路由表事件、邻接表事件、连接跟踪事件、接口变化事件。唯独没有套接字事件。或者,也许它深深地隐藏在一个 Netlink 接口中。
@ -28,23 +27,23 @@
### 内核跟踪和 eBPF一些它们的历史
直到最近,仅有的方式是去在内核上打一个补丁程序或者借助于 SystemTap。[SytemTap][5] 是一个 Linux 系统跟踪器。简单地说,它提供了一个 DSL然后编译进内核模块,然后被内核加载运行。除了一些因安全原因禁用动态模块加载的生产系统之外,包括在那个时候我工作的那一个。另外的方式是为内核打一个补丁程序去触发一些事件,可能是基于 netlink。但是这很不方便。深入内核带来的缺点包括 “有趣的” 新 “特性” 增加了维护负担。
直到最近,内核跟踪的唯一方式是对内核上打补丁或者借助于 SystemTap。[SytemTap][5] 是一个 Linux 系统跟踪器。简单地说,它提供了一个 DSL编译进内核模块然后被内核加载运行。除了一些因安全原因禁用动态模块加载的生产系统之外包括在那个时候我开发的那一个。另外的方式是为内核打一个补丁程序以触发一些事件,可能是基于 netlink。但是这很不方便。深入内核带来的缺点包括 “有趣的” 新 “特性” ,并增加了维护负担。
从 Linux 3.15 开始给我们带来了希望,它支持任何可跟踪内核函数可安全转换为用户空间事件。在一般的计算机科学中,“安全” 是指 ”一些虚拟机”。这里说的情况不是这种意思。Linux 已经有多好年了。自从 Linux 2.1.75 在 1997 年正式发行以来。但是,对被称为伯克利包过滤器的 BPF 来说它的历史是很短的。正如它的名字所表达的那样,它最初是为 BSD 防火墙开发的。它仅有两个寄存器,并且它仅允许跳转,意味着你不能使用它写一个循环(好吧,如果你知道最大迭代次数并且去手工实现它,你也可以实现循环)。这一点保证了程序总会终止并且从来不会使系统处于 hang 的状态。还不确定它的作用吗?即便你用的是 iptables。它的作用正如 [CloudFlare 的 DDos 防护基础][6]。
从 Linux 3.15 开始给我们带来了希望,它支持任何可跟踪内核函数可安全转换为用户空间事件。在一般的计算机科学中,“安全” 是指 “某些虚拟机”。在此也不例外。自从 Linux 2.1.75 在 1997 年正式发行以来Linux 已经有这个多好年了。但是,它被称为伯克利包过滤器,或简称 BPF。正如它的名字所表达的那样,它最初是为 BSD 防火墙开发的。它仅有两个寄存器,并且它仅允许向前跳转,意味着你不能使用它写一个循环(好吧,如果你知道最大迭代次数并且去手工实现它,你也可以实现循环)。这一点保证了程序总会终止,而不会使系统处于挂起的状态。还不知道它有什么用?你用过 iptables 的话,其作用就是 [CloudFlare 的 DDos 防护的基础][6]。
好的,因此,随着 Linux 3.15[BPF 被扩展了][7] 转变为 eBPF。对于 “扩展的” BPF。它从两个 32 位寄存器升级到 10 个 64 位寄存器,并且增加了它们之间向后跳转的特性。它因此将被 [在 Linux 3.18 中进一步扩展][8],并将被移到网络子系统中并且增加了像映射maps)这样的工具。为保证安全,它 [引进了一个检查器][9],它验证所有的内存访问和可能的代码路径。如果检查器不能保证代码在固定的边界内,代码将被终止,它拒绝程序的初始插入。
好的,因此,随着 Linux 3.15[BPF 被扩展][7] 成为了 eBPF。对于 “扩展的” BPF。它从两个 32 位寄存器升级到 10 个 64 位寄存器,并且增加了它们之间向后跳转的特性。然后它 [在 Linux 3.18 中被进一步扩展][8],并将被移出网络子系统中并且增加了像映射map这样的工具。为保证安全 [引进了一个检查器][9],它验证所有的内存访问和可能的代码路径。如果检查器不能保证代码会终止在固定的边界内,它一开始就要拒绝程序的插入。
关于它的更多历史,可以看 [Oracle 的关于 eBPF 的一个很的演讲][10]。
关于它的更多历史,可以看 [Oracle 的关于 eBPF 的一个很的演讲][10]。
让我们开始吧!
### 来自 `inet_listen` 的问候
### 来自 inet_listen 的问候
因为写一个汇编程序并不是件容易的任务,甚至对于很优秀的我们来说,我将使用 [bcc][11]。bcc 是一个基于 LLVM 的采集工具,并且用 Python 抽象了底层机制。探针是用 C 写的,并且返回的结果可以被 Python 利用,来写一些非常简单的应用程序。
因为写一个汇编程序并不是件十分容易的任务,甚至对于很优秀的我们来说,我将使用 [bcc][11]。bcc 是一个基于 LLVM 的工具,并且用 Python 抽象了底层机制。探针是用 C 写的,并且返回的结果可以被 Python 利用,可以很容易地写一些不算简单的应用程序。
首先安装 bcc。对于一些示例你可能会被要求使用一个最新的内核版本(>= 4.4)。如果你想亲自去尝试一下这些示例,我强烈推荐你安装一台虚拟机 _而不是_ 一个 Docker 容器。你不能在一个容器中改变内核。作为一个非常新的很活跃的项目,安装教程高度依赖平台/版本。你可以在 [https://github.com/iovisor/bcc/blob/master/INSTALL.md][12] 上找到最新的教程。
首先安装 bcc。对于一些示例你可能会需要使用一个最新的内核版本(>= 4.4)。如果你想亲自去尝试一下这些示例,我强烈推荐你安装一台虚拟机 _而不是_ 一个 Docker 容器。你不能在一个容器中改变内核。作为一个非常新的很活跃的项目,安装教程高度依赖平台/版本。你可以在 [https://github.com/iovisor/bcc/blob/master/INSTALL.md][12] 上找到最新的教程。
现在,我希望在 TCP 套接字上进行监听,不管什么时候,只要有任何程序启动我将得到一个事件。当我在一个 `AF_INET` + `SOCK_STREAM` 套接字上调用一个 `listen()` 系统调用时,底层的内核函数是 [`inet_listen`][13]。我将钩在 `kprobe` 的输入点上,它启动时输出一个 “Hello World”。
现在,我希望不管在什么时候,只要有任何程序开始监听 TCP 套接字,我将得到一个事件。当我在一个 `AF_INET` + `SOCK_STREAM` 套接字上调用一个 `listen()` 系统调用时,底层的内核函数是 [`inet_listen`][13]。我将钩在一个“Hello World” `kprobe` 的入口上开始
```
from bcc import BPF
@ -54,7 +53,7 @@ bpf_text = """
#include <net/inet_sock.h>
#include <bcc/proto.h>
// 1\. Attach kprobe to "inet_listen"
// 1. Attach kprobe to "inet_listen"
int kprobe__inet_listen(struct pt_regs *ctx, struct socket *sock, int backlog)
{
bpf_trace_printk("Hello World!\\n");
@ -62,22 +61,25 @@ int kprobe__inet_listen(struct pt_regs *ctx, struct socket *sock, int backlog)
};
"""
# 2\. Build and Inject program
# 2. Build and Inject program
b = BPF(text=bpf_text)
# 3\. Print debug output
# 3. Print debug output
while True:
print b.trace_readline()
```
这个程序做了三件事件:1. 它使用一个命名惯例附加到一个内核探针上。如果函数被调用,输出 “my_probe”它使用 `b.attach_kprobe("inet_listen", "my_probe")` 被显式地附加。2.它使用 LLVM 去 new 一个 BPF 后端来构建程序。使用 (new) `bpf()` 系统调用去注入结果字节码并且按匹配的命名惯例自动附加探针。3. 从内核管道读取原生输出。
这个程序做了三件事件:
注意eBPF 的后端 LLVM 还很新。如果你认为你发了一个 bug你可以去升级它。
1. 它通过命名惯例来附加到一个内核探针上。如果函数被调用,比如说 `my_probe` 函数,它会使用 `b.attach_kprobe("inet_listen", "my_probe")` 显式附加。
2. 它使用 LLVM 新的 BPF 后端来构建程序。使用(新的) `bpf()` 系统调用去注入结果字节码,并且按匹配的命名惯例自动附加探针。
3. 从内核管道读取原生输出。
注意到 `bpf_trace_printk` 调用了吗?这是一个内核的 `printk()` 精简版的 debug 函数。使用时,它产生一个跟踪信息到 `/sys/kernel/debug/tracing/trace_pipe` 中的专门的内核管道。就像名字所暗示的那样,这是一个管道。如果多个读取者消费它,仅有一个将得到一个给定的行。对生产系统来说,这样是不合适的。
注意eBPF 的后端 LLVM 还很新。如果你认为你遇到了一个 bug你也许应该去升级
幸运的是Linux 3.19 引入了对消息传递的映射以及 Linux 4.4 带来了任意 perf 事件支持。在这篇文章的后面部分,我将演示 perf 事件。
注意到 `bpf_trace_printk` 调用了吗?这是一个内核的 `printk()` 精简版的调试函数。使用时,它产生跟踪信息到一个专门的内核管道 `/sys/kernel/debug/tracing/trace_pipe` 。就像名字所暗示的那样,这是一个管道。如果多个读取者在读取它,仅有一个将得到一个给定的行。对生产系统来说,这样是不合适的。
幸运的是Linux 3.19 引入了对消息传递的映射,以及 Linux 4.4 带来了对任意 perf 事件的支持。在这篇文章的后面部分,我将演示基于 perf 事件的方式。
```
# From a first console
@ -90,11 +92,11 @@ ubuntu@bcc:~$ nc -l 0 4242
```
Yay!
搞定!
### 抓取 backlog
现在,让我们输出一些很容易访问到的数据,叫做 “backlog”。backlog 是正在建立 TCP 连接的、即将成为 `accept()` 的数量。
现在,让我们输出一些很容易访问到的数据,比如说 “backlog”。backlog 是正在建立 TCP 连接的、即将被 `accept()` 的连接的数量。
只要稍微调整一下 `bpf_trace_printk`
@ -111,26 +113,24 @@ bpf_trace_printk("Listening with with up to %d pending connections!\\n", backlog
```
`nc` 是一个单个的连接程序,因此,在 1\. Nginx 或者 Redis 上的 backlog 在这里将输出 128 。但是,那是另外一件事。
`nc` 是个单连接程序,因此,其 backlog 是 1。而 Nginx 或者 Redis 上的 backlog 将在这里输出 128 。但是,那是另外一件事。
简单吧?现在让我们获取它的端口。
### 抓取端口和 IP
正在研究的 `inet_listen` 的信息来源于内核,我们知道它需要从 `socket` 对象中取得 `inet_sock`就像从源头拷贝,然后插入到跟踪器的开始处:
正在研究的 `inet_listen` 来源于内核,我们知道它需要从 `socket` 对象中取得 `inet_sock`只需要从源头拷贝,然后插入到跟踪器的开始处:
```
// cast types. Intermediate cast not needed, kept for readability
struct sock *sk = sock->sk;
struct inet_sock *inet = inet_sk(sk);
```
端口现在可以在按网络字节顺序(就是“从小到大”的顺序)的 `inet->inet_sport` 访问到。很容易吧!因此,我们将替换为 `bpf_trace_printk`
端口现在可以按网络字节顺序(就是“从小到大、大端”的顺序)从 `inet->inet_sport` 访问到。很容易吧!因此,我们只需要把 `bpf_trace_printk` 替换为
```
bpf_trace_printk("Listening on port %d!\\n", inet->inet_sport);
```
然后运行:
@ -141,10 +141,9 @@ ubuntu@bcc:~/dev/listen-evts$ sudo /python tcv4listen.py
R1 invalid mem access 'inv'
...
Exception: Failed to load BPF program kprobe__inet_listen
```
除了它不再简单之外Bcc 现在提升了 _许多_。直到写这篇文章的时候,几个问题已经被处理了,但是并没有全部处理完。这个错误意味着内核检查器可以证实程序中的内存访问是正确的。看显式的类型转换。我们需要一点帮助,以使访问更加明确。我们将使用 `bpf_probe_read` 可信任的函数去读取一个任意内存位置,虽然为了确保,要像如下的那样做一些必需的检查
抛出的异常并没有那么简单Bcc 现在提升了 _许多_。直到写这篇文章的时候,几个问题已经被处理了,但是并没有全部处理完。这个错误意味着内核检查器可以证实程序中的内存访问是正确的。看这个显式的类型转换。我们需要一点帮助,以使访问更加明确。我们将使用 `bpf_probe_read` 可信任的函数去读取一个任意内存位置,同时确保所有必要的检查都是用类似这样方法完成的
```
// Explicit initialization. The "=0" part is needed to "give life" to the variable on the stack
@ -156,7 +155,7 @@ bpf_probe_read(&lport, sizeof(lport), &(inet->inet_sport));
```
使用 `inet->inet_rcv_saddr` 读取 IPv4 边界地址,和它基本上是相同的。如果我把这些一起放上去,我们将得到 backlog端口和边界 IP
读取 IPv4 边界地址和它基本上是相同的,使用 `inet->inet_rcv_saddr` 。如果我把这些一起放上去,我们将得到 backlog端口和边界 IP
```
from bcc import BPF
@ -198,7 +197,7 @@ while True:
```
运行一个测试,输出的内容像下面这样:
测试运行输出的内容像下面这样:
```
(bcc)ubuntu@bcc:~/dev/listen-evts$ sudo python tcv4listen.py
@ -206,15 +205,15 @@ while True:
```
你的监听是在本地主机上提供的。因为没有处理为友好的输出,这里的地址以 16 进制的方式显示,并且那是有线的。并且它很酷。
这证明你的监听是在本地主机上的。因为没有处理为友好的输出,这里的地址以 16 进制的方式显示,但是这是没错的,并且它很酷。
注意:你可能想知道为什么 `ntohs` 和 `ntohl` 可以从 BPF 中被调用,即便它们并不可信。这是因为它们是宏,并且是从 “.h” 文件中来的内联函数,并且,在写这篇文章的时候一个小的 bug 已经 [修复了][14]。
全部完成之后,再来一个代码片断:我们希望获取相关的容器。在一个网络环境中,那意味着我们希望取得网络的命名空间。网络命名空间是一个容器的构建块,它允许它们拥有独立的网络。
全部达成了,还剩下一些:我们希望获取相关的容器。在一个网络环境中,那意味着我们希望取得网络的命名空间。网络命名空间是一个容器的构建块,它允许它们拥有独立的网络。
### 抓取网络命名空间:被迫引入的 perf 事件
在用户空间中,网络命名空间可以通过检查 `/proc/PID/ns/net` 的目标来确定,它将看起来像 `net:[4026531957]` 这样。方括号中的数字是节点的网络空间编号。这就是说,我们可以通过 `/proc` 来取得,但是这并不是好的方式,我们或许可以临时处理时用一下。我们可以从内核中直接抓取节点编号。幸运的是,那样做很容易:
在用户空间中,网络命名空间可以通过检查 `/proc/PID/ns/net` 的目标来确定,它将看起来像 `net:[4026531957]` 这样。方括号中的数字是网络空间的 inode 编号。这就是说,我们可以通过 `/proc` 来取得,但是这并不是好的方式,我们或许可以临时处理时用一下。我们可以从内核中直接抓取 inode 编号。幸运的是,那样做很容易:
```
// Create an populate the variable
@ -231,7 +230,6 @@ netns = sk->__sk_common.skc_net.net->ns.inum;
```
bpf_trace_printk("Listening on %x %d with %d pending connections in container %d\\n", ntohl(laddr), ntohs(lport), backlog, netns);
```
如果你尝试去运行它,你将看到一些令人难解的错误信息:
@ -240,24 +238,19 @@ bpf_trace_printk("Listening on %x %d with %d pending connections in container %d
(bcc)ubuntu@bcc:~/dev/listen-evts$ sudo python tcv4listen.py
error: in function kprobe__inet_listen i32 (%struct.pt_regs*, %struct.socket*, i32)
too many args to 0x1ba9108: i64 = Constant<6>
```
clang 想尝试去告诉你的是 “Hey pal`bpf_trace_printk` 只能带四个参数,你刚才给它传递了 5 个“。在这里我不打算继续追究细节了,但是,那是 BPF 的一个限制。如果你想继续去深入研究,[这里是一个很好的起点][15]。
clang 想尝试去告诉你的是 “嗨,哥们,`bpf_trace_printk` 只能带四个参数,你刚才给它传递了 5 个”。在这里我不打算继续追究细节了,但是,那是 BPF 的一个限制。如果你想继续去深入研究,[这里是一个很好的起点][15]。
去修复它的唯一方式是 … 停止调试并且准备投入使用。因此,让我们开始吧(确保运行在内核版本为 4.4 的 Linux 系统上)我将使用 perf 事件,它支持传递任意大小的结构体到用户空间。另外,只有我们的读者可以获得它,因此,多个没有关系的 eBPF 程序可以并发产生数据而不会出现问题。
去修复它的唯一方式是 … 停止调试并且准备投入使用。因此,让我们开始吧(确保运行在内核版本为 4.4 的 Linux 系统上)我将使用 perf 事件,它支持传递任意大小的结构体到用户空间。另外,只有我们的读者可以获得它,因此,多个没有关系的 eBPF 程序可以并发产生数据而不会出现问题。
去使用它吧,我们需要:
1. 定义一个结构体
2. 声明事件
3. 推送事件
4. 在 Python 端重新声明事件(这一步以后将不再需要)
5. 消费和格式化事件
5. 处理和格式化事件
这看起来似乎很多,其它并不多,看下面示例:
@ -314,7 +307,7 @@ while True:
```
来试一下吧。在这个示例中,我有一个 redis 运行在一个 Docker 容器中,并且 nc 在主机上:
来试一下吧。在这个示例中,我有一个 redis 运行在一个 Docker 容器中,并且 `nc` 运行在主机上:
```
(bcc)ubuntu@bcc:~/dev/listen-evts$ sudo python tcv4listen.py
@ -326,7 +319,7 @@ Listening on 7f000001 6588 with 1 pending connections in container 4026531957
### 结束语
现在,所有事情都可以在内核中使用 eBPF 将任何函数的调用设置为触发事件,并且在学习 eBPF 时,你将看到了我所遇到的大多数的问题。如果你希望去看这个工具的所有版本,像 IPv6 支持这样的一些技巧,看一看 [https://github.com/iovisor/bcc/blob/master/tools/solisten.py][16]。它现在是一个官方的工具,感谢 bcc 团队的支持。
现在,所有事情都可以在内核中使用 eBPF 将任何函数的调用设置为触发事件,并且你看到了我在学习 eBPF 时所遇到的大多数的问题。如果你希望去看这个工具的完整版本,像 IPv6 支持这样的一些技巧,看一看 [https://github.com/iovisor/bcc/blob/master/tools/solisten.py][16]。它现在是一个官方的工具,感谢 bcc 团队的支持。
更进一步地去学习,你可能需要去关注 Brendan Gregg 的博客,尤其是 [关于 eBPF 映射和统计的文章][17]。他是这个项目的主要贡献人之一。
@ -337,7 +330,7 @@ via: https://blog.yadutaf.fr/2016/03/30/turn-any-syscall-into-event-introducing-
作者:[Jean-Tiare Le Bigot][a]
译者:[qhwdw](https://github.com/qhwdw)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,98 @@
调试器到底怎样工作
======
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/annoyingbugs.png?itok=ywFZ99Gs)
供图opensource.com
调试器是那些大多数(即使不是每个)开发人员在软件工程职业生涯中至少使用过一次的软件之一,但是你们中有多少人知道它们到底是如何工作的?我在悉尼 [linux.conf.au 2018][1] 的演讲中,将讨论从头开始编写调试器...使用 [Rust][2]
在本文中,术语调试器/跟踪器可以互换。 “被跟踪者”是指正在被跟踪者跟踪的进程。
### ptrace 系统调用
大多数调试器严重依赖称为 `ptrace(2)` 的系统调用,其原型如下:
```
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
```
这是一个可以操纵进程几乎所有方面的系统调用;但是,在调试器可以连接到一个进程之前,“被跟踪者”必须以请求 `PTRACE_TRACEME` 调用 `ptrace`。这告诉 Linux父进程通过 `ptrace` 连接到这个进程是合法的。但是......我们如何强制一个进程调用 `ptrace`?很简单!`fork/execve` 提供了在 `fork` 之后但在被跟踪者真正开始使用 `execve` 之前调用 `ptrace` 的简单方法。很方便地,`fork` 还会返回被跟踪者的 `pid`,这是后面使用 `ptrace` 所必需的。
现在被跟踪者可以被调试器追踪,重要的变化发生了:
* 每当一个信号被传送到被调试者时,它就会停止,并且一个可以被 `wait` 系列系统调用捕获的等待事件被传送给跟踪器。
* 每个 `execve` 系统调用都会导致 `SIGTRAP` 被传递给被跟踪者。(与之前的项目相结合,这意味着被跟踪者在一个 `execve` 完全发生之前停止。)
这意味着,一旦我们发出 `PTRACE_TRACEME` 请求并调用 `execve` 系统调用来实际在被跟踪者(进程上下文)中启动程序时,被跟踪者将立即停止,因为 `execve` 会传递一个 `SIGTRAP`,并且会被跟踪器中的等待事件捕获。我们如何继续?正如人们所期望的那样,`ptrace` 有大量的请求可以用来告诉被跟踪者可以继续:
* `PTRACE_CONT`:这是最简单的。 被跟踪者运行,直到它接收到一个信号,此时等待事件被传递给跟踪器。这是最常见的实现真实世界调试器的“继续直至断点”和“永远继续”选项的方式。断点将在下面介绍。
* `PTRACE_SYSCALL`:与 `PTRACE_CONT` 非常相似,但在进入系统调用之前以及在系统调用返回到用户空间之前停止。它可以与其他请求(我们将在本文后面介绍)结合使用来监视和修改系统调用的参数或返回值。系统调用追踪程序 `strace` 很大程度上使用这个请求来获知进程发起了哪些系统调用。
* `PTRACE_SINGLESTEP`:这个很好理解。如果您之前使用过调试器(你会知道),此请求会执行下一条指令,然后立即停止。
我们可以通过各种各样的请求停止进程,但我们如何获得被调试者的状态?进程的状态大多是通过其寄存器捕获的,所以当然 `ptrace` 有一个请求来获得(或修改)寄存器:
* `PTRACE_GETREGS`:这个请求将给出被跟踪者刚刚被停止时的寄存器的状态。
* `PTRACE_SETREGS`:如果跟踪器之前通过调用 `PTRACE_GETREGS` 得到了寄存器的值,它可以在参数结构中修改相应寄存器的值并使用 `PTRACE_SETREGS` 将寄存器设为新值。
* `PTRACE_PEEKUSER``PTRACE_POKEUSER`:这些允许从被跟踪者的 `USER` 区读取信息,这里保存了寄存器和其他有用的信息。 这可以用来修改单一寄存器,而避免使用更重的 `PTRACE_{GET,SET}REGS` 请求。
在调试器仅仅修改寄存器是不够的。调试器有时需要读取一部分内存甚至对其进行修改。GDB 可以使用 `print` 得到一个内存位置或变量的值。`ptrace` 通过下面的方法实现这个功能:
* `PTRACE_PEEKTEXT``PTRACE_POKETEXT`:这些允许读取和写入被跟踪者地址空间中的一个字。当然,使用这个功能时被跟踪者要被暂停。
真实世界的调试器也有类似断点和观察点的功能。 在接下来的部分中我将深入体系结构对调试器支持的细节。为了清晰和简洁本文将只考虑x86。
### 体系结构的支持
`ptrace` 很酷,但它是如何工作? 在前面的部分中,我们已经看到 `ptrace` 跟信号有很大关系:`SIGTRAP` 可以在单步跟踪、`execve` 之前以及系统调用前后被传送。信号可以通过一些方式产生,但我们将研究两个具体的例子,以展示信号可以被调试器用来在给定的位置停止程序(有效地创建一个断点!):
* **未定义的指令**当一个进程尝试执行一个未定义的指令CPU 将产生一个异常。此异常通过 CPU 中断处理,内核中相应的中断处理程序被调用。这将导致一个 `SIGILL` 信号被发送给进程。 这依次导致进程被停止,跟踪器通过一个等待事件被通知,然后它可以决定后面做什么。在 x86 上,指令 `ud2` 被确保始终是未定义的。
* **调试中断**:前面的方法的问题是,`ud2` 指令需要占用两个字节的机器码。存在一条特殊的单字节指令能够触发一个中断,它是 `int $3`,机器码是 `0xCC`。 当该中断发出时,内核向进程发送一个 `SIGTRAP`,如前所述,跟踪器被通知。
这很好,但如何做我们胁迫的被跟踪者执行这些指令? 这很简单:利用 `ptrace``PTRACE_POKETEXT` 请求,它可以覆盖内存中的一个字。 调试器将使用 `PTRACE_PEEKTEXT` 读取该位置原来的值并替换为 `0xCC` ,然后在其内部状态中记录该处原来的值,以及它是一个断点的事实。 下次被跟踪者执行到该位置时,它将被通过 `SIGTRAP` 信号自动停止。 然后调试器的最终用户可以决定如何继续(例如,检查寄存器)。
好吧,我们已经讲过了断点,那观察点呢? 当一个特定的内存位置被读或写,调试器如何停止程序? 当然你不可能为了能够读或写内存而去把每一个指令都覆盖为 `int $3`。有一组调试寄存器为了更有效的满足这个目的而被设计出来:
* `DR0``DR3`:这些寄存器中的每个都包含一个地址(内存位置),调试器因为某种原因希望被跟踪者在那些地址那里停止。 其原因以掩码方式被设定在 `DR7` 寄存器中。
* `DR4``DR5`:这些分别是 `DR6``DR7`过时的别名。
* `DR6`:调试状态。包含有关 `DR0``DR3` 中的哪个寄存器导致调试异常被引发的信息。这被 Linux 用来计算与 `SIGTRAP` 信号一起传递给被跟踪者的信息。
* `DR7`调试控制。通过使用这些寄存器中的位调试器可以控制如何解释DR0至DR3中指定的地址。位掩码控制监视点的尺寸监视1,2,4或8个字节以及是否在执行、读取、写入时引发异常或在读取或写入时引发异常。
由于调试寄存器是进程的 `USER` 区域的一部分,调试器可以使用 `PTRACE_POKEUSER` 将值写入调试寄存器。调试寄存器只与特定进程相关,因此在进程抢占并重新获得 CPU 控制权之前,调试寄存器会被恢复。
### 冰山一角
我们已经浏览了一个调试器的“冰山”:我们已经介绍了 `ptrace`,了解了它的一些功能,然后我们看到了 `ptrace` 是如何实现的。 `ptrace` 的某些部分可以用软件实现,但其它部分必须用硬件来实现,否则实现代价会非常高甚至无法实现。
当然有很多我们没有涉及。例如“调试器如何知道变量在内存中的位置?”等问题由于空间和时间限制而尚未解答,但我希望你从本文中学到了一些东西;如果它激起你的兴趣,网上有足够的资源可以了解更多。
想要了解更多,请查看 [linux.conf.au][1] 中 Levente Kurusa 的演讲 [Let's Write a Debugger!][3],于一月 22-26 日在悉尼举办。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/1/how-debuggers-really-work
作者:[Levente Kurusa][a]
译者:[stephenxs](https://github.com/stephenxs)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/lkurusa
[1]:https://linux.conf.au/index.html
[2]:https://www.rust-lang.org
[3]:https://rego.linux.conf.au/schedule/presentation/91/

View File

@ -0,0 +1,107 @@
如何在 Linux 中的特定时间运行命令
======
![](https://www.ostechnix.com/wp-content/uploads/2018/02/Run-A-Command-For-A-Specific-Time-In-Linux-1-720x340.png)
有一天,我使用 rsync 将大文件传输到局域网上的另一个系统。由于它是非常大的文件,大约需要 20 分钟才能完成。我不想再等了,我也不想按 CTRL+C 来终止这个过程。我只是想知道在类 Unix 操作系统中是否有简单的方法可以在特定的时间运行一个命令,并且一旦超时就自动杀死它 - 因此有了这篇文章。请继续阅读。
### 在 Linux 中在特定时间运行命令
我们可以用两种方法做到这一点。
#### 方法 1 - 使用 “timeout” 命令
最常用的方法是使用 **timeout** 命令。对于那些不知道的人来说timeout 命令会有效地限制一个进程的绝对执行时间。timeout 命令是 GNU coreutils 包的一部分,因此它预装在所有 GNU/Linux 系统中。
假设你只想运行一个命令 5 秒钟,然后杀死它。为此,我们使用:
```
$ timeout <time-limit-interval> <command>
```
例如,以下命令将在 10 秒后终止。
```
$ timeout 10s tail -f /var/log/pacman.log
```
![][2]
你也可以不用在秒数后加后缀 “s”。以下命令与上面的相同。
```
$ timeout 10 tail -f /var/log/pacman.log
```
其他可用的后缀有:
* m 代表分钟。
* h 代表小时。
* d 代表天。
如果你运行这个 **tail -f /var/log/pacman.log** 命令,它将继续运行,直到你按 CTRL+C 手动结束它。但是,如果你使用 **timeout** 命令运行它,它将在给定的时间间隔后自动终止。如果该命令在超时后仍在运行,则可以发送 **kill** 信号,如下所示。
```
$ timeout -k 20 10 tail -f /var/log/pacman.log
```
在这种情况下,如果 tail 命令在 10 秒后仍然运行timeout 命令将在 20 秒后发送一个 kill 信号并结束。
有关更多详细信息,请查看手册页。
```
$ man timeout
```
有时,某个特定程序可能需要很长时间才能完成并最终冻结你的系统。在这种情况下,你可以使用此技巧在特定时间后自动结束该进程。
另外,可以考虑使用 **cpulimit**,一个简单的限制进程的 CPU 使用率的程序。有关更多详细信息,请查看下面的链接。
#### 方法 2 - 使用 “Timelimit” 程序
Timelimit 使用提供的参数执行给定的命令,并在给定的时间后使用给定的信号终止进程。首先,它会发送警告信号,然后在超时后发送 **kill** 信号。
与 timeout 不同Timelimit 有更多选项。你可以传递参数数量,如 killsig、warnsig、killtime、warntime 等。它存在于基于 Debian 的系统的默认仓库中。所以,你可以使用命令来安装它:
```
$ sudo apt-get install timelimit
```
对于基于 Arch 的系统,它在 AUR 中存在。因此,你可以使用任何 AUR 助手进行安装,例如 [**Pacaur**][3]、[**Packer**][4]、[**Yay**][5]、[**Yaourt**][6] 等。
对于其他发行版,请[**在这里**][7]下载源码并手动安装。安装 Timelimit 后,运行下面的命令一段特定的时间,例如 10 秒钟:
```
$ timelimit -t10 tail -f /var/log/pacman.log
```
如果不带任何参数运行 timelimit它将使用默认值warntime=3600 秒、warnsig=15、killtime=120、killsig=9。有关更多详细信息请参阅本指南最后给出的手册页和项目网站。
```
$ man timelimit
```
今天就是这些。我希望对你有用。还有更好的东西。敬请关注!
干杯!
--------------------------------------------------------------------------------
via: https://www.ostechnix.com/run-command-specific-time-linux/
作者:[SK][a]
译者:[geekpi](https://github.com/geekpi)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.ostechnix.com/author/sk/
[2]:http://www.ostechnix.com/wp-content/uploads/2018/02/Timeout.gif
[3]:https://www.ostechnix.com/install-pacaur-arch-linux/
[4]:https://www.ostechnix.com/install-packer-arch-linux-2/
[5]:https://www.ostechnix.com/yay-found-yet-another-reliable-aur-helper/
[6]:https://www.ostechnix.com/install-yaourt-arch-linux/
[7]:http://devel.ringlet.net/sysutils/timelimit/#download