Create a sample procd init script

I'm trying to create a service running via "procd"

but I'm struggling to make the service always active,
with running after 600 seconds after the router boots

can someone help me out, thanks

the code is available here:

The service is currently running:

root@LTE5398-M904:~# service watchdog_mbim status
running

I don't really like (even though I wrote it) the part about waiting for the router to get past 600 seconds of uptime, is there a way to get something cleaner?

# for 600 sec from boot not exec nothing
while true; do
    if [ $(awk -F "." '{print $1}' /proc/uptime) -lt "600" ]; then
    sleep 1
    fi
done

Take a look at this code in adblock-lean which gets the uptime in seconds:

Example use (provided that you copy-paste the function and replace the call to reg_failure(), which is an internal adblock-lean function, with your own error reporting code):

get_uptime_s uptime_s
sleep_time=$((600-uptime_s))
case "$sleep_time" in
    -*|'') ;; # do nothing if sleep_time is negative or empty string
    *) sleep "$sleep_time"
esac

You could make the code more compact if you want to but this should work as-is.

1 Like

is there any option to instruct "procd" that allows the script to be executed after a certain time?

the example you gave me is really too complex for me I tried to insert it into my code and it works (it created a sleep of 456 seconds) and the script remained running, executing the lines following the code inserted.

But I would like to know if there is a better option ...

ps: I'm just of the opinion that the less code there is the fewer problems there might be ...

Not that I'm aware of, but I'm not really familiar with all procd intricacies and options. Anyway, for reference:

https://openwrt.org/docs/guide-developer/procd-init-scripts

This is not an "actionable" statement, i.e. it doesn't ask any specific questions or make any requests. You can rephrase it in various ways if you want to get help, for example:

  • what does this part of code do?
  • why is this part of code needed?

If you don't want to invest the time into learning but you want a ready-to-go solution then you already have it, as you noted:

This is a very reasonable approach, and as I wrote above: you can make the code more compact if you want to, but generally when doing programming, one doesn't expect other people to write the code for them. Asking questions and seeking advice is perfectly fine though (although be prepared that some of the answers will be "google X" or "read the manual for Y").

2 Likes

First of all, thanks for the support received.

Let me wait for other contributions if there is a possibility to start the service with a scheduled wait directly from "procd" if there is no such possibility, I thank you again for the support.

Thanks

It was the first thing I did looking for an option that allows you to intervene on the script call but maybe I didn't ask the search engine the right question.

Thanks again.

1 Like

P.s. the code you wrote could work as well if it included a break command. Without break, you have an infinite loop which will also start to consume lots of CPU cycles as soon as the if condition is not satisfied (so sleep will not be called).

While it would work with the above modification (simply adding an else break statement), it is not ideal in some additional ways, which is why I suggested the adblock-lean code as a replacement:

  • it creates an unnecessary loop. Generally, avoid loops when possible
  • it wakes up every second
  • it creates a subshell every second. Specifically, this: $() creates a subshell. Creating subshells is fairly slow and should be avoided when possible especially inside loops.
  • it calls a binary (awk) to remove a part of a string. Calling binaries is also fairly slow and should be avoided where a built-in shell command can achieve the same, especially so inside loops. Every POSIX- compliant shell has a built-in which can do this (see line 54 in the adblock-lean code)
1 Like

as i said i'm not a good programmer...

try to see if you like this one better (and thanks again)

You don't need to apologize. It's perfectly fine to be a beginner programmer. Every programmer started off as such.

I took a brief look at the code and here are some thoughts:

  • looks like you copy-pasted the function from adblock-lean and the example code I wrote verbatim. So there is not much for me to comment on in this part, except the fact that you did not replace the call to reg_failure() with your own code. If you try to run reg_failure in your shell, you will get an error because it's an internal adblock-lean function which is undefined outside of adblock-lean code. You can simply replace it with a logger command and then it will actually do something useful when reading and parsing the line from /proc/uptime fails. It should never fail, so most people writing scripts would not even include code handling this error. Which is not a good practice because generally, good code should handle errors even if it doesn't expect them to be likely.
  • if you like compact and tidy code, you can replace the 2 if statements in lines 69-80 with one case statement:
case "${LTEERROR}" in
    0)
        # handle 0 result
        ;;
    *)
        # handle all other results
esac
  • since you are running ifdown wan && ifup wan regardless of the value of ${LTEERROR}, I don't see why these commands should be inside your if ... fi statements. You could as well run them after handling the value of ${LTEERROR}.
  • the while true; do ... done loop doesn't have any break command, so execution will never reach the line exit 0

