分类 技术 下的文章

学习如何在 Linux 中使用 parted 命令来对存储设备分区。

在 Linux 中创建和删除分区是一种常见的操作,因为存储设备(如硬盘驱动器和 USB 驱动器)在使用之前必须以某种方式进行结构化。在大多数情况下,大型存储设备被分为称为 分区 partition 的独立部分。分区操作允许您将硬盘分割成独立的部分,每个部分都像是一个硬盘驱动器一样。如果您运行多个操作系统,那么分区是非常有用的。

在 Linux 中有许多强大的工具可以创建、删除和操作磁盘分区。在本文中,我将解释如何使用 parted 命令,这对于大型磁盘设备和许多磁盘分区尤其有用。parted 与更常见的 fdiskcfdisk 命令之间的区别包括:

  • GPT 格式:parted 命令可以创建全局惟一的标识符分区表 GPT,而 fdiskcfdisk 则仅限于 DOS 分区表。
  • 更大的磁盘: DOS 分区表可以格式化最多 2TB 的磁盘空间,尽管在某些情况下最多可以达到 16TB。然而,一个 GPT 分区表可以处理最多 8ZiB 的空间。
  • 更多的分区: 使用主分区和扩展分区,DOS 分区表只允许 16 个分区。在 GPT 中,默认情况下您可以得到 128 个分区,并且可以选择更多的分区。
  • 可靠性: 在 DOS 分区表中,只保存了一份分区表备份,在 GPT 中保留了两份分区表的备份(在磁盘的起始和结束部分),同时 GPT 还使用了 CRC 校验和来检查分区表的完整性,在 DOS 分区中并没有实现。

由于现在的磁盘更大,需要更灵活地使用它们,建议使用 parted 来处理磁盘分区。大多数时候,磁盘分区表是作为操作系统安装过程的一部分创建的。在向现有系统添加存储设备时,直接使用 parted 命令非常有用。

尝试一下 parted

下面解释了使用 parted 命令对存储设备进行分区的过程。为了尝试这些步骤,我强烈建议使用一块全新的存储设备或一种您不介意将其内容删除的设备。

1、列出分区

使用 parted -l 来标识你要进行分区的设备。一般来说,第一个硬盘 (/dev/sda/dev/vda )保存着操作系统, 因此要寻找另一个磁盘,以找到你想要分区的磁盘 (例如,/dev/sdb/dev/sdc/dev/vdb/dev/vdc 等)。

$ sudo parted -l
[sudo] password for daniel: 
Model: ATA RevuAhn_850X1TU5 (scsi)
Disk /dev/vdc: 512GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start   End    Size   Type     File system  Flags
 1      1049kB  525MB  524MB  primary  ext4         boot
 2      525MB   512GB  512GB  primary               lvm

2、打开存储设备

使用 parted 选中您要分区的设备。在这里例子中,是虚拟系统上的第三个磁盘(/dev/vdc)。指明你要使用哪一个设备非常重要。 如果你仅仅输入了 parted 命令而没有指定设备名字, 它会随机选择一个设备进行操作。

$ sudo parted /dev/vdc
GNU Parted 3.2
Using /dev/vdc
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted)

3、 设定分区表

设置分区表为 GPT ,然后输入 Yes 开始执行。

(parted) mklabel gpt 
Warning: the existing disk label on /dev/vdc will be destroyed 
and all data on this disk will be lost. Do you want to continue? 
Yes/No? Yes

mklabelmktable 命令用于相同的目的(在存储设备上创建分区表)。支持的分区表有:aix、amiga、bsd、dvh、gpt、mac、ms-dos、pc98、sun 和 loop。记住 mklabel 不会创建一个分区,而是创建一个分区表。

4、 检查分区表

查看存储设备信息:

(parted) print 
Model: Virtio Block Device (virtblk) 
Disk /dev/vdc: 1396MB 
Sector size (logical/physical): 512B/512B 
Partition Table: gpt 
Disk Flags: 
Number Start End Size File system Name Flags

5、 获取帮助

为了知道如何去创建一个新分区,输入: (parted) help mkpart

(parted) help mkpart 
  mkpart PART-TYPE [FS-TYPE] START END     make a partition

        PART-TYPE is one of: primary, logical, extended
        FS-TYPE is one of: btrfs, nilfs2, ext4, ext3, ext2, fat32, fat16, hfsx, hfs+, hfs, jfs, swsusp,
        linux-swap(v1), linux-swap(v0), ntfs, reiserfs, hp-ufs, sun-ufs, xfs, apfs2, apfs1, asfs, amufs5,
        amufs4, amufs3, amufs2, amufs1, amufs0, amufs, affs7, affs6, affs5, affs4, affs3, affs2, affs1,
        affs0, linux-swap, linux-swap(new), linux-swap(old)
        START and END are disk locations, such as 4GB or 10%.  Negative values count from the end of the
        disk.  For example, -1s specifies exactly the last sector.

        'mkpart' makes a partition without creating a new file system on the partition.  FS-TYPE may be
        specified to set an appropriate partition ID.

6、 创建分区

为了创建一个新分区(在这个例子中,分区 0 有 1396MB),输入下面的命令:

(parted) mkpart primary 0 1396MB 

Warning: The resulting partition is not properly aligned for best performance 
Ignore/Cancel? I 

(parted) print 
Model: Virtio Block Device (virtblk) 
Disk /dev/vdc: 1396MB 
Sector size (logical/physical): 512B/512B 
Partition Table: gpt 
Disk Flags: 
Number Start   End     Size    File system Name Flags 
1      17.4kB  1396MB  1396MB  primary

文件系统类型(fstype)并不是在 /dev/vdc1上创建 ext4 文件系统。 DOS 分区表的分区类型是 主分区 primary 逻辑分区 logical 扩展分区 extended 。 在 GPT 分区表中,分区类型用作分区名称。 在 GPT 下必须提供分区名称;在上例中,primary 是分区名称,而不是分区类型。

7、 保存退出

当你退出 parted 时,修改会自动保存。退出请输入如下命令:

(parted) quit
Information: You may need to update /etc/fstab.
$

谨记

当您添加新的存储设备时,请确保在开始更改其分区表之前确定正确的磁盘。如果您错误地更改了包含计算机操作系统的磁盘分区,会使您的系统无法启动。


via: https://opensource.com/article/18/6/how-partition-disk-linux

作者:Daniel Oh 选题:lujun9972 译者:amwps290 校对:wxy

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

