1#! /bin/sh 2# $NetBSD: postmulti-script,v 1.1.1.2 2009/08/31 17:53:37 tron Exp $ 3# 4 5umask 022 6 7# postmulti(1) contract: 8# 9# Arguments: 10# postmulti-script -e <edit_command> 11# 12# Environment: 13# 14# All actions: 15# 16# MAIL_CONFIG - config_directory of primary instance 17# command_directory - From primary instance 18# daemon_directory - From primary instance 19# config_directroy - config_directory of target instance 20# queue_directory - queue_directory of target instance 21# data_directory - data_directory of target instance 22# 23# Create, destroy, import and deport: 24# 25# multi_instance_directories - New value for primary instance 26# 27# Create, import and assign (unset == nochange, "-" == clear): 28# 29# multi_instance_group - New value for target instance 30# multi_instance_name - New value for target instance 31 32: ${MAIL_CONFIG:?"do not invoke this command directly"} 33: ${command_directory:?"do not invoke this command directly"} 34: ${daemon_directory:?"do not invoke this command directly"} 35 36USAGE="$0 -e create|destroy|import|deport|enable|disable|assign|init" 37usage() { echo "$0: Error: Usage: $USAGE" >&2; exit 1; } 38 39TAG="$MAIL_LOGTAG/postmulti-script" 40fatal() { postlog -p fatal -t "$TAG" "$1"; exit 1; } 41 42# args: add|del $dir 43# 44update_cfdirs() { 45 op=$1 46 dir=$2 47 48 alt=`postconf -h alternate_config_directories` || return 1 49 50 shift $# # Needed on SunOS where bare "set --" is NOP! 51 IFS="$IFS,"; set -- $alt; IFS="$BACKUP_IFS" 52 keep= 53 found= 54 # Portability: SunOS "sh" needs 'in "$@"' for one-line for-loop. 55 for d in "$@"; do [ "$d" = "$dir" ] && found=1 || keep="$keep $d"; done 56 57 set -- "multi_instance_directories = $multi_instance_directories" 58 59 case $op in 60 add) test -n "$found" || 61 set -- "$@" "alternate_config_directories =$keep $dir";; 62 del) test -n "$found" && 63 set -- "$@" "alternate_config_directories =$keep";; 64 *) return 1;; # XXX: Internal error 65 esac 66 postconf -e "$@" || return 1 67} 68 69assign_names() { 70 # Set the instance name and group 71 # 72 test -n "$multi_instance_name" && { 73 test "$multi_instance_name" = "-" && multi_instance_name= 74 set -- "$@" "multi_instance_name = $multi_instance_name" 75 } 76 test -n "$multi_instance_group" && { 77 test "$multi_instance_group" = "-" && multi_instance_group= 78 set -- "$@" "multi_instance_group = $multi_instance_group" 79 } 80 test $# -eq 0 || postconf -c "$config_directory" -e "$@" || return 1 81} 82 83# Process command-line options and parameter settings. Work around 84# brain damaged shells. "IFS=value command" should not make the 85# IFS=value setting permanent. But some broken standard allows it. 86 87BACKUP_IFS="$IFS" 88action= 89 90while getopts ":e:" opt 91do 92 case $opt in 93 e) action="$OPTARG";; 94 *) usage;; 95 esac 96done 97shift `expr $OPTIND - 1` 98 99# Check for valid action and required instance name 100case "$action" in 101 create|import|destroy|deport|enable|disable|assign|init) ;; 102 *) usage;; 103esac 104test $# -eq 0 || usage 105 106case $action in 107init) 108 postconf -e \ 109 'multi_instance_wrapper = ${command_directory}/postmulti -p --' \ 110 'multi_instance_enable = yes' 111 exit $? ;; 112esac 113 114: ${config_directory:?"Invalid empty target instance config_directory"} 115 116case $action in 117create|import) 118 119 # Atomically install stock main.cf/master.cf files. We install the 120 # master.cf file last. Once it is present the instance is complete. 121 # 122 test -f $config_directory/main.cf -a \ 123 -f $config_directory/master.cf || { 124 125 test "$action" = "create" || { 126 test -f $config_directory/main.cf || 127 fatal "'$config_directory' lacks a main.cf file" 128 test -f $config_directory/master.cf || 129 fatal "'$config_directory' lacks a master.cf file" 130 } 131 132 # Create instance-specific directories 133 # 134 test -d $config_directory || 135 { (umask 022; mkdir -p $config_directory) || exit 1; } 136 test -d $queue_directory || 137 { (umask 022; mkdir -p $queue_directory) || exit 1; } 138 test -d $data_directory || 139 { (umask 077; mkdir -p $data_directory) || exit 1; } 140 141 tmpdir=$config_directory/.tmp 142 (umask 077; mkdir -p $tmpdir) || exit 1 143 cp -p $daemon_directory/main.cf $tmpdir/main.cf || exit 1 144 145 # Shared install parameters are cloned from user-specified values in 146 # the default instance, but only if explicitly set there. Otherwise, 147 # they are commented out in the new main.cf file. 148 # 149 SHARED_PARAMETERS=" 150 command_directory 151 daemon_directory 152 mail_owner 153 setgid_group 154 sendmail_path 155 mailq_path 156 newaliases_path 157 html_directory 158 manpage_directory 159 sample_directory 160 readme_directory 161 " 162 163 shift $# # Needed on SunOS where bare "set --" is NOP! 164 comment_out= 165 for p in $SHARED_PARAMETERS; do 166 val=`postconf -nh $p` || exit 1 167 test -n "$val" && { set -- "$@" "$p = $val"; continue; } 168 comment_out="$comment_out $p" 169 done 170 171 # First comment-out any parameters that take default values 172 test -n "$comment_out" && { 173 postconf -c $tmpdir -# $comment_out || exit 1 174 } 175 176 # Now add instance-specific and non-default values. 177 # By default, disable inet services and local submission 178 # in new instances 179 # 180 postconf -c $tmpdir -e \ 181 "queue_directory = $queue_directory" \ 182 "data_directory = $data_directory" \ 183 "authorized_submit_users =" \ 184 "master_service_disable = inet" \ 185 "$@" || exit 1 186 187 188 cp -p $daemon_directory/master.cf $tmpdir/master.cf || exit 1 189 mv $tmpdir/main.cf $config_directory/main.cf || exit 1 190 mv $tmpdir/master.cf $config_directory/master.cf || exit 1 191 rmdir $tmpdir 2>/dev/null 192 } 193 194 # Set instance name and group 195 # 196 assign_names || exit 1 197 198 # Update multi_instance_directories 199 # and drop from alternate_config_directories 200 # 201 # XXX: Must happen before set-permissions below, otherwise instance 202 # is treated as a non-slave instance by post-install via postfix(1). 203 # 204 update_cfdirs del $config_directory || exit 1 205 206 # Update permissions of private files. Verifies existence of 207 # queue_directory and data_directory, ... 208 # 209 # XXX: Must happen after instance list updates above, otherwise instance 210 # is treated as a non-slave instance by post-install via postfix(1). 211 # 212 postfix -c $config_directory set-permissions || exit 1 213 ;; 214 215deport) 216 # Deporting an already deleted instance? 217 # 218 [ -f "$config_directory/main.cf" ] || { 219 update_cfdirs del $config_directory 220 exit $? 221 } 222 223 postfix -c "$config_directory" status >/dev/null 2>&1 && 224 fatal "Instance '$config_directory' is not stopped" 225 226 # Update multi_instance_directories 227 # and add to alternate_config_directories 228 # 229 update_cfdirs add $config_directory || exit 1 230 ;; 231 232destroy) 233 234 # "postmulti -e destroy" will remove an entire instance only when 235 # invoked immediately after "postmulti -e create" (i.e. before 236 # other files are added to the instance). We delete only known 237 # safe names without "/". 238 # 239 QUEUE_SUBDIRS="active bounce corrupt defer deferred flush hold \ 240 incoming maildrop pid private public saved trace" 241 #DEBUG=echo 242 WARN="postlog -p warn -t $TAG" 243 244 # Locate the target instance 245 # 246 [ -f "$config_directory/main.cf" ] || 247 fatal "$config_directory/main.cf file not found" 248 249 postfix -c "$config_directory" status >/dev/null 2>&1 && 250 fatal "Instance '$config_directory' is not stopped" 251 252 # Update multi_instance directories 253 # and also (just in case) drop from alternate_config_directories 254 # 255 $DEBUG update_cfdirs del "$config_directory" || exit 1 256 257 # XXX: Internal "postfix /some/cmd" interface. 258 # 259 postfix -c "$config_directory" /bin/sh -c " 260 for q in $QUEUE_SUBDIRS 261 do 262 $DEBUG rmdir -- \$q || 263 $WARN \`pwd\`/\$q: please verify contents and remove by hand 264 done 265 " 266 267 postfix -c "$config_directory" /bin/sh -c " 268 for dir in \$data_directory \$queue_directory 269 do 270 $DEBUG rmdir -- \$dir || 271 $WARN \$dir: please verify contents and remove by hand 272 done 273 " 274 275 # In the configuration directory remove just the main.cf and master.cf 276 # files. 277 $DEBUG rm -f -- "$config_directory/master.cf" "$config_directory/main.cf" 2>/dev/null 278 $DEBUG rmdir -- "$config_directory" || 279 $WARN $config_directory: please verify contents and remove by hand 280 ;; 281 282enable) 283 postconf -c "$config_directory" -e \ 284 "multi_instance_enable = yes" || exit 1;; 285disable) 286 postconf -c "$config_directory" -e \ 287 "multi_instance_enable = no" || exit 1;; 288assign) 289 assign_names || exit 1;; 290esac 291 292exit 0 293