]> granicus.if.org Git - postgresql/blob - src/backend/utils/error/elog.c
566125f6e45337ac0904e2bb425ccfc87c26540f
[postgresql] / src / backend / utils / error / elog.c
1 /*-------------------------------------------------------------------------
2  *
3  * elog.c--
4  *        error logger
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.24 1998/01/07 21:06:23 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include <stdio.h>
15 #include <string.h>
16 #include <time.h>
17 #include <fcntl.h>
18 #ifndef O_RDONLY
19 #include <sys/file.h>
20 #endif                                                  /* O_RDONLY */
21 #include <sys/types.h>
22 #include <stdarg.h>
23 #include <errno.h>
24 #include <unistd.h>
25 #include <signal.h>
26
27 #include "postgres.h"
28 #include "miscadmin.h"
29 #include "libpq/libpq.h"
30 #include "storage/proc.h"
31
32 static int      Debugfile = -1;
33 static int      Err_file = -1;
34 static int      ElogDebugIndentLevel = 0;
35
36 extern char OutputFileName[];
37
38 /*
39  * elog --
40  *              Old error logging function.
41  */
42 void
43 elog(int lev, const char *fmt,...)
44 {
45         va_list         ap;
46         char            buf[ELOG_MAXLEN],
47                                 line[ELOG_MAXLEN];
48         register char *bp;
49         register const char *cp;
50         extern int      errno,
51                                 sys_nerr;
52
53 #ifndef PG_STANDALONE
54         extern FILE *Pfout;
55
56 #endif                                                  /* !PG_STANDALONE */
57 #ifdef ELOG_TIMESTAMPS
58         time_t          tim;
59
60 #endif
61         int                     len;
62         int                     i = 0;
63
64         va_start(ap, fmt);
65         if (lev == DEBUG && Debugfile < 0)
66         {
67                 return;
68         }
69         switch (lev)
70         {
71                 case NOIND:
72                         i = ElogDebugIndentLevel - 1;
73                         if (i < 0)
74                                 i = 0;
75                         if (i > 30)
76                                 i = i % 30;
77                         cp = "DEBUG:  ";
78                         break;
79                 case DEBUG:
80                         i = ElogDebugIndentLevel;
81                         if (i < 0)
82                                 i = 0;
83                         if (i > 30)
84                                 i = i % 30;
85                         cp = "DEBUG:  ";
86                         break;
87                 case NOTICE:
88                         cp = "NOTICE:  ";
89                         break;
90                 case ERROR:
91                         cp = "ERROR:  ";
92                         break;
93                 default:
94                         sprintf(line, "FATAL %d:  ", lev);
95                         cp = line;
96         }
97 #ifdef ELOG_TIMESTAMPS
98         time(&tim);
99         strcat(strcpy(buf, cp), ctime(&tim) + 4);
100         bp = buf + strlen(buf) - 6;
101         *bp++ = ':';
102 #else
103         strcpy(buf, cp);
104         bp = buf + strlen(buf);
105 #endif
106         while (i-- > 0)
107                 *bp++ = ' ';
108         for (cp = fmt; *cp; cp++)
109                 if (*cp == '%' && *(cp + 1) == 'm')
110                 {
111                         if (errno < sys_nerr && errno >= 0)
112                                 strcpy(bp, strerror(errno));
113                         else
114                                 sprintf(bp, "error %d", errno);
115                         bp += strlen(bp);
116                         cp++;
117                 }
118                 else
119                         *bp++ = *cp;
120         *bp = '\0';
121         vsprintf(line, buf, ap);
122         va_end(ap);
123         len = strlen(strcat(line, "\n"));
124         if (Debugfile > -1)
125                 write(Debugfile, line, len);
126         if (lev == DEBUG || lev == NOIND)
127                 return;
128
129         /*
130          * If there's an error log file other than our channel to the
131          * front-end program, write to it first.  This is important because
132          * there's a bug in the socket code on ultrix.  If the front end has
133          * gone away (so the channel to it has been closed at the other end),
134          * then writing here can cause this backend to exit without warning --
135          * that is, write() does an exit(). In this case, our only hope of
136          * finding out what's going on is if Err_file was set to some disk
137          * log.  This is a major pain.
138          */
139
140         if (Err_file > -1 && Debugfile != Err_file)
141         {
142                 if (write(Err_file, line, len) < 0)
143                 {
144                         write(open("/dev/console", O_WRONLY, 0666), line, len);
145                         fflush(stdout);
146                         fflush(stderr);
147                         exitpg(lev);
148                 }
149                 fsync(Err_file);
150         }
151
152 #ifndef PG_STANDALONE
153         /* Send IPC message to the front-end program */
154         if (Pfout != NULL && lev > DEBUG)
155         {
156                 /* notices are not exactly errors, handle it differently */
157                 if (lev == NOTICE)
158                         pq_putnchar("N", 1);
159                 else
160                         pq_putnchar("E", 1);
161                 /* pq_putint(-101, 4); *//* should be query id */
162                 pq_putstr(line);
163                 pq_flush();
164         }
165         if (Pfout == NULL) {
166         /* There is no socket.  One explanation for this is we are running
167            as the Postmaster.  So we'll write the message to stderr.
168          */
169                 fputs(line, stderr);
170         }
171 #endif                                                  /* !PG_STANDALONE */
172
173         if (lev == ERROR)
174         {
175                 extern int      InError;
176
177                 ProcReleaseSpins(NULL); /* get rid of spinlocks we hold */
178                 if (!InError)
179                 {
180                         kill(getpid(), 1);      /* abort to traffic cop */
181                         pause();
182                 }
183
184                 /*
185                  * The pause(3) is just to avoid race conditions where the thread
186                  * of control on an MP system gets past here (i.e., the signal is
187                  * not received instantaneously).
188                  */
189         }
190
191         if (lev == FATAL)
192         {
193
194                 /*
195                  * Assume that if we have detected the failure we can exit with a
196                  * normal exit status.  This will prevent the postmaster from
197                  * cleaning up when it's not needed.
198                  */
199                 fflush(stdout);
200                 fflush(stderr);
201                 ProcReleaseSpins(NULL); /* get rid of spinlocks we hold */
202                 ProcReleaseLocks();             /* get rid of real locks we hold */
203                 exitpg(0);
204         }
205
206         if (lev > FATAL)
207         {
208                 fflush(stdout);
209                 fflush(stderr);
210                 exitpg(lev);
211         }
212 }
213
214 #ifndef PG_STANDALONE
215 int
216 DebugFileOpen(void)
217 {
218         int                     fd,
219                                 istty;
220
221         Err_file = Debugfile = -1;
222         ElogDebugIndentLevel = 0;
223
224         if (OutputFileName[0])
225         {
226                 OutputFileName[MAXPGPATH - 1] = '\0';
227                 if ((fd = open(OutputFileName, O_CREAT | O_APPEND | O_WRONLY,
228                                            0666)) < 0)
229                         elog(FATAL, "DebugFileOpen: open of %s: %m",
230                                  OutputFileName);
231                 istty = isatty(fd);
232                 close(fd);
233
234                 /*
235                  * If the file is a tty and we're running under the postmaster,
236                  * try to send stdout there as well (if it isn't a tty then stderr
237                  * will block out stdout, so we may as well let stdout go wherever
238                  * it was going before).
239                  */
240                 if (istty &&
241                         IsUnderPostmaster &&
242                         !freopen(OutputFileName, "a", stdout))
243                         elog(FATAL, "DebugFileOpen: %s reopen as stdout: %m",
244                                  OutputFileName);
245                 if (!freopen(OutputFileName, "a", stderr))
246                         elog(FATAL, "DebugFileOpen: %s reopen as stderr: %m",
247                                  OutputFileName);
248                 Err_file = Debugfile = fileno(stderr);
249                 return (Debugfile);
250         }
251
252         /*
253          * If no filename was specified, send debugging output to stderr. If
254          * stderr has been hosed, try to open a file.
255          */
256         fd = fileno(stderr);
257         if (fcntl(fd, F_GETFD, 0) < 0)
258         {
259                 sprintf(OutputFileName, "%s/pg.errors.%d",
260                                 DataDir, (int) getpid());
261                 fd = open(OutputFileName, O_CREAT | O_APPEND | O_WRONLY, 0666);
262         }
263         if (fd < 0)
264                 elog(FATAL, "DebugFileOpen: could not open debugging file");
265
266         Err_file = Debugfile = fd;
267         return (Debugfile);
268 }
269
270 #endif