1#! /bin/sh 2# $NetBSD: postmulti-script,v 1.1.1.1 2009/06/23 10:08:23 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 # Locate the target instance 234 # 235 [ -f "$config_directory/main.cf" ] || 236 fatal "$config_directory/main.cf file not found" 237 238 postfix -c "$config_directory" status >/dev/null 2>&1 && 239 fatal "Instance '$config_directory' is not stopped" 240 241 # XXX: Internal "postfix /some/cmd" interface via /bin/env for execvp(). 242 # 243 for q in maildrop incoming active deferred hold 244 do 245 postfix -c "$config_directory" /bin/env \ 246 find "$q" ! -name "$q" ! -name "?" -perm 0700 -print | 247 grep "^" >/dev/null && 248 fatal "Instance '$config_directory' $q queue is not empty" 249 done 250 251 # Update multi_instance directories 252 # and also (just in case) drop from alternate_config_directories 253 # 254 update_cfdirs del $config_directory || exit 1 255 256 # Change default personalities: 257 MAIL_CONFIG="$config_directory"; export MAIL_CONFIG 258 259 # Full steam ahead, instance will be at least partly destroyed! 260 261 # Try to remove data_directory, but not sub-directories. 262 # Note: care with "$TAG" insertion into sh -c 'script'. 263 # 264 postfix /bin/sh -c \ 265 'cd $data_directory; rm -f -- *; cd ..; rmdir $data_directory; \ 266 PATH=$command_directory:$PATH; export PATH; \ 267 test -d $data_directory && \ 268 postlog -p warn -t "'"$TAG"'" \ 269 "$data_directory partly removed" 2>&1' 2>/dev/null 270 271 # Remove Postfix-owned files in the queue directory. 272 # Remove all files in the "pid" sub-directory. 273 # Remove empty directories. 274 # Note: care with "$TAG" insertion into sh -c 'script'. 275 postfix /bin/sh -c \ 276 'find . -user $mail_owner ! -type d -exec rm -f -- "{}" ";"; \ 277 find . -depth -user $mail_owner -type d -exec rmdir -- "{}" ";"; \ 278 rm -f -- pid/*; rmdir *; cd ..; rmdir $queue_directory; \ 279 PATH=$command_directory:$PATH; export PATH; \ 280 test -d $queue_directory && \ 281 postlog -p warn -t "'"$TAG"'" \ 282 "$queue_directory partly removed" 2>&1' 2>/dev/null 283 284 # In the configuration directory remove just the main.cf and master.cf 285 # files. 286 rm -f -- "$MAIL_CONFIG/master.cf" "$MAIL_CONFIG/main.cf" 2>/dev/null 287 rmdir -- "$MAIL_CONFIG" 2>/dev/null 288 test -d "$MAIL_CONFIG" && \ 289 postlog -p warn -t "$TAG" \ 290 "$MAIL_CONFIG partly removed" 2>&1 291 ;; 292enable) 293 postconf -c "$config_directory" -e \ 294 "multi_instance_enable = yes" || exit 1;; 295disable) 296 postconf -c "$config_directory" -e \ 297 "multi_instance_enable = no" || exit 1;; 298assign) 299 assign_names || exit 1;; 300esac 301 302exit 0 303