/*
* $Id: journal.c,v 1.11 2002/10/17 20:02:30 ljb Exp $
* originally Id: journal.c,v 1.13 1998/06/23 23:30:44 gerald Exp
*/
#include <stdio.h>
#include <string.h>
#include "mrt.h"
#include "trace.h"
#include <time.h>
#include <signal.h>
#include "config_file.h"
#include <sys/stat.h>
#include <fcntl.h>
#include "irrd.h"
extern trace_t *default_trace;
void make_journal_name (char * dbname, int journal_ext, char * journal_name);
/* journal_irr_update
* Record what we're doing to the database in the <DB>.journal file
* if mode == IRR_UPDATE then an add
*/
/* JW this routine can be speeded up. We know the offset and length
of the object, lets read it and write it with two sys calls
*/
void journal_irr_update (irr_database_t *db, irr_object_t *object,
int mode, int skip_obj) {
char buffer[BUFSIZE+1];
char *sadd = "ADD\n\n";
char *sdelete = "DEL\n\n";
db->serial_number++;
/* until we have our syntax checker, just copy the serial as is */
#ifdef notdef /* serial numbers will get messed up if we actually skip */
if (!skip_obj) /* don't put bogus/filtered objects in journal file */
#endif
{
journal_log_serial_number (db);
if (mode == IRR_UPDATE)
write (db->journal_fd, sadd, strlen (sadd));
else if (mode == IRR_DELETE)
write (db->journal_fd, sdelete, strlen (sdelete));
else {
trace (ERROR, default_trace,"ERROR journal.c: journal_write_serial(): unrecognized mode (%d) db-(%s)\n", mode, db->name);
return;
/*
write (db->journal_fd, snomode, strlen (snomode));
*/
}
fseek (object->fp, object->offset, SEEK_SET);
while (fgets (buffer, BUFSIZE, object->fp) != NULL) {
if (strlen (buffer) < 2) break;
write (db->journal_fd, buffer, strlen (buffer));
}
strcpy (buffer, "\n");
write (db->journal_fd, buffer, strlen (buffer));
}
/* whew! The change is on disk, so we can save the new serial number */
write_irr_serial (db);
return;
}
/* journal_log_serial_number
* For crash recovery and when we act as a mirror server,
* stamp the <DB>.journal file with the current serial
* number for the database
*/
void journal_log_serial_number (irr_database_t *database) {
char buffer[512];
sprintf (buffer, "%s SERIAL %ld\n", "%", database->serial_number);
write (database->journal_fd, buffer, strlen (buffer));
return;
}
/* if the journal file is too big, roll it over and create a <db>.JOURNAL.old
* or something like that
*/
void journal_maybe_rollover (irr_database_t *database) {
struct stat buf;
char file_old[BUFSIZE], file_new[BUFSIZE];
fstat(database->journal_fd, &buf);
if (buf.st_size > IRR_MAX_JOURNAL_SIZE) {
trace (NORM, default_trace, "Rolling Journal file (> %d bytes) for %s\n",
IRR_MAX_JOURNAL_SIZE, database->name);
make_journal_name (database->name, JOURNAL_NEW, file_new);
make_journal_name (database->name, JOURNAL_OLD, file_old);
close (database->journal_fd);
rename(file_new, file_old);
if ((database->journal_fd = open (file_new, O_RDWR | O_CREAT, 0664)) < 0)
trace (NORM, default_trace, "**** ERROR **** Could not open %s (%s)!\n",
file_new, strerror (errno));
}
return;
}
/*
* return 1 if *.JOURNAL file exists and a valid serial # header is found
* otherwise return 0
* return value of first good serial found if possible
*/
int find_oldest_serial (char *dbname, int journal_ext, u_long *oldestserial) {
char file[BUFSIZE], buf[BUFSIZE];
FILE *fp;
make_journal_name (dbname, journal_ext, file);
if ((fp = fopen (file, "r")) != NULL) {
while (fgets (buf, sizeof (buf) - 1, fp) != NULL) {
if (sscanf (buf, "%% SERIAL %s", file) == 1) {
fclose (fp);
if (convert_to_lu (file, oldestserial) < 0)
return (0);
return (1);
}
}
}
if (fp != NULL)
fclose (fp);
return (0);
}
/*
* return 1 if *.CURRENTSERIAL is read without error
* else return -1
*/
int get_current_serial (char *dbname, u_long *currserial) {
char tmp[BUFSIZE], file[BUFSIZE];
int ret_val = -1;
FILE *fp;
strcpy (tmp, dbname);
convert_toupper(tmp);
sprintf (file, "%s/%s.CURRENTSERIAL", IRR.database_dir, tmp);
if ((fp = fopen (file, "r")) != NULL) {
memset (tmp, 0, sizeof (tmp));
if (fgets (tmp, sizeof (tmp) - 1, fp) != NULL &&
convert_to_lu (tmp, currserial) > 0)
ret_val = 1;
fclose (fp);
}
return (ret_val);
}
void make_journal_name (char * dbname, int journal_ext, char * journal_name) {
if (journal_ext == JOURNAL_NEW)
sprintf (journal_name, "%s/%s.%s", IRR.database_dir, dbname, SJOURNAL_NEW);
else
sprintf (journal_name, "%s/%s.%s", IRR.database_dir, dbname, SJOURNAL_OLD);
}
#define FLS_BUFSIZE 2048
#define FLS_OVERFLOW 12 /* 99 billion + NL */
/*
* return 0 if unable to find a serial number, or there are problems opening
* or reading JOURNAL file.
* return 1 if found
*/
int find_last_serial (char *dbname, int journal_ext, u_long *last_serial) {
char file[BUFSIZE], sz_serialno[BUFSIZE];
char buf [FLS_BUFSIZE + FLS_OVERFLOW + 1];
off_t offset;
ssize_t bytes_read, bytes_to_read = FLS_BUFSIZE;
int off_by_one = 0;
int i, fd = -1;
FILE *fp;
make_journal_name (dbname, journal_ext, file);
if ((fp = fopen (file, "r")) != NULL) {
fd = fileno (fp);
memset(buf, 0, FLS_BUFSIZE + FLS_OVERFLOW + 1);
/* Find end of file */
offset = lseek (fd, 0L, SEEK_END);
if (offset == -1) {
goto FAIL;
}
while (offset > 0) {
offset = MAX((offset - FLS_BUFSIZE), 0);
/* We should really check return here */
lseek(fd, offset, SEEK_SET);
bytes_read = read (fd, buf, bytes_to_read);
if (bytes_read <= 0) {
/* We probably should throw a trace here */
goto FAIL;
}
/* Start at end of buffer, work towards front looking for % SERIAL */
for (i = bytes_read + off_by_one; (i >= 0) && (buf[i] != '%'); i--);
off_by_one = 0;
if ((i > 0) || ((i == 0) && (offset == 0))) {
/* We've found the % */
/* It either at start of file or has a preceding NL */
if ((i == 0) || (buf[i-1] == '\n')) {
sscanf(buf+i, "%% SERIAL %s\n", sz_serialno);
if (convert_to_lu (sz_serialno, last_serial) < 0)
goto FAIL;
else {
fclose (fp);
return (1);
}
break;
}
}
else if (i == 0) { /* And offset != 0 */
off_by_one = 1;
}
if (offset <= bytes_to_read) { bytes_to_read = offset; }
memcpy(buf + bytes_to_read, buf, ((FLS_OVERFLOW+FLS_BUFSIZE)-bytes_to_read));
}
}
FAIL:
if (fd >= 0) { fclose (fp); }
return (0);
}
syntax highlighted by Code2HTML, v. 0.9.1