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