source: trunk/essentials/net-misc/wget/src/log.c

Last change on this file was 3440, checked in by bird, 18 years ago

wget 1.10.2

File size: 23.8 KB
Line 
1/* Messages logging.
2 Copyright (C) 2005 Free Software Foundation, Inc.
3
4This file is part of GNU Wget.
5
6GNU Wget is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11GNU Wget is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with Wget; if not, write to the Free Software
18Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20In addition, as a special exception, the Free Software Foundation
21gives permission to link the code of its release of Wget with the
22OpenSSL project's "OpenSSL" library (or with modified versions of it
23that use the same license as the "OpenSSL" library), and distribute
24the linked executables. You must obey the GNU General Public License
25in all respects for all of the code used other than "OpenSSL". If you
26modify this file, you may extend this exception to your version of the
27file, but you are not obligated to do so. If you do not wish to do
28so, delete this exception statement from your version. */
29
30#include <config.h>
31
32#include <stdio.h>
33#ifdef HAVE_STRING_H
34# include <string.h>
35#else
36# include <strings.h>
37#endif
38#include <stdlib.h>
39#ifdef WGET_USE_STDARG
40# include <stdarg.h>
41#else
42# include <varargs.h>
43#endif
44#ifdef HAVE_UNISTD_H
45# include <unistd.h>
46#endif
47#include <assert.h>
48#include <errno.h>
49
50#include "wget.h"
51#include "utils.h"
52#include "log.h"
53
54#ifndef errno
55extern int errno;
56#endif
57
58/* This file impplement support for "logging". Logging means printing
59 output, plus several additional features:
60
61 - Cataloguing output by importance. You can specify that a log
62 message is "verbose" or "debug", and it will not be printed unless
63 in verbose or debug mode, respectively.
64
65 - Redirecting the log to the file. When Wget's output goes to the
66 terminal, and Wget receives SIGHUP, all further output is
67 redirected to a log file. When this is the case, Wget can also
68 print the last several lines of "context" to the log file so that
69 it does not begin in the middle of a line. For this to work, the
70 logging code stores the last several lines of context. Callers may
71 request for certain output not to be stored.
72
73 - Inhibiting output. When Wget receives SIGHUP, but redirecting
74 the output fails, logging is inhibited. */
75
76
77
78/* The file descriptor used for logging. This is NULL before log_init
79 is called; logging functions log to stderr then. log_init sets it
80 either to stderr or to a file pointer obtained from fopen(). If
81 logging is inhibited, logfp is set back to NULL. */
82static FILE *logfp;
83
84/* If non-zero, it means logging is inhibited, i.e. nothing is printed
85 or stored. */
86static int inhibit_logging;
87
88/* Whether the last output lines are stored for use as context. */
89static int save_context_p;
90
91/* Whether the log is flushed after each command. */
92static int flush_log_p = 1;
93
94/* Whether any output has been received while flush_log_p was 0. */
95static int needs_flushing;
96
97/* In the event of a hang-up, and if its output was on a TTY, Wget
98 redirects its output to `wget-log'.
99
100 For the convenience of reading this newly-created log, we store the
101 last several lines ("screenful", hence the choice of 24) of Wget
102 output, and dump them as context when the time comes. */
103#define SAVED_LOG_LINES 24
104
105/* log_lines is a circular buffer that stores SAVED_LOG_LINES lines of
106 output. log_line_current always points to the position in the
107 buffer that will be written to next. When log_line_current reaches
108 SAVED_LOG_LINES, it is reset to zero.
109
110 The problem here is that we'd have to either (re)allocate and free
111 strings all the time, or limit the lines to an arbitrary number of
112 characters. Instead of settling for either of these, we do both:
113 if the line is smaller than a certain "usual" line length (128
114 chars by default), a preallocated memory is used. The rare lines
115 that are longer than 128 characters are malloc'ed and freed
116 separately. This gives good performance with minimum memory
117 consumption and fragmentation. */
118
119#define STATIC_LENGTH 128
120
121static struct log_ln {
122 char static_line[STATIC_LENGTH + 1]; /* statically allocated
123 line. */
124 char *malloced_line; /* malloc'ed line, for lines of output
125 larger than 80 characters. */
126 char *content; /* this points either to malloced_line
127 or to the appropriate static_line.
128 If this is NULL, it means the line
129 has not yet been used. */
130} log_lines[SAVED_LOG_LINES];
131
132/* The current position in the ring. */
133static int log_line_current = -1;
134
135/* Whether the most recently written line was "trailing", i.e. did not
136 finish with \n. This is an important piece of information because
137 the code is always careful to append data to trailing lines, rather
138 than create new ones. */
139static int trailing_line;
140
141static void check_redirect_output PARAMS ((void));
142
143
144#define ROT_ADVANCE(num) do { \
145 if (++num >= SAVED_LOG_LINES) \
146 num = 0; \
147} while (0)
148
149/* Free the log line index with NUM. This calls free on
150 ln->malloced_line if it's non-NULL, and it also resets
151 ln->malloced_line and ln->content to NULL. */
152
153static void
154free_log_line (int num)
155{
156 struct log_ln *ln = log_lines + num;
157 if (ln->malloced_line)
158 {
159 xfree (ln->malloced_line);
160 ln->malloced_line = NULL;
161 }
162 ln->content = NULL;
163}
164
165/* Append bytes in the range [start, end) to one line in the log. The
166 region is not supposed to contain newlines, except for the last
167 character (at end[-1]). */
168
169static void
170saved_append_1 (const char *start, const char *end)
171{
172 int len = end - start;
173 if (!len)
174 return;
175
176 /* First, check whether we need to append to an existing line or to
177 create a new one. */
178 if (!trailing_line)
179 {
180 /* Create a new line. */
181 struct log_ln *ln;
182
183 if (log_line_current == -1)
184 log_line_current = 0;
185 else
186 free_log_line (log_line_current);
187 ln = log_lines + log_line_current;
188 if (len > STATIC_LENGTH)
189 {
190 ln->malloced_line = strdupdelim (start, end);
191 ln->content = ln->malloced_line;
192 }
193 else
194 {
195 memcpy (ln->static_line, start, len);
196 ln->static_line[len] = '\0';
197 ln->content = ln->static_line;
198 }
199 }
200 else
201 {
202 /* Append to the last line. If the line is malloc'ed, we just
203 call realloc and append the new string. If the line is
204 static, we have to check whether appending the new string
205 would make it exceed STATIC_LENGTH characters, and if so,
206 convert it to malloc(). */
207 struct log_ln *ln = log_lines + log_line_current;
208 if (ln->malloced_line)
209 {
210 /* Resize malloc'ed line and append. */
211 int old_len = strlen (ln->malloced_line);
212 ln->malloced_line = xrealloc (ln->malloced_line, old_len + len + 1);
213 memcpy (ln->malloced_line + old_len, start, len);
214 ln->malloced_line[old_len + len] = '\0';
215 /* might have changed due to realloc */
216 ln->content = ln->malloced_line;
217 }
218 else
219 {
220 int old_len = strlen (ln->static_line);
221 if (old_len + len > STATIC_LENGTH)
222 {
223 /* Allocate memory and concatenate the old and the new
224 contents. */
225 ln->malloced_line = (char *)xmalloc (old_len + len + 1);
226 memcpy (ln->malloced_line, ln->static_line,
227 old_len);
228 memcpy (ln->malloced_line + old_len, start, len);
229 ln->malloced_line[old_len + len] = '\0';
230 ln->content = ln->malloced_line;
231 }
232 else
233 {
234 /* Just append to the old, statically allocated
235 contents. */
236 memcpy (ln->static_line + old_len, start, len);
237 ln->static_line[old_len + len] = '\0';
238 ln->content = ln->static_line;
239 }
240 }
241 }
242 trailing_line = !(end[-1] == '\n');
243 if (!trailing_line)
244 ROT_ADVANCE (log_line_current);
245}
246
247/* Log the contents of S, as explained above. If S consists of
248 multiple lines, they are logged separately. If S does not end with
249 a newline, it will form a "trailing" line, to which things will get
250 appended the next time this function is called. */
251
252static void
253saved_append (const char *s)
254{
255 while (*s)
256 {
257 const char *end = strchr (s, '\n');
258 if (!end)
259 end = s + strlen (s);
260 else
261 ++end;
262 saved_append_1 (s, end);
263 s = end;
264 }
265}
266
267
268/* Check X against opt.verbose and opt.quiet. The semantics is as
269 follows:
270
271 * LOG_ALWAYS - print the message unconditionally;
272
273 * LOG_NOTQUIET - print the message if opt.quiet is non-zero;
274
275 * LOG_NONVERBOSE - print the message if opt.verbose is zero;
276
277 * LOG_VERBOSE - print the message if opt.verbose is non-zero. */
278#define CHECK_VERBOSE(x) \
279 switch (x) \
280 { \
281 case LOG_ALWAYS: \
282 break; \
283 case LOG_NOTQUIET: \
284 if (opt.quiet) \
285 return; \
286 break; \
287 case LOG_NONVERBOSE: \
288 if (opt.verbose || opt.quiet) \
289 return; \
290 break; \
291 case LOG_VERBOSE: \
292 if (!opt.verbose) \
293 return; \
294 }
295
296/* Returns the file descriptor for logging. This is LOGFP, except if
297 called before log_init, in which case it returns stderr. This is
298 useful in case someone calls a logging function before log_init.
299
300 If logging is inhibited, return NULL. */
301
302static FILE *
303get_log_fp (void)
304{
305 if (inhibit_logging)
306 return NULL;
307 if (logfp)
308 return logfp;
309 return stderr;
310}
311
312
313/* Log a literal string S. The string is logged as-is, without a
314 newline appended. */
315
316void
317logputs (enum log_options o, const char *s)
318{
319 FILE *fp;
320
321 check_redirect_output ();
322 if ((fp = get_log_fp ()) == NULL)
323 return;
324 CHECK_VERBOSE (o);
325
326 fputs (s, fp);
327 if (save_context_p)
328 saved_append (s);
329 if (flush_log_p)
330 logflush ();
331 else
332 needs_flushing = 1;
333}
334
335struct logvprintf_state {
336 char *bigmsg;
337 int expected_size;
338 int allocated;
339};
340
341/* Print a message to the log. A copy of message will be saved to
342 saved_log, for later reusal by log_dump_context().
343
344 Normally we'd want this function to loop around vsnprintf until
345 sufficient room is allocated, as the Linux man page recommends.
346 However each call to vsnprintf() must be preceded by va_start and
347 followed by va_end. Since calling va_start/va_end is possible only
348 in the function that contains the `...' declaration, we cannot call
349 vsnprintf more than once. Therefore this function saves its state
350 to logvprintf_state and signals the parent to call it again.
351
352 (An alternative approach would be to use va_copy, but that's not
353 portable.) */
354
355static int
356log_vprintf_internal (struct logvprintf_state *state, const char *fmt,
357 va_list args)
358{
359 char smallmsg[128];
360 char *write_ptr = smallmsg;
361 int available_size = sizeof (smallmsg);
362 int numwritten;
363 FILE *fp = get_log_fp ();
364
365 if (!save_context_p)
366 {
367 /* In the simple case just call vfprintf(), to avoid needless
368 allocation and games with vsnprintf(). */
369 vfprintf (fp, fmt, args);
370 goto flush;
371 }
372
373 if (state->allocated != 0)
374 {
375 write_ptr = state->bigmsg;
376 available_size = state->allocated;
377 }
378
379 /* The GNU coding standards advise not to rely on the return value
380 of sprintf(). However, vsnprintf() is a relatively new function
381 missing from legacy systems. Therefore I consider it safe to
382 assume that its return value is meaningful. On the systems where
383 vsnprintf() is not available, we use the implementation from
384 snprintf.c which does return the correct value. */
385 numwritten = vsnprintf (write_ptr, available_size, fmt, args);
386
387 /* vsnprintf() will not step over the limit given by available_size.
388 If it fails, it will return either -1 (POSIX?) or the number of
389 characters that *would have* been written, if there had been
390 enough room (C99). In the former case, we double the
391 available_size and malloc to get a larger buffer, and try again.
392 In the latter case, we use the returned information to build a
393 buffer of the correct size. */
394
395 if (numwritten == -1)
396 {
397 /* Writing failed, and we don't know the needed size. Try
398 again with doubled size. */
399 int newsize = available_size << 1;
400 state->bigmsg = xrealloc (state->bigmsg, newsize);
401 state->allocated = newsize;
402 return 0;
403 }
404 else if (numwritten >= available_size)
405 {
406 /* Writing failed, but we know exactly how much space we
407 need. */
408 int newsize = numwritten + 1;
409 state->bigmsg = xrealloc (state->bigmsg, newsize);
410 state->allocated = newsize;
411 return 0;
412 }
413
414 /* Writing succeeded. */
415 saved_append (write_ptr);
416 fputs (write_ptr, fp);
417 if (state->bigmsg)
418 xfree (state->bigmsg);
419
420 flush:
421 if (flush_log_p)
422 logflush ();
423 else
424 needs_flushing = 1;
425
426 return 1;
427}
428
429/* Flush LOGFP. Useful while flushing is disabled. */
430void
431logflush (void)
432{
433 FILE *fp = get_log_fp ();
434 if (fp)
435 fflush (fp);
436 needs_flushing = 0;
437}
438
439/* Enable or disable log flushing. */
440void
441log_set_flush (int flush)
442{
443 if (flush == flush_log_p)
444 return;
445
446 if (flush == 0)
447 {
448 /* Disable flushing by setting flush_log_p to 0. */
449 flush_log_p = 0;
450 }
451 else
452 {
453 /* Reenable flushing. If anything was printed in no-flush mode,
454 flush the log now. */
455 if (needs_flushing)
456 logflush ();
457 flush_log_p = 1;
458 }
459}
460
461/* (Temporarily) disable storing log to memory. Returns the old
462 status of storing, with which this function can be called again to
463 reestablish storing. */
464
465int
466log_set_save_context (int savep)
467{
468 int old = save_context_p;
469 save_context_p = savep;
470 return old;
471}
472
473/* Handle difference in va_start between pre-ANSI and ANSI C. Note
474 that we always use `...' in function definitions and let ansi2knr
475 convert it for us. */
476
477#ifdef WGET_USE_STDARG
478# define VA_START(args, arg1) va_start (args, arg1)
479#else
480# define VA_START(args, ignored) va_start (args)
481#endif
482
483/* Print a message to the screen or to the log. The first argument
484 defines the verbosity of the message, and the rest are as in
485 printf(3). */
486
487void
488logprintf (enum log_options o, const char *fmt, ...)
489{
490 va_list args;
491 struct logvprintf_state lpstate;
492 int done;
493
494 check_redirect_output ();
495 if (inhibit_logging)
496 return;
497 CHECK_VERBOSE (o);
498
499 xzero (lpstate);
500 do
501 {
502 VA_START (args, fmt);
503 done = log_vprintf_internal (&lpstate, fmt, args);
504 va_end (args);
505 }
506 while (!done);
507}
508
509#ifdef ENABLE_DEBUG
510/* The same as logprintf(), but does anything only if opt.debug is
511 non-zero. */
512void
513debug_logprintf (const char *fmt, ...)
514{
515 if (opt.debug)
516 {
517 va_list args;
518 struct logvprintf_state lpstate;
519 int done;
520
521 check_redirect_output ();
522 if (inhibit_logging)
523 return;
524
525 xzero (lpstate);
526 do
527 {
528 VA_START (args, fmt);
529 done = log_vprintf_internal (&lpstate, fmt, args);
530 va_end (args);
531 }
532 while (!done);
533 }
534}
535#endif /* ENABLE_DEBUG */
536
537
538/* Open FILE and set up a logging stream. If FILE cannot be opened,
539 exit with status of 1. */
540void
541log_init (const char *file, int appendp)
542{
543 if (file)
544 {
545 logfp = fopen (file, appendp ? "a" : "w");
546 if (!logfp)
547 {
548 fprintf (stderr, "%s: %s: %s\n", exec_name, file, strerror (errno));
549 exit (1);
550 }
551 }
552 else
553 {
554 /* The log goes to stderr to avoid collisions with the output if
555 the user specifies `-O -'. #### Francois Pinard suggests
556 that it's a better idea to print to stdout by default, and to
557 stderr only if the user actually specifies `-O -'. He says
558 this inconsistency is harder to document, but is overall
559 easier on the user. */
560 logfp = stderr;
561
562 if (1
563#ifdef HAVE_ISATTY
564 && isatty (fileno (logfp))
565#endif
566 )
567 {
568 /* If the output is a TTY, enable save context, i.e. store
569 the most recent several messages ("context") and dump
570 them to a log file in case SIGHUP or SIGUSR1 is received
571 (or Ctrl+Break is pressed under Windows). */
572 save_context_p = 1;
573 }
574 }
575}
576
577/* Close LOGFP, inhibit further logging and free the memory associated
578 with it. */
579void
580log_close (void)
581{
582 int i;
583
584 if (logfp)
585 fclose (logfp);
586 logfp = NULL;
587 inhibit_logging = 1;
588 save_context_p = 0;
589
590 for (i = 0; i < SAVED_LOG_LINES; i++)
591 free_log_line (i);
592 log_line_current = -1;
593 trailing_line = 0;
594}
595
596/* Dump saved lines to logfp. */
597static void
598log_dump_context (void)
599{
600 int num = log_line_current;
601 FILE *fp = get_log_fp ();
602 if (!fp)
603 return;
604
605 if (num == -1)
606 return;
607 if (trailing_line)
608 ROT_ADVANCE (num);
609 do
610 {
611 struct log_ln *ln = log_lines + num;
612 if (ln->content)
613 fputs (ln->content, fp);
614 ROT_ADVANCE (num);
615 }
616 while (num != log_line_current);
617 if (trailing_line)
618 if (log_lines[log_line_current].content)
619 fputs (log_lines[log_line_current].content, fp);
620 fflush (fp);
621}
622
623
624/* String escape functions. */
625
626/* Return the number of non-printable characters in SOURCE.
627 Non-printable characters are determined as per safe-ctype.c. */
628
629static int
630count_nonprint (const char *source)
631{
632 const char *p;
633 int cnt;
634 for (p = source, cnt = 0; *p; p++)
635 if (!ISPRINT (*p))
636 ++cnt;
637 return cnt;
638}
639
640/* Copy SOURCE to DEST, escaping non-printable characters.
641
642 Non-printable refers to anything outside the non-control ASCII
643 range (32-126) which means that, for example, CR, LF, and TAB are
644 considered non-printable along with ESC, BS, and other control
645 chars. This is by design: it makes sure that messages from remote
646 servers cannot be easily used to deceive the users by mimicking
647 Wget's output. Disallowing non-ASCII characters is another
648 necessary security measure, which makes sure that remote servers
649 cannot garble the screen or guess the local charset and perform
650 homographic attacks.
651
652 Of course, the above mandates that escnonprint only be used in
653 contexts expected to be ASCII, such as when printing host names,
654 URL components, HTTP headers, FTP server messages, and the like.
655
656 ESCAPE is the leading character of the escape sequence. BASE
657 should be the base of the escape sequence, and must be either 8 for
658 octal or 16 for hex.
659
660 DEST must point to a location with sufficient room to store an
661 encoded version of SOURCE. */
662
663static void
664copy_and_escape (const char *source, char *dest, char escape, int base)
665{
666 const char *from = source;
667 char *to = dest;
668 unsigned char c;
669
670 /* Copy chars from SOURCE to DEST, escaping non-printable ones. */
671 switch (base)
672 {
673 case 8:
674 while ((c = *from++) != '\0')
675 if (ISPRINT (c))
676 *to++ = c;
677 else
678 {
679 *to++ = escape;
680 *to++ = '0' + (c >> 6);
681 *to++ = '0' + ((c >> 3) & 7);
682 *to++ = '0' + (c & 7);
683 }
684 break;
685 case 16:
686 while ((c = *from++) != '\0')
687 if (ISPRINT (c))
688 *to++ = c;
689 else
690 {
691 *to++ = escape;
692 *to++ = XNUM_TO_DIGIT (c >> 4);
693 *to++ = XNUM_TO_DIGIT (c & 0xf);
694 }
695 break;
696 default:
697 abort ();
698 }
699 *to = '\0';
700}
701
702#define RING_SIZE 3
703struct ringel {
704 char *buffer;
705 int size;
706};
707static struct ringel ring[RING_SIZE]; /* ring data */
708
709static const char *
710escnonprint_internal (const char *str, char escape, int base)
711{
712 static int ringpos; /* current ring position */
713 int nprcnt;
714
715 assert (base == 8 || base == 16);
716
717 nprcnt = count_nonprint (str);
718 if (nprcnt == 0)
719 /* If there are no non-printable chars in STR, don't bother
720 copying anything, just return STR. */
721 return str;
722
723 {
724 /* Set up a pointer to the current ring position, so we can write
725 simply r->X instead of ring[ringpos].X. */
726 struct ringel *r = ring + ringpos;
727
728 /* Every non-printable character is replaced with the escape char
729 and three (or two, depending on BASE) *additional* chars. Size
730 must also include the length of the original string and one
731 additional char for the terminating \0. */
732 int needed_size = strlen (str) + 1 + (base == 8 ? 3 * nprcnt : 2 * nprcnt);
733
734 /* If the current buffer is uninitialized or too small,
735 (re)allocate it. */
736 if (r->buffer == NULL || r->size < needed_size)
737 {
738 r->buffer = xrealloc (r->buffer, needed_size);
739 r->size = needed_size;
740 }
741
742 copy_and_escape (str, r->buffer, escape, base);
743 ringpos = (ringpos + 1) % RING_SIZE;
744 return r->buffer;
745 }
746}
747
748/* Return a pointer to a static copy of STR with the non-printable
749 characters escaped as \ooo. If there are no non-printable
750 characters in STR, STR is returned. See copy_and_escape for more
751 information on which characters are considered non-printable.
752
753 DON'T call this function on translated strings because escaping
754 will break them. Don't call it on literal strings from the source,
755 which are by definition trusted. If newlines are allowed in the
756 string, escape and print it line by line because escaping the whole
757 string will convert newlines to \012. (This is so that expectedly
758 single-line messages cannot use embedded newlines to mimic Wget's
759 output and deceive the user.)
760
761 escnonprint doesn't quote its escape character because it is notf
762 meant as a general and reversible quoting mechanism, but as a quick
763 way to defang binary junk sent by malicious or buggy servers.
764
765 NOTE: since this function can return a pointer to static data, be
766 careful to copy its result before calling it again. However, to be
767 more useful with printf, it maintains an internal ring of static
768 buffers to return. Currently the ring size is 3, which means you
769 can print up to three values in the same printf; if more is needed,
770 bump RING_SIZE. */
771
772const char *
773escnonprint (const char *str)
774{
775 return escnonprint_internal (str, '\\', 8);
776}
777
778/* Return a pointer to a static copy of STR with the non-printable
779 characters escaped as %XX. If there are no non-printable
780 characters in STR, STR is returned.
781
782 See escnonprint for usage details. */
783
784const char *
785escnonprint_uri (const char *str)
786{
787 return escnonprint_internal (str, '%', 16);
788}
789
790void
791log_cleanup (void)
792{
793 int i;
794 for (i = 0; i < countof (ring); i++)
795 xfree_null (ring[i].buffer);
796}
797
798
799/* When SIGHUP or SIGUSR1 are received, the output is redirected
800 elsewhere. Such redirection is only allowed once. */
801enum { RR_NONE, RR_REQUESTED, RR_DONE } redirect_request = RR_NONE;
802static const char *redirect_request_signal_name;
803
804/* Redirect output to `wget-log'. */
805
806static void
807redirect_output (void)
808{
809 char *logfile;
810 logfp = unique_create (DEFAULT_LOGFILE, 0, &logfile);
811 if (logfp)
812 {
813 fprintf (stderr, _("\n%s received, redirecting output to `%s'.\n"),
814 redirect_request_signal_name, logfile);
815 xfree (logfile);
816 /* Dump the context output to the newly opened log. */
817 log_dump_context ();
818 }
819 else
820 {
821 /* Eek! Opening the alternate log file has failed. Nothing we
822 can do but disable printing completely. */
823 fprintf (stderr, _("\n%s received.\n"), redirect_request_signal_name);
824 fprintf (stderr, _("%s: %s; disabling logging.\n"),
825 logfile, strerror (errno));
826 inhibit_logging = 1;
827 }
828 save_context_p = 0;
829}
830
831/* Check whether a signal handler requested the output to be
832 redirected. */
833
834static void
835check_redirect_output (void)
836{
837 if (redirect_request == RR_REQUESTED)
838 {
839 redirect_request = RR_DONE;
840 redirect_output ();
841 }
842}
843
844/* Request redirection at a convenient time. This may be called from
845 a signal handler. */
846
847void
848log_request_redirect_output (const char *signal_name)
849{
850 if (redirect_request == RR_NONE && save_context_p)
851 /* Request output redirection. The request will be processed by
852 check_redirect_output(), which is called from entry point log
853 functions. */
854 redirect_request = RR_REQUESTED;
855 redirect_request_signal_name = signal_name;
856}
Note: See TracBrowser for help on using the repository browser.