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