update 2026-09-24 16:56:26

This commit is contained in:
action committed 2026-09-24 16:56:26 +08:00
1 parent b31a5c3878
commit e4cee331e9
6885 files changed
+3240523

No files matched your search

+161
View File
@@ -0,0 +1,161 @@
### 路由器端API:
0. 获取csrfToken(用于POST请求)
```
GET /cgi-bin/luci/admin/store/token
{"token":"xxx"}
```
1. 已安装软件列表
```
GET /cgi-bin/luci/admin/store/installed
[
{
"description": "DDNS.TO内网穿透",
"tags": [
"net",
"tool"
],
"entry": "/cgi-bin/luci/admin/services/ddnsto",
"author": "xiaobao",
"depends": [
"ddnsto",
"luci-app-ddnsto",
"luci-i18n-ddnsto-zh-cn"
],
"title": "DDNS.TO",
"time": 1629356347,
"release": 1,
"website": "https://www.ddnsto.com/",
"name": "ddnsto",
"version": "1.0.0"
}
]
```
2. 安装软件
```
POST /cgi-bin/luci/admin/store/install
token=xxx&package=upnp&autoconf=1&path=/mnt/nvme&enable=1
autoconf=1&path=/mnt/nvme&enable=1 是可选参数,表示安装完以后是否自动配置插件
{"code":0, "stdout":"", "stderr":""}
```
3. 更新软件
```
POST /cgi-bin/luci/admin/store/upgrade
token=xxx&package=upnp
{"code":0, "stdout":"", "stderr":""}
```
4. 卸载软件
```
POST /cgi-bin/luci/admin/store/remove
token=xxx&package=upnp
{"code":0, "stdout":"", "stderr":""}
```
5. 刷新可用软件列表
```
POST /cgi-bin/luci/admin/store/update
token=xxx
{"code":0, "stdout":"", "stderr":""}
```
6. 查询特定软件状态
```
GET /cgi-bin/luci/admin/store/status?package=ddnsto
{
"description": "DDNS.TO内网穿透",
"tags": [
"net",
"tool"
],
"entry": "/cgi-bin/luci/admin/services/ddnsto",
"author": "xiaobao",
"depends": [
"ddnsto",
"luci-app-ddnsto",
"luci-i18n-ddnsto-zh-cn"
],
"installed": true,
"title": "DDNS.TO",
"time": "1629356347",
"release": 1,
"website": "https://www.ddnsto.com/",
"name": "ddnsto",
"version": "1.0.0"
}
{"installed":false}
```
7. 任务状态(日志),已废弃,使用luci-lib-taskd提供的封装
```
GET /cgi-bin/luci/admin/store/log
{
"stdout": "Installing app-meta-ddnsto (1.0.0) to root...\nDownloading http://192.168.9.168:9999/packages/aarch64_cortex-a53/meta/app-meta-ddnsto_1.0.0_all.ipk\nConfiguring app-meta-ddnsto.\n",
"stderr": "",
"code": 206
}
{"stdout":"","stderr":"","code":0}
```
8. 上传安装
```
POST /cgi-bin/luci/admin/store/upload
(文件上传表单,支持文件扩展名".ipk,.run")
{"code":0, "stdout":"", "stderr":""}
```
9. 检查iStore自身更新
```
GET /cgi-bin/luci/admin/store/check_self_upgrade
{"code":500, "msg":"Internal Error"}
{"code":200, "msg":"1.1.2"}
{"code":304, "msg":""}
```
1. 更新iStore自身
> 检查iStore自身更新接口返回code为200时才调用这个接口
```
POST /cgi-bin/luci/admin/store/do_self_upgrade
token=xxx
{"code":0, "stdout":"", "stderr":""}
```
2. 枚举块设备
```
GET /cgi-bin/luci/admin/store/get_block_devices
{"code":500, "msg":"Unable to execute block utility"}
{"code":200, "data":{"sda1":{"dev":"\/dev\/sda1","uuid":"f54566dd-ec58-4e24-9451-bbf75834add3","version":"1.0","type":"ext4","size":"238.46 GB"},"mmcblk0p2":{"dev":"\/dev\/mmcblk0p2","uuid":"dba3d0dc-f072-4e81-a0ac-ac35197fb286","version":"1.0","label":"etc","mount":"\/overlay","type":"ext4","size":"6.87 GB"},"mmcblk0p1":{"dev":"\/dev\/mmcblk0p1","uuid":"8f9564a1-68006e25-c4c26df6-de88ef16","version":"4.0","mount":"\/rom","type":"squashfs","size":"127.99 MB"}}}
```
3. 检查插件是否已经配置过
```
GET /cgi-bin/luci/admin/store/configured?uci=ddnsto
uci参数是uci配置文件的名称,不是包名,不过大部分情况下都是一致的。
{"code":200}
{"code":200, "configured":true}
```
+41
View File
@@ -0,0 +1,41 @@
# Copyright (C) 2016 Openwrt.org
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI based ipk/apk store
LUCI_DESCRIPTION:=luci-app-store is a ipk/apk store developed by LinkEase team
LUCI_DEPENDS:=+curl +tar +libuci-lua +mount-utils +luci-lib-taskd
LUCI_EXTRA_DEPENDS:=luci-lib-taskd (>=1.0.19)
LUCI_PKGARCH:=all
PKG_VERSION:=0.2.1-r1
# PKG_RELEASE MUST be empty for luci.mk
PKG_RELEASE:=
ISTORE_UI_VERSION:=0.2.0
ISTORE_UI_RELEASE:=2
PKG_HASH:=9aec741aa5675347bc5a818acb285901bddf309af8ae402dd898336751de38be
PKG_SOURCE_URL_FILE:=v$(ISTORE_UI_VERSION)-$(ISTORE_UI_RELEASE).tar.gz
PKG_SOURCE:=istore-ui-$(PKG_SOURCE_URL_FILE)
PKG_SOURCE_URL:=https://github.com/linkease/istore-ui/archive/refs/tags
PKG_MAINTAINER:=jjm2473 <jjm2473@gmail.com>
TARGET_CONFIGURE_OPTS= FRONTEND_DIST="$(BUILD_DIR)/istore-ui-$(ISTORE_UI_VERSION)-$(ISTORE_UI_RELEASE)/app-store-ui/src/dist" APP_STORE_VERSION="$(PKG_VERSION)"
TARGET_CONFIGURE_OPTS+= SED="$(SED)"
TARGET_CONFIGURE_OPTS+= USE_APK="$(CONFIG_USE_APK)"
define Package/luci-app-store/conffiles
/etc/.app_store.id
/etc/config/istore
endef
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature
+3
View File
@@ -0,0 +1,3 @@
# luci-app-store
OpenWRT应用商店
File diff suppressed because it is too large. Load diff
+64
View File
@@ -0,0 +1,64 @@
<%+header%>
<%
local jsonc = require "luci.jsonc"
%>
<script>
(function(){
var vue_prefix="<%=prefix%>";
var myurl = window.location.pathname;
window.addEventListener('popstate', function(){
if (myurl != window.location.pathname
&& window.location.pathname != vue_prefix
&& ! window.location.pathname.startsWith(vue_prefix+'/')) {
window.location.href = window.location.pathname;
}
});
window.vue_base = vue_prefix + '/';
// window.istore_api_base = "https://istore.istoreos.com";
// window.istore_icon_base = "https://istore.linkease.com.cdn.koolcenter.com";
window.vue_lang_data = '/luci-static/istore/i18n/<%=lang%>.json?v=<%=id.version%>';
window.vue_lang = '<%=lang%>';
window.token = "<%=token%>";
window.device_id = {arch:"<%=id.arch%>",uid:"<%=id.uid%>",version:"<%=id.version%>"};
window.istore_features = <%=jsonc.stringify(features)%>.filter(f => f !== '_lua_force_array_');
window.istore_config = <%=jsonc.stringify(user_config or {})%>;
})();
</script>
<h2 name="content"><%:iStore%>
<a onclick="void(0)" href="https://github.com/linkease/istore/issues/22" target="_blank" style="text-decoration: none;">
v<%=id.version%>
</a>
</h2>
<link rel="stylesheet" href="/luci-static/istore/style.css?v=<%=id.version%>">
<div id="app">
</div>
<%+tasks/embed%>
<script>
(function() {
let beforeunloadRegistered = false;
taskd.show_mask_on_stopped = true;
window.istore_log = function(flush_menu_onclose, onExit) {
if (flush_menu_onclose && !beforeunloadRegistered) {
beforeunloadRegistered = true;
window.addEventListener("beforeunload", function(event) {
try { window.L.ui.menu.flushCache() } catch (e) { }
return true;
});
}
taskd.show_log("istore", true, onExit);
};
})();
<%
local taskd = require "luci.model.tasks"
local status = taskd.status("istore")
if status.running or status.exit_code ~= 404 then
-%>
window.istore_log(true);
<%
end
%>
</script>
<script type="module" crossorigin src="/luci-static/istore/index.js?v=<%=id.version%>"></script>
<%+footer%>
+564
View File
@@ -0,0 +1,564 @@
#!/bin/sh
# this script MUST supports executting without luci-app-store installed,
# so we can use this script to install luci-app-store itself
action=${1}
shift
if [ "${action:0:9}" = "AUTOCONF=" ]; then
export "ISTORE_${action}"
exec "$0" "$@"
fi
IS_ROOT=/tmp/is-root
TMP_SELF_COPY=/var/run/cloned-is-opkg
USE_APK=false
DISABLE_MIRROR=false
if [[ -s /etc/apk/arch ]]; then
USE_APK=true
fi
if $USE_APK; then
LISTS_DIR=${IS_ROOT}/apk
APK_CONF=${IS_ROOT}/etc/apk.conf
FEEDS_SERVER=https://istore.istoreos.com/repo-apk
FEEDS_SERVER_MIRRORS="https://repo.istoreos.com/repo-apk"
ISTORE_INDEX=$FEEDS_SERVER/all/store/packages.adb
META_DIR=/lib/apk
ARCH=`cat /rom/etc/apk/arch /etc/apk/arch 2>/dev/null | head -1`
else
LISTS_DIR_O=/tmp/opkg-lists
LISTS_DIR=${IS_ROOT}${LISTS_DIR_O}
OPKG_CONF_DIR=${IS_ROOT}/etc/opkg
OPKG_CONF_DIR_M=${IS_ROOT}/etc/opkg_m
FEEDS_SERVER=https://istore.istoreos.com/repo
FEEDS_SERVER_MIRRORS="https://repo.istoreos.com/repo"
ISTORE_INDEX=$FEEDS_SERVER/all/store/Packages.gz
META_DIR=/usr/lib/opkg
ARCH=`sed -n -e 's/^Architecture: *\([^ ]\+\) *$/\1/p' /rom/usr/lib/opkg/info/libc.control /usr/lib/opkg/info/libc.control 2>/dev/null | head -1`
fi
# for istore self upgrade
ISTORE_PKG=luci-app-store
ISTORE_DEP_PKGS="luci-lib-taskd luci-lib-xterm taskd"
NEWLINE=$'\n'
is_init() {
mkdir -p ${LISTS_DIR} ${IS_ROOT}/etc ${IS_ROOT}/var
if $USE_APK; then
return 0
fi
cat /etc/opkg.conf | grep -Fv lists_dir | grep -Fv check_signature > ${IS_ROOT}/etc/opkg.conf
cp ${IS_ROOT}/etc/opkg.conf ${IS_ROOT}/etc/opkg_o.conf
echo >> ${IS_ROOT}/etc/opkg.conf
echo "lists_dir ext ${LISTS_DIR}" >> ${IS_ROOT}/etc/opkg.conf
# create opkg_o.conf for executting 'opkg update' with offline-root, so we don't overwrite system opkg list
echo >> ${IS_ROOT}/etc/opkg_o.conf
echo "lists_dir ext ${LISTS_DIR_O}" >> ${IS_ROOT}/etc/opkg_o.conf
cp -au /etc/opkg ${IS_ROOT}/etc/
[ -e ${IS_ROOT}/var/lock ] || ln -s /var/lock ${IS_ROOT}/var/lock
}
apk_wrap() {
APK_CONFIG=${APK_CONF} apk "$@"
}
opkg_wrap() {
OPKG_CONF_DIR=${OPKG_CONF_DIR} opkg -f ${IS_ROOT}/etc/opkg.conf "$@"
}
simple_apk_opkg() {
local action="$1"
shift
if $USE_APK; then
case "$action" in
"install")
action=add
;;
"remove")
action=del
;;
esac
apk_wrap "$action" "$@"
else
opkg_wrap "$action" "$@"
fi
}
do_in_mirrors() {
local server
if ! $DISABLE_MIRROR; then
local newpath="/usr/libexec/istore/mirror-bin:$PATH"
for server in $FEEDS_SERVER_MIRRORS ; do
echo "Try mirror server $server"
PATH="$newpath" IS_ORIG_SERVER=$FEEDS_SERVER IS_MIRROR_SERVER=$server "$@" && return 0
done
DISABLE_MIRROR=true
fi
echo "Try origin server $FEEDS_SERVER"
"$@"
}
apk_wrap_mirrors() {
do_in_mirrors apk_wrap "$@"
}
opkg_wrap_mirrors() {
do_in_mirrors opkg_wrap "$@"
}
do_install_in_mirrors() {
if $USE_APK; then
apk_wrap_mirrors add "$@"
else
opkg_wrap_mirrors install "$@"
fi
}
do_upgrade_in_mirrors() {
if $USE_APK; then
apk_wrap_mirrors upgrade "$@"
else
opkg_wrap_mirrors upgrade "$@"
fi
}
alias fcurl='curl -L --fail --show-error'
check_space() {
local free="$((`df -kP / | awk 'NR==2 {print $4}'` >> 10 ))"
if [ "$free" -lt 1 ]; then
echo "Root disk full!" >&2
exit 1
fi
return 0
}
update() {
if [ -z "${ARCH}" ]; then
echo "Get architecture failed" >&2
return 1
fi
echo "Fetch feed list for ${ARCH}"
if $USE_APK; then
rm -rf ${IS_ROOT}/var/tmp ${IS_ROOT}/etc/arch ${IS_ROOT}/etc/istore.pem
mkdir -p ${IS_ROOT}/var/tmp
fcurl --no-progress-meter -o ${IS_ROOT}/var/tmp/meta.conf "${FEEDS_SERVER}/all/meta.conf" && \
fcurl --no-progress-meter -o ${IS_ROOT}/var/tmp/all.conf "${FEEDS_SERVER}/all/isfeeds.conf" && \
fcurl --no-progress-meter -o ${IS_ROOT}/var/tmp/arch.conf "${FEEDS_SERVER}/${ARCH}/isfeeds.conf" && \
fcurl --no-progress-meter -o ${IS_ROOT}/etc/arch "${FEEDS_SERVER}/${ARCH}/archlist.conf" || \
return 1
echo "cache-dir $LISTS_DIR" > ${APK_CONF}
cat ${IS_ROOT}/var/tmp/arch.conf ${IS_ROOT}/var/tmp/all.conf ${IS_ROOT}/var/tmp/meta.conf >> ${APK_CONF}
local line
while read -r line; do
if [[ -n "$line" ]]; then
grep -Fxq "$line" /etc/apk/arch || echo "$line" >> /etc/apk/arch
fi
done < ${IS_ROOT}/etc/arch
sync /etc/apk/arch
if [[ ! -s /etc/apk/keys/istore.pem && ! -s /etc/apk/keys/istore-tmp.pem ]]; then
fcurl --no-progress-meter -o ${IS_ROOT}/etc/istore.pem "${FEEDS_SERVER}/istore-apk.pem" && \
cp -a ${IS_ROOT}/etc/istore.pem /etc/apk/keys/istore-tmp.pem || \
return 1
fi
else
fcurl --no-progress-meter -o ${OPKG_CONF_DIR}/meta.conf "${FEEDS_SERVER}/all/meta.conf" && \
fcurl --no-progress-meter -o ${OPKG_CONF_DIR}/all.conf "${FEEDS_SERVER}/all/isfeeds.conf" && \
fcurl --no-progress-meter -o ${OPKG_CONF_DIR}/arch.conf "${FEEDS_SERVER}/${ARCH}/isfeeds.conf" || \
return 1
fi
echo "Update feeds index"
if $USE_APK; then
apk_wrap update
else
opkg -f ${IS_ROOT}/etc/opkg_o.conf --offline-root ${IS_ROOT} update
fi
return 0
}
update_if_outdate() {
local idle_t=$((`date '+%s'` - `date -r ${IS_ROOT}/.last_force_ts '+%s' 2>/dev/null || echo '0'`))
[ $idle_t -gt ${1:-120} ] || return 2
update || return 1
touch ${IS_ROOT}/.last_force_ts
return 0
}
get_online_version() {
local index="$1"
local pkg="$2"
if $USE_APK; then
apk --cache-dir $LISTS_DIR --cache-max-age 0 --repositories-file /dev/null --repository "$index" update >/dev/null 2>&1
apk --cache-dir $LISTS_DIR --cache-max-age 0 --repositories-file /dev/null --repository "$index" query --available --fields version "$pkg" 2>/dev/null | grep -Fm1 'Version: ' | sed 's/^Version: //'
else
curl --connect-timeout 2 --max-time 5 -s "$index" | gunzip | grep -FA10 "Package: $pkg" | grep -Fm1 'Version: ' | sed 's/^Version: //'
fi
}
get_local_version() {
local pkg="$1"
if $USE_APK; then
apk query --installed --fields version "$pkg" 2>/dev/null | grep -Fm1 'Version: ' | sed 's/^Version: //'
else
grep -Fm1 'Version: ' /usr/lib/opkg/info/$pkg.control 2>/dev/null | sed 's/^Version: //'
fi
}
check_self_upgrade() {
local newest=`get_online_version "$ISTORE_INDEX" "$ISTORE_PKG"`
local current=`get_local_version "$ISTORE_PKG"`
if [ "v$newest" = "v" -o "v$current" = "v" ]; then
echo "Check version failed!" >&2
exit 255
fi
if [ "$newest" != "$current" ]; then
echo "$newest"
fi
return 0
}
do_self_upgrade_0() {
simple_apk_opkg upgrade ${ISTORE_DEP_PKGS} && simple_apk_opkg upgrade ${ISTORE_PKG}
}
do_self_upgrade() {
check_mtime || return 1
local newest=`get_online_version "$ISTORE_INDEX" "$ISTORE_PKG"`
local current=`get_local_version "$ISTORE_PKG"`
if [ "v$newest" = "v" -o "v$current" = "v" ]; then
echo "Check version failed!" >&2
return 1
fi
if [ "$newest" = "$current" ]; then
echo "Already the latest version!" >&2
return 1
fi
if $USE_APK || opkg_wrap info ${ISTORE_PKG} | grep -qFm1 "Version: $newest"; then
do_self_upgrade_0 && return 0
update_if_outdate || return 1
do_self_upgrade_0
else
update_if_outdate || return 1
do_self_upgrade_0
fi
}
check_mtime() {
local file
if $USE_APK; then
file=${APK_CONF}
else
file=${OPKG_CONF_DIR}/arch.conf
fi
find "$file" -mtime -1 2>/dev/null | grep -q . || update
}
wrapped_in_update() {
check_mtime || return 1
eval "$@" && return 0
update_if_outdate || return 1
eval "$@"
}
refresh_installed() {
local pkg
for pkg in $@; do
[[ $pkg == app-meta-* ]] || continue
pkg="$META_DIR/meta/${pkg#app-meta-}.json"
[[ -f "$pkg" ]] && touch "$pkg"
done
return 0
}
step_upgrade() {
local pkg
local pkgs=""
local metapkg=""
for pkg in $@; do
if [[ $pkg == app-meta-* ]]; then
metapkg="$metapkg $pkg"
else
pkgs="$pkgs $pkg"
fi
done
if [ -n "$pkgs" ]; then
do_upgrade_in_mirrors $pkgs || return 1
fi
if [ -n "$metapkg" ]; then
do_upgrade_in_mirrors $metapkg || return 1
refresh_installed $metapkg
fi
return 0
}
new_upgrade() {
check_mtime || return 1
local metapkg=`echo "$@" | sed 's/ /\n/g' | grep -F app-meta-`
if [[ -z "$metapkg" ]] || [[ -z "$(get_local_version $metapkg)" ]]; then
true
else
update_if_outdate
fi
wrapped_in_update step_upgrade "$@"
}
remove() {
if $USE_APK; then
apk_wrap del -r "$@"
else
opkg_wrap --autoremove --force-removal-of-dependent-packages remove "$@"
fi
}
autoconf_to_env() {
local autoconf path enable
eval "local autoconf=$ISTORE_AUTOCONF"
export -n ISTORE_AUTOCONF
export -n ISTORE_DONT_START
export -n ISTORE_CONF_DIR
export -n ISTORE_CACHE_DIR
export -n ISTORE_PUBLIC_DIR
export -n ISTORE_DL_DIR
ISTORE_AUTOCONF=$autoconf
if [ -n "$path" ]; then
export ISTORE_CONF_DIR="$path/Configs"
export ISTORE_CACHE_DIR="$path/Caches"
export ISTORE_PUBLIC_DIR="$path/Public"
export ISTORE_DL_DIR="$ISTORE_PUBLIC_DIR/Downloads"
fi
[ "$enable" = 0 ] && export ISTORE_DONT_START="1"
}
try_autoconf() {
[ -n "$ISTORE_AUTOCONF" ] || return 0
autoconf_to_env
[ -n "$ISTORE_AUTOCONF" ] || return 1
echo "Auto configure $ISTORE_AUTOCONF"
PATH="$CLEANPATH" /usr/libexec/istorea/${ISTORE_AUTOCONF}.sh
}
try_upgrade_depends() {
local pkg="$1"
if [[ $pkg == app-meta-* ]]; then
local deps
if $USE_APK; then
deps=$(apk --repositories-file /dev/null info -R "$pkg" | tail +2 | grep -vFw libc | xargs echo)
else
deps=$(grep '^Depends: ' "/usr/lib/opkg/info/$pkg.control" | busybox sed -e 's/^Depends: //' -e 's/,/\n/g' -e 's/ //g' | grep -vFw libc | xargs echo)
fi
[ -z "$deps" ] || do_install_in_mirrors $deps
fi
return 0
}
if $USE_APK; then
CMD_INSTALLED="apk --repositories-file /dev/null info | cut -d' ' -f1 | sort -u"
CMD_INSTALL="apk add --allow-untrusted"
else
CMD_INSTALLED="opkg list-installed | cut -d' ' -f1 | sort -u"
CMD_INSTALL="opkg install"
fi
dotrun() {
local path="$1"
[ -f "$path" ] || { echo "file not found: $path" >&2; return 1; }
ls -l "$path"
local md5=$(md5sum "$path" 2>/dev/null | cut -d' ' -f1)
local ts=$(date '+%s')
#local date=$(date '+%Y-%m-%d_%H-%M-%S')
echo "MD5: $md5"
echo "Save installed pkg list before installing"
sh -c "$CMD_INSTALLED" > "/tmp/is-root/tmp/pre_$md5.txt"
if echo "$path" | grep -q '\.run$'; then
echo "Executing .run file"
chmod 0755 "$path" && "$path"
else
echo "Installing pkg file"
$CMD_INSTALL "$path"
fi
local RET=$?
rm -f "$path"
if [ -s "/tmp/is-root/tmp/pre_$md5.txt" ]; then
echo "Save installed pkg list after installing"
sh -c "$CMD_INSTALLED" > "/tmp/is-root/tmp/post_$md5.txt"
grep -Fxf "/tmp/is-root/tmp/pre_$md5.txt" -v "/tmp/is-root/tmp/post_$md5.txt" > "/tmp/is-root/tmp/added_$md5.txt"
if [ -s "/tmp/is-root/tmp/added_$md5.txt" ]; then
echo "The following packages were added:"
cat "/tmp/is-root/tmp/added_$md5.txt"
mkdir -p /usr/share/istore/run-records
path="${path##*/}"
path="${path//\\/\\\\}" #\
path="${path//\"/\\\"}" #"
path="${path//$NEWLINE/\\n}" # \n
path="${path//^M/\\r}" # \r
echo "{\"id\":\"$ts-$md5\",\"ts\":$ts,\"md5\":\"$md5\",\"file\":\"$path\"}" > /usr/share/istore/run-records/$ts-$md5.txt
cat "/tmp/is-root/tmp/added_$md5.txt" >> /usr/share/istore/run-records/$ts-$md5.txt
fi
fi
rm -f "/tmp/is-root/tmp/pre_$md5.txt" "/tmp/is-root/tmp/post_$md5.txt" "/tmp/is-root/tmp/added_$md5.txt"
return $RET
}
run_records() {
local record
local file
echo "["
for record in /usr/share/istore/run-records/*.txt; do
[ -f "$record" ] || continue
echo "`head -1 "$record"`,"
done | head -c -2
echo ""
echo "]"
}
if $USE_APK; then
CMD_REMOVE="apk del"
else
CMD_REMOVE="opkg --autoremove remove"
fi
unrun() {
local id="$1"
[ -s "/usr/share/istore/run-records/$id.txt" ] || { echo "record not found: $id" >&2; return 1; }
mkdir -p /tmp/is-root/tmp
echo "The following packages will be removed:"
tail -n +2 "/usr/share/istore/run-records/$id.txt" > "/tmp/is-root/tmp/to_unrun_$id.txt"
cat "/tmp/is-root/tmp/to_unrun_$id.txt"
local round max_round=6
for round in `seq 1 $max_round`; do
if [ $round == $max_round ]; then
$CMD_REMOVE `cat "/tmp/is-root/tmp/to_unrun_$id.txt"`
else
$CMD_REMOVE `cat "/tmp/is-root/tmp/to_unrun_$id.txt"` 2>/dev/null && break
fi
done
sh -c "$CMD_INSTALLED" > "/tmp/is-root/tmp/post_unrun_$id.txt"
grep -Fxf "/tmp/is-root/tmp/post_unrun_$id.txt" "/tmp/is-root/tmp/to_unrun_$id.txt" > "/tmp/is-root/tmp/remain_unrun_$id.txt"
if [ -s "/tmp/is-root/tmp/remain_unrun_$id.txt" ]; then
echo "The following packages failed to be removed:"
cat "/tmp/is-root/tmp/remain_unrun_$id.txt"
else
echo "All packages removed successfully."
rm -f "/usr/share/istore/run-records/$id.txt"
fi
rm -f "/tmp/is-root/tmp/to_unrun_$id.txt" "/tmp/is-root/tmp/post_unrun_$id.txt" "/tmp/is-root/tmp/remain_unrun_$id.txt"
return 0
}
usage() {
echo "usage: is-opkg sub-command [arguments...]"
echo "where sub-command is one of:"
echo " update Update list of available packages"
echo " upgrade <pkgs> Upgrade package(s)"
echo " install <pkgs> Install package(s)"
echo " remove <pkgs|regexp> Remove package(s)"
echo " info [pkg|regexp] Display all info for <pkg>"
echo " list-upgradable List installed and upgradable packages"
echo " check_self_upgrade Check iStore upgrade"
echo " do_self_upgrade Upgrade iStore"
echo " arch Show libc architecture"
echo " opkg sys opkg wrap"
echo " dotrun {path} install .run/.ipk/.apk"
echo " run_records list .run/.ipk/.apk install records"
echo " del_record {id} delete .run/.ipk/.apk install record"
echo " unrun {id} Remove installed packages by .run/.ipk/.apk"
exit 1
}
if [[ "$action" = "do_self_upgrade" && "$0" != "$TMP_SELF_COPY" ]]; then
echo "copy self $0 to $TMP_SELF_COPY when self upgrade"
cp -af "$0" "$TMP_SELF_COPY" || exit 1
exec "$TMP_SELF_COPY" do_self_upgrade "$@" || exit 1
fi
is_init >/dev/null 2>&1
CLEANPATH="$PATH"
case $action in
"update"|"install"|"upgrade"|"opkg"|"check_self_upgrade"|"do_self_upgrade"|"dotrun")
if [[ "`uci -q get istore.istore.ipv4`" = "1" ]]; then
export PATH="/usr/libexec/istore/ipv4-bin:$CLEANPATH"
fi
;;
esac
case $action in
"update")
update
;;
"install")
check_space
wrapped_in_update do_install_in_mirrors "$@" && refresh_installed "$1" && try_upgrade_depends "$1" && try_autoconf
;;
"autoconf")
try_autoconf
;;
"upgrade")
new_upgrade "$@"
;;
"remove")
remove "$@" || remove "$@"
;;
"info")
if $USE_APK; then
apk_wrap query "$@"
else
opkg_wrap info "$@"
fi
;;
"list-upgradable")
if $USE_APK; then
apk_wrap query --upgradable --summarize package '*'
else
opkg_wrap list-upgradable
fi
;;
"check_self_upgrade")
check_self_upgrade
;;
"do_self_upgrade")
check_space
do_self_upgrade
;;
"arch")
echo "$ARCH"
;;
"opkg")
opkg_wrap "$@"
;;
"dotrun")
dotrun "$@"
;;
"run_records")
run_records
;;
"del_record")
rm -f "/usr/share/istore/run-records/$1.txt"
;;
"unrun")
unrun "$1"
;;
"link_meta")
[[ -d "$META_DIR/meta" ]] || mkdir -p "$META_DIR/meta"
[ -e /tmp/run/istore-meta ] || ln -sf "$META_DIR" /tmp/run/istore-meta
;;
*)
usage
;;
esac
+8
View File
@@ -0,0 +1,8 @@
config istore 'istore'
# option hide_docker '0'
# option ignore_arch '0'
# option last_path '/mnt/nvme'
# option channel 'istore'
# option super_arch 'x86_64'
# option super_arch 'aarch64'
# option ipv4 '0'
+55
View File
@@ -0,0 +1,55 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2016 OpenWrt.org
START=45
boot() {
local ARCH=`/bin/is-opkg arch`
generate_store_id $ARCH
generate_super_arch $ARCH
/bin/is-opkg link_meta
}
generate_store_id() {
[ -s /etc/.app_store.id ] && return 0
local ARCH=$1
local iface HASH
for iface in eth0 br-lan; do
if [ -e /sys/class/net/$iface/address ]; then
HASH=`md5sum /sys/class/net/$iface/address | cut -d ' ' -f1`
break
fi
done
if [ -z "$HASH" ]; then
HASH=`dd if=/dev/urandom bs=512 count=1 2>/dev/null | md5sum | cut -d ' ' -f1`
fi
echo "{\"arch\":\"${ARCH}\", \"uid\":\"${HASH}\"}" > /etc/.app_store.id
}
generate_super_arch() {
local ARCH=$1
local super_arch
case "$ARCH" in
arm*)
super_arch="arm"
;;
i386)
super_arch="x86"
;;
x86_64)
super_arch="x86_64"
;;
*)
super_arch="${ARCH%%_*}"
;;
esac
local old=`uci -q get istore.istore.super_arch`
[ "$old" = "$super_arch" ] && return 0
uci -q batch <<-EOF >/dev/null
set istore.istore.super_arch=$super_arch
commit istore
EOF
}
@@ -0,0 +1,15 @@
#!/bin/sh
/etc/init.d/istore boot
if [ -z "`uci -q get istore.istore.hide_docker`" ] && ! which docker >/dev/null; then
uci -q batch <<-EOF >/dev/null
set istore.istore.hide_docker=1
commit istore
EOF
fi
# remove tmp keys that used for self-installation, which is not needed after installation
rm -f /etc/apk/keys/istore-tmp.pem
rm -rf /tmp/luci-indexcache /tmp/luci-modulecache
+305
View File
@@ -0,0 +1,305 @@
#!/bin/sh
#set -x
#IS_DEBUG=1
IS_ROOT=/tmp/is-backup
APP_LIST_FILE=/etc/istore/app.list
BACKUP_CONFIG_FILE=/etc/config/istore
USE_APK=false
[[ -s /etc/apk/arch ]] && USE_APK=true
action=${1}
shift
is_init() {
mkdir -p ${IS_ROOT}
}
opkg_list_installed_packages() {
local target=$1
local dir
local OPKG_INFO_DIR
case $target in
"preinstalled")
OPKG_INFO_DIR="/rom/usr/lib/opkg/info"
;;
"userinstalled")
OPKG_INFO_DIR="/overlay/upper/usr/lib/opkg/info /ext_overlay/upper/usr/lib/opkg/info"
;;
"allinstalled")
OPKG_INFO_DIR="/usr/lib/opkg/info"
;;
*)
echo "invalid target"
exit
;;
esac
for dir in $OPKG_INFO_DIR ; do
[ -d "$dir" ] || continue
(cd "$dir" && find . -depth -maxdepth 1 -name "*.list" -type f | sed 's#^\./\(.*\)\.list$#\1#g')
done
}
ipk_build() {
PKG_NAME_TEMP=$1
IPK_OUTPUT_DIR=$2
UCI_BAK_DIR="/etc/istore/uci-defaults_bak/"
UCI_DEF_DIR="etc/uci-defaults"
local OPKG_INFO_DIR="/usr/lib/opkg/info/"
[ -n "${PKG_NAME_TEMP}" ] || exit 1
#get real pkg name in opkg
PKG_NAME_TEMP=`cat ${IS_ROOT}/all_installed_package.list | sort -u | grep "^${PKG_NAME_TEMP}" | head -n 1`
[ -n "${PKG_NAME_TEMP}" ] || exit 1
PKG_NAME=`cat ${OPKG_INFO_DIR}${PKG_NAME_TEMP}.control | grep "^Package: " | cut -d ' ' -f2`
PKG_VER=`cat ${OPKG_INFO_DIR}${PKG_NAME}.control | grep "^Version: " | cut -d ' ' -f2`
PKG_ARCH=`cat ${OPKG_INFO_DIR}${PKG_NAME}.control | grep "^Architecture: " | cut -d ' ' -f2`
IPK_FILE_NAME="${PKG_NAME}_${PKG_VER}_${PKG_ARCH}"
rm -rf ${IS_ROOT}/${IPK_FILE_NAME}
mkdir -p ${IS_ROOT}/${IPK_FILE_NAME}
#(1)make CONTROL dir; (2)copy control file to dir
cd ${IS_ROOT}/${IPK_FILE_NAME}
mkdir -p CONTROL
for control_file in `ls ${OPKG_INFO_DIR}${PKG_NAME}.* | grep -v ".list$"`; do
file=${control_file##*/}
suffix=${file##*.}
cp ${control_file} CONTROL/${suffix}
done
#(1)make DATA depend dir; (2)copy uci-defaults_bak file to dir; (3)copy other file to dir
for pkgfile in `cat ${OPKG_INFO_DIR}${PKG_NAME}.list | cut -b 2-`; do
file=${pkgfile##*/}
path=${pkgfile%/*}
mkdir -p ${path}
if [ `echo "${path}" | grep "^${UCI_DEF_DIR}"` ]; then
cp "${UCI_BAK_DIR}${file}" "${pkgfile}"
else
cp "/${pkgfile}" "${pkgfile}"
fi
done
#call ipkg-build script to build ipk
/usr/libexec/istore/ipkg-build ${IS_ROOT}/${IPK_FILE_NAME} ${IPK_OUTPUT_DIR}
echo "${IPK_FILE_NAME}.ipk" >> ${IPK_OUTPUT_DIR}/appdepipk.list
[ -n "${IS_DEBUG}" ] || rm -rf ${IS_ROOT}/${IPK_FILE_NAME}
}
# if arg is NULL, use light backup, otherwise use local backup
backup() {
if [ -n "$1" ]; then
if $USE_APK; then
echo "does not support apk package manager" >&2
exit 1
fi
BACKUP_PATH=$1
fi
if $USE_APK; then
( cd /lib/apk/packages && ls *.list ) | grep '^app-meta-' | sed 's/.list$//' | sort -u > ${IS_ROOT}/istore_installed_package.list
else
#write user installed package list to file
opkg_list_installed_packages "userinstalled" 2>/dev/null | sort -u > ${IS_ROOT}/user_installed_package.list
#write installed package list by istore feed to file
cat ${IS_ROOT}/user_installed_package.list | \
grep '^app-meta-' > ${IS_ROOT}/istore_installed_package.list
fi
#if no input backup path, only back app.list
mkdir -p /etc/istore
cp ${IS_ROOT}/istore_installed_package.list ${APP_LIST_FILE}
echo "backup installed package list to ${APP_LIST_FILE}"
if [ ! -n "${BACKUP_PATH}" ]; then
echo "backup success"
exit 0
fi
if [ ! -d "${BACKUP_PATH}" ] && ! mkdir -p "${BACKUP_PATH}" ; then
echo "invalid backup path, can not backup ipk"
exit 1
fi
#write all installed package list to file
opkg_list_installed_packages "allinstalled" 2>/dev/null | sort -u > ${IS_ROOT}/all_installed_package.list
#write system pre installed package list to file
opkg_list_installed_packages "preinstalled" 2>/dev/null | sort -u > ${IS_ROOT}/pre_installed_package.list
#write installed packages and depends list by istore feed to file by depend sequence
appdep_list=""
temp_list=`cat ${IS_ROOT}/istore_installed_package.list | sed 's/^/\t/'`
while [ -n "${temp_list}" ]
do
#get real pkg name
for PKG_NAME_TEMP in ${temp_list}; do
REAL_PKG_NAME=`cat ${IS_ROOT}/all_installed_package.list | sort -u | grep "^${PKG_NAME_TEMP}" | head -n 1`
if [ "${REAL_PKG_NAME}" != "${PKG_NAME_TEMP}" ]; then
temp_list=`echo "${temp_list}" | sed 's/^\t'"${PKG_NAME_TEMP}"'$/\t'"${REAL_PKG_NAME}"'/'`
fi
done
appdep_list=`echo -e "${temp_list}\n${appdep_list}"`
[ -n "${IS_DEBUG}" ] && echo -e "temp_list:\n""${temp_list}"
[ -n "${IS_DEBUG}" ] && echo -e "appdep_list:\n""${appdep_list}"
temp_list=`echo "${temp_list}" | xargs opkg depends | grep -v "depends on:" | grep -v " (>= " | grep -v " (= " | sort -u`
done
appdep_list_all=`echo "${appdep_list}" | cut -f2 | grep -v "^$" | awk '!seen[$0]++'`
[ -n "${IS_DEBUG}" ] && echo -e "appdep_list_all:\n""${appdep_list_all}"
echo "${appdep_list_all}" > ${IS_ROOT}/appdep.list
#3.rebuild all istore installed package to ipk and backup to userdata partation
# 4. create dir
date=$(date +%Y-%m%d-%H%M)
if [ ! -d "$BACKUP_PATH/backup_istore_$date" ];then
mkdir $BACKUP_PATH/backup_istore_$date
fi
cp ${IS_ROOT}/istore_installed_package.list $BACKUP_PATH/backup_istore_$date/app.list
cp ${IS_ROOT}/appdep.list $BACKUP_PATH/backup_istore_$date/appdep.list
#only backup non pre installed ipk
cp ${IS_ROOT}/appdep.list ${IS_ROOT}/appdep_strip.list
for pre_installed_pkg in `cat ${IS_ROOT}/appdep.list ${IS_ROOT}/pre_installed_package.list | sort -n | uniq -d`; do
sed -i '/^'"$pre_installed_pkg"'$/d' ${IS_ROOT}/appdep_strip.list
done
rm -f $BACKUP_PATH/backup_istore_$date/appdepipk.list
echo "build ipk"
for pkg_name in `cat ${IS_ROOT}/appdep_strip.list`; do
ipk_build ${pkg_name} $BACKUP_PATH/backup_istore_$date
done
# 5. create tar.gz file,and remove dir
cd $BACKUP_PATH
echo "write backup file to $BACKUP_PATH/backup_istore_$date.backup.tar.gz"
tar -czf $BACKUP_PATH/backup_istore_$date.backup.tar.gz backup_istore_$date
rm -rf $BACKUP_PATH/backup_istore_$date
echo "backup success"
}
# if arg is NULL, use light backup, otherwise use local backup
restore() {
if [ -n "$1" ]; then
if $USE_APK; then
echo "does not support apk package manager" >&2
exit 1
fi
BACKUP_PATH_FILE=$1
else
echo "install package by ${APP_LIST_FILE}"
is-opkg update
for app in `cat ${APP_LIST_FILE}`; do
#skip resotre istore self
[ "A${app}" == "A""luci-app-store" ] && continue
is-opkg install ${app}
done
exit 0
fi
if [ ! -f "${BACKUP_PATH_FILE}" ];then
echo "invalid backup file, can not restore ipk"
exit 1
fi
#1. Unzip file to dir
BACKUP_PATH_FILE_NAME=${BACKUP_PATH_FILE##*/}
BACKUP_PATH=/tmp/${BACKUP_PATH_FILE_NAME%.backup.tar.gz*}
if [ -d "$BACKUP_PATH" ];then
rm -rf $BACKUP_PATH
fi
mkdir -p $BACKUP_PATH
echo "unpack input file..."
# fix tar path error
tar -zxf ${BACKUP_PATH_FILE} -C /tmp/
echo "check file"
if [ ! -f "${BACKUP_PATH}/appdep.list" ];then
echo "no available appdep.list, can not restore ipk"
exit 1
fi
echo "check success"
#2. install ipk by backup path
echo "restore begin"
( cd ${BACKUP_PATH}; opkg install `cat ${BACKUP_PATH}/appdepipk.list` )
#3. rm dir
rm -rf ${BACKUP_PATH}
echo "restore success"
}
get_support_backup_features() {
echo "light_backup"
#istore custom img mean support local_backup
if ! $USE_APK; then
echo "local_backup"
fi
}
get_backup_app_list_file_path() {
echo "${APP_LIST_FILE}"
}
get_backup_app_list() {
if [ ! -f "${APP_LIST_FILE}" ];then
echo "no app.list, can not get backup app list"
exit 1
fi
cat ${APP_LIST_FILE}
}
get_available_backup_file_list() {
local backup_file
if [ -n "$1" ]; then
for backup_file in `cd $1 && ls backup_istore_*.backup.tar.gz`; do
echo "${backup_file}"
done
else
echo "input backup path is null"
exit 1
fi
}
usage() {
echo "usage: backup sub-command [arguments...]"
echo "where sub-command is one of:"
echo " backup [dir] Backup all installed package(s) to [directory]"
echo " restore [dir] Restore package(s) by [directory]"
echo " get_support_backup_features get device support backup features"
echo " get_backup_app_list_file_path get light backup app list file path"
echo " get_backup_app_list get light backup app list"
echo " get_available_backup_file_list get local available backup file list"
}
is_init >/dev/null 2>&1
case $action in
"get_support_backup_features")
get_support_backup_features
;;
"backup")
backup "$@"
;;
"restore")
restore "$@"
;;
"get_backup_app_list_file_path")
get_backup_app_list_file_path
;;
"get_backup_app_list")
get_backup_app_list
;;
"get_available_backup_file_list")
get_available_backup_file_list "$@"
;;
*)
usage
;;
esac
+114
View File
@@ -0,0 +1,114 @@
#!/bin/sh
handle_part() {
case "$MOUNT" in
"/overlay")
return 1
;;
esac
return 0
}
check_dir() {
local data_root=$(uci -q get dockerd.globals.data_root)
[ -n "$data_root" ] || return 0
local block_dev=$(findmnt -T "$data_root" -v -o SOURCE | sed -n 2p)
[ -n "$block_dev" ] || return 0
[ "overlayfs:/overlay" = "$block_dev" ] && return 1
local line=$(block info "$block_dev" 2>/dev/null)
[ -n "$line" ] || return 0
eval "${line##*: } handle_part ${line%%: *}"
}
migrate_check(){
local dest="$1"
[ -n "$dest" ] || {
echo "dest dir not specified!" >&2
return 1
}
local data_root="$2"
[ -n "$data_root" ] || data_root=$(uci -q get dockerd.globals.data_root)
[ -n "$data_root" ] || {
echo "get docker data_root failed!" >&2
return 1
}
[ "$data_root" = "/" ] || data_root="${data_root%%/}"
[ "$dest" = "/" ] || dest="${dest%%/}"
[ "$data_root" = "$dest" ] && {
echo "dest dir is the same as data_root!" >&2
return 1
}
[ 1 = "$FORCE" ] && return 0
[ -e "$dest" ] || return 0
[ -d "$dest" ] || {
echo "$dest is existed and it's not a dir, use FORCE=1 to overwrite it" >&2
return 2
}
[ 0 = "$(ls -A "$dest" | head -1 | wc -l)" ] || {
echo "$dest is existed and it's not empty, use FORCE=1 to overwrite it" >&2
return 2
}
return 0
}
migrate() {
local dest="$1"
local data_root=$(uci -q get dockerd.globals.data_root)
[ -n "$data_root" ] || {
echo "get docker data_root failed!" >&2
return 1
}
[ "$data_root" = "/" ] || data_root="${data_root%%/}"
[ "$dest" = "/" ] || dest="${dest%%/}"
FORCE=1 migrate_check "$dest" "$data_root"
local check_result=$?
[ 0 = $check_result ] || return $check_result
if [ "$UCI_ONLY" != 1 ]; then
rm -rf "$dest"
mkdir -p "$dest"
echo "Copy $data_root to $dest ..."
cp -a "$data_root/." "$dest/" || return 1
fi
echo "Change dockerd data_root to $dest and restart"
uci set dockerd.globals.data_root="$dest"
uci commit dockerd
/etc/init.d/dockerd restart
echo "Done"
}
action=${1}
shift
usage() {
echo "usage: $1 sub-command [arguments...]"
echo "where sub-command is one of:"
echo " check_dir Check docker data_root is on extrnal disk"
echo " migrate_check {target_dir} Check target_dir is valid for migration, return 2 if target_dir existed and not empty"
echo " migrate {target_dir} Migrate docker data_root to target_dir"
echo " change_dir {target_dir} Migrate docker data_root to target_dir but change dir only (no data copy)"
}
case $action in
"check_dir")
check_dir
;;
"migrate")
migrate "$@"
;;
"migrate_check")
migrate_check "$@"
;;
"change_dir")
UCI_ONLY=1 migrate "$@"
;;
*)
usage "$0"
;;
esac
+8
View File
@@ -0,0 +1,8 @@
#!/bin/sh
newpath=$(echo ":$PATH:" | sed -e 's#:/usr/libexec/istore/ipv4-bin:#:#g' -e 's/^:*//' -e 's/:*$//')
[ -z "$newpath" ] && newpath="/usr/sbin:/usr/bin:/sbin:/bin"
export PATH="$newpath"
exec curl --ipv4 "$@"
+8
View File
@@ -0,0 +1,8 @@
#!/bin/sh
newpath=$(echo ":$PATH:" | sed -e 's#:/usr/libexec/istore/ipv4-bin:#:#g' -e 's/^:*//' -e 's/:*$//')
[ -z "$newpath" ] && newpath="/usr/sbin:/usr/bin:/sbin:/bin"
export PATH="$newpath"
exec wget -4 "$@"
+26
View File
@@ -0,0 +1,26 @@
#!/bin/sh
newpath=$(echo ":$PATH:" | sed -e 's#:/usr/libexec/istore/mirror-bin:#:#g' -e 's/^:*//' -e 's/:*$//')
[ -z "$newpath" ] && newpath="/usr/sbin:/usr/bin:/sbin:/bin"
export PATH="$newpath"
# if url starts with $IS_ORIG_SERVER, replace it with $IS_MIRROR_SERVER
if [ -n "$IS_ORIG_SERVER" ] && [ -n "$IS_MIRROR_SERVER" ]; then
n=$#
while [ "$n" -gt 0 ]; do
i="$1"
shift
case "$i" in
"$IS_ORIG_SERVER"/*.apk|\
"$IS_ORIG_SERVER"/*.ipk)
i="$IS_MIRROR_SERVER/${i#$IS_ORIG_SERVER/}"
;;
esac
set -- "$@" "$i"
n=$((n - 1))
done
fi
export -n IS_ORIG_SERVER IS_MIRROR_SERVER
exec curl "$@"
+26
View File
@@ -0,0 +1,26 @@
#!/bin/sh
newpath=$(echo ":$PATH:" | sed -e 's#:/usr/libexec/istore/mirror-bin:#:#g' -e 's/^:*//' -e 's/:*$//')
[ -z "$newpath" ] && newpath="/usr/sbin:/usr/bin:/sbin:/bin"
export PATH="$newpath"
# if url starts with $IS_ORIG_SERVER, replace it with $IS_MIRROR_SERVER
if [ -n "$IS_ORIG_SERVER" ] && [ -n "$IS_MIRROR_SERVER" ]; then
n=$#
while [ "$n" -gt 0 ]; do
i="$1"
shift
case "$i" in
"$IS_ORIG_SERVER"/*.apk|\
"$IS_ORIG_SERVER"/*.ipk)
i="$IS_MIRROR_SERVER/${i#$IS_ORIG_SERVER/}"
;;
esac
set -- "$@" "$i"
n=$((n - 1))
done
fi
export -n IS_ORIG_SERVER IS_MIRROR_SERVER
exec wget "$@"
+237
View File
@@ -0,0 +1,237 @@
#!/bin/sh
TMP_SELF_COPY=/var/run/cloned-overlay-backup
action=${1}
shift
has_overlay() {
[ -d "/overlay/upper" ] || return 1
[ "overlay" = "$(/bin/mount | awk '($3 ~ /^\/$/) && ($5 !~ /rootfs/) { print $5 }')" ] || return 1
return 0
}
has_ext_overlay() {
[ -d "/ext_overlay/upper" ] || return 1
grep '^overlayfs:/overlay / ' /proc/mounts | grep -Fq 'upperdir=/ext_overlay/upper' || return 1
return 0
}
backup() {
if ! has_overlay; then
echo "only supports squashfs firmware"
exit 1
fi
if [ -z "$1" ]; then
echo "input backup path is null"
exit 1
fi
local BACKUP_PATH="$1"
if echo "$BACKUP_PATH" | grep -q -e '^/overlay/upper' -e '^/ext_overlay/upper' ; then
echo "can not backup to /overlay/upper, /ext_overlay/upper"
exit 1
fi
if [ ! -d "${BACKUP_PATH}" ] && ! mkdir -p "${BACKUP_PATH}" ; then
echo "backup path does not exist and can not be create"
exit 1
fi
local realpath="$(cd "${BACKUP_PATH}"; pwd -P)"
if [ -z "$realpath" ]; then
echo "cannot get absolute path of ${BACKUP_PATH}"
exit 1
fi
local mountpoint=$(findmnt -T $realpath -o TARGET | sed -n 2p)
# while read -r; do
# if [[ "x$realpath" == "x$REPLY" || "x${realpath#$REPLY/}" != "x$realpath" ]]; then
# mountpoint="$REPLY"
# break
# fi
# done < <(
# cat /proc/mounts | grep -v '^overlay ' | awk 'NR>1 {print $2}' | grep -v '^/$' | \
# sort -u | \
# while read -r; do printf "%b\n" "$REPLY" ; done | \
# awk '{print length, $0}' | sort -nr | cut -d' ' -f2-
# )
if [ "/" = "$mountpoint" ]; then
echo "can not backup to /"
exit 1
else
echo "found mount point $mountpoint"
fi
local filename_suffix=
local tar_extra_args=
if has_ext_overlay; then
tar_extra_args="$tar_extra_args ext_overlay/upper"
filename_suffix="${filename_suffix}.s"
fi
local hostname=$(cat /proc/sys/kernel/hostname)
local fwver=$(. /etc/openwrt_release; echo $DISTRIB_ID-$DISTRIB_RELEASE)
local date=$(date +%Y-%m%d-%H%M)
local backup_name="backup_overlay_${hostname}_${fwver}_${date}${filename_suffix}.overlay.tar.gz"
local backup_full_path="$BACKUP_PATH/$backup_name"
echo "writing backup to $backup_full_path"
if tar -C / -cz overlay/upper $tar_extra_args > "$backup_full_path" ; then
sync "$BACKUP_PATH"
echo "backup success"
return 0
else
rm -f "$backup_full_path"
echo "backup failed"
exit 1
fi
}
patch_sandbox_device() {
local overlay="$1"
local ucidir="$overlay/upper/etc/config"
local uci_section=$(uci -c "$ucidir" -q show fstab | grep '^fstab\.@mount\[[0-9]*\]\.target='"'/overlay'\$" | head -1 | grep -o '^fstab\.@mount\[[0-9]*\]')
if [ -n "$uci_section" ]; then
if [ "x1" = "x$(uci -c "$ucidir" get "$uci_section.enabled")" ]; then
uci -c "$ucidir" -q delete "$uci_section.uuid"
uci -c "$ucidir" -q delete "$uci_section.label"
uci -c "$ucidir" -q delete "$uci_section.device"
if [ -n "$SANDBOX_UUID" ]; then
uci -c "$ucidir" set "$uci_section.uuid=$SANDBOX_UUID"
elif [ -n "$SANDBOX_LABEL" ]; then
uci -c "$ucidir" set "$uci_section.label=$SANDBOX_LABEL"
else
uci -c "$ucidir" set "$uci_section.device=$SANDBOX_DEVICE"
fi
uci -c "$ucidir" commit fstab
echo "found and patched $overlay"
return 0
fi
fi
return 1
}
restore() {
if ! has_overlay; then
echo "only supports squashfs firmware"
exit 1
fi
if [ -z "$1" ]; then
echo "input backup path is null"
exit 1
fi
local BACKUP_PATH_FILE="$1"
if [ ! -f "${BACKUP_PATH_FILE}" ]; then
echo "invalid backup file, can not restore"
exit 1
fi
# prevent uci cache
rm -rf /var/run/uci
SANDBOX_UUID=
SANDBOX_LABEL=
SANDBOX_DEVICE=
local tar_extra_args=overlay/upper
if has_ext_overlay; then
tar_extra_args=
if echo "${BACKUP_PATH_FILE}" | grep -q '\.s\.overlay\.tar\.gz$' ; then
local uuid label device line
local uci_section=$(uci -c /overlay/upper/etc/config show fstab | grep '^fstab\.@mount\[[0-9]*\]\.target='"'/overlay'\$" | head -1 | grep -o '^fstab\.@mount\[[0-9]*\]')
if [ -z "$uci_section" ]; then
echo "failed to find sandbox config, there is debug info:"
uci -c /overlay/upper/etc/config show fstab | grep '^fstab\.[^.]*\.target='"'/overlay'\$"
exit 1
fi
while read line; do
export -n "$line"
done <<EOF
$(uci -c /overlay/upper/etc/config show "$uci_section" | sed -e '/^fstab\.[^\.]*=/d' -e 's/^fstab\.[^\.]*\.//g' | grep -e '^uuid=' -e '^label=' -e '^device=' | sed "s/'//g")
EOF
SANDBOX_UUID=$uuid
SANDBOX_LABEL=$label
SANDBOX_DEVICE=$device
fi
fi
sync /
echo "restoring from ${BACKUP_PATH_FILE}"
if tar -C / -xz $tar_extra_args < "${BACKUP_PATH_FILE}" ; then
if [ -n "$SANDBOX_UUID" -o -n "$SANDBOX_LABEL" -o -n "$SANDBOX_DEVICE" ]; then
echo "patch sandbox device ${SANDBOX_UUID}${SANDBOX_LABEL}${SANDBOX_DEVICE}"
patch_sandbox_device /overlay && patch_sandbox_device /ext_overlay
fi
sync /overlay /ext_overlay
echo "restore success"
echo "schedule to restart after 5 seconds!"
/etc/init.d/tasks task_add reboot 'reboot -d 5'
return 0
else
echo "restore failed"
exit 1
fi
}
supports_overlay_backup() {
has_overlay || return 1
echo "overlay"
has_ext_overlay && echo "ext_overlay"
return 0
}
filter_backups() {
if has_ext_overlay; then
cat
else
# do not support restoring sandbox backup on non sandbox env
grep -v '\.s\.overlay\.tar\.gz$'
fi
}
get_backup_file_list() {
if [ -n "$1" ]; then
( cd "$1" && ls backup_overlay_*.overlay.tar.gz | filter_backups )
return 0
else
echo "input backup path is null"
exit 1
fi
}
usage() {
echo "usage: overlay-backup sub-command [arguments...]"
echo "where sub-command is one of:"
echo " backup [dir] Backup all installed package(s) to [directory]"
echo " restore [dir] Restore package(s) by [directory]"
echo " supports_overlay_backup check system supports overlay backup"
echo " get_backup_file_list [dir] get local available backup file list in [dir]"
}
case $action in
"supports_overlay_backup")
supports_overlay_backup
;;
"backup")
backup "$@"
;;
"restore")
if [ "$0" = "$TMP_SELF_COPY" ]; then
restore "$@"
else
echo "copy self $0 to $TMP_SELF_COPY when restore"
cp -af "$0" "$TMP_SELF_COPY"
exec "$TMP_SELF_COPY" restore "$@"
fi
;;
"get_available_backup_file_list")
get_backup_file_list "$@"
;;
*)
usage
;;
esac
+27
View File
@@ -0,0 +1,27 @@
clean:
compile:
include $(TOPDIR)/rules.mk
LUCI_NAME:=luci-lib-dummy
INCLUDE_DIR:=./dummy
include $(TOPDIR)/feeds/luci/luci.mk
install:
[ -n "$(APP_STORE_VERSION)" ]
mkdir -p "$(DESTDIR)/www/luci-static" "$(DESTDIR)/etc"
cp -a "$(FRONTEND_DIST)/luci-static/istore" "$(DESTDIR)/www/luci-static/"
$(SED) 's#\.js"#.js?v=$(APP_STORE_VERSION)"#g' "$(DESTDIR)/www/luci-static/istore/index.js"
echo "$(APP_STORE_VERSION)" > "$(DESTDIR)/etc/.app_store.version"
ifneq ($(USE_APK),)
cp -pR ./root-apk/* "$(DESTDIR)/"
else
cp -pR ./root-opkg/* "$(DESTDIR)/"
mkdir -p "$(DESTDIR)/etc/opkg/keys"
cp -a ./key-build.pub $(DESTDIR)/etc/opkg/keys/`$(STAGING_DIR_HOST)/bin/usign -F -p ./key-build.pub`
endif
mkdir -p "$(DESTDIR)$(LUCI_LIBRARYDIR)/i18n"
$(foreach lang,$(LUCI_LANGUAGES),$(foreach po,$(wildcard ${CURDIR}/po/$(lang)/*.po), \
po2lmo $(po) \
$(DESTDIR)$(LUCI_LIBRARYDIR)/i18n/$(basename $(notdir $(po))).$(lang).lmo;))
+2
View File
@@ -0,0 +1,2 @@
define BuildPackage
endef
+2
View File
@@ -0,0 +1,2 @@
untrusted comment: istore key
RWSlbxYnTG1Ia0BvB+xd7YdP7QDQACljfpve7sx9KYq94QgIqtlljuME
@@ -0,0 +1,11 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "istore_vue_lang"
msgstr "en"
msgid "iStore"
msgstr ""
msgid "This package is broken! Please reinstall or uninstall it."
msgstr ""
+11
View File
@@ -0,0 +1,11 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "istore_vue_lang"
msgstr "zh-cn"
msgid "iStore"
msgstr "iStore"
msgid "This package is broken! Please reinstall or uninstall it."
msgstr "此软件包已损坏!请重新安装或卸载它。"
+11
View File
@@ -0,0 +1,11 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "istore_vue_lang"
msgstr "zh-cn"
msgid "iStore"
msgstr "iStore"
msgid "This package is broken! Please reinstall or uninstall it."
msgstr "此軟體包已損壞!請重新安裝或卸載它。"
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEybK5eaXsrK06Thc1dbA3FC45Tlp8
8X5Z831vU6JggiV6tJiwI/B05IsdklTaZE8SYh0XCHcnXSjzRMLtarBisg==
-----END PUBLIC KEY-----
@@ -0,0 +1 @@
https://istore.istoreos.com/repo-apk/all/compat/packages.adb
@@ -0,0 +1 @@
src/gz istore_compat https://istore.istoreos.com/repo/all/compat
+200
View File
@@ -0,0 +1,200 @@
#!/bin/sh
# ipkg-build -- construct a .ipk from a directory
# Carl Worth <cworth@east.isi.edu>
# based on a script by Steve Redler IV, steve@sr-tech.com 5-21-2001
# 2003-04-25 rea@sr.unh.edu
# Updated to work on Familiar Pre0.7rc1, with busybox tar.
# Note it Requires: binutils-ar (since the busybox ar can't create)
# For UID debugging it needs a better "find".
set -e
version=1.0
FIND="$(command -v find)"
FIND="${FIND:-$(command -v gfind)}"
TAR="${TAR:-$(command -v tar)}"
GZIP="$(command -v gzip)"
# try to use fixed source epoch
if [ -n "$PKG_SOURCE_DATE_EPOCH" ]; then
TIMESTAMP=$(date --date="@$PKG_SOURCE_DATE_EPOCH")
elif [ -n "$SOURCE_DATE_EPOCH" ]; then
TIMESTAMP=$(date --date="@$SOURCE_DATE_EPOCH")
else
TIMESTAMP=$(date)
fi
ipkg_extract_value() {
sed -e "s/^[^:]*:[[:space:]]*//"
}
required_field() {
field=$1
grep "^$field:" < $CONTROL/control | ipkg_extract_value
}
pkg_appears_sane() {
local pkg_dir=$1
local owd=$PWD
cd $pkg_dir
PKG_ERROR=0
pkg=`required_field Package`
version=`required_field Version | sed 's/Version://; s/^.://g;'`
arch=`required_field Architecture`
if echo $pkg | grep '[^a-zA-Z0-9_.+-]'; then
echo "*** Error: Package name $name contains illegal characters, (other than [a-z0-9.+-])" >&2
PKG_ERROR=1;
fi
if [ -f $CONTROL/conffiles ]; then
rm -f $CONTROL/conffiles.resolved
for cf in `$FIND $(sed -e "s!^/!$pkg_dir/!" $CONTROL/conffiles) -type f`; do
echo "${cf#$pkg_dir}" >> $CONTROL/conffiles.resolved
done
rm $CONTROL/conffiles
if [ -f $CONTROL/conffiles.resolved ]; then
mv $CONTROL/conffiles.resolved $CONTROL/conffiles
chmod 0644 $CONTROL/conffiles
fi
fi
cd $owd
return $PKG_ERROR
}
resolve_file_mode_id() {
local var=$1 type=$2 name=$3 id
case "$name" in
root)
id=0
;;
*[!0-9]*)
id=$(sed -ne "s#^$type $name \\([0-9]\\+\\)\\b.*\$#\\1#p" "$TOPDIR/tmp/.packageusergroup" 2>/dev/null)
;;
*)
id=$name
;;
esac
export "$var=$id"
[ -n "$id" ]
}
###
# ipkg-build "main"
###
file_modes=""
usage="Usage: $0 [-v] [-h] [-m] <pkg_directory> [<destination_directory>]"
while getopts "hvm:" opt; do
case $opt in
v ) echo $version
exit 0
;;
h ) echo $usage >&2 ;;
m ) file_modes=$OPTARG ;;
\? ) echo $usage >&2
esac
done
shift $(($OPTIND - 1))
# continue on to process additional arguments
case $# in
1)
dest_dir=$PWD
;;
2)
dest_dir=$2
if [ "$dest_dir" = "." -o "$dest_dir" = "./" ] ; then
dest_dir=$PWD
fi
;;
*)
echo $usage >&2
exit 1
;;
esac
pkg_dir=$1
if [ ! -d $pkg_dir ]; then
echo "*** Error: Directory $pkg_dir does not exist" >&2
exit 1
fi
# CONTROL is second so that it takes precedence
CONTROL=
[ -d $pkg_dir/CONTROL ] && CONTROL=CONTROL
if [ -z "$CONTROL" ]; then
echo "*** Error: Directory $pkg_dir has no CONTROL subdirectory." >&2
exit 1
fi
if ! pkg_appears_sane $pkg_dir; then
echo >&2
echo "ipkg-build: Please fix the above errors and try again." >&2
exit 1
fi
tmp_dir=$dest_dir/IPKG_BUILD.$$
mkdir $tmp_dir
echo $CONTROL > $tmp_dir/tarX
cd $pkg_dir
for file_mode in $file_modes; do
case $file_mode in
/*:*:*:*)
;;
*)
echo "ERROR: file modes must use absolute path and contain user:group:mode"
echo "$file_mode"
exit 1
;;
esac
mode=${file_mode##*:}; path=${file_mode%:*}
group=${path##*:}; path=${path%:*}
user=${path##*:}; path=${path%:*}
if ! resolve_file_mode_id uid user "$user"; then
echo "ERROR: unable to resolve uid of $user" >&2
exit 1
fi
if ! resolve_file_mode_id gid group "$group"; then
echo "ERROR: unable to resolve gid of $group" >&2
exit 1
fi
chown "$uid:$gid" "$pkg_dir/$path"
chmod "$mode" "$pkg_dir/$path"
done
$TAR -X $tmp_dir/tarX --format=gnu --sort=name -cpf - --mtime="$TIMESTAMP" . | $GZIP -n - > $tmp_dir/data.tar.gz
installed_size=`ls -ln $tmp_dir/data.tar.gz | awk 'NR==1 {print $5}'`
sed -i -e "s/^Installed-Size: .*/Installed-Size: $installed_size/" \
$pkg_dir/$CONTROL/control
( cd $pkg_dir/$CONTROL && $TAR --format=gnu --sort=name -cf - --mtime="$TIMESTAMP" . | $GZIP -n - > $tmp_dir/control.tar.gz )
rm $tmp_dir/tarX
echo "2.0" > $tmp_dir/debian-binary
pkg_file=$dest_dir/${pkg}_${version}_${arch}.ipk
rm -f $pkg_file
( cd $tmp_dir && $TAR --format=gnu --sort=name -cf - --mtime="$TIMESTAMP" ./debian-binary ./data.tar.gz ./control.tar.gz | $GZIP -n - > $pkg_file )
rm $tmp_dir/debian-binary $tmp_dir/data.tar.gz $tmp_dir/control.tar.gz
rmdir $tmp_dir
echo "Packaged contents of $pkg_dir into $pkg_file"
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
for i in "$@"; do
echo "$i" | grep -s -q "/etc/uci-defaults/" \
&& mkdir -p /etc/istore/uci-defaults_bak \
&& cp -f "$i" /etc/istore/uci-defaults_bak/
done
/bin/rm "$@"
+513
View File
@@ -0,0 +1,513 @@
swagger: "2.0"
info:
description: Store API V1
title: Store API V1
version: 3.0.0
paths:
/cgi-bin/luci/admin/store/token:
get:
tags:
- token
summary: 获取csrfToken(用于POST请求)
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStoreToken"
/cgi-bin/luci/admin/store/installed:
get:
tags:
- installed
summary: 获取已安装的插件
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStoreInstalled"
/cgi-bin/luci/admin/store/install:
post:
tags:
- install
summary: 安装插件。安装过程中使用taskd接口获取日志
parameters:
- in: "query"
name: "token"
type: string
required: true
- in: "query"
name: "package"
type: string
required: true
- in: "query"
name: "autoconf"
type: string
description: "可选参数,表示安装完以后是否自动配置插件"
- in: "query"
name: "path"
type: string
description: "可选参数,表示安装完以后是否自动配置插件"
- in: "query"
name: "enable"
type: string
description: "可选参数,表示安装完以后是否自动配置插件"
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStore"
/cgi-bin/luci/admin/store/autoconf:
post:
tags:
- install
summary: 自动配置插件
parameters:
- in: "query"
name: "token"
type: string
required: true
- in: "query"
name: "package"
type: string
required: true
- in: "query"
name: "path"
type: string
description: "可选参数"
- in: "query"
name: "enable"
type: string
description: "可选参数"
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStore"
/cgi-bin/luci/admin/store/remove:
post:
tags:
- remove
summary: 卸载插件
parameters:
- in: "query"
name: "token"
type: string
required: true
- in: "query"
name: "package"
type: string
required: true
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStore"
/cgi-bin/luci/admin/store/upgrade:
post:
tags:
- upgrade
summary: 更新插件
parameters:
- in: "query"
name: "token"
type: string
required: true
- in: "query"
name: "package"
type: string
required: true
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStore"
/cgi-bin/luci/admin/store/upload:
post:
tags:
- upload
summary: 上传插件
description: "(文件上传表单,支持文件扩展名 .ipk,.run )"
consumes:
- multipart/form-data
parameters:
- in: formData
name: file
type: file
description: The file to upload.
- in: "query"
name: "token"
type: string
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStore"
/cgi-bin/luci/admin/store/update:
post:
tags:
- update
summary: 刷新可用软件列表
parameters:
- in: "query"
name: "token"
type: string
required: true
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStore"
/cgi-bin/luci/admin/store/status:
get:
tags:
- status
summary: 查询特定软件状态
parameters:
- in: "query"
name: "package"
type: string
required: true
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStoreStatus"
/cgi-bin/luci/admin/store/log:
get:
tags:
- log
summary: 任务日志,已废弃
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStore"
/cgi-bin/luci/admin/store/check_self_upgrade:
get:
tags:
- check_self_upgrade
summary: 检查iStore自身更新
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStoreCheckSelfUpgrade"
/cgi-bin/luci/admin/store/do_self_upgrade:
post:
tags:
- do_self_upgrade
summary: 更新iStore自身
parameters:
- in: "query"
name: "token"
type: string
required: true
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStore"
/cgi-bin/luci/admin/store/get_block_devices:
get:
tags:
- get_block_devices
summary: 枚举块设备
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStoreGetBlockDevices"
/cgi-bin/luci/admin/store/configured:
get:
tags:
- configured
summary: 检查插件是否已经配置过
parameters:
- in: "query"
name: "uci"
type: string
required: true
description: "要检查的uci配置文件名称"
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStoreConfigured"
/cgi-bin/luci/admin/store/entrysh:
post:
tags:
- entrysh
summary: 查询插件运行状态,主要为了获取入口信息。
description: 调用前应该检查meta数据中flags数组包含entrysh,注意如果是安装插件则检查服务器端的flags,如果是调用已安装插件则检查路由器端的flags。
parameters:
- in: "query"
name: "token"
type: string
required: true
- in: "query"
name: "package"
type: string
description: "包名,例如aria2。支持英文逗号分隔多个包名。如果未提供,则返回所有支持entrysh的包"
- in: "query"
name: "hostname"
type: string
required: true
description: "主机名,不包含端口。前端应该使用location.hostname获取"
- in: "query"
name: "update"
type: integer
description: "如果为1则强制更新缓存"
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStoreEntrysh"
"400":
description: Bad Request。hostname不合法
/cgi-bin/luci/admin/store/docker_check_dir:
get:
tags:
- docker_check_dir
summary: 检查docker目录是否在系统盘
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseDockerCheckDir"
/cgi-bin/luci/admin/store/docker_check_migrate:
get:
tags:
- docker_check_migrate
summary: 检查docker迁移目标目录是否有效
parameters:
- in: "query"
name: "path"
type: string
required: true
description: "完整目标路径"
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseDockerCheckMigrate"
/cgi-bin/luci/admin/store/docker_migrate:
post:
tags:
- docker_migrate
summary: docker迁移到目标目录,异步
description: 当返回code为0的时候,可以使用taskd接口展示日志,跟安装插件时一样
parameters:
- in: "query"
name: "token"
type: string
required: true
- in: "query"
name: "path"
type: string
required: true
description: "完整目标路径"
- in: "query"
name: "overwrite"
type: string
description: "如果docker_check_migrate返回的result是existed,使用此参数指定解决方案:‘true’表示覆盖目标目录;‘chdir’表示只修改路径不复制文件"
responses:
"200":
description: OK
schema:
$ref: "#/definitions/ResponseStore"
definitions:
ResponseStoreToken:
type: object
properties:
token:
type: string
StoreInstalledApp:
type: object
properties:
tutorial:
type: string
description: "教程"
arch:
type: array
description: "适用的架构平台"
items:
type: string
entry:
type: string
description: "对于的页面地址"
author:
type: string
description: "作者"
depends:
type: array
description: "关联的依赖"
items:
type: string
time:
type: integer
description: "更新日期"
tags:
type: array
description: "标签"
items:
type: string
description_en:
type: string
description: "简介,英文"
description:
type: string
description: "简介,英文"
title:
type: string
description: "标题"
release:
type: integer
description: "发布"
website:
type: string
description: "官网"
version:
type: string
description: "版本号"
name:
type: string
description: "名称"
ResponseStoreInstalled:
type: array
items:
$ref: "#/definitions/StoreInstalledApp"
ResponseStore:
type: object
properties:
code:
type: integer
stdout:
type: string
stderr:
type: string
ResponseStoreStatus:
type: object
allOf:
- $ref: "#/definitions/StoreInstalledApp"
properties:
installed:
type: boolean
ResponseStoreCheckSelfUpgrade:
type: object
properties:
code:
type: integer
description: "为200时,msg会显示版本号"
msg:
type: string
description: "内容"
GetBlockDevice:
type: object
properties:
dev:
type: string
uuid:
type: string
version:
type: string
label:
type: string
mount:
type: string
type:
type: string
size:
type: string
ResponseStoreGetBlockDevices:
type: object
properties:
code:
type: integer
description: "为200时"
msg:
type: string
description: "内容"
data:
type: object
additionalProperties:
$ref: "#/definitions/GetBlockDevice"
ResponseStoreConfigured:
type: object
properties:
code:
type: integer
description: "为200时"
configured:
type: boolean
ResponseDockerCheckDir:
type: object
properties:
code:
type: integer
description: "为200时"
docker_on_system:
type: boolean
description: "docker数据在系统盘"
ResponseDockerCheckMigrate:
type: object
properties:
code:
type: integer
description: "为200时"
result:
type: string
description: "检查结果。可能值‘good’,‘bad’,‘existed’"
error:
type: string
description: "当result为bad时,此处返回错误日志"
StoreEntrysh:
type: object
description: "状态和入口信息,不同插件可能有些不一样,仅列出常用公共参数"
properties:
app:
type: string
description: "插件名称"
docker:
type: boolean
description: "如果是docker插件"
running:
type: boolean
description: "是否运行中"
deployed:
type: boolean
description: "如果是docker插件且未运行,则是否已经部署"
web:
type: string
description: "url"
href:
type: string
description: "web端直接跳转url"
ResponseStoreEntrysh:
type: object
properties:
code:
type: integer
description: "为200时"
status:
description: "处理成功的结果集"
type: array
items:
$ref: "#/definitions/StoreEntrysh"
errors:
description: "处理失败的结果集"
type: array
items:
type: object
description: "失败信息"
properties:
app:
type: string
description: "插件名称"
code:
type: integer
description: "404或500"
msg:
type: string
description: "错误信息"