长文预警:在最新的 Linux 内核(>=4.4)中使用 eBPF,你可以将任何内核函数调用转换为一个带有任意数据的用户空间事件。这通过 bcc 来做很容易。这个探针是用 C 语言写的,而数据是由 Python 来处理的。

如果你对 eBPF 或者 Linux 跟踪不熟悉,那你应该好好阅读一下整篇文章。本文尝试逐步去解决我在使用 bcc/eBPF 时遇到的困难,以为您节省我在搜索和挖掘上花费的时间。

在 Linux 的世界中关于推送与轮询的一个看法

当我开始在容器上工作的时候,我想知道我们怎么基于一个真实的系统状态去动态更新一个负载均衡器的配置。一个通用的策略是这样做的,无论什么时候只要一个容器启动,容器编排器触发一个负载均衡配置更新动作,负载均衡器去轮询每个容器,直到它的健康状态检查结束。它也许只是简单进行 “SYN” 测试。

虽然这种配置方式可以有效工作,但是它的缺点是你的负载均衡器为了让一些系统变得可用需要等待,而不是 … 让负载去均衡。

可以做的更好吗?

当你希望在一个系统中让一个程序对一些变化做出反应,这里有两种可能的策略。程序可以去 轮询 系统去检测变化,或者,如果系统支持,系统可以 推送 事件并且让程序对它作出反应。你希望去使用推送还是轮询取决于上下文环境。一个好的经验法则是,基于处理时间的考虑,如果事件发生的频率较低时使用推送,而当事件发生的较快或者让系统变得不可用时切换为轮询。例如,一般情况下,网络驱动程序将等待来自网卡的事件,但是,像 dpdk 这样的框架对事件将主动轮询网卡,以达到高吞吐低延迟的目的。

理想状态下,我们将有一些内核接口告诉我们:

  • “容器管理器,你好,我刚才为容器 servestaticfiles 的 Nginx-ware 创建了一个套接字,或许你应该去更新你的状态?
  • “好的,操作系统,感谢你告诉我这个事件”

虽然 Linux 有大量的接口去处理事件,对于文件事件高达 3 个,但是没有专门的接口去得到套接字事件提示。你可以得到路由表事件、邻接表事件、连接跟踪事件、接口变化事件。唯独没有套接字事件。或者,也许它深深地隐藏在一个 Netlink 接口中。

理想情况下,我们需要一个做这件事的通用方法,怎么办呢?

内核跟踪和 eBPF,一些它们的历史

直到最近,内核跟踪的唯一方式是对内核上打补丁或者借助于 SystemTap。SytemTap 是一个 Linux 系统跟踪器。简单地说,它提供了一个 DSL,编译进内核模块,然后被内核加载运行。除了一些因安全原因禁用动态模块加载的生产系统之外,包括在那个时候我开发的那一个。另外的方式是为内核打一个补丁程序以触发一些事件,可能是基于 netlink。但是这很不方便。深入内核所带来的缺点包括 “有趣的” 新 “特性” ,并增加了维护负担。

从 Linux 3.15 开始给我们带来了希望,它支持将任何可跟踪内核函数可安全转换为用户空间事件。在一般的计算机科学中,“安全” 是指 “某些虚拟机”。在此也不例外。自从 Linux 2.1.75 在 1997 年正式发行以来,Linux 已经有这个多好年了。但是,它被称为伯克利包过滤器,或简称 BPF。正如它的名字所表达的那样,它最初是为 BSD 防火墙开发的。它仅有两个寄存器,并且它仅允许向前跳转,这意味着你不能使用它写一个循环(好吧,如果你知道最大迭代次数并且去手工实现它,你也可以实现循环)。这一点保证了程序总会终止,而不会使系统处于挂起的状态。还不知道它有什么用?你用过 iptables 的话,其作用就是 CloudFlare 的 DDos 防护的基础

好的,因此,随着 Linux 3.15,BPF 被扩展 成为了 eBPF。对于 “扩展的” BPF。它从两个 32 位寄存器升级到 10 个 64 位寄存器,并且增加了它们之间向后跳转的特性。然后它 在 Linux 3.18 中被进一步扩展,并将被移出网络子系统中,并且增加了像映射(map)这样的工具。为保证安全,它 引进了一个检查器,它验证所有的内存访问和可能的代码路径。如果检查器不能保证代码会终止在固定的边界内,它一开始就要拒绝程序的插入。

关于它的更多历史,可以看 Oracle 的关于 eBPF 的一个很棒的演讲

让我们开始吧!

来自 inet\_listen 的问候

因为写一个汇编程序并不是件十分容易的任务,甚至对于很优秀的我们来说,我将使用 bcc。bcc 是一个基于 LLVM 的工具集,并且用 Python 抽象了底层机制。探针是用 C 写的,并且返回的结果可以被 Python 利用,可以很容易地写一些不算简单的应用程序。

首先安装 bcc。对于一些示例,你可能会需要使用一个最新的内核版本(>= 4.4)。如果你想亲自去尝试一下这些示例,我强烈推荐你安装一台虚拟机, 而不是 一个 Docker 容器。你不能在一个容器中改变内核。作为一个非常新的很活跃的项目,其安装教程高度依赖于平台/版本。你可以在 https://github.com/iovisor/bcc/blob/master/INSTALL.md 上找到最新的教程。

现在,我希望不管在什么时候,只要有任何程序开始监听 TCP 套接字,我将得到一个事件。当我在一个 AF_INET + SOCK_STREAM 套接字上调用一个 listen() 系统调用时,其底层的内核函数是 inet_listen。我将从钩在一个“Hello World” kprobe 的入口上开始。

from bcc import BPF

# Hello BPF Program
bpf_text = """ 
#include <net/inet_sock.h>
#include <bcc/proto.h>

// 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");
    return 0;
};
"""

# 2. Build and Inject program
b = BPF(text=bpf_text)

# 3. Print debug output
while True:
    print b.trace_readline()

这个程序做了三件事件:

  1. 它通过命名惯例来附加到一个内核探针上。如果函数被调用,比如说 my_probe 函数,它会使用 b.attach_kprobe("inet_listen", "my_probe") 显式附加。
  2. 它使用 LLVM 新的 BPF 后端来构建程序。使用(新的) bpf() 系统调用去注入结果字节码,并且按匹配的命名惯例自动附加探针。
  3. 从内核管道读取原生输出。

