mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-10-30 15:05:13 +08:00
update 2026-09-26 11:07:27
This commit is contained in:
1 parent
7b88b273d0
commit
97ae9f68da
4898 files changed
-1712274
No files matched your search
@@ -1,5 +0,0 @@
|
||||
config global 'global'
|
||||
option target_function '/opt'
|
||||
option target_disk ''
|
||||
option keep_config '0'
|
||||
option format_type '0'
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
chmod +x /usr/bin/partexp /usr/libexec/rpcd/partexp
|
||||
/etc/init.d/rpcd restart
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
||||
@@ -1,803 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright (C) 2021-2026 sirpdboy <herboy2008@gmail.com> https://github.com/sirpdboy/luci-app-partexp
|
||||
#
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
#
|
||||
|
||||
CONFIG="partexp"
|
||||
LOCK=/var/lock/$CONFIG.lock
|
||||
LOGD=/var/$CONFIG
|
||||
LOG=$LOGD/bk$CONFIG.log
|
||||
|
||||
[ -d "$LOGD" ] || mkdir -p $LOGD
|
||||
|
||||
|
||||
init_env() {
|
||||
[ ! -f "$LOG" ] && echo " " > $LOG
|
||||
}
|
||||
|
||||
gen_log() {
|
||||
log " == 开始执行 == " | tee -a $LOG
|
||||
}
|
||||
|
||||
log(){
|
||||
echo -e " $(date +'%Y-%m-%d %H:%M:%S') $*" | tee -a $LOG
|
||||
}
|
||||
|
||||
logn(){
|
||||
echo -e " $*" | tee -a $LOG
|
||||
}
|
||||
|
||||
load_uci_config() {
|
||||
if [ -f "/etc/config/$CONFIG" ]; then
|
||||
target_function=$(uci -q get $CONFIG.global.target_function)
|
||||
target_disk=$(uci -q get $CONFIG.global.target_disk)
|
||||
keep_config=$(uci -q get $CONFIG.global.keep_config)
|
||||
format_type=$(uci -q get $CONFIG.global.format_type)
|
||||
|
||||
target_function="${target_function:-/opt}"
|
||||
keep_config="${keep_config:-0}"
|
||||
format_type="${format_type:-0}"
|
||||
|
||||
return 0
|
||||
else
|
||||
log "警告:配置文件不存在"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
is_disk_mounted() {
|
||||
DISK=$1
|
||||
if mount | grep -q "$DISK "; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
mount_device() {
|
||||
local DEVICE=$1
|
||||
local MOUNT_POINT=$2
|
||||
local TYPE=$3
|
||||
|
||||
if [ ! -e "$DEVICE" ]; then
|
||||
log "设备 $DEVICE 不存在"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$MOUNT_POINT" ]; then
|
||||
log "挂载点 $MOUNT_POINT 不存在,正在创建..."
|
||||
mkdir -p "$MOUNT_POINT"
|
||||
if [ $? -ne 0 ]; then
|
||||
log "无法创建挂载点 $MOUNT_POINT"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if mount | grep -q "$DEVICE"; then
|
||||
log "设备 $DEVICE 已挂载到其他位置"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if mount | grep -q "$MOUNT_POINT"; then
|
||||
log "挂载点 $MOUNT_POINT 已被其他设备占用"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log "正在挂载 $DEVICE 到 $MOUNT_POINT..."
|
||||
|
||||
mount $TYPE "$DEVICE" "$MOUNT_POINT" >/dev/null 2> /dev/null
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
log "挂载成功: $DEVICE -> $MOUNT_POINT"
|
||||
return 0
|
||||
else
|
||||
log "挂载失败: $DEVICE -> $MOUNT_POINT"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 取消硬盘挂载
|
||||
umount_disk() {
|
||||
DISK=$1
|
||||
MOUNT=''
|
||||
eval $(block info "$DISK" | grep -o -e "MOUNT=\S*")
|
||||
if [ "$MOUNT" ]; then
|
||||
umount $DISK 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
log "取消挂载:$DISK成功"
|
||||
else
|
||||
log "取消挂载:$DISK失败,请手动操作"
|
||||
fi
|
||||
else
|
||||
log "设备/dev/$DISK未挂载"
|
||||
fi
|
||||
}
|
||||
|
||||
# 从 block info 中提取指定字段的值
|
||||
get_block() {
|
||||
local DISK=$1
|
||||
local TYPE=$2
|
||||
local value
|
||||
value=`mount | grep $DISK |awk -F $TYPE '{print $2}' |awk '{print $1}' | head -1`
|
||||
echo $value
|
||||
}
|
||||
|
||||
# 检查是否有共享挂载(如 Samba 或 NFS)
|
||||
check_shared_mount() {
|
||||
DISK=$1
|
||||
if [ -f /etc/config/samba ]; then
|
||||
SHARED=$(grep -q "/dev/$DISK" /etc/config/samba)
|
||||
if [ $? -eq 0 ]; then
|
||||
log "检测到 Samba 共享挂载: /dev/$DISK"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f /etc/exports ]; then
|
||||
SHARED=$(grep -q "/dev/$DISK" /etc/exports)
|
||||
if [ $? -eq 0 ]; then
|
||||
log "检测到 NFS 共享挂载: /dev/$DISK"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
usamba(){
|
||||
s=$1
|
||||
[ -e "/etc/config/$s" ] && {
|
||||
msum=$(grep -c "config sambashare" /etc/config/$s)
|
||||
for i in $(seq 0 $((msum)));do
|
||||
pdev=`uci -q get $s.@sambashare[$i].path `
|
||||
[ "$pdev" = "$2" ] && {
|
||||
uci delete $s.@sambashare[$i]
|
||||
uci commit $s
|
||||
log "分区/dev/$b被挂载$MOUNT共享使用,删除$s共享成功!"
|
||||
sleep 5
|
||||
}
|
||||
done
|
||||
}
|
||||
|
||||
if [ -f /etc/config/$s ]; then
|
||||
sed -i "/\/dev\/$b/d" /etc/config/$s
|
||||
/etc/init.d/$s restart
|
||||
fi
|
||||
|
||||
if [ -f /etc/exports ]; then
|
||||
sed -i "/\/dev\/$b/d" /etc/exports
|
||||
/etc/init.d/nfs restart
|
||||
fi
|
||||
}
|
||||
|
||||
is_disk_partitioned() {
|
||||
PARTITION_COUNT=$(fdisk -l /dev/$1 2>/dev/null | grep -E "^/dev/$2" | wc -l)
|
||||
if [[ "$PARTITION_COUNT" -gt 0 ]]; then
|
||||
echo 1
|
||||
else
|
||||
echo 0
|
||||
fi
|
||||
}
|
||||
|
||||
partednew(){
|
||||
DISK=$1
|
||||
parted -s /dev/$DISK mklabel gpt
|
||||
parted -s /dev/$DISK mkpart primary ext4 1MiB -1
|
||||
}
|
||||
|
||||
fdisknew(){
|
||||
echo -e "n\np\n\n\n\nw" | fdisk /dev/$1 >/dev/null 2> /dev/null
|
||||
}
|
||||
|
||||
fdisksave(){
|
||||
echo -e "n\w" | fdisk /dev/$1 >/dev/null 2> /dev/null
|
||||
}
|
||||
|
||||
# 格式化磁盘函数 DISK=/dev/sda1 ;TYPE=btrfs
|
||||
format_disk() {
|
||||
local DISK=$1
|
||||
local TYPE=$2
|
||||
[[ $TYPE == '0' || $TYPE == '' ]] && TYPE="ext4"
|
||||
log "正在格式化 $DISK "
|
||||
mkfs.$TYPE -F "$DISK" >/dev/null 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
log "格式化 $TYPE 成功 $DISK"
|
||||
return 0
|
||||
else
|
||||
log "格式化 $TYPE 失败 $DISK"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# 获取系统盘
|
||||
get_system_disk() {
|
||||
rom_dev=$(df -h | grep boot | awk '{print $1}' | head -1 )
|
||||
[ -z ${rom_dev} ] && rom_dev=`df -P /boot 2>/dev/null | awk 'NR==2 {print $1}'`
|
||||
[ -z ${rom_dev} ] && rom_dev=`blkid -t TYPE="squashfs" |awk -F : '{print $1}'`
|
||||
[ -z ${rom_dev} ] && TDISK=`lsblk -l -o NAME,MOUNTPOINTS | grep -E '/rom'| grep -v '/rom/' | head -1 | awk '{print $1}'` && rom_dev="/dev/$TDISK"
|
||||
if [ -n "$rom_dev" ]; then
|
||||
case "$rom_dev" in
|
||||
/dev/sd[a-z][0-9]*)
|
||||
disk=$(echo "$rom_dev" | sed 's/[0-9]*$//')
|
||||
;;
|
||||
/dev/nvme[0-9]*n[0-9]*p[0-9]*)
|
||||
disk=$(echo "$rom_dev" | sed 's/p[0-9]*$//')
|
||||
;;
|
||||
/dev/mmcblk[0-9]*p[0-9]*)
|
||||
disk=$(echo "$rom_dev" | sed 's/p[0-9]*$//')
|
||||
;;
|
||||
/dev/vd[a-z][0-9]*)
|
||||
disk=$(echo "$rom_dev" | sed 's/[0-9]*$//')
|
||||
;;
|
||||
/dev/mtdblock*)
|
||||
disk="$rom_dev"
|
||||
;;
|
||||
/dev/ubiblock*)
|
||||
disk="$rom_dev"
|
||||
;;
|
||||
/dev/root)
|
||||
# 特殊处理 /dev/root
|
||||
disk=$(lsblk -no PKNAME / 2>/dev/null)
|
||||
if [ -n "$disk" ]; then
|
||||
disk="/dev/$disk"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# 尝试通用匹配
|
||||
if echo "$rom_dev" | grep -qE '^/dev/[a-z]+[0-9]+'; then
|
||||
disk=$(echo "$rom_dev" | sed 's/[0-9]*$//')
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ -n "$disk" ] && [ ! -b "$disk" ]; then
|
||||
disk=""
|
||||
fi
|
||||
|
||||
echo "$disk"
|
||||
}
|
||||
|
||||
get_all_disks() {
|
||||
DISKS=`find /dev -regex '.*/\(sd[a-z]\|mmcblk[0-9]\+\|sata[a-z]\|nvme[0-9]\+n[0-9]\+\|vd[a-z]\)$'`
|
||||
echo "$DISKS"
|
||||
}
|
||||
|
||||
check_part_space() {
|
||||
DISK=$1
|
||||
info=$(lsblk -no SIZE,FSTYPE,MOUNTPOINT "$DISK" | awk '{print $1}')
|
||||
if [ -z "$info" ]; then
|
||||
echo "物理大小: 未知(可能是未格式化的裸分区)"
|
||||
else
|
||||
echo $info |awk -F '.' '{print $1}' | sed 's/[A-Za-z]//g'
|
||||
fi
|
||||
}
|
||||
|
||||
check_free_space() {
|
||||
DISK=$1
|
||||
PARTED_OUTPUT=$(parted -s /dev/$DISK unit GB print free 2>/dev/null)
|
||||
FREE_SPACE=$(echo "$PARTED_OUTPUT" | awk '/Free Space/ {last=$3} END {print last}' | sed 's/GB$//')
|
||||
echo $FREE_SPACE | cut -d'.' -f1
|
||||
}
|
||||
|
||||
show_partition_info() {
|
||||
local partition="$1"
|
||||
if [ ! -e "$partition" ]; then
|
||||
logn "错误:分区 $partition 不存在!"
|
||||
return 1
|
||||
fi
|
||||
logn " === 分区信息 [$partition] ==="
|
||||
local lsblk_info=$(lsblk -no SIZE,FSTYPE,MOUNTPOINT "$partition" 2>/dev/null)
|
||||
if [ -z "$lsblk_info" ]; then
|
||||
logn "物理大小: 未知(可能是未格式化的裸分区)"
|
||||
else
|
||||
local size=$(echo "$lsblk_info" | awk '{print $1}')
|
||||
local fstype=$(echo "$lsblk_info" | awk '{print $2}')
|
||||
local mountpoint=$(echo "$lsblk_info" | awk '{print $3}')
|
||||
logn "物理大小: $size 文件系统: ${fstype:-未知} 挂载点: ${mountpoint:-未挂载}"
|
||||
fi
|
||||
if df "$partition" &>/dev/null; then
|
||||
local df_info=$(df -h "$partition" | tail -n 1 | awk 'NR=2 {print $2,$3,$4,$5}')
|
||||
logn "[已挂载] 空间使用情况:"
|
||||
logn "总容量: $(echo "$df_info" | awk '{print $1}') 已用: $(echo "$df_info" | awk '{print $2}') 剩余: $(echo "$df_info" | awk '{print $3}') 使用率: $(echo "$df_info" | awk '{print $4}')"
|
||||
|
||||
else
|
||||
logn "[未挂载] 无法查询使用情况(需先挂载)"
|
||||
fi
|
||||
|
||||
local disk="${partition%[0-9]*}"
|
||||
local part_num="${partition##*[!0-9]}"
|
||||
logn "分区表信息:"
|
||||
logn `parted -s "$disk" unit MiB print | grep -w "^ $part_num" | awk '{print "起始: " $2 " MiB | 结束: " $3 " MiB | 类型: " $5}'`
|
||||
|
||||
}
|
||||
|
||||
get_next_partition_number() {
|
||||
DISK=$1
|
||||
PARTITIONS=$(fdisk -l /dev/$DISK 2>/dev/null | grep -v boot | grep -E "^/dev/$DISK" | awk '{print $1}' | sed 's/\/dev\/[a-z]*//g' | awk -F '[^0-9]+' '{print $NF}')
|
||||
MAX_PARTITION=$(echo "$PARTITIONS" | sort -n | tail -n 1)
|
||||
NEXT_PARTITION=$(awk -v n="$MAX_PARTITION" 'BEGIN { print n + 1 }')
|
||||
echo "$NEXT_PARTITION"
|
||||
}
|
||||
|
||||
get_last_partition_number() {
|
||||
DISK=$1
|
||||
PARTITIONS=$(fdisk -l /dev/$DISK 2>/dev/null | grep -v boot | grep -E "^/dev/$DISK" | awk '{print $1}' | sed 's/\/dev\/[a-z]*//g' | awk -F '[^0-9]+' '{print $NF}')
|
||||
MAX_PARTITION=$(echo "$PARTITIONS" | sort -n | tail -n 1)
|
||||
echo "$MAX_PARTITION"
|
||||
}
|
||||
|
||||
get_partition_number() {
|
||||
DISK=$1
|
||||
PARTITIONS=$(fdisk -l /dev/$DISK 2>/dev/null | grep -v boot | grep -E "^/dev/$DISK" | awk '{print $1}' | sed 's/\/dev\/[a-z]*//g' | wc -l)
|
||||
echo "$PARTITIONS"
|
||||
}
|
||||
|
||||
rootpt_resize() {
|
||||
if [ ! -e /etc/rootpt-resize ]; then
|
||||
log "--->请稍侯,系统根分区扩展中<---"
|
||||
ROOTBLK="$(readlink -f /sys/dev/block/"$(awk -e '$9="/dev/root"{print $3}' /proc/self/mountinfo)")"
|
||||
ROOTDISK="/dev/$(basename "${ROOTBLK%/}")"
|
||||
ROOTPART="${ROOTBLK##*[^0-9]}"
|
||||
partplace=$(fdisk -l 2>/dev/null | grep "$ROOTDISK" | awk '{print $5}' )
|
||||
log "--->根分区$ROOTDISK:$partplace <---"
|
||||
sleep 3
|
||||
parted -f -s "${ROOTDISK}" resizepart "${ROOTPART}" 100%
|
||||
mount_root done
|
||||
touch /etc/rootpt-resize
|
||||
sleep 3
|
||||
log "--->系统根分区扩展成功!<---"
|
||||
partplace=$(fdisk -l 2>/dev/null | grep "$ROOTDISK" | awk '{print $5}' )
|
||||
log "--->根分区$ROOTDISK扩展后容量:$partplace <---"
|
||||
log "--->如果没生效,请重启设备<---"
|
||||
expquit 2
|
||||
else
|
||||
log "已经扩展过或者挂载分区过,请删除分区或者重置重新操作或者联系作者sirpdboy!"
|
||||
expquit 1
|
||||
fi
|
||||
}
|
||||
|
||||
rootfs_resize() {
|
||||
if [ ! -e /etc/rootfs-resize ] && [ -e /etc/rootpt-resize ]; then
|
||||
log "--->请稍侯,系统根分区扩展中<---"
|
||||
ROOTBLK="$(readlink -f /sys/dev/block/"$(awk -e '$9="/dev/root"{print $3}' /proc/self/mountinfo)")"
|
||||
ROOTPART="${ROOTBLK##*[^0-9]}"
|
||||
ROOTDISK="/dev/$(basename "${ROOTBLK%/}")"
|
||||
partplace=$(fdisk -l 2>/dev/null | grep "$ROOTDISK" | awk '{print $5}' )
|
||||
log "--->根分区$ROOTDISK:$partplace <---"
|
||||
sleep 3
|
||||
parted -f -s "${ROOTDISK}" resizepart "${ROOTPART}" 100%
|
||||
mount_root done
|
||||
touch /etc/rootpt-resize
|
||||
sleep 3
|
||||
log "--->系统根分区扩展成功!<---"
|
||||
partplace=$(fdisk -l 2>/dev/null | grep "$ROOTDISK" | awk '{print $5}' )
|
||||
log "--->根分区$ROOTDISK扩展后容量:$partplace <---"
|
||||
log "--->请稍侯,系统overlay扩展中<---"
|
||||
df -h /overlay | awk 'NR=2 {printf " overlay扩展前: 总容量: %s 已用: %s 剩余: %s 使用率: %s", $2, $3, $4, $5}'
|
||||
LOOPDEV="$(awk -e '$5="/overlay"{print $9}' /proc/self/mountinfo)"
|
||||
if [ -z "${LOOPDEV}" ]; then
|
||||
LOOP_DEV="$(losetup -f)"
|
||||
losetup "${LOOPDEV}" "${ROOTDEV}"
|
||||
fi
|
||||
|
||||
FSTYPE=$(blkid -o value -s TYPE "$LOOPDEV" 2>/dev/null)
|
||||
umount -l /overlay
|
||||
mount -t tmpfs -o size=128M tmpfs /overlay
|
||||
losetup -d /dev/loop0
|
||||
losetup -fP ${ROOTDISK}
|
||||
|
||||
case "$FSTYPE" in
|
||||
f2fs)
|
||||
umount /overlay || { log "错误:无法卸载 /overlay"; expquit 1; }
|
||||
fsck.f2fs -f "$LOOPDEV"
|
||||
resize.f2fs -f "$LOOPDEV" || { log "错误:f2fs 调整大小失败"; expquit 1; }
|
||||
;;
|
||||
ext4)
|
||||
resize2fs -f "$LOOPDEV" || { log "错误:ext4 调整大小失败"; expquit 1; }
|
||||
;;
|
||||
*)
|
||||
log "--->分区格式 $FSTYPE 不识别,overlay 扩展失败!<---"
|
||||
expquit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
mount_root done
|
||||
touch /etc/rootfs-resize
|
||||
sleep 3
|
||||
log "--->系统overlay扩展成功!<---"
|
||||
df -h /overlay | awk 'NR=2 {printf " overlay扩展后: 总容量: %s 已用: %s 剩余: %s 使用率: %s", $2, $3, $4, $5}'
|
||||
log "--->如果没生效,请重启设备<---"
|
||||
expquit 2
|
||||
else
|
||||
log "已经扩展过或者挂载分区过,请删除分区或者重置重新操作或者联系作者sirpdboy!"
|
||||
expquit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# 修改 fdiskB 函数,使用环境变量参数
|
||||
fdiskB() {
|
||||
a=$1
|
||||
b=$1$2
|
||||
log "开始检测目标$a信息"
|
||||
log "检测/dev/$a是否需要分区和格式化"
|
||||
|
||||
block detect > /etc/config/fstab
|
||||
uci -q set fstab.@global[0].anon_mount='0'
|
||||
uci -q set fstab.@global[0].auto_mount='0'
|
||||
uci commit fstab
|
||||
|
||||
if [ "$target_function" = '/opt' ]; then
|
||||
/etc/init.d/dockerd stop >/dev/null 2> /dev/null
|
||||
amount=`mount |grep /opt | awk '{print $1}'`
|
||||
if [ -n "$amount" ]; then
|
||||
umount $amount >/dev/null 2> /dev/null
|
||||
log "取消/opt之前的挂载$amount成功!"
|
||||
fi
|
||||
for OPT in $(mount |grep /opt | awk '{print $3}');do
|
||||
umount $OPT >/dev/null 2> /dev/null
|
||||
log "取消/opt之前的挂载$OPT成功!"
|
||||
done
|
||||
fi
|
||||
|
||||
[ -d "/mnt/$b" ] || mkdir -p /mnt/$b
|
||||
|
||||
if is_disk_mounted "/dev/$b"; then
|
||||
log "设备 /dev/$b 已挂载,尝试取消挂载..."
|
||||
if check_shared_mount $b; then
|
||||
usamba samba4 $MOUNT
|
||||
usamba samba $MOUNT
|
||||
sleep 5
|
||||
fi
|
||||
umount_disk "/dev/$b"
|
||||
[ $? -ne 0 ] || umount_disk "/mnt/$b"
|
||||
else
|
||||
log "设备/dev/$b未挂载"
|
||||
isfdisk=0
|
||||
isP=$(is_disk_partitioned $a $b)
|
||||
if [ "$isP" = '0' ]; then
|
||||
fdisksave $a
|
||||
fdisknew $a
|
||||
sleep 2
|
||||
isfdisk=1
|
||||
fi
|
||||
isP=$(is_disk_partitioned $a $b)
|
||||
if [[ "$isP" = '1' && "$isfdisk" = 1 ]]; then
|
||||
log "分区$b建立成功!"
|
||||
elif [[ "$isP" = '1' && "$isfdisk" = 0 ]]; then
|
||||
log "检测目标分区$b已存在."
|
||||
else
|
||||
log "分区$b建立失败,请检查$b硬盘空间!"
|
||||
expquit 1
|
||||
fi
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
if is_disk_mounted "/dev/$b"; then
|
||||
umount /dev/$b >/dev/null 2> /dev/null
|
||||
[ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null
|
||||
fi
|
||||
sleep 5
|
||||
if [[ "$target_function" = "/" || "$target_function" = "/overlay" ]]; then
|
||||
format_disk "/dev/$b" $format_type
|
||||
elif [[ "$format_type" != "0" || "$isfdisk" = "1" ]]; then
|
||||
format_disk "/dev/$b" $format_type
|
||||
else
|
||||
log "设备/dev/$b如果未格式化,可能无法正常使用."
|
||||
fi
|
||||
|
||||
TYPE=''
|
||||
eval $(blkid "/dev/$b" | grep -o -e "TYPE=\S*")
|
||||
log "检测设备/dev/$b分区$TYPE格式!"
|
||||
|
||||
sleep 1
|
||||
if [ "$TYPE" = "ntfs" ]; then
|
||||
if [ `which ntfs-3g` ]; then
|
||||
if is_disk_mounted "/mnt/$b"; then
|
||||
mount_device /dev/$b /mnt/$b "-t ntfs-3g"
|
||||
fi
|
||||
else
|
||||
if is_disk_mounted "/mnt/$b"; then
|
||||
mount_device /dev/$b /mnt/$b "-t ntfs3"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
mount /dev/$b /mnt/$b >/dev/null 2> /dev/null
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
UUID=''
|
||||
eval $(block info /dev/$b | grep -o -e "UUID=\S*")
|
||||
if [ ! "$UUID" ]; then
|
||||
log "获取/dev/$b设备UUID信息失败!"
|
||||
expquit 1
|
||||
else
|
||||
log "获取/dev/$b设备UUID信息成功!"
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
case "$target_function" in
|
||||
"/overlay")
|
||||
if [ "$keep_config" = "1" ]; then
|
||||
tar -C /overlay -cvf - . | tar -C /mnt/$b/ -xf - || tar -C /rom/overlay -cvf - . | tar -C /mnt/$b/ -xf -
|
||||
umount /dev/$b >/dev/null 2> /dev/null
|
||||
[ $? -ne 0 ] && umount /mnt/$b >/dev/null 2> /dev/null
|
||||
[ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null
|
||||
block detect > /etc/config/fstab
|
||||
OVERLAY=`uci -q get fstab.@mount[0].target`
|
||||
if [[ "$OVERLAY" = "/overlay" || "$OVERLAY" = "/dev/loop0" ]]; then
|
||||
uci -q set fstab.@mount[0].uuid="${UUID}"
|
||||
uci -q set fstab.@mount[0].target='/overlay'
|
||||
uci -q set fstab.@mount[0].enabled='0'
|
||||
fi
|
||||
msum=$(grep -c "'mount'" /etc/config/fstab)
|
||||
for i in $(seq 0 $((msum-1)))
|
||||
do
|
||||
zuuid=`uci -q get fstab.@mount[$i].uuid`
|
||||
[ $? -ne 0 ] && break
|
||||
if [ "$zuuid" = "$UUID" ]; then
|
||||
uci -q set fstab.@mount[$i].target="/overlay"
|
||||
uci -q set fstab.@mount[$i].enabled='1'
|
||||
fi
|
||||
done
|
||||
uci set fstab.@global[0].delay_root="15"
|
||||
uci commit fstab
|
||||
log "保留数据overlay扩展/dev/$b成功!"
|
||||
eval $(block info /dev/$b | grep -o -e "MOUNT=\S*")
|
||||
echo $MOUNT $a> /etc/partexppath
|
||||
log "扩容成功!可直接【在线升级】扩容升级了!"
|
||||
show_partition_info /dev/$b
|
||||
sleep 3
|
||||
|
||||
expquit 2
|
||||
else
|
||||
umount /dev/$b >/dev/null 2> /dev/null
|
||||
[ $? -ne 0 ] && umount /mnt/$b >/dev/null 2> /dev/null
|
||||
[ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null
|
||||
block detect > /etc/config/fstab
|
||||
OVERLAY=`uci -q get fstab.@mount[0].target`
|
||||
if [[ "$OVERLAY" = "/overlay" || "$OVERLAY" = "/dev/loop0" ]]; then
|
||||
uci -q set fstab.@mount[0].uuid="${UUID}"
|
||||
uci -q set fstab.@mount[0].target='/overlay'
|
||||
uci -q set fstab.@mount[0].enabled='0'
|
||||
fi
|
||||
msum=$(grep -c "'mount'" /etc/config/fstab)
|
||||
for i in $(seq 0 $((msum-1)))
|
||||
do
|
||||
zuuid=`uci -q get fstab.@mount[$i].uuid`
|
||||
[ $? -ne 0 ] && break
|
||||
if [ "$zuuid" = "$UUID" ]; then
|
||||
uci -q set fstab.@mount[$i].target="/overlay"
|
||||
uci -q set fstab.@mount[$i].enabled='1'
|
||||
fi
|
||||
done
|
||||
uci set fstab.@global[0].delay_root="15"
|
||||
uci commit fstab
|
||||
log "不保留数据overlay扩展/dev/$b成功!"
|
||||
eval $(block info /dev/$b | grep -o -e "MOUNT=\S*")
|
||||
echo $MOUNT $a> /etc/partexppath
|
||||
log "扩容成功!可直接【在线升级】扩容升级了!"
|
||||
show_partition_info /dev/$b
|
||||
sleep 3
|
||||
expquit 2
|
||||
fi
|
||||
;;
|
||||
"/opt")
|
||||
umount /dev/$b >/dev/null 2> /dev/null
|
||||
[ $? -ne 0 ] && umount /mnt/$b >/dev/null 2> /dev/null
|
||||
[ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null
|
||||
block detect > /etc/config/fstab
|
||||
mkdir -p $target_function
|
||||
msum=$(grep -c "'mount'" /etc/config/fstab)
|
||||
mount_device /dev/$b "$target_function"
|
||||
for i in $(seq 0 $((msum-1)))
|
||||
do
|
||||
zuuid=`uci -q get fstab.@mount[$i].uuid`
|
||||
[ $? -ne 0 ] && break
|
||||
if [ "$zuuid" = "$UUID" ]; then
|
||||
uci -q set fstab.@mount[$i].target="$target_function"
|
||||
uci -q set fstab.@mount[$i].enabled='1'
|
||||
fi
|
||||
done
|
||||
uci commit fstab
|
||||
if is_disk_mounted "/opt"; then
|
||||
log "/dev/$b分区扩容和挂载到$target_function成功!"
|
||||
eval $(block info /dev/$b | grep -o -e "MOUNT=\S*")
|
||||
echo $MOUNT $a> /etc/partexppath
|
||||
log "扩容成功!可直接【在线升级】扩容升级了!"
|
||||
show_partition_info /dev/$b
|
||||
expquit 2
|
||||
else
|
||||
log "/dev/$b分区扩容和挂载到$target_function失败!"
|
||||
fi
|
||||
;;
|
||||
"/")
|
||||
ROOTBLK="$(readlink -f /sys/dev/block/"$(awk '$9="/dev/root"{print $3}' /proc/self/mountinfo)")"
|
||||
[ -z "$ROOTBLK" ] && { log "错误:无法获取根分区块设备"; expquit 1; }
|
||||
ROOTDISK="/dev/$(basename "${ROOTBLK%/}")"
|
||||
FSTYPE=$(blkid -o value -s TYPE "$ROOTDISK" 2>/dev/null)
|
||||
if [[ "$FSTYPE" != "squashfs" && -n "$FSTYPE" ]]; then
|
||||
if [ "$target_function" = '/' ]; then
|
||||
FREE_SPACE=$(check_free_space $(basename $DISK))
|
||||
log "目标盘 $ROOT_PART $FSTYPE有剩余空间: $FREE_SPACE Gb"
|
||||
if [[ "$FREE_SPACE" -gt 2 ]]; then
|
||||
rootpt_resize
|
||||
expquit 2
|
||||
else
|
||||
log "目标盘 $SYSTEM_DISK $FSTYPE没有足够的剩余空间!"
|
||||
expquit 1
|
||||
fi
|
||||
fi
|
||||
if [ "$target_function" = '/overlay' ]; then
|
||||
FREE_SPACE=$(check_free_space $(basename $DISK))
|
||||
log "目标盘 $ROOT_PART $FSTYPE有剩余空间: $FREE_SPACE Gb"
|
||||
if [[ "$FREE_SPACE" -gt 2 ]]; then
|
||||
rootfs_resize
|
||||
eval $(block info /dev/$b | grep -o -e "MOUNT=\S*")
|
||||
log "/dev/$b分区扩容和挂载到$target_function成功!"
|
||||
echo $MOUNT $a> /etc/partexppath
|
||||
log "扩容成功!可直接【在线升级】扩容升级了!"
|
||||
show_partition_info /dev/$b
|
||||
expquit 2
|
||||
else
|
||||
log "目标盘 $SYSTEM_DISK $FSTYPE没有足够的剩余空间!"
|
||||
expquit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
log "目标硬盘不支持/根分区扩展!请换EXT4固件!"
|
||||
fi
|
||||
sleep 3
|
||||
expquit 2
|
||||
;;
|
||||
*)
|
||||
umount /dev/$b >/dev/null 2> /dev/null
|
||||
[ $? -ne 0 ] && umount /mnt/$b >/dev/null 2> /dev/null
|
||||
[ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null
|
||||
block detect > /etc/config/fstab
|
||||
mkdir -p /mnt/$b
|
||||
msum=$(grep -c "'mount'" /etc/config/fstab)
|
||||
mount_device /dev/$b /mnt/$b
|
||||
for i in $(seq 0 $((msum-1)))
|
||||
do
|
||||
zuuid=`uci -q get fstab.@mount[$i].uuid`
|
||||
[ $? -ne 0 ] && break
|
||||
if [ "$zuuid" = "$UUID" ]; then
|
||||
uci -q set fstab.@mount[$i].target="/mnt/$b"
|
||||
uci -q set fstab.@mount[$i].enabled='1'
|
||||
fi
|
||||
done
|
||||
uci commit fstab
|
||||
if is_disk_mounted /mnt/$b; then
|
||||
log "/dev/$b分区扩容和挂载到/mnt/$b成功!"
|
||||
eval $(block info /dev/$b | grep -o -e "MOUNT=\S*")
|
||||
echo $MOUNT $a> /etc/partexppath
|
||||
log "扩容成功!可直接【在线升级】扩容升级了!"
|
||||
show_partition_info /dev/$b
|
||||
expquit 2
|
||||
else
|
||||
log "/dev/$b分区扩容和挂载到/mnt/$b失败!"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
autopart() {
|
||||
|
||||
[ -f $LOCK ] && expquit 1
|
||||
if [ -f "/etc/config/$CONFIG" ]; then
|
||||
target_function=$(uci -q get partexp.global.target_function)
|
||||
target_disk=$(uci -q get partexp.global.target_disk)
|
||||
keep_config=$(uci -q get partexp.global.keep_config)
|
||||
format_type=$(uci -q get partexp.global.format_type)
|
||||
export target_function="${target_function:-/opt}"
|
||||
export keep_config="${keep_config:-0}"
|
||||
export format_type="${format_type:-0}"
|
||||
export target_disk="${target_disk:-sda}"
|
||||
fi
|
||||
touch $LOCK
|
||||
init_env
|
||||
gen_log
|
||||
|
||||
uci -q set fstab.@global[0].anon_mount='0'
|
||||
uci -q set fstab.@global[0].auto_mount='0'
|
||||
uci commit fstab
|
||||
|
||||
[ -e "/etc/config/dockerd" ] && /etc/init.d/dockerd stop >/dev/null 2> /dev/null
|
||||
|
||||
DISK=${target_disk}
|
||||
NEXTPART=1
|
||||
DISKSALL=$(get_all_disks)
|
||||
DISK_COUNT=$(echo "$DISKSALL" | wc -l)
|
||||
log "系统中检测到的硬盘数量: $DISK_COUNT"
|
||||
log "硬盘信息列表:" $DISKSALL
|
||||
|
||||
SYSTEM_DISK=$(get_system_disk)
|
||||
log "系统盘: "$SYSTEM_DISK
|
||||
|
||||
case "$SYSTEM_DISK" in
|
||||
/dev/$DISK*)
|
||||
fdisksave /dev/$DISK
|
||||
log "操作功能:$target_function ,系统盘:/dev/$DISK"
|
||||
|
||||
PARTITIONSUM=$(get_partition_number $DISK)
|
||||
log "目标盘 $DISK 一共有分区数: $PARTITIONSUM个"
|
||||
|
||||
if [[ "$PARTITIONSUM" -gt 2 ]]; then
|
||||
FREE_SPACE=$(check_free_space $(basename $DISK))
|
||||
log "目标盘 $DISK 有剩余空间: $FREE_SPACE Gb"
|
||||
if [[ "$FREE_SPACE" -gt 2 ]]; then
|
||||
NEXTPART=$(get_next_partition_number $DISK)
|
||||
else
|
||||
NEXTPART=$(get_last_partition_number $DISK)
|
||||
fi
|
||||
else
|
||||
FREE_SPACE=$(check_free_space $(basename $DISK))
|
||||
log "目标盘 $DISK 有剩余空间: $FREE_SPACE Gb"
|
||||
if [[ "$FREE_SPACE" -gt 2 ]]; then
|
||||
NEXTPART=$(get_next_partition_number $DISK)
|
||||
else
|
||||
log "目标盘 $SYSTEM_DISK 没有足够的剩余空间!"
|
||||
expquit 1
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
log "操作功能:$target_function ,非系统盘:/dev/$DISK"
|
||||
PARTITIONSUM=$(get_partition_number $DISK)
|
||||
log "目标盘 $DISK 一共有分区数: $PARTITIONSUM个"
|
||||
|
||||
if [[ "$PARTITIONSUM" -gt 1 ]]; then
|
||||
FREE_SPACE=$(check_free_space $(basename $DISK))
|
||||
log "目标盘 $DISK 有剩余空间: $FREE_SPACE Gb"
|
||||
[[ $FREE_SPACE -gt 2 ]] && NEXTPART=$(get_next_partition_number $DISK) || NEXTPART=$(get_last_partition_number $DISK)
|
||||
else
|
||||
NEXTPART=1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
log "定位到操作目标设备分区:/dev/$DISK$NEXTPART"
|
||||
|
||||
case "$DISK" in
|
||||
vd*|sd*) fdiskB $DISK $NEXTPART;;
|
||||
nvme*|mmc*) fdiskB $DISK p$NEXTPART;;
|
||||
# mtdblock*|ubiblock*) fdiskB $DISK $NEXTPART;;
|
||||
*)
|
||||
log "目标设备/dev/$DISK暂不支持!请联系作者sirpdboy!"
|
||||
;;
|
||||
esac
|
||||
expquit 1
|
||||
}
|
||||
|
||||
|
||||
stop() {
|
||||
rm -f $LOCK 2>/dev/null
|
||||
}
|
||||
|
||||
expquit() {
|
||||
rm -f $LOCK
|
||||
uci -q set fstab.@global[0].anon_mount='1'
|
||||
uci -q set fstab.@global[0].auto_mount='1'
|
||||
uci commit fstab
|
||||
[ -e "/etc/config/dockerd" ] && /etc/init.d/dockerd restart >/dev/null 2> /dev/null
|
||||
[ "$1" = "2" ] && log "如果没生效,请重启设备"
|
||||
sleep 1
|
||||
log "== 操作完成 =="
|
||||
[ "$1" = "3" ] && log "重启中...\n" && reboot
|
||||
exit $1
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
autopart)
|
||||
"$1"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {autopart}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -1,228 +0,0 @@
|
||||
#!/bin/sh
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
# 分区扩展服务
|
||||
case "$1" in
|
||||
list)
|
||||
echo '{
|
||||
"autopart": {
|
||||
"description": "Execute automatic partition expansion"
|
||||
},
|
||||
"get_log": {
|
||||
"description": "Get operation log",
|
||||
"arguments": {
|
||||
"position": "string"
|
||||
}
|
||||
},
|
||||
"get_devices": {
|
||||
"description": "Get available disk devices"
|
||||
},
|
||||
"get_status": {
|
||||
"description": "Get operation status"
|
||||
},
|
||||
"save_config": {
|
||||
"description": "Save configuration",
|
||||
"arguments": {
|
||||
"target_function": "string",
|
||||
"target_disk": "string",
|
||||
"keep_config": "string",
|
||||
"format_type": "string"
|
||||
}
|
||||
}
|
||||
}'
|
||||
;;
|
||||
call)
|
||||
case "$2" in
|
||||
autopart)
|
||||
if [ -f "/var/run/partexp.lock" ]; then
|
||||
echo '{"error": "Another operation is in progress"}'
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 检查配置文件是否存在
|
||||
if [ ! -f "/etc/config/partexp" ]; then
|
||||
echo '{"error": "Configuration file not found. Please save settings first."}'
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 创建锁文件
|
||||
touch /var/run/partexp.lock
|
||||
|
||||
# 执行分区操作(后台异步执行)
|
||||
{
|
||||
# 清空日志文件
|
||||
echo "" > /tmp/partexp.log
|
||||
|
||||
# 调用原 partexp 脚本
|
||||
/usr/bin/partexp autopart > /tmp/partexp.log 2>&1
|
||||
|
||||
# 清理锁文件
|
||||
rm -f /var/run/partexp.lock
|
||||
} &
|
||||
|
||||
echo '{"success": true, "pid": "'$!'", "message": "Partition expansion started"}'
|
||||
;;
|
||||
|
||||
get_log)
|
||||
# 获取操作日志
|
||||
read input
|
||||
json_load "$input"
|
||||
json_get_vars position
|
||||
|
||||
if [ ! -f "/tmp/partexp.log" ]; then
|
||||
echo '{"log": "", "complete": true}'
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -z "$position" ] || [ "$position" = "0" ]; then
|
||||
# 从头读取
|
||||
log_content=$(cat /tmp/partexp.log 2>/dev/null | tail -c 2048000)
|
||||
new_position=$(stat -c%s /tmp/partexp.log 2>/dev/null || echo "0")
|
||||
|
||||
json_init
|
||||
json_add_string "log" "$log_content"
|
||||
json_add_boolean "complete" false
|
||||
json_add_string "position" "$new_position"
|
||||
json_dump
|
||||
else
|
||||
# 从指定位置读取
|
||||
position=${position:-0}
|
||||
file_size=$(stat -c%s /tmp/partexp.log 2>/dev/null || echo 0)
|
||||
|
||||
if [ "$position" -lt "$file_size" ]; then
|
||||
log_content=$(tail -c +$((position + 1)) /tmp/partexp.log | head -c 2048000)
|
||||
new_position=$((position + ${#log_content}))
|
||||
|
||||
json_init
|
||||
json_add_string "log" "$log_content"
|
||||
json_add_boolean "complete" false
|
||||
json_add_string "position" "$new_position"
|
||||
json_dump
|
||||
else
|
||||
json_init
|
||||
json_add_string "log" ""
|
||||
json_add_boolean "complete" true
|
||||
json_add_string "position" "$position"
|
||||
json_dump
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
get_devices)
|
||||
# 获取可用设备列表 - 仅磁盘
|
||||
json_init
|
||||
json_add_array "devices"
|
||||
|
||||
# 所有可能的磁盘设备模式
|
||||
disk_patterns="
|
||||
^sd[a-z]$
|
||||
^mmcblk[0-9]+$
|
||||
^nvme[0-9]+n[0-9]+$
|
||||
^vd[a-z]$
|
||||
^hd[a-z]$
|
||||
^xvd[a-z]$
|
||||
^ubd[a-z]+$
|
||||
^dasd[a-z]+$
|
||||
^cciss[0-9]+$
|
||||
^ida[0-9]+$
|
||||
^rd[0-9]+$
|
||||
^mtdblock[0-9]+$
|
||||
^nbd[0-9]+$
|
||||
^zram[0-9]+$
|
||||
"
|
||||
|
||||
for dev in /sys/class/block/*; do
|
||||
dev_name=$(basename "$dev")
|
||||
|
||||
# 跳过分区、loop、dm 设备
|
||||
if [ -f "$dev/partition" ] || [ -d "$dev/loop" ] || [ -d "$dev/dm" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# 检查是否为磁盘设备
|
||||
is_disk=0
|
||||
for pattern in $disk_patterns; do
|
||||
if echo "$dev_name" | grep -qE "$pattern"; then
|
||||
is_disk=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $is_disk -eq 1 ]; then
|
||||
size="0"
|
||||
if [ -f "$dev/size" ]; then
|
||||
size_sectors=$(cat "$dev/size")
|
||||
size=$((size_sectors / 2048))
|
||||
fi
|
||||
|
||||
json_add_object
|
||||
json_add_string "name" "$dev_name"
|
||||
json_add_string "dev" "/dev/$dev_name"
|
||||
json_add_int "size" "$size"
|
||||
json_close_object
|
||||
fi
|
||||
done
|
||||
|
||||
json_close_array
|
||||
json_dump
|
||||
;;
|
||||
|
||||
|
||||
get_status)
|
||||
# 获取操作状态
|
||||
if [ -f "/var/run/partexp.lock" ]; then
|
||||
echo '{"running": true}'
|
||||
else
|
||||
echo '{"running": false}'
|
||||
fi
|
||||
;;
|
||||
|
||||
|
||||
save_config)
|
||||
# 保存配置
|
||||
read input
|
||||
json_load "$input"
|
||||
json_get_vars target_function target_disk keep_config format_type
|
||||
|
||||
# 验证参数
|
||||
if [ -z "$target_function" ]; then
|
||||
echo '{"error": "Missing target_function parameter"}'
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 设置默认值
|
||||
target_disk="${target_disk:-}"
|
||||
keep_config="${keep_config:-0}"
|
||||
format_type="${format_type:-0}"
|
||||
|
||||
# 构建配置内容
|
||||
CONFIG_FILE="/etc/config/partexp"
|
||||
mkdir -p "$(dirname "$CONFIG_FILE")"
|
||||
|
||||
cat > "$CONFIG_FILE" << EOF
|
||||
# Auto-generated by partexp
|
||||
|
||||
config global global
|
||||
option target_function '$target_function'
|
||||
option target_disk '$target_disk'
|
||||
option keep_config '$keep_config'
|
||||
option format_type '$format_type'
|
||||
EOF
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo '{"success": true, "message": "Configuration saved"}'
|
||||
else
|
||||
echo '{"error": "Failed to save configuration"}'
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
echo '{"error": "Method not found"}'
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
echo '{"error": "Invalid action"}'
|
||||
;;
|
||||
esac
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"admin/system/partexp": {
|
||||
"title": "Partition Expansion",
|
||||
"order": 54,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "partexp"
|
||||
},
|
||||
"acl": ["luci-app-partexp"],
|
||||
"depends": {
|
||||
"acl": ["luci-app-partexp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"luci-app-partexp": {
|
||||
"description": "Grant access for luci-app-partexp",
|
||||
"read": {
|
||||
"ubus": {
|
||||
"file": ["exec", "list", "stat", "read"],
|
||||
"uci": ["partexp"],
|
||||
"partexp": ["get_devices", "get_log", "get_status"]
|
||||
}
|
||||
},
|
||||
"write": {
|
||||
"ubus": {
|
||||
"partexp": ["autopart", "save_config"],
|
||||
"file": ["write"]
|
||||
},
|
||||
"file": {
|
||||
"/etc/config/partexp": ["write"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user