mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-01-28 23:20:10 +08:00
Merge remote-tracking branch 'LCTT/master'
This commit is contained in:
commit
11450b8b15
@ -1,36 +1,35 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (HankChow)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12766-1.html)
|
||||
[#]: subject: (Automate your container orchestration with Ansible modules for Kubernetes)
|
||||
[#]: via: (https://opensource.com/article/20/9/ansible-modules-kubernetes)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
|
||||
使用 Ansible Kubernetes 模块实现容器编排自动化
|
||||
使用 Ansible 的 Kubernetes 模块实现容器编排自动化
|
||||
======
|
||||
> 在云上的 Kubernetes 中结合 Ansible 实现自动化的同时,还可以参照我们的速记表熟悉 Ansible 的 k8s 模块。
|
||||
|
||||
![Ship captain sailing the Kubernetes seas][1]
|
||||
> 将 Kubernetes 与 Ansible 结合实现云端自动化。此外,还可以参照我们的 Ansible 的 k8s 模块速查表。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202010/28/211747jhlttlf3f81xrffi.jpg)
|
||||
|
||||
[Ansible][2] 是实现自动化工作的优秀工具,而 [Kubernetes][3] 则是容器编排方面的利器,要是把两者结合起来,会有怎样的效果呢?正如你所猜测的,Ansible + Kubernetes 的确可以实现容器编排自动化。
|
||||
|
||||
### Ansible 模块
|
||||
|
||||
实际上,Ansible 本身只是一个用于解释 YAML 文件的框架。它真正强大之处在于它[丰富的模块][4],所谓<ruby>模块<rt>module</rt></ruby>,就是在 Ansible playbook 中让你得以通过简单配置就能调用外部应用程序的一些工具。
|
||||
实际上,Ansible 本身只是一个用于解释 YAML 文件的框架。它真正强大之处在于它[丰富的模块][4],所谓<ruby>模块<rt>module</rt></ruby>,就是在 Ansible <ruby>剧本<rt>playbook</rt></ruby> 中让你得以通过简单配置就能调用外部应用程序的一些工具。
|
||||
|
||||
Ansible 中有模块可以直接操作 Kubernetes,也有对一些相关组件(例如 [Docker][5] 和 [Podman][6])实现操作的模块。学习使用一个新模块的过程和学习新的终端命令、API 一样,可以先从文档中了解这个模块在调用的时候需要接受哪些参数,以及这些参数在外部应用程序中产生的具体作用。
|
||||
|
||||
### 访问 Kubernetes 集群
|
||||
|
||||
在使用 Ansible Kubernetes 模块之前,先要有能够访问 Kubernetes 集群的权限。在没有权限的情况下,可以尝试使用一个短期账号,但我们更推荐的是按照 Kubernetes 官网上的指引,或是参考 Braynt Son 《[入门 Kubernetes][8]》的教程安装 [Minikube][7]。Minikube 提供了一个单节点 Kubernetes 实例的安装过程,你可以像使用一个完整集群一样对其进行配置和交互。
|
||||
在使用 Ansible Kubernetes 模块之前,先要有能够访问 Kubernetes 集群的权限。在没有权限的情况下,可以尝试使用一个短期在线试用账号,但我们更推荐的是按照 Kubernetes 官网上的指引,或是参考 Braynt Son 《[入门 Kubernetes][8]》的教程安装 [Minikube][7]。Minikube 提供了一个单节点 Kubernetes 实例的安装过程,你可以像使用一个完整集群一样对其进行配置和交互。
|
||||
|
||||
**[下载 [Ansible k8s 速记表][9]]**
|
||||
- 下载 [Ansible k8s 速记表][9](需注册)
|
||||
|
||||
在安装 Minikube 之前,你需要确保你的环境支持虚拟化并安装 `libvirt`,然后对 `libvirt` 用户组授权:
|
||||
|
||||
|
||||
```
|
||||
$ sudo dnf install libvirt
|
||||
$ sudo systemctl start libvirtd
|
||||
@ -42,7 +41,6 @@ $ newgrp libvirt
|
||||
|
||||
为了能够在 Ansible 中使用 Kubernetes 相关的模块,你需要安装以下这些 Python 模块:
|
||||
|
||||
|
||||
```
|
||||
$ pip3.6 install kubernetes --user
|
||||
$ pip3.6 install openshift --user
|
||||
@ -52,9 +50,8 @@ $ pip3.6 install openshift --user
|
||||
|
||||
如果你使用的是 Minikube 而不是完整的 Kubernetes 集群,请使用 `minikube` 命令在本地创建一个最精简化的 Kubernetes 实例:
|
||||
|
||||
|
||||
```
|
||||
`$ minikube start --driver=kvm2 --kvm-network default`
|
||||
$ minikube start --driver=kvm2 --kvm-network default
|
||||
```
|
||||
|
||||
然后等待 Minikube 完成初始化,这个过程所需的时间会因实际情况而异。
|
||||
@ -63,29 +60,26 @@ $ pip3.6 install openshift --user
|
||||
|
||||
集群启动以后,通过 `cluster-info` 选项就可以获取到集群相关信息了:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl cluster-info
|
||||
Kubernetes master is running at <https://192.168.39.190:8443>
|
||||
KubeDNS is running at <https://192.168.39.190:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy>
|
||||
Kubernetes master is running at https://192.168.39.190:8443
|
||||
KubeDNS is running at https://192.168.39.190:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
|
||||
|
||||
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
|
||||
```
|
||||
|
||||
### 使用 `k8s` 模块
|
||||
|
||||
Ansible 使用 `k8s` 这个模块来实现对 Kubernetes 的操作,在 playbook 中使用 `k8s` 模块就可以对 Kuvernetes 对象进行管理。这个模块描述了 `kubectl` 命令的最终状态,例如对于以下这个使用 `kubectl` 创建新的[命名空间][10]的操作:
|
||||
### 使用 k8s 模块
|
||||
|
||||
Ansible 使用 `k8s` 这个模块来实现对 Kubernetes 的操作,在剧本中使用 `k8s` 模块就可以对 Kuvernetes 对象进行管理。这个模块描述了 `kubectl` 命令的最终状态,例如对于以下这个使用 `kubectl` 创建新的[命名空间][10]的操作:
|
||||
|
||||
```
|
||||
`$ kubectl create namespace my-namespace`
|
||||
$ kubectl create namespace my-namespace
|
||||
```
|
||||
|
||||
这是一个很简单的操作,而对这个操作的最终状态用 YAML 文件来描述是这样的:
|
||||
|
||||
|
||||
```
|
||||
\- hosts: localhost
|
||||
- hosts: localhost
|
||||
tasks:
|
||||
- name: create namespace
|
||||
k8s:
|
||||
@ -95,25 +89,22 @@ Ansible 使用 `k8s` 这个模块来实现对 Kubernetes 的操作,在 playboo
|
||||
state: present
|
||||
```
|
||||
|
||||
如果你使用的是 Minikube,那么主机名应该定义为 `localhost`。需要注意的是,模块中对其它可用参数也定义了对应的语法(例如 `api_version` 和 `kind` 参数)。
|
||||
|
||||
在运行这个 playbook 之前,先通过 `yamllint` 命令验证是否有错误:
|
||||
如果你使用的是 Minikube,那么主机名(`hosts`)应该定义为 `localhost`。需要注意的是,所使用的模块也定义了可用参数的语法(例如 `api_version` 和 `kind` 参数)。
|
||||
|
||||
在运行这个剧本之前,先通过 `yamllint` 命令验证是否有错误:
|
||||
|
||||
```
|
||||
`$ yamllint example.yaml`
|
||||
$ yamllint example.yaml
|
||||
```
|
||||
|
||||
确保没有错误之后,运行 playbook:
|
||||
|
||||
确保没有错误之后,运行剧本:
|
||||
|
||||
```
|
||||
`$ ansible-playbook ./example.yaml`
|
||||
$ ansible-playbook ./example.yaml
|
||||
```
|
||||
|
||||
可以验证新的命名空间是否已经被创建出来:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl get namespaces
|
||||
NAME STATUS AGE
|
||||
@ -127,10 +118,9 @@ my-namespace Active 3s
|
||||
|
||||
### 使用 Podman 拉取容器镜像
|
||||
|
||||
容器是受 Kubernetes 管理的最小单位 Linux 系统,因此 [LXC 项目][11]和 Docker 对容器定义了很多规范。Podman 是一个最新的容器操作工具集,它不需要守护进程就可以运行,为此受到了很多用户的欢迎。
|
||||
|
||||
通过 Podman 可以从 Docker Hub 或者 Quay.io 拉取到容器镜像。这一操作对应的 Ansible 语法也很简单,只需要将存储库网站提供的镜像路径写在 playbook 中的相应位置就可以了:
|
||||
容器是个 Linux 系统,几乎是最小化的,可以由 Kubernetes 管理。[LXC 项目][11]和 Docker 定义了大部分的容器规范。最近加入容器工具集的是 Podman,它不需要守护进程就可以运行,为此受到了很多用户的欢迎。
|
||||
|
||||
通过 Podman 可以从 Docker Hub 或者 Quay.io 等存储库拉取容器镜像。这一操作对应的 Ansible 语法也很简单,只需要将存储库网站提供的镜像路径写在剧本中的相应位置就可以了:
|
||||
|
||||
```
|
||||
- name: pull an image
|
||||
@ -140,13 +130,11 @@ my-namespace Active 3s
|
||||
|
||||
使用 `yamllint` 验证:
|
||||
|
||||
|
||||
```
|
||||
`$ yamllint example.yaml`
|
||||
$ yamllint example.yaml
|
||||
```
|
||||
|
||||
运行 playbook:
|
||||
|
||||
运行剧本:
|
||||
|
||||
```
|
||||
$ ansible-playbook ./example.yaml
|
||||
@ -171,8 +159,7 @@ localhost: ok=3 changed=1 unreachable=0 failed=0
|
||||
|
||||
### 使用 Ansible 实现部署
|
||||
|
||||
Ansible 除了可以执行小型维护任务以外,还可以通过 playbook 实现其它由 `kubectl` 实现的功能,因为两者的 YAML 文件之间只有少量的差异。 在 Kubernetes 中使用的 YAML 文件只需要稍加改动,就可以在 Ansible playbook 中使用。例如下面这个用于使用 `kubectl` 命令部署 Web 服务器的 YAML 文件:
|
||||
|
||||
Ansible 除了可以执行小型维护任务以外,还可以通过剧本实现其它由 `kubectl` 实现的功能,因为两者的 YAML 文件之间只有少量的差异。在 Kubernetes 中使用的 YAML 文件只需要稍加改动,就可以在 Ansible 剧本中使用。例如下面这个用于使用 `kubectl` 命令部署 Web 服务器的 YAML 文件:
|
||||
|
||||
```
|
||||
apiVersion: apps/v1
|
||||
@ -196,8 +183,7 @@ spec:
|
||||
- containerPort: 80
|
||||
```
|
||||
|
||||
如果你对其中的参数比较熟悉,你只要把 YAML 文件中的大部分内容放到 playbook 中的 `definition` 部分,就可以在 Ansible 中使用了:
|
||||
|
||||
如果你对其中的参数比较熟悉,你只要把 YAML 文件中的大部分内容放到剧本中的 `definition` 部分,就可以在 Ansible 中使用了:
|
||||
|
||||
```
|
||||
- name: deploy a web server
|
||||
@ -230,7 +216,6 @@ spec:
|
||||
|
||||
执行完成后,使用 `kubectl` 命令可以看到预期中的的<ruby>部署<rt>deployment</rt></ruby>:
|
||||
|
||||
|
||||
```
|
||||
$ kubectl -n my-namespace get pods
|
||||
NAME READY STATUS
|
||||
@ -248,7 +233,7 @@ via: https://opensource.com/article/20/9/ansible-modules-kubernetes
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[HankChow](https://github.com/HankChow)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,139 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (A few things I've learned about email marketing)
|
||||
[#]: via: (https://jvns.ca/blog/2020/10/28/a-few-things-i-ve-learned-about-email-marketing/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
A few things I've learned about email marketing
|
||||
======
|
||||
|
||||
Hello! I’ve been learning a lot about business over the last few years (it’s possible to make a living by helping people learn! it’s amazing!). One of the things I’ve found hardest to get my head around was email marketing.
|
||||
|
||||
Like a lot of people, I get a lot of unwanted email, and at first I was really opposed to doing any kind of email marketing because I was worried I’d be the _source_ of that unwanted email. But I’ve learned how to do it in a way that feels good to me, and where the replies to my marketing emails are usually along the lines of “wow, I love this, thank you so much!”. ([literally: here are excerpts from the last 20 or so replies I’ve gotten][1])
|
||||
|
||||
I’m going to structure this as a series of beliefs I had about email marketing that turned out not to be universally true.
|
||||
|
||||
### myth 1: selling things is an adversarial relationship
|
||||
|
||||
I used to think that selling things was a sort of adversarial relationship: the person selling the product wants to convince the buyer (by any means necessary) to spend as much money as possible, and that people buying things are usually kind of resentful of anyone asking them to spend money.
|
||||
|
||||
I’ve learned that actually a lot of people are happy (or even actively **want**) to spend money on something that will help them solve a problem they have.
|
||||
|
||||
Here’s a silly example of something illustrating this: 2 years ago, we’d hired someone to paint our new apartment. We decided to paint a lot of the walls white, and we were stuck with the impossible problem of deciding which of the 10 billion possible shades of white to paint the walls. I found a $27 ebook called [white is complicated][2], and (long story short, this blog post is not about painting) it really helped me confidently choose a shade of white!! We spent thousands of dollars on painting, so $30 was a really good investment in making sure we’d be happy with the result.
|
||||
|
||||
So even though $27 for an ebook on how to choose a white seems silly at first, I was really happy to spend the money, and my guess is a lot of other people who bought that ebook are as well.
|
||||
|
||||
The bigger idea here is that it’s easier to run a business when you’re selling to people who are happy to buy things based on the value they’re getting from the product. In my case, I’ve found that there are lots of programmers who are happy to pay for clear, short, friendly explanations of concepts they need to understand for their jobs.
|
||||
|
||||
### a quick note on how I learned these things: 30x500
|
||||
|
||||
I originally wrote this blog post about all these things I learned, and it kind of read like I figured out all of these things naturally over the course of running a business. But that’s not how it went at all! I’ve actually found it very hard to debug business problems on my own. A lot of the attitudes I had when I started out running a business were counterproductive (like thinking of selling something as an adversarial process), and I don’t know that many people who run similar businesses who I can get advice from.
|
||||
|
||||
I learned how to think about selling things as a non-adversarial process (and everything else in this blog post, and a lot more) from [30x500][3], a business class by Amy Hoy ([her writing is here][4]) and [Alex Hillman][5] that I bought a couple of years ago. 30x500 is about running a specific kind of business (very briefly: sell to people who buy based on value, decide what to build by researching your audience, market by teaching people helpful things), which happens to be the exact kind of business that I run. It’s been a really great way to learn how to run my business better.
|
||||
|
||||
Okay, back to my misconceptions about email marketing!
|
||||
|
||||
### myth 2: sending email is inherently bad
|
||||
|
||||
The next thing I believed was that sending email from a business was somehow inherently bad and that all marketing email was unwanted.
|
||||
|
||||
I now realize this is untrue even for normal marketing emails – for example, lots of people subscribe to marketing newsletters for brands they like because they want to hear about new products when they come out & sales.
|
||||
|
||||
But marketing emails aren’t just “not inherently bad”, they can actually be really useful!
|
||||
|
||||
### marketing is about building trust
|
||||
|
||||
When I started sending out business emails, I based them on the emails I was used to receiving – I’d announce new zines I’d written, and explain why the zine was useful.
|
||||
|
||||
But what I’ve learned is that (at least for me) marketing isn’t about describing your product to the audience, **marketing is about building trust by helping people**.
|
||||
|
||||
So, instead of just periodically emailing out “hey, here’s a new zine, here’s why it’s good”, my main marketing email list is called [saturday comics][6], and it sends you 1 email a week with a programming comic.
|
||||
|
||||
What I like about this approach to marketing (“just help people learn things for free”) is that it’s literally just what I love doing anyway – I wrote this blog to help people learn things for free for years just because I think it’s fun to help people learn.
|
||||
|
||||
And people love the Saturday Comics! And it makes money – I announce new zines to that list as well, and lots of people buy them. It’s really simple and nice!
|
||||
|
||||
### myth 3: you have to trick people into signing up for your email marketing list
|
||||
|
||||
One pattern I see a lot is that I sign up for some free service, and then I start getting deluged with marketing emails trying to convince me to upgrade to the paid tier or whatever. I used to think that this was how marketing emails **had** to work – you somehow get people’s email and then send them email, and hope that for some reason (???) they decide to buy things from you.
|
||||
|
||||
But, of course, this isn’t true! If your marketing list is actually just full of genuinely helpful emails, and you can describe who it’s intended for clearly (give people a link to the archive to see if they like what they see!), then a lot of people will be happy to sign up and receive the emails!
|
||||
|
||||
If you clearly communicate who your mailing list will help, then people can easily filter themselves in, and the only people on the list will be happy to be on the list. And then you don’t have to send any unwanted email at all! Hooray!
|
||||
|
||||
Here’s one story that influenced how I think about this: once I sent an email to everyone who had bought a past zine saying “hey, I just released this other zine, maybe you want to buy it!”. And I got an angry reply from someone saying something like “why are you emailing me, I just bought that one thing from you, I don’t want you to keep emailing me about other things”. I decided that I agreed with that, and now I’m more careful about being clear about what kinds of emails people are opting into.
|
||||
|
||||
### marketing is about communicating clearly & honestly
|
||||
|
||||
One insight (from Alex Hillman) that helped me a lot recently was – when someone is dissatisfied with something they bought, it doesn’t always mean that the product is “bad”. Maybe the product is helpful to many other people!
|
||||
|
||||
But it definitely means that the person’s expectations weren’t met. A tiny example: one of the few refund requests I’ve gotten for a zine was from someone from who expected there to be more information about sed in the zine, and they were disappointed there was only 1 page about sed.
|
||||
|
||||
So if I communicate clearly & accurately what problems a product solves, who it’s for, and how it solves those problems, people are much more likely to be delighted when they buy it and be happy to buy from me again in the future!. For my zines specifically, I like to make the table of contents very easy to find so that people can see that there’s [1 page about sed][7] :)
|
||||
|
||||
### myth 4: you have to constantly produce new emails
|
||||
|
||||
I’ve tried and failed to start a lot of mailing lists. the pattern I kept getting stuck in was:
|
||||
|
||||
I have an idea for a weekly mailing list I send 2 emails I give up forever
|
||||
|
||||
This was partly because I thought that to have a weekly/biweekly mailing list, you have to write new emails every week. And some people definitely do mailing lists this way, like [Austin Kleon][8].
|
||||
|
||||
But I learned that there’s a different way to write a mailing list! Instead, you:
|
||||
|
||||
put together a list of your best articles / comics / whatever when someone subscribes to that list, send them 1 email a week (or every 2 weeks, or whatever) with one article from the List Of Your Best Articles
|
||||
|
||||
The point is most people in the world probably haven’t already read your best articles, and so if you just send them one article a week from that list, it’ll probably actually be MORE helpful to them than if you were writing a new article every week. And you don’t need to write any emails every week!
|
||||
|
||||
I think this is called a “drip marketing campaign”, but when I search for that term I don’t find the results super helpful – there’s a lot out there about tools to do this, but as with anything I think the actual content of the emails is the most important thing.
|
||||
|
||||
### myth 5: unsubscribes are the end of the world
|
||||
|
||||
Another email marketing thing I used to get stressed out about was unsubscribes. It always feels a little sad to send an email about something I’m excited about and see 20 people unsubscribe immediately, even if it’s only 0.3% of people on the mailing list.
|
||||
|
||||
But I know that I subscribe to mailing lists very liberally, even on topics that I’m not that interested in, and 70% of the time I decide that I’m not that interested in the topic and unsubscribe eventually. A small percentage of people unsubscribing really just isn’t that big of a deal.
|
||||
|
||||
### myth 6: you need to optimize your open rates
|
||||
|
||||
There are all kinds of analytics you can do with email marketing, like open rates. I love numbers and analyzing things, but so far I really haven’t found trying to A/B test or optimize my numbers to be that productive or healthy. I’d rather spend my energy on just writing more helpful things for people to read.
|
||||
|
||||
The most important thing I’ve learned about website analytics is that it’s unproductive to look at random statistics like “the open rate on this email is 43% but the last one was 47%” and wonder what they mean. What _has_ been helpful has been coming up with a few specific questions that are important to me (“are people visiting this page from links on other sites, or only from my links?”) and keeping very rough track of the answers over time.
|
||||
|
||||
So far I’ve really never used any of the tracking features of my email marketing software. The only thing I’ve done that I’ve found helpful is: sometimes when I release a new zine I’ll send out a discount code to people on the list, and I can tell if people bought the thing from the mailing list because they used the discount code.
|
||||
|
||||
### it’s important to remember there are people on the other side
|
||||
|
||||
The last thing that’s helped me is to remember that even though emailing thousands of people sometimes feels like a weird anonymous thing, there are a lot of very delightful people on the other side! So when I write emails, I usually try to imagine that I’m writing to some very nice person I met at a conference one time who told me that they like my blog. We’re not best friends, but they know my work to some extent, and they’re interested to hear what I have to say.
|
||||
|
||||
I often like to remind people why they’re getting the email, especially if I haven’t emailed that list for a long time – “you signed up to get announcements when I release a new zine, so here’s an announcement!”. I think the technical email marketing term for this is a list being “cold” and “warm”, like if you don’t email a list for too long it’s “cold” and your subscribers might have forgotten that they’re on it.
|
||||
|
||||
### that’s all!
|
||||
|
||||
When I started, I was really convinced that email marketing was this terrible, awful thing that I could not do that mostly involved tricking people into getting emails they don’t want (ok, I’m exaggerating a bit, but I really struggled with it). But it’s possible to do it in a transparent way where I’m mostly just sending people helpful emails that they do want!
|
||||
|
||||
The big surprise for me was that email marketing is not a monolithic thing. I have a lot of choices about how to do it, and if I don’t like the way someone else does email marketing, I can just make different choices when doing it myself!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2020/10/28/a-few-things-i-ve-learned-about-email-marketing/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://gist.github.com/jvns/c2aaecbbbf60b7f3adf3e0be18d54a7b
|
||||
[2]: https://mariakillam.com/product/white-is-complicated/
|
||||
[3]: https://30x500.com/academy/
|
||||
[4]: https://stackingthebricks.com/
|
||||
[5]: https://dangerouslyawesome.com
|
||||
[6]: https://wizardzines.com/saturday-comics
|
||||
[7]: https://wizardzines.com/zines/bite-size-command-line/
|
||||
[8]: https://austinkleon.com/
|
@ -1,210 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to Install Ubuntu Server on a Raspberry Pi)
|
||||
[#]: via: (https://itsfoss.com/install-ubuntu-server-raspberry-pi/)
|
||||
[#]: author: (Dimitrios Savvopoulos https://itsfoss.com/author/dimitrios/)
|
||||
|
||||
How to Install Ubuntu Server on a Raspberry Pi
|
||||
======
|
||||
|
||||
The [Raspberry Pi][1] is the best-known [single-board computer][2]. Initially, the scope of the Raspberry Pi project was targeted to the promotion of teaching of basic computer science in schools and in developing countries.
|
||||
|
||||
Its low cost, portability and very low power consumption, made the models far more popular than anticipated. From weather station to home automation, tinkerers built so many [cool projects using Raspberry Pi][3].
|
||||
|
||||
The [4th generation of the Raspberry Pi][4], is equipped with features and processing power of a regular desktop computer. But this article is not about using RPi as desktop. Instead, I’ll show you how to install Ubuntu server on Raspberry Pi.
|
||||
|
||||
In this tutorial I will use a Raspberry Pi 4 and I will cover the following:
|
||||
|
||||
* Installing Ubuntu Server on a microSD card
|
||||
* Setting up a wireless network connection on the Raspberry Pi
|
||||
* Accessing your Raspberry Pi via SSH
|
||||
|
||||
|
||||
|
||||
![][5]
|
||||
|
||||
**You’ll need the following things for this tutorial**:
|
||||
|
||||
* A micro SD card (8 GB or greater recommended)
|
||||
* A computer (running Linux, Windows or macOS) with a micro SD card reader
|
||||
* A Raspberry Pi 2, 3 or 4
|
||||
* Good internet connection
|
||||
* An HDMI cable for the Pi 2 & 3 and a micro HDMI cable for the Pi 4 (optional)
|
||||
* A USB keyboard set (optional)
|
||||
|
||||
|
||||
|
||||
### Installing Ubuntu Server on a Raspberry Pi
|
||||
|
||||
![][6]
|
||||
|
||||
I have used Ubuntu for creating Raspberry Pi SD card in this tutorial but you may follow it on other Linux distributions, macOS and Windows as well. This is because the steps for preparing the SD card is the same with Raspberry Pi Imager tool.
|
||||
|
||||
The Raspberry Pi Imager tool downloads the image of your [choice of Raspberry Pi OS][7] automatically. This means that you need a good internet connection for downloading data around 1 GB.
|
||||
|
||||
#### Step 1: Prepare the SD Card with Raspberry Pi Imager
|
||||
|
||||
Make sure you have inserted the microSD card into your computer, and install the Raspberry Pi Imager at your computer.
|
||||
|
||||
You can download the Imager tool for your operating system from these links:
|
||||
|
||||
* [Raspberry Pi Imager for Ubuntu/Debian][8]
|
||||
* [Raspberry Pi Imager for Windows][9]
|
||||
* [Raspberry Pi Imager for MacOS][10]
|
||||
|
||||
|
||||
|
||||
Despite I use Ubuntu, I won’t use the Debian package that is listed above, but I will install the snap package using the command line. This method can be applied to wider range of Linux distributions.
|
||||
|
||||
```
|
||||
sudo snap install rpi-imager
|
||||
```
|
||||
|
||||
Once you have installed Raspberry Pi Imager tool, find and open it and click on the “CHOOSE OS” menu.
|
||||
|
||||
![][11]
|
||||
|
||||
Scroll across the menu and click on “Ubuntu” (Core and Server Images).
|
||||
|
||||
![][12]
|
||||
|
||||
From the available images, I choose the Ubuntu 20.04 LTS 64 bit. If you have a Raspberry Pi 2, you are limited to the 32bit image.
|
||||
|
||||
**Important Note: If you use the latest Raspberry Pi 4 – 8 GB RAM model, you should choose the 64bit OS, otherwise you will be able to use 4 GB RAM only.**
|
||||
|
||||
![][13]
|
||||
|
||||
Select your microSD card from the “SD Card” menu, and click on “WRITE”after.
|
||||
|
||||
![][14]
|
||||
|
||||
If it shows some error, try writing it again. It will now download the Ubuntu server image and write it to the micro SD card.
|
||||
|
||||
It will notify you when the process is completed.
|
||||
|
||||
![][15]
|
||||
|
||||
#### Step 2: Add WiFi support to Ubuntu server
|
||||
|
||||
Once the micro SD card flashing is done, you are almost ready to use it. There is one thng that you may want to do before using it and that is to add Wi-Fi support.
|
||||
|
||||
With the SD card still inserted in the card reader, open the file manager and locate the “system-boot” partition on the card.
|
||||
|
||||
The file that you are looking for and need to edit is named `network-config`.
|
||||
|
||||
![][16]
|
||||
|
||||
This process can be done on Windows and MacOS too. Edit the **`network-config`** file as already mentioned to add your Wi-Fi credentials.
|
||||
|
||||
Firstly, uncomment (remove the hashtag “#” at the beginning) from lines that are included in the rectangular box.
|
||||
|
||||
After that, replace myhomewifi with your Wi-Fi network name enclosed in quotation marks, such as “itsfoss” and the “S3kr1t” with the Wi-Fi password enclosed in quotation marks, such as “12345679”.
|
||||
|
||||
![][17]
|
||||
|
||||
It may look like this:
|
||||
|
||||
```
|
||||
wifis:
|
||||
wlan0:
|
||||
dhcp4: true
|
||||
optional: true
|
||||
access-points:
|
||||
"your wifi name":
|
||||
password: "your_wifi_password"
|
||||
```
|
||||
|
||||
Save the file and insert the micro SD card into your Raspberry Pi. During the first boot, if your Raspberry Pi fails connect to the Wi-Fi network, simply reboot your device.
|
||||
|
||||
#### Step 3: Use Ubuntu server on Raspberry Pi (if you have dedicated monitor, keyboard and mouse for Raspberry Pi)
|
||||
|
||||
If you have got an additional set of mouse, keyboard and a monitor for the Raspberry Pi, you can use easily use it like any other computer (but without GUI).
|
||||
|
||||
Simply insert the micro SD card to the Raspberry Pi, plug in the monitor, keyboard and mouse. Now [turn on your Raspberry Pi][18]. It will present TTY login screen (black terminal screen) and aks for username and password.
|
||||
|
||||
* Default username: ubuntu
|
||||
* Default password: ubuntu
|
||||
|
||||
|
||||
|
||||
When prompted, use “**ubuntu**” for the password. Right after a successful login, [Ubuntu will ask you to change the default password][19].
|
||||
|
||||
Enjoy your Ubuntu Server!
|
||||
|
||||
#### Step 3: Connect remotely to your Raspberry Pi via SSH (if you don’t have monitor, keyboard and mouse for Raspberry Pi)
|
||||
|
||||
It is okay if you don’t have a dedicated monitor to be used with Raspberry Pi. Who needs a monitor with a server when you can just SSH into it and use it the way you want?
|
||||
|
||||
**On Ubuntu and Mac OS**, an SSH client is usually already installed. To connect remotely to your Raspberry Pi, you need to discover its IP address. Check the [devices connected to your network][20] and see which one is the Raspberry Pi.
|
||||
|
||||
Since I don’t have access to a Windows machine, you can access a comprehensive guide provided by [Microsoft][21].
|
||||
|
||||
Open a terminal and run the following command:
|
||||
|
||||
```
|
||||
ssh [email protected]_pi_ip_address
|
||||
```
|
||||
|
||||
You will be asked to confirm the connection with the message:
|
||||
|
||||
```
|
||||
Are you sure you want to continue connecting (yes/no/[fingerprint])?
|
||||
```
|
||||
|
||||
Type “yes” and click the enter key.
|
||||
|
||||
![][22]
|
||||
|
||||
When prompted, use “ubuntu” for the password as mentioned earlier. You’ll be asked to change the password of course.
|
||||
|
||||
Once done, you will be automatically logged out and you have to reconnect, using your new password.
|
||||
|
||||
Your Ubuntu server is up and running on a Raspberry Pi!
|
||||
|
||||
**Conclusion**
|
||||
|
||||
Installing Ubuntu Server on a Raspberry Pi is an easy process and it comes pre-configured at a great degree which the use a pleasant experience.
|
||||
|
||||
I have to say that among all the [operating systems that I tried on my Raspberry Pi][7], Ubuntu Server was the easiest to install. I am not exaggerating. Check my guide on [installing Arch Linux on Raspberry Pi][23] for reference.
|
||||
|
||||
I hope this guide helped you in installing Ubuntu server on your Raspberry Pi as well. If you have questions or suggestions, please let me know in the comment section.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/install-ubuntu-server-raspberry-pi/
|
||||
|
||||
作者:[Dimitrios Savvopoulos][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/dimitrios/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.raspberrypi.org/
|
||||
[2]: https://itsfoss.com/raspberry-pi-alternatives/
|
||||
[3]: https://itsfoss.com/raspberry-pi-projects/
|
||||
[4]: https://itsfoss.com/raspberry-pi-4/
|
||||
[5]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/09/Ubuntu-Server-20.04.1-LTS-aarch64.png?resize=800%2C600&ssl=1
|
||||
[6]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/ubuntu-server-raspberry-pi.png?resize=800%2C450&ssl=1
|
||||
[7]: https://itsfoss.com/raspberry-pi-os/
|
||||
[8]: https://downloads.raspberrypi.org/imager/imager_amd64.deb
|
||||
[9]: https://downloads.raspberrypi.org/imager/imager.exe
|
||||
[10]: https://downloads.raspberrypi.org/imager/imager.dmg
|
||||
[11]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/raspberry-pi-imager.png?resize=800%2C600&ssl=1
|
||||
[12]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/raspberry-pi-imager-choose-ubuntu.png?resize=800%2C600&ssl=1
|
||||
[13]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/raspberry-pi-imager-ubuntu-server.png?resize=800%2C600&ssl=1
|
||||
[14]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/raspberry-pi-imager-sd-card.png?resize=800%2C600&ssl=1
|
||||
[15]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/ubuntu-server-installed-raspberry-pi.png?resize=799%2C506&ssl=1
|
||||
[16]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/ubuntu-server-pi-network-config.png?resize=800%2C565&ssl=1
|
||||
[17]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/Ubuntu-server-wifi.png?resize=800%2C600&ssl=1
|
||||
[18]: https://itsfoss.com/turn-on-raspberry-pi/
|
||||
[19]: https://itsfoss.com/change-password-ubuntu/
|
||||
[20]: https://itsfoss.com/how-to-find-what-devices-are-connected-to-network-in-ubuntu/
|
||||
[21]: https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse
|
||||
[22]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/ubuntu-server-change-password.png?resize=800%2C600&ssl=1
|
||||
[23]: https://itsfoss.com/install-arch-raspberry-pi/
|
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -1,117 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (ninja: a simple way to do builds)
|
||||
[#]: via: (https://jvns.ca/blog/2020/10/26/ninja--a-simple-way-to-do-builds/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
ninja: a simple way to do builds
|
||||
======
|
||||
|
||||
Hello! Every so often I find a new piece of software I really like, and today I want to talk about one of my recent favourites: [ninja][1]!
|
||||
|
||||
### incremental builds are useful
|
||||
|
||||
I do a lot of small projects where I want to set up incremental builds – for example, right now I’m writing a zine about bash, and I have one `.svg` file for each page of the zine. I need to convert the SVGs to PDFs, and I’d been doing it something like this:
|
||||
|
||||
```
|
||||
for i in *.svg
|
||||
do
|
||||
svg2pdf $i $i.pdf # or ${i/.svg/.pdf} if you want to get really fancy
|
||||
done
|
||||
```
|
||||
|
||||
This works fine, but my `svg2pdf` script is a little slow (it uses Inkscape), and it’s annoying to have to wait 90 seconds or whatever to rebuild all the PDFs when I’ve just updated 1 page.
|
||||
|
||||
### build systems are confusing
|
||||
|
||||
In the past I’ve been pretty put off by using a Build System like make or bazel for my small projects because bazel is this Big Complicated Thing and `make` feels a little arcane to me. I don’t really know how to use either of them.
|
||||
|
||||
So for a long time I’ve just written a bash script or something for my builds and resigned myself to just waiting for a minute sometimes.
|
||||
|
||||
### ninja is an EXTREMELY SIMPLE build system
|
||||
|
||||
But ninja is not complicated! Here is literally everything I know about ninja build file syntax: how to create a `rule` and a `build`:
|
||||
|
||||
a `rule` has a command and description (the description is just for humans to read so you can tell what it’s doing when it’s building your code)
|
||||
|
||||
```
|
||||
rule svg2pdf
|
||||
command = inkscape $in --export-text-to-path --export-pdf=$out
|
||||
description = svg2pdf $in $out
|
||||
```
|
||||
|
||||
the syntax for `build` is `build output_file: rule_name input_files`. Here’s one using the `svg2pdf` rule. The output goes in `$out` in the rule and the input goes in `$in`.
|
||||
|
||||
```
|
||||
build pdfs/variables.pdf: svg2pdf variables.svg
|
||||
```
|
||||
|
||||
That’s it! If you put those two things in a file called `build.ninja` and then run `ninja`, ninja will run `inkscape variables.svg --export-text-to-path --export-pdf=pdfs/variables.pdf`. And then if you run it again, it won’t run anything (because it can tell that you’ve already built `pdfs/variables.pdf` and you’re up to date)
|
||||
|
||||
Ninja has a few more features than this (see [the manual][2]), but I haven’t used them yet. It was originally built [for Chromium][3], so even with a small feature set it can support large builds.
|
||||
|
||||
### ninja files are usually automatically generated
|
||||
|
||||
The magic of ninja is that instead of having to use some confusing Build Language that’s hard to remember because you use it so infrequently (like make), instead the ninja language is SUPER simple, and if you want to do something complicated then you just generate the build file you want using any programming language you want.
|
||||
|
||||
I like to make a `build.py` file or that looks something like this, that creates the ninja build file and then runs `ninja`:
|
||||
|
||||
```
|
||||
with open('build.ninja', 'w') as ninja_file:
|
||||
# write some rules
|
||||
ninja_file.write("""
|
||||
rule svg2pdf
|
||||
command = inkscape $in --export-text-to-path --export-pdf=$out
|
||||
description = svg2pdf $in $out
|
||||
""")
|
||||
|
||||
# some for loop with every file I need to build
|
||||
for filename in things_to_convert:
|
||||
ninja_file.write(f"""
|
||||
build {filename.replace('svg', 'pdf')}: svg2pdf {filename}
|
||||
""")
|
||||
|
||||
# run ninja
|
||||
import subprocess
|
||||
subprocess.check_call(['ninja'])
|
||||
```
|
||||
|
||||
I’m sure there are a bunch of ninja best practices, but I don’t know them and for my small projects I find this works well.
|
||||
|
||||
### meson is a build system that generates ninja files
|
||||
|
||||
I don’t know too much about [Meson][4] yet, but recently I was building a C program ([plocate][5], a faster alternative to `locate`) and I noticed that instead of the usual `./configure; make; make install`, there were different build instructions:
|
||||
|
||||
```
|
||||
meson builddir
|
||||
cd builddir
|
||||
ninja
|
||||
```
|
||||
|
||||
It seems like Meson is a build system for C/C++/Java/Rust/Fortran that can use ninja as a backend.
|
||||
|
||||
### that’s all!
|
||||
|
||||
I’ve been using ninja for a few months now. I really like it and it’s caused me approximately 0 build-related headaches which feels pretty magical to me.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2020/10/26/ninja--a-simple-way-to-do-builds/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://ninja-build.org/
|
||||
[2]: https://ninja-build.org/manual.html
|
||||
[3]: http://neugierig.org/software/chromium/notes/2011/02/ninja.html
|
||||
[4]: https://mesonbuild.com/Tutorial.html
|
||||
[5]: https://blog.sesse.net/blog/tech/2020-09-28-00-37_introducing_plocate
|
@ -0,0 +1,73 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Bring old hardware back to life with OpenBSD)
|
||||
[#]: via: (https://opensource.com/article/20/10/old-hardware-openbsd)
|
||||
[#]: author: (Jonathan Garrido https://opensource.com/users/jgarrido)
|
||||
|
||||
Bring old hardware back to life with OpenBSD
|
||||
======
|
||||
Install OpenBSD and the Xfce desktop to give a new spin to an old
|
||||
machine—for free.
|
||||
![Old UNIX computer][1]
|
||||
|
||||
Almost everyone has (or knows someone who has) old hardware sitting around gathering dust because they believe that no modern operating system (OS) supports such a relic. I know this is wrong because I am one of those geeks who likes to use every piece of equipment as long as it is possibly functional.
|
||||
|
||||
Although most modern OSes do run better on modern hardware, it is also true that there are alternatives for up-to-date 32-bit OSes to run all types of machines, including very old ones. Thanks to a bunch of people with enough determination and skills, there are different types of Linux and BSD distros that you can use, free of charge, to give a new spin to an old machine.
|
||||
|
||||
## What can you do with a new OS on old hardware?
|
||||
|
||||
Besides the obvious benefit of bringing back a piece of equipment that has been idle for a price that is equal to nothing, using an open source 32-bit distro to revive "antique" hardware has several benefits and purposes, including:
|
||||
|
||||
* **Create single-purpose equipment:** Today's networks are complex, and there are a lot of services that interact with one another. After bringing an old machine back to life, you can set it up to fulfill one of those unique services within your infrastructure, such as DHCP, DNS, or SFTP.
|
||||
* **Learn how the OS works:** I always want to know how things work under the hood. Tinkering with old hardware and tiny OSes gives you the chance to understand the interactions between hardware and software, learn how to tune the installation's default settings to make the most of a system, and much, much more.
|
||||
* **Teach others about open source:** Finally, 32-bit OSes and old hardware can teach the next generation about OSes and the open source world. One of the main features of these types of OSes is their simplicity of use with fewer options to overwhelm the user. This makes them an excellent tool to teach and explore the essential components of any operating system.
|
||||
|
||||
|
||||
|
||||
## Distributions to try
|
||||
|
||||
To encourage you, here is a list of distros that I have tried on old hardware with very good results. These are not the only options available, but these are the ones I have used the most:
|
||||
|
||||
* [Linux Lite][2]
|
||||
* [FreeBSD][3]
|
||||
* [OpenBSD][4]
|
||||
* [Lubuntu][5]
|
||||
* [Debian][6]
|
||||
* [Tiny Core Linux][7]
|
||||
* [Slax Linux][8]
|
||||
|
||||
|
||||
|
||||
## Give it a try with OpenBSD
|
||||
|
||||
OpenBSD is one of the main [BSD][9] distros. It is well-known because it is made with security in mind, with almost no security bugs in the default installation and a lot of cryptography tools available to users. Another cool feature, at least for me, is the fact that you can run it on a huge variety of hardware, from new computers to very old machines.
|
||||
|
||||
For this installation, my hardware was a 2005 MacBook with the following specs:
|
||||
|
||||
* A 32-bit, dual-core processor
|
||||
* 2GB of RAM (with no possibility of expansion)
|
||||
* A 32GB hard drive
|
||||
* Two network cards
|
||||
* A CD-ROM (reads only CDs)
|
||||
* A few USB ports
|
||||
|
||||
|
||||
|
||||
### Install OpenBSD
|
||||
|
||||
The installation was very straightforward. I [downloaded][10] the most recent version of OpenBSD and created a boot CD (because there is no other way to boot my old laptop besides the internal drive). The installation went flawlessly. It recognized my hardware, network (including my access point), and time zone; let me choose the layout of my hard drive and manage my users; and asked some questions about the system's security setup. Also, even though the installation has a very small footprint, OpenBSD let me choose what to install and from where.
|
||||
|
||||
I ended up with a brand-new, up-to-date operating system and a screen like this.
|
||||
|
||||
![OpenBSD][11]
|
||||
|
||||
(Jonathan Garrido, [CC BY-SA 4.0][12])
|
||||
|
||||
### Add a graphical desktop
|
||||
|
||||
If you want your desktop to use graphical applications, a black terminal with white letters is not enough. So follow these steps to install the [Xfce desktop][13]:
|
||||
|
||||
1. As root, run: [code]`pkg_add xcfe xfce-extras slim slim-themes consolekit2 polkit`[/code] to install the Xfce environment and the login greeter. In the above, `pkg_add` is the utility to use when you want to d
|
@ -0,0 +1,133 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (5 new sudo features you need to know in 2020)
|
||||
[#]: via: (https://opensource.com/article/20/10/sudo-19)
|
||||
[#]: author: (Peter Czanik https://opensource.com/users/czanik)
|
||||
|
||||
5 new sudo features you need to know in 2020
|
||||
======
|
||||
From central session recording through chroot support to Python API,
|
||||
sudo 1.9 offers many new features.
|
||||
![Wratchet set tools][1]
|
||||
|
||||
When you want to perform an action on a [POSIX system][2], one of the safest ways to do so is to use the sudo command. Unlike logging in as the root user and performing what could be a dangerous action, sudo grants any user [designated as a "sudoer"][3] by the sysadmin temporary permission to perform a normally restricted activity.
|
||||
|
||||
This system has helped keep Linux, Unix, and macOS systems safe from silly mistakes and malicious attacks for decades, and it is the default administrative mechanism on all major Linux distributions today.
|
||||
|
||||
When it was released in May 2020, sudo 1.9 brought many new features, including central collection of session recordings, support for chroot within sudo, and a Python API. If you are surprised by any of these, read my article about some [lesser-known features of sudo][4].
|
||||
|
||||
Sudo is a lot more than just a prefix for administrative commands. You can fine-tune permissions, record what is happening on the terminal, extend sudo using plugins, store configurations in LDAP, do extensive logging, and much more.
|
||||
|
||||
Version 1.9.0 and subsequent minor releases added a variety of new features (which I'll describe below), including:
|
||||
|
||||
* A recording service to collect sudo session recordings centrally
|
||||
* Audit plugin API
|
||||
* Approval plugin API
|
||||
* Python support for plugins
|
||||
* Chroot and CWD support built into sudo (starting with 1.9.3)
|
||||
|
||||
|
||||
|
||||
### Where to get sudo 1.9
|
||||
|
||||
Most Linux distributions still package the previous generation of sudo (version 1.8), and it will stay that way in long-term support (LTS) releases for several years. The most complete sudo 1.9 package I am aware of in a Linux distribution is openSUSE [Tumbleweed][5], which is a rolling distro, and the sudo package has Python support available in a subpackage. Recent [Fedora][6] releases include sudo 1.9 but without Python. [FreeBSD Ports][7] has the latest sudo version available, and you can enable Python support if you build sudo yourself instead of using the package.
|
||||
|
||||
If your favorite Linux distribution does not yet include sudo 1.9, check the [sudo binaries page][8] to see if a ready-to-use package is available for your system. This page also has packages for several commercial Unix variants.
|
||||
|
||||
As usual, before you start experimenting with sudo settings, _make sure you know the root password_. Yes, even on Ubuntu. Having a temporary "backdoor" is important; without it, you would have to hack your own system if something goes wrong. And remember: a syntactically correct configuration does not mean that anybody can do anything through sudo on that system!
|
||||
|
||||
### Recording service
|
||||
|
||||
The recording service collects session recordings centrally. This offers many advantages compared to local session log storage:
|
||||
|
||||
* It is more convenient to search in one place instead of visiting individual machines for recordings
|
||||
* Recordings are available even if the sending machine is down
|
||||
* Recordings cannot be deleted by local users who want to cover their tracks
|
||||
|
||||
|
||||
|
||||
For a quick test, you can send sessions through non-encrypted connections to the recording service. My blog contains [instructions][9] for setting it up in just a few minutes. For a production setup, I recommend using encryption. There are many possibilities, so read the [documentation][10] that best suits your environment.
|
||||
|
||||
### Audit plugin API
|
||||
|
||||
The new audit plugin API is not a user-visible feature. In other words, you cannot configure it from the sudoers file. It is an API, meaning that you can access audit information from plugins, including ones written in Python. You can use it in many different ways, like sending events from sudo directly to Elasticsearch or Logging-as-a-Service (LaaS) when something interesting happens. You can also use it for debugging and print otherwise difficult-to-access information to the screen in whatever format you like.
|
||||
|
||||
Depending on how you want to use it, you can find its documentation in the sudo plugin manual page (for C) and the sudo Python plugin manual. [Sample Python code][11] is available in the sudo source code, and there is also a [simplified example][12] on my blog.
|
||||
|
||||
### Approval plugin API
|
||||
|
||||
The approval plugin API makes it possible to include extra restrictions before a command will execute. These will run only after the policy plugin succeeds, so you can effectively add additional policy layers without replacing the policy plugin and thus sudoers. Multiple approval plugins may be defined, and all must succeed for the command to execute.
|
||||
|
||||
As with the audit plugin API, you can use it both from C and Python. The [sample Python code][13] documented on my blog is a good introduction to the API. Once you understand how it works, you can extend it to connect sudo to ticketing systems and approve sessions only with a related open ticket. You can also connect to an HR database so that only the engineer on duty can gain administrative privileges.
|
||||
|
||||
### Python support for plugins
|
||||
|
||||
Even though I am not a programmer, my favorite new sudo 1.9 feature is Python support for plugins. You can use most of the APIs available from C with Python as well. Luckily, sudo is not performance-sensitive, so the relatively slow speed of running Python code is not a problem for sudo. Using Python for extending sudo has many advantages:
|
||||
|
||||
* Easier, faster development
|
||||
* No need to compile; code might even be distributed by configuration management
|
||||
* Many APIs do not have ready-to-use C clients, but Python code is available
|
||||
|
||||
|
||||
|
||||
In addition to the audit and approval plugin APIs, there are a few others available, and you can do very interesting things with them.
|
||||
|
||||
By using the policy plugin API, you can replace the sudo policy engine. Note you will lose most sudo features, and there is no more sudoers-based configuration. This can still be useful in niche cases, but most of the time, it is better to keep using sudoers and create additional policies using the approval plugin API. If you want to give it a try, my [introduction to the Python plugin][14] provides a very simple policy: allowing only the `id` command. Once again, make sure you know the root password, as once this policy is enabled, it prevents any practical use of sudo.
|
||||
|
||||
Using the I/O logs API, you can access input and output from user sessions. This means you can analyze what is happening in a session and even terminate it if you find something suspicious. This API has many possible uses, such as data-leak prevention. You can monitor the screen for keywords and, if any of them appear in the data stream, you can break the connection before the keyword can appear on the user's screen. Another possibility is checking what the user is typing and using that data to reconstruct the command line the user is entering. For example, if a user enters `rm -fr /`, you can disconnect the user even before Enter is hit.
|
||||
|
||||
The group plugin API allows non-Unix group lookups. In a way, this is similar to the approval plugin API as it also extends the policy plugin. You can check if a user is part of a given group and act based on this in later parts of the configuration.
|
||||
|
||||
### Chroot and CWD support
|
||||
|
||||
The latest additions to sudo are chroot and change working directory (CWD) support. Neither option is enabled by default—you need to explicitly enable them in the sudoers file. When they're enabled, you can fine-tune target directories or allow users to specify which directory to use. The logs reflect when these settings were used.
|
||||
|
||||
On most systems, chroot is available only to root. If one of your users needs chroot, you need to give them root access, which gives them a lot more power than just chroot. Alternately, you can allow access to the chroot command through sudo, but it still allows loopholes where they can gain full access. When you use sudo's built-in chroot support, you can easily restrict access to a single directory. You can also give users the flexibility to specify the root directory. Of course, this might lead to disasters (e.g., `sudo --chroot / -s`), but at least the event is logged.
|
||||
|
||||
When you run a command through sudo, it sets the working directory to the current directory. This is the expected behavior, but there may be cases when the command needs to be run in a different directory. For example, I recall using an application that checked my privileges by checking whether my working directory was `/root`.
|
||||
|
||||
### Try the new features
|
||||
|
||||
I hope that this article inspires you to take a closer look at sudo 1.9. Central session recording is both more convenient and secure than storing session logs locally. Chroot and CWD support give you additional security and flexibility. And using Python to extend sudo makes it easy to custom-tailor sudo to your environment. You can try the new features by using one of the latest Linux distributions or the ready-to-use packages from the sudo website.
|
||||
|
||||
If you want to learn more about sudo, here are a few resources:
|
||||
|
||||
* [Sudo website][15]
|
||||
* [Sudo blog][16]
|
||||
* [Sudo on Twitter][17]
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/10/sudo-19
|
||||
|
||||
作者:[Peter Czanik][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/czanik
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/tools_osyearbook2016_sysadmin_cc.png?itok=Y1AHCKI4 (Wratchet set tools)
|
||||
[2]: https://opensource.com/article/19/7/what-posix-richard-stallman-explains
|
||||
[3]: https://opensource.com/article/17/12/using-sudo-delegate
|
||||
[4]: https://opensource.com/article/19/10/know-about-sudo
|
||||
[5]: https://software.opensuse.org/distributions/tumbleweed
|
||||
[6]: https://getfedora.org/
|
||||
[7]: https://www.freebsd.org/ports/
|
||||
[8]: https://www.sudo.ws/download.html#binary
|
||||
[9]: https://blog.sudo.ws/posts/2020/03/whats-new-in-sudo-1.9-recording-service/
|
||||
[10]: https://www.sudo.ws/man/sudo_logsrvd.man.html#EXAMPLES
|
||||
[11]: https://github.com/sudo-project/sudo/blob/master/plugins/python/example_audit_plugin.py
|
||||
[12]: https://blog.sudo.ws/posts/2020/06/sudo-1.9-using-the-new-audit-api-from-python/
|
||||
[13]: https://blog.sudo.ws/posts/2020/08/sudo-1.9-using-the-new-approval-api-from-python/
|
||||
[14]: https://blog.sudo.ws/posts/2020/01/whats-new-in-sudo-1.9-python/
|
||||
[15]: https://www.sudo.ws/
|
||||
[16]: https://blog.sudo.ws/
|
||||
[17]: https://twitter.com/sudoproject
|
@ -0,0 +1,81 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How JavaScript became a serious programming language)
|
||||
[#]: via: (https://opensource.com/article/20/10/history-javascript)
|
||||
[#]: author: (Nimisha Mukherjee https://opensource.com/users/nimisha)
|
||||
|
||||
How JavaScript became a serious programming language
|
||||
======
|
||||
From humble beginnings as a way to make websites pretty, JavaScript has
|
||||
been transformed into a serious programming language.
|
||||
![Javascript code close-up with neon graphic overlay][1]
|
||||
|
||||
JavaScript's humble start began in 1995, when it was [created in just 10 days][2] by Brendan Eich, then an employee with Netscape Communications Corporation. JavaScript has come a long way since then, from a tool to make websites pretty to a serious programming language.
|
||||
|
||||
In its early days, JavaScript was considered a visual tool that made websites a little more fun and attractive. Languages like [Jakarta Server Pages][3] (JSP; formerly JavaServer Pages) used to do all the heavy lifting on rendered web pages, and JavaScript was used to create basic interactions, visual enhancements, and animations.
|
||||
|
||||
For a long time, the demarcations between HTML, CSS, and JavaScript were not clear. Frontend development primarily consists of HTML, CSS, and JavaScript, forming a "[layer cake][4]" of standard web technologies.
|
||||
|
||||
![Layer cake of standard web technologies][5]
|
||||
|
||||
The "[layer cake][4]" of standard web technologies (Mozilla Developers Network, [CC BY-SA 4.0][6])
|
||||
|
||||
HTML and CSS provide structure, format, and style to content. JavaScript comes into play once a web page does something beyond displaying static content. Ecma International develops JavaScript specifications, and the World Wide Web Consortium (W3C) develops HTML and CSS specifications.
|
||||
|
||||
### How JavaScript gained prominence
|
||||
|
||||
There is a long [history][7] behind how JavaScript came to be the [most popular][8] programming language. Back in the 1990s, Java was king, and comparisons to it were inevitable. Many engineers thought JavaScript was not a good programming language due to lack of support for object-oriented programming. Even though it was not evident, JavaScript's object-model and functional features were already present in its first version.
|
||||
|
||||
After JavaScript's rushed release in 1995, Netscape submitted it to the European Computer Manufacturers Association (ECMA) International for standardization. This led to [ECMAScript][9], a JavaScript standard meant to ensure interoperability of web pages across different web browsers. ECMAScript 1 came out in June 1997 and helped to advance the standardization of JavaScript.
|
||||
|
||||
During this time, PHP and JSP became popular server-side language choices. JSP had gained prominence as the preferred alternative to Common Gateway Interface ([CGI][10]) because it enabled embedding Java code in HTML. While it was popular, developers found it unnatural to have Java inside HTML. In addition, even for the simplest text change on HTML, JSP had to undergo a time-consuming lifecycle. In today's microservice world, JSP-oriented pages are considered technical debt.
|
||||
|
||||
[PHP][11] works similarly to JSP but the PHP code is processed as a Common Gateway Interface ([CGI][10]) executable. PHP-based web applications are easier to deploy than those based on JSP. Overall, it is easier to get up and running with PHP. Today, PHP and JavaScript are one of the most popular combinations for creating dynamic websites. PHP serves as the server-side scripting and JavaScript as the client-side scripting.
|
||||
|
||||
JavaScript's adoption grew with the release of [jQuery][12], a multi-purpose JavaScript library that simplifies tedious Document Object Model (DOM) management, event handling, and [Ajax][13], in 2006.
|
||||
|
||||
The turning point for JavaScript came in 2009 when [Node.js][14] was released. Developers could now write server-side scripting with JavaScript. Closely following were frameworks like [Backbone.js][15] and [AngularJS][16], both released in 2010. This led to the concept of full-stack development using a single language.
|
||||
|
||||
In 2015, Ecma International released ECMAScript 6 (ES6), which added significant new syntax for writing complex applications, including class declarations. Other new features included iterators, arrow function expressions, let and const keywords, typed arrays, new collections (maps, sets, and WeakMap), promises, template literals for strings, and many other cool features. Later editions have gone on to add more features that have made JavaScript more robust, streamlined, and reliable.
|
||||
|
||||
### Conclusion
|
||||
|
||||
JavaScript has advanced significantly over the past two decades. Most browsers now compete to meet compliance, so the latest specifications are rolled out faster.
|
||||
|
||||
There are a host of stable JavaScript frameworks to choose from, depending on your project requirements, including the most popular ones: [React][17], [Angular][18], and [Vue.js][19]. In the next article in this series, I'll dive into why JavaScript is so popular.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/10/history-javascript
|
||||
|
||||
作者:[Nimisha Mukherjee][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/nimisha
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/code_javascript.jpg?itok=60evKmGl (Javascript code close-up with neon graphic overlay)
|
||||
[2]: https://en.wikipedia.org/wiki/JavaScript
|
||||
[3]: https://en.wikipedia.org/wiki/Jakarta_Server_Pages
|
||||
[4]: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript
|
||||
[5]: https://opensource.com/sites/default/files/uploads/layercakewebtech.png (Layer cake of standard web technologies)
|
||||
[6]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[7]: https://blog.logrocket.com/history-of-frontend-frameworks/
|
||||
[8]: https://octoverse.github.com/
|
||||
[9]: https://en.wikipedia.org/wiki/ECMAScript
|
||||
[10]: https://en.wikipedia.org/wiki/Common_Gateway_Interface
|
||||
[11]: https://en.wikipedia.org/wiki/PHP#:~:text=PHP%20development%20began%20in%201994,Interpreter%22%20or%20PHP%2FFI.
|
||||
[12]: https://en.wikipedia.org/wiki/JQuery
|
||||
[13]: https://en.wikipedia.org/wiki/Ajax_(programming)
|
||||
[14]: https://en.wikipedia.org/wiki/Node.js
|
||||
[15]: https://en.wikipedia.org/wiki/Backbone.js
|
||||
[16]: https://en.wikipedia.org/wiki/AngularJS
|
||||
[17]: https://reactjs.org/
|
||||
[18]: https://angular.io/
|
||||
[19]: https://vuejs.org/
|
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -0,0 +1,629 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Program in Arm6 assembly language on a Raspberry Pi)
|
||||
[#]: via: (https://opensource.com/article/20/10/arm6-assembly-language)
|
||||
[#]: author: (Marty Kalin https://opensource.com/users/mkalindepauledu)
|
||||
|
||||
Program in Arm6 assembly language on a Raspberry Pi
|
||||
======
|
||||
Assembly language offers special insights into how machines work and how
|
||||
they can be programmed.
|
||||
![An intersection of pipes.][1]
|
||||
|
||||
The [Arm website][2] touts the processor's underlying architecture as "the keystone of the world's largest compute ecosystem," which is plausible given the number of handheld and embedded devices with Arm processors. Arm processors are prevalent in the Internet of Things (IoT), but they are also used in desktop machines, servers, and even high-performance computers, such as the Fugaku HPC. But why look at Arm machines through the lens of assembly language?
|
||||
|
||||
Assembly language is the symbolic language immediately above machine code and thereby offers special insights into how machines work and how they can be programmed efficiently. In this article, I hope to illustrate this point with the Arm6 architecture using a Raspberry Pi 4 mini-desktop machine running Debian.
|
||||
|
||||
The Arm6 family of processors supports two instruction sets:
|
||||
|
||||
* The Arm set, with 32-bit instructions throughout.
|
||||
* The Thumb set, with a mix of 16-bit and 32-bit instructions.
|
||||
|
||||
|
||||
|
||||
The examples in this article use the Arm instruction set. The Arm assembly code is in lowercase, and, for contrast, pseudo-assembly code is in uppercase.
|
||||
|
||||
### Load-store machines
|
||||
|
||||
The RISC/CISC distinction is often seen when comparing the Arm family and the Intel x86 family of processors, both of which are commercial products competing on the market. The terms RISC (reduced instruction set computer) and CISC (complex instruction set computer) date from the middle 1980s. Even then the terms were misleading, in that both RISC (e.g., MIPS) and CISC (e.g., Intel) processors had about 300 instructions in their instruction sets; today the counts for core instructions in Arm and Intel machines are close, although both types of machines have extended their instruction sets. A sharper distinction between Arm and Intel machines draws on an architectural feature other than instruction count.
|
||||
|
||||
An instruction set architecture (ISA) is an abstract model of a computing machine. Processors from Arm and Intel implement different ISAs: Arm processors implement a load-store ISA, whereas their Intel counterparts implement a register-memory ISA. The difference in ISAs can be described as:
|
||||
|
||||
* In a load-store machine, only two instructions move data between a CPU and the memory subsystem:
|
||||
* A load instruction copies bits from memory into a CPU register.
|
||||
* A store instruction copies bits from a CPU register into memory.
|
||||
* Other instructions—in particular, the ones for arithmetic-logic operations—use only CPU registers as source and destination operands. For example, here is pseudo-assembly code on a load-store machine to add two numbers originally in memory, storing their sum back in memory (comments start with `##`): [code] ## R0 is a CPU register, RAM[32] is a memory location
|
||||
LOAD R0, RAM[32] ## R0 = RAM[32]
|
||||
LOAD R1, RAM[64] ## R1 = RAM[64]
|
||||
ADD R2, R0, R1 ## R2 = R0 + R1
|
||||
STORE R2, RAM[32] ## RAM[32] = R2 [/code] The task requires four instructions: two LOADs, one ADD, and one STORE.
|
||||
* By contrast, a register-memory machine allows the operands for arithmetic-logic instructions to be registers or memory locations, usually in any combination. For example, here is pseudo-assembly code on a register-memory machine to add two numbers in memory: [code]`ADD RAM[32], RAM[32], RAM[64] ## RAM[32] += RAM[64]`[/code] The task can be accomplished with a single instruction, although the bits to be added must still be fetched from memory to a CPU, and the sum then must be copied back to memory location RAM[32].
|
||||
|
||||
|
||||
|
||||
Any ISA comes with tradeoffs. As the example above illustrates, a load-store ISA has what architects call "low instruction density": relatively many instructions may be required to perform a task. A register-memory machine has high instruction density, which is an upside. There are upsides, as well, to the load-store ISA.
|
||||
|
||||
Load-store design is an effort to simplify an architecture. For instance, consider the case in which a register-memory machine has an instruction with mixed operands:
|
||||
|
||||
|
||||
```
|
||||
COPY R2, RAM[64] ## R2 = RAM[64]
|
||||
ADD RAM[32], RAM[32], R2 ## RAM[32] = RAM[32] + R2
|
||||
```
|
||||
|
||||
Executing the ADD instruction is tricky in that the access times for the numbers to be added differs—perhaps significantly if the memory operand happens to be only in main memory rather than also in a cache thereof. Load-store machines avoid the problem of mixed access times in arithmetic-logic operations: all operands, as registers, have the same access time.
|
||||
|
||||
Furthermore, load-store architectures emphasize fixed-sized instructions (e.g., 32-bits apiece), limited formats (e.g., one, two, or three fields per instruction), and relatively few addressing modes. These design constraints mean that the processor's control unit (CU) and arithmetic-logic unit (ALU) can be simplified: fewer transistors and wires, less required power and generated heat, and so on. Load-store machines are designed to be architecturally sparse.
|
||||
|
||||
My aim is not to step into the debate over load-store versus register-memory machines but rather to set up a code example in the load-store Arm6 architecture. This first look at load-store helps to explain the code that follows. The two programs (one in C, one in Arm6 assembly) are available on [my website][3].
|
||||
|
||||
### The hstone program in C
|
||||
|
||||
Among my favorite short code examples is the hailstone function, which takes a positive integer as an argument. (I used this example in an [earlier article on WebAssembly][4].) This function is rich enough to highlight important assembly-language details. The function is defined as:
|
||||
|
||||
|
||||
```
|
||||
3N+1 if N is odd
|
||||
hstone(N) =
|
||||
N/2 if N is even
|
||||
```
|
||||
|
||||
For example, hstone(12) evaluates to 6, whereas hstone(11) evaluates to 34. If N is odd, then 3N+1 is even; but if N is even, then N/2 could be either even (e.g., 4/2 = 2) or odd (e.g., 6/2 = 3).
|
||||
|
||||
The hstone function can be used iteratively by passing the returned value as the next argument. The result is a _hailstone sequence_, such as this one, which starts with 24 as the original argument, the returned value 12 as the next argument, and so on:
|
||||
|
||||
|
||||
```
|
||||
`24,12,6,3,10,5,16,8,4,2,1,4,2,1,...`
|
||||
```
|
||||
|
||||
It takes 10 steps for the sequence to converge to 1, at which point the sequence of 4,2,1 repeats indefinitely: (3x1)+1 is 4, which is halved to yield 2, which is halved to yield 1, and so on. For an explanation of why "hailstone" seems an appropriate name for such sequences, see "[Mathematical mysteries: Hailstone sequences][5]."
|
||||
|
||||
Note that powers of 2 converge quickly: 2N requires just N divisions by 2 to reach 1. For example, 32 = 25 has a convergence length of 5, and 512 = 29 has a convergence length of 9. If the hailstone function returns any power of 2, then the sequence converges to 1. Of interest here is the sequence length from the initial argument to the first occurrence of 1.
|
||||
|
||||
The [Collatz conjecture][6] is that a hailstone sequence converges to 1 no matter what the initial argument N > 0 happens to be. Neither a counterexample nor a proof has been found. The conjecture, simple as it is to illustrate with a program, remains a profoundly challenging problem in number theory.
|
||||
|
||||
Below is the C source code for the hstoneC program, which computes the length of the hailstone sequence whose starting value is given as user input. The assembly-language version of the program (hstoneS) is provided after an overview of Arm6 basics. For clarity, the two programs are structurally similar.
|
||||
|
||||
Here is the C source code:
|
||||
|
||||
|
||||
```
|
||||
#include <stdio.h>
|
||||
|
||||
/* Compute steps from n to 1.
|
||||
-- update an odd n to (3 * n) + 1
|
||||
-- update an even n to (n / 2) */
|
||||
unsigned hstone(unsigned n) {
|
||||
unsigned len = 0; /* counter */
|
||||
while (1) {
|
||||
if (1 == n) break;
|
||||
n = (0 == (n & 1)) ? n / 2 : (3 * n) + 1;
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int main() {
|
||||
[printf][7]("Integer > 0: ");
|
||||
unsigned num;
|
||||
[scanf][8]("%u", &num);
|
||||
[printf][7]("Steps from %u to 1: %u\n", num, hstone(num));
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
When the program is run with an input of 9, the output is:
|
||||
|
||||
|
||||
```
|
||||
`Steps from 9 to 1: 19`
|
||||
```
|
||||
|
||||
The hstoneC program has a simple structure. The `main` function prompts the user for an input N (an integer > 0) and then calls the `hstone` function with this input as an argument. The `hstone` function loops until the sequence from N reaches the first 1, returning the number of steps required.
|
||||
|
||||
The most complicated statement in the program involves C's conditional operator, which is used to update N:
|
||||
|
||||
|
||||
```
|
||||
`n = (0 == (n & 1)) ? n / 2 : (3 * n) + 1;`
|
||||
```
|
||||
|
||||
This is a terse form of an if-then construct. The test `(0 == (n & 1))` checks whether the C variable `n` (representing N) is even or odd depending on whether the bitwise AND of N and 1 is zero: an integer value is even just in case its least-significant (rightmost) bit is zero. If N is even, N/2 becomes the new value; otherwise, 3N+1 becomes the new value. The assembly-language version of the program (hstoneS) likewise avoids an explicit if-else construct in updating its implementation of N.
|
||||
|
||||
My Arm6 mini-desktop machine includes the GNU C toolset, which can generate the corresponding code in assembly language. With `%` as the command-line prompt, the command is:
|
||||
|
||||
|
||||
```
|
||||
`% gcc -S hstoneC.c ## -S flag produces and saves assembly code`
|
||||
```
|
||||
|
||||
This produces the file hstoneC.s, which is about 120 lines of assembly-language source code, including a `nop` ("no operation") instruction. Compiler-generated assembly tends to be hard to read and may have inefficiencies such as the `nop`. A hand-crafted version, such as `hstoneS.s` (below), can be easier to follow and even significantly shorter (e.g., `hstoneS.s` has about 50 lines of code).
|
||||
|
||||
### Assembly language basics
|
||||
|
||||
Arm6, like most modern architectures, is byte-addressable: a memory address is of a byte, even if the addressed item (e.g., a 32-bit instruction) consists of multiple bytes. Instructions are addressed in little-[endian][9] fashion: the address is of the low-order byte. Data items are addressed in little-endian fashion by default, but this can be changed to big-endian so that the address of a multi-byte data item points to the high-order byte. By tradition, the low-order byte is depicted as the rightmost one and the high-order byte as the leftmost one:
|
||||
|
||||
|
||||
```
|
||||
high-order low-order
|
||||
/ /
|
||||
+----+----+----+----+
|
||||
| b1 | b2 | b3 | b4 | ## 4 bytes = 32 bits
|
||||
+----+----+----+----+
|
||||
```
|
||||
|
||||
Addresses are 32-bits in size, and data items come in three standard sizes:
|
||||
|
||||
* A _byte_ is 8 bits in size.
|
||||
* A _halfword_ is 16 bits in size.
|
||||
* A _word_ is 32 bits in size.
|
||||
|
||||
|
||||
|
||||
Aggregates of bytes, halfwords, and words (e.g., arrays and structures) are supported. CPU registers are 32-bits in size.
|
||||
|
||||
Assembly languages, in general, have three key features with a syntax that is close and, at times, identical:
|
||||
|
||||
* Directives in both Arm6 and Intel assembly start with a period. Here are two Arm6 examples, which happen to work in Intel as well:
|
||||
|
||||
|
||||
```
|
||||
.data
|
||||
.align 4
|
||||
```
|
||||
|
||||
The first directive indicates that the following section holds data items rather than code. The `.align 4` directive specifies that data items should be laid out, in memory, on 4-byte boundaries, which is common in modern architectures. As the name suggests, a directive gives direction to the translator (the "assembler") as this does its work.
|
||||
|
||||
By contrast, this directive indicates a code rather than a data section:
|
||||
|
||||
|
||||
```
|
||||
`.text`
|
||||
```
|
||||
|
||||
The term "text" is traditional, and its meaning, in this context, is "read-only": during program execution, code is read-only, whereas data can be read and written.
|
||||
|
||||
* Labels in both recent Arm and Intel assembly end with colons. A label is a memory address for either data items (e.g., variables) or code blocks (e.g., functions). Assembly languages, in general, rely heavily on addresses, which means that manipulating pointers—in particular, dereferencing them to get the values to which they point—takes front stage in assembly-language programming. Here are two labels in the hstoneS program:
|
||||
|
||||
|
||||
```
|
||||
collatz: /* label */
|
||||
mov r0, #0 /* instruction */
|
||||
loop_start: /* label */
|
||||
...
|
||||
```
|
||||
|
||||
The first label marks the start of the `collatz` function, whose first instruction copies the value zero (`#0`) into the register `r0`. (The `mov` for "move" opcode occurs across assembly languages but really means "copy.") The second label, `loop_start:`, is the address of the loop that computes the length of the hailstone sequence. The register `r0` serves as the sequence counter.
|
||||
|
||||
* Instructions, which assembly-sensitive editors usually indent along with directives, specify the operations to be performed (e.g., `mov`) together with operands (in this case, `r0` and `#0`). There are instructions with no operands and others with several.
|
||||
|
||||
|
||||
|
||||
|
||||
The `mov` instruction above does not violate the load-store principle about memory access. In general, a load instruction (`ldr` in Arm6) loads memory contents into a register. By contrast, a `mov` instruction can be used to copy an "immediate value," such as an integer constant, into a register:
|
||||
|
||||
|
||||
```
|
||||
`mov r0, #0 /* copy zero into r0 */`
|
||||
```
|
||||
|
||||
A `mov` instruction also can be used to copy the contents of one register into another:
|
||||
|
||||
|
||||
```
|
||||
`mov r1, r0 /* r1 = r0 */`
|
||||
```
|
||||
|
||||
The load opcode `ldr` would be inappropriate in both cases because a memory location is not in play. Examples of Arm6 `ldr` ("load register") and `str` ("store register") instructions are forthcoming.
|
||||
|
||||
The Arm6 architecture has 16 primary CPU registers (each 32-bits in size), a mix of general-purpose and special-purpose. Table 1 gives a summary, listing special features and uses beyond scratchpad:
|
||||
|
||||
#### Table 1. Primary CPU registers
|
||||
|
||||
Register | Special features
|
||||
---|---
|
||||
r0 | 1st arg to library function, retval
|
||||
r1 | 2nd arg to library function
|
||||
r2 | 3rd arg to library function
|
||||
r3 | 4th arg to library function
|
||||
r4 | callee-saved
|
||||
r5 | callee-saved
|
||||
r6 | callee-saved
|
||||
r7 | callee-saved, system calls
|
||||
r8 | callee-saved
|
||||
r9 | callee-saved
|
||||
r10 | callee-saved
|
||||
r11 | callee-saved, frame pointer
|
||||
r12 | intra-procedure
|
||||
r13 | stack pointer
|
||||
r14 | link register
|
||||
r15 | program counter
|
||||
|
||||
In general, CPU registers serve as a backup for the stack, the area of main memory that provides reusable scratchpad storage for the arguments passed to functions and the local variables used in functions and other code blocks (e.g., the body of a loop). Given that CPU registers reside on the same chip as the CPU, access time is fast. Access to the stack is significantly slower, with the details depending on the particularities of a system. However, registers are scarce. In the case of Arm6, there are only 16 primary CPU registers, and some of these have special uses beyond scratchpad.
|
||||
|
||||
The first four registers, `r0` through `r3`, are used for scratchpad but also to pass arguments along to library functions. For example, calling a library function such as `printf` (used in both the hstoneC and hstoneS programs) requires that the expected arguments be in the expected registers. The `printf` function takes at least one argument (a format string) but usually takes others, as well (the values to be formatted). The address of the format string has to be in register `r0` for the call to succeed. A programmer-defined function can implement its own register strategy, of course, but using the first four registers for function arguments is common in Arm6 programming.
|
||||
|
||||
Register `r0` also has special uses. For example, it typically holds the value returned from a function, as in the `collatz` function of the hstoneS program. If a program calls the `syscall` function, which is used to invoke system functions such as `read` and `write`, register `r0` holds the integer identifier of the system function to be called (e.g., function `write` has 4 as its identifier). In this respect, register `r0` is similar in purpose to register `r7`, which holds such an identifier when function `svc` ("supervisor call") is used instead of `syscall`.
|
||||
|
||||
Registers `r4` through `r11` are general-purpose and "callee saved" (aka "non-volatile" or "call-preserved"). Consider the case in which function F1 calls function F2 using registers to pass arguments to F2. The registers `r0` through `r3` are "caller saved" (aka "volatile" or "call-clobbered") in that, for example, the called function F2 might call some other function F3 by using the very same registers that F1 did—but with new values therein:
|
||||
|
||||
|
||||
```
|
||||
27 13 191 437
|
||||
\ \ \ \
|
||||
r0, r1 r0, r1
|
||||
F1-------->F2-------->F3
|
||||
```
|
||||
|
||||
After F1 calls F2, the contents of registers `r0` and `r1` get changed for F2's call to F3. Accordingly, F1 must not assume that its values in `r0` and `r1` (27 and 13, respectively) have been preserved; instead, these values have been overwritten—clobbered by the new values 191 and 437. Because the first four registers are not "callee saved," called function F2 is not responsible for preserving and later restoring the values in the registers set by F1.
|
||||
|
||||
Callee-saved registers bring responsibility to a called function. For example, if F1 used callee-saved registers `r4` and `r5` in its call to F2, then F2 would be responsible for saving the contents of these registers (typically on the stack) and then restoring the values before returning to F1. F2's code then might start and end as follows:
|
||||
|
||||
|
||||
```
|
||||
push {r4, r5} /* save r4 and r5 values on the stack */
|
||||
... /* reuse r4 and r5 for some other task */
|
||||
pop {r4, r5} /* restore r4 and r5 values */
|
||||
```
|
||||
|
||||
The `push` operation saves the values in `r4` and `r5` to the stack. The matching `pop` operation then recovers these values from the stack and puts them into `r4` and `r5`.
|
||||
|
||||
Other registers in Table 1 can be used as scratchpad, but some have a special use, as well. As noted earlier, register `r7` can be used to make system calls (e.g., to function `write`), which a later example shows in detail. In an `svc` instruction, the integer identifier for a particular system function must be in register `r7` (e.g., 4 to identify the `write` function).
|
||||
|
||||
Register `r11` is aliased as `fp` for "frame pointer," which points to the start of the current call frame. When one function calls another, the called function gets its own area of the stack (a call frame) for use as scratchpad. A frame pointer, unlike the stack pointer described below, typically remains fixed until a called function returns.
|
||||
|
||||
Register `r12`, also known as `ip` ("intra-procedure"), is used by the dynamic linker. Between calls to dynamically linked library functions, however, a program can use this register as scratchpad.
|
||||
|
||||
Register `r13`, which has `sp` ("stack pointer") as an alias, points to the top of the stack and is updated automatically through `push` and `pop` operations. The stack pointer also can be used as a base address with an offset; for example, `sp - #4` points 4 bytes below where the `sp` points. The Arm6 stack, like its Intel counterpart, grows from high to low addresses. (Some authors accordingly describe the stack pointer as pointing to the bottom rather than the top of the stack.)
|
||||
|
||||
Register `r14`, with `lr` as an alias, serves as the "link register" that holds a return address for a function. However, a called function can call another with a `bl` ("branch with link") or `bx` ("branch with exchange") instruction, thereby clobbering the contents of the `lr` register. For example, in the hstoneS program, the function `main` calls four others. Accordingly, function `main` saves the `lr` of its caller on the stack and later restores this value. The pattern occurs regularly in Arm6 assembly language:
|
||||
|
||||
|
||||
```
|
||||
push {lr} /* save caller's lr */
|
||||
... /* call some functions */
|
||||
pop {lr} /* restore caller's lr */
|
||||
```
|
||||
|
||||
Register `r15` is also the `pc` ("program counter"). In most architectures, the program counter points to the "next" instruction to be executed. For historical reasons, the Arm6 `pc` points to _two_ instructions beyond the current one. The `pc` can be manipulated directly (for example, to call a function), but the recommended approach is to use instructions such as `bl` that manipulate the link register.
|
||||
|
||||
Arm6 has the usual assortment of instructions for arithmetic (e.g., add, subtract, multiply, divide), logic (e.g., compare, shift), control (e.g., branch, exit), and input/output (e.g., read, write). The results of comparisons and other operations are saved in the special-purpose register `cpsr` ("current processor status register"). For example, this register records whether an addition caused an overflow or whether two compared integer values are equal.
|
||||
|
||||
It is worth repeating that the Arm6 has exactly two basic data movement instructions: `ldr` to load memory contents into a register and `str` to store register contents in memory. Arm6 includes variations of the basic `ldr` and `str` instructions, but the load-store pattern of moving data between registers and memory remains the same.
|
||||
|
||||
A code example brings these architectural details to life. The next section introduces the hailstone program in assembly language.
|
||||
|
||||
### The hstone program in Arm6 assembly
|
||||
|
||||
The above overview of Arm6 assembly is enough to introduce the full code example for hstoneS. For clarity, the assembly-language program hstoneS has essentially the same structure as the C program hstoneC: two functions, `main` and `collatz`, and mostly straight-line code execution in each function. The behavior of the two programs is the same.
|
||||
|
||||
Here is the source code for hstoneS:
|
||||
|
||||
|
||||
```
|
||||
.data /* data versus code */
|
||||
.balign 4 /* alignment on 4-byte boundaries */
|
||||
|
||||
/* labels (addresses) for user input, formatters, etc. */
|
||||
num: .int 0 /* 4-byte integer */
|
||||
steps: .int 0 /* another for the result */
|
||||
prompt: .asciz "Integer > 0: " /* zero-terminated ASCII string */
|
||||
format: .asciz "%u" /* %u for "unsigned" */
|
||||
report: .asciz "From %u to 1 takes %u steps.\n"
|
||||
|
||||
.text /* code: 'text' in the sense of 'read only' */
|
||||
.global main /* program's entry point must be global */
|
||||
.extern [printf][7] /* library function */
|
||||
.extern [scanf][8] /* ditto */
|
||||
|
||||
collatz: /** collatz function **/
|
||||
mov r0, #0 /* r0 is the step counter */
|
||||
loop_start: /** collatz loop **/
|
||||
cmp r1, #1 /* are we done? (num == 1?) */
|
||||
beq collatz_end /* if so, return to main */
|
||||
|
||||
and r2, r1, #1 /* odd-even test for r1 (num) */
|
||||
cmp r2, #0 /* even? */
|
||||
moveq r1, r1, LSR #1 /* even: divide by 2 via a 1-bit right shift */
|
||||
addne r1, r1, r1, LSL #1 /* odd: multiply by adding and 1-bit left shift */
|
||||
addne r1, #1 /* odd: add the 1 for (3 * num) + 1 */
|
||||
|
||||
add r0, r0, #1 /* increment counter by 1 */
|
||||
b loop_start /* loop again */
|
||||
collatz_end:
|
||||
bx lr /* return to caller (main) */
|
||||
|
||||
main:
|
||||
push {lr} /* save link register to stack */
|
||||
|
||||
/* prompt for and read user input */
|
||||
ldr r0, =prompt /* format string's address into r0 */
|
||||
bl [printf][7] /* call printf, with r0 as only argument */
|
||||
|
||||
ldr r0, =format /* format string for scanf */
|
||||
ldr r1, =num /* address of num into r1 */
|
||||
bl [scanf][8] /* call scanf */
|
||||
|
||||
ldr r1, =num /* address of num into r1 */
|
||||
ldr r1, [r1] /* value at the address into r1 */
|
||||
bl collatz /* call collatz with r1 as the argument */
|
||||
|
||||
/* demo a store */
|
||||
ldr r3, =steps /* load memory address into r3 */
|
||||
str r0, [r3] /* store hailstone steps at mem[r3] */
|
||||
|
||||
/* setup report */
|
||||
mov r2, r0 /* r0 holds hailstone steps: copy into r2 */
|
||||
ldr r1, =num /* get user's input again */
|
||||
ldr r1, [r1] /* dereference address to get value */
|
||||
ldr r0, =report /* format string for report into r0 */
|
||||
bl [printf][7] /* print report */
|
||||
|
||||
pop {lr} /* return to caller */
|
||||
```
|
||||
|
||||
Arm6 assembly supports documentation in either C style (the slash-star and star-slash syntax used here) or one-line comments introduced by the @ sign. The hstoneS program, like its C counterpart, has two functions:
|
||||
|
||||
* The program's entry point is the `main` function, which is identified by the label `main:`; this label marks where the function's first instruction is found. In Arm6 assembly, the entry point must be declared as global:
|
||||
|
||||
|
||||
```
|
||||
`.global main`
|
||||
```
|
||||
|
||||
In C, a function's _name_ is the address of the code block that makes up the function's body, and a C function is `extern` (global) by default. It is unsurprising how much C and assembly language resemble one another; indeed, C is portable assembly language.
|
||||
|
||||
* The `collatz` function expects one argument, which is implemented by the register `r1` to hold the user's input of an unsigned integer value (e.g., 9). This function updates register `r1` until it equals 1, keeping count of the steps involved with register `r0`, which thereby serves as the function's return value.
|
||||
|
||||
|
||||
|
||||
|
||||
An early and interesting code segment in `main` involves the call to the library function `scanf`, a high-level input function that scans a value from the standard input (by default, the keyboard) and converts this value to the desired data type, in this case, a 4-byte unsigned integer. Here is the code segment in full:
|
||||
|
||||
|
||||
```
|
||||
ldr r0, =format /* address of format string into r0 */
|
||||
ldr r1, =num /* address of num into r1 */
|
||||
bl [scanf][8] /* call scanf (bl = branch with link) */
|
||||
|
||||
ldr r1, =num /* address of num into r1 */
|
||||
ldr r1, [r1] /* value at the address into r1 */
|
||||
bl collatz /* call collatz with r1 as the argument */
|
||||
```
|
||||
|
||||
Two labels (addresses) are in play: `format` and `num`, both of which are defined in the `.data` section at the top of the program:
|
||||
|
||||
|
||||
```
|
||||
num: .int 0
|
||||
format: .asciz "%u"
|
||||
```
|
||||
|
||||
The label `num:` is the memory address of a 4-byte integer value, initialized to zero; the label `format:` points to a null-terminated (the "z" in "asciz" for zero) string `"%u"`, which specifies that the scanned input should be converted to an unsigned integer. Accordingly, the first two instructions in the code segment load the address of the format string (`=format`) into register `r0` and the address for the scanned number (`=num`) into register `r1`. Note that each label now starts with an equals sign ("assign address") and that the colon is dropped at the end of each label. The library function `scanf` can take an arbitrary number of arguments, but the first (which `scanf` expects in register `r0`) should be the "address" of a format string. In this example, the second argument to `scanf` is the "address" at which to save the scanned integer.
|
||||
|
||||
The last three instructions in the code segment highlight important assembly details. The first `ldr` instruction loads the _address_ of the memory-based integer (`=num`) into register `r1`. However, the `collatz` function expects the _value_ stored at this address, not the address itself; hence, the address is dereferenced to get the value:
|
||||
|
||||
|
||||
```
|
||||
ldr r1, =num /* load address into r1 */
|
||||
ldr r1, [r1] /* dereference to get value */
|
||||
```
|
||||
|
||||
The square brackets specify memory and `r1` holds a memory address. The expression `[r1]` thus evaluates to the _value_ stored in memory at address `r1`. The example underscores that registers can hold addresses and values stored at addresses: register `r1` first holds an address and then the value stored at this address.
|
||||
|
||||
When the `collatz` function returns to `main`, this function first performs a store operation:
|
||||
|
||||
|
||||
```
|
||||
ldr r3, =steps /* steps is a memory address */
|
||||
str r0, [r3] /* store r0 value at mem[r3] */
|
||||
```
|
||||
|
||||
The label `steps:` is from the `.data` section and register `r0` holds the steps computed in the `collatz` function. The `str` instruction thus saves to memory the length of the hailstone sequence. In a `ldr` instruction, the first operand (a register) is the _target_ for the load; but in a `str` operation, the first operand (also a register) is the _source_ for the store. In both cases, the second operand is a memory location.
|
||||
|
||||
Some additional work in `main` sets up the final report:
|
||||
|
||||
|
||||
```
|
||||
mov r2, r0 /* save count in r2 */
|
||||
ldr r1, =num /* recover user input */
|
||||
ldr r1, [r1] /* dereference r1 */
|
||||
ldr r0, =report /* r0 points to format string */
|
||||
bl [printf][7] /* print report */
|
||||
```
|
||||
|
||||
In the `collatz` function, register `r0` tracks how many steps are needed to reach 1 from the user's input, but the library function `printf` expects its first argument (the address of a format string) to be stored in register `r0`. The return value in register `r0` is therefore copied into register `r2` with the `mov` instruction. The address of the format string for `printf` is then stored in register `r0`.
|
||||
|
||||
The argument to the `collatz` function is the scanned input, which is stored in register `r1`; but this register is updated in the `collatz` loop unless the value happens to be 1 at the start. Accordingly, the address `num:` is again copied into `r1` and then dereferenced to get the user's original input. This value becomes the second argument to `printf`, the starting value of the hailstone sequence. With this setup in place, `main` calls `printf` with the `bl` ("branch with link") instruction.
|
||||
|
||||
At the very start of the `collatz` loop, the program checks whether the sequence has hit a 1:
|
||||
|
||||
|
||||
```
|
||||
cmp r1, #1
|
||||
beq collatz_end
|
||||
```
|
||||
|
||||
If register `r1` has 1 as its value, there is a branch (`beq` for "branch if equal") to the end of the `collatz` function, which means a return to its caller `main` with register `r0` as the return value—the number of steps in the hailstone sequence.
|
||||
|
||||
The `collatz` function introduces new features and opcodes, which illustrate how efficient assembly code can be. The assembly code, like the C code, checks for N's parity, with register `r1` as N:
|
||||
|
||||
|
||||
```
|
||||
and r2, r1, #1 /* r2 = r1 & 1 */
|
||||
cmp r2, #0 /* is the result even? */
|
||||
```
|
||||
|
||||
The result of the bitwise AND operation on register `r1` and 1 is stored in register `r2`. If the least-significant (rightmost) bit of register `r2` is a 1, then N (register `r1`) is odd, and otherwise, it is even. The result of this comparison (saved in the special-purpose register `cpsr`) is used automatically in forthcoming instructions such as `moveq` ("move if equal") and `addne` ("add if not equal").
|
||||
|
||||
The assembly code, like the C code, now avoids an explicit if-else construct. This code segment has the same effect as an if-else test, but the code is more efficient in that no branching is involved—the code executes in straight-line fashion because the conditional tests are built into the instruction opcodes:
|
||||
|
||||
|
||||
```
|
||||
moveq r1, r1, LSR #1 /* right-shift 1 bit if even */
|
||||
addne r1, r1, r1, LSL #1 /* left-shift 1 bit and add otherwise */
|
||||
addne r1, #1 /* add 1 for the + 1 in N = 3N + 1 */
|
||||
```
|
||||
|
||||
The `moveq` (`eq` for "if equal") instruction checks the outcome of the earlier `cmp` test, which determines whether the current value of register `r1` (N) is even or odd. If the value in register `r1` is even, this value must be updated to its half, which is done by a 1-bit right-shift (`LSR #1`). In general, right-shifting an integer is more efficient than explicitly dividing it by two. For example, suppose that register `r1` currently holds 4, whose least significant four bits are:
|
||||
|
||||
|
||||
```
|
||||
`...0100 ## 4 in binary`
|
||||
```
|
||||
|
||||
Shifting right by 1 bit yields:
|
||||
|
||||
|
||||
```
|
||||
`...0010 ## 2 in binary`
|
||||
```
|
||||
|
||||
The `LSR` stands for "logical shift right" and contrasts with `ASR` for "arithmetic shift right." An arithmetic shift is sign-preserving (most significant bit of 1 for negative and 0 for non-negative), whereas a logical shift is not, but the hailstone programs deal exclusively with _unsigned_ (hence, non-negative) values. In a logical shift, the shifted bits are replaced by zeros.
|
||||
|
||||
If register `r1` holds a value with odd parity, similar straight-line code occurs:
|
||||
|
||||
|
||||
```
|
||||
addne r1, r1, r1, LSL #1 /* r1 = r1 * 3 */
|
||||
addne r1, #1 /* r1 = r1 + 1 */
|
||||
```
|
||||
|
||||
The two `addne` instructions (`ne` for "if not equal") execute only if the earlier check for parity indicates an odd value. The first `addne` instruction does multiplication through a 1-bit left-shift and addition. In general, shifting and adding are more efficient than explicitly multiplying. The second `addne` then adds 1 to register `r1` so that the update is from N to 3N+1.
|
||||
|
||||
### Assembling the hstoneS program
|
||||
|
||||
The assembly source code for the hstoneS program needs to be translated ("assembled") into a binary _object module_, which is then linked with appropriate libraries to become executable. The simplest approach is to use the GNU C compiler in the same way as it is used to compile a C program such as hstoneC:
|
||||
|
||||
|
||||
```
|
||||
`% gcc -o hstoneS hstoneS.s`
|
||||
```
|
||||
|
||||
This command does the assembling and linking.
|
||||
|
||||
A slightly more efficient approach is to use the _as_ utility that ships with the GNU toolset. This approach separates the assembling and the linking. Here is the assembling step:
|
||||
|
||||
|
||||
```
|
||||
`% as -o hstoneS.o hstoneS.s ## assemble`
|
||||
```
|
||||
|
||||
The extension `.o` is traditional for object modules. The system utility _ld_ then could be used for the linking, but an easier and equally efficient approach is to revert to the _gcc_ command:
|
||||
|
||||
|
||||
```
|
||||
`% gcc -o hstoneS hstoneS.o ## link`
|
||||
```
|
||||
|
||||
This approach highlights again that the C compiler handles any mix of C and assembly, whether source files or object modules.
|
||||
|
||||
### Wrapping up with an explicit system call
|
||||
|
||||
The two hailstone programs use the high-level input/output functions `scanf` and `printf`. These functions are high-level in that they deal with formatted types (in this case, unsigned integers) rather than with raw bytes. In an embedded system, however, these functions might not be available; the low-level input/output functions `read` and `write`, which ultimately implement their high-level counterparts, then would be used instead. These two system functions are low-level in that they work with raw bytes.
|
||||
|
||||
In Arm6 assembly, a program explicitly calls a system function such as `write` in an indirect manner—by invoking one of the aforementioned functions `svc` or `syscall`, for example:
|
||||
|
||||
|
||||
```
|
||||
calls calls
|
||||
program------->svc------->write
|
||||
```
|
||||
|
||||
The integer identifier for a particular system function (e.g., 4 identifies `write`) goes into the appropriate register (register `r7` for `svc` and register `r0` for `syscall`). The code segments below illustrate, first with `svc` and then with `syscall`.
|
||||
|
||||
The two code segments write the traditional greeting to the standard output, which is the screen by default. The standard output has a _file descriptor_, a non-negative integer value that identifies it. The three predefined descriptors are:
|
||||
|
||||
|
||||
```
|
||||
standard input: 0 (keyboard by default)
|
||||
standard output: 1 (screen by default)
|
||||
standard error: 2 (screen by default)
|
||||
```
|
||||
|
||||
Here is the code segment for a sample system call with `svc`:
|
||||
|
||||
|
||||
```
|
||||
msg: .asciz "Hello, world!\n" /* greeting */
|
||||
...
|
||||
mov r0, #1 /* 1 = standard output */
|
||||
ldr r1, =msg /* address of bytes to write */
|
||||
mov r2, #14 /* message length (in bytes) */
|
||||
mov r7, #4 /* write has 4 as an id */
|
||||
svc #0 /* system call to write */
|
||||
```
|
||||
|
||||
The function `write` takes three arguments and, when called via `svc`, the function's arguments go into the following registers:
|
||||
|
||||
* `r0` holds the target for the write operation, in this case, the standard output (`#1`).
|
||||
* `r1` has the address of the byte(s) to write (`=msg`).
|
||||
* `r2` specifies how many bytes are to be written (`#14`).
|
||||
|
||||
|
||||
|
||||
In the case of the `svc` instruction, register `r7` identifies, with a non-negative integer (in this case, `#4`), which system function to call. The `svc` call returns zero (the `#0`) to signal success but usually a negative value to signal an error.
|
||||
|
||||
The `syscall` and `svc` functions differ in detail, but using either to invoke a system function requires the same two steps:
|
||||
|
||||
* Specify the system function to be called (in `r7` for `svc`, in `r0` for `syscall`).
|
||||
* Put the arguments for the system function in the appropriate registers, which differ between the `svc` and `syscall` variants.
|
||||
|
||||
|
||||
|
||||
Here is the `syscall` example of invoking the `write` function:
|
||||
|
||||
|
||||
```
|
||||
msg: .asciz "Hello, world!\n" /* greeting */
|
||||
...
|
||||
mov r1, #1 /* standard output */
|
||||
ldr r2, =msg /* address of message */
|
||||
mov r3, #14 /* byte count */
|
||||
mov r0, #4 /* identifier for write */
|
||||
syscall
|
||||
```
|
||||
|
||||
C has a thin wrapper not only for the `syscall` function but for the system functions `read` and `write` as well. The C wrapper for `syscall` gives the gist at a high level:
|
||||
|
||||
|
||||
```
|
||||
syscall(SYS_write, /* 4 is the id for write */
|
||||
STDOUT_FILENO, /* 1 is the standard output */
|
||||
"Hello, world!\n", /* message */
|
||||
14); /* byte length */
|
||||
```
|
||||
|
||||
The direct approach in C uses the wrapper for the system `write` function:
|
||||
|
||||
|
||||
```
|
||||
`write(STDOUT_FILENO, "Hello, world!\n", 14);`
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/10/arm6-assembly-language
|
||||
|
||||
作者:[Marty Kalin][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者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/mkalindepauledu
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/LAW-Internet_construction_9401467_520x292_0512_dc.png?itok=RPkPPtDe (An intersection of pipes.)
|
||||
[2]: https://www.arm.com/
|
||||
[3]: https://condor.depaul.edu/mkalin
|
||||
[4]: https://opensource.com/article/19/8/webassembly-speed-code-reuse
|
||||
[5]: https://plus.maths.org/content/mathematical-mysteries-hailstone-sequences
|
||||
[6]: https://en.wikipedia.org/wiki/Collatz_conjecture
|
||||
[7]: http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
|
||||
[8]: http://www.opengroup.org/onlinepubs/009695399/functions/scanf.html
|
||||
[9]: https://en.wikipedia.org/wiki/Endianness
|
81
sources/tech/20201028 What-s new in Fedora 33 Workstation.md
Normal file
81
sources/tech/20201028 What-s new in Fedora 33 Workstation.md
Normal file
@ -0,0 +1,81 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (What’s new in Fedora 33 Workstation)
|
||||
[#]: via: (https://fedoramagazine.org/whats-new-fedora-33-workstation/)
|
||||
[#]: author: (Gregory Bartholomew https://fedoramagazine.org/author/glb/)
|
||||
|
||||
What’s new in Fedora 33 Workstation
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
Fedora 33 Workstation is the [latest release][2] of our free, leading-edge operating system. You can download it from [the official website here][3] right now. There are several new and noteworthy changes in Fedora 33 Workstation. Read more details below.
|
||||
|
||||
### GNOME 3.38
|
||||
|
||||
Fedora 33 Workstation includes the latest release of GNOME Desktop Environment for users of all types. GNOME 3.38 in Fedora 33 Workstation includes many updates and improvements, including:
|
||||
|
||||
#### A new GNOME Tour app
|
||||
|
||||
New users are now greeted by “a new _Tour_ application, highlighting the main functionality of the desktop and providing first time users a nice welcome to GNOME.”
|
||||
|
||||
![The new GNOME Tour application in Fedora 33][4]
|
||||
|
||||
#### Drag to reorder apps
|
||||
|
||||
GNOME 3.38 replaces the previously split Frequent and All apps views with a single customizable and consistent view that allows you to reorder apps and organize them into custom folders. Simply click and drag to move apps around.
|
||||
|
||||
![GNOME 3.38 Drag to Reorder][5]
|
||||
|
||||
#### Improved screen recording
|
||||
|
||||
The screen recording infrastructure in GNOME Shell has been improved to take advantage of PipeWire and kernel APIs. This will help reduce resource consumption and improve responsiveness.
|
||||
|
||||
GNOME 3.38 also provides many additional features and enhancements. Check out the [GNOME 3.38 Release Notes][6] for further information.
|
||||
|
||||
* * *
|
||||
|
||||
### B-tree file system
|
||||
|
||||
As [announced previously][7], new installations of Fedora 33 will default to using [Btrfs][8]. Features and enhancements are added to Btrfs with each new kernel release. The [change log][9] has a complete summary of the features that each new kernel version brings to Btrfs.
|
||||
|
||||
* * *
|
||||
|
||||
### Swap on ZRAM
|
||||
|
||||
Anaconda and Fedora IoT have been using swap-on-zram by default for years. With Fedora 33, swap-on-zram will be enabled by default instead of a swap partition. Check out [the Fedora wiki page][10] for more details about swap-on-zram.
|
||||
|
||||
* * *
|
||||
|
||||
### Nano by default
|
||||
|
||||
Fresh Fedora 33 installations will set the EDITOR environment variable to [_nano_ by default][11]. This change affects several command line tools that spawn a text editor when they require user input. With earlier releases, this environment variable default was unspecified, leaving it up to the individual application to pick a default editor. Typically, applications would use _[vi][12]_ as their default editor due to it being a small application that is traditionally available on the base installation of most Unix/Linux operating systems. Since Fedora 33 includes nano in its base installation, and since nano is more intuitive for a beginning user to use, Fedora 33 will use nano by default. Users who want vi can, of course, override the value of the EDITOR variable in their own environment. See [the Fedora change request][11] for more details.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/whats-new-fedora-33-workstation/
|
||||
|
||||
作者:[Gregory Bartholomew][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/glb/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2020/10/f33workstation-816x345.jpg
|
||||
[2]: https://fedoramagazine.org/announcing-fedora-33/
|
||||
[3]: https://getfedora.org/workstation
|
||||
[4]: https://fedoramagazine.org/wp-content/uploads/2020/10/fedora-33-gnome-tour-1.png
|
||||
[5]: https://fedoramagazine.org/wp-content/uploads/2020/10/drag-to-reorder-1.gif
|
||||
[6]: https://help.gnome.org/misc/release-notes/3.38/
|
||||
[7]: https://fedoramagazine.org/btrfs-coming-to-fedora-33/
|
||||
[8]: https://en.wikipedia.org/wiki/Btrfs
|
||||
[9]: https://btrfs.wiki.kernel.org/index.php/Changelog#By_feature
|
||||
[10]: https://fedoraproject.org/wiki/Changes/SwapOnZRAM
|
||||
[11]: https://fedoraproject.org/wiki/Changes/UseNanoByDefault
|
||||
[12]: https://en.wikipedia.org/wiki/Vi
|
@ -0,0 +1,93 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Linux Kernel 5.10 Will be the Next LTS Release and it has Some Exciting Improvements Lined Up)
|
||||
[#]: via: (https://itsfoss.com/kernel-5-10/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
Linux Kernel 5.10 Will be the Next LTS Release and it has Some Exciting Improvements Lined Up
|
||||
======
|
||||
|
||||
_**Development for Linux Kernel 5.10 is in progress. It’s been confirmed to be a long term support release and it will be bringing newer hardware support among other promised features.**_
|
||||
|
||||
### Linux Kernel 5.10 will be Long Term Support Release
|
||||
|
||||
**Greg Kroah-Hartman**, the key stable kernel maintainer, addressed an “Ask the Expert” session at Linux Foundation’s Open-Source Summit Europe and confirmed that Linux 5.10 will be the next LTS release.
|
||||
|
||||
Even though there were some early speculations of 5.9 being the LTS release, Greg clarified that the last kernel release of the year will always be an LTS release.
|
||||
|
||||
As of now, [Linux Kernel 5.4][1] series happens to be the latest LTS version out there which added a lot of improvements and hardware support. Also, considering the development progress with Linux [Kernel 5.8][2] being the biggest release so far and Linux 5.10’s first release candidate being close to it, there’s a lot of things going on under the hood.
|
||||
|
||||
> Because people keep asking me… <https://t.co/cUcGoXEZtX>
|
||||
>
|
||||
> — Greg K-H (@gregkh) [October 26, 2020][3]
|
||||
|
||||
Let’s take a look at some of the features and improvements that you can expect with Linux Kernel 5.10.
|
||||
|
||||
### Linux kernel 5.10 features
|
||||
|
||||
![][4]
|
||||
|
||||
**Note:** _Linux Kernel 5.10 is still in early development. So, we will be updating the article regularly for the latest additions/feature updates._
|
||||
|
||||
#### AMD Zen 3 Processor Support
|
||||
|
||||
The new [Ryzen 5000][5] lineup is one of the biggest buzzes of 2020. So, with Linux Kernel 5.10 release candidate version, various additions are being made for Zen 3 processors.
|
||||
|
||||
#### Intel Rocket Lake Support
|
||||
|
||||
I do not hope for a lot with Intel’s Rocket Lake chipsets arriving Q1 next year (2021). But, considering that Intel’s constantly squeezing everything out of that 14 nm process, it is definitely a good thing to see work done for Intel Rocket Lake on Linux Kernel 5.10
|
||||
|
||||
#### Open Source Driver for Radeon RX 6000 series
|
||||
|
||||
Even though we’re covering this a day before the Big Navi reveal, the Radeon RX 6000 series is definitely going to be something impressive to compete with NVIDIA RTX 3000 series.
|
||||
|
||||
Of course, unless it suffers from the same issues the Vega series or the 5000 series met with.
|
||||
|
||||
It’s good to see work being already done for an open source driver to support the next-gen Radeon GPUs on Linux Kernel 5.10.
|
||||
|
||||
#### File System Optimizations and Storage Improvements
|
||||
|
||||
[Phoronix][6] reports on file-system optimizations and storage improvements with 5.10 as well. So, judging by that, we should see some performance improvements.
|
||||
|
||||
#### Other Improvements
|
||||
|
||||
Undoubtedly, you should expect a great deal of driver updates and hardware supports with the new kernel.
|
||||
|
||||
For now, the support for SoundBlaster AE-7, early support for NVIDIA Orin (AI processor), and Tiger Lake GPU improvements seem to be the key highlights.
|
||||
|
||||
A stable release for Linux Kernel 5.10 should be expected around the mid-December timeline. It will be supported for at least 2 years but you could end up with security/bug fix updates till 2026. So, we will have to stay tuned to the development for anything exciting on the next Linux Kernel 5.10 LTS release.
|
||||
|
||||
**Recommended Read:**
|
||||
|
||||
![][7]
|
||||
|
||||
#### [Explained! Why Your Distribution Still Using an ‘Outdated’ Linux Kernel?][8]
|
||||
|
||||
A new stable kernel is released every 2-3 months yet your distribution might still be using an old, outdated Linux kernel. But you don’t need to worry and here’s why!
|
||||
|
||||
What do you think about the upcoming Linux Kernel 5.10 release? Let us know your thoughts in the comments.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/kernel-5-10/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/linux-kernel-5-4/
|
||||
[2]: https://itsfoss.com/kernel-5-8-release/
|
||||
[3]: https://twitter.com/gregkh/status/1320745076566433793?ref_src=twsrc%5Etfw
|
||||
[4]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/10/kernel-5-10-release.png?resize=800%2C450&ssl=1
|
||||
[5]: https://www.tomsguide.com/news/amd-ryzen-5000-revealed-what-it-means-for-pc-gaming
|
||||
[6]: https://www.phoronix.com/scan.php?page=article&item=linux-510-features&num=1
|
||||
[7]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2019/12/why_Linux_distro_use_outdated_kernel.jpg?fit=800%2C450&ssl=1
|
||||
[8]: https://itsfoss.com/why-distros-use-old-kernel/
|
@ -0,0 +1,211 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to Install Ubuntu Server on a Raspberry Pi)
|
||||
[#]: via: (https://itsfoss.com/install-ubuntu-server-raspberry-pi/)
|
||||
[#]: author: (Dimitrios Savvopoulos https://itsfoss.com/author/dimitrios/)
|
||||
|
||||
如何在树莓派上安装 Ubuntu 服务器?
|
||||
======
|
||||
|
||||
[树莓派][1]是最著名的[单板计算机][2]。最初,树莓派项目的范围是针对促进学校和发展中国家的计算机基础科学教学。
|
||||
|
||||
它的低成本、便携性和极低的功耗,使得它的受欢迎程度远远超过预期。从气象站到家庭自动化,玩家们用树莓派搭建了许多[酷炫的项目][3]。
|
||||
|
||||
[第四代树莓派][4]具备了普通台式电脑的功能和处理能力。但本文并不是要介绍如何使用树莓派作为桌面。相反,我会告诉你如何在树莓派上安装 Ubuntu 服务器。
|
||||
|
||||
在本教程中,我将使用树莓派 4,以下是我将介绍的内容:
|
||||
|
||||
* 在 microSD 卡上安装 Ubuntu 服务器
|
||||
* 在树莓派上设置无线网络连接
|
||||
* 通过 SSH 访问你的树莓派
|
||||
|
||||
|
||||
|
||||
![][5]
|
||||
|
||||
**本教程需要以下东西**:
|
||||
|
||||
* 一张 micro SD 卡(建议使用 8GB 或更大的卡)
|
||||
* 一台带有 micro SD 卡读卡器的计算机(运行 Linux、Windows 或 macOS)
|
||||
* 树莓派 2、3 或 4
|
||||
* 良好的互联网连接
|
||||
* 用于树莓派 2 和 3 的 HDMI 线和用于树莓派 4的 micro HDMI 线(可选)
|
||||
* 一套 USB 键盘(可选)
|
||||
|
||||
|
||||
|
||||
### 在树莓派上安装 Ubuntu 服务器
|
||||
|
||||
![][6]
|
||||
|
||||
在本教程中,我使用 Ubuntu 来创建树莓派 SD 卡,但你可以在其他 Linux 发行版、macOS 和 Windows 上创建它。这是因为准备 SD 卡的步骤对 Raspberry Pi Imager 工具而言是一样的。
|
||||
|
||||
Raspberry Pi Imager 工具会自动下载你[选择树莓派系统][7]的镜像。这意味着你需要一个良好的网络连接来下载 1GB 左右的数据。
|
||||
|
||||
#### 步骤 1:用 Raspberry Pi Imager 准备 SD 卡
|
||||
|
||||
确保你已将 microSD 卡插入电脑,并在电脑上安装 Raspberry Pi Imager。
|
||||
|
||||
你可以从这些链接中下载适合你操作系统的 Imager 工具:
|
||||
|
||||
* [用于 Ubuntu/Debian 的 Raspberry Pi Imager][8]
|
||||
* [用于 Windows 的 Raspberry Pi Imager][9]
|
||||
* [用于 MacOS 的 Raspberry Pi Imager][10]
|
||||
|
||||
|
||||
|
||||
|
||||
尽管我使用的是 Ubuntu,但我不会使用上面列出的 Debian 软件包,而是使用命令行安装 snap 包。这个方法可以适用于更广泛的 Linux 发行版。
|
||||
|
||||
```
|
||||
sudo snap install rpi-imager
|
||||
```
|
||||
|
||||
安装好 Raspberry Pi Imager 工具后,找到并打开它,点击 ”CHOOSE OS“ 菜单。
|
||||
|
||||
![][11]
|
||||
|
||||
滚动菜单并点击 ”Ubuntu“ (核心和服务器镜像)。
|
||||
|
||||
![][12]
|
||||
|
||||
从可用的镜像中,我选择了 Ubuntu 20.04 LTS 64 位。如果你有一个树莓派 2,那你只能选择 32 位镜像。
|
||||
|
||||
**重要提示:如果你使用的是最新的树莓派 4 - 8 GB 内存型号,你应该选择 64 位操作系统,否则只能使用 4 GB 内存。**
|
||||
|
||||
![][13]
|
||||
|
||||
从 “SD Card” 菜单中选择你的 microSD 卡,然后点击 ”WRITE“。
|
||||
|
||||
![][14]
|
||||
|
||||
如果它显示一些错误,请尝试再次写入它。现在它将下载 Ubuntu 服务器镜像并将其写入 micro SD 卡。
|
||||
|
||||
当这个过程完成时,它将通知你。
|
||||
|
||||
![][15]
|
||||
|
||||
#### 步骤 2:在 Ubuntu 服务器上添加 WiFi 支持
|
||||
|
||||
烧录完 micro SD 卡后,你就差不多可以使用它了。在使用它之前,有一件事情你可能想做,那就是添加 Wi-Fi 支持。
|
||||
|
||||
SD 卡仍然插入读卡器中,打开文件管理器,找到卡上的 ”system-boot” 分区。
|
||||
|
||||
你要找的和需要编辑的文件名为 `network-config`。
|
||||
|
||||
![][16]
|
||||
|
||||
这个过程也可以在 Windows 和 MacOS 上完成。如前所述,编辑 **`network-config`** 文件,添加你的 Wi-Fi 凭证。
|
||||
|
||||
首先,取消矩形框内的行的注释(删除开头的标签 “#”),然后将 myhomewifi 替换为你的 Wi-Fi 网络名称。
|
||||
|
||||
之后,将 myhomewifi 替换为你的 Wi-Fi 网络名,用引号括起来,比如 ”itsfoss“,将 ”S3kr1t“ 替换为 Wi-Fi 密码,用引号括起来,比如 ”12345679“。
|
||||
|
||||
![][17]
|
||||
|
||||
它可能看上去像这样:
|
||||
|
||||
```
|
||||
wifis:
|
||||
wlan0:
|
||||
dhcp4: true
|
||||
optional: true
|
||||
access-points:
|
||||
"your wifi name":
|
||||
password: "your_wifi_password"
|
||||
```
|
||||
|
||||
保存文件并将 micro SD 卡插入到你的树莓派中。在第一次启动时,如果你的树莓派无法连接到 Wi-Fi 网络,只需重启你的设备。
|
||||
|
||||
#### 步骤 3:在树莓派上使用 Ubuntu 服务器(如果你有专门的显示器、键盘和鼠标的话)
|
||||
|
||||
如果你有一套额外的鼠标,键盘和显示器,你可以很容易地像其他电脑一样使用树莓派(但没有 GUI)。
|
||||
|
||||
只需将 micro SD 卡插入树莓派,连接显示器、键盘和鼠标。现在[打开你的树莓派][18]。它将出现 TTY 登录屏幕(黑色终端屏幕)并询问用户名和密码。
|
||||
|
||||
* 默认用户名:ubuntu
|
||||
* 默认密码:ubuntu
|
||||
|
||||
|
||||
|
||||
看到提示时,用 “**ubuntu**” 作为密码。登录成功后,[Ubuntu 会要求你更改默认密码][19]。
|
||||
|
||||
享受你的 Ubuntu 服务器吧!
|
||||
|
||||
#### 步骤 3:通过 SSH 远程连接到你的树莓派(如果你没有树莓派的显示器、键盘和鼠标的话)
|
||||
|
||||
如果你没有专门的显示器与树莓派一起使用也没关系。当你可以直接通过 SSH 进入它并按照你的方式使用它时,谁还需要一个带有显示器的服务器呢?
|
||||
|
||||
**在 Ubuntu 和 Mac OS**上,通常已经安装了一个 SSH 客户端。要远程连接到你的树莓派,你需要发现它的 IP 地址。检查[连接到你的网络的设备][20],看看哪个是树莓派。
|
||||
|
||||
由于我没有 Windows 机器,你可以访问[微软][21]提供的综合指南。
|
||||
|
||||
打开终端,运行以下命令:
|
||||
|
||||
```
|
||||
ssh [email protected]_pi_ip_address
|
||||
```
|
||||
|
||||
你可能会看到以下信息确认连接:
|
||||
|
||||
```
|
||||
Are you sure you want to continue connecting (yes/no/[fingerprint])?
|
||||
```
|
||||
|
||||
输入 ”yes“,然后点击回车键。
|
||||
|
||||
![][22]
|
||||
|
||||
当提示时,用前面提到的 ”ubuntu“ 作为密码。当然,你会被要求更改密码。
|
||||
|
||||
完成后,你将自动注销,你必须使用新密码重新连接。
|
||||
|
||||
你的 Ubuntu 服务器就可以在树莓派上运行了!
|
||||
|
||||
**总结**
|
||||
|
||||
在树莓派上安装 Ubuntu 服务器是一个简单的过程,而且它的预配置程度很高,使用起来很愉快。
|
||||
|
||||
我不得不说,在所有[我在树莓派上尝试的操作系统][7]中,Ubuntu 服务器是最容易安装的。我并没有夸大其词。请查看我的[在树莓派上安装 Arch Linux][23]的指南,以供参考。
|
||||
|
||||
希望这篇指南也能帮助你在树莓派上安装 Ubuntu 服务器。如果你有问题或建议,请在评论区告诉我。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/install-ubuntu-server-raspberry-pi/
|
||||
|
||||
作者:[Dimitrios Savvopoulos][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/dimitrios/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.raspberrypi.org/
|
||||
[2]: https://itsfoss.com/raspberry-pi-alternatives/
|
||||
[3]: https://itsfoss.com/raspberry-pi-projects/
|
||||
[4]: https://itsfoss.com/raspberry-pi-4/
|
||||
[5]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/09/Ubuntu-Server-20.04.1-LTS-aarch64.png?resize=800%2C600&ssl=1
|
||||
[6]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/ubuntu-server-raspberry-pi.png?resize=800%2C450&ssl=1
|
||||
[7]: https://itsfoss.com/raspberry-pi-os/
|
||||
[8]: https://downloads.raspberrypi.org/imager/imager_amd64.deb
|
||||
[9]: https://downloads.raspberrypi.org/imager/imager.exe
|
||||
[10]: https://downloads.raspberrypi.org/imager/imager.dmg
|
||||
[11]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/raspberry-pi-imager.png?resize=800%2C600&ssl=1
|
||||
[12]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/raspberry-pi-imager-choose-ubuntu.png?resize=800%2C600&ssl=1
|
||||
[13]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/raspberry-pi-imager-ubuntu-server.png?resize=800%2C600&ssl=1
|
||||
[14]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/raspberry-pi-imager-sd-card.png?resize=800%2C600&ssl=1
|
||||
[15]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/ubuntu-server-installed-raspberry-pi.png?resize=799%2C506&ssl=1
|
||||
[16]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/ubuntu-server-pi-network-config.png?resize=800%2C565&ssl=1
|
||||
[17]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/Ubuntu-server-wifi.png?resize=800%2C600&ssl=1
|
||||
[18]: https://itsfoss.com/turn-on-raspberry-pi/
|
||||
[19]: https://itsfoss.com/change-password-ubuntu/
|
||||
[20]: https://itsfoss.com/how-to-find-what-devices-are-connected-to-network-in-ubuntu/
|
||||
[21]: https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse
|
||||
[22]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/ubuntu-server-change-password.png?resize=800%2C600&ssl=1
|
||||
[23]: https://itsfoss.com/install-arch-raspberry-pi/
|
117
translated/tech/20201026 ninja- a simple way to do builds.md
Normal file
117
translated/tech/20201026 ninja- a simple way to do builds.md
Normal file
@ -0,0 +1,117 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (ninja: a simple way to do builds)
|
||||
[#]: via: (https://jvns.ca/blog/2020/10/26/ninja--a-simple-way-to-do-builds/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
ninja:一个简单的构建方式
|
||||
======
|
||||
|
||||
大家好!每隔一段时间,我就会发现一款我非常喜欢的新软件,今天我想说说我最近喜欢的一款软件:[ninja][1]!
|
||||
|
||||
### 增量构建很有用
|
||||
|
||||
我做了很多小项目,在这些项目中,我想设置增量构建。例如,现在我正在写一本关于 bash 的杂志,杂志的每一页都有一个 `.svg`文件。我需要将 SVG 转换为 PDF,我的做法是这样的:
|
||||
|
||||
```
|
||||
for i in *.svg
|
||||
do
|
||||
svg2pdf $i $i.pdf # or ${i/.svg/.pdf} if you want to get really fancy
|
||||
done
|
||||
```
|
||||
|
||||
这很好用,但是我的 `svg2pdf` 脚本有点慢(它使用 Inkscape),而且当我刚刚只更新了一页的时候,必须等待 90 秒或者其他什么时间来重建所有的 PDF 文件,这很烦人。
|
||||
|
||||
### 构建系统是让人困惑的
|
||||
|
||||
在过去,我对使用 make 或 bazel 这样的构建系统来做我的小项目一直很反感,因为 bazel 是个大而复杂的东西,而 `make` 对我来说感觉有点神秘。我真的不知道如何使用它们中的任何一个。
|
||||
|
||||
所以很长时间以来,我只是写了一个 bash 脚本或者其他的东西来进行构建,然后就认命了,有时候只能等一分钟。
|
||||
|
||||
### ninja 是一个非常简单的构建系统
|
||||
|
||||
但 ninja 并不复杂!以下是我所知道的关于 ninja 构建文件的语法:如何创建一个 `rule `和一个 `build`:
|
||||
|
||||
`rule` 有一个命令和描述(描述只是给人看的,所以你可以知道它在构建你的代码时在做什么)。
|
||||
|
||||
```
|
||||
rule svg2pdf
|
||||
command = inkscape $in --export-text-to-path --export-pdf=$out
|
||||
description = svg2pdf $in $out
|
||||
```
|
||||
|
||||
`build` 的语法是 `build output_file: rule_name input_files`。下面是一个使用 `svg2pdf` 规则的例子。输出在规则中的 `$out` 里,输入在 `$in` 里。
|
||||
|
||||
```
|
||||
build pdfs/variables.pdf: svg2pdf variables.svg
|
||||
```
|
||||
|
||||
这就完成了!如果你把这两个东西放在一个叫 `build.ninja` 的文件里,然后运行 `ninja`,ninja 会运行 `inkscape variables.svg --export-text-to-path --export-pdf=pdfs/variables.pdf`。然后如果你再次运行它,它不会运行任何东西(因为它可以告诉你已经构建了 `pdfs/variables.pdf`,而且是最新的)。
|
||||
|
||||
Ninja 还有一些更多的功能(见[手册][2]),但我还没有用过。它最初是[为 Chromium][3] 构建的,所以即使只有一个小的功能集,它也能支持大型构建。
|
||||
|
||||
### ninja 文件通常是自动生成的
|
||||
|
||||
ninja 的神奇之处在于,你不必使用一些混乱的构建语言,它们很难记住(比如 make),因为你不经常使用它,相反,ninja 语言超级简单,如果你想做一些复杂的事情,那么你只需使用任意编程语言生成你想要的构建文件。
|
||||
|
||||
我喜欢写一个 `build.py` 文件,或者像这样的文件,创建 ninja 的构建文件,然后运行 `ninja`:
|
||||
|
||||
```
|
||||
with open('build.ninja', 'w') as ninja_file:
|
||||
# write some rules
|
||||
ninja_file.write("""
|
||||
rule svg2pdf
|
||||
command = inkscape $in --export-text-to-path --export-pdf=$out
|
||||
description = svg2pdf $in $out
|
||||
""")
|
||||
|
||||
# some for loop with every file I need to build
|
||||
for filename in things_to_convert:
|
||||
ninja_file.write(f"""
|
||||
build {filename.replace('svg', 'pdf')}: svg2pdf {filename}
|
||||
""")
|
||||
|
||||
# run ninja
|
||||
import subprocess
|
||||
subprocess.check_call(['ninja'])
|
||||
```
|
||||
|
||||
我相信有一堆 ninja 的最佳实践,但我不知道。对于我的小项目而言,我发现它很好用。
|
||||
|
||||
### meson 是一个生成 ninja 文件的构建系统
|
||||
|
||||
我对 [Meson][4] 还不太了解,但最近我在构建一个 C 程序 ([plocate][5],一个比 `locate` 更快的替代方案)时,我注意到它有不同的构建说明,而不是通常的 `./configure; make; make install`:
|
||||
|
||||
```
|
||||
meson builddir
|
||||
cd builddir
|
||||
ninja
|
||||
```
|
||||
|
||||
好像 Meson 是一个 C/C++/Java/Rust/Fortran 的构建系统,可以用 ninja 作为后端。
|
||||
|
||||
### 就是这些!
|
||||
|
||||
我使用 ninja 已经有几个月了。我真的很喜欢它,而且它几乎没有给我带来让人头疼的构建问题,这让我感觉非常神奇。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2020/10/26/ninja--a-simple-way-to-do-builds/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://ninja-build.org/
|
||||
[2]: https://ninja-build.org/manual.html
|
||||
[3]: http://neugierig.org/software/chromium/notes/2011/02/ninja.html
|
||||
[4]: https://mesonbuild.com/Tutorial.html
|
||||
[5]: https://blog.sesse.net/blog/tech/2020-09-28-00-37_introducing_plocate
|
Loading…
Reference in New Issue
Block a user