注意:eBPF 的后端 LLVM 还很新。如果你认为你遇到了一个 bug,你也许应该去升级。

注意到 bpf_trace_printk 调用了吗?这是一个内核的 printk() 精简版的调试函数。使用时,它产生跟踪信息到一个专门的内核管道 /sys/kernel/debug/tracing/trace_pipe 。就像名字所暗示的那样,这是一个管道。如果多个读取者在读取它,仅有一个将得到一个给定的行。对生产系统来说,这样是不合适的。

幸运的是,Linux 3.19 引入了对消息传递的映射,以及 Linux 4.4 带来了对任意 perf 事件的支持。在这篇文章的后面部分,我将演示基于 perf 事件的方式。

# From a first console
ubuntu@bcc:~/dev/listen-evts$ sudo /python tcv4listen.py 
              nc-4940  [000] d... 22666.991714: : Hello World!

# From a second console
ubuntu@bcc:~$ nc -l 0 4242
^C

搞定!

抓取 backlog

现在,让我们输出一些很容易访问到的数据,比如说 “backlog”。backlog 是正在建立 TCP 连接的、即将被 accept() 的连接的数量。

只要稍微调整一下 bpf_trace_printk

bpf_trace_printk("Listening with with up to %d pending connections!\\n", backlog);

如果你用这个 “革命性” 的改善重新运行这个示例,你将看到如下的内容:

(bcc)ubuntu@bcc:~/dev/listen-evts$ sudo python tcv4listen.py 
              nc-5020  [000] d... 25497.154070: : Listening with with up to 1 pending connections!

nc 是个单连接程序,因此,其 backlog 是 1。而 Nginx 或者 Redis 上的 backlog 将在这里输出 128 。但是,那是另外一件事。

简单吧?现在让我们获取它的端口。

抓取端口和 IP

正在研究的 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 替换为:

bpf_trace_printk("Listening on port %d!\\n", inet->inet_sport);

然后运行:

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 可信任的函数去读取一个任意内存位置,同时确保所有必要的检查都是用类似这样方法完成的:

// Explicit initialization. The "=0" part is needed to "give life" to the variable on the stack
u16 lport = 0;

// Explicit arbitrary memory access. Read it:
//    Read into 'lport', 'sizeof(lport)' bytes from 'inet->inet_sport' memory location
bpf_probe_read(&lport, sizeof(lport), &(inet->inet_sport));

读取 IPv4 边界地址和它基本上是相同的,使用 inet->inet_rcv_saddr 。如果我把这些一起放上去,我们将得到 backlog、端口和边界 IP:

from bcc import BPF  

# BPF Program  
bpf_text = """   
#include <net/sock.h>  
#include <net/inet_sock.h>  
#include <bcc/proto.h>  

// Send an event for each IPv4 listen with PID, bound address and port  
int kprobe__inet_listen(struct pt_regs *ctx, struct socket *sock, int backlog)  
{  
    // Cast types. Intermediate cast not needed, kept for readability  
    struct sock *sk = sock->sk;  
    struct inet_sock *inet = inet_sk(sk);  

    // Working values. You *need* to initialize them to give them "life" on the stack and use them afterward  
    u32 laddr = 0;  
    u16 lport = 0;  

    // Pull in details. As 'inet_sk' is internally a type cast, we need to use 'bpf_probe_read'  
    // read: load into 'laddr' 'sizeof(laddr)' bytes from address 'inet->inet_rcv_saddr'  
    bpf_probe_read(&laddr, sizeof(laddr), &(inet->inet_rcv_saddr));  
    bpf_probe_read(&lport, sizeof(lport), &(inet->inet_sport));  

    // Push event
    bpf_trace_printk("Listening on %x %d with %d pending connections\\n", ntohl(laddr), ntohs(lport), backlog);  
    return 0;
};  
"""  

# Build and Inject BPF  
b = BPF(text=bpf_text)  

# Print debug output  
while True:  
  print b.trace_readline()

测试运行输出的内容像下面这样:

(bcc)ubuntu@bcc:~/dev/listen-evts$ sudo python tcv4listen.py 
              nc-5024  [000] d... 25821.166286: : Listening on 7f000001 4242 with 1 pending connections

这证明你的监听是在本地主机上的。因为没有处理为友好的输出,这里的地址以 16 进制的方式显示,但是这是没错的,并且它很酷。

注意:你可能想知道为什么 ntohsntohl 可以从 BPF 中被调用,即便它们并不可信。这是因为它们是宏,并且是从 “.h” 文件中来的内联函数,并且,在写这篇文章的时候一个小的 bug 已经 修复了

全部达成了,还剩下一些:我们希望获取相关的容器。在一个网络环境中,那意味着我们希望取得网络的命名空间。网络命名空间是一个容器的构建块,它允许它们拥有独立的网络。

抓取网络命名空间:被迫引入的 perf 事件

在用户空间中,网络命名空间可以通过检查 /proc/PID/ns/net 的目标来确定,它将看起来像 net:[4026531957] 这样。方括号中的数字是网络空间的 inode 编号。这就是说,我们可以通过 /proc 来取得,但是这并不是好的方式,我们或许可以临时处理时用一下。我们可以从内核中直接抓取 inode 编号。幸运的是,那样做很容易:

// Create an populate the variable
u32 netns = 0;

// Read the netns inode number, like /proc does
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);

如果你尝试去运行它,你将看到一些令人难解的错误信息:

