cli: Introduce a logfile command to log errors to a file

The evolution would be to introduce libosmocore and start using
the logging framework. But even then we can map this option to
the file target.

Fixes: SYS#263
diff --git a/ggsn/cmdline.c b/ggsn/cmdline.c
index a84e7e8..3fcfbd5 100644
--- a/ggsn/cmdline.c
+++ b/ggsn/cmdline.c
@@ -52,6 +52,7 @@
   "      --timelimit=INT    Exit after timelimit seconds  (default=`0')",
   "  -a, --apn=STRING       Access point name  (default=`internet')",
   "  -q, --qos=INT          Requested quality of service  (default=`0x0b921f')",
+  "      --logfile=STRING   Logfile for errors",
     0
 };
 
@@ -119,6 +120,7 @@
   args_info->timelimit_given = 0 ;
   args_info->apn_given = 0 ;
   args_info->qos_given = 0 ;
+  args_info->logfile_given = 0 ;
 }
 
 static
@@ -155,6 +157,8 @@
   args_info->apn_orig = NULL;
   args_info->qos_arg = 0x0b921f;
   args_info->qos_orig = NULL;
+  args_info->logfile_arg = NULL;
+  args_info->logfile_orig = NULL;
   
 }
 
@@ -181,6 +185,7 @@
   args_info->timelimit_help = gengetopt_args_info_help[15] ;
   args_info->apn_help = gengetopt_args_info_help[16] ;
   args_info->qos_help = gengetopt_args_info_help[17] ;
+  args_info->logfile_help = gengetopt_args_info_help[18] ;
   
 }
 
@@ -290,6 +295,8 @@
   free_string_field (&(args_info->apn_arg));
   free_string_field (&(args_info->apn_orig));
   free_string_field (&(args_info->qos_orig));
+  free_string_field (&(args_info->logfile_arg));
+  free_string_field (&(args_info->logfile_orig));
   
   
 
@@ -356,6 +363,8 @@
     write_into_file(outfile, "apn", args_info->apn_orig, 0);
   if (args_info->qos_given)
     write_into_file(outfile, "qos", args_info->qos_orig, 0);
+  if (args_info->logfile_given)
+    write_into_file(outfile, "logfile", args_info->logfile_orig, 0);
   
 
   i = EXIT_SUCCESS;
@@ -626,6 +635,7 @@
         { "timelimit",	1, NULL, 0 },
         { "apn",	1, NULL, 'a' },
         { "qos",	1, NULL, 'q' },
+        { "logfile",	1, NULL, 0 },
         { 0,  0, 0, 0 }
       };
 
@@ -853,6 +863,20 @@
               goto failure;
           
           }
+          /* Logfile for errors.  */
+          else if (strcmp (long_options[option_index].name, "logfile") == 0)
+          {
+          
+          
+            if (update_arg( (void *)&(args_info->logfile_arg), 
+                 &(args_info->logfile_orig), &(args_info->logfile_given),
+                &(local_args_info.logfile_given), optarg, 0, 0, ARG_STRING,
+                check_ambiguity, override, 0, 0,
+                "logfile", '-',
+                additional_error))
+              goto failure;
+          
+          }
           
           break;
         case '?':	/* Invalid option.  */
diff --git a/ggsn/cmdline.ggo b/ggsn/cmdline.ggo
index e7e0f66..5bb05dc 100644
--- a/ggsn/cmdline.ggo
+++ b/ggsn/cmdline.ggo
@@ -31,5 +31,5 @@
 
 option  "apn"         a "Access point name"             string default="internet" no
 option  "qos"         q "Requested quality of service"  int    default="0x0b921f" no
-
+option  "logfile"     - "Logfile for errors"            string no
 
diff --git a/ggsn/cmdline.h b/ggsn/cmdline.h
index 1ce222e..f3636e8 100644
--- a/ggsn/cmdline.h
+++ b/ggsn/cmdline.h
@@ -89,6 +89,9 @@
   int qos_arg;	/**< @brief Requested quality of service (default='0x0b921f').  */
   char * qos_orig;	/**< @brief Requested quality of service original value given at command line.  */
   const char *qos_help; /**< @brief Requested quality of service help description.  */
