LXR | KVM | PM | Time | Interrupt | Systems Performance | Bootup Optimization

OpenWRT(4):启动流程以及添加自己的服务

OpenWRT的启动流程主要如下:

  • 启动/init脚本,挂载tmpfs,并切换到/sbin/init运行。
  • 启动/sbin/init,然后依次启动/etc/preinit和/sbin/procd。
    • 如需要在/sbin/procd之前处理工作,需要在/lib/preinit按序号添加脚本。
  • /sbin/procd根据/etc/inittab执行,包括/etc/rc.d中的启动脚本。
    • 在/etc/init.d中按照规则添加启动脚本,启动守护进程。

总体执行顺序如下:

1 /init启动脚本

 init启动脚本并没有直接启动系统,而是做了一些准备工作,然后调用/sbin/init启动OpenWRT系统:

  • 创建/new_root,并关在一个tmpfs文件系统到其上。
  • 将当前文件系统内容拷贝到/new_root里面。
  • 切换到/new_root作为新的rootfs,并且启动里面的/sbin/init程序作为init进程。
#!/bin/sh
# Copyright (C) 2006 OpenWrt.org
export INITRAMFS=1

# switch to tmpfs to allow run daemons in jail on initramfs boot
DIRS=$(echo *)
NEW_ROOT=/new_root

mkdir -p $NEW_ROOT
mount -t tmpfs tmpfs $NEW_ROOT

cp -pr $DIRS $NEW_ROOT

exec switch_root $NEW_ROOT /sbin/init

2 /sbin/init启动进程

OpenWRT的init进程来自于procd软件包:

  • 初始化日志。
  • 挂载文件系统、创建节点文件、创建目录等。
  • 启动kmodloader加载内核module。
  • 通过procd启动hotplug功能。
  • 执行/etc/preinit脚本。
  • 执行procd,替换当前init进程。
main
  ulog_open--用于初始化日志系统的函数。用于设置日志记录的目标和日志级别。
  early--检查pid必须为1,否则返回。
    early_mounts--mount proc/sysfs/tmpfs等文件系统,创建一些目录或者文件。
      early_dev
      early_console
    early_env--设置PATH变量。
  cmdline--解析命令行中是否存在init_debug,并根据这个值配置debug等级。
  /sbin/kmodloader--启动kmodloader加载/etc/modules-boot.d/里面的module。
  waitpid--循环等待kmodloader结束。
  uloop_init--用于初始化事件循环的函数。负责处理定时器、信号、socket 事件等。
  preinit
    execvp--启动/sbin/procd启动一个hotplug程序,配置文件为/etc/hotplug-preinit.json。
    uloop_process_add--用于将一个进程添加到uloop的管理中。确保在调用uloop_process_add之前,子进程已经创建,并且pid已经设置为子进程的实际PID。
    execvp--执行/etc/preinit脚本。
    uloop_process_add--执行完的uloop回调函数为spawn_procd。
      spawn_procd--退出/etc/preinit之后,执行procd替换init
  uloop_run--用于启动事件循环的函数。一旦调用这个函数,事件循环就会开始运行,处理注册的事件,直到接收到退出信号或发生错误。

3 kmodloader

kmodloader是一个在 Linux 系统中用于加载和卸载内核模块的工具。内核模块是动态加载到 Linux 内核中的代码,它们可以扩展内核的功能。

kmod 命令是kmodloader的一部分,它提供了一些用于管理内核模块的实用功能。

kmodloader还实现了insmod/lsmod/rmmod/modinfo/modprobe功能:

/sbin/insmod -> /sbin/kmodloader
/sbin/kmodloader
/sbin/lsmod -> /sbin/kmodloader
/sbin/modinfo -> /sbin/kmodloader
/sbin/modprobe -> /sbin/kmodloader
/sbin/rmmod -> /sbin/kmodloader

其代码执行流程如下:

main
  main_insmod
  main_rmmod
  main_lsmod
  main_modinfo
  main_modprobe
  main_loader--以上命令之外,kmodloader对应的路径。
    scan_module_folders--遍历/etc/modules.d目录下的模块名称。
      init_module_folders
      scan_module_folder
    scan_loaded_modules
    find_module
    load_modprobe
      insert_module
        __NR_init_module--系统调用加载内核模块。

两次调用kmodeloader的地方分别是:

  • /sbin/init中启动kmodeloader加载/etc/modules-boot.d/中指定的模块。
  • 在procd中调用/etc/rc.d脚本/etc/rc.d/S10boot中执行/sbin/kmodloader,默认加载/etc/modules.d中指定模块。