(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 想尝试去告诉你的是 “嗨,哥们,bpf_trace_printk 只能带四个参数,你刚才给它传递了 5 个”。在这里我不打算继续追究细节了,但是,那是 BPF 的一个限制。如果你想继续去深入研究,这里是一个很好的起点

去修复它的唯一方式是 … 停止调试并且准备投入使用。因此,让我们开始吧(确保运行在内核版本为 4.4 的 Linux 系统上)。我将使用 perf 事件,它支持传递任意大小的结构体到用户空间。另外,只有我们的读者可以获得它,因此,多个没有关系的 eBPF 程序可以并发产生数据而不会出现问题。

去使用它吧,我们需要:

  1. 定义一个结构体
  2. 声明事件
  3. 推送事件
  4. 在 Python 端重新声明事件(这一步以后将不再需要)
  5. 处理和格式化事件

这看起来似乎很多,其它并不多,看下面示例:

// At the begining of the C program, declare our event
struct listen_evt_t {
    u64 laddr;
    u64 lport;
    u64 netns;
    u64 backlog;
};
BPF_PERF_OUTPUT(listen_evt);

// In kprobe__inet_listen, replace the printk with
struct listen_evt_t evt = {
    .laddr = ntohl(laddr),
    .lport = ntohs(lport),
    .netns = netns,
    .backlog = backlog,
};
listen_evt.perf_submit(ctx, &evt, sizeof(evt));

Python 端将需要一点更多的工作:

# We need ctypes to parse the event structure
import ctypes

# Declare data format
class ListenEvt(ctypes.Structure):
    _fields_ = [
        ("laddr",   ctypes.c_ulonglong),
        ("lport",   ctypes.c_ulonglong),
        ("netns",   ctypes.c_ulonglong),
        ("backlog", ctypes.c_ulonglong),
    ]

# Declare event printer
def print_event(cpu, data, size):
    event = ctypes.cast(data, ctypes.POINTER(ListenEvt)).contents
    print("Listening on %x %d with %d pending connections in container %d" % (
        event.laddr,
        event.lport,
        event.backlog,
        event.netns,
    ))

# Replace the event loop
b["listen_evt"].open_perf_buffer(print_event)
while True:
    b.kprobe_poll()

来试一下吧。在这个示例中,我有一个 redis 运行在一个 Docker 容器中,并且 nc 运行在主机上:

(bcc)ubuntu@bcc:~/dev/listen-evts$ sudo python tcv4listen.py
Listening on 0 6379 with 128 pending connections in container 4026532165
Listening on 0 6379 with 128 pending connections in container 4026532165
Listening on 7f000001 6588 with 1 pending connections in container 4026531957

结束语

现在,所有事情都可以在内核中使用 eBPF 将任何函数的调用设置为触发事件,并且你看到了我在学习 eBPF 时所遇到的大多数的问题。如果你希望去看这个工具的完整版本,像 IPv6 支持这样的一些技巧,看一看 https://github.com/iovisor/bcc/blob/master/tools/solisten.py。它现在是一个官方的工具,感谢 bcc 团队的支持。

更进一步地去学习,你可能需要去关注 Brendan Gregg 的博客,尤其是 关于 eBPF 映射和统计的文章。他是这个项目的主要贡献人之一。


via: https://blog.yadutaf.fr/2016/03/30/turn-any-syscall-into-event-introducing-ebpf-kernel-probes/

作者:Jean-Tiare Le Bigot 译者:qhwdw 校对:wxy

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

我们已经学会了如何为多个平台构建包,以及如何从源代码构建包。 今天,我们将学习如何将 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 辅助工具(如 PacaurPackerYaourt )来安装它。

使用 pacaur 安装 debtap 运行:

pacaur -S debtap

使用 Packer 安装:

packer -S debtap

使用 Yaourt 安装:

yaourt -S debtap

同时,你的 Arch 系统也应该已经安装好了 bashbinutilspkgfilefakeroot 包。

在安装 Debtap 和所有上述依赖关系之后,运行以下命令来创建/更新 pkgfile 和 debtap 数据库。

sudo debtap -u

示例输出是:

==> Synchronizing pkgfile database...
:: Updating 6 repos...
 download complete: archlinuxfr [ 151.7 KiB 67.5K/s 5 remaining]
 download complete: multilib [ 319.5 KiB 36.2K/s 4 remaining]
 download complete: core [ 707.7 KiB 49.5K/s 3 remaining]
 download complete: testing [ 1716.3 KiB 58.2K/s 2 remaining]
 download complete: extra [ 7.4 MiB 109K/s 1 remaining]
 download complete: community [ 16.9 MiB 131K/s 0 remaining]
:: download complete in 131.47s < 27.1 MiB 211K/s 6 files >
:: waiting for 1 process to finish repacking repos...
==> Synchronizing debtap database...
 % Total % Received % Xferd Average Speed Time Time Time Current
 Dload Upload Total Spent Left Speed
100 34.1M 100 34.1M 0 0 206k 0 0:02:49 0:02:49 --:--:-- 180k
 % Total % Received % Xferd Average Speed Time Time Time Current
 Dload Upload Total Spent Left Speed
100 814k 100 814k 0 0 101k 0 0:00:08 0:00:08 --:--:-- 113k
 % Total % Received % Xferd Average Speed Time Time Time Current
 Dload Upload Total Spent Left Speed
100 120k 100 120k 0 0 61575 0 0:00:02 0:00:02 --:--:-- 52381
 % Total % Received % Xferd Average Speed Time Time Time Current
 Dload Upload Total Spent Left Speed
100 35.4M 100 35.4M 0 0 175k 0 0:03:27 0:03:27 --:--:-- 257k
==> Downloading latest virtual packages list...
 % Total % Received % Xferd Average Speed Time Time Time Current
 Dload Upload Total Spent Left Speed
100 149 0 149 0 0 49 0 --:--:-- 0:00:03 --:--:-- 44
100 11890 0 11890 0 0 2378 0 --:--:-- 0:00:05 --:--:-- 8456
==> Downloading latest AUR packages list...
 % Total % Received % Xferd Average Speed Time Time Time Current
 Dload Upload Total Spent Left Speed
100 264k 0 264k 0 0 30128 0 --:--:-- 0:00:09 --:--:-- 74410
==> Generating base group packages list...
==> All steps successfully completed!

你至少需要运行上述命令一次。

现在是时候开始转换包了。

比如说要使用 debtap 转换包 Quadrapassel,你可以这样做:

debtap quadrapassel_3.22.0-1.1_arm64.deb

上述的命令会将 DEB 包文件转换为 Arch Linux 包。你需要输入包的维护者和许可证,输入他们,然后按下回车键就可以开始转换了。

包转换的过程可能依赖于你的 CPU 的速度从几秒到几分钟不等。喝一杯咖啡等一等。

示例输出:

==> Extracting package data...
==> Fixing possible directories structure differencies...
==> Generating .PKGINFO file...

:: Enter Packager name:
quadrapassel

:: Enter package license (you can enter multiple licenses comma separated):
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)...

:: 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:

==> Generating .MTREE file...

==> Creating final package...
==> Package successfully created!
==> Removing leftover files...

:Quadrapassel 在 Arch Linux 官方的软件库中早已可用,我只是用它来说明一下。

如果在包转化的过程中,你不想回答任何问题,使用 -q 略过除了编辑元数据之外的所有问题。

debtap -q quadrapassel_3.22.0-1.1_arm64.deb

