Busybox 1.21.0 squashed commit for jellybean

Change-Id: I423c7fc1254050c6495126b1b18dd33af07fed6b
Signed-off-by: Tanguy Pruvot <tanguy.pruvot@gmail.com>
diff --git a/sysklogd/Config.src b/sysklogd/Config.src
index b7a494e..fcf9930 100644
--- a/sysklogd/Config.src
+++ b/sysklogd/Config.src
@@ -113,6 +113,19 @@
 	  from circular buffer, minimizing semaphore
 	  contention at some minor memory expense.
 
+config FEATURE_KMSG_SYSLOG
+	bool "Linux kernel printk buffer support"
+	default y
+	depends on SYSLOGD
+	select PLATFORM_LINUX
+	help
+	  When you enable this feature, the syslogd utility will
+	  write system log message to the Linux kernel's printk buffer.
+	  This can be used as a smaller alternative to the syslogd IPC
+	  support, as klogd and logread aren't needed.
+
+	  NOTICE: Syslog facilities in log entries needs kernel 3.5+.
+
 config KLOGD
 	bool "klogd"
 	default y
@@ -123,6 +136,9 @@
 	  you wish to record the messages produced by the kernel,
 	  you should enable this option.
 
+comment "klogd should not be used together with syslog to kernel printk buffer"
+	depends on KLOGD && FEATURE_KMSG_SYSLOG
+
 config FEATURE_KLOGD_KLOGCTL
 	bool "Use the klogctl() interface"
 	default y
diff --git a/sysklogd/klogd.c b/sysklogd/klogd.c
index efa0e53..432ded1 100644
--- a/sysklogd/klogd.c
+++ b/sysklogd/klogd.c
@@ -195,6 +195,8 @@
 
 	syslog(LOG_NOTICE, "klogd started: %s", bb_banner);
 
+	write_pidfile(CONFIG_PID_FILE_PATH "/klogd.pid");
+
 	used = 0;
 	while (!bb_got_signal) {
 		int n;
@@ -238,11 +240,8 @@
 			priority = LOG_INFO;
 			if (*start == '<') {
 				start++;
-				if (*start) {
-					/* kernel never generates multi-digit prios */
-					priority = (*start - '0');
-					start++;
-				}
+				if (*start)
+					priority = strtoul(start, &start, 10);
 				if (*start == '>')
 					start++;
 			}
@@ -258,6 +257,7 @@
 
 	klogd_close();
 	syslog(LOG_NOTICE, "klogd: exiting");
+	remove_pidfile(CONFIG_PID_FILE_PATH "/klogd.pid");
 	if (bb_got_signal)
 		kill_myself_with_sig(bb_got_signal);
 	return EXIT_FAILURE;
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c
index fc380d9..3fe3f53 100644
--- a/sysklogd/syslogd.c
+++ b/sysklogd/syslogd.c
@@ -43,6 +43,9 @@
 //usage:     "\n	-f FILE		Use FILE as config (default:/etc/syslog.conf)"
 //usage:	)
 /* //usage:  "\n	-m MIN		Minutes between MARK lines (default:20, 0=off)" */
+//usage:	IF_FEATURE_KMSG_SYSLOG(
+//usage:     "\n	-K		Log to kernel printk buffer (use dmesg to read it)"
+//usage:	)
 //usage:
 //usage:#define syslogd_example_usage
 //usage:       "$ syslogd -R masterlog:514\n"
@@ -140,6 +143,10 @@
 ) \
 IF_FEATURE_SYSLOGD_CFG( \
 	logRule_t *log_rules; \
+) \
+IF_FEATURE_KMSG_SYSLOG( \
+	int kmsgfd; \
+	int primask; \
 )
 
 struct init_globals {
@@ -212,6 +219,7 @@
 	IF_FEATURE_IPC_SYSLOG(    OPTBIT_circularlog,)	// -C
 	IF_FEATURE_SYSLOGD_DUP(   OPTBIT_dup        ,)	// -D
 	IF_FEATURE_SYSLOGD_CFG(   OPTBIT_cfg        ,)	// -f
+	IF_FEATURE_KMSG_SYSLOG(   OPTBIT_kmsg       ,)	// -K
 
 	OPT_mark        = 1 << OPTBIT_mark    ,
 	OPT_nofork      = 1 << OPTBIT_nofork  ,
@@ -225,6 +233,8 @@
 	OPT_circularlog = IF_FEATURE_IPC_SYSLOG(    (1 << OPTBIT_circularlog)) + 0,
 	OPT_dup         = IF_FEATURE_SYSLOGD_DUP(   (1 << OPTBIT_dup        )) + 0,
 	OPT_cfg         = IF_FEATURE_SYSLOGD_CFG(   (1 << OPTBIT_cfg        )) + 0,
+	OPT_kmsg        = IF_FEATURE_KMSG_SYSLOG(   (1 << OPTBIT_kmsg       )) + 0,
+
 };
 #define OPTION_STR "m:nO:l:S" \
 	IF_FEATURE_ROTATE_LOGFILE("s:" ) \
@@ -233,7 +243,8 @@
 	IF_FEATURE_REMOTE_LOG(    "L"  ) \
 	IF_FEATURE_IPC_SYSLOG(    "C::") \
 	IF_FEATURE_SYSLOGD_DUP(   "D"  ) \
