270 #include <sys/stat.h>
303 #define MAIL_QUEUE_INTERNAL
311 #define MAX_TEMP_AGE (60 * 60 * 24)
312 #define STR vstring_str
314 #define ACTION_STRUCT (1<<0)
315 #define ACTION_PURGE (1<<1)
316 #define ACTION_DELETE_ONE (1<<2)
317 #define ACTION_DELETE_ALL (1<<3)
318 #define ACTION_REQUEUE_ONE (1<<4)
319 #define ACTION_REQUEUE_ALL (1<<5)
320 #define ACTION_HOLD_ONE (1<<6)
321 #define ACTION_HOLD_ALL (1<<7)
322 #define ACTION_RELEASE_ONE (1<<8)
323 #define ACTION_RELEASE_ALL (1<<9)
324 #define ACTION_STRUCT_RED (1<<10)
326 #define ACTION_DEFAULT (ACTION_STRUCT | ACTION_PURGE)
332 #define ACTIONS_BY_QUEUE_ID (ACTION_DELETE_ONE | ACTION_REQUEUE_ONE \
333 | ACTION_HOLD_ONE | ACTION_RELEASE_ONE)
339 #define ACTIONS_AFTER_INUM_FIX (ACTION_REQUEUE_ALL | ACTION_HOLD_ALL \
340 | ACTION_RELEASE_ALL)
355 #define RECURSE (1<<0)
356 #define DONT_RECURSE 0
387 #define SUFFIX "#FIX"
394 static int message_requeued = 0;
395 static int message_held = 0;
396 static int message_released = 0;
397 static int message_deleted = 0;
398 static int inode_fixed = 0;
399 static int inode_mismatch = 0;
400 static int position_mismatch = 0;
406 #define MESSAGE_QUEUE(qp) ((qp)->perms == MAIL_QUEUE_STAT_READY)
407 #define READY_MESSAGE(st) (((st).st_mode & S_IRWXU) == MAIL_QUEUE_STAT_READY)
411 static struct queue_info *find_queue_info(
const char *queue_name)
413 struct queue_info *qp;
415 for (qp = queue_info; qp->
name; qp++)
416 if (strcmp(queue_name, qp->
name) == 0)
418 msg_fatal(
"invalid directory name: %s", queue_name);
423 static int postremove(
const char *path)
427 if ((ret =
remove(path)) < 0) {
439 static int postrename(
const char *old,
const char *
new)
448 msg_fatal(
"rename file %s as %s: %m", old,
new);
451 msg_info(
"renamed file %s as %s", old,
new);
458 static int postrmdir(
const char *path)
462 if ((ret = rmdir(path)) < 0) {
464 msg_fatal(
"remove directory %s: %m", path);
467 msg_info(
"remove directory %s", path);
474 static int delete_one(
const char **queue_names,
const char *queue_id)
477 const char **msg_qpp;
478 const char **log_qpp;
479 const char *msg_path;
488 msg_warn(
"invalid mail queue id: %s", queue_id);
499 for (found = 0, tries = 0; found == 0 && tries < 2; tries++) {
500 for (msg_qpp = queue_names; *msg_qpp != 0; msg_qpp++) {
507 if (postremove(msg_path) == 0) {
520 static int requeue_one(
const char **queue_names,
const char *queue_id)
523 const char **msg_qpp;
524 const char *old_path;
534 msg_warn(
"invalid mail queue id: %s", queue_id);
545 for (found = 0, tries = 0; found == 0 && tries < 2; tries++) {
546 for (msg_qpp = queue_names; *msg_qpp != 0; msg_qpp++) {
554 if (postrename(old_path,
STR(new_path_buf)) == 0) {
555 tbuf.actime = tbuf.modtime = time((time_t *) 0);
556 if (utime(
STR(new_path_buf), &tbuf) < 0)
557 msg_warn(
"%s: reset time stamps: %m",
STR(new_path_buf));
570 static int hold_one(
const char **queue_names,
const char *queue_id)
573 const char **msg_qpp;
574 const char *old_path;
583 msg_warn(
"invalid mail queue id: %s", queue_id);
597 for (found = 0, tries = 0; found == 0 && tries < 2; tries++) {
598 for (msg_qpp = queue_names; *msg_qpp != 0; msg_qpp++) {
608 if (postrename(old_path,
STR(new_path_buf)) == 0) {
609 msg_info(
"%s: placed on hold", queue_id);
621 static int release_one(
const char **queue_names,
const char *queue_id)
624 const char **msg_qpp;
625 const char *old_path;
633 msg_warn(
"invalid mail queue id: %s", queue_id);
643 for (msg_qpp = queue_names; *msg_qpp != 0; msg_qpp++) {
649 if (postrename(old_path,
STR(new_path_buf)) == 0) {
650 msg_info(
"%s: released from hold", queue_id);
661 static int operate_stream(
VSTREAM *fp,
662 int (*
operator) (
const char **,
const char *),
669 found += operator(queues,
STR(buf));
677 static int fix_queue_id(
const char *actual_path,
const char *actual_queue,
678 const char *actual_id,
struct stat * st)
683 const char **log_qpp;
693 if (MQID_FIND_LG_INUM_SEPARATOR(cp, actual_id) == 0) {
696 MQID_SH_USEC_PAD, actual_id,
701 (
int) (cp - actual_id), actual_id, MQID_LG_INUM_SEP,
705 MQID_LG_GET_HEX_USEC(new_id, cp);
717 postrename(
STR(old_path),
STR(new_path));
726 ret = postrename(actual_path,
STR(new_path));
740 static void super(
const char **queues,
int action)
746 const char *queue_name;
752 struct queue_info *qp;
761 while ((queue_name = *queues++) != 0) {
771 qp = find_queue_info(queue_name);
772 for (cpp = hash_queue_names->
argv; ; cpp++) {
777 if (strcmp(*cpp, queue_name) == 0) {
787 msg_fatal(
"%s queue must not be hashed", queue_name);
802 if (actual_depth == 0)
804 if (actual_depth > wanted_depth)
828 if (
stat(
STR(actual_path), &st) < 0)
836 if (S_ISDIR(st.st_mode)) {
837 if (rmdir(
STR(actual_path)) < 0) {
839 msg_warn(
"remove subdirectory %s: %m",
STR(actual_path));
842 msg_info(
"remove subdirectory %s",
STR(actual_path));
855 if (postremove(
STR(actual_path)) == 0)
867 if (!S_ISREG(st.st_mode)
872 (void) postremove(
STR(actual_path));
893 MQID_GET_INUM(path, inum, long_name, error);
898 if (inum != (
unsigned long) st.st_ino) {
899 msg_warn(
"name/inode mismatch: %s",
STR(actual_path));
904 if (postrename(
STR(actual_path),
STR(wanted_path)) < 0) {
943 MQID_GET_INUM(path, inum, long_name, error);
949 || (inum != (
unsigned long) st.st_ino
953 fix_queue_id(
STR(actual_path), queue_name, path, &st);
971 if (postrename(
STR(actual_path),
STR(wanted_path)) == 0)
991 if (postrename(
STR(actual_path),
STR(wanted_path)) == 0)
1006 if (postrename(
STR(actual_path),
STR(wanted_path)) == 0)
1020 if (action & ACTION_STRUCT) {
1022 if (strcmp(
STR(actual_path),
STR(wanted_path)) != 0) {
1023 position_mismatch++;
1024 (void) postrename(
STR(actual_path),
STR(wanted_path));
1043 static void interrupted(
int sig)
1056 if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
1057 (void) signal(SIGQUIT, SIG_IGN);
1058 (void) signal(SIGTERM, SIG_IGN);
1059 (void) signal(SIGHUP, SIG_IGN);
1060 if (inode_mismatch > 0 || inode_fixed > 0 || position_mismatch > 0)
1061 msg_warn(
"OPERATION INCOMPLETE -- RERUN COMMAND TO FIX THE QUEUE FIRST");
1069 static void fatal_warning(
void)
1082 const char **queues;
1084 ARGV *requeue_names = 0;
1085 ARGV *delete_names = 0;
1086 ARGV *hold_names = 0;
1087 ARGV *release_names = 0;
1098 static char *default_queues[] = {
1109 static char *default_hold_queues[] = {
1115 static char *default_release_queues[] = {
1135 for (fd = 0; fd < 3; fd++)
1136 if (
fstat(fd, &st) == -1
1137 && (close(fd), open(
"/dev/null", O_RDWR, 0)) != fd)
1149 if ((slash = strrchr(argv[0],
'/')) != 0 && slash[1])
1150 argv[0] = slash + 1;
1168 msg_fatal(
"this postfix command must not run as a set-uid process");
1170 msg_fatal(
"use of this command is reserved for the superuser");
1175 while ((c =
GETOPT(argc, argv,
"c:d:h:H:pr:sSv")) > 0) {
1180 "[-d queue_id (delete)] "
1181 "[-h queue_id (hold)] [-H queue_id (un-hold)] "
1182 "[-p (purge temporary files)] [-r queue_id (requeue)] "
1183 "[-s (structure fix)] [-S (redundant structure fix)]"
1184 "[-v (verbose)] [queue...]", argv[0]);
1187 msg_fatal(
"-c requires absolute pathname");
1192 if (delete_names == 0)
1194 argv_add(delete_names, optarg, (
char *) 0);
1195 action |= (strcmp(optarg,
"ALL") == 0 ?
1199 if (hold_names == 0)
1201 argv_add(hold_names, optarg, (
char *) 0);
1202 action |= (strcmp(optarg,
"ALL") == 0 ?
1206 if (release_names == 0)
1208 argv_add(release_names, optarg, (
char *) 0);
1209 action |= (strcmp(optarg,
"ALL") == 0 ?
1216 if (requeue_names == 0)
1218 argv_add(requeue_names, optarg, (
char *) 0);
1219 action |= (strcmp(optarg,
"ALL") == 0 ?
1277 signal(SIGINT, interrupted);
1278 signal(SIGQUIT, interrupted);
1279 if (signal(SIGTERM, SIG_IGN) == SIG_DFL)
1280 signal(SIGTERM, interrupted);
1281 if (signal(SIGHUP, SIG_IGN) == SIG_DFL)
1282 signal(SIGHUP, interrupted);
1289 msg_warn(
"option \"-d ALL\" will ignore other command line queue IDs");
1290 action &= ~ACTION_DELETE_ONE;
1293 msg_warn(
"option \"-r ALL\" will ignore other command line queue IDs");
1294 action &= ~ACTION_REQUEUE_ONE;
1297 msg_warn(
"option \"-h ALL\" will ignore other command line queue IDs");
1298 action &= ~ACTION_HOLD_ONE;
1301 msg_warn(
"option \"-H ALL\" will ignore other command line queue IDs");
1302 action &= ~ACTION_RELEASE_ONE;
1317 if (argv[optind] != 0)
1318 queues = (
const char **) argv + optind;
1319 else if (action == ACTION_HOLD_ALL)
1320 queues = (
const char **) default_hold_queues;
1321 else if (action == ACTION_RELEASE_ALL)
1322 queues = (
const char **) default_release_queues;
1324 queues = (
const char **) default_queues;
1332 super(queues, action);
1340 if (inode_mismatch > 0)
1341 super(queues, action);
1349 && (inode_mismatch > 0 || inode_fixed > 0)) {
1350 msg_error(
"QUEUE FILE NAMES WERE CHANGED TO MATCH INODE NUMBERS");
1351 msg_fatal(
"CHECK YOUR QUEUE IDS AND RE-ISSUE THE COMMAND");
1359 if (action & ACTION_DELETE_ONE) {
1361 queues = (
const char **)
1362 (argv[optind] ? argv + optind : default_queues);
1363 for (cpp = delete_names->
argv; *cpp; cpp++) {
1364 if (strcmp(*cpp,
"ALL") == 0)
1366 if (strcmp(*cpp,
"-") == 0)
1368 operate_stream(
VSTREAM_IN, delete_one, queues);
1370 message_deleted += delete_one(queues, *cpp);
1379 if (action & ACTION_REQUEUE_ONE) {
1381 queues = (
const char **)
1382 (argv[optind] ? argv + optind : default_queues);
1383 for (cpp = requeue_names->
argv; *cpp; cpp++) {
1384 if (strcmp(*cpp,
"ALL") == 0)
1386 if (strcmp(*cpp,
"-") == 0)
1388 operate_stream(
VSTREAM_IN, requeue_one, queues);
1390 message_requeued += requeue_one(queues, *cpp);
1399 if (action & ACTION_HOLD_ONE) {
1401 queues = (
const char **)
1402 (argv[optind] ? argv + optind : default_hold_queues);
1403 for (cpp = hold_names->
argv; *cpp; cpp++) {
1404 if (strcmp(*cpp,
"ALL") == 0)
1406 if (strcmp(*cpp,
"-") == 0)
1408 operate_stream(
VSTREAM_IN, hold_one, queues);
1410 message_held += hold_one(queues, *cpp);
1419 if (action & ACTION_RELEASE_ONE) {
1421 queues = (
const char **)
1422 (argv[optind] ? argv + optind : default_release_queues);
1423 for (cpp = release_names->
argv; *cpp; cpp++) {
1424 if (strcmp(*cpp,
"ALL") == 0)
1426 if (strcmp(*cpp,
"-") == 0)
1428 operate_stream(
VSTREAM_IN, release_one, queues);
1430 message_released += release_one(queues, *cpp);
1437 if (message_requeued > 0)
1438 msg_info(
"Requeued: %d message%s", message_requeued,
1439 message_requeued > 1 ?
"s" :
"");
1440 if (message_deleted > 0)
1441 msg_info(
"Deleted: %d message%s", message_deleted,
1442 message_deleted > 1 ?
"s" :
"");
1443 if (message_held > 0)
1444 msg_info(
"Placed on hold: %d message%s",
1445 message_held, message_held > 1 ?
"s" :
"");
1446 if (message_released > 0)
1447 msg_info(
"Released from hold: %d message%s",
1448 message_released, message_released > 1 ?
"s" :
"");
1449 if (inode_fixed > 0)
1450 msg_info(
"Renamed to match inode number: %d message%s", inode_fixed,
1451 inode_fixed > 1 ?
"s" :
"");
1452 if (inode_mismatch > 0 || inode_fixed > 0)
1453 msg_warn(
"QUEUE FILE NAMES WERE CHANGED TO MATCH INODE NUMBERS");
void msg_error(const char *fmt,...)
void scan_dir_push(SCAN_DIR *scan, const char *path)
const char * mail_task(const char *argv0)
#define MAIL_QUEUE_BOUNCE
char * mystrdup(const char *str)
SCAN_DIR * scan_dir_pop(SCAN_DIR *scan)
char * var_import_environ
int vstring_get_nonl(VSTRING *vp, VSTREAM *fp)
int mail_queue_id_ok(const char *queue_id)
void set_mail_conf_str(const char *, const char *)
ARGV * argv_free(ARGV *argvp)
#define VAR_IMPORT_ENVIRON
#define MAIL_QUEUE_ACTIVE
int mail_queue_mkdirs(const char *path)
#define MESSAGE_QUEUE(qp)
void argv_add(ARGV *argvp,...)
ARGV * argv_alloc(ssize_t len)
#define MAIL_QUEUE_STAT_READY
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
void mail_conf_read(void)
const char * mail_queue_path(VSTRING *buf, const char *queue_name, const char *queue_id)
SCAN_DIR * scan_dir_open(const char *path)
#define ACTION_REQUEUE_ONE
#define ACTION_STRUCT_RED
char * var_hash_queue_names
MAIL_VERSION_STAMP_DECLARE
ARGV * mail_parm_split(const char *name, const char *value)
char * scan_dir_path(SCAN_DIR *scan)
#define ACTION_DELETE_ALL
SCAN_DIR * scan_dir_close(SCAN_DIR *scan)
#define READY_MESSAGE(st)
int main(int argc, char **argv)
char * safe_getenv(const char *)
#define MAIL_QUEUE_INCOMING
int mail_open_ok(const char *queue_name, const char *queue_id, struct stat *statp, const char **path)
void msg_warn(const char *fmt,...)
VSTRING * vstring_alloc(ssize_t len)
#define ACTIONS_AFTER_INUM_FIX
#define MAIL_VERSION_STAMP_ALLOCATE
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
#define MAIL_QUEUE_MAILDROP
#define ACTION_DELETE_ONE
NORETURN msg_fatal(const char *fmt,...)
#define MAIL_VERSION_CHECK
#define ACTION_RELEASE_ONE
#define ACTION_RELEASE_ALL
void update_env(char **preserve_list)
#define MAIL_QUEUE_DEFERRED
ARGV * argv_split(const char *, const char *)
#define ACTION_REQUEUE_ALL
const char * log_queue_names[]
#define GETOPT(argc, argv, str)
void msg_syslog_init(const char *name, int logopt, int facility)
void set_ugid(uid_t uid, gid_t gid)
VSTRING * vstring_free(VSTRING *vp)
const char * get_file_id_st(struct stat *st, int long_flag)
void msg_vstream_init(const char *name, VSTREAM *vp)
#define ACTIONS_BY_QUEUE_ID
MSG_CLEANUP_FN msg_cleanup(MSG_CLEANUP_FN cleanup_fn)
VSTRING * vstring_strcat(VSTRING *vp, const char *src)
char * scan_dir_next(SCAN_DIR *scan)
void argv_terminate(ARGV *argvp)
int WARN_UNUSED_RESULT sane_rename(const char *, const char *)
void msg_info(const char *fmt,...)