为了略过所有的问题(不推荐),使用 -Q

debtap -Q quadrapassel_3.22.0-1.1_arm64.deb

转换完成后,您可以使用 pacman 在 Arch 系统中安装新转换的软件包,如下所示。

sudo pacman -U <package-name>

显示帮助文档,使用 -h

$ debtap -h
Syntax: debtap [options] package_filename

Options:

 -h --h -help --help Prints this help message
 -u --u -update --update Update debtap database
 -q --q -quiet --quiet Bypass all questions, except for editing metadata file(s)
 -Q --Q -Quiet --Quiet Bypass all questions (not recommended)
 -s --s -pseudo --pseudo Create a pseudo-64-bit package from a 32-bit .deb package
 -w --w -wipeout --wipeout Wipeout versions from all dependencies, conflicts etc.
 -p --p -pkgbuild --pkgbuild Additionally generate a PKGBUILD file
 -P --P -Pkgbuild --Pkgbuild Generate a PKGBUILD file only

这就是现在要讲的。希望这个工具有所帮助。如果你发现我们的指南有用,请花一点时间在你的社交、专业网络分享并支持我们!

更多的好东西来了。请继续关注!

干杯!


via: https://www.ostechnix.com/convert-deb-packages-arch-linux-packages/

作者:SK 译者:amwps290 校对:wxy

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

利用这 8 个命令可以学习 Docker 容器的基本管理方式。这是一个为 Docker 初学者准备的,带有示范命令输出的指南。

Docker 容器管理命令

在这篇文章中,我们将带你学习 8 个基本的 Docker 容器命令,它们操控着 Docker 容器的基本活动,例如 运行 run 列举 list 停止 stop 、 查看 历史纪录 logs 删除 delete 等等。如果你对 Docker 的概念很陌生,推荐你看看我们的 介绍指南,来了解 Docker 的基本内容以及 如何 在 Linux 上安装 Docker。 现在让我们赶快进入要了解的命令:

如何运行 Docker 容器?

众所周知,Docker 容器只是一个运行于 宿主操作系统 host OS 上的应用进程,所以你需要一个镜像来运行它。Docker 镜像以进程的方式运行时就叫做 Docker 容器。你可以加载本地 Docker 镜像,也可以从 Docker Hub 上下载。Docker Hub 是一个提供公有和私有镜像来进行 拉取 pull 操作的集中仓库。官方的 Docker Hub 位于 hub.docker.com。 当你指示 Docker 引擎运行容器时,它会首先搜索本地镜像,如果没有找到,它会从 Docker Hub 上拉取相应的镜像。

让我们运行一个 Apache web 服务器的 Docker 镜像,比如 httpd 进程。你需要运行 docker container run 命令。旧的命令为 docker run, 但后来 Docker 添加了子命令部分,所以新版本支持下列命令:

root@kerneltalks # docker container run -d -p 80:80 httpd
Unable to find image 'httpd:latest' locally
latest: Pulling from library/httpd
3d77ce4481b1: Pull complete
73674f4d9403: Pull complete
d266646f40bd: Pull complete
ce7b0dda0c9f: Pull complete
01729050d692: Pull complete
014246127c67: Pull complete
7cd2e04cf570: Pull complete
Digest: sha256:f4610c3a1a7da35072870625733fd0384515f7e912c6223d4a48c6eb749a8617
Status: Downloaded newer image for httpd:latest
c46f2e9e4690f5c28ee7ad508559ceee0160ac3e2b1688a61561ce9f7d99d682

Docker 的 run 命令将镜像名作为强制参数,另外还有很多可选参数。常用的参数有:

  • -d:从当前 shell 脱离容器
  • -p X:Y:绑定容器的端口 Y 到宿主机的端口 X
  • --name:命名你的容器。如果未指定,它将被赋予随机生成的名字
  • -e:当启动容器时传递环境编辑及其值

通过以上输出你可以看到,我们将 httpd 作为镜像名来运行容器。接着,本地镜像没有找到,Docker 引擎从 Docker Hub 拉取了它。注意,它下载了镜像 httpd:latest, 其中 : 后面跟着版本号。如果你需要运行特定版本的容器,你可以在镜像名后面注明版本名。如果不提供版本名,Docker 引擎会自动拉取最新的版本。

输出的最后一行显示了你新运行的 httpd 容器的唯一 ID。

如何列出所有运行中的 Docker 容器?

现在,你的容器已经运行起来了,你可能想要确认这一点,或者你想要列出你的机器上运行的所有容器。你可以使用 docker container ls 命令。在旧的 Docker 版本中,对应的命令为 docker ps

root@kerneltalks # docker container ls
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                NAMES
c46f2e9e4690        httpd               "httpd-foreground"   11 minutes ago      Up 11 minutes       0.0.0.0:80->80/tcp   cranky_cori

列出的结果是按列显示的。每一列的值分别为:

  1. Container ID :一开始的几个字符对应你的容器的唯一 ID
  2. Image :你运行容器的镜像名
  3. Command :容器启动后运行的命令
  4. Created :创建时间
  5. Status :容器当前状态
  6. Ports :与宿主端口相连接的端口信息
  7. Names :容器名(如果你没有命名你的容器,那么会随机创建)

如何查看 Docker 容器的历史纪录?

在第一步我们使用了 -d 参数来将容器,在它一开始运行的时候,就从当前的 shell 中脱离出来。在这种情况下,我们不知道容器里面发生了什么。所以为了查看容器的历史纪录,Docker 提供了 logs 命令。它采用容器名称或 ID 作为参数。

root@kerneltalks # docker container logs cranky_cori
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
[Thu May 31 18:35:07.301158 2018] [mpm_event:notice] [pid 1:tid 139734285989760] AH00489: Apache/2.4.33 (Unix) configured -- resuming normal operations
[Thu May 31 18:35:07.305153 2018] [core:notice] [pid 1:tid 139734285989760] AH00094: Command line: 'httpd -D FOREGROUND'

这里我使用了容器名称作为参数。你可以看到在我们的 httpd 容器中与 Apache 相关的历史纪录。

如何确定 Docker 容器的进程?

容器是一个使用宿主资源来运行的进程。这样,你可以在宿主系统的进程表中定位容器的进程。让我们在宿主系统上确定容器进程。

Docker 使用著名的 top 命令作为子命令的名称,来查看容器产生的进程。它采用容器的名称或 ID 作为参数。在旧版本的 Docker 中,只可运行 docker top 命令。在新版本中,docker topdocker container top 命令都可以生效。

