1 #include <errno.h>
2 #include <stdarg.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <syslog.h>
7 
8 #include "warnp.h"
9 
10 static int initialized = 0;
11 static char * name = NULL;
12 static int use_syslog = 0;
13 static int syslog_priority = LOG_WARNING;
14 
15 /* Free the name string and clean up writing to the syslog (if applicable). */
16 static void
done(void)17 done(void)
18 {
19 
20 	/* Clean up writing to the syslog (if applicable).  */
21 	if (use_syslog)
22 		closelog();
23 
24 	free(name);
25 	name = NULL;
26 }
27 
28 /**
29  * warnp_setprogname(progname):
30  * Set the program name to be used by warn() and warnx() to ${progname}.
31  */
32 void
warnp_setprogname(const char * progname)33 warnp_setprogname(const char * progname)
34 {
35 	const char * p;
36 
37 	/* Free the name if we already have one. */
38 	free(name);
39 
40 	/* Find the last segment of the program name. */
41 	for (p = progname; progname[0] != '\0'; progname++)
42 		if (progname[0] == '/')
43 			p = progname + 1;
44 
45 	/* Copy the name string. */
46 	name = strdup(p);
47 
48 	/* If we haven't already done so, register our exit handler. */
49 	if (initialized == 0) {
50 		atexit(done);
51 		initialized = 1;
52 	}
53 }
54 
55 void
warn(const char * fmt,...)56 warn(const char * fmt, ...)
57 {
58 	va_list ap;
59 	char msgbuf[WARNP_SYSLOG_MAX_LINE + 1];
60 
61 	va_start(ap, fmt);
62 	if (use_syslog == 0) {
63 		/* Stop other threads writing to stderr. */
64 		flockfile(stderr);
65 
66 		/* Print to stderr. */
67 		fprintf(stderr, "%s", (name != NULL) ? name : "(unknown)");
68 		if (fmt != NULL) {
69 			fprintf(stderr, ": ");
70 			vfprintf(stderr, fmt, ap);
71 		}
72 		fprintf(stderr, ": %s\n", strerror(errno));
73 
74 		/* Allow other threads to write to stderr. */
75 		funlockfile(stderr);
76 	} else {
77 		/* Print to syslog. */
78 		if (fmt != NULL) {
79 			/* No need to print "${name}: "; syslog does it. */
80 			vsnprintf(msgbuf, WARNP_SYSLOG_MAX_LINE + 1, fmt, ap);
81 			syslog(syslog_priority, "%s: %s\n", msgbuf,
82 			    strerror(errno));
83 		} else
84 			syslog(syslog_priority, "%s\n", strerror(errno));
85 	}
86 	va_end(ap);
87 }
88 
89 void
warnx(const char * fmt,...)90 warnx(const char * fmt, ...)
91 {
92 	va_list ap;
93 	char msgbuf[WARNP_SYSLOG_MAX_LINE + 1];
94 
95 	va_start(ap, fmt);
96 	if (use_syslog == 0) {
97 		/* Stop other threads writing to stderr. */
98 		flockfile(stderr);
99 
100 		/* Print to stderr. */
101 		fprintf(stderr, "%s", (name != NULL) ? name : "(unknown)");
102 		if (fmt != NULL) {
103 			fprintf(stderr, ": ");
104 			vfprintf(stderr, fmt, ap);
105 		}
106 		fprintf(stderr, "\n");
107 
108 		/* Allow other threads to write to stderr. */
109 		funlockfile(stderr);
110 	} else {
111 		/* Print to syslog. */
112 		if (fmt != NULL) {
113 			/* No need to print "${name}: "; syslog does it. */
114 			vsnprintf(msgbuf, WARNP_SYSLOG_MAX_LINE + 1, fmt, ap);
115 			syslog(syslog_priority, "%s\n", msgbuf);
116 		} else
117 			syslog(syslog_priority, "\n");
118 	}
119 	va_end(ap);
120 }
121 
122 /**
123  * warnp_syslog(enable):
124  * Send future messages to syslog if ${enable} is non-zero.  Messages to
125  * syslog will be truncated at WARNP_SYSLOG_MAX_LINE characters.
126  */
127 void
warnp_syslog(int enable)128 warnp_syslog(int enable)
129 {
130 
131 	/* Clean up writing to the syslog (if applicable).  */
132 	if (use_syslog && !enable)
133 		closelog();
134 
135 	use_syslog = enable;
136 }
137 
138 /**
139  * warnp_syslog_priority(priority):
140  * Tag future syslog messages with priority ${priority}.  Do not enable
141  * syslog messages; for that, use warnp_syslog().
142  */
143 void
warnp_syslog_priority(int priority)144 warnp_syslog_priority(int priority)
145 {
146 
147 	syslog_priority = priority;
148 }
149