1/*
2 * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26#include "util.h"
27
28#include <time.h>
29#include <errno.h>
30#include <sys/types.h>
31
32#include "proc_md.h"
33
34#include "log_messages.h"
35
36#ifdef JDWP_LOGGING
37
38#define MAXLEN_INTEGER 20
39#define MAXLEN_FILENAME 256
40#define MAXLEN_TIMESTAMP 80
41#define MAXLEN_LOCATION (MAXLEN_FILENAME+MAXLEN_INTEGER+16)
42#define MAXLEN_MESSAGE 256
43#define MAXLEN_EXEC (MAXLEN_FILENAME*2+MAXLEN_INTEGER+16)
44
45#define TIMESTAMP_SIZE (MAXLEN_TIMESTAMP+1)
46#define MAXLEN_DT 19 // "DD.MM.YYYY HH:MM:SS"
47#define MAXLEN_MS 5 // ".mmm "
48#define DT_SIZE (MAXLEN_DT+1)
49#define TZ_SIZE (TIMESTAMP_SIZE-MAXLEN_DT-MAXLEN_MS)
50
51static MUTEX_T my_mutex = MUTEX_INIT;
52
53/* Static variables (should be protected with mutex) */
54static int logging;
55static FILE * log_file;
56static char logging_filename[MAXLEN_FILENAME+1+6];
57static char location_stamp[MAXLEN_LOCATION+1];
58static PID_T processPid;
59static int open_count;
60
61/*
62 * "DD.MM.YYYY HH:MM:SS.mmm <TZ>"
63 */
64static void
65get_time_stamp(char *tbuf, size_t ltbuf)
66{
67 char timestamp_date_time[DT_SIZE];
68 char timestamp_timezone[TZ_SIZE];
69 unsigned millisecs = 0;
70 time_t t = 0;
71
72 GETMILLSECS(millisecs);
73 if ( time(&t) == (time_t)(-1) ) {
74 t = 0;
75 }
76
77 (void)strftime(timestamp_date_time, DT_SIZE,
78 "%d.%m.%Y %T", localtime(&t));
79 (void)strftime(timestamp_timezone, TZ_SIZE,
80 "%Z", localtime(&t));
81 (void)snprintf(tbuf, ltbuf,
82 "%s.%.3d %s", timestamp_date_time,
83 (int)(millisecs), timestamp_timezone);
84}
85
86/* Get basename of filename */
87static const char *
88file_basename(const char *file)
89{
90 char *p1;
91 char *p2;
92
93 if ( file==NULL )
94 return "unknown";
95 p1 = strrchr(file, '\\');
96 p2 = strrchr(file, '/');
97 p1 = ((p1 > p2) ? p1 : p2);
98 if (p1 != NULL) {
99 file = p1 + 1;
100 }
101 return file;
102}
103
104/* Fill in the exact source location of the LOG entry. */
105static void
106fill_location_stamp(const char *flavor, const char *file, int line)
107{
108 (void)snprintf(location_stamp, sizeof(location_stamp),
109 "%s:\"%s\":%d;",
110 flavor, file_basename(file), line);
111 location_stamp[sizeof(location_stamp)-1] = 0;
112}
113
114/* Begin a log entry. */
115void
116log_message_begin(const char *flavor, const char *file, int line)
117{
118 MUTEX_LOCK(my_mutex); /* Unlocked in log_message_end() */
119 if ( logging ) {
120 location_stamp[0] = 0;
121 fill_location_stamp(flavor, file, line);
122 }
123}
124
125/* Standard Logging Format Entry */
126static void
127standard_logging_format(FILE *fp,
128 const char *datetime,
129 const char *level,
130 const char *product,
131 const char *module,
132 const char *optional,
133 const char *messageID,
134 const char *message)
135{
136 const char *format;
137
138 /* "[#|Date&Time&Zone|LogLevel|ProductName|ModuleID|
139 * OptionalKey1=Value1;OptionalKeyN=ValueN|MessageID:MessageText|#]\n"
140 */
141
142 format="[#|%s|%s|%s|%s|%s|%s:%s|#]\n";
143
144 print_message(fp, "", "", format,
145 datetime,
146 level,
147 product,
148 module,
149 optional,
150 messageID,
151 message);
152}
153
154/* End a log entry */
155void
156log_message_end(const char *format, ...)
157{
158 if ( logging ) {
159 va_list ap;
160 THREAD_T tid;
161 char datetime[MAXLEN_TIMESTAMP+1];
162 const char *level;
163 const char *product;
164 const char *module;
165 char optional[MAXLEN_INTEGER+6+MAXLEN_INTEGER+6+MAXLEN_LOCATION+1];
166 const char *messageID;
167 char message[MAXLEN_MESSAGE+1];
168
169 /* Grab the location, start file if needed, and clear the lock */
170 if ( log_file == NULL && open_count == 0 && logging_filename[0] != 0 ) {
171 open_count++;
172 log_file = fopen(logging_filename, "w");
173 if ( log_file!=NULL ) {
174 (void)setvbuf(log_file, NULL, _IOLBF, BUFSIZ);
175 } else {
176 logging = 0;
177 }
178 }
179
180 if ( log_file != NULL ) {
181
182 /* Get the rest of the needed information */
183 tid = GET_THREAD_ID();
184 level = "FINEST"; /* FIXUP? */
185 product = "J2SE1.5"; /* FIXUP? */
186 module = "jdwp"; /* FIXUP? */
187 messageID = ""; /* FIXUP: Unique message string ID? */
188 (void)snprintf(optional, sizeof(optional),
189 "LOC=%s;PID=%d;THR=t@%d",
190 location_stamp,
191 (int)processPid,
192 (int)(intptr_t)tid);
193
194 /* Construct message string. */
195 va_start(ap, format);
196 (void)vsnprintf(message, sizeof(message), format, ap);
197 message[sizeof(message) - 1] = 0;
198 va_end(ap);
199
200 get_time_stamp(datetime, sizeof(datetime));
201
202 /* Send out standard logging format message */
203 standard_logging_format(log_file,
204 datetime,
205 level,
206 product,
207 module,
208 optional,
209 messageID,
210 message);
211 }
212 location_stamp[0] = 0;
213 }
214 MUTEX_UNLOCK(my_mutex); /* Locked in log_message_begin() */
215}
216
217#endif
218
219/* Set up the logging with the name of a logging file. */
220void
221setup_logging(const char *filename, unsigned flags)
222{
223#ifdef JDWP_LOGGING
224 FILE *fp = NULL;
225
226 /* Turn off logging */
227 logging = 0;
228 gdata->log_flags = 0;
229
230 /* Just return if not doing logging */
231 if ( filename==NULL || flags==0 )
232 return;
233
234 /* Create potential filename for logging */
235 processPid = GETPID();
236 (void)snprintf(logging_filename, sizeof(logging_filename),
237 "%s.%d", filename, (int)processPid);
238
239 /* Turn on logging (do this last) */
240 logging = 1;
241 gdata->log_flags = flags;
242
243#endif
244}
245
246/* Finish up logging, flush output to the logfile. */
247void
248finish_logging()
249{
250#ifdef JDWP_LOGGING
251 MUTEX_LOCK(my_mutex);
252 if ( logging ) {
253 logging = 0;
254 if ( log_file != NULL ) {
255 (void)fflush(log_file);
256 (void)fclose(log_file);
257 log_file = NULL;
258 }
259 }
260 MUTEX_UNLOCK(my_mutex);
261#endif
262}
263