File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / smartmontools / os_win32 / syslog_win32.cpp
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:17:36 2013 UTC (10 years, 11 months ago) by misho
Branches: smartmontools, elwix, MAIN
CVS tags: v6_2, v6_1p0, v6_1, HEAD
6.1

    1: /*
    2:  * os_win32/syslog_win32.cpp
    3:  *
    4:  * Home page of code is: http://smartmontools.sourceforge.net
    5:  *
    6:  * Copyright (C) 2004-12 Christian Franke <smartmontools-support@lists.sourceforge.net>
    7:  *
    8:  * This program is free software; you can redistribute it and/or modify
    9:  * it under the terms of the GNU General Public License as published by
   10:  * the Free Software Foundation; either version 2, or (at your option)
   11:  * any later version.
   12:  *
   13:  * You should have received a copy of the GNU General Public License
   14:  * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
   15:  *
   16:  */
   17: 
   18: // Win32 Emulation of syslog() for smartd
   19: // Writes to windows event log on NT4/2000/XP
   20: // (Register syslogevt.exe as event message file)
   21: // If facility is set to LOG_LOCAL[0-7], log is written to
   22: // file "<ident>.log", stdout, stderr, "<ident>[1-5].log".
   23: 
   24: 
   25: #include "syslog.h"
   26: 
   27: #include <stdlib.h>
   28: #include <stdio.h>
   29: #include <time.h>
   30: #include <errno.h>
   31: #include <process.h> // getpid()
   32: 
   33: #define WIN32_LEAN_AND_MEAN
   34: #include <windows.h> // RegisterEventSourceA(), ReportEventA(), ...
   35: 
   36: const char *syslog_win32_cpp_cvsid = "$Id: syslog_win32.cpp,v 1.1.1.2 2013/07/22 01:17:36 misho Exp $"
   37:   SYSLOG_H_CVSID;
   38: 
   39: #ifdef _MSC_VER
   40: // MSVC
   41: #define snprintf _snprintf
   42: #define vsnprintf _vsnprintf
   43: #endif
   44: 
   45: #define ARGUSED(x) ((void)(x))
   46: 
   47: 
   48: #ifndef _MT
   49: //MT runtime not necessary, because thread uses no unsafe lib functions
   50: //#error Program must be linked with multithreaded runtime library
   51: #endif
   52: 
   53: 
   54: #ifdef TESTEVT
   55: // Redirect event log to stdout for testing
   56: 
   57: static BOOL Test_ReportEventA(HANDLE h, WORD type, WORD cat, DWORD id, PSID usid,
   58: 						WORD nstrings, WORD datasize, LPCTSTR * strings, LPVOID data)
   59: {
   60: 	int i;
   61: 	printf("%u %lu:%s", type, id, nstrings != 1?"\n":"");
   62: 	for (i = 0; i < nstrings; i++)
   63: 		printf(" \"%s\"\n", strings[i]);
   64: 	fflush(stdout);
   65: 	return TRUE;
   66: }
   67: 
   68: HANDLE Test_RegisterEventSourceA(LPCTSTR server, LPCTSTR source)
   69: {
   70: 	return (HANDLE)42;
   71: }
   72: 
   73: #define ReportEventA Test_ReportEventA
   74: #define RegisterEventSourceA Test_RegisterEventSourceA
   75: #endif // TESTEVT
   76: 
   77: 
   78: // Event message ids,
   79: // should be identical to MSG_SYSLOG* in "syslogevt.h"
   80: // (generated by "mc" from "syslogevt.mc")
   81: #define MSG_SYSLOG                       0x00000000L
   82: #define MSG_SYSLOG_01                    0x00000001L
   83: // ...
   84: #define MSG_SYSLOG_10                    0x0000000AL
   85: 
   86: static char sl_ident[100];
   87: static char sl_logpath[sizeof(sl_ident) + sizeof("0.log")-1];
   88: static FILE * sl_logfile;
   89: static char sl_pidstr[16];
   90: static HANDLE sl_hevtsrc;
   91: 
   92: 
   93: // Ring buffer for event log output via thread
   94: #define MAXLINES 10
   95: #define LINELEN 200
   96: 
   97: static HANDLE evt_hthread;
   98: static char evt_lines[MAXLINES][LINELEN+1];
   99: static int evt_priorities[MAXLINES];
  100: static volatile int evt_timeout;
  101: static int evt_index_in, evt_index_out;
  102: static HANDLE evt_wait_in, evt_wait_out;
  103: 
  104: 
  105: // Map syslog priority to event type
  106: 
  107: static WORD pri2evtype(int priority)
  108: {
  109: 	switch (priority) {
  110: 		default:
  111: 		case LOG_EMERG: case LOG_ALERT:
  112: 		case LOG_CRIT:  case LOG_ERR:
  113: 			return EVENTLOG_ERROR_TYPE;
  114: 		case LOG_WARNING:
  115: 			return EVENTLOG_WARNING_TYPE;
  116: 		case LOG_NOTICE: case LOG_INFO:
  117: 		case LOG_DEBUG:
  118: 			return EVENTLOG_INFORMATION_TYPE;
  119: 	}
  120: }
  121: 
  122: 
  123: // Map syslog priority to string
  124: 
  125: static const char * pri2text(int priority)
  126: {
  127: 	switch (priority) {
  128: 		case LOG_EMERG:   return "EMERG";
  129: 		case LOG_ALERT:   return "ALERT";
  130: 		case LOG_CRIT:    return "CRIT";
  131: 		default:
  132: 		case LOG_ERR:     return "ERROR";
  133: 		case LOG_WARNING: return "Warn";
  134: 		case LOG_NOTICE:  return "Note";
  135: 		case LOG_INFO:    return "Info";
  136: 		case LOG_DEBUG:   return "Debug";
  137: 	}
  138: }
  139: 
  140: 
  141: // Output cnt events from ring buffer
  142: 
  143: static void report_events(int cnt)
  144: {
  145: 	const char * msgs[3+MAXLINES];
  146: 
  147: 	int i, pri;
  148: 	if (cnt <= 0)
  149: 		return;
  150: 	if (cnt > MAXLINES)
  151: 		cnt = MAXLINES;
  152: 
  153: 	pri = evt_priorities[evt_index_out];
  154: 
  155: 	msgs[0] = sl_ident;
  156: 	msgs[1] = sl_pidstr;
  157: 	msgs[2] = pri2text(pri);
  158: 	for (i = 0; i < cnt; i++) {
  159: 		//assert(evt_priorities[evt_index_out] == pri);
  160: 		msgs[3+i] = evt_lines[evt_index_out];
  161: 		if (++evt_index_out >= MAXLINES)
  162: 			evt_index_out = 0;
  163: 	}
  164: 	ReportEventA(sl_hevtsrc,
  165: 		pri2evtype(pri), // type
  166: 		0, MSG_SYSLOG+cnt,    // category, message id
  167: 		NULL,                 // no security id
  168: 		(WORD)(3+cnt), 0,     // 3+cnt strings, ...
  169: 		msgs, NULL);          // ...          , no data
  170: }
  171: 
  172: 
  173: // Thread to combine several syslog lines into one event log entry
  174: 
  175: static ULONG WINAPI event_logger_thread(LPVOID arg)
  176: {
  177: 	int cnt;
  178: 	ARGUSED(arg);
  179: 
  180: 	cnt = 0;
  181: 	for (;;) {
  182: 		// Wait for first line ...
  183: 		int prior, i, rest;
  184: 		if (cnt == 0) {
  185: 			if (WaitForSingleObject(evt_wait_out, (evt_timeout? INFINITE : 0)) != WAIT_OBJECT_0)
  186: 				break;
  187: 			cnt = 1;
  188: 		}
  189: 
  190: 		// ... wait some time for more lines with same prior
  191: 		i = evt_index_out;
  192: 		prior = evt_priorities[i];
  193: 		rest = 0;
  194: 		while (cnt < MAXLINES) {
  195: 			long timeout =
  196: 				evt_timeout * ((1000L * (MAXLINES-cnt+1))/MAXLINES);
  197: 			if (WaitForSingleObject(evt_wait_out, timeout) != WAIT_OBJECT_0)
  198: 				break;
  199: 			if (++i >= MAXLINES)
  200: 				i = 0;
  201: 			if (evt_priorities[i] != prior) {
  202: 				rest = 1;
  203: 				break;
  204: 			}
  205: 			cnt++;
  206: 		}
  207: 
  208: 		// Output all in one event log entry
  209: 		report_events(cnt);
  210: 
  211: 		// Signal space
  212: 		if (!ReleaseSemaphore(evt_wait_in, cnt, NULL))
  213: 			break;
  214: 		cnt = rest;
  215: 	}
  216: 	return 0;
  217: }
  218: 
  219: 
  220: static void on_exit_event_logger(void)
  221: {
  222: 	// Output lines immediate if exiting
  223: 	evt_timeout = 0; 
  224: 	// Wait for thread to finish
  225: 	WaitForSingleObject(evt_hthread, 1000L);
  226: 	CloseHandle(evt_hthread);
  227: #if 0
  228: 	if (sl_hevtsrc) {
  229: 		DeregisterEventSource(sl_hevtsrc); sl_hevtsrc = 0;
  230: 	}
  231: #else
  232: 	// Leave event message source open to prevent losing messages during shutdown
  233: #endif
  234: }
  235: 
  236: 
  237: static int start_event_logger()
  238: {
  239: 	DWORD tid;
  240: 	evt_timeout = 1;
  241: 	if (   !(evt_wait_in  = CreateSemaphore(NULL,  MAXLINES, MAXLINES, NULL))
  242: 		|| !(evt_wait_out = CreateSemaphore(NULL,         0, MAXLINES, NULL))) {
  243: 		fprintf(stderr,"CreateSemaphore failed, Error=%ld\n", GetLastError());
  244: 		return -1;
  245: 	}
  246: 	if (!(evt_hthread = CreateThread(NULL, 0, event_logger_thread, NULL, 0, &tid))) {
  247: 		fprintf(stderr,"CreateThread failed, Error=%ld\n", GetLastError());
  248: 		return -1;
  249: 	}
  250: 	atexit(on_exit_event_logger);
  251: 	return 0;
  252: }
  253: 
  254: 
  255: // Write lines to event log ring buffer
  256: 
  257: static void write_event_log(int priority, const char * lines)
  258: {
  259: 	int cnt = 0;
  260: 	int i;
  261: 	for (i = 0; lines[i]; i++) {
  262: 		int len = 0;
  263: 		while (lines[i+len] && lines[i+len] != '\n')
  264: 			len++;
  265: 			;
  266: 		if (len > 0) {
  267: 			// Wait for space
  268: 			if (WaitForSingleObject(evt_wait_in, INFINITE) != WAIT_OBJECT_0)
  269: 				return;
  270: 			// Copy line
  271: 			evt_priorities[evt_index_in] = priority;
  272: 			memcpy(evt_lines[evt_index_in], lines+i, (len < LINELEN ? len : LINELEN));
  273: 			if (len < LINELEN)
  274: 				evt_lines[evt_index_in][len] = 0;
  275: 			if (++evt_index_in >= MAXLINES)
  276: 				evt_index_in = 0;
  277: 			// Signal avail if ring buffer full
  278: 			if (++cnt >= MAXLINES) {
  279: 				ReleaseSemaphore(evt_wait_out, cnt, NULL);
  280: 				cnt = 0;
  281: 			}
  282: 			i += len;
  283: 		}
  284: 		if (!lines[i])
  285: 			break;
  286: 	}
  287: 
  288: 	// Signal avail
  289: 	if (cnt > 0)
  290: 		ReleaseSemaphore(evt_wait_out, cnt, NULL);
  291: 	Sleep(1);
  292: }
  293: 
  294: 
  295: // Write lines to logfile
  296: 
  297: static void write_logfile(FILE * f, int priority, const char * lines)
  298: {
  299: 	time_t now; char stamp[sizeof("2004-04-04 10:00:00")+13];
  300: 	int i;
  301: 
  302: 	now = time((time_t*)0);
  303: 	if (!strftime(stamp, sizeof(stamp)-1, "%Y-%m-%d %H:%M:%S", localtime(&now)))
  304: 		strcpy(stamp,"?");
  305: 
  306: 	for (i = 0; lines[i]; i++) {
  307: 		int len = 0;
  308: 		while (lines[i+len] && lines[i+len] != '\n')
  309: 			len++;
  310: 		if (len > 0) {
  311: 			fprintf(f, "%s %s[%s]: %-5s: ",
  312: 				stamp, sl_ident, sl_pidstr, pri2text(priority));
  313: 			fwrite(lines+i, len, 1, f);
  314: 			fputc('\n', f);
  315: 			i += len;
  316: 		}
  317: 		if (!lines[i])
  318: 			break;
  319: 	}
  320: }
  321: 
  322: 
  323: void openlog(const char *ident, int logopt, int facility)
  324: {
  325: 	int pid;
  326: 	if (sl_logpath[0] || sl_logfile || sl_hevtsrc)
  327: 		return; // Already open
  328: 
  329: 	strncpy(sl_ident, ident, sizeof(sl_ident)-1);
  330: 	// logopt==LOG_PID assumed
  331: 	ARGUSED(logopt);
  332: 	pid = getpid();
  333: 	if (snprintf(sl_pidstr, sizeof(sl_pidstr)-1, (pid >= 0 ? "%d" : "0x%X"), pid) < 0)
  334: 		strcpy(sl_pidstr,"?");
  335: 
  336: 	if (facility == LOG_LOCAL0) // "ident.log"
  337: 		strcat(strcpy(sl_logpath, sl_ident), ".log");
  338: 	else if (facility == LOG_LOCAL1) // stdout
  339: 		sl_logfile = stdout;
  340: 	else if (facility == LOG_LOCAL2) // stderr
  341: 		sl_logfile = stderr;
  342: 	else if (LOG_LOCAL2 < facility && facility <= LOG_LOCAL7) { // "ident[1-5].log"
  343: 		snprintf(sl_logpath, sizeof(sl_logpath)-1, "%s%d.log",
  344: 			sl_ident, LOG_FAC(facility)-LOG_FAC(LOG_LOCAL2));
  345: 	}
  346: 	else // Assume LOG_DAEMON, use event log if possible, else "ident.log"
  347: 	if (!(sl_hevtsrc = RegisterEventSourceA(NULL/*localhost*/, sl_ident))) {
  348: 		// Cannot open => Use logfile
  349: 		long err = GetLastError();
  350: 		strcat(strcpy(sl_logpath, sl_ident), ".log");
  351: 		fprintf(stderr, "%s: Cannot register event source (Error=%ld), writing to %s\n",
  352: 			sl_ident, err, sl_logpath);
  353: 	}
  354: 	else {
  355: 		// Start event log thread
  356: 		start_event_logger();
  357: 	}
  358: 	//assert(sl_logpath[0] || sl_logfile || sl_hevtsrc);
  359: 
  360: }
  361: 
  362: 
  363: void closelog()
  364: {
  365: }
  366: 
  367: 
  368: void vsyslog(int priority, const char * message, va_list args)
  369: {
  370: 	char buffer[1000];
  371: 
  372: 	// Translation of %m to error text not supported yet
  373: 	if (strstr(message, "%m"))
  374: 		message = "Internal error: \"%%m\" in log message";
  375: 
  376: 	// Format message
  377: 	if (vsnprintf(buffer, sizeof(buffer)-1, message, args) < 0)
  378: 		strcpy(buffer, "Internal Error: buffer overflow");
  379: 
  380: 	if (sl_hevtsrc) {
  381: 		// Write to event log
  382: 		write_event_log(priority, buffer);
  383: 	}
  384: 	else if (sl_logfile) {
  385: 		// Write to stdout/err
  386: 		write_logfile(sl_logfile, priority, buffer);
  387: 		fflush(sl_logfile);
  388: 	}
  389: 	else if (sl_logpath[0]) {
  390: 		// Append to logfile
  391: 		FILE * f;
  392: 		if (!(f = fopen(sl_logpath, "a")))
  393: 			return;
  394: 		write_logfile(f, priority, buffer);
  395: 		fclose(f);
  396: 	}
  397: }
  398: 
  399: 
  400: #ifdef TEST
  401: // Test program
  402: 
  403: void syslog(int priority, const char *message, ...)
  404: {
  405: 	va_list args;
  406: 	va_start(args, message);
  407: 	vsyslog(priority, message, args);
  408: 	va_end(args);
  409: }
  410: 
  411: int main(int argc, char* argv[])
  412: {
  413: 	int i;
  414: 	openlog(argc < 2 ? "test" : argv[1], LOG_PID, (argc < 3 ? LOG_DAEMON : LOG_LOCAL1));
  415: 	syslog(LOG_INFO,    "Info\n");
  416: 	syslog(LOG_WARNING, "Warning %d\n\n", 42);
  417: 	syslog(LOG_ERR,     "Error %s", "Fatal");
  418: 	for (i = 0; i < 100; i++) {
  419: 		char buf[LINELEN];
  420: 		if (i % 13 == 0)
  421: 			Sleep(1000L);
  422: 		sprintf(buf, "Log Line %d\n", i);
  423: 		syslog(i % 17 ? LOG_INFO : LOG_ERR, buf);
  424: 	}
  425: 	closelog();
  426: 	return 0;
  427: }
  428: 
  429: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>