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.40 2006/07/26 11:49:32 martinea 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_name = NULL; /* filename */
51 static char *db_filename = NULL; /* /path/to/filename */
53 static pid_t debug_prefix_pid = 0;
54 static char *get_debug_name(time_t t, int n);
55 static void debug_setup_1(char *config, char *subdir);
56 static void debug_setup_2(char *s, int fd, char *notation);
57 static times_t debug_start_time;
58 static int debug_clock_is_running = 0;
61 * Format and write a debug message to the process debug file.
63 printf_arglist_function(void debug_printf, const char *, format)
68 * It is common in the code to call dbprintf to write out
69 * syserrno(errno) and then turn around and try to do something else
70 * with errno (e.g. printf() or log()), so we make sure errno goes
71 * back out with the same value it came in with.
77 if(db_file == NULL && db_fd == 2) {
81 arglist_start(argp, format);
82 vfprintf(db_file, format, argp);
91 * Generate a debug file name. The name is based on the program name,
92 * followed by a timestamp, an optional sequence number, and ".debug".
99 char number[NUM_STR_SIZE];
103 if(n < 0 || n > 1000) {
106 ts = construct_timestamp(&t);
110 snprintf(number, SIZEOF(number), "%03d", n - 1);
112 result = vstralloc(get_pname(), ".", ts, number, ".debug", NULL);
117 static char *dbgdir = NULL;
118 static time_t curtime;
121 debug_setup_1(char *config, char *subdir)
123 struct passwd *pwent;
129 struct dirent *entry;
132 size_t test_name_len;
135 char *dbfilename = NULL;
136 char *sane_config = NULL;
139 memset(&sbuf, 0, SIZEOF(sbuf));
140 if(client_uid == (uid_t) -1 && (pwent = getpwnam(CLIENT_LOGIN)) != NULL) {
141 client_uid = pwent->pw_uid;
142 client_gid = pwent->pw_gid;
147 pname_len = strlen(pname);
150 * Create the debug directory if it does not yet exist.
154 sane_config = sanitise_filename(config);
155 if (sane_config && subdir)
156 dbgdir = vstralloc(AMANDA_DBGDIR, "/", subdir, "/", sane_config,
158 else if (sane_config)
159 dbgdir = vstralloc(AMANDA_DBGDIR, "/", sane_config, "/", NULL);
161 dbgdir = vstralloc(AMANDA_DBGDIR, "/", subdir, "/", NULL);
163 dbgdir = stralloc2(AMANDA_DBGDIR, "/");
164 if(mkpdir(dbgdir, 02700, client_uid, client_gid) == -1) {
165 error("create debug directory \"%s\": %s",
166 dbgdir, strerror(errno));
172 * Clean out old debug files. We also rename files with old style
173 * names (XXX.debug or XXX.$PID.debug) into the new name format.
174 * We assume no system has 17 digit PID-s :-) and that there will
175 * not be a conflict between an old and new name.
177 if((d = opendir(dbgdir)) == NULL) {
178 error("open debug directory \"%s\": %s",
179 dbgdir, strerror(errno));
183 test_name = get_debug_name(curtime - (AMANDA_DEBUG_DAYS * 24 * 60 * 60), 0);
184 test_name_len = strlen(test_name);
185 while((entry = readdir(d)) != NULL) {
186 if(is_dot_or_dotdot(entry->d_name)) {
189 d_name_len = strlen(entry->d_name);
190 if(strncmp(entry->d_name, pname, pname_len) != 0
191 || entry->d_name[pname_len] != '.'
193 || strcmp(entry->d_name + d_name_len - 6, ".debug") != 0) {
194 continue; /* not one of our debug files */
196 e = newvstralloc(e, dbgdir, entry->d_name, NULL);
197 if(d_name_len < test_name_len) {
199 * Create a "pretend" name based on the last modification
200 * time. This name will be used to decide if the real name
201 * should be removed. If not, it will be used to rename the
204 if(stat(e, &sbuf) != 0) {
205 continue; /* ignore errors */
208 dbfilename = get_debug_name((time_t)sbuf.st_mtime, 0);
211 dbfilename = newstralloc(dbfilename, entry->d_name);
214 if(strcmp(dbfilename, test_name) < 0) {
215 (void) unlink(e); /* get rid of old file */
220 while(dbfilename != NULL
221 && (s = newvstralloc(s, dbgdir, dbfilename, NULL)) != NULL
222 && rename(e, s) != 0 && errno != ENOENT) {
224 dbfilename = get_debug_name((time_t)sbuf.st_mtime, ++i);
226 if(dbfilename == NULL) {
227 error("cannot rename old debug file \"%s\"", entry->d_name);
247 int fd_close[MIN_DB_FD+1];
252 if ((rc = chown(db_filename, client_uid, client_gid)) < 0) {
253 dbprintf(("chown(%s, %d, %d) failed. <%s>",
254 db_filename, client_uid, client_gid, strerror(errno)));
259 * Move the file descriptor up high so it stays out of the way
260 * of other processing, e.g. sendbackup.
265 while((db_fd = dup(fd)) < MIN_DB_FD) {
266 fd_close[i++] = db_fd;
271 db_file = fdopen(db_fd, "a");
276 * Make the first debug log file entry.
278 saved_debug = debug; debug = 1;
279 debug_printf("%s: debug %d pid %ld ruid %ld euid %ld: %s at %s",
280 get_pname(), saved_debug, (long)getpid(),
281 (long)getuid(), (long)geteuid(),
289 debug_open(char *subdir)
295 amanda_timezone dontcare;
297 amanda_gettimeofday(&debug_start_time.r, &dontcare);
298 debug_clock_is_running = 1;
303 debug_setup_1(NULL, subdir);
306 * Create the new file with a unique sequence number.
308 mask = (mode_t)umask((mode_t)0037); /* Allow the group read bit through */
309 for(i = 0; fd < 0; i++) {
311 if ((db_name = get_debug_name(curtime, i)) == NULL) {
312 error("Cannot create %s debug file", get_pname());
316 if ((s = newvstralloc(s, dbgdir, db_name, NULL)) == NULL) {
317 error("Cannot allocate %s debug file name memory", get_pname());
321 if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
322 if (errno != EEXIST) {
323 error("Cannot create %s debug file: %s",
324 get_pname(), strerror(errno));
330 (void)umask(mask); /* Restore mask */
335 * Note: we release control of the string 's' points to.
337 debug_setup_2(s, fd, "start");
348 if (dbfilename == NULL) {
355 debug_setup_1(NULL, NULL);
360 if (*dbfilename == '/') {
361 s = stralloc(dbfilename);
363 s = newvstralloc(s, dbgdir, dbfilename, NULL);
365 if ((fd = open(s, O_RDWR|O_APPEND)) < 0) {
366 error("cannot reopen %s debug file %s", get_pname(), dbfilename);
373 * Note: we release control of the string 's' points to.
375 debug_setup_2(s, fd, notation);
394 debug_setup_1(config, subdir);
396 s = newvstralloc(s, dbgdir, db_name, NULL);
398 if (strcmp(db_filename, s) == 0) {
403 mask = (mode_t)umask((mode_t)0037);
404 /* check if a file with the same name already exist */
405 if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
406 for(i = 0; fd < 0; i++) {
408 if ((db_name = get_debug_name(curtime, i)) == NULL) {
409 dbprintf(("Cannot create %s debug file", get_pname()));
413 s = newvstralloc(s, dbgdir, db_name, NULL);
414 if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
415 if (errno != EEXIST) {
416 dbprintf(("Cannot create %s debug file: %s", get_pname(),
425 rename(db_filename, s);
427 (void)umask(mask); /* Restore mask */
432 * Note: we release control of the string 's' points to.
434 debug_setup_2(s, -1, "rename");
447 save_pid = debug_prefix_pid;
448 debug_prefix_pid = 0;
449 debug_printf("%s: pid %ld finish time %s",
450 debug_prefix_time(NULL),
453 debug_prefix_pid = save_pid;
456 if(db_file && fclose(db_file) == EOF) {
457 int save_errno = errno;
459 db_file = NULL; /* prevent recursion */
460 fprintf(stderr, "close debug file: %s", strerror(save_errno));
487 * Routines for returning a common debug file line prefix. Always starts
488 * with the current program name, possibly with an optional suffix.
489 * May then be followed by a PID. May then be followed by an elapsed
494 set_debug_prefix_pid(
497 debug_prefix_pid = p;
505 static char *s = NULL;
506 char debug_pid[NUM_STR_SIZE];
509 s = newvstralloc(s, get_pname(), suffix, NULL);
510 if (debug_prefix_pid != (pid_t) 0) {
511 snprintf(debug_pid, SIZEOF(debug_pid),
513 (long) debug_prefix_pid);
514 s = newvstralloc(s, s, "[", debug_pid, "]", NULL);
525 static char *s = NULL;
529 times_t debug_end_time;
530 amanda_timezone dontcare;
533 if (debug_clock_is_running == 1) {
534 amanda_gettimeofday(&debug_end_time.r, &dontcare);
535 diff = timessub(debug_end_time,debug_start_time);
537 t2 = walltime_str(diff);
542 s = newvstralloc(s, debug_prefix(suffix), t1, t2, NULL);