Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 28 Oct 1997 12:37:00 +1030
From:      Mike Smith <mike@smith.net.au>
To:        davet@ttfn.com
Cc:        Warner Losh <imp@village.org>, freebsd-mobile@FreeBSD.ORG
Subject:   Re: How do you solve... 
Message-ID:  <199710280207.MAA00954@word.smith.net.au>
In-Reply-To: Your message of "Mon, 27 Oct 1997 14:52:09 -0800." <13903.877992729@nomad> 

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multipart MIME message.

--==_Exmh_21172141880
Content-Type: text/plain; charset=us-ascii

> ------- =_aaaaaaaaaa0
> Content-Type: text/plain; charset="us-ascii"
> Content-ID: <13900.877992729.1@nomad>
> Content-MD5: TG/OeIqtvEKKsx94a+5wqw==
> Content-Transfer-Encoding: quoted-printable

Please avoid using 'quoted-unprintable' for plain message text.  
Replying to it is a Real Pain.

> My laptop's been using the ISC DHCP client for the past 8 months to 
> configureitself for both my home and work networks.  It works great,
> and saves me the hassle of remembering to reconfigure anything by hand. 
> The only problems I've had to hack around are getting sendmail to
> recognize the change to resolv.conf so it can talk to the local 
> nameserver, and changing the mailrelay so it can route mail out
> past my home firewall.  (Elegant idea for handling such dynamic
> configuration issues are always welcome.)

Rewrite your /etc/sendmail.cf and change the

O FallbackMXhost=

line to point to your local firewall when you're there, and then
'killall -HUP sendmail'.  It'll reread your config at that point; I'm 
not sure if it actually restarts proper, which is what it would take to 
get it to pick up changes to /etc/resolv.conf.

I actually use a fairly neat tool I wrote called 'personality' for 
managing this (attached).  Just add '/sbin/personality menu' in /etc/rc 
just before rc.conf is read; I use:

# If the system personality system is configured, run the selector
if [ -d /etc/personality ]; then
        /sbin/personality menu 5
fi

mike

--==_Exmh_21172141880
Content-Type: text/plain; name="personality"; charset=us-ascii
Content-Description: personality
Content-Disposition: attachment; filename="personality"

#!/bin/sh
##############################################################################
#
# Copyright (c) 1997 Michael Smith
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#	$Id$
#
##############################################################################
#
# This script provides functionality for manipulating collections of 
# configuration files which can be organised so as to alter the
# personality of a system.
#
# Initially, the "base" personality is established.  This personality
# contains the "reference" copies of configuration files, and is used
# when creating new personalities.  The files which are currently
# considered part of the system's personality are those contained in
# the base personality.
#
# A new personality is established by making a copy of the base 
# personality under a new name.  Each personality maintains a
# separate copy of all configuration files under /etc/personality.
#
# To install a new personality, the files currently in place are 
# saved back to the current personality as indicated in 
# /etc/personality/current, and the files for the new personality
# copied into place.  The 'select' and 'menu' commands which perform
# these installations are implemented in such a fashion as to only
# require the tools available on the root filesystem, so that they
# may be invoked at the earliest stage during system startup.
#
# If the current personality has become damaged, it can be restored
# from the saved copy.
#
# Files can be added to and removed from the personality set.  When
# a new file is added, it is copied from the current system into all
# personalities and added to the list file.  When a file is removed
# the current version is kept in place, but all copies are removed 
# from saved personalities and the file is removed from the list.
#
# XXX To Do :
# Files can be inherited by one personality from another.  This is
# simply achieved by copying the relevant files under /etc/personality,
# and into the current system if required.
#
##############################################################################

# Establish some global constants
P_ROOT=/etc/personality
#P_ROOT=/tmp/personality
P_BASE="${P_ROOT}/_base"
P_CURRENT="${P_ROOT}/current"
P_FILES="${P_ROOT}/files"
P_LIST="${P_ROOT}/list"
scriptname="$0"

##############################################################################
# pers_main
#
# Execution begins here after the file has been read.
#
pers_main()
{
    case "$1" in
    menu)
	pers_menu $2 $3
	;;
    select)
	pers_select $2
	;;
    restore)
	pers_restore
	;;
    save)
	pers_save
	;;
    saveas)
	pers_saveas $2
	pers_reindex
	;;
    create)
	pers_create $2
	pers_reindex
	;;
    delete)
	pers_delete $2
	pers_reindex
	;;
    add)
	pers_add $2
	pers_reindex
	;;
    list)
	pers_list
	;;
    remove)
	pers_remove $2
	pers_reindex
	;;
    init)
	pers_init
	pers_reindex
	;;
    *)
	usage
	;;
    esac
}

