Release v.5.0.0
[screen.git] / src / logfile.c
blob65e72052ad06ffebea002b2b45dd560b1c1bfce0
1 /* Copyright (c) 2008, 2009
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Micah Cowan (micah@cowan.name)
5 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
6 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
7 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
8 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
9 * Copyright (c) 1987 Oliver Laumann
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3, or (at your option)
14 * any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program (see the file COPYING); if not, see
23 * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include "config.h"
31 #include "logfile.h"
33 #include <sys/types.h> /* dev_t, ino_t, off_t, ... */
34 #include <sys/stat.h> /* struct stat */
35 #include <fcntl.h> /* O_WRONLY for logfile_reopen */
36 #include <stdint.h>
37 #include <stdbool.h>
39 #include "screen.h"
41 #include "misc.h"
43 static void changed_logfile(Log *);
44 static Log *lookup_logfile(char *);
45 static int stolen_logfile(Log *);
47 static Log *logroot = NULL;
49 static void changed_logfile(Log *l)
51 struct stat o, *s = l->st;
53 if (fstat(fileno(l->fp), &o) < 0) /* get trouble later */
54 return;
55 if (o.st_size > s->st_size) { /* aha, appended text */
56 s->st_size = o.st_size; /* this should have changed */
57 s->st_mtime = o.st_mtime; /* only size and mtime */
62 * Requires fd to be open and need_fd to be closed.
63 * If possible, need_fd will be open afterwards and refer to
64 * the object originally reffered by fd. fd will be closed then.
65 * Works just like ``fcntl(fd, DUPFD, need_fd); close(fd);''
67 * need_fd is returned on success, else -1 is returned.
69 int lf_move_fd(int fd, int need_fd)
71 int r = -1;
73 if (fd == need_fd)
74 return fd;
75 if (fd >= 0 && fd < need_fd)
76 r = lf_move_fd(dup(fd), need_fd);
77 close(fd);
78 return r;
81 static int logfile_reopen(char *name, int wantfd, Log *l)
83 int got_fd;
85 close(wantfd);
86 if (((got_fd = open(name, O_WRONLY | O_CREAT | O_APPEND, 0666)) < 0) || lf_move_fd(got_fd, wantfd) < 0) {
87 logfclose(l);
88 return -1;
90 changed_logfile(l);
91 l->st->st_ino = l->st->st_dev = 0;
92 return 0;
96 * If the logfile has been removed, truncated, unlinked or the like,
97 * return nonzero.
98 * The l->st structure initialised by logfopen is updated
99 * on every call.
101 static int stolen_logfile(Log *l)
103 struct stat o, *s = l->st;
105 o = *s;
106 if (fstat(fileno(l->fp), s) < 0) /* remember that stat failed */
107 s->st_ino = s->st_dev = 0;
108 if (!o.st_dev && !o.st_ino) /* nothing to compare with */
109 return 0;
111 if ((!s->st_dev && !s->st_ino) || /* stat failed, that's new! */
112 !s->st_nlink || /* red alert: file unlinked */
113 (s->st_size < o.st_size) || /* file truncated */
114 (s->st_mtime != o.st_mtime) || /* file modified */
115 ((s->st_ctime != o.st_ctime) && /* file changed (moved) */
116 !(s->st_mtime == s->st_ctime && /* and it was not a change */
117 o.st_ctime < s->st_ctime))) { /* due to delayed nfs write */
118 return -1;
121 return 0;
124 static Log *lookup_logfile(char *name)
126 Log *l;
128 for (l = logroot; l; l = l->next)
129 if (!strcmp(name, l->name))
130 return l;
131 return NULL;
134 Log *logfopen(char *name, FILE * fp)
136 Log *l;
138 if (!fp) {
139 if (!(l = lookup_logfile(name)))
140 return NULL;
141 l->opencount++;
142 return l;
145 if (!(l = calloc(1, sizeof(Log))))
146 return NULL;
147 if (!(l->st = calloc(1, sizeof(struct stat)))) {
148 free((char *)l);
149 return NULL;
152 if (!(l->name = SaveStr(name))) {
153 free((char *)l->st);
154 free((char *)l);
155 return NULL;
157 l->fp = fp;
158 l->opencount = 1;
159 l->writecount = 0;
160 l->flushcount = 0;
161 changed_logfile(l);
163 l->next = logroot;
164 logroot = l;
165 return l;
168 int islogfile(char *name)
170 if (!name)
171 return logroot ? 1 : 0;
172 return lookup_logfile(name) ? 1 : 0;
175 int logfclose(Log *l)
177 Log **lp;
179 for (lp = &logroot; *lp; lp = &(*lp)->next)
180 if (*lp == l)
181 break;
183 if (!*lp)
184 return -1;
186 if ((--l->opencount) > 0)
187 return 0;
188 if (l->opencount < 0)
189 abort();
191 *lp = l->next;
192 fclose(l->fp);
193 free(l->name);
194 free((char *)l);
195 return 0;
199 * XXX
200 * write and flush both *should* check the file's stat, if it disappeared
201 * or changed, re-open it.
203 int logfwrite(Log *l, char *buf, size_t n)
205 int r;
207 if (stolen_logfile(l) && logfile_reopen(l->name, fileno(l->fp), l))
208 return -1;
209 r = fwrite(buf, n, 1, l->fp);
210 l->writecount += l->flushcount + 1;
211 l->flushcount = 0;
212 changed_logfile(l);
213 return r;
216 int logfflush(Log *l)
218 int r = 0;
220 if (!l)
221 for (l = logroot; l; l = l->next) {
222 if (stolen_logfile(l) && logfile_reopen(l->name, fileno(l->fp), l))
223 return -1;
224 r |= fflush(l->fp);
225 l->flushcount++;
226 changed_logfile(l);
227 } else {
228 if (stolen_logfile(l) && logfile_reopen(l->name, fileno(l->fp), l))
229 return -1;
230 r = fflush(l->fp);
231 l->flushcount++;
232 changed_logfile(l);
234 return r;