]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - ubuntu/vbox/vboxguest/common/log/log.c
UBUNTU: ubuntu: vbox -- update to 5.2.2-dfsg-2
[mirror_ubuntu-bionic-kernel.git] / ubuntu / vbox / vboxguest / common / log / log.c
index 08fb0897c03b321b546070c92624b78eb809ca3d..fb44c9d3b9ea9ba73aea1128f64b940deeaec587 100644 (file)
@@ -227,13 +227,12 @@ static void rtR0LogLoggerExFallback(uint32_t fDestFlags, uint32_t fFlags, PRTLOG
                                     const char *pszFormat, va_list va);
 #endif
 #ifdef IN_RING3
-static int rtlogFileOpen(PRTLOGGER pLogger, char *pszErrorMsg, size_t cchErrorMsg);
-static void rtlogRotate(PRTLOGGER pLogger, uint32_t uTimeSlot, bool fFirst);
+static int  rtR3LogOpenFileDestination(PRTLOGGER pLogger, PRTERRINFO pErrInfo);
 #endif
 #ifndef IN_RC
 static void rtLogRingBufFlush(PRTLOGGER pLogger);
 #endif
-static void rtlogFlush(PRTLOGGER pLogger);
+static void rtlogFlush(PRTLOGGER pLogger, bool fNeedSpace);
 static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars);
 static DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars, size_t cbChars);
 static void rtlogLoggerExVLocked(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args);
@@ -777,13 +776,11 @@ static void rtLogRingBufFlush(PRTLOGGER pLogger)
 }
 
 
-
-
 RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszGroupSettings,
                            const char *pszEnvVarBase, unsigned cGroups, const char * const *papszGroups,
                            uint32_t fDestFlags, PFNRTLOGPHASE pfnPhase, uint32_t cHistory,
                            uint64_t cbHistoryFileMax, uint32_t cSecsHistoryTimeSlot,
-                           char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, va_list args)
+                           PRTERRINFO pErrInfo, const char *pszFilenameFmt, va_list args)
 {
     int         rc;
     size_t      offInternal;
@@ -793,17 +790,14 @@ RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, uint32_t fFlags, const char *psz
     /*
      * Validate input.
      */
-    if (    (cGroups && !papszGroups)
-        ||  !VALID_PTR(ppLogger) )
+    if (   (cGroups && !papszGroups)
+        || !VALID_PTR(ppLogger) )
     {
         AssertMsgFailed(("Invalid parameters!\n"));
         return VERR_INVALID_PARAMETER;
     }
     *ppLogger = NULL;
 
-    if (pszErrorMsg)
-        RTStrPrintf(pszErrorMsg, cchErrorMsg, N_("unknown error"));
-
     AssertMsgReturn(cHistory < _1M, ("%#x", cHistory), VERR_OUT_OF_RANGE);
 
     /*
@@ -884,11 +878,11 @@ RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, uint32_t fFlags, const char *psz
         }
         else
         {
+            rc = VERR_NO_MEMORY;
 #  ifdef RT_OS_LINUX
-            if (pszErrorMsg) /* Most probably SELinux causing trouble since the larger RTMemAlloc succeeded. */
-                RTStrPrintf(pszErrorMsg, cchErrorMsg, N_("mmap(PROT_WRITE | PROT_EXEC) failed -- SELinux?"));
+                /* Most probably SELinux causing trouble since the larger RTMemAlloc succeeded. */
+            RTErrInfoSet(pErrInfo, rc, N_("mmap(PROT_WRITE | PROT_EXEC) failed -- SELinux?"));
 #  endif
-            rc = VERR_NO_MEMORY;
         }
         if (RT_SUCCESS(rc))
 # endif /* X86 wrapper code*/
