diff options
Diffstat (limited to 'conf/postmulti-script')
-rw-r--r-- | conf/postmulti-script | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/conf/postmulti-script b/conf/postmulti-script new file mode 100644 index 0000000..b1aea8e --- /dev/null +++ b/conf/postmulti-script @@ -0,0 +1,312 @@ +#! /bin/sh + +umask 022 + +# postmulti(1) contract: +# +# Arguments: +# postmulti-script -e <edit_command> +# +# Environment: +# +# All actions: +# +# MAIL_CONFIG - config_directory of primary instance +# command_directory - From primary instance +# daemon_directory - From primary instance +# meta_directory - From primary instance +# shlib_directory - From primary instance +# config_directroy - config_directory of target instance +# queue_directory - queue_directory of target instance +# data_directory - data_directory of target instance +# +# Create, destroy, import and deport: +# +# multi_instance_directories - New value for primary instance +# +# Create, import and assign (unset == nochange, "-" == clear): +# +# multi_instance_group - New value for target instance +# multi_instance_name - New value for target instance + +: ${MAIL_CONFIG:?"do not invoke this command directly"} +: ${command_directory:?"do not invoke this command directly"} +: ${daemon_directory:?"do not invoke this command directly"} +: ${meta_directory:?"do not invoke this command directly"} +: ${shlib_directory:?"do not invoke this command directly"} + +USAGE="$0 -e create|destroy|import|deport|enable|disable|assign|init" +usage() { echo "$0: Error: Usage: $USAGE" >&2; exit 1; } + +TAG="$MAIL_LOGTAG/postmulti-script" +fatal() { postlog -p fatal -t "$TAG" "$1"; exit 1; } + +# args: add|del $dir +# +update_cfdirs() { + op=$1 + dir=$2 + + alt=`postconf -h alternate_config_directories` || return 1 + + shift $# # Needed on SunOS where bare "set --" is NOP! + IFS="$IFS,"; set -- $alt; IFS="$BACKUP_IFS" + keep= + found= + # Portability: SunOS "sh" needs 'in "$@"' for one-line for-loop. + for d in "$@"; do [ "$d" = "$dir" ] && found=1 || keep="$keep $d"; done + + set -- "multi_instance_directories = $multi_instance_directories" + + case $op in + add) test -n "$found" || + set -- "$@" "alternate_config_directories =$keep $dir";; + del) test -n "$found" && + set -- "$@" "alternate_config_directories =$keep";; + *) return 1;; # XXX: Internal error + esac + postconf -e "$@" || return 1 +} + +assign_names() { + # Set the instance name and group + # + test -n "$multi_instance_name" && { + test "$multi_instance_name" = "-" && multi_instance_name= + set -- "$@" "multi_instance_name = $multi_instance_name" + } + test -n "$multi_instance_group" && { + test "$multi_instance_group" = "-" && multi_instance_group= + set -- "$@" "multi_instance_group = $multi_instance_group" + } + test $# -eq 0 || postconf -c "$config_directory" -e "$@" || return 1 +} + +# Process command-line options and parameter settings. Work around +# brain damaged shells. "IFS=value command" should not make the +# IFS=value setting permanent. But some broken standard allows it. + +BACKUP_IFS="$IFS" +action= + +while getopts ":e:" opt +do + case $opt in + e) action="$OPTARG";; + *) usage;; + esac +done +shift `expr $OPTIND - 1` + +# Check for valid action and required instance name +case "$action" in + create|import|destroy|deport|enable|disable|assign|init) ;; + *) usage;; +esac +test $# -eq 0 || usage + +case $action in +init) + postconf -e \ + 'multi_instance_wrapper = ${command_directory}/postmulti -p --' \ + 'multi_instance_enable = yes' + exit $? ;; +esac + +# Backport note: "-x" requires 2.10 or later, and is not essential here. +# +wrapper=`postconf -hx multi_instance_wrapper` || exit 1 +enable=`postconf -hx multi_instance_enable` || exit 1 + +test -n "$wrapper" || + fatal "multi_instance_wrapper is empty, run 'postmulti -e init' first." + +test "$enable" = "yes" || + fatal "multi_instance_enable!=yes, run 'postmulti -e init' first." + +: ${config_directory:?"Invalid empty target instance config_directory"} + +case $action in +create|import) + + # Atomically install stock main.cf/master.cf files. We install the + # master.cf file last. Once it is present the instance is complete. + # + test -f $config_directory/main.cf -a \ + -f $config_directory/master.cf || { + + test "$action" = "create" || { + test -f $config_directory/main.cf || + fatal "'$config_directory' lacks a main.cf file" + test -f $config_directory/master.cf || + fatal "'$config_directory' lacks a master.cf file" + } + + test -f $meta_directory/main.cf.proto || + fatal "Missing main.cf prototype: $meta_directory/main.cf.proto" + test -f $meta_directory/master.cf.proto || + fatal "Missing master.cf prototype: $meta_directory/master.cf.proto" + + # Create instance-specific directories + # + test -d $config_directory || + { (umask 022; mkdir -p $config_directory) || exit 1; } + test -d $queue_directory || + { (umask 022; mkdir -p $queue_directory) || exit 1; } + test -d $data_directory || + { (umask 077; mkdir -p $data_directory) || exit 1; } + + tmpdir=$config_directory/.tmp + (umask 077; mkdir -p $tmpdir) || exit 1 + cp -p $meta_directory/main.cf.proto $tmpdir/main.cf || exit 1 + + # Shared install parameters are cloned from user-specified values in + # the default instance, but only if explicitly set there. Otherwise, + # they are commented out in the new main.cf file. + # + SHARED_PARAMETERS=" + command_directory + daemon_directory + meta_directory + mail_owner + setgid_group + sendmail_path + mailq_path + newaliases_path + html_directory + manpage_directory + sample_directory + readme_directory + shlib_directory + " + + shift $# # Needed on SunOS where bare "set --" is NOP! + comment_out= + for p in $SHARED_PARAMETERS; do + val=`postconf -nh $p` || exit 1 + test -n "$val" && { set -- "$@" "$p = $val"; continue; } + comment_out="$comment_out $p" + done + + # First comment-out any parameters that take default values + test -n "$comment_out" && { + postconf -c $tmpdir -# $comment_out || exit 1 + } + + # Now add instance-specific and non-default values. + # By default, disable inet services and local submission + # in new instances + # + postconf -c $tmpdir -e \ + "queue_directory = $queue_directory" \ + "data_directory = $data_directory" \ + "authorized_submit_users =" \ + "master_service_disable = inet" \ + "$@" || exit 1 + + + cp -p $meta_directory/master.cf.proto $tmpdir/master.cf || exit 1 + mv $tmpdir/main.cf $config_directory/main.cf || exit 1 + mv $tmpdir/master.cf $config_directory/master.cf || exit 1 + rmdir $tmpdir 2>/dev/null + } + + # Set instance name and group + # + assign_names || exit 1 + + # Update multi_instance_directories + # and drop from alternate_config_directories + # + # XXX: Must happen before set-permissions below, otherwise instance + # is treated as a non-slave instance by post-install via postfix(1). + # + update_cfdirs del $config_directory || exit 1 + + # Update permissions of private files. Verifies existence of + # queue_directory and data_directory, ... + # + # XXX: Must happen after instance list updates above, otherwise instance + # is treated as a non-slave instance by post-install via postfix(1). + # + postfix -c $config_directory set-permissions || exit 1 + ;; + +deport) + # Deporting an already deleted instance? + # + [ -f "$config_directory/main.cf" ] || { + update_cfdirs del $config_directory + exit $? + } + + postfix -c "$config_directory" status >/dev/null 2>&1 && + fatal "Instance '$config_directory' is not stopped" + + # Update multi_instance_directories + # and add to alternate_config_directories + # + update_cfdirs add $config_directory || exit 1 + ;; + +destroy) + + # "postmulti -e destroy" will remove an entire instance only when + # invoked immediately after "postmulti -e create" (i.e. before + # other files are added to the instance). We delete only known + # safe names without "/". + # + QUEUE_SUBDIRS="active bounce corrupt defer deferred flush hold \ + incoming maildrop pid private public saved trace" + #DEBUG=echo + WARN="postlog -p warn -t $TAG" + + # Locate the target instance + # + [ -f "$config_directory/main.cf" ] || + fatal "$config_directory/main.cf file not found" + + postfix -c "$config_directory" status >/dev/null 2>&1 && + fatal "Instance '$config_directory' is not stopped" + + # Update multi_instance directories + # and also (just in case) drop from alternate_config_directories + # + $DEBUG update_cfdirs del "$config_directory" || exit 1 + + # XXX: Internal "postfix /some/cmd" interface. + # + postfix -c "$config_directory" /bin/sh -c " + for q in $QUEUE_SUBDIRS + do + $DEBUG rmdir -- \$q || + $WARN \`pwd\`/\$q: please verify contents and remove by hand + done + " + + postfix -c "$config_directory" /bin/sh -c " + for dir in \$data_directory \$queue_directory + do + $DEBUG rmdir -- \$dir || + $WARN \$dir: please verify contents and remove by hand + done + " + + # In the configuration directory remove just the main.cf and master.cf + # files. + $DEBUG rm -f -- "$config_directory/master.cf" "$config_directory/main.cf" 2>/dev/null + $DEBUG rmdir -- "$config_directory" || + $WARN $config_directory: please verify contents and remove by hand + ;; + +enable) + postconf -c "$config_directory" -e \ + "multi_instance_enable = yes" || exit 1;; +disable) + postconf -c "$config_directory" -e \ + "multi_instance_enable = no" || exit 1;; +assign) + assign_names || exit 1;; +esac + +exit 0 |