• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aremmell / libsir / 906

26 Sep 2023 10:02AM UTC coverage: 95.12% (-0.02%) from 95.136%
906

Pull #305

gitlab-ci

web-flow
Merge branch 'master' into 092423/win-evt-log
Pull Request #305: Add support for Windows Event Viewer

12 of 12 new or added lines in 2 files covered. (100.0%)

3723 of 3914 relevant lines covered (95.12%)

524431.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.52
/src/sirinternal.c
1
/*
2
 * sirinternal.c
3
 *
4
 * Author:    Ryan M. Lederman <lederman@gmail.com>
5
 * Copyright: Copyright (c) 2018-2023
6
 * Version:   2.2.4
7
 * License:   The MIT License (MIT)
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
10
 * this software and associated documentation files (the "Software"), to deal in
11
 * the Software without restriction, including without limitation the rights to
12
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
13
 * the Software, and to permit persons to whom the Software is furnished to do so,
14
 * subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included in all
17
 * copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
21
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
22
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
23
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 */
26
#include "sir/internal.h"
27
#include "sir/console.h"
28
#include "sir/defaults.h"
29
#include "sir/filecache.h"
30
#include "sir/plugins.h"
31
#include "sir/textstyle.h"
32
#include "sir/filesystem.h"
33
#include "sir/mutex.h"
34

35
#if defined(__WIN__)
36
# if defined(SIR_EVENTLOG_ENABLED)
37
#  include "sir/wineventlog.h"
38
#  pragma comment(lib, "advapi32.lib")
39
# endif
40
# if defined(__EMBARCADEROC__) && defined(_WIN64)
41
#  pragma comment(lib, "ws2_32.a")
42
# else
43
#  pragma comment(lib, "ws2_32.lib")
44
# endif
45
#endif
46

47
static sirconfig _sir_cfg      = {0};
48
static sirfcache _sir_fc       = {0};
49
static sir_plugincache _sir_pc = {0};
50

51
static sir_mutex cfg_mutex  = SIR_MUTEX_INIT;
52
static sir_mutex fc_mutex   = SIR_MUTEX_INIT;
53
static sir_mutex pc_mutex   = SIR_MUTEX_INIT;
54
static sir_mutex ts_mutex   = SIR_MUTEX_INIT;
55
static sir_once static_once = SIR_ONCE_INIT;
56

57
#if defined(__WIN__)
58
static LARGE_INTEGER _sir_perfcntr_freq = {0};
59
#endif
60

61
#if defined(__HAVE_ATOMIC_H__)
62
static atomic_uint_fast32_t _sir_magic;
63
#else
64
static volatile uint32_t _sir_magic = 0U;
65
#endif
66

67
static _sir_thread_local char _sir_tid[SIR_MAXPID]   = {0};
68
static _sir_thread_local sir_time _sir_last_thrd_chk = {0};
69
static _sir_thread_local time_t _sir_last_timestamp  = 0;
70

71
bool _sir_makeinit(sirinit* si) {
67✔
72
    bool retval = _sir_validptr(si);
67✔
73

74
    if (retval) {
67✔
75
        memset(si, 0, sizeof(sirinit));
61✔
76

77
        si->d_stdout.opts   = SIRO_DEFAULT;
67✔
78
        si->d_stdout.levels = SIRL_DEFAULT;
67✔
79

80
        si->d_stderr.opts   = SIRO_DEFAULT;
67✔
81
        si->d_stderr.levels = SIRL_DEFAULT;
67✔
82

83
#if !defined(SIR_NO_SYSTEM_LOGGERS)
84
        si->d_syslog.opts   = SIRO_DEFAULT;
54✔
85
        si->d_syslog.levels = SIRL_DEFAULT;
54✔
86
#else
87
        si->d_syslog.opts   = SIRO_MSGONLY;
13✔
88
        si->d_syslog.levels = SIRL_NONE;
13✔
89
#endif
90
    }
91

92
    return retval;
67✔
93
}
94

95
bool _sir_init(sirinit* si) {
869✔
96
    (void)_sir_seterror(_SIR_E_NOERROR);
869✔
97

98
    /* can only fail on Windows. */
99
    bool once_init = _sir_once(&static_once, _sir_init_static_once);
869✔
100
#if !defined(__WIN__)
101
    SIR_UNUSED(once_init);
102
#else
103
    if (!once_init) {
104
        _sir_selflog("error: static data initialization routine failed!");
105
        return false;
106
    }
107
#endif
108

109
    if (!_sir_validptr(si))
869✔
110
        return false;
19✔
111

112
#if defined(__HAVE_ATOMIC_H__)
113
    if (_SIR_MAGIC == atomic_load(&_sir_magic))
847✔
114
#else
115
    if (_SIR_MAGIC == _sir_magic)
116
#endif
117
        return _sir_seterror(_SIR_E_ALREADY);
24✔
118

119
    _sir_defaultlevels(&si->d_stdout.levels, sir_stdout_def_lvls);
823✔
120
    _sir_defaultopts(&si->d_stdout.opts, sir_stdout_def_opts);
823✔
121

122
    _sir_defaultlevels(&si->d_stderr.levels, sir_stderr_def_lvls);
823✔
123
    _sir_defaultopts(&si->d_stderr.opts, sir_stderr_def_opts);
823✔
124

125
#if !defined(SIR_NO_SYSTEM_LOGGERS)
126
    _sir_defaultlevels(&si->d_syslog.levels, sir_syslog_def_lvls);
613✔
127
    _sir_defaultopts(&si->d_syslog.opts, sir_syslog_def_opts);
613✔
128
#endif
129

130
    if (!_sir_init_sanity(si))
823✔
131
        return false;
19✔
132

133
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
801✔
134

135
    bool init = true;
693✔
136

137
#if defined(__HAVE_ATOMIC_H__)
138
    atomic_store(&_sir_magic, _SIR_MAGIC);
801✔
139
#else
140
    _sir_magic = _SIR_MAGIC;
141
#endif
142

143
    _sir_reset_tls();
801✔
144

145
#if defined(__WIN__)
146
    _sir_initialize_stdio();
147
#else
148
    tzset();
801✔
149
#endif
150

151
    if (!_sir_setcolormode(SIRCM_16)) {
801✔
152
        init = false;
×
153
        _sir_selflog("error: failed to set color mode!");
×
154
    }
155

156
    if (!_sir_resettextstyles()) {
801✔
157
        init = false;
×
158
        _sir_selflog("error: failed to reset text styles!");
×
159
    }
160

161
    memset(&_cfg->state, 0, sizeof(_cfg->state));
801✔
162
    memcpy(&_cfg->si, si, sizeof(sirinit));
801✔
163

164
    /* forcibly null-terminate the process name. */
165
    _cfg->si.name[SIR_MAXNAME - 1] = '\0';
801✔
166

167
    /* Store PID. */
168
    _cfg->state.pid = _sir_getpid();
801✔
169

170
    (void)snprintf(_cfg->state.pidbuf, SIR_MAXPID, SIR_PIDFORMAT,
801✔
171
        PID_CAST _cfg->state.pid);
172

173
#if !defined(SIR_NO_SYSTEM_LOGGERS)
174
    /* initialize system logger. */
175
    _sir_syslog_reset(&_cfg->si.d_syslog);
597✔
176

177
    if (_cfg->si.d_syslog.levels != SIRL_NONE &&
615✔
178
        !_sir_syslog_init(_cfg->si.name, &_cfg->si.d_syslog)) {
106✔
179
        init = false;
×
180
        _sir_selflog("failed to initialize system logger!");
×
181
    }
182
#endif
183

184
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
801✔
185

186
    _sir_selflog("initialized %s", (init ? "successfully" : "with errors"));
765✔
187

188
    SIR_ASSERT(init);
765✔
189
    return init;
729✔
190
}
191

192
bool _sir_cleanup(void) {
822✔
193
    if (!_sir_sanity())
822✔
194
        return false;
20✔
195

196
    _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, false);
799✔
197
    bool cleanup   = true;
691✔
198
    bool destroyfc = _sir_fcache_destroy(sfc);
799✔
199
    SIR_ASSERT(destroyfc);
763✔
200

201
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
799✔
202
    _sir_eqland(cleanup, destroyfc);
691✔
203

204
#if !defined(SIR_NO_PLUGINS)
205
    _SIR_LOCK_SECTION(sir_plugincache, spc, SIRMI_PLUGINCACHE, false);
