static void logger_channel_file_flush(logger_channel* chan) { file_data* sd = (file_data*)chan->data; output_stream_flush(&sd->os); }
static ya_result counter_flush(output_stream* stream) { counter_output_stream_data* data = (counter_output_stream_data*)stream->data; if(ISOK(data->result)) { data->result = output_stream_flush(data->filtered); } return data->result; }
static ya_result logger_channel_file_vmsg(logger_channel* chan, int level, char* text, va_list args) { file_data* sd = (file_data*)chan->data; vosformat(&sd->os, text, args); ya_result ret = output_stream_write(&sd->os, (const u8*)"\n", 1); if(sd->force_flush) { output_stream_flush(&sd->os); } return ret; }
static ya_result logger_channel_file_constmsg(logger_channel* chan, int level, char* text, u32 text_len, u32 date_offset) { file_data* sd = (file_data*)chan->data; output_stream_write(&sd->os, (const u8*)text, text_len); ya_result ret = output_stream_write(&sd->os, (const u8*)"\n", 1); if(sd->force_flush) { output_stream_flush(&sd->os); } return ret; }
static void logger_channel_file_close(logger_channel* chan) { file_data* sd = (file_data*)chan->data; output_stream_flush(&sd->os); output_stream_close(&sd->os); free(sd->file_name); chan->vtbl = NULL; sd->os.data = NULL; sd->os.vtbl = NULL; free(chan->data); chan->data = NULL; }
static ya_result journal_ix_append_ixfr_stream(journal *jh, input_stream *ixfr_wire_is) { journal_ix *jix = (journal_ix*)jh; journal_ix_writelock(jix); /* * Move at the end of the file * Check that the wire starts with the last soa/serial * Append the wire * update the last serial */ // read the record ya_result return_value; dns_resource_record rr; dns_resource_record_init(&rr); if((return_value = dns_resource_record_read(&rr, ixfr_wire_is)) <= 0) { /* FAIL or EOF */ dns_resource_record_clear(&rr); journal_ix_writeunlock(jix); log_err("journal: ix: unable to read record: %r", return_value); return return_value; } /* * The first record is an SOA and our starting point (to be deleted) */ #ifdef DEBUG rdata_desc rdatadesc = {rr.tctr.qtype, rr.rdata_size, rr.rdata}; log_debug("journal: ix: DEL %{dnsname} %{typerdatadesc}", rr.name, &rdatadesc); #endif if(rr.tctr.qtype != TYPE_SOA) { u16 rtype = rr.tctr.qtype; dns_resource_record_clear(&rr); journal_ix_writeunlock(jix); log_err("journal: ix: expected SOA record but got %{dnstype} instead", &rtype); return ZDB_JOURNAL_SOA_RECORD_EXPECTED; } /* * check the journal file exists/is defined * do it now if not * proceed */ if(((jix->first_serial == 0) && (jix->last_serial == 0)) || (jix->fd == -1)) { /* the file does not exists yet */ if(FAIL(return_value = rr_soa_get_serial(rr.rdata, rr.rdata_size, &jix->first_serial))) { dns_resource_record_clear(&rr); journal_ix_writeunlock(jix); log_err("journal: ix: unable to read record: %r", return_value); return return_value; } int fd = open_create_ex(jix->journal_name, O_RDWR|O_CREAT, 0644); if(fd < 0) { return_value = ERRNO_ERROR; dns_resource_record_clear(&rr); journal_ix_writeunlock(jix); log_err("journal: ix: unable to open journal file '%s': %r", jix->journal_name, return_value); return return_value; } log_info("journal: ix: journal file created '%s'", jix->journal_name); jix->fd = fd; } if(FAIL(return_value = journal_ix_ensure_opened(jix))) { return return_value; } u64 valid_offset = lseek(jix->fd, 0, SEEK_END); u64 current_offset = valid_offset; u32 valid_serial = jix->last_serial; u32 potential_serial = valid_serial; s64 valid_page_offset = jix->last_page_offset; s64 potential_page_offset = current_offset; #ifdef DEBUG log_debug("journal: ix: ready to append to journal after serial %08x (%d) at offset %lld", valid_serial, valid_serial, valid_offset); #endif u8 mode = 0; /* 0: del, 1: add */ output_stream fos; output_stream bos; fd_output_stream_attach(&fos, jix->fd); buffer_output_stream_init(&bos, &fos, 512); for(;;) { /* write the first */ if(FAIL(return_value = dns_resource_record_write(&rr, &bos))) { /* this is VERY bad */ log_err("journal: ix: error writing a record to the journal: %r", return_value); break; } /* update the current offset */ current_offset += return_value; if((return_value = dns_resource_record_read(&rr, ixfr_wire_is)) <= 0) /* no bytes read OR error, there is no macro for this */ { /* error or end of stream */ if(return_value == 0) /* end of stream */ { if(mode != 0) /* on add mode so everything should be fine */ { valid_offset = current_offset; valid_serial = potential_serial; valid_page_offset = potential_page_offset; } else /* but on delete mode instead of add mode */ { log_err("journal: ix: ixfr stream unexpected eof"); return_value = UNEXPECTED_EOF; /* we have an error */ } } break; } if(rr.tctr.qtype == TYPE_SOA) { mode ^= 1; #ifdef DEBUG rdata_desc rdatadesc = {rr.tctr.qtype, rr.rdata_size, rr.rdata}; log_debug("journal: ix: %s %{dnsname} %{typerdatadesc}", (mode!=0)?"add":"del", rr.name, &rdatadesc); #endif if(mode == 0) { /* * new SOA to delete * * it's a new "page" (delete -> add) * * the offset before we write this record is the highest valid one in the file * so the error correcting truncation will be made at that offset */ valid_offset = current_offset; /* * the serial number that has been added with the previous page */ valid_serial = potential_serial; /* * the offset of the previous page */ valid_page_offset = potential_page_offset; /* * the new page starts here : update */ potential_page_offset = current_offset; } else { /* * new SOA add * * this is the second half of the page, we know what serial it is about */ if(FAIL(return_value = rr_soa_get_serial(rr.rdata, rr.rdata_size, &potential_serial))) { break; } } } #ifdef DEBUG else { rdata_desc rdatadesc = {rr.tctr.qtype, rr.rdata_size, rr.rdata}; log_debug("journal: ix: %s %{dnsname} %{typerdatadesc}", (mode!=0)?"add":"del", rr.name, &rdatadesc); } #endif } if(FAIL(return_value)) { /* * The journal is only valid up to valid_offset with serial ... */ log_err("journal: ix: rewinding journal up to last valid point (%lld)", valid_offset); ftruncate(jix->fd, valid_offset); } #ifdef DEBUG log_debug("journal: ix: page offset got from %d to %d", jix->last_page_offset, valid_page_offset); log_debug("journal: ix: serial got from %d to %d", jix->last_serial, valid_serial); #endif jix->last_page_offset = valid_page_offset; jix->last_serial = valid_serial; /* * rename the file */ if(ISOK(return_value)) { char new_name[PATH_MAX]; memcpy(new_name, jix->journal_name, jix->journal_name_len); snformat(&new_name[jix->journal_name_len - FIRST_FROM_END], 8 + 1 + 8 + 1 + IX_EXT_STRLEN + 1, "%08x-%08x." IX_EXT , jix->first_serial, jix->last_serial); if(rename(jix->journal_name, new_name) >= 0) { memcpy(jix->journal_name, new_name, jix->journal_name_len); } } /* */ #ifdef DEBUG log_debug("journal: ix: fd=%i from=%08x to=%08x soa@%lld file=%s", jix->fd, jix->first_serial, jix->last_serial, jix->last_page_offset, (jix->journal_name!=NULL)?jix->journal_name:"NONE-YET"); #endif output_stream_flush(&bos); fd_output_stream_detach(buffer_output_stream_get_filtered(&bos)); output_stream_close(&bos); dns_resource_record_clear(&rr); journal_ix_writeunlock(jix); if(ISOK(return_value)) { #ifdef DEBUG log_debug("journal: ix: page added (fd=%i from=%08x to=%08x soa@%lld file=%s): %r", jix->fd, jix->first_serial, jix->last_serial, jix->last_page_offset, (jix->journal_name!=NULL)?jix->journal_name:"NONE-YET", return_value); #endif return TYPE_IXFR; /* that's what the caller expects to handle the new journal pages */ } else { log_err("journal: ix: failed to add page"); return return_value; } }
static ya_result logger_channel_file_reopen(logger_channel* chan) { ya_result return_code; file_data* sd = (file_data*)chan->data; output_stream_flush(&sd->os); /* open a new file stream */ output_stream errlog_os; if(FAIL(return_code = file_output_stream_open_ex(sd->file_name, O_CREAT|O_APPEND|O_RDWR, sd->mode, &errlog_os))) { logger_channel_file_flush(chan); logger_channel_file_msg(chan, LOG_NOTICE, "unable to reopen '%s': %r, resuming on original", sd->file_name, return_code); logger_channel_file_flush(chan); return return_code; } /* change ownership of the file */ int fd = fd_output_stream_get_filedescriptor(&errlog_os); if(fchown(fd, sd->uid, sd->gid) < 0) { return_code = ERRNO_ERROR; output_stream_close(&errlog_os); logger_channel_file_flush(chan); logger_channel_file_msg(chan, LOG_NOTICE, "unable to fchown '%s': %r, resuming on original", sd->file_name, return_code); logger_channel_file_flush(chan); return return_code; } logger_channel_file_flush(chan); logger_channel_file_msg(chan, LOG_NOTICE, "reopening '%s'", sd->file_name); logger_channel_file_flush(chan); output_stream* fos = buffer_output_stream_get_filtered(&sd->os); /* exchange the file descriptors */ fd_output_stream_attach(fd, fos); fd_output_stream_attach(sd->fd, &errlog_os); sd->fd = fd; output_stream_close(&errlog_os); logger_channel_file_flush(chan); logger_channel_file_msg(chan, LOG_NOTICE, "reopened '%s'", sd->file_name); logger_channel_file_flush(chan); return return_code; }
static void stdstream_flush_both_terms() { output_stream_flush(&__termout__); output_stream_flush(&__termerr__); }