mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-31 12:35:13 +08:00
⛅ Sync 2026-05-12 21:14:24
This commit is contained in:
1 parent
8073883628
commit
a3469dafa2
26 files changed
+424
-310
No files matched your search
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=hickory-dns
|
||||
PKG_VERSION:=0.26.1
|
||||
PKG_RELEASE:=25
|
||||
PKG_RELEASE:=26
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/hickory-dns/hickory-dns/tar.gz/v$(PKG_VERSION)?
|
||||
|
||||
@@ -6,38 +6,62 @@ STOP=51
|
||||
|
||||
PROG=/usr/bin/hickory-dns
|
||||
CONF=/etc/hickory-dns/forwarder.toml
|
||||
CONF_DIR=/etc/hickory-dns
|
||||
TSIG_KEY=/etc/hickory-dns/update.key
|
||||
NEIGH_PROG=/usr/bin/ipv6-neigh
|
||||
|
||||
RUN_USER=nobody
|
||||
RUN_GROUP=nogroup
|
||||
|
||||
STATE_DIR=/var/lib/hickory-dns
|
||||
LAN_JOURNAL="${STATE_DIR}/lan.jrnl"
|
||||
|
||||
prepare_config_dir() {
|
||||
[ -d "$CONF_DIR" ] || mkdir -p "$CONF_DIR"
|
||||
|
||||
chown -R "$RUN_USER:$RUN_GROUP" "$CONF_DIR" 2>/dev/null || true
|
||||
|
||||
find "$CONF_DIR" -type d -exec chmod 755 {} \; 2>/dev/null || true
|
||||
find "$CONF_DIR" -type f -exec chmod 644 {} \; 2>/dev/null || true
|
||||
}
|
||||
|
||||
generate_tsig_key() {
|
||||
[ -f "$TSIG_KEY" ] && return 0
|
||||
dd if=/dev/urandom bs=32 count=1 of="$TSIG_KEY" 2>/dev/null
|
||||
chown nobody:nogroup "$TSIG_KEY" 2>/dev/null || true
|
||||
chmod 400 "$TSIG_KEY"
|
||||
if [ ! -f "$TSIG_KEY" ]; then
|
||||
dd if=/dev/urandom bs=32 count=1 of="$TSIG_KEY" 2>/dev/null
|
||||
fi
|
||||
|
||||
chown "$RUN_USER:$RUN_GROUP" "$TSIG_KEY" 2>/dev/null || true
|
||||
chmod 400 "$TSIG_KEY" 2>/dev/null || true
|
||||
}
|
||||
|
||||
prepare_runtime_dirs() {
|
||||
mkdir -p "$STATE_DIR"
|
||||
|
||||
chown "$RUN_USER:$RUN_GROUP" "$STATE_DIR" 2>/dev/null || true
|
||||
chmod 755 "$STATE_DIR" 2>/dev/null || true
|
||||
}
|
||||
|
||||
cleanup_stale_state() {
|
||||
# Remove stale journal so hickory-dns always starts from the zone file.
|
||||
# ipv6-neigh re-registers all dynamic entries on startup, so the journal
|
||||
# has no durable value and may contain corrupt state after unclean shutdown.
|
||||
rm -f "$LAN_JOURNAL"
|
||||
}
|
||||
|
||||
start_service() {
|
||||
prepare_config_dir
|
||||
generate_tsig_key
|
||||
mkdir -p /var/lib/hickory-dns
|
||||
chown nobody:nogroup /var/lib/hickory-dns
|
||||
# Remove stale journal so hickory-dns always starts from the zone file.
|
||||
# ipv6-neigh re-registers all dynamic entries on startup, so the journal
|
||||
# has no durable value and may contain a corrupt state after unclean shutdown.
|
||||
rm -f /var/lib/hickory-dns/lan.jrnl
|
||||
prepare_runtime_dirs
|
||||
cleanup_stale_state
|
||||
|
||||
procd_open_instance hickory-dns
|
||||
procd_set_param command $PROG -c $CONF -q
|
||||
procd_set_param command "$PROG" -c "$CONF" -q
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
procd_set_param respawn "${respawn_threshold:-3600}" "${respawn_timeout:-5}" "${respawn_retry:-5}"
|
||||
procd_close_instance hickory-dns
|
||||
for i in $(seq 1 10); do
|
||||
if ss -ltn | grep -q ':53'; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
procd_open_instance ipv6-neigh
|
||||
procd_set_param command $NEIGH_PROG --private-subnet-v4 -d "[::1]:53" -z lan --router-alias router
|
||||
procd_set_param command /usr/bin/ipv6-neigh-wrapper
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
procd_set_param respawn "${respawn_threshold:-3600}" "${respawn_timeout:-5}" "${respawn_retry:-5}"
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
NEIGH_PROG=/usr/bin/ipv6-neigh
|
||||
RETRY=30
|
||||
|
||||
trap 'exit 1' TERM INT
|
||||
|
||||
logger -t ipv6-neigh-wrapper "waiting for DNS port 53"
|
||||
|
||||
i=0
|
||||
while [ "$i" -lt "$RETRY" ]; do
|
||||
if ss -lnt | grep -q ':53'; then
|
||||
logger -t ipv6-neigh-wrapper "DNS port 53 ready, starting ipv6-neigh"
|
||||
exec "$NEIGH_PROG" --private-subnet-v4 -d "[::1]:53" -z lan --router-alias router
|
||||
fi
|
||||
i=$((i + 1))
|
||||
sleep 1
|
||||
done
|
||||
|
||||
logger -t ipv6-neigh-wrapper "DNS port 53 not ready after ${RETRY}s, exiting"
|
||||
exit 1
|
||||
+3
-3
@@ -10,10 +10,10 @@ include $(TOPDIR)/rules.mk
|
||||
PKG_ARCH_kai:=$(ARCH)
|
||||
|
||||
PKG_NAME:=kai
|
||||
PKG_VERSION:=0.0.5
|
||||
PKG_RELEASE:=2
|
||||
PKG_VERSION:=0.0.2
|
||||
PKG_RELEASE:=3
|
||||
PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/linkease/istore-packages/releases/download/prebuilt/
|
||||
PKG_SOURCE_URL:=https://github.com/Carseason/openwrt-packages/releases/download/prebuilt/
|
||||
PKG_HASH:=skip
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-binary-$(PKG_VERSION)
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
config kai
|
||||
option 'enabled' '0'
|
||||
option 'data_dir' ''
|
||||
option 'port' '8197'
|
||||
option 'cwd' '/tmp/kai'
|
||||
+9
-90
@@ -5,95 +5,24 @@ USE_PROCD=1
|
||||
|
||||
get_config() {
|
||||
config_get_bool enabled $1 enabled 1
|
||||
config_get data_dir $1 data_dir ""
|
||||
config_get port $1 port "8197"
|
||||
}
|
||||
|
||||
http_get() {
|
||||
local url="$1"
|
||||
if command -v uclient-fetch >/dev/null 2>&1; then
|
||||
uclient-fetch -O /dev/stdout "$url" 2>/dev/null
|
||||
return $?
|
||||
fi
|
||||
if command -v wget >/dev/null 2>&1; then
|
||||
wget -qO- "$url" 2>/dev/null
|
||||
return $?
|
||||
fi
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsL "$url" 2>/dev/null
|
||||
return $?
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
maybe_refresh_opencode_skills_cache() {
|
||||
[ -n "$data_dir" ] || return 0
|
||||
[ -n "$port" ] || return 0
|
||||
command -v jsonfilter >/dev/null 2>&1 || return 0
|
||||
|
||||
local cache_root="${data_dir}/cache/opencode/skills"
|
||||
local state_root="${data_dir}/state/opencode"
|
||||
local version_file="${state_root}/skills.manifest.version"
|
||||
local managed_file="${state_root}/skills.managed.list"
|
||||
local manifest_url="http://127.0.0.1:${port}/agentconf/skills/manifest.json"
|
||||
|
||||
[ -d "$cache_root" ] || mkdir -p "$cache_root"
|
||||
[ -d "$state_root" ] || mkdir -p "$state_root"
|
||||
|
||||
local manifest version prev_version skills
|
||||
manifest="$(http_get "$manifest_url")" || return 0
|
||||
version="$(printf '%s' "$manifest" | jsonfilter -e '@.version' 2>/dev/null)"
|
||||
[ -n "$version" ] || return 0
|
||||
|
||||
prev_version=""
|
||||
[ -f "$version_file" ] && prev_version="$(cat "$version_file" 2>/dev/null)"
|
||||
[ "$version" = "$prev_version" ] && return 0
|
||||
|
||||
logger -t kai "opencode skills manifest changed; refreshing managed skill cache"
|
||||
|
||||
if [ -f "$managed_file" ]; then
|
||||
while IFS= read -r s; do
|
||||
[ -n "$s" ] || continue
|
||||
rm -rf "${cache_root}/${s}"
|
||||
done <"$managed_file"
|
||||
fi
|
||||
|
||||
skills="$(printf '%s' "$manifest" | jsonfilter -e '@.skills[*]' 2>/dev/null)"
|
||||
if [ -n "$skills" ]; then
|
||||
printf '%s\n' "$skills" >"$managed_file"
|
||||
printf '%s\n' "$skills" | while IFS= read -r s; do
|
||||
[ -n "$s" ] || continue
|
||||
rm -rf "${cache_root}/${s}"
|
||||
done
|
||||
else
|
||||
: >"$managed_file"
|
||||
fi
|
||||
|
||||
printf '%s\n' "$version" >"$version_file"
|
||||
return 0
|
||||
config_get cwd $1 cwd "/tmp/kai"
|
||||
}
|
||||
|
||||
start_kai_bin(){
|
||||
procd_open_instance kai_bin
|
||||
procd_set_param command /usr/sbin/kai_bin -a 0.0.0.0 -p "$port"
|
||||
procd_set_param command /usr/sbin/kai_bin
|
||||
procd_set_param stderr 1
|
||||
procd_set_param respawn
|
||||
procd_close_instance
|
||||
}
|
||||
mkdir_cwd(){
|
||||
[ -d "$1" ] || mkdir -p "$1"
|
||||
if [ ! -d $1 ]; then
|
||||
mkdir -p $1
|
||||
fi
|
||||
}
|
||||
start_kai_session(){
|
||||
procd_open_instance kai_session
|
||||
local root="${data_dir}"
|
||||
local cwd="${data_dir}/cwd"
|
||||
procd_set_param env \
|
||||
OPENCODE_CWD="${cwd}" \
|
||||
OPENCODE_CONFIG="http://127.0.0.1:${port}/agentconf/opencode.json" \
|
||||
XDG_CACHE_HOME="${root}/cache" \
|
||||
XDG_DATA_HOME="${root}/data" \
|
||||
XDG_CONFIG_HOME="${root}/config" \
|
||||
XDG_STATE_HOME="${root}/state"
|
||||
procd_set_param env OPENCODE_CWD=$1 OPENCODE_CONFIG=http://127.0.0.1:8197/config/opencode/opencode.json
|
||||
procd_set_param command /usr/sbin/kai_session
|
||||
procd_append_param command serve --port "8196" --hostname "127.0.0.1"
|
||||
procd_set_param stderr 1
|
||||
@@ -106,24 +35,14 @@ start_service() {
|
||||
if [ $enabled != 1 ]; then
|
||||
return 1
|
||||
fi
|
||||
if [ -z "${data_dir}" ]; then
|
||||
logger -t kai "data_dir is empty; please set option data_dir in /etc/config/kai"
|
||||
return 1
|
||||
fi
|
||||
logger -t kai "Starting KAI Service"
|
||||
start_kai_bin
|
||||
sleep 1
|
||||
mkdir_cwd "${data_dir}"
|
||||
mkdir_cwd "${data_dir}/cwd"
|
||||
mkdir_cwd "${data_dir}/cache"
|
||||
mkdir_cwd "${data_dir}/data"
|
||||
mkdir_cwd "${data_dir}/config"
|
||||
mkdir_cwd "${data_dir}/state"
|
||||
maybe_refresh_opencode_skills_cache
|
||||
start_kai_session
|
||||
mkdir_cwd $cwd
|
||||
start_kai_session $cwd
|
||||
logger -t kai "Starting KAI Service Completed"
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "kai"
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,10 @@ include $(TOPDIR)/rules.mk
|
||||
PKG_ARCH_kai_session:=$(ARCH)
|
||||
|
||||
PKG_NAME:=kai_session
|
||||
PKG_VERSION:=0.0.5
|
||||
PKG_RELEASE:=2
|
||||
PKG_VERSION:=0.0.2
|
||||
PKG_RELEASE:=3
|
||||
PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/linkease/istore-packages/releases/download/prebuilt/
|
||||
PKG_SOURCE_URL:=https://github.com/Carseason/openwrt-packages/releases/download/prebuilt/
|
||||
PKG_HASH:=skip
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-binary-$(PKG_VERSION)
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-amlogic
|
||||
PKG_VERSION:=3.1.303
|
||||
PKG_RELEASE:=8
|
||||
PKG_VERSION:=3.1.309
|
||||
PKG_RELEASE:=9
|
||||
|
||||
PKG_LICENSE:=GPL-2.0 License
|
||||
PKG_MAINTAINER:=ophub <https://github.com/ophub/luci-app-amlogic>
|
||||
|
||||
@@ -461,9 +461,10 @@ return view.extend({
|
||||
dom.content(verKernel, s && s.current_kernel_version
|
||||
? E('span', { class: 'amlogic-status-ok' }, _('Current Version') + ' [ ' + s.current_kernel_version + ' ] ')
|
||||
: E('span', { class: 'amlogic-status-err' }, _('Invalid value.')));
|
||||
dom.content(branchSpan, s && s.current_kernel_branch
|
||||
? ' [ ' + s.current_kernel_branch + '.y ] '
|
||||
: ' [ ' + _('Invalid value.') + ' ]');
|
||||
var branchLabel = s && s.plugin_branch
|
||||
? (s.plugin_branch === 'lua' ? 'Lua' : 'JavaScript')
|
||||
: (s && s.has_luci_js ? 'JavaScript' : 'Lua');
|
||||
dom.content(branchSpan, ' [ ' + branchLabel + ' ] ');
|
||||
|
||||
// Rescue row: show same kernel version directly via the verRescue span
|
||||
dom.content(verRescue, s && s.current_kernel_version
|
||||
|
||||
@@ -130,11 +130,14 @@ return view.extend({
|
||||
// 8. Plugin branch
|
||||
const pbranch = o.option(form.ListValue, 'amlogic_plugin_branch',
|
||||
_('Set plugin branch:'),
|
||||
_('Set the branch of the luci-app-amlogic plugin used in [Only update Amlogic Service]. Default (empty) uses the main (JavaScript) branch.'));
|
||||
pbranch.value('', _('main [JavaScript version]'));
|
||||
state.has_luci_js
|
||||
? _('Set the branch of the luci-app-amlogic plugin used in [Only update Amlogic Service]. Select main for JavaScript version or lua for Lua version.')
|
||||
: _('Set the branch of the luci-app-amlogic plugin used in [Only update Amlogic Service]. This system does not have JS LuCI, only the Lua branch is available.'));
|
||||
if (state.has_luci_js)
|
||||
pbranch.value('main', _('main [JavaScript version]'));
|
||||
pbranch.value('lua', _('lua [Lua version]'));
|
||||
pbranch.default = '';
|
||||
pbranch.rmempty = true;
|
||||
pbranch.default = state.has_luci_js ? 'main' : 'lua';
|
||||
pbranch.rmempty = false;
|
||||
|
||||
// 9. Keep config
|
||||
const fcfg = o.option(form.Flag, 'amlogic_firmware_config',
|
||||
|
||||
@@ -425,8 +425,8 @@ msgstr "Укажите ветку версии для файлов OpenWrt и я
|
||||
msgid "Set plugin branch:"
|
||||
msgstr "Ветка плагина:"
|
||||
|
||||
msgid "Set the branch of the luci-app-amlogic plugin used in [Only update Amlogic Service]. Default (empty) uses the main (JavaScript) branch."
|
||||
msgstr "Укажите ветку плагина luci-app-amlogic для раздела [Только обновить сервис Amlogic]. По умолчанию (пусто) используется ветка main (JavaScript)."
|
||||
msgid "Set the branch of the luci-app-amlogic plugin used in [Only update Amlogic Service]. Select main for JavaScript version or lua for Lua version."
|
||||
msgstr "Укажите ветку плагина luci-app-amlogic для раздела [Только обновить сервис Amlogic]. Выберите main для JavaScript версии или lua для Lua версии."
|
||||
|
||||
msgid "main [JavaScript version]"
|
||||
msgstr "main [JavaScript версия]"
|
||||
|
||||
@@ -425,8 +425,8 @@ msgstr "设置 [在线下载更新] 时 OpenWrt 文件与内核所选用的版
|
||||
msgid "Set plugin branch:"
|
||||
msgstr "设置插件分支:"
|
||||
|
||||
msgid "Set the branch of the luci-app-amlogic plugin used in [Only update Amlogic Service]. Default (empty) uses the main (JavaScript) branch."
|
||||
msgstr "设置 [仅更新晶晨宝盒] 时使用的插件分支。默认(空)使用 main (JavaScript) 分支。"
|
||||
msgid "Set the branch of the luci-app-amlogic plugin used in [Only update Amlogic Service]. Select main for JavaScript version or lua for Lua version."
|
||||
msgstr "设置 [仅更新晶晨宝盒] 时使用的插件分支。选择 main 使用 JavaScript 版本,选择 lua 使用 Lua 版本。"
|
||||
|
||||
msgid "main [JavaScript version]"
|
||||
msgstr "main [JavaScript 版本]"
|
||||
|
||||
@@ -64,19 +64,40 @@ fi
|
||||
tolog "PLATFORM: [ ${PLATFORM} ]"
|
||||
sleep 2
|
||||
|
||||
# Read plugin branch from UCI config; default to "" (main-js) when missing or empty
|
||||
# When amlogic_plugin_branch is missing, add it with empty value (main-js default)
|
||||
if [[ -f "${AMLOGIC_CONFIG_FILE}" ]]; then
|
||||
plugin_branch="$(uci get amlogic.config.amlogic_plugin_branch 2>/dev/null | xargs)"
|
||||
if ! grep -q "amlogic_plugin_branch" "${AMLOGIC_CONFIG_FILE}" 2>/dev/null; then
|
||||
uci set amlogic.config.amlogic_plugin_branch='' 2>/dev/null
|
||||
uci commit amlogic 2>/dev/null
|
||||
plugin_branch=""
|
||||
# Read and resolve plugin_branch from UCI config.
|
||||
# Normalise to canonical values: "main" (JS) or "lua".
|
||||
# Priority: UCI value → auto-detect from system.
|
||||
plugin_branch="$(uci get amlogic.config.amlogic_plugin_branch 2>/dev/null | tr '[:upper:]' '[:lower:]' | xargs)"
|
||||
|
||||
# Normalize aliases (js / javascript / main → "main"; anything else → "lua")
|
||||
case "${plugin_branch}" in
|
||||
js | javascript | main)
|
||||
plugin_branch="main"
|
||||
;;
|
||||
lua)
|
||||
plugin_branch="lua"
|
||||
;;
|
||||
*)
|
||||
# Empty, unknown, or missing → auto-detect from system
|
||||
if [[ -f "/www/luci-static/resources/luci.js" ]]; then
|
||||
plugin_branch="main"
|
||||
else
|
||||
plugin_branch="lua"
|
||||
fi
|
||||
else
|
||||
plugin_branch=""
|
||||
;;
|
||||
esac
|
||||
|
||||
# Safety check: "main" requires JS LuCI; fall back when absent
|
||||
if [[ "${plugin_branch}" == "main" && ! -f "/www/luci-static/resources/luci.js" ]]; then
|
||||
plugin_branch="lua"
|
||||
tolog "Warning: JS LuCI not found, falling back to lua branch."
|
||||
fi
|
||||
tolog "Plugin branch: [ ${plugin_branch:-main-js} ]"
|
||||
|
||||
# Persist the resolved value back to UCI (covers migration + branch-switch cases)
|
||||
uci set amlogic.config.amlogic_plugin_branch="${plugin_branch}" 2>/dev/null
|
||||
uci commit amlogic 2>/dev/null
|
||||
|
||||
tolog "Plugin branch: [ ${plugin_branch} ]"
|
||||
sleep 1
|
||||
get_plugin_info() {
|
||||
package_manager=""
|
||||
@@ -114,19 +135,21 @@ check_plugin() {
|
||||
sleep 2
|
||||
|
||||
tolog "02. Start querying plugin version..."
|
||||
if [[ "${plugin_branch}" == "lua" ]]; then
|
||||
if [[ "${plugin_branch}" == "main" ]]; then
|
||||
# JS branch: match tags ending with -js (e.g. 3.1.305-js)
|
||||
latest_version="$(
|
||||
curl -fsSL -m 10 \
|
||||
https://github.com/ophub/luci-app-amlogic/releases |
|
||||
grep -oE 'expanded_assets/[0-9]+\.[0-9]+\.[0-9]+-lua' | sed 's|expanded_assets/||g' |
|
||||
grep -oE 'expanded_assets/[0-9]+\.[0-9]+\.[0-9]+-js' | sed 's|expanded_assets/||g' |
|
||||
sort -urV | head -n 1
|
||||
)"
|
||||
else
|
||||
# Lua branch: match tags with digits only, no suffix (e.g. 3.1.305)
|
||||
latest_version="$(
|
||||
curl -fsSL -m 10 \
|
||||
https://github.com/ophub/luci-app-amlogic/releases |
|
||||
grep -oE 'expanded_assets/[0-9]+\.[0-9]+\.[0-9]+' | sed 's|expanded_assets/||g' |
|
||||
grep -v '\-lua' |
|
||||
grep -v -- '-' |
|
||||
sort -urV | head -n 1
|
||||
)"
|
||||
fi
|
||||
@@ -141,12 +164,12 @@ check_plugin() {
|
||||
latest_version_base="${latest_version%%-*}"
|
||||
|
||||
# Determine target PKG_RELEASE for the selected branch:
|
||||
# js branch (default) -> release 2
|
||||
# lua branch -> release 1
|
||||
if [[ "${plugin_branch}" == "lua" ]]; then
|
||||
target_release="1"
|
||||
else
|
||||
# main branch -> release 2 (tag: 3.x.xxx-js)
|
||||
# lua branch -> release 1 (tag: 3.x.xxx, no suffix)
|
||||
if [[ "${plugin_branch}" == "main" ]]; then
|
||||
target_release="2"
|
||||
else
|
||||
target_release="1"
|
||||
fi
|
||||
|
||||
# Only report "already latest" when BOTH the version number AND the installed
|
||||
|
||||
@@ -92,6 +92,31 @@ function show_install_menu() {
|
||||
return m ? m[1] : 'Unknown';
|
||||
}
|
||||
|
||||
// Detect whether OpenWrt's root fs is on internal storage (eMMC/NVMe/fixed disk).
|
||||
// Returns true → already installed, hide the Install menu.
|
||||
// Returns false → running from USB/SD, show the Install menu.
|
||||
//
|
||||
// sd* devices can be either USB (removable=1) or internal SATA (removable=0);
|
||||
// we read /sys/block/<base_dev>/removable to distinguish them.
|
||||
// mmcblk* and nvme* are always internal storage on these platforms.
|
||||
function root_on_internal_storage() {
|
||||
const root_pt = trim(sh("df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}'"));
|
||||
if (!root_pt) return false;
|
||||
|
||||
if (match(root_pt, /^mmcblk[0-9]+p[0-9]+$/) || match(root_pt, /^nvme[0-9]+n[0-9]+p[0-9]+$/)) {
|
||||
// eMMC and NVMe are always internal
|
||||
return true;
|
||||
}
|
||||
if (match(root_pt, /^[hsv]d[a-z][0-9]+$/)) {
|
||||
// Strip trailing partition digit(s) to get base device (e.g. sda2 → sda)
|
||||
const base_dev = replace(root_pt, /[0-9]+$/, '');
|
||||
const removable = trim(sh('cat /sys/block/' + shq(base_dev) + '/removable 2>/dev/null'));
|
||||
// removable=0 → internal SATA/fixed disk; removable=1 → USB/removable
|
||||
return (removable == '0');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pick the helper script names for the current platform (as the original
|
||||
// controller did).
|
||||
function platform_scripts() {
|
||||
@@ -224,7 +249,9 @@ function m_state() {
|
||||
current_plugin_version: current_plugin_version(),
|
||||
current_kernel_version: current_kernel_version(),
|
||||
current_kernel_branch: current_kernel_branch(),
|
||||
kernel_release: sh('uname -r')
|
||||
kernel_release: sh('uname -r'),
|
||||
has_luci_js: access('/www/luci-static/resources/luci.js') ? true : false,
|
||||
plugin_branch: access('/usr/lib/lua/luci/controller/amlogic.lua') ? 'lua' : 'main'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -241,14 +268,10 @@ function m_platform_info() {
|
||||
const can_install = (index(p, 'amlogic') >= 0 || index(p, 'allwinner') >= 0 || index(m, 'yes') >= 0);
|
||||
// can_armcpu: all platforms except qemu support CPU frequency settings
|
||||
const can_armcpu = (index(p, 'qemu') < 0);
|
||||
// is_installed: root fs is on an internal storage device (mmcblk/sd/hd/vd),
|
||||
// meaning OpenWrt has already been installed to eMMC/NVMe/disk. When true,
|
||||
// the Install OpenWrt menu should be hidden.
|
||||
const root_pt = sh("df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}'");
|
||||
const is_installed = (root_pt != '' &&
|
||||
(match(root_pt, /^mmcblk[0-9]+p[1-4]$/) ||
|
||||
match(root_pt, /^[hsv]d[a-z][0-9]+$/) ||
|
||||
match(root_pt, /^nvme[0-9]+n[0-9]+p[0-9]+$/)));
|
||||
// is_installed: root fs is on an internal storage device (eMMC/NVMe/fixed disk).
|
||||
// sd* devices may be USB (removable=1) or internal SATA (removable=0); check
|
||||
// /sys/block/<dev>/removable to distinguish. When true the Install menu is hidden.
|
||||
const is_installed = root_on_internal_storage();
|
||||
return {
|
||||
platform: p,
|
||||
install_menu: m,
|
||||
@@ -382,6 +405,30 @@ function m_start_plugin() {
|
||||
+ 'cfg=' + shq(cfg) + '\n'
|
||||
+ 'cfg_bak=' + shq(cfg_bak) + '\n'
|
||||
+ '[ -f "$cfg" ] && cp -f "$cfg" "$cfg_bak"\n'
|
||||
+ '# Detect new release from downloaded file name (r1=lua, r2=js)\n'
|
||||
+ 'new_release=""\n'
|
||||
+ 'cur_release=""\n'
|
||||
+ 'if command -v opkg >/dev/null 2>&1; then\n'
|
||||
+ ' _ipk="$(ls /tmp/amlogic/luci-app-amlogic_*.ipk 2>/dev/null | head -n 1)"\n'
|
||||
+ ' new_release="$(echo "${_ipk}" | grep -oE \'\\-r[0-9]+_\' | grep -oE \'[0-9]+\')"\n'
|
||||
+ ' _raw="$(opkg list-installed 2>/dev/null | grep \'^luci-app-amlogic \' | awk \'{print $3}\' | cut -d\'-\' -f2)"\n'
|
||||
+ ' cur_release="${_raw#r}"\n'
|
||||
+ 'elif command -v apk >/dev/null 2>&1; then\n'
|
||||
+ ' _apk="$(ls /tmp/amlogic/luci-app-amlogic_*.apk 2>/dev/null | head -n 1)"\n'
|
||||
+ ' new_release="$(echo "${_apk}" | grep -oE \'\\-r[0-9]+[-~]\' | grep -oE \'[0-9]+\')"\n'
|
||||
+ ' cur_release="$(apk list --installed 2>/dev/null | grep \'^luci-app-amlogic-\' | awk \'{print $1}\' | cut -d\'-\' -f5 | sed \'s/^r//\')"\n'
|
||||
+ 'fi\n'
|
||||
+ '# When switching branches (r1<->r2), remove old package first so that\n'
|
||||
+ '# opkg/apk registers all new files. plain remove does NOT touch dep packages.\n'
|
||||
+ 'if [ -n "$cur_release" ] && [ -n "$new_release" ] && [ "$cur_release" != "$new_release" ]; then\n'
|
||||
+ ' echo "Branch switch detected (r${cur_release} -> r${new_release}), removing old package first..." >> "$LOG"\n'
|
||||
+ ' if command -v opkg >/dev/null 2>&1; then\n'
|
||||
+ ' opkg remove luci-app-amlogic --force-depends >> "$LOG" 2>&1 || true\n'
|
||||
+ ' elif command -v apk >/dev/null 2>&1; then\n'
|
||||
+ ' apk del luci-app-amlogic >> "$LOG" 2>&1 || true\n'
|
||||
+ ' fi\n'
|
||||
+ ' echo "Old package removed (dependencies kept)." >> "$LOG"\n'
|
||||
+ 'fi\n'
|
||||
+ 'if command -v opkg >/dev/null 2>&1; then\n'
|
||||
+ ' echo "System uses opkg." >> "$LOG"\n'
|
||||
+ ' opkg --force-reinstall --force-downgrade install /tmp/amlogic/*.ipk >> "$LOG" 2>&1\n'
|
||||
@@ -396,7 +443,7 @@ function m_start_plugin() {
|
||||
+ 'fi\n'
|
||||
+ 'if [ "$rc" = "0" ]; then\n'
|
||||
+ ' [ -f "$cfg_bak" ] && cp -f "$cfg_bak" "$cfg"\n'
|
||||
+ ' rm -f /etc/config/amlogic.apk-new /etc/config/amlogic.ipk-old\n'
|
||||
+ ' rm -f /etc/config/amlogic.apk-new /etc/config/amlogic.ipk-old /etc/config/amlogic-opkg\n'
|
||||
+ ' rm -rf /tmp/luci-indexcache /tmp/luci-modulecache/* "$cfg_bak"\n'
|
||||
+ ' echo "" > "$LOG_RUNNING"\n'
|
||||
+ ' echo "Successful Update" > "$LOG"\n'
|
||||
@@ -418,6 +465,16 @@ function m_start_plugin() {
|
||||
+ ' rm -f /usr/share/rpcd/ucode/luci.amlogic\n'
|
||||
+ ' rm -f /www/luci-static/resources/view/amlogic/*.js\n'
|
||||
+ ' rm -f /usr/share/luci/menu.d/luci-app-amlogic.json\n'
|
||||
+ ' fi\n'
|
||||
+ ' # Auto-set plugin branch in UCI config if not already configured\n'
|
||||
+ ' _cur_branch="$(uci -q get amlogic.config.amlogic_plugin_branch 2>/dev/null)"\n'
|
||||
+ ' if [ -z "${_cur_branch}" ]; then\n'
|
||||
+ ' if [ -f "/www/luci-static/resources/luci.js" ]; then\n'
|
||||
+ ' uci set amlogic.config.amlogic_plugin_branch=\'main\' 2>/dev/null\n'
|
||||
+ ' else\n'
|
||||
+ ' uci set amlogic.config.amlogic_plugin_branch=\'lua\' 2>/dev/null\n'
|
||||
+ ' fi\n'
|
||||
+ ' uci commit amlogic 2>/dev/null\n'
|
||||
+ ' fi) &\n'
|
||||
+ 'else\n'
|
||||
+ ' echo "--- INSTALLATION FAILED! ---" >> "$LOG"\n'
|
||||
@@ -684,11 +741,7 @@ function m_sync_menu() {
|
||||
const p = platform();
|
||||
const m = show_install_menu();
|
||||
// Detect whether OpenWrt has already been installed to internal storage
|
||||
const root_pt = sh("df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}'");
|
||||
const is_installed = (root_pt != '' &&
|
||||
(match(root_pt, /^mmcblk[0-9]+p[1-4]$/) ||
|
||||
match(root_pt, /^[hsv]d[a-z][0-9]+$/) ||
|
||||
match(root_pt, /^nvme[0-9]+n[0-9]+p[0-9]+$/)));
|
||||
const is_installed = root_on_internal_storage();
|
||||
const can_install = (index(p, 'amlogic') >= 0 || index(p, 'allwinner') >= 0 || index(m, 'yes') >= 0);
|
||||
const show_install = (can_install && !is_installed) ? 'yes' : 'no';
|
||||
const show_armcpu = (index(p, 'qemu') < 0) ? 'yes' : 'no';
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=kai
|
||||
PKG_VERSION:=1.0.1
|
||||
PKG_RELEASE:=3
|
||||
LUCI_DEPENDS:=+kai +kai_session +luci-compat
|
||||
PKG_VERSION:=1.0.0
|
||||
PKG_RELEASE:=4
|
||||
LUCI_DEPENDS:=+kai +kai_session
|
||||
LUCI_MINIFY_CSS:=0
|
||||
LUCI_MINIFY_JS:=0
|
||||
|
||||
@@ -17,7 +17,7 @@ define Package/luci-app-kai/conffiles
|
||||
/etc/config/kai
|
||||
endef
|
||||
|
||||
define Package/luci-app-kai/postrm
|
||||
define Package/luci-nginxer/postrm
|
||||
#!/bin/sh
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
||||
@@ -25,4 +25,4 @@ endef
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
@@ -1,6 +1,6 @@
|
||||
local m, s
|
||||
|
||||
m = Map("kai", translate("KAI"), translate("KAI is an efficient AI tool."))
|
||||
m = Map("kai", translate("KAI"), translate("KAI is an efficient data transfer tool."))
|
||||
m:section(SimpleSection).template = "kai/kai_status"
|
||||
|
||||
s=m:section(TypedSection, "kai", translate("Global settings"))
|
||||
@@ -8,25 +8,6 @@ s.addremove=false
|
||||
s.anonymous=true
|
||||
|
||||
s:option(Flag, "enabled", translate("Enable")).rmempty=false
|
||||
|
||||
local kai_model = require "luci.model.kai"
|
||||
local blocks = kai_model.blocks()
|
||||
local home = kai_model.home()
|
||||
|
||||
local data_dir = s:option(Value, "data_dir", translate("Data directory"))
|
||||
data_dir.rmempty = false
|
||||
data_dir.description = translate("Required. KAI session will store cwd/cache/data/config/state under this directory (subfolders: cwd, cache, data, config, state).")
|
||||
|
||||
local paths, default_path = kai_model.find_paths(blocks, home, "Configs")
|
||||
for _, val in pairs(paths) do
|
||||
data_dir:value(val, val)
|
||||
end
|
||||
data_dir.default = default_path
|
||||
|
||||
local port = s:option(Value, "port", translate("API port"))
|
||||
port.default = "8197"
|
||||
port.rmempty = false
|
||||
port.datatype = "port"
|
||||
port.description = translate("Port for KAI HTTP server (kai_bin). kai_session will read OPENCODE_CONFIG via 127.0.0.1:<port>.")
|
||||
|
||||
return m
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
local jsonc = require "luci.jsonc"
|
||||
|
||||
local kai = {}
|
||||
|
||||
kai.blocks = function()
|
||||
local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r")
|
||||
local vals = {}
|
||||
if f then
|
||||
local ret = f:read("*all")
|
||||
f:close()
|
||||
local obj = jsonc.parse(ret)
|
||||
for _, val in pairs(obj and obj["blockdevices"] or {}) do
|
||||
local fsize = val["fssize"]
|
||||
if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then
|
||||
vals[#vals + 1] = val["mountpoint"]
|
||||
end
|
||||
end
|
||||
end
|
||||
return vals
|
||||
end
|
||||
|
||||
kai.home = function()
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local home_dirs = {}
|
||||
home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root")
|
||||
home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"] .. "/Configs")
|
||||
home_dirs["Public"] = uci:get_first("quickstart", "main", "pub_dir", home_dirs["main_dir"] .. "/Public")
|
||||
home_dirs["Downloads"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["Public"] .. "/Downloads")
|
||||
home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"] .. "/Caches")
|
||||
return home_dirs
|
||||
end
|
||||
|
||||
kai.find_paths = function(blocks, home_dirs, path_name)
|
||||
local default_path = ""
|
||||
local paths = {}
|
||||
|
||||
default_path = home_dirs[path_name] .. "/KAI"
|
||||
if #blocks == 0 then
|
||||
table.insert(paths, default_path)
|
||||
else
|
||||
for _, val in pairs(blocks) do
|
||||
table.insert(paths, val .. "/" .. path_name .. "/KAI")
|
||||
end
|
||||
local without_conf_dir = "/root/" .. path_name .. "/KAI"
|
||||
if default_path == without_conf_dir then
|
||||
default_path = paths[1]
|
||||
end
|
||||
end
|
||||
|
||||
return paths, default_path
|
||||
end
|
||||
|
||||
return kai
|
||||
|
||||
@@ -14,7 +14,7 @@ XHR.poll(5, '<%=url("admin/services/kai_status")%>', null,function(x, st){
|
||||
//]]></script>
|
||||
|
||||
<fieldset class="cbi-section">
|
||||
<legend><%:Status%></legend>
|
||||
<legend>状态</legend>
|
||||
<p id="kai_status">
|
||||
<em><%:Collecting data...%></em>
|
||||
</p>
|
||||
|
||||
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall
|
||||
PKG_VERSION:=26.5.11
|
||||
PKG_RELEASE:=118
|
||||
PKG_RELEASE:=119
|
||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
|
||||
@@ -1775,12 +1775,12 @@ local function select_node(nodes, config, parentConfig)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- 第一优先级 类型 + 备注 + IP + 端口
|
||||
-- 第一优先级 类型 + 备注 + IP + 端口 + 分组
|
||||
if not server then
|
||||
for index, node in pairs(nodes) do
|
||||
if config.currentNode.type and config.currentNode.remarks and config.currentNode.address and config.currentNode.port then
|
||||
if node.type and node.remarks and node.address and node.port then
|
||||
if node.type == config.currentNode.type and node.remarks == config.currentNode.remarks and (node.address .. ':' .. node.port == config.currentNode.address .. ':' .. config.currentNode.port) then
|
||||
if node.type == config.currentNode.type and node.remarks == config.currentNode.remarks and (node.address .. ':' .. node.port == config.currentNode.address .. ':' .. config.currentNode.port) and node.group == config.currentNode.group then
|
||||
if config.log == nil or config.log == true then
|
||||
log('更新【' .. config.remarks .. '】第一匹配节点:' .. node.remarks)
|
||||
end
|
||||
@@ -1791,12 +1791,12 @@ local function select_node(nodes, config, parentConfig)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- 第二优先级 类型 + IP + 端口
|
||||
-- 第二优先级 类型 + IP + 端口 + 分组
|
||||
if not server then
|
||||
for index, node in pairs(nodes) do
|
||||
if config.currentNode.type and config.currentNode.address and config.currentNode.port then
|
||||
if node.type and node.address and node.port then
|
||||
if node.type == config.currentNode.type and (node.address .. ':' .. node.port == config.currentNode.address .. ':' .. config.currentNode.port) then
|
||||
if node.type == config.currentNode.type and (node.address .. ':' .. node.port == config.currentNode.address .. ':' .. config.currentNode.port) and node.group == config.currentNode.group then
|
||||
if config.log == nil or config.log == true then
|
||||
log('更新【' .. config.remarks .. '】第二匹配节点:' .. node.remarks)
|
||||
end
|
||||
@@ -1807,12 +1807,12 @@ local function select_node(nodes, config, parentConfig)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- 第三优先级 IP + 端口
|
||||
-- 第三优先级 IP + 端口 + 分组
|
||||
if not server then
|
||||
for index, node in pairs(nodes) do
|
||||
if config.currentNode.address and config.currentNode.port then
|
||||
if node.address and node.port then
|
||||
if node.address .. ':' .. node.port == config.currentNode.address .. ':' .. config.currentNode.port then
|
||||
if node.address .. ':' .. node.port == config.currentNode.address .. ':' .. config.currentNode.port and node.group == config.currentNode.group then
|
||||
if config.log == nil or config.log == true then
|
||||
log('更新【' .. config.remarks .. '】第三匹配节点:' .. node.remarks)
|
||||
end
|
||||
@@ -1823,12 +1823,12 @@ local function select_node(nodes, config, parentConfig)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- 第四优先级 IP
|
||||
-- 第四优先级 IP + 分组
|
||||
if not server then
|
||||
for index, node in pairs(nodes) do
|
||||
if config.currentNode.address then
|
||||
if node.address then
|
||||
if node.address == config.currentNode.address then
|
||||
if node.address == config.currentNode.address and node.group == config.currentNode.group then
|
||||
if config.log == nil or config.log == true then
|
||||
log('更新【' .. config.remarks .. '】第四匹配节点:' .. node.remarks)
|
||||
end
|
||||
@@ -1839,12 +1839,12 @@ local function select_node(nodes, config, parentConfig)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- 第五优先级备注
|
||||
-- 第五优先级备注 + 分组
|
||||
if not server then
|
||||
for index, node in pairs(nodes) do
|
||||
if config.currentNode.remarks then
|
||||
if node.remarks then
|
||||
if node.remarks == config.currentNode.remarks then
|
||||
if node.remarks == config.currentNode.remarks and node.group == config.currentNode.group then
|
||||
if config.log == nil or config.log == true then
|
||||
log('更新【' .. config.remarks .. '】第五匹配节点:' .. node.remarks)
|
||||
end
|
||||
|
||||
@@ -8,17 +8,17 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=Nginxer
|
||||
LUCI_DESCRIPTION:=Standard OpenWrt set including full admin with ppp support and the default Bootstrap theme
|
||||
PKG_VERSION:=0.0.2
|
||||
PKG_RELEASE:=1
|
||||
PKG_VERSION:=0.0.1
|
||||
PKG_RELEASE:=2
|
||||
LUCI_DEPENDS:=+luci-nginx
|
||||
|
||||
define Package/luci-nginxer/postrm
|
||||
#!/bin/sh
|
||||
/etc/init.d/uhttpd enable
|
||||
/etc/init.d/uhttpd enabled
|
||||
/etc/init.d/uhttpd start
|
||||
exit 0
|
||||
endef
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
@@ -8,11 +8,7 @@ if [ "$nginxer" != 1 ]; then
|
||||
uci set nginx._redirect2ssl.access_log='off; # logd openwrt'
|
||||
uci set nginx.global.nginxer='1'
|
||||
uci commit nginx
|
||||
|
||||
# fix firmware upload failed
|
||||
sed -i 's/client_max_body_size 128M;/client_max_body_size 256M;/g' /etc/nginx/uci.conf.template
|
||||
|
||||
# /etc/init.d/uhttpd running || /etc/init.d/uhttpd disable
|
||||
/etc/init.d/nginx reload
|
||||
fi
|
||||
exit 0
|
||||
exit 0
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=nexttrace
|
||||
PKG_VERSION:=1.6.4
|
||||
PKG_RELEASE:=4
|
||||
PKG_VERSION:=1.6.5
|
||||
PKG_RELEASE:=5
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/nxtrace/NTrace-core/tar.gz/v$(PKG_VERSION)?
|
||||
|
||||
+2
-2
@@ -8,8 +8,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=qminfo
|
||||
PKG_VERSION=0.0.1
|
||||
PKG_RELEASE:=2
|
||||
PKG_VERSION=0.0.2
|
||||
PKG_RELEASE:=3
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
|
||||
+84
-27
@@ -1,37 +1,97 @@
|
||||
# ─────────────────────────────────────────────────────────────────
|
||||
# Makefile for qminfo
|
||||
#
|
||||
# Usage:
|
||||
# make — compile
|
||||
# make install — install /usr/local/bin
|
||||
# make uninstall — remove
|
||||
# make clean — remove build
|
||||
# make run [DEV=/dev/cdc-wdm0] — run text mode
|
||||
# make json [DEV=/dev/cdc-wdm0] — run JSON output
|
||||
# Build:
|
||||
# make
|
||||
#
|
||||
# Cross Build:
|
||||
# make ARCH=aarch64
|
||||
# make ARCH=armv7
|
||||
# make ARCH=armv5
|
||||
# make ARCH=mipsle
|
||||
#
|
||||
# С sysroot (Buildroot/Yocto/OpenWRT):
|
||||
# make ARCH=mipsle SYSROOT=/path/to/staging
|
||||
# ─────────────────────────────────────────────────────────────────
|
||||
|
||||
CC := gcc
|
||||
TARGET := qminfo
|
||||
SRC := qminfo.c
|
||||
OBJ := $(SRC:.c=.o)
|
||||
ARCH ?=
|
||||
SYSROOT ?=
|
||||
|
||||
PKG := qmi-glib
|
||||
CFLAGS := $(shell pkg-config --cflags $(PKG)) -Wall -Wextra -O2
|
||||
LIBS := $(shell pkg-config --libs $(PKG)) -lm
|
||||
ifeq ($(ARCH),aarch64)
|
||||
CROSS_TRIPLE := aarch64-linux-gnu
|
||||
ARCH_CFLAGS :=
|
||||
else ifeq ($(ARCH),armv7)
|
||||
CROSS_TRIPLE := arm-linux-gnueabihf
|
||||
ARCH_CFLAGS := -march=armv7-a -mfpu=vfpv3 -mfloat-abi=hard
|
||||
else ifeq ($(ARCH),armv5)
|
||||
CROSS_TRIPLE := arm-linux-gnueabi
|
||||
ARCH_CFLAGS := -march=armv5te -mfloat-abi=soft
|
||||
else ifeq ($(ARCH),mipsle)
|
||||
CROSS_TRIPLE := mipsel-linux-gnu
|
||||
ARCH_CFLAGS := -march=mips32 -mabi=32 -EL
|
||||
else
|
||||
CROSS_TRIPLE :=
|
||||
ARCH_CFLAGS :=
|
||||
endif
|
||||
|
||||
PREFIX := /usr/local
|
||||
BINDIR := $(PREFIX)/bin
|
||||
DEV := /dev/cdc-wdm0
|
||||
ifdef CROSS_TRIPLE
|
||||
CC := $(CROSS_TRIPLE)-gcc
|
||||
STRIP := $(CROSS_TRIPLE)-strip
|
||||
else
|
||||
CC := gcc
|
||||
STRIP := strip
|
||||
endif
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────
|
||||
TARGET := qminfo
|
||||
SRC := qminfo.c
|
||||
OBJ := $(SRC:.c=.o)
|
||||
|
||||
.PHONY: all clean install uninstall run json check-pkg
|
||||
# pkg-config
|
||||
PKG_QMI := qmi-glib
|
||||
PKG_MBIM := mbim-glib
|
||||
|
||||
ifdef SYSROOT
|
||||
PKG_CONFIG := PKG_CONFIG_SYSROOT_DIR=$(SYSROOT) \
|
||||
PKG_CONFIG_LIBDIR=$(SYSROOT)/usr/lib/pkgconfig:$(SYSROOT)/usr/share/pkgconfig \
|
||||
PKG_CONFIG_PATH= \
|
||||
pkg-config
|
||||
SYSROOT_FLAGS := --sysroot=$(SYSROOT)
|
||||
else ifdef CROSS_TRIPLE
|
||||
PKG_CONFIG := PKG_CONFIG_PATH=/usr/lib/$(CROSS_TRIPLE)/pkgconfig \
|
||||
pkg-config
|
||||
SYSROOT_FLAGS :=
|
||||
else
|
||||
PKG_CONFIG := pkg-config
|
||||
SYSROOT_FLAGS :=
|
||||
endif
|
||||
|
||||
# if mbim-glib — link it (need for QMI over MBIM)
|
||||
MBIM_LIBS := $(shell $(PKG_CONFIG) --libs $(PKG_MBIM) 2>/dev/null)
|
||||
MBIM_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(PKG_MBIM) 2>/dev/null)
|
||||
|
||||
CFLAGS := $(shell $(PKG_CONFIG) --cflags $(PKG_QMI)) \
|
||||
$(MBIM_CFLAGS) \
|
||||
$(ARCH_CFLAGS) \
|
||||
$(SYSROOT_FLAGS) \
|
||||
-Wall -Wextra -O2 -pipe
|
||||
|
||||
LIBS := $(shell $(PKG_CONFIG) --libs $(PKG_QMI)) \
|
||||
$(MBIM_LIBS) \
|
||||
-lm
|
||||
|
||||
PREFIX := /usr/local
|
||||
BINDIR := $(PREFIX)/bin
|
||||
|
||||
.PHONY: all clean install uninstall run json run-mbim json-mbim strip help check-pkg
|
||||
|
||||
all: check-pkg $(TARGET)
|
||||
|
||||
check-pkg:
|
||||
@pkg-config --exists $(PKG) || \
|
||||
{ echo "Error: $(PKG) not found. Install libqmi-glib-dev"; exit 1; }
|
||||
@$(PKG_CONFIG) --exists $(PKG_QMI) || \
|
||||
{ echo "Error: $(PKG_QMI) not found. Install libqmi-glib-dev"; exit 1; }
|
||||
@$(PKG_CONFIG) --exists $(PKG_MBIM) && \
|
||||
echo " mbim-glib: found (QMI over MBIM supported)" || \
|
||||
echo " mbim-glib: not found (QMI over MBIM disabled)"
|
||||
|
||||
$(OBJ): $(SRC)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
@@ -39,6 +99,9 @@ $(OBJ): $(SRC)
|
||||
$(TARGET): $(OBJ)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
strip: $(TARGET)
|
||||
$(STRIP) --strip-all $(TARGET)
|
||||
|
||||
install: $(TARGET)
|
||||
install -d $(DESTDIR)$(BINDIR)
|
||||
install -m 755 $(TARGET) $(DESTDIR)$(BINDIR)/$(TARGET)
|
||||
@@ -46,11 +109,5 @@ install: $(TARGET)
|
||||
uninstall:
|
||||
rm -f $(DESTDIR)$(BINDIR)/$(TARGET)
|
||||
|
||||
run: $(TARGET)
|
||||
sudo ./$(TARGET) $(DEV)
|
||||
|
||||
json: $(TARGET)
|
||||
sudo ./$(TARGET) $(DEV) --json
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ) $(TARGET)
|
||||
+103
-12
@@ -9,8 +9,11 @@
|
||||
* gcc $(pkg-config --cflags --libs qmi-glib) -lm -o qminfo qminfo.c
|
||||
*
|
||||
* run:
|
||||
* sudo ./qminfo /dev/cdc-wdm0
|
||||
* sudo ./qminfo /dev/cdc-wdm0 --json
|
||||
* sudo ./qminfo /dev/cdc-wdm0 # auto-detect (QMI first)
|
||||
* sudo ./qminfo /dev/cdc-wdm0 --json # JSON output
|
||||
* sudo ./qminfo /dev/cdc-wdm0 --qmi # force native QMI
|
||||
* sudo ./qminfo /dev/cdc-wdm0 --mbim # force QMI over MBIM
|
||||
* sudo ./qminfo /dev/cdc-wdm0 --mbim --json
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -86,6 +89,14 @@ static ModemInfo info;
|
||||
static gboolean json_mode = FALSE;
|
||||
static const char *dev_path = NULL;
|
||||
static gint pending = 0;
|
||||
typedef enum {
|
||||
MODE_AUTO, /* try QMI first, fallback to MBIM */
|
||||
MODE_QMI, /* force native QMI */
|
||||
MODE_MBIM, /* force QMI over MBIM */
|
||||
} DeviceMode;
|
||||
|
||||
static DeviceMode device_mode = MODE_AUTO;
|
||||
static gint open_retries = 0; /* retry counter for auto mode */
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* helpers
|
||||
@@ -604,7 +615,7 @@ static void on_lte_ca(QmiClientNas *client, GAsyncResult *res, gpointer ud)
|
||||
snprintf(tmp, sizeof(tmp), "B%u", active_band_to_lte_band(el->lte_band));
|
||||
g_strlcat(info.scc_bands, tmp, sizeof(info.scc_bands));
|
||||
/* For json mode: +40 */
|
||||
snprintf(tmp, sizeof(tmp), "+%u ", active_band_to_lte_band(el->lte_band));
|
||||
snprintf(tmp, sizeof(tmp), "+%u", active_band_to_lte_band(el->lte_band));
|
||||
g_strlcat(info.scc_bands_json, tmp, sizeof(info.scc_bands_json));
|
||||
|
||||
total += bw_index_to_khz((guint8)el->dl_bandwidth);
|
||||
@@ -1052,21 +1063,69 @@ static void on_dms_client(QmiDevice *dev, GAsyncResult *res, gpointer ud)
|
||||
start_dms_chain();
|
||||
}
|
||||
|
||||
static void try_open_device(void); /* forward */
|
||||
|
||||
static void on_device_open(QmiDevice *dev, GAsyncResult *res, gpointer ud)
|
||||
{
|
||||
(void)dev; (void)ud;
|
||||
GError *err = NULL;
|
||||
if (!qmi_device_open_finish(device, res, &err)) {
|
||||
if (device_mode == MODE_AUTO && open_retries == 0) {
|
||||
/* QMI failed in auto mode — retry with MBIM */
|
||||
g_clear_error(&err);
|
||||
open_retries++;
|
||||
try_open_device();
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "Open error: %s\n", err ? err->message : "?");
|
||||
g_clear_error(&err);
|
||||
g_main_loop_quit(loop);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Restore normal log handler after successful open in auto mode */
|
||||
if (device_mode == MODE_AUTO)
|
||||
g_log_set_handler("Qmi",
|
||||
G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL,
|
||||
g_log_default_handler, NULL);
|
||||
|
||||
qmi_device_allocate_client(device, QMI_SERVICE_DMS,
|
||||
QMI_CID_NONE, 10, NULL,
|
||||
(GAsyncReadyCallback)on_dms_client, NULL);
|
||||
}
|
||||
|
||||
/* Open device with flags depending on mode / retry state */
|
||||
static void try_open_device(void)
|
||||
{
|
||||
QmiDeviceOpenFlags flags = QMI_DEVICE_OPEN_FLAGS_PROXY;
|
||||
gboolean mbim;
|
||||
|
||||
switch (device_mode) {
|
||||
case MODE_MBIM:
|
||||
mbim = TRUE;
|
||||
break;
|
||||
case MODE_QMI:
|
||||
mbim = FALSE;
|
||||
break;
|
||||
case MODE_AUTO:
|
||||
default:
|
||||
/* First attempt: QMI; after retry: MBIM */
|
||||
mbim = (open_retries > 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (mbim) {
|
||||
flags |= QMI_DEVICE_OPEN_FLAGS_MBIM;
|
||||
//fprintf(stderr, "Opening as QMI over MBIM\n");
|
||||
} else {
|
||||
flags |= QMI_DEVICE_OPEN_FLAGS_NET_802_3 |
|
||||
QMI_DEVICE_OPEN_FLAGS_NET_NO_QOS_HEADER;
|
||||
}
|
||||
|
||||
qmi_device_open(device, flags, 15, NULL,
|
||||
(GAsyncReadyCallback)on_device_open, NULL);
|
||||
}
|
||||
|
||||
static void on_device_new(GObject *src, GAsyncResult *res, gpointer ud)
|
||||
{
|
||||
(void)src; (void)ud;
|
||||
@@ -1078,12 +1137,19 @@ static void on_device_new(GObject *src, GAsyncResult *res, gpointer ud)
|
||||
g_main_loop_quit(loop);
|
||||
return;
|
||||
}
|
||||
qmi_device_open(device,
|
||||
QMI_DEVICE_OPEN_FLAGS_PROXY |
|
||||
QMI_DEVICE_OPEN_FLAGS_NET_802_3 |
|
||||
QMI_DEVICE_OPEN_FLAGS_NET_NO_QOS_HEADER,
|
||||
15, NULL,
|
||||
(GAsyncReadyCallback)on_device_open, NULL);
|
||||
try_open_device();
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Silent log handler — suppresses GLib/QMI warnings
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
static void log_silent(const gchar *domain,
|
||||
GLogLevelFlags level,
|
||||
const gchar *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
(void)domain; (void)level; (void)message; (void)user_data;
|
||||
/* intentionally empty */
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
@@ -1092,19 +1158,44 @@ static void on_device_new(GObject *src, GAsyncResult *res, gpointer ud)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s <device> [--json]\n", argv[0]);
|
||||
fprintf(stderr, "Usage: %s <device> [--json] [--qmi|--mbim]\n", argv[0]);
|
||||
fprintf(stderr, " --json JSON output\n");
|
||||
fprintf(stderr, " --qmi force native QMI mode\n");
|
||||
fprintf(stderr, " --mbim force QMI over MBIM mode\n");
|
||||
fprintf(stderr, " (default: auto-detect, try QMI first)\n");
|
||||
fprintf(stderr, "Example: %s /dev/cdc-wdm0 --json\n", argv[0]);
|
||||
fprintf(stderr, " %s /dev/cdc-wdm0 --mbim --json\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
dev_path = argv[1];
|
||||
json_mode = (argc >= 3 && strcmp(argv[2], "--json") == 0);
|
||||
dev_path = argv[1];
|
||||
json_mode = FALSE;
|
||||
device_mode = MODE_AUTO;
|
||||
|
||||
for (int i = 2; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--json") == 0)
|
||||
json_mode = TRUE;
|
||||
else if (strcmp(argv[i], "--mbim") == 0)
|
||||
device_mode = MODE_MBIM;
|
||||
else if (strcmp(argv[i], "--qmi") == 0)
|
||||
device_mode = MODE_QMI;
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.chip_temp = -999;
|
||||
info.csq = -1;
|
||||
info.is_umts = FALSE;
|
||||
|
||||
/* In auto-detect mode, suppress QMI warnings that are expected
|
||||
* when probing QMI on an MBIM-only device:
|
||||
* "requested QMI mode but unexpected transport type found"
|
||||
* "Cannot read from istream: connection broken" */
|
||||
if (device_mode == MODE_AUTO) {
|
||||
g_log_set_handler("Qmi",
|
||||
G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL,
|
||||
log_silent, NULL);
|
||||
}
|
||||
|
||||
loop = g_main_loop_new(NULL, FALSE);
|
||||
|
||||
GFile *f = g_file_new_for_path(dev_path);
|
||||
|
||||
Reference in new issue
Block a user