745✔
206
    bool destroypc = _sir_plugin_cache_destroy(spc);
745✔
207
    SIR_ASSERT(destroypc);
709✔
208
    _SIR_UNLOCK_SECTION(SIRMI_PLUGINCACHE);
745✔
209
    _sir_eqland(cleanup, destroypc);
745✔
210
#endif
211

212
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
799✔
213

214
#if !defined(SIR_NO_SYSTEM_LOGGERS)
215
    if (!_sir_syslog_close(&_cfg->si.d_syslog)) {
595✔
216
        cleanup = false;
×
217
        _sir_selflog("error: failed to close system logger!");
×
218
    }
219

220
    _sir_syslog_reset(&_cfg->si.d_syslog);
595✔
221
#endif
222

223
    if (!_sir_resettextstyles()) {
799✔
224
        cleanup = false;
×
225
        _sir_selflog("error: failed to reset text styles!");
×
226
    }
227

228
#if defined(__HAVE_ATOMIC_H__)
229
    atomic_store(&_sir_magic, 0);
799✔
230
#else
231
    _sir_magic = 0U;
232
#endif
233

234
    _sir_reset_tls();
799✔
235

236
    memset(_cfg, 0, sizeof(sirconfig));
691✔
237
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
799✔
238

239
    _sir_selflog("cleaned up %s", (cleanup ? "successfully" : "with errors"));
763✔
240

241
    SIR_ASSERT(cleanup);
763✔
242
    return cleanup;
727✔
243
}
244

245
bool _sir_isinitialized(void) {
2,500,230✔
246
#if defined(__HAVE_ATOMIC_H__)
247
    if (_SIR_MAGIC == atomic_load(&_sir_magic))
2,500,230✔
248
        return true;
2,500,206✔
249
#else
250
    if (_SIR_MAGIC == _sir_magic)
251
        return true;
252
#endif
253
    return false;
46✔
254
}
255

256
bool _sir_sanity(void) {
2,500,162✔
257
    if (_sir_isinitialized())
2,500,162✔
258
        return true;
2,419,928✔
259
    return _sir_seterror(_SIR_E_NOTREADY);
54✔
260
}
261

262
bool _sir_init_sanity(const sirinit* si) {
823✔
263
    if (!_sir_validptr(si))
823✔
264
        return false;
×
265

266
    bool levelcheck = true;
712✔
267
    _sir_eqland(levelcheck, _sir_validlevels(si->d_stdout.levels));
823✔
268
    _sir_eqland(levelcheck, _sir_validlevels(si->d_stderr.levels));
823✔
269

270
    bool regcheck = true;
712✔
271
    _sir_eqland(regcheck, SIRL_NONE == si->d_stdout.levels);
786✔
272
    _sir_eqland(regcheck, SIRL_NONE == si->d_stderr.levels);
786✔
273

274
#if !defined(SIR_NO_SYSTEM_LOGGERS)
275
    _sir_eqland(levelcheck, _sir_validlevels(si->d_syslog.levels));
613✔
276
    _sir_eqland(regcheck, SIRL_NONE == si->d_syslog.levels);
576✔
277
#endif
278

279
    if (regcheck)
712✔
280
        _sir_selflog("warning: no level registrations set!");
41✔
281

282
    bool optscheck = true;
712✔
283
    _sir_eqland(optscheck, _sir_validopts(si->d_stdout.opts));
823✔
284
    _sir_eqland(optscheck, _sir_validopts(si->d_stderr.opts));
823✔
285

286
#if !defined(SIR_NO_SYSTEM_LOGGERS)
287
    _sir_eqland(optscheck, _sir_validopts(si->d_syslog.opts));
613✔
288
#endif
289

290
    return levelcheck && optscheck;
823✔
291
}
292

293
void _sir_reset_tls(void) {
1,600✔
294
    _sir_resetstr(_sir_tid);
1,600✔
295
    memset(&_sir_last_thrd_chk, 0, sizeof(sir_time));
1,384✔
296
    _sir_last_timestamp = 0;
1,600✔
297
    _sir_reset_tls_error();
1,600✔
298
}
1,600✔
299

300
static
301
bool _sir_updatelevels(const char* name, sir_levels* old, const sir_levels* new) {
873✔
302
    if (*old != *new) {
873✔
303
        _sir_selflog("updating %s levels from %04"PRIx16" to %04"PRIx16, name, *old, *new);
789✔
304
        *old = *new;
835✔
305
    } else {
306
        _sir_selflog("skipped superfluous update of %s levels: %04"PRIx16, name, *old);
36✔
307
    }
308
    return true;
873✔
309
}
310

311
static
312
bool _sir_updateopts(const char* name, sir_options* old, const sir_options* new) {
72,829✔
313
    if (*old != *new) {
72,829✔
314
        _sir_selflog("updating %s options from %08"PRIx32" to %08"PRIx32, name, *old, *new);
34,991✔
315
        *old = *new;
37,000✔
316
    } else {
317
        _sir_selflog("skipped superfluous update of %s options: %08"PRIx32, name, *old);
33,792✔
318
    }
319
    return true;
72,829✔
320
}
321

322
bool _sir_stdoutlevels(sirinit* si, const sir_update_config_data* data) {
424✔
323
    return _sir_updatelevels(SIR_DESTNAME_STDOUT, &si->d_stdout.levels, data->levels);
424✔
324
}
325

326
bool _sir_stdoutopts(sirinit* si, const sir_update_config_data* data) {
72,380✔
327
    return _sir_updateopts(SIR_DESTNAME_STDOUT, &si->d_stdout.opts, data->opts);
72,380✔
328
}
329

330
bool _sir_stderrlevels(sirinit* si, const sir_update_config_data* data) {
380✔
331
    return _sir_updatelevels(SIR_DESTNAME_STDERR, &si->d_stderr.levels, data->levels);
380✔
332
}
333

334
bool _sir_stderropts(sirinit* si, const sir_update_config_data* data) {
380✔
335
    return _sir_updateopts(SIR_DESTNAME_STDERR, &si->d_stderr.opts, data->opts);
380✔
336
}
337

338
bool _sir_sysloglevels(sirinit* si, const sir_update_config_data* data) {
69✔
339
    bool updated = _sir_updatelevels(SIR_DESTNAME_SYSLOG, &si->d_syslog.levels, data->levels);
69✔
340
    if (updated) {
69✔
341
        _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
69✔
342
        updated = _sir_syslog_updated(si, data);
69✔
343
        _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_LEVELS);
69✔
344
    }
345
    return updated;
69✔
346
}
347

348
bool _sir_syslogopts(sirinit* si, const sir_update_config_data* data) {
69✔
349
    bool updated = _sir_updateopts(SIR_DESTNAME_SYSLOG, &si->d_syslog.opts, data->opts);
69✔
350
    if (updated) {
69✔
351
        _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_OPTIONS);
69✔
352
        updated = _sir_syslog_updated(si, data);
69✔
353
        _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_OPTIONS);
69✔
354
    }
355
    return updated;
69✔
356
}
357

358
bool _sir_syslogid(sirinit* si, const sir_update_config_data* data) {
107✔
359
    bool cur_valid = _sir_validstrnofail(si->d_syslog.identity);
107✔
360
    if (!cur_valid || 0 != strncmp(si->d_syslog.identity, data->sl_identity, SIR_MAX_SYSLOG_ID)) {
107✔
361
        _sir_selflog("updating %s identity from '%s' to '%s'", SIR_DESTNAME_SYSLOG,
66✔
362
            si->d_syslog.identity, data->sl_identity);
363
        _sir_strncpy(si->d_syslog.identity, SIR_MAX_SYSLOG_ID, data->sl_identity,
66✔
364
            strnlen(data->sl_identity, SIR_MAX_SYSLOG_ID));
63✔
365
    } else {
366
        _sir_selflog("skipped superfluous update of %s identity: '%s'", SIR_DESTNAME_SYSLOG,
39✔
367
            si->d_syslog.identity);
368
        return true;
39✔
369
    }
370

371
    _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_IDENTITY);
66✔
372
    bool updated = _sir_syslog_updated(si, data);
66✔
373
    _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_IDENTITY);
66✔
374

375
    return updated;
66✔
376
}
377

