Merge branch 'master' into lua-scripting
[screen-lua.git] / src / logfile.c
blobd2eaccef2fe5338472f9ee91aebe0c5c6dc045f7
1 /* Copyright (c) 1993-2002
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 ****************************************************************
24 #include <sys/types.h> /* dev_t, ino_t, off_t, ... */
25 #include <sys/stat.h> /* struct stat */
26 #include <fcntl.h> /* O_WRONLY for logfile_reopen */
29 #include "config.h"
30 #include "screen.h"
31 #include "extern.h"
32 #include "logfile.h"
34 static void changed_logfile __P((struct logfile *));
35 static struct logfile *lookup_logfile __P((char *));
36 static int stolen_logfile __P((struct logfile *));
38 static struct logfile *logroot = NULL;
40 static void
41 changed_logfile(l)
42 struct logfile *l;
44 struct stat o, *s = l->st;
46 if (fstat(fileno(l->fp), &o) < 0) /* get trouble later */
47 return;
48 if (o.st_size > s->st_size) /* aha, appended text */
50 s->st_size = o.st_size; /* this should have changed */
51 s->st_mtime = o.st_mtime; /* only size and mtime */
56 * Requires fd to be open and need_fd to be closed.
57 * If possible, need_fd will be open afterwards and refer to
58 * the object originally reffered by fd. fd will be closed then.
59 * Works just like ``fcntl(fd, DUPFD, need_fd); close(fd);''
61 * need_fd is returned on success, else -1 is returned.
63 int
64 lf_move_fd(fd, need_fd)
65 int need_fd, fd;
67 int r = -1;
69 if (fd == need_fd)
70 return fd;
71 if (fd >=0 && fd < need_fd)
72 r = lf_move_fd(dup(fd), need_fd);
73 close(fd);
74 return r;
77 static int
78 logfile_reopen(name, wantfd, l)
79 char *name;
80 int wantfd;
81 struct logfile *l;
83 int got_fd;
85 close(wantfd);
86 if (((got_fd = open(name, O_WRONLY | O_CREAT | O_APPEND, 0666)) < 0) ||
87 lf_move_fd(got_fd, wantfd) < 0)
89 logfclose(l);
90 debug1("logfile_reopen: failed for %s\n", name);
91 return -1;
93 changed_logfile(l);
94 debug2("logfile_reopen: %d = %s\n", wantfd, name);
95 return 0;
98 static int (* lf_reopen_fn)() = logfile_reopen;
101 * Whenever logfwrite discoveres that it is required to close and
102 * reopen the logfile, the function registered here is called.
103 * If you do not register anything here, the above logfile_reopen()
104 * will be used instead.
105 * Your function should perform the same steps as logfile_reopen():
106 * a) close the original filedescriptor without flushing any output
107 * b) open a new logfile for future output on the same filedescriptor number.
108 * c) zero out st_dev, st_ino to tell the stolen_logfile() indcator to
109 * reinitialise itself.
110 * d) return 0 on success.
112 void
113 logreopen_register(fn)
114 int (*fn) __P((char *, int, struct logfile *));
116 lf_reopen_fn = fn ? fn : logfile_reopen;
120 * If the logfile has been removed, truncated, unlinked or the like,
121 * return nonzero.
122 * The l->st structure initialised by logfopen is updated
123 * on every call.
125 static int
126 stolen_logfile(l)
127 struct logfile *l;
129 struct stat o, *s = l->st;
131 o = *s;
132 if (fstat(fileno(l->fp), s) < 0) /* remember that stat failed */
133 s->st_ino = s->st_dev = 0;
134 ASSERT(s == l->st);
135 if (!o.st_dev && !o.st_ino) /* nothing to compare with */
136 return 0;
138 if ((!s->st_dev && !s->st_ino) || /* stat failed, that's new! */
139 !s->st_nlink || /* red alert: file unlinked */
140 (s->st_size < o.st_size) || /* file truncated */
141 (s->st_mtime != o.st_mtime) || /* file modified */
142 ((s->st_ctime != o.st_ctime) && /* file changed (moved) */
143 !(s->st_mtime == s->st_ctime && /* and it was not a change */
144 o.st_ctime < s->st_ctime))) /* due to delayed nfs write */
146 debug1("stolen_logfile: %s stolen!\n", l->name);
147 debug3("st_dev %d, st_ino %d, st_nlink %d\n",
148 (int)s->st_dev, (int)s->st_ino, (int)s->st_nlink);
149 debug2("s->st_size %d, o.st_size %d\n", (int)s->st_size, (int)o.st_size);
150 debug2("s->st_mtime %d, o.st_mtime %d\n",
151 (int)s->st_mtime, (int)o.st_mtime);
152 debug2("s->st_ctime %d, o.st_ctime %d\n",
153 (int)s->st_ctime, (int)o.st_ctime);
154 return -1;
157 debug1("stolen_logfile: %s o.k.\n", l->name);
158 return 0;
161 static struct logfile *
162 lookup_logfile(name)
163 char *name;
165 struct logfile *l;
167 for (l = logroot; l; l = l->next)
168 if (!strcmp(name, l->name))
169 return l;
170 return NULL;
173 struct logfile *
174 logfopen(name, fp)
175 char *name;
176 FILE *fp;
178 struct logfile *l;
180 if (!fp)
182 if (!(l = lookup_logfile(name)))
183 return NULL;
184 l->opencount++;
185 return l;
188 if (!(l = (struct logfile *)malloc(sizeof(struct logfile))))
189 return NULL;
190 if (!(l->st = (struct stat *)malloc(sizeof(struct stat))))
192 free((char *)l);
193 return NULL;
196 if (!(l->name = SaveStr(name)))
198 free((char *)l->st);
199 free((char *)l);
200 return NULL;
202 l->fp = fp;
203 l->opencount = 1;
204 l->writecount = 0;
205 l->flushcount = 0;
206 changed_logfile(l);
208 l->next = logroot;
209 logroot = l;
210 return l;
214 islogfile(name)
215 char *name;
217 if (!name)
218 return logroot ? 1 : 0;
219 return lookup_logfile(name) ? 1 : 0;
223 logfclose(l)
224 struct logfile *l;
226 struct logfile **lp;
228 for (lp = &logroot; *lp; lp = &(*lp)->next)
229 if (*lp == l)
230 break;
232 if (!*lp)
233 return -1;
235 if ((--l->opencount) > 0)
236 return 0;
237 if (l->opencount < 0)
238 abort();
240 *lp = l->next;
241 fclose(l->fp);
242 free(l->name);
243 free((char *)l);
244 return 0;
248 * XXX
249 * write and flush both *should* check the file's stat, if it disappeared
250 * or changed, re-open it.
253 logfwrite(l, buf, n)
254 struct logfile *l;
255 char *buf;
256 int n;
258 int r;
260 if (stolen_logfile(l) && lf_reopen_fn(l->name, fileno(l->fp), l))
261 return -1;
262 r = fwrite(buf, n, 1, l->fp);
263 l->writecount += l->flushcount + 1;
264 l->flushcount = 0;
265 changed_logfile(l);
266 return r;
270 logfflush(l)
271 struct logfile *l;
273 int r = 0;
275 if (!l)
276 for (l = logroot; l; l = l->next)
278 if (stolen_logfile(l) && lf_reopen_fn(l->name, fileno(l->fp), l))
279 return -1;
280 r |= fflush(l->fp);
281 l->flushcount++;
282 changed_logfile(l);
284 else
286 if (stolen_logfile(l) && lf_reopen_fn(l->name, fileno(l->fp), l))
287 return -1;
288 r = fflush(l->fp);
289 l->flushcount++;
290 changed_logfile(l);
292 return r;