Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 508 lines (462 sloc) 17.8 KB
#!/bin/bash
#
# This is netprofile, an application which allows to use
# different sets of network profiles on same physical network connections.
#
# Copyright, (C) Mandriva, 2003-2009.
# Copyright, (C) Frederic Lepied, 2003-2005
# Copyright, (C) Eugeni Dodonov, 2009
#
# TODO: security concerns (profiles containing '/', ';' or '..')
# TODO: implement check command (to check for changes in profile)
# TODO: implement getopt support
NETPROFILE=/etc/netprofile
PROFILES=$NETPROFILE/profiles
MODULES=$NETPROFILE/modules
CURRENT=$NETPROFILE/current
VERBOSE=0
LOG=/var/log/netprofile.log
DATE=$(date)
LOG_TMP=$(mktemp)
DEFAULT_PROFILE=default
function cleanup {
rm -f $LOG_TMP
}
trap cleanup 0
# TODO: handle other signals gracefully
function restore_files {
PROFILE=$1
MODULE=$2
FILES=$3
# restoring old files
SAVED_FILES="$PROFILES/$PROFILE/$MODULE"
if [ ! -d "$SAVED_FILES" ]; then
log " ** no saved files for $MODULE were found in $PROFILE"
else
log " ** restoring files for $MODULE from $SAVED_FILES"
rm -f $LOG_TMP
(cd $SAVED_FILES && tar cpf - . 2>>$LOG_TMP) | (cd / && tar xpf - 2>>$LOG_TMP)
catlog
fi
}
function remove_files {
PROFILE=$1
MODULE=$2
FILES=$3
SAVED_FILES="$PROFILES/$PROFILE/$MODULE"
if [ ! -d "$SAVED_FILES" ]; then
log " ** not removing files for $MODULE in $PROFILE as no saved files were found"
else
log " ** removing files to restore $MODULE from $PROFILE"
rm -f $LOG_TMP
rm -rf -- $(echo $FILES) 2>>$LOG_TMP
catlog
fi
}
function save_files {
PROFILE=$1
MODULE=$2
FILES=$3
# saving files
SAVED_FILES="$PROFILES/$PROFILE/$MODULE"
if [ ! -d "$SAVED_FILES" ]; then
log "creating profile directory: $SAVED_FILES"
mkdir -p $SAVED_FILES
fi
log " ** copying files for $MODULE into $SAVED_FILES"
rm -f $LOG_TMP
tar cpf - $(echo $FILES) 2>>$LOG_TMP | (cd $SAVED_FILES && tar xpf -) 2>>$LOG_TMP
catlog
}
function restart_services {
SERVICES=$1
for service in $SERVICES; do
log " ** restarting service $service"
rm -f $LOG_TMP
chkconfig $service && service $service restart 2>>$LOG_TMP
catlog
done
}
function print_debug {
if [ "a$VERBOSE" = "a1" ]; then
echo "$*"
fi
}
function log {
print_debug "$1"
echo "$DATE: $1" >> $LOG
}
function catlog {
if [ -s $LOG_TMP ]; then
while read line; do
echo "$DATE: $line" >> $LOG
done < $LOG_TMP
fi
}
function restore_profile {
# sets a network profile
PROFILE=$1
RESTART_SERVICES=${1:-0}
# do we have a profile?
if [ ! -d "$PROFILES/$PROFILE" ]; then
log "Profile $PROFILE does not exists"
return 1
else
log "Restoring profile $PROFILE from $PROFILES/$PROFILE"
fi
for module in $MODULES/*; do
# if module is not executable, disable it
test -x $module || continue
# unsetting old variables
unset NAME SERVICES FILES
# unsetting old functions
unset -f save restore
. $module
print_debug "Removing old files for $NAME"
remove_files "$PROFILE" "$NAME" "$FILES"
print_debug "Restoring files for $NAME"
restore_files "$PROFILE" "$NAME" "$FILES"
if [ ! "a$RESTART_SERVICES" = "a0" ]; then
print_debug "Restarting services for $NAME"
restart_services "$SERVICES"
fi
# calling module-specific hook
if [ "`type -t restore`" == 'function' ]; then
restore "$PROFILE"
fi
done
}
function update_current {
PROFILE=$1
echo "$PROFILE" > $CURRENT
}
function save_profile {
# saves current system settings into a profile
PROFILE=$1
test -d "$PROFILES/$PROFILE" || mkdir -p "$PROFILES/$PROFILE"
log "Saving files for $PROFILE"
for module in $MODULES/*; do
# if module is not executable, disable it
test -x $module || continue
# unsetting old variables
unset NAME SERVICES FILES
# unsetting old functions
unset -f save restore
. $module
save_files "$PROFILE" "$NAME" "$FILES"
# calling module-specific hook
if [ "`type -t save`" == 'function' ]; then
save "$PROFILE"
fi
done
}
function remove_profile {
# removes a network profile
PROFILE=$1
# do we have a profile?
if [ ! -d "$PROFILES/$PROFILE" ]; then
log "Profile $PROFILE does not exists"
return 1
else
log "Removing profile $PROFILE from $PROFILES/$PROFILE"
fi
# TODO: save backup
rm -rf "$PROFILES/$PROFILE"
}
function check_root {
# must be run as root
if [ ! "a$UID" = "a0" ]; then
echo "Error: $0 must be run as root!"
exit 1
fi
}
function check_current_profile {
if [ -z "$NEW_PROFILE" ]; then
echo "Error: no profile specified"
exit 1
fi
if [ "a$NEW_PROFILE" = "a$CURPROFILE" ]; then
echo "The $NEW_PROFILE is the current profile."
exit 0
fi
}
function get_boot_profile {
if [ -z "$NEW_PROFILE" ]; then
# get profile name from cmdline
NEW_PROFILE=$(cat /proc/cmdline | tr ' ' '\n' | grep PROFILE | cut -f 2 -d =)
fi
# no profile passed on command line, show user a menu
if [[ -z "$NEW_PROFILE" && -d /etc/netprofile/profiles/ ]]; then
nb_profiles=`ls /etc/netprofile/profiles | wc -l`;
if [[ "$nb_profiles" == "1" ]]; then
NEW_PROFILE=`basename /etc/netprofile/profiles/*`
else
pushd /etc/netprofile/profiles/ > /dev/null 2>&1
count=1
profiles=""
keys=""
for z in *; do
if [ "a$profiles" = "a" ]; then
profiles="($count) $z"
else
profiles="$profiles ($count) $z"
fi
# is it current profile?
if [ "a$z" = "a$CURPROFILE" ]; then
profiles="${profiles}*"
fi
# update keystrokes
keys="${keys}${count}"
count=$((count + 1))
# we stop at 9 profiles to fit on screen
if [ $count -gt 9 ]; then
profiles="$profiles ..."
break
fi
done
popd > /dev/null 2>&1
# show graphical choice if plymouth is running
if [ -x /bin/plymouth ] && /bin/plymouth --ping ; then
/bin/plymouth pause-progress
message=$(echo -ne "Select network profile:\n$profiles")
/bin/plymouth message --text="$message"
# show the message on screen, as plymouth seems not to work well
# with text mode :(
echo
echo $message
# using /var/run/netprofile_boot as flag to indicate that user
# has chosen a profile. If no profile was chosen, leave after
# 5 seconds
{
# stop waiting for keystroke after timeout
sleep 5
if [ ! -f /var/run/netprofile_boot ]; then
# kill pending plymouth process, otherwise
# we'll hang later in boot stage
kill $(pidof plymouth) > /dev/null 2>&1
/bin/plymouth unpause-progress
message="Using current network profile ($(netprofile current))"
/bin/plymouth message --text="$message"
echo
echo netprofile: $message
else
rm -f /var/run/netprofile_boot
fi
exit 0
}&
rm -f /var/run/netprofile_boot
exec 2>/dev/null
/bin/plymouth watch-keystroke --keys=$keys --command=/sbin/read-netprofile
else
# plymouth not available, should use text-based choice (ncurses?)
exit 0
fi
exit 0
fi
fi
}
function reload_netapplet {
# make net_applet reload the configuration
# (needs "current" file to be up to date)
PID=`pidof -x net_applet`
[[ -n "$PID" ]] && kill -HUP $PID
}
function notify {
MESSAGE="$1"
DBUS_SEND=`which dbus-send 2>/dev/null`
if [ -x "$DBUS_SEND" ]; then
$DBUS_SEND --system --type=signal /com/mandriva/user com.mandriva.user.custom_notification string:"NetProfile" string:"$MESSAGE"
fi
}
function usage {
cat << EOF
Usage: $0 [-options] <operation> [profile]
The following operations are supported:
operations on network profiles:
switch [-v] save the system configuration into current profile, and
restore files belonging to the new profile. If the new
profile does not exists, it will be created with base on
current configuration.
boot [-v] determine the desired profile from the kernel command line,
or show user a menu to select the desired profile.
delete [-v] delete an existent profile.
current display the currently used profile.
list [-v] list available profiles.
reset resets the network profiles configuration. This action will
have the following effects:
- all existent profiles will be removed
- current system configuration will be saved as
'$DEFAULT_PROFILE' profile
you might want to use this action when a big system change
was performed (distro upgrade), or you simple want to start
over with a new configuration.
advanced options:
save [-v] save current settings into the current profile without switching
to a different profile
load [-v] load a different profile without saving current settings
basically, the sequence of 'netprofile save; netprofile load'
does exactly the same thing as 'netprofile switch', but with
higher degree of control over the performed actions.
operations on netprofile modules:
modules [-v] list available modules
module_enable [-v] enables a netprofile module
module_disable [-v] disables a netprofile module
Options:
-v, --verbose show detailed information for performed
operations
-h, --help show this help message
EOF
exit 0
}
NO_RESTART_NETWORK=
if [ "a$1" = "a" ]; then
usage
fi
args=`getopt -o v,h -l verbose,help -n "$0" -- "$@"`
eval set -- "$args"
while true; do
case "$1" in
-v|--verbose) VERBOSE=1; shift 1;;
-h|--help) usage; shift 1;;
--) shift ; break;;
*) echo "Invalid argument: $1"; exit 1 ;;
esac
done
ACTION="$1"
NEW_PROFILE="$2"
CURPROFILE=$(cat $CURRENT 2>/dev/null)
if [ "a$ACTION" = "aswitch" ]; then
check_root
check_current_profile
if [ ! -n "$CURPROFILE" ]; then
# no current profile
log "Creating initial profile $NEW_PROFILE"
save_profile "$NEW_PROFILE"
else
log "Switching from profile $CURPROFILE to profile $NEW_PROFILE"
save_profile "$CURPROFILE"
notify "Switching to network profile $NEW_PROFILE, please wait a few moments..."
restore_profile "$NEW_PROFILE" 1 || (log "Creating new profile $NEW_PROFILE"; save_profile "$NEW_PROFILE")
fi
update_current "$NEW_PROFILE"
notify "You are now using the network profile $NEW_PROFILE"
reload_netapplet
elif [ "a$ACTION" = "asave" ]; then
check_root
save_profile "$CURPROFILE"
elif [ "a$ACTION" = "aload" ]; then
check_root
check_current_profile
log "Switching from profile $CURPROFILE to profile $NEW_PROFILE"
notify "Switching to network profile $NEW_PROFILE, please wait a few moments..."
restore_profile "$NEW_PROFILE" 1
update_current "$NEW_PROFILE"
notify "You are now using the network profile $NEW_PROFILE"
reload_netapplet
elif [ "a$ACTION" = "aboot" ]; then
check_root
get_boot_profile
check_current_profile
log "Switching from profile $CURPROFILE to profile $NEW_PROFILE"
save_profile "$CURPROFILE"
restore_profile "$NEW_PROFILE"
update_current "$NEW_PROFILE"
reload_netapplet
elif [ "a$ACTION" = "adelete" ]; then
check_root
check_current_profile
print_debug "Removing profile $NEW_PROFILE"
remove_profile "$NEW_PROFILE"
reload_netapplet
elif [ "a$ACTION" = "acurrent" ]; then
echo $CURPROFILE
exit 0
elif [ "a$ACTION" = "alist" ]; then
# shows available netprofiles
(
cd $PROFILES
for z in *; do
if [ "a$VERBOSE" = "a1" -a "$z" = "$CURPROFILE" ]; then
echo "(current) $z"
else
echo "$z"
fi
done
)
exit 0
elif [ "a$ACTION" = "areset" ]; then
# resets netprofile configuration
check_root
(
cd $PROFILES
for z in *; do
if [ ! "$CURPROFILE" = "$z" ]; then
if [ "a$VERBOSE" = "a" ]; then
echo "Removing profile $z"
fi
remove_profile $z
fi
done
if [ "a$VERBOSE" = "a" ]; then
echo "Setting profile $CURPROFILE as new $DEFAULT_PROFILE profile"
fi
mv "$CURPROFILE" $DEFAULT_PROFILE && update_current "$DEFAULT_PROFILE"
)
reload_netapplet
elif [ "a$ACTION" = "amodules" ]; then
# show available modules
(
cd $MODULES
for module in *; do
# is module enabled?
if [ -x "$module" ]; then
ENABLED="+"
ENABLED_VERBOSE="enabled"
else
ENABLED="-"
ENABLED_VERBOSE="disabled"
fi
. $module
if [ "a$VERBOSE" = "a1" ]; then
echo -e "$module\t($ENABLED_VERBOSE):\t$NAME ($DESCRIPTION)"
else
echo -e "$module\t$ENABLED\t$NAME\t$DESCRIPTION"
fi
done
)
elif [ "a$ACTION" = "amodule_enable" ]; then
MODULE=$2
check_root
# enable a module
(
cd $MODULES
if [ ! -f "$MODULE" ]; then
echo "Error: module $MODULE not found"
exit 1
fi
if [ "a$VERBOSE" = "a1" ]; then
echo "Enabling $MODULE"
fi
chmod +x $MODULE
)
elif [ "a$ACTION" = "amodule_disable" ]; then
MODULE=$2
check_root
# enable a module
(
cd $MODULES
if [ ! -f "$MODULE" ]; then
echo "Error: module $MODULE not found"
exit 1
fi
if [ "a$VERBOSE" = "a1" ]; then
echo "Disabling $MODULE"
fi
chmod -x $MODULE
)
else
echo "$0: unknown action $ACTION"
exit 1
fi
exit 0
# set-netprofile ends here