4 /etc/preinit

/etc/preinit在执行/sbin/procd之前做一些准备工作:

  • source一些脚本,获取函数定义。
    • boot_hook_init:函数用于初始化一个新的启动钩子。这个函数接收一个参数,即钩子的名称,然后设置一个环境变量来存储与该钩子相关的函数列表。
    • boot_hook_add:函数用于向已初始化的钩子添加函数。这个函数接收两个参数:钩子的名称和要添加的函数名称。
    • boot_run_hook:函数用于执行与特定钩子关联的所有函数。
  • 遍历/lib/preinit中preinit脚本,添加hook。
  • 依次执行preinit_essential和preinit_main两个hook。

/etc/preinit调用 boot_hook_init来初始化一系列钩子;/etc/preinit按序号依次执行/lib/preinit中的脚本调用boot_hook_add来向该钩子添加需要执行的函数;/etc/preinit调用boot_run_hook 来执行所有已添加到该钩子preinit_essential和preinit_main的函数。

#!/bin/sh
# Copyright (C) 2006-2016 OpenWrt.org
# Copyright (C) 2010 Vertical Communications
[ -z "$PREINIT" ] && exec /sbin/init
export PATH="%PATH%"

. /lib/functions.sh
. /lib/functions/preinit.sh
. /lib/functions/system.sh

boot_hook_init preinit_essential
boot_hook_init preinit_main
boot_hook_init failsafe
boot_hook_init initramfs
boot_hook_init preinit_mount_root

