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