378
bool _sir_syslogcat(sirinit* si, const sir_update_config_data* data) {
90✔
379
    bool cur_valid = _sir_validstrnofail(si->d_syslog.category);
90✔
380
    if (!cur_valid || 0 != strncmp(si->d_syslog.category, data->sl_category, SIR_MAX_SYSLOG_CAT)) {
90✔
381
        _sir_selflog("updating %s category from '%s' to '%s'", SIR_DESTNAME_SYSLOG,
45✔
382
            si->d_syslog.category, data->sl_category);
383
        _sir_strncpy(si->d_syslog.category, SIR_MAX_SYSLOG_CAT, data->sl_category,
45✔
384
            strnlen(data->sl_category, SIR_MAX_SYSLOG_CAT));
42✔
385
    } else {
386
        _sir_selflog("skipped superfluous update of %s category: '%s'", SIR_DESTNAME_SYSLOG,
42✔
387
            si->d_syslog.identity);
388
        return true;
42✔
389
    }
390

391
    _sir_setbitshigh(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_CATEGORY);
45✔
392
    bool updated = _sir_syslog_updated(si, data);
45✔
393
    _sir_setbitslow(&si->d_syslog._state.mask, SIRSL_UPDATED | SIRSL_CATEGORY);
45✔
394

395
    return updated;
45✔
396
}
397

398
bool _sir_writeinit(const sir_update_config_data* data, sirinit_update update) {
73,891✔
399
    (void)_sir_seterror(_SIR_E_NOERROR);
73,891✔
400

401
    if (!_sir_sanity() || !_sir_validupdatedata(data) || !_sir_validfnptr(update))
73,889✔
402
        return false;
×
403

404
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
73,882✔
405

406
    bool updated = update(&_cfg->si, data);
73,899✔
407
    if (!updated)
69,794✔
408
        _sir_selflog("error: update routine failed!");
×
409

410
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
73,899✔
411
    return updated;
73,899✔
412
}
413

414
void* _sir_locksection(sir_mutex_id mid) {
9,067,029✔
415
    sir_mutex* m = NULL;
9,067,029✔
416
    void* sec    = NULL;
9,067,029✔
417

418
    bool enter = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexlock(m);
9,067,029✔
419
    SIR_ASSERT(enter);
9,014,518✔
420

421
    return enter ? sec : NULL;
9,070,288✔
422
}
423

424
void _sir_unlocksection(sir_mutex_id mid) {
9,069,031✔
425
    sir_mutex* m = NULL;
9,069,031✔
426
    void* sec    = NULL;
9,069,031✔
427

428
    bool leave = _sir_mapmutexid(mid, &m, &sec) && _sir_mutexunlock(m);
9,069,031✔
429
    SIR_ASSERT_UNUSED(leave, leave);
9,015,622✔
430
}
9,071,717✔
431

432
bool _sir_mapmutexid(sir_mutex_id mid, sir_mutex** m, void** section) {
18,129,071✔
433
    sir_mutex* tmpm;
434
    void* tmpsec;
435

436
    switch (mid) {
18,129,071✔
437
        case SIRMI_CONFIG:
8,666,775✔
438
            tmpm   = &cfg_mutex;
8,666,775✔
439
            tmpsec = &_sir_cfg;
8,666,775✔
440
            break;
8,666,775✔
441
        case SIRMI_FILECACHE:
4,476,492✔
442
            tmpm   = &fc_mutex;
4,400,514✔
443
            tmpsec = &_sir_fc;
4,400,514✔
444
            break;
4,476,492✔
445
        case SIRMI_PLUGINCACHE:
244,813✔
446
            tmpm   = &pc_mutex;
204,899✔
447
            tmpsec = &_sir_pc;
204,899✔
448
            break;
244,813✔
449
        case SIRMI_TEXTSTYLE:
4,633,440✔
450
            tmpm   = &ts_mutex;
4,533,767✔
451
            tmpsec = &sir_text_style_section;
4,533,767✔
452
            break;
4,633,440✔
453
        // GCOVR_EXCL_START
454
        default: /* this should never happen. */
455
            SIR_ASSERT(false);
456
            tmpm   = NULL;
457
            tmpsec = NULL;
458
            break;
459
        // GCOVR_EXCL_STOP
460
    }
461

462
    *m = tmpm;
18,142,612✔
463

464
    if (section)
18,142,612✔
465
        *section = tmpsec;
18,129,447✔
466

467
    return *m != NULL && (!section || *section != NULL);
18,142,612✔
468
}
469

470
#if !defined(__WIN__)
471
void _sir_init_static_once(void) {
59✔
472
    (void)_sir_init_common_static();
59✔
473
}
59✔
474
#else /* __WIN__ */
475
BOOL CALLBACK _sir_init_static_once(PINIT_ONCE ponce, PVOID param, PVOID* ctx) {
476
    SIR_UNUSED(ponce);
477
    SIR_UNUSED(param);
478
    SIR_UNUSED(ctx);
479
    return _sir_init_common_static() ? TRUE : FALSE;
480
}
481
#endif
482

483
bool _sir_init_common_static(void) {
59✔
484
#if defined(__HAVE_ATOMIC_H__)
485
    atomic_init(&_sir_magic, 0);
59✔
486
#endif
487

488
#if defined(__WIN__)
489
    (void)QueryPerformanceFrequency(&_sir_perfcntr_freq);
490
#endif
491

492
    bool created = _sir_mutexcreate(&cfg_mutex);
59✔
493
    SIR_ASSERT(created);
57✔
494

495
    _sir_eqland(created, _sir_mutexcreate(&fc_mutex));
59✔
496
    SIR_ASSERT(created);
57✔
497

498
    _sir_eqland(created, _sir_mutexcreate(&pc_mutex));
59✔
499
    SIR_ASSERT(created);
57✔
500

501
    _sir_eqland(created, _sir_mutexcreate(&ts_mutex));
59✔
502
    SIR_ASSERT(created);
57✔
503

504
    return created;
59✔
505
}
506

507
bool _sir_once(sir_once* once, sir_once_fn func) {
869✔
508
#if !defined(__WIN__)
509
    int ret = pthread_once(once, func);
869✔
510
    return 0 == ret ? true : _sir_handleerr(ret);
869✔
511
#else /* __WIN__ */
512
    return (FALSE != InitOnceExecuteOnce(once, func, NULL, NULL)) ? true
513
        : _sir_handlewin32err(GetLastError());
514
#endif
515
}
516

