网站首页 全球最实用的IT互联网站!

人工智能P2P分享Wind搜索发布信息网站地图标签大全

当前位置:诺佳网 > 电子/半导体 > 嵌入式技术 >

【技术分享】正确编写SysV Init脚本以实现Systemd兼

时间:2025-10-28 11:45

人气:

作者:admin

标签:

导读:嵌入式的ubuntu系统如何写好SysVInit脚本呢?与system服务又有什么差别呢?一起随着文章来探究吧。问题背景许多传统Linux服务仍使用SysVInit脚本(/etc/init.d/),但在Systemd系统中,这些脚本...


嵌入式的ubuntu系统如何写好SysV Init脚本呢?与system服务又有什么差别呢?一起随着文章来探究吧。


79a40b4e-b3b0-11f0-8ce9-92fbcf53809c.jpg  问题背景

许多传统Linux服务仍使用SysV Init脚本(/etc/init.d/),但在Systemd系统中,这些脚本需通过systemd-sysv-generator换为原生服务单元。若脚本未遵循Linux Standard Base (LSB)规范,会导致以下问题:

  1. 服务启动/停止有误:缺失关键命令(如status)或错误退出码。
  2. 依赖混乱:未声明依赖关系,导致服务启动顺序错误。
  3. 日志污染:输出未重定向,干扰Systemd日志(journald)。


79a40b4e-b3b0-11f0-8ce9-92fbcf53809c.jpg  SysV Init脚本规范指南

1. 必须支持的标准命令脚本需实现以下命令:

1.case"$1"in2.start)3.# 启动服务逻辑4.;;5.stop)6.# 停止服务逻辑7.;;8.restart)9.# 建议直接调用自身stop再start,或委托给Systemd10.$0stop11.$0start12.;;13.status)14.# 返回服务运行状态(必需!)15.ifpidof -x"$DAEMON">/dev/null;then16.echo"Service is running"17.exit018.else19.echo"Service is stopped"20.exit3# LSB规范:未运行状态码21.fi22.;;23.*)24.echo"Usage:$0{start|stop|restart|status}"25.exit1esac

2. LSB头部注释(必需)在脚本开头添加元数据:

1.### BEGIN INIT INFO2.# Provides: my_service3.# Required-Start: $network $syslog4.# Required-Stop: $network $syslog5.# Default-Start: 23456.# Default-Stop: 0167.# Short-Description: My Custom Service8.# Description: This service does something magical.

  • Provides:服务名称,需唯一。
  • Required-Start/Stop:定义依赖的其他服务或设施如($network表示网络就绪)。

3. 正确退出状态码退出码含义

  • 0 成功
  • 1 泛型错误
  • 2 无效命令参数
  • 3 服务未运行(status命令专用)
  • 4 权限不足

退出码含义0成功1泛型错误2无效命令参数3服务未运行(status命令专用)4权限不足4. 避免破坏Systemd的特性Systemd 是一个进程生命周期管理器,它需要直接跟踪服务的主进程(PID)。如果服务脚本不遵循规范,会导致Systemd无法正确管理服务状态(如判断是否运行、自动重启等)。4.1 禁止后台化进程4.1.1 错误写法

# 传统SysV脚本中常见的后台化方式/usr/bin/my_daemon --config /etc/my.conf &

4.1.2 问题

  • Systemd 会启动脚本,但脚本中的 & 会让 /usr/bin/my_daemon 在后台运行。
  • Systemd 只能监控到脚本自身(即Shell进程)的状态,而无法追踪真正的服务进程(my_daemon)。
  • 当Shell脚本执行完毕后,Systemd 会认为服务已退出,导致服务状态显示为 inactive (dead),即使my_daemon仍在运行。

4.1.3 正确写法

# 使用 exec 替换当前进程(Shell脚本进程被替换为服务进程)exec/usr/bin/my_daemon --config /etc/my.conf

4.1.4 原理

  • exec命令会让当前Shell进程直接被替换为my_daemon进程。
  • Systemd 可以追踪到 my_daemon 的PID,从而正确管理服务状态。

4.2 日志输出规范4.2.1错误写法

