Postfix3.3.1
showq_compat.c
[詳解]
1 /*++
2 /* NAME
3 /* showq_compat 8
4 /* SUMMARY
5 /* Sendmail mailq compatibitily adapter
6 /* SYNOPSIS
7 /* void showq_compat(
8 /* VSTREAM *showq)
9 /* DESCRIPTION
10 /* This function converts a record stream from the showq(8)
11 /* daemon to of an approximation of Sendmail mailq command
12 /* output.
13 /* DIAGNOSTICS
14 /* Fatal errors: out of memory, malformed showq(8) daemon output.
15 /* LICENSE
16 /* .ad
17 /* .fi
18 /* The Secure Mailer license must be distributed with this software.
19 /* AUTHOR(S)
20 /* Wietse Venema
21 /* IBM T.J. Watson Research
22 /* P.O. Box 704
23 /* Yorktown Heights, NY 10598, USA
24 /*
25 /* Wietse Venema
26 /* Google, Inc.
27 /* 111 8th Avenue
28 /* New York, NY 10011, USA
29 /*--*/
30 
31 /* System library. */
32 
33 #include <sys_defs.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <time.h>
37 #include <string.h>
38 #include <sysexits.h>
39 #include <errno.h>
40 
41 /* Utility library. */
42 
43 #include <vstring.h>
44 #include <vstream.h>
45 #include <stringops.h>
46 #include <mymalloc.h>
47 #include <msg.h>
48 
49 /* Global library. */
50 
51 #include <mail_proto.h>
52 #include <mail_queue.h>
53 #include <mail_date.h>
54 #include <mail_params.h>
55 
56 /* Application-specific. */
57 
58 #include <postqueue.h>
59 
60  /*
61  * The enable_long_queue_ids parameter determines the output format.
62  *
63  * The historical output format for short queue IDs (inode number and time in
64  * microseconds modulo 1) is not suitable for large inode numbers, but we
65  * won't change it to avoid breaking compatibility with programs that parse
66  * this output.
67  */
68 #define S_STRING_FORMAT "%-11s %7s %-20s %s\n"
69 #define S_SENDER_FORMAT "%-11s %7ld %20.20s %s\n"
70 #define S_HEADINGS "-Queue ID-", "--Size--", \
71  "----Arrival Time----", "-Sender/Recipient-------"
72 
73 #define L_STRING_FORMAT "%-17s %8s %-19s %s\n"
74 #define L_SENDER_FORMAT "%-17s %8ld %19.19s %s\n"
75 #define L_HEADINGS "----Queue ID-----", "--Size--", \
76  "---Arrival Time----", "--Sender/Recipient------"
77 
78 #define STR(x) vstring_str(x)
79 
80 /* showq_message - report status for one message */
81 
82 static unsigned long showq_message(VSTREAM *showq_stream)
83 {
84  static VSTRING *queue_name = 0;
85  static VSTRING *queue_id = 0;
86  static VSTRING *id_status = 0;
87  static VSTRING *addr = 0;
88  static VSTRING *why = 0;
89  long arrival_time;
90  long message_size;
91  int message_status;
92  char *saved_reason = mystrdup("");
93  const char *show_reason;
94  int padding;
95  int showq_status;
96  time_t time_t_arrival_time;
97 
98  /*
99  * One-time initialization.
100  */
101  if (queue_name == 0) {
102  queue_name = vstring_alloc(100);
103  queue_id = vstring_alloc(100);
104  id_status = vstring_alloc(100);
105  addr = vstring_alloc(100);
106  why = vstring_alloc(100);
107  }
108 
109  /*
110  * Read the message properties and sender address.
111  */
112  if (attr_scan(showq_stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
113  RECV_ATTR_STR(MAIL_ATTR_QUEUE, queue_name),
114  RECV_ATTR_STR(MAIL_ATTR_QUEUEID, queue_id),
115  RECV_ATTR_LONG(MAIL_ATTR_TIME, &arrival_time),
116  RECV_ATTR_LONG(MAIL_ATTR_SIZE, &message_size),
118  ATTR_TYPE_END) != 5)
119  msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
120 
121  /*
122  * Decorate queue file names in specific states, then print the result
123  * left-aligned, followed by other status info and the sender address
124  * which is already in externalized RFC 5321 form.
125  */
126  message_status = (strcmp(STR(queue_name), MAIL_QUEUE_ACTIVE) == 0 ? '*' :
127  strcmp(STR(queue_name), MAIL_QUEUE_HOLD) == 0 ? '!' : ' ');
128  vstring_sprintf(id_status, "%s%c", STR(queue_id), message_status);
129  time_t_arrival_time = arrival_time;
131  L_SENDER_FORMAT : S_SENDER_FORMAT, STR(id_status),
132  message_size, asctime(localtime(&time_t_arrival_time)),
133  STR(addr));
134 
135  /*
136  * Read zero or more (recipient, reason) pair(s) until attr_scan_more()
137  * consumes a terminator. If the showq daemon messes up, don't try to
138  * resynchronize.
139  */
140  while ((showq_status = attr_scan_more(showq_stream)) > 0) {
141  if (attr_scan(showq_stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
144  ATTR_TYPE_END) != 2)
145  msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
146 
147  /*
148  * Don't output a "(reason)" line when no recipient has a reason, or
149  * when the previous recipient has the same (non)reason as the
150  * current recipient. Do output a "(reason unavailable)" when the
151  * previous recipient has a reason, and the current recipient has
152  * none.
153  */
154  if (strcmp(saved_reason, STR(why)) != 0) {
155  myfree(saved_reason);
156  saved_reason = mystrdup(STR(why));
157  show_reason = *saved_reason ? saved_reason : "reason unavailable";
158  if ((padding = 76 - (int) strlen(show_reason)) < 0)
159  padding = 0;
160  vstream_printf("%*s(%s)\n", padding, "", show_reason);
161  }
164  "", "", "", STR(addr));
165  }
166  if (showq_status < 0)
167  msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
168  myfree(saved_reason);
169  return (message_size);
170 }
171 
172 /* showq_compat - legacy mailq-style output adapter */
173 
174 void showq_compat(VSTREAM *showq_stream)
175 {
176  unsigned long file_count = 0;
177  unsigned long queue_size = 0;
178  int showq_status;
179 
180  /*
181  * Process zero or more queue file objects until attr_scan_more()
182  * consumes a terminator.
183  */
184  while ((showq_status = attr_scan_more(showq_stream)) > 0) {
185  if (file_count > 0) {
186  vstream_printf("\n");
187  } else if (var_long_queue_ids) {
189  } else {
191  }
192  queue_size += showq_message(showq_stream);
193  file_count++;
195  if (errno != EPIPE)
196  msg_fatal_status(EX_IOERR, "output write error: %m");
197  return;
198  }
199  }
200  if (showq_status < 0)
201  msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
202 
203  /*
204  * Print the queue summary.
205  */
206  if (file_count == 0)
207  vstream_printf("Mail queue is empty\n");
208  else {
209  vstream_printf("\n-- %lu Kbytes in %lu Request%s.\n",
210  queue_size / 1024, file_count,
211  file_count == 1 ? "" : "s");
212  }
213  if (vstream_fflush(VSTREAM_OUT) && errno != EPIPE)
214  msg_fatal_status(EX_IOERR, "output write error: %m");
215 }
void myfree(void *ptr)
Definition: mymalloc.c:207
#define L_SENDER_FORMAT
Definition: showq_compat.c:74
char * mystrdup(const char *str)
Definition: mymalloc.c:225
void showq_compat(VSTREAM *showq_stream)
Definition: showq_compat.c:174
#define MAIL_QUEUE_ACTIVE
Definition: mail_queue.h:31
#define VSTREAM_OUT
Definition: vstream.h:67
#define MAIL_ATTR_SIZE
Definition: mail_proto.h:139
#define EX_IOERR
Definition: sys_exits.h:41
#define ATTR_TYPE_END
Definition: attr.h:39
#define MAIL_QUEUE_HOLD
Definition: mail_queue.h:29
#define MAIL_ATTR_QUEUE
Definition: mail_proto.h:129
bool var_long_queue_ids
Definition: mail_params.c:339
#define EX_SOFTWARE
Definition: sys_exits.h:37
#define S_STRING_FORMAT
Definition: showq_compat.c:68
#define RECV_ATTR_LONG(name, val)
Definition: attr.h:75
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
#define MAIL_ATTR_WHY
Definition: mail_proto.h:135
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define S_SENDER_FORMAT
Definition: showq_compat.c:69
#define L_HEADINGS
Definition: showq_compat.c:75
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
Definition: vstring.c:602
#define MAIL_ATTR_TIME
Definition: mail_proto.h:142
#define attr_scan_more
Definition: attr.h:113
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
#define MAIL_ATTR_RECIP
Definition: mail_proto.h:134
#define S_HEADINGS
Definition: showq_compat.c:70
#define MAIL_ATTR_SENDER
Definition: mail_proto.h:131
#define STR(x)
Definition: showq_compat.c:78
NORETURN msg_fatal_status(int status, const char *fmt,...)
Definition: msg.c:272
#define MAIL_ATTR_QUEUEID
Definition: mail_proto.h:130
#define attr_scan
Definition: attr.h:111
#define ATTR_FLAG_MORE
Definition: attr.h:101
#define L_STRING_FORMAT
Definition: showq_compat.c:73
#define RECV_ATTR_STR(name, val)
Definition: attr.h:72
#define ATTR_FLAG_STRICT
Definition: attr.h:103