root@kerneltalks # docker container top  cranky_cori
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                15702               15690               0                   18:35               ?                   00:00:00            httpd -DFOREGROUND
bin                 15729               15702               0                   18:35               ?                   00:00:00            httpd -DFOREGROUND
bin                 15730               15702               0                   18:35               ?                   00:00:00            httpd -DFOREGROUND
bin                 15731               15702               0                   18:35               ?                   00:00:00            httpd -DFOREGROUND

root@kerneltalks # ps -ef |grep -i 15702
root     15702 15690  0 18:35 ?        00:00:00 httpd -DFOREGROUND
bin      15729 15702  0 18:35 ?        00:00:00 httpd -DFOREGROUND
bin      15730 15702  0 18:35 ?        00:00:00 httpd -DFOREGROUND
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

在第一个输出中,列出了容器产生的进程的列表。它包含了所有细节,包括 用户号 uid 进程号 pid 父进程号 ppid 、开始时间、命令,等等。这里所有的进程号你都可以在宿主的进程表里搜索到。这就是我们在第二个命令里做得。这证明了容器确实是宿主系统中的进程。

如何停止 Docker 容器?

只需要 stop 命令!同样,它采用容器名称或 ID 作为参数。

root@kerneltalks # docker container stop cranky_cori
cranky_cori

如何列出停止的或不活动的 Docker 容器?

现在我们停止了我们的容器,这时如果我们使用 ls 命令,它将不会出现在列表中。

root@kerneltalks # docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

所以,在这种情况下,如果想要查看停止的或不活动的容器,你需要在 ls 命令里同时使用 -a 参数。

root@kerneltalks # docker container ls -a
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS                     PORTS               NAMES
c46f2e9e4690        httpd               "httpd-foreground"   33 minutes ago      Exited (0) 2 minutes ago                       cranky_cori

有了 -a 参数,现在我们可以查看已停止的容器。注意这些容器的状态被标注为 已退出 exited 。既然容器只是一个进程,那么用“退出”比“停止”更合适!

如何(重新)启动 Docker 容器?

现在,我们来启动这个已停止的容器。这和运行一个容器有所区别。当你运行一个容器时,你将启动一个全新的容器。当你启动一个容器时,你将开始一个已经停止并保存了当时运行状态的容器。它将以停止时的状态重新开始运行。

root@kerneltalks #  docker container start c46f2e9e4690
c46f2e9e4690

root@kerneltalks # docker container ls -a
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                NAMES
c46f2e9e4690        httpd               "httpd-foreground"   35 minutes ago      Up 8 seconds        0.0.0.0:80->80/tcp   cranky_cori

如何移除 Docker 容器?

我们使用 rm 命令来移除容器。你不可以移除运行中的容器。移除之前需要先停止容器。你可以使用 -f 参数搭配 rm 命令来强制移除容器,但并不推荐这么做。

root@kerneltalks # docker container rm cranky_cori
cranky_cori
root@kerneltalks # docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

你看,一旦移除了容器,即使再使用 ls -a 命令也查看不到容器了。


via: https://kerneltalks.com/virtualization/8-basic-docker-container-management-commands/

作者:Shrikant Lavhate 选题:lujun9972 译者:lonaparte 校对:wxy

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

学习如何使用一个树莓派 Zero、高清网络摄像头和一个空的粉盒来搭建一个简单的相机。

在 2015 年底的时候,树莓派基金会发布了一个让大家很惊艳的非常小的 树莓派 Zero。更夸张的是,他们随 MagPi 杂志一起 免费赠送。我看到这个消息后立即冲出去到处找报刊亭,直到我在这一地区的某处找到最后两份。实际上我还没有想好如何去使用它们,但是我知道,因为它们非常小,所以,它们可以做很多全尺寸树莓派没法做的一些项目。

 title=

从 MagPi 杂志上获得的树莓派 Zero。CC BY-SA.4.0。

因为我对天文摄影非常感兴趣,我以前还改造过一台微软出的 LifeCam Cinema 高清网络摄像头,拆掉了它的外壳、镜头、以及红外滤镜,露出了它的 CCD 芯片。我把它定制为我的 Celestron 天文望远镜的目镜。用它我捕获到了令人难以置信的木星照片、月球上的陨石坑、以及太阳黑子的特写镜头(使用了适当的 Baader 安全保护膜)。

在那之前,我甚至还在我的使用胶片的 SLR 摄像机上,通过在镜头盖(这个盖子就是在摄像机上没有安装镜头时,用来保护摄像机的内部元件的那个盖子)上钻一个小孔来变成一个 针孔摄像机,将这个钻了小孔的盖子,盖到一个汽水罐上切下来的小圆盘上,以提供一个针孔。碰巧有一天,这个放在我的桌子上的针孔镜头盖被改成了用于天文摄像的网络摄像头。我很好奇这个网络摄像头是否有从针孔盖子后面捕获低照度图像的能力。我花了一些时间使用 GNOME Cheese 应用程序,去验证这个针孔摄像头确实是个可行的创意。

自从有了这个想法,我就有了树莓派 Zero 的一个用法!针孔摄像机一般都非常小,除了曝光时间和胶片的 ISO 速率外,一般都不提供其它的控制选项。数字摄像机就不一样了,它至少有 20 多个按钮和成百上千的设置菜单。我的数字针孔摄像头的目标是真实反映天文摄像的传统风格,设计一个没有控制选项的极简设备,甚至连曝光时间控制也没有。

用树莓派 Zero、高清网络镜头和空的粉盒设计的数字针孔摄像头,是我设计的 一系列 针孔摄像头的 第一个项目。现在,我们开始来制作它。

硬件

因为我手头已经有了一个树莓派 Zero,为完成这个项目我还需要一个网络摄像头。这个树莓派 Zero 在英国的零售价是 4 英磅,这个项目其它部件的价格,我希望也差不多是这样的价格水平。花费 30 英磅买来的摄像头安装在一个 4 英磅的计算机主板上,让我感觉有些不平衡。显而易见的答案是前往一个知名的拍卖网站上,去找到一些二手的网络摄像头。不久之后,我仅花费了 1 英磅再加一些运费,获得了一个普通的高清摄像头。之后,在 Fedora 上做了一些测试操作,以确保它是可用正常使用的,我拆掉了它的外壳,以检查它的电子元件的大小是否适合我的项目。

 title=

