Import NetBSD dev_mkdb(8)

Adapt libc devname(3) to make use of it, so that such device name
queries are now several orders of magnitude faster.  The database
is created and updated at system bootup time.

Change-Id: I0cbcb24c7d47577d4d6af9c8290c21ee4df9a0ff
This commit is contained in:
David van Moolenbroek 2015-10-06 16:42:46 +00:00 committed by Lionel Sambuc
parent 1f761e1bea
commit 180e74704d
11 changed files with 436 additions and 10 deletions

View File

@ -883,6 +883,7 @@
./usr/sbin/btrace minix-base
./usr/sbin/chown minix-base
./usr/sbin/chroot minix-base
./usr/sbin/dev_mkdb minix-base
./usr/sbin/diskctl minix-base
./usr/sbin/download-vulnerability-list minix-base crypto
./usr/sbin/fbdctl minix-base

View File

@ -3358,6 +3358,7 @@
./usr/man/man8/cleantmp.8 minix-man
./usr/man/man8/config.8 minix-man
./usr/man/man8/cron.8 minix-man
./usr/man/man8/dev_mkdb.8 minix-man
./usr/man/man8/devsize.8 minix-man
./usr/man/man8/dhcpd.8 minix-man
./usr/man/man8/diskctl.8 minix-man

View File

@ -393,6 +393,15 @@ start|autoboot)
fi
fi
# Now that all device files should be created, see if we need to update the
# device file database. This code is butchered from NetBSD etc/rc.d/sysdb.
DEVDIR=/dev
DEVDB=/var/run/dev.cdb
if [ ! -f "$DEVDB" -o "$DEVDIR" -nt "$DEVDB" ]
then
dev_mkdb
fi
if [ "$net" ]
then
# Get the nodename from the DNS and set it.

View File

@ -45,11 +45,14 @@ __RCSID("$NetBSD: devname.c,v 1.22 2012/06/03 21:42:46 joerg Exp $");
#include <string.h>
#include <stdlib.h>
#ifdef __minix
#include <minix/dmap.h> /* for UNIX98_MINOR */
#endif /* __minix */
#ifdef __weak_alias
__weak_alias(devname_r,_devname_r)
#endif
#if !defined(__minix)
static once_t db_opened = ONCE_INITIALIZER;
static struct cdbr *db;
static devmajor_t pts;
@ -95,14 +98,25 @@ devname_ptslookup(dev_t dev, mode_t type, char *path, size_t len)
if (type != S_IFCHR || pts == NODEVMAJOR || major(dev) != pts)
return ENOENT;
#ifdef __minix
/*
* MINIX3 does not use an identity mapping for /dev/pts, because the
* same major number is also used for PTY masters and legacy PTYs.
*/
if (minor(dev) < UNIX98_MINOR || !(minor(dev) & 1))
return ENOENT;
#endif /* __minix */
rv = snprintf(path, len, "%s%d", _PATH_DEV_PTS + sizeof(_PATH_DEV) - 1,
#ifndef __minix
minor(dev));
#else /* __minix */
(minor(dev) - UNIX98_MINOR) >> 1);
#endif /* __minix */
if (rv < 0 || (size_t)rv >= len)
return ERANGE;
return 0;
}
#endif /* !defined(__minix) */
static int
devname_fts(dev_t dev, mode_t type, char *path, size_t len)
@ -142,7 +156,6 @@ devname_r(dev_t dev, mode_t type, char *path, size_t len)
{
int rv;
#if !defined(__minix)
thr_once(&db_opened, devname_dbopen);
if (db != NULL) {
@ -157,7 +170,6 @@ devname_r(dev_t dev, mode_t type, char *path, size_t len)
if (db != NULL)
return ENOENT;
#endif /* !defined(__minix) */
rv = devname_fts(dev, type, path, len);
return rv;
}

View File

@ -84,7 +84,14 @@
*
*/
#if defined(_REENTRANT) && defined(__minix)
#if !defined(__minix) || !defined(_LIBC_REENTRANT_H)
#ifdef __minix
/*
* If _REENTRANT is not defined, the header may not be included more than once.
* This is probably a NetBSD libc bug, but for now we solve it for MINIX3 only.
*/
#define _LIBC_REENTRANT_H
#endif /* __minix */
/*
* Abstract thread interface for thread-safe libraries. These routines
@ -93,6 +100,8 @@
* is.
*/
#ifndef __minix
#include <pthread.h>
#include <signal.h>
@ -124,6 +133,17 @@
#define once_t pthread_once_t
#define ONCE_INITIALIZER PTHREAD_ONCE_INIT
#else /* __minix */
typedef struct {
int pto_done;
} once_t;
#define ONCE_INITIALIZER { .pto_done = 0 }
#endif /* __minix */
#ifdef _REENTRANT
#ifndef __LIBC_THREAD_STUBS
__BEGIN_DECLS
@ -311,7 +331,6 @@ __END_DECLS
#define mutexattr_settype(ma, t) __empty
#define mutexattr_destroy(ma) __empty
#if !defined(__minix)
static inline int
thr_once(once_t *once_control, void (*routine)(void))
{
@ -321,7 +340,6 @@ thr_once(once_t *once_control, void (*routine)(void))
}
return 0;
}
#endif /* defined(__minix) */
#define thr_sigsetmask(f, n, o) __empty
#define thr_self() __empty
#define thr_errno() __empty
@ -331,3 +349,5 @@ thr_once(once_t *once_control, void (*routine)(void))
#define FUNLOCKFILE(fp) __empty
#endif /* _REENTRANT */
#endif /* !defined(__minix) || !defined(_LIBC_REENTRANT_H) */

