164562Sgshapiro/*
2261363Sgshapiro** Copyright (c) 1999-2002 Proofpoint, Inc. and its suppliers.
364562Sgshapiro**	All rights reserved.
464562Sgshapiro**
564562Sgshapiro** By using this file, you agree to the terms and conditions set
664562Sgshapiro** forth in the LICENSE file which can be found at the top level of
764562Sgshapiro** the sendmail distribution.
864562Sgshapiro*/
964562Sgshapiro
1090792Sgshapiro#include <sm/gen.h>
11266692SgshapiroSM_RCSID("@(#)$Id: smndbm.c,v 8.55 2013-11-22 20:51:49 ca Exp $")
1264562Sgshapiro
1364562Sgshapiro#include <fcntl.h>
1464562Sgshapiro#include <stdlib.h>
1564562Sgshapiro#include <unistd.h>
1664562Sgshapiro
1764562Sgshapiro#include <sendmail/sendmail.h>
1864562Sgshapiro#include <libsmdb/smdb.h>
1964562Sgshapiro
2064562Sgshapiro#ifdef NDBM
2164562Sgshapiro
2264562Sgshapiro# define SMNDB_DIR_FILE_EXTENSION "dir"
2364562Sgshapiro# define SMNDB_PAG_FILE_EXTENSION "pag"
2464562Sgshapiro
2564562Sgshapirostruct smdb_dbm_database_struct
2664562Sgshapiro{
2764562Sgshapiro	DBM	*smndbm_dbm;
2864562Sgshapiro	int	smndbm_lock_fd;
2964562Sgshapiro	bool	smndbm_cursor_in_use;
3064562Sgshapiro};
3164562Sgshapirotypedef struct smdb_dbm_database_struct SMDB_DBM_DATABASE;
3264562Sgshapiro
3364562Sgshapirostruct smdb_dbm_cursor_struct
3464562Sgshapiro{
3564562Sgshapiro	SMDB_DBM_DATABASE	*smndbmc_db;
3664562Sgshapiro	datum			smndbmc_current_key;
3764562Sgshapiro};
3864562Sgshapirotypedef struct smdb_dbm_cursor_struct SMDB_DBM_CURSOR;
3964562Sgshapiro
4090792Sgshapiro/*
4164562Sgshapiro**  SMDB_PUT_FLAGS_TO_NDBM_FLAGS -- Translates smdb put flags to ndbm put flags.
4264562Sgshapiro**
4364562Sgshapiro**	Parameters:
4464562Sgshapiro**		flags -- The flags to translate.
4564562Sgshapiro**
4664562Sgshapiro**	Returns:
4764562Sgshapiro**		The ndbm flags that are equivalent to the smdb flags.
4864562Sgshapiro**
4964562Sgshapiro**	Notes:
5064562Sgshapiro**		Any invalid flags are ignored.
5164562Sgshapiro**
5264562Sgshapiro*/
5364562Sgshapiro
5464562Sgshapiroint
5564562Sgshapirosmdb_put_flags_to_ndbm_flags(flags)
5664562Sgshapiro	SMDB_FLAG flags;
5764562Sgshapiro{
5864562Sgshapiro	int return_flags;
5964562Sgshapiro
6064562Sgshapiro	return_flags = 0;
6164562Sgshapiro	if (bitset(SMDBF_NO_OVERWRITE, flags))
6264562Sgshapiro		return_flags = DBM_INSERT;
6364562Sgshapiro	else
6464562Sgshapiro		return_flags = DBM_REPLACE;
6564562Sgshapiro
6664562Sgshapiro	return return_flags;
6764562Sgshapiro}
6864562Sgshapiro
6990792Sgshapiro/*
7090792Sgshapiro**  Except for smdb_ndbm_open, the rest of these function correspond to the
7190792Sgshapiro**  interface laid out in smdb.h.
7264562Sgshapiro*/
7364562Sgshapiro
7464562SgshapiroSMDB_DBM_DATABASE *
7564562Sgshapirosmdbm_malloc_database()
7664562Sgshapiro{
7764562Sgshapiro	SMDB_DBM_DATABASE *db;
7864562Sgshapiro
7964562Sgshapiro	db = (SMDB_DBM_DATABASE *) malloc(sizeof(SMDB_DBM_DATABASE));
8064562Sgshapiro	if (db != NULL)
8164562Sgshapiro	{
8264562Sgshapiro		db->smndbm_dbm = NULL;
8364562Sgshapiro		db->smndbm_lock_fd = -1;
8490792Sgshapiro		db->smndbm_cursor_in_use = false;
8564562Sgshapiro	}
8664562Sgshapiro
8764562Sgshapiro	return db;
8864562Sgshapiro}
8964562Sgshapiro
9064562Sgshapiroint
9164562Sgshapirosmdbm_close(database)
9264562Sgshapiro	SMDB_DATABASE *database;
9364562Sgshapiro{
9464562Sgshapiro	SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl;
9564562Sgshapiro	DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
9664562Sgshapiro
9764562Sgshapiro	dbm_close(dbm);
9864562Sgshapiro	if (db->smndbm_lock_fd != -1)
9964562Sgshapiro		close(db->smndbm_lock_fd);
10064562Sgshapiro
10164562Sgshapiro	free(db);
10264562Sgshapiro	database->smdb_impl = NULL;
10364562Sgshapiro
10464562Sgshapiro	return SMDBE_OK;
10564562Sgshapiro}
10664562Sgshapiro
10764562Sgshapiroint
10864562Sgshapirosmdbm_del(database, key, flags)
10964562Sgshapiro	SMDB_DATABASE *database;
11064562Sgshapiro	SMDB_DBENT *key;
11190792Sgshapiro	unsigned int flags;
11264562Sgshapiro{
11364562Sgshapiro	int result;
11464562Sgshapiro	DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
11571345Sgshapiro	datum dbkey;
11664562Sgshapiro
11790792Sgshapiro	(void) memset(&dbkey, '\0', sizeof dbkey);
11871345Sgshapiro	dbkey.dptr = key->data;
11971345Sgshapiro	dbkey.dsize = key->size;
12071345Sgshapiro
12164562Sgshapiro	errno = 0;
12271345Sgshapiro	result = dbm_delete(dbm, dbkey);
12364562Sgshapiro	if (result != 0)
12464562Sgshapiro	{
12564562Sgshapiro		int save_errno = errno;
12664562Sgshapiro
12764562Sgshapiro		if (dbm_error(dbm))
12864562Sgshapiro			return SMDBE_IO_ERROR;
12964562Sgshapiro
13064562Sgshapiro		if (save_errno != 0)
13164562Sgshapiro			return save_errno;
13264562Sgshapiro
13364562Sgshapiro		return SMDBE_NOT_FOUND;
13464562Sgshapiro	}
13564562Sgshapiro	return SMDBE_OK;
13664562Sgshapiro}
13764562Sgshapiro
13864562Sgshapiroint
13964562Sgshapirosmdbm_fd(database, fd)
14064562Sgshapiro	SMDB_DATABASE *database;
14164562Sgshapiro	int *fd;
14264562Sgshapiro{
14364562Sgshapiro	DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
14464562Sgshapiro
14564562Sgshapiro	*fd = dbm_dirfno(dbm);
14664562Sgshapiro	if (*fd <= 0)
14764562Sgshapiro		return EINVAL;
14864562Sgshapiro
14964562Sgshapiro	return SMDBE_OK;
15064562Sgshapiro}
15164562Sgshapiro
15264562Sgshapiroint
15366494Sgshapirosmdbm_lockfd(database)
15466494Sgshapiro	SMDB_DATABASE *database;
15566494Sgshapiro{
15666494Sgshapiro	SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl;
15766494Sgshapiro
15866494Sgshapiro	return db->smndbm_lock_fd;
15966494Sgshapiro}
16066494Sgshapiro
16166494Sgshapiroint
16264562Sgshapirosmdbm_get(database, key, data, flags)
16364562Sgshapiro	SMDB_DATABASE *database;
16464562Sgshapiro	SMDB_DBENT *key;
16564562Sgshapiro	SMDB_DBENT *data;
16690792Sgshapiro	unsigned int flags;
16764562Sgshapiro{
16864562Sgshapiro	DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
16971345Sgshapiro	datum dbkey, dbdata;
17064562Sgshapiro
17190792Sgshapiro	(void) memset(&dbkey, '\0', sizeof dbkey);
17290792Sgshapiro	(void) memset(&dbdata, '\0', sizeof dbdata);
17371345Sgshapiro	dbkey.dptr = key->data;
17471345Sgshapiro	dbkey.dsize = key->size;
17571345Sgshapiro
17664562Sgshapiro	errno = 0;
17771345Sgshapiro	dbdata = dbm_fetch(dbm, dbkey);
17871345Sgshapiro	if (dbdata.dptr == NULL)
17964562Sgshapiro	{
18064562Sgshapiro		int save_errno = errno;
18164562Sgshapiro
18264562Sgshapiro		if (dbm_error(dbm))
18364562Sgshapiro			return SMDBE_IO_ERROR;
18464562Sgshapiro
18564562Sgshapiro		if (save_errno != 0)
18664562Sgshapiro			return save_errno;
18764562Sgshapiro
18864562Sgshapiro		return SMDBE_NOT_FOUND;
18964562Sgshapiro	}
19071345Sgshapiro	data->data = dbdata.dptr;
19171345Sgshapiro	data->size = dbdata.dsize;
19264562Sgshapiro	return SMDBE_OK;
19364562Sgshapiro}
19464562Sgshapiro
19564562Sgshapiroint
19664562Sgshapirosmdbm_put(database, key, data, flags)
19764562Sgshapiro	SMDB_DATABASE *database;
19864562Sgshapiro	SMDB_DBENT *key;
19964562Sgshapiro	SMDB_DBENT *data;
20090792Sgshapiro	unsigned int flags;
20164562Sgshapiro{
20264562Sgshapiro	int result;
20364562Sgshapiro	int save_errno;
20464562Sgshapiro	DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
20571345Sgshapiro	datum dbkey, dbdata;
20664562Sgshapiro
20790792Sgshapiro	(void) memset(&dbkey, '\0', sizeof dbkey);
20890792Sgshapiro	(void) memset(&dbdata, '\0', sizeof dbdata);
20971345Sgshapiro	dbkey.dptr = key->data;
21071345Sgshapiro	dbkey.dsize = key->size;
21171345Sgshapiro	dbdata.dptr = data->data;
21271345Sgshapiro	dbdata.dsize = data->size;
21371345Sgshapiro
21464562Sgshapiro	errno = 0;
21571345Sgshapiro	result = dbm_store(dbm, dbkey, dbdata,
21664562Sgshapiro			   smdb_put_flags_to_ndbm_flags(flags));
21764562Sgshapiro	switch (result)
21864562Sgshapiro	{
21964562Sgshapiro	  case 1:
22064562Sgshapiro		return SMDBE_DUPLICATE;
22164562Sgshapiro
22264562Sgshapiro	  case 0:
22364562Sgshapiro		return SMDBE_OK;
22464562Sgshapiro
22564562Sgshapiro	  default:
22664562Sgshapiro		save_errno = errno;
22764562Sgshapiro
22864562Sgshapiro		if (dbm_error(dbm))
22964562Sgshapiro			return SMDBE_IO_ERROR;
23064562Sgshapiro
23164562Sgshapiro		if (save_errno != 0)
23264562Sgshapiro			return save_errno;
23364562Sgshapiro
23464562Sgshapiro		return SMDBE_IO_ERROR;
23564562Sgshapiro	}
23664562Sgshapiro	/* NOTREACHED */
23764562Sgshapiro}
23864562Sgshapiro
23964562Sgshapiroint
24064562Sgshapirosmndbm_set_owner(database, uid, gid)
24164562Sgshapiro	SMDB_DATABASE *database;
24264562Sgshapiro	uid_t uid;
24364562Sgshapiro	gid_t gid;
24464562Sgshapiro{
24564562Sgshapiro# if HASFCHOWN
24664562Sgshapiro	int fd;
24764562Sgshapiro	int result;
24864562Sgshapiro	DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
24964562Sgshapiro
25064562Sgshapiro	fd = dbm_dirfno(dbm);
25164562Sgshapiro	if (fd <= 0)
25264562Sgshapiro		return EINVAL;
25364562Sgshapiro
25464562Sgshapiro	result = fchown(fd, uid, gid);
25564562Sgshapiro	if (result < 0)
25664562Sgshapiro		return errno;
25764562Sgshapiro
25864562Sgshapiro	fd = dbm_pagfno(dbm);
25964562Sgshapiro	if (fd <= 0)
26064562Sgshapiro		return EINVAL;
26164562Sgshapiro
26264562Sgshapiro	result = fchown(fd, uid, gid);
26364562Sgshapiro	if (result < 0)
26464562Sgshapiro		return errno;
26564562Sgshapiro# endif /* HASFCHOWN */
26664562Sgshapiro
26764562Sgshapiro	return SMDBE_OK;
26864562Sgshapiro}
26964562Sgshapiro
27064562Sgshapiroint
27164562Sgshapirosmdbm_sync(database, flags)
27264562Sgshapiro	SMDB_DATABASE *database;
27390792Sgshapiro	unsigned int flags;
27464562Sgshapiro{
27564562Sgshapiro	return SMDBE_UNSUPPORTED;
27664562Sgshapiro}
27764562Sgshapiro
27864562Sgshapiroint
27964562Sgshapirosmdbm_cursor_close(cursor)
28064562Sgshapiro	SMDB_CURSOR *cursor;
28164562Sgshapiro{
28264562Sgshapiro	SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
28364562Sgshapiro	SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
28464562Sgshapiro
28564562Sgshapiro	if (!db->smndbm_cursor_in_use)
28664562Sgshapiro		return SMDBE_NOT_A_VALID_CURSOR;
28764562Sgshapiro
28890792Sgshapiro	db->smndbm_cursor_in_use = false;
28964562Sgshapiro	free(dbm_cursor);
29064562Sgshapiro	free(cursor);
29164562Sgshapiro
29264562Sgshapiro	return SMDBE_OK;
29364562Sgshapiro}
29464562Sgshapiro
29564562Sgshapiroint
29664562Sgshapirosmdbm_cursor_del(cursor, flags)
29764562Sgshapiro	SMDB_CURSOR *cursor;
29890792Sgshapiro	unsigned int flags;
29964562Sgshapiro{
30064562Sgshapiro	int result;
30164562Sgshapiro	SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
30264562Sgshapiro	SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
30364562Sgshapiro	DBM *dbm = db->smndbm_dbm;
30464562Sgshapiro
30564562Sgshapiro	errno = 0;
30664562Sgshapiro	result = dbm_delete(dbm, dbm_cursor->smndbmc_current_key);
30764562Sgshapiro	if (result != 0)
30864562Sgshapiro	{
30964562Sgshapiro		int save_errno = errno;
31064562Sgshapiro
31164562Sgshapiro		if (dbm_error(dbm))
31264562Sgshapiro			return SMDBE_IO_ERROR;
31364562Sgshapiro
31464562Sgshapiro		if (save_errno != 0)
31564562Sgshapiro			return save_errno;
31664562Sgshapiro
31764562Sgshapiro		return SMDBE_NOT_FOUND;
31864562Sgshapiro	}
31964562Sgshapiro	return SMDBE_OK;
32064562Sgshapiro}
32164562Sgshapiro
32264562Sgshapiroint
32364562Sgshapirosmdbm_cursor_get(cursor, key, value, flags)
32464562Sgshapiro	SMDB_CURSOR *cursor;
32564562Sgshapiro	SMDB_DBENT *key;
32664562Sgshapiro	SMDB_DBENT *value;
32764562Sgshapiro	SMDB_FLAG flags;
32864562Sgshapiro{
32964562Sgshapiro	SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
33064562Sgshapiro	SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
33164562Sgshapiro	DBM *dbm = db->smndbm_dbm;
33271345Sgshapiro	datum dbkey, dbdata;
33364562Sgshapiro
33490792Sgshapiro	(void) memset(&dbkey, '\0', sizeof dbkey);
33590792Sgshapiro	(void) memset(&dbdata, '\0', sizeof dbdata);
33671345Sgshapiro
33764562Sgshapiro	if (flags == SMDB_CURSOR_GET_RANGE)
33864562Sgshapiro		return SMDBE_UNSUPPORTED;
33964562Sgshapiro
34064562Sgshapiro	if (dbm_cursor->smndbmc_current_key.dptr == NULL)
34164562Sgshapiro	{
34264562Sgshapiro		dbm_cursor->smndbmc_current_key = dbm_firstkey(dbm);
34364562Sgshapiro		if (dbm_cursor->smndbmc_current_key.dptr == NULL)
34464562Sgshapiro		{
34564562Sgshapiro			if (dbm_error(dbm))
34664562Sgshapiro				return SMDBE_IO_ERROR;
34764562Sgshapiro			return SMDBE_LAST_ENTRY;
34864562Sgshapiro		}
34964562Sgshapiro	}
35064562Sgshapiro	else
35164562Sgshapiro	{
35264562Sgshapiro		dbm_cursor->smndbmc_current_key = dbm_nextkey(dbm);
35364562Sgshapiro		if (dbm_cursor->smndbmc_current_key.dptr == NULL)
35464562Sgshapiro		{
35564562Sgshapiro			if (dbm_error(dbm))
35664562Sgshapiro				return SMDBE_IO_ERROR;
35764562Sgshapiro			return SMDBE_LAST_ENTRY;
35864562Sgshapiro		}
35964562Sgshapiro	}
36064562Sgshapiro
36164562Sgshapiro	errno = 0;
36271345Sgshapiro	dbdata = dbm_fetch(dbm, dbm_cursor->smndbmc_current_key);
36371345Sgshapiro	if (dbdata.dptr == NULL)
36464562Sgshapiro	{
36564562Sgshapiro		int save_errno = errno;
36664562Sgshapiro
36764562Sgshapiro		if (dbm_error(dbm))
36864562Sgshapiro			return SMDBE_IO_ERROR;
36964562Sgshapiro
37064562Sgshapiro		if (save_errno != 0)
37164562Sgshapiro			return save_errno;
37264562Sgshapiro
37364562Sgshapiro		return SMDBE_NOT_FOUND;
37464562Sgshapiro	}
37571345Sgshapiro	value->data = dbdata.dptr;
37671345Sgshapiro	value->size = dbdata.dsize;
37771345Sgshapiro	key->data = dbm_cursor->smndbmc_current_key.dptr;
37871345Sgshapiro	key->size = dbm_cursor->smndbmc_current_key.dsize;
37964562Sgshapiro
38064562Sgshapiro	return SMDBE_OK;
38164562Sgshapiro}
38264562Sgshapiro
38364562Sgshapiroint
38464562Sgshapirosmdbm_cursor_put(cursor, key, value, flags)
38564562Sgshapiro	SMDB_CURSOR *cursor;
38664562Sgshapiro	SMDB_DBENT *key;
38764562Sgshapiro	SMDB_DBENT *value;
38864562Sgshapiro	SMDB_FLAG flags;
38964562Sgshapiro{
39064562Sgshapiro	int result;
39164562Sgshapiro	int save_errno;
39264562Sgshapiro	SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
39364562Sgshapiro	SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
39464562Sgshapiro	DBM *dbm = db->smndbm_dbm;
39571345Sgshapiro	datum dbdata;
39664562Sgshapiro
39790792Sgshapiro	(void) memset(&dbdata, '\0', sizeof dbdata);
39871345Sgshapiro	dbdata.dptr = value->data;
39971345Sgshapiro	dbdata.dsize = value->size;
40071345Sgshapiro
40164562Sgshapiro	errno = 0;
40271345Sgshapiro	result = dbm_store(dbm, dbm_cursor->smndbmc_current_key, dbdata,
40364562Sgshapiro			   smdb_put_flags_to_ndbm_flags(flags));
40464562Sgshapiro	switch (result)
40564562Sgshapiro	{
40664562Sgshapiro	  case 1:
40764562Sgshapiro		return SMDBE_DUPLICATE;
40864562Sgshapiro
40964562Sgshapiro	  case 0:
41064562Sgshapiro		return SMDBE_OK;
41164562Sgshapiro
41264562Sgshapiro	  default:
41364562Sgshapiro		save_errno = errno;
41464562Sgshapiro
41564562Sgshapiro		if (dbm_error(dbm))
41664562Sgshapiro			return SMDBE_IO_ERROR;
41764562Sgshapiro
41864562Sgshapiro		if (save_errno != 0)
41964562Sgshapiro			return save_errno;
42064562Sgshapiro
42164562Sgshapiro		return SMDBE_IO_ERROR;
42264562Sgshapiro	}
42364562Sgshapiro	/* NOTREACHED */
42464562Sgshapiro}
42564562Sgshapiro
42664562Sgshapiroint
42764562Sgshapirosmdbm_cursor(database, cursor, flags)
42864562Sgshapiro	SMDB_DATABASE *database;
42964562Sgshapiro	SMDB_CURSOR **cursor;
43064562Sgshapiro	SMDB_FLAG flags;
43164562Sgshapiro{
43264562Sgshapiro	SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl;
43364562Sgshapiro	SMDB_CURSOR *cur;
43464562Sgshapiro	SMDB_DBM_CURSOR *dbm_cursor;
43564562Sgshapiro
43664562Sgshapiro	if (db->smndbm_cursor_in_use)
43764562Sgshapiro		return SMDBE_ONLY_SUPPORTS_ONE_CURSOR;
43864562Sgshapiro
43990792Sgshapiro	db->smndbm_cursor_in_use = true;
44064562Sgshapiro	dbm_cursor = (SMDB_DBM_CURSOR *) malloc(sizeof(SMDB_DBM_CURSOR));
441261363Sgshapiro	if (dbm_cursor == NULL)
442261363Sgshapiro		return SMDBE_MALLOC;
44364562Sgshapiro	dbm_cursor->smndbmc_db = db;
44464562Sgshapiro	dbm_cursor->smndbmc_current_key.dptr = NULL;
44564562Sgshapiro	dbm_cursor->smndbmc_current_key.dsize = 0;
44664562Sgshapiro
44764562Sgshapiro	cur = (SMDB_CURSOR*) malloc(sizeof(SMDB_CURSOR));
44864562Sgshapiro	if (cur == NULL)
449261363Sgshapiro	{
450261363Sgshapiro		free(dbm_cursor);
45164562Sgshapiro		return SMDBE_MALLOC;
452261363Sgshapiro	}
45364562Sgshapiro
45464562Sgshapiro	cur->smdbc_impl = dbm_cursor;
45564562Sgshapiro	cur->smdbc_close = smdbm_cursor_close;
45664562Sgshapiro	cur->smdbc_del = smdbm_cursor_del;
45764562Sgshapiro	cur->smdbc_get = smdbm_cursor_get;
45864562Sgshapiro	cur->smdbc_put = smdbm_cursor_put;
45964562Sgshapiro	*cursor = cur;
46064562Sgshapiro
46164562Sgshapiro	return SMDBE_OK;
46264562Sgshapiro}
46390792Sgshapiro/*
46464562Sgshapiro**  SMDB_NDBM_OPEN -- Opens a ndbm database.
46564562Sgshapiro**
46664562Sgshapiro**	Parameters:
46764562Sgshapiro**		database -- An unallocated database pointer to a pointer.
46864562Sgshapiro**		db_name -- The name of the database without extension.
46964562Sgshapiro**		mode -- File permisions on a created database.
47064562Sgshapiro**		mode_mask -- Mode bits that much match on an opened database.
47164562Sgshapiro**		sff -- Flags to safefile.
47264562Sgshapiro**		type -- The type of database to open.
47364562Sgshapiro**			Only SMDB_NDBM is supported.
47464562Sgshapiro**		user_info -- Information on the user to use for file
47564562Sgshapiro**			    permissions.
47690792Sgshapiro**		db_params -- No params are supported.
47764562Sgshapiro**
47864562Sgshapiro**	Returns:
47964562Sgshapiro**		SMDBE_OK -- Success, otherwise errno:
48064562Sgshapiro**		SMDBE_MALLOC -- Cannot allocate memory.
48164562Sgshapiro**		SMDBE_UNSUPPORTED -- The type is not supported.
48264562Sgshapiro**		SMDBE_GDBM_IS_BAD -- We have detected GDBM and we don't
48364562Sgshapiro**				    like it.
48464562Sgshapiro**		SMDBE_BAD_OPEN -- dbm_open failed and errno was not set.
48564562Sgshapiro**		Anything else: errno
48664562Sgshapiro*/
48764562Sgshapiro
48864562Sgshapiroint
48964562Sgshapirosmdb_ndbm_open(database, db_name, mode, mode_mask, sff, type, user_info,
49064562Sgshapiro	       db_params)
49164562Sgshapiro	SMDB_DATABASE **database;
49264562Sgshapiro	char *db_name;
49364562Sgshapiro	int mode;
49464562Sgshapiro	int mode_mask;
49564562Sgshapiro	long sff;
49664562Sgshapiro	SMDB_DBTYPE type;
49764562Sgshapiro	SMDB_USER_INFO *user_info;
49864562Sgshapiro	SMDB_DBPARAMS *db_params;
49964562Sgshapiro{
50094334Sgshapiro	bool lockcreated = false;
50164562Sgshapiro	int result;
50264562Sgshapiro	int lock_fd;
50364562Sgshapiro	SMDB_DATABASE *smdb_db;
50464562Sgshapiro	SMDB_DBM_DATABASE *db;
50564562Sgshapiro	DBM *dbm = NULL;
50664562Sgshapiro	struct stat dir_stat_info;
50764562Sgshapiro	struct stat pag_stat_info;
50864562Sgshapiro
50964562Sgshapiro	result = SMDBE_OK;
51064562Sgshapiro	*database = NULL;
51164562Sgshapiro
51264562Sgshapiro	if (type == NULL)
51364562Sgshapiro		return SMDBE_UNKNOWN_DB_TYPE;
51464562Sgshapiro
51564562Sgshapiro	result = smdb_setup_file(db_name, SMNDB_DIR_FILE_EXTENSION, mode_mask,
51664562Sgshapiro				 sff, user_info, &dir_stat_info);
51764562Sgshapiro	if (result != SMDBE_OK)
51864562Sgshapiro		return result;
51964562Sgshapiro
52064562Sgshapiro	result = smdb_setup_file(db_name, SMNDB_PAG_FILE_EXTENSION, mode_mask,
52164562Sgshapiro				 sff, user_info, &pag_stat_info);
52264562Sgshapiro	if (result != SMDBE_OK)
52364562Sgshapiro		return result;
52464562Sgshapiro
52594334Sgshapiro	if ((dir_stat_info.st_mode == ST_MODE_NOFILE ||
52694334Sgshapiro	     pag_stat_info.st_mode == ST_MODE_NOFILE) &&
52794334Sgshapiro	    bitset(mode, O_CREAT))
52894334Sgshapiro		lockcreated = true;
52994334Sgshapiro
53064562Sgshapiro	lock_fd = -1;
53164562Sgshapiro	result = smdb_lock_file(&lock_fd, db_name, mode, sff,
53264562Sgshapiro				SMNDB_DIR_FILE_EXTENSION);
53364562Sgshapiro	if (result != SMDBE_OK)
53464562Sgshapiro		return result;
53564562Sgshapiro
53694334Sgshapiro	if (lockcreated)
53794334Sgshapiro	{
53894334Sgshapiro		int pag_fd;
53994334Sgshapiro
54094334Sgshapiro		/* Need to pre-open the .pag file as well with O_EXCL */
54194334Sgshapiro		result = smdb_lock_file(&pag_fd, db_name, mode, sff,
54294334Sgshapiro					SMNDB_PAG_FILE_EXTENSION);
54394334Sgshapiro		if (result != SMDBE_OK)
54494334Sgshapiro		{
54594334Sgshapiro			(void) close(lock_fd);
54694334Sgshapiro			return result;
54794334Sgshapiro		}
54894334Sgshapiro		(void) close(pag_fd);
54994334Sgshapiro
55094334Sgshapiro		mode |= O_TRUNC;
55194334Sgshapiro		mode &= ~(O_CREAT|O_EXCL);
55294334Sgshapiro	}
55394334Sgshapiro
55464562Sgshapiro	smdb_db = smdb_malloc_database();
55564562Sgshapiro	if (smdb_db == NULL)
55664562Sgshapiro		result = SMDBE_MALLOC;
55764562Sgshapiro
55864562Sgshapiro	db = smdbm_malloc_database();
55964562Sgshapiro	if (db == NULL)
56064562Sgshapiro		result = SMDBE_MALLOC;
56164562Sgshapiro
56264562Sgshapiro	/* Try to open database */
56364562Sgshapiro	if (result == SMDBE_OK)
56464562Sgshapiro	{
56564562Sgshapiro		db->smndbm_lock_fd = lock_fd;
56664562Sgshapiro
56764562Sgshapiro		errno = 0;
56898121Sgshapiro		dbm = dbm_open(db_name, mode, DBMMODE);
56964562Sgshapiro		if (dbm == NULL)
57064562Sgshapiro		{
57164562Sgshapiro			if (errno == 0)
57264562Sgshapiro				result = SMDBE_BAD_OPEN;
57364562Sgshapiro			else
57464562Sgshapiro				result = errno;
57564562Sgshapiro		}
57664562Sgshapiro		db->smndbm_dbm = dbm;
57764562Sgshapiro	}
57864562Sgshapiro
57964562Sgshapiro	/* Check for GDBM */
58064562Sgshapiro	if (result == SMDBE_OK)
58164562Sgshapiro	{
58264562Sgshapiro		if (dbm_dirfno(dbm) == dbm_pagfno(dbm))
58364562Sgshapiro			result = SMDBE_GDBM_IS_BAD;
58464562Sgshapiro	}
58564562Sgshapiro
58664562Sgshapiro	/* Check for filechanged */
58764562Sgshapiro	if (result == SMDBE_OK)
58864562Sgshapiro	{
58964562Sgshapiro		result = smdb_filechanged(db_name, SMNDB_DIR_FILE_EXTENSION,
59064562Sgshapiro					  dbm_dirfno(dbm), &dir_stat_info);
59164562Sgshapiro		if (result == SMDBE_OK)
59264562Sgshapiro		{
59364562Sgshapiro			result = smdb_filechanged(db_name,
59464562Sgshapiro						  SMNDB_PAG_FILE_EXTENSION,
59564562Sgshapiro						  dbm_pagfno(dbm),
59664562Sgshapiro						  &pag_stat_info);
59764562Sgshapiro		}
59864562Sgshapiro	}
59964562Sgshapiro
60064562Sgshapiro	/* XXX Got to get fchown stuff in here */
60164562Sgshapiro
60264562Sgshapiro	/* Setup driver if everything is ok */
60364562Sgshapiro	if (result == SMDBE_OK)
60464562Sgshapiro	{
60564562Sgshapiro		*database = smdb_db;
60664562Sgshapiro
60764562Sgshapiro		smdb_db->smdb_close = smdbm_close;
60864562Sgshapiro		smdb_db->smdb_del = smdbm_del;
60964562Sgshapiro		smdb_db->smdb_fd = smdbm_fd;
61066494Sgshapiro		smdb_db->smdb_lockfd = smdbm_lockfd;
61164562Sgshapiro		smdb_db->smdb_get = smdbm_get;
61264562Sgshapiro		smdb_db->smdb_put = smdbm_put;
61364562Sgshapiro		smdb_db->smdb_set_owner = smndbm_set_owner;
61464562Sgshapiro		smdb_db->smdb_sync = smdbm_sync;
61564562Sgshapiro		smdb_db->smdb_cursor = smdbm_cursor;
61664562Sgshapiro
61764562Sgshapiro		smdb_db->smdb_impl = db;
61864562Sgshapiro
61964562Sgshapiro		return SMDBE_OK;
62064562Sgshapiro	}
62164562Sgshapiro
62264562Sgshapiro	/* If we're here, something bad happened, clean up */
62364562Sgshapiro	if (dbm != NULL)
62464562Sgshapiro		dbm_close(dbm);
62564562Sgshapiro
62664562Sgshapiro	smdb_unlock_file(db->smndbm_lock_fd);
62764562Sgshapiro	free(db);
62864562Sgshapiro	smdb_free_database(smdb_db);
62964562Sgshapiro
63064562Sgshapiro	return result;
63164562Sgshapiro}
63264562Sgshapiro#endif /* NDBM */
633