I assume from this:

esac || { reg_failure "Failed to get uptime from /proc/uptime."; eval "${1}"=0; return 1; }

to:

esac

should be enough...

the code part:

LTESTATUS=$(uqmi -m -d /dev/cdc-wdm0 -t 20000 --get-data-status)
LTEERROR=$?
LTEFIND=$(echo ${LTESTATUS} | grep "\"connected\"" | wc -l)

sorry but I didn't understand the command can fail reporting an error if the timeout is exceeded or it can fail because there is no connection so I prefer to have the two checks ...

It will be enough, unless reading from /proc/uptime fails for any reason, or an unexpected string is read. As I wrote above, this should generally never happen, but can I guarantee that this does not happen? No. Which is why there is error-handling code. If writing code which may silently misbehave is good enough for you then yes - removing error handling is totally fine.

Looks like you joined several sentences in one without any punctuation, so I can not understand what you are saying. Please try again and maybe use Google Translate if you have trouble expressing yourself in English. In general, these 2 code snippets are equivalent (they do they same thing) but the second one is tidier:

if [ $x -eq 0 ]; then
    do_a
fi
if [ $x -ne 0 ]; then
    do_b
fi
case "$x" in
    0)
        do_a
        ;;
    *)
        do_b
esac

use a procd service trigger. Search for 'procd_add_interface_trigger' in the main github openwrt package repo, there are tons of examples. The main idea is that your script gets triggered whenever your LTE interface comes up ...

2 Likes

In the meantime, thanks for your contribution, :grinning_face:

