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