LCOV - code coverage report
Current view: top level - util - debug.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 107 179 59.8 %
Date: 2015-10-19 Functions: 9 14 64.3 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         Simo Sorce <ssorce@redhat.com>
       4             :         Stephen Gallagher <sgallagh@redhat.com>
       5             : 
       6             :     Copyright (C) 2009 Red Hat
       7             : 
       8             :     This program is free software; you can redistribute it and/or modify
       9             :     it under the terms of the GNU General Public License as published by
      10             :     the Free Software Foundation; either version 3 of the License, or
      11             :     (at your option) any later version.
      12             : 
      13             :     This program is distributed in the hope that it will be useful,
      14             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :     GNU General Public License for more details.
      17             : 
      18             :     You should have received a copy of the GNU General Public License
      19             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "config.h"
      23             : 
      24             : #include <stdio.h>
      25             : #include <stdarg.h>
      26             : #include <stdlib.h>
      27             : #include <fcntl.h>
      28             : 
      29             : #include <sys/types.h>
      30             : #include <sys/stat.h>
      31             : #include <sys/time.h>
      32             : 
      33             : #ifdef WITH_JOURNALD
      34             : #include <systemd/sd-journal.h>
      35             : #endif
      36             : 
      37             : #include "util/util.h"
      38             : 
      39             : const char *debug_prg_name = "sssd";
      40             : 
      41             : int debug_level = SSSDBG_UNRESOLVED;
      42             : int debug_timestamps = SSSDBG_TIMESTAMP_UNRESOLVED;
      43             : int debug_microseconds = SSSDBG_MICROSECONDS_UNRESOLVED;
      44             : int debug_to_file = 0;
      45             : int debug_to_stderr = 0;
      46             : const char *debug_log_file = "sssd";
      47             : FILE *debug_file = NULL;
      48             : 
      49          60 : errno_t set_debug_file_from_fd(const int fd)
      50             : {
      51             :     FILE *dummy;
      52             :     errno_t ret;
      53             : 
      54          60 :     errno = 0;
      55          60 :     dummy = fdopen(fd, "a");
      56          60 :     if (dummy == NULL) {
      57           0 :         ret = errno;
      58           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
      59             :               "fdopen failed [%d][%s].\n", ret, strerror(ret));
      60           0 :         sss_log(SSS_LOG_ERR,
      61             :                 "Could not open debug file descriptor [%d]. "
      62             :                 "Debug messages will not be written to the file "
      63             :                 "for this child process [%s][%s]\n",
      64             :                 fd, debug_prg_name, strerror(ret));
      65           0 :         return ret;
      66             :     }
      67             : 
      68          60 :     debug_file = dummy;
      69             : 
      70          60 :     return EOK;
      71             : }
      72             : 
      73           0 : int get_fd_from_debug_file(void)
      74             : {
      75           0 :     if (debug_file == NULL) {
      76           0 :         return STDERR_FILENO;
      77             :     }
      78             : 
      79           0 :     return fileno(debug_file);
      80             : }
      81             : 
      82          36 : int debug_convert_old_level(int old_level)
      83             : {
      84          36 :     if ((old_level != 0) && !(old_level & 0x000F))
      85          14 :         return old_level;
      86             : 
      87          22 :     int new_level = SSSDBG_FATAL_FAILURE;
      88             : 
      89          22 :     if (old_level <= 0)
      90          13 :         return new_level;
      91             : 
      92           9 :     if (old_level >= 1)
      93           9 :         new_level |= SSSDBG_CRIT_FAILURE;
      94             : 
      95           9 :     if (old_level >= 2)
      96           8 :         new_level |= SSSDBG_OP_FAILURE;
      97             : 
      98           9 :     if (old_level >= 3)
      99           7 :         new_level |= SSSDBG_MINOR_FAILURE;
     100             : 
     101           9 :     if (old_level >= 4)
     102           6 :         new_level |= SSSDBG_CONF_SETTINGS;
     103             : 
     104           9 :     if (old_level >= 5)
     105           5 :         new_level |= SSSDBG_FUNC_DATA;
     106             : 
     107           9 :     if (old_level >= 6)
     108           4 :         new_level |= SSSDBG_TRACE_FUNC;
     109             : 
     110           9 :     if (old_level >= 7)
     111           3 :         new_level |= SSSDBG_TRACE_LIBS;
     112             : 
     113           9 :     if (old_level >= 8)
     114           2 :         new_level |= SSSDBG_TRACE_INTERNAL;
     115             : 
     116           9 :     if (old_level >= 9)
     117           1 :         new_level |= SSSDBG_TRACE_ALL | SSSDBG_BE_FO;
     118             : 
     119           9 :     return new_level;
     120             : }
     121             : 
     122         106 : static void debug_fflush(void)
     123             : {
     124         106 :     fflush(debug_file ? debug_file : stderr);
     125         106 : }
     126             : 
     127         212 : static void debug_vprintf(const char *format, va_list ap)
     128             : {
     129         212 :     vfprintf(debug_file ? debug_file : stderr, format, ap);
     130         212 : }
     131             : 
     132             : static void debug_printf(const char *format, ...)
     133             :                 SSS_ATTRIBUTE_PRINTF(1, 2);
     134             : 
     135         106 : static void debug_printf(const char *format, ...)
     136             : {
     137             :     va_list ap;
     138             : 
     139         106 :     va_start(ap, format);
     140             : 
     141         106 :     debug_vprintf(format, ap);
     142             : 
     143         106 :     va_end(ap);
     144         106 : }
     145             : 
     146             : #ifdef WITH_JOURNALD
     147          20 : errno_t journal_send(const char *file,
     148             :         long line,
     149             :         const char *function,
     150             :         int level,
     151             :         const char *format,
     152             :         va_list ap)
     153             : {
     154             :     errno_t ret;
     155             :     int res;
     156          20 :     char *message = NULL;
     157          20 :     char *code_file = NULL;
     158          20 :     char *code_line = NULL;
     159             :     const char *domain;
     160             : 
     161             :     /* First, evaluate the message to be sent */
     162          20 :     ret = vasprintf(&message, format, ap);
     163          20 :     if (ret == -1) {
     164             :         /* ENOMEM, just return */
     165           0 :         return ENOMEM;
     166             :     }
     167             : 
     168          20 :     res = asprintf(&code_file, "CODE_FILE=%s", file);
     169          20 :     if (res == -1) {
     170           0 :         ret = ENOMEM;
     171           0 :         goto journal_done;
     172             :     }
     173             : 
     174          20 :     res = asprintf(&code_line, "CODE_LINE=%ld", line);
     175          20 :     if (res == -1) {
     176           0 :         ret = ENOMEM;
     177           0 :         goto journal_done;
     178             :     }
     179             : 
     180             :     /* If this log message was sent from a provider,
     181             :      * track the domain.
     182             :      */
     183          20 :     domain = getenv(SSS_DOM_ENV);
     184          20 :     if (domain == NULL) {
     185          20 :         domain = "";
     186             :     }
     187             : 
     188             :     /* Send the log message to journald, specifying the
     189             :      * source code location and other tracking data.
     190             :      */
     191          20 :     res = sd_journal_send_with_location(
     192             :             code_file, code_line, function,
     193             :             "MESSAGE=%s", message,
     194             :             "PRIORITY=%i", LOG_DEBUG,
     195             :             "SSSD_DOMAIN=%s", domain,
     196             :             "SSSD_PRG_NAME=%s", debug_prg_name,
     197             :             "SSSD_DEBUG_LEVEL=%x", level,
     198             :             NULL);
     199          20 :     ret = -res;
     200             : 
     201             : journal_done:
     202          20 :     free(code_line);
     203          20 :     free(code_file);
     204          20 :     free(message);
     205          20 :     return ret;
     206             : }
     207             : #endif /* WiTH_JOURNALD */
     208             : 
     209         126 : void debug_fn(const char *file,
     210             :               long line,
     211             :               const char *function,
     212             :               int level,
     213             :               const char *format, ...)
     214             : {
     215             :     va_list ap;
     216             :     struct timeval tv;
     217             :     struct tm *tm;
     218             :     char datetime[20];
     219             :     int year;
     220             : 
     221             : #ifdef WITH_JOURNALD
     222             :     errno_t ret;
     223             :     va_list ap_fallback;
     224             : 
     225         126 :     if (!debug_file && !debug_to_stderr) {
     226             :         /* If we are not outputting logs to files, we should be sending them
     227             :          * to journald.
     228             :          * NOTE: on modern systems, this is where stdout/stderr will end up
     229             :          * from system services anyway. The only difference here is that we
     230             :          * can also provide extra structuring data to make it more easily
     231             :          * searchable.
     232             :          */
     233          20 :         va_start(ap, format);
     234          20 :         va_copy(ap_fallback, ap);
     235          20 :         ret = journal_send(file, line, function, level, format, ap);
     236          20 :         va_end(ap);
     237          20 :         if (ret != EOK) {
     238             :             /* Emergency fallback, send to STDERR */
     239           0 :             debug_vprintf(format, ap_fallback);
     240           0 :             debug_fflush();
     241             :         }
     242          20 :         va_end(ap_fallback);
     243          20 :         return;
     244             :     }
     245             : #endif
     246             : 
     247         106 :     if (debug_timestamps) {
     248          96 :         gettimeofday(&tv, NULL);
     249          96 :         tm = localtime(&tv.tv_sec);
     250          96 :         year = tm->tm_year + 1900;
     251             :         /* get date time without year */
     252          96 :         memcpy(datetime, ctime(&tv.tv_sec), 19);
     253          96 :         datetime[19] = '\0';
     254          96 :         if (debug_microseconds) {
     255          86 :             debug_printf("(%s:%.6ld %d) [%s] [%s] (%#.4x): ",
     256             :                          datetime, tv.tv_usec,
     257             :                          year, debug_prg_name,
     258             :                          function, level);
     259             :         } else {
     260          10 :             debug_printf("(%s %d) [%s] [%s] (%#.4x): ",
     261             :                          datetime, year,
     262             :                          debug_prg_name, function, level);
     263             :         }
     264             :     } else {
     265          10 :         debug_printf("[%s] [%s] (%#.4x): ",
     266             :                      debug_prg_name, function, level);
     267             :     }
     268             : 
     269         106 :     va_start(ap, format);
     270         106 :     debug_vprintf(format, ap);
     271         106 :     va_end(ap);
     272         106 :     debug_fflush();
     273             : }
     274             : 
     275       74792 : void ldb_debug_messages(void *context, enum ldb_debug_level level,
     276             :                         const char *fmt, va_list ap)
     277             : {
     278       74792 :     int loglevel = SSSDBG_UNRESOLVED;
     279             :     int ret;
     280       74792 :     char * message = NULL;
     281             : 
     282       74792 :     switch(level) {
     283             :     case LDB_DEBUG_FATAL:
     284           0 :         loglevel = SSSDBG_FATAL_FAILURE;
     285           0 :         break;
     286             :     case LDB_DEBUG_ERROR:
     287           0 :         loglevel = SSSDBG_CRIT_FAILURE;
     288           0 :         break;
     289             :     case LDB_DEBUG_WARNING:
     290        1081 :         loglevel = SSSDBG_TRACE_FUNC;
     291        1081 :         break;
     292             :     case LDB_DEBUG_TRACE:
     293       73711 :         loglevel = SSSDBG_TRACE_ALL;
     294       73711 :         break;
     295             :     }
     296             : 
     297       74792 :     ret = vasprintf(&message, fmt, ap);
     298       74792 :     if (ret < 0) {
     299             :         /* ENOMEM */
     300           0 :         return;
     301             :     }
     302             : 
     303       74792 :     if (DEBUG_IS_SET(loglevel))
     304           0 :         debug_fn(__FILE__, __LINE__, "ldb", loglevel, "%s\n", message);
     305             : 
     306       74792 :     free(message);
     307             : }
     308             : 
     309             : /* In cases SSSD used to run as the root user, but runs as the SSSD user now,
     310             :  * we need to chown the log files
     311             :  */
     312           3 : int chown_debug_file(const char *filename,
     313             :                      uid_t uid, gid_t gid)
     314             : {
     315             :     char *logpath;
     316             :     const char *log_file;
     317             :     errno_t ret;
     318             : 
     319           3 :     if (filename == NULL) {
     320           3 :         log_file = debug_log_file;
     321             :     } else {
     322           0 :         log_file = filename;
     323             :     }
     324             : 
     325           3 :     ret = asprintf(&logpath, "%s/%s.log", LOG_PATH, log_file);
     326           3 :     if (ret == -1) {
     327           0 :         return ENOMEM;
     328             :     }
     329             : 
     330           3 :     ret = chown(logpath, uid, gid);
     331           3 :     free(logpath);
     332           3 :     if (ret != 0) {
     333           3 :         ret = errno;
     334           3 :         DEBUG(SSSDBG_FATAL_FAILURE, "chown failed for [%s]: [%d]\n",
     335             :               log_file, ret);
     336           3 :         return ret;
     337             :     }
     338             : 
     339           0 :     return EOK;
     340             : }
     341             : 
     342           0 : int open_debug_file_ex(const char *filename, FILE **filep, bool want_cloexec)
     343             : {
     344           0 :     FILE *f = NULL;
     345             :     char *logpath;
     346             :     const char *log_file;
     347             :     mode_t old_umask;
     348             :     int ret;
     349             :     int debug_fd;
     350             :     int flags;
     351             : 
     352           0 :     if (filename == NULL) {
     353           0 :         log_file = debug_log_file;
     354             :     } else {
     355           0 :         log_file = filename;
     356             :     }
     357             : 
     358           0 :     ret = asprintf(&logpath, "%s/%s.log", LOG_PATH, log_file);
     359           0 :     if (ret == -1) {
     360           0 :         return ENOMEM;
     361             :     }
     362             : 
     363           0 :     if (debug_file && !filep) fclose(debug_file);
     364             : 
     365           0 :     old_umask = umask(SSS_DFL_UMASK);
     366           0 :     errno = 0;
     367           0 :     f = fopen(logpath, "a");
     368           0 :     if (f == NULL) {
     369           0 :         sss_log(SSS_LOG_EMERG, "Could not open file [%s]. Error: [%d][%s]\n",
     370           0 :                                logpath, errno, strerror(errno));
     371           0 :         free(logpath);
     372           0 :         return EIO;
     373             :     }
     374           0 :     umask(old_umask);
     375             : 
     376           0 :     debug_fd = fileno(f);
     377           0 :     if (debug_fd == -1) {
     378           0 :         fclose(f);
     379           0 :         free(logpath);
     380           0 :         return EIO;
     381             :     }
     382             : 
     383           0 :     if(want_cloexec) {
     384           0 :         flags = fcntl(debug_fd, F_GETFD, 0);
     385           0 :         (void) fcntl(debug_fd, F_SETFD, flags | FD_CLOEXEC);
     386             :     }
     387             : 
     388           0 :     if (filep == NULL) {
     389           0 :         debug_file = f;
     390             :     } else {
     391           0 :         *filep = f;
     392             :     }
     393           0 :     free(logpath);
     394           0 :     return EOK;
     395             : }
     396             : 
     397           0 : int open_debug_file(void)
     398             : {
     399           0 :     return open_debug_file_ex(NULL, NULL, true);
     400             : }
     401             : 
     402           0 : int rotate_debug_files(void)
     403             : {
     404             :     int ret;
     405             :     errno_t error;
     406             : 
     407           0 :     if (!debug_to_file) return EOK;
     408             : 
     409             :     do {
     410           0 :         error = 0;
     411           0 :         ret = fclose(debug_file);
     412           0 :         if (ret != 0) {
     413           0 :             error = errno;
     414             :         }
     415             : 
     416             :         /* Check for EINTR, which means we should retry
     417             :          * because the system call was interrupted by a
     418             :          * signal
     419             :          */
     420           0 :     } while (error == EINTR);
     421             : 
     422           0 :     if (error != 0) {
     423             :         /* Even if we were unable to close the debug log, we need to make
     424             :          * sure that we open up a new one. Log rotation will remove the
     425             :          * current file, so all debug messages will be disappearing.
     426             :          *
     427             :          * We should write an error to the syslog warning of the resource
     428             :          * leak and then proceed with opening the new file.
     429             :          */
     430           0 :         sss_log(SSS_LOG_ALERT, "Could not close debug file [%s]. [%d][%s]\n",
     431             :                                debug_log_file, error, strerror(error));
     432           0 :         sss_log(SSS_LOG_ALERT, "Attempting to open new file anyway. "
     433             :                                "Be aware that this is a resource leak\n");
     434             :     }
     435             : 
     436           0 :     debug_file = NULL;
     437             : 
     438           0 :     return open_debug_file();
     439             : }
     440             : 
     441           0 : void talloc_log_fn(const char *message)
     442             : {
     443           0 :     DEBUG(SSSDBG_FATAL_FAILURE, "%s\n", message);
     444           0 : }

Generated by: LCOV version 1.10