-	IF_FEATURE_SYSLOGD_CFG(   "f:"  )
+	IF_FEATURE_SYSLOGD_CFG(   "f:" ) \
+	IF_FEATURE_KMSG_SYSLOG(   "K"  )
 #define OPTION_DECL *opt_m, *opt_l \
 	IF_FEATURE_ROTATE_LOGFILE(,*opt_s) \
 	IF_FEATURE_ROTATE_LOGFILE(,*opt_b) \
@@ -242,7 +253,7 @@
 #define OPTION_PARAM &opt_m, &(G.logFile.path), &opt_l \
 	IF_FEATURE_ROTATE_LOGFILE(,&opt_s) \
 	IF_FEATURE_ROTATE_LOGFILE(,&opt_b) \
-	IF_FEATURE_REMOTE_LOG(	  ,&remoteAddrList) \
+	IF_FEATURE_REMOTE_LOG(    ,&remoteAddrList) \
 	IF_FEATURE_IPC_SYSLOG(    ,&opt_C) \
 	IF_FEATURE_SYSLOGD_CFG(   ,&opt_f)
 
@@ -418,7 +429,9 @@
 	return;
 
  cfgerr:
-	bb_error_msg_and_die("error in '%s' at line %d", file, parser->lineno);
+	bb_error_msg_and_die("error in '%s' at line %d",
+			file ? file : "/etc/syslog.conf",
+			parser->lineno);
 }
 #endif
 
@@ -518,11 +531,49 @@
 		printf("tail:%d\n", G.shbuf->tail);
 }
 #else
-void ipcsyslog_cleanup(void);
-void ipcsyslog_init(void);
+static void ipcsyslog_cleanup(void) {}
+static void ipcsyslog_init(void) {}
 void log_to_shmem(const char *msg);
 #endif /* FEATURE_IPC_SYSLOG */
 
+#if ENABLE_FEATURE_KMSG_SYSLOG
+static void kmsg_init(void)
+{
+	G.kmsgfd = xopen("/dev/kmsg", O_WRONLY);
+
+	/*
+	 * kernel < 3.5 expects single char printk KERN_* priority prefix,
+	 * from 3.5 onwards the full syslog facility/priority format is supported
+	 */
+	if (get_linux_version_code() < KERNEL_VERSION(3,5,0))
+		G.primask = LOG_PRIMASK;
+	else
+		G.primask = -1;
+}
+
+static void kmsg_cleanup(void)
+{
+	if (ENABLE_FEATURE_CLEAN_UP)
+		close(G.kmsgfd);
+}
+
+/* Write message to /dev/kmsg */
+static void log_to_kmsg(int pri, const char *msg)
+{
+	/*
+	 * kernel < 3.5 expects single char printk KERN_* priority prefix,
+	 * from 3.5 onwards the full syslog facility/priority format is supported
+	 */
+	pri &= G.primask;
+
+	write(G.kmsgfd, G.printbuf, sprintf(G.printbuf, "<%d>%s\n", pri, msg));
+}
+#else
+static void kmsg_init(void) {}
+static void kmsg_cleanup(void) {}
+static void log_to_kmsg(int pri UNUSED_PARAM, const char *msg UNUSED_PARAM) {}
+#endif /* FEATURE_KMSG_SYSLOG */
+
 /* Print a message to the log file. */
 static void log_locally(time_t now, char *msg, logFile_t *log_file)
 {
@@ -657,6 +708,11 @@
 	}
 	timestamp[15] = '\0';
 
+	if (option_mask32 & OPT_kmsg) {
+		log_to_kmsg(pri, msg);
+		return;
+	}
+
 	if (option_mask32 & OPT_small)
 		sprintf(G.printbuf, "%s %s\n", timestamp, msg);
 	else {
@@ -827,9 +883,11 @@
 #endif
 	sock_fd = create_socket();
 
-	if (ENABLE_FEATURE_IPC_SYSLOG && (option_mask32 & OPT_circularlog)) {
+	if (option_mask32 & OPT_circularlog)
 		ipcsyslog_init();
-	}
+
+	if (option_mask32 & OPT_kmsg)
+		kmsg_init();
 
 	timestamp_and_log_internal("syslogd started: BusyBox v" BB_VER);
 
@@ -916,8 +974,10 @@
 
 	timestamp_and_log_internal("syslogd exiting");
 	puts("syslogd exiting");
-	if (ENABLE_FEATURE_IPC_SYSLOG)
-		ipcsyslog_cleanup();
+	remove_pidfile(CONFIG_PID_FILE_PATH "/syslogd.pid");
+	ipcsyslog_cleanup();
+	if (option_mask32 & OPT_kmsg)
+		kmsg_cleanup();
 	kill_myself_with_sig(bb_got_signal);
 #undef recvbuf
 }
@@ -979,8 +1039,10 @@
 	if (!(opts & OPT_nofork)) {
 		bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
 	}
+
 	//umask(0); - why??
-	write_pidfile("/var/run/syslogd.pid");
+	write_pidfile(CONFIG_PID_FILE_PATH "/syslogd.pid");
+
 	do_syslogd();
 	/* return EXIT_SUCCESS; */
 }