3 * tailing reliable realtime streaming feeder for inn
4 * help.c - logging and utility functions
6 * Copyright (C) 2010 Ian Jackson <ijackson@chiark.greenend.org.uk>
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * (I believe that when you compile and link this as part of the inn2
22 * build, with the Makefile runes I have provided, all the libraries
23 * and files which end up included in innduct are licence-compatible
24 * with GPLv3. If not then please let me know. -Ian Jackson.)
30 /* for logging, simulation, debugging, etc. */
31 int simulate_flush= -1;
33 const char *logv_prefix="";
35 /*========== logging ==========*/
37 static void logcore(int sysloglevel, const char *fmt, ...) PRINTF(2,3);
38 static void logcore(int sysloglevel, const char *fmt, ...) {
40 if (logv_use_syslog) {
41 vsyslog(sysloglevel,fmt,al);
43 if (self_pid) fprintf(stderr,"[%lu] ",(unsigned long)self_pid);
44 vfprintf(stderr,fmt,al);
50 void logv(int sysloglevel, const char *pfx, int errnoval,
51 const char *fmt, va_list al) {
52 char msgbuf[1024]; /* NB do not call mvasprintf here or you'll recurse */
53 vsnprintf(msgbuf,sizeof(msgbuf), fmt,al);
54 msgbuf[sizeof(msgbuf)-1]= 0;
56 if (sysloglevel >= LOG_ERR && (errnoval==EACCES || errnoval==EPERM))
57 sysloglevel= LOG_ERR; /* run by wrong user, probably */
59 logcore(sysloglevel, "%s%s: %s%s%s",
60 logv_prefix, pfx, msgbuf,
61 errnoval>=0 ? ": " : "",
62 errnoval>=0 ? strerror(errnoval) : "");
65 #define DEFFATAL(fn, pfx, sysloglevel, err, estatus) \
66 void fn(const char *fmt, ...) { \
69 logv(sysloglevel, pfx, err, fmt, al); \
73 #define DEFLOG(fn, pfx, sysloglevel, err) \
74 void fn(const char *fmt, ...) { \
76 logv(sysloglevel, pfx, err, fmt, al); \
80 #define INNLOGSET_DEFINE(fn, pfx, sysloglevel) \
81 void duct_log_##fn(int l, const char *fmt, va_list al, int errval) { \
82 logv(sysloglevel, pfx, errval ? errval : -1, fmt, al); \
86 /* We want to extend the set of logging functions from inn, and we
87 * want to prepend the site name to all our messages. */
89 DEFFATAL(syscrash, "critical", LOG_CRIT, errno, 16);
90 DEFFATAL(crash, "critical", LOG_CRIT, -1, 16);
92 INNLOGSETS(INNLOGSET_DEFINE)
94 DEFLOG(info, "info", LOG_INFO, -1)
95 DEFLOG(dbg, "debug", LOG_DEBUG, -1)
98 /*========== utility functions etc. ==========*/
100 char *mvasprintf(const char *fmt, va_list al) {
102 int rc= vasprintf(&str,fmt,al);
103 if (rc<0) sysdie("vasprintf(\"%s\",...) failed", fmt);
107 char *masprintf(const char *fmt, ...) {
109 char *str= mvasprintf(fmt,al);
114 int close_perhaps(int *fd) {
115 if (*fd <= 0) return 0;
120 void xclose(int fd, const char *what, const char *what2) {
122 if (r) syscrash("close %s%s",what,what2?what2:"");
124 void xclose_perhaps(int *fd, const char *what, const char *what2) {
125 if (*fd <= 0) return;
126 xclose(*fd,what,what2);
130 pid_t xfork_bare(const char *what) {
132 if (child==-1) sysdie("cannot fork for %s",what);
133 dbg("forked %s %ld", what, (unsigned long)child);
137 pid_t xfork(const char *what) {
138 pid_t child= xfork_bare(what);
139 if (!child) postfork();
143 void on_fd_read_except(int fd, oop_call_fd callback) {
144 loop->on_fd(loop, fd, OOP_READ, callback, 0);
145 loop->on_fd(loop, fd, OOP_EXCEPTION, callback, 0);
147 void cancel_fd_read_except(int fd) {
148 loop->cancel_fd(loop, fd, OOP_READ);
149 loop->cancel_fd(loop, fd, OOP_EXCEPTION);
152 void report_child_status(const char *what, int status) {
153 if (WIFEXITED(status)) {
154 int es= WEXITSTATUS(status);
156 warn("%s: child died with error exit status %d", what, es);
157 } else if (WIFSIGNALED(status)) {
158 int sig= WTERMSIG(status);
159 const char *sigstr= strsignal(sig);
160 const char *coredump= WCOREDUMP(status) ? " (core dumped)" : "";
162 warn("%s: child died due to fatal signal %s%s", what, sigstr, coredump);
164 warn("%s: child died due to unknown fatal signal %d%s",
165 what, sig, coredump);
167 warn("%s: child died with unknown wait status %d", what,status);
171 int xwaitpid(pid_t *pid, const char *what) {
174 int r= kill(*pid, SIGKILL);
175 if (r) syscrash("cannot kill %s child", what);
177 pid_t got= waitpid(*pid, &status, 0);
178 if (got==-1) syscrash("cannot reap %s child", what);
179 if (got==0) crash("cannot reap %s child", what);
186 void *zxmalloc(size_t sz) {
187 void *p= xmalloc(sz);
192 void xunlink(const char *path, const char *what) {
194 if (r) syscrash("can't unlink %s %s", path, what);
199 if (now==-1) syscrash("time(2) failed");
203 void xsigaction(int signo, const struct sigaction *sa) {
204 int r= sigaction(signo,sa,0);
205 if (r) syscrash("sigaction failed for \"%s\"", strsignal(signo));
207 void xsigsetdefault(int signo) {
209 memset(&sa,0,sizeof(sa));
210 sa.sa_handler= SIG_DFL;
211 xsigaction(signo,&sa);
213 void raise_default(int signo) {
214 xsigsetdefault(signo);
219 void xgettimeofday(struct timeval *tv_r) {
220 int r= gettimeofday(tv_r,0);
221 if (r) syscrash("gettimeofday(2) failed");
223 void xsetnonblock(int fd, int nonb) {
224 int errnoval= oop_fd_nonblock(fd, nonb);
225 if (errnoval) { errno= errnoval; syscrash("setnonblocking"); }
228 void check_isreg(const struct stat *stab, const char *path,
230 if (!S_ISREG(stab->st_mode))
231 crash("%s %s not a plain file (mode 0%lo)",
232 what, path, (unsigned long)stab->st_mode);
235 void xfstat(int fd, struct stat *stab_r, const char *what) {
236 int r= fstat(fd, stab_r);
237 if (r) syscrash("could not fstat %s", what);
240 void xfstat_isreg(int fd, struct stat *stab_r,
241 const char *path, const char *what) {
242 xfstat(fd, stab_r, what);
243 check_isreg(stab_r, path, what);
246 void xlstat_isreg(const char *path, struct stat *stab,
247 int *enoent_r /* 0 means ENOENT is fatal */,
249 int r= lstat(path, stab);
251 if (errno==ENOENT && enoent_r) { *enoent_r=1; return; }
252 syscrash("could not lstat %s %s", what, path);
254 if (enoent_r) *enoent_r= 0;
255 check_isreg(stab, path, what);
258 int samefile(const struct stat *a, const struct stat *b) {
259 assert(S_ISREG(a->st_mode));
260 assert(S_ISREG(b->st_mode));
261 return (a->st_ino == b->st_ino &&
262 a->st_dev == b->st_dev);
265 char *sanitise(const char *input, int len) {
266 static char sanibuf[100]; /* returns pointer to this buffer! */
268 const char *p= input;
269 const char *endp= len>=0 ? input+len : 0;
273 if (q > sanibuf+sizeof(sanibuf)-8) { strcpy(q,"'.."); break; }
274 int c= (!endp || p<endp) ? *p++ : 0;
275 if (!c) { *q++= '\''; *q=0; break; }
276 if (c>=' ' && c<=126 && c!='\\') { *q++= c; continue; }
277 sprintf(q,"\\x%02x",c);