View File

@ -7,7 +7,7 @@
#define PTMX_MINOR 0 /* minor of the Unix98 clone device */
#define TTYPX_MINOR 128
#define PTYPX_MINOR 192
#define UNIX98_MINOR 256 /* start of Unix98 pairs */
/* UNIX98_MINOR is defined in minix/dmap.h */
#define TTY_IN_BYTES 256 /* tty input queue size */
#define TTY_OUT_BYTES 2048 /* tty output queue size */

View File

@ -94,6 +94,15 @@
/* Minor device numbers for the TTY driver. */
# define CONS_MINOR 0 /* console device */
/* Minor device numbers for the PTY driver. */
# define UNIX98_MINOR 256 /* Base number of UNIX98 PTYs, which
* are allocated in (master,slave)
* pairs: 256=master#0, 257=slave#0,
* 258=master#1, 259=slave#1, etc.
* This logic is shared between the
* PTY service and libc devname(3).
*/
#define CTRLR(n) ((n)==0 ? 3 : (8 + 2*((n)-1))) /* magic formula */
/* Minor device numbers for log driver. */
@ -104,4 +113,3 @@
# define DEV_IMGRD ((dev_t) 0x0106) /* device number of /dev/imgrd */
#endif /* _DMAP_H */

View File

@ -6,7 +6,7 @@
SUBDIR= \
\
chroot \
\
dev_mkdb \
\
\
\

View File

@ -0,0 +1,12 @@
# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
# $NetBSD: Makefile,v 1.9 2012/08/10 12:10:28 joerg Exp $
PROG= dev_mkdb
MAN= dev_mkdb.8
LDADD+= -lutil
DPADD+= ${LIBUTIL}
.include <bsd.prog.mk>
LDFLAGS+= -Wl,--no-fatal-warnings

View File

@ -0,0 +1,95 @@
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" from: @(#)dev_mkdb.8 8.1 (Berkeley) 6/6/93
.\" $NetBSD: dev_mkdb.8,v 1.13 2012/06/03 21:42:47 joerg Exp $
.\"
.Dd June 1, 2012
.Dt DEV_MKDB 8
.Os
.Sh NAME
.Nm dev_mkdb
.Nd create
.Pa /dev
database
.Sh SYNOPSIS
.Nm
.Op Fl c
.Op Fl o Ar database
.Op directory
.Sh DESCRIPTION
The
.Nm
command creates a
.Xr cdbr 3
database in
.Dq Pa /var/run/dev.cdb
which contains the names of all of the character and block special
files in the specified directory, using the file type and the
.Fa st_rdev
field as the key.
If no directory is specified, the
.Dq Pa /dev
directory is used.
.Pp
Keys are a structure containing a mode_t followed by a dev_t,
with any padding zero'd out.
The former is the type of the file (st_mode \*[Am] S_IFMT),
the latter is the st_rdev field.
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl c
Create a
.Xr db 3
database for compatibility with libc versions and statically linked programs
from before
.Nx 6.0 .
The default name is
.Dq Pa /var/run/dev.db .
.It Fl o Ar database
Put the output databases in the named file.
.El
.Sh FILES
.Bl -tag -width /var/run/dev.db -compact
.It Pa /dev
Device directory.
.It Pa /var/run/dev.db
Database file.
.El
.Sh SEE ALSO
.Xr ps 1 ,
.Xr stat 2 ,
.Xr db 3 ,
.Xr devname 3 ,
.Xr kvm_nlist 3 ,
.Xr ttyname 3
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.4 .

View File

