xref: /netbsd-src/external/ibm-public/postfix/dist/src/postmulti/postmulti.c (revision 7330f729ccf0bd976a06f95fad452fe774fc7fd1)
1 /*	$NetBSD: postmulti.c,v 1.2 2017/02/14 01:16:47 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	postmulti 1
6 /* SUMMARY
7 /*	Postfix multi-instance manager
8 /* SYNOPSIS
9 /* .fi
10 /* .ti -4
11 /*	\fBEnabling multi-instance management:\fR
12 /*
13 /*	\fBpostmulti\fR \fB-e init\fR [\fB-v\fR]
14 /*
15 /* .ti -4
16 /*	\fBIterator mode:\fR
17 /*
18 /*	\fBpostmulti\fR \fB-l\fR [\fB-aRv\fR] [\fB-g \fIgroup\fR]
19 /*	[\fB-i \fIname\fR]
20 /*
21 /*	\fBpostmulti\fR \fB-p\fR [\fB-av\fR] [\fB-g \fIgroup\fR]
22 /*	[\fB-i \fIname\fR] \fIcommand...\fR
23 /*
24 /*	\fBpostmulti\fR \fB-x\fR [\fB-aRv\fR] [\fB-g \fIgroup\fR]
25 /*	[\fB-i \fIname\fR] \fIcommand...\fR
26 /*
27 /* .ti -4
28 /*	\fBLife-cycle management:\fR
29 /*
30 /*	\fBpostmulti\fR \fB-e create\fR [\fB-av\fR]
31 /*	[\fB-g \fIgroup\fR] [\fB-i \fIname\fR] [\fB-G \fIgroup\fR]
32 /*	[\fB-I \fIname\fR] [\fIparam=value\fR ...]
33 /*
34 /*	\fBpostmulti\fR \fB-e import\fR [\fB-av\fR]
35 /*	[\fB-g \fIgroup\fR] [\fB-i \fIname\fR] [\fB-G \fIgroup\fR]
36 /*	[\fB-I \fIname\fR] [\fBconfig_directory=\fI/path\fR]
37 /*
38 /*	\fBpostmulti\fR \fB-e destroy\fR [\fB-v\fR] \fB-i \fIname\fR
39 /*
40 /*	\fBpostmulti\fR \fB-e deport\fR [\fB-v\fR] \fB-i \fIname\fR
41 /*
42 /*	\fBpostmulti\fR \fB-e enable\fR [\fB-v\fR] \fB-i \fIname\fR
43 /*
44 /*	\fBpostmulti\fR \fB-e disable\fR [\fB-v\fR] \fB-i \fIname\fR
45 /*
46 /*	\fBpostmulti\fR \fB-e assign\fR [\fB-v\fR] \fB-i \fIname\fR
47 /*	[\fB-I \fIname\fR] [-G \fIgroup\fR]
48 /* DESCRIPTION
49 /*	The \fBpostmulti\fR(1) command allows a Postfix administrator
50 /*	to manage multiple Postfix instances on a single host.
51 /*
52 /*	\fBpostmulti\fR(1) implements two fundamental modes of
53 /*	operation.  In \fBiterator\fR mode, it executes the same
54 /*	command for multiple Postfix instances.  In \fBlife-cycle
55 /*	management\fR mode, it adds or deletes one instance, or
56 /*	changes the multi-instance status of one instance.
57 /*
58 /*	Each mode of operation has its own command syntax. For this
59 /*	reason, each mode is documented in separate sections below.
60 /* BACKGROUND
61 /* .ad
62 /* .fi
63 /*	A multi-instance configuration consists of one primary
64 /*	Postfix instance, and one or more secondary instances whose
65 /*	configuration directory pathnames are recorded in the primary
66 /*	instance's main.cf file. Postfix instances share program
67 /*	files and documentation, but have their own configuration,
68 /*	queue and data directories.
69 /*
70 /*	Currently, only the default Postfix instance can be used
71 /*	as primary instance in a multi-instance configuration. The
72 /*	\fBpostmulti\fR(1) command does not currently support a \fB-c\fR
73 /*	option to select an alternative primary instance, and exits
74 /*	with a fatal error if the \fBMAIL_CONFIG\fR environment
75 /*	variable is set to a non-default configuration directory.
76 /*
77 /*	See the MULTI_INSTANCE_README tutorial for a more detailed
78 /*	discussion of multi-instance management with \fBpostmulti\fR(1).
79 /* ITERATOR MODE
80 /* .ad
81 /* .fi
82 /*	In iterator mode, \fBpostmulti\fR performs the same operation
83 /*	on all Postfix instances in turn.
84 /*
85 /*	If multi-instance support is not enabled, the requested
86 /*	command is performed just for the primary instance.
87 /* .PP
88 /*	Iterator mode implements the following command options:
89 /* .SH "Instance selection"
90 /* .IP \fB-a\fR
91 /*	Perform the operation on all instances. This is the default.
92 /* .IP "\fB-g \fIgroup\fR"
93 /*	Perform the operation only for members of the named \fIgroup\fR.
94 /* .IP "\fB-i \fIname\fR"
95 /*	Perform the operation only for the instance with the specified
96 /*	\fIname\fR.  You can specify either the instance name
97 /*	or the absolute pathname of the instance's configuration
98 /*	directory.  Specify "-" to select the primary Postfix instance.
99 /* .IP \fB-R\fR
100 /*	Reverse the iteration order. This may be appropriate when
101 /*	updating a multi-instance system, where "sink" instances
102 /*	are started before "source" instances.
103 /* .sp
104 /*	This option cannot be used with \fB-p\fR.
105 /* .SH "List mode"
106 /* .IP \fB-l\fR
107 /*	List Postfix instances with their instance name, instance
108 /*	group name, enable/disable status and configuration directory.
109 /* .SH "Postfix-wrapper mode"
110 /* .IP \fB-p\fR
111 /*	Invoke \fBpostfix(1)\fR to execute the specified \fIcommand\fR.
112 /*	This option implements the \fBpostfix-wrapper\fR(5) interface.
113 /* .RS
114 /* .IP \(bu
115 /*	With "start"-like commands, "postfix check" is executed for
116 /*	instances that are not enabled. The full list of commands
117 /*	is specified with the postmulti_start_commands parameter.
118 /* .IP \(bu
119 /*	With "stop"-like commands, the iteration order is reversed,
120 /*	and disabled instances are skipped. The full list of commands
121 /*	is specified with the postmulti_stop_commands parameter.
122 /* .IP \(bu
123 /*	With "reload" and other commands that require a started
124 /*	instance, disabled instances are skipped. The full list of
125 /*	commands is specified with the postmulti_control_commands
126 /*	parameter.
127 /* .IP \(bu
128 /*	With "status" and other commands that don't require a started
129 /*	instance, the command is executed for all instances.
130 /* .RE
131 /* .IP
132 /*	The \fB-p\fR option can also be used interactively to
133 /*	start/stop/etc.  a named instance or instance group. For
134 /*	example, to start just the instances in the group "msa",
135 /*	invoke \fBpostmulti\fR(1) as follows:
136 /* .RS
137 /* .IP
138 /*	# postmulti -g msa -p start
139 /* .RE
140 /* .SH "Command mode"
141 /* .IP \fB-x\fR
142 /*	Execute the specified \fIcommand\fR for all Postfix instances.
143 /*	The command runs with appropriate environment settings for
144 /*	MAIL_CONFIG, command_directory, daemon_directory,
145 /*	config_directory, queue_directory, data_directory,
146 /*	multi_instance_name, multi_instance_group and
147 /*	multi_instance_enable.
148 /* .SH "Other options"
149 /* .IP \fB-v\fR
150 /*	Enable verbose logging for debugging purposes. Multiple
151 /*	\fB-v\fR options make the software increasingly verbose.
152 /* LIFE-CYCLE MANAGEMENT MODE
153 /* .ad
154 /* .fi
155 /*	With the \fB-e\fR option \fBpostmulti\fR(1) can be used to
156 /*	add or delete a Postfix instance, and to manage the
157 /*	multi-instance status of an existing instance.
158 /* .PP
159 /*	The following options are implemented:
160 /* .SH "Existing instance selection"
161 /* .IP \fB-a\fR
162 /*	When creating or importing an instance, place the new
163 /*	instance at the front of the secondary instance list.
164 /* .IP "\fB-g \fIgroup\fR"
165 /*	When creating or importing an instance, place the new
166 /*	instance before the first secondary instance that is a
167 /*	member of the specified group.
168 /* .IP "\fB-i \fIname\fR"
169 /*	When creating or importing an instance, place the new
170 /*	instance before the matching secondary instance.
171 /* .sp
172 /*	With other life-cycle operations, apply the operation to
173 /*	the named existing instance.  Specify "-" to select the
174 /*	primary Postfix instance.
175 /* .SH "New or existing instance name assignment"
176 /* .IP "\fB-I \fIname\fR"
177 /*	Assign the specified instance \fIname\fR to an existing
178 /*	instance, newly-created instance, or imported instance.
179 /*	Instance
180 /*	names other than "-" (which makes the instance "nameless")
181 /*	must start with "postfix-".  This restriction reduces the
182 /*	likelihood of name collisions with system files.
183 /* .IP "\fB-G \fIgroup\fR"
184 /*	Assign the specified \fIgroup\fR name to an existing instance
185 /*	or to a newly created or imported instance.
186 /* .SH "Instance creation/deletion/status change"
187 /* .IP "\fB-e \fIaction\fR"
188 /*	"Edit" managed instances. The following actions are supported:
189 /* .RS
190 /* .IP \fBinit\fR
191 /*	This command is required before \fBpostmulti\fR(1) can be
192 /*	used to manage Postfix instances.  The "postmulti -e init"
193 /*	command updates the primary instance's main.cf file by
194 /*	setting:
195 /* .RS
196 /* .IP
197 /* .nf
198 /*	multi_instance_wrapper =
199 /*		${command_directory}/postmulti -p --
200 /*	multi_instance_enable = yes
201 /* .fi
202 /* .RE
203 /* .IP
204 /*	You can set these by other means if you prefer.
205 /* .IP \fBcreate\fR
206 /*	Create a new Postfix instance and add it to the
207 /*	multi_instance_directories parameter of the primary instance.
208 /*	The "\fB-I \fIname\fR" option is recommended to give the
209 /*	instance a short name that is used to construct default
210 /*	values for the private directories of the new instance. The
211 /*	"\fB-G \fIgroup\fR" option may be specified to assign the
212 /*	instance to a group, otherwise, the new instance is not a
213 /*	member of any groups.
214 /* .sp
215 /*	The new instance main.cf is the stock main.cf with the
216 /*	parameters that specify the locations of shared files cloned
217 /*	from the primary instance.  For "nameless" instances, you
218 /*	should manually adjust "syslog_name" to yield a unique
219 /*	"logtag" starting with "postfix-" that will uniquely identify
220 /*	the instance in the mail logs. It is simpler to assign the
221 /*	instance a short name with the "\fB-I \fIname\fR" option.
222 /* .sp
223 /*	Optional "name=value" arguments specify the instance
224 /*	config_directory, queue_directory and data_directory.
225 /*	For example:
226 /* .RS
227 /* .IP
228 /* .nf
229 /*	# postmulti -I postfix-mumble \e
230 /*		-G mygroup -e create \e
231 /*		config_directory=/my/config/dir \e
232 /*		queue_directory=/my/queue/dir \e
233 /*		data_directory=/my/data/dir
234 /* .fi
235 /* .RE
236 /* .IP
237 /*	If any of these pathnames is not supplied, the program
238 /*	attempts to generate the pathname by taking the corresponding
239 /*	primary instance pathname, and by replacing the last pathname
240 /*	component by the value of the \fB-I\fR option.
241 /* .sp
242 /*	If the instance configuration directory already exists, and
243 /*	contains both a main.cf and master.cf file, \fBcreate\fR
244 /*	will "import" the instance as-is. For existing instances,
245 /*	\fBcreate\fR and \fBimport\fR are identical.
246 /* .IP \fBimport\fR
247 /*	Import an existing instance into the list of instances
248 /*	managed by the \fBpostmulti\fR(1) multi-instance manager.
249 /*	This adds the instance to the multi_instance_directories
250 /*	list of the primary instance.  If the "\fB-I \fIname\fR"
251 /*	option is provided it specifies the new name for the instance
252 /*	and is used to define a default location for the instance
253 /*	configuration directory	(as with \fBcreate\fR above).  The
254 /*	"\fB-G \fIgroup\fR" option may be used to assign the instance
255 /*	to a group. Add a "\fBconfig_directory=\fI/path\fR" argument
256 /*	to override a default pathname based on "\fB-I \fIname\fR".
257 /* .IP \fBdestroy\fR
258 /*	Destroy a secondary Postfix instance. To be a candidate for
259 /*	destruction an instance must be disabled, stopped and its
260 /*	queue must not contain any messages. Attempts to destroy
261 /*	the primary Postfix instance trigger a fatal error, without
262 /*	destroying the instance.
263 /* .sp
264 /*	The instance is removed from the primary instance main.cf
265 /*	file's alternate_config_directories parameter and its data,
266 /*	queue and configuration directories are cleaned of files
267 /*	and directories created by the Postfix system. The main.cf
268 /*	and master.cf files are removed from the configuration
269 /*	directory even if they have been modified since initial
270 /*	creation. Finally, the instance is "deported" from the list
271 /*	of managed instances.
272 /* .sp
273 /*	If other files are present in instance private directories,
274 /*	the directories may not be fully removed, a warning is
275 /*	logged to alert the administrator. It is expected that an
276 /*	instance built using "fresh" directories via the \fBcreate\fR
277 /*	action will be fully removed by the \fBdestroy\fR action
278 /*	(if first disabled). If the instance configuration and queue
279 /*	directories are populated with additional files	(access and
280 /*	rewriting tables, chroot jail content, etc.) the instance
281 /*	directories will not be fully removed.
282 /* .sp
283 /*	The \fBdestroy\fR action triggers potentially dangerous
284 /*	file removal operations. Make sure the instance's data,
285 /*	queue and configuration directories are set correctly and
286 /*	do not contain any valuable files.
287 /* .IP \fBdeport\fR
288 /*	Deport a secondary instance from the list of managed
289 /*	instances. This deletes the instance configuration directory
290 /*	from the primary instance's multi_instance_directories list,
291 /*	but does not remove any files or directories.
292 /* .IP \fBassign\fR
293 /*	Assign a new instance name or a new group name to the
294 /*	selected instance.  Use "\fB-G -\fR" to specify "no group"
295 /*	and "\fB-I -\fR" to specify "no name".  If you choose to
296 /*	make an instance "nameless", set a suitable syslog_name in
297 /*	the corresponding main.cf file.
298 /* .IP \fBenable\fR
299 /*	Mark the selected instance as enabled. This just sets the
300 /*	multi_instance_enable parameter to "yes" in the instance's
301 /*	main.cf file.
302 /* .IP \fBdisable\fR
303 /*	Mark the selected instance as disabled. This means that
304 /*	the instance will not be started etc. with "postfix start",
305 /*	"postmulti -p start" and so on. The instance can still be
306 /*	started etc. with "postfix -c config-directory start".
307 /* .SH "Other options"
308 /* .IP \fB-v\fR
309 /*	Enable verbose logging for debugging purposes. Multiple
310 /*	\fB-v\fR options make the software increasingly verbose.
311 /* .RE
312 /* ENVIRONMENT
313 /* .ad
314 /* .fi
315 /*	The \fBpostmulti\fR(1) command exports the following environment
316 /*	variables before executing the requested \fIcommand\fR for a given
317 /*	instance:
318 /* .IP \fBMAIL_VERBOSE\fR
319 /*	This is set when the -v command-line option is present.
320 /* .IP \fBMAIL_CONFIG\fR
321 /*	The location of the configuration directory of the instance.
322 /* CONFIGURATION PARAMETERS
323 /* .ad
324 /* .fi
325 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
326 /*	The default location of the Postfix main.cf and master.cf
327 /*	configuration files.
328 /* .IP "\fBdaemon_directory (see 'postconf -d' output)\fR"
329 /*	The directory with Postfix support programs and daemon programs.
330 /* .IP "\fBimport_environment (see 'postconf -d' output)\fR"
331 /*	The list of environment parameters that a Postfix process will
332 /*	import from a non-Postfix parent process.
333 /* .IP "\fBmulti_instance_directories (empty)\fR"
334 /*	An optional list of non-default Postfix configuration directories;
335 /*	these directories belong to additional Postfix instances that share
336 /*	the Postfix executable files and documentation with the default
337 /*	Postfix instance, and that are started, stopped, etc., together
338 /*	with the default Postfix instance.
339 /* .IP "\fBmulti_instance_group (empty)\fR"
340 /*	The optional instance group name of this Postfix instance.
341 /* .IP "\fBmulti_instance_name (empty)\fR"
342 /*	The optional instance name of this Postfix instance.
343 /* .IP "\fBmulti_instance_enable (no)\fR"
344 /*	Allow this Postfix instance to be started, stopped, etc., by a
345 /*	multi-instance manager.
346 /* .IP "\fBpostmulti_start_commands (start)\fR"
347 /*	The \fBpostfix\fR(1) commands that the \fBpostmulti\fR(1) instance manager treats
348 /*	as "start" commands.
349 /* .IP "\fBpostmulti_stop_commands (see 'postconf -d' output)\fR"
350 /*	The \fBpostfix\fR(1) commands that the \fBpostmulti\fR(1) instance manager treats
351 /*	as "stop" commands.
352 /* .IP "\fBpostmulti_control_commands (reload flush)\fR"
353 /*	The \fBpostfix\fR(1) commands that the \fBpostmulti\fR(1) instance manager
354 /*	treats as "control" commands, that operate on running instances.
355 /* .IP "\fBsyslog_facility (mail)\fR"
356 /*	The syslog facility of Postfix logging.
357 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
358 /*	The mail system name that is prepended to the process name in syslog
359 /*	records, so that "smtpd" becomes, for example, "postfix/smtpd".
360 /* .PP
361 /*	Available in Postfix 3.0 and later:
362 /* .IP "\fBmeta_directory (see 'postconf -d' output)\fR"
363 /*	The location of non-executable files that are shared among
364 /*	multiple Postfix instances, such as postfix-files, dynamicmaps.cf,
365 /*	and the multi-instance template files main.cf.proto and master.cf.proto.
366 /* .IP "\fBshlib_directory (see 'postconf -d' output)\fR"
367 /*	The location of Postfix dynamically-linked libraries
368 /*	(libpostfix-*.so), and the default location of Postfix database
369 /*	plugins (postfix-*.so) that have a relative pathname in the
370 /*	dynamicmaps.cf file.
371 /* FILES
372 /*	$meta_directory/main.cf.proto, stock configuration file
373 /*	$meta_directory/master.cf.proto, stock configuration file
374 /*	$daemon_directory/postmulti-script, life-cycle helper program
375 /* SEE ALSO
376 /*	postfix(1), Postfix control program
377 /*	postfix-wrapper(5), Postfix multi-instance API
378 /* README FILES
379 /* .ad
380 /* .fi
381 /*	Use "\fBpostconf readme_directory\fR" or "\fBpostconf
382 /*	html_directory\fR" to locate this information.
383 /* .nf
384 /* .na
385 /*	MULTI_INSTANCE_README, Postfix multi-instance management
386 /* HISTORY
387 /* .ad
388 /* .fi
389 /*	The \fBpostmulti\fR(1) command was introduced with Postfix
390 /*	version 2.6.
391 /* LICENSE
392 /* .ad
393 /* .fi
394 /*	The Secure Mailer license must be distributed with this software.
395 /* AUTHOR(S)
396 /*	Victor Duchovni
397 /*	Morgan Stanley
398 /*
399 /*	Wietse Venema
400 /*	IBM T.J. Watson Research
401 /*	P.O. Box 704
402 /*	Yorktown Heights, NY 10598, USA
403 /*--*/
404 
405 /* System library. */
406 
407 #include <sys_defs.h>
408 #include <sys/stat.h>
409 #include <sys/wait.h>
410 #include <vstream.h>
411 #include <stdlib.h>
412 #include <unistd.h>
413 #include <string.h>
414 #include <fcntl.h>
415 #include <syslog.h>
416 #include <errno.h>
417 #include <ctype.h>
418 #ifdef USE_PATHS_H
419 #include <paths.h>
420 #endif
421 #include <stddef.h>
422 
423 /* Utility library. */
424 
425 #include <msg.h>
426 #include <msg_vstream.h>
427 #include <msg_syslog.h>
428 #include <vstream.h>
429 #include <vstring_vstream.h>
430 #include <stringops.h>
431 #include <clean_env.h>
432 #include <argv.h>
433 #include <safe.h>
434 #include <mymalloc.h>
435 #include <htable.h>
436 #include <name_code.h>
437 #include <ring.h>
438 #include <warn_stat.h>
439 
440 /* Global library. */
441 
442 #include <mail_version.h>
443 #include <mail_params.h>
444 #include <mail_conf.h>
445 #include <mail_parm_split.h>
446 
447 /* Application-specific. */
448 
449  /*
450   * Configuration parameters, specific to postmulti(1).
451   */
452 char   *var_multi_start_cmds;
453 char   *var_multi_stop_cmds;
454 char   *var_multi_cntrl_cmds;
455 
456  /*
457   * Shared directory pathnames.
458   */
459 typedef struct {
460     const char *param_name;
461     char  **param_value;
462 } SHARED_PATH;
463 
464 static SHARED_PATH shared_dir_table[] = {
465     VAR_COMMAND_DIR, &var_command_dir,
466     VAR_DAEMON_DIR, &var_daemon_dir,
467     VAR_META_DIR, &var_meta_dir,
468     VAR_SHLIB_DIR, &var_shlib_dir,
469     0,
470 };
471 
472  /*
473   * Actions.
474   */
475 #define ITER_CMD_POSTFIX	(1<<0)	/* postfix(1) iterator mode */
476 #define ITER_CMD_LIST		(1<<1)	/* listing iterator mode */
477 #define ITER_CMD_GENERIC	(1<<2)	/* generic command iterator mode */
478 
479 #define ITER_CMD_MASK_ALL \
480     (ITER_CMD_POSTFIX | ITER_CMD_LIST | ITER_CMD_GENERIC)
481 
482 #define EDIT_CMD_CREATE		(1<<4)	/* create new instance */
483 #define EDIT_CMD_IMPORT		(1<<5)	/* import existing instance */
484 #define EDIT_CMD_DESTROY	(1<<6)	/* destroy instance */
485 #define EDIT_CMD_DEPORT		(1<<7)	/* export instance */
486 #define EDIT_CMD_ENABLE		(1<<8)	/* enable start/stop */
487 #define EDIT_CMD_DISABLE	(1<<9)	/* disable start/stop */
488 #define EDIT_CMD_ASSIGN		(1<<10)	/* assign name/group */
489 #define EDIT_CMD_INIT		(1<<11)	/* hook into main.cf */
490 
491 #define EDIT_CMD_MASK_ADD	(EDIT_CMD_CREATE | EDIT_CMD_IMPORT)
492 #define EDIT_CMD_MASK_DEL	(EDIT_CMD_DESTROY | EDIT_CMD_DEPORT)
493 #define EDIT_CMD_MASK_ASSIGN	(EDIT_CMD_MASK_ADD | EDIT_CMD_ASSIGN)
494 #define EDIT_CMD_MASK_ENB	(EDIT_CMD_ENABLE | EDIT_CMD_DISABLE)
495 #define EDIT_CMD_MASK_ALL \
496     (EDIT_CMD_MASK_ASSIGN | EDIT_CMD_MASK_DEL | EDIT_CMD_MASK_ENB | \
497 	EDIT_CMD_INIT)
498 
499  /*
500   * Edit command to number mapping, and vice versa.
501   */
502 static NAME_CODE edit_command_table[] = {
503     "create", EDIT_CMD_CREATE,
504     "import", EDIT_CMD_IMPORT,
505     "destroy", EDIT_CMD_DESTROY,
506     "deport", EDIT_CMD_DEPORT,
507     "enable", EDIT_CMD_ENABLE,
508     "disable", EDIT_CMD_DISABLE,
509     "assign", EDIT_CMD_ASSIGN,
510     "init", EDIT_CMD_INIT,
511     0, -1,
512 };
513 
514 #define EDIT_CMD_CODE(str) \
515 	name_code(edit_command_table, NAME_CODE_FLAG_STRICT_CASE, (str))
516 #define EDIT_CMD_STR(code)	str_name_code(edit_command_table, (code))
517 
518  /*
519   * Mandatory prefix for non-empty instance names.
520   */
521 #ifndef NAME_PREFIX
522 #define NAME_PREFIX "postfix-"
523 #endif
524 #define HAS_NAME_PREFIX(name) \
525      (strncmp((name), NAME_PREFIX, sizeof(NAME_PREFIX)-1) == 0)
526 #define NEED_NAME_PREFIX(name) \
527     ((name) != 0 && strcmp((name), "-") != 0 && !HAS_NAME_PREFIX(name))
528 #define NAME_SUFFIX(name) ((name) + sizeof(NAME_PREFIX) - 1)
529 
530  /*
531   * In-core instance structure. Only private information is kept here.
532   */
533 typedef struct instance {
534     RING    ring;			/* linkage. */
535     char   *config_dir;			/* private */
536     char   *queue_dir;			/* private */
537     char   *data_dir;			/* private */
538     char   *name;			/* null or name */
539     char   *gname;			/* null or group */
540     int     enabled;			/* start/stop enable */
541     int     primary;			/* special */
542 } INSTANCE;
543 
544  /*
545   * Managed instance list (edit mode and iterator mode).
546   */
547 static RING instance_hd[1];		/* instance list head */
548 
549 #define RING_TO_INSTANCE(ring_ptr)	RING_TO_APPL(ring_ptr, INSTANCE, ring)
550 #define RING_PTR_OF(x)			(&((x)->ring))
551 
552 #define FOREACH_INSTANCE(entry) \
553     for ((entry) = instance_hd; \
554 	 ((entry) = ring_succ(entry)) != instance_hd;)
555 
556 #define FOREACH_SECONDARY_INSTANCE(entry) \
557     for ((entry) = ring_succ(instance_hd); \
558 	 ((entry) = ring_succ(entry)) != instance_hd;)
559 
560 #define NEXT_ITERATOR_INSTANCE(flags, entry) \
561     (((flags) & ITER_FLAG_REVERSE) ? ring_pred(entry) : ring_succ(entry))
562 
563 #define FOREACH_ITERATOR_INSTANCE(flags, entry) \
564     for ((entry) = instance_hd; \
565 	((entry) = NEXT_ITERATOR_INSTANCE(flags, (entry))) != instance_hd;)
566 
567  /*
568   * Instance selection. One can either select all instances, select by
569   * instance name, or select by instance group.
570   */
571 typedef struct {
572     int     type;			/* see below */
573     char   *name;			/* undefined or name */
574 } INST_SELECTION;
575 
576 #define INST_SEL_NONE		0	/* default: no selection */
577 #define INST_SEL_ALL		1	/* select all instances */
578 #define INST_SEL_NAME		2	/* select instance name */
579 #define INST_SEL_GROUP		3	/* select instance group */
580 
581  /*
582   * Instance name assignment. Each instance may be assigned an instance name
583   * (this must be globally unique within a multi-instance cluster) or an
584   * instance group name (this is intended to be shared). Externally, empty
585   * names may be represented as "-". Internally, we use "" only, to simplify
586   * the code.
587   */
588 typedef struct {
589     char   *name;			/* null or assigned instance name */
590     char   *gname;			/* null or assigned group name */
591 } NAME_ASSIGNMENT;
592 
593  /*
594   * Iterator controls for non-edit commands. One can reverse the iteration
595   * order, or give special treatment to disabled instances.
596   */
597 #define ITER_FLAG_DEFAULT	0	/* default setting */
598 #define ITER_FLAG_REVERSE	(1<<0)	/* reverse iteration order */
599 #define ITER_FLAG_CHECK_DISABLED (1<<1)	/* check disabled instances */
600 #define ITER_FLAG_SKIP_DISABLED	(1<<2)	/* skip disabled instances */
601 
602  /*
603   * Environment export controls for edit commands. postmulti(1) exports only
604   * things that need to be updated.
605   */
606 #define EXP_FLAG_MULTI_DIRS	(1<<0)	/* export multi_instance_directories */
607 #define EXP_FLAG_MULTI_NAME	(1<<1)	/* export multi_instance_name */
608 #define EXP_FLAG_MULTI_GROUP	(1<<2)	/* export multi_instance_group */
609 
610  /*
611   * To detect conflicts, each instance name and each shared or private
612   * pathname is registered in one place, with its owner. Everyone must
613   * register their claims when they join, and will be rejected in case of
614   * conlict.
615   *
616   * Each claim value involves a parameter value (either a directory name or an
617   * instance name). Each claim owner is the config_directory pathname plus
618   * the parameter name.
619   *
620   * XXX: No multi.cf lock file, so this is not race-free.
621   */
622 static HTABLE *claim_table;
623 
624 #define IS_CLAIMED_BY(name) \
625     (claim_table ? htable_find(claim_table, (name)) : 0)
626 
627  /*
628   * Forward references.
629   */
630 static int iterate_command(int, int, char **, INST_SELECTION *);
631 static int match_instance_selection(INSTANCE *, INST_SELECTION *);
632 
633  /*
634   * Convenience.
635   */
636 #define INSTANCE_NAME(i) ((i)->name ? (i)->name : (i)->config_dir)
637 #define STR(buf)	vstring_str(buf)
638 
639 /* register_claim - register claim or bust */
640 
641 static void register_claim(const char *instance_path, const char *param_name,
642 			           const char *param_value)
643 {
644     const char *myname = "register_claim";
645     char   *requestor;
646     const char *owner;
647 
648     /*
649      * Sanity checks.
650      */
651     if (instance_path == 0 || *instance_path == 0)
652 	msg_panic("%s: no or empty instance pathname", myname);
653     if (param_name == 0 || *param_name == 0)
654 	msg_panic("%s: no or empty parameter name", myname);
655     if (param_value == 0)
656 	msg_panic("%s: no parameter value", myname);
657 
658     /*
659      * Make a claim or report a conflict.
660      */
661     if (claim_table == 0)
662 	claim_table = htable_create(100);
663     requestor = concatenate(instance_path, ", ", param_name, (char *) 0);
664     if ((owner = htable_find(claim_table, param_value)) == 0) {
665 	(void) htable_enter(claim_table, param_value, requestor);
666     } else if (strcmp(owner, requestor) == 0) {
667 	myfree(requestor);
668     } else {
669 	msg_fatal("instance %s, %s=%s conflicts with instance %s=%s",
670 		instance_path, param_name, param_value, owner, param_value);
671     }
672 }
673 
674 /* claim_instance_attributes - claim multiple private instance attributes */
675 
676 static void claim_instance_attributes(INSTANCE *ip)
677 {
678 
679     /*
680      * Detect instance name or pathname conflicts between this instance and
681      * other instances. XXX: No multi.cf lock file, so this is not race-free.
682      */
683     if (ip->name)
684 	register_claim(ip->config_dir, VAR_MULTI_NAME, ip->name);
685     register_claim(ip->config_dir, VAR_CONFIG_DIR, ip->config_dir);
686     register_claim(ip->config_dir, VAR_QUEUE_DIR, ip->queue_dir);
687     register_claim(ip->config_dir, VAR_DATA_DIR, ip->data_dir);
688 }
689 
690 /* alloc_instance - allocate a single instance object */
691 
692 static INSTANCE *alloc_instance(const char *config_dir)
693 {
694     INSTANCE *ip = (INSTANCE *) mymalloc(sizeof(INSTANCE));
695 
696     ring_init(RING_PTR_OF(ip));
697     ip->config_dir = config_dir ? mystrdup(config_dir) : 0;
698     ip->queue_dir = 0;
699     ip->data_dir = 0;
700     ip->name = 0;
701     ip->gname = 0;
702     ip->enabled = 0;
703     ip->primary = 0;
704 
705     return (ip);
706 }
707 
708 #if 0
709 
710 /* free_instance - free a single instance object */
711 
712 static void free_instance(INSTANCE *ip)
713 {
714 
715     /*
716      * If we continue after secondary main.cf file read error, we must be
717      * prepared for the case that some parameters may be missing.
718      */
719     if (ip->name)
720 	myfree(ip->name);
721     if (ip->gname)
722 	myfree(ip->gname);
723     if (ip->config_dir)
724 	myfree(ip->config_dir);
725     if (ip->queue_dir)
726 	myfree(ip->queue_dir);
727     if (ip->data_dir)
728 	myfree(ip->data_dir);
729     myfree((void *) ip);
730 }
731 
732 #endif
733 
734 /* insert_instance - insert instance before selected location, claim names */
735 
736 static void insert_instance(INSTANCE *ip, INST_SELECTION *selection)
737 {
738     RING   *old;
739 
740 #define append_instance(ip) insert_instance((ip), (INST_SELECTION *) 0)
741 
742     /*
743      * Insert instance before the selected site.
744      */
745     claim_instance_attributes(ip);
746     if (ring_succ(instance_hd) == 0)
747 	ring_init(instance_hd);
748     if (selection && selection->type != INST_SEL_NONE) {
749 	FOREACH_SECONDARY_INSTANCE(old) {
750 	    if (match_instance_selection(RING_TO_INSTANCE(old), selection)) {
751 		ring_prepend(old, RING_PTR_OF(ip));
752 		return;
753 	    }
754 	}
755 	if (selection->type != INST_SEL_ALL)
756 	    msg_fatal("No matching secondary instances");
757     }
758     ring_prepend(instance_hd, RING_PTR_OF(ip));
759 }
760 
761 /* create_primary_instance - synthetic entry for primary instance */
762 
763 static INSTANCE *create_primary_instance(void)
764 {
765     INSTANCE *ip = alloc_instance(var_config_dir);
766 
767     /*
768      * There is no need to load primary instance paramater settings from
769      * file. We already have the main.cf parameters of interest in memory.
770      */
771 #define SAVE_INSTANCE_NAME(val) (*(val) ? mystrdup(val) : 0)
772 
773     ip->name = SAVE_INSTANCE_NAME(var_multi_name);
774     ip->gname = SAVE_INSTANCE_NAME(var_multi_group);
775     ip->enabled = var_multi_enable;
776     ip->queue_dir = mystrdup(var_queue_dir);
777     ip->data_dir = mystrdup(var_data_dir);
778     ip->primary = 1;
779     return (ip);
780 }
781 
782 /* load_instance - read instance parameters from config_dir/main.cf */
783 
784 static INSTANCE *load_instance(INSTANCE *ip)
785 {
786     VSTREAM *pipe;
787     VSTRING *buf;
788     char   *name;
789     char   *value;
790     ARGV   *cmd;
791     int     count = 0;
792     static NAME_CODE bool_code[] = {
793 	CONFIG_BOOL_YES, 1,
794 	CONFIG_BOOL_NO, 0,
795 	0, -1,
796     };
797 
798     /*
799      * Expand parameter values in the context of the target main.cf file.
800      */
801 #define REQUEST_PARAM_COUNT 5			/* # of requested parameters */
802 
803     cmd = argv_alloc(REQUEST_PARAM_COUNT + 3);
804     name = concatenate(var_command_dir, "/", "postconf", (char *) 0);
805     argv_add(cmd, name, "-xc", ip->config_dir,
806 	     VAR_QUEUE_DIR, VAR_DATA_DIR,
807 	     VAR_MULTI_NAME, VAR_MULTI_GROUP, VAR_MULTI_ENABLE,
808 	     (char *) 0);
809     myfree(name);
810     pipe = vstream_popen(O_RDONLY, CA_VSTREAM_POPEN_ARGV(cmd->argv),
811 			 CA_VSTREAM_POPEN_END);
812     argv_free(cmd);
813     if (pipe == 0)
814 	msg_fatal("Cannot parse %s/main.cf file: %m", ip->config_dir);
815 
816     /*
817      * Read parameter settings from postconf. See also comments below on
818      * whether we should continue or skip groups after error instead of
819      * bailing out immediately.
820      */
821     buf = vstring_alloc(100);
822     while (vstring_get_nonl(buf, pipe) != VSTREAM_EOF) {
823 	if (split_nameval(STR(buf), &name, &value))
824 	    msg_fatal("Invalid %s/main.cf parameter: %s",
825 		      ip->config_dir, STR(buf));
826 	if (strcmp(name, VAR_QUEUE_DIR) == 0 && ++count)
827 	    ip->queue_dir = mystrdup(value);
828 	else if (strcmp(name, VAR_DATA_DIR) == 0 && ++count)
829 	    ip->data_dir = mystrdup(value);
830 	else if (strcmp(name, VAR_MULTI_NAME) == 0 && ++count)
831 	    ip->name = SAVE_INSTANCE_NAME(value);
832 	else if (strcmp(name, VAR_MULTI_GROUP) == 0 && ++count)
833 	    ip->gname = SAVE_INSTANCE_NAME(value);
834 	else if (strcmp(name, VAR_MULTI_ENABLE) == 0 && ++count) {
835 	    /* mail_conf_bool(3) is case insensitive! */
836 	    ip->enabled = name_code(bool_code, NAME_CODE_FLAG_NONE, value);
837 	    if (ip->enabled < 0)
838 		msg_fatal("Unexpected %s/main.cf entry: %s = %s",
839 			  ip->config_dir, VAR_MULTI_ENABLE, value);
840 	}
841     }
842     vstring_free(buf);
843 
844     /*
845      * XXX We should not bail out while reading a bad secondary main.cf file.
846      * When we manage dozens or more instances, the likelihood increases that
847      * some file will be damaged or missing after a system crash. That is not
848      * a good reason to prevent undamaged Postfix instances from starting.
849      */
850     if (count != REQUEST_PARAM_COUNT)
851 	msg_fatal("Failed to obtain all required %s/main.cf parameters",
852 		  ip->config_dir);
853 
854     if (vstream_pclose(pipe))
855 	msg_fatal("Cannot parse %s/main.cf file", ip->config_dir);
856     return (ip);
857 }
858 
859 /* load_all_instances - compute list of Postfix instances */
860 
861 static void load_all_instances(void)
862 {
863     INSTANCE *primary_instance;
864     char  **cpp;
865     ARGV   *secondary_names;
866 
867     /*
868      * Avoid unexpected behavior when $multi_instance_directories contains
869      * only comma characters. Count the actual number of elements, before we
870      * decide that the list is empty.
871      */
872     secondary_names = argv_split(var_multi_conf_dirs, CHARS_COMMA_SP);
873 
874     /*
875      * First, the primary instance.  This is synthesized out of thin air.
876      */
877     primary_instance = create_primary_instance();
878     if (secondary_names->argc == 0)
879 	primary_instance->enabled = 1;		/* Single-instance mode */
880     append_instance(primary_instance);
881 
882     /*
883      * Next, instances defined in $multi_instance_directories. Note:
884      * load_instance() has side effects on the global config dictionary, but
885      * this does not affect the values that have already been extracted into
886      * C variables.
887      */
888     for (cpp = secondary_names->argv; *cpp != 0; cpp++)
889 	append_instance(load_instance(alloc_instance(*cpp)));
890 
891     argv_free(secondary_names);
892 }
893 
894 /* match_instance_selection - match all/name/group constraints */
895 
896 static int match_instance_selection(INSTANCE *ip, INST_SELECTION *selection)
897 {
898     char   *iname;
899     char   *name;
900 
901     /*
902      * When selecting (rather than assigning names) an instance, we match by
903      * the instance name, config_directory path, or the instance name suffix
904      * (name without mandatory prefix). Selecting "-" selects the primary
905      * instance.
906      */
907     switch (selection->type) {
908     case INST_SEL_NONE:
909 	return (0);
910     case INST_SEL_ALL:
911 	return (1);
912     case INST_SEL_GROUP:
913 	return (ip->gname != 0 && strcmp(selection->name, ip->gname) == 0);
914     case INST_SEL_NAME:
915 	name = selection->name;
916 	if (*name == '/' || ip->name == 0)
917 	    iname = ip->config_dir;
918 	else if (!HAS_NAME_PREFIX(name) && HAS_NAME_PREFIX(ip->name))
919 	    iname = NAME_SUFFIX(ip->name);
920 	else
921 	    iname = ip->name;
922 	return (strcmp(name, iname) == 0
923 		|| (ip->primary && strcmp(name, "-") == 0));
924     default:
925 	msg_panic("match_instance_selection: unknown selection type: %d",
926 		  selection->type);
927     }
928 }
929 
930 /* check_setenv - setenv() with extreme prejudice */
931 
932 static void check_setenv(const char *name, const char *value)
933 {
934 #define CLOBBER 1
935     if (setenv(name, value, CLOBBER) < 0)
936 	msg_fatal("setenv: %m");
937 }
938 
939 /* prepend_command_path - prepend command_directory to PATH */
940 
941 static void prepend_command_path(void)
942 {
943     char   *cmd_path;
944 
945     /*
946      * Carefully prepend "$command_directory:" to PATH. We can free the
947      * buffer after check_setenv(), since the value is copied there.
948      */
949     cmd_path = safe_getenv("PATH");
950     cmd_path = concatenate(var_command_dir, ":", (cmd_path && *cmd_path) ?
951 			   cmd_path : ROOT_PATH, (char *) 0);
952     check_setenv("PATH", cmd_path);
953     myfree(cmd_path);
954 }
955 
956 /* check_shared_dir_status - check and claim shared directories */
957 
958 static void check_shared_dir_status(void)
959 {
960     struct stat st;
961     const SHARED_PATH *sp;
962 
963     /*
964      * XXX Avoid false conflicts with meta_directory. This usually overlaps
965      * with other directories, typcally config_directory, shlib_directory or
966      * daemon_directory.
967      */
968     for (sp = shared_dir_table; sp->param_name; ++sp) {
969 	if (sp->param_value[0][0] != '/')	/* "no" or other special */
970 	    continue;
971 	if (stat(sp->param_value[0], &st) < 0)
972 	    msg_fatal("%s = '%s': directory not found: %m",
973 		      sp->param_name, sp->param_value[0]);
974 	if (!S_ISDIR(st.st_mode))
975 	    msg_fatal("%s = '%s' is not a directory",
976 		      sp->param_name, sp->param_value[0]);
977 	if (strcmp(sp->param_name, VAR_META_DIR) == 0)
978 	    continue;
979 	register_claim(var_config_dir, sp->param_name, sp->param_value[0]);
980     }
981 }
982 
983 /* check_safe_name - allow instance or group name with only "safe" characters */
984 
985 static int check_safe_name(const char *s)
986 {
987 #define SAFE_PUNCT	"!@%-_=+:./"
988     if (*s == 0)
989 	return (0);
990     for (; *s; ++s) {
991 	if (!ISALNUM(*s) && !strchr(SAFE_PUNCT, *s))
992 	    return (0);
993     }
994     return (1);
995 }
996 
997 /* check_name_assignments - Check validity of assigned instance or group name */
998 
999 static void check_name_assignments(NAME_ASSIGNMENT *assignment)
1000 {
1001 
1002     /*
1003      * Syntax check the assigned instance name. This name is also used to
1004      * generate directory pathnames, so we must not allow "/" characters.
1005      *
1006      * The value "" will clear the name and is always valid. The command-line
1007      * parser has already converted "-" into "", to simplify implementation.
1008      */
1009     if (assignment->name && *assignment->name) {
1010 	if (!check_safe_name(assignment->name))
1011 	    msg_fatal("Unsafe characters in new instance name: '%s'",
1012 		      assignment->name);
1013 	if (strchr(assignment->name, '/'))
1014 	    msg_fatal("Illegal '/' character in new instance name: '%s'",
1015 		      assignment->name);
1016 	if (NEED_NAME_PREFIX(assignment->name))
1017 	    msg_fatal("New instance name must start with '%s'",
1018 		      NAME_PREFIX);
1019     }
1020 
1021     /*
1022      * Syntax check the assigned group name.
1023      */
1024     if (assignment->gname && *assignment->gname) {
1025 	if (!check_safe_name(assignment->gname))
1026 	    msg_fatal("Unsafe characters in '-G %s'", assignment->gname);
1027     }
1028 }
1029 
1030 /* do_name_assignments - assign instance/group names */
1031 
1032 static int do_name_assignments(INSTANCE *target, NAME_ASSIGNMENT *assignment)
1033 {
1034     int     export_flags = 0;
1035 
1036     /*
1037      * The command-line parser has already converted "-" into "", to simplify
1038      * implementation.
1039      */
1040     if (assignment->name
1041 	&& strcmp(assignment->name, target->name ? target->name : "")) {
1042 	register_claim(target->config_dir, VAR_MULTI_NAME, assignment->name);
1043 	if (target->name)
1044 	    myfree(target->name);
1045 	target->name = SAVE_INSTANCE_NAME(assignment->name);
1046 	export_flags |= EXP_FLAG_MULTI_NAME;
1047     }
1048     if (assignment->gname
1049 	&& strcmp(assignment->gname, target->gname ? target->gname : "")) {
1050 	if (target->gname)
1051 	    myfree(target->gname);
1052 	target->gname = SAVE_INSTANCE_NAME(assignment->gname);
1053 	export_flags |= EXP_FLAG_MULTI_GROUP;
1054     }
1055     return (export_flags);
1056 }
1057 
1058 /* make_private_path - generate secondary pathname using primary as template */
1059 
1060 static char *make_private_path(const char *param_name,
1061 			               const char *primary_value,
1062 			               NAME_ASSIGNMENT *assignment)
1063 {
1064     char   *path;
1065     char   *base;
1066     char   *end;
1067 
1068     /*
1069      * The command-line parser has already converted "-" into "", to simplify
1070      * implementation.
1071      */
1072     if (assignment->name == 0 || *assignment->name == 0)
1073 	msg_fatal("Missing %s parameter value", param_name);
1074 
1075     if (*primary_value != '/')
1076 	msg_fatal("Invalid default %s parameter value: '%s': "
1077 		  "specify an absolute pathname",
1078 		  param_name, primary_value);
1079 
1080     base = mystrdup(primary_value);
1081     if ((end = strrchr(base, '/')) != 0) {
1082 	/* Drop trailing slashes */
1083 	if (end[1] == '\0') {
1084 	    while (--end > base && *end == '/')
1085 		*end = '\0';
1086 	    end = strrchr(base, '/');
1087 	}
1088 	/* Drop last path component */
1089 	while (end > base && *end == '/')
1090 	    *end-- = '\0';
1091     }
1092     path = concatenate(base[1] ? base : "", "/",
1093 		       assignment->name, (char *) 0);
1094     myfree(base);
1095     return (path);
1096 }
1097 
1098 /* assign_new_parameter - assign new instance private name=value */
1099 
1100 static void assign_new_parameter(INSTANCE *new, int edit_cmd,
1101 				         const char *arg)
1102 {
1103     char   *saved_arg;
1104     char   *name;
1105     char   *value;
1106     char   *end;
1107     char  **target = 0;
1108 
1109     /*
1110      * With "import", only config_directory is specified on the command line
1111      * (either explicitly as config_directory=/path/name, or implicitly as
1112      * instance name). The other private directory pathnames are taken from
1113      * the existing instance's main.cf file.
1114      *
1115      * With "create", all private pathname parameters are specified on the
1116      * command line, or generated from an instance name.
1117      */
1118     saved_arg = mystrdup(arg);
1119     if (split_nameval(saved_arg, &name, &value))
1120 	msg_fatal("Malformed parameter setting '%s'", arg);
1121 
1122     if (strcmp(VAR_CONFIG_DIR, name) == 0) {
1123 	target = &new->config_dir;
1124     } else if (edit_cmd != EDIT_CMD_IMPORT) {
1125 	if (strcmp(VAR_QUEUE_DIR, name) == 0) {
1126 	    target = &new->queue_dir;
1127 	} else if (strcmp(VAR_DATA_DIR, name) == 0) {
1128 	    target = &new->data_dir;
1129 	}
1130     }
1131     if (target == 0)
1132 	msg_fatal("Parameter '%s' not valid with action %s",
1133 		  name, EDIT_CMD_STR(edit_cmd));
1134 
1135     /*
1136      * Extract and assign the parameter value. We do a limited number of
1137      * checks here. Conflicts between instances are checked by the caller.
1138      * More checks may be implemented in the helper script if inspired.
1139      */
1140     if (*value != '/')
1141 	msg_fatal("Parameter setting '%s' is not an absolute path", name);
1142 
1143     /* Tolerate+trim trailing "/" from readline completion */
1144     for (end = value + strlen(value) - 1; end > value && *end == '/'; --end)
1145 	*end = 0;
1146 
1147     /* No checks here for "/." or other shoot-foot silliness. */
1148     if (end == value)
1149 	msg_fatal("Parameter setting '%s' is the root directory", name);
1150 
1151     if (*target)
1152 	myfree(*target);
1153     *target = mystrdup(value);
1154 
1155     /*
1156      * Cleanup.
1157      */
1158     myfree(saved_arg);
1159 }
1160 
1161 /* assign_new_parameters - initialize new instance private parameters */
1162 
1163 static void assign_new_parameters(INSTANCE *new, int edit_cmd,
1164 			           char **argv, NAME_ASSIGNMENT *assignment)
1165 {
1166     const char *owner;
1167 
1168     /*
1169      * Sanity check the explicit parameter settings. More stringent checks
1170      * may take place in the helper script.
1171      */
1172     while (*argv)
1173 	assign_new_parameter(new, edit_cmd, *argv++);
1174 
1175     /*
1176      * Initialize any missing private directory pathnames, using the primary
1177      * configuration directory parameter values as a template, and using the
1178      * assigned instance name to fill in the blanks.
1179      *
1180      * When importing an existing instance, load private directory pathnames
1181      * from its main.cf file.
1182      */
1183     if (new->config_dir == 0)
1184 	new->config_dir =
1185 	    make_private_path(VAR_CONFIG_DIR, var_config_dir, assignment);
1186     /* Needed for better-quality error message. */
1187     if ((owner = IS_CLAIMED_BY(new->config_dir)) != 0)
1188 	msg_fatal("new %s=%s is already in use by instance %s=%s",
1189 		  VAR_CONFIG_DIR, new->config_dir, owner, new->config_dir);
1190     if (edit_cmd != EDIT_CMD_IMPORT) {
1191 	if (new->queue_dir == 0)
1192 	    new->queue_dir =
1193 		make_private_path(VAR_QUEUE_DIR, var_queue_dir, assignment);
1194 	if (new->data_dir == 0)
1195 	    new->data_dir =
1196 		make_private_path(VAR_DATA_DIR, var_data_dir, assignment);
1197     } else {
1198 	load_instance(new);
1199     }
1200 }
1201 
1202 /* export_helper_environment - update environment settings for helper command */
1203 
1204 static void export_helper_environment(INSTANCE *target, int export_flags)
1205 {
1206     ARGV   *import_env;
1207     VSTRING *multi_dirs;
1208     const SHARED_PATH *sp;
1209     RING   *entry;
1210 
1211     /*
1212      * Environment import filter, to enforce consistent behavior whether this
1213      * command is started by hand, or at system boot time. This is necessary
1214      * because some shell scripts use environment settings to override
1215      * main.cf settings.
1216      */
1217     import_env = mail_parm_split(VAR_IMPORT_ENVIRON, var_import_environ);
1218     clean_env(import_env->argv);
1219     argv_free(import_env);
1220 
1221     /*
1222      * Prepend $command_directory: to PATH. This supposedly ensures that
1223      * naive programs will execute commands from the right Postfix version.
1224      */
1225     prepend_command_path();
1226 
1227     /*
1228      * The following ensures that Postfix's own programs will target the
1229      * primary instance.
1230      */
1231     check_setenv(CONF_ENV_PATH, var_config_dir);
1232 
1233     /*
1234      * Export the parameter settings that are shared between instances.
1235      */
1236     for (sp = shared_dir_table; sp->param_name; ++sp)
1237 	check_setenv(sp->param_name, sp->param_value[0]);
1238 
1239     /*
1240      * Export the target instance's private directory locations.
1241      */
1242     check_setenv(VAR_CONFIG_DIR, target->config_dir);
1243     check_setenv(VAR_QUEUE_DIR, target->queue_dir);
1244     check_setenv(VAR_DATA_DIR, target->data_dir);
1245 
1246     /*
1247      * With operations that add or delete a secondary instance, we export the
1248      * modified multi_instance_directories parameter value for the primary
1249      * Postfix instance.
1250      */
1251     if (export_flags & EXP_FLAG_MULTI_DIRS) {
1252 	multi_dirs = vstring_alloc(100);
1253 	FOREACH_SECONDARY_INSTANCE(entry) {
1254 	    if (VSTRING_LEN(multi_dirs) > 0)
1255 		VSTRING_ADDCH(multi_dirs, ' ');
1256 	    vstring_strcat(multi_dirs, RING_TO_INSTANCE(entry)->config_dir);
1257 	}
1258 	check_setenv(VAR_MULTI_CONF_DIRS, STR(multi_dirs));
1259 	vstring_free(multi_dirs);
1260     }
1261 
1262     /*
1263      * Export updates for the instance name and group. Empty value (or no
1264      * export) means don't update, "-" means clear.
1265      */
1266     if (export_flags & EXP_FLAG_MULTI_NAME)
1267 	check_setenv(VAR_MULTI_NAME, target->name && *target->name ?
1268 		     target->name : "-");
1269 
1270     if (export_flags & EXP_FLAG_MULTI_GROUP)
1271 	check_setenv(VAR_MULTI_GROUP, target->gname && *target->gname ?
1272 		     target->gname : "-");
1273 
1274     /*
1275      * If we would implement enable/disable commands by exporting the updated
1276      * parameter value, then we could skip commands that have no effect, just
1277      * like we can skip "assign" commands that make no change.
1278      */
1279 }
1280 
1281 /* install_new_instance - install and return newly created instance */
1282 
1283 static INSTANCE *install_new_instance(int edit_cmd, char **argv,
1284 				              INST_SELECTION *selection,
1285 				              NAME_ASSIGNMENT *assignment,
1286 				              int *export_flags)
1287 {
1288     INSTANCE *new;
1289 
1290     new = alloc_instance((char *) 0);
1291     check_name_assignments(assignment);
1292     assign_new_parameters(new, edit_cmd, argv, assignment);
1293     *export_flags |=
1294 	(do_name_assignments(new, assignment) | EXP_FLAG_MULTI_DIRS);
1295     insert_instance(new, selection);
1296     return (new);
1297 }
1298 
1299 /* update_instance - update existing instance, return export flags */
1300 
1301 static int update_instance(INSTANCE *target, NAME_ASSIGNMENT *assignment)
1302 {
1303     int     export_flags;
1304 
1305     check_name_assignments(assignment);
1306     export_flags = do_name_assignments(target, assignment);
1307     return (export_flags);
1308 }
1309 
1310 /* select_existing_instance - return instance selected for management */
1311 
1312 static INSTANCE *select_existing_instance(INST_SELECTION *selection,
1313 					          int unlink_flag,
1314 					          int *export_flags)
1315 {
1316     INSTANCE *selected = 0;
1317     RING   *entry;
1318     INSTANCE *ip;
1319 
1320 #define DONT_UNLINK	0
1321 #define DO_UNLINK	1
1322 
1323     if (selection->type != INST_SEL_NAME)
1324 	msg_fatal("Select an instance via '-i name'");
1325 
1326     /* Find the selected instance and its predecessor */
1327     FOREACH_INSTANCE(entry) {
1328 	if (match_instance_selection(ip = RING_TO_INSTANCE(entry), selection)) {
1329 	    selected = ip;
1330 	    break;
1331 	}
1332     }
1333 
1334     if (selected == 0)
1335 	msg_fatal("No instance named %s", selection->name);
1336 
1337     if (unlink_flag) {
1338 	/* Splice the target instance out of the list */
1339 	if (ring_pred(entry) == instance_hd)
1340 	    msg_fatal("Cannot remove the primary instance");
1341 	if (selected->enabled)
1342 	    msg_fatal("Cannot remove enabled instances");
1343 	ring_detach(entry);
1344 	if (export_flags == 0)
1345 	    msg_panic("select_existing_instance: no export flags");
1346 	*export_flags |= EXP_FLAG_MULTI_DIRS;
1347     }
1348     return (selected);
1349 }
1350 
1351 /* manage - create/destroy/... manage instances */
1352 
1353 static NORETURN manage(int edit_cmd, int argc, char **argv,
1354 		               INST_SELECTION *selection,
1355 		               NAME_ASSIGNMENT *assignment)
1356 {
1357     char   *cmd;
1358     INSTANCE *target;
1359     int     export_flags;
1360 
1361     /*
1362      * Edit mode is not subject to iterator controls.
1363      */
1364 #define NO_EXPORT_FLAGS		((int *) 0)
1365     export_flags = 0;
1366 
1367     switch (edit_cmd) {
1368     case EDIT_CMD_INIT:
1369 	target = create_primary_instance();
1370 	break;
1371 
1372     case EDIT_CMD_CREATE:
1373     case EDIT_CMD_IMPORT:
1374 	load_all_instances();
1375 	target = install_new_instance(edit_cmd, argv, selection,
1376 				      assignment, &export_flags);
1377 	break;
1378 
1379     case EDIT_CMD_ASSIGN:
1380 	load_all_instances();
1381 	target =
1382 	    select_existing_instance(selection, DONT_UNLINK, NO_EXPORT_FLAGS);
1383 	export_flags |= update_instance(target, assignment);
1384 	if (export_flags == 0)
1385 	    exit(0);
1386 	break;
1387 
1388     case EDIT_CMD_DESTROY:
1389     case EDIT_CMD_DEPORT:
1390 	load_all_instances();
1391 	target = select_existing_instance(selection, DO_UNLINK, &export_flags);
1392 	break;
1393 
1394     default:
1395 	load_all_instances();
1396 	target =
1397 	    select_existing_instance(selection, DONT_UNLINK, NO_EXPORT_FLAGS);
1398 	break;
1399     }
1400 
1401     /*
1402      * Set up the helper script's process environment, and execute the helper
1403      * script.
1404      */
1405 #define HELPER "postmulti-script"
1406 
1407     export_helper_environment(target, export_flags);
1408     cmd = concatenate(var_daemon_dir, "/" HELPER, (char *) 0);
1409     execl(cmd, cmd, "-e", EDIT_CMD_STR(edit_cmd), (char *) 0);
1410     msg_fatal("%s: %m", cmd);
1411 }
1412 
1413 /* run_user_command - execute external command with requested MAIL_CONFIG env */
1414 
1415 static int run_user_command(INSTANCE *ip, int iter_cmd, int iter_flags,
1416 			            char **argv)
1417 {
1418     WAIT_STATUS_T status;
1419     int     pid;
1420     int     wpid;
1421 
1422     /*
1423      * Set up a process environment. The postfix(1) command needs MAIL_CONFIG
1424      * (or the equivalent command-line option); it overrides everything else.
1425      *
1426      * postmulti(1) typically runs various Postfix utilities (postsuper, ...) in
1427      * the context of one or more instances. It can also run various scripts
1428      * on the users PATH. So we can't clobber the user's PATH, but do want to
1429      * make sure that the utilities in $command_directory are always found in
1430      * the right place (or at all).
1431      */
1432     switch (pid = fork()) {
1433     case -1:
1434 	msg_warn("fork %s: %m", argv[0]);
1435 	return -1;
1436     case 0:
1437 	check_setenv(CONF_ENV_PATH, ip->config_dir);
1438 	if (iter_cmd != ITER_CMD_POSTFIX) {
1439 	    check_setenv(VAR_DAEMON_DIR, var_daemon_dir);
1440 	    check_setenv(VAR_COMMAND_DIR, var_command_dir);
1441 	    check_setenv(VAR_CONFIG_DIR, ip->config_dir);
1442 	    check_setenv(VAR_QUEUE_DIR, ip->queue_dir);
1443 	    check_setenv(VAR_DATA_DIR, ip->data_dir);
1444 	    check_setenv(VAR_MULTI_NAME, ip->name ? ip->name : "");
1445 	    check_setenv(VAR_MULTI_GROUP, ip->gname ? ip->gname : "");
1446 	    check_setenv(VAR_MULTI_ENABLE, ip->enabled ?
1447 			 CONFIG_BOOL_YES : CONFIG_BOOL_NO);
1448 	    prepend_command_path();
1449 	}
1450 
1451 	/*
1452 	 * Replace: postfix -- start ... With: postfix -- check ...
1453 	 */
1454 	if (iter_cmd == ITER_CMD_POSTFIX
1455 	    && (iter_flags & ITER_FLAG_CHECK_DISABLED) && !ip->enabled)
1456 	    argv[2] = "check";
1457 
1458 	execvp(argv[0], argv);
1459 	msg_fatal("execvp %s: %m", argv[0]);
1460     default:
1461 	do {
1462 	    wpid = waitpid(pid, &status, 0);
1463 	} while (wpid == -1 && errno == EINTR);
1464 	return (wpid == -1 ? -1 :
1465 		WIFEXITED(status) ? WEXITSTATUS(status) : 1);
1466     }
1467 }
1468 
1469 /* word_in_list - look up command in start, stop, or control list */
1470 
1471 static int word_in_list(char *cmdlist, const char *cmd)
1472 {
1473     char   *saved;
1474     char   *cp;
1475     char   *elem;
1476 
1477     cp = saved = mystrdup(cmdlist);
1478     while ((elem = mystrtok(&cp, CHARS_COMMA_SP)) != 0 && strcmp(elem, cmd) != 0)
1479 	 /* void */ ;
1480     myfree(saved);
1481     return (elem != 0);
1482 }
1483 
1484 /* iterate_postfix_command - execute postfix(1) command */
1485 
1486 static int iterate_postfix_command(int iter_cmd, int argc, char **argv,
1487 				           INST_SELECTION *selection)
1488 {
1489     int     exit_status;
1490     char   *cmd;
1491     ARGV   *my_argv;
1492     int     iter_flags;
1493 
1494     /*
1495      * Override the iterator controls.
1496      */
1497     if (word_in_list(var_multi_start_cmds, argv[0])) {
1498 	iter_flags = ITER_FLAG_CHECK_DISABLED;
1499     } else if (word_in_list(var_multi_stop_cmds, argv[0])) {
1500 	iter_flags = ITER_FLAG_SKIP_DISABLED | ITER_FLAG_REVERSE;
1501     } else if (word_in_list(var_multi_cntrl_cmds, argv[0])) {
1502 	iter_flags = ITER_FLAG_SKIP_DISABLED;
1503     } else {
1504 	iter_flags = 0;
1505     }
1506 
1507     /*
1508      * Override the command line in a straightforward manner: prepend
1509      * "postfix --" to the command arguments. Other overrides (environment,
1510      * start -> check) are implemented below the iterator.
1511      */
1512 #define POSTFIX_CMD	"postfix"
1513 
1514     my_argv = argv_alloc(argc + 2);
1515     cmd = concatenate(var_command_dir, "/" POSTFIX_CMD, (char *) 0);
1516     argv_add(my_argv, cmd, "--", (char *) 0);
1517     myfree(cmd);
1518     while (*argv)
1519 	argv_add(my_argv, *argv++, (char *) 0);
1520 
1521     /*
1522      * Execute the command for all applicable Postfix instances.
1523      */
1524     exit_status =
1525 	iterate_command(iter_cmd, iter_flags, my_argv->argv, selection);
1526 
1527     argv_free(my_argv);
1528     return (exit_status);
1529 }
1530 
1531 /* list_instances - list all selected instances */
1532 
1533 static void list_instances(int iter_flags, INST_SELECTION *selection)
1534 {
1535     RING   *entry;
1536     INSTANCE *ip;
1537 
1538     /*
1539      * Iterate over the selected instances.
1540      */
1541     FOREACH_ITERATOR_INSTANCE(iter_flags, entry) {
1542 	ip = RING_TO_INSTANCE(entry);
1543 	if (match_instance_selection(ip, selection))
1544 	    vstream_printf("%-15s %-15s %-9s %s\n",
1545 			   ip->name ? ip->name : "-",
1546 			   ip->gname ? ip->gname : "-",
1547 			   ip->enabled ? "y" : "n",
1548 			   ip->config_dir);
1549     }
1550     if (vstream_fflush(VSTREAM_OUT))
1551 	msg_fatal("error writing output: %m");
1552 }
1553 
1554 /* iterate_command - execute command for selected instances */
1555 
1556 static int iterate_command(int iter_cmd, int iter_flags, char **argv,
1557 			           INST_SELECTION *selection)
1558 {
1559     int     exit_status = 0;
1560     int     matched = 0;
1561     RING   *entry;
1562     INSTANCE *ip;
1563 
1564     /*
1565      * Iterate over the selected instances.
1566      */
1567     FOREACH_ITERATOR_INSTANCE(iter_flags, entry) {
1568 	ip = RING_TO_INSTANCE(entry);
1569 	if ((iter_flags & ITER_FLAG_SKIP_DISABLED) && !ip->enabled)
1570 	    continue;
1571 	if (!match_instance_selection(ip, selection))
1572 	    continue;
1573 	matched = 1;
1574 
1575 	/* Run the requested command */
1576 	if (run_user_command(ip, iter_cmd, iter_flags, argv) != 0)
1577 	    exit_status = 1;
1578     }
1579     if (matched == 0)
1580 	msg_fatal("No matching instances");
1581 
1582     return (exit_status);
1583 }
1584 
1585 /* iterate - Iterate over all or selected instances */
1586 
1587 static NORETURN iterate(int iter_cmd, int iter_flags, int argc, char **argv,
1588 			        INST_SELECTION *selection)
1589 {
1590     int     exit_status;
1591 
1592     /*
1593      * In iterator mode, no selection means wild-card selection.
1594      */
1595     if (selection->type == INST_SEL_NONE)
1596 	selection->type = INST_SEL_ALL;
1597 
1598     /*
1599      * Load the in-memory instance table from main.cf files.
1600      */
1601     load_all_instances();
1602 
1603     /*
1604      * Iterate over the selected instances.
1605      */
1606     switch (iter_cmd) {
1607     case ITER_CMD_POSTFIX:
1608 	exit_status = iterate_postfix_command(iter_cmd, argc, argv, selection);
1609 	break;
1610     case ITER_CMD_LIST:
1611 	list_instances(iter_flags, selection);
1612 	exit_status = 0;
1613 	break;
1614     case ITER_CMD_GENERIC:
1615 	exit_status = iterate_command(iter_cmd, iter_flags, argv, selection);
1616 	break;
1617     default:
1618 	msg_panic("iterate: unknown mode: %d", iter_cmd);
1619     }
1620     exit(exit_status);
1621 }
1622 
1623 static NORETURN usage(const char *progname)
1624 {
1625     msg_fatal("Usage:"
1626 	      "%s -l [-v] [-a] [-g group] [-i instance] | "
1627 	      "%s -p [-v] [-a] [-g group] [-i instance] command... | "
1628 	      "%s -x [-v] [-a] [-i name] [-g group] command... | "
1629 	      "%s -e action [-v] [-a] [-i name] [-g group] [-I name] "
1630 	      "[-G group] [param=value ...]",
1631 	      progname, progname, progname, progname);
1632 }
1633 
1634 MAIL_VERSION_STAMP_DECLARE;
1635 
1636 /* main - iterate commands over multiple instance or manage instances */
1637 
1638 int     main(int argc, char **argv)
1639 {
1640     int     fd;
1641     struct stat st;
1642     char   *slash;
1643     char   *config_dir;
1644     int     ch;
1645     static const CONFIG_STR_TABLE str_table[] = {
1646 	VAR_MULTI_START_CMDS, DEF_MULTI_START_CMDS, &var_multi_start_cmds, 0, 0,
1647 	VAR_MULTI_STOP_CMDS, DEF_MULTI_STOP_CMDS, &var_multi_stop_cmds, 0, 0,
1648 	VAR_MULTI_CNTRL_CMDS, DEF_MULTI_CNTRL_CMDS, &var_multi_cntrl_cmds, 0, 0,
1649 	0,
1650     };
1651     int     instance_select_count = 0;
1652     int     command_mode_count = 0;
1653     INST_SELECTION selection;
1654     NAME_ASSIGNMENT assignment;
1655     int     iter_flags = ITER_FLAG_DEFAULT;
1656     int     cmd_mode = 0;
1657     int     code;
1658 
1659     selection.type = INST_SEL_NONE;
1660     assignment.name = assignment.gname = 0;
1661 
1662     /*
1663      * Fingerprint executables and core dumps.
1664      */
1665     MAIL_VERSION_STAMP_ALLOCATE;
1666 
1667     /*
1668      * Be consistent with file permissions.
1669      */
1670     umask(022);
1671 
1672     /*
1673      * To minimize confusion, make sure that the standard file descriptors
1674      * are open before opening anything else. XXX Work around for 44BSD where
1675      * fstat can return EBADF on an open file descriptor.
1676      */
1677     for (fd = 0; fd < 3; fd++)
1678 	if (fstat(fd, &st) == -1
1679 	    && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
1680 	    msg_fatal("open /dev/null: %m");
1681 
1682     /*
1683      * Set up diagnostics. XXX What if stdin is the system console during
1684      * boot time? It seems a bad idea to log startup errors to the console.
1685      * This is UNIX, a system that can run without hand holding.
1686      */
1687     if ((slash = strrchr(argv[0], '/')) != 0 && slash[1])
1688 	argv[0] = slash + 1;
1689     if (isatty(STDERR_FILENO))
1690 	msg_vstream_init(argv[0], VSTREAM_ERR);
1691     msg_syslog_init(argv[0], LOG_PID, LOG_FACILITY);
1692 
1693     /*
1694      * Check the Postfix library version as soon as we enable logging.
1695      */
1696     MAIL_VERSION_CHECK;
1697 
1698     if ((config_dir = getenv(CONF_ENV_PATH)) != 0
1699 	&& strcmp(config_dir, DEF_CONFIG_DIR) != 0)
1700 	msg_fatal("Non-default configuration directory: %s=%s",
1701 		  CONF_ENV_PATH, config_dir);
1702 
1703     /*
1704      * Parse switches.
1705      */
1706     while ((ch = GETOPT(argc, argv, "ae:g:i:G:I:lpRvx")) > 0) {
1707 	switch (ch) {
1708 	default:
1709 	    usage(argv[0]);
1710 	    /* NOTREACHED */
1711 	case 'a':
1712 	    if (selection.type != INST_SEL_ALL)
1713 		instance_select_count++;
1714 	    selection.type = INST_SEL_ALL;
1715 	    break;
1716 	case 'e':
1717 	    if ((code = EDIT_CMD_CODE(optarg)) < 0)
1718 		msg_fatal("Invalid '-e' edit action '%s'. Specify '%s', "
1719 			  "'%s', '%s', '%s', '%s', '%s', '%s' or '%s'",
1720 			  optarg,
1721 			  EDIT_CMD_STR(EDIT_CMD_CREATE),
1722 			  EDIT_CMD_STR(EDIT_CMD_DESTROY),
1723 			  EDIT_CMD_STR(EDIT_CMD_IMPORT),
1724 			  EDIT_CMD_STR(EDIT_CMD_DEPORT),
1725 			  EDIT_CMD_STR(EDIT_CMD_ENABLE),
1726 			  EDIT_CMD_STR(EDIT_CMD_DISABLE),
1727 			  EDIT_CMD_STR(EDIT_CMD_ASSIGN),
1728 			  EDIT_CMD_STR(EDIT_CMD_INIT));
1729 	    if (cmd_mode != code)
1730 		command_mode_count++;
1731 	    cmd_mode = code;
1732 	    break;
1733 	case 'g':
1734 	    instance_select_count++;
1735 	    selection.type = INST_SEL_GROUP;
1736 	    selection.name = optarg;
1737 	    break;
1738 	case 'i':
1739 	    instance_select_count++;
1740 	    selection.type = INST_SEL_NAME;
1741 	    selection.name = optarg;
1742 	    break;
1743 	case 'G':
1744 	    if (assignment.gname != 0)
1745 		msg_fatal("Specify at most one '-G' option");
1746 	    assignment.gname = strcmp(optarg, "-") == 0 ? "" : optarg;
1747 	    break;
1748 	case 'I':
1749 	    if (assignment.name != 0)
1750 		msg_fatal("Specify at most one '-I' option");
1751 	    assignment.name = strcmp(optarg, "-") == 0 ? "" : optarg;
1752 	    break;
1753 	case 'l':
1754 	    if (cmd_mode != ITER_CMD_LIST)
1755 		command_mode_count++;
1756 	    cmd_mode = ITER_CMD_LIST;
1757 	    break;
1758 	case 'p':
1759 	    if (cmd_mode != ITER_CMD_POSTFIX)
1760 		command_mode_count++;
1761 	    cmd_mode = ITER_CMD_POSTFIX;
1762 	    break;
1763 	case 'R':
1764 	    iter_flags ^= ITER_FLAG_REVERSE;
1765 	    break;
1766 	case 'v':
1767 	    msg_verbose++;
1768 	    check_setenv(CONF_ENV_VERB, "");
1769 	    break;
1770 	case 'x':
1771 	    if (cmd_mode != ITER_CMD_GENERIC)
1772 		command_mode_count++;
1773 	    cmd_mode = ITER_CMD_GENERIC;
1774 	    break;
1775 	}
1776     }
1777 
1778     /*
1779      * Report missing arguments, or wrong arguments in the wrong context.
1780      */
1781     if (instance_select_count > 1)
1782 	msg_fatal("Specity no more than one of '-a', '-g', '-i'");
1783 
1784     if (command_mode_count != 1)
1785 	msg_fatal("Specify exactly one of '-e', '-l', '-p', '-x'");
1786 
1787     if (cmd_mode == ITER_CMD_LIST && argc > optind)
1788 	msg_fatal("Command not allowed with '-l'");
1789 
1790     if (cmd_mode == ITER_CMD_POSTFIX || cmd_mode == ITER_CMD_GENERIC)
1791 	if (argc == optind)
1792 	    msg_fatal("Command required with '-p' or '-x' option");
1793 
1794     if (cmd_mode == ITER_CMD_POSTFIX || (cmd_mode & EDIT_CMD_MASK_ALL))
1795 	if (iter_flags != ITER_FLAG_DEFAULT)
1796 	    msg_fatal("The '-p' and '-e' options preclude the use of '-R'");
1797 
1798     if ((cmd_mode & EDIT_CMD_MASK_ASSIGN) == 0
1799 	&& (assignment.name || assignment.gname)) {
1800 	if ((cmd_mode & EDIT_CMD_MASK_ALL) == 0)
1801 	    msg_fatal("Cannot assign instance name or group without '-e %s'",
1802 		      EDIT_CMD_STR(EDIT_CMD_ASSIGN));
1803 	else
1804 	    msg_fatal("Cannot assign instance name or group with '-e %s'",
1805 		      EDIT_CMD_STR(cmd_mode));
1806     }
1807     if (cmd_mode & EDIT_CMD_MASK_ALL) {
1808 	if (cmd_mode == EDIT_CMD_ASSIGN
1809 	    && (assignment.name == 0 && assignment.gname == 0))
1810 	    msg_fatal("Specify new instance name or group with '-e %s'",
1811 		      EDIT_CMD_STR(cmd_mode));
1812 
1813 	if ((cmd_mode & ~EDIT_CMD_MASK_ADD) != 0 && argc > optind)
1814 	    msg_fatal("Parameter overrides not valid with '-e %s'",
1815 		      EDIT_CMD_STR(cmd_mode));
1816     }
1817 
1818     /*
1819      * Proces main.cf parameters.
1820      */
1821     mail_conf_read();
1822     get_mail_conf_str_table(str_table);
1823 
1824     /*
1825      * Sanity checks.
1826      */
1827     check_shared_dir_status();
1828 
1829     /*
1830      * Iterate over selected instances, or manipulate one instance.
1831      */
1832     if (cmd_mode & ITER_CMD_MASK_ALL)
1833 	iterate(cmd_mode, iter_flags, argc - optind, argv + optind, &selection);
1834     else
1835 	manage(cmd_mode, argc - optind, argv + optind, &selection, &assignment);
1836 }
1837