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