~dannf/ubuntu/saucy/screen/lp1213278-from-debian

« back to all changes in this revision

Viewing changes to logfile.c

  • Committer: Bazaar Package Importer
  • Author(s): Nathaniel McCallum
  • Date: 2004-09-03 15:15:33 UTC
  • Revision ID: james.westby@ubuntu.com-20040903151533-px02yqlrchs4fv2t
Tags: upstream-4.0.2
ImportĀ upstreamĀ versionĀ 4.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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
 
20
 *
 
21
 ****************************************************************
 
22
 */
 
23
 
 
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 */
 
27
 
 
28
 
 
29
#include "config.h"
 
30
#include "screen.h"
 
31
#include "extern.h"
 
32
#include "logfile.h"
 
33
 
 
34
static void changed_logfile __P((struct logfile *));
 
35
static struct logfile *lookup_logfile __P((char *));
 
36
static int stolen_logfile __P((struct logfile *));
 
37
 
 
38
static struct logfile *logroot = NULL;
 
39
 
 
40
static void
 
41
changed_logfile(l)
 
42
struct logfile *l;
 
43
{
 
44
  struct stat o, *s = l->st;
 
45
 
 
46
  if (fstat(fileno(l->fp), &o) < 0)             /* get trouble later */
 
47
    return;
 
48
  if (o.st_size > s->st_size)           /* aha, appended text */
 
49
    {
 
50
      s->st_size = o.st_size;           /* this should have changed */
 
51
      s->st_mtime = o.st_mtime;         /* only size and mtime */
 
52
    }
 
53
}
 
54
 
 
55
/*
 
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);''
 
60
 * 
 
61
 * need_fd is returned on success, else -1 is returned.
 
62
 */
 
63
int
 
64
lf_move_fd(fd, need_fd)
 
65
int need_fd, fd;
 
66
{
 
67
  int r = -1;
 
68
  
 
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;
 
75
}
 
76
 
 
77
static int
 
78
logfile_reopen(name, wantfd, l)
 
79
char *name;
 
80
int wantfd;
 
81
struct logfile *l;
 
82
{
 
83
  int got_fd;
 
84
 
 
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)
 
88
    {
 
89
      logfclose(l);
 
90
      debug1("logfile_reopen: failed for %s\n", name);
 
91
      return -1;
 
92
    }
 
93
  changed_logfile(l);
 
94
  debug2("logfile_reopen: %d = %s\n", wantfd, name);
 
95
  return 0;
 
96
}
 
97
 
 
98
static int (* lf_reopen_fn)() = logfile_reopen;
 
99
 
 
100
/* 
 
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.
 
111
 */
 
112
void
 
113
logreopen_register(fn)
 
114
int (*fn) __P((char *, int, struct logfile *));
 
115
{
 
116
  lf_reopen_fn = fn ? fn : logfile_reopen;
 
117
}
 
118
 
 
119
/*
 
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.
 
124
 */
 
125
static int
 
126
stolen_logfile(l)
 
127
struct logfile *l;
 
128
{
 
129
  struct stat o, *s = l->st;
 
130
 
 
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;
 
137
 
 
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 */
 
145
    {
 
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;
 
155
    }
 
156
 
 
157
  debug1("stolen_logfile: %s o.k.\n", l->name);
 
158
  return 0;
 
159
}
 
160
 
 
161
static struct logfile *
 
162
lookup_logfile(name)
 
163
char *name;
 
164
{
 
165
  struct logfile *l;
 
166
 
 
167
  for (l = logroot; l; l = l->next)
 
168
    if (!strcmp(name, l->name))
 
169
      return l;
 
170
  return NULL;
 
171
}
 
172
 
 
173
struct logfile *
 
174
logfopen(name, fp)
 
175
char *name;
 
176
FILE *fp;
 
177
{
 
178
  struct logfile *l;
 
179
 
 
180
  if (!fp)
 
181
    {
 
182
      if (!(l = lookup_logfile(name)))
 
183
        return NULL;
 
184
      l->opencount++;
 
185
      return l;
 
186
    }
 
187
 
 
188
  if (!(l = (struct logfile *)malloc(sizeof(struct logfile))))
 
189
    return NULL;
 
190
  if (!(l->st = (struct stat *)malloc(sizeof(struct stat))))
 
191
    {
 
192
      free((char *)l);
 
193
      return NULL;
 
194
    }
 
195
 
 
196
  if (!(l->name = SaveStr(name)))
 
197
    {
 
198
      free((char *)l->st);
 
199
      free((char *)l);
 
200
      return NULL;
 
201
    }
 
202
  l->fp = fp;
 
203
  l->opencount = 1;
 
204
  l->writecount = 0;
 
205
  l->flushcount = 0;
 
206
  changed_logfile(l);
 
207
 
 
208
  l->next = logroot;
 
209
  logroot = l;
 
210
  return l;
 
211
}
 
212
 
 
213
int
 
214
islogfile(name)
 
215
char *name;
 
216
{
 
217
  if (!name)
 
218
    return logroot ? 1 : 0;
 
219
  return lookup_logfile(name) ? 1 : 0;
 
220
}
 
221
 
 
222
int
 
223
logfclose(l)
 
224
struct logfile *l;
 
225
{
 
226
  struct logfile **lp;
 
227
 
 
228
  for (lp = &logroot; *lp; lp = &(*lp)->next)
 
229
    if (*lp == l)
 
230
      break;
 
231
 
 
232
  if (!*lp)
 
233
    return -1;
 
234
 
 
235
  if ((--l->opencount) > 0)
 
236
    return 0;
 
237
  if (l->opencount < 0)
 
238
    abort();
 
239
 
 
240
  *lp = l->next;
 
241
  fclose(l->fp);
 
242
  free(l->name);
 
243
  free((char *)l);
 
244
  return 0;
 
245
}
 
246
 
 
247
/* 
 
248
 * XXX
 
249
 * write and flush both *should* check the file's stat, if it disappeared
 
250
 * or changed, re-open it.
 
251
 */
 
252
int
 
253
logfwrite(l, buf, n)
 
254
struct logfile *l;
 
255
char *buf;
 
256
int n;
 
257
{
 
258
  int r;
 
259
 
 
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;
 
267
}
 
268
 
 
269
int
 
270
logfflush(l)
 
271
struct logfile *l;
 
272
{
 
273
  int r = 0;
 
274
 
 
275
  if (!l)
 
276
    for (l = logroot; l; l = l->next)
 
277
      {
 
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); 
 
283
      }
 
284
  else
 
285
    {
 
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); 
 
291
    }
 
292
  return r;
 
293
}
 
294