Imported Upstream version 2.6.0p1
[debian/amanda] / common-src / debug.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: debug.c,v 1.40 2006/07/26 11:49:32 martinea Exp $
29  *
30  * Logging support
31  */
32
33 #include "amanda.h"
34 #include "util.h"
35 #include "arglist.h"
36 #include "clock.h"
37 #include "timestamp.h"
38 #include "conffile.h"
39
40 /* Minimum file descriptor on which to keep the debug file.  This is intended
41  * to keep the descriptor "out of the way" of other processing.  It's not clear
42  * that this is required any longer, but it doesn't hurt anything.
43  */
44 #define MIN_DB_FD                       10
45
46 /* information on the current debug file */
47 static int db_fd = 2;                   /* file descriptor (default stderr) */
48 static FILE *db_file = NULL;            /* stdio stream */
49 static char *db_name  = NULL;           /* unqualified filename */
50 static char *db_filename = NULL;        /* fully qualified pathname */
51
52 /* directory containing debug file, including trailing slash */
53 static char *dbgdir = NULL;
54
55 /* time debug log was opened (timestamp of the file) */
56 static time_t open_time;
57
58 /* pointer to logfile.c's 'logerror()', if we're linked
59  * with it */
60 static void (*logerror_fn)(char *) = NULL;
61
62 /* storage for global variables */
63 erroutput_type_t erroutput_type = ERR_INTERACTIVE;
64 int error_exit_status = 1;
65
66 /* static function prototypes */
67 static char *get_debug_name(time_t t, int n);
68 static void debug_setup_1(char *config, char *subdir);
69 static void debug_setup_2(char *s, int fd, char *annotation);
70 static char *msg_timestamp(void);
71
72 static void debug_logging_handler(const gchar *log_domain,
73         GLogLevelFlags log_level,
74         const gchar *message,
75         gpointer user_data);
76 static void debug_setup_logging(void);
77
78 /*
79  * Generate a debug file name.  The name is based on the program name,
80  * followed by a timestamp, an optional sequence number, and ".debug".
81  *
82  * @param t: timestamp
83  * @param n: sequence number between 1 and 1000; if zero, no sequence number
84  * is included.
85  */
86 static char *
87 get_debug_name(
88     time_t      t,
89     int         n)
90 {
91     char number[NUM_STR_SIZE];
92     char *ts;
93     char *result;
94
95     if(n < 0 || n > 1000) {
96         return NULL;
97     }
98     ts = get_timestamp_from_time(t);
99     if(n == 0) {
100         number[0] = '\0';
101     } else {
102         g_snprintf(number, SIZEOF(number), "%03d", n - 1);
103     }
104     result = vstralloc(get_pname(), ".", ts, number, ".debug", NULL);
105     amfree(ts);
106     return result;
107 }
108
109 /* A GLogFunc to handle g_log calls.  This function assumes that user_data
110  * is either NULL or a pointer to one of the debug_* configuration variables
111  * in conffile.c, indicating whether logging for this log domain is enabled.
112  *
113  * @param log_domain: the log domain, or NULL for general logging
114  * @param log_level: level, fatality, and recursion flags
115  * @param message: the message to log
116  * @param user_pointer: unused
117  */
118 static void
119 debug_logging_handler(const gchar *log_domain G_GNUC_UNUSED,
120             GLogLevelFlags log_level,
121             const gchar *message,
122             gpointer user_data G_GNUC_UNUSED)
123 {
124     char *maxlevel = NULL;
125
126     /* convert the highest level to a string and dbprintf it */
127     if (log_level & G_LOG_LEVEL_ERROR)
128         maxlevel = _("error (fatal): ");
129     else if (log_level & G_LOG_LEVEL_CRITICAL)
130         maxlevel = _("critical (fatal): ");
131     else if (log_level & G_LOG_LEVEL_WARNING)
132         maxlevel = _("warning: ");
133     else if (log_level & G_LOG_LEVEL_MESSAGE)
134         maxlevel = _("message: ");
135     else if (log_level & G_LOG_LEVEL_INFO)
136         maxlevel = _("info: ");
137     else
138         maxlevel = ""; /* no level displayed for debugging */
139
140     debug_printf("%s%s\n", maxlevel, message);
141
142     /* error and critical levels have special handling */
143     if (log_level & (G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL)) {
144         if (erroutput_type & ERR_AMANDALOG && logerror_fn != NULL)
145             (*logerror_fn)((char *)message); /* discard 'const' */
146
147         if (erroutput_type & ERR_SYSLOG) {
148 #ifdef LOG_AUTH
149             openlog(get_pname(), LOG_PID, LOG_AUTH);
150 #else
151             openlog(get_pname(), LOG_PID, 0);
152 #endif
153             syslog(LOG_NOTICE, "%s", message);
154             closelog();
155         }
156
157         if (erroutput_type & ERR_INTERACTIVE) {
158             g_fprintf(stderr, "%s: %s\n", get_pname(), message);
159             fflush(stderr);
160         }
161
162         /* we're done */
163         if (log_level & G_LOG_LEVEL_CRITICAL)
164             exit(error_exit_status);
165         else
166             abort();
167         g_assert_not_reached();
168     }
169 }
170
171 /* Install our handler into the glib log handling system.
172  */
173 static void
174 debug_setup_logging(void)
175 {
176     /* g_error and g_critical should be fatal, although the log handler
177      * takes care of this anyway */
178     g_log_set_always_fatal(G_LOG_LEVEL_ERROR |  G_LOG_LEVEL_CRITICAL);
179
180     /* set up handler (g_log_set_default_handler is new in glib-2.6, and
181      * hence not useable here) */
182     g_log_set_handler(NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
183                       debug_logging_handler, NULL);
184 }
185
186 /* Set the global dbgdir according to 'config' and 'subdir', and clean
187  * old debug files out of that directory
188  *
189  * The global open_time is set to the current time, and used to delete
190  * old files.
191  *
192  * @param config: configuration or NULL
193  * @param subdir: subdirectory (server, client, etc.) or NULL
194  */
195 static void
196 debug_setup_1(char *config, char *subdir)
197 {
198     char *pname;
199     size_t pname_len;
200     char *e = NULL;
201     char *s = NULL;
202     DIR *d;
203     struct dirent *entry;
204     int do_rename;
205     char *test_name;
206     size_t test_name_len;
207     size_t d_name_len;
208     struct stat sbuf;
209     char *dbfilename = NULL;
210     char *sane_config = NULL;
211     int i;
212
213     memset(&sbuf, 0, SIZEOF(sbuf));
214
215     pname = get_pname();
216     pname_len = strlen(pname);
217
218     /*
219      * Create the debug directory if it does not yet exist.
220      */
221     amfree(dbgdir);
222     if (config)
223         sane_config = sanitise_filename(config);
224     if (sane_config && subdir)
225         dbgdir = vstralloc(AMANDA_DBGDIR, "/", subdir, "/", sane_config,
226                            "/", NULL);
227     else if (sane_config)
228         dbgdir = vstralloc(AMANDA_DBGDIR, "/", sane_config, "/", NULL);
229     else if (subdir)
230         dbgdir = vstralloc(AMANDA_DBGDIR, "/", subdir, "/", NULL);
231     else
232         dbgdir = stralloc2(AMANDA_DBGDIR, "/");
233     if(mkpdir(dbgdir, 0700, get_client_uid(), get_client_gid()) == -1) {
234         error(_("create debug directory \"%s\": %s"),
235               dbgdir, strerror(errno));
236         /*NOTREACHED*/
237     }
238     amfree(sane_config);
239
240     /*
241      * Clean out old debug files.  We also rename files with old style
242      * names (XXX.debug or XXX.$PID.debug) into the new name format.
243      * We assume no system has 17 digit PID-s :-) and that there will
244      * not be a conflict between an old and new name.
245      */
246     if((d = opendir(dbgdir)) == NULL) {
247         error(_("open debug directory \"%s\": %s"),
248               dbgdir, strerror(errno));
249         /*NOTREACHED*/
250     }
251     time(&open_time);
252     test_name = get_debug_name(open_time - (AMANDA_DEBUG_DAYS * 24 * 60 * 60), 0);
253     test_name_len = strlen(test_name);
254     while((entry = readdir(d)) != NULL) {
255         if(is_dot_or_dotdot(entry->d_name)) {
256             continue;
257         }
258         d_name_len = strlen(entry->d_name);
259         if(strncmp(entry->d_name, pname, pname_len) != 0
260            || entry->d_name[pname_len] != '.'
261            || d_name_len < 6
262            || strcmp(entry->d_name + d_name_len - 6, ".debug") != 0) {
263             continue;                           /* not one of our debug files */
264         }
265         e = newvstralloc(e, dbgdir, entry->d_name, NULL);
266         if(d_name_len < test_name_len) {
267             /*
268              * Create a "pretend" name based on the last modification
269              * time.  This name will be used to decide if the real name
270              * should be removed.  If not, it will be used to rename the
271              * real name.
272              */
273             if(stat(e, &sbuf) != 0) {
274                 continue;                       /* ignore errors */
275             }
276             amfree(dbfilename);
277             dbfilename = get_debug_name((time_t)sbuf.st_mtime, 0);
278             do_rename = 1;
279         } else {
280             dbfilename = newstralloc(dbfilename, entry->d_name);
281             do_rename = 0;
282         }
283         if(strcmp(dbfilename, test_name) < 0) {
284             (void) unlink(e);                   /* get rid of old file */
285             continue;
286         }
287         if(do_rename) {
288             i = 0;
289             while(dbfilename != NULL
290                   && (s = newvstralloc(s, dbgdir, dbfilename, NULL)) != NULL
291                   && rename(e, s) != 0 && errno != ENOENT) {
292                 amfree(dbfilename);
293                 dbfilename = get_debug_name((time_t)sbuf.st_mtime, ++i);
294             }
295             if(dbfilename == NULL) {
296                 error(_("cannot rename old debug file \"%s\""), entry->d_name);
297                 /*NOTREACHED*/
298             }
299         }
300     }
301     amfree(dbfilename);
302     amfree(e);
303     amfree(s);
304     amfree(test_name);
305     closedir(d);
306 }
307
308 /* Given an already-opened debug file, set the file's ownership
309  * appropriately, move its file descriptor above MIN_DB_FD, and
310  * add an initial log entry to the file.
311  *
312  * This function records the file's identity in the globals
313  * db_filename, db_fd, and db_file.  It does *not* set db_name.
314  * db_file is not set if fd is -1
315  *
316  * This function uses the global 'open_time', which is set by
317  * debug_setup_1.
318  *
319  * @param s: the filename of the debug file; string should be malloc'd,
320  * and should *not* be freed by the caller.
321  * @param fd: the descriptor connected to the debug file, or -1 if
322  * no decriptor moving should take place.
323  * @param annotation: an extra string to include in the initial
324  * log entry.
325  */
326 static void
327 debug_setup_2(
328     char *      s,
329     int         fd,
330     char *      annotation)
331 {
332     int i;
333     int fd_close[MIN_DB_FD+1];
334
335     amfree(db_filename);
336     db_filename = s;
337     s = NULL;
338
339     /* If we're root, change the ownership of the debug files.  If we're not root,
340      * this would either be redundant or an error. */
341     if (geteuid() == 0) {
342         if (chown(db_filename, get_client_uid(), get_client_gid()) < 0) {
343             dbprintf(_("chown(%s, %d, %d) failed: %s"),
344                      db_filename, (int)get_client_uid(), (int)get_client_gid(), strerror(errno));
345         }
346     }
347     amfree(dbgdir);
348     /*
349      * Move the file descriptor up high so it stays out of the way
350      * of other processing, e.g. sendbackup.
351      */
352     if (fd >= 0) {
353         i = 0;
354         fd_close[i++] = fd;
355         while((db_fd = dup(fd)) < MIN_DB_FD) {
356             fd_close[i++] = db_fd;
357         }
358         while(--i >= 0) {
359             close(fd_close[i]);
360         }
361         db_file = fdopen(db_fd, "a");
362     }
363
364     if (annotation) {
365         /*
366          * Make the first debug log file entry.
367          */
368         debug_printf(_("pid %ld ruid %ld euid %ld: %s at %s"),
369                      (long)getpid(),
370                      (long)getuid(), (long)geteuid(),
371                      annotation,
372                      ctime(&open_time));
373     }
374 }
375
376 /* Get current GMT time and return a message timestamp.
377  * Used for g_printf calls to logs and such.  The return value
378  * is to a static buffer, so it should be used immediately.
379  *
380  * @returns: timestamp
381  */
382 static char *
383 msg_timestamp(void)
384 {
385     static char timestamp[128];
386     struct timeval tv;
387
388     gettimeofday(&tv, NULL);
389     g_snprintf(timestamp, SIZEOF(timestamp), "%lld.%06ld",
390                 (long long)tv.tv_sec, (long)tv.tv_usec);
391
392     return timestamp;
393 }
394
395 /*
396  * ---- public functions
397  */
398
399 void
400 set_logerror(void (*f)(char *))
401 {
402     logerror_fn = f;
403 }
404
405 void
406 debug_open(char *subdir)
407 {
408     int fd = -1;
409     int i;
410     char *s = NULL;
411     mode_t mask;
412
413     /* set up logging while we're here */
414     debug_setup_logging();
415
416     /* set 'dbgdir' and clean out old debug files */
417     debug_setup_1(NULL, subdir);
418
419     /*
420      * Create the new file with a unique sequence number.
421      */
422     mask = (mode_t)umask((mode_t)0037); /* Allow the group read bit through */
423
424     /* iteratate through sequence numbers until we find one that
425      * is not already in use */
426     for(i = 0; fd < 0; i++) {
427         amfree(db_name);
428         if ((db_name = get_debug_name(open_time, i)) == NULL) {
429             error(_("Cannot create debug file name in %d tries."), i);
430             /*NOTREACHED*/
431         }
432
433         if ((s = newvstralloc(s, dbgdir, db_name, NULL)) == NULL) {
434             error(_("Cannot allocate debug file name memory"));
435             /*NOTREACHED*/
436         }
437
438         if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
439             if (errno != EEXIST) {
440                 error(_("Cannot create debug file \"%s\": %s"),
441                         s, strerror(errno));
442                 /*NOTREACHED*/
443             }
444             amfree(s);
445         }
446     }
447     (void)umask(mask); /* Restore mask */
448
449     /*
450      * Finish setup.
451      *
452      * Note: we release control of the string 's' points to.
453      */
454     debug_setup_2(s, fd, "start");
455 }
456
457 void
458 debug_reopen(
459     char *      dbfilename,
460     char *      annotation)
461 {
462     char *s = NULL;
463     int fd;
464
465     if (dbfilename == NULL) {
466         return;
467     }
468
469     /* set 'dbgdir' and clean out old debug files */
470     debug_setup_1(NULL, NULL);
471
472     /*
473      * Reopen the file.
474      */
475     if (*dbfilename == '/') {
476         s = stralloc(dbfilename);
477     } else {
478         s = newvstralloc(s, dbgdir, dbfilename, NULL);
479     }
480     if ((fd = open(s, O_RDWR|O_APPEND)) < 0) {
481         error(_("cannot reopen debug file %s"), dbfilename);
482         /*NOTREACHED*/
483     }
484
485     /*
486      * Finish setup.
487      *
488      * Note: we release control of the string 's' points to.
489      */
490     debug_setup_2(s, fd, annotation);
491 }
492
493 void
494 debug_rename(
495     char *config,
496     char *subdir)
497 {
498     int fd = -1;
499     int i;
500     char *s = NULL;
501     mode_t mask;
502
503     if (!db_filename)
504         return;
505
506     /* set 'dbgdir' and clean out old debug files */
507     debug_setup_1(config, subdir);
508
509     s = newvstralloc(s, dbgdir, db_name, NULL);
510
511     if (strcmp(db_filename, s) == 0) {
512         amfree(s);
513         return;
514     }
515
516     mask = (mode_t)umask((mode_t)0037);
517
518 #if defined(__CYGWIN__)
519     /*
520      * On cygwin, rename will not overwrite an existing file nor
521      * will it rename a file that is open for writing...
522      *
523      * Rename file directly.  Expect failure if file already exists
524      * or is open by another user.
525      */
526
527     i = 0;
528     while (rename(db_filename, s) < 0) {
529         if (errno != EEXIST) {
530             /*
531              * If the failure was not due to the target file name already
532              * existing then we have bigger issues at hand so we keep 
533              * the existing file.
534              */
535             dbprintf(_("Cannot rename \"%s\" to \"%s\": %s\n"),
536                      db_filename, s, strerror(errno));
537             s = newvstralloc(s, db_filename, NULL);
538             i = -1;
539             break;
540         }
541
542         /*
543          * Files already exists:
544          * Continue searching for a unique file name that will work.
545          */
546         amfree(db_name);
547         if ((db_name = get_debug_name(open_time, i++)) == NULL) {
548             dbprintf(_("Cannot create unique debug file name"));
549             break;
550         }
551         s = newvstralloc(s, dbgdir, db_name, NULL);
552     }
553     if (i >= 0) {
554         /*
555          * We need to close and reopen the original file handle to
556          * release control of the original debug file name.
557          */
558         if ((fd = open(s, O_WRONLY|O_APPEND, 0640)) >= 0) {
559             /*
560              * We can safely close the the original log file
561              * since we now have a new working handle.
562              */
563             db_fd = 2;
564             fclose(db_file);
565             db_file = NULL;
566         }
567     }
568 #else
569     /* check if a file with the same name already exists. */
570     if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
571         for(i = 0; fd < 0; i++) {
572             amfree(db_name);
573             if ((db_name = get_debug_name(open_time, i)) == NULL) {
574                 dbprintf(_("Cannot create debug file"));
575                 break;
576             }
577
578             s = newvstralloc(s, dbgdir, db_name, NULL);
579             if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
580                 if (errno != EEXIST) {
581                     dbprintf(_("Cannot create debug file: %s"),
582                               strerror(errno));
583                     break;
584                 }
585             }
586         }
587     }
588
589     if (fd >= 0) {
590         close(fd);
591         if (rename(db_filename, s) == -1) {
592             dbprintf(_("Cannot rename \"%s\" to \"%s\": %s\n"),
593                      db_filename, s, strerror(errno));
594         }
595         fd = -1;
596     }
597 #endif
598
599     (void)umask(mask); /* Restore mask */
600     /*
601      * Finish setup.
602      *
603      * Note: we release control of the string 's' points to.
604      */
605     debug_setup_2(s, fd, "rename");
606 }
607
608 void
609 debug_close(void)
610 {
611     time_t curtime;
612
613     time(&curtime);
614     debug_printf(_("pid %ld finish time %s"), (long)getpid(), ctime(&curtime));
615
616     if(db_file && fclose(db_file) == EOF) {
617         int save_errno = errno;
618
619         db_file = NULL;                         /* prevent recursion */
620         g_fprintf(stderr, _("close debug file: %s"), strerror(save_errno));
621         /*NOTREACHED*/
622     }
623     db_fd = 2;
624     db_file = NULL;
625     amfree(db_filename);
626     amfree(db_name);
627 }
628
629 /*
630  * Format and write a debug message to the process debug file.
631  */
632 printf_arglist_function(void debug_printf, const char *, format)
633 {
634     va_list argp;
635     int save_errno;
636
637     /*
638      * It is common in the code to call dbprintf to write out
639      * syserrno(errno) and then turn around and try to do something else
640      * with errno (e.g. g_printf() or log()), so we make sure errno goes
641      * back out with the same value it came in with.
642      */
643
644     save_errno = errno;
645
646     /* handle the default (stderr) if debug_open hasn't been called yet */
647     if(db_file == NULL && db_fd == 2) {
648         db_file = stderr;
649     }
650     if(db_file != NULL) {
651         if (db_file != stderr)
652             g_fprintf(db_file, "%s: %s: ", msg_timestamp(), get_pname());
653         else 
654             g_fprintf(db_file, "%s: ", get_pname());
655         arglist_start(argp, format);
656         g_vfprintf(db_file, format, argp);
657         arglist_end(argp);
658         fflush(db_file);
659     }
660     errno = save_errno;
661 }
662
663 int
664 debug_fd(void)
665 {
666     return db_fd;
667 }
668
669 FILE *
670 debug_fp(void)
671 {
672     return db_file;
673 }
674
675 char *
676 debug_fn(void)
677 {
678     return db_filename;
679 }
680
681 void
682 debug_dup_stderr_to_debug(void)
683 {
684     if(db_fd != -1 && db_fd != STDERR_FILENO)
685     {
686        if(dup2(db_fd, STDERR_FILENO) != STDERR_FILENO)
687        {
688            error(_("can't redirect stderr to the debug file"));
689            g_assert_not_reached();
690        }
691     }
692 }
693