091b69b7f88873c42152bffa5233feeeef770902
[platform/core/security/ode.git] / server / file-sink.cpp
1 /*
2  *  Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License
15  */
16 #ifndef _GNU_SOURCE
17 #define _GNU_SOURCE
18 #endif
19
20 #include <iostream>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <chrono>
26 #include <errno.h>
27
28 #include "file-sink.h"
29
30 namespace ode {
31
32 #define MAX_LOG_LEN 16
33
34 namespace {
35 std::string getFileName(const std::string &path)
36 {
37         std::string name;
38         auto pos = path.rfind('/');
39         pos = (pos == std::string::npos) ? 0 : pos + 1;
40         name = path.substr(pos, path.size());
41         return name;
42 }
43 } //namespace
44
45 FileLogSink::FileLogSink(const std::string& name)
46         : path("/opt/var/log/"), fd(-1)
47 {
48         path.append(getFileName(name));
49         fd = ::open(path.c_str(), O_CREAT | O_RDWR | O_APPEND | O_SYNC, 0664);
50 }
51
52 FileLogSink::~FileLogSink()
53 {
54         ::close(fd);
55 }
56
57 void FileLogSink::resize()
58 {
59         std::lock_guard<std::recursive_mutex> lock(mtx);
60         struct stat st;
61         int ret = 0;
62         int blkcnt = MAX_LOG_LEN;
63         size_t blksize = 0;
64
65         if (::lstat(path.c_str(), &st) < 0) {
66                 std::cerr << "Invalid log file" << std::endl;
67                 return;
68         }
69
70         blksize = st.st_blksize;
71         if (blksize > 0)
72                 blkcnt = (st.st_size / blksize) + 1;
73
74         if (blkcnt <= MAX_LOG_LEN)
75                 return;
76
77         ret = ::fallocate(fd, FALLOC_FL_COLLAPSE_RANGE, 0, blksize*(blkcnt-MAX_LOG_LEN));
78         if (ret < 0)
79                 std::cerr << "Failed to collapse the log file : " << errno << std::endl;
80 }
81
82 void FileLogSink::write(const std::string &message)
83 {
84         std::lock_guard<std::recursive_mutex> lock(mtx);
85         resize();
86
87         auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
88         std::tm tm = {
89                 .tm_sec = 0,
90                 .tm_min = 0,
91                 .tm_hour = 0,
92                 .tm_mday = 1,
93                 .tm_mon = 1,
94                 .tm_year = 0,
95                 .tm_wday = 0,
96                 .tm_yday = 0,
97                 .tm_isdst = 1,
98         };
99
100         if (::localtime_r(&now, &tm) == nullptr)
101                 std::cerr << "Failed to get local time" << std::endl;
102
103         std::string log("[" + std::to_string(tm.tm_hour)
104                         + ":"
105                         + std::to_string(tm.tm_min)
106                         + ":"
107                         + std::to_string(tm.tm_sec) + "] ");
108
109         log.append(message);
110
111         size_t written = 0, size = log.size();
112         const char *data = log.c_str();
113
114         while (written < size) {
115                 int bytes = ::write(fd, data + written, size-written);
116                 if (bytes >= 0) {
117                         written += bytes;
118                 } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
119                         continue;
120                 } else {
121                         std::cerr << "Failed to write log" << std::endl;
122                         break;
123                 }
124         }
125         ::sync();
126 }
127
128 void FileLogSink::sink(const std::string &message)
129 {
130         auto level = message.substr(0, message.find('<'));
131         auto subMsg = message.substr(message.find(':') + 1);
132         std::string log;
133
134         switch (audit::StringToLogLevel(level)) {
135         case audit::LogLevel::Error:
136                 log.append("[ERROR] : " + subMsg);
137                 break;
138         case audit::LogLevel::Warning:
139                 log.append("[WARN] : " + subMsg);
140                 break;
141         case audit::LogLevel::Debug:
142                 log.append("[DEBUG] : " + subMsg);
143                 break;
144         case audit::LogLevel::Info:
145                 log.append("[INFO] : " + subMsg);
146                 break;
147         case audit::LogLevel::Trace:
148                 log.append("[TRACE] : " + subMsg);
149                 break;
150         default:
151                 log.append("[SILENT] : " + subMsg);
152                 break;
153         }
154
155         write(log);
156 }
157
158 } //namespace ode