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