for pi_source_file in /lib/preinit/*; do
    . $pi_source_file
done

boot_run_hook preinit_essential

pi_mount_skip_next=false
pi_jffs2_mount_success=false
pi_failsafe_net_message=false

boot_run_hook preinit_main

 /lib/preinit的配置和脚本包括:

lib/preinit/
├── 00_preinit.conf
├── 02_default_set_state
├── 02_sysinfo
├── 10_indicate_failsafe
├── 10_indicate_preinit
├── 30_failsafe_wait
├── 40_run_failsafe_hook
├── 50_indicate_regular_preinit
├── 70_initramfs_test
├── 80_mount_root
├── 81_urandom_seed
├── 99_10_failsafe_dropbear
├── 99_10_failsafe_login
└── 99_10_run_init

以添加一个preinit_main hook函数为例:

define_default_set_state() {
    . /etc/diag.sh
}

boot_hook_add preinit_main define_default_set_state

其中define_default_set_state()脚本函数会在/etc/preinit执行期间被调用到。

5 /sbin/procd

更多参考:《[OpenWrt Wiki] Procd system init and daemon management》、《[OpenWrt Wiki] Init Scripts》、《[OpenWrt Wiki] procd init scripts》。

5.1 procd启动流程

/sbin/procd被/sbin/init启动,并处理如下工作:

  • 初始化日志。
  • 注册信号处理函数。
  • 依次进入如下四种状态:
    • STATE_EARLY:处理coldplug和hotplug。
    • STATE_UBUS:启动ubus服务。
    • STATE_INIT:处理inittab中respawn/askconsole/askfirst/sysinit等action。
    • STATE_RUNNING:处理inittab中respawnlate/askconsolelate等action。
main
  hotplug_run---h选项时调用,rulles参数为/etc/hotplug-preinit.json。
  ulog_open
  uloop_init
  procd_signal
  procd_state_next
    state_enter
      STATE_EARLY
        hotplug--根据/etc/hotplug.json定义的规则处理热插拔事件。
          --打开PF_NETLINK域的NETLINK_KOBJECT_UEVENT协议socket,并循环读取内容。
            hotplug_handler--热插拔时间处理函数。
              recv--从socket读取uevent内容。
              json_script_run--执行热插拔相关脚本。
        procd_coldplug
          execvp--启动udevtrigger进程。
          uloop_process_add--udevtrigger结束后回调函数udevtrigger_complete。
            udevtrigger_complete
              hotplug_last_event--启动一个uloop定时器,超时执行回调函数coldplug_complete。
                coldplug_complete
                  hotplug_last_event--参数为NULL,停止定时器。
                  procd_state_next
      STATE_UBUS
        procd_connect_ubus
          timeout_retry--启动ubus_timer。
            ubus_connect_cb--
        service_start_early--启动ubusd守护进程此后可以提供ubus IPC服务。          
      STATE_INIT
        procd_inittab--解析/etc/inittab。
        procd_inittab_run--依次执行inittab中的respawn/askconsole/askfirst/sysinit。
          rcrespawn
          askconsole
          askfirst
          runrc--sysinit action对应的操作函数。
            rcS
              runqueue_init--初始化一个运行队列。
              _rc--遍历/etc/rc.d目录下所有启动脚本。
                add_initd
                  runqueue_task_add--将一个init脚本加入到运行队列,执行函数为q_initd_run。
                    q_initd_run--创建一个进程执行脚本,并将脚本输出通过pipe中定向到procd进行处理。
                      pipe_cb--procd读取并处理/etc/rc.d中脚本执行生成的日志。
            rcdone
              procd_state_next
      STATE_RUNNING
        procd_inittab_run--执行inittab的respawnlate/askconsolelate。
      STATE_SHUTDOWN
        procd_inittab_run--执行inittab的shutdown。
      STATE_HALT
        signal-发送SIGTERM、SIGKILL关闭进程。
  uloop_run
  uloop_done

5.2 hotplug配置文件

/etc/hotplug-preinit.json定义了add FIRMWARE热插拔行为:

[
    [ "case", "ACTION", {
        "add": [
            [ "if",
                [ "has", "FIRMWARE" ],
                [
                    [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ],
                    [ "load-firmware", "/lib/firmware" ],
                    [ "return" ]
                ]
            ]
        ]
    } ],
    [ "if",
        [ "eq", "SUBSYSTEM", "button" ],
        [ "exec", "/etc/rc.button/failsafe" ]
    ]
]

/etc/hotplug.json定义了add/remove等热插拔行为:

[
    [ "case", "ACTION", {
        "add": [
            [ "if",
                [ "and",
                    [ "has", "MAJOR" ],
                    [ "has", "MINOR" ]
                ],
                [
                    [ "if",
                        [ "eq", "DEVNAME", "null" ],
                        [
                            [ "makedev", "/dev/%DEVNAME%", "0666" ],
                            [ "exec", "/bin/ln", "-s", "/proc/self/fd/0", "/dev/stdin" ],
                            [ "exec", "/bin/ln", "-s", "/proc/self/fd/1", "/dev/stdout" ],
                            [ "exec", "/bin/ln", "-s", "/proc/self/fd/2", "/dev/stderr" ],
                            [ "return" ]
                        ]
                    ],
...
                ]
            ],
            [ "if",
                [ "has", "FIRMWARE" ],
                [
                    [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ],
                    [ "load-firmware", "/lib/firmware" ],
                    [ "return" ]
                ]
            ],
            [ "if",
                [ "regex", "DEVNAME", "^ttyGS" ],
                [ "start-console", "%DEVNAME%" ]
            ]
        ],
        "remove" : [
            [ "if",
                [ "and",
                    [ "has", "DEVNAME" ],
                    [ "has", "MAJOR" ],
                    [ "has", "MINOR" ]
                ],
                [ "rm", "/dev/%DEVNAME%" ]
            ]
        ]
    } ],
    [ "if",
        [ "and",
            [ "has", "BUTTON" ],
            [ "eq", "SUBSYSTEM", "button" ]
        ],
        [ "button", "/etc/rc.button/%BUTTON%" ]
    ],
    [ "if",
        [ "and",
            [ "eq", "SUBSYSTEM", "usb-serial" ],
            [ "regex", "DEVNAME",
                [ "^ttyUSB", "^ttyACM" ]
            ]
        ],
        [ "exec", "/sbin/hotplug-call", "tty" ],
        [ "if",
            [ "isdir", "/etc/hotplug.d/%SUBSYSTEM%" ],
            [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ]
        ]
    ]
]

5.3 procd配置文件/etc/inittab

/etc/inittab定义了procd不同action操作:

::sysinit:/etc/init.d/rcS S boot
::shutdown:/etc/init.d/rcS K shutdown--sysinit和shutdown都调用/etc/rc.d中的启动脚本。
ttyAMA0::askfirst:/usr/libexec/login.sh
ttyS0::askfirst:/usr/libexec/login.sh
hvc0::askfirst:/usr/libexec/login.sh

5.4 /etc/init.d到/etc/rc.d转换

在include/rootfs.mk中,执行prepare_rootfs会在/etc/rc.d目录中生成/etc/init.d目录中脚本的链接:

define prepare_rootfs
    $(if $(2),@if [ -d '$(2)' ]; then \
        $(call file_copy,$(2)/.,$(1)); \
    fi)
    @mkdir -p $(1)/etc/rc.d
    @mkdir -p $(1)/var/lock
    @( \
        cd $(1); \
...
        for script in ./etc/init.d/*; do \
            grep '#!/bin/sh /etc/rc.common' $$script >/dev/null || continue; \
            if ! echo " $(3) " | grep -q " $$(basename $$script) "; then \
                IPKG_INSTROOT=$(1) $$(command -v bash) ./etc/rc.common $$script enable; \
                echo "Enabling" $$(basename $$script); \
            else \
                IPKG_INSTROOT=$(1) $$(command -v bash) ./etc/rc.common $$script disable; \
                echo "Disabling" $$(basename $$script); \
            fi; \
        done || true \
    )
...
endef

在/etc/rc.comm中生成链接文件:

disable() {
    name="$(basename "${initscript}")"
    rm -f "$IPKG_INSTROOT"/etc/rc.d/S??$name
    rm -f "$IPKG_INSTROOT"/etc/rc.d/K??$name
}

enable() {
    err=1
    name="$(basename "${initscript}")"
    [ "$START" ] && \
        ln -sf "../init.d/$name" "$IPKG_INSTROOT/etc/rc.d/S${START}${name##S[0-9][0-9]}" && \
        err=0
    [ "$STOP" ] && \
        ln -sf "../init.d/$name" "$IPKG_INSTROOT/etc/rc.d/K${STOP}${name##K[0-9][0-9]}" && \
        err=0
    return $err
}

START=和STOP=行确定了这个脚本在sysinit初始化中何时被执行。在启动时,procd只是开始执行它在/etc/rc.d中找到的脚本,根据它们的文件名顺序来执行。初始化脚本可以作为符号链接放置在这里,链接到 /etc/init.d/ 中的 init.d 脚本。使用 enable 和 disable 命令,这个过程是/etc/rc.comm中处理完成的。在这种情况下:

START=10 - 这意味着文件将作为符号链接 /etc/rc.d/S10example - 换句话说,它将在 START=9 及以下的初始化脚本之后启动,但在 START=11 及以上之前。

STOP=15 - 这意味着文件将作为符号链接 /etc/rc.d/K15example - 这意味着它将在 STOP=14 及以下的初始化脚本之后停止,但在 STOP=16 及以上之前。这是可选的。

如果多个初始化脚本具有相同的启动值,调用顺序将由初始化脚本名称的字母顺序决定。

不要忘记确保脚本具有执行权限,通过运行chmod +x /etc/init.d/example。

START和STOP值应该在 1-99 范围内,因为它们是按字母顺序运行的,这意味着100会在10之后执行。

OpenWrt 将在构建期间在宿主系统上运行初始化脚本(当前使用动作 “enable” 或 “disable”),并且它必须正确处理这个特殊情况,避免不必要的副作用。

5.5 创建启动脚本实例

创建package/base-files/files/etc/init.d/example如下:

#!/bin/sh /etc/rc.common

START=88
STOP=88
USE_PROCD=1

start() {        
    echo "start(): $@"
    # commands to launch application
}                 
 
stop() {          
    echo "stop(): $@"
    # commands to kill application 
}

boot() {
    echo "boot(): $@"
}

shutdown() {
    # The service is finished, so turn off the hardware
    stop
    echo "shutdown(): $@"
}

EXTRA_COMMANDS="custom1 custom2 custom3"
EXTRA_HELP=<<EOF
        custom1 Help for the custom1 command
        custom2 Help for the custom2 command
        custom3 Help for the custom3 command
EOF
 
custom1 () {
        echo "custom1"
        # do the stuff for custom1
}
custom2 () {
        echo "custom2"
        # do the stuff for custom2
}
custom3 () {
        echo "custom3"
        # do the stuff for custom3
}

5.6 显示启动日志

q_initd_run运行inittab启动脚本:

static void q_initd_run(struct runqueue *q, struct runqueue_task *t)
{
    struct initd *s = container_of(t, struct initd, proc.task);
    int pipefd[2];
    pid_t pid;

    clock_gettime(CLOCK_MONOTONIC_RAW, &s->ts_start);
    DEBUG(2, "start %s %s \n", s->file, s->param);
    if (pipe(pipefd) == -1) {--创建pipe。
        ERROR("Failed to create pipe: %m\n");
        return;
    }

    pid = fork();--创建一个新进程。
    if (pid < 0)
        return;

    if (pid) {
        close(pipefd[1]);
        fcntl(pipefd[0], F_SETFD, FD_CLOEXEC);--父进程关闭pipe[1],通过pipefd[0]接收子进程发送的消息。
        s->fd.stream.string_data = true,
        s->fd.stream.notify_read = pipe_cb,
        runqueue_process_add(q, &s->proc, pid);
        ustream_fd_init(&s->fd, pipefd[0]);
        return;
    }
    close(pipefd[0]);--子进程关闭pipe[0]。

    int devnull = open("/dev/null", O_RDONLY);
    dup2(devnull, STDIN_FILENO);--子进程输入指向/dev/null,即关闭输入。
    dup2(pipefd[1], STDOUT_FILENO);--子进程输出指向pipe[1],通过pipe输出给父进程。
    dup2(pipefd[1], STDERR_FILENO);--子进程错误指向pipe[1],通过pipe输出给父进程。

    if (devnull > STDERR_FILENO)
        close(devnull);

    printf("arnoldlu %s: %s %s\n", __func__, s->file, s->param);
    execlp(s->file, s->file, s->param, NULL);
    exit(1);
}

父进程在pipe_cb中处理通过pipe接收的消息:

static void pipe_cb(struct ustream *s, int bytes)
{
    struct initd *initd = container_of(s, struct initd, fd.stream);
    char *newline, *str;
    int len;

    do {
        str = ustream_get_read_buf(s, NULL);
        if (!str)
            break;
        newline = strchr(str, '\n');
        if (!newline)
            break;
        *newline = 0;
        len = newline + 1 - str;
        ULOG_NOTE("%s: %s", initd->file, str);
#ifdef SHOW_BOOT_ON_CONSOLE--打开这个宏,可以显示子进程通过pipe发送过来的消息。
        fprintf(stderr, "%s: %s\n", "arnoldlu", str);
#endif
        ustream_consume(s, len);
    } while (1);
}

6 udevtrigger

udevtrigger是一个与 udev(用户空间的设备管理器)相关的命令行工具,它用于触发 udev 系统去处理设备相关的事件。

具体来说,udevtrigger扫描 sysfs 文件系统,生成相应的硬件设备 hotplug 事件,这些事件随后由procd处理,以创建或移除相应的设备节点

在系统启动时,udevtrigger执行 coldplug 操作,这个过程会检测到系统上所有已经存在的硬件设备,并通过 sysfs 内核虚拟文件系统获取这些设备的相关信息。然后,udevtrigger根据这些信息生成 hotplug 事件,procd再读取这些事件并生成对应的硬件设备文件。

main
  scan_subdir--依次扫描/sys/bus、/sys/class、/sys/block目录。
    device_list_insert
      trigger_uevent--往设备的uevent写add,出发uevent事件。procd在接收到uevent事件后,根据hotplug.json定义的热插拔行进行处理。

7 启动实例

以uhttpd启动脚本为例,在package/network/services/uhttpd/Makefile中:

define Package/uhttpd/install
    $(INSTALL_DIR) $(1)/etc/init.d
    $(INSTALL_BIN) ./files/uhttpd.init $(1)/etc/init.d/uhttpd--inittab对应的启动脚本。
    $(INSTALL_DIR) $(1)/etc/config
    $(INSTALL_CONF) ./files/uhttpd.config $(1)/etc/config/uhttpd--uhttpd配置文件。
    $(VERSION_SED_SCRIPT) $(1)/etc/config/uhttpd
    $(INSTALL_DIR) $(1)/usr/sbin
    $(INSTALL_BIN) $(PKG_BUILD_DIR)/uhttpd $(1)/usr/sbin/uhttpd--uhttpd守护进程。
endef

在uhttpd.init中启动uhttpd守护进程:

start_service() {
    config_load uhttpd
    config_foreach start_instance uhttpd
}

start_instance()
{
    UHTTPD_CERT=""
    UHTTPD_KEY=""

    local cfg="$1"
    local realm="$(uci_get system.@system[0].hostname)"
    local listen http https interpreter indexes path handler httpdconf haveauth
    local enabled

    config_get_bool enabled "$cfg" 'enabled' 1
    [ $enabled -gt 0 ] || return

    procd_open_instance
    procd_set_param respawn
    procd_set_param stderr 1
    procd_set_param command "$UHTTPD_BIN" -f

    config_get config "$cfg" config
    if [ -z "$config" ]; then
        mkdir -p /var/etc/uhttpd
        httpdconf="/var/etc/uhttpd/httpd.${cfg}.conf"
        rm -f ${httpdconf}
        config_list_foreach "$cfg" httpauth create_httpauth
        if [ "$haveauth" = "1" ]; then
            procd_append_param command -c ${httpdconf}--启动uhttpd守护进程。
            [ -r /etc/httpd.conf ] && cat /etc/httpd.conf >>/var/etc/uhttpd/httpd.${cfg}.conf
        fi
    fi
...
    procd_close_instance
}

最终启动结果如下:

UID        PID  PPID CMD
root         2     0 [kthreadd]
root        11     2   [rcu_sched]
root        10     2   [ksoftirqd/0]
root        12     2   [migration/0]
root         7     2   [kworker/u4:0-events_unbound]
root         6     2   [kworker/0:0H-events_highpri]
root         8     2   [mm_percpu_wq]
root         4     2   [rcu_par_gp]
root         3     2   [rcu_gp]
root         5     2   [kworker/0:0-events]
root         9     2   [rcu_tasks_trace]
root        17     2   [kworker/1:0-events]
root        16     2   [ksoftirqd/1]
root        18     2   [kworker/1:0H-events_highpri]
root        13     2   [cpuhp/0]
root        14     2   [cpuhp/1]
root        15     2   [migration/1]
root        19     2   [netns]
root        20     2   [kworker/u4:1-events_power_efficient]
root        37     2   [kworker/1:1-events]
root        35     2   [kworker/0:1-events]
root       171     2   [kworker/u4:2-events_unbound]
root       205     2   [oom_reaper]
root       206     2   [writeback]
root       208     2   [kcompactd0]
root       232     2   [blkcg_punt_bio]
root       222     2   [cryptd]
root       218     2   [pencrypt_serial]
root       220     2   [pdecrypt_serial]
root       230     2   [kblockd]
root       261     2   [kworker/0:1H]
root       311     2   [kswapd0]
root       318     2   [kthrotld]
root       400     2   [kworker/1:1H-kblockd]
root       399     2   [ipv6_addrconf]
root       593     2   [kworker/1:2-rcu_gp]
root         1     0 /sbin/procd
ubus       501     1   /sbin/ubusd
root       502     1   /bin/ash --login
root      2683   502     ps -AFH
root       534     1   /sbin/urngd
root       735     1   /usr/sbin/uhttpd -f -h /www -r OpenWrt -x /cgi-bin -l /cgi-bin/luci -L /usr/lib/lua/luci/sgi/uhttpd.lua -u /ubus -t 60 -T 30 -k 20 -A 1 -n 3 -N 100 -R -p 0.0.0.0:80 -p [::]:80 -C /etc/uhttpd.crt -K /etc/uhttpd.key -s 0.0.0.0:443 -s [:
logd       976     1   /sbin/logd -S 64
root      1031     1   /sbin/rpcd -s /var/run/ubus/ubus.sock -t 30
root      1249     1   /usr/sbin/dropbear -F -P /var/run/dropbear.1.pid -p 22 -K 300 -T 3
root      1370     1   /sbin/netifd
root      1432     1   /usr/sbin/odhcpd
root      2115     1   /sbin/ujail -t 5 -n ntpd -U ntp -G ntp -C /etc/capabilities/ntpd.json -c -u -r /bin/ubus -r /usr/bin/env -r /usr/bin/jshn -r /usr/sbin/ntpd-hotplug -r /usr/share/libubox/jshn.sh -- /usr/sbin/ntpd -n -N -S /usr/sbin/ntpd-hotplug -p 0.o
ntp       2123  2115     /usr/sbin/ntpd -n -N -S /usr/sbin/ntpd-hotplug -p 0.openwrt.pool.ntp.org -p 1.openwrt.pool.ntp.org -p 2.openwrt.pool.ntp.org -p 3.openwrt.pool.ntp.org
root      2206     1   /sbin/ujail -t 5 -n dnsmasq -u -l -r /bin/ubus -r /etc/TZ -r /etc/dnsmasq.conf -r /etc/ethers -r /etc/group -r /etc/hosts -r /etc/passwd -w /tmp/dhcp.leases -r /tmp/dnsmasq.d -r /tmp/hosts -r /tmp/resolv.conf.d -r /usr/bin/jshn -r /us
dnsmasq   2212  2206     /usr/sbin/dnsmasq -C /var/etc/dnsmasq.conf.cfg01411c -k -x /var/run/dnsmasq/dnsmasq.cfg01411c.pid

 

posted on 2024-07-24 23:59  ArnoldLu  阅读(842)  评论(2编辑  收藏  举报

导航