66d31bd42c409247d4e8a5c9f9b847be6703a64c
[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.36 2006/01/12 01:57:05 paddy_s Exp $
29  *
30  * debug log subroutines
31  */
32
33 #include "amanda.h"
34 #include "util.h"
35 #include "arglist.h"
36 #include "clock.h"
37
38 #ifndef AMANDA_DBGDIR
39 #  define AMANDA_DBGDIR         AMANDA_TMPDIR
40 #endif
41
42 #ifdef DEBUG_CODE
43
44 int debug = 1;
45
46 #define MIN_DB_FD                       10
47
48 static int db_fd = 2;                   /* default is stderr */
49 static FILE *db_file = NULL;            /* stderr may not be a constant */
50 static char *db_filename = NULL;
51
52 static pid_t debug_prefix_pid = 0;
53
54 /*
55  * Format and write a debug message to the process debug file.
56  */
57 printf_arglist_function(void debug_printf, const char *, format)
58 {
59     va_list argp;
60     int save_errno;
61
62     /*
63      * It is common in the code to call dbprintf to write out
64      * syserrno(errno) and then turn around and try to do something else
65      * with errno (e.g. printf() or log()), so we make sure errno goes
66      * back out with the same value it came in with.
67      */
68     save_errno = errno;
69
70     if(db_file == NULL && db_fd == 2) {
71         db_file = stderr;
72     }
73     if(db_file != NULL) {
74         arglist_start(argp, format);
75         vfprintf(db_file, format, argp);
76         fflush(db_file);
77         arglist_end(argp);
78     }
79
80     errno = save_errno;
81 }
82
83 /*
84  * Generate a debug file name.  The name is based on the program name,
85  * followed by a timestamp, an optional sequence number, and ".debug".
86  */
87 static char *
88 get_debug_name(t, n)
89     time_t t;
90     int n;
91 {
92     char number[NUM_STR_SIZE];
93     char *ts;
94     char *result;
95
96     if(n < 0 || n > 1000) {
97         return NULL;
98     }
99     ts = construct_timestamp(&t);
100     if(n == 0) {
101         number[0] = '\0';
102     } else {
103         snprintf(number, sizeof(number), "%03d", n - 1);
104     }
105     result = vstralloc(get_pname(), ".", ts, number, ".debug", NULL);
106     amfree(ts);
107     return result;
108 }
109
110 static char *dbgdir = NULL;
111 static time_t curtime;
112
113 static void debug_setup_1()
114 {
115     struct passwd *pwent;
116     char *pname;
117     size_t pname_len;
118     char *e = NULL;
119     char *s = NULL;
120     DIR *d;
121     struct dirent *entry;
122     int do_rename;
123     char *test_name = NULL;
124     size_t test_name_len;
125     size_t d_name_len;
126     struct stat sbuf;
127     char *dbfilename = NULL;
128     int i;
129
130     if(client_uid == (uid_t) -1 && (pwent = getpwnam(CLIENT_LOGIN)) != NULL) {
131         client_uid = pwent->pw_uid;
132         client_gid = pwent->pw_gid;
133         endpwent();
134     }
135
136     pname = get_pname();
137     pname_len = strlen(pname);
138
139     /*
140      * Create the debug directory if it does not yet exist.
141      */
142     amfree(dbgdir);
143     dbgdir = stralloc2(AMANDA_DBGDIR, "/");
144     if(mkpdir(dbgdir, 02700, client_uid, client_gid) == -1) {
145         error("create debug directory \"%s\": %s",
146               AMANDA_DBGDIR, strerror(errno));
147     }
148
149     /*
150      * Clean out old debug files.  We also rename files with old style
151      * names (XXX.debug or XXX.$PID.debug) into the new name format.
152      * We assume no system has 17 digit PID-s :-) and that there will
153      * not be a conflict between an old and new name.
154      */
155     if((d = opendir(AMANDA_DBGDIR)) == NULL) {
156         error("open debug directory \"%s\": %s",
157               AMANDA_DBGDIR, strerror(errno));
158     }
159     time(&curtime);
160     test_name = get_debug_name(curtime - (AMANDA_DEBUG_DAYS * 24 * 60 * 60), 0);
161     test_name_len = strlen(test_name);
162     while((entry = readdir(d)) != NULL) {
163         if(is_dot_or_dotdot(entry->d_name)) {
164             continue;
165         }
166         d_name_len = strlen(entry->d_name);
167         if(strncmp(entry->d_name, pname, pname_len) != 0
168            || entry->d_name[pname_len] != '.'
169            || d_name_len < 6
170            || strcmp(entry->d_name + d_name_len - 6, ".debug") != 0) {
171             continue;                           /* not one of our debug files */
172         }
173         e = newvstralloc(e, dbgdir, entry->d_name, NULL);
174         if(d_name_len < test_name_len) {
175             /*
176              * Create a "pretend" name based on the last modification
177              * time.  This name will be used to decide if the real name
178              * should be removed.  If not, it will be used to rename the
179              * real name.
180              */
181             if(stat(e, &sbuf) != 0) {
182                 continue;                       /* ignore errors */
183             }
184             amfree(dbfilename);
185             dbfilename = get_debug_name((time_t)sbuf.st_mtime, 0);
186             do_rename = 1;
187         } else {
188             dbfilename = newstralloc(dbfilename, entry->d_name);
189             do_rename = 0;
190         }
191         if(strcmp(dbfilename, test_name) < 0) {
192             (void) unlink(e);                   /* get rid of old file */
193             continue;
194         }
195         if(do_rename) {
196             i = 0;
197             while(dbfilename != NULL
198                   && (s = newvstralloc(s, dbgdir, dbfilename, NULL)) != NULL
199                   && rename(e, s) != 0 && errno != ENOENT) {
200                 amfree(dbfilename);
201                 dbfilename = get_debug_name((time_t)sbuf.st_mtime, ++i);
202             }
203             if(dbfilename == NULL) {
204                 error("cannot rename old debug file \"%s\"", entry->d_name);
205             }
206         }
207     }
208     amfree(dbfilename);
209     amfree(e);
210     amfree(s);
211     amfree(test_name);
212     closedir(d);
213 }
214
215 static void debug_setup_2(s, fd, notation)
216     char *s;
217     int fd;
218     char *notation;
219 {
220     int saved_debug;
221     int i;
222     int fd_close[MIN_DB_FD+1];
223
224     amfree(db_filename);
225     db_filename = s;
226     s = NULL;
227     (void) chown(db_filename, client_uid, client_gid);
228     amfree(dbgdir);
229     /*
230      * Move the file descriptor up high so it stays out of the way
231      * of other processing, e.g. sendbackup.
232      */
233     i = 0;
234     fd_close[i++] = fd;
235     while((db_fd = dup(fd)) < MIN_DB_FD) {
236         fd_close[i++] = db_fd;
237     }
238     while(--i >= 0) {
239         close(fd_close[i]);
240     }
241     db_file = fdopen(db_fd, "a");
242
243     if (notation) {
244         /*
245          * Make the first debug log file entry.
246          */
247         saved_debug = debug; debug = 1;
248         debug_printf("%s: debug %d pid %ld ruid %ld euid %ld: %s at %s",
249                      get_pname(), saved_debug, (long)getpid(),
250                      (long)getuid(), (long)geteuid(),
251                      notation,
252                      ctime(&curtime));
253         debug = saved_debug;
254     }
255 }
256
257 void debug_open()
258 {
259     char *dbfilename = NULL;
260     int fd = -1;
261     int i;
262     char *s = NULL;
263     mode_t mask;
264
265     /*
266      * Do initial setup.
267      */
268     debug_setup_1();
269
270     /*
271      * Create the new file with a unique sequence number.
272      */
273     mask = umask(0037); /* Allow the group read bit through */
274     for(i = 0; fd < 0; i++) {
275         if ((dbfilename = get_debug_name(curtime, i)) == NULL) {
276             error("Cannot create %s debug file", get_pname());
277             /* NOTREACHED */
278         }
279
280         if ((s = newvstralloc(s, dbgdir, dbfilename, NULL)) == NULL) {
281             error("Cannot allocate %s debug file name memory", get_pname());
282             /* NOTREACHED */
283         }
284         amfree(dbfilename);
285
286         if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
287             if (errno != EEXIST) {
288                 error("Cannot create %s debug file: %s",
289                        get_pname(), strerror(errno));
290                 /* NOTREACHED */
291             }
292             amfree(s);
293         }
294     }
295     (void)umask(mask); /* Restore mask */
296
297     /*
298      * Finish setup.
299      *
300      * Note: we release control of the string 's' points to.
301      */
302     debug_setup_2(s, fd, "start");
303 }
304
305 void debug_reopen(dbfilename, notation)
306     char *dbfilename;
307     char *notation;
308 {
309     char *s = NULL;
310     int fd = -1;
311
312     if (dbfilename == NULL) {
313         return;
314     }
315
316     /*
317      * Do initial setup.
318      */
319     debug_setup_1();
320
321     /*
322      * Reopen the file.
323      */
324     if (*dbfilename == '/') {
325         s = stralloc(dbfilename);
326     } else {
327         s = newvstralloc(s, dbgdir, dbfilename, NULL);
328     }
329     if ((fd = open(s, O_RDWR|O_APPEND)) < 0) {
330         error("cannot reopen %s debug file %s", get_pname(), dbfilename);
331     }
332
333     /*
334      * Finish setup.
335      *
336      * Note: we release control of the string 's' points to.
337      */
338     debug_setup_2(s, fd, notation);
339 }
340
341 void debug_close()
342 {
343     time_t curtime;
344     int save_debug;
345     pid_t save_pid;
346
347     time(&curtime);
348     save_debug = debug;
349     debug = 1;
350     save_pid = debug_prefix_pid;
351     debug_prefix_pid = 0;
352     debug_printf("%s: pid %ld finish time %s",
353                  debug_prefix_time(NULL),
354                  (long)getpid(),
355                  ctime(&curtime));
356     debug_prefix_pid = save_pid;
357     debug = save_debug;
358
359     if(db_file && fclose(db_file) == EOF) {
360         int save_errno = errno;
361
362         db_file = NULL;                         /* prevent recursion */
363         error("close debug file: %s", strerror(save_errno));
364     }
365     db_fd = -1;
366     db_file = NULL;
367     amfree(db_filename);
368 }
369
370 int debug_fd()
371 {
372     return db_fd;
373 }
374
375 FILE *debug_fp()
376 {
377     return db_file;
378 }
379
380 char *debug_fn()
381 {
382     return db_filename;
383 }
384
385 /*
386  * Routines for returning a common debug file line prefix.  Always starts
387  * with the current program name, possibly with an optional suffix.
388  * May then be followed by a PID.  May then be followed by an elapsed
389  * time indicator.
390  */ 
391
392 void set_debug_prefix_pid(p)
393     pid_t p;
394 {
395     debug_prefix_pid = p;
396 }
397
398 char *debug_prefix(suffix)
399     char *suffix;
400 {
401     int save_errno;
402     static char *s = NULL;
403     char debug_pid[NUM_STR_SIZE];
404
405     save_errno = errno;
406     s = newvstralloc(s, get_pname(), suffix, NULL);
407     if (debug_prefix_pid != (pid_t) 0) {
408         snprintf(debug_pid, sizeof(debug_pid),
409                  "%ld",
410                  (long) debug_prefix_pid);
411         s = newvstralloc(s, s, "[", debug_pid, "]", NULL);
412     }
413     errno = save_errno;
414     return s;
415 }
416
417 char *debug_prefix_time(suffix)
418     char *suffix;
419 {
420     int save_errno;
421     static char *s = NULL;
422     char *t1;
423     char *t2;
424
425     save_errno = errno;
426     if (clock_is_running()) {
427         t1 = ": time ";
428         t2 = walltime_str(curclock());
429     } else {
430         t1 = t2 = NULL;
431     }
432
433     s = newvstralloc(s, debug_prefix(suffix), t1, t2, NULL);
434
435     errno = save_errno;
436     return s;
437 }
438 #endif