mailbox-log.c revision bcb4e51a409d94ae670de96afb8483a4f7855294
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen/* How often to reopen the log file to make sure that the changes are written
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen to the latest file. The main problem here is if the value is too high the
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen changes could be written to a file that was already rotated and deleted.
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen That wouldn't happen in any real world situations though, since the file
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen rotation time is probably measured in months or years. Still, each session
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen rarely writes anything here, so the value can just as well be a pretty small
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen one without any performance problems. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void mailbox_log_close(struct mailbox_log *log);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenstruct mailbox_log *mailbox_log_alloc(const char *path)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen log->filepath2 = i_strconcat(path, ".2", NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mailbox_log_free(struct mailbox_log **_log)
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainenstatic void mailbox_log_close(struct mailbox_log *log)
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainenvoid mailbox_log_set_permissions(struct mailbox_log *log, mode_t mode,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int mailbox_log_open(struct mailbox_log *log)
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen log->fd = open(log->filepath, O_RDWR | O_APPEND);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen /* try to create it */
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen log->fd = open(log->filepath, O_RDWR | O_APPEND | O_CREAT, 0666);
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainen i_error("creat(%s) failed: %m", log->filepath);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_error("%s", eacces_error_get("creat", log->filepath));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fchown(log->fd, (uid_t)-1, log->gid) < 0) {
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen i_error("fchown(%s) failed: %m", log->filepath);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic int mailbox_log_rotate_if_needed(struct mailbox_log *log)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("fstat(%s) failed: %m", log->filepath);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (rename(log->filepath, log->filepath2) < 0 && errno != ENOENT) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mailbox_log_record_set_timestamp(struct mailbox_log_record *rec,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainentime_t mailbox_log_record_get_timestamp(const struct mailbox_log_record *rec)
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen return (time_t) be32_to_cpu_unaligned(rec->timestamp);
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainenint mailbox_log_append(struct mailbox_log *log,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen /* we don't have to be too strict about appending to the latest log
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen file. the records' ordering doesn't matter and iteration goes
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen through both logs anyway. still, if there's a long running session
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen it shouldn't keep writing to a rotated log forever. */
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (log->open_timestamp/MAILBOX_LOG_REOPEN_SECS !=
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen /* We don't bother with locking, atomic appends will protect us.
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen If they don't (NFS), the worst that can happen is that a few
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen records get overwritten (because they're all the same size).
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen This whole log isn't supposed to be super-reliable anyway. */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen i_error("write(%s) failed: %m", log->filepath);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen i_error("write(%s) wrote %d/%u bytes", log->filepath,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (ftruncate(log->fd, st.st_size - ret) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool mailbox_log_iter_open_next(struct mailbox_log_iter *iter)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (iter->filepath == iter->log->filepath2)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen iter->fd = open(iter->filepath, O_RDONLY | O_APPEND);
06fb99af33bd380b382d2d4f2994cf9a5bf0bbaeTimo Sirainen i_error("open(%s) failed: %m", iter->filepath);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainenstruct mailbox_log_iter *mailbox_log_iter_init(struct mailbox_log *log)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainenmailbox_log_iter_next(struct mailbox_log_iter *iter)
5529671faac3c5672a948be93091056736c7afffTimo Sirainen ret = pread(iter->fd, iter->buf, sizeof(iter->buf),
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen i_error("pread(%s) failed: %m", iter->filepath);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen iter->offset += iter->count * sizeof(iter->buf[0]);
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen if (rec->type < MAILBOX_LOG_RECORD_DELETE_MAILBOX ||
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen (iter->count - iter->idx) * sizeof(iter->buf[0]);
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen i_error("Corrupted mailbox log %s at offset %"PRIuUOFF_T": "
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen "type=%d", iter->filepath, offset, rec->type);