summaryrefslogtreecommitdiff
path: root/rsync/trace.c
blob: b7e2b876a508679bef5eb36645dee58d7dbfec36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
 *
 * librsync -- library for network deltas
 * $Id$
 *
 * Copyright (C) 2000, 2001 by Martin Pool <mbp@samba.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

                                     /*
                                      | Finality is death.
                                      | Perfection is finality.
                                      | Nothing is perfect.
                                      | There are lumps in it.
                                      */



/*
 * TODO: Have a bit set in the log level that says not to include the
 * function name.
 */

#include <config_rsync.h>

#include <unistd.h>
#include <stdio.h>
#include <sys/file.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <assert.h>
#include <stdarg.h>

#include "rsync.h"
#include "util.h"
#include "trace.h"


rs_trace_fn_t  *rs_trace_impl = rs_trace_stderr;

int rs_trace_level = RS_LOG_INFO;

#ifdef HAVE_PROGRAM_INVOCATION_NAME
#  define MY_NAME program_invocation_short_name
#else
#  define MY_NAME "librsync"
#endif

static void rs_log_va(int level, char const *fn, char const *fmt, va_list va);

#if SIZEOF_SIZE_T > SIZEOF_LONG
#  warning size_t is larger than a long integer, values in trace messages may be wrong
#endif


/**
 * Log severity strings, if any.  Must match ordering in
 * ::rs_loglevel.
 */
static const char *rs_severities[] = {
    "EMERGENCY! ", "ALERT! ", "CRITICAL! ", "ERROR: ", "Warning: ",
    "", "", ""
};



/**
 * \brief Set the destination of trace information.
 *
 * The callback scheme allows for use within applications that may
 * have their own particular ways of reporting errors: log files for a
 * web server, perhaps, and an error dialog for a browser.
 *
 * \todo Do we really need such fine-grained control, or just yes/no
 * tracing?
 */
void
rs_trace_to(rs_trace_fn_t * new_impl)
{
    rs_trace_impl = new_impl;
}


/** 
 * Set the least important message severity that will be output.
 */
void
rs_trace_set_level(rs_loglevel level)
{
    rs_trace_level = level;
}


static void
rs_log_va(int flags, char const *fn, char const *fmt, va_list va)
{
    int level = flags & RS_LOG_PRIMASK;
    
    if (rs_trace_impl && level <= rs_trace_level) {
        char            buf[1000];
        char            full_buf[1000];

        vsnprintf(buf, sizeof buf - 1, fmt, va);

        if (flags & RS_LOG_NONAME) { 
            snprintf(full_buf, sizeof full_buf - 1,
                     "%s: %s%s\n",
                     MY_NAME, rs_severities[level], buf);
        } else { 
            snprintf(full_buf, sizeof full_buf - 1,
                     "%s: %s(%s) %s\n",
                     MY_NAME, rs_severities[level], fn, buf);
        } 

	rs_trace_impl(level, full_buf);
    }
}



/**
 * Called by a macro, used on platforms where we can't determine the
 * calling function name.
 */
void
rs_log0_nofn(int level, char const *fmt, ...)
{
    va_list         va;

    va_start(va, fmt);
    rs_log_va(level, PACKAGE, fmt, va);
    va_end(va);
}


/* Called by a macro that prepends the calling function name,
 * etc.  */
void
rs_log0(int level, char const *fn, char const *fmt, ...)
{
    va_list         va;

    va_start(va, fmt);
    rs_log_va(level, fn, fmt, va);
    va_end(va);
}


void
rs_trace_stderr(int UNUSED(level), char const *msg)
{
    /* NOTE NO TRAILING NUL */
    write(STDERR_FILENO, msg, strlen(msg));
}


/* This is called directly if the machine doesn't allow varargs
 * macros. */
void
rs_fatal0(char const *s, ...) 
{
    va_list	va;

    va_start(va, s);
    rs_log_va(RS_LOG_CRIT, PACKAGE, s, va);
    va_end(va);
}


/* This is called directly if the machine doesn't allow varargs
 * macros. */
void
rs_error0(char const *s, ...) 
{
    va_list	va;

    va_start(va, s);
    rs_log_va(RS_LOG_ERR, PACKAGE, s, va);
    va_end(va);
}


/* This is called directly if the machine doesn't allow varargs
 * macros. */
void
rs_trace0(char const *s, ...) 
{
    va_list	va;

    va_start(va, s);
    rs_log_va(RS_LOG_DEBUG, PACKAGE, s, va);
    va_end(va);
}


/**
 * Return true if the library contains trace code; otherwise false.
 * If this returns false, then trying to turn trace on will achieve
 * nothing.
 */
int
rs_supports_trace(void)
{
#ifdef DO_RS_TRACE
    return 1;
#else
    return 0;
#endif				/* !DO_RS_TRACE */
}