2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
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.
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.
23 * Author: James da Silva, Systems Design and Analysis Group
24 * Computer Science Department
25 * University of Maryland at College Park
28 * $Id: logfile.c,v 1.31 2006/06/01 14:54:39 martinea Exp $
30 * common log file writing routine
39 char *logtype_str[] = {
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 */
45 /* the end of a dump */
46 "DONE", "PART", "PARTPARTIAL", "SUCCESS", "PARTIAL", "FAIL", "STRANGE",
47 "CHUNK", "CHUNKSUCCESS", /* ... continued */
48 "STATS", /* statistics */
49 "MARKER", /* marker for reporter */
50 "CONT" /* continuation line; special */
53 char *program_str[] = {
54 "UNKNOWN", "planner", "driver", "amreport", "dumper", "chunker",
55 "taper", "amflush", "amdump", "amidxtaped", "amfetchdump", "amcheckdump"
65 static int logfd = -1;
68 * Note that technically we could use two locks, a read lock
69 * from 0-EOF and a write-lock from EOF-EOF, thus leaving the
70 * beginning of the file open for read-only access. Doing so
71 * would open us up to some race conditions unless we're pretty
72 * careful, and on top of that the functions here are so far
73 * the only accesses to the logfile, so keep things simple.
77 static void open_log(void);
78 static void close_log(void);
84 log_add(L_FATAL, "%s", msg);
88 printf_arglist_function2(char *log_genstring, logtype_t, typ, char *, pname, char *, format)
92 char linebuf[STR_SIZE];
93 char *xlated_fmt = dgettext("C", format);
95 /* format error message */
97 if((int)typ <= (int)L_BOGUS || (int)typ > (int)L_MARKER) typ = L_BOGUS;
100 leader = stralloc(" "); /* continuation line */
102 leader = vstralloc(logtype_str[(int)typ], " ", pname, " ", NULL);
105 arglist_start(argp, format);
106 g_vsnprintf(linebuf, SIZEOF(linebuf)-1, xlated_fmt, argp);
107 /* -1 to allow for '\n' */
109 return(vstralloc(leader, linebuf, "\n", NULL));
112 printf_arglist_function1(void log_add, logtype_t, typ, char *, format)
117 char *xlated_fmt = gettext(format);
118 char linebuf[STR_SIZE];
121 /* format error message */
123 if((int)typ <= (int)L_BOGUS || (int)typ > (int)L_MARKER) typ = L_BOGUS;
126 leader = stralloc(" "); /* continuation line */
128 leader = vstralloc(logtype_str[(int)typ], " ", get_pname(), " ", NULL);
131 arglist_start(argp, format);
132 /* use sizeof(linebuf)-2 to save space for a trailing newline */
133 g_vsnprintf(linebuf, SIZEOF(linebuf)-2, xlated_fmt, argp);
134 /* -1 to allow for '\n' */
137 /* avoid recursive call from error() */
139 saved_errout = erroutput_type;
140 erroutput_type &= ~ERR_AMANDALOG;
142 /* append message to the log file */
144 if(multiline == -1) open_log();
146 if (full_write(logfd, leader, strlen(leader)) < strlen(leader)) {
147 error(_("log file write error: %s"), strerror(errno));
153 /* add a newline if necessary */
155 if(n == 0 || linebuf[n-1] != '\n') linebuf[n++] = '\n';
158 if (full_write(logfd, linebuf, n) < n) {
159 error(_("log file write error: %s"), strerror(errno));
163 if(multiline != -1) multiline++;
166 erroutput_type = saved_errout;
170 log_start_multiline(void)
172 assert(multiline == -1);
180 log_end_multiline(void)
182 assert(multiline != -1);
195 char seq_str[NUM_STR_SIZE];
199 if(datestamp == NULL) datestamp = "error";
201 conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
202 logfile = vstralloc(conf_logdir, "/log", NULL);
204 for(seq = 0; 1; seq++) { /* if you've got MAXINT files in your dir... */
205 g_snprintf(seq_str, SIZEOF(seq_str), "%u", seq);
206 fname = newvstralloc(fname,
211 if(stat(fname, &statbuf) == -1 && errno == ENOENT) break;
214 if(rename(logfile, fname) == -1) {
215 error(_("could not rename \"%s\" to \"%s\": %s"),
216 logfile, fname, strerror(errno));
231 /* now that we have a logfile, let the debug module know how to write
232 * error messages to it. This is due to some rather obscure linking
234 set_logerror(logerror);
236 conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
237 logfile = vstralloc(conf_logdir, "/log", NULL);
240 logfd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600);
243 error(_("could not open log file %s: %s"), logfile, strerror(errno));
247 if(amflock(logfd, "log") == -1) {
248 error(_("could not lock log file %s: %s"), logfile, strerror(errno));
257 if(amfunlock(logfd, "log") == -1) {
258 error(_("could not unlock log file %s: %s"), logfile, strerror(errno));
262 if(close(logfd) == -1) {
263 error(_("close log file: %s"), strerror(errno));
271 /* WARNING: Function accesses globals curstr, curlog, and curprog
272 * WARNING: Function has static member logline, returned via globals */
277 static char *logline = NULL;
278 char *logstr, *progstr;
283 while ((logline = agets(logf)) != NULL) {
284 if (logline[0] != '\0')
288 if (logline == NULL) return 0;
293 /* continuation lines are special */
295 if(logline[0] == ' ' && logline[1] == ' ') {
297 /* curprog stays the same */
298 skip_whitespace(s, ch);
303 /* isolate logtype field */
305 skip_whitespace(s, ch);
307 skip_non_whitespace(s, ch);
310 /* isolate program name field */
312 skip_whitespace(s, ch);
314 skip_non_whitespace(s, ch);
317 /* rest of line is logtype dependent string */
319 skip_whitespace(s, ch);
324 for(curlog = L_MARKER; curlog != L_BOGUS; curlog--)
325 if(strcmp(logtype_str[curlog], logstr) == 0) break;
327 for(curprog = P_LAST; curprog != P_UNKNOWN; curprog--)
328 if(strcmp(program_str[curprog], progstr) == 0) break;