1/* $NetBSD: postlog.c,v 1.1.1.2 2012/06/09 11:27:17 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 100/* Global library. */ 101 102#include <mail_params.h> /* XXX right place for LOG_FACILITY? */ 103#include <mail_version.h> 104#include <mail_conf.h> 105#include <mail_task.h> 106 107/* Application-specific. */ 108 109 /* 110 * Support for the severity level mapping. 111 */ 112struct level_table { 113 char *name; 114 int level; 115}; 116 117static struct level_table level_table[] = { 118 "info", MSG_INFO, 119 "warn", MSG_WARN, 120 "warning", MSG_WARN, 121 "error", MSG_ERROR, 122 "err", MSG_ERROR, 123 "fatal", MSG_FATAL, 124 "crit", MSG_FATAL, 125 "panic", MSG_PANIC, 126 0, 127}; 128 129/* level_map - lookup facility or severity value */ 130 131static int level_map(char *name) 132{ 133 struct level_table *t; 134 135 for (t = level_table; t->name; t++) 136 if (strcasecmp(t->name, name) == 0) 137 return (t->level); 138 msg_fatal("bad severity: \"%s\"", name); 139} 140 141/* log_argv - log the command line */ 142 143static void log_argv(int level, char **argv) 144{ 145 VSTRING *buf = vstring_alloc(100); 146 147 while (*argv) { 148 vstring_strcat(buf, *argv++); 149 if (*argv) 150 vstring_strcat(buf, " "); 151 } 152 msg_text(level, vstring_str(buf)); 153 vstring_free(buf); 154} 155 156/* log_stream - log lines from a stream */ 157 158static void log_stream(int level, VSTREAM *fp) 159{ 160 VSTRING *buf = vstring_alloc(100); 161 162 while (vstring_get_nonl(buf, fp) != VSTREAM_EOF) 163 msg_text(level, vstring_str(buf)); 164 vstring_free(buf); 165} 166 167MAIL_VERSION_STAMP_DECLARE; 168 169/* main - logger */ 170 171int main(int argc, char **argv) 172{ 173 struct stat st; 174 char *slash; 175 int fd; 176 int ch; 177 const char *tag; 178 int log_flags = 0; 179 int level = MSG_INFO; 180 181 /* 182 * Fingerprint executables and core dumps. 183 */ 184 MAIL_VERSION_STAMP_ALLOCATE; 185 186 /* 187 * Be consistent with file permissions. 188 */ 189 umask(022); 190 191 /* 192 * To minimize confusion, make sure that the standard file descriptors 193 * are open before opening anything else. XXX Work around for 44BSD where 194 * fstat can return EBADF on an open file descriptor. 195 */ 196 for (fd = 0; fd < 3; fd++) 197 if (fstat(fd, &st) == -1 198 && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) 199 msg_fatal("open /dev/null: %m"); 200 201 /* 202 * Set up diagnostics. 203 */ 204 if ((slash = strrchr(argv[0], '/')) != 0 && slash[1]) 205 tag = mail_task(slash + 1); 206 else 207 tag = mail_task(argv[0]); 208 if (isatty(STDERR_FILENO)) 209 msg_vstream_init(tag, VSTREAM_ERR); 210 msg_syslog_init(tag, LOG_PID, LOG_FACILITY); 211 212 /* 213 * Parse switches. 214 */ 215 while ((ch = GETOPT(argc, argv, "c:ip:t:v")) > 0) { 216 switch (ch) { 217 default: 218 msg_fatal("usage: %s [-c config_dir] [-i] [-p priority] [-t tag] [-v] [text]", tag); 219 break; 220 case 'c': 221 if (setenv(CONF_ENV_PATH, optarg, 1) < 0) 222 msg_fatal("out of memory"); 223 break; 224 case 'i': 225 log_flags |= LOG_PID; 226 break; 227 case 'p': 228 level = level_map(optarg); 229 break; 230 case 't': 231 tag = optarg; 232 break; 233 case 'v': 234 msg_verbose++; 235 break; 236 } 237 } 238 239 /* 240 * Process the main.cf file. This overrides any logging facility that was 241 * specified with msg_syslog_init(); 242 */ 243 mail_conf_read(); 244 if (tag == 0 && strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0) { 245 if ((slash = strrchr(argv[0], '/')) != 0 && slash[1]) 246 tag = mail_task(slash + 1); 247 else 248 tag = mail_task(argv[0]); 249 } 250 251 /* 252 * Re-initialize the logging, this time with the tag specified in main.cf 253 * or on the command line. 254 */ 255 if (tag != 0) { 256 if (isatty(STDERR_FILENO)) 257 msg_vstream_init(tag, VSTREAM_ERR); 258 msg_syslog_init(tag, LOG_PID, LOG_FACILITY); 259 } 260 261 /* 262 * Log the command line or log lines from standard input. 263 */ 264 if (argc > optind) { 265 log_argv(level, argv + optind); 266 } else { 267 log_stream(level, VSTREAM_IN); 268 } 269 exit(0); 270} 271