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