Hercules DualPix 高清网络摄像头,它将被解剖以提取它的电路板和 CCD 图像传感器。CC BY-SA 4.0.

接下来,我需要一个安放摄像头的外壳。树莓派 Zero 电路板大小仅仅为 65mm x 30mm x 5mm。虽然网络摄像头的 CCD 芯片周围有一个用来安装镜头的塑料支架,但是,实际上它的电路板尺寸更小。我在家里找了一圈,希望能够找到一个适合盛放这两个极小的电路板的容器。最后,我发现我妻子的粉盒足够去安放树莓派的电路板。稍微做一些小调整,似乎也可以将网络摄像头的电路板放进去。

 title=

变成我的针孔摄像头外壳的粉盒。CC BY-SA 4.0.

我拆掉了网络摄像头外壳上的一些螺丝,取出了它的内部元件。网络摄像头外壳的大小反映了它的电路板的大小或 CCD 的位置。我很幸运,这个网络摄像头很小而且它的电路板的布局也很方便。因为我要做一个针孔摄像头,我需要取掉镜头,露出 CCD 芯片。

它的塑料外壳大约有 1 厘米高,它太高了没有办法放进粉盒里。我拆掉了电路板后面的螺丝,将它完全拆开,我认为将它放在盒子里有助于阻挡从缝隙中来的光线,因此,我用一把工艺刀将它修改成 4 毫米高,然后将它重新安装。我折弯了 LED 的支脚以降低它的高度。最后,我切掉了安装麦克风的塑料管,因为我不想采集声音。

 title=

取下镜头以后,就可以看到裸露的 CCD 芯片了。圆柱形的塑料柱将镜头固定在合适的位置上,并阻挡 LED 光进入镜头破坏图像。CC BY-SA 4.0

网络摄像头有一个很长的带全尺寸插头的 USB 线缆,而树莓派 Zero 使用的是一个 Micro-USB 插座,因此,我需要一个 USB 转 Micro-USB 的适配器。但是,使用适配器插入,这个树莓派将放不进这个粉盒中,更不用说还有将近一米长的 USB 线缆。因此,我用刀将 Micro-USB 适配器削开,切掉了它的 USB 插座并去掉这些塑料,露出连接到 Micro-USB 插头上的金属材料。同时也把网络摄像头的 USB 电缆切到大约 6 厘米长,并剥掉裹在它外面的锡纸,露出它的四根电线。我把它们直接焊接到 Micro-USB 插头上。现在网络摄像头可以插入到树莓派 Zero 上了,并且电线也可以放到粉盒中了。

 title=

网络摄像头使用的 Micro-USB 插头已经剥掉了线,并直接焊接到触点上。这个插头现在插入到树莓派 Zero 后大约仅高出树莓派 1 厘米。CC BY-SA 4.0

最初,我认为到此为止,已经全部完成了电子设计部分,但是在测试之后,我意识到,如果摄像头没有捕获图像或者甚至没有加电我都不知道。我决定使用树莓派的 GPIO 针脚去驱动 LED 指示灯。一个黄色的 LED 表示网络摄像头控制软件已经运行,而一个绿色的 LED 表示网络摄像头正在捕获图像。我在 BCM 的 17 号和 18 号针脚上各自串接一个 300 欧姆的电阻,并将它们各自连接到 LED 的正极上,然后将 LED 的负极连接到一起并接入到公共地针脚上。

 title=

LED 使用一个 300 欧姆的电阻连接到 GPIO 的 BCM 17 号和 BCM 18 号针脚上,负极连接到公共地针脚。CC BY-SA 4.0.

接下来,该去修改粉盒了。首先,我去掉了卡在粉盒上的托盘以腾出更多的空间,并且用刀将连接处切开。我打算在一个便携式充电宝上运行树莓派 Zero,充电宝肯定是放不到这个盒子里面,因此,我挖了一个孔,这样就可以引出 USB 连接头。LED 的光需要能够从盒子外面看得见,因此,我在盖子上钻了两个 3 毫米的小孔。

然后,我使用一个 6 毫米的钻头在盖子的底部中间处钻了一个孔,并找了一个薄片盖在它上面,然后用针在它的中央扎了一个小孔。一定要确保针尖很细,因为如果插入整个针会使孔太大。我使用干/湿砂纸去打磨这个针孔,以让它更光滑,然后从另一面再次打孔,再强调一次仅使用针尖。使用针孔摄像头的目的是为了得到一个规则的、没有畸形或凸起的圆孔,并且勉强让光通过。孔越小,图像越锐利。

 title=

带针孔的盒子底部。CC BY-SA 4.0

剩下的工作就是将这些已经改造完成的设备封装起来。首先我使用蓝色腻子将摄像头的电路板固定在盒子中合适的位置,这样针孔就直接处于 CCD 之上了。使用蓝色腻子的好处是,如果我需要清理污渍(或者如果放错了位置)时,就可以很容易地重新安装 CCD 了。将树莓派 Zero 直接放在摄像头电路板上面。为防止这两个电路板之间可能出现的短路情况,我在树莓派的背面贴了几层防静电胶带。

树莓派 Zero 非常适合放到这个粉盒中,并且不需要任何固定,而从小孔中穿出去连接充电宝的 USB 电缆需要将它粘住固定。最后,我将 LED 塞进了前面在盒子上钻的孔中,并用胶水将它们固定住。我在 LED 的针脚之中放了一些防静电胶带,以防止盒子盖上时,它与树莓派电路板接触而发生短路。

 title=

树莓派 Zero 塞入到这个盒子中后,周围的空隙不到 1mm。从盒子中引出的连接到网络摄像头上的 Micro-USB 插头,接下来需要将它连接到充电宝上。CC BY-SA 4.0

软件

当然,计算机硬件离开控制它的软件是不能使用的。树莓派 Zero 同样可以运行全尺寸树莓派能够运行的软件,但是,因为树莓派 Zero 的 CPU 速度比较慢,让它去引导传统的 Raspbian OS 镜像非常耗时。打开摄像头都要花费差不多一分钟的时间,这样的速度在现实中是没有什么用处的。而且,一个完整的树莓派操作系统对我的这个摄像头项目来说也没有必要。甚至是,我禁用了引导时启动的所有可禁用的服务,启动仍然需要很长的时间。因此,我决定仅使用需要的软件,我将用一个 U-Boot 引导加载器和 Linux 内核。自定义 init 二进制文件从 microSD 卡上加载 root 文件系统、读入驱动网络摄像头所需要的内核模块,并将它放在 /dev 目录下,然后运行二进制的应用程序。

