new port of Michael Smith's personality script

personality manages different system configurations
This commit is contained in:
Andreas Klemm 2001-03-25 20:34:50 +00:00
parent e995a513a1
commit 6b34a8a9ea
Notes: svn2git 2021-03-31 03:12:20 +00:00
svn path=/head/; revision=40370
8 changed files with 672 additions and 0 deletions

View file

@ -88,6 +88,7 @@
SUBDIR += p5-SyslogScan
SUBDIR += p5-Unix-ConfigFile
SUBDIR += p5-Unix-Syslog
SUBDIR += personality
SUBDIR += pib
SUBDIR += pkg_remove
SUBDIR += portupgrade

View file

@ -0,0 +1,32 @@
# New ports collection makefile for: personality
# Date created: 25 Mar 2001
# Whom: Andreas Klemm <andreas@FreeBSD.org>
#
# $FreeBSD$
#
PORTNAME= personality
PORTVERSION= 1.0
CATEGORIES= sysutils
DISTFILES= # none
MAINTAINER= andreas@FreeBSD.org
WRKSRC= ${WRKDIR}/src
NO_BUILD= YES
do-extract:
@ ${RM} -rf ${WRKDIR}
@ ${MKDIR} ${WRKDIR}
@ ${CP} -RP ${.CURDIR}/src ${WRKDIR}
MAN8= personality.8
do-install:
@ ${INSTALL_SCRIPT} ${WRKSRC}/personality ${PREFIX}/sbin
@ ${INSTALL_DATA} ${WRKSRC}/personality.8 ${PREFIX}/man/man8
post-install:
@ ${CAT} ${.CURDIR}/pkg-message
.include <bsd.port.mk>

View file

@ -0,0 +1 @@
System configuration management utility to alter system personality

View file

@ -0,0 +1,21 @@
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.

View file

@ -0,0 +1,8 @@
To change the personality of your system at system boot
you have to add the following line into the /etc/rc script.
[ -x /usr/local/sbin/personality ] && /usr/local/sbin/personality menu 60
Make sure that you add this after mounting of the ufs filesystems.
If you prefer you can use other values than 60 seconds.
After 60 seconds the system boots with the last configuration.

View file

@ -0,0 +1 @@
sbin/personality

View file

@ -0,0 +1,536 @@
#! /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.
#
# $FreeBSD$
#
##############################################################################
#
# 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;

View file

@ -0,0 +1,72 @@
.\" Copyright (c) 2000
.\" Andreas Klemm <andreas@FreeBSD.org>. All rights reserved.
.\"
.\" $FreeBSD$
.\"
.Dd March 25, 2001
.Dt PERSONALITY 1
.Os
.Sh NAME
.Nm personality
.Nd system configuration management utility
.Sh SYNOPSIS
.Nm personality
.Op options ...
.Sh DESCRIPTION
This script provides functionality for manipulating collections of
configuration files which can be organised so as to alter the
personality of a system.
.Pp
Initially, the
.Ic base
personality is established. This personality contains the
.Ic 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.
.Pp
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
.Ic /etc/personality .
.Pp
To install a new personality, the files currently in place are saved back
to the current personality as indicated in
.Ic /etc/personality/current ,
and the files for the new personality copied into place.
.Pp
The
.Ic select
and
.Ic 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.
.Pp
If the current personality has become damaged, it can be restored
from the saved copy.
.Pp
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.
.Sh FILES
.Bl -tag -width /etc/personality/current -compact
.It Pa /etc/personality
configuration base
.It Pa /etc/personality/_base
system files under management of personality
.It Pa /etc/personality/current
backup location of current files before new personality is copied into place
.Sh SEE ALSO
.Xr rc 8
.Sh BUGS
Currently none.
.Sh HISTORY
The
.Nm
script has been written 1997 by Mike Smith <msmith@FreeBSD.org>.
The
.Nm
manual page has been written by Andreas Klemm <andreas@FreeBSD.org>.