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,...)