Postfix3.3.1
postlock.c
[詳解]
1 /*++
2 /* NAME
3 /* postlock 1
4 /* SUMMARY
5 /* lock mail folder and execute command
6 /* SYNOPSIS
7 /* .fi
8 /* \fBpostlock\fR [\fB-c \fIconfig_dir\fR] [\fB-l \fIlock_style\fR]
9 /* [\fB-v\fR] \fIfile command...\fR
10 /* DESCRIPTION
11 /* The \fBpostlock\fR(1) command locks \fIfile\fR for exclusive
12 /* access, and executes \fIcommand\fR. The locking method is
13 /* compatible with the Postfix UNIX-style local delivery agent.
14 /*
15 /* Options:
16 /* .IP "\fB-c \fIconfig_dir\fR"
17 /* Read the \fBmain.cf\fR configuration file in the named directory
18 /* instead of the default configuration directory.
19 /* .IP "\fB-l \fIlock_style\fR"
20 /* Override the locking method specified via the
21 /* \fBmailbox_delivery_lock\fR configuration parameter (see below).
22 /* .IP \fB-v\fR
23 /* Enable verbose logging for debugging purposes. Multiple \fB-v\fR
24 /* options make the software increasingly verbose.
25 /* .PP
26 /* Arguments:
27 /* .IP \fIfile\fR
28 /* A mailbox file. The user should have read/write permission.
29 /* .IP \fIcommand...\fR
30 /* The command to execute while \fIfile\fR is locked for exclusive
31 /* access. The command is executed directly, i.e. without
32 /* interpretation by a shell command interpreter.
33 /* DIAGNOSTICS
34 /* The result status is 75 (EX_TEMPFAIL) when \fBpostlock\fR(1)
35 /* could not perform the requested operation. Otherwise, the
36 /* exit status is the exit status from the command.
37 /* BUGS
38 /* With remote file systems, the ability to acquire a lock does not
39 /* necessarily eliminate access conflicts. Avoid file access by
40 /* processes running on different machines.
41 /* ENVIRONMENT
42 /* .ad
43 /* .fi
44 /* .IP \fBMAIL_CONFIG\fR
45 /* Directory with Postfix configuration files.
46 /* .IP \fBMAIL_VERBOSE\fR
47 /* Enable verbose logging for debugging purposes.
48 /* CONFIGURATION PARAMETERS
49 /* .ad
50 /* .fi
51 /* The following \fBmain.cf\fR parameters are especially relevant to
52 /* this program.
53 /* The text below provides only a parameter summary. See
54 /* \fBpostconf\fR(5) for more details including examples.
55 /* LOCKING CONTROLS
56 /* .ad
57 /* .fi
58 /* .IP "\fBdeliver_lock_attempts (20)\fR"
59 /* The maximal number of attempts to acquire an exclusive lock on a
60 /* mailbox file or \fBbounce\fR(8) logfile.
61 /* .IP "\fBdeliver_lock_delay (1s)\fR"
62 /* The time between attempts to acquire an exclusive lock on a mailbox
63 /* file or \fBbounce\fR(8) logfile.
64 /* .IP "\fBstale_lock_time (500s)\fR"
65 /* The time after which a stale exclusive mailbox lockfile is removed.
66 /* .IP "\fBmailbox_delivery_lock (see 'postconf -d' output)\fR"
67 /* How to lock a UNIX-style \fBlocal\fR(8) mailbox before attempting delivery.
68 /* RESOURCE AND RATE CONTROLS
69 /* .ad
70 /* .fi
71 /* .IP "\fBfork_attempts (5)\fR"
72 /* The maximal number of attempts to fork() a child process.
73 /* .IP "\fBfork_delay (1s)\fR"
74 /* The delay between attempts to fork() a child process.
75 /* MISCELLANEOUS CONTROLS
76 /* .ad
77 /* .fi
78 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
79 /* The default location of the Postfix main.cf and master.cf
80 /* configuration files.
81 /* .IP "\fBimport_environment (see 'postconf -d' output)\fR"
82 /* The list of environment parameters that a privileged Postfix
83 /* process will import from a non-Postfix parent process, or name=value
84 /* environment overrides.
85 /* SEE ALSO
86 /* postconf(5), configuration parameters
87 /* LICENSE
88 /* .ad
89 /* .fi
90 /* The Secure Mailer license must be distributed with this software.
91 /* AUTHOR(S)
92 /* Wietse Venema
93 /* IBM T.J. Watson Research
94 /* P.O. Box 704
95 /* Yorktown Heights, NY 10598, USA
96 /*
97 /* Wietse Venema
98 /* Google, Inc.
99 /* 111 8th Avenue
100 /* New York, NY 10011, USA
101 /*--*/
102 
103 /* System library. */
104 
105 #include <sys_defs.h>
106 #include <sys/stat.h>
107 #include <sys/wait.h>
108 #include <stdlib.h>
109 #include <unistd.h>
110 #include <fcntl.h>
111 #include <errno.h>
112 
113 /* Utility library. */
114 
115 #include <msg.h>
116 #include <vstring.h>
117 #include <vstream.h>
118 #include <msg_vstream.h>
119 #include <iostuff.h>
120 #include <warn_stat.h>
121 #include <clean_env.h>
122 
123 /* Global library. */
124 
125 #include <mail_params.h>
126 #include <mail_version.h>
127 #include <dot_lockfile.h>
128 #include <deliver_flock.h>
129 #include <mail_conf.h>
130 #include <sys_exits.h>
131 #include <mbox_conf.h>
132 #include <mbox_open.h>
133 #include <dsn_util.h>
134 #include <mail_parm_split.h>
135 
136 /* Application-specific. */
137 
138 /* usage - explain */
139 
140 static NORETURN usage(char *myname)
141 {
142  msg_fatal("usage: %s [-c config_dir] [-l lock_style] [-v] folder command...", myname);
143 }
144 
145 /* fatal_exit - all failures are deemed recoverable */
146 
147 static void fatal_exit(void)
148 {
149  exit(EX_TEMPFAIL);
150 }
151 
153 
154 /* main - go for it */
155 
156 int main(int argc, char **argv)
157 {
158  DSN_BUF *why;
159  char *folder;
160  char **command;
161  int ch;
162  int fd;
163  struct stat st;
164  int count;
165  WAIT_STATUS_T status;
166  pid_t pid;
167  int lock_mask;
168  char *lock_style = 0;
169  MBOX *mp;
170  ARGV *import_env;
171 
172  /*
173  * Fingerprint executables and core dumps.
174  */
176 
177  /*
178  * Be consistent with file permissions.
179  */
180  umask(022);
181 
182  /*
183  * To minimize confusion, make sure that the standard file descriptors
184  * are open before opening anything else. XXX Work around for 44BSD where
185  * fstat can return EBADF on an open file descriptor.
186  */
187  for (fd = 0; fd < 3; fd++)
188  if (fstat(fd, &st) == -1
189  && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
190  msg_fatal("open /dev/null: %m");
191 
192  /*
193  * Process environment options as early as we can. We are not set-uid,
194  * and we are supposed to be running in a controlled environment.
195  */
196  if (getenv(CONF_ENV_VERB))
197  msg_verbose = 1;
198 
199  /*
200  * Set up logging and error handling. Intercept fatal exits so we can
201  * return a distinguished exit status.
202  */
203  msg_vstream_init(argv[0], VSTREAM_ERR);
204  msg_cleanup(fatal_exit);
205 
206  /*
207  * Parse JCL.
208  */
209  while ((ch = GETOPT(argc, argv, "c:l:v")) > 0) {
210  switch (ch) {
211  default:
212  usage(argv[0]);
213  break;
214  case 'c':
215  if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
216  msg_fatal("out of memory");
217  break;
218  case 'l':
219  lock_style = optarg;
220  break;
221  case 'v':
222  msg_verbose++;
223  break;
224  }
225  }
226  if (optind + 2 > argc)
227  usage(argv[0]);
228  folder = argv[optind];
229  command = argv + optind + 1;
230 
231  /*
232  * Read the config file. The command line lock style can override the
233  * configured lock style.
234  */
235  mail_conf_read();
236  /* Enforce consistent operation of different Postfix parts. */
238  update_env(import_env->argv);
239  argv_free(import_env);
240  lock_mask = mbox_lock_mask(lock_style ? lock_style :
241  get_mail_conf_str(VAR_MAILBOX_LOCK, DEF_MAILBOX_LOCK, 1, 0));
242 
243  /*
244  * Lock the folder for exclusive access. Lose the lock upon exit. The
245  * command is not supposed to disappear into the background.
246  */
247  why = dsb_create();
248  if ((mp = mbox_open(folder, O_APPEND | O_WRONLY | O_CREAT,
249  S_IRUSR | S_IWUSR, (struct stat *) 0,
250  -1, -1, lock_mask, "5.2.0", why)) == 0)
251  msg_fatal("open file %s: %s", folder, vstring_str(why->reason));
252  dsb_free(why);
253 
254  /*
255  * Run the command. Remove the lock after completion.
256  */
257  for (count = 1; (pid = fork()) == -1; count++) {
258  msg_warn("fork %s: %m", command[0]);
259  if (count >= var_fork_tries) {
260  mbox_release(mp);
261  exit(EX_TEMPFAIL);
262  }
263  sleep(var_fork_delay);
264  }
265  switch (pid) {
266  case 0:
267  (void) msg_cleanup((MSG_CLEANUP_FN) 0);
268  execvp(command[0], command);
269  msg_fatal("execvp %s: %m", command[0]);
270  default:
271  if (waitpid(pid, &status, 0) < 0)
272  msg_fatal("waitpid: %m");
273  vstream_fclose(mp->fp);
274  mbox_release(mp);
275  exit(WIFEXITED(status) ? WEXITSTATUS(status) : 1);
276  }
277 }
int msg_verbose
Definition: msg.c:177
MAIL_VERSION_STAMP_DECLARE
Definition: postlock.c:152
DSN_BUF * dsb_create(void)
Definition: dsn_buf.c:169
char * var_import_environ
Definition: mail_params.c:296
ARGV * argv_free(ARGV *argvp)
Definition: argv.c:136
#define NORETURN
Definition: sys_defs.h:1583
Definition: argv.h:17
#define VAR_IMPORT_ENVIRON
Definition: mail_params.h:2506
void(* MSG_CLEANUP_FN)(void)
Definition: msg.h:23
#define vstring_str(vp)
Definition: vstring.h:71
#define stat(p, s)
Definition: warn_stat.h:18
int var_fork_delay
Definition: mail_params.c:276
char ** argv
Definition: argv.h:20
void dsb_free(DSN_BUF *dsb)
Definition: dsn_buf.c:190
VSTREAM * fp
Definition: mbox_open.h:31
#define CONF_ENV_VERB
Definition: mail_conf.h:23
void mail_conf_read(void)
Definition: mail_conf.c:178
#define CONF_ENV_PATH
Definition: mail_conf.h:22
ARGV * mail_parm_split(const char *name, const char *value)
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
Definition: mbox_open.h:29
int mbox_lock_mask(const char *string)
Definition: mbox_conf.c:83
void msg_warn(const char *fmt,...)
Definition: msg.c:215
void mbox_release(MBOX *mp)
Definition: mbox_open.c:224
#define MAIL_VERSION_STAMP_ALLOCATE
Definition: mail_version.h:67
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
void update_env(char **preserve_list)
Definition: clean_env.c:102
#define GETOPT(argc, argv, str)
Definition: sys_defs.h:1313
int var_fork_tries
Definition: mail_params.c:275
VSTRING * reason
Definition: dsn_buf.h:37
int main(int argc, char **argv)
Definition: postlock.c:156
#define VAR_MAILBOX_LOCK
Definition: mail_params.h:626
void msg_vstream_init(const char *name, VSTREAM *vp)
Definition: msg_vstream.c:77
#define EX_TEMPFAIL
Definition: sys_exits.h:42
char * get_mail_conf_str(const char *, const char *, int, int)
MBOX * mbox_open(const char *path, int flags, mode_t mode, struct stat *st, uid_t chown_uid, gid_t chown_gid, int lock_style, const char *def_dsn, DSN_BUF *why)
Definition: mbox_open.c:105
int WAIT_STATUS_T
Definition: sys_defs.h:1436
MSG_CLEANUP_FN msg_cleanup(MSG_CLEANUP_FN cleanup_fn)
Definition: msg.c:317
#define VSTREAM_ERR
Definition: vstream.h:68
#define fstat(f, s)
Definition: warn_stat.h:20