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: debug.c,v 1.36 2006/01/12 01:57:05 paddy_s Exp $
30 * debug log subroutines
39 # define AMANDA_DBGDIR AMANDA_TMPDIR
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;
52 static pid_t debug_prefix_pid = 0;
55 * Format and write a debug message to the process debug file.
57 printf_arglist_function(void debug_printf, const char *, format)
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.
70 if(db_file == NULL && db_fd == 2) {
74 arglist_start(argp, format);
75 vfprintf(db_file, format, argp);
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".
92 char number[NUM_STR_SIZE];
96 if(n < 0 || n > 1000) {
99 ts = construct_timestamp(&t);
103 snprintf(number, sizeof(number), "%03d", n - 1);
105 result = vstralloc(get_pname(), ".", ts, number, ".debug", NULL);
110 static char *dbgdir = NULL;
111 static time_t curtime;
113 static void debug_setup_1()
115 struct passwd *pwent;
121 struct dirent *entry;
123 char *test_name = NULL;
124 size_t test_name_len;
127 char *dbfilename = NULL;
130 if(client_uid == (uid_t) -1 && (pwent = getpwnam(CLIENT_LOGIN)) != NULL) {
131 client_uid = pwent->pw_uid;
132 client_gid = pwent->pw_gid;
137 pname_len = strlen(pname);
140 * Create the debug directory if it does not yet exist.
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));
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.
155 if((d = opendir(AMANDA_DBGDIR)) == NULL) {
156 error("open debug directory \"%s\": %s",
157 AMANDA_DBGDIR, strerror(errno));
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)) {
166 d_name_len = strlen(entry->d_name);
167 if(strncmp(entry->d_name, pname, pname_len) != 0
168 || entry->d_name[pname_len] != '.'
170 || strcmp(entry->d_name + d_name_len - 6, ".debug") != 0) {
171 continue; /* not one of our debug files */
173 e = newvstralloc(e, dbgdir, entry->d_name, NULL);
174 if(d_name_len < test_name_len) {
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
181 if(stat(e, &sbuf) != 0) {
182 continue; /* ignore errors */
185 dbfilename = get_debug_name((time_t)sbuf.st_mtime, 0);
188 dbfilename = newstralloc(dbfilename, entry->d_name);
191 if(strcmp(dbfilename, test_name) < 0) {
192 (void) unlink(e); /* get rid of old file */
197 while(dbfilename != NULL
198 && (s = newvstralloc(s, dbgdir, dbfilename, NULL)) != NULL
199 && rename(e, s) != 0 && errno != ENOENT) {
201 dbfilename = get_debug_name((time_t)sbuf.st_mtime, ++i);
203 if(dbfilename == NULL) {
204 error("cannot rename old debug file \"%s\"", entry->d_name);
215 static void debug_setup_2(s, fd, notation)
222 int fd_close[MIN_DB_FD+1];
227 (void) chown(db_filename, client_uid, client_gid);
230 * Move the file descriptor up high so it stays out of the way
231 * of other processing, e.g. sendbackup.
235 while((db_fd = dup(fd)) < MIN_DB_FD) {
236 fd_close[i++] = db_fd;
241 db_file = fdopen(db_fd, "a");
245 * Make the first debug log file entry.
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(),
259 char *dbfilename = NULL;
271 * Create the new file with a unique sequence number.
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());
280 if ((s = newvstralloc(s, dbgdir, dbfilename, NULL)) == NULL) {
281 error("Cannot allocate %s debug file name memory", get_pname());
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));
295 (void)umask(mask); /* Restore mask */
300 * Note: we release control of the string 's' points to.
302 debug_setup_2(s, fd, "start");
305 void debug_reopen(dbfilename, notation)
312 if (dbfilename == NULL) {
324 if (*dbfilename == '/') {
325 s = stralloc(dbfilename);
327 s = newvstralloc(s, dbgdir, dbfilename, NULL);
329 if ((fd = open(s, O_RDWR|O_APPEND)) < 0) {
330 error("cannot reopen %s debug file %s", get_pname(), dbfilename);
336 * Note: we release control of the string 's' points to.
338 debug_setup_2(s, fd, notation);
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),
356 debug_prefix_pid = save_pid;
359 if(db_file && fclose(db_file) == EOF) {
360 int save_errno = errno;
362 db_file = NULL; /* prevent recursion */
363 error("close debug file: %s", strerror(save_errno));
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
392 void set_debug_prefix_pid(p)
395 debug_prefix_pid = p;
398 char *debug_prefix(suffix)
402 static char *s = NULL;
403 char debug_pid[NUM_STR_SIZE];
406 s = newvstralloc(s, get_pname(), suffix, NULL);
407 if (debug_prefix_pid != (pid_t) 0) {
408 snprintf(debug_pid, sizeof(debug_pid),
410 (long) debug_prefix_pid);
411 s = newvstralloc(s, s, "[", debug_pid, "]", NULL);
417 char *debug_prefix_time(suffix)
421 static char *s = NULL;
426 if (clock_is_running()) {
428 t2 = walltime_str(curclock());
433 s = newvstralloc(s, debug_prefix(suffix), t1, t2, NULL);