@@ -901,7 +895,8 @@ RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, uint32_t fFlags, const char *psz
             {
                 /** @todo validate the length, fail on overflow. */
                 RTStrPrintfV(pLogger->pInt->szFilename, sizeof(pLogger->pInt->szFilename), pszFilenameFmt, args);
-                pLogger->fDestFlags |= RTLOGDEST_FILE;
+                if (pLogger->pInt->szFilename[0])
+                    pLogger->fDestFlags |= RTLOGDEST_FILE;
             }
 
             /*
@@ -946,32 +941,12 @@ RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, uint32_t fFlags, const char *psz
              * Open the destination(s).
              */
             rc = VINF_SUCCESS;
+            if ((pLogger->fDestFlags & (RTLOGDEST_F_DELAY_FILE | RTLOGDEST_FILE)) == RTLOGDEST_F_DELAY_FILE)
+                pLogger->fDestFlags &= ~RTLOGDEST_F_DELAY_FILE;
 # ifdef IN_RING3
-            if (pLogger->fDestFlags & RTLOGDEST_FILE)
-            {
-                if (pLogger->fFlags & RTLOGFLAGS_APPEND)
-                {
-                    rc = rtlogFileOpen(pLogger, pszErrorMsg, cchErrorMsg);
-
-                    /* Rotate in case of appending to a too big log file,
-                       otherwise this simply doesn't do anything. */
-                    rtlogRotate(pLogger, 0, true /* fFirst */);
-                }
-                else
-                {
-                    /* Force rotation if it is configured. */
-                    pLogger->pInt->cbHistoryFileWritten = UINT64_MAX;
-                    rtlogRotate(pLogger, 0, true /* fFirst */);
-
-                    /* If the file is not open then rotation is not set up. */
-                    if (pLogger->pInt->hFile == NIL_RTFILE)
-                    {
-                        pLogger->pInt->cbHistoryFileWritten = 0;
-                        rc = rtlogFileOpen(pLogger, pszErrorMsg, cchErrorMsg);
-                    }
-                }
-            }
-# endif  /* IN_RING3 */
+            if ((pLogger->fDestFlags & (RTLOGDEST_FILE | RTLOGDEST_F_DELAY_FILE)) == RTLOGDEST_FILE)
+                rc = rtR3LogOpenFileDestination(pLogger, pErrInfo);
+# endif
 
             if ((pLogger->fDestFlags & RTLOGDEST_RINGBUF) && RT_SUCCESS(rc))
                 rc = rtLogRingBufAdjust(pLogger, pLogger->pInt->cbRingBuf, true /*fForce*/);
@@ -1006,8 +981,7 @@ RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, uint32_t fFlags, const char *psz
                     return VINF_SUCCESS;
                 }
 
-                if (pszErrorMsg)
-                    RTStrPrintf(pszErrorMsg, cchErrorMsg, N_("failed to create semaphore"));
+                RTErrInfoSet(pErrInfo, rc, N_("failed to create semaphore"));
             }
 # ifdef IN_RING3
             RTFileClose(pLogger->pInt->hFile);
@@ -1038,7 +1012,7 @@ RTDECL(int) RTLogCreate(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszGro
     va_start(args, pszFilenameFmt);
     rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups,
                         fDestFlags, NULL /*pfnPhase*/, 0 /*cHistory*/, 0 /*cbHistoryFileMax*/, 0 /*cSecsHistoryTimeSlot*/,
-                        NULL /*pszErrorMsg*/, 0 /*cchErrorMsg*/, pszFilenameFmt, args);
+                        NULL /*pErrInfo*/, pszFilenameFmt, args);
     va_end(args);
     return rc;
 }
@@ -1049,7 +1023,7 @@ RTDECL(int) RTLogCreateEx(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszG
                           const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
                           uint32_t fDestFlags, PFNRTLOGPHASE pfnPhase, uint32_t cHistory,
                           uint64_t cbHistoryFileMax, uint32_t cSecsHistoryTimeSlot,
-                          char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, ...)
+                          PRTERRINFO pErrInfo, const char *pszFilenameFmt, ...)
 {
     va_list args;
     int rc;
@@ -1057,7 +1031,7 @@ RTDECL(int) RTLogCreateEx(PRTLOGGER *ppLogger, uint32_t fFlags, const char *pszG
     va_start(args, pszFilenameFmt);
     rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups,
                         fDestFlags, pfnPhase, cHistory, cbHistoryFileMax, cSecsHistoryTimeSlot,
-                        pszErrorMsg, cchErrorMsg, pszFilenameFmt, args);
+                        pErrInfo, pszFilenameFmt, args);
     va_end(args);
     return rc;
 }
