1 /* 2 ** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 ** Distributed under the terms of the OpenBeOS License. 4 */ 5 6 7 #include "syslog_output.h" 8 9 #include <FindDirectory.h> 10 #include <Path.h> 11 12 #include <syslog.h> 13 #include <stdio.h> 14 #include <string.h> 15 #include <unistd.h> 16 #include <sys/stat.h> 17 18 19 static const size_t kMaxLogSize = 524288; // 512kB 20 21 static const char *kFacilities[] = { 22 "KERN", "USER", "MAIL", "DAEMON", 23 "AUTH", "SYSLOGD", "LPR", "NEWS", 24 "UUCP", "CRON", "AUTHPRIV", 25 "", "", "", "", "", 26 "LOCAL0", "LOCAL1", "LOCAL2", "LOCAL3", 27 "LOCAL4", "LOCAL5", "LOCAL6", "LOCAL7", 28 NULL 29 }; 30 static const int32 kNumFacilities = 24; 31 32 int sLog = -1; 33 char sLastMessage[1024]; 34 thread_id sLastThread; 35 int32 sRepeatCount; 36 37 38 static status_t 39 prepare_output() 40 { 41 bool needNew = true; 42 bool tooLarge = false; 43 44 if (sLog >= 0) { 45 // check file size 46 struct stat stat; 47 if (fstat(sLog, &stat) == 0) { 48 if (stat.st_size < kMaxLogSize) 49 needNew = false; 50 else 51 tooLarge = true; 52 } 53 } 54 55 if (needNew) { 56 // close old file; it'll be (re)moved soon 57 if (sLog >= 0) 58 close(sLog); 59 60 // get path 61 BPath base; 62 find_directory(/*B_COMMON_LOG_DIRECTORY*/B_COMMON_TEMP_DIRECTORY, &base); 63 // ToDo: change to correct "which" parameter! 64 65 BPath syslog(base); 66 syslog.Append("syslog"); 67 68 // move old file if it already exists 69 if (tooLarge) { 70 BPath oldlog(base); 71 oldlog.Append("syslog.old"); 72 73 remove(oldlog.Path()); 74 rename(syslog.Path(), oldlog.Path()); 75 76 // ToDo: just remove old file if space on device is tight? 77 } 78 79 bool haveSyslog = sLog >= 0; 80 81 // open file 82 sLog = open(syslog.Path(), O_APPEND | O_CREAT | O_WRONLY, 644); 83 if (!haveSyslog && sLog >=0) { 84 // first time open, check file size again 85 prepare_output(); 86 } 87 } 88 89 return sLog >= 0 ? B_OK : B_ERROR; 90 } 91 92 93 static status_t 94 write_to_log(const char *buffer, int32 length) 95 { 96 if (sRepeatCount > 0) { 97 char repeat[64]; 98 ssize_t size = snprintf(repeat, sizeof(repeat), 99 "Last message repeated %ld time%s\n", sRepeatCount, 100 sRepeatCount > 1 ? "s" : ""); 101 sRepeatCount = 0; 102 if (write(sLog, repeat, strlen(repeat)) < size) 103 return B_ERROR; 104 } 105 106 if (write(sLog, buffer, length) < length) 107 return B_ERROR; 108 109 return B_OK; 110 } 111 112 113 static void 114 syslog_output(syslog_message &message) 115 { 116 // did we get this message already? 117 if (message.from == sLastThread 118 && !strncmp(message.message, sLastMessage, sizeof(sLastMessage))) { 119 sRepeatCount++; 120 return; 121 } 122 123 char buffer[4096]; 124 125 #if 0 126 // parse & nicely print the time stamp from the message 127 struct tm when; 128 localtime_r(&message.when, &when); 129 int32 pos = strftime(buffer, sizeof(buffer), "%b %d, %H:%M:%S ", &when); 130 #else 131 int32 pos = 0; 132 #endif 133 134 // add facility 135 int facility = SYSLOG_FACILITY_INDEX(message.priority); 136 if (facility >= kNumFacilities) 137 facility = SYSLOG_FACILITY_INDEX(LOG_USER); 138 pos += snprintf(buffer + pos, sizeof(buffer) - pos, "%s", kFacilities[facility]); 139 140 // add ident/thread ID 141 if (message.ident[0] == '\0') { 142 // ToDo: find out team name? 143 } else 144 pos += snprintf(buffer + pos, sizeof(buffer) - pos, " '%s'", message.ident); 145 146 if (message.options & LOG_PID) 147 pos += snprintf(buffer + pos, sizeof(buffer) - pos, "[%ld]", message.from); 148 149 // add message itself 150 int32 length = pos + snprintf(buffer + pos, sizeof(buffer) - pos, ": %s\n", message.message); 151 152 // ToDo: be less lazy about it - there is virtually no reason to truncate the message 153 if (strlen(message.message) > sizeof(buffer) - pos - 1) 154 strcpy(&buffer[sizeof(buffer) - 8], "<TRUNC>\n"); 155 156 // dump message 157 158 if (prepare_output() < B_OK 159 || write_to_log(buffer, length) < B_OK) { 160 // cannot write to syslog! 161 fputs(buffer, stderr); 162 } 163 164 // save this message to suppress repeated messages 165 strlcpy(sLastMessage, message.message, sizeof(sLastMessage)); 166 sLastThread = message.from; 167 } 168 169 170 void 171 init_syslog_output(SyslogDaemon *daemon) 172 { 173 daemon->AddHandler(syslog_output); 174 } 175 176