# 直接输出到控制台或文件echo"Starting service..."> /dev/console/usr/bin/my_daemon >> /var/log/my_service.log2>&1

4.2.2 问题

  • Systemd 默认通过 journald 集中管理日志,直接写入文件会导致日志分散,难以查询。
  • 若服务崩溃,Systemd 可能无法捕获崩溃前的最后日志。

4.2.3 原理

  • Systemd 会自动捕获服务的stdout/stderr 并写入 journald。
  • 可通过journalctl -u my_service 查看完整日志,无需手动管理日志文件。

5. 注册服务依赖SysV脚本需通过 LSB头部注释 声明依赖关系,帮助Systemd理解服务启动顺序和条件。这是SysV与Systemd兼容的关键!5.1 LSB头部详解

### BEGIN INIT INFO#Provides: my_service# 服务名称(唯一标识)#Required-Start:$network$syslog# 依赖的服务或系统设施#Required-Stop:$network$syslog# 停止时的依赖#Default-Start: 2345# 启用服务的运行级别#Default-Stop: 016# 禁用服务的运行级别#Short-Description: My Service# 简短描述#Description: Long description here.### END INIT INFO

5.1.1 关键字段Required-Start 服务启动前必须就绪的依赖项,例如:

  • $network 等待网络就绪;
  • $syslog 等待日志系统就绪;
  • nginx 等待$network服务启动;
  • docker.socket 等待Docker套接字就绪;
  • Default-Start/Default-Stop 定义服务在哪些运行级别自动启动或停止;
  • 2 3 4 5 多用户模式(无图形界面或图形界面);
  • 0 1 6 关机、单用户模式、重启。

5.2 依赖注册命令5.2.1 目的将LSB头部中的依赖关系转换为系统实际的启动链接(符号链接到 /etc/rcX.d/ 目录)。

Debian/Ubuntu:# 生成依赖链接 sudoupdate-rc.d my_service defaults
# 移除依赖链接sudoupdate-rc.d my_service remove

5.3 依赖不注册的后果假设 my_service 依赖网络,但未声明 $network:

  • SysV场景:服务可能在网络未就绪时启动,导致连接失败。
  • Systemd场景:systemd-sysv-generator 无法生成正确的依赖关系,服务可能并行启动,引发竞态条件。

79bde8c0-b3b0-11f0-8ce9-92fbcf53809c.png6. 总结

  • 避免后台化 → 让Systemd直接跟踪主进程。
  • 规范日志输出 → 信任Systemd的日志管理能力。
  • 声明依赖 → 通过LSB头部告诉Systemd“谁先谁后”。
  • 注册服务 → 确保依赖关系生效,服务按预期启动。
  • SysV脚本的“四不像”问题本质是 对Systemd机制的不理解。遵循上述规范,可最大限度兼容Systemd,同时为未来迁移到原生Systemd服务铺平道路。


79a40b4e-b3b0-11f0-8ce9-92fbcf53809c.jpg  创建并启用 SysV Init 脚本的完整流程

1. 创建 SysV Init 脚本的位置SysV Init 脚本必须放置在 /etc/init.d 目录下,这是所有 SysV 风格服务脚本的标准位置。Systemd 的兼容层(systemd-sysv-generator)会自动扫描此目录,将符合规范的脚本转换为 Systemd 服务单元。

2. 创建脚本的步骤

2.1 创建脚本文件使用文本编辑器(如 nano)在/etc/init.d/下创建脚本文件:

sudo nano/etc/init.d/my_service

2.2 编写脚本内容粘贴以下模板(需根据实际服务修改):

#!/bin/bash### BEGIN INIT INFO# Provides: my_service# Required-Start: $network $syslog# Required-Stop: $network $syslog# Default-Start: 2345# Default-Stop: 016# Short-Description: My Custom Service# Description: This service does something important.### END INIT INFO
# 服务主程序路径DAEMON="/usr/bin/my_daemon"NAME="my_service"
case"$1"instart)echo"Starting$NAME"exec$DAEMON;;stop)echo"Stopping$NAME"killall -9$DAEMON;;restart)$0stop$0start;;status)ifpidof -x"$DAEMON">/dev/null;thenecho"$NAMEis running"exit0elseecho"$NAMEis stopped"exit3fi;;*)echo"Usage:$0{start|stop|restart|status}"exit1esac
exit0