517
PRINTF_FORMAT_ATTR(2, 0)
518
bool _sir_logv(sir_level level, PRINTF_FORMAT const char* format, va_list args) {
2,159,341✔
519
    if (!_sir_sanity() || !_sir_validlevel(level) || !_sir_validstr(format))
2,159,341✔
520
        return false;
44✔
521

522
    (void)_sir_seterror(_SIR_E_NOERROR);
2,159,295✔
523

524
    _SIR_LOCK_SECTION(sirconfig, _cfg, SIRMI_CONFIG, false);
2,159,295✔
525

526
    sirbuf buf = {0};
2,159,302✔
527

528
    /* from time to time, update the host name in the config, just in case. */
529
    time_t now_sec = -1;
2,159,302✔
530
    if (-1 != time(&now_sec) &&
2,159,302✔
531
        (now_sec - _cfg->state.last_hname_chk) > SIR_HNAME_CHK_INTERVAL) {
2,151,281✔
532
        _sir_selflog("updating hostname...");
8,433✔
533
        if (!_sir_gethostname(_cfg->state.hostname)) {
8,456✔
534
            _sir_selflog("error: failed to get hostname!");
8,021✔
535
        } else {
536
            _cfg->state.last_hname_chk = now_sec;
435✔
537
            _sir_selflog("hostname: '%s'", _cfg->state.hostname);
412✔
538
        }
539
    }
540

541
    /* format timestamp (h/m/s only if the integer time has changed). */
542
    long now_msec = 0L;
2,159,302✔
543
    bool gettime = _sir_clock_gettime(SIR_WALLCLOCK, &now_sec, &now_msec);
2,159,302✔
544
    SIR_ASSERT_UNUSED(gettime, gettime);
2,151,281✔
545

546
    /* milliseconds. */
547
    _sir_snprintf_trunc(buf.msec, SIR_MAXMSEC, SIR_MSECFORMAT, now_msec);
2,159,302✔
548

549
    /* hours/minutes/seconds. */
550
    if (now_sec > _sir_last_timestamp || !*_cfg->state.timestamp) {
2,159,302✔
551
        _sir_last_timestamp = now_sec;
8,814✔
552
        bool fmt = _sir_formattime(now_sec, _cfg->state.timestamp, SIR_TIMEFORMAT);
8,814✔
553
        SIR_ASSERT_UNUSED(fmt, fmt);
8,774✔
554
    }
555

556
    /* check elapsed time since updating thread identifier/name. */
557
    sir_time thrd_chk;
558
    double msec_since_thrd_chk = _sir_msec_since(&_sir_last_thrd_chk, &thrd_chk);
2,159,302✔
559

560
    /* update the thread identifier/name if enough time has elapsed. */
561
    if (msec_since_thrd_chk > SIR_THRD_CHK_INTERVAL) {
2,159,302✔
562
        _sir_last_thrd_chk = thrd_chk;
813✔
563

564
        pid_t tid         = _sir_gettid();
813✔
565
        bool resolved_tid = false;
690✔
566

567
        /* prefer thread names. */
568
        resolved_tid = _sir_getthreadname(_sir_tid);
813✔
569

570
        /* if tid is identical to pid... */
571
        if (!resolved_tid && tid == _cfg->state.pid) {
813✔
572
            /* don't use anything to identify the thread. */
573
            _sir_resetstr(_sir_tid);
163✔
574
            resolved_tid = true;
136✔
575
        }
576

577
        /* fall back on tid. */
578
        if (!resolved_tid)
690✔
579
            _sir_snprintf_trunc(_sir_tid, SIR_MAXPID, SIR_PIDFORMAT,
×
580
                PID_CAST tid);
581
    }
582

583
    sirconfig cfg;
584
    memcpy(&cfg, _cfg, sizeof(sirconfig));
2,135,239✔
585
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
2,159,302✔
586

587
    buf.timestamp = cfg.state.timestamp;
2,159,302✔
588
    buf.hostname  = cfg.state.hostname;
2,159,302✔
589
    buf.pid       = cfg.state.pidbuf;
2,159,302✔
590
    buf.name      = cfg.si.name;
2,159,302✔
591

592
    const char* style_str = _sir_gettextstyle(level);
2,159,302✔
593

594
    SIR_ASSERT(NULL != style_str);
2,151,281✔
595
    if (NULL != style_str)
2,143,260✔
596
        (void)_sir_strncpy(buf.style, SIR_MAXSTYLE, style_str,
2,159,302✔
597
            strnlen(style_str, SIR_MAXSTYLE));
598

599
    buf.level = _sir_formattedlevelstr(level);
2,159,301✔
600

601
    if (_sir_validstrnofail(_sir_tid))
2,159,301✔
602
        (void)_sir_strncpy(buf.tid, SIR_MAXPID, _sir_tid,
2,085,477✔
603
            strnlen(_sir_tid, SIR_MAXPID));
604

605
    (void)vsnprintf(buf.message, SIR_MAXMESSAGE, format, args);
2,135,237✔
606

607
    if (!_sir_validstrnofail(buf.message))
2,159,298✔
608
        return _sir_seterror(_SIR_E_INTERNAL);
21✔
609

610
    bool match             = false;
2,135,220✔
611
    bool exit_early        = false;
2,135,220✔
612
    bool update_last_props = true;
2,135,220✔
613
    uint64_t hash          = 0ULL;
2,135,220✔
614

615
    if (cfg.state.last.level == level &&
2,159,280✔
616
        cfg.state.last.prefix[0] == buf.message[0]  &&
2,112,043✔
617
        cfg.state.last.prefix[1] == buf.message[1]) {
2,066,433✔
618
        hash  = FNV64_1a(buf.message);
2,077,313✔
619
        match = cfg.state.last.hash == hash;
2,077,313✔
620
    }
621

622
    if (match) {
2,146,735✔
623
        cfg.state.last.counter++;
33,071✔
624

625
        /* _sir_selflog("message '%s' matches last; incremented counter to %zu", buf.message,
626
            cfg.state.last.counter); */
627

628
        if (cfg.state.last.counter >= cfg.state.last.threshold - 2) {
33,071✔
629
            size_t old_threshold = cfg.state.last.threshold;
912✔
630

631
            update_last_props = false;
912✔
632
            cfg.state.last.threshold *= SIR_SQUELCH_BACKOFF_FACTOR;
1,056✔
633
            cfg.state.last.squelch = true;
1,056✔
634

635
            _sir_selflog("hit squelch threshold of %zu; setting new threshold"
1,008✔
636
                         " to %zu (factor: %d)", old_threshold,
637
                         cfg.state.last.threshold, SIR_SQUELCH_BACKOFF_FACTOR);
638

639
            (void)snprintf(buf.message, SIR_MAXMESSAGE, SIR_SQUELCH_MSG_FORMAT, old_threshold);
912✔
640
        } else if (cfg.state.last.squelch) {
32,015✔
641
            exit_early = true;
26,733✔
642
        }
643
    } else {
644
        cfg.state.last.squelch   = false;
2,126,209✔
645
        cfg.state.last.counter   = 0;
2,126,209✔
646
        cfg.state.last.threshold = SIR_SQUELCH_THRESHOLD;
2,126,209✔
647
        /* _sir_selflog("message '%s' does not match last; resetting", buf.message); */
648
    }
649

650
    _cfg = _sir_locksection(SIRMI_CONFIG);
2,159,280✔
651
    if (!_cfg)
2,159,280✔
652
        return _sir_seterror(_SIR_E_INTERNAL);
×
653

654
    _cfg->state.last.squelch = cfg.state.last.squelch;
2,159,280✔
655

656
    if (update_last_props) {
2,159,280✔
657
        _cfg->state.last.level     = level;
2,158,224✔
658
        _cfg->state.last.hash      = hash;
2,158,224✔
659
        _cfg->state.last.prefix[0] = buf.message[0];
2,158,224✔
660
        _cfg->state.last.prefix[1] = buf.message[1];
2,158,224✔
661
    }
662

663
    _cfg->state.last.counter   = cfg.state.last.counter;
2,159,280✔
664
    _cfg->state.last.threshold = cfg.state.last.threshold;
2,159,280✔
665

666
    _SIR_UNLOCK_SECTION(SIRMI_CONFIG);
2,159,280✔
667

668
    if (exit_early)
2,159,276✔
669
        return false;
26,733✔
670

671
    bool dispatched = _sir_dispatch(&cfg.si, level, &buf);
2,128,322✔
672
    return update_last_props ? dispatched : false;
2,128,325✔
673
}
674

675
bool _sir_dispatch(const sirinit* si, sir_level level, sirbuf* buf) {
2,128,321✔
676
    bool retval       = true;
2,108,482✔
677
    size_t dispatched = 0;
2,108,482✔
678
    size_t wanted     = 0;
2,108,482✔
679

680
    if (_sir_bittest(si->d_stdout.levels, level)) {
2,128,321✔
681
        const char* write = _sir_format(true, si->d_stdout.opts, buf);
1,124,736✔
682
        bool wrote        = _sir_validstrnofail(write) &&
2,249,481✔
683
            _sir_write_stdout(write, buf->output_len);
1,124,741✔
684
        _sir_eqland(retval, wrote);
1,105,499✔
685

686
        if (wrote)
1,105,499✔
687
            dispatched++;
1,099,173✔
688
        wanted++;
1,105,499✔
689
    }
690

691
    if (_sir_bittest(si->d_stderr.levels, level)) {
2,128,322✔
692
        const char* write = _sir_format(true, si->d_stderr.opts, buf);
1,285✔
693
        bool wrote        = _sir_validstrnofail(write) &&
2,570✔
694
            _sir_write_stderr(write, buf->output_len);
1,285✔
695
        _sir_eqland(retval, wrote);
1,285✔
696

697
        if (wrote)
1,285✔
698
            dispatched++;
1,276✔
699
        wanted++;
1,285✔
700
    }
701

702
#if !defined(SIR_NO_SYSTEM_LOGGERS)
703
    if (_sir_bittest(si->d_syslog.levels, level)) {
2,093,286✔
704
        if (_sir_syslog_write(level, buf, &si->d_syslog))
679✔
705
            dispatched++;
679✔
706
        wanted++;
679✔
707
    }
708
#endif
709

710
    _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, false);
2,128,322✔
711
    size_t fdispatched = 0;
2,128,326✔
712
    size_t fwanted     = 0;
2,128,326✔
713
    _sir_eqland(retval, _sir_fcache_dispatch(sfc, level, buf, &fdispatched, &fwanted));
2,128,326✔
714
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
2,128,326✔
715

716
    dispatched += fdispatched;
2,128,322✔
717
    wanted += fwanted;
2,128,322✔
718