@ -0,0 +1,268 @@
/* $NetBSD: dev_mkdb.c,v 1.29 2012/06/03 21:42:47 joerg Exp $ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: dev_mkdb.c,v 1.29 2012/06/03 21:42:47 joerg Exp $");
#include <sys/queue.h>
#include <sys/stat.h>
#include <cdbw.h>
#include <db.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
#include <paths.h>
#include <search.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <util.h>
#define HASH_SIZE 65536
#define FILE_PERMISSION S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH
static struct cdbw *db;
static DB *db_compat;
static const char *db_name;
static char *db_name_tmp;
static void usage(void) __dead;
static void
cdb_open(void)
{
db = cdbw_open();
if (db == NULL)
err(1, "opening cdb writer failed");
}
static void
cdb_close(void)
{
int fd;
fd = open(db_name_tmp, O_CREAT|O_EXCL|O_WRONLY, FILE_PERMISSION);
if (fd == -1)
err(1, "opening %s failed", db_name_tmp);
if (cdbw_output(db, fd, "NetBSD6 devdb", NULL))
err(1, "failed to write temporary database %s", db_name_tmp);
cdbw_close(db);
db = NULL;
if (close(fd))
err(1, "failed to write temporary database %s", db_name_tmp);
}
static void
cdb_add_entry(dev_t dev, mode_t type, const char *relpath)
{
uint8_t *buf;
size_t len;
len = strlen(relpath) + 1;
buf = malloc(len + 10);
le64enc(buf, dev);
le16enc(buf + 8, type);
memcpy(buf + 10, relpath, len);
cdbw_put(db, buf, 10, buf, len + 10);
free(buf);
}
static void
compat_open(void)
{
static HASHINFO openinfo = {
4096, /* bsize */
128, /* ffactor */
1024, /* nelem */
2048 * 1024, /* cachesize */
NULL, /* hash() */
0 /* lorder */
};
db_compat = dbopen(db_name_tmp, O_CREAT|O_EXCL|O_EXLOCK|O_RDWR|O_TRUNC,
FILE_PERMISSION, DB_HASH, &openinfo);
if (db_compat == NULL)
err(1, "failed to create temporary database %s",
db_name_tmp);
}
static void
compat_close(void)
{
if ((*db_compat->close)(db_compat))
err(1, "failed to write temporary database %s", db_name_tmp);
}
static void
compat_add_entry(dev_t dev, mode_t type, const char *relpath)
{
/*
* Keys are a mode_t followed by a dev_t. The former is the type of
* the file (mode & S_IFMT), the latter is the st_rdev field. Note
* that the structure may contain padding, so we have to clear it
* out here.
*/
struct {
mode_t type;
dev_t dev;
} bkey;
struct {
mode_t type;
int32_t dev;
} obkey;
DBT data, key;
(void)memset(&bkey, 0, sizeof(bkey));
key.data = &bkey;
key.size = sizeof(bkey);
data.data = __UNCONST(relpath);
data.size = strlen(relpath) + 1;
bkey.type = type;
bkey.dev = dev;
if ((*db_compat->put)(db_compat, &key, &data, 0))
err(1, "failed to write temporary database %s", db_name_tmp);
/*
* If the device fits into the old 32bit format, add compat entry
* for pre-NetBSD6 libc.
*/
if ((dev_t)(int32_t)dev != dev)
return;
(void)memset(&obkey, 0, sizeof(obkey));
key.data = &obkey;
key.size = sizeof(obkey);
data.data = __UNCONST(relpath);
data.size = strlen(relpath) + 1;
obkey.type = type;
obkey.dev = (int32_t)dev;
if ((*db_compat->put)(db_compat, &key, &data, 0))
err(1, "failed to write temporary database %s", db_name_tmp);
}
int
main(int argc, char **argv)
{
struct stat *st;
FTS *ftsp;
FTSENT *p;
int ch;
char *pathv[2];
size_t dlen;
int compat_mode;
setprogname(argv[0]);
compat_mode = 0;
while ((ch = getopt(argc, argv, "co:")) != -1)
switch (ch) {
case 'c':
compat_mode = 1;
break;
case 'o':
db_name = optarg;
break;
default:
usage();
}
argc -= optind;
argv += optind;
if (argc > 1)
usage();
pathv[1] = NULL;
if (argc == 1)
pathv[0] = argv[0];
else
pathv[0] = __UNCONST(_PATH_DEV);
ftsp = fts_open(pathv, FTS_NOCHDIR | FTS_PHYSICAL, NULL);
if (ftsp == NULL)
err(1, "fts_open: %s", pathv[0]);
if (db_name == NULL) {
if (compat_mode)
db_name = _PATH_DEVDB;
else
db_name = _PATH_DEVCDB;
}
easprintf(&db_name_tmp, "%s.XXXXXXX", db_name);
mktemp(db_name_tmp);
if (compat_mode)
compat_open();
else
cdb_open();
while ((p = fts_read(ftsp)) != NULL) {
if (p->fts_info != FTS_DEFAULT)
continue;
st = p->fts_statp;
if (!S_ISCHR(st->st_mode) && !S_ISBLK(st->st_mode))
continue;
dlen = strlen(pathv[0]);
while (pathv[0][dlen] == '/')
++dlen;
if (compat_mode)
compat_add_entry(st->st_rdev, st->st_mode & S_IFMT,
p->fts_path + dlen);
else
cdb_add_entry(st->st_rdev, st->st_mode & S_IFMT,
p->fts_path + dlen);
}
(void)fts_close(ftsp);
if (compat_mode)
compat_close();
else
cdb_close();
if (rename(db_name_tmp, db_name) == -1)
err(1, "rename %s to %s", db_name_tmp, db_name);
return 0;
}
static void
usage(void)
{
(void)fprintf(stderr, "Usage: %s [-c] [-o database] [directory]\n",
getprogname());
exit(1);
}