添加服务及修改coreelec固件
本文目的是如何在一个coreelec(一个 LibreELEC系统的s90x芯片系列的分支)中根据linux-
systemd.service
服务启动原理,添加NPC内网穿透模块自启动服务的过程。
System unit简介
Systemd 是一个基于 unit
的概念来进行启动和监督整个操作系统、是 Linux 下一个与 SysV 和 LSB 初始化脚本兼容的系统和服务管理器。unit
是由一个与配置文件对应的名字和类型组成的(例如:avahi.service unit 有一个具有相同名字的配置文件,是守护进程 Avahi 的一个封装单元)。unit 有以下几种类型:
wuhu.service
:守护进程的启动、停止、重启和重载是此类 unit 中最为明显的几个类型。wuhu.socket
:此类 unit 封装系统和互联网中的一个 socket 。当下,systemd 支持流式、数据报和连续包的 AF_INET、AF_INET6、AF_UNIX socket 。也支持传统的 FIFOs 传输模式。每一个 socket unit 都有一个相应的服务 unit 。相应的服务在第一个“连接”进入 socket 或 FIFO 时就会启动(例如:nscd.socket 在有新连接后便启动 nscd.service)。wuhu.device
:此类 unit 封装一个存在于 Linux 设备树中的设备。每一个使用 udev 规则标记的设备都将会在 systemd 中作为一个设备 unit 出现。udev 的属性设置可以作为配置设备 unit 依赖关系的配置源。wuhu.mount
:此类 unit 封装系统结构层次中的一个挂载点。wuhu.automount
:此类 unit 封装系统结构层次中的一个自挂载点。每一个自挂载 unit 对应一个已挂载的挂载 unit (需要在自挂载目录可以存取的情况下尽早挂载)。wuhu.target
:此类 unit 为其他 unit 进行逻辑分组。它们本身实际上并不做什么,只是引用其他 unit 而已。这样便可以对 unit 做一个统一的控制。(例如:multi-user.target 相当于在传统使用 SysV 的系统中运行级别5);bluetooth.target 只有在蓝牙适配器可用的情况下才调用与蓝牙相关的服务,如:bluetooth 守护进程、obex 守护进程等)wuhu.snapshot
:与 target unit 相似,快照本身不做什么,唯一的目的就是引用其他 unit 。
-点击查看详细介绍
配置服务文件: systemd.service
kodi.bin 官方文档
linux系统启动的systemd.service过程图
那如何优美地添加一个漂亮的systemd服务呢?总共分三步走:
- 准备大象 :贴出我的NPC.service参考:
[Unit]
Description=Stop kodi and start NPC 描述部分
After=kodi.target 在kode.target后启动
[Service]
Type=simple 表明只启动ExecStart为主进程
ExecStart=/usr/bin/bash /storage/NPC_main.sh start 需要启动的命令、程序、脚本
ExecReload=/usr/bin/bash /storage/NPC_main.sh restart 重新启动的命令、程序、脚本
ExecStop=/usr/bin/kill -TERM $MAINPID 接收到 stop 命令时执行
Restart=always 遇到意外关闭、超时都重启
RestartSec=2 重启间隔,默认是100ms,只给数字则默认为秒
StartLimitInterval=10 启动间隔
PrivateTmp=true 这个服务进程使用私有的tmp缓存
[Install]
WantedBy=multi-user.target 被这个.target需要,意思是它启动本Unit也启动,
下面有详细介绍
- 找到冰箱 放到systemd.service 的默认目录/
usr/lib/systemd/system
,也可能在/etc/systemd/system
。实在找不到可以使用systemctl status xxx
第一行的Loaded
一般就是目录
cp your.service /usr/lib/systemd/system/
coreelec系统可以放在`~/.config/system.d/` 或者打包进/flsah/SYSTEM
- 塞入大象 使用命令开启这个服务,并设置开机自启动
~$ systemctl daemon-reload //Systemd 将Unit 文件的内容写到缓存中,即加载新的.service
~$ systemctl enable yourservice //不需要.service后缀,除了激活服务,也置服务为开机启动
~$ systemctl start yourservice //开启服务
~$ systemctl status yourservice //查看服务运行状态
reboot
一下看看是否成功自启动和保活,不行的话就看看是不是文件没写对或者服务的启动顺序冲突了,因为优先级原因而被Systemd干掉了,使用命令~# journalctl
来查看启动日志以查明哪个服务冲突了,。
下面是对文件[Unit]
、[Service]
、[install]
部分的常用选项讲解:
systemd.service 官方英文原文档
systemd.service 翻译文档-译者:金步国
[Unit]部分: 配置服务的基础信息
【这个Unit】意思是正在编辑的这个your.service服务配置文件
Description=
:描述这个 Unit 文件的信息,在systemctl status xxx 的时候会列出来Documentation=
:指定服务的文档,可以是一个或多个文档的 URL 路径Requires=
:需要;设置此Unit单元所必须依赖的其他单元,列在其中的 Unit 会在这个服务启动时的同时被启动。并且,如果其中任意一个服务启动失败,这个服务也会被终止。Wants=
:弱化的 Requires ,当这个Unit启动时,会去启动列出的每个 Unit 单元,但并不关心这些单元启动是否成功。BindsTo
:绑定;强化的 Requires,而且如果这里列出的任意一个单元停止运行或者崩溃,那么也会连带导致该单元自身被停止。After=
,Before=
:强制指定单元之间的先后顺序。 如 foo.service 单元有 Before=bar.service 设置, 那么当两个单元都需要启动的时候, bar.service 会一直等到 foo.service 启动完毕之后再启动。 注意,停止顺序与启动顺序正好相反。PartOf
:某某的一部分;仅作用于单元的停止或重启。 其含义是,当停止或重启这里列出的某个单元时, 也会同时停止或重启该单元自身。 注意,这个依赖是单向的, 该单元自身的停止或重启并不影响这里列出的单元。OnFailure
:当这个Unit启动失败时,就会自动启动列出的每个单元Conflicts
:列出冲突而不能同时运行的单元。如果列出的单元中有已在运行的,这个Unit就不能启动。
[Service]部分:配置服务的启动和操作
【这个Unit】意思是正在编辑的这个your.service服务配置文件
EnvironmentFile=
:从给定的绝对路径的文件加载环境变量,常用来当作配置文件 .conf。在后续的ExecStart= 等可以直接 $XXX 引用。若有多个环境变量文件则需要分段添加而不是用空格分隔;加"-" 号代表忽略不存在的文件;行尾的反斜杠()将被视为续行符。ExecStartPre=
,ExecStartPost=
设置在执行 ExecStart= 之前/后执行的命令行。 语法规则与 ExecStart= 完全相同。 如果设置了多个命令行, 那么这些命令行将以其在单元文件中出现的顺序 依次执行。如果有“-“前缀,代表不关心启动失败还是成功,否则这些之前/后执行的命令行若失败,则这个Unit启动也失败”(failed)状态。ExecStart=
在启动该服务时需要执行的 命令行(命令+参数)。 有关命令行的更多细节, 可参见后文的"命令行"小节。除非 Type=oneshot ,否则必须且只能设置一个命令行。 仅在 Type=oneshot 的情况下,才可以设置任意个命令行(包括零个), 多个命令行既可以在同一个 ExecStart= 中设置,也可以通过设置多个 ExecStart= 来达到相同的效果。 如果设为一个空字符串,那么先前设置的所有命令行都将被清空。ExecStop=
可选的指令, 用于设置当该服务被要求停止时所执行的命令行。 语法规则与 ExecStart= 完全相同。 执行完此处设置的所有命令行之后,该服务将被视为已经停止, 此时,该服务所有剩余的进程将会根据 KillMode= 的设置被杀死(参见 systemd.kill(5))。 如果未设置此选项,那么当此服务被停止时, 该服务的所有进程都将会根据 KillSignal= 的设置被立即全部杀死。有一个特殊的环境变量$MAINPID
可用于表示主进程的PID 。ExecStopPost=
可选的指令, 用于设置在该服务停止之后(无论服务是否启动成功)无条件执行的命令行。 语法规则与 ExecStart= 完全相同。 有以下环境变量: $SERVICE_RESULT(服务的最终结果), $EXIT_CODE(服务主进程的退出码), $EXIT_STATUS(服务主进程的退出状态)。 详见 systemd.exec(5) 手册。Type=
设置进程的启动类型。必须设为 simple, exec, forking, oneshot, dbus, notify, idle 之一,默认和常用的值是Type=simple,代表此Unit的 ExecStart= 进程就是该Unit的主进程,并且 systemd 会认为在创建了该服务的主服务进程之后,该服务就已经启动完成。Type=forking常用来做守护进程。关于其他Type值的详情请浏览此段段末的手册。TimeoutStopSec=
设置这个Unit自身停止的超时时长。如果超时,那么该服务将会立即被 SIGTERM 信号强制关闭(参见 systemd.kill(5) 手册中的 KillMode= 选项)。 如果未指定时间单位,那么将视为以秒为单位。 设为 “infinity” 则表示永不超时。 默认值等于 DefaultTimeoutStopSec= 的值(参见 systemd-system.conf(5) 手册)。Restart=
当服务进程 正常退出、异常退出、被杀死、超时的时候, 是否重新启动该服务。 所谓"服务进程" 是指 Exec*= 中设置的进程。 当进程是由于 systemd 的正常操作(例如 systemctl stop|restart)而被停止时, 该服务不会被重新启动。 所谓"超时"可以是看门狗的"keep-alive ping"超时, 也可以是 systemctl start|reload|stop 操作超时。- 该值可以为no, on-success, on-failure, on-abnormal, on-watchdog, on-abort, always 之一。 no(默认值) 表示不会被重启。 always 表示会被无条件的重启。有关“异常退出”或者“正常退出”的情况,请参考本段段末的手册。
RestartSec=
设置在重启服务(Restart=)前暂停多长时间。 默认值是100毫秒(100ms)。 如果未指定时间单位,那么将视为以秒为单位。 例如设为"20"等价于设为"20s"。StartLimitIntervalSec=interval
,StartLimitBurst=burst=
设置单元的启动频率限制。 也就是该单元在 interval 时间内最多允许启动 burst 次。这俩的默认值都在systemd 配置文件(system.conf)中TimeoutStartSec=
设置该服务允许的最大启动时长。 如果进程未能在限定的时长内发出"启动完毕"的信号,那么该服务将被视为启动失败,并会被关闭。 如果未指定时间单位,那么将视为以秒为单位。 例如设为"20"等价于设为"20s"。 设为 “infinity” 则表示永不超时。 当 Type=oneshot 时, 默认值为 “infinity” (永不超时)。
-更多【Service】选项–译者:金步国
-【service】允许的环境变量参数
[Install]部分:systemctl enable
或disable
时才会启动/依赖
【这个Unit】意思是正在编辑的这个your.service服务配置文件
这一部分的内容只有在systemctl enable
或diasable
的时候才会启动
WantedBy=
,RequiredBy=
:在给出列表中的任意一个单元启动时,这个Unit都会被启动。每个单元间允许空格间隔,实际上是在列出的单元的 .wants/ 或 .requires/ 目录中创建一个指向该单元文件的软连接。 这相当于在它们的配置文件里添加了Wants=这个Unit
或Requires=这个Unit
选项。Also=
设置这个Unit的附属Unit服务, 可以设为一个空格分隔的单元列表。 表示当使用 systemctl enable 启用 或 systemctl disable 停用 此服务时, 也同时自动的启用或停用附属的服务。
修改coreelec固件 — Squashfs文件(非coreelec系统可不用)
NPS-内网穿透模块,【nps for server】, n【pc for client】,使用uname -a 获取系统芯片类型
systemctl
命令的简单使用方法如下[1]
启动服务: systemctl start xxx.service
关闭服务: systemctl stop xxx.service
重启服务: systemctl restart xxx.service
显示服务的状态: systemctl status xxx.service
在开机时启用服务: systemctl enable xxx.service
在开机时禁用服务: systemctl disable xxx.service
查看服务是否开机启动: systemctl is-enabled xxx.service
查看已启动的服务列表: systemctl list-unit-files|grep enabled
查看启动失败的服务列表: systemctl --failed
移除标记为丢失的 Unit 文件: systemctl reset-failed
squashfs文件简介:
squashfs是以linux 内核源码补丁的形式发布的文件系统。squashfs可以将整个文件系统或者某个单一的目录压缩在一起, 存放在某个嵌入式设备。在使用上类似一个可以直接用来mount挂载的“压缩”文件系统.。在诸如coreelec的嵌入式系统上,可能会使用squashfs文件来初始化为文件系统根目录/
,这就是“改固件”操作时所改动的固件。
- 整体操作流程是 【获取原固件】 – > 【解压】 – > 【添加需要的文件】 – > 【压缩】 – > 【替代原固件】
开始这节的操作之前,记得先下载squashfs文件的解压和压缩工具:
mksquashfs.1 命令的官方手册
unsquashfs.1 命令的官方手册
以上两个命令,每个版本支持的内容都不一样,使用-h
选项查看实际支持的操作
CoreELEC系统使用了squashfs
文件格式来保存它的根目录文件树/
,然后每次开机时就把它mount
到根目录使用。所以我们的改动要写入它的squashfs
文件,这样才能保证所有改动在开机时一起载入。在这张图中可以看到/flash/SYSTEM
就是coreelec加载的squashfs
文件格式下的根目录,它就是我们接下来要改动的对象:
【获取原固件】需要改动的根目录squashfs文件是/flash/SYSTEM
。首先去获取它
实际上我们不能直接在这个目录更改,~# df -h ./
后~# mount
看了一下,存放根目录squashfs文件的目录/flash
是个只读系统
【解压】cp复制/flash/SYSTEM
到可读写的~/
。然后使用命令解压 SYSTEM
这个文件:
~$ unsquashfs SYSTEM
【添加需要的文件】这里没有指定解压出来的文件夹名字,所以一般会在同目录下生成一个叫squashfs-root
的文件夹。里面就是coreelec启动时加载的根文件树,在里面添加自己的文件即可。本文这里添加的是NPC.service
服务Unit文件:
【压缩】添加完所需要的文件之后,就需要压缩成squashfs文件,为了兼容起见,压缩后生成的squashfs文件的压缩格式、块大小要一致,使用unsquashfs -s 原文件名
来查看
根据-h
帮助,我这里使用的压缩命令 (mksquashfs版本是4.5) 是
~$ mksquashfs squashfs-root/ SYSTEM_2 -b 524288 -comp lzo -Xalgorithm lzo1x_999 -Xcompression-level 9
压缩完成后,在当前目录下新建一个target文件夹,把上面压缩出来的SYSTEM
放进去,然后使用~# md5sum
命令进行md5摘要计算一下。这一步是看到了/flash
下面除了有SYSYTEM
文件之外还有个SYSTEM.md5
,所以也同步一下操作。为了方便后续替换原固件,生成的md5摘要算法文件SYSTEM.md5也放在/target
目录下:
~$ md5sum target/SYSTEM >> target/SYSTEM.md5
之所以为啥要放在target/
目录下,因为在md5sum校验原文件的时候,看到它加载的原文件的路径在target/下, 所以秉承旧制。
完成上述的压缩、md5摘要计算后,应该能得到如下两个文件,将它们~# scp file hostname@IP:/PATH
传输到Ubuntu。
然后在Ubuntu上将这两个文件放到共享文件夹,将之移动到windows系统上。插入带有coreelec的U盘,然后把上述得到的两个SYSTEM
、SYSTEM.md5
文件替换掉原文件(因为这两文件都是原根文件,所以原文件最好做一份备份,放在windows本地其他硬盘而不是U盘)
修改过后的两个SYSTEM
、SYSTEM.md5
文件替换掉原文件后,把coreelecU盘插入到x96mini盒子上桶av口,coreelec就可以从修改过的固件上面启动啦~
echo 输出彩色字符串:
这段是个人常用,但单独写个文章又感觉没必要,于是加的,方便查看_(:з」∠)_
- 模板:
echo -e "\e[xx;xxm 你的内容 \e[0m"
-
解析:
-e
是echo的转义字符意思。
\e[xxm
xx是数字选项,选择字体属性、颜色、背景色用的,对顺序没有要求 -
各类数字选项:
背景色:
黑色背景:40
红色背景:41
绿色背景:42
黄色背景:43
蓝色背景:44
洋红背景:45
青色背景:46
白色背景:47
字体颜色:
黑色字体:30
红色字体:31
绿色字体:32
黄色字体:33
蓝色字体:34
洋红字体:35
青色字体:36
白色字体:37
属性
0: OFF
1: 高亮显示
3: 斜体
4: 下划线
5: 闪烁
7: 反色显示
8: 不可见
9: 删除线
echo -e "\e[9;32m hello \e[0m" #绿色字体、删除线的hello
参考文章
systemctl 命令简单使用
systemd.service 及systemctl 命令的详细讲解
Squashfs文件系统 - 可直接mount挂载使用的“压缩文件树”