Subject: Re: syslog_r (Re: CVS commit: src/lib/libc)
To: None <tech-userlevel@netbsd.org>
From: Christos Zoulas <christos@astron.com>
List: tech-userlevel
Date: 10/26/2006 19:18:12
In article <17728.58915.311144.117018@srapc2586.sra.co.jp>,
SODA Noriyuki  <soda@sra.co.jp> wrote:
>>> As I said elsewhere, I think it would useful for PAM modules and
>>> possibly other libraries.  There are times inside PAM modules where  
>>> one
>>> really wants to make a log entry, but can't be sure if openlog() has
>>> been called or what facility was used.
>
>> This is a reasonable justification.  
>
>And it matches with the Tru64's syslog_r() behavior:
>http://h30097.www3.hp.com/docs/base_doc/DOCUMENTATION/V51B_HTML/MAN/MAN3/1847____.HTM
>
>It does support floating point format too.
>
>On the other hand, syslog_r() on Tru64 is not async-signal-safe:
>
>http://h30097.www3.hp.com/docs/base_doc/DOCUMENTATION/V51_HTML/MAN/MAN4/0226____.HTM

So it is really trivial to make syslog_r async-signal-safe in our case.

First we add a flag in stdio.h:
Index: stdio.h
===================================================================
RCS file: /cvsroot/src/include/stdio.h,v
retrieving revision 1.64
diff -u -u -r1.64 stdio.h
--- stdio.h	10 May 2006 21:09:45 -0000	1.64
+++ stdio.h	26 Oct 2006 19:13:57 -0000
@@ -157,6 +157,7 @@
 #define	__SOFF	0x1000		/* set iff _offset is in fact correct */
 #define	__SMOD	0x2000		/* true => fgetln modified _p text */
 #define	__SALC	0x4000		/* allocate string space dynamically */
+#define	__SAFE	0x8000		/* don't call signal-unsafe functions */
 
 /*
  * The following three definitions are for ANSI C, which took them

Then we use it to avoid calling non-signal-safe functions in vfprintf():
Index: vfprintf.c
===================================================================
RCS file: /cvsroot/src/lib/libc/stdio/vfprintf.c,v
retrieving revision 1.50
diff -u -b -w -u -r1.50 vfprintf.c
--- vfprintf.c	16 Feb 2006 23:26:19 -0000	1.50
+++ vfprintf.c	26 Oct 2006 19:10:23 -0000
@@ -335,6 +335,10 @@
 	 */
 	for (;;) {
 		cp = fmt;
+		if (fp->_flags & __SAFE) {
+			for (; *fmt &&*fmt != '%'; fmt++)
+				continue;
+		} else {
 		while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
 			fmt += n;
 			if (wc == '%') {
@@ -342,6 +346,7 @@
 				break;
 			}
 		}
+		}
 		if ((m = fmt - cp) != 0) {
 			PRINT(cp, m);
 			ret += m;
@@ -493,7 +498,7 @@
 				size = 3;
 				break;
 			}
-			if (isnan(_double)) {
+			if ((fp->_flags & __SAFE) || isnan(_double)) {
 				if (ch == 'E' || ch == 'F' || ch == 'G')
 					cp = "NAN";
 				else

Finally we provide a snprintf_r() and a vsnprintf_r() [call them what you
wish] wrappers that look like the nor _r functions, but they only do:

	fp->_flags |= __SAFE;

Then we can use them in syslog_r(), and everything works as expected.
Well, floating point numbers print NaN, but...

Opinions?

christos