3 * tailing reliable realtime streaming feeder for inn
4 * help.c - logging and utility functions
6 * Copyright Ian Jackson <ijackson@chiark.greenend.org.uk>
7 * and contributors; see LICENCE.txt.
8 * SPDX-License-Identifier: GPL-3.0-or-later
14 /* for logging, simulation, debugging, etc. */
15 int simulate_flush= -1;
17 const char *logv_prefix="";
19 /*========== logging ==========*/
21 static void logcore(int sysloglevel, const char *fmt, ...) PRINTF(2,3);
22 static void logcore(int sysloglevel, const char *fmt, ...) {
24 if (logv_use_syslog) {
25 vsyslog(sysloglevel,fmt,al);
27 if (self_pid) fprintf(stderr,"[%lu] ",(unsigned long)self_pid);
28 vfprintf(stderr,fmt,al);
34 void logv(int sysloglevel, const char *pfx, int errnoval,
35 const char *fmt, va_list al) {
36 char msgbuf[1024]; /* NB do not call mvasprintf here or you'll recurse */
37 vsnprintf(msgbuf,sizeof(msgbuf), fmt,al);
38 msgbuf[sizeof(msgbuf)-1]= 0;
40 if (sysloglevel >= LOG_ERR && (errnoval==EACCES || errnoval==EPERM))
41 sysloglevel= LOG_ERR; /* run by wrong user, probably */
43 logcore(sysloglevel, "%s%s: %s%s%s",
44 logv_prefix, pfx, msgbuf,
45 errnoval>=0 ? ": " : "",
46 errnoval>=0 ? strerror(errnoval) : "");
49 #define DEFFATAL(fn, pfx, sysloglevel, err, estatus) \
50 void fn(const char *fmt, ...) { \
53 logv(sysloglevel, pfx, err, fmt, al); \
57 #define DEFLOG(fn, pfx, sysloglevel, err) \
58 void fn(const char *fmt, ...) { \
60 logv(sysloglevel, pfx, err, fmt, al); \
64 #define INNLOGSET_DEFINE(fn, pfx, sysloglevel) \
65 void duct_log_##fn(int l, const char *fmt, va_list al, int errval) { \
66 logv(sysloglevel, pfx, errval ? errval : -1, fmt, al); \
70 /* We want to extend the set of logging functions from inn, and we
71 * want to prepend the site name to all our messages. */
73 DEFFATAL(syscrash, "critical", LOG_CRIT, errno, 16);
74 DEFFATAL(crash, "critical", LOG_CRIT, -1, 16);
76 INNLOGSETS(INNLOGSET_DEFINE)
78 DEFLOG(info, "info", LOG_INFO, -1)
79 DEFLOG(dbg, "debug", LOG_DEBUG, -1)
82 /*========== utility functions etc. ==========*/
84 char *mvasprintf(const char *fmt, va_list al) {
86 int rc= vasprintf(&str,fmt,al);
87 if (rc<0) sysdie("vasprintf(\"%s\",...) failed", fmt);
91 char *masprintf(const char *fmt, ...) {
93 char *str= mvasprintf(fmt,al);
98 int close_perhaps(int *fd) {
99 if (*fd <= 0) return 0;
104 void xclose(int fd, const char *what, const char *what2) {
106 if (r) syscrash("close %s%s",what,what2?what2:"");
108 void xclose_perhaps(int *fd, const char *what, const char *what2) {
109 if (*fd <= 0) return;
110 xclose(*fd,what,what2);
114 pid_t xfork_bare(const char *what) {
116 if (child==-1) sysdie("cannot fork for %s",what);
117 dbg("forked %s %ld", what, (unsigned long)child);
121 pid_t xfork(const char *what) {
122 pid_t child= xfork_bare(what);
123 if (!child) postfork();
127 void on_fd_read_except(int fd, oop_call_fd callback) {
128 loop->on_fd(loop, fd, OOP_READ, callback, 0);
129 loop->on_fd(loop, fd, OOP_EXCEPTION, callback, 0);
131 void cancel_fd_read_except(int fd) {
132 loop->cancel_fd(loop, fd, OOP_READ);
133 loop->cancel_fd(loop, fd, OOP_EXCEPTION);
136 void report_child_status(const char *what, int status) {
137 if (WIFEXITED(status)) {
138 int es= WEXITSTATUS(status);
140 warn("%s: child died with error exit status %d", what, es);
141 } else if (WIFSIGNALED(status)) {
142 int sig= WTERMSIG(status);
143 const char *sigstr= strsignal(sig);
144 const char *coredump= WCOREDUMP(status) ? " (core dumped)" : "";
146 warn("%s: child died due to fatal signal %s%s", what, sigstr, coredump);
148 warn("%s: child died due to unknown fatal signal %d%s",
149 what, sig, coredump);
151 warn("%s: child died with unknown wait status %d", what,status);
155 int xwaitpid(pid_t *pid, const char *what) {
158 int r= kill(*pid, SIGKILL);
159 if (r) syscrash("cannot kill %s child", what);
161 pid_t got= waitpid(*pid, &status, 0);
162 if (got==-1) syscrash("cannot reap %s child", what);
163 if (got==0) crash("cannot reap %s child", what);
170 void *zxmalloc(size_t sz) {
171 void *p= xmalloc(sz);
176 void xunlink(const char *path, const char *what) {
178 if (r) syscrash("can't unlink %s %s", path, what);
183 if (now==-1) syscrash("time(2) failed");
187 void xsigaction(int signo, const struct sigaction *sa) {
188 int r= sigaction(signo,sa,0);
189 if (r) syscrash("sigaction failed for \"%s\"", strsignal(signo));
191 void xsigsetdefault(int signo) {
193 memset(&sa,0,sizeof(sa));
194 sa.sa_handler= SIG_DFL;
195 xsigaction(signo,&sa);
197 void raise_default(int signo) {
198 xsigsetdefault(signo);
203 void xgettimeofday(struct timeval *tv_r) {
204 int r= gettimeofday(tv_r,0);
205 if (r) syscrash("gettimeofday(2) failed");
207 void xsetnonblock(int fd, int nonb) {
208 int errnoval= oop_fd_nonblock(fd, nonb);
209 if (errnoval) { errno= errnoval; syscrash("setnonblocking"); }
212 void check_isreg(const struct stat *stab, const char *path,
214 if (!S_ISREG(stab->st_mode))
215 crash("%s %s not a plain file (mode 0%lo)",
216 what, path, (unsigned long)stab->st_mode);
219 void xfstat(int fd, struct stat *stab_r, const char *what) {
220 int r= fstat(fd, stab_r);
221 if (r) syscrash("could not fstat %s", what);
224 void xfstat_isreg(int fd, struct stat *stab_r,
225 const char *path, const char *what) {
226 xfstat(fd, stab_r, what);
227 check_isreg(stab_r, path, what);
230 void xlstat_isreg(const char *path, struct stat *stab,
231 int *enoent_r /* 0 means ENOENT is fatal */,
233 int r= lstat(path, stab);
235 if (errno==ENOENT && enoent_r) { *enoent_r=1; return; }
236 syscrash("could not lstat %s %s", what, path);
238 if (enoent_r) *enoent_r= 0;
239 check_isreg(stab, path, what);
242 int samefile(const struct stat *a, const struct stat *b) {
243 assert(S_ISREG(a->st_mode));
244 assert(S_ISREG(b->st_mode));
245 return (a->st_ino == b->st_ino &&
246 a->st_dev == b->st_dev);
249 char *sanitise(const char *input, int len) {
250 static char sanibuf[100]; /* returns pointer to this buffer! */
252 const char *p= input;
253 const char *endp= len>=0 ? input+len : 0;
257 if (q > sanibuf+sizeof(sanibuf)-8) { strcpy(q,"'.."); break; }
258 int c= (!endp || p<endp) ? *p++ : 0;
259 if (!c) { *q++= '\''; *q=0; break; }
260 if (c>=' ' && c<=126 && c!='\\') { *q++= c; continue; }
261 sprintf(q,"\\x%02x",c);