mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-29 20:55:13 +08:00
🔥 Sync 2026-06-14 00:24:29
This commit is contained in:
1 parent
dfdaff1ccc
commit
77b1ba4540
7 files changed
+874
-1
No files matched your search
+341
@@ -0,0 +1,341 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
BASE_DIR="/tmp/luci-app-run"
|
||||
UPLOAD_DIR="$BASE_DIR/uploads"
|
||||
RUN_DIR="$BASE_DIR/runs"
|
||||
STATE_FILE="$BASE_DIR/state"
|
||||
MAX_SIZE=$((256 * 1024 * 1024))
|
||||
|
||||
umask 077
|
||||
|
||||
mkdir -p "$UPLOAD_DIR" "$RUN_DIR"
|
||||
|
||||
reply() {
|
||||
printf '%s\n' "$1"
|
||||
}
|
||||
|
||||
json_error() {
|
||||
local msg="$1"
|
||||
json_init
|
||||
json_add_int code 1
|
||||
json_add_string error "$msg"
|
||||
json_dump
|
||||
}
|
||||
|
||||
json_ok() {
|
||||
json_init
|
||||
json_add_int code 0
|
||||
[ -n "$1" ] && json_add_string message "$1"
|
||||
json_dump
|
||||
}
|
||||
|
||||
sanitize_name() {
|
||||
local name="$1"
|
||||
name="${name##*/}"
|
||||
name="${name##*\\}"
|
||||
printf '%s' "$name" | tr -c 'A-Za-z0-9._-' '_'
|
||||
}
|
||||
|
||||
valid_id() {
|
||||
case "$1" in
|
||||
""|*[!A-Za-z0-9_-]*) return 1 ;;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
|
||||
load_input() {
|
||||
local input
|
||||
input="$(cat)"
|
||||
json_load "$input" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
get_string() {
|
||||
json_get_var "$1" "$1"
|
||||
}
|
||||
|
||||
get_int() {
|
||||
json_get_var "$1" "$1"
|
||||
}
|
||||
|
||||
new_token() {
|
||||
local token
|
||||
token="$(hexdump -n 16 -e '16/1 "%02x"' /dev/urandom 2>/dev/null)"
|
||||
[ -n "$token" ] || token="$(date +%s)_$$_$(awk 'BEGIN{srand();print int(rand()*1000000)}')"
|
||||
printf '%s' "$token" | tr -c 'A-Za-z0-9_' '_'
|
||||
}
|
||||
|
||||
session_dir() {
|
||||
printf '%s/%s' "$UPLOAD_DIR" "$1"
|
||||
}
|
||||
|
||||
write_state() {
|
||||
local pid="$1"
|
||||
local file="$2"
|
||||
local log="$3"
|
||||
local started="$4"
|
||||
{
|
||||
printf 'PID=%s\n' "$pid"
|
||||
printf 'FILE=%s\n' "$file"
|
||||
printf 'LOG=%s\n' "$log"
|
||||
printf 'STARTED=%s\n' "$started"
|
||||
} > "$STATE_FILE"
|
||||
}
|
||||
|
||||
read_state() {
|
||||
[ -f "$STATE_FILE" ] && . "$STATE_FILE"
|
||||
}
|
||||
|
||||
is_running() {
|
||||
local pid="$1"
|
||||
[ -n "$pid" ] && [ -d "/proc/$pid" ]
|
||||
}
|
||||
|
||||
method_list() {
|
||||
cat <<'JSON'
|
||||
{
|
||||
"upload_start": {
|
||||
"filename": "String",
|
||||
"size": "Integer"
|
||||
},
|
||||
"upload_chunk": {
|
||||
"id": "String",
|
||||
"data": "String",
|
||||
"index": "Integer"
|
||||
},
|
||||
"upload_finish": {
|
||||
"id": "String"
|
||||
},
|
||||
"run": {
|
||||
"id": "String"
|
||||
},
|
||||
"status": {},
|
||||
"read_log": {
|
||||
"offset": "Integer"
|
||||
},
|
||||
"cleanup": {}
|
||||
}
|
||||
JSON
|
||||
}
|
||||
|
||||
upload_start() {
|
||||
load_input
|
||||
get_string filename
|
||||
get_int size
|
||||
|
||||
[ -n "$filename" ] || { json_error "Missing filename"; return; }
|
||||
[ -n "$size" ] || size=0
|
||||
[ "$size" -le "$MAX_SIZE" ] 2>/dev/null || { json_error "File is larger than 256 MiB"; return; }
|
||||
|
||||
local clean id token dir file
|
||||
clean="$(sanitize_name "$filename")"
|
||||
case "$clean" in
|
||||
*.run) ;;
|
||||
*) json_error "Only .run files are accepted"; return ;;
|
||||
esac
|
||||
|
||||
id="$(date +%s)_$$"
|
||||
token="$(new_token)"
|
||||
dir="$(session_dir "$id")"
|
||||
file="$dir/$clean"
|
||||
mkdir -p "$dir" || { json_error "Unable to create upload directory"; return; }
|
||||
: > "$file" || { json_error "Unable to create upload file"; return; }
|
||||
printf '%s\n' "$clean" > "$dir/name"
|
||||
printf '%s\n' "$size" > "$dir/size"
|
||||
printf '%s\n' "$token" > "$dir/token"
|
||||
|
||||
json_init
|
||||
json_add_int code 0
|
||||
json_add_string id "$id"
|
||||
json_add_string token "$token"
|
||||
json_add_string filename "$clean"
|
||||
json_dump
|
||||
}
|
||||
|
||||
upload_chunk() {
|
||||
load_input
|
||||
get_string id
|
||||
get_string data
|
||||
get_int index
|
||||
|
||||
valid_id "$id" || { json_error "Invalid upload id"; return; }
|
||||
[ -n "$data" ] || { json_error "Missing chunk data"; return; }
|
||||
|
||||
local dir name file
|
||||
dir="$(session_dir "$id")"
|
||||
[ -d "$dir" ] || { json_error "Unknown upload id"; return; }
|
||||
name="$(cat "$dir/name" 2>/dev/null)"
|
||||
file="$dir/$name"
|
||||
|
||||
printf '%s' "$data" | base64 -d >> "$file" 2>/dev/null || {
|
||||
json_error "Unable to decode upload chunk"
|
||||
return
|
||||
}
|
||||
|
||||
json_init
|
||||
json_add_int code 0
|
||||
json_add_int index "$index"
|
||||
json_add_int received "$(wc -c < "$file" 2>/dev/null)"
|
||||
json_dump
|
||||
}
|
||||
|
||||
upload_finish() {
|
||||
load_input
|
||||
get_string id
|
||||
|
||||
valid_id "$id" || { json_error "Invalid upload id"; return; }
|
||||
|
||||
local dir name file expected actual
|
||||
dir="$(session_dir "$id")"
|
||||
[ -d "$dir" ] || { json_error "Unknown upload id"; return; }
|
||||
name="$(cat "$dir/name" 2>/dev/null)"
|
||||
expected="$(cat "$dir/size" 2>/dev/null)"
|
||||
file="$dir/$name"
|
||||
actual="$(wc -c < "$file" 2>/dev/null)"
|
||||
|
||||
[ -s "$file" ] || { json_error "Uploaded file is empty"; return; }
|
||||
if [ -n "$expected" ] && [ "$expected" -gt 0 ] 2>/dev/null; then
|
||||
[ "$actual" -eq "$expected" ] 2>/dev/null || {
|
||||
json_error "Upload size mismatch"
|
||||
return
|
||||
}
|
||||
fi
|
||||
|
||||
chmod 700 "$file" || { json_error "Unable to chmod uploaded file"; return; }
|
||||
|
||||
json_init
|
||||
json_add_int code 0
|
||||
json_add_string id "$id"
|
||||
json_add_string filename "$name"
|
||||
json_add_int size "$actual"
|
||||
json_dump
|
||||
}
|
||||
|
||||
run_installer() {
|
||||
load_input
|
||||
get_string id
|
||||
|
||||
valid_id "$id" || { json_error "Invalid upload id"; return; }
|
||||
|
||||
local dir name file log work pid now
|
||||
dir="$(session_dir "$id")"
|
||||
[ -d "$dir" ] || { json_error "Unknown upload id"; return; }
|
||||
name="$(cat "$dir/name" 2>/dev/null)"
|
||||
file="$dir/$name"
|
||||
[ -x "$file" ] || { json_error "Uploaded file is not executable"; return; }
|
||||
|
||||
read_state
|
||||
if is_running "$PID"; then
|
||||
json_error "Another installer is already running"
|
||||
return
|
||||
fi
|
||||
|
||||
now="$(date '+%Y-%m-%d %H:%M:%S')"
|
||||
work="$RUN_DIR/$id"
|
||||
log="$work/output.log"
|
||||
mkdir -p "$work" || { json_error "Unable to create run directory"; return; }
|
||||
|
||||
(
|
||||
cd "$work" || exit 1
|
||||
printf 'luci-app-run: started %s\n' "$now"
|
||||
printf 'luci-app-run: executing %s\n\n' "$file"
|
||||
"$file"
|
||||
rc=$?
|
||||
printf '\nluci-app-run: exited with status %s at %s\n' "$rc" "$(date '+%Y-%m-%d %H:%M:%S')"
|
||||
exit "$rc"
|
||||
) > "$log" 2>&1 &
|
||||
|
||||
pid="$!"
|
||||
write_state "$pid" "$file" "$log" "$now"
|
||||
|
||||
json_init
|
||||
json_add_int code 0
|
||||
json_add_int pid "$pid"
|
||||
json_add_string log "$log"
|
||||
json_dump
|
||||
}
|
||||
|
||||
status() {
|
||||
read_state
|
||||
|
||||
json_init
|
||||
json_add_int code 0
|
||||
if is_running "$PID"; then
|
||||
json_add_boolean running 1
|
||||
else
|
||||
json_add_boolean running 0
|
||||
fi
|
||||
[ -n "$PID" ] && json_add_int pid "$PID"
|
||||
[ -n "$FILE" ] && json_add_string file "$FILE"
|
||||
[ -n "$LOG" ] && json_add_string log "$LOG"
|
||||
[ -n "$STARTED" ] && json_add_string started "$STARTED"
|
||||
json_dump
|
||||
}
|
||||
|
||||
read_log() {
|
||||
load_input
|
||||
get_int offset
|
||||
[ -n "$offset" ] || offset=0
|
||||
|
||||
read_state
|
||||
[ -n "$LOG" ] && [ -f "$LOG" ] || {
|
||||
json_init
|
||||
json_add_int code 0
|
||||
json_add_string data ""
|
||||
json_add_int offset 0
|
||||
json_add_boolean running 0
|
||||
json_dump
|
||||
return
|
||||
}
|
||||
|
||||
local size data start
|
||||
size="$(wc -c < "$LOG" 2>/dev/null)"
|
||||
[ "$offset" -le "$size" ] 2>/dev/null || offset=0
|
||||
start=$((offset + 1))
|
||||
data="$(tail -c +"$start" "$LOG" 2>/dev/null)"
|
||||
|
||||
json_init
|
||||
json_add_int code 0
|
||||
json_add_string data "$data"
|
||||
json_add_int offset "$size"
|
||||
if is_running "$PID"; then
|
||||
json_add_boolean running 1
|
||||
else
|
||||
json_add_boolean running 0
|
||||
fi
|
||||
json_dump
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
read_state
|
||||
if is_running "$PID"; then
|
||||
json_error "Cannot clean up while installer is running"
|
||||
return
|
||||
fi
|
||||
|
||||
rm -rf "$UPLOAD_DIR" "$RUN_DIR" "$STATE_FILE"
|
||||
mkdir -p "$UPLOAD_DIR" "$RUN_DIR"
|
||||
json_ok "Cleaned"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
list)
|
||||
method_list
|
||||
;;
|
||||
call)
|
||||
case "$2" in
|
||||
upload_start) upload_start ;;
|
||||
upload_chunk) upload_chunk ;;
|
||||
upload_finish) upload_finish ;;
|
||||
run) run_installer ;;
|
||||
status) status ;;
|
||||
read_log) read_log ;;
|
||||
cleanup) cleanup ;;
|
||||
*) json_error "Unknown method" ;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
reply '{}'
|
||||
;;
|
||||
esac
|
||||
Reference in new issue
Block a user