3 * Copyright (c) 2005-2008, The Android Open Source Project
4 * Copyright (c) 2012-2015 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 #include <queued_entry_timestamp.h>
23 #include <sys/types.h>
30 #define DEFAULT_LOGFILE_PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
33 * @addtogroup SHARED_FUNCTIONS
37 void logfile_init(struct log_file *l_file)
41 memset(l_file, 0, sizeof(struct log_file));
44 l_file->rotate_size_kbytes = DEFAULT_ROTATE_SIZE_KB;
45 l_file->max_rotated = DEFAULT_ROTATE_NUM_FILES;
46 l_file->format.format = FORMAT_BRIEF;
47 l_file->isatty = false;
48 l_file->colors_auto = true;
49 l_file->prev_sec = INT_MIN;
50 l_file->prev_nsec = INT_MIN;
51 l_file->buffer = (struct log_write_buffer) { };
54 bool logfile_init_buffer(struct log_file *l_file, size_t buf_size)
57 assert(l_file->buffer.size == 0);
62 l_file->buffer.data = malloc(buf_size);
63 if (!l_file->buffer.data) {
64 l_file->buffer = (struct log_write_buffer) { };
68 l_file->buffer.position = 0;
69 l_file->buffer.size = buf_size;
74 static void logfile_set_should_close(struct log_file *l_file, int on_off)
78 assert(l_file->fd >= 0);
80 l_file->should_close = !!on_off;
83 void logfile_set_fd(struct log_file *l_file, int fd, int should_close)
88 l_file->isatty = isatty(fd);
89 logfile_set_should_close(l_file, should_close);
92 int logfile_set_path(struct log_file *l_file, const char *path)
96 char *p = strdup(path);
107 static void logfile_close_if_needed(struct log_file *l_file)
111 if (l_file->fd >= 0 && l_file->should_close) {
113 logfile_set_should_close(l_file, 0);
119 void logfile_free(struct log_file *l_file)
127 if (l_file->buffer.data) {
128 logfile_flush(l_file);
129 free(l_file->buffer.data);
130 l_file->buffer.data = NULL;
131 l_file->buffer.position = 0;
132 l_file->buffer.size = 0;
134 logfile_close_if_needed(l_file);
137 static int logfile_update_fsize(struct log_file *l_file)
140 assert(l_file->fd >= 0);
144 if (fstat(l_file->fd, &st) < 0)
147 l_file->size = st.st_size;
151 static int logfile_open_internal(struct log_file *l_file)
154 assert(l_file->path);
156 logfile_close_if_needed(l_file);
158 int fd = open(l_file->path, O_CREAT | O_WRONLY | O_APPEND, DEFAULT_LOGFILE_PERM);
162 logfile_set_fd(l_file, fd, 1);
163 logfile_update_fsize(l_file);
168 void logfile_move(struct log_file *to, struct log_file *from)
174 from->buffer = (struct log_write_buffer) { };
178 * @brief Open a log file
179 * @details Open a log file into the passed structure.
180 * @param[in] l_file The file structure to contain the opened file descriptor
181 * @remarks Creates the file if it does not exist, else appends to it.
183 int logfile_open(struct log_file *l_file)
187 int r = logfile_open_internal(l_file);
191 r = logfile_rotate_needed(l_file);
193 logfile_do_rotate(l_file);
199 * @brief Checks if log file should be rotated
200 * @param[in] l_file The file structure to contain the currently opened file
201 * @remarks Updates l_file->size with on-disk file size
202 * @returns 1 if rotate is needed, 0 if not, -errno on error
204 int logfile_rotate_needed(struct log_file *l_file)
208 if (l_file->path == NULL || l_file->rotate_size_kbytes <= 0 || l_file->max_rotated <= 0)
211 logfile_update_fsize(l_file);
213 size_t size = l_file->size;
214 if (l_file->buffer.data)
215 size += l_file->buffer.position;
217 return BtoKiB(size) > l_file->rotate_size_kbytes;
221 * @brief Rotate log files
222 * @details Opens a new file and moves existing files further back
223 * @param[in] file The file structure to contain the currently opened file
225 void logfile_do_rotate(struct log_file *file)
231 char path0[PATH_MAX];
232 char path1[PATH_MAX];
234 if ((errno = -logfile_flush(file)) > 0)
235 ERR("while flushing log file");
237 for (i = file->max_rotated ; i > 0 ; i--) {
238 snprintf(path1, PATH_MAX, "%s.%d", file->path, i);
240 snprintf(path0, PATH_MAX, "%s", file->path);
242 snprintf(path0, PATH_MAX, "%s.%d", file->path, i - 1);
243 if (rename(path0, path1) < 0 && errno != ENOENT)
244 ERR("while rotating log file: %s", file->path);
247 /* open log file again */
248 logfile_open_internal(file);
251 static void logfile_add_timestamp(struct log_file *file, struct timespec ts)
253 file->prev_sec = ts.tv_sec;
254 file->prev_nsec = ts.tv_nsec;
257 int logfile_flush(struct log_file *file)
261 if (!file->buffer.data)
264 int written = write(file->fd, file->buffer.data, file->buffer.position);
266 file->buffer.position = 0; // TODO: data loss possibility here
271 * @brief Write with rotation
272 * @details Writes the entry to given file, automatically handling file rotation
273 * @param[in] e The entry to write
274 * @param[in] file The file to write to
275 * @returns 0 if log was successfully written, else 1
277 int logfile_write_with_rotation(const dlogutil_entry_s *e, struct log_file *file, dlogutil_sorting_order_e sort_by)
279 if (file->colors_auto)
280 file->format.color = file->isatty;
282 int written_bytes = 0;
285 if (dlogutil_entry_get_timestamp(e, sort_by, &ts) != TIZEN_ERROR_NONE)
288 if (ts.tv_sec < file->prev_sec || (ts.tv_sec == file->prev_sec && ts.tv_nsec < file->prev_nsec)) {
289 struct dlogutil_entry_with_msg msg;
290 memcpy(&msg, e, sizeof *e);
292 if (dlogutil_entry_get_tag(e, &tag) != TIZEN_ERROR_NONE)
294 int r = snprintf(msg.msg, sizeof msg.msg, "%s%c%s", tag, '\0', "INFO: Following log entry could not be sorted and is out of order.");
297 ERR("unable to format out-of-order message %m");
300 msg.header.len = r + 1 + sizeof *e;
302 written_bytes += log_print_log_line(file->format, file->fd, &msg.header, &file->buffer);
304 if (written_bytes < 0) {
305 ERR("unable to write out-of-order message %m");
311 written_bytes += log_print_log_line(file->format, file->fd, e, &file->buffer);
312 if (written_bytes <= 0)
314 file->size += written_bytes;
316 logfile_add_timestamp(file, ts);
318 if (logfile_rotate_needed(file))
319 logfile_do_rotate(file);