00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "ink_config.h"
00025
00026 #include <assert.h>
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <stdarg.h>
00030 #include <string.h>
00031 #include <time.h>
00032
00033 #include <sys/time.h>
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <unistd.h>
00037 #include <sys/socket.h>
00038 #include <netinet/in.h>
00039 #include <arpa/inet.h>
00040 #include <netdb.h>
00041
00042 #include "P_RecProcess.h"
00043
00044
00045
00046
00047 #include "Compatability.h"
00048
00049 #include "LogUtils.h"
00050 #include "LogLimits.h"
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 int
00065 LogUtils::timestamp_to_str(long timestamp, char *buf, int size)
00066 {
00067 static const char *format_str = "%Y%m%d.%Hh%Mm%Ss";
00068 struct tm res;
00069 struct tm *tms;
00070 tms = ink_localtime_r((const time_t *) ×tamp, &res);
00071 return strftime(buf, size, format_str, tms);
00072 }
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 char *
00086 LogUtils::timestamp_to_netscape_str(long timestamp)
00087 {
00088 static char timebuf[64];
00089 static char gmtstr[16];
00090 static long last_timestamp = 0;
00091 static char bad_time[] = "Bad timestamp";
00092
00093
00094 if (timestamp < 0) {
00095 return bad_time;
00096 }
00097
00098
00099
00100
00101
00102 if (timestamp != last_timestamp) {
00103
00104
00105
00106
00107 #ifdef NEED_ALTZONE_DEFINED
00108 time_t altzone = timezone;
00109 #endif
00110 struct tm res;
00111 struct tm *tms = ink_localtime_r((const time_t *) ×tamp, &res);
00112
00113 #ifdef NEED_ALTZONE_DEFINED
00114 long zone = (tms->tm_isdst > 0) ? altzone : timezone;
00115 #else
00116 long zone = -tms->tm_gmtoff;
00117 #endif
00118 int offset;
00119 char sign;
00120
00121 if (zone >= 0) {
00122 offset = zone / 60;
00123 sign = '-';
00124 } else {
00125 offset = zone / -60;
00126 sign = '+';
00127 }
00128 int glen = snprintf(gmtstr, 16, "%c%.2d%.2d", sign, offset / 60, offset % 60);
00129
00130 strftime(timebuf, 64 - glen, "%d/%b/%Y:%H:%M:%S ", tms);
00131 ink_strlcat(timebuf, gmtstr, sizeof(timebuf));
00132 last_timestamp = timestamp;
00133 }
00134 return timebuf;
00135 }
00136
00137
00138
00139
00140
00141
00142
00143
00144 char *
00145 LogUtils::timestamp_to_date_str(long timestamp)
00146 {
00147 static char timebuf[64];
00148 static long last_timestamp = 0;
00149 static char bad_time[] = "Bad timestamp";
00150
00151
00152 if (timestamp < 0) {
00153 return bad_time;
00154 }
00155
00156
00157
00158
00159
00160 if (timestamp != last_timestamp) {
00161 struct tm res;
00162 struct tm *tms = ink_localtime_r((const time_t *) ×tamp, &res);
00163 strftime(timebuf, 64, "%Y-%m-%d", tms);
00164 last_timestamp = timestamp;
00165 }
00166 return timebuf;
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176 char *
00177 LogUtils::timestamp_to_time_str(long timestamp)
00178 {
00179 static char timebuf[64];
00180 static long last_timestamp = 0;
00181 static char bad_time[] = "Bad timestamp";
00182
00183
00184 if (timestamp < 0) {
00185 return bad_time;
00186 }
00187
00188
00189
00190
00191
00192 if (timestamp != last_timestamp) {
00193 struct tm res;
00194 struct tm *tms = ink_localtime_r((const time_t *) ×tamp, &res);
00195 strftime(timebuf, 64, "%H:%M:%S", tms);
00196 last_timestamp = timestamp;
00197 }
00198 return timebuf;
00199 }
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 void
00212 LogUtils::manager_alarm(LogUtils::AlarmType alarm_type, const char *msg, ...)
00213 {
00214 char msg_buf[LOG_MAX_FORMATTED_LINE];
00215 va_list ap;
00216
00217 ink_assert(alarm_type >= 0 && alarm_type < LogUtils::LOG_ALARM_N_TYPES);
00218
00219 if (msg == NULL) {
00220 snprintf(msg_buf, sizeof(msg_buf), "No Message");
00221 } else {
00222 va_start(ap, msg);
00223 vsnprintf(msg_buf, LOG_MAX_FORMATTED_LINE, msg, ap);
00224 va_end(ap);
00225 }
00226
00227 switch (alarm_type) {
00228 case LogUtils::LOG_ALARM_ERROR:
00229 RecSignalManager(REC_SIGNAL_LOGGING_ERROR, msg_buf);
00230 break;
00231
00232 case LogUtils::LOG_ALARM_WARNING:
00233 RecSignalManager(REC_SIGNAL_LOGGING_WARNING, msg_buf);
00234 break;
00235
00236 default:
00237 ink_assert(false);
00238 }
00239 }
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250 void
00251 LogUtils::strip_trailing_newline(char *buf)
00252 {
00253 if (buf != NULL) {
00254 int len =::strlen(buf);
00255 if (len > 0) {
00256 if (buf[len - 1] == '\n') {
00257 buf[len - 1] = '\0';
00258 }
00259 }
00260 }
00261 }
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 char *
00273 LogUtils::escapify_url(Arena *arena, char *url, size_t len_in, int *len_out, char *dst, size_t dst_size, const unsigned char *map)
00274 {
00275
00276
00277
00278
00279
00280
00281
00282 static const unsigned char codes_to_escape[32] = {
00283 0xFF, 0xFF, 0xFF, 0xFF,
00284 0xB4,
00285 0x00, 0x00,
00286 0x0A,
00287 0x00, 0x00, 0x00,
00288 0x1E, 0x80,
00289 0x00, 0x00,
00290 0x1F,
00291 0x00, 0x00, 0x00, 0x00,
00292 0x00, 0x00, 0x00, 0x00,
00293 0x00, 0x00, 0x00, 0x00,
00294 0x00, 0x00, 0x00, 0x00
00295 };
00296
00297 static char hex_digit[16] = {
00298 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
00299 'D', 'E', 'F'
00300 };
00301
00302 if (!url || (dst && dst_size < len_in)) {
00303 *len_out = 0;
00304 return NULL;
00305 }
00306
00307 if (!map)
00308 map = codes_to_escape;
00309
00310
00311
00312 int count = 0;
00313 char *p = url;
00314 char *in_url_end = url + len_in;
00315
00316 while (p < in_url_end) {
00317 unsigned char c = *p;
00318 if (map[c / 8] & (1 << (7 - c % 8))) {
00319 ++count;
00320 }
00321 ++p;
00322 }
00323
00324 if (!count) {
00325
00326
00327 *len_out = len_in;
00328 if (dst)
00329 ink_strlcpy(dst, url, dst_size);
00330 return url;
00331 }
00332
00333
00334
00335
00336
00337
00338
00339
00340 size_t out_len = len_in + 2 * count;
00341
00342 if (dst && out_len > dst_size) {
00343 *len_out = 0;
00344 return NULL;
00345 }
00346
00347
00348
00349
00350
00351 char *new_url;
00352
00353 if (dst)
00354 new_url = dst;
00355 else
00356 new_url = (char *) arena->str_alloc(out_len + 1);
00357
00358 char *from = url;
00359 char *to = new_url;
00360
00361 while (from < in_url_end) {
00362 unsigned char c = *from;
00363 if (map[c / 8] & (1 << (7 - c % 8))) {
00364 *to++ = '%';
00365 *to++ = hex_digit[c / 16];
00366 *to++ = hex_digit[c % 16];
00367 } else {
00368 *to++ = *from;
00369 }
00370 from++;
00371 }
00372 *to = '\0';
00373
00374 *len_out = out_len;
00375 return new_url;
00376 }
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387 void
00388 LogUtils::remove_content_type_attributes(char *type_str, int *type_len)
00389 {
00390 if (!type_str) {
00391 *type_len = 0;
00392 return;
00393 }
00394
00395
00396 char *p = (char *) memchr(type_str, ';', *type_len);
00397 if (p) {
00398 *type_len = p - type_str;
00399 }
00400 }
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 int
00417 LogUtils::timestamp_to_hex_str(unsigned ip, char *buf, size_t bufLen, size_t * numCharsPtr)
00418 {
00419 static const char *table = "0123456789abcdef@";
00420 int retVal = 1;
00421 int shift = 28;
00422 if (buf && bufLen > 0) {
00423 if (bufLen > 8)
00424 bufLen = 8;
00425 for (retVal = 0; retVal < (int) bufLen;) {
00426 buf[retVal++] = (char) table[((ip >> shift) & 0xf)];
00427 shift -= 4;
00428 }
00429
00430 if (numCharsPtr) {
00431 *numCharsPtr = (size_t) retVal;
00432 }
00433 retVal = (retVal == 8) ? 0 : 1;
00434 }
00435 return retVal;
00436 }
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455 int
00456 LogUtils::seconds_to_next_roll(time_t time_now, int rolling_offset, int rolling_interval)
00457 {
00458 struct tm lt;
00459 ink_localtime_r((const time_t *) &time_now, <);
00460 int sidl = lt.tm_sec + lt.tm_min * 60 + lt.tm_hour * 3600;
00461 int tr = rolling_offset * 3600;
00462 return ((tr >= sidl ? (tr - sidl) % rolling_interval : (86400 - (sidl - tr)) % rolling_interval));
00463 }
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485 int
00486 LogUtils::file_is_writeable(const char *full_filename,
00487 off_t * size_bytes, bool * has_size_limit, uint64_t * current_size_limit_bytes)
00488 {
00489 int ret_val = 0;
00490 int e;
00491 struct stat stat_data;
00492
00493 e = stat(full_filename, &stat_data);
00494 if (e == 0) {
00495
00496
00497
00498 if (!(stat_data.st_mode & S_IFREG || stat_data.st_mode & S_IFIFO)) {
00499 ret_val = 1;
00500 } else if (!(stat_data.st_mode & S_IWUSR)) {
00501 errno = EACCES;
00502 ret_val = -1;
00503 }
00504 if (size_bytes)
00505 *size_bytes = stat_data.st_size;
00506 } else {
00507
00508
00509 if (errno != ENOENT) {
00510
00511
00512 ret_val = -1;
00513 } else {
00514
00515
00516
00517 char *dir;
00518 char *prefix = 0;
00519
00520
00521
00522
00523 const char *slash = strrchr(full_filename, '/');
00524 if (slash) {
00525 size_t prefix_len = slash - full_filename + 1;
00526 prefix = new char[prefix_len + 1];
00527 memcpy(prefix, full_filename, prefix_len);
00528 prefix[prefix_len] = 0;
00529 dir = prefix;
00530 } else {
00531 dir = (char *) ".";
00532 }
00533
00534
00535
00536 e = access(dir, X_OK | W_OK);
00537 if (e < 0) {
00538 ret_val = -1;
00539 } else {
00540 if (size_bytes)
00541 *size_bytes = 0;
00542 }
00543
00544 if (prefix) {
00545 delete[]prefix;
00546 }
00547 }
00548 }
00549
00550
00551
00552 if (ret_val == 0) {
00553 struct rlimit limit_data;
00554 e = getrlimit(RLIMIT_FSIZE, &limit_data);
00555 if (e < 0) {
00556 ret_val = -1;
00557 } else {
00558 if (limit_data.rlim_cur != (rlim_t)RLIM_INFINITY) {
00559 if (has_size_limit)
00560 *has_size_limit = true;
00561 if (current_size_limit_bytes)
00562 *current_size_limit_bytes = limit_data.rlim_cur;
00563 } else {
00564 if (has_size_limit)
00565 *has_size_limit = false;
00566 }
00567 }
00568 }
00569
00570 return ret_val;
00571 }