summaryrefslogtreecommitdiffstats
path: root/conf/postmulti-script
diff options
context:
space:
mode:
Diffstat (limited to 'conf/postmulti-script')
-rw-r--r--conf/postmulti-script312
1 files changed, 312 insertions, 0 deletions
diff --git a/conf/postmulti-script b/conf/postmulti-script
new file mode 100644
index 0000000..1b31755
--- /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_directory - 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 an independent 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 an independent 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