##############################################################################
# pers_menu
#
# Present a menu of currently-selectable personalities, assign hotkeys,
# describe the default and optionally go with the default after a timeout
#
pers_menu()
{
    # Look and see if there's actually anything to work with
    if [ ! -d "${P_ROOT}" ]; then
	return
    fi

    # Pick up a timeout if specified, default to 10 seconds
    timeout=10
    if [ ! -z "$1" ]; then
	timeout="$1"
    fi

    # Assign a default, if suitable
    defpers=""
    defname="<none>"
    if [ -f "${P_CURRENT}" ]; then
	defpers=`cat "${P_CURRENT}"`
	defname="${defpers}"
    fi

    # Loop prompting/reading input until we get a result
    while :; do

	# Print menu
	echo "";
	echo "Select System Personality"
	echo "========================="
	hkey=0
	for pers in `cat "${P_LIST}"`; do
	    echo "    ${hkey})  ${pers}"
	    eval index_${hkey}="${pers}"
	    hkey=`expr ${hkey} + 1`
	done
	echo "";

	echo "  Default   : ${defname}"
	read -t "${timeout}" -p "  Selection : " input
	eval selvar=\$index_"${input}"
	selpers=""
	if [ -z "${input}" ]; then
	    selpers="${defpers}"
	    break
	elif [ -n "${selvar}" ]; then
	    selpers="${selvar}"
	    break
	elif [ -d "${P_ROOT}/_${input}" ]; then
	    selpers="${input}"
	    break
	fi
    done
    
    # $selpers now contains the personality we wish to select,
    # or is empty if we selected the default when there was none
    if [ -z "${selpers}" ]; then
	return
    fi

    # select the personality nominated
    pers_select "${selpers}"
}

##############################################################################
# pers_select
#
# Copy the files from the nominated personality out of the repository
# into the real system.  Note that this must be able to run with
# nothing other than the contents of /bin available.
#
pers_select()
{
    src="${P_ROOT}/_$1";
    if [ ! -d "${src}" ]; then
	fail "no such personality '$1'"
    fi

    # Iterate over the file listing, copy them all out
    for file in `cat "${P_FILES}"`; do
	cp -p "${src}/${file}" "${file}"
    done

    # Register this personality as being current
    echo "$1" > "${P_CURRENT}"
}

##############################################################################
# pers_restore
#
# Reload the configuration files for the current personality, eliminating
# any changes that may have been made.
#
pers_restore()
{
    if [ ! -e "${P_CURRENT}" ]; then
	fail "no personality currently active"
    fi

    # Check that the current personality exists
    pers=`cat "${P_CURRENT}"`
    src="${P_ROOT}/_${pers}"
    if [ ! -d "${src}" ]; then
	fail "current personality '${pers}' not in the repository!"
    fi

    # Iterate over the file listing, copy them all out
    for file in `cat "${P_FILES}"`; do
	cp -p "${src}/${file}" "${file}"
    done
}

##############################################################################
# pers_save
#
# If a personality is current, save the current set of files to that
# personality.
#
pers_save()
{
    if [ ! -e "${P_CURRENT}" ]; then
	fail "no personality currently active"
    fi

    # Check that the current personality exists
    pers=`cat "${P_CURRENT}"`
    dest="${P_ROOT}/_${pers}"
    if [ ! -d "${dest}" ]; then
	fail "current personality '${pers}' not in the repository!"
    fi

    # OK, go ahead and save stuff.  If this fails, we're
    # moderately stuffed, so don't worry about it.
    for file in `cat "${P_FILES}"`; do
	stub=`dirname "${file}"`
	mkdir -p "${dest}/${stub}"
	cp -p "${file}" "${dest}/${file}"
    done
}

##############################################################################
# pers_saveas
#
# Take the currently-active set of configuration files, and save them as
# a new personality, set the new personality as current.
#
pers_saveas()
{
    dest="${P_ROOT}/_$1"
    if [ -e "${dest}" ]; then
	fail "cannot create new personality '$1', name already in use"
    fi

    # Create the personality directory
    mkdir -p "${dest}" || pers_saveas_fail "$1"

    # iterate over files to save, copy them in
    for file in `cat "${P_FILES}"`; do
	stub=`dirname "${file}"`
	mkdir -p "${dest}/${stub}"
	cp -p "${file}" "${dest}/${file}" || pers_saveas_fail $1
    done

    # new personality is current
    echo "$1" > "${P_CURRENT}"
}

########################################
# pers_saveas_fail
#
# The 'save as' operation failed.  Clean
# up and emit a failure message.
#
pers_saveas_fail()
{
    rm -Rf "${P_ROOT}/_$1"
    fail "could not save current personality as '$1'"
}

##############################################################################
# pers_create
#
# Create a new personality, duplicated from the current base personality
#
pers_create()
{
    if [ -e "${P_ROOT}/_$1" ]; then
	fail "cannot create new personality '$1', name already in use"
    fi

    # Ok, duplicate it
    cp -Rp "${P_BASE}" "${P_ROOT}/_$1" || pers_create_fail "$1"
}

########################################
# pers_create_fail
#
# An attempt to create a personality failed.
# Clean up and exit with an error message.
#
pers_create_fail() 
{
    rm -Rf "${P_ROOT}/_$1"
    fail "'$1' could not be created"
}

