xref: /netbsd-src/external/ibm-public/postfix/dist/conf/postmulti-script (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
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