parent
efd1b11b3e
commit
b6e611d63c
@ -1,3 +1,4 @@
|
|||||||
out/
|
out/
|
||||||
*.rpm
|
*.rpm
|
||||||
*.deb
|
*.deb
|
||||||
|
.vagrant*/
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
#!/sbin/openrc-run
|
||||||
|
|
||||||
|
name="OpenNebula contextualization"
|
||||||
|
|
||||||
|
depend() {
|
||||||
|
need one-context-local net
|
||||||
|
before sshd
|
||||||
|
use logger
|
||||||
|
keyword -stop -shutdown
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
ebegin "Starting one-context"
|
||||||
|
/usr/sbin/one-contextd network
|
||||||
|
eend $?
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
#!/sbin/openrc-run
|
||||||
|
|
||||||
|
name="OpenNebula pre-networking contextualization"
|
||||||
|
|
||||||
|
depend() {
|
||||||
|
need localmount udev udev-trigger udev-settle
|
||||||
|
before net iptables keepalived
|
||||||
|
use logger
|
||||||
|
keyword -stop -shutdown
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
ebegin "Starting one-context-local"
|
||||||
|
/usr/sbin/one-contextd local
|
||||||
|
eend $?
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
#!/sbin/openrc-run
|
||||||
|
|
||||||
|
name="OpenNebula reconfiguration"
|
||||||
|
|
||||||
|
depend() {
|
||||||
|
need one-context one-context-local
|
||||||
|
keyword -stop -shutdown
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
ebegin "Starting one-context-reconfigure"
|
||||||
|
export TIMEOUT=0
|
||||||
|
/usr/sbin/one-context-reconfigure
|
||||||
|
eend $?
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
#!/sbin/openrc-run
|
||||||
|
|
||||||
|
name="OpenNebula delayed reconfiguration"
|
||||||
|
|
||||||
|
depend() {
|
||||||
|
need one-context one-context-local
|
||||||
|
keyword -stop -shutdown
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
ebegin "Starting one-context-reconfigure-delayed"
|
||||||
|
/usr/sbin/one-context-reconfigure
|
||||||
|
eend $?
|
||||||
|
}
|
@ -0,0 +1,257 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------- #
|
||||||
|
# Copyright 2010-2014, C12G Labs S.L. #
|
||||||
|
# #
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
||||||
|
# not use this file except in compliance with the License. You may obtain #
|
||||||
|
# a copy of the License at #
|
||||||
|
# #
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 #
|
||||||
|
# #
|
||||||
|
# Unless required by applicable law or agreed to in writing, software #
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, #
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
||||||
|
# See the License for the specific language governing permissions and #
|
||||||
|
# limitations under the License. #
|
||||||
|
#--------------------------------------------------------------------------- #
|
||||||
|
|
||||||
|
ACTION=$1
|
||||||
|
|
||||||
|
if [ -z "$ACTION" ]; then
|
||||||
|
ACTION="none"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Gets IP address from a given MAC
|
||||||
|
mac2ip() {
|
||||||
|
mac=$1
|
||||||
|
|
||||||
|
let ip_a=0x`echo $mac | cut -d: -f 3`
|
||||||
|
let ip_b=0x`echo $mac | cut -d: -f 4`
|
||||||
|
let ip_c=0x`echo $mac | cut -d: -f 5`
|
||||||
|
let ip_d=0x`echo $mac | cut -d: -f 6`
|
||||||
|
|
||||||
|
ip="$ip_a.$ip_b.$ip_c.$ip_d"
|
||||||
|
|
||||||
|
echo $ip
|
||||||
|
}
|
||||||
|
|
||||||
|
# Gets the network part of an IP
|
||||||
|
get_network() {
|
||||||
|
network=$(get_iface_var "NETWORK")
|
||||||
|
|
||||||
|
if [ -z "$network" ]; then
|
||||||
|
network="$(echo $IP | cut -d'.' -f1,2,3).0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $network
|
||||||
|
}
|
||||||
|
|
||||||
|
# Gets the network mask
|
||||||
|
get_mask() {
|
||||||
|
mask=$(get_iface_var "MASK")
|
||||||
|
|
||||||
|
if [ -z "$mask" ]; then
|
||||||
|
mask="255.255.255.0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $mask
|
||||||
|
}
|
||||||
|
|
||||||
|
# Gets device MTU
|
||||||
|
get_mtu() {
|
||||||
|
mtu=$(get_iface_var "MTU")
|
||||||
|
|
||||||
|
echo $mtu
|
||||||
|
}
|
||||||
|
|
||||||
|
is_gateway() {
|
||||||
|
if [ -z "$GATEWAY_IFACE_NUM" ]; then
|
||||||
|
true
|
||||||
|
else
|
||||||
|
[ "$IFACE_NUM" = "$GATEWAY_IFACE_NUM" ]
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Gets the network gateway
|
||||||
|
get_gateway() {
|
||||||
|
if is_gateway; then
|
||||||
|
get_iface_var "GATEWAY"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Gets the network gateway6
|
||||||
|
get_gateway6() {
|
||||||
|
if is_gateway; then
|
||||||
|
get_iface_var "GATEWAY6"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_ip() {
|
||||||
|
ip=$(get_iface_var "IP")
|
||||||
|
|
||||||
|
if [ -z "$ip" ]; then
|
||||||
|
ip=$(mac2ip $MAC)
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $ip
|
||||||
|
}
|
||||||
|
|
||||||
|
get_iface_var() {
|
||||||
|
var_name="${UPCASE_DEV}_$1"
|
||||||
|
var=$(eval "echo \"\${$var_name}\"")
|
||||||
|
|
||||||
|
echo $var
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_iface_conf() {
|
||||||
|
cat <<EOT
|
||||||
|
iface $DEV inet static
|
||||||
|
address $IP
|
||||||
|
network $NETWORK
|
||||||
|
netmask $MASK
|
||||||
|
EOT
|
||||||
|
|
||||||
|
if [ -n "$MTU" ]; then
|
||||||
|
echo " mtu $MTU"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$GATEWAY" ]; then
|
||||||
|
echo " gateway $GATEWAY"
|
||||||
|
|
||||||
|
if [ -n "$METRIC" ]; then
|
||||||
|
echo " metric $METRIC"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_iface6_conf() {
|
||||||
|
cat <<EOT
|
||||||
|
iface $DEV inet6 static
|
||||||
|
address $IPV6
|
||||||
|
netmask 64
|
||||||
|
EOT
|
||||||
|
|
||||||
|
if [ -n "$MTU" ]; then
|
||||||
|
echo " mtu $MTU"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$GATEWAY6" ]; then
|
||||||
|
echo " gateway $GATEWAY6"
|
||||||
|
|
||||||
|
if [ -n "$METRIC" ]; then
|
||||||
|
echo " metric $METRIC"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
get_interface_mac()
|
||||||
|
{
|
||||||
|
ip link show | awk '/^[0-9]+: [A-Za-z0-9]+:/ { device=$2; gsub(/:/, "",device)} /link\/ether/ { print device " " $2 }'
|
||||||
|
}
|
||||||
|
|
||||||
|
get_context_interfaces()
|
||||||
|
{
|
||||||
|
env | grep -E "^ETH[0-9]+_MAC=" | sed 's/_.*$//' | sort
|
||||||
|
}
|
||||||
|
|
||||||
|
get_dev()
|
||||||
|
{
|
||||||
|
list="$1"
|
||||||
|
mac="$2"
|
||||||
|
|
||||||
|
echo "$list" | grep "$mac" | cut -d' ' -f1 | tail -n1
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_network_configuration()
|
||||||
|
{
|
||||||
|
cat <<EOT
|
||||||
|
auto lo
|
||||||
|
iface lo inet loopback
|
||||||
|
|
||||||
|
EOT
|
||||||
|
|
||||||
|
INTERFACE_MAC=$(get_interface_mac)
|
||||||
|
CONTEXT_INTERFACES=$(get_context_interfaces)
|
||||||
|
GATEWAY_IFACE_NUM=$(echo "$GATEWAY_IFACE" | sed 's/^ETH//')
|
||||||
|
|
||||||
|
for interface in $CONTEXT_INTERFACES; do
|
||||||
|
UPCASE_DEV=$interface
|
||||||
|
MAC=$(get_iface_var "MAC")
|
||||||
|
DEV=$(get_dev "$INTERFACE_MAC" "$MAC")
|
||||||
|
IFACE_NUM=$(echo "$UPCASE_DEV" | sed 's/^ETH//')
|
||||||
|
|
||||||
|
IP=$(get_ip)
|
||||||
|
NETWORK=$(get_network)
|
||||||
|
MASK=$(get_mask)
|
||||||
|
MTU=$(get_mtu)
|
||||||
|
GATEWAY=$(get_gateway)
|
||||||
|
METRIC=$(get_iface_var "METRIC")
|
||||||
|
|
||||||
|
IPV6=$(get_iface_var "IPV6")
|
||||||
|
[[ -z $IPV6 ]] && IPV6=$(get_iface_var "IP6")
|
||||||
|
GATEWAY6=$(get_gateway6)
|
||||||
|
CONTEXT_FORCE_IPV4=$(get_iface_var "CONTEXT_FORCE_IPV4")
|
||||||
|
|
||||||
|
[ -z "${IP}${IPV6}" ] && continue
|
||||||
|
[ -z "${DEV}" ] && continue
|
||||||
|
|
||||||
|
echo "auto $DEV"
|
||||||
|
|
||||||
|
#[[ -z $IPV6 || -n $CONTEXT_FORCE_IPV4 ]] && gen_iface_conf
|
||||||
|
#[[ -n $IPV6 ]] && gen_iface6_conf
|
||||||
|
|
||||||
|
gen_iface_conf
|
||||||
|
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
configure_network()
|
||||||
|
{
|
||||||
|
gen_network_configuration > /etc/network/interfaces
|
||||||
|
#echo "source /etc/network/interfaces.d/*.cfg" >> /etc/network/interfaces
|
||||||
|
}
|
||||||
|
|
||||||
|
deactivate_network()
|
||||||
|
{
|
||||||
|
. /etc/os-release
|
||||||
|
if [ $ID = "ubuntu" ]; then
|
||||||
|
IFACES=`/sbin/ifquery --list -a`
|
||||||
|
|
||||||
|
for i in $IFACES; do
|
||||||
|
if [ $i != 'lo' ]; then
|
||||||
|
/sbin/ifdown $i
|
||||||
|
/sbin/ip addr flush dev $i
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
service networking stop
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
activate_network()
|
||||||
|
{
|
||||||
|
. /etc/os-release
|
||||||
|
if [ $ID = "ubuntu" ]; then
|
||||||
|
IFACES=`/sbin/ifquery --list -a`
|
||||||
|
|
||||||
|
for i in $IFACES; do
|
||||||
|
/sbin/ifup $i
|
||||||
|
done
|
||||||
|
else
|
||||||
|
service networking stop
|
||||||
|
sleep 1
|
||||||
|
service networking start
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
}
|
||||||
|
|
||||||
|
[ $ACTION == "reconfigure" ] && deactivate_network
|
||||||
|
configure_network
|
||||||
|
[ $ACTION == "reconfigure" ] && activate_network
|
||||||
|
|
@ -0,0 +1,89 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------- #
|
||||||
|
# Copyright 2010-2016, OpenNebula Systems #
|
||||||
|
# #
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
||||||
|
# not use this file except in compliance with the License. You may obtain #
|
||||||
|
# a copy of the License at #
|
||||||
|
# #
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 #
|
||||||
|
# #
|
||||||
|
# Unless required by applicable law or agreed to in writing, software #
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, #
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
||||||
|
# See the License for the specific language governing permissions and #
|
||||||
|
# limitations under the License. #
|
||||||
|
#--------------------------------------------------------------------------- #
|
||||||
|
|
||||||
|
get_management_interfaces() {
|
||||||
|
env | grep -E "^ETH[0-9]+_VROUTER_MANAGEMENT=YES" | sed 's/_.*$//' | tr 'ETH' 'eth' | sort
|
||||||
|
}
|
||||||
|
|
||||||
|
get_context_interfaces() {
|
||||||
|
interfaces="$(env | grep -E "^ETH[0-9]+_MAC=" | sed 's/_.*$//' | tr 'ETH' 'eth' | sort)"
|
||||||
|
management="$(get_management_interfaces)"
|
||||||
|
if [ -n "$management" ]; then
|
||||||
|
interfaces="$(echo "$interfaces" | grep -v "$management")"
|
||||||
|
fi
|
||||||
|
echo "$interfaces"
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_header() {
|
||||||
|
cat <<EOT
|
||||||
|
*filter
|
||||||
|
:INPUT ACCEPT [0:0]
|
||||||
|
:FORWARD DROP [0:0]
|
||||||
|
:OUTPUT ACCEPT [0:0]
|
||||||
|
EOT
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_footer() {
|
||||||
|
cat <<EOT
|
||||||
|
COMMIT
|
||||||
|
EOT
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_forwarding() {
|
||||||
|
for interface in $(get_context_interfaces); do
|
||||||
|
for destination in $(get_context_interfaces | grep -v $interface); do
|
||||||
|
cat << EOT
|
||||||
|
-A FORWARD -i $interface -o $destination -j ACCEPT
|
||||||
|
EOT
|
||||||
|
done
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_close_web_interface() {
|
||||||
|
for interface in $(get_context_interfaces); do
|
||||||
|
cat <<EOT
|
||||||
|
-A INPUT -i $interface -p tcp --dport 443 -j DROP
|
||||||
|
-A OUTPUT -o $interface -p tcp --sport 443 -j DROP
|
||||||
|
EOT
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
reload_service() {
|
||||||
|
service iptables reload
|
||||||
|
}
|
||||||
|
|
||||||
|
# skip the script if instance is not Virtual Router
|
||||||
|
if [ -z "${VROUTER_ID}${VROUTER_KEEPALIVED_ID}" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
(
|
||||||
|
|
||||||
|
gen_header
|
||||||
|
gen_forwarding
|
||||||
|
gen_close_web_interface
|
||||||
|
gen_footer
|
||||||
|
|
||||||
|
) > /etc/iptables/rules-save
|
||||||
|
|
||||||
|
if [ "$1" == "reconfigure" ]; then
|
||||||
|
reload_service
|
||||||
|
else
|
||||||
|
rc-update add iptables boot
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ -z "${VROUTER_ID}${VROUTER_KEEPALIVED_ID}" ]; then
|
||||||
|
if [ -f /etc/sysctl.d/01-one.conf ]; then
|
||||||
|
unlink /etc/sysctl.d/01-one.conf
|
||||||
|
sysctl -w net.ipv4.ip_forward=0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo 'net.ipv4.ip_forward = 1' >/etc/sysctl.d/01-one.conf
|
||||||
|
sysctl -w net.ipv4.ip_forward=1
|
||||||
|
fi
|
@ -0,0 +1,144 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------- #
|
||||||
|
# Copyright 2010-2016, OpenNebula Systems #
|
||||||
|
# #
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
||||||
|
# not use this file except in compliance with the License. You may obtain #
|
||||||
|
# a copy of the License at #
|
||||||
|
# #
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 #
|
||||||
|
# #
|
||||||
|
# Unless required by applicable law or agreed to in writing, software #
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, #
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
||||||
|
# See the License for the specific language governing permissions and #
|
||||||
|
# limitations under the License. #
|
||||||
|
#--------------------------------------------------------------------------- #
|
||||||
|
|
||||||
|
get_context_interfaces() {
|
||||||
|
env | grep -E "^ETH[0-9]+_VROUTER_IP=" | sed 's/_.*$//' | sort
|
||||||
|
}
|
||||||
|
|
||||||
|
downcase() {
|
||||||
|
tr 'ETH' 'eth'
|
||||||
|
}
|
||||||
|
|
||||||
|
get_ip() {
|
||||||
|
ip=$(get_iface_var "$1" "IP")
|
||||||
|
|
||||||
|
echo $ip
|
||||||
|
}
|
||||||
|
|
||||||
|
get_vrouter_id() {
|
||||||
|
vrouter_id="$VROUTER_KEEPALIVED_ID"
|
||||||
|
|
||||||
|
if [ -z "$vrouter_id" ]; then
|
||||||
|
vrouter_id="0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# vrouter_id is a byte
|
||||||
|
vrouter_id=$(( $vrouter_id & 255 ))
|
||||||
|
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
vrouter_id="0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $vrouter_id
|
||||||
|
}
|
||||||
|
|
||||||
|
get_vrouter_password() {
|
||||||
|
password="$VROUTER_KEEPALIVED_PASSWORD"
|
||||||
|
|
||||||
|
echo $password
|
||||||
|
}
|
||||||
|
|
||||||
|
get_iface_var() {
|
||||||
|
var_name="$1_$2"
|
||||||
|
var=$(eval "echo \"\${$var_name}\"")
|
||||||
|
|
||||||
|
echo $var
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_group() {
|
||||||
|
cat <<EOT
|
||||||
|
vrrp_sync_group router {
|
||||||
|
group {
|
||||||
|
EOT
|
||||||
|
|
||||||
|
for interface in $(get_context_interfaces); do
|
||||||
|
vrouter_ip=$(get_iface_var $interface VROUTER_IP)
|
||||||
|
|
||||||
|
if [ -n $vrouter_ip ]; then
|
||||||
|
echo " $interface"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
cat <<EOT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EOT
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_auth() {
|
||||||
|
password=$(get_vrouter_password)
|
||||||
|
|
||||||
|
if [ -n "$password" ]; then
|
||||||
|
cat <<EOT
|
||||||
|
authentication {
|
||||||
|
auth_type PASS
|
||||||
|
auth_pass $password
|
||||||
|
}
|
||||||
|
EOT
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_instances() {
|
||||||
|
for interface in $(get_context_interfaces); do
|
||||||
|
vrouter_ip=$(get_iface_var $interface VROUTER_IP)
|
||||||
|
interface_downcase=$(echo $interface | downcase)
|
||||||
|
|
||||||
|
if [ -n $vrouter_ip ]; then
|
||||||
|
cat <<EOT
|
||||||
|
vrrp_instance $interface {
|
||||||
|
state master
|
||||||
|
interface $interface_downcase
|
||||||
|
virtual_router_id $(get_vrouter_id)
|
||||||
|
priority 101
|
||||||
|
advert_int 1
|
||||||
|
virtual_ipaddress {
|
||||||
|
$vrouter_ip
|
||||||
|
}
|
||||||
|
$(gen_auth)
|
||||||
|
nopreempt
|
||||||
|
}
|
||||||
|
|
||||||
|
EOT
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
reload_service() {
|
||||||
|
service keepalived reload
|
||||||
|
}
|
||||||
|
|
||||||
|
#####
|
||||||
|
|
||||||
|
# skip the script if instance is not Virtual Router
|
||||||
|
if [ -z "${VROUTER_ID}${VROUTER_KEEPALIVED_ID}" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
(
|
||||||
|
|
||||||
|
gen_group
|
||||||
|
gen_instances
|
||||||
|
|
||||||
|
) > /etc/keepalived/keepalived.conf
|
||||||
|
|
||||||
|
if [ "$1" == "reconfigure" ]; then
|
||||||
|
reload_service
|
||||||
|
else
|
||||||
|
rc-update add keepalived boot
|
||||||
|
fi
|
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
poweroff
|
||||||
|
|
@ -0,0 +1,8 @@
|
|||||||
|
# On NIC hogplug the delayed reconfiguration is triggered.
|
||||||
|
SUBSYSTEM=="net", ACTION=="add", \
|
||||||
|
RUN+="/sbin/service one-context-reconfigure-delayed restart"
|
||||||
|
|
||||||
|
# On CONTEXT CD-ROM change the immediate reconfiguration is triggered.
|
||||||
|
SUBSYSTEM=="block", ACTION=="change", \
|
||||||
|
ENV{ID_FS_TYPE}=="iso9660" ENV{ID_FS_LABEL_ENC}=="CONTEXT", \
|
||||||
|
RUN+="/sbin/service one-context-reconfigure restart"
|
@ -0,0 +1,780 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Copyright (C) 2011 Canonical Ltd.
|
||||||
|
# Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
|
||||||
|
#
|
||||||
|
# Authors: Scott Moser <smoser@canonical.com>
|
||||||
|
# Juerg Haefliger <juerg.haefliger@hp.com>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, version 3 of the License.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# the fudge factor. if within this many bytes dont bother
|
||||||
|
FUDGE=${GROWPART_FUDGE:-$((1024*1024))}
|
||||||
|
TEMP_D=""
|
||||||
|
RESTORE_FUNC=""
|
||||||
|
RESTORE_HUMAN=""
|
||||||
|
VERBOSITY=0
|
||||||
|
DISK=""
|
||||||
|
PART=""
|
||||||
|
PT_UPDATE=false
|
||||||
|
DRY_RUN=0
|
||||||
|
|
||||||
|
SFDISK_VERSION=""
|
||||||
|
SFDISK_2_26="22600"
|
||||||
|
SFDISK_V_WORKING_GPT="22603"
|
||||||
|
MBR_BACKUP=""
|
||||||
|
GPT_BACKUP=""
|
||||||
|
_capture=""
|
||||||
|
|
||||||
|
error() {
|
||||||
|
echo "$@" 1>&2
|
||||||
|
}
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
[ $# -eq 0 ] || echo "FAILED:" "$@"
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
nochange() {
|
||||||
|
echo "NOCHANGE:" "$@"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
changed() {
|
||||||
|
echo "CHANGED:" "$@"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
change() {
|
||||||
|
echo "CHANGE:" "$@"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
if [ -n "${RESTORE_FUNC}" ]; then
|
||||||
|
error "***** WARNING: Resize failed, attempting to revert ******"
|
||||||
|
if ${RESTORE_FUNC} ; then
|
||||||
|
error "***** Appears to have gone OK ****"
|
||||||
|
else
|
||||||
|
error "***** FAILED! ******"
|
||||||
|
if [ -n "${RESTORE_HUMAN}" -a -f "${RESTORE_HUMAN}" ]; then
|
||||||
|
error "**** original table looked like: ****"
|
||||||
|
cat "${RESTORE_HUMAN}" 1>&2
|
||||||
|
else
|
||||||
|
error "We seem to have not saved the partition table!"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
[ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
|
||||||
|
}
|
||||||
|
|
||||||
|
debug() {
|
||||||
|
local level=${1}
|
||||||
|
shift
|
||||||
|
[ "${level}" -gt "${VERBOSITY}" ] && return
|
||||||
|
if [ "${DEBUG_LOG}" ]; then
|
||||||
|
echo "$@" >>"${DEBUG_LOG}"
|
||||||
|
else
|
||||||
|
error "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
debugcat() {
|
||||||
|
local level="$1"
|
||||||
|
shift;
|
||||||
|
[ "${level}" -gt "$VERBOSITY" ] && return
|
||||||
|
if [ "${DEBUG_LOG}" ]; then
|
||||||
|
cat "$@" >>"${DEBUG_LOG}"
|
||||||
|
else
|
||||||
|
cat "$@" 1>&2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
mktemp_d() {
|
||||||
|
# just a mktemp -d that doens't need mktemp if its not there.
|
||||||
|
_RET=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX" 2>/dev/null) &&
|
||||||
|
return
|
||||||
|
_RET=$(umask 077 && t="${TMPDIR:-/tmp}/${0##*/}.$$" &&
|
||||||
|
mkdir "${t}" && echo "${t}")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Usage() {
|
||||||
|
cat <<EOF
|
||||||
|
${0##*/} disk partition
|
||||||
|
rewrite partition table so that partition takes up all the space it can
|
||||||
|
options:
|
||||||
|
-h | --help print Usage and exit
|
||||||
|
--fudge F if part could be resized, but change would be
|
||||||
|
less than 'F' bytes, do not resize (default: ${FUDGE})
|
||||||
|
-N | --dry-run only report what would be done, show new 'sfdisk -d'
|
||||||
|
-v | --verbose increase verbosity / debug
|
||||||
|
-u | --update R update the the kernel partition table info after growing
|
||||||
|
this requires kernel support and 'partx --update'
|
||||||
|
R is one of:
|
||||||
|
- 'auto' : [default] update partition if possible
|
||||||
|
- 'force' : try despite sanity checks (fail on failure)
|
||||||
|
- 'off' : do not attempt
|
||||||
|
- 'on' : fail if sanity checks indicate no support
|
||||||
|
|
||||||
|
Example:
|
||||||
|
- ${0##*/} /dev/sda 1
|
||||||
|
Resize partition 1 on /dev/sda
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
bad_Usage() {
|
||||||
|
Usage 1>&2
|
||||||
|
error "$@"
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdisk_restore_legacy() {
|
||||||
|
sfdisk --no-reread "${DISK}" -I "${MBR_BACKUP}"
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdisk_restore() {
|
||||||
|
# files are named: sfdisk-<device>-<offset>.bak
|
||||||
|
local f="" offset="" fails=0
|
||||||
|
for f in "${MBR_BACKUP}"*.bak; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
offset=${f##*-}
|
||||||
|
offset=${offset%.bak}
|
||||||
|
[ "$offset" = "$f" ] && {
|
||||||
|
error "WARN: confused by file $f";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dd "if=$f" "of=${DISK}" seek=$(($offset)) bs=1 conv=notrunc ||
|
||||||
|
{ error "WARN: failed restore from $f"; fails=$(($fails+1)); }
|
||||||
|
done
|
||||||
|
return $fails
|
||||||
|
}
|
||||||
|
|
||||||
|
sfdisk_worked_but_blkrrpart_failed() {
|
||||||
|
local ret="$1" output="$2"
|
||||||
|
# exit code found was just 1, but dont insist on that
|
||||||
|
#[ $ret -eq 1 ] || return 1
|
||||||
|
# Successfully wrote the new partition table
|
||||||
|
grep -qi "Success.* wrote.* new.* partition" "$output" &&
|
||||||
|
grep -qi "BLKRRPART: Device or resource busy" "$output"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
get_sfdisk_version() {
|
||||||
|
# set SFDISK_VERSION to MAJOR*10000+MINOR*100+MICRO
|
||||||
|
local out oifs="$IFS" ver=""
|
||||||
|
[ -n "$SFDISK_VERSION" ] && return 0
|
||||||
|
# expected output: sfdisk from util-linux 2.25.2
|
||||||
|
out=$(sfdisk --version) ||
|
||||||
|
{ error "failed to get sfdisk version"; return 1; }
|
||||||
|
set -- $out
|
||||||
|
ver=$4
|
||||||
|
case "$ver" in
|
||||||
|
[0-9]*.[0-9]*.[0-9]|[0-9].[0-9]*)
|
||||||
|
IFS="."; set -- $ver; IFS="$oifs"
|
||||||
|
SFDISK_VERSION=$(($1*10000+$2*100+${3:-0}))
|
||||||
|
return 0;;
|
||||||
|
*) error "unexpected output in sfdisk --version [$out]"
|
||||||
|
return 1;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
resize_sfdisk() {
|
||||||
|
local humanpt="${TEMP_D}/recovery"
|
||||||
|
local mbr_backup="${TEMP_D}/orig.save"
|
||||||
|
local restore_func=""
|
||||||
|
local format="$1"
|
||||||
|
|
||||||
|
local change_out=${TEMP_D}/change.out
|
||||||
|
local dump_out=${TEMP_D}/dump.out
|
||||||
|
local new_out=${TEMP_D}/new.out
|
||||||
|
local dump_mod=${TEMP_D}/dump.mod
|
||||||
|
local tmp="${TEMP_D}/tmp.out"
|
||||||
|
local err="${TEMP_D}/err.out"
|
||||||
|
local mbr_max_512="4294967296"
|
||||||
|
|
||||||
|
local pt_start pt_size pt_end max_end new_size change_info dpart
|
||||||
|
local sector_num sector_size disk_size tot out
|
||||||
|
|
||||||
|
rqe sfd_list sfdisk --list --unit=S "$DISK" >"$tmp" ||
|
||||||
|
fail "failed: sfdisk --list $DISK"
|
||||||
|
if [ "${SFDISK_VERSION}" -lt ${SFDISK_2_26} ]; then
|
||||||
|
# exected output contains: Units: sectors of 512 bytes, ...
|
||||||
|
out=$(awk '$1 == "Units:" && $5 ~ /bytes/ { print $4 }' "$tmp") ||
|
||||||
|
fail "failed to read sfdisk output"
|
||||||
|
if [ -z "$out" ]; then
|
||||||
|
error "WARN: sector size not found in sfdisk output, assuming 512"
|
||||||
|
sector_size=512
|
||||||
|
else
|
||||||
|
sector_size="$out"
|
||||||
|
fi
|
||||||
|
local _w _cyl _w1 _heads _w2 sectors _w3 t s
|
||||||
|
# show-size is in units of 1024 bytes (same as /proc/partitions)
|
||||||
|
t=$(sfdisk --show-size "${DISK}") ||
|
||||||
|
fail "failed: sfdisk --show-size $DISK"
|
||||||
|
disk_size=$((t*1024))
|
||||||
|
sector_num=$(($disk_size/$sector_size))
|
||||||
|
msg="disk size '$disk_size' not evenly div by sector size '$sector_size'"
|
||||||
|
[ "$((${disk_size}%${sector_size}))" -eq 0 ] ||
|
||||||
|
error "WARN: $msg"
|
||||||
|
restore_func=sfdisk_restore_legacy
|
||||||
|
else
|
||||||
|
# --list first line output:
|
||||||
|
# Disk /dev/vda: 20 GiB, 21474836480 bytes, 41943040 sectors
|
||||||
|
local _x
|
||||||
|
read _x _x _x _x disk_size _x sector_num _x < "$tmp"
|
||||||
|
sector_size=$((disk_size/$sector_num))
|
||||||
|
restore_func=sfdisk_restore
|
||||||
|
fi
|
||||||
|
|
||||||
|
debug 1 "$sector_num sectors of $sector_size. total size=${disk_size} bytes"
|
||||||
|
[ $(($disk_size/512)) -gt $mbr_max_512 ] &&
|
||||||
|
debug 1 "WARN: disk is larger than 2TB. additional space will go unused."
|
||||||
|
|
||||||
|
rqe sfd_dump sfdisk --unit=S --dump "${DISK}" >"${dump_out}" ||
|
||||||
|
fail "failed to dump sfdisk info for ${DISK}"
|
||||||
|
RESTORE_HUMAN="$dump_out"
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "## sfdisk --unit=S --dump ${DISK}"
|
||||||
|
cat "${dump_out}"
|
||||||
|
} >"$humanpt"
|
||||||
|
|
||||||
|
[ $? -eq 0 ] || fail "failed to save sfdisk -d output"
|
||||||
|
RESTORE_HUMAN="$humanpt"
|
||||||
|
|
||||||
|
debugcat 1 "$humanpt"
|
||||||
|
|
||||||
|
sed -e 's/,//g; s/start=/start /; s/size=/size /' "${dump_out}" \
|
||||||
|
>"${dump_mod}" ||
|
||||||
|
fail "sed failed on dump output"
|
||||||
|
|
||||||
|
dpart="${DISK}${PART}" # disk and partition number
|
||||||
|
if [ -b "${DISK}p${PART}" -a "${DISK%[0-9]}" != "${DISK}" ]; then
|
||||||
|
# for block devices that end in a number (/dev/nbd0)
|
||||||
|
# the partition is "<name>p<partition_number>" (/dev/nbd0p1)
|
||||||
|
dpart="${DISK}p${PART}"
|
||||||
|
elif [ "${DISK#/dev/loop[0-9]}" != "${DISK}" ]; then
|
||||||
|
# for /dev/loop devices, sfdisk output will be <name>p<number>
|
||||||
|
# format also, even though there is not a device there.
|
||||||
|
dpart="${DISK}p${PART}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
pt_start=$(awk '$1 == pt { print $4 }' "pt=${dpart}" <"${dump_mod}") &&
|
||||||
|
pt_size=$(awk '$1 == pt { print $6 }' "pt=${dpart}" <"${dump_mod}") &&
|
||||||
|
[ -n "${pt_start}" -a -n "${pt_size}" ] &&
|
||||||
|
pt_end=$((${pt_size}+${pt_start})) ||
|
||||||
|
fail "failed to get start and end for ${dpart} in ${DISK}"
|
||||||
|
|
||||||
|
# find the minimal starting location that is >= pt_end
|
||||||
|
max_end=$(awk '$3 == "start" { if($4 >= pt_end && $4 < min)
|
||||||
|
{ min = $4 } } END { printf("%s\n",min); }' \
|
||||||
|
min=${sector_num} pt_end=${pt_end} "${dump_mod}") &&
|
||||||
|
[ -n "${max_end}" ] ||
|
||||||
|
fail "failed to get max_end for partition ${PART}"
|
||||||
|
|
||||||
|
mbr_max_sectors=$((mbr_max_512*$((sector_size/512))))
|
||||||
|
if [ "$max_end" -gt "$mbr_max_sectors" ]; then
|
||||||
|
max_end=$mbr_max_sectors
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$format" = "gpt" ]; then
|
||||||
|
# sfdisk respects 'last-lba' in input, and complains about
|
||||||
|
# partitions that go past that. without it, it does the right thing.
|
||||||
|
sed -i '/^last-lba:/d' "$dump_out" ||
|
||||||
|
fail "failed to remove last-lba from output"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local gpt_second_size="33"
|
||||||
|
if [ "${max_end}" -gt "$((${sector_num}-${gpt_second_size}))" ]; then
|
||||||
|
# if mbr allow subsequent conversion to gpt without shrinking the
|
||||||
|
# partition. safety net at cost of 33 sectors, seems reasonable.
|
||||||
|
# if gpt, we can't write there anyway.
|
||||||
|
debug 1 "padding ${gpt_second_size} sectors for gpt secondary header"
|
||||||
|
max_end=$((${sector_num}-${gpt_second_size}))
|
||||||
|
fi
|
||||||
|
|
||||||
|
debug 1 "max_end=${max_end} tot=${sector_num} pt_end=${pt_end}" \
|
||||||
|
"pt_start=${pt_start} pt_size=${pt_size}"
|
||||||
|
[ $((${pt_end})) -eq ${max_end} ] &&
|
||||||
|
nochange "partition ${PART} is size ${pt_size}. it cannot be grown"
|
||||||
|
[ $((${pt_end}+(${FUDGE}/$sector_size))) -gt ${max_end} ] &&
|
||||||
|
nochange "partition ${PART} could only be grown by" \
|
||||||
|
"$((${max_end}-${pt_end})) [fudge=$((${FUDGE}/$sector_size))]"
|
||||||
|
|
||||||
|
# now, change the size for this partition in ${dump_out} to be the
|
||||||
|
# new size
|
||||||
|
new_size=$((${max_end}-${pt_start}))
|
||||||
|
sed "\|^\s*${dpart} |s/${pt_size},/${new_size},/" "${dump_out}" \
|
||||||
|
>"${new_out}" ||
|
||||||
|
fail "failed to change size in output"
|
||||||
|
|
||||||
|
change_info="partition=${PART} start=${pt_start} old: size=${pt_size} end=${pt_end} new: size=${new_size},end=${max_end}"
|
||||||
|
if [ ${DRY_RUN} -ne 0 ]; then
|
||||||
|
echo "CHANGE: ${change_info}"
|
||||||
|
{
|
||||||
|
echo "# === old sfdisk -d ==="
|
||||||
|
cat "${dump_out}"
|
||||||
|
echo "# === new sfdisk -d ==="
|
||||||
|
cat "${new_out}"
|
||||||
|
} 1>&2
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
MBR_BACKUP="${mbr_backup}"
|
||||||
|
LANG=C sfdisk --no-reread "${DISK}" --force \
|
||||||
|
-O "${mbr_backup}" <"${new_out}" >"${change_out}" 2>&1
|
||||||
|
ret=$?
|
||||||
|
[ $ret -eq 0 ] || RESTORE_FUNC="${restore_func}"
|
||||||
|
|
||||||
|
if [ $ret -eq 0 ]; then
|
||||||
|
:
|
||||||
|
elif $PT_UPDATE &&
|
||||||
|
sfdisk_worked_but_blkrrpart_failed "$ret" "${change_out}"; then
|
||||||
|
# if the command failed, but it looks like only because
|
||||||
|
# the device was busy and we have pt_update, then go on
|
||||||
|
debug 1 "sfdisk failed, but likely only because of blkrrpart"
|
||||||
|
else
|
||||||
|
error "attempt to resize ${DISK} failed. sfdisk output below:"
|
||||||
|
sed 's,^,| ,' "${change_out}" 1>&2
|
||||||
|
fail "failed to resize"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rq pt_update pt_update "$DISK" "$PART" ||
|
||||||
|
fail "pt_resize failed"
|
||||||
|
|
||||||
|
RESTORE_FUNC=""
|
||||||
|
|
||||||
|
changed "${change_info}"
|
||||||
|
|
||||||
|
# dump_out looks something like:
|
||||||
|
## partition table of /tmp/out.img
|
||||||
|
#unit: sectors
|
||||||
|
#
|
||||||
|
#/tmp/out.img1 : start= 1, size= 48194, Id=83
|
||||||
|
#/tmp/out.img2 : start= 48195, size= 963900, Id=83
|
||||||
|
#/tmp/out.img3 : start= 1012095, size= 305235, Id=82
|
||||||
|
#/tmp/out.img4 : start= 1317330, size= 771120, Id= 5
|
||||||
|
#/tmp/out.img5 : start= 1317331, size= 642599, Id=83
|
||||||
|
#/tmp/out.img6 : start= 1959931, size= 48194, Id=83
|
||||||
|
#/tmp/out.img7 : start= 2008126, size= 80324, Id=83
|
||||||
|
}
|
||||||
|
|
||||||
|
gpt_restore() {
|
||||||
|
sgdisk -l "${GPT_BACKUP}" "${DISK}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resize_sgdisk() {
|
||||||
|
GPT_BACKUP="${TEMP_D}/pt.backup"
|
||||||
|
|
||||||
|
local pt_info="${TEMP_D}/pt.info"
|
||||||
|
local pt_pretend="${TEMP_D}/pt.pretend"
|
||||||
|
local pt_data="${TEMP_D}/pt.data"
|
||||||
|
local out="${TEMP_D}/out"
|
||||||
|
|
||||||
|
local dev="disk=${DISK} partition=${PART}"
|
||||||
|
|
||||||
|
local pt_start pt_end pt_size last pt_max code guid name new_size
|
||||||
|
local old new change_info sector_size
|
||||||
|
|
||||||
|
# Dump the original partition information and details to disk. This is
|
||||||
|
# used in case something goes wrong and human interaction is required
|
||||||
|
# to revert any changes.
|
||||||
|
rqe sgd_info sgdisk "--info=${PART}" --print "${DISK}" >"${pt_info}" ||
|
||||||
|
fail "${dev}: failed to dump original sgdisk info"
|
||||||
|
RESTORE_HUMAN="${pt_info}"
|
||||||
|
|
||||||
|
sector_size=$(awk '$0 ~ /^Logical sector size:.*bytes/ { print $4 }' \
|
||||||
|
"$pt_info") && [ -n "$sector_size" ] || {
|
||||||
|
sector_size=512
|
||||||
|
error "WARN: did not find sector size, assuming 512"
|
||||||
|
}
|
||||||
|
|
||||||
|
debug 1 "$dev: original sgdisk info:"
|
||||||
|
debugcat 1 "${pt_info}"
|
||||||
|
|
||||||
|
# Pretend to move the backup GPT header to the end of the disk and dump
|
||||||
|
# the resulting partition information. We use this info to determine if
|
||||||
|
# we have to resize the partition.
|
||||||
|
rqe sgd_pretend sgdisk --pretend --move-second-header \
|
||||||
|
--print "${DISK}" >"${pt_pretend}" ||
|
||||||
|
fail "${dev}: failed to dump pretend sgdisk info"
|
||||||
|
|
||||||
|
debug 1 "$dev: pretend sgdisk info"
|
||||||
|
debugcat 1 "${pt_pretend}"
|
||||||
|
|
||||||
|
# Extract the partition data from the pretend dump
|
||||||
|
awk 'found { print } ; $1 == "Number" { found = 1 }' \
|
||||||
|
"${pt_pretend}" >"${pt_data}" ||
|
||||||
|
fail "${dev}: failed to parse pretend sgdisk info"
|
||||||
|
|
||||||
|
# Get the start and end sectors of the partition to be grown
|
||||||
|
pt_start=$(awk '$1 == '"${PART}"' { print $2 }' "${pt_data}") &&
|
||||||
|
[ -n "${pt_start}" ] ||
|
||||||
|
fail "${dev}: failed to get start sector"
|
||||||
|
pt_end=$(awk '$1 == '"${PART}"' { print $3 }' "${pt_data}") &&
|
||||||
|
[ -n "${pt_end}" ] ||
|
||||||
|
fail "${dev}: failed to get end sector"
|
||||||
|
pt_size="$((${pt_end} - ${pt_start}))"
|
||||||
|
|
||||||
|
# Get the last usable sector
|
||||||
|
last=$(awk '/last usable sector is/ { print $NF }' \
|
||||||
|
"${pt_pretend}") && [ -n "${last}" ] ||
|
||||||
|
fail "${dev}: failed to get last usable sector"
|
||||||
|
|
||||||
|
# Find the minimal start sector that is >= pt_end
|
||||||
|
pt_max=$(awk '{ if ($2 >= pt_end && $2 < min) { min = $2 } } END \
|
||||||
|
{ print min }' min="${last}" pt_end="${pt_end}" \
|
||||||
|
"${pt_data}") && [ -n "${pt_max}" ] ||
|
||||||
|
fail "${dev}: failed to find max end sector"
|
||||||
|
|
||||||
|
debug 1 "${dev}: pt_start=${pt_start} pt_end=${pt_end}" \
|
||||||
|
"pt_size=${pt_size} pt_max=${pt_max} last=${last}"
|
||||||
|
|
||||||
|
# Check if the partition can be grown
|
||||||
|
[ "${pt_end}" -eq "${pt_max}" ] &&
|
||||||
|
nochange "${dev}: size=${pt_size}, it cannot be grown"
|
||||||
|
[ "$((${pt_end} + ${FUDGE}/${sector_size}))" -gt "${pt_max}" ] &&
|
||||||
|
nochange "${dev}: could only be grown by" \
|
||||||
|
"$((${pt_max} - ${pt_end})) [fudge=$((${FUDGE}/$sector_size))]"
|
||||||
|
|
||||||
|
# The partition can be grown if we made it here. Get some more info
|
||||||
|
# about it so we can do it properly.
|
||||||
|
# FIXME: Do we care about the attribute flags?
|
||||||
|
code=$(awk '/^Partition GUID code:/ { print $4 }' "${pt_info}")
|
||||||
|
guid=$(awk '/^Partition unique GUID:/ { print $4 }' "${pt_info}")
|
||||||
|
name=$(awk '/^Partition name:/ { gsub(/'"'"'/, "") ; \
|
||||||
|
if (NF >= 3) print substr($0, index($0, $3)) }' "${pt_info}")
|
||||||
|
[ -n "${code}" -a -n "${guid}" ] ||
|
||||||
|
fail "${dev}: failed to parse sgdisk details"
|
||||||
|
|
||||||
|
debug 1 "${dev}: code=${code} guid=${guid} name='${name}'"
|
||||||
|
local wouldrun=""
|
||||||
|
[ "$DRY_RUN" -ne 0 ] && wouldrun="would-run"
|
||||||
|
|
||||||
|
# Calculate the new size of the partition
|
||||||
|
new_size=$((${pt_max} - ${pt_start}))
|
||||||
|
old="old: size=${pt_size},end=${pt_end}"
|
||||||
|
new="new: size=${new_size},end=${pt_max}"
|
||||||
|
change_info="${dev}: start=${pt_start} ${old} ${new}"
|
||||||
|
|
||||||
|
# Backup the current partition table, we're about to modify it
|
||||||
|
rq sgd_backup $wouldrun sgdisk "--backup=${GPT_BACKUP}" "${DISK}" ||
|
||||||
|
fail "${dev}: failed to backup the partition table"
|
||||||
|
|
||||||
|
# Modify the partition table. We do it all in one go (the order is
|
||||||
|
# important!):
|
||||||
|
# - move the GPT backup header to the end of the disk
|
||||||
|
# - delete the partition
|
||||||
|
# - recreate the partition with the new size
|
||||||
|
# - set the partition code
|
||||||
|
# - set the partition GUID
|
||||||
|
# - set the partition name
|
||||||
|
rq sgdisk_mod $wouldrun sgdisk --move-second-header "--delete=${PART}" \
|
||||||
|
"--new=${PART}:${pt_start}:${pt_max}" \
|
||||||
|
"--typecode=${PART}:${code}" \
|
||||||
|
"--partition-guid=${PART}:${guid}" \
|
||||||
|
"--change-name=${PART}:${name}" "${DISK}" &&
|
||||||
|
rq pt_update $wouldrun pt_update "$DISK" "$PART" || {
|
||||||
|
RESTORE_FUNC=gpt_restore
|
||||||
|
fail "${dev}: failed to repartition"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Dry run
|
||||||
|
[ "${DRY_RUN}" -ne 0 ] && change "${change_info}"
|
||||||
|
|
||||||
|
changed "${change_info}"
|
||||||
|
}
|
||||||
|
|
||||||
|
kver_to_num() {
|
||||||
|
local kver="$1" maj="" min="" mic="0"
|
||||||
|
kver=${kver%%-*}
|
||||||
|
maj=${kver%%.*}
|
||||||
|
min=${kver#${maj}.}
|
||||||
|
min=${min%%.*}
|
||||||
|
mic=${kver#${maj}.${min}.}
|
||||||
|
[ "$kver" = "$mic" ] && mic=0
|
||||||
|
_RET=$(($maj*1000*1000+$min*1000+$mic))
|
||||||
|
}
|
||||||
|
|
||||||
|
kver_cmp() {
|
||||||
|
local op="$2" n1="" n2=""
|
||||||
|
kver_to_num "$1"
|
||||||
|
n1="$_RET"
|
||||||
|
kver_to_num "$3"
|
||||||
|
n2="$_RET"
|
||||||
|
[ $n1 $op $n2 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
rq() {
|
||||||
|
# runquieterror(label, command)
|
||||||
|
# gobble stderr of a command unless it errors
|
||||||
|
local label="$1" ret="" efile=""
|
||||||
|
efile="$TEMP_D/$label.err"
|
||||||
|
shift;
|
||||||
|
|
||||||
|
local rlabel="running"
|
||||||
|
[ "$1" = "would-run" ] && rlabel="would-run" && shift
|
||||||
|
|
||||||
|
local cmd="" x=""
|
||||||
|
for x in "$@"; do
|
||||||
|
[ "${x#* }" != "$x" -o "${x#* \"}" != "$x" ] && x="'$x'"
|
||||||
|
cmd="$cmd $x"
|
||||||
|
done
|
||||||
|
cmd=${cmd# }
|
||||||
|
|
||||||
|
debug 2 "$rlabel[$label][$_capture]" "$cmd"
|
||||||
|
[ "$rlabel" = "would-run" ] && return 0
|
||||||
|
|
||||||
|
if [ "${_capture}" = "erronly" ]; then
|
||||||
|
"$@" 2>"$TEMP_D/$label.err"
|
||||||
|
ret=$?
|
||||||
|
else
|
||||||
|
"$@" >"$TEMP_D/$label.err" 2>&1
|
||||||
|
ret=$?
|
||||||
|
fi
|
||||||
|
if [ $ret -ne 0 ]; then
|
||||||
|
error "failed [$label:$ret]" "$@"
|
||||||
|
cat "$efile" 1>&2
|
||||||
|
fi
|
||||||
|
return $ret
|
||||||
|
}
|
||||||
|
|
||||||
|
rqe() {
|
||||||
|
local _capture="erronly"
|
||||||
|
rq "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_ptupdate() {
|
||||||
|
local input="$1" found="" reason="" kver=""
|
||||||
|
|
||||||
|
# we can always satisfy 'off'
|
||||||
|
if [ "$input" = "off" ]; then
|
||||||
|
_RET="false";
|
||||||
|
return 0;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v partx >/dev/null 2>&1; then
|
||||||
|
local out="" ret=0
|
||||||
|
out=$(partx --help 2>&1)
|
||||||
|
ret=$?
|
||||||
|
if [ $ret -eq 0 ]; then
|
||||||
|
echo "$out" | grep -q -- --update || {
|
||||||
|
reason="partx has no '--update' flag in usage."
|
||||||
|
found="off"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
reason="'partx --help' returned $ret. assuming it is old."
|
||||||
|
found="off"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
reason="no 'partx' command"
|
||||||
|
found="off"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$found" ]; then
|
||||||
|
if [ "$(uname)" != "Linux" ]; then
|
||||||
|
reason="Kernel is not Linux per uname."
|
||||||
|
found="off"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$found" ]; then
|
||||||
|
kver=$(uname -r) || debug 1 "uname -r failed!"
|
||||||
|
|
||||||
|
if ! kver_cmp "${kver-0.0.0}" -ge 3.8.0; then
|
||||||
|
reason="Kernel '$kver' < 3.8.0."
|
||||||
|
found="off"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$found" ]; then
|
||||||
|
_RET="true"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$input" in
|
||||||
|
on) error "$reason"; return 1;;
|
||||||
|
auto)
|
||||||
|
_RET="false";
|
||||||
|
debug 1 "partition update disabled: $reason"
|
||||||
|
return 0;;
|
||||||
|
force)
|
||||||
|
_RET="true"
|
||||||
|
error "WARNING: ptupdate forced on even though: $reason"
|
||||||
|
return 0;;
|
||||||
|
esac
|
||||||
|
error "unknown input '$input'";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pt_update() {
|
||||||
|
local dev="$1" part="$2" update="${3:-$PT_UPDATE}"
|
||||||
|
if ! $update; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
# partx only works on block devices (do not run on file)
|
||||||
|
[ -b "$dev" ] || return 0
|
||||||
|
partx --update "$part" "$dev"
|
||||||
|
}
|
||||||
|
|
||||||
|
has_cmd() {
|
||||||
|
command -v "${1}" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
resize_sgdisk_gpt() {
|
||||||
|
resize_sgdisk gpt
|
||||||
|
}
|
||||||
|
|
||||||
|
resize_sgdisk_dos() {
|
||||||
|
fail "unable to resize dos label with sgdisk"
|
||||||
|
}
|
||||||
|
|
||||||
|
resize_sfdisk_gpt() {
|
||||||
|
resize_sfdisk gpt
|
||||||
|
}
|
||||||
|
|
||||||
|
resize_sfdisk_dos() {
|
||||||
|
resize_sfdisk dos
|
||||||
|
}
|
||||||
|
|
||||||
|
get_table_format() {
|
||||||
|
local out="" disk="$1"
|
||||||
|
if has_cmd blkid && out=$(blkid -o value -s PTTYPE "$disk") &&
|
||||||
|
[ "$out" = "dos" -o "$out" = "gpt" ]; then
|
||||||
|
_RET="$out"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
_RET="dos"
|
||||||
|
if [ ${SFDISK_VERSION} -lt ${SFDISK_2_26} ] &&
|
||||||
|
out=$(sfdisk --id --force "$disk" 1 2>/dev/null); then
|
||||||
|
if [ "$out" = "ee" ]; then
|
||||||
|
_RET="gpt"
|
||||||
|
else
|
||||||
|
_RET="dos"
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
elif out=$(LANG=C sfdisk --list "$disk"); then
|
||||||
|
out=$(echo "$out" | sed -e '/Disklabel type/!d' -e 's/.*: //')
|
||||||
|
case "$out" in
|
||||||
|
gpt|dos) _RET="$out";;
|
||||||
|
*) error "WARN: unknown label $out";;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_resizer() {
|
||||||
|
local format="$1" user=${2:-"auto"}
|
||||||
|
|
||||||
|
case "$user" in
|
||||||
|
sgdisk) _RET="resize_sgdisk_$format"; return;;
|
||||||
|
sfdisk) _RET="resize_sfdisk_$format"; return;;
|
||||||
|
auto) :;;
|
||||||
|
*) error "unexpected input: '$user'";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ "$format" = "dos" ]; then
|
||||||
|
_RET="resize_sfdisk_dos"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${SFDISK_VERSION}" -ge ${SFDISK_V_WORKING_GPT} ]; then
|
||||||
|
# sfdisk 2.26.2 works for resize but loses type (LP: #1474090)
|
||||||
|
_RET="resize_sfdisk_gpt"
|
||||||
|
elif has_cmd sgdisk; then
|
||||||
|
_RET="resize_sgdisk_$format"
|
||||||
|
else
|
||||||
|
error "no tools available to resize disk with '$format'"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pt_update="auto"
|
||||||
|
resizer=${GROWPART_RESIZER:-"auto"}
|
||||||
|
while [ $# -ne 0 ]; do
|
||||||
|
cur=${1}
|
||||||
|
next=${2}
|
||||||
|
case "$cur" in
|
||||||
|
-h|--help)
|
||||||
|
Usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
--fudge)
|
||||||
|
FUDGE=${next}
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-N|--dry-run)
|
||||||
|
DRY_RUN=1
|
||||||
|
;;
|
||||||
|
-u|--update|--update=*)
|
||||||
|
if [ "${cur#--update=}" != "$cur" ]; then
|
||||||
|
next="${cur#--update=}"
|
||||||
|
else
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
case "$next" in
|
||||||
|
off|auto|force|on) pt_update=$next;;
|
||||||
|
*) fail "unknown --update option: $next";;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
-v|--verbose)
|
||||||
|
VERBOSITY=$(($VERBOSITY+1))
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
fail "unknown option ${cur}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ -z "${DISK}" ]; then
|
||||||
|
DISK=${cur}
|
||||||
|
else
|
||||||
|
[ -z "${PART}" ] || fail "confused by arg ${cur}"
|
||||||
|
PART=${cur}
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -n "${DISK}" ] || bad_Usage "must supply disk and partition-number"
|
||||||
|
[ -n "${PART}" ] || bad_Usage "must supply partition-number"
|
||||||
|
|
||||||
|
has_cmd "sfdisk" || fail "sfdisk not found"
|
||||||
|
get_sfdisk_version || fail
|
||||||
|
|
||||||
|
[ -e "${DISK}" ] || fail "${DISK}: does not exist"
|
||||||
|
|
||||||
|
[ "${PART#*[!0-9]}" = "${PART}" ] || fail "partition-number must be a number"
|
||||||
|
|
||||||
|
verify_ptupdate "$pt_update" || fail
|
||||||
|
PT_UPDATE=$_RET
|
||||||
|
|
||||||
|
debug 1 "update-partition set to $PT_UPDATE"
|
||||||
|
|
||||||
|
mktemp_d && TEMP_D="${_RET}" || fail "failed to make temp dir"
|
||||||
|
trap cleanup 0 # EXIT - some shells may not like 'EXIT' but are ok with 0
|
||||||
|
|
||||||
|
# get the ID of the first partition to determine if it's MBR or GPT
|
||||||
|
get_table_format "$DISK" || fail
|
||||||
|
format=$_RET
|
||||||
|
get_resizer "$format" "$resizer" ||
|
||||||
|
fail "failed to get a resizer for id '$id'"
|
||||||
|
resizer=$_RET
|
||||||
|
|
||||||
|
debug 1 "resizing $PART on $DISK using $resizer"
|
||||||
|
"$resizer"
|
||||||
|
|
||||||
|
# vi: ts=4 noexpandtab
|
Loading…
Reference in new issue