@@ -1101,7 +1075,7 @@ RTDECL(int) RTLogDestroy(PRTLOGGER pLogger)
     /*
      * Flush it.
      */
-    rtlogFlush(pLogger);
+    rtlogFlush(pLogger, false /*fNeedSpace*/);
 
 # ifdef IN_RING3
     /*
@@ -2447,6 +2421,53 @@ RTDECL(int) RTLogDestinations(PRTLOGGER pLogger, char const *pszValue)
 RT_EXPORT_SYMBOL(RTLogDestinations);
 
 
+/**
+ * Clear the file delay flag if set, opening the destination and flushing.
+ *
+ * @returns IPRT status code.
+ * @param   pLogger             Logger instance (NULL for default logger).
+ * @param   pszValue            The value to parse.
+ * @param   pErrInfo            Where to return extended error info.  Optional.
+ */
+RTDECL(int) RTLogClearFileDelayFlag(PRTLOGGER pLogger, PRTERRINFO pErrInfo)
+{
+    /*
+     * Resolve defaults.
+     */
+    if (!pLogger)
+    {
+        pLogger = RTLogDefaultInstance();
+        if (!pLogger)
+            return VINF_SUCCESS;
+    }
+
+    /*
+     * Do the work.
+     */
+    int rc = rtlogLock(pLogger);
+    if (RT_SUCCESS(rc))
+    {
+        if (pLogger->fDestFlags & RTLOGDEST_F_DELAY_FILE)
+        {
+            pLogger->fDestFlags &= ~RTLOGDEST_F_DELAY_FILE;
+# ifdef IN_RING3
+            if (   pLogger->fDestFlags & RTLOGDEST_FILE
+                && pLogger->pInt->hFile == NIL_RTFILE)
+            {
+                rc = rtR3LogOpenFileDestination(pLogger, pErrInfo);
+                if (RT_SUCCESS(rc))
+                    rtlogFlush(pLogger, false /*fNeedSpace*/);
+            }
+# endif
+            RT_NOREF(pErrInfo); /** @todo fix create API to use RTErrInfo */
+        }
+        rtlogUnlock(pLogger);
+    }
+    return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTLogClearFileDelayFlag);
+
+
 /**
  * Get the current log destinations as a string.
  *
@@ -2604,7 +2625,7 @@ RTDECL(void) RTLogFlush(PRTLOGGER pLogger)
         /*
          * Call worker.
          */
-        rtlogFlush(pLogger);
+        rtlogFlush(pLogger, false /*fNeedSpace*/);
 
 #ifndef IN_RC
         /*
@@ -3149,11 +3170,10 @@ RT_EXPORT_SYMBOL(RTLogDumpPrintfV);
  * Opens/creates the log file.
  *
  * @param   pLogger         The logger instance to update. NULL is not allowed!
- * @param   pszErrorMsg     A buffer which is filled with an error message if
- *                          something fails.  May be NULL.
- * @param   cchErrorMsg     The size of the error message buffer.
+ * @param   pErrInfo        Where to return extended error information.
+ *                          Optional.
  */
