Annotation of embedaddon/smartmontools/os_win32/syslog_win32.cpp, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * os_win32/syslog_win32.cpp
                      3:  *
                      4:  * Home page of code is: http://smartmontools.sourceforge.net
                      5:  *
1.1.1.2 ! misho       6:  * Copyright (C) 2004-12 Christian Franke <smartmontools-support@lists.sourceforge.net>
1.1       misho       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
1.1.1.2 ! misho      14:  * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
1.1       misho      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: 
1.1.1.2 ! misho      36: const char *syslog_win32_cpp_cvsid = "$Id: syslog_win32.cpp 3575 2012-07-19 21:32:56Z chrfranke $"
        !            37:   SYSLOG_H_CVSID;
1.1       misho      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");
1.1.1.2 ! misho     351:                fprintf(stderr, "%s: Cannot register event source (Error=%ld), writing to %s\n",
        !           352:                        sl_ident, err, sl_logpath);
1.1       misho     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>