5

我需要在 Yocto 构建的目标操作系统上运行脚本。

该脚本需要作为安装的一部分运行,因此只能运行一次(在整个操作系统安装后或首次启动时)。它不能在主机系统上运行,因为它依赖于仅存在于目标上的硬件 IO。

另一个较小的限制是 rootfs 以只读方式安装,但我想可以通过将脚本重新安装为 rw 并在执行后再次重新安装为 r 或类似这些行的东西来避免这种情况。

任何帮助表示赞赏。

4

5 回答 5

13

我最终做了shibley写的事情。以下是详细的操作方法:

创建一个新层

将所需的图层放在其他图层所在的任何位置。我的在stuff目录中,在构建目录旁边。

创建以下文件/目录:

meta_mylayer
├── conf
│   └── layer.conf
└── recipes-core
    └── mylayer-initscript
        ├── initscript.bb
        └── files
            ├── initscript.service
            └── initscript.sh

meta_mylayer是新图层的名称。

让我们在其中定义层conf/layer.conf并告诉它在哪里搜索食谱:

BBPATH .= ":${LAYERDIR}"
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb ${LAYERDIR}/recipes-*/*/*.bbappend"
BBFILE_COLLECTIONS += "meta-mylayer"
BBFILE_PATTERN_meta-mylayer := "^${LAYERDIR}/"
BBFILE_PRIORITY_meta-mylayer = "99"

配方由 .bb 文件的名称定义。这一层只有一个配方,名为initscript

initscript.bb包含配方信息。以下配方将添加我们的 initscript 服务并将实际的安装脚本initscript.sh, 放入/usr/sbin/

SUMMARY = "Initial boot script"
DESCRIPTION = "Script to do any first boot init, started as a systemd service which removes itself once finished"
LICENSE = "CLOSED"
PR = "r3"

SRC_URI =  " \
    file://initscript.sh \
    file://initscript.service \
"

do_compile () {
}

do_install () {
    install -d ${D}/${sbindir}
    install -m 0755 ${WORKDIR}/initscript.sh ${D}/${sbindir}

    install -d ${D}${systemd_unitdir}/system/
    install -m 0644 ${WORKDIR}/initscript.service ${D}${systemd_unitdir}/system
}

NATIVE_SYSTEMD_SUPPORT = "1"
SYSTEMD_PACKAGES = "${PN}"
SYSTEMD_SERVICE_${PN} = "initscript.service"

inherit allarch systemd

install -d将创建指定路径所需的任何目录,同时install -m 0644将复制具有 644 权限的指定文件。${D}是目标目录,默认是${WORKDIR}/image

创建 systemd 服务定义

我不会详细介绍 systemd 的工作原理,而是粘贴服务定义:

[Unit]
Description=start initscript upon first boot

[Service]
Type=simple
ExecStart=/bin/sh -c 'sleep 5 ; /usr/sbin/initscript.sh'

请注意脚本的位置- 这是我们上面函数/usr/sbin/的最后一行将复制的位置。do_install

最后,我们的initscript.sh脚本本身:

#!/bin/sh

logger "starting initscript"

# do some work here. Mount rootfs as rw if needed.

logger "initscript work done"

#job done, remove it from systemd services
systemctl disable initscript.service

logger "initscript disabled"

注册图层

我们需要注册我们的新层,以便 bitbake 知道它的存在。编辑build/conf/bblayers.conf文件并将以下行添加到BASELAYERS变量中:

  ${TOPDIR}/../stuff/meta-mylayer \

现在 bitbake 识别了我们的层,我们需要将我们的食谱添加到图像中。编辑build/conf/local.conf并将 initscript 配方添加到IMAGE_INSTALL_append变量中。这是添加到 python 旁边时的样子。

IMAGE_INSTALL_append = " python initscript"

运行构建

像往常一样运行构建。例如:

bitbake angstrom-lxde-image

首次安装构建并启动后,您的initscript.sh将被执行。

于 2016-11-14T21:02:42.780 回答
2

基本方法是编写一个 systemd 服务。该服务可以默认启用,如 yocto recipe systemd 配置中定义的那样。服务调用的脚本或应用程序将在脚本/应用程序完成时禁用服务 - 即。systemctl disable foo. 因此,该服务将不会在以后的引导中运行。

正如您所提到的,rootfs 需要安装为 rw 才能正常工作。

于 2016-11-04T23:10:03.140 回答
1

谢谢,这有帮助。我需要添加

[Install] WantedBy=multi-user.target

到 initscript.service 让它工作

于 2017-12-22T00:34:58.197 回答
0

一个简单的解决方案是使用包发布/安装脚本,该脚本在 rootfs 时间停止自身运行(如果设置了 $D,则退出 1)。这将导致它在第一次启动时运行。是的,脚本需要重新挂载根 fs。

于 2016-11-06T10:00:36.413 回答
0

另外,我不知道如何解决rootfs被挂载为只读的问题,你可以使用pkg_postinst_ontarget_${PN}

将此添加到您的食谱之一:

pkg_postinst_ontarget_${PN}() {
    #!/bin/bash
    // bash script you want to run
    echo Post Install Script Test > /dev/ttyS1
}

${PN}将替换为配方对应的包名称。
该脚本将仅在目标计算机上首次启动时作为软件包的安装后脚本运行一次。

于 2020-12-28T14:30:33.737 回答