summaryrefslogtreecommitdiff
path: root/usr.sbin/nsd/udb.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/nsd/udb.c')
-rw-r--r--usr.sbin/nsd/udb.c32
1 files changed, 28 insertions, 4 deletions
diff --git a/usr.sbin/nsd/udb.c b/usr.sbin/nsd/udb.c
index 02c81973942..c3b1de0347c 100644
--- a/usr.sbin/nsd/udb.c
+++ b/usr.sbin/nsd/udb.c
@@ -70,7 +70,7 @@ udb_base*
udb_base_create_fd(const char* fname, int fd, udb_walk_relptr_func walkfunc,
void* arg)
{
- uint64_t m;
+ uint64_t m, fsz;
udb_glob_d g;
ssize_t r;
udb_base* udb = (udb_base*)xalloc_zero(sizeof(*udb));
@@ -136,7 +136,7 @@ udb_base_create_fd(const char* fname, int fd, udb_walk_relptr_func walkfunc,
(int)g.hsize);
goto fail;
}
- if(g.clean_close != 0) {
+ if(g.clean_close != 1) {
log_msg(LOG_WARNING, "%s: not cleanly closed %d", fname,
(int)g.clean_close);
goto fail;
@@ -146,13 +146,27 @@ udb_base_create_fd(const char* fname, int fd, udb_walk_relptr_func walkfunc,
(int)g.dirty_alloc);
goto fail;
}
- /* TODO check if too large (>4g on 32bit); mmap-usage would fail */
-
+
+ /* check file size correctly written, for 4.0.2 nsd.db failure */
+ fsz = (uint64_t)lseek(fd, (off_t)0, SEEK_END);
+ (void)lseek(fd, (off_t)0, SEEK_SET);
+ if(g.fsize != fsz) {
+ log_msg(LOG_WARNING, "%s: file size %llu but mmap header "
+ "has size %llu", fname, (unsigned long long)fsz,
+ (unsigned long long)g.fsize);
+ goto fail;
+ }
+
/* mmap it */
if(g.fsize < UDB_HEADER_SIZE || g.fsize < g.hsize) {
log_msg(LOG_ERR, "%s: file too short", fname);
goto fail;
}
+ if(g.fsize > (uint64_t)400*1024*1024*1024*1024) /* 400 Tb */ {
+ log_msg(LOG_WARNING, "%s: file size too large %llu",
+ fname, (unsigned long long)g.fsize);
+ goto fail;
+ }
udb->base_size = (size_t)g.fsize;
/* note the size_t casts must be there for portability, on some
* systems the layout of memory is otherwise broken. */
@@ -189,6 +203,7 @@ udb_base_create_fd(const char* fname, int fd, udb_walk_relptr_func walkfunc,
udb_alloc_compact(udb, udb->alloc);
udb_base_sync(udb, 1);
}
+ udb->glob_data->clean_close = 0;
return udb;
}
@@ -245,6 +260,7 @@ udb_base* udb_base_create_new(const char* fname, udb_walk_relptr_func walkfunc,
m = UDB_MAGIC;
udb_glob_init_new(&g);
udb_alloc_init_new(&a);
+ g.clean_close = 1;
/* write new data to file (closes fd on error) */
if(!write_fdata(fname, fd, &m, sizeof(m)))
@@ -263,6 +279,13 @@ udb_base* udb_base_create_new(const char* fname, udb_walk_relptr_func walkfunc,
close(fd);
return NULL;
}
+ /* truncate to the right size */
+ if(ftruncate(fd, (off_t)g.fsize) < 0) {
+ log_msg(LOG_ERR, "%s: ftruncate(%d): %s", fname,
+ (int)g.fsize, strerror(errno));
+ close(fd);
+ return NULL;
+ }
return udb_base_create_fd(fname, fd, walkfunc, arg);
}
@@ -292,6 +315,7 @@ void udb_base_close(udb_base* udb)
udb_base_shrink(udb, nsize);
}
if(udb->fd != -1) {
+ udb->glob_data->clean_close = 1;
close(udb->fd);
udb->fd = -1;
}