1 /********************************************************************************
2  *                              Nepenthes
3  *                        - finest collection -
4  *
5  *
6  *
7  * Copyright (C) 2005  Paul Baecher & Markus Koetter
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22  *
23  *
24  *             contact nepenthesdev@users.sourceforge.net
25  *
26  *******************************************************************************/
27 
28 /* $Id: RingFileLogger.cpp 697 2006-11-11 09:17:19Z common $ */
29 
30 #include <ctime>
31 
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <cstdio>
36 #include <cstdlib>
37 #include <cstring>
38 #include <string>
39 #include <cerrno>
40 #include <pwd.h>
41 #include <grp.h>
42 
43 #include "RingFileLogger.hpp"
44 #include "Nepenthes.hpp"
45 #include "LogManager.hpp"
46 
47 using namespace nepenthes;
48 using namespace std;
49 
50 
RingFileLogger(LogManager * lm)51 RingFileLogger::RingFileLogger(LogManager *lm) //: LogHandler(lm)
52 {
53 	m_FileFormat = 0;
54 	m_FirstFile = 0;
55 	m_MaxFiles = 0;
56 	m_MaxSize = 0;
57 	m_LogManager = lm;
58 }
59 
60 
~RingFileLogger()61 RingFileLogger::~RingFileLogger()
62 {
63 	if (m_FileFormat != NULL)
64 	{
65 		free(m_FileFormat);
66 	}
67 
68 	if (m_FirstFile != NULL)
69 	{
70     	free(m_FirstFile);
71 	}
72 }
73 
74 
setLogFileFormat(char * fmt)75 void RingFileLogger::setLogFileFormat(char *fmt)
76 {
77 	if (m_FileFormat != NULL)
78 	{
79 		free(m_FileFormat);
80 	}
81 	m_FileFormat = strdup(fmt);
82 
83 
84 	if (m_FirstFile != NULL)
85 	{
86 		free(m_FirstFile);
87 	}
88 	asprintf(&m_FirstFile, m_FileFormat, 0);
89 }
90 
setMaxFiles(uint8_t count)91 void RingFileLogger::setMaxFiles(uint8_t count)
92 {
93 	m_MaxFiles = count;
94 }
95 
setMaxSize(size_t size)96 void RingFileLogger::setMaxSize(size_t size)
97 {
98 	m_MaxSize = size;
99 }
100 
rotate()101 void RingFileLogger::rotate()
102 {
103 	int32_t i;
104 	static char filename[0xff], newfilename[0xff];
105 
106 	snprintf(filename, sizeof(filename), m_FileFormat, m_MaxFiles - 1);
107 	unlink(filename);
108 
109 	for( i = m_MaxFiles - 2; i >= 0; i-- )
110 	{
111 		snprintf(filename, sizeof(filename), m_FileFormat, i);
112 		snprintf(newfilename, sizeof(newfilename), m_FileFormat, i + 1);
113 
114 		rename(filename, newfilename);
115 	}
116 }
117 
log(uint32_t mask,const char * message)118 void RingFileLogger::log(uint32_t mask, const char *message)
119 {
120 	if( !m_FileFormat || !m_MaxSize || !m_MaxFiles )
121 		return;
122 
123 	FILE *f;
124 
125 	if( !(f = fopen(m_FirstFile, "a")) )
126 		return;
127 
128 	struct tm       t;
129 	time_t          stamp;
130 	time(&stamp);
131 
132 #ifdef WIN32
133 	struct tm *pt =localtime(&stamp);
134 	memcpy(&t,pt,sizeof(struct tm));
135 #else
136 	localtime_r(&stamp, &t);
137 #endif
138 
139 
140 	string tag = "";
141 	for ( uint32_t i = 0; i < MAX_TAGS; i++ )
142 		if ( (1 << i) & mask  )
143 		{
144 			tag += " ";
145 			tag += m_LogManager->getTagName(i);
146 		}
147 
148     fprintf(f, "[%02d%02d%04d %02d:%02d:%02d%s] %s", t.tm_mday, t.tm_mon + 1, t.tm_year + 1900,
149 			 t.tm_hour, t.tm_min, t.tm_sec, tag.c_str(), message);
150 
151 	struct stat s;
152 
153 	fclose(f);
154 
155 	// rotation needed?
156 	stat(m_FirstFile, &s);
157 
158 	if( (uint32_t)s.st_size > m_MaxSize )
159 		rotate();
160 }
161 
162 
163 
setOwnership(uid_t uid,gid_t gid)164 bool RingFileLogger::setOwnership(uid_t uid, gid_t gid)
165 {
166 #if !defined(CYGWIN) && !defined(CYGWIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) && !defined(WIN32)
167 	char filename[0xff];
168 	struct stat s;
169 
170 	for ( int32_t i = 0; i < m_MaxFiles; i++ )
171 	{
172 		snprintf(filename, sizeof(filename), m_FileFormat, i);
173 		int32_t filestat = stat(filename, &s);
174 
175 		if ( filestat != 0 )
176 		{
177 			if ( errno == ENOENT )
178 			{
179 				logInfo("Creating logfile %s\n",filename);
180 				FILE *f = fopen(filename,"w");
181 				if (f == NULL)
182 				{
183                    	logCrit("Logfile %s does not exist, creating failed with %s\n", filename,strerror(errno));
184 					return false;
185 				}
186 				fclose(f);
187 			}
188 			else
189 			{
190 				logCrit("Could not access logfile %s: %s\n", filename, strerror(errno));
191 				return false;
192 			}
193 		}
194 
195 		if( s.st_uid != uid || s.st_gid != gid )
196 		{
197 			if ( chown(filename, uid, gid) != 0 )
198 			{
199 				logCrit("Failed to change ownership for file %s: %s\n", filename, strerror(errno));
200 				return false;
201 			}
202 
203 			logInfo("Logfile %s ownership is now %d:%d (%s:%s)\n", filename, uid, gid, getpwuid(uid)->pw_name,
204 				getgrgid(gid)->gr_name);
205 		}
206 	}
207 #endif
208 
209 	return true;
210 }
211 
212 
213