xref: /original-bsd/usr.sbin/kvm_mkdb/kvm_mkdb.c (revision da7c76f1)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms is permitted
6  * provided that all copyright information, including this notice,
7  * is retained in all such forms, and that any documentation,
8  * advertising or other materials related to such distribution and
9  * use acknowledge that the software was
10  * developed by the University of California, Berkeley.  The name
11  * of the University may not be used to endorse or promote products
12  * derived from this software without specific prior written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17  */
18 
19 #ifndef lint
20 char copyright[] =
21 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
22  All rights reserved.\n";
23 #endif /* not lint */
24 
25 /*
26  * kvm_mkdb -- Create kernel information database for running kernel.
27  */
28 
29 #ifndef lint
30 static char sccsid[] = "@(#)kvm_mkdb.c	5.2 (Berkeley) 05/15/90";
31 #endif /* not lint */
32 #include <sys/param.h>
33 #include <sys/file.h>
34 #include <ndbm.h>
35 #include <a.out.h>
36 #include <kvm.h>
37 #include <paths.h>
38 #include <limits.h>
39 #include <errno.h>
40 #include <string.h>
41 #include <stdio.h>
42 
43 char *tmp;
44 #define basename(cp)	((tmp=rindex((cp), '/')) ? tmp+1 : (cp))
45 #define USAGE	"kvm_mkdb"
46 extern errno;
47 
48 char *progname;
49 
50 main(argc, argv)
51 	char *argv[];
52 {
53 	DBM *db;
54 	char *nlistpath, *nlistname;
55 	char dbtemp[MAXPATHLEN];
56 	char dbname[MAXPATHLEN];
57 	extern char *optarg;
58 	extern int optind;
59 	int ch;
60 
61 	progname = argv[0];
62 	while ((ch = getopt(argc, argv, "")) != EOF)
63 		switch((char)ch) {
64 		case '?':
65 		default:
66 			fprintf(stderr, "usage: %s", progname, USAGE);
67 			exit(1);
68 		}
69 	argc -= optind;
70 	argv += optind;
71 
72 	nlistpath = argc > 1 ? argv[0] : _PATH_UNIX;
73 	nlistname = basename(nlistpath);
74 	sprintf(dbtemp, "%s/kvm_tmp%s", KVMDBDIR, nlistname);
75 	sprintf(dbname, "%s/kvm_%s", KVMDBDIR, nlistname);
76 	rmdb(dbtemp);
77 	umask(0);
78 	if ((db = dbm_open(dbtemp, O_CREAT|O_WRONLY|O_EXCL, 0644)) == NULL)
79 		syserrexit("error opening dbmfile");
80 	if (create_knlist(nlistpath, db) == -1)
81 		errexit("error creating kernel namelist");
82 	if (create_devnames(db) == -1)
83 		errexit("error creating devnames");
84 	rmdb(dbname);
85 	mvdb(dbtemp, dbname);
86 
87 	exit(0);
88 }
89 
90 rmdb(file)
91 	char *file;
92 {
93 	int len = strlen(file);
94 
95 	if (len > (MAXPATHLEN - 5))
96 		errexit("pathname too long: %s", file);
97 	strcpy(file+len, ".dir");
98 	if (unlink(file) < 0 && errno != ENOENT)
99 		syserrexit("can't unlink %s", file);
100 	strcpy(file+len, ".pag");
101 	if (unlink(file) < 0 && errno != ENOENT)
102 		syserrexit("can't unlink %s", file);
103 	*(file+len) = '\0';
104 }
105 
106 mvdb(from, to)
107 	char *from;
108 	char *to;
109 {
110 	int flen = strlen(from);
111 	int tlen = strlen(to);
112 
113 	if (flen > (MAXPATHLEN - 5) || tlen > (MAXPATHLEN - 5))
114 		errexit("pathname too long: %s or %s", from, to);
115 	strcpy(from+flen, ".dir");
116 	strcpy(to+tlen, ".dir");
117 	if (rename(from, to) == -1)
118 		syserrexit("rename %s to %s", from, to);
119 	strcpy(from+flen, ".pag");
120 	strcpy(to+tlen, ".pag");
121 	if (rename(from, to) == -1)
122 		syserrexit("rename %s to %s", from, to);
123 	*(from+flen) = *(to+tlen) = '\0';
124 }
125 
126 /* from libc/nlist.c */
127 #include <unistd.h>
128 
129 typedef struct nlist NLIST;
130 #define	_strx	n_un.n_strx
131 #define	_name	n_un.n_name
132 #define	ISVALID(p)	(p->_name && p->_name[0])
133 #define MAXSYMSIZE	256
134 
135 create_knlist(name, db)
136 	char *name;
137 	DBM *db;
138 {
139 	register NLIST *p, *s;
140 	struct exec ebuf;
141 	FILE *fstr, *fsym;
142 	NLIST nbuf;
143 	off_t strings_offset, symbol_offset, symbol_size, lseek();
144 	char sbuf[MAXSYMSIZE+1];
145 	register char *bp;
146 	register int c, len;
147 	datum key, data;
148 
149 	if (!(fsym = fopen(name, "r")))
150 		syserrexit("can't open %s", name);
151 	if (fread((char *)&ebuf, sizeof(struct exec), 1, fsym) != 1 ||
152 	    N_BADMAG(ebuf))
153 		syserrexit("can't read exec");
154 
155 	symbol_offset = N_SYMOFF(ebuf);
156 	symbol_size = ebuf.a_syms;
157 	strings_offset = symbol_offset + symbol_size;
158 
159 	if (fseek(fsym, symbol_offset, SEEK_SET) == -1)
160 		syserrexit("can't seek symbol table: %x", symbol_offset);
161 	if ((fstr = fopen(name, "r")) == NULL)
162 		syserrexit("can't open %s", name);
163 
164 	sbuf[0] = KVMDB_NLIST;
165 	key.dptr = sbuf;
166 	data.dptr = (char *)&nbuf;
167 	data.dsize = sizeof (NLIST);
168 
169 	for (s = &nbuf; symbol_size; symbol_size -= sizeof (NLIST)) {
170 		if (fread((char *)s, sizeof (NLIST), 1, fsym) != 1)
171 			syserrexit("can't read nlist entry");
172 		if (!s->_strx || s->n_type&N_STAB)
173 			continue;
174 		if (fseek(fstr, strings_offset + s->_strx, SEEK_SET) == -1)
175 			syserrexit("can't seek string: %x",
176 				strings_offset + s->_strx);
177 		/*
178 		 * read string
179 		 */
180 		bp = sbuf + 1;
181 		len = 0;
182 		while ((c = fgetc(fstr)) != EOF && c != '\0') {
183 			if (++len == MAXSYMSIZE)
184 				errexit("string too long");
185 			*bp++ = c;
186 		}
187 		*bp = '\0';
188 		/*
189 		 * and store it
190 		 */
191 		key.dsize = bp - sbuf;
192 		if (dbm_store(db, key, data, DBM_INSERT) < 0)
193 			syserrexit("dbm_store");
194 		if (strcmp(sbuf+1, "_version") == 0) {
195 			/*
196 			 * store the value of version in VERSION
197 			 */
198 			datum vers;
199 			char versbuf[LINE_MAX];
200 			long versoff;
201 			long reloffset;
202 
203 			/*
204 			 * Offset relative to start of text image in VM.
205 			 * On tahoe, first 0x800 is reserved for
206 			 * communication with the console processor.
207 			 */
208 #ifdef tahoe
209 			reloffset = ((s->n_value & ~KERNBASE) - 0x800);
210 #endif
211 #ifdef vax
212 			reloffset = (s->n_value & ~KERNBASE);
213 #endif
214 			/*
215 			 * When loaded, data is rounded
216 			 * to next 1024 after text, but not in file.
217 			 */
218 			reloffset -= 1024 - (ebuf.a_text % 1024);
219 			versoff = N_TXTOFF(ebuf) + reloffset;
220 			if (fseek(fstr, versoff, SEEK_SET) == -1)
221 				syserrexit("seek (version): %x", s->n_value);
222 			/*
223 			 * Just read version string up to, and
224 			 * including newline.
225 			 */
226 			if (fgets(versbuf, LINE_MAX, fstr) == NULL)
227 				syserrexit("can't read version");
228 			strcpy(sbuf+1, "VERSION");
229 			key.dsize = (sizeof ("VERSION") - 1) + 1;
230 			vers.dptr = versbuf;
231 			vers.dsize = strlen(versbuf);
232 			if (dbm_store(db, key, vers, DBM_INSERT) < 0)
233 				syserrexit("dbm_store: can't store VERSION");
234 		}
235 	}
236 	(void)fclose(fstr);
237 	(void)fclose(fsym);
238 	return (0);
239 }
240 
241 create_devnames() {}
242 
243 #include <varargs.h>
244 
245 warning(va_alist)
246 	va_dcl
247 {
248 	char *fmt;
249 	va_list ap;
250 
251 	fprintf(stderr, "%s: warning: ", progname);
252 	va_start(ap);
253 	fmt = va_arg(ap, char *);
254 	(void) vfprintf(stderr, fmt, ap);
255 	va_end(ap);
256 	fprintf(stderr, "\n");
257 }
258 
259 
260 errexit(va_alist)
261 	va_dcl
262 {
263 	char *fmt;
264 	va_list ap;
265 
266 	fprintf(stderr, "%s: ", progname);
267 	va_start(ap);
268 	fmt = va_arg(ap, char *);
269 	(void) vfprintf(stderr, fmt, ap);
270 	va_end(ap);
271 	fprintf(stderr, "\n");
272 	exit(1);
273 }
274 
275 
276 syserrexit(va_alist)
277 	va_dcl
278 {
279 	char *fmt;
280 	va_list ap;
281 
282 	fprintf(stderr, "%s: ", progname);
283 	va_start(ap);
284 	fmt = va_arg(ap, char *);
285 	(void) vfprintf(stderr, fmt, ap);
286 	va_end(ap);
287 	fprintf(stderr, ": %s\n", strerror(errno));
288 	exit(1);
289 }
290