mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
mode = __db_omode("rwrw--");
db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)	const char *fname;	DBTYPE type;	int flags, mode;	DB_ENV *dbenv;	DB_INFO *dbinfo;	DB **dbpp;{	BTMETA *btm;	DB *dbp;	DBT pgcookie;	DB_ENV *envp, t_dbenv;	DB_PGINFO pginfo;	HASHHDR *hashm;	size_t cachesize;	ssize_t nr;	u_int32_t iopsize;	int fd, ftype, need_fileid, restore, ret, retry_cnt, swapped;	char *real_name, mbuf[512];	/* Validate arguments. */#ifdef HAVE_SPINLOCKS#define	OKFLAGS	(DB_CREATE | DB_NOMMAP | DB_RDONLY | DB_THREAD | DB_TRUNCATE)#else#define	OKFLAGS	(DB_CREATE | DB_NOMMAP | DB_RDONLY | DB_TRUNCATE)#endif	if ((ret = __db_fchk(dbenv, "db_open", flags, OKFLAGS)) != 0)		return (ret);	if (dbenv != NULL &&	    LF_ISSET(DB_THREAD) && !F_ISSET(dbenv, DB_ENV_THREAD)) {		__db_err(dbenv, "environment not created using DB_THREAD");		return (EINVAL);	}	/* Initialize for error return. */	fd = -1;	need_fileid = 1;	real_name = NULL;	/* Allocate the DB structure, reference the DB_ENV structure. */	if ((dbp = (DB *)__db_calloc(1, sizeof(DB))) == NULL) {		__db_err(dbenv, "%s", strerror(ENOMEM));		return (ENOMEM);	}	dbp->dbenv = dbenv;	/* Convert the db_open(3) flags. */	if (LF_ISSET(DB_RDONLY))		F_SET(dbp, DB_AM_RDONLY);	if (LF_ISSET(DB_THREAD))		F_SET(dbp, DB_AM_THREAD);	/* Convert the dbinfo structure flags. */	if (dbinfo != NULL) {		/*		 * !!!		 * We can't check for illegal flags until we know what type		 * of open we're doing.		 */		if (F_ISSET(dbinfo, DB_DELIMITER))			F_SET(dbp, DB_RE_DELIMITER);		if (F_ISSET(dbinfo, DB_DUP))			F_SET(dbp, DB_AM_DUP);		if (F_ISSET(dbinfo, DB_FIXEDLEN))			F_SET(dbp, DB_RE_FIXEDLEN);		if (F_ISSET(dbinfo, DB_PAD))			F_SET(dbp, DB_RE_PAD);		if (F_ISSET(dbinfo, DB_RECNUM))			F_SET(dbp, DB_BT_RECNUM);		if (F_ISSET(dbinfo, DB_RENUMBER))			F_SET(dbp, DB_RE_RENUMBER);		if (F_ISSET(dbinfo, DB_SNAPSHOT))			F_SET(dbp, DB_RE_SNAPSHOT);	}	/*	 * Always set the master and initialize the queues, so we can	 * use these fields without checking the thread bit.	 */	dbp->master = dbp;	LIST_INIT(&dbp->handleq);	LIST_INSERT_HEAD(&dbp->handleq, dbp, links);	TAILQ_INIT(&dbp->curs_queue);	/*	 * Set based on the dbenv fields, although no logging or transactions	 * are possible for temporary files.	 */	if (dbenv != NULL) {		if (dbenv->lk_info != NULL)			F_SET(dbp, DB_AM_LOCKING);		if (fname != NULL && dbenv->lg_info != NULL)			F_SET(dbp, DB_AM_LOGGING);	}	/* Set the common fields. */	if (dbinfo == NULL) {		dbp->pgsize = 0;		dbp->db_malloc = NULL;	} else {		dbp->pgsize = dbinfo->db_pagesize;		dbp->db_malloc = dbinfo->db_malloc;	}	/* Fill in the default file mode. */	if (mode == 0)		mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;	/* Check if the user wants us to swap byte order. */	if (dbinfo != NULL)		switch (ret = __db_byteorder(dbenv, dbinfo->db_lorder)) {		case 0:			break;		case DB_SWAPBYTES:			F_SET(dbp, DB_AM_SWAP);			break;		default:			goto err;		}	/*	 * If we have a file name, try and read the first page, figure out	 * what type of file it is, and initialize everything we can based	 * on that file's meta-data page.	 *	 * XXX	 * We don't actually expect zero-length strings as arguments.  We	 * do the check, permitting them, because scripting languages, e.g.,	 * the Tcl test suite, doesn't know anything about passing NULL's.	 */	if (fname != NULL && fname[0] != '\0') {		/* Get the real file name. */		if ((ret = __db_appname(dbenv,		     DB_APP_DATA, NULL, fname, NULL, &real_name)) != 0)			goto err;		/*		 * Open the backing file.  We need to make sure that multiple		 * processes attempting to create the file at the same time		 * are properly ordered so that only one of them creates the		 * "unique" file id, so we open it O_EXCL and O_CREAT so two		 * simultaneous attempts to create the region will return		 * failure in one of the attempts.  If we're one of the ones		 * that fail, we simply retry without the O_CREAT flag, which		 * will require that the meta-data page exist.		 */		retry_cnt = 0;open_retry:	if (LF_ISSET(DB_CREATE)) {			if ((ret = __db_open(real_name, flags | DB_EXCL,			    OKFLAGS | DB_EXCL, mode, &fd)) != 0)				if (ret == EEXIST) {					LF_CLR(DB_CREATE);					goto open_retry;				} else {					__db_err(dbenv,					    "%s: %s", fname, strerror(ret));					goto err;				}		} else			if ((ret = __db_open(real_name,			    flags, OKFLAGS, mode, &fd)) != 0) {				__db_err(dbenv, "%s: %s", fname, strerror(ret));				goto err;			}		/*		 * Use the optimum I/O size as the pagesize if a pagesize not		 * specified.  Some filesystems have 64K as their optimum I/O		 * size, but as that results in impossibly large default cache		 * sizes, we limit the default pagesize to 16K.		 */		if (dbp->pgsize == 0) {			if ((ret = __db_ioinfo(real_name,			    fd, NULL, NULL, &iopsize)) != 0) {				__db_err(dbenv,				    "%s: %s", real_name, strerror(ret));				goto err;			}			if (iopsize < 512)				iopsize = 512;			if (iopsize > 16 * 1024)				iopsize = 16 * 1024;			dbp->pgsize = iopsize;			F_SET(dbp, DB_AM_PGDEF);		}		/*		 * Try and read the first disk sector -- this code assumes		 * that the meta-data for all access methods fits in 512		 * bytes, and that no database will be smaller than that.		 */		if ((ret = __db_read(fd, mbuf, sizeof(mbuf), &nr)) != 0)			goto err;		/* The fd is no longer needed. */		(void)__db_close(fd);		fd = -1;		if (nr != sizeof(mbuf)) {			if (nr != 0) {				__db_err(dbenv,				    "%s: unexpected file format", fname);				goto einval;			}			/*			 * The only way we can reach here with the DB_CREATE			 * flag set is if we created the file.  If that's not			 * the case, then a) someone else created the file			 * but has not yet written out the meta-data page, or			 * b) we truncated the file (DB_TRUNCATE) leaving it			 * zero-length.  In the case of a), we want to sleep			 * and give the file creator some time to write the			 * metadata page.  In the case of b), charge forward.			 * Note, there is a race in the case of two processes			 * opening the file with the DB_TRUNCATE flag set at			 * roughly the same time, and they could theoretically			 * hurt each other, although it's pretty unlikely.			 */			if (retry_cnt++ < 3 &&			    !LF_ISSET(DB_CREATE | DB_TRUNCATE)) {				__db_sleep(1, 0);				goto open_retry;			}			if (type == DB_UNKNOWN) {				__db_err(dbenv,				    "%s: DBTYPE of unknown with empty file",				    fname);				goto einval;			}			goto empty;		}		/*		 * A found file overrides some user information.  We'll check		 * for possible error conditions based on conflicts between		 * the file and the user's arguments below.		 */		swapped = 0;		F_CLR(dbp, DB_AM_SWAP);retry:		switch (((BTMETA *)mbuf)->magic) {		case DB_BTREEMAGIC:			if (type != DB_BTREE &&			    type != DB_RECNO && type != DB_UNKNOWN)				goto einval;			btm = (BTMETA *)mbuf;			if (swapped && (ret = __bam_mswap((PAGE *)btm)) != 0)				goto err;			if (btm->version < DB_BTREEOLDVER ||			    btm->version > DB_BTREEVERSION) {				__db_err(dbenv,				    "%s: unsupported btree version number %lu",				    fname, (u_long)btm->version);				goto einval;			}			dbp->pgsize = btm->pagesize;			F_CLR(dbp, DB_AM_PGDEF);			if ((ret = __db_fchk(dbenv,			    "db_open", btm->flags, BTM_MASK)) != 0)				goto err;			DBINFO_FCHK(dbp, "DB_DUP",			    btm->flags, BTM_DUP, DB_AM_DUP);			if (F_ISSET(btm, BTM_RECNO)) {				DBINFO_FCHK(dbp, "DB_FIXEDLEN",				    btm->flags, BTM_FIXEDLEN, DB_RE_FIXEDLEN);				DBINFO_FCHK(dbp, "DB_RENUMBER",				    btm->flags, BTM_RENUMBER, DB_RE_RENUMBER);				type = DB_RECNO;			} else {				DBINFO_FCHK(dbp, "DB_RECNUM",				    btm->flags, BTM_RECNUM, DB_BT_RECNUM);				type = DB_BTREE;			}			/* Copy the file's unique id. */			need_fileid = 0;			memcpy(dbp->lock.fileid, btm->uid, DB_FILE_ID_LEN);			break;		case DB_HASHMAGIC:			if (type != DB_HASH && type != DB_UNKNOWN)				goto einval;			hashm = (HASHHDR *)mbuf;			if (swapped && (ret = __ham_mswap((PAGE *)hashm)) != 0)				goto err;			if (hashm->version < DB_HASHOLDVER ||			    hashm->version > DB_HASHVERSION) {				__db_err(dbenv,				    "%s: unsupported hash version number %lu",				    fname, hashm->version);				goto einval;			}			dbp->pgsize = hashm->pagesize;			F_CLR(dbp, DB_AM_PGDEF);			if ((ret = __db_fchk(dbenv,			    "db_open", hashm->flags, DB_HASH_DUP)) != 0)				goto err;			DBINFO_FCHK(dbp, "DB_DUP",			    hashm->flags, DB_HASH_DUP, DB_AM_DUP);			type = DB_HASH;			/* Copy the file's unique id. */			need_fileid = 0;			memcpy(dbp->lock.fileid, hashm->uid, DB_FILE_ID_LEN);			break;		default:			if (swapped) {				__db_err(dbenv, "unrecognized file type");				goto einval;			}			M_32_SWAP(((BTMETA *)mbuf)->magic);			F_SET(dbp, DB_AM_SWAP);			swapped = 1;			goto retry;		}	} else {		fname = real_name = NULL;		if (type == DB_UNKNOWN) {			__db_err(dbenv,			    "DBTYPE of unknown without existing file");			goto einval;		}		F_SET(dbp, DB_AM_INMEM);	}empty:	/*	 * By the time we get here we've either set the type or we're taking	 * it from the user.	 */	dbp->type = type;	/*	 * Set the page size to the best value for I/O to this file.  Don't	 * overflow the page offset type.  The page size must be db_indx_t	 * aligned and >= MIN_PAGE_SIZE.	 *	 * XXX	 * Should we be checking for a page size that's not a multiple of 512?	 */	if (dbp->pgsize == 0) {		F_SET(dbp, DB_AM_PGDEF);		dbp->pgsize = 8 * 1024;	}	if (dbp->pgsize < DB_MIN_PGSIZE ||	    dbp->pgsize > DB_MAX_PGSIZE ||	    dbp->pgsize & (sizeof(db_indx_t) - 1)) {		__db_err(dbenv, "illegal page size");		goto einval;	}	/*	 * Set and/or correct the cache size; must be a multiple of the	 * page size.	 */	if (dbinfo == NULL || dbinfo->db_cachesize == 0)		cachesize = dbp->pgsize * DB_MINCACHE;	else {		cachesize = dbinfo->db_cachesize;		if (cachesize & (dbp->pgsize - 1))			cachesize += (~cachesize & (dbp->pgsize - 1)) + 1;		if (cachesize < dbp->pgsize * DB_MINCACHE)			cachesize = dbp->pgsize * DB_MINCACHE;		if (cachesize < 20 * 1024)			cachesize = 20 * 1024;	}	/*	 * If no mpool supplied by the application, attach to a local,	 * created buffer pool.	 *	 * XXX	 * If the user has a DB_ENV structure, we have to use a temporary	 * one so that we don't step on their values.  If the user doesn't,	 * we have to create one, and keep it around until the call to the	 * memp_close() function.  This is all so the mpool functions get	 * the error stuff right.	 */	if (dbenv == NULL || dbenv->mp_info == NULL) {		F_SET(dbp, DB_AM_MLOCAL);		if (dbenv == NULL) {			if ((dbp->mp_dbenv =			    (DB_ENV *)__db_calloc(sizeof(DB_ENV), 1)) == NULL) {				ret = ENOMEM;				goto err;			}			envp = dbp->mp_dbenv;			restore = 0;		} else {			t_dbenv = *dbenv;			envp = dbenv;			restore = 1;		}		envp->mp_size = cachesize;		if ((ret = memp_open(NULL, DB_CREATE | DB_MPOOL_PRIVATE |		    (F_ISSET(dbp, DB_AM_THREAD) ? DB_THREAD : 0),		    S_IRUSR | S_IWUSR, envp, &dbp->mp)) != 0)			goto err;		if (restore)			*dbenv = t_dbenv;	} else		dbp->mp = dbenv->mp_info;	/* Register DB's pgin/pgout functions. */	if ((ret = memp_register(dbp->mp,	    DB_FTYPE_BTREE, __bam_pgin, __bam_pgout)) != 0)		goto err;	if ((ret = memp_register(dbp->mp,	    DB_FTYPE_HASH, __ham_pgin, __ham_pgout)) != 0)		goto err;	/*	 * If we don't already have one, get a unique file ID.  If the file	 * is a temporary file, then we have to create a unique file ID --	 * no backing file will be created until the mpool cache is filled	 * forcing it to go to disk.  The created ID must never match any	 * potential real file ID -- we know it won't because real file IDs	 * contain a time stamp after the dev/ino pair, and we're simply	 * storing a 4-byte locker ID.	 *	 * XXX	 * Store the file id in the locker structure -- we can get it from	 * there as necessary, and it saves having two copies.	 */	if (need_fileid)		if (fname == NULL) {			memset(dbp->lock.fileid, 0, DB_FILE_ID_LEN);			if (F_ISSET(dbp, DB_AM_LOCKING) &&			    (ret = lock_id(dbenv->lk_info,			    (u_int32_t *)dbp->lock.fileid)) != 0)				goto err;		} else			if ((ret = __db_fileid(dbenv,			    real_name, 1, dbp->lock.fileid)) != 0)				goto err;	/* No further use for the real name. */	if (real_name != NULL)		FREES(real_name);	real_name = NULL;	/*	 * Open a backing file in the memory pool.	 *	 * If we need to process the file's pages on I/O, set the file type.	 * If it's a hash file, always call pgin and pgout routines.  This	 * means that hash files can never be mapped into process memory.  If	 * it's a btree file and requires swapping, we need to page the file	 * in and out.  This has to be right -- we can't mmap files that are	 * being paged in and out.	 */	if (type == DB_HASH)		ftype = DB_FTYPE_HASH;	else		ftype = F_ISSET(dbp, DB_AM_SWAP) ? DB_FTYPE_BTREE : 0;	pginfo.db_pagesize = dbp->pgsize;	pginfo.needswap = F_ISSET(dbp, DB_AM_SWAP);	pgcookie.data = &pginfo;	pgcookie.size = sizeof(DB_PGINFO);	if ((ret = memp_fopen(dbp->mp, fname, ftype,	    F_ISSET(dbp, DB_AM_RDONLY) ? DB_RDONLY : 0, 0, dbp->pgsize,	    0, &pgcookie, dbp->lock.fileid, &dbp->mpf)) != 0)		goto err;	/*	 * XXX	 * Truly spectacular layering violation.  We need a per-thread mutex	 * that lives in shared memory (thanks, HP-UX!) and so we acquire a	 * pointer to the mpool one.	 */	if (F_ISSET(dbp, DB_AM_THREAD))		dbp->mutexp = dbp->mpf->mutexp;	/* Get a log file id. */	if (F_ISSET(dbp, DB_AM_LOGGING) &&	    (ret = log_register(dbenv->lg_info,	    dbp, fname, type, &dbp->log_fileid)) != 0)		goto err;	/*	 * Get a locker id for this DB, and build the lock cookie: the first	 * db_pgno_t bytes are the page number, the next N bytes are the file	 * id.	 */	if (F_ISSET(dbp, DB_AM_LOCKING)) {		if ((ret = lock_id(dbenv->lk_info, &dbp->locker)) != 0)			goto err;		dbp->lock_dbt.size = sizeof(dbp->lock);		dbp->lock_dbt.data = &dbp->lock;	}	/* Call the real open function. */	switch (type) {	case DB_BTREE:		if (dbinfo != NULL && (ret = __db_fchk(dbenv,		    "db_open", dbinfo->flags, DB_RECNUM | DB_DUP)) != 0)			goto err;		if (dbinfo != NULL && (ret = __db_fcchk(dbenv,		    "db_open", dbinfo->flags, DB_DUP, DB_RECNUM)) != 0)			goto err;		if ((ret = __bam_open(dbp, type, dbinfo)) != 0)			goto err;		break;	case DB_HASH:		if (dbinfo != NULL && (ret = __db_fchk(dbenv,		    "db_open", dbinfo->flags, DB_DUP)) != 0)			goto err;		if ((ret = __ham_open(dbp, dbinfo)) != 0)			goto err;		break;	case DB_RECNO:#define	DB_INFO_FLAGS \	(DB_DELIMITER | DB_FIXEDLEN | DB_PAD | DB_RENUMBER | DB_SNAPSHOT)		if (dbinfo != NULL && (ret = __db_fchk(dbenv,		    "db_open", dbinfo->flags, DB_INFO_FLAGS)) != 0)			goto err;		if ((ret = __ram_open(dbp, type, dbinfo)) != 0)			goto err;		break;	default:		abort();	}	/* Call a local close routine. */	dbp->close = db_close;	dbp->fd = db_fd;	*dbpp = dbp;	return (0);einval:	ret = EINVAL;err:	/* Close the file descriptor. */	if (fd != -1)		(void)__db_close(fd);	/* Discard the log file id. */	if (dbp->log_fileid != 0)		(void)log_unregister(dbenv->lg_info, dbp->log_fileid);	/* Close the memory pool file. */	if (dbp->mpf != NULL)		(void)memp_fclose(dbp->mpf);	/* If the memory pool was local, close it. */	if (F_ISSET(dbp, DB_AM_MLOCAL) && dbp->mp != NULL)		(void)memp_close(dbp->mp);	/* If we allocated a DB_ENV, discard it. */	if (dbp->mp_dbenv != NULL)		FREE(dbp->mp_dbenv, sizeof(DB_ENV));	if (real_name != NULL)		FREES(real_name);	if (dbp != NULL)		FREE(dbp, sizeof(DB));	return (ret);}