]> mj.ucw.cz Git - libucw.git/blobdiff - ucw/log-file.c
fb-grow: Renamed fbgrow_read_all() to fbgrow_get_buf().
[libucw.git] / ucw / log-file.c
index 65418a29d16d39de40a7d679a891dde3af50f8b3..efa0665f99bde467954390a085f267b6687e502c 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "ucw/lib.h"
 #include "ucw/log.h"
+#include "ucw/log-internal.h"
 #include "ucw/lfs.h"
 #include "ucw/threads.h"
 #include "ucw/simple-lists.h"
 #include <fcntl.h>
 #include <unistd.h>
 #include <time.h>
+#include <errno.h>
 
-/*
- *  Use of the private fields of struct log_stream:
- *
- *     idata   file descriptor
- *     udata   various flags (FF_xxx)
- *     pdata   original name with strftime escapes
- *     name    current name of the log file
- *             (a dynamically allocated buffer)
- */
-
-enum log_file_flag {
-  FF_FORMAT_NAME = 1,          // Name contains strftime escapes
-  FF_CLOSE_FD = 2,             // Close the fd with the stream
+struct file_stream {
+  struct log_stream ls;                // ls.name is the current name of the log file
+  int fd;
+  uns flags;                   // FF_xxx
+  char *orig_name;             // Original name with strftime escapes
 };
 
 #define MAX_EXPAND 64          // Maximum size of expansion of strftime escapes
@@ -40,41 +34,39 @@ enum log_file_flag {
 static int log_switch_nest;
 
 static void
-do_log_reopen(struct log_stream *ls, const char *name)
+do_log_reopen(struct file_stream *fs, const char *name)
 {
   int fd = ucw_open(name, O_WRONLY | O_CREAT | O_APPEND, 0666);
   if (fd < 0)
     die("Unable to open log file %s: %m", name);
-  if (ls->idata < 0)
-    ls->idata = fd;
-  else
+  if (fs->fd >= 0)
+    close(fs->fd);
+  fs->fd = fd;
+  if (fs->flags & FF_FD2_FOLLOWS)
+    dup2(fd, 2);
+  if (fs->ls.name)
     {
-      dup2(fd, ls->idata);
-      close(fd);
+      xfree(fs->ls.name);
+      fs->ls.name = NULL;      // We have to keep the stream consistent -- die() below can invoke logging
     }
-  if (ls->name)
-    {
-      xfree(ls->name);
-      ls->name = NULL;         // We have to keep this consistent, die() below can invoke logging
-    }
-  ls->name = xstrdup(name);
+  fs->ls.name = xstrdup(name);
 }
 
 static int
-do_log_switch(struct log_stream *ls, struct tm *tm)
+do_log_switch(struct file_stream *fs, struct tm *tm)
 {
-  if (!(ls->udata & FF_FORMAT_NAME))
+  if (!(fs->flags & FF_FORMAT_NAME))
     {
-      if (ls->idata >= 0)
+      if (fs->fd >= 0)
        return 1;
       else
        {
-         do_log_reopen(ls, ls->pdata);
+         do_log_reopen(fs, fs->orig_name);
          return 1;
        }
     }
 
-  int buflen = strlen(ls->pdata) + MAX_EXPAND;
+  int buflen = strlen(fs->orig_name) + MAX_EXPAND;
   char name[buflen];
   int switched = 0;
 
@@ -82,12 +74,12 @@ do_log_switch(struct log_stream *ls, struct tm *tm)
   if (!log_switch_nest)                // Avoid infinite loops if we die when switching logs
     {
       log_switch_nest++;
-      int l = strftime(name, buflen, ls->pdata, tm);
+      int l = strftime(name, buflen, fs->orig_name, tm);
       if (l < 0 || l >= buflen)
        die("Error formatting log file name: %m");
-      if (!ls->name || strcmp(name, ls->name))
+      if (!fs->ls.name || strcmp(name, fs->ls.name))
        {
-         do_log_reopen(ls, name);
+         do_log_reopen(fs, name);
          switched = 1;
        }
       log_switch_nest--;
@@ -96,55 +88,34 @@ do_log_switch(struct log_stream *ls, struct tm *tm)
   return switched;
 }
 
-/* Emulate the old single-file interface: close the existing log file and open a new one. */
-void
-log_file(const char *name)
-{
-  if (!name)
-    return;
-
-  struct log_stream *ls = log_new_file(name);
-  struct log_stream *def = log_stream_by_flags(0);
-  simp_node *s;
-  while (s = clist_head(&def->substreams))
-    {
-      struct log_stream *old = s->p;
-      log_rm_substream(def, old);
-      if (old != (struct log_stream *) &log_stream_default)
-       log_close_stream(old);
-    }
-  dup2(ls->idata, 2);                  // Let fd2 be an alias for the log file
-  log_add_substream(def, ls);
-}
-
-/* destructor for standard files */
 static void
 file_close(struct log_stream *ls)
 {
-  if ((ls->udata & FF_CLOSE_FD) && ls->idata >= 0)
-    close(ls->idata);
-  xfree(ls->name);
+  struct file_stream *fs = (struct file_stream *) ls;
+  if ((fs->flags & FF_CLOSE_FD) && fs->fd >= 0)
+    close(fs->fd);
+  xfree(fs->ls.name);
+  xfree(fs->orig_name);
 }
 
-/* handler for standard files */
 static int
 file_handler(struct log_stream *ls, struct log_msg *m)
 {
-  if ((ls->udata & FF_FORMAT_NAME) && m->tm)
-    do_log_switch(ls, m->tm);
+  struct file_stream *fs = (struct file_stream *) ls;
+  if ((fs->flags & FF_FORMAT_NAME) && m->tm)
+    do_log_switch(fs, m->tm);
 
-  int r = write(ls->idata, m->m, m->m_len);
-  /* FIXME: check for errors here? */
-  return 0;
+  int r = write(fs->fd, m->m, m->m_len);
+  return ((r < 0) ? errno : 0);
 }
 
-/* assign log to a file descriptor */
-/* initialize with the default formatting, does NOT close the descriptor */
 struct log_stream *
-log_new_fd(int fd)
+log_new_fd(int fd, uns flags)
 {
-  struct log_stream *ls = log_new_stream();
-  ls->idata = fd;
+  struct log_stream *ls = log_new_stream(sizeof(struct file_stream));
+  struct file_stream *fs = (struct file_stream *) ls;
+  fs->fd = fd;
+  fs->flags = flags;
   ls->msgfmt = LSFMT_DEFAULT;
   ls->handler = file_handler;
   ls->close = file_close;
@@ -153,17 +124,16 @@ log_new_fd(int fd)
   return ls;
 }
 
-/* open() a file (append mode) */
-/* initialize with the default formatting */
 struct log_stream *
-log_new_file(const char *path)
+log_new_file(const char *path, uns flags)
 {
-  struct log_stream *ls = log_new_stream();
-  ls->idata = -1;
-  ls->pdata = (void *) path;
+  struct log_stream *ls = log_new_stream(sizeof(struct file_stream));
+  struct file_stream *fs = (struct file_stream *) ls;
+  fs->fd = -1;
+  fs->orig_name = xstrdup(path);
   if (strchr(path, '%'))
-    ls->udata = FF_FORMAT_NAME;
-  ls->udata |= FF_CLOSE_FD;
+    fs->flags = FF_FORMAT_NAME;
+  fs->flags |= FF_CLOSE_FD | flags;
   ls->msgfmt = LSFMT_DEFAULT;
   ls->handler = file_handler;
   ls->close = file_close;
@@ -171,7 +141,7 @@ log_new_file(const char *path)
   time_t now = time(NULL);
   struct tm *tm = localtime(&now);
   ASSERT(tm);
-  do_log_switch(ls, tm);               // die()'s on errors
+  do_log_switch(fs, tm);               // die()'s on errors
   return ls;
 }
 
@@ -185,7 +155,7 @@ log_switch(void)
   int switched = 0;
   for (int i=0; i < log_streams_after; i++)
     if (log_streams.ptr[i]->handler == file_handler)
-      switched |= do_log_switch(log_streams.ptr[i], tm);
+      switched |= do_log_switch((struct file_stream *) log_streams.ptr[i], tm);
   return switched;
 }
 
@@ -202,16 +172,30 @@ log_switch_enable(void)
   log_switch_nest--;
 }
 
+void
+log_file(const char *name)
+{
+  if (!name)
+    return;
+
+  struct log_stream *ls = log_new_file(name, FF_FD2_FOLLOWS);
+  struct log_stream *def = log_stream_by_flags(0);
+  log_rm_substream(def, NULL);
+  log_add_substream(def, ls);
+  log_close_stream(ls);
+}
+
 #ifdef TEST
 
 int main(int argc, char **argv)
 {
   log_init(argv[0]);
   log_file("/proc/self/fd/1");
-  // struct log_stream *ls = log_new_fd(1);
-  // struct log_stream *ls = log_new_file("/tmp/quork-%Y%m%d-%H%M%S");
+  // struct log_stream *ls = log_new_fd(1, 0);
+  // struct log_stream *ls = log_new_file("/tmp/quork-%Y%m%d-%H%M%S", 0);
   for (int i=1; i<argc; i++)
     msg(L_INFO, argv[i]);
+  log_close_all();
   return 0;
 }