Imported Upstream version 2.4.4p3
[debian/amanda] / server-src / logfile.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Author: James da Silva, Systems Design and Analysis Group
24  *                         Computer Science Department
25  *                         University of Maryland at College Park
26  */
27 /*
28  * $Id: logfile.c,v 1.17.4.1.4.2.2.3 2003/01/01 23:28:56 martinea Exp $
29  *
30  * common log file writing routine
31  */
32 #include "amanda.h"
33 #include "arglist.h"
34 #include "conffile.h"
35
36 #include "logfile.h"
37
38 char *logtype_str[] = {
39     "BOGUS",
40     "FATAL",            /* program died for some reason, used by error() */
41     "ERROR", "WARNING", "INFO", "SUMMARY",       /* information messages */
42     "START", "FINISH",                             /* start/end of a run */
43     "DISK",                                                      /* disk */
44     "SUCCESS", "FAIL", "STRANGE",                   /* the end of a dump */
45     "STATS",                                               /* statistics */
46     "MARKER",                                     /* marker for reporter */
47     "CONT"                                 /* continuation line; special */
48 };
49
50 char *program_str[] = {
51     "UNKNOWN", "planner", "driver", "amreport", "dumper", "taper", "amflush"
52 };
53
54 int curlinenum;
55 logtype_t curlog;
56 program_t curprog;
57 char *curstr;
58
59 int multiline = -1;
60 static char *logfile;
61 static int logfd = -1;
62
63  /*
64   * Note that technically we could use two locks, a read lock
65   * from 0-EOF and a write-lock from EOF-EOF, thus leaving the
66   * beginning of the file open for read-only access.  Doing so
67   * would open us up to some race conditions unless we're pretty
68   * careful, and on top of that the functions here are so far
69   * the only accesses to the logfile, so keep things simple.
70   */
71
72 /* local functions */
73 static void open_log P((void));
74 static void close_log P((void));
75
76 void logerror(msg)
77 char *msg;
78 {
79     log_add(L_FATAL, "%s", msg);
80 }
81
82 printf_arglist_function1(void log_add, logtype_t, typ, char *, format)
83 {
84     va_list argp;
85     int saved_errout;
86     char *leader = NULL;
87     char linebuf[STR_SIZE];
88     int l, n, s;
89
90
91     /* format error message */
92
93     if((int)typ <= (int)L_BOGUS || (int)typ > (int)L_MARKER) typ = L_BOGUS;
94
95     if(multiline > 0) {
96         leader = stralloc("  ");                /* continuation line */
97     } else {
98         leader = vstralloc(logtype_str[(int)typ], " ", get_pname(), " ", NULL);
99     }
100
101     arglist_start(argp, format);
102     ap_vsnprintf(linebuf, sizeof(linebuf)-1, format, argp);
103                                                 /* -1 to allow for '\n' */
104     arglist_end(argp);
105
106     /* avoid recursive call from error() */
107
108     saved_errout = erroutput_type;
109     erroutput_type &= ~ERR_AMANDALOG;
110
111     /* append message to the log file */
112
113     if(multiline == -1) open_log();
114
115     for(l = 0, n = strlen(leader); l < n; l += s) {
116         if((s = write(logfd, leader + l, n - l)) < 0) {
117             error("log file write error: %s", strerror(errno));
118         }
119     }
120
121     amfree(leader);
122
123     n = strlen(linebuf);
124     if(n == 0 || linebuf[n-1] != '\n') linebuf[n++] = '\n';
125     linebuf[n] = '\0';
126
127     for(l = 0; l < n; l += s) {
128         if((s = write(logfd, linebuf + l, n - l)) < 0) {
129             error("log file write error: %s", strerror(errno));
130         }
131     }
132
133     if(multiline != -1) multiline++;
134     else close_log();
135
136     erroutput_type = saved_errout;
137 }
138
139 void log_start_multiline()
140 {
141     assert(multiline == -1);
142
143     multiline = 0;
144     open_log();
145 }
146
147
148 void log_end_multiline()
149 {
150     assert(multiline != -1);
151     multiline = -1;
152     close_log();
153 }
154
155
156 void log_rename(datestamp)
157 char *datestamp;
158 {
159     char *conf_logdir;
160     char *logfile;
161     char *fname = NULL;
162     char seq_str[NUM_STR_SIZE];
163     unsigned int seq;
164     struct stat statbuf;
165
166     if(datestamp == NULL) datestamp = "error";
167
168     conf_logdir = getconf_str(CNF_LOGDIR);
169     if (*conf_logdir == '/') {
170         conf_logdir = stralloc(conf_logdir);
171     } else {
172         conf_logdir = stralloc2(config_dir, conf_logdir);
173     }
174     logfile = vstralloc(conf_logdir, "/log", NULL);
175
176     for(seq = 0; 1; seq++) {    /* if you've got MAXINT files in your dir... */
177         ap_snprintf(seq_str, sizeof(seq_str), "%d", seq);
178         fname = newvstralloc(fname,
179                              logfile,
180                              ".", datestamp,
181                              ".", seq_str,
182                              NULL);
183         if(stat(fname, &statbuf) == -1 && errno == ENOENT) break;
184     }
185
186     if(rename(logfile, fname) != 0) {
187         error("could not rename \"%s\" to \"%s\": %s",
188               logfile, fname, strerror(errno));
189     }
190
191     amfree(fname);
192     amfree(logfile);
193     amfree(conf_logdir);
194 }
195
196
197 static void open_log()
198 {
199     char *conf_logdir;
200
201     conf_logdir = getconf_str(CNF_LOGDIR);
202     if (*conf_logdir == '/') {
203         conf_logdir = stralloc(conf_logdir);
204     } else {
205         conf_logdir = stralloc2(config_dir, conf_logdir);
206     }
207     logfile = vstralloc(conf_logdir, "/log", NULL);
208     amfree(conf_logdir);
209
210     logfd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600);
211
212     if(logfd == -1) {
213         error("could not open log file %s: %s", logfile, strerror(errno));
214     }
215
216     if(amflock(logfd, "log") == -1)
217         error("could not lock log file %s: %s", logfile, strerror(errno));
218 }
219
220
221 static void close_log()
222 {
223     if(amfunlock(logfd, "log") == -1)
224         error("could not unlock log file %s: %s", logfile, strerror(errno));
225
226     if(close(logfd) == -1)
227         error("close log file: %s", strerror(errno));
228
229     logfd = -1;
230     amfree(logfile);
231 }
232
233
234 int get_logline(logf)
235 FILE *logf;
236 {
237     static char *logline = NULL;
238     char *logstr, *progstr;
239     char *s;
240     int ch;
241
242     amfree(logline);
243     if((logline = agets(logf)) == NULL) return 0;
244     curlinenum++;
245     s = logline;
246     ch = *s++;
247
248     /* continuation lines are special */
249
250     if(logline[0] == ' ' && logline[1] == ' ') {
251         curlog = L_CONT;
252         /* curprog stays the same */
253         skip_whitespace(s, ch);
254         curstr = s-1;
255         return 1;
256     }
257
258     /* isolate logtype field */
259
260     skip_whitespace(s, ch);
261     logstr = s - 1;
262     skip_non_whitespace(s, ch);
263     s[-1] = '\0';
264
265     /* isolate program name field */
266
267     skip_whitespace(s, ch);
268     progstr = s - 1;
269     skip_non_whitespace(s, ch);
270     s[-1] = '\0';
271
272     /* rest of line is logtype dependent string */
273
274     skip_whitespace(s, ch);
275     curstr = s - 1;
276
277     /* lookup strings */
278
279     for(curlog = L_MARKER; curlog != L_BOGUS; curlog--)
280         if(strcmp(logtype_str[curlog], logstr) == 0) break;
281
282     for(curprog = P_LAST; curprog != P_UNKNOWN; curprog--)
283         if(strcmp(program_str[curprog], progstr) == 0) break;
284
285     return 1;
286 }