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