##############################################################################
# pers_delete
#
# Remove a personality from the system.  It is legitimate to remove
# the current personality.
#
pers_delete()
{
    if [ ! -e "${P_ROOT}/_$1" ]; then
	fail "no such personality '$1' to remove"
    fi
    if [ "$1" = _base ]; then
	fail "cannot remove base personality"
    fi

    # If the requested personality is current, remove the
    # reference.
    if [ -e "${P_CURRENT}" ]; then 
	if [ `cat "${P_CURRENT}"` = "$1" ]; then
	    rm -f "${P_CURRENT}"
	fi
    fi

    # Remove the repository entry
    rm -Rf "${P_ROOT}/_$1";

    # Make sure it's gone
    if [ -e "${P_ROOT}/_$1" ]; then
	fail "failed to completely remove personality '$1'";
    fi
}

##############################################################################
# pers_add
#
# Add a new file to the system; copy it from the 'real' path into 
# each personality directory.  Check first to make sure it's not already 
# part of the system, and check that the path supplied is absolute.
#
# The file is stored with its full path relative to the repository
# directory.
#
pers_add()
{
    if [ ! -r "/$1" ]; then
	fail "cannot read '$1' to add to the Personality System"
    fi
    if [ -e "${P_BASE}/$1" ]; then
	fail "file '$1' already part of the Personality System"
    fi
    if [ ! -f "$1" ]; then
	fail "only files can be added to the Personality System"
    fi

    # looks OK, copy it in
    stub=`dirname "$1"`
    for targ in ${P_ROOT}/_*; do
	mkdir -p "${targ}/${stub}"
	cp -p "$1" "${targ}/${stub}" || pers_add_fail "$1";
    done
}

########################################
# pers_add_fail
#
# A failure occurred while adding a file to
# the repository; back out any copies that 
# made it in and abort with an error.
#
pers_add_fail()
{
    for cand in ${P_ROOT}/_*; do
	if [ -f "${cand}/$1" ]; then
	    rm -f "${cand}/$1";
	fi
    done
    fail "'$1' could not be added";
}
	
##############################################################################
# pers_remove
#
# Remove a file from all personalities in the repository.
#
pers_remove()
{
    if [ ! -f "${P_BASE}/$1" ]; then
	fail "'$1' is not part of the Personality System";
    fi

    # OK, it should be there; nuke whatever we can find
    for cand in ${P_ROOT}/_*; do
	if [ -f "${cand}/$1" ]; then
	    rm -f "${cand}/$1";
	fi
    done
}

##############################################################################
# pers_list
#
# List all of the files that comprise the system personality.
#
pers_list() 
{
    echo "Current personalities:"
    for pers in `cat "${P_LIST}"`; do
	echo "  ${pers}";
    done
    echo "Files in system personality:"
    for file in `cat "${P_FILES}"`; do
	echo "  ${file}"
    done
}

##############################################################################
# pers_init
#
# Initialise the personality collection; refuse to do so if there is 
# already one in place, or something else occupying the root path.
#
pers_init()
{
    if [ -e "${P_ROOT}" ]; then
	fail "cannot initialise, '${P_ROOT}' already exists"
    fi

    # Create the repository with no files, and no current personality
    mkdir -p "${P_ROOT}"
    mkdir -p "${P_BASE}"
}

##############################################################################
# pers_reindex
#
# Clean out any empty directories in the repository.  This is achieved 
# by silently trying to rmdir everything that looks like a directory
# under any personality.
#
# Then rebuild the list of files that comprise the system personality,
# so that the select and menu functions work.
#
pers_reindex()
{
    # Remove empty directories
    for cand in ${P_ROOT}/_*; do
	find -dX "${cand}/." -type d | xargs rmdir >/dev/null 2>&1
    done
    
    # Regenerate the files list
    find -X "${P_BASE}" -type f | sed "s%${P_BASE}%%" > "${P_FILES}"
    # regenerate the personalities list
    ls -d "${P_ROOT}/_"* | sed "s%${P_ROOT}/_%%" > "${P_LIST}"
}

##############################################################################
# usage
#
# Emit a (hopefully) helpful diagnostic and exit
#
usage() 
{
    echo "${scriptname}: incorrect argument(s)"
    echo ""
    echo " Usage is ${scriptname} <command>, where valid commands are :"
    echo "  menu [<timeout>]      Invoke the menu-driven personality selector"
    echo "  select <personality>  Select a specific personality"
    echo "  restore               Restore the current personality from the saved version"
    echo "  save                  Save the current personality"
    echo "  saveas <personality>  Save the current personality under a new name"
    echo "  create <personality>  Create a new personality from the base"
    echo "  delete <personality>  Delete a personality"
    echo "  add <full path>       Add a new file"
    echo "  remove <full path>    Remove a file"
    echo "  list                  List all files"
    echo "  init                  Initialise the Personality System"
    echo ""
    exit 2;
}

##############################################################################
# fail
#
# Emit an error message to stderr and exit
#
fail () 
{
    echo "${scriptname}: $1";
    exit 1;
}

##############################################################################
# Now we have parsed everything, start.
pers_main $1 $2 $3 $4;
exit 0;

--==_Exmh_21172141880--





Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199710280207.MAA00954>