+  char * logfile_arg;	/**< @brief Logfile for errors.  */
+  char * logfile_orig;	/**< @brief Logfile for errors original value given at command line.  */
+  const char *logfile_help; /**< @brief Logfile for errors help description.  */
   
   unsigned int help_given ;	/**< @brief Whether help was given.  */
   unsigned int version_given ;	/**< @brief Whether version was given.  */
@@ -108,6 +111,7 @@
   unsigned int timelimit_given ;	/**< @brief Whether timelimit was given.  */
   unsigned int apn_given ;	/**< @brief Whether apn was given.  */
   unsigned int qos_given ;	/**< @brief Whether qos was given.  */
+  unsigned int logfile_given ;	/**< @brief Whether logfile was given.  */
 
 } ;
 
diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c
index 1152519..0022b1b 100644
--- a/ggsn/ggsn.c
+++ b/ggsn/ggsn.c
@@ -283,6 +283,18 @@
 	if (cmdline_parser_configfile(args_info.conf_arg, &args_info, 0, 0, 0)
 	    != 0)
 		exit(1);
+
+	/* Open a log file */
+	if (args_info.logfile_arg) {
+		FILE* log_file = fopen(args_info.logfile_arg, "a");
+		if (!log_file) {
+			printf("Failed to open logfile: '%s'\n",
+				args_info.logfile_arg);
+			exit(1);
+		}
+		sys_err_setlogfile(log_file);
+	}
+
 	if (args_info.debug_flag) {
 		printf("cmdline_parser_configfile\n");
 		printf("listen: %s\n", args_info.listen_arg);
diff --git a/lib/syserr.c b/lib/syserr.c
index 048cd45..66a2067 100644
--- a/lib/syserr.c
+++ b/lib/syserr.c
@@ -20,6 +20,13 @@
 
 #include "syserr.h"
 
+static FILE* err_log;
+
+void sys_err_setlogfile(FILE* log)
+{
+	err_log = log;
+}
+
 void sys_err(int pri, char *fn, int ln, int en, char *fmt, ...)
 {
 	va_list args;
@@ -29,11 +36,17 @@
 	vsnprintf(buf, SYSERR_MSGSIZE, fmt, args);
 	va_end(args);
 	buf[SYSERR_MSGSIZE - 1] = 0;	/* Make sure it is null terminated */
-	if (en)
+	if (en) {
+		if (err_log)
+			fprintf(err_log, "%s: %d: %d (%s) %s\n",
+				fn, ln, en, strerror(en), buf);
 		syslog(pri, "%s: %d: %d (%s) %s", fn, ln, en, strerror(en),
 		       buf);
-	else
+	} else {
+		if (err_log)
+			fprintf(err_log, "%s: %d: %s\n", fn, ln, buf);
 		syslog(pri, "%s: %d: %s", fn, ln, buf);
+	}
 }
 
 void sys_errpack(int pri, char *fn, int ln, int en, struct sockaddr_in *peer,
@@ -65,10 +78,16 @@
 	}
 	buf2[pos] = 0;
 
-	if (en)
+	if (en) {
+		if (err_log)
+			fprintf(err_log, "%s: %d: %d (%s) %s. %s\n",
+				fn, ln, en, strerror(en), buf, buf2);
 		syslog(pri, "%s: %d: %d (%s) %s. %s", fn, ln, en, strerror(en),
 		       buf, buf2);
-	else
+	} else {
+		if (err_log)
+			fprintf(err_log, "%s: %d: %s. %s\n", fn, ln, buf, buf2);
 		syslog(pri, "%s: %d: %s. %s", fn, ln, buf, buf2);
+	}
 
 }
diff --git a/lib/syserr.h b/lib/syserr.h
index e3ebdf0..a65dfc3 100644
--- a/lib/syserr.h
+++ b/lib/syserr.h
@@ -14,6 +14,8 @@
 
 #define SYSERR_MSGSIZE 256
 
+void sys_err_setlogfile(FILE*);
+
 void sys_err(int pri, char *filename, int en, int line, char *fmt, ...);
 void sys_errpack(int pri, char *fn, int ln, int en, struct sockaddr_in *peer,
 		 void *pack, unsigned len, char *fmt, ...);