1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <unistd.h> 29 #include <time.h> 30 #include <syslog.h> 31 #include <thread.h> 32 #include <string.h> 33 #include <strings.h> 34 #include <stdarg.h> 35 #include <sys/synch.h> 36 #include <sys/stat.h> 37 #include <sys/errno.h> 38 #include <ctype.h> 39 #include "eventlog.h" 40 41 #define LOGR_SYSLOG_PARSE_ENTRY_SUCCESS 0 42 #define LOGR_SYSLOG_PARSE_ENTRY_ERR -1 43 #define LOGR_SYSLOG_PARSE_NOPRI_ERR -2 44 45 #define LOGR_SYSLOG_PARSE_IDTOKEN_PFX "[ID" 46 47 typedef enum { 48 LOGR_SYSLOG_MONTH = 0, 49 LOGR_SYSLOG_DAY, 50 LOGR_SYSLOG_TIME, 51 LOGR_SYSLOG_MACHINENAME, 52 LOGR_SYSLOG_SOURCE, 53 LOGR_SYSLOG_ID, 54 LOGR_SYSLOG_PRI_FAC, 55 LOGR_SYSLOG_NARG 56 } logr_syslog_tokens; 57 58 typedef enum { 59 LOGR_SYSLOG_FACILITY = 0, 60 LOGR_SYSLOG_PRIORITY, 61 LOGR_SYSLOG_PRI_FAC_NARG 62 } logr_syslog_pri_fac_tokens; 63 64 /* 65 * Event code translation struct for use in processing config file 66 */ 67 typedef struct logr_code_tbl { 68 char *c_name; 69 int c_val; 70 } logr_code_tbl_t; 71 72 static logr_code_tbl_t logr_syslog_pri_names[] = { 73 "panic", LOG_EMERG, 74 "emerg", LOG_EMERG, 75 "alert", LOG_ALERT, 76 "crit", LOG_CRIT, 77 "err", LOG_ERR, 78 "error", LOG_ERR, 79 "warn", LOG_WARNING, 80 "warning", LOG_WARNING, 81 "notice", LOG_NOTICE, 82 "info", LOG_INFO, 83 "debug", LOG_DEBUG 84 }; 85 86 static logr_code_tbl_t logr_syslog_fac_names[] = { 87 "kern", LOG_KERN, 88 "user", LOG_USER, 89 "mail", LOG_MAIL, 90 "daemon", LOG_DAEMON, 91 "auth", LOG_AUTH, 92 "security", LOG_AUTH, 93 "syslog", LOG_SYSLOG, 94 "lpr", LOG_LPR, 95 "news", LOG_NEWS, 96 "uucp", LOG_UUCP, 97 "audit", LOG_AUDIT, 98 "cron", LOG_CRON, 99 "local0", LOG_LOCAL0, 100 "local1", LOG_LOCAL1, 101 "local2", LOG_LOCAL2, 102 "local3", LOG_LOCAL3, 103 "local4", LOG_LOCAL4, 104 "local5", LOG_LOCAL5, 105 "local6", LOG_LOCAL6, 106 "local7", LOG_LOCAL7 107 }; 108 109 typedef struct logr_syslog_node { 110 list_node_t ln_node; 111 char ln_logline[LOGR_MAXENTRYLEN]; 112 } logr_syslog_node_t; 113 114 /* 115 * Sets the loghost of an syslog entry. 116 * Returns 0 on success, -1 on failure. 117 */ 118 static int 119 logr_syslog_set_loghost(char *log_host, logr_entry_t *le) 120 { 121 if (log_host == NULL) 122 return (-1); 123 124 (void) strlcpy(le->le_hostname, log_host, MAXHOSTNAMELEN); 125 126 return (0); 127 } 128 129 /* 130 * Sets the timestamp of an syslog entry. 131 * Returns 0 on success, -1 on failure. 132 */ 133 static int 134 logr_syslog_set_timestamp(char *month, char *day, char *time, logr_entry_t *le) 135 { 136 struct timeval now; 137 struct tm tm, cur_tm; 138 char buf[30]; 139 140 if ((month == NULL) || (day == NULL) || (time == NULL)) 141 return (-1); 142 143 bzero(&tm, sizeof (tm)); 144 (void) snprintf(buf, 30, "%s %s %s", month, day, time); 145 if (strptime(buf, "%b" "%d" "%H:%M:%S", &tm) == NULL) 146 return (-1); 147 148 /* get the current dst, year and apply it. */ 149 if (gettimeofday(&now, NULL) != 0) 150 return (-1); 151 152 if (localtime_r(&now.tv_sec, &cur_tm) == NULL) 153 return (-1); 154 155 tm.tm_isdst = cur_tm.tm_isdst; 156 tm.tm_year = cur_tm.tm_year; 157 if (tm.tm_mon > cur_tm.tm_mon) 158 tm.tm_year = tm.tm_year - 1; 159 160 if ((le->le_timestamp.tv_sec = mktime(&tm)) == -1) 161 return (-1); 162 163 return (0); 164 } 165 166 /* 167 * Sets the Priority and Facility of an syslog entry. 168 * Returns 0 on success, -1 on failure. 169 */ 170 static int 171 logr_syslog_set_pri_fac(char *pf_tkn, logr_entry_t *le) 172 { 173 int pri_fac[LOGR_SYSLOG_PRI_FAC_NARG]; 174 int j, sz = 0; 175 176 le->le_pri = LOG_INFO; 177 178 if (pf_tkn == NULL) 179 return (-1); 180 181 /* Defaults */ 182 pri_fac[LOGR_SYSLOG_FACILITY] = LOG_USER; 183 pri_fac[LOGR_SYSLOG_PRIORITY] = LOG_INFO; 184 185 sz = sizeof (logr_syslog_fac_names) / sizeof (logr_syslog_fac_names[0]); 186 for (j = 0; j < sz; j++) { 187 if (strstr(pf_tkn, logr_syslog_fac_names[j].c_name) != NULL) { 188 pri_fac[LOGR_SYSLOG_FACILITY] = 189 logr_syslog_fac_names[j].c_val; 190 break; 191 } 192 } 193 194 sz = sizeof (logr_syslog_pri_names) / sizeof (logr_syslog_pri_names[0]); 195 for (j = 0; j < sz; j++) { 196 if (strstr(pf_tkn, logr_syslog_pri_names[j].c_name) != NULL) { 197 pri_fac[LOGR_SYSLOG_PRIORITY] = 198 logr_syslog_pri_names[j].c_val; 199 break; 200 } 201 } 202 203 le->le_pri = pri_fac[LOGR_SYSLOG_PRIORITY]; 204 205 return (0); 206 } 207 208 /* 209 * Sets the messages of an syslog entry. 210 */ 211 static void 212 logr_syslog_set_message(char *logline, logr_entry_t *le) 213 { 214 char *p; 215 216 if ((p = strchr(logline, '\n')) != NULL) 217 *p = '\0'; 218 219 (void) strlcpy(le->le_msg, logline, LOGR_MAXENTRYLEN); 220 } 221 222 /* 223 * Parses the tokens from an syslog entry. A typical syslog entry is of the 224 * following standard format, 225 * 226 * <month> <day> <time> <loghost> <source>: [ID <ID> <facility.priority>] <msg> 227 * For Example: 228 * Oct 29 09:49:20 pbgalaxy1 smbd[104039]: [ID 702911 daemon.info] init done. 229 * 230 * This method parses the above syslog entry and populates the log_entry_t 231 * structure from the parsed tokens. It returns the following return codes. 232 * 233 * Returns, 234 * LOGR_SYSLOG_PARSE_ENTRY_ERR: If the syslog entry is NULL, or there is 235 * error in parsing the entry or entry is 236 * not in the standard format. 237 * LOGR_SYSLOG_PARSE_NOPRI_ERR: If the priority of the message cannot be 238 * obtained from the parsed tokens. 239 * LOGR_SYSLOG_PARSE_ENTRY_SUCCESS: If the syslog entry is sucessfully 240 * parsed. 241 */ 242 static int 243 logr_syslog_parse_tokens(char *logline, logr_entry_t *le) 244 { 245 char *argv[LOGR_SYSLOG_NARG]; 246 int i; 247 boolean_t no_pri = B_TRUE; 248 249 for (i = 0; i < LOGR_SYSLOG_NARG; ++i) { 250 if ((argv[i] = strsep(&logline, " ")) == NULL) 251 return (LOGR_SYSLOG_PARSE_ENTRY_ERR); 252 253 (void) trim_whitespace(logline); 254 255 if ((i == LOGR_SYSLOG_ID) && 256 (strcmp(argv[i], LOGR_SYSLOG_PARSE_IDTOKEN_PFX) == 0)) { 257 i--; 258 no_pri = B_FALSE; 259 } 260 } 261 262 if (logr_syslog_set_timestamp(argv[LOGR_SYSLOG_MONTH], 263 argv[LOGR_SYSLOG_DAY], argv[LOGR_SYSLOG_TIME], le) < 0) 264 return (LOGR_SYSLOG_PARSE_ENTRY_ERR); 265 266 if (logr_syslog_set_loghost(argv[LOGR_SYSLOG_MACHINENAME], le) < 0) 267 return (LOGR_SYSLOG_PARSE_ENTRY_ERR); 268 269 if (no_pri) 270 return (LOGR_SYSLOG_PARSE_NOPRI_ERR); 271 272 if (logr_syslog_set_pri_fac(argv[LOGR_SYSLOG_PRI_FAC], le) < 0) 273 return (LOGR_SYSLOG_PARSE_NOPRI_ERR); 274 275 logr_syslog_set_message(logline, le); 276 277 return (LOGR_SYSLOG_PARSE_ENTRY_SUCCESS); 278 } 279 280 /* 281 * log_syslog_parse_entry 282 * 283 * Parse the given syslog entry into a log_entry_t structure. 284 * 285 * Returns, 286 * LOGR_SYSLOG_PARSE_ENTRY_SUCCESS: If the parsing is successful. 287 * An error code less than zero, if parsing fails. 288 */ 289 static int 290 logr_syslog_parse_entry(char *logline, logr_entry_t *le) 291 { 292 char *dup_logline; 293 int ret = LOGR_SYSLOG_PARSE_ENTRY_SUCCESS; 294 295 if (logline == NULL) 296 return (LOGR_SYSLOG_PARSE_ENTRY_ERR); 297 298 dup_logline = strdup(logline); 299 ret = logr_syslog_parse_tokens(dup_logline, le); 300 free(dup_logline); 301 302 switch (ret) { 303 case LOGR_SYSLOG_PARSE_NOPRI_ERR: 304 le->le_pri = LOG_INFO; 305 logr_syslog_set_message(logline, le); 306 ret = LOGR_SYSLOG_PARSE_ENTRY_SUCCESS; 307 break; 308 default: 309 break; 310 } 311 312 return (ret); 313 } 314 315 static void 316 logr_syslog_destroy_queue(list_t *queue) 317 { 318 logr_syslog_node_t *head; 319 320 while ((head = list_head(queue)) != NULL) { 321 list_remove(queue, head); 322 free(head); 323 } 324 list_destroy(queue); 325 } 326 327 static int 328 logr_syslog_construct_queue(FILE *fp, list_t *queue) 329 { 330 logr_syslog_node_t *node, *head; 331 int line_num = 0; 332 char logline[LOGR_MAXENTRYLEN]; 333 334 list_create(queue, sizeof (logr_syslog_node_t), 335 offsetof(logr_syslog_node_t, ln_node)); 336 337 bzero(logline, LOGR_MAXENTRYLEN); 338 while (fgets(logline, LOGR_MAXENTRYLEN, fp) != NULL) { 339 /* Read the last 1024 entries in the queue */ 340 if (line_num > LOGR_NMSGMASK) { 341 head = list_head(queue); 342 list_remove(queue, head); 343 free(head); 344 } 345 346 if ((node = malloc(sizeof (logr_syslog_node_t))) == NULL) { 347 logr_syslog_destroy_queue(queue); 348 return (-1); 349 } 350 bzero(node->ln_logline, LOGR_MAXENTRYLEN); 351 352 (void) strlcpy(node->ln_logline, logline, LOGR_MAXENTRYLEN); 353 list_insert_tail(queue, node); 354 bzero(logline, LOGR_MAXENTRYLEN); 355 line_num++; 356 } 357 358 return (0); 359 } 360 361 /* 362 * logr_syslog_load 363 * 364 * Loads the given log file into log_info_t structure format. 365 * 366 * Returns pointer to the allocated log structure on success. 367 * Note that the caller is responsible for freeing the allocated 368 * memory for returned log_info_t structure. 369 */ 370 static int 371 logr_syslog_load(FILE *fp, logr_info_t *log) 372 { 373 logr_entry_t *entry; 374 int i = 0; 375 376 list_t queue; 377 logr_syslog_node_t *node; 378 379 if (logr_syslog_construct_queue(fp, &queue) < 0) 380 return (-1); 381 382 node = list_head(&queue); 383 while (node) { 384 entry = &log->li_entry[i]; 385 386 if (logr_syslog_parse_entry(node->ln_logline, entry) != 387 LOGR_SYSLOG_PARSE_ENTRY_SUCCESS) { 388 node = list_next(&queue, node); 389 continue; 390 } 391 392 if (++i > LOGR_NMSGMASK) 393 break; 394 395 node = list_next(&queue, node); 396 } 397 398 logr_syslog_destroy_queue(&queue); 399 log->li_idx = i; 400 401 return (0); 402 } 403 404 /* 405 * logr_syslog_snapshot 406 * 407 * Return a snapshot of the given log in the buffer 408 * provided by the caller. Returns the number of entries in 409 * the log. 410 */ 411 int 412 logr_syslog_snapshot(logr_info_t *loginfo) 413 { 414 FILE *fp; 415 416 if (loginfo == NULL) 417 return (-1); 418 419 if ((fp = fopen("/var/adm/messages", "r")) == 0) 420 return (-1); 421 422 if (logr_syslog_load(fp, loginfo) < 0) { 423 (void) fclose(fp); 424 return (-1); 425 } 426 (void) fclose(fp); 427 428 if (loginfo->li_idx <= LOGR_NMSGMASK) 429 return (loginfo->li_idx); 430 431 return (LOGR_NMSGMASK+1); 432 } 433