3. 启用服务的两种方式3.1 传统 SysV 方法(兼容 Systemd)

# Debian/Ubuntusudoupdate-rc.d my_service defaults

3.2 Systemd 原生方法(推荐)

# 直接通过 Systemd 启用(等效于 update-rc.d)sudo systemctlenablemy_serviceSystemd 会自动生成符号链接:Created symlink /etc/systemd/system/multi-user.target.wants/my_service.service → /lib/systemd/system/my_service.service.

4. 验证脚本兼容性4.1 检查 LSB 头部合规性

# Debian/Ubuntusudoinsserv -n my_service

输出应无错误,显示依赖关系已解析。4.2 查看 Systemd 生成的单元文件

# 查看生成的 .service 文件systemctl cat my_service输出示例:# /run/systemd/generator.late/my_service.service# Automatically generated by systemd-sysv-generator
[Unit]Documentation=man:systemd-sysv-generator(8)SourcePath=/etc/init.d/my_serviceDescription=My Custom ServiceAfter=network.target syslog.target
[Service]Type=forkingRestart=noTimeoutSec=5minIgnoreSIGPIPE=noKillMode=processGuessMainPID=noRemainAfterExit=yesExecStart=/etc/init.d/my_service startExecStop=/etc/init.d/my_service stopExecReload=/etc/init.d/my_service restart

5. 管理服务

# 启动服务sudosystemctl start my_service

# 查看状态systemctlstatus my_service

# 停止服务sudosystemctl stop my_service

# 重启服务sudosystemctl restart my_service

6. 关键注意事项6.1 避免冲突配置如果服务已存在 Systemd 原生单元文件(如/lib/systemd/system/my_service.service),需删除或禁用它,否则 SysV 脚本可能被忽略。6.2 禁用传统服务干扰停止并禁用旧版networking服务(如果存在):

systemctl stop networkingsudo systemctldisablenetworking

6.3 日志输出规范确保服务进程的日志输出到 stdout/stderr,而非直接写入文件。Systemd 会通过 journalctl 捕获日志:

journalctl-u my_service -f

7. 总结步骤命令/操作目的创建脚本sudo nano /etc/init.d/my_service定义服务行为赋予执行权限sudo chmod +x /etc/init.d/my_service确保脚本可执行启用服务sudo systemctl enable my_service设置开机自启验证 Systemd 兼容性systemctl cat my_service检查自动生成的单元文件管理服务生命周期systemctl start/stop/restart my_service控制服务运行状态通过遵循上述步骤,您可以在 Systemd 系统中安全地使用 SysV Init 脚本,同时享受 Systemd 的监控和管理功能。但长期来看,仍建议迁移到原生 Systemd 服务单元(.service 文件),以充分利用资源控制、依赖管理和自动重启等高级特性。
79d0d8d6-b3b0-11f0-8ce9-92fbcf53809c.jpg  EM系列储能边缘智能网关

EM系列储能边缘智能网关是ZLG致远电子专为新能源储能系统设计的一款高性能、多接口通讯管理设备,可在储能系统应用中作为边缘EMS(能源管理系统)总控、通讯管理机、规约转换器或BAU(电池管理总控)使用。该系列产品集成丰富的外设接口,支持各类BMS、PCS、空调、电表、屏显等设备的通讯传输,且软件上支持RT-Linux、Ubuntu等操作系统,支持IEC-61850/IEC-104/EtherCAT等专用协议,可广泛满足各类储能系统的本地能源管理应用需求。

温馨提示:以上内容整理于网络,仅供参考,如果对您有帮助,留下您的阅读感言吧!
相关阅读
本类排行
相关标签
本类推荐

CPU | 内存 | 硬盘 | 显卡 | 显示器 | 主板 | 电源 | 键鼠 | 网站地图

Copyright © 2025-2035 诺佳网 版权所有 备案号:赣ICP备2025066733号
本站资料均来源互联网收集整理,作品版权归作者所有,如果侵犯了您的版权,请跟我们联系。

关注微信