1 /*
2  * Copyright (c) 2003, 2005, 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 static MUTEX_T my_mutex = MUTEX_INIT;
46 
47 /* Static variables (should be protected with mutex) */
48 static int logging;
49 static FILE * log_file;
50 static char logging_filename[MAXLEN_FILENAME+1+6];
51 static char location_stamp[MAXLEN_LOCATION+1];
52 static PID_T processPid;
53 static int open_count;
54 
55 /* Ascii id of current native thread. */
56 static void
get_time_stamp(char * tbuf,size_t ltbuf)57 get_time_stamp(char *tbuf, size_t ltbuf)
58 {
59     char format[MAXLEN_TIMESTAMP+1];
60     unsigned millisecs = 0;
61     time_t t = 0;
62 
63     GETMILLSECS(millisecs);
64     if ( time(&t) == (time_t)(-1) )
65         t = 0;
66     (void)strftime(format, sizeof(format),
67                 /* Break this string up for SCCS's sake */
68                 "%" "d.%" "m.%" "Y %" "T.%%.3d %" "Z", localtime(&t));
69     (void)snprintf(tbuf, ltbuf, format, (int)(millisecs));
70 }
71 
72 /* Get basename of filename */
73 static const char *
file_basename(const char * file)74 file_basename(const char *file)
75 {
76     char *p1;
77     char *p2;
78 
79     if ( file==NULL )
80         return "unknown";
81     p1 = strrchr(file, '\\');
82     p2 = strrchr(file, '/');
83     p1 = ((p1 > p2) ? p1 : p2);
84     if (p1 != NULL) {
85         file = p1 + 1;
86     }
87     return file;
88 }
89 
90 /* Fill in the exact source location of the LOG entry. */
91 static void
fill_location_stamp(const char * flavor,const char * file,int line)92 fill_location_stamp(const char *flavor, const char *file, int line)
93 {
94     (void)snprintf(location_stamp, sizeof(location_stamp),
95                     "%s:\"%s\":%d;",
96                     flavor, file_basename(file), line);
97     location_stamp[sizeof(location_stamp)-1] = 0;
98 }
99 
100 /* Begin a log entry. */
101 void
log_message_begin(const char * flavor,const char * file,int line)102 log_message_begin(const char *flavor, const char *file, int line)
103 {
104     MUTEX_LOCK(my_mutex); /* Unlocked in log_message_end() */
105     if ( logging ) {
106         location_stamp[0] = 0;
107         fill_location_stamp(flavor, file, line);
108     }
109 }
110 
111 /* Standard Logging Format Entry */
112 static void
standard_logging_format(FILE * fp,const char * datetime,const char * level,const char * product,const char * module,const char * optional,const char * messageID,const char * message)113 standard_logging_format(FILE *fp,
114         const char *datetime,
115         const char *level,
116         const char *product,
117         const char *module,
118         const char *optional,
119         const char *messageID,
120         const char *message)
121 {
122     const char *format;
123 
124     /* "[#|Date&Time&Zone|LogLevel|ProductName|ModuleID|
125      *     OptionalKey1=Value1;OptionalKeyN=ValueN|MessageID:MessageText|#]\n"
126      */
127 
128     format="[#|%s|%s|%s|%s|%s|%s:%s|#]\n";
129 
130     print_message(fp, "", "", format,
131             datetime,
132             level,
133             product,
134             module,
135             optional,
136             messageID,
137             message);
138 }
139 
140 /* End a log entry */
141 void
log_message_end(const char * format,...)142 log_message_end(const char *format, ...)
143 {
144     if ( logging ) {
145         va_list ap;
146         THREAD_T tid;
147         char datetime[MAXLEN_TIMESTAMP+1];
148         const char *level;
149         const char *product;
150         const char *module;
151         char optional[MAXLEN_INTEGER+6+MAXLEN_INTEGER+6+MAXLEN_LOCATION+1];
152         const char *messageID;
153         char message[MAXLEN_MESSAGE+1];
154 
155         /* Grab the location, start file if needed, and clear the lock */
156         if ( log_file == NULL && open_count == 0 && logging_filename[0] != 0 ) {
157             open_count++;
158             log_file = fopen(logging_filename, "w");
159             if ( log_file!=NULL ) {
160                 (void)setvbuf(log_file, NULL, _IOLBF, BUFSIZ);
161             } else {
162                 logging = 0;
163             }
164         }
165 
166         if ( log_file != NULL ) {
167 
168             /* Get the rest of the needed information */
169             tid = GET_THREAD_ID();
170             level = "FINEST"; /* FIXUP? */
171             product = "J2SE1.5"; /* FIXUP? */
172             module = "jdwp"; /* FIXUP? */
173             messageID = ""; /* FIXUP: Unique message string ID? */
174             (void)snprintf(optional, sizeof(optional),
175                         "LOC=%s;PID=%d;THR=t@%d",
176                         location_stamp,
177                         (int)processPid,
178                         (int)tid);
179 
180             /* Construct message string. */
181             va_start(ap, format);
182             (void)vsnprintf(message, sizeof(message), format, ap);
183             va_end(ap);
184 
185             get_time_stamp(datetime, sizeof(datetime));
186 
187             /* Send out standard logging format message */
188             standard_logging_format(log_file,
189                 datetime,
190                 level,
191                 product,
192                 module,
193                 optional,
194                 messageID,
195                 message);
196         }
197         location_stamp[0] = 0;
198     }
199     MUTEX_UNLOCK(my_mutex); /* Locked in log_message_begin() */
200 }
201 
202 #endif
203 
204 /* Set up the logging with the name of a logging file. */
205 /* ANDROID-CHANGED: Added directlog */
206 void
setup_logging(const char * filename,unsigned flags,int directlog)207 setup_logging(const char *filename, unsigned flags, int directlog)
208 {
209 #ifdef JDWP_LOGGING
210     FILE *fp = NULL;
211 
212     /* Turn off logging */
213     logging = 0;
214     gdata->log_flags = 0;
215 
216     /* Just return if not doing logging */
217     if ( filename==NULL || flags==0 )
218         return;
219 
220     /* Create potential filename for logging */
221     /* ANDROID-CHANGED: Add directlog */
222     if (directlog) {
223       strncpy(logging_filename, filename, sizeof(logging_filename));
224     } else {
225       processPid = GETPID();
226       (void)snprintf(logging_filename, sizeof(logging_filename),
227                       "%s.%d", filename, (int)processPid);
228     }
229 
230     /* Turn on logging (do this last) */
231     logging = 1;
232     gdata->log_flags = flags;
233 
234 #endif
235 }
236 
237 /* Finish up logging, flush output to the logfile. */
238 void
finish_logging()239 finish_logging()
240 {
241 #ifdef JDWP_LOGGING
242     MUTEX_LOCK(my_mutex);
243     if ( logging ) {
244         logging = 0;
245         if ( log_file != NULL ) {
246             (void)fflush(log_file);
247             (void)fclose(log_file);
248             log_file = NULL;
249         }
250     }
251     MUTEX_UNLOCK(my_mutex);
252 #endif
253 }
254