0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include <ndrx_config.h>
0037 #include <stdio.h>
0038 #include <stdlib.h>
0039 #include <time.h>
0040 #include <fcntl.h>
0041
0042 #include <unistd.h>
0043 #include <stdarg.h>
0044 #include <ctype.h>
0045 #include <memory.h>
0046 #include <errno.h>
0047 #include <signal.h>
0048 #include <limits.h>
0049 #include <pthread.h>
0050 #include <string.h>
0051 #include <assert.h>
0052
0053 #include <sys/time.h> /* purely for dbg_timer() */
0054 #include <sys/stat.h>
0055 #include <ndrstandard.h>
0056 #include <ndebug.h>
0057 #include <nstdutil.h>
0058 #include <limits.h>
0059 #include <sys_unix.h>
0060 #include <nstd_int.h>
0061
0062 #include "nstd_tls.h"
0063 #include "userlog.h"
0064 #include "utlist.h"
0065 #include <expluginbase.h>
0066 #include <sys_test.h>
0067 #include <lcfint.h>
0068 #include <ndebugcmn.h>
0069 #include <thlock.h>
0070
0071
0072
0073
0074
0075
0076
0077 exprivate MUTEX_LOCKDECL(M_sink_lock);
0078 exprivate ndrx_debug_file_sink_t *M_sink_hash = NULL;
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088 exprivate void ndrx_debug_fclose( ndrx_debug_file_sink_t* mysink)
0089 {
0090 if (! (mysink->flags & NDRX_LOG_FOSHSTDERR ||
0091 mysink->flags & NDRX_LOG_FOSHSTDOUT)
0092 )
0093 {
0094 NDRX_FCLOSE(mysink->fp);
0095 }
0096 }
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114 expublic ndrx_debug_file_sink_t* ndrx_debug_get_sink(const char *fname,
0115 int do_lock, ndrx_debug_t *dbg_ptr, int *p_ret)
0116 {
0117 ndrx_debug_file_sink_t *ret = NULL;
0118 long flags=0;
0119
0120 if (do_lock)
0121 {
0122 MUTEX_LOCK_V(M_sink_lock);
0123 }
0124
0125
0126 EXHASH_FIND_STR( M_sink_hash, fname, ret);
0127
0128 if (NULL==ret)
0129 {
0130
0131 ret = NDRX_FPMALLOC(sizeof(ndrx_debug_file_sink_t), 0);
0132
0133 if (NULL==ret)
0134 {
0135 userlog("Failed to malloc file sink handler (%s) bytes: %s",
0136 sizeof(ndrx_debug_file_sink_t), strerror(errno));
0137 goto out;
0138 }
0139
0140
0141 if (0==strcmp(fname, NDRX_LOG_OSSTDOUT))
0142 {
0143 ret->fp=stdout;
0144 flags |=NDRX_LOG_FOSHSTDOUT;
0145 ret->fname_org[0] = EXEOS;
0146 }
0147 else if (0==strcmp(fname, NDRX_LOG_OSSTDERR))
0148 {
0149 ret->fp=stderr;
0150 flags |=NDRX_LOG_FOSHSTDERR;
0151 ret->fname_org[0] = EXEOS;
0152 }
0153 else
0154 {
0155 ret->fp = ndrx_dbg_fopen_mkdir(fname, "a", dbg_ptr, ret);
0156
0157 if (NULL==ret->fp)
0158 {
0159
0160 if (NULL!=p_ret)
0161 {
0162 *p_ret=EXFAIL;
0163 }
0164 userlog("Failed to to open [%s]: %d/%s - fallback to stderr", fname,
0165 errno, strerror(errno));
0166 ret->fp=stderr;
0167
0168
0169
0170
0171 flags|=NDRX_LOG_FOSHSTDERR;
0172
0173
0174 NDRX_STRCPY_SAFE(ret->fname_org, fname);
0175 fname = NDRX_LOG_OSSTDERR;
0176
0177 }
0178 else
0179 {
0180
0181 ret->fname_org[0] = EXEOS;
0182 }
0183 }
0184
0185
0186
0187 MUTEX_VAR_INIT(ret->change_lock);
0188 MUTEX_VAR_INIT(ret->busy_lock);
0189 NDRX_SPIN_INIT_V(ret->writters_lock);
0190 pthread_cond_init(&ret->change_wait, NULL);
0191
0192
0193 MUTEX_VAR_INIT_RECURS(ret->line_lock);
0194
0195 NDRX_STRCPY_SAFE(ret->fname, fname);
0196 ret->writters=0;
0197 ret->chwait=0;
0198 ret->refcount=1;
0199 ret->flags=flags;
0200
0201 EXHASH_ADD_STR( M_sink_hash, fname, ret );
0202
0203 }
0204 else
0205 {
0206
0207 ret->refcount++;
0208 }
0209
0210
0211 if (dbg_ptr->flags & LOG_FACILITY_PROCESS)
0212 {
0213 ret->flags |=NDRX_LOG_FPROC;
0214
0215
0216
0217
0218 if (LOG_THREADED_LINEL & dbg_ptr->is_threaded)
0219 {
0220 ret->flags |=NDRX_LOG_FLOCK;
0221 }
0222
0223 }
0224
0225 out:
0226
0227 if (NULL!=dbg_ptr && NULL!=ret)
0228 {
0229 dbg_ptr->dbg_f_ptr = ret;
0230 NDRX_STRCPY_SAFE(dbg_ptr->filename, ret->fname);
0231 }
0232
0233 if (do_lock)
0234 {
0235 MUTEX_UNLOCK_V(M_sink_lock);
0236 }
0237
0238 if (NULL==ret)
0239 {
0240 userlog("Cannot work with out logger (OOM?)!");
0241 exit(EXFAIL);
0242 }
0243
0244 return ret;
0245 }
0246
0247
0248
0249
0250
0251
0252
0253
0254 expublic int ndrx_debug_unset_sink(ndrx_debug_file_sink_t* mysink, int do_lock, int force)
0255 {
0256 int ret = EXFALSE;
0257
0258 if (do_lock)
0259 {
0260 MUTEX_LOCK_V(M_sink_lock);
0261 }
0262
0263 mysink->refcount--;
0264
0265 assert(mysink->refcount >=0);
0266
0267
0268
0269
0270 if ((mysink->refcount == 0 && ! (mysink->flags & NDRX_LOG_FPROC)) || force)
0271 {
0272
0273 ndrx_debug_fclose(mysink);
0274
0275
0276 pthread_cond_destroy(&mysink->change_wait);
0277 MUTEX_DESTROY_V(mysink->change_lock);
0278 MUTEX_DESTROY_V(mysink->busy_lock);
0279 NDRX_SPIN_DESTROY_V(mysink->writters_lock);
0280 MUTEX_DESTROY_V(mysink->line_lock);
0281
0282
0283 EXHASH_DEL(M_sink_hash, mysink);
0284 NDRX_FPFREE(mysink);
0285
0286 ret=EXTRUE;
0287
0288 }
0289
0290 if (do_lock)
0291 {
0292 MUTEX_UNLOCK_V(M_sink_lock);
0293 }
0294
0295 return ret;
0296 }
0297
0298
0299
0300
0301
0302 expublic void ndrx_debug_addref(ndrx_debug_file_sink_t* mysink)
0303 {
0304 MUTEX_LOCK_V(M_sink_lock);
0305 mysink->refcount++;
0306 MUTEX_UNLOCK_V(M_sink_lock);
0307 }
0308
0309
0310
0311
0312
0313
0314 expublic void ndrx_debug_refcount(int *sinks, int *refs)
0315 {
0316 ndrx_debug_file_sink_t* el, *elt;
0317
0318 *sinks=0;
0319 *refs=0;
0320
0321
0322 MUTEX_LOCK_V(M_sink_lock);
0323
0324 EXHASH_ITER(hh, M_sink_hash, el, elt)
0325 {
0326 (*sinks)++;
0327 *refs = *refs + el->refcount;
0328 }
0329
0330 MUTEX_UNLOCK_V(M_sink_lock);
0331
0332
0333 }
0334
0335
0336
0337
0338
0339
0340 expublic void ndrx_debug_lock(ndrx_debug_file_sink_t* mysink)
0341 {
0342 int is_busy=EXFALSE;
0343
0344
0345 NDRX_SPIN_LOCK_V(mysink->writters_lock);
0346
0347 if (mysink->chwait)
0348 {
0349 is_busy=EXTRUE;
0350 }
0351 else
0352 {
0353 mysink->writters++;
0354 }
0355
0356 NDRX_SPIN_UNLOCK_V(mysink->writters_lock);
0357
0358 if (is_busy)
0359 {
0360
0361 MUTEX_LOCK_V(mysink->busy_lock);
0362
0363
0364 NDRX_SPIN_LOCK_V(mysink->writters_lock);
0365 mysink->writters++;
0366 NDRX_SPIN_UNLOCK_V(mysink->writters_lock);
0367
0368 MUTEX_UNLOCK_V(mysink->busy_lock);
0369
0370 }
0371
0372
0373 if (mysink->flags & NDRX_LOG_FLOCK)
0374 {
0375 MUTEX_LOCK_V(mysink->line_lock);
0376 }
0377
0378 }
0379
0380
0381
0382
0383
0384 expublic void ndrx_debug_unlock(ndrx_debug_file_sink_t* mysink)
0385 {
0386 int do_signal = EXFALSE;
0387
0388
0389
0390
0391 if (mysink->flags & NDRX_LOG_FLOCK)
0392 {
0393 MUTEX_UNLOCK_V(mysink->line_lock);
0394 }
0395
0396
0397 NDRX_SPIN_LOCK_V(mysink->writters_lock);
0398
0399 mysink->writters--;
0400
0401
0402
0403
0404
0405 if (mysink->chwait && 0==mysink->writters)
0406 {
0407 do_signal=EXTRUE;
0408 }
0409
0410 NDRX_SPIN_UNLOCK_V(mysink->writters_lock);
0411
0412 if (do_signal)
0413 {
0414 MUTEX_LOCK_V(mysink->change_lock);
0415
0416 pthread_cond_signal(&mysink->change_wait);
0417 MUTEX_UNLOCK_V(mysink->change_lock);
0418 }
0419 }
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435 expublic int ndrx_debug_changename(const char *toname, int do_lock, ndrx_debug_t *dbg_ptr,
0436 ndrx_debug_file_sink_t* fileupdate)
0437 {
0438 int ret = EXSUCCEED;
0439 int writters;
0440 ndrx_debug_file_sink_t* mysink;
0441
0442 if (NULL!=dbg_ptr)
0443 {
0444 mysink = dbg_ptr->dbg_f_ptr;
0445 }
0446 else
0447 {
0448 mysink=fileupdate;
0449 }
0450
0451 if (do_lock)
0452 {
0453
0454 MUTEX_LOCK_V(M_sink_lock);
0455 }
0456
0457
0458
0459
0460 if (fileupdate && EXEOS!=fileupdate->fname_org[0])
0461 {
0462 toname = fileupdate->fname_org;
0463 }
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476 if ( NULL!=dbg_ptr && !(LOG_FACILITY_PROCESS & dbg_ptr->flags) &&
0477 mysink->refcount > 1 && 0!=strcmp(mysink->fname, toname))
0478 {
0479
0480 ndrx_debug_unset_sink(mysink, EXFALSE, EXFALSE);
0481
0482
0483 dbg_ptr->dbg_f_ptr = ndrx_debug_get_sink(toname, EXFALSE, dbg_ptr, &ret);
0484
0485
0486 goto out_final;
0487 }
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499 MUTEX_LOCK_V(mysink->busy_lock);
0500 MUTEX_LOCK_V(mysink->change_lock);
0501
0502
0503
0504 NDRX_SPIN_LOCK_V(mysink->writters_lock);
0505 mysink->chwait=EXTRUE;
0506 writters = mysink->writters;
0507 NDRX_SPIN_UNLOCK_V(mysink->writters_lock);
0508
0509 assert(writters>=0);
0510
0511 if (writters)
0512 {
0513
0514 pthread_cond_wait(&mysink->change_wait, &mysink->change_lock);
0515 }
0516
0517 ndrx_debug_fclose(mysink);
0518
0519
0520 mysink->flags&=(~NDRX_LOG_FOSHSTDERR);
0521 mysink->flags&=(~NDRX_LOG_FOSHSTDOUT);
0522
0523
0524
0525 if (0==strcmp(toname, NDRX_LOG_OSSTDERR))
0526 {
0527 mysink->fp=stderr;
0528 mysink->flags|=NDRX_LOG_FOSHSTDERR;
0529 }
0530 else if (0==strcmp(toname, NDRX_LOG_OSSTDOUT))
0531 {
0532 mysink->fp=stdout;
0533 mysink->flags|=NDRX_LOG_FOSHSTDOUT;
0534 }
0535 else
0536 {
0537 if (NULL!=dbg_ptr)
0538 {
0539 mysink->fp=ndrx_dbg_fopen_mkdir(toname, "a", dbg_ptr, dbg_ptr->dbg_f_ptr);
0540 }
0541 else
0542 {
0543 mysink->fp=ndrx_dbg_fopen_mkdir(toname, "a", dbg_ptr, fileupdate);
0544 }
0545
0546 if (NULL==mysink->fp)
0547 {
0548 userlog("Failed to set log file to [%s]: %s -> fallback to stderr",
0549 toname, strerror(errno));
0550
0551 mysink->fp=stderr;
0552 mysink->flags|=NDRX_LOG_FOSHSTDERR;
0553
0554
0555 NDRX_STRCPY_SAFE(mysink->fname_org, toname);
0556 NDRX_STRCPY_SAFE(mysink->fname, NDRX_LOG_OSSTDERR);
0557
0558
0559
0560
0561
0562
0563
0564 ret=EXFAIL;
0565 }
0566 else
0567 {
0568 int fd = fileno(mysink->fp);
0569
0570 mysink->fname_org[0] = EXEOS;
0571 if (mysink->fname!=toname)
0572 {
0573 NDRX_STRCPY_SAFE(mysink->fname, toname);
0574 }
0575
0576 if (mysink->flags & NDRX_LOG_FSYNCSTDOUT)
0577 {
0578 if (EXFAIL==dup2(fd, STDOUT_FILENO))
0579 {
0580 userlog("%s: Failed to dup2(1): %s", __func__, strerror(errno));
0581 }
0582 }
0583
0584 if (mysink->flags & NDRX_LOG_FSYNCSTDERR)
0585 {
0586 if (EXFAIL==dup2(fd, STDERR_FILENO))
0587 {
0588 userlog("%s: Failed to dup2(2): %s", __func__, strerror(errno));
0589 }
0590 }
0591
0592 }
0593 }
0594
0595
0596 mysink->chwait=EXFALSE;
0597
0598 MUTEX_UNLOCK_V(mysink->change_lock);
0599 MUTEX_UNLOCK_V(mysink->busy_lock);
0600
0601 out:
0602
0603
0604 if (NULL!=dbg_ptr)
0605 {
0606 NDRX_STRCPY_SAFE(dbg_ptr->filename, mysink->fname);
0607 }
0608
0609 out_final:
0610
0611 if (do_lock)
0612 {
0613
0614 MUTEX_UNLOCK_V(M_sink_lock);
0615 }
0616
0617 return ret;
0618 }
0619
0620
0621
0622
0623
0624 expublic int ndrx_debug_reopen_all(void)
0625 {
0626 int ret = EXSUCCEED;
0627 char *fname;
0628 int do_run;
0629 ndrx_debug_file_sink_t* el, *elt;
0630
0631 MUTEX_LOCK_V(M_sink_lock);
0632
0633 EXHASH_ITER(hh, M_sink_hash, el, elt)
0634 {
0635
0636 if (EXEOS!=el->fname_org[0])
0637 {
0638 fname = el->fname_org;
0639 do_run = EXTRUE;
0640 }
0641 else
0642 {
0643 fname = el->fname;
0644
0645 if (el->flags & NDRX_LOG_FOSHSTDERR || el->flags & NDRX_LOG_FOSHSTDOUT)
0646 {
0647 do_run=EXFALSE;
0648 }
0649 else
0650 {
0651 do_run=EXTRUE;
0652 }
0653 }
0654
0655 if (do_run && EXSUCCEED!=ndrx_debug_changename(fname, EXFALSE, NULL, el))
0656 {
0657 ret=EXFAIL;
0658 }
0659 }
0660
0661 MUTEX_UNLOCK_V(M_sink_lock);
0662
0663 out:
0664 return ret;
0665
0666 }
0667
0668
0669
0670
0671
0672 expublic int ndrx_debug_is_proc_stderr(void)
0673 {
0674 int ret = EXFALSE;
0675
0676 MUTEX_LOCK_V(M_sink_lock);
0677
0678 if (((ndrx_debug_file_sink_t*)G_ndrx_debug.dbg_f_ptr)->flags & NDRX_LOG_FOSHSTDERR)
0679 {
0680 ret=EXTRUE;
0681 }
0682
0683 MUTEX_UNLOCK_V(M_sink_lock);
0684
0685 return ret;
0686 }
0687
0688
0689
0690
0691
0692
0693 expublic void ndrx_debug_proc_link_ndrx(long flags)
0694 {
0695 MUTEX_LOCK_V(M_sink_lock);
0696 ((ndrx_debug_file_sink_t*)G_ndrx_debug.dbg_f_ptr)->flags|=flags;
0697 MUTEX_UNLOCK_V(M_sink_lock);
0698 }
0699
0700