Implement CLOCK_MONOTONIC using getnanouptime(), which in DragonFly is
[dragonfly.git] / contrib / cvs-1.12.9 / src / log-buffer.c
1 /* CVS client logging buffer.
2
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.  */
12
13 #include <config.h>
14
15 #include <stdio.h>
16
17 #include "cvs.h"
18 #include "buffer.h"
19
20 #ifdef CLIENT_SUPPORT
21
22 /* We want to be able to log data sent between us and the server.  We
23    do it using log buffers.  Each log buffer has another buffer which
24    handles the actual I/O, and a file to log information to.
25
26    This structure is the closure field of a log buffer.  */
27
28 struct log_buffer
29 {
30     /* The underlying buffer.  */
31     struct buffer *buf;
32     /* The file to log information to.  */
33     FILE *log;
34 };
35
36 static int log_buffer_input (void *, char *, int, int, int *);
37 static int log_buffer_output (void *, const char *, int, int *);
38 static int log_buffer_flush (void *);
39 static int log_buffer_block (void *, int);
40 static int log_buffer_shutdown (struct buffer *);
41
42 /* Create a log buffer.  */
43
44 static struct buffer *
45 log_buffer_initialize (struct buffer *buf, FILE *fp, int input, void (*memory) (struct buffer *))
46 {
47     struct log_buffer *n;
48
49     n = (struct log_buffer *) xmalloc (sizeof *n);
50     n->buf = buf;
51     n->log = fp;
52     return buf_initialize (input ? log_buffer_input : NULL,
53                            input ? NULL : log_buffer_output,
54                            input ? NULL : log_buffer_flush,
55                            log_buffer_block,
56                            log_buffer_shutdown,
57                            memory,
58                            n);
59 }
60
61 /* The input function for a log buffer.  */
62
63 static int
64 log_buffer_input (void *closure, char *data, int need, int size, int *got)
65 {
66     struct log_buffer *lb = (struct log_buffer *) closure;
67     int status;
68     size_t n_to_write;
69
70     if (lb->buf->input == NULL)
71         abort ();
72
73     status = (*lb->buf->input) (lb->buf->closure, data, need, size, got);
74     if (status != 0)
75         return status;
76
77     if (*got > 0)
78     {
79         n_to_write = *got;
80         if (fwrite (data, 1, n_to_write, lb->log) != n_to_write)
81             error (0, errno, "writing to log file");
82     }
83
84     return 0;
85 }
86
87 /* The output function for a log buffer.  */
88
89 static int
90 log_buffer_output (void *closure, const char *data, int have, int *wrote)
91 {
92     struct log_buffer *lb = (struct log_buffer *) closure;
93     int status;
94     size_t n_to_write;
95
96     if (lb->buf->output == NULL)
97         abort ();
98
99     status = (*lb->buf->output) (lb->buf->closure, data, have, wrote);
100     if (status != 0)
101         return status;
102
103     if (*wrote > 0)
104     {
105         n_to_write = *wrote;
106         if (fwrite (data, 1, n_to_write, lb->log) != n_to_write)
107             error (0, errno, "writing to log file");
108     }
109
110     return 0;
111 }
112
113 /* The flush function for a log buffer.  */
114
115 static int
116 log_buffer_flush (void *closure)
117 {
118     struct log_buffer *lb = (struct log_buffer *) closure;
119
120     if (lb->buf->flush == NULL)
121         abort ();
122
123     /* We don't really have to flush the log file here, but doing it
124        will let tail -f on the log file show what is sent to the
125        network as it is sent.  */
126     if (fflush (lb->log) != 0)
127         error (0, errno, "flushing log file");
128
129     return (*lb->buf->flush) (lb->buf->closure);
130 }
131
132 /* The block function for a log buffer.  */
133
134 static int
135 log_buffer_block (void *closure, int block)
136 {
137     struct log_buffer *lb = (struct log_buffer *) closure;
138
139     if (block)
140         return set_block (lb->buf);
141     else
142         return set_nonblock (lb->buf);
143 }
144
145 /* The shutdown function for a log buffer.  */
146
147 static int
148 log_buffer_shutdown (struct buffer *buf)
149 {
150     struct log_buffer *lb = (struct log_buffer *) buf->closure;
151     int retval;
152
153     retval = buf_shutdown (lb->buf);
154     if (fclose (lb->log) < 0)
155         error (0, errno, "closing log file");
156     return retval;
157 }
158
159
160 void
161 setup_logfiles (struct buffer **to_server_p, struct buffer **from_server_p)
162 {
163   char *log = getenv ("CVS_CLIENT_LOG");
164
165   /* Set up logfiles, if any.
166    *
167    * We do this _after_ authentication on purpose.  Wouldn't really like to
168    * worry about logging passwords...
169    */
170   if (log)
171     {
172       int len = strlen (log);
173       char *buf = xmalloc (len + 5);
174       char *p;
175       FILE *fp;
176
177       strcpy (buf, log);
178       p = buf + len;
179
180       /* Open logfiles in binary mode so that they reflect
181          exactly what was transmitted and received (that is
182          more important than that they be maximally
183          convenient to view).  */
184       /* Note that if we create several connections in a single CVS client
185          (currently used by update.c), then the last set of logfiles will
186          overwrite the others.  There is currently no way around this.  */
187       strcpy (p, ".in");
188       fp = open_file (buf, "wb");
189       if (fp == NULL)
190         error (0, errno, "opening to-server logfile %s", buf);
191       else
192         *to_server_p = log_buffer_initialize (*to_server_p, fp, 0,
193                                               (BUFMEMERRPROC) NULL);
194
195       strcpy (p, ".out");
196       fp = open_file (buf, "wb");
197       if (fp == NULL)
198         error (0, errno, "opening from-server logfile %s", buf);
199       else
200         *from_server_p = log_buffer_initialize (*from_server_p, fp, 1,
201                                                 (BUFMEMERRPROC) NULL);
202
203       free (buf);
204     }
205 }
206
207 #endif /* CLIENT_SUPPORT */