#!/bin/sh # The "pkg_dir" variable points to the directory containing the packages. # This path must be absolute. pkg_dir="/pkgs" # The "target_dir" variable points to the directory where the target # directories are located. This path must be absolute. target_dir="/" command="${1}" pkg_name="${2}" pkg_version="${3}" # Unfortunately, bash does not support map or dictionary data structures. # The goal of map_dir is to simulate this data structure. Given a source # directory, it will map it to a target directory. # # Input: ${1} - the path of the source directory; the path cannot be absolute # but must be relative to the package's directory. # Result: the target directory if the source directory has a target, otherwise # an empty string. function map_dir () { dir_entries () { # target-point source-dir echo "${target_dir}/bin bin" echo "${target_dir}/bin jre/bin" echo "${target_dir}/bin usr/bin" echo "${target_dir}/bin usr/local/bin" echo "${target_dir}/sbin sbin" echo "${target_dir}/sbin usr/sbin" echo "${target_dir}/sbin usr/local/sbin" echo "${target_dir}/lib lib" echo "${target_dir}/lib jre/lib" echo "${target_dir}/lib usr/lib" echo "${target_dir}/lib usr/local/lib" echo "${target_dir}/lib lib64" echo "${target_dir}/lib usr/lib64" echo "${target_dir}/lib usr/local/lib64" echo "${target_dir}/usr/include include" echo "${target_dir}/usr/include usr/include" echo "${target_dir}/usr/include usr/local/include" echo "${target_dir}/usr/share share" echo "${target_dir}/usr/share usr/share" echo "${target_dir}/usr/share usr/local/share" echo "${target_dir}/usr/man man" echo "${target_dir}/usr/man usr/man" echo "${target_dir}/usr/man usr/share/man" echo "${target_dir}/usr/man usr/local/share/man" echo "${target_dir}/etc etc" echo "${target_dir}/var var" } ( dir_entries ) | while read mount_point source_dir; do if [ "${source_dir}" == "${1}" ]; then echo "${mount_point}" exit 0 fi done echo } function print_usage() { echo "Usage: ${0} " echo "Commands:" echo " list" echo " list all packages" echo " list package-name" echo " list versions of specified package" echo " load package-name [package-version]" echo " load a package" echo " unload package-name" echo " unload a package" echo " test package-name [package-version]" echo " dump mount points of a package" } # Find all the sub-directories in a package directory. The prefix of ./ is # stripped off from all sub-directory paths returned by find. # Input: ${1} - the package name # ${2} - the package version # Result: all of the sub-directories function find_dirs() { dir="${pkg_dir}/${1}/${2}/" cd ${dir} find . -maxdepth 3 -mindepth 1 -type d | sed 's/\.\///' } # Checks the variable ${pkg_name} to see if the package name exists. # It prints messages to standard error if the package is not found. # Input: ${pkg_name} - the name of the package. # Result: 0 if the package directory is found, 1 if not. function check_pkg_name() { if [ "${pkg_name}" == "" ]; then echo "No package was specified" >&2 exit 1 elif [ ! -d "${pkg_dir}/${pkg_name}" ]; then echo "Package \`${pkg_name}' does not exist" >&2 potential_pkg_names="" for potential_pkg_name in `${0} list`; do matches=`echo ${potential_pkg_name} | grep ${pkg_name}` if [ ! "${matches}" == "" ]; then potential_pkg_names="${matches} ${potential_pkg_names}" fi done if [ ! "${potential_pkg_names}" == "" ]; then echo "Possible packages are: ${potential_pkg_names}" >&2 fi exit 1 else exit 0 fi } # Checks the package version in order to determine if it is valid. # If ${pkg_version} is empty, the default package version is used instead. # Input: ${pkg_version} - the package version to check # Result: the package version to use. This can be different from the supplied # ${pkg_version} if it is an empty string. function check_pkg_version() { if [ "${pkg_version}" == "" ]; then cd "${pkg_dir}/${pkg_name}" for version in `ls -r`; do pkg_version=${version}; done if [ "${pkg_version}" == "" ]; then echo "No package versions are available for package \`${pkg_name}'" >&2 exit 1 else echo "No package version was specified for \`${pkg_name}'; defaulting to \`${pkg_version}'" >&2 fi else if [ ! -d "${pkg_dir}/${pkg_name}/${pkg_version}" ]; then echo "Version \`${pkg_version}' does not exist for package \`${pkg_name}'" >&2 echo -n "Available versions are: " >&2 ${0} list ${pkg_name} >&2 exit 1 fi fi echo "${pkg_version}" exit 0 } # Performs a supplied function on each directory returned by map_dir. # On each directory returned, the function will be called with the parameters: # ${1} set to the absolute path to the source directory, and ${2} set to # the path to the target directory. # Input: ${1} - the function name to execute # ${2} - the package name # ${3} - the package version # Result: 0 if the supplied function succeeded for each directory, 1 otherwise. function for_each_mapped_dir () { for dir in `( find_dirs ${2} ${3} )`; do dest=`( map_dir ${dir} )` if [ "${dest}" != "" ]; then ( "${1}" "${pkg_dir}/${2}/${3}/${dir}" "${dest}" ) if [ ! $? -eq 0 ]; then exit 1; fi fi done } case "${command}" in list) if [ "${pkg_name}" == "" ]; then cd ${pkg_dir} for pkg_name in *; do if [ -d ${pkg_dir}/${pkg_name} ]; then echo -n "${pkg_name} " cd ${pkg_name} for version in *; do echo -n "${version} " done echo cd .. fi done echo else ( check_pkg_name ); if [ ! $? -eq 0 ]; then exit 1; fi cd ${pkg_dir}/${pkg_name} for version in *; do echo -n "${version} " done echo fi ;; load) ( check_pkg_name ); if [ ! $? -eq 0 ]; then exit 1; fi pkg_version=`( check_pkg_version )`; if [ ! $? -eq 0 ]; then exit 1; fi do_load () { mount -n -t unionfs -o "remount,add=:${1}=rw" none "${2}" } ( for_each_mapped_dir "do_load" ${pkg_name} ${pkg_version} ) exit ${?} ;; unload) ( check_pkg_name ); if [ ! $? -eq 0 ]; then exit 1; fi pkg_version=`( check_pkg_version )`; if [ ! $? -eq 0 ]; then exit 1; fi do_unload () { mount -n -t unionfs -o "remount,del=${1}" none "${2}" } ( for_each_mapped_dir "do_unload" ${pkg_name} ${pkg_version} ) exit ${?} ;; test) ( check_pkg_name ); if [ ! $? -eq 0 ]; then exit 1; fi pkg_version=`( check_pkg_version )`; if [ ! $? -eq 0 ]; then exit 1; fi do_test () { echo ${2} \<== ${1} } ( for_each_mapped_dir "do_test" ${pkg_name} ${pkg_version} ) exit $? ;; *) if [ ! "${command}" == "" ]; then echo "Command \`${command}' not understood" fi ( print_usage ) exit 1 ;; esac