719
#if !defined(SIR_NO_PLUGINS)
720
    _SIR_LOCK_SECTION(sir_plugincache, spc, SIRMI_PLUGINCACHE, false);
121,577✔
721
    size_t pdispatched = 0;
121,581✔
722
    size_t pwanted     = 0;
121,581✔
723
    _sir_eqland(retval, _sir_plugin_cache_dispatch(spc, level, buf, &pdispatched, &pwanted));
121,581✔
724
    _SIR_UNLOCK_SECTION(SIRMI_PLUGINCACHE);
121,581✔
725

726
    dispatched += pdispatched;
121,581✔
727
    wanted += pwanted;
121,581✔
728
#endif
729

730
    if (0 == wanted) {
2,128,326✔
731
        _sir_selflog("error: no destinations registered for level %04"PRIx16, level);
730✔
732
        return _sir_seterror(_SIR_E_NODEST);
776✔
733
    }
734

735
    return retval && (dispatched == wanted);
2,127,549✔
736
}
737

738
const char* _sir_format(bool styling, sir_options opts, sirbuf* buf) {
2,277,276✔
739
    if (_sir_validptr(buf)) {
2,277,276✔
740
        bool first = true;
2,232,227✔
741

742
        _sir_resetstr(buf->output);
2,277,234✔
743

744
        if (styling)
2,277,271✔
745
            _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->style, SIR_MAXSTYLE);
1,126,016✔
746

747
        if (!_sir_bittest(opts, SIRO_NOTIME)) {
2,277,265✔
748
            _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->timestamp, SIR_MAXTIME);
2,110,858✔
749
            first = false;
2,091,980✔
750

751
#if defined(SIR_MSEC_TIMER)
752
            if (!_sir_bittest(opts, SIRO_NOMSEC))
2,110,861✔
753
                _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->msec, SIR_MAXMSEC);
74,742✔
754
#endif
755
        }
756

757
        if (!_sir_bittest(opts, SIRO_NOHOST) && _sir_validstrnofail(buf->hostname)) {
2,277,223✔
758
            if (!first)
1,033,561✔
759
                _sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,001,553✔
760
            _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->hostname, SIR_MAXHOST);
1,033,561✔
761
            first = false;
1,027,267✔
762
        }
763

764
        if (!_sir_bittest(opts, SIRO_NOLEVEL)) {
2,277,116✔
765
            if (!first)
2,163,756✔
766
                _sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
2,110,938✔
767
            _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->level, SIR_MAXLEVEL);
2,163,755✔
768
            first = false;
2,137,632✔
769
        }
770

771
        bool name = false;
2,232,060✔
772
        if (!_sir_bittest(opts, SIRO_NONAME) && _sir_validstrnofail(buf->name)) {
2,277,116✔
773
            if (!first)
1,110,225✔
774
                _sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,106,213✔
775
            _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->name, SIR_MAXNAME);
1,110,236✔
776
            first = false;
1,091,420✔
777
            name  = true;
1,091,420✔
778
        }
779

780
        bool wantpid = !_sir_bittest(opts, SIRO_NOPID) && _sir_validstrnofail(buf->pid);
2,277,240✔
781
        bool wanttid = !_sir_bittest(opts, SIRO_NOTID) && _sir_validstrnofail(buf->tid);
2,277,557✔
782

783
        if (wantpid || wanttid) {
2,277,416✔
784
            if (name)
2,144,326✔
785
                _sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDPREFIX, 1);
1,104,750✔
786
            else if (!first)
1,039,576✔
787
                _sir_strncat(buf->output, SIR_MAXOUTPUT, " ", 1);
1,039,567✔
788

789
            if (wantpid)
2,144,337✔
790
                _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->pid, SIR_MAXPID);
2,076,550✔
791

792
            if (wanttid) {
2,144,338✔
793
                if (wantpid)
2,138,814✔
794
                    _sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSEPARATOR, 1);
2,071,116✔
795
                _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->tid, SIR_MAXPID);
2,138,810✔
796
            }
797

798
            if (name)
2,144,210✔
799
                _sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_PIDSUFFIX, 1);
1,104,703✔
800

801
            first = false;
2,119,148✔
802
        }
803

804
        if (!first)
2,252,238✔
805
            _sir_strncat(buf->output, SIR_MAXOUTPUT, ": ", 2);
2,199,463✔
806

807
        _sir_strncat(buf->output, SIR_MAXOUTPUT, buf->message, SIR_MAXMESSAGE);
2,277,231✔
808

809
        if (styling)
2,277,131✔
810
            _sir_strncat(buf->output, SIR_MAXOUTPUT, SIR_ESC_RST, SIR_MAXSTYLE);
1,125,990✔
811

812
        _sir_strncat(buf->output, SIR_MAXOUTPUT, "\n", 1);
2,277,140✔
813

814
        buf->output_len = strnlen(buf->output, SIR_MAXOUTPUT);
2,277,214✔
815

816
        return buf->output;
2,277,214✔
817
    }
818

819
    return NULL;
×
820
}
821

822
bool _sir_syslog_init(const char* name, sir_syslog_dest* ctx) {
241✔
823
#if !defined(SIR_NO_SYSTEM_LOGGERS)
824
    if (!_sir_validptr(name) || !_sir_validptr(ctx))
241✔
825
        return false;
×
826

827
    /* begin resolve identity. */
828
    if (!_sir_validstrnofail(ctx->identity)) {
241✔
829
        _sir_selflog("ctx->identity is no good; trying name");
61✔
830
        if (_sir_validstrnofail(name)) {
65✔
831
            _sir_selflog("using name");
23✔
832
            _sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, name, strnlen(name, SIR_MAX_SYSLOG_ID));
24✔
833
        } else {
834
            _sir_selflog("name is no good; trying filename");
38✔
835
            char* appbasename = _sir_getappbasename();
41✔
836
            if (_sir_validstrnofail(appbasename)) {
41✔
837
                _sir_selflog("filename is good: %s", appbasename);
37✔
838
                _sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, appbasename,
37✔
839
                    strnlen(appbasename, SIR_MAX_SYSLOG_ID));
840
            } else {
841
                _sir_selflog("filename no good; using fallback");
4✔
842
                _sir_strncpy(ctx->identity, SIR_MAX_SYSLOG_ID, SIR_FALLBACK_SYSLOG_ID,
4✔
843
                    strnlen(SIR_FALLBACK_SYSLOG_ID, SIR_MAX_SYSLOG_ID));
844
            }
845
            _sir_safefree(&appbasename);
41✔
846
        }
847
    } else {
848
        _sir_selflog("already have identity");
167✔
849
    }
850

851
    /* category */
852
    if (!_sir_validstrnofail(ctx->category)) {
241✔
853
        _sir_selflog("category not set; using fallback");
82✔
854
        _sir_strncpy(ctx->category, SIR_MAX_SYSLOG_CAT, SIR_FALLBACK_SYSLOG_CAT,
86✔
855
            strnlen(SIR_FALLBACK_SYSLOG_CAT, SIR_MAX_SYSLOG_CAT));
856
    } else {
857
        _sir_selflog("already have category");
146✔
858
    }
859

860
    _sir_setbitshigh(&ctx->_state.mask, SIRSL_IS_INIT);
241✔
861
    _sir_selflog("resolved (identity: '%s', category: '%s')", ctx->identity, ctx->category);
228✔
862

863
    return _sir_syslog_open(ctx);
241✔
864
#else
865
    SIR_UNUSED(name);
866
    SIR_UNUSED(ctx);
867
    return false;
×
868
#endif
869
}
870

871
bool _sir_syslog_open(sir_syslog_dest* ctx) {
241✔
872
#if !defined(SIR_NO_SYSTEM_LOGGERS)
873
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_INIT)) {
241✔
874
        _sir_selflog("not initialized; ignoring");
×
875
        return _sir_seterror(_SIR_E_INVALID);
×
876
    }
877

878
    if (_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
241✔
879
        _sir_selflog("log already open; ignoring");
×
880
        return true;
×
881
    }
882

883
    _sir_selflog("opening log (levels: %04"PRIx16", options: %08"PRIx32")", ctx->levels,
241✔
884
        ctx->opts);
885

886
# if defined(SIR_OS_LOG_ENABLED)
887
    ctx->_state.logger = (void*)os_log_create(ctx->identity, ctx->category);
888
    _sir_selflog("opened os_log ('%s', '%s')", ctx->identity, ctx->category);