这个二进制的应用程序是另一个定制的 C 程序,它做的核心工作就是管理摄像头。首先,它等待内核驱动程序去初始化网络摄像头、打开它、以及通过低级的 v4l ioctl 调用去初始化它。GPIO 针配置用来通过 /dev/mem 寄存器去驱动 LED。

初始化完成之后,摄像头进入一个循环。每个图像捕获循环是摄像头使用缺省配置,以 JPEG 格式捕获一个单一的图像帧、保存这个图像帧到 SD 卡、然后休眠三秒。这个循环持续运行直到断电为止。这已经很完美地实现了我的最初目标,那就是用一个传统的模拟的针孔摄像头设计一个简单的数字摄像头。

定制的用户空间 代码 在遵守 GPLv3 或者更新版许可下自由使用。树莓派 Zero 需要 ARMv6 的二进制文件,因此,我使用了 QEMU ARM 模拟器在一台 x86\_64 主机上进行编译,它使用了 Pignus 发行版(一个针对 ARMv6 移植/重构建的 Fedora 23 版本)下的工具链,在 chroot 环境下进行编译。所有的二进制文件都静态链接了 glibc,因此,它们都是自包含的。我构建了一个定制的 RAMDisk 去包含这些二进制文件和所需的内核模块,并将它拷贝到 SD 卡,这样引导加载器就可以找到它们了。

 title=

最终完成的摄像机完全隐藏在这个粉盒中了。唯一露在外面的东西就是 USB 电缆。CC BY-SA 4.0

照像

软件和硬件已经完成了,是该去验证一下它能做什么了。每个人都熟悉用现代的数字摄像头拍摄的高质量图像,不论它是用专业的 DSLRs 还是移动电话拍的。但是,这个高清的 1280x1024 分辨率的网络摄像头(差不多是一百万像素),在这里可能会让你失望。这个 CCD 从一个光通量极小的针孔中努力捕获图像。网络摄像头自动提升增益和曝光时间来进行补偿,最后的结果是一幅噪点很高的图像。图像的动态范围也非常窄,从一个非常拥挤的柱状图就可以看出来,这可以通过后期处理来拉长它,以得到更真实的亮部和暗部。

在户外阳光充足时捕获的图像达到了最佳效果,因此在室内获得的图像大多数都是不可用的图像。它的 CCD 直径仅有大约 1cm,并且是从一个几毫米的针孔中来捕获图像的,它的视界相当窄。比如,在自拍时,手臂拿着相机尽可能伸长,所获得的图像也就是充满整个画面的人头。最后,图像都是失焦的,所有的针孔摄像机都是这样的。

 title=

在伦敦,大街上的屋顶。CC BY-SA 4.0

 title=

范堡罗机场的老航站楼。CC BY-SA 4.0

最初,我只是想使用摄像头去捕获一些静态图像。后面,我降低了循环的延迟时间,从三秒改为一秒,然后用它捕获一段时间内的一系列图像。我使用 GStreamer 将这些图像做成了延时视频。

以下是我创建视频的过程:

视频是我在某天下班之后,从银行沿着泰晤式河到滑铁卢的画面。以每分钟 40 帧捕获的 1200 帧图像被我制作成了每秒 20 帧的动画。


via: https://opensource.com/article/18/3/how-build-digital-pinhole-camera-raspberry-pi

作者:Daniel Berrange 选题:lujun9972 译者:qhwdw 校对:wxy

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

今天,我们将看到如何禁用未使用的内置网络摄像头或外置摄像头,以及如何在 Linux 中需要时启用它。禁用网络摄像头可以在很多方面为你提供帮助。你可以防止恶意软件控制你的集成摄像头,并监视你和你的家庭。我们已经阅读过无数的故事,一些黑客可以在你不知情的情况下使用你的摄像头监视你。通过黑客攻击你的网络摄像头,用户可以在线共享你的私人照片和视频。可能有很多原因。如果你想知道如何禁用笔记本电脑或台式机中的网络摄像头,那么你很幸运。这个简短的教程将告诉你如何做。请继续阅读。

我在 Arch Linux 和 Ubuntu 上测试了这个指南。它的工作原理如下所述。我希望这也可以用在其他 Linux 发行版上。

在 Linux 中禁用内置摄像头

首先,使用如下命令找到网络摄像头驱动:

$ sudo lsmod | grep uvcvideo

示例输出:

uvcvideo 114688 1
videobuf2_vmalloc 16384 1 uvcvideo
videobuf2_v4l2 28672 1 uvcvideo
videobuf2_common 53248 2 uvcvideo,videobuf2_v4l2
videodev 208896 4 uvcvideo,videobuf2_common,videobuf2_v4l2
media 45056 2 uvcvideo,videodev
usbcore 286720 9 uvcvideo,usbhid,usb_storage,ehci_hcd,ath3k,btusb,uas,ums_realtek,ehci_pci

这里,uvcvideo 是我的网络摄像头驱动。

现在,让我们禁用网络摄像头。

为此,请编辑以下文件(如果文件不存在,只需创建它):

$ sudo nano /etc/modprobe.d/blacklist.conf

添加以下行:

##Disable webcam.
blacklist uvcvideo

##Disable webcam 这行不是必需的。为了便于理解,我添加了它。

保存并退出文件。重启系统以使更改生效。

要验证网络摄像头是否真的被禁用,请打开任何即时通讯程序或网络摄像头软件,如 Cheese 或 Guvcview。你会看到如下的空白屏幕。

Cheese 输出:

Guvcview 输出:

看见了么?网络摄像头被禁用而无法使用。

要启用它,请编辑:

$ sudo nano /etc/modprobe.d/blacklist.conf

注释掉你之前添加的行。

##Disable webcam.
#blacklist uvcvideo

保存并关闭文件。然后,重启计算机以启用网络摄像头。

这样够了吗?不。为什么?如果有人可以远程访问你的系统,他们可以轻松启用网络摄像头。所以,在不使用时用胶带覆盖它或者拔掉相机或者在 BIOS 中禁用它是一个不错的主意。此方法不仅用于禁用内置摄像头,还用于外部网络摄像头。

就是这些了。希望对你有用。还有更好的东西。敬请关注!

干杯!


via: https://www.ostechnix.com/how-to-disable-built-in-webcam-in-ubuntu/

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

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