Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief NDR Debug library routines
0003  *   Enduro Execution system platform library
0004  *   TODO: We might want to switch the tplogconfig() to rwlocks
0005  *   
0006  * @file ndebug.c
0007  */
0008 /* -----------------------------------------------------------------------------
0009  * Enduro/X Middleware Platform for Distributed Transaction Processing
0010  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0011  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0012  * This software is released under one of the following licenses:
0013  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0014  * See LICENSE file for full text.
0015  * -----------------------------------------------------------------------------
0016  * AGPL license:
0017  *
0018  * This program is free software; you can redistribute it and/or modify it under
0019  * the terms of the GNU Affero General Public License, version 3 as published
0020  * by the Free Software Foundation;
0021  *
0022  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0023  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0024  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0025  * for more details.
0026  *
0027  * You should have received a copy of the GNU Affero General Public License along 
0028  * with this program; if not, write to the Free Software Foundation, Inc.,
0029  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0030  *
0031  * -----------------------------------------------------------------------------
0032  * A commercial use license is available from Mavimax, Ltd
0033  * contact@mavimax.com
0034  * -----------------------------------------------------------------------------
0035  */
0036 
0037 /*---------------------------Includes-----------------------------------*/
0038 #include <ndrx_config.h>
0039 #include <stdio.h>
0040 #include <stdlib.h>
0041 #include <time.h>
0042 #include <fcntl.h>
0043 
0044 #include <unistd.h>
0045 #include <stdarg.h>
0046 #include <ctype.h>
0047 #include <memory.h>
0048 #include <errno.h>
0049 #include <signal.h>
0050 #include <limits.h>
0051 #include <pthread.h>
0052 #include <string.h>
0053 
0054 #include <sys/time.h>                   /* purely for dbg_timer()       */
0055 #include <sys/stat.h>
0056 #include <ndrstandard.h>
0057 #include <ndebug.h>
0058 #include <nstdutil.h>
0059 #include <limits.h>
0060 #include <sys_unix.h>
0061 #include <cconfig.h>
0062 #include <nstd_int.h>
0063 #include "nstd_tls.h"
0064 #include "userlog.h"
0065 #include "utlist.h"
0066 #include <expluginbase.h>
0067 #include <sys_test.h>
0068 #include <lcfint.h>
0069 #include <exregex.h>
0070 /*---------------------------Externs------------------------------------*/
0071 /*---------------------------Macros-------------------------------------*/
0072 
0073 #define BUFFER_CONTROL(dbg_p)\
0074     dbg_p->lines_written++;\
0075     if (dbg_p->lines_written >= dbg_p->buf_lines)\
0076     {\
0077         dbg_p->lines_written = 0;\
0078         fflush( ((ndrx_debug_file_sink_t*)dbg_p->dbg_f_ptr)->fp);\
0079     }
0080 
0081 #define BUFFERED_PRINT_LINE(dbg_p, line)\
0082     fputs(line, ((ndrx_debug_file_sink_t*)dbg_p->dbg_f_ptr)->fp);\
0083     fputs("\n", ((ndrx_debug_file_sink_t*)dbg_p->dbg_f_ptr)->fp);\
0084     BUFFER_CONTROL(dbg_p)
0085 
0086 
0087 #define DEFAULT_BUFFER_SIZE         50000
0088 
0089 /*
0090  * Logger initializer 
0091  */
0092 #define DEBUG_INITIALIZER(CODE, MODULE, FLAGS)   \
0093 {\
0094     .level = 0,\
0095     .dbg_f_ptr = NULL,\
0096     .filename = "",\
0097     .filename_th_template="",\
0098     .pid = 0,\
0099     .buf_lines = 0,\
0100     .buffer_size = 0,\
0101     .lines_written = 0,\
0102     .module=MODULE,\
0103     .is_user=0,\
0104     .code=CODE,\
0105     .iflags="",\
0106     .is_threaded=0,\
0107     .threadnr=0,\
0108     .flags=FLAGS,\
0109     .memlog=NULL,\
0110     .hostnamecrc32=0x0,\
0111     .swait=NDRX_LOG_SWAIT_DEFAULT,\
0112     .version=0\
0113 }
0114 
0115 /*---------------------------Enums--------------------------------------*/
0116 /*---------------------------Typedefs-----------------------------------*/
0117 
0118 /**
0119  * Holds the regex match strings
0120  */
0121 typedef struct
0122 {
0123     char *binname;  /**< logical binary name, hashed by */
0124     char *dbgstr;  /**< configuration string           */
0125     EX_hash_handle hh; /**< hash handle                 */
0126 
0127 } ndrx_debug_rebins_t;
0128 
0129 /*---------------------------Globals------------------------------------*/
0130 ndrx_debug_t G_ubf_debug = DEBUG_INITIALIZER(LOG_CODE_UBF, "UBF ", (LOG_FACILITY_UBF|LOG_FACILITY_PROCESS));
0131 ndrx_debug_t G_ndrx_debug = DEBUG_INITIALIZER(LOG_CODE_NDRX, "NDRX", (LOG_FACILITY_NDRX|LOG_FACILITY_PROCESS));
0132 ndrx_debug_t G_tp_debug = DEBUG_INITIALIZER(LOG_CODE_TP, "USER", (LOG_FACILITY_TP|LOG_FACILITY_PROCESS));
0133 
0134 ndrx_debug_t G_stdout_debug;
0135 /*---------------------------Statics------------------------------------*/
0136 volatile int G_ndrx_debug_first = EXTRUE;
0137 volatile unsigned M_thread_nr = 0;
0138 exprivate int __thread M_is_initlock_owner = 0; /* for recursive logging calls */
0139 exprivate MUTEX_LOCKDECL(M_dbglock);
0140 exprivate MUTEX_LOCKDECL(M_thread_nr_lock);
0141 exprivate MUTEX_LOCKDECL(M_memlog_lock);
0142 
0143 
0144 exprivate ndrx_debug_rebins_t *M_rebins = NULL; /**< regular expression based bins */
0145 /*---------------------------Prototypes---------------------------------*/
0146 
0147 /**
0148  * Standard banner if configuration have failed
0149  */
0150 expublic void ndrx_init_fail_banner(void)
0151 {
0152     
0153     fprintf(stderr, "********************************************************************************\n");
0154     fprintf(stderr, "**                         CONFIGURATION ERROR !                              **\n");
0155     fprintf(stderr, "**                         ... now worry                                      **\n");
0156     fprintf(stderr, "**                                                                            **\n");
0157     fprintf(stderr, "** Enduro/X Application server is not in proper environment or not configured **\n");
0158     fprintf(stderr, "**                                                                            **\n");
0159     fprintf(stderr, "** Possible causes:                                                           **\n");
0160     fprintf(stderr, "** - Classical environment variables are not loaded (see ex_env(5) man page)  **\n");
0161     fprintf(stderr, "** - Or Common-Config NDRX_CCONFIG env variable is not set                    **\n");
0162     fprintf(stderr, "** See \"Getting Started Tutorial\" in order to get system up-and-running       **\n");
0163     fprintf(stderr, "** More info can be found here http://www.endurox.org/dokuwiki                **\n");
0164     fprintf(stderr, "**                                                                            **\n");
0165     fprintf(stderr, "** Process is now terminating with failure                                    **\n");
0166     fprintf(stderr, "********************************************************************************\n");
0167     exit(EXFAIL);
0168 }
0169 
0170 /**
0171  * Reply the cached log to the real/initilaized logger
0172  * @param dbg logger (after init)
0173  */
0174 exprivate void ndrx_dbg_reply_memlog(ndrx_debug_t *dbg)
0175 {
0176     ndrx_memlogger_t *line, *tmp;
0177     
0178     /* This shall be done by one thread only...
0179      * Thus we need a lock.
0180      */
0181     DL_FOREACH_SAFE(dbg->memlog, line, tmp)
0182     {
0183         /* Bug #321 */
0184         if (line->level <= dbg->level)
0185         {
0186             BUFFERED_PRINT_LINE(dbg, line->line)
0187         }
0188         
0189         DL_DELETE(dbg->memlog, line);
0190         NDRX_FREE(line);
0191     }
0192 }
0193 
0194 /**
0195  * Reply all logs..
0196  */
0197 expublic void ndrx_dbg_reply_memlog_all(void)
0198 {
0199     /* Check that logs are initialized (in case of call from 
0200      * other bootstrap sources, with out call  */
0201     NDRX_DBG_INIT_ENTRY;
0202     MUTEX_LOCK_V(M_memlog_lock);
0203 
0204     if (NULL!=G_ubf_debug.memlog)
0205     {
0206         ndrx_dbg_reply_memlog(&G_ubf_debug);
0207     }
0208 
0209     if (NULL!=G_ndrx_debug.memlog)
0210     {
0211         ndrx_dbg_reply_memlog(&G_ndrx_debug);
0212     }
0213 
0214     if (NULL!=G_tp_debug.memlog)
0215     {
0216         ndrx_dbg_reply_memlog(&G_tp_debug);
0217     }
0218     MUTEX_UNLOCK_V(M_memlog_lock);
0219 }
0220 
0221 /**
0222  * Function returns true if current thread init lock owner
0223  * @return TRUE (we are performing init) / FALSE (we are not performing init)
0224  */
0225 expublic int ndrx_dbg_intlock_isset(void)
0226 {
0227     return M_is_initlock_owner;
0228 }
0229 
0230 /**
0231  * Sets init lock to us
0232  */
0233 expublic void ndrx_dbg_intlock_set(void)
0234 {   
0235     M_is_initlock_owner++;
0236 }
0237 
0238 /**
0239  * Unset (decrement) lock & reply logs if we are at the end.
0240  * @param do_reply reply logs if becoming 0 owner
0241  */
0242 expublic void ndrx_dbg_intlock_unset(int *do_reply)
0243 {   
0244     M_is_initlock_owner--;
0245     
0246     if (M_is_initlock_owner < 0)
0247     {
0248         M_is_initlock_owner = 0;
0249     }
0250     
0251     /*
0252      * Reply memory based logs to the file.
0253      * mem debugs are filled only if we are doing the init
0254      * and the init was doing some debug (while the debug it self was not
0255      * initialized).
0256      */
0257     if (0==M_is_initlock_owner)
0258     {  
0259         *do_reply=EXTRUE;
0260     }
0261 }
0262 
0263 /**
0264  * Initialize operating thread number.
0265  * note default is zero.
0266  */
0267 expublic void ndrx_dbg_setthread(long threadnr)
0268 {
0269     NSTD_TLS_ENTRY;
0270     G_nstd_tls->M_threadnr = threadnr;
0271 }
0272 
0273 /**
0274  * Lock the debug output
0275  */
0276 expublic void ndrx_dbg_lock(void)
0277 {
0278     MUTEX_LOCK_V(M_dbglock);
0279 }
0280 
0281 /**
0282  * Unlock the debug output
0283  */
0284 expublic void ndrx_dbg_unlock(void)
0285 {
0286     MUTEX_UNLOCK_V(M_dbglock);
0287 }
0288 
0289 /**
0290  * Update logger pids
0291  */
0292 expublic void ndrx_dbg_pid_update(void)
0293 {
0294     G_tp_debug.pid = G_ubf_debug.pid = G_ndrx_debug.pid = G_stdout_debug.pid = getpid();
0295 }
0296 
0297 /**
0298  * Return the logger according to current thread settings.
0299  * Note the internals should no call the logging. as this will cause recursive loop...
0300  * @param dbg_ptr
0301  * @return 
0302  */
0303 exprivate ndrx_debug_t * get_debug_ptr(ndrx_debug_t *dbg_ptr)
0304 {
0305     static __thread int recursive = EXFALSE;
0306     long flags = 0;
0307     char new_file[PATH_MAX];
0308     /* If tls is enabled and we run threaded modes */
0309     if (NULL!=G_nstd_tls && !recursive)
0310     {
0311         if ( (LOG_THREADED_TEMPL & dbg_ptr->is_threaded) &&
0312                 (( 
0313                   ((dbg_ptr->flags & LOG_FACILITY_NDRX)
0314                         /* assign target logger */
0315                         && (flags = LOG_FACILITY_NDRX_THREAD)
0316                         && NULL==G_nstd_tls->threadlog_ndrx.dbg_f_ptr ) ||
0317                   ((dbg_ptr->flags & LOG_FACILITY_UBF) 
0318                         /* assign target logger */
0319                         && (flags = LOG_FACILITY_UBF_THREAD)
0320                         && NULL==G_nstd_tls->threadlog_ubf.dbg_f_ptr) ||
0321                   ((dbg_ptr->flags & LOG_FACILITY_TP)
0322                          /* assign target logger */
0323                         && (flags = LOG_FACILITY_TP_THREAD)
0324                         && NULL==G_nstd_tls->threadlog_tp.dbg_f_ptr )
0325                 ) || (G_nstd_tls->M_threadnr_logopen != G_nstd_tls->M_threadnr)
0326                 )
0327             )
0328         {
0329             /* format new line... */
0330             snprintf(new_file, sizeof(new_file), dbg_ptr->filename_th_template, 
0331                     (unsigned)G_nstd_tls->M_threadnr);
0332             
0333             /* configure the thread based logger.. */
0334             G_nstd_tls->M_threadnr_logopen = G_nstd_tls->M_threadnr;
0335             
0336             recursive = EXTRUE; /* forbid recursive function call.. when doing some logging... */
0337             
0338             if (EXFAIL==tplogconfig(flags, 
0339                     dbg_ptr->level, NULL, dbg_ptr->module, new_file))
0340             {
0341                 userlog("Failed to configure thread based logger for thread %d file %s: %s",
0342                         G_nstd_tls->M_threadnr, new_file, Nstrerror(Nerror));
0343             }
0344             
0345             recursive = EXFALSE; /* forbid recursive function call.. when doing some logging... */
0346             
0347         }
0348 
0349 /** In case if new levels are published by LCF
0350  * use them by correspoding loggers
0351  */
0352 #define SYNC_LEVELS(X, Y) if (X.version!=Y.version)\
0353                 {\
0354                     X.version = Y.version;\
0355                     X.level = Y.level;\
0356                 }
0357         
0358         if (NULL!=G_nstd_tls && !recursive)
0359         {
0360             if (dbg_ptr == &G_tp_debug && NULL!=G_nstd_tls->requestlog_tp.dbg_f_ptr)
0361             {
0362                 SYNC_LEVELS(G_nstd_tls->requestlog_tp, G_tp_debug);
0363                 return &G_nstd_tls->requestlog_tp;
0364             }
0365             else if (dbg_ptr == &G_tp_debug && NULL!=G_nstd_tls->threadlog_tp.dbg_f_ptr)
0366             {
0367                 SYNC_LEVELS(G_nstd_tls->threadlog_tp, G_tp_debug);
0368                 return &G_nstd_tls->threadlog_tp;
0369             }
0370             else if (dbg_ptr == &G_ndrx_debug && NULL!=G_nstd_tls->requestlog_ndrx.dbg_f_ptr)
0371             {
0372                 SYNC_LEVELS(G_nstd_tls->requestlog_ndrx, G_ndrx_debug);
0373                 return &G_nstd_tls->requestlog_ndrx;
0374             }
0375             else if (dbg_ptr == &G_ndrx_debug && NULL!=G_nstd_tls->threadlog_ndrx.dbg_f_ptr)
0376             {
0377                 SYNC_LEVELS(G_nstd_tls->threadlog_ndrx, G_ndrx_debug);
0378                 return &G_nstd_tls->threadlog_ndrx;
0379             }
0380             else if (dbg_ptr == &G_ubf_debug && NULL!=G_nstd_tls->requestlog_ubf.dbg_f_ptr)
0381             {
0382                 SYNC_LEVELS(G_nstd_tls->requestlog_ubf, G_ubf_debug);
0383                 return &G_nstd_tls->requestlog_ubf;
0384             }
0385             else if (dbg_ptr == &G_ubf_debug && NULL!=G_nstd_tls->threadlog_ubf.dbg_f_ptr)
0386             {
0387                 SYNC_LEVELS(G_nstd_tls->threadlog_ubf, G_ubf_debug);
0388                 return &G_nstd_tls->threadlog_ubf;
0389             }
0390         }
0391     }
0392     
0393     return dbg_ptr;
0394 }
0395 
0396 /**
0397  * Parse & load binlist of rebins
0398  * @param binlist value of rebins keyword
0399  * @return EXSUCCEED/EXFAIL
0400  */
0401 exprivate int ndrx_dbg_rebins_load(char *binlist)
0402 {
0403     int ret = EXSUCCEED;
0404     ndrx_stdcfgstr_t* parsed2=NULL, *el2;
0405     
0406     /* initial load of regex bins 
0407      * Firstly parse the value
0408      */
0409     if (EXSUCCEED!=ndrx_stdcfgstr_parse(binlist, &parsed2))
0410     {
0411         userlog("Failed to parse rebins [%s]", binlist);
0412         EXFAIL_OUT(ret);
0413     }
0414 
0415     DL_FOREACH(parsed2, el2)
0416     {
0417         ndrx_debug_rebins_t *tmp=NULL;
0418 
0419         /* check that key is not already hashed... 
0420          * ignore if found already...
0421          */
0422         EXHASH_FIND_STR(M_rebins, el2->key, tmp);
0423         if (NULL==tmp)
0424         {
0425             ndrx_debug_rebins_t *tmp = NDRX_FPMALLOC(sizeof(ndrx_debug_rebins_t), 0);
0426             
0427             if (NULL==tmp)
0428             {
0429                 userlog("Failed to malloc ndrx_debug_rebins_t: %s", strerror(errno));
0430                 EXFAIL_OUT(ret);
0431             }
0432                 
0433             memset(tmp, 0, sizeof(*tmp));
0434 
0435             if (NULL==(tmp->binname = NDRX_STRDUP(el2->key)))
0436             {
0437                 userlog("Failed to malloc binname for rebins: %s", strerror(errno));
0438                 EXFAIL_OUT(ret);
0439             }
0440 
0441             /* hash the key.. */
0442             EXHASH_ADD_KEYPTR(hh, M_rebins, tmp->binname, 
0443                     strlen(tmp->binname), tmp);
0444         }
0445     }
0446 out:
0447     
0448     if (NULL!=parsed2)
0449     {
0450         ndrx_stdcfgstr_free(parsed2);
0451     }
0452 
0453     return ret;
0454 }
0455 
0456 
0457 /**
0458  * Check name & add to rebins if required
0459  * Used for ndrxdebug.conf file handling
0460  * @param name name of the binary
0461  * @param dbgstr debug string to load if matched
0462  * @return EXSUCCEED/EXFAIL
0463  */
0464 exprivate int ndrx_dbg_rebins_chkaddcfg(char *name, char *dbgstr)
0465 {
0466     int ret = EXSUCCEED;
0467     ndrx_debug_rebins_t *re_tmp=NULL;
0468     
0469     /* check that key is not already hashed... 
0470     * ignore if found already...
0471     */
0472     EXHASH_FIND_STR(M_rebins, name, re_tmp);
0473 
0474     if (NULL!=re_tmp)
0475     {
0476        /* copy the debug line */
0477        re_tmp->dbgstr = NDRX_STRDUP(dbgstr);
0478 
0479        if (NULL==re_tmp->dbgstr)
0480        {
0481            userlog("Failed to strdup: %s", strerror(errno));
0482            EXFAIL_OUT(ret);
0483        }
0484     }
0485     
0486 out:
0487     return ret;
0488 }
0489 
0490 /**
0491  * scan the hashmap and resolve debug strings.
0492  * @param conf CCconfig section to lookup for rebins
0493  * @return EXSUCCEED/EXFAIL
0494  */
0495 exprivate int ndrx_dbg_rebins_scancfg(ndrx_inicfg_section_keyval_t *conf)
0496 {
0497     int ret = EXSUCCEED;
0498     ndrx_inicfg_section_keyval_t *cc;
0499     ndrx_debug_rebins_t *el, *elt;
0500     
0501     EXHASH_ITER(hh, M_rebins, el, elt)
0502     {
0503         if (NULL!=(cc=ndrx_keyval_hash_get(conf, el->binname)))
0504         {
0505             el->dbgstr = NDRX_STRDUP(cc->val);
0506 
0507             if (NULL==el->dbgstr)
0508             {
0509                 userlog("Failed to strdup: %s", strerror(errno));
0510                 EXFAIL_OUT(ret);
0511             }
0512         }
0513     }
0514     
0515 out:
0516     return ret;
0517 }
0518 
0519 /**
0520  * Apply regexp match...
0521  * @param name our binary name to match on...
0522  * @param tmpfname output filename
0523  * @param tmpfnamesz filename size
0524  * @return EXTRUE (if applied), EXFALSE (not applied)
0525  */
0526 exprivate int ndrx_dbg_rebins_apply(char *name, char *tmpfname, size_t tmpfnamesz)
0527 {
0528     ndrx_debug_rebins_t *el, *elt;
0529     
0530     EXHASH_ITER(hh, M_rebins, el, elt)
0531     {
0532         int do_match;
0533         
0534         /* might be null as user may add stuff to rebins, but not declare the line */
0535         if (NULL!=el->dbgstr && EXSUCCEED==ndrx_init_parse_line(el->dbgstr, NULL,  
0536                 tmpfname, tmpfnamesz, &do_match, name))
0537         {
0538             if (EXTRUE==do_match)
0539             {
0540                 return EXTRUE;
0541             }
0542         }
0543     }
0544     
0545     return EXFALSE;
0546 }
0547 
0548 /**
0549  * Free up the rebins list
0550  */
0551 exprivate void ndrx_dbg_rebins_free(void)
0552 {
0553     ndrx_debug_rebins_t *el, *elt;
0554     
0555     EXHASH_ITER(hh, M_rebins, el, elt)
0556     {
0557         EXHASH_DEL(M_rebins, el);
0558         
0559         if (NULL!=el->binname)
0560         {
0561             NDRX_FREE(el->binname);
0562         }
0563         
0564         if (NULL!=el->dbgstr)
0565         {
0566             NDRX_FREE(el->dbgstr);
0567         }
0568         
0569         NDRX_FPFREE(el);
0570     }
0571 }
0572 
0573 
0574 /**
0575  * Parser sharing the functionality with common config & old style debug.conf
0576  * User update mode: tok1 == NULL, tok2 config string
0577  * CConfig mode: tok1 != NULL, tok2 != NULL
0578  * ndrxdebug.conf mode: tok1 !=NULL tok2 == NULL
0579  * @param dbgstr (config string for CConfig or update mode)
0580  * @param tmpfname file name if not using dbg_ptr
0581  * @param tmpfnamesz buffer size for file
0582  * @param upd_mode not config parse mode.
0583  * @param do_match process regexp match (if NULL, no regex matching required)
0584  * @param match_nm match name
0585  * @return EXSUCCEED/EXFAIL
0586  */
0587 expublic int ndrx_init_parse_line(const char *dbgstr, ndrx_debug_t *dbg_ptr, 
0588         char *tmpfname, size_t tmpfnamesz, int *do_match, char *match_nm)
0589 {
0590     int ret = EXSUCCEED;
0591     /* have a own copies of params as we do the token over them... */
0592     ndrx_stdcfgstr_t* parsed=NULL, *el;    
0593     ndrx_debug_t *tmp_ptr;
0594 
0595     /* parse standard configuration string */
0596     if (EXSUCCEED!=ndrx_stdcfgstr_parse(dbgstr, &parsed))
0597     {
0598         userlog("Failed to parse debug string [%s]", dbgstr);
0599         EXFAIL_OUT(ret);
0600     }
0601     
0602     if (NULL!=do_match)
0603     {
0604         *do_match=EXFALSE;
0605         /* scan the list & do match if found "match" keyword */
0606         
0607         DL_FOREACH(parsed, el)
0608         {
0609             if (0==strcmp(el->key, "match"))
0610             {
0611                 if (NULL==el->value)
0612                 {
0613                     userlog("Invalid debug string [%s] missing value for key [%s]", 
0614                             dbgstr, el->key);
0615                 }
0616                 else if (EXSUCCEED==ndrx_regqexec(el->value, match_nm))
0617                 {
0618                     /* check regex match */
0619                     *do_match=EXTRUE;
0620                     break;
0621                 }
0622                 /* invalid str or no match.. */
0623                 goto out;
0624             }
0625         }
0626     } /* regexp match used. */
0627 
0628     DL_FOREACH(parsed, el)
0629     {
0630         if (NULL==el->value)
0631         {
0632             userlog("Invalid debug string [%s] missing value for key [%s]", 
0633                     dbgstr, el->key);
0634         }
0635         else if (0==strcmp("ndrx", el->key))
0636         {
0637             int lev = atoi(el->value);
0638 
0639             if (NULL!=dbg_ptr)
0640             {
0641                 if ( (dbg_ptr->flags & LOG_FACILITY_NDRX) ||
0642                         (dbg_ptr->flags & LOG_FACILITY_NDRX_THREAD) ||
0643                         (dbg_ptr->flags & LOG_FACILITY_NDRX_REQUEST) )
0644                 {
0645                     dbg_ptr->level = lev;
0646                 }
0647             }
0648             else
0649             {
0650                 G_ndrx_debug.level = lev;
0651             }
0652         }
0653         else if (0==strcmp("ubf", el->key))
0654         {
0655             int lev = atoi(el->value);
0656 
0657             if (NULL!=dbg_ptr)
0658             {
0659                 if ( (dbg_ptr->flags & LOG_FACILITY_UBF) ||
0660                         (dbg_ptr->flags & LOG_FACILITY_UBF_THREAD) ||
0661                         (dbg_ptr->flags & LOG_FACILITY_UBF_REQUEST) )
0662                 {
0663                     dbg_ptr->level = lev;
0664                 }
0665             }
0666             else
0667             {
0668                 G_ubf_debug.level = lev;
0669             }
0670 
0671         }
0672         else if (0==strcmp("tp", el->key))
0673         {
0674             int lev = atoi(el->value);
0675 
0676             if (NULL!=dbg_ptr)
0677             {
0678                 if ( (dbg_ptr->flags & LOG_FACILITY_TP) ||
0679                         (dbg_ptr->flags & LOG_FACILITY_TP_THREAD) ||
0680                         (dbg_ptr->flags & LOG_FACILITY_TP_REQUEST) )
0681                 {
0682                     dbg_ptr->level = lev;
0683                 }
0684             }
0685             else
0686             {
0687                 G_tp_debug.level = lev;
0688             }
0689         }
0690         else if (0==strcmp("iflags", el->key))
0691         {
0692             /* Setup integration flags */
0693 
0694             /* Feature #312 apply to all facilities, as during integration
0695              * these might be used too */
0696             NDRX_STRCPY_SAFE(G_ndrx_debug.iflags, el->value);
0697             NDRX_STRCPY_SAFE(G_ubf_debug.iflags, el->value);
0698             NDRX_STRCPY_SAFE(G_tp_debug.iflags, el->value);
0699         }
0700         else if (0==strcmp("lines", el->key))
0701         {
0702             int lines = atoi(el->value);
0703 
0704             if (lines < 0)
0705             {
0706                 lines = 0;
0707             }
0708 
0709             if (NULL!=dbg_ptr)
0710             {
0711                 dbg_ptr->buf_lines = lines;
0712             }
0713             else
0714             {
0715                 G_tp_debug.buf_lines = 
0716                         G_ndrx_debug.buf_lines = 
0717                         G_ubf_debug.buf_lines = lines;
0718             }
0719         }
0720         else if (0==strcmp("bufsz", el->key))
0721         {
0722             int bufsz = atoi(el->value);
0723 
0724             if (bufsz<=0)
0725             {
0726                 bufsz = DEFAULT_BUFFER_SIZE;
0727             }
0728 
0729             if (NULL!=dbg_ptr)
0730             {
0731                 dbg_ptr->buffer_size = bufsz;
0732             }
0733             else
0734             {
0735                 G_tp_debug.buffer_size = 
0736                         G_ndrx_debug.buffer_size = 
0737                         G_ubf_debug.buffer_size = bufsz;
0738             }
0739         }
0740         else if (0==strcmp("file", el->key))
0741         {
0742             NDRX_STRCPY_SAFE_DST(tmpfname, el->value, tmpfnamesz);
0743         } /* Feature #167 */
0744         else if (0==strcmp("threaded", el->key))
0745         {
0746             int val = 0;
0747 
0748             if (el->value[0] == 'Y' || el->value[0] == 'y')
0749             {
0750                 val = LOG_THREADED_TEMPL;
0751             }
0752             else if (el->value[0] == 'L' || el->value[0] == 'l')
0753             {
0754                 val = LOG_THREADED_LINEL;
0755             }
0756 
0757             if (NULL!=dbg_ptr)
0758             {
0759                 dbg_ptr->is_threaded = val;
0760             }
0761             else
0762             {
0763                 G_tp_debug.is_threaded = val;
0764                 G_ubf_debug.is_threaded = val;
0765                 G_ndrx_debug.is_threaded = val;
0766             }
0767         }
0768         else if (0==strcmp("mkdir", el->key))
0769         {
0770             int val = EXFALSE;
0771 
0772             if (el->value[0] == 'Y' || el->value[0] == 'y')
0773             {
0774                 val = EXTRUE;
0775             }
0776 
0777             if (NULL!=dbg_ptr)
0778             {
0779                 dbg_ptr->is_mkdir = val;
0780             }
0781             else
0782             {
0783                 G_tp_debug.is_mkdir = val;
0784                 G_ubf_debug.is_mkdir = val;
0785                 G_ndrx_debug.is_mkdir = val;
0786             }
0787         }
0788         else if (0==strcmp("rebins", el->key))
0789         {
0790             if (EXSUCCEED!=ndrx_dbg_rebins_load(el->value))
0791             {
0792                 EXFAIL_OUT(ret);
0793             }
0794         } /* rebins */
0795     } /* for each conf string keyword */
0796 
0797     ndrx_str_env_subs_len(tmpfname, tmpfnamesz);
0798     
0799     if (NULL!=dbg_ptr)
0800     {
0801         tmp_ptr = dbg_ptr;
0802     }
0803     else
0804     {
0805         tmp_ptr = &G_ndrx_debug;
0806     }
0807 
0808     /* Configure template for threads...
0809      * Feature #167
0810      */
0811     if ((tmp_ptr->is_threaded & LOG_THREADED_TEMPL) && EXEOS!=tmpfname[0])
0812     {
0813         int len;
0814         int len2;
0815         char *p;
0816         
0817         len2 = 3; /* len of .%u */
0818         
0819         /* 
0820          * Escape any %
0821          */
0822         if (strchr(tmpfname, '%'))
0823         {
0824             /*
0825              * escape any %, if buffer len is reached, the trailing % shall be
0826              * stripped... as 1x there could be left and then processed by
0827              * printf engine.
0828              */
0829             ndrx_str_fmtesc(tmp_ptr->filename_th_template,
0830                     sizeof(tmp_ptr->filename_th_template), tmpfname);
0831         }
0832         else
0833         {
0834             NDRX_STRCPY_SAFE(tmp_ptr->filename_th_template, tmpfname);
0835         }
0836         
0837         len = strlen(tmp_ptr->filename_th_template);
0838         
0839         /* needs space for EOS! If not space left, just use without the numbering. */
0840         if (len+len2+1 <= tmpfnamesz)
0841         {
0842             /* Thread based logfile name... */
0843             if (NULL!=(p = strrchr(tmp_ptr->filename_th_template, '.')))
0844             {
0845                 /* insert the" .%u", move other part to the back..*/
0846         /* + include EOS... */
0847                 memmove(p+len2, p, strlen(p)+1);
0848                 NDRX_STRNCPY(p, ".%u", len2);
0849             }
0850             else
0851             {
0852                 /* add the .%d */
0853                 NDRX_STRCAT_S(tmp_ptr->filename_th_template, 
0854                         sizeof(tmp_ptr->filename_th_template), ".%u");
0855             }
0856             
0857             /* set template to standard loggers */
0858             if (NULL==dbg_ptr)
0859             {
0860                 NDRX_STRCPY_SAFE(G_ubf_debug.filename_th_template, 
0861                         G_ndrx_debug.filename_th_template);
0862                 
0863                 NDRX_STRCPY_SAFE(G_tp_debug.filename_th_template, 
0864                         G_ndrx_debug.filename_th_template);
0865             }
0866         }
0867     }
0868 
0869 out:
0870     if (NULL!=parsed)
0871     {
0872         ndrx_stdcfgstr_free(parsed);
0873     }
0874     
0875     return ret;
0876 }
0877 
0878 /**
0879  * Open file for debug, if enabled mkdir and we get NOENT error,
0880  * try to recursively create the directory
0881  * @param[in] filename debug file name
0882  * @param[in] mode mode string for fopen
0883  * @param[in,out] dbg_ptr debug pointer which opens the file, optional
0884  * @param[in,out] fsink file sink to use if dbg_ptr is not available.
0885  * @return ptr to FILE or NULL and errno set
0886  */
0887 expublic FILE *ndrx_dbg_fopen_mkdir(const char *filename, const char *mode,
0888         ndrx_debug_t *dbg_ptr, ndrx_debug_file_sink_t *fsink)
0889 {
0890     FILE *ret = NULL;
0891     int got_dir = EXFALSE;
0892     int fallbacks = 0;
0893     
0894     int is_mkdir;
0895     int buffer_size;
0896     
0897     ret = NDRX_FOPEN(filename, mode);
0898     
0899     /* if have recursive setting, then continue  */
0900     
0901     if (NULL!=dbg_ptr)
0902     {
0903         is_mkdir = dbg_ptr->is_mkdir;
0904         buffer_size = dbg_ptr->buffer_size;
0905     }
0906     else
0907     {
0908         is_mkdir = fsink->org_is_mkdir;
0909         buffer_size = fsink->org_buffer_size;
0910     }
0911     
0912     if (!is_mkdir)
0913     {
0914         goto out;
0915     }
0916     
0917     /* do some recursive mkdir... */
0918     if (NULL==ret && errno==ENOENT)
0919     {
0920         /* loop over the path and try to make it... */
0921         char tmp[PATH_MAX+1];
0922         char *p;
0923         
0924         NDRX_STRCPY_SAFE(tmp, filename);
0925         
0926         /*
0927          * Try to create folder in reverse order from longest path to shortest
0928          */
0929         while (NULL!=(p=strrchr(tmp, '/')))
0930         {
0931             *p = EXEOS;
0932             
0933             /* try to create folder */
0934             if (EXSUCCEED!=mkdir(tmp, NDRX_DIR_PERM))
0935             {
0936                 if (ENOENT!=errno)
0937                 {
0938                     break;
0939                 }
0940             }
0941             else
0942             {
0943                 got_dir = EXTRUE;
0944                 break;
0945             }
0946             
0947             fallbacks++;
0948         }
0949         
0950         if (!got_dir)
0951         {
0952             goto out;
0953         }
0954         
0955         /*
0956          * Now if we fall back more that one folder, we need to create the
0957          * upper ones.
0958          */
0959         while (fallbacks > 0)
0960         {
0961             tmp[strlen(tmp)]='/';
0962             
0963             if (EXSUCCEED!=mkdir(tmp, NDRX_DIR_PERM))
0964             {
0965                 /* the next will fail fore sure */
0966                 goto out;
0967             }
0968             
0969             fallbacks--;
0970         }
0971         
0972         ret = NDRX_FOPEN(filename, "a");
0973     }
0974     
0975 out:
0976     
0977     if (NULL!=ret)
0978     {
0979         /* close descriptors of fork: Bug #176 */
0980         if (EXSUCCEED!=fcntl(fileno(ret), F_SETFD, FD_CLOEXEC))
0981         {
0982             userlog("WARNING: Failed to set FD_CLOEXEC: %s", strerror(errno));
0983         }
0984         /* just use process level ndrx buffer size 
0985          * as files are shared between loggers
0986          */
0987         setvbuf(ret, NULL, _IOFBF, buffer_size);
0988         
0989         /* copy off the settings */
0990         if (NULL!=dbg_ptr && NULL!=fsink)
0991         {
0992             fsink->org_is_mkdir = dbg_ptr->is_mkdir;
0993             fsink->org_buffer_size = dbg_ptr->buffer_size;
0994         }        
0995     }
0996 
0997     return ret;
0998 }
0999 
1000 /**
1001  * This initializes debug out form ndebug.conf
1002  * NOTE This also loads the common configuration at standard library level 
1003  * 
1004  */
1005 expublic void ndrx_init_debug(void)
1006 {
1007     char *cfg_file = getenv(CONF_NDRX_DEBUG_CONF);
1008     char *inline_setting = getenv(CONF_NDRX_DEBUG_STR);
1009     FILE *f;
1010     ndrx_inicfg_section_keyval_t *conf = NULL, *cc;
1011     ndrx_inicfg_t *cconfig = NULL;
1012     char hostname[PATH_MAX];
1013     char buf[PATH_MAX*2];
1014     char *tmp;
1015     char tmpname[PATH_MAX+1]={EXEOS};
1016     int lcf_status=EXFAIL;
1017     int do_reply=EXFALSE;
1018     int did_match = EXFALSE; /**< do we have exact binary name match? */
1019     char *svname = getenv(CONF_NDRX_SVPROCNAME);
1020     
1021     ndrx_dbg_intlock_set();
1022     
1023     /*
1024      * init in declaration...
1025     memset(&G_ubf_debug, 0, sizeof(G_ubf_debug));
1026     memset(&G_ndrx_debug, 0, sizeof(G_ndrx_debug));
1027     memset(&G_stdout_debug, 0, sizeof(G_stdout_debug));
1028     */
1029     
1030     ndrx_dbg_pid_update();
1031     
1032     ndrx_sys_get_hostname(hostname, sizeof(hostname));
1033     
1034     /* copy number of chars specified in hostname if debug config */
1035     
1036     G_tp_debug.hostnamecrc32 = G_ubf_debug.hostnamecrc32 = 
1037                 G_ndrx_debug.hostnamecrc32 = G_stdout_debug.hostnamecrc32 = 
1038                 ndrx_Crc32_ComputeBuf(0, hostname, strlen(hostname));
1039     
1040     cconfig = ndrx_get_G_cconfig();
1041     
1042     /* Initialize with defaults.. 
1043      * Set to NULL.
1044      */
1045     G_ndrx_debug.dbg_f_ptr = NULL;
1046     G_ubf_debug.dbg_f_ptr = NULL;
1047     G_tp_debug.dbg_f_ptr = NULL;
1048     G_stdout_debug.dbg_f_ptr = NULL;
1049     
1050     G_ndrx_debug.version = 0;
1051     G_ubf_debug.version = 0;
1052     G_tp_debug.version = 0;
1053     G_stdout_debug.version = 0;
1054     
1055     /* For system V please using line locking by default
1056      * as admin/tout threads will render logs unreadable
1057      * also tmqueue/tmsrv/tpbridge shall be configured set
1058      * to use line logging too by default
1059      */
1060 #ifdef EX_USE_SYSVQ
1061     G_ndrx_debug.is_threaded = LOG_THREADED_LINEL;
1062     G_ubf_debug.is_threaded = LOG_THREADED_LINEL;
1063     G_tp_debug.is_threaded = LOG_THREADED_LINEL;
1064     G_stdout_debug.is_threaded = LOG_THREADED_LINEL;
1065 #endif
1066     
1067     /* static coinf */
1068     G_stdout_debug.buf_lines = 1;
1069     G_stdout_debug.buffer_size = 1;
1070     G_stdout_debug.level = log_debug;
1071     
1072     /* default bufsz  */
1073     G_tp_debug.buffer_size = G_ubf_debug.buffer_size = G_ndrx_debug.buffer_size = 50000;
1074 
1075     G_tp_debug.buf_lines = G_ubf_debug.buf_lines = G_ndrx_debug.buf_lines = 1;
1076     G_ubf_debug.level = G_ndrx_debug.level = log_error;
1077     /* leave user logging as is */
1078     G_tp_debug.level = log_debug;
1079 
1080     if (NULL==cconfig)
1081     {
1082         if (NULL!=inline_setting)
1083         {
1084             ndrx_init_parse_line(inline_setting, NULL, tmpname, sizeof(tmpname),
1085                     NULL, NULL);
1086         }
1087         else if (NULL!=cfg_file && EXEOS==cfg_file[0])
1088         {
1089             /* allow zero config -> no debug intially. */
1090             G_tp_debug.level = G_ubf_debug.level = G_ndrx_debug.level = log_error;
1091         }
1092         else if (NULL!=cfg_file &&
1093                 NULL!=(f=fopen(cfg_file, "r")))
1094         {
1095 
1096             /* process line by line */
1097             while (NULL!=fgets(buf, sizeof(buf), f))
1098             {
1099                 int offs;
1100                 
1101                 if ('#'==buf[0] || '\n'==buf[0])
1102                 {
1103                     /* skip comments */
1104                     continue;
1105                 }
1106                 if (buf[strlen(buf)-1]=='\n')
1107                 {
1108                     buf[strlen(buf)-1]=EXEOS;
1109                 }
1110                 
1111                 offs = strcspn(buf, "\t ");
1112                 
1113                 /* if string is valid... (have separator) */
1114                 if (offs > 0)
1115                 {
1116                     *(buf + offs)=EXEOS;
1117                     
1118                     if (0==strcmp(buf, (char *)EX_PROGNAME) || 
1119                             NULL!=svname && 0==strcmp(buf, svname) ||
1120                             0==strcmp(buf, "*"))
1121                     {
1122                         ndrx_init_parse_line((buf+offs+1), NULL, 
1123                                 tmpname, sizeof(tmpname),
1124                                 NULL, NULL);
1125                         
1126                         /* got exact match... */
1127                         if (0!=strcmp(buf, "*"))
1128                         {
1129                             did_match=EXTRUE;
1130                             break;
1131                         }
1132                     }
1133                 
1134                     /* if regexp, copy the debug string... */
1135                     if (M_rebins)
1136                     {
1137                         ndrx_dbg_rebins_chkaddcfg(buf, (buf+offs+1));
1138                     }
1139                 }
1140                 
1141             }
1142 
1143             fclose(f);
1144         }
1145         else if (NULL==f && NULL!=cfg_file)
1146         {
1147             fprintf(stderr, "Failed to to open [%s]: %d/%s\n", cfg_file,
1148                                 errno, strerror(errno));
1149         }
1150     }
1151     else
1152     {
1153         /* CCONFIG in use, get the section */
1154         ndrx_cconfig_load(); /* load the global section... */
1155         if (EXSUCCEED==ndrx_cconfig_get(NDRX_CONF_SECTION_DEBUG, &conf))
1156         {
1157             
1158             /* Load the env variable */
1159             if (NULL!=inline_setting)
1160             {
1161                 ndrx_init_parse_line(inline_setting, NULL, tmpname, sizeof(tmpname),
1162                         NULL, NULL);
1163             }
1164             /* 1. get he line by common & process */
1165             else 
1166             {
1167                 
1168                 if (NULL!=(cc=ndrx_keyval_hash_get(conf, "*")))
1169                 {
1170                     ndrx_init_parse_line(cc->val, NULL, tmpname, sizeof(tmpname),
1171                             NULL, NULL);
1172                 }
1173             
1174                 /* 2. get the line by binary name 
1175                  * - For servers lookup by logical server name.
1176                  * - For clients only program name
1177                  */
1178                 if (
1179                     NULL!=svname && NULL!=(cc=ndrx_keyval_hash_get(conf, (char *)svname)) 
1180                     ||
1181                     NULL!=(cc=ndrx_keyval_hash_get(conf, (char *)EX_PROGNAME)) 
1182                     )
1183                 {
1184                     ndrx_init_parse_line(cc->val, NULL, tmpname, sizeof(tmpname),
1185                             NULL, NULL);
1186                     
1187                     did_match=EXTRUE;
1188                 }
1189                 
1190                 if (!did_match && M_rebins)
1191                 {
1192                     /* Scan the regexp list & load configs */
1193                     ndrx_dbg_rebins_scancfg(conf);
1194                     
1195                 }
1196             } /* not inline */
1197         } /* debug section found of the cc */
1198     } /* using cc */
1199     
1200     
1201     /* do regex match if have configuration of */
1202     if (!did_match && M_rebins)
1203     {
1204         /* Scan the regexp list & load configs */
1205         if (NULL!=svname && EXTRUE==ndrx_dbg_rebins_apply(svname, tmpname, sizeof(tmpname)))
1206         {
1207             did_match = EXTRUE;
1208         }
1209         
1210         if (!did_match)
1211         {
1212             ndrx_dbg_rebins_apply((char *)EX_PROGNAME, tmpname, sizeof(tmpname));
1213         }
1214     }
1215     
1216     ndrx_dbg_rebins_free();
1217     M_rebins=NULL;
1218     
1219     /* open debug file.. */
1220     if (EXEOS==tmpname[0])
1221     {
1222         /* try to get from env -> override... */
1223         tmp = getenv(CONF_NDRX_DFLTLOG);
1224         
1225         if (NULL!=tmp)
1226         {
1227             NDRX_STRCPY_SAFE(tmpname, tmp);
1228         }
1229     }
1230         
1231     if (EXEOS==tmpname[0])
1232     {
1233         NDRX_STRCPY_SAFE(tmpname, NDRX_LOG_OSSTDERR);
1234     }
1235     
1236     /* propagate to other loggers too... */
1237     NDRX_STRCPY_SAFE(G_stdout_debug.filename, NDRX_LOG_OSSTDOUT);
1238     
1239     /* get handles now in feedback we get the actual file name open */
1240     ndrx_debug_get_sink(tmpname, EXTRUE, &G_ndrx_debug, NULL);
1241     ndrx_debug_get_sink(tmpname, EXTRUE, &G_ubf_debug, NULL);
1242     ndrx_debug_get_sink(tmpname, EXTRUE, &G_tp_debug, NULL);
1243     ndrx_debug_get_sink(G_stdout_debug.filename, EXTRUE, 
1244             &G_stdout_debug, NULL);
1245 
1246     /* if file is not found, then try CONF_NDRX_DFLTLOG, if this not found, open stderr */
1247 
1248     /*
1249      Expected file syntax is:
1250      * file=/tmp/common.log ndrx=5 ubf=5 buf=1
1251      ndrxd file=/tmp/ndrxd.log  threaded=y
1252      xadmin file=/tmp/xadmin.log
1253      ...
1254      */
1255     
1256     if (NULL!=conf)
1257     {
1258         /* kill the conf */
1259         ndrx_keyval_hash_free(conf);
1260     }
1261     
1262     
1263     /* Initialize system test sub-system */
1264     ndrx_systest_init();
1265     
1266     /* init must be done before debug opens
1267      * as we map the check are to shared memory it might conflict
1268      * with some other thread starting up and reading some incomplete pointer
1269      */
1270     lcf_status = ndrx_lcf_init();
1271     
1272     G_ndrx_debug_first = EXFALSE;
1273     
1274     ndrx_dbg_intlock_unset(&do_reply);
1275     
1276     /* to avoid deadlocks, do this ouside any load locking */
1277     if (do_reply)
1278     {
1279         ndrx_dbg_reply_memlog_all();
1280     }
1281     
1282     /* print the standard errors */
1283     if (EXSUCCEED!=lcf_status)
1284     {
1285         /* ndrx_init_fail_banner(); this termiantes the binary */
1286         NDRX_LOG(log_warn, "LCF startup failed -> LCF commands will not be processed");
1287     }
1288     
1289 }
1290 
1291 /**
1292  * Return current NDRX debug level.
1293  * @return - debug level..
1294  */
1295 expublic ndrx_debug_t * debug_get_ndrx_ptr(void)
1296 {
1297     /* NSTD_TLS_ENTRY; */
1298     NDRX_DBG_INIT_ENTRY;
1299     
1300     return get_debug_ptr(&G_ndrx_debug);
1301 }
1302 
1303 /**
1304  * Return TP pointer
1305  * @return 
1306  */
1307 expublic ndrx_debug_t * debug_get_tp_ptr(void)
1308 {
1309     /* NSTD_TLS_ENTRY; */
1310     NDRX_DBG_INIT_ENTRY;
1311     
1312     return get_debug_ptr(&G_tp_debug);
1313 }
1314 
1315 /**
1316  * Return current UBF debug level.
1317  * @return
1318  */
1319 expublic ndrx_debug_t * debug_get_ubf_ptr(void)
1320 {   /* NSTD_TLS_ENTRY; */
1321     NDRX_DBG_INIT_ENTRY;
1322     
1323     return get_debug_ptr(&G_ubf_debug);
1324 }
1325 
1326 /**
1327  * Return current NDRX debug level.
1328  * @return - debug level..
1329  */
1330 expublic int debug_get_ndrx_level(void)
1331 {
1332     NDRX_DBG_INIT_ENTRY;
1333     return G_ndrx_debug.level;
1334 }
1335 
1336 /**
1337  * Return current UBF debug level.
1338  * @return 
1339  */
1340 expublic int debug_get_ubf_level(void)
1341 {
1342     NDRX_DBG_INIT_ENTRY;
1343     return G_ubf_debug.level;
1344 }
1345 
1346 /**
1347  * Return current UBF debug level.
1348  * @return 
1349  */
1350 expublic int debug_get_tp_level(void)
1351 {
1352     NDRX_DBG_INIT_ENTRY;
1353     return G_tp_debug.level;
1354 }
1355 
1356 /**
1357  * Print buffer dump diff to log file. Diffing buffer sizes must match the "len"
1358  * @param dbg_ptr - debug config
1359  * @param lev - level
1360  * @param mod - module
1361  * @param file - source file
1362  * @param line - source line
1363  * @param func - calling func
1364  * @param comment - comment
1365  * @param ptr - buffer1
1366  * @param ptr2 - buffer2
1367  * @param len - buffer size
1368  */
1369 expublic void __ndrx_debug_dump_diff__(ndrx_debug_t *dbg_ptr, int lev, const char *file, 
1370         long line, const char *func, const char *comment, void *ptr, void *ptr2, long len)
1371 {
1372     
1373     int i;
1374     unsigned char buf[17];
1375     unsigned char buf2[17];
1376     unsigned char *cptr = (unsigned char*)ptr;
1377     unsigned char *cptr2 = (unsigned char*)ptr2;
1378     char print_line[256]={0};
1379     char print_line2[256]={0};
1380     /* NSTD_TLS_ENTRY; */
1381     /* NDRX_DBG_INIT_ENTRY; - called by master macro */
1382     dbg_ptr = get_debug_ptr(dbg_ptr);
1383     
1384     if (dbg_ptr->level < lev)
1385     {
1386         return; /* the level is lowered by thread/request logger */
1387     }
1388         
1389     __ndrx_debug__(dbg_ptr, lev, file, line, func, "%s", comment);
1390     
1391     if (0==len)
1392     {
1393         __ndrx_debug__(dbg_ptr, lev, file, line, func, "Notice: Hex dump diff - "
1394                 "nothing to dump: len=%d ptr=%p ptr2=%p", len, ptr, ptr2);
1395         
1396         return; /* nothing todo... */
1397     }
1398     
1399     ndrx_debug_lock(dbg_ptr->dbg_f_ptr);
1400     
1401     for (i = 0; i < len; i++)
1402     {
1403         if ((i % 16) == 0)
1404         {
1405             if (i != 0)
1406             {
1407                 sprintf (print_line + strlen(print_line), "  %s", buf);
1408                 sprintf (print_line2 + strlen(print_line2), "  %s", buf2);
1409 
1410                 if (0!=strcmp(print_line, print_line2))
1411                 {
1412                     /* print line 1 */
1413                     fputs("<", ((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr)->fp);
1414                     fputs(print_line, ((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr)->fp);
1415                     fputs("\n", ((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr)->fp);
1416                     BUFFER_CONTROL(dbg_ptr);
1417                     
1418                     /* print line 2 */
1419                     fputs(">", ((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr)->fp);
1420                     fputs(print_line2, ((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr)->fp);
1421                     fputs("\n", ((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr)->fp);
1422                     BUFFER_CONTROL(dbg_ptr);
1423                 }
1424 
1425                 print_line[0] = 0;
1426                 print_line2[0] = 0;
1427             }
1428 
1429             sprintf (print_line + strlen(print_line), "  %04x ", i);
1430             sprintf (print_line2 + strlen(print_line2), "  %04x ", i);
1431         }
1432 
1433         sprintf (print_line + strlen(print_line), " %02x", cptr[i]);
1434         sprintf (print_line2 + strlen(print_line2), " %02x", cptr2[i]);
1435 
1436         if ((cptr[i] < 0x20) || (cptr[i] > 0x7e))
1437         {
1438             buf[i % 16] = '.';
1439         }
1440         else
1441         {
1442             buf[i % 16] = cptr[i];
1443         }
1444         buf[(i % 16) + 1] = '\0';
1445 
1446         if ((cptr2[i] < 0x20) || (cptr2[i] > 0x7e))
1447         {
1448             buf2[i % 16] = '.';
1449         }
1450         else
1451         {
1452             buf2[i % 16] = cptr2[i];
1453         }
1454         buf2[(i % 16) + 1] = '\0';
1455     }
1456 
1457     while ((i % 16) != 0)
1458     {
1459         sprintf (print_line + strlen(print_line), "   ");
1460         sprintf (print_line2 + strlen(print_line2), "   ");
1461         i++;
1462     }
1463 
1464     sprintf (print_line + strlen(print_line), "  %s", buf);
1465     sprintf (print_line2 + strlen(print_line2), "  %s", buf2);
1466 
1467     if (0!=strcmp(print_line, print_line2))
1468     {
1469         /* print line 1 */
1470         fputs("<", ((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr)->fp);
1471         fputs(print_line, ((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr)->fp);
1472         fputs("\n", ((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr)->fp);
1473         BUFFER_CONTROL(dbg_ptr);
1474 
1475         /* print line 2 */
1476         fputs(">", ((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr)->fp);
1477         fputs(print_line2, ((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr)->fp);
1478         fputs("\n", ((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr)->fp);
1479         BUFFER_CONTROL(dbg_ptr);
1480     }
1481     print_line[0] = 0;
1482     print_line2[0] = 0;
1483     
1484     ndrx_debug_unlock(dbg_ptr->dbg_f_ptr);
1485 }
1486 
1487 /**
1488  * Print buffer dump to log file
1489  * @param dbg_ptr - debug config
1490  * @param lev - level
1491  * @param mod - module
1492  * @param file - source file
1493  * @param line - source line
1494  * @param func - calling func
1495  * @param comment - comment
1496  * @param ptr - buffer1
1497  * @param len - buffer size
1498  */
1499 expublic void __ndrx_debug_dump__(ndrx_debug_t *dbg_ptr, int lev, const char *file, 
1500         long line, const char *func, const char *comment, void *ptr, long len)
1501 {
1502     int i;
1503     unsigned char buf[17];
1504     unsigned char *cptr = (unsigned char*)ptr;
1505     char print_line[256]={0};
1506     NSTD_TLS_ENTRY;
1507     /* NDRX_DBG_INIT_ENTRY; - called by master macro */
1508     
1509     dbg_ptr = get_debug_ptr(dbg_ptr);
1510     
1511     if (dbg_ptr->level < lev)
1512     {
1513         return; /* the level is lowered by thread/request logger */
1514     }
1515     
1516     __ndrx_debug__(dbg_ptr, lev, file, line, func, "%s (nr bytes: %ld)", 
1517             comment, len);
1518     
1519     if (0==len)
1520     {
1521         __ndrx_debug__(dbg_ptr, lev, file, line, func, "Notice: Hex dump - "
1522                 "nothing to dump: len=%d ptr=%p", len, ptr);
1523         
1524         return; /* nothing todo... */
1525     }
1526 
1527     /* fast locking for file name changing.. */
1528     
1529     ndrx_debug_lock(dbg_ptr->dbg_f_ptr);
1530     
1531     for (i = 0; i < len; i++)
1532     {
1533         if ((i % 16) == 0)
1534         {
1535             if (i != 0)
1536             {
1537                 sprintf (print_line + strlen(print_line), "  %s", buf);
1538                 BUFFERED_PRINT_LINE(dbg_ptr, print_line);
1539                 print_line[0] = 0;
1540             }
1541 
1542             sprintf (print_line + strlen(print_line), "  %04x ", i);
1543         }
1544         sprintf (print_line + strlen(print_line), " %02x", cptr[i]);
1545 
1546         if ((cptr[i] < 0x20) || (cptr[i] > 0x7e))
1547         {
1548             buf[i % 16] = '.';
1549         }
1550         else
1551         {
1552             buf[i % 16] = cptr[i];
1553         }
1554         buf[(i % 16) + 1] = '\0';
1555     }
1556 
1557     while ((i % 16) != 0)
1558     {
1559         sprintf (print_line + strlen(print_line), "   ");
1560         i++;
1561     }
1562 
1563     /* And print the final ASCII bit. */
1564     sprintf (print_line + strlen(print_line), "  %s", buf);
1565     BUFFERED_PRINT_LINE(dbg_ptr, print_line);
1566     print_line[0] = 0;
1567     
1568     ndrx_debug_unlock(dbg_ptr->dbg_f_ptr);
1569     
1570 }
1571 
1572 /**
1573  * Print stuff to trace file
1574  * @param dbg_ptr - debug conf
1575  * @param lev - level
1576  * @param mod - module
1577  * @param file - source file
1578  * @param line - source line
1579  * @param func - source func
1580  * @param fmt - format
1581  * @param ... - varargs
1582  */
1583 expublic void __ndrx_debug__(ndrx_debug_t *dbg_ptr, int lev, const char *file, 
1584         long line, const char *func, const char *fmt, ...)
1585 {
1586     va_list ap;
1587     char line_start[128];
1588     long ldate, ltime, lusec;
1589     char *line_print;
1590     char *func_last;
1591     int len;
1592     long  thread_nr = 0;
1593     static __thread uint64_t ostid = 0;
1594     static __thread int first = EXTRUE;
1595     /* NSTD_TLS_ENTRY; */
1596     
1597     /* NDRX_DBG_INIT_ENTRY; - called by master macro */
1598     
1599     if (NULL!=G_nstd_tls)
1600     {
1601         thread_nr = G_nstd_tls->M_threadnr;
1602     }
1603     
1604     /* get the physical tid */
1605     if (first)
1606     {
1607         ostid = ndrx_gettid();
1608         first = EXFALSE;
1609     }
1610     
1611     if (!M_is_initlock_owner)
1612     {
1613         dbg_ptr = get_debug_ptr(dbg_ptr);
1614 
1615         if (dbg_ptr->level < lev)
1616         {
1617             return; /* the level is lowered by thread/request logger */
1618         }
1619     }
1620     
1621     if ((len=strlen(file)) > 8)
1622     {
1623         line_print = (char *)file+len-8;
1624     }
1625     else
1626     {
1627         line_print = (char *)file;
1628     }
1629     
1630     if ((len=strlen(func)) > 12)
1631     {
1632         func_last = (char *)func+len-12;
1633     }
1634     else
1635     {
1636         func_last = (char *)func;
1637     }
1638 
1639     ndrx_get_dt_local(&ldate, &ltime, &lusec);
1640     
1641     snprintf(line_start, sizeof(line_start), 
1642         "%c:%s:%d:%08x:%05d:%08llx:%03ld:%08ld:%06ld%06d:%-12.12s:%-8.8s:%04ld:",
1643         dbg_ptr->code, dbg_ptr->module, lev, (unsigned int)dbg_ptr->hostnamecrc32, 
1644             (int)dbg_ptr->pid, (unsigned long long)(ostid), thread_nr, ldate, ltime, 
1645         (int)(lusec), func_last, line_print, line);
1646     
1647     /* lock the sink */
1648     
1649     if (!M_is_initlock_owner)
1650     {
1651         
1652         /* last locking */
1653         ndrx_debug_lock((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr);
1654         
1655         fputs(line_start, ((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr)->fp);
1656         va_start(ap, fmt);    
1657         (void) vfprintf(((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr)->fp, fmt, ap);
1658         va_end(ap);
1659         fputs("\n", ((ndrx_debug_file_sink_t*)dbg_ptr->dbg_f_ptr)->fp);
1660         
1661         /* Handle some buffering... */
1662         BUFFER_CONTROL(dbg_ptr);
1663         
1664         ndrx_debug_unlock(dbg_ptr->dbg_f_ptr);
1665     }
1666     else
1667     {
1668         ndrx_memlogger_t *memline = NDRX_MALLOC(sizeof(ndrx_memlogger_t));
1669         
1670         if (NULL==memline)
1671         {
1672             userlog("Failed to malloc mem debug line: %s - skipping log entry", 
1673                     strerror(errno));
1674         }
1675         else
1676         {
1677             int len;
1678             memline->line[0] = EXEOS;
1679             memline->level = lev; /* user for log reply to actual logger */
1680             /* alloc the storage object */
1681             NDRX_STRCPY_SAFE(memline->line, line_start);
1682             
1683             len = strlen(memline->line);
1684             
1685             va_start(ap, fmt);    
1686             (void) vsnprintf(memline->line+len, sizeof(memline->line)-len, fmt, ap);
1687             va_end(ap);
1688             
1689             
1690             /* Add line to the logger */
1691             MUTEX_LOCK_V(M_memlog_lock);
1692             DL_APPEND(dbg_ptr->memlog, memline);
1693             MUTEX_UNLOCK_V(M_memlog_lock);
1694             
1695         }
1696     }
1697 }
1698 
1699 /**
1700  * Initialize debug library
1701  * Currently default level is to use maximum.
1702  *
1703  * Debug buffer is set to default 0, can be overriden by <KEY>+DBGBUF
1704  * @param module - module form which debug is initialized
1705  */
1706 expublic void ndrx_dbg_init(char *module, char *config_key)
1707 {
1708    NDRX_DBG_INIT_ENTRY;
1709 }
1710 
1711 /**
1712  * Debug version of malloc();
1713  * @param size
1714  * @param line
1715  * @param file
1716  * @param func
1717  * @return 
1718  */
1719 expublic void *ndrx_malloc_dbg(size_t size, long line, const char *file, const char *func)
1720 {
1721     void *ret;
1722     int errnosv;
1723     
1724     ret=malloc(size);
1725     errnosv = errno;
1726     
1727     userlog("[%p] <= malloc(size=%d):%s %s:%ld", ret, size, func, file, line);
1728     
1729     errno = errnosv;
1730     
1731     return ret;
1732 }
1733 
1734 /**
1735  * Debug version of free();
1736  * @param size
1737  * @param line
1738  * @param file
1739  * @param func
1740  * @return 
1741  */
1742 expublic void ndrx_free_dbg(void *ptr, long line, const char *file, const char *func)
1743 {
1744     userlog("[%p] => free(ptr=%p):%s %s:%ld", ptr, ptr, func, file, line);
1745     free(ptr);
1746 }
1747 
1748 /**
1749  * Debug version of calloc();
1750  * @param size
1751  * @param line
1752  * @param file
1753  * @param func
1754  * @return 
1755  */
1756 expublic void *ndrx_calloc_dbg(size_t nmemb, size_t size, long line, const char *file, const char *func)
1757 {
1758     void *ret;
1759     int errnosv;
1760     
1761     ret=calloc(nmemb, size);
1762     errnosv = errno;
1763     userlog("[%p] <= calloc(nmemb=%d, size=%d):%s %s:%ld", ret, nmemb, 
1764             size, func, file, line);
1765     
1766     errno = errnosv;
1767     
1768     return ret;
1769 }
1770 
1771 /**
1772  * Debug version of realloc();
1773  * @param size
1774  * @param line
1775  * @param file
1776  * @param func
1777  * @return 
1778  */
1779 expublic void *ndrx_realloc_dbg(void *ptr, size_t size, long line, const char *file, const char *func)
1780 {   
1781     void *ret;
1782     int errnosv;
1783     
1784     ret= realloc(ptr, size);
1785     
1786     errnosv = errno;
1787             
1788     userlog("[%p] <= realloc(ptr=[%p], size=%d):%s %s:%ld", ret, ptr, 
1789             size, func, file, line);
1790     
1791     errno = errnosv;
1792     return ret;
1793 }
1794 
1795 
1796 /**
1797  * Memory logging version of fopen(3)
1798  * @param path
1799  * @param mode
1800  * @return 
1801  */
1802 expublic FILE *ndrx_fopen_dbg(const char *path, const char *mode, 
1803         long line, const char *file, const char *func)
1804 {
1805     FILE *ret;
1806     int errnosv;
1807     
1808     ret = fopen(path, mode);
1809     errnosv = errno;
1810    
1811     userlog("[%p] <= fopen(path=%s, mode=%s):%s %s:%ld", ret,  path, mode,
1812             func, file, line);
1813     
1814     errno = errnosv;
1815     
1816     return ret;
1817 }
1818 
1819 
1820 /**
1821  * Memory logging version of fclose(3)
1822  * @param fp
1823  * @return 
1824  */
1825 expublic int ndrx_fclose_dbg(FILE *fp, long line, const char *file, const char *func)
1826 {
1827     int ret;
1828     int errnosv;
1829     
1830     ret = fclose(fp);
1831     
1832     errnosv = errno;
1833             
1834     userlog("[%p] => fclose(fp=%p) => %d:%s %s:%ld", fp, fp, ret, 
1835             func, file, line);
1836     
1837     errno = errnosv;
1838     
1839     return ret;
1840     
1841 }
1842 
1843 /**
1844  * Debug version of strdup();
1845  * @return 
1846  */
1847 expublic char *ndrx_strdup_dbg(char *ptr, long line, const char *file, const char *func)
1848 {
1849     char *ret;
1850     int errnosv;
1851     
1852     ret=strdup(ptr);
1853     errnosv = errno;
1854     
1855     userlog("[%p] <= strdup(ptr=%p):%s %s:%ld", ret, ptr, func, file, line);
1856     
1857     errno = errnosv;
1858     
1859     return ret;
1860 }
1861 
1862 /* vim: set ts=4 sw=4 et smartindent: */