889
# elif defined(SIR_SYSLOG_ENABLED)
890
    int logopt   = LOG_NDELAY | (_sir_bittest(ctx->opts, SIRO_NOPID) ? 0 : LOG_PID);
241✔
891
    int facility = LOG_USER;
201✔
892

893
    openlog(ctx->identity, logopt, facility);
241✔
894
    _sir_selflog("opened syslog('%s', %x, %x)", ctx->identity, logopt, facility);
228✔
895
# elif defined(SIR_EVENTLOG_ENABLED)
896
    DWORD reg = EventRegister(&SIR_EVENTLOG_GUID, NULL, NULL,
897
        (PREGHANDLE)&ctx->_state.logger);
898
    if (ERROR_SUCCESS == reg) {
899
        _sir_selflog("opened eventlog('%s')", ctx->identity);
900
    } else {
901
        /* not fatal; logging calls will just silently fail. */
902
        _sir_selflog("failed to open eventlog! error: %lu", reg);
903
        (void)_sir_handlewin32err(reg);
904
    }
905
# endif
906

907
    _sir_setbitshigh(&ctx->_state.mask, SIRSL_IS_OPEN);
241✔
908
    return true;
241✔
909
#else
910
    SIR_UNUSED(ctx);
911
    return false;
×
912
#endif
913
}
914

915
bool _sir_syslog_write(sir_level level, const sirbuf* buf, const sir_syslog_dest* ctx) {
679✔
916
#if !defined(SIR_NO_SYSTEM_LOGGERS)
917
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_INIT)) {
679✔
918
        _sir_selflog("not initialized; ignoring");
×
919
        return _sir_seterror(_SIR_E_INVALID);
×
920
    }
921

922
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
679✔
923
        _sir_selflog("log not open; ignoring");
×
924
        return _sir_seterror(_SIR_E_INVALID);
×
925
    }
926

927
# if defined(SIR_OS_LOG_ENABLED)
928
    if (SIRL_DEBUG == level)
