140358Smarc /*
240358Smarc  * Copyright (c) 1989 The Regents of the University of California.
340358Smarc  * All rights reserved.
440358Smarc  *
540358Smarc  * Redistribution and use in source and binary forms is permitted
640358Smarc  * provided that all copyright information, including this notice,
740358Smarc  * is retained in all such forms, and that any documentation,
840358Smarc  * advertising or other materials related to such distribution and
940358Smarc  * use acknowledge that the software was
1040358Smarc  * developed by the University of California, Berkeley.  The name
1140358Smarc  * of the University may not be used to endorse or promote products
1240358Smarc  * derived from this software without specific prior written permission.
1340358Smarc  *
1440358Smarc  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1540358Smarc  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1640358Smarc  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1740358Smarc  */
1840358Smarc 
1940358Smarc #ifndef lint
2040358Smarc char copyright[] =
2140358Smarc "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
2240358Smarc  All rights reserved.\n";
2340358Smarc #endif /* not lint */
2440358Smarc 
2540358Smarc /*
2640358Smarc  * kvm_mkdb -- Create kernel information database for running kernel.
2740358Smarc  */
2840358Smarc 
2940358Smarc #ifndef lint
30*42064Sbostic static char sccsid[] = "@(#)kvm_mkdb.c	5.2 (Berkeley) 05/15/90";
3140358Smarc #endif /* not lint */
3240358Smarc #include <sys/param.h>
3340358Smarc #include <sys/file.h>
3440358Smarc #include <ndbm.h>
3540358Smarc #include <a.out.h>
3640358Smarc #include <kvm.h>
3740358Smarc #include <paths.h>
3840358Smarc #include <limits.h>
3940358Smarc #include <errno.h>
40*42064Sbostic #include <string.h>
4140358Smarc #include <stdio.h>
4240358Smarc 
4340358Smarc char *tmp;
4440358Smarc #define basename(cp)	((tmp=rindex((cp), '/')) ? tmp+1 : (cp))
4540358Smarc #define USAGE	"kvm_mkdb"
4640358Smarc extern errno;
4740358Smarc 
4840358Smarc char *progname;
4940358Smarc 
5040358Smarc main(argc, argv)
5140358Smarc 	char *argv[];
5240358Smarc {
5340358Smarc 	DBM *db;
5440358Smarc 	char *nlistpath, *nlistname;
5540358Smarc 	char dbtemp[MAXPATHLEN];
5640358Smarc 	char dbname[MAXPATHLEN];
5740358Smarc 	extern char *optarg;
5840358Smarc 	extern int optind;
5940358Smarc 	int ch;
6040358Smarc 
6140358Smarc 	progname = argv[0];
6240358Smarc 	while ((ch = getopt(argc, argv, "")) != EOF)
6340358Smarc 		switch((char)ch) {
6440358Smarc 		case '?':
6540358Smarc 		default:
6640358Smarc 			fprintf(stderr, "usage: %s", progname, USAGE);
6740358Smarc 			exit(1);
6840358Smarc 		}
6940358Smarc 	argc -= optind;
7040358Smarc 	argv += optind;
7140358Smarc 
7240358Smarc 	nlistpath = argc > 1 ? argv[0] : _PATH_UNIX;
7340358Smarc 	nlistname = basename(nlistpath);
7440358Smarc 	sprintf(dbtemp, "%s/kvm_tmp%s", KVMDBDIR, nlistname);
7540358Smarc 	sprintf(dbname, "%s/kvm_%s", KVMDBDIR, nlistname);
7640358Smarc 	rmdb(dbtemp);
7740358Smarc 	umask(0);
7840358Smarc 	if ((db = dbm_open(dbtemp, O_CREAT|O_WRONLY|O_EXCL, 0644)) == NULL)
7940358Smarc 		syserrexit("error opening dbmfile");
8040358Smarc 	if (create_knlist(nlistpath, db) == -1)
8140358Smarc 		errexit("error creating kernel namelist");
8240358Smarc 	if (create_devnames(db) == -1)
8340358Smarc 		errexit("error creating devnames");
8440358Smarc 	rmdb(dbname);
8540358Smarc 	mvdb(dbtemp, dbname);
8640358Smarc 
8740358Smarc 	exit(0);
8840358Smarc }
8940358Smarc 
9040358Smarc rmdb(file)
9140358Smarc 	char *file;
9240358Smarc {
9340358Smarc 	int len = strlen(file);
9440358Smarc 
9540358Smarc 	if (len > (MAXPATHLEN - 5))
9640358Smarc 		errexit("pathname too long: %s", file);
9740358Smarc 	strcpy(file+len, ".dir");
9840358Smarc 	if (unlink(file) < 0 && errno != ENOENT)
9940358Smarc 		syserrexit("can't unlink %s", file);
10040358Smarc 	strcpy(file+len, ".pag");
10140358Smarc 	if (unlink(file) < 0 && errno != ENOENT)
10240358Smarc 		syserrexit("can't unlink %s", file);
10340358Smarc 	*(file+len) = '\0';
10440358Smarc }
10540358Smarc 
10640358Smarc mvdb(from, to)
10740358Smarc 	char *from;
10840358Smarc 	char *to;
10940358Smarc {
11040358Smarc 	int flen = strlen(from);
11140358Smarc 	int tlen = strlen(to);
11240358Smarc 
11340358Smarc 	if (flen > (MAXPATHLEN - 5) || tlen > (MAXPATHLEN - 5))
11440358Smarc 		errexit("pathname too long: %s or %s", from, to);
11540358Smarc 	strcpy(from+flen, ".dir");
11640358Smarc 	strcpy(to+tlen, ".dir");
11740358Smarc 	if (rename(from, to) == -1)
11840358Smarc 		syserrexit("rename %s to %s", from, to);
11940358Smarc 	strcpy(from+flen, ".pag");
12040358Smarc 	strcpy(to+tlen, ".pag");
12140358Smarc 	if (rename(from, to) == -1)
12240358Smarc 		syserrexit("rename %s to %s", from, to);
12340358Smarc 	*(from+flen) = *(to+tlen) = '\0';
12440358Smarc }
12540358Smarc 
12640358Smarc /* from libc/nlist.c */
12740358Smarc #include <unistd.h>
12840358Smarc 
12940358Smarc typedef struct nlist NLIST;
13040358Smarc #define	_strx	n_un.n_strx
13140358Smarc #define	_name	n_un.n_name
13240358Smarc #define	ISVALID(p)	(p->_name && p->_name[0])
13340358Smarc #define MAXSYMSIZE	256
13440358Smarc 
13540358Smarc create_knlist(name, db)
13640358Smarc 	char *name;
13740358Smarc 	DBM *db;
13840358Smarc {
13940358Smarc 	register NLIST *p, *s;
14040358Smarc 	struct exec ebuf;
14140358Smarc 	FILE *fstr, *fsym;
14240358Smarc 	NLIST nbuf;
14340358Smarc 	off_t strings_offset, symbol_offset, symbol_size, lseek();
14440358Smarc 	char sbuf[MAXSYMSIZE+1];
14540358Smarc 	register char *bp;
14640358Smarc 	register int c, len;
14740358Smarc 	datum key, data;
14840358Smarc 
14940358Smarc 	if (!(fsym = fopen(name, "r")))
15040358Smarc 		syserrexit("can't open %s", name);
15140358Smarc 	if (fread((char *)&ebuf, sizeof(struct exec), 1, fsym) != 1 ||
15240358Smarc 	    N_BADMAG(ebuf))
15340358Smarc 		syserrexit("can't read exec");
15440358Smarc 
15540358Smarc 	symbol_offset = N_SYMOFF(ebuf);
15640358Smarc 	symbol_size = ebuf.a_syms;
15740358Smarc 	strings_offset = symbol_offset + symbol_size;
15840358Smarc 
15940358Smarc 	if (fseek(fsym, symbol_offset, SEEK_SET) == -1)
16040358Smarc 		syserrexit("can't seek symbol table: %x", symbol_offset);
16140358Smarc 	if ((fstr = fopen(name, "r")) == NULL)
16240358Smarc 		syserrexit("can't open %s", name);
16340358Smarc 
16440358Smarc 	sbuf[0] = KVMDB_NLIST;
16540358Smarc 	key.dptr = sbuf;
16640358Smarc 	data.dptr = (char *)&nbuf;
16740358Smarc 	data.dsize = sizeof (NLIST);
16840358Smarc 
16940358Smarc 	for (s = &nbuf; symbol_size; symbol_size -= sizeof (NLIST)) {
17040358Smarc 		if (fread((char *)s, sizeof (NLIST), 1, fsym) != 1)
17140358Smarc 			syserrexit("can't read nlist entry");
17240358Smarc 		if (!s->_strx || s->n_type&N_STAB)
17340358Smarc 			continue;
17440358Smarc 		if (fseek(fstr, strings_offset + s->_strx, SEEK_SET) == -1)
17540358Smarc 			syserrexit("can't seek string: %x",
17640358Smarc 				strings_offset + s->_strx);
17740358Smarc 		/*
17840358Smarc 		 * read string
17940358Smarc 		 */
18040358Smarc 		bp = sbuf + 1;
18140358Smarc 		len = 0;
18240358Smarc 		while ((c = fgetc(fstr)) != EOF && c != '\0') {
18340358Smarc 			if (++len == MAXSYMSIZE)
18440358Smarc 				errexit("string too long");
18540358Smarc 			*bp++ = c;
18640358Smarc 		}
18740358Smarc 		*bp = '\0';
18840358Smarc 		/*
18940358Smarc 		 * and store it
19040358Smarc 		 */
19140358Smarc 		key.dsize = bp - sbuf;
19240358Smarc 		if (dbm_store(db, key, data, DBM_INSERT) < 0)
19340358Smarc 			syserrexit("dbm_store");
19440358Smarc 		if (strcmp(sbuf+1, "_version") == 0) {
19540358Smarc 			/*
19640358Smarc 			 * store the value of version in VERSION
19740358Smarc 			 */
19840358Smarc 			datum vers;
19940358Smarc 			char versbuf[LINE_MAX];
20040358Smarc 			long versoff;
20140358Smarc 			long reloffset;
20240358Smarc 
20340358Smarc 			/*
20440358Smarc 			 * Offset relative to start of text image in VM.
20540358Smarc 			 * On tahoe, first 0x800 is reserved for
20640358Smarc 			 * communication with the console processor.
20740358Smarc 			 */
20840358Smarc #ifdef tahoe
20940358Smarc 			reloffset = ((s->n_value & ~KERNBASE) - 0x800);
21040358Smarc #endif
21140358Smarc #ifdef vax
21240358Smarc 			reloffset = (s->n_value & ~KERNBASE);
21340358Smarc #endif
21440358Smarc 			/*
21540358Smarc 			 * When loaded, data is rounded
21640358Smarc 			 * to next 1024 after text, but not in file.
21740358Smarc 			 */
21840358Smarc 			reloffset -= 1024 - (ebuf.a_text % 1024);
21940358Smarc 			versoff = N_TXTOFF(ebuf) + reloffset;
22040358Smarc 			if (fseek(fstr, versoff, SEEK_SET) == -1)
22140358Smarc 				syserrexit("seek (version): %x", s->n_value);
22240358Smarc 			/*
22340358Smarc 			 * Just read version string up to, and
22440358Smarc 			 * including newline.
22540358Smarc 			 */
22640358Smarc 			if (fgets(versbuf, LINE_MAX, fstr) == NULL)
22740358Smarc 				syserrexit("can't read version");
22840358Smarc 			strcpy(sbuf+1, "VERSION");
22940358Smarc 			key.dsize = (sizeof ("VERSION") - 1) + 1;
23040358Smarc 			vers.dptr = versbuf;
23140358Smarc 			vers.dsize = strlen(versbuf);
23240358Smarc 			if (dbm_store(db, key, vers, DBM_INSERT) < 0)
23340358Smarc 				syserrexit("dbm_store: can't store VERSION");
23440358Smarc 		}
23540358Smarc 	}
23640358Smarc 	(void)fclose(fstr);
23740358Smarc 	(void)fclose(fsym);
23840358Smarc 	return (0);
23940358Smarc }
24040358Smarc 
24140358Smarc create_devnames() {}
24240358Smarc 
24340358Smarc #include <varargs.h>
24440358Smarc 
24540358Smarc warning(va_alist)
24640358Smarc 	va_dcl
24740358Smarc {
24840358Smarc 	char *fmt;
24940358Smarc 	va_list ap;
25040358Smarc 
25140358Smarc 	fprintf(stderr, "%s: warning: ", progname);
25240358Smarc 	va_start(ap);
25340358Smarc 	fmt = va_arg(ap, char *);
25440358Smarc 	(void) vfprintf(stderr, fmt, ap);
25540358Smarc 	va_end(ap);
25640358Smarc 	fprintf(stderr, "\n");
25740358Smarc }
25840358Smarc 
25940358Smarc 
26040358Smarc errexit(va_alist)
26140358Smarc 	va_dcl
26240358Smarc {
26340358Smarc 	char *fmt;
26440358Smarc 	va_list ap;
26540358Smarc 
26640358Smarc 	fprintf(stderr, "%s: ", progname);
26740358Smarc 	va_start(ap);
26840358Smarc 	fmt = va_arg(ap, char *);
26940358Smarc 	(void) vfprintf(stderr, fmt, ap);
27040358Smarc 	va_end(ap);
27140358Smarc 	fprintf(stderr, "\n");
27240358Smarc 	exit(1);
27340358Smarc }
27440358Smarc 
27540358Smarc 
27640358Smarc syserrexit(va_alist)
27740358Smarc 	va_dcl
27840358Smarc {
27940358Smarc 	char *fmt;
28040358Smarc 	va_list ap;
28140358Smarc 
28240358Smarc 	fprintf(stderr, "%s: ", progname);
28340358Smarc 	va_start(ap);
28440358Smarc 	fmt = va_arg(ap, char *);
28540358Smarc 	(void) vfprintf(stderr, fmt, ap);
28640358Smarc 	va_end(ap);
28740358Smarc 	fprintf(stderr, ": %s\n", strerror(errno));
28840358Smarc 	exit(1);
28940358Smarc }
290