Change from getopt to popt -- requires const-correctness on arguments.
[rsync/rsync.git] / log.c
CommitLineData
a039749b
MP
1/* -*- c-file-style: "linux"; -*-
2
3e3dcd62 3 Copyright (C) 1998-2001 by Andrew Tridgell
0b76cd63
AT
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18*/
19
20/*
3e3dcd62 21 Logging and utility functions.
0b76cd63 22
3e3dcd62
MP
23 Mapping to human-readable messages added by Martin Pool
24 <mbp@samba.org>, Oct 2000.
0b76cd63
AT
25 */
26#include "rsync.h"
27
45a83540 28static char *logfname;
4f6325c3 29static FILE *logfile;
554e0a8d 30static int log_error_fd = -1;
e0414f42 31
af642a61
MP
32
33struct {
34 int code;
35 char const *name;
36} const rerr_names[] = {
37 { RERR_SYNTAX , "syntax or usage error" },
38 { RERR_PROTOCOL , "protocol incompatibility" },
39 { RERR_FILESELECT , "errors selecting input/output files, dirs" },
40 { RERR_UNSUPPORTED , "requested action not supported" },
41 { RERR_SOCKETIO , "error in socket IO" },
42 { RERR_FILEIO , "error in file IO" },
43 { RERR_STREAMIO , "error in rsync protocol data stream" },
44 { RERR_MESSAGEIO , "errors with program diagnostics" },
45 { RERR_IPC , "error in IPC code" },
3e3dcd62 46 { RERR_SIGNAL , "received SIGUSR1 or SIGINT" },
af642a61
MP
47 { RERR_WAITCHILD , "some error returned by waitpid()" },
48 { RERR_MALLOC , "error allocating core memory buffers" },
49 { RERR_TIMEOUT , "timeout in data send/receive" },
50 { 0, NULL }
51};
52
53
54
55/*
56 * Map from rsync error code to name, or return NULL.
57 */
58static char const *rerr_name(int code)
59{
60 int i;
61 for (i = 0; rerr_names[i].name; i++) {
62 if (rerr_names[i].code == code)
63 return rerr_names[i].name;
64 }
65 return NULL;
66}
67
68
4f6325c3
AT
69static void logit(int priority, char *buf)
70{
45a83540 71 if (logfname) {
15b84e14
DD
72 if (!logfile)
73 log_open();
67ea0d48 74 fprintf(logfile,"%s [%d] %s",
f7632fc6 75 timestring(time(NULL)), (int)getpid(), buf);
4f6325c3
AT
76 fflush(logfile);
77 } else {
78 syslog(priority, "%s", buf);
79 }
80}
e42c9458 81
45a83540 82void log_init(void)
1a016bfd
AT
83{
84 static int initialised;
85 int options = LOG_PID;
bcf5b133 86 time_t t;
1a016bfd
AT
87
88 if (initialised) return;
89 initialised = 1;
90
958f3735
AT
91 /* this looks pointless, but it is needed in order for the
92 C library on some systems to fetch the timezone info
93 before the chroot */
94 t = time(NULL);
95 localtime(&t);
96
97 /* optionally use a log file instead of syslog */
45a83540
DD
98 logfname = lp_log_file();
99 if (logfname) {
15b84e14
DD
100 if (*logfname) {
101 log_open();
45a83540 102 return;
15b84e14 103 }
45a83540 104 logfname = NULL;
4f6325c3
AT
105 }
106
1a016bfd
AT
107#ifdef LOG_NDELAY
108 options |= LOG_NDELAY;
109#endif
110
111#ifdef LOG_DAEMON
112 openlog("rsyncd", options, lp_syslog_facility());
113#else
114 openlog("rsyncd", options);
115#endif
116
117#ifndef LOG_NDELAY
4f6325c3 118 logit(LOG_INFO,"rsyncd started\n");
1a016bfd
AT
119#endif
120}
1a016bfd 121
15b84e14
DD
122void log_open()
123{
124 if (logfname && !logfile) {
125 extern int orig_umask;
126 int old_umask = umask(022 | orig_umask);
127 logfile = fopen(logfname, "a");
128 umask(old_umask);
129 }
130}
131
132void log_close()
45a83540
DD
133{
134 if (logfile) {
135 fclose(logfile);
136 logfile = NULL;
137 }
138}
139
554e0a8d
AT
140/* setup the error file descriptor - used when we are a server
141 that is receiving files */
142void set_error_fd(int fd)
143{
144 log_error_fd = fd;
145}
146
147/* this is the underlying (unformatted) rsync debugging function. Call
148 it with FINFO, FERROR or FLOG */
ff41a59f 149void rwrite(enum logcode code, char *buf, int len)
0b76cd63 150{
0b76cd63
AT
151 FILE *f=NULL;
152 extern int am_daemon;
4a814638 153 extern int am_server;
b86f0cef 154 extern int quiet;
8d9dc9f9 155 /* recursion can happen with certain fatal conditions */
8d9dc9f9 156
6d7b6081 157 if (quiet && code == FINFO) return;
b86f0cef 158
65417579 159 if (len < 0) exit_cleanup(RERR_MESSAGEIO);
0b76cd63 160
ff8b29b8
AT
161 buf[len] = 0;
162
ff41a59f 163 if (code == FLOG) {
11a5a3c7 164 if (am_daemon) logit(LOG_INFO, buf);
11a5a3c7
AT
165 return;
166 }
167
4a814638
AT
168 /* first try to pass it off the our sibling */
169 if (am_server && io_error_write(log_error_fd, code, buf, len)) {
6d7b6081
AT
170 return;
171 }
172
4a814638
AT
173 /* then try to pass it to the other end */
174 if (am_server && io_multiplex_write(code, buf, len)) {
6d7b6081
AT
175 return;
176 }
ff41a59f 177
ff8b29b8 178 if (am_daemon) {
b24203b3 179 static int depth;
ff8b29b8 180 int priority = LOG_INFO;
ff41a59f 181 if (code == FERROR) priority = LOG_WARNING;
45ccc5c0 182
b24203b3
AT
183 if (depth) return;
184
f27b53f5
AT
185 depth++;
186
45a83540 187 log_init();
6d7b6081 188 logit(priority, buf);
8d9dc9f9
AT
189
190 depth--;
ff8b29b8 191 return;
0b76cd63
AT
192 }
193
ff41a59f 194 if (code == FERROR) {
ff8b29b8
AT
195 f = stderr;
196 }
197
ff41a59f 198 if (code == FINFO) {
ff8b29b8
AT
199 if (am_server)
200 f = stderr;
201 else
202 f = stdout;
203 }
204
65417579 205 if (!f) exit_cleanup(RERR_MESSAGEIO);
0b76cd63 206
65417579 207 if (fwrite(buf, len, 1, f) != 1) exit_cleanup(RERR_MESSAGEIO);
8d9dc9f9 208
bcf5b133 209 if (buf[len-1] == '\r' || buf[len-1] == '\n') fflush(f);
0b76cd63 210}
554e0a8d
AT
211
212
a039749b
MP
213/* This is the rsync debugging function. Call it with FINFO, FERROR or
214 * FLOG. */
215void rprintf(enum logcode code, const char *format, ...)
554e0a8d
AT
216{
217 va_list ap;
218 char buf[1024];
219 int len;
220
221 va_start(ap, format);
222 len = vslprintf(buf, sizeof(buf), format, ap);
223 va_end(ap);
224
225 if (len > sizeof(buf)-1) exit_cleanup(RERR_MESSAGEIO);
226
ff41a59f 227 rwrite(code, buf, len);
554e0a8d 228}
0b76cd63 229
a039749b
MP
230
231/* This is like rprintf, but it also tries to print some
232 * representation of the error code. Normally errcode = errno.
233 *
234 * Unlike rprintf, this always adds a newline and there should not be
235 * one in the format string.
236 *
237 * Note that since strerror might involve dynamically loading a
238 * message catalog we need to call it once before chroot-ing. */
239void rsyserr(enum logcode code, int errcode, const char *format, ...)
240{
241 va_list ap;
242 char buf[1024];
243 int len, sys_len;
244 char *sysmsg;
245
246 va_start(ap, format);
247 len = vslprintf(buf, sizeof(buf), format, ap);
248 va_end(ap);
249
250 if (len > sizeof(buf)-1) exit_cleanup(RERR_MESSAGEIO);
251
252 sysmsg = strerror(errcode);
253 sys_len = strlen(sysmsg);
254 if (len + 3 + sys_len > sizeof(buf) - 1)
255 exit_cleanup(RERR_MESSAGEIO);
256
257 strcpy(buf + len, ": ");
258 len += 2;
259 strcpy(buf + len, sysmsg);
260 len += sys_len;
261 strcpy(buf + len, "\n");
262 len++;
263
264 rwrite(code, buf, len);
265}
266
267
268
ff41a59f 269void rflush(enum logcode code)
0b76cd63
AT
270{
271 FILE *f = NULL;
272 extern int am_daemon;
273
274 if (am_daemon) {
275 return;
276 }
277
ff41a59f 278 if (code == FLOG) {
e08bfe12
AT
279 return;
280 }
281
ff41a59f 282 if (code == FERROR) {
0b76cd63
AT
283 f = stderr;
284 }
285
ff41a59f 286 if (code == FINFO) {
0b76cd63
AT
287 extern int am_server;
288 if (am_server)
289 f = stderr;
290 else
291 f = stdout;
292 }
293
65417579 294 if (!f) exit_cleanup(RERR_MESSAGEIO);
0b76cd63
AT
295 fflush(f);
296}
297
11a5a3c7 298
e08bfe12
AT
299
300/* a generic logging routine for send/recv, with parameter
301 substitiution */
0f3203c3 302static void log_formatted(enum logcode code,
b6062654 303 char *format, char *op, struct file_struct *file,
1b7c47cb 304 struct stats *initial_stats)
e08bfe12
AT
305{
306 extern int module_id;
97cb8dc2 307 extern char *auth_user;
e08bfe12 308 char buf[1024];
ab7104da 309 char buf2[1024];
e08bfe12 310 char *p, *s, *n;
e08bfe12 311 int l;
1b7c47cb
AT
312 extern struct stats stats;
313 extern int am_sender;
af77cc6b 314 extern int am_daemon;
1b7c47cb 315 int64 b;
e08bfe12 316
37f9805d 317 strlcpy(buf, format, sizeof(buf));
e08bfe12
AT
318
319 for (s=&buf[0];
320 s && (p=strchr(s,'%')); ) {
321 n = NULL;
322 s = p + 1;
323
324 switch (p[1]) {
af77cc6b
AT
325 case 'h': if (am_daemon) n = client_name(0); break;
326 case 'a': if (am_daemon) n = client_addr(0); break;
e08bfe12 327 case 'l':
37f9805d 328 slprintf(buf2,sizeof(buf2),"%.0f",
e08bfe12
AT
329 (double)file->length);
330 n = buf2;
331 break;
332 case 'p':
37f9805d 333 slprintf(buf2,sizeof(buf2),"%d",
e08bfe12
AT
334 (int)getpid());
335 n = buf2;
336 break;
337 case 'o': n = op; break;
ab7104da 338 case 'f':
37f9805d 339 slprintf(buf2, sizeof(buf2), "%s/%s",
ab7104da
AT
340 file->basedir?file->basedir:"",
341 f_name(file));
342 clean_fname(buf2);
343 n = buf2;
b6062654 344 if (*n == '/') n++;
ab7104da 345 break;
97cb8dc2 346 case 'm': n = lp_name(module_id); break;
b6062654 347 case 't': n = timestring(time(NULL)); break;
97cb8dc2
AT
348 case 'P': n = lp_path(module_id); break;
349 case 'u': n = auth_user; break;
1b7c47cb
AT
350 case 'b':
351 if (am_sender) {
352 b = stats.total_written -
353 initial_stats->total_written;
354 } else {
355 b = stats.total_read -
356 initial_stats->total_read;
357 }
37f9805d 358 slprintf(buf2,sizeof(buf2),"%.0f", (double)b);
1b7c47cb
AT
359 n = buf2;
360 break;
361 case 'c':
362 if (!am_sender) {
363 b = stats.total_written -
364 initial_stats->total_written;
365 } else {
366 b = stats.total_read -
367 initial_stats->total_read;
368 }
37f9805d 369 slprintf(buf2,sizeof(buf2),"%.0f", (double)b);
1b7c47cb
AT
370 n = buf2;
371 break;
e08bfe12
AT
372 }
373
374 if (!n) continue;
375
376 l = strlen(n);
377
378 if ((l-1) + ((int)(s - &buf[0])) > sizeof(buf)) {
379 rprintf(FERROR,"buffer overflow expanding %%%c - exiting\n",
380 p[0]);
65417579 381 exit_cleanup(RERR_MESSAGEIO);
e08bfe12
AT
382 }
383
384 if (l != 2) {
34720097 385 memmove(s+(l-1), s+1, strlen(s+1)+1);
e08bfe12
AT
386 }
387 memcpy(p, n, l);
388
389 s = p+l;
390 }
391
0f3203c3 392 rprintf(code,"%s\n", buf);
e08bfe12
AT
393}
394
11a5a3c7 395/* log the outgoing transfer of a file */
1b7c47cb 396void log_send(struct file_struct *file, struct stats *initial_stats)
11a5a3c7
AT
397{
398 extern int module_id;
b6062654
AT
399 extern int am_server;
400 extern char *log_format;
401
11a5a3c7 402 if (lp_transfer_logging(module_id)) {
b6062654
AT
403 log_formatted(FLOG, lp_log_format(module_id), "send", file, initial_stats);
404 } else if (log_format && !am_server) {
405 log_formatted(FINFO, log_format, "send", file, initial_stats);
11a5a3c7
AT
406 }
407}
408
409/* log the incoming transfer of a file */
1b7c47cb 410void log_recv(struct file_struct *file, struct stats *initial_stats)
11a5a3c7
AT
411{
412 extern int module_id;
b6062654
AT
413 extern int am_server;
414 extern char *log_format;
415
11a5a3c7 416 if (lp_transfer_logging(module_id)) {
117af102 417 log_formatted(FLOG, lp_log_format(module_id), "recv", file, initial_stats);
b6062654 418 } else if (log_format && !am_server) {
117af102 419 log_formatted(FINFO, log_format, "recv", file, initial_stats);
11a5a3c7
AT
420 }
421}
422
af642a61
MP
423
424
425
426/*
427 * Called when the transfer is interrupted for some reason.
428 *
429 * Code is one of the RERR_* codes from errcode.h, or terminating
430 * successfully.
431 */
a9766ef1 432void log_exit(int code, const char *file, int line)
9b73d1c0
AT
433{
434 if (code == 0) {
435 extern struct stats stats;
67ea0d48 436 rprintf(FLOG,"wrote %.0f bytes read %.0f bytes total size %.0f\n",
9b73d1c0
AT
437 (double)stats.total_written,
438 (double)stats.total_read,
439 (double)stats.total_size);
440 } else {
af642a61
MP
441 const char *name;
442
443 name = rerr_name(code);
444 if (!name)
445 name = "unexplained error";
446
447 rprintf(FLOG,"transfer interrupted: %s (code %d) at %s(%d)\n",
448 name, code, file, line);
9b73d1c0
AT
449 }
450}
451
af642a61
MP
452
453
454
11a5a3c7 455/* log the incoming transfer of a file for interactive use, this
b6062654
AT
456 will be called at the end where the client was run
457
458 it i called when a file starts to be transferred
459*/
a9766ef1 460void log_transfer(struct file_struct *file, const char *fname)
11a5a3c7
AT
461{
462 extern int verbose;
463
464 if (!verbose) return;
465
466 rprintf(FINFO,"%s\n", fname);
467}
9b73d1c0 468