de063dcfd1782f023f03e8b51f55a98cf169c5a7
[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.29 2005/12/04 22:56:55 martinea Exp $
29  *
30  * common log file writing routine
31  */
32 #include "amanda.h"
33 #include "arglist.h"
34 #include "util.h"
35 #include "conffile.h"
36
37 #include "logfile.h"
38
39 char *logtype_str[] = {
40     "BOGUS",
41     "FATAL",            /* program died for some reason, used by error() */
42     "ERROR", "WARNING", "INFO", "SUMMARY",       /* information messages */
43     "START", "FINISH",                             /* start/end of a run */
44     "DISK",                                                      /* disk */
45     "SUCCESS", "PARTIAL", "FAIL", "STRANGE",        /* the end of a dump */
46     "CHUNK", "CHUNKSUCCESS",                            /* ... continued */
47     "STATS",                                               /* statistics */
48     "MARKER",                                     /* marker for reporter */
49     "CONT"                                 /* continuation line; special */
50 };
51
52 char *program_str[] = {
53     "UNKNOWN", "planner", "driver", "amreport", "dumper", "chunker",
54     "taper", "amflush"
55 };
56
57 int curlinenum;
58 logtype_t curlog;
59 program_t curprog;
60 char *curstr;
61
62 int multiline = -1;
63 static char *logfile;
64 static int logfd = -1;
65
66  /*
67   * Note that technically we could use two locks, a read lock
68   * from 0-EOF and a write-lock from EOF-EOF, thus leaving the
69   * beginning of the file open for read-only access.  Doing so
70   * would open us up to some race conditions unless we're pretty
71   * careful, and on top of that the functions here are so far
72   * the only accesses to the logfile, so keep things simple.
73   */
74
75 /* local functions */
76 static void open_log P((void));
77 static void close_log P((void));
78
79 void logerror(msg)
80 char *msg;
81 {
82     log_add(L_FATAL, "%s", msg);
83 }
84
85
86 printf_arglist_function2(char *log_genstring, logtype_t, typ, char *, pname, char *, format)
87 {
88     va_list argp;
89     char *leader = NULL;
90     char linebuf[STR_SIZE];
91
92
93     /* format error message */
94
95     if((int)typ <= (int)L_BOGUS || (int)typ > (int)L_MARKER) typ = L_BOGUS;
96
97     if(multiline > 0) {
98         leader = stralloc("  ");                /* continuation line */
99     } else {
100         leader = vstralloc(logtype_str[(int)typ], " ", pname, " ", NULL);
101     }
102
103     arglist_start(argp, format);
104     vsnprintf(linebuf, sizeof(linebuf)-1, format, argp);
105                                                 /* -1 to allow for '\n' */
106     return(vstralloc(leader, linebuf, "\n", NULL));
107 }
108
109 printf_arglist_function1(void log_add, logtype_t, typ, char *, format)
110 {
111     va_list argp;
112     int saved_errout;
113     char *leader = NULL;
114     char linebuf[STR_SIZE];
115     int n;
116
117
118     /* format error message */
119
120     if((int)typ <= (int)L_BOGUS || (int)typ > (int)L_MARKER) typ = L_BOGUS;
121
122     if(multiline > 0) {
123         leader = stralloc("  ");                /* continuation line */
124     } else {
125         leader = vstralloc(logtype_str[(int)typ], " ", get_pname(), " ", NULL);
126     }
127
128     arglist_start(argp, format);
129     vsnprintf(linebuf, sizeof(linebuf)-1, format, argp);
130                                                 /* -1 to allow for '\n' */
131     arglist_end(argp);
132
133     /* avoid recursive call from error() */
134
135     saved_errout = erroutput_type;
136     erroutput_type &= ~ERR_AMANDALOG;
137
138     /* append message to the log file */
139
140     if(multiline == -1) open_log();
141
142     if (fullwrite(logfd, leader, strlen(leader)) < 0)
143         error("log file write error: %s", strerror(errno));
144
145     amfree(leader);
146
147     n = strlen(linebuf);
148     if(n == 0 || linebuf[n-1] != '\n') linebuf[n++] = '\n';
149     linebuf[n] = '\0';
150
151     if (fullwrite(logfd, linebuf, n) < 0)
152         error("log file write error: %s", strerror(errno));
153
154     if(multiline != -1) multiline++;
155     else close_log();
156
157     erroutput_type = saved_errout;
158 }
159
160 void log_start_multiline()
161 {
162     assert(multiline == -1);
163
164     multiline = 0;
165     open_log();
166 }
167
168
169 void log_end_multiline()
170 {
171     assert(multiline != -1);
172     multiline = -1;
173     close_log();
174 }
175
176
177 void log_rename(datestamp)
178 char *datestamp;
179 {
180     char *conf_logdir;
181     char *logfile;
182     char *fname = NULL;
183     char seq_str[NUM_STR_SIZE];
184     unsigned int seq;
185     struct stat statbuf;
186
187     if(datestamp == NULL) datestamp = "error";
188
189     conf_logdir = getconf_str(CNF_LOGDIR);
190     if (*conf_logdir == '/') {
191         conf_logdir = stralloc(conf_logdir);
192     } else {
193         conf_logdir = stralloc2(config_dir, conf_logdir);
194     }
195     logfile = vstralloc(conf_logdir, "/log", NULL);
196
197     for(seq = 0; 1; seq++) {    /* if you've got MAXINT files in your dir... */
198         snprintf(seq_str, sizeof(seq_str), "%d", seq);
199         fname = newvstralloc(fname,
200                              logfile,
201                              ".", datestamp,
202                              ".", seq_str,
203                              NULL);
204         if(stat(fname, &statbuf) == -1 && errno == ENOENT) break;
205     }
206
207     if(rename(logfile, fname) == -1)
208         error("could not rename \"%s\" to \"%s\": %s",
209               logfile, fname, strerror(errno));
210
211     amfree(fname);
212     amfree(logfile);
213     amfree(conf_logdir);
214 }
215
216
217 static void open_log()
218 {
219     char *conf_logdir;
220
221     conf_logdir = getconf_str(CNF_LOGDIR);
222     if (*conf_logdir == '/') {
223         conf_logdir = stralloc(conf_logdir);
224     } else {
225         conf_logdir = stralloc2(config_dir, conf_logdir);
226     }
227     logfile = vstralloc(conf_logdir, "/log", NULL);
228     amfree(conf_logdir);
229
230     logfd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600);
231
232     if(logfd == -1)
233         error("could not open log file %s: %s", logfile, strerror(errno));
234
235     if(amflock(logfd, "log") == -1)
236         error("could not lock log file %s: %s", logfile, strerror(errno));
237 }
238
239
240 static void close_log()
241 {
242     if(amfunlock(logfd, "log") == -1)
243         error("could not unlock log file %s: %s", logfile, strerror(errno));
244
245     if(close(logfd) == -1)
246         error("close log file: %s", strerror(errno));
247
248     logfd = -1;
249     amfree(logfile);
250 }
251
252
253 int get_logline(logf)
254 FILE *logf;
255 {
256     static char *logline = NULL;
257     char *logstr, *progstr;
258     char *s;
259     int ch;
260
261     amfree(logline);
262     if((logline = agets(logf)) == NULL) return 0;
263     curlinenum++;
264     s = logline;
265     ch = *s++;
266
267     /* continuation lines are special */
268
269     if(logline[0] == ' ' && logline[1] == ' ') {
270         curlog = L_CONT;
271         /* curprog stays the same */
272         skip_whitespace(s, ch);
273         curstr = s-1;
274         return 1;
275     }
276
277     /* isolate logtype field */
278
279     skip_whitespace(s, ch);
280     logstr = s - 1;
281     skip_non_whitespace(s, ch);
282     s[-1] = '\0';
283
284     /* isolate program name field */
285
286     skip_whitespace(s, ch);
287     progstr = s - 1;
288     skip_non_whitespace(s, ch);
289     s[-1] = '\0';
290
291     /* rest of line is logtype dependent string */
292
293     skip_whitespace(s, ch);
294     curstr = s - 1;
295
296     /* lookup strings */
297
298     for(curlog = L_MARKER; curlog != L_BOGUS; curlog--)
299         if(strcmp(logtype_str[curlog], logstr) == 0) break;
300
301     for(curprog = P_LAST; curprog != P_UNKNOWN; curprog--)
302         if(strcmp(program_str[curprog], progstr) == 0) break;
303
304     return 1;
305 }