mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-02 21:43:56 +08:00
✨ Sync 2026-07-29 08:29:27
This commit is contained in:
1 parent
b17aa6f5de
commit
3cdc6def95
10 files changed
+143
-27
No files matched your search
@@ -4,7 +4,7 @@ LUCI_TITLE:=Web UI for QEMU Virtual Machine Simple (VMS)
|
|||||||
LUCI_DEPENDS:=+qemu-vms +ttyd +usbutils +pciutils
|
LUCI_DEPENDS:=+qemu-vms +ttyd +usbutils +pciutils
|
||||||
PKG_LICENSE:=GPLv3
|
PKG_LICENSE:=GPLv3
|
||||||
PKG_VERSION:=0.0.1
|
PKG_VERSION:=0.0.1
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=2
|
||||||
|
|
||||||
include $(TOPDIR)/feeds/luci/luci.mk
|
include $(TOPDIR)/feeds/luci/luci.mk
|
||||||
|
|
||||||
|
|||||||
@@ -297,8 +297,8 @@ return view.extend({
|
|||||||
var rows = devices.map(function(dev) {
|
var rows = devices.map(function(dev) {
|
||||||
var section = self.findPciSection(dev.addr);
|
var section = self.findPciSection(dev.addr);
|
||||||
var owner = self.pciOwner(dev.addr);
|
var owner = self.pciOwner(dev.addr);
|
||||||
var passthroughStatus = section ? _('Passthrough active (section: %s)').format(section) : _('Not passthrough');
|
var passthroughStatus = section ? _('Active<br />Section: %s').format(section) : _('Not passthrough');
|
||||||
if (owner) passthroughStatus += ' ' + _('(attached to VM: %s)').format(owner);
|
if (owner) passthroughStatus += ' ' + _('<br />Host: %s').format(owner);
|
||||||
|
|
||||||
var actionButton;
|
var actionButton;
|
||||||
if (section) {
|
if (section) {
|
||||||
@@ -325,11 +325,11 @@ return view.extend({
|
|||||||
|
|
||||||
return E('table', { 'class': 'table' }, [
|
return E('table', { 'class': 'table' }, [
|
||||||
E('tr', { 'class': 'tr table-titles' }, [
|
E('tr', { 'class': 'tr table-titles' }, [
|
||||||
E('th', { 'class': 'th' }, _('PCI address')),
|
E('th', { 'class': 'th' }, _('Address')),
|
||||||
E('th', { 'class': 'th' }, _('Vendor')),
|
E('th', { 'class': 'th' }, _('Vendor')),
|
||||||
E('th', { 'class': 'th' }, _('Device')),
|
E('th', { 'class': 'th' }, _('Device')),
|
||||||
E('th', { 'class': 'th' }, _('Current driver')),
|
E('th', { 'class': 'th' }, _('Driver')),
|
||||||
E('th', { 'class': 'th' }, _('Passthrough status')),
|
E('th', { 'class': 'th', 'style': 'min-width: 140px;' }, _('Status')),
|
||||||
E('th', { 'class': 'th' }, _('Action'))
|
E('th', { 'class': 'th' }, _('Action'))
|
||||||
])
|
])
|
||||||
].concat(rows));
|
].concat(rows));
|
||||||
@@ -343,8 +343,8 @@ return view.extend({
|
|||||||
var section = (vendorId && productId) ? self.findUsbSection(vendorId, productId) : null;
|
var section = (vendorId && productId) ? self.findUsbSection(vendorId, productId) : null;
|
||||||
var owners = (vendorId && productId) ? self.usbOwners(vendorId, productId) : [];
|
var owners = (vendorId && productId) ? self.usbOwners(vendorId, productId) : [];
|
||||||
|
|
||||||
var passthroughStatus = section ? _('Passthrough active (section: %s)').format(section) : _('Not passthrough');
|
var passthroughStatus = section ? _('Active<br />Section: %s').format(section) : _('Not passthrough');
|
||||||
if (owners.length) passthroughStatus += ' ' + _('(attached to VM: %s)').format(owners.join(', '));
|
if (owners.length) passthroughStatus += ' ' + _('<br />Host: %s').format(owners.join(', '));
|
||||||
|
|
||||||
var actionButton;
|
var actionButton;
|
||||||
if (section) {
|
if (section) {
|
||||||
@@ -371,9 +371,9 @@ return view.extend({
|
|||||||
return E('table', { 'class': 'table' }, [
|
return E('table', { 'class': 'table' }, [
|
||||||
E('tr', { 'class': 'tr table-titles' }, [
|
E('tr', { 'class': 'tr table-titles' }, [
|
||||||
E('th', { 'class': 'th' }, _('Bus:Dev')),
|
E('th', { 'class': 'th' }, _('Bus:Dev')),
|
||||||
E('th', { 'class': 'th' }, _('VendorID:ProductID')),
|
E('th', { 'class': 'th' }, _('VID:PID')),
|
||||||
E('th', { 'class': 'th' }, _('Description')),
|
E('th', { 'class': 'th' }, _('Description')),
|
||||||
E('th', { 'class': 'th' }, _('Passthrough status')),
|
E('th', { 'class': 'th', 'style': 'min-width: 140px;' }, _('Status')),
|
||||||
E('th', { 'class': 'th' }, _('Action'))
|
E('th', { 'class': 'th' }, _('Action'))
|
||||||
])
|
])
|
||||||
].concat(rows));
|
].concat(rows));
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ return view.extend({
|
|||||||
|
|
||||||
handleLog: function(name, ev) {
|
handleLog: function(name, ev) {
|
||||||
return callReadlog(name, 400).then(function(res) {
|
return callReadlog(name, 400).then(function(res) {
|
||||||
ui.showModal(_('Console log: %s').format(name), [
|
ui.showModal(_('Instanse log: %s').format(name), [
|
||||||
E('pre', {
|
E('pre', {
|
||||||
'style': 'max-height: 60vh; overflow: auto; white-space: pre-wrap; font-size: 12px;'
|
'style': 'max-height: 60vh; overflow: auto; white-space: pre-wrap; font-size: 12px;'
|
||||||
}, res.log || _('(empty)')),
|
}, res.log || _('(empty)')),
|
||||||
@@ -493,6 +493,9 @@ return view.extend({
|
|||||||
E('label', { 'class': 'cbi-value-title' }, _('Attached networks')),
|
E('label', { 'class': 'cbi-value-title' }, _('Attached networks')),
|
||||||
E('div', { 'class': 'cbi-value-field' }, networkChecks)
|
E('div', { 'class': 'cbi-value-field' }, networkChecks)
|
||||||
]),
|
]),
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('p', { 'class': 'cbi-value-description' }, _('Changes will take effect after restarting the VM.'))
|
||||||
|
]),
|
||||||
E('div', { 'class': 'right', 'style': 'margin-top: 1em' }, [
|
E('div', { 'class': 'right', 'style': 'margin-top: 1em' }, [
|
||||||
E('button', { 'class': 'btn', 'click': ui.hideModal }, _('Cancel')),
|
E('button', { 'class': 'btn', 'click': ui.hideModal }, _('Cancel')),
|
||||||
' ',
|
' ',
|
||||||
@@ -590,6 +593,13 @@ return view.extend({
|
|||||||
else
|
else
|
||||||
uci.unset('qemu-vms', name, 'pci_passthrough');
|
uci.unset('qemu-vms', name, 'pci_passthrough');
|
||||||
|
|
||||||
|
var newUsb = Array.prototype.slice.call(document.querySelectorAll('.edit-usb-check:checked'))
|
||||||
|
.map(function(el) { return el.value; });
|
||||||
|
if (newUsb.length)
|
||||||
|
uci.set('qemu-vms', name, 'usb_passthrough', newUsb);
|
||||||
|
else
|
||||||
|
uci.unset('qemu-vms', name, 'usb_passthrough');
|
||||||
|
|
||||||
|
|
||||||
//var nets = Array.prototype.slice.call(document.querySelectorAll('.edit-network-check:checked'))
|
//var nets = Array.prototype.slice.call(document.querySelectorAll('.edit-network-check:checked'))
|
||||||
// .map(function(el) { return el.value; });
|
// .map(function(el) { return el.value; });
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ console_close() {
|
|||||||
readlog() {
|
readlog() {
|
||||||
local vm="$1"
|
local vm="$1"
|
||||||
local lines="${2:-200}"
|
local lines="${2:-200}"
|
||||||
local log="/var/log/qemu-$vm-console.log"
|
local log="/var/log/qemu-vms/$vm.log"
|
||||||
|
|
||||||
json_init
|
json_init
|
||||||
if [ -f "$log" ]; then
|
if [ -f "$log" ]; then
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=qemu-vms
|
PKG_NAME:=qemu-vms
|
||||||
PKG_VERSION:=0.0.1
|
PKG_VERSION:=0.0.1
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=2
|
||||||
PKG_MAINTAINER:=Konstantine Shevlakov <shevlakov@132lan.ru>
|
PKG_MAINTAINER:=Konstantine Shevlakov <shevlakov@132lan.ru>
|
||||||
|
|
||||||
include $(INCLUDE_DIR)/package.mk
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
|||||||
@@ -5,6 +5,23 @@ STOP=10
|
|||||||
USE_PROCD=1
|
USE_PROCD=1
|
||||||
|
|
||||||
STATUS_DIR="/var/run/qemu-vms"
|
STATUS_DIR="/var/run/qemu-vms"
|
||||||
|
LOG_DIR="/var/log/qemu-vms"
|
||||||
|
|
||||||
|
host_log() {
|
||||||
|
# Per-VM HOST-side lifecycle log: start/stop attempts, config
|
||||||
|
# warnings (missing MAC, unknown disk_bus, VNC without a port,
|
||||||
|
# passthrough bind issues), and QEMU's own stderr (KVM unavailable,
|
||||||
|
# image not found, device init failures). Deliberately separate from
|
||||||
|
# the guest's own serial console capture
|
||||||
|
# (/var/log/qemu-$vm-console.log): that one shows what the GUEST OS
|
||||||
|
# printed; this one shows whether the HOST managed to start/
|
||||||
|
# configure the VM at all - meaningful for VNC-mode VMs too, which
|
||||||
|
# have no serial console capture at all.
|
||||||
|
local cfg="$1"
|
||||||
|
shift
|
||||||
|
mkdir -p "$LOG_DIR"
|
||||||
|
echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> "$LOG_DIR/$cfg.log"
|
||||||
|
}
|
||||||
|
|
||||||
is_anonymous_section() {
|
is_anonymous_section() {
|
||||||
# UCI auto-generated names look like: cfgXXXXXX (cfg + hex)
|
# UCI auto-generated names look like: cfgXXXXXX (cfg + hex)
|
||||||
@@ -84,6 +101,27 @@ _add_usb() {
|
|||||||
usb_needed=1
|
usb_needed=1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_unbind_usb_host() {
|
||||||
|
local usbcfg="$1"
|
||||||
|
local vendor_id product_id
|
||||||
|
config_get vendor_id "$usbcfg" vendor_id
|
||||||
|
config_get product_id "$usbcfg" product_id
|
||||||
|
[ -n "$vendor_id" ] && [ -n "$product_id" ] || return 0
|
||||||
|
for dev in /sys/bus/usb/devices/*; do
|
||||||
|
if [ -f "$dev/idVendor" ] && [ -f "$dev/idProduct" ]; then
|
||||||
|
local v=$(cat "$dev/idVendor") p=$(cat "$dev/idProduct")
|
||||||
|
if [ "$v" = "$vendor_id" ] && [ "$p" = "$product_id" ]; then
|
||||||
|
if [ -L "$dev/driver" ]; then
|
||||||
|
local driver_path=$(readlink -f "$dev/driver")
|
||||||
|
local driver_name=$(basename "$driver_path")
|
||||||
|
echo -n "$(basename "$dev")" > "$driver_path/unbind" 2>/dev/null
|
||||||
|
host_log "$cfg" "USB: unbound $(basename "$dev") from $driver_name"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
build_customargs() {
|
build_customargs() {
|
||||||
local cfg="$1"
|
local cfg="$1"
|
||||||
custom_opts=""
|
custom_opts=""
|
||||||
@@ -113,24 +151,30 @@ build_diskargs() {
|
|||||||
|
|
||||||
case "$bus" in
|
case "$bus" in
|
||||||
virtio)
|
virtio)
|
||||||
disk_opts="-drive file=$image,format=raw,if=virtio"
|
#disk_opts="-drive file=$image,format=raw,if=virtio"
|
||||||
|
disk_opts="-drive file=$image,if=virtio"
|
||||||
;;
|
;;
|
||||||
ide)
|
ide)
|
||||||
# Widest guest compatibility (old Windows/DOS/legacy kernels
|
# Widest guest compatibility (old Windows/DOS/legacy kernels
|
||||||
# without virtio drivers), at some cost to I/O throughput.
|
# without virtio drivers), at some cost to I/O throughput.
|
||||||
disk_opts="-drive file=$image,format=raw,if=ide"
|
#disk_opts="-drive file=$image,format=$format,if=ide"
|
||||||
|
disk_opts="-drive file=$image,if=ide"
|
||||||
;;
|
;;
|
||||||
scsi)
|
scsi)
|
||||||
disk_controller_opts="-device virtio-scsi-pci,id=scsi0"
|
disk_controller_opts="-device virtio-scsi-pci,id=scsi0"
|
||||||
disk_opts="-drive file=$image,format=raw,if=none,id=drive0 -device scsi-hd,drive=drive0,bus=scsi0.0"
|
#disk_opts="-drive file=$image,format=$format,if=none,id=drive0 -device scsi-hd,drive=drive0,bus=scsi0.0"
|
||||||
|
disk_opts="-drive file=$image,if=none,id=drive0 -device scsi-hd,drive=drive0,bus=scsi0.0"
|
||||||
;;
|
;;
|
||||||
sata|ahci)
|
sata|ahci)
|
||||||
disk_controller_opts="-device ahci,id=ahci0"
|
disk_controller_opts="-device ahci,id=ahci0"
|
||||||
disk_opts="-drive file=$image,format=raw,if=none,id=drive0 -device ide-hd,drive=drive0,bus=ahci0.0"
|
#disk_opts="-drive file=$image,format=$format,if=none,id=drive0 -device ide-hd,drive=drive0,bus=ahci0.0"
|
||||||
|
disk_opts="-drive file=$image,if=none,id=drive0 -device ide-hd,drive=drive0,bus=ahci0.0"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
logger -t qemu-vms "WARNING: VM '$cfg' has unknown disk_bus '$bus', falling back to virtio"
|
logger -t qemu-vms "WARNING: VM '$cfg' has unknown disk_bus '$bus', falling back to virtio"
|
||||||
disk_opts="-drive file=$image,format=raw,if=virtio"
|
#disk_opts="-drive file=$image,format=$format,if=virtio"
|
||||||
|
disk_opts="-drive file=$image,if=virtio"
|
||||||
|
host_log "$cfg" "WARNING: unknown disk_bus '$bus', falling back to virtio"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@@ -145,12 +189,15 @@ start_vm() {
|
|||||||
[ "$enabled" = "1" ] || return 0
|
[ "$enabled" = "1" ] || return 0
|
||||||
|
|
||||||
local existing_pid
|
local existing_pid
|
||||||
|
existing_pid="$(cat "$STATUS_DIR/$cfg.pid" 2>/dev/null)"
|
||||||
if [ -n "$existing_pid" ] && kill -0 "$existing_pid" 2>/dev/null && \
|
if [ -n "$existing_pid" ] && kill -0 "$existing_pid" 2>/dev/null && \
|
||||||
grep -aq "qemu-system-x86_64" "/proc/$existing_pid/cmdline" 2>/dev/null; then
|
grep -aq "qemu-system-x86_64" "/proc/$existing_pid/cmdline" 2>/dev/null; then
|
||||||
logger -t qemu-vms "start_vm: '$cfg' already running (pid $existing_pid), skipping"
|
logger -t qemu-vms "start_vm: '$cfg' already running (pid $existing_pid), skipping"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
host_log "$cfg" "=== start_vm: attempting to start ==="
|
||||||
|
|
||||||
warn_if_anonymous "$cfg"
|
warn_if_anonymous "$cfg"
|
||||||
|
|
||||||
config_get image "$cfg" image
|
config_get image "$cfg" image
|
||||||
@@ -158,6 +205,7 @@ start_vm() {
|
|||||||
config_get memory "$cfg" memory 128
|
config_get memory "$cfg" memory 128
|
||||||
config_get smp "$cfg" smp 1
|
config_get smp "$cfg" smp 1
|
||||||
config_get cpu "$cfg" cpu "host"
|
config_get cpu "$cfg" cpu "host"
|
||||||
|
config_list_foreach "$cfg" usb_passthrough _unbind_usb_host
|
||||||
config_get pci_passthrough "$cfg" pci_passthrough
|
config_get pci_passthrough "$cfg" pci_passthrough
|
||||||
config_get display_type "$cfg" display_type "serial"
|
config_get display_type "$cfg" display_type "serial"
|
||||||
config_get vnc_port "$cfg" vnc_port
|
config_get vnc_port "$cfg" vnc_port
|
||||||
@@ -176,12 +224,47 @@ start_vm() {
|
|||||||
config_get pci_id "$pci_passthrough" pci_id
|
config_get pci_id "$pci_passthrough" pci_id
|
||||||
config_get vendor_id "$pci_passthrough" vendor_id
|
config_get vendor_id "$pci_passthrough" vendor_id
|
||||||
if [ -n "$vendor_id" ] && [ -n "$pci_id" ]; then
|
if [ -n "$vendor_id" ] && [ -n "$pci_id" ]; then
|
||||||
[ -e "/sys/bus/pci/devices/0000:$pci_id/driver" ] || \
|
if [ -e "/sys/bus/pci/devices/0000:$pci_id/driver" ]; then
|
||||||
|
local current_driver
|
||||||
|
current_driver="$(basename "$(readlink -f "/sys/bus/pci/devices/0000:$pci_id/driver" 2>/dev/null)" 2>/dev/null)"
|
||||||
|
host_log "$cfg" "PCI passthrough: $pci_id already bound to driver '$current_driver'"
|
||||||
|
else
|
||||||
echo "$vendor_id" > /sys/bus/pci/drivers/vfio-pci/new_id 2>/dev/null
|
echo "$vendor_id" > /sys/bus/pci/drivers/vfio-pci/new_id 2>/dev/null
|
||||||
|
if [ -e "/sys/bus/pci/devices/0000:$pci_id/driver" ]; then
|
||||||
|
host_log "$cfg" "PCI passthrough: bound $pci_id (vendor/device $vendor_id) to vfio-pci"
|
||||||
|
else
|
||||||
|
host_log "$cfg" "WARNING: PCI passthrough: failed to bind $pci_id to vfio-pci - check IOMMU/BIOS settings"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
pci_opts="-device vfio-pci,host=$pci_id"
|
pci_opts="-device vfio-pci,host=$pci_id"
|
||||||
|
else
|
||||||
|
host_log "$cfg" "WARNING: pci_passthrough='$pci_passthrough' is set but its pci_id/vendor_id are incomplete - skipping passthrough"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Test version PCI Pass
|
||||||
|
#local pci_id="" pci_opts=""
|
||||||
|
#if [ -n "$pci_passthrough" ]; then
|
||||||
|
# config_get pci_id "$pci_passthrough" pci_id
|
||||||
|
# if [ -n "$pci_id" ]; then
|
||||||
|
# local pci_path="/sys/bus/pci/devices/0000:$pci_id"
|
||||||
|
# if [ -e "$pci_path/driver" ]; then
|
||||||
|
# echo -n "0000:$pci_id" > "$pci_path/driver/unbind" 2>/dev/null
|
||||||
|
# host_log "$cfg" "PCI: unbound $pci_id from $(basename "$(readlink -f "$pci_path/driver")")"
|
||||||
|
# fi
|
||||||
|
# echo "vfio-pci" > "$pci_path/driver_override" 2>/dev/null
|
||||||
|
# echo "0000:$pci_id" > /sys/bus/pci/drivers/vfio-pci/bind 2>/dev/null
|
||||||
|
# if [ -e "$pci_path/driver" ] && [ "$(basename "$(readlink -f "$pci_path/driver")")" = "vfio-pci" ]; then
|
||||||
|
# host_log "$cfg" "PCI passthrough: $pci_id successfully bound to vfio-pci"
|
||||||
|
# else
|
||||||
|
# host_log "$cfg" "ERROR: PCI passthrough: failed to bind $pci_id to vfio-pci. Check IOMMU groups and BIOS settings."
|
||||||
|
# fi
|
||||||
|
# pci_opts="-device vfio-pci,host=$pci_id"
|
||||||
|
# else
|
||||||
|
# host_log "$cfg" "WARNING: pci_passthrough section exists but pci_id is empty - skipping"
|
||||||
|
# fi
|
||||||
|
#fi
|
||||||
|
|
||||||
local cdrom_opts=""
|
local cdrom_opts=""
|
||||||
[ -n "$cdrom" ] && cdrom_opts="-cdrom $cdrom"
|
[ -n "$cdrom" ] && cdrom_opts="-cdrom $cdrom"
|
||||||
|
|
||||||
@@ -206,10 +289,12 @@ start_vm() {
|
|||||||
|
|
||||||
#rm -f "$console_sock" "$qmp_sock"
|
#rm -f "$console_sock" "$qmp_sock"
|
||||||
mkdir -p "$STATUS_DIR"
|
mkdir -p "$STATUS_DIR"
|
||||||
|
mkdir -p "$LOG_DIR"
|
||||||
mkdir -p "$(dirname "$console_log")"
|
mkdir -p "$(dirname "$console_log")"
|
||||||
|
|
||||||
procd_open_instance "qemu-$cfg"
|
procd_open_instance "qemu-$cfg"
|
||||||
procd_set_param command /usr/bin/qemu-system-x86_64 \
|
procd_set_param command /usr/libexec/qemu-vms/run-with-log.sh "$LOG_DIR/$cfg.log" \
|
||||||
|
/usr/bin/qemu-system-x86_64 \
|
||||||
-enable-kvm -cpu "$cpu" -smp "$smp" -m "${memory}M" \
|
-enable-kvm -cpu "$cpu" -smp "$smp" -m "${memory}M" \
|
||||||
$disk_controller_opts $disk_opts \
|
$disk_controller_opts $disk_opts \
|
||||||
$device_opts $netdev_opts $pci_opts $cdrom_opts $usb_controller_opts $usb_opts $vnc_opts $custom_opts \
|
$device_opts $netdev_opts $pci_opts $cdrom_opts $usb_controller_opts $usb_opts $vnc_opts $custom_opts \
|
||||||
@@ -244,6 +329,6 @@ start_service() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
service_triggers() {
|
#service_triggers() {
|
||||||
procd_add_reload_trigger "qemu-vms"
|
# procd_add_reload_trigger "qemu-vms"
|
||||||
}
|
#}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# /usr/libexec/qemu-vms/run-with-log.sh
|
||||||
|
#
|
||||||
|
# Usage: run-with-log.sh <logfile> <command> [args...]
|
||||||
|
#
|
||||||
|
# Appends the wrapped command's stdout/stderr to <logfile>, then execs it.
|
||||||
|
# Deliberately does NOT build a shell string out of <command>/[args...] -
|
||||||
|
# they are received and forwarded as genuine argv elements ("$@"), never
|
||||||
|
# re-parsed as shell syntax. This matters because some of the arguments
|
||||||
|
# QEMU is started with (e.g. custom_arg from the LuCI "Custom QEMU
|
||||||
|
# arguments" field) are admin-supplied free text: if this script instead
|
||||||
|
# did something like `sh -c "exec $* >>logfile"`, shell metacharacters in
|
||||||
|
# that text (;, `, $(...), |, &&) would be interpreted as shell syntax
|
||||||
|
# and executed - not just passed to qemu as inert argv text. Using "$@"
|
||||||
|
# throughout preserves the same "argv, not a string" trust model as a
|
||||||
|
# direct (unwrapped) exec.
|
||||||
|
|
||||||
|
logfile="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
exec "$@" >> "$logfile" 2>&1
|
||||||
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=sqm-autorate
|
PKG_NAME:=sqm-autorate
|
||||||
PKG_VERSION:=0.1
|
PKG_VERSION:=0.1
|
||||||
PKG_RELEASE:=2
|
PKG_RELEASE:=3
|
||||||
|
|
||||||
include $(INCLUDE_DIR)/package.mk
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ set -o pipefail
|
|||||||
export LC_ALL=C
|
export LC_ALL=C
|
||||||
|
|
||||||
# Set PREFIX
|
# Set PREFIX
|
||||||
PREFIX=/root/cake-autorate
|
PREFIX=/usr/share/sqm-autorate
|
||||||
|
|
||||||
# shellcheck source=lib.sh
|
# shellcheck source=lib.sh
|
||||||
. "${PREFIX}/lib.sh"
|
. "${PREFIX}/lib.sh"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
cake_instances=(/root/cake-autorate/config.*.sh)
|
cake_instances=(/usr/share/sqm-autorate/config.*.sh)
|
||||||
cake_instance_pids=()
|
cake_instance_pids=()
|
||||||
|
|
||||||
trap kill_cake_instances INT TERM EXIT
|
trap kill_cake_instances INT TERM EXIT
|
||||||
@@ -20,7 +20,7 @@ kill_cake_instances()
|
|||||||
|
|
||||||
for cake_instance in "${cake_instances[@]}"
|
for cake_instance in "${cake_instances[@]}"
|
||||||
do
|
do
|
||||||
/root/cake-autorate/cake-autorate.sh "${cake_instance}" &
|
/usr/share/sqm-autorate/cake-autorate.sh "${cake_instance}" &
|
||||||
cake_instance_pids+=(${!})
|
cake_instance_pids+=(${!})
|
||||||
done
|
done
|
||||||
wait
|
wait
|
||||||
Reference in new issue
Block a user