929
        os_log_debug((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
930
    else if (SIRL_INFO == level || SIRL_NOTICE == level)
931
        os_log_info((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
932
    else if (SIRL_WARN == level || SIRL_ERROR == level)
933
        os_log_error((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
934
    else if (SIRL_CRIT == level || SIRL_ALERT == level || SIRL_EMERG == level)
935
        os_log_fault((os_log_t)ctx->_state.logger, SIR_OS_LOG_FORMAT, buf->message);
936

937
    return true;
938
# elif defined(SIR_SYSLOG_ENABLED)
939
    int syslog_level;
940
    switch (level) {
679✔
941
        case SIRL_DEBUG:  syslog_level = LOG_DEBUG; break;
34✔
942
        case SIRL_INFO:   syslog_level = LOG_INFO; break;
37✔
943
        case SIRL_NOTICE: syslog_level = LOG_NOTICE; break;
86✔
944
        case SIRL_WARN:   syslog_level = LOG_WARNING; break;
86✔
945
        case SIRL_ERROR:  syslog_level = LOG_ERR; break;
86✔
946
        case SIRL_CRIT:   syslog_level = LOG_CRIT; break;
111✔
947
        case SIRL_ALERT:  syslog_level = LOG_ALERT; break;
111✔
948
        case SIRL_EMERG:  syslog_level = LOG_EMERG; break;
111✔
949
        // GCOVR_EXCL_START
950
        default: /* this should never happen. */
951
            SIR_ASSERT(false);
952
            syslog_level = LOG_DEBUG;
953
        // GCOVR_EXCL_STOP
954
    }
955

956
    syslog(syslog_level, "%s", buf->message);
679✔
957
    return true;
679✔
958
# elif defined(SIR_EVENTLOG_ENABLED)
959
    const EVENT_DESCRIPTOR* edesc = NULL;
960
    if (SIRL_DEBUG == level)
961
        edesc = &SIR_EVT_DEBUG;
962
    else if (SIRL_INFO == level || SIRL_NOTICE == level)
963
        edesc = &SIR_EVT_INFO;
964
    else if (SIRL_WARN == level)
965
        edesc = &SIR_EVT_WARNING;
966
    else if (SIRL_ERROR == level)
967
        edesc = &SIR_EVT_ERROR;
968
    else if (SIRL_CRIT == level || SIRL_ALERT == level || SIRL_EMERG == level)
969
        edesc = &SIR_EVT_CRITICAL;
970

971
    SIR_ASSERT(NULL != edesc);
972
    if (NULL == edesc)
973
        return _sir_seterror(_SIR_E_INTERNAL);
974

975
#  if defined(__HAVE_STDC_SECURE_OR_EXT1__)
976
    size_t msg_len = strnlen_s(buf->message, SIR_MAXMESSAGE) + 1;
977
#  else
978
    size_t msg_len = strnlen(buf->message, SIR_MAXMESSAGE) + 1;
979
#  endif
980
    int wlen = MultiByteToWideChar(CP_UTF8, 0UL, buf->message, (int)msg_len, NULL, 0);
981
    if (wlen <= 0)
982
        return _sir_handlewin32err(GetLastError());
983

984
    DWORD write = 1UL;
985
    wchar_t* wmsg = calloc(sizeof(wchar_t), wlen);
986
    if (NULL != wmsg) {
987
        int conv = MultiByteToWideChar(CP_UTF8, 0UL, buf->message, (int)msg_len, wmsg, wlen);
988
        if (conv > 0) {
989
            EVENT_DATA_DESCRIPTOR eddesc = {0};
990
            EventDataDescCreate(&eddesc, wmsg, (ULONG)(wlen * sizeof(wchar_t)));
991

992
            write = EventWrite((REGHANDLE)ctx->_state.logger, edesc, 1UL, &eddesc);
993
            if (ERROR_SUCCESS != write) {
994
                _sir_selflog("failed to write eventlog! error: %lu", write);
995
                (void)_sir_handlewin32err(write);
996
            }
997
        }
998
        _sir_safefree(&wmsg);
999
    }
1000

1001
    return ERROR_SUCCESS == write;
1002
# else
1003
    SIR_UNUSED(level);
1004
    SIR_UNUSED(buf);
1005
    SIR_UNUSED(ctx);
1006
    return false;
1007
# endif
1008
#else
1009
    SIR_UNUSED(level);
1010
    SIR_UNUSED(buf);
1011
    SIR_UNUSED(ctx);
1012
    return false;
×
1013
#endif
1014
}
1015

1016
bool _sir_syslog_updated(sirinit* si, const sir_update_config_data* data) {
249✔
1017
#if !defined(SIR_NO_SYSTEM_LOGGERS)
1018
    if (!_sir_validptr(si) || !_sir_validptr(data))
249✔
1019
        return false;
×
1020

1021
    if (_sir_bittest(si->d_syslog._state.mask, SIRSL_UPDATED)) {
249✔
1022
        bool levels   = _sir_bittest(si->d_syslog._state.mask, SIRSL_LEVELS);
235✔
1023
        bool options  = _sir_bittest(si->d_syslog._state.mask, SIRSL_OPTIONS);
249✔
1024
        bool category = _sir_bittest(si->d_syslog._state.mask, SIRSL_CATEGORY);
235✔
1025
        bool identity = _sir_bittest(si->d_syslog._state.mask, SIRSL_IDENTITY);
249✔
1026
        bool is_init  = _sir_bittest(si->d_syslog._state.mask, SIRSL_IS_INIT);
249✔
1027
        bool is_open  = _sir_bittest(si->d_syslog._state.mask, SIRSL_IS_OPEN);
249✔
1028

1029
        _sir_selflog("config update: (levels: %u, options: %u, category: %u,"
235✔
1030
                     " identity: %u, is_init: %u, is_open: %u)",
1031
                     levels, options, category, identity, is_init, is_open);
1032

1033
        bool must_init = false;
207✔
1034
# if defined(SIR_OS_LOG_ENABLED)
1035
        /* for os_log, if initialized and open already, only need to reconfigure
1036
         * if identity or category changed. */
1037
        must_init = (!is_init || !is_open) || (identity || category);
1038
# elif defined(SIR_SYSLOG_ENABLED)
1039
        /* for syslog, if initialized and open already, only need to reconfigure
1040
         * if identity or options changed. */
1041
        must_init = (!is_init || !is_open) || (identity || options);
249✔
1042
# elif defined(SIR_EVENTLOG_ENABLED)
1043
        /* for event log, if initialized and open already, only need to reconfigure
1044
         * if identity changed. */
1045
        must_init = (!is_init || !is_open) || identity;
1046
# endif
1047
        bool init = true;
207✔
1048
        if (must_init) {
207✔
1049
            if (is_open) /* close first; open will fail otherwise. */
135✔
1050
                init = _sir_syslog_close(&si->d_syslog);
110✔
1051

1052
            _sir_selflog("re-init...");
128✔
1053
            _sir_eqland(init, _sir_syslog_init(si->name, &si->d_syslog));
135✔
1054
            _sir_selflog("re-init %s", init ? "succeeded" : "failed");
128✔
1055
        } else {
1056
            _sir_selflog("no re-init necessary");
107✔
1057
        }
1058

1059
        return init;
249✔
1060
    }
1061

1062
    return false;
×
1063
#else
1064
    SIR_UNUSED(si);
1065
    SIR_UNUSED(data);
1066
    return false;
×
1067
#endif
1068
}
1069

1070
bool _sir_syslog_close(sir_syslog_dest* ctx) {
705✔
1071
#if !defined(SIR_NO_SYSTEM_LOGGERS)
1072
    if (!_sir_validptr(ctx))
705✔
1073
        return false;
×
1074

1075
    if (!_sir_bittest(ctx->_state.mask, SIRSL_IS_OPEN)) {
705✔
1076
        _sir_selflog("log not open; ignoring");
435✔
1077
        return true;
435✔
1078
    }
1079

1080
# if defined(SIR_OS_LOG_ENABLED)
1081
    /* Evidently, you don't need to close the handle returned from os_log_create(), and
1082
     * if you make that call again, you'll get the same cached value. so let's keep the
1083
     * value we've got in the global context. */
1084
    _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
1085
    _sir_selflog("log closure not necessary");
1086
    return true;
1087
# elif defined(SIR_SYSLOG_ENABLED)
1088
    closelog();
241✔
1089
    _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
241✔
1090
    _sir_selflog("closed log");
228✔
1091
    return true;
241✔
1092
# elif defined(SIR_EVENTLOG_ENABLED)
1093
    ULONG unreg = EventUnregister((REGHANDLE)ctx->_state.logger);
1094
    _sir_setbitslow(&ctx->_state.mask, SIRSL_IS_OPEN);
1095
    if (ERROR_SUCCESS == unreg)
1096
        _sir_selflog("closed log");
1097
    else
1098
        _sir_selflog("error: failed to close log");
1099

1100
    return ERROR_SUCCESS == unreg;
1101
# else
1102
    SIR_UNUSED(ctx);
1103
    return false;
1104
# endif
1105
#else
1106
    SIR_UNUSED(ctx);
1107
    return false;
×
1108
#endif
1109
}
1110

1111
void _sir_syslog_reset(sir_syslog_dest* ctx) {
1,192✔
1112
#if !defined(SIR_NO_SYSTEM_LOGGERS)
1113
    if (_sir_validptr(ctx)) {
1,192✔
1114
        uint32_t old       = ctx->_state.mask;
1,120✔
1115
        ctx->_state.mask   = 0U;
1,192✔
1116
        ctx->_state.logger = NULL;
1,192✔
1117
        _sir_selflog("state reset; mask was %08"PRIx32, old);
1,120✔
1118
    }
1119
#else
1120
    SIR_UNUSED(ctx);
1121
#endif
1122
}
1,192✔
1123

1124
const char* _sir_formattedlevelstr(sir_level level) {
2,159,300✔
1125
    static const size_t low  = 0;
1126
    static const size_t high = SIR_NUMLEVELS - 1;
1127

1128
    const char* retval = SIR_UNKNOWN;
2,135,237✔
1129

1130
    _SIR_DECLARE_BIN_SEARCH(low, high);
2,135,237✔
1131
    _SIR_BEGIN_BIN_SEARCH()
1132

1133
    if (sir_level_to_str_map[_mid].level == level) {
8,592,513✔
1134
        retval = sir_level_to_str_map[_mid].fmt;
2,159,301✔
1135
        break;
2,159,301✔
1136
    }
1137

1138
    _SIR_ITERATE_BIN_SEARCH((sir_level_to_str_map[_mid].level < level ? 1 : -1));
6,433,212✔
1139
    _SIR_END_BIN_SEARCH();
1140

1141
    return retval;
2,159,300✔
1142
}
1143

1144
bool _sir_clock_gettime(int clock, time_t* tbuf, long* msecbuf) {
6,318,682✔
1145
    if (tbuf) {
6,318,682✔
1146
#if defined(SIR_MSEC_POSIX)
1147
        struct timespec ts = {0};
6,318,682✔
1148
        int ret            = clock_gettime(clock, &ts);
6,318,682✔
1149
        SIR_ASSERT(0 == ret);
6,302,637✔
1150

1151
        if (0 == ret) {
6,286,592✔
1152
            *tbuf = ts.tv_sec;
6,302,717✔
1153
            if (msecbuf)
6,302,717✔
1154
                *msecbuf = ts.tv_nsec / 1000000L;
6,302,717✔
1155
        } else {
1156
            if (msecbuf)
15,965✔
1157
                *msecbuf = 0L;
15,965✔
1158
            return _sir_handleerr(errno);
15,965✔
1159
        }
1160
#elif defined(SIR_MSEC_WIN32)
1161
        SIR_UNUSED(clock);
1162
        static const ULONGLONG uepoch = (ULONGLONG)116444736e9;
1163

1164
        FILETIME ftutc = {0};
1165
        GetSystemTimePreciseAsFileTime(&ftutc);
1166

1167
        ULARGE_INTEGER ftnow = {0};
1168
        ftnow.HighPart = ftutc.dwHighDateTime;
1169
        ftnow.LowPart  = ftutc.dwLowDateTime;
1170
        ftnow.QuadPart = (ULONGLONG)((ftnow.QuadPart - uepoch) / 10000000ULL);
1171

1172
        *tbuf = (time_t)ftnow.QuadPart;
1173

1174
        SYSTEMTIME st = {0};
1175
        if (FileTimeToSystemTime(&ftutc, &st)) {
1176
            if (msecbuf)
1177
                *msecbuf = (long)st.wMilliseconds;
1178
        } else {
1179
            if (msecbuf)
1180
                *msecbuf = 0L;
1181
            return _sir_handlewin32err(GetLastError());
1182
        }
1183
#else
1184
        SIR_UNUSED(clock);
1185
        time(tbuf);
1186
        if (msecbuf)
1187
            *msecbuf = 0L;
1188
#endif
1189
        return true;
6,302,717✔
1190
    }
1191
    return false;
×
1192
}
1193

1194
double _sir_msec_since(const sir_time* when, sir_time* out) {
4,159,380✔
1195
    if (!_sir_validptr(out))
4,159,380✔
1196
        return 0.0;
×
1197
#if !defined(__WIN__)
1198
    out->sec = 0;
4,159,380✔
1199
    out->msec = 0L;
4,159,380✔
1200

1201
    bool gettime = _sir_clock_gettime(SIR_INTERVALCLOCK, &out->sec, &out->msec);
4,159,380✔
1202
    SIR_ASSERT(gettime);
4,151,356✔
1203

1204
    if (!_sir_validptrnofail(when) || !gettime || (out->sec < when->sec ||
4,159,380✔
1205
        (out->sec == when->sec && out->msec < when->msec)))
4,150,515✔
1206
        return 0.0;
8,026✔
1207

1208
    return ((((double)out->sec) * 1e3) + (double)out->msec) -
4,151,348✔
1209
           ((((double)when->sec) * 1e3) + (double)when->msec);
4,151,348✔
1210
#else /* __WIN__ */
1211
    SIR_ASSERT(_sir_perfcntr_freq.QuadPart > 0LL);
1212

1213
    if (_sir_perfcntr_freq.QuadPart <= 0LL)
1214
        (void)QueryPerformanceFrequency(&_sir_perfcntr_freq);
1215

1216
    (void)QueryPerformanceCounter(&out->counter);
1217

1218
    if (!_sir_validptrnofail(when) || out->counter.QuadPart <= when->counter.QuadPart)
1219
        return 0.0;
1220

1221
    double msec_ratio = ((double)_sir_perfcntr_freq.QuadPart) / 1e3;
1222
    return ((double)(out->counter.QuadPart - when->counter.QuadPart)) / msec_ratio;
1223
#endif
1224
}
1225

1226
pid_t _sir_getpid(void) {
817✔
1227
#if !defined(__WIN__)
1228
    return getpid();
817✔
1229
#else /* __WIN__ */
1230
    return (pid_t)GetCurrentProcessId();
1231
#endif
1232
}
1233

1234
pid_t _sir_gettid(void) {
947✔
1235
    pid_t tid = 0;
803✔
1236
#if defined(__MACOS__)
1237
    uint64_t tid64 = 0ULL;
1238
    int gettid     = pthread_threadid_np(NULL, &tid64);
1239
    if (0 != gettid)
1240
        (void)_sir_handleerr(gettid);
1241
    tid = (pid_t)tid64;
1242
#elif (defined(__BSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)) || \
1243
      defined(__DragonFly_getthreadid__)
1244
    tid = (pid_t)pthread_getthreadid_np();
1245
#elif defined(__OpenBSD__)
1246
    tid = (pid_t)getthrid();
1247
#elif defined(__SOLARIS__) || defined(__NetBSD__) || defined(__HURD__) || \
1248
      defined(__DragonFly__) || defined(__CYGWIN__) || defined(_AIX) || \
1249
      defined(__EMSCRIPTEN__)
1250
# if defined(__CYGWIN__)
1251
    tid = (pid_t)(uintptr_t)pthread_self();
1252
# else
1253
    tid = (pid_t)pthread_self();
1254
# endif
1255
#elif defined(__HAIKU__)
1256
    tid = get_pthread_thread_id(pthread_self());
1257
#elif defined(__linux__) || defined(__serenity__)
1258
# if (defined(__GLIBC__) && GLIBC_VERSION >= 23000) || defined(__serenity__)
1259
    tid = gettid();
947✔
1260
# else
1261
    tid = syscall(SYS_gettid);
1262
# endif
1263
#elif defined(__WIN__)
1264
    tid = (pid_t)GetCurrentThreadId();
1265
#else
1266
# error "unable to determine how to get a thread identifier"
1267
#endif
1268
    return tid;
947✔
1269
}
1270

1271
bool _sir_getthreadname(char name[SIR_MAXPID]) {
813✔
1272
    _sir_resetstr(name);
813✔
1273
#if defined(__MACOS__) || (defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_12_2__)) || \
1274
    (defined(__linux__) && defined(__UCLIBC__) && defined(_GNU_SOURCE)) || \
1275
    (defined(__GLIBC__) && GLIBC_VERSION >= 21200 && defined(_GNU_SOURCE)) || \
1276
    (defined(__ANDROID__) &&  __ANDROID_API__ >= 26) || defined(SIR_PTHREAD_GETNAME_NP) || \
1277
    defined(__serenity__) || (defined(__linux__) && !defined(__GLIBC__) && \
1278
    defined(_GNU_SOURCE) && defined(__NEED_pthread_t))
1279
    int ret = pthread_getname_np(pthread_self(), name, SIR_MAXPID);
813✔
1280
    if (0 != ret)
813✔
1281
        return _sir_handleerr(ret);
×
1282
# if defined(__HAIKU__)
1283
    if (!(strncmp(name, "pthread func", SIR_MAXPID)))
1284
        (void)snprintf(name, SIR_MAXPID, "%ld", (long)get_pthread_thread_id(pthread_self()));
1285
# endif
1286
    return _sir_validstrnofail(name);
813✔
1287
#elif defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_11_3__)
1288
    pthread_get_name_np(pthread_self(), name, SIR_MAXPID);
1289
    return _sir_validstrnofail(name);
1290
#elif defined(__WIN__)
1291
    wchar_t* wname = NULL;
1292
    HRESULT hr     = GetThreadDescription(GetCurrentThread(), &wname);
1293
    if (FAILED(hr))
1294
        return _sir_handlewin32err(GetLastError());
1295
    bool success = true;
1296
# if defined(__HAVE_STDC_SECURE_OR_EXT1__)
1297
    size_t wlen = wcsnlen_s(wname, SIR_MAXPID);
1298
# elif defined(__EMBARCADEROC__)
1299
    size_t wlen = wcslen(wname);
1300
# else
1301
    size_t wlen = wcsnlen(wname, SIR_MAXPID);
1302
# endif
1303
    if (wlen > 0) {
1304
        if (!WideCharToMultiByte(CP_UTF8, 0UL, wname, (int)wlen, name,
1305
            SIR_MAXPID, NULL, NULL)) {
1306
            success = false;
1307
            (void)_sir_handlewin32err(GetLastError());
1308
        }
1309
    }
1310
    (void)LocalFree(wname);
1311
    return success && _sir_validstrnofail(name);
1312
#else
1313
# if !defined(SUNLINT) && !defined(_AIX) && !defined(__HURD__)
1314
#  pragma message("unable to determine how to get a thread name")
1315
# endif
1316
    SIR_UNUSED(name);
1317
    return false;
1318
#endif
1319
}
1320

1321
bool _sir_setthreadname(const char* name) {
237✔
1322
    if (!_sir_validptr(name))
237✔
1323
        return false;
×
1324
#if defined(__MACOS__)
1325
    int ret = pthread_setname_np(name);
1326
    return (0 != ret) ? _sir_handleerr(ret) : true;
1327
#elif defined(__HAIKU__)
1328
    status_t ret = rename_thread(find_thread(NULL), name);
1329
    return (B_OK != ret) ? _sir_handleerr((int)ret) : true;
1330
#elif defined(__NetBSD__)
1331
    int ret = pthread_setname_np(pthread_self(), "%s", name);
1332
    return (0 != ret) ? _sir_handleerr(ret) : true;
1333
#elif (defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_12_2__)) || \
1334
      (defined(__linux__) && defined(__UCLIBC__) && defined(_GNU_SOURCE)) || \
1335
      (defined(__GLIBC__) && GLIBC_VERSION >= 21200 && defined(_GNU_SOURCE)) || \
1336
       defined(__QNXNTO__) || defined(__SOLARIS__) || defined(SIR_PTHREAD_GETNAME_NP) || \
1337
       defined(__ANDROID__) && !defined(__OpenBSD__) || defined(__serenity__) || \
1338
      (defined(__linux__) && !defined(__GLIBC__) && \
1339
       defined(_GNU_SOURCE) && defined(__NEED_pthread_t))
1340
    int ret = pthread_setname_np(pthread_self(), name);
237✔
1341
    return (0 != ret) ? _sir_handleerr(ret) : true;
237✔
1342
#elif defined(__OpenBSD__) || defined(__BSD__) && defined(__FreeBSD_PTHREAD_NP_11_3__)
1343
    pthread_set_name_np(pthread_self(), name);
1344
    return true;
1345
#elif defined(__WIN__)
1346
# if defined(__HAVE_STDC_SECURE_OR_EXT1__)
1347
    size_t name_len = strnlen_s(name, SIR_MAXPID);
1348
# else
1349
    size_t name_len = strnlen(name, SIR_MAXPID);
1350
# endif
1351
    if (0 == name_len)
1352
        name_len = 1;
1353

1354
    wchar_t buf[SIR_MAXPID] = {0};
1355
    if (!MultiByteToWideChar(CP_UTF8, 0UL, name, (int)name_len, buf, SIR_MAXPID))
1356
        return _sir_handlewin32err(GetLastError());
1357

1358
    HRESULT hr = SetThreadDescription(GetCurrentThread(), buf);
1359
    return FAILED(hr) ? _sir_handlewin32err(hr) : true;
1360
#else
1361
# if !defined(SUNLINT) && !defined(_AIX)
1362
#  pragma message("unable to determine how to set a thread name")
1363
# endif
1364
    SIR_UNUSED(name);
1365
    return false;
1366
#endif
1367
}
1368

1369
bool _sir_gethostname(char name[SIR_MAXHOST]) {
8,456✔
1370
#if !defined(__WIN__)
1371
    int ret = gethostname(name, SIR_MAXHOST - 1);
8,387✔
1372
    return 0 == ret ? true : _sir_handleerr(errno);
8,456✔
1373
#else
1374
    WSADATA wsad = {0};
1375
    int ret      = WSAStartup(MAKEWORD(2, 2), &wsad);
1376
    if (0 != ret)
1377
        return _sir_handlewin32err(ret);
1378

1379
    if (SOCKET_ERROR == gethostname(name, SIR_MAXHOST)) {
1380
        int err = WSAGetLastError();
1381
        WSACleanup();
1382
        return _sir_handlewin32err(err);
1383
    }
1384

1385
    WSACleanup();
1386
    return true;
1387
#endif /* !__WIN__ */
1388
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc