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