]> git.sur5r.net Git - i3/i3/blobdiff - src/log.c
fix formatting in get_process_filename.c
[i3/i3] / src / log.c
index d6f277f2f2bc3a54f2150e79807e4ab23c66f627..42e714ef0bcee0f65445a557c15f7019d5453707 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -1,3 +1,5 @@
+#undef I3__FILE__
+#define I3__FILE__ "log.c"
 /*
  * vim:ts=4:sw=4:expandtab
  *
@@ -18,6 +20,7 @@
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <pthread.h>
 #if defined(__APPLE__)
 #include <sys/types.h>
 #include <sys/sysctl.h>
@@ -46,6 +49,8 @@ int shmlog_size = 0;
 static char *logbuffer;
 /* A pointer (within logbuffer) where data will be written to next. */
 static char *logwalk;
+/* A pointer to the shmlog header */
+static i3_shmlog_header *header;
 /* A pointer to the byte where we last wrapped. Necessary to not print the
  * left-overs at the end of the ringbuffer. */
 static char *loglastwrap;
@@ -61,8 +66,6 @@ static int logbuffer_shm;
  *
  */
 static void store_log_markers(void) {
-    i3_shmlog_header *header = (i3_shmlog_header*)logbuffer;
-
     header->offset_next_write = (logwalk - logbuffer);
     header->offset_last_wrap = (loglastwrap - logbuffer);
     header->size = logbuffer_size;
@@ -105,7 +108,7 @@ void init_logging(void) {
 #endif
         logbuffer_size = min(physical_mem_bytes * 0.01, shmlog_size);
         sasprintf(&shmlogname, "/i3-log-%d", getpid());
-        logbuffer_shm = shm_open(shmlogname, O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
+        logbuffer_shm = shm_open(shmlogname, O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
         if (logbuffer_shm == -1) {
             ELOG("Could not shm_open SHM segment for the i3 log: %s\n", strerror(errno));
             return;
@@ -126,10 +129,23 @@ void init_logging(void) {
             logbuffer = NULL;
             return;
         }
+
+        /* Initialize with 0-bytes, just to be sureā€¦ */
+        memset(logbuffer, '\0', logbuffer_size);
+
+        header = (i3_shmlog_header*)logbuffer;
+
+        pthread_condattr_t cond_attr;
+        pthread_condattr_init(&cond_attr);
+        if (pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED) != 0)
+            ELOG("pthread_condattr_setpshared() failed, i3-dump-log -f will not work!\n");
+        pthread_cond_init(&(header->condvar), &cond_attr);
+
         logwalk = logbuffer + sizeof(i3_shmlog_header);
         loglastwrap = logbuffer + logbuffer_size;
         store_log_markers();
     }
+    atexit(purge_zerobyte_logfile);
 }
 
 /*
@@ -196,22 +212,25 @@ static void vlog(const bool print, const char *fmt, va_list args) {
             fprintf(stderr, "BUG: single log message > 4k\n");
         }
 
-        /* If there is no space for the current message (plus trailing
-         * nullbyte) in the ringbuffer, we need to wrap and write to the
-         * beginning again. */
-        if ((len+1) >= (logbuffer_size - (logwalk - logbuffer))) {
+        /* If there is no space for the current message in the ringbuffer, we
+         * need to wrap and write to the beginning again. */
+        if (len >= (logbuffer_size - (logwalk - logbuffer))) {
             loglastwrap = logwalk;
             logwalk = logbuffer + sizeof(i3_shmlog_header);
+            store_log_markers();
+            header->wrap_count++;
         }
 
-        /* Copy the buffer, terminate it, move the write pointer to the byte after
-         * our current message. */
+        /* Copy the buffer, move the write pointer to the byte after our
+         * current message. */
         strncpy(logwalk, message, len);
-        logwalk[len] = '\0';
-        logwalk += len + 1;
+        logwalk += len;
 
         store_log_markers();
 
+        /* Wake up all (i3-dump-log) processes waiting for condvar. */
+        pthread_cond_broadcast(&(header->condvar));
+
         if (print)
             fwrite(message, len, 1, stdout);
     }
@@ -267,3 +286,30 @@ void debuglog(char *fmt, ...) {
     vlog(debug_logging, fmt, args);
     va_end(args);
 }
+
+/*
+ * Deletes the unused log files. Useful if i3 exits immediately, eg.
+ * because --get-socketpath was called. We don't care for syscall
+ * failures. This function is invoked automatically when exiting.
+ */
+void purge_zerobyte_logfile(void) {
+    struct stat st;
+    char *slash;
+
+    if (!errorfilename)
+        return;
+
+    /* don't delete the log file if it contains something */
+    if ((stat(errorfilename, &st)) == -1 || st.st_size > 0)
+        return;
+
+    if (unlink(errorfilename) == -1)
+        return;
+
+    if ((slash = strrchr(errorfilename, '/')) != NULL) {
+        *slash = '\0';
+        /* possibly fails with ENOTEMPTY if there are files (or
+         * sockets) left. */
+        rmdir(errorfilename);
+    }
+}