can I ask you what function does this numeric argument "1000" reported with the command "service watchdog_mbim info" (obviously I tried to search for documentation but I didn't find anything).

I attach the output of the command:

 service watchdog_mbim info
{ "name": "watchdog_mbim", "verbose": true }
{
        "watchdog_mbim": {
                "instances": {
                        "instance1": {
                                "running": true,
                                "pid": 11426,
                                "command": [
                                        "/root/watchdog_mbim",
                                        "--pidfile",
                                        "/var/run/watchdog_mbim.pid"
                                ],
                                "term_timeout": 5,
                                "respawn": {
                                        "threshold": 3600,
                                        "timeout": 5,
                                        "retry": 5
                                },
                                "pidfile": "/var/run/watchdog_mbim.pid"
                        }
                },
                "triggers": [
                        [
                                "interface.*.up",
                                [
                                        "if",
                                        [
                                                "eq",
                                                "interface",
                                                "wan"
                                        ],
                                        [
                                                "run_script",
                                                "/etc/init.d/watchdog",
                                                "reload"
                                        ]
                                ],
                                1000   # <---- What does this do?
                        ]
                ]
        }
}

1000 is the procd default, you can overrule this with the environment variable "PROCD_RELOAD_DELAY", see an example here:

2 Likes

I assume that this parameter is expressed in milliseconds

and that it does not allow me to avoid inserting an uptime control into the code if I want my script to remain running after 600 seconds from boot (for the first 600 seconds it must not do anything, then it must be relaunched every 20 seconds for example as per my code),

or I have misinterpreted its function which should be to establish a time in milliseconds from the "up" or "down" event of the interface

You don't need such control - just use the procd builtins:

During boot only the procd service (with triggers) will be registered but not executed. Whenever the script gets triggered by the LTE/WAN event the service will be executed. This is much more reliable and flexible than a hardcoded timeout.

2 Likes

the underlying problem is that sometimes the wan interface remains in a non-coherent state, no disconnection event is recorded, so to work around this problem I'm analyzing the alternatives, could you kindly give me a solution.

The first steps I took is to analyze if a disconnection event is detected by creating:

cat /etc/hotplug.d/iface/99-ifup-wan 
#!/bin/sh
#logger -t hotplug "/etc/hotplug.d/iface Device: ${DEVICE} / Action: ${ACTION} / Interface: ${INTERFACE}"

response no, no event is detected when there is a loss of connectivity (or maybe I did something wrong ... you know I don't know everything)

After that I switched to a crontab script (run every minute) and it works now I'm trying to use an init script and I'm trying to solve it so if you can help me I would be grateful.

or are you telling me to create appropriate sections in the init service for example:

suspend() {
	rc_procd start_service suspend
}

resume() {
	rc_procd start_service resume
}

Thanks anyway for all the information you are giving me...

ps: I apologize if the questions I ask are stupid or poorly phrased.

the logger statement is in comment, that can't work ...

1 Like

obviously I commented it after realizing that no event was recorded / emitted ...

in 24 hours I hope to be able to attach a report in the event that an unexpected disconnection occurs ...

I reactivated the events and disabled both the service created by me and any crontab regarding the connectivity check

currently I have this file:

cat /etc/hotplug.d/iface/99-ifup-wan

logger -t hotplug "/etc/hotplug.d/iface Device: ${DEVICE} / Action: ${ACTION} / Interface: ${INTERFACE}"

[ "$DEVICE" = "wwan0" -a  "$ACTION" = "ifup" -a "$INTERFACE" = "wan_4" ] && {
logger -t hotplug "iface wan_4 up detected... from /etc/hotplug.d/iface/ exec: /root/wan2_connect (For now it does nothing...)"
#sh -x /root/wan2_connect
}

[ "$DEVICE" = "wwan0" -a  "$ACTION" = "ifupdate" -a "$INTERFACE" = "wan" ] && {
logger -t hotplug "iface wan up detected... from /etc/hotplug.d/iface/ exec: /root/wan2_connect (For now it does nothing...)"
#sh -x /root/wan2_connect
}

and I proceeded to clean the logs.

cat clearlog

#!/bin/sh
dmesg -c
/etc/init.d/log restart
sleep 1
logger "exec: /root/clearlog $(date)"
root@LTE5398-M904:~# logread
Mon Apr 28 00:53:24 2025 user.notice root: exec: /root/clearlog Mon Apr 28 00:53:24 CEST 2025

cat /etc/crontabs/root

#min hour day month day-week command
#0-59 0-23 1-31 1-12 0-6(0=Sunday) exec

service

Usage: service <service> [command]
/etc/init.d/atd                    enabled         running
/etc/init.d/boot                   enabled         stopped
/etc/init.d/bootcount              enabled         stopped
/etc/init.d/cron                   enabled         running
/etc/init.d/dnsmasq                enabled         running
/etc/init.d/done                   enabled         stopped
/etc/init.d/dropbear               enabled         running
/etc/init.d/firewall               enabled         stopped
/etc/init.d/fstab                  enabled         stopped
/etc/init.d/gpio_switch            enabled         stopped
/etc/init.d/https-dns-proxy        enabled         running
/etc/init.d/ksmbd                 disabled         stopped
/etc/init.d/led                    enabled         stopped
/etc/init.d/log                    enabled         running
/etc/init.d/network                enabled         running
/etc/init.d/odhcpd                 enabled         running
/etc/init.d/packet_steering        enabled         stopped
/etc/init.d/pingcheck             disabled         stopped
/etc/init.d/rpcd                   enabled         running
/etc/init.d/sysctl                 enabled         stopped
/etc/init.d/sysfixtime             enabled         stopped
/etc/init.d/sysntpd                enabled         running
/etc/init.d/system                 enabled         stopped
/etc/init.d/ubihealthd             enabled         running
/etc/init.d/ucitrack               enabled         stopped
/etc/init.d/uhttpd                 enabled         running
/etc/init.d/umount                 enabled         stopped
/etc/init.d/urandom_seed           enabled         stopped
/etc/init.d/urngd                  enabled         running
/etc/init.d/watchdog_mbim         disabled         stopped
/etc/init.d/wpad                   enabled         running

version of OpenWrt running:

ubus call system board

{
        "kernel": "6.6.73",
        "hostname": "LTE5398-M904",
        "system": "MediaTek MT7621 ver:1 eco:3",
        "model": "Zyxel LTE5398-M904",
        "board_name": "zyxel,lte5398-m904",
        "rootfs_type": "squashfs",
        "release": {
                "distribution": "OpenWrt",
                "version": "24.10.0",
                "revision": "r28427-6df0e3d02a",
                "target": "ramips/mt7621",
                "description": "OpenWrt 24.10.0 r28427-6df0e3d02a",
                "builddate": "1738624177"
        }
}

and here is a first disconnection that I detected manually,

for the first time I notice a repeated error message on the log
example:
"Mon Apr 28 02:27:57 2025 kern.crit kernel: [ 6893.011866] cdc_mbim 2-1:1.8 wwan0: NETDEV WATCHDOG: CPU: 3: transmit queue 0 timed out 5560 ms"
I'm doing some research on this ...

and here is the situation as it appears:

root@LTE5398-M904:~# date
Mon Apr 28 08:16:11 CEST 2025

root@LTE5398-M904:~# ping -c 1 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes

--- 8.8.8.8 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss

root@LTE5398-M904:~# ifstatus wan
{
        "up": true,
        "pending": false,
        "available": true,
        "autostart": true,
        "dynamic": false,
        "uptime": 27671,
        "l3_device": "wwan0",
        "proto": "mbim",
        "metric": 0,
        "dns_metric": 0,
        "delegation": true,
        "ipv4-address": [

        ],
        "ipv6-address": [

        ],
        "ipv6-prefix": [

        ],
        "ipv6-prefix-assignment": [

        ],
        "route": [

        ],
        "dns-server": [

        ],
        "dns-search": [

        ],
        "neighbors": [

        ],
        "inactive": {
                "ipv4-address": [

                ],
                "ipv6-address": [

                ],
                "route": [

                ],
                "dns-server": [

                ],
                "dns-search": [

                ],
                "neighbors": [

                ]
        },
        "data": {

        }
}

root@LTE5398-M904:~# logread; # cut log for repeated lines
Mon Apr 28 00:53:24 2025 user.notice root: exec: /root/clearlog Mon Apr 28 00:53:24 CEST 2025
Mon Apr 28 02:27:57 2025 kern.crit kernel: [ 6893.011866] cdc_mbim 2-1:1.8 wwan0: NETDEV WATCHDOG: CPU: 3: transmit queue 0 timed out 5560 ms
Mon Apr 28 02:28:07 2025 kern.crit kernel: [ 6903.011621] cdc_mbim 2-1:1.8 wwan0: NETDEV WATCHDOG: CPU: 3: transmit queue 0 timed out 5480 ms
Mon Apr 28 02:28:18 2025 kern.crit kernel: [ 6913.971357] cdc_mbim 2-1:1.8 wwan0: NETDEV WATCHDOG: CPU: 3: transmit queue 0 timed out 5610 ms
# cut log for repeated lines
Mon Apr 28 08:16:44 2025 kern.crit kernel: [27819.880953] cdc_mbim 2-1:1.8 wwan0: NETDEV WATCHDOG: CPU: 3: transmit queue 0 timed out 5010 ms

root@LTE5398-M904:~# logread | grep "NETDEV WATCHDOG: CPU: 3:" | wc -l
465

root@LTE5398-M904:~# uqmi -m -d /dev/cdc-wdm0 -t 20000 --get-data-status
Request timed out
"Failed to connect to service"

root@LTE5398-M904:~# ifdown wan
root@LTE5398-M904:~# ifup wan

root@LTE5398-M904:~# logread; # only the interesting part after running ifdown, ifup
Mon Apr 28 08:20:36 2025 daemon.notice netifd: Interface 'wan_4' is now down
Mon Apr 28 08:20:36 2025 daemon.notice netifd: Interface 'wan_4' is disabled
Mon Apr 28 08:20:36 2025 daemon.notice netifd: Interface 'wan_4' has link connectivity loss
Mon Apr 28 08:20:36 2025 daemon.notice netifd: Network alias '' link is down
Mon Apr 28 08:20:36 2025 user.notice hotplug: /etc/hotplug.d/iface Device:  / Action: ifdown / Interface: wan
Mon Apr 28 08:20:36 2025 daemon.notice netifd: wan (11020): mbim[11020] Stopping network
Mon Apr 28 08:20:38 2025 user.notice https-dns-proxy [11030]: Starting https-dns-proxy 2023.12.26-r4 instances on_interface_trigger ✓
Mon Apr 28 08:20:38 2025 user.notice https-dns-proxy [11030]: Setting trigger for wan ✓
Mon Apr 28 08:20:41 2025 daemon.notice netifd: Interface 'wan' is now down
Mon Apr 28 08:20:41 2025 daemon.notice netifd: Interface 'wan' is setting up now
Mon Apr 28 08:20:41 2025 user.notice hotplug: /etc/hotplug.d/iface Device:  / Action: ifdown / Interface: wan
Mon Apr 28 08:20:41 2025 daemon.notice netifd: wan (11266): mbim[11266] Reading capabilities
Mon Apr 28 08:20:43 2025 user.notice https-dns-proxy [11314]: Starting https-dns-proxy 2023.12.26-r4 instances on_interface_trigger ✓
Mon Apr 28 08:20:43 2025 user.notice https-dns-proxy [11314]: Setting trigger for wan ✓

uncut file available on: