xref: /netbsd-src/external/ibm-public/postfix/dist/src/postlog/postlog.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: postlog.c,v 1.2 2017/02/14 01:16:46 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	postlog 1
6 /* SUMMARY
7 /*	Postfix-compatible logging utility
8 /* SYNOPSIS
9 /* .fi
10 /* .ad
11 /*	\fBpostlog\fR [\fB-iv\fR] [\fB-c \fIconfig_dir\fR]
12 /*	[\fB-p \fIpriority\fR] [\fB-t \fItag\fR] [\fItext...\fR]
13 /* DESCRIPTION
14 /*	The \fBpostlog\fR(1) command implements a Postfix-compatible logging
15 /*	interface for use in, for example, shell scripts.
16 /*
17 /*	By default, \fBpostlog\fR(1) logs the \fItext\fR given on the command
18 /*	line as one record. If no \fItext\fR is specified on the command
19 /*	line, \fBpostlog\fR(1) reads from standard input and logs each input
20 /*	line as one record.
21 /*
22 /*	Logging is sent to \fBsyslogd\fR(8); when the standard error stream
23 /*	is connected to a terminal, logging is sent there as well.
24 /*
25 /*	The following options are implemented:
26 /* .IP "\fB-c \fIconfig_dir\fR"
27 /*	Read the \fBmain.cf\fR configuration file in the named directory
28 /*	instead of the default configuration directory.
29 /* .IP \fB-i\fR
30 /*	Include the process ID in the logging tag.
31 /* .IP "\fB-p \fIpriority\fR (default: \fBinfo\fR)"
32 /*	Specifies the logging severity: \fBinfo\fR, \fBwarn\fR,
33 /*	\fBerror\fR, \fBfatal\fR, or \fBpanic\fR. With Postfix 3.1
34 /*	and later, the program will pause for 1 second after reporting
35 /*	a \fBfatal\fR or \fBpanic\fR condition, just like other
36 /*	Postfix programs.
37 /* .IP "\fB-t \fItag\fR"
38 /*	Specifies the logging tag, that is, the identifying name that
39 /*	appears at the beginning of each logging record. A default tag
40 /*	is used when none is specified.
41 /* .IP \fB-v\fR
42 /*	Enable verbose logging for debugging purposes. Multiple \fB-v\fR
43 /*	options make the software increasingly verbose.
44 /* ENVIRONMENT
45 /* .ad
46 /* .fi
47 /* .IP MAIL_CONFIG
48 /*	Directory with the \fBmain.cf\fR file.
49 /* CONFIGURATION PARAMETERS
50 /* .ad
51 /* .fi
52 /*	The following \fBmain.cf\fR parameters are especially relevant to
53 /*	this program.
54 /*
55 /*	The text below provides only a parameter summary. See
56 /*	\fBpostconf\fR(5) for more details including examples.
57 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
58 /*	The default location of the Postfix main.cf and master.cf
59 /*	configuration files.
60 /* .IP "\fBsyslog_facility (mail)\fR"
61 /*	The syslog facility of Postfix logging.
62 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
63 /*	The mail system name that is prepended to the process name in syslog
64 /*	records, so that "smtpd" becomes, for example, "postfix/smtpd".
65 /* SEE ALSO
66 /*	postconf(5), configuration parameters
67 /*	syslogd(8), syslog daemon
68 /* LICENSE
69 /* .ad
70 /* .fi
71 /*	The Secure Mailer license must be distributed with this software.
72 /* AUTHOR(S)
73 /*	Wietse Venema
74 /*	IBM T.J. Watson Research
75 /*	P.O. Box 704
76 /*	Yorktown Heights, NY 10598, USA
77 /*
78 /*	Wietse Venema
79 /*	Google, Inc.
80 /*	111 8th Avenue
81 /*	New York, NY 10011, USA
82 /*--*/
83 
84 /* System library. */
85 
86 #include <sys_defs.h>
87 #include <sys/stat.h>
88 #include <string.h>
89 #include <syslog.h>
90 #include <fcntl.h>
91 #include <stdlib.h>
92 #include <unistd.h>
93 
94 #ifdef STRCASECMP_IN_STRINGS_H
95 #include <strings.h>
96 #endif
97 
98 /* Utility library. */
99 
100 #include <msg.h>
101 #include <vstring.h>
102 #include <vstream.h>
103 #include <vstring_vstream.h>
104 #include <msg_output.h>
105 #include <msg_vstream.h>
106 #include <msg_syslog.h>
107 #include <warn_stat.h>
108 
109 /* Global library. */
110 
111 #include <mail_params.h>		/* XXX right place for LOG_FACILITY? */
112 #include <mail_version.h>
113 #include <mail_conf.h>
114 #include <mail_task.h>
115 
116 /* Application-specific. */
117 
118  /*
119   * Support for the severity level mapping.
120   */
121 struct level_table {
122     char   *name;
123     int     level;
124 };
125 
126 static struct level_table level_table[] = {
127     "info", MSG_INFO,
128     "warn", MSG_WARN,
129     "warning", MSG_WARN,
130     "error", MSG_ERROR,
131     "err", MSG_ERROR,
132     "fatal", MSG_FATAL,
133     "crit", MSG_FATAL,
134     "panic", MSG_PANIC,
135     0,
136 };
137 
138 /* level_map - lookup facility or severity value */
139 
140 static int level_map(char *name)
141 {
142     struct level_table *t;
143 
144     for (t = level_table; t->name; t++)
145 	if (strcasecmp(t->name, name) == 0)
146 	    return (t->level);
147     msg_fatal("bad severity: \"%s\"", name);
148 }
149 
150 /* log_argv - log the command line */
151 
152 static void log_argv(int level, char **argv)
153 {
154     VSTRING *buf = vstring_alloc(100);
155 
156     while (*argv) {
157 	vstring_strcat(buf, *argv++);
158 	if (*argv)
159 	    vstring_strcat(buf, " ");
160     }
161     msg_text(level, vstring_str(buf));
162     vstring_free(buf);
163 }
164 
165 /* log_stream - log lines from a stream */
166 
167 static void log_stream(int level, VSTREAM *fp)
168 {
169     VSTRING *buf = vstring_alloc(100);
170 
171     while (vstring_get_nonl(buf, fp) != VSTREAM_EOF)
172 	msg_text(level, vstring_str(buf));
173     vstring_free(buf);
174 }
175 
176 MAIL_VERSION_STAMP_DECLARE;
177 
178 /* main - logger */
179 
180 int     main(int argc, char **argv)
181 {
182     struct stat st;
183     int     fd;
184     int     ch;
185     const char *tag;
186     int     log_flags = 0;
187     int     level = MSG_INFO;
188 
189     /*
190      * Fingerprint executables and core dumps.
191      */
192     MAIL_VERSION_STAMP_ALLOCATE;
193 
194     /*
195      * Be consistent with file permissions.
196      */
197     umask(022);
198 
199     /*
200      * To minimize confusion, make sure that the standard file descriptors
201      * are open before opening anything else. XXX Work around for 44BSD where
202      * fstat can return EBADF on an open file descriptor.
203      */
204     for (fd = 0; fd < 3; fd++)
205 	if (fstat(fd, &st) == -1
206 	    && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
207 	    msg_fatal("open /dev/null: %m");
208 
209     /*
210      * Set up diagnostics.
211      */
212     tag = mail_task(argv[0]);
213     if (isatty(STDERR_FILENO))
214 	msg_vstream_init(tag, VSTREAM_ERR);
215     msg_syslog_init(tag, LOG_PID, LOG_FACILITY);
216 
217     /*
218      * Check the Postfix library version as soon as we enable logging.
219      */
220     MAIL_VERSION_CHECK;
221 
222     /*
223      * Parse switches.
224      */
225     tag = 0;
226     while ((ch = GETOPT(argc, argv, "c:ip:t:v")) > 0) {
227 	switch (ch) {
228 	default:
229 	    msg_fatal("usage: %s [-c config_dir] [-i] [-p priority] [-t tag] [-v] [text]", argv[0]);
230 	    break;
231 	case 'c':
232 	    if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
233 		msg_fatal("out of memory");
234 	    break;
235 	case 'i':
236 	    log_flags |= LOG_PID;
237 	    break;
238 	case 'p':
239 	    level = level_map(optarg);
240 	    break;
241 	case 't':
242 	    tag = optarg;
243 	    break;
244 	case 'v':
245 	    msg_verbose++;
246 	    break;
247 	}
248     }
249 
250     /*
251      * Process the main.cf file. This may change the syslog_name setting and
252      * may require that mail_task() be re-evaluated.
253      */
254     mail_conf_read();
255     if (tag == 0)
256 	tag = mail_task(argv[0]);
257 
258     /*
259      * Re-initialize the logging, this time with the tag specified in main.cf
260      * or on the command line.
261      */
262     if (isatty(STDERR_FILENO))
263 	msg_vstream_init(tag, VSTREAM_ERR);
264     msg_syslog_init(tag, LOG_PID, LOG_FACILITY);
265 
266     /*
267      * Log the command line or log lines from standard input.
268      */
269     if (argc > optind) {
270 	log_argv(level, argv + optind);
271     } else {
272 	log_stream(level, VSTREAM_IN);
273     }
274 
275     /*
276      * Consistency with msg(3) functions.
277      */
278     if (level >= MSG_FATAL)
279 	sleep(1);
280     exit(0);
281 }
282