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
  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 *
  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
  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
 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
 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
 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 void
 206 setup_logging(const char *filename, unsigned flags)
 207 {
 208 #ifdef JDWP_LOGGING
 209     FILE *fp = NULL;
 210 
 211     /* Turn off logging */
 212     logging = 0;
 213     gdata->log_flags = 0;
 214 
 215     /* Just return if not doing logging */
 216     if ( filename==NULL || flags==0 )
 217         return;
 218 
 219     /* Create potential filename for logging */
 220     processPid = GETPID();
 221     (void)snprintf(logging_filename, sizeof(logging_filename),
 222                     "%s.%d", filename, (int)processPid);
 223 
 224     /* Turn on logging (do this last) */
 225     logging = 1;
 226     gdata->log_flags = flags;
 227 
 228 #endif
 229 }
 230 
 231 /* Finish up logging, flush output to the logfile. */
 232 void
 233 finish_logging(int exit_code)
 234 {
 235 #ifdef JDWP_LOGGING
 236     MUTEX_LOCK(my_mutex);
 237     if ( logging ) {
 238         logging = 0;
 239         if ( log_file != NULL ) {
 240             (void)fflush(log_file);
 241             (void)fclose(log_file);
 242             log_file = NULL;
 243         }
 244     }
 245     MUTEX_UNLOCK(my_mutex);
 246 #endif
 247 }