#!/bin/bash APP_SVNID='$HeadURL$ $LastChangedRevision$' . $(ade-config ade_share_prefix)/include/ade.sh || { echo "${0##*/}: INTERNAL ERROR: failed to load ade.sh" >&2; exit 3; } . <(pcms-config --format=shell) || { echo "$PROGNAME: INTERNAL ERROR: failed to run pcms-config" >&2; exit 3; } PCMS_DEFINED_ERRORS=( "KEY=PCMS_ERR_MISC; FMT=\"%s\"" ) # Other globals KNOWN_PCMS_PASS_NUMS="3,2,1,0" pcms() { local ERRSTACK_REF="$1"; shift local DIR VAR PROGNAME PKG FILE MAKEOPTS local RC TEE_STDOUT_PID TEE_STDERR_PID LOG_FILE SAVED_ARGS PLUGIN_NAME PLUGIN_DIR VERBOSELEVEL ########################################################################### # # SET ADE OPTIONS # ########################################################################### # Register application-specific errors ade_err_registerdefderrs PCMS_DEFINED_ERRORS # Uncomment this to enable displaying full error stacks. #ade_err_resetstack "$ERRSTACK_REF" dumpall=true # Uncomment and adjust this to change the default way messages are displayed. #ade_err_resetstack "$ERRSTACK_REF" writers="_ade_msg_writer_stderr _ade_msg_writer_logfile _ade_msg_writer_syslog _ade_msg_writer_null" # If you specified _ade_msg_writer_syslog above then you'll need to # uncomment and adjust these two too. #ade_err_resetstack "$ERRSTACK_REF" facility=user #ade_err_resetstack "$ERRSTACK_REF" priority=notice # If you specified _ade_msg_writer_logfile above then you'll need to # uncomment and adjust this too. #ade_err_resetstack "$ERRSTACK_REF" logfile=/var/log/pcms.log ########################################################################### # # PROCESS OPTIONS # ########################################################################### # Keep argument list for when we call ourselves. SAVED_ARGS=( "$@" ) # Defaults for normal options ade_app_get_progname "$ERRSTACK_REF" PROGNAME OPT_CONFIG_FILE=$PCMS_ETC_PREFIX/$PROGNAME.conf # Defaults for options that can be specified in the config file or the # command line options (though some lack implementation as command line # options) DFLT_SITE_CONFIG_FACILITY_MK= DFLT_SITE_CONFIG_MASTER_HOST_DERIVER_CMD= DFLT_SITE_CONFIG_UPDATER_CMD= DFLT_UPDATE_OS_FLAG=true DFLT_CLEANUP_FLAG=true DFLT_PLUGINS_FLAG=true DFLT_ENABLED_FLAG=true DFLT_MAKE_FLAG=true DFLT_UPDATE_SITE_CONFIG_FLAG=true DFLT_SITE_CONFIG_DIR=$PCMS_ETC_PREFIX/site-config DFLT_CONFIG_FILE=$PCMS_ETC_PREFIX/$PROGNAME.conf DFLT_PCMS_PASS_NUMS="3,2,1,0" # The values for command-line- or config-file-specified options are all # blank. After the config file is loaded we can work out where to source # still-unset values from. OPT_SITE_CONFIG_FACILITY_MK= OPT_SITE_CONFIG_MASTER_HOST_DERIVER_CMD= OPT_SITE_CONFIG_UPDATER_CMD= OPT_UPDATE_OS_FLAG= OPT_CLEANUP_FLAG= OPT_PLUGINS_FLAG= OPT_ENABLED_FLAG= OPT_MAKE_FLAG= OPT_UPDATE_SITE_CONFIG_FLAG= OPT_SITE_CONFIG_DIR= OPT_PCMS_PASS_NUMS= # Register pcms options ade_opt_register "$ERRSTACK_REF" --longoptions=passes:,update-os,no-update-os,update-site-config,no-update-site-config,cleanup,no-cleanup,plugins,no-plugins,make,no-make,site-config-dir,config-file --callback-template="pcms_opt_handler_%s" || return $? ade_msg_register "$ERRSTACK_REF" pcms_usage pcms_version pcms_listpaths || return $? # Process options ade_opt_process "$ERRSTACK_REF" NEW_DOLLAR_AT "$@" || return $? set -- "${NEW_DOLLAR_AT[@]}" # Sanity checks and derivations # We're probably running under cron. PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin if [ "X$OPT_CONFIG_FILE" = X ]; then ade_err_internal "$ERRSTACK_REF" "pcms: OPT_CONFIG_FILE got *unset* as a result of a command line option!" elif [ ! -f $OPT_CONFIG_FILE ]; then ade_err_debug "$ERRSTACK_REF" 10 "pcms: $OPT_CONFIG_FILE: no such file; no config will be loaded (this is not really an error in itself)" elif ! OPT_CONFIG_FILE_OUTPUT=$(bash -c ". $OPT_CONFIG_FILE 2>&1"); then ade_err_error "$ERRSTACK_REF" PCMS_ERR_MISC "$OPT_CONFIG_FILE: not loadable (hint: do you have a syntax error in it?)" return $ADE_ERR_FAIL else ade_err_debug "$ERRSTACK_REF" 10 "pcms: $OPT_CONFIG_FILE: loading config ..." . $OPT_CONFIG_FILE fi # We pass on our verbosity to various pcms-provided scripts we call. ade_msg_get_verboselevel "$ERRSTACK_REF" VERBOSELEVEL || return $? # Merge commandline-specified, configfile-specified and default values into *non-OPT/DFLT-prefixed var. VARS=( ENABLED_FLAG PCMS_PASS_NUMS SITE_CONFIG_FACILITY_MK SITE_CONFIG_MASTER_HOST_DERIVER_CMD SITE_CONFIG_UPDATER_CMD UPDATE_OS_FLAG CLEANUP_FLAG PLUGINS_FLAG MAKE_FLAG UPDATE_SITE_CONFIG_FLAG SITE_CONFIG_DIR CONFIG_FILE ) for VAR in "${VARS[@]}"; do # If a variable was set via a command line option then use that. if eval "[ \"X\$OPT_$VAR\" != X ]"; then ade_err_debug "$ERRSTACK_REF" 10 "pcms: $VAR: set via command-line option" eval "$VAR=\"\$OPT_$VAR\"" # If set via config file then use that value. elif eval "[ \"X\$$VAR\" != X ]"; then ade_err_debug "$ERRSTACK_REF" 10 "pcms: $VAR: set via config file" # If not set on command line or config file then use default. else ade_err_debug "$ERRSTACK_REF" 10 "pcms: $VAR: not set; defaulting ..." eval "$VAR=\"\$DFLT_$VAR\"" fi done ade_err_debug "$ERRSTACK_REF" 10 "pcms: PCMS_PASS_NUMS=$PCMS_PASS_NUMS" # Check all options/config params are now set. Some of these have empty defaults and some don't # but, after loading the config file, the user could have blanked any of them, so we need to # check they *all* have values. We split this into two parts because if ENABLED_FLAG is false # the the rest are irrelevant. ade_err_debug "$ERRSTACK_REF" 10 "pcms: checking all configuration variables set (part #1) ..." for VAR in "${VARS[@]}"; do [ $VAR = ENABLED_FLAG ] || continue if eval "[ \"X\$$VAR\" = X ]"; then ade_err_error "$ERRSTACK_REF" PCMS_ERR_MISC "$VAR: not set" return $ADE_ERR_FAIL fi done # If not enabled then exit *before* checking if other directories/settings/etc are correct. $ENABLED_FLAG || return $ADE_ERR_OK ade_err_debug "$ERRSTACK_REF" 10 "pcms: checking all configuration variables set (part #2) ..." for VAR in "${VARS[@]}"; do [ $VAR != ENABLED_FLAG ] || continue if eval "[ \"X\$$VAR\" = X ]"; then ade_err_error "$ERRSTACK_REF" PCMS_ERR_MISC "$VAR: not set (hint: define either in $CONFIG_FILE or by suitable command-line option)" return $ADE_ERR_FAIL fi done # Expand placeholders in configuration values ade_err_debug "$ERRSTACK_REF" 10 "pcms: replacing placeholders in configuration values ..." for VAR in SITE_CONFIG_UPDATER_CMD SITE_CONFIG_MASTER_HOST_DERIVER_CMD SITE_CONFIG_FACILITY_MK; do for PLACEHOLDER_CORE in SITE_CONFIG_DIR; do ade_err_debug "$ERRSTACK_REF" 10 "pcms: replacing placeholder '$PLACEHOLDER_CORE' in configuration variable $VAR ..." eval "{ ! [[ \$$VAR =~ %\\{$PLACEHOLDER_CORE\\} ]]; } || $VAR=\${$VAR//\\%\\{$PLACEHOLDER_CORE\\}/\$$PLACEHOLDER_CORE}" done done # Derive site-config master host ade_err_debug "$ERRSTACK_REF" 10 "pcms: deriving SITE_CONFIG_MASTER_HOST from SITE_CONFIG_MASTER_HOST_DERIVER_CMD ($SITE_CONFIG_MASTER_HOST_DERIVER_CMD) ..." if ! SITE_CONFIG_MASTER_HOST=$(eval "$SITE_CONFIG_MASTER_HOST_DERIVER_CMD"); then ade_err_error "$ERRSTACK_REF" PCMS_ERR_MISC "failed to derive the config master host (hint: see error messages above)" return $ADE_ERR_FAIL fi [[ $PCMS_PASS_NUMS =~ ^[0-3](,[0-3]){0,}$ ]] || ade_msg_usage "$ERRSTACK_REF" for DIR in $PCMS_SHARE_PREFIX/{scripts,makefiles}; do [ -d $DIR ] || ade_err_internal "$ERRSTACK_REF" "$DIR: no such directory (hint: is PCMS properly installed?)" done for DIR in $SITE_CONFIG_DIR{,/makefiles,/files}; do if [ ! -d $DIR ]; then ade_err_error "$ERRSTACK_REF" PCMS_ERR_MISC "$DIR: no such directory (hint: is SITE_CONFIG_DIR set wrongly in $CONFIG_FILE?)" return $ADE_ERR_FAIL fi done PATH=$SITE_CONFIG_DIR/scripts:$PCMS_SHARE_PREFIX/scripts:$PATH FILESPATH=$SITE_CONFIG_DIR/hosts/$(uname -n)/files:$SITE_CONFIG_DIR/files:$PCMS_SHARE_PREFIX/files:$PCMS_STATE_PREFIX/generated-files KEYSPATH=$SITE_CONFIG_DIR/hosts/$(uname -n)/keys:$SITE_CONFIG_DIR/keys:$PCMS_SHARE_PREFIX/keys GENERATORSPATH=$SITE_CONFIG_DIR/hosts/$(uname -n)/generators:$SITE_CONFIG_DIR/generators:$PCMS_SHARE_PREFIX/generators # If SITE_CONFIG_FACILITY_MK ends with pipe then we'll run it rather than copying it. # The space in '${X: -1}' is necessary to avoid confusion with '${X:-defaultvalue}'. if [ "X${SITE_CONFIG_FACILITY_MK: -1}" != "X|" ]; then SITE_CONFIG_FACILITY_MK_IS_EXECUTABLE_FLAG=false else SITE_CONFIG_FACILITY_MK_IS_EXECUTABLE_FLAG=true SITE_CONFIG_FACILITY_MK=${SITE_CONFIG_FACILITY_MK::-1} fi if { ! $SITE_CONFIG_FACILITY_MK_IS_EXECUTABLE_FLAG; } && [ ! -f $SITE_CONFIG_FACILITY_MK ]; then ade_err_error "$ERRSTACK_REF" PCMS_ERR_MISC "$SITE_CONFIG_FACILITY_MK: not accessible (hint: sorry, no hint available)" return $ADE_ERR_FAIL fi # Lock if ! ${PCMS_LOCKING_DONE_ALREADY_FLAG:-false}; then ade_lck_lock_simple "$ERRSTACK_REF" $PCMS_LOCK_PREFIX/$PROGNAME.pid || { RC=$? ade_err_error "$ERRSTACK_REF" PCMS_ERR_MISC "locking failed" return $RC } fi # If not running under the logging wrapper already then run under the logging wrapper. if ! ${PCMS_RUNNING_UNDER_LOGGING_WRAPPER_FLAG:-false}; then # Save file handles 1 and 2 to 3 and 4 exec 3>&1 exec 4>&2 [ -d $PCMS_LOG_PREFIX ] || mkdir -p $PCMS_LOG_PREFIX LOG_FILE=$PCMS_LOG_PREFIX/$PROGNAME.log # Any write to stdout should go to tee, which can write it to the log file *and* to stdout. exec > >(exec tee -ia $LOG_FILE) TEE_STDOUT_PID=$! # Any write to stderr should go to tee, which can write it to the log file *and* to stderr. exec 2> >(exec tee -ia $LOG_FILE >&2) TEE_STDERR_PID=$! # Log a header line directly to the logs, not to stdout/sterr. { echo "-------------------------------------------------------------------------------" pcms_version "$ERRSTACK_REF" VERSION echo "$PROGNAME version $VERSION started at $(date) with pid $$" } >> $LOG_FILE # Do the real stuff. We could just call main() here but the problem with that # is that any exits that the script make will not result in it coming back here, # whereas if we really call ourselves as a new process then it won't matter. RC=0; PCMS_LOCKING_DONE_ALREADY_FLAG=true PCMS_RUNNING_UNDER_LOGGING_WRAPPER_FLAG=true $0 "${SAVED_ARGS[@]}" || RC=$? # Restore the file handles. I think this should result in the tee getting EOF, # or possibly in the shell killing it? Anyway, a few moments later the processes # will have exited. exec 1>&3 exec 2>&4 # Close the ones we saved them to 3<&- 4<&- # Even though restoring the file handles to their originals should terminate the # tees, they may not have exited by the time we get to the end of the script, so # we must wait. wait $TEE_STDOUT_PID $TEE_STDERR_PID 2>/dev/null || true return $RC fi # Update site config. if ! $UPDATE_SITE_CONFIG_FLAG; then ade_err_warning "$ERRSTACK_REF" PCMS_ERR_MISC "not updating site-config" elif ! netreach --debug=$VERBOSELEVEL $SITE_CONFIG_MASTER_HOST; then ade_err_warning "$ERRSTACK_REF" PCMS_ERR_MISC "not updating site-config due to network problems" else ade_err_info "$ERRSTACK_REF" "updating site-config ..." eval "$SITE_CONFIG_UPDATER_CMD" fi # Upgrade OS. if ! $UPDATE_OS_FLAG; then ade_err_warning "$ERRSTACK_REF" PCMS_ERR_MISC "not updating OS" elif ! netreach --debug=$VERBOSELEVEL repos; then ade_err_warning "$ERRSTACK_REF" PCMS_ERR_MISC "not updating OS due to network problems" else ade_err_info "$ERRSTACK_REF" "updating OS ..." package --debug=$VERBOSELEVEL update package --debug=$VERBOSELEVEL dist-upgrade fi # Run make. if ! $MAKE_FLAG; then ade_err_warning "$ERRSTACK_REF" PCMS_ERR_MISC "not running make" else [ -d $PCMS_STATE_PREFIX/timestamps ] || mkdir -p $PCMS_STATE_PREFIX/timestamps cd $PCMS_STATE_PREFIX/timestamps # We do two passes. The main reason for this is that make needs it (the first pass generates # some makefiles, the second - which we name the zeroth to avoid renumbering if I decide # we need a third pass). But we can take advantage of the passes and update the working # copy of the config module only on the first pass. ade_err_debug "$ERRSTACK_REF" 10 "pcms: PCMS_PASS_NUMS=$PCMS_PASS_NUMS" # Don't go willy-nilly including old stuff. rm -fr $PCMS_STATE_PREFIX/makefiles FIRST_LOOP_FLAG=true for PCMS_PASS_NUM in ${PCMS_PASS_NUMS//,/ }; do MATCH=false for KNOWN_PCMS_PASS_NUM in ${KNOWN_PCMS_PASS_NUMS//,/ }; do [ $KNOWN_PCMS_PASS_NUM != $PCMS_PASS_NUM ] || { MATCH=true; break; } done $MATCH || continue ade_err_info "$ERRSTACK_REF" "running make pass #$PCMS_PASS_NUM ..." # First loop only (whatever pass number that is), we generate facility-local.mk. if $FIRST_LOOP_FLAG; then # Create facility-local.mk, which is included by the main makefile. It has to be # done after the configuration (in /etc/pcms?) has been updated. It makes most sense # to do it in the earliest-run pass, so that all passes have access to it. ade_err_debug "$ERRSTACK_REF" 10 "pcms: generating settings.mk ..." mkdir -p $PCMS_STATE_PREFIX/makefiles if ! $SITE_CONFIG_FACILITY_MK_IS_EXECUTABLE_FLAG; then cat $SITE_CONFIG_FACILITY_MK > $PCMS_STATE_PREFIX/makefiles/facility-local.mk elif ! eval "PCMS_VERBOSELEVEL=$VERBOSELEVEL $SITE_CONFIG_FACILITY_MK > $PCMS_STATE_PREFIX/makefiles/facility-local.mk"; then ade_err_error "$ERRSTACK_REF" PCMS_ERR_MISC "failed to run '$SITE_CONFIG_FACILITY_MK' (hint: see error messages above)" return $ADE_ERR_FAIL fi FIRST_LOOP_FLAG=false fi # In passes 3, 2 and 1 we make everything, regardless of whether the # user specified '-n' or not. That is because we're making makefiles, not real targets. if [ $PCMS_PASS_NUM != 0 ]; then # Note we don't pass our commandline arguments (i.e. what to make) to make because we don't want # the level-0 make to make anything except its default. Instead we put the commandline arguments # in a make variable and the level-0 make will append them to the level-1 make's argument list. MAKE_ARGUMENTS=( ) # In the last pass (numbered '0' 'cos we're counting down in order to be able to add # earlier-run passes in the future without affecting existing numbering), we honour the # options (e.g. '-n', '-t', '') that the user specified. elif [ $PCMS_PASS_NUM = 0 ]; then MAKE_ARGUMENTS=( "$@" ) fi # Call make. Could add -s, -k, -j. MAKEOPTS="--no-print-directory --no-builtin-rules -I $SITE_CONFIG_DIR/makefiles/facilities -I $PCMS_SHARE_PREFIX/makefiles/facilities -I $SITE_CONFIG_DIR/makefiles/files -I $PCMS_SHARE_PREFIX/makefiles/files -I $SITE_CONFIG_DIR/makefiles/methods -I $PCMS_SHARE_PREFIX/makefiles/methods -f $PCMS_SHARE_PREFIX/makefiles/Makefile" if [ $VERBOSELEVEL -le 3 ]; then MAKEOPTS+=" -s" fi MAKECMD=make # Most of these are *not* PCMS_-prefixed, but that is okay, # because these are make *arguments*, not environment settings. VARIABLE_MAKEARGS="PCMS_SHARE_PREFIX=$PCMS_SHARE_PREFIX SITE_CONFIG_DIR=$SITE_CONFIG_DIR PCMS_STATE_PREFIX=$PCMS_STATE_PREFIX PCMS_LOG_PREFIX=$PCMS_LOG_PREFIX FILESPATH=$FILESPATH GENERATORSPATH=$GENERATORSPATH KEYSPATH=$KEYSPATH VERBOSELEVEL=$VERBOSELEVEL PROGNAME=$PROGNAME PCMS_PASS_NUM=$PCMS_PASS_NUM" ade_err_debug "$ERRSTACK_REF" 10 "pcms: calling [$MAKECMD $MAKEOPTS $VARIABLE_MAKEARGS ${MAKE_ARGUMENTS[*]}] ..." if ! $MAKECMD $MAKEOPTS $VARIABLE_MAKEARGS "${MAKE_ARGUMENTS[@]}"; then ade_err_error "$ERRSTACK_REF" PCMS_ERR_MISC "make failed (hint: see messages above)" return $ADE_ERR_FAIL fi done # Clean up { ! $CLEANUP_FLAG; } || rm -fr $PCMS_STATE_PREFIX/makefiles fi if $UPDATE_OS_FLAG; then ade_err_info "$ERRSTACK_REF" "removing obsolete packages ..." package --debug=$VERBOSELEVEL autoremove || true fi if ! $PLUGINS_FLAG; then ade_err_warning "$ERRSTACK_REF" PCMS_ERR_MISC "not running plugins" else ade_err_info "$ERRSTACK_REF" "running plugins ..." # This is an priority-first order list of directories that can contain # plugins. PLUGIN_DIRS=( $SITE_CONFIG_DIR/hosts/$(uname -n)/plugins $SITE_CONFIG_DIR/plugins $PCMS_SHARE_PREFIX/hosts/$(uname -n)/plugins $PCMS_SHARE_PREFIX/plugins ) # Get a unique list of plugins readarray -t PLUGIN_NAMES < <(find "${PLUGIN_DIRS[@]}" -mindepth 1 -maxdepth 1 -type f 2>/dev/null | sed 's@.*/@@' | sort -u) # Identify which of each unique plugin name we'll run (i.e. if # plugin 'X' exists in multiple of the directories in $PLUGIN_DIRS, # then which version of it do we run?) and run it. for PLUGIN_NAME in "${PLUGIN_NAMES[@]}"; do for PLUGIN_DIR in "${PLUGIN_DIRS[@]}"; do if [ -x $PLUGIN_DIR/$PLUGIN_NAME ]; then ade_err_debug "$ERRSTACK_REF" 10 "pcms: calling [$PLUGIN_DIR/$PLUGIN_NAME] ..." # We ignore the return code of plugins. $PLUGIN_DIR/$PLUGIN_NAME --debug=$VERBOSELEVEL || true break fi done done fi # Unlock if ! ${PCMS_LOCKING_DONE_ALREADY_FLAG:-false}; then ade_lck_unlock_simple "$ERRSTACK_REF" $PCMS_LOCK_PREFIX/$PROGNAME.pid fi return $ADE_ERR_OK } pcms_opt_handler_passes() { local ERRSTACK_REF="$1"; shift OPT_PCMS_PASS_NUMS="$1" ade_err_debug "$ERRSTACK_REF" 10 "pcms_opt_handler_passes: OPT_PCMS_PASS_NUMS=$OPT_PCMS_PASS_NUMS" return $ADE_ERR_OK } pcms_opt_handler_update_os() { local ERRSTACK_REF="$1"; shift OPT_UPDATE_OS_FLAG=true return $ADE_ERR_OK } pcms_opt_handler_no_update_os() { local ERRSTACK_REF="$1"; shift OPT_UPDATE_OS_FLAG=false return $ADE_ERR_OK } pcms_opt_handler_update_site_config() { local ERRSTACK_REF="$1"; shift OPT_UPDATE_SITE_CONFIG_FLAG=true return $ADE_ERR_OK } pcms_opt_handler_no_update_site_config() { local ERRSTACK_REF="$1"; shift OPT_UPDATE_SITE_CONFIG_FLAG=false return $ADE_ERR_OK } pcms_opt_handler_cleanup() { local ERRSTACK_REF="$1"; shift OPT_CLEANUP_FLAG=true return $ADE_ERR_OK } pcms_opt_handler_no_cleanup() { local ERRSTACK_REF="$1"; shift OPT_CLEANUP_FLAG=false return $ADE_ERR_OK } pcms_opt_handler_plugins() { local ERRSTACK_REF="$1"; shift OPT_PLUGINS_FLAG=true return $ADE_ERR_OK } pcms_opt_handler_no_plugins() { local ERRSTACK_REF="$1"; shift OPT_PLUGINS_FLAG=false return $ADE_ERR_OK } pcms_opt_handler_make() { local ERRSTACK_REF="$1"; shift OPT_MAKE_FLAG=true return $ADE_ERR_OK } pcms_opt_handler_no_make() { local ERRSTACK_REF="$1"; shift OPT_MAKE_FLAG=false return $ADE_ERR_OK } pcms_opt_handler_site_config_dir() { local ERRSTACK_REF="$1"; shift OPT_SITE_CONFIG_DIR="$1" return $ADE_ERR_OK } pcms_opt_handler_config_file() { local ERRSTACK_REF="$1"; shift OPT_CONFIG_FILE="$1" return $ADE_ERR_OK } pcms_usage() { local ERRSTACK_REF="$1"; shift local USAGETEXT_REF="$1"; shift local PASSNO=$1; shift if [ $PASSNO = 1 ]; then eval "$USAGETEXT_REF=\"[ -- [ ] [ ... ] ]\"" elif [ $PASSNO = 2 ]; then eval "$USAGETEXT_REF=\"\ --update-os update OS --no-update-os don't update OS --update-site-config update site-config --no-update-site-config don't update site-config --make run make --no-make don't run make --passes=[,...] run specified make passes --cleanup clean up afterwards --no-cleanup don't clean up afterwards --plugins run plugins --no-plugins don't run plugins --config-file= use specific config file --site-config-dir= use specific site-config\"" # The last two options there can't have their defaults displayed, because # they are worked out only after commandline options have been processed. fi return $ADE_ERR_OK } pcms_listpaths() { local ERRSTACK_REF="$1"; shift local PATHLIST_REF=$1; shift eval "$PATHLIST_REF=\"\"" return $ADE_ERR_OK } pcms_version() { local ERRSTACK_REF="$1"; shift local VERSION_REF=$1; shift ade_smf_extractversionfromsvnstring "$ERRSTACK_REF" "$APP_SVNID" "$VERSION_REF" return $ADE_ERR_OK } ade_gep_main pcms "$@"