-static int rtlogFileOpen(PRTLOGGER pLogger, char *pszErrorMsg, size_t cchErrorMsg)
+static int rtlogFileOpen(PRTLOGGER pLogger, PRTERRINFO pErrInfo)
 {
     uint32_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_NONE;
     if (pLogger->fFlags & RTLOGFLAGS_APPEND)
@@ -3186,8 +3206,7 @@ static int rtlogFileOpen(PRTLOGGER pLogger, char *pszErrorMsg, size_t cchErrorMs
     else
     {
         pLogger->pInt->hFile = NIL_RTFILE;
-        if (pszErrorMsg)
-            RTStrPrintf(pszErrorMsg, cchErrorMsg, N_("could not open file '%s' (fOpen=%#x)"), pLogger->pInt->szFilename, fOpen);
+        RTErrInfoSetF(pErrInfo, rc, N_("could not open file '%s' (fOpen=%#x)"), pLogger->pInt->szFilename, fOpen);
     }
     return rc;
 }
@@ -3203,8 +3222,9 @@ static int rtlogFileOpen(PRTLOGGER pLogger, char *pszErrorMsg, size_t cchErrorMs
  * @param   fFirst      Flag whether this is the beginning of logging, i.e.
  *                      called from RTLogCreateExV.  Prevents pfnPhase from
  *                      being called.
+ * @param   pErrInfo    Where to return extended error information. Optional.
  */
-static void rtlogRotate(PRTLOGGER pLogger, uint32_t uTimeSlot, bool fFirst)
+static void rtlogRotate(PRTLOGGER pLogger, uint32_t uTimeSlot, bool fFirst, PRTERRINFO pErrInfo)
 {
     /* Suppress rotating empty log files simply because the time elapsed. */
     if (RT_UNLIKELY(!pLogger->pInt->cbHistoryFileWritten))
@@ -3296,7 +3316,7 @@ static void rtlogRotate(PRTLOGGER pLogger, uint32_t uTimeSlot, bool fFirst)
      */
     pLogger->pInt->cbHistoryFileWritten = 0;
     pLogger->pInt->uHistoryTimeSlotStart = uTimeSlot;
-    rtlogFileOpen(pLogger, NULL, 0);
+    rtlogFileOpen(pLogger, pErrInfo);
 
     /*
      * Use the callback to generate some initial log contents, but only if this
@@ -3316,21 +3336,64 @@ static void rtlogRotate(PRTLOGGER pLogger, uint32_t uTimeSlot, bool fFirst)
     pLogger->fFlags         = fSavedFlags;
 }
 
+
+/**
+ * Worker for RTLogCreateExV and RTLogClearFileDelayFlag.
+ *
+ * This will later be used to reopen the file by RTLogDestinations.
+ *
+ * @returns IPRT status code.
+ * @param   pLogger             The logger.
+ * @param   pErrInfo            Where to return extended error information.
+ *                              Optional.
+ */
+static int rtR3LogOpenFileDestination(PRTLOGGER pLogger, PRTERRINFO pErrInfo)
+{
+    int rc;
+    if (pLogger->fFlags & RTLOGFLAGS_APPEND)
+    {
+        rc = rtlogFileOpen(pLogger, pErrInfo);
+
+        /* Rotate in case of appending to a too big log file,
+           otherwise this simply doesn't do anything. */
+        rtlogRotate(pLogger, 0, true /* fFirst */, pErrInfo);
+    }
+    else
+    {
+        /* Force rotation if it is configured. */
+        pLogger->pInt->cbHistoryFileWritten = UINT64_MAX;
+        rtlogRotate(pLogger, 0, true /* fFirst */, pErrInfo);
+
+        /* If the file is not open then rotation is not set up. */
+        if (pLogger->pInt->hFile == NIL_RTFILE)
+        {
+            pLogger->pInt->cbHistoryFileWritten = 0;
+            rc = rtlogFileOpen(pLogger, pErrInfo);
+        }
+        else
+            rc = VINF_SUCCESS;
+    }
+    return rc;
+}
+
 #endif /* IN_RING3 */
 
 
 /**
  * Writes the buffer to the given log device without checking for buffered
  * data or anything.
+ *
  * Used by the RTLogFlush() function.
  *
  * @param   pLogger     The logger instance to write to. NULL is not allowed!
+ * @param   fNeedSpace  Set if the caller assumes space will be made available.
  */
-static void rtlogFlush(PRTLOGGER pLogger)
+static void rtlogFlush(PRTLOGGER pLogger, bool fNeedSpace)
 {
     uint32_t const cchScratch = pLogger->offScratch;
     if (cchScratch == 0)
         return; /* nothing to flush. */
+    NOREF(fNeedSpace);
 
 #ifndef IN_RC
     /*
@@ -3344,7 +3407,14 @@ static void rtlogFlush(PRTLOGGER pLogger)
         rtLogRingBufWrite(pLogger->pInt, pLogger->achScratch, pLogger->offScratch);
         pLogger->offScratch = 0; /* empty the buffer. */
     }
+    /*
+     * In file delay mode, we ignore flush requests except when we're full
+     * and the caller really needs some scratch space to get work done.
+     */
     else
+# ifdef IN_RING3
+        if (!(pLogger->fDestFlags & RTLOGDEST_F_DELAY_FILE))
+# endif
 #endif
     {
         /* Make sure the string is terminated.  On Windows, RTLogWriteDebugger
@@ -3406,9 +3476,32 @@ static void rtlogFlush(PRTLOGGER pLogger)
          */
         if (   (pLogger->fDestFlags & RTLOGDEST_FILE)
             && pLogger->pInt->cHistory)
-            rtlogRotate(pLogger, RTTimeProgramSecTS() / pLogger->pInt->cSecsHistoryTimeSlot, false /* fFirst */);
+            rtlogRotate(pLogger, RTTimeProgramSecTS() / pLogger->pInt->cSecsHistoryTimeSlot, false /*fFirst*/, NULL /*pErrInfo*/);
 #endif
     }
+#ifdef IN_RING3
+    else
+    {
+        /*
+         * Delay file open but the caller really need some space.  So, give him half a
+         * buffer and insert a message indicating that we've dropped output.
+         */
+        uint32_t offHalf = sizeof(pLogger->achScratch) / 2;
+        if (cchScratch > offHalf)
+        {
+            if (pLogger->fFlags & RTLOGFLAGS_USECRLF)
+                pLogger->achScratch[offHalf++] = '\r';
+            static const char s_szDropMsg[] = "\n[DROP DROP DROP]";
+            memcpy(&pLogger->achScratch[offHalf], RT_STR_TUPLE(s_szDropMsg));
+            offHalf += sizeof(s_szDropMsg) - 1;
+            if (pLogger->fFlags & RTLOGFLAGS_USECRLF)
+                pLogger->achScratch[offHalf++] = '\r';
+            pLogger->achScratch[offHalf++] = '\n';
+
+            pLogger->offScratch = offHalf;
+        }
+    }
+#endif
 }
 
 
@@ -3454,7 +3547,7 @@ static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t
             pachChars += cb;
 
             /* flush */
-            rtlogFlush(pLogger);
+            rtlogFlush(pLogger, true /*fNeedSpace*/);
         }
 
         /* won't ever get here! */
@@ -3551,7 +3644,7 @@ static DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars,
                  */
                 if (cb < 256 + 16)
                 {
-                    rtlogFlush(pLogger);
+                    rtlogFlush(pLogger, true /*fNeedSpace*/);
                     offScratch = pLogger->offScratch;
                     cb = sizeof(pLogger->achScratch) - offScratch - 1;
                 }
@@ -3849,7 +3942,7 @@ static DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars,
             }
             else if (cb <= 0)
             {
-                rtlogFlush(pLogger);
+                rtlogFlush(pLogger, true /*fNeedSpace*/);
                 offScratch = pLogger->offScratch;
                 cb = sizeof(pLogger->achScratch) - offScratch - 1;
             }
@@ -3952,7 +4045,7 @@ static void rtlogLoggerExVLocked(PRTLOGGER pLogger, unsigned fFlags, unsigned iG
         RTLogFormatV(rtLogOutput, pLogger, pszFormat, args);
     if (    !(pLogger->fFlags & RTLOGFLAGS_BUFFERED)
         &&  pLogger->offScratch)
-        rtlogFlush(pLogger);
+        rtlogFlush(pLogger, false /*fNeedSpace*/);
 }