]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Add the ability to direct logs etc. to a file or pipe.
authorMike Brady <mikebradydublin@icloud.com>
Thu, 28 May 2020 11:19:59 +0000 (12:19 +0100)
committerMike Brady <mikebradydublin@icloud.com>
Thu, 28 May 2020 11:19:59 +0000 (12:19 +0100)
common.c
common.h
scripts/shairport-sync.conf
shairport.c

index bb824ca68bb3fb3cfab581a587d0274b6a11f915..f10ef7bf70b79fc1b2752d3f2d271c15c6e6ab93 100644 (file)
--- a/common.c
+++ b/common.c
@@ -41,6 +41,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <libgen.h>
 
 #ifdef COMPILE_FOR_OSX
 #include <CoreServices/CoreServices.h>
@@ -139,8 +140,70 @@ void do_sps_log_to_stdout(__attribute__((unused)) int prio, const char *t, ...)
   fprintf(stdout, "%s\n", s);
 }
 
+int create_log_file(const char* path) {
+       int fd = -1;
+       if (path != NULL) {
+               char *dirc = strdup(path);
+               if (dirc) {
+                       char *dname = dirname(dirc);
+                       // create the directory, if necessary
+                       int result = 0;
+                       if (dname) {
+                               char *pdir = realpath(dname, NULL); // will return a NULL if the directory doesn't exist
+                               if (pdir == NULL) {
+                                       mode_t oldumask = umask(000);
+                                       result = mkpath(dname, 0777);
+                                       umask(oldumask);
+                               } else {
+                                       free(pdir);
+                               }
+                               if ((result == 0) || (result == -EEXIST)) {
+                                       // now open the file
+                                       fd = open(path, O_WRONLY | O_NONBLOCK | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+                                       if ((fd == -1) && (errno == EEXIST))
+                                               fd = open(path, O_WRONLY | O_APPEND | O_NONBLOCK);
+
+                                       if (fd >= 0) {
+                                               // now we switch to blocking mode
+                                               int flags = fcntl(fd, F_GETFL);
+                                               if ((flags == -1)) {
+//                                                     strerror_r(errno, (char *)errorstring, sizeof(errorstring));
+//                                                     debug(1, "create_log_file -- error %d (\"%s\") getting flags of pipe: \"%s\".", errno,
+//                                                                             (char *)errorstring, pathname);
+                                               } else {
+                                                       flags = fcntl(fd, F_SETFL,flags & ~O_NONBLOCK);
+//                                                     if (flags == -1) {
+//                                                             strerror_r(errno, (char *)errorstring, sizeof(errorstring));
+//                                                             debug(1, "create_log_file -- error %d (\"%s\") unsetting NONBLOCK of pipe: \"%s\".", errno,
+//                                                                                     (char *)errorstring, pathname);
+                                               }
+                                       }
+                               }
+                       }
+                       free(dirc);
+               }
+       }
+       return fd;
+}
+
+void do_sps_log_to_fd(__attribute__((unused)) int prio, const char *t, ...) {
+               char s[1024];
+               va_list args;
+               va_start(args, t);
+               vsnprintf(s, sizeof(s), t, args);
+               va_end(args);
+               if (config.log_fd == -1)
+                       config.log_fd = create_log_file(config.log_file_path);
+       if (config.log_fd >= 0) {
+               dprintf(config.log_fd, "%s\n", s);
+  } else if (errno != ENXIO) { // maybe there is a pipe there but not hooked up
+       fprintf(stderr, "%s\n", s);
+  }
+}
+
 void log_to_stderr() { sps_log = do_sps_log_to_stderr; }
 void log_to_stdout() { sps_log = do_sps_log_to_stdout; }
+void log_to_file() { sps_log = do_sps_log_to_fd; }
 void log_to_syslog() {
 #ifdef CONFIG_LIBDAEMON
        sps_log = daemon_log;
index df4243a9590cd69a30b867c14fd6decbc2d9482f..3540bcd074e11a36098566520a0c0d89130f1df1 100644 (file)
--- a/common.h
+++ b/common.h
@@ -182,6 +182,8 @@ typedef struct {
   char *pidfile;
 #endif
 
+       int     log_fd; // file descriptor of the file or pipe to log stuff to.
+       char *log_file_path; // path to file or pipe to log to, if any
   int logOutputLevel;              // log output level
   int debugger_show_elapsed_time;  // in the debug message, display the time since startup
   int debugger_show_relative_time; // in the debug message, display the time since the last one
@@ -298,6 +300,8 @@ void memory_barrier();
 void log_to_stderr(); // call this to direct logging to stderr;
 void log_to_stdout(); // call this to direct logging to stdout;
 void log_to_syslog(); // call this to direct logging to the system log;
+void log_to_file(); // call this to direct logging to a file or (pre-existing) pipe;
+
 
 
 // true if Shairport Sync is supposed to be sending output to the output device, false otherwise
index 1b6105cb40ffd32730e87bbbb4ddd9ee65f26811..efa349965fb3a2112c5e1f451b5089a01138dcd9 100644 (file)
@@ -245,7 +245,7 @@ mqtt =
 diagnostics =
 {
 //     disable_resend_requests = "no"; // set this to yes to stop Shairport Sync from requesting the retransmission of missing packets. Default is "no".
-//     log_output_to = "syslog"; // set this to "syslog" (default), "STDERR" or "STDOUT" to specify were all logs, statistics and diagnostic messages are written to.
+//     log_output_to = "syslog"; // set this to "syslog" (default), "stderr" or "stdout" or a file or pipe path to specify were all logs, statistics and diagnostic messages are written to. If there's anything wrong with the file spec, output will be to "stderr".
 //     statistics = "no"; // set to "yes" to print statistics in the log
 //     log_verbosity = 0; // "0" means no debug verbosity, "3" is most verbose.
 //     log_show_file_and_line = "yes"; // set this to yes if you want the file and line number of the message source in the log file
index fc1643ab00d6e4ea76d88c126b7af4bbc81f9454..af11ade286660e5b7fcae762936cf540558ec7cf 100644 (file)
@@ -671,8 +671,9 @@ int parse_options(int argc, char **argv) {
         } else if (strcasecmp(str, "stderr") == 0) {
           log_to_stderr();
         } else {
-               log_to_syslog();
-          die("Invalid diagnostics log_output_to setting \"%s\". It should be \"syslog\", \"STDERR\" or \"STDOUT\". It is set to syslog.");
+               config.log_file_path = (char *)str;
+               config.log_fd = -1;
+               log_to_file();
         }
       }
       /* Get the ignore_volume_control setting. */
@@ -1423,6 +1424,7 @@ int main(int argc, char **argv) {
 #ifdef CONFIG_LIBDAEMON
   pid = getpid();
 #endif
+       config.log_fd = -1;
   conns = NULL; // no connections active
   memset((void *)&main_thread_id, 0, sizeof(main_thread_id));
   memset(&